/** * Vocabulary for the subprocess Service Definition: fully-specified spawn requests with * Node-shaped per-stream stdio modes, bounded collected output with spill * recovery, raw piped streams, and tree-scoped termination. Command * defaulting, shell semantics, protocol framing, and presentation belong to * consumers such as the bash executor seam. * @module dsh-subprocess/types */ import type { Readable, Writable } from 'node:stream'; /** Namespace prefix reserved for DeepSeek Harness-managed child environment facts. */ export declare const DSH_ENV_PREFIX: "DSH_"; /** One environment key inside the managed {@link DSH_ENV_PREFIX} namespace. */ export type DshEnvironmentKey = `${typeof DSH_ENV_PREFIX}${string}`; /** Trusted DeepSeek Harness variables for one child-process execution. */ export type DshEnvironment = Readonly>; /** One captured stream: the (possibly truncated) text plus recovery info. */ export interface CollectedOutput { /** Collected text — the TAIL of the stream when truncated. */ text: string; /** True when bytes were dropped from `text`. */ truncated: boolean; /** Path to a file holding the COMPLETE stream, when truncated and available. */ spillPath?: string; } /** * stdin disposition. `'ignore'` leaves fd 0 on `/dev/null`; `'pipe'` exposes * {@link SubprocessHandle.stdin} for the caller's ongoing protocol writes; * `{ data }` writes the bytes and closes (the batch shape). */ export type SubprocessStdinMode = 'ignore' | 'pipe' | { readonly data: string; }; /** * Bounded in-memory collection for one output stream, with an optional * full-stream spill file. Omitting `spill` keeps only the in-memory tail — * the diagnostic-tail shape (a language server's stderr); including it makes * the complete stream recoverable up to its cap (the bash tool shape). */ export interface SubprocessCollect { /** In-memory cap in bytes; overflow keeps the TAIL. */ maxBytes: number; /** Full-stream spill file; absent disables spilling entirely. */ spill?: { /** Whole-stream byte cap; a larger stream discards its now-incomplete spill. */ maxBytes: number; }; } /** * stdout/stderr disposition. `'pipe'` exposes the raw `Readable` for the * caller's protocol decoding; `'inherit'` passes the parent's descriptor * through (child diagnostics land on the harness's own stream); a * {@link SubprocessCollect} object buffers boundedly with offset-based reads. */ export type SubprocessOutputMode = 'pipe' | 'inherit' | SubprocessCollect; /** Per-stream stdio dispositions, all explicit — this seam applies no defaults. */ export interface SubprocessStdio { stdin: SubprocessStdinMode; stdout: SubprocessOutputMode; stderr: SubprocessOutputMode; } /** * A fully-specified spawn request. This seam applies no defaults: every * disposition, limit, and directory is explicit, so the caller's own config — * not a hidden subprocess-service default — decides them (the `dsh-bash` * request/spec split is the owning template). */ export interface SubprocessSpawnSpec { /** Executable and arguments; `argv[0]` is the program. Never shell-interpreted here. */ argv: readonly string[]; /** Working directory for the child. */ cwd: string; /** Per-stream stdio dispositions. */ stdio: SubprocessStdio; /** * Positive finite grace period in milliseconds, no greater than * `MAX_TIMER_DELAY_MS`, for the {@link SubprocessHandle.terminate} escalation * and for draining still-open collected pipes after the process exits (an * inherited descriptor held by a surviving descendant cannot hold the * outcome open indefinitely). */ graceMs: number; /** * Abort signal — starts the terminate escalation on the process tree when * it fires. The caller owns deadlines and cause classification; this seam * only reacts to the abort. */ signal?: AbortSignal | undefined; /** * Explicit environment entries merged onto the implementation's scrubbed * parent base (see `scrubbedParentEnv`), with no namespace validation. A * string is a deliberate caller opt-in, so a forwarded credential-shaped * entry or current `DSH_*` fact survives the scrub; `undefined` is a * tombstone that removes an ordinary ambient entry from the child. */ env?: NodeJS.ProcessEnv | undefined; } /** * Exit facts of one closed process — Node's `close`-event vocabulary. * Deliberately carries NO timeout or cancellation classification (the caller * reads the signal it owns to classify causes) and NO output: collected * streams stay readable through {@link SubprocessHandle.collected} after * settlement, so batch and streaming callers share one access path. */ export interface SubprocessOutcome { /** Exit code; null when the process died from a signal. */ exitCode: number | null; /** Terminating signal (e.g. 'SIGTERM'); null on normal exit. */ signal: NodeJS.Signals | null; } /** One incremental {@link SubprocessOutputReader.readFrom} read. */ export interface SubprocessOutputRead { /** Stream text from the requested offset (the whole retained tail when lossy). */ text: string; /** Whole-stream offset to resume from on the next read. */ nextOffset: number; /** True when the requested offset slid out of the in-memory tail window. */ lossy: boolean; /** Path to the full-stream spill file, when one was created and remains intact. */ spillPath?: string; } /** * Cursor-free incremental access to one collected output stream. Offsets are * whole-stream byte coordinates owned by the caller, so independent readers * cannot consume one another's output; `readFrom(0)` after settlement is the * batch result (`lossy` then means the in-memory tail lost its head — the * {@link CollectedOutput.truncated} fact). */ export interface SubprocessOutputReader { /** * Read everything captured since `fromByte`. When that offset has slid out * of the in-memory tail window the read is `lossy` — it returns the whole * retained tail and the gap is only recoverable from the spill file. * @param fromByte - whole-stream offset to resume from (a prior read's `nextOffset`; 0 for the first read). * @returns the delta text, the next offset, the `lossy` flag, and the spill path when one exists. */ readFrom(fromByte: number): SubprocessOutputRead; } /** Offset-based readers for the streams spawned in collect mode. */ export interface SubprocessCollectedOutputs { /** Present iff stdout is a {@link SubprocessCollect}. */ readonly stdout?: SubprocessOutputReader; /** Present iff stderr is a {@link SubprocessCollect}. */ readonly stderr?: SubprocessOutputReader; } /** * A live child process rooted in its own process tree. Collected output * remains readable after exit; piped streams belong to the caller. * * Termination is tree-scoped everywhere: POSIX signals the detached process * group (falling back to the direct child when the group is gone), Windows * terminates the tree via `taskkill /T`, so helper processes cannot outlive * the handle unnoticed. */ export interface SubprocessHandle { /** Process id (tree root); -1 when the spawn itself failed. */ readonly pid: number; /** The child's stdin, present iff spawned with `stdin: 'pipe'`. */ readonly stdin: Writable | undefined; /** The child's raw stdout, present iff spawned with `stdout: 'pipe'`. */ readonly stdout: Readable | undefined; /** The child's raw stderr, present iff spawned with `stderr: 'pipe'`. */ readonly stderr: Readable | undefined; /** Offset-based readers for collect-mode streams (also readable after exit). */ readonly collected: SubprocessCollectedOutputs; /** Resolves at process close with exit facts; rejects only for spawn-level failures. */ readonly done: Promise; /** * Begin the SIGTERM → `graceMs` → SIGKILL escalation on the process tree * (Windows force-terminates immediately) — the seam's only termination * verb. Idempotent, a no-op once the tree is gone (the pid may be reused), * and also triggered by the spec's abort signal. */ terminate(): void; /** * Wait until the process tree has exited — the tree, not just the direct * child, so a still-running helper is observable before teardown returns. * @param signal - optional bound for the wait. * @returns `true` when the tree exited, `false` when the signal aborted first. */ waitForExit(signal?: AbortSignal): Promise; } /** * Signals supported by the terminal-process primitive. Kept member-identical * to `PtySignal` in `@deepseek-ai/dsh-pty` without a cross-seam dependency; * change both together. */ export type SubprocessTerminalSignal = 'SIGINT' | 'SIGTERM' | 'SIGKILL' | 'SIGTSTP' | 'SIGHUP'; /** A fully specified terminal-process spawn. */ export interface SubprocessTerminalSpawnSpec { /** Executable and arguments; `argv[0]` is the program. */ argv: readonly string[]; /** Working directory in this subprocess provider's execution world. */ cwd: string; /** Explicit environment layered after the provider's ambient scrub. */ env?: Record | undefined; /** Initial terminal row count. */ rows: number; /** Initial terminal column count. */ cols: number; /** TERM-to-KILL cleanup grace for the complete terminal session. */ graceMs: number; /** Cancellation of terminal allocation; a published handle owns its later lifetime. */ signal?: AbortSignal | undefined; } /** Current foreground process-group facts for one terminal. */ export interface SubprocessTerminalForeground { /** Foreground process-group id published by the terminal driver. */ processGroupId: number; /** Whether the provider can currently prove that group is waiting on terminal input. */ inputWaiting: boolean; } /** * One live terminal process and its owned OS session. Terminal allocation, * foreground-group inspection/signalling, and session-tree cleanup are one * deep subprocess primitive because none can be reconstructed from ordinary * piped stdio without substrate-specific process control. */ export interface SubprocessTerminalHandle { /** Top-level terminal process id. */ readonly pid: number; /** UTF-8 terminal output bytes in delivery order; ends after queued output when the terminal exits. */ readonly output: Readable; /** Resolves when the top-level process exits; rejects only for a live transport failure. */ readonly done: Promise; /** * Write text to the terminal input. * @param data - text to deliver without implicit newline conversion. */ write(data: string): Promise; /** * Inspect the current foreground process group. * @returns its id and input-wait fact, or undefined when no foreground group can be resolved. */ inspectForeground(): Promise; /** * Deliver a signal to the current foreground process group. * @param signal - permitted terminal signal. * @returns the exact group id that received it. */ signalForeground(signal: SubprocessTerminalSignal): Promise; /** * Idempotently terminate every terminal-session member the provider can still observe and await quiescence. * After settlement, no write, inspection, or signal call remains in flight. * Providers document substrate-specific observability limits. */ terminate(): Promise; } //# sourceMappingURL=types.d.ts.map