craftcommit-cli 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js ADDED
@@ -0,0 +1,262 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import chalk from 'chalk';
4
+ import ora from 'ora';
5
+ import inquirer from 'inquirer';
6
+ import clipboardy from 'clipboardy';
7
+ import { simpleGit } from 'simple-git';
8
+ import { loadConfig, saveConfig, getApiKey, getDefaultModel } from './config.js';
9
+ import { generateCommitMessages, formatCommitMessage } from './ai.js';
10
+ const VERSION = '0.3.0';
11
+ const git = simpleGit();
12
+ async function getStagedDiff() {
13
+ const [diff, fileSummary] = await Promise.all([
14
+ git.diff(['--cached']),
15
+ git.diff(['--cached', '--name-status'])
16
+ ]);
17
+ return { diff, fileSummary };
18
+ }
19
+ async function hasStagedChanges() {
20
+ const diff = await git.diff(['--cached', '--name-only']);
21
+ return diff.trim().length > 0;
22
+ }
23
+ async function getCurrentBranch() {
24
+ const branchSummary = await git.branch();
25
+ return branchSummary.current;
26
+ }
27
+ function extractIssueFromBranch(branchName, pattern) {
28
+ if (!pattern)
29
+ return null;
30
+ try {
31
+ const regex = new RegExp(pattern);
32
+ const match = branchName.match(regex);
33
+ return match?.[1] || match?.[0] || null;
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ async function generateCommand(options) {
40
+ const config = loadConfig();
41
+ // Override config with CLI options
42
+ const provider = options.provider || config.provider;
43
+ const model = options.model || config.model || getDefaultModel(provider);
44
+ const language = options.language || config.language;
45
+ // Check for API key
46
+ const apiKey = getApiKey({ ...config, provider });
47
+ if (!apiKey) {
48
+ console.error(chalk.red(`\nNo API key found for ${provider}.`));
49
+ console.log(chalk.yellow(`\nSet your API key:`));
50
+ console.log(chalk.gray(` Environment: OPENAI_API_KEY, GROQ_API_KEY, or GEMINI_API_KEY`));
51
+ console.log(chalk.gray(` Config file: ~/.commitcraftrc`));
52
+ console.log(chalk.gray(` Or run: commitcraft config\n`));
53
+ process.exit(1);
54
+ }
55
+ // Check for staged changes
56
+ const hasChanges = await hasStagedChanges();
57
+ if (!hasChanges) {
58
+ console.log(chalk.yellow('\nNo staged changes found.'));
59
+ console.log(chalk.gray('Stage files with: git add <files>\n'));
60
+ process.exit(1);
61
+ }
62
+ // Get diff
63
+ const spinner = ora('Getting staged changes...').start();
64
+ let diff;
65
+ let fileSummary;
66
+ try {
67
+ const result = await getStagedDiff();
68
+ diff = result.diff;
69
+ fileSummary = result.fileSummary;
70
+ if (!diff.trim()) {
71
+ spinner.fail('No diff content found');
72
+ process.exit(1);
73
+ }
74
+ // Truncate large diffs
75
+ const MAX_CHARS = 12000;
76
+ if (diff.length > MAX_CHARS) {
77
+ diff = diff.substring(0, MAX_CHARS) + '\n... [truncated]';
78
+ }
79
+ spinner.succeed('Got staged changes');
80
+ }
81
+ catch (error) {
82
+ spinner.fail('Failed to get staged changes');
83
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
84
+ process.exit(1);
85
+ }
86
+ // Extract issue from branch if pattern is configured
87
+ let issueReference;
88
+ if (options.issuePattern) {
89
+ try {
90
+ const branchName = await getCurrentBranch();
91
+ const issue = extractIssueFromBranch(branchName, options.issuePattern);
92
+ if (issue) {
93
+ issueReference = (options.issuePrefix || '') + issue;
94
+ console.log(chalk.blue(`\nDetected issue: ${issueReference}`));
95
+ }
96
+ }
97
+ catch {
98
+ // Ignore branch detection errors
99
+ }
100
+ }
101
+ // Generate commit messages
102
+ const generateSpinner = ora(`Generating commit messages via ${provider}...`).start();
103
+ let candidates;
104
+ try {
105
+ candidates = await generateCommitMessages(provider, apiKey, diff, fileSummary, model, language, config.ollamaUrl, issueReference);
106
+ generateSpinner.succeed('Generated commit messages');
107
+ }
108
+ catch (error) {
109
+ generateSpinner.fail('Failed to generate commit messages');
110
+ const message = error instanceof Error ? error.message : String(error);
111
+ if (message.includes('401') || message.includes('Unauthorized')) {
112
+ console.error(chalk.red(`\nInvalid ${provider} API key.`));
113
+ }
114
+ else if (message.includes('ECONNREFUSED')) {
115
+ console.error(chalk.red(`\nCannot connect to Ollama at ${config.ollamaUrl}`));
116
+ }
117
+ else {
118
+ console.error(chalk.red(`\n${message}`));
119
+ }
120
+ process.exit(1);
121
+ }
122
+ // Format choices for inquirer
123
+ const choices = candidates.map((commit, index) => ({
124
+ name: `${index + 1}. ${formatCommitMessage(commit)}`,
125
+ value: commit
126
+ }));
127
+ choices.push({
128
+ name: chalk.gray('Cancel'),
129
+ value: null
130
+ });
131
+ // Let user select a message
132
+ console.log();
133
+ const { selected } = await inquirer.prompt([
134
+ {
135
+ type: 'list',
136
+ name: 'selected',
137
+ message: 'Select a commit message:',
138
+ choices
139
+ }
140
+ ]);
141
+ if (!selected) {
142
+ console.log(chalk.yellow('\nCancelled.'));
143
+ process.exit(0);
144
+ }
145
+ const commitMessage = formatCommitMessage(selected);
146
+ if (options.commit) {
147
+ // Auto-commit
148
+ const commitSpinner = ora('Committing...').start();
149
+ try {
150
+ await git.commit(commitMessage);
151
+ commitSpinner.succeed(chalk.green(`Committed: ${commitMessage}`));
152
+ }
153
+ catch (error) {
154
+ commitSpinner.fail('Failed to commit');
155
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
156
+ process.exit(1);
157
+ }
158
+ }
159
+ else {
160
+ // Copy to clipboard
161
+ try {
162
+ await clipboardy.write(commitMessage);
163
+ console.log(chalk.green(`\n✓ Copied to clipboard: ${commitMessage}`));
164
+ }
165
+ catch {
166
+ // Clipboard might not work in all environments
167
+ console.log(chalk.green(`\n✓ Selected: ${commitMessage}`));
168
+ console.log(chalk.gray('(Copy manually if clipboard is not available)'));
169
+ }
170
+ }
171
+ }
172
+ async function configCommand() {
173
+ console.log(chalk.bold('\nCommitCraft CLI Configuration\n'));
174
+ const { provider } = await inquirer.prompt([
175
+ {
176
+ type: 'list',
177
+ name: 'provider',
178
+ message: 'Select AI provider:',
179
+ choices: [
180
+ { name: 'OpenAI', value: 'openai' },
181
+ { name: 'Groq', value: 'groq' },
182
+ { name: 'Gemini', value: 'gemini' },
183
+ { name: 'Ollama (local)', value: 'ollama' }
184
+ ]
185
+ }
186
+ ]);
187
+ let apiKey;
188
+ if (provider !== 'ollama') {
189
+ const { key } = await inquirer.prompt([
190
+ {
191
+ type: 'password',
192
+ name: 'key',
193
+ message: `Enter your ${provider} API key:`,
194
+ mask: '*'
195
+ }
196
+ ]);
197
+ apiKey = key;
198
+ }
199
+ const { language } = await inquirer.prompt([
200
+ {
201
+ type: 'list',
202
+ name: 'language',
203
+ message: 'Select language for commit messages:',
204
+ choices: [
205
+ { name: 'English', value: 'english' },
206
+ { name: 'Korean', value: 'korean' }
207
+ ]
208
+ }
209
+ ]);
210
+ const { model } = await inquirer.prompt([
211
+ {
212
+ type: 'input',
213
+ name: 'model',
214
+ message: 'Model (leave empty for default):',
215
+ default: getDefaultModel(provider)
216
+ }
217
+ ]);
218
+ const configToSave = {
219
+ provider,
220
+ language,
221
+ model
222
+ };
223
+ if (apiKey) {
224
+ const keyName = `${provider}ApiKey`;
225
+ configToSave[keyName] = apiKey;
226
+ }
227
+ if (provider === 'ollama') {
228
+ const { ollamaUrl } = await inquirer.prompt([
229
+ {
230
+ type: 'input',
231
+ name: 'ollamaUrl',
232
+ message: 'Ollama URL:',
233
+ default: 'http://localhost:11434'
234
+ }
235
+ ]);
236
+ configToSave.ollamaUrl = ollamaUrl;
237
+ }
238
+ saveConfig(configToSave);
239
+ console.log(chalk.green('\n✓ Configuration saved to ~/.commitcraftrc\n'));
240
+ }
241
+ // Main CLI
242
+ const program = new Command();
243
+ program
244
+ .name('commitcraft')
245
+ .description('Generate AI-powered commit messages')
246
+ .version(VERSION);
247
+ program
248
+ .command('generate', { isDefault: true })
249
+ .description('Generate commit message from staged changes')
250
+ .option('-p, --provider <provider>', 'AI provider (openai, groq, gemini, ollama)')
251
+ .option('-m, --model <model>', 'Model to use')
252
+ .option('-l, --language <language>', 'Language (english, korean)')
253
+ .option('-c, --commit', 'Auto-commit with selected message')
254
+ .option('--issue-pattern <pattern>', 'Regex to extract issue from branch name')
255
+ .option('--issue-prefix <prefix>', 'Prefix for issue reference (e.g., #)')
256
+ .action(generateCommand);
257
+ program
258
+ .command('config')
259
+ .description('Configure API keys and preferences')
260
+ .action(configCommand);
261
+ program.parse();
262
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export type Provider = 'openai' | 'groq' | 'gemini' | 'ollama';
2
+ export type Language = 'english' | 'korean';
3
+ export interface Config {
4
+ provider: Provider;
5
+ model: string;
6
+ language: Language;
7
+ ollamaUrl: string;
8
+ openaiApiKey?: string;
9
+ groqApiKey?: string;
10
+ geminiApiKey?: string;
11
+ }
12
+ export declare function loadConfig(): Config;
13
+ export declare function saveConfig(config: Partial<Config>): void;
14
+ export declare function getApiKey(config: Config): string | undefined;
15
+ export declare function getDefaultModel(provider: Provider): string;
16
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAC/D,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE5C,MAAM,WAAW,MAAM;IACrB,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAmDD,wBAAgB,UAAU,IAAI,MAAM,CAenC;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAcxD;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAa5D;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAE1D"}
package/dist/config.js ADDED
@@ -0,0 +1,94 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import dotenv from 'dotenv';
5
+ const CONFIG_FILE = '.commitcraftrc';
6
+ const CONFIG_PATH = path.join(os.homedir(), CONFIG_FILE);
7
+ const DEFAULT_MODELS = {
8
+ openai: 'gpt-4o-mini',
9
+ groq: 'llama-3.1-8b-instant',
10
+ gemini: 'gemini-1.5-flash',
11
+ ollama: 'llama3.2'
12
+ };
13
+ function loadEnvFile() {
14
+ // Load from current directory .env first
15
+ const localEnv = path.join(process.cwd(), '.env');
16
+ if (fs.existsSync(localEnv)) {
17
+ dotenv.config({ path: localEnv });
18
+ }
19
+ // Then load from home directory
20
+ const homeEnv = path.join(os.homedir(), '.env');
21
+ if (fs.existsSync(homeEnv)) {
22
+ dotenv.config({ path: homeEnv });
23
+ }
24
+ }
25
+ function loadConfigFile() {
26
+ // Check local config first
27
+ const localConfig = path.join(process.cwd(), CONFIG_FILE);
28
+ if (fs.existsSync(localConfig)) {
29
+ try {
30
+ const content = fs.readFileSync(localConfig, 'utf-8');
31
+ return JSON.parse(content);
32
+ }
33
+ catch {
34
+ // Ignore parse errors
35
+ }
36
+ }
37
+ // Then check home directory
38
+ if (fs.existsSync(CONFIG_PATH)) {
39
+ try {
40
+ const content = fs.readFileSync(CONFIG_PATH, 'utf-8');
41
+ return JSON.parse(content);
42
+ }
43
+ catch {
44
+ // Ignore parse errors
45
+ }
46
+ }
47
+ return {};
48
+ }
49
+ export function loadConfig() {
50
+ loadEnvFile();
51
+ const fileConfig = loadConfigFile();
52
+ const provider = (process.env.COMMITCRAFT_PROVIDER || fileConfig.provider || 'openai');
53
+ return {
54
+ provider,
55
+ model: process.env.COMMITCRAFT_MODEL || fileConfig.model || DEFAULT_MODELS[provider],
56
+ language: (process.env.COMMITCRAFT_LANGUAGE || fileConfig.language || 'english'),
57
+ ollamaUrl: process.env.OLLAMA_URL || fileConfig.ollamaUrl || 'http://localhost:11434',
58
+ openaiApiKey: process.env.OPENAI_API_KEY || fileConfig.openaiApiKey,
59
+ groqApiKey: process.env.GROQ_API_KEY || fileConfig.groqApiKey,
60
+ geminiApiKey: process.env.GEMINI_API_KEY || fileConfig.geminiApiKey
61
+ };
62
+ }
63
+ export function saveConfig(config) {
64
+ let existingConfig = {};
65
+ if (fs.existsSync(CONFIG_PATH)) {
66
+ try {
67
+ const content = fs.readFileSync(CONFIG_PATH, 'utf-8');
68
+ existingConfig = JSON.parse(content);
69
+ }
70
+ catch {
71
+ // Ignore parse errors
72
+ }
73
+ }
74
+ const newConfig = { ...existingConfig, ...config };
75
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify(newConfig, null, 2));
76
+ }
77
+ export function getApiKey(config) {
78
+ switch (config.provider) {
79
+ case 'openai':
80
+ return config.openaiApiKey;
81
+ case 'groq':
82
+ return config.groqApiKey;
83
+ case 'gemini':
84
+ return config.geminiApiKey;
85
+ case 'ollama':
86
+ return 'ollama-no-key-needed';
87
+ default:
88
+ return undefined;
89
+ }
90
+ }
91
+ export function getDefaultModel(provider) {
92
+ return DEFAULT_MODELS[provider];
93
+ }
94
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "craftcommit-cli",
3
+ "version": "0.3.0",
4
+ "description": "Generate AI-powered commit messages from terminal",
5
+ "author": "youngsikkk",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/youngsikkk/ai-commit-msg"
10
+ },
11
+ "keywords": [
12
+ "git",
13
+ "commit",
14
+ "ai",
15
+ "openai",
16
+ "groq",
17
+ "gemini",
18
+ "ollama",
19
+ "conventional-commits",
20
+ "cli"
21
+ ],
22
+ "bin": {
23
+ "commitcraft": "./dist/cli.js"
24
+ },
25
+ "main": "./dist/cli.js",
26
+ "type": "module",
27
+ "scripts": {
28
+ "build": "tsc",
29
+ "dev": "tsc --watch",
30
+ "prepublishOnly": "npm run build",
31
+ "start": "node ./dist/cli.js"
32
+ },
33
+ "engines": {
34
+ "node": ">=18.0.0"
35
+ },
36
+ "dependencies": {
37
+ "@google/generative-ai": "^0.24.1",
38
+ "chalk": "^5.3.0",
39
+ "clipboardy": "^4.0.0",
40
+ "commander": "^12.1.0",
41
+ "dotenv": "^16.4.5",
42
+ "inquirer": "^9.3.7",
43
+ "openai": "^4.73.0",
44
+ "ora": "^8.1.1",
45
+ "simple-git": "^3.30.0"
46
+ },
47
+ "devDependencies": {
48
+ "@types/inquirer": "^9.0.7",
49
+ "@types/node": "^22.0.0",
50
+ "typescript": "^5.9.3"
51
+ }
52
+ }