ai-git-tools 2.0.19 → 2.0.21

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 CHANGED
@@ -163,6 +163,7 @@ npx ai-git-tools pr [選項]
163
163
  --no-confirm 跳過確認直接創建
164
164
  --interactive-reviewers 啟用互動式 reviewer 選擇 (預設啟用)
165
165
  --auto-labels 自動添加 Labels (預設啟用)
166
+ --include-impact 在 PR 中包含影響範圍分析和注意事項 (預設關閉)
166
167
  \`\`\`
167
168
 
168
169
  **範例:**
@@ -211,8 +212,9 @@ export default {
211
212
 
212
213
  // GitHub 設定
213
214
  github: {
214
- defaultBase: 'release', // 預設目標分支
215
+ defaultBase: 'release', // 預設目標分支:'release'=自動查找最新,或指定具體分支名
215
216
  autoLabels: true, // 自動添加 Labels
217
+ includeImpactAnalysis: false, // 是否在 PR 中包含影響範圍分析和注意事項 (使用 --include-impact 啟用)
216
218
  },
217
219
 
218
220
  // Reviewer 設定
@@ -231,6 +233,44 @@ export default {
231
233
  };
232
234
  \`\`\`
233
235
 
236
+ ### defaultBase 配置說明
237
+
238
+ \`defaultBase\` 支援兩種模式:
239
+
240
+ #### 1. 自動模式(推薦)
241
+ ```javascript
242
+ github: {
243
+ defaultBase: 'release', // 自動查找最新的 release 分支
244
+ }
245
+ ```
246
+ - 工具會自動偵測所有 \`release-*\` 或 \`release/*\` 格式的分支
247
+ - 自動選擇最新版本(優先選擇月度分支,如 release-2025-m12.1)
248
+ - 適合經常更新 release 版本的專案
249
+
250
+ #### 2. 具體分支模式
251
+ ```javascript
252
+ github: {
253
+ defaultBase: 'release-2025-m12.1', // 固定使用此分支
254
+ }
255
+ ```
256
+ - 直接使用指定的分支名稱
257
+ - 適合需要固定某個版本的情況
258
+ - 或使用 \`main\`、\`develop\` 等標準分支
259
+
260
+ **範例輸出**:
261
+ ```bash
262
+ # 使用 defaultBase: 'release'
263
+ 配置檔指定使用 release 分支,正在偵測最新版本...
264
+ 📋 偵測到的 release 分支:
265
+ 月度分支 (優先):
266
+ 1. release-2025-m12.1 ← 最新
267
+ 2. release-2025-m11.1
268
+ ✅ 自動選擇最新 release 分支: release-2025-m12.1
269
+
270
+ # 使用 defaultBase: 'release-2025-m12.1'
271
+ ✅ 使用配置檔指定的分支: release-2025-m12.1
272
+ ```
273
+
234
274
  ## 🔧 環境需求
235
275
 
236
276
  - **Node.js** >= 18.0.0
package/bin/cli.js CHANGED
@@ -52,11 +52,10 @@ program
52
52
  .description('AI 自動生成 PR 並創建 Pull Request')
53
53
  .option('--base <branch>', '指定目標分支')
54
54
  .option('--model <model>', '指定 AI 模型')
55
- .option('--org <org-name>', '指定 GitHub 組織名稱')
56
55
  .option('--preview', '僅預覽 PR 內容,不實際創建')
57
56
  .option('--no-confirm', '跳過確認直接創建')
58
- .option('--auto-labels', '自動添加 Labels')
59
- .option('--no-labels', '不添加 Labels')
57
+ .option('--auto-labels', '自動添加 Labels (預設啟用)')
58
+ .option('--include-impact', ' PR 中包含影響範圍分析和注意事項 (預設關閉)')
60
59
  .action(prCommand);
61
60
 
62
61
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-git-tools",
3
- "version": "2.0.19",
3
+ "version": "2.0.21",
4
4
  "description": "AI-powered Git automation tools for commit messages and PR generation",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -23,9 +23,9 @@ export default {
23
23
 
24
24
  // GitHub 相關配置
25
25
  github: {
26
- orgName: '', // GitHub 組織名稱(留空則自動從 git remote 取得)
27
- defaultBase: 'release', // PR分支(使用 'release' 自動偵測最新 release 分支,如 release-2025-m11.1)
26
+ defaultBase: 'release', // PR 預設目標分支(使用 'release' 自動偵測最新 release 分支,如 release-2025-m11.1)
28
27
  autoLabels: true, // 自動新增 Labels
28
+ includeImpactAnalysis: false, // 是否在 PR 中包含影響範圍分析和注意事項(使用 --include-impact 啟用)
29
29
  },
30
30
 
31
31
  // Reviewers 相關配置
@@ -4,7 +4,6 @@
4
4
  * 支援從任何目錄下的 .ai-git-config.mjs 載入配置
5
5
  */
6
6
 
7
- import { execSync } from 'child_process';
8
7
  import { existsSync } from 'fs';
9
8
  import { resolve } from 'path';
10
9
 
@@ -111,7 +110,6 @@ export function parsePRCliArgs() {
111
110
  noConfirm: false,
112
111
  autoReviewers: false,
113
112
  autoLabels: null,
114
- orgName: null,
115
113
  };
116
114
 
117
115
  for (let i = 0; i < args.length; i++) {
@@ -122,9 +120,6 @@ export function parsePRCliArgs() {
122
120
  case '--model':
123
121
  config.model = args[++i];
124
122
  break;
125
- case '--org':
126
- config.orgName = args[++i];
127
- break;
128
123
  case '--preview':
129
124
  config.preview = true;
130
125
  break;
@@ -134,9 +129,6 @@ export function parsePRCliArgs() {
134
129
  case '--auto-labels':
135
130
  config.autoLabels = true;
136
131
  break;
137
- case '--no-labels':
138
- config.autoLabels = false;
139
- break;
140
132
  default:
141
133
  break;
142
134
  }
@@ -166,31 +158,20 @@ export async function loadPRConfig() {
166
158
  if (!config) {
167
159
  config = {
168
160
  ai: { model: 'gpt-4.1', maxDiffLength: 8000, maxRetries: 3 },
169
- github: { orgName: '', defaultBase: 'release', autoLabels: true },
161
+ github: { defaultBase: 'release', autoLabels: true },
170
162
  reviewers: { autoSelect: true, maxSuggested: 5, gitHistoryDepth: 20, excludeAuthors: [] },
171
163
  output: { verbose: false, saveHistory: false },
172
164
  };
173
165
  }
174
166
 
175
- // 如果 orgName 為空,嘗試從 git remote 取得,否則使用 'kingsinfo-project'
176
- if (!config.github.orgName) {
177
- try {
178
- const remoteUrl = execSync('git config --get remote.origin.url', { encoding: 'utf-8' }).trim();
179
- const match = remoteUrl.match(/github\.com[:/]([^/]+)\//);
180
- config.github.orgName = match ? match[1] : 'kingsinfo-project';
181
- } catch (error) {
182
- config.github.orgName = 'kingsinfo-project';
183
- }
167
+ // 確保 github 物件存在
168
+ if (!config.github) {
169
+ config.github = {};
184
170
  }
185
171
 
186
172
  // 合併命令行參數
187
173
  const cliConfig = parsePRCliArgs();
188
174
  if (cliConfig.model) config.ai.model = cliConfig.model;
189
- if (cliConfig.orgName) config.github.orgName = cliConfig.orgName;
190
- if (cliConfig.autoReviewers) config.reviewers.autoSelect = cliConfig.autoReviewers;
191
- if (cliConfig.autoLabels !== null) config.github.autoLabels = cliConfig.autoLabels;
192
-
193
- config.baseBranch = cliConfig.baseBranch;
194
175
  config.headBranch = cliConfig.headBranch;
195
176
  config.draft = cliConfig.draft;
196
177
  config.preview = cliConfig.preview;
@@ -123,7 +123,7 @@ ${skillsSummary}
123
123
  - [ ] ⚡ 效能改進 (perf)
124
124
  - [ ] 🔧 其他 (chore)
125
125
 
126
- > 請根據實際變更勾選對應的類型(可複選)
126
+ > **重要**: 請根據實際變更**自動勾選**對應的類型(可複選),將 [ ] 改為 [x]
127
127
 
128
128
  ## 🧪 測試方法
129
129
  1. [具體的測試步驟 1]
@@ -14,6 +14,7 @@ export function parseCliArgs() {
14
14
  noConfirm: false,
15
15
  interactiveReviewers: undefined,
16
16
  autoLabels: null,
17
+ includeImpactAnalysis: null,
17
18
  };
18
19
 
19
20
  for (let i = 0; i < args.length; i++) {
@@ -39,6 +40,9 @@ export function parseCliArgs() {
39
40
  case '--auto-labels':
40
41
  config.autoLabels = true;
41
42
  break;
43
+ case '--include-impact':
44
+ config.includeImpactAnalysis = true;
45
+ break;
42
46
  case '--help':
43
47
  showHelp();
44
48
  process.exit(0);
@@ -67,7 +71,7 @@ export async function loadConfig() {
67
71
  // 使用內建預設值
68
72
  config = {
69
73
  ai: { model: 'gpt-4.1', maxDiffLength: 8000, maxRetries: 3 },
70
- github: { defaultBase: 'release', autoLabels: true },
74
+ github: { defaultBase: 'release', autoLabels: true, includeImpactAnalysis: false },
71
75
  reviewers: { interactiveReviewers: true, maxSuggested: 5, gitHistoryDepth: 20, excludeAuthors: [] },
72
76
  output: { verbose: false, saveHistory: false },
73
77
  };
@@ -80,6 +84,7 @@ export async function loadConfig() {
80
84
  if (cliConfig.model) config.ai.model = cliConfig.model;
81
85
  if (cliConfig.interactiveReviewers !== undefined) config.reviewers.interactiveReviewers = cliConfig.interactiveReviewers;
82
86
  if (cliConfig.autoLabels !== null) config.github.autoLabels = cliConfig.autoLabels;
87
+ if (cliConfig.includeImpactAnalysis !== null) config.github.includeImpactAnalysis = cliConfig.includeImpactAnalysis;
83
88
 
84
89
  // 其他 CLI 參數直接加入 config
85
90
  config.baseBranch = cliConfig.baseBranch;
@@ -113,13 +113,6 @@ export class GitHubAPI {
113
113
  * 從 GitHub 抓取組織的團隊列表
114
114
  */
115
115
  async fetchTeams(orgName = this.orgName) {
116
- // 如果沒有 orgName,直接返回空結果
117
- if (!orgName || orgName.trim() === '') {
118
- log.warning('未設置 GitHub 組織名稱,且無法自動偵測');
119
- log.info('請在 .ai-pr-config.js 中設置 github.orgName 或使用 --org 參數\n');
120
- return { teams: {}, members: [] };
121
- }
122
-
123
116
  try {
124
117
  // 先檢查認證狀態
125
118
  const authStatus = this.checkAuth();
@@ -198,8 +191,7 @@ export class GitHubAPI {
198
191
  console.log(' 1. 已安裝 GitHub CLI: brew install gh');
199
192
  console.log(' 2. 已執行認證: gh auth login');
200
193
  console.log(' 3. 選擇正確的認證範圍(需要 read:org 權限)');
201
- console.log(` 4. 有權限存取 ${orgName} 組織`);
202
- console.log(' 5. 組織名稱正確(可用 --org 參數指定)\n');
194
+ console.log(` 4. 有權限存取 ${orgName} 組織\n`);
203
195
 
204
196
  log.info('提示: 你仍可以手動輸入 reviewer 的 GitHub username\n');
205
197
 
@@ -101,8 +101,31 @@ export class PRWorkflow {
101
101
  if (!baseBranch) {
102
102
  // 優先使用配置檔中的 defaultBase
103
103
  if (this.config.github?.defaultBase) {
104
- baseBranch = this.config.github.defaultBase;
105
- log.success(`使用配置檔指定的分支: ${baseBranch}\n`);
104
+ const defaultBase = this.config.github.defaultBase;
105
+
106
+ // 如果 defaultBase 是 'release',則自動查找最新的 release 分支
107
+ if (defaultBase === 'release' || defaultBase.match(/^release$/i)) {
108
+ log.step('配置檔指定使用 release 分支,正在偵測最新版本...\n');
109
+ const allBranches = this.git.detectReleaseBranches();
110
+ const latestRelease = this.git.findLatestReleaseBranch();
111
+
112
+ if (latestRelease) {
113
+ baseBranch = latestRelease;
114
+ this.displayDetectedBranches(allBranches, latestRelease);
115
+ log.success(`自動選擇最新 release 分支: ${baseBranch}`);
116
+ log.info(`提示: 使用 --base <分支名> 指定其他分支\n`);
117
+ } else {
118
+ throw new PRError('未偵測到任何 release 分支', 'NO_RELEASE_BRANCH', [
119
+ '使用 --base 參數指定目標分支',
120
+ '或在 .ai-git-config.js 中設置具體的分支名(如 release-2025-m12.1)',
121
+ '確認遠端分支存在: git branch -r | grep release',
122
+ ]);
123
+ }
124
+ } else {
125
+ // 使用配置檔中指定的具體分支名
126
+ baseBranch = defaultBase;
127
+ log.success(`使用配置檔指定的分支: ${baseBranch}\n`);
128
+ }
106
129
  } else {
107
130
  // 如果沒有配置,則自動偵測最新的 release 分支
108
131
  log.step('正在偵測 release 分支...\n');
@@ -263,19 +286,27 @@ export class PRWorkflow {
263
286
  // 生成 PR 標題和描述
264
287
  const { title, body } = await this.ai.generatePRContent(changeData.commits, changeData.diff);
265
288
 
266
- // 分析影響範圍
267
- log.step('正在使用 AI 深度分析影響範圍和潛在問題...\n');
268
- const { blastRadius, warnings } = await this.ai.analyzeImpact(
269
- changeData.changedFiles,
270
- changeData.diff,
271
- changeData.commits
272
- );
289
+ let enhancedBody = body;
290
+ let blastRadius = null;
291
+ let warnings = [];
292
+
293
+ // 根據配置決定是否進行影響範圍分析
294
+ if (this.config.github.includeImpactAnalysis === true) {
295
+ log.step('正在使用 AI 深度分析影響範圍和潛在問題...\n');
296
+ const analysis = await this.ai.analyzeImpact(
297
+ changeData.changedFiles,
298
+ changeData.diff,
299
+ changeData.commits
300
+ );
301
+ blastRadius = analysis.blastRadius;
302
+ warnings = analysis.warnings;
273
303
 
274
- // 顯示分析結果摘要
275
- this.displayAnalysisSummary(blastRadius, warnings);
304
+ // 顯示分析結果摘要
305
+ this.displayAnalysisSummary(blastRadius, warnings);
276
306
 
277
- // 將分析結果附加到 body
278
- const enhancedBody = this.ai.appendAnalysisToBody(body, blastRadius, warnings);
307
+ // 將分析結果附加到 body
308
+ enhancedBody = this.ai.appendAnalysisToBody(body, blastRadius, warnings);
309
+ }
279
310
 
280
311
  return { title, body: enhancedBody, blastRadius, warnings };
281
312
  }