fix: quote Windows UI runner paths

This commit is contained in:
Peter Steinberger
2026-04-26 08:30:46 +01:00
parent 434c8a1c91
commit 4c7a94aac4
3 changed files with 22 additions and 3 deletions

View File

@@ -80,6 +80,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- UI/Windows: quote resolved pnpm `.cmd` launcher paths before spawning UI install/build/test commands so Node installs under `C:\Program Files` no longer fail as `C:\Program`. Fixes #45275. Thanks @Kobevictor, @stoppieboy, and @iubns.
- Plugins/uninstall: remove tracked plugin files from their recorded managed extensions root even when the current state directory points somewhere else, so `openclaw plugins uninstall --force` does not leave the plugin discoverable. Thanks @shakkernerd.
- Agents/runtime: add `agentRuntime.id` as the canonical config key, migrate
legacy runtime-policy configs with `openclaw doctor --fix`, and route

View File

@@ -76,6 +76,10 @@ export function assertSafeWindowsShellArgs(args, platform = process.platform) {
);
}
export function prepareSpawnCommand(cmd, platform = process.platform) {
return shouldUseShellForCommand(cmd, platform) ? `"${cmd}"` : cmd;
}
function createSpawnOptions(cmd, args, envOverride) {
const useShell = shouldUseShellForCommand(cmd);
if (useShell) {
@@ -92,7 +96,7 @@ function createSpawnOptions(cmd, args, envOverride) {
function run(cmd, args) {
let child;
try {
child = spawn(cmd, args, createSpawnOptions(cmd, args));
child = spawn(prepareSpawnCommand(cmd), args, createSpawnOptions(cmd, args));
} catch (err) {
console.error(`Failed to launch ${cmd}:`, err);
process.exit(1);
@@ -113,7 +117,7 @@ function run(cmd, args) {
function runSync(cmd, args, envOverride) {
let result;
try {
result = spawnSync(cmd, args, createSpawnOptions(cmd, args, envOverride));
result = spawnSync(prepareSpawnCommand(cmd), args, createSpawnOptions(cmd, args, envOverride));
} catch (err) {
console.error(`Failed to launch ${cmd}:`, err);
process.exit(1);

View File

@@ -1,5 +1,9 @@
import { describe, expect, it } from "vitest";
import { assertSafeWindowsShellArgs, shouldUseShellForCommand } from "../../scripts/ui.js";
import {
assertSafeWindowsShellArgs,
prepareSpawnCommand,
shouldUseShellForCommand,
} from "../../scripts/ui.js";
describe("scripts/ui windows spawn behavior", () => {
it("enables shell for Windows command launchers that require cmd.exe", () => {
@@ -14,6 +18,16 @@ describe("scripts/ui windows spawn behavior", () => {
expect(shouldUseShellForCommand("/usr/local/bin/pnpm", "linux")).toBe(false);
});
it("quotes Windows shell launcher paths before passing them to spawn", () => {
expect(prepareSpawnCommand("C:\\Program Files\\nodejs\\pnpm.cmd", "win32")).toBe(
'"C:\\Program Files\\nodejs\\pnpm.cmd"',
);
expect(prepareSpawnCommand("C:\\Program Files\\nodejs\\pnpm.exe", "win32")).toBe(
"C:\\Program Files\\nodejs\\pnpm.exe",
);
expect(prepareSpawnCommand("/usr/local/bin/pnpm", "linux")).toBe("/usr/local/bin/pnpm");
});
it("allows safe forwarded args when shell mode is required on Windows", () => {
expect(() =>
assertSafeWindowsShellArgs(["run", "build", "--filter", "@openclaw/ui"], "win32"),