job51-gitlab-cr-node-jt-1 2.4.5 → 2.4.7
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/.claude/rules/code-review-rules.md +9 -12
- package/.claude/skills/simple-code-review/SKILL.md +11 -17
- package/index.js +39 -39
- package/log.txt +759 -704
- package/package.json +1 -1
|
@@ -181,18 +181,15 @@
|
|
|
181
181
|
12. 最终输出必须以 `<REPORT>` 开始,以 `</REPORT>` 结束;
|
|
182
182
|
|
|
183
183
|
13. **行号计算规范**:
|
|
184
|
-
> -
|
|
185
|
-
|
|
186
|
-
> -
|
|
187
|
-
|
|
188
|
-
> -
|
|
189
|
-
|
|
190
|
-
> -
|
|
191
|
-
> -
|
|
192
|
-
> -
|
|
193
|
-
> - 第 1 行 `+`:行号 = 1
|
|
194
|
-
> - 第 2 行 `+`:行号 = 2
|
|
195
|
-
> - **关键**:问题行号必须准确指向变更后代码的实际行号(绝对行号)
|
|
184
|
+
> - **行号定义**:行号是变更后文件中的**绝对行号**(从 1 开始计数)
|
|
185
|
+
> - **如何确定行号**:
|
|
186
|
+
> - 读取变更后文件(基于 `New Path`)
|
|
187
|
+
> - 找到新增代码在文件中的实际行号
|
|
188
|
+
> - 例如:如果新增代码在变更后文件的第 43 行,则 `new_line = 43`
|
|
189
|
+
> - **示例**:
|
|
190
|
+
> - 新增文件 `@@ -0,0 +1,49 @@`:第 1 行 `+` 的行号 = 1,第 2 行 `+` 的行号 = 2
|
|
191
|
+
> - 已有文件 `@@ -42,3 +43,5 @@`:新增代码在文件第 43 行,则 `new_line = 43`
|
|
192
|
+
> - **关键**:问题行号必须准确指向变更后代码在文件中的实际行号(绝对行号)
|
|
196
193
|
|
|
197
194
|
14. `<REPORT>` 标签示例中的问题块数量仅用于展示格式,实际数量由 review 结果决定;
|
|
198
195
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
2
|
name: simple-code-review
|
|
3
3
|
description: 代码审查技能,审查变更代码并输出 REPORT 和 LINE_INFO
|
|
4
4
|
---
|
|
@@ -9,18 +9,14 @@ description: 代码审查技能,审查变更代码并输出 REPORT 和 LINE_IN
|
|
|
9
9
|
|
|
10
10
|
2. **解析文件信息**:从 `=== File Information ===` 部分提取
|
|
11
11
|
- `Block Index`: 当前块索引号
|
|
12
|
-
- `New Start`: 当前 diff
|
|
12
|
+
- `New Start`: 当前 diff 块在变更后文件中的起始行号(仅供参考)
|
|
13
13
|
- `New Count`: 当前 diff 块的行数
|
|
14
14
|
- `New Path` / `Old Path`: 文件路径(去掉 `a/` 或 `b/` 前缀)
|
|
15
15
|
|
|
16
|
-
3.
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
- 第 1 行 `+` 或空格:行号 = `New Start`
|
|
21
|
-
- 第 2 行 `+` 或空格:行号 = `New Start + 1`
|
|
22
|
-
- 以此类推,`-` 开头的删除行不计入行号
|
|
23
|
-
- **重要**:行号是变更后文件中的绝对行号,必须使用 `New Start` 作为基准计算
|
|
16
|
+
3. **解析行号**:返回文件中变更代码的**绝对行号**(即变更后文件中的行号)
|
|
17
|
+
- 行号定义:行号是变更后文件中的绝对行号(从 1 开始计数)
|
|
18
|
+
- 例如:如果新增代码在变更后文件的第 43 行,则 `new_line = 43`
|
|
19
|
+
- **如何确定行号**:读取变更后文件(基于 `New Path`),找到新增代码在文件中的实际行号
|
|
24
20
|
|
|
25
21
|
4. **读取上下文**:基于 New Path 读取变更后文件,涉及方法调用时追踪读取实现代码
|
|
26
22
|
|
|
@@ -29,7 +25,7 @@ description: 代码审查技能,审查变更代码并输出 REPORT 和 LINE_IN
|
|
|
29
25
|
6. **输出结果**:
|
|
30
26
|
- 审查结果放入 `<REPORT>` 标签
|
|
31
27
|
- 行号信息放入 `<LINE_INFO>` 标签(必须输出)
|
|
32
|
-
- LINE_INFO 格式参考 @.claude/rules/code-review-rules.md 第
|
|
28
|
+
- LINE_INFO 格式参考 @.claude/rules/code-review-rules.md 第 18 条
|
|
33
29
|
- **问题和行号对应**:`<LINE_INFO>` 中的第 N 个元素对应第 N 个问题的行号
|
|
34
30
|
|
|
35
31
|
## 输出模板
|
|
@@ -39,16 +35,13 @@ description: 代码审查技能,审查变更代码并输出 REPORT 和 LINE_IN
|
|
|
39
35
|
|
|
40
36
|
### 🔴 严重问题
|
|
41
37
|
|
|
42
|
-
---
|
|
43
38
|
**问题 1**:[问题描述]<br/>
|
|
44
39
|
**文件及行号**:[文件路径:行号]<br/>
|
|
45
40
|
**修改建议**:[正确示例代码或说明]
|
|
46
|
-
---
|
|
47
41
|
|
|
48
42
|
**问题 2**:[问题描述]<br/>
|
|
49
43
|
**文件及行号**:[文件路径:行号]<br/>
|
|
50
44
|
**修改建议**:[正确示例代码或说明]
|
|
51
|
-
---
|
|
52
45
|
|
|
53
46
|
</REPORT>
|
|
54
47
|
|
|
@@ -57,7 +50,8 @@ description: 代码审查技能,审查变更代码并输出 REPORT 和 LINE_IN
|
|
|
57
50
|
</LINE_INFO>
|
|
58
51
|
|
|
59
52
|
**说明**:
|
|
60
|
-
-
|
|
61
|
-
-
|
|
53
|
+
- 无问题时省略 `### 🔴 严重问题` 标题,但 `<LINE_INFO>` 必须输出(空数组:`[]`)
|
|
54
|
+
- 每个问题以 `**问题 N**:` 开头,方便切分
|
|
62
55
|
- **`<LINE_INFO>` 数组中的元素顺序必须与问题顺序一致**:第 1 个元素对应问题 1 的行号,第 2 个元素对应问题 2 的行号,以此类推
|
|
63
|
-
-
|
|
56
|
+
- 行号:返回变更后文件中的绝对行号(从 1 开始计数),例如文件第 43 行则 `new_line = 43`
|
|
57
|
+
- **无严重问题时,LINE_INFO 必须输出空数组 `[]`**
|
package/index.js
CHANGED
|
@@ -102,7 +102,7 @@ class GitLabCodeReviewer {
|
|
|
102
102
|
// 无严重问题 → 直接返回标准空格式
|
|
103
103
|
if (!hasSeriousProblem) {
|
|
104
104
|
debugLog(`【决策】报告无严重问题,返回标准空格式`);
|
|
105
|
-
return { reportContent:
|
|
105
|
+
return { reportContent: '<REPORT>\n## 🤖 AI 代码审查结果\n\n</REPORT>', lineInfo: '[]' };
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
// 有严重问题 → 检查标题是否符合要求
|
|
@@ -297,7 +297,7 @@ ${diffObject.diff}`;
|
|
|
297
297
|
// 无严重问题 → 直接返回标准空格式
|
|
298
298
|
if (!hasSeriousProblem) {
|
|
299
299
|
debugLog(`【决策】报告无严重问题,返回标准空格式`);
|
|
300
|
-
return { reportContent:
|
|
300
|
+
return { reportContent: '<REPORT>\n## 🤖 AI 代码审查结果\n\n</REPORT>', lineInfo: '[]' };
|
|
301
301
|
}
|
|
302
302
|
|
|
303
303
|
// 有严重问题 → 检查标题是否符合要求
|
|
@@ -383,7 +383,7 @@ ${diffObject.diff}`;
|
|
|
383
383
|
const regex = /(?=@@\s-\d+(?:,\d+)?\s\+\d+(?:,\d+)?\s@@)/g;
|
|
384
384
|
const diffBlocks = diffObj.diff.split(regex);
|
|
385
385
|
// 过滤掉空块并提取行号信息
|
|
386
|
-
|
|
386
|
+
const result = diffBlocks
|
|
387
387
|
.filter(block => block.trim() !== '')
|
|
388
388
|
.map(block => {
|
|
389
389
|
// 解析diff头信息 @@ -old_start,old_count +new_start,new_count @@
|
|
@@ -407,6 +407,8 @@ ${diffObject.diff}`;
|
|
|
407
407
|
new_count = headerMatch[4] ? parseInt(headerMatch[4], 10) : 1;
|
|
408
408
|
}
|
|
409
409
|
|
|
410
|
+
debugLog(`解析 diff 块:file=${diffObj.new_path || diffObj.old_path}, headerMatch=${headerMatch ? headerMatch[0] : 'N/A'}, new_start=${new_start}, new_count=${new_count}`);
|
|
411
|
+
|
|
410
412
|
return {
|
|
411
413
|
diff: block,
|
|
412
414
|
new_path: diffObj.new_path,
|
|
@@ -427,6 +429,9 @@ ${diffObject.diff}`;
|
|
|
427
429
|
}
|
|
428
430
|
};
|
|
429
431
|
});
|
|
432
|
+
|
|
433
|
+
debugLog(`文件 ${diffObj.new_path || diffObj.old_path} 拆分为 ${result.length} 个 diff 块`);
|
|
434
|
+
return result;
|
|
430
435
|
}
|
|
431
436
|
|
|
432
437
|
/**
|
|
@@ -514,29 +519,32 @@ ${diffObject.diff}`;
|
|
|
514
519
|
*/
|
|
515
520
|
extractSingleProblemReport(fullReport, problemIndex) {
|
|
516
521
|
const lines = fullReport.split('\n');
|
|
517
|
-
// 使用
|
|
522
|
+
// 使用 **问题 N**: 模式来切分问题
|
|
518
523
|
const problemBlocks = [];
|
|
519
524
|
let currentBlock = [];
|
|
520
|
-
let
|
|
525
|
+
let currentBlockIndex = 0;
|
|
521
526
|
|
|
522
527
|
for (const line of lines) {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
inBlock = false;
|
|
531
|
-
} else {
|
|
532
|
-
// 块开始
|
|
533
|
-
inBlock = true;
|
|
528
|
+
// 检查是否是新的问题开始(如 **问题 1**:, **问题 2**:等)
|
|
529
|
+
const problemMatch = line.match(/\*\*问题\s*(\d+)\*\*/);
|
|
530
|
+
if (problemMatch) {
|
|
531
|
+
// 保存上一个问题块
|
|
532
|
+
if (currentBlock.length > 0 && currentBlockIndex > 0) {
|
|
533
|
+
problemBlocks.push(currentBlock.join('\n'));
|
|
534
|
+
currentBlock = [];
|
|
534
535
|
}
|
|
535
|
-
|
|
536
|
+
currentBlockIndex = parseInt(problemMatch[1]);
|
|
537
|
+
currentBlock.push(line);
|
|
538
|
+
} else {
|
|
536
539
|
currentBlock.push(line);
|
|
537
540
|
}
|
|
538
541
|
}
|
|
539
542
|
|
|
543
|
+
// 保存最后一个问题块
|
|
544
|
+
if (currentBlock.length > 0 && currentBlockIndex > 0) {
|
|
545
|
+
problemBlocks.push(currentBlock.join('\n'));
|
|
546
|
+
}
|
|
547
|
+
|
|
540
548
|
// 返回第 problemIndex 个问题(索引从 1 开始)
|
|
541
549
|
if (problemIndex >= 1 && problemIndex <= problemBlocks.length) {
|
|
542
550
|
return problemBlocks[problemIndex - 1];
|
|
@@ -588,11 +596,10 @@ ${diffObject.diff}`;
|
|
|
588
596
|
const startSha = versionInfo.start_commit_sha;
|
|
589
597
|
debugLog(`获取到版本信息 - base: ${baseSha}, head: ${headSha}, start: ${startSha}`);
|
|
590
598
|
|
|
591
|
-
// 解析 diff
|
|
592
|
-
const newStart = diff_info.new_start || 1;
|
|
593
|
-
const newCount = diff_info.new_count || 1;
|
|
594
|
-
|
|
595
|
-
debugLog(`Diff 块行号范围:[${newStart}, ${maxValidLine}],共 ${newCount} 行`);
|
|
599
|
+
// 解析 diff 头信息(用于日志记录)
|
|
600
|
+
const newStart = diff_info.line_info?.new_start || 1;
|
|
601
|
+
const newCount = diff_info.line_info?.new_count || 1;
|
|
602
|
+
debugLog(`Diff 块信息:new_start=${newStart}, new_count=${newCount}`);
|
|
596
603
|
|
|
597
604
|
const allLineInfo = this.parseAllLineInfoFromReviewResult(lineInfoTag);
|
|
598
605
|
debugLog(`解析到 ${allLineInfo.length} 个问题的行号信息`);
|
|
@@ -606,10 +613,8 @@ ${diffObject.diff}`;
|
|
|
606
613
|
debugLog(`处理第 ${i + 1}/${allLineInfo.length} 个问题:文件=${problemInfo.new_path}, 行号=${problemInfo.new_line}`);
|
|
607
614
|
const singleProblemContent = this.extractSingleProblemReport(fullReportContent, i + 1);
|
|
608
615
|
|
|
609
|
-
//
|
|
616
|
+
// 构建目标行号
|
|
610
617
|
let targetLine;
|
|
611
|
-
let originalLine = problemInfo.new_line;
|
|
612
|
-
let needsGeneralDiscussion = false;
|
|
613
618
|
|
|
614
619
|
if (problemInfo.old_line && !problemInfo.new_line) {
|
|
615
620
|
// 删除代码,使用 old_line
|
|
@@ -618,23 +623,18 @@ ${diffObject.diff}`;
|
|
|
618
623
|
old_line: problemInfo.old_line
|
|
619
624
|
};
|
|
620
625
|
} else if (problemInfo.new_line) {
|
|
621
|
-
//
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
}
|
|
626
|
-
targetLine = {
|
|
627
|
-
new_path: problemInfo.new_path,
|
|
628
|
-
new_line: problemInfo.new_line
|
|
629
|
-
};
|
|
630
|
-
}
|
|
626
|
+
// AI 返回的是文件中的绝对行号,直接使用
|
|
627
|
+
targetLine = {
|
|
628
|
+
new_path: problemInfo.new_path,
|
|
629
|
+
new_line: problemInfo.new_line
|
|
630
|
+
};
|
|
631
631
|
}
|
|
632
632
|
|
|
633
|
-
if (
|
|
634
|
-
//
|
|
635
|
-
debugLog(`第 ${i + 1}
|
|
633
|
+
if (!targetLine) {
|
|
634
|
+
// 无法解析行号,使用一般讨论
|
|
635
|
+
debugLog(`第 ${i + 1} 个问题无法解析行号,发布为一般讨论`);
|
|
636
636
|
await this.createGeneralDiscussion(projectId, mergeRequestIid, file_path_with_line, singleProblemContent);
|
|
637
|
-
debugLog(`第 ${i + 1} 个问题的评论已发布 (
|
|
637
|
+
debugLog(`第 ${i + 1} 个问题的评论已发布 (作为一般讨论)`);
|
|
638
638
|
continue;
|
|
639
639
|
}
|
|
640
640
|
|