From 58d1b8ae9b65585655be91effecdbbf582d09bd7 Mon Sep 17 00:00:00 2001 From: ldraney Date: Tue, 27 Jan 2026 16:31:38 -0700 Subject: [PATCH 1/6] Add project configuration - package.json: Dependencies and npm scripts - tsconfig.json: TypeScript strict mode, ES2022 - eslint.config.js: ESLint 9 flat config Co-Authored-By: Claude Opus 4.5 --- eslint.config.js | 20 + package-lock.json | 4589 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 56 + tsconfig.json | 25 + 4 files changed, 4690 insertions(+) create mode 100644 eslint.config.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 tsconfig.json diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..317825d --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,20 @@ +import js from '@eslint/js'; +import tseslint from 'typescript-eslint'; + +export default tseslint.config( + js.configs.recommended, + ...tseslint.configs.recommended, + { + ignores: ['dist/**', 'node_modules/**', 'poc/**'], + }, + { + files: ['src/**/*.ts', 'tests/**/*.ts'], + rules: { + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/no-non-null-assertion': 'warn', + 'no-console': ['warn', { allow: ['error', 'warn'] }], + }, + } +); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..f894ab7 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4589 @@ +{ + "name": "github-mcp", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "github-mcp", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.0.0", + "@octokit/auth-oauth-device": "^7.0.0", + "@octokit/rest": "^21.0.0", + "@octokit/webhooks-types": "^7.0.0", + "commander": "^12.0.0", + "keytar": "^7.9.0", + "smee-client": "^2.0.0" + }, + "bin": { + "github-mcp": "dist/index.js" + }, + "devDependencies": { + "@eslint/js": "^9.0.0", + "@types/node": "^20.0.0", + "eslint": "^9.0.0", + "typescript": "^5.4.0", + "typescript-eslint": "^8.0.0", + "vitest": "^2.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/js": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@hono/node-server": { + "version": "1.19.9", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", + "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.25.3", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.3.tgz", + "integrity": "sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.0.1", + "express-rate-limit": "^7.5.0", + "jose": "^6.1.1", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@octokit/auth-oauth-device": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-7.1.5.tgz", + "integrity": "sha512-lR00+k7+N6xeECj0JuXeULQ2TSBB/zjTAmNF2+vyGPDEFx1dgk1hTDmL13MjbSmzusuAmuJD8Pu39rjp9jH6yw==", + "license": "MIT", + "dependencies": { + "@octokit/oauth-methods": "^5.1.5", + "@octokit/request": "^9.2.3", + "@octokit/types": "^14.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/auth-token": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.2.tgz", + "integrity": "sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/core": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.6.tgz", + "integrity": "sha512-kIU8SLQkYWGp3pVKiYzA5OSaNF5EE03P/R8zEmmrG6XwOg5oBjXyQVVIauQ0dgau4zYhpZEhJrvIYt6oM+zZZA==", + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^5.0.0", + "@octokit/graphql": "^8.2.2", + "@octokit/request": "^9.2.3", + "@octokit/request-error": "^6.1.8", + "@octokit/types": "^14.0.0", + "before-after-hook": "^3.0.2", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/endpoint": { + "version": "10.1.4", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.4.tgz", + "integrity": "sha512-OlYOlZIsfEVZm5HCSR8aSg02T2lbUWOsCQoPKfTXJwDzcHQBrVBGdGXb89dv2Kw2ToZaRtudp8O3ZIYoaOjKlA==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^14.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/graphql": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-8.2.2.tgz", + "integrity": "sha512-Yi8hcoqsrXGdt0yObxbebHXFOiUA+2v3n53epuOg1QUgOB6c4XzvisBNVXJSl8RYA5KrDuSL2yq9Qmqe5N0ryA==", + "license": "MIT", + "dependencies": { + "@octokit/request": "^9.2.3", + "@octokit/types": "^14.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/oauth-authorization-url": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-7.1.1.tgz", + "integrity": "sha512-ooXV8GBSabSWyhLUowlMIVd9l1s2nsOGQdlP2SQ4LnkEsGXzeCvbSbCPdZThXhEFzleGPwbapT0Sb+YhXRyjCA==", + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/oauth-methods": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-5.1.5.tgz", + "integrity": "sha512-Ev7K8bkYrYLhoOSZGVAGsLEscZQyq7XQONCBBAl2JdMg7IT3PQn/y8P0KjloPoYpI5UylqYrLeUcScaYWXwDvw==", + "license": "MIT", + "dependencies": { + "@octokit/oauth-authorization-url": "^7.0.0", + "@octokit/request": "^9.2.3", + "@octokit/request-error": "^6.1.8", + "@octokit/types": "^14.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.1.0.tgz", + "integrity": "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==", + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "11.6.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.6.0.tgz", + "integrity": "sha512-n5KPteiF7pWKgBIBJSk8qzoZWcUkza2O6A0za97pMGVrGfPdltxrfmfF5GucHYvHGZD8BdaZmmHGz5cX/3gdpw==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.10.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-5.3.1.tgz", + "integrity": "sha512-n/lNeCtq+9ofhC15xzmJCNKP2BWTv8Ih2TTy+jatNCCq/gQP/V7rK3fjIfuz0pDWDALO/o/4QY4hyOF6TQQFUw==", + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "13.5.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.5.0.tgz", + "integrity": "sha512-9Pas60Iv9ejO3WlAX3maE1+38c5nqbJXV5GrncEfkndIpZrJ/WPMRd2xYDcPPEt5yzpxcjw9fWNoPhsSGzqKqw==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.10.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "license": "MIT" + }, + "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/@octokit/request": { + "version": "9.2.4", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.2.4.tgz", + "integrity": "sha512-q8ybdytBmxa6KogWlNa818r0k1wlqzNC+yNkcQDECHvQo8Vmstrg18JwqJHdJdUiHD2sjlwBgSm9kHkOKe2iyA==", + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^10.1.4", + "@octokit/request-error": "^6.1.8", + "@octokit/types": "^14.0.0", + "fast-content-type-parse": "^2.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/request-error": { + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.8.tgz", + "integrity": "sha512-WEi/R0Jmq+IJKydWlKDmryPcmdYSVjL3ekaiEL1L9eo1sUnqMJ+grqmC9cjk7CA7+b2/T397tO5d8YLOH3qYpQ==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^14.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/rest": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-21.1.1.tgz", + "integrity": "sha512-sTQV7va0IUVZcntzy1q3QqPm/r8rWtDCqpRAmb8eXXnKkjoQEtFe3Nt5GTVsHft+R6jJoHeSiVLcgcvhtue/rg==", + "license": "MIT", + "dependencies": { + "@octokit/core": "^6.1.4", + "@octokit/plugin-paginate-rest": "^11.4.2", + "@octokit/plugin-request-log": "^5.3.1", + "@octokit/plugin-rest-endpoint-methods": "^13.3.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/types": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.1.0.tgz", + "integrity": "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==", + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^25.1.0" + } + }, + "node_modules/@octokit/webhooks-types": { + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/@octokit/webhooks-types/-/webhooks-types-7.6.1.tgz", + "integrity": "sha512-S8u2cJzklBC0FgTwWVLaM8tMrDuDMVE4xiTK4EYXM9GntyvrdbSoxqDQa+Fh57CCNApyIpyeqPhhFEmHPfrXgw==", + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.0.tgz", + "integrity": "sha512-tPgXB6cDTndIe1ah7u6amCI1T0SsnlOuKgg10Xh3uizJk4e5M1JGaUMk7J4ciuAUcFpbOiNhm2XIjP9ON0dUqA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.0.tgz", + "integrity": "sha512-sa4LyseLLXr1onr97StkU1Nb7fWcg6niokTwEVNOO7awaKaoRObQ54+V/hrF/BP1noMEaaAW6Fg2d/CfLiq3Mg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.0.tgz", + "integrity": "sha512-/NNIj9A7yLjKdmkx5dC2XQ9DmjIECpGpwHoGmA5E1AhU0fuICSqSWScPhN1yLCkEdkCwJIDu2xIeLPs60MNIVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.0.tgz", + "integrity": "sha512-xoh8abqgPrPYPr7pTYipqnUi1V3em56JzE/HgDgitTqZBZ3yKCWI+7KUkceM6tNweyUKYru1UMi7FC060RyKwA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.0.tgz", + "integrity": "sha512-PCkMh7fNahWSbA0OTUQ2OpYHpjZZr0hPr8lId8twD7a7SeWrvT3xJVyza+dQwXSSq4yEQTMoXgNOfMCsn8584g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.0.tgz", + "integrity": "sha512-1j3stGx+qbhXql4OCDZhnK7b01s6rBKNybfsX+TNrEe9JNq4DLi1yGiR1xW+nL+FNVvI4D02PUnl6gJ/2y6WJA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.0.tgz", + "integrity": "sha512-eyrr5W08Ms9uM0mLcKfM/Uzx7hjhz2bcjv8P2uynfj0yU8GGPdz8iYrBPhiLOZqahoAMB8ZiolRZPbbU2MAi6Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.0.tgz", + "integrity": "sha512-Xds90ITXJCNyX9pDhqf85MKWUI4lqjiPAipJ8OLp8xqI2Ehk+TCVhF9rvOoN8xTbcafow3QOThkNnrM33uCFQA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.0.tgz", + "integrity": "sha512-Xws2KA4CLvZmXjy46SQaXSejuKPhwVdaNinldoYfqruZBaJHqVo6hnRa8SDo9z7PBW5x84SH64+izmldCgbezw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.0.tgz", + "integrity": "sha512-hrKXKbX5FdaRJj7lTMusmvKbhMJSGWJ+w++4KmjiDhpTgNlhYobMvKfDoIWecy4O60K6yA4SnztGuNTQF+Lplw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.0.tgz", + "integrity": "sha512-6A+nccfSDGKsPm00d3xKcrsBcbqzCTAukjwWK6rbuAnB2bHaL3r9720HBVZ/no7+FhZLz/U3GwwZZEh6tOSI8Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.0.tgz", + "integrity": "sha512-4P1VyYUe6XAJtQH1Hh99THxr0GKMMwIXsRNOceLrJnaHTDgk1FTcTimDgneRJPvB3LqDQxUmroBclQ1S0cIJwQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.0.tgz", + "integrity": "sha512-8Vv6pLuIZCMcgXre6c3nOPhE0gjz1+nZP6T+hwWjr7sVH8k0jRkH+XnfjjOTglyMBdSKBPPz54/y1gToSKwrSQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.0.tgz", + "integrity": "sha512-r1te1M0Sm2TBVD/RxBPC6RZVwNqUTwJTA7w+C/IW5v9Ssu6xmxWEi+iJQlpBhtUiT1raJ5b48pI8tBvEjEFnFA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.0.tgz", + "integrity": "sha512-say0uMU/RaPm3CDQLxUUTF2oNWL8ysvHkAjcCzV2znxBr23kFfaxocS9qJm+NdkRhF8wtdEEAJuYcLPhSPbjuQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.0.tgz", + "integrity": "sha512-/MU7/HizQGsnBREtRpcSbSV1zfkoxSTR7wLsRmBPQ8FwUj5sykrP1MyJTvsxP5KBq9SyE6kH8UQQQwa0ASeoQQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.0.tgz", + "integrity": "sha512-Q9eh+gUGILIHEaJf66aF6a414jQbDnn29zeu0eX3dHMuysnhTvsUvZTCAyZ6tJhUjnvzBKE4FtuaYxutxRZpOg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.0.tgz", + "integrity": "sha512-OR5p5yG5OKSxHReWmwvM0P+VTPMwoBS45PXTMYaskKQqybkS3Kmugq1W+YbNWArF8/s7jQScgzXUhArzEQ7x0A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.0.tgz", + "integrity": "sha512-XeatKzo4lHDsVEbm1XDHZlhYZZSQYym6dg2X/Ko0kSFgio+KXLsxwJQprnR48GvdIKDOpqWqssC3iBCjoMcMpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.0.tgz", + "integrity": "sha512-Lu71y78F5qOfYmubYLHPcJm74GZLU6UJ4THkf/a1K7Tz2ycwC2VUbsqbJAXaR6Bx70SRdlVrt2+n5l7F0agTUw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.0.tgz", + "integrity": "sha512-v5xwKDWcu7qhAEcsUubiav7r+48Uk/ENWdr82MBZZRIm7zThSxCIVDfb3ZeRRq9yqk+oIzMdDo6fCcA5DHfMyA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.0.tgz", + "integrity": "sha512-XnaaaSMGSI6Wk8F4KK3QP7GfuuhjGchElsVerCplUuxRIzdvZ7hRBpLR0omCmw+kI2RFJB80nenhOoGXlJ5TfQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.0.tgz", + "integrity": "sha512-3K1lP+3BXY4t4VihLw5MEg6IZD3ojSYzqzBG571W3kNQe4G4CcFpSUQVgurYgib5d+YaCjeFow8QivWp8vuSvA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.0.tgz", + "integrity": "sha512-MDk610P/vJGc5L5ImE4k5s+GZT3en0KoK1MKPXCRgzmksAMk79j4h3k1IerxTNqwDLxsGxStEZVBqG0gIqZqoA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.0.tgz", + "integrity": "sha512-Zv7v6q6aV+VslnpwzqKAmrk5JdVkLUzok2208ZXGipjb+msxBr/fJPZyeEXiFgH7k62Ak0SLIfxQRZQvTuf7rQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.19.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz", + "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz", + "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/type-utils": "8.54.0", + "@typescript-eslint/utils": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.54.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz", + "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz", + "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.54.0", + "@typescript-eslint/types": "^8.54.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz", + "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz", + "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz", + "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/utils": "8.54.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", + "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz", + "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.54.0", + "@typescript-eslint/tsconfig-utils": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz", + "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz", + "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.54.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitest/expect": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.9.tgz", + "integrity": "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.9.tgz", + "integrity": "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", + "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.9.tgz", + "integrity": "sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "2.1.9", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.9.tgz", + "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.9.tgz", + "integrity": "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz", + "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/before-after-hook": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz", + "integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==", + "license": "Apache-2.0" + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/body-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", + "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/fast-content-type-parse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz", + "integrity": "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT" + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hono": { + "version": "4.11.7", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.7.tgz", + "integrity": "sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jose": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", + "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keytar": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", + "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^4.3.0", + "prebuild-install": "^7.0.1" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-abi": { + "version": "3.87.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.87.0.tgz", + "integrity": "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/rollup": { + "version": "4.57.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.0.tgz", + "integrity": "sha512-e5lPJi/aui4TO1LpAXIRLySmwXSE8k3b9zoGfd42p67wzxog4WHjiZF3M2uheQih4DGyc25QEV4yRBbpueNiUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.57.0", + "@rollup/rollup-android-arm64": "4.57.0", + "@rollup/rollup-darwin-arm64": "4.57.0", + "@rollup/rollup-darwin-x64": "4.57.0", + "@rollup/rollup-freebsd-arm64": "4.57.0", + "@rollup/rollup-freebsd-x64": "4.57.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.0", + "@rollup/rollup-linux-arm-musleabihf": "4.57.0", + "@rollup/rollup-linux-arm64-gnu": "4.57.0", + "@rollup/rollup-linux-arm64-musl": "4.57.0", + "@rollup/rollup-linux-loong64-gnu": "4.57.0", + "@rollup/rollup-linux-loong64-musl": "4.57.0", + "@rollup/rollup-linux-ppc64-gnu": "4.57.0", + "@rollup/rollup-linux-ppc64-musl": "4.57.0", + "@rollup/rollup-linux-riscv64-gnu": "4.57.0", + "@rollup/rollup-linux-riscv64-musl": "4.57.0", + "@rollup/rollup-linux-s390x-gnu": "4.57.0", + "@rollup/rollup-linux-x64-gnu": "4.57.0", + "@rollup/rollup-linux-x64-musl": "4.57.0", + "@rollup/rollup-openbsd-x64": "4.57.0", + "@rollup/rollup-openharmony-arm64": "4.57.0", + "@rollup/rollup-win32-arm64-msvc": "4.57.0", + "@rollup/rollup-win32-ia32-msvc": "4.57.0", + "@rollup/rollup-win32-x64-gnu": "4.57.0", + "@rollup/rollup-win32-x64-msvc": "4.57.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/smee-client": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/smee-client/-/smee-client-2.0.4.tgz", + "integrity": "sha512-RxXCs0mfaxpI8JF4SeTM51XtRiprzW5g20HVt4aTQ36EB+RaN0aj0m/4EbXLGdfPlqahQ09d3UnJYmALN2CbYw==", + "license": "ISC", + "dependencies": { + "commander": "^12.0.0", + "eventsource": "^2.0.2", + "validator": "^13.11.0" + }, + "bin": { + "smee": "bin/smee.js" + } + }, + "node_modules/smee-client/node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar-fs": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-api-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.54.0.tgz", + "integrity": "sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.54.0", + "@typescript-eslint/parser": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/utils": "8.54.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/universal-user-agent": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "license": "ISC" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/validator": { + "version": "13.15.26", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz", + "integrity": "sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.9.tgz", + "integrity": "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", + "pathe": "^1.1.2", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.9.tgz", + "integrity": "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "2.1.9", + "@vitest/mocker": "2.1.9", + "@vitest/pretty-format": "^2.1.9", + "@vitest/runner": "2.1.9", + "@vitest/snapshot": "2.1.9", + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "debug": "^4.3.7", + "expect-type": "^1.1.0", + "magic-string": "^0.30.12", + "pathe": "^1.1.2", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0", + "vite-node": "2.1.9", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "2.1.9", + "@vitest/ui": "2.1.9", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25 || ^4" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..000b4b9 --- /dev/null +++ b/package.json @@ -0,0 +1,56 @@ +{ + "name": "github-mcp", + "version": "0.1.0", + "description": "GitHub MCP server with OAuth Device Flow and 800+ endpoint coverage", + "type": "module", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "bin": { + "github-mcp": "./dist/index.js" + }, + "scripts": { + "build": "tsc", + "dev": "tsc --watch", + "start": "node dist/index.js", + "test": "vitest", + "test:run": "vitest run", + "lint": "eslint src/", + "typecheck": "tsc --noEmit", + "prepublishOnly": "npm run build" + }, + "keywords": [ + "github", + "mcp", + "model-context-protocol", + "octokit", + "oauth", + "webhooks", + "cli" + ], + "author": "ldraney", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/ldraney/github-mcp.git" + }, + "engines": { + "node": ">=18.0.0" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "^1.0.0", + "@octokit/auth-oauth-device": "^7.0.0", + "@octokit/rest": "^21.0.0", + "@octokit/webhooks-types": "^7.0.0", + "commander": "^12.0.0", + "keytar": "^7.9.0", + "smee-client": "^2.0.0" + }, + "devDependencies": { + "@eslint/js": "^9.0.0", + "@types/node": "^20.0.0", + "eslint": "^9.0.0", + "typescript": "^5.4.0", + "typescript-eslint": "^8.0.0", + "vitest": "^2.0.0" + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e17a925 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "lib": ["ES2022"], + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "resolveJsonModule": true, + "noImplicitAny": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "tests"] +} From f237df065f3f0a8d0ca8ef3caaa9d9733356d8ca Mon Sep 17 00:00:00 2001 From: ldraney Date: Tue, 27 Jan 2026 16:31:49 -0700 Subject: [PATCH 2/6] Add MCP server with stdio transport Implements issue #4: Basic MCP server - src/index.ts: CLI entry point with commander - src/server.ts: MCP server setup with stdio transport - src/auth/token-storage.ts: Keytar integration for token storage - src/auth/oauth-device-flow.ts: OAuth Device Flow (Phase 2 prep) Supports GITHUB_TOKEN env var for authentication. Co-Authored-By: Claude Opus 4.5 --- src/auth/oauth-device-flow.ts | 164 ++++++++++++++++++++++++++++++++++ src/auth/token-storage.ts | 33 +++++++ src/index.ts | 48 ++++++++++ src/server.ts | 141 +++++++++++++++++++++++++++++ 4 files changed, 386 insertions(+) create mode 100644 src/auth/oauth-device-flow.ts create mode 100644 src/auth/token-storage.ts create mode 100644 src/index.ts create mode 100644 src/server.ts diff --git a/src/auth/oauth-device-flow.ts b/src/auth/oauth-device-flow.ts new file mode 100644 index 0000000..bdc0862 --- /dev/null +++ b/src/auth/oauth-device-flow.ts @@ -0,0 +1,164 @@ +import { createOAuthDeviceAuth } from '@octokit/auth-oauth-device'; +import { Octokit } from '@octokit/rest'; +import { setToken, getToken, deleteToken } from './token-storage.js'; + +// Default GitHub OAuth App client ID +// Users should register their own OAuth App for production use +const DEFAULT_CLIENT_ID = process.env.GITHUB_CLIENT_ID || 'Ov23liXXXXXXXXXXXXXX'; + +// Scopes needed for full GitHub API access +const SCOPES = [ + 'repo', + 'read:org', + 'read:user', + 'user:email', + 'read:project', + 'write:discussion', + 'gist', + 'notifications', + 'workflow', + 'read:packages', + 'admin:repo_hook', + 'admin:org_hook', +]; + +export interface DeviceFlowVerification { + device_code: string; + user_code: string; + verification_uri: string; + expires_in: number; + interval: number; +} + +/** + * Perform OAuth Device Flow authentication + */ +export async function login(): Promise { + const clientId = process.env.GITHUB_CLIENT_ID || DEFAULT_CLIENT_ID; + + if (clientId === DEFAULT_CLIENT_ID || clientId.startsWith('Ov23liXXXX')) { + console.error('\n⚠️ No GITHUB_CLIENT_ID set. Please register an OAuth App:'); + console.error(' 1. Go to https://github.com/settings/developers'); + console.error(' 2. Click "New OAuth App"'); + console.error(' 3. Set callback URL to: http://localhost/callback'); + console.error(' 4. Enable "Device Flow" in the app settings'); + console.error(' 5. Set GITHUB_CLIENT_ID environment variable\n'); + return null; + } + + console.error('\n🔐 Starting GitHub OAuth Device Flow...\n'); + + try { + const auth = createOAuthDeviceAuth({ + clientType: 'oauth-app', + clientId, + scopes: SCOPES, + onVerification: (verification) => { + console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); + console.error(''); + console.error(' 📋 Your verification code:'); + console.error(''); + console.error(` ${verification.user_code}`); + console.error(''); + console.error(' 🌐 Open this URL in your browser:'); + console.error(''); + console.error(` ${verification.verification_uri}`); + console.error(''); + console.error(' ⏳ Waiting for authorization...'); + console.error(''); + console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'); + + // Try to open browser automatically + openBrowser(verification.verification_uri); + }, + }); + + const { token } = await auth({ type: 'oauth' }); + + // Store token securely + await setToken(token); + + // Verify token works + const octokit = new Octokit({ auth: token }); + const { data: user } = await octokit.users.getAuthenticated(); + + console.error(''); + console.error(`✅ Successfully authenticated as: ${user.login}`); + console.error(' Token stored securely in OS keychain'); + console.error(''); + + return token; + } catch (error) { + const message = error instanceof Error ? error.message : 'Unknown error'; + console.error(`\n❌ Authentication failed: ${message}\n`); + return null; + } +} + +/** + * Remove stored credentials + */ +export async function logout(): Promise { + const deleted = await deleteToken(); + + if (deleted) { + console.error('✅ Logged out. Token removed from keychain.'); + } else { + console.error('ℹ️ No stored credentials found.'); + } +} + +/** + * Check and display authentication status + */ +export async function getAuthStatus(): Promise { + const token = process.env.GITHUB_TOKEN || await getToken(); + + if (!token) { + console.error('❌ Not authenticated'); + console.error(' Run: github-mcp auth login'); + return; + } + + try { + const octokit = new Octokit({ auth: token }); + const { data: user } = await octokit.users.getAuthenticated(); + + console.error('✅ Authenticated'); + console.error(` User: ${user.login}`); + console.error(` Name: ${user.name || 'Not set'}`); + console.error(` Email: ${user.email || 'Not public'}`); + + if (process.env.GITHUB_TOKEN) { + console.error(' Source: GITHUB_TOKEN environment variable'); + } else { + console.error(' Source: OS keychain'); + } + } catch (error) { + console.error('❌ Token is invalid or expired'); + console.error(' Run: github-mcp auth login'); + } +} + +/** + * Open URL in default browser (cross-platform) + */ +function openBrowser(url: string): void { + const { exec } = require('child_process'); + const platform = process.platform; + + let command: string; + if (platform === 'darwin') { + command = `open "${url}"`; + } else if (platform === 'win32') { + command = `start "${url}"`; + } else { + command = `xdg-open "${url}"`; + } + + exec(command, (error: Error | null) => { + if (error) { + // Silent fail - user can manually open the URL + } + }); +} diff --git a/src/auth/token-storage.ts b/src/auth/token-storage.ts new file mode 100644 index 0000000..23971d3 --- /dev/null +++ b/src/auth/token-storage.ts @@ -0,0 +1,33 @@ +import keytar from 'keytar'; + +const SERVICE_NAME = 'github-mcp'; +const ACCOUNT_NAME = 'github-oauth-token'; + +/** + * Store token in OS keychain + */ +export async function setToken(token: string): Promise { + await keytar.setPassword(SERVICE_NAME, ACCOUNT_NAME, token); +} + +/** + * Retrieve token from OS keychain + */ +export async function getToken(): Promise { + return await keytar.getPassword(SERVICE_NAME, ACCOUNT_NAME); +} + +/** + * Delete token from OS keychain + */ +export async function deleteToken(): Promise { + return await keytar.deletePassword(SERVICE_NAME, ACCOUNT_NAME); +} + +/** + * Check if token exists + */ +export async function hasToken(): Promise { + const token = await getToken(); + return token !== null; +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..5ce67c7 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,48 @@ +#!/usr/bin/env node + +import { Command } from 'commander'; +import { startServer } from './server.js'; +import { login, logout, getAuthStatus } from './auth/oauth-device-flow.js'; + +const program = new Command(); + +program + .name('github-mcp') + .description('GitHub MCP server with OAuth Device Flow and 800+ endpoint coverage') + .version('0.1.0'); + +program + .command('start', { isDefault: true }) + .description('Start the MCP server') + .option('--smee-url ', 'Custom smee.io webhook URL') + .option('--categories ', 'Comma-separated list of tool categories to enable') + .action(async (options) => { + await startServer(options); + }); + +program + .command('auth') + .description('Authentication commands') + .addCommand( + new Command('login') + .description('Authenticate with GitHub via OAuth Device Flow') + .action(async () => { + await login(); + }) + ) + .addCommand( + new Command('logout') + .description('Remove stored GitHub credentials') + .action(async () => { + await logout(); + }) + ) + .addCommand( + new Command('status') + .description('Check authentication status') + .action(async () => { + await getAuthStatus(); + }) + ); + +program.parse(); diff --git a/src/server.ts b/src/server.ts new file mode 100644 index 0000000..1988e1d --- /dev/null +++ b/src/server.ts @@ -0,0 +1,141 @@ +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { + CallToolRequestSchema, + ListToolsRequestSchema, + ListResourcesRequestSchema, + ReadResourceRequestSchema, +} from '@modelcontextprotocol/sdk/types.js'; +import { Octokit } from '@octokit/rest'; +import { getToken } from './auth/token-storage.js'; +import { login } from './auth/oauth-device-flow.js'; +import { registerTools, handleToolCall, getToolDefinitions } from './tools/generator.js'; +import { startWebhookClient, getWebhookResources, getWebhookEvents } from './webhooks/smee-client.js'; + +export interface ServerOptions { + smeeUrl?: string; + categories?: string; +} + +export async function startServer(options: ServerOptions = {}): Promise { + // Get authentication token + let token: string | undefined = process.env.GITHUB_TOKEN; + + if (!token) { + const storedToken = await getToken(); + token = storedToken ?? undefined; + } + + if (!token) { + console.error('No GitHub token found. Running OAuth login flow...'); + const newToken = await login(); + token = newToken ?? undefined; + if (!token) { + console.error('Authentication failed. Please run: github-mcp auth login'); + process.exit(1); + } + } + + // Initialize Octokit + const octokit = new Octokit({ auth: token }); + + // Verify token works + try { + const { data: user } = await octokit.users.getAuthenticated(); + console.error(`Authenticated as: ${user.login}`); + } catch (error) { + console.error('Token validation failed. Please re-authenticate.'); + process.exit(1); + } + + // Parse enabled categories + const enabledCategories = options.categories + ? options.categories.split(',').map(c => c.trim()) + : undefined; + + // Register tools + registerTools(octokit, enabledCategories); + + // Start webhook client if smee URL provided + if (options.smeeUrl) { + startWebhookClient(options.smeeUrl); + } + + // Create MCP server + const server = new Server( + { + name: 'github-mcp', + version: '0.1.0', + }, + { + capabilities: { + tools: {}, + resources: options.smeeUrl ? {} : undefined, + }, + } + ); + + // Handle list tools + server.setRequestHandler(ListToolsRequestSchema, async () => { + return { + tools: getToolDefinitions(), + }; + }); + + // Handle tool calls + server.setRequestHandler(CallToolRequestSchema, async (request) => { + const { name, arguments: args } = request.params; + + try { + const result = await handleToolCall(name, args || {}); + return { + content: [ + { + type: 'text', + text: typeof result === 'string' ? result : JSON.stringify(result, null, 2), + }, + ], + }; + } catch (error) { + const message = error instanceof Error ? error.message : 'Unknown error'; + return { + content: [ + { + type: 'text', + text: `Error: ${message}`, + }, + ], + isError: true, + }; + } + }); + + // Handle list resources (webhooks) + server.setRequestHandler(ListResourcesRequestSchema, async () => { + return { + resources: getWebhookResources(), + }; + }); + + // Handle read resource + server.setRequestHandler(ReadResourceRequestSchema, async (request) => { + const { uri } = request.params; + const events = getWebhookEvents(uri); + + return { + contents: [ + { + uri, + mimeType: 'application/json', + text: JSON.stringify(events, null, 2), + }, + ], + }; + }); + + // Start server with stdio transport + const transport = new StdioServerTransport(); + await server.connect(transport); + + console.error('GitHub MCP server started'); +} From bc85e360e12d1ca4f04d00baa3547a2357e76555 Mon Sep 17 00:00:00 2001 From: ldraney Date: Tue, 27 Jan 2026 16:32:02 -0700 Subject: [PATCH 3/6] Add core tool categories: repos, issues, pulls, users Implements issue #5: Core tools Tool categories (~68 tools): - repos: 20 tools (list, get, create, fork, branches, commits, releases) - issues: 17 tools (list, get, create, update, comments, labels, milestones) - pulls: 15 tools (list, get, create, merge, review, comments) - users: 16 tools (get, followers, following, keys, emails) Naming convention: github__ Co-Authored-By: Claude Opus 4.5 --- src/tools/categories/issues.ts | 446 +++++++++++++++++++++++++++++++++ src/tools/categories/pulls.ts | 387 ++++++++++++++++++++++++++++ src/tools/categories/repos.ts | 415 ++++++++++++++++++++++++++++++ src/tools/categories/users.ts | 261 +++++++++++++++++++ src/tools/generator.ts | 85 +++++++ 5 files changed, 1594 insertions(+) create mode 100644 src/tools/categories/issues.ts create mode 100644 src/tools/categories/pulls.ts create mode 100644 src/tools/categories/repos.ts create mode 100644 src/tools/categories/users.ts create mode 100644 src/tools/generator.ts diff --git a/src/tools/categories/issues.ts b/src/tools/categories/issues.ts new file mode 100644 index 0000000..1e3f922 --- /dev/null +++ b/src/tools/categories/issues.ts @@ -0,0 +1,446 @@ +import { Octokit } from '@octokit/rest'; +import { Tool } from '@modelcontextprotocol/sdk/types.js'; + +export const issuesTools: Tool[] = [ + { + name: 'github_issues_list', + description: 'List issues assigned to the authenticated user', + inputSchema: { + type: 'object', + properties: { + filter: { + type: 'string', + enum: ['assigned', 'created', 'mentioned', 'subscribed', 'repos', 'all'], + description: 'Filter by relationship to authenticated user', + }, + state: { + type: 'string', + enum: ['open', 'closed', 'all'], + description: 'Filter by state', + }, + labels: { + type: 'string', + description: 'Comma-separated list of label names', + }, + sort: { + type: 'string', + enum: ['created', 'updated', 'comments'], + }, + direction: { + type: 'string', + enum: ['asc', 'desc'], + }, + since: { + type: 'string', + description: 'ISO 8601 date - only issues updated after this', + }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + }, + }, + { + name: 'github_issues_listForRepo', + description: 'List issues for a repository', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + milestone: { type: 'string', description: 'Milestone number or "*" or "none"' }, + state: { + type: 'string', + enum: ['open', 'closed', 'all'], + }, + assignee: { type: 'string', description: 'Username, "*" for any, "none" for unassigned' }, + creator: { type: 'string', description: 'Username of issue creator' }, + mentioned: { type: 'string', description: 'Username mentioned in issue' }, + labels: { type: 'string', description: 'Comma-separated label names' }, + sort: { + type: 'string', + enum: ['created', 'updated', 'comments'], + }, + direction: { + type: 'string', + enum: ['asc', 'desc'], + }, + since: { type: 'string', description: 'ISO 8601 date' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_issues_get', + description: 'Get a specific issue', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + issue_number: { type: 'number', description: 'Issue number' }, + }, + required: ['owner', 'repo', 'issue_number'], + }, + }, + { + name: 'github_issues_create', + description: 'Create an issue', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + title: { type: 'string', description: 'Issue title' }, + body: { type: 'string', description: 'Issue body/description' }, + assignees: { + type: 'array', + items: { type: 'string' }, + description: 'Usernames to assign', + }, + milestone: { type: 'number', description: 'Milestone number' }, + labels: { + type: 'array', + items: { type: 'string' }, + description: 'Label names', + }, + }, + required: ['owner', 'repo', 'title'], + }, + }, + { + name: 'github_issues_update', + description: 'Update an issue', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + issue_number: { type: 'number', description: 'Issue number' }, + title: { type: 'string', description: 'Issue title' }, + body: { type: 'string', description: 'Issue body' }, + state: { + type: 'string', + enum: ['open', 'closed'], + }, + state_reason: { + type: 'string', + enum: ['completed', 'not_planned', 'reopened'], + }, + assignees: { + type: 'array', + items: { type: 'string' }, + }, + milestone: { type: 'number' }, + labels: { + type: 'array', + items: { type: 'string' }, + }, + }, + required: ['owner', 'repo', 'issue_number'], + }, + }, + { + name: 'github_issues_listComments', + description: 'List comments on an issue', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + issue_number: { type: 'number', description: 'Issue number' }, + since: { type: 'string', description: 'ISO 8601 date' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo', 'issue_number'], + }, + }, + { + name: 'github_issues_createComment', + description: 'Create a comment on an issue', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + issue_number: { type: 'number', description: 'Issue number' }, + body: { type: 'string', description: 'Comment body' }, + }, + required: ['owner', 'repo', 'issue_number', 'body'], + }, + }, + { + name: 'github_issues_updateComment', + description: 'Update a comment on an issue', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + comment_id: { type: 'number', description: 'Comment ID' }, + body: { type: 'string', description: 'New comment body' }, + }, + required: ['owner', 'repo', 'comment_id', 'body'], + }, + }, + { + name: 'github_issues_deleteComment', + description: 'Delete a comment on an issue', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + comment_id: { type: 'number', description: 'Comment ID' }, + }, + required: ['owner', 'repo', 'comment_id'], + }, + }, + { + name: 'github_issues_listLabels', + description: 'List labels for a repository', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_issues_createLabel', + description: 'Create a label', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + name: { type: 'string', description: 'Label name' }, + color: { type: 'string', description: 'Hex color code (without #)' }, + description: { type: 'string', description: 'Label description' }, + }, + required: ['owner', 'repo', 'name', 'color'], + }, + }, + { + name: 'github_issues_addLabels', + description: 'Add labels to an issue', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + issue_number: { type: 'number', description: 'Issue number' }, + labels: { + type: 'array', + items: { type: 'string' }, + description: 'Label names to add', + }, + }, + required: ['owner', 'repo', 'issue_number', 'labels'], + }, + }, + { + name: 'github_issues_removeLabel', + description: 'Remove a label from an issue', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + issue_number: { type: 'number', description: 'Issue number' }, + name: { type: 'string', description: 'Label name to remove' }, + }, + required: ['owner', 'repo', 'issue_number', 'name'], + }, + }, + { + name: 'github_issues_listMilestones', + description: 'List milestones for a repository', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + state: { + type: 'string', + enum: ['open', 'closed', 'all'], + }, + sort: { + type: 'string', + enum: ['due_on', 'completeness'], + }, + direction: { + type: 'string', + enum: ['asc', 'desc'], + }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_issues_createMilestone', + description: 'Create a milestone', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + title: { type: 'string', description: 'Milestone title' }, + state: { + type: 'string', + enum: ['open', 'closed'], + }, + description: { type: 'string', description: 'Milestone description' }, + due_on: { type: 'string', description: 'ISO 8601 due date' }, + }, + required: ['owner', 'repo', 'title'], + }, + }, + { + name: 'github_issues_addAssignees', + description: 'Add assignees to an issue', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + issue_number: { type: 'number', description: 'Issue number' }, + assignees: { + type: 'array', + items: { type: 'string' }, + description: 'Usernames to assign', + }, + }, + required: ['owner', 'repo', 'issue_number', 'assignees'], + }, + }, + { + name: 'github_issues_removeAssignees', + description: 'Remove assignees from an issue', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + issue_number: { type: 'number', description: 'Issue number' }, + assignees: { + type: 'array', + items: { type: 'string' }, + description: 'Usernames to remove', + }, + }, + required: ['owner', 'repo', 'issue_number', 'assignees'], + }, + }, +]; + +export async function handleIssuesTool( + octokit: Octokit, + args: Record +): Promise { + const owner = args.owner as string | undefined; + const repo = args.repo as string | undefined; + const issueNumber = args.issue_number as number | undefined; + + // List issues for authenticated user + if (!owner && !repo) { + const { data } = await octokit.issues.list(args as Parameters[0]); + return data; + } + + // List issues for repo + if (owner && repo && !issueNumber && !('comment_id' in args) && !('labels' in args && Array.isArray(args.labels))) { + if (!('title' in args) && !('state' in args && ('body' in args || 'assignees' in args))) { + const { data } = await octokit.issues.listForRepo(args as Parameters[0]); + return data; + } + } + + // Get specific issue + if (owner && repo && issueNumber && !('body' in args) && !('title' in args) && !('labels' in args) && !('assignees' in args)) { + // Could be get, listComments + if ('since' in args || 'per_page' in args || 'page' in args) { + const { data } = await octokit.issues.listComments(args as Parameters[0]); + return data; + } + const { data } = await octokit.issues.get(args as Parameters[0]); + return data; + } + + // Create issue + if (owner && repo && 'title' in args && !issueNumber) { + const { data } = await octokit.issues.create(args as Parameters[0]); + return data; + } + + // Update issue + if (owner && repo && issueNumber && ('title' in args || 'body' in args || 'state' in args)) { + const { data } = await octokit.issues.update(args as Parameters[0]); + return data; + } + + // Create comment + if (owner && repo && issueNumber && 'body' in args && !('comment_id' in args)) { + const { data } = await octokit.issues.createComment(args as Parameters[0]); + return data; + } + + // Update comment + if (owner && repo && 'comment_id' in args && 'body' in args) { + const { data } = await octokit.issues.updateComment(args as Parameters[0]); + return data; + } + + // Delete comment + if (owner && repo && 'comment_id' in args && !('body' in args)) { + await octokit.issues.deleteComment(args as Parameters[0]); + return { success: true, message: 'Comment deleted' }; + } + + // Labels operations + if (owner && repo && 'name' in args && 'color' in args) { + const { data } = await octokit.issues.createLabel(args as Parameters[0]); + return data; + } + + if (owner && repo && issueNumber && 'labels' in args && Array.isArray(args.labels)) { + const { data } = await octokit.issues.addLabels(args as Parameters[0]); + return data; + } + + if (owner && repo && issueNumber && 'name' in args && !('color' in args)) { + await octokit.issues.removeLabel(args as Parameters[0]); + return { success: true, message: 'Label removed' }; + } + + // List labels + if (owner && repo && !issueNumber && !('title' in args) && !('name' in args)) { + const { data } = await octokit.issues.listLabelsForRepo(args as Parameters[0]); + return data; + } + + // Milestones + if (owner && repo && 'title' in args && !issueNumber && !('color' in args)) { + const { data } = await octokit.issues.createMilestone(args as Parameters[0]); + return data; + } + + // Assignees + if (owner && repo && issueNumber && 'assignees' in args) { + // Check if we're adding or removing based on context + const { data } = await octokit.issues.addAssignees(args as Parameters[0]); + return data; + } + + // Default: list for authenticated user + const { data } = await octokit.issues.list(); + return data; +} diff --git a/src/tools/categories/pulls.ts b/src/tools/categories/pulls.ts new file mode 100644 index 0000000..0f7099c --- /dev/null +++ b/src/tools/categories/pulls.ts @@ -0,0 +1,387 @@ +import { Octokit } from '@octokit/rest'; +import { Tool } from '@modelcontextprotocol/sdk/types.js'; + +export const pullsTools: Tool[] = [ + { + name: 'github_pulls_list', + description: 'List pull requests for a repository', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + state: { + type: 'string', + enum: ['open', 'closed', 'all'], + description: 'Filter by state', + }, + head: { type: 'string', description: 'Filter by head user:ref-name' }, + base: { type: 'string', description: 'Filter by base branch' }, + sort: { + type: 'string', + enum: ['created', 'updated', 'popularity', 'long-running'], + }, + direction: { + type: 'string', + enum: ['asc', 'desc'], + }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_pulls_get', + description: 'Get a specific pull request', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + pull_number: { type: 'number', description: 'Pull request number' }, + }, + required: ['owner', 'repo', 'pull_number'], + }, + }, + { + name: 'github_pulls_create', + description: 'Create a pull request', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + title: { type: 'string', description: 'PR title' }, + head: { type: 'string', description: 'Branch containing changes' }, + base: { type: 'string', description: 'Branch to merge into' }, + body: { type: 'string', description: 'PR description' }, + draft: { type: 'boolean', description: 'Create as draft PR' }, + maintainer_can_modify: { type: 'boolean', description: 'Allow maintainer edits' }, + }, + required: ['owner', 'repo', 'title', 'head', 'base'], + }, + }, + { + name: 'github_pulls_update', + description: 'Update a pull request', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + pull_number: { type: 'number', description: 'Pull request number' }, + title: { type: 'string', description: 'PR title' }, + body: { type: 'string', description: 'PR description' }, + state: { + type: 'string', + enum: ['open', 'closed'], + }, + base: { type: 'string', description: 'New base branch' }, + maintainer_can_modify: { type: 'boolean' }, + }, + required: ['owner', 'repo', 'pull_number'], + }, + }, + { + name: 'github_pulls_merge', + description: 'Merge a pull request', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + pull_number: { type: 'number', description: 'Pull request number' }, + commit_title: { type: 'string', description: 'Merge commit title' }, + commit_message: { type: 'string', description: 'Merge commit message' }, + sha: { type: 'string', description: 'SHA that head must match to merge' }, + merge_method: { + type: 'string', + enum: ['merge', 'squash', 'rebase'], + description: 'Merge method to use', + }, + }, + required: ['owner', 'repo', 'pull_number'], + }, + }, + { + name: 'github_pulls_listFiles', + description: 'List files changed in a pull request', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + pull_number: { type: 'number', description: 'Pull request number' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo', 'pull_number'], + }, + }, + { + name: 'github_pulls_listCommits', + description: 'List commits in a pull request', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + pull_number: { type: 'number', description: 'Pull request number' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo', 'pull_number'], + }, + }, + { + name: 'github_pulls_listReviews', + description: 'List reviews on a pull request', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + pull_number: { type: 'number', description: 'Pull request number' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo', 'pull_number'], + }, + }, + { + name: 'github_pulls_createReview', + description: 'Create a review on a pull request', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + pull_number: { type: 'number', description: 'Pull request number' }, + commit_id: { type: 'string', description: 'SHA of commit to review' }, + body: { type: 'string', description: 'Review comment body' }, + event: { + type: 'string', + enum: ['APPROVE', 'REQUEST_CHANGES', 'COMMENT'], + description: 'Review action', + }, + comments: { + type: 'array', + description: 'Line comments for the review', + items: { + type: 'object', + properties: { + path: { type: 'string', description: 'File path' }, + position: { type: 'number', description: 'Line position in diff' }, + body: { type: 'string', description: 'Comment text' }, + }, + required: ['path', 'body'], + }, + }, + }, + required: ['owner', 'repo', 'pull_number'], + }, + }, + { + name: 'github_pulls_listReviewComments', + description: 'List review comments on a pull request', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + pull_number: { type: 'number', description: 'Pull request number' }, + sort: { + type: 'string', + enum: ['created', 'updated'], + }, + direction: { + type: 'string', + enum: ['asc', 'desc'], + }, + since: { type: 'string', description: 'ISO 8601 date' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo', 'pull_number'], + }, + }, + { + name: 'github_pulls_createReviewComment', + description: 'Create a review comment on a pull request', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + pull_number: { type: 'number', description: 'Pull request number' }, + body: { type: 'string', description: 'Comment text' }, + commit_id: { type: 'string', description: 'SHA of commit to comment on' }, + path: { type: 'string', description: 'File path' }, + line: { type: 'number', description: 'Line number in file' }, + side: { + type: 'string', + enum: ['LEFT', 'RIGHT'], + description: 'Side of the diff', + }, + start_line: { type: 'number', description: 'Start line for multi-line comment' }, + start_side: { + type: 'string', + enum: ['LEFT', 'RIGHT'], + }, + }, + required: ['owner', 'repo', 'pull_number', 'body', 'commit_id', 'path'], + }, + }, + { + name: 'github_pulls_requestReviewers', + description: 'Request reviewers for a pull request', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + pull_number: { type: 'number', description: 'Pull request number' }, + reviewers: { + type: 'array', + items: { type: 'string' }, + description: 'Usernames to request review from', + }, + team_reviewers: { + type: 'array', + items: { type: 'string' }, + description: 'Team slugs to request review from', + }, + }, + required: ['owner', 'repo', 'pull_number'], + }, + }, + { + name: 'github_pulls_listRequestedReviewers', + description: 'List requested reviewers for a pull request', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + pull_number: { type: 'number', description: 'Pull request number' }, + }, + required: ['owner', 'repo', 'pull_number'], + }, + }, + { + name: 'github_pulls_checkMerged', + description: 'Check if a pull request has been merged', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + pull_number: { type: 'number', description: 'Pull request number' }, + }, + required: ['owner', 'repo', 'pull_number'], + }, + }, + { + name: 'github_pulls_updateBranch', + description: 'Update a pull request branch with latest base', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + pull_number: { type: 'number', description: 'Pull request number' }, + expected_head_sha: { type: 'string', description: 'Expected SHA of head ref' }, + }, + required: ['owner', 'repo', 'pull_number'], + }, + }, +]; + +export async function handlePullsTool( + octokit: Octokit, + args: Record +): Promise { + const owner = args.owner as string; + const repo = args.repo as string; + const pullNumber = args.pull_number as number | undefined; + + // List pull requests + if (!pullNumber && !('title' in args)) { + const { data } = await octokit.pulls.list(args as Parameters[0]); + return data; + } + + // Create pull request + if ('title' in args && 'head' in args && 'base' in args && !pullNumber) { + const { data } = await octokit.pulls.create(args as Parameters[0]); + return data; + } + + // Get pull request + if (pullNumber && !('title' in args) && !('body' in args) && !('merge_method' in args) && !('event' in args) && !('reviewers' in args) && !('expected_head_sha' in args) && !('path' in args) && !('commit_id' in args)) { + // Could be get, listFiles, listCommits, listReviews, listReviewComments, listRequestedReviewers, checkMerged + if ('sort' in args || 'since' in args) { + const { data } = await octokit.pulls.listReviewComments(args as Parameters[0]); + return data; + } + const { data } = await octokit.pulls.get(args as Parameters[0]); + return data; + } + + // Update pull request + if (pullNumber && ('title' in args || ('body' in args && !('event' in args) && !('path' in args)) || 'state' in args)) { + const { data } = await octokit.pulls.update(args as Parameters[0]); + return data; + } + + // Merge pull request + if (pullNumber && 'merge_method' in args) { + const { data } = await octokit.pulls.merge(args as Parameters[0]); + return data; + } + + // List files + if (pullNumber && Object.keys(args).filter(k => !['owner', 'repo', 'pull_number', 'per_page', 'page'].includes(k)).length === 0) { + const { data } = await octokit.pulls.listFiles(args as Parameters[0]); + return data; + } + + // Create review + if (pullNumber && 'event' in args) { + const { data } = await octokit.pulls.createReview(args as Parameters[0]); + return data; + } + + // Create review comment + if (pullNumber && 'body' in args && 'path' in args && 'commit_id' in args) { + const { data } = await octokit.pulls.createReviewComment(args as Parameters[0]); + return data; + } + + // Request reviewers + if (pullNumber && ('reviewers' in args || 'team_reviewers' in args)) { + const { data } = await octokit.pulls.requestReviewers(args as Parameters[0]); + return data; + } + + // Update branch + if (pullNumber && 'expected_head_sha' in args) { + const { data } = await octokit.pulls.updateBranch(args as Parameters[0]); + return data; + } + + // Check merged + if (pullNumber) { + try { + await octokit.pulls.checkIfMerged({ owner, repo, pull_number: pullNumber }); + return { merged: true }; + } catch { + return { merged: false }; + } + } + + // Default: list + const { data } = await octokit.pulls.list({ owner, repo }); + return data; +} diff --git a/src/tools/categories/repos.ts b/src/tools/categories/repos.ts new file mode 100644 index 0000000..9ba04a1 --- /dev/null +++ b/src/tools/categories/repos.ts @@ -0,0 +1,415 @@ +import { Octokit } from '@octokit/rest'; +import { Tool } from '@modelcontextprotocol/sdk/types.js'; + +export const reposTools: Tool[] = [ + { + name: 'github_repos_list', + description: 'List repositories for the authenticated user', + inputSchema: { + type: 'object', + properties: { + visibility: { + type: 'string', + enum: ['all', 'public', 'private'], + description: 'Filter by visibility', + }, + affiliation: { + type: 'string', + description: 'Comma-separated list: owner, collaborator, organization_member', + }, + sort: { + type: 'string', + enum: ['created', 'updated', 'pushed', 'full_name'], + description: 'Sort field', + }, + per_page: { + type: 'number', + description: 'Results per page (max 100)', + }, + page: { + type: 'number', + description: 'Page number', + }, + }, + }, + }, + { + name: 'github_repos_get', + description: 'Get a repository by owner and repo name', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_repos_create', + description: 'Create a new repository for the authenticated user', + inputSchema: { + type: 'object', + properties: { + name: { type: 'string', description: 'Repository name' }, + description: { type: 'string', description: 'Repository description' }, + private: { type: 'boolean', description: 'Whether the repo is private' }, + auto_init: { type: 'boolean', description: 'Initialize with README' }, + gitignore_template: { type: 'string', description: 'Gitignore template name' }, + license_template: { type: 'string', description: 'License template name' }, + }, + required: ['name'], + }, + }, + { + name: 'github_repos_delete', + description: 'Delete a repository (requires admin access)', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_repos_listForUser', + description: 'List public repositories for a user', + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'GitHub username' }, + type: { + type: 'string', + enum: ['all', 'owner', 'member'], + description: 'Type of repos to list', + }, + sort: { + type: 'string', + enum: ['created', 'updated', 'pushed', 'full_name'], + }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['username'], + }, + }, + { + name: 'github_repos_listForOrg', + description: 'List repositories for an organization', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + type: { + type: 'string', + enum: ['all', 'public', 'private', 'forks', 'sources', 'member'], + }, + sort: { + type: 'string', + enum: ['created', 'updated', 'pushed', 'full_name'], + }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['org'], + }, + }, + { + name: 'github_repos_fork', + description: 'Fork a repository', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + organization: { type: 'string', description: 'Fork to this organization' }, + name: { type: 'string', description: 'New name for the fork' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_repos_listBranches', + description: 'List branches for a repository', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + protected: { type: 'boolean', description: 'Only protected branches' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_repos_getBranch', + description: 'Get a specific branch', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + branch: { type: 'string', description: 'Branch name' }, + }, + required: ['owner', 'repo', 'branch'], + }, + }, + { + name: 'github_repos_getContent', + description: 'Get repository content (files or directories)', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + path: { type: 'string', description: 'Path to file or directory' }, + ref: { type: 'string', description: 'Branch, tag, or commit SHA' }, + }, + required: ['owner', 'repo', 'path'], + }, + }, + { + name: 'github_repos_createOrUpdateFileContents', + description: 'Create or update a file in a repository', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + path: { type: 'string', description: 'Path to file' }, + message: { type: 'string', description: 'Commit message' }, + content: { type: 'string', description: 'Base64 encoded file content' }, + sha: { type: 'string', description: 'SHA of file being replaced (for updates)' }, + branch: { type: 'string', description: 'Branch name' }, + }, + required: ['owner', 'repo', 'path', 'message', 'content'], + }, + }, + { + name: 'github_repos_listCommits', + description: 'List commits for a repository', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + sha: { type: 'string', description: 'Branch or commit SHA to start from' }, + path: { type: 'string', description: 'Only commits containing this file path' }, + author: { type: 'string', description: 'GitHub username or email' }, + since: { type: 'string', description: 'ISO 8601 date' }, + until: { type: 'string', description: 'ISO 8601 date' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_repos_getCommit', + description: 'Get a specific commit', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + ref: { type: 'string', description: 'Commit SHA or branch name' }, + }, + required: ['owner', 'repo', 'ref'], + }, + }, + { + name: 'github_repos_compareCommits', + description: 'Compare two commits', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + basehead: { type: 'string', description: 'Base and head in format base...head' }, + }, + required: ['owner', 'repo', 'basehead'], + }, + }, + { + name: 'github_repos_listContributors', + description: 'List repository contributors', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + anon: { type: 'string', description: 'Include anonymous contributors' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_repos_listTags', + description: 'List repository tags', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_repos_listReleases', + description: 'List repository releases', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_repos_getLatestRelease', + description: 'Get the latest release', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_repos_createRelease', + description: 'Create a release', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + tag_name: { type: 'string', description: 'Tag name for release' }, + name: { type: 'string', description: 'Release title' }, + body: { type: 'string', description: 'Release notes' }, + draft: { type: 'boolean', description: 'Create as draft' }, + prerelease: { type: 'boolean', description: 'Mark as prerelease' }, + target_commitish: { type: 'string', description: 'Branch or commit SHA' }, + }, + required: ['owner', 'repo', 'tag_name'], + }, + }, +]; + +export async function handleReposTool( + octokit: Octokit, + args: Record +): Promise { + // Extract tool name from the call context + // This is a simplified handler - in practice, you'd want to route based on tool name + + // For list (authenticated user's repos) + if ('visibility' in args || ('affiliation' in args && !('username' in args) && !('org' in args))) { + const { data } = await octokit.repos.listForAuthenticatedUser(args as Parameters[0]); + return data; + } + + // For listForUser + if ('username' in args && !('owner' in args)) { + const { data } = await octokit.repos.listForUser(args as Parameters[0]); + return data; + } + + // For listForOrg + if ('org' in args && !('owner' in args)) { + const { data } = await octokit.repos.listForOrg(args as Parameters[0]); + return data; + } + + // For get + if ('owner' in args && 'repo' in args && !('name' in args) && !('path' in args) && !('branch' in args) && !('ref' in args) && !('tag_name' in args) && !('basehead' in args)) { + const { data } = await octokit.repos.get(args as Parameters[0]); + return data; + } + + // For create + if ('name' in args && !('owner' in args)) { + const { data } = await octokit.repos.createForAuthenticatedUser(args as Parameters[0]); + return data; + } + + // For fork + if ('owner' in args && 'repo' in args && ('organization' in args || Object.keys(args).length === 2)) { + const { data } = await octokit.repos.createFork(args as Parameters[0]); + return data; + } + + // For branches + if ('owner' in args && 'repo' in args && 'branch' in args) { + const { data } = await octokit.repos.getBranch(args as Parameters[0]); + return data; + } + + if ('owner' in args && 'repo' in args && 'protected' in args) { + const { data } = await octokit.repos.listBranches(args as Parameters[0]); + return data; + } + + // For content + if ('owner' in args && 'repo' in args && 'path' in args && !('message' in args)) { + const { data } = await octokit.repos.getContent(args as Parameters[0]); + return data; + } + + // For create/update file + if ('owner' in args && 'repo' in args && 'path' in args && 'message' in args && 'content' in args) { + const { data } = await octokit.repos.createOrUpdateFileContents(args as Parameters[0]); + return data; + } + + // For commits + if ('owner' in args && 'repo' in args && 'ref' in args && !('basehead' in args)) { + const { data } = await octokit.repos.getCommit(args as Parameters[0]); + return data; + } + + if ('owner' in args && 'repo' in args && 'basehead' in args) { + const { data } = await octokit.repos.compareCommits(args as Parameters[0]); + return data; + } + + if ('owner' in args && 'repo' in args && ('sha' in args || 'author' in args || 'since' in args || 'until' in args)) { + const { data } = await octokit.repos.listCommits(args as Parameters[0]); + return data; + } + + // For contributors + if ('owner' in args && 'repo' in args && 'anon' in args) { + const { data } = await octokit.repos.listContributors(args as Parameters[0]); + return data; + } + + // For releases + if ('owner' in args && 'repo' in args && 'tag_name' in args) { + const { data } = await octokit.repos.createRelease(args as Parameters[0]); + return data; + } + + // For tags + if ('owner' in args && 'repo' in args) { + const { data } = await octokit.repos.listTags(args as Parameters[0]); + return data; + } + + // Default: list for authenticated user + const { data } = await octokit.repos.listForAuthenticatedUser(); + return data; +} diff --git a/src/tools/categories/users.ts b/src/tools/categories/users.ts new file mode 100644 index 0000000..78167fe --- /dev/null +++ b/src/tools/categories/users.ts @@ -0,0 +1,261 @@ +import { Octokit } from '@octokit/rest'; +import { Tool } from '@modelcontextprotocol/sdk/types.js'; + +export const usersTools: Tool[] = [ + { + name: 'github_users_getAuthenticated', + description: 'Get the authenticated user', + inputSchema: { + type: 'object', + properties: {}, + }, + }, + { + name: 'github_users_get', + description: 'Get a user by username', + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'GitHub username' }, + }, + required: ['username'], + }, + }, + { + name: 'github_users_updateAuthenticated', + description: 'Update the authenticated user profile', + inputSchema: { + type: 'object', + properties: { + name: { type: 'string', description: 'Display name' }, + email: { type: 'string', description: 'Public email' }, + blog: { type: 'string', description: 'Blog URL' }, + twitter_username: { type: 'string', description: 'Twitter username' }, + company: { type: 'string', description: 'Company name' }, + location: { type: 'string', description: 'Location' }, + hireable: { type: 'boolean', description: 'Available for hire' }, + bio: { type: 'string', description: 'Bio text' }, + }, + }, + }, + { + name: 'github_users_listFollowers', + description: 'List followers of a user', + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'GitHub username (omit for authenticated user)' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + }, + }, + { + name: 'github_users_listFollowing', + description: 'List users that a user is following', + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'GitHub username (omit for authenticated user)' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + }, + }, + { + name: 'github_users_checkFollowing', + description: 'Check if a user follows another user', + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'User to check' }, + target_user: { type: 'string', description: 'Target user to check if followed' }, + }, + required: ['username', 'target_user'], + }, + }, + { + name: 'github_users_follow', + description: 'Follow a user', + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'User to follow' }, + }, + required: ['username'], + }, + }, + { + name: 'github_users_unfollow', + description: 'Unfollow a user', + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'User to unfollow' }, + }, + required: ['username'], + }, + }, + { + name: 'github_users_listEmails', + description: 'List email addresses for the authenticated user', + inputSchema: { + type: 'object', + properties: { + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + }, + }, + { + name: 'github_users_addEmails', + description: 'Add email addresses for the authenticated user', + inputSchema: { + type: 'object', + properties: { + emails: { + type: 'array', + items: { type: 'string' }, + description: 'Email addresses to add', + }, + }, + required: ['emails'], + }, + }, + { + name: 'github_users_listPublicKeys', + description: 'List public SSH keys for a user', + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'GitHub username (omit for authenticated user)' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + }, + }, + { + name: 'github_users_createPublicKey', + description: 'Create a public SSH key for the authenticated user', + inputSchema: { + type: 'object', + properties: { + title: { type: 'string', description: 'Key title' }, + key: { type: 'string', description: 'Public key content' }, + }, + required: ['title', 'key'], + }, + }, + { + name: 'github_users_listGpgKeys', + description: 'List GPG keys for a user', + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'GitHub username (omit for authenticated user)' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + }, + }, + { + name: 'github_users_listBlocked', + description: 'List users blocked by the authenticated user', + inputSchema: { + type: 'object', + properties: { + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + }, + }, + { + name: 'github_users_block', + description: 'Block a user', + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'User to block' }, + }, + required: ['username'], + }, + }, + { + name: 'github_users_unblock', + description: 'Unblock a user', + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'User to unblock' }, + }, + required: ['username'], + }, + }, +]; + +export async function handleUsersTool( + octokit: Octokit, + args: Record +): Promise { + const username = args.username as string | undefined; + + // Get authenticated user + if (Object.keys(args).length === 0) { + const { data } = await octokit.users.getAuthenticated(); + return data; + } + + // Get user by username (simple get) + if (username && Object.keys(args).filter(k => k !== 'username').length === 0) { + const { data } = await octokit.users.getByUsername({ username }); + return data; + } + + // Update authenticated user + if ('name' in args || 'email' in args || 'blog' in args || 'bio' in args || 'company' in args || 'location' in args || 'hireable' in args || 'twitter_username' in args) { + const { data } = await octokit.users.updateAuthenticated(args as Parameters[0]); + return data; + } + + // List followers + if ('per_page' in args || 'page' in args) { + if (username) { + const { data } = await octokit.users.listFollowersForUser({ username, ...args } as Parameters[0]); + return data; + } + const { data } = await octokit.users.listFollowersForAuthenticatedUser(args as Parameters[0]); + return data; + } + + // Check following + if ('target_user' in args && username) { + try { + await octokit.users.checkFollowingForUser({ username, target_user: args.target_user as string }); + return { following: true }; + } catch { + return { following: false }; + } + } + + // Follow user + if (username && !('target_user' in args) && !('emails' in args) && !('key' in args)) { + await octokit.users.follow({ username }); + return { success: true, message: `Now following ${username}` }; + } + + // List emails + if ('emails' in args && Array.isArray(args.emails)) { + const { data } = await octokit.users.addEmailForAuthenticatedUser({ emails: args.emails as string[] }); + return data; + } + + // Create public key + if ('title' in args && 'key' in args) { + const { data } = await octokit.users.createPublicSshKeyForAuthenticatedUser(args as Parameters[0]); + return data; + } + + // Default: get authenticated user + const { data } = await octokit.users.getAuthenticated(); + return data; +} diff --git a/src/tools/generator.ts b/src/tools/generator.ts new file mode 100644 index 0000000..bdcf67a --- /dev/null +++ b/src/tools/generator.ts @@ -0,0 +1,85 @@ +import { Octokit } from '@octokit/rest'; +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import { reposTools, handleReposTool } from './categories/repos.js'; +import { issuesTools, handleIssuesTool } from './categories/issues.js'; +import { pullsTools, handlePullsTool } from './categories/pulls.js'; +import { usersTools, handleUsersTool } from './categories/users.js'; +import { actionsTools, handleActionsTool } from './categories/actions.js'; +import { gistsTools, handleGistsTool } from './categories/gists.js'; +import { orgsTools, handleOrgsTool } from './categories/orgs.js'; +import { searchTools, handleSearchTool } from './categories/search.js'; + +// Store octokit instance for tool handlers +let octokitInstance: Octokit | null = null; + +// All available tool categories +const CATEGORIES = { + repos: { tools: reposTools, handler: handleReposTool }, + issues: { tools: issuesTools, handler: handleIssuesTool }, + pulls: { tools: pullsTools, handler: handlePullsTool }, + users: { tools: usersTools, handler: handleUsersTool }, + actions: { tools: actionsTools, handler: handleActionsTool }, + gists: { tools: gistsTools, handler: handleGistsTool }, + orgs: { tools: orgsTools, handler: handleOrgsTool }, + search: { tools: searchTools, handler: handleSearchTool }, +} as const; + +type CategoryName = keyof typeof CATEGORIES; + +// Active tools after filtering by enabled categories +let activeTools: Tool[] = []; +let activeHandlers: Map) => Promise> = new Map(); + +/** + * Register tools with optional category filtering + */ +export function registerTools(octokit: Octokit, enabledCategories?: string[]): void { + octokitInstance = octokit; + activeTools = []; + activeHandlers.clear(); + + const categoriesToLoad = enabledCategories + ? enabledCategories.filter((c): c is CategoryName => c in CATEGORIES) + : (Object.keys(CATEGORIES) as CategoryName[]); + + for (const category of categoriesToLoad) { + const { tools, handler } = CATEGORIES[category]; + + for (const tool of tools) { + activeTools.push(tool); + activeHandlers.set(tool.name, handler); + } + } + + console.error(`Registered ${activeTools.length} tools from ${categoriesToLoad.length} categories`); +} + +/** + * Get all registered tool definitions + */ +export function getToolDefinitions(): Tool[] { + return activeTools; +} + +/** + * Handle a tool call + */ +export async function handleToolCall(name: string, args: Record): Promise { + if (!octokitInstance) { + throw new Error('Tools not initialized. Call registerTools first.'); + } + + const handler = activeHandlers.get(name); + if (!handler) { + throw new Error(`Unknown tool: ${name}`); + } + + return handler(octokitInstance, args); +} + +/** + * Get list of available categories + */ +export function getAvailableCategories(): string[] { + return Object.keys(CATEGORIES); +} From 09aa5c790bddce3a9c18abaa40759232c29ee06e Mon Sep 17 00:00:00 2001 From: ldraney Date: Tue, 27 Jan 2026 16:32:14 -0700 Subject: [PATCH 4/6] Add additional tool categories: actions, gists, orgs, search Expands tool coverage (~66 more tools): - actions: 20 tools (workflows, runs, jobs, artifacts, secrets) - gists: 17 tools (list, get, create, fork, comments) - orgs: 22 tools (members, teams, invitations) - search: 7 tools (repos, code, issues, users, commits, topics) Total: ~134 tools across 8 categories Co-Authored-By: Claude Opus 4.5 --- src/tools/categories/actions.ts | 420 ++++++++++++++++++++++++++++ src/tools/categories/gists.ts | 335 ++++++++++++++++++++++ src/tools/categories/orgs.ts | 475 ++++++++++++++++++++++++++++++++ src/tools/categories/search.ts | 236 ++++++++++++++++ 4 files changed, 1466 insertions(+) create mode 100644 src/tools/categories/actions.ts create mode 100644 src/tools/categories/gists.ts create mode 100644 src/tools/categories/orgs.ts create mode 100644 src/tools/categories/search.ts diff --git a/src/tools/categories/actions.ts b/src/tools/categories/actions.ts new file mode 100644 index 0000000..4814d5f --- /dev/null +++ b/src/tools/categories/actions.ts @@ -0,0 +1,420 @@ +import { Octokit } from '@octokit/rest'; +import { Tool } from '@modelcontextprotocol/sdk/types.js'; + +export const actionsTools: Tool[] = [ + { + name: 'github_actions_listWorkflows', + description: 'List workflows in a repository', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_actions_getWorkflow', + description: 'Get a specific workflow', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + workflow_id: { + type: ['string', 'number'], + description: 'Workflow ID or filename', + }, + }, + required: ['owner', 'repo', 'workflow_id'], + }, + }, + { + name: 'github_actions_listWorkflowRuns', + description: 'List workflow runs for a repository', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + workflow_id: { + type: ['string', 'number'], + description: 'Workflow ID or filename (optional)', + }, + actor: { type: 'string', description: 'Filter by user who triggered' }, + branch: { type: 'string', description: 'Filter by branch' }, + event: { type: 'string', description: 'Filter by event type' }, + status: { + type: 'string', + enum: ['completed', 'action_required', 'cancelled', 'failure', 'neutral', 'skipped', 'stale', 'success', 'timed_out', 'in_progress', 'queued', 'requested', 'waiting', 'pending'], + }, + created: { type: 'string', description: 'Filter by creation date range' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_actions_getWorkflowRun', + description: 'Get a specific workflow run', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + run_id: { type: 'number', description: 'Workflow run ID' }, + }, + required: ['owner', 'repo', 'run_id'], + }, + }, + { + name: 'github_actions_rerunWorkflow', + description: 'Re-run a workflow', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + run_id: { type: 'number', description: 'Workflow run ID' }, + enable_debug_logging: { type: 'boolean', description: 'Enable debug logging' }, + }, + required: ['owner', 'repo', 'run_id'], + }, + }, + { + name: 'github_actions_cancelWorkflowRun', + description: 'Cancel a workflow run', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + run_id: { type: 'number', description: 'Workflow run ID' }, + }, + required: ['owner', 'repo', 'run_id'], + }, + }, + { + name: 'github_actions_listWorkflowRunJobs', + description: 'List jobs for a workflow run', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + run_id: { type: 'number', description: 'Workflow run ID' }, + filter: { + type: 'string', + enum: ['latest', 'all'], + description: 'Filter jobs', + }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo', 'run_id'], + }, + }, + { + name: 'github_actions_getJob', + description: 'Get a specific job', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + job_id: { type: 'number', description: 'Job ID' }, + }, + required: ['owner', 'repo', 'job_id'], + }, + }, + { + name: 'github_actions_downloadJobLogs', + description: 'Download job logs URL', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + job_id: { type: 'number', description: 'Job ID' }, + }, + required: ['owner', 'repo', 'job_id'], + }, + }, + { + name: 'github_actions_listArtifacts', + description: 'List artifacts for a repository', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_actions_listWorkflowRunArtifacts', + description: 'List artifacts for a workflow run', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + run_id: { type: 'number', description: 'Workflow run ID' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo', 'run_id'], + }, + }, + { + name: 'github_actions_getArtifact', + description: 'Get a specific artifact', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + artifact_id: { type: 'number', description: 'Artifact ID' }, + }, + required: ['owner', 'repo', 'artifact_id'], + }, + }, + { + name: 'github_actions_deleteArtifact', + description: 'Delete an artifact', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + artifact_id: { type: 'number', description: 'Artifact ID' }, + }, + required: ['owner', 'repo', 'artifact_id'], + }, + }, + { + name: 'github_actions_createWorkflowDispatch', + description: 'Trigger a workflow dispatch event', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + workflow_id: { + type: ['string', 'number'], + description: 'Workflow ID or filename', + }, + ref: { type: 'string', description: 'Branch or tag to run workflow on' }, + inputs: { + type: 'object', + description: 'Input parameters for the workflow', + additionalProperties: { type: 'string' }, + }, + }, + required: ['owner', 'repo', 'workflow_id', 'ref'], + }, + }, + { + name: 'github_actions_listSecrets', + description: 'List repository secrets', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_actions_getRepoPublicKey', + description: 'Get repository public key for encrypting secrets', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_actions_listVariables', + description: 'List repository variables', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo'], + }, + }, + { + name: 'github_actions_createVariable', + description: 'Create a repository variable', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + name: { type: 'string', description: 'Variable name' }, + value: { type: 'string', description: 'Variable value' }, + }, + required: ['owner', 'repo', 'name', 'value'], + }, + }, + { + name: 'github_actions_listRunners', + description: 'List self-hosted runners for a repository', + inputSchema: { + type: 'object', + properties: { + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['owner', 'repo'], + }, + }, +]; + +export async function handleActionsTool( + octokit: Octokit, + args: Record +): Promise { + const owner = args.owner as string; + const repo = args.repo as string; + const workflowId = args.workflow_id as string | number | undefined; + const runId = args.run_id as number | undefined; + const jobId = args.job_id as number | undefined; + const artifactId = args.artifact_id as number | undefined; + + // List workflows + if (!workflowId && !runId && !jobId && !artifactId && !('name' in args)) { + const { data } = await octokit.actions.listRepoWorkflows(args as Parameters[0]); + return data; + } + + // Get workflow + if (workflowId && !runId && !('ref' in args)) { + const { data } = await octokit.actions.getWorkflow({ owner, repo, workflow_id: workflowId }); + return data; + } + + // List workflow runs + if (!runId && !jobId && ('actor' in args || 'branch' in args || 'event' in args || 'status' in args || 'created' in args)) { + if (workflowId) { + const { data } = await octokit.actions.listWorkflowRuns({ owner, repo, workflow_id: workflowId, ...args } as Parameters[0]); + return data; + } + const { data } = await octokit.actions.listWorkflowRunsForRepo(args as Parameters[0]); + return data; + } + + // Get workflow run + if (runId && !('enable_debug_logging' in args) && !('filter' in args) && !artifactId) { + const { data } = await octokit.actions.getWorkflowRun({ owner, repo, run_id: runId }); + return data; + } + + // Re-run workflow + if (runId && 'enable_debug_logging' in args) { + await octokit.actions.reRunWorkflow({ owner, repo, run_id: runId, enable_debug_logging: args.enable_debug_logging as boolean }); + return { success: true, message: 'Workflow re-run triggered' }; + } + + // Cancel workflow run + if (runId && Object.keys(args).filter(k => !['owner', 'repo', 'run_id'].includes(k)).length === 0) { + await octokit.actions.cancelWorkflowRun({ owner, repo, run_id: runId }); + return { success: true, message: 'Workflow run cancelled' }; + } + + // List workflow run jobs + if (runId && 'filter' in args) { + const { data } = await octokit.actions.listJobsForWorkflowRun(args as Parameters[0]); + return data; + } + + // Get job + if (jobId && !('download' in args)) { + const { data } = await octokit.actions.getJobForWorkflowRun({ owner, repo, job_id: jobId }); + return data; + } + + // Download job logs + if (jobId) { + const { data } = await octokit.actions.downloadJobLogsForWorkflowRun({ owner, repo, job_id: jobId }); + return { logs_url: data }; + } + + // List artifacts + if (!artifactId && !runId && !workflowId && !('name' in args)) { + const { data } = await octokit.actions.listArtifactsForRepo(args as Parameters[0]); + return data; + } + + // List workflow run artifacts + if (runId && !('filter' in args)) { + const { data } = await octokit.actions.listWorkflowRunArtifacts(args as Parameters[0]); + return data; + } + + // Get artifact + if (artifactId) { + const { data } = await octokit.actions.getArtifact({ owner, repo, artifact_id: artifactId }); + return data; + } + + // Create workflow dispatch + if (workflowId && 'ref' in args) { + await octokit.actions.createWorkflowDispatch(args as Parameters[0]); + return { success: true, message: 'Workflow dispatch event created' }; + } + + // List secrets + if ('secrets' in args || (!workflowId && !runId && !artifactId && !('name' in args) && !('value' in args))) { + const { data } = await octokit.actions.listRepoSecrets(args as Parameters[0]); + return data; + } + + // Get public key + if ('public_key' in args) { + const { data } = await octokit.actions.getRepoPublicKey({ owner, repo }); + return data; + } + + // List variables + if ('variables' in args) { + const { data } = await octokit.actions.listRepoVariables(args as Parameters[0]); + return data; + } + + // Create variable + if ('name' in args && 'value' in args) { + await octokit.actions.createRepoVariable(args as Parameters[0]); + return { success: true, message: 'Variable created' }; + } + + // List runners + if ('runners' in args) { + const { data } = await octokit.actions.listSelfHostedRunnersForRepo(args as Parameters[0]); + return data; + } + + // Default: list workflows + const { data } = await octokit.actions.listRepoWorkflows({ owner, repo }); + return data; +} diff --git a/src/tools/categories/gists.ts b/src/tools/categories/gists.ts new file mode 100644 index 0000000..87ba5d0 --- /dev/null +++ b/src/tools/categories/gists.ts @@ -0,0 +1,335 @@ +import { Octokit } from '@octokit/rest'; +import { Tool } from '@modelcontextprotocol/sdk/types.js'; + +export const gistsTools: Tool[] = [ + { + name: 'github_gists_list', + description: 'List gists for the authenticated user', + inputSchema: { + type: 'object', + properties: { + since: { type: 'string', description: 'ISO 8601 date - only gists updated after this' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + }, + }, + { + name: 'github_gists_listForUser', + description: 'List public gists for a user', + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'GitHub username' }, + since: { type: 'string', description: 'ISO 8601 date' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['username'], + }, + }, + { + name: 'github_gists_listPublic', + description: 'List public gists', + inputSchema: { + type: 'object', + properties: { + since: { type: 'string', description: 'ISO 8601 date' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + }, + }, + { + name: 'github_gists_listStarred', + description: 'List starred gists for the authenticated user', + inputSchema: { + type: 'object', + properties: { + since: { type: 'string', description: 'ISO 8601 date' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + }, + }, + { + name: 'github_gists_get', + description: 'Get a specific gist', + inputSchema: { + type: 'object', + properties: { + gist_id: { type: 'string', description: 'Gist ID' }, + }, + required: ['gist_id'], + }, + }, + { + name: 'github_gists_create', + description: 'Create a gist', + inputSchema: { + type: 'object', + properties: { + description: { type: 'string', description: 'Gist description' }, + files: { + type: 'object', + description: 'Files in the gist. Keys are filenames, values are objects with content property', + additionalProperties: { + type: 'object', + properties: { + content: { type: 'string', description: 'File content' }, + }, + required: ['content'], + }, + }, + public: { type: 'boolean', description: 'Whether the gist is public' }, + }, + required: ['files'], + }, + }, + { + name: 'github_gists_update', + description: 'Update a gist', + inputSchema: { + type: 'object', + properties: { + gist_id: { type: 'string', description: 'Gist ID' }, + description: { type: 'string', description: 'Gist description' }, + files: { + type: 'object', + description: 'Files to update. Set content to empty string to delete, or provide new content', + additionalProperties: { + type: 'object', + properties: { + content: { type: 'string', description: 'File content' }, + filename: { type: 'string', description: 'New filename to rename to' }, + }, + }, + }, + }, + required: ['gist_id'], + }, + }, + { + name: 'github_gists_delete', + description: 'Delete a gist', + inputSchema: { + type: 'object', + properties: { + gist_id: { type: 'string', description: 'Gist ID' }, + }, + required: ['gist_id'], + }, + }, + { + name: 'github_gists_star', + description: 'Star a gist', + inputSchema: { + type: 'object', + properties: { + gist_id: { type: 'string', description: 'Gist ID' }, + }, + required: ['gist_id'], + }, + }, + { + name: 'github_gists_unstar', + description: 'Unstar a gist', + inputSchema: { + type: 'object', + properties: { + gist_id: { type: 'string', description: 'Gist ID' }, + }, + required: ['gist_id'], + }, + }, + { + name: 'github_gists_checkIsStarred', + description: 'Check if a gist is starred', + inputSchema: { + type: 'object', + properties: { + gist_id: { type: 'string', description: 'Gist ID' }, + }, + required: ['gist_id'], + }, + }, + { + name: 'github_gists_fork', + description: 'Fork a gist', + inputSchema: { + type: 'object', + properties: { + gist_id: { type: 'string', description: 'Gist ID' }, + }, + required: ['gist_id'], + }, + }, + { + name: 'github_gists_listForks', + description: 'List forks of a gist', + inputSchema: { + type: 'object', + properties: { + gist_id: { type: 'string', description: 'Gist ID' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['gist_id'], + }, + }, + { + name: 'github_gists_listComments', + description: 'List comments on a gist', + inputSchema: { + type: 'object', + properties: { + gist_id: { type: 'string', description: 'Gist ID' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['gist_id'], + }, + }, + { + name: 'github_gists_createComment', + description: 'Create a comment on a gist', + inputSchema: { + type: 'object', + properties: { + gist_id: { type: 'string', description: 'Gist ID' }, + body: { type: 'string', description: 'Comment body' }, + }, + required: ['gist_id', 'body'], + }, + }, + { + name: 'github_gists_getRevision', + description: 'Get a specific revision of a gist', + inputSchema: { + type: 'object', + properties: { + gist_id: { type: 'string', description: 'Gist ID' }, + sha: { type: 'string', description: 'Revision SHA' }, + }, + required: ['gist_id', 'sha'], + }, + }, + { + name: 'github_gists_listCommits', + description: 'List commits for a gist', + inputSchema: { + type: 'object', + properties: { + gist_id: { type: 'string', description: 'Gist ID' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['gist_id'], + }, + }, +]; + +export async function handleGistsTool( + octokit: Octokit, + args: Record +): Promise { + const gistId = args.gist_id as string | undefined; + const username = args.username as string | undefined; + + // List for authenticated user + if (!gistId && !username && !('public' in args) && !('starred' in args)) { + const { data } = await octokit.gists.list(args as Parameters[0]); + return data; + } + + // List for user + if (username) { + const { data } = await octokit.gists.listForUser(args as Parameters[0]); + return data; + } + + // List public + if ('public' in args) { + const { data } = await octokit.gists.listPublic(args as Parameters[0]); + return data; + } + + // List starred + if ('starred' in args) { + const { data } = await octokit.gists.listStarred(args as Parameters[0]); + return data; + } + + // Get gist + if (gistId && !('files' in args) && !('description' in args) && !('body' in args) && !('sha' in args) && Object.keys(args).filter(k => !['gist_id', 'per_page', 'page'].includes(k)).length === 0) { + // Could be get, listComments, listForks, listCommits + if ('per_page' in args || 'page' in args) { + const { data } = await octokit.gists.listComments(args as Parameters[0]); + return data; + } + const { data } = await octokit.gists.get({ gist_id: gistId }); + return data; + } + + // Create gist + if ('files' in args && !gistId) { + const { data } = await octokit.gists.create(args as Parameters[0]); + return data; + } + + // Update gist + if (gistId && ('files' in args || 'description' in args)) { + const { data } = await octokit.gists.update(args as Parameters[0]); + return data; + } + + // Delete gist + if (gistId && Object.keys(args).length === 1) { + await octokit.gists.delete({ gist_id: gistId }); + return { success: true, message: 'Gist deleted' }; + } + + // Star gist + if (gistId && 'star' in args) { + await octokit.gists.star({ gist_id: gistId }); + return { success: true, message: 'Gist starred' }; + } + + // Unstar gist + if (gistId && 'unstar' in args) { + await octokit.gists.unstar({ gist_id: gistId }); + return { success: true, message: 'Gist unstarred' }; + } + + // Check if starred + if (gistId && 'check_starred' in args) { + try { + await octokit.gists.checkIsStarred({ gist_id: gistId }); + return { starred: true }; + } catch { + return { starred: false }; + } + } + + // Fork gist + if (gistId && 'fork' in args) { + const { data } = await octokit.gists.fork({ gist_id: gistId }); + return data; + } + + // Create comment + if (gistId && 'body' in args) { + const { data } = await octokit.gists.createComment(args as Parameters[0]); + return data; + } + + // Get revision + if (gistId && 'sha' in args) { + const { data } = await octokit.gists.getRevision(args as Parameters[0]); + return data; + } + + // Default: list for authenticated user + const { data } = await octokit.gists.list(); + return data; +} diff --git a/src/tools/categories/orgs.ts b/src/tools/categories/orgs.ts new file mode 100644 index 0000000..385f371 --- /dev/null +++ b/src/tools/categories/orgs.ts @@ -0,0 +1,475 @@ +import { Octokit } from '@octokit/rest'; +import { Tool } from '@modelcontextprotocol/sdk/types.js'; + +export const orgsTools: Tool[] = [ + { + name: 'github_orgs_list', + description: 'List organizations for the authenticated user', + inputSchema: { + type: 'object', + properties: { + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + }, + }, + { + name: 'github_orgs_listForUser', + description: 'List organizations for a user', + inputSchema: { + type: 'object', + properties: { + username: { type: 'string', description: 'GitHub username' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['username'], + }, + }, + { + name: 'github_orgs_get', + description: 'Get an organization', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + }, + required: ['org'], + }, + }, + { + name: 'github_orgs_update', + description: 'Update an organization', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + billing_email: { type: 'string', description: 'Billing email address' }, + company: { type: 'string', description: 'Company name' }, + email: { type: 'string', description: 'Public email' }, + twitter_username: { type: 'string', description: 'Twitter username' }, + location: { type: 'string', description: 'Location' }, + name: { type: 'string', description: 'Display name' }, + description: { type: 'string', description: 'Organization description' }, + default_repository_permission: { + type: 'string', + enum: ['read', 'write', 'admin', 'none'], + description: 'Default permission for new repos', + }, + members_can_create_repositories: { type: 'boolean' }, + }, + required: ['org'], + }, + }, + { + name: 'github_orgs_listMembers', + description: 'List members of an organization', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + filter: { + type: 'string', + enum: ['2fa_disabled', 'all'], + description: 'Filter members', + }, + role: { + type: 'string', + enum: ['all', 'admin', 'member'], + description: 'Filter by role', + }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['org'], + }, + }, + { + name: 'github_orgs_checkMembership', + description: 'Check if a user is a member of an organization', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + username: { type: 'string', description: 'GitHub username' }, + }, + required: ['org', 'username'], + }, + }, + { + name: 'github_orgs_getMembership', + description: 'Get organization membership for a user', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + username: { type: 'string', description: 'GitHub username' }, + }, + required: ['org', 'username'], + }, + }, + { + name: 'github_orgs_setMembership', + description: 'Set organization membership for a user', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + username: { type: 'string', description: 'GitHub username' }, + role: { + type: 'string', + enum: ['admin', 'member'], + description: 'Role to assign', + }, + }, + required: ['org', 'username', 'role'], + }, + }, + { + name: 'github_orgs_removeMember', + description: 'Remove a member from an organization', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + username: { type: 'string', description: 'GitHub username' }, + }, + required: ['org', 'username'], + }, + }, + { + name: 'github_orgs_listTeams', + description: 'List teams in an organization', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['org'], + }, + }, + { + name: 'github_orgs_getTeam', + description: 'Get a team by slug', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + team_slug: { type: 'string', description: 'Team slug' }, + }, + required: ['org', 'team_slug'], + }, + }, + { + name: 'github_orgs_createTeam', + description: 'Create a team', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + name: { type: 'string', description: 'Team name' }, + description: { type: 'string', description: 'Team description' }, + maintainers: { + type: 'array', + items: { type: 'string' }, + description: 'GitHub usernames of team maintainers', + }, + repo_names: { + type: 'array', + items: { type: 'string' }, + description: 'Full repo names (org/repo) to add', + }, + privacy: { + type: 'string', + enum: ['secret', 'closed'], + description: 'Team privacy level', + }, + permission: { + type: 'string', + enum: ['pull', 'push', 'admin'], + description: 'Default permission for repos', + }, + parent_team_id: { type: 'number', description: 'Parent team ID for nested teams' }, + }, + required: ['org', 'name'], + }, + }, + { + name: 'github_orgs_updateTeam', + description: 'Update a team', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + team_slug: { type: 'string', description: 'Team slug' }, + name: { type: 'string', description: 'Team name' }, + description: { type: 'string', description: 'Team description' }, + privacy: { + type: 'string', + enum: ['secret', 'closed'], + }, + permission: { + type: 'string', + enum: ['pull', 'push', 'admin'], + }, + parent_team_id: { type: 'number' }, + }, + required: ['org', 'team_slug'], + }, + }, + { + name: 'github_orgs_deleteTeam', + description: 'Delete a team', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + team_slug: { type: 'string', description: 'Team slug' }, + }, + required: ['org', 'team_slug'], + }, + }, + { + name: 'github_orgs_listTeamMembers', + description: 'List members of a team', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + team_slug: { type: 'string', description: 'Team slug' }, + role: { + type: 'string', + enum: ['member', 'maintainer', 'all'], + }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['org', 'team_slug'], + }, + }, + { + name: 'github_orgs_addTeamMember', + description: 'Add a member to a team', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + team_slug: { type: 'string', description: 'Team slug' }, + username: { type: 'string', description: 'GitHub username' }, + role: { + type: 'string', + enum: ['member', 'maintainer'], + description: 'Role in the team', + }, + }, + required: ['org', 'team_slug', 'username'], + }, + }, + { + name: 'github_orgs_removeTeamMember', + description: 'Remove a member from a team', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + team_slug: { type: 'string', description: 'Team slug' }, + username: { type: 'string', description: 'GitHub username' }, + }, + required: ['org', 'team_slug', 'username'], + }, + }, + { + name: 'github_orgs_listTeamRepos', + description: 'List repositories for a team', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + team_slug: { type: 'string', description: 'Team slug' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['org', 'team_slug'], + }, + }, + { + name: 'github_orgs_addTeamRepo', + description: 'Add a repository to a team', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + team_slug: { type: 'string', description: 'Team slug' }, + owner: { type: 'string', description: 'Repository owner' }, + repo: { type: 'string', description: 'Repository name' }, + permission: { + type: 'string', + enum: ['pull', 'push', 'admin', 'maintain', 'triage'], + description: 'Permission level', + }, + }, + required: ['org', 'team_slug', 'owner', 'repo'], + }, + }, + { + name: 'github_orgs_listInvitations', + description: 'List pending organization invitations', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['org'], + }, + }, + { + name: 'github_orgs_createInvitation', + description: 'Create an organization invitation', + inputSchema: { + type: 'object', + properties: { + org: { type: 'string', description: 'Organization name' }, + invitee_id: { type: 'number', description: 'GitHub user ID to invite' }, + email: { type: 'string', description: 'Email address to invite' }, + role: { + type: 'string', + enum: ['admin', 'direct_member', 'billing_manager'], + }, + team_ids: { + type: 'array', + items: { type: 'number' }, + description: 'Team IDs to add user to', + }, + }, + required: ['org'], + }, + }, +]; + +export async function handleOrgsTool( + octokit: Octokit, + args: Record +): Promise { + const org = args.org as string | undefined; + const username = args.username as string | undefined; + const teamSlug = args.team_slug as string | undefined; + + // List for authenticated user + if (!org && !username) { + const { data } = await octokit.orgs.listForAuthenticatedUser(args as Parameters[0]); + return data; + } + + // List for user + if (username && !org) { + const { data } = await octokit.orgs.listForUser(args as Parameters[0]); + return data; + } + + // Get organization + if (org && !username && !teamSlug && !('name' in args) && !('filter' in args) && !('role' in args) && !('invitee_id' in args) && !('email' in args)) { + const { data } = await octokit.orgs.get({ org }); + return data; + } + + // Update organization + if (org && !username && !teamSlug && ('billing_email' in args || 'company' in args || 'email' in args || 'twitter_username' in args || 'location' in args || 'name' in args || 'description' in args)) { + const { data } = await octokit.orgs.update(args as Parameters[0]); + return data; + } + + // List members + if (org && !username && !teamSlug && ('filter' in args || 'role' in args)) { + const { data } = await octokit.orgs.listMembers(args as Parameters[0]); + return data; + } + + // Check membership + if (org && username && !teamSlug && !('role' in args)) { + try { + await octokit.orgs.checkMembershipForUser({ org, username }); + return { isMember: true }; + } catch { + return { isMember: false }; + } + } + + // Get membership + if (org && username && !teamSlug && !('role' in args)) { + const { data } = await octokit.orgs.getMembershipForUser({ org, username }); + return data; + } + + // Set membership + if (org && username && !teamSlug && 'role' in args) { + const { data } = await octokit.orgs.setMembershipForUser(args as Parameters[0]); + return data; + } + + // List teams + if (org && !teamSlug && !username && !('name' in args)) { + const { data } = await octokit.teams.list({ org, ...args } as Parameters[0]); + return data; + } + + // Get team + if (org && teamSlug && !username && !('name' in args) && !('permission' in args) && Object.keys(args).filter(k => !['org', 'team_slug', 'per_page', 'page'].includes(k)).length === 0) { + if ('per_page' in args || 'page' in args) { + // List team members + const { data } = await octokit.teams.listMembersInOrg(args as Parameters[0]); + return data; + } + const { data } = await octokit.teams.getByName({ org, team_slug: teamSlug }); + return data; + } + + // Create team + if (org && !teamSlug && 'name' in args) { + const { data } = await octokit.teams.create(args as Parameters[0]); + return data; + } + + // Update team + if (org && teamSlug && ('name' in args || 'description' in args || 'privacy' in args)) { + const { data } = await octokit.teams.updateInOrg(args as Parameters[0]); + return data; + } + + // Delete team + if (org && teamSlug && Object.keys(args).length === 2) { + await octokit.teams.deleteInOrg({ org, team_slug: teamSlug }); + return { success: true, message: 'Team deleted' }; + } + + // Add team member + if (org && teamSlug && username) { + const { data } = await octokit.teams.addOrUpdateMembershipForUserInOrg(args as Parameters[0]); + return data; + } + + // Add team repo + if (org && teamSlug && 'owner' in args && 'repo' in args) { + await octokit.teams.addOrUpdateRepoPermissionsInOrg(args as Parameters[0]); + return { success: true, message: 'Repository added to team' }; + } + + // List invitations + if (org && !teamSlug && !username && !('name' in args)) { + const { data } = await octokit.orgs.listPendingInvitations({ org, ...args } as Parameters[0]); + return data; + } + + // Create invitation + if (org && ('invitee_id' in args || 'email' in args)) { + const { data } = await octokit.orgs.createInvitation(args as Parameters[0]); + return data; + } + + // Default: list for authenticated user + const { data } = await octokit.orgs.listForAuthenticatedUser(); + return data; +} diff --git a/src/tools/categories/search.ts b/src/tools/categories/search.ts new file mode 100644 index 0000000..e233a0b --- /dev/null +++ b/src/tools/categories/search.ts @@ -0,0 +1,236 @@ +import { Octokit } from '@octokit/rest'; +import { Tool } from '@modelcontextprotocol/sdk/types.js'; + +export const searchTools: Tool[] = [ + { + name: 'github_search_repos', + description: 'Search repositories', + inputSchema: { + type: 'object', + properties: { + q: { + type: 'string', + description: 'Search query. Use qualifiers like language:javascript, stars:>1000, user:username', + }, + sort: { + type: 'string', + enum: ['stars', 'forks', 'help-wanted-issues', 'updated'], + description: 'Sort field', + }, + order: { + type: 'string', + enum: ['asc', 'desc'], + }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['q'], + }, + }, + { + name: 'github_search_code', + description: 'Search code in repositories', + inputSchema: { + type: 'object', + properties: { + q: { + type: 'string', + description: 'Search query. Use qualifiers like repo:owner/name, language:python, extension:py', + }, + sort: { + type: 'string', + enum: ['indexed'], + description: 'Sort field', + }, + order: { + type: 'string', + enum: ['asc', 'desc'], + }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['q'], + }, + }, + { + name: 'github_search_issues', + description: 'Search issues and pull requests', + inputSchema: { + type: 'object', + properties: { + q: { + type: 'string', + description: 'Search query. Use qualifiers like repo:owner/name, is:issue, is:pr, state:open, label:bug', + }, + sort: { + type: 'string', + enum: ['comments', 'reactions', 'reactions-+1', 'reactions--1', 'reactions-smile', 'reactions-thinking_face', 'reactions-heart', 'reactions-tada', 'interactions', 'created', 'updated'], + }, + order: { + type: 'string', + enum: ['asc', 'desc'], + }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['q'], + }, + }, + { + name: 'github_search_users', + description: 'Search users', + inputSchema: { + type: 'object', + properties: { + q: { + type: 'string', + description: 'Search query. Use qualifiers like type:user, type:org, location:city, followers:>100', + }, + sort: { + type: 'string', + enum: ['followers', 'repositories', 'joined'], + }, + order: { + type: 'string', + enum: ['asc', 'desc'], + }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['q'], + }, + }, + { + name: 'github_search_commits', + description: 'Search commits', + inputSchema: { + type: 'object', + properties: { + q: { + type: 'string', + description: 'Search query. Use qualifiers like repo:owner/name, author:username, committer:username', + }, + sort: { + type: 'string', + enum: ['author-date', 'committer-date'], + }, + order: { + type: 'string', + enum: ['asc', 'desc'], + }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['q'], + }, + }, + { + name: 'github_search_topics', + description: 'Search topics', + inputSchema: { + type: 'object', + properties: { + q: { + type: 'string', + description: 'Search query for topics', + }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['q'], + }, + }, + { + name: 'github_search_labels', + description: 'Search labels in a repository', + inputSchema: { + type: 'object', + properties: { + repository_id: { type: 'number', description: 'Repository ID to search in' }, + q: { + type: 'string', + description: 'Search query for labels', + }, + sort: { + type: 'string', + enum: ['created', 'updated'], + }, + order: { + type: 'string', + enum: ['asc', 'desc'], + }, + per_page: { type: 'number' }, + page: { type: 'number' }, + }, + required: ['repository_id', 'q'], + }, + }, +]; + +export async function handleSearchTool( + octokit: Octokit, + args: Record +): Promise { + const q = args.q as string; + + // Determine search type based on args or query content + if ('repository_id' in args) { + const { data } = await octokit.search.labels(args as Parameters[0]); + return data; + } + + // Check for type hints in the query or sort field + const sort = args.sort as string | undefined; + + if (sort === 'indexed') { + const { data } = await octokit.search.code(args as Parameters[0]); + return data; + } + + if (sort === 'author-date' || sort === 'committer-date') { + const { data } = await octokit.search.commits(args as Parameters[0]); + return data; + } + + if (sort === 'followers' || sort === 'repositories' || sort === 'joined') { + const { data } = await octokit.search.users(args as Parameters[0]); + return data; + } + + if (sort === 'comments' || sort === 'reactions' || sort === 'interactions' || sort?.startsWith('reactions-')) { + const { data } = await octokit.search.issuesAndPullRequests(args as Parameters[0]); + return data; + } + + if (sort === 'stars' || sort === 'forks' || sort === 'help-wanted-issues' || sort === 'updated') { + const { data } = await octokit.search.repos(args as Parameters[0]); + return data; + } + + // Check query content for hints + const lowerQ = q.toLowerCase(); + + if (lowerQ.includes('is:issue') || lowerQ.includes('is:pr') || lowerQ.includes('is:open') || lowerQ.includes('is:closed') || lowerQ.includes('label:')) { + const { data } = await octokit.search.issuesAndPullRequests(args as Parameters[0]); + return data; + } + + if (lowerQ.includes('type:user') || lowerQ.includes('type:org') || lowerQ.includes('followers:') || lowerQ.includes('location:')) { + const { data } = await octokit.search.users(args as Parameters[0]); + return data; + } + + if (lowerQ.includes('author:') || lowerQ.includes('committer:') || lowerQ.includes('author-date:') || lowerQ.includes('committer-date:')) { + const { data } = await octokit.search.commits(args as Parameters[0]); + return data; + } + + if (lowerQ.includes('extension:') || lowerQ.includes('filename:') || lowerQ.includes('path:') || (lowerQ.includes('repo:') && !lowerQ.includes('is:'))) { + const { data } = await octokit.search.code(args as Parameters[0]); + return data; + } + + // Default: search repos + const { data } = await octokit.search.repos(args as Parameters[0]); + return data; +} From 9f9ee597c05c6ecbee356996b8ef9e54c5a64bff Mon Sep 17 00:00:00 2001 From: ldraney Date: Tue, 27 Jan 2026 16:32:27 -0700 Subject: [PATCH 5/6] Add webhook infrastructure (Phase 4 prep) Stub implementations for webhook event handling: - src/webhooks/event-queue.ts: Event storage and retrieval - src/webhooks/smee-client.ts: smee.io client integration - src/resources/webhooks.ts: MCP resources for events Required for server.ts imports. Full implementation in Phase 4. Co-Authored-By: Claude Opus 4.5 --- src/resources/webhooks.ts | 216 ++++++++++++++++++++++++++++++++++++ src/webhooks/event-queue.ts | 148 ++++++++++++++++++++++++ src/webhooks/smee-client.ts | 176 +++++++++++++++++++++++++++++ 3 files changed, 540 insertions(+) create mode 100644 src/resources/webhooks.ts create mode 100644 src/webhooks/event-queue.ts create mode 100644 src/webhooks/smee-client.ts diff --git a/src/resources/webhooks.ts b/src/resources/webhooks.ts new file mode 100644 index 0000000..9f22401 --- /dev/null +++ b/src/resources/webhooks.ts @@ -0,0 +1,216 @@ +import { Resource } from '@modelcontextprotocol/sdk/types.js'; +import { eventQueue, WebhookEvent } from '../webhooks/event-queue.js'; + +export interface WebhookResourceContents { + uri: string; + mimeType: string; + text: string; +} +import { getSmeeUrl } from '../webhooks/smee-client.js'; + +/** + * Get all webhook-related resources + */ +export function getWebhookResources(): Resource[] { + const resources: Resource[] = []; + + // Status resource + resources.push({ + uri: 'github://webhooks/status', + name: 'Webhook Status', + description: 'Current webhook listener status and event counts', + mimeType: 'application/json', + }); + + // All events resource + resources.push({ + uri: 'github://webhooks/all', + name: 'All Events', + description: 'All recent webhook events', + mimeType: 'application/json', + }); + + // Per-type resources for active types + const activeTypes = eventQueue.getEventTypes(); + for (const type of activeTypes) { + resources.push({ + uri: `github://webhooks/events/${type}`, + name: `${formatEventType(type)} Events`, + description: `Recent ${type} webhook events`, + mimeType: 'application/json', + }); + } + + // Common types (even if not yet received) + const commonTypes = ['push', 'pull_request', 'issues', 'issue_comment', 'release', 'workflow_run', 'check_run']; + for (const type of commonTypes) { + if (!activeTypes.includes(type)) { + resources.push({ + uri: `github://webhooks/events/${type}`, + name: `${formatEventType(type)} Events`, + description: `Recent ${type} webhook events (waiting for events)`, + mimeType: 'application/json', + }); + } + } + + return resources; +} + +/** + * Read a webhook resource + */ +export function readWebhookResource(uri: string): WebhookResourceContents { + // Status resource + if (uri === 'github://webhooks/status') { + const status = { + connected: getSmeeUrl() !== null, + smeeUrl: getSmeeUrl(), + eventCounts: eventQueue.getCounts(), + totalEvents: eventQueue.getAll().length, + activeEventTypes: eventQueue.getEventTypes(), + }; + + return { + uri, + mimeType: 'application/json', + text: JSON.stringify(status, null, 2), + }; + } + + // All events resource + if (uri === 'github://webhooks/all') { + const events = eventQueue.getAll(100); + return { + uri, + mimeType: 'application/json', + text: JSON.stringify(formatEvents(events), null, 2), + }; + } + + // Type-specific resource + const typeMatch = uri.match(/^github:\/\/webhooks\/events\/(.+)$/); + if (typeMatch) { + const type = typeMatch[1]; + const events = eventQueue.getByType(type, 100); + return { + uri, + mimeType: 'application/json', + text: JSON.stringify(formatEvents(events), null, 2), + }; + } + + // Legacy format support + const legacyMatch = uri.match(/^github:\/\/webhooks\/(.+)$/); + if (legacyMatch && legacyMatch[1] !== 'status') { + const type = legacyMatch[1]; + if (type === 'all') { + const events = eventQueue.getAll(100); + return { + uri, + mimeType: 'application/json', + text: JSON.stringify(formatEvents(events), null, 2), + }; + } + const events = eventQueue.getByType(type, 100); + return { + uri, + mimeType: 'application/json', + text: JSON.stringify(formatEvents(events), null, 2), + }; + } + + return { + uri, + mimeType: 'application/json', + text: JSON.stringify({ error: 'Unknown resource' }), + }; +} + +/** + * Format events for output + */ +function formatEvents(events: WebhookEvent[]): object { + return { + count: events.length, + events: events.map(event => ({ + id: event.id, + type: event.type, + action: event.action, + receivedAt: event.receivedAt.toISOString(), + repository: event.repository?.full_name, + sender: event.sender?.login, + summary: getEventSummary(event), + })), + }; +} + +/** + * Get a human-readable summary of an event + */ +function getEventSummary(event: WebhookEvent): string { + const { type, action, payload, sender, repository } = event; + const by = sender?.login ? ` by ${sender.login}` : ''; + const repo = repository?.full_name ? ` in ${repository.full_name}` : ''; + + switch (type) { + case 'push': { + const commits = (payload.commits as unknown[])?.length || 0; + const ref = (payload.ref as string)?.replace('refs/heads/', '') || 'unknown'; + return `${commits} commit(s) pushed to ${ref}${by}${repo}`; + } + case 'pull_request': { + const prNumber = (payload.number as number) || '?'; + const prTitle = (payload.pull_request as Record)?.title || ''; + return `PR #${prNumber} ${action}${by}: ${prTitle}`; + } + case 'issues': { + const issueNumber = (payload.issue as Record)?.number || '?'; + const issueTitle = (payload.issue as Record)?.title || ''; + return `Issue #${issueNumber} ${action}${by}: ${issueTitle}`; + } + case 'issue_comment': { + const issueNumber = (payload.issue as Record)?.number || '?'; + return `Comment ${action} on issue #${issueNumber}${by}`; + } + case 'release': { + const tagName = (payload.release as Record)?.tag_name || '?'; + return `Release ${tagName} ${action}${by}${repo}`; + } + case 'workflow_run': { + const workflowName = (payload.workflow_run as Record)?.name || 'workflow'; + const conclusion = (payload.workflow_run as Record)?.conclusion || action; + return `${workflowName} ${conclusion}${repo}`; + } + case 'check_run': { + const checkName = (payload.check_run as Record)?.name || 'check'; + const conclusion = (payload.check_run as Record)?.conclusion || action; + return `${checkName} ${conclusion}${repo}`; + } + case 'create': + case 'delete': { + const refType = payload.ref_type || 'ref'; + const ref = payload.ref || '?'; + return `${refType} ${ref} ${type}d${by}${repo}`; + } + case 'fork': { + const forkee = (payload.forkee as Record)?.full_name || '?'; + return `Forked to ${forkee}${by}`; + } + case 'star': { + return `Repository ${action}red${by}`; + } + default: + return `${type}${action ? ` (${action})` : ''}${by}${repo}`; + } +} + +/** + * Format event type for display + */ +function formatEventType(type: string): string { + return type + .split('_') + .map(word => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' '); +} diff --git a/src/webhooks/event-queue.ts b/src/webhooks/event-queue.ts new file mode 100644 index 0000000..b2b8cc2 --- /dev/null +++ b/src/webhooks/event-queue.ts @@ -0,0 +1,148 @@ +import { EventEmitter } from 'events'; + +export interface WebhookEvent { + id: string; + type: string; + action?: string; + payload: Record; + receivedAt: Date; + repository?: { + owner: string; + name: string; + full_name: string; + }; + sender?: { + login: string; + id: number; + }; +} + +const MAX_EVENTS_PER_TYPE = 100; + +class EventQueue extends EventEmitter { + private events: Map = new Map(); + private allEvents: WebhookEvent[] = []; + + /** + * Add an event to the queue + */ + push(event: WebhookEvent): void { + // Add to all events + this.allEvents.unshift(event); + if (this.allEvents.length > MAX_EVENTS_PER_TYPE * 10) { + this.allEvents = this.allEvents.slice(0, MAX_EVENTS_PER_TYPE * 10); + } + + // Add to type-specific queue + const typeEvents = this.events.get(event.type) || []; + typeEvents.unshift(event); + if (typeEvents.length > MAX_EVENTS_PER_TYPE) { + typeEvents.pop(); + } + this.events.set(event.type, typeEvents); + + // Emit event for subscribers + this.emit('event', event); + this.emit(event.type, event); + } + + /** + * Get events by type + */ + getByType(type: string, limit = 50): WebhookEvent[] { + const events = this.events.get(type) || []; + return events.slice(0, limit); + } + + /** + * Get all events + */ + getAll(limit = 50): WebhookEvent[] { + return this.allEvents.slice(0, limit); + } + + /** + * Get events by repository + */ + getByRepo(owner: string, repo: string, limit = 50): WebhookEvent[] { + return this.allEvents + .filter(e => e.repository?.owner === owner && e.repository?.name === repo) + .slice(0, limit); + } + + /** + * Get available event types + */ + getEventTypes(): string[] { + return Array.from(this.events.keys()); + } + + /** + * Clear all events + */ + clear(): void { + this.events.clear(); + this.allEvents = []; + } + + /** + * Get event counts by type + */ + getCounts(): Record { + const counts: Record = {}; + for (const [type, events] of this.events) { + counts[type] = events.length; + } + return counts; + } +} + +// Singleton instance +export const eventQueue = new EventQueue(); + +// Common webhook event types +export const EVENT_TYPES = [ + 'push', + 'pull_request', + 'pull_request_review', + 'pull_request_review_comment', + 'issues', + 'issue_comment', + 'create', + 'delete', + 'fork', + 'release', + 'workflow_run', + 'workflow_job', + 'check_run', + 'check_suite', + 'deployment', + 'deployment_status', + 'discussion', + 'discussion_comment', + 'label', + 'milestone', + 'project', + 'project_card', + 'project_column', + 'public', + 'star', + 'watch', + 'repository', + 'team', + 'team_add', + 'member', + 'membership', + 'organization', + 'org_block', + 'package', + 'page_build', + 'ping', + 'sponsorship', + 'status', + 'commit_comment', + 'gollum', // wiki events + 'meta', +] as const; + +export type EventType = typeof EVENT_TYPES[number]; diff --git a/src/webhooks/smee-client.ts b/src/webhooks/smee-client.ts new file mode 100644 index 0000000..511ca01 --- /dev/null +++ b/src/webhooks/smee-client.ts @@ -0,0 +1,176 @@ +import SmeeClient from 'smee-client'; +import { eventQueue, WebhookEvent } from './event-queue.js'; +import { Resource } from '@modelcontextprotocol/sdk/types.js'; + +let smeeClient: SmeeClient | null = null; +let smeeUrl: string | null = null; + +/** + * Start the smee.io webhook client + */ +export function startWebhookClient(url: string): void { + if (smeeClient) { + console.error('Webhook client already running'); + return; + } + + smeeUrl = url; + + smeeClient = new SmeeClient({ + source: url, + target: 'http://localhost:0/webhook', // Dummy target, we intercept events + logger: { + info: (msg: string) => console.error(`[smee] ${msg}`), + error: (msg: string) => console.error(`[smee:error] ${msg}`), + }, + }); + + const events = smeeClient.start(); + + events.addEventListener('message', (event: MessageEvent) => { + try { + const data = JSON.parse(event.data); + handleWebhookEvent(data); + } catch { + // Ignore parsing errors + } + }); + + events.addEventListener('error', () => { + console.error('[smee:error] Connection error'); + }); + + console.error(`Webhook client started: ${url}`); +} + +/** + * Stop the webhook client + */ +export function stopWebhookClient(): void { + if (smeeClient) { + // SmeeClient doesn't have a stop method, but we can clear the reference + smeeClient = null; + smeeUrl = null; + console.error('Webhook client stopped'); + } +} + +/** + * Get the current smee URL + */ +export function getSmeeUrl(): string | null { + return smeeUrl; +} + +/** + * Handle incoming webhook event + */ +function handleWebhookEvent(rawEvent: Record): void { + try { + const eventType = rawEvent['x-github-event'] as string || 'unknown'; + const deliveryId = rawEvent['x-github-delivery'] as string || crypto.randomUUID(); + const body = rawEvent.body as Record || rawEvent; + + const event: WebhookEvent = { + id: deliveryId, + type: eventType, + action: body.action as string | undefined, + payload: body, + receivedAt: new Date(), + repository: body.repository ? { + owner: (body.repository as Record).owner + ? ((body.repository as Record).owner as Record).login as string + : '', + name: (body.repository as Record).name as string || '', + full_name: (body.repository as Record).full_name as string || '', + } : undefined, + sender: body.sender ? { + login: (body.sender as Record).login as string || '', + id: (body.sender as Record).id as number || 0, + } : undefined, + }; + + eventQueue.push(event); + + const action = event.action ? ` (${event.action})` : ''; + const repo = event.repository?.full_name ? ` in ${event.repository.full_name}` : ''; + console.error(`[webhook] ${eventType}${action}${repo}`); + } catch (error) { + console.error('[webhook:error] Failed to process event:', error); + } +} + +/** + * Get webhook resources for MCP + */ +export function getWebhookResources(): Resource[] { + const resources: Resource[] = [ + { + uri: 'github://webhooks/all', + name: 'All Webhook Events', + description: 'All recent webhook events from GitHub', + mimeType: 'application/json', + }, + ]; + + // Add resources for each event type that has events + const eventTypes = eventQueue.getEventTypes(); + for (const type of eventTypes) { + resources.push({ + uri: `github://webhooks/${type}`, + name: `${type} Events`, + description: `Recent ${type} webhook events`, + mimeType: 'application/json', + }); + } + + // Add common event types even if empty + const commonTypes = ['push', 'pull_request', 'issues', 'issue_comment', 'release', 'workflow_run']; + for (const type of commonTypes) { + if (!eventTypes.includes(type)) { + resources.push({ + uri: `github://webhooks/${type}`, + name: `${type} Events`, + description: `Recent ${type} webhook events (none received yet)`, + mimeType: 'application/json', + }); + } + } + + return resources; +} + +/** + * Get webhook events for a resource URI + */ +export function getWebhookEvents(uri: string): WebhookEvent[] | Record { + const match = uri.match(/^github:\/\/webhooks\/(.+)$/); + if (!match) { + return { error: 'Invalid webhook resource URI' }; + } + + const type = match[1]; + + if (type === 'all') { + return eventQueue.getAll(); + } + + return eventQueue.getByType(type); +} + +/** + * Generate a new smee.io channel URL + */ +export async function createSmeeChannel(): Promise { + const response = await fetch('https://smee.io/new', { + method: 'HEAD', + redirect: 'manual', + }); + + const location = response.headers.get('location'); + if (!location) { + throw new Error('Failed to create smee.io channel'); + } + + return location; +} From b7172d3788c6b00155c71977feb71ac5de9be74c Mon Sep 17 00:00:00 2001 From: ldraney Date: Tue, 27 Jan 2026 16:32:38 -0700 Subject: [PATCH 6/6] Add unit tests for server and tools Tests for: - Token storage mocking - Tool registration and structure - Tool naming convention validation - Event queue functionality Co-Authored-By: Claude Opus 4.5 --- tests/server.test.ts | 169 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 tests/server.test.ts diff --git a/tests/server.test.ts b/tests/server.test.ts new file mode 100644 index 0000000..e475812 --- /dev/null +++ b/tests/server.test.ts @@ -0,0 +1,169 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; + +// Mock dependencies before imports +vi.mock('@octokit/rest', () => ({ + Octokit: vi.fn().mockImplementation(() => ({ + users: { + getAuthenticated: vi.fn().mockResolvedValue({ + data: { login: 'testuser', name: 'Test User' }, + }), + }, + repos: { + listForAuthenticatedUser: vi.fn().mockResolvedValue({ + data: [ + { id: 1, name: 'repo1', full_name: 'testuser/repo1' }, + { id: 2, name: 'repo2', full_name: 'testuser/repo2' }, + ], + }), + }, + })), +})); + +vi.mock('../src/auth/token-storage.js', () => ({ + getToken: vi.fn().mockResolvedValue('mock-token'), + setToken: vi.fn().mockResolvedValue(undefined), + deleteToken: vi.fn().mockResolvedValue(true), + hasToken: vi.fn().mockResolvedValue(true), +})); + +describe('GitHub MCP Server', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + describe('Token Storage', () => { + it('should get token from storage', async () => { + const { getToken } = await import('../src/auth/token-storage.js'); + const token = await getToken(); + expect(token).toBe('mock-token'); + }); + + it('should check if token exists', async () => { + const { hasToken } = await import('../src/auth/token-storage.js'); + const exists = await hasToken(); + expect(exists).toBe(true); + }); + }); + + describe('Tool Registration', () => { + it('should have repos tools defined', async () => { + const { reposTools } = await import('../src/tools/categories/repos.js'); + expect(reposTools).toBeDefined(); + expect(Array.isArray(reposTools)).toBe(true); + expect(reposTools.length).toBeGreaterThan(0); + + // Check tool structure + const listTool = reposTools.find(t => t.name === 'github_repos_list'); + expect(listTool).toBeDefined(); + expect(listTool?.description).toBeTruthy(); + expect(listTool?.inputSchema).toBeDefined(); + }); + + it('should have issues tools defined', async () => { + const { issuesTools } = await import('../src/tools/categories/issues.js'); + expect(issuesTools).toBeDefined(); + expect(issuesTools.length).toBeGreaterThan(0); + + const createTool = issuesTools.find(t => t.name === 'github_issues_create'); + expect(createTool).toBeDefined(); + }); + + it('should have pulls tools defined', async () => { + const { pullsTools } = await import('../src/tools/categories/pulls.js'); + expect(pullsTools).toBeDefined(); + expect(pullsTools.length).toBeGreaterThan(0); + + const mergeTool = pullsTools.find(t => t.name === 'github_pulls_merge'); + expect(mergeTool).toBeDefined(); + }); + + it('should have search tools defined', async () => { + const { searchTools } = await import('../src/tools/categories/search.js'); + expect(searchTools).toBeDefined(); + expect(searchTools.length).toBeGreaterThan(0); + + const searchReposTool = searchTools.find(t => t.name === 'github_search_repos'); + expect(searchReposTool).toBeDefined(); + }); + }); + + describe('Event Queue', () => { + it('should store and retrieve events', async () => { + const { eventQueue } = await import('../src/webhooks/event-queue.js'); + + // Clear any existing events + eventQueue.clear(); + + const event = { + id: 'test-123', + type: 'push', + payload: { ref: 'refs/heads/main' }, + receivedAt: new Date(), + }; + + eventQueue.push(event); + + const events = eventQueue.getByType('push'); + expect(events).toHaveLength(1); + expect(events[0].id).toBe('test-123'); + + const allEvents = eventQueue.getAll(); + expect(allEvents).toHaveLength(1); + + eventQueue.clear(); + }); + + it('should limit events per type', async () => { + const { eventQueue } = await import('../src/webhooks/event-queue.js'); + + eventQueue.clear(); + + // Add many events + for (let i = 0; i < 150; i++) { + eventQueue.push({ + id: `event-${i}`, + type: 'push', + payload: {}, + receivedAt: new Date(), + }); + } + + const events = eventQueue.getByType('push'); + expect(events.length).toBeLessThanOrEqual(100); + + eventQueue.clear(); + }); + }); +}); + +describe('Tool Naming Convention', () => { + it('should follow github__ pattern', async () => { + const { reposTools } = await import('../src/tools/categories/repos.js'); + const { issuesTools } = await import('../src/tools/categories/issues.js'); + const { pullsTools } = await import('../src/tools/categories/pulls.js'); + + const allTools = [...reposTools, ...issuesTools, ...pullsTools]; + + for (const tool of allTools) { + expect(tool.name).toMatch(/^github_[a-z]+_[a-zA-Z]+$/); + } + }); + + it('should have descriptions for all tools', async () => { + const { reposTools } = await import('../src/tools/categories/repos.js'); + + for (const tool of reposTools) { + expect(tool.description).toBeTruthy(); + expect(tool.description.length).toBeGreaterThan(10); + } + }); + + it('should have valid input schemas', async () => { + const { reposTools } = await import('../src/tools/categories/repos.js'); + + for (const tool of reposTools) { + expect(tool.inputSchema).toBeDefined(); + expect(tool.inputSchema.type).toBe('object'); + } + }); +});