重构: 拆agentic.rs第一批GeneratingGuard(strategy自底向上)

- 新建 agentic/guard.rs(69行): GeneratingGuard struct+new/reset/disarm/Drop(F-09 batch2 per_conv双写语义保留, pub(super)可见性)
- agentic.rs 1221→agentic/mod.rs 1165行: mod guard + use GeneratingGuard + 删原定义
- loop主体(run_agentic_loop/try_continue/stream_one_provider/compress)原位保留(后续批,高风险)
helpers未建: 无独立纯helper可抽(DEFAULT_*被state.rs引用留原位, PROTECT_COUNT loop绑定)
主代兜底: cargo check --workspace 0 + test 98 + grep guard抽离/mod.rs use印证
strategy: 自底向上, 单批1-2文件原子, loop主体留后续批(行为敏感需充分测试)
This commit is contained in:
2026-06-19 03:37:28 +08:00
parent 63fe0a6375
commit 96a05638b1
3 changed files with 140 additions and 60 deletions

View File

@@ -489,3 +489,70 @@
— 新建 `crates/df-mcp/` + `src-tauri/src/main.rs` + `src-tauri/Cargo.toml` + 可选 `crates/df-ai/src/ai_tools.rs`
---
### 💡 2026-06-19 新需求AI 工具文件访问动态权限模型·已分析·待实施)
> 用户需求:将现有 `workspace_root` 单一根目录模型,升级为**动态白名单池 + 运行时权限申请**机制(类似 macOS / VS Code 的权限申请模式)。解决「锁太死」(只能绑定单一 workspace_root和「放太宽」的矛盾。
>
> **与 MCP ServerF-260619-02无关**:本需求是 DevFlow 应用内部 AI 工具read_file/write_file 等)的文件系统访问权限升级,不涉及对外 MCP 协议暴露。
- [ ] **F-260619-03 [P1]****AI 工具文件访问动态权限模型workspace_root 单根 → 动态白名单池 + 运行时申请**
**核心机制**:当 AI 调用 `read_file` / `write_file` 等文件系统工具时,路径校验从「单一 workspace_root 前缀匹配」升级为「动态白名单池校验 + 未命中则挂起 Agentic Loop 向前端弹窗申请授权」。
**数据结构变更**
1. **持久化白名单**Settings KV 存储):`app_settings` 表 key=`allowed_dirs`value=JSON 数组 `["E:/wk-lab/u-abc", "E:/wk-lab/u-img"]`。前端 Settings 页提供列表增删改查 UI。
2. **会话级临时白名单**(内存):`AiSession` 新增 `session_allowed_dirs: HashSet<PathBuf>`,仅限当前会话有效。
3. **全局状态**`AppState` 引入 `AllowedDirs { persistent: HashSet<PathBuf>, session: HashSet<PathBuf> }`,替代写死的 `workspace_root()`
**权限拦截与申请流程**
1. **规范化路径**`canonicalize`(解析软链接、`.``..`)。
2. **检查白名单**:判断 `canonicalize` 后的真实路径是否在持久化或会话白名单中(`real_path.starts_with(allowed_dir)`)。
3. **命中则放行**:执行原逻辑。
4. **未命中则拦截**:挂起当前 Agentic Loop → Tauri 事件向前端弹窗 `AiDirAuthRequired { path, tool_name }` → 用户选择「仅本次」(加入 session_allowed_dirs/「未来都允许」(写入 DB Settings + 更新 persistent/「拒绝」→ 恢复执行。
**授权粒度**:弹窗中建议授权目标文件所在的**项目根目录**(而非具体文件),减少弹窗频率。用户可在弹窗中手动收窄或放宽范围。
**安全防护(三层)**
- **第一层 canonicalize**:解析软链接后校验真实路径,防软链接逃逸(授权目录本身也需 canonicalize
- **第二层白名单**`real_path.starts_with(allowed_dir)` 校验。
- **第三层黑名单兜底**:保留现有 `validate_path`,禁止系统敏感目录(`/etc``/var``C:\Windows\System32` 等)。
**写操作额外约束**写操作write_file/delete_file/patch_file即使目录已授权仍走现有 RiskLevel 审批流Medium/High 需用户确认);`delete_file` 始终 High 风险审批,不受白名单影响。
**分阶段实施**
| 阶段 | 内容 | 复杂度 | 优先级 |
|------|------|--------|--------|
| **Phase A** | Settings 持久化白名单 + `resolve_workspace_path` 改造为多目录校验canonicalize + starts_with | 低 | P1 |
| **Phase B** | 会话级临时授权 + Agentic Loop 挂起/恢复 + 前端弹窗 UI + Tauri 事件 | 高 | P2 |
| **Phase C** | 软链接深度防护 + 系统目录黑名单完善 + 写操作额外约束 | 中 | P2 |
Phase A 成本最低但收益最大——立即解决「只能绑定单一 workspace_root」的限制且为后续动态授权打好数据基础。
**与现有架构的契合点**
- SettingsRepo KV 存储:已有,`allowed_dirs` 直接复用,零迁移成本。
- RiskLevel 审批流:已有完整 tool approval 机制,动态授权可视为「路径级别的 approval」。
- Agentic Loop已有挂起/恢复能力(审批等待),扩展路径授权挂起是同构的。
- Tauri 事件系统:已有 `ai-chat-event`,新增 `AiDirAuthRequired` 事件类型即可。
**关键改动点**
- `tool_registry.rs`handler 闭包需引入 `AllowedDirs``Arc` 引用(当前闭包是无状态 `Box::new(|args| ...)`),调整注册逻辑。
- `resolve_workspace_path`(或等效路径校验函数):从单一 workspace_root 前缀匹配 → 多目录白名单 canonicalize 校验。
- `state.rs`AppState 新增 `allowed_dirs` 字段。
- `commands/ai/mod.rs`AiSession 新增 `session_allowed_dirs` 字段。
- `agentic.rs`:捕获 `PATH_AUTH_REQUIRED` 信号 → 挂起 → emit 事件 → 等待恢复。
- 前端 Settings 页:新增「授权目录」管理 UI。
- 前端 AiChat新增路径授权弹窗组件。
**验收标准**
1. Settings 页可管理持久化授权目录列表(增删改查)
2. AI 访问授权目录内文件正常执行,无额外弹窗
3. AI 访问授权目录外文件时弹窗申请,用户可选择「仅本次」/「未来都允许」/「拒绝」
4. 软链接逃逸被 canonicalize 校验拦截
5. 系统敏感目录始终被拒绝(黑名单兜底)
6. `cargo check --workspace EXIT 0` + `vue-tsc EXIT 0`
`src-tauri/src/state.rs` + `src-tauri/src/commands/ai/{mod.rs,tool_registry.rs,agentic.rs}` + `src-tauri/src/commands/settings.rs` + 前端 Settings 页 + AiChat 弹窗组件