import type { Readable, Writable } from "node:stream"; import type { AgentTurn } from "../engine/types.ts"; /** * The part of a `child_process.ChildProcess` a background subagent needs: a pipe to write its prompt to, * two pipes to drain, an exit to await, and a way to kill it. Structural on purpose — a real * `ChildProcess` satisfies it, and so does a test fake built from streams, with no cast and no real * binary. */ export interface SubagentProcess { readonly stdin: Writable | null; readonly stdout: Readable | null; readonly stderr: Readable | null; on(event: "exit" | "close", listener: (code: number | null) => void): unknown; on(event: "error", listener: (error: Error) => void): unknown; kill(signal?: NodeJS.Signals): boolean; } /** How a background subagent's process is started; injectable so the streaming/abort wiring is testable offline. */ export type SubagentSpawner = (command: string, args: readonly string[], env?: NodeJS.ProcessEnv) => SubagentProcess; /** * The default spawner: a real child process with a writable stdin — the prompt goes there, never in * `args` (see `writePrompt` below for why) — and both output pipes ours to drain. * * `env` ADDS to the parent's environment rather than replacing it: a step child must keep the * provider config, auth and agent-dir it inherits, and only gains the step-specific handoff on top. */ export declare const subagentSpawner: SubagentSpawner; /** Everything a finished subagent process leaves behind — all of it bounded, none of it its stdout. */ export interface SubagentResult { readonly code: number; readonly turn: AgentTurn; /** The last {@link STDERR_TAIL_CHARS} of stderr — enough to name a failure, capped so it cannot be one. */ readonly stderrTail: string; } /** * Run one subagent process to completion, reducing its output AS IT ARRIVES rather than collecting it. * * Both pipes are drained the moment they produce anything — stdout into the incremental reader, stderr * into a fixed-size tail — so nothing this function holds grows with how much the child says. `prompt` is * delivered over stdin (see {@link writePrompt}), never in `args`: with a piped (non-TTY) stdin the * harness silently ignores a positional argument (verified against a real `pi` binary). * * A child ended by a SIGNAL has no exit code; it is reported as 0, which is what `pi.exec` did (`code ?? * 0`) and so keeps a cancel reading as a cancel rather than as a mystery exit. The one signal we send * ourselves is on abort, and pi-agent.ts's `backgroundSession` checks `signal.aborted` before it looks * at the code at all. */ export declare function runSubagent(spawnSubagent: SubagentSpawner, command: string, args: readonly string[], prompt: string, signal: AbortSignal | undefined, env?: NodeJS.ProcessEnv): Promise; //# sourceMappingURL=subagent-process.d.ts.map