diff --git a/next/src/lib/agents/detect.ts b/next/src/lib/agents/detect.ts index c72c8db..ef0b0d6 100644 --- a/next/src/lib/agents/detect.ts +++ b/next/src/lib/agents/detect.ts @@ -360,9 +360,10 @@ export async function resolveOpenclawAgentId(bin: string): Promise { try { const { spawn } = await import("node:child_process"); const out = await new Promise((res, rej) => { - const child = spawn(bin, ["agents", "list"], { + const useShell = process.platform === "win32"; + const child = spawn(useShell ? `"${bin}"` : bin, ["agents", "list"], { stdio: ["ignore", "pipe", "pipe"], - shell: process.platform === "win32", + shell: useShell, }); let buf = ""; child.stdout.setEncoding("utf8"); diff --git a/next/src/lib/agents/invoke.ts b/next/src/lib/agents/invoke.ts index 6626592..78c7903 100644 --- a/next/src/lib/agents/invoke.ts +++ b/next/src/lib/agents/invoke.ts @@ -158,18 +158,20 @@ export function invokeAgent(opts: InvokeOpts): ReadableStream { if (promptViaMessageFlag) argv = [...argv, "--message", opts.prompt]; try { - child = spawn(bin!, argv, { + // On Windows, `spawn` cannot launch a `.cmd` / `.bat` shim (which is + // what npm installs for most CLI agents) without going through the + // shell. Without this, every agent invocation fails with + // EINVAL / "spawn 无效的参数". macOS/Linux use direct exec. + // Safety: prompt content is delivered via stdin or `--message + // ` (argv-message), not interpolated into a shell command, + // so this does not introduce a shell-injection vector. + const useShell = process.platform === "win32"; + child = spawn(useShell ? `"${bin}"` : bin!, argv, { cwd: opts.cwd ?? process.cwd(), env, stdio: ["pipe", "pipe", "pipe"], - // On Windows, `spawn` cannot launch a `.cmd` / `.bat` shim (which is - // what npm installs for most CLI agents) without going through the - // shell. Without this, every agent invocation fails with - // EINVAL / "spawn 无效的参数". macOS/Linux use direct exec. - // Safety: prompt content is delivered via stdin or `--message - // ` (argv-message), not interpolated into a shell command, - // so this does not introduce a shell-injection vector. - shell: process.platform === "win32", + shell: useShell, + windowsVerbatimArguments: false, }); } catch (err) { safeEnqueue({