@spaceflow/review 0.76.0 → 0.78.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.
Files changed (37) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/index.js +3830 -2469
  3. package/package.json +2 -2
  4. package/src/deletion-impact.service.ts +17 -130
  5. package/src/index.ts +34 -2
  6. package/src/issue-verify.service.ts +18 -82
  7. package/src/locales/en/review.json +2 -1
  8. package/src/locales/zh-cn/review.json +2 -1
  9. package/src/mcp/index.ts +4 -1
  10. package/src/prompt/code-review.ts +95 -0
  11. package/src/prompt/deletion-impact.ts +105 -0
  12. package/src/prompt/index.ts +37 -0
  13. package/src/prompt/issue-verify.ts +86 -0
  14. package/src/prompt/pr-description.ts +149 -0
  15. package/src/prompt/schemas.ts +106 -0
  16. package/src/prompt/types.ts +53 -0
  17. package/src/pull-request-model.ts +236 -0
  18. package/src/review-context.ts +433 -0
  19. package/src/review-includes-filter.spec.ts +284 -0
  20. package/src/review-includes-filter.ts +196 -0
  21. package/src/review-issue-filter.ts +523 -0
  22. package/src/review-llm.ts +543 -0
  23. package/src/review-result-model.spec.ts +657 -0
  24. package/src/review-result-model.ts +1046 -0
  25. package/src/review-spec/review-spec.service.ts +26 -5
  26. package/src/review-spec/types.ts +2 -0
  27. package/src/review.config.ts +40 -5
  28. package/src/review.service.spec.ts +102 -1625
  29. package/src/review.service.ts +608 -2742
  30. package/src/system-rules/index.ts +48 -0
  31. package/src/system-rules/max-lines-per-file.ts +57 -0
  32. package/src/types/review-llm.ts +21 -0
  33. package/src/utils/review-llm.spec.ts +277 -0
  34. package/src/utils/review-llm.ts +177 -0
  35. package/src/utils/review-pr-comment.spec.ts +340 -0
  36. package/src/utils/review-pr-comment.ts +186 -0
  37. package/tsconfig.json +1 -1
@@ -13,6 +13,7 @@ import { homedir } from "os";
13
13
  import { execSync } from "child_process";
14
14
  import micromatch from "micromatch";
15
15
  import { ReviewSpec, ReviewRule, RuleExample, Severity } from "./types";
16
+ import { extractGlobsFromIncludes } from "../review-includes-filter";
16
17
 
17
18
  /** 远程规则缓存 TTL(毫秒),默认 5 分钟 */
18
19
  const REMOTE_SPEC_CACHE_TTL = 5 * 60 * 1000;
@@ -69,7 +70,23 @@ export class ReviewSpecService {
69
70
  }
70
71
  }
71
72
 
72
- return specs.filter((spec) => spec.extensions.some((ext) => changedExtensions.has(ext)));
73
+ console.log(
74
+ `[filterApplicableSpecs] changedExtensions=${JSON.stringify([...changedExtensions])}, specs count=${specs.length}`,
75
+ );
76
+ const result = specs.filter((spec) => {
77
+ const matches = spec.extensions.some((ext) => changedExtensions.has(ext));
78
+ if (!matches) {
79
+ console.log(
80
+ `[filterApplicableSpecs] spec ${spec.filename} (ext: ${JSON.stringify(spec.extensions)}) NOT matched`,
81
+ );
82
+ } else {
83
+ console.log(
84
+ `[filterApplicableSpecs] spec ${spec.filename} (ext: ${JSON.stringify(spec.extensions)}) MATCHED`,
85
+ );
86
+ }
87
+ return matches;
88
+ });
89
+ return result;
73
90
  }
74
91
 
75
92
  async loadReviewSpecs(specDir: string): Promise<ReviewSpec[]> {
@@ -524,8 +541,10 @@ export class ReviewSpecService {
524
541
  return true;
525
542
  }
526
543
 
527
- // 检查文件是否匹配 includes 模式
528
- const matches = micromatch.isMatch(issue.file, includes, { matchBase: true });
544
+ // 检查文件是否匹配 includes 模式(转换为纯 glob,避免 status| 前缀和 code-* 空串传入 micromatch)
545
+ const globs = extractGlobsFromIncludes(includes);
546
+ if (globs.length === 0) return true;
547
+ const matches = micromatch.isMatch(issue.file, globs, { matchBase: true });
529
548
  if (!matches) {
530
549
  // console.log(` Issue [${issue.ruleId}] 在文件 ${issue.file} 不匹配 includes 模式,跳过`);
531
550
  }
@@ -638,8 +657,10 @@ export class ReviewSpecService {
638
657
  if (scoped.includes.length === 0) {
639
658
  return true;
640
659
  }
641
- // 使用 micromatch 检查文件是否匹配 includes 模式
642
- return issueFile && micromatch.isMatch(issueFile, scoped.includes, { matchBase: true });
660
+ // 使用 micromatch 检查文件是否匹配 includes 模式(转换为纯 glob)
661
+ const globs = extractGlobsFromIncludes(scoped.includes);
662
+ if (globs.length === 0) return true;
663
+ return issueFile && micromatch.isMatch(issueFile, globs, { matchBase: true });
643
664
  });
