新增: 全量走查报告 — 代码/前端/文档体系
- Rust 后端 12 crate: 锁/LIKE 通配符/jitter/路径穿越 等 15 项 - Vue 3 前端: Arco 残留/confirm 重复/类型退化 等 13 项 - 文档体系: 工具清单过时/INDEX 漏列 9 文档/死链/SSOT 违反 等 9 项
This commit is contained in:
392
docs/05-代码审查/全量走查报告-2026-06-28.md
Normal file
392
docs/05-代码审查/全量走查报告-2026-06-28.md
Normal file
@@ -0,0 +1,392 @@
|
|||||||
|
# 全量走查报告(2026-06-28)
|
||||||
|
|
||||||
|
> 范围:全栈 Rust 12 crate + Tauri 命令层 + Vue 3 前端 + 文档体系
|
||||||
|
> 方法:3 路并行(Rust 后端/Vue 前端/文档体系),主代理综合整理
|
||||||
|
> 原则:dry — 仅审查 + 文档,不改代码
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔴 安全
|
||||||
|
|
||||||
|
### ① relay.rs — 硬编码默认 Token
|
||||||
|
|
||||||
|
**文件**: `crates/df-relay/src/relay.rs:36-37`
|
||||||
|
|
||||||
|
中继服务使用硬编码 `DEFAULT_TOKEN = "devflow-relay-default-token"`,所有未设环境变量的部署均使用同一静态 token。通过 `strings` 即可从二进制提取。
|
||||||
|
|
||||||
|
**建议**:启动时要求必须设置 `DF_RELAY_TOKEN` 环境变量,移除默认值。
|
||||||
|
|
||||||
|
### ② models.rs — `AiProviderRecord` Debug 未脱敏 api_key,日志泄漏风险
|
||||||
|
|
||||||
|
**文件**: `crates/df-storage/src/models.rs:288`
|
||||||
|
|
||||||
|
`AiProviderRecord` 未实现自定义 `Debug` 对 `api_key` 脱敏。若上层代码意外 `{:?}` 打印(如 `tracing::debug!`),明文 API key 会写入日志。`model_configs`(L296)与 `config`(L298)等 JSON 字段同样不安全。
|
||||||
|
|
||||||
|
**建议**:为 `AiProviderRecord` 实现自定义 `Debug`,将 `api_key` 输出为 `"sk-****"`。
|
||||||
|
|
||||||
|
### ③ ScriptNode — 命令无白名单/沙箱
|
||||||
|
|
||||||
|
**文件**: `crates/df-nodes/src/script_node.rs:15-19` + `crates/df-execute/src/shell.rs:92-117`
|
||||||
|
|
||||||
|
ScriptNode 从 config 取 `command` 字符串透传给 shell(`cmd /C` / `sh -c`),无任何命令白名单或参数校验。工作流定义来自 AI 生成或外部导入时,恶意命令可通过 AINode 写入 ScriptNode config 注入执行。
|
||||||
|
|
||||||
|
**建议**:添加危险命令关键词告警(`rm -rf`/`DROP TABLE`/`Format`),可选白名单/环境变量隔离配置。
|
||||||
|
|
||||||
|
### ④ bind_directory — 原始路径入库未规范化 + 无沙箱校验
|
||||||
|
|
||||||
|
**文件**: `crates/df-mcp/src/tools.rs:314-342`
|
||||||
|
|
||||||
|
`bind_directory` 接收用户传入 `path`,`normalize_path` 仅用于去重检测,**原始 `path` 值直接存储**。同一目录可用两种写法绑定两次绕过冲突检测。且未校验规范化后路径在项目沙箱允许范围内。
|
||||||
|
|
||||||
|
**建议**:存储前 `normalize_path()` + 校验在沙箱目录内 + 拒绝含 `..` 的原始路径。
|
||||||
|
|
||||||
|
### ⑤ state.rs — `std::sync::Mutex` 在 async 上下文中持锁风险
|
||||||
|
|
||||||
|
**文件**: `crates/df-workflow/src/state.rs:34-36, 55, 97, 104`
|
||||||
|
|
||||||
|
`StateMachine` 使用 `std::sync::Mutex` 保护 HashMap,在 `get()` 等同步方法中直接 `lock().expect()`。`DagExecutor` 在 `futures::future::join_all` 同层并发时,若某节点持有引用后 `.await` 另一操作间接尝试锁 `states`,会死锁。通篇 4 处 `expect`——某节点 panic 导致锁中毒,连锁 fatal。
|
||||||
|
|
||||||
|
**建议**:改用 `tokio::sync::Mutex`,或在文档中明确标注「state_machine 方法不得在 `.await` 期间持锁」。
|
||||||
|
|
||||||
|
### ⑥ eventbus.rs — 错误静默吞噬
|
||||||
|
|
||||||
|
**文件**: `crates/df-workflow/src/eventbus.rs:16, 32`
|
||||||
|
|
||||||
|
`DEFAULT_CAPACITY: usize = 256`,`EventBus::send` 调用处 `let _` 吞噬所有错误。当并发节点多且事件消费慢时,256 溢出导致最早接收者 Lagged 错误。
|
||||||
|
|
||||||
|
**建议**:`send` 处 `tracing::warn!` 记录 Lagged 错误。
|
||||||
|
|
||||||
|
### ⑦ shell.rs — `probe_pwsh` 同步阻塞 tokio 运行时
|
||||||
|
|
||||||
|
**文件**: `crates/df-execute/src/shell.rs:53-66`
|
||||||
|
|
||||||
|
`probe_pwsh()` 在 `Default::default()` 中调用,`Default` 在 `execute()` 异步函数内调用。在 tokio 异步函数中同步阻塞 `cmd.status()` 违反最佳实践。
|
||||||
|
|
||||||
|
**建议**:惰性异步探测(`OnceLock` 配 `tokio::task::spawn_blocking`)。
|
||||||
|
|
||||||
|
### ⑧ retry.rs — backoff jitter 随机性弱
|
||||||
|
|
||||||
|
**文件**: `crates/df-ai/src/retry.rs:77-81`
|
||||||
|
|
||||||
|
jitter 使用 `SystemTime::now().duration_since().subsec_nanos() % 2000` 映射到 `[-1.0, 1.0)`。纳秒级退化到 1ms 粒度时多个请求可能拿到同一值,重试碰撞风险。
|
||||||
|
|
||||||
|
**建议**:改用 `fastrand`,jitter 范围扩大到 ±50%(当前 ±20%)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔴 文档
|
||||||
|
|
||||||
|
### ⑨ AI对话引擎-2026-06-14.md — 工具清单严重过时
|
||||||
|
|
||||||
|
**文件**: `docs/03-模块文档/AI对话引擎-2026-06-14.md §四`
|
||||||
|
|
||||||
|
标题自称"12 个"工具,表格实际列出 **13 行**(自相矛盾);与 `df-ai-AI集成模块-2026-06-12.md` 声称的 **22 个工具**严重对不齐;缺失 `run_command`/`patch_file`/`list_trash`/`file_info`/`search_files`/`delete_task`/`restore_project`/`purge_project` 等工具。
|
||||||
|
|
||||||
|
**建议**:全文同步至当前实际 22 个工具的最新清单。
|
||||||
|
|
||||||
|
### ⑩ 02-架构设计/INDEX.md — 漏索引 9 个已有文档
|
||||||
|
|
||||||
|
**文件**: `docs/02-架构设计/INDEX.md`
|
||||||
|
|
||||||
|
| 子目录 | 漏列数 | 典型遗漏 |
|
||||||
|
|-------|-------|---------|
|
||||||
|
| 专项设计 | 7 | `AI原生上下文地图`、`AST符号解析`、`插件机制`、`查询能力补全方案`、`项目知识图谱` 等 |
|
||||||
|
| 已编号方案 | 2 | `F-260622-01-跨端AIChat-Phase3联调设计`、`消息级溯源P2-切读方案`(今天新增) |
|
||||||
|
| 构想审查 | 1 | `跑题改进试验记录` |
|
||||||
|
| 根目录 | 2 | `单对话并行多轮-Phase0落地路线图`、`单对话并行多轮-设计` |
|
||||||
|
|
||||||
|
**建议**:批量补齐,建立「新增文档 → 立即更新 INDEX」的提交习惯。
|
||||||
|
|
||||||
|
### ⑪ Agent架构说明 — 死链
|
||||||
|
|
||||||
|
**文件**: `docs/02-架构设计/专项设计/Agent架构说明-2026-06-14.md:4`
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
> 关联: [任务推进设计](任务推进构想-2026-06-14.md)
|
||||||
|
```
|
||||||
|
目标文件在 `构想审查/` 下,当前路径解析到 `专项设计/` 下不存在。
|
||||||
|
|
||||||
|
**建议**:改为 `[任务推进设计](../构想审查/任务推进构想-2026-06-14.md)`。
|
||||||
|
|
||||||
|
### ⑫ ARCHITECTURE.md §七 + 新设计文档 — 大段逐字重复
|
||||||
|
|
||||||
|
**文件**: `ARCHITECTURE.md:538-665` / `docs/02-架构设计/专项设计/三层模型-流程模板与人设体系-2026-06-28.md`
|
||||||
|
|
||||||
|
YAML 模板示例(52行)、`AgentPersona` struct 定义(11行)、三层定义表、实例化流程——**大段逐字重复**,违反文档记录规范 SSOT 原则。
|
||||||
|
|
||||||
|
**建议**:`ARCHITECTURE.md §七` 保留概要(三层定义 + 关系图 + 关键原则),YAML 全文和 struct 定义仅在专项设计文档展开,ARCH 以引用链接替代。
|
||||||
|
|
||||||
|
### ⑬ ARCHITECTURE.md 仍保留 ~100 行已移除模块细节
|
||||||
|
|
||||||
|
**文件**: `ARCHITECTURE.md:210-318`(`df-task` / `df-traceability` 章节)
|
||||||
|
|
||||||
|
保留 Task 生命周期图、分支策略、标注系统、需求-功能-测试映射、Decision struct 等已移除模块的详细设计。造成认知负担。
|
||||||
|
|
||||||
|
**建议**:将已移除模块的详细历史移至 `功能决策记录-归档`,ARCHITECTURE.md 仅保留「已移除,见归档」。
|
||||||
|
|
||||||
|
### ⑭ 模块文档更新停滞(最长 16 天)
|
||||||
|
|
||||||
|
| 文档 | 最后更新 | 距今天数 |
|
||||||
|
|-----|---------|---------|
|
||||||
|
| `df-workflow-工作流引擎-2026-06-12.md` | 06-15 | 13 天 |
|
||||||
|
| `df-ai-AI集成模块-2026-06-12.md` | 06-14 | 14 天 |
|
||||||
|
| `df-storage-存储层-2026-06-12.md` | 06-15 | 13 天 |
|
||||||
|
| `想法探索-对抗式评估-2026-06-12.md` | 无更新 | 16 天 |
|
||||||
|
|
||||||
|
**建议**:对上述文档做一次「代码对齐」检查。
|
||||||
|
|
||||||
|
### ⑮ ARCHITECTURE.md 版本状态过时
|
||||||
|
|
||||||
|
**文件**: `ARCHITECTURE.md:3`
|
||||||
|
|
||||||
|
当前 `状态: 设计阶段`。工程处于 **Phase 2 验证阶段**(df-workflow 核心完成、AI ReAct 循环运行中、审批机制就绪),状态标签与实际不符。
|
||||||
|
|
||||||
|
**建议**:改为 `状态: Phase 2 本地优先开发流程验证`(与 `docs/INDEX.md` 一致)。
|
||||||
|
|
||||||
|
### ⑯ 新设计文档与现有文档缺失交叉引用
|
||||||
|
|
||||||
|
**文件**: `docs/02-架构设计/专项设计/三层模型-流程模板与人设体系-2026-06-28.md`
|
||||||
|
|
||||||
|
应当引用但未引用:`全局事件数据总线`、`df-nodes-节点集合`、`任务推进构想`。
|
||||||
|
|
||||||
|
**建议**:补充上述交叉引用。
|
||||||
|
|
||||||
|
### ⑰ AI对话引擎文档边界归属模糊
|
||||||
|
|
||||||
|
**文件**: `docs/03-模块文档/AI对话引擎-2026-06-14.md`
|
||||||
|
|
||||||
|
位于 `03-模块文档/`,但内容大量描述 `src-tauri/commands/ai/` 下的 Tauri 层代码,而非 `crates/df-ai` crate 内部。按文档记录规范职责矩阵,`03-模块文档/` 应记录各 crate 实现细节。
|
||||||
|
|
||||||
|
**建议**:移入 `02-架构设计/` 适当子目录,或明确标注为跨层交互设计文档。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🟡 代码质量
|
||||||
|
|
||||||
|
### ⑱ dag.rs — `deep_merge` 收到 null 返回 null,覆盖全局配置
|
||||||
|
|
||||||
|
**文件**: `crates/df-workflow/src/dag.rs:174-192`
|
||||||
|
|
||||||
|
`deep_merge(global, null)` 返回 `null`。若某节点定义写了 `"config": null`(JSON 显式 null),该节点 `ctx.config = Value::Null`,原本期望继承全局 config 的节点拿到空配置。
|
||||||
|
|
||||||
|
**建议**:`DagExecutor.run()` 中对 `deep_merge` 结果做 `if result.is_null() { initial_config.clone() }` 兜底。
|
||||||
|
|
||||||
|
### ⑲ dag.rs — `_` 通配 match 掩盖未覆盖变体
|
||||||
|
|
||||||
|
**文件**: `crates/df-workflow/src/dag.rs:191`
|
||||||
|
|
||||||
|
`deep_merge` 的 match 最后分支 `_ => node.clone()` 过于宽泛。若未来新增 `serde_json::Value` 变体,不会被编译器捕获。
|
||||||
|
|
||||||
|
**建议**:显式列出所有剩余变体并 `bail!`,迫使维护者在修改时意识到影响。
|
||||||
|
|
||||||
|
### ⑳ shell.rs — `String::from_utf8_lossy` 编码错误被静默替换
|
||||||
|
|
||||||
|
**文件**: `crates/df-execute/src/shell.rs:155-156`
|
||||||
|
|
||||||
|
shell 输出使用 `String::from_utf8_lossy`,将非 UTF-8 字节替换为 `<60>`。对于中文/日文环境(如 `chcp 65001` 前的 GBK 输出),用户看到乱码替代符,诊断困难。
|
||||||
|
|
||||||
|
**建议**:添加 `tracing::debug!` 记录损失性替换的字节数,或提供 `encoding_rs` 转码选项。
|
||||||
|
|
||||||
|
### ㉑ query LIKE 搜索 — SQL 通配符未转义
|
||||||
|
|
||||||
|
**文件**: `crates/df-storage/src/crud/project_repo.rs:245-246`
|
||||||
|
|
||||||
|
`LIKE ?` 使用 `%{trimmed}%` 拼接,`keyword` 中的 `%`/`_` 会被字面匹配。用户搜索 `100%` 匹配所有行,搜索 `error_404` 匹配 `errorX404`。
|
||||||
|
|
||||||
|
**建议**:对 keyword 中的 `%`/`_` 做 `replace` 转义,加 `ESCAPE '\'` 子句。
|
||||||
|
|
||||||
|
### ㉒ coordinator.rs — 空壳仅用注释声明"勿删",应加编译期守卫
|
||||||
|
|
||||||
|
**文件**: `crates/df-ai/src/coordinator.rs:1-24`
|
||||||
|
|
||||||
|
注释声明「B 路线占位,有意保留空壳,勿删」,但无 `#[deprecated]` 或 `#[doc(hidden)]` 编译期标记。调用方引入 `AgentCoordinator::new().run()` 只能运行时发现返回 `"TODO"`。
|
||||||
|
|
||||||
|
**建议**:加 `#[deprecated(note = "B 路线占位,勿用于生产")]`。
|
||||||
|
|
||||||
|
### ㉓ secret.rs — 密钥迁移 sidecar 文件写入无原子性
|
||||||
|
|
||||||
|
**文件**: `crates/df-storage/src/secret.rs:75-81`
|
||||||
|
|
||||||
|
`record_migration_fail` 每次调用同步读文件 → 改 map → 写文件,迁移时 10+ provider 逐条失败时每条 2 次文件 I/O。无原子写入保障,异常中断可能产生半写文件。
|
||||||
|
|
||||||
|
**建议**:积累内存中的失败计数,迁移循环结束后一次性持久化。
|
||||||
|
|
||||||
|
### ㉔ Intent/planner/plan_hint — 纯函数模块无单测覆盖
|
||||||
|
|
||||||
|
**文件**: `crates/df-ai/src/intent.rs` / `planner.rs` / `plan_hint.rs`
|
||||||
|
|
||||||
|
注释声称「纯函数、零 IO」,均无 `#[cfg(test)]` 覆盖。Phase 1 接入主 loop 前应补充。
|
||||||
|
|
||||||
|
**建议**:为这些纯函数模块补充输入输出确定性匹配测试。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🟡 前端
|
||||||
|
|
||||||
|
### ㉕ Settings.vue — 内联 confirm 弹层重复实现
|
||||||
|
|
||||||
|
**文件**: `src/views/Settings.vue:7-16`
|
||||||
|
|
||||||
|
Settings.vue 内联了完整 confirm 弹层模板,完全复制了 `ConfirmDialog.vue` 的 UI/逻辑,自身维护 `confirmState`/`answerConfirm`。全项目已有 `useConfirm` composable。
|
||||||
|
|
||||||
|
**建议**:用 `useConfirm` + `ConfirmDialog` 替换内联实现。
|
||||||
|
|
||||||
|
### ㉖ 多视图 — 按钮 CSS 重复定义
|
||||||
|
|
||||||
|
**文件**: `Dashboard.vue:126-162` / `Projects.vue:445-458` / `Ideas.vue:421-432` / `Knowledge.vue:449-458`
|
||||||
|
|
||||||
|
四处视图各自定义 scoped 按钮样式。项目已通过 `main.ts` 导入全局 `styles/components.css`。
|
||||||
|
|
||||||
|
**建议**:删除视图内按钮样式,统一走全局 CSS。
|
||||||
|
|
||||||
|
### ㉗ Ideas.vue + Knowledge.vue — tags 解析逻辑重复
|
||||||
|
|
||||||
|
**文件**: `src/views/Ideas.vue:302` / `src/views/Knowledge.vue:321`
|
||||||
|
|
||||||
|
```ts
|
||||||
|
tags.split(',').map(t => t.trim()).filter(Boolean)
|
||||||
|
```
|
||||||
|
|
||||||
|
**建议**:提取为工具函数 `parseTagsInput` 放进 `src/utils/`。
|
||||||
|
|
||||||
|
### ㉘ Ideas.vue — Arco Design `Message` 残留
|
||||||
|
|
||||||
|
**文件**: `src/views/Ideas.vue:144`
|
||||||
|
|
||||||
|
全项目仅在 Ideas.vue 使用了 Arco 的 `Message` 组件(3 处),其余使用自建 toast。混用。
|
||||||
|
|
||||||
|
**建议**:用自建 `showToast` 替换后删除 Arco 依赖。
|
||||||
|
|
||||||
|
### ㉙ stores/ai.ts — 两个 watch 监听同一 `.messages.length`
|
||||||
|
|
||||||
|
**文件**: `src/stores/ai.ts:204, 241`
|
||||||
|
|
||||||
|
两个 `watch(() => state.messages.length, ...)` 分别处理条数上限和 parts 体积上限。每次 length 变化触发两个 watch,第二个还要遍历 messages 求和。
|
||||||
|
|
||||||
|
**建议**:合并为一个 watch。
|
||||||
|
|
||||||
|
### ㉚ AiChat.vue — `initDrainQueueListener` 每次 `useAiStore()` 调用都执行
|
||||||
|
|
||||||
|
**文件**: `src/stores/ai.ts:304`
|
||||||
|
|
||||||
|
```ts
|
||||||
|
void initDrainQueueListener()
|
||||||
|
```
|
||||||
|
每次调用 `useAiStore()` 都执行。需确认内部做了幂等守卫。
|
||||||
|
|
||||||
|
**建议**:确保只初始化一次(如外层 `initOnce` 布尔守卫)。
|
||||||
|
|
||||||
|
### ㉛ AiChat.vue — 空值传播无告警
|
||||||
|
|
||||||
|
**文件**: `src/components/AiChat.vue:238`
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const conv = store.state.conversations.find(c => c.id === id)
|
||||||
|
const title = conv?.title || t('aiChat.newConversation')
|
||||||
|
```
|
||||||
|
`find` 返回 `undefined` 时静默回退默认标题。非预期 ID 进入时不告警。
|
||||||
|
|
||||||
|
**建议**:至少 `console.warn` 记录 ID 不在列表中的情况。
|
||||||
|
|
||||||
|
### ㉜ 多视图 — `catch (e: any)` 类型退化
|
||||||
|
|
||||||
|
**文件**: 几乎所有 Vue 视图
|
||||||
|
|
||||||
|
```ts
|
||||||
|
catch (e: any) {
|
||||||
|
state.error = e?.toString() ?? t('xxx.failed')
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**建议**:统一改为 `catch (e: unknown)`。
|
||||||
|
|
||||||
|
### ㉝ AiChat.vue — 体积仍偏大
|
||||||
|
|
||||||
|
**文件**: `src/components/AiChat.vue`(模板 128 行 + script ~200+ 行)
|
||||||
|
|
||||||
|
仍承载全局快捷键处理、编辑态管理、队列编辑态管理、Toast 共享状态等。
|
||||||
|
|
||||||
|
**建议**:将键盘快捷键抽离为 `useAiShortcuts` composable。
|
||||||
|
|
||||||
|
### ㉞ Ideas.vue — `searchQuery.trim()` 重复调用
|
||||||
|
|
||||||
|
**文件**: `src/views/Ideas.vue:219-220`
|
||||||
|
|
||||||
|
```ts
|
||||||
|
if (searchQuery.value.trim()) {
|
||||||
|
q.keyword = searchQuery.value.trim()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**建议**:提取 `const trimmed = searchQuery.value.trim()`。
|
||||||
|
|
||||||
|
### ㉟ Projects.vue — 冗余 `as string` 断言
|
||||||
|
|
||||||
|
**文件**: `src/views/Projects.vue:217-218, 222`
|
||||||
|
|
||||||
|
`selected` 已被类型收窄为 `string`,后续 `as string` 多余。
|
||||||
|
|
||||||
|
### ㊱ MCP tools/list — `unwrap_or(Value::Null)` 在数组中混入 null
|
||||||
|
|
||||||
|
**文件**: `crates/df-mcp/src/server.rs:140-142`
|
||||||
|
|
||||||
|
```rust
|
||||||
|
serde_json::to_value(&t.tool).unwrap_or(Value::Null)
|
||||||
|
```
|
||||||
|
若某个 tool schema 序列化失败,tools 数组中混入 `null`。
|
||||||
|
|
||||||
|
**建议**:`.filter_map(|t| serde_json::to_value(&t.tool).ok())`。
|
||||||
|
|
||||||
|
### ㊲ Ideas.vue — `IdeaQuery` 类型未充分对齐
|
||||||
|
|
||||||
|
**文件**: `src/views/Ideas.vue:146, 214-217`
|
||||||
|
|
||||||
|
`order_by` 字段类型为 `string | null`,后端若收窄为联合类型白名单,前端不会报错。
|
||||||
|
|
||||||
|
**建议**:前端 `order_by` 使用 `'score' | 'created_at' | null`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ 亮点
|
||||||
|
|
||||||
|
### ① 密钥管理分层设计(secret.rs)
|
||||||
|
`resolve_provider_secret` 三阶段回落:DB 明文(向前兼容)→ OS keyring → 空字符串。迁移非阻断、幂等、失败计数告警。单测通过 `cfg` gate 仅桌面 OS 跑 keyring 测试。
|
||||||
|
|
||||||
|
### ② SQL 注入防护体系
|
||||||
|
列名白名单(`validate_column_name` + `impl_repo!` 宏统一调用),`build_order_clause` 对排序方向也做白名单校验。软删除/恢复/清空全部参数化 SQL。
|
||||||
|
|
||||||
|
### ③ 前端竞态保护(knowledge.ts)
|
||||||
|
递增序列号丢弃过期响应。`ai.ts` watch 双重守卫(`oldLen > 0 && newLen - oldLen <= 2`)精确区分局部增长和整体替换。
|
||||||
|
|
||||||
|
### ④ `useConfirm` 统一确认弹层
|
||||||
|
从 4 个视图中提取重复 Promise+resolve 模式,正确处理并发覆盖场景(前一个 Promise 先 resolve false)。
|
||||||
|
|
||||||
|
### ⑤ Store 内部分拆 4 子 store
|
||||||
|
`stores/project/` 拆分为 projects/tasks/ideas/workflow,共享 `state.ts` 单例,对外 `useProjectStore()` 不变——「内部拆分,外部零改动」。
|
||||||
|
|
||||||
|
### ⑥ 取消路径 TOCTOU 三层防护
|
||||||
|
`state.rs:86-100` + `executor.rs:180-232`:Ok 后检查、Err 分支检查、阻塞节点轮询。注释详细记录了 TOCTOU 时序窗口。
|
||||||
|
|
||||||
|
### ⑦ MCP 多层防御
|
||||||
|
三级过滤:`visible()` 读模式仅 Low 工具、`tools/list` 剔除 High、`dispatch` 再拦截 read-only + Medium 拒 + High 兜底拒。
|
||||||
|
|
||||||
|
### ⑧ V21 大版本迁移谨慎
|
||||||
|
`BATCH_SIZE=50` 分页、空库跳过、解析失败 skip 而非崩溃、`column_exists` 守卫 ALTER TABLE 防重复执行。
|
||||||
|
|
||||||
|
### ⑨ 子进程清理 + Windows 黑窗抑制
|
||||||
|
`kill_on_drop(true)` 超时后子进程不残留;`creation_flags(0x08000000)` 抑制 Windows 黑窗闪现。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 汇总
|
||||||
|
|
||||||
|
| 分类 | 🔴 | 🟡 | ✅ |
|
||||||
|
|------|----|----|----|
|
||||||
|
| 安全 | 8 | — | — |
|
||||||
|
| 文档 | 9 | — | — |
|
||||||
|
| 代码质量 | — | 7 | — |
|
||||||
|
| 前端 | — | 13 | — |
|
||||||
|
| 亮点 | — | — | 9 |
|
||||||
|
| **合计** | **17** | **20** | **9** |
|
||||||
|
|
||||||
|
**总体评价**:核心安全架构扎实(SQL 注入防护、密钥管理、MCP 多层防御、取消 TOCTOU)。主要风险集中在 `state.rs` 同步锁在 async 上下文中的潜在死锁、文档与代码脱节(AI对话引擎工具数过时、INDEX 漏列 9 文档、~100 行已移除模块残留)。前端整体质量高,但需清理少量遗留(Arco 残留、内联 confirm 重复)。
|
||||||
Reference in New Issue
Block a user