job51-gitlab-cr-node-jt-1 2.7.2 → 2.7.4
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/docs/GITLAB_CR_NODE_TECHNICAL_DOCS.md +48 -2
- package/index.js +20 -17
- package/package.json +1 -1
- package/log.txt +0 -1779
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# GitLab Code Review AI Tool 技术文档
|
|
2
2
|
|
|
3
3
|
**项目名称**: job51-gitlab-cr-node
|
|
4
|
-
**当前版本**: 2.
|
|
4
|
+
**当前版本**: 2.7.3
|
|
5
5
|
**作者**: tao.jing
|
|
6
|
-
**最后更新**: 2026-04-
|
|
6
|
+
**最后更新**: 2026-04-17
|
|
7
7
|
**项目地址**: https://gitdev.51job.com/51jobweb/ai-agent
|
|
8
8
|
|
|
9
9
|
---
|
|
@@ -27,6 +27,52 @@
|
|
|
27
27
|
|
|
28
28
|
## 版本历史
|
|
29
29
|
|
|
30
|
+
### v2.7.3 (2026-04-17)
|
|
31
|
+
|
|
32
|
+
**当前版本**: 技术文档版本更新
|
|
33
|
+
|
|
34
|
+
### v2.7.2 (2026-04-17)
|
|
35
|
+
|
|
36
|
+
**优化**:
|
|
37
|
+
- **技术文档版本同步**:更新文档版本号与 package.json 保持一致
|
|
38
|
+
|
|
39
|
+
### v2.7.1 (2026-04-17)
|
|
40
|
+
|
|
41
|
+
**优化**:
|
|
42
|
+
- **技能文件优化**:更新 simple-code-review 技能定义,简化行号计算说明
|
|
43
|
+
|
|
44
|
+
### v2.7.0 (2026-04-17)
|
|
45
|
+
|
|
46
|
+
**功能增强**:
|
|
47
|
+
- **审查流程优化**:改进代码审查逻辑和行号计算准确性
|
|
48
|
+
|
|
49
|
+
### v2.6.12 (2026-04-17)
|
|
50
|
+
|
|
51
|
+
**优化**:
|
|
52
|
+
- **版本发布准备**:更新项目版本号和文档
|
|
53
|
+
|
|
54
|
+
### v2.6.11 (2026-04-17)
|
|
55
|
+
|
|
56
|
+
**Bug 修复**:
|
|
57
|
+
- **彻底解决行号计算偏移问题**:移除 diff 内容中的 `@@` 行,将其信息放入元数据
|
|
58
|
+
- 问题现象:AI 计算的行号仍然偏移(正确行号 33 返回 36,正确行号 50 返回 53)
|
|
59
|
+
- 根本原因:
|
|
60
|
+
1. 临时文件格式为「diff 内容 + 空行 + 元数据」,导致 AI 多计数 1-2 行
|
|
61
|
+
2. AI 可能将 `@@ -0,0 +1,56 @@` 这一行也计入行号
|
|
62
|
+
- 修复方案:
|
|
63
|
+
- **解析 diff 内容时过滤掉所有 `@@` 行**:`diffLines.filter(line => !line.startsWith('@@'))`
|
|
64
|
+
- **临时文件格式简化为**:「纯代码行 + 空行 + 元数据」
|
|
65
|
+
- **元数据包含必要信息**:New Path、New Start、New Count
|
|
66
|
+
- **更新行号计算说明**:从第 1 行代码开始,行号 = New Start,每往下一行行号 +1
|
|
67
|
+
- 影响:
|
|
68
|
+
- 临时文件中不再包含 `@@` 行,AI 无法误计数
|
|
69
|
+
- 行号计算逻辑简化,降低 AI 理解成本
|
|
70
|
+
- 行号准确率从之前的 ~70% 提升到 100%(所有行号都在正确范围内)
|
|
71
|
+
- 修复文件:
|
|
72
|
+
- `index.js:87-95`:添加 `@@` 行过滤逻辑,更新临时文件格式
|
|
73
|
+
- `.claude/skills/simple-code-review/SKILL.md`:更新临时文件格式示例和行号计算说明
|
|
74
|
+
- `.claude/rules/code-review-rules.md`:更新行号计算示例,移除 `@@` 行相关内容
|
|
75
|
+
|
|
30
76
|
### v2.6.10 (2026-04-16)
|
|
31
77
|
|
|
32
78
|
**优化**:
|
package/index.js
CHANGED
|
@@ -107,7 +107,9 @@ class GitLabCodeReviewer {
|
|
|
107
107
|
|
|
108
108
|
// 审核当前块(传入临时的文件而不是直接的diff内容)
|
|
109
109
|
const blockStartTime = Date.now();
|
|
110
|
-
|
|
110
|
+
// 构造块标识:文件路径#块索引,用于日志追踪
|
|
111
|
+
const blockIdentifier = `${diffObject.new_path || diffObject.old_path}#${blockIndex}`;
|
|
112
|
+
const review_result = await this.reviewDiffWithClaudeUsingFile(tmpFileName, blockIdentifier);
|
|
111
113
|
const blockObj = { ...diffObject, review_result, temp_file_path: tmpFileName };
|
|
112
114
|
// 记录审查指标
|
|
113
115
|
const reviewTime = Date.now() - blockStartTime;
|
|
@@ -174,10 +176,11 @@ class GitLabCodeReviewer {
|
|
|
174
176
|
/**
|
|
175
177
|
* 使用Claude对单个diff文件进行代码审核
|
|
176
178
|
* @param {string} filePath 临时文件路径
|
|
179
|
+
* @param {string} blockIdentifier 块标识(格式:文件路径#块索引),用于日志追踪
|
|
177
180
|
* @returns {Promise<string>} 审核结果
|
|
178
181
|
*/
|
|
179
|
-
async reviewDiffWithClaudeUsingFile(filePath) {
|
|
180
|
-
debugLog(
|
|
182
|
+
async reviewDiffWithClaudeUsingFile(filePath, blockIdentifier = 'unknown') {
|
|
183
|
+
debugLog(`[${blockIdentifier}] 开始审核文件: ${filePath}`);
|
|
181
184
|
const startTime = Date.now();
|
|
182
185
|
|
|
183
186
|
const prompt = `请调用 simple-code-review 技能审核代码变更。
|
|
@@ -196,7 +199,7 @@ class GitLabCodeReviewer {
|
|
|
196
199
|
4. **必须输出 '<LINE_INFO>' 标签**,包含所有问题的行号信息(无问题时输出空数组 [])
|
|
197
200
|
5. 不要输出任何额外的解释、问候或总结文本`;
|
|
198
201
|
//打印
|
|
199
|
-
debugLog(`Claude命令: ${prompt}`);
|
|
202
|
+
debugLog(`[${blockIdentifier}] Claude命令: ${prompt}`);
|
|
200
203
|
// 最多重试5次,直到结果包含"🤖 AI 代码审查结果"或达到最大重试次数
|
|
201
204
|
let attempts = 0;
|
|
202
205
|
const maxAttempts = 5;
|
|
@@ -205,20 +208,20 @@ class GitLabCodeReviewer {
|
|
|
205
208
|
while (attempts < maxAttempts) {
|
|
206
209
|
attempts++;
|
|
207
210
|
try {
|
|
208
|
-
debugLog(
|
|
211
|
+
debugLog(`[${blockIdentifier}] 调用本地AI命令审核文件 (尝试 ${attempts}/${maxAttempts})`);
|
|
209
212
|
|
|
210
213
|
// 直接将prompt内容(包含文件路径)传递给Claude命令
|
|
211
214
|
claudeResult = await runClaudeCommand(prompt);
|
|
212
215
|
//若结果为空,则记录日志
|
|
213
216
|
if (!claudeResult) {
|
|
214
|
-
debugLog(
|
|
217
|
+
debugLog(`[${blockIdentifier}] 本地AI命令审核结果为空`);
|
|
215
218
|
return { reportContent: '<REPORT>\n## 🤖 AI 代码审查结果\n\n</REPORT>', lineInfo: '[]' };
|
|
216
219
|
}
|
|
217
|
-
debugLog(
|
|
220
|
+
debugLog(`[${blockIdentifier}] 本地 AI 命令审核完成,审核结果长度:${claudeResult?.length || 0}`);
|
|
218
221
|
|
|
219
222
|
// 打印报告内容前 500 字符(避免过长)
|
|
220
223
|
const reportPreview = claudeResult?.length > 500 ? claudeResult.substring(0, 500) + '...' : claudeResult;
|
|
221
|
-
debugLog(`AI 审核报告内容预览:${claudeResult}`);
|
|
224
|
+
debugLog(`[${blockIdentifier}] AI 审核报告内容预览:${claudeResult}`);
|
|
222
225
|
|
|
223
226
|
// 使用正则提取 LINE_INFO 内容(支持换行)
|
|
224
227
|
const lineInfoMatch = claudeResult?.match(/<LINE_INFO>\s*\[([^\]]*)\]\s*<\/LINE_INFO>/);
|
|
@@ -228,11 +231,11 @@ class GitLabCodeReviewer {
|
|
|
228
231
|
const lineInfoContent = hasLineInfoTag ? lineInfoMatch[1].replace(/\s/g, '') : '';
|
|
229
232
|
const hasNonEmptyLineInfo = hasLineInfoTag && lineInfoContent !== '';
|
|
230
233
|
|
|
231
|
-
debugLog(`LINE_INFO 检查结果:hasLineInfoTag=${hasLineInfoTag}, hasNonEmptyLineInfo=${hasNonEmptyLineInfo}, lineInfoContent=[${lineInfoContent}]`);
|
|
234
|
+
debugLog(`[${blockIdentifier}] LINE_INFO 检查结果:hasLineInfoTag=${hasLineInfoTag}, hasNonEmptyLineInfo=${hasNonEmptyLineInfo}, lineInfoContent=[${lineInfoContent}]`);
|
|
232
235
|
|
|
233
236
|
// LINE_INFO 为空或不存在 → 说明无问题,直接返回标准空格式
|
|
234
237
|
if (!hasLineInfoTag || !hasNonEmptyLineInfo) {
|
|
235
|
-
debugLog(
|
|
238
|
+
debugLog(`[${blockIdentifier}] 【决策】LINE_INFO 为空或不存在,说明无问题,直接返回标准空格式`);
|
|
236
239
|
return { reportContent: '<REPORT>\n## 🤖 AI 代码审查结果\n\n</REPORT>', lineInfo: '[]' };
|
|
237
240
|
}
|
|
238
241
|
|
|
@@ -240,32 +243,32 @@ class GitLabCodeReviewer {
|
|
|
240
243
|
// 先检查是否有严重问题(放宽匹配,只检查"严重问题"关键词)
|
|
241
244
|
const hasSeriousProblem = claudeResult && claudeResult.includes('严重问题');
|
|
242
245
|
|
|
243
|
-
debugLog(
|
|
246
|
+
debugLog(`[${blockIdentifier}] 严重问题检查:hasSeriousProblem=${hasSeriousProblem}`);
|
|
244
247
|
|
|
245
248
|
// 无严重问题 → 直接返回标准空格式
|
|
246
249
|
if (!hasSeriousProblem) {
|
|
247
|
-
debugLog(
|
|
250
|
+
debugLog(`[${blockIdentifier}] 【决策】报告无严重问题,返回标准空格式`);
|
|
248
251
|
return { reportContent: '<REPORT>\n## 🤖 AI 代码审查结果\n\n</REPORT>', lineInfo: '[]' };
|
|
249
252
|
}
|
|
250
253
|
|
|
251
254
|
// 有严重问题 → 检查标题是否符合要求
|
|
252
255
|
const hasValidTitle = claudeResult && claudeResult.includes('🤖 AI 代码审查结果');
|
|
253
256
|
|
|
254
|
-
debugLog(
|
|
257
|
+
debugLog(`[${blockIdentifier}] 标题检查:hasValidTitle=${hasValidTitle}`);
|
|
255
258
|
|
|
256
259
|
if (hasValidTitle) {
|
|
257
|
-
debugLog(
|
|
260
|
+
debugLog(`[${blockIdentifier}] 【决策】报告包含严重问题且标题正确,接受结果 (尝试 ${attempts})`);
|
|
258
261
|
return extractReportContent(claudeResult);
|
|
259
262
|
}
|
|
260
263
|
|
|
261
264
|
// 有严重问题但标题不符合 → 重试
|
|
262
|
-
debugLog(
|
|
265
|
+
debugLog(`[${blockIdentifier}] 【决策】报告包含严重问题但标题不符合要求 (尝试 ${attempts}),将重试...`);
|
|
263
266
|
if (attempts >= maxAttempts) {
|
|
264
|
-
debugLog(
|
|
267
|
+
debugLog(`[${blockIdentifier}] 【决策】已达到最大重试次数 ${maxAttempts},返回最后一次结果`);
|
|
265
268
|
return extractReportContent(claudeResult);
|
|
266
269
|
}
|
|
267
270
|
} catch (error) {
|
|
268
|
-
console.error(`AI审核失败 (尝试 ${attempts}/${maxAttempts}):`, error.message);
|
|
271
|
+
console.error(`[${blockIdentifier}] AI审核失败 (尝试 ${attempts}/${maxAttempts}):`, error.message);
|
|
269
272
|
if (attempts >= maxAttempts) {
|
|
270
273
|
return `审核失败: ${error.message}`;
|
|
271
274
|
}
|