/**
 * Tracked subprocess spawn with process-tree kill.
 *
 * Problem this solves:
 *   Node's `child_process.spawn(..., { timeout })` only sends SIGTERM to the
 *   immediate child. When the child is `bash -c "<cmd>"`, descendants (npm,
 *   playwright, chromium, …) keep running. Same story for any manual
 *   `process.kill(child.pid, sig)` — the call only targets the immediate
 *   child, never its descendants.
 *
 * Approach:
 *   POSIX — spawn with `detached: true` so the child becomes its own process
 *           group leader (pgid === child.pid). Kill the whole tree via
 *           `process.kill(-pgid, sig)`. SIGTERM → SIGKILL escalation after a
 *           grace period (default 5s, 1s when called from cancellation).
 *   Windows — `taskkill /T /F /PID <pid>` (the `/T` flag walks the tree).
 *
 * The helper owns the timeout timer (`setTimeout`, `.unref()`'d) so a
 * long-running tracked child never holds the event loop open against a
 * graceful gateway exit. `killAllTracked` provides explicit cleanup on
 * harness shutdown for any children still in flight.
 *
 * Reusable primitive: any caller that spawns a shell which may itself
 * spawn descendants (test runners, browser drivers, package managers)
 * should prefer this helper over raw `spawn` to avoid orphan trees.
 */
import { type ChildProcess, type StdioOptions } from "node:child_process";
export interface SpawnTrackedOptions {
    cwd?: string;
    env?: NodeJS.ProcessEnv;
    stdio?: StdioOptions;
    windowsHide?: boolean;
    /** Optional — helper owns the timer; cleared on close/exit. */
    timeoutMs?: number;
    /** SIGTERM → SIGKILL escalation delay (POSIX only). Default 5000ms. */
    killGraceMs?: number;
    /** Invoked once when the timer fires, before the tree kill. */
    onTimeout?: () => void;
}
export interface TrackedChild {
    readonly child: ChildProcess;
    /**
     * Kill the entire process tree. Idempotent.
     * On POSIX, SIGTERM is sent first; SIGKILL escalates after grace.
     * `graceMsOverride` shortens (or lengthens) the SIGKILL escalation
     * window for this kill specifically (e.g. cancellation uses 1000ms).
     */
    killTree(signal?: "SIGTERM" | "SIGKILL", graceMsOverride?: number): void;
    killed(): boolean;
    timedOut(): boolean;
    /**
     * Mark this tracked child as surviving gateway shutdown. When set,
     * `killAllTracked()` skips this entry so the child outlives the
     * gateway process — enabling Layer 1 restart-survival for detached
     * verification command steps (see `_resumeCommandStep`).
     */
    markSurvival(): void;
}
/** Spawn a process whose entire tree we can later kill. */
export declare function spawnTracked(cmd: string, args: readonly string[], opts?: SpawnTrackedOptions): TrackedChild;
/**
 * Kill every tracked child whose subprocess tree is still alive.
 * Called from harness shutdown to ensure no chromium / playwright
 * descendants leak across gateway restarts.
 */
export declare function killAllTracked(signal?: "SIGTERM" | "SIGKILL", includeSurvival?: boolean): void;
/**
 * Tree-kill a process by PID from outside the spawn site — used by the
 * recovery path (`_resumeCommandStep`) where the persisted pid is also
 * the pgid (because the original spawn used `detached: true`).
 *
 * On Windows, falls back to `taskkill /T /F /PID <pid>`.
 */
export declare function killTreeByPid(pid: number, signal?: NodeJS.Signals): void;
/** Test-only: number of tracked children currently registered. */
export declare function _trackedCount(): number;
//# sourceMappingURL=spawn-tree.d.ts.map