mirror of
https://github.com/openclaw/openclaw.git
synced 2026-02-19 18:39:20 -05:00
fix(process): disable detached spawn on Windows to fix empty exec output (#18035)
The supervisor's child adapter always spawned with `detached: true`,
which creates a new process group. On Windows Scheduled Tasks (headless,
no console), this prevents stdout/stderr pipes from properly connecting,
causing all exec tool output to silently disappear.
The old exec path (pre-supervisor refactor) never used `detached: true`.
The regression was introduced in cd44a0d01 (refactor process spawning).
Changes:
- child.ts: set `detached: false` on Windows, keep `detached: true` on
POSIX (where it's needed to survive parent exit). Skip the no-detach
fallback on Windows since it's already the default.
- child.test.ts: platform-aware assertions for detached behavior.
Fixes #18035
Fixes #17806
This commit is contained in:
committed by
Peter Steinberger
parent
d0a5ee0176
commit
a1a1f56841
@@ -60,8 +60,15 @@ describe("createChildAdapter", () => {
|
||||
options?: { detached?: boolean };
|
||||
fallbacks?: Array<{ options?: { detached?: boolean } }>;
|
||||
};
|
||||
expect(spawnArgs.options?.detached).toBe(true);
|
||||
expect(spawnArgs.fallbacks?.[0]?.options?.detached).toBe(false);
|
||||
// On Windows, detached defaults to false (headless Scheduled Task compat);
|
||||
// on POSIX, detached is true with a no-detach fallback.
|
||||
if (process.platform === "win32") {
|
||||
expect(spawnArgs.options?.detached).toBe(false);
|
||||
expect(spawnArgs.fallbacks).toEqual([]);
|
||||
} else {
|
||||
expect(spawnArgs.options?.detached).toBe(true);
|
||||
expect(spawnArgs.fallbacks?.[0]?.options?.detached).toBe(false);
|
||||
}
|
||||
|
||||
adapter.kill();
|
||||
|
||||
|
||||
@@ -42,11 +42,17 @@ export async function createChildAdapter(params: {
|
||||
|
||||
const stdinMode = params.stdinMode ?? (params.input !== undefined ? "pipe-closed" : "inherit");
|
||||
|
||||
// On Windows, `detached: true` creates a new process group and can prevent
|
||||
// stdout/stderr pipes from connecting when running under a Scheduled Task
|
||||
// (headless, no console). Default to `detached: false` on Windows; on
|
||||
// POSIX systems keep `detached: true` so the child survives parent exit.
|
||||
const useDetached = process.platform !== "win32";
|
||||
|
||||
const options: SpawnOptions = {
|
||||
cwd: params.cwd,
|
||||
env: params.env ? toStringEnv(params.env) : undefined,
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
detached: true,
|
||||
detached: useDetached,
|
||||
windowsHide: true,
|
||||
windowsVerbatimArguments: params.windowsVerbatimArguments,
|
||||
};
|
||||
@@ -59,12 +65,14 @@ export async function createChildAdapter(params: {
|
||||
const spawned = await spawnWithFallback({
|
||||
argv: resolvedArgv,
|
||||
options,
|
||||
fallbacks: [
|
||||
{
|
||||
label: "no-detach",
|
||||
options: { detached: false },
|
||||
},
|
||||
],
|
||||
fallbacks: useDetached
|
||||
? [
|
||||
{
|
||||
label: "no-detach",
|
||||
options: { detached: false },
|
||||
},
|
||||
]
|
||||
: [],
|
||||
});
|
||||
|
||||
const child = spawned.child as ChildProcessWithoutNullStreams;
|
||||
|
||||
Reference in New Issue
Block a user