/** * The whole of JAM's terminal presentation. * * Deliberately hand-rolled rather than pulled from a TUI library: JAM needs a * status line, a section heading and a single-choice list, and a dependency * that renders full-screen frames would be a lot of surface for that. It also * keeps the non-TTY path honest - everything here degrades to plain lines. */ export type UiOptions = { stream?: NodeJS.WriteStream; input?: NodeJS.ReadStream; /** Force interactivity on or off; defaults to detection. */ interactive?: boolean; color?: boolean; }; export declare const SYMBOLS: { readonly section: "◆"; readonly success: "✓"; readonly warning: "!"; readonly failure: "×"; readonly selected: "❯"; readonly pending: "○"; readonly next: "›"; }; /** * Colour is suppressed for NO_COLOR, for CI, and for anything that is not a * TTY - a log file full of escape codes helps nobody. Meaning is never carried * by colour alone; every state also has a distinct symbol. */ export declare function colorEnabled(stream: NodeJS.WriteStream, env?: NodeJS.ProcessEnv): boolean; export declare function interactiveEnabled(stream: NodeJS.WriteStream, input: NodeJS.ReadStream, env?: NodeJS.ProcessEnv): boolean; export declare class CancelledError extends Error { constructor(); } /** * Raised when a question is unavoidable but there is no terminal to ask it in. * Distinct from any JAM/Jira error: nothing is wrong with the setup, there is * just no one to answer, and the fix is a flag rather than a diagnosis. */ export declare class NonInteractiveError extends Error { /** A whole instruction, printed as given - not a bare flag or command. */ readonly flagHint: string; constructor(question: string, flagHint: string); } /** * The one mapping of a prompt that could not run to an exit code. * * Returns undefined for anything else, which the caller must rethrow: a * cancelled prompt is not a failure, and a missing terminal is guidance rather * than a diagnosis, but a real fault must still surface as one. */ export declare function reportPromptError(err: unknown, ui: Ui): number | undefined; export type Choice = { value: T; label: string; /** Shown dimmed under the label. */ hint?: string; }; export declare class Ui { readonly interactive: boolean; private readonly stream; private readonly input; private readonly useColor; constructor(options?: UiOptions); private paint; write(text: string): void; line(text?: string): void; /** * A stage heading. Sections replace a rigid "[2/5]" counter, which lies * whenever a step turns out to be already done and gets skipped. */ section(title: string, subtitle?: string): void; success(text: string, detail?: string): void; warn(text: string, detail?: string): void; failure(text: string, detail?: string): void; pending(text: string, detail?: string): void; next(text: string): void; private status; /** * Spinner for genuine waiting only - a network round trip, a package * download. Spinning while reading a local file is theatre that makes fast * operations look slow. */ spin(label: string, work: () => Promise): Promise; /** * Free-text answer, echoed as it is typed. * * The line editor is Node's readline, not JAM's: IME composition, CJK width, * grapheme deletion, cursor movement and paste are the terminal's job, and a * hand-rolled reader gets every one of them wrong. Cancelling is Ctrl-C, * Ctrl-D or a closed stdin - readline swallows a lone Escape, so unlike * `secret()` and `select()` this prompt cannot be cancelled with it. */ prompt(question: string, flagHint: string, fallback?: string): Promise; /** * Secret answer - nothing typed is ever echoed, to this stream or any other. * * No dots, no length hint, no redraw: an API token pasted into a terminal * should leave no trace on screen for someone glancing over, in a screen * share, or in scrollback. */ secret(question: string, flagHint: string): Promise; /** * The only place raw mode and a hand-managed buffer still live. * * A token needs four things - no echo, paste, delete, Enter - and a line * editor that echoes nothing is not something readline offers. Everything * `prompt` needs and this does not - cursor movement, IME, character width - * stays out. */ private readSecret; /** * Single-choice list. Throws in non-interactive mode rather than silently * picking a default - an unattended run that quietly chose for you is worse * than one that tells you which flag to pass. */ select(question: string, choices: Choice[], flagHint: string): Promise; }