Skip to content

Commit 9bce96c

Browse files
committed
🤖 fix: keep runtime exec helpers resilient to spawn errors
1 parent 2cb481b commit 9bce96c

File tree

2 files changed

+30
-8
lines changed

2 files changed

+30
-8
lines changed

src/node/runtime/LocalBaseRuntime.ts

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,25 @@ export abstract class LocalBaseRuntime implements Runtime {
6363
);
6464
}
6565

66-
// If niceness is specified on Unix/Linux, spawn nice directly to avoid escaping issues
67-
// Windows doesn't have nice command, so just spawn bash directly
66+
// If niceness is specified on Unix/Linux, try to spawn `nice` directly to avoid
67+
// escaping issues. Some minimal environments may not have `nice` on PATH, so
68+
// fall back to running bash directly.
6869
const isWindows = process.platform === "win32";
6970
const bashPath = getBashPath();
70-
const spawnCommand = options.niceness !== undefined && !isWindows ? "nice" : bashPath;
71+
72+
const shouldNice = options.niceness !== undefined && !isWindows;
73+
const nicePath = shouldNice
74+
? fs.existsSync("/usr/bin/nice")
75+
? "/usr/bin/nice"
76+
: fs.existsSync("/bin/nice")
77+
? "/bin/nice"
78+
: null
79+
: null;
80+
81+
const spawnCommand = nicePath ?? bashPath;
7182
const spawnArgs =
72-
options.niceness !== undefined && !isWindows
73-
? ["-n", options.niceness.toString(), bashPath, "-c", command]
83+
nicePath !== null
84+
? ["-n", options.niceness!.toString(), bashPath, "-c", command]
7485
: ["-c", command];
7586

7687
const childProcess = spawn(spawnCommand, spawnArgs, {
@@ -145,7 +156,12 @@ export abstract class LocalBaseRuntime implements Runtime {
145156
});
146157
});
147158

148-
const duration = exitCode.then(() => performance.now() - startTime);
159+
// Always resolve duration even if exitCode rejects (e.g. spawn errors).
160+
// Consumers frequently ignore duration; rejecting would surface as an unhandled rejection.
161+
const duration = exitCode.then(
162+
() => performance.now() - startTime,
163+
() => performance.now() - startTime
164+
);
149165

150166
// Register process group cleanup with DisposableProcess
151167
// This ensures ALL background children are killed when process exits
@@ -175,8 +191,13 @@ export abstract class LocalBaseRuntime implements Runtime {
175191
disposable[Symbol.dispose](); // Kill process and run cleanup
176192
}, options.timeout * 1000);
177193

178-
// Clear timeout if process exits naturally
179-
void exitCode.finally(() => clearTimeout(timeoutHandle));
194+
// Clear timeout if process exits naturally.
195+
// Swallow rejections to avoid unhandled promise noise on spawn errors.
196+
exitCode
197+
.finally(() => clearTimeout(timeoutHandle))
198+
.catch(() => {
199+
/* ignore */
200+
});
180201
}
181202

182203
return { stdout, stderr, stdin, exitCode, duration };

tests/browser/harness/env.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ export async function createBrowserTestEnv(): Promise<BrowserTestEnv> {
8989
menuEventService: services.menuEventService,
9090
voiceService: services.voiceService,
9191
telemetryService: services.telemetryService,
92+
sessionUsageService: services.sessionUsageService,
9293
};
9394

9495
const orpc = createOrpcTestClient(orpcContext);

0 commit comments

Comments
 (0)