From 5cd045316228fa95c2ecfdd7af24fce6fe4712a4 Mon Sep 17 00:00:00 2001 From: ArthurErlich Date: Sun, 6 Sep 2026 18:21:33 +0200 Subject: [PATCH] Fix qwen_delegate: quote args for shell:true on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Node's shell:true does NOT escape array args on Windows (DEP0190) — it just space-joins them, so any multi-word prompt silently split into extra positional args and collided with qwen's -p flag ("Cannot use both a positional prompt and the --prompt (-p) flag together"). Never caught before because the tool was only smoke-tested via tools/list, not an actual invocation. Build the command as a single explicitly-quoted string instead. Verified against real qwen-code CLI arg parsing; existing mocked tests still pass. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01CRnb5Gqdu7gVTQrwAqFdfJ --- src/qwen-delegate.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/qwen-delegate.ts b/src/qwen-delegate.ts index 04317a9..b76d63d 100644 --- a/src/qwen-delegate.ts +++ b/src/qwen-delegate.ts @@ -25,15 +25,22 @@ const DEFAULT_TIMEOUT_MS = 10 * 60 * 1000; // 10 min * qwen-code prints startup warnings (e.g. failed MCP sub-servers) to stderr; those are * ignored on success and surfaced only when the run itself fails. */ -export function delegateToQwen ( +export function delegateToQwen( prompt: string, options: DelegateOptions = {}, ): Promise { const { timeoutMs = DEFAULT_TIMEOUT_MS, spawnFn = spawn } = options; return new Promise((resolve) => { - const child: ChildProcess = spawnFn("qwen", ["-p", prompt], { - shell: true, // qwen.cmd on Windows needs a shell to resolve + // shell:true is required for qwen.cmd to resolve on Windows, but Node does NOT escape + // array args in that mode (see DEP0190) — it just space-joins them, so an unquoted + // multi-word prompt silently splits into extra positional args and confuses qwen's CLI + // parser ("Cannot use both a positional prompt and the --prompt (-p) flag together"). + // Build the command as a single, explicitly-quoted string instead. + const quoteArg = (s: string) => `"${s.replace(/"/g, '\\"')}"`; + const command = ["qwen", "-p", quoteArg(prompt)].join(" "); + const child: ChildProcess = spawnFn(command, { + shell: true, stdio: ["ignore", "pipe", "pipe"], });