import { type KeyEvent as TuiKeyEvent, type InputSource, type OutputTarget } from "../tui/index.js";
import type { Frame } from "../tui/frame.js";
type ChoiceItem = {
    key: string;
    label: string;
};
type ChoiceRequest = {
    title: string;
    body: string;
    items: ChoiceItem[];
    allowFreeText?: boolean;
};
/** TEST ONLY — inject an `InputSource` (e.g. `ScriptedInput`) for the
 *  declarative bridge. Pass `null` to clear between tests. */
export declare function _setInputSource(src: InputSource | null): void;
/** TEST ONLY — inject an `OutputTarget` (e.g. `FrameRecorder`) for the
 *  declarative bridge. Pass `null` to clear between tests. */
export declare function _setOutputTarget(out: OutputTarget | null): void;
/** TEST ONLY — extract the recorded frames from the injected
 *  `FrameRecorder` as plain-text per-frame strings. Returns `[]`
 *  when no recorder is installed (production path). */
export declare function _recordedFrameTexts(): string[];
/** TEST ONLY — set the viewport (width / height) the bridge passes
 *  to `Screen`. Production reads `process.stdout.columns` / `.rows`. */
export declare function _setSize(w: number, h: number): void;
/** Returns true while a `_runLoop` (or future `_runLoopHybrid`) call
 *  is in flight. Used by `std::policy.cliPolicyHandler` to probe
 *  whether a REPL owns the screen and route prompts accordingly. */
export declare function _hasActiveScreen(): boolean;
/**
 * Wake the active runLoop so it repaints immediately. Used by
 * `_beginSubmit` (the async-callback path) and by Agency-side
 * `pushMessage` so transcript updates show up without waiting for
 * the user to press another key. No-op when no input source supports
 * synthetic injection (we keep the check defensive since custom
 * `InputSource`s aren't required to implement `feedKey`).
 */
export declare function _triggerRender(): void;
/** Shape of the `state` arg `_beginSubmit` mutates while the async
 *  onSubmit settles. Defined locally because the Agency `ReplState`
 *  is record-typed and the bridge only cares about these two fields.
 *  The exit-on-`false`-return path uses the `_signalReplExit` bridge
 *  flag rather than mutating `state.done` here — see that function's
 *  comment for why. */
type SubmitTargetState = {
    submit?: {
        busy?: boolean;
        label?: string;
        startedAtMs?: number;
    };
    transcript: {
        messages: string[];
    };
};
export declare function truncateForTui(text: string): string;
export declare function _installConsoleCapture(messages: string[]): void;
export declare function _uninstallConsoleCapture(): void;
export declare function _nowMs(): number;
export declare function _elapsedSeconds(startedAtMs: number, nowMs?: number): number;
export declare function _spinnerFrame(startedAtMs: number, nowMs?: number): string;
/** Signal that the active `repl()` should exit on its next isDone
 *  check. Called from `_beginSubmit` when `onSubmit` returns `false`,
 *  and from any future "force exit" plumbing. Wakes the loop so
 *  `_replIsDone` runs immediately. */
export declare function _signalReplExit(): void;
/** Read the exit signal without clearing it. The Agency `_replIsDone`
 *  calls this on every tick; once true the loop terminates and the
 *  flag is reset by `_runReplLoop` in its finally block so the next
 *  REPL invocation starts fresh. */
export declare function _peekReplExitSignal(): boolean;
/** Reset the exit signal. Called by `_runReplLoop` before and after
 *  the loop runs, so a leftover signal from a prior REPL session
 *  doesn't cause the next one to exit on first frame. */
export declare function _resetReplExitSignal(): void;
export declare function _beginSubmit(state: SubmitTargetState, submitted: string, onSubmit: unknown): void;
export declare function _runLoop(initialState: any, renderFn: unknown, handleKeyFn: unknown, isDoneFn: unknown, tickMs?: number | null): Promise<any>;
/**
 * REPL-only wrapper around `_runLoop` that guarantees the
 * console-capture install is reversed even if the loop (or any
 * Agency callback it invokes) throws. Agency has no `finally`, so
 * the cleanup pair `_installConsoleCapture` / `_uninstallConsoleCapture`
 * has to live on the TS side of the bridge to keep stdout / console
 * from staying monkeypatched after a failed REPL.
 *
 * `transcriptMessages` is the same array `repl()` renders from; we
 * pass it through to `_installConsoleCapture` so console / print
 * output appends to the live transcript.
 */
export declare function _runReplLoop(initialState: any, renderFn: unknown, handleKeyFn: unknown, isDoneFn: unknown, tickMs: number | null | undefined, transcriptMessages: string[]): Promise<any>;
/** Single-shot render of an element tree. Useful for non-interactive
 *  output or for tests that want to inspect a rendered frame
 *  without entering a loop. */
export declare function _renderOnce(element: any): void;
/** Read one key from the active screen's input source if a loop is
 *  running, else construct a one-off screen for the read. Blocks
 *  until a key arrives. */
