@spaceflow/review 5.0.0 → 5.0.2
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 +18 -0
- package/README.md +5 -11
- package/dist/index.js +13 -44
- package/package.json +3 -3
- package/src/README.md +4 -4
- package/src/deletion-impact.service.spec.ts +8 -12
- package/src/deletion-impact.service.ts +5 -5
- package/src/issue-verify.service.spec.ts +0 -4
- package/src/locales/en/review.json +2 -2
- package/src/locales/zh-cn/review.json +2 -2
- package/src/mcp/index.ts +1 -5
- package/src/parse-title-options.spec.ts +4 -4
- package/src/parse-title-options.ts +3 -3
- package/src/review-context.ts +1 -1
- package/src/review-llm.spec.ts +1 -18
- package/src/review-result-model.ts +6 -6
- package/src/review.config.ts +2 -2
- package/src/review.service.spec.ts +4 -59
- package/src/review.service.ts +0 -27
- package/src/utils/review-pr-comment.spec.ts +8 -11
- package/src/utils/review-pr-comment.ts +2 -2
- package/src/coverage/base.css +0 -224
- package/src/coverage/block-navigation.js +0 -87
- package/src/coverage/clover.xml +0 -1942
- package/src/coverage/coverage-final.json +0 -7
- package/src/coverage/favicon.png +0 -0
- package/src/coverage/index.html +0 -131
- package/src/coverage/prettify.css +0 -1
- package/src/coverage/prettify.js +0 -2
- package/src/coverage/sort-arrow-sprite.png +0 -0
- package/src/coverage/sorter.js +0 -210
- package/src/coverage/src/deletion-impact.service.ts.html +0 -2716
- package/src/coverage/src/index.html +0 -161
- package/src/coverage/src/issue-verify.service.ts.html +0 -1006
- package/src/coverage/src/parse-title-options.ts.html +0 -640
- package/src/coverage/src/review-spec/index.html +0 -131
- package/src/coverage/src/review-spec/review-spec.service.ts.html +0 -2782
- package/src/coverage/src/review-spec/types.ts.html +0 -535
- package/src/coverage/src/review.service.ts.html +0 -8911
- package/src/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [5.0.1](https://github.com/Lydanne/spaceflow/compare/@spaceflow/review@5.0.0...@spaceflow/review@5.0.1) (2026-04-14)
|
|
4
|
+
|
|
5
|
+
### 修复BUG
|
|
6
|
+
|
|
7
|
+
* **review:** 修正已解决问题统计逻辑,避免与已修复问题重复计数 ([6d191bb](https://github.com/Lydanne/spaceflow/commit/6d191bbd71b8ce6194ce56a8d008dd966173541b))
|
|
8
|
+
|
|
9
|
+
### 代码重构
|
|
10
|
+
|
|
11
|
+
* **shared:** 移除 Claude Code 相关配置和文档,统一使用 OpenAI/Gemini/OpenCode ([b0754d6](https://github.com/Lydanne/spaceflow/commit/b0754d64f8991a10708730c191cf0f335e8aa6ca))
|
|
12
|
+
|
|
13
|
+
### 其他修改
|
|
14
|
+
|
|
15
|
+
* **cli:** released version 5.0.1 [no ci] ([f3009ea](https://github.com/Lydanne/spaceflow/commit/f3009eaaf26759d708541f54e707882b4927ebbd))
|
|
16
|
+
* **core:** released version 5.0.1 [no ci] ([7904b9b](https://github.com/Lydanne/spaceflow/commit/7904b9bbc619c91a3a4fa1c8ea04d9dc548495ad))
|
|
17
|
+
* **core:** 移除 @anthropic-ai/claude-agent-sdk 依赖及相关 sharp 图像处理包 ([7b50e06](https://github.com/Lydanne/spaceflow/commit/7b50e066df97d408eb63707eb27273592a28d34d))
|
|
18
|
+
* **publish:** released version 5.0.1 [no ci] ([b14849f](https://github.com/Lydanne/spaceflow/commit/b14849ffafd38f230a3e69c2d63c468cb1946388))
|
|
19
|
+
* **shared:** released version 5.0.1 [no ci] ([f70cd93](https://github.com/Lydanne/spaceflow/commit/f70cd930b01ffa09187f66522c8d6b18f835ec53))
|
|
20
|
+
|
|
3
21
|
## [4.0.1](https://github.com/Lydanne/spaceflow/compare/@spaceflow/review@4.0.0...@spaceflow/review@4.0.1) (2026-04-13)
|
|
4
22
|
|
|
5
23
|
### 新特性
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@spaceflow/review)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
> Spaceflow AI 代码审查扩展,使用 LLM 对 PR 代码进行自动审查。支持 OpenAI、
|
|
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、
|
|
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` / `
|
|
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` / `
|
|
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` 配置路径、`.
|
|
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 模式:
|
|
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:
|
|
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,9 +2252,9 @@ 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
|
|
2255
|
+
const resolved = validIssue.filter((i)=>i.resolved).length;
|
|
2256
2256
|
const invalid = total - validTotal;
|
|
2257
|
-
const pending = validTotal - fixed
|
|
2257
|
+
const pending = validTotal - validIssue.filter((i)=>i.fixed || i.resolved).length;
|
|
2258
2258
|
const fixRate = validTotal > 0 ? Math.round(fixed / validTotal * 100 * 10) / 10 : 0;
|
|
2259
2259
|
const resolveRate = validTotal > 0 ? Math.round(resolved / validTotal * 100 * 10) / 10 : 0;
|
|
2260
2260
|
return {
|
|
@@ -3131,10 +3131,7 @@ function generateIssueKey(issue) {
|
|
|
3131
3131
|
if (round > 1) {
|
|
3132
3132
|
const prevIssues = allIssues.filter((i)=>i.round === round - 1);
|
|
3133
3133
|
if (prevIssues.length > 0) {
|
|
3134
|
-
const prevFixed = prevIssues
|
|
3135
|
-
const prevResolved = prevIssues.filter((i)=>i.resolved && !i.fixed).length;
|
|
3136
|
-
const prevInvalid = prevIssues.filter((i)=>i.valid === "false" && !i.fixed && !i.resolved).length;
|
|
3137
|
-
const prevPending = prevIssues.length - prevFixed - prevResolved - prevInvalid;
|
|
3134
|
+
const { fixed: prevFixed, resolved: prevResolved, invalid: prevInvalid, pending: prevPending } = calculateIssueStats(prevIssues);
|
|
3138
3135
|
parts.push("");
|
|
3139
3136
|
parts.push(`<details><summary>📊 Round ${round - 1} 回顾 (${prevIssues.length} 个问题)</summary>\n`);
|
|
3140
3137
|
parts.push(`| 状态 | 数量 |`);
|
|
@@ -3153,7 +3150,6 @@ function generateIssueKey(issue) {
|
|
|
3153
3150
|
;// CONCATENATED MODULE: ./src/review.config.ts
|
|
3154
3151
|
|
|
3155
3152
|
/** LLM 模式 schema(与 core 中的 LLMMode 保持一致) */ const llmModeSchema = z["enum"]([
|
|
3156
|
-
"claude-code",
|
|
3157
3153
|
"openai",
|
|
3158
3154
|
"gemini",
|
|
3159
3155
|
"open-code"
|
|
@@ -3308,7 +3304,7 @@ function generateIssueKey(issue) {
|
|
|
3308
3304
|
* 支持的格式:标题末尾 [/review -l openai -v 2]
|
|
3309
3305
|
*
|
|
3310
3306
|
* 支持的参数:
|
|
3311
|
-
* - `-l, --llm-mode <mode>`: LLM 模式 (
|
|
3307
|
+
* - `-l, --llm-mode <mode>`: LLM 模式 (openai, gemini, open-code)
|
|
3312
3308
|
* - `-v, --verbose [level]`: 详细输出级别 (1 或 2)
|
|
3313
3309
|
* - `-d, --dry-run`: 仅打印不执行
|
|
3314
3310
|
* - `-i, --includes <pattern>`: 文件过滤模式
|
|
@@ -3438,15 +3434,15 @@ function generateIssueKey(issue) {
|
|
|
3438
3434
|
}
|
|
3439
3435
|
function isValidLLMMode(value) {
|
|
3440
3436
|
return [
|
|
3441
|
-
"claude-code",
|
|
3442
3437
|
"openai",
|
|
3443
|
-
"gemini"
|
|
3438
|
+
"gemini",
|
|
3439
|
+
"open-code"
|
|
3444
3440
|
].includes(value);
|
|
3445
3441
|
}
|
|
3446
3442
|
function isValidDeletionAnalysisMode(value) {
|
|
3447
3443
|
return [
|
|
3448
3444
|
"openai",
|
|
3449
|
-
"
|
|
3445
|
+
"open-code"
|
|
3450
3446
|
].includes(value);
|
|
3451
3447
|
}
|
|
3452
3448
|
function isValidAnalyzeDeletionsMode(value) {
|
|
@@ -5711,7 +5707,6 @@ class ReviewLlmProcessor {
|
|
|
5711
5707
|
|
|
5712
5708
|
|
|
5713
5709
|
|
|
5714
|
-
|
|
5715
5710
|
class ReviewService {
|
|
5716
5711
|
gitProvider;
|
|
5717
5712
|
config;
|
|
@@ -6191,28 +6186,6 @@ class ReviewService {
|
|
|
6191
6186
|
}
|
|
6192
6187
|
return result;
|
|
6193
6188
|
}
|
|
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
6189
|
}
|
|
6217
6190
|
|
|
6218
6191
|
;// CONCATENATED MODULE: ./src/issue-verify.service.ts
|
|
@@ -6505,11 +6478,8 @@ class DeletionImpactService {
|
|
|
6505
6478
|
// 3. 根据分析模式选择不同的分析方法
|
|
6506
6479
|
const analysisMode = context.analysisMode ?? "openai";
|
|
6507
6480
|
let result;
|
|
6508
|
-
if (
|
|
6509
|
-
|
|
6510
|
-
"open-code"
|
|
6511
|
-
].includes(analysisMode)) {
|
|
6512
|
-
// Claude Agent 模式:使用工具主动探索代码库
|
|
6481
|
+
if (analysisMode === "open-code") {
|
|
6482
|
+
// Agent 模式:使用工具主动探索代码库
|
|
6513
6483
|
result = await this.analyzeWithAgent(analysisMode, deletedBlocks, references, verbose);
|
|
6514
6484
|
} else {
|
|
6515
6485
|
// OpenAI 模式:标准 chat completion
|
|
@@ -6887,8 +6857,8 @@ class DeletionImpactService {
|
|
|
6887
6857
|
}
|
|
6888
6858
|
}
|
|
6889
6859
|
/**
|
|
6890
|
-
* 使用
|
|
6891
|
-
*
|
|
6860
|
+
* 使用 Agent 模式分析删除代码的影响
|
|
6861
|
+
* Agent 可以使用工具主动探索代码库,分析更深入
|
|
6892
6862
|
*/ async analyzeWithAgent(analysisMode, deletedBlocks, references, verbose) {
|
|
6893
6863
|
const llmJsonPut = new LlmJsonPut(DELETION_IMPACT_SCHEMA);
|
|
6894
6864
|
const { systemPrompt, userPrompt } = buildDeletionImpactAgentPrompt({
|
|
@@ -7110,7 +7080,6 @@ const getRulesFromDirInputSchema = z.object({
|
|
|
7110
7080
|
// 忽略配置读取错误
|
|
7111
7081
|
}
|
|
7112
7082
|
const defaultDirs = [
|
|
7113
|
-
join(cwd, ".claude", "skills"),
|
|
7114
7083
|
join(cwd, ".cursor", "skills"),
|
|
7115
7084
|
join(cwd, "review-specs")
|
|
7116
7085
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spaceflow/review",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.2",
|
|
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.
|
|
28
|
+
"@spaceflow/cli": "5.0.1"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"@spaceflow/core": "5.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 /
|
|
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 模式:
|
|
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,
|
|
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
|
-
│ -
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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("
|
|
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
|
|
902
|
-
const context = { owner: "o", repo: "r", prNumber: 1, analysisMode: "
|
|
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 使用标准模式,
|
|
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 (
|
|
160
|
-
//
|
|
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
|
-
* 使用
|
|
588
|
-
*
|
|
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:
|
|
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
|
|
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 模式:
|
|
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 (标准模式) 或
|
|
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
|
|
38
|
+
const title = "fix: bug [/ai-review -l openai]";
|
|
39
39
|
const options = parseTitleOptions(title);
|
|
40
40
|
|
|
41
|
-
expect(options.llmMode).toBe("
|
|
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
|
|
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("
|
|
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 模式 (
|
|
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 ["
|
|
170
|
+
return ["openai", "gemini", "open-code"].includes(value);
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
function isValidDeletionAnalysisMode(value: string): value is LLMMode {
|
|
174
|
-
return ["openai", "
|
|
174
|
+
return ["openai", "open-code"].includes(value);
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
function isValidAnalyzeDeletionsMode(value: string): boolean {
|
package/src/review-context.ts
CHANGED
|
@@ -37,7 +37,7 @@ export interface ReviewContext extends ReviewOptions {
|
|
|
37
37
|
retryDelay?: number;
|
|
38
38
|
/** 仅执行删除代码分析,跳过常规代码审查 */
|
|
39
39
|
deletionOnly?: boolean;
|
|
40
|
-
/** 删除代码分析模式:openai 使用标准模式,
|
|
40
|
+
/** 删除代码分析模式:openai 使用标准模式,open-code 使用 Agent 模式 */
|
|
41
41
|
deletionAnalysisMode?: LLMMode;
|
|
42
42
|
/** 输出格式:markdown, terminal, json。不指定则智能选择 */
|
|
43
43
|
outputFormat?: ReportFormat;
|
package/src/review-llm.spec.ts
CHANGED
|
@@ -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(["
|
|
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")
|
|
@@ -1069,12 +1069,12 @@ export class ReviewResultModel {
|
|
|
1069
1069
|
if (round > 1) {
|
|
1070
1070
|
const prevIssues = allIssues.filter((i) => i.round === round - 1);
|
|
1071
1071
|
if (prevIssues.length > 0) {
|
|
1072
|
-
const
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1072
|
+
const {
|
|
1073
|
+
fixed: prevFixed,
|
|
1074
|
+
resolved: prevResolved,
|
|
1075
|
+
invalid: prevInvalid,
|
|
1076
|
+
pending: prevPending,
|
|
1077
|
+
} = calculateIssueStats(prevIssues);
|
|
1078
1078
|
parts.push("");
|
|
1079
1079
|
parts.push(
|
|
1080
1080
|
`<details><summary>📊 Round ${round - 1} 回顾 (${prevIssues.length} 个问题)</summary>\n`,
|
package/src/review.config.ts
CHANGED
|
@@ -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(["
|
|
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 使用标准模式,
|
|
72
|
+
/** 删除代码分析模式:openai 使用标准模式,open-code 使用 Agent 模式 */
|
|
73
73
|
deletionAnalysisMode?: LLMMode;
|
|
74
74
|
/** 输出格式:markdown, terminal, json。不指定则智能选择 */
|
|
75
75
|
outputFormat?: ReportFormat;
|