job51-gitlab-cr-node-jt-1 2.8.3 → 2.8.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.
@@ -1,9 +1,9 @@
1
1
  # GitLab Code Review AI Tool 技术文档
2
2
 
3
3
  **项目名称**: job51-gitlab-cr-node
4
- **当前版本**: 2.7.4
4
+ **当前版本**: 2.8.3
5
5
  **作者**: tao.jing
6
- **最后更新**: 2026-04-20
6
+ **最后更新**: 2026-04-23
7
7
  **项目地址**: https://gitdev.51job.com/51jobweb/ai-agent
8
8
 
9
9
  ---
@@ -27,9 +27,94 @@
27
27
 
28
28
  ## 版本历史
29
29
 
30
+ ### v2.8.3 (2026-04-23)
31
+
32
+ **当前版本**: 评论发布功能修复
33
+
34
+ **Bug 修复**:
35
+ - **GitLab 评论 API 兼容性修复**:将汇总报告的评论发布从 Discussions API 改为 Notes API,避免权限问题
36
+ - 问题现象:使用 Discussions API 发布汇总报告时可能遇到权限限制或评论类型设置问题
37
+ - 修复方案:
38
+ - 在 `postSummaryCommentToGitLab` 方法中改用 `/projects/:id/merge_requests/:iid/notes` API 端点
39
+ - Notes API 发布的是普通注释(Note),不会显示 resolve 按钮
40
+ - 移除不必要的 `resolvable` 参数配置,简化评论发布流程
41
+ - 影响:
42
+ - 汇总报告评论不再显示 resolve 按钮,避免用户误操作
43
+ - 评论类型统一为普通注释,提高 API 兼容性
44
+ - 简化评论发布逻辑,降低出错概率
45
+ - 修复文件:
46
+ - `index.js:987-1011`:重构汇总报告发布方法,使用 Notes API
47
+ - 移除 `resolvable: false` 参数,Notes API 自动使用普通注释类型
48
+
49
+ ### v2.8.2 (2026-04-22)
50
+
51
+ **更新**:
52
+ - **版本号同步**:更新 package.json 版本号到 2.8.2
53
+
54
+ ### v2.8.1 (2026-04-22)
55
+
56
+ **Bug 修复**:
57
+ - **汇总报告评论 Resolve 问题修复**:为汇总报告评论设置 `resolvable: false`,避免用户误操作
58
+ - 问题现象:汇总报告作为 Discussion 评论发布时带有 resolve 按钮,用户可能误点 resolve 导致报告消失
59
+ - 修复方案:
60
+ - 在 `postSummaryCommentToGitLab` 方法中添加 `resolvable: false` 参数
61
+ - GitLab Discussion API 中设置 `resolvable: false` 后评论不会显示 resolve 按钮
62
+ - 汇总报告作为信息展示类评论,不应该被 resolve
63
+ - 影响:
64
+ - 汇总报告评论不再显示 resolve 按钮
65
+ - 报告永久保留在 MR 讨论区,方便用户随时查看
66
+ - 避免用户误操作导致报告消失
67
+ - 修复文件:
68
+ - `index.js:988-1010`:添加 `resolvable: false` 配置
69
+
70
+ ### v2.8.0 (2026-04-22)
71
+
72
+ **重大功能更新**: AI 汇总报告生成功能
73
+
74
+ **新增功能**:
75
+ - **自动生成汇总报告**:在所有 diff 块审查完成后,自动调用 Claude AI 生成结构化的汇总报告
76
+ - 功能流程:
77
+ 1. 收集所有 diff 块的审查报告内容(`collectAllReviewReports` 方法)
78
+ 2. 为每个报告添加文件路径和 diff 块索引标识
79
+ 3. 调用 Claude CLI 命令生成汇总报告(`callClaudeForSummary` 方法)
80
+ 4. 提取 `<SUMMARY_REPORT>` 标签内容
81
+ 5. 发布汇总报告到 GitLab MR(`postSummaryCommentToGitLab` 方法)
82
+ - 汇总报告结构:
83
+ - 审查概览:文件数量、diff 块数量、问题总数、严重问题数、警告数
84
+ - 无问题文件列表:列出所有没有问题的文件路径(完整路径)
85
+ - 严重问题汇总:按文件分组,完整展示每个问题的描述、位置、修改建议
86
+ - 警告汇总:按文件分组,完整展示每个问题的描述、位置、修改建议
87
+ - 建议:针对问题的处理建议
88
+ - Prompt 设计:
89
+ - 使用东八区时间(北京时间,UTC+8)生成时间戳
90
+ - 构造详细的汇总报告模板,要求 AI 严格按照模板格式输出
91
+ - 强制使用 `<SUMMARY_REPORT>` 标签包裹报告内容
92
+ - 要求统计数据准确(文件数、问题数)
93
+ - 要求完整展示每个问题的描述、位置、修改建议,不简化
94
+ - 重试机制:
95
+ - 最大重试次数:5 次
96
+ - 验证返回内容是否包含 `<SUMMARY_REPORT>` 标签
97
+ - 缺少标签时自动重试
98
+ - 新增方法:
99
+ - `collectAllReviewReports(results)`: 收集并拼接所有审查报告内容
100
+ - `generateSummaryReportWithAI(allReportsText)`: 调用 Claude AI 生成汇总报告
101
+ - `buildSummaryPrompt(allReportsText)`: 构造汇总报告生成的 Prompt
102
+ - `callClaudeForSummary(promptFile)`: 调用 Claude CLI 命令生成汇总报告
103
+ - `postSummaryCommentToGitLab(projectId, mergeRequestIid, summaryReport)`: 发布汇总报告到 GitLab MR
104
+ - 集成位置:
105
+ - 在 `reviewMergeRequest` 方法结束时自动调用(index.js:173-192)
106
+ - 即使生成失败也不影响主流程,确保已发布的单个评论不受影响
107
+ - 新增文件:
108
+ - `index.js:196-428`:汇总报告生成相关方法(约 232 行新增代码)
109
+ - 效果:
110
+ - 用户可以在 MR 讨论区看到一份完整的汇总报告,包含所有问题的统一视图
111
+ - 汇总报告按文件分组展示问题,方便用户快速定位和修复
112
+ - 提供无问题文件列表,让用户了解审查覆盖范围
113
+ - 自动生成统计数据和可视化标记(🔴 严重问题、🟡 警告、✅ 无问题)
114
+
30
115
  ### v2.7.4 (2026-04-20)
