From a132c0271180a0f4d0c155da711bf26554158584 Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Sat, 16 May 2026 13:04:08 +0700 Subject: [PATCH] fix(update): bypass Rust arg escaping in cmd.exe handoff MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rust's std::process::Command escapes inner double quotes as \" when wrapping the args(["/c", &cmd]) array. cmd.exe does not understand the \" escape, so the swap-and-restart command got mangled: `start "" "PATH"` arrived as `start \"\" \"PATH\"`, which the cmd parser collapsed into `start \ PATH` — producing the "Windows cannot find '\'" dialog and aborting the update. Switching to raw_arg lets us hand cmd.exe the literal command line it expects. The two quote characters cmd needs to keep are the outer pair wrapping the whole /c argument; cmd's "more than two quotes, special chars present" branch then preserves the inner path quotes intact. Bumps version to 0.1.2 since this is the first updater fix that ships through the updater itself for any future v0.1.2+ user. --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/update/install.rs | 8 +++++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9f39421..ecfe73b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -68,7 +68,7 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "claude-code-usage-bubble" -version = "0.1.1" +version = "0.1.2" dependencies = [ "dirs", "embed-resource", diff --git a/Cargo.toml b/Cargo.toml index ac99889..a86ca95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "claude-code-usage-bubble" -version = "0.1.1" +version = "0.1.2" edition = "2021" license = "Apache-2.0" description = "Floating bubble showing Claude Code and Codex usage on Windows" diff --git a/src/update/install.rs b/src/update/install.rs index d248704..e0d6213 100644 --- a/src/update/install.rs +++ b/src/update/install.rs @@ -58,8 +58,14 @@ fn spawn_handoff(source: &std::path::Path, target: &std::path::Path) -> Result<( let cmd = format!( r#"timeout /t 2 /nobreak >nul & move /y "{src_str}" "{tgt_str}" & start "" "{tgt_str}""# ); + // raw_arg bypasses Rust's std auto-escaping which would turn the inner + // `"` characters into `\"`. cmd.exe does not recognise `\"`, so the + // escaped form makes `start` see the path as `\\` and emit a + // "Windows cannot find '\\'" dialog. Feeding the command line raw + // preserves the quotes cmd.exe actually expects. Command::new("cmd.exe") - .args(["/c", &cmd]) + .raw_arg("/c") + .raw_arg(format!("\"{cmd}\"")) .creation_flags(CREATE_NO_WINDOW | DETACHED_PROCESS) .stdin(Stdio::null()) .stdout(Stdio::null())