fix(windows): resolve daemon startup failures and Git Bash compatibility (#582)

* fix(windows): resolve daemon startup failures and Git Bash compatibility

Three root causes behind 27 open Windows issues:

1. Path::canonicalize() returns \\?\ prefixed paths on Windows that
   Node.js cannot parse, preventing daemon startup. Strip the prefix
   before passing to Node. (fixes #522, #390, #56, #25, #37, #89)

2. Git Bash/MSYS2 translates Unix-style paths and resolves node to
   a shell wrapper script. Use node.exe explicitly and set
   MSYS_NO_PATHCONV/MSYS2_ARG_CONV_EXCL to prevent argument mangling.
   (fixes #148, #108, #171)

3. postinstall fixWindowsShims() hardcoded x64 arch and did not verify
   the native binary exists before rewriting shims. Now detects arch
   dynamically and validates the binary path. (fixes #262)

Also:
- Error messages now show TCP port on Windows instead of Unix socket path
- Windows CI expanded to test full daemon lifecycle (open, snapshot, close)

* fix(windows): strip \\?\ prefix in auth-cli path (fixes #579)

Same canonicalize() issue as the daemon spawn path, but in
run_auth_cli() which passes the script path to Node.js.
This commit is contained in:
Chris Tate
2026-03-03 08:00:14 -06:00
committed by GitHub
parent d97e2016f5
commit c6a33b6338
4 changed files with 77 additions and 26 deletions
+16
View File
@@ -31,6 +31,15 @@ use std::process::Command as ProcessCommand;
fn run_auth_cli(cmd: &serde_json::Value, json_mode: bool) -> ! {
let exe_path = env::current_exe().unwrap_or_default();
let exe_path = exe_path.canonicalize().unwrap_or(exe_path);
#[cfg(windows)]
let exe_path = {
let p = exe_path.to_string_lossy();
if let Some(stripped) = p.strip_prefix(r"\\?\") {
PathBuf::from(stripped)
} else {
exe_path
}
};
let exe_dir = exe_path.parent().unwrap_or(std::path::Path::new("."));
let mut script_paths = vec![
@@ -233,6 +242,13 @@ fn main() {
libc::signal(libc::SIGPIPE, libc::SIG_DFL);
}
// Prevent MSYS/Git Bash path translation from mangling arguments
#[cfg(windows)]
{
env::set_var("MSYS_NO_PATHCONV", "1");
env::set_var("MSYS2_ARG_CONV_EXCL", "*");
}
let args: Vec<String> = env::args().skip(1).collect();
let flags = parse_flags(&args);
let clean = clean_args(&args);