- AI 修复:无原生 fix 的 linter 条目走 AI 修复(aiFixEngine/fixPrompt,AI 重检收敛),自定义规则与 AI 审查条目新增 AI 修复按钮(customFixEngine),自定义规则条目展开显示 AI 建议(suggestion 字段)
- 修复预览:面板触发修复先用内置 diff 预览,面板内「应用/取消」两步确认后才写入(fixPreview/fixPending,单条与分 tab 批量均支持)
- 修复面板交互:linter/custom/ai 分 tab「全部修复」、已修复+撤销、pending 按钮状态同步
- bug 修复:修复按钮失败后卡 ⏳ 不恢复;custom/ai 修复不稳定(空修复重试、AI 重检收敛判定放宽、降级接受最后一次有效修复)
- 移除 AI codeDiff 展示块
140 lines
7.1 KiB
Markdown
140 lines
7.1 KiB
Markdown
# 修复功能扩展到自定义规则与 AI 审查设计书
|
||
|
||
> 日期:2026-08-20
|
||
> 状态:已批准(Stage ④ 通过)
|
||
> 流程:① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批
|
||
|
||
## 1. 背景与目标
|
||
|
||
当前自动修复只支持静态分析(linter)条目:`fixIssue`/`fixAll` 从 `orchestrator.getAnalysisResult()` 取 linter 诊断,走 native fix 或 `aiFixDiagnostic`(依赖 LinterAdapter 重 lint 验证收敛)。
|
||
|
||
用户要求将修复能力扩展到**自定义规则(custom tab)**与 **AI 审查(ai tab)** 条目。
|
||
|
||
## 2. 需求澄清结论(Stage ② 共识)
|
||
|
||
| 决策项 | 结论 |
|
||
|--------|------|
|
||
| 修复范围 | 面板 custom + ai 条目标题均支持 AI 修复 |
|
||
| 验证方式 | custom/ai 无对应 linter 适配器,无法重 lint 验证 → **AI 重检收敛**(新文本提交 AI 确认问题消除,未消除带反馈重试 ≤maxIterations) |
|
||
| 入口交互 | **面板按钮 + 两步确认**(与 linter 一致:打开 diff → 应用/取消) |
|
||
| 全部修复 | **分 tab 批量**:linter/custom/ai 各自有「全部修复」按钮 |
|
||
| 修复引擎 | **新建 `customFixEngine.ts`**,复用 AI 修复 prompt,无 adapter 依赖 |
|
||
| 修复后展示 | 各 tab 顶部显示「✅ 已修复 + 撤销」区块 |
|
||
| ai codeDiff | **删除**该字段(schema/prompt/报告展示全部移除) |
|
||
|
||
## 3. 现状关键点(已核实)
|
||
|
||
- `fixIssue`(commands.ts:360)从 `orchestrator.getAnalysisResult()` 取 linter 诊断,`resolveFix` 依赖 adapter。
|
||
- custom 诊断在 `currentReport.customRuleDiagnostics`(`LinterDiagnostic[]`);ai 诊断在 `currentReport.aiFindings`(`AIFinding[]`,`f.line` 已转 0-based)。
|
||
- `aiFixEngine.requestFix`(依赖 provider/options/diag/context)可复用;其收敛验证 `adapter.check` 对 custom/ai 不可用。
|
||
- 两步确认基础设施已完备:`fixPending.ts`、`openPreviewDiff`/`closePreviewEditor`/`applyNewText`、4 个 preview 命令、`reviewPanel.js` 按钮翻转、`pendingStore`。
|
||
- `codeDiff` 字段定义于 schema,唯一用途是 report.ts 导出 Markdown 时展示 ` ```diff ` 块,从未用于真实修复。
|
||
|
||
## 4. 架构概览
|
||
|
||
```
|
||
面板 custom/ai 条目标题「🤖 AI 修复」 / 各 tab「全部修复」
|
||
│ send('fix', line, ruleId, 'custom'|'ai') / send('fixAll', ..., 'custom'|'ai')
|
||
▼
|
||
codeReviewer.fixIssue / fixAll (payload.source 分流)
|
||
│ source === 'custom'|'ai'
|
||
▼
|
||
findCustomIssue / findAIIssue 从 currentReport 定位 ReviewIssueInput
|
||
│
|
||
▼
|
||
customFixEngine.aiFixReviewIssue(document, diag, maxIterations, provider, options, dryRun)
|
||
每轮:buildFixContext → requestFix(AI 生成 {originalText,newText}) → indexOf 匹配替换
|
||
→ verifyFixed(AI 重检 {fixed,reason}) → 未消除带反馈重试 ≤maxIterations
|
||
│ dryRun=true 返回 newText(不写盘)
|
||
▼
|
||
两步确认:openPreviewDiff + pendingStore + postMessage 翻转按钮
|
||
▼ 面板「应用」→ applyFixPreview/applyAllPreview → applyNewText + recordFixes(source) + save + refresh
|
||
```
|
||
|
||
## 5. 文件变更清单
|
||
|
||
### 新建
|
||
|
||
| 文件 | 职责 |
|
||
|------|------|
|
||
| `src/fix/fixPrompt.ts` | 共享修复/重检 prompt builder(三语):`buildFixSystemPrompt`/`buildFixUserPrompt`/`buildFixContext`/`buildVerifySystemPrompt`/`buildVerifyUserPrompt`,`ReviewIssueInput` 接口 |
|
||
| `src/fix/customFixEngine.ts` | `aiFixReviewIssue`:AI 生成修复 + AI 重检收敛,无 adapter 依赖,支持 dryRun |
|
||
| `src/test/customFixEngine.test.ts` | 4 用例(收敛/匹配失败/重试收敛/最大轮次失败) |
|
||
|
||
### 修改
|
||
|
||
| 文件 | 变更 |
|
||
|------|------|
|
||
| `src/fix/aiFixEngine.ts` | 移除内联 prompt builder,改用共享 fixPrompt(行为不变) |
|
||
| `src/fix/fixSession.ts` | `FixedEntry.source: 'linter'|'custom'|'ai'`;`recordFixes` 加 source 参数(默认 linter) |
|
||
| `src/fix/fixPending.ts` | `PendingFix`/`PendingBatch` 加 `source` 字段 |
|
||
| `src/activation/commands.ts` | `resolveReviewIssueFix`/`findCustomIssue`/`findAIIssue`;`fixIssue` 按 source 分流(custom/ai 走 AI 重检);`fixAll` 分 tab 批量;`applyFixPreview`/`applyAllPreview` recordFixes 传 source;`refreshAfterFix` 保留 custom suggestion |
|
||
| `src/panel/webview.ts` | custom/ai 列表启用 AI 修复按钮 + 各自「全部修复」按钮 + 已修复区块(按 source 过滤/徽章);`handleMessage.fixAll` 传 source;`FixedEntryView` 接口 |
|
||
| `src/ai/schema.ts` | 删 `TranslatedDiagnostic.codeDiff`、`AIFinding.codeDiff` |
|
||
| `src/ai/engine.ts` | 删完整审查 + 方法审查 prompt 中的 codeDiff 要求 |
|
||
| `src/utils/report.ts` | 删 Markdown 导出的 ` ```diff ` codeDiff 块 |
|
||
|
||
## 6. 关键接口
|
||
|
||
### 6.1 `src/fix/fixPrompt.ts`
|
||
|
||
```typescript
|
||
export interface ReviewIssueInput {
|
||
ruleId: string;
|
||
line: number; // 0-based
|
||
message: string;
|
||
suggestion?: string;
|
||
}
|
||
export function buildFixSystemPrompt(): string;
|
||
export function buildFixUserPrompt(diag: ReviewIssueInput, context: string): string;
|
||
export function buildFixContext(code: string, line: number): string;
|
||
export function buildVerifySystemPrompt(): string;
|
||
export function buildVerifyUserPrompt(diag: ReviewIssueInput, code: string): string;
|
||
```
|
||
|
||
### 6.2 `src/fix/customFixEngine.ts`
|
||
|
||
```typescript
|
||
export async function aiFixReviewIssue(
|
||
document: vscode.TextDocument,
|
||
diag: ReviewIssueInput,
|
||
maxIterations: number,
|
||
provider: AIProvider,
|
||
options: ChatOptions,
|
||
dryRun?: boolean
|
||
): Promise<FixResult>; // 复用 FixResult/AppliedFix,无 adapter
|
||
```
|
||
|
||
流程:每轮 `requestFix`(AI 生成 `{originalText,newText}`)→ `indexOf` 匹配 → 替换 → `verifyFixed`(AI 重检 `{fixed,reason}`)→ 未消除带 reason 反馈重试。
|
||
|
||
### 6.3 命令协议
|
||
|
||
- `fixIssue` payload.source:`'linter'|'custom'|'ai'`(webview 已传),命令分流。
|
||
- `fixAll` payload:`{ source?: 'linter'|'custom'|'ai' }`,分 tab 批量。
|
||
- 面板消息 `fixAll` 透传 source:`send('fixAll', undefined, undefined, 'custom')`。
|
||
|
||
### 6.4 面板
|
||
|
||
- custom/ai 条目:`buildIssueItem(..., aiFixable=true)` → 显示「🤖 AI 修复」+ 隐藏的应用/取消按钮(复用现有两步确认)。
|
||
- 各 tab 顶部「全部修复」→ `send('fixAll', ..., source)`。
|
||
- 已修复区块:`fixedEntries` 按 `source` 过滤 + `buildFixedItem` 按 source 渲染徽章;custom/ai 列表用 fixedKeys 过滤已修条目。
|
||
|
||
## 7. 删除 codeDiff
|
||
|
||
- schema.ts:`TranslatedDiagnostic.codeDiff`、`AIFinding.codeDiff` 移除。
|
||
- engine.ts:完整审查(zh/en/ja)与方法审查(En/Zh/Ja)prompt 中 `"codeDiff"` 要求行全部移除。
|
||
- report.ts:`reportToMarkdown` 中 ` ```diff ` 代码块展示移除。
|
||
|
||
## 8. i18n
|
||
|
||
无需新增 key(复用 `fix.aiRunning`/`fix.aiFailed`/`fix.noAI`/`report.fixAll`/`report.fixAILabel`/`report.fixedIssues`/`report.undoFix`)。
|
||
|
||
## 9. 测试计划
|
||
|
||
- 新增 `customFixEngine.test.ts` 4 用例:收敛、匹配失败、重检后重试收敛、最大轮次失败。
|
||
- 现有 106 用例回归通过(共 110 passing)。
|
||
|
||
## 10. 验证顺序
|
||
|
||
`lint → compile → test`(`npm run lint` / `npm run compile` / `npm test`)。
|