Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions next/src/lib/agents/detect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,9 +360,10 @@ export async function resolveOpenclawAgentId(bin: string): Promise<string> {
try {
const { spawn } = await import("node:child_process");
const out = await new Promise<string>((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");
Expand Down
20 changes: 11 additions & 9 deletions next/src/lib/agents/invoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,18 +158,20 @@ export function invokeAgent(opts: InvokeOpts): ReadableStream<InvokeEvent> {
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
// <text>` (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, {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolveOpenclawAgentId(bin) is called just above this block for the OpenClaw path, and that helper still does spawn(bin, ["agents", "list"], { shell: process.platform === "win32" }) in next/src/lib/agents/detect.ts:363-366. On a Windows install under C:\Program Files\..., cmd.exe will split that probe exactly the same way it split the main launch path here, so OpenClaw still fails before this quoted spawn(...) ever runs. Because the helper catches the error and falls back to "main", the failure is also silent and can target the wrong agent when the configured OpenClaw agent id is not main. Please apply the same useShell ? \"${bin}"` : binhandling inresolveOpenclawAgentId`, and add regression coverage for the Windows probe path with a spaced binary location.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

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
// <text>` (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({
Expand Down