From d2f586fc52e72d082b057c910e7b4071f76bd662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BB=9D=E5=B0=98?= <237809796@qq.com> Date: Tue, 6 Oct 2026 12:47:18 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E:=20=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E6=B1=87=E6=8A=A5=E9=99=84=20git=20=E5=AE=9E=E6=B5=8B=E9=99=84?= =?UTF-8?q?=E5=BD=95=20branch/HEAD/=E6=9C=AA=E6=8F=90=E4=BA=A4=E8=AE=A1?= =?UTF-8?q?=E6=95=B0(B1-H1=20=E5=8D=95=E7=82=B9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/todo.md | 3 +-- src-tauri/src/commands/ai/commands/chat.rs | 29 ++++++++++++++++++++++ src-tauri/src/commands/ai/tools/git.rs | 10 ++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/docs/todo.md b/docs/todo.md index 7deb17e..e5cac4e 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -1057,8 +1057,7 @@ graph TD > 附:挂机汇报自报 🔴10 已修验证通过+43 文件产出——挂机模式推进有效,路径修复别误伤它。 ## 无人值守可靠性专项(2026-10-06 swarm 立项,设计档:docs/02-架构设计/无人值守可靠性专项设计-20261006.md+temp/V49断点续跑设计-20261006.md) -- [ ] B1(S):H1 汇报 git 实测附录(chat.rs:919 单点)+ 探活告警口径修正 -- [ ] B2(M):H2 token 三闸(抄 sub_agent round_budget_stop)+ H4 产出审计 subscriber +- [x] B1(S):H1 汇报 git 实测附录 ✅(2026-10-06:deliver_completion_report_if_waited 单点 append_git_facts——branch/HEAD/未提交计数三行,非 git 仓静默跳过,超长报告不追,git.rs 增 git_exec 只读薄封装)+ 探活告警口径修正 ✅(同日 18 批:inflight 计数点前移到 handle_message 白名单通过处,覆盖占位卡 HTTP+per-chat 锁排队窗口,旧计数点删除防双计)- [ ] B2(M):H2 token 三闸(抄 sub_agent round_budget_stop)+ H4 产出审计 subscriber - [ ] B3(M):V49 防覆盖定稿+单测 + ai_list_recoverable IPC + 桌面「可恢复」入口 - [ ] B4(L):ai_recover_parked 重启恢复 + H3 外部干预感知(git HEAD 比对→Parked) diff --git a/src-tauri/src/commands/ai/commands/chat.rs b/src-tauri/src/commands/ai/commands/chat.rs index 8464724..60218a0 100644 --- a/src-tauri/src/commands/ai/commands/chat.rs +++ b/src-tauri/src/commands/ai/commands/chat.rs @@ -922,6 +922,11 @@ pub(crate) async fn deliver_completion_report_if_waited(app_handle: &AppHandle, return; } let report = crate::commands::ai::agentic::last_active_assistant_text(&app_state.ai_session, conv_id).await; + // B1-H1 汇报附 git 实测(无人值守可靠性专项,2026-10-06):自报≠事实(11:23 汇报失实证), + // summary 组装单点追加 git 实测附录——非 git 仓/命令失败静默跳过(附录是增益非阻断); + // 有未提交改动时标 ⚠ 防汇报宣称「已提交」而工作区残留。飞书 watcher 与桌面任务卡 + // 零改动同享(单一事实源)。 + let report = append_git_facts(&report).await; app_state.notify_agent_completion(conv_id, report.clone()); // ── #14 任务式委托(2026-10-06):完成事件广播 ── // 通知桥 oneshot 只投给单个等待方(编排节点/飞书 handle_message);异步委托两段式下 @@ -941,6 +946,30 @@ pub(crate) async fn deliver_completion_report_if_waited(app_handle: &AppHandle, }); } +/// B1-H1 git 实测附录(无人值守专项):branch/HEAD/未提交计数三行,汇报自报之外的 +/// 机器事实。git 不可用(非仓/超时/未装)返回原文不动——附录增益非阻断,失败不惊扰。 +/// 摘要超长时不追附录(报告限长纪律,附录在末尾易被消费端截断丢失反而误导)。 +async fn append_git_facts(report: &str) -> String { + // 空报告/超长报告不追(超长阈值与子代理报告纪律同量级) + if report.trim().is_empty() || report.chars().count() > 8000 { + return report.to_string(); + } + // cwd 取当前工作目录(与桌面应用运行根一致;失败用 "." 兜底) + let cwd = std::env::current_dir() + .map(|p| p.to_string_lossy().to_string()) + .unwrap_or_else(|_| ".".to_string()); + let (branch, b_ok) = crate::commands::ai::tools::git::git_exec("rev-parse", &["--abbrev-ref", "HEAD"], &cwd).await; + if !b_ok { + return report.to_string(); // 非 git 仓/命令失败:静默跳过 + } + let (head, h_ok) = crate::commands::ai::tools::git::git_exec("rev-parse", &["--short", "HEAD"], &cwd).await; + let (dirty, d_ok) = crate::commands::ai::tools::git::git_exec("status", &["--porcelain"], &cwd).await; + let dirty_n = if d_ok { dirty.lines().filter(|l| !l.trim().is_empty()).count() } else { 0 }; + let dirty_mark = if dirty_n > 0 { format!(" ⚠ {dirty_n} 项未提交") } else { String::new() }; + let head_s = if h_ok { head.trim() } else { "?" }; + format!("{report}\n\n---\n📎 git 实测: `{branch}`@{head_s}{dirty_mark}") +} + pub(crate) fn orchestration_session_spawner() -> df_nodes::ai_agent_node::SpawnFn { std::sync::Arc::new(|task: String| -> df_nodes::ai_agent_node::SpawnFuture { Box::pin(async move { diff --git a/src-tauri/src/commands/ai/tools/git.rs b/src-tauri/src/commands/ai/tools/git.rs index e9784bc..b084f5b 100644 --- a/src-tauri/src/commands/ai/tools/git.rs +++ b/src-tauri/src/commands/ai/tools/git.rs @@ -89,6 +89,16 @@ async fn exec_git(working_dir: &str, args: &[&str]) -> (String, bool) { (out, code == Some(0)) } +/// B1-H1 git 实测附录(无人值守专项)专用只读入口:rev-parse/status 等探测命令, +/// 供 deliver_completion_report_if_waited 汇报附录调用。独立薄封装而非开放 exec_git—— +/// 写操作仍收敛在本模块工具注册内,附录路径只读零副作用。 +pub(crate) async fn git_exec(sub: &str, args: &[&str], working_dir: &str) -> (String, bool) { + let mut full: Vec<&str> = Vec::with_capacity(args.len() + 1); + full.push(sub); + full.extend_from_slice(args); + exec_git(working_dir, &full).await +} + /// git status --porcelain 解析为结构化文件列表。 /// /// 成功判定(对齐 run_command succeeded=exit_code==0 口径):`status --porcelain`