diff --git a/.github/workflows/code-qa.yml b/.github/workflows/code-qa.yml index 06367080fc3..e28302f46d8 100644 --- a/.github/workflows/code-qa.yml +++ b/.github/workflows/code-qa.yml @@ -28,6 +28,21 @@ jobs: - name: Lint run: npm run lint + knip: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + cache: 'npm' + - name: Install dependencies + run: npm run install:all + - name: Run knip checks + run: npm run knip + unit-test: runs-on: ubuntu-latest steps: diff --git a/knip.json b/knip.json new file mode 100644 index 00000000000..b0e0839da77 --- /dev/null +++ b/knip.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://unpkg.com/knip@latest/schema.json", + "entry": ["src/extension.ts", "src/activate/index.ts", "webview-ui/src/index.tsx"], + "project": ["src/**/*.ts", "webview-ui/src/**/*.{ts,tsx}"], + "ignore": [ + "**/__mocks__/**", + "**/__tests__/**", + "**/test/**", + "**/*.test.ts", + "**/*.test.tsx", + "**/stories/**", + "coverage/**", + "dist/**", + "out/**", + "bin/**", + "src/activate/**", + "src/exports/**", + "src/extension.ts", + ".vscode-test.mjs" + ], + "workspaces": { + "webview-ui": { + "entry": ["src/index.tsx"], + "project": ["src/**/*.{ts,tsx}"] + } + } +} diff --git a/package-lock.json b/package-lock.json index 4f7cf4246ce..0e139c0ff82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -76,6 +76,7 @@ "husky": "^9.1.7", "jest": "^29.7.0", "jest-simple-dot-reporter": "^1.0.5", + "knip": "^5.44.4", "lint-staged": "^15.2.11", "mkdirp": "^3.0.1", "mocha": "^11.1.0", @@ -5854,6 +5855,47 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, + "node_modules/@snyk/github-codeowners": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@snyk/github-codeowners/-/github-codeowners-1.1.0.tgz", + "integrity": "sha512-lGFf08pbkEac0NYgVf4hdANpAgApRjNByLXB+WBip3qj1iendOIyAwP2GKkKbQMNVy2r1xxDf0ssfWscoiC+Vw==", + "dev": true, + "dependencies": { + "commander": "^4.1.1", + "ignore": "^5.1.8", + "p-map": "^4.0.0" + }, + "bin": { + "github-codeowners": "dist/cli.js" + }, + "engines": { + "node": ">=8.10" + } + }, + "node_modules/@snyk/github-codeowners/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@snyk/github-codeowners/node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", @@ -6696,6 +6738,19 @@ "node": ">= 8.0.0" } }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -7530,6 +7585,15 @@ "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==", "dev": true }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/cli-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", @@ -7662,6 +7726,16 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.8" + } + }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -7957,6 +8031,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "optional": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -8207,6 +8294,27 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, + "node_modules/easy-table": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.2.0.tgz", + "integrity": "sha512-OFzVOv03YpvtcWGe5AayU5G2hgybsg3iqA6drU8UaoZyB9jLGMTrz9+asnLp/E+6qPh88yEI1gvyZFZ41dmgww==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "optionalDependencies": { + "wcwidth": "^1.0.1" + } + }, + "node_modules/easy-table/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -8299,9 +8407,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", - "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -8947,15 +9055,15 @@ "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -9957,6 +10065,15 @@ "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -11323,6 +11440,15 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "dev": true, + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -11472,6 +11598,114 @@ "node": ">=6" } }, + "node_modules/knip": { + "version": "5.44.4", + "resolved": "https://registry.npmjs.org/knip/-/knip-5.44.4.tgz", + "integrity": "sha512-Ryn8LwWHLId8jSK1DgtT0hmg5DbzkqAtH+Gg3vZJpmSMgGHMspej9Ag+qKTm8wsPLDjVetuEz/lIsobo0XCMvQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/webpro" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/knip" + }, + { + "type": "polar", + "url": "https://polar.sh/webpro-nl" + } + ], + "dependencies": { + "@nodelib/fs.walk": "3.0.1", + "@snyk/github-codeowners": "1.1.0", + "easy-table": "1.2.0", + "enhanced-resolve": "^5.18.0", + "fast-glob": "^3.3.3", + "jiti": "^2.4.2", + "js-yaml": "^4.1.0", + "minimist": "^1.2.8", + "picocolors": "^1.1.0", + "picomatch": "^4.0.1", + "pretty-ms": "^9.0.0", + "smol-toml": "^1.3.1", + "strip-json-comments": "5.0.1", + "summary": "2.1.0", + "zod": "^3.22.4", + "zod-validation-error": "^3.0.3" + }, + "bin": { + "knip": "bin/knip.js", + "knip-bun": "bin/knip-bun.js" + }, + "engines": { + "node": ">=18.18.0" + }, + "peerDependencies": { + "@types/node": ">=18", + "typescript": ">=5.0.4" + } + }, + "node_modules/knip/node_modules/@nodelib/fs.scandir": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-4.0.1.tgz", + "integrity": "sha512-vAkI715yhnmiPupY+dq+xenu5Tdf2TBQ66jLvBIcCddtz+5Q8LbMKaf9CIJJreez8fQ8fgaY+RaywQx8RJIWpw==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "4.0.0", + "run-parallel": "^1.2.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/knip/node_modules/@nodelib/fs.stat": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-4.0.0.tgz", + "integrity": "sha512-ctr6bByzksKRCV0bavi8WoQevU6plSp2IkllIsEqaiKe2mwNNnaluhnRhcsgGZHrrHk57B3lf95MkLMO3STYcg==", + "dev": true, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/knip/node_modules/@nodelib/fs.walk": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-3.0.1.tgz", + "integrity": "sha512-nIh/M6Kh3ZtOmlY00DaUYB4xeeV6F3/ts1l29iwl3/cfyY/OuCfUx+v08zgx8TKPTifXRcjjqVQ4KB2zOYSbyw==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "4.0.1", + "fastq": "^1.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/knip/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/knip/node_modules/strip-json-comments": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz", + "integrity": "sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -12205,6 +12439,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", @@ -13170,6 +13413,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parse5": { "version": "7.2.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", @@ -13480,6 +13735,21 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/pretty-ms": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.2.0.tgz", + "integrity": "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==", + "dev": true, + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -14340,6 +14610,18 @@ "npm": ">= 3.0.0" } }, + "node_modules/smol-toml": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.3.1.tgz", + "integrity": "sha512-tEYNll18pPKHroYSmLLrksq233j021G0giwW7P3D24jC54pQ5W5BXMsQ/Mvw1OJCmEYDgY+lrzT+3nNUtoNfXQ==", + "dev": true, + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, "node_modules/socks": { "version": "2.8.3", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", @@ -14761,6 +15043,12 @@ "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" }, + "node_modules/summary": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/summary/-/summary-2.1.0.tgz", + "integrity": "sha512-nMIjMrd5Z2nuB2RZCKJfFMjgS3fygbeyGk9PxPPaJR1RIcyN9yn4A63Isovzm3ZtQuEkLBVgMdPup8UeLH7aQw==", + "dev": true + }, "node_modules/supports-color": { "version": "9.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz", @@ -15336,6 +15624,16 @@ "makeerror": "1.0.12" } }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "optional": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, "node_modules/web-streams-polyfill": { "version": "4.0.0-beta.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", @@ -15962,6 +16260,18 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zod-validation-error": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.4.0.tgz", + "integrity": "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==", + "dev": true, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.18.0" + } } } } diff --git a/package.json b/package.json index 4a5ba593254..133580698df 100644 --- a/package.json +++ b/package.json @@ -281,6 +281,7 @@ "compile": "tsc -p . --outDir out && node esbuild.js", "compile:integration": "tsc -p tsconfig.integration.json", "install:all": "npm install && cd webview-ui && npm install", + "knip": "knip --include files", "lint": "eslint src --ext ts && npm run lint --prefix webview-ui", "lint-local": "eslint -c .eslintrc.local.json src --ext ts && npm run lint --prefix webview-ui", "lint-fix": "eslint src --ext ts --fix && npm run lint-fix --prefix webview-ui", @@ -371,6 +372,7 @@ "husky": "^9.1.7", "jest": "^29.7.0", "jest-simple-dot-reporter": "^1.0.5", + "knip": "^5.44.4", "lint-staged": "^15.2.11", "mkdirp": "^3.0.1", "mocha": "^11.1.0", diff --git a/src/api/transform/o1-format.ts b/src/api/transform/o1-format.ts deleted file mode 100644 index 040bca7a303..00000000000 --- a/src/api/transform/o1-format.ts +++ /dev/null @@ -1,429 +0,0 @@ -import { Anthropic } from "@anthropic-ai/sdk" -import OpenAI from "openai" - -const o1SystemPrompt = (systemPrompt: string) => ` -# System Prompt - -${systemPrompt} - -# Instructions for Formulating Your Response - -You must respond to the user's request by using at least one tool call. When formulating your response, follow these guidelines: - -1. Begin your response with normal text, explaining your thoughts, analysis, or plan of action. -2. If you need to use any tools, place ALL tool calls at the END of your message, after your normal text explanation. -3. You can use multiple tool calls if needed, but they should all be grouped together at the end of your message. -4. After placing the tool calls, do not add any additional normal text. The tool calls should be the final content in your message. - -Here's the general structure your responses should follow: - -\`\`\` -[Your normal text response explaining your thoughts and actions] - -[Tool Call 1] -[Tool Call 2 if needed] -[Tool Call 3 if needed] -... -\`\`\` - -Remember: -- Choose the most appropriate tool(s) based on the task and the tool descriptions provided. -- Formulate your tool calls using the XML format specified for each tool. -- Provide clear explanations in your normal text about what actions you're taking and why you're using particular tools. -- Act as if the tool calls will be executed immediately after your message, and your next response will have access to their results. - -# Tool Descriptions and XML Formats - -1. execute_command: - -Your command here - -Description: Execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory. - -2. list_files: - -Directory path here -true or false (optional) - -Description: List files and directories within the specified directory. If recursive is true, it will list all files and directories recursively. If recursive is false or not provided, it will only list the top-level contents. - -3. list_code_definition_names: - -Directory path here - -Description: Lists definition names (classes, functions, methods, etc.) used in source code files at the top level of the specified directory. This tool provides insights into the codebase structure and important constructs, encapsulating high-level concepts and relationships that are crucial for understanding the overall architecture. - -4. search_files: - -Directory path here -Your regex pattern here -Optional file pattern here - -Description: Perform a regex search across files in a specified directory, providing context-rich results. This tool searches for patterns or specific content across multiple files, displaying each match with encapsulating context. - -5. read_file: - -File path here - -Description: Read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string. - -6. create_file: - -File path here - -Your file content here - - -Description: Write content to a file at the specified path. If the file exists, it will be overwritten with the provided content. If the file doesn't exist, it will be created. Always provide the full intended content of the file, without any truncation. This tool will automatically create any directories needed to write the file. - -7. ask_followup_question: - -Your question here - -Description: Ask the user a question to gather additional information needed to complete the task. This tool should be used when you encounter ambiguities, need clarification, or require more details to proceed effectively. It allows for interactive problem-solving by enabling direct communication with the user. Use this tool judiciously to maintain a balance between gathering necessary information and avoiding excessive back-and-forth. - -8. attempt_completion: - -Optional command to demonstrate result - -Your final result description here - - -Description: Once you've completed the task, use this tool to present the result to the user. They may respond with feedback if they are not satisfied with the result, which you can use to make improvements and try again. - -# Examples - -Here are some examples of how to structure your responses with tool calls: - -Example 1: Using a single tool - -Let's run the test suite for our project. This will help us ensure that all our components are functioning correctly. - - -npm test - - -Example 2: Using multiple tools - -Let's create two new configuration files for the web application: one for the frontend and one for the backend. - - -./frontend-config.json - -{ - "apiEndpoint": "https://api.example.com", - "theme": { - "primaryColor": "#007bff", - "secondaryColor": "#6c757d", - "fontFamily": "Arial, sans-serif" - }, - "features": { - "darkMode": true, - "notifications": true, - "analytics": false - }, - "version": "1.0.0" -} - - - - -./backend-config.yaml - -database: - host: localhost - port: 5432 - name: myapp_db - user: admin - -server: - port: 3000 - environment: development - logLevel: debug - -security: - jwtSecret: your-secret-key-here - passwordSaltRounds: 10 - -caching: - enabled: true - provider: redis - ttl: 3600 - -externalServices: - emailProvider: sendgrid - storageProvider: aws-s3 - - - -Example 3: Asking a follow-up question - -I've analyzed the project structure, but I need more information to proceed. Let me ask the user for clarification. - - -Which specific feature would you like me to implement in the example.py file? - -` - -export function convertToO1Messages( - openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[], - systemPrompt: string, -): OpenAI.Chat.ChatCompletionMessageParam[] { - const toolsReplaced = openAiMessages.reduce((acc, message) => { - if (message.role === "tool") { - // Convert tool messages to user messages - acc.push({ - role: "user", - content: message.content || "", - }) - } else if (message.role === "assistant" && message.tool_calls) { - // Convert tool calls to content and remove tool_calls - let content = message.content || "" - message.tool_calls.forEach((toolCall) => { - if (toolCall.type === "function") { - content += `\nTool Call: ${toolCall.function.name}\nArguments: ${toolCall.function.arguments}` - } - }) - acc.push({ - role: "assistant", - content: content, - tool_calls: undefined, - }) - } else { - // Keep other messages as they are - acc.push(message) - } - return acc - }, [] as OpenAI.Chat.ChatCompletionMessageParam[]) - - // Find the index of the last assistant message - // const lastAssistantIndex = findLastIndex(toolsReplaced, (message) => message.role === "assistant") - - // Create a new array to hold the modified messages - const messagesWithSystemPrompt = [ - { - role: "user", - content: o1SystemPrompt(systemPrompt), - } as OpenAI.Chat.ChatCompletionUserMessageParam, - ...toolsReplaced, - ] - - // If there's an assistant message, insert the system prompt after it - // if (lastAssistantIndex !== -1) { - // const insertIndex = lastAssistantIndex + 1 - // if (insertIndex < messagesWithSystemPrompt.length && messagesWithSystemPrompt[insertIndex].role === "user") { - // messagesWithSystemPrompt.splice(insertIndex, 0, { - // role: "user", - // content: o1SystemPrompt(systemPrompt), - // }) - // } - // } else { - // // If there were no assistant messages, prepend the system prompt - // messagesWithSystemPrompt.unshift({ - // role: "user", - // content: o1SystemPrompt(systemPrompt), - // }) - // } - - return messagesWithSystemPrompt -} - -interface ToolCall { - tool: string - tool_input: Record -} - -const toolNames = [ - "execute_command", - "list_files", - "list_code_definition_names", - "search_files", - "read_file", - "create_file", - "ask_followup_question", - "attempt_completion", -] - -function parseAIResponse(response: string): { normalText: string; toolCalls: ToolCall[] } { - // Create a regex pattern to match any tool call opening tag - const toolCallPattern = new RegExp(`<(${toolNames.join("|")})`, "i") - const match = response.match(toolCallPattern) - - if (!match) { - // No tool calls found - return { normalText: response.trim(), toolCalls: [] } - } - - const toolCallStart = match.index! - const normalText = response.slice(0, toolCallStart).trim() - const toolCallsText = response.slice(toolCallStart) - - const toolCalls = parseToolCalls(toolCallsText) - - return { normalText, toolCalls } -} - -function parseToolCalls(toolCallsText: string): ToolCall[] { - const toolCalls: ToolCall[] = [] - - let remainingText = toolCallsText - - while (remainingText.length > 0) { - const toolMatch = toolNames.find((tool) => new RegExp(`<${tool}`, "i").test(remainingText)) - - if (!toolMatch) { - break // No more tool calls found - } - - const startTag = `<${toolMatch}` - const endTag = `` - const startIndex = remainingText.indexOf(startTag) - const endIndex = remainingText.indexOf(endTag, startIndex) - - if (endIndex === -1) { - break // Malformed XML, no closing tag found - } - - const toolCallContent = remainingText.slice(startIndex, endIndex + endTag.length) - remainingText = remainingText.slice(endIndex + endTag.length).trim() - - const toolCall = parseToolCall(toolMatch, toolCallContent) - if (toolCall) { - toolCalls.push(toolCall) - } - } - - return toolCalls -} - -function parseToolCall(toolName: string, content: string): ToolCall | null { - const tool_input: Record = {} - - // Remove the outer tool tags - const innerContent = content.replace(new RegExp(`^<${toolName}>|$`, "g"), "").trim() - - // Parse nested XML elements - const paramRegex = /<(\w+)>([\s\S]*?)<\/\1>/gs - let match - - while ((match = paramRegex.exec(innerContent)) !== null) { - const [, paramName, paramValue] = match - // Preserve newlines and trim only leading/trailing whitespace - tool_input[paramName] = paramValue.replace(/^\s+|\s+$/g, "") - } - - // Validate required parameters - if (!validateToolInput(toolName, tool_input)) { - console.error(`Invalid tool call for ${toolName}:`, content) - return null - } - - return { tool: toolName, tool_input } -} - -function validateToolInput(toolName: string, tool_input: Record): boolean { - switch (toolName) { - case "execute_command": - return "command" in tool_input - case "read_file": - case "list_code_definition_names": - case "list_files": - return "path" in tool_input - case "search_files": - return "path" in tool_input && "regex" in tool_input - case "create_file": - return "path" in tool_input && "content" in tool_input - case "ask_followup_question": - return "question" in tool_input - case "attempt_completion": - return "result" in tool_input - default: - return false - } -} - -// Example usage: -// const aiResponse = `Here's my analysis of the situation... - -// -// ls -la -// - -// -// ./example.txt -// Hello, World! -// `; -// -// const { normalText, toolCalls } = parseAIResponse(aiResponse); -// console.log(normalText); -// console.log(toolCalls); - -// Convert OpenAI response to Anthropic format -export function convertO1ResponseToAnthropicMessage( - completion: OpenAI.Chat.Completions.ChatCompletion, -): Anthropic.Messages.Message { - const openAiMessage = completion.choices[0].message - const { normalText, toolCalls } = parseAIResponse(openAiMessage.content || "") - - const anthropicMessage: Anthropic.Messages.Message = { - id: completion.id, - type: "message", - role: openAiMessage.role, // always "assistant" - content: [ - { - type: "text", - text: normalText, - }, - ], - model: completion.model, - stop_reason: (() => { - switch (completion.choices[0].finish_reason) { - case "stop": - return "end_turn" - case "length": - return "max_tokens" - case "tool_calls": - return "tool_use" - case "content_filter": // Anthropic doesn't have an exact equivalent - default: - return null - } - })(), - stop_sequence: null, // which custom stop_sequence was generated, if any (not applicable if you don't use stop_sequence) - usage: { - input_tokens: completion.usage?.prompt_tokens || 0, - output_tokens: completion.usage?.completion_tokens || 0, - }, - } - - if (toolCalls.length > 0) { - anthropicMessage.content.push( - ...toolCalls.map((toolCall: ToolCall, index: number): Anthropic.ToolUseBlock => { - return { - type: "tool_use", - id: `call_${index}_${Date.now()}`, // Generate a unique ID for each tool call - name: toolCall.tool, - input: toolCall.tool_input, - } - }), - ) - } - - return anthropicMessage -} - -// Example usage: -// const openAICompletion = { -// id: "cmpl-123", -// choices: [{ -// message: { -// role: "assistant", -// content: "Here's my analysis...\n\n\n ls -la\n" -// }, -// finish_reason: "stop" -// }], -// model: "gpt-3.5-turbo", -// usage: { prompt_tokens: 50, completion_tokens: 100 } -// }; -// const anthropicMessage = convertO1ResponseToAnthropicMessage(openAICompletion); -// console.log(anthropicMessage); diff --git a/src/integrations/diagnostics/DiagnosticsMonitor.ts b/src/integrations/diagnostics/DiagnosticsMonitor.ts deleted file mode 100644 index 67735674844..00000000000 --- a/src/integrations/diagnostics/DiagnosticsMonitor.ts +++ /dev/null @@ -1,123 +0,0 @@ -/* -import * as vscode from "vscode" -import deepEqual from "fast-deep-equal" - -type FileDiagnostics = [vscode.Uri, vscode.Diagnostic[]][] - - -About Diagnostics: -The Problems tab shows diagnostics that have been reported for your project. These diagnostics are categorized into: -Errors: Critical issues that usually prevent your code from compiling or running correctly. -Warnings: Potential problems in the code that may not prevent it from running but could cause issues (e.g., bad practices, unused variables). -Information: Non-critical suggestions or tips (e.g., formatting issues or notes from linters). -The Problems tab displays diagnostics from various sources: -1. Language Servers: - - TypeScript: Type errors, missing imports, syntax issues - - Python: Syntax errors, invalid type hints, undefined variables - - JavaScript/Node.js: Parsing and execution errors -2. Linters: - - ESLint: Code style, best practices, potential bugs - - Pylint: Unused imports, naming conventions - - TSLint: Style and correctness issues in TypeScript -3. Build Tools: - - Webpack: Module resolution failures, build errors - - Gulp: Build errors during task execution -4. Custom Validators: - - Extensions can generate custom diagnostics for specific languages or tools -Each problem typically indicates its source (e.g., language server, linter, build tool). -Diagnostics update in real-time as you edit code, helping identify issues quickly. For example, if you introduce a syntax error in a TypeScript file, the Problems tab will immediately display the new error. - -Notes on diagnostics: -- linter diagnostics are only captured for open editors -- this works great for us since when cline edits/creates files its through vscode's textedit api's and we get those diagnostics for free -- some tools might require you to save the file or manually refresh to clear the problem from the list. - -System Prompt -- You will automatically receive workspace error diagnostics in environment_details. Be mindful that this may include issues beyond the scope of your task or the user's request. Only address errors relevant to your work, and avoid fixing pre-existing or unrelated issues unless the user specifically instructs you to do so. -- If you are unable to resolve errors provided in environment_details after two attempts, consider using ask_followup_question to ask the user for additional information, such as the latest documentation related to a problematic framework, to help you make progress on the task. If the error remains unresolved after this step, proceed with your task while disregarding the error. - -class DiagnosticsMonitor { - private diagnosticsChangeEmitter: vscode.EventEmitter = new vscode.EventEmitter() - private disposables: vscode.Disposable[] = [] - private lastDiagnostics: FileDiagnostics = [] - - constructor() { - this.disposables.push( - vscode.languages.onDidChangeDiagnostics(() => { - this.diagnosticsChangeEmitter.fire() - }) - ) - } - - public async getCurrentDiagnostics(shouldWaitForChanges: boolean): Promise { - const currentDiagnostics = this.getDiagnostics() - if (!shouldWaitForChanges) { - this.lastDiagnostics = currentDiagnostics - return currentDiagnostics - } - - if (!deepEqual(this.lastDiagnostics, currentDiagnostics)) { - this.lastDiagnostics = currentDiagnostics - return currentDiagnostics - } - - let timeout = 300 // only way this happens is if theres no errors - - // if diagnostics contain existing errors (since the check above didn't trigger) then it's likely cline just did something that should have fixed the error, so we'll give a longer grace period for diagnostics to catch up - const hasErrors = currentDiagnostics.some(([_, diagnostics]) => - diagnostics.some((d) => d.severity === vscode.DiagnosticSeverity.Error) - ) - if (hasErrors) { - console.log("Existing errors detected, extending timeout", currentDiagnostics) - timeout = 10_000 - } - - return this.waitForUpdatedDiagnostics(timeout) - } - - private async waitForUpdatedDiagnostics(timeout: number): Promise { - return new Promise((resolve, reject) => { - const timer = setTimeout(() => { - cleanup() - const finalDiagnostics = this.getDiagnostics() - this.lastDiagnostics = finalDiagnostics - resolve(finalDiagnostics) - }, timeout) - - const disposable = this.diagnosticsChangeEmitter.event(() => { - const updatedDiagnostics = this.getDiagnostics() // I thought this would only trigger when diagnostics changed, but that's not the case. - if (deepEqual(this.lastDiagnostics, updatedDiagnostics)) { - // diagnostics have not changed, ignoring... - return - } - cleanup() - this.lastDiagnostics = updatedDiagnostics - resolve(updatedDiagnostics) - }) - - const cleanup = () => { - clearTimeout(timer) - disposable.dispose() - } - }) - } - - private getDiagnostics(): FileDiagnostics { - const allDiagnostics = vscode.languages.getDiagnostics() - return allDiagnostics - .filter(([_, diagnostics]) => diagnostics.some((d) => d.severity === vscode.DiagnosticSeverity.Error)) - .map(([uri, diagnostics]) => [ - uri, - diagnostics.filter((d) => d.severity === vscode.DiagnosticSeverity.Error), - ]) - } - - public dispose() { - this.disposables.forEach((d) => d.dispose()) - this.disposables = [] - this.diagnosticsChangeEmitter.dispose() - } -} - -export default DiagnosticsMonitor -*/ diff --git a/src/integrations/terminal/TerminalActions.ts b/src/integrations/terminal/TerminalActions.ts deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/src/integrations/workspace/get-python-env.ts b/src/integrations/workspace/get-python-env.ts deleted file mode 100644 index 92575b408ab..00000000000 --- a/src/integrations/workspace/get-python-env.ts +++ /dev/null @@ -1,42 +0,0 @@ -import * as vscode from "vscode" - -/* -Used to get user's current python environment (unnecessary now that we use the IDE's terminal) -${await (async () => { - try { - const pythonEnvPath = await getPythonEnvPath() - if (pythonEnvPath) { - return `\nPython Environment: ${pythonEnvPath}` - } - } catch {} - return "" - })()} -*/ -export async function getPythonEnvPath(): Promise { - const pythonExtension = vscode.extensions.getExtension("ms-python.python") - - if (!pythonExtension) { - return undefined - } - - // Ensure the Python extension is activated - if (!pythonExtension.isActive) { - // if the python extension is not active, we can assume the project is not a python project - return undefined - } - - // Access the Python extension API - const pythonApi = pythonExtension.exports - // Get the active environment path for the current workspace - const workspaceFolder = vscode.workspace.workspaceFolders?.[0] - if (!workspaceFolder) { - return undefined - } - // Get the active python environment path for the current workspace - const pythonEnv = await pythonApi?.environments?.getActiveEnvironmentPath(workspaceFolder.uri) - if (pythonEnv && pythonEnv.path) { - return pythonEnv.path - } else { - return undefined - } -} diff --git a/webview-ui/src/components/common/Demo.tsx b/webview-ui/src/components/common/Demo.tsx deleted file mode 100644 index 6efd7e34301..00000000000 --- a/webview-ui/src/components/common/Demo.tsx +++ /dev/null @@ -1,130 +0,0 @@ -import { - VSCodeBadge, - VSCodeButton, - VSCodeCheckbox, - VSCodeDataGrid, - VSCodeDataGridCell, - VSCodeDataGridRow, - VSCodeDivider, - VSCodeDropdown, - VSCodeLink, - VSCodeOption, - VSCodePanels, - VSCodePanelTab, - VSCodePanelView, - VSCodeProgressRing, - VSCodeRadio, - VSCodeRadioGroup, - VSCodeTag, - VSCodeTextArea, - VSCodeTextField, -} from "@vscode/webview-ui-toolkit/react" - -function Demo() { - // function handleHowdyClick() { - // vscode.postMessage({ - // command: "hello", - // text: "Hey there partner! 🤠", - // }) - // } - - const rowData = [ - { - cell1: "Cell Data", - cell2: "Cell Data", - cell3: "Cell Data", - cell4: "Cell Data", - }, - { - cell1: "Cell Data", - cell2: "Cell Data", - cell3: "Cell Data", - cell4: "Cell Data", - }, - { - cell1: "Cell Data", - cell2: "Cell Data", - cell3: "Cell Data", - cell4: "Cell Data", - }, - ] - - return ( -
-

