/** * Shared child-process runner for lifecycle actions and plugin hooks. * * Both callers hand the event payload to the child on stdin. `spawnSync` forks * first and writes that payload afterwards, so a command that never reads stdin * can exit before the write lands — the write then hits a closed pipe and * `spawnSync` reports `EPIPE` for a command that ran and exited 0. The race is * deterministic above the 64 KiB pipe buffer and load-dependent below it, which * is how it reached CI as a release-blocking flake that survived three retries * (see .aidlc/state/subprocess-test-flake/reproduction.md). * * So the child's exit status — not the parent's stdin write — is the verdict on * whether a hook succeeded, and a failure has to carry enough detail to be * diagnosed from a CI log alone. * * Requirements: subprocess-test-flake/AC-1 .. AC-8 */ import type { SpawnSyncReturns } from 'node:child_process'; /** Wall-clock budget for a single hook or action command. */ export declare const COMMAND_TIMEOUT_MS = 30000; export interface RunCommandOptions { /** Environment for the child (callers pass process.env plus AIDLC_* vars). */ env: NodeJS.ProcessEnv; /** Payload written to the child's stdin. */ input: string; /** Working directory; undefined inherits the parent's. */ cwd?: string; /** Overrides COMMAND_TIMEOUT_MS (tests use a short budget). */ timeoutMs?: number; } export interface RunCommandResult { success: boolean; /** Present only on failure: exit status, signal, errno, and child stderr. */ error?: string; } /** * How a command is actually spawned. Only tests pass anything but the default: * a transient spawn errno (EAGAIN and friends) cannot be provoked on demand * from inside a process, and the retry it triggers is the one behaviour here * that no real command can exercise. */ export type SpawnFn = (command: string, options: { shell: true; env: NodeJS.ProcessEnv; input: string; stdio: ['pipe', 'pipe', 'pipe']; timeout: number; cwd?: string; encoding: 'utf8'; }) => SpawnSyncReturns; /** * Run a hook or action command synchronously and classify the outcome. * * The success path spawns exactly once and never sleeps; only a transient spawn * errno costs a second attempt (AC-4). */ export declare function runCommand(command: string, opts: RunCommandOptions, spawn?: SpawnFn): RunCommandResult; //# sourceMappingURL=run-command.d.ts.map