31
116
 
32
- **当前版本**: 日志标识增强
117
+ **优化**: 日志标识增强
33
118
 
34
119
  **优化**:
35
120
  - **日志追踪标识**:为每个 diff 块的 AI 调用添加唯一标识,解决 CI 环境中处理多个 diff 块重试时日志追踪困难的问题
@@ -218,6 +303,10 @@ GitLab Code Review AI Tool 是一个基于 Claude AI 的自动化代码审查工
218
303
  │ 4. 发布评论 ←───────────────────────────────────── │
219
304
  │ ↓ │
220
305
  │ GitLab Discussion API (行级评论/一般讨论) │
306
+ │ ↓ │
307
+ │ 5. 收集所有报告 ──→ 6. AI生成汇总 ──→ 7. 发布汇总报告 │
308
+ │ ↓ ↓ ↓ │
309
+ │ 拼接报告内容 Claude CLI调用 GitLab Notes API │
221
310
  └─────────────────────────────────────────────────────────────┘
222
311
  ```
223
312
 
@@ -239,9 +328,10 @@ GitLab Code Review AI Tool 是一个基于 Claude AI 的自动化代码审查工
239
328
  │ │ GitLabAPIClient │ │ reviewDiffWith │ │ postCommentsTo │ │
240
329
  │ │ (GitLab 通信) │ │ ClaudeUsingFile │ │ GitLab │ │
241
330
  │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
242
- │ ┌─────────────────┐
243
- │ │ MetricsCollector│ (性能指标收集)
244
- └─────────────────┘
331
+ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
332
+ │ │ MetricsCollector│ │ generateSummary │ │ postSummaryTo │ │
333
+ │ │ (性能指标收集) │ │ ReportWithAI │ │ GitLab │ │
334
+ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
245
335
  └─────────────────────────────────────────────────────────────────┘
246
336
 
247
337
  ┌─────────────────────────────────────────────────────────────────┐
@@ -252,6 +342,11 @@ GitLab Code Review AI Tool 是一个基于 Claude AI 的自动化代码审查工
252
342
  │ │ │ simple-code- │ │ code-review- │ │ SKILL.md │ │ │
253
343
  │ │ │ review 技能 │ │ rules.md │ │ 模板 │ │ │
254
344
  │ │ └───────────────┘ └───────────────┘ └─────────────┘ │ │
345
+ │ └─────────────────────────────────────────────────────────┐ │
346
+ │ │ Claude CLI (汇总报告生成) │ │
347
+ │ │ ┌─────────────────────────────────────────────────┐ │ │
348
+ │ │ │ buildSummaryPrompt → callClaudeForSummary │ │ │
349
+ │ │ └─────────────────────────────────────────────────┘ │ │
255
350
  │ └─────────────────────────────────────────────────────────┘ │
256
351
  └─────────────────────────────────────────────────────────────────┘
257
352
  ```
@@ -287,12 +382,18 @@ constructor(gitlabToken, gitlabUrl = null)
287
382
  2. 获取 MR 的 diff 信息
288
383
  3. 调用 AI 进行代码审查
289
384
  4. 将审查结果发布到 GitLab
290
- 5. 性能指标收集与统计
385
+ 5. 生成并发布 AI 汇总报告
386
+ 6. 性能指标收集与统计
291
387
 
292
388
  **新增功能** (v2.5.x):
293
389
  - `_versionCache`: MR 版本信息缓存,避免重复 API 调用
294
390
  - `metrics`: MetricsCollector 实例,收集性能指标
295
391
 
