mirror of
https://github.com/andrepimenta/claude-code-chat.git
synced 2025-12-14 17:49:38 +00:00
Merge pull request #49 from andrepimenta/feature/mcp-support
Feature/mcp support
This commit is contained in:
@@ -9,4 +9,5 @@ vsc-extension-quickstart.md
|
||||
**/*.map
|
||||
**/*.ts
|
||||
**/.vscode-test.*
|
||||
backup
|
||||
backup
|
||||
.claude
|
||||
13954
mcp-permissions.js
Normal file
13954
mcp-permissions.js
Normal file
File diff suppressed because one or more lines are too long
719
package-lock.json
generated
719
package-lock.json
generated
@@ -1,15 +1,14 @@
|
||||
{
|
||||
"name": "claude-code-chat",
|
||||
"version": "0.1.3",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "claude-code-chat",
|
||||
"version": "0.1.3",
|
||||
"version": "1.0.0",
|
||||
"license": "SEE LICENSE IN LICENSE",
|
||||
"devDependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.15.0",
|
||||
"@types/mocha": "^10.0.10",
|
||||
"@types/node": "20.x",
|
||||
"@types/vscode": "^1.94.0",
|
||||
@@ -19,8 +18,7 @@
|
||||
"@vscode/test-electron": "^2.5.2",
|
||||
"@vscode/vsce": "^3.5.0",
|
||||
"eslint": "^9.25.1",
|
||||
"typescript": "^5.8.3",
|
||||
"zod": "^3.25.76"
|
||||
"typescript": "^5.8.3"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.94.0"
|
||||
@@ -558,30 +556,6 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@modelcontextprotocol/sdk": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.15.0.tgz",
|
||||
"integrity": "sha512-67hnl/ROKdb03Vuu0YOr+baKTvf1/5YBHBm9KnZdjdAh8hjt4FRCPD5ucwxGB237sBpzlqQsLy1PFu7z/ekZ9Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ajv": "^6.12.6",
|
||||
"content-type": "^1.0.5",
|
||||
"cors": "^2.8.5",
|
||||
"cross-spawn": "^7.0.5",
|
||||
"eventsource": "^3.0.2",
|
||||
"eventsource-parser": "^3.0.0",
|
||||
"express": "^5.0.1",
|
||||
"express-rate-limit": "^7.5.0",
|
||||
"pkce-challenge": "^5.0.0",
|
||||
"raw-body": "^3.0.0",
|
||||
"zod": "^3.23.8",
|
||||
"zod-to-json-schema": "^3.24.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@@ -1539,43 +1513,6 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
|
||||
"integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-types": "^3.0.0",
|
||||
"negotiator": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts/node_modules/mime-db": {
|
||||
"version": "1.54.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
||||
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts/node_modules/mime-types": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
|
||||
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "^1.54.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.14.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
|
||||
@@ -1834,27 +1771,6 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
|
||||
"integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "^3.1.2",
|
||||
"content-type": "^1.0.5",
|
||||
"debug": "^4.4.0",
|
||||
"http-errors": "^2.0.0",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"on-finished": "^2.4.1",
|
||||
"qs": "^6.14.0",
|
||||
"raw-body": "^3.0.0",
|
||||
"type-is": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/boolbase": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
@@ -1952,16 +1868,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/c8": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/c8/-/c8-9.1.0.tgz",
|
||||
@@ -2317,50 +2223,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
|
||||
"integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "5.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/content-disposition/node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/content-type": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
|
||||
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/convert-source-map": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
||||
@@ -2368,26 +2230,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
|
||||
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie-signature": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
|
||||
"integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/core-util-is": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||
@@ -2395,20 +2237,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cors": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"object-assign": "^4",
|
||||
"vary": "^1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
@@ -2565,16 +2393,6 @@
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
|
||||
@@ -2695,13 +2513,6 @@
|
||||
"url": "https://bevry.me/fund"
|
||||
}
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
|
||||
@@ -2709,16 +2520,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
|
||||
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/encoding-sniffer": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz",
|
||||
@@ -2832,13 +2633,6 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-html": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
@@ -3093,39 +2887,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/etag": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/eventsource": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz",
|
||||
"integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"eventsource-parser": "^3.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eventsource-parser": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.3.tgz",
|
||||
"integrity": "sha512-nVpZkTMM9rF6AQ9gPJpFsNAMt48wIzB5TQgiTLdHiuO8XEDhUgZEhqKlZWXbIzo9VmJ/HvysHqEaVeD5v9TPvA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/expand-template": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
|
||||
@@ -3136,88 +2897,6 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
|
||||
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"accepts": "^2.0.0",
|
||||
"body-parser": "^2.2.0",
|
||||
"content-disposition": "^1.0.0",
|
||||
"content-type": "^1.0.5",
|
||||
"cookie": "^0.7.1",
|
||||
"cookie-signature": "^1.2.1",
|
||||
"debug": "^4.4.0",
|
||||
"encodeurl": "^2.0.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"etag": "^1.8.1",
|
||||
"finalhandler": "^2.1.0",
|
||||
"fresh": "^2.0.0",
|
||||
"http-errors": "^2.0.0",
|
||||
"merge-descriptors": "^2.0.0",
|
||||
"mime-types": "^3.0.0",
|
||||
"on-finished": "^2.4.1",
|
||||
"once": "^1.4.0",
|
||||
"parseurl": "^1.3.3",
|
||||
"proxy-addr": "^2.0.7",
|
||||
"qs": "^6.14.0",
|
||||
"range-parser": "^1.2.1",
|
||||
"router": "^2.2.0",
|
||||
"send": "^1.1.0",
|
||||
"serve-static": "^2.2.0",
|
||||
"statuses": "^2.0.1",
|
||||
"type-is": "^2.0.1",
|
||||
"vary": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/express-rate-limit": {
|
||||
"version": "7.5.1",
|
||||
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz",
|
||||
"integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/express-rate-limit"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"express": ">= 4.11"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/mime-db": {
|
||||
"version": "1.54.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
||||
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/mime-types": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
|
||||
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "^1.54.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
@@ -3317,24 +2996,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/finalhandler": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
|
||||
"integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.4.0",
|
||||
"encodeurl": "^2.0.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"on-finished": "^2.4.1",
|
||||
"parseurl": "^1.3.3",
|
||||
"statuses": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/find-up": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
||||
@@ -3416,26 +3077,6 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/fresh": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
|
||||
"integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
@@ -3769,33 +3410,6 @@
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/http-errors": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
|
||||
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"depd": "2.0.0",
|
||||
"inherits": "2.0.4",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "2.0.1",
|
||||
"toidentifier": "1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/http-errors/node_modules/statuses": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/http-proxy-agent": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
|
||||
@@ -3936,16 +3550,6 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/is-arrayish": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||
@@ -4064,13 +3668,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-promise": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
|
||||
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-unicode-supported": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
|
||||
@@ -4555,29 +4152,6 @@
|
||||
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/media-typer": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
|
||||
"integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-descriptors": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
|
||||
"integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
@@ -4921,16 +4495,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/negotiator": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
|
||||
"integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.75.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.75.0.tgz",
|
||||
@@ -5012,16 +4576,6 @@
|
||||
"url": "https://github.com/fb55/nth-check?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.13.4",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
||||
@@ -5034,19 +4588,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/on-finished": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
||||
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ee-first": "1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
@@ -5386,16 +4927,6 @@
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/parseurl": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
@@ -5443,16 +4974,6 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz",
|
||||
"integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/path-type": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz",
|
||||
@@ -5490,16 +5011,6 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/pkce-challenge": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz",
|
||||
"integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pluralize": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz",
|
||||
@@ -5553,20 +5064,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"forwarded": "0.2.0",
|
||||
"ipaddr.js": "1.9.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/pump": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
|
||||
@@ -5643,32 +5140,6 @@
|
||||
"safe-buffer": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/range-parser": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/raw-body": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
|
||||
"integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.6.3",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/rc": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
|
||||
@@ -5823,23 +5294,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/router": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
|
||||
"integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.4.0",
|
||||
"depd": "^2.0.0",
|
||||
"is-promise": "^4.0.0",
|
||||
"parseurl": "^1.3.3",
|
||||
"path-to-regexp": "^8.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/run-applescript": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz",
|
||||
@@ -5929,52 +5383,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
|
||||
"integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.5",
|
||||
"encodeurl": "^2.0.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"etag": "^1.8.1",
|
||||
"fresh": "^2.0.0",
|
||||
"http-errors": "^2.0.0",
|
||||
"mime-types": "^3.0.1",
|
||||
"ms": "^2.1.3",
|
||||
"on-finished": "^2.4.1",
|
||||
"range-parser": "^1.2.1",
|
||||
"statuses": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/mime-db": {
|
||||
"version": "1.54.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
||||
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/mime-types": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
|
||||
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "^1.54.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/serialize-javascript": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
|
||||
@@ -5985,22 +5393,6 @@
|
||||
"randombytes": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/serve-static": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
|
||||
"integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"encodeurl": "^2.0.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"parseurl": "^1.3.3",
|
||||
"send": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/setimmediate": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||
@@ -6008,13 +5400,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
@@ -6237,16 +5622,6 @@
|
||||
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/statuses": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
|
||||
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/stdin-discarder": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz",
|
||||
@@ -6688,16 +6063,6 @@
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/toidentifier": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-api-utils": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
|
||||
@@ -6764,44 +6129,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/type-is": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
|
||||
"integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"content-type": "^1.0.5",
|
||||
"media-typer": "^1.1.0",
|
||||
"mime-types": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/type-is/node_modules/mime-db": {
|
||||
"version": "1.54.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
||||
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/type-is/node_modules/mime-types": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
|
||||
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "^1.54.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/typed-rest-client": {
|
||||
"version": "1.8.11",
|
||||
"resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz",
|
||||
@@ -6876,16 +6203,6 @@
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/uri-js": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||
@@ -6943,16 +6260,6 @@
|
||||
"spdx-expression-parse": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/version-range": {
|
||||
"version": "4.14.0",
|
||||
"resolved": "https://registry.npmjs.org/version-range/-/version-range-4.14.0.tgz",
|
||||
@@ -7280,26 +6587,6 @@
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.25.76",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
||||
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
},
|
||||
"node_modules/zod-to-json-schema": {
|
||||
"version": "3.24.6",
|
||||
"resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz",
|
||||
"integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"peerDependencies": {
|
||||
"zod": "^3.24.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "claude-code-chat",
|
||||
"displayName": "Claude Code Chat",
|
||||
"description": "Beautiful Claude Code Chat Interface for VS Code",
|
||||
"version": "0.1.3",
|
||||
"version": "1.0.0",
|
||||
"publisher": "AndrePimenta",
|
||||
"author": "Andre Pimenta",
|
||||
"repository": {
|
||||
@@ -207,8 +207,6 @@
|
||||
"@vscode/test-electron": "^2.5.2",
|
||||
"@vscode/vsce": "^3.5.0",
|
||||
"eslint": "^9.25.1",
|
||||
"typescript": "^5.8.3",
|
||||
"@modelcontextprotocol/sdk": "^1.15.0",
|
||||
"zod": "^3.25.76"
|
||||
"typescript": "^5.8.3"
|
||||
}
|
||||
}
|
||||
|
||||
304
src/extension.ts
304
src/extension.ts
@@ -86,6 +86,7 @@ class ClaudeChatProvider {
|
||||
private _webview: vscode.Webview | undefined;
|
||||
private _webviewView: vscode.WebviewView | undefined;
|
||||
private _disposables: vscode.Disposable[] = [];
|
||||
private _messageHandlerDisposable: vscode.Disposable | undefined;
|
||||
private _totalCost: number = 0;
|
||||
private _totalTokensInput: number = 0;
|
||||
private _totalTokensOutput: number = 0;
|
||||
@@ -286,11 +287,35 @@ class ClaudeChatProvider {
|
||||
case 'addPermission':
|
||||
this._addPermission(message.toolName, message.command);
|
||||
return;
|
||||
case 'loadMCPServers':
|
||||
this._loadMCPServers();
|
||||
return;
|
||||
case 'saveMCPServer':
|
||||
this._saveMCPServer(message.name, message.config);
|
||||
return;
|
||||
case 'deleteMCPServer':
|
||||
this._deleteMCPServer(message.name);
|
||||
return;
|
||||
case 'getCustomSnippets':
|
||||
this._sendCustomSnippets();
|
||||
return;
|
||||
case 'saveCustomSnippet':
|
||||
this._saveCustomSnippet(message.snippet);
|
||||
return;
|
||||
case 'deleteCustomSnippet':
|
||||
this._deleteCustomSnippet(message.snippetId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private _setupWebviewMessageHandler(webview: vscode.Webview) {
|
||||
webview.onDidReceiveMessage(
|
||||
// Dispose of any existing message handler
|
||||
if (this._messageHandlerDisposable) {
|
||||
this._messageHandlerDisposable.dispose();
|
||||
}
|
||||
|
||||
// Set up new message handler
|
||||
this._messageHandlerDisposable = webview.onDidReceiveMessage(
|
||||
message => this._handleWebviewMessage(message),
|
||||
null,
|
||||
this._disposables
|
||||
@@ -342,6 +367,7 @@ class ClaudeChatProvider {
|
||||
// Only reinitialize if we have a webview (sidebar)
|
||||
if (this._webview) {
|
||||
this._initializeWebview();
|
||||
// Set up message handler for the webview
|
||||
this._setupWebviewMessageHandler(this._webview);
|
||||
}
|
||||
}
|
||||
@@ -427,9 +453,9 @@ class ClaudeChatProvider {
|
||||
// Add MCP configuration for permissions
|
||||
const mcpConfigPath = this.getMCPConfigPath();
|
||||
if (mcpConfigPath) {
|
||||
args.push('--mcp-config', mcpConfigPath);
|
||||
args.push('--allowedTools', 'mcp__permissions__approval_prompt');
|
||||
args.push('--permission-prompt-tool', 'mcp__permissions__approval_prompt');
|
||||
args.push('--mcp-config', this.convertToWSLPath(mcpConfigPath));
|
||||
args.push('--allowedTools', 'mcp__claude-code-chat-permissions__approval_prompt');
|
||||
args.push('--permission-prompt-tool', 'mcp__claude-code-chat-permissions__approval_prompt');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,9 +482,13 @@ class ClaudeChatProvider {
|
||||
let claudeProcess: cp.ChildProcess;
|
||||
|
||||
if (wslEnabled) {
|
||||
// Use WSL
|
||||
// Use WSL with bash -ic for proper environment loading
|
||||
console.log('Using WSL configuration:', { wslDistro, nodePath, claudePath });
|
||||
claudeProcess = cp.spawn('wsl', ['-d', wslDistro, nodePath, '--no-warnings', '--enable-source-maps', claudePath, ...args], {
|
||||
const wslCommand = `"${nodePath}" --no-warnings --enable-source-maps "${claudePath}" ${args.join(' ')}`;
|
||||
|
||||
console.log('wsl', ['-d', wslDistro, 'bash', '-ic', wslCommand].join(" "))
|
||||
|
||||
claudeProcess = cp.spawn('wsl', ['-d', wslDistro, 'bash', '-ic', wslCommand], {
|
||||
cwd: cwd,
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
env: {
|
||||
@@ -653,6 +683,12 @@ class ClaudeChatProvider {
|
||||
for (const content of jsonData.message.content) {
|
||||
if (content.type === 'tool_result') {
|
||||
let resultContent = content.content || 'Tool executed successfully';
|
||||
|
||||
// Stringify if content is an object or array
|
||||
if (typeof resultContent === 'object' && resultContent !== null) {
|
||||
resultContent = JSON.stringify(resultContent, null, 2);
|
||||
}
|
||||
|
||||
const isError = content.is_error || false;
|
||||
|
||||
// Find the last tool use to get the tool name
|
||||
@@ -782,6 +818,9 @@ class ClaudeChatProvider {
|
||||
}
|
||||
|
||||
public newSessionOnConfigChange() {
|
||||
// Reinitialize MCP config with new WSL paths
|
||||
this._initializeMCPConfig();
|
||||
|
||||
// Start a new session due to configuration change
|
||||
this._newSession();
|
||||
|
||||
@@ -1017,27 +1056,41 @@ class ClaudeChatProvider {
|
||||
console.log(`Created MCP config directory at: ${mcpConfigDir}`);
|
||||
}
|
||||
|
||||
// Create mcp-servers.json with correct path to compiled MCP permissions server
|
||||
// Create or update mcp-servers.json with permissions server, preserving existing servers
|
||||
const mcpConfigPath = path.join(mcpConfigDir, 'mcp-servers.json');
|
||||
const mcpPermissionsPath = path.join(this._extensionUri.fsPath, 'out', 'permissions', 'mcp-permissions.js');
|
||||
const permissionRequestsPath = path.join(storagePath, 'permission-requests');
|
||||
const mcpPermissionsPath = this.convertToWSLPath(path.join(this._extensionUri.fsPath, 'mcp-permissions.js'));
|
||||
const permissionRequestsPath = this.convertToWSLPath(path.join(storagePath, 'permission-requests'));
|
||||
|
||||
const mcpConfig = {
|
||||
mcpServers: {
|
||||
permissions: {
|
||||
command: 'node',
|
||||
args: [mcpPermissionsPath],
|
||||
env: {
|
||||
CLAUDE_PERMISSIONS_PATH: permissionRequestsPath
|
||||
}
|
||||
}
|
||||
// Load existing config or create new one
|
||||
let mcpConfig: any = { mcpServers: {} };
|
||||
const mcpConfigUri = vscode.Uri.file(mcpConfigPath);
|
||||
|
||||
try {
|
||||
const existingContent = await vscode.workspace.fs.readFile(mcpConfigUri);
|
||||
mcpConfig = JSON.parse(new TextDecoder().decode(existingContent));
|
||||
console.log('Loaded existing MCP config, preserving user servers');
|
||||
} catch {
|
||||
console.log('No existing MCP config found, creating new one');
|
||||
}
|
||||
|
||||
// Ensure mcpServers exists
|
||||
if (!mcpConfig.mcpServers) {
|
||||
mcpConfig.mcpServers = {};
|
||||
}
|
||||
|
||||
// Add or update the permissions server entry
|
||||
mcpConfig.mcpServers['claude-code-chat-permissions'] = {
|
||||
command: 'node',
|
||||
args: [mcpPermissionsPath],
|
||||
env: {
|
||||
CLAUDE_PERMISSIONS_PATH: permissionRequestsPath
|
||||
}
|
||||
};
|
||||
|
||||
const configContent = new TextEncoder().encode(JSON.stringify(mcpConfig, null, 2));
|
||||
await vscode.workspace.fs.writeFile(vscode.Uri.file(mcpConfigPath), configContent);
|
||||
await vscode.workspace.fs.writeFile(mcpConfigUri, configContent);
|
||||
|
||||
console.log(`Created MCP config at: ${mcpConfigPath}`);
|
||||
console.log(`Updated MCP config at: ${mcpConfigPath}`);
|
||||
} catch (error: any) {
|
||||
console.error('Failed to initialize MCP config:', error.message);
|
||||
}
|
||||
@@ -1049,7 +1102,7 @@ class ClaudeChatProvider {
|
||||
if (!storagePath) {return;}
|
||||
|
||||
// Create permission requests directory
|
||||
this._permissionRequestsPath = path.join(storagePath, 'permission-requests');
|
||||
this._permissionRequestsPath = path.join(path.join(storagePath, 'permission-requests'));
|
||||
try {
|
||||
await vscode.workspace.fs.stat(vscode.Uri.file(this._permissionRequestsPath));
|
||||
} catch {
|
||||
@@ -1057,12 +1110,15 @@ class ClaudeChatProvider {
|
||||
console.log(`Created permission requests directory at: ${this._permissionRequestsPath}`);
|
||||
}
|
||||
|
||||
console.log("DIRECTORY-----", this._permissionRequestsPath)
|
||||
|
||||
// Set up file watcher for *.request files
|
||||
this._permissionWatcher = vscode.workspace.createFileSystemWatcher(
|
||||
new vscode.RelativePattern(this._permissionRequestsPath, '*.request')
|
||||
);
|
||||
|
||||
this._permissionWatcher.onDidCreate(async (uri) => {
|
||||
console.log("----file", uri)
|
||||
// Only handle file scheme URIs, ignore vscode-userdata scheme
|
||||
if (uri.scheme === 'file') {
|
||||
await this._handlePermissionRequest(uri);
|
||||
@@ -1451,10 +1507,208 @@ class ClaudeChatProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private async _loadMCPServers(): Promise<void> {
|
||||
try {
|
||||
const mcpConfigPath = this.getMCPConfigPath();
|
||||
if (!mcpConfigPath) {
|
||||
this._postMessage({ type: 'mcpServers', data: {} });
|
||||
return;
|
||||
}
|
||||
|
||||
const mcpConfigUri = vscode.Uri.file(mcpConfigPath);
|
||||
let mcpConfig: any = { mcpServers: {} };
|
||||
|
||||
try {
|
||||
const content = await vscode.workspace.fs.readFile(mcpConfigUri);
|
||||
mcpConfig = JSON.parse(new TextDecoder().decode(content));
|
||||
} catch (error) {
|
||||
console.log('MCP config file not found or error reading:', error);
|
||||
// File doesn't exist, return empty servers
|
||||
}
|
||||
|
||||
// Filter out internal servers before sending to UI
|
||||
const filteredServers = Object.fromEntries(
|
||||
Object.entries(mcpConfig.mcpServers || {}).filter(([name]) => name !== 'claude-code-chat-permissions')
|
||||
);
|
||||
this._postMessage({ type: 'mcpServers', data: filteredServers });
|
||||
} catch (error) {
|
||||
console.error('Error loading MCP servers:', error);
|
||||
this._postMessage({ type: 'mcpServerError', data: { error: 'Failed to load MCP servers' } });
|
||||
}
|
||||
}
|
||||
|
||||
private async _saveMCPServer(name: string, config: any): Promise<void> {
|
||||
try {
|
||||
const mcpConfigPath = this.getMCPConfigPath();
|
||||
if (!mcpConfigPath) {
|
||||
this._postMessage({ type: 'mcpServerError', data: { error: 'Storage path not available' } });
|
||||
return;
|
||||
}
|
||||
|
||||
const mcpConfigUri = vscode.Uri.file(mcpConfigPath);
|
||||
let mcpConfig: any = { mcpServers: {} };
|
||||
|
||||
// Load existing config
|
||||
try {
|
||||
const content = await vscode.workspace.fs.readFile(mcpConfigUri);
|
||||
mcpConfig = JSON.parse(new TextDecoder().decode(content));
|
||||
} catch {
|
||||
// File doesn't exist, use default structure
|
||||
}
|
||||
|
||||
// Ensure mcpServers exists
|
||||
if (!mcpConfig.mcpServers) {
|
||||
mcpConfig.mcpServers = {};
|
||||
}
|
||||
|
||||
// Add/update the server
|
||||
mcpConfig.mcpServers[name] = config;
|
||||
|
||||
// Ensure directory exists
|
||||
const mcpDir = vscode.Uri.file(path.dirname(mcpConfigPath));
|
||||
try {
|
||||
await vscode.workspace.fs.stat(mcpDir);
|
||||
} catch {
|
||||
await vscode.workspace.fs.createDirectory(mcpDir);
|
||||
}
|
||||
|
||||
// Save the config
|
||||
const configContent = new TextEncoder().encode(JSON.stringify(mcpConfig, null, 2));
|
||||
await vscode.workspace.fs.writeFile(mcpConfigUri, configContent);
|
||||
|
||||
this._postMessage({ type: 'mcpServerSaved', data: { name } });
|
||||
console.log(`Saved MCP server: ${name}`);
|
||||
} catch (error) {
|
||||
console.error('Error saving MCP server:', error);
|
||||
this._postMessage({ type: 'mcpServerError', data: { error: 'Failed to save MCP server' } });
|
||||
}
|
||||
}
|
||||
|
||||
private async _deleteMCPServer(name: string): Promise<void> {
|
||||
try {
|
||||
const mcpConfigPath = this.getMCPConfigPath();
|
||||
if (!mcpConfigPath) {
|
||||
this._postMessage({ type: 'mcpServerError', data: { error: 'Storage path not available' } });
|
||||
return;
|
||||
}
|
||||
|
||||
const mcpConfigUri = vscode.Uri.file(mcpConfigPath);
|
||||
let mcpConfig: any = { mcpServers: {} };
|
||||
|
||||
// Load existing config
|
||||
try {
|
||||
const content = await vscode.workspace.fs.readFile(mcpConfigUri);
|
||||
mcpConfig = JSON.parse(new TextDecoder().decode(content));
|
||||
} catch {
|
||||
// File doesn't exist, nothing to delete
|
||||
this._postMessage({ type: 'mcpServerError', data: { error: 'MCP config file not found' } });
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete the server
|
||||
if (mcpConfig.mcpServers && mcpConfig.mcpServers[name]) {
|
||||
delete mcpConfig.mcpServers[name];
|
||||
|
||||
// Save the updated config
|
||||
const configContent = new TextEncoder().encode(JSON.stringify(mcpConfig, null, 2));
|
||||
await vscode.workspace.fs.writeFile(mcpConfigUri, configContent);
|
||||
|
||||
this._postMessage({ type: 'mcpServerDeleted', data: { name } });
|
||||
console.log(`Deleted MCP server: ${name}`);
|
||||
} else {
|
||||
this._postMessage({ type: 'mcpServerError', data: { error: `Server '${name}' not found` } });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error deleting MCP server:', error);
|
||||
this._postMessage({ type: 'mcpServerError', data: { error: 'Failed to delete MCP server' } });
|
||||
}
|
||||
}
|
||||
|
||||
private async _sendCustomSnippets(): Promise<void> {
|
||||
try {
|
||||
const customSnippets = this._context.globalState.get<{[key: string]: any}>('customPromptSnippets', {});
|
||||
this._postMessage({
|
||||
type: 'customSnippetsData',
|
||||
data: customSnippets
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error loading custom snippets:', error);
|
||||
this._postMessage({
|
||||
type: 'customSnippetsData',
|
||||
data: {}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async _saveCustomSnippet(snippet: any): Promise<void> {
|
||||
try {
|
||||
const customSnippets = this._context.globalState.get<{[key: string]: any}>('customPromptSnippets', {});
|
||||
customSnippets[snippet.id] = snippet;
|
||||
|
||||
await this._context.globalState.update('customPromptSnippets', customSnippets);
|
||||
|
||||
this._postMessage({
|
||||
type: 'customSnippetSaved',
|
||||
data: { snippet }
|
||||
});
|
||||
|
||||
console.log('Saved custom snippet:', snippet.name);
|
||||
} catch (error) {
|
||||
console.error('Error saving custom snippet:', error);
|
||||
this._postMessage({
|
||||
type: 'error',
|
||||
data: 'Failed to save custom snippet'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async _deleteCustomSnippet(snippetId: string): Promise<void> {
|
||||
try {
|
||||
const customSnippets = this._context.globalState.get<{[key: string]: any}>('customPromptSnippets', {});
|
||||
|
||||
if (customSnippets[snippetId]) {
|
||||
delete customSnippets[snippetId];
|
||||
await this._context.globalState.update('customPromptSnippets', customSnippets);
|
||||
|
||||
this._postMessage({
|
||||
type: 'customSnippetDeleted',
|
||||
data: { snippetId }
|
||||
});
|
||||
|
||||
console.log('Deleted custom snippet:', snippetId);
|
||||
} else {
|
||||
this._postMessage({
|
||||
type: 'error',
|
||||
data: 'Snippet not found'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error deleting custom snippet:', error);
|
||||
this._postMessage({
|
||||
type: 'error',
|
||||
data: 'Failed to delete custom snippet'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private convertToWSLPath(windowsPath: string): string {
|
||||
const config = vscode.workspace.getConfiguration('claudeCodeChat');
|
||||
const wslEnabled = config.get<boolean>('wsl.enabled', false);
|
||||
|
||||
if (wslEnabled && windowsPath.match(/^[a-zA-Z]:/)) {
|
||||
// Convert C:\Users\... to /mnt/c/Users/...
|
||||
return windowsPath.replace(/^([a-zA-Z]):/, '/mnt/$1').toLowerCase().replace(/\\/g, '/');
|
||||
}
|
||||
|
||||
return windowsPath;
|
||||
}
|
||||
|
||||
public getMCPConfigPath(): string | undefined {
|
||||
const storagePath = this._context.storageUri?.fsPath;
|
||||
if (!storagePath) {return undefined;}
|
||||
return path.join(storagePath, 'mcp', 'mcp-servers.json');
|
||||
|
||||
const configPath = path.join(storagePath, 'mcp', 'mcp-servers.json');
|
||||
return path.join(configPath);
|
||||
}
|
||||
|
||||
private _sendAndSaveMessage(message: { type: string, data: any }): void {
|
||||
@@ -1990,6 +2244,12 @@ class ClaudeChatProvider {
|
||||
this._panel = undefined;
|
||||
}
|
||||
|
||||
// Dispose message handler if it exists
|
||||
if (this._messageHandlerDisposable) {
|
||||
this._messageHandlerDisposable.dispose();
|
||||
this._messageHandlerDisposable = undefined;
|
||||
}
|
||||
|
||||
while (this._disposables.length) {
|
||||
const disposable = this._disposables.pop();
|
||||
if (disposable) {
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||
import { z } from "zod";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
const server = new McpServer({
|
||||
name: "Claude Code Permissions MCP Server",
|
||||
version: "0.0.1",
|
||||
});
|
||||
|
||||
// Get permissions directory from environment
|
||||
const PERMISSIONS_PATH = process.env.CLAUDE_PERMISSIONS_PATH;
|
||||
if (!PERMISSIONS_PATH) {
|
||||
console.error("CLAUDE_PERMISSIONS_PATH environment variable not set");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
interface WorkspacePermissions {
|
||||
alwaysAllow: {
|
||||
[toolName: string]: boolean | string[]; // true for all, or array of allowed commands/patterns
|
||||
};
|
||||
}
|
||||
|
||||
function getWorkspacePermissionsPath(): string | null {
|
||||
if (!PERMISSIONS_PATH) return null;
|
||||
return path.join(PERMISSIONS_PATH, 'permissions.json');
|
||||
}
|
||||
|
||||
function loadWorkspacePermissions(): WorkspacePermissions {
|
||||
const permissionsPath = getWorkspacePermissionsPath();
|
||||
if (!permissionsPath || !fs.existsSync(permissionsPath)) {
|
||||
return { alwaysAllow: {} };
|
||||
}
|
||||
|
||||
try {
|
||||
const content = fs.readFileSync(permissionsPath, 'utf8');
|
||||
return JSON.parse(content);
|
||||
} catch (error) {
|
||||
console.error(`Error loading workspace permissions: ${error}`);
|
||||
return { alwaysAllow: {} };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function isAlwaysAllowed(toolName: string, input: any): boolean {
|
||||
const permissions = loadWorkspacePermissions();
|
||||
const toolPermission = permissions.alwaysAllow[toolName];
|
||||
|
||||
if (!toolPermission) return false;
|
||||
|
||||
// If it's true, always allow
|
||||
if (toolPermission === true) return true;
|
||||
|
||||
// If it's an array, check for specific commands (mainly for Bash)
|
||||
if (Array.isArray(toolPermission)) {
|
||||
if (toolName === 'Bash' && input.command) {
|
||||
const command = input.command.trim();
|
||||
return toolPermission.some(allowedCmd => {
|
||||
// Support exact match or pattern matching
|
||||
if (allowedCmd.includes('*')) {
|
||||
// Handle patterns like "npm i *" to match both "npm i" and "npm i something"
|
||||
const baseCommand = allowedCmd.replace(' *', '');
|
||||
if (command === baseCommand) {
|
||||
return true; // Exact match for base command
|
||||
}
|
||||
// Pattern match for command with arguments
|
||||
const pattern = allowedCmd.replace(/\*/g, '.*');
|
||||
return new RegExp(`^${pattern}$`).test(command);
|
||||
}
|
||||
return command.startsWith(allowedCmd);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function generateRequestId(): string {
|
||||
return `req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
||||
}
|
||||
|
||||
async function requestPermission(tool_name: string, input: any): Promise<{approved: boolean, reason?: string}> {
|
||||
if (!PERMISSIONS_PATH) {
|
||||
console.error("Permissions path not available");
|
||||
return { approved: false, reason: "Permissions path not configured" };
|
||||
}
|
||||
|
||||
// Check if this tool/command is always allowed for this workspace
|
||||
if (isAlwaysAllowed(tool_name, input)) {
|
||||
console.error(`Tool ${tool_name} is always allowed for this workspace`);
|
||||
return { approved: true };
|
||||
}
|
||||
|
||||
const requestId = generateRequestId();
|
||||
const requestFile = path.join(PERMISSIONS_PATH, `${requestId}.request`);
|
||||
const responseFile = path.join(PERMISSIONS_PATH, `${requestId}.response`);
|
||||
|
||||
// Write request file
|
||||
const request = {
|
||||
id: requestId,
|
||||
tool: tool_name,
|
||||
input: input,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
|
||||
try {
|
||||
fs.writeFileSync(requestFile, JSON.stringify(request, null, 2));
|
||||
|
||||
// Use fs.watch to wait for response file
|
||||
return new Promise<{approved: boolean, reason?: string}>((resolve) => {
|
||||
const timeout = setTimeout(() => {
|
||||
watcher.close();
|
||||
// Clean up request file on timeout
|
||||
if (fs.existsSync(requestFile)) {
|
||||
fs.unlinkSync(requestFile);
|
||||
}
|
||||
console.error(`Permission request ${requestId} timed out`);
|
||||
resolve({ approved: false, reason: "Permission request timed out" });
|
||||
}, 3600000); // 1 hour timeout
|
||||
|
||||
const watcher = fs.watch(PERMISSIONS_PATH, (eventType, filename) => {
|
||||
if (eventType === 'rename' && filename === path.basename(responseFile)) {
|
||||
// Check if file exists (rename event can be for creation or deletion)
|
||||
if (fs.existsSync(responseFile)) {
|
||||
try {
|
||||
const responseContent = fs.readFileSync(responseFile, 'utf8');
|
||||
const response = JSON.parse(responseContent);
|
||||
|
||||
// Clean up response file
|
||||
fs.unlinkSync(responseFile);
|
||||
|
||||
// Clear timeout and close watcher
|
||||
clearTimeout(timeout);
|
||||
watcher.close();
|
||||
|
||||
resolve({
|
||||
approved: response.approved,
|
||||
reason: response.approved ? undefined : "User rejected the request"
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`Error reading response file: ${error}`);
|
||||
// Continue watching in case of read error
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Handle watcher errors
|
||||
watcher.on('error', (error) => {
|
||||
console.error(`File watcher error: ${error}`);
|
||||
clearTimeout(timeout);
|
||||
watcher.close();
|
||||
resolve({ approved: false, reason: "File watcher error" });
|
||||
});
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error(`Error requesting permission: ${error}`);
|
||||
return { approved: false, reason: `Error processing permission request: ${error}` };
|
||||
}
|
||||
}
|
||||
|
||||
server.tool(
|
||||
"approval_prompt",
|
||||
'Request user permission to execute a tool via VS Code dialog',
|
||||
{
|
||||
tool_name: z.string().describe("The name of the tool requesting permission"),
|
||||
input: z.object({}).passthrough().describe("The input for the tool"),
|
||||
tool_use_id: z.string().optional().describe("The unique tool use request ID"),
|
||||
},
|
||||
async ({ tool_name, input }) => {
|
||||
console.error(`Requesting permission for tool: ${tool_name}`);
|
||||
|
||||
const permissionResult = await requestPermission(tool_name, input);
|
||||
|
||||
const behavior = permissionResult.approved ? "allow" : "deny";
|
||||
console.error(`Permission ${behavior}ed for tool: ${tool_name}`);
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: behavior === "allow" ?
|
||||
JSON.stringify({
|
||||
behavior: behavior,
|
||||
updatedInput: input,
|
||||
})
|
||||
:
|
||||
JSON.stringify({
|
||||
behavior: behavior,
|
||||
message: permissionResult.reason || "Permission denied",
|
||||
})
|
||||
,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
async function main() {
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
console.error(`Permissions MCP Server running on stdio`);
|
||||
console.error(`Using permissions directory: ${PERMISSIONS_PATH}`);
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error("Fatal error in main():", error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"permissions": {
|
||||
"command": "node",
|
||||
"args": [
|
||||
"./out/permissions/mcp-permissions.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
564
src/ui-styles.ts
564
src/ui-styles.ts
@@ -1351,6 +1351,7 @@ const styles = `
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.slash-btn,
|
||||
.at-btn {
|
||||
background-color: transparent;
|
||||
color: var(--vscode-foreground);
|
||||
@@ -1363,6 +1364,7 @@ const styles = `
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.slash-btn:hover,
|
||||
.at-btn:hover {
|
||||
background-color: var(--vscode-list-hoverBackground);
|
||||
}
|
||||
@@ -1622,12 +1624,14 @@ const styles = `
|
||||
.tools-modal-content {
|
||||
background-color: var(--vscode-editor-background);
|
||||
border: 1px solid var(--vscode-panel-border);
|
||||
border-radius: 6px;
|
||||
width: 500px;
|
||||
max-height: 600px;
|
||||
border-radius: 8px;
|
||||
width: 700px;
|
||||
max-width: 90vw;
|
||||
max-height: 80vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tools-modal-header {
|
||||
@@ -1636,6 +1640,13 @@ const styles = `
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.tools-modal-body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.tools-modal-header span {
|
||||
@@ -1667,6 +1678,30 @@ const styles = `
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* MCP Modal content area improvements */
|
||||
#mcpModal * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#mcpModal .tools-list {
|
||||
padding: 24px;
|
||||
max-height: calc(80vh - 120px);
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#mcpModal .mcp-servers-list {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#mcpModal .mcp-add-server {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#mcpModal .mcp-add-form {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.tool-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
@@ -1880,12 +1915,116 @@ const styles = `
|
||||
}
|
||||
|
||||
/* Slash commands modal */
|
||||
.slash-commands-search {
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid var(--vscode-panel-border);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background-color: var(--vscode-editor-background);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.search-input-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: 1px solid var(--vscode-input-border);
|
||||
border-radius: 6px;
|
||||
background-color: var(--vscode-input-background);
|
||||
transition: all 0.2s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-input-wrapper:focus-within {
|
||||
border-color: var(--vscode-focusBorder);
|
||||
box-shadow: 0 0 0 1px var(--vscode-focusBorder);
|
||||
}
|
||||
|
||||
.search-prefix {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 32px;
|
||||
height: 32px;
|
||||
background-color: var(--vscode-button-secondaryBackground);
|
||||
color: var(--vscode-button-secondaryForeground);
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
border-radius: 4px 0 0 4px;
|
||||
border-right: 1px solid var(--vscode-input-border);
|
||||
}
|
||||
|
||||
.slash-commands-search input {
|
||||
flex: 1;
|
||||
padding: 8px 12px;
|
||||
border: none !important;
|
||||
background: transparent;
|
||||
color: var(--vscode-input-foreground);
|
||||
font-size: 13px;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.slash-commands-search input:focus {
|
||||
border: none !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.slash-commands-search input::placeholder {
|
||||
color: var(--vscode-input-placeholderForeground);
|
||||
}
|
||||
|
||||
.command-input-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: 1px solid var(--vscode-input-border);
|
||||
border-radius: 6px;
|
||||
background-color: var(--vscode-input-background);
|
||||
transition: all 0.2s ease;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.command-input-wrapper:focus-within {
|
||||
border-color: var(--vscode-focusBorder);
|
||||
box-shadow: 0 0 0 1px var(--vscode-focusBorder);
|
||||
}
|
||||
|
||||
.command-prefix {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 32px;
|
||||
height: 32px;
|
||||
background-color: var(--vscode-button-secondaryBackground);
|
||||
color: var(--vscode-button-secondaryForeground);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
border-radius: 4px 0 0 4px;
|
||||
border-right: 1px solid var(--vscode-input-border);
|
||||
}
|
||||
|
||||
.slash-commands-section {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.slash-commands-section:last-child {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.slash-commands-section h3 {
|
||||
margin: 16px 20px 12px 20px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--vscode-foreground);
|
||||
}
|
||||
|
||||
.slash-commands-info {
|
||||
padding: 12px 16px;
|
||||
padding: 12px 20px;
|
||||
background-color: rgba(255, 149, 0, 0.1);
|
||||
border: 1px solid rgba(255, 149, 0, 0.2);
|
||||
border-radius: 4px;
|
||||
margin-bottom: 16px;
|
||||
margin: 0 20px 16px 20px;
|
||||
}
|
||||
|
||||
.slash-commands-info p {
|
||||
@@ -1896,33 +2035,161 @@ const styles = `
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.prompt-snippet-item {
|
||||
border-left: 2px solid var(--vscode-charts-blue);
|
||||
background-color: rgba(0, 122, 204, 0.03);
|
||||
}
|
||||
|
||||
.prompt-snippet-item:hover {
|
||||
background-color: rgba(0, 122, 204, 0.08);
|
||||
}
|
||||
|
||||
.add-snippet-item {
|
||||
border-left: 2px solid var(--vscode-charts-green);
|
||||
background-color: rgba(0, 200, 83, 0.03);
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
.add-snippet-item:hover {
|
||||
background-color: rgba(0, 200, 83, 0.08);
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.add-snippet-form {
|
||||
background-color: var(--vscode-editor-background);
|
||||
border: 1px solid var(--vscode-panel-border);
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
margin: 8px 0;
|
||||
animation: slideDown 0.2s ease;
|
||||
}
|
||||
|
||||
.add-snippet-form .form-group {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.add-snippet-form label {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
font-weight: 500;
|
||||
font-size: 12px;
|
||||
color: var(--vscode-foreground);
|
||||
}
|
||||
|
||||
.add-snippet-form textarea {
|
||||
width: 100%;
|
||||
padding: 6px 8px;
|
||||
border: 1px solid var(--vscode-input-border);
|
||||
border-radius: 3px;
|
||||
background-color: var(--vscode-input-background);
|
||||
color: var(--vscode-input-foreground);
|
||||
font-size: 12px;
|
||||
font-family: var(--vscode-font-family);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.add-snippet-form .command-input-wrapper input {
|
||||
flex: 1;
|
||||
padding: 6px 8px;
|
||||
border: none !important;
|
||||
background: transparent;
|
||||
color: var(--vscode-input-foreground);
|
||||
font-size: 12px;
|
||||
font-family: var(--vscode-font-family);
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.add-snippet-form .command-input-wrapper input:focus {
|
||||
border: none !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.add-snippet-form textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--vscode-focusBorder);
|
||||
}
|
||||
|
||||
.add-snippet-form input::placeholder,
|
||||
.add-snippet-form textarea::placeholder {
|
||||
color: var(--vscode-input-placeholderForeground);
|
||||
}
|
||||
|
||||
.add-snippet-form textarea {
|
||||
resize: vertical;
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
.add-snippet-form .form-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
justify-content: flex-end;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.custom-snippet-item {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.snippet-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.custom-snippet-item:hover .snippet-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.snippet-delete-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--vscode-descriptionForeground);
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
transition: all 0.2s ease;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.snippet-delete-btn:hover {
|
||||
background-color: rgba(231, 76, 60, 0.1);
|
||||
color: var(--vscode-errorForeground);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.slash-commands-list {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
gap: 6px;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.slash-command-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 12px 16px;
|
||||
border-radius: 6px;
|
||||
padding: 10px 14px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
transition: all 0.15s ease;
|
||||
border: 1px solid transparent;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.slash-command-item:hover {
|
||||
background-color: var(--vscode-list-hoverBackground);
|
||||
border-color: var(--vscode-focusBorder);
|
||||
border-color: var(--vscode-list-hoverBackground);
|
||||
}
|
||||
|
||||
.slash-command-icon {
|
||||
font-size: 18px;
|
||||
min-width: 24px;
|
||||
font-size: 16px;
|
||||
min-width: 20px;
|
||||
text-align: center;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.slash-command-content {
|
||||
@@ -1931,7 +2198,7 @@ const styles = `
|
||||
|
||||
.slash-command-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
font-weight: 500;
|
||||
color: var(--vscode-foreground);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
@@ -1939,45 +2206,39 @@ const styles = `
|
||||
.slash-command-description {
|
||||
font-size: 11px;
|
||||
color: var(--vscode-descriptionForeground);
|
||||
opacity: 0.8;
|
||||
opacity: 0.7;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
/* Custom command input */
|
||||
/* Quick command input */
|
||||
.custom-command-item {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.custom-command-input-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
.custom-command-item .command-input-wrapper {
|
||||
margin-top: 4px;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.command-prefix {
|
||||
font-size: 12px;
|
||||
color: var(--vscode-foreground);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.custom-command-input {
|
||||
background-color: var(--vscode-input-background);
|
||||
border: 1px solid var(--vscode-input-border);
|
||||
.custom-command-item .command-input-wrapper input {
|
||||
flex: 1;
|
||||
padding: 4px 6px;
|
||||
border: none !important;
|
||||
background: transparent;
|
||||
color: var(--vscode-input-foreground);
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 11px;
|
||||
outline: none;
|
||||
min-width: 120px;
|
||||
font-family: var(--vscode-editor-font-family);
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.custom-command-input:focus {
|
||||
border-color: var(--vscode-focusBorder);
|
||||
box-shadow: 0 0 0 1px var(--vscode-focusBorder);
|
||||
.custom-command-item .command-input-wrapper input:focus {
|
||||
border: none !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.custom-command-input::placeholder {
|
||||
.custom-command-item .command-input-wrapper input::placeholder {
|
||||
color: var(--vscode-input-placeholderForeground);
|
||||
opacity: 0.7;
|
||||
}
|
||||
@@ -2307,6 +2568,231 @@ const styles = `
|
||||
color: var(--vscode-foreground);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* MCP Servers styles */
|
||||
.mcp-servers-list {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.mcp-server-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20px 24px;
|
||||
border: 1px solid var(--vscode-panel-border);
|
||||
border-radius: 8px;
|
||||
margin-bottom: 16px;
|
||||
background-color: var(--vscode-editor-background);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.mcp-server-item:hover {
|
||||
border-color: var(--vscode-focusBorder);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.server-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.server-name {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
color: var(--vscode-foreground);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.server-type {
|
||||
display: inline-block;
|
||||
background-color: var(--vscode-badge-background);
|
||||
color: var(--vscode-badge-foreground);
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.server-config {
|
||||
font-size: 13px;
|
||||
color: var(--vscode-descriptionForeground);
|
||||
opacity: 0.9;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.server-delete-btn {
|
||||
padding: 8px 16px;
|
||||
font-size: 13px;
|
||||
color: var(--vscode-errorForeground);
|
||||
border-color: var(--vscode-errorForeground);
|
||||
min-width: 80px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.server-delete-btn:hover {
|
||||
background-color: var(--vscode-inputValidation-errorBackground);
|
||||
border-color: var(--vscode-errorForeground);
|
||||
}
|
||||
|
||||
.server-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.server-edit-btn {
|
||||
padding: 8px 16px;
|
||||
font-size: 13px;
|
||||
color: var(--vscode-foreground);
|
||||
border-color: var(--vscode-panel-border);
|
||||
min-width: 80px;
|
||||
transition: all 0.2s ease;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.server-edit-btn:hover {
|
||||
background-color: var(--vscode-list-hoverBackground);
|
||||
border-color: var(--vscode-focusBorder);
|
||||
}
|
||||
|
||||
.mcp-add-server {
|
||||
text-align: center;
|
||||
margin-bottom: 24px;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.mcp-add-form {
|
||||
background-color: var(--vscode-editor-background);
|
||||
border: 1px solid var(--vscode-panel-border);
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
margin-top: 20px;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
font-weight: 500;
|
||||
font-size: 13px;
|
||||
color: var(--vscode-foreground);
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group select,
|
||||
.form-group textarea {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--vscode-input-border);
|
||||
border-radius: 4px;
|
||||
background-color: var(--vscode-input-background);
|
||||
color: var(--vscode-input-foreground);
|
||||
font-size: 13px;
|
||||
font-family: var(--vscode-font-family);
|
||||
box-sizing: border-box;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.form-group input:focus,
|
||||
.form-group select:focus,
|
||||
.form-group textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--vscode-focusBorder);
|
||||
box-shadow: 0 0 0 1px var(--vscode-focusBorder);
|
||||
}
|
||||
|
||||
.form-group textarea {
|
||||
resize: vertical;
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
.form-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
justify-content: flex-end;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.no-servers {
|
||||
text-align: center;
|
||||
color: var(--vscode-descriptionForeground);
|
||||
font-style: italic;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
/* Popular MCP Servers */
|
||||
.mcp-popular-servers {
|
||||
margin-top: 32px;
|
||||
padding-top: 24px;
|
||||
border-top: 1px solid var(--vscode-panel-border);
|
||||
}
|
||||
|
||||
.mcp-popular-servers h4 {
|
||||
margin: 0 0 16px 0;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--vscode-foreground);
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.popular-servers-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.popular-server-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 12px 16px;
|
||||
background-color: var(--vscode-editor-background);
|
||||
border: 1px solid var(--vscode-panel-border);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.popular-server-item:hover {
|
||||
border-color: var(--vscode-focusBorder);
|
||||
background-color: var(--vscode-list-hoverBackground);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.popular-server-icon {
|
||||
font-size: 24px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.popular-server-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.popular-server-name {
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
color: var(--vscode-foreground);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.popular-server-desc {
|
||||
font-size: 11px;
|
||||
color: var(--vscode-descriptionForeground);
|
||||
opacity: 0.8;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
</style>`
|
||||
|
||||
export default styles
|
||||
789
src/ui.ts
789
src/ui.ts
@@ -75,14 +75,15 @@ const html = `<!DOCTYPE html>
|
||||
<path d="M1 2.5l3 3 3-3"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="tools-btn" onclick="showToolsModal()" title="Configure tools">
|
||||
Tools: All
|
||||
<button class="tools-btn" onclick="showMCPModal()" title="Configure MCP servers">
|
||||
MCP
|
||||
<svg width="8" height="8" viewBox="0 0 8 8" fill="currentColor">
|
||||
<path d="M1 2.5l3 3 3-3"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="right-controls">
|
||||
<button class="slash-btn" onclick="showSlashCommandsModal()" title="Slash commands">/</button>
|
||||
<button class="at-btn" onclick="showFilePicker()" title="Reference files">@</button>
|
||||
<button class="image-btn" id="imageBtn" onclick="selectImage()" title="Attach images">
|
||||
<svg
|
||||
@@ -148,60 +149,108 @@ const html = `<!DOCTYPE html>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tools modal -->
|
||||
<div id="toolsModal" class="tools-modal" style="display: none;">
|
||||
<!-- MCP Servers modal -->
|
||||
<div id="mcpModal" class="tools-modal" style="display: none;">
|
||||
<div class="tools-modal-content">
|
||||
<div class="tools-modal-header">
|
||||
<span>Claude Code Tools</span>
|
||||
<button class="tools-close-btn" onclick="hideToolsModal()">✕</button>
|
||||
<span>MCP Servers</span>
|
||||
<button class="tools-close-btn" onclick="hideMCPModal()">✕</button>
|
||||
</div>
|
||||
<div class="tools-beta-warning">
|
||||
In Beta: All tools are enabled by default. Use at your own risk.
|
||||
</div>
|
||||
<div id="toolsList" class="tools-list">
|
||||
<div class="tool-item">
|
||||
<input type="checkbox" id="tool-bash" checked disabled>
|
||||
<label for="tool-bash">Bash - Execute shell commands</label>
|
||||
<div class="tools-list">
|
||||
<div class="mcp-servers-list" id="mcpServersList">
|
||||
<!-- MCP servers will be loaded here -->
|
||||
</div>
|
||||
<div class="tool-item">
|
||||
<input type="checkbox" id="tool-read" checked disabled>
|
||||
<label for="tool-read">Read - Read file contents</label>
|
||||
<div class="mcp-add-server">
|
||||
<button class="btn outlined" onclick="showAddServerForm()" id="addServerBtn">+ Add MCP Server</button>
|
||||
</div>
|
||||
<div class="tool-item">
|
||||
<input type="checkbox" id="tool-edit" checked disabled>
|
||||
<label for="tool-edit">Edit - Modify files</label>
|
||||
<div class="mcp-popular-servers" id="popularServers">
|
||||
<h4>Popular MCP Servers</h4>
|
||||
<div class="popular-servers-grid">
|
||||
<div class="popular-server-item" onclick="addPopularServer('context7', { type: 'http', url: 'https://context7.liam.sh/mcp' })">
|
||||
<div class="popular-server-icon">📚</div>
|
||||
<div class="popular-server-info">
|
||||
<div class="popular-server-name">Context7</div>
|
||||
<div class="popular-server-desc">Up-to-date Code Docs For Any Prompt</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="popular-server-item" onclick="addPopularServer('sequential-thinking', { type: 'stdio', command: 'npx', args: ['-y', '@modelcontextprotocol/server-sequential-thinking'] })">
|
||||
<div class="popular-server-icon">🔗</div>
|
||||
<div class="popular-server-info">
|
||||
<div class="popular-server-name">Sequential Thinking</div>
|
||||
<div class="popular-server-desc">Step-by-step reasoning capabilities</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="popular-server-item" onclick="addPopularServer('memory', { type: 'stdio', command: 'npx', args: ['-y', '@modelcontextprotocol/server-memory'] })">
|
||||
<div class="popular-server-icon">🧠</div>
|
||||
<div class="popular-server-info">
|
||||
<div class="popular-server-name">Memory</div>
|
||||
<div class="popular-server-desc">Knowledge graph storage</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="popular-server-item" onclick="addPopularServer('puppeteer', { type: 'stdio', command: 'npx', args: ['-y', '@modelcontextprotocol/server-puppeteer'] })">
|
||||
<div class="popular-server-icon">🎭</div>
|
||||
<div class="popular-server-info">
|
||||
<div class="popular-server-name">Puppeteer</div>
|
||||
<div class="popular-server-desc">Browser automation</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="popular-server-item" onclick="addPopularServer('fetch', { type: 'stdio', command: 'npx', args: ['-y', '@modelcontextprotocol/server-fetch'] })">
|
||||
<div class="popular-server-icon">🌐</div>
|
||||
<div class="popular-server-info">
|
||||
<div class="popular-server-name">Fetch</div>
|
||||
<div class="popular-server-desc">HTTP requests & web scraping</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="popular-server-item" onclick="addPopularServer('filesystem', { type: 'stdio', command: 'npx', args: ['-y', '@modelcontextprotocol/server-filesystem'] })">
|
||||
<div class="popular-server-icon">📁</div>
|
||||
<div class="popular-server-info">
|
||||
<div class="popular-server-name">Filesystem</div>
|
||||
<div class="popular-server-desc">File operations & management</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tool-item">
|
||||
<input type="checkbox" id="tool-write" checked disabled>
|
||||
<label for="tool-write">Write - Create new files</label>
|
||||
<div class="mcp-add-form" id="addServerForm" style="display: none;">
|
||||
<div class="form-group">
|
||||
<label for="serverName">Server Name:</label>
|
||||
<input type="text" id="serverName" placeholder="my-server" required>
|
||||
</div>
|
||||
<div class="tool-item">
|
||||
<input type="checkbox" id="tool-glob" checked disabled>
|
||||
<label for="tool-glob">Glob - Find files by pattern</label>
|
||||
<div class="form-group">
|
||||
<label for="serverType">Server Type:</label>
|
||||
<select id="serverType" onchange="updateServerForm()">
|
||||
<option value="http">HTTP</option>
|
||||
<option value="sse">SSE</option>
|
||||
<option value="stdio">stdio</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="tool-item">
|
||||
<input type="checkbox" id="tool-grep" checked disabled>
|
||||
<label for="tool-grep">Grep - Search file contents</label>
|
||||
<div class="form-group" id="commandGroup" style="display: none;">
|
||||
<label for="serverCommand">Command:</label>
|
||||
<input type="text" id="serverCommand" placeholder="/path/to/server">
|
||||
</div>
|
||||
<div class="tool-item">
|
||||
<input type="checkbox" id="tool-ls" checked disabled>
|
||||
<label for="tool-ls">LS - List directory contents</label>
|
||||
<div class="form-group" id="urlGroup">
|
||||
<label for="serverUrl">URL:</label>
|
||||
<input type="text" id="serverUrl" placeholder="https://example.com/mcp">
|
||||
</div>
|
||||
<div class="tool-item">
|
||||
<input type="checkbox" id="tool-multiedit" checked disabled>
|
||||
<label for="tool-multiedit">MultiEdit - Edit multiple files</label>
|
||||
<div class="form-group" id="argsGroup" style="display: none;">
|
||||
<label for="serverArgs">Arguments (one per line):</label>
|
||||
<textarea id="serverArgs" placeholder="--api-key abc123" rows="3"></textarea>
|
||||
</div>
|
||||
<div class="tool-item">
|
||||
<input type="checkbox" id="tool-websearch" checked disabled>
|
||||
<label for="tool-websearch">WebSearch - Search the web</label>
|
||||
<div class="form-group" id="envGroup" style="display: none;">
|
||||
<label for="serverEnv">Environment Variables (KEY=value, one per line):</label>
|
||||
<textarea id="serverEnv" placeholder="API_KEY=123 CACHE_DIR=/tmp" rows="3"></textarea>
|
||||
</div>
|
||||
<div class="tool-item">
|
||||
<input type="checkbox" id="tool-webfetch" checked disabled>
|
||||
<label for="tool-webfetch">WebFetch - Fetch web content</label>
|
||||
<div class="form-group" id="headersGroup">
|
||||
<label for="serverHeaders">Headers (KEY=value, one per line):</label>
|
||||
<textarea id="serverHeaders" placeholder="Authorization=Bearer token X-API-Key=key" rows="3"></textarea>
|
||||
</div>
|
||||
<div class="form-buttons">
|
||||
<button class="btn" onclick="saveMCPServer()">Add Server</button>
|
||||
<button class="btn outlined" onclick="hideAddServerForm()">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Settings modal -->
|
||||
<div id="settingsModal" class="tools-modal" style="display: none;">
|
||||
@@ -295,19 +344,6 @@ const html = `<!DOCTYPE html>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 style="margin-top: 24px; margin-bottom: 16px; font-size: 14px; font-weight: 600;">MCP Configuration (coming soon)</h3>
|
||||
<div>
|
||||
<p style="font-size: 11px; color: var(--vscode-descriptionForeground); margin: 0;">
|
||||
Model Context Protocol (MCP) allows Claude Code to connect to external systems and services for enhanced capabilities like databases, APIs, and tools.
|
||||
</p>
|
||||
</div>
|
||||
<div class="settings-group">
|
||||
<div class="tool-item">
|
||||
<input type="checkbox" id="mcp-enabled" disabled>
|
||||
<label for="mcp-enabled">Enable MCP Integration <span style="font-style: italic; opacity: 0.7;">(Coming Soon)</span></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 style="margin-top: 24px; margin-bottom: 16px; font-size: 14px; font-weight: 600;">Custom Slash Commands (coming soon)</h3>
|
||||
<div>
|
||||
<p style="font-size: 11px; color: var(--vscode-descriptionForeground); margin: 0;">
|
||||
@@ -403,13 +439,121 @@ const html = `<!DOCTYPE html>
|
||||
<div id="slashCommandsModal" class="tools-modal" style="display: none;">
|
||||
<div class="tools-modal-content">
|
||||
<div class="tools-modal-header">
|
||||
<span>Claude Code Commands</span>
|
||||
<span>Commands & Prompt Snippets</span>
|
||||
<button class="tools-close-btn" onclick="hideSlashCommandsModal()">✕</button>
|
||||
</div>
|
||||
<div class="slash-commands-info">
|
||||
<p>These commands require the Claude CLI and will open in VS Code terminal. Return here after completion.</p>
|
||||
<div class="tools-modal-body">
|
||||
|
||||
<!-- Search box -->
|
||||
<div class="slash-commands-search">
|
||||
<div class="search-input-wrapper">
|
||||
<span class="search-prefix">/</span>
|
||||
<input type="text" id="slashCommandsSearch" placeholder="Search commands and snippets..." oninput="filterSlashCommands()">
|
||||
</div>
|
||||
</div>
|
||||
<div class="slash-commands-list">
|
||||
|
||||
<!-- Custom Commands Section -->
|
||||
<div class="slash-commands-section">
|
||||
<h3>Custom Commands</h3>
|
||||
<div class="slash-commands-info">
|
||||
<p>Custom slash commands for quick prompt access. Click to use directly in chat.</p>
|
||||
</div>
|
||||
<div class="slash-commands-list" id="promptSnippetsList">
|
||||
<!-- Add Custom Snippet Button -->
|
||||
<div class="slash-command-item add-snippet-item" onclick="showAddSnippetForm()">
|
||||
<div class="slash-command-icon">➕</div>
|
||||
<div class="slash-command-content">
|
||||
<div class="slash-command-title">Add Custom Command</div>
|
||||
<div class="slash-command-description">Create your own slash command</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add Custom Command Form (initially hidden) -->
|
||||
<div class="add-snippet-form" id="addSnippetForm" style="display: none;">
|
||||
<div class="form-group">
|
||||
<label for="snippetName">Command name:</label>
|
||||
<div class="command-input-wrapper">
|
||||
<span class="command-prefix">/</span>
|
||||
<input type="text" id="snippetName" placeholder="e.g., fix-bug" maxlength="50">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="snippetPrompt">Prompt Text:</label>
|
||||
<textarea id="snippetPrompt" placeholder="e.g., Help me fix this bug in my code..." rows="3" maxlength="500"></textarea>
|
||||
</div>
|
||||
<div class="form-buttons">
|
||||
<button class="btn" onclick="saveCustomSnippet()">Save Command</button>
|
||||
<button class="btn outlined" onclick="hideAddSnippetForm()">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Built-in Snippets -->
|
||||
<div class="slash-command-item prompt-snippet-item" onclick="usePromptSnippet('performance-analysis')">
|
||||
<div class="slash-command-icon">⚡</div>
|
||||
<div class="slash-command-content">
|
||||
<div class="slash-command-title">/performance-analysis</div>
|
||||
<div class="slash-command-description">Analyze this code for performance issues and suggest optimizations</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slash-command-item prompt-snippet-item" onclick="usePromptSnippet('security-review')">
|
||||
<div class="slash-command-icon">🔒</div>
|
||||
<div class="slash-command-content">
|
||||
<div class="slash-command-title">/security-review</div>
|
||||
<div class="slash-command-description">Review this code for security vulnerabilities</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slash-command-item prompt-snippet-item" onclick="usePromptSnippet('implementation-review')">
|
||||
<div class="slash-command-icon">🔍</div>
|
||||
<div class="slash-command-content">
|
||||
<div class="slash-command-title">/implementation-review</div>
|
||||
<div class="slash-command-description">Review the implementation in this code</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slash-command-item prompt-snippet-item" onclick="usePromptSnippet('code-explanation')">
|
||||
<div class="slash-command-icon">📖</div>
|
||||
<div class="slash-command-content">
|
||||
<div class="slash-command-title">/code-explanation</div>
|
||||
<div class="slash-command-description">Explain how this code works in detail</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slash-command-item prompt-snippet-item" onclick="usePromptSnippet('bug-fix')">
|
||||
<div class="slash-command-icon">🐛</div>
|
||||
<div class="slash-command-content">
|
||||
<div class="slash-command-title">/bug-fix</div>
|
||||
<div class="slash-command-description">Help me fix this bug in my code</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slash-command-item prompt-snippet-item" onclick="usePromptSnippet('refactor')">
|
||||
<div class="slash-command-icon">🔄</div>
|
||||
<div class="slash-command-content">
|
||||
<div class="slash-command-title">/refactor</div>
|
||||
<div class="slash-command-description">Refactor this code to improve readability and maintainability</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slash-command-item prompt-snippet-item" onclick="usePromptSnippet('test-generation')">
|
||||
<div class="slash-command-icon">🧪</div>
|
||||
<div class="slash-command-content">
|
||||
<div class="slash-command-title">/test-generation</div>
|
||||
<div class="slash-command-description">Generate comprehensive tests for this code</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slash-command-item prompt-snippet-item" onclick="usePromptSnippet('documentation')">
|
||||
<div class="slash-command-icon">📝</div>
|
||||
<div class="slash-command-content">
|
||||
<div class="slash-command-title">/documentation</div>
|
||||
<div class="slash-command-description">Generate documentation for this code</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Built-in Commands Section -->
|
||||
<div class="slash-commands-section">
|
||||
<h3>Built-in Commands</h3>
|
||||
<div class="slash-commands-info">
|
||||
<p>These commands require the Claude CLI and will open in VS Code terminal. Return here after completion.</p>
|
||||
</div>
|
||||
<div class="slash-commands-list" id="nativeCommandsList">
|
||||
<div class="slash-command-item" onclick="executeSlashCommand('bug')">
|
||||
<div class="slash-command-icon">🐛</div>
|
||||
<div class="slash-command-content">
|
||||
@@ -546,9 +690,9 @@ const html = `<!DOCTYPE html>
|
||||
<div class="slash-command-item custom-command-item">
|
||||
<div class="slash-command-icon">⚡</div>
|
||||
<div class="slash-command-content">
|
||||
<div class="slash-command-title">Custom Command</div>
|
||||
<div class="slash-command-title">Quick Command</div>
|
||||
<div class="slash-command-description">
|
||||
<div class="custom-command-input-container">
|
||||
<div class="command-input-wrapper">
|
||||
<span class="command-prefix">/</span>
|
||||
<input type="text"
|
||||
class="custom-command-input"
|
||||
@@ -561,6 +705,7 @@ const html = `<!DOCTYPE html>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -923,7 +1068,7 @@ const html = `<!DOCTYPE html>
|
||||
} else if (valueStr.length > 100) {
|
||||
const truncated = valueStr.substring(0, 97) + '...';
|
||||
const escapedValue = valueStr.replace(/"/g, '"').replace(/'/g, ''');
|
||||
result += '<strong>' + key + ':</strong> ' + truncated + ' <span class="expand-btn" data-key="' + key + '" data-value="' + escapedValue + '" onclick="toggleExpand(this)">expand</span>';
|
||||
result += '<span class="expandable-item"><strong>' + key + ':</strong> ' + truncated + ' <span class="expand-btn" data-key="' + key + '" data-value="' + escapedValue + '" onclick="toggleExpand(this)">expand</span></span>';
|
||||
} else {
|
||||
result += '<strong>' + key + ':</strong> ' + valueStr;
|
||||
}
|
||||
@@ -1234,6 +1379,46 @@ const html = `<!DOCTYPE html>
|
||||
}
|
||||
}
|
||||
|
||||
function toggleExpand(button) {
|
||||
const key = button.getAttribute('data-key');
|
||||
const value = button.getAttribute('data-value');
|
||||
|
||||
// Find the container that holds just this key-value pair
|
||||
let container = button.parentNode;
|
||||
while (container && !container.classList.contains('expandable-item')) {
|
||||
container = container.parentNode;
|
||||
}
|
||||
|
||||
if (!container) {
|
||||
// Fallback: create a wrapper around the current line
|
||||
const parent = button.parentNode;
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.className = 'expandable-item';
|
||||
parent.insertBefore(wrapper, button.previousSibling || button);
|
||||
|
||||
// Move the key, value text, and button into the wrapper
|
||||
let currentNode = wrapper.nextSibling;
|
||||
const nodesToMove = [];
|
||||
while (currentNode && currentNode !== button.nextSibling) {
|
||||
nodesToMove.push(currentNode);
|
||||
currentNode = currentNode.nextSibling;
|
||||
}
|
||||
nodesToMove.forEach(node => wrapper.appendChild(node));
|
||||
container = wrapper;
|
||||
}
|
||||
|
||||
if (button.textContent === 'expand') {
|
||||
// Show full content
|
||||
const decodedValue = value.replace(/"/g, '"').replace(/'/g, "'");
|
||||
container.innerHTML = '<strong>' + key + ':</strong> ' + decodedValue + ' <span class="expand-btn" data-key="' + key + '" data-value="' + value + '" onclick="toggleExpand(this)">collapse</span>';
|
||||
} else {
|
||||
// Show truncated content
|
||||
const decodedValue = value.replace(/"/g, '"').replace(/'/g, "'");
|
||||
const truncated = decodedValue.substring(0, 97) + '...';
|
||||
container.innerHTML = '<strong>' + key + ':</strong> ' + truncated + ' <span class="expand-btn" data-key="' + key + '" data-value="' + value + '" onclick="toggleExpand(this)">expand</span>';
|
||||
}
|
||||
}
|
||||
|
||||
function sendMessage() {
|
||||
const text = messageInput.value.trim();
|
||||
if (text) {
|
||||
@@ -1523,8 +1708,10 @@ const html = `<!DOCTYPE html>
|
||||
});
|
||||
|
||||
// Tools modal functions
|
||||
function showToolsModal() {
|
||||
document.getElementById('toolsModal').style.display = 'flex';
|
||||
function showMCPModal() {
|
||||
document.getElementById('mcpModal').style.display = 'flex';
|
||||
// Load existing MCP servers
|
||||
loadMCPServers();
|
||||
}
|
||||
|
||||
function updateYoloWarning() {
|
||||
@@ -1575,17 +1762,310 @@ const html = `<!DOCTYPE html>
|
||||
}
|
||||
}
|
||||
|
||||
function hideToolsModal() {
|
||||
document.getElementById('toolsModal').style.display = 'none';
|
||||
function hideMCPModal() {
|
||||
document.getElementById('mcpModal').style.display = 'none';
|
||||
hideAddServerForm();
|
||||
}
|
||||
|
||||
// Close tools modal when clicking outside
|
||||
document.getElementById('toolsModal').addEventListener('click', (e) => {
|
||||
if (e.target === document.getElementById('toolsModal')) {
|
||||
hideToolsModal();
|
||||
// Close MCP modal when clicking outside
|
||||
document.getElementById('mcpModal').addEventListener('click', (e) => {
|
||||
if (e.target === document.getElementById('mcpModal')) {
|
||||
hideMCPModal();
|
||||
}
|
||||
});
|
||||
|
||||
// MCP Server management functions
|
||||
function loadMCPServers() {
|
||||
vscode.postMessage({ type: 'loadMCPServers' });
|
||||
}
|
||||
|
||||
function showAddServerForm() {
|
||||
document.getElementById('addServerBtn').style.display = 'none';
|
||||
document.getElementById('popularServers').style.display = 'none';
|
||||
document.getElementById('addServerForm').style.display = 'block';
|
||||
}
|
||||
|
||||
function hideAddServerForm() {
|
||||
document.getElementById('addServerBtn').style.display = 'block';
|
||||
document.getElementById('popularServers').style.display = 'block';
|
||||
document.getElementById('addServerForm').style.display = 'none';
|
||||
|
||||
// Reset editing state
|
||||
editingServerName = null;
|
||||
|
||||
// Reset form title and button
|
||||
const formTitle = document.querySelector('#addServerForm h5');
|
||||
if (formTitle) formTitle.remove();
|
||||
|
||||
const saveBtn = document.querySelector('#addServerForm .btn:not(.outlined)');
|
||||
if (saveBtn) saveBtn.textContent = 'Add Server';
|
||||
|
||||
// Clear form
|
||||
document.getElementById('serverName').value = '';
|
||||
document.getElementById('serverName').disabled = false;
|
||||
document.getElementById('serverCommand').value = '';
|
||||
document.getElementById('serverUrl').value = '';
|
||||
document.getElementById('serverArgs').value = '';
|
||||
document.getElementById('serverEnv').value = '';
|
||||
document.getElementById('serverHeaders').value = '';
|
||||
document.getElementById('serverType').value = 'http';
|
||||
updateServerForm();
|
||||
}
|
||||
|
||||
function updateServerForm() {
|
||||
const serverType = document.getElementById('serverType').value;
|
||||
const commandGroup = document.getElementById('commandGroup');
|
||||
const urlGroup = document.getElementById('urlGroup');
|
||||
const argsGroup = document.getElementById('argsGroup');
|
||||
const envGroup = document.getElementById('envGroup');
|
||||
const headersGroup = document.getElementById('headersGroup');
|
||||
|
||||
if (serverType === 'stdio') {
|
||||
commandGroup.style.display = 'block';
|
||||
urlGroup.style.display = 'none';
|
||||
argsGroup.style.display = 'block';
|
||||
envGroup.style.display = 'block';
|
||||
headersGroup.style.display = 'none';
|
||||
} else if (serverType === 'http' || serverType === 'sse') {
|
||||
commandGroup.style.display = 'none';
|
||||
urlGroup.style.display = 'block';
|
||||
argsGroup.style.display = 'none';
|
||||
envGroup.style.display = 'none';
|
||||
headersGroup.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
function saveMCPServer() {
|
||||
const name = document.getElementById('serverName').value.trim();
|
||||
const type = document.getElementById('serverType').value;
|
||||
|
||||
if (!name) {
|
||||
// Use a simple notification instead of alert which is blocked
|
||||
const notification = document.createElement('div');
|
||||
notification.textContent = 'Server name is required';
|
||||
notification.style.cssText = 'position: fixed; top: 20px; right: 20px; background: var(--vscode-inputValidation-errorBackground); color: var(--vscode-inputValidation-errorForeground); padding: 8px 12px; border-radius: 4px; z-index: 9999;';
|
||||
document.body.appendChild(notification);
|
||||
setTimeout(() => notification.remove(), 3000);
|
||||
return;
|
||||
}
|
||||
|
||||
// If editing, we can use the same name; if adding, check for duplicates
|
||||
if (!editingServerName) {
|
||||
const serversList = document.getElementById('mcpServersList');
|
||||
const existingServers = serversList.querySelectorAll('.server-name');
|
||||
for (let server of existingServers) {
|
||||
if (server.textContent === name) {
|
||||
const notification = document.createElement('div');
|
||||
notification.textContent = \`Server "\${name}" already exists\`;
|
||||
notification.style.cssText = 'position: fixed; top: 20px; right: 20px; background: var(--vscode-inputValidation-errorBackground); color: var(--vscode-inputValidation-errorForeground); padding: 8px 12px; border-radius: 4px; z-index: 9999;';
|
||||
document.body.appendChild(notification);
|
||||
setTimeout(() => notification.remove(), 3000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const serverConfig = { type };
|
||||
|
||||
if (type === 'stdio') {
|
||||
const command = document.getElementById('serverCommand').value.trim();
|
||||
if (!command) {
|
||||
const notification = document.createElement('div');
|
||||
notification.textContent = 'Command is required for stdio servers';
|
||||
notification.style.cssText = 'position: fixed; top: 20px; right: 20px; background: var(--vscode-inputValidation-errorBackground); color: var(--vscode-inputValidation-errorForeground); padding: 8px 12px; border-radius: 4px; z-index: 9999;';
|
||||
document.body.appendChild(notification);
|
||||
setTimeout(() => notification.remove(), 3000);
|
||||
return;
|
||||
}
|
||||
serverConfig.command = command;
|
||||
|
||||
const argsText = document.getElementById('serverArgs').value.trim();
|
||||
if (argsText) {
|
||||
serverConfig.args = argsText.split('\\n').filter(line => line.trim());
|
||||
}
|
||||
|
||||
const envText = document.getElementById('serverEnv').value.trim();
|
||||
if (envText) {
|
||||
serverConfig.env = {};
|
||||
envText.split('\\n').forEach(line => {
|
||||
const [key, ...valueParts] = line.split('=');
|
||||
if (key && valueParts.length > 0) {
|
||||
serverConfig.env[key.trim()] = valueParts.join('=').trim();
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (type === 'http' || type === 'sse') {
|
||||
const url = document.getElementById('serverUrl').value.trim();
|
||||
if (!url) {
|
||||
const notification = document.createElement('div');
|
||||
notification.textContent = 'URL is required for HTTP/SSE servers';
|
||||
notification.style.cssText = 'position: fixed; top: 20px; right: 20px; background: var(--vscode-inputValidation-errorBackground); color: var(--vscode-inputValidation-errorForeground); padding: 8px 12px; border-radius: 4px; z-index: 9999;';
|
||||
document.body.appendChild(notification);
|
||||
setTimeout(() => notification.remove(), 3000);
|
||||
return;
|
||||
}
|
||||
serverConfig.url = url;
|
||||
|
||||
const headersText = document.getElementById('serverHeaders').value.trim();
|
||||
if (headersText) {
|
||||
serverConfig.headers = {};
|
||||
headersText.split('\\n').forEach(line => {
|
||||
const [key, ...valueParts] = line.split('=');
|
||||
if (key && valueParts.length > 0) {
|
||||
serverConfig.headers[key.trim()] = valueParts.join('=').trim();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
vscode.postMessage({
|
||||
type: 'saveMCPServer',
|
||||
name: name,
|
||||
config: serverConfig
|
||||
});
|
||||
|
||||
hideAddServerForm();
|
||||
}
|
||||
|
||||
function deleteMCPServer(serverName) {
|
||||
// Just delete without confirmation
|
||||
vscode.postMessage({
|
||||
type: 'deleteMCPServer',
|
||||
name: serverName
|
||||
});
|
||||
}
|
||||
|
||||
let editingServerName = null;
|
||||
|
||||
function editMCPServer(name, config) {
|
||||
editingServerName = name;
|
||||
|
||||
// Hide add button and popular servers
|
||||
document.getElementById('addServerBtn').style.display = 'none';
|
||||
document.getElementById('popularServers').style.display = 'none';
|
||||
|
||||
// Show form
|
||||
document.getElementById('addServerForm').style.display = 'block';
|
||||
|
||||
// Update form title and button
|
||||
const formTitle = document.querySelector('#addServerForm h5') ||
|
||||
document.querySelector('#addServerForm').insertAdjacentHTML('afterbegin', '<h5>Edit MCP Server</h5>') ||
|
||||
document.querySelector('#addServerForm h5');
|
||||
if (!document.querySelector('#addServerForm h5')) {
|
||||
document.getElementById('addServerForm').insertAdjacentHTML('afterbegin', '<h5 style="margin: 0 0 20px 0; font-size: 14px; font-weight: 600;">Edit MCP Server</h5>');
|
||||
} else {
|
||||
document.querySelector('#addServerForm h5').textContent = 'Edit MCP Server';
|
||||
}
|
||||
|
||||
// Update save button text
|
||||
const saveBtn = document.querySelector('#addServerForm .btn:not(.outlined)');
|
||||
if (saveBtn) saveBtn.textContent = 'Update Server';
|
||||
|
||||
// Populate form with existing values
|
||||
document.getElementById('serverName').value = name;
|
||||
document.getElementById('serverName').disabled = true; // Don't allow name changes when editing
|
||||
|
||||
document.getElementById('serverType').value = config.type || 'stdio';
|
||||
|
||||
if (config.command) {
|
||||
document.getElementById('serverCommand').value = config.command;
|
||||
}
|
||||
if (config.url) {
|
||||
document.getElementById('serverUrl').value = config.url;
|
||||
}
|
||||
if (config.args && Array.isArray(config.args)) {
|
||||
document.getElementById('serverArgs').value = config.args.join('\\n');
|
||||
}
|
||||
if (config.env) {
|
||||
const envLines = Object.entries(config.env).map(([key, value]) => \`\${key}=\${value}\`);
|
||||
document.getElementById('serverEnv').value = envLines.join('\\n');
|
||||
}
|
||||
if (config.headers) {
|
||||
const headerLines = Object.entries(config.headers).map(([key, value]) => \`\${key}=\${value}\`);
|
||||
document.getElementById('serverHeaders').value = headerLines.join('\\n');
|
||||
}
|
||||
|
||||
// Update form field visibility
|
||||
updateServerForm();
|
||||
|
||||
const toolsList = document.querySelector('.tools-list');
|
||||
if (toolsList) {
|
||||
toolsList.scrollTop = toolsList.scrollHeight;
|
||||
}
|
||||
}
|
||||
|
||||
function addPopularServer(name, config) {
|
||||
// Check if server already exists
|
||||
const serversList = document.getElementById('mcpServersList');
|
||||
const existingServers = serversList.querySelectorAll('.server-name');
|
||||
for (let server of existingServers) {
|
||||
if (server.textContent === name) {
|
||||
const notification = document.createElement('div');
|
||||
notification.textContent = \`Server "\${name}" already exists\`;
|
||||
notification.style.cssText = 'position: fixed; top: 20px; right: 20px; background: var(--vscode-inputValidation-errorBackground); color: var(--vscode-inputValidation-errorForeground); padding: 8px 12px; border-radius: 4px; z-index: 9999;';
|
||||
document.body.appendChild(notification);
|
||||
setTimeout(() => notification.remove(), 3000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the server
|
||||
vscode.postMessage({
|
||||
type: 'saveMCPServer',
|
||||
name: name,
|
||||
config: config
|
||||
});
|
||||
}
|
||||
|
||||
function displayMCPServers(servers) {
|
||||
const serversList = document.getElementById('mcpServersList');
|
||||
serversList.innerHTML = '';
|
||||
|
||||
if (Object.keys(servers).length === 0) {
|
||||
serversList.innerHTML = '<div class="no-servers">No MCP servers configured</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
for (const [name, config] of Object.entries(servers)) {
|
||||
const serverItem = document.createElement('div');
|
||||
serverItem.className = 'mcp-server-item';
|
||||
|
||||
// Defensive check for config structure
|
||||
if (!config || typeof config !== 'object') {
|
||||
console.error('Invalid config for server:', name, config);
|
||||
continue;
|
||||
}
|
||||
|
||||
const serverType = config.type || 'stdio';
|
||||
let configDisplay = '';
|
||||
|
||||
if (serverType === 'stdio') {
|
||||
configDisplay = \`Command: \${config.command || 'Not specified'}\`;
|
||||
if (config.args && Array.isArray(config.args)) {
|
||||
configDisplay += \`<br>Args: \${config.args.join(' ')}\`;
|
||||
}
|
||||
} else if (serverType === 'http' || serverType === 'sse') {
|
||||
configDisplay = \`URL: \${config.url || 'Not specified'}\`;
|
||||
} else {
|
||||
configDisplay = \`Type: \${serverType}\`;
|
||||
}
|
||||
|
||||
serverItem.innerHTML = \`
|
||||
<div class="server-info">
|
||||
<div class="server-name">\${name}</div>
|
||||
<div class="server-type">\${serverType.toUpperCase()}</div>
|
||||
<div class="server-config">\${configDisplay}</div>
|
||||
</div>
|
||||
<div class="server-actions">
|
||||
<button class="btn outlined server-edit-btn" onclick="editMCPServer('\${name}', \${JSON.stringify(config).replace(/"/g, '"')})">Edit</button>
|
||||
<button class="btn outlined server-delete-btn" onclick="deleteMCPServer('\${name}')">Delete</button>
|
||||
</div>
|
||||
\`;
|
||||
|
||||
serversList.appendChild(serverItem);
|
||||
}
|
||||
}
|
||||
|
||||
// Model selector functions
|
||||
let currentModel = 'opus'; // Default model
|
||||
|
||||
@@ -1605,6 +2085,10 @@ const html = `<!DOCTYPE html>
|
||||
// Slash commands modal functions
|
||||
function showSlashCommandsModal() {
|
||||
document.getElementById('slashCommandsModal').style.display = 'flex';
|
||||
// Auto-focus the search input
|
||||
setTimeout(() => {
|
||||
document.getElementById('slashCommandsSearch').focus();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function hideSlashCommandsModal() {
|
||||
@@ -1739,6 +2223,136 @@ const html = `<!DOCTYPE html>
|
||||
}
|
||||
}
|
||||
|
||||
// Store custom snippets data globally
|
||||
let customSnippetsData = {};
|
||||
|
||||
function usePromptSnippet(snippetType) {
|
||||
const builtInSnippets = {
|
||||
'performance-analysis': 'Analyze this code for performance issues and suggest optimizations',
|
||||
'security-review': 'Review this code for security vulnerabilities',
|
||||
'implementation-review': 'Review the implementation in this code',
|
||||
'code-explanation': 'Explain how this code works in detail',
|
||||
'bug-fix': 'Help me fix this bug in my code',
|
||||
'refactor': 'Refactor this code to improve readability and maintainability',
|
||||
'test-generation': 'Generate comprehensive tests for this code',
|
||||
'documentation': 'Generate documentation for this code'
|
||||
};
|
||||
|
||||
// Check built-in snippets first
|
||||
let promptText = builtInSnippets[snippetType];
|
||||
|
||||
// If not found in built-in, check custom snippets
|
||||
if (!promptText && customSnippetsData[snippetType]) {
|
||||
promptText = customSnippetsData[snippetType].prompt;
|
||||
}
|
||||
|
||||
if (promptText) {
|
||||
// Hide the modal
|
||||
hideSlashCommandsModal();
|
||||
|
||||
// Insert the prompt into the message input
|
||||
messageInput.value = promptText;
|
||||
messageInput.focus();
|
||||
|
||||
// Auto-resize the textarea
|
||||
autoResizeTextarea();
|
||||
}
|
||||
}
|
||||
|
||||
function showAddSnippetForm() {
|
||||
document.getElementById('addSnippetForm').style.display = 'block';
|
||||
document.getElementById('snippetName').focus();
|
||||
}
|
||||
|
||||
function hideAddSnippetForm() {
|
||||
document.getElementById('addSnippetForm').style.display = 'none';
|
||||
// Clear form fields
|
||||
document.getElementById('snippetName').value = '';
|
||||
document.getElementById('snippetPrompt').value = '';
|
||||
}
|
||||
|
||||
function saveCustomSnippet() {
|
||||
const name = document.getElementById('snippetName').value.trim();
|
||||
const prompt = document.getElementById('snippetPrompt').value.trim();
|
||||
|
||||
if (!name || !prompt) {
|
||||
alert('Please fill in both name and prompt text.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate a unique ID for the snippet
|
||||
const snippetId = 'custom-' + Date.now();
|
||||
|
||||
// Save the snippet using VS Code global storage
|
||||
const snippetData = {
|
||||
name: name,
|
||||
prompt: prompt,
|
||||
id: snippetId
|
||||
};
|
||||
|
||||
vscode.postMessage({
|
||||
type: 'saveCustomSnippet',
|
||||
snippet: snippetData
|
||||
});
|
||||
|
||||
// Hide the form
|
||||
hideAddSnippetForm();
|
||||
}
|
||||
|
||||
function loadCustomSnippets(snippetsData = {}) {
|
||||
const snippetsList = document.getElementById('promptSnippetsList');
|
||||
|
||||
// Remove existing custom snippets
|
||||
const existingCustom = snippetsList.querySelectorAll('.custom-snippet-item');
|
||||
existingCustom.forEach(item => item.remove());
|
||||
|
||||
// Add custom snippets after the add button and form
|
||||
const addForm = document.getElementById('addSnippetForm');
|
||||
|
||||
Object.values(snippetsData).forEach(snippet => {
|
||||
const snippetElement = document.createElement('div');
|
||||
snippetElement.className = 'slash-command-item prompt-snippet-item custom-snippet-item';
|
||||
snippetElement.onclick = () => usePromptSnippet(snippet.id);
|
||||
|
||||
snippetElement.innerHTML = \`
|
||||
<div class="slash-command-icon">📝</div>
|
||||
<div class="slash-command-content">
|
||||
<div class="slash-command-title">/\${snippet.name}</div>
|
||||
<div class="slash-command-description">\${snippet.prompt}</div>
|
||||
</div>
|
||||
<div class="snippet-actions">
|
||||
<button class="snippet-delete-btn" onclick="event.stopPropagation(); deleteCustomSnippet('\${snippet.id}')" title="Delete snippet">🗑️</button>
|
||||
</div>
|
||||
\`;
|
||||
|
||||
// Insert after the form
|
||||
addForm.parentNode.insertBefore(snippetElement, addForm.nextSibling);
|
||||
});
|
||||
}
|
||||
|
||||
function deleteCustomSnippet(snippetId) {
|
||||
vscode.postMessage({
|
||||
type: 'deleteCustomSnippet',
|
||||
snippetId: snippetId
|
||||
});
|
||||
}
|
||||
|
||||
function filterSlashCommands() {
|
||||
const searchTerm = document.getElementById('slashCommandsSearch').value.toLowerCase();
|
||||
const allItems = document.querySelectorAll('.slash-command-item');
|
||||
|
||||
allItems.forEach(item => {
|
||||
const title = item.querySelector('.slash-command-title').textContent.toLowerCase();
|
||||
const description = item.querySelector('.slash-command-description').textContent.toLowerCase();
|
||||
|
||||
if (title.includes(searchTerm) || description.includes(searchTerm)) {
|
||||
item.style.display = 'flex';
|
||||
} else {
|
||||
item.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function openModelTerminal() {
|
||||
vscode.postMessage({
|
||||
type: 'openModelTerminal'
|
||||
@@ -2141,11 +2755,28 @@ const html = `<!DOCTYPE html>
|
||||
case 'permissionRequest':
|
||||
addPermissionRequestMessage(message.data);
|
||||
break;
|
||||
case 'mcpServers':
|
||||
displayMCPServers(message.data);
|
||||
break;
|
||||
case 'mcpServerSaved':
|
||||
loadMCPServers(); // Reload the servers list
|
||||
addMessage('✅ MCP server "' + message.data.name + '" saved successfully', 'system');
|
||||
break;
|
||||
case 'mcpServerDeleted':
|
||||
loadMCPServers(); // Reload the servers list
|
||||
addMessage('✅ MCP server "' + message.data.name + '" deleted successfully', 'system');
|
||||
break;
|
||||
case 'mcpServerError':
|
||||
addMessage('❌ Error with MCP server: ' + message.data.error, 'error');
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// Permission request functions
|
||||
function addPermissionRequestMessage(data) {
|
||||
const messagesDiv = document.getElementById('messages');
|
||||
const shouldScroll = shouldAutoScroll(messagesDiv);
|
||||
|
||||
const messageDiv = document.createElement('div');
|
||||
messageDiv.className = 'message permission-request';
|
||||
|
||||
@@ -2852,6 +3483,11 @@ const html = `<!DOCTYPE html>
|
||||
}
|
||||
});
|
||||
|
||||
// Request custom snippets from VS Code on page load
|
||||
vscode.postMessage({
|
||||
type: 'getCustomSnippets'
|
||||
});
|
||||
|
||||
// Detect slash commands input
|
||||
messageInput.addEventListener('input', (e) => {
|
||||
const value = messageInput.value;
|
||||
@@ -2866,7 +3502,22 @@ const html = `<!DOCTYPE html>
|
||||
window.addEventListener('message', event => {
|
||||
const message = event.data;
|
||||
|
||||
if (message.type === 'settingsData') {
|
||||
if (message.type === 'customSnippetsData') {
|
||||
// Update global custom snippets data
|
||||
customSnippetsData = message.data || {};
|
||||
// Refresh the snippets display
|
||||
loadCustomSnippets(customSnippetsData);
|
||||
} else if (message.type === 'customSnippetSaved') {
|
||||
// Refresh snippets after saving
|
||||
vscode.postMessage({
|
||||
type: 'getCustomSnippets'
|
||||
});
|
||||
} else if (message.type === 'customSnippetDeleted') {
|
||||
// Refresh snippets after deletion
|
||||
vscode.postMessage({
|
||||
type: 'getCustomSnippets'
|
||||
});
|
||||
} else if (message.type === 'settingsData') {
|
||||
// Update UI with current settings
|
||||
const thinkingIntensity = message.data['thinking.intensity'] || 'think';
|
||||
const intensityValues = ['think', 'think-hard', 'think-harder', 'ultrathink'];
|
||||
|
||||
@@ -13,5 +13,8 @@
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
}
|
||||
},
|
||||
"exclude": [
|
||||
"mcp-permissions.js"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user