644
665
 
645
666
  if (matched) {
@@ -147,6 +147,8 @@ export interface ReviewResult {
147
147
  summary: FileSummary[];
148
148
  deletionImpact?: DeletionImpactResult;
149
149
  round: number; // 当前 review 的轮次
150
+ /** 最后一次审查时的 head commit SHA */
151
+ headSha?: string;
150
152
  /** 问题统计信息 */
151
153
  stats?: ReviewStats;
152
154
  }
@@ -27,6 +27,15 @@ export type AnalyzeDeletionsMode = z.infer<typeof analyzeDeletionsModeSchema>;
27
27
  /** 审查规则严重级别 */
28
28
  export type Severity = z.infer<typeof severitySchema>;
29
29
 
30
+ /**
31
+ * 系统规则配置,不依赖 LLM,在构建 prompt 前直接检查并生成系统问题。
32
+ * 格式为 [阈值, severity]
33
+ */
34
+ export interface SystemRules {
35
+ /** 单文件最大审查行数,超过时跳过 LLM 并生成系统问题。格式: [maxLine, severity] */
36
+ maxLinesPerFile?: [number, Severity];
37
+ }
38
+
30
39
  /**
31
40
  * 变更文件处理策略
32
41
  * - 'invalidate': 将变更文件的历史问题标记为无效(默认)
@@ -47,6 +56,11 @@ export interface ReviewOptions {
47
56
  references?: string[];
48
57
  verbose?: VerboseLevel;
49
58
  includes?: string[];
59
+ /**
60
+ * 代码结构过滤配置,指定在代码审查时要关注的代码结构类型
61
+ * 支持格式:"function"、"class"、"interface"、"type"、"method"
62
+ */
63
+ whenModifiedCode?: string[];
50
64
  llmMode?: LLMMode;
51
65
  files?: string[];
52
66
  commits?: string[];
@@ -80,17 +94,28 @@ export interface ReviewOptions {
80
94
  */
81
95
  local?: LocalReviewMode;
82
96
  /**
83
- * 跳过重复的 review workflow 检查
84
- * - true: 启用检查,当检测到同名 workflow 正在运行时跳过审查
85
- * - false: 禁用检查(默认)
97
+ * 处理重复 workflow 的策略
98
+ * - 'off': 禁用检查
99
+ * - 'skip': 检测到同名 workflow 正在运行时跳过审查
100
+ * - 'delete': 检测到同名 workflow 时删除旧的 AI Review 评论和 PR Review(默认)
86
101
  */
87
- skipDuplicateWorkflow?: boolean;
102
+ duplicateWorkflowResolved?: "off" | "skip" | "delete";
88
103
  /**
89
104
  * 自动批准合并
90
105
  * - true: 当所有问题都已解决时,自动提交 APPROVE review
91
106
  * - false: 不自动批准(默认)
92
107
  */
93
108
  autoApprove?: boolean;
109
+ /**
110
+ * 存在未解决问题时以非零退出码退出(工作流抛出异常)
111
+ * - 'off': 禁用(默认),即使有问题也正常退出
112
+ * - 'warn': 有未解决的 warn 级别问题时抛出异常
113
+ * - 'error': 有未解决的 error 级别问题时抛出异常
114
+ * - 'warn+error': 有未解决的 warn 或 error 级别问题时抛出异常
115
+ */
116
+ failOnIssues?: "off" | "warn" | "error" | "warn+error";
117
+ /** 系统规则配置,不依赖 LLM,直接在检查阶段生成系统问题 */
118
+ systemRules?: SystemRules;
94
119
  }
95
120
 
96
121
  /** review 命令配置 schema(LLM 敏感配置由系统 llm.config.ts 管理) */
@@ -99,6 +124,7 @@ export const reviewSchema = () =>
99
124
  references: z.array(z.string()).optional(),
100
125
  llmMode: llmModeSchema.default("openai").optional(),
101
126
  includes: z.array(z.string()).optional(),
127
+ whenModifiedCode: z.array(z.string()).optional(),
102
128
  rules: z.record(z.string(), severitySchema).optional(),
103
129
  verifyFixes: z.boolean().default(false),
104
130
  verifyFixesConcurrency: z.number().default(10).optional(),
@@ -112,8 +138,17 @@ export const reviewSchema = () =>
112
138
  retries: z.number().default(0).optional(),
113
139
  retryDelay: z.number().default(1000).optional(),
114
140
  invalidateChangedFiles: invalidateChangedFilesSchema.default("invalidate").optional(),
115
- skipDuplicateWorkflow: z.boolean().default(false).optional(),
141
+ duplicateWorkflowResolved: z.enum(["off", "skip", "delete"]).default("delete").optional(),
116
142
  autoApprove: z.boolean().default(false).optional(),
143
+ failOnIssues: z.enum(["off", "warn", "error", "warn+error"]).default("off").optional(),
144
+ systemRules: z
145
+ .object({
146
+ maxLinesPerFile: z
147
+ .tuple([z.number(), severitySchema])
148
+ .transform((v): [number, Severity] => [v[0], v[1]])
149
+ .optional(),
150
+ })
151
+ .optional(),
117
152
  });
118
153
 
119
154
  /** review 配置类型(从 schema 推导) */