diff --git a/Cargo.lock b/Cargo.lock index 547ad40..af39c95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -859,6 +859,8 @@ dependencies = [ "tauri-plugin-window-state", "tokio", "tracing", + "tracing-appender", + "tracing-subscriber", "tree-sitter", "tree-sitter-go", "tree-sitter-java", @@ -4201,6 +4203,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + [[package]] name = "syn" version = "1.0.109" @@ -5039,6 +5047,19 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" +dependencies = [ + "crossbeam-channel", + "symlink", + "thiserror 2.0.18", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.31" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 41a8260..ab64d71 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -22,6 +22,8 @@ serde_json.workspace = true tokio.workspace = true anyhow.workspace = true tracing.workspace = true +tracing-subscriber = { version = "0.3", features = ["env-filter"] } +tracing-appender = "0.2" chrono.workspace = true # augmentation::MentionResolver async trait(Input Augmentation 层核心设计2) async-trait = { workspace = true } diff --git a/src-tauri/src/commands/ai/agentic/mod.rs b/src-tauri/src/commands/ai/agentic/mod.rs index 7d22766..e871028 100644 --- a/src-tauri/src/commands/ai/agentic/mod.rs +++ b/src-tauri/src/commands/ai/agentic/mod.rs @@ -816,6 +816,7 @@ pub(crate) async fn run_agentic_loop( tracing::info!( conv_id = %conv_id, count = goals.len(), + first_goal = %goals.first().map(|g| &g[..std::cmp::min(120, g.len())]).unwrap_or(""), "[ai] G1 目标钉扎:已把 {} 个 pinned_goals 拼进 system_prompt", goals.len() ); diff --git a/src-tauri/src/commands/ai/mod.rs b/src-tauri/src/commands/ai/mod.rs index 3497da1..1ee4d0f 100644 --- a/src-tauri/src/commands/ai/mod.rs +++ b/src-tauri/src/commands/ai/mod.rs @@ -437,24 +437,6 @@ fn normalize_dir_key(dir: &str) -> String { } } -/// workspace_root 字符串(作 run_command working_dir 缺省时的 trust key 回退)。 -/// -/// 与 tool_registry.rs workspace_root() 同源(CARGO_MANIFEST_DIR 上两级),canonicalize 后 -/// 保证与 run_command handler 默认 working_dir = workspace_root().to_string() 生成的 key 一致。 -fn workspace_root_str() -> String { - let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .parent() - .and_then(|p| p.parent()) - .map(PathBuf::from) - .unwrap_or_else(|| PathBuf::from(".")); - root.canonicalize() - .map(|c| c.to_string_lossy().to_string()) - .unwrap_or_else(|_| root.to_string_lossy().to_string()) -} - -// 引入 PathBuf 供 workspace_root_str / dir_of_path_normalized 使用 -use std::path::PathBuf; - /// AI 会话内状态(Mutex 保护) /// /// F-260616-09 B 批4(决策 e 真并发上线):会话级状态全部迁入 [`per_conv`](Self::per_conv) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 02d0006..24632cc 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -11,6 +11,27 @@ use df_tunnel::TunnelClient; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { + // 初始化文件日志:追加到 %TEMP%/devflow-trace.log,RUST_LOG 控制级别(默认 info) + let log_path = std::env::temp_dir().join("devflow-trace.log"); + let log_file = std::fs::OpenOptions::new() + .create(true) + .append(true) + .open(&log_path) + .expect("创建日志文件失败"); + let (non_blocking, _guard) = tracing_appender::non_blocking(log_file); + tracing_subscriber::fmt() + .with_env_filter( + tracing_subscriber::EnvFilter::try_from_default_env() + .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")) + ) + .with_writer(non_blocking) + .with_ansi(false) + .init(); + tracing::info!( + path = %log_path.display(), + "[startup] 日志已初始化" + ); + tauri::Builder::default() .plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_dialog::init()) diff --git a/src-tauri/src/state.rs b/src-tauri/src/state.rs index f1f6f16..d725fd5 100644 --- a/src-tauri/src/state.rs +++ b/src-tauri/src/state.rs @@ -463,9 +463,9 @@ impl AllowedDirs { pub const SETTINGS_KEY: &'static str = "allowed_dirs"; /// 空白名单(方案①弱化 workspace_root:不再编译期硬塞开发机 CARGO_MANIFEST_DIR)。 - /// 分发后该路径指向编译机不存在的目录,硬塞反成脏白名单;用户首次访问任意目录 - /// 走弹窗三档授权(once/session/always),对齐产品定位(不预设源码目录)。仅作 init - /// 占位(reload_allowed_dirs 从 KV 覆盖)+ 测试构造基线。 + /// 分发后该路径指向编译机不存在的目录,硬塞反成脏白名单。 + /// 当前仅测试使用,生产环境由 reload_allowed_dirs 覆盖。 + #[cfg_attr(not(test), allow(dead_code))] pub fn default_with_root() -> Self { Self { persistent: HashSet::new(), session: HashSet::new(), once: HashSet::new() } } @@ -668,14 +668,6 @@ fn workspace_root_path() -> PathBuf { .unwrap_or_else(|| PathBuf::from(".")) } -/// 应用数据目录(运行期确定,跨平台)。 -/// 不依赖编译期常量,打包分发后仍有效。 -/// 用于 DevFlow 自身数据存储(.trash / logs 等),非用户项目目录。 -/// 取 AppState.data_dir,不持 state 时回退 workspace_root_path()(开发期兼容)。 -pub fn data_dir_path(state: &AppState) -> &Path { - &state.data_dir -} - impl AppState { /// 初始化应用状态:打开(或创建)数据库并执行迁移,构建各 Repo 与节点注册表 pub async fn init(db_path: &Path, data_dir: PathBuf) -> Result {