/**
 * Pipe-error resilience for stdout/stderr writes.
 *
 * Why this exists:
 *
 *   The wizard writes structured NDJSON to stdout in agent mode and
 *   human-readable status lines elsewhere. When the receiving end of
 *   stdout/stderr closes mid-run (the parent process dies, the user
 *   pipes through `head`, an outer agent crashes, etc.), Node emits an
 *   `EPIPE` on the next write. If nothing handles the resulting `error`
 *   event, Node throws it as an uncaught exception and the wizard
 *   crashes — visible in production Sentry as WIZARD-CLI-8 (`emit` at
 *   `agent-ui.ts`) and WIZARD-CLI-5 (`afterWriteDispatched` in
 *   `stream_base_commons`). Fatal-level events from real users.
 *
 * Two layers cover both the sync and async failure modes:
 *
 *   1. `installPipeErrorHandlers()` attaches process-level `error`
 *      listeners on `process.stdout` and `process.stderr` that swallow
 *      EPIPE (and the related EIO / ECONNRESET pipe-reset codes).
 *      Catches the async `afterWriteDispatched` path where the error
 *      surfaces a tick after the synchronous write call returned.
 *
 *   2. `safePipeWrite(stream, data)` wraps a synchronous write call so
 *      a thrown EPIPE during the write itself doesn't bubble up. Use
 *      from any code path that writes user output and shouldn't crash
 *      the run on a broken pipe.
 *
 * On first pipe break, both layers register a one-shot trigger that
 * schedules `abortWizard()` (in agent / non-TUI contexts) so the
 * wizard exits cleanly rather than continuing to produce output that
 * silently disappears. Without this, an orchestrator that drops its
 * read end mid-stream would still be billed for a long-running agent
 * run that has no audience.
 *
 * Subsequent writes after the pipe break are still no-ops — the data
 * is silently dropped because there's nothing on the other end to
 * receive it. The single-shot abort guarantees we don't burn cycles
 * on a doomed run.
 *
 * Idempotent. `installPipeErrorHandlers()` may be called multiple times
 * (e.g. once from `bin.ts`, once from `agent-ui.ts` module init) without
 * stacking listeners.
 */
/**
 * Type guard for Node ErrnoException-shaped errors. Avoids a bare
 * `(err as NodeJS.ErrnoException).code` cast and keeps the runtime
 * check honest about the property's presence.
 */
declare function isPipeError(err: unknown): boolean;
/**
 * Pluggable abort dispatcher. Defaults to dynamically importing
 * `./wizard-abort` (avoids the circular load — `wizard-abort.ts`
 * imports `./ui` which imports `./agent-ui` which imports this
 * file). Tests inject a synchronous mock via
 * `__setPipeAbortDispatcherForTests` so they don't have to wrestle
 * with vi.mock and dynamic-import resolution timing.
 */
type AbortDispatcher = () => void | Promise<void>;
/** Test-only reset for `_pipeAbortTriggered`. */
export declare const __resetPipeAbortTriggeredForTests: () => void;
/**
 * Mark the wizard as "already exiting" so any future EPIPE detected
 * by `safePipeWrite` / the stream error listener short-circuits
 * instead of scheduling a deferred `wizardAbort`.
 *
 * Why this exists: `wizardSuccessExit` and `wizardAbort` write to
 * stdout (e.g. the `run_completed` NDJSON event) AFTER the consumer
 * may have closed the pipe. Without this flag, that write hits EPIPE,
 * `triggerPipeAbort` schedules `setImmediate(() => wizardAbort())`,
 * and the deferred abort fires during the success path's own
 * analytics-shutdown await — calling `process.exit(130)` before the
 * success path reaches `process.exit(0)`. CI watchers see code 130
 * (USER_CANCELLED) on a fully successful run.
 *
 * Calling this idempotent setter at the START of every exit funnel
 * suppresses the race: we're already on the way out, the deferred
 * abort would just stomp our exit code. Bugbot finding (Medium).
 */
export declare const suppressPipeAbort: () => void;
/** Test-only dispatcher injection. Pass `null` to restore the default. */
export declare const __setPipeAbortDispatcherForTests: (dispatcher: AbortDispatcher | null) => void;
export declare function installPipeErrorHandlers(): void;
/**
 * Synchronously write `data` to `stream`, swallowing EPIPE-class
 * errors. Returns true if the write was queued, false if the pipe is
 * already broken (data dropped).
 *
 * The async `error` listener installed by `installPipeErrorHandlers`
 * still fires on the same write if the failure is delayed past the
 * synchronous return — both layers are needed because Node can route
 * the error either way depending on the stream's internal state.
 */
export declare function safePipeWrite(stream: NodeJS.WritableStream, data: string): boolean;
export declare const __test: {
    isPipeError: typeof isPipeError;
    PIPE_ERROR_CODES: Set<string>;
};
export {};
