gitlab-ai-review 2.5.3 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -0
- package/cli.js +72 -59
- package/index.js +158 -48
- package/lib/diff-parser.js +0 -31
- package/lib/gitlab-client.js +69 -0
- package/lib/impact-analyzer.js +455 -0
- package/lib/prompt-tools.js +219 -64
- package/package.json +17 -4
package/lib/prompt-tools.js
CHANGED
|
@@ -28,90 +28,244 @@ export function buildSystemPrompt(projectPrompt = '') {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
31
|
+
* 构建整个文件所有变更行的批量审查提示词
|
|
32
32
|
* @param {string} fileName - 文件名
|
|
33
33
|
* @param {Array} meaningfulChanges - 有意义的变更数组
|
|
34
|
-
* @param {Array} hunkGroups - 按 hunk 分组的变更数组
|
|
35
34
|
* @param {string} projectPrompt - 项目配置的 prompt
|
|
36
35
|
* @returns {string} 批量审查提示词
|
|
37
36
|
*/
|
|
38
|
-
export function buildFileReviewPrompt(fileName, meaningfulChanges
|
|
39
|
-
|
|
40
|
-
const totalDeletions = meaningfulChanges.filter(c => c.type === 'deletion').length;
|
|
41
|
-
|
|
42
|
-
let prompt = `请审查以下文件的代码变更,只对**有问题的新增行**提出审查意见。
|
|
37
|
+
export function buildFileReviewPrompt(fileName, meaningfulChanges) {
|
|
38
|
+
let prompt = `请审查以下文件的代码变更,只对**有问题的行**提出审查意见,代码没有问题的行不需要评论。
|
|
43
39
|
|
|
44
40
|
**文件名**: ${fileName}
|
|
45
|
-
|
|
46
|
-
- 共 ${hunkGroups.length} 个代码块(hunk)
|
|
47
|
-
- 删除了 ${totalDeletions} 行(旧代码)
|
|
48
|
-
- 新增了 ${totalAdditions} 行(新代码)
|
|
41
|
+
**变更数量**: ${meaningfulChanges.length} 行
|
|
49
42
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
-
|
|
54
|
-
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
meaningfulChanges.forEach((change, index) => {
|
|
46
|
+
prompt += `\n### 变更 ${index + 1} - 第 ${change.lineNumber} 行\n`;
|
|
47
|
+
prompt += `**类型**: ${change.type === 'addition' ? '新增' : '删除'}\n`;
|
|
48
|
+
prompt += `**内容**:\n\`\`\`\n`;
|
|
49
|
+
|
|
50
|
+
// 上下文
|
|
51
|
+
if (change.context?.before?.length > 0) {
|
|
52
|
+
change.context.before.forEach(line => {
|
|
53
|
+
prompt += ` ${line}\n`;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 变更行
|
|
58
|
+
prompt += `${change.type === 'addition' ? '+' : '-'} ${change.content}\n`;
|
|
59
|
+
|
|
60
|
+
// 下文
|
|
61
|
+
if (change.context?.after?.length > 0) {
|
|
62
|
+
change.context.after.forEach(line => {
|
|
63
|
+
prompt += ` ${line}\n`;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
prompt += `\`\`\`\n`;
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
prompt += `\n## 审查要求
|
|
71
|
+
|
|
72
|
+
1. 仔细审查每一行变更,判断是否存在问题
|
|
73
|
+
2. **只对有问题的行提出审查意见**,没有问题的行不需要评论
|
|
74
|
+
3. **必须使用中文**返回审查意见
|
|
75
|
+
4. 返回 JSON 格式的结果,格式如下:
|
|
76
|
+
|
|
77
|
+
\`\`\`json
|
|
78
|
+
{
|
|
79
|
+
"reviews": [
|
|
80
|
+
{
|
|
81
|
+
"lineNumber": 15,
|
|
82
|
+
"hasIssue": true,
|
|
83
|
+
"comment": "这里用中文描述具体的问题和改进建议"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"lineNumber": 20,
|
|
87
|
+
"hasIssue": false
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
\`\`\`
|
|
92
|
+
|
|
93
|
+
5. 如果所有代码都没有问题,返回空的 reviews 数组:\`{"reviews": []}\`
|
|
94
|
+
6. 只返回 JSON,不要包含其他文字说明
|
|
95
|
+
7. comment 字段必须使用中文,要简洁明了`;
|
|
55
96
|
|
|
56
|
-
|
|
97
|
+
return prompt;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 构建整个文件批量审查的完整消息数组
|
|
102
|
+
* @param {string} fileName - 文件名
|
|
103
|
+
* @param {Array} meaningfulChanges - 有意义的变更数组
|
|
104
|
+
* @param {string} projectPrompt - 项目配置的 prompt
|
|
105
|
+
* @returns {Array} 消息数组
|
|
106
|
+
*/
|
|
107
|
+
export function buildFileReviewMessages(fileName, meaningfulChanges, projectPrompt = '') {
|
|
108
|
+
return [
|
|
109
|
+
{ role: 'system', content: buildSystemPrompt(projectPrompt) },
|
|
110
|
+
{ role: 'user', content: buildFileReviewPrompt(fileName, meaningfulChanges) },
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 构建包含影响分析的审查提示词
|
|
116
|
+
* @param {string} fileName - 文件名
|
|
117
|
+
* @param {Array} meaningfulChanges - 有意义的变更数组
|
|
118
|
+
* @param {Object} impactAnalysis - 影响分析结果
|
|
119
|
+
* @returns {string} 审查提示词
|
|
120
|
+
*/
|
|
121
|
+
export function buildFileReviewWithImpactPrompt(fileName, meaningfulChanges, impactAnalysis) {
|
|
122
|
+
let prompt = `请审查以下文件的代码变更,只对**有问题的行**提出审查意见,代码没有问题的行不需要评论。
|
|
123
|
+
|
|
124
|
+
**文件名**: ${fileName}
|
|
125
|
+
**变更数量**: ${meaningfulChanges.length} 行
|
|
57
126
|
|
|
58
127
|
`;
|
|
59
128
|
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
prompt +=
|
|
129
|
+
// 添加影响分析信息
|
|
130
|
+
if (impactAnalysis && !impactAnalysis.error) {
|
|
131
|
+
prompt += `\n## 🔍 影响分析\n\n`;
|
|
63
132
|
|
|
64
|
-
//
|
|
65
|
-
if (
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (
|
|
71
|
-
|
|
72
|
-
|
|
133
|
+
// 变更的符号统计
|
|
134
|
+
if (impactAnalysis.changedSymbols) {
|
|
135
|
+
const { added, deleted, modified } = impactAnalysis.changedSymbols;
|
|
136
|
+
|
|
137
|
+
if (added.length > 0 || deleted.length > 0 || modified.length > 0) {
|
|
138
|
+
prompt += `**符号变更统计**:\n`;
|
|
139
|
+
if (added.length > 0) {
|
|
140
|
+
prompt += `- 新增: ${added.length} 个\n`;
|
|
141
|
+
}
|
|
142
|
+
if (deleted.length > 0) {
|
|
143
|
+
prompt += `- 删除: ${deleted.length} 个 ⚠️\n`;
|
|
144
|
+
}
|
|
145
|
+
if (modified.length > 0) {
|
|
146
|
+
prompt += `- 修改: ${modified.length} 个 ⚠️\n`;
|
|
147
|
+
}
|
|
148
|
+
prompt += `\n`;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// 被删除的符号详情
|
|
152
|
+
if (deleted.length > 0) {
|
|
153
|
+
const deletedDefs = deleted.filter(s => s.type === 'definition');
|
|
154
|
+
if (deletedDefs.length > 0) {
|
|
155
|
+
prompt += `**⚠️ 被删除的函数/类/组件** (${deletedDefs.length} 个):\n`;
|
|
156
|
+
deletedDefs.slice(0, 10).forEach(symbol => {
|
|
157
|
+
prompt += `- \`${symbol.name}\`\n`;
|
|
73
158
|
});
|
|
159
|
+
prompt += `\n`;
|
|
74
160
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// 新增或修改的符号
|
|
164
|
+
const changedDefs = [...added, ...modified].filter(s => s.type === 'definition');
|
|
165
|
+
if (changedDefs.length > 0) {
|
|
166
|
+
prompt += `**新增/修改的函数/类/组件** (${changedDefs.length} 个):\n`;
|
|
167
|
+
changedDefs.slice(0, 10).forEach(symbol => {
|
|
168
|
+
prompt += `- \`${symbol.name}\`\n`;
|
|
169
|
+
});
|
|
170
|
+
prompt += `\n`;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// 文件内部使用情况(重要!)
|
|
175
|
+
if (impactAnalysis.internalUsage && impactAnalysis.internalUsage.length > 0) {
|
|
176
|
+
prompt += `**🚨 文件内部冲突** (${impactAnalysis.internalUsage.length} 处):\n`;
|
|
177
|
+
prompt += `当前文件内部仍在使用已删除的符号,将导致运行时错误:\n\n`;
|
|
178
|
+
|
|
179
|
+
impactAnalysis.internalUsage.slice(0, 5).forEach((usage, index) => {
|
|
180
|
+
prompt += `${index + 1}. 第 ${usage.lineNumber} 行使用了被删除的 \`${usage.symbol}\`:\n`;
|
|
181
|
+
prompt += `\`\`\`javascript\n${usage.line}\n\`\`\`\n`;
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
if (impactAnalysis.internalUsage.length > 5) {
|
|
185
|
+
prompt += `... 还有 ${impactAnalysis.internalUsage.length - 5} 处\n`;
|
|
186
|
+
}
|
|
187
|
+
prompt += `\n`;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// 函数签名
|
|
191
|
+
if (impactAnalysis.signatures && impactAnalysis.signatures.length > 0) {
|
|
192
|
+
prompt += `**函数/类签名**:\n`;
|
|
193
|
+
impactAnalysis.signatures.forEach(sig => {
|
|
194
|
+
prompt += `\`\`\`javascript\n${sig.signature}\n\`\`\`\n`;
|
|
78
195
|
});
|
|
196
|
+
prompt += `\n`;
|
|
79
197
|
}
|
|
80
198
|
|
|
81
|
-
//
|
|
82
|
-
if (
|
|
83
|
-
prompt +=
|
|
84
|
-
|
|
85
|
-
prompt +=
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
199
|
+
// 受影响的其他文件
|
|
200
|
+
if (impactAnalysis.affectedFiles && impactAnalysis.affectedFiles.length > 0) {
|
|
201
|
+
prompt += `**其他受影响的文件** (${impactAnalysis.totalAffectedFiles || impactAnalysis.affectedFiles.length} 个`;
|
|
202
|
+
if (impactAnalysis.totalAffectedFiles > impactAnalysis.affectedFiles.length) {
|
|
203
|
+
prompt += `,显示前 ${impactAnalysis.affectedFiles.length} 个`;
|
|
204
|
+
}
|
|
205
|
+
prompt += `):\n\n`;
|
|
206
|
+
|
|
207
|
+
impactAnalysis.affectedFiles.forEach((file, index) => {
|
|
208
|
+
prompt += `### ${index + 1}. ${file.path}\n`;
|
|
209
|
+
prompt += `使用的符号: ${file.symbols.join(', ')}\n`;
|
|
210
|
+
|
|
211
|
+
// 添加代码片段
|
|
212
|
+
if (file.snippets && file.snippets.length > 0) {
|
|
213
|
+
prompt += `\n**使用示例**:\n`;
|
|
214
|
+
file.snippets.forEach(snippet => {
|
|
215
|
+
prompt += `\`\`\`javascript (第 ${snippet.lineNumber} 行附近)\n`;
|
|
216
|
+
prompt += snippet.snippet;
|
|
217
|
+
prompt += `\n\`\`\`\n`;
|
|
90
218
|
});
|
|
91
219
|
}
|
|
92
|
-
|
|
93
|
-
prompt += `【新增 - 第 ${change.lineNumber} 行】${change.content}\n`;
|
|
94
|
-
prompt += `\`\`\`\n\n`;
|
|
220
|
+
prompt += `\n`;
|
|
95
221
|
});
|
|
222
|
+
|
|
223
|
+
prompt += `---\n\n`;
|
|
96
224
|
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// 添加代码变更
|
|
228
|
+
prompt += `## 📝 代码变更\n\n`;
|
|
229
|
+
meaningfulChanges.forEach((change, index) => {
|
|
230
|
+
prompt += `### 变更 ${index + 1} - 第 ${change.lineNumber} 行\n`;
|
|
231
|
+
prompt += `**类型**: ${change.type === 'addition' ? '新增' : '删除'}\n`;
|
|
232
|
+
prompt += `**内容**:\n\`\`\`\n`;
|
|
233
|
+
|
|
234
|
+
// 上下文
|
|
235
|
+
if (change.context?.before?.length > 0) {
|
|
236
|
+
change.context.before.forEach(line => {
|
|
237
|
+
prompt += ` ${line}\n`;
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// 变更行
|
|
242
|
+
prompt += `${change.type === 'addition' ? '+' : '-'} ${change.content}\n`;
|
|
97
243
|
|
|
98
|
-
//
|
|
99
|
-
if (
|
|
100
|
-
|
|
244
|
+
// 下文
|
|
245
|
+
if (change.context?.after?.length > 0) {
|
|
246
|
+
change.context.after.forEach(line => {
|
|
247
|
+
prompt += ` ${line}\n`;
|
|
248
|
+
});
|
|
101
249
|
}
|
|
102
250
|
|
|
103
|
-
prompt +=
|
|
251
|
+
prompt += `\`\`\`\n`;
|
|
104
252
|
});
|
|
105
253
|
|
|
106
|
-
prompt +=
|
|
254
|
+
prompt += `\n## 审查要求
|
|
107
255
|
|
|
108
|
-
1.
|
|
109
|
-
2.
|
|
110
|
-
3.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
256
|
+
1. 仔细审查每一行变更,判断是否存在问题
|
|
257
|
+
2. **🚨 最高优先级**:检查是否有符号被删除但仍被使用(文件内部或其他文件)
|
|
258
|
+
3. **特别关注**:
|
|
259
|
+
- 删除的函数/类/组件是否在其他地方被调用
|
|
260
|
+
- 修改的函数签名是否会导致现有调用失效
|
|
261
|
+
- 新增的代码是否会影响其他文件的正常运行
|
|
262
|
+
4. 检查函数签名是否改变,所有调用方式是否需要更新
|
|
263
|
+
5. 检查是否有潜在的 API 不兼容问题
|
|
264
|
+
6. 如果发现文件内部使用了被删除的符号,这是**严重错误**
|
|
265
|
+
7. 如果发现其他文件使用了被删除/修改的符号,需要提醒可能的影响
|
|
266
|
+
8. **只对有问题的行提出审查意见**,没有问题的行不需要评论
|
|
267
|
+
9. **必须使用中文**返回审查意见
|
|
268
|
+
10. 返回 JSON 格式的结果,格式如下:
|
|
115
269
|
|
|
116
270
|
\`\`\`json
|
|
117
271
|
{
|
|
@@ -129,26 +283,25 @@ export function buildFileReviewPrompt(fileName, meaningfulChanges, hunkGroups) {
|
|
|
129
283
|
}
|
|
130
284
|
\`\`\`
|
|
131
285
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
11. comment 字段必须使用中文,要简洁明了`;
|
|
286
|
+
11. 如果所有代码都没有问题,返回空的 reviews 数组:\`{"reviews": []}\`
|
|
287
|
+
12. 只返回 JSON,不要包含其他文字说明
|
|
288
|
+
13. comment 字段必须使用中文,要简洁明了,重点指出影响范围`;
|
|
136
289
|
|
|
137
290
|
return prompt;
|
|
138
291
|
}
|
|
139
292
|
|
|
140
293
|
/**
|
|
141
|
-
*
|
|
294
|
+
* 构建包含影响分析的完整消息数组
|
|
142
295
|
* @param {string} fileName - 文件名
|
|
143
296
|
* @param {Array} meaningfulChanges - 有意义的变更数组
|
|
144
|
-
* @param {
|
|
297
|
+
* @param {Object} impactAnalysis - 影响分析结果
|
|
145
298
|
* @param {string} projectPrompt - 项目配置的 prompt
|
|
146
299
|
* @returns {Array} 消息数组
|
|
147
300
|
*/
|
|
148
|
-
export function
|
|
301
|
+
export function buildFileReviewWithImpactMessages(fileName, meaningfulChanges, impactAnalysis, projectPrompt = '') {
|
|
149
302
|
return [
|
|
150
303
|
{ role: 'system', content: buildSystemPrompt(projectPrompt) },
|
|
151
|
-
{ role: 'user', content:
|
|
304
|
+
{ role: 'user', content: buildFileReviewWithImpactPrompt(fileName, meaningfulChanges, impactAnalysis) },
|
|
152
305
|
];
|
|
153
306
|
}
|
|
154
307
|
|
|
@@ -157,5 +310,7 @@ export default {
|
|
|
157
310
|
buildSystemPrompt,
|
|
158
311
|
buildFileReviewPrompt,
|
|
159
312
|
buildFileReviewMessages,
|
|
313
|
+
buildFileReviewWithImpactPrompt,
|
|
314
|
+
buildFileReviewWithImpactMessages,
|
|
160
315
|
};
|
|
161
316
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gitlab-ai-review",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "GitLab AI Review SDK
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "GitLab AI Review SDK with Impact Analysis - 支持影响分析、删除符号检测、文件内部冲突检查的智能代码审查工具",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -22,11 +22,24 @@
|
|
|
22
22
|
"gitlab",
|
|
23
23
|
"ai",
|
|
24
24
|
"review",
|
|
25
|
+
"code-review",
|
|
25
26
|
"sdk",
|
|
26
|
-
"ci-cd"
|
|
27
|
+
"ci-cd",
|
|
28
|
+
"impact-analysis",
|
|
29
|
+
"static-analysis",
|
|
30
|
+
"merge-request",
|
|
31
|
+
"automation"
|
|
27
32
|
],
|
|
28
|
-
"author": "",
|
|
33
|
+
"author": "Your Name <your.email@example.com>",
|
|
29
34
|
"license": "MIT",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/yourusername/gitlab-ai-review.git"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/yourusername/gitlab-ai-review/issues"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/yourusername/gitlab-ai-review#readme",
|
|
30
43
|
"engines": {
|
|
31
44
|
"node": ">=18.0.0"
|
|
32
45
|
},
|