From 4835185d66e239f706f9c3d63f24036a689e4bff Mon Sep 17 00:00:00 2001 From: Eduard Ruzga Date: Fri, 5 Jun 2026 13:32:34 +0300 Subject: [PATCH] fix(windows): preserve quotes in cmd commands via verbatim args On Windows, start_process spawns the shell executable directly (`cmd /c `) with useShellOption=false. Node/libuv then applies its default MSVCRT-style argument quoting, which escapes embedded double quotes as \". cmd.exe does not treat \" as an escape, so every quoted command was corrupted before cmd parsed it -- e.g. a quoted path with spaces ("C:\Program Files\app.exe") or `tasklist /fi "imagename eq x"` would fail with "syntax incorrect" / "Invalid argument". Set windowsVerbatimArguments=true for the cmd branch so cmd parses its own quoting (the same thing Node does internally for `shell: true`). Scoped to cmd only via a new ShellSpawnConfig.windowsVerbatim flag: PowerShell/pwsh have different quote rules and must NOT use verbatim (it splits quoted arguments into separate tokens), and POSIX shells (bash/zsh/fish, incl. WSL) are unaffected -- windowsVerbatimArguments is a no-op outside win32. No behaviour change on macOS/Linux. Before: echo "hello world" a"b"c -> \"hello world\" a\"b\"c After: echo "hello world" a"b"c -> "hello world" a"b"c --- src/terminal-manager.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/terminal-manager.ts b/src/terminal-manager.ts index 00ffb6f2..821a514b 100644 --- a/src/terminal-manager.ts +++ b/src/terminal-manager.ts @@ -62,6 +62,9 @@ interface ShellSpawnConfig { executable: string; args: string[]; useShellOption: string | boolean; + // When true, pass args verbatim on Windows (see executeCommand). Only cmd.exe + // needs this; its quote parsing conflicts with libuv's default \" escaping. + windowsVerbatim?: boolean; } /** @@ -103,6 +106,7 @@ function getShellSpawnArgs(shellPath: string, command: string): ShellSpawnConfig return { executable: shellPath, args: ['/c', command], + windowsVerbatim: true, useShellOption: false }; } @@ -222,6 +226,17 @@ export class TerminalManager { spawnOptions.env.PATHEXT = getRepairedPathExt(); } + // On Windows, when we invoke cmd.exe directly and pass the user's command as a + // single argument, Node/libuv applies MSVCRT-style quoting that escapes embedded + // double quotes as \" . cmd.exe does not understand that escaping, so any command + // containing quotes (e.g. a quoted path with spaces like "C:\Program Files\app.exe") + // is corrupted before the shell ever parses it. Passing arguments verbatim lets + // cmd handle its own quoting. Scoped to shells that set windowsVerbatim (cmd only) + // because PowerShell/pwsh have different quote rules and must NOT use verbatim. + if (process.platform === 'win32' && spawnConfig.windowsVerbatim) { + spawnOptions.windowsVerbatimArguments = true; + } + // Spawn the process with appropriate arguments const childProcess = spawn(spawnConfig.executable, spawnConfig.args, spawnOptions); let output = '';