Hello World!

- Howdy! - -
- - - - A Custom Header Title - - - Another Custom Title - - - Title Is Custom - - - Custom Title - - - {rowData.map((row, index) => ( - - {row.cell1} - {row.cell2} - {row.cell3} - {row.cell4} - - ))} - - - -
- - - - - - - - - -
-
- - - - - - Add - Remove - - - Badge - Checkbox - - - Option 1 - Option 2 - - Link - - Tab 1 - Tab 2 - Panel View 1 - Panel View 2 - - - Radio 1 - Radio 2 - - Tag - -
-
- ) -} - -export default Demo diff --git a/webview-ui/src/components/settings/TabNavbar.tsx b/webview-ui/src/components/settings/TabNavbar.tsx deleted file mode 100644 index cdf40c64d21..00000000000 --- a/webview-ui/src/components/settings/TabNavbar.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import { VSCodeButton } from "@vscode/webview-ui-toolkit/react" -import React, { useState } from "react" - -export const TAB_NAVBAR_HEIGHT = 24 -const BUTTON_MARGIN_RIGHT = "3px" -const LAST_BUTTON_MARGIN_RIGHT = "13px" - -type TabNavbarProps = { - onPlusClick: () => void - onHistoryClick: () => void - onSettingsClick: () => void -} - -type TooltipProps = { - text: string - isVisible: boolean - position: { x: number; y: number } - align?: "left" | "center" | "right" -} - -const Tooltip: React.FC = ({ text, isVisible, position, align = "center" }) => { - let leftPosition = position.x - let triangleStyle: React.CSSProperties = { - left: "50%", - marginLeft: "-5px", - } - - if (align === "right") { - leftPosition = position.x - 10 // Adjust this value as needed - triangleStyle = { - right: "10px", // Adjust this value to match the tooltip's right padding - marginLeft: "0", - } - } else if (align === "left") { - leftPosition = position.x + 10 // Adjust this value as needed - triangleStyle = { - left: "10px", // Adjust this value to match the tooltip's left padding - marginLeft: "0", - } - } - - return ( -
-
-
- {text} -
- ) -} - -const TabNavbar = ({ onPlusClick, onHistoryClick, onSettingsClick }: TabNavbarProps) => { - const [tooltip, setTooltip] = useState({ - text: "", - isVisible: false, - position: { x: 0, y: 0 }, - align: "center", - }) - - const showTooltip = (text: string, event: React.MouseEvent, align: "left" | "center" | "right" = "center") => { - const rect = event.currentTarget.getBoundingClientRect() - setTooltip({ - text, - isVisible: true, - position: { x: rect.left + rect.width / 2, y: rect.bottom + 7 }, - align, - }) - } - - const hideTooltip = () => { - setTooltip((prev) => ({ ...prev, isVisible: false })) - } - - const buttonStyle = { - marginRight: BUTTON_MARGIN_RIGHT, - } - - const lastButtonStyle = { - ...buttonStyle, - marginRight: LAST_BUTTON_MARGIN_RIGHT, - } - - return ( - <> -
- showTooltip("New Chat", e, "center")} - onMouseLeave={hideTooltip} - onMouseMove={(e) => showTooltip("New Chat", e, "center")}> - - - showTooltip("History", e, "center")} - onMouseLeave={hideTooltip} - onMouseMove={(e) => showTooltip("History", e, "center")}> - - - showTooltip("Settings", e, "right")} - onMouseLeave={hideTooltip} - onMouseMove={(e) => showTooltip("Settings", e, "right")}> - - -
- - - ) -} - -export default TabNavbar diff --git a/webview-ui/src/services/GitService.ts b/webview-ui/src/services/GitService.ts deleted file mode 100644 index 57a83e5ad93..00000000000 --- a/webview-ui/src/services/GitService.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { vscode } from "../utils/vscode" - -export interface GitCommit { - hash: string - shortHash: string - subject: string - author: string - date: string -} - -class GitService { - private commits: GitCommit[] | null = null - private lastQuery: string = "" - - async searchCommits(query: string = ""): Promise { - if (query === this.lastQuery && this.commits) { - return this.commits - } - - // Request search from extension - vscode.postMessage({ type: "searchCommits", query }) - - // Wait for response - const response = await new Promise((resolve) => { - const handler = (event: MessageEvent) => { - const message = event.data - if (message.type === "commitSearchResults") { - window.removeEventListener("message", handler) - resolve(message.commits) - } - } - window.addEventListener("message", handler) - }) - - this.commits = response - this.lastQuery = query - return response - } - - clearCache() { - this.commits = null - this.lastQuery = "" - } -} - -export const gitService = new GitService()