@dongowu/git-ai-cli 1.0.2 → 1.0.6
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/README.md +127 -0
- package/dist/cli.js +73 -3
- package/dist/cli.js.map +1 -1
- package/dist/commands/commit.d.ts +6 -1
- package/dist/commands/commit.d.ts.map +1 -1
- package/dist/commands/commit.js +113 -22
- package/dist/commands/commit.js.map +1 -1
- package/dist/commands/hook.d.ts +2 -0
- package/dist/commands/hook.d.ts.map +1 -0
- package/dist/commands/hook.js +296 -0
- package/dist/commands/hook.js.map +1 -0
- package/dist/commands/msg.d.ts +18 -0
- package/dist/commands/msg.d.ts.map +1 -0
- package/dist/commands/msg.js +103 -0
- package/dist/commands/msg.js.map +1 -0
- package/package.json +8 -2
- package/scripts/release.sh +34 -0
package/README.md
CHANGED
|
@@ -69,6 +69,9 @@ git-ai
|
|
|
69
69
|
| 🏠 **本地部署** | 支持 Ollama、LM Studio,数据不出本机 |
|
|
70
70
|
| 🔍 **智能 Diff** | 自动过滤 lock 文件,Token 优化截断 |
|
|
71
71
|
| 💬 **交互式** | 提交 / 编辑 / 重新生成 / 取消 |
|
|
72
|
+
| ⚡ **一键提交** | `-y` 参数跳过确认,CI/CD 友好 |
|
|
73
|
+
| 🎯 **多条候选** | `-n 3` 生成多条消息供选择 |
|
|
74
|
+
| 🪝 **Git Hook** | 自动集成到 git commit 流程 |
|
|
72
75
|
| 📝 **规范化** | 遵循 Conventional Commits 标准 |
|
|
73
76
|
| 🌍 **中英双语** | 支持中文和英文输出 |
|
|
74
77
|
|
|
@@ -124,6 +127,91 @@ git-ai config
|
|
|
124
127
|
|
|
125
128
|
## 🔧 高级功能
|
|
126
129
|
|
|
130
|
+
### 命令结构
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
git-ai # 交互式生成并提交(默认)
|
|
134
|
+
git-ai commit # 同上,显式提交命令
|
|
135
|
+
git-ai msg # 仅生成消息,输出到 stdout(供脚本/Hook 使用)
|
|
136
|
+
git-ai config # 配置 AI 服务商
|
|
137
|
+
git-ai hook # 管理 Git Hook
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 命令行选项
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# 一键提交(跳过确认,CI/CD 友好)
|
|
144
|
+
git-ai -y
|
|
145
|
+
git-ai --yes
|
|
146
|
+
|
|
147
|
+
# 生成多条候选消息
|
|
148
|
+
git-ai -n 3
|
|
149
|
+
git-ai --num 3
|
|
150
|
+
|
|
151
|
+
# 组合使用
|
|
152
|
+
git-ai -y -n 3 # 生成 3 条,自动选择第一条提交
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### `git-ai msg` - 脚本友好模式
|
|
156
|
+
|
|
157
|
+
专为 Hook 和脚本设计,仅输出 commit message:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# 纯文本输出
|
|
161
|
+
git-ai msg
|
|
162
|
+
|
|
163
|
+
# JSON 格式输出(含元数据)
|
|
164
|
+
git-ai msg --json
|
|
165
|
+
|
|
166
|
+
# 静默模式(无 spinner)
|
|
167
|
+
git-ai msg --quiet
|
|
168
|
+
|
|
169
|
+
# 生成多条
|
|
170
|
+
git-ai msg -n 3
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
JSON 输出示例:
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"success": true,
|
|
177
|
+
"message": "feat(auth): add OAuth2 login support",
|
|
178
|
+
"metadata": {
|
|
179
|
+
"stagedFiles": ["src/auth.ts", "src/login.ts"],
|
|
180
|
+
"truncated": false,
|
|
181
|
+
"ignoredFiles": ["package-lock.json"]
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Git Hook 集成
|
|
187
|
+
|
|
188
|
+
自动集成到 `git commit` 流程,无需手动运行 `git-ai`:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# 安装 hook
|
|
192
|
+
git-ai hook install
|
|
193
|
+
|
|
194
|
+
# 查看状态
|
|
195
|
+
git-ai hook status
|
|
196
|
+
|
|
197
|
+
# 移除 hook
|
|
198
|
+
git-ai hook remove
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Hook 特性:**
|
|
202
|
+
- **链式执行**:如果已有 `prepare-commit-msg` hook,git-ai 会作为 wrapper 执行,原 hook 仍会运行
|
|
203
|
+
- **递归保护**:通过环境变量防止 hook 递归调用
|
|
204
|
+
- **智能跳过**:使用 `-m` 参数或 merge/amend 时自动跳过
|
|
205
|
+
|
|
206
|
+
安装后,直接运行 `git commit`(不带 `-m`)会自动生成 commit message:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
git add .
|
|
210
|
+
git commit # 自动调用 git-ai msg 生成消息
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
> 💡 跳过 hook: `git commit --no-verify`
|
|
214
|
+
|
|
127
215
|
### 自动忽略的文件
|
|
128
216
|
|
|
129
217
|
以下文件会自动从 Diff 分析中排除,避免浪费 Token:
|
|
@@ -166,8 +254,47 @@ git-ai
|
|
|
166
254
|
- **Local deployment**: Ollama, LM Studio - keep your data private
|
|
167
255
|
- **Smart diff**: Auto-filter lock files, token optimization
|
|
168
256
|
- **Interactive**: Commit / Edit / Regenerate / Cancel
|
|
257
|
+
- **One-click commit**: `-y` flag for CI/CD pipelines
|
|
258
|
+
- **Multiple choices**: `-n 3` to generate multiple options
|
|
259
|
+
- **Git Hook**: Auto-integrate with `git commit`
|
|
169
260
|
- **Conventional Commits**: Standard commit message format
|
|
170
261
|
|
|
262
|
+
### Commands
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
git-ai # Interactive commit (default)
|
|
266
|
+
git-ai commit # Same as above, explicit command
|
|
267
|
+
git-ai msg # Generate message only (stdout, for scripts/hooks)
|
|
268
|
+
git-ai config # Configure AI provider
|
|
269
|
+
git-ai hook # Manage Git hooks
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### CLI Options
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
# Auto commit (skip confirmation)
|
|
276
|
+
git-ai -y
|
|
277
|
+
|
|
278
|
+
# Generate multiple choices
|
|
279
|
+
git-ai -n 3
|
|
280
|
+
|
|
281
|
+
# Script-friendly message generation
|
|
282
|
+
git-ai msg # Plain text output
|
|
283
|
+
git-ai msg --json # JSON output with metadata
|
|
284
|
+
git-ai msg --quiet # No spinner
|
|
285
|
+
|
|
286
|
+
# Git Hook management
|
|
287
|
+
git-ai hook install # Install hook (chains with existing hooks)
|
|
288
|
+
git-ai hook remove # Remove hook
|
|
289
|
+
git-ai hook status # Check status
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Git Hook Features
|
|
293
|
+
|
|
294
|
+
- **Hook chaining**: Works alongside existing `prepare-commit-msg` hooks
|
|
295
|
+
- **Recursion protection**: Prevents infinite loops via environment variable
|
|
296
|
+
- **Smart skip**: Skips when using `-m`, merge, or amend
|
|
297
|
+
|
|
171
298
|
### Workflow
|
|
172
299
|
|
|
173
300
|
```
|
package/dist/cli.js
CHANGED
|
@@ -4,14 +4,29 @@ import chalk from 'chalk';
|
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
5
|
import { runConfig } from './commands/config.js';
|
|
6
6
|
import { runCommit } from './commands/commit.js';
|
|
7
|
+
import { runMsg } from './commands/msg.js';
|
|
8
|
+
import { runHook } from './commands/hook.js';
|
|
7
9
|
const require = createRequire(import.meta.url);
|
|
8
10
|
const pkg = require('../package.json');
|
|
9
11
|
const cli = cac('git-ai');
|
|
12
|
+
// Default command (backward compatible) - interactive commit
|
|
10
13
|
cli
|
|
11
|
-
.command('', 'Generate AI-powered commit message')
|
|
12
|
-
.
|
|
14
|
+
.command('', 'Generate AI-powered commit message (interactive)')
|
|
15
|
+
.option('-y, --yes', 'Skip confirmation and commit directly')
|
|
16
|
+
.option('-n, --num <count>', 'Generate multiple commit messages to choose from', { default: 1 })
|
|
17
|
+
.option('--hook', '[deprecated] Use `git-ai msg` instead')
|
|
18
|
+
.action(async (options) => {
|
|
13
19
|
try {
|
|
14
|
-
|
|
20
|
+
// Deprecated --hook redirects to msg command behavior
|
|
21
|
+
if (options.hook) {
|
|
22
|
+
const { runMsg } = await import('./commands/msg.js');
|
|
23
|
+
await runMsg({ quiet: true });
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
await runCommit({
|
|
27
|
+
autoCommit: options.yes ?? false,
|
|
28
|
+
numChoices: Math.min(Math.max(Number(options.num) || 1, 1), 5),
|
|
29
|
+
});
|
|
15
30
|
}
|
|
16
31
|
catch (error) {
|
|
17
32
|
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
@@ -19,6 +34,49 @@ cli
|
|
|
19
34
|
process.exit(1);
|
|
20
35
|
}
|
|
21
36
|
});
|
|
37
|
+
// Explicit commit subcommand
|
|
38
|
+
cli
|
|
39
|
+
.command('commit', 'Generate and commit with AI message (interactive)')
|
|
40
|
+
.option('-y, --yes', 'Skip confirmation and commit directly')
|
|
41
|
+
.option('-n, --num <count>', 'Generate multiple commit messages to choose from', { default: 1 })
|
|
42
|
+
.action(async (options) => {
|
|
43
|
+
try {
|
|
44
|
+
await runCommit({
|
|
45
|
+
autoCommit: options.yes ?? false,
|
|
46
|
+
numChoices: Math.min(Math.max(Number(options.num) || 1, 1), 5),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
51
|
+
console.error(chalk.red(`\n❌ Error: ${message}\n`));
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
// Message-only command (for hooks and scripts)
|
|
56
|
+
cli
|
|
57
|
+
.command('msg', 'Generate commit message only (stdout, for hooks/scripts)')
|
|
58
|
+
.option('-n, --num <count>', 'Generate multiple messages', { default: 1 })
|
|
59
|
+
.option('--json', 'Output as JSON')
|
|
60
|
+
.option('--quiet', 'Suppress spinner and colors')
|
|
61
|
+
.action(async (options) => {
|
|
62
|
+
try {
|
|
63
|
+
await runMsg({
|
|
64
|
+
num: Math.min(Math.max(Number(options.num) || 1, 1), 5),
|
|
65
|
+
json: options.json ?? false,
|
|
66
|
+
quiet: options.quiet ?? false,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (options.json) {
|
|
71
|
+
console.log(JSON.stringify({ success: false, error: String(error) }));
|
|
72
|
+
}
|
|
73
|
+
else if (!options.quiet) {
|
|
74
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
75
|
+
console.error(chalk.red(`\n❌ Error: ${message}\n`));
|
|
76
|
+
}
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
22
80
|
cli
|
|
23
81
|
.command('config', 'Configure AI provider settings')
|
|
24
82
|
.action(async () => {
|
|
@@ -31,6 +89,18 @@ cli
|
|
|
31
89
|
process.exit(1);
|
|
32
90
|
}
|
|
33
91
|
});
|
|
92
|
+
cli
|
|
93
|
+
.command('hook <action>', 'Manage Git hooks (install/remove/status)')
|
|
94
|
+
.action(async (action) => {
|
|
95
|
+
try {
|
|
96
|
+
await runHook(action);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
100
|
+
console.error(chalk.red(`\n❌ Error: ${message}\n`));
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
34
104
|
cli.help();
|
|
35
105
|
cli.version(pkg.version || '0.0.0');
|
|
36
106
|
cli.parse();
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
export
|
|
1
|
+
export interface CommitOptions {
|
|
2
|
+
autoCommit?: boolean;
|
|
3
|
+
numChoices?: number;
|
|
4
|
+
hookMode?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function runCommit(options?: CommitOptions): Promise<void>;
|
|
2
7
|
//# sourceMappingURL=commit.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commit.d.ts","sourceRoot":"","sources":["../../src/commands/commit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"commit.d.ts","sourceRoot":"","sources":["../../src/commands/commit.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAYD,wBAAsB,SAAS,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmJ1E"}
|
package/dist/commands/commit.js
CHANGED
|
@@ -4,48 +4,97 @@ import ora from 'ora';
|
|
|
4
4
|
import { getConfig } from '../utils/config.js';
|
|
5
5
|
import { isGitInstalled, isInGitRepo, getStagedFiles, getFilteredDiff, commit, } from '../utils/git.js';
|
|
6
6
|
import { createAIClient, generateCommitMessage, } from '../utils/ai.js';
|
|
7
|
-
function exitWithError(message, hint) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
function exitWithError(message, hint, silent = false) {
|
|
8
|
+
if (!silent) {
|
|
9
|
+
console.error(chalk.red(`❌ ${message}`));
|
|
10
|
+
if (hint) {
|
|
11
|
+
console.log(chalk.gray(` ${hint}`));
|
|
12
|
+
}
|
|
11
13
|
}
|
|
12
14
|
process.exit(1);
|
|
13
15
|
}
|
|
14
|
-
export async function runCommit() {
|
|
16
|
+
export async function runCommit(options = {}) {
|
|
17
|
+
const { autoCommit = false, numChoices = 1, hookMode = false } = options;
|
|
18
|
+
// Recursion guard - prevent hook from triggering another git-ai
|
|
19
|
+
if (process.env.GIT_AI_RUNNING === '1') {
|
|
20
|
+
if (!hookMode) {
|
|
21
|
+
console.log(chalk.yellow('⚠️ git-ai is already running (recursion prevented)'));
|
|
22
|
+
}
|
|
23
|
+
process.exit(0);
|
|
24
|
+
}
|
|
25
|
+
process.env.GIT_AI_RUNNING = '1';
|
|
15
26
|
// Environment checks
|
|
16
27
|
if (!(await isGitInstalled())) {
|
|
17
|
-
exitWithError('Git is not installed. Please install git first.');
|
|
28
|
+
exitWithError('Git is not installed. Please install git first.', undefined, hookMode);
|
|
18
29
|
}
|
|
19
30
|
if (!(await isInGitRepo())) {
|
|
20
|
-
exitWithError('Not in a git repository.');
|
|
31
|
+
exitWithError('Not in a git repository.', undefined, hookMode);
|
|
21
32
|
}
|
|
22
33
|
const stagedFiles = await getStagedFiles();
|
|
23
34
|
if (stagedFiles.length === 0) {
|
|
24
|
-
exitWithError('No staged changes found.', 'Use `git add <files>` to stage your changes first.');
|
|
35
|
+
exitWithError('No staged changes found.', 'Use `git add <files>` to stage your changes first.', hookMode);
|
|
25
36
|
}
|
|
26
37
|
// Check config
|
|
27
38
|
const config = getConfig();
|
|
28
39
|
if (!config) {
|
|
29
40
|
exitWithError('Configuration not found.', 'Run `git-ai config` to set up your AI provider.');
|
|
30
41
|
}
|
|
31
|
-
// Show staged files
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
// Show staged files (skip in hook mode)
|
|
43
|
+
if (!hookMode) {
|
|
44
|
+
console.log(chalk.cyan('\n📁 Staged files:'));
|
|
45
|
+
stagedFiles.forEach((file) => {
|
|
46
|
+
console.log(chalk.gray(` ${file}`));
|
|
47
|
+
});
|
|
48
|
+
}
|
|
36
49
|
// Get filtered diff
|
|
37
50
|
const { diff, truncated, ignoredFiles } = await getFilteredDiff(stagedFiles);
|
|
38
|
-
if (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
if (!hookMode) {
|
|
52
|
+
if (ignoredFiles.length > 0) {
|
|
53
|
+
const preview = ignoredFiles.slice(0, 8).join(', ');
|
|
54
|
+
const more = ignoredFiles.length > 8 ? ` (+${ignoredFiles.length - 8} more)` : '';
|
|
55
|
+
console.log(chalk.gray(`\n🧹 Ignored from diff (token optimization): ${preview}${more}`));
|
|
56
|
+
}
|
|
57
|
+
if (truncated) {
|
|
58
|
+
console.log(chalk.yellow('\n⚠️ Diff was truncated due to size limits.'));
|
|
59
|
+
}
|
|
45
60
|
}
|
|
46
61
|
// Create AI client
|
|
47
62
|
const client = createAIClient(config);
|
|
48
|
-
|
|
63
|
+
const input = { diff, stagedFiles, ignoredFiles, truncated };
|
|
64
|
+
// Generate commit message(s)
|
|
65
|
+
let commitMessage;
|
|
66
|
+
if (hookMode) {
|
|
67
|
+
// Hook mode: silent generation, output only the message
|
|
68
|
+
try {
|
|
69
|
+
commitMessage = await generateCommitMessage(client, input, config);
|
|
70
|
+
console.log(commitMessage);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (numChoices > 1) {
|
|
78
|
+
// Generate multiple choices
|
|
79
|
+
const messages = await generateMultipleWithSpinner(client, input, config, numChoices);
|
|
80
|
+
if (autoCommit) {
|
|
81
|
+
// Auto mode: use first message
|
|
82
|
+
commitMessage = messages[0];
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
commitMessage = await selectFromChoices(messages);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
commitMessage = await generateWithSpinner(client, input, config);
|
|
90
|
+
}
|
|
91
|
+
// Auto commit mode
|
|
92
|
+
if (autoCommit) {
|
|
93
|
+
console.log(chalk.green('\n✨ Generated commit message:\n'));
|
|
94
|
+
console.log(chalk.white.bold(` ${commitMessage.split('\n').join('\n ')}`));
|
|
95
|
+
await performCommit(commitMessage);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
49
98
|
// Interactive loop
|
|
50
99
|
while (true) {
|
|
51
100
|
console.log(chalk.green('\n✨ Generated commit message:\n'));
|
|
@@ -84,7 +133,13 @@ export async function runCommit() {
|
|
|
84
133
|
}
|
|
85
134
|
}
|
|
86
135
|
else if (action === 'regenerate') {
|
|
87
|
-
|
|
136
|
+
if (numChoices > 1) {
|
|
137
|
+
const messages = await generateMultipleWithSpinner(client, input, config, numChoices);
|
|
138
|
+
commitMessage = await selectFromChoices(messages);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
commitMessage = await generateWithSpinner(client, input, config);
|
|
142
|
+
}
|
|
88
143
|
}
|
|
89
144
|
else {
|
|
90
145
|
console.log(chalk.gray('\n👋 Commit cancelled.\n'));
|
|
@@ -92,6 +147,23 @@ export async function runCommit() {
|
|
|
92
147
|
}
|
|
93
148
|
}
|
|
94
149
|
}
|
|
150
|
+
async function selectFromChoices(messages) {
|
|
151
|
+
if (messages.length === 1) {
|
|
152
|
+
return messages[0];
|
|
153
|
+
}
|
|
154
|
+
const { selected } = await inquirer.prompt([
|
|
155
|
+
{
|
|
156
|
+
type: 'list',
|
|
157
|
+
name: 'selected',
|
|
158
|
+
message: 'Select a commit message:',
|
|
159
|
+
choices: messages.map((msg, i) => ({
|
|
160
|
+
name: `${i + 1}. ${msg.split('\n')[0]}`,
|
|
161
|
+
value: msg,
|
|
162
|
+
})),
|
|
163
|
+
},
|
|
164
|
+
]);
|
|
165
|
+
return selected;
|
|
166
|
+
}
|
|
95
167
|
async function generateWithSpinner(client, input, config) {
|
|
96
168
|
const spinner = ora({
|
|
97
169
|
text: 'Generating commit message...',
|
|
@@ -108,6 +180,25 @@ async function generateWithSpinner(client, input, config) {
|
|
|
108
180
|
exitWithError(errorMessage);
|
|
109
181
|
}
|
|
110
182
|
}
|
|
183
|
+
async function generateMultipleWithSpinner(client, input, config, count) {
|
|
184
|
+
const spinner = ora({
|
|
185
|
+
text: `Generating ${count} commit messages...`,
|
|
186
|
+
color: 'cyan',
|
|
187
|
+
}).start();
|
|
188
|
+
try {
|
|
189
|
+
const promises = Array.from({ length: count }, () => generateCommitMessage(client, input, config));
|
|
190
|
+
const messages = await Promise.all(promises);
|
|
191
|
+
// Dedupe
|
|
192
|
+
const unique = [...new Set(messages)];
|
|
193
|
+
spinner.succeed(`Generated ${unique.length} commit message(s)!`);
|
|
194
|
+
return unique;
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
spinner.fail('Failed to generate commit messages');
|
|
198
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
199
|
+
exitWithError(errorMessage);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
111
202
|
async function performCommit(message) {
|
|
112
203
|
const spinner = ora({
|
|
113
204
|
text: 'Creating commit...',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commit.js","sourceRoot":"","sources":["../../src/commands/commit.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EACL,cAAc,EACd,WAAW,EACX,cAAc,EACd,eAAe,EACf,MAAM,GACP,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,cAAc,EACd,qBAAqB,GAEtB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"commit.js","sourceRoot":"","sources":["../../src/commands/commit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../src/commands/hook.ts"],"names":[],"mappings":"AA6KA,wBAAsB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB3D"}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { execa } from 'execa';
|
|
3
|
+
import { existsSync, readFileSync, writeFileSync, unlinkSync, chmodSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
const HOOK_NAME = 'prepare-commit-msg';
|
|
6
|
+
const HOOK_MARKER = '# git-ai-hook-start';
|
|
7
|
+
const HOOK_END_MARKER = '# git-ai-hook-end';
|
|
8
|
+
// Hook script with all protections
|
|
9
|
+
const HOOK_SCRIPT = `#!/bin/sh
|
|
10
|
+
${HOOK_MARKER}
|
|
11
|
+
# git-ai hook - auto-generate commit message
|
|
12
|
+
# To disable: git commit --no-verify
|
|
13
|
+
|
|
14
|
+
COMMIT_MSG_FILE="$1"
|
|
15
|
+
COMMIT_SOURCE="$2"
|
|
16
|
+
|
|
17
|
+
# Recursion guard
|
|
18
|
+
if [ "$GIT_AI_RUNNING" = "1" ]; then
|
|
19
|
+
exit 0
|
|
20
|
+
fi
|
|
21
|
+
export GIT_AI_RUNNING=1
|
|
22
|
+
|
|
23
|
+
# Only run for regular commits (not merge, squash, amend, etc.)
|
|
24
|
+
if [ -n "$COMMIT_SOURCE" ]; then
|
|
25
|
+
exit 0
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# Check if there's already a non-comment message
|
|
29
|
+
if [ -s "$COMMIT_MSG_FILE" ]; then
|
|
30
|
+
EXISTING_MSG=$(grep -v "^#" "$COMMIT_MSG_FILE" | grep -v "^$" | head -1)
|
|
31
|
+
if [ -n "$EXISTING_MSG" ]; then
|
|
32
|
+
exit 0
|
|
33
|
+
fi
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Generate commit message using git-ai msg
|
|
37
|
+
if command -v git-ai >/dev/null 2>&1; then
|
|
38
|
+
MSG=$(git-ai msg --quiet 2>/dev/null)
|
|
39
|
+
EXIT_CODE=$?
|
|
40
|
+
|
|
41
|
+
if [ $EXIT_CODE -eq 0 ] && [ -n "$MSG" ]; then
|
|
42
|
+
# Preserve existing comments, prepend AI message
|
|
43
|
+
if [ -f "$COMMIT_MSG_FILE" ]; then
|
|
44
|
+
COMMENTS=$(grep "^#" "$COMMIT_MSG_FILE" || true)
|
|
45
|
+
printf '%s\\n\\n%s\\n' "$MSG" "$COMMENTS" > "$COMMIT_MSG_FILE"
|
|
46
|
+
else
|
|
47
|
+
printf '%s\\n' "$MSG" > "$COMMIT_MSG_FILE"
|
|
48
|
+
fi
|
|
49
|
+
fi
|
|
50
|
+
fi
|
|
51
|
+
${HOOK_END_MARKER}
|
|
52
|
+
|
|
53
|
+
`;
|
|
54
|
+
// Wrapper template for chaining with existing hook
|
|
55
|
+
const WRAPPER_TEMPLATE = `#!/bin/sh
|
|
56
|
+
${HOOK_MARKER}
|
|
57
|
+
# git-ai hook wrapper - chains with existing hook
|
|
58
|
+
# To disable: git commit --no-verify
|
|
59
|
+
|
|
60
|
+
COMMIT_MSG_FILE="$1"
|
|
61
|
+
COMMIT_SOURCE="$2"
|
|
62
|
+
SHA1="$3"
|
|
63
|
+
|
|
64
|
+
# Recursion guard
|
|
65
|
+
if [ "$GIT_AI_RUNNING" = "1" ]; then
|
|
66
|
+
# Still call original hook if exists
|
|
67
|
+
if [ -x "__ORIGINAL_HOOK__" ]; then
|
|
68
|
+
"__ORIGINAL_HOOK__" "$COMMIT_MSG_FILE" "$COMMIT_SOURCE" "$SHA1"
|
|
69
|
+
fi
|
|
70
|
+
exit $?
|
|
71
|
+
fi
|
|
72
|
+
export GIT_AI_RUNNING=1
|
|
73
|
+
|
|
74
|
+
# Only run for regular commits
|
|
75
|
+
if [ -n "$COMMIT_SOURCE" ]; then
|
|
76
|
+
# Still call original hook
|
|
77
|
+
if [ -x "__ORIGINAL_HOOK__" ]; then
|
|
78
|
+
"__ORIGINAL_HOOK__" "$COMMIT_MSG_FILE" "$COMMIT_SOURCE" "$SHA1"
|
|
79
|
+
fi
|
|
80
|
+
exit $?
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# Check if there's already a non-comment message
|
|
84
|
+
if [ -s "$COMMIT_MSG_FILE" ]; then
|
|
85
|
+
EXISTING_MSG=$(grep -v "^#" "$COMMIT_MSG_FILE" | grep -v "^$" | head -1)
|
|
86
|
+
if [ -n "$EXISTING_MSG" ]; then
|
|
87
|
+
# Still call original hook
|
|
88
|
+
if [ -x "__ORIGINAL_HOOK__" ]; then
|
|
89
|
+
"__ORIGINAL_HOOK__" "$COMMIT_MSG_FILE" "$COMMIT_SOURCE" "$SHA1"
|
|
90
|
+
fi
|
|
91
|
+
exit $?
|
|
92
|
+
fi
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
# Generate commit message using git-ai msg
|
|
96
|
+
if command -v git-ai >/dev/null 2>&1; then
|
|
97
|
+
MSG=$(git-ai msg --quiet 2>/dev/null)
|
|
98
|
+
EXIT_CODE=$?
|
|
99
|
+
|
|
100
|
+
if [ $EXIT_CODE -eq 0 ] && [ -n "$MSG" ]; then
|
|
101
|
+
if [ -f "$COMMIT_MSG_FILE" ]; then
|
|
102
|
+
COMMENTS=$(grep "^#" "$COMMIT_MSG_FILE" || true)
|
|
103
|
+
printf '%s\\n\\n%s\\n' "$MSG" "$COMMENTS" > "$COMMIT_MSG_FILE"
|
|
104
|
+
else
|
|
105
|
+
printf '%s\\n' "$MSG" > "$COMMIT_MSG_FILE"
|
|
106
|
+
fi
|
|
107
|
+
fi
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
# Call original hook
|
|
111
|
+
if [ -x "__ORIGINAL_HOOK__" ]; then
|
|
112
|
+
"__ORIGINAL_HOOK__" "$COMMIT_MSG_FILE" "$COMMIT_SOURCE" "$SHA1"
|
|
113
|
+
exit $?
|
|
114
|
+
fi
|
|
115
|
+
${HOOK_END_MARKER}
|
|
116
|
+
|
|
117
|
+
exit 0
|
|
118
|
+
`;
|
|
119
|
+
async function getGitHooksPath() {
|
|
120
|
+
try {
|
|
121
|
+
// Check if custom hooks path is configured
|
|
122
|
+
const { stdout } = await execa('git', ['config', '--get', 'core.hooksPath']);
|
|
123
|
+
return stdout.trim();
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// Default to .git/hooks
|
|
127
|
+
const { stdout } = await execa('git', ['rev-parse', '--git-dir']);
|
|
128
|
+
return join(stdout.trim(), 'hooks');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function isInGitRepo() {
|
|
132
|
+
try {
|
|
133
|
+
await execa('git', ['rev-parse', '--is-inside-work-tree']);
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function isGitAiHook(content) {
|
|
141
|
+
return content.includes(HOOK_MARKER) || content.includes('git-ai');
|
|
142
|
+
}
|
|
143
|
+
function hasOtherHookContent(content) {
|
|
144
|
+
// Remove git-ai hook section and check if there's other content
|
|
145
|
+
const lines = content.split('\n');
|
|
146
|
+
let inGitAiSection = false;
|
|
147
|
+
const otherLines = [];
|
|
148
|
+
for (const line of lines) {
|
|
149
|
+
if (line.includes(HOOK_MARKER)) {
|
|
150
|
+
inGitAiSection = true;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (line.includes(HOOK_END_MARKER)) {
|
|
154
|
+
inGitAiSection = false;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (!inGitAiSection) {
|
|
158
|
+
// Skip shebang and empty lines
|
|
159
|
+
if (!line.startsWith('#!') && line.trim() !== '') {
|
|
160
|
+
otherLines.push(line);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return otherLines.some(line => !line.startsWith('#') && line.trim() !== '');
|
|
165
|
+
}
|
|
166
|
+
export async function runHook(action) {
|
|
167
|
+
if (!['install', 'remove', 'status'].includes(action)) {
|
|
168
|
+
console.error(chalk.red(`❌ Unknown action: ${action}`));
|
|
169
|
+
console.log(chalk.gray(' Available actions: install, remove, status'));
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
if (!(await isInGitRepo())) {
|
|
173
|
+
console.error(chalk.red('❌ Not in a git repository.'));
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
const hooksPath = await getGitHooksPath();
|
|
177
|
+
const hookFile = join(hooksPath, HOOK_NAME);
|
|
178
|
+
if (action === 'status') {
|
|
179
|
+
await showStatus(hookFile);
|
|
180
|
+
}
|
|
181
|
+
else if (action === 'install') {
|
|
182
|
+
await installHook(hookFile, hooksPath);
|
|
183
|
+
}
|
|
184
|
+
else if (action === 'remove') {
|
|
185
|
+
await removeHook(hookFile);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
async function showStatus(hookFile) {
|
|
189
|
+
if (existsSync(hookFile)) {
|
|
190
|
+
const content = readFileSync(hookFile, 'utf-8');
|
|
191
|
+
if (isGitAiHook(content)) {
|
|
192
|
+
console.log(chalk.green('✅ git-ai hook is installed'));
|
|
193
|
+
console.log(chalk.gray(` Location: ${hookFile}`));
|
|
194
|
+
// Check if it's a wrapper
|
|
195
|
+
const originalHook = `${hookFile}.original`;
|
|
196
|
+
if (existsSync(originalHook)) {
|
|
197
|
+
console.log(chalk.cyan(' Mode: Wrapper (chained with original hook)'));
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
console.log(chalk.cyan(' Mode: Standalone'));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
console.log(chalk.yellow('⚠️ A prepare-commit-msg hook exists but is not from git-ai'));
|
|
205
|
+
console.log(chalk.gray(` Location: ${hookFile}`));
|
|
206
|
+
console.log(chalk.gray(' Run `git-ai hook install` to add git-ai (will chain with existing hook)'));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
console.log(chalk.gray('❌ git-ai hook is not installed'));
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async function installHook(hookFile, hooksPath) {
|
|
214
|
+
// Ensure hooks directory exists
|
|
215
|
+
if (!existsSync(hooksPath)) {
|
|
216
|
+
await execa('mkdir', ['-p', hooksPath]);
|
|
217
|
+
}
|
|
218
|
+
// Check if hook already exists
|
|
219
|
+
if (existsSync(hookFile)) {
|
|
220
|
+
const content = readFileSync(hookFile, 'utf-8');
|
|
221
|
+
if (isGitAiHook(content)) {
|
|
222
|
+
// Already has git-ai, update it
|
|
223
|
+
console.log(chalk.yellow('⚠️ git-ai hook already installed, updating...'));
|
|
224
|
+
// Check if there's an original hook
|
|
225
|
+
const originalHook = `${hookFile}.original`;
|
|
226
|
+
if (existsSync(originalHook)) {
|
|
227
|
+
// Re-create wrapper with updated script
|
|
228
|
+
const wrapper = WRAPPER_TEMPLATE.replace(/__ORIGINAL_HOOK__/g, originalHook);
|
|
229
|
+
writeFileSync(hookFile, wrapper);
|
|
230
|
+
chmodSync(hookFile, 0o755);
|
|
231
|
+
console.log(chalk.green('✅ git-ai hook updated (wrapper mode)'));
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
writeFileSync(hookFile, HOOK_SCRIPT);
|
|
235
|
+
chmodSync(hookFile, 0o755);
|
|
236
|
+
console.log(chalk.green('✅ git-ai hook updated'));
|
|
237
|
+
}
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
// Existing non-git-ai hook - use wrapper mode
|
|
241
|
+
const originalHook = `${hookFile}.original`;
|
|
242
|
+
// Backup original
|
|
243
|
+
writeFileSync(originalHook, content);
|
|
244
|
+
chmodSync(originalHook, 0o755);
|
|
245
|
+
console.log(chalk.gray(` Original hook saved to: ${originalHook}`));
|
|
246
|
+
// Install wrapper
|
|
247
|
+
const wrapper = WRAPPER_TEMPLATE.replace(/__ORIGINAL_HOOK__/g, originalHook);
|
|
248
|
+
writeFileSync(hookFile, wrapper);
|
|
249
|
+
chmodSync(hookFile, 0o755);
|
|
250
|
+
console.log(chalk.green('✅ git-ai hook installed (wrapper mode)'));
|
|
251
|
+
console.log(chalk.cyan(' Your original hook will still be executed after git-ai'));
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
// No existing hook - install standalone
|
|
255
|
+
writeFileSync(hookFile, HOOK_SCRIPT);
|
|
256
|
+
chmodSync(hookFile, 0o755);
|
|
257
|
+
console.log(chalk.green('✅ git-ai hook installed'));
|
|
258
|
+
}
|
|
259
|
+
console.log(chalk.gray(` Location: ${hookFile}`));
|
|
260
|
+
console.log('');
|
|
261
|
+
console.log(chalk.cyan('📝 How it works:'));
|
|
262
|
+
console.log(chalk.gray(' When you run `git commit` without -m flag,'));
|
|
263
|
+
console.log(chalk.gray(' git-ai will auto-generate a commit message.'));
|
|
264
|
+
console.log('');
|
|
265
|
+
console.log(chalk.cyan('💡 Tips:'));
|
|
266
|
+
console.log(chalk.gray(' • Skip hook: git commit --no-verify'));
|
|
267
|
+
console.log(chalk.gray(' • Remove hook: git-ai hook remove'));
|
|
268
|
+
}
|
|
269
|
+
async function removeHook(hookFile) {
|
|
270
|
+
if (!existsSync(hookFile)) {
|
|
271
|
+
console.log(chalk.gray('❌ No hook to remove'));
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const content = readFileSync(hookFile, 'utf-8');
|
|
275
|
+
if (!isGitAiHook(content)) {
|
|
276
|
+
console.log(chalk.yellow('⚠️ The existing hook is not from git-ai, skipping removal'));
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
// Check for original hook
|
|
280
|
+
const originalHook = `${hookFile}.original`;
|
|
281
|
+
if (existsSync(originalHook)) {
|
|
282
|
+
// Restore original hook
|
|
283
|
+
const originalContent = readFileSync(originalHook, 'utf-8');
|
|
284
|
+
writeFileSync(hookFile, originalContent);
|
|
285
|
+
chmodSync(hookFile, 0o755);
|
|
286
|
+
unlinkSync(originalHook);
|
|
287
|
+
console.log(chalk.green('✅ git-ai hook removed'));
|
|
288
|
+
console.log(chalk.gray(' Original hook restored'));
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
// Just remove the hook
|
|
292
|
+
unlinkSync(hookFile);
|
|
293
|
+
console.log(chalk.green('✅ git-ai hook removed'));
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
//# sourceMappingURL=hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.js","sourceRoot":"","sources":["../../src/commands/hook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface MsgOptions {
|
|
2
|
+
json?: boolean;
|
|
3
|
+
quiet?: boolean;
|
|
4
|
+
num?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface MsgResult {
|
|
7
|
+
success: boolean;
|
|
8
|
+
message?: string;
|
|
9
|
+
messages?: string[];
|
|
10
|
+
error?: string;
|
|
11
|
+
metadata?: {
|
|
12
|
+
stagedFiles: string[];
|
|
13
|
+
truncated: boolean;
|
|
14
|
+
ignoredFiles: string[];
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export declare function runMsg(options?: MsgOptions): Promise<void>;
|
|
18
|
+
//# sourceMappingURL=msg.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"msg.d.ts","sourceRoot":"","sources":["../../src/commands/msg.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE;QACT,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,SAAS,EAAE,OAAO,CAAC;QACnB,YAAY,EAAE,MAAM,EAAE,CAAC;KACxB,CAAC;CACH;AAYD,wBAAsB,MAAM,CAAC,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAmGpE"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { getConfig } from '../utils/config.js';
|
|
4
|
+
import { isGitInstalled, isInGitRepo, getStagedFiles, getFilteredDiff, } from '../utils/git.js';
|
|
5
|
+
import { createAIClient, generateCommitMessage, } from '../utils/ai.js';
|
|
6
|
+
function exitWithError(message, options) {
|
|
7
|
+
if (options.json) {
|
|
8
|
+
const result = { success: false, error: message };
|
|
9
|
+
console.log(JSON.stringify(result, null, 2));
|
|
10
|
+
}
|
|
11
|
+
else if (!options.quiet) {
|
|
12
|
+
console.error(chalk.red(`❌ ${message}`));
|
|
13
|
+
}
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
export async function runMsg(options = {}) {
|
|
17
|
+
const { json = false, quiet = false, num = 1 } = options;
|
|
18
|
+
// Check for recursion guard
|
|
19
|
+
if (process.env.GIT_AI_RUNNING === '1') {
|
|
20
|
+
if (json) {
|
|
21
|
+
console.log(JSON.stringify({ success: false, error: 'Recursion detected' }));
|
|
22
|
+
}
|
|
23
|
+
process.exit(0);
|
|
24
|
+
}
|
|
25
|
+
// Set recursion guard
|
|
26
|
+
process.env.GIT_AI_RUNNING = '1';
|
|
27
|
+
// Environment checks
|
|
28
|
+
if (!(await isGitInstalled())) {
|
|
29
|
+
exitWithError('Git is not installed.', options);
|
|
30
|
+
}
|
|
31
|
+
if (!(await isInGitRepo())) {
|
|
32
|
+
exitWithError('Not in a git repository.', options);
|
|
33
|
+
}
|
|
34
|
+
const stagedFiles = await getStagedFiles();
|
|
35
|
+
if (stagedFiles.length === 0) {
|
|
36
|
+
exitWithError('No staged changes found. Use `git add <files>` first.', options);
|
|
37
|
+
}
|
|
38
|
+
// Check config
|
|
39
|
+
const config = getConfig();
|
|
40
|
+
if (!config) {
|
|
41
|
+
exitWithError('Configuration not found. Run `git-ai config` first.', options);
|
|
42
|
+
}
|
|
43
|
+
// Get filtered diff
|
|
44
|
+
const { diff, truncated, ignoredFiles } = await getFilteredDiff(stagedFiles);
|
|
45
|
+
// Create AI client
|
|
46
|
+
const client = createAIClient(config);
|
|
47
|
+
const input = { diff, stagedFiles, ignoredFiles, truncated };
|
|
48
|
+
// Generate message(s)
|
|
49
|
+
try {
|
|
50
|
+
let spinner = null;
|
|
51
|
+
if (!quiet && !json) {
|
|
52
|
+
spinner = ora({
|
|
53
|
+
text: num > 1 ? `Generating ${num} commit messages...` : 'Generating commit message...',
|
|
54
|
+
color: 'cyan',
|
|
55
|
+
}).start();
|
|
56
|
+
}
|
|
57
|
+
if (num > 1) {
|
|
58
|
+
// Generate multiple messages
|
|
59
|
+
const promises = Array.from({ length: num }, () => generateCommitMessage(client, input, config));
|
|
60
|
+
const messages = await Promise.all(promises);
|
|
61
|
+
const unique = [...new Set(messages)];
|
|
62
|
+
if (spinner) {
|
|
63
|
+
spinner.stop();
|
|
64
|
+
}
|
|
65
|
+
if (json) {
|
|
66
|
+
const result = {
|
|
67
|
+
success: true,
|
|
68
|
+
messages: unique,
|
|
69
|
+
metadata: { stagedFiles, truncated, ignoredFiles },
|
|
70
|
+
};
|
|
71
|
+
console.log(JSON.stringify(result, null, 2));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
// Plain output: one message per line
|
|
75
|
+
unique.forEach((msg) => console.log(msg));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Single message
|
|
80
|
+
const message = await generateCommitMessage(client, input, config);
|
|
81
|
+
if (spinner) {
|
|
82
|
+
spinner.stop();
|
|
83
|
+
}
|
|
84
|
+
if (json) {
|
|
85
|
+
const result = {
|
|
86
|
+
success: true,
|
|
87
|
+
message,
|
|
88
|
+
metadata: { stagedFiles, truncated, ignoredFiles },
|
|
89
|
+
};
|
|
90
|
+
console.log(JSON.stringify(result, null, 2));
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
// Plain output
|
|
94
|
+
console.log(message);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
100
|
+
exitWithError(errorMessage, options);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=msg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"msg.js","sourceRoot":"","sources":["../../src/commands/msg.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EACL,cAAc,EACd,WAAW,EACX,cAAc,EACd,eAAe,GAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,cAAc,EACd,qBAAqB,GAEtB,MAAM,gBAAgB,CAAC;AAoBxB,SAAS,aAAa,CAAC,OAAe,EAAE,OAAmB;IACzD,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,MAAM,GAAc,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QAC7D,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;SAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,UAAsB,EAAE;IACnD,MAAM,EAAE,IAAI,GAAG,KAAK,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC;IAEzD,4BAA4B;IAC5B,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,GAAG,EAAE,CAAC;QACvC,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,CAAC,CAAC;QAC/E,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,sBAAsB;IACtB,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,GAAG,CAAC;IAEjC,qBAAqB;IACrB,IAAI,CAAC,CAAC,MAAM,cAAc,EAAE,CAAC,EAAE,CAAC;QAC9B,aAAa,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;IAClD,CAAC;IAED,IAAI,CAAC,CAAC,MAAM,WAAW,EAAE,CAAC,EAAE,CAAC;QAC3B,aAAa,CAAC,0BAA0B,EAAE,OAAO,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,cAAc,EAAE,CAAC;IAC3C,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,aAAa,CAAC,uDAAuD,EAAE,OAAO,CAAC,CAAC;IAClF,CAAC;IAED,eAAe;IACf,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,aAAa,CAAC,qDAAqD,EAAE,OAAO,CAAC,CAAC;IAChF,CAAC;IAED,oBAAoB;IACpB,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,MAAM,eAAe,CAAC,WAAW,CAAC,CAAC;IAE7E,mBAAmB;IACnB,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,KAAK,GAAiC,EAAE,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;IAE3F,sBAAsB;IACtB,IAAI,CAAC;QACH,IAAI,OAAO,GAAkC,IAAI,CAAC;QAElD,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;YACpB,OAAO,GAAG,GAAG,CAAC;gBACZ,IAAI,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,GAAG,qBAAqB,CAAC,CAAC,CAAC,8BAA8B;gBACvF,KAAK,EAAE,MAAM;aACd,CAAC,CAAC,KAAK,EAAE,CAAC;QACb,CAAC;QAED,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;YACZ,6BAA6B;YAC7B,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,CAChD,qBAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAC7C,CAAC;YACF,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;YAEtC,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,CAAC;YAED,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,MAAM,GAAc;oBACxB,OAAO,EAAE,IAAI;oBACb,QAAQ,EAAE,MAAM;oBAChB,QAAQ,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE;iBACnD,CAAC;gBACF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC/C,CAAC;iBAAM,CAAC;gBACN,qCAAqC;gBACrC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;aAAM,CAAC;YACN,iBAAiB;YACjB,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;YAEnE,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,CAAC;YAED,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,MAAM,GAAc;oBACxB,OAAO,EAAE,IAAI;oBACb,OAAO;oBACP,QAAQ,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE;iBACnD,CAAC;gBACF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC/C,CAAC;iBAAM,CAAC;gBACN,eAAe;gBACf,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QAC9E,aAAa,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dongowu/git-ai-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Fast, privacy-first, bring-your-own-model Git commit message generator",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cli.js",
|
|
@@ -11,7 +11,13 @@
|
|
|
11
11
|
"build": "tsc",
|
|
12
12
|
"dev": "tsc --watch",
|
|
13
13
|
"start": "node dist/cli.js",
|
|
14
|
-
"prepublishOnly": "npm run build"
|
|
14
|
+
"prepublishOnly": "npm run build",
|
|
15
|
+
"release": "npm version patch && git push && git push --tags && npm publish --access=public",
|
|
16
|
+
"release:minor": "npm version minor && git push && git push --tags && npm publish --access=public",
|
|
17
|
+
"release:major": "npm version major && git push && git push --tags && npm publish --access=public",
|
|
18
|
+
"tag": "npm version patch && git push && git push --tags",
|
|
19
|
+
"tag:minor": "npm version minor && git push && git push --tags",
|
|
20
|
+
"tag:major": "npm version major && git push && git push --tags"
|
|
15
21
|
},
|
|
16
22
|
"keywords": [
|
|
17
23
|
"git",
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# release.sh - 自动发布脚本
|
|
3
|
+
|
|
4
|
+
set -e
|
|
5
|
+
|
|
6
|
+
# 颜色
|
|
7
|
+
GREEN='\033[0;32m'
|
|
8
|
+
YELLOW='\033[1;33m'
|
|
9
|
+
NC='\033[0m'
|
|
10
|
+
|
|
11
|
+
# 获取版本类型
|
|
12
|
+
VERSION_TYPE=${1:-patch}
|
|
13
|
+
|
|
14
|
+
echo -e "${GREEN}🚀 Starting release...${NC}"
|
|
15
|
+
|
|
16
|
+
# 1. 构建
|
|
17
|
+
echo -e "${YELLOW}📦 Building...${NC}"
|
|
18
|
+
npm run build
|
|
19
|
+
|
|
20
|
+
# 2. 更新版本
|
|
21
|
+
echo -e "${YELLOW}📝 Bumping ${VERSION_TYPE} version...${NC}"
|
|
22
|
+
npm version $VERSION_TYPE
|
|
23
|
+
|
|
24
|
+
# 3. 推送到 GitHub
|
|
25
|
+
echo -e "${YELLOW}📤 Pushing to GitHub...${NC}"
|
|
26
|
+
git push
|
|
27
|
+
git push --tags
|
|
28
|
+
|
|
29
|
+
# 4. 发布到 npm
|
|
30
|
+
echo -e "${YELLOW}📦 Publishing to npm...${NC}"
|
|
31
|
+
read -p "Enter OTP code: " OTP
|
|
32
|
+
npm publish --access=public --otp=$OTP
|
|
33
|
+
|
|
34
|
+
echo -e "${GREEN}✅ Release complete!${NC}"
|