fix(runtime): hide cli child windows by default
This commit is contained in:
parent
d5f87a286a
commit
5610e13b98
2 changed files with 39 additions and 6 deletions
|
|
@ -242,12 +242,16 @@ export function killTrackedCliProcesses(signal: NodeJS.Signals = 'SIGKILL'): voi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Merge CLI_ENV_DEFAULTS into spawn/exec options.env (or process.env if absent). */
|
/** Apply shared CLI process defaults without overriding explicit caller choices. */
|
||||||
function withCliEnv<T extends { env?: NodeJS.ProcessEnv | Record<string, string | undefined> }>(
|
function withCliProcessDefaults<
|
||||||
options: T
|
T extends {
|
||||||
): T {
|
env?: NodeJS.ProcessEnv | Record<string, string | undefined>;
|
||||||
|
windowsHide?: boolean;
|
||||||
|
},
|
||||||
|
>(options: T): T & { windowsHide: boolean } {
|
||||||
return {
|
return {
|
||||||
...options,
|
...options,
|
||||||
|
windowsHide: options.windowsHide ?? true,
|
||||||
env: { ...(options.env ?? process.env), ...CLI_ENV_DEFAULTS },
|
env: { ...(options.env ?? process.env), ...CLI_ENV_DEFAULTS },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -270,7 +274,7 @@ export async function execCli(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const target = binaryPath;
|
const target = binaryPath;
|
||||||
const opts = withCliEnv(options);
|
const opts = withCliProcessDefaults(options);
|
||||||
const directLauncher = resolveDirectWindowsLauncher(target);
|
const directLauncher = resolveDirectWindowsLauncher(target);
|
||||||
if (directLauncher) {
|
if (directLauncher) {
|
||||||
const result = await execFileAsync(
|
const result = await execFileAsync(
|
||||||
|
|
@ -316,7 +320,7 @@ export function spawnCli(
|
||||||
args: string[],
|
args: string[],
|
||||||
options: SpawnOptions = {}
|
options: SpawnOptions = {}
|
||||||
): ReturnType<typeof spawn> {
|
): ReturnType<typeof spawn> {
|
||||||
const opts = withCliEnv(options);
|
const opts = withCliProcessDefaults(options);
|
||||||
const directLauncher = resolveDirectWindowsLauncher(binaryPath);
|
const directLauncher = resolveDirectWindowsLauncher(binaryPath);
|
||||||
if (directLauncher) {
|
if (directLauncher) {
|
||||||
const directOpts = { ...opts };
|
const directOpts = { ...opts };
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,18 @@ describe('cli child process helpers', () => {
|
||||||
expect(result).toEqual({} as any);
|
expect(result).toEqual({} as any);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('hides spawned CLI windows by default but preserves explicit opt-out', () => {
|
||||||
|
setPlatform('win32');
|
||||||
|
const spawnMock = child.spawn as unknown as Mock;
|
||||||
|
spawnMock.mockReturnValue({} as any);
|
||||||
|
|
||||||
|
spawnCli('C:\\bin\\claude.exe', ['--version']);
|
||||||
|
expect(spawnMock.mock.calls[0][2]).toMatchObject({ windowsHide: true });
|
||||||
|
|
||||||
|
spawnCli('C:\\bin\\claude.exe', ['--version'], { windowsHide: false });
|
||||||
|
expect(spawnMock.mock.calls[1][2]).toMatchObject({ windowsHide: false });
|
||||||
|
});
|
||||||
|
|
||||||
it('falls back to shell when spawn throws EINVAL', () => {
|
it('falls back to shell when spawn throws EINVAL', () => {
|
||||||
setPlatform('win32');
|
setPlatform('win32');
|
||||||
const error: any = new Error('spawn EINVAL');
|
const error: any = new Error('spawn EINVAL');
|
||||||
|
|
@ -296,6 +308,23 @@ describe('cli child process helpers', () => {
|
||||||
expect(result.stdout).toBe('ok');
|
expect(result.stdout).toBe('ok');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('hides exec CLI windows by default but preserves explicit opt-out', async () => {
|
||||||
|
setPlatform('win32');
|
||||||
|
const execFileMock = child.execFile as unknown as Mock;
|
||||||
|
execFileMock.mockImplementation(
|
||||||
|
(_cmd: string, _args: string[], _opts: unknown, cb: ExecCallback) => {
|
||||||
|
cb(null, 'ok', '');
|
||||||
|
return {} as any;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
await execCli('C:\\bin\\claude.exe', ['--version']);
|
||||||
|
expect(execFileMock.mock.calls[0][2]).toMatchObject({ windowsHide: true });
|
||||||
|
|
||||||
|
await execCli('C:\\bin\\claude.exe', ['--version'], { windowsHide: false });
|
||||||
|
expect(execFileMock.mock.calls[1][2]).toMatchObject({ windowsHide: false });
|
||||||
|
});
|
||||||
|
|
||||||
it('skips straight to shell for Windows cmd launchers', async () => {
|
it('skips straight to shell for Windows cmd launchers', async () => {
|
||||||
setPlatform('win32');
|
setPlatform('win32');
|
||||||
const execFileMock = child.execFile as unknown as Mock;
|
const execFileMock = child.execFile as unknown as Mock;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue