@spaceflow/review 0.68.0 → 0.69.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,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.68.0](https://github.com/Lydanne/spaceflow/compare/@spaceflow/review@0.67.0...@spaceflow/review@0.68.0) (2026-03-04)
4
+
5
+ ### 代码重构
6
+
7
+ * **review:** 区分 ☹️ 和 👎 reaction 的语义,☹️ 标记无效,👎 标记未解决 ([f1419fe](https://github.com/Lydanne/spaceflow/commit/f1419fe47448a80f373ffac082ac3a2e9320d200))
8
+
9
+ ### 其他修改
10
+
11
+ * **review-summary:** released version 0.35.0 [no ci] ([4f2607d](https://github.com/Lydanne/spaceflow/commit/4f2607def2725946f32eccc4aa4e687a3cdd9bab))
12
+ * **scripts:** released version 0.28.0 [no ci] ([55db5cf](https://github.com/Lydanne/spaceflow/commit/55db5cfa1dc0a1e318085caa0cfd9f91b06dcb21))
13
+ * **shell:** released version 0.28.0 [no ci] ([01f180f](https://github.com/Lydanne/spaceflow/commit/01f180f2508e75524a33e66fea580a738adc689f))
14
+
3
15
  ## [0.67.0](https://github.com/Lydanne/spaceflow/compare/@spaceflow/review@0.66.0...@spaceflow/review@0.67.0) (2026-03-03)
4
16
 
5
17
  ### 新特性
package/dist/index.js CHANGED
@@ -1169,24 +1169,28 @@ class MarkdownFormatter {
1169
1169
  if (summaries.length === 0) {
1170
1170
  return "没有需要审查的文件";
1171
1171
  }
1172
- // 🟢 已修复 | 🔴 待处理error | 🟡 待处理warn | ⚪ 已解决(非代码修复)
1172
+ // 🟢 已修复 | 🔴 error数量 | 🟡 warn数量 | ⚪ 已解决(非代码修复)
1173
1173
  const issuesByFile = new Map();
1174
1174
  for (const issue of issues){
1175
1175
  if (issue.valid === "false") continue;
1176
1176
  const stats = issuesByFile.get(issue.file) || {
1177
+ total: 0,
1177
1178
  fixed: 0,
1178
- pendingErrors: 0,
1179
- pendingWarns: 0,
1179
+ errorCount: 0,
1180
+ warnCount: 0,
1180
1181
  resolved: 0
1181
1182
  };
1183
+ stats.total++;
1182
1184
  if (issue.fixed) {
1183
1185
  stats.fixed++;
1184
- } else if (issue.resolved) {
1186
+ }
1187
+ if (issue.resolved) {
1185
1188
  stats.resolved++;
1186
- } else if (issue.severity === "error") {
1187
- stats.pendingErrors++;
1189
+ }
1190
+ if (issue.severity === "error") {
1191
+ stats.errorCount++;
1188
1192
  } else {
1189
- stats.pendingWarns++;
1193
+ stats.warnCount++;
1190
1194
  }
1191
1195
  issuesByFile.set(issue.file, stats);
1192
1196
  }
@@ -1202,18 +1206,18 @@ class MarkdownFormatter {
1202
1206
  const fileSummaryLines = [];
1203
1207
  for (const fileSummary of summaries){
1204
1208
  const stats = issuesByFile.get(fileSummary.file) || {
1209
+ total: 0,
1205
1210
  fixed: 0,
1206
- pendingErrors: 0,
1207
- pendingWarns: 0,
1211
+ errorCount: 0,
1212
+ warnCount: 0,
1208
1213
  resolved: 0
1209
1214
  };
1210
- const fileTotal = stats.fixed + stats.pendingErrors + stats.pendingWarns + stats.resolved;
1211
- totalAll += fileTotal;
1215
+ totalAll += stats.total;
1212
1216
  totalFixed += stats.fixed;
1213
- totalPendingErrors += stats.pendingErrors;
1214
- totalPendingWarns += stats.pendingWarns;
1217
+ totalPendingErrors += stats.errorCount;
1218
+ totalPendingWarns += stats.warnCount;
1215
1219
  totalResolved += stats.resolved;
1216
- lines.push(`| \`${fileSummary.file}\` | ${fileTotal} | ${stats.fixed} | ${stats.pendingErrors} | ${stats.pendingWarns} | ${stats.resolved} |`);
1220
+ lines.push(`| \`${fileSummary.file}\` | ${stats.total} | ${stats.fixed} | ${stats.errorCount} | ${stats.warnCount} | ${stats.resolved} |`);
1217
1221
  // 收集问题总结用于折叠块展示
1218
1222
  if (fileSummary.summary.trim()) {
1219
1223
  fileSummaryLines.push(`### 💡 \`${fileSummary.file}\``);
@@ -1386,19 +1390,23 @@ class TerminalFormatter {
1386
1390
  for (const issue of issues){
1387
1391
  if (issue.valid === "false") continue;
1388
1392
  const stats = issuesByFile.get(issue.file) || {
1393
+ total: 0,
1389
1394
  fixed: 0,
1390
- pendingErrors: 0,
1391
- pendingWarns: 0,
1395
+ errorCount: 0,
1396
+ warnCount: 0,
1392
1397
  resolved: 0
1393
1398
  };
1399
+ stats.total++;
1394
1400
  if (issue.fixed) {
1395
1401
  stats.fixed++;
1396
- } else if (issue.resolved) {
1402
+ }
1403
+ if (issue.resolved) {
1397
1404
  stats.resolved++;
1398
- } else if (issue.severity === "error") {
1399
- stats.pendingErrors++;
1405
+ }
1406
+ if (issue.severity === "error") {
1407
+ stats.errorCount++;
1400
1408
  } else {
1401
- stats.pendingWarns++;
1409
+ stats.warnCount++;
1402
1410
  }
1403
1411
  issuesByFile.set(issue.file, stats);
1404
1412
  }
@@ -1411,21 +1419,21 @@ class TerminalFormatter {
1411
1419
  const lines = [];
1412
1420
  for (const fileSummary of summaries){
1413
1421
  const stats = issuesByFile.get(fileSummary.file) || {
1422
+ total: 0,
1414
1423
  fixed: 0,
1415
- pendingErrors: 0,
1416
- pendingWarns: 0,
1424
+ errorCount: 0,
1425
+ warnCount: 0,
1417
1426
  resolved: 0
1418
1427
  };
1419
- const fileTotal = stats.fixed + stats.pendingErrors + stats.pendingWarns + stats.resolved;
1420
- totalAll += fileTotal;
1428
+ totalAll += stats.total;
1421
1429
  totalFixed += stats.fixed;
1422
- totalPendingErrors += stats.pendingErrors;
1423
- totalPendingWarns += stats.pendingWarns;
1430
+ totalPendingErrors += stats.errorCount;
1431
+ totalPendingWarns += stats.warnCount;
1424
1432
  totalResolved += stats.resolved;
1425
- const totalText = fileTotal > 0 ? `${BOLD}${fileTotal} 问题${RESET}` : "";
1433
+ const totalText = stats.total > 0 ? `${BOLD}${stats.total} 问题${RESET}` : "";
1426
1434
  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}` : "";
1435
+ const errorText = stats.errorCount > 0 ? `${RED}🔴 ${stats.errorCount} error${RESET}` : "";
1436
+ const warnText = stats.warnCount > 0 ? `${YELLOW}🟡 ${stats.warnCount} warn${RESET}` : "";
1429
1437
  const resolvedText = stats.resolved > 0 ? `⚪ ${stats.resolved} 已解决` : "";
1430
1438
  const statsText = [
1431
1439
  totalText,
@@ -2602,18 +2610,20 @@ class ReviewService {
2602
2610
  specs = await this.loadSpecs(specSources, verbose);
2603
2611
  fileContents = await this.getFileContents(owner, repo, changedFiles, commits, headSha, prNumber, verbose);
2604
2612
  }
2605
- return this.issueVerifyService.verifyIssueFixes(issues, fileContents, specs, llmMode, verbose, context.verifyConcurrency);
2613
+ return await this.issueVerifyService.verifyIssueFixes(issues, fileContents, specs, llmMode, verbose, context.verifyConcurrency);
2606
2614
  }
2607
2615
  /**
2608
2616
  * 计算问题状态统计
2609
2617
  */ calculateIssueStats(issues) {
2610
2618
  const total = issues.length;
2611
- const fixed = issues.filter((i)=>i.fixed).length;
2612
- const resolved = issues.filter((i)=>i.resolved && !i.fixed).length;
2613
- const invalid = issues.filter((i)=>i.valid === "false" && !i.fixed && !i.resolved).length;
2614
- const pending = total - fixed - resolved - invalid;
2615
- const fixRate = total > 0 ? Math.round(fixed / total * 100 * 10) / 10 : 0;
2616
- const resolveRate = total > 0 ? Math.round((fixed + resolved) / total * 100 * 10) / 10 : 0;
2619
+ const validIssue = issues.filter((i)=>i.valid !== "false");
2620
+ const validTotal = validIssue.length;
2621
+ const fixed = validIssue.filter((i)=>i.fixed).length;
2622
+ const resolved = validIssue.filter((i)=>i.resolved).length;
2623
+ const invalid = total - validTotal;
2624
+ const pending = validTotal - fixed;
2625
+ const fixRate = validTotal > 0 ? Math.round(fixed / validTotal * 100 * 10) / 10 : 0;
2626
+ const resolveRate = validTotal > 0 ? Math.round(resolved / validTotal * 100 * 10) / 10 : 0;
2617
2627
  return {
2618
2628
  total,
2619
2629
  fixed,
@@ -4314,6 +4324,7 @@ class IssueVerifyService {
4314
4324
  }
4315
4325
  verifiedIssues.push({
4316
4326
  ...issue,
4327
+ resolved: new Date().toISOString(),
4317
4328
  fixed: new Date().toISOString(),
4318
4329
  valid: FALSE,
4319
4330
  reason: "文件已删除"
@@ -4397,6 +4408,7 @@ class IssueVerifyService {
4397
4408
  console.log(` ✅ 已修复: ${result.reason}`);
4398
4409
  }
4399
4410
  updatedIssue.fixed = new Date().toISOString();
4411
+ updatedIssue.resolved = new Date().toISOString();
4400
4412
  } else if (!result.valid) {
4401
4413
  if (shouldLog(verbose, 1)) {
4402
4414
  console.log(` ❌ 无效问题: ${result.reason}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spaceflow/review",
3
- "version": "0.68.0",
3
+ "version": "0.69.0",
4
4
  "description": "Spaceflow 代码审查插件,使用 LLM 对 PR 代码进行自动审查",
5
5
  "license": "MIT",
6
6
  "author": "Lydanne",
@@ -107,6 +107,7 @@ export class IssueVerifyService {
107
107
  }
108
108
  verifiedIssues.push({
109
109
  ...issue,
110
+ resolved: new Date().toISOString(),
110
111
  fixed: new Date().toISOString(),
111
112
  valid: FALSE,
112
113
  reason: "文件已删除",
@@ -209,6 +210,7 @@ export class IssueVerifyService {
209
210
  console.log(` ✅ 已修复: ${result.reason}`);
210
211
  }
211
212
  updatedIssue.fixed = new Date().toISOString();
213
+ updatedIssue.resolved = new Date().toISOString();
212
214
  } else if (!result.valid) {
213
215
  if (shouldLog(verbose, 1)) {
214
216
  console.log(` ❌ 无效问题: ${result.reason}`);
@@ -130,27 +130,37 @@ export class MarkdownFormatter implements ReviewReportFormatter, ReviewReportPar
130
130
  return "没有需要审查的文件";
131
131
  }
132
132
 
133
- // 🟢 已修复 | 🔴 待处理error | 🟡 待处理warn | ⚪ 已解决(非代码修复)
133
+ // 🟢 已修复 | 🔴 error数量 | 🟡 warn数量 | ⚪ 已解决(非代码修复)
134
134
  const issuesByFile = new Map<
135
135
  string,
136
- { fixed: number; pendingErrors: number; pendingWarns: number; resolved: number }
136
+ {
137
+ fixed: number;
138
+ errorCount: number;
139
+ warnCount: number;
140
+ resolved: number;
141
+ total: number;
142
+ }
137
143
  >();
138
144
  for (const issue of issues) {
139
145
  if (issue.valid === "false") continue;
140
146
  const stats = issuesByFile.get(issue.file) || {
147
+ total: 0,
141
148
  fixed: 0,
142
- pendingErrors: 0,
143
- pendingWarns: 0,
149
+ errorCount: 0,
150
+ warnCount: 0,
144
151
  resolved: 0,
145
152
  };
153
+ stats.total++;
146
154
  if (issue.fixed) {
147
155
  stats.fixed++;
148
- } else if (issue.resolved) {
156
+ }
157
+ if (issue.resolved) {
149
158
  stats.resolved++;
150
- } else if (issue.severity === "error") {
151
- stats.pendingErrors++;
159
+ }
160
+ if (issue.severity === "error") {
161
+ stats.errorCount++;
152
162
  } else {
153
- stats.pendingWarns++;
163
+ stats.warnCount++;
154
164
  }
155
165
  issuesByFile.set(issue.file, stats);
156
166
  }
@@ -169,20 +179,20 @@ export class MarkdownFormatter implements ReviewReportFormatter, ReviewReportPar
169
179
  const fileSummaryLines: string[] = [];
170
180
  for (const fileSummary of summaries) {
171
181
  const stats = issuesByFile.get(fileSummary.file) || {
182
+ total: 0,
172
183
  fixed: 0,
173
- pendingErrors: 0,
174
- pendingWarns: 0,
184
+ errorCount: 0,
185
+ warnCount: 0,
175
186
  resolved: 0,
176
187
  };
177
- const fileTotal = stats.fixed + stats.pendingErrors + stats.pendingWarns + stats.resolved;
178
- totalAll += fileTotal;
188
+ totalAll += stats.total;
179
189
  totalFixed += stats.fixed;
180
- totalPendingErrors += stats.pendingErrors;
181
- totalPendingWarns += stats.pendingWarns;
190
+ totalPendingErrors += stats.errorCount;
191
+ totalPendingWarns += stats.warnCount;
182
192
  totalResolved += stats.resolved;
183
193
 
184
194
  lines.push(
185
- `| \`${fileSummary.file}\` | ${fileTotal} | ${stats.fixed} | ${stats.pendingErrors} | ${stats.pendingWarns} | ${stats.resolved} |`,
195
+ `| \`${fileSummary.file}\` | ${stats.total} | ${stats.fixed} | ${stats.errorCount} | ${stats.warnCount} | ${stats.resolved} |`,
186
196
  );
187
197
 
188
198
  // 收集问题总结用于折叠块展示
@@ -31,24 +31,34 @@ export class TerminalFormatter implements ReviewReportFormatter {
31
31
  // 🟢 已修复 | 🔴 待处理error | 🟡 待处理warn | ⚪ 已解决(非代码修复)
32
32
  const issuesByFile = new Map<
33
33
  string,
34
- { fixed: number; pendingErrors: number; pendingWarns: number; resolved: number }
34
+ {
35
+ fixed: number;
36
+ errorCount: number;
37
+ warnCount: number;
38
+ resolved: number;
39
+ total: number;
40
+ }
35
41
  >();
36
42
  for (const issue of issues) {
37
43
  if (issue.valid === "false") continue;
38
44
  const stats = issuesByFile.get(issue.file) || {
45
+ total: 0,
39
46
  fixed: 0,
40
- pendingErrors: 0,
41
- pendingWarns: 0,
47
+ errorCount: 0,
48
+ warnCount: 0,
42
49
  resolved: 0,
43
50
  };
51
+ stats.total++;
44
52
  if (issue.fixed) {
45
53
  stats.fixed++;
46
- } else if (issue.resolved) {
54
+ }
55
+ if (issue.resolved) {
47
56
  stats.resolved++;
48
- } else if (issue.severity === "error") {
49
- stats.pendingErrors++;
57
+ }
58
+ if (issue.severity === "error") {
59
+ stats.errorCount++;
50
60
  } else {
51
- stats.pendingWarns++;
61
+ stats.warnCount++;
52
62
  }
53
63
  issuesByFile.set(issue.file, stats);
54
64
  }
@@ -63,24 +73,22 @@ export class TerminalFormatter implements ReviewReportFormatter {
63
73
  const lines: string[] = [];
64
74
  for (const fileSummary of summaries) {
65
75
  const stats = issuesByFile.get(fileSummary.file) || {
76
+ total: 0,
66
77
  fixed: 0,
67
- pendingErrors: 0,
68
- pendingWarns: 0,
78
+ errorCount: 0,
79
+ warnCount: 0,
69
80
  resolved: 0,
70
81
  };
71
- const fileTotal = stats.fixed + stats.pendingErrors + stats.pendingWarns + stats.resolved;
72
- totalAll += fileTotal;
82
+ totalAll += stats.total;
73
83
  totalFixed += stats.fixed;
74
- totalPendingErrors += stats.pendingErrors;
75
- totalPendingWarns += stats.pendingWarns;
84
+ totalPendingErrors += stats.errorCount;
85
+ totalPendingWarns += stats.warnCount;
76
86
  totalResolved += stats.resolved;
77
87
 
78
- const totalText = fileTotal > 0 ? `${BOLD}${fileTotal} 问题${RESET}` : "";
88
+ const totalText = stats.total > 0 ? `${BOLD}${stats.total} 问题${RESET}` : "";
79
89
  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}` : "";
90
+ const errorText = stats.errorCount > 0 ? `${RED}🔴 ${stats.errorCount} error${RESET}` : "";
91
+ const warnText = stats.warnCount > 0 ? `${YELLOW}🟡 ${stats.warnCount} warn${RESET}` : "";
84
92
  const resolvedText = stats.resolved > 0 ? `⚪ ${stats.resolved} 已解决` : "";
85
93
  const statsText = [totalText, fixedText, errorText, warnText, resolvedText]
86
94
  .filter(Boolean)
@@ -125,9 +125,9 @@ export interface ReviewStats {
125
125
  invalid: number;
126
126
  /** 待处理数 */
127
127
  pending: number;
128
- /** 修复率 (0-100),仅计算代码修复:fixed / total */
128
+ /** 修复率 (0-100),仅计算代码修复:fixed / validTotal */
129
129
  fixRate: number;
130
- /** 解决率 (0-100),计算修复+解决:(fixed + resolved) / total */
130
+ /** 解决率 (0-100),计算已解决:resolved / validTotal */
131
131
  resolveRate: number;
132
132
  }
133
133
 
@@ -1079,7 +1079,7 @@ export class ReviewService {
1079
1079
  );
1080
1080
  }
1081
1081
 
1082
- return this.issueVerifyService.verifyIssueFixes(
1082
+ return await this.issueVerifyService.verifyIssueFixes(
1083
1083
  issues,
1084
1084
  fileContents,
1085
1085
  specs,
@@ -1094,12 +1094,14 @@ export class ReviewService {
1094
1094
  */
1095
1095
  protected calculateIssueStats(issues: ReviewIssue[]): ReviewStats {
1096
1096
  const total = issues.length;
1097
- const fixed = issues.filter((i) => i.fixed).length;
1098
- const resolved = issues.filter((i) => i.resolved && !i.fixed).length;
1099
- const invalid = issues.filter((i) => i.valid === "false" && !i.fixed && !i.resolved).length;
1100
- const pending = total - fixed - resolved - invalid;
1101
- const fixRate = total > 0 ? Math.round((fixed / total) * 100 * 10) / 10 : 0;
1102
- const resolveRate = total > 0 ? Math.round(((fixed + resolved) / total) * 100 * 10) / 10 : 0;
1097
+ const validIssue = issues.filter((i) => i.valid !== "false");
1098
+ const validTotal = validIssue.length;
1099
+ const fixed = validIssue.filter((i) => i.fixed).length;
1100
+ const resolved = validIssue.filter((i) => i.resolved).length;
1101
+ const invalid = total - validTotal;
1102
+ const pending = validTotal - fixed;
1103
+ const fixRate = validTotal > 0 ? Math.round((fixed / validTotal) * 100 * 10) / 10 : 0;
1104
+ const resolveRate = validTotal > 0 ? Math.round((resolved / validTotal) * 100 * 10) / 10 : 0;
1103
1105
  return { total, fixed, resolved, invalid, pending, fixRate, resolveRate };
1104
1106
  }
1105
1107