export declare function _readKey(): Promise<TuiKeyEvent>;
/**
 * `OutputTarget` for `repl()`'s hybrid rendering. Renders each frame
 * directly inside the terminal's reserved bottom region:
 * `withBottomCursor` saves the cursor, positions it at the start of
 * the bottom region, writes the frame ANSI (no `CURSOR_HOME` prefix,
 * no alt-screen entry — both would defeat the hybrid scrollback
 * goal), and restores the cursor so subsequent plain stdout writes
 * still scroll inside the top region.
 *
 * Does NOT wrap an inner OutputTarget. The bridge's default
 * `TerminalOutput` enters the alt-screen and prepends `CURSOR_HOME`
 * to every write, which is exactly what hybrid mode must avoid; this
 * target sidesteps both by talking to `process.stdout` itself via
 * `toANSI`. `destroy()` is a no-op: this target owns no resources
 * (the scroll region itself is torn down by `_resetScrollRegion`).
 */
export declare class BottomRegionOutputTarget implements OutputTarget {
    write(frame: Frame, _label?: string): void;
    destroy(): void;
}
/**
 * Append a raw text line to the scroll region. Plain
 * `process.stdout.write` — no ANSI; the scroll region installed by
 * `installRegion` in `./ui-region.ts` does the scrolling. Used by
 * `repl()` to stream `output()` lines into the terminal's native
 * scrollback as new tail elements appear.
 */
export declare function _writeScrollLine(text: string): void;
/**
 * Render an interrupt-style choice prompt to stdout: blank line,
 * dim-gray background block with bold yellow `⚠ Title`, body lines,
 * and aligned `key  label` rows; blank line trailing. The `input("> ")`
 * loop that captures the answer stays on the Agency side.
 *
 * On a non-TTY stdout, falls through to plain `console.log` lines
 * matching the pre-styling output so piped logs stay clean.
 */
export declare function _printChoicePromptFallback(title: string, body: string, items: ChoiceItem[]): void;
/**
 * Open a modal choice prompt over the currently-running REPL. Stores
 * the request in the active context's UI-state slot that the Agency
 * reducer reads via `_peekPendingChoiceRequest()` on every tick (so a
 * fresh frame sees the modal even though reducers return new state
 * records), then returns a Promise that the Agency reducer resolves
 * via `_resolveChoice(answer)` (Enter) or rejects via `_cancelChoice`
 * (Escape, or REPL torn down).
 *
 * Rejects if another prompt is already open in this context — the
 * caller should serialize.
 */
export declare function _openChoicePrompt(request: ChoiceRequest): Promise<string>;
/**
 * Read the pending choice request without consuming it. Returns
 * `null` when no prompt is open. The Agency reducer calls this on
 * every keystroke to sync `state.choice` with the TS-side request:
 * if TS has a request but state.choice is null, the reducer
 * initializes it; if TS has no request but state.choice is set,
 * the reducer clears it.
 */
export declare function _peekPendingChoiceRequest(): ChoiceRequest | null;
/** Resolve the pending choice promise with `answer` and clear both
 *  the promise slot and the request slot. Called by the Agency
 *  reducer when Enter is pressed on a filtered, non-empty list.
 *  No-op when no prompt is open. */
export declare function _resolveChoice(answer: string): void;
/** Reject the pending choice promise with `reason` and clear both
 *  the promise slot and the request slot. Called by the Agency
 *  reducer on Escape, or by `_runReplLoop` in its finally block to
 *  break out of any prompt left hanging by an exception. No-op when
 *  no prompt is open. */
export declare function _cancelChoice(reason: string): void;
/** Test/debug hook. Returns true while a choice prompt is awaiting a
 *  reducer callback. */
export declare function _hasPendingChoice(): boolean;
/** Install a `bottomRows`-row reserved region at the bottom of the
 *  terminal. The top `H - bottomRows` rows scroll natively. No-op on
 *  non-TTY. Idempotent — call again to resize the region. */
export declare function _installScrollRegion(bottomRows: number): void;
/** Tear down the reserved region. Restores the default scroll region
 *  (the whole terminal) and prints a trailing newline so the next
 *  shell prompt lands below the bottom region. */
export declare function _resetScrollRegion(): void;
/** Hybrid-mode variant of `_runLoop`. Drives the `repl()` widget's
 *  bounded `Screen` (bottom `bottomRows` rows only); frames render
 *  into the terminal's reserved bottom region while plain stdout
 *  writes keep scrolling in the top region. The scroll region itself
 *  is installed by `repl()` via `_installScrollRegion` before this
 *  call and torn down via `_resetScrollRegion` afterwards (including
 *  on exception paths via the Agency `handle` block).
 *
 *  Output target selection:
 *  - **Test mode** (`bridgeOutputTarget` is a `FrameRecorder`,
 *    injected by `_setOutputTarget`): frames go straight into the
 *    recorder so tests can inspect them.
 *  - **Real terminal mode**: a fresh `BottomRegionOutputTarget`
 *    writes ANSI to stdout via `withBottomCursor`, bypassing the
 *    default `TerminalOutput` (which would enter the alt screen and
 *    prepend `CURSOR_HOME` — both fatal to hybrid scrollback).
 */
export declare function _runLoopHybrid(initialState: any, renderFn: unknown, handleKeyFn: unknown, isDoneFn: unknown, tickMs: number, bottomRows: number): Promise<any>;
export {};
