feat: AI 修复预生成 + 审查面板 diff 预览两步确认 + SQLFluff 行号修复 + PMD 内置规则精简
- AI 修复预生成:静态/custom/AI 条目审查时预生成修复片段(originalText/newText),展开问题即显示行级 diff,无预生成时展示占位提示,匹配失败回退实时 LLM 生成 - 修复前 diff 预览:侧边新建编辑器组打开内置 diff,确认后写入(两步确认),不覆盖当前文件 - fix: sqlfluff 在 jinja 标签位于注释内时 JJ01 JSON 缺失 end_line_no/end_line_pos,适配器 Range 构造产生 NaN 被 VSCode 交换 start/end 导致行号 LNaN;新增 resolveSqlFluffRange 兜底 + 面板/report 行号 Number.isFinite 防御 - fix: 从 PMD 内置 ruleset 移除 5 条实际不可触发规则(AvoidAssertAsIdentifier、AvoidEnumAsIdentifier、AccessorClassGeneration、AccessorMethodGeneration、LoosePackageCoupling),内置配置 274→269 条全部可触发,同步 static-rules.json 与翻译脚本 - docs: README/DESIGN 更新
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
# 审核时预生成修复 + 展开问题即显示 diff
|
||||
|
||||
日期:2026-08-22
|
||||
状态:已批准
|
||||
|
||||
## 目标
|
||||
|
||||
1. 审核时 AI 为三类问题(custom 规则问题、AI 深度审查发现、linter 无 autofix 诊断)预生成可直接应用的修复片段 `{ originalText, newText }`。
|
||||
2. 点击面板"修复"按钮直接从报告取片段匹配应用,无需再调 LLM;匹配失败自动回退实时 AI 修复。
|
||||
3. 面板展开问题时,直接以行级 `-/+` 对比显示修复前后代码(所有可修复问题,含 linter 自带 fix)。
|
||||
4. `fixAll` 采用"预生成片段优先,失败回退实时"策略,不做偏移修正。
|
||||
|
||||
## 数据流
|
||||
|
||||
```
|
||||
审核(发现 + 预生成修复片段) → 面板
|
||||
├─ 点修复 → 直接匹配应用(免等待) → 失败 → 回退实时 LLM
|
||||
└─ 展开问题 → 行级 -/+ diff 立即渲染
|
||||
```
|
||||
|
||||
## 关键决策
|
||||
|
||||
| 决策点 | 结论 |
|
||||
|---|---|
|
||||
| 预生成覆盖 | custom + AI findings + linter 无 autofix 诊断 |
|
||||
| 匹配失败 | 回退实时 AI 修复 |
|
||||
| 点击修复 | 保留 diff 预览确认,内容来自预生成片段 |
|
||||
| 展开 diff 形式 | 行级 -/+ 对比(红删/绿增) |
|
||||
| 展开 diff 范围 | 所有可修复问题(含 linter 自带 fix) |
|
||||
| fixAll 策略 | 预生成片段优先,失败回退实时,不做偏移修正 |
|
||||
| 兼容性 | `fix`/`aiFix` 字段可选,缺失则该问题无预生成修复/diff,行为不变 |
|
||||
|
||||
## 文件变更
|
||||
|
||||
| 文件 | 变更 |
|
||||
|---|---|
|
||||
| `src/types.ts` | 新增 `AiFixSnippet { originalText; newText }`;`LinterFix` 加 `originalText?`;`LinterDiagnostic` 加 `aiFix?: AiFixSnippet` |
|
||||
| `src/ai/schema.ts` | `CustomRuleResult`、`AIFinding`、`TranslatedDiagnostic` 加可选 `fix?: AiFixSnippet` |
|
||||
| `src/ai/engine.ts` | 三语 prompt(zh/en/ja)的 `customRuleResults`/`findings`/`translatedDiagnostics` 输出格式加 `fix` 字段(含"原文逐字、不含行号前缀"说明);`runAIReview`/`runMethodReview` 解析容错保留 `fix` |
|
||||
| `src/merger/merger.ts` | `MergeInput` 加 `code?`;映射 `staticDiagnostics` 时从 `code` 按 `fix.range` 切片补 `fix.originalText`;映射 `customRuleResults` 时带 `aiFix` |
|
||||
| `src/activation/commands.ts` | 所有 `mergeResults` 调用点传 `document.getText()` 作为 `code`;`refreshAfterFix` 重建时保留 `aiFix`;`findCustomIssue`/`findAIIssue`/`fixAll` 带 `fix` |
|
||||
| `src/fix/fixPrompt.ts` | `ReviewIssueInput` 加 `fix?: AiFixSnippet` |
|
||||
| `src/fix/customFixEngine.ts` | `aiFixReviewIssue` 开头尝试预生成片段直接应用,失败进实时循环 |
|
||||
| `src/fix/aiFixEngine.ts` | `aiFixDiagnostic` 开头尝试预生成片段直接应用 |
|
||||
| `src/utils/diff.ts`(新建) | 轻量行级 diff(LCS),返回 `{type:'del'\|'add'\|'same', text}[]` |
|
||||
| `src/panel/webview.ts` | 展开区渲染行级 diff(`.diff-del` 红 / `.diff-add` 绿 + CSS);三列表构造 detailHtml 时并入 diff;suggestion 与 diff 同时展示 |
|
||||
|
||||
## 核心逻辑
|
||||
|
||||
### 预生成片段直接应用(两个修复引擎开头共用模式)
|
||||
|
||||
```ts
|
||||
const p = diag.fix ?? diag.aiFix;
|
||||
if (p?.originalText && p?.newText) {
|
||||
const i = currentText.indexOf(p.originalText);
|
||||
if (i !== -1) {
|
||||
const next = currentText.slice(0, i) + p.newText + currentText.slice(i + p.originalText.length);
|
||||
if (next !== currentText) {
|
||||
appliedFixes.push({ originalText: p.originalText, newText: p.newText, line });
|
||||
return dryRun ? { success: true, appliedFixes, newText: next }
|
||||
: applyWorkspaceEdit(document, next, appliedFixes);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 匹配失败 → 继续现有 for 循环(实时 LLM)
|
||||
```
|
||||
|
||||
### 展开 diff 渲染
|
||||
|
||||
```ts
|
||||
// 提取每条问题的修复片段
|
||||
linter: d.fix?.originalText + d.fix?.text // 或 d.aiFix
|
||||
custom: d.aiFix
|
||||
ai: f.fix
|
||||
// 生成行级 diff HTML
|
||||
diffHtml = computeLineDiff(originalText, newText)
|
||||
.map(l => `<div class="diff-${l.type}">${esc(l.text)}</div>`).join('')
|
||||
```
|
||||
|
||||
### fixAll 策略
|
||||
|
||||
逐条串行处理:每条问题先尝试预生成片段在当前累积文本 `currentText` 上匹配,命中则直接应用(不调 LLM);失败或无片段则走现有实时修复。完成后保留批量 diff 预览 + 应用确认。
|
||||
|
||||
## 影响与风险
|
||||
|
||||
- 审核输出变长(三个来源都输出 fix),token/耗时略增——换取点修复零等待 + 展开即见 diff
|
||||
- linter 原文片段依赖 `code` 全文切片;`refreshAfterFix` 需传当前文本,否则 diff 基于旧文本(匹配失败会回退,体验无损)
|
||||
- 自写 diff 仅行级对比,不做字符级高亮
|
||||
|
||||
## 验证
|
||||
|
||||
- `npm run lint` → `npm run compile` → `npm test`
|
||||
- 手动验证:custom / AI findings / linter 无 autofix 三条路径的"展开即见 diff"与"点修复免等待"
|
||||
- 修改代码后再点修复应回退实时
|
||||
- fixAll 批量场景多数问题秒过,个别失败回退实时
|
||||
Reference in New Issue
Block a user