mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
fix(cli): hide windows console windows for runner/claude subprocesses (#242)
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
import { beforeAll, afterAll, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import type { SpawnOptions } from 'child_process';
|
||||
|
||||
const spawnMock = vi.fn((..._args: any[]) => ({ pid: 12345 } as any));
|
||||
|
||||
vi.mock('child_process', async () => {
|
||||
const actual = await vi.importActual<typeof import('child_process')>('child_process');
|
||||
return {
|
||||
...actual,
|
||||
spawn: spawnMock
|
||||
};
|
||||
});
|
||||
|
||||
const originalPlatformDescriptor = Object.getOwnPropertyDescriptor(process, 'platform');
|
||||
|
||||
function setPlatform(value: string) {
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value,
|
||||
configurable: true
|
||||
});
|
||||
}
|
||||
|
||||
function getSpawnOptionsOrThrow(): SpawnOptions {
|
||||
expect(spawnMock).toHaveBeenCalledTimes(1);
|
||||
const firstCall = spawnMock.mock.calls[0] as unknown[] | undefined;
|
||||
const options = firstCall?.[2] as SpawnOptions | undefined;
|
||||
if (!options) {
|
||||
throw new Error('Expected spawn options to be passed as third argument');
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
describe('spawnHappyCLI windowsHide behavior', () => {
|
||||
beforeAll(() => {
|
||||
if (!originalPlatformDescriptor?.configurable) {
|
||||
throw new Error('process.platform is not configurable in this runtime');
|
||||
}
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
if (originalPlatformDescriptor) {
|
||||
Object.defineProperty(process, 'platform', originalPlatformDescriptor);
|
||||
}
|
||||
});
|
||||
|
||||
it('sets windowsHide=true when platform is win32 and detached=true', async () => {
|
||||
setPlatform('win32');
|
||||
const { spawnHappyCLI } = await import('./spawnHappyCLI');
|
||||
|
||||
spawnHappyCLI(['runner', 'start-sync'], {
|
||||
detached: true,
|
||||
stdio: 'ignore'
|
||||
});
|
||||
|
||||
const options = getSpawnOptionsOrThrow();
|
||||
expect(options.detached).toBe(true);
|
||||
expect(options.windowsHide).toBe(true);
|
||||
});
|
||||
|
||||
it('does not set windowsHide when platform is win32 but detached is false', async () => {
|
||||
setPlatform('win32');
|
||||
const { spawnHappyCLI } = await import('./spawnHappyCLI');
|
||||
|
||||
spawnHappyCLI(['runner', 'start-sync'], {
|
||||
detached: false,
|
||||
stdio: 'ignore'
|
||||
});
|
||||
|
||||
const options = getSpawnOptionsOrThrow();
|
||||
expect(options.detached).toBe(false);
|
||||
expect('windowsHide' in options).toBe(false);
|
||||
});
|
||||
|
||||
it('does not set windowsHide on non-win32 even when detached=true', async () => {
|
||||
setPlatform('linux');
|
||||
const { spawnHappyCLI } = await import('./spawnHappyCLI');
|
||||
|
||||
spawnHappyCLI(['runner', 'start-sync'], {
|
||||
detached: true,
|
||||
stdio: 'ignore'
|
||||
});
|
||||
|
||||
const options = getSpawnOptionsOrThrow();
|
||||
expect(options.detached).toBe(true);
|
||||
expect('windowsHide' in options).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -105,5 +105,11 @@ export function spawnHappyCLI(args: string[], options: SpawnOptions = {}): Child
|
||||
}
|
||||
}
|
||||
|
||||
return spawn(spawnCommand, spawnArgs, options);
|
||||
// On Windows, detached processes allocate a new console window by default.
|
||||
// windowsHide: true suppresses this to prevent cmd windows from accumulating.
|
||||
const finalOptions: SpawnOptions = { ...options };
|
||||
if (process.platform === 'win32' && options.detached) {
|
||||
finalOptions.windowsHide = true;
|
||||
}
|
||||
return spawn(spawnCommand, spawnArgs, finalOptions);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user