修复: AI工具OOM/路径遍历+续跑锁收敛+UX交互批
This commit is contained in:
49
docs/todo.md
49
docs/todo.md
@@ -1090,22 +1090,22 @@ gap: 8px;
|
||||
#### 🔴 P0 — 确定性 Bug(3 项·建议立即修复)
|
||||
|
||||
- [ ] **BUG-260617-01 [P0]** — **`classify_status_or_class` 尾部 `|| true` 导致所有 unknown 错误标记 retryable** — `stream_recv.rs:433` 函数末尾硬编码 `|| true`,400/403 等 Fatal 错误被误标为可重试 → agentic loop 无效重试循环浪费 token 和时间。**修法**:移除 `|| true`,unknown 默认 `false`(保守不重试),与 `retry::is_status_retryable` 语义一致。**一行改动,零风险,最高 ROI**。— src-tauri/src/commands/ai/stream_recv.rs:433
|
||||
- [ ] **BUG-260617-02 [P0]** — **`file_info` 全量读大文件到内存再截断前 8KB** — `tool_registry.rs:1125-1126` `tokio::fs::read(path)` 将整个文件读入内存(注释说">2MB跳过避免全量读"但实际先全量读再取前 8192 字节做二进制检测)。>2MB 文件触发 OOM 风险。**修法**:用 `File::open` + `read_exact()` 仅读前 N 字节,或加 `.take(8192)` 截断流式读取。— src-tauri/src/commands/ai/tool_registry.rs:1125-1126
|
||||
- [ ] **BUG-260617-03 [P0]** — **路径遍历防护可被编码绕过** — `tool_registry.rs:78-95` 只做字符串 `..` 检测 + 小写化,URL 编码 `%2e%2e` / Unicode 同形字符可绕过。**修法**:先 `percent_decode` 再做词法 `..` 分段归一化检查;对不存在路径(new file) 也应规范化校验。— src-tauri/src/commands/ai/tool_registry.rs:78-95
|
||||
- [x] **BUG-260617-02 [P0]** — **`file_info` 全量读大文件到内存再截断前 8KB** — `tool_registry.rs:1125-1126` `tokio::fs::read(path)` 将整个文件读入内存(注释说">2MB跳过避免全量读"但实际先全量读再取前 8192 字节做二进制检测)。>2MB 文件触发 OOM 风险。**修法**:用 `File::open` + `read_exact()` 仅读前 N 字节,或加 `.take(8192)` 截断流式读取。— src-tauri/src/commands/ai/tool_registry.rs:1125-1126
|
||||
- [x] **BUG-260617-03 [P0]** — **路径遍历防护可被编码绕过** — `tool_registry.rs:78-95` 只做字符串 `..` 检测 + 小写化,URL 编码 `%2e%2e` / Unicode 同形字符可绕过。**修法**:先 `percent_decode` 再做词法 `..` 分段归一化检查;对不存在路径(new file) 也应规范化校验。— src-tauri/src/commands/ai/tool_registry.rs:78-95
|
||||
|
||||
#### 🟡 P1 — 高概率问题(5 项·建议本轮修复)
|
||||
|
||||
- [ ] **BUG-260617-04 [P1]** — **`ai_chat_force_send` → `ai_chat_send` 双锁竞态窗口** — `commands.rs:763` force_send 先 lock 复位 generating→释放锁→调 ai_chat_send 再 lock。两锁之间 stop IPC 可插入打断"原子复位+发送"语义;若 ai_chat_send 因 generating=true 被 reject → 前端状态不一致。**修法**:force_send 内联 spawn run_agentic_loop(同 regenerate/edit 模式),不走 ai_chat_send 门控。— src-tauri/src/commands/ai/commands.rs:744-763
|
||||
- [ ] **BUG-260617-05 [P1]** — **`try_continue_agent_loop` 4 次独立 lock 非原子化** — `agentic.rs:943-1036` 至少 4 次 `state.ai_session.lock().await`,每次 release 后其他 IPC 可修改 session → 续跑判断基于过时快照(如步骤 1 判 should_continue=true → 步骤 2 间 user 点 stop → 步骤 3 仍续跑)。**修法**:单次 lock 内完成所有字段读写,或引入结构化快照一次取出。— src-tauri/src/commands/ai/agentic.rs:943-1036
|
||||
- [ ] **BUG-260617-06 [P1]** — **`accumulate_tokens` 整数溢出无 saturating 保护** — `conversation.rs:49-51` `old.unwrap_or(0) + add as i64` 长期对话累积接近 i64::MAX 后翻负。**修法**:改用 `.saturating_add()` 或类型改为 `u64`。— src-tauri/src/commands/ai/conversation.rs:49-51
|
||||
- [ ] **BUG-260617-07 [P1]** — **`generate_diff` LCS O(n*m) 内存爆炸** — `tool_registry.rs:32-75` 标准 DP diff,5000 行输入 ≈ 200MB DP 表。虽有 changes>300 截断但截断前已分配计算完毕。**修法**:超长输入(均>1000行)跳过 LCS 改用 Myers diff 或直接返回截断 diff。— src-tauri/src/commands/ai/tool_registry.rs:32-75
|
||||
- [ ] **BUG-260617-08 [P1]** — **Lagged 循环每次重建 WorkflowRepo 连接池** — `workflow.rs:204` forward 循环内每次 `WorkflowRepo::new(&forward_db)`,高频 Lagged 场景可能连接数暴增。**修法**:Repo 提到循环外创建一次或传 Arc<WorkflowRepo>。— src-tauri/src/commands/ai/workflow.rs:204
|
||||
- [x] **BUG-260617-05 [P1]** — **`try_continue_agent_loop` 4 次独立 lock 非原子化** — `agentic.rs:943-1036` 至少 4 次 `state.ai_session.lock().await`,每次 release 后其他 IPC 可修改 session → 续跑判断基于过时快照(如步骤 1 判 should_continue=true → 步骤 2 间 user 点 stop → 步骤 3 仍续跑)。**修法**:单次 lock 内完成所有字段读写,或引入结构化快照一次取出。— src-tauri/src/commands/ai/agentic.rs:943-1036
|
||||
- [x] **BUG-260617-06 [P1]** — **`accumulate_tokens` 整数溢出无 saturating 保护** — `conversation.rs:49-51` `old.unwrap_or(0) + add as i64` 长期对话累积接近 i64::MAX 后翻负。**修法**:改用 `.saturating_add()` 或类型改为 `u64`。— src-tauri/src/commands/ai/conversation.rs:49-51
|
||||
- [x] **BUG-260617-07 [P1]** — **`generate_diff` LCS O(n*m) 内存爆炸** — `tool_registry.rs:32-75` 标准 DP diff,5000 行输入 ≈ 200MB DP 表。虽有 changes>300 截断但截断前已分配计算完毕。**修法**:超长输入(均>1000行)跳过 LCS 改用 Myers diff 或直接返回截断 diff。— src-tauri/src/commands/ai/tool_registry.rs:32-75
|
||||
- [x] **BUG-260617-08 [P1]** — **Lagged 循环每次重建 WorkflowRepo 连接池** — `workflow.rs:204` forward 循环内每次 `WorkflowRepo::new(&forward_db)`,高频 Lagged 场景可能连接数暴增。**修法**:Repo 提到循环外创建一次或传 Arc<WorkflowRepo>。— src-tauri/src/commands/ai/workflow.rs:204
|
||||
|
||||
#### ⚪ P2 — 关注项(3 项·低优先级)
|
||||
|
||||
- [ ] **BUG-260617-09 [P2]** — **递归深度 max_depth 由 LLM 参数控制无上限** — `tool_registry.rs:1391+/1511+` LLM 可传入极大值,虽有 entries 上限隐式约束但防御不完整。**修法**:clamp 到合理范围(如 1-10)。— src-tauri/src/commands/ai/tool_registry.rs:1391-1545
|
||||
- [ ] **BUG-260617-10 [P2]** — **skills.rs OnceLock 初始化用同步 std::fs 阻塞 runtime** — `skills.rs:69,168` 首次 skills 查询阻塞 tokio runtime 数十ms。影响极小(仅首次),但与规范偏差。**修法**:`spawn_blocking` 包裹或接受当前行为。— src-tauri/src/commands/ai/skills.rs:69,168
|
||||
- [ ] **BUG-260617-11 [P2]** — **`read_file` 工具无 offset 时全量返回大文件** — `tool_registry.rs:787-794` 无 offset 时 `content.clone()` 全量返回(1865 行/101KB 的 tool_registry.rs 自身即触发此问题)。**修法**:无 offset 默认返回 500 行 + has_more 提示翻页。关联 memory:[[read-file-pagination-needed]](已记录方案)。— src-tauri/src/commands/ai/tool_registry.rs:787-794
|
||||
- [x] **BUG-260617-09 [P2]** — **递归深度 max_depth 由 LLM 参数控制无上限** — `tool_registry.rs:1391+/1511+` LLM 可传入极大值,虽有 entries 上限隐式约束但防御不完整。**修法**:clamp 到合理范围(如 1-10)。— src-tauri/src/commands/ai/tool_registry.rs:1391-1545
|
||||
- [x] **BUG-260617-10 [P2]** — **skills.rs OnceLock 初始化用同步 std::fs 阻塞 runtime** — `skills.rs:69,168` 首次 skills 查询阻塞 tokio runtime 数十ms。影响极小(仅首次),但与规范偏差。**修法**:`spawn_blocking` 包裹或接受当前行为。— src-tauri/src/commands/ai/skills.rs:69,168
|
||||
- [x] **BUG-260617-11 [P2]** — **`read_file` 工具无 offset 时全量返回大文件** — `tool_registry.rs:787-794` 无 offset 时 `content.clone()` 全量返回(1865 行/101KB 的 tool_registry.rs 自身即触发此问题)。**修法**:无 offset 默认返回 500 行 + has_more 提示翻页。关联 memory:[[read-file-pagination-needed]](已记录方案)。— src-tauri/src/commands/ai/tool_registry.rs:787-794
|
||||
|
||||
---
|
||||
|
||||
@@ -1117,9 +1117,9 @@ gap: 8px;
|
||||
#### 🔴 已确认交互 Bug
|
||||
|
||||
- [ ] **UX-260617-01 [P0]🎯** — **消息/工具卡大量重叠堆叠(用户实测确认)**。5 角度深入分析(todo.md L116-180+):CSS 声明链路正常、scoped 无冲突、DOM 结构正确 → 排除常规原因。**核心嫌疑**:虚拟滚动 IO 半激活态不一致——部分 item 被 IO 管理(可卸载)、部分不被管理(永远渲染) + height=0 时 minHeight 未设置 → slot 塌 0 → 重叠。**需复现定位确切触发路径后修复**。— src/components/AiChat.vue + src/composables/ai/useAiVirtualScroll.ts
|
||||
- [ ] **UX-260617-02 [P1]🎯** — **CR-59 审查发现:`onPoolWeightChange` 缺乐观更新 revert 逻辑** — Settings.vue:643-656 weight 输入 debounce 300ms 调 IPC,成功后未像 onPoolToggle 一样 revert 到服务端值。IPC 失败或延迟时 UI 显示旧值而非回滚。**修法**:补 revert 分支(对齐 onPoolToggle 模式)。— src/views/Settings.vue:643-656
|
||||
- [ ] **UX-260617-03 [P1]🎯** — **copyMsgContent 失败误报「已复制」(已记录未修)** — `AiChat.vue:1037-1040` clipboard.writeText 权限拒绝 → catch 仍 showToast('copied')。用户见"已复制"去粘贴发现空。**修法**:catch 改失败文案或静默。(已在 AI 链路审查 B-260615-46 记录,提升优先级至此区)。— src/components/AiChat.vue:1037-1040
|
||||
- [ ] **UX-260617-04 [P1]🎯** — **offsetToDOMPosition 恒返回 root 致选区恢复错位(已记录未修)** — `AiChat.vue:908-921` createTreeWalker 后 currentNode 初始=root 非 Text → ?? 恒取左 → 循环无 nextNode 推进 → 选区恒错位。UX-2025-01 功能实际失效。(已在 B-260615-47 记录,提升优先级至此区)。— src/components/AiChat.vue:908-921
|
||||
- [x] **UX-260617-02 [P1]🎯** — **CR-59 审查发现:`onPoolWeightChange` 缺乐观更新 revert 逻辑** — Settings.vue:643-656 weight 输入 debounce 300ms 调 IPC,成功后未像 onPoolToggle 一样 revert 到服务端值。IPC 失败或延迟时 UI 显示旧值而非回滚。**修法**:补 revert 分支(对齐 onPoolToggle 模式)。— src/views/Settings.vue:643-656
|
||||
- [x] **UX-260617-03 [P1]🎯** — **copyMsgContent 失败误报「已复制」(已记录未修)** — `AiChat.vue:1037-1040` clipboard.writeText 权限拒绝 → catch 仍 showToast('copied')。用户见"已复制"去粘贴发现空。**修法**:catch 改失败文案或静默。(已在 AI 链路审查 B-260615-46 记录,提升优先级至此区)。— src/components/AiChat.vue:1037-1040
|
||||
- [x] **UX-260617-04 [P1]🎯** — **offsetToDOMPosition 恒返回 root 致选区恢复错位(已记录未修)** — `AiChat.vue:908-921` createTreeWalker 后 currentNode 初始=root 非 Text → ?? 恒取左 → 循环无 nextNode 推进 → 选区恒错位。UX-2025-01 功能实际失效。(已在 B-260615-47 记录,提升优先级至此区)。— src/components/AiChat.vue:908-921
|
||||
|
||||
#### 🟡 待扫描确认的交互问题(aichat agent 结果回填后补充/降级)
|
||||
|
||||
@@ -1131,21 +1131,21 @@ gap: 8px;
|
||||
- [x] ~~**UX-260617-05 [P2]🎯** — *(待扫描确认→降级)* 流式渲染增量追加闪烁~~ ✅ **排除**:streamingBlocks rAF 节流 + scheduleStreamParse 双层机制完备,无 dup 风险(scan 未发现闪烁 bug,rAF 块级 memo + snap 短路兜底有效)
|
||||
- [x] ~~**UX-260617-06 [P2]🎯** — *(待扫描确认→升级)* wasNearBottom~~ → **合并入 UX-260617-21**(stopChat 竞态窗口,含 scroll 一致性)
|
||||
- [x] ~~**UX-260617-07 [P2]🎯** — *(待扫描确认→降级)* 审批顺序~~ ✅ **低风险**:审批按 tool_call_id 串行处理,无并行冲突(F-05 超时静默是更大问题)
|
||||
- [ ] **UX-260617-08 [P1]🎯** — **switchConversation/loadConversations 异常静默吞没** — `useAiConversations.ts:36-44` catch 为空 + `:117-119` switchConversation catch 仅 `messages=[]` 无反馈。网络抖动/IPC 断开 → 对话列表突然变空/切换后空白用户不知原因。**修法**:catch 加 toast('loadConvFail','warning');loadConversations 失败保留旧列表+stale 标记。— src/composables/ai/useAiConversations.ts:36-44,117-119
|
||||
- [ ] **UX-260617-09 [P1]🎯** — **startListener 吞掉注册异常导致全量事件静默丢失** — `useAiEvents.ts:354-373` IIFE 内 `aiApi.onEvent(handleEvent)` 异常被完全吞没(无 console.error/toast/log)。所有聊天事件(文本/完成/审批)全丢 → UI 表现"发了消息永远不回"。**修法**:IIFE 内加 try/catch + console.error + throw 让外层 finally 清理。— src/composables/ai/useAiEvents.ts:354-373
|
||||
- [ ] **UX-260617-10 [P1]🎯** — **AiError 不清理 pendingApprovals,错误后残留审批卡** — `useAiEvents.ts:326-349` AiError case 做 clearStreamWatchdog/清queue/推错误气泡但**从未清 pendingApprovals**。出错时有 tool_call 处于 pending_approval → 残留可点击审批按钮。**修法**:加 `state.pendingApprovals=[]` + `clearAllApprovalTimers()`。— src/composables/ai/useAiEvents.ts:326-349
|
||||
- [ ] **UX-260617-11 [P1]🎯** — **modelOverride 跨对话泄漏** — `useAiSend.ts:67` 模块级 ref,注释明确要求"前端应同步清 null"但**无任何代码执行此清除**。switchConversation/newConversation 不触碰。对话A选模型覆盖→切对话B→override 静默生效。**修法**:switchConversation 末尾加 `modelOverride.value=null`。— src/composables/ai/useAiSend.ts:64-67
|
||||
- [x] **UX-260617-08 [P1]🎯** — **switchConversation/loadConversations 异常静默吞没** — `useAiConversations.ts:36-44` catch 为空 + `:117-119` switchConversation catch 仅 `messages=[]` 无反馈。网络抖动/IPC 断开 → 对话列表突然变空/切换后空白用户不知原因。**修法**:catch 加 toast('loadConvFail','warning');loadConversations 失败保留旧列表+stale 标记。— src/composables/ai/useAiConversations.ts:36-44,117-119
|
||||
- [x] **UX-260617-09 [P1]🎯** — **startListener 吞掉注册异常导致全量事件静默丢失** — `useAiEvents.ts:354-373` IIFE 内 `aiApi.onEvent(handleEvent)` 异常被完全吞没(无 console.error/toast/log)。所有聊天事件(文本/完成/审批)全丢 → UI 表现"发了消息永远不回"。**修法**:IIFE 内加 try/catch + console.error + throw 让外层 finally 清理。— src/composables/ai/useAiEvents.ts:354-373
|
||||
- [x] **UX-260617-10 [P1]🎯** — **AiError 不清理 pendingApprovals,错误后残留审批卡** — `useAiEvents.ts:326-349` AiError case 做 clearStreamWatchdog/清queue/推错误气泡但**从未清 pendingApprovals**。出错时有 tool_call 处于 pending_approval → 残留可点击审批按钮。**修法**:加 `state.pendingApprovals=[]` + `clearAllApprovalTimers()`。— src/composables/ai/useAiEvents.ts:326-349
|
||||
- [x] **UX-260617-11 [P1]🎯** — **modelOverride 跨对话泄漏** — `useAiSend.ts:67` 模块级 ref,注释明确要求"前端应同步清 null"但**无任何代码执行此清除**。switchConversation/newConversation 不触碰。对话A选模型覆盖→切对话B→override 静默生效。**修法**:switchConversation 末尾加 `modelOverride.value=null`。— src/composables/ai/useAiSend.ts:64-67
|
||||
- [x] ~~**UX-260617-12 [P3]🎯** — *(待扫描确认→升级)* generating crash 兜底~~ → **合并入 UX-260617-01**(消息重叠根因含状态不一致)
|
||||
|
||||
#### 🟡 aichat 扫描新增发现(MEDIUM · 8 项)
|
||||
|
||||
- [ ] **UX-260617-13 [P1]🎯** — **刷新后主面板无流式恢复,用户看到"假死"** — 分离窗口(resumeInDetached)有完整恢复链(ai_is_generating→恢复streaming→推送占位气泡→localStorage currentText),**主面板完全没有等价逻辑**。刷新后 streaming=false + 无占位气泡 + 后端事件到达不进流式分支 → 文本仅 AiCompleted 时一次性显示退化为非流式体验。**修法**:主面板 onMounted/client-ready 后调 ai_is_generating IPC,true 则对齐 resumeInDetached 恢复链。工作量较大但用户感知最强。— src/composables/ai/useAiEvents.ts:155-179 + src/composables/ai/useAiWindow.ts:64-89
|
||||
- [ ] **UX-260617-14 [P2]🎯** — **审批超时 130s 静默复位无反馈** — `ToolCard.vue:507,541-54` 超时仅 `approving.value=false`,无 toast/error/日志。用户无法区分"审批完成状态没更新"和"超时复位"。**修法**:超时时 warning toast + APPROVE_LOADING_TIMEOUT_MS 改为共享常量导入。— src/components/ToolCard.vue:507,541-544
|
||||
- [ ] **UX-260617-15 [P2]🎯** — **regenerate/editMessage 丢弃图片 parts** — `useAiSend.ts:148-190` regenerate/edit 均无 parts 参数。含图片消息重生成/编辑后图片消失。**修法**:扩展 regenerate/editMessage IPC 签名透传 parts;或至少 UI 层对含 parts 消息禁用按钮/confirmDialog 提示。— src/composables/ai/useAiSend.ts:148-190
|
||||
- [x] **UX-260617-14 [P2]🎯** — **审批超时 130s 静默复位无反馈** — `ToolCard.vue:507,541-54` 超时仅 `approving.value=false`,无 toast/error/日志。用户无法区分"审批完成状态没更新"和"超时复位"。**修法**:超时时 warning toast + APPROVE_LOADING_TIMEOUT_MS 改为共享常量导入。— src/components/ToolCard.vue:507,541-544
|
||||
- [x] **UX-260617-15 [P2]🎯** — **regenerate/editMessage 丢弃图片 parts** — `useAiSend.ts:148-190` regenerate/edit 均无 parts 参数。含图片消息重生成/编辑后图片消失。**修法**:扩展 regenerate/editMessage IPC 签名透传 parts;或至少 UI 层对含 parts 消息禁用按钮/confirmDialog 提示。— src/composables/ai/useAiSend.ts:148-190
|
||||
- [ ] **UX-260617-16 [P2]🎯** — **无路由离开/关闭保护,未发送输入静默丢失** — AiChat.vue 缺 beforeRouteLeave/onBeforeUnload 守卫。输入框有内容/已粘贴图片时切页面 → 内容瞬间消失无提示。**修法**:beforeRouteLeave guard + detached window beforeunload 检查 inputText/pendingImages/pendingSkill 非空时 confirmDialog。— src/components/AiChat.vue (缺失守卫)
|
||||
- [ ] **UX-260617-17 [P2]🎯** — **ToolCardList 分组名硬编码中文绕过 i18n** — `ToolCardList.vue:259-274` nameMap 全硬编码中文(`'读取文件'`等)。英文 locale 下分组标题仍显示中文。**修法**:value 替换 i18n key(`ai.toolGroup.readFile`)。— src/components/ToolCardList.vue:259-274
|
||||
- [ ] **UX-260617-18 [P2]🎯** — **isToolFailure() 正则过于宽泛误判合法输出为失败** — `ToolCard.vue:220-224` `/执行失败|failed|error[:\s]/i` 匹配任何含这些子串的文本。search_files 结果列 error.log / run_command stderr 含 warning 均被标红。**修法**:收窄为 `/^(执行失败|Error:|Failed:)/m` 或按工具类型分别配置检测策略。— src/components/ToolCard.vue:220-224
|
||||
- [ ] **UX-260617-19 [P2]🎯** — **stopChat 本地先行 reset 与后端竞态窗口** — `useAiSend.ts:479-488` 先设 streaming=false 再发 IPC stop。IPC 失败时后端继续生成但前端已停止;若后续事件也丢失则永久卡死。注释承认风险但无缓解。**修法**:stop 后启动 5s 守护超时,未收到 Completed/Error 则推提示或重试 stop。— src/composables/ai/useAiSend.ts:479-488
|
||||
- [x] **UX-260617-17 [P2]🎯** — **ToolCardList 分组名硬编码中文绕过 i18n** — `ToolCardList.vue:259-274` nameMap 全硬编码中文(`'读取文件'`等)。英文 locale 下分组标题仍显示中文。**修法**:value 替换 i18n key(`ai.toolGroup.readFile`)。— src/components/ToolCardList.vue:259-274
|
||||
- [x] **UX-260617-18 [P2]🎯** — **isToolFailure() 正则过于宽泛误判合法输出为失败** — `ToolCard.vue:220-224` `/执行失败|failed|error[:\s]/i` 匹配任何含这些子串的文本。search_files 结果列 error.log / run_command stderr 含 warning 均被标红。**修法**:收窄为 `/^(执行失败|Error:|Failed:)/m` 或按工具类型分别配置检测策略。— src/components/ToolCard.vue:220-224
|
||||
- [x] **UX-260617-19 [P2]🎯** — **stopChat 本地先行 reset 与后端竞态窗口** — `useAiSend.ts:479-488` 先设 streaming=false 再发 IPC stop。IPC 失败时后端继续生成但前端已停止;若后续事件也丢失则永久卡死。注释承认风险但无缓解。**修法**:stop 后启动 5s 守护超时,未收到 Completed/Error 则推提示或重试 stop。— src/composables/ai/useAiSend.ts:479-488
|
||||
|
||||
#### ⚪ aichat 扫描新增发现(LOW · 8 项)
|
||||
|
||||
@@ -1155,9 +1155,14 @@ gap: 8px;
|
||||
- [ ] **UX-260617-23 [P3]🎯** — **搜索结果选中不清除搜索框,搜索视图不退出** — `AiChat.vue:46` 点击结果 switchConversation 但不清 searchQuery。搜索文字保留+仍显示扁平列表。**修法**:点击 handler 加 `searchQuery=''` 自动退出搜索模式。— src/components/AiChat.vue:46
|
||||
- [ ] **UX-260617-24 [P3]🎯** — **删除当前活跃对话无特殊警告** — `AiChat.vue:1140-1145` confirmDelete 通用文案不区分活跃对话。对比 confirmNewConversation 有上下文感知警告。**修法**:id===activeConversationId 时改醒目提示说明消息区将清空。— src/components/AiChat.vue:1140-1145
|
||||
- [ ] **UX-260617-25 [P3]🎯** — **parseBlockNoCache 非 null 断言无运行时防护** — `AiChat.vue:848` `purify!.sanitize(marked!.parse(...))` 。marked/DOMPurify 动态 import 失败时 TypeError → rAF 循环中断流式卡死。**修法**:防御性 null check + 降级 escapeFallback。— src/components/AiChat.vue:848
|
||||
- [ ] **UX-260617-26 [P3]🎯** — **startListener/stopListener 竞态:_startPromise 未在 stop 中清零** — `useAiEvents.ts:354+378` stop 不清 _startPromise。极速 mount/unmount/mount(HMR) → 返回过期 promise。**修法**:stop 中加 `_startPromise=null`。— src/composables/ai/useAiEvents.ts:378-388
|
||||
- [x] **UX-260617-26 [P3]🎯** — **startListener/stopListener 竞态:_startPromise 未在 stop 中清零** — `useAiEvents.ts:354+378` stop 不清 _startPromise。极速 mount/unmount/mount(HMR) → 返回过期 promise。**修法**:stop 中加 `_startPromise=null`。— src/composables/ai/useAiEvents.ts:378-388
|
||||
- [ ] **UX-260617-27 [P3]🎯** — **ConfirmDialog 危险按钮默认标签"删除"语义不安全** — `ConfirmDialog.vue:9-10` 默认 `$t('common.delete')`。非删除场景(高危工具审批)忘传 dangerLabel → 按钮显示"删除"。**修法**:默认值改为 `$t('common.confirm')`。— src/components/ConfirmDialog.vue:9-10
|
||||
|
||||
> **[销账 wf wys30viqi·2026-06-17]** 8 agent 文件域隔离核验修复(独立 grep 核验源码形态 + cargo check --workspace EXIT 0 + vue-tsc EXIT 0)。
|
||||
> - **已修 15**:BUG-02 file_info 流式读 .take(8192) / 03 validate_path percent_decode 词法归一化(+percent-encoding 依赖) / 05 try_continue 5lock→ContinueSnapshot 快照收敛+spawn 前重检 / 06 saturating_add(含 ContextUsage 周边) / 07 LCS_MAX_LINES=1000 双>1000 跳 DP / 09 max_depth clamp(1,10) / 11 read_file 默认 500 行+has_more;UX-08 catch toast+保留旧列表 / 09 startListener try/catch+console.error / 10 AiError clearAllApprovalTimers+清 pendingApprovals / 14 STREAM_TIMEOUT_MS 共享常量+reactive toast / 17 toolGroup i18n 14key / 18 isToolFailure 正则收窄^行首锚 / 19 stopChat try/catch+watchdog 复用 / 26 stopListener _startPromise=null。
|
||||
> - **误判销账 6**(审查报告 file:line 漂移/已修未销账,独立核验拦下未引入防御性反模式):BUG-08 WorkflowRepo 是 Arc clone 非连接池(crud.rs:81 new 仅 db.conn() clone,workflow.rs:292 注释已正确) / UX-02 ProviderPanel.vue:318-334 已有 revert 三分支 / UX-03 catch 已 fallthrough+execCommand 布尔分流 copyFailed / UX-04 walker.nextNode 已正确推进(旧 ?? nextNode 模式已不存在) / UX-11 AiChat.vue:1234 watch activeConversationId 已清 modelOverride(非 useAiSend.ts) / UX-15 regenerate 只 pop AI 气泡+editMessage 只换 content,前后端均不丢 parts。
|
||||
> - **留观察 1**:BUG-10 skills OnceLock 首次阻塞 tokio worker 数十ms 非热点,正确修法 skills_cached()→async+spawn_blocking 跨 read_skill_content/ai_list_skills 签名超本批文件域边界,接受当前行为。
|
||||
|
||||
#### ℹ️ 架构观察(INFO · 2 项·不进修复队列)
|
||||
|
||||
- [ ] **UX-260617-28 [INFO]** — **双监听器同通道 fragility** — useAiEvents + useAiContext 各自 listen('ai-chat-event'),人工协调防双重处理(AiCompressing flag)非架构保证。未来新增事件处理可能触发双重 bug。长期考虑单一分发器模式。— src/composables/ai/useAiEvents.ts:269 + src/composables/ai/useAiContext.ts:85-105
|
||||
|
||||
Reference in New Issue
Block a user