|
|
@@ -7,7 +7,7 @@
|
|
|
* @module dsh-subprocess-local/spawn
|
|
|
*/
|
|
|
|
|
|
-import { type ChildProcess, spawn, spawnSync } from 'node:child_process'
|
|
|
+import { type ChildProcess, type SpawnOptions, spawn, spawnSync } from 'node:child_process'
|
|
|
import type { Readable } from 'node:stream'
|
|
|
import { randomBytes } from 'node:crypto'
|
|
|
import { closeSync, mkdtempSync, openSync, unlinkSync, writeSync } from 'node:fs'
|
|
|
@@ -26,6 +26,12 @@ import type {
|
|
|
} from '@deepseek-ai/dsh-subprocess'
|
|
|
import { linuxProcessGroupHasLiveMembers } from './process-inspector.ts'
|
|
|
|
|
|
+type SpawnProcess = (
|
|
|
+ program: string,
|
|
|
+ args: readonly string[],
|
|
|
+ options: SpawnOptions,
|
|
|
+) => ChildProcess
|
|
|
+
|
|
|
/**
|
|
|
* Build a child environment: explicit caller entries override the scrubbed
|
|
|
* parent base using the target platform's environment-key semantics. A string
|
|
|
@@ -48,6 +54,8 @@ export function childEnv(extra?: Readonly<NodeJS.ProcessEnv>): NodeJS.ProcessEnv
|
|
|
|
|
|
/** Injectable knobs so tests can exercise spill and platform behavior deterministically. */
|
|
|
export interface SpawnInternals {
|
|
|
+ /** Node process spawner used by focused option tests. */
|
|
|
+ spawn?: SpawnProcess
|
|
|
/** Directory for spill files (defaults to the OS temp dir). */
|
|
|
spillDir?: string
|
|
|
/** Windows tree-termination runner (defaults to `taskkill /PID <pid> /T /F`). */
|
|
|
@@ -329,6 +337,7 @@ export function spawnSubprocess(spec: SubprocessSpawnSpec, internals: SpawnInter
|
|
|
}
|
|
|
const spillDir = internals.spillDir ?? privateSpillDir()
|
|
|
const platform = internals.platform ?? process.platform
|
|
|
+ const spawnProcess = internals.spawn ?? spawn
|
|
|
const taskkill = internals.taskkill ?? taskkillProcessTree
|
|
|
const linuxGroupHasLiveMembers = internals.linuxProcessGroupHasLiveMembers ?? linuxProcessGroupHasLiveMembers
|
|
|
|
|
|
@@ -347,7 +356,7 @@ export function spawnSubprocess(spec: SubprocessSpawnSpec, internals: SpawnInter
|
|
|
const stdinMode = spec.stdio.stdin
|
|
|
|
|
|
const env = childEnv(spec.env)
|
|
|
- const child = spawn(program, args, {
|
|
|
+ const child = spawnProcess(program, args, {
|
|
|
cwd: spec.cwd,
|
|
|
env,
|
|
|
stdio: [
|
|
|
@@ -358,6 +367,7 @@ export function spawnSubprocess(spec: SubprocessSpawnSpec, internals: SpawnInter
|
|
|
// `detached` gives teardown a tree root on POSIX (its own process group);
|
|
|
// Windows terminates by root pid through taskkill /T instead.
|
|
|
detached: platform !== 'win32',
|
|
|
+ windowsHide: platform === 'win32',
|
|
|
})
|
|
|
|
|
|
const collectStream = (mode: SubprocessOutputMode, stream: Readable | null, label: string): OutputCollector | undefined => {
|