@spaceflow/review 0.61.0 → 0.63.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.62.0](https://github.com/Lydanne/spaceflow/compare/@spaceflow/review@0.61.0...@spaceflow/review@0.62.0) (2026-03-03)
4
+
5
+ ### 代码重构
6
+
7
+ * **review:** 优化问题统计展示,统一状态图标并新增汇总行 ([c764625](https://github.com/Lydanne/spaceflow/commit/c76462548a299ee51af98553c73ba4f705031cd3))
8
+ * **review:** 优化问题统计表格布局,将总结内容移至折叠块展示 ([629e96f](https://github.com/Lydanne/spaceflow/commit/629e96f5960167b689c724a4fb4df4fb29088002))
9
+
10
+ ### 其他修改
11
+
12
+ * **review-summary:** released version 0.29.0 [no ci] ([ef6209c](https://github.com/Lydanne/spaceflow/commit/ef6209cf15114fa9ece2e7e11a9131081d92d443))
13
+
14
+ ## [0.61.0](https://github.com/Lydanne/spaceflow/compare/@spaceflow/review@0.60.0...@spaceflow/review@0.61.0) (2026-03-03)
15
+
16
+ ### 代码重构
17
+
18
+ * **review:** 优化无效问题统计逻辑,排除已修复和已解决的问题 ([1de7b2a](https://github.com/Lydanne/spaceflow/commit/1de7b2a23fcc3ff73f679fc219342e111d96acf7))
19
+
20
+ ### 其他修改
21
+
22
+ * **review-summary:** released version 0.28.0 [no ci] ([e131ed8](https://github.com/Lydanne/spaceflow/commit/e131ed83528ef8b45b3e3edaac5dab3389812323))
23
+ * **scripts:** released version 0.25.0 [no ci] ([88292c0](https://github.com/Lydanne/spaceflow/commit/88292c07b7787bcd4492c8b88cfb516b3e81d9be))
24
+ * **shell:** released version 0.25.0 [no ci] ([fc78e10](https://github.com/Lydanne/spaceflow/commit/fc78e10a0bab04d575867732b922a2a1989a594e))
25
+
3
26
  ## [0.60.0](https://github.com/Lydanne/spaceflow/compare/@spaceflow/review@0.59.0...@spaceflow/review@0.60.0) (2026-03-02)
4
27
 
5
28
  ### 代码重构
package/dist/index.js CHANGED
@@ -1169,34 +1169,69 @@ class MarkdownFormatter {
1169
1169
  if (summaries.length === 0) {
1170
1170
  return "没有需要审查的文件";
1171
1171
  }
1172
+ // 🟢 已修复 | 🔴 待处理error | 🟡 待处理warn | ⚪ 已解决(非代码修复)
1172
1173
  const issuesByFile = new Map();
1173
1174
  for (const issue of issues){
1174
1175
  if (issue.valid === "false") continue;
1175
1176
  const stats = issuesByFile.get(issue.file) || {
1176
- resolved: 0,
1177
- errors: 0,
1178
- warns: 0
1177
+ fixed: 0,
1178
+ pendingErrors: 0,
1179
+ pendingWarns: 0,
1180
+ resolved: 0
1179
1181
  };
1180
1182
  if (issue.fixed) {
1183
+ stats.fixed++;
1184
+ } else if (issue.resolved) {
1181
1185
  stats.resolved++;
1182
1186
  } else if (issue.severity === "error") {
1183
- stats.errors++;
1187
+ stats.pendingErrors++;
1184
1188
  } else {
1185
- stats.warns++;
1189
+ stats.pendingWarns++;
1186
1190
  }
1187
1191
  issuesByFile.set(issue.file, stats);
1188
1192
  }
1189
1193
  const lines = [];
1190
- lines.push("| 文件 | 🟢 | 🔴 | 🟡 | 总结 |");
1191
- lines.push("|------|----|----|----|----|");
1194
+ lines.push("| 文件 | 总数 | 🟢 | 🔴 | 🟡 | |");
1195
+ lines.push("|------|------|----|----|----|-----|");
1196
+ // 汇总统计
1197
+ let totalAll = 0;
1198
+ let totalFixed = 0;
1199
+ let totalPendingErrors = 0;
1200
+ let totalPendingWarns = 0;
1201
+ let totalResolved = 0;
1202
+ const fileSummaryLines = [];
1192
1203
  for (const fileSummary of summaries){
1193
1204
  const stats = issuesByFile.get(fileSummary.file) || {
1194
- resolved: 0,
1195
- errors: 0,
1196
- warns: 0
1205
+ fixed: 0,
1206
+ pendingErrors: 0,
1207
+ pendingWarns: 0,
1208
+ resolved: 0
1197
1209
  };
1198
- const summaryText = fileSummary.summary.split("\n").filter((line)=>line.trim()).join("<br>");
1199
- lines.push(`| \`${fileSummary.file}\` | ${stats.resolved} | ${stats.errors} | ${stats.warns} | ${summaryText} |`);
1210
+ const fileTotal = stats.fixed + stats.pendingErrors + stats.pendingWarns + stats.resolved;
1211
+ totalAll += fileTotal;
1212
+ totalFixed += stats.fixed;
1213
+ totalPendingErrors += stats.pendingErrors;
1214
+ totalPendingWarns += stats.pendingWarns;
1215
+ totalResolved += stats.resolved;
1216
+ lines.push(`| \`${fileSummary.file}\` | ${fileTotal} | ${stats.fixed} | ${stats.pendingErrors} | ${stats.pendingWarns} | ${stats.resolved} |`);
1217
+ // 收集问题总结用于折叠块展示
1218
+ if (fileSummary.summary.trim()) {
1219
+ fileSummaryLines.push(`### 💡 \`${fileSummary.file}\``);
1220
+ fileSummaryLines.push(`${fileSummary.summary.trim()}`);
1221
+ fileSummaryLines.push("");
1222
+ }
1223
+ }
1224
+ // 添加汇总行
1225
+ if (summaries.length > 1) {
1226
+ lines.push(`| **总计** | **${totalAll}** | **${totalFixed}** | **${totalPendingErrors}** | **${totalPendingWarns}** | **${totalResolved}** |`);
1227
+ }
1228
+ // 问题总结放到折叠块中
1229
+ if (fileSummaryLines.length > 0) {
1230
+ lines.push("");
1231
+ lines.push("<details>");
1232
+ lines.push("<summary>📝 问题总结</summary>\n");
1233
+ lines.push(...fileSummaryLines);
1234
+ lines.push("</details>");
1200
1235
  }
1201
1236
  return lines.join("\n");
1202
1237
  }
@@ -1310,8 +1345,8 @@ class MarkdownFormatter {
1310
1345
  `|------|------|`
1311
1346
  ];
1312
1347
  lines.push(`| 总问题数 | ${stats.total} |`);
1313
- lines.push(`| 已修复 | ${stats.fixed} |`);
1314
- lines.push(`| 🟢 已解决 | ${stats.resolved} |`);
1348
+ lines.push(`| 🟢 已修复 | ${stats.fixed} |`);
1349
+ lines.push(`| 已解决 | ${stats.resolved} |`);
1315
1350
  lines.push(`| ❌ 无效 | ${stats.invalid} |`);
1316
1351
  lines.push(`| ⚠️ 待处理 | ${stats.pending} |`);
1317
1352
  lines.push(`| 修复率 | ${stats.fixRate}% |`);
@@ -1346,36 +1381,58 @@ class TerminalFormatter {
1346
1381
  if (summaries.length === 0) {
1347
1382
  return "没有需要审查的文件";
1348
1383
  }
1384
+ // 🟢 已修复 | 🔴 待处理error | 🟡 待处理warn | ⚪ 已解决(非代码修复)
1349
1385
  const issuesByFile = new Map();
1350
1386
  for (const issue of issues){
1387
+ if (issue.valid === "false") continue;
1351
1388
  const stats = issuesByFile.get(issue.file) || {
1352
- resolved: 0,
1353
- errors: 0,
1354
- warns: 0
1389
+ fixed: 0,
1390
+ pendingErrors: 0,
1391
+ pendingWarns: 0,
1392
+ resolved: 0
1355
1393
  };
1356
1394
  if (issue.fixed) {
1395
+ stats.fixed++;
1396
+ } else if (issue.resolved) {
1357
1397
  stats.resolved++;
1358
1398
  } else if (issue.severity === "error") {
1359
- stats.errors++;
1399
+ stats.pendingErrors++;
1360
1400
  } else {
1361
- stats.warns++;
1401
+ stats.pendingWarns++;
1362
1402
  }
1363
1403
  issuesByFile.set(issue.file, stats);
1364
1404
  }
1405
+ // 汇总统计
1406
+ let totalAll = 0;
1407
+ let totalFixed = 0;
1408
+ let totalPendingErrors = 0;
1409
+ let totalPendingWarns = 0;
1410
+ let totalResolved = 0;
1365
1411
  const lines = [];
1366
1412
  for (const fileSummary of summaries){
1367
1413
  const stats = issuesByFile.get(fileSummary.file) || {
1368
- resolved: 0,
1369
- errors: 0,
1370
- warns: 0
1414
+ fixed: 0,
1415
+ pendingErrors: 0,
1416
+ pendingWarns: 0,
1417
+ resolved: 0
1371
1418
  };
1372
- const resolvedText = stats.resolved > 0 ? `${GREEN}✅ ${stats.resolved} 已解决${RESET}` : "";
1373
- const errorText = stats.errors > 0 ? `${RED}🔴 ${stats.errors} error${RESET}` : "";
1374
- const warnText = stats.warns > 0 ? `${YELLOW}🟡 ${stats.warns} warn${RESET}` : "";
1419
+ const fileTotal = stats.fixed + stats.pendingErrors + stats.pendingWarns + stats.resolved;
1420
+ totalAll += fileTotal;
1421
+ totalFixed += stats.fixed;
1422
+ totalPendingErrors += stats.pendingErrors;
1423
+ totalPendingWarns += stats.pendingWarns;
1424
+ totalResolved += stats.resolved;
1425
+ const totalText = fileTotal > 0 ? `${BOLD}${fileTotal} 问题${RESET}` : "";
1426
+ const fixedText = stats.fixed > 0 ? `${GREEN}🟢 ${stats.fixed} 已修复${RESET}` : "";
1427
+ const errorText = stats.pendingErrors > 0 ? `${RED}🔴 ${stats.pendingErrors} error${RESET}` : "";
1428
+ const warnText = stats.pendingWarns > 0 ? `${YELLOW}🟡 ${stats.pendingWarns} warn${RESET}` : "";
1429
+ const resolvedText = stats.resolved > 0 ? `⚪ ${stats.resolved} 已解决` : "";
1375
1430
  const statsText = [
1376
- resolvedText,
1431
+ totalText,
1432
+ fixedText,
1377
1433
  errorText,
1378
- warnText
1434
+ warnText,
1435
+ resolvedText
1379
1436
  ].filter(Boolean).join(" / ");
1380
1437
  if (statsText) {
1381
1438
  lines.push(`${BOLD}${fileSummary.file}${RESET} (${statsText}): ${fileSummary.summary}`);
@@ -1383,6 +1440,18 @@ class TerminalFormatter {
1383
1440
  lines.push(`${BOLD}${fileSummary.file}${RESET}: ${fileSummary.summary}`);
1384
1441
  }
1385
1442
  }
1443
+ // 添加汇总行
1444
+ if (summaries.length > 1) {
1445
+ lines.push("");
1446
+ const summaryParts = [
1447
+ `${BOLD}总计: ${totalAll} 问题${RESET}`
1448
+ ];
1449
+ if (totalFixed > 0) summaryParts.push(`${GREEN}🟢 ${totalFixed} 已修复${RESET}`);
1450
+ if (totalPendingErrors > 0) summaryParts.push(`${RED}🔴 ${totalPendingErrors} error${RESET}`);
1451
+ if (totalPendingWarns > 0) summaryParts.push(`${YELLOW}🟡 ${totalPendingWarns} warn${RESET}`);
1452
+ if (totalResolved > 0) summaryParts.push(`⚪ ${totalResolved} 已解决`);
1453
+ lines.push(summaryParts.join(" / "));
1454
+ }
1386
1455
  return lines.join("\n");
1387
1456
  }
1388
1457
  format(result, _options = {}) {
@@ -1437,8 +1506,8 @@ class TerminalFormatter {
1437
1506
  `\n${BOLD}${CYAN}📊 ${title}:${RESET}`
1438
1507
  ];
1439
1508
  lines.push(` 总问题数: ${stats.total}`);
1440
- lines.push(` ${GREEN} 已修复: ${stats.fixed}${RESET}`);
1441
- lines.push(` ${GREEN}🟢 已解决: ${stats.resolved}${RESET}`);
1509
+ lines.push(` ${GREEN}🟢 已修复: ${stats.fixed}${RESET}`);
1510
+ lines.push(` 已解决: ${stats.resolved}`);
1442
1511
  lines.push(` ${RED}❌ 无效: ${stats.invalid}${RESET}`);
1443
1512
  lines.push(` ${YELLOW}⚠️ 待处理: ${stats.pending}${RESET}`);
1444
1513
  lines.push(` 修复率: ${stats.fixRate}%`);
@@ -3705,12 +3774,16 @@ ${fileChanges || "无"}`;
3705
3774
  /**
3706
3775
  * 构建行级评论 Review 的 body(marker + 本轮统计 + 上轮回顾)
3707
3776
  */ buildLineReviewBody(issues, round, allIssues) {
3708
- const errorCount = issues.filter((i)=>i.severity === "error").length;
3709
- const warnCount = issues.filter((i)=>i.severity === "warn").length;
3777
+ // 只统计待处理的问题(未修复且未解决)
3778
+ const pendingIssues = issues.filter((i)=>!i.fixed && !i.resolved && i.valid !== "false");
3779
+ const pendingErrors = pendingIssues.filter((i)=>i.severity === "error").length;
3780
+ const pendingWarns = pendingIssues.filter((i)=>i.severity === "warn").length;
3710
3781
  const fileCount = new Set(issues.map((i)=>i.file)).size;
3782
+ const totalPending = pendingErrors + pendingWarns;
3711
3783
  const badges = [];
3712
- if (errorCount > 0) badges.push(`🔴 ${errorCount}`);
3713
- if (warnCount > 0) badges.push(`🟡 ${warnCount}`);
3784
+ if (totalPending > 0) badges.push(`⚠️ ${totalPending}`);
3785
+ if (pendingErrors > 0) badges.push(`🔴 ${pendingErrors}`);
3786
+ if (pendingWarns > 0) badges.push(`🟡 ${pendingWarns}`);
3714
3787
  const parts = [
3715
3788
  REVIEW_LINE_COMMENTS_MARKER
3716
3789
  ];
@@ -3732,8 +3805,8 @@ ${fileChanges || "无"}`;
3732
3805
  parts.push(`<details><summary>📊 Round ${round - 1} 回顾 (${prevIssues.length} 个问题)</summary>\n`);
3733
3806
  parts.push(`| 状态 | 数量 |`);
3734
3807
  parts.push(`|------|------|`);
3735
- if (prevFixed > 0) parts.push(`| 已修复 | ${prevFixed} |`);
3736
- if (prevResolved > 0) parts.push(`| 🟢 已解决 | ${prevResolved} |`);
3808
+ if (prevFixed > 0) parts.push(`| 🟢 已修复 | ${prevFixed} |`);
3809
+ if (prevResolved > 0) parts.push(`| 已解决 | ${prevResolved} |`);
3737
3810
  if (prevInvalid > 0) parts.push(`| ❌ 无效 | ${prevInvalid} |`);
3738
3811
  if (prevPending > 0) parts.push(`| ⚠️ 待处理 | ${prevPending} |`);
3739
3812
  parts.push(`\n</details>`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spaceflow/review",
3
- "version": "0.61.0",
3
+ "version": "0.63.0",
4
4
  "description": "Spaceflow 代码审查插件,使用 LLM 对 PR 代码进行自动审查",
5
5
  "license": "MIT",
6
6
  "author": "Lydanne",
@@ -130,35 +130,85 @@ export class MarkdownFormatter implements ReviewReportFormatter, ReviewReportPar
130
130
  return "没有需要审查的文件";
131
131
  }
132
132
 
133
- const issuesByFile = new Map<string, { resolved: number; errors: number; warns: number }>();
133
+ // 🟢 已修复 | 🔴 待处理error | 🟡 待处理warn | 已解决(非代码修复)
134
+ const issuesByFile = new Map<
135
+ string,
136
+ { fixed: number; pendingErrors: number; pendingWarns: number; resolved: number }
137
+ >();
134
138
  for (const issue of issues) {
135
139
  if (issue.valid === "false") continue;
136
- const stats = issuesByFile.get(issue.file) || { resolved: 0, errors: 0, warns: 0 };
140
+ const stats = issuesByFile.get(issue.file) || {
141
+ fixed: 0,
142
+ pendingErrors: 0,
143
+ pendingWarns: 0,
144
+ resolved: 0,
145
+ };
137
146
  if (issue.fixed) {
147
+ stats.fixed++;
148
+ } else if (issue.resolved) {
138
149
  stats.resolved++;
139
150
  } else if (issue.severity === "error") {
140
- stats.errors++;
151
+ stats.pendingErrors++;
141
152
  } else {
142
- stats.warns++;
153
+ stats.pendingWarns++;
143
154
  }
144
155
  issuesByFile.set(issue.file, stats);
145
156
  }
146
157
 
147
158
  const lines: string[] = [];
148
- lines.push("| 文件 | 🟢 | 🔴 | 🟡 | 总结 |");
149
- lines.push("|------|----|----|----|----|");
159
+ lines.push("| 文件 | 总数 | 🟢 | 🔴 | 🟡 | |");
160
+ lines.push("|------|------|----|----|----|-----|");
161
+
162
+ // 汇总统计
163
+ let totalAll = 0;
164
+ let totalFixed = 0;
165
+ let totalPendingErrors = 0;
166
+ let totalPendingWarns = 0;
167
+ let totalResolved = 0;
150
168
 
169
+ const fileSummaryLines: string[] = [];
151
170
  for (const fileSummary of summaries) {
152
- const stats = issuesByFile.get(fileSummary.file) || { resolved: 0, errors: 0, warns: 0 };
153
- const summaryText = fileSummary.summary
154
- .split("\n")
155
- .filter((line) => line.trim())
156
- .join("<br>");
171
+ const stats = issuesByFile.get(fileSummary.file) || {
172
+ fixed: 0,
173
+ pendingErrors: 0,
174
+ pendingWarns: 0,
175
+ resolved: 0,
176
+ };
177
+ const fileTotal = stats.fixed + stats.pendingErrors + stats.pendingWarns + stats.resolved;
178
+ totalAll += fileTotal;
179
+ totalFixed += stats.fixed;
180
+ totalPendingErrors += stats.pendingErrors;
181
+ totalPendingWarns += stats.pendingWarns;
182
+ totalResolved += stats.resolved;
183
+
184
+ lines.push(
185
+ `| \`${fileSummary.file}\` | ${fileTotal} | ${stats.fixed} | ${stats.pendingErrors} | ${stats.pendingWarns} | ${stats.resolved} |`,
186
+ );
187
+
188
+ // 收集问题总结用于折叠块展示
189
+ if (fileSummary.summary.trim()) {
190
+ fileSummaryLines.push(`### 💡 \`${fileSummary.file}\``);
191
+ fileSummaryLines.push(`${fileSummary.summary.trim()}`);
192
+ fileSummaryLines.push("");
193
+ }
194
+ }
195
+
196
+ // 添加汇总行
197
+ if (summaries.length > 1) {
157
198
  lines.push(
158
- `| \`${fileSummary.file}\` | ${stats.resolved} | ${stats.errors} | ${stats.warns} | ${summaryText} |`,
199
+ `| **总计** | **${totalAll}** | **${totalFixed}** | **${totalPendingErrors}** | **${totalPendingWarns}** | **${totalResolved}** |`,
159
200
  );
160
201
  }
161
202
 
203
+ // 问题总结放到折叠块中
204
+ if (fileSummaryLines.length > 0) {
205
+ lines.push("");
206
+ lines.push("<details>");
207
+ lines.push("<summary>📝 问题总结</summary>\n");
208
+ lines.push(...fileSummaryLines);
209
+ lines.push("</details>");
210
+ }
211
+
162
212
  return lines.join("\n");
163
213
  }
164
214
 
@@ -289,8 +339,8 @@ export class MarkdownFormatter implements ReviewReportFormatter, ReviewReportPar
289
339
  const title = prNumber ? `PR #${prNumber} Review 状态统计` : "Review 状态统计";
290
340
  const lines = [`## 📊 ${title}\n`, `| 指标 | 数量 |`, `|------|------|`];
291
341
  lines.push(`| 总问题数 | ${stats.total} |`);
292
- lines.push(`| 已修复 | ${stats.fixed} |`);
293
- lines.push(`| 🟢 已解决 | ${stats.resolved} |`);
342
+ lines.push(`| 🟢 已修复 | ${stats.fixed} |`);
343
+ lines.push(`| 已解决 | ${stats.resolved} |`);
294
344
  lines.push(`| ❌ 无效 | ${stats.invalid} |`);
295
345
  lines.push(`| ⚠️ 待处理 | ${stats.pending} |`);
296
346
  lines.push(`| 修复率 | ${stats.fixRate}% |`);
@@ -28,26 +28,63 @@ export class TerminalFormatter implements ReviewReportFormatter {
28
28
  return "没有需要审查的文件";
29
29
  }
30
30
 
31
- const issuesByFile = new Map<string, { resolved: number; errors: number; warns: number }>();
31
+ // 🟢 已修复 | 🔴 待处理error | 🟡 待处理warn | 已解决(非代码修复)
32
+ const issuesByFile = new Map<
33
+ string,
34
+ { fixed: number; pendingErrors: number; pendingWarns: number; resolved: number }
35
+ >();
32
36
  for (const issue of issues) {
33
- const stats = issuesByFile.get(issue.file) || { resolved: 0, errors: 0, warns: 0 };
37
+ if (issue.valid === "false") continue;
38
+ const stats = issuesByFile.get(issue.file) || {
39
+ fixed: 0,
40
+ pendingErrors: 0,
41
+ pendingWarns: 0,
42
+ resolved: 0,
43
+ };
34
44
  if (issue.fixed) {
45
+ stats.fixed++;
46
+ } else if (issue.resolved) {
35
47
  stats.resolved++;
36
48
  } else if (issue.severity === "error") {
37
- stats.errors++;
49
+ stats.pendingErrors++;
38
50
  } else {
39
- stats.warns++;
51
+ stats.pendingWarns++;
40
52
  }
41
53
  issuesByFile.set(issue.file, stats);
42
54
  }
43
55
 
56
+ // 汇总统计
57
+ let totalAll = 0;
58
+ let totalFixed = 0;
59
+ let totalPendingErrors = 0;
60
+ let totalPendingWarns = 0;
61
+ let totalResolved = 0;
62
+
44
63
  const lines: string[] = [];
45
64
  for (const fileSummary of summaries) {
46
- const stats = issuesByFile.get(fileSummary.file) || { resolved: 0, errors: 0, warns: 0 };
47
- const resolvedText = stats.resolved > 0 ? `${GREEN}✅ ${stats.resolved} 已解决${RESET}` : "";
48
- const errorText = stats.errors > 0 ? `${RED}🔴 ${stats.errors} error${RESET}` : "";
49
- const warnText = stats.warns > 0 ? `${YELLOW}🟡 ${stats.warns} warn${RESET}` : "";
50
- const statsText = [resolvedText, errorText, warnText].filter(Boolean).join(" / ");
65
+ const stats = issuesByFile.get(fileSummary.file) || {
66
+ fixed: 0,
67
+ pendingErrors: 0,
68
+ pendingWarns: 0,
69
+ resolved: 0,
70
+ };
71
+ const fileTotal = stats.fixed + stats.pendingErrors + stats.pendingWarns + stats.resolved;
72
+ totalAll += fileTotal;
73
+ totalFixed += stats.fixed;
74
+ totalPendingErrors += stats.pendingErrors;
75
+ totalPendingWarns += stats.pendingWarns;
76
+ totalResolved += stats.resolved;
77
+
78
+ const totalText = fileTotal > 0 ? `${BOLD}${fileTotal} 问题${RESET}` : "";
79
+ const fixedText = stats.fixed > 0 ? `${GREEN}🟢 ${stats.fixed} 已修复${RESET}` : "";
80
+ const errorText =
81
+ stats.pendingErrors > 0 ? `${RED}🔴 ${stats.pendingErrors} error${RESET}` : "";
82
+ const warnText =
83
+ stats.pendingWarns > 0 ? `${YELLOW}🟡 ${stats.pendingWarns} warn${RESET}` : "";
84
+ const resolvedText = stats.resolved > 0 ? `⚪ ${stats.resolved} 已解决` : "";
85
+ const statsText = [totalText, fixedText, errorText, warnText, resolvedText]
86
+ .filter(Boolean)
87
+ .join(" / ");
51
88
 
52
89
  if (statsText) {
53
90
  lines.push(`${BOLD}${fileSummary.file}${RESET} (${statsText}): ${fileSummary.summary}`);
@@ -56,6 +93,17 @@ export class TerminalFormatter implements ReviewReportFormatter {
56
93
  }
57
94
  }
58
95
 
96
+ // 添加汇总行
97
+ if (summaries.length > 1) {
98
+ lines.push("");
99
+ const summaryParts = [`${BOLD}总计: ${totalAll} 问题${RESET}`];
100
+ if (totalFixed > 0) summaryParts.push(`${GREEN}🟢 ${totalFixed} 已修复${RESET}`);
101
+ if (totalPendingErrors > 0) summaryParts.push(`${RED}🔴 ${totalPendingErrors} error${RESET}`);
102
+ if (totalPendingWarns > 0) summaryParts.push(`${YELLOW}🟡 ${totalPendingWarns} warn${RESET}`);
103
+ if (totalResolved > 0) summaryParts.push(`⚪ ${totalResolved} 已解决`);
104
+ lines.push(summaryParts.join(" / "));
105
+ }
106
+
59
107
  return lines.join("\n");
60
108
  }
61
109
 
@@ -123,8 +171,8 @@ export class TerminalFormatter implements ReviewReportFormatter {
123
171
  const title = prNumber ? `PR #${prNumber} Review 状态统计` : "Review 状态统计";
124
172
  const lines = [`\n${BOLD}${CYAN}📊 ${title}:${RESET}`];
125
173
  lines.push(` 总问题数: ${stats.total}`);
126
- lines.push(` ${GREEN} 已修复: ${stats.fixed}${RESET}`);
127
- lines.push(` ${GREEN}🟢 已解决: ${stats.resolved}${RESET}`);
174
+ lines.push(` ${GREEN}🟢 已修复: ${stats.fixed}${RESET}`);
175
+ lines.push(` 已解决: ${stats.resolved}`);
128
176
  lines.push(` ${RED}❌ 无效: ${stats.invalid}${RESET}`);
129
177
  lines.push(` ${YELLOW}⚠️ 待处理: ${stats.pending}${RESET}`);
130
178
  lines.push(` 修复率: ${stats.fixRate}%`);
@@ -2506,13 +2506,17 @@ ${fileChanges || "无"}`;
2506
2506
  round: number,
2507
2507
  allIssues: ReviewIssue[],
2508
2508
  ): string {
2509
- const errorCount = issues.filter((i) => i.severity === "error").length;
2510
- const warnCount = issues.filter((i) => i.severity === "warn").length;
2509
+ // 只统计待处理的问题(未修复且未解决)
2510
+ const pendingIssues = issues.filter((i) => !i.fixed && !i.resolved && i.valid !== "false");
2511
+ const pendingErrors = pendingIssues.filter((i) => i.severity === "error").length;
2512
+ const pendingWarns = pendingIssues.filter((i) => i.severity === "warn").length;
2511
2513
  const fileCount = new Set(issues.map((i) => i.file)).size;
2512
2514
 
2515
+ const totalPending = pendingErrors + pendingWarns;
2513
2516
  const badges: string[] = [];
2514
- if (errorCount > 0) badges.push(`🔴 ${errorCount}`);
2515
- if (warnCount > 0) badges.push(`🟡 ${warnCount}`);
2517
+ if (totalPending > 0) badges.push(`⚠️ ${totalPending}`);
2518
+ if (pendingErrors > 0) badges.push(`🔴 ${pendingErrors}`);
2519
+ if (pendingWarns > 0) badges.push(`🟡 ${pendingWarns}`);
2516
2520
 
2517
2521
  const parts: string[] = [REVIEW_LINE_COMMENTS_MARKER];
2518
2522
  parts.push(`### 🚀 Spaceflow Review · Round ${round}`);
@@ -2540,8 +2544,8 @@ ${fileChanges || "无"}`;
2540
2544
  );
2541
2545
  parts.push(`| 状态 | 数量 |`);
2542
2546
  parts.push(`|------|------|`);
2543
- if (prevFixed > 0) parts.push(`| 已修复 | ${prevFixed} |`);
2544
- if (prevResolved > 0) parts.push(`| 🟢 已解决 | ${prevResolved} |`);
2547
+ if (prevFixed > 0) parts.push(`| 🟢 已修复 | ${prevFixed} |`);
2548
+ if (prevResolved > 0) parts.push(`| 已解决 | ${prevResolved} |`);
2545
2549
  if (prevInvalid > 0) parts.push(`| ❌ 无效 | ${prevInvalid} |`);
2546
2550
  if (prevPending > 0) parts.push(`| ⚠️ 待处理 | ${prevPending} |`);
2547
2551
  parts.push(`\n</details>`);