新增: Phase2 阶段收尾(Sprint 1-20)

重构:删 5 零引用 crate(df-evolve/plugin/stages/task/traceability)+ 清死模块、ai.rs 拆 11 子 module、ai.ts 拆 6 composable、i18n 拆目录
功能:知识库全栈(df-project/scan + CRUD + 时间线 + 前端)、Settings 拆分、appSettings KV 迁移、模型池、LLM 并发 Semaphore
修复:审批持久化根治、ConditionEngine 默认拒绝、NodeRegistry unimplemented 清除、promote 补偿删除、工具结果截断 50KB、路径校验防 symlink 逃逸
文档:B-03 人工审批设计、决策记录三分档、规格契约自检、经验记录、todo 看板、PROGRESS 更新

详见 PROGRESS.md。src-tauri/儿童每日打卡应用/ 与本项目无关,已排除。
This commit is contained in:
2026-06-14 14:08:20 +08:00
parent 98393b4908
commit cf017f81e2
167 changed files with 19549 additions and 6886 deletions

View File

@@ -1,6 +1,6 @@
# DevFlow — 项目进展与工作交接
> 创建: 2026-06-10 | 最后更新: 2026-06-12 | 当前阶段: Phase 2 aichat UX 快赢A 路线)+ 技能联想需求调研Sprint 8
> 创建: 2026-06-10 | 最后更新: 2026-06-14 | 当前阶段: list_directory 防爆 + localStorage→SQLite 统一持久化 + token/发送 bug 修复(Sprint 19) → 项目管理模块代码审查 + 全局核对(Sprint 20未改代码)
---
@@ -13,47 +13,45 @@
| 路径 | `E:/wk-lab/devflow/` |
| 架构文档 | `ARCHITECTURE.md` (22,745 字) |
| Git 状态 | 未首次 commit代码全在 untracked |
| AI 能力 | df-ai OpenAI 兼容 Provider + 12 工具 + Agentic Loop |
| AI 能力 | df-ai OpenAI/Anthropic 双协议 Provider + 12 工具 + Agentic Loop |
---
## 二、代码规模统计
### Rust 后端 (71 个 .rs 文件)
### Rust 后端 (78 个 .rs 文件)
| Crate | 文件数 | 总行数 | 有效行 | 实现程度 |
|-------|--------|--------|--------|---------|
| df-core | 4 | 259 | 151 | ✅ 完整 — 错误/事件/状态枚举/ID生成 |
| df-workflow | 7 | 489 | 333 | ✅ 核心 — DAG拓扑排序/执行器/状态机/事件总线 可用 |
| df-storage | 4 | 294 | 217 | ✅ 部分SQLite连接/迁移/建表完整,**缺 CRUD 层** |
| df-core | 4 | 429 | ~260 | ✅ 完整 — 错误/事件/状态枚举/ID生成 |
| df-workflow | 9 | 908 | ~620 | ✅ 核心 — DAG拓扑排序/执行器/状态机/事件总线 可用 |
| df-storage | 5 | ~2,100 | ~1,400 | ✅ 完整 — 连接/迁移/建表(V1-V8) + impl_repo! 宏 CRUD + KnowledgeReposearch/list_by_status/set_embedding/search_vector 等)+ 余弦相似度工具函数 |
| df-execute | 5 | 203 | 129 | ⚡ 混合 — Shell 执行器真实可用Docker/SSH/Git 骨架 |
| df-ideas | 6 | 421 | 278 | ⚡ 大部分 — 捕获/评估/晋升/关联图 有逻辑,评分固定值 |
| df-task | 5 | 390 | 252 | ⚡ 大部分 — Task/Branch/Semver 可用,合并冲突 骨架 |
| df-ideas | 7 | 761 | ~500 | ✅ 评分/对抗启发式已真实化Sprint 9— 捕获/评估/晋升/关联图 有逻辑,晋升/关联图仍骨架 |
| df-project | 5 | 272 | 175 | ⚡ 混合 — 数据模型/Timeline 可用,调度器 骨架 |
| df-ai | 6 | 281 | 173 | 🔧 接口 — 类型/Provider trait 完整,无实际 LLM 调用 |
| df-traceability | 4 | 312 | 201 | ⚡ 混合 — 决策记录/标注构建 可用SQLite查询 骨架 |
| df-plugin | 4 | 255 | 158 | ⚡ 混合 — Host/Builder 有逻辑,核心加载 骨架 |
| df-evolve | 6 | 301 | 172 | ⚡ 混合 — Knowledge/PromptTemplate 可用,引擎/提取器 骨架 |
| df-nodes | 9 | 344 | 277 | ⚡ 混合 — script_node 真实可用(接 Shellhuman_node 半实现(审批响应 TODO其余 6 种骨架 |
| df-stages | 6 | 287 | 209 | 🔩 全骨架 — 11个阶段节点 Schema 完整execute() 全空 |
| **合计** | **71** | **~4,108** | **~2,625** | |
| df-ai | 9 | 1,965 | ~1,300 | ✅ 完整 — OpenAI/Anthropic 双协议 Provider + 流式 SSE + 上下文窗口(ContextManager 分组滑窗) + token usage 解析 + 12 工具 |
| df-nodes | 9 | ~500 | ~350 | ⚡ 混合 — script_node接 Shell/ ai_node接 df-aiSprint 7真实可用human_node 半实现(审批响应 TODO其余骨架 |
| **合计** | **53** | **~7,400** | **~4,800** | 已删除 5 个零引用 crate2026-06-14原 78/9100/5900 |
### 前端 (9 页面 + Store + i18n)
### 前端 (9 页面 + 2 组件 + Store + i18n)
| 类别 | 文件数 | 行数 | 状态 |
|------|--------|------|------|
| Vue 页面 | 9 | ~3,372 | ✅ UI 全部真实 — 无空壳 |
| Pinia Store | 4 | ~362 | ⚠️ 有 state/getter 但**无 actionView 未引用** |
| Router | 1 | 63 | ✅ 9 条路由含动态路由 |
| i18n | 2 | ~94 | ⚠️ 翻译完整但**未接入 main.ts** |
| Vue 页面 | 9 | ~3,372 | ✅ UI 全部真实 — 无空壳(含 AiHome/AiDetached|
| Vue 组件 | 2 | ~1,400 | ✅ AiChat主面板+ ConfirmDialog |
| Pinia Store | 4+ | ~800 | ✅ composable 模式View 已引用Sprint 4 接入)|
| Router | 1 | ~90 | ✅ 10 条路由含动态路由Sprint 7 增 AiHome/AiDetached|
| i18n | 2 | ~94 | ✅ 已注册 main.tsSprint 7+ localStorage 持久化 |
| 设计系统 | 1 | 105 | ✅ CSS 变量/动画/Arco 暗色覆盖 |
| Tauri Commands | 1 | 13 | 🔩 仅 `greet` 示例,无业务逻辑 |
| **前端合计** | | **~8,812** | |
**前端关键问题**
- 所有 View 组件数据**硬编码** (`ref([...])`),与 Store 完全独立
- 所有按钮事件处理函数为**空函数** `{}`
- i18n 插件未注册到 Vue app
- Arco Design 组件库未实际使用(仅 CSS 变量覆盖)
> Tauri Commands 已达 **57 个**project/task/idea/workflow + AI 对话/工具/审批/Provider/技能全功能 + 知识库 11 个),见后端 src-tauri/src/commands/。
**前端关键问题**Sprint 4/7 已全部解决):
- ~~所有 View 组件数据硬编码~~ ✅ Sprint 4 接 Store 真数据
- ~~所有按钮事件处理函数为空函数~~ ✅ Sprint 4 接 Store action
- ~~i18n 插件未注册~~ ✅ Sprint 7 注册 + $t() 全 view 改造
- ~~Arco Design 组件库未实际使用~~ ✅ 已用(表单/弹窗/消息等CSS 变量覆盖暗色
---
@@ -68,11 +66,11 @@
待打通路径(骨架就位,需填充):
df-workflow → df-nodes (8种节点 execute() 待实现)
df-workflow → df-stages (11种阶段节点 execute() 待实现)
df-ai → LlmProvider 实现 (无 HTTP client)
df-storage → 所有 crate 的 CRUD 操作
Tauri commands → Rust 业务逻辑
Vue Views → Pinia Store → Tauri IPC → Rust
~~df-workflow → df-stages (11种阶段节点 execute() 待实现)~~ — df-stages 已移除2026-06-14 零引用清理)
~~df-ai → LlmProvider 实现~~ ✅ 已打通OpenAI/Anthropic 双协议真实 HTTPSprint 5/8
~~df-storage → 所有 crate 的 CRUD 操作~~ ✅ 已打通impl_repo! 宏 CRUD + 多 RepoSprint 2
~~Tauri commands → Rust 业务逻辑~~ ✅ 已打通47 commands 全接业务Sprint 3
~~Vue Views → Pinia Store → Tauri IPC → Rust~~ ✅ 已打通Sprint 4
```
---
@@ -89,6 +87,7 @@
| 6 | **条件表达式引擎** — 仅支持 true/false 字面量 | 条件分支不可用 | P2 | ⬜ 待办 |
| 7 | **i18n 未注册** — 翻译文件存在但未挂载 | 多语言不生效 | P2 | ✅ Sprint 7 |
| 8 | **未 git commit** — 代码全 untracked | 无版本基线 | P0 | ✅ Sprint 2 |
| 9 | **AI 删项目绕过软删** — tool_registry:263 `repo.delete` 物理删IPC 走 `soft_delete` 进回收站AI 层缺 restore/purge/list_trash 工具(仅 project 表有回收站设计,故最该修) | AI 对话删项目 = 数据丢失不可恢复,与 UI 删语义割裂 | P1 | ⬜ Sprint 20 待修批1 |
---
@@ -121,9 +120,9 @@
| AI Chat 面板 | ✅ | 侧边栏 + 分离窗口 + 拖拽调宽 + 对话管理 |
| Agentic Loop | ✅ | 多轮工具调用循环max 10 轮)+ 中/高风险人工审批 |
| AI Node 实现 | ✅ | df-nodes 接 df-aiconfig 驱动 providerbase_url/api_key/model/prompt→ OpenAICompatProvider.complete → 输出 text/model/usage注册 "ai" 节点;未端到端实测 |
| **AI Chat LLM 优化** | 🚧 P0 完成 | 任务 #43P0 可靠性(超时/断连/停止生成P1 token 控制usage采集/滑动窗口/摘要)⬜ | |
| **AI Chat LLM 优化** | ✅ ABCD 完成 | 任务 #43P0 可靠性P1 上下文窗口ContextManager 分组滑窗)✅ + 并行化(工具 join_all / save 后台)✅;**Sprint 14 流式 token 用量记录usage 解析 + 累加落库 + 展示 + Settings 开关)✅**Part C 并发 Semaphore双层 + 运行时可调)+ Part D Settings UI ✅Sprint 16Review 两轮 8 修复 ✅ | |
### Phase 3 — 想法池 + 多项目 (3-4 周) | ⬜ 未开始
### Phase 3 — 想法池 + 多项目 (3-4 周) | 🚧 进行中 — Sprint 9 评估闭环已通(启发式评分 + 对抗评估接 IPC晋升前端层闭环多项目/关联图待续Sprint 12 全面审查修 5 项前端 bug置信度条/状态选择/删除确认等),死代码组缓另会话重审
### Phase 4 — 节点丰富 + 阶段插件 (3-4 周) | ⬜ 未开始
### Phase 5 — 体验打磨 (4-6 周) | ⬜ 未开始
@@ -318,7 +317,7 @@
- **审查项落地**:删全屏 Tool Approval Modal保留行内卡片审批、错误友好化`friendlyError` 正则映射 404/401/timeout/network → 中文提示 + `isError` 红色气泡)、智能滚动(`isNearBottom` < 80px 阈值、provider bar 点击切换、未配 provider 空状态引导、删死 class
- **B 路线(规划式多智能体)单独立项**:填 `coordinator.rs` + `conditions.rs` 空壳,详见 memory `aichat-decision-capability`
**B. 技能联想功能需求(本轮重点,未实现,需求阶段**
**B. 技能联想功能(首批 Claude 3 类,已实现待实测**
- **需求**aichat 输入框输入 `/` → 联想列出本机 Claude 技能SKILL.md按输入过滤选中插入 `/name`;发送时后端读 SKILL.md 全文注入 system prompt / context
- **首批数据源 = Claude 3 类**SKILL.md frontmatter 统一 `name` / `description` / `user_invocable` / `metadata.argument-hint` / `triggers[]`,只取 `user_invocable: true`
1. Claude skills`~/.claude/skills/*/SKILL.md`23 个sleep / mission-control / idea / cpa 等)
@@ -338,10 +337,347 @@
**代码变更**A 路线 — `crates/df-ai/src/{anthropic_compat.rs, lib.rs}``src-tauri/src/commands/ai.rs``crates/df-nodes/src/ai_node.rs``src/views/Settings.vue``src/stores/ai.ts``src/components/AiChat.vue``src/api/types.ts`
**遗留问题 / 下一步**
1. **技能联想B实现**需求已记,首批聚焦 Claude 3 类,等排期(工作量中:后端扫文件 + IPC、前端联想浮层
1. **技能联想B实现待实测**`ai_list_skills` IPC扫 skills/commands/plugins 三类 + frontmatter 解析 + name 去重)+ `ai_chat_send``skill` 参数读 SKILL.md 注入 system prompt + 前端 `/` 浮层(↑↓ 导航 / Enter·Tab 选中 / chip 显示 / Esc 关。cargo check ✓7 warning 既有)/ bun build ✓4.68s)。实测:重启 dev → AiChat 输入 `/` → 选技能 → 发送
2. **A 路线剩余场景实测**:切对话不中断(场景 2/3、错误友好化场景 4待用户实测
3. **B 路线(规划式能力)**coordinator / conditions 空壳,单独立项
### [Sprint 9] 2026-06-12 — 灵感模块评估闭环(启发式评分 + 对抗评估接 IPC
**工作内容**
- **df-ideas 修复与真实化**:① 修 adversarial.rs E0308 类型错(`AdversarialEval.negative: Argument` vs `generate_negative_argument``CounterArgument` 直接赋值df-ideas 实际编译不过——前文档"cargo check 通过"为误记)→ 删 CounterArgument、正反方归一 Argument② scoring.rs 三维固定 5.0 → 内容启发式priority / 描述充实度 / tags / 中英关键词clamp 0-10③ adversarial.rs 正反方论点/evidence 基于真实 idea 内容生成confidence 由评分驱动final_score=综合评分AssessmentLevel 由 overall 映射
- **devflow 接 df-ideas**`src-tauri/Cargo.toml` +df-ideas +chrono 依赖df-ideas 此前为孤儿 cratedevflow 未依赖、零 IPC 接入)
- **evaluate_idea IPC**commands/idea.rs取 IdeaRecord → record_to_idea 转 df-ideas::Idea → ScoringEngine + AdversarialEngine.evaluate → 组装前端扁平结构(对齐 Ideas.vue AdversarialEval interface→ 写回 scores中文维度 0-100/score0-100/ai_analysis/status=pending_review → 返回更新记录lib.rs 注册
- **前端接真实评估**api/idea.ts +evaluatestores/project.ts +evaluateIdea actionIdeas.vue 删 mockEval 调真实 + evaluating loading 态
- **审核修 2 bug**:① recommendation 大小写(后端原 "With Resources" 与前端 assessmentLabel 全小写 map key 不匹配致中文标签不显示)→ 全小写空格;② assessmentClass 生成的 class 与 CSS 类名不一致致 badge 无色 → map 映射到 .immediate/.soon/.conditional/.revised/.defer/.cancel
**代码变更**df-ideas/{scoring,adversarial}.rs、src-tauri/{Cargo.toml,commands/idea.rs,lib.rs}、前端 {api/idea.ts,stores/project.ts,views/Ideas.vue}8 文件)
**验证**cargo check -p df-ideas ✓、cargo check -p devflow ✓、bun run build ✓vue-tsc + vite 3.3s
**遗留问题 / 下一步**
1. 对抗评估仍启发式,未接 df-ai LlmProvider设计LLM 生成正反方论点 + 启发式 fallback
2. promotion.rs do_promote 仍 TODO晋升走前端 createProject 闭环,不经 df-ideas/promotion
3. evaluate_idea 用 list_all().find() + 5 次 update_fieldIdeaRepo 无 get/多字段更新,量小可接受)
4. IdeaGraph 关联图零接入(自动关联发现/聚类待续)
5. scores JSON 含「综合」维度也被雷达图渲染一行(小瑕疵)
### [Sprint 10] 2026-06-12 — AiChat 工具卡片自动折叠(卡片级折叠 + 新内容追加自动收起)
**工作内容**
- **需求**对话中工具调用卡片List Projects / List Tasks / Create Idea / List Ideas / 读取文件等)完成后仍整卡铺开,多步调用时界面臃肿。目标——展示更友好紧凑:所有卡片可点击 header 展开/收起,新内容追加时旧卡片自动收起为单行 header类似 ChatGPT/Cursor 旧 tool call 折叠)
- **卡片级折叠**(区别于 read_file 已有的内容级折叠):`.ai-tool-card` 内 body 区(骨架屏/审批/拒绝/file/dir/write/通用结果)包进 `.ai-tool-body``v-show` 控制显隐header 加 `@click` + ▸ 箭头指示器;新增 `expandedCards` Set + `toggleCardExpand` + `cardCollapseClass`,与既有 `expandedTools`read_file 预览级)职责分离不互相干扰
- **自动收起**deep watch `store.state.messages` + 轻量 JSON snapshot diff 检测新内容(新消息 / toolCall 状态变化 / 文本增长)→ 清除旧 completed/rejected 的展开态,保留 running/pending 活跃卡片;`isFirst` guard 防首次加载/切对话误触发
- **running/pending_approval 强制展开**(需看骨架屏与审批按钮);`v-show` 保留 DOM 避免重挂载
**代码变更**`src/components/AiChat.vue`template header/body 包裹 + script 状态与 watcher + style 折叠态),单文件 7 处改动
**验证**vue-tsc --noEmit ✓(运行时待 `bun run tauri dev` 实测多步工具调用折叠效果)
**遗留问题 / 下一步**
1. ~~审查项 ①~~ ✅ 已落地2026-06-12`isRunningOrPending(status)``shouldKeepOpen(tc)``running` / `pending_approval` / `rejected` / `write_file` 强制展开(短结果不折叠、原因/路径不丢失),仅 `read_file` / `list_directory` / 通用 JSON 大体量结果折叠。vue-tsc --noEmit ✓。决策详见 [功能决策记录 - 短结果保持展开](docs/02-架构设计/功能决策记录.md)
2. 实测验证tauri dev 发多步工具调用消息,观察"执行中展开→完成→新内容追加自动收起→点击 header 重展开"
### [Sprint 11] 2026-06-13 — AI Chat LLM 优化(上下文窗口管理 + 并行化)
**任务 #43 续**Part A + B 落地Part C/D 待续)
**工作内容**
**Part A: 上下文窗口管理df-ai/context.rs + ai.rs 接线)** — 长对话无限增长致 `context_length_exceeded` 死锁
- **A1 ContextManager**`crates/df-ai/src/context.rs` 新增 ~350 行TokenEstimator 字符粗估chars×0.35 + per_message 4 + per_tool_call 30零依赖保守 ±15%+ ContextConfigmax_tokens 128k / output_reserve 8192 / safety 0.85+ 分组滑动窗口淘汰——淘汰单元保工具调用三元组原子性ToolCallHead + ToolResultTail* + 紧随文本 Assistant 同进同出),保护区最后 6 条永不裁裁剪仅影响发送视图build_for_request 返裁剪 Vec不影响持久化all_messages_clone 返全量。5 单测全绿(短对话无裁剪 / 超预算裁剪保保护区 / 三元组原子性双分支 / replace 重估 token / restore 重建缓存)
- **A2 ai.rs 接线**~15 处AiSession.messages 类型 `Vec<ChatMessage>``ContextManager`;核心 run_agentic_loop 用 `build_for_request(sys_tokens)` 替代全量 `.clone()`save/title 用 `all_messages_clone()`switch 用 `restore_from_messages()``replace_tool_result` 收敛为 ContextManager 方法DRY删自由函数
**Part B: 并行化改造ai.rs** — 串行瓶颈 + Completed 事件阻塞
- **B1 process_tool_calls 并行化**Low 风险工具 `futures::future::join_all` 并行 execute + 即时 emit Completed结果串行回填 session.messagesN 个独立工具 ≈ 最慢一个耗时,原 N 倍串行Med/High 仍串行审批门控。tool_result push 顺序变化无语义影响LLM 按 tool_call_id 关联,不看绝对位置)
- **B2 正常完成后台化**save+extract+title 打包同一 `tauri::async_runtime::spawn`(非裸 spawn save——保 maybe_spawn_extraction 读已落库消息的顺序依赖Completed 事件即时下发
- **B3 标题后台化**`ensure_conversation_title` 签名收 `provider_config` 克隆进 task 自建 provider`&dyn` 非 'static 无法 move`spawn_ensure_title` 后台(含 2 处 stop 路径)
**关键取舍**:①打包 spawn 而非裸 spawn save保 extract 顺序依赖);②并发 upsert 低概率丢少量 token 可接受(非功能错误);③停止路径保持同步 save避免 stop 后即发新消息的并发 upsert 竞态丢 token
**代码变更**`crates/df-ai/src/context.rs`(新增)、`src-tauri/src/commands/ai.rs`(核心改造)、`docs/02-架构设计/功能决策记录.md`8 条新决策Part A 2 + Part B 3 + 既有的)
**验证**cargo check -p df-ai ✓5 单测绿、cargo check -p devflow ✓6 既有 warning无 error无单测回归
**遗留问题 / 下一步**
1. **Part C/D 未做**todo #48-52 已建)—— Part C 双层 Semaphoreglobal 默认 3 / per_conv 默认 2+ 3 LLM 调用点stream_llm / 标题 / 提炼)加 permit + `ai_set_concurrency_config` commandPart D Settings.vue 两 setting-row + localStorage 持久化 + onMounted 同步
2. **实测验证**P1tauri dev 验证长对话裁剪行为 + 多工具并行耗时 + Completed 事件即时性
### [Sprint 12] 2026-06-13 — 灵感模块全面审查 + A 类问题修复
**工作内容**
- **df-ideas 灵感模块全面审查**(前端 Ideas.vue / api / store + IPC idea.rs + crate 7 文件 + df-project/manager + df-storage/crud按「界面展示 / 交互 / 功能可用性 / 合理性」+「功能架构 / 代码逻辑 / 代码架构」六维逐条核对,共 12 项发现🔴5 🟡5 ⚪2。复核确认 12 项全部真实存在、无误判无虚报。
- **修复 A 类 5 项**(明确知道怎么做、零争议,全在 Ideas.vue
- ① 置信度进度条不显示填充(`::after` 无 width + 锚点跑到 `.debate-column`)→ 拆 `.confidence-bar`(灰轨)+ `.confidence-fill`(填充层,正绿反红),删失效 `::after`
- ② 状态 select 改选不生效v-model 绑只读 computed 致写失败、回弹并写回旧 status→ 弃 v-model`:value` + `@change``event.target.value`
- ③ 删 `filterIdeas` 空函数及其 `@input` 绑定filteredIdeas 本是 computed 自动响应)
- ④ 删除想法加 `confirm()` 二次确认
- ⑥ 对抗评估标题加「启发式」tag诚实标注当前为启发式非 LLM避免「对抗辩论」措辞误导
- **决策**:死代码/双套抽象组⑦⑧⑨⑩缓到另一会话届时重新审核问题真实性B 类(⑤⑥根治⑪⑫)方案未定,待定方向后再推。
**代码变更**`src/views/Ideas.vue`(单文件 9 处:模板 5 + script 3 + CSS 2 段)
**验证**`vue-tsc --noEmit` ✓(零错误零输出)
**遗留问题 / 下一步**
1. **B 类(有必要但方案未定)**:⑤ 立项引导(三种改法改变产品流程语义:放宽显示条件 / 保持 approved 门槛加提示 / 评估达标自动 approved/ ⑥ 对抗评估接 df-ai LlmProvider 根治(大工程,单独立项;当前 UI「启发式」标记为临时绕过/ ⑪ 状态常量集中(跨 Rust+TS 双侧IdeaStatus 枚举已有但 IdeaRecord 用 String 落库)/ ⑫ 实体↔Record 映射(评估为合理分层,建议不改)
2. **缓组(另会话重审真实性后再动)**:⑦ df-ideas 死代码空壳capture/graph/evaluator/promotionIdeaGraph 关联图是已知下一步增强需求,删/留需定)/ ⑧ 两套 Recommendation 枚举 + 两套评估入口并存adversarial 6 变体实用 vs evaluator 5 变体仅死代码引用)/ ⑨ PromotionPolicy 三档死枚举 / ⑩ Idea 实体构造分散record_to_idea 与 IdeaCapture::capture 字段重叠)
3. **实测验证**tauri dev 看置信度条彩色填充 / 状态切换生效 / 删除弹确认 / 评估区「启发式」标
### [Sprint 13] 2026-06-13 — 文档记录治理体系(路由规范 + decision-record skill + 降频自检 hook
**背景**:功能决策/需求散落于对话、PROGRESS、模块文档缺统一真相源与触发机制。建立「单一真相源 + 自动自检」治理体系。
**工作内容**
- **文档记录规范**`docs/02-架构设计/文档记录规范.md` 新建核心原则SSOT / 不复制只引用 / 决策与流水分离 / 先主后辅)+ 文档职责矩阵(每类信息唯一主文档)+ 内容路由表 + 更新顺序 + 唯一性记录与检测(记前 grep 查重 / 单向引用 / 定期扫描)+ 与 skill 关系 + 治理体系实现决策hook 设计取舍)
- **功能决策记录扩展**`docs/02-架构设计/功能决策记录.md`):约定节加需求条目说明;末尾新增「需求与待办」总览(📋 待做需求表 + 需求澄清)——散落各决策条目 📐/🚧 状态的待办汇集为单一清单
- **decision-record skill 增强**`~/.claude/skills/decision-record/SKILL.md`):除「为什么这么定」决策,增记需求细节(待做/规格/澄清);维护规则(记前查重 / 演进 `→` 标注 / 定期压缩防爆炸);原则补「更新优先于新增」
- **降频自检 Stop hook**`~/.claude/hooks/dr-check.sh` + `settings.json` Stop 配置):累计 ≥10 轮 或 (>1 轮 且 距上次 ≥10 分钟) 才注入自检提示触发 skill纯脚本计数无 API替代每轮自检省 ~90% token`stop_hook_active` guard 防循环;状态按项目隔离(`~/.claude/.dr-state/`,不污染 git。设计取舍详见 [文档记录规范 - 治理体系实现决策](docs/02-架构设计/文档记录规范.md)
- **修 `docs/INDEX.md` 误登记**PROGRESS 实际在根级,移除 `07-项目管理/` 树下的重复登记行
**代码变更**:非产品代码——`docs/02-架构设计/{文档记录规范.md,功能决策记录.md,INDEX.md}``~/.claude/{skills/decision-record/SKILL.md,hooks/dr-check.sh,settings.json}`
**验证**hook 逻辑实测(首战静默初始化 / 2-9 轮静默计数 / 第 10 轮或 ≥10 分钟触发 / 防循环 guard无 jq 依赖纯脚本
**遗留问题 / 下一步**
1. hook 实际长期触发频率待观察10 轮 / 10 分钟阈值是否合理,按需调)
2. 决策爆炸后执行首次压缩(> 300 行 / 老 Sprint > 3 / 单域 > 10 条触发归档或拆域)
### [Sprint 14] 2026-06-13 — 流式 token 用量记录 + Provider 默认态持久化
**工作内容**
**A. 流式 Token 用量获取 + 记录 + 展示 + 设置开关**(跨 df-ai/df-storage/src-tauri/前端11 文件)— `stream_llm` 全程丢弃 token 计数、`AiCompleted.total_tokens` 恒 0 的旧疾根治Sprint 6 P1 token 控制中「usage 采集用户叫停」项重启落地):
- **Provider 层 usage 解析**`StreamChunk``usage: Option<TokenUsage>`OpenAI 开 `stream_options:{include_usage:true}` 末 chunk 取累计 usageAnthropic `message_start`/`message_delta` 累积output_tokens 当累计值覆盖,非增量)
- **累加落库**`ai_conversations``prompt_tokens`/`completion_tokens`V5 迁移);`save_conversation` upsert 走累加模式(读旧值叠加,非覆盖——保审批暂停→恢复跨 loop 实例总用量正确);`run_agentic_loop` 局部累加器每轮叠加
- **前端展示 + 开关**store 双状态 `lastTokenUsage`(单次)+ `convTokenTotal`(对话累计,切对话从 DB 加载AI 气泡底部 token 条(默认关闭,`df-show-token-usage` 开关放 Settings
- **model 记录**:消息级 model + 对话级 models 数组C+B`default_model` 配置值补填不覆盖
**B. Provider 默认态持久化is_default 重启丢失 bug 修复)** — 「设为默认」重启后丢失、两条记录都显示「设为默认」按钮的 bug 根治:
- 根因:`is_default` 字段恒写 `false` + `ai_set_provider` 只改内存 session 不落库 → 重启 session 清零默认全丢
- 修复:`ai_set_provider` 互斥落库(目标 true/其余 false仅写变化记录`ai_save_provider` 新建首个自动默认;`ai_list_providers` 直返 DB 值;`active_provider_id` 降为运行时缓存
**代码变更**A — df-ai/{provider,openai_compat,anthropic_compat}.rs、df-storage/{models,crud,migrations}.rs、src-tauri/commands/ai.rs、前端 {types,stores/ai,components/AiChat,views/Settings}11 文件B — src-tauri/commands/ai.rs3 函数)
**验证**cargo check --workspace ✓0 error6 既有 warning、vue-tsc --noEmit ✓。**未 tauri dev 运行时实测**
**遗留问题 / 下一步**
1. tauri dev 实测token 落库 / 切换对话总量加载 / 重启保默认 / 首个自动默认
2. `ai_save_provider` get_by_id 双调用review 🟡①,冗余往返,待合并)
3. Settings 页面 UI 重构Part D用户说稍后
4. model UI 展示(暂缓)
### [Sprint 15] 2026-06-13 — 知识库 Tier 1 全栈打通 + Phase 5.5 向量检索
**工作内容**
**Tier 1 知识库双向闭环AI Chat ↔ 知识库,全栈打通)** — candidate→published 状态机 + AI 提炼 + 手动录入 + 知识注入:
**A. 存储层df-storageV7/V8 迁移)**
- V7 建表 `knowledges`id/kind/title/content/tags/status/confidence/reuse_count/verified/source_project/source_ref/created_at/updated_at3 索引
- V8 幂等补列 `embedding BLOB`PRAGMA table_info 探测,同 v4/v5/v6 模式)
- `KnowledgeRecord`models.rs`embedding: Option<Vec<u8>>`
- `KnowledgeRepo`crud.rs`search()`LIKE 双分支,按 kind 可选过滤)/ `list_by_status()`CASE WHEN confidence 语义排序)/ `increment_reuse_count()`SQL 原子 +1/ `top_used()`;向量扩展:`set_embedding()` / `search_vector()`(纯 Rust 余弦批量比较skip 维度不匹配);工具函数:`f32s_to_blob` / `blob_to_f32s` / `cosine_similarity`
**B. 领域层df-evolve**
- `KnowledgeStatus` 枚举Candidate/PendingReview/Published/Archivedsnake_case`from_str`/`as_str`
- `Confidence` 枚举High/Medium/Low同上
- `Knowledge` struct移除 `effectiveness` 字段,时间字段统一 String 毫秒(对齐全部既有 model
- `pattern.rs`:清理死参数 `result_quality: f32`
**C. IPC 层src-tauri/commands/knowledge.rs 新建11 个 Command**
- `knowledge_{list,get,search,create,update_status,record_reuse,list_candidates,archive,get_config,save_config,extract_now}`
- 状态转换合法矩阵硬编码candidate→{pending_review|published|archived}; pending_review→{published|archived}; published→{archived}
- `knowledge_archive`(软删除,匹配 `ai_conversation_archive` 语义)
- 配置读写:`knowledge_{get,save}_config`(读写 `AppState.knowledge_config: Arc<Mutex<KnowledgeConfig>>`
- 手动提炼:`knowledge_extract_now`
**D. AI 集成ai.rs知识注入 + 提炼)**
- `build_knowledge_context()``auto_inject` 开关 → `hybrid_search()` top-3 → `increment_reuse_count` fire-and-forget → 注入 system prompt 头部
- `extract_knowledge_from_conversation()`:后台 spawnmin_messages≥4 守卫 → 取最后 6 条消息 → LLM JSON 提炼 → 逐条写 candidate提炼失败仅 warn 不阻断
- `maybe_spawn_extraction()`agentic loop 两处正常退出统一调用(`OnComplete` 默认模式)
**Phase 5.5 — 向量检索Settings 开关,默认关闭)**
- `LlmProvider::embed()` trait 方法:默认返回 Erropenai_compat 实现 POST `/v1/embeddings`(按 index 排序)
- `KnowledgeConfig` 加三字段:`vector_enabled`(默认 false/ `embedding_provider_id`(排除 anthropic/ `embedding_model`
- `generate_embedding()`:截断 8000 字 → build_provider → embed()
- `spawn_embedding_for_knowledge()`:知识发布时 fire-and-forget 生成嵌入(不在 candidate 阶段浪费调用)
- `hybrid_search()`三层降级链——开关关→LIKE; embed 失败→LIKE; 正常→双信号排序(同时命中>仅 LIKE>仅向量 cos≥0.3);不引入 sqlite-vec规避 Windows MSVC C 扩展编译风险)
- `Settings.vue`:语义检索开关 + v-if 联动 embedding provider 下拉 + 模型名输入
**E. 前端TypeScript + Vue**
- `types.ts``KnowledgeRecord` / `CreateKnowledgeInput` / `KnowledgeConfig`(含 vector 三字段)
- `api/knowledge.ts`新建11 个 invoke 封装)
- `stores/knowledge.ts`完全重写getter 模式,消除全部 15 条 mock + localStorage
- `Knowledge.vue`(完全重写:知识库/审核收件箱双 Tab + 状态徽章 + confidence 指示器 + 新增对话框 + 候选 badge
- `App.vue`:侧栏候选 badge`candidateCount` refstore loadCandidates 后更新)
**F. 配置设计**AppState 内存 + IPC非 Tauri config 插件):
- `KnowledgeConfig`state.rsauto_extract / trigger_mode / min_messages / idle_timeout_ms / auto_inject / vector_enabled / embedding_provider_id / embedding_model
**代码变更**df-storagemodels.rs/crud.rs/migrations.rs/ df-evolveknowledge.rs/pattern.rs/ src-tauristate.rs + commands/knowledge.rs 新建 + commands/ai.rs + lib.rs/ 前端api/types.ts + api/knowledge.ts 新建 + api/index.ts + stores/knowledge.ts + views/Knowledge.vue + views/Settings.vue + App.vue。约 1,400 行 Rust + 700 行 TS。
**验证**cargo check 0 error ✓vue-tsc 0 error ✓。**未 tauri dev 运行时实测**
**遗留问题 / 下一步**
1. tauri dev 实测 10 项功能验证清单(手动录入 / 审核流 / 归档 / 检索注入 / reuse_count / AI 提炼 OnComplete / AI 提炼 Manual / 配置修改 / 注入开关 / 矛盾场景)
2. 向量检索待实测(需配 embedding provider + 开启开关 + 发布 ≥1 条知识后验证混合排序)
3. Tier 2 待做ai_node prompt 注入 / 工作流 NodeFailed→pitfall / 决策记录→architecture_pattern前置 traceability 持久化)
4. 知识库 API 对外暴露MCP Shell 封装,外部工具 Claude Code/CodeX/Cursor 使用)
### [Sprint 16] 2026-06-13 — AI Chat LLM 优化收尾(Part C/D + Review 修复) + AI Node 单测
**工作内容**
- **Part C LLM 并发控制**`state.rs` 新增 `LlmConcurrency`(双层 `Arc<Mutex<Arc<Semaphore>>>` — 全局默认 3 / 单对话默认 2,运行时替换内层 Arc 重建);`ai.rs` 3 个叶子 LLM 调用点(stream_llm / generate_title / extract_knowledge)加 permit,acquire 顺序固定 global→per_conv 防死锁,stream 后显式 `drop` 不占工具执行槽;新增 `ai_set_concurrency_config` command(运行时调并发上限);`lib.rs` 注册
- **Part D Settings UI**`Settings.vue` 通用设置区加「全局最大并发 / 单对话并发」两 setting-row + 前端 clamp(1-10 / 1-5)+ debounce 300ms + localStorage 持久化 + onMounted 启动同步 + onUnmounted 清 timer
- **Review 两轮 8 修复**:首轮 6(① per_conv 单例语义注释 / ② save-extract 并发注释改正 / ③ permit 显式 drop / ④ Settings clamp / ⑤ 合并 to_chat_messages 进 all_messages_clone / ⑥ system prompt 超 budget warn)+ 复审 2(后端 set_concurrency 补 clamp 边界对齐前端 / onUnmounted 清 debounce timer)
- **AI Node 单测**`ai_node.rs` 重构抽 `parse_params` 纯函数(execute 参数解析剥离,单测不 mock LLM 零网络)+ 7 单测(缺参×3 / prompt 上游优先回退 / config 取值 / 可选默认值 / 显式参数解析)
- **任务收尾**#43/#44 → completed(代码 + 单测全绿,GUI 实测转跟踪);新增 #54(GUI 动态实测跟踪任务)
**代码变更**
- `crates/df-ai/src/context.rs`(Review ⑤⑥ — 合并 to_chat_messages / system prompt 超 budget warn)
- `src-tauri/src/state.rs`(LlmConcurrency 双层 Semaphore + per_conv 单例语义注释)
- `src-tauri/src/commands/ai.rs`(permit×3 + drop / process_tool_calls join_all 并行 / save 后台 spawn / ai_set_concurrency_config command + clamp)
- `src-tauri/src/lib.rs`(注册 ai_set_concurrency_config)
- `src/views/Settings.vue`(并发 UI + clamp + debounce + onUnmounted)
- `crates/df-nodes/src/ai_node.rs`(parse_params 重构 + 7 单测)
- `docs/02-架构设计/功能决策记录.md`(新增「AI Node」域记 parse_params 决策 + per_conv 退化条目)
**验证**cargo check 0 error ✓ / df-ai context 5 单测 ✓ / df-nodes ai_node 7 单测 ✓ / vue-tsc 0 error ✓。**未 tauri dev 运行时实测**(转 #54 跟踪)
**遗留问题 / 下一步**
1. **#54 GUI 动态实测**(用户跑 tauri dev,Claude 核对日志):长对话裁剪(context_trimmed 日志 + DB 全量)/ 多工具并行(Low join_all 时序)/ save 异步不阻塞 Completed / 双层 Semaphore 限流(多对话撞 RPM)/ Settings 并发即时生效 + 刷新保持 / DAG ai 节点真调 LLM
2. ~~AI Node 可补 GLM 集成测试~~ ✅ 已补并通过:`glm_live_complete`(`#[ignore]` + env var)真调 GLM glm-4-flash 返回"通过",usage 解析正确(provider 调用层验证;GUI DAG 触发仍属 #54)
### [Sprint 17] 2026-06-13 — 模块文档↔代码一致性审查(4 文档纠错补全)
**工作内容**:
- **审查范围**:docs/03 模块文档(df-ai / df-storage / df-workflow)+ docs/01 技术文档(SQLite-CRUD 模式)共 4 份 vs 对应 crate 代码,三代理并行审查
- **🔴 硬伤 28 全修**:df-ai(LlmProvider trait 签名 / 删 OpenAI 虚构 idle-timeout + finished_received / ContextManager 方法名 replace_tool_result_content + build_for_request 返回元组 / Token 公式 / Anthropic usage take() / 工具归属)/ df-storage(V1 表名 / Repo 表名 releases·workflow_executions / search published 过滤 / increment_reuse_count updated_at / cosine epsilon / blob 截断)/ SQLite-CRUD 整篇过时(表 6→11 / CRUD 待→已 / 时间 INTEGER→TEXT / 写返回 ()→String·bool / 连接池→单连接 / schema.rs→migrations.rs)/ df-workflow(Node trait 按值 + 默认 false + node_type / 文件名 conditions·eventbus / 虚构事件区分已发未发)
- **⚪ 虚构 7 全清**:df-workflow(阻塞节点「等待人工操作」标未实现 / 持久化快照删改仅内存态 / 断点续跑补无暂停恢复机制)/ df-ai(conditions.rs 不存在,清状态表 + 决策缺口表虚构引用 / AiToolRegistry「12 工具」夸大改基础设施)
- **🟡 核心 8 + 碎琐 10 补全**:df-ai(apply_openai_sse / apply_anthropic_event 纯函数 / ContextManager 6 pub 方法 / Anthropic 事件全集 / 文件结构 router·stream / URL 三分支 / finish=length / max_tokens 4096 / PROTECT_COUNT / budget 公式)/ df-workflow(NodeRegistry / DagDef / StateMachine / Dag API / NodeContext·NodeOutput 字段 / EventBus API / 条件引擎默认放行 warn)/ df-storage(list_non_archived / set_archived 例外对照)
**代码变更**:无(纯文档纠错,代码未动)
**验证**:每项修正均经代理 Read 代码复核签名/SQL/行为后改;git diff 4 文档落地(df-ai 443 / df-storage 134 / SQLite-CRUD 56 / df-workflow 122 行变动)
**遗留问题 / 下一步**:
1. 4 文档已与代码实质一致;后续若改 df-ai/df-storage/df-workflow 公开接口,需同步对应模块文档(文档治理:模块文档随代码变)
2. df-evolve(knowledge.rs / pattern.rs)本轮未审 — docs/03 无对应模块文档,若补可另起审查
### [Sprint 18] 2026-06-13 — 知识生命线(详情页 + 溯源 + 引用 + 生命周期)
**工作内容**:
- **根因**:知识库 candidate 卡片点不开详情、不能编辑、看不到"为什么产生";reasoning 字段被 prompt 要求但写库丢弃(bug);increment_reuse_count 只 +1 不记去向;无状态变更历史。用户要求呈现知识完整生命周期:产生→审核→引用→归档,且约束异步不阻塞、代码简洁易扩展。
**A. 存储层(df-storage,V10 迁移)**:
- V10:幂等补 `knowledges.reasoning TEXT` 列 + 新建 `knowledge_events` 审计表(id/knowledge_id/event_type/source_ref/context_json/timestamp + 3 索引)
- `KnowledgeRecord``reasoning: Option<String>`;新增 `KnowledgeEventRecord`(6 字段)
- `KnowledgeEventsRepo`(impl_repo! 宏 7 方法 + 扩展 `list_by_knowledge`/`list_by_knowledge_type`);5 处显式 SELECT 列列举 + from_row + insert/update body 全线接 reasoning
**B. 后端埋点(src-tauri)**:
- **新建 `commands/knowledge_timeline.rs`** — `KnowledgeTimeline` 独立记录器(持 Arc<Database>),便捷方法 record_extracted/referenced/status_change/created,内部 `fire()` 吞错误 fire-and-forget。各业务流程只调一行,不内联写 SQL(代码简洁约束)
- `extract_knowledge_from_conversation`:回填 reasoning(修 bug)+ 查对话标题 + insert 后记 extracted 事件
- `build_knowledge_context`:加 conv_id 参数 + spawn 块内 increment_reuse_count 后记 referenced 事件(conv_id+query);调用点上移 conv_id 快照
- `knowledge_create/update_status`:记 created/status_changed 事件(归档复用 status_changed,删 dead code EVENT_ARCHIVED/record_archived)
- 3 新 IPC command:`knowledge_get_detail`(聚合 knowledge+events)/`knowledge_update`(部分更新编辑)/`knowledge_events`(查生命线);AppState 加 `knowledge_events` Repo;lib.rs 注册
**C. 前端**:
- types.ts:KnowledgeRecord 加 reasoning + 新增 KnowledgeEventRecord/KnowledgeDetailPayload/UpdateKnowledgeInput
- api/store:各加 getDetail/update/getEvents
- **Knowledge.vue 全面重构**:Ideas 式左右分栏(左卡片列表 @click 选中 / 右详情四分区 — ①基本信息+编辑 ②溯源(产生方式/来源对话/AI reasoning) ③引用记录(复用次数+最近 N 条) ④生命周期时间线)。可编辑 title/content/tags/confidence
**关键决策**(详见 docs/02-架构设计/功能决策记录.md):① 独立 events 表非 JSON 嵌主表(引用数百次防行膨胀);② 独立 KnowledgeTimeline 记录器(不散落埋点);③ 归档复用 status_changed(防冗余);④ reasoning 回填(修 prompt 要求但丢弃的 bug)
**代码变更**:df-storage(migrations/models/crud)+ src-tauri(state/knowledge_timeline 新建/ai/knowledge/lib/mod)+ 前端(types/api/knowledge.ts/stores/knowledge.ts/Knowledge.vue)= 12 文件
**验证**:cargo check --workspace ✓(仅既有警告)/ vue-tsc --noEmit ✓ 零错误 / cargo test -p df-storage ✓ 21 单测全过。**未 tauri dev 运行时实测**
**遗留问题 / 下一步**:
1. **#54 GUI 实测**:AI 对话结束→提炼→收件箱→点详情看 reasoning+来源;发布→生命线 status_changed;新对话注入→referenced 事件;编辑 candidate→保存
2. 老库历史 candidate 无 reasoning/events,详情页降级展示(手动录入/无溯源)——属预期兼容
3. knowledge_events 纯追加表,长期可清理 >90 天 referenced 事件(本次不做)
### [Sprint 19] 2026-06-14 — list_directory 防爆 + localStorage→SQLite 统一持久化 + token/发送 bug 修复
**工作内容**:用户报多个 AiChat bug + 提需求:list_directory 扫出 13782 项塞爆对话;token 显示"0 in";发送卡住/留框;LLM 并发上限太小;localStorage 散落要统一入 SQLite。同时用户并行主导 ai.rs→ai/ + ai.ts→composables 模块拆分(我观察配合,不接管)。
**A. list_directory 递归防爆(Part A)**:
- `list_dir_recursive`(ai/tool_registry.rs)加噪音目录剪枝(`.git`/`node_modules`/`target`/`dist`/`build`/`.next`/`.cache`/`__pycache__`/`.venv`/`venv`/`.idea`)——**列出但不深入内部**;硬上限 1000 条 + `truncated` 标志;默认 max_depth 3→2;加 `skip_noise_dirs` 参数(默认 true,AI 看编译产物 dist/target 时传 false)
- 根因:AI 广扫项目根传 `recursive:true`,噪音目录铺平致 13782 项塞进对话 message(UI 卡 + token 爆)
**B. localStorage → SQLite 统一持久化(Part B)**:
- 新建 `app_settings` KV 表(V13 迁移)+ 手写 `SettingsRepo`(get/set/get_all/delete,不走 `impl_repo!` 宏因 KV 无固定 schema);4 IPC(settings_get/set/get_all/delete);AppState 加 settings 字段
- 前端 `appSettings` store(reactive 缓存 + 300ms debounce + `useSetting` ref)+ api 封装
- **11 key 迁移**:敏感 `df-connections` + UI 偏好(theme/language/ai-width/ai-ui/token/concurrency)+ `df-ai-active-conv`;**例外 `df-ai-gen`/`df-ai-text`**(流式临时快照,高频写留 localStorage)。App.vue onMounted 一次性迁移旧 localStorage
**C. Bug 修复**:
- **token prompt=0**:GLM 流式 usage 带 completion 不带 prompt → 加估算兜底(provider 返回 0 时按请求消息 `TokenEstimator::estimate_message` 求和)
- **发送卡住/留框**:`sendMessage` IPC 失败时无 catch → streaming 永真(光标卡死)+ handleSend 回填输入(消息已显示);改 try/catch 回滚 streaming + 清空气泡占位
- **LLM 并发上限**:三层(模板 max / JS Math.min / 后端 .clamp)全去上限,保留 min=1 + `per-conv ≤ global` 约束
**D. token 暴增诊断 + 清理**:
- 查 SQLite 实数据:对话 e4365d47 累积 in=115万 / out=2万 / 消息体 1.6MB
- 根因:**单条 list_directory 工具结果 1.2MB**(13782 项,Part A 修复前产生)落库后每轮重发 + save 累加 → 暴增;token 估算准,膨胀是真(非估算锅)
- 删除污染对话(`ai_conversations` 1 行 + `ai_tool_executions` 123 行)
**E. 模块拆分(用户主导,本会话发生,我配合不接管)**:
- `ai.rs`(2651 行)→ `ai/` 11 子模块(agentic/audit/commands/conversation/knowledge_inject/mod/prompt/skills/stream_recv/title/tool_registry),旧 ai.rs 删
- `stores/ai.ts`(749 行)→ 薄壳 + `composables/ai/*`(events/stream/send/conversations/window/panel)
- `df-evolve` crate 移除(workspace/代码零引用)
- 踩坑(glob 重导出命令宏符号 / super 路径失效 / 0 字节残留触发 E0761)已记入经验记录.md
**关键决策**(详见功能决策记录 / 经验记录):① list_directory 剪枝 + skip_noise 保留访问能力(定点查/强制递归两路通);② KV 表统一持久化复用 SettingsRepo(兑现经验记录预言);③ token 估算兜底(provider 不报时按消息估);④ 发送失败回滚 streaming;⑤ 并发去上限保 per-conv≤global
**代码变更**:src-tauri(`commands/ai/` 新模块 + `commands/settings.rs` + state.rs + lib.rs)+ crates/df-storage(migrations V13 + crud SettingsRepo)+ 前端(api/settings.ts + stores/appSettings.ts + App.vue/Settings.vue/composables/ai/* + i18n)≈ 25 文件
**验证**:cargo check ✓ / vue-tsc ✓ 零错 / tauri dev 启动 ✓ 运行;token/发送/并发/list_directory 已实测
**遗留 / 下一步**:
1. **Fix 1(待用户最终定)**:工具结果入库前截断 50KB(堵 `read_file` 1MB 洞 + 防御);Fix 2(放宽旧工具结果裁剪)因 Part A 已杀主源,延后不做
2. Settings.vue(1037 行)拆 panel 子组件——早前建议,用户已做 ai.rs,此件待评估
3. 诊断日志清理(handleEvent/approveToolCall 早期调试 console.log 残留)
### [Sprint 20] 2026-06-14 — 项目管理模块代码审查 + 全局核对3-agent review 验证)
**工作内容**: 应用户要求审查「项目管理 / 项目导入 / 生命周期可用性」(后端 commands/project.rs + ai/tool_registry.rs + df-project/scan.rs + 前端 Projects.vue / ProjectDetail.vue。先 3-agent 并行 review 出 15 项发现,剔幻觉 2 项read_readme 命名误判 / conflict.name null 过度防御)后剩 13 项;再应要求**全局核对**grep 全仓库 6 维度)确认每项发现是孤例还是系统性,保证全局成立有效。**本次仅审查 + 核对,未改代码。**
**验证结论**: 13/13 发现**事实全部成立**无幻觉。4 处行号偏差(① 249→263 / ⑤ 113→136 / ⑫ 130→145 / ③ 未标→2712 处范围需补(⑧ 实 8 处非 3 处 / ③ 漏 relocate:212
**🔴 必须修复3**:
1. **AI delete_project 硬删绕过软删**tool_registry.rs:263 `repo.delete` 物理 DELETE vs IPC project.rs:120 `soft_delete` 进回收站)—— 同一操作两种后果AI 对话删 = 数据丢失不可恢复UI 删 = 可恢复。**数据安全缺口**
2. **AI 缺回收站生命周期工具**restore/purge/list_deleted 全无)—— ProjectRepo 有完整方法crud.rs:572/591/610/634+ IPC 全注册project.rs:125-145AI 层零覆盖,割裂工作流
3. **collect_sample 同步 IO 阻塞 async**project.rs:271 在 async fn 内直接同步调 df-project::scan—— 对比 scan_project_stack:182用了 spawn_blocking不一致
**🟡 建议改进6**: ④ normalize_path 两份重复project.rs:154 + tool_registry.rs:180/ ⑤ update 白名单双份不同步tool_registry:136 硬编码 vs crud.rs:287 allowed_columnsidea_id 字段不同步)/ ⑥ AI 扫描 + 目录状态文案硬编码未走 $tProjects.vue:33/195 + ProjectDetail.vue:93/ ⑦ parseStack 两份重复Projects.vue:143 + ProjectDetail.vue:321/ ⑧ 原生 alert/confirm全局 8 处非仅 ProjectDetail 3 处Ideas.vue:378/391 同病)/ ⑨ collect_sample 无文件大小预检scan.rs:151/205 read 全文后截断)
**⚪ 可选3**: ⑩ LLM 无超时project.rs:297 占 llm_concurrency permit 无限 await/ ⑪ JSON 提取取首尾花括号project.rs:368-369 多 JSON 场景错)/ ⑫ create_project 无 path 参数tool_registry:145 需 create+bind 两步)
**全局核对关键定性**6 维度 grep 全仓库):
- **① 是 project 特例但最该修**: soft_delete/回收站机制**全仓库仅 project 一张表有**task/idea/branch/release/workflow 本就物理删,无语义不一致);正因 project 唯一设计回收站AI 硬删直接击穿其数据安全设计
- **⑧ 系统性**: 全仓库 8 处原生弹窗ProjectDetail 4 + Projects 2 + Ideas 2非局部
- **③ 范围补报**: 不只 :271relocate_project_path:212 同步 detect_stack 同样阻塞3 处未包 spawn_blocking vs 1 处包了
- **src-tauri 层自身干净**: `std::fs` 同步调用零匹配,阻塞全在跨 crate 调同步的 df-project::scan
- **④⑤⑦ 精准**: 全仓库确为两份/一处无更多副本validate_path/resolve_workspace_path 是安全校验,职责不同非 normalize 重复
**未改代码**(待用户定推进批次)
**遗留 / 下一步(修复批次建议)**:
- **批1 数据安全**: ①AI delete 改 soft_delete+ ②(补 restore/purge/list_trash 三工具,复用 ProjectRepo 对应方法)
- **批2 阻塞 + 去重**: ③(:270/:271/:212 三处统一 spawn_blocking+ ④(抽公共 normalize_path 到 df-project/df-core+ ⑤tool_registry 复用 allowed_columns_for
- **批3 前端**: ⑥(补 i18n key+ ⑦(抽 src/utils/project.ts+ ⑧(全局 8 处 alert/confirm 换 Arco Modal
- ⚪ 可选: ⑨⑩⑪⑫ 按需
---
### [设计] 2026-06-14 — B-03 人工审批响应机制设计
**工作内容**df-workflow HumanNode 审批响应机制设计B-260614-03。勘察确认链路基础设施 90% 已通EventBus broadcast / `HumanApprovalResponse` 事件 / `approve_human_approval` IPC / 前端 store 已接通),唯一缺口为 `human_node.rs:55` 发完请求直接 return "同意"。设计:订阅时序铁律(`subscribe()` 先于 `send(Request)`+ `tokio::select!` 循环(响应 / 超时 / 取消)+ execution_id+node_id 双键过滤 + Lagged 容忍。澄清 B-06/B-07 前置真实影响B-06=并发隔离非单流功能前置B-07=取消必要非充分),拆 **B-03a**(响应等待 + 超时)/ **B-03b**(取消机制:`set_cancelled` + cancel IPC + 前端按钮)。
**产出**:完整设计文档 [B-03-人工审批响应机制.md](./docs/02-架构设计/B-03-人工审批响应机制.md)功能决策记录加「工作流人工审批节点B-03」摘要章节。
**下一步**B-06execution_id 下沉)/ B-07共享 StateMachine前置修复 → 落 B-03a 实现 → B-03b 取消机制补全。
<!--
### [Sprint N] YYYY-MM-DD — 简述