//! AE-2025-03(路径 B):write_file 审批预览 diff 生成。 //! //! 第五批从 audit/mod.rs 抽离,行为零变更。`build_write_file_diff` 仅 process_tool_calls //! 在 write_file 高风险审批分支裸名调用,依赖 `super::super::tool_registry::generate_diff` //! (F-260615-10 LCS 行级 diff),故 diff.rs 直接 `use super::super::tool_registry::generate_diff`。 //! //! re-export 保持原路径透明:audit/mod.rs 通过 `use diff::build_write_file_diff` 裸名调用。 use super::super::tool_registry::generate_diff; /// 从 write_file args 取 path(旧文件路径)+ content(新内容), /// 预读旧文件 → 复用 `generate_diff`(F-260615-10 LCS 行级 diff)注入审批事件。 /// 旧文件不存在(新建)/ 读失败 / args 缺字段 → None(前端回退显新 content)。 /// /// **仅读不改**:审批未通过前不动文件;读路径不校验(write_file handler 自身会校验 /// validate_path,审批拒绝则 handler 不执行,恶意路径读失败仅得到 None 不产生危害)。 pub(super) async fn build_write_file_diff(args: &serde_json::Value) -> Option { let path = args.get("path")?.as_str()?; let new_content = args.get("content")?.as_str()?; match tokio::fs::read_to_string(path).await { Ok(old_content) => { if old_content == new_content { return None; // 无变化不生成 diff(理论上 write_file 不会如此,容错) } Some(generate_diff(&old_content, new_content)) } Err(_) => None, // 文件不存在(新建)/ 无读权限 → 无 diff,前端显新 content } }