ai-git-tools 2.0.20 → 2.0.22
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 +2 -0
- package/bin/cli.js +2 -3
- package/package.json +1 -1
- package/src/commands/init.js +3 -3
- package/src/core/config-loader.js +4 -23
- package/src/pr-modules/ai/code-analyzer.js +19 -1
- package/src/pr-modules/core/config-loader.js +6 -1
- package/src/pr-modules/core/github-api.js +1 -9
- package/src/pr-modules/core/workflow.js +19 -11
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
|
**範例:**
|
|
@@ -213,6 +214,7 @@ export default {
|
|
|
213
214
|
github: {
|
|
214
215
|
defaultBase: 'release', // 預設目標分支:'release'=自動查找最新,或指定具體分支名
|
|
215
216
|
autoLabels: true, // 自動添加 Labels
|
|
217
|
+
includeImpactAnalysis: false, // 是否在 PR 中包含影響範圍分析和注意事項 (使用 --include-impact 啟用)
|
|
216
218
|
},
|
|
217
219
|
|
|
218
220
|
// Reviewer 設定
|
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('--
|
|
57
|
+
.option('--auto-labels', '自動添加 Labels (預設啟用)')
|
|
58
|
+
.option('--include-impact', '在 PR 中包含影響範圍分析和注意事項 (預設關閉)')
|
|
60
59
|
.action(prCommand);
|
|
61
60
|
|
|
62
61
|
program.parse();
|
package/package.json
CHANGED
package/src/commands/init.js
CHANGED
|
@@ -23,9 +23,9 @@ export default {
|
|
|
23
23
|
|
|
24
24
|
// GitHub 相關配置
|
|
25
25
|
github: {
|
|
26
|
-
|
|
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 相關配置
|
|
@@ -38,7 +38,7 @@ export default {
|
|
|
38
38
|
|
|
39
39
|
// 輸出相關配置
|
|
40
40
|
output: {
|
|
41
|
-
verbose:
|
|
41
|
+
verbose: true, // 詳細輸出
|
|
42
42
|
},
|
|
43
43
|
};
|
|
44
44
|
`;
|
|
@@ -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: {
|
|
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
|
-
//
|
|
176
|
-
if (!config.github
|
|
177
|
-
|
|
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;
|
|
@@ -105,6 +105,7 @@ ${skillsSummary}
|
|
|
105
105
|
# [type]: [PR 標題]
|
|
106
106
|
|
|
107
107
|
> type 必須是以下之一:feat / fix / refactor / style / docs / test / chore / perf
|
|
108
|
+
> **重要**:如果有新增任何功能、新增檔案、新增 API、新增組件,優先使用 **feat**
|
|
108
109
|
|
|
109
110
|
## 📝 變更摘要
|
|
110
111
|
[簡述這個 PR 的主要目的和影響範圍,2-3 句話]
|
|
@@ -123,7 +124,18 @@ ${skillsSummary}
|
|
|
123
124
|
- [ ] ⚡ 效能改進 (perf)
|
|
124
125
|
- [ ] 🔧 其他 (chore)
|
|
125
126
|
|
|
126
|
-
>
|
|
127
|
+
> **重要**: 請仔細分析 diff 和 commit 訊息,**自動勾選**對應的類型(可複選),將 [ ] 改為 [x]
|
|
128
|
+
>
|
|
129
|
+
> **判斷準則**:
|
|
130
|
+
> - ✨ **新功能 (feat)**: 新增檔案、新增 API、新增組件、新增功能邏輯、新增配置選項
|
|
131
|
+
> - 🐛 **Bug 修復 (fix)**: 修復錯誤、修正邏輯問題
|
|
132
|
+
> - ♻️ **重構 (refactor)**: 重組程式碼結構但不改變功能
|
|
133
|
+
> - 💄 **樣式調整 (style)**: UI/CSS 調整、格式化
|
|
134
|
+
> - 📝 **文件更新 (docs)**: README、註解、文檔變更
|
|
135
|
+
> - ⚡ **效能改進 (perf)**: 優化效能
|
|
136
|
+
> - 🔧 **其他 (chore)**: 建構工具、依賴更新、配置調整
|
|
137
|
+
>
|
|
138
|
+
> **特別注意**: 如果 diff 中有「新增檔案」或「新增功能」,**務必勾選** ✨ 新功能 (feat)
|
|
127
139
|
|
|
128
140
|
## 🧪 測試方法
|
|
129
141
|
1. [具體的測試步驟 1]
|
|
@@ -166,6 +178,12 @@ ${skillsSummary}
|
|
|
166
178
|
4. 全部使用繁體中文(台灣正體)
|
|
167
179
|
5. 不要在開頭加引導語句
|
|
168
180
|
6. 直接開始輸出 # [type]: [標題]
|
|
181
|
+
7. **變更類型判斷必須準確**:
|
|
182
|
+
- 檢查 diff 中是否有 "new file mode" 或大量 "+++" 行(表示新增檔案)
|
|
183
|
+
- 檢查 commit 訊息是否包含「新增」、「add」、「feat」等關鍵字
|
|
184
|
+
- 檢查主要變更列表,如果提到「新增 xxx」就必須勾選 ✨ 新功能 (feat)
|
|
185
|
+
- 新增配置檔、新增組件、新增 API、新增功能都算 feat
|
|
186
|
+
- 一個 PR 可以同時是多種類型(如:feat + refactor + chore)
|
|
169
187
|
|
|
170
188
|
---
|
|
171
189
|
|
|
@@ -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
|
|
|
@@ -286,19 +286,27 @@ export class PRWorkflow {
|
|
|
286
286
|
// 生成 PR 標題和描述
|
|
287
287
|
const { title, body } = await this.ai.generatePRContent(changeData.commits, changeData.diff);
|
|
288
288
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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;
|
|
296
303
|
|
|
297
|
-
|
|
298
|
-
|
|
304
|
+
// 顯示分析結果摘要
|
|
305
|
+
this.displayAnalysisSummary(blastRadius, warnings);
|
|
299
306
|
|
|
300
|
-
|
|
301
|
-
|
|
307
|
+
// 將分析結果附加到 body
|
|
308
|
+
enhancedBody = this.ai.appendAnalysisToBody(body, blastRadius, warnings);
|
|
309
|
+
}
|
|
302
310
|
|
|
303
311
|
return { title, body: enhancedBody, blastRadius, warnings };
|
|
304
312
|
}
|