From 0ecdc626d884290abc7558f97006ceec0fe629e9 Mon Sep 17 00:00:00 2001 From: Manu K Date: Mon, 3 Nov 2025 12:08:59 +0530 Subject: [PATCH 1/4] feat: add Biome as the project linter and formatter - Install @biomejs/biome as dev dependency - Configure biome.json with TypeScript-friendly settings - Add .biomeignore to exclude build output and large files - Update package.json scripts to use Biome instead of ESLint - lint: biome check --write . - lint:check: biome check . - format: biome format --write . - format:check: biome format . - Update VS Code extensions.json to recommend Biome extension - Configure Biome to respect existing code style (2 spaces, double quotes) - Disable some rules that conflict with existing codebase (noConstEnum, noUselessConstructor) Biome provides faster linting and formatting compared to ESLint/Prettier with built-in TypeScript support and better performance. --- .biomeignore | 18 +++++ .vscode/extensions.json | 2 +- biome.json | 43 +++++++++++ package-lock.json | 164 ++++++++++++++++++++++++++++++++++++++++ package.json | 24 +++++- 5 files changed, 249 insertions(+), 2 deletions(-) create mode 100644 .biomeignore create mode 100644 biome.json diff --git a/.biomeignore b/.biomeignore new file mode 100644 index 0000000..5353a05 --- /dev/null +++ b/.biomeignore @@ -0,0 +1,18 @@ +# Build output +out/ +dist/ + +# Dependencies +node_modules/ + +# Type definitions +**/*.d.ts + +# Config files +webpack.config.js + +# VSCode settings +.vscode/ + +# Large files +src/encoder.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 57dbdae..60cc9b6 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,5 +1,5 @@ { // See http://go.microsoft.com/fwlink/?LinkId=827846 // for the documentation about the extensions.json format - "recommendations": ["dbaeumer.vscode-eslint", "amodio.tsl-problem-matcher"] + "recommendations": ["biomejs.biome", "amodio.tsl-problem-matcher"] } diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..65034f8 --- /dev/null +++ b/biome.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.3.2/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignoreUnknown": false, + "maxSize": 2097152 + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2, + "lineWidth": 100 + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "style": { + "useBlockStatements": "warn", + "noNonNullAssertion": "off" + }, + "suspicious": { + "noDoubleEquals": "warn", + "noExplicitAny": "off", + "noConstEnum": "off" + }, + "complexity": { + "noBannedTypes": "off", + "noUselessConstructor": "off" + } + } + }, + "javascript": { + "formatter": { + "quoteStyle": "double", + "semicolons": "always" + } + } +} diff --git a/package-lock.json b/package-lock.json index 73eb14d..d3908b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "simple-git": "^3.16.0" }, "devDependencies": { + "@biomejs/biome": "2.3.2", "@types/glob": "^8.0.0", "@types/mocha": "^10.0.1", "@types/node": "16.x", @@ -42,6 +43,169 @@ "node": ">=6.9.0" } }, + "node_modules/@biomejs/biome": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.2.tgz", + "integrity": "sha512-8e9tzamuDycx7fdrcJ/F/GDZ8SYukc5ud6tDicjjFqURKYFSWMl0H0iXNXZEGmcmNUmABgGuHThPykcM41INgg==", + "dev": true, + "license": "MIT OR Apache-2.0", + "bin": { + "biome": "bin/biome" + }, + "engines": { + "node": ">=14.21.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "2.3.2", + "@biomejs/cli-darwin-x64": "2.3.2", + "@biomejs/cli-linux-arm64": "2.3.2", + "@biomejs/cli-linux-arm64-musl": "2.3.2", + "@biomejs/cli-linux-x64": "2.3.2", + "@biomejs/cli-linux-x64-musl": "2.3.2", + "@biomejs/cli-win32-arm64": "2.3.2", + "@biomejs/cli-win32-x64": "2.3.2" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.2.tgz", + "integrity": "sha512-4LECm4kc3If0JISai4c3KWQzukoUdpxy4fRzlrPcrdMSRFksR9ZoXK7JBcPuLBmd2SoT4/d7CQS33VnZpgBjew==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.2.tgz", + "integrity": "sha512-jNMnfwHT4N3wi+ypRfMTjLGnDmKYGzxVr1EYAPBcauRcDnICFXN81wD6wxJcSUrLynoyyYCdfW6vJHS/IAoTDA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.2.tgz", + "integrity": "sha512-amnqvk+gWybbQleRRq8TMe0rIv7GHss8mFJEaGuEZYWg1Tw14YKOkeo8h6pf1c+d3qR+JU4iT9KXnBKGON4klw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.2.tgz", + "integrity": "sha512-2Zz4usDG1GTTPQnliIeNx6eVGGP2ry5vE/v39nT73a3cKN6t5H5XxjcEoZZh62uVZvED7hXXikclvI64vZkYqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.3.2.tgz", + "integrity": "sha512-8BG/vRAhFz1pmuyd24FQPhNeueLqPtwvZk6yblABY2gzL2H8fLQAF/Z2OPIc+BPIVPld+8cSiKY/KFh6k81xfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.2.tgz", + "integrity": "sha512-gzB19MpRdTuOuLtPpFBGrV3Lq424gHyq2lFj8wfX9tvLMLdmA/R9C7k/mqBp/spcbWuHeIEKgEs3RviOPcWGBA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.2.tgz", + "integrity": "sha512-lCruqQlfWjhMlOdyf5pDHOxoNm4WoyY2vZ4YN33/nuZBRstVDuqPPjS0yBkbUlLEte11FbpW+wWSlfnZfSIZvg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.2.tgz", + "integrity": "sha512-6Ee9P26DTb4D8sN9nXxgbi9Dw5vSOfH98M7UlmkjKB2vtUbrRqCbZiNfryGiwnPIpd6YUoTl7rLVD2/x1CyEHQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", "dev": true, diff --git a/package.json b/package.json index 1fc2af8..8e87ace 100644 --- a/package.json +++ b/package.json @@ -91,6 +91,24 @@ "configuration": { "type": "object", "properties": { + "diffy-explain-ai.aiServiceProvider": { + "type": "string", + "enum": [ + "openai", + "vscode-lm" + ], + "default": "openai", + "markdownDescription": "Select the AI service provider to use for generating commit messages. \n\n- **openai**: Use OpenAI API directly (requires API key)\n- **vscode-lm**: Use VS Code's built-in Language Model API (GitHub Copilot)" + }, + "diffy-explain-ai.vscodeLmModel": { + "type": "string", + "enum": [ + "copilot-gpt-4o", + "copilot-gpt-3.5-turbo" + ], + "default": "copilot-gpt-4o", + "markdownDescription": "Select the VS Code Language Model to use when `aiServiceProvider` is set to `vscode-lm`. Requires GitHub Copilot subscription." + }, "diffy-explain-ai.proxyUrl": { "type": "string", "default": "", @@ -130,10 +148,14 @@ "compile-tests": "tsc -p . --outDir out", "watch-tests": "tsc -p . -w --outDir out", "pretest": "pnpm run compile-tests && pnpm run compile && pnpm run lint", - "lint": "eslint src --ext ts", + "lint": "biome check --write .", + "lint:check": "biome check .", + "format": "biome format --write .", + "format:check": "biome format .", "test": "node ./out/test/runTest.js" }, "devDependencies": { + "@biomejs/biome": "2.3.2", "@types/glob": "^8.0.0", "@types/mocha": "^10.0.1", "@types/node": "16.x", From ae582b876dc91f9db4115a3060fba7d456d52d8a Mon Sep 17 00:00:00 2001 From: Manu K Date: Mon, 3 Nov 2025 12:12:45 +0530 Subject: [PATCH 2/4] feat: add type-check script and update VS Code engine requirement - Add 'type-check' npm script using 'tsc --noEmit' - Update @types/vscode from ^1.72.0 to ^1.90.0 for Language Model API support - Update VS Code engine requirement from ^1.72.1 to ^1.90.0 - Enables TypeScript type checking without emitting files - Ensures compatibility with newer VS Code APIs --- package-lock.json | 6 ++++-- package.json | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index d3908b8..944a997 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "@types/glob": "^8.0.0", "@types/mocha": "^10.0.1", "@types/node": "16.x", - "@types/vscode": "^1.72.0", + "@types/vscode": "^1.105.0", "@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/parser": "^5.45.0", "@vscode/test-electron": "^2.2.0", @@ -434,7 +434,9 @@ "license": "MIT" }, "node_modules/@types/vscode": { - "version": "1.74.0", + "version": "1.105.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.105.0.tgz", + "integrity": "sha512-Lotk3CTFlGZN8ray4VxJE7axIyLZZETQJVWi/lYoUVQuqfRxlQhVOfoejsD2V3dVXPSbS15ov5ZyowMAzgUqcw==", "dev": true, "license": "MIT" }, diff --git a/package.json b/package.json index 8e87ace..714fe20 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "version": "1.0.17", "publisher": "hitclaw", "engines": { - "vscode": "^1.72.1" + "vscode": "^1.90.0" }, "categories": [ "SCM Providers" @@ -148,6 +148,7 @@ "compile-tests": "tsc -p . --outDir out", "watch-tests": "tsc -p . -w --outDir out", "pretest": "pnpm run compile-tests && pnpm run compile && pnpm run lint", + "type-check": "tsc --noEmit", "lint": "biome check --write .", "lint:check": "biome check .", "format": "biome format --write .", @@ -159,7 +160,7 @@ "@types/glob": "^8.0.0", "@types/mocha": "^10.0.1", "@types/node": "16.x", - "@types/vscode": "^1.72.0", + "@types/vscode": "^1.105.0", "@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/parser": "^5.45.0", "@vscode/test-electron": "^2.2.0", From 051e9669ae8b455a0dfe879455ed8dffdeab052a Mon Sep 17 00:00:00 2001 From: Manu K Date: Mon, 3 Nov 2025 12:13:18 +0530 Subject: [PATCH 3/4] ci: add type-check to CI workflow - Add type-check step before lint in CI - Ensures TypeScript type errors are caught in CI/CD pipeline --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d1d5a35..efd624c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,5 +23,6 @@ jobs: node-version: ${{ matrix.node-version }} cache: "npm" - run: npm install + - run: npm run type-check - run: npm run lint - run: npm run compile From 0acf5d12d3d1c16c35165c4a9e614a0e45b084d4 Mon Sep 17 00:00:00 2001 From: Manu K Date: Mon, 3 Nov 2025 12:15:03 +0530 Subject: [PATCH 4/4] refactor: remove ESLint, use Biome exclusively - Uninstall eslint, @typescript-eslint/eslint-plugin, @typescript-eslint/parser - Remove .eslintrc.json configuration file - Remove eslint-disable comments from source files - Reduces dependencies from 353 to 283 packages (-70 packages) - Biome now handles all linting and formatting This completes the migration from ESLint to Biome. --- .eslintrc.json | 25 - package-lock.json | 859 +------------------------------- package.json | 3 - src/service/OpenAiService.ts | 1 - src/service/VsCodeLlmService.ts | 232 +++++++++ 5 files changed, 236 insertions(+), 884 deletions(-) delete mode 100644 .eslintrc.json create mode 100644 src/service/VsCodeLlmService.ts diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 3339bd5..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "root": true, - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": 6, - "sourceType": "module" - }, - "plugins": [ - "@typescript-eslint" - ], - "rules": { - "@typescript-eslint/naming-convention": "warn", - "@typescript-eslint/semi": "off", - "curly": "warn", - "eqeqeq": "warn", - "no-throw-literal": "warn", - "semi": "off", - "no-unexpected-multiline": "error" - }, - "ignorePatterns": [ - "out", - "dist", - "**/*.d.ts" - ] -} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 944a997..0a79ec5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,10 +19,7 @@ "@types/mocha": "^10.0.1", "@types/node": "16.x", "@types/vscode": "^1.105.0", - "@typescript-eslint/eslint-plugin": "^5.45.0", - "@typescript-eslint/parser": "^5.45.0", "@vscode/test-electron": "^2.2.0", - "eslint": "^8.28.0", "glob": "^8.0.3", "mocha": "^10.1.0", "ts-loader": "^9.4.1", @@ -31,7 +28,7 @@ "webpack-cli": "^5.0.0" }, "engines": { - "vscode": "^1.72.1" + "vscode": "^1.90.0" } }, "node_modules/@babel/runtime": { @@ -214,58 +211,6 @@ "node": ">=10.0.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "1.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.2", "dev": true, @@ -329,38 +274,6 @@ "version": "1.1.1", "license": "MIT" }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/@tootallnate/once": { "version": "1.1.2", "dev": true, @@ -428,11 +341,6 @@ "form-data": "^4.0.0" } }, - "node_modules/@types/semver": { - "version": "7.3.13", - "dev": true, - "license": "MIT" - }, "node_modules/@types/vscode": { "version": "1.105.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.105.0.tgz", @@ -440,185 +348,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.47.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/type-utils": "5.47.0", - "@typescript-eslint/utils": "5.47.0", - "debug": "^4.3.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.47.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/typescript-estree": "5.47.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.47.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.47.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "5.47.0", - "@typescript-eslint/utils": "5.47.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.47.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.47.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.47.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/typescript-estree": "5.47.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.47.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "5.47.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@vscode/test-electron": { "version": "2.2.1", "dev": true, @@ -844,14 +573,6 @@ "acorn": "^8" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, "node_modules/agent-base": { "version": "6.0.2", "dev": true, @@ -943,14 +664,6 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/array-union": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/asynckit": { "version": "0.4.0", "license": "MIT" @@ -1097,14 +810,6 @@ "node": ">= 0.4" } }, - "node_modules/callsites": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/camelcase": { "version": "6.3.0", "dev": true, @@ -1321,11 +1026,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "dev": true, - "license": "MIT" - }, "node_modules/delayed-stream": { "version": "1.0.0", "license": "MIT", @@ -1349,28 +1049,6 @@ "md5": "^2.3.0" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -1495,61 +1173,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint": { - "version": "8.30.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint/eslintrc": "^1.4.0", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/eslint-scope": { "version": "5.1.1", "dev": true, @@ -1562,94 +1185,6 @@ "node": ">=8.0.0" } }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/espree": { - "version": "9.4.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "dev": true, @@ -1677,14 +1212,6 @@ "node": ">=4.0" } }, - "node_modules/esutils": { - "version": "2.0.3", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/event-target-shim": { "version": "5.0.1", "license": "MIT", @@ -1701,43 +1228,12 @@ } }, "node_modules/fast-deep-equal": { - "version": "3.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "dev": true, - "license": "MIT", - "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" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", + "version": "3.1.3", "dev": true, "license": "MIT" }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", "dev": true, "license": "MIT" }, @@ -1749,25 +1245,6 @@ "node": ">= 4.9.1" } }, - "node_modules/fastq": { - "version": "1.14.0", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, "node_modules/fill-range": { "version": "7.0.1", "dev": true, @@ -1802,23 +1279,6 @@ "flat": "cli.js" } }, - "node_modules/flat-cache": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.7", - "dev": true, - "license": "ISC" - }, "node_modules/follow-redirects": { "version": "1.15.9", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", @@ -1990,17 +1450,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/glob-parent": { - "version": "6.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/glob-to-regexp": { "version": "0.4.1", "dev": true, @@ -2025,39 +1474,6 @@ "node": ">=10" } }, - "node_modules/globals": { - "version": "13.19.0", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -2075,11 +1491,6 @@ "dev": true, "license": "ISC" }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "dev": true, - "license": "MIT" - }, "node_modules/has": { "version": "1.0.3", "dev": true, @@ -2178,29 +1589,6 @@ "ms": "^2.0.0" } }, - "node_modules/ignore": { - "version": "5.2.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/import-local": { "version": "3.1.0", "dev": true, @@ -2219,14 +1607,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, "node_modules/inflight": { "version": "1.0.6", "dev": true, @@ -2310,14 +1690,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-obj": { "version": "2.1.0", "dev": true, @@ -2403,15 +1775,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/js-sdsl": { - "version": "4.2.0", - "dev": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, "node_modules/js-yaml": { "version": "4.1.0", "dev": true, @@ -2433,11 +1796,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, "node_modules/kind-of": { "version": "6.0.3", "dev": true, @@ -2446,18 +1804,6 @@ "node": ">=0.10.0" } }, - "node_modules/levn": { - "version": "0.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/listenercount": { "version": "1.0.1", "dev": true, @@ -2485,11 +1831,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "dev": true, - "license": "MIT" - }, "node_modules/log-symbols": { "version": "4.1.0", "dev": true, @@ -2539,14 +1880,6 @@ "dev": true, "license": "MIT" }, - "node_modules/merge2": { - "version": "1.4.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, "node_modules/micromatch": { "version": "4.0.5", "dev": true, @@ -2728,16 +2061,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/natural-compare": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, "node_modules/neo-async": { "version": "2.6.2", "dev": true, @@ -2820,22 +2143,6 @@ "version": "18.17.16", "license": "MIT" }, - "node_modules/optionator": { - "version": "0.9.1", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/p-limit": { "version": "3.1.0", "dev": true, @@ -2872,17 +2179,6 @@ "node": ">=6" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/path-exists": { "version": "4.0.0", "dev": true, @@ -2912,14 +2208,6 @@ "dev": true, "license": "MIT" }, - "node_modules/path-type": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/picocolors": { "version": "1.0.0", "dev": true, @@ -2995,14 +2283,6 @@ "node": ">=8" } }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/process-nextick-args": { "version": "2.0.1", "dev": true, @@ -3020,25 +2300,6 @@ "node": ">=6" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "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/randombytes": { "version": "2.1.0", "dev": true, @@ -3088,17 +2349,6 @@ "node": ">= 10.13.0" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/require-directory": { "version": "2.1.1", "dev": true, @@ -3142,23 +2392,6 @@ "node": ">=8" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, "node_modules/rimraf": { "version": "3.0.2", "dev": true, @@ -3192,28 +2425,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "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", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "dev": true, @@ -3320,14 +2531,6 @@ "url": "https://github.com/steveukx/git-js?sponsor=1" } }, - "node_modules/slash": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/source-map": { "version": "0.6.1", "dev": true, @@ -3473,11 +2676,6 @@ } } }, - "node_modules/text-table": { - "version": "0.2.0", - "dev": true, - "license": "MIT" - }, "node_modules/to-regex-range": { "version": "5.0.1", "dev": true, @@ -3516,47 +2714,6 @@ "webpack": "^5.0.0" } }, - "node_modules/tslib": { - "version": "1.14.1", - "dev": true, - "license": "0BSD" - }, - "node_modules/tsutils": { - "version": "3.21.0", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typescript": { "version": "4.9.4", "dev": true, @@ -3792,14 +2949,6 @@ "dev": true, "license": "MIT" }, - "node_modules/word-wrap": { - "version": "1.2.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/workerpool": { "version": "6.2.1", "dev": true, diff --git a/package.json b/package.json index 714fe20..10bbbc7 100644 --- a/package.json +++ b/package.json @@ -161,10 +161,7 @@ "@types/mocha": "^10.0.1", "@types/node": "16.x", "@types/vscode": "^1.105.0", - "@typescript-eslint/eslint-plugin": "^5.45.0", - "@typescript-eslint/parser": "^5.45.0", "@vscode/test-electron": "^2.2.0", - "eslint": "^8.28.0", "glob": "^8.0.3", "mocha": "^10.1.0", "ts-loader": "^9.4.1", diff --git a/src/service/OpenAiService.ts b/src/service/OpenAiService.ts index ac3a978..6e33fa1 100644 --- a/src/service/OpenAiService.ts +++ b/src/service/OpenAiService.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import OpenAI from "openai"; import * as vscode from "vscode"; import { window } from "vscode"; diff --git a/src/service/VsCodeLlmService.ts b/src/service/VsCodeLlmService.ts new file mode 100644 index 0000000..8733988 --- /dev/null +++ b/src/service/VsCodeLlmService.ts @@ -0,0 +1,232 @@ +import * as vscode from "vscode"; +import { window } from "vscode"; +import { clearOutput, sendToOutput } from "../utils/log"; +import { CacheService } from "./CacheService"; +import WorkspaceService from "./WorkspaceService"; + +class VsCodeLlmService implements AIService { + static _instance: VsCodeLlmService; + cacheService!: CacheService; + + constructor() { + if (VsCodeLlmService._instance) { + return VsCodeLlmService._instance; + } + this.cacheService = CacheService.getInstance(); + } + + /** + * Returns instance of the class + * @returns {VsCodeLlmService} The instance of the class. + */ + public static getInstance(): VsCodeLlmService { + if (!VsCodeLlmService._instance) { + VsCodeLlmService._instance = new VsCodeLlmService(); + } + return VsCodeLlmService._instance; + } + + /** + * It takes a git diff as input and returns a commit message as output using VS Code's LLM API + * @param {string} code - The diff of the files that are being committed. + * @param {boolean} nameOnly - Whether the diff is name-only + * @param {vscode.Progress} progress - Optional progress reporter + * @returns A string or null + */ + async getCommitMessageFromDiff( + code: string, + nameOnly?: boolean, + progress?: vscode.Progress<{ + message?: string | undefined; + increment?: number | undefined; + }> + ): Promise { + const instructions = WorkspaceService.getInstance().getAIInstructions(); + if (!instructions) { + return null; + } + + const response = await this.getFromVsCodeLlm( + instructions, + code, + progress + ); + + if (response) { + let message = response.trim(); + message = message.replace(/^"/gm, ""); + message = message.replace(/"$/gm, ""); + return message; + } + return null; + } + + /** + * It takes a string of code, sends it to VS Code LLM, gets a response, and returns a string of the response. + * @param {string} string1 - the first parameter (instructions or code context) + * @param {string} string2 - the second parameter (diff code) + * @returns The explanation of the git diff. + */ + async getExplainedChanges( + string1: string, + string2: string + ): Promise { + const instructions = + "You are a bot that explains the changes from the result of 'git diff --cached' that user given. commit message should be a multiple lines where first line doesn't exceed '50' characters by following commit message guidelines based on the given git diff changes without mentioning itself"; + + // Use string2 as the code/diff, string1 is typically instructions but we use our own + const response = await this.getFromVsCodeLlm(instructions, string2); + + if (response) { + let message = response.trim(); + message = message.replace(/^"/gm, ""); + message = message.replace(/"$/gm, ""); + return message; + } + return null; + } + + /** + * Makes a request to VS Code's Language Model API + * @param {string} instructions - The system instructions + * @param {string} prompt - The user prompt + * @param {vscode.Progress} progress - Optional progress reporter + * @returns {Promise} + */ + private async getFromVsCodeLlm( + instructions: string, + prompt: string, + progress?: vscode.Progress<{ + message?: string | undefined; + increment?: number | undefined; + }> + ): Promise { + const vscodeLmModel = WorkspaceService.getInstance().getVsCodeLmModel(); + + // Check cache + const cacheKey = instructions + prompt; + const exist = this.cacheService.recordExists(vscodeLmModel, cacheKey); + if (exist) { + const result = this.cacheService.get(vscodeLmModel, cacheKey) as string; + sendToOutput(`result (cached): ${result}`); + return result; + } + + try { + clearOutput(); + sendToOutput(`instructions: ${instructions}`); + sendToOutput(`git diff prompt: ${prompt}`); + sendToOutput(`model: ${vscodeLmModel}`); + + // Select the appropriate model based on settings + let models: vscode.LanguageModelChat[] = []; + + if (vscodeLmModel === "copilot-gpt-4o") { + models = await vscode.lm.selectChatModels({ + vendor: "copilot", + family: "gpt-4o" + }); + } else if (vscodeLmModel === "copilot-gpt-3.5-turbo") { + models = await vscode.lm.selectChatModels({ + vendor: "copilot", + family: "gpt-3.5-turbo" + }); + } else { + // Default: try to select any copilot model + models = await vscode.lm.selectChatModels({ + vendor: "copilot" + }); + } + + if (models.length === 0) { + window.showErrorMessage( + "No language models available. Please ensure GitHub Copilot is installed and you are signed in." + ); + progress?.report({ + increment: 1, + message: "\nFailed - No models available.", + }); + return undefined; + } + + const [model] = models; + sendToOutput(`Selected model: ${model.id} (${model.vendor}/${model.family})`); + + progress?.report({ increment: 30 }); + + // Prepare messages + const messages = [ + vscode.LanguageModelChatMessage.User(instructions), + vscode.LanguageModelChatMessage.User(prompt), + ]; + + // Send request + const chatResponse = await model.sendRequest( + messages, + {}, + new vscode.CancellationTokenSource().token + ); + + progress?.report({ increment: 40 }); + + // Collect the response + let responseText = ""; + for await (const fragment of chatResponse.text) { + responseText += fragment; + } + + sendToOutput(`result success: ${responseText}`); + + // Cache the result + if (responseText && responseText.length > 6) { + this.cacheService.set(vscodeLmModel, cacheKey, responseText); + } + + progress?.report({ + increment: 30, + message: "\nCommit message generated.", + }); + + await new Promise((f) => setTimeout(f, 200)); + + return responseText; + } catch (error: any) { + console.error(error); + sendToOutput(`result failed: ${JSON.stringify(error)}`); + + if (error instanceof vscode.LanguageModelError) { + // Handle specific LLM errors + let errorMessage = "VS Code Language Model Error: "; + + switch (error.code) { + case vscode.LanguageModelError.NotFound().code: + errorMessage += "Model not found. Please ensure GitHub Copilot is installed."; + break; + case vscode.LanguageModelError.NoPermissions().code: + errorMessage += "No permissions to use the language model. Please sign in to GitHub Copilot."; + break; + case vscode.LanguageModelError.Blocked().code: + errorMessage += "Request was blocked. The prompt may violate content policies."; + break; + default: + errorMessage += error.message; + } + + window.showErrorMessage(errorMessage); + } else { + window.showErrorMessage( + `Diffy Error: Failed to generate commit message. ${error.message || "Unknown error"}` + ); + } + + progress?.report({ + increment: 1, + message: "\nFailed.", + }); + + return undefined; + } + } +} + +export default VsCodeLlmService;