392
+ **新增功能** (v2.8.0):
393
+ - `collectAllReviewReports`: 收集所有审查报告内容
394
+ - `generateSummaryReportWithAI`: 调用 AI 生成汇总报告
395
+ - `postSummaryCommentToGitLab`: 发布汇总报告到 GitLab MR
396
+
296
397
  ### 3.2 GitLabAPIClient 类
297
398
 
298
399
  **位置**: `utils.js:70-107`
@@ -327,7 +428,7 @@ class GitLabAPIClient {
327
428
  5. 重试机制 (最多 5 次)
328
429
  ```
329
430
 
330
- **重试策略** (`index.js:192-267`):
431
+ **重试策略** (`index.js:457-533`):
331
432
  - 最大重试次数:5 次
332
433
  - 递增等待时间:`1000 * attempts` 毫秒
333
434
  - 三级验证条件:
@@ -335,6 +436,85 @@ class GitLabAPIClient {
335
436
  2. 包含"严重问题"关键词
336
437
  3. 标题为"🤖 AI 代码审查结果"
337
438
 
439
+ ### 3.4 AI 汇总报告生成模块
440
+
441
+ **位置**: `index.js:196-428`
442
+
443
+ **核心职责**:
444
+ 1. 收集所有 diff 块的审查报告内容
445
+ 2. 为每个报告添加文件路径和 diff 块索引标识
446
+ 3. 构造汇总报告生成的 Prompt
447
+ 4. 调用 Claude CLI 生成结构化的汇总报告
448
+ 5. 提取 `<SUMMARY_REPORT>` 标签内容
449
+ 6. 发布汇总报告到 GitLab MR
450
+
451
+ **汇总报告结构**:
452
+ ```
453
+ <SUMMARY_REPORT>
454
+ ## 🤖 AI 代码审查汇总报告
455
+
456
+ **生成时间**: [时间戳]
457
+ **审查范围**: [文件数量]个文件,[diff块数量]个变更块
458
+ **发现问题**: [总数]个,其中严重问题[数量]个
459
+
460
+ ---
461
+
462
+ ### 📊 审查概览
463
+
464
+ - ✅ 无问题文件:[数量]个(详见下方列表)
465
+ - ⚠️ 有问题文件:[数量]个
466
+ - 🔴 严重问题:[数量]个
467
+ - 🟡 一般警告:[数量]个
468
+
469
+ ---
470
+
471
+ ### ✅ 无问题文件列表
472
+
473
+ 以下文件审查完成,未发现问题:
474
+
475
+ 1. `[文件路径1]`
476
+ 2. `[文件路径2]`
477
+ ...
478
+
479
+ ---
480
+
481
+ ### 🔴 严重问题汇总
482
+
483
+ 以下文件包含严重问题,需要优先处理:
484
+
485
+ #### 1. [文件路径] ([问题数量]个问题)
486
+
487
+ **问题 1**:[完整问题描述]
488
+ - **位置**:[文件路径]:[行号]
489
+ - **修改建议**:[完整修改建议,包含示例代码]
490
+
491
+ **问题 2**:...
492
+
493
+ ---
494
+
495
+ ### 🟡 一般警告汇总
496
+
497
+ ...
498
+
499
+ ---
500
+
501
+ ### 💡 建议
502
+
503
+ 1. **优先处理严重问题**:这些问题可能导致运行时异常或数据错误
504
+ 2. **测试验证**:建议对修改后的代码进行充分的单元测试和集成测试
505
+ 3. **代码规范**:部分警告涉及代码风格,建议参考项目规范进行统一
506
+
507
+ ---
508
+
509
+ *本报告由 AI 自动生成,建议结合人工审查确认问题准确性*
510
+ </SUMMARY_REPORT>
511
+ ```
512
+
513
+ **重试机制** (`index.js:372-428`):
514
+ - 最大重试次数:5 次
515
+ - 验证条件:返回内容必须包含 `<SUMMARY_REPORT>` 标签
516
+ - 失败时继续重试,达到最大次数后抛出错误
517
+
338
518
  ---
339
519
 
340
520
  ## 4. 关键算法与流程
@@ -525,6 +705,193 @@ export GITLAB_CR_CONCURRENCY=5 # 默认 3
525
705
  ### 4.6 行号解析算法
526
706
 
527
707
  **解析函数**:
708
+
709
+ ### 4.7 AI 汇总报告生成流程
710
+
711
+ **位置**: `index.js:173-192` (集成点), `index.js:196-428` (核心逻辑)
712
+
713
+ **完整流程**:
714
+ ```
715
+ ┌─────────────────────────────────────────────────────────────────────────┐
716
+ │ AI 汇总报告生成流程 │
717
+ ├─────────────────────────────────────────────────────────────────────────┤
718
+ │ │
719
+ │ 步骤 1: 所有 diff 块审查完成 │
720
+ │ ┌───────────────────────────────────────────────────────────────────┐ │
721
+ │ │ reviewMergeRequest 方法中,所有 diff 块审查并发布评论完成 │ │
722
+ │ │ results 数组包含所有审查结果 │ │
723
+ │ └───────────────────────────────────────────────────────────────────┘ │
724
+ │ ↓ │
725
+ │ 步骤 2: 收集所有审查报告内容 │
726
+ │ ┌───────────────────────────────────────────────────────────────────┐ │
727
+ │ │ collectAllReviewReports(results) │ │
728
+ │ │ │ │
729
+ │ │ 遍历所有审查结果: │ │
730
+ │ │ - 为每个报告添加文件路径标识 │ │
731
+ │ │ - 为每个报告添加 diff 块索引标识 │ │
732
+ │ │ - 拼接所有报告内容为完整文本 │ │
733
+ │ │ │ │
734
+ │ │ 输出格式: │ │
735
+ │ │ ========== 审查报告 #1 ========== │ │
736
+ │ │ 文件:src/main/java/UserService.java │ │
737
+ │ │ Diff 块索引:#0 │ │
738
+ │ │ │ │
739
+ │ │ <REPORT>...</REPORT> │ │
740
+ │ │ │ │
741
+ │ │ ========== 审查报告 #2 ========== │ │
742
+ │ │ ... │ │
743
+ │ └───────────────────────────────────────────────────────────────────┘ │
744
+ │ ↓ │
745
+ │ 步骤 3: 构造汇总报告生成 Prompt │
746
+ │ ┌───────────────────────────────────────────────────────────────────┐ │
747
+ │ │ buildSummaryPrompt(allReportsText) │ │
748
+ │ │ │ │
749
+ │ │ Prompt 内容包含: │ │
750
+ │ │ - 角色定义:专业的代码审查汇总助手 │ │
751
+ │ │ - 输出要求: │ │
752
+ │ │ * 仅输出一份汇总报告 │ │
753
+ │ │ * 以 <SUMMARY_REPORT> 开始,以 </SUMMARY_REPORT> 结束 │ │
754
+ │ │ * 不得输出任何解释、问候或额外文本 │ │
755
+ │ │ - 汇总报告结构(详细模板): │ │
756
+ │ │ * 审查概览:文件数量、问题总数、严重问题数 │ │
757
+ │ │ * 无问题文件列表:完整路径列表 │ │
758
+ │ │ * 严重问题汇总:按文件分组,完整展示 │ │
759
+ │ │ * 警告汇总:按文件分组,完整展示 │ │
760
+ │ │ * 建议:针对问题的处理建议 │ │
761
+ │ │ - 统计数据准确要求 │ │
762
+ │ │ - 完整展示问题要求 │ │
763
+ │ │ - 问题位置格式要求 │ │
764
+ │ │ - 时间戳生成(东八区时间) │ │
765
+ │ │ - 输出格式模板(Markdown 格式) │ │
766
+ │ │ - 提供的审查报告内容 │ │
767
+ │ │ - 最后强调:必须严格按照模板格式输出 │ │
768
+ │ └───────────────────────────────────────────────────────────────────┘ │
769
+ │ ↓ │
770
+ │ 步骤 4: 创建临时 Prompt 文件 │
771
+ │ ┌───────────────────────────────────────────────────────────────────┐ │
772
+ │ │ tmpFileName = summary_prompt_${Date.now()}.txt │ │
773
+ │ │ fs.writeFileSync(tmpFileName, prompt, 'utf-8') │ │
774
+ │ └───────────────────────────────────────────────────────────────────┘ │
775
+ │ ↓ │
776
+ │ 步骤 5: 调用 Claude CLI 生成汇总报告 │
777
+ │ ┌───────────────────────────────────────────────────────────────────┐ │
778
+ │ │ callClaudeForSummary(tmpFileName) │ │
779
+ │ │ │ │
780
+ │ │ 最大重试次数:5 次 │ │
781
+ │ │ 重试循环: │ │
782
+ │ │ 1. 执行 Claude CLI 命令: │ │
783
+ │ │ spawn('claude', ['--tools', 'default', '-p', '--', tmpFileName])│
784
+ │ │ 2. 捕获 stdout 和 stderr 输出 │ │
785
+ │ │ 3. 等待进程完成(Promise 等待) │ │
786
+ │ │ 4. 验证返回内容是否包含 <SUMMARY_REPORT> 标签 │ │
787
+ │ │ 5. 如果包含 → 返回成功 │ │
788
+ │ │ 6. 如果不包含 → 重试 │ │
789
+ │ │ 7. 如果失败 → 等待后重试 │ │
790
+ │ │ │ │
791
+ │ │ 验证条件: │ │
792
+ │ │ stdout.includes('<SUMMARY_REPORT>') │ │
793
+ │ └───────────────────────────────────────────────────────────────────┘ │
794
+ │ ↓ │
795
+ │ 步骤 6: 提取汇总报告内容 │
796
+ │ ┌───────────────────────────────────────────────────────────────────┐ │
797
+ │ │ reportMatch = summaryReport.match( │ │
798
+ │ │ /<SUMMARY_REPORT>(.*?)<\/SUMMARY_REPORT>/s │ │
799
+ │ │ ) │ │
800
+ │ │ │ │
801
+ │ │ 如果有匹配 → 返回 reportMatch[1].trim() │ │
802
+ │ │ 如果无匹配 → 返回 summaryReport.trim() │ │
803
+ │ └───────────────────────────────────────────────────────────────────┘ │
804
+ │ ↓ │
805
+ │ 步骤 7: 发布汇总报告到 GitLab MR │
806
+ │ ┌───────────────────────────────────────────────────────────────────┐ │
807
+ │ │ postSummaryCommentToGitLab(projectId, mergeRequestIid, summaryReport)│
808
+ │ │ │ │
809
+ │ │ v2.8.3 版本(当前): │ │
810
+ │ │ 使用 GitLab Notes API 发布普通注释 │ │
811
+ │ │ API 端点:/projects/:id/merge_requests/:iid/notes │ │
812
+ │ │ Payload: │ │
813
+ │ │ { │ │
814
+ │ │ "body": summaryReport // Markdown 格式的汇总报告内容 │ │
815
+ │ │ } │ │
816
+ │ │ │ │
817
+ │ │ v2.8.0-v2.8.1 版本(已废弃): │ │
818
+ │ │ 使用 GitLab Discussions API │ │
819
+ │ │ API 端点:/projects/:id/merge_requests/:iid/discussions │ │
820
+ │ │ Payload: │ │
821
+ │ │ { │ │
822
+ │ │ "body": summaryReport, │ │
823
+ │ │ "resolvable": false // v2.8.1 新增,避免用户误操作 │ │
824
+ │ │ } │ │
825
+ │ │ │ │
826
+ │ │ 注意: │ │
827
+ │ │ - Notes API 发布的是普通注释(Note),不会显示 resolve 按钮 │ │
828
+ │ │ - Discussions API 发布的是讨论(Discussion),会显示 resolve 按钮│ │
829
+ │ │ - v2.8.3 使用 Notes API 提高兼容性 │ │
830
+ │ │ - 发布失败不影响主流程,确保已发布的单个评论不受影响 │ │
831
+ │ │ - 记录评论发布指标:this.metrics.recordCommentPublished() │ │
832
+ │ └───────────────────────────────────────────────────────────────────┘ │
833
+ │ ↓ │
834
+ │ 步骤 8: 清理临时 Prompt 文件 │
835
+ │ ┌───────────────────────────────────────────────────────────────────┐ │
836
+ │ │ finally { │ │
837
+ │ │ if (fs.existsSync(tmpFileName)) { │ │
838
+ │ │ fs.unlinkSync(tmpFileName); │ │
839
+ │ │ } │ │
840
+ │ │ } │ │
841
+ │ └───────────────────────────────────────────────────────────────────┘ │
842
+ │ ↓ │
843
+ │ 步骤 9: 汇总报告发布完成 │
844
+ │ ┌───────────────────────────────────────────────────────────────────┐ │
845
+ │ │ 汇总报告已成功发布到 GitLab MR 讨论区 │ │
846
+ │ │ 用户可以在 MR 页面看到完整的汇总报告 │ │
847
+ │ │ │ │
848
+ │ │ 报告包含: │ │
849
+ │ │ - 审查概览和统计数据 │ │
850
+ │ │ - 无问题文件列表 │ │
851
+ │ │ - 按文件分组的严重问题汇总 │ │
852
+ │ │ - 按文件分组的警告汇总 │ │
853
+ │ │ - 处理建议 │ │
854
+ │ │ │ │
855
+ │ │ 特点: │ │
856
+ │ │ - 普通注释类型(v2.8.3),不显示 resolve 按钮 │ │
857
+ │ │ - 永久保留在 MR 讨论区 │ │
858
+ │ │ - Markdown 格式,可视化标记 │ │
859
+ │ │ - AI 自动生成,统计数据准确 │ │
860
+ │ └───────────────────────────────────────────────────────────────────┘ │
861
+ └─────────────────────────────────────────────────────────────────────────┘
862
+ ```
863
+
864
+ **关键设计决策**:
865
+
866
+ | 设计点 | 决策内容 | 理由 |
867
+ |--------|----------|------|
868
+ | **集成时机** | 所有 diff 块审查完成后 | 确保汇总报告包含完整的审查结果 |
869
+ | **失败处理** | 不抛出错误,允许主流程继续 | 确保已发布的单个评论不受影响 |
870
+ | **重试机制** | 最大 5 次,验证 `<SUMMARY_REPORT>` 标签 | 确保生成成功率,避免格式错误 |
871
+ | **时间戳生成** | 使用东八区时间(北京时间,UTC+8) | 符合中国用户习惯 |
872
+ | **API 选择** | v2.8.3 使用 Notes API(普通注释) | 提高兼容性,避免权限问题 |
873
+ | **评论类型** | 普通注释(Note),无 resolve 按钮 | 避免用户误操作,报告永久保留 |
874
+ | **数据完整性** | 完整展示每个问题的描述、位置、修改建议 | 不简化,方便用户理解问题详情 |
875
+ | **文件分组** | 按文件分组展示问题 | 方便用户快速定位和修复 |
876
+
877
+ **Prompt 设计特点**:
878
+
879
+ 1. **角色定义明确**:专业的代码审查汇总助手
880
+ 2. **输出格式强制**:必须使用 `<SUMMARY_REPORT>` 标签包裹
881
+ 3. **结构化模板**:提供详细的 Markdown 格式模板
882
+ 4. **统计准确性**:要求根据提供的报告内容准确统计
883
+ 5. **完整展示**:每个问题都要完整展示,不简化
884
+ 6. **可视化标记**:使用 emoji 标记(🔴 严重问题、🟡 警告、✅ 无问题)
885
+ 7. **问题位置格式**:统一使用"文件路径:行号"格式
886
+ 8. **无问题处理**:即使无问题也生成报告说明审查完成
887
+ 9. **最后强调**:必须严格按照模板格式输出,不得输出其他文本
888
+
889
+ **v2.8.3 版本改进**:
890
+
891
+ - **API 兼容性**:从 Discussions API 改为 Notes API,避免权限问题
892
+ - **评论类型简化**:使用普通注释(Note),移除不必要的 `resolvable` 参数
893
+ - **用户体验优化**:汇总报告不显示 resolve 按钮,避免用户误操作
894
+ - **代码简化**:移除 Discussions API 的复杂配置,降低出错概率
528
895
  ```javascript
529
896
  // 解析所有问题行号 (v2.4.6)
530
897
  parseAllLineInfoFromReviewResult(lineInfoTag) {
@@ -589,7 +956,32 @@ extractSingleProblemReport(fullReport, problemIndex) {
589
956
  }
590
957
  ```
591
958
 
592
- ### 5.3 LINE_INFO 格式
959
+ ### 5.3 汇总报告请求结构
960
+
961
+ ```javascript
962
+ {
963
+ prompt: string, // 汇总报告生成的 Prompt 内容
964
+ tmpFileName: string // 临时 Prompt 文件路径
965
+ }
966
+ ```
967
+
968
+ ### 5.4 汇总报告响应结构
969
+
970
+ ```javascript
971
+ {
972
+ summaryReport: string, // <SUMMARY_REPORT>...</SUMMARY_REPORT> 内容
973
+ timestamp: string, // 生成时间戳(东八区时间)
974
+ stats: {
975
+ totalFiles: number, // 审查文件总数
976
+ totalBlocks: number, // 审查 diff 块总数
977
+ totalProblems: number, // 发现问题总数
978
+ seriousProblems: number, // 严重问题数量
979
+ warnings: number // 一般警告数量
980
+ }
981
+ }
982
+ ```
983
+
984
+ ### 5.5 LINE_INFO 格式
593
985
 
594
986
  ```json
595
987
  [
@@ -746,6 +1138,11 @@ curl --request POST \
746
1138
  | `postSingleCommentToGitLab` | projectId, mergeRequestIid, result | `Promise<void>` | 发布单条评论 |
747
1139
  | `getMergeRequestVersions` | projectId, mergeRequestIid | `Promise<Object>` | 获取 MR 版本信息 |
748
1140
  | `getVersionInfo` | projectId, mergeRequestIid | `Promise<Object>` | 获取 MR 版本信息 (带缓存) |
1141
+ | `collectAllReviewReports` | results | `string` | 收集所有审查报告内容 |
1142
+ | `generateSummaryReportWithAI` | allReportsText | `Promise<string>` | 调用 AI 生成汇总报告 |
1143
+ | `buildSummaryPrompt` | allReportsText | `string` | 构造汇总报告 Prompt |
1144
+ | `callClaudeForSummary` | promptFile | `Promise<string>` | 调用 Claude CLI 生成汇总报告 |
1145
+ | `postSummaryCommentToGitLab` | projectId, mergeRequestIid, summaryReport | `Promise<void>` | 发布汇总报告到 GitLab MR |
749
1146
 
750
1147
  ### 8.2 GitLab API 端点
751
1148
 
@@ -756,7 +1153,7 @@ GET /projects/{projectId}/merge_requests/{iid}/diffs?per_page=20&page=1
756
1153
  // 获取 Versions
757
1154
  GET /projects/{projectId}/merge_requests/{iid}/versions
758
1155
 
759
- // 发布 Discussion
1156
+ // 发布 Discussion (单个问题评论)
760
1157
  POST /projects/{projectId}/merge_requests/{iid}/discussions
761
1158
  {
762
1159
  "body": "评论内容",
@@ -769,6 +1166,12 @@ POST /projects/{projectId}/merge_requests/{iid}/discussions
769
1166
  "new_path": "file.java"
770
1167
  }
771
1168
  }
1169
+
1170
+ // 发布 Note (汇总报告评论,v2.8.3 新增)
1171
+ POST /projects/{projectId}/merge_requests/{iid}/notes
1172
+ {
1173
+ "body": "汇总报告内容(Markdown 格式)"
1174
+ }
772
1175
  ```
773
1176
 
774
1177
  ---
@@ -1008,6 +1411,10 @@ npm run dev
1008
1411
 
1009
1412
  | 版本 | 日期 | 变更说明 |
1010
1413
  |------|------|----------|
1414
+ | **2.8.3** | 2026-04-23 | **GitLab 评论 API 兼容性修复**:将汇总报告发布从 Discussions API 改为 Notes API,避免权限问题;移除 `resolvable` 参数,使用普通注释类型发布;影响:汇总报告不再显示 resolve 按钮,评论类型统一为普通注释,提高 API 兼容性;修复文件:`index.js:987-1011` |
1415
+ | **2.8.2** | 2026-04-22 | **版本号同步**:更新 package.json 版本号到 2.8.2 |
1416
+ | **2.8.1** | 2026-04-22 | **汇总报告评论 Resolve 问题修复**:为汇总报告评论设置 `resolvable: false`,避免用户误操作导致报告消失;影响:汇总报告永久保留在 MR 讨论区;修复文件:`index.js:988-1010` |
1417
+ | **2.8.0** | 2026-04-22 | **重大功能更新**:新增 AI 汇总报告生成功能;新增方法:`collectAllReviewReports`、`generateSummaryReportWithAI`、`buildSummaryPrompt`、`callClaudeForSummary`、`postSummaryCommentToGitLab`;汇总报告结构:审查概览、无问题文件列表、严重问题汇总、警告汇总、建议;新增代码:约 232 行;集成位置:`reviewMergeRequest` 方法结束时自动调用;效果:用户可看到完整的汇总报告,包含所有问题的统一视图 |
1011
1418
  | **2.6.2** | 2026-04-16 | **行号计算示例增强**:添加临时文件完整格式示例,明确展示元数据行和 `@@` 行不编号。问题根因:尽管规则已明确"从 `@@` 之后开始计数",但 AI 仍然错误地将元数据行和 `@@` 行算入编号,导致行号系统性偏差(如正确行号 29 返回 43、31 返回 45 等)。修复方案:(1) 在 `code-review-rules.md` 第 13 条添加**示例 0:临时文件完整格式**,逐行标注哪些行忽略、哪些行编号、编号如何计算;(2) 在 `SKILL.md` 第 3 步添加**临时文件格式示例**,展示完整的计数过程;(3) 示例中明确标注 `=== File Information ===` 等 7 行元数据 + `@@` 行共 8 行都必须忽略,从 `@@` 之后的第一行才开始编号为 1 |
1012
1419
  | **2.6.1** | 2026-04-16 | 行号计数起点明确修复 - 补充示例 |
1013
1420
  | **2.6.0** | 2026-04-16 | **行号计数起点明确修复**:修复 AI 返回的行号系统性偏差 +8 的问题。问题根因:AI 在计数时把 `@@ ... @@` 这一行也算进去了,导致所有行号都 +8(如正确行号 30 返回 38、34 返回 42、38 返回 46、48 返回 56、54 返回 62)。修复方案:(1) 更新 `SKILL.md` 第 3 步,明确"`@@ ... @@`这一行本身也不编号,从它**之后**的第一行才开始编号";(2) 更新 `code-review-rules.md` 第 13 条,明确"`@@ ... @@`这一行本身**不编号**,从它**之后**的第一行才开始编号";(3) 在计数步骤中细化为 6 步,第 1 步"找到 `@@ ... @@` 行",第 2 步"从`@@ ... @@`**之后**的第一行开始编号" |
@@ -1026,12 +1433,12 @@ npm run dev
1026
1433
 
1027
1434
  | 文件 | 行数 | 职责 |
1028
1435
  |------|------|------|
1029
- | `index.js` | 796 | 主入口,审查逻辑 |
1436
+ | `index.js` | 1095 | 主入口,审查逻辑,汇总报告生成逻辑 |
1030
1437
  | `utils.js` | 354 | 工具函数,GitLab 客户端,指标收集器 |
1031
1438
  | `package.json` | 28 | 项目配置 |
1032
1439
  | `.claude/rules/code-review-rules.md` | 200+ | 审查规则 |
1033
1440
  | `.claude/skills/simple-code-review/SKILL.md` | 91 | 技能定义 |
1034
- | `docs/GITLAB_CR_NODE_TECHNICAL_DOCS.md` | 500+ | 技术文档 |
1441
+ | `docs/GITLAB_CR_NODE_TECHNICAL_DOCS.md` | 1100+ | 技术文档 |
1035
1442
 
1036
1443
  ---
1037
1444
 
@@ -1070,4 +1477,4 @@ export LOG_LEVEL=0 # DEBUG 级别
1070
1477
 
1071
1478
  ---
1072
1479
 
1073
- *文档生成时间:2026-04-16*
1480
+ *文档生成时间:2026-04-23*
package/index.js CHANGED
@@ -856,43 +856,53 @@ ${allReportsText}
856
856
  let targetLine = null;
857
857
  let skipReason = null;
858
858
 
859
- if (problemInfo.old_line && !problemInfo.new_line) {
860
- // 删除代码,使用 old_line
861
- if (oldCount === 0) {
862
- skipReason = `删除文件的 diff (old_count=${oldCount}),无法使用 old_line`;
863
- } else if (problemInfo.old_line < oldStart || problemInfo.old_line > oldEnd) {
864
- skipReason = `old_line=${problemInfo.old_line} 超出 diff 块范围 [${oldStart}, ${oldEnd}]`;
865
- } else {
866
- targetLine = {
867
- old_path: problemInfo.old_path || diff_info.old_path,
868
- old_line: problemInfo.old_line
869
- };
870
- }
871
- } else if (problemInfo.new_line) {
872
- // 新增代码或修改代码,使用 new_line
873
- // 对于删除文件(new_count=0),AI 可能返回 new_line 但实际应该用 old_line
874
- if (isDeleteFile) {
875
- // 删除文件:将 AI 返回的 new_line 视为原文件行号,使用 old_path + old_line
876
- if (problemInfo.new_line < oldStart || problemInfo.new_line > oldEnd) {
877
- skipReason = `删除文件中 new_line=${problemInfo.new_line} 超出原文件范围 [${oldStart}, ${oldEnd}]`;
859
+ // 验证文件路径是否匹配当前 diff
860
+ if (problemInfo.new_path && diff_info.new_path &&
861
+ problemInfo.new_path !== diff_info.new_path) {
862
+ skipReason = `AI 返回的文件路径 ${problemInfo.new_path} 与当前 diff 块文件 ${diff_info.new_path} 不匹配,可能存在AI幻觉`;
863
+ debugLog(`第 ${i + 1} 个问题 ${skipReason}`);
864
+ }
865
+
866
+ // 只有文件路径匹配时,才继续验证行号
867
+ if (!skipReason) {
868
+ if (problemInfo.old_line && !problemInfo.new_line) {
869
+ // 删除代码,使用 old_line
870
+ if (oldCount === 0) {
871
+ skipReason = `删除文件的 diff 块 (old_count=${oldCount}),无法使用 old_line`;
872
+ } else if (problemInfo.old_line < oldStart || problemInfo.old_line > oldEnd) {
873
+ skipReason = `old_line=${problemInfo.old_line} 超出 diff 块范围 [${oldStart}, ${oldEnd}]`;
874
+ } else {
875
+ targetLine = {
876
+ old_path: problemInfo.old_path || diff_info.old_path,
877
+ old_line: problemInfo.old_line
878
+ };
879
+ }
880
+ } else if (problemInfo.new_line) {
881
+ // 新增代码或修改代码,使用 new_line
882
+ // 对于删除文件(new_count=0),AI 可能返回 new_line 但实际应该用 old_line
883
+ if (isDeleteFile) {
884
+ // 删除文件:将 AI 返回的 new_line 视为原文件行号,使用 old_path + old_line
885
+ if (problemInfo.new_line < oldStart || problemInfo.new_line > oldEnd) {
886
+ skipReason = `删除文件中 new_line=${problemInfo.new_line} 超出原文件范围 [${oldStart}, ${oldEnd}]`;
887
+ } else {
888
+ targetLine = {
889
+ old_path: problemInfo.new_path || diff_info.old_path,
890
+ old_line: problemInfo.new_line
891
+ };
892
+ }
893
+ } else if (newCount === 0) {
894
+ skipReason = `new_count=0,无法使用 new_line`;
895
+ } else if (problemInfo.new_line < newStart || problemInfo.new_line > newEnd) {
896
+ skipReason = `new_line=${problemInfo.new_line} 超出 diff 块范围 [${newStart}, ${newEnd}]`;
878
897
  } else {
898
+ // 新增文件/新增行:使用 new_path + new_line
879
899
  targetLine = {
880
- old_path: problemInfo.new_path || diff_info.old_path,
881
- old_line: problemInfo.new_line
900
+ new_path: problemInfo.new_path || diff_info.new_path,
901
+ new_line: problemInfo.new_line
882
902
  };
883
903
  }
884
- } else if (newCount === 0) {
885
- skipReason = `new_count=0,无法使用 new_line`;
886
- } else if (problemInfo.new_line < newStart || problemInfo.new_line > newEnd) {
887
- skipReason = `new_line=${problemInfo.new_line} 超出 diff 块范围 [${newStart}, ${newEnd}]`;
888
- } else {
889
- // 新增文件/新增行:使用 new_path + new_line
890
- targetLine = {
891
- new_path: problemInfo.new_path || diff_info.new_path,
892
- new_line: problemInfo.new_line
893
- };
894
904
  }
895
- }
905
+ } // 文件路径验证条件块结束
896
906
 
897
907
  if (!targetLine) {
898
908
  // 无法解析行号或行号超出范围,使用一般讨论
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "job51-gitlab-cr-node-jt-1",
3
- "version": "2.8.3",
3
+ "version": "2.8.4",
4
4
  "description": "GitLab merge request code review tool with AI-powered analysis and project context support",
5
5
  "main": "index.js",
6
6
  "bin": {