@spaceflow/review 5.0.0 → 5.0.1

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/README.md +5 -11
  2. package/dist/index.js +11 -39
  3. package/package.json +3 -3
  4. package/src/README.md +4 -4
  5. package/src/deletion-impact.service.spec.ts +8 -12
  6. package/src/deletion-impact.service.ts +5 -5
  7. package/src/issue-verify.service.spec.ts +0 -4
  8. package/src/locales/en/review.json +2 -2
  9. package/src/locales/zh-cn/review.json +2 -2
  10. package/src/mcp/index.ts +1 -5
  11. package/src/parse-title-options.spec.ts +4 -4
  12. package/src/parse-title-options.ts +3 -3
  13. package/src/review-context.ts +1 -1
  14. package/src/review-llm.spec.ts +1 -18
  15. package/src/review.config.ts +2 -2
  16. package/src/review.service.spec.ts +4 -59
  17. package/src/review.service.ts +0 -27
  18. package/src/utils/review-pr-comment.ts +1 -1
  19. package/src/coverage/base.css +0 -224
  20. package/src/coverage/block-navigation.js +0 -87
  21. package/src/coverage/clover.xml +0 -1942
  22. package/src/coverage/coverage-final.json +0 -7
  23. package/src/coverage/favicon.png +0 -0
  24. package/src/coverage/index.html +0 -131
  25. package/src/coverage/prettify.css +0 -1
  26. package/src/coverage/prettify.js +0 -2
  27. package/src/coverage/sort-arrow-sprite.png +0 -0
  28. package/src/coverage/sorter.js +0 -210
  29. package/src/coverage/src/deletion-impact.service.ts.html +0 -2716
  30. package/src/coverage/src/index.html +0 -161
  31. package/src/coverage/src/issue-verify.service.ts.html +0 -1006
  32. package/src/coverage/src/parse-title-options.ts.html +0 -640
  33. package/src/coverage/src/review-spec/index.html +0 -131
  34. package/src/coverage/src/review-spec/review-spec.service.ts.html +0 -2782
  35. package/src/coverage/src/review-spec/types.ts.html +0 -535
  36. package/src/coverage/src/review.service.ts.html +0 -8911
  37. package/src/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![npm version](https://img.shields.io/npm/v/@spaceflow/review?color=blue)](https://www.npmjs.com/package/@spaceflow/review)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- > Spaceflow AI 代码审查扩展,使用 LLM 对 PR 代码进行自动审查。支持 OpenAI、Claude Code、Gemini、Open Code 等多种 LLM 模式。
6
+ > Spaceflow AI 代码审查扩展,使用 LLM 对 PR 代码进行自动审查。支持 OpenAI、Gemini、Open Code 等多种 LLM 模式。
7
7
 
8
8
  ## 安装
9
9
 
@@ -13,7 +13,7 @@ pnpm spaceflow install @spaceflow/review
13
13
 
14
14
  ## 功能特性
15
15
 
16
- - **多 LLM 支持** — OpenAI、Claude Code、Gemini、Open Code 可选
16
+ - **多 LLM 支持** — OpenAI、Gemini、Open Code 可选
17
17
  - **行级评论** — 在 PR 中精确定位问题代码行
18
18
  - **增量审查** — 多次运行时自动去重,追踪问题修复状态
19
19
  - **删除代码分析** — 评估删除代码可能带来的风险
@@ -63,7 +63,7 @@ spaceflow review -p 123 --fail-on-issues -l openai
63
63
  | `--pr-number <number>` | `-p` | PR 编号 |
64
64
  | `--base <ref>` | `-b` | 基准分支/tag |
65
65
  | `--head <ref>` | | 目标分支/tag |
66
- | `--llm-mode <mode>` | `-l` | LLM 模式(`openai` / `claude-code` / `gemini` / `open-code`) |
66
+ | `--llm-mode <mode>` | `-l` | LLM 模式(`openai` / `gemini` / `open-code`) |
67
67
  | `--files <files...>` | `-f` | 仅审查指定文件 |
68
68
  | `--commits <commits...>` | | 仅审查指定 commits |
69
69
  | `--includes <patterns...>` | `-i` | 文件 glob 过滤模式 |
@@ -74,7 +74,7 @@ spaceflow review -p 123 --fail-on-issues -l openai
74
74
  | `--no-verify-fixes` | | 禁用历史问题验证 |
75
75
  | `--analyze-deletions` | | 分析删除代码影响 |
76
76
  | `--deletion-only` | | 仅执行删除代码分析 |
77
- | `--deletion-analysis-mode <mode>` | | 删除分析 LLM 模式(`openai` / `claude-code`) |
77
+ | `--deletion-analysis-mode <mode>` | | 删除分析 LLM 模式(`openai` / `open-code`) |
78
78
  | `--generate-description` | | 使用 AI 生成 PR 功能描述 |
79
79
  | `--output-format <format>` | `-o` | 输出格式(`markdown` / `terminal` / `json`) |
80
80
  | `--local [mode]` | | 本地审查模式(`uncommitted` / `staged`,默认 `uncommitted`) |
@@ -157,7 +157,7 @@ spaceflow review -p 123 --fail-on-issues -l openai
157
157
  | `get_rule_detail` | 获取单条规则的详细信息 | `ruleId` |
158
158
  | `get_rules_from_dir` | 从指定目录加载审查规则 | `dirPath`, `includeExamples?` |
159
159
 
160
- 规则搜索目录包括:`review.references` 配置路径、`.claude/skills`、`.cursor/skills`、`review-specs`。
160
+ 规则搜索目录包括:`review.references` 配置路径、`.cursor/skills`、`review-specs`。
161
161
 
162
162
  ## 审查规范格式
163
163
 
@@ -437,12 +437,6 @@ jobs:
437
437
  | `OPENAI_API_KEY` | OpenAI API Key |
438
438
  | `OPENAI_MODEL` | OpenAI 模型名称 |
439
439
 
440
- ### Claude Code
441
-
442
- | 变量 | 说明 |
443
- | ------------------- | ---------------- |
444
- | `ANTHROPIC_API_KEY` | Anthropic API Key |
445
-
446
440
  ### Gemini
447
441
 
448
442
  | 变量 | 说明 |
package/dist/index.js CHANGED
@@ -42,9 +42,9 @@ __webpack_require__.d(__webpack_exports__, {
42
42
  ;// CONCATENATED MODULE: external "@spaceflow/core"
43
43
 
44
44
  ;// CONCATENATED MODULE: ./src/locales/zh-cn/review.json
45
- var review_namespaceObject = JSON.parse('{"description":"代码审查命令,使用 LLM 对 PR 代码进行自动审查","options.dryRun":"仅打印将要执行的操作,不实际提交评论","options.prNumber":"PR 编号,如果不指定则从环境变量获取","options.base":"基准分支/tag,用于比较差异","options.head":"目标分支/tag,用于比较差异","options.includes":"要审查的文件 glob 模式,如 *.ts *.js(可多次指定)。支持变更类型前缀: added|*.ts(仅新增)、modified|*.ts(仅修改)、deleted|*.ts(仅删除)","options.llmMode":"使用的 LLM 模式: claude-code, openai, gemini","options.files":"仅审查指定的文件(空格分隔)","options.commits":"仅审查指定的 commits(空格分隔)","options.verifyFixes":"是否验证历史问题是否已修复(默认从配置文件读取)","options.noVerifyFixes":"禁用历史问题验证","options.verifyConcurrency":"验证历史问题的并发数(默认 10)","options.analyzeDeletions":"分析删除代码可能带来的影响 (true, false, ci, pr, terminal)","options.deletionAnalysisMode":"删除代码分析模式: openai (标准模式) 或 claude-code (Agent 模式,可使用工具)","options.deletionOnly":"仅执行删除代码分析,跳过常规代码审查","options.outputFormat":"输出格式: markdown, terminal, json。不指定则智能选择(PR 用 markdown,终端用 terminal)","options.generateDescription":"使用 AI 生成 PR 功能描述","options.showAll":"显示所有发现的问题,不过滤非变更行的问题","options.flush":"仅刷新状态(同步 reactions、resolved conversations、replies),不执行 LLM 审查","options.eventAction":"PR 事件类型(opened, synchronize, closed 等),closed 时仅收集统计不进行 AI 审查","options.local":"审查本地未提交的代码。模式: \'uncommitted\'(默认,暂存区+工作区)或 \'staged\'(仅暂存区)","options.noLocal":"禁用本地模式,使用分支比较","options.failOnIssues":"存在未解决问题时工作流抛出异常。模式: warn(仅 warn 问题)/ error(仅 error 问题)/ warn&error(warn 或 error 问题)。不加模式等同 error","extensionDescription":"代码审查命令,使用 LLM 对 PR 代码进行自动审查","mcp.serverDescription":"代码审查规则查询服务","mcp.listRules":"获取当前项目的所有代码审查规则,返回规则列表包含 ID、标题、描述、适用的文件扩展名等信息","mcp.getRulesForFile":"获取某个文件应该使用的代码审查规则,根据文件扩展名和 includes 配置过滤","mcp.getRuleDetail":"获取某个规则的完整详情,包括描述、示例代码等","mcp.ruleNotFound":"规则 {{ruleId}} 不存在","mcp.dto.cwd":"项目根目录路径,默认为当前工作目录","mcp.dto.filePath":"文件路径,可以是相对路径或绝对路径","mcp.dto.includeExamples":"是否包含规则示例代码,默认 false","mcp.dto.ruleId":"规则 ID,如 JsTs.Naming.FileName","mcp.getRulesFromDir":"从指定目录加载代码审查规则。读取目录下所有 .md 文件,解析为规则并按规则 ID 去重(后加载的覆盖先加载的)","mcp.dto.dirPath":"包含规则 .md 文件的目录路径,可以是相对路径或绝对路径"}')
45
+ var review_namespaceObject = JSON.parse('{"description":"代码审查命令,使用 LLM 对 PR 代码进行自动审查","options.dryRun":"仅打印将要执行的操作,不实际提交评论","options.prNumber":"PR 编号,如果不指定则从环境变量获取","options.base":"基准分支/tag,用于比较差异","options.head":"目标分支/tag,用于比较差异","options.includes":"要审查的文件 glob 模式,如 *.ts *.js(可多次指定)。支持变更类型前缀: added|*.ts(仅新增)、modified|*.ts(仅修改)、deleted|*.ts(仅删除)","options.llmMode":"使用的 LLM 模式: openai, gemini, open-code","options.files":"仅审查指定的文件(空格分隔)","options.commits":"仅审查指定的 commits(空格分隔)","options.verifyFixes":"是否验证历史问题是否已修复(默认从配置文件读取)","options.noVerifyFixes":"禁用历史问题验证","options.verifyConcurrency":"验证历史问题的并发数(默认 10)","options.analyzeDeletions":"分析删除代码可能带来的影响 (true, false, ci, pr, terminal)","options.deletionAnalysisMode":"删除代码分析模式: openai (标准模式) 或 open-code (Agent 模式,可使用工具)","options.deletionOnly":"仅执行删除代码分析,跳过常规代码审查","options.outputFormat":"输出格式: markdown, terminal, json。不指定则智能选择(PR 用 markdown,终端用 terminal)","options.generateDescription":"使用 AI 生成 PR 功能描述","options.showAll":"显示所有发现的问题,不过滤非变更行的问题","options.flush":"仅刷新状态(同步 reactions、resolved conversations、replies),不执行 LLM 审查","options.eventAction":"PR 事件类型(opened, synchronize, closed 等),closed 时仅收集统计不进行 AI 审查","options.local":"审查本地未提交的代码。模式: \'uncommitted\'(默认,暂存区+工作区)或 \'staged\'(仅暂存区)","options.noLocal":"禁用本地模式,使用分支比较","options.failOnIssues":"存在未解决问题时工作流抛出异常。模式: warn(仅 warn 问题)/ error(仅 error 问题)/ warn&error(warn 或 error 问题)。不加模式等同 error","extensionDescription":"代码审查命令,使用 LLM 对 PR 代码进行自动审查","mcp.serverDescription":"代码审查规则查询服务","mcp.listRules":"获取当前项目的所有代码审查规则,返回规则列表包含 ID、标题、描述、适用的文件扩展名等信息","mcp.getRulesForFile":"获取某个文件应该使用的代码审查规则,根据文件扩展名和 includes 配置过滤","mcp.getRuleDetail":"获取某个规则的完整详情,包括描述、示例代码等","mcp.ruleNotFound":"规则 {{ruleId}} 不存在","mcp.dto.cwd":"项目根目录路径,默认为当前工作目录","mcp.dto.filePath":"文件路径,可以是相对路径或绝对路径","mcp.dto.includeExamples":"是否包含规则示例代码,默认 false","mcp.dto.ruleId":"规则 ID,如 JsTs.Naming.FileName","mcp.getRulesFromDir":"从指定目录加载代码审查规则。读取目录下所有 .md 文件,解析为规则并按规则 ID 去重(后加载的覆盖先加载的)","mcp.dto.dirPath":"包含规则 .md 文件的目录路径,可以是相对路径或绝对路径"}')
46
46
  ;// CONCATENATED MODULE: ./src/locales/en/review.json
47
- var en_review_namespaceObject = JSON.parse('{"description":"Code review command using LLM for automated PR review","options.dryRun":"Only print actions without posting comments","options.prNumber":"PR number, auto-detected from env if not specified","options.base":"Base branch/tag for diff comparison","options.head":"Head branch/tag for diff comparison","options.includes":"File glob patterns to review, e.g. *.ts *.js (can be specified multiple times). Supports change-type prefixes: added|*.ts (new files only), modified|*.ts (modified only), deleted|*.ts (deleted only)","options.llmMode":"LLM mode: claude-code, openai, gemini","options.files":"Only review specified files (space-separated)","options.commits":"Only review specified commits (space-separated)","options.verifyFixes":"Verify if historical issues are fixed (default from config)","options.noVerifyFixes":"Disable historical issue verification","options.verifyConcurrency":"Concurrency for verifying historical issues (default 10)","options.analyzeDeletions":"Analyze impact of deleted code (true, false, ci, pr, terminal)","options.deletionAnalysisMode":"Deletion analysis mode: openai (standard) or claude-code (Agent mode with tools)","options.deletionOnly":"Only run deletion analysis, skip regular code review","options.outputFormat":"Output format: markdown, terminal, json. Auto-selected if not specified (markdown for PR, terminal for CLI)","options.generateDescription":"Generate PR description using AI","options.showAll":"Show all issues found, including those on unchanged lines","options.flush":"Only sync status (reactions, resolved conversations, replies), skip LLM review","options.eventAction":"PR event type (opened, synchronize, closed, etc.), closed only collects stats without AI review","options.local":"Review local uncommitted code. Mode: \'uncommitted\' (default, staged + working) or \'staged\' (only staged)","options.noLocal":"Disable local mode, use branch comparison instead","options.failOnIssues":"Fail the workflow when unresolved issues exist. Mode: warn (warn-level only) / error (error-level only) / warn+error (either warn or error). Passing no mode is equivalent to error","extensionDescription":"Code review command using LLM for automated PR review","mcp.serverDescription":"Code review rules query service","mcp.listRules":"List all code review rules for the current project, returning rule list with ID, title, description, applicable file extensions, etc.","mcp.getRulesForFile":"Get applicable code review rules for a specific file, filtered by file extension and includes configuration","mcp.getRuleDetail":"Get full details of a specific rule, including description, example code, etc.","mcp.ruleNotFound":"Rule {{ruleId}} not found","mcp.dto.cwd":"Project root directory path, defaults to current working directory","mcp.dto.filePath":"File path, can be relative or absolute","mcp.dto.includeExamples":"Whether to include rule example code, defaults to false","mcp.dto.ruleId":"Rule ID, e.g. JsTs.Naming.FileName","mcp.getRulesFromDir":"Load code review rules from a specific directory. Reads all .md files in the directory, parses them into rules, and deduplicates by rule ID (later rules override earlier ones)","mcp.dto.dirPath":"Directory path containing rule .md files, can be relative or absolute"}')
47
+ var en_review_namespaceObject = JSON.parse('{"description":"Code review command using LLM for automated PR review","options.dryRun":"Only print actions without posting comments","options.prNumber":"PR number, auto-detected from env if not specified","options.base":"Base branch/tag for diff comparison","options.head":"Head branch/tag for diff comparison","options.includes":"File glob patterns to review, e.g. *.ts *.js (can be specified multiple times). Supports change-type prefixes: added|*.ts (new files only), modified|*.ts (modified only), deleted|*.ts (deleted only)","options.llmMode":"LLM mode: openai, gemini, open-code","options.files":"Only review specified files (space-separated)","options.commits":"Only review specified commits (space-separated)","options.verifyFixes":"Verify if historical issues are fixed (default from config)","options.noVerifyFixes":"Disable historical issue verification","options.verifyConcurrency":"Concurrency for verifying historical issues (default 10)","options.analyzeDeletions":"Analyze impact of deleted code (true, false, ci, pr, terminal)","options.deletionAnalysisMode":"Deletion analysis mode: openai (standard) or open-code (Agent mode with tools)","options.deletionOnly":"Only run deletion analysis, skip regular code review","options.outputFormat":"Output format: markdown, terminal, json. Auto-selected if not specified (markdown for PR, terminal for CLI)","options.generateDescription":"Generate PR description using AI","options.showAll":"Show all issues found, including those on unchanged lines","options.flush":"Only sync status (reactions, resolved conversations, replies), skip LLM review","options.eventAction":"PR event type (opened, synchronize, closed, etc.), closed only collects stats without AI review","options.local":"Review local uncommitted code. Mode: \'uncommitted\' (default, staged + working) or \'staged\' (only staged)","options.noLocal":"Disable local mode, use branch comparison instead","options.failOnIssues":"Fail the workflow when unresolved issues exist. Mode: warn (warn-level only) / error (error-level only) / warn+error (either warn or error). Passing no mode is equivalent to error","extensionDescription":"Code review command using LLM for automated PR review","mcp.serverDescription":"Code review rules query service","mcp.listRules":"List all code review rules for the current project, returning rule list with ID, title, description, applicable file extensions, etc.","mcp.getRulesForFile":"Get applicable code review rules for a specific file, filtered by file extension and includes configuration","mcp.getRuleDetail":"Get full details of a specific rule, including description, example code, etc.","mcp.ruleNotFound":"Rule {{ruleId}} not found","mcp.dto.cwd":"Project root directory path, defaults to current working directory","mcp.dto.filePath":"File path, can be relative or absolute","mcp.dto.includeExamples":"Whether to include rule example code, defaults to false","mcp.dto.ruleId":"Rule ID, e.g. JsTs.Naming.FileName","mcp.getRulesFromDir":"Load code review rules from a specific directory. Reads all .md files in the directory, parses them into rules, and deduplicates by rule ID (later rules override earlier ones)","mcp.dto.dirPath":"Directory path containing rule .md files, can be relative or absolute"}')
48
48
  ;// CONCATENATED MODULE: ./src/locales/index.ts
49
49
 
50
50
 
@@ -2252,7 +2252,7 @@ function generateIssueKey(issue) {
2252
2252
  const validIssue = issues.filter((i)=>i.valid !== "false");
2253
2253
  const validTotal = validIssue.length;
2254
2254
  const fixed = validIssue.filter((i)=>i.fixed).length;
2255
- const resolved = validIssue.filter((i)=>i.resolved && !i.fixed).length;
2255
+ const resolved = validIssue.filter((i)=>i.resolved).length;
2256
2256
  const invalid = total - validTotal;
2257
2257
  const pending = validTotal - fixed - resolved;
2258
2258
  const fixRate = validTotal > 0 ? Math.round(fixed / validTotal * 100 * 10) / 10 : 0;
@@ -3153,7 +3153,6 @@ function generateIssueKey(issue) {
3153
3153
  ;// CONCATENATED MODULE: ./src/review.config.ts
3154
3154
 
3155
3155
  /** LLM 模式 schema(与 core 中的 LLMMode 保持一致) */ const llmModeSchema = z["enum"]([
3156
- "claude-code",
3157
3156
  "openai",
3158
3157
  "gemini",
3159
3158
  "open-code"
@@ -3308,7 +3307,7 @@ function generateIssueKey(issue) {
3308
3307
  * 支持的格式:标题末尾 [/review -l openai -v 2]
3309
3308
  *
3310
3309
  * 支持的参数:
3311
- * - `-l, --llm-mode <mode>`: LLM 模式 (claude-code, openai, gemini)
3310
+ * - `-l, --llm-mode <mode>`: LLM 模式 (openai, gemini, open-code)
3312
3311
  * - `-v, --verbose [level]`: 详细输出级别 (1 或 2)
3313
3312
  * - `-d, --dry-run`: 仅打印不执行
3314
3313
  * - `-i, --includes <pattern>`: 文件过滤模式
@@ -3438,15 +3437,15 @@ function generateIssueKey(issue) {
3438
3437
  }
3439
3438
  function isValidLLMMode(value) {
3440
3439
  return [
3441
- "claude-code",
3442
3440
  "openai",
3443
- "gemini"
3441
+ "gemini",
3442
+ "open-code"
3444
3443
  ].includes(value);
3445
3444
  }
3446
3445
  function isValidDeletionAnalysisMode(value) {
3447
3446
  return [
3448
3447
  "openai",
3449
- "claude-code"
3448
+ "open-code"
3450
3449
  ].includes(value);
3451
3450
  }
3452
3451
  function isValidAnalyzeDeletionsMode(value) {
@@ -5711,7 +5710,6 @@ class ReviewLlmProcessor {
5711
5710
 
5712
5711
 
5713
5712
 
5714
-
5715
5713
  class ReviewService {
5716
5714
  gitProvider;
5717
5715
  config;
@@ -6191,28 +6189,6 @@ class ReviewService {
6191
6189
  }
6192
6190
  return result;
6193
6191
  }
6194
- /**
6195
- * 确保 Claude CLI 已安装
6196
- */ async ensureClaudeCli(ci) {
6197
- try {
6198
- execSync("claude --version", {
6199
- stdio: "ignore"
6200
- });
6201
- } catch {
6202
- if (ci) {
6203
- throw new Error("Claude CLI 未安装。CI 环境请在 workflow 中预装: npm install -g @anthropic-ai/claude-code");
6204
- }
6205
- console.log("🔧 Claude CLI 未安装,正在安装...");
6206
- try {
6207
- execSync("npm install -g @anthropic-ai/claude-code", {
6208
- stdio: "inherit"
6209
- });
6210
- console.log("✅ Claude CLI 安装完成");
6211
- } catch (installError) {
6212
- throw new Error(`Claude CLI 安装失败: ${installError instanceof Error ? installError.message : String(installError)}`);
6213
- }
6214
- }
6215
- }
6216
6192
  }
6217
6193
 
6218
6194
  ;// CONCATENATED MODULE: ./src/issue-verify.service.ts
@@ -6505,11 +6481,8 @@ class DeletionImpactService {
6505
6481
  // 3. 根据分析模式选择不同的分析方法
6506
6482
  const analysisMode = context.analysisMode ?? "openai";
6507
6483
  let result;
6508
- if ([
6509
- "claude-code",
6510
- "open-code"
6511
- ].includes(analysisMode)) {
6512
- // Claude Agent 模式:使用工具主动探索代码库
6484
+ if (analysisMode === "open-code") {
6485
+ // Agent 模式:使用工具主动探索代码库
6513
6486
  result = await this.analyzeWithAgent(analysisMode, deletedBlocks, references, verbose);
6514
6487
  } else {
6515
6488
  // OpenAI 模式:标准 chat completion
@@ -6887,8 +6860,8 @@ class DeletionImpactService {
6887
6860
  }
6888
6861
  }
6889
6862
  /**
6890
- * 使用 Claude Agent 模式分析删除代码的影响
6891
- * Claude Agent 可以使用工具主动探索代码库,分析更深入
6863
+ * 使用 Agent 模式分析删除代码的影响
6864
+ * Agent 可以使用工具主动探索代码库,分析更深入
6892
6865
  */ async analyzeWithAgent(analysisMode, deletedBlocks, references, verbose) {
6893
6866
  const llmJsonPut = new LlmJsonPut(DELETION_IMPACT_SCHEMA);
6894
6867
  const { systemPrompt, userPrompt } = buildDeletionImpactAgentPrompt({
@@ -7110,7 +7083,6 @@ const getRulesFromDirInputSchema = z.object({
7110
7083
  // 忽略配置读取错误
7111
7084
  }
7112
7085
  const defaultDirs = [
7113
- join(cwd, ".claude", "skills"),
7114
7086
  join(cwd, ".cursor", "skills"),
7115
7087
  join(cwd, "review-specs")
7116
7088
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spaceflow/review",
3
- "version": "5.0.0",
3
+ "version": "5.0.1",
4
4
  "description": "Spaceflow 代码审查插件,使用 LLM 对 PR 代码进行自动审查",
5
5
  "license": "MIT",
6
6
  "author": "Lydanne",
@@ -25,10 +25,10 @@
25
25
  "@vitest/coverage-v8": "^4.0.18",
26
26
  "unplugin-swc": "^1.5.9",
27
27
  "vitest": "^4.0.18",
28
- "@spaceflow/cli": "5.0.0"
28
+ "@spaceflow/cli": "5.0.1"
29
29
  },
30
30
  "peerDependencies": {
31
- "@spaceflow/core": "5.0.0"
31
+ "@spaceflow/core": "5.0.1"
32
32
  },
33
33
  "spaceflow": {
34
34
  "type": "flow",
package/src/README.md CHANGED
@@ -23,7 +23,7 @@ review/src/
23
23
  review extension
24
24
  ├── GitProviderService # Git 平台适配器
25
25
  ├── GitSdkService # Git 命令封装
26
- ├── LlmProxyService # LLM 统一代理(OpenAI / Claude
26
+ ├── LlmProxyService # LLM 统一代理(OpenAI / OpenCode
27
27
  ├── LoggerService # 日志系统
28
28
  ├── StorageService # 缓存存储
29
29
  └── ParallelService # 并行执行
@@ -44,7 +44,7 @@ CLI 命令入口,支持以下参数:
44
44
  | `--head <ref>` | | 目标分支/tag |
45
45
  | `--verbose [level]` | `-v` | 详细输出 (1: 过程日志, 2: 含提示词) |
46
46
  | `--includes <patterns...>` | `-i` | 文件 glob 过滤模式 |
47
- | `--llm-mode <mode>` | `-l` | LLM 模式: claude-code, openai, gemini |
47
+ | `--llm-mode <mode>` | `-l` | LLM 模式: openai, gemini, open-code |
48
48
  | `--files <files...>` | `-f` | 仅审查指定文件 |
49
49
  | `--commits <commits...>` | | 仅审查指定 commits |
50
50
  | `--verify-fixes` | | 验证历史问题是否已修复 |
@@ -52,7 +52,7 @@ CLI 命令入口,支持以下参数:
52
52
  | `--verify-concurrency <n>` | | 验证并发数(默认 10) |
53
53
  | `--analyze-deletions` | | 分析删除代码影响 |
54
54
  | `--deletion-only` | | 仅执行删除代码分析 |
55
- | `--deletion-analysis-mode <mode>` | | 删除分析模式: openai, claude-code |
55
+ | `--deletion-analysis-mode <mode>` | | 删除分析模式: openai, open-code |
56
56
  | `--output-format <format>` | `-o` | 输出格式: markdown, terminal, json |
57
57
  | `--generate-description` | | 使用 AI 生成 PR 功能描述 |
58
58
 
@@ -176,7 +176,7 @@ analyzeDeletionImpact()
176
176
  │ 2. 查找代码引用关系 (git grep) │
177
177
  │ 3. 调用 LLM 分析影响 │
178
178
  │ - OpenAI 模式:标准 chat │
179
- │ - Claude Agent 模式:可用工具
179
+ │ - OpenCode 模式:可用工具
180
180
  └─────────────────────────────────────┘
181
181
  ```
182
182
 
@@ -3,10 +3,6 @@ import { DeletionImpactService } from "./deletion-impact.service";
3
3
  import * as child_process from "child_process";
4
4
  import { EventEmitter } from "events";
5
5
 
6
- vi.mock("@anthropic-ai/claude-agent-sdk", () => ({
7
- query: vi.fn(),
8
- }));
9
-
10
6
  vi.mock("child_process");
11
7
 
12
8
  describe("DeletionImpactService", () => {
@@ -520,7 +516,7 @@ diff --git a/file2.ts b/file2.ts
520
516
 
521
517
  const blocks = [{ file: "test.ts", startLine: 1, endLine: 1, content: "const x = 1;" }];
522
518
  const refs = new Map<string, string[]>();
523
- const result = await (service as any).analyzeWithAgent("claude-code", blocks, refs);
519
+ const result = await (service as any).analyzeWithAgent("open-code", blocks, refs);
524
520
  expect(result.summary).toBe("agent ok");
525
521
  });
526
522
 
@@ -533,7 +529,7 @@ diff --git a/file2.ts b/file2.ts
533
529
  const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
534
530
  const blocks = [{ file: "test.ts", startLine: 1, endLine: 1, content: "const x = 1;" }];
535
531
  const refs = new Map<string, string[]>();
536
- const result = await (service as any).analyzeWithAgent("claude-code", blocks, refs);
532
+ const result = await (service as any).analyzeWithAgent("open-code", blocks, refs);
537
533
  expect(result.impacts).toHaveLength(0);
538
534
  consoleSpy.mockRestore();
539
535
  });
@@ -546,7 +542,7 @@ diff --git a/file2.ts b/file2.ts
546
542
  const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
547
543
  const blocks = [{ file: "test.ts", startLine: 1, endLine: 1, content: "const x = 1;" }];
548
544
  const refs = new Map<string, string[]>();
549
- const result = await (service as any).analyzeWithAgent("claude-code", blocks, refs);
545
+ const result = await (service as any).analyzeWithAgent("open-code", blocks, refs);
550
546
  expect(result.summary).toBe("Agent 调用失败");
551
547
  consoleSpy.mockRestore();
552
548
  });
@@ -559,7 +555,7 @@ diff --git a/file2.ts b/file2.ts
559
555
  const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
560
556
  const blocks = [{ file: "test.ts", startLine: 1, endLine: 1, content: "const x = 1;" }];
561
557
  const refs = new Map<string, string[]>();
562
- const result = await (service as any).analyzeWithAgent("claude-code", blocks, refs);
558
+ const result = await (service as any).analyzeWithAgent("open-code", blocks, refs);
563
559
  expect(result.summary).toBe("Agent 调用失败");
564
560
  consoleSpy.mockRestore();
565
561
  });
@@ -572,7 +568,7 @@ diff --git a/file2.ts b/file2.ts
572
568
 
573
569
  const blocks = [{ file: "test.ts", startLine: 1, endLine: 1, content: "const x = 1;" }];
574
570
  const refs = new Map<string, string[]>();
575
- const result = await (service as any).analyzeWithAgent("claude-code", blocks, refs);
571
+ const result = await (service as any).analyzeWithAgent("open-code", blocks, refs);
576
572
  expect(result.summary).toBe("分析返回格式无效");
577
573
  });
578
574
 
@@ -587,7 +583,7 @@ diff --git a/file2.ts b/file2.ts
587
583
 
588
584
  const blocks = [{ file: "test.ts", startLine: 1, endLine: 1, content: "const x = 1;" }];
589
585
  const refs = new Map<string, string[]>();
590
- const result = await (service as any).analyzeWithAgent("claude-code", blocks, refs, 2);
586
+ const result = await (service as any).analyzeWithAgent("open-code", blocks, refs, 2);
591
587
  expect(result.summary).toBe("ok");
592
588
  });
593
589
  });
@@ -898,8 +894,8 @@ diff --git a/file2.ts b/file2.ts
898
894
  });
899
895
 
900
896
  describe("analyzeDeletionImpact - agent mode", () => {
901
- it("should use agent mode for claude-code", async () => {
902
- const context = { owner: "o", repo: "r", prNumber: 1, analysisMode: "claude-code" as const };
897
+ it("should use agent mode for open-code", async () => {
898
+ const context = { owner: "o", repo: "r", prNumber: 1, analysisMode: "open-code" as const };
903
899
  gitProvider.getPullRequestFiles.mockResolvedValue([
904
900
  {
905
901
  filename: "test.ts",
@@ -37,7 +37,7 @@ export interface DeletionAnalysisContext {
37
37
  headRef?: string;
38
38
  /** diff 来源:provider-api 使用 Git Provider API,git-diff 使用本地 git 命令(两点语法) */
39
39
  diffSource?: DeletionDiffSource;
40
- /** 分析模式:openai 使用标准模式,claude-agent 使用 Agent 模式(可使用工具) */
40
+ /** 分析模式:openai 使用标准模式,open-code 使用 Agent 模式(可使用工具) */
41
41
  analysisMode?: LLMMode;
42
42
  /** 文件过滤 glob 模式,与 review.includes 一致 */
43
43
  includes?: string[];
@@ -156,8 +156,8 @@ export class DeletionImpactService {
156
156
  const analysisMode = context.analysisMode ?? "openai";
157
157
  let result: DeletionImpactResult;
158
158
 
159
- if (["claude-code", "open-code"].includes(analysisMode)) {
160
- // Claude Agent 模式:使用工具主动探索代码库
159
+ if (analysisMode === "open-code") {
160
+ // Agent 模式:使用工具主动探索代码库
161
161
  result = await this.analyzeWithAgent(analysisMode, deletedBlocks, references, verbose);
162
162
  } else {
163
163
  // OpenAI 模式:标准 chat completion
@@ -584,8 +584,8 @@ export class DeletionImpactService {
584
584
  }
585
585
 
586
586
  /**
587
- * 使用 Claude Agent 模式分析删除代码的影响
588
- * Claude Agent 可以使用工具主动探索代码库,分析更深入
587
+ * 使用 Agent 模式分析删除代码的影响
588
+ * Agent 可以使用工具主动探索代码库,分析更深入
589
589
  */
590
590
  protected async analyzeWithAgent(
591
591
  analysisMode: LLMMode,
@@ -2,10 +2,6 @@ import { vi } from "vitest";
2
2
  import { ReviewIssue, FileContentsMap } from "./review-spec";
3
3
  import { IssueVerifyService } from "./issue-verify.service";
4
4
 
5
- vi.mock("@anthropic-ai/claude-agent-sdk", () => ({
6
- query: vi.fn(),
7
- }));
8
-
9
5
  describe("IssueVerifyService", () => {
10
6
  let service: IssueVerifyService;
11
7
  let llmProxyService: any;
@@ -5,14 +5,14 @@
5
5
  "options.base": "Base branch/tag for diff comparison",
6
6
  "options.head": "Head branch/tag for diff comparison",
7
7
  "options.includes": "File glob patterns to review, e.g. *.ts *.js (can be specified multiple times). Supports change-type prefixes: added|*.ts (new files only), modified|*.ts (modified only), deleted|*.ts (deleted only)",
8
- "options.llmMode": "LLM mode: claude-code, openai, gemini",
8
+ "options.llmMode": "LLM mode: openai, gemini, open-code",
9
9
  "options.files": "Only review specified files (space-separated)",
10
10
  "options.commits": "Only review specified commits (space-separated)",
11
11
  "options.verifyFixes": "Verify if historical issues are fixed (default from config)",
12
12
  "options.noVerifyFixes": "Disable historical issue verification",
13
13
  "options.verifyConcurrency": "Concurrency for verifying historical issues (default 10)",
14
14
  "options.analyzeDeletions": "Analyze impact of deleted code (true, false, ci, pr, terminal)",
15
- "options.deletionAnalysisMode": "Deletion analysis mode: openai (standard) or claude-code (Agent mode with tools)",
15
+ "options.deletionAnalysisMode": "Deletion analysis mode: openai (standard) or open-code (Agent mode with tools)",
16
16
  "options.deletionOnly": "Only run deletion analysis, skip regular code review",
17
17
  "options.outputFormat": "Output format: markdown, terminal, json. Auto-selected if not specified (markdown for PR, terminal for CLI)",
18
18
  "options.generateDescription": "Generate PR description using AI",
@@ -5,14 +5,14 @@
5
5
  "options.base": "基准分支/tag,用于比较差异",
6
6
  "options.head": "目标分支/tag,用于比较差异",
7
7
  "options.includes": "要审查的文件 glob 模式,如 *.ts *.js(可多次指定)。支持变更类型前缀: added|*.ts(仅新增)、modified|*.ts(仅修改)、deleted|*.ts(仅删除)",
8
- "options.llmMode": "使用的 LLM 模式: claude-code, openai, gemini",
8
+ "options.llmMode": "使用的 LLM 模式: openai, gemini, open-code",
9
9
  "options.files": "仅审查指定的文件(空格分隔)",
10
10
  "options.commits": "仅审查指定的 commits(空格分隔)",
11
11
  "options.verifyFixes": "是否验证历史问题是否已修复(默认从配置文件读取)",
12
12
  "options.noVerifyFixes": "禁用历史问题验证",
13
13
  "options.verifyConcurrency": "验证历史问题的并发数(默认 10)",
14
14
  "options.analyzeDeletions": "分析删除代码可能带来的影响 (true, false, ci, pr, terminal)",
15
- "options.deletionAnalysisMode": "删除代码分析模式: openai (标准模式) 或 claude-code (Agent 模式,可使用工具)",
15
+ "options.deletionAnalysisMode": "删除代码分析模式: openai (标准模式) 或 open-code (Agent 模式,可使用工具)",
16
16
  "options.deletionOnly": "仅执行删除代码分析,跳过常规代码审查",
17
17
  "options.outputFormat": "输出格式: markdown, terminal, json。不指定则智能选择(PR 用 markdown,终端用 terminal)",
18
18
  "options.generateDescription": "使用 AI 生成 PR 功能描述",
package/src/mcp/index.ts CHANGED
@@ -50,11 +50,7 @@ async function getSpecDirs(cwd: string, ctx: SpaceflowContext): Promise<string[]
50
50
  } catch {
51
51
  // 忽略配置读取错误
52
52
  }
53
- const defaultDirs = [
54
- join(cwd, ".claude", "skills"),
55
- join(cwd, ".cursor", "skills"),
56
- join(cwd, "review-specs"),
57
- ];
53
+ const defaultDirs = [join(cwd, ".cursor", "skills"), join(cwd, "review-specs")];
58
54
  for (const dir of defaultDirs) {
59
55
  if (existsSync(dir)) {
60
56
  dirs.push(dir);
@@ -35,10 +35,10 @@ describe("parseTitleOptions", () => {
35
35
 
36
36
  describe("LLM 模式参数", () => {
37
37
  it("应该解析 -l 短参数", () => {
38
- const title = "fix: bug [/ai-review -l claude-code]";
38
+ const title = "fix: bug [/ai-review -l openai]";
39
39
  const options = parseTitleOptions(title);
40
40
 
41
- expect(options.llmMode).toBe("claude-code");
41
+ expect(options.llmMode).toBe("openai");
42
42
  });
43
43
 
44
44
  it("应该解析 --llm-mode 长参数", () => {
@@ -193,10 +193,10 @@ describe("parseTitleOptions", () => {
193
193
  });
194
194
 
195
195
  it("应该解析 --deletion-analysis-mode", () => {
196
- const title = "fix: bug [/ai-review --deletion-analysis-mode claude-code]";
196
+ const title = "fix: bug [/ai-review --deletion-analysis-mode open-code]";
197
197
  const options = parseTitleOptions(title);
198
198
 
199
- expect(options.deletionAnalysisMode).toBe("claude-code");
199
+ expect(options.deletionAnalysisMode).toBe("open-code");
200
200
  });
201
201
  });
202
202
 
@@ -22,7 +22,7 @@ export interface TitleOptions {
22
22
  * 支持的格式:标题末尾 [/review -l openai -v 2]
23
23
  *
24
24
  * 支持的参数:
25
- * - `-l, --llm-mode <mode>`: LLM 模式 (claude-code, openai, gemini)
25
+ * - `-l, --llm-mode <mode>`: LLM 模式 (openai, gemini, open-code)
26
26
  * - `-v, --verbose [level]`: 详细输出级别 (1 或 2)
27
27
  * - `-d, --dry-run`: 仅打印不执行
28
28
  * - `-i, --includes <pattern>`: 文件过滤模式
@@ -167,11 +167,11 @@ function parseArgs(argsString: string): string[] {
167
167
  }
168
168
 
169
169
  function isValidLLMMode(value: string): value is LLMMode {
170
- return ["claude-code", "openai", "gemini"].includes(value);
170
+ return ["openai", "gemini", "open-code"].includes(value);
171
171
  }
172
172
 
173
173
  function isValidDeletionAnalysisMode(value: string): value is LLMMode {
174
- return ["openai", "claude-code"].includes(value);
174
+ return ["openai", "open-code"].includes(value);
175
175
  }
176
176
 
177
177
  function isValidAnalyzeDeletionsMode(value: string): boolean {
@@ -37,7 +37,7 @@ export interface ReviewContext extends ReviewOptions {
37
37
  retryDelay?: number;
38
38
  /** 仅执行删除代码分析,跳过常规代码审查 */
39
39
  deletionOnly?: boolean;
40
- /** 删除代码分析模式:openai 使用标准模式,claude-agent 使用 Agent 模式 */
40
+ /** 删除代码分析模式:openai 使用标准模式,open-code 使用 Agent 模式 */
41
41
  deletionAnalysisMode?: LLMMode;
42
42
  /** 输出格式:markdown, terminal, json。不指定则智能选择 */
43
43
  outputFormat?: ReportFormat;
@@ -4,9 +4,6 @@ import type { ReviewPrompt } from "./review.service";
4
4
  import { ChangedFileCollection } from "./changed-file-collection";
5
5
 
6
6
  vi.mock("c12");
7
- vi.mock("@anthropic-ai/claude-agent-sdk", () => ({
8
- query: vi.fn(),
9
- }));
10
7
  vi.mock("@opencode-ai/sdk", () => ({
11
8
  createOpencodeClient: vi.fn().mockReturnValue({
12
9
  session: {
@@ -72,7 +69,7 @@ describe("ReviewLlmProcessor", () => {
72
69
  chat: vi.fn(),
73
70
  chatStream: vi.fn(),
74
71
  createSession: vi.fn(),
75
- getAvailableAdapters: vi.fn().mockReturnValue(["claude-code", "openai"]),
72
+ getAvailableAdapters: vi.fn().mockReturnValue(["openai", "open-code"]),
76
73
  };
77
74
 
78
75
  processor = new ReviewLlmProcessor(mockLlmProxyService as any, mockReviewSpecService as any);
@@ -83,20 +80,6 @@ describe("ReviewLlmProcessor", () => {
83
80
  });
84
81
 
85
82
  describe("runLLMReview", () => {
86
- it("should call callLLM when llmMode is claude", async () => {
87
- const callLLMSpy = vi
88
- .spyOn(processor, "callLLM")
89
- .mockResolvedValue({ issues: [], summary: [] } as any);
90
-
91
- const mockPrompt: ReviewPrompt = {
92
- filePrompts: [{ filename: "test.ts", systemPrompt: "system", userPrompt: "user" }],
93
- };
94
-
95
- await processor.runLLMReview("claude-code", mockPrompt);
96
-
97
- expect(callLLMSpy).toHaveBeenCalledWith("claude-code", mockPrompt, {});
98
- });
99
-
100
83
  it("should call callLLM when llmMode is openai", async () => {
101
84
  const callLLMSpy = vi
102
85
  .spyOn(processor, "callLLM")
@@ -3,7 +3,7 @@ import type { LLMMode, VerboseLevel, LocalReviewMode } from "@spaceflow/core";
3
3
  import type { ReportFormat } from "./review-report";
4
4
 
5
5
  /** LLM 模式 schema(与 core 中的 LLMMode 保持一致) */
6
- const llmModeSchema = z.enum(["claude-code", "openai", "gemini", "open-code"]);
6
+ const llmModeSchema = z.enum(["openai", "gemini", "open-code"]);
7
7
 
8
8
  /** 删除代码分析模式 schema */
9
9
  const analyzeDeletionsModeSchema = z.union([z.boolean(), z.enum(["ci", "pr", "terminal"])]);
@@ -69,7 +69,7 @@ export interface ReviewOptions {
69
69
  analyzeDeletions?: AnalyzeDeletionsMode;
70
70
  /** 仅执行删除代码分析,跳过常规代码审查 */
71
71
  deletionOnly?: boolean;
72
- /** 删除代码分析模式:openai 使用标准模式,claude-agent 使用 Agent 模式 */
72
+ /** 删除代码分析模式:openai 使用标准模式,open-code 使用 Agent 模式 */
73
73
  deletionAnalysisMode?: LLMMode;
74
74
  /** 输出格式:markdown, terminal, json。不指定则智能选择 */
75
75
  outputFormat?: ReportFormat;