From ed9d9b5436a7c18bf2946f49c56d1f6ee4382a9d Mon Sep 17 00:00:00 2001 From: w0x7ce Date: Mon, 29 Dec 2025 09:36:55 +0800 Subject: [PATCH] fix(commands): add auto-cleanup for temp config files when terminal closes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在 open_provider_terminal 功能中添加了临时配置文件的自动清理逻辑, 确保在用户关闭终端窗口时自动删除创建的临时配置文件。 修改内容: - Linux: 使用 bash -c 嵌套包装脚本,通过 trap EXIT 信号在 shell 退出时清理配置文件 - macOS: 同样使用嵌套 bash + trap 机制来处理清理 - Windows: 保持原有的批处理文件自删除逻辑(del 命令) 技术细节: - 之前使用 sh -c "...; exec $SHELL" 会导致 trap 失效 - 现在使用 bash -c 'trap ... EXIT; ...; exec bash --norc --noprofile' - exec 会替换进程但保留 trap 信号处理器 - 当用户关闭终端时,EXIT 信号触发清理操作 影响范围: - src-tauri/src/commands/misc.rs (launch_terminal_with_env 函数) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src-tauri/src/commands/misc.rs | 73 ++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 17 deletions(-) diff --git a/src-tauri/src/commands/misc.rs b/src-tauri/src/commands/misc.rs index 122e9b1bc..6be009ef0 100644 --- a/src-tauri/src/commands/misc.rs +++ b/src-tauri/src/commands/misc.rs @@ -410,17 +410,28 @@ fn launch_terminal_with_env(env_vars: Vec<(String, String)>, provider_id: &str) #[cfg(target_os = "macos")] { - // macOS: 使用 Terminal.app 启动 claude + // macOS: 使用 Terminal.app 启动 claude,使用包装脚本来处理清理 let mut terminal_cmd = Command::new("osascript"); terminal_cmd.arg("-e"); - let config_file_for_cleanup = config_file.clone(); + // 使用 bash 的 trap 来清理配置文件 + let config_path_for_script = config_file.to_string_lossy() + .replace('\\', "\\\\") + .replace('"', "\\\""); + + let shell_script = format!( + "bash -c 'trap \"rm -f \\\"{}\\\"\" EXIT; echo \"Using provider-specific claude config:\"; echo \"{}\"; claude --settings \"{}\"; exec bash --norc --noprofile'", + config_path_for_script, + config_path_escaped, + config_path_escaped + ); + let script = format!( r#"tell application "Terminal" activate - do script "echo 'Using provider-specific claude config:' && echo '{}' && claude --settings '{}'; exit" + do script "{}" end tell"#, - config_path_escaped, config_path_escaped + shell_script.replace('\\', "\\\\").replace('"', "\\\"") ); terminal_cmd.arg(&script); @@ -434,7 +445,7 @@ fn launch_terminal_with_env(env_vars: Vec<(String, String)>, provider_id: &str) #[cfg(target_os = "linux")] { - // Linux: 尝试使用常见终端 + // Linux: 尝试使用常见终端,使用包装脚本在 shell 退出时清理配置文件 let terminals = [ "gnome-terminal", "konsole", "xfce4-terminal", "mate-terminal", "lxterminal", "alacritty", "kitty", @@ -442,21 +453,38 @@ fn launch_terminal_with_env(env_vars: Vec<(String, String)>, provider_id: &str) let mut last_error = String::from("未找到可用的终端"); + // 使用 bash 创建包装脚本来处理清理 + let config_path_for_bash = config_file.to_string_lossy(); + let shell_cmd = format!( + "bash -c 'trap \"rm -f \\\"{}\\\"\" EXIT; echo \"Using provider-specific claude config:\"; echo \"{}\"; claude --settings \"{}\"; exec bash --norc --noprofile'", + config_path_for_bash, config_path_escaped, config_path_escaped + ); + for terminal in terminals { // 检查终端是否存在 if Command::new("which").arg(terminal).output().is_err() { continue; } - let result = Command::new(terminal) - .arg("--") - .arg("sh") - .arg("-c") - .arg(&format!( - "echo 'Using provider-specific claude config:' && echo '{}' && claude --settings '{}'; $SHELL", - config_path_escaped, config_path_escaped - )) - .spawn(); + // 不同的终端使用不同的参数格式 + let result = match terminal { + "gnome-terminal" | "mate-terminal" => { + Command::new(terminal) + .arg("--") + .arg("bash") + .arg("-c") + .arg(&shell_cmd) + .spawn() + } + _ => { + Command::new(terminal) + .arg("-e") + .arg("bash") + .arg("-c") + .arg(&shell_cmd) + .spawn() + } + }; match result { Ok(_) => { @@ -478,13 +506,24 @@ fn launch_terminal_with_env(env_vars: Vec<(String, String)>, provider_id: &str) { use std::io::Write; - // Windows: 创建临时批处理文件 + // Windows: 创建临时批处理文件,并在执行完毕后清理配置文件 let bat_file = temp_dir.join(format!("cc_switch_claude_{}.bat", std::process::id())); + // 转义配置文件路径用于批处理 + let config_path_for_batch = config_file.to_string_lossy() + .to_string() + .replace('&', "^&"); + let mut content = String::from("@echo off\n"); content.push_str(&format!("echo Using provider-specific claude config:\n")); - content.push_str(&format!("echo {}\n", config_file.to_string_lossy().to_string().replace('&', "^&"))); - content.push_str(&format!("claude --settings \"{}\"\n", config_file.to_string_lossy().to_string().replace('&', "^&"))); + content.push_str(&format!("echo {}\n", config_path_for_batch)); + content.push_str(&format!("claude --settings \"{}\"\n", config_path_for_batch)); + + // 在 claude 执行完毕后(无论成功与否),删除临时配置文件和批处理文件本身 + content.push_str(&format!("del \"{}\" >nul 2>&1\n", config_path_for_batch)); + content.push_str(&format!("del \"%%~f0\" >nul 2>&1\n")); // %%~f0 表示批处理文件自身 + + // 如果 claude 出错,暂停以便用户查看错误信息 content.push_str("if errorlevel 1 (\n"); content.push_str(" echo.\n"); content.push_str(" echo Press any key to close...\n");