diff --git a/src/gateway/cron-exit-watch-shell.ts b/src/gateway/cron-exit-watch-shell.ts index db59c9eb1469..b769737dd6c4 100644 --- a/src/gateway/cron-exit-watch-shell.ts +++ b/src/gateway/cron-exit-watch-shell.ts @@ -5,7 +5,7 @@ export function resolveExitWatchShell(platform: NodeJS.Platform = process.platfo } { if (platform === "win32") { return { - command: process.env.ComSpec ?? "cmd.exe", + command: process.env.ComSpec?.trim() || "cmd.exe", // /d skip AutoRun, /s strip outer quotes, /c run then exit. argsFor: (command: string) => ["/d", "/s", "/c", command], }; diff --git a/src/gateway/cron-exit-watchers.test.ts b/src/gateway/cron-exit-watchers.test.ts index caa45ffadcba..939cf304c149 100644 --- a/src/gateway/cron-exit-watchers.test.ts +++ b/src/gateway/cron-exit-watchers.test.ts @@ -1,5 +1,5 @@ import { expectDefined } from "@openclaw/normalization-core"; -import { describe, expect, it, vi } from "vitest"; +import { afterEach, describe, expect, it, vi } from "vitest"; import type { CronJob } from "../cron/types.js"; import { resolveExitWatchShell } from "./cron-exit-watch-shell.js"; import { createCronExitWatchers, type CronExitResult } from "./cron-exit-watchers.js"; @@ -437,12 +437,21 @@ describe("createCronExitWatchers", () => { }); describe("resolveExitWatchShell", () => { + afterEach(() => { + vi.unstubAllEnvs(); + }); + it("uses cmd.exe on Windows so native gateways without bash can run on-exit", () => { const shell = resolveExitWatchShell("win32"); expect(shell.command).toMatch(/cmd\.exe$/i); expect(shell.argsFor("echo hi")).toEqual(["/d", "/s", "/c", "echo hi"]); }); + it("uses cmd.exe when ComSpec is blank", () => { + vi.stubEnv("ComSpec", " "); + expect(resolveExitWatchShell("win32").command).toBe("cmd.exe"); + }); + it("uses bash -lc on POSIX", () => { expect(resolveExitWatchShell("linux").command).toBe("bash"); expect(resolveExitWatchShell("linux").argsFor("echo hi")).toEqual(["-lc", "echo hi"]);