job51-gitlab-cr-node-jt-1 2.6.7 → 2.6.9
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.
|
@@ -182,82 +182,73 @@
|
|
|
182
182
|
|
|
183
183
|
13. **行号计算规范**:
|
|
184
184
|
> - **行号定义**:行号是**变更后文件中的绝对行号**(从 1 开始计数,即该行在完整文件中的实际行号)
|
|
185
|
-
> - **⚠️
|
|
186
|
-
> -
|
|
187
|
-
|
|
185
|
+
> - **⚠️ 关键规则:如何计算绝对行号**(强制执行,推荐方法 A):
|
|
186
|
+
> - **方法 A:直接从 new_start 开始递增**(推荐,不易出错)
|
|
187
|
+
> 1. 找到 `@@ -old_start,old_count +new_start,new_count @@` 行
|
|
188
|
+
> 2. 从这一行**之后**的第一行开始,行号 = `new_start`
|
|
189
|
+
> 3. 每往下一行(`+` 开头或空格开头),行号 +1
|
|
190
|
+
> 4. `-` 开头的删除行**不计数**,行号不增加
|
|
191
|
+
> 5. 示例:`@@ -0,0 +1,58 @@` 之后的第一行行号=1,第二行行号=2,以此类推
|
|
192
|
+
> - **方法 B:先编号再转换**
|
|
193
|
+
> 1. 从 `@@` 之后开始编号:第 1 行、第 2 行、第 3 行...
|
|
194
|
+
> 2. 绝对行号 = 编号 + new_start - 1
|
|
195
|
+
> 3. 对于 `@@ -0,0 +1,N @@`(新增文件):绝对行号 = 编号
|
|
196
|
+
> - **⚠️ 重要:忽略所有元数据行**(临时文件开头的 `# File Information`、`# New Path:` 等以 `# ` 开头的行都**不编号**,直接跳过)
|
|
188
197
|
> - **⚠️ 关键**:`@@ ... @@` 这一行本身**不编号**,从它**之后**的第一行才开始编号
|
|
189
|
-
> - **计数步骤**:
|
|
190
|
-
> 1. 找到 `@@ ... @@` 行(unified diff 的块头)
|
|
191
|
-
> 2. 从 `@@ ... @@` **之后**的第一行开始,按顺序给每一行编号(第 1 行、第 2 行、第 3 行...)
|
|
192
|
-
> 3. `+` 开头的新增代码:编号
|
|
193
|
-
> 4. 空格开头的上下文代码:编号
|
|
194
|
-
> 5. `-` 开头的删除代码:**不编号**(已删除)
|
|
195
|
-
> 6. **绝对行号 = 编号 + new_start - 1**
|
|
196
|
-
> - **简化理解**:
|
|
197
|
-
> - 对于 `@@ -0,0 +1,N @@`(新增文件):`绝对行号 = 编号`(因为 new_start=1)
|
|
198
|
-
> - 对于 `@@ -old_start,old_count +new_start,new_count @@`(修改文件):`绝对行号 = 编号 + new_start - 1`
|
|
199
198
|
> - **⚠️ 行号计算示例**(必读):
|
|
200
199
|
> - **示例 0:临时文件完整格式**(理解计数起点)
|
|
201
200
|
```
|
|
202
201
|
# File Information (AI 请忽略这些元数据行,从 @@ 之后开始计数)
|
|
203
|
-
# New Path: b/src/Test.java <--
|
|
204
|
-
#
|
|
205
|
-
#
|
|
206
|
-
#
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
+ obj.toString(); <-- + 开头,编号=3,绝对行号=3+29-1=31 ← 问题在这,new_line=31
|
|
213
|
-
} <-- 空格开头,编号=4,绝对行号=4+29-1=32
|
|
202
|
+
# New Path: b/src/Test.java <-- 元数据行,忽略,直接跳过
|
|
203
|
+
# Block Index: 0 <-- 元数据行,忽略,直接跳过
|
|
204
|
+
# New Start: 29 <-- 元数据行,忽略,直接跳过
|
|
205
|
+
# Diff Content Below
|
|
206
|
+
@@ -28,8 +29,10 @@ <-- @@ 行,不编号!从下一行开始行号=29(new_start)
|
|
207
|
+
public void method() { <-- 空格开头,行号 = 29(new_start)
|
|
208
|
+
+ Object obj = getXxx(); <-- + 开头,行号 = 30(29+1)← 问题在这,new_line=30
|
|
209
|
+
+ obj.toString(); <-- + 开头,行号 = 31(30+1)← 问题在这,new_line=31
|
|
210
|
+
} <-- 空格开头,行号 = 32(31+1)
|
|
214
211
|
```
|
|
215
|
-
> - **示例 1:新增文件** `@@ -0,0 +1,58 @@`(
|
|
212
|
+
> - **示例 1:新增文件** `@@ -0,0 +1,58 @@`(new_start=1)
|
|
216
213
|
```
|
|
217
214
|
@@ -0,0 +1,58 @@
|
|
218
|
-
+package com.job51.dev.bbs.service.impl; //
|
|
219
|
-
+ //
|
|
220
|
-
+import com.job51.dev.bbs.mapper.ForumMapper; //
|
|
215
|
+
+package com.job51.dev.bbs.service.impl; // 行号 = 1(new_start)
|
|
216
|
+
+ // 行号 = 2
|
|
217
|
+
+import com.job51.dev.bbs.mapper.ForumMapper; // 行号 = 3
|
|
221
218
|
...
|
|
222
|
-
+public class TestMultiIssuesService { //
|
|
223
|
-
+ public Map<String, Object> getTestData(String forumId, String userId) { //
|
|
224
|
-
+ Object forum = forumMapper.selectById(forumId); //
|
|
225
|
-
+ String forumName = forum.toString(); //
|
|
226
|
-
+ Object firstPost = posts.get(0); //
|
|
219
|
+
+public class TestMultiIssuesService { // 行号 = 17
|
|
220
|
+
+ public Map<String, Object> getTestData(String forumId, String userId) { // 行号 = 27
|
|
221
|
+
+ Object forum = forumMapper.selectById(forumId); // 行号 = 28
|
|
222
|
+
+ String forumName = forum.toString(); // 行号 = 30 ← 问题在这,new_line = 30
|
|
223
|
+
+ Object firstPost = posts.get(0); // 行号 = 38 ← 问题在这,new_line = 38
|
|
227
224
|
```
|
|
228
|
-
> - **示例 2:已有文件修改** `@@ -42,3 +43,5 @@`(new_start=43
|
|
225
|
+
> - **示例 2:已有文件修改** `@@ -42,3 +43,5 @@`(new_start=43)
|
|
229
226
|
```
|
|
230
227
|
@@ -42,3 +43,5 @@
|
|
231
|
-
public void method() { //
|
|
232
|
-
+ Object obj = service.getData(); //
|
|
233
|
-
+ obj.toString(); //
|
|
234
|
-
}
|
|
228
|
+
public void method() { // 行号 = 43(new_start)
|
|
229
|
+
+ Object obj = service.getData(); // 行号 = 44(43+1)
|
|
230
|
+
+ obj.toString(); // 行号 = 45(44+1)← 问题在这,new_line = 45
|
|
231
|
+
} // 行号 = 46(45+1)
|
|
235
232
|
```
|
|
236
233
|
> - **⚠️ 验证方法**(强制执行,输出前必须检查):
|
|
237
234
|
> 1. **查看 diff 头的 new_start 和 new_count 值**:
|
|
238
|
-
|
|
239
|
-
|
|
235
|
+
> - `@@ -0,0 +1,N @@` → 行号范围 = [1, N]
|
|
236
|
+
> - `@@ -old_start,old_count +new_start,new_count @@` → 行号范围 = [new_start, new_start + new_count - 1]
|
|
240
237
|
> 2. **确保所有问题的行号在范围内**
|
|
241
|
-
> 3.
|
|
238
|
+
> 3. **如果行号超出范围,说明计算错误,必须重新计数**
|
|
242
239
|
> 4. **⚠️ 特别场景:读取完整项目文件后的行号处理**
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
> 5.
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
> - 错误示例:如果你返回的行号是 8、9、43 等,说明你把 7 行元数据算进去了,**必须重新计数**
|
|
256
|
-
> 6. **输出前最终验证**:
|
|
257
|
-
> - 对于每个问题的行号 X,问自己:"X - new_start + 1 是否等于我在 diff 块中从 `@@` 之后开始数的位置?"
|
|
258
|
-
> - 如果不等,说明计算错误,必须重新从 `@@` 之后逐行计数
|
|
259
|
-
> - 示例:`@@ -0,0 +1,56 @@` 的 diff 块,行号范围是 [1, 56],**不能返回 57、60 等超出范围的值**
|
|
260
|
-
> - 示例:`@@ -167,7 +167,6 @@` 的 diff 块,new_start=167, new_count=6,行号范围是 [167, 172]
|
|
240
|
+
> - 如果你读取了完整的项目文件(通过 Read 工具)来追踪问题位置
|
|
241
|
+
> - **必须验证:该行是否在 diff 块范围内**
|
|
242
|
+
> - 验证公式:`new_start <= 行号 <= new_start + new_count - 1`
|
|
243
|
+
> - **如果行号超出范围,说明你定位的行不在当前 diff 块内**
|
|
244
|
+
> - **正确做法**:放弃从完整文件读取的行号,重新基于 diff 块内容逐行计数
|
|
245
|
+
> - 示例:diff 块 `@@ -0,0 +1,56 @@` 范围是 [1, 56],如果你在完整文件中定位到第 60 行 → **该行不在 diff 块内,不能用**
|
|
246
|
+
> - **原因**:GitLab API 只能评论 diff 块范围内的行
|
|
247
|
+
> 5. **输出前最终验证**:
|
|
248
|
+
> - 对于每个问题的行号 X,问自己:"X - new_start + 1 是否等于我在 diff 块中从 `@@` 之后开始数的位置?"
|
|
249
|
+
> - 如果不等,说明计算错误,必须重新从 `@@` 之后逐行计数
|
|
250
|
+
> - 示例:`@@ -0,0 +1,56 @@` 的 diff 块,行号范围是 [1, 56],**不能返回 57、60 等超出范围的值**
|
|
251
|
+
> - 示例:`@@ -167,7 +167,6 @@` 的 diff 块,new_start=167, new_count=6,行号范围是 [167, 172]
|
|
261
252
|
> - **关键**:绝对行号必须通过 diff 块内计数计算,且结果必须在 diff 块范围 [new_start, new_start + new_count - 1] 内
|
|
262
253
|
|
|
263
254
|
14. `<REPORT>` 标签示例中的问题块数量仅用于展示格式,实际数量由 review 结果决定;
|
|
@@ -7,7 +7,7 @@ description: 代码审查技能,审查变更代码并输出 REPORT 和 LINE_IN
|
|
|
7
7
|
|
|
8
8
|
1. **读取 diff 文件**:使用 Read 工具读取文件:$ARGUMENTS
|
|
9
9
|
|
|
10
|
-
2. **解析文件信息**:从
|
|
10
|
+
2. **解析文件信息**:从 `# File Information` 部分提取
|
|
11
11
|
- `Block Index`: 当前块索引号
|
|
12
12
|
- `New Start`: 当前 diff 块在变更后文件中的起始行号(仅供参考)
|
|
13
13
|
- `New Count`: 当前 diff 块的行数
|
|
@@ -15,45 +15,40 @@ description: 代码审查技能,审查变更代码并输出 REPORT 和 LINE_IN
|
|
|
15
15
|
|
|
16
16
|
3. **解析行号**:**基于 diff 块内容逐行计数,计算绝对行号**
|
|
17
17
|
- **⚠️ 重要**:行号计算规则详见 @.claude/rules/code-review-rules.md 第 13 条
|
|
18
|
-
-
|
|
19
|
-
|
|
18
|
+
- **行号计算方法**(任选一种,推荐方法 A):
|
|
19
|
+
- **方法 A:直接从 new_start 开始递增**(推荐,不易出错)
|
|
20
|
+
1. 找到 `@@ -old_start,old_count +new_start,new_count @@` 行
|
|
21
|
+
2. 从这一行**之后**的第一行开始,行号 = `new_start`
|
|
22
|
+
3. 每往下一行(`+` 开头或空格开头),行号 +1
|
|
23
|
+
4. `-` 开头的删除行**不计数**,行号不增加
|
|
24
|
+
5. 示例:`@@ -0,0 +1,58 @@` 之后的第一行行号=1,第二行行号=2,以此类推
|
|
25
|
+
- **方法 B:先编号再转换**
|
|
26
|
+
1. 从 `@@` 之后开始编号:第 1 行、第 2 行、第 3 行...
|
|
27
|
+
2. 绝对行号 = 编号 + new_start - 1
|
|
28
|
+
3. 对于 `@@ -0,0 +1,N @@`(新增文件):绝对行号 = 编号
|
|
29
|
+
- **忽略元数据行**:临时文件开头的 `# File Information`、`# New Path:` 等以 `# ` 开头的行都**不编号**,直接跳过
|
|
20
30
|
- **⚠️ 关键**:`@@ ... @@` 这一行本身也不编号,从它**之后**的第一行才开始编号
|
|
21
31
|
- **⚠️ 临时文件格式示例**(理解计数起点):
|
|
22
32
|
```
|
|
23
33
|
# File Information (AI 请忽略这些元数据行,从 @@ 之后开始计数)
|
|
24
34
|
# New Path: b/src/Test.java <-- 元数据行,忽略,不编号
|
|
25
|
-
# Old Path: a/src/Test.java <-- 元数据行,忽略,不编号
|
|
26
35
|
# Block Index: 0 <-- 元数据行,忽略,不编号
|
|
27
36
|
# New Start: 29 <-- 元数据行,忽略,不编号
|
|
28
|
-
#
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
+
|
|
33
|
-
|
|
34
|
-
} <-- 空格开头,编号=4,绝对行号=4+29-1=32
|
|
37
|
+
# Diff Content Below
|
|
38
|
+
@@ -28,8 +29,10 @@ <-- @@ 行,不编号!从下一行才开始计数
|
|
39
|
+
public void method() { <-- 空格开头,行号 = 29(new_start)
|
|
40
|
+
+ Object obj = getXxx(); <-- + 开头,行号 = 30(29+1)
|
|
41
|
+
+ obj.toString(); <-- + 开头,行号 = 31(30+1)
|
|
42
|
+
} <-- 空格开头,行号 = 32(31+1)
|
|
35
43
|
```
|
|
36
|
-
- **计数步骤**:
|
|
37
|
-
1. 找到 `@@ ... @@` 行(unified diff 的块头)
|
|
38
|
-
2. 从 `@@ ... @@` **之后**的第一行开始,按顺序给每一行编号(第 1 行、第 2 行、第 3 行...)
|
|
39
|
-
3. `+` 开头的新增代码:编号;空格开头的上下文代码:编号;`-` 开头的删除代码:**不编号**
|
|
40
|
-
4. **绝对行号 = 编号 + new_start - 1**
|
|
41
|
-
- **简化计算**:
|
|
42
|
-
- 对于 `@@ -0,0 +1,N @@`(新增文件):`绝对行号 = 编号`(因为 new_start=1)
|
|
43
|
-
- 对于 `@@ -old_start,old_count +new_start,new_count @@`(修改文件):`绝对行号 = 编号 + new_start - 1`
|
|
44
44
|
- **⚠️ 强制验证步骤**(输出前必须执行):
|
|
45
45
|
1. 从 diff 头提取 `new_start` 和 `new_count`,计算行号范围:`[new_start, new_start + new_count - 1]`
|
|
46
46
|
2. **逐个检查**每个问题的行号是否在该范围内
|
|
47
|
-
3.
|
|
47
|
+
3. **如果任何行号超出范围,必须重新计数**
|
|
48
48
|
4. **禁止**直接使用从完整文件读取的行号
|
|
49
|
-
5. **验证计算过程**:在输出前,必须在心中默念验证:
|
|
50
|
-
- "这个行号 X 是否在 [new_start, new_start + new_count - 1] 范围内?"
|
|
51
|
-
- "如果 X 超出范围,说明我计数错误,必须从 `@@` 行之后重新逐行编号"
|
|
52
|
-
- "临时文件的元数据行(以 `# ` 开头)和 `@@` 行都不能编号,从 `@@` 之后的第一行才开始编号为 1"
|
|
53
49
|
- **示例**:
|
|
54
50
|
- `@@ -0,0 +1,56 @@` 的行号范围是 [1, 56],**不能返回 57、60 等超出范围的值**
|
|
55
51
|
- `@@ -167,7 +167,6 @@` 的行号范围是 [167, 172],**不能返回 <167 或 >172 的值**
|
|
56
|
-
- 如果完整文件中某行在第 60 行,但 diff 块范围是 [1, 56],说明该行不在当前 diff 块内,**必须放弃该行号**
|
|
57
52
|
|
|
58
53
|
4. **读取上下文**:基于 New Path 读取变更后文件,涉及方法调用时追踪读取实现代码
|
|
59
54
|
- **⚠️ 重要**:读取完整文件仅用于理解代码逻辑,**不得**直接使用完整文件中的行号
|
|
@@ -94,6 +89,20 @@ description: 代码审查技能,审查变更代码并输出 REPORT 和 LINE_IN
|
|
|
94
89
|
|
|
95
90
|
7. **必须输出 `<LINE_INFO>` 标签**:即使无问题也要输出空数组 `<LINE_INFO>[]</LINE_INFO>`
|
|
96
91
|
|
|
92
|
+
8. **修改建议中的代码格式**:
|
|
93
|
+
- **必须使用 markdown 代码块**(```language ... ```)展示建议代码
|
|
94
|
+
- **禁止**使用行内代码(\`xxx\`)展示多行代码示例
|
|
95
|
+
- 代码块的语言根据文件类型自动选择(如 \`java\`、\`js\`、\`ts\`、\`py\`、\`go\` 等)
|
|
96
|
+
- 示例:
|
|
97
|
+
\`\`\`
|
|
98
|
+
**修改建议**:添加空值检查
|
|
99
|
+
\`\`\`java
|
|
100
|
+
if (forum != null) {
|
|
101
|
+
String forumName = forum.toString();
|
|
102
|
+
}
|
|
103
|
+
\`\`\`
|
|
104
|
+
\`\`\`
|
|
105
|
+
|
|
97
106
|
<REPORT>
|
|
98
107
|
## 🤖 AI 代码审查结果
|
|
99
108
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# GitLab Code Review AI Tool 技术文档
|
|
2
2
|
|
|
3
3
|
**项目名称**: job51-gitlab-cr-node
|
|
4
|
-
**当前版本**: 2.6.
|
|
4
|
+
**当前版本**: 2.6.8
|
|
5
5
|
**作者**: tao.jing
|
|
6
6
|
**最后更新**: 2026-04-16
|
|
7
7
|
**项目地址**: https://gitdev.51job.com/51jobweb/ai-agent
|
|
@@ -27,6 +27,31 @@
|
|
|
27
27
|
|
|
28
28
|
## 版本历史
|
|
29
29
|
|
|
30
|
+
### v2.6.8 (2026-04-16)
|
|
31
|
+
|
|
32
|
+
**Bug 修复**:
|
|
33
|
+
- **修复 SKILL.md 中临时文件格式描述不一致问题**:将 `=== File Information ===` 更新为 `# File Information`
|
|
34
|
+
- 问题现象:v2.6.7 修复行号偏移后,AI 仍不能正确计算行号
|
|
35
|
+
- 根本原因:SKILL.md 第 2 行仍描述从 `=== File Information ===` 提取信息,但临时文件格式已改为 `# File Information`
|
|
36
|
+
- 修复方案:更新 SKILL.md 中的格式描述,使其与临时文件实际格式一致
|
|
37
|
+
- 修复文件:`.claude/skills/simple-code-review/SKILL.md`
|
|
38
|
+
|
|
39
|
+
### v2.6.7 (2026-04-16)
|
|
40
|
+
|
|
41
|
+
**Bug 修复**:
|
|
42
|
+
- **修复行号计算偏移问题**:修改临时文件格式,元数据行改为以 `# ` 开头,方便 AI 识别并忽略
|
|
43
|
+
- 问题现象:AI 计算的绝对行号总是比正确值多 8(如正确行号 30 返回 38)
|
|
44
|
+
- 根本原因:AI 没有正确忽略临时文件的元数据行(`=== File Information ===` 等 7 行)
|
|
45
|
+
- 修复方案:
|
|
46
|
+
- 修改临时文件格式:元数据行改为 `# File Information`、`# New Path:` 等注释格式
|
|
47
|
+
- 更新 SKILL.md:明确指示 AI 忽略所有以 `# ` 开头的行,从 `@@` 之后开始编号
|
|
48
|
+
- 更新 code-review-rules.md:同步更新示例格式
|
|
49
|
+
- 修复文件:`index.js:87-96`、`.claude/skills/simple-code-review/SKILL.md`、`.claude/rules/code-review-rules.md`
|
|
50
|
+
- **优化修改建议代码格式**:支持多语言代码块格式
|
|
51
|
+
- 修改建议中的代码示例必须使用 markdown 代码块(```language ... ```)
|
|
52
|
+
- 语言类型根据实际文件类型自动选择(java、js、py 等)
|
|
53
|
+
- 禁止使用行内代码(`xxx`)展示多行代码
|
|
54
|
+
|
|
30
55
|
### v2.6.6 (2026-04-16)
|
|
31
56
|
|
|
32
57
|
**Bug 修复**:
|
package/index.js
CHANGED
|
@@ -86,7 +86,7 @@ class GitLabCodeReviewer {
|
|
|
86
86
|
|
|
87
87
|
// 构造包含元数据的 diff 内容
|
|
88
88
|
// 注意:元数据行以 '# ' 开头,AI 会忽略这些行,从 '@@' 之后开始计数
|
|
89
|
-
const diffContentWithMetadata = `# File Information
|
|
89
|
+
const diffContentWithMetadata = `# File Information
|
|
90
90
|
# New Path: ${diffObject.new_path || 'N/A'}
|
|
91
91
|
# Old Path: ${diffObject.old_path || 'N/A'}
|
|
92
92
|
# Block Index: ${blockIndex}
|