ai-git-tools 2.0.0 → 2.0.1

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/bin/cli.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * AI Git Tools CLI
5
5
  *
6
6
  * AI-powered Git automation for commit messages and PR generation
7
- * 完全重写版本基于 scripts/ 原始实现
7
+ * 完全重写版本基於 scripts/ 原始实现
8
8
  */
9
9
 
10
10
  import { Command } from 'commander';
@@ -23,7 +23,7 @@ program
23
23
  // Init 命令
24
24
  program
25
25
  .command('init')
26
- .description('初始化配置文件 (.ai-git-config.mjs)')
26
+ .description('初始化配置檔案 (.ai-git-config.mjs)')
27
27
  .action(initCommand);
28
28
 
29
29
  // Commit 命令
@@ -31,7 +31,7 @@ program
31
31
  .command('commit')
32
32
  .description('AI 自动生成 commit message 并提交')
33
33
  .option('--model <model>', '指定 AI 模型')
34
- .option('-v, --verbose', '显示详细输出')
34
+ .option('-v, --verbose', '顯示详细输出')
35
35
  .option('--max-diff <number>', '最大 diff 长度')
36
36
  .option('--max-retries <number>', '最大重试次数')
37
37
  .action(commitCommand);
@@ -39,9 +39,9 @@ program
39
39
  // Commit All 命令
40
40
  program
41
41
  .command('commit-all')
42
- .description('智能分析所有变更并自动分组提交')
42
+ .description('智慧分析所有變更并自动分組提交')
43
43
  .option('--model <model>', '指定 AI 模型')
44
- .option('-v, --verbose', '显示详细输出')
44
+ .option('-v, --verbose', '顯示详细输出')
45
45
  .option('--max-diff <number>', '最大 diff 长度')
46
46
  .option('--max-retries <number>', '最大重试次数')
47
47
  .action(commitAllCommand);
@@ -53,10 +53,10 @@ program
53
53
  .option('--base <branch>', '指定目标分支')
54
54
  .option('--head <branch>', '指定来源分支')
55
55
  .option('--model <model>', '指定 AI 模型')
56
- .option('--org <org-name>', '指定 GitHub 组织名称')
56
+ .option('--org <org-name>', '指定 GitHub 組织名称')
57
57
  .option('--draft', '创建草稿 PR')
58
58
  .option('--preview', '仅预览 PR 内容,不实际创建')
59
- .option('--no-confirm', '跳过确认直接创建')
59
+ .option('--no-confirm', '跳過确认直接创建')
60
60
  .option('--auto-reviewers', '自动选择 reviewers')
61
61
  .option('--auto-labels', '自动添加 Labels')
62
62
  .option('--no-labels', '不添加 Labels')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-git-tools",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "AI-powered Git automation tools for commit messages and PR generation",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Commit All 命令
3
- * 基于 scripts/ai-auto-commit-all.mjs
4
- * 智能分析所有变更并自动分类提交
3
+ * 基於 scripts/ai-auto-commit-all.mjs
4
+ * 智慧分析所有變更並自動分類提交
5
5
  */
6
6
 
7
7
  import { execSync } from 'child_process';
@@ -12,28 +12,28 @@ import { Logger } from '../utils/logger.js';
12
12
  import { handleError } from '../utils/helpers.js';
13
13
 
14
14
  /**
15
- * 获取文件的变更内容
15
+ * 獲取檔案的變更內容
16
16
  */
17
17
  function getFileDiff(filePath, isNew) {
18
18
  try {
19
19
  if (isNew) {
20
- // 新文件:读取完整内容(前 100 行)
20
+ // 新檔案:讀取完整內容(前 100 行)
21
21
  const content = readFileSync(filePath, 'utf-8');
22
22
  const lines = content.split('\n').slice(0, 100);
23
- return `[新文件]\n${lines.join('\n')}${lines.length >= 100 ? '\n...' : ''}`;
23
+ return `[新檔案]\n${lines.join('\n')}${lines.length >= 100 ? '\n...' : ''}`;
24
24
  }
25
- // 已存在文件:获取 diff
25
+ // 已存在檔案:獲取 diff
26
26
  const diff = execSync(`git diff HEAD -- "${filePath}"`, {
27
27
  encoding: 'utf-8',
28
28
  }).toString();
29
- return diff || '[无变更]';
29
+ return diff || '[無變更]';
30
30
  } catch (error) {
31
- return `[读取错误: ${error.message}]`;
31
+ return `[讀取錯誤: ${error.message}]`;
32
32
  }
33
33
  }
34
34
 
35
35
  /**
36
- * 获取所有未提交的变更
36
+ * 獲取所有未提交的變更
37
37
  */
38
38
  function getAllChanges() {
39
39
  try {
@@ -52,12 +52,12 @@ function getAllChanges() {
52
52
  const statusCode = line.substring(0, 2);
53
53
  const filePath = line.substring(3).trim();
54
54
 
55
- // 跳过已删除的文件
55
+ // 跳過已刪除的檔案
56
56
  if (statusCode.includes('D')) {
57
57
  continue;
58
58
  }
59
59
 
60
- // 跳过某些不需要提交的文件
60
+ // 跳過某些不需要提交的檔案
61
61
  if (
62
62
  filePath.includes('node_modules/') ||
63
63
  filePath.includes('.next/') ||
@@ -80,115 +80,115 @@ function getAllChanges() {
80
80
 
81
81
  return changes;
82
82
  } catch (error) {
83
- console.error('获取变更列表失败:', error.message);
83
+ console.error('獲取變更列表失敗:', error.message);
84
84
  return [];
85
85
  }
86
86
  }
87
87
 
88
88
  /**
89
- * 使用 AI 分析并分组变更
89
+ * 使用 AI 分析並分組變更
90
90
  */
91
91
  async function analyzeAndGroupChanges(changes, config) {
92
- console.log('🤖 正在使用 AI 分析变更并分组...\n');
92
+ console.log('🤖 正在使用 AI 分析變更並分組...\n');
93
93
 
94
- // 准备变更摘要
94
+ // 準備變更摘要
95
95
  const maxDiffPerFile = Math.floor(config.ai.maxDiffLength / Math.max(changes.length, 1));
96
96
  const changeSummary = changes
97
97
  .map((change, index) => {
98
98
  const diff = getFileDiff(change.filePath, change.isNew);
99
99
  const lines = diff.split('\n');
100
100
  const truncatedDiff = lines.slice(0, Math.min(50, maxDiffPerFile / 100)).join('\n');
101
- return `[文件 ${index}] ${change.filePath}\n${
102
- change.isNew ? '(新文件)' : '(已修改)'
101
+ return `[檔案 ${index}] ${change.filePath}\n${
102
+ change.isNew ? '(新檔案)' : '(已修改)'
103
103
  }\n${truncatedDiff}\n`;
104
104
  })
105
105
  .join('\n---\n\n');
106
106
 
107
- const prompt = `你是一个资深前端工程师,熟悉 Next.js 专案的开发规范。请分析以下的文件变更,并将它们按照功能/目的分组。
107
+ const prompt = `你是一個資深前端工程師,熟悉 Next.js 專案的開發規範。請分析以下的檔案變更,並將它們按照功能/目的分組。
108
108
 
109
- **专案背景**:
109
+ **專案背景**:
110
110
  - Next.js 12+ (Pages Router)
111
111
  - TypeScript + JavaScript 混合
112
112
  - Tailwind CSS + Styled Components
113
- - Zustand (客户端状态) + SWR (伺服器资料获取)
114
- - React Hook Form + Zod (表单处理)
113
+ - Zustand (客戶端狀態) + SWR (伺服器資料獲取)
114
+ - React Hook Form + Zod (表單處理)
115
115
  - 架构:Modified Atomic Design(UI / Page / Feature 三层)
116
116
 
117
- **专案目录结构参考**:
118
- - pages/ → 页面路由
119
- - components/Page/ → 页面级元件
117
+ **專案目錄結構參考**:
118
+ - pages/ → 頁面路由
119
+ - components/Page/ → 頁面級元件
120
120
  - components/UI/ 或 components/Common/ → 共用 UI 元件
121
- - components/[Feature]/ → 功能模块元件
122
- - store/ → Zustand 状态管理
121
+ - components/[Feature]/ → 功能模組元件
122
+ - store/ → Zustand 狀態管理
123
123
  - api/ → API 呼叫
124
124
  - utils/ → 工具函式
125
- - styles/ → 全域样式
126
-
127
- 规则:
128
- 1. 将相关功能的变更归类在同一组(例如:同一个功能开发、同一个 bug 修复、相关的重构等)
129
- 2. 每组应该要有明确的主题
130
- 3. 同一个功能的元件、API、store、样式应归为同一组
131
- 4. 设定档(config)和文件(docs)变更可以独立成一组
132
- 5. 输出格式为 JSON 数组,每个元素包含:
133
- - group_name: 群组名称(简短描述,繁体中文)
134
- - commit_type: commit 类型(feat/fix/docs/style/refactor/test/chore/perf)
135
- - commit_scope: commit 影响范围(如 member、report、auth、api、ui、config)
136
- - file_indices: 属于这组的文件索引数组(对应上面的 [文件 X])
137
- - description: 这组变更的详细说明(繁体中文)
138
-
139
- 范例输出:
125
+ - styles/ → 全域樣式
126
+
127
+ 規則:
128
+ 1. 將相關功能的變更歸類在同一組(例如:同一個功能開發、同一個 bug 修復、相關的重構等)
129
+ 2. 每組應該要有明確的主題
130
+ 3. 同一個功能的元件、API、store、樣式應歸為同一組
131
+ 4. 設定檔(config)和檔案(docs)變更可以獨立成一組
132
+ 5. 輸出格式為 JSON 陣列,每個元素包含:
133
+ - group_name: 群組名稱(簡短描述,繁體中文)
134
+ - commit_type: commit 類型(feat/fix/docs/style/refactor/test/chore/perf)
135
+ - commit_scope: commit 影響範圍(如 member、report、auth、api、ui、config)
136
+ - file_indices: 屬於這組的檔案索引陣列(對應上面的 [檔案 X])
137
+ - description: 這組變更的詳細說明(繁體中文)
138
+
139
+ 範例輸出:
140
140
  [
141
141
  {
142
142
  "group_name": "新增使用者登入功能",
143
143
  "commit_type": "feat",
144
144
  "commit_scope": "auth",
145
145
  "file_indices": [0, 1, 2],
146
- "description": "实作使用者登入 API 和前端页面"
146
+ "description": "實作使用者登入 API 和前端頁面"
147
147
  },
148
148
  {
149
- "group_name": "修正导航列手机版显示",
149
+ "group_name": "修正導航列手機版顯示",
150
150
  "commit_type": "fix",
151
151
  "commit_scope": "ui",
152
152
  "file_indices": [3, 4],
153
- "description": "修正导航列在手机版的显示问题"
153
+ "description": "修正導航列在手機版的顯示問題"
154
154
  }
155
155
  ]
156
156
 
157
- 文件变更内容:
157
+ 檔案變更內容:
158
158
  ${changeSummary}
159
159
 
160
- 请只输出 JSON,不要其他文字。`;
160
+ 請只輸出 JSON,不要其他文字。`;
161
161
 
162
162
  const response = await AIClient.sendAndWait(prompt, config.ai.model);
163
163
 
164
164
  try {
165
165
  return AIClient.parseJSON(response);
166
166
  } catch (error) {
167
- console.error('❌ 无法解析 AI 回应:', error.message);
168
- console.log('原始回应:', response);
167
+ console.error('❌ 無法解析 AI 回應:', error.message);
168
+ console.log('原始回應:', response);
169
169
  return null;
170
170
  }
171
171
  }
172
172
 
173
173
  /**
174
- * 为特定群组生成 commit message
174
+ * 为特定群組生成 commit message
175
175
  */
176
176
  async function generateCommitMessage(group, files, config) {
177
177
  const filesList = files
178
178
  .map((file) => {
179
179
  const diff = getFileDiff(file.filePath, file.isNew);
180
- return `文件: ${file.filePath}\n${diff}`;
180
+ return `檔案: ${file.filePath}\n${diff}`;
181
181
  })
182
182
  .join('\n\n---\n\n');
183
183
 
184
184
  const prompt = `请根据以下资讯生成一则 commit message:
185
185
 
186
- 群组名称: ${group.group_name}
186
+ 群組名称: ${group.group_name}
187
187
  Commit 类型: ${group.commit_type}
188
188
  Commit 范围: ${group.commit_scope || '未指定'}
189
189
  说明: ${group.description}
190
190
 
191
- 文件变更:
191
+ 檔案變更:
192
192
  ${filesList}
193
193
 
194
194
  规则:
@@ -196,7 +196,7 @@ ${filesList}
196
196
  group.commit_scope ? `(${group.commit_scope})` : ''
197
197
  }: <subject>
198
198
  - subject 限制在 50 字内,使用繁体中文
199
- - 如果变更复杂,可以加上 body(用空行分隔),body 使用 bullet points
199
+ - 如果變更複雜,可以加上 body(用空行分隔),body 使用 bullet points
200
200
  - 只输出 commit message 本身,不要其他说明
201
201
  - 不要包含 markdown code block 标记(不要 \`\`\`)
202
202
  - 不要加上任何引导语句
@@ -221,30 +221,30 @@ feat(auth): 新增使用者登入功能
221
221
  }
222
222
 
223
223
  /**
224
- * 执行分组提交
224
+ * 執行分組提交
225
225
  */
226
226
  async function commitGroup(group, files, config) {
227
227
  try {
228
- console.log(`\n📦 处理群组: ${group.group_name}`);
228
+ console.log(`\n📦 处理群組: ${group.group_name}`);
229
229
  console.log(
230
230
  ` 类型: ${group.commit_type}${group.commit_scope ? `(${group.commit_scope})` : ''}`
231
231
  );
232
- console.log(` 文件数量: ${files.length}`);
232
+ console.log(` 檔案数量: ${files.length}`);
233
233
 
234
- // 先 reset 所有已 staged 的文件
234
+ // 先 reset 所有已 staged 的檔案
235
235
  try {
236
236
  execSync('git reset HEAD -- .', { stdio: 'ignore' });
237
237
  } catch (e) {
238
- // 忽略错误(可能没有 staged 的文件)
238
+ // 忽略錯誤(可能没有 staged 的檔案)
239
239
  }
240
240
 
241
- // Add 这组的文件
241
+ // Add 这組的檔案
242
242
  for (const file of files) {
243
243
  console.log(` ├─ ${file.filePath}`);
244
244
  try {
245
245
  execSync(`git add "${file.filePath}"`, { encoding: 'utf-8' });
246
246
  } catch (addError) {
247
- console.error(` ⚠️ 无法加入文件: ${file.filePath}`, addError.message);
247
+ console.error(` ⚠️ 無法加入檔案: ${file.filePath}`, addError.message);
248
248
  throw addError;
249
249
  }
250
250
  }
@@ -254,7 +254,7 @@ async function commitGroup(group, files, config) {
254
254
  const commitMessage = await generateCommitMessage(group, files, config);
255
255
 
256
256
  if (!commitMessage) {
257
- console.log(` ❌ 无法生成 commit message,跳过此群组`);
257
+ console.log(` ❌ 無法生成 commit message,跳過此群組`);
258
258
  return false;
259
259
  }
260
260
 
@@ -265,8 +265,8 @@ async function commitGroup(group, files, config) {
265
265
  });
266
266
  console.log(` ${'─'.repeat(50)}`);
267
267
 
268
- // 执行 commit
269
- // 使用临时文件避免 commit message 中的特殊字符问题
268
+ // 執行 commit
269
+ // 使用暫存檔案避免 commit message 中的特殊字元問題
270
270
  const tmpFile = '.git/COMMIT_EDITMSG_TMP';
271
271
  try {
272
272
  writeFileSync(tmpFile, commitMessage, 'utf-8');
@@ -278,7 +278,7 @@ async function commitGroup(group, files, config) {
278
278
  try {
279
279
  unlinkSync(tmpFile);
280
280
  } catch (e) {
281
- // 忽略删除临时文件的错误
281
+ // 忽略刪除临时檔案的錯誤
282
282
  }
283
283
  throw commitError;
284
284
  }
@@ -286,7 +286,7 @@ async function commitGroup(group, files, config) {
286
286
  console.log(` ✅ Commit 完成!`);
287
287
  return true;
288
288
  } catch (error) {
289
- console.error(` ❌ Commit 失败:`, error.message);
289
+ console.error(` ❌ Commit 失敗:`, error.message);
290
290
  return false;
291
291
  }
292
292
  }
@@ -298,10 +298,10 @@ export async function commitAllCommand() {
298
298
  const logger = new Logger();
299
299
 
300
300
  try {
301
- // 载入配置
301
+ // 載入配置
302
302
  const config = await loadCommitConfig();
303
303
 
304
- logger.header('智能分析所有变更并自动提交');
304
+ logger.header('智慧分析所有變更並自動提交');
305
305
 
306
306
  if (config.output.verbose) {
307
307
  console.log('📋 使用配置:');
@@ -311,39 +311,39 @@ export async function commitAllCommand() {
311
311
  console.log('');
312
312
  }
313
313
 
314
- // 1. 获取所有变更
315
- logger.step('扫描变更中...');
314
+ // 1. 獲取所有變更
315
+ logger.step('掃描變更中...');
316
316
  const changes = getAllChanges();
317
317
 
318
318
  if (changes.length === 0) {
319
- logger.info('没有需要提交的变更');
319
+ logger.info('沒有需要提交的變更');
320
320
  process.exit(0);
321
321
  }
322
322
 
323
- console.log(`📊 找到 ${changes.length} 个变更的文件:\n`);
323
+ console.log(`📊 找到 ${changes.length} 个變更的檔案:\n`);
324
324
  changes.forEach((change, index) => {
325
325
  const status = change.isNew ? '新增' : '修改';
326
326
  console.log(` [${index}] ${status} - ${change.filePath}`);
327
327
  });
328
328
  console.log();
329
329
 
330
- // 2. 使用 AI 分析并分组
330
+ // 2. 使用 AI 分析並分組
331
331
  const groups = await analyzeAndGroupChanges(changes, config);
332
332
 
333
333
  if (!groups || groups.length === 0) {
334
- logger.error('AI 分析失败或没有产生分组');
334
+ logger.error('AI 分析失敗或沒有產生分組');
335
335
  process.exit(1);
336
336
  }
337
337
 
338
- logger.success(`AI 分析完成,共分为 ${groups.length} 个群组:\n`);
338
+ logger.success(`AI 分析完成,共分為 ${groups.length} 個群組:\n`);
339
339
  groups.forEach((group, index) => {
340
- console.log(` 群组 ${index + 1}: ${group.group_name} (${group.commit_type})`);
341
- console.log(` └─ 包含 ${group.file_indices.length} 个文件`);
340
+ console.log(` 群組 ${index + 1}: ${group.group_name} (${group.commit_type})`);
341
+ console.log(` └─ 包含 ${group.file_indices.length} 个檔案`);
342
342
  });
343
343
 
344
- // 3. 依序提交每个群组
344
+ // 3. 依序提交每个群組
345
345
  logger.separator('=', 60);
346
- console.log('开始执行提交...');
346
+ console.log('開始執行提交...');
347
347
  logger.separator('=', 60);
348
348
 
349
349
  let successCount = 0;
@@ -357,16 +357,16 @@ export async function commitAllCommand() {
357
357
  }
358
358
  }
359
359
 
360
- // 4. 显示摘要
360
+ // 4. 顯示摘要
361
361
  logger.separator('=', 60);
362
- logger.success(`完成!成功提交 ${successCount}/${groups.length} 个群组`);
362
+ logger.success(`完成!成功提交 ${successCount}/${groups.length} 个群組`);
363
363
  logger.separator('=', 60);
364
364
 
365
- // 显示最近的几个 commits
365
+ // 顯示最近的几个 commits
366
366
  console.log('\n📋 最近的 commits:');
367
367
  execSync(`git log -${successCount} --oneline`, { stdio: 'inherit' });
368
368
 
369
- // Reset 任何剩余的 staged 文件
369
+ // Reset 任何剩餘的 staged 檔案
370
370
  try {
371
371
  execSync('git reset HEAD -- .', { stdio: 'ignore' });
372
372
  } catch (e) {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Commit 命令
3
- * 基于 scripts/ai-auto-commit.mjs
4
- * 自动生成 commit message 并执行 commit
3
+ * 基於 scripts/ai-auto-commit.mjs
4
+ * 自動產生 commit message 並執行 commit
5
5
  */
6
6
 
7
7
  import { execSync } from 'child_process';
@@ -15,7 +15,7 @@ export async function commitCommand() {
15
15
  const logger = new Logger();
16
16
 
17
17
  try {
18
- // 载入配置
18
+ // 載入配置
19
19
  const config = await loadCommitConfig();
20
20
 
21
21
  if (config.output.verbose) {
@@ -25,59 +25,59 @@ export async function commitCommand() {
25
25
  console.log('');
26
26
  }
27
27
 
28
- // 检查是否有 staged 变更
28
+ // 檢查是否有 staged 變更
29
29
  const diff = GitOperations.getStagedDiff();
30
30
 
31
31
  if (!diff.trim()) {
32
- logger.error('没有 staged 的变更');
33
- console.log('💡 请先使用 git add stage 你的变更');
32
+ logger.error('沒有 staged 的變更');
33
+ console.log('💡 請先使用 git add stage 你的變更');
34
34
  process.exit(1);
35
35
  }
36
36
 
37
- logger.step('正在分析变更内容...\n');
37
+ logger.step('正在分析變更內容...\n');
38
38
 
39
- // 截断过长的 diff
39
+ // 截斷過長的 diff
40
40
  const truncatedDiff =
41
41
  diff.length > config.ai.maxDiffLength
42
- ? diff.substring(0, config.ai.maxDiffLength) + '\n\n... [diff 过长已截断]'
42
+ ? diff.substring(0, config.ai.maxDiffLength) + '\n\n... [diff 過長已截斷]'
43
43
  : diff;
44
44
 
45
45
  if (config.output.verbose && diff.length > config.ai.maxDiffLength) {
46
- logger.warning(`Diff 已从 ${diff.length} 字元截断至 ${config.ai.maxDiffLength} 字元\n`);
46
+ logger.warning(`Diff 已從 ${diff.length} 字元截斷至 ${config.ai.maxDiffLength} 字元\n`);
47
47
  }
48
48
 
49
- // 使用 AI 生成 commit message
49
+ // 使用 AI 產生 commit message
50
50
  let commitMessage = '';
51
51
  let lastError = null;
52
52
 
53
53
  for (let attempt = 1; attempt <= config.ai.maxRetries; attempt++) {
54
54
  try {
55
55
  if (config.output.verbose && attempt > 1) {
56
- console.log(`🔄 重试第 ${attempt}/${config.ai.maxRetries} 次...\n`);
56
+ console.log(`🔄 重試第 ${attempt}/${config.ai.maxRetries} 次...\n`);
57
57
  }
58
58
 
59
59
  const prompt = `${getProjectTypePrompt()}
60
60
 
61
- 请根据以下 git diff 产生一则 commit message。
61
+ 請根據以下 git diff 產生一則 commit message。
62
62
 
63
- **Commit Message 规则**:
63
+ **Commit Message 規則**:
64
64
  1. 使用 Conventional Commits 格式:type(scope): subject
65
- 2. type 必须是:feat/fix/docs/style/refactor/test/chore/perf 其中之一
66
- 3. scope: 影响范围(如 member、report、auth、api、ui、config)
67
- 4. subject 限制在 50 字内,使用繁体中文
68
- 5. 如果变更复杂,加上 body 说明(使用 bullet points)
65
+ 2. type 必須是:feat/fix/docs/style/refactor/test/chore/perf 其中之一
66
+ 3. scope: 影響範圍(如 member、report、auth、api、ui、config)
67
+ 4. subject 限制在 50 字內,使用繁體中文
68
+ 5. 如果變更複雜,加上 body 說明(使用 bullet points)
69
69
 
70
70
  **重要**:
71
- - 直接输出 commit message 纯文字,不要使用 markdown 程式码区块(\`\`\`)
72
- - 不要加上任何前缀说明或后缀文字
73
- - 第一行是标题,如有需要可加上空行后的详细说明
71
+ - 直接輸出 commit message 純文字,不要使用 markdown 程式碼區塊(\`\`\`)
72
+ - 不要加上任何前綴說明或後綴文字
73
+ - 第一行是標題,如有需要可加上空行後的詳細說明
74
74
 
75
- **范例格式**:
76
- feat(member): 新增会员管理页面
75
+ **範例格式**:
76
+ feat(member): 新增會員管理頁面
77
77
 
78
- - 实作会员列表查询功能
79
- - 新增会员资料编辑表单
80
- - 整合 Zustand 状态管理
78
+ - 實作會員列表查詢功能
79
+ - 新增會員資料編輯表單
80
+ - 整合 Zustand 狀態管理
81
81
 
82
82
  git diff:
83
83
  ${truncatedDiff}`;
@@ -85,18 +85,18 @@ ${truncatedDiff}`;
85
85
  const response = await AIClient.sendAndWait(prompt, config.ai.model);
86
86
  commitMessage = cleanCommitMessage(response);
87
87
 
88
- // 验证 commit message
88
+ // 驗證 commit message
89
89
  const validation = validateCommitMessage(commitMessage);
90
90
  if (!validation.valid) {
91
- throw new Error(`无效的 commit message: ${validation.reason}`);
91
+ throw new Error(`無效的 commit message: ${validation.reason}`);
92
92
  }
93
93
 
94
- // 成功生成,跳出重试循环
94
+ // 成功產生,跳出重試迴圈
95
95
  break;
96
96
  } catch (error) {
97
97
  lastError = error;
98
98
  if (config.output.verbose) {
99
- logger.warning(`尝试 ${attempt} 失败: ${error.message}\n`);
99
+ logger.warning(`嘗試 ${attempt} 失敗: ${error.message}\n`);
100
100
  }
101
101
 
102
102
  if (attempt < config.ai.maxRetries) {
@@ -105,26 +105,26 @@ ${truncatedDiff}`;
105
105
  }
106
106
  }
107
107
 
108
- // 所有重试都失败
108
+ // 所有重試都失敗
109
109
  if (!commitMessage) {
110
- logger.error('无法生成有效的 commit message');
110
+ logger.error('無法產生有效的 commit message');
111
111
  if (lastError && config.output.verbose) {
112
- console.log(` 最后错误: ${lastError.message}`);
112
+ console.log(` 最後錯誤: ${lastError.message}`);
113
113
  }
114
- console.log('\n💡 建议:');
115
- console.log(' 1. 检查网路连线');
116
- console.log(' 2. 尝试更换 AI 模型(使用 --model 参数)');
117
- console.log(' 3. 确认变更内容不会太复杂或太大');
114
+ console.log('\n💡 建議:');
115
+ console.log(' 1. 檢查網路連線');
116
+ console.log(' 2. 嘗試更換 AI 模型(使用 --model 參數)');
117
+ console.log(' 3. 確認變更內容不會太複雜或太大');
118
118
  process.exit(1);
119
119
  }
120
120
 
121
- logger.success('生成的 Commit Message:');
121
+ logger.success('產生的 Commit Message:');
122
122
  logger.separator('─', 60);
123
123
  console.log(commitMessage);
124
124
  logger.separator('─', 60);
125
125
 
126
- // 执行 commit
127
- logger.step('\n正在执行 commit...');
126
+ // 執行 commit
127
+ logger.step('\n正在執行 commit...');
128
128
  execSync(`git commit -m "${commitMessage.replace(/"/g, '\\"')}"`, {
129
129
  stdio: 'inherit',
130
130
  });
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Init 命令
3
- * 初始化配置文件
3
+ * 初始化配置檔案
4
4
  */
5
5
 
6
6
  import { writeFileSync, existsSync } from 'fs';
@@ -8,38 +8,38 @@ import { resolve } from 'path';
8
8
  import { Logger } from '../utils/logger.js';
9
9
 
10
10
  const DEFAULT_CONFIG = `/**
11
- * AI Git Tools 配置文件
11
+ * AI Git Tools 配置檔案
12
12
  *
13
- * 此文件用于配置 AI 自动化 Git 工具的行为
13
+ * 此檔案用於設定 AI 自動化 Git 工具的行為
14
14
  */
15
15
 
16
16
  export default {
17
- // AI 相关配置
17
+ // AI 相關配置
18
18
  ai: {
19
19
  model: 'gpt-4.1', // AI 模型
20
- maxDiffLength: 8000, // 最大 diff 长度
21
- maxRetries: 3, // 最大重试次数
20
+ maxDiffLength: 8000, // 最大 diff 長度
21
+ maxRetries: 3, // 最大重試次數
22
22
  },
23
23
 
24
- // GitHub 相关配置
24
+ // GitHub 相關配置
25
25
  github: {
26
- orgName: 'your-org-name', // GitHub 组织名称
27
- defaultBase: 'auto', // 默认 base 分支('auto' 为自动侦测)
28
- autoLabels: true, // 自动添加 Labels
26
+ orgName: 'your-org-name', // GitHub 組織名稱
27
+ defaultBase: 'auto', // 預設 base 分支('auto' 為自動偵測)
28
+ autoLabels: true, // 自動新增 Labels
29
29
  },
30
30
 
31
- // Reviewers 相关配置
31
+ // Reviewers 相關配置
32
32
  reviewers: {
33
- autoSelect: false, // 自动选择 reviewers
34
- maxSuggested: 5, // 最大建议 reviewers 数量
35
- gitHistoryDepth: 20, // Git 历史深度
33
+ autoSelect: false, // 自動選擇 reviewers
34
+ maxSuggested: 5, // 最大建議 reviewers 數量
35
+ gitHistoryDepth: 20, // Git 歷史深度
36
36
  excludeAuthors: [], // 排除的作者列表
37
37
  },
38
38
 
39
- // 输出相关配置
39
+ // 輸出相關配置
40
40
  output: {
41
- verbose: false, // 详细输出
42
- saveHistory: false, // 保存历史记录
41
+ verbose: false, // 詳細輸出
42
+ saveHistory: false, // 儲存歷史記錄
43
43
  },
44
44
  };
45
45
  `;
@@ -49,17 +49,17 @@ export async function initCommand() {
49
49
  const configPath = resolve(process.cwd(), '.ai-git-config.mjs');
50
50
 
51
51
  if (existsSync(configPath)) {
52
- logger.warning('配置文件已存在: .ai-git-config.mjs');
53
- console.log('如要重新初始化,请先删除现有配置文件');
52
+ logger.warning('配置檔案已存在: .ai-git-config.mjs');
53
+ console.log('如要重新初始化,請先刪除現有配置檔案');
54
54
  return;
55
55
  }
56
56
 
57
57
  try {
58
58
  writeFileSync(configPath, DEFAULT_CONFIG, 'utf-8');
59
- logger.success('已创建配置文件: .ai-git-config.mjs');
60
- console.log('\n请编辑此文件以自定义配置');
59
+ logger.success('已建立配置檔案: .ai-git-config.mjs');
60
+ console.log('\n請編輯此檔案以自訂配置');
61
61
  } catch (error) {
62
- logger.error(`创建配置文件失败: ${error.message}`);
62
+ logger.error(`建立配置檔案失敗: ${error.message}`);
63
63
  process.exit(1);
64
64
  }
65
65
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * PR 命令
3
- * 基于 scripts/ai-auto-pr.mjs 简化版
4
- * 生成 PR 标题、描述并创建 Pull Request
3
+ * 基於 scripts/ai-auto-pr.mjs 簡化版
4
+ * 產生 PR 標題、描述並建立 Pull Request
5
5
  */
6
6
 
7
7
  import { execSync } from 'child_process';
@@ -16,13 +16,13 @@ import { handleError, getProjectTypePrompt } from '../utils/helpers.js';
16
16
  */
17
17
  async function generatePRContent(baseBranch, headBranch, config) {
18
18
  const logger = new Logger();
19
- logger.step('AI 正在分析变更并生成 PR 内容...');
19
+ logger.step('AI 正在分析變更并生成 PR 内容...');
20
20
 
21
- // 获取 diff 和 commits
21
+ // 獲取 diff 和 commits
22
22
  const diff = GitOperations.getDiff(baseBranch, headBranch);
23
23
  const commits = GitOperations.getCommits(baseBranch, headBranch);
24
24
 
25
- // 智能截断 diff
25
+ // 智慧截断 diff
26
26
  const truncatedDiff = GitOperations.truncateDiff(diff, config.ai.maxDiffLength);
27
27
 
28
28
  const prompt = `${getProjectTypePrompt()}
@@ -42,10 +42,10 @@ ${truncatedDiff}
42
42
  }
43
43
 
44
44
  **PR 描述应包含**:
45
- 1. ## 📝 变更摘要(简述主要变更)
45
+ 1. ## 📝 變更摘要(简述主要變更)
46
46
  2. ## ✨ 主要功能(列出新增功能或修正项目)
47
- 3. ## 🔧 技术细节(选填,如有重要的技术变更)
48
- 4. ## ✅ 测试(如何测试这些变更)
47
+ 3. ## 🔧 技术细节(选填,如有重要的技术變更)
48
+ 4. ## ✅ 测试(如何测试这些變更)
49
49
 
50
50
  请只输出 JSON,不要其他文字。`;
51
51
 
@@ -56,12 +56,12 @@ ${truncatedDiff}
56
56
  logger.success('PR 内容生成完成\n');
57
57
  return prContent;
58
58
  } catch (error) {
59
- throw new Error(`无法解析 AI 回应: ${error.message}`);
59
+ throw new Error(`無法解析 AI 回应: ${error.message}`);
60
60
  }
61
61
  }
62
62
 
63
63
  /**
64
- * 显示 PR 预览
64
+ * 顯示 PR 预览
65
65
  */
66
66
  function displayPreview(prContent, stats) {
67
67
  console.log('\n' + '═'.repeat(60));
@@ -69,7 +69,7 @@ function displayPreview(prContent, stats) {
69
69
  console.log('═'.repeat(60));
70
70
  console.log(`\n标题: ${prContent.title}\n`);
71
71
  console.log(`统计: ${stats.stats}`);
72
- console.log(`文件数: ${stats.filesChanged} 个文件\n`);
72
+ console.log(`檔案数: ${stats.filesChanged} 个檔案\n`);
73
73
  console.log('─'.repeat(60));
74
74
  console.log('描述:\n');
75
75
  console.log(prContent.description);
@@ -85,10 +85,10 @@ export async function prCommand() {
85
85
  try {
86
86
  logger.header('AI Auto PR Generator');
87
87
 
88
- // 载入配置
88
+ // 載入配置
89
89
  const config = await loadPRConfig();
90
90
 
91
- // 获取当前分支
91
+ // 獲取当前分支
92
92
  const currentBranch = GitOperations.getCurrentBranch();
93
93
  let headBranch = config.headBranch || currentBranch;
94
94
  let baseBranch = config.baseBranch;
@@ -108,7 +108,7 @@ export async function prCommand() {
108
108
  }
109
109
  }
110
110
 
111
- // 检查是否在 base branch
111
+ // 檢查是否在 base branch
112
112
  if (currentBranch === baseBranch) {
113
113
  logger.error(`你目前在 ${baseBranch} 分支,请切换到 feature 分支`);
114
114
  console.log('💡 切换到 feature 分支: git checkout <feature-branch>');
@@ -119,7 +119,7 @@ export async function prCommand() {
119
119
  console.log(` Base: ${baseBranch}`);
120
120
  console.log(` Head: ${headBranch}\n`);
121
121
 
122
- // 推送到远端(预览模式跳过)
122
+ // 推送到远端(预览模式跳過)
123
123
  if (!config.preview) {
124
124
  logger.step(`推送到远端分支: origin/${headBranch}`);
125
125
  GitOperations.push(headBranch);
@@ -132,18 +132,18 @@ export async function prCommand() {
132
132
  logger.success('同步完成\n');
133
133
  }
134
134
 
135
- // 获取变更统计
135
+ // 獲取變更统计
136
136
  const stats = GitOperations.getChangeStats(baseBranch, headBranch);
137
- console.log(`📈 变更统计: ${stats.stats}`);
138
- console.log(`📁 影响文件: ${stats.filesChanged} 个\n`);
137
+ console.log(`📈 變更统计: ${stats.stats}`);
138
+ console.log(`📁 影响檔案: ${stats.filesChanged} 个\n`);
139
139
 
140
140
  // 生成 PR 内容
141
141
  const prContent = await generatePRContent(baseBranch, headBranch, config);
142
142
 
143
- // 显示预览
143
+ // 顯示预览
144
144
  displayPreview(prContent, stats);
145
145
 
146
- // 预览模式:仅显示不创建
146
+ // 预览模式:仅顯示不创建
147
147
  if (config.preview) {
148
148
  logger.info('预览模式:未创建 PR');
149
149
  return;
@@ -152,13 +152,13 @@ export async function prCommand() {
152
152
  // 创建 PR(使用 GitHub CLI)
153
153
  logger.step('创建 Pull Request...');
154
154
 
155
- // 准备 PR body
155
+ // 準備 PR body
156
156
  const prBody = prContent.description;
157
157
 
158
158
  // 构建 gh pr create 命令
159
159
  let ghCommand = `gh pr create --base ${baseBranch} --head ${headBranch} --title "${prContent.title.replace(/"/g, '\\"')}"`;
160
160
 
161
- // 将 body 写入临时文件
161
+ // 将 body 写入临时檔案
162
162
  const { writeFileSync, unlinkSync } = await import('fs');
163
163
  const tmpFile = '/tmp/pr-body-temp.md';
164
164
  writeFileSync(tmpFile, prBody, 'utf-8');
@@ -180,7 +180,7 @@ export async function prCommand() {
180
180
  } catch (e) {
181
181
  // 忽略
182
182
  }
183
- throw new Error(`创建 PR 失败: ${error.message}`);
183
+ throw new Error(`创建 PR 失敗: ${error.message}`);
184
184
  }
185
185
  } catch (error) {
186
186
  handleError(error);
@@ -1,13 +1,13 @@
1
1
  /**
2
- * AI 客户端
3
- * 基于 @github/copilot-sdk
2
+ * AI 客戶端
3
+ * 基於 @github/copilot-sdk
4
4
  */
5
5
 
6
6
  import { CopilotClient } from '@github/copilot-sdk';
7
7
 
8
8
  export class AIClient {
9
9
  /**
10
- * 发送 prompt 并等待回应(带重试机制)
10
+ * 發送 prompt 並等待回應(帶重試機制)
11
11
  */
12
12
  static async sendAndWait(prompt, model = 'gpt-4.1', maxRetries = 3) {
13
13
  const client = new CopilotClient();
@@ -24,27 +24,27 @@ export class AIClient {
24
24
  } catch (error) {
25
25
  lastError = error;
26
26
  if (attempt < maxRetries) {
27
- console.log(`⚠️ AI 请求失败,重试第 ${attempt}/${maxRetries} 次...`);
27
+ console.log(`⚠️ AI 請求失敗,重試第 ${attempt}/${maxRetries} 次...`);
28
28
  await new Promise((resolve) => setTimeout(resolve, 1000 * attempt));
29
29
  continue;
30
30
  }
31
31
  }
32
32
  }
33
33
 
34
- throw new Error(`AI 请求失败: ${lastError?.message || '未知错误'}`);
34
+ throw new Error(`AI 請求失敗: ${lastError?.message || '未知錯誤'}`);
35
35
  }
36
36
 
37
37
  /**
38
- * 解析 JSON 响应
38
+ * 解析 JSON 回應
39
39
  */
40
40
  static parseJSON(content) {
41
- // 移除可能的 markdown code block 标记
41
+ // 移除可能的 markdown code block 標記
42
42
  const jsonContent = content.replace(/```json\n?/g, '').replace(/```\n?/g, '').trim();
43
43
 
44
44
  try {
45
45
  return JSON.parse(jsonContent);
46
46
  } catch (error) {
47
- throw new Error(`无法解析 AI 回应为 JSON: ${error.message}`);
47
+ throw new Error(`無法解析 AI 回應為 JSON: ${error.message}`);
48
48
  }
49
49
  }
50
50
  }
@@ -1,14 +1,14 @@
1
1
  /**
2
- * 配置加载器
3
- * 基于 scripts/commit-modules/config-loader.mjs 和 scripts/ai-pr-modules/core/config-loader.mjs
4
- * 支持从任何目录下的 .ai-git-config.mjs 加载配置
2
+ * 配置載入器
3
+ * 基於 scripts/commit-modules/config-loader.mjs 和 scripts/ai-pr-modules/core/config-loader.mjs
4
+ * 支援從任何目錄下的 .ai-git-config.mjs 載入配置
5
5
  */
6
6
 
7
7
  import { existsSync } from 'fs';
8
8
  import { resolve } from 'path';
9
9
 
10
10
  /**
11
- * 解析命令行参数
11
+ * 解析命令行參數
12
12
  */
13
13
  export function parseCliArgs() {
14
14
  const args = process.argv.slice(2);
@@ -43,11 +43,11 @@ export function parseCliArgs() {
43
43
  }
44
44
 
45
45
  /**
46
- * 加载配置(commit 工具使用)
47
- * 支持从当前工作目录或用户项目目录加载 .ai-git-config.mjs
46
+ * 載入配置(commit 工具使用)
47
+ * 支援從目前工作目錄或使用者專案目錄載入 .ai-git-config.mjs
48
48
  */
49
49
  export async function loadCommitConfig() {
50
- // 内建默认值
50
+ // 內建預設值
51
51
  const defaults = {
52
52
  ai: {
53
53
  model: 'gpt-4.1',
@@ -60,7 +60,7 @@ export async function loadCommitConfig() {
60
60
  },
61
61
  };
62
62
 
63
- // 尝试从当前工作目录加载配置文件
63
+ // 嘗試從目前工作目錄載入配置檔案
64
64
  const configPath = resolve(process.cwd(), '.ai-git-config.mjs');
65
65
  let userConfig = {};
66
66
 
@@ -69,11 +69,11 @@ export async function loadCommitConfig() {
69
69
  const imported = await import(`file://${configPath}`);
70
70
  userConfig = imported.default || {};
71
71
  } catch (error) {
72
- console.warn(`⚠️ 加载配置文件失败: ${error.message}`);
72
+ console.warn(`⚠️ 載入配置檔案失敗: ${error.message}`);
73
73
  }
74
74
  }
75
75
 
76
- // 合并配置
76
+ // 合併配置
77
77
  const config = {
78
78
  ai: {
79
79
  model: userConfig.ai?.model ?? defaults.ai.model,
@@ -86,7 +86,7 @@ export async function loadCommitConfig() {
86
86
  },
87
87
  };
88
88
 
89
- // 命令行参数优先
89
+ // 命令行參數優先
90
90
  const cliConfig = parseCliArgs();
91
91
  if (cliConfig.model) config.ai.model = cliConfig.model;
92
92
  if (cliConfig.verbose) config.output.verbose = cliConfig.verbose;
@@ -97,7 +97,7 @@ export async function loadCommitConfig() {
97
97
  }
98
98
 
99
99
  /**
100
- * 解析 PR 命令行参数
100
+ * 解析 PR 命令行參數
101
101
  */
102
102
  export function parsePRCliArgs() {
103
103
  const args = process.argv.slice(2);
@@ -154,10 +154,10 @@ export function parsePRCliArgs() {
154
154
  }
155
155
 
156
156
  /**
157
- * 加载 PR 配置
157
+ * 載入 PR 配置
158
158
  */
159
159
  export async function loadPRConfig() {
160
- // 尝试从当前工作目录加载配置文件
160
+ // 嘗試從目前工作目錄載入配置檔案
161
161
  const configPath = resolve(process.cwd(), '.ai-git-config.mjs');
162
162
  let config = null;
163
163
 
@@ -166,11 +166,11 @@ export async function loadPRConfig() {
166
166
  const userConfig = await import(`file://${configPath}`);
167
167
  config = userConfig.default;
168
168
  } catch (error) {
169
- console.warn(`⚠️ 加载配置文件失败: ${error.message}`);
169
+ console.warn(`⚠️ 載入配置檔案失敗: ${error.message}`);
170
170
  }
171
171
  }
172
172
 
173
- // 使用默认配置
173
+ // 使用預設配置
174
174
  if (!config) {
175
175
  config = {
176
176
  ai: { model: 'gpt-4.1', maxDiffLength: 8000, maxRetries: 3 },
@@ -180,7 +180,7 @@ export async function loadPRConfig() {
180
180
  };
181
181
  }
182
182
 
183
- // 合并命令行参数
183
+ // 合併命令行參數
184
184
  const cliConfig = parsePRCliArgs();
185
185
  if (cliConfig.model) config.ai.model = cliConfig.model;
186
186
  if (cliConfig.orgName) config.github.orgName = cliConfig.orgName;
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Git 操作封装
3
- * 基于 scripts/ai-pr-modules/core/git-operations.mjs
2
+ * Git 操作封裝
3
+ * 基於 scripts/ai-pr-modules/core/git-operations.mjs
4
4
  */
5
5
 
6
6
  import { execSync } from 'child_process';
@@ -10,7 +10,7 @@ const DIFF_CONTEXT_LINES = 50;
10
10
 
11
11
  export class GitOperations {
12
12
  /**
13
- * 执行 Git 命令
13
+ * 執行 Git 命令
14
14
  */
15
15
  static exec(command, options = {}) {
16
16
  try {
@@ -30,7 +30,7 @@ export class GitOperations {
30
30
  }
31
31
 
32
32
  /**
33
- * 检查是否在 Git 仓库中
33
+ * 檢查是否在 Git 倉庫中
34
34
  */
35
35
  static isGitRepository() {
36
36
  try {
@@ -42,21 +42,21 @@ export class GitOperations {
42
42
  }
43
43
 
44
44
  /**
45
- * 获取当前分支
45
+ * 獲取目前分支
46
46
  */
47
47
  static getCurrentBranch() {
48
48
  return GitOperations.exec('git rev-parse --abbrev-ref HEAD', { silent: true });
49
49
  }
50
50
 
51
51
  /**
52
- * 获取 staged diff
52
+ * 獲取 staged diff
53
53
  */
54
54
  static getStagedDiff() {
55
55
  return GitOperations.exec('git diff --staged', { silent: true });
56
56
  }
57
57
 
58
58
  /**
59
- * 侦测可用的 release 分支
59
+ * 偵測可用的 release 分支
60
60
  */
61
61
  static detectReleaseBranches() {
62
62
  try {
@@ -89,7 +89,7 @@ export class GitOperations {
89
89
  }
90
90
 
91
91
  /**
92
- * 获取变更的文件列表
92
+ * 獲取變更的檔案列表
93
93
  */
94
94
  static getChangedFiles(baseBranch, headBranch) {
95
95
  try {
@@ -105,7 +105,7 @@ export class GitOperations {
105
105
  }
106
106
 
107
107
  /**
108
- * 获取 commit 列表
108
+ * 獲取 commit 列表
109
109
  */
110
110
  static getCommits(baseBranch, headBranch) {
111
111
  try {
@@ -113,12 +113,12 @@ export class GitOperations {
113
113
  encoding: 'utf-8',
114
114
  });
115
115
  } catch (error) {
116
- throw new Error(`无法比较分支差异: ${error.message}`);
116
+ throw new Error(`無法比較分支差異: ${error.message}`);
117
117
  }
118
118
  }
119
119
 
120
120
  /**
121
- * 获取 diff
121
+ * 獲取 diff
122
122
  */
123
123
  static getDiff(baseBranch, headBranch) {
124
124
  try {
@@ -127,21 +127,21 @@ export class GitOperations {
127
127
  maxBuffer: MAX_BUFFER_SIZE,
128
128
  });
129
129
  } catch (error) {
130
- // 尝试替代方案
130
+ // 嘗試替代方案
131
131
  try {
132
132
  return execSync(`git diff origin/${baseBranch}..${headBranch}`, {
133
133
  encoding: 'utf-8',
134
134
  maxBuffer: MAX_BUFFER_SIZE,
135
135
  });
136
136
  } catch (fallbackError) {
137
- throw new Error(`无法获取分支差异: ${error.message}`);
137
+ throw new Error(`無法獲取分支差異: ${error.message}`);
138
138
  }
139
139
  }
140
140
  }
141
141
 
142
142
  /**
143
- * 智能截断 diff
144
- * 保留前后各 50 行,中间用省略标记
143
+ * 智能截斷 diff
144
+ * 保留前後各 50 行,中間用省略標記
145
145
  */
146
146
  static truncateDiff(diff, maxLength = 8000) {
147
147
  if (diff.length <= maxLength) return diff;
@@ -157,23 +157,23 @@ export class GitOperations {
157
157
  const footer = lines.slice(-contextLines).join('\n');
158
158
  const omittedLines = lines.length - contextLines * 2;
159
159
 
160
- return `${header}\n\n... [已省略 ${omittedLines} 行变更] ...\n\n${footer}`;
160
+ return `${header}\n\n... [已省略 ${omittedLines} 行變更] ...\n\n${footer}`;
161
161
  }
162
162
 
163
163
  /**
164
- * 推送到远端
164
+ * 推送到遠端
165
165
  */
166
166
  static push(branch) {
167
167
  try {
168
168
  execSync(`git push -u origin ${branch}`, { stdio: 'inherit' });
169
169
  return true;
170
170
  } catch (error) {
171
- throw new Error(`推送失败: ${error.message}`);
171
+ throw new Error(`推送失敗: ${error.message}`);
172
172
  }
173
173
  }
174
174
 
175
175
  /**
176
- * 同步远端信息
176
+ * 同步遠端資訊
177
177
  */
178
178
  static fetch() {
179
179
  try {
@@ -185,7 +185,7 @@ export class GitOperations {
185
185
  }
186
186
 
187
187
  /**
188
- * 获取变更统计
188
+ * 獲取變更統計
189
189
  */
190
190
  static getChangeStats(baseBranch, headBranch) {
191
191
  try {
@@ -200,7 +200,7 @@ export class GitOperations {
200
200
 
201
201
  return { stats, filesChanged: parseInt(filesChanged, 10) };
202
202
  } catch (error) {
203
- return { stats: '无法获取统计', filesChanged: 0 };
203
+ return { stats: '無法獲取統計', filesChanged: 0 };
204
204
  }
205
205
  }
206
206
  }
@@ -1,41 +1,41 @@
1
1
  /**
2
- * Helper 工具函数
3
- * 基于 scripts/ai-pr-modules/utils/helpers.mjs
2
+ * Helper 工具函式
3
+ * 基於 scripts/ai-pr-modules/utils/helpers.mjs
4
4
  */
5
5
 
6
6
  /**
7
7
  * 清理 commit message
8
- * 移除 markdown 代码块标记
8
+ * 移除 markdown 程式碼區塊標記
9
9
  */
10
10
  export function cleanCommitMessage(message) {
11
11
  if (!message) return '';
12
12
 
13
13
  let cleaned = message.trim();
14
14
 
15
- // 移除 markdown 代码块标记
15
+ // 移除 markdown 程式碼區塊標記
16
16
  cleaned = cleaned.replace(/^```[\w]*\n/gm, '');
17
17
  cleaned = cleaned.replace(/\n```$/gm, '');
18
18
  cleaned = cleaned.replace(/^```$/gm, '');
19
19
 
20
- // 移除开头和结尾的引号
20
+ // 移除開頭和結尾的引號
21
21
  cleaned = cleaned.replace(/^["']|["']$/g, '');
22
22
 
23
23
  return cleaned.trim();
24
24
  }
25
25
 
26
26
  /**
27
- * 验证 commit message
27
+ * 驗證 commit message
28
28
  */
29
29
  export function validateCommitMessage(message) {
30
30
  if (!message || message.length === 0) {
31
- return { valid: false, reason: 'Commit message 为空' };
31
+ return { valid: false, reason: 'Commit message 為空' };
32
32
  }
33
33
 
34
34
  if (message.length < 5) {
35
- return { valid: false, reason: 'Commit message 太短(少于 5 个字元)' };
35
+ return { valid: false, reason: 'Commit message 太短(少於 5 個字元)' };
36
36
  }
37
37
 
38
- // 检查是否只包含特殊字符或空白
38
+ // 檢查是否只包含特殊字元或空白
39
39
  if (!/[a-zA-Z0-9\u4e00-\u9fa5]/.test(message)) {
40
40
  return { valid: false, reason: 'Commit message 不包含有效字元' };
41
41
  }
@@ -44,26 +44,26 @@ export function validateCommitMessage(message) {
44
44
  }
45
45
 
46
46
  /**
47
- * 错误处理
47
+ * 錯誤處理
48
48
  */
49
49
  export function handleError(error) {
50
- console.error('\n❌ 错误:', error.message);
50
+ console.error('\n❌ 錯誤:', error.message);
51
51
 
52
52
  if (error.suggestions && error.suggestions.length > 0) {
53
- console.log('\n💡 建议解决方案:');
53
+ console.log('\n💡 建議解決方案:');
54
54
  error.suggestions.forEach((suggestion, index) => {
55
55
  console.log(` ${index + 1}. ${suggestion}`);
56
56
  });
57
57
  }
58
58
 
59
59
  if (error.stack && process.env.VERBOSE) {
60
- console.error('\n堆栈追踪:');
60
+ console.error('\n堆疊追蹤:');
61
61
  console.error(error.stack);
62
62
  }
63
63
  }
64
64
 
65
65
  /**
66
- * 获取项目类型提示(用于 AI prompt)
66
+ * 獲取專案類型提示(用於 AI prompt)
67
67
  */
68
68
  export function getProjectTypePrompt() {
69
69
  return `你是一個資深前端工程師,熟悉 Next.js 專案的開發規範。
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Logger 工具
3
- * 基于 scripts/ai-pr-modules/ui/logger.mjs
3
+ * 基於 scripts/ai-pr-modules/ui/logger.mjs
4
4
  */
5
5
 
6
6
  const colors = {