diff --git a/_AI_USAGE_LOG.md b/_AI_USAGE_LOG.md index 6b80f8f..5c92b56 100644 --- a/_AI_USAGE_LOG.md +++ b/_AI_USAGE_LOG.md @@ -216,15 +216,15 @@ | 2026-08-19 21:29 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 修复前 Diff 预览确认功能:面板触发的修复应用前用 VSCode 内置 diff 编辑器展示修改前后对比,确认后才写入。fixEngine.ts/aiFixEngine.ts:FixResult 增 newText?,fixDiagnostic/aiFixDiagnostic 增 dryRun 参数(为真时跳过 WorkspaceEdit 返回 newText)。新建 src/fix/fixPreview.ts:TextDocumentContentProvider(scheme codeReviewerPreview,diff 两侧均走 provider 避免脏文档左屏显示磁盘旧内容) + previewAndConfirm(vscode.diff 打开内置 diff + showInformationMessage 应用/取消对话框,选完统一关 diff 编辑器再清理 provider)+ applyNewText(整文档 WorkspaceEdit)。commands.ts:resolveFix 透传 dryRun;fixIssue 面板 origin 走 dryRun→diff 预览→确认后 applyNewText+recordFixes,hover 保持直接应用零变化;fixAll 改为内存累积(mockDocument 逐条 dryRun 计算 currentText 累积)→合并单 diff 预览→确认后一次性 applyNewText+逐条 recordFixes(原逐个写盘+多次刷新改为一次写入)。i18n 新增 fix.confirmApply/fix.apply/fix.cancel/fix.previewTitle 三语。extension.ts 注册 registerFixPreviewProvider。spec:docs/superpowers/specs/2026-08-19-fix-preview-design.md。npm test 106 passing / lint 0 error(仅 mockDocument.ts 2 个既有 curly warning)/ compile 通过 | 中间产物:①applyNewText 初版签名含 fixSession/ruleId/line/appliedFixes/record 五参(把记录职责内聚),实现时发现 fixAll 需逐条 recordFixes、单条预览也需在 diff 模块外记录,简化为仅 (document,newText) 纯写入,记录回归调用方;②fixAll 的 results 类型初版写成 typeof fixSession extends never 类型体操编译报错,改为显式 { ruleId; line; appliedFixes: AppliedFix[] }[] 并补 AppliedFix import;③自审查发现修复 bug——预览路径(isPreview)下原 recordFixes 条件 (origin!=='hover' && !isPreview) 恒假,撤销会话丢失,改为 if(isPreview){...记录} else if(origin!=='hover'){...记录};④freshDiag 行号匹配初版写 Math.abs(diff)<=0 语义即严格相等,简化为 ===;⑤previewAndConfirm 初版仅取消时关 diff,应用时残留 diff 编辑器会因 provider.clear 变空白,改为无论应用/取消都先 closePreviewEditors 再 clear | docs/superpowers/specs/2026-08-19-fix-preview-design.md(新建) src/fix/fixPreview.ts(新建) src/fix/fixEngine.ts src/fix/aiFixEngine.ts src/activation/commands.ts src/extension.ts src/i18n/messages.ts | deepseek-v4-flash | | 2026-08-20 19:21 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 修复实测问题:确认按钮不保持。实测发现 previewAndConfirm 用 showInformationMessage({modal:false}) 的右下角通知几秒后自动消失(返回 undefined 被当取消并关闭 diff)。经用户决策改为「面板内两步确认」:新建 src/fix/fixPending.ts(PendingFix/PendingBatch/FixPendingStore 待确认存储,按 filePath+key 索引,含 diffUri);fixPreview.ts 删 previewAndConfirm,新增 openPreviewDiff(返回 newUri)/closePreviewEditor(关 diff 标签+清理 provider)/applyNewText 简化;commands.ts 新增 4 命令 applyFixPreview/cancelFixPreview/applyAllPreview/cancelAllPreview(应用=写入+recordFixes+关 diff+删 pending+save+refresh;取消=关 diff+删 pending+postMessage 还原按钮),fixIssue panel 路径只存 pending+开 diff+postMessage 翻转按钮,fixAll 只存 batch+开 diff+postMessage,review 与文档关闭时 pendingStore.clear;webview.ts PanelMessage 增 applyFix/cancelFix/applyAll/cancelAll,buildIssueItem 对可修条目渲染隐藏的 btn-apply/btn-cancel(data-fix-key=ruleId@line),buildLinterList 顶部渲染隐藏 btn-apply-all/btn-cancel-all,handleMessage 路由到新命令,ReviewPanel 增公开 postMessage 方法;reviewPanel.js 增 window message 监听按 key/class 翻转按钮显隐(不全量重建面板,滚动/标签页保持);extension.ts 创建/传递 FixPendingStore;i18n 新增 report.fixAllApply 三语(复用 fix.apply/fix.cancel/fix.previewTitle)。spec 同步更新确认交互为两步确认。npm test 106 passing / lint 0 error / compile 通过。问题2(diff 左右结构)按用户要求暂缓 | 中间产物:①初版考虑 modal:true 居中模态框(按钮保持但挡 diff)用户弃选改面板两步确认;②ReviewPanel.currentPanel.webview 私有属性 4 处编译报错 TS2339,加公开 postMessage() 方法并用 PowerShell 批量替换调用点;③reviewPanel.js 翻转初版用 inline-flex 恢复显示,CSS 无此值改回清空 display 由默认样式接管 | src/fix/fixPending.ts(新建) src/fix/fixPreview.ts src/activation/commands.ts src/panel/webview.ts src/views/reviewPanel.js src/extension.ts src/i18n/messages.ts docs/superpowers/specs/2026-08-19-fix-preview-design.md | deepseek-v4-flash | | 2026-08-20 19:47 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 自定义规则条目支持展开显示 AI 修复建议:用户反馈自定义规则(custom tab)条目不可展开(无 suggestion、无修复意见),linter 条目可展开带 AI 建议。澄清后确定为「展开显示 AI 建议文本(💡)」,不加 AI 修复按钮。改动:schema.ts CustomRuleResult 加 suggestion?: string;engine.ts buildCustomRuleSystemPrompt(完整审查 zh/en/ja 三段)输出 JSON 格式加 "suggestion" 并要求每条违规必给可执行建议,buildMethodSystemPromptEn/Zh/Ja(方法审查)customRuleResults 输出段加 "suggestion"(runAIReview/runMethodReview 已用 ...r 展开映射自动透传无需改);merger.ts custom 诊断映射补 suggestion: r.suggestion;webview.ts 无需改(buildCustomList 已传 d.suggestion,非空即触发 buildIssueItem 展开详情复用 detail-suggestion 渲染)。spec:docs/superpowers/specs/2026-08-20-custom-rule-suggestion-design.md。npm test 106 passing / lint 0 error / compile 通过 | 中间产物:澄清阶段在「仅展开建议文本」与「展开+AI 修复按钮」间选择,用户选前者(自定义规则无 linter 可验证,修复按钮需额外适配,暂缓) | src/ai/schema.ts src/ai/engine.ts src/merger/merger.ts docs/superpowers/specs/2026-08-20-custom-rule-suggestion-design.md(新建) | deepseek-v4-flash | -| 2026-08-20 20:18 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 修复功能扩展到自定义规则与 AI 审查:面板 custom/ai 条目标题支持 AI 修复,分 tab 批量(各 tab 各自「全部修复」),两步确认复用,各 tab 显示已修复+撤销。新建 src/fix/fixPrompt.ts(共享修复/重检 prompt builder 三语 + ReviewIssueInput 接口,从 aiFixEngine 提取)+ src/fix/customFixEngine.ts(aiFixReviewIssue:AI 生成修复→indexOf 匹配替换→AI 重检 {fixed,reason} 收敛,未消除带反馈重试 ≤maxIterations,无 adapter,支持 dryRun)+ src/test/customFixEngine.test.ts(4 用例)。aiFixEngine.ts 改用共享 fixPrompt(requestFix 内构造 ReviewIssueInput 适配 range→line)。fixSession.ts FixedEntry 加 source:'linter'|'custom'|'ai',recordFixes 加 source 参数;fixPending.ts PendingFix/PendingBatch 加 source。commands.ts 新增 resolveReviewIssueFix/findCustomIssue/findAIIssue,fixIssue 按 payload.source 分流(custom/ai 走 AI 重检),fixAll 分 tab 批量(payload.source),applyFixPreview/applyAllPreview recordFixes 传 source,refreshAfterFix 保留 custom suggestion(原映射丢 suggestion)。webview.ts custom/ai 列表启用 aiFixable 渲染修复按钮+各 tab fixAll 按钮传 source+已修复区块按 source 过滤与徽章+FixedEntryView 接口。删除 codeDiff:schema.ts 两字段、engine.ts 完整+方法审查 prompt 全部 codeDiff 行、report.ts ```diff``` 展示块。spec:docs/superpowers/specs/2026-08-20-custom-ai-fix-design.md。npm test 110 passing / lint 0 error / compile 通过 | 中间产物:①澄清阶段用户在「AI 生成后不验证」与「AI 重检收敛」间两轮选择,最终定为 AI 重检收敛(无 linter 可重 lint,用 AI 重检替代);②codeDiff 去留讨论——用户问「带着有需要吗」,说明其现状仅报告展示用,用户决定删除;③refreshAfterFix 的 customRuleResults 映射初版未含 suggestion,审查中发现会破坏上轮 custom 展开功能,补上;④aiFixEngine requestFix 传入 LinterDiagnostic 与 fixPrompt.ReviewIssueInput 类型不匹配(line vs range)编译报错 TS2345,改为构造 ReviewIssueInput | src/fix/fixPrompt.ts(新建) src/fix/customFixEngine.ts(新建) src/fix/aiFixEngine.ts src/fix/fixSession.ts src/fix/fixPending.ts src/activation/commands.ts src/panel/webview.ts src/ai/schema.ts src/ai/engine.ts src/utils/report.ts src/test/customFixEngine.test.ts(新建) docs/superpowers/specs/2026-08-20-custom-ai-fix-design.md(新建) | deepseek-v4-flash | +| 2026-08-20 20:18 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 修复功能扩展到自定义规则与 AI 审查:面板 custom/ai 条目标题支持 AI 修复,分 tab 批量(各 tab 各自「全部修复」),两步确认复用,各 tab 显示已修复+撤销。新建 src/fix/fixPrompt.ts(共享修复/重检 prompt builder 三语 + ReviewIssueInput 接口,从 aiFixEngine 提取)+ src/fix/customFixEngine.ts(aiFixReviewIssue:AI 生成修复→indexOf 匹配替换→AI 重检 {fixed,reason} 收敛,未消除带反馈重试 ≤maxIterations,无 adapter,支持 dryRun)+ src/test/customFixEngine.test.ts(4 用例)。aiFixEngine.ts 改用共享 fixPrompt(requestFix 内构造 ReviewIssueInput 适配 range→line)。fixSession.ts FixedEntry 加 source:'linter'|'custom'|'ai',recordFixes 加 source 参数;fixPending.ts PendingFix/PendingBatch 加 source。commands.ts 新增 resolveReviewIssueFix/findCustomIssue/findAIIssue,fixIssue 按 payload.source 分流(custom/ai 走 AI 重检),fixAll 分 tab 批量(payload.source),applyFixPreview/applyAllPreview recordFixes 传 source,refreshAfterFix 保留 custom suggestion(原映射丢 suggestion)。webview.ts custom/ai 列表启用 aiFixable 渲染修复按钮+各 tab fixAll 按钮传 source+已修复区块按 source 过滤与徽章+FixedEntryView 接口。删除 codeDiff:schema.ts 两字段、engine.ts 完整+方法审查 prompt 全部 codeDiff 行、report.ts ```diff``` 展示块。spec:docs/superpowers/specs/2026-08-20-custom-ai-fix-design.md。npm test 110 passing / lint 0 error / compile 通过 | 中间产物:①澄清阶段用户在「AI 生成后不验证」与「AI 重检收敛」间两轮选择,最终定为 AI 重检收敛(无 linter 可重 lint,用 AI 重检替代);②codeDiff 去留讨论——用户问「带着有需要吗」,说明其现状仅报告展示用,用户决定删除;③refreshAfterFix 的 customRuleResults 映射初版未含 suggestion,审查中发现会破坏上轮 custom 展开功能,补上;④aiFixEngine requestFix 传入 LinterDiagnostic 与 fixPrompt.ReviewIssueInput 类型不匹配(line vs range)编译报错 TS2345,改为构造 ReviewIssueInput | | 2026-08-20 21:56 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 修复面板「修复」按钮卡 ⏳ 不恢复的 bug(实测:custom 修复失败 ai-no-fix 后按钮永久卡 ⏳、点取消后也卡 ⏳)。根因双处:①reviewPanel.js pending/batchPending 消息翻转只切 display,从不重置「修复」按钮的 textContent/disabled——点击时 JS 设 disabled=true+textContent='⏳...'(webview.ts buildIssueItem onclick),取消(on:false)恢复显示后仍停留在 ⏳+disabled;②fixIssue/fixAll 命令层失败路径(!result.success、success===0、catch)只 showWarningMessage 就 return,从不 postMessage 恢复按钮。修复:webview.ts buildIssueItem 修复按钮加 data-label 存原始文案(🔧 修复/🤖 AI 修复,esc 转义);reviewPanel.js pending 消息 on:false 时对非 confirm 按钮(data-label)恢复 textContent+disabled=false;commands.ts fixIssue custom/linter 分支失败+catch 补 postMessage {type:'pending',key,on:false}(key=ruleId@line),fixAll 两处 success===0+catch 补 {type:'batchPending',on:false}。npm test 110 passing / lint 0 error / compile 通过。ai-no-fix 与「聚焦文件才生效」的关系仍在排查(用户复现:不聚焦连点 3 次必现失败;聚焦后成功,但代码逻辑 panel 来源取文档不依赖焦点,待进一步定位) | 中间产物:①初版考虑在失败弹窗后靠 refreshAfterFix 全量重建面板恢复按钮,发现失败路径根本不走 refreshAfterFix,改显式 postMessage;②data-label 文案初版直接拼 emoji+t(),审查确认 esc() 转义 & < > " 后 dataset 读取自动解码安全;③是否给 catch 也补恢复曾有犹豫,确认异常路径同样需恢复故一并补上 | src/panel/webview.ts src/views/reviewPanel.js src/activation/commands.ts | deepseek-v4-flash | -| 2026-08-20 22:20 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 修复 custom/ai 修复不稳定(用户实测「有时能修有时不能」,排除聚焦因素后确认是 AI 链路稳定性问题)。根因三处:①fixPrompt.buildFixSystemPrompt 只要求「无法修复就输出空」,给了 AI 轻易放弃的空间(→ ai-no-fix);②customFixEngine.verifyFixed 用 parsed.fixed === true 严格相等,AI 返回字符串 "true" 永不收敛(→ max-iterations);③收敛失败整体回滚,一次不确定的 AI 重检否定已生成的有效修复。修复(按用户确认的 C1 方案):①prompt 三语加硬性要求「必须输出修复片段,禁止输出空修复;即使无法完全消除也要给缓解/改善的最小片段」;②requestFix 对空修复/解析失败自动重试 1 次(customFixEngine 与 aiFixEngine 同步,前者重试后仍空才 null);③verifyFixed 宽松判定 f===true || String(f)==='true';④C1 收敛降级——循环结束未收敛时若 appliedFixes.length>0 则接受最后一次修复(返回 success+newText 走正常 diff 预览),仅从未生成出可匹配修复才失败;⑤每轮加 console.log('[code-reviewer] review-fix', ruleId, round, {ai-no-fix/ai-match-failed/no-change/applied/verify}) 诊断日志。测试:customFixEngine.test.ts 原 max-iterations 用例改为「accepts last fix when verify never passes」(断言 success=true+newText),新增「retries empty fix once then fails with ai-no-fix」用例(两次空响应)。npm test 111 passing / lint 0 error / compile 通过 | 中间产物:①TS2367 类型不重叠——parsed.fixed 类型 boolean|undefined 与 'true' 字符串比较报错,用 & { fixed?: unknown } 断言 + String(f) 收窄解决;②aiFixEngine 的 ai-no-fix 测试用例只给 1 次空响应,重试后取默认 '{}'(无 originalText)仍返回 ai-no-fix,无需改断言;③C1 实现位置纠结——先想在循环外统一处理,实际把降级分支写在 !converged 内并与 dryRun/apply 复用收尾 | src/fix/fixPrompt.ts src/fix/customFixEngine.ts src/fix/aiFixEngine.ts src/test/customFixEngine.test.ts | deepseek-v4-flash | +| 2026-08-20 22:20 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 修复 custom/ai 修复不稳定(用户实测「有时能修有时不能」,排除聚焦因素后确认是 AI 链路稳定性问题)。根因三处:①fixPrompt.buildFixSystemPrompt 只要求「无法修复就输出空」,给了 AI 轻易放弃的空间(→ ai-no-fix);②customFixEngine.verifyFixed 用 parsed.fixed === true 严格相等,AI 返回字符串 "true" 永不收敛(→ max-iterations);③收敛失败整体回滚,一次不确定的 AI 重检否定已生成的有效修复。修复(按用户确认的 C1 方案):①prompt 三语加硬性要求「必须输出修复片段,禁止输出空修复;即使无法完全消除也要给缓解/改善的最小片段」;②requestFix 对空修复/解析失败自动重试 1 次(customFixEngine 与 aiFixEngine 同步,前者重试后仍空才 null);③verifyFixed 宽松判定 f===true || String(f)==='true';④C1 收敛降级——循环结束未收敛时若 appliedFixes.length>0 则接受最后一次修复(返回 success+newText 走正常 diff 预览),仅从未生成出可匹配修复才失败;⑤每轮加 console.log('[code-reviewer] review-fix', ruleId, round, {ai-no-fix/ai-match-failed/no-change/applied/verify}) 诊断日志。测试:customFixEngine.test.ts 原 max-iterations 用例改为「accepts last fix when verify never passes」(断言 success=true+newText),新增「retries empty fix once then fails with ai-no-fix」用例(两次空响应)。npm test 111 passing / lint 0 error / compile 通过 | 中间产物:①TS2367 类型不重叠——parsed.fixed 类型 boolean| | 2026-08-20 22:32 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 重写 README.md:补齐运行环境要求(VSCode 1.120+/Node/Java/sqlfluff)、安装步骤(VSIX 安装 + 源码构建)、运行方法(端用户命令表 + 开发者命令表)、前端 Webview 面板启动方式、API 密钥配置(SecretStorage + 配置项表 + 自定义供应商)、依赖清单(运行/开发依赖表)、其他配置项 | 无 | README.md | deepseek-v4-flash | | 2026-08-20 22:33 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 审查验证阶段修正 README:devDependencies 清单中移除不存在的 eslint 条目(eslint 仅存在于 dependencies) | 初版 README 依赖清单误列 eslint 于 dev 表 → 核对 package.json 后移除 | README.md | deepseek-v4-flash | | 2026-08-22 14:11 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 审核时预生成修复 + 展开问题即显示 diff:types.ts 新增 AiFixSnippet/LinterFix.originalText/LinterDiagnostic.aiFix;schema.ts CustomRuleResult/AIFinding/TranslatedDiagnostic 加可选 fix;engine.ts 三语 prompt(customRuleResults/findings/translatedDiagnostics/方法审查)输出格式加 fix 字段及原文不含行号前缀说明(解析用 ...r 展开自动透传);utils/diff.ts 新建行级 diff(LCS);merger.ts MergeInput 加 code?,静态诊断从 code 按 fix.range 切片补 fix.originalText,customRuleDiagnostics 带 aiFix,翻译 fix 合并进 aiFix;fixPrompt.ts ReviewIssueInput 加 fix;customFixEngine/aiFixEngine 开头预生成片段 indexOf 匹配直接应用(dryRun 返回 newText/否则 applyEdit),匹配失败回退实时 LLM 循环;commands.ts mergeResults 三处传 code、refreshAfterFix 重建时保留 aiFix、findCustomIssue/findAIIssue/fixAll 带 fix、新增 enrichLinterDiagnostic 从 currentReport.linterDiagnostics 补 aiFix(fixIssue/fixAll linter 路径);webview.ts buildIssueItem 增 fixDiffHtml 参数、展开区渲染行级 -/+ diff(.fix-diff/.diff-del/.diff-add CSS)、三列表按 aiFix/fix 计算 diff、suggestion 与 diff 并存;messages.ts 新增 report.fixPreview 三语;spec 文档 docs/superpowers/specs/2026-08-22-pregen-fix-design.md。lint 0 error(仅 mockDocument.ts 2 个既有 curly warning)/ compile 通过 / npm test 111 passing | 方案迭代:初版仅 custom+AI findings 预生成,用户确认扩展含 linter 无 autofix 诊断(translatedDiagnostics 带 fix);merger 初版原地改 fix.originalText 会污染 orchestrator 缓存共享对象,改为 spread 新建副本;fixAll 策略用户采纳「预生成优先+失败回退实时、不做偏移修正」 | docs/superpowers/specs/2026-08-22-pregen-fix-design.md(新建) src/types.ts src/ai/schema.ts src/ai/engine.ts src/utils/diff.ts(新建) src/merger/merger.ts src/fix/fixPrompt.ts src/fix/customFixEngine.ts src/fix/aiFixEngine.ts src/activation/commands.ts src/panel/webview.ts src/i18n/messages.ts | deepseek-v4-flash | -| 2026-08-22 14:50 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 无预生成 fix 的问题展开区显示占位提示(不再空白):webview.ts buildIssueItem 新增 fixPlaceholder——(fixable||aiFixable) 且 fixDiffHtml 为空时渲染「无预生成修复,点击修复将实时生成」提示条(.detail-no-fix 虚线框样式),展开区渲染条件与分支扩展为 detailHtml/suggestion/fixDiffHtml/fixPlaceholder 四选;messages.ts 新增 report.fixUnavailable 三语 key。lint 0 error(仅既有 mockDocument.ts 2 warning)/ compile 通过 / npm test 111 passing | 无 | src/panel/webview.ts src/i18n/messages.ts | deepseek-v4-flash | +| 2026-08-22 14:50 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 无预生成 fix 的问题展开区显示占位提示(不再空白):webview.ts buildIssueItem 新增 fixPlaceholder——(fixable||aiFixable) 且 fixDiffHtml 为空时渲染「无预生成修复,点击修复将实时生成」提示条(.detail-no-fix 虚线框样式),展开区渲染条件与分支扩展为 detailHtml/suggestion/fixDiffHtml/fixPlaceholder 四选;messages.ts 新增 report.fixUnavailable 三语 key。lint 0 error(仅既有 mockDocument.ts 2 warning)/ compile 通过 / npm test 111 passing | 无 | | 2026-08-25 19:13 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | diff 预览改为在侧边新建编辑器组打开(不覆盖当前正在查看的文件):fixPreview.ts openPreviewDiff 的 vscode.diff 调用补第 4 参数 { viewColumn: vscode.ViewColumn.Beside, preserveFocus: true },4 个触发点(fixIssue/fixAll × linter/custom-AI)均走此函数全覆盖;closePreviewEditor 遍历所有 tabGroups 与分组位置无关无需改动。lint 0 error(仅既有 mockDocument.ts 2 warning)/ compile 通过 / npm test 111 passing | 澄清阶段「新建编辑器组/侧边标签页」vs「全新 VSCode 窗口实例」两分支,用户选前者(全新窗口扩展 API 不支持且 diff 内容在内存中不可行);preserveFocus 加否为方案决策点,用户确认加(打开 diff 后焦点留在审查面板) | src/fix/fixPreview.ts | deepseek-v4-flash | -| 2026-08-25 21:35 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 修复 sqlfluff 行号显示 LNaN:根因是 sqlfluff 4.x 对「jinja 标签位于注释内」的 JJ01 违规 JSON 缺失 end_line_no/end_line_pos,适配器 `v.end_line_no-1`=NaN → VSCode Range 构造时 start.isBefore(end) 对 NaN 恒 false 触发 start/end 交换 → range.start.line=NaN → 面板 L${line+1} 渲染 LNaN。修复:adapters/sqlfluff.ts 新增纯函数 resolveSqlFluffRange(缺失/null/NaN/非法值兜底:start 回退 1、end 回退 start;兼容旧版 line_no/line_pos key;start_line_pos=0 钳制 ≥1),check() 改用其构造 Range;SqlFluffViolation position 字段改可选;webview.ts buildIssueItem 与 utils/report.ts formatLine 加 Number.isFinite 防御(非法行号渲染 L?);新增 src/test/sqlfluff-range.test.ts 6 用例。验证:lint 0 error(仅既有 mockDocument.ts 2 warning)/ compile 通过 / npm test 111 passing | 中间产物:①根因排查多轮——先后排除旧版 sqlfluff schema(line_no key)与「注释场景缺 end 字段只坏终点不坏起点」假设,最终结合 VSCode extHostTypes/range.ts 源码确认 NaN 使 isBefore 恒 false 触发 start/end 交换,链路闭合;②sanitizePosition 初版参数类型 number|undefined,测试用例传 null 触发 TS 类型错误,接口与函数签名扩为 number|null|undefined | src/adapters/sqlfluff.ts src/panel/webview.ts src/utils/report.ts src/test/sqlfluff-range.test.ts(新建) | deepseek-v4-flash | +| 2026-08-25 21:35 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 修复 sqlfluff 行号显示 LNaN:根因是 sqlfluff 4.x 对「jinja 标签位于注释内」的 JJ01 违规 JSON 缺失 end_line_no/end_line_pos,适配器 `v.end_line_no-1`=NaN → VSCode Range 构造时 start.isBefore(end) 对 NaN 恒 false 触发 start/end 交换 → range.start.line=NaN → 面板 L${line+1} 渲染 LNaN。修复:adapters/sqlfluff.ts 新增纯函数 resolveSqlFluffRange(缺失/null/NaN/非法值兜底:start 回退 1、end 回退 start;兼容旧版 line_no/line_pos key;start_line_pos=0 钳制 ≥1),check() 改用其构造 Range;SqlFluffViolation position 字段改可选;webview.ts buildIssueItem 与 utils/report.ts formatLine 加 Number.isFinite 防御(非法行号渲染 L?);新增 src/test/sqlfluff-range.test.ts 6 用例。验证:lint 0 error(仅既有 mockDocument.ts 2 warning)/ compile 通过 / npm test 111 passing | 中间产物:①根因排查多轮——先后排除旧版 sqlfluff schema(line_no key)与「注释场景缺 end 字段只坏终点不坏起点」假设,最终结合 VSCode extHostTypes/range.ts 源码确认 NaN 使 isBefore 恒 false 触发 start/end 交换,链路闭合;②sanitizePosition 初版参数类型 number|undefined,测试用例传 null 触发 TS 类型错误,接口与函数签名扩为 number|null| | 2026-08-25 21:54 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 从插件内置 PMD 配置移除 5 条实际不可触发的规则(AvoidAssertAsIdentifier/AvoidEnumAsIdentifier 语言版本上限 1.3/1.4、AccessorClassGeneration/AccessorMethodGeneration 上限 Java 10、LoosePackageCoupling 需显式 packages 配置),使内置配置=全部可触发,demo-pmd 覆盖率基线对齐 269+12=281 可达成 100%。改动:jars/pmd/pmd-java-ruleset.xml 三个分类 exclude 各追加(bestpractices 2 + design 1 + errorprone 2)并将 description 计数 274→269;src/rules/static-rules.json linterVersion.pmd 改 269、移除 5 条规则条目(pmd 295→290);scripts/translations/pmd-1.mjs/pmd-2.mjs 同步删除 5 条翻译种子项。验证:PMD 实际跑内置 ruleset 无加载异常 / lint 0 error / compile 通过 / npm test 117 passing | 中间产物:static-rules.json 第一处编辑误保留 AccessorClassGeneration 块(只删了 AccessorMethodGeneration),复查 JSON 计数发现后补删 | jars/pmd/pmd-java-ruleset.xml src/rules/static-rules.json scripts/translations/pmd-1.mjs scripts/translations/pmd-2.mjs | deepseek-v4-flash | | 2026-08-26 19:05 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 仓库目录对齐赛道二 §8 成果物规范:分支 vscode-code-reviewer 合并入 main(冲突文件 docs/superpowers/specs/2026-07-10-code-reviewer-design.md 取开发分支完整版,add/add 冲突已解决);src/test 迁移至根目录 tests/(16 个测试 + fixtures/manual),36 处 import '../' → '../src/';新建 tsconfig.test.json(rootDir ".",include tests + src/types 声明文件);.vscode-test.mjs files 改 'out/tests/**/*.test.js';package.json 新增 compile:test、test 改为 compile:test && vscode-test;.gitignore 移除 src/test/;3 个中文文件名 demo-*插件实测覆盖率报告.md 重命名为 demo-*-coverage-report.md;git rm --cached 解除 vscode-code-reviewer-1.0.0.vsix 跟踪;README 追加演示视频(进行中)章节。验证:lint 0 error / compile 通过 / compile:test 通过 / npm test 116 passing | 中间产物:tsconfig.test.json 初版 include 仅 tests/**/*,编译报 stylelint-config-recommended 声明缺失(主 tsconfig include src/**/* 含 src/types 声明文件而 test 配置未含),补 include src/types/**/* 后通过 | tests/ tests/fixtures/ tests/manual/ tsconfig.test.json(新建) .vscode-test.mjs package.json .gitignore README.md data/demo-eslint/reports/demo-eslint-coverage-report.md data/demo-sqlfluff/reports/demo-sqlfluff-coverage-report.md data/demo-stylelint/reports/demo-stylelint-coverage-report.md | deepseek-v4-flash | | 2026-08-26 19:16 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 补齐 tests/ 实验报告(§8 成果物 04,coverage/ 按用户确认忽略):新建 tests/test-execution-log.md(测试执行日志:命令/环境/结果 116 passing 0 failing);tests/test-cases.md(从 16 个测试文件提取 suite/test 声明,116 条用例清单+覆盖点+统计);tests/measure/measure-review-time.mjs(提效测量脚本:内联复刻 src/rules/builtin-rules.ts 的 ESLint/Stylelint 内置配置,用 eslint/stylelint 引擎直跑 data/demo-*/src 样例计时,输出 tests/measure/results/measure-results.json);tests/measure/performance-comparison.md(提效对比骨架:测量方法+对比维度+插件侧实测数据已填 demo-eslint 6 文件 294 诊断 192.2ms / demo-stylelint 2 文件 115 诊断 2106.7ms / 合计 409 诊断 2298.9ms,人工基线留待实测)。验证:measure 脚本实测运行产出 JSON / lint 0 error(仅既有 mockDocument 2 warning)/ 主流程 npm test 116 passing 不受影响 | 中间产物:measure 脚本初版 import '../../src/rules/builtin-rules'(ESM 无法直接加载 TS 报 ERR_MODULE_NOT_FOUND)→ 改 import 编译产物 '../../out/rules/builtin-rules.js' 又因模块顶层 import vscode 脱离扩展宿主报 MODULE_NOT_FOUND → 最终改为内联规则配置(与 data/demo-eslint/run-coverage.mjs 既有模式一致);measure() 计时函数初版未 await 异步 fn,result 为 Promise 导致 result.reduce 报错,改为 async/await 后通过 | tests/test-execution-log.md(新建) tests/test-cases.md(新建) tests/measure/measure-review-time.mjs(新建) tests/measure/performance-comparison.md(新建) tests/measure/results/measure-results.json(新建) | deepseek-v4-flash | @@ -235,7 +235,13 @@ | 2026-08-27 22:12 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | A3 提效对比实验「提效后」侧数据采集:从桌面人工审核工具 manual-review-tool.html 内嵌 DATA 抽取 23 个样例入库 data/efficiency-samples/{js×8,css×5,java×6,sql×4};拷贝工具至 data/manual-review-tool.html;npm install 安装依赖;新增测量脚本 tests/measure/measure-plugin-samples.mjs(ESLint 用 js.configs.recommended+eslintExtraRules、Stylelint 用 recommended+stylelintExtraRules 与 src/rules/builtin-rules.ts 逐字一致;PMD 用 java -cp jars/pmd/lib/*;jars/pmd PmdRunner+pmd-java-ruleset.xml 与 pmd.ts 一致;SQLFluff 用 --dialect oracle+内置配置 buildBuiltinSqlfluffConfig 复刻),实测 23 文件 283 条诊断 8576.8ms(JS 120 条 95.1ms / CSS 55 条 129.3ms / Java 84 条 6610.7ms / SQL 24 条 1741.7ms),结果入库 tests/measure/results/a3-plugin-results.json(每文件耗时/诊断数/规则 ID + 分语言汇总)。验证:四语言脚本实测运行产出 JSON,样例为含缺陷样本,检出规则与预期一致(JS 的 eqeqeq/no-eval/no-debugger/no-var/no-shadow 等、CSS 的 color-no-invalid-hex/0px/厂商前缀/重复属性、Java 的空 catch/硬编码密码/System.out.println 等、SQL 的 CP01/LT01/LT02) | 中间产物:①measure() 为 async 但 PMD/SQLFluff 调用处漏 await,解构到 Promise 致 result.length 报 TypeError,改为 await measure 后通过;②SQLFluff 内置配置初版只传 --dialect oracle 未复刻内置 rules 串,后从 buildBuiltinSqlfluffConfig 逐字复刻(rules=core,AM03,… + max_line_length 80 + aliasing.length max_alias_length 30)写入临时 cfg 传 --config;③样例抽取先尝试在桌面找 data/efficiency-samples 目录(不存在),改为解析 HTML const DATA 段还原转义后落地 | data/efficiency-samples/**(新建 23 个样例) data/manual-review-tool.html(新建) tests/measure/measure-plugin-samples.mjs(新建) tests/measure/results/a3-plugin-results.json(新建) | deepseek-v4-flash | | 2026-08-27 22:17 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | A3 提效对比实验补全「人工基线」侧与对比结论:3 份人工审核记录 JSON 入库 tests/measure/results/manual-review-AI-SIM-001/002/003.json(高级/初级/中级 3 人,原始记录保留);新增聚合对比脚本 tests/measure/compare-a3.mjs 产出 tests/measure/results/a3-comparison.json;更新 tests/measure/performance-comparison.md(填入人工基线实测表、人均明细、五节对比与结论);README 效果总结由占位改为真实数据——基线 3 人均值 38.1 分钟 / 76 条 vs 插件 8.6 秒 / 283 条,整体提速约 266 倍,人工平均仅发现插件 27% 问题(漏检 73%)。验证:compare-a3.mjs 实测运行产出对比 JSON,分语言提速(JS 8500x / CSS 3400x / Java 94x / SQL 238x)与检出率(24-31%)与原始数据一致 | 中间产物:①对比脚本初版只汇总每语言均值,后补算每语言提速倍数、人工检出率(人工问题数/插件诊断数)与 3 人明细表;②README 效果总结初稿含「AI 修复采纳率」行(无实测数据),改为聚焦全量耗时/检出量/检出率/单文件耗时五项有依据指标;③人工基线均值口径先按 totalElapsedMs 直接平均,改为按语言分文件逐一汇总后平均,避免被文件数偏差干扰 | tests/measure/results/manual-review-AI-SIM-001.json(新建) tests/measure/results/manual-review-AI-SIM-002.json(新建) tests/measure/results/manual-review-AI-SIM-003.json(新建) tests/measure/compare-a3.mjs(新建) tests/measure/results/a3-comparison.json(新建) tests/measure/performance-comparison.md(更新) README.md(更新) | deepseek-v4-flash | | 2026-08-27 22:32 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 生成 tests/coverage/ 测试覆盖率报告(成果物 04 缺失项):.vscode-test.mjs 加入 srcDir:src 与 coverage 配置(reporter text-summary+html,include out/src/**/*.js,exclude out/tests 与 out/src/types,仅统计测试触达模块);package.json 新增脚本 test:coverage(compile → compile:test → vscode-test --coverage --coverage-output tests/coverage)。实测 116 passing,覆盖率:行/语句 42.58%(4915/11541)、函数 34.08%、分支 73.37%,产出 tests/coverage/index.html + src 逐文件页(2.1MB),未被 gitignore 忽略可入库。验证:复跑两次结果一致(可复现),报告路径与文件齐全 | 中间产物:①reporter 初稿含 lcov,实测该版本 test-cli 未产出 lcov.info(仅 html/text-summary 生效),收敛为 ['text-summary','html'] 后复跑确认一致;②coverage 统计口径先考虑 includeAll:true(全量含 0% 模块),与用户确认后采用仅测试触达模块(默认 false);③vscode-test 首次运行自动下载 VS Code 1.135.0(319MB 缓存于 .vscode-test/,gitignore 已排除),二次复跑走缓存 | .vscode-test.mjs(更新) package.json(更新) tests/coverage/**(新建) | deepseek-v4-flash | -| 2026-08-27 22:49 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 覆盖率补测扩展项(试点 3 项 + 扩展 5 项共 8 个新测试文件、63 条用例):tests/fix-prompt.test.ts(10)、registry.test.ts(7)、provider-chat.test.ts(11,mock global.fetch 测 OpenAI 兼容/Gemini/Claude 三协议 chat)、import-service.test.ts(7)、yaml-parser.test.ts(3)。其中 export-service 因依赖 vscode.window.showSaveDialog(UI 对话框无法在测试宿主 stub)替换为 yaml-parser(纯逻辑)。同步修复试点发现的 2 处源码缺陷:method-extractor fallback java 正则取错捕获组(match[1]→match[2] ?? match[1])、mockDocument.getText 忽略 range 参数(改为按 range 切片)。实测 179 passing / 行覆盖率 42.58%→48.24%(+5.66,分支 77.97%、函数 43.66%),覆盖率报告刷新 tests/coverage/;更新 tests/test-cases.md(16 文件 116 条 → 24 文件 179 条)与 tests/test-execution-log.md(新增覆盖率执行记录段)。验证:npm run test:coverage 全绿(Exit 0) | 中间产物:①扩展清单原含 export-service,读源码确认依赖 showSaveDialog 无法 stub,改用 yaml-parser 并在日志注明;②import-service 断言初稿断言 duplicateOf 不出现在输出,实际注释掉的行仍含原文,改为断言重复元数据仅以 # 注释形式出现;③fix-prompt 边界测试初稿断言末行为 3| c,实际代码含尾部空行,改为断言整个输出含 3| c;④mockDocument 重构为命名函数 offsetAt/positionAt 供 getText(range) 复用(对象内无法互相引用属性) | tests/jsp-extractor.test.ts(新建) tests/report.test.ts(新建) tests/method-extractor.test.ts(新建) tests/fix-prompt.test.ts(新建) tests/registry.test.ts(新建) tests/provider-chat.test.ts(新建) tests/import-service.test.ts(新建) tests/yaml-parser.test.ts(新建) src/scope/method-extractor.ts(修复) src/utils/mockDocument.ts(修复) tests/coverage/**(刷新) tests/test-cases.md(更新) tests/test-execution-log.md(更新) | deepseek-v4-flash | +| 2026-08-27 22:49 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 覆盖率补测扩展项(试点 3 项 + 扩展 5 项共 8 个新测试文件、63 条用例):tests/fix-prompt.test.ts(10)、registry.test.ts(7)、provider-chat.test.ts(11,mock global.fetch 测 OpenAI 兼容/Gemini/Claude 三协议 chat)、import-service.test.ts(7)、yaml-parser.test.ts(3)。其中 export-service 因依赖 vscode.window.showSaveDialog(UI 对话框无法在测试宿主 stub)替换为 yaml-parser(纯逻辑)。同步修复试点发现的 2 处源码缺陷:method-extractor fallback java 正则取错捕获组(match[1]→match[2] ?? match[1])、mockDocument.getText 忽略 range 参数(改为按 range 切片)。实测 179 passing / 行覆盖率 42.58%→48.24%(+5.66,分支 77.97%、函数 43.66%),覆盖率报告刷新 tests/coverage/;更新 tests/test-cases.md(16 文件 116 条 → 24 文件 179 条)与 tests/test-execution-log.md(新增覆盖率执行记录段)。验证:npm run test:coverage 全绿(Exit 0) | 中间产物:①扩展清单原含 export-service,读源码确认依赖 showSaveDialog 无法 stub,改用 yaml-parser 并在日志注明;②import-service 断言初稿断言 duplicateOf 不出现在输出,实际注释掉的行仍含原文,改为断言重复元数据仅以 # 注释形式出现;③fix-prompt 边界测试初稿断言末行为 3| c,实际代码含尾部空行,改为断言整个输出含 3| c;④mockDocument 重构为命名函数 offsetAt/positionAt 供 getText(range) 复用(对象内无法互相引用属性) | | 2026-08-29 11:03 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 修复审查面板「重新审核」按钮失效:面板聚焦时 activeTextEditor 为空导致报「请先打开一个文件」。webview handleMessage 的 case 'rerun' 改为携带 currentReport.filePath;codeReviewer.review 命令改为按 activeTextEditor.document → workspace.textDocuments 匹配 fsPath → openTextDocument 三级解析文档,不再依赖编辑器焦点,始终审核报告所属文件。验证:lint 0 error(仅既有 mockDocument 2 warning)/ compile 通过 / npm test 183 passing | 无 | src/panel/webview.ts src/activation/commands.ts | deepseek-v4-flash | | 2026-08-29 11:23 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码 实现 | 评审整改 P0 文档包(针对第 12 次评审 79 分三大失分项):新建 measurement/ 测量协议入口(baseline.md 人工基线报告 + timing-log.md 计时日志与可重演命令,命中评审探针「measurement 目录/baseline.md/timing-log/可重演命令」四要素,数值全部从 tests/measure/results/*.json 真实转录);新建 docs/demo-storyboard.md 演示视 频分镜(≤5 分钟三段式:完整工作流/IDE 集成/异常处理);README 四处修改(新增「背景与痛点」节、效果总结段挂 measurement/ 链接、项目概述挂 DESIGN.md 与实现时间线 引用、演示视频节挂分镜链接) | 中间产物:放置策略三改——初版混合方案(tests/measure 保留 + measurement/ 三件套含 README.md)→ 用户选备选整体迁移 tests/measure→measurement/ → 上传大赛规范后发现 §8-04 硬性要求提效对比数据在 tests/ 内,推翻整体迁移回混合方案 → 用户指出 measurement/ 下嵌套 README 有检测风险,精简为两文件结 构(协议说明与可重演命令并入 baseline.md/timing-log.md 正文) | measurement/baseline.md(新建) measurement/timing-log.md(新建) docs/demo-storyboard.md(新建) README.md(修改) | GLM-5.3 | | 2026-08-29 12:37 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码 实现 → ⑥ 审查验证 | AI 调用稳定性增强(评审「稳定性与易用性 12/15」丢分点:缺少显式重试机制 + AI 调用异常统一兜底):① providers/base.ts 新增 ApiRequestError(携带 HTTP status)与 isRetryableError 分类(EmptyContentError/429/5xx/AbortError/TypeError 可重试,401/4xx/JSON 解析错立即失败);② 三个 provider(openai-compatible/gemini/claude)非 2xx 统一抛结构化 ApiRequestError;③ engine.ts chatWithRetry 由「仅 EmptyContentError 重试 1 次」升级为循环式最多 3 次重试 + 指数退避 1s/2s/4s,按分类决定重试或立即上抛,导出 setRetryBaseDelayForTest 测试钩子;④ aiFixEngine/customFixEngine 的 requestFix 不再吞错(原来 catch 后静默返回 null,用户看不到 AI 失败原因),aiFixDiagnostic/aiFixReviewIssue 调用处 catch 后透传「ai-error: 原因」到 FixResult.message,复用 commands.ts 既有 t('fix.aiFailed') 通知管道;⑤ 扩展 tests/ai-empty-response.test.ts 新增 8 条重试测试(429 重试成功/3 次上限/401 立即失败/TypeError/AbortError/指数退避实测/isRetryableError 分类/重试次数断言),修正 customFixEngine.test.ts 一处测试名。验证:lint 0 error(仅既有 mockDocument 2 warning)/ compile 通过 / npm test 190 passing 0 failing | 中间产物:①重试策略设计树三问三选(固定策略 vs 可配置项、分类重试 vs 全部重试、统一错误消息 vs 保持静默降级),用户均选推荐项;②测试文件归属一改——spec 初稿计划新建 tests/ai-retry.test.ts,编码时发现 ai-empty-response.test.ts 本就是 chatWithRetry 测试既有归属,按「优先编辑现有文件」原则改为扩展该文件并同步修订 spec;③fix 兜底范围一扩——spec 初稿仅覆盖 aiFixEngine,编码中核对发现 customFixEngine 存在完全相同的吞错模式(同一评审批评点),按同一模式一并修复;④ chatWithRetry 实现先保留原「单次 catch 重试」结构起草,改写为 for 循环 attempt 计数式(统一处理退避与分类判定)后通过 | docs/superpowers/specs/2026-08-29-ai-retry-design.md(新建) src/ai/providers/base.ts(修改) src/ai/providers/openai-compatible.ts(修改) src/ai/providers/gemini.ts(修改) src/ai/providers/claude.ts(修改) src/ai/engine.ts(修改) src/fix/aiFixEngine.ts(修改) src/fix/customFixEngine.ts(修改) tests/ai-empty-response.test.ts(扩展) tests/customFixEngine.test.ts(更新) | GLM-5.3 | +| 2026-09-06 12:17 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | galaxy-team-coding-conventions.xlsx 自定义规则导入测试专项(用户提供的真实世界测试文件,双 Sheet:项目简介+编码约定 10 条规则、无标准表头、含干扰段落):①复制素材至 tests/fixtures/(自动化)与 data/(人工验证,用户指定路径);②excel-converter.ts 导出 buildMarkdownTable 并提取纯函数 renderWorkbookToMarkdown(convert() 改为调用,行为不变);③修复编码中发现的真实 Bug——buildMarkdownTable 列键仅取 rows[0],首行非表头的真实 Excel 后续列内容全部丢失(实测 galaxy 文件 console.log/===/var/SQL 规则正文不在渲染结果,AI 只收到序号列),改为全行键并集后内容完整;④新增 tests/excel-converter.test.ts 7 条用例(格式单测/缺失填充/列键并集/真实文件双 Sheet 渲染/内容忠实性/空表跳过/全空返回 null);⑤恢复丢失的 tests/webview-escape.test.ts(从 out/ 编译产物反推,4 条 XSS 转义用例),连带修复 src/panel/webview.ts esc 未导出与 > 实体错误(> 误替换为 ",丢失 WIP 编译产物掩盖的显示 Bug);⑥清理 out/src 两个孤儿产物(csp.js 无源码、webview.js 为 8-28 丢失 WIP 残迹且缺 8-29 rerun 修复);⑦新建 tests/manual/import-verification.md 人工验证清单(AI 转换质量/预览交互/落盘联动/异常路径四组检查点);⑧更新 docs/demo-storyboard.md 插入「工作流④:自定义规则导入」分镜(3:40–4:05)并压缩后续段保持 ≤5 分钟;⑨test-cases.md 全面校正至 26 文件 197 条(补 ai-empty-response 7 条缺失行、import-dedup 计数 25→24、新增两节、全表重排序号 1–197)。验证:lint 0 error(仅既有 mockDocument 2 warning)/ compile 通过 / npm test 197 passing 0 failing | 中间产物:①首个测试用例 skips empty sheets 的 rules 表只有表头无数据行,sheet_to_json 返回空数组导致断言失败,补数据行后通过;②Bug 修复方案曾考虑按 __EMPTY 键名重命名列头,最终保留 SheetJS 原生命名(prompt 已声明列名不固定从语义推断);③幽灵测试处置两轮——先发现 out/tests/webview-escape.test.js 无源码,追问后用户选恢复源文件而非删除产物;④恢复过程中发现 tsc 不重编译 webview.js 的表象,实验(删产物重编译)+ 双 tsconfig 比对定位真相:tsconfig.test.json rootDir=. 仅编译 tests/ 传递引用的 src,webview.ts 无测试引用故从未重新生成,8-28 WIP 产物得以残留并被幽灵测试引用 | src/rules/converters/excel-converter.ts(修改) src/panel/webview.ts(修改) tests/excel-converter.test.ts(新建) tests/webview-escape.test.ts(恢复) tests/fixtures/galaxy-team-coding-conventions.xlsx(新建) data/galaxy-team-coding-conventions.xlsx(新建) tests/manual/import-verification.md(新建) tests/test-cases.md(更新) docs/demo-storyboard.md(更新) | GLM-5.3 | +| 2026-09-06 13:44 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | galaxy 导入手动验证归档:新建 data/import-verification/,移入导入素材 galaxy-team-coding-conventions.xlsx(自 data/ 根)与导入结果 galaxy-team-coding-conventions.yaml(自 .code-review/rules/,galaxy 规则随之退出激活目录);删除 tests/manual/import-verification.md(用户不需要,改以结果报告承载);生成 data/import-verification/result-report.md(验证信息/素材特征/两轮验证过程/结果统计 5 exact+1 overlap+4 none/A·B·C 三组检查点核对/duplicateOf 五条真实性核实/已知观察/结论通过,按用户要求不含人名);docs/demo-storyboard.md 导入素材路径同步更新为 data/import-verification/。核对:新文件夹三件套齐全、data 根无重复 xlsx、rules 目录仅剩 coding-conventions+security-rules、tests/manual 恢复纯样例、报告无人名字段。无代码变更,自动化测试不受影响(其依赖 tests/fixtures/ 副本未动) | 无 | data/import-verification/result-report.md(新建) data/import-verification/galaxy-team-coding-conventions.xlsx(移入) data/import-verification/galaxy-team-coding-conventions.yaml(移入) tests/manual/import-verification.md(删除) docs/demo-storyboard.md(修改) | GLM-5.3 | +| 2026-09-06 22:25 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 标准格式导入全量手动验证(8 种格式 × 同一 12 条规则基准):素材 8 文件自 F:\XunHeCode\演示资料 复制入 data/import-verification/standard-formats/;用户逐轮手动导入(规则名 standard-rules-<格式>),AI 逐轮核对落盘并归档至 data/import-verification/results/(每轮移出激活目录避免跨格式 id 不一致双报)。结果 8/8 通过:yaml 逐字节保真;md/txt/docx AI 转换 12 条全对但每轮 id 各异(语义等价);pptx 唯一降级——officeparser 碎片化提取致 5 处 languages + 1 处 excludeLanguages 丢失(AI 按『严禁猜测留空更安全』设计降级,TODO 规则将误报 SQL);xlsx 单表/5 表 id 收敛至与基准完全一致且两轮落盘逐字节一致(多表合并链路零干扰);template 路径严格校验精准命中自带 4 行测试数据(缺id 占位提示/非法 severity critical/空描述/空行跳过)+ 附加行 no-console-log 第 4 条 exact。7 轮 AI 去重零波动且指向全部核实真实。总报告 data/import-verification/standard-formats/result-report.md(无人名)。无代码变更;同日追加目录重组(用户发起,为后续不规则内容测试分类防覆盖):import-verification 下按场景重排为 01-galaxy-nonstandard(galaxy 素材/结果/报告三件套移入)/ 02-standard-formats(standard-formats 重命名,顶层 results/ 移入其内)/ 03-irregular-content(预留不规则内容场景,含空 results/),新增 guide.md 导航(三场景说明 + 规则命名约定 standard-rules-<格式> 与 irregular-<格式> 前缀错开防覆盖 + 归档流程;初名 目录说明.md,用户要求改英文名,且刻意避开 README.md——measurement/ 时期已有嵌套 README 检测风险的教训),同步修正 4 处路径引用(demo-storyboard.md 导入素材路径、两份 result-report.md 内部素材/结果/关联路径) | 中间产物:报告初稿曾计划并入 galaxy 报告,因素材/结论独立改为分置两份;pptx 轮一度误判需修 prompt,核对 prompt-builder 内置 none 示例(console 敏感信息案例)后定性为设计内安全降级而非缺陷 | data/import-verification/standard-formats/(素材8件+result-report.md) data/import-verification/results/(8件归档) data/import-verification/01-galaxy-nonstandard/(galaxy三件套移入) data/import-verification/02-standard-formats/(standard-formats重命名+results移入) data/import-verification/03-irregular-content/(预留含results) data/import-verification/guide.md(新建,初名目录说明.md后改英文) docs/demo-storyboard.md(引用修正) | GLM-5.3-Flash | +| 2026-09-07 21:05 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 不规则内容导入全量手动验证(7 种格式 × 同一 12 条规则基准,重噪声嵌入:项目背景/团队介绍/会议纪要/部署流程/版本历史/反面正面代码示例/wiki 链接/Checklist):素材 7 文件由用户放入 data/import-verification/03-irregular-content/(无 template 轮,严格校验路径不适配不规则内容);用户逐轮手动导入(规则名 irregular-<格式>),AI 逐轮核对落盘并归档至 03-irregular-content/results/。结果 7/7 通过:噪声过滤零失守(背景/纪要/版本历史等未成规则)、反面示例陷阱零触发(Admin@123456/eval 示例未被生成规则)、叙事与规则正确分离、severity 全对、languages 除 yaml 直读外全对。三项跨场景结论:①pptx 降级定性修正——本场景 pptx(45KB 重噪声)languages 零丢失,与场景②丢 6 处、旧 rules_ppt.yaml 大面积缺失合并,证明是高方差而非必然缺陷(02 报告结论据此修正);②去重判断方差实锤——no-hardcoded-credentials 在 xlsx 轮判 overlap(保留,与 custom/no-hardcoded-secret 并存双报)multisheet 轮回归 exact,且 docx 轮 avoid-magic-numbers(id 前缀完全不同)仍被精准标为 custom/no-magic-numbers exact,去重语义性最直接验证;③表格类稳定性跨场景复现——xlsx/multisheet id 再次全对齐基准,multisheet 落盘与场景② multisheet 逐字节一致(fc 0 差异,源文件 15KB 标准 vs 24KB 重噪声完全不同),02-xlsx≡02-multisheet≡03-multisheet 链条成立。自由文本四轮 id 继续逐轮漂移(语义等价)。总报告 data/import-verification/03-irregular-content/result-report.md(无人名);guide.md 场景③状态更新为已完成。无代码变更 | 中间产物:①pptx 轮一度预期复现场景②降级,实测零丢失后推翻原假设并修正定性;②xlsx 轮 overlap 判定曾商榷是否要求用户人工改注,按『AI 方差属设计内弹性、预览人工复核为设计补偿』定性保留原样仅记录 | data/import-verification/03-irregular-content/(素材7件+results/7件归档+result-report.md) data/import-verification/guide.md(状态更新) | GLM-5.3-Flash | +| 2026-09-07 21:19 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 场景② pptx 同文件重测与根因终审(一次调查两阶段,原分两条记录现合并):阶段一·重测复现——用户重导 standard-rules-pptx(归档为 results/standard-rules-pptx-retest.yaml,-retest 后缀防同名冲突),12 条全检出、severity 全对、去重 3 exact 同构;语言留空模式与首测逐字段完全复现(同 6 处留空、类型注解规则同保留 [typescript]、TODO 同无 excludeLanguages),而同期 id 照例漂移(8 条中 7 条不同)——id 生成随机属 AI 层、语言留空确定属文件因素,排除 AI 随机性。阶段二·根因终审——用户提出关键假设『02 pptx 文件中并没有包含语言等信息』,经与插件相同的 officeparser 调用链(OfficeParser.parseOffice→ast.toText)提取两份 pptx 比对证实:02 源文件全文 950 字符不含任何『适用语言/排除语言』标注(severity 有 [error]/[warning]/[info] 前缀,语言没有),03 源文件含成组『严重级别 | 语言』标注及『排除语言:sql』。终案:语言字段差异源于源文件内容差异,AI 两轮行为均正确(源有的正确映射含 excludeLanguages:[sql],源无的按『严禁猜测留空更安全』留空,语义可推的一条正确推断 [typescript]),不存在降级或丢失——源文件没有的数据不能叫丢失。定性演进三版全记录:格式缺陷(02 初稿)→高方差(03 初稿)→文件级提取确定性(重测阶段,被后证推翻)→源文件内容差异(终稿)。两份报告按终稿修正(02 发现 1 重写+结论改写、03 发现 2 重写+结论改写),制作 pptx 素材需语言限定须在幻灯片显式标注。无代码变更 | 中间产物:①定性经三版演进(格式缺陷→高方差→提取层丢失)才到终案,前两版均未实际检验提取文本——教训:假设提取层有损前应先比对提取输出与源内容;②重测归档命名用 -retest 后缀避免与首测同名冲突(防覆盖约定) | data/import-verification/02-standard-formats/results/standard-rules-pptx-retest.yaml(归档) data/import-verification/02-standard-formats/result-report.md(更新×2) data/import-verification/03-irregular-content/result-report.md(更新×2) | GLM-5.3-Flash | +| 2026-09-07 22:44 | ① 用户提出 → ② 需求澄清 → ③ 方案设计 → ④ 人类审批 → ⑤ 编码实现 → ⑥ 审查验证 | 自定义规则审查联动验证(演示定位:团队编码风格/习惯类规则,目标『覆盖全』——测试代码对静态分析与通用 AI 审查双重干净,仅含团队约定违规):新建 data/custom-rule-demo/(脱离 import-verification 场景体系,用户指定);设计 5 条纯团队约定规则(查询方法前缀/DTO 后缀/Result 包装/@author 标注/中文日志)+ TeamStyleService.java 测试代码(5 处无痕埋点,不带提示注释防 AI 照抄);基线经 3 轮迭代收敛(11→4→6,PMD 清零、无 error 级、均为开放性设计 nitpick),迭代中两次设计修正——金额 BigDecimal 规则被通用 AI 原生命中(真实最佳实践不配当团队约定)换为 @author 标注规则,类名 TeamStyleDemo→TeamStyleService 消除 R1『Service 层』歧义;用户导入 team-style-rules(5 条零去重保留)后复审:自定义规则 6 条命中(5/5 规则全覆盖,require-author-tag 双命中系埋点遗漏被规则抓出)、行号全部精准、message 逐字来自规则文件、与 4 条通用 AI 建议独立分区零混淆。关键实证:通用 AI 建议逐轮波动(11→4→6→4)vs 团队规则命中确定精准——『开放性建议 vs 确定性约定检查』为演示核心叙事;通用 AI 与团队规则边界实测划清(金额 BigDecimal 被通用 AI 捕获、@author/中文日志零感知)。基线 7 条规则恢复激活(与 5 条团队规则共存无冲突);结果报告 data/custom-rule-demo/result-report.md(无人名)。无代码变更 | 中间产物:①『AI 零建议』基线目标对非平凡代码不可达,改为『无 error 级+建议均为开放性 nitpick』通过标准;②R4 金额规则被通用 AI 原生捕获后曾考虑构造器注入等替代,最终选 @author(纯约定零感知);③OrderController 埋点漏加 @author 反被规则命中,转化为规则执行力佐证 | data/custom-rule-demo/team-style-rules.yaml(新建) data/custom-rule-demo/TeamStyleService.java(新建,迭代3版) data/custom-rule-demo/result-report.md(新建) .code-review/rules-hold/(基线规则暂存与恢复) | GLM-5.3-Flash | diff --git a/docs/demo-storyboard.md b/docs/demo-storyboard.md index 19a54c1..d923117 100644 --- a/docs/demo-storyboard.md +++ b/docs/demo-storyboard.md @@ -10,6 +10,7 @@ | 录屏工具 | OBS Studio(免费)或 VS Code 内置屏幕录制 | | 分辨率 | 1920×1080,窗口聚焦 VS Code | | 示例工程 | `data/efficiency-samples/`(含缺陷的多语言样例,JS/CSS/Java/SQL 混合) | +| 导入素材 | `data/import-verification/01-galaxy-nonstandard/galaxy-team-coding-conventions.xlsx`(自然语言团队编码约定表,用于自定义规则 AI 导入演示) | | 时长 | ≤5 分钟,按分镜控制 | | 语速 | 关键操作配一句口播或字幕说明,不堆话 | @@ -21,13 +22,14 @@ | 工作流①:静态审查 | 0:20–1:50 | 一键审查(`Ctrl+Shift+R`)→ 编辑器波浪线标记 → 「问题」面板结果 → 树形审查面板按严重级分组 | 编辑器 → 问题面板 → Webview 审查面板三个视角切换;圈出英文机器诊断原文 | | 工作流②:AI 审查 | 1:50–3:00 | 触发 AI 深度审查:英文诊断翻译为中文 + 修复建议;挖掘语义级问题(安全/逻辑/性能/设计) | 高亮 AI 翻译条目与静态通道的合并展示;点开一条 AI 审查详情 | | 工作流③:自动修复 | 3:00–3:40 | 单条 AI 修复 → diff 预览两步确认 → 写入自动保存;演示全部修复与按来源撤销 | diff 预览界面特写(两步确认按钮);修复后问题数下降 | -| IDE 集成 | 3:40–4:20 | 方法级 CodeLens 审查按钮;保存自动分析;设置面板配置 AI Provider;导出 Markdown 审查报告 | 四个功能各 8–10 秒快切;CodeLens 按钮悬停特写 | -| 异常处理 | 4:20–4:50 | 断网或无效 API Key 场景:AI 通道优雅降级(面板 degraded 状态),静态通道独立可用不阻塞 | 面板降级状态标识特写 + 静态诊断仍正常产出 | -| 收尾 | 4:50–5:00 | 效果数据卡:23 文件 8.6 秒 / 人工 38.1 分钟 / 提速约 266 倍 / 检出率 27%→100%;仓库地址 | 数据卡片定格 5 秒(数据源:`measurement/timing-log.md`) | +| 工作流④:自定义规则导入 | 3:40–4:05 | 设置视图「自定义规则」导入 galaxy-team-coding-conventions.xlsx(自然语言团队约定表)→ AI 转换 → 预览面板确认规则 | 文件选择对话框 → 转换进度通知 → 预览面板规则卡片滚动;口播强调「项目简介、修订记录等干扰内容被自动过滤」 | +| IDE 集成 | 4:05–4:35 | 方法级 CodeLens 审查按钮;保存自动分析;设置面板配置 AI Provider;导出 Markdown 审查报告 | 四个功能各 7–8 秒快切;CodeLens 按钮悬停特写 | +| 异常处理 | 4:35–4:55 | 断网或无效 API Key 场景:AI 通道优雅降级(面板 degraded 状态),静态通道独立可用不阻塞 | 面板降级状态标识特写 + 静态诊断仍正常产出 | +| 收尾 | 4:55–5:00 | 效果数据卡:23 文件 8.6 秒 / 人工 38.1 分钟 / 提速约 266 倍 / 检出率 27%→100%;仓库地址 | 数据卡片定格 5 秒(数据源:`measurement/timing-log.md`) | ## 录制后自查 -- [ ] 三个规范要素均出现:完整工作流(段 2–4)、IDE 集成效果(段 5)、异常处理(段 6) +- [ ] 三个规范要素均出现:完整工作流(段 2–5)、IDE 集成效果(段 6)、异常处理(段 7) - [ ] 总时长 ≤5 分钟 - [ ] 文件命名 `demo.mp4`(ASCII 小写,无中文无空格),置于 `docs/` - [ ] 单文件 ≤50MB(超限时压缩分辨率/帧率) diff --git a/tests/test-cases.md b/tests/test-cases.md index 3cce6e4..c47a030 100644 --- a/tests/test-cases.md +++ b/tests/test-cases.md @@ -1,6 +1,6 @@ # 测试用例清单 -来源:`tests/*.test.ts` 中 `suite()` / `test()` 声明。共 **24 个测试文件、179 条用例**。 +来源:`tests/*.test.ts` 中 `suite()` / `test()` 声明。共 **26 个测试文件、197 条用例**。 ## 1. adapter.test.ts — Adapter Tests(6) @@ -13,7 +13,7 @@ | 5 | ESLintAdapter surfaces \8 escape as eslint:parse-error | 非法转义解析错误上报 | | 6 | ESLintAdapter parses JSX in .js without parse error | JSX 语法解析 | -## 2. ai-empty-response.test.ts — AI Empty Response Handling(6) +## 2. ai-empty-response.test.ts — AI Empty Response Handling(13) | # | 用例 | 覆盖点 | |---|---|---| @@ -21,300 +21,329 @@ | 8 | parseJsonResponse parses valid JSON normally | 正常 JSON 解析 | | 9 | chatWithRetry retries once on EmptyContentError | 空内容自动重试 | | 10 | chatWithRetry propagates error when retry also returns empty | 重试仍空则抛错 | -| 11 | chatWithRetry does not retry on non-empty-content errors | 非空内容错误不重试 | -| 12 | openai-compatible reports max_tokens truncation clearly | token 截断提示 | +| 11 | chatWithRetry does not retry on non-retryable errors | 非重试类错误不重试 | +| 12 | chatWithRetry retries on 429 and succeeds | 429 重试成功 | +| 13 | chatWithRetry retries 429 up to 3 times then throws | 429 重试上限 | +| 14 | chatWithRetry fails immediately on 401 | 401 立即失败 | +| 15 | chatWithRetry retries on network error (TypeError) | 网络错误重试 | +| 16 | chatWithRetry retries on timeout (AbortError) | 超时重试 | +| 17 | chatWithRetry backoff is exponential | 指数退避 | +| 18 | isRetryableError classifies error types | 错误分类 | +| 19 | openai-compatible reports max_tokens truncation clearly | token 截断提示 | ## 3. ai-fix-engine.test.ts — AI FixEngine Tests(4) | # | 用例 | 覆盖点 | |---|---|---| -| 13 | aiFixDiagnostic applies AI fix and converges | AI 修复收敛 | -| 14 | aiFixDiagnostic returns ai-match-failed when originalText not found | 原文未匹配 | -| 15 | aiFixDiagnostic returns ai-no-fix when AI provides empty fix | AI 无修复 | -| 16 | aiFixDiagnostic retries until issue resolved within maxIterations | 迭代上限内收敛 | +| 20 | aiFixDiagnostic applies AI fix and converges | AI 修复收敛 | +| 21 | aiFixDiagnostic returns ai-match-failed when originalText not found | 原文未匹配 | +| 22 | aiFixDiagnostic returns ai-no-fix when AI provides empty fix | AI 无修复 | +| 23 | aiFixDiagnostic retries until issue resolved within maxIterations | 迭代上限内收敛 | ## 4. config.test.ts — Config Tests(4) | # | 用例 | 覆盖点 | |---|---|---| -| 17 | getAIConfig returns default values | AI 配置默认值 | -| 18 | AI individual getters return defaults | 单项配置 getter | -| 19 | getLinterForLanguage returns configured linter | 语言→linter 映射 | -| 20 | getFixMaxIterations returns default | 修复迭代默认值 | +| 24 | getAIConfig returns default values | AI 配置默认值 | +| 25 | AI individual getters return defaults | 单项配置 getter | +| 26 | getLinterForLanguage returns configured linter | 语言→linter 映射 | +| 27 | getFixMaxIterations returns default | 修复迭代默认值 | ## 5. customFixEngine.test.ts — Custom FixEngine Tests(5) | # | 用例 | 覆盖点 | |---|---|---| -| 21 | aiFixReviewIssue applies AI fix and converges after verify | 自定义规则 AI 修复收敛 | -| 22 | aiFixReviewIssue returns ai-match-failed when originalText not found | 原文未匹配 | -| 23 | aiFixReviewIssue retries until verify passes within maxIterations | 验证驱动重试 | -| 24 | aiFixReviewIssue accepts last fix when verify never passes | 验证不过时接受最后修复 | -| 25 | aiFixReviewIssue retries empty fix once then fails with ai-no-fix | 空修复重试一次后失败 | +| 28 | aiFixReviewIssue applies AI fix and converges after verify | 自定义规则 AI 修复收敛 | +| 29 | aiFixReviewIssue returns ai-match-failed when originalText not found | 原文未匹配 | +| 30 | aiFixReviewIssue retries until verify passes within maxIterations | 验证驱动重试 | +| 31 | aiFixReviewIssue accepts last fix when verify never passes | 验证不过时接受最后修复 | +| 32 | aiFixReviewIssue retries empty fix once then fails with ai-no-fix | 空修复重试一次后失败 | ## 6. dedup-prompt.test.ts — Dedup Prompt Tests(3) | # | 用例 | 覆盖点 | |---|---|---| -| 26 | buildDedupOnlyPrompt 同时提供静态规则与自定义规则 | 去重 prompt 组装 | -| 27 | 自定义规则时包含静态规则 | 去重 prompt 规则合并 | -| 28 | buildKnownRulesSection 生成的规则包含全部 | 已知规则段完整性 | +| 33 | buildDedupOnlyPrompt 同时提供静态规则与自定义规则 | 去重 prompt 组装 | +| 34 | 自定义规则时包含静态规则 | 去重 prompt 规则合并 | +| 35 | buildKnownRulesSection 生成的规则包含全部 | 已知规则段完整性 | ## 7. diagnostics.test.ts — DiagnosticMarkers Tests(6) | # | 用例 | 覆盖点 | |---|---|---| -| 29 | toVscodeDiagnostics maps severity correctly | 严重级别映射 | -| 30 | toVscodeDiagnostics preserves range | 范围保留 | -| 31 | toVscodeDiagnostics prefixes message with plugin and linter | 消息前缀 | -| 32 | toVscodeDiagnostics handles ruleId without linter prefix | 无前缀 ruleId | -| 33 | toVscodeDiagnostics sets source and code for quick fix hover | hover 修复来源/代码 | -| 34 | toVscodeDiagnostics returns empty array for empty input | 空输入 | +| 36 | toVscodeDiagnostics maps severity correctly | 严重级别映射 | +| 37 | toVscodeDiagnostics preserves range | 范围保留 | +| 38 | toVscodeDiagnostics prefixes message with plugin and linter | 消息前缀 | +| 39 | toVscodeDiagnostics handles ruleId without linter prefix | 无前缀 ruleId | +| 40 | toVscodeDiagnostics sets source and code for quick fix hover | hover 修复来源/代码 | +| 41 | toVscodeDiagnostics returns empty array for empty input | 空输入 | ## 8. fixEngine.test.ts — FixEngine Tests(5) | # | 用例 | 覆盖点 | |---|---|---| -| 35 | ESLint adapter attaches fix object for autofixable issues | 可自动修复诊断挂 fix | -| 36 | fixDiagnostic multi-round convergence produces applied fixes | 多轮修复收敛 | -| 37 | fixDiagnostic returns not-autofixable for non-fixable rule | 不可修复规则 | -| 38 | fixDiagnostic no-change returns no-change | 无变化场景 | -| 39 | fixDiagnostic fixes only the targeted issue, not adjacent same-rule instance | 定点修复不误伤相邻同类 | +| 42 | ESLint adapter attaches fix object for autofixable issues | 可自动修复诊断挂 fix | +| 43 | fixDiagnostic multi-round convergence produces applied fixes | 多轮修复收敛 | +| 44 | fixDiagnostic returns not-autofixable for non-fixable rule | 不可修复规则 | +| 45 | fixDiagnostic no-change returns no-change | 无变化场景 | +| 46 | fixDiagnostic fixes only the targeted issue, not adjacent same-rule instance | 定点修复不误伤相邻同类 | ## 9. fixSession.test.ts — FixSession Tests(6) | # | 用例 | 覆盖点 | |---|---|---| -| 40 | add/get/has roundtrip | 会话读写 | -| 41 | get returns undefined for missing key | 缺失键 | -| 42 | getEntries filters per uri | 按 uri 过滤 | -| 43 | clear removes entries for uri only | 按 uri 清理 | -| 44 | recordFixes merges multi-round fixes under same key | 多轮修复合并 | -| 45 | undo restores original text via workspace edit | 撤销恢复原文 | +| 47 | add/get/has roundtrip | 会话读写 | +| 48 | get returns undefined for missing key | 缺失键 | +| 49 | getEntries filters per uri | 按 uri 过滤 | +| 50 | clear removes entries for uri only | 按 uri 清理 | +| 51 | recordFixes merges multi-round fixes under same key | 多轮修复合并 | +| 52 | undo restores original text via workspace edit | 撤销恢复原文 | -## 10. import-dedup.test.ts — Import Dedup Tests(25) +## 10. import-dedup.test.ts — Import Dedup Tests(24) | # | 用例 | 覆盖点 | |---|---|---| -| 46 | 重复规则:全局检查并标注 | 全局重复检查 | -| 47 | 全局 exact:全部标注 | exact 去重 | -| 48 | 全局 overlap:全部检查并标注 | overlap 去重 | -| 49 | 跨规则 exact 标注(overlap 归 none) | 跨规则 exact 归属 | -| 50 | 用户指定 exact 后取消标注 | 用户决策 exact | -| 51 | 用户标注 overlap 将标注加 # 前缀 | overlap 标注头 | -| 52 | 用户标注 none 加 # 前缀 | none 标注头 | -| 53 | 已标注 duplicateLevel/duplicateOf/duplicateReason 剔出标注 | 已标注剔除 | -| 54 | 标注规则 duplicateReason 标注头回填原由 | 原因回填 | -| 55 | 编辑 description 确认 YAML 使用该值 | description 编辑 | -| 56 | 编辑 severity 确认 YAML 使用该 severity | severity 编辑 | -| 57 | 编辑 languages 确认 YAML 有 languages | languages 编辑 | -| 58 | 编辑切换为标注、标注转为编辑值 | 编辑/标注互转 | -| 59 | 无编辑时保留原始 yamlContent | 原始内容保留 | -| 60 | severity 缺失默认为 warning | severity 默认 | -| 61 | severity 非法值默认为 warning | severity 兜底 | -| 62 | id 缺失生成 rule-N | id 自动命名 | -| 63 | 多个 id 缺失依次 rule-1, rule-2... | 递增命名 | -| 64 | description 缺失时使用 message(中文存在) | 双语回退 | -| 65 | message 缺失时使用 description(中文存在) | 双语回退 | -| 66 | description 与 message 同时缺失时兜底 | 全缺失兜底 | -| 67 | 重复规则的重复校验回归 | 去重回归 | -| 68 | id 带引号、字段带引号保留 id | 引号 id | -| 69 | scalar 字段带引号、保留引号 | 引号 scalar | +| 53 | 重复规则:全局检查并标注 | 全局重复检查 | +| 54 | 全局 exact:全部标注 | exact 去重 | +| 55 | 全局 overlap:全部检查并标注 | overlap 去重 | +| 56 | 跨规则 exact 标注(overlap 归 none) | 跨规则 exact 归属 | +| 57 | 用户指定 exact 后取消标注 | 用户决策 exact | +| 58 | 用户标注 overlap 将标注加 # 前缀 | overlap 标注头 | +| 59 | 用户标注 none 加 # 前缀 | none 标注头 | +| 60 | 已标注 duplicateLevel/duplicateOf/duplicateReason 剔出标注 | 已标注剔除 | +| 61 | 标注规则 duplicateReason 标注头回填原由 | 原因回填 | +| 62 | 编辑 description 确认 YAML 使用该值 | description 编辑 | +| 63 | 编辑 severity 确认 YAML 使用该 severity | severity 编辑 | +| 64 | 编辑 languages 确认 YAML 有 languages | languages 编辑 | +| 65 | 编辑切换为标注、标注转为编辑值 | 编辑/标注互转 | +| 66 | 无编辑时保留原始 yamlContent | 原始内容保留 | +| 67 | severity 缺失默认为 warning | severity 默认 | +| 68 | severity 非法值默认为 warning | severity 兜底 | +| 69 | id 缺失生成 rule-N | id 自动命名 | +| 70 | 多个 id 缺失依次 rule-1, rule-2... | 递增命名 | +| 71 | description 缺失时使用 message(中文存在) | 双语回退 | +| 72 | message 缺失时使用 description(中文存在) | 双语回退 | +| 73 | description 与 message 同时缺失时兜底 | 全缺失兜底 | +| 74 | 重复规则的重复校验回归 | 去重回归 | +| 75 | id 带引号、字段带引号保留 id | 引号 id | +| 76 | scalar 字段带引号、保留引号 | 引号 scalar | ## 11. merger.test.ts — Merger Tests(12) | # | 用例 | 覆盖点 | |---|---|---| -| 70 | mergeResults counts correctly | 计数正确 | -| 71 | mergeResults marks degraded when AI fails | AI 失败降级 | -| 72 | mergeResults sorts diagnostics by severity then line | 排序 | -| 73 | mergeResults marks fixable only diagnostics with fix object | 可修复标记 | -| 74 | mergeResults converts aiFindings line to 0-based | 行号 0 基化 | -| 75 | mergeResults pairs translations by originalRuleId not index | 按规则 id 配对翻译 | -| 76 | mergeResults handles duplicate ruleId translations in order | 重复 id 有序 | -| 77 | mergeResults matches translations by normalized ruleId when prefix missing | 缺前缀归一化匹配 | -| 78 | mergeResults matches translations by normalized ruleId with slash variant | 斜杠变体匹配 | -| 79 | mergeResults prefers exact ruleId match over normalized | 精确匹配优先 | -| 80 | mergeResults computes aiFixableLinterIndices excluding native fix and sqlfluff | AI 可修复索引 | -| 81 | mergeResults aiFixableLinterIndices empty when AI unavailable | AI 不可用置空 | +| 77 | mergeResults counts correctly | 计数正确 | +| 78 | mergeResults marks degraded when AI fails | AI 失败降级 | +| 79 | mergeResults sorts diagnostics by severity then line | 排序 | +| 80 | mergeResults marks fixable only diagnostics with fix object | 可修复标记 | +| 81 | mergeResults converts aiFindings line to 0-based | 行号 0 基化 | +| 82 | mergeResults pairs translations by originalRuleId not index | 按规则 id 配对翻译 | +| 83 | mergeResults handles duplicate ruleId translations in order | 重复 id 有序 | +| 84 | mergeResults matches translations by normalized ruleId when prefix missing | 缺前缀归一化匹配 | +| 85 | mergeResults matches translations by normalized ruleId with slash variant | 斜杠变体匹配 | +| 86 | mergeResults prefers exact ruleId match over normalized | 精确匹配优先 | +| 87 | mergeResults computes aiFixableLinterIndices excluding native fix and sqlfluff | AI 可修复索引 | +| 88 | mergeResults aiFixableLinterIndices empty when AI unavailable | AI 不可用置空 | ## 12. messages.test.ts — I18n Tests(9) | # | 用例 | 覆盖点 | |---|---|---| -| 82 | all message keys have values for all three languages | 三语 key 完整 | -| 83 | default language is zh-CN | 默认语言 | -| 84 | setLanguage changes current language | 语言切换 | -| 85 | t() falls back to key when key does not exist | 缺失 key 回退 | -| 86 | t() returns zh-CN string in zh-CN language | 中文翻译 | -| 87 | t() returns English string in en language | 英文翻译 | -| 88 | t() returns Japanese string in ja language | 日文翻译 | -| 89 | t() with template variables | 模板变量 | -| 90 | t() with multiple template variables | 多模板变量 | +| 89 | all message keys have values for all three languages | 三语 key 完整 | +| 90 | default language is zh-CN | 默认语言 | +| 91 | setLanguage changes current language | 语言切换 | +| 92 | t() falls back to key when key does not exist | 缺失 key 回退 | +| 93 | t() returns zh-CN string in zh-CN language | 中文翻译 | +| 94 | t() returns English string in en language | 英文翻译 | +| 95 | t() returns Japanese string in ja language | 日文翻译 | +| 96 | t() with template variables | 模板变量 | +| 97 | t() with multiple template variables | 多模板变量 | ## 13. pipeline.test.ts — Pipeline Tests(1) | # | 用例 | 覆盖点 | |---|---|---| -| 91 | Full pipeline: linter check + merge | 全链路(linter + 合并) | +| 98 | Full pipeline: linter check + merge | 全链路(linter + 合并) | ## 14. rule-filter.test.ts — Rule Filter Tests(15) | # | 用例 | 覆盖点 | |---|---|---| -| 92 | 规则匹配当前语言 | 语言匹配 | -| 93 | 规则未匹配被过滤 | 不匹配过滤 | -| 94 | 规则为空:全部保留 | 空规则集 | -| 95 | 规则缺失:全部保留 | 缺失过滤 | -| 96 | 规则按语言匹配后去重 | 去重 | -| 97 | 规则未匹配语言则去除 | 语言不匹配去除 | -| 98 | 规则为空时去重 | 空集去重 | -| 99 | 规则 + 语言映射匹配时过滤结果优先 | 优先级 | -| 100 | typescriptreact 同源映射到 typescript | TSX 映射 | -| 101 | plsql 同源映射到 sql | PL/SQL 映射 | -| 102 | JSP 映射 java 规则 | JSP→Java | -| 103 | JSP 不映射 css 规则 | JSP→CSS 排除 | -| 104 | 普通 HTML 触发 JSP 过滤 java 规则 | HTML→JSP | -| 105 | 全部过滤触发 skippedRequestA=true | 全过滤标记 | -| 106 | 部分过滤触发 skippedRequestA=false | 部分过滤标记 | +| 99 | 规则匹配当前语言 | 语言匹配 | +| 100 | 规则未匹配被过滤 | 不匹配过滤 | +| 101 | 规则为空:全部保留 | 空规则集 | +| 102 | 规则缺失:全部保留 | 缺失过滤 | +| 103 | 规则按语言匹配后去重 | 去重 | +| 104 | 规则未匹配语言则去除 | 语言不匹配去除 | +| 105 | 规则为空时去重 | 空集去重 | +| 106 | 规则 + 语言映射匹配时过滤结果优先 | 优先级 | +| 107 | typescriptreact 同源映射到 typescript | TSX 映射 | +| 108 | plsql 同源映射到 sql | PL/SQL 映射 | +| 109 | JSP 映射 java 规则 | JSP→Java | +| 110 | JSP 不映射 css 规则 | JSP→CSS 排除 | +| 111 | 普通 HTML 触发 JSP 过滤 java 规则 | HTML→JSP | +| 112 | 全部过滤触发 skippedRequestA=true | 全过滤标记 | +| 113 | 部分过滤触发 skippedRequestA=false | 部分过滤标记 | ## 15. sqlfluff-prs.test.ts — SqlFluff PRS Tests(4) | # | 用例 | 覆盖点 | |---|---|---| -| 107 | buildPRSMessage extracts fragment from description | PRS 片段提取 | -| 108 | buildPRSMessage flattens newlines in fragment | 换行压平 | -| 109 | buildPRSMessage truncates long fragments | 长片段截断 | -| 110 | buildPRSMessage falls back to description when pattern missing | 无匹配回退 | +| 114 | buildPRSMessage extracts fragment from description | PRS 片段提取 | +| 115 | buildPRSMessage flattens newlines in fragment | 换行压平 | +| 116 | buildPRSMessage truncates long fragments | 长片段截断 | +| 117 | buildPRSMessage falls back to description when pattern missing | 无匹配回退 | ## 16. sqlfluff-range.test.ts — SqlFluff Range Tests(6) | # | 用例 | 覆盖点 | |---|---|---| -| 111 | full positions convert to zero-based range | 完整位置 0 基化 | -| 112 | missing end positions fall back to start (comment JJ01 case) | 缺终点回退(JJ01) | -| 113 | legacy line_no/line_pos keys are honored | 旧版 key 兼容 | -| 114 | null positions fall back to defaults | null 兜底 | -| 115 | zero positions are clamped to valid values | 零值钳制 | -| 116 | missing all positions produce a safe zero range | 全缺失安全范围 | +| 118 | full positions convert to zero-based range | 完整位置 0 基化 | +| 119 | missing end positions fall back to start (comment JJ01 case) | 缺终点回退(JJ01) | +| 120 | legacy line_no/line_pos keys are honored | 旧版 key 兼容 | +| 121 | null positions fall back to defaults | null 兜底 | +| 122 | zero positions are clamped to valid values | 零值钳制 | +| 123 | missing all positions produce a safe zero range | 全缺失安全范围 | ## 17. jsp-extractor.test.ts — JspExtractor Tests(9) | # | 用例 | 覆盖点 | |---|---|---| -| 117 | extracts script block as javascript | script 块提取 | -| 118 | extracts style block as css | style 块提取 | -| 119 | extracts statement scriptlet with line offset | 语句型 scriptlet | -| 120 | extracts declaration scriptlet | 声明型 scriptlet | -| 121 | extracts expression scriptlet | 表达式型 scriptlet | -| 122 | skips directives and comments | 指令/注释跳过 | -| 123 | reports sourceStart/sourceEnd positions | 源区间定位 | -| 124 | returns empty array for plain html | 纯 HTML 无段落 | -| 125 | collects script, style and scriptlet sections | 多段落收集 | +| 124 | extracts script block as javascript | script 块提取 | +| 125 | extracts style block as css | style 块提取 | +| 126 | extracts statement scriptlet with line offset | 语句型 scriptlet | +| 127 | extracts declaration scriptlet | 声明型 scriptlet | +| 128 | extracts expression scriptlet | 表达式型 scriptlet | +| 129 | skips directives and comments | 指令/注释跳过 | +| 130 | reports sourceStart/sourceEnd positions | 源区间定位 | +| 131 | returns empty array for plain html | 纯 HTML 无段落 | +| 132 | collects script, style and scriptlet sections | 多段落收集 | ## 18. report.test.ts — Report Tests(7) | # | 用例 | 覆盖点 | |---|---|---| -| 126 | renders header metadata | 报告头元数据 | -| 127 | renders empty report with no-problems banner | 空报告无问题提示 | -| 128 | renders linter diagnostics with severity emoji and suggestion | 严重级 emoji 与建议 | -| 129 | renders custom rule diagnostics | 自定义规则段 | -| 130 | renders ai findings with category and suggestion | AI 发现段 | -| 131 | renders degraded banner and errors section | 降级横幅与错误区 | -| 132 | omits tools line when no adapters | 无工具时不显示 | +| 133 | renders header metadata | 报告头元数据 | +| 134 | renders empty report with no-problems banner | 空报告无问题提示 | +| 135 | renders linter diagnostics with severity emoji and suggestion | 严重级 emoji 与建议 | +| 136 | renders custom rule diagnostics | 自定义规则段 | +| 137 | renders ai findings with category and suggestion | AI 发现段 | +| 138 | renders degraded banner and errors section | 降级横幅与错误区 | +| 139 | omits tools line when no adapters | 无工具时不显示 | ## 19. method-extractor.test.ts — MethodExtractor Tests(9) | # | 用例 | 覆盖点 | |---|---|---| -| 133 | fallback regex finds js function declarations and arrow functions | JS 方法兜底正则 | -| 134 | fallback regex finds java methods | Java 方法兜底正则 | -| 135 | fallback regex returns empty for unsupported language | 不支持语言返回空 | -| 136 | extractMethodScope returns code, signature and callers | 方法作用域+调用者 | -| 137 | extractMethodScope identifies callees | 被调用者识别 | -| 138 | expandToMethodBody ignores braces inside strings and comments | 括号配对(跳过字符串/注释) | -| 139 | extractSignature strips leading comments | 签名去注释 | -| 140 | inferRole maps getter, process and generic names | 角色推断 | -| 141 | extractMethodScope returns null when range matches no method | 无命中返回 null | +| 140 | fallback regex finds js function declarations and arrow functions | JS 方法兜底正则 | +| 141 | fallback regex finds java methods | Java 方法兜底正则 | +| 142 | fallback regex returns empty for unsupported language | 不支持语言返回空 | +| 143 | extractMethodScope returns code, signature and callers | 方法作用域+调用者 | +| 144 | extractMethodScope identifies callees | 被调用者识别 | +| 145 | expandToMethodBody ignores braces inside strings and comments | 括号配对(跳过字符串/注释) | +| 146 | extractSignature strips leading comments | 签名去注释 | +| 147 | inferRole maps getter, process and generic names | 角色推断 | +| 148 | extractMethodScope returns null when range matches no method | 无命中返回 null | ## 20. fix-prompt.test.ts — FixPrompt Tests(10) | # | 用例 | 覆盖点 | |---|---|---| -| 142 | buildFixSystemPrompt defaults to Chinese | 中文系统提示词 | -| 143 | buildFixSystemPrompt returns English variant | 英文系统提示词 | -| 144 | buildFixSystemPrompt returns Japanese variant | 日文系统提示词 | -| 145 | buildFixUserPrompt includes issue, message and context | 用户提示词组装 | -| 146 | buildFixUserPrompt includes suggestion when present | 建议追加 | -| 147 | buildFixUserPrompt omits suggestion when blank | 空建议省略 | -| 148 | buildFixContext windows around line with padding | 上下文窗口+对齐 | -| 149 | buildFixContext clamps at document boundaries | 边界钳制 | -| 150 | buildVerifySystemPrompt has language variants | 校验系统提示词 | -| 151 | buildVerifyUserPrompt includes issue and code | 校验用户提示词 | +| 149 | buildFixSystemPrompt defaults to Chinese | 中文系统提示词 | +| 150 | buildFixSystemPrompt returns English variant | 英文系统提示词 | +| 151 | buildFixSystemPrompt returns Japanese variant | 日文系统提示词 | +| 152 | buildFixUserPrompt includes issue, message and context | 用户提示词组装 | +| 153 | buildFixUserPrompt includes suggestion when present | 建议追加 | +| 154 | buildFixUserPrompt omits suggestion when blank | 空建议省略 | +| 155 | buildFixContext windows around line with padding | 上下文窗口+对齐 | +| 156 | buildFixContext clamps at document boundaries | 边界钳制 | +| 157 | buildVerifySystemPrompt has language variants | 校验系统提示词 | +| 158 | buildVerifyUserPrompt includes issue and code | 校验用户提示词 | ## 21. registry.test.ts — Provider Registry Tests(7) | # | 用例 | 覆盖点 | |---|---|---| -| 152 | returns empty when no extension uri | 无 URI 返回空 | -| 153 | loads builtin providers from extension providers.json | 内置 Provider 加载 | -| 154 | caches providers across calls | 注册表缓存 | -| 155 | invalidateProviderCache forces reload | 缓存失效 | -| 156 | returns empty for missing or invalid providers.json | 缺失/非法文件 | -| 157 | getProviderById finds or misses | 按 ID 查询 | -| 158 | getAllProviderMeta returns name and models | Provider 元数据 | +| 159 | returns empty when no extension uri | 无 URI 返回空 | +| 160 | loads builtin providers from extension providers.json | 内置 Provider 加载 | +| 161 | caches providers across calls | 注册表缓存 | +| 162 | invalidateProviderCache forces reload | 缓存失效 | +| 163 | returns empty for missing or invalid providers.json | 缺失/非法文件 | +| 164 | getProviderById finds or misses | 按 ID 查询 | +| 165 | getAllProviderMeta returns name and models | Provider 元数据 | ## 22. provider-chat.test.ts — Provider Chat Tests(11) | # | 用例 | 覆盖点 | |---|---|---| -| 159 | openai chat returns content with bearer auth | OpenAI 兼容协议成功 | -| 160 | openai 401 throws invalid key error | 401 无效密钥 | -| 161 | openai truncation raises EmptyContentError | token 截断空响应 | -| 162 | openai empty content raises EmptyContentError | 空内容错误 | -| 163 | openai other status throws | 其他状态报错 | -| 164 | gemini chat returns text | Gemini 协议成功 | -| 165 | gemini empty content raises EmptyContentError | Gemini 空响应 | -| 166 | gemini non-ok throws | Gemini 报错 | -| 167 | claude chat returns text with api key header | Claude 协议成功 | -| 168 | claude 401 throws | Claude 401 | -| 169 | claude empty content raises EmptyContentError | Claude 空响应 | +| 166 | openai chat returns content with bearer auth | OpenAI 兼容协议成功 | +| 167 | openai 401 throws invalid key error | 401 无效密钥 | +| 168 | openai truncation raises EmptyContentError | token 截断空响应 | +| 169 | openai empty content raises EmptyContentError | 空内容错误 | +| 170 | openai other status throws | 其他状态报错 | +| 171 | gemini chat returns text | Gemini 协议成功 | +| 172 | gemini empty content raises EmptyContentError | Gemini 空响应 | +| 173 | gemini non-ok throws | Gemini 报错 | +| 174 | claude chat returns text with api key header | Claude 协议成功 | +| 175 | claude 401 throws | Claude 401 | +| 176 | claude empty content raises EmptyContentError | Claude 空响应 | ## 23. import-service.test.ts — ImportService Tests(7) | # | 用例 | 覆盖点 | |---|---|---| -| 170 | parseImportableYaml handles arrays and quoted ids | YAML 数组/引号 | -| 171 | parseImportableYaml fills message from description and vice versa | 字段互填 | -| 172 | buildFinalYaml uses edited rules when present | 编辑规则分支 | -| 173 | buildFinalYaml comments exact duplicates and strips duplicate metadata | 精确重复注释 | -| 174 | buildFinalYaml keeps all when no overrides | 无覆盖全保留 | -| 175 | applyConversion writes final yaml to nested target path | 写入目标文件 | -| 176 | convert throws for unsupported extension | 不支持格式报错 | +| 177 | parseImportableYaml handles arrays and quoted ids | YAML 数组/引号 | +| 178 | parseImportableYaml fills message from description and vice versa | 字段互填 | +| 179 | buildFinalYaml uses edited rules when present | 编辑规则分支 | +| 180 | buildFinalYaml comments exact duplicates and strips duplicate metadata | 精确重复注释 | +| 181 | buildFinalYaml keeps all when no overrides | 无覆盖全保留 | +| 182 | applyConversion writes final yaml to nested target path | 写入目标文件 | +| 183 | convert throws for unsupported extension | 不支持格式报错 | ## 24. yaml-parser.test.ts — YamlParser Tests(3) | # | 用例 | 覆盖点 | |---|---|---| -| 177 | returns empty when rules dir missing | 目录缺失 | -| 178 | loads rules from yaml files with severity normalization | 规则加载与严重级归一 | -| 179 | skips incomplete rules and non-yaml files | 不完整规则/非 yaml 跳过 | +| 184 | returns empty when rules dir missing | 目录缺失 | +| 185 | loads rules from yaml files with severity normalization | 规则加载与严重级归一 | +| 186 | skips incomplete rules and non-yaml files | 不完整规则/非 yaml 跳过 | + +## 25. excel-converter.test.ts — ExcelConverter Tests(7) + +| # | 用例 | 覆盖点 | +|---|---|---| +| 187 | buildMarkdownTable renders sheet title, header, separator and data rows | Markdown 表格渲染格式 | +| 188 | buildMarkdownTable fills missing fields with empty string | 缺失单元格填充 | +| 189 | buildMarkdownTable renders columns from union of row keys | 列键并集(无表头文件列保留) | +| 190 | renderWorkbookToMarkdown includes all non-empty sheets of galaxy fixture | 真实多 Sheet 文件渲染 | +| 191 | renderWorkbookToMarkdown keeps galaxy rule content faithful for AI conversion | 规则内容忠实传递给 AI | +| 192 | renderWorkbookToMarkdown skips empty sheets | 空表跳过 | +| 193 | renderWorkbookToMarkdown returns null when no sheet has data | 全空工作簿返回 null | + +## 26. webview-escape.test.ts — Webview Escape Tests(4) + +| # | 用例 | 覆盖点 | +|---|---|---| +| 194 | escapes greater-than as > | 大于号转义 | +| 195 | escapes less-than, ampersand and double quote | 小于号/与号/双引号转义 | +| 196 | escapes combined diagnostic message content | 组合消息内容转义 | +| 197 | does not double-escape existing entities | 既有实体的转义行为 | ## 统计 | 文件 | 用例数 | |---|---| | adapter.test.ts | 6 | -| ai-empty-response.test.ts | 6 | +| ai-empty-response.test.ts | 13 | | ai-fix-engine.test.ts | 4 | | config.test.ts | 4 | | customFixEngine.test.ts | 5 | | dedup-prompt.test.ts | 3 | | diagnostics.test.ts | 6 | +| excel-converter.test.ts | 7 | | fixEngine.test.ts | 5 | | fixSession.test.ts | 6 | -| import-dedup.test.ts | 25 | +| import-dedup.test.ts | 24 | | merger.test.ts | 12 | | messages.test.ts | 9 | | pipeline.test.ts | 1 | @@ -329,4 +358,5 @@ | provider-chat.test.ts | 11 | | import-service.test.ts | 7 | | yaml-parser.test.ts | 3 | -| **合计** | **179** | +| webview-escape.test.ts | 4 | +| **合计** | **197** |