From 22480302c34a6c22ffca82683fe3542696451c14 Mon Sep 17 00:00:00 2001 From: suger Date: Thu, 9 Apr 2026 01:26:18 +0800 Subject: [PATCH 1/2] feat: add VS Code IDE bridge extension --- .vscode/launch.json | 16 + .vscode/tasks.json | 35 +- bun.lock | 423 ++++++++++- .../plans/2026-04-07-vscode-ide-bridge.md | 664 ++++++++++++++++++ .../2026-04-07-vscode-ide-bridge-design.md | 350 +++++++++ .../vscode-ide-bridge/.vscode/launch.json | 36 + packages/vscode-ide-bridge/.vscode/tasks.json | 47 ++ packages/vscode-ide-bridge/.vscodeignore | 6 + packages/vscode-ide-bridge/LICENSE.txt | 3 + packages/vscode-ide-bridge/README.md | 59 ++ packages/vscode-ide-bridge/package.json | 59 ++ packages/vscode-ide-bridge/src/extension.ts | 61 ++ .../src/server/bridgeServer.ts | 139 ++++ .../src/server/diffController.ts | 350 +++++++++ .../src/server/localIdeBridgeService.ts | 231 ++++++ .../vscode-ide-bridge/src/server/lockfile.ts | 56 ++ .../vscode-ide-bridge/src/server/protocol.ts | 33 + .../src/server/randomToken.ts | 5 + .../src/server/selectionPublisher.ts | 41 ++ .../src/server/serverWebSocketTransport.ts | 92 +++ .../src/server/terminalEnvironment.ts | 19 + .../src/server/workspaceInfo.ts | 53 ++ packages/vscode-ide-bridge/src/vscode.d.ts | 4 + packages/vscode-ide-bridge/src/ws.d.ts | 3 + .../test/bridgeServer.test.ts | 135 ++++ .../test/diffController.test.ts | 247 +++++++ .../vscode-ide-bridge/test/lockfile.test.ts | 39 + .../vscode-ide-bridge/test/package.test.ts | 32 + .../test/packagePackaging.test.ts | 71 ++ .../test/packageWorkspaceWorkflow.test.ts | 89 +++ .../test/selectionPublisher.test.ts | 27 + .../test/serverWebSocketTransport.test.ts | 71 ++ .../test/terminalEnvironment.test.ts | 48 ++ .../test/vscodeWorkflow.test.ts | 61 ++ .../test/workspaceInfo.test.ts | 41 ++ packages/vscode-ide-bridge/tsconfig.json | 19 + 36 files changed, 3659 insertions(+), 6 deletions(-) create mode 100644 docs/superpowers/plans/2026-04-07-vscode-ide-bridge.md create mode 100644 docs/superpowers/specs/2026-04-07-vscode-ide-bridge-design.md create mode 100644 packages/vscode-ide-bridge/.vscode/launch.json create mode 100644 packages/vscode-ide-bridge/.vscode/tasks.json create mode 100644 packages/vscode-ide-bridge/.vscodeignore create mode 100644 packages/vscode-ide-bridge/LICENSE.txt create mode 100644 packages/vscode-ide-bridge/README.md create mode 100644 packages/vscode-ide-bridge/package.json create mode 100644 packages/vscode-ide-bridge/src/extension.ts create mode 100644 packages/vscode-ide-bridge/src/server/bridgeServer.ts create mode 100644 packages/vscode-ide-bridge/src/server/diffController.ts create mode 100644 packages/vscode-ide-bridge/src/server/localIdeBridgeService.ts create mode 100644 packages/vscode-ide-bridge/src/server/lockfile.ts create mode 100644 packages/vscode-ide-bridge/src/server/protocol.ts create mode 100644 packages/vscode-ide-bridge/src/server/randomToken.ts create mode 100644 packages/vscode-ide-bridge/src/server/selectionPublisher.ts create mode 100644 packages/vscode-ide-bridge/src/server/serverWebSocketTransport.ts create mode 100644 packages/vscode-ide-bridge/src/server/terminalEnvironment.ts create mode 100644 packages/vscode-ide-bridge/src/server/workspaceInfo.ts create mode 100644 packages/vscode-ide-bridge/src/vscode.d.ts create mode 100644 packages/vscode-ide-bridge/src/ws.d.ts create mode 100644 packages/vscode-ide-bridge/test/bridgeServer.test.ts create mode 100644 packages/vscode-ide-bridge/test/diffController.test.ts create mode 100644 packages/vscode-ide-bridge/test/lockfile.test.ts create mode 100644 packages/vscode-ide-bridge/test/package.test.ts create mode 100644 packages/vscode-ide-bridge/test/packagePackaging.test.ts create mode 100644 packages/vscode-ide-bridge/test/packageWorkspaceWorkflow.test.ts create mode 100644 packages/vscode-ide-bridge/test/selectionPublisher.test.ts create mode 100644 packages/vscode-ide-bridge/test/serverWebSocketTransport.test.ts create mode 100644 packages/vscode-ide-bridge/test/terminalEnvironment.test.ts create mode 100644 packages/vscode-ide-bridge/test/vscodeWorkflow.test.ts create mode 100644 packages/vscode-ide-bridge/test/workspaceInfo.test.ts create mode 100644 packages/vscode-ide-bridge/tsconfig.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 1ca6dd46e..72602b763 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,6 +1,22 @@ { "version": "0.2.0", "configurations": [ + { + "name": "Run VSCode IDE Bridge", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--new-window", + "--disable-extensions", + "--extensionDevelopmentPath=${workspaceFolder}/packages/vscode-ide-bridge", + "${workspaceFolder}" + ], + "outFiles": [ + "${workspaceFolder}/packages/vscode-ide-bridge/dist/**/*.js" + ], + "preLaunchTask": "Build VSCode IDE Bridge" + }, { "type": "bun", "request": "attach", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 29f31d4ba..ce7712710 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,6 +1,39 @@ { "version": "2.0.0", "tasks": [ + { + "label": "Build VSCode IDE Bridge", + "type": "shell", + "command": "bunx", + "args": [ + "tsc", + "-p", + "packages/vscode-ide-bridge/tsconfig.json" + ], + "presentation": { + "reveal": "always", + "focus": false, + "panel": "shared", + "clear": true + }, + "problemMatcher": [] + }, + { + "label": "Test VSCode IDE Bridge", + "type": "shell", + "command": "bun", + "args": [ + "test", + "packages/vscode-ide-bridge/test" + ], + "presentation": { + "reveal": "always", + "focus": false, + "panel": "shared", + "clear": true + }, + "problemMatcher": [] + }, { "label": "Start Claude Code TUI", "type": "shell", @@ -24,4 +57,4 @@ } } ] -} \ No newline at end of file +} diff --git a/bun.lock b/bun.lock index 06021cca8..0e5b4b305 100644 --- a/bun.lock +++ b/bun.lock @@ -188,6 +188,19 @@ "name": "url-handler-napi", "version": "1.0.0", }, + "packages/vscode-ide-bridge": { + "name": "vscode-ide-bridge", + "version": "0.0.1", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.29.0", + "ws": "^8.20.0", + }, + "devDependencies": { + "@types/bun": "^1.3.11", + "@vscode/vsce": "^3.7.0", + "typescript": "^6.0.2", + }, + }, }, "packages": { "@alcalzone/ansi-tokenize": ["@alcalzone/ansi-tokenize@0.3.0", "https://registry.npmmirror.com/@alcalzone/ansi-tokenize/-/ansi-tokenize-0.3.0.tgz", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-p+CMKJ93HFmLkjXKlXiVGlMQEuRb6H0MokBSwUsX+S6BRX8eV5naFZpQJFfJHjRZY0Hmnqy1/r6UWl3x+19zYA=="], @@ -294,6 +307,10 @@ "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.4", "https://registry.npmmirror.com/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.4.tgz", {}, "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ=="], + "@azu/format-text": ["@azu/format-text@1.0.2", "https://registry.npmmirror.com/@azu/format-text/-/format-text-1.0.2.tgz", {}, "sha512-Swi4N7Edy1Eqq82GxgEECXSSLyn6GOb5htRFPzBDdUkECGXtlf12ynO5oJSpWKPwCaUssOu7NfhDcCWpIC6Ywg=="], + + "@azu/style-format": ["@azu/style-format@1.0.1", "https://registry.npmmirror.com/@azu/style-format/-/style-format-1.0.1.tgz", { "dependencies": { "@azu/format-text": "^1.0.1" } }, "sha512-AHcTojlNBdD/3/KxIKlg8sxIWHfOtQszLvOpagLTO+bjC3u7SAszu1lf//u7JJC50aUSH+BVWDD/KvaA6Gfn5g=="], + "@azure/abort-controller": ["@azure/abort-controller@2.1.2", "https://registry.npmmirror.com/@azure/abort-controller/-/abort-controller-2.1.2.tgz", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA=="], "@azure/core-auth": ["@azure/core-auth@1.10.1", "https://registry.npmmirror.com/@azure/core-auth/-/core-auth-1.10.1.tgz", { "dependencies": { "@azure/abort-controller": "^2.1.2", "@azure/core-util": "^1.13.0", "tslib": "^2.6.2" } }, "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg=="], @@ -316,6 +333,10 @@ "@azure/msal-node": ["@azure/msal-node@5.1.1", "https://registry.npmmirror.com/@azure/msal-node/-/msal-node-5.1.1.tgz", { "dependencies": { "@azure/msal-common": "16.4.0", "jsonwebtoken": "^9.0.0", "uuid": "^8.3.0" } }, "sha512-71grXU6+5hl+3CL3joOxlj/AW6rmhthuTlG0fRqsTrhPArQBpZuUFzCIlKOGdcafLUa/i1hBdV78ZxJdlvRA+g=="], + "@babel/code-frame": ["@babel/code-frame@7.29.0", "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.29.0.tgz", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], + + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], + "@babel/runtime": ["@babel/runtime@7.29.2", "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.29.2.tgz", {}, "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g=="], "@biomejs/biome": ["@biomejs/biome@2.4.10", "https://registry.npmmirror.com/@biomejs/biome/-/biome-2.4.10.tgz", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.10", "@biomejs/cli-darwin-x64": "2.4.10", "@biomejs/cli-linux-arm64": "2.4.10", "@biomejs/cli-linux-arm64-musl": "2.4.10", "@biomejs/cli-linux-x64": "2.4.10", "@biomejs/cli-linux-x64-musl": "2.4.10", "@biomejs/cli-win32-arm64": "2.4.10", "@biomejs/cli-win32-x64": "2.4.10" }, "bin": { "biome": "bin/biome" } }, "sha512-xxA3AphFQ1geij4JTHXv4EeSTda1IFn22ye9LdyVPoJU19fNVl0uzfEuhsfQ4Yue/0FaLs2/ccVi4UDiE7R30w=="], @@ -432,6 +453,8 @@ "@inquirer/type": ["@inquirer/type@2.0.0", "https://registry.npmmirror.com/@inquirer/type/-/type-2.0.0.tgz", { "dependencies": { "mute-stream": "^1.0.0" } }, "sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag=="], + "@isaacs/cliui": ["@isaacs/cliui@9.0.0", "https://registry.npmmirror.com/@isaacs/cliui/-/cliui-9.0.0.tgz", {}, "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg=="], + "@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "https://registry.npmmirror.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="], "@mixmark-io/domino": ["@mixmark-io/domino@2.2.0", "https://registry.npmmirror.com/@mixmark-io/domino/-/domino-2.2.0.tgz", {}, "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw=="], @@ -650,6 +673,30 @@ "@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "https://registry.npmmirror.com/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="], + "@secretlint/config-creator": ["@secretlint/config-creator@10.2.2", "https://registry.npmmirror.com/@secretlint/config-creator/-/config-creator-10.2.2.tgz", { "dependencies": { "@secretlint/types": "^10.2.2" } }, "sha512-BynOBe7Hn3LJjb3CqCHZjeNB09s/vgf0baBaHVw67w7gHF0d25c3ZsZ5+vv8TgwSchRdUCRrbbcq5i2B1fJ2QQ=="], + + "@secretlint/config-loader": ["@secretlint/config-loader@10.2.2", "https://registry.npmmirror.com/@secretlint/config-loader/-/config-loader-10.2.2.tgz", { "dependencies": { "@secretlint/profiler": "^10.2.2", "@secretlint/resolver": "^10.2.2", "@secretlint/types": "^10.2.2", "ajv": "^8.17.1", "debug": "^4.4.1", "rc-config-loader": "^4.1.3" } }, "sha512-ndjjQNgLg4DIcMJp4iaRD6xb9ijWQZVbd9694Ol2IszBIbGPPkwZHzJYKICbTBmh6AH/pLr0CiCaWdGJU7RbpQ=="], + + "@secretlint/core": ["@secretlint/core@10.2.2", "https://registry.npmmirror.com/@secretlint/core/-/core-10.2.2.tgz", { "dependencies": { "@secretlint/profiler": "^10.2.2", "@secretlint/types": "^10.2.2", "debug": "^4.4.1", "structured-source": "^4.0.0" } }, "sha512-6rdwBwLP9+TO3rRjMVW1tX+lQeo5gBbxl1I5F8nh8bgGtKwdlCMhMKsBWzWg1ostxx/tIG7OjZI0/BxsP8bUgw=="], + + "@secretlint/formatter": ["@secretlint/formatter@10.2.2", "https://registry.npmmirror.com/@secretlint/formatter/-/formatter-10.2.2.tgz", { "dependencies": { "@secretlint/resolver": "^10.2.2", "@secretlint/types": "^10.2.2", "@textlint/linter-formatter": "^15.2.0", "@textlint/module-interop": "^15.2.0", "@textlint/types": "^15.2.0", "chalk": "^5.4.1", "debug": "^4.4.1", "pluralize": "^8.0.0", "strip-ansi": "^7.1.0", "table": "^6.9.0", "terminal-link": "^4.0.0" } }, "sha512-10f/eKV+8YdGKNQmoDUD1QnYL7TzhI2kzyx95vsJKbEa8akzLAR5ZrWIZ3LbcMmBLzxlSQMMccRmi05yDQ5YDA=="], + + "@secretlint/node": ["@secretlint/node@10.2.2", "https://registry.npmmirror.com/@secretlint/node/-/node-10.2.2.tgz", { "dependencies": { "@secretlint/config-loader": "^10.2.2", "@secretlint/core": "^10.2.2", "@secretlint/formatter": "^10.2.2", "@secretlint/profiler": "^10.2.2", "@secretlint/source-creator": "^10.2.2", "@secretlint/types": "^10.2.2", "debug": "^4.4.1", "p-map": "^7.0.3" } }, "sha512-eZGJQgcg/3WRBwX1bRnss7RmHHK/YlP/l7zOQsrjexYt6l+JJa5YhUmHbuGXS94yW0++3YkEJp0kQGYhiw1DMQ=="], + + "@secretlint/profiler": ["@secretlint/profiler@10.2.2", "https://registry.npmmirror.com/@secretlint/profiler/-/profiler-10.2.2.tgz", {}, "sha512-qm9rWfkh/o8OvzMIfY8a5bCmgIniSpltbVlUVl983zDG1bUuQNd1/5lUEeWx5o/WJ99bXxS7yNI4/KIXfHexig=="], + + "@secretlint/resolver": ["@secretlint/resolver@10.2.2", "https://registry.npmmirror.com/@secretlint/resolver/-/resolver-10.2.2.tgz", {}, "sha512-3md0cp12e+Ae5V+crPQYGd6aaO7ahw95s28OlULGyclyyUtf861UoRGS2prnUrKh7MZb23kdDOyGCYb9br5e4w=="], + + "@secretlint/secretlint-formatter-sarif": ["@secretlint/secretlint-formatter-sarif@10.2.2", "https://registry.npmmirror.com/@secretlint/secretlint-formatter-sarif/-/secretlint-formatter-sarif-10.2.2.tgz", { "dependencies": { "node-sarif-builder": "^3.2.0" } }, "sha512-ojiF9TGRKJJw308DnYBucHxkpNovDNu1XvPh7IfUp0A12gzTtxuWDqdpuVezL7/IP8Ua7mp5/VkDMN9OLp1doQ=="], + + "@secretlint/secretlint-rule-no-dotenv": ["@secretlint/secretlint-rule-no-dotenv@10.2.2", "https://registry.npmmirror.com/@secretlint/secretlint-rule-no-dotenv/-/secretlint-rule-no-dotenv-10.2.2.tgz", { "dependencies": { "@secretlint/types": "^10.2.2" } }, "sha512-KJRbIShA9DVc5Va3yArtJ6QDzGjg3PRa1uYp9As4RsyKtKSSZjI64jVca57FZ8gbuk4em0/0Jq+uy6485wxIdg=="], + + "@secretlint/secretlint-rule-preset-recommend": ["@secretlint/secretlint-rule-preset-recommend@10.2.2", "https://registry.npmmirror.com/@secretlint/secretlint-rule-preset-recommend/-/secretlint-rule-preset-recommend-10.2.2.tgz", {}, "sha512-K3jPqjva8bQndDKJqctnGfwuAxU2n9XNCPtbXVI5JvC7FnQiNg/yWlQPbMUlBXtBoBGFYp08A94m6fvtc9v+zA=="], + + "@secretlint/source-creator": ["@secretlint/source-creator@10.2.2", "https://registry.npmmirror.com/@secretlint/source-creator/-/source-creator-10.2.2.tgz", { "dependencies": { "@secretlint/types": "^10.2.2", "istextorbinary": "^9.5.0" } }, "sha512-h6I87xJfwfUTgQ7irWq7UTdq/Bm1RuQ/fYhA3dtTIAop5BwSFmZyrchph4WcoEvbN460BWKmk4RYSvPElIIvxw=="], + + "@secretlint/types": ["@secretlint/types@10.2.2", "https://registry.npmmirror.com/@secretlint/types/-/types-10.2.2.tgz", {}, "sha512-Nqc90v4lWCXyakD6xNyNACBJNJ0tNCwj2WNk/7ivyacYHxiITVgmLUFXTBOeCdy79iz6HtN9Y31uw/jbLrdOAg=="], + "@sentry/core": ["@sentry/core@10.47.0", "https://registry.npmmirror.com/@sentry/core/-/core-10.47.0.tgz", {}, "sha512-nsYRAx3EWezDut+Zl+UwwP07thh9uY7CfSAi2whTdcJl5hu1nSp2z8bba7Vq/MGbNLnazkd3A+GITBEML924JA=="], "@sentry/node": ["@sentry/node@10.47.0", "https://registry.npmmirror.com/@sentry/node/-/node-10.47.0.tgz", { "dependencies": { "@fastify/otel": "0.18.0", "@opentelemetry/api": "^1.9.1", "@opentelemetry/context-async-hooks": "^2.6.1", "@opentelemetry/core": "^2.6.1", "@opentelemetry/instrumentation": "^0.214.0", "@opentelemetry/instrumentation-amqplib": "0.61.0", "@opentelemetry/instrumentation-connect": "0.57.0", "@opentelemetry/instrumentation-dataloader": "0.31.0", "@opentelemetry/instrumentation-express": "0.62.0", "@opentelemetry/instrumentation-fs": "0.33.0", "@opentelemetry/instrumentation-generic-pool": "0.57.0", "@opentelemetry/instrumentation-graphql": "0.62.0", "@opentelemetry/instrumentation-hapi": "0.60.0", "@opentelemetry/instrumentation-http": "0.214.0", "@opentelemetry/instrumentation-ioredis": "0.62.0", "@opentelemetry/instrumentation-kafkajs": "0.23.0", "@opentelemetry/instrumentation-knex": "0.58.0", "@opentelemetry/instrumentation-koa": "0.62.0", "@opentelemetry/instrumentation-lru-memoizer": "0.58.0", "@opentelemetry/instrumentation-mongodb": "0.67.0", "@opentelemetry/instrumentation-mongoose": "0.60.0", "@opentelemetry/instrumentation-mysql": "0.60.0", "@opentelemetry/instrumentation-mysql2": "0.60.0", "@opentelemetry/instrumentation-pg": "0.66.0", "@opentelemetry/instrumentation-redis": "0.62.0", "@opentelemetry/instrumentation-tedious": "0.33.0", "@opentelemetry/instrumentation-undici": "0.24.0", "@opentelemetry/resources": "^2.6.1", "@opentelemetry/sdk-trace-base": "^2.6.1", "@opentelemetry/semantic-conventions": "^1.40.0", "@prisma/instrumentation": "7.6.0", "@sentry/core": "10.47.0", "@sentry/node-core": "10.47.0", "@sentry/opentelemetry": "10.47.0", "import-in-the-middle": "^3.0.0" } }, "sha512-R+btqPepv88o635G6HtVewLjqCLUedBg5HBs7Nq1qbbKvyti01uArUF2f+3DsLenk5B9LUNiRlE+frZA44Ahmw=="], @@ -750,6 +797,16 @@ "@smithy/uuid": ["@smithy/uuid@1.1.2", "https://registry.npmmirror.com/@smithy/uuid/-/uuid-1.1.2.tgz", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g=="], + "@textlint/ast-node-types": ["@textlint/ast-node-types@15.5.2", "https://registry.npmmirror.com/@textlint/ast-node-types/-/ast-node-types-15.5.2.tgz", {}, "sha512-fCaOxoup5LIyBEo7R1oYWE7V4bSX0KQeHh66twon9e9usaLE3ijgF8QjYsR6joCssdeCHVd0wHm7ppsEyTr6vg=="], + + "@textlint/linter-formatter": ["@textlint/linter-formatter@15.5.2", "https://registry.npmmirror.com/@textlint/linter-formatter/-/linter-formatter-15.5.2.tgz", { "dependencies": { "@azu/format-text": "^1.0.2", "@azu/style-format": "^1.0.1", "@textlint/module-interop": "15.5.2", "@textlint/resolver": "15.5.2", "@textlint/types": "15.5.2", "chalk": "^4.1.2", "debug": "^4.4.3", "js-yaml": "^4.1.1", "lodash": "^4.17.23", "pluralize": "^2.0.0", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "table": "^6.9.0", "text-table": "^0.2.0" } }, "sha512-jAw7jWM8+wU9cG6Uu31jGyD1B+PAVePCvnPKC/oov+2iBPKk3ao30zc/Itmi7FvXo4oPaL9PmzPPQhyniPVgVg=="], + + "@textlint/module-interop": ["@textlint/module-interop@15.5.2", "https://registry.npmmirror.com/@textlint/module-interop/-/module-interop-15.5.2.tgz", {}, "sha512-mg6rMQ3+YjwiXCYoQXbyVfDucpTa1q5mhspd/9qHBxUq4uY6W8GU42rmT3GW0V1yOfQ9z/iRrgPtkp71s8JzXg=="], + + "@textlint/resolver": ["@textlint/resolver@15.5.2", "https://registry.npmmirror.com/@textlint/resolver/-/resolver-15.5.2.tgz", {}, "sha512-YEITdjRiJaQrGLUWxWXl4TEg+d2C7+TNNjbGPHPH7V7CCnXm+S9GTjGAL7Q2WSGJyFEKt88Jvx6XdJffRv4HEA=="], + + "@textlint/types": ["@textlint/types@15.5.2", "https://registry.npmmirror.com/@textlint/types/-/types-15.5.2.tgz", { "dependencies": { "@textlint/ast-node-types": "15.5.2" } }, "sha512-sJOrlVLLXp4/EZtiWKWq9y2fWyZlI8GP+24rnU5avtPWBIMm/1w97yzKrAqYF8czx2MqR391z5akhnfhj2f/AQ=="], + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "https://registry.npmmirror.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], "@types/bun": ["@types/bun@1.3.11", "https://registry.npmmirror.com/@types/bun/-/bun-1.3.11.tgz", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="], @@ -768,6 +825,8 @@ "@types/node": ["@types/node@25.5.0", "https://registry.npmmirror.com/@types/node/-/node-25.5.0.tgz", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw=="], + "@types/normalize-package-data": ["@types/normalize-package-data@2.4.4", "https://registry.npmmirror.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", {}, "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="], + "@types/pg": ["@types/pg@8.15.6", "https://registry.npmmirror.com/@types/pg/-/pg-8.15.6.tgz", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, "sha512-NoaMtzhxOrubeL/7UZuNTrejB4MPAJ0RpxZqXQf2qXuVlTPuG6Y8p4u9dKRaue4yjmC7ZhzVO2/Yyyn25znrPQ=="], "@types/pg-pool": ["@types/pg-pool@2.0.7", "https://registry.npmmirror.com/@types/pg-pool/-/pg-pool-2.0.7.tgz", { "dependencies": { "@types/pg": "*" } }, "sha512-U4CwmGVQcbEuqpyju8/ptOKg6gEC+Tqsvj2xS9o1g71bUh8twxnC6ZL5rZKCsGN0iyH0CwgUyc9VR5owNQF9Ng=="], @@ -778,6 +837,8 @@ "@types/react-reconciler": ["@types/react-reconciler@0.33.0", "https://registry.npmmirror.com/@types/react-reconciler/-/react-reconciler-0.33.0.tgz", { "peerDependencies": { "@types/react": "*" } }, "sha512-HZOXsKT0tGI9LlUw2LuedXsVeB88wFa536vVL0M6vE8zN63nI+sSr1ByxmPToP5K5bukaVscyeCJcF9guVNJ1g=="], + "@types/sarif": ["@types/sarif@2.1.7", "https://registry.npmmirror.com/@types/sarif/-/sarif-2.1.7.tgz", {}, "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ=="], + "@types/sharp": ["@types/sharp@0.32.0", "https://registry.npmmirror.com/@types/sharp/-/sharp-0.32.0.tgz", { "dependencies": { "sharp": "*" } }, "sha512-OOi3kL+FZDnPhVzsfD37J88FNeZh6gQsGcLc95NbeURRGvmSjeXiDcyWzF2o3yh/gQAUn2uhh/e+CPCa5nwAxw=="], "@types/tedious": ["@types/tedious@4.0.14", "https://registry.npmmirror.com/@types/tedious/-/tedious-4.0.14.tgz", { "dependencies": { "@types/node": "*" } }, "sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw=="], @@ -788,6 +849,28 @@ "@typespec/ts-http-runtime": ["@typespec/ts-http-runtime@0.3.4", "https://registry.npmmirror.com/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.4.tgz", { "dependencies": { "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "tslib": "^2.6.2" } }, "sha512-CI0NhTrz4EBaa0U+HaaUZrJhPoso8sG7ZFya8uQoBA57fjzrjRSv87ekCjLZOFExN+gXE/z0xuN2QfH4H2HrLQ=="], + "@vscode/vsce": ["@vscode/vsce@3.7.1", "https://registry.npmmirror.com/@vscode/vsce/-/vsce-3.7.1.tgz", { "dependencies": { "@azure/identity": "^4.1.0", "@secretlint/node": "^10.1.2", "@secretlint/secretlint-formatter-sarif": "^10.1.2", "@secretlint/secretlint-rule-no-dotenv": "^10.1.2", "@secretlint/secretlint-rule-preset-recommend": "^10.1.2", "@vscode/vsce-sign": "^2.0.0", "azure-devops-node-api": "^12.5.0", "chalk": "^4.1.2", "cheerio": "^1.0.0-rc.9", "cockatiel": "^3.1.2", "commander": "^12.1.0", "form-data": "^4.0.0", "glob": "^11.0.0", "hosted-git-info": "^4.0.2", "jsonc-parser": "^3.2.0", "leven": "^3.1.0", "markdown-it": "^14.1.0", "mime": "^1.3.4", "minimatch": "^3.0.3", "parse-semver": "^1.1.1", "read": "^1.0.7", "secretlint": "^10.1.2", "semver": "^7.5.2", "tmp": "^0.2.3", "typed-rest-client": "^1.8.4", "url-join": "^4.0.1", "xml2js": "^0.5.0", "yauzl": "^2.3.1", "yazl": "^2.2.2" }, "optionalDependencies": { "keytar": "^7.7.0" }, "bin": { "vsce": "vsce" } }, "sha512-OTm2XdMt2YkpSn2Nx7z2EJtSuhRHsTPYsSK59hr3v8jRArK+2UEoju4Jumn1CmpgoBLGI6ReHLJ/czYltNUW3g=="], + + "@vscode/vsce-sign": ["@vscode/vsce-sign@2.0.9", "https://registry.npmmirror.com/@vscode/vsce-sign/-/vsce-sign-2.0.9.tgz", { "optionalDependencies": { "@vscode/vsce-sign-alpine-arm64": "2.0.6", "@vscode/vsce-sign-alpine-x64": "2.0.6", "@vscode/vsce-sign-darwin-arm64": "2.0.6", "@vscode/vsce-sign-darwin-x64": "2.0.6", "@vscode/vsce-sign-linux-arm": "2.0.6", "@vscode/vsce-sign-linux-arm64": "2.0.6", "@vscode/vsce-sign-linux-x64": "2.0.6", "@vscode/vsce-sign-win32-arm64": "2.0.6", "@vscode/vsce-sign-win32-x64": "2.0.6" } }, "sha512-8IvaRvtFyzUnGGl3f5+1Cnor3LqaUWvhaUjAYO8Y39OUYlOf3cRd+dowuQYLpZcP3uwSG+mURwjEBOSq4SOJ0g=="], + + "@vscode/vsce-sign-alpine-arm64": ["@vscode/vsce-sign-alpine-arm64@2.0.6", "https://registry.npmmirror.com/@vscode/vsce-sign-alpine-arm64/-/vsce-sign-alpine-arm64-2.0.6.tgz", { "os": "none", "cpu": "arm64" }, "sha512-wKkJBsvKF+f0GfsUuGT0tSW0kZL87QggEiqNqK6/8hvqsXvpx8OsTEc3mnE1kejkh5r+qUyQ7PtF8jZYN0mo8Q=="], + + "@vscode/vsce-sign-alpine-x64": ["@vscode/vsce-sign-alpine-x64@2.0.6", "https://registry.npmmirror.com/@vscode/vsce-sign-alpine-x64/-/vsce-sign-alpine-x64-2.0.6.tgz", { "os": "none", "cpu": "x64" }, "sha512-YoAGlmdK39vKi9jA18i4ufBbd95OqGJxRvF3n6ZbCyziwy3O+JgOpIUPxv5tjeO6gQfx29qBivQ8ZZTUF2Ba0w=="], + + "@vscode/vsce-sign-darwin-arm64": ["@vscode/vsce-sign-darwin-arm64@2.0.6", "https://registry.npmmirror.com/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.6.tgz", { "os": "darwin", "cpu": "arm64" }, "sha512-5HMHaJRIQuozm/XQIiJiA0W9uhdblwwl2ZNDSSAeXGO9YhB9MH5C4KIHOmvyjUnKy4UCuiP43VKpIxW1VWP4tQ=="], + + "@vscode/vsce-sign-darwin-x64": ["@vscode/vsce-sign-darwin-x64@2.0.6", "https://registry.npmmirror.com/@vscode/vsce-sign-darwin-x64/-/vsce-sign-darwin-x64-2.0.6.tgz", { "os": "darwin", "cpu": "x64" }, "sha512-25GsUbTAiNfHSuRItoQafXOIpxlYj+IXb4/qarrXu7kmbH94jlm5sdWSCKrrREs8+GsXF1b+l3OB7VJy5jsykw=="], + + "@vscode/vsce-sign-linux-arm": ["@vscode/vsce-sign-linux-arm@2.0.6", "https://registry.npmmirror.com/@vscode/vsce-sign-linux-arm/-/vsce-sign-linux-arm-2.0.6.tgz", { "os": "linux", "cpu": "arm" }, "sha512-UndEc2Xlq4HsuMPnwu7420uqceXjs4yb5W8E2/UkaHBB9OWCwMd3/bRe/1eLe3D8kPpxzcaeTyXiK3RdzS/1CA=="], + + "@vscode/vsce-sign-linux-arm64": ["@vscode/vsce-sign-linux-arm64@2.0.6", "https://registry.npmmirror.com/@vscode/vsce-sign-linux-arm64/-/vsce-sign-linux-arm64-2.0.6.tgz", { "os": "linux", "cpu": "arm64" }, "sha512-cfb1qK7lygtMa4NUl2582nP7aliLYuDEVpAbXJMkDq1qE+olIw/es+C8j1LJwvcRq1I2yWGtSn3EkDp9Dq5FdA=="], + + "@vscode/vsce-sign-linux-x64": ["@vscode/vsce-sign-linux-x64@2.0.6", "https://registry.npmmirror.com/@vscode/vsce-sign-linux-x64/-/vsce-sign-linux-x64-2.0.6.tgz", { "os": "linux", "cpu": "x64" }, "sha512-/olerl1A4sOqdP+hjvJ1sbQjKN07Y3DVnxO4gnbn/ahtQvFrdhUi0G1VsZXDNjfqmXw57DmPi5ASnj/8PGZhAA=="], + + "@vscode/vsce-sign-win32-arm64": ["@vscode/vsce-sign-win32-arm64@2.0.6", "https://registry.npmmirror.com/@vscode/vsce-sign-win32-arm64/-/vsce-sign-win32-arm64-2.0.6.tgz", { "os": "win32", "cpu": "arm64" }, "sha512-ivM/MiGIY0PJNZBoGtlRBM/xDpwbdlCWomUWuLmIxbi1Cxe/1nooYrEQoaHD8ojVRgzdQEUzMsRbyF5cJJgYOg=="], + + "@vscode/vsce-sign-win32-x64": ["@vscode/vsce-sign-win32-x64@2.0.6", "https://registry.npmmirror.com/@vscode/vsce-sign-win32-x64/-/vsce-sign-win32-x64-2.0.6.tgz", { "os": "win32", "cpu": "x64" }, "sha512-mgth9Kvze+u8CruYMmhHw6Zgy3GRX2S+Ed5oSokDEK5vPEwGGKnmuXua9tmFhomeAnhgJnL4DCna3TiNuGrBTQ=="], + "@xmldom/xmldom": ["@xmldom/xmldom@0.8.12", "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.8.12.tgz", {}, "sha512-9k/gHF6n/pAi/9tqr3m3aqkuiNosYTurLLUtc7xQ9sxB/wm7WPygCv8GYa6mS0fLJEHhqMC1ATYhz++U/lRHqg=="], "accepts": ["accepts@2.0.0", "https://registry.npmmirror.com/accepts/-/accepts-2.0.0.tgz", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], @@ -810,8 +893,12 @@ "any-promise": ["any-promise@1.3.0", "https://registry.npmmirror.com/any-promise/-/any-promise-1.3.0.tgz", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], + "argparse": ["argparse@2.0.1", "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + "asciichart": ["asciichart@1.5.25", "https://registry.npmmirror.com/asciichart/-/asciichart-1.5.25.tgz", {}, "sha512-PNxzXIPPOtWq8T7bgzBtk9cI2lgS4SJZthUHEiQ1aoIc3lNzGfUvIvo9LiAnq26TACo9t1/4qP6KTGAUbzX9Xg=="], + "astral-regex": ["astral-regex@2.0.0", "https://registry.npmmirror.com/astral-regex/-/astral-regex-2.0.0.tgz", {}, "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ=="], + "asynckit": ["asynckit@0.4.0", "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], "audio-capture-napi": ["audio-capture-napi@workspace:packages/audio-capture-napi"], @@ -820,7 +907,9 @@ "axios": ["axios@1.14.0", "https://registry.npmmirror.com/axios/-/axios-1.14.0.tgz", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^2.1.0" } }, "sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ=="], - "balanced-match": ["balanced-match@4.0.4", "https://registry.npmmirror.com/balanced-match/-/balanced-match-4.0.4.tgz", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + "azure-devops-node-api": ["azure-devops-node-api@12.5.0", "https://registry.npmmirror.com/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz", { "dependencies": { "tunnel": "0.0.6", "typed-rest-client": "^1.8.4" } }, "sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og=="], + + "balanced-match": ["balanced-match@1.0.2", "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "base64-js": ["base64-js@1.5.1", "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], @@ -828,14 +917,26 @@ "bignumber.js": ["bignumber.js@9.3.1", "https://registry.npmmirror.com/bignumber.js/-/bignumber.js-9.3.1.tgz", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="], + "binaryextensions": ["binaryextensions@6.11.0", "https://registry.npmmirror.com/binaryextensions/-/binaryextensions-6.11.0.tgz", { "dependencies": { "editions": "^6.21.0" } }, "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw=="], + + "bl": ["bl@4.1.0", "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], + "body-parser": ["body-parser@2.2.2", "https://registry.npmmirror.com/body-parser/-/body-parser-2.2.2.tgz", { "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" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], + "boolbase": ["boolbase@1.0.0", "https://registry.npmmirror.com/boolbase/-/boolbase-1.0.0.tgz", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], + + "boundary": ["boundary@2.0.0", "https://registry.npmmirror.com/boundary/-/boundary-2.0.0.tgz", {}, "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA=="], + "bowser": ["bowser@2.14.1", "https://registry.npmmirror.com/bowser/-/bowser-2.14.1.tgz", {}, "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg=="], - "brace-expansion": ["brace-expansion@5.0.5", "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-5.0.5.tgz", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ=="], + "brace-expansion": ["brace-expansion@1.1.13", "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.13.tgz", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w=="], "braces": ["braces@3.0.3", "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + "buffer": ["buffer@5.7.1", "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + + "buffer-crc32": ["buffer-crc32@0.2.13", "https://registry.npmmirror.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="], + "buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "https://registry.npmmirror.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="], "bun-types": ["bun-types@1.3.11", "https://registry.npmmirror.com/bun-types/-/bun-types-1.3.11.tgz", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="], @@ -856,8 +957,14 @@ "chardet": ["chardet@0.7.0", "https://registry.npmmirror.com/chardet/-/chardet-0.7.0.tgz", {}, "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="], + "cheerio": ["cheerio@1.2.0", "https://registry.npmmirror.com/cheerio/-/cheerio-1.2.0.tgz", { "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "encoding-sniffer": "^0.2.1", "htmlparser2": "^10.1.0", "parse5": "^7.3.0", "parse5-htmlparser2-tree-adapter": "^7.1.0", "parse5-parser-stream": "^7.1.2", "undici": "^7.19.0", "whatwg-mimetype": "^4.0.0" } }, "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg=="], + + "cheerio-select": ["cheerio-select@2.1.0", "https://registry.npmmirror.com/cheerio-select/-/cheerio-select-2.1.0.tgz", { "dependencies": { "boolbase": "^1.0.0", "css-select": "^5.1.0", "css-what": "^6.1.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1" } }, "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g=="], + "chokidar": ["chokidar@5.0.0", "https://registry.npmmirror.com/chokidar/-/chokidar-5.0.0.tgz", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], + "chownr": ["chownr@1.1.4", "https://registry.npmmirror.com/chownr/-/chownr-1.1.4.tgz", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], + "cjs-module-lexer": ["cjs-module-lexer@2.2.0", "https://registry.npmmirror.com/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", {}, "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ=="], "cli-boxes": ["cli-boxes@4.0.1", "https://registry.npmmirror.com/cli-boxes/-/cli-boxes-4.0.1.tgz", {}, "sha512-5IOn+jcCEHEraYolBPs/sT4BxYCe2nHg374OPiItB1O96KZFseS2gthU4twyYzeDcFew4DaUM/xwc5BQf08JJw=="], @@ -868,6 +975,8 @@ "cliui": ["cliui@7.0.4", "https://registry.npmmirror.com/cliui/-/cliui-7.0.4.tgz", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="], + "cockatiel": ["cockatiel@3.2.1", "https://registry.npmmirror.com/cockatiel/-/cockatiel-3.2.1.tgz", {}, "sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q=="], + "code-excerpt": ["code-excerpt@4.0.0", "https://registry.npmmirror.com/code-excerpt/-/code-excerpt-4.0.0.tgz", { "dependencies": { "convert-to-spaces": "^2.0.1" } }, "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA=="], "color": ["color@4.2.3", "https://registry.npmmirror.com/color/-/color-4.2.3.tgz", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="], @@ -884,6 +993,8 @@ "commander": ["commander@13.1.0", "https://registry.npmmirror.com/commander/-/commander-13.1.0.tgz", {}, "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw=="], + "concat-map": ["concat-map@0.0.1", "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + "content-disposition": ["content-disposition@1.0.1", "https://registry.npmmirror.com/content-disposition/-/content-disposition-1.0.1.tgz", {}, "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q=="], "content-type": ["content-type@1.0.5", "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], @@ -898,6 +1009,10 @@ "cross-spawn": ["cross-spawn@7.0.6", "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + "css-select": ["css-select@5.2.2", "https://registry.npmmirror.com/css-select/-/css-select-5.2.2.tgz", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], + + "css-what": ["css-what@6.2.2", "https://registry.npmmirror.com/css-what/-/css-what-6.2.2.tgz", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], + "cssfilter": ["cssfilter@0.0.10", "https://registry.npmmirror.com/cssfilter/-/cssfilter-0.0.10.tgz", {}, "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw=="], "csstype": ["csstype@3.2.3", "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], @@ -908,6 +1023,10 @@ "decamelize": ["decamelize@1.2.0", "https://registry.npmmirror.com/decamelize/-/decamelize-1.2.0.tgz", {}, "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="], + "decompress-response": ["decompress-response@6.0.0", "https://registry.npmmirror.com/decompress-response/-/decompress-response-6.0.0.tgz", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="], + + "deep-extend": ["deep-extend@0.6.0", "https://registry.npmmirror.com/deep-extend/-/deep-extend-0.6.0.tgz", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], + "default-browser": ["default-browser@5.5.0", "https://registry.npmmirror.com/default-browser/-/default-browser-5.5.0.tgz", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw=="], "default-browser-id": ["default-browser-id@5.0.1", "https://registry.npmmirror.com/default-browser-id/-/default-browser-id-5.0.1.tgz", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="], @@ -926,18 +1045,36 @@ "dom-mutator": ["dom-mutator@0.6.0", "https://registry.npmmirror.com/dom-mutator/-/dom-mutator-0.6.0.tgz", {}, "sha512-iCt9o0aYfXMUkz/43ZOAUFQYotjGB+GNbYJiJdz4TgXkyToXbbRy5S6FbTp72lRBtfpUMwEc1KmpFEU4CZeoNg=="], + "dom-serializer": ["dom-serializer@2.0.0", "https://registry.npmmirror.com/dom-serializer/-/dom-serializer-2.0.0.tgz", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], + + "domelementtype": ["domelementtype@2.3.0", "https://registry.npmmirror.com/domelementtype/-/domelementtype-2.3.0.tgz", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + + "domhandler": ["domhandler@5.0.3", "https://registry.npmmirror.com/domhandler/-/domhandler-5.0.3.tgz", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], + + "domutils": ["domutils@3.2.2", "https://registry.npmmirror.com/domutils/-/domutils-3.2.2.tgz", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], + "dunder-proto": ["dunder-proto@1.0.1", "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "https://registry.npmmirror.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="], + "editions": ["editions@6.22.0", "https://registry.npmmirror.com/editions/-/editions-6.22.0.tgz", { "dependencies": { "version-range": "^4.15.0" } }, "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ=="], + "ee-first": ["ee-first@1.1.1", "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], "emoji-regex": ["emoji-regex@10.6.0", "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-10.6.0.tgz", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], "encodeurl": ["encodeurl@2.0.0", "https://registry.npmmirror.com/encodeurl/-/encodeurl-2.0.0.tgz", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], + "encoding-sniffer": ["encoding-sniffer@0.2.1", "https://registry.npmmirror.com/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", { "dependencies": { "iconv-lite": "^0.6.3", "whatwg-encoding": "^3.1.1" } }, "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw=="], + + "end-of-stream": ["end-of-stream@1.4.5", "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.5.tgz", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], + + "entities": ["entities@4.5.0", "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + "env-paths": ["env-paths@4.0.0", "https://registry.npmmirror.com/env-paths/-/env-paths-4.0.0.tgz", { "dependencies": { "is-safe-filename": "^0.1.0" } }, "sha512-pxP8eL2SwwaTRi/KHYwLYXinDs7gL3jxFcBYmEdYfZmZXbaVDvdppd0XBU8qVz03rDfKZMXg1omHCbsJjZrMsw=="], + "environment": ["environment@1.1.0", "https://registry.npmmirror.com/environment/-/environment-1.1.0.tgz", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="], + "es-define-property": ["es-define-property@1.0.1", "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], "es-errors": ["es-errors@1.3.0", "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], @@ -960,6 +1097,8 @@ "execa": ["execa@9.6.1", "https://registry.npmmirror.com/execa/-/execa-9.6.1.tgz", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.6", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.2.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.1.1" } }, "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA=="], + "expand-template": ["expand-template@2.0.3", "https://registry.npmmirror.com/expand-template/-/expand-template-2.0.3.tgz", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="], + "express": ["express@5.2.1", "https://registry.npmmirror.com/express/-/express-5.2.1.tgz", { "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" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], "express-rate-limit": ["express-rate-limit@8.3.2", "https://registry.npmmirror.com/express-rate-limit/-/express-rate-limit-8.3.2.tgz", { "dependencies": { "ip-address": "10.1.0" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg=="], @@ -982,6 +1121,8 @@ "fd-package-json": ["fd-package-json@2.0.0", "https://registry.npmmirror.com/fd-package-json/-/fd-package-json-2.0.0.tgz", { "dependencies": { "walk-up-path": "^4.0.0" } }, "sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ=="], + "fd-slicer": ["fd-slicer@1.1.0", "https://registry.npmmirror.com/fd-slicer/-/fd-slicer-1.1.0.tgz", { "dependencies": { "pend": "~1.2.0" } }, "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g=="], + "fetch-blob": ["fetch-blob@3.2.0", "https://registry.npmmirror.com/fetch-blob/-/fetch-blob-3.2.0.tgz", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="], "fflate": ["fflate@0.8.2", "https://registry.npmmirror.com/fflate/-/fflate-0.8.2.tgz", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], @@ -998,6 +1139,8 @@ "follow-redirects": ["follow-redirects@1.15.11", "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.11.tgz", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], + "foreground-child": ["foreground-child@3.3.1", "https://registry.npmmirror.com/foreground-child/-/foreground-child-3.3.1.tgz", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + "form-data": ["form-data@4.0.5", "https://registry.npmmirror.com/form-data/-/form-data-4.0.5.tgz", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], "formatly": ["formatly@0.3.0", "https://registry.npmmirror.com/formatly/-/formatly-0.3.0.tgz", { "dependencies": { "fd-package-json": "^2.0.0" }, "bin": { "formatly": "bin/index.mjs" } }, "sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w=="], @@ -1010,6 +1153,8 @@ "fresh": ["fresh@2.0.0", "https://registry.npmmirror.com/fresh/-/fresh-2.0.0.tgz", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], + "fs-constants": ["fs-constants@1.0.0", "https://registry.npmmirror.com/fs-constants/-/fs-constants-1.0.0.tgz", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], + "fs-extra": ["fs-extra@10.1.0", "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], "fs-minipass": ["fs-minipass@3.0.3", "https://registry.npmmirror.com/fs-minipass/-/fs-minipass-3.0.3.tgz", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="], @@ -1036,10 +1181,14 @@ "get-tsconfig": ["get-tsconfig@4.13.7", "https://registry.npmmirror.com/get-tsconfig/-/get-tsconfig-4.13.7.tgz", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q=="], + "github-from-package": ["github-from-package@0.0.0", "https://registry.npmmirror.com/github-from-package/-/github-from-package-0.0.0.tgz", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="], + "glob": ["glob@13.0.6", "https://registry.npmmirror.com/glob/-/glob-13.0.6.tgz", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], "glob-parent": ["glob-parent@5.1.2", "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "globby": ["globby@14.1.0", "https://registry.npmmirror.com/globby/-/globby-14.1.0.tgz", { "dependencies": { "@sindresorhus/merge-streams": "^2.1.0", "fast-glob": "^3.3.3", "ignore": "^7.0.3", "path-type": "^6.0.0", "slash": "^5.1.0", "unicorn-magic": "^0.3.0" } }, "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA=="], + "google-auth-library": ["google-auth-library@10.6.2", "https://registry.npmmirror.com/google-auth-library/-/google-auth-library-10.6.2.tgz", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.1.4", "gcp-metadata": "8.1.2", "google-logging-utils": "1.1.3", "jws": "^4.0.0" } }, "sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw=="], "google-logging-utils": ["google-logging-utils@1.1.3", "https://registry.npmmirror.com/google-logging-utils/-/google-logging-utils-1.1.3.tgz", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="], @@ -1064,6 +1213,10 @@ "hono": ["hono@4.12.9", "https://registry.npmmirror.com/hono/-/hono-4.12.9.tgz", {}, "sha512-wy3T8Zm2bsEvxKZM5w21VdHDDcwVS1yUFFY6i8UobSsKfFceT7TOwhbhfKsDyx7tYQlmRM5FLpIuYvNFyjctiA=="], + "hosted-git-info": ["hosted-git-info@4.1.0", "https://registry.npmmirror.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz", { "dependencies": { "lru-cache": "^6.0.0" } }, "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA=="], + + "htmlparser2": ["htmlparser2@10.1.0", "https://registry.npmmirror.com/htmlparser2/-/htmlparser2-10.1.0.tgz", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "entities": "^7.0.1" } }, "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ=="], + "http-errors": ["http-errors@2.0.1", "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.1.tgz", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], "http-proxy-agent": ["http-proxy-agent@7.0.2", "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], @@ -1074,6 +1227,8 @@ "iconv-lite": ["iconv-lite@0.7.2", "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.7.2.tgz", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], + "ieee754": ["ieee754@1.2.1", "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + "ignore": ["ignore@7.0.5", "https://registry.npmmirror.com/ignore/-/ignore-7.0.5.tgz", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], "image-processor-napi": ["image-processor-napi@workspace:packages/image-processor-napi"], @@ -1082,8 +1237,12 @@ "indent-string": ["indent-string@5.0.0", "https://registry.npmmirror.com/indent-string/-/indent-string-5.0.0.tgz", {}, "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg=="], + "index-to-position": ["index-to-position@1.2.0", "https://registry.npmmirror.com/index-to-position/-/index-to-position-1.2.0.tgz", {}, "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw=="], + "inherits": ["inherits@2.0.4", "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + "ini": ["ini@1.3.8", "https://registry.npmmirror.com/ini/-/ini-1.3.8.tgz", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], + "ip-address": ["ip-address@10.1.0", "https://registry.npmmirror.com/ip-address/-/ip-address-10.1.0.tgz", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="], "ipaddr.js": ["ipaddr.js@1.9.1", "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], @@ -1116,10 +1275,18 @@ "isexe": ["isexe@2.0.0", "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "istextorbinary": ["istextorbinary@9.5.0", "https://registry.npmmirror.com/istextorbinary/-/istextorbinary-9.5.0.tgz", { "dependencies": { "binaryextensions": "^6.11.0", "editions": "^6.21.0", "textextensions": "^6.11.0" } }, "sha512-5mbUj3SiZXCuRf9fT3ibzbSSEWiy63gFfksmGfdOzujPjW3k+z8WvIBxcJHBoQNlaZaiyB25deviif2+osLmLw=="], + + "jackspeak": ["jackspeak@4.2.3", "https://registry.npmmirror.com/jackspeak/-/jackspeak-4.2.3.tgz", { "dependencies": { "@isaacs/cliui": "^9.0.0" } }, "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg=="], + "jiti": ["jiti@2.6.1", "https://registry.npmmirror.com/jiti/-/jiti-2.6.1.tgz", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], "jose": ["jose@6.2.2", "https://registry.npmmirror.com/jose/-/jose-6.2.2.tgz", {}, "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ=="], + "js-tokens": ["js-tokens@4.0.0", "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "js-yaml": ["js-yaml@4.1.1", "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.1.tgz", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + "json-bigint": ["json-bigint@1.0.0", "https://registry.npmmirror.com/json-bigint/-/json-bigint-1.0.0.tgz", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="], "json-schema-to-ts": ["json-schema-to-ts@3.1.1", "https://registry.npmmirror.com/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", { "dependencies": { "@babel/runtime": "^7.18.3", "ts-algebra": "^2.0.0" } }, "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g=="], @@ -1128,6 +1295,8 @@ "json-schema-typed": ["json-schema-typed@8.0.2", "https://registry.npmmirror.com/json-schema-typed/-/json-schema-typed-8.0.2.tgz", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="], + "json5": ["json5@2.2.3", "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], + "jsonc-parser": ["jsonc-parser@3.3.1", "https://registry.npmmirror.com/jsonc-parser/-/jsonc-parser-3.3.1.tgz", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="], "jsonfile": ["jsonfile@6.2.0", "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.0.tgz", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], @@ -1138,10 +1307,18 @@ "jws": ["jws@4.0.1", "https://registry.npmmirror.com/jws/-/jws-4.0.1.tgz", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="], + "keytar": ["keytar@7.9.0", "https://registry.npmmirror.com/keytar/-/keytar-7.9.0.tgz", { "dependencies": { "node-addon-api": "^4.3.0", "prebuild-install": "^7.0.1" } }, "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ=="], + "knip": ["knip@6.1.1", "https://registry.npmmirror.com/knip/-/knip-6.1.1.tgz", { "dependencies": { "@nodelib/fs.walk": "^1.2.3", "fast-glob": "^3.3.3", "formatly": "^0.3.0", "get-tsconfig": "4.13.7", "jiti": "^2.6.0", "minimist": "^1.2.8", "oxc-parser": "^0.121.0", "oxc-resolver": "^11.19.1", "picocolors": "^1.1.1", "picomatch": "^4.0.1", "smol-toml": "^1.6.1", "strip-json-comments": "5.0.3", "unbash": "^2.2.0", "yaml": "^2.8.2", "zod": "^4.1.11" }, "bin": { "knip": "bin/knip.js", "knip-bun": "bin/knip-bun.js" } }, "sha512-BC/kbdxwCgv+p/3YkGbtlLxbOXhQDuR+CeKKFEpJyKb3BFwG1gZa+CMWSqAnPi+kUexz74m327d3zWxyn2fMew=="], + "leven": ["leven@3.1.0", "https://registry.npmmirror.com/leven/-/leven-3.1.0.tgz", {}, "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="], + + "linkify-it": ["linkify-it@5.0.0", "https://registry.npmmirror.com/linkify-it/-/linkify-it-5.0.0.tgz", { "dependencies": { "uc.micro": "^2.0.0" } }, "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ=="], + "locate-path": ["locate-path@5.0.0", "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + "lodash": ["lodash@4.18.1", "https://registry.npmmirror.com/lodash/-/lodash-4.18.1.tgz", {}, "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q=="], + "lodash-es": ["lodash-es@4.17.23", "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.23.tgz", {}, "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg=="], "lodash.camelcase": ["lodash.camelcase@4.3.0", "https://registry.npmmirror.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="], @@ -1162,14 +1339,20 @@ "lodash.once": ["lodash.once@4.1.1", "https://registry.npmmirror.com/lodash.once/-/lodash.once-4.1.1.tgz", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="], + "lodash.truncate": ["lodash.truncate@4.4.2", "https://registry.npmmirror.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz", {}, "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw=="], + "long": ["long@5.3.2", "https://registry.npmmirror.com/long/-/long-5.3.2.tgz", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], "lru-cache": ["lru-cache@11.2.7", "https://registry.npmmirror.com/lru-cache/-/lru-cache-11.2.7.tgz", {}, "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA=="], + "markdown-it": ["markdown-it@14.1.1", "https://registry.npmmirror.com/markdown-it/-/markdown-it-14.1.1.tgz", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA=="], + "marked": ["marked@17.0.5", "https://registry.npmmirror.com/marked/-/marked-17.0.5.tgz", { "bin": { "marked": "bin/marked.js" } }, "sha512-6hLvc0/JEbRjRgzI6wnT2P1XuM1/RrrDEX0kPt0N7jGm1133g6X7DlxFasUIx+72aKAr904GTxhSLDrd5DIlZg=="], "math-intrinsics": ["math-intrinsics@1.1.0", "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + "mdurl": ["mdurl@2.0.0", "https://registry.npmmirror.com/mdurl/-/mdurl-2.0.0.tgz", {}, "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="], + "media-typer": ["media-typer@1.1.0", "https://registry.npmmirror.com/media-typer/-/media-typer-1.1.0.tgz", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], "merge-descriptors": ["merge-descriptors@2.0.0", "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-2.0.0.tgz", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], @@ -1178,11 +1361,15 @@ "micromatch": ["micromatch@4.0.8", "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + "mime": ["mime@1.6.0", "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], + "mime-db": ["mime-db@1.54.0", "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], "mime-types": ["mime-types@3.0.2", "https://registry.npmmirror.com/mime-types/-/mime-types-3.0.2.tgz", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], - "minimatch": ["minimatch@10.2.5", "https://registry.npmmirror.com/minimatch/-/minimatch-10.2.5.tgz", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + "mimic-response": ["mimic-response@3.1.0", "https://registry.npmmirror.com/mimic-response/-/mimic-response-3.1.0.tgz", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], + + "minimatch": ["minimatch@3.1.5", "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], "minimist": ["minimist@1.2.8", "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], @@ -1194,26 +1381,40 @@ "minipass-pipeline": ["minipass-pipeline@1.2.4", "https://registry.npmmirror.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A=="], + "mkdirp-classic": ["mkdirp-classic@0.5.3", "https://registry.npmmirror.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="], + "modifiers-napi": ["modifiers-napi@workspace:packages/modifiers-napi"], "module-details-from-path": ["module-details-from-path@1.0.4", "https://registry.npmmirror.com/module-details-from-path/-/module-details-from-path-1.0.4.tgz", {}, "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w=="], "ms": ["ms@2.1.3", "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "mute-stream": ["mute-stream@1.0.0", "https://registry.npmmirror.com/mute-stream/-/mute-stream-1.0.0.tgz", {}, "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA=="], + "mute-stream": ["mute-stream@0.0.8", "https://registry.npmmirror.com/mute-stream/-/mute-stream-0.0.8.tgz", {}, "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="], "mz": ["mz@2.7.0", "https://registry.npmmirror.com/mz/-/mz-2.7.0.tgz", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], + "napi-build-utils": ["napi-build-utils@2.0.0", "https://registry.npmmirror.com/napi-build-utils/-/napi-build-utils-2.0.0.tgz", {}, "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA=="], + "negotiator": ["negotiator@1.0.0", "https://registry.npmmirror.com/negotiator/-/negotiator-1.0.0.tgz", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + "node-abi": ["node-abi@3.89.0", "https://registry.npmmirror.com/node-abi/-/node-abi-3.89.0.tgz", { "dependencies": { "semver": "^7.3.5" } }, "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA=="], + + "node-addon-api": ["node-addon-api@4.3.0", "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-4.3.0.tgz", {}, "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ=="], + "node-domexception": ["node-domexception@1.0.0", "https://registry.npmmirror.com/node-domexception/-/node-domexception-1.0.0.tgz", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], "node-fetch": ["node-fetch@3.3.2", "https://registry.npmmirror.com/node-fetch/-/node-fetch-3.3.2.tgz", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], "node-forge": ["node-forge@1.4.0", "https://registry.npmmirror.com/node-forge/-/node-forge-1.4.0.tgz", {}, "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ=="], + "node-sarif-builder": ["node-sarif-builder@3.4.0", "https://registry.npmmirror.com/node-sarif-builder/-/node-sarif-builder-3.4.0.tgz", { "dependencies": { "@types/sarif": "^2.1.7", "fs-extra": "^11.1.1" } }, "sha512-tGnJW6OKRii9u/b2WiUViTJS+h7Apxx17qsMUjsUeNDiMMX5ZFf8F8Fcz7PAQ6omvOxHZtvDTmOYKJQwmfpjeg=="], + + "normalize-package-data": ["normalize-package-data@6.0.2", "https://registry.npmmirror.com/normalize-package-data/-/normalize-package-data-6.0.2.tgz", { "dependencies": { "hosted-git-info": "^7.0.0", "semver": "^7.3.5", "validate-npm-package-license": "^3.0.4" } }, "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g=="], + "npm-run-path": ["npm-run-path@6.0.0", "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-6.0.0.tgz", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="], + "nth-check": ["nth-check@2.1.1", "https://registry.npmmirror.com/nth-check/-/nth-check-2.1.1.tgz", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], + "object-assign": ["object-assign@4.1.1", "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], "object-inspect": ["object-inspect@1.13.4", "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.4.tgz", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], @@ -1240,12 +1441,20 @@ "p-try": ["p-try@2.2.0", "https://registry.npmmirror.com/p-try/-/p-try-2.2.0.tgz", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], + "package-json-from-dist": ["package-json-from-dist@1.0.1", "https://registry.npmmirror.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + + "parse-json": ["parse-json@8.3.0", "https://registry.npmmirror.com/parse-json/-/parse-json-8.3.0.tgz", { "dependencies": { "@babel/code-frame": "^7.26.2", "index-to-position": "^1.1.0", "type-fest": "^4.39.1" } }, "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ=="], + "parse-ms": ["parse-ms@4.0.0", "https://registry.npmmirror.com/parse-ms/-/parse-ms-4.0.0.tgz", {}, "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw=="], + "parse-semver": ["parse-semver@1.1.1", "https://registry.npmmirror.com/parse-semver/-/parse-semver-1.1.1.tgz", { "dependencies": { "semver": "^5.1.0" } }, "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ=="], + "parse5": ["parse5@5.1.1", "https://registry.npmmirror.com/parse5/-/parse5-5.1.1.tgz", {}, "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug=="], "parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@6.0.1", "https://registry.npmmirror.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", { "dependencies": { "parse5": "^6.0.1" } }, "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA=="], + "parse5-parser-stream": ["parse5-parser-stream@7.1.2", "https://registry.npmmirror.com/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", { "dependencies": { "parse5": "^7.0.0" } }, "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow=="], + "parseurl": ["parseurl@1.3.3", "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], "path-exists": ["path-exists@4.0.0", "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], @@ -1258,6 +1467,10 @@ "path-to-regexp": ["path-to-regexp@8.4.1", "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-8.4.1.tgz", {}, "sha512-fvU78fIjZ+SBM9YwCknCvKOUKkLVqtWDVctl0s7xIqfmfb38t2TT4ZU2gHm+Z8xGwgW+QWEU3oQSAzIbo89Ggw=="], + "path-type": ["path-type@6.0.0", "https://registry.npmmirror.com/path-type/-/path-type-6.0.0.tgz", {}, "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ=="], + + "pend": ["pend@1.2.0", "https://registry.npmmirror.com/pend/-/pend-1.2.0.tgz", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="], + "pg-int8": ["pg-int8@1.0.1", "https://registry.npmmirror.com/pg-int8/-/pg-int8-1.0.1.tgz", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="], "pg-protocol": ["pg-protocol@1.13.0", "https://registry.npmmirror.com/pg-protocol/-/pg-protocol-1.13.0.tgz", {}, "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w=="], @@ -1272,6 +1485,8 @@ "plist": ["plist@3.1.0", "https://registry.npmmirror.com/plist/-/plist-3.1.0.tgz", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ=="], + "pluralize": ["pluralize@8.0.0", "https://registry.npmmirror.com/pluralize/-/pluralize-8.0.0.tgz", {}, "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA=="], + "pngjs": ["pngjs@5.0.0", "https://registry.npmmirror.com/pngjs/-/pngjs-5.0.0.tgz", {}, "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw=="], "postgres-array": ["postgres-array@2.0.0", "https://registry.npmmirror.com/postgres-array/-/postgres-array-2.0.0.tgz", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="], @@ -1282,6 +1497,8 @@ "postgres-interval": ["postgres-interval@1.2.0", "https://registry.npmmirror.com/postgres-interval/-/postgres-interval-1.2.0.tgz", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="], + "prebuild-install": ["prebuild-install@7.1.3", "https://registry.npmmirror.com/prebuild-install/-/prebuild-install-7.1.3.tgz", { "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" } }, "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug=="], + "pretty-bytes": ["pretty-bytes@5.6.0", "https://registry.npmmirror.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz", {}, "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg=="], "pretty-ms": ["pretty-ms@9.3.0", "https://registry.npmmirror.com/pretty-ms/-/pretty-ms-9.3.0.tgz", { "dependencies": { "parse-ms": "^4.0.0" } }, "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ=="], @@ -1294,6 +1511,10 @@ "proxy-from-env": ["proxy-from-env@2.1.0", "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-2.1.0.tgz", {}, "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA=="], + "pump": ["pump@3.0.4", "https://registry.npmmirror.com/pump/-/pump-3.0.4.tgz", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA=="], + + "punycode.js": ["punycode.js@2.3.1", "https://registry.npmmirror.com/punycode.js/-/punycode.js-2.3.1.tgz", {}, "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="], + "qrcode": ["qrcode@1.5.4", "https://registry.npmmirror.com/qrcode/-/qrcode-1.5.4.tgz", { "dependencies": { "dijkstrajs": "^1.0.1", "pngjs": "^5.0.0", "yargs": "^15.3.1" }, "bin": { "qrcode": "bin/qrcode" } }, "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg=="], "qs": ["qs@6.15.0", "https://registry.npmmirror.com/qs/-/qs-6.15.0.tgz", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ=="], @@ -1304,12 +1525,22 @@ "raw-body": ["raw-body@3.0.2", "https://registry.npmmirror.com/raw-body/-/raw-body-3.0.2.tgz", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], + "rc": ["rc@1.2.8", "https://registry.npmmirror.com/rc/-/rc-1.2.8.tgz", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], + + "rc-config-loader": ["rc-config-loader@4.1.4", "https://registry.npmmirror.com/rc-config-loader/-/rc-config-loader-4.1.4.tgz", { "dependencies": { "debug": "^4.4.3", "js-yaml": "^4.1.1", "json5": "^2.2.3", "require-from-string": "^2.0.2" } }, "sha512-3GiwEzklkbXTDp52UR5nT8iXgYAx1V9ZG/kDZT7p60u2GCv2XTwQq4NzinMoMpNtXhmt3WkhYXcj6HH8HdwCEQ=="], + "react": ["react@19.2.4", "https://registry.npmmirror.com/react/-/react-19.2.4.tgz", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], "react-compiler-runtime": ["react-compiler-runtime@1.0.0", "https://registry.npmmirror.com/react-compiler-runtime/-/react-compiler-runtime-1.0.0.tgz", { "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^0.0.0-experimental" } }, "sha512-rRfjYv66HlG8896yPUDONgKzG5BxZD1nV9U6rkm+7VCuvQc903C4MjcoZR4zPw53IKSOX9wMQVpA1IAbRtzQ7w=="], "react-reconciler": ["react-reconciler@0.33.0", "https://registry.npmmirror.com/react-reconciler/-/react-reconciler-0.33.0.tgz", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-KetWRytFv1epdpJc3J4G75I4WrplZE5jOL7Yq0p34+OVOKF4Se7WrdIdVC45XsSSmUTlht2FM/fM1FZb1mfQeA=="], + "read": ["read@1.0.7", "https://registry.npmmirror.com/read/-/read-1.0.7.tgz", { "dependencies": { "mute-stream": "~0.0.4" } }, "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ=="], + + "read-pkg": ["read-pkg@9.0.1", "https://registry.npmmirror.com/read-pkg/-/read-pkg-9.0.1.tgz", { "dependencies": { "@types/normalize-package-data": "^2.4.3", "normalize-package-data": "^6.0.0", "parse-json": "^8.0.0", "type-fest": "^4.6.0", "unicorn-magic": "^0.1.0" } }, "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA=="], + + "readable-stream": ["readable-stream@3.6.2", "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + "readdirp": ["readdirp@5.0.0", "https://registry.npmmirror.com/readdirp/-/readdirp-5.0.0.tgz", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], "require-directory": ["require-directory@2.1.1", "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], @@ -1336,8 +1567,12 @@ "safer-buffer": ["safer-buffer@2.1.2", "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + "sax": ["sax@1.6.0", "https://registry.npmmirror.com/sax/-/sax-1.6.0.tgz", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], + "scheduler": ["scheduler@0.27.0", "https://registry.npmmirror.com/scheduler/-/scheduler-0.27.0.tgz", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], + "secretlint": ["secretlint@10.2.2", "https://registry.npmmirror.com/secretlint/-/secretlint-10.2.2.tgz", { "dependencies": { "@secretlint/config-creator": "^10.2.2", "@secretlint/formatter": "^10.2.2", "@secretlint/node": "^10.2.2", "@secretlint/profiler": "^10.2.2", "debug": "^4.4.1", "globby": "^14.1.0", "read-pkg": "^9.0.1" }, "bin": "./bin/secretlint.js" }, "sha512-xVpkeHV/aoWe4vP4TansF622nBEImzCY73y/0042DuJ29iKIaqgoJ8fGxre3rVSHHbxar4FdJobmTnLp9AU0eg=="], + "semver": ["semver@7.7.4", "https://registry.npmmirror.com/semver/-/semver-7.7.4.tgz", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], "send": ["send@1.2.1", "https://registry.npmmirror.com/send/-/send-1.2.1.tgz", { "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" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], @@ -1366,10 +1601,26 @@ "signal-exit": ["signal-exit@4.1.0", "https://registry.npmmirror.com/signal-exit/-/signal-exit-4.1.0.tgz", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + "simple-concat": ["simple-concat@1.0.1", "https://registry.npmmirror.com/simple-concat/-/simple-concat-1.0.1.tgz", {}, "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="], + + "simple-get": ["simple-get@4.0.1", "https://registry.npmmirror.com/simple-get/-/simple-get-4.0.1.tgz", { "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA=="], + "simple-swizzle": ["simple-swizzle@0.2.4", "https://registry.npmmirror.com/simple-swizzle/-/simple-swizzle-0.2.4.tgz", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw=="], + "slash": ["slash@5.1.0", "https://registry.npmmirror.com/slash/-/slash-5.1.0.tgz", {}, "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg=="], + + "slice-ansi": ["slice-ansi@4.0.0", "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-4.0.0.tgz", { "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" } }, "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ=="], + "smol-toml": ["smol-toml@1.6.1", "https://registry.npmmirror.com/smol-toml/-/smol-toml-1.6.1.tgz", {}, "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg=="], + "spdx-correct": ["spdx-correct@3.2.0", "https://registry.npmmirror.com/spdx-correct/-/spdx-correct-3.2.0.tgz", { "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA=="], + + "spdx-exceptions": ["spdx-exceptions@2.5.0", "https://registry.npmmirror.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="], + + "spdx-expression-parse": ["spdx-expression-parse@3.0.1", "https://registry.npmmirror.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="], + + "spdx-license-ids": ["spdx-license-ids@3.0.23", "https://registry.npmmirror.com/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", {}, "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw=="], + "ssri": ["ssri@13.0.1", "https://registry.npmmirror.com/ssri/-/ssri-13.0.1.tgz", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ=="], "stack-utils": ["stack-utils@2.0.6", "https://registry.npmmirror.com/stack-utils/-/stack-utils-2.0.6.tgz", { "dependencies": { "escape-string-regexp": "^2.0.0" } }, "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ=="], @@ -1378,6 +1629,8 @@ "string-width": ["string-width@8.2.0", "https://registry.npmmirror.com/string-width/-/string-width-8.2.0.tgz", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw=="], + "string_decoder": ["string_decoder@1.3.0", "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + "strip-ansi": ["strip-ansi@7.2.0", "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.2.0.tgz", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], "strip-final-newline": ["strip-final-newline@4.0.0", "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-4.0.0.tgz", {}, "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw=="], @@ -1386,17 +1639,31 @@ "strnum": ["strnum@2.2.2", "https://registry.npmmirror.com/strnum/-/strnum-2.2.2.tgz", {}, "sha512-DnR90I+jtXNSTXWdwrEy9FakW7UX+qUZg28gj5fk2vxxl7uS/3bpI4fjFYVmdK9etptYBPNkpahuQnEwhwECqA=="], + "structured-source": ["structured-source@4.0.0", "https://registry.npmmirror.com/structured-source/-/structured-source-4.0.0.tgz", { "dependencies": { "boundary": "^2.0.0" } }, "sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA=="], + "supports-color": ["supports-color@10.2.2", "https://registry.npmmirror.com/supports-color/-/supports-color-10.2.2.tgz", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], "supports-hyperlinks": ["supports-hyperlinks@4.4.0", "https://registry.npmmirror.com/supports-hyperlinks/-/supports-hyperlinks-4.4.0.tgz", { "dependencies": { "has-flag": "^5.0.1", "supports-color": "^10.2.2" } }, "sha512-UKbpT93hN5Nr9go5UY7bopIB9YQlMz9nm/ct4IXt/irb5YRkn9WaqrOBJGZ5Pwvsd5FQzSVeYlGdXoCAPQZrPg=="], + "table": ["table@6.9.0", "https://registry.npmmirror.com/table/-/table-6.9.0.tgz", { "dependencies": { "ajv": "^8.0.1", "lodash.truncate": "^4.4.2", "slice-ansi": "^4.0.0", "string-width": "^4.2.3", "strip-ansi": "^6.0.1" } }, "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A=="], + "tagged-tag": ["tagged-tag@1.0.0", "https://registry.npmmirror.com/tagged-tag/-/tagged-tag-1.0.0.tgz", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="], + "tar-fs": ["tar-fs@2.1.4", "https://registry.npmmirror.com/tar-fs/-/tar-fs-2.1.4.tgz", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ=="], + + "tar-stream": ["tar-stream@2.2.0", "https://registry.npmmirror.com/tar-stream/-/tar-stream-2.2.0.tgz", { "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" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], + + "terminal-link": ["terminal-link@4.0.0", "https://registry.npmmirror.com/terminal-link/-/terminal-link-4.0.0.tgz", { "dependencies": { "ansi-escapes": "^7.0.0", "supports-hyperlinks": "^3.2.0" } }, "sha512-lk+vH+MccxNqgVqSnkMVKx4VLJfnLjDBGzH16JVZjKE2DoxP57s6/vt6JmXV5I3jBcfGrxNrYtC+mPtU7WJztA=="], + + "text-table": ["text-table@0.2.0", "https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz", {}, "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="], + + "textextensions": ["textextensions@6.11.0", "https://registry.npmmirror.com/textextensions/-/textextensions-6.11.0.tgz", { "dependencies": { "editions": "^6.21.0" } }, "sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ=="], + "thenify": ["thenify@3.3.1", "https://registry.npmmirror.com/thenify/-/thenify-3.3.1.tgz", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], "thenify-all": ["thenify-all@1.6.0", "https://registry.npmmirror.com/thenify-all/-/thenify-all-1.6.0.tgz", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], - "tmp": ["tmp@0.0.33", "https://registry.npmmirror.com/tmp/-/tmp-0.0.33.tgz", { "dependencies": { "os-tmpdir": "~1.0.2" } }, "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw=="], + "tmp": ["tmp@0.2.5", "https://registry.npmmirror.com/tmp/-/tmp-0.2.5.tgz", {}, "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow=="], "to-regex-range": ["to-regex-range@5.0.1", "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], @@ -1410,16 +1677,26 @@ "tslib": ["tslib@2.8.1", "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "tunnel": ["tunnel@0.0.6", "https://registry.npmmirror.com/tunnel/-/tunnel-0.0.6.tgz", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="], + + "tunnel-agent": ["tunnel-agent@0.6.0", "https://registry.npmmirror.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], + "turndown": ["turndown@7.2.2", "https://registry.npmmirror.com/turndown/-/turndown-7.2.2.tgz", { "dependencies": { "@mixmark-io/domino": "^2.2.0" } }, "sha512-1F7db8BiExOKxjSMU2b7if62D/XOyQyZbPKq/nUwopfgnHlqXHqQ0lvfUTeUIr1lZJzOPFn43dODyMSIfvWRKQ=="], "type-fest": ["type-fest@5.5.0", "https://registry.npmmirror.com/type-fest/-/type-fest-5.5.0.tgz", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-PlBfpQwiUvGViBNX84Yxwjsdhd1TUlXr6zjX7eoirtCPIr08NAmxwa+fcYBTeRQxHo9YC9wwF3m9i700sHma8g=="], "type-is": ["type-is@2.0.1", "https://registry.npmmirror.com/type-is/-/type-is-2.0.1.tgz", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], + "typed-rest-client": ["typed-rest-client@1.8.11", "https://registry.npmmirror.com/typed-rest-client/-/typed-rest-client-1.8.11.tgz", { "dependencies": { "qs": "^6.9.1", "tunnel": "0.0.6", "underscore": "^1.12.1" } }, "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA=="], + "typescript": ["typescript@6.0.2", "https://registry.npmmirror.com/typescript/-/typescript-6.0.2.tgz", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="], + "uc.micro": ["uc.micro@2.1.0", "https://registry.npmmirror.com/uc.micro/-/uc.micro-2.1.0.tgz", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="], + "unbash": ["unbash@2.2.0", "https://registry.npmmirror.com/unbash/-/unbash-2.2.0.tgz", {}, "sha512-X2wH19RAPZE3+ldGicOkoj/SIA83OIxcJ6Cuaw23hf8Xc6fQpvZXY0SftE2JgS0QhYLUG4uwodSI3R53keyh7w=="], + "underscore": ["underscore@1.13.8", "https://registry.npmmirror.com/underscore/-/underscore-1.13.8.tgz", {}, "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ=="], + "undici": ["undici@7.24.6", "https://registry.npmmirror.com/undici/-/undici-7.24.6.tgz", {}, "sha512-Xi4agocCbRzt0yYMZGMA6ApD7gvtUFaxm4ZmeacWI4cZxaF6C+8I8QfofC20NAePiB/IcvZmzkJ7XPa471AEtA=="], "undici-types": ["undici-types@7.18.2", "https://registry.npmmirror.com/undici-types/-/undici-types-7.18.2.tgz", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], @@ -1432,12 +1709,22 @@ "url-handler-napi": ["url-handler-napi@workspace:packages/url-handler-napi"], + "url-join": ["url-join@4.0.1", "https://registry.npmmirror.com/url-join/-/url-join-4.0.1.tgz", {}, "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="], + "usehooks-ts": ["usehooks-ts@3.1.1", "https://registry.npmmirror.com/usehooks-ts/-/usehooks-ts-3.1.1.tgz", { "dependencies": { "lodash.debounce": "^4.0.8" }, "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-I4diPp9Cq6ieSUH2wu+fDAVQO43xwtulo+fKEidHUwZPnYImbtkTjzIJYcDcJqxgmX31GVqNFURodvcgHcW0pA=="], + "util-deprecate": ["util-deprecate@1.0.2", "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + "uuid": ["uuid@8.3.2", "https://registry.npmmirror.com/uuid/-/uuid-8.3.2.tgz", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + "validate-npm-package-license": ["validate-npm-package-license@3.0.4", "https://registry.npmmirror.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", { "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="], + "vary": ["vary@1.1.2", "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + "version-range": ["version-range@4.15.0", "https://registry.npmmirror.com/version-range/-/version-range-4.15.0.tgz", {}, "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg=="], + + "vscode-ide-bridge": ["vscode-ide-bridge@workspace:packages/vscode-ide-bridge"], + "vscode-jsonrpc": ["vscode-jsonrpc@8.2.1", "https://registry.npmmirror.com/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz", {}, "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ=="], "vscode-languageserver-protocol": ["vscode-languageserver-protocol@3.17.5", "https://registry.npmmirror.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", { "dependencies": { "vscode-jsonrpc": "8.2.0", "vscode-languageserver-types": "3.17.5" } }, "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg=="], @@ -1450,6 +1737,10 @@ "webidl-conversions": ["webidl-conversions@3.0.1", "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + "whatwg-encoding": ["whatwg-encoding@3.1.1", "https://registry.npmmirror.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ=="], + + "whatwg-mimetype": ["whatwg-mimetype@4.0.0", "https://registry.npmmirror.com/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="], + "whatwg-url": ["whatwg-url@5.0.0", "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], "which": ["which@2.0.2", "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], @@ -1464,6 +1755,8 @@ "wsl-utils": ["wsl-utils@0.1.0", "https://registry.npmmirror.com/wsl-utils/-/wsl-utils-0.1.0.tgz", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="], + "xml2js": ["xml2js@0.5.0", "https://registry.npmmirror.com/xml2js/-/xml2js-0.5.0.tgz", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="], + "xmlbuilder": ["xmlbuilder@15.1.1", "https://registry.npmmirror.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="], "xss": ["xss@1.0.15", "https://registry.npmmirror.com/xss/-/xss-1.0.15.tgz", { "dependencies": { "commander": "^2.20.3", "cssfilter": "0.0.10" }, "bin": { "xss": "bin/xss" } }, "sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg=="], @@ -1480,6 +1773,10 @@ "yargs-parser": ["yargs-parser@20.2.9", "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.9.tgz", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], + "yauzl": ["yauzl@2.10.0", "https://registry.npmmirror.com/yauzl/-/yauzl-2.10.0.tgz", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="], + + "yazl": ["yazl@2.5.1", "https://registry.npmmirror.com/yazl/-/yazl-2.5.1.tgz", { "dependencies": { "buffer-crc32": "~0.2.3" } }, "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw=="], + "yoctocolors": ["yoctocolors@2.1.2", "https://registry.npmmirror.com/yoctocolors/-/yoctocolors-2.1.2.tgz", {}, "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug=="], "yoctocolors-cjs": ["yoctocolors-cjs@2.1.3", "https://registry.npmmirror.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", {}, "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw=="], @@ -1646,14 +1943,20 @@ "@fastify/otel/@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.212.0", "https://registry.npmmirror.com/@opentelemetry/instrumentation/-/instrumentation-0.212.0.tgz", { "dependencies": { "@opentelemetry/api-logs": "0.212.0", "import-in-the-middle": "^2.0.6", "require-in-the-middle": "^8.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IyXmpNnifNouMOe0I/gX7ENfv2ZCNdYTF0FpCsoBcpbIHzk81Ww9rQTYTnvghszCg7qGrIhNvWC8dhEifgX9Jg=="], + "@fastify/otel/minimatch": ["minimatch@10.2.5", "https://registry.npmmirror.com/minimatch/-/minimatch-10.2.5.tgz", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + "@grpc/proto-loader/yargs": ["yargs@17.7.2", "https://registry.npmmirror.com/yargs/-/yargs-17.7.2.tgz", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], "@inquirer/core/@types/node": ["@types/node@22.19.15", "https://registry.npmmirror.com/@types/node/-/node-22.19.15.tgz", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg=="], + "@inquirer/core/mute-stream": ["mute-stream@1.0.0", "https://registry.npmmirror.com/mute-stream/-/mute-stream-1.0.0.tgz", {}, "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA=="], + "@inquirer/core/strip-ansi": ["strip-ansi@6.0.1", "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "@inquirer/core/wrap-ansi": ["wrap-ansi@6.2.0", "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], + "@inquirer/type/mute-stream": ["mute-stream@1.0.0", "https://registry.npmmirror.com/mute-stream/-/mute-stream-1.0.0.tgz", {}, "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA=="], + "@prisma/instrumentation/@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.207.0", "https://registry.npmmirror.com/@opentelemetry/instrumentation/-/instrumentation-0.207.0.tgz", { "dependencies": { "@opentelemetry/api-logs": "0.207.0", "import-in-the-middle": "^2.0.0", "require-in-the-middle": "^8.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-y6eeli9+TLKnznrR8AZlQMSJT7wILpXH+6EYq5Vf/4Ao+huI7EedxQHwRgVUOMLFbe7VFDvHJrX9/f4lcwnJsA=="], "@smithy/config-resolver/@smithy/types": ["@smithy/types@4.13.1", "https://registry.npmmirror.com/@smithy/types/-/types-4.13.1.tgz", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g=="], @@ -1768,10 +2071,28 @@ "@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.2.2", "https://registry.npmmirror.com/@smithy/util-buffer-from/-/util-buffer-from-4.2.2.tgz", { "dependencies": { "@smithy/is-array-buffer": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-FDXD7cvUoFWwN6vtQfEta540Y/YBe5JneK3SoZg9bThSoOAC/eGeYEua6RkBgKjGa/sz6Y+DuBZj3+YEY21y4Q=="], + "@textlint/linter-formatter/chalk": ["chalk@4.1.2", "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "@textlint/linter-formatter/pluralize": ["pluralize@2.0.0", "https://registry.npmmirror.com/pluralize/-/pluralize-2.0.0.tgz", {}, "sha512-TqNZzQCD4S42De9IfnnBvILN7HAW7riLqsCyp8lgjXeysyPlX5HhqKAcJHHHb9XskE4/a+7VGC9zzx8Ls0jOAw=="], + + "@textlint/linter-formatter/string-width": ["string-width@4.2.3", "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "@textlint/linter-formatter/strip-ansi": ["strip-ansi@6.0.1", "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "@typespec/ts-http-runtime/https-proxy-agent": ["https-proxy-agent@7.0.6", "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], + "@vscode/vsce/chalk": ["chalk@4.1.2", "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "@vscode/vsce/commander": ["commander@12.1.0", "https://registry.npmmirror.com/commander/-/commander-12.1.0.tgz", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], + + "@vscode/vsce/glob": ["glob@11.1.0", "https://registry.npmmirror.com/glob/-/glob-11.1.0.tgz", { "dependencies": { "foreground-child": "^3.3.1", "jackspeak": "^4.1.1", "minimatch": "^10.1.1", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw=="], + "ansi-escapes/type-fest": ["type-fest@0.21.3", "https://registry.npmmirror.com/type-fest/-/type-fest-0.21.3.tgz", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], + "cheerio/parse5": ["parse5@7.3.0", "https://registry.npmmirror.com/parse5/-/parse5-7.3.0.tgz", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], + + "cheerio/parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@7.1.0", "https://registry.npmmirror.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", { "dependencies": { "domhandler": "^5.0.3", "parse5": "^7.0.0" } }, "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g=="], + "cli-highlight/chalk": ["chalk@4.1.2", "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "cli-highlight/highlight.js": ["highlight.js@10.7.3", "https://registry.npmmirror.com/highlight.js/-/highlight.js-10.7.3.tgz", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="], @@ -1782,14 +2103,26 @@ "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "encoding-sniffer/iconv-lite": ["iconv-lite@0.6.3", "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + "external-editor/iconv-lite": ["iconv-lite@0.4.24", "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], + "external-editor/tmp": ["tmp@0.0.33", "https://registry.npmmirror.com/tmp/-/tmp-0.0.33.tgz", { "dependencies": { "os-tmpdir": "~1.0.2" } }, "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw=="], + "form-data/mime-types": ["mime-types@2.1.35", "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], "gaxios/https-proxy-agent": ["https-proxy-agent@7.0.6", "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], + "glob/minimatch": ["minimatch@10.2.5", "https://registry.npmmirror.com/minimatch/-/minimatch-10.2.5.tgz", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "globby/@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@2.3.0", "https://registry.npmmirror.com/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", {}, "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg=="], + "gtoken/gaxios": ["gaxios@6.7.1", "https://registry.npmmirror.com/gaxios/-/gaxios-6.7.1.tgz", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", "node-fetch": "^2.6.9", "uuid": "^9.0.1" } }, "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ=="], + "hosted-git-info/lru-cache": ["lru-cache@6.0.0", "https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], + + "htmlparser2/entities": ["entities@7.0.1", "https://registry.npmmirror.com/entities/-/entities-7.0.1.tgz", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], + "http-proxy-agent/agent-base": ["agent-base@7.1.4", "https://registry.npmmirror.com/agent-base/-/agent-base-7.1.4.tgz", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], "image-processor-napi/sharp": ["sharp@0.33.5", "https://registry.npmmirror.com/sharp/-/sharp-0.33.5.tgz", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="], @@ -1800,16 +2133,48 @@ "minipass-pipeline/minipass": ["minipass@3.3.6", "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "node-sarif-builder/fs-extra": ["fs-extra@11.3.4", "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.3.4.tgz", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA=="], + + "normalize-package-data/hosted-git-info": ["hosted-git-info@7.0.2", "https://registry.npmmirror.com/hosted-git-info/-/hosted-git-info-7.0.2.tgz", { "dependencies": { "lru-cache": "^10.0.1" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="], + "npm-run-path/path-key": ["path-key@4.0.0", "https://registry.npmmirror.com/path-key/-/path-key-4.0.0.tgz", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], + "parse-json/type-fest": ["type-fest@4.41.0", "https://registry.npmmirror.com/type-fest/-/type-fest-4.41.0.tgz", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], + + "parse-semver/semver": ["semver@5.7.2", "https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], + "parse5-htmlparser2-tree-adapter/parse5": ["parse5@6.0.1", "https://registry.npmmirror.com/parse5/-/parse5-6.0.1.tgz", {}, "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="], + "parse5-parser-stream/parse5": ["parse5@7.3.0", "https://registry.npmmirror.com/parse5/-/parse5-7.3.0.tgz", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], + "proper-lockfile/signal-exit": ["signal-exit@3.0.7", "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], "qrcode/yargs": ["yargs@15.4.1", "https://registry.npmmirror.com/yargs/-/yargs-15.4.1.tgz", { "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" } }, "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A=="], + "rc/strip-json-comments": ["strip-json-comments@2.0.1", "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], + + "read-pkg/type-fest": ["type-fest@4.41.0", "https://registry.npmmirror.com/type-fest/-/type-fest-4.41.0.tgz", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], + + "read-pkg/unicorn-magic": ["unicorn-magic@0.1.0", "https://registry.npmmirror.com/unicorn-magic/-/unicorn-magic-0.1.0.tgz", {}, "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ=="], + + "slice-ansi/ansi-styles": ["ansi-styles@4.3.0", "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "table/string-width": ["string-width@4.2.3", "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "table/strip-ansi": ["strip-ansi@6.0.1", "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "terminal-link/ansi-escapes": ["ansi-escapes@7.3.0", "https://registry.npmmirror.com/ansi-escapes/-/ansi-escapes-7.3.0.tgz", { "dependencies": { "environment": "^1.0.0" } }, "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg=="], + + "terminal-link/supports-hyperlinks": ["supports-hyperlinks@3.2.0", "https://registry.npmmirror.com/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", { "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" } }, "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig=="], + "vscode-languageserver-protocol/vscode-jsonrpc": ["vscode-jsonrpc@8.2.0", "https://registry.npmmirror.com/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", {}, "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="], + "whatwg-encoding/iconv-lite": ["iconv-lite@0.6.3", "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + + "xml2js/xmlbuilder": ["xmlbuilder@11.0.1", "https://registry.npmmirror.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="], + "xss/commander": ["commander@2.20.3", "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], "yargs/string-width": ["string-width@4.2.3", "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], @@ -1860,6 +2225,8 @@ "@fastify/otel/@opentelemetry/instrumentation/import-in-the-middle": ["import-in-the-middle@2.0.6", "https://registry.npmmirror.com/import-in-the-middle/-/import-in-the-middle-2.0.6.tgz", { "dependencies": { "acorn": "^8.15.0", "acorn-import-attributes": "^1.9.5", "cjs-module-lexer": "^2.2.0", "module-details-from-path": "^1.0.4" } }, "sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw=="], + "@fastify/otel/minimatch/brace-expansion": ["brace-expansion@5.0.5", "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-5.0.5.tgz", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ=="], + "@grpc/proto-loader/yargs/cliui": ["cliui@8.0.1", "https://registry.npmmirror.com/cliui/-/cliui-8.0.1.tgz", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], "@grpc/proto-loader/yargs/string-width": ["string-width@4.2.3", "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], @@ -1916,8 +2283,26 @@ "@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.2", "https://registry.npmmirror.com/@smithy/is-array-buffer/-/is-array-buffer-4.2.2.tgz", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow=="], + "@textlint/linter-formatter/chalk/ansi-styles": ["ansi-styles@4.3.0", "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "@textlint/linter-formatter/chalk/supports-color": ["supports-color@7.2.0", "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "@textlint/linter-formatter/string-width/emoji-regex": ["emoji-regex@8.0.0", "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "@textlint/linter-formatter/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "@textlint/linter-formatter/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "@typespec/ts-http-runtime/https-proxy-agent/agent-base": ["agent-base@7.1.4", "https://registry.npmmirror.com/agent-base/-/agent-base-7.1.4.tgz", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], + "@vscode/vsce/chalk/ansi-styles": ["ansi-styles@4.3.0", "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "@vscode/vsce/chalk/supports-color": ["supports-color@7.2.0", "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "@vscode/vsce/glob/minimatch": ["minimatch@10.2.5", "https://registry.npmmirror.com/minimatch/-/minimatch-10.2.5.tgz", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "cheerio/parse5/entities": ["entities@6.0.1", "https://registry.npmmirror.com/entities/-/entities-6.0.1.tgz", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + "cli-highlight/chalk/ansi-styles": ["ansi-styles@4.3.0", "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "cli-highlight/chalk/supports-color": ["supports-color@7.2.0", "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], @@ -1934,6 +2319,8 @@ "gaxios/https-proxy-agent/agent-base": ["agent-base@7.1.4", "https://registry.npmmirror.com/agent-base/-/agent-base-7.1.4.tgz", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], + "glob/minimatch/brace-expansion": ["brace-expansion@5.0.5", "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-5.0.5.tgz", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ=="], + "gtoken/gaxios/https-proxy-agent": ["https-proxy-agent@7.0.6", "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], "gtoken/gaxios/is-stream": ["is-stream@2.0.1", "https://registry.npmmirror.com/is-stream/-/is-stream-2.0.1.tgz", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], @@ -1980,6 +2367,10 @@ "image-processor-napi/sharp/@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "https://registry.npmmirror.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="], + "normalize-package-data/hosted-git-info/lru-cache": ["lru-cache@10.4.3", "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.4.3.tgz", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "parse5-parser-stream/parse5/entities": ["entities@6.0.1", "https://registry.npmmirror.com/entities/-/entities-6.0.1.tgz", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + "qrcode/yargs/cliui": ["cliui@6.0.0", "https://registry.npmmirror.com/cliui/-/cliui-6.0.0.tgz", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" } }, "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ=="], "qrcode/yargs/string-width": ["string-width@4.2.3", "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], @@ -1988,6 +2379,16 @@ "qrcode/yargs/yargs-parser": ["yargs-parser@18.1.3", "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-18.1.3.tgz", { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ=="], + "table/string-width/emoji-regex": ["emoji-regex@8.0.0", "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "table/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "table/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "terminal-link/supports-hyperlinks/has-flag": ["has-flag@4.0.0", "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "terminal-link/supports-hyperlinks/supports-color": ["supports-color@7.2.0", "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "yargs/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], @@ -2028,6 +2429,8 @@ "@aws-sdk/nested-clients/@smithy/util-base64/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@4.2.2", "https://registry.npmmirror.com/@smithy/is-array-buffer/-/is-array-buffer-4.2.2.tgz", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow=="], + "@fastify/otel/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "https://registry.npmmirror.com/balanced-match/-/balanced-match-4.0.4.tgz", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + "@grpc/proto-loader/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "@grpc/proto-loader/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], @@ -2058,8 +2461,16 @@ "@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@2.2.0", "https://registry.npmmirror.com/@smithy/querystring-builder/-/querystring-builder-2.2.0.tgz", { "dependencies": { "@smithy/types": "^2.12.0", "@smithy/util-uri-escape": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A=="], + "@textlint/linter-formatter/chalk/supports-color/has-flag": ["has-flag@4.0.0", "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "@vscode/vsce/chalk/supports-color/has-flag": ["has-flag@4.0.0", "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "@vscode/vsce/glob/minimatch/brace-expansion": ["brace-expansion@5.0.5", "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-5.0.5.tgz", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ=="], + "cli-highlight/chalk/supports-color/has-flag": ["has-flag@4.0.0", "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + "glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "https://registry.npmmirror.com/balanced-match/-/balanced-match-4.0.4.tgz", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + "gtoken/gaxios/https-proxy-agent/agent-base": ["agent-base@7.1.4", "https://registry.npmmirror.com/agent-base/-/agent-base-7.1.4.tgz", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], "qrcode/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -2086,6 +2497,8 @@ "@smithy/smithy-client/@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder/@smithy/util-uri-escape": ["@smithy/util-uri-escape@2.2.0", "https://registry.npmmirror.com/@smithy/util-uri-escape/-/util-uri-escape-2.2.0.tgz", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA=="], + "@vscode/vsce/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "https://registry.npmmirror.com/balanced-match/-/balanced-match-4.0.4.tgz", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + "qrcode/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "qrcode/yargs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], diff --git a/docs/superpowers/plans/2026-04-07-vscode-ide-bridge.md b/docs/superpowers/plans/2026-04-07-vscode-ide-bridge.md new file mode 100644 index 000000000..808cd8046 --- /dev/null +++ b/docs/superpowers/plans/2026-04-07-vscode-ide-bridge.md @@ -0,0 +1,664 @@ +# VSCode IDE Bridge Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 为当前 CLI 增加一个可运行的 VSCode `ws-ide` 扩展端实现,让 `/ide`、选区上下文注入和 IDE diff 预览在本地 VSCode 中可用。 + +**Architecture:** 在仓库中新增独立的 VSCode 扩展包,扩展在本地启动 WebSocket IDE Bridge,并通过 lockfile 让 CLI 自动发现。扩展在该连接上暴露一个 MCP Server,负责发送 `selection_changed` / `ide_connected` 通知,并实现 `openDiff`、`close_tab`、`closeAllDiffTabs` 这几个 CLI 已使用的 MCP tools。 + +**Tech Stack:** TypeScript、VSCode Extension API、WebSocket、`@modelcontextprotocol/sdk`、Node.js 文件系统 API + +> 说明:执行前已校正协议边界。这里的 `openDiff` / `close_tab` / `closeAllDiffTabs` 不是自定义裸 WebSocket RPC,而是通过 MCP tool 调用完成;`selection_changed` / `ide_connected` 才是扩展主动发往 CLI 的通知。 + +--- + +### Task 1: 脚手架 VSCode 扩展包 + +**Files:** +- Create: `packages/vscode-ide-bridge/package.json` +- Create: `packages/vscode-ide-bridge/tsconfig.json` +- Create: `packages/vscode-ide-bridge/src/extension.ts` +- Modify: `package.json` + +- [ ] **Step 1: 写出失败测试或校验入口约束** + +使用最小结构校验,确保新包会被 workspace 识别并且扩展入口文件存在。 + +```ts +import { describe, expect, test } from "bun:test"; +import pkg from "../../vscode-ide-bridge/package.json"; + +describe("vscode-ide-bridge package", () => { + test("declares a VSCode extension entry", () => { + expect(pkg.main).toBe("./dist/extension.js"); + expect(pkg.engines.vscode).toBeDefined(); + }); +}); +``` + +- [ ] **Step 2: 运行测试并确认失败** + +Run: `bun test packages/vscode-ide-bridge/test/package.test.ts` +Expected: FAIL,提示包文件不存在或字段缺失 + +- [ ] **Step 3: 写最小扩展包结构** + +`packages/vscode-ide-bridge/package.json` + +```json +{ + "name": "vscode-ide-bridge", + "private": true, + "version": "0.0.1", + "type": "module", + "main": "./dist/extension.js", + "engines": { + "vscode": "^1.90.0" + }, + "activationEvents": [ + "onStartupFinished", + "onCommand:claudeCodeBridge.restart", + "onCommand:claudeCodeBridge.showStatus" + ], + "contributes": { + "commands": [ + { + "command": "claudeCodeBridge.restart", + "title": "Claude Code Bridge: Restart" + }, + { + "command": "claudeCodeBridge.showStatus", + "title": "Claude Code Bridge: Show Status" + } + ] + } +} +``` + +`packages/vscode-ide-bridge/tsconfig.json` + +```json +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "dist", + "rootDir": "src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "types": ["node", "vscode"] + }, + "include": ["src/**/*.ts"] +} +``` + +`packages/vscode-ide-bridge/src/extension.ts` + +```ts +import * as vscode from "vscode"; + +export async function activate(context: vscode.ExtensionContext): Promise { + context.subscriptions.push( + vscode.commands.registerCommand("claudeCodeBridge.restart", () => {}), + vscode.commands.registerCommand("claudeCodeBridge.showStatus", () => {}) + ); +} + +export async function deactivate(): Promise {} +``` + +根目录 `package.json` workspace 增加: + +```json +{ + "workspaces": [ + "packages/*", + "packages/@ant/*", + "packages/vscode-ide-bridge" + ] +} +``` + +- [ ] **Step 4: 运行测试确认通过** + +Run: `bun test packages/vscode-ide-bridge/test/package.test.ts` +Expected: PASS + +- [ ] **Step 5: Commit** + +```bash +git add package.json packages/vscode-ide-bridge/package.json packages/vscode-ide-bridge/tsconfig.json packages/vscode-ide-bridge/src/extension.ts packages/vscode-ide-bridge/test/package.test.ts +git commit -m "feat: scaffold vscode ide bridge extension" +``` + +### Task 2: 实现 lockfile 与状态模型 + +**Files:** +- Create: `packages/vscode-ide-bridge/src/server/lockfile.ts` +- Create: `packages/vscode-ide-bridge/src/server/workspaceInfo.ts` +- Create: `packages/vscode-ide-bridge/src/server/protocol.ts` +- Create: `packages/vscode-ide-bridge/test/lockfile.test.ts` + +- [ ] **Step 1: 写失败测试** + +```ts +import { describe, expect, test } from "bun:test"; +import { buildLockfilePayload } from "../src/server/lockfile"; + +describe("buildLockfilePayload", () => { + test("includes ws transport, auth token and workspace folders", () => { + const payload = buildLockfilePayload({ + port: 8123, + pid: 100, + ideName: "VS Code", + workspaceFolders: ["D:/repo"], + authToken: "token-1", + runningInWindows: true + }); + + expect(payload.transport).toBe("ws"); + expect(payload.authToken).toBe("token-1"); + expect(payload.workspaceFolders).toEqual(["D:/repo"]); + }); +}); +``` + +- [ ] **Step 2: 运行测试并确认失败** + +Run: `bun test packages/vscode-ide-bridge/test/lockfile.test.ts` +Expected: FAIL,提示模块不存在 + +- [ ] **Step 3: 写最小实现** + +`packages/vscode-ide-bridge/src/server/protocol.ts` + +```ts +export type LockfilePayload = { + workspaceFolders: string[]; + pid: number; + ideName: string; + transport: "ws"; + runningInWindows: boolean; + authToken: string; +}; +``` + +`packages/vscode-ide-bridge/src/server/lockfile.ts` + +```ts +import { mkdir, rm, writeFile } from "node:fs/promises"; +import { homedir } from "node:os"; +import { join } from "node:path"; +import type { LockfilePayload } from "./protocol"; + +export function buildLockfilePayload(input: { + port: number; + pid: number; + ideName: string; + workspaceFolders: string[]; + authToken: string; + runningInWindows: boolean; +}): LockfilePayload { + return { + workspaceFolders: input.workspaceFolders, + pid: input.pid, + ideName: input.ideName, + transport: "ws", + runningInWindows: input.runningInWindows, + authToken: input.authToken + }; +} + +export function getLockfilePath(port: number): string { + return join(homedir(), ".claude", "ide", `${port}.lock`); +} + +export async function writeLockfile(port: number, payload: LockfilePayload): Promise { + const path = getLockfilePath(port); + await mkdir(join(homedir(), ".claude", "ide"), { recursive: true }); + await writeFile(path, JSON.stringify(payload), "utf8"); + return path; +} + +export async function removeLockfile(path: string | null): Promise { + if (!path) return; + await rm(path, { force: true }); +} +``` + +`packages/vscode-ide-bridge/src/server/workspaceInfo.ts` + +```ts +import * as vscode from "vscode"; + +export function getWorkspaceFolders(): string[] { + return (vscode.workspace.workspaceFolders ?? []).map(folder => folder.uri.fsPath); +} +``` + +- [ ] **Step 4: 运行测试确认通过** + +Run: `bun test packages/vscode-ide-bridge/test/lockfile.test.ts` +Expected: PASS + +- [ ] **Step 5: Commit** + +```bash +git add packages/vscode-ide-bridge/src/server/protocol.ts packages/vscode-ide-bridge/src/server/lockfile.ts packages/vscode-ide-bridge/src/server/workspaceInfo.ts packages/vscode-ide-bridge/test/lockfile.test.ts +git commit -m "feat: add vscode ide bridge lockfile support" +``` + +### Task 3: 实现选区发布链路 + +**Files:** +- Create: `packages/vscode-ide-bridge/src/server/selectionPublisher.ts` +- Create: `packages/vscode-ide-bridge/test/selectionPublisher.test.ts` +- Modify: `packages/vscode-ide-bridge/src/extension.ts` + +- [ ] **Step 1: 写失败测试** + +```ts +import { describe, expect, test } from "bun:test"; +import { buildSelectionChangedParams } from "../src/server/selectionPublisher"; + +describe("buildSelectionChangedParams", () => { + test("serializes editor selection and text", () => { + const params = buildSelectionChangedParams({ + filePath: "D:/repo/src/app.ts", + text: "const x = 1;", + start: { line: 1, character: 0 }, + end: { line: 1, character: 12 } + }); + + expect(params.filePath).toBe("D:/repo/src/app.ts"); + expect(params.text).toBe("const x = 1;"); + expect(params.selection?.start.line).toBe(1); + }); +}); +``` + +- [ ] **Step 2: 运行测试并确认失败** + +Run: `bun test packages/vscode-ide-bridge/test/selectionPublisher.test.ts` +Expected: FAIL,提示导出不存在 + +- [ ] **Step 3: 写最小实现** + +`packages/vscode-ide-bridge/src/server/selectionPublisher.ts` + +```ts +export type SelectionPoint = { + line: number; + character: number; +}; + +export type SelectionChangedParams = { + selection: { + start: SelectionPoint; + end: SelectionPoint; + } | null; + text?: string; + filePath?: string; +}; + +export function buildSelectionChangedParams(input: { + filePath?: string; + text?: string; + start?: SelectionPoint; + end?: SelectionPoint; +}): SelectionChangedParams { + if (!input.start || !input.end) { + return { + selection: null, + text: input.text, + filePath: input.filePath + }; + } + + return { + selection: { + start: input.start, + end: input.end + }, + text: input.text, + filePath: input.filePath + }; +} +``` + +`packages/vscode-ide-bridge/src/extension.ts` 先增加一个占位发布调用: + +```ts +import * as vscode from "vscode"; +import { buildSelectionChangedParams } from "./server/selectionPublisher"; + +export async function activate(context: vscode.ExtensionContext): Promise { + const disposable = vscode.window.onDidChangeTextEditorSelection(event => { + const editor = event.textEditor; + const selection = editor.selection; + buildSelectionChangedParams({ + filePath: editor.document.uri.fsPath, + text: editor.document.getText(selection), + start: { + line: selection.start.line, + character: selection.start.character + }, + end: { + line: selection.end.line, + character: selection.end.character + } + }); + }); + + context.subscriptions.push( + disposable, + vscode.commands.registerCommand("claudeCodeBridge.restart", () => {}), + vscode.commands.registerCommand("claudeCodeBridge.showStatus", () => {}) + ); +} +``` + +- [ ] **Step 4: 运行测试确认通过** + +Run: `bun test packages/vscode-ide-bridge/test/selectionPublisher.test.ts` +Expected: PASS + +- [ ] **Step 5: Commit** + +```bash +git add packages/vscode-ide-bridge/src/server/selectionPublisher.ts packages/vscode-ide-bridge/test/selectionPublisher.test.ts packages/vscode-ide-bridge/src/extension.ts +git commit -m "feat: add vscode selection publisher primitives" +``` + +### Task 4: 实现 WebSocket bridge server 与鉴权 + +**Files:** +- Create: `packages/vscode-ide-bridge/src/server/bridgeServer.ts` +- Create: `packages/vscode-ide-bridge/test/bridgeServer.test.ts` +- Modify: `packages/vscode-ide-bridge/src/extension.ts` + +- [ ] **Step 1: 写失败测试** + +```ts +import { describe, expect, test } from "bun:test"; +import { isAuthorizedUpgrade } from "../src/server/bridgeServer"; + +describe("isAuthorizedUpgrade", () => { + test("accepts matching token", () => { + expect(isAuthorizedUpgrade("abc", "abc")).toBe(true); + }); + + test("rejects mismatched token", () => { + expect(isAuthorizedUpgrade("abc", "def")).toBe(false); + }); +}); +``` + +- [ ] **Step 2: 运行测试并确认失败** + +Run: `bun test packages/vscode-ide-bridge/test/bridgeServer.test.ts` +Expected: FAIL,提示模块不存在 + +- [ ] **Step 3: 写最小实现** + +`packages/vscode-ide-bridge/src/server/bridgeServer.ts` + +```ts +import { WebSocketServer } from "ws"; + +export function isAuthorizedUpgrade(expected: string, actual: string | undefined): boolean { + return Boolean(actual) && expected === actual; +} + +export class BridgeServer { + private server: WebSocketServer | null = null; + + constructor(private readonly authToken: string) {} + + async start(port: number): Promise { + this.server = new WebSocketServer({ + host: "127.0.0.1", + port + }); + } + + async stop(): Promise { + await new Promise(resolve => { + if (!this.server) return resolve(); + this.server.close(() => resolve()); + this.server = null; + }); + } +} +``` + +`packages/vscode-ide-bridge/src/extension.ts` 中接入: + +```ts +import * as vscode from "vscode"; +import { randomUUID } from "node:crypto"; +import { BridgeServer } from "./server/bridgeServer"; + +let bridgeServer: BridgeServer | null = null; + +export async function activate(context: vscode.ExtensionContext): Promise { + bridgeServer = new BridgeServer(randomUUID()); + await bridgeServer.start(0); + context.subscriptions.push({ + dispose() { + void bridgeServer?.stop(); + } + }); +} +``` + +- [ ] **Step 4: 运行测试确认通过** + +Run: `bun test packages/vscode-ide-bridge/test/bridgeServer.test.ts` +Expected: PASS + +- [ ] **Step 5: Commit** + +```bash +git add packages/vscode-ide-bridge/src/server/bridgeServer.ts packages/vscode-ide-bridge/test/bridgeServer.test.ts packages/vscode-ide-bridge/src/extension.ts +git commit -m "feat: add vscode ide bridge websocket server" +``` + +### Task 5: 实现 diff RPC 和状态命令 + +**Files:** +- Create: `packages/vscode-ide-bridge/src/server/diffController.ts` +- Modify: `packages/vscode-ide-bridge/src/extension.ts` +- Create: `packages/vscode-ide-bridge/test/diffController.test.ts` + +- [ ] **Step 1: 写失败测试** + +```ts +import { describe, expect, test } from "bun:test"; +import { DiffSessionStore } from "../src/server/diffController"; + +describe("DiffSessionStore", () => { + test("stores and removes tab mappings by tab name", () => { + const store = new DiffSessionStore(); + store.set("tab-1", "memfs:/right.ts"); + expect(store.get("tab-1")).toBe("memfs:/right.ts"); + store.delete("tab-1"); + expect(store.get("tab-1")).toBeUndefined(); + }); +}); +``` + +- [ ] **Step 2: 运行测试并确认失败** + +Run: `bun test packages/vscode-ide-bridge/test/diffController.test.ts` +Expected: FAIL,提示模块不存在 + +- [ ] **Step 3: 写最小实现** + +`packages/vscode-ide-bridge/src/server/diffController.ts` + +```ts +export class DiffSessionStore { + private readonly sessions = new Map(); + + set(tabName: string, uri: string): void { + this.sessions.set(tabName, uri); + } + + get(tabName: string): string | undefined { + return this.sessions.get(tabName); + } + + delete(tabName: string): void { + this.sessions.delete(tabName); + } + + clear(): void { + this.sessions.clear(); + } +} +``` + +`packages/vscode-ide-bridge/src/extension.ts` 增加状态命令: + +```ts +import * as vscode from "vscode"; + +export async function activate(context: vscode.ExtensionContext): Promise { + const output = vscode.window.createOutputChannel("Claude Code IDE Bridge"); + + context.subscriptions.push( + output, + vscode.commands.registerCommand("claudeCodeBridge.showStatus", async () => { + output.appendLine("Claude Code IDE Bridge is running."); + output.show(true); + }) + ); +} +``` + +- [ ] **Step 4: 运行测试确认通过** + +Run: `bun test packages/vscode-ide-bridge/test/diffController.test.ts` +Expected: PASS + +- [ ] **Step 5: Commit** + +```bash +git add packages/vscode-ide-bridge/src/server/diffController.ts packages/vscode-ide-bridge/test/diffController.test.ts packages/vscode-ide-bridge/src/extension.ts +git commit -m "feat: add vscode ide bridge diff state and status command" +``` + +### Task 6: 接通完整激活流程与手工验证说明 + +**Files:** +- Modify: `packages/vscode-ide-bridge/src/extension.ts` +- Modify: `README.md` +- Modify: `README_EN.md` + +- [ ] **Step 1: 写失败校验** + +用文档断言确保 README 中包含 bridge 启动与 `/ide` 使用说明。 + +```ts +import { describe, expect, test } from "bun:test"; +import { readFileSync } from "node:fs"; + +describe("README bridge docs", () => { + test("documents vscode ide bridge usage", () => { + const readme = readFileSync("README.md", "utf8"); + expect(readme.includes("VSCode IDE Bridge")).toBe(true); + expect(readme.includes("/ide")).toBe(true); + }); +}); +``` + +- [ ] **Step 2: 运行测试并确认失败** + +Run: `bun test packages/vscode-ide-bridge/test/readme.test.ts` +Expected: FAIL,提示 README 中没有 bridge 文档 + +- [ ] **Step 3: 实现激活主流程与文档** + +`packages/vscode-ide-bridge/src/extension.ts` 最终需要做到: + +```ts +import * as vscode from "vscode"; +import { randomUUID } from "node:crypto"; +import { writeLockfile, removeLockfile, buildLockfilePayload } from "./server/lockfile"; +import { getWorkspaceFolders } from "./server/workspaceInfo"; +import { BridgeServer } from "./server/bridgeServer"; + +let lockfilePath: string | null = null; +let bridgeServer: BridgeServer | null = null; + +export async function activate(context: vscode.ExtensionContext): Promise { + const authToken = randomUUID(); + const output = vscode.window.createOutputChannel("Claude Code IDE Bridge"); + + bridgeServer = new BridgeServer(authToken); + await bridgeServer.start(0); + + const payload = buildLockfilePayload({ + port: 0, + pid: process.pid, + ideName: "VS Code", + workspaceFolders: getWorkspaceFolders(), + authToken, + runningInWindows: process.platform === "win32" + }); + + lockfilePath = await writeLockfile(0, payload); + output.appendLine(`Bridge started. Lockfile: ${lockfilePath}`); + + context.subscriptions.push(output, { + dispose() { + void bridgeServer?.stop(); + void removeLockfile(lockfilePath); + } + }); +} + +export async function deactivate(): Promise { + await bridgeServer?.stop(); + await removeLockfile(lockfilePath); +} +``` + +README 中文和英文各补一个简短章节,说明: + +- 扩展启动后会暴露本地 bridge +- 启动 CLI 后执行 `/ide` +- 在 VSCode 里选中代码,再向 CLI 提问 +- diff 预览由 CLI 主动触发 + +- [ ] **Step 4: 运行验证** + +Run: `bun test packages/vscode-ide-bridge/test/readme.test.ts` +Expected: PASS + +Run: `bun test packages/vscode-ide-bridge/test/*.test.ts` +Expected: PASS + +手工验证: + +Run: `bun run build.ts` +Expected: 构建完成,无本次改动引入的额外错误 + +手工步骤: + +1. 在 VSCode 启动扩展开发宿主 +2. 打开本仓库 +3. 启动 CLI +4. 执行 `/ide` +5. 在编辑器中选中文本后提问 +6. 验证 CLI 可见 IDE 选区上下文 + +- [ ] **Step 5: Commit** + +```bash +git add packages/vscode-ide-bridge/src/extension.ts README.md README_EN.md packages/vscode-ide-bridge/test/readme.test.ts +git commit -m "feat: wire vscode ide bridge activation and docs" +``` diff --git a/docs/superpowers/specs/2026-04-07-vscode-ide-bridge-design.md b/docs/superpowers/specs/2026-04-07-vscode-ide-bridge-design.md new file mode 100644 index 000000000..4182dd72f --- /dev/null +++ b/docs/superpowers/specs/2026-04-07-vscode-ide-bridge-design.md @@ -0,0 +1,350 @@ +# VSCode IDE Bridge 设计文档 + +**日期:** 2026-04-07 + +## 1. 背景 + +当前仓库已经具备一套较完整的 IDE 接入链路: + +- CLI 能发现 `ws-ide` / `sse-ide` 类型的 IDE 连接 +- CLI 能接收 `selection_changed` 并将其注入为 `` 上下文 +- CLI 能调用 `openDiff`、`close_tab`、`closeAllDiffTabs` 等 IDE RPC +- `/ide`、diff 预览、选区提示、已打开文件提示都依赖这套链路 + +但当前仓库中没有可直接使用的 VSCode 扩展实现,导致本地 VSCode 无法真正把这些能力提供给 CLI。目标不是重做一个聊天面板,而是补齐一个兼容现有 CLI 协议的 VSCode 扩展,让 CLI “像连接到原生 IDE 扩展一样”工作。 + +## 2. 目标 + +构建一个独立的 VSCode 扩展,在本地暴露一个与当前 CLI 兼容的 `ws-ide` 服务,完成以下能力: + +1. 让 CLI 能自动发现 VSCode +2. 让 VSCode 当前文件和选区变化能进入 CLI 的 IDE 上下文链路 +3. 让 CLI 发起的 diff 预览能在 VSCode 中打开和关闭 +4. 保持实现最小、可调试、可逐步扩展 + +## 3. 非目标 + +第一版明确不做以下内容: + +- 不实现 VSCode 聊天面板 +- 不接入远程工作区、Codespaces、Dev Container、SSH Remote +- 不兼容多台机器之间的桥接 +- 不实现复杂的会话恢复或扩展端持久化缓存 +- 不覆盖官方扩展的所有功能 + +## 4. 总体方案 + +采用“独立 sidecar 扩展 + 本地 WebSocket IDE Bridge”的方式。 + +### 4.1 连接模型 + +VSCode 扩展启动后: + +1. 在 `127.0.0.1` 上启动一个随机可用端口的 WebSocket 服务 +2. 生成与 CLI 现有 IDE 发现逻辑兼容的 lockfile +3. 等待 CLI 以 `ws-ide` MCP 客户端身份连接 +4. 扩展在该 WebSocket 连接上暴露 MCP Server,负责把 IDE 事件推送给 CLI,并响应 CLI 发来的 MCP tool 调用 + +### 4.2 复用现有 CLI 能力 + +扩展尽量不改 CLI 的上层交互,只复用现有协议: + +- VSCode -> CLI:`selection_changed`、`ide_connected` 通知 +- CLI -> VSCode:通过 MCP tool 调用 `openDiff`、`close_tab`、`closeAllDiffTabs` + +这样可以最大化复用: + +- `src/hooks/useIdeSelection.ts` +- `src/utils/attachments.ts` +- `src/utils/messages.ts` +- `src/hooks/useDiffInIDE.ts` +- `/ide` 命令及 IDE 状态展示 + +## 5. 协议设计 + +### 5.1 Lockfile + +扩展写出的 lockfile 需要满足 CLI 的 IDE 自动发现逻辑。内容至少包含: + +- `workspaceFolders` +- `pid` +- `ideName` +- `transport: "ws"` +- `runningInWindows` +- `authToken` + +文件名使用端口号,例如 `.lock`。 + +### 5.2 鉴权 + +扩展启动时生成一次随机 `authToken`: + +- 写入 lockfile +- CLI 连接 `ws-ide` 时通过 `X-Claude-Code-Ide-Authorization` 头带上 +- 扩展端校验成功后才允许建立 MCP/WebSocket 会话 + +第一版只允许本地回环地址,不暴露到公网。 + +### 5.3 VSCode -> CLI 通知 + +#### `selection_changed` + +在下列事件触发后发送: + +- `window.onDidChangeTextEditorSelection` +- `window.onDidChangeActiveTextEditor` +- 扩展激活完成后的初始同步 + +消息字段包含: + +- `selection.start.line` +- `selection.start.character` +- `selection.end.line` +- `selection.end.character` +- `text` +- `filePath` + +若当前没有活动选区: + +- `selection` 允许为 `null` +- 仍尽量发送 `filePath` + +这样 CLI 至少可以知道“用户当前打开的是哪个文件”。 + +### 5.4 CLI -> VSCode MCP tools + +#### `openDiff` + +入参: + +- `old_file_path` +- `new_file_path` +- `new_file_contents` +- `tab_name` + +行为: + +- 读取当前磁盘文件内容作为左侧内容 +- 使用临时文档或内存文档构造右侧内容 +- 在 VSCode 中打开 diff 视图 +- 记录 `tab_name -> 资源引用` 映射 + +#### `close_tab` + +入参: + +- `tab_name` + +行为: + +- 根据映射关闭对应 diff 视图 +- 清理映射与临时资源 + +#### `closeAllDiffTabs` + +行为: + +- 关闭所有由本扩展打开的 diff 标签 +- 清理内部状态 + +## 6. 扩展内部结构 + +建议新增独立包:`packages/vscode-ide-bridge` + +目录结构如下: + +```text +packages/vscode-ide-bridge/ + package.json + tsconfig.json + src/ + extension.ts + server/ + bridgeServer.ts + lockfile.ts + workspaceInfo.ts + selectionPublisher.ts + diffController.ts + protocol.ts + util/ + randomToken.ts + disposables.ts + test/ + selectionPublisher.test.ts + lockfile.test.ts + bridgeServer.test.ts + diffController.test.ts +``` + +各模块职责如下: + +- `extension.ts` + VSCode 扩展入口,负责激活、停用、启动 bridge、注册命令。 + +- `bridgeServer.ts` + 本地 WebSocket 服务与消息路由层,负责握手、鉴权、连接管理,以及把单个 WebSocket 连接桥接为 MCP transport。 + +- `lockfile.ts` + 负责写 lockfile、更新 lockfile、删除 lockfile。 + +- `workspaceInfo.ts` + 负责采集工作区目录、平台信息、活动编辑器文件路径。 + +- `selectionPublisher.ts` + 监听 VSCode 编辑器事件,并把选区信息转换为 `selection_changed`。 + +- `diffController.ts` + 处理 `openDiff` / `close_tab` / `closeAllDiffTabs` 这三个 MCP tools,维护临时资源和 tab 映射。 + +- `protocol.ts` + 统一定义扩展端需要识别和发送的消息结构,避免字符串散落。 + +## 7. 命令与可观察性 + +虽然主流程是自动连接,但第一版仍建议提供两个调试命令: + +- `Claude Code Bridge: Restart` +- `Claude Code Bridge: Show Status` + +状态信息至少包含: + +- 当前监听端口 +- lockfile 路径 +- 是否有 CLI 已连接 +- 当前工作区数量 +- 最近一次选区推送时间 + +另外建议注册一个 output channel: + +- `Claude Code IDE Bridge` + +用于输出: + +- 启动日志 +- 鉴权失败 +- lockfile 写入失败 +- diff 打开失败 +- 连接断开原因 + +## 8. 错误处理策略 + +### 8.1 端口占用 + +- 自动尝试新的随机端口 +- 更新 lockfile +- 在 output channel 中记录端口变化 + +### 8.2 lockfile 写入失败 + +- bridge 不进入 ready 状态 +- 弹出 VSCode 错误通知 +- output channel 记录完整错误 + +### 8.3 WebSocket 鉴权失败 + +- 拒绝连接 +- 记录远端地址和失败原因 + +### 8.4 活动编辑器为空 + +- 发送空选区状态或仅跳过通知 +- 不抛异常、不打断 bridge 生命周期 + +### 8.5 diff 打开失败 + +- 返回明确错误结果给 CLI +- 不留下半开的临时资源 + +### 8.6 扩展退出 + +- 关闭 WebSocket server +- 删除 lockfile +- 释放临时文档资源 +- 清空 tab 映射 + +## 9. 测试方案 + +### 9.1 单元测试 + +覆盖以下逻辑: + +- lockfile 内容生成与路径选择 +- 选区对象到协议消息的转换 +- tab 映射和关闭逻辑 +- 鉴权令牌校验 + +### 9.2 集成测试 + +通过 Node/WebSocket 客户端模拟 CLI: + +- 连接本地 bridge server +- 验证鉴权成功与失败 +- 验证 `selection_changed` 是否按预期发送 +- 验证 `openDiff` / `close_tab` 是否触发预期行为 + +### 9.3 手工验证 + +手工验证路径: + +1. 启动 VSCode 扩展 +2. 启动 `claude-code-best` +3. 执行 `/ide` +4. 确认 CLI 能识别到 VSCode +5. 在 VSCode 中选中一段代码并提问 +6. 确认 CLI 能注入 `` +7. 触发一次 IDE diff +8. 确认 diff 标签可打开、保存、关闭 + +## 10. 风险与取舍 + +### 10.1 MCP 完整兼容风险 + +仓库当前 CLI 连接 `ws-ide` 时使用的是 MCP 客户端通路,因此扩展端若实现过薄,可能在握手或工具注册阶段与 CLI 预期不一致。 + +**取舍:** +第一版只实现 CLI 当前实际会调用到的最小工具与通知,不尝试泛化为完整 MCP server,但协议层要留出扩展空间。 + +### 10.2 VSCode diff 资源回收 + +VSCode diff 视图不是纯命名 tab,直接按 `tab_name` 定位关闭可能和实际标签生命周期有偏差。 + +**取舍:** +扩展内部维护显式映射,以资源 URI 为主、`tab_name` 为辅,不依赖 UI 文本匹配。 + +### 10.3 多工作区与路径兼容 + +Windows、WSL、单根工作区、多根工作区在路径表示上会不同。 + +**取舍:** +第一版先以本机本地工作区为主,路径统一走绝对路径;WSL/Windows 转换尽量复用 CLI 现有约定,不在扩展端重新发明路径映射。 + +## 11. 分阶段交付 + +### 第一阶段 + +目标:打通本地 VSCode 与 CLI 的最小闭环。 + +范围: + +- 启动 `ws-ide` +- 写 lockfile +- 发送 `selection_changed` +- 实现 `openDiff` +- 实现 `close_tab` +- 实现 `closeAllDiffTabs` +- 提供状态命令和日志输出 + +### 第二阶段 + +目标:增强稳定性和调试能力。 + +范围: + +- 更细的错误提示 +- 更稳定的 tab 生命周期管理 +- 更多 IDE 状态信息展示 +- 更完整的集成测试 + +## 12. 结论 + +推荐按本设计实现独立的 VSCode IDE Bridge 扩展,并让它完全对齐当前 CLI 已有的 `ws-ide` 连接与 IDE 上下文/差异视图协议。这样能在不大改 CLI 上层逻辑的前提下,把 VSCode 选区、当前文件和 diff 预览能力真正打通。 diff --git a/packages/vscode-ide-bridge/.vscode/launch.json b/packages/vscode-ide-bridge/.vscode/launch.json new file mode 100644 index 000000000..3150ce289 --- /dev/null +++ b/packages/vscode-ide-bridge/.vscode/launch.json @@ -0,0 +1,36 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Run VSCode IDE Bridge", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--new-window", + "--disable-extensions", + "--extensionDevelopmentPath=${workspaceFolder}" + ], + "outFiles": [ + "${workspaceFolder}/dist/**/*.js" + ], + "preLaunchTask": "Build VSCode IDE Bridge" + }, + { + "name": "Run VSCode IDE Bridge (Open Claude Code Root)", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--new-window", + "--disable-extensions", + "--extensionDevelopmentPath=${workspaceFolder}", + "${workspaceFolder}/../.." + ], + "outFiles": [ + "${workspaceFolder}/dist/**/*.js" + ], + "preLaunchTask": "Build VSCode IDE Bridge" + } + ] +} diff --git a/packages/vscode-ide-bridge/.vscode/tasks.json b/packages/vscode-ide-bridge/.vscode/tasks.json new file mode 100644 index 000000000..536279bbe --- /dev/null +++ b/packages/vscode-ide-bridge/.vscode/tasks.json @@ -0,0 +1,47 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build VSCode IDE Bridge", + "type": "shell", + "command": "bunx", + "args": [ + "tsc", + "-p", + "tsconfig.json" + ], + "options": { + "cwd": "${workspaceFolder}" + }, + "group": "build", + "problemMatcher": "$tsc" + }, + { + "label": "Test VSCode IDE Bridge", + "type": "shell", + "command": "bun", + "args": [ + "test", + "test" + ], + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [] + }, + { + "label": "Package VSCode IDE Bridge", + "type": "shell", + "command": "bun", + "args": [ + "run", + "package" + ], + "options": { + "cwd": "${workspaceFolder}" + }, + "group": "build", + "problemMatcher": [] + } + ] +} diff --git a/packages/vscode-ide-bridge/.vscodeignore b/packages/vscode-ide-bridge/.vscodeignore new file mode 100644 index 000000000..10a1753fd --- /dev/null +++ b/packages/vscode-ide-bridge/.vscodeignore @@ -0,0 +1,6 @@ +src/** +test/** +.vscode/** +tsconfig.json +*.tsbuildinfo +dist/server/** diff --git a/packages/vscode-ide-bridge/LICENSE.txt b/packages/vscode-ide-bridge/LICENSE.txt new file mode 100644 index 000000000..f7e56d6a0 --- /dev/null +++ b/packages/vscode-ide-bridge/LICENSE.txt @@ -0,0 +1,3 @@ +UNLICENSED + +This package is not licensed for public redistribution. diff --git a/packages/vscode-ide-bridge/README.md b/packages/vscode-ide-bridge/README.md new file mode 100644 index 000000000..0ca21bb6a --- /dev/null +++ b/packages/vscode-ide-bridge/README.md @@ -0,0 +1,59 @@ +# VSCode IDE Bridge + +这是一个给当前仓库配套的本地 VSCode 扩展,用来把 VSCode 和现有 Claude Code CLI 的 `ws-ide` 链路接起来。 + +## 当前能力 + +- 在本地 `127.0.0.1` 启动 `ws-ide` WebSocket 服务 +- 写出 CLI 可发现的 `~/.claude/ide/.lock` +- 把 VSCode 当前活动文件和选区变化发送为 `selection_changed` +- 实现 `openDiff`、`close_tab`、`closeAllDiffTabs` 三个 IDE MCP tools +- 提供 `Claude Code Bridge: Restart` 和 `Claude Code Bridge: Show Status` 两个调试命令 + +## 当前限制 + +- diff 现在支持通过保存右侧文件把修改回传给 CLI,但还没有补“未保存直接接受右侧手工编辑”这类更细的交互 +- 还没有补 `openFile`、`getDiagnostics`、`at_mentioned`、`log_event` 这些附加能力 +- 目前按单个活动 CLI 连接设计,新连接会替换旧连接 + +## 本地使用 + +推荐把这个目录单独当成一个扩展工程来打开,而不是总是从 monorepo 根目录调试。 + +1. 在 VSCode 中直接打开 `packages/vscode-ide-bridge` +2. 打开“运行和调试” +3. 二选一: + - `Run VSCode IDE Bridge` + - `Run VSCode IDE Bridge (Open Claude Code Root)`,会直接在测试窗口里打开 monorepo 根目录 +4. 这会自动先执行 `Build VSCode IDE Bridge` +5. 如果用了第一个启动项,就在新开的 Extension Development Host 窗口中再打开你真正要联调的目标工作区 + 如果用了第二个启动项,会直接打开 `claude-code` 根目录 +6. 打开命令面板,执行 `Claude Code Bridge: Show Status` +7. 确认输出中已经出现监听端口和 lockfile 路径 +8. 在这个测试窗口的集成终端里启动 Claude Code CLI;如果没有自动连上,再执行 `/ide` + +这个目录自带自己的 VSCode 配置: + +- `Run VSCode IDE Bridge` +- `Run VSCode IDE Bridge (Open Claude Code Root)` +- `Build VSCode IDE Bridge` +- `Test VSCode IDE Bridge` +- `Package VSCode IDE Bridge` + +如果你仍然从 monorepo 根目录开发,也可以继续使用根目录下的 `.vscode` 配置。 + +## 打包 + +可以直接在这个包目录里执行: + +```bash +bun run package +``` + +成功后会在 `dist/vscode-ide-bridge.vsix` 生成可安装的 VSCode 扩展包。 + +## 验证建议 + +- 选中一段代码后发起提问,确认 CLI prompt 中出现 `` +- 触发一次文件 diff,确认 VSCode 中会打开 diff,并能通过通知选择“接受”或“拒绝” +- 查看 `Claude Code IDE Bridge` output channel,确认没有鉴权失败或 lockfile 写入失败 diff --git a/packages/vscode-ide-bridge/package.json b/packages/vscode-ide-bridge/package.json new file mode 100644 index 000000000..c37e93364 --- /dev/null +++ b/packages/vscode-ide-bridge/package.json @@ -0,0 +1,59 @@ +{ + "name": "vscode-ide-bridge", + "private": true, + "version": "0.0.1", + "description": "Local VSCode ws-ide bridge for Claude Code", + "displayName": "Claude Code IDE Bridge", + "publisher": "claude-code-best", + "license": "UNLICENSED", + "type": "module", + "main": "./dist/extension.js", + "repository": { + "type": "git", + "url": "git+https://github.com/claude-code-best/claude-code.git", + "directory": "packages/vscode-ide-bridge" + }, + "homepage": "https://github.com/claude-code-best/claude-code/tree/main/packages/vscode-ide-bridge", + "bugs": { + "url": "https://github.com/claude-code-best/claude-code/issues" + }, + "categories": [ + "Other" + ], + "engines": { + "vscode": "^1.90.0" + }, + "activationEvents": [ + "onStartupFinished", + "onCommand:claudeCodeBridge.restart", + "onCommand:claudeCodeBridge.showStatus" + ], + "contributes": { + "commands": [ + { + "command": "claudeCodeBridge.restart", + "title": "Claude Code Bridge: Restart" + }, + { + "command": "claudeCodeBridge.showStatus", + "title": "Claude Code Bridge: Show Status" + } + ] + }, + "scripts": { + "build": "bunx tsc -p tsconfig.json", + "bundle": "bun build ./src/extension.ts --outdir dist --target node --format esm --external vscode", + "test": "bun test", + "check": "bunx tsc -p tsconfig.json --pretty false", + "package": "bun run bundle && bunx @vscode/vsce package --no-dependencies --out dist/vscode-ide-bridge.vsix" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "^1.29.0", + "ws": "^8.20.0" + }, + "devDependencies": { + "@vscode/vsce": "^3.7.0", + "@types/bun": "^1.3.11", + "typescript": "^6.0.2" + } +} diff --git a/packages/vscode-ide-bridge/src/extension.ts b/packages/vscode-ide-bridge/src/extension.ts new file mode 100644 index 000000000..be4766179 --- /dev/null +++ b/packages/vscode-ide-bridge/src/extension.ts @@ -0,0 +1,61 @@ +import * as vscode from 'vscode' +import { LocalIdeBridgeService } from './server/localIdeBridgeService.js' + +let bridgeService: LocalIdeBridgeService | null = null + +export async function activate(context: any): Promise { + const outputChannel = vscode.window.createOutputChannel( + 'Claude Code IDE Bridge', + ) + + bridgeService = new LocalIdeBridgeService( + vscode, + outputChannel, + context.environmentVariableCollection, + ) + await bridgeService.start() + + context.subscriptions.push( + outputChannel, + { + dispose: () => { + void bridgeService?.dispose() + }, + }, + vscode.commands.registerCommand('claudeCodeBridge.restart', async () => { + await bridgeService?.restart() + const status = bridgeService?.getStatus() + vscode.window.showInformationMessage( + `Claude Code Bridge 已重启${status?.port ? `,端口 ${status.port}` : ''}`, + ) + }), + vscode.commands.registerCommand('claudeCodeBridge.showStatus', () => { + const status = bridgeService?.getStatus() + outputChannel.show(true) + outputChannel.appendLine( + `[status] port=${status?.port ?? 'n/a'} connected=${String(status?.hasConnectedClient ?? false)} cliPid=${status?.connectedCliPid ?? 'n/a'} lockfile=${status?.lockfilePath ?? 'n/a'}`, + ) + vscode.window.showInformationMessage( + status?.port + ? `Claude Code Bridge 正在监听 127.0.0.1:${status.port}` + : 'Claude Code Bridge 尚未启动', + ) + }), + vscode.window.onDidChangeTextEditorSelection(() => { + void bridgeService?.publishActiveSelection() + }), + vscode.window.onDidChangeActiveTextEditor(() => { + void bridgeService?.publishActiveSelection() + }), + vscode.workspace.onDidChangeWorkspaceFolders(() => { + void bridgeService?.refreshLockfile() + }), + ) + + await bridgeService.publishActiveSelection() +} + +export async function deactivate(): Promise { + await bridgeService?.dispose() + bridgeService = null +} diff --git a/packages/vscode-ide-bridge/src/server/bridgeServer.ts b/packages/vscode-ide-bridge/src/server/bridgeServer.ts new file mode 100644 index 000000000..9cbf9cd6d --- /dev/null +++ b/packages/vscode-ide-bridge/src/server/bridgeServer.ts @@ -0,0 +1,139 @@ +import { Server } from '@modelcontextprotocol/sdk/server/index.js' +import { + CallToolRequestSchema, + type CallToolResult, + ListToolsRequestSchema, + type Tool, +} from '@modelcontextprotocol/sdk/types.js' +import type { SelectionChangedParams } from './selectionPublisher.js' +import { + CloseAllDiffTabsArgumentsSchema, + CloseTabArgumentsSchema, + IdeConnectedNotificationSchema, + OpenDiffArgumentsSchema, + type CloseTabArguments, + type OpenDiffArguments, +} from './protocol.js' + +export type DiffController = { + openDiff(args: OpenDiffArguments): Promise + closeTab(args: CloseTabArguments): Promise + closeAllDiffTabs(): Promise +} + +type CreateIdeBridgeServerOptions = { + diffController: DiffController +} + +const IDE_BRIDGE_TOOLS: Tool[] = [ + { + name: 'openDiff', + description: 'Open a diff view in the IDE and resolve when the user acts.', + inputSchema: { + type: 'object', + properties: { + old_file_path: { type: 'string' }, + new_file_path: { type: 'string' }, + new_file_contents: { type: 'string' }, + tab_name: { type: 'string' }, + }, + required: [ + 'old_file_path', + 'new_file_path', + 'new_file_contents', + 'tab_name', + ], + additionalProperties: false, + }, + }, + { + name: 'close_tab', + description: 'Close a previously opened IDE tab by Claude Code tab name.', + inputSchema: { + type: 'object', + properties: { + tab_name: { type: 'string' }, + }, + required: ['tab_name'], + additionalProperties: false, + }, + }, + { + name: 'closeAllDiffTabs', + description: 'Close all diff tabs created by the IDE bridge.', + inputSchema: { + type: 'object', + properties: {}, + additionalProperties: false, + }, + }, +] + +export function createIdeBridgeServer(options: CreateIdeBridgeServerOptions): { + server: Server + notifySelectionChanged(params: SelectionChangedParams): Promise + getConnectedCliPid(): number | null +} { + const server = new Server( + { + name: 'claude-code-vscode-ide-bridge', + version: '0.0.1', + }, + { + capabilities: { + tools: {}, + }, + }, + ) + + let connectedCliPid: number | null = null + + server.setRequestHandler(ListToolsRequestSchema, async () => { + return { + tools: IDE_BRIDGE_TOOLS, + } + }) + + server.setRequestHandler(CallToolRequestSchema, async request => { + switch (request.params.name) { + case 'openDiff': + return options.diffController.openDiff( + OpenDiffArgumentsSchema.parse(request.params.arguments ?? {}), + ) + case 'close_tab': + return options.diffController.closeTab( + CloseTabArgumentsSchema.parse(request.params.arguments ?? {}), + ) + case 'closeAllDiffTabs': + CloseAllDiffTabsArgumentsSchema.parse(request.params.arguments ?? {}) + return options.diffController.closeAllDiffTabs() + default: + return { + isError: true, + content: [ + { + type: 'text', + text: `Unsupported IDE tool: ${request.params.name}`, + }, + ], + } + } + }) + + server.setNotificationHandler(IdeConnectedNotificationSchema, notification => { + connectedCliPid = notification.params.pid + }) + + return { + server, + async notifySelectionChanged(params) { + await server.notification({ + method: 'selection_changed', + params, + }) + }, + getConnectedCliPid() { + return connectedCliPid + }, + } +} diff --git a/packages/vscode-ide-bridge/src/server/diffController.ts b/packages/vscode-ide-bridge/src/server/diffController.ts new file mode 100644 index 000000000..3dc53d4f1 --- /dev/null +++ b/packages/vscode-ide-bridge/src/server/diffController.ts @@ -0,0 +1,350 @@ +import { readFile } from 'node:fs/promises' +import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js' +import * as vscode from 'vscode' +import type { DiffController } from './bridgeServer.js' +import type { OpenDiffArguments } from './protocol.js' + +const DIFF_SCHEME = 'claude-code-bridge' +const ACCEPT_LABEL = '接受' +const REJECT_LABEL = '拒绝' + +type DiffSession = { + tabName: string + leftUri: any + rightUri: any + filePath: string + hasBeenVisible: boolean + settled: boolean + resolve: (result: CallToolResult) => void +} + +class VirtualDocumentProvider { + private readonly contents = new Map() + + provideTextDocumentContent(uri: any): string { + return this.contents.get(uri.toString()) ?? '' + } + + set(uri: any, content: string): void { + this.contents.set(uri.toString(), content) + } + + delete(uri: any): void { + this.contents.delete(uri.toString()) + } +} + +function createTextResult(text: string): CallToolResult { + return { + content: [ + { + type: 'text', + text, + }, + ], + } +} + +function createFileSavedResult(contents: string): CallToolResult { + return { + content: [ + { + type: 'text', + text: 'FILE_SAVED', + }, + { + type: 'text', + text: contents, + }, + ], + } +} + +function buildDiffUri(kind: 'left' | 'right', tabName: string, filePath: string) { + return vscode.Uri.parse( + `${DIFF_SCHEME}:/${kind}/${encodeURIComponent(tabName)}?filePath=${encodeURIComponent(filePath)}`, + ) +} + +function getDocumentFullRange(document: any): any { + const lineCount = Math.max(document?.lineCount ?? 1, 1) + const lastLine = document?.lineAt?.(lineCount - 1) + const lastCharacter = lastLine?.text?.length ?? 0 + return new vscode.Range(0, 0, lineCount - 1, lastCharacter) +} + +async function replaceDocumentContents( + editor: any, + nextContent: string, +): Promise { + const currentContent = editor?.document?.getText?.() ?? '' + if (currentContent === nextContent) { + return + } + + await editor.edit((editBuilder: any) => { + editBuilder.replace( + getDocumentFullRange(editor.document), + nextContent, + ) + }) +} + +function matchesSessionDocument(session: DiffSession, document: any): boolean { + const uriString = document?.uri?.toString?.() + const fsPath = document?.uri?.fsPath + + return ( + uriString === session.rightUri.toString() || + (typeof fsPath === 'string' && fsPath === session.filePath) + ) +} + +export function createDiffController(outputChannel: any): DiffController & { + dispose(): Promise +} { + const provider = new VirtualDocumentProvider() + const sessions = new Map() + + const providerDisposable = + vscode.workspace.registerTextDocumentContentProvider( + DIFF_SCHEME, + provider, + ) + + const visibilityDisposable = vscode.window.onDidChangeVisibleTextEditors( + (editors: any[]) => { + const visibleUris = new Set( + editors.map(editor => editor?.document?.uri?.toString?.()), + ) + + for (const session of sessions.values()) { + const leftVisible = visibleUris.has(session.leftUri.toString()) + const rightVisible = visibleUris.has(session.rightUri.toString()) + + if (leftVisible || rightVisible) { + session.hasBeenVisible = true + continue + } + + if (session.hasBeenVisible) { + void settleSession( + session.tabName, + createTextResult('TAB_CLOSED'), + false, + ) + } + } + }, + ) + + const saveDisposable = vscode.workspace.onDidSaveTextDocument( + (document: any) => { + for (const session of sessions.values()) { + if (!matchesSessionDocument(session, document)) { + continue + } + + void settleSession( + session.tabName, + createFileSavedResult(document.getText()), + true, + ) + } + }, + ) + + async function settleSession( + tabName: string, + result: CallToolResult, + closeEditors: boolean, + ): Promise { + const session = sessions.get(tabName) + if (!session || session.settled) { + return + } + + session.settled = true + sessions.delete(tabName) + provider.delete(session.leftUri) + provider.delete(session.rightUri) + + if (closeEditors) { + await closeSessionEditors(session).catch(() => {}) + } + + session.resolve(result) + } + + async function closeSessionEditors(session: DiffSession): Promise { + for (const editor of vscode.window.visibleTextEditors ?? []) { + if ( + matchesSessionDocument(session, editor?.document) && + editor?.document?.isDirty + ) { + await vscode.window.showTextDocument(editor.document, { + preview: false, + preserveFocus: false, + viewColumn: editor.viewColumn, + }) + await vscode.commands.executeCommand('workbench.action.files.revert') + } + } + + const matchedTabs: any[] = [] + + for (const group of vscode.window.tabGroups?.all ?? []) { + for (const tab of group.tabs ?? []) { + const original = tab?.input?.original?.toString?.() + const modified = tab?.input?.modified?.toString?.() + const uri = tab?.input?.uri?.toString?.() + if ( + original === session.leftUri.toString() || + modified === session.rightUri.toString() || + uri === session.rightUri.toString() || + tab?.input?.uri?.fsPath === session.filePath || + tab?.label === session.tabName + ) { + matchedTabs.push(tab) + } + } + } + + if (matchedTabs.length > 0 && vscode.window.tabGroups?.close) { + await vscode.window.tabGroups.close(matchedTabs, true) + return + } + + for (const editor of vscode.window.visibleTextEditors ?? []) { + const uri = editor?.document?.uri?.toString?.() + if ( + uri === session.leftUri.toString() || + uri === session.rightUri.toString() + ) { + await vscode.window.showTextDocument(editor.document, { + preview: false, + preserveFocus: false, + viewColumn: editor.viewColumn, + }) + await vscode.commands.executeCommand('workbench.action.closeActiveEditor') + } + } + } + + return { + async openDiff(args: OpenDiffArguments): Promise { + await settleSession(args.tab_name, createTextResult('TAB_CLOSED'), true) + + const leftContent = await readFile(args.old_file_path, 'utf8').catch( + () => '', + ) + const leftUri = buildDiffUri('left', args.tab_name, args.old_file_path) + const rightUri = vscode.Uri.file(args.new_file_path) + + provider.set(leftUri, leftContent) + + const rightDocument = await vscode.workspace.openTextDocument(rightUri) + const rightEditor = await vscode.window.showTextDocument(rightDocument, { + preview: false, + preserveFocus: true, + }) + await replaceDocumentContents(rightEditor, args.new_file_contents) + + const resultPromise = new Promise(resolve => { + sessions.set(args.tab_name, { + tabName: args.tab_name, + leftUri, + rightUri, + filePath: args.new_file_path, + hasBeenVisible: false, + settled: false, + resolve, + }) + }) + + outputChannel.appendLine( + `[diff] open ${args.tab_name} -> ${args.new_file_path}`, + ) + + await vscode.commands.executeCommand( + 'vscode.diff', + leftUri, + rightUri, + args.tab_name, + { + preview: false, + }, + ) + + queueMicrotask(() => { + const visibleUris = new Set( + (vscode.window.visibleTextEditors ?? []).map((editor: any) => + editor?.document?.uri?.toString?.(), + ), + ) + const session = sessions.get(args.tab_name) + if (!session) { + return + } + if ( + visibleUris.has(session.leftUri.toString()) || + visibleUris.has(session.rightUri.toString()) + ) { + session.hasBeenVisible = true + } + }) + + void vscode.window + .showInformationMessage( + `Claude Code 提议了对 ${args.new_file_path} 的修改`, + ACCEPT_LABEL, + REJECT_LABEL, + ) + .then((choice: string | undefined) => { + if (choice === ACCEPT_LABEL) { + void settleSession( + args.tab_name, + createTextResult('TAB_CLOSED'), + true, + ) + } else if (choice === REJECT_LABEL) { + void settleSession( + args.tab_name, + createTextResult('DIFF_REJECTED'), + true, + ) + } + }) + + return resultPromise + }, + + async closeTab(args): Promise { + const session = sessions.get(args.tab_name) + if (session) { + await closeSessionEditors(session).catch(() => {}) + await settleSession(args.tab_name, createTextResult('TAB_CLOSED'), false) + } + return createTextResult('TAB_CLOSED') + }, + + async closeAllDiffTabs(): Promise { + for (const tabName of [...sessions.keys()]) { + const session = sessions.get(tabName) + if (!session) { + continue + } + await closeSessionEditors(session).catch(() => {}) + await settleSession(tabName, createTextResult('TAB_CLOSED'), false) + } + return createTextResult('OK') + }, + + async dispose(): Promise { + visibilityDisposable.dispose() + saveDisposable.dispose() + providerDisposable.dispose() + await this.closeAllDiffTabs() + }, + } +} diff --git a/packages/vscode-ide-bridge/src/server/localIdeBridgeService.ts b/packages/vscode-ide-bridge/src/server/localIdeBridgeService.ts new file mode 100644 index 000000000..1f3447615 --- /dev/null +++ b/packages/vscode-ide-bridge/src/server/localIdeBridgeService.ts @@ -0,0 +1,231 @@ +import { WebSocketServer } from 'ws' +import { createIdeBridgeServer } from './bridgeServer.js' +import { createDiffController } from './diffController.js' +import { + buildLockfilePayload, + removeLockfile, + writeLockfile, +} from './lockfile.js' +import { createAuthToken } from './randomToken.js' +import { ServerWebSocketTransport } from './serverWebSocketTransport.js' +import { + clearClaudeCodeIdePort, + setClaudeCodeIdePort, +} from './terminalEnvironment.js' +import { getActiveSelectionSnapshot, getWorkspaceFolderPaths } from './workspaceInfo.js' + +type BridgeStatus = { + port: number | null + lockfilePath: string | null + hasConnectedClient: boolean + connectedCliPid: number | null + workspaceFolders: string[] + lastSelectionSentAt: string | null +} + +type ActiveConnection = { + socket: any + bridge: ReturnType + transport: ServerWebSocketTransport +} + +export class LocalIdeBridgeService { + private readonly diffController + private readonly ideName = 'VS Code' + private readonly runningInWindows = process.platform === 'win32' + + private server: any | null = null + private port: number | null = null + private lockfilePath: string | null = null + private authToken = '' + private activeConnection: ActiveConnection | null = null + private lastSelectionSentAt: string | null = null + private disposed = false + + constructor( + private readonly vscode: any, + private readonly outputChannel: any, + private readonly environmentVariableCollection?: { + replace(name: string, value: string): void + delete(name: string): void + }, + ) { + this.diffController = createDiffController(outputChannel) + } + + async start(): Promise { + if (this.server || this.disposed) { + return + } + + this.authToken = createAuthToken() + this.server = await this.createWebSocketServer() + this.port = this.getServerPort() + await this.refreshLockfile() + + this.outputChannel.appendLine( + `[bridge] listening on ws://127.0.0.1:${this.port}`, + ) + } + + async restart(): Promise { + await this.stop() + this.disposed = false + await this.start() + } + + async refreshLockfile(): Promise { + if (!this.port) { + return + } + + setClaudeCodeIdePort(this.environmentVariableCollection, this.port) + await removeLockfile(this.lockfilePath) + this.lockfilePath = await writeLockfile( + this.port, + buildLockfilePayload({ + pid: process.pid, + ideName: this.ideName, + workspaceFolders: getWorkspaceFolderPaths( + this.vscode.workspace.workspaceFolders, + ), + authToken: this.authToken, + runningInWindows: this.runningInWindows, + }), + ) + + this.outputChannel.appendLine(`[bridge] lockfile -> ${this.lockfilePath}`) + this.outputChannel.appendLine( + `[bridge] terminal env CLAUDE_CODE_SSE_PORT=${this.port}`, + ) + } + + async publishActiveSelection(): Promise { + if (!this.activeConnection) { + return + } + + const snapshot = getActiveSelectionSnapshot(this.vscode.window.activeTextEditor) + + if (!snapshot.selection && !snapshot.filePath) { + return + } + + await this.activeConnection.bridge.notifySelectionChanged(snapshot) + this.lastSelectionSentAt = new Date().toISOString() + } + + getStatus(): BridgeStatus { + return { + port: this.port, + lockfilePath: this.lockfilePath, + hasConnectedClient: this.activeConnection !== null, + connectedCliPid: + this.activeConnection?.bridge.getConnectedCliPid() ?? null, + workspaceFolders: getWorkspaceFolderPaths( + this.vscode.workspace.workspaceFolders, + ), + lastSelectionSentAt: this.lastSelectionSentAt, + } + } + + async stop(): Promise { + await this.closeActiveConnection() + + if (this.server) { + await new Promise(resolve => { + this.server?.close(() => resolve()) + }) + this.server = null + } + + await removeLockfile(this.lockfilePath) + clearClaudeCodeIdePort(this.environmentVariableCollection) + this.lockfilePath = null + this.port = null + } + + async dispose(): Promise { + if (this.disposed) { + return + } + + this.disposed = true + await this.stop() + await this.diffController.dispose() + } + + private async createWebSocketServer(): Promise { + const server = new WebSocketServer({ + host: '127.0.0.1', + port: 0, + }) + + await new Promise((resolve, reject) => { + server.once('listening', () => resolve()) + server.once('error', (error: Error) => reject(error)) + }) + + server.on('connection', (socket: any, request: any) => { + const authHeader = request.headers['x-claude-code-ide-authorization'] + if (authHeader !== this.authToken) { + this.outputChannel.appendLine('[bridge] rejected unauthorized client') + socket.close(4003, 'unauthorized') + return + } + + void this.handleConnection(socket) + }) + + return server + } + + private getServerPort(): number { + const address = this.server?.address() + if (!address || typeof address === 'string') { + throw new Error('Unable to determine bridge port') + } + return address.port + } + + private async handleConnection(socket: any): Promise { + await this.closeActiveConnection() + + const bridge = createIdeBridgeServer({ + diffController: this.diffController, + }) + const transport = new ServerWebSocketTransport(socket) + + socket.on('close', () => { + if (this.activeConnection?.socket === socket) { + this.activeConnection = null + } + }) + + await bridge.server.connect(transport) + + this.activeConnection = { + socket, + bridge, + transport, + } + + this.outputChannel.appendLine('[bridge] CLI client connected') + await this.publishActiveSelection().catch(error => { + this.outputChannel.appendLine( + `[bridge] failed to publish initial selection: ${(error as Error).message}`, + ) + }) + } + + private async closeActiveConnection(): Promise { + if (!this.activeConnection) { + return + } + + const connection = this.activeConnection + this.activeConnection = null + + await connection.transport.close().catch(() => {}) + } +} diff --git a/packages/vscode-ide-bridge/src/server/lockfile.ts b/packages/vscode-ide-bridge/src/server/lockfile.ts new file mode 100644 index 000000000..3b8711bb2 --- /dev/null +++ b/packages/vscode-ide-bridge/src/server/lockfile.ts @@ -0,0 +1,56 @@ +import { mkdir, rm, writeFile } from 'node:fs/promises' +import { homedir } from 'node:os' +import { join } from 'node:path' +import type { LockfilePayload } from './protocol.js' + +type BuildLockfilePayloadInput = { + pid: number + ideName: string + workspaceFolders: string[] + authToken: string + runningInWindows: boolean +} + +function getClaudeConfigDir(): string { + return (process.env.CLAUDE_CONFIG_DIR ?? join(homedir(), '.claude')).normalize( + 'NFC', + ) +} + +export function buildLockfilePayload( + input: BuildLockfilePayloadInput, +): LockfilePayload { + return { + workspaceFolders: input.workspaceFolders, + pid: input.pid, + ideName: input.ideName, + transport: 'ws', + runningInWindows: input.runningInWindows, + authToken: input.authToken, + } +} + +export function getLockfileDir(): string { + return join(getClaudeConfigDir(), 'ide') +} + +export function getLockfilePath(port: number): string { + return join(getLockfileDir(), `${port}.lock`) +} + +export async function writeLockfile( + port: number, + payload: LockfilePayload, +): Promise { + const lockfilePath = getLockfilePath(port) + await mkdir(getLockfileDir(), { recursive: true }) + await writeFile(lockfilePath, JSON.stringify(payload), 'utf8') + return lockfilePath +} + +export async function removeLockfile(lockfilePath: string | null): Promise { + if (!lockfilePath) { + return + } + await rm(lockfilePath, { force: true }) +} diff --git a/packages/vscode-ide-bridge/src/server/protocol.ts b/packages/vscode-ide-bridge/src/server/protocol.ts new file mode 100644 index 000000000..a598d419c --- /dev/null +++ b/packages/vscode-ide-bridge/src/server/protocol.ts @@ -0,0 +1,33 @@ +import { z } from 'zod/v4' + +export type LockfilePayload = { + workspaceFolders: string[] + pid: number + ideName: string + transport: 'ws' + runningInWindows: boolean + authToken: string +} + +export const OpenDiffArgumentsSchema = z.object({ + old_file_path: z.string(), + new_file_path: z.string(), + new_file_contents: z.string(), + tab_name: z.string(), +}) + +export const CloseTabArgumentsSchema = z.object({ + tab_name: z.string(), +}) + +export const CloseAllDiffTabsArgumentsSchema = z.object({}) + +export const IdeConnectedNotificationSchema = z.object({ + method: z.literal('ide_connected'), + params: z.object({ + pid: z.number(), + }), +}) + +export type OpenDiffArguments = z.infer +export type CloseTabArguments = z.infer diff --git a/packages/vscode-ide-bridge/src/server/randomToken.ts b/packages/vscode-ide-bridge/src/server/randomToken.ts new file mode 100644 index 000000000..0fb2d46b5 --- /dev/null +++ b/packages/vscode-ide-bridge/src/server/randomToken.ts @@ -0,0 +1,5 @@ +import { randomBytes } from 'node:crypto' + +export function createAuthToken(): string { + return randomBytes(24).toString('hex') +} diff --git a/packages/vscode-ide-bridge/src/server/selectionPublisher.ts b/packages/vscode-ide-bridge/src/server/selectionPublisher.ts new file mode 100644 index 000000000..e532476ba --- /dev/null +++ b/packages/vscode-ide-bridge/src/server/selectionPublisher.ts @@ -0,0 +1,41 @@ +export type SelectionPoint = { + line: number + character: number +} + +export type SelectionChangedParams = { + selection: { + start: SelectionPoint + end: SelectionPoint + } | null + text?: string + filePath?: string +} + +type BuildSelectionChangedParamsInput = { + filePath?: string + text?: string + start?: SelectionPoint + end?: SelectionPoint +} + +export function buildSelectionChangedParams( + input: BuildSelectionChangedParamsInput, +): SelectionChangedParams { + if (!input.start || !input.end) { + return { + selection: null, + text: input.text, + filePath: input.filePath, + } + } + + return { + selection: { + start: input.start, + end: input.end, + }, + text: input.text, + filePath: input.filePath, + } +} diff --git a/packages/vscode-ide-bridge/src/server/serverWebSocketTransport.ts b/packages/vscode-ide-bridge/src/server/serverWebSocketTransport.ts new file mode 100644 index 000000000..df54ea393 --- /dev/null +++ b/packages/vscode-ide-bridge/src/server/serverWebSocketTransport.ts @@ -0,0 +1,92 @@ +import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js' +import { + type JSONRPCMessage, + JSONRPCMessageSchema, +} from '@modelcontextprotocol/sdk/types.js' + +type WebSocketLike = { + readyState: number + send(data: string, callback?: (error?: Error) => void): void + close(): void + on(event: 'message', listener: (data: Buffer | string) => void): void + on(event: 'close', listener: () => void): void + on(event: 'error', listener: (error: Error) => void): void + off(event: 'message', listener: (data: Buffer | string) => void): void + off(event: 'close', listener: () => void): void + off(event: 'error', listener: (error: Error) => void): void +} + +const WS_OPEN = 1 + +export class ServerWebSocketTransport implements Transport { + private started = false + + constructor(private readonly socket: WebSocketLike) { + this.socket.on('message', this.handleMessage) + this.socket.on('close', this.handleClose) + this.socket.on('error', this.handleError) + } + + onclose?: () => void + onerror?: (error: Error) => void + onmessage?: (message: JSONRPCMessage) => void + + async start(): Promise { + if (this.started) { + throw new Error('Start can only be called once per transport.') + } + if (this.socket.readyState !== WS_OPEN) { + throw new Error('WebSocket is not open. Cannot start transport.') + } + this.started = true + } + + async send(message: JSONRPCMessage): Promise { + if (this.socket.readyState !== WS_OPEN) { + throw new Error('WebSocket is not open. Cannot send message.') + } + + await new Promise((resolve, reject) => { + this.socket.send(JSON.stringify(message), error => { + if (error) { + reject(error) + return + } + resolve() + }) + }) + } + + async close(): Promise { + if (this.socket.readyState === WS_OPEN) { + this.socket.close() + return + } + this.cleanup() + } + + private handleMessage = (data: Buffer | string) => { + try { + const raw = typeof data === 'string' ? data : data.toString('utf8') + const parsed = JSONRPCMessageSchema.parse(JSON.parse(raw)) + this.onmessage?.(parsed) + } catch (error) { + this.handleError(error instanceof Error ? error : new Error(String(error))) + } + } + + private handleClose = () => { + this.cleanup() + this.onclose?.() + } + + private handleError = (error: Error) => { + this.onerror?.(error) + } + + private cleanup() { + this.socket.off('message', this.handleMessage) + this.socket.off('close', this.handleClose) + this.socket.off('error', this.handleError) + } +} diff --git a/packages/vscode-ide-bridge/src/server/terminalEnvironment.ts b/packages/vscode-ide-bridge/src/server/terminalEnvironment.ts new file mode 100644 index 000000000..e70d0994f --- /dev/null +++ b/packages/vscode-ide-bridge/src/server/terminalEnvironment.ts @@ -0,0 +1,19 @@ +type EnvironmentVariableCollectionLike = { + replace(name: string, value: string): void + delete(name: string): void +} + +const CLAUDE_CODE_SSE_PORT = 'CLAUDE_CODE_SSE_PORT' + +export function setClaudeCodeIdePort( + collection: EnvironmentVariableCollectionLike | undefined, + port: number, +): void { + collection?.replace(CLAUDE_CODE_SSE_PORT, String(port)) +} + +export function clearClaudeCodeIdePort( + collection: EnvironmentVariableCollectionLike | undefined, +): void { + collection?.delete(CLAUDE_CODE_SSE_PORT) +} diff --git a/packages/vscode-ide-bridge/src/server/workspaceInfo.ts b/packages/vscode-ide-bridge/src/server/workspaceInfo.ts new file mode 100644 index 000000000..3ea874127 --- /dev/null +++ b/packages/vscode-ide-bridge/src/server/workspaceInfo.ts @@ -0,0 +1,53 @@ +import { buildSelectionChangedParams } from './selectionPublisher.js' + +type WorkspaceFolderLike = { + uri?: { + fsPath?: string + } +} + +type EditorLike = { + document?: { + uri?: { + fsPath?: string + } + getText(selection: unknown): string + } + selection?: { + start: { + line: number + character: number + } + end: { + line: number + character: number + } + isEmpty?: boolean + } +} + +export function getWorkspaceFolderPaths( + workspaceFolders: WorkspaceFolderLike[] | undefined, +): string[] { + return (workspaceFolders ?? []) + .map(folder => folder.uri?.fsPath) + .filter((value): value is string => Boolean(value)) +} + +export function getActiveSelectionSnapshot(editor: EditorLike | undefined) { + const filePath = editor?.document?.uri?.fsPath + const selection = editor?.selection + + if (!editor?.document || !selection || selection.isEmpty) { + return buildSelectionChangedParams({ + filePath, + }) + } + + return buildSelectionChangedParams({ + filePath, + text: editor.document.getText(selection), + start: selection.start, + end: selection.end, + }) +} diff --git a/packages/vscode-ide-bridge/src/vscode.d.ts b/packages/vscode-ide-bridge/src/vscode.d.ts new file mode 100644 index 000000000..a56afc17c --- /dev/null +++ b/packages/vscode-ide-bridge/src/vscode.d.ts @@ -0,0 +1,4 @@ +declare module 'vscode' { + const vscode: any + export = vscode +} diff --git a/packages/vscode-ide-bridge/src/ws.d.ts b/packages/vscode-ide-bridge/src/ws.d.ts new file mode 100644 index 000000000..54011aed5 --- /dev/null +++ b/packages/vscode-ide-bridge/src/ws.d.ts @@ -0,0 +1,3 @@ +declare module 'ws' { + export const WebSocketServer: any +} diff --git a/packages/vscode-ide-bridge/test/bridgeServer.test.ts b/packages/vscode-ide-bridge/test/bridgeServer.test.ts new file mode 100644 index 000000000..476d0ba90 --- /dev/null +++ b/packages/vscode-ide-bridge/test/bridgeServer.test.ts @@ -0,0 +1,135 @@ +import { Client } from '@modelcontextprotocol/sdk/client/index.js' +import { describe, expect, test } from 'bun:test' +import { z } from 'zod/v4' +import { createLinkedTransportPair } from '../../../src/services/mcp/InProcessTransport.js' +import { + createIdeBridgeServer, + type DiffController, +} from '../src/server/bridgeServer.js' + +const SelectionChangedSchema = z.object({ + method: z.literal('selection_changed'), + params: z.object({ + selection: z + .object({ + start: z.object({ line: z.number(), character: z.number() }), + end: z.object({ line: z.number(), character: z.number() }), + }) + .nullable(), + text: z.string().optional(), + filePath: z.string().optional(), + }), +}) + +function createTestClient() { + return new Client({ + name: 'vscode-ide-bridge-test-client', + version: '0.0.1', + }) +} + +describe('ide bridge MCP server', () => { + test('lists the bridge tools and delegates openDiff calls', async () => { + const openDiffCalls: Array> = [] + const diffController: DiffController = { + async openDiff(args) { + openDiffCalls.push(args) + return { + content: [{ type: 'text', text: 'TAB_CLOSED' }], + } + }, + async closeTab() { + return { + content: [{ type: 'text', text: 'TAB_CLOSED' }], + } + }, + async closeAllDiffTabs() { + return { + content: [{ type: 'text', text: 'OK' }], + } + }, + } + + const bridge = createIdeBridgeServer({ diffController }) + const client = createTestClient() + const [clientTransport, serverTransport] = createLinkedTransportPair() + + await bridge.server.connect(serverTransport) + await client.connect(clientTransport) + + const toolResult = await client.listTools() + expect(toolResult.tools.map(tool => tool.name)).toEqual([ + 'openDiff', + 'close_tab', + 'closeAllDiffTabs', + ]) + + const openDiffResult = await client.callTool({ + name: 'openDiff', + arguments: { + old_file_path: 'D:/vibe/claude-code/src/cli/print.ts', + new_file_path: 'D:/vibe/claude-code/src/cli/print.ts', + new_file_contents: 'new content', + tab_name: 'tab-1', + }, + }) + + expect(openDiffResult.content[0]).toEqual({ + type: 'text', + text: 'TAB_CLOSED', + }) + expect(openDiffCalls).toHaveLength(1) + expect(openDiffCalls[0]?.tab_name).toBe('tab-1') + }) + + test('forwards selection_changed notifications to the connected client', async () => { + const diffController: DiffController = { + async openDiff() { + return { + content: [{ type: 'text', text: 'TAB_CLOSED' }], + } + }, + async closeTab() { + return { + content: [{ type: 'text', text: 'TAB_CLOSED' }], + } + }, + async closeAllDiffTabs() { + return { + content: [{ type: 'text', text: 'OK' }], + } + }, + } + + const bridge = createIdeBridgeServer({ diffController }) + const client = createTestClient() + const [clientTransport, serverTransport] = createLinkedTransportPair() + + await bridge.server.connect(serverTransport) + await client.connect(clientTransport) + + const notificationPromise = new Promise>( + resolve => { + client.setNotificationHandler(SelectionChangedSchema, notification => { + resolve(notification) + }) + }, + ) + + await bridge.notifySelectionChanged({ + selection: { + start: { line: 4, character: 2 }, + end: { line: 6, character: 0 }, + }, + text: 'selected text', + filePath: 'D:/vibe/claude-code/src/cli/print.ts', + }) + + const notification = await notificationPromise + expect(notification.params.filePath).toBe( + 'D:/vibe/claude-code/src/cli/print.ts', + ) + expect(notification.params.text).toBe('selected text') + expect(notification.params.selection?.start.line).toBe(4) + }) +}) diff --git a/packages/vscode-ide-bridge/test/diffController.test.ts b/packages/vscode-ide-bridge/test/diffController.test.ts new file mode 100644 index 000000000..3fdf8598d --- /dev/null +++ b/packages/vscode-ide-bridge/test/diffController.test.ts @@ -0,0 +1,247 @@ +import { mkdtempSync, writeFileSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { afterEach, describe, expect, mock, test } from 'bun:test' + +type FakeUri = { + scheme: string + fsPath: string + path: string + query: string + toString(): string +} + +type FakeDocument = { + uri: FakeUri + isDirty: boolean + lineCount: number + lineAt(index: number): { text: string } + getText(): string + setText(next: string): void +} + +function createFakeUri( + scheme: string, + fsPath: string, + query = '', +): FakeUri { + const normalizedFsPath = fsPath.replaceAll('\\', '/') + return { + scheme, + fsPath, + path: fsPath, + query, + toString() { + if (scheme === 'file') { + return `file://${normalizedFsPath}` + } + return `${scheme}:/${normalizedFsPath}${query ? `?${query}` : ''}` + }, + } +} + +function createFakeVscode() { + const documents = new Map() + const saveListeners = new Set<(document: FakeDocument) => void>() + const visibleEditorListeners = new Set<(editors: any[]) => void>() + const visibleTextEditors: any[] = [] + + function createDocument(uri: FakeUri, initialText = ''): FakeDocument { + let text = initialText + return { + uri, + isDirty: false, + get lineCount() { + return Math.max(text.split('\n').length, 1) + }, + lineAt(index: number) { + return { + text: text.split('\n')[index] ?? '', + } + }, + getText() { + return text + }, + setText(next: string) { + text = next + this.isDirty = true + }, + } + } + + const vscode = { + Uri: { + parse(value: string) { + const match = value.match(/^([a-z-]+):\/(.+?)(?:\?(.*))?$/i) + if (!match) { + throw new Error(`Unsupported URI: ${value}`) + } + const [, scheme, path, query = ''] = match + return createFakeUri( + scheme, + decodeURIComponent(path), + query, + ) + }, + file(filePath: string) { + return createFakeUri('file', filePath) + }, + }, + Range: class { + constructor( + public startLine: number, + public startCharacter: number, + public endLine: number, + public endCharacter: number, + ) {} + }, + workspace: { + registerTextDocumentContentProvider() { + return { dispose() {} } + }, + onDidSaveTextDocument(handler: (document: FakeDocument) => void) { + saveListeners.add(handler) + return { + dispose() { + saveListeners.delete(handler) + }, + } + }, + async openTextDocument(uri: FakeUri) { + const key = uri.toString() + const existing = documents.get(key) + if (existing) { + return existing + } + const doc = createDocument(uri) + documents.set(key, doc) + return doc + }, + }, + window: { + visibleTextEditors, + tabGroups: { + all: [], + async close() {}, + }, + onDidChangeVisibleTextEditors(handler: (editors: any[]) => void) { + visibleEditorListeners.add(handler) + return { + dispose() { + visibleEditorListeners.delete(handler) + }, + } + }, + async showTextDocument(document: FakeDocument) { + const editor = { + document, + viewColumn: 1, + async edit( + callback: (editBuilder: { replace(range: unknown, text: string): void }) => void, + ) { + callback({ + replace(_range, text) { + document.setText(text) + }, + }) + return true + }, + } + if (!visibleTextEditors.includes(editor)) { + visibleTextEditors.splice(0, visibleTextEditors.length, editor) + for (const listener of visibleEditorListeners) { + listener([...visibleTextEditors]) + } + } + return editor + }, + async showInformationMessage() { + return undefined + }, + }, + commands: { + async executeCommand() {}, + }, + __documents: documents, + async __emitSave(document: FakeDocument) { + document.isDirty = false + for (const listener of saveListeners) { + listener(document) + } + }, + } + + return vscode +} + +async function waitForDocument( + filePath: string, + attempts = 20, +): Promise { + for (let i = 0; i < attempts; i++) { + const document = fakeVscode.__documents.get( + fakeVscode.Uri.file(filePath).toString(), + ) + if (document) { + return document + } + await new Promise(resolve => setTimeout(resolve, 10)) + } + return undefined +} + +const fakeVscode = createFakeVscode() +mock.module('vscode', () => fakeVscode) + +afterEach(() => { + fakeVscode.__documents.clear() + fakeVscode.window.visibleTextEditors.splice( + 0, + fakeVscode.window.visibleTextEditors.length, + ) +}) + +describe('diff controller', () => { + test('returns FILE_SAVED with the saved file contents', async () => { + const { createDiffController } = await import( + '../src/server/diffController.js' + ) + + const tempDir = mkdtempSync(join(tmpdir(), 'claude-code-bridge-')) + const filePath = join(tempDir, 'sample.ts') + writeFileSync(filePath, 'const before = true\n') + + const controller = createDiffController({ + appendLine() {}, + }) + + const resultPromise = controller.openDiff({ + old_file_path: filePath, + new_file_path: filePath, + new_file_contents: 'const proposed = true\n', + tab_name: 'sample.ts', + }) + + const savedDocument = await waitForDocument(filePath) + expect(savedDocument).toBeDefined() + + savedDocument?.setText('const saved = true\n') + await fakeVscode.__emitSave(savedDocument as FakeDocument) + + const result = await Promise.race([ + resultPromise, + new Promise(resolve => + setTimeout(() => resolve('timed-out'), 200), + ), + ]) + + expect(result).toEqual({ + content: [ + { type: 'text', text: 'FILE_SAVED' }, + { type: 'text', text: 'const saved = true\n' }, + ], + }) + + await controller.dispose() + }) +}) diff --git a/packages/vscode-ide-bridge/test/lockfile.test.ts b/packages/vscode-ide-bridge/test/lockfile.test.ts new file mode 100644 index 000000000..4a14c7a6b --- /dev/null +++ b/packages/vscode-ide-bridge/test/lockfile.test.ts @@ -0,0 +1,39 @@ +import { describe, expect, test } from 'bun:test' +import { + buildLockfilePayload, + getLockfilePath, +} from '../src/server/lockfile.js' + +describe('lockfile helpers', () => { + test('builds a ws-ide lockfile payload with auth token and workspace folders', () => { + const payload = buildLockfilePayload({ + pid: 123, + ideName: 'VS Code', + workspaceFolders: ['D:/vibe/claude-code'], + authToken: 'token-123', + runningInWindows: true, + }) + + expect(payload.transport).toBe('ws') + expect(payload.authToken).toBe('token-123') + expect(payload.workspaceFolders).toEqual(['D:/vibe/claude-code']) + expect(payload.pid).toBe(123) + }) + + test('derives the lockfile path from CLAUDE_CONFIG_DIR when provided', () => { + const originalConfigDir = process.env.CLAUDE_CONFIG_DIR + process.env.CLAUDE_CONFIG_DIR = 'D:/tmp/claude-config' + + try { + expect(getLockfilePath(4567)).toBe( + 'D:\\tmp\\claude-config\\ide\\4567.lock', + ) + } finally { + if (originalConfigDir === undefined) { + delete process.env.CLAUDE_CONFIG_DIR + } else { + process.env.CLAUDE_CONFIG_DIR = originalConfigDir + } + } + }) +}) diff --git a/packages/vscode-ide-bridge/test/package.test.ts b/packages/vscode-ide-bridge/test/package.test.ts new file mode 100644 index 000000000..baca452fe --- /dev/null +++ b/packages/vscode-ide-bridge/test/package.test.ts @@ -0,0 +1,32 @@ +import { existsSync, readFileSync } from 'node:fs' +import { join } from 'node:path' +import { describe, expect, test } from 'bun:test' + +const packageRoot = join(import.meta.dir, '..') +const packageJsonPath = join(packageRoot, 'package.json') + +describe('vscode-ide-bridge package', () => { + test('declares a VSCode extension entry', () => { + expect(existsSync(packageJsonPath)).toBe(true) + + const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as { + main?: string + engines?: { vscode?: string } + activationEvents?: string[] + dependencies?: Record + devDependencies?: Record + } + + expect(packageJson.main).toBe('./dist/extension.js') + expect(packageJson.engines?.vscode).toBeDefined() + expect(packageJson.activationEvents).toContain('onStartupFinished') + expect(packageJson.dependencies).toMatchObject({ + '@modelcontextprotocol/sdk': expect.any(String), + ws: expect.any(String), + }) + expect(packageJson.devDependencies).toMatchObject({ + '@types/bun': expect.any(String), + typescript: expect.any(String), + }) + }) +}) diff --git a/packages/vscode-ide-bridge/test/packagePackaging.test.ts b/packages/vscode-ide-bridge/test/packagePackaging.test.ts new file mode 100644 index 000000000..818aa0cab --- /dev/null +++ b/packages/vscode-ide-bridge/test/packagePackaging.test.ts @@ -0,0 +1,71 @@ +import { existsSync, readFileSync } from 'node:fs' +import { join } from 'node:path' +import { describe, expect, test } from 'bun:test' + +type PackageJson = { + displayName?: string + publisher?: string + license?: string + scripts?: Record +} + +type TaskConfig = { + label?: string + command?: string + args?: string[] +} + +const packageRoot = join(import.meta.dir, '..') +const packageJsonPath = join(packageRoot, 'package.json') +const tasksJsonPath = join(packageRoot, '.vscode', 'tasks.json') +const vscodeIgnorePath = join(packageRoot, '.vscodeignore') +const readmePath = join(packageRoot, 'README.md') + +describe('vscode-ide-bridge packaging workflow', () => { + test('declares the metadata and script needed to package a .vsix', () => { + const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')) as PackageJson + + expect(packageJson.displayName).toBe('Claude Code IDE Bridge') + expect(packageJson.publisher).toBe('claude-code-best') + expect(packageJson.license).toBeDefined() + expect(packageJson.scripts?.bundle).toBe( + 'bun build ./src/extension.ts --outdir dist --target node --format esm --external vscode', + ) + expect(packageJson.scripts?.package).toBe( + 'bun run bundle && bunx @vscode/vsce package --no-dependencies --out dist/vscode-ide-bridge.vsix', + ) + }) + + test('declares a package-local task for building a .vsix', () => { + expect(existsSync(tasksJsonPath)).toBe(true) + + const tasksJson = JSON.parse(readFileSync(tasksJsonPath, 'utf8')) as { + tasks?: TaskConfig[] + } + + const packageTask = tasksJson.tasks?.find( + item => item.label === 'Package VSCode IDE Bridge', + ) + + expect(packageTask).toBeDefined() + expect(packageTask?.command).toBe('bun') + expect(packageTask?.args).toEqual(['run', 'package']) + }) + + test('excludes development-only files from the packaged extension', () => { + expect(existsSync(vscodeIgnorePath)).toBe(true) + + const contents = readFileSync(vscodeIgnorePath, 'utf8') + + expect(contents).toContain('src/**') + expect(contents).toContain('test/**') + expect(contents).toContain('tsconfig.json') + }) + + test('keeps the packaged README free of local absolute file links', () => { + const contents = readFileSync(readmePath, 'utf8') + + expect(contents).not.toContain('](/') + expect(contents).not.toContain(':/') + }) +}) diff --git a/packages/vscode-ide-bridge/test/packageWorkspaceWorkflow.test.ts b/packages/vscode-ide-bridge/test/packageWorkspaceWorkflow.test.ts new file mode 100644 index 000000000..8a03123d8 --- /dev/null +++ b/packages/vscode-ide-bridge/test/packageWorkspaceWorkflow.test.ts @@ -0,0 +1,89 @@ +import { existsSync, readFileSync } from 'node:fs' +import { join } from 'node:path' +import { describe, expect, test } from 'bun:test' + +type LaunchConfig = { + name?: string + type?: string + request?: string + preLaunchTask?: string + args?: string[] +} + +type TaskConfig = { + label?: string + command?: string + args?: string[] +} + +const packageRoot = join(import.meta.dir, '..') +const launchJsonPath = join(packageRoot, '.vscode', 'launch.json') +const tasksJsonPath = join(packageRoot, '.vscode', 'tasks.json') + +describe('standalone package workspace workflow', () => { + test('declares a package-local extension host launch config', () => { + expect(existsSync(launchJsonPath)).toBe(true) + + const launchJson = JSON.parse(readFileSync(launchJsonPath, 'utf8')) as { + configurations?: LaunchConfig[] + } + + const config = launchJson.configurations?.find( + item => item.name === 'Run VSCode IDE Bridge', + ) + + expect(config).toBeDefined() + expect(config?.type).toBe('extensionHost') + expect(config?.request).toBe('launch') + expect(config?.preLaunchTask).toBe('Build VSCode IDE Bridge') + expect(config?.args).toContain('--new-window') + expect(config?.args).toContain('--disable-extensions') + expect(config?.args).toContain( + '--extensionDevelopmentPath=${workspaceFolder}', + ) + }) + + test('declares a launch config that opens the claude-code workspace root', () => { + const launchJson = JSON.parse(readFileSync(launchJsonPath, 'utf8')) as { + configurations?: LaunchConfig[] + } + + const config = launchJson.configurations?.find( + item => item.name === 'Run VSCode IDE Bridge (Open Claude Code Root)', + ) + + expect(config).toBeDefined() + expect(config?.type).toBe('extensionHost') + expect(config?.request).toBe('launch') + expect(config?.preLaunchTask).toBe('Build VSCode IDE Bridge') + expect(config?.args).toContain('--new-window') + expect(config?.args).toContain('--disable-extensions') + expect(config?.args).toContain( + '--extensionDevelopmentPath=${workspaceFolder}', + ) + expect(config?.args).toContain('${workspaceFolder}/../..') + }) + + test('declares package-local build and test tasks', () => { + expect(existsSync(tasksJsonPath)).toBe(true) + + const tasksJson = JSON.parse(readFileSync(tasksJsonPath, 'utf8')) as { + tasks?: TaskConfig[] + } + + const buildTask = tasksJson.tasks?.find( + item => item.label === 'Build VSCode IDE Bridge', + ) + const testTask = tasksJson.tasks?.find( + item => item.label === 'Test VSCode IDE Bridge', + ) + + expect(buildTask).toBeDefined() + expect(buildTask?.command).toBe('bunx') + expect(buildTask?.args).toEqual(['tsc', '-p', 'tsconfig.json']) + + expect(testTask).toBeDefined() + expect(testTask?.command).toBe('bun') + expect(testTask?.args).toEqual(['test', 'test']) + }) +}) diff --git a/packages/vscode-ide-bridge/test/selectionPublisher.test.ts b/packages/vscode-ide-bridge/test/selectionPublisher.test.ts new file mode 100644 index 000000000..e8bb52522 --- /dev/null +++ b/packages/vscode-ide-bridge/test/selectionPublisher.test.ts @@ -0,0 +1,27 @@ +import { describe, expect, test } from 'bun:test' +import { buildSelectionChangedParams } from '../src/server/selectionPublisher.js' + +describe('selection publisher helpers', () => { + test('serializes a selected range with text and file path', () => { + const params = buildSelectionChangedParams({ + filePath: 'D:/vibe/claude-code/src/cli/print.ts', + text: 'const value = 1', + start: { line: 10, character: 2 }, + end: { line: 10, character: 17 }, + }) + + expect(params.filePath).toBe('D:/vibe/claude-code/src/cli/print.ts') + expect(params.text).toBe('const value = 1') + expect(params.selection?.start.line).toBe(10) + expect(params.selection?.end.character).toBe(17) + }) + + test('keeps file context when there is no active selection', () => { + const params = buildSelectionChangedParams({ + filePath: 'D:/vibe/claude-code/src/cli/print.ts', + }) + + expect(params.filePath).toBe('D:/vibe/claude-code/src/cli/print.ts') + expect(params.selection).toBeNull() + }) +}) diff --git a/packages/vscode-ide-bridge/test/serverWebSocketTransport.test.ts b/packages/vscode-ide-bridge/test/serverWebSocketTransport.test.ts new file mode 100644 index 000000000..dd30e2880 --- /dev/null +++ b/packages/vscode-ide-bridge/test/serverWebSocketTransport.test.ts @@ -0,0 +1,71 @@ +import { EventEmitter } from 'node:events' +import { describe, expect, test } from 'bun:test' +import { ServerWebSocketTransport } from '../src/server/serverWebSocketTransport.js' + +class FakeWebSocket extends EventEmitter { + readyState = 1 + sent: string[] = [] + closed = false + + send(data: string, callback?: (error?: Error) => void) { + this.sent.push(data) + callback?.() + } + + close() { + this.closed = true + this.emit('close') + } +} + +describe('server web socket transport', () => { + test('forwards incoming JSON-RPC messages to the MCP server', async () => { + const socket = new FakeWebSocket() + const transport = new ServerWebSocketTransport(socket) + const messages: unknown[] = [] + + transport.onmessage = message => { + messages.push(message) + } + + await transport.start() + socket.emit( + 'message', + Buffer.from( + JSON.stringify({ + jsonrpc: '2.0', + id: 1, + method: 'ping', + params: {}, + }), + ), + ) + + expect(messages).toHaveLength(1) + expect(messages[0]).toEqual({ + jsonrpc: '2.0', + id: 1, + method: 'ping', + params: {}, + }) + }) + + test('serializes outgoing JSON-RPC messages back to the websocket', async () => { + const socket = new FakeWebSocket() + const transport = new ServerWebSocketTransport(socket) + + await transport.start() + await transport.send({ + jsonrpc: '2.0', + id: 2, + result: {}, + }) + + expect(socket.sent).toHaveLength(1) + expect(JSON.parse(socket.sent[0] ?? 'null')).toEqual({ + jsonrpc: '2.0', + id: 2, + result: {}, + }) + }) +}) diff --git a/packages/vscode-ide-bridge/test/terminalEnvironment.test.ts b/packages/vscode-ide-bridge/test/terminalEnvironment.test.ts new file mode 100644 index 000000000..12885a7c9 --- /dev/null +++ b/packages/vscode-ide-bridge/test/terminalEnvironment.test.ts @@ -0,0 +1,48 @@ +import { describe, expect, test } from 'bun:test' +import { + clearClaudeCodeIdePort, + setClaudeCodeIdePort, +} from '../src/server/terminalEnvironment.js' + +type FakeEnvironmentVariableCollection = { + replaceCalls: Array<{ name: string; value: string }> + deleteCalls: string[] + replace(name: string, value: string): void + delete(name: string): void +} + +function createFakeCollection(): FakeEnvironmentVariableCollection { + return { + replaceCalls: [], + deleteCalls: [], + replace(name, value) { + this.replaceCalls.push({ name, value }) + }, + delete(name) { + this.deleteCalls.push(name) + }, + } +} + +describe('terminal environment sync', () => { + test('sets CLAUDE_CODE_SSE_PORT to the active bridge port', () => { + const collection = createFakeCollection() + + setClaudeCodeIdePort(collection, 52075) + + expect(collection.replaceCalls).toEqual([ + { + name: 'CLAUDE_CODE_SSE_PORT', + value: '52075', + }, + ]) + }) + + test('clears CLAUDE_CODE_SSE_PORT when the bridge stops', () => { + const collection = createFakeCollection() + + clearClaudeCodeIdePort(collection) + + expect(collection.deleteCalls).toEqual(['CLAUDE_CODE_SSE_PORT']) + }) +}) diff --git a/packages/vscode-ide-bridge/test/vscodeWorkflow.test.ts b/packages/vscode-ide-bridge/test/vscodeWorkflow.test.ts new file mode 100644 index 000000000..de698f3ce --- /dev/null +++ b/packages/vscode-ide-bridge/test/vscodeWorkflow.test.ts @@ -0,0 +1,61 @@ +import { readFileSync } from 'node:fs' +import { join } from 'node:path' +import { describe, expect, test } from 'bun:test' + +type LaunchConfig = { + name?: string + type?: string + request?: string + preLaunchTask?: string + args?: string[] +} + +type TaskConfig = { + label?: string + command?: string + args?: string[] +} + +const workspaceRoot = join(import.meta.dir, '..', '..', '..') +const launchJsonPath = join(workspaceRoot, '.vscode', 'launch.json') +const tasksJsonPath = join(workspaceRoot, '.vscode', 'tasks.json') + +describe('VSCode IDE bridge developer workflow', () => { + test('declares a one-click extension host launch config', () => { + const launchJson = JSON.parse(readFileSync(launchJsonPath, 'utf8')) as { + configurations?: LaunchConfig[] + } + + const config = launchJson.configurations?.find( + item => item.name === 'Run VSCode IDE Bridge', + ) + + expect(config).toBeDefined() + expect(config?.type).toBe('extensionHost') + expect(config?.request).toBe('launch') + expect(config?.preLaunchTask).toBe('Build VSCode IDE Bridge') + expect(config?.args).toContain('--new-window') + expect(config?.args).toContain('--disable-extensions') + expect(config?.args).toContain( + '--extensionDevelopmentPath=${workspaceFolder}/packages/vscode-ide-bridge', + ) + }) + + test('declares a build task for the bridge package', () => { + const tasksJson = JSON.parse(readFileSync(tasksJsonPath, 'utf8')) as { + tasks?: TaskConfig[] + } + + const task = tasksJson.tasks?.find( + item => item.label === 'Build VSCode IDE Bridge', + ) + + expect(task).toBeDefined() + expect(task?.command).toBe('bunx') + expect(task?.args).toEqual([ + 'tsc', + '-p', + 'packages/vscode-ide-bridge/tsconfig.json', + ]) + }) +}) diff --git a/packages/vscode-ide-bridge/test/workspaceInfo.test.ts b/packages/vscode-ide-bridge/test/workspaceInfo.test.ts new file mode 100644 index 000000000..a48791663 --- /dev/null +++ b/packages/vscode-ide-bridge/test/workspaceInfo.test.ts @@ -0,0 +1,41 @@ +import { describe, expect, test } from 'bun:test' +import { + getActiveSelectionSnapshot, + getWorkspaceFolderPaths, +} from '../src/server/workspaceInfo.js' + +describe('workspace info helpers', () => { + test('collects workspace folder fs paths', () => { + expect( + getWorkspaceFolderPaths([ + { uri: { fsPath: 'D:/vibe/claude-code' } }, + { uri: { fsPath: 'D:/vibe/another-project' } }, + ]), + ).toEqual(['D:/vibe/claude-code', 'D:/vibe/another-project']) + }) + + test('extracts the active editor selection text and file path', () => { + const snapshot = getActiveSelectionSnapshot({ + document: { + uri: { fsPath: 'D:/vibe/claude-code/src/cli/print.ts' }, + getText(selection: unknown) { + expect(selection).toEqual({ + start: { line: 3, character: 1 }, + end: { line: 5, character: 0 }, + isEmpty: false, + }) + return 'selected lines' + }, + }, + selection: { + start: { line: 3, character: 1 }, + end: { line: 5, character: 0 }, + isEmpty: false, + }, + }) + + expect(snapshot.filePath).toBe('D:/vibe/claude-code/src/cli/print.ts') + expect(snapshot.text).toBe('selected lines') + expect(snapshot.selection?.start.line).toBe(3) + }) +}) diff --git a/packages/vscode-ide-bridge/tsconfig.json b/packages/vscode-ide-bridge/tsconfig.json new file mode 100644 index 000000000..0607863a0 --- /dev/null +++ b/packages/vscode-ide-bridge/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "dist", + "rootDir": "src", + "strict": true, + "skipLibCheck": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "types": [ + "bun" + ] + }, + "include": [ + "src/**/*.ts" + ] +} From ea344ad036d763955254fa165e8c94ab5363d27b Mon Sep 17 00:00:00 2001 From: suger Date: Thu, 9 Apr 2026 01:37:27 +0800 Subject: [PATCH 2/2] test: make lockfile path assertion cross-platform --- packages/vscode-ide-bridge/test/lockfile.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/vscode-ide-bridge/test/lockfile.test.ts b/packages/vscode-ide-bridge/test/lockfile.test.ts index 4a14c7a6b..205727976 100644 --- a/packages/vscode-ide-bridge/test/lockfile.test.ts +++ b/packages/vscode-ide-bridge/test/lockfile.test.ts @@ -1,3 +1,4 @@ +import { join } from 'node:path' import { describe, expect, test } from 'bun:test' import { buildLockfilePayload, @@ -26,7 +27,7 @@ describe('lockfile helpers', () => { try { expect(getLockfilePath(4567)).toBe( - 'D:\\tmp\\claude-config\\ide\\4567.lock', + join('D:/tmp/claude-config', 'ide', '4567.lock'), ) } finally { if (originalConfigDir === undefined) {