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.
@@ -181,18 +181,15 @@
181
181
  12. 最终输出必须以 `<REPORT>` 开始,以 `</REPORT>` 结束;
182
182
 
183
183
  13. **行号计算规范**:
184
- > - **Diff 头信息格式**:`@@ -84,9 +84,11 @@`
185
- > - `-84,9`:旧文件从第 84 行开始,共 9 行
186
- > - `+84,11`:新文件从第 84 行开始,共 11 行
187
- > - **行号计算**(绝对行号,非相对偏移):
188
- > - 初始值 = `new_start`(从 diff 头解析)
189
- > - 空格开头(上下文):当前行号 = 计数器值,计数器 +1
190
- > - `-` 开头(删除):跳过,计数器不变
191
- > - `+` 开头(新增):当前行号 = 计数器值,计数器 +1
192
- > - **示例**:`@@ -0,0 +1,49 @@`(新增文件)
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. **解析行号**:使用 `New Start` 作为基准,遍历 diff 内容计算每行的绝对行号
17
- - 行号计算规则:
18
- - **基准行号** = `New Start`(从 File Information 中获取)
19
- - 遍历 diff 内容,只计数 `+` 开头(新增)和空格开头(上下文)的行
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 第 19
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
- - 无问题时省略对应标题,但 `<LINE_INFO>` 必须输出(空数组:`[]`)
61
- - 每个问题用 `---` 分割线分隔,方便切分
53
+ - 无问题时省略 `### 🔴 严重问题` 标题,但 `<LINE_INFO>` 必须输出(空数组:`[]`)
54
+ - 每个问题以 `**问题 N**:` 开头,方便切分
62
55
  - **`<LINE_INFO>` 数组中的元素顺序必须与问题顺序一致**:第 1 个元素对应问题 1 的行号,第 2 个元素对应问题 2 的行号,以此类推
63
- - 行号计算:使用 `New Start` 作为基准,第 1 `+` 或空格的行号 = `New Start`,第 2 行 = `New Start + 1`,依此类推
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: claudeResult, lineInfo: lineInfoContent };
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: claudeResult, lineInfo: lineInfoContent };
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
- return diffBlocks
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 inBlock = false;
525
+ let currentBlockIndex = 0;
521
526
 
522
527
  for (const line of lines) {
523
- if (line.trim() === '---') {
524
- if (inBlock) {
525
- // 块结束
526
- if (currentBlock.length > 0) {
527
- problemBlocks.push(currentBlock.join('\n'));
528
- currentBlock = [];
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
- } else if (inBlock) {
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
- const maxValidLine = newStart + newCount - 1;
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
- if (problemInfo.new_line < newStart || problemInfo.new_line > maxValidLine) {
623
- debugLog(`⚠️ 行号 ${problemInfo.new_line} 超出有效范围 [${newStart}, ${maxValidLine}],改用一般讨论`);
624
- needsGeneralDiscussion = true;
625
- } else {
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 (needsGeneralDiscussion) {
634
- // 行号无效,改用一般讨论
635
- debugLog(`第 ${i + 1} 个问题的行号 ${originalLine} 无效,发布为一般讨论`);
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