diff --git a/package-lock.json b/package-lock.json index af28478..0c7f110 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,21 @@ { "name": "gitbun", - "version": "1.12.1", + "version": "1.15.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "gitbun", - "version": "1.12.1", + "version": "1.15.0", "license": "MIT", "dependencies": { + "@anthropic-ai/sdk": "^0.115.0", "chalk": "^5.6.2", "commander": "^14.0.3", "cosmiconfig": "^9.0.0", "inquirer": "^13.2.4", "node-fetch": "^3.3.2", + "openai": "^6.49.0", "ora": "^9.3.0", "simple-git": "^3.31.1", "ts-morph": "^28.0.0" @@ -95,6 +97,27 @@ "dev": true, "license": "MIT" }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.115.0", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.115.0.tgz", + "integrity": "sha512-BJrFIVyjNuU8lfDyIJTvlRYzgQg+zEl78BxE7fq8esULsGz9IRQvGtW5spq3tydmtjQb/GFdooKGdGsetpx+lQ==", + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "^3.1.1", + "standardwebhooks": "^1.0.0" + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, "node_modules/@babel/code-frame": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", @@ -118,6 +141,15 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -2433,6 +2465,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@stablelib/base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", + "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==", + "license": "MIT" + }, "node_modules/@standard-schema/spec": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", @@ -2522,7 +2560,7 @@ "version": "25.9.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.0.tgz", "integrity": "sha512-AOQwYUNolgy3VosiRqXrACUXTN8nJUtPl7FJXMqZVyxiiCLhQuG3jXKvCS1ALr+Y2OmZhzzLVlYPEqJaiqkaJQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "undici-types": ">=7.24.0 <7.24.7" @@ -4288,6 +4326,12 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-sha256": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz", + "integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==", + "license": "Unlicense" + }, "node_modules/fast-string-truncated-width": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", @@ -5152,6 +5196,19 @@ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "license": "MIT" }, + "node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -7750,6 +7807,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openai": { + "version": "6.49.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.49.0.tgz", + "integrity": "sha512-aYCc0C6L864eR6WSYIwQGyXriw/nIyZx0ObvhzOEVuk0zoBDpynjSbrionWI7q65B5H8jJX0DXR9snEzM6bfPg==", + "license": "Apache-2.0", + "peerDependencies": { + "@aws-sdk/credential-provider-node": ">=3.972.0 <4", + "@smithy/hash-node": ">=4.3.0 <5", + "@smithy/signature-v4": ">=5.4.0 <6", + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-provider-node": { + "optional": true + }, + "@smithy/hash-node": { + "optional": true + }, + "@smithy/signature-v4": { + "optional": true + }, + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -9247,6 +9334,16 @@ "dev": true, "license": "MIT" }, + "node_modules/standardwebhooks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.0.0.tgz", + "integrity": "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==", + "license": "MIT", + "dependencies": { + "@stablelib/base64": "^1.0.0", + "fast-sha256": "^1.3.0" + } + }, "node_modules/std-env": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", @@ -9583,6 +9680,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "license": "MIT" + }, "node_modules/ts-api-utils": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", @@ -9696,7 +9799,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -9758,7 +9861,7 @@ "version": "7.24.6", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/unicode-emoji-modifier-base": { diff --git a/package.json b/package.json index c1bd43b..c2a6471 100644 --- a/package.json +++ b/package.json @@ -33,11 +33,13 @@ "node": ">=20" }, "dependencies": { + "@anthropic-ai/sdk": "^0.115.0", "chalk": "^5.6.2", "commander": "^14.0.3", "cosmiconfig": "^9.0.0", "inquirer": "^13.2.4", "node-fetch": "^3.3.2", + "openai": "^6.49.0", "ora": "^9.3.0", "simple-git": "^3.31.1", "ts-morph": "^28.0.0" diff --git a/src/config/loadConfig.ts b/src/config/loadConfig.ts index 3ac90fc..c86774a 100644 --- a/src/config/loadConfig.ts +++ b/src/config/loadConfig.ts @@ -5,6 +5,10 @@ export interface GitbunConfig { customPrompt?: string; format?: string; model?: string; + ai?: boolean; + interactive?: boolean; + provider?: 'ollama' | 'openai' | 'anthropic'; // add this + apiKey?: string; } /** Loads and returns user config from .gitbunrc or cosmiconfig. */ diff --git a/src/providers/anthropic.provider.ts b/src/providers/anthropic.provider.ts new file mode 100644 index 0000000..57543fe --- /dev/null +++ b/src/providers/anthropic.provider.ts @@ -0,0 +1,20 @@ +import Anthropic from '@anthropic-ai/sdk'; + +export class AnthropicProvider { + private client: Anthropic; + private model: string; + + constructor(apiKey: string, model = 'claude-haiku-4-5') { + this.client = new Anthropic({ apiKey }); + this.model = model; + } + + async generateCommitMessage(diff: string, prompt: string): Promise { + const response = await this.client.messages.create({ + model: this.model, + max_tokens: 200, + messages: [{ role: 'user', content: `${prompt}\n\nGit diff:\n\`\`\`\n${diff}\n\`\`\`` }], + }); + return (response.content[0] as { text: string }).text.trim(); + } +} \ No newline at end of file diff --git a/src/providers/openai.provider.ts b/src/providers/openai.provider.ts new file mode 100644 index 0000000..a510ab5 --- /dev/null +++ b/src/providers/openai.provider.ts @@ -0,0 +1,24 @@ +import OpenAI from 'openai'; + +export class OpenAIProvider { + private client: OpenAI; + private model: string; + + constructor(apiKey: string, model = 'gpt-4o-mini') { + this.client = new OpenAI({ apiKey }); + this.model = model; + } + + async generateCommitMessage(diff: string, prompt: string): Promise { + const response = await this.client.chat.completions.create({ + model: this.model, + messages: [ + { role: 'system', content: prompt }, + { role: 'user', content: `Git diff:\n\`\`\`\n${diff}\n\`\`\`` }, + ], + max_tokens: 200, + temperature: 0.3, + }); + return response.choices[0].message.content?.trim() ?? ''; + } +} \ No newline at end of file