import { StatusLevel, StatusUpdateCallback } from '#src/core/types.js'; /** * The console level is held in {@link @gaunt-sloth/core!utils/consoleLevel | utils/consoleLevel}, a * module with no dependencies of its own, so that a writer which cannot use these helpers can still * consult the same gate — see that module for why. Re-exported here because this is the spelling * `consoleLevel` has always had, and one public name for one setting is worth more than tidiness. */ export { getConsoleLevel, resetConsoleLevel, setConsoleLevel } from '#src/utils/consoleLevel.js'; /** * ANSI color codes — the 16-colour slots only, deliberately. A 16-colour slot is rendered with the * user's OWN terminal theme colour, so output looks native in light and dark schemes alike; a * 256-colour or 24-bit escape would pin us to one palette and clash with half of them. * * Exported so the surfaces that build their own pre-styled blocks (rather than passing a whole * message through `colorText`) still draw from this one table — see * `core/launchBanner.ts`, which paints only the face half of each banner row. * * `as const` because `packages/core` publishes `"./*.js": "./dist/*.js"`, so this is PUBLIC API of a * published package: without it any consumer could assign `ANSI_COLORS.magenta` and repaint the * whole CLI from the outside. Read-only, one table, no remote control. */ export declare const ANSI_COLORS: { readonly red: '\u001B[31m'; readonly yellow: '\u001B[33m'; readonly green: '\u001B[32m'; readonly magenta: '\u001B[35m'; readonly dim: '\u001B[2m'; readonly reset: '\u001B[0m'; }; export declare const initSessionLogging: (logFileName: string, enableLogging: boolean) => void; export declare const flushSessionLog: () => void; export declare const stopSessionLogging: () => void; export declare function displayError(message: string): void; /** * Open a warning-capture window: from now until {@link endWarningCapture}, each * `displayWarning` message is buffered (IN ADDITION to being printed/logged as usual). Used by * the TUI session module to grab the transient load-time config advisories and thread them into * the persistent notice surface. Idempotent-ish: a second call starts a fresh buffer. */ export declare const beginWarningCapture: () => void; /** * Close the warning-capture window opened by {@link beginWarningCapture} and return everything * collected (empty array if none / never opened). Always call this — a `try/finally` around the * captured work — so a throw can't leak the capture state into later warnings. */ export declare const endWarningCapture: () => string[]; export declare function displayWarning(message: string): void; export declare function displaySuccess(message: string): void; export declare function displayInfo(message: string): void; export declare function display(message: string): void; /** * TUI-C30 — print one pre-styled tool-call indication block (the plain surface's compact * `✓ name(args…)` + greyed preview, built by `core/plainToolIndication.ts`). Same stdout channel * and session-log treatment as {@link displayInfo} — matching the stream discipline of the * existing tool notices — but WITHOUT the blanket dim wrap: the block styles each line itself * (diff colours, per-line dim), and an outer wrapper would be broken by the inner resets. The * session log gets the ANSI-stripped text via `writeToSessionLog`. * * [[TUI-C108]] — **`level` is the CALL'S OUTCOME, not this call site's loudness**, and that is the * whole point of the parameter. While the level was hardcoded here, every `consoleLevel` rung that * hid a successful tool call hid a failed one with it, so "keep only the failures" was not * expressible at any setting. The caller derives it from the tone it has already computed, which * makes a quieted console drop the chatter and keep what went wrong. * * **The LEVEL moves; the CHANNEL deliberately does not.** An ERROR-gated line still goes to * `su.info` rather than to stderr — as {@link displayError} already writes with `su.log` — because * splitting one surface's tool rows across two streams would reorder them against each other and * against the model text they are interleaved with. Level and stream are independent here. * * The `StatusLevel.INFO` default is what keeps every existing caller, and the default console * level, rendering exactly as before. */ export declare function displayToolIndication(message: string, level?: StatusLevel): void; /** * TUI-C33 — print the interactive-launch banner (the pre-styled block built by * `core/launchBanner.ts`) on the plain surface. Same DISPLAY-level gate and stdout channel as * {@link display}, so a quieted console silences it too, but deliberately NOT routed through * `writeToSessionLog`: the session log is a transcript of the conversation, not a screenshot * of the screen, and a five-row sloth at the top of it is noise. The block also styles itself (the * face half of each row carries the colour), so no outer wrap is applied. */ export declare function displayLaunchBanner(message: string): void; export declare function formatInputPrompt(message: string): string; /** * How loud one line of an interactive dialog is — its COLOUR, and nothing else. * * The other `display*` helpers bind a colour to a stream: picking red means picking stdout, picking * yellow means picking stderr. A dialog needs both halves independently, so this names the half that * is about appearance and leaves the stream to {@link displayDialogLine}, which always chooses the * same one. * * `notice`/`warn`/`danger` are the three tones `core/shell/escalationSeverity` grades an escalation * with, so a surface can pass a rater outcome's tone straight through; `plain` is text with no * severity (the framed command, a blank spacer) and `prompt` is the line the human types their * answer after. */ export type DialogTone = 'plain' | 'notice' | 'warn' | 'danger' | 'prompt'; /** * Print one line of an interactive dialog — an approval prompt, an attack banner — **on stderr**. * * ## One dialog, one stream * * A dialog's meaning is carried by the ORDER of its lines: a heading, then whose words the next * lines are, then the words. Two streams cannot promise an order. Only writes to the *same* stream * are delivered in the order they were made — across stdout and stderr nothing is promised, and the * difference is observable the moment the two go to different places: with stdout a pipe or a file * it is block-buffered while stderr is not, so a captured run can carry a rater's answer above the * command it answers. A security dialog whose line order holds only on a terminal is not a gate, so * every line of one goes through here and through nothing else. * * **stderr, because a prompt is not program output.** It is the conventional home for interaction, * it is not block-buffered, and it leaves stdout carrying only what the run produced. The cost is * real and is documented for users: piping stdout (`gth code --no-tui | tee log`) no longer captures * the dialog — the terminal still shows it, `2>` still collects it, and an enabled session log still * records it. The log write here is UNCONDITIONAL, which the gated helpers' is not: theirs sits * behind the level guard, so a quieted console drops those lines from the transcript as well as * from the screen. A dialog stays whole in both places. * * ## Not level-gated, on purpose * * The dialog is a QUESTION, not a status message, and the level filter is per line: gated, a quieted * console prints the parts above its threshold and drops the rest, which is how an approval prompt * comes to show a severity heading with no command under it. Half a dialog is worse than none, * because it still looks like a whole one. */ export declare function displayDialogLine(message: string, tone?: DialogTone): void; /** * How loud a NOTICE is — the title's colour, and the marker that says the same thing in the text. * * Two tones, matching the `SlashCommandNotice` vocabulary the surfaces already build notices with, * so a builder's tone passes straight through instead of being re-derived here. */ export type NoticeTone = 'info' | 'warn'; /** * The warn tone, said in the text rather than in the colour. * * Colour is the first thing a surface loses — `NO_COLOR`, a pipe, a monochrome terminal, a reader * who cannot distinguish yellow from grey — and a severity that exists only in the colour is a * severity those readers never receive. `⚠` is the marker the rest of the CLI already uses for * exactly this (`core/shell/escalationSeverity`, `core/toolDisplay`, `core/shell/framing`), so this * adds no second vocabulary for the same idea. * * Applied by {@link displayNotice} at render time and never written into the notice VALUE: the same * `title` travels to the Ink TUI, ACP and AG-UI, and a marker baked into the value would reach all * of them as data rather than as presentation. AG-UI keeps the classification by shipping the whole * notice object, and so does ACP, in `_meta` (see `acpTerminationMeta`) — what ACP joins into one * text block is the human-readable half, not the classification. The Ink TUI marks tone * by COLOUR ALONE (`CommandNotice`'s yellow-vs-cyan title), so under `NO_COLOR` a warn notice there * is indistinguishable from an info one — a known TUI-C14 residual, NOT something this marker * covers. */ export declare const NOTICE_WARN_MARKER = "\u26A0 "; /** * When `consoleLevel` may silence a notice: at a {@link StatusLevel}, or never. * * A level here gates the WHOLE notice — see {@link displayNotice} — so it can never mean "some of * this notice". */ export type NoticeGate = StatusLevel | 'always'; /** * Print one whole NOTICE — a title and its body lines — **on stderr**. * * ## One notice, one stream * * A notice is a title that names something and body lines that are the substance of it; neither * half is usable alone. Written through the ordinary helpers it is written across BOTH streams, * because those bind colour to stream: a title coloured with `displayWarning` is yellow AND stderr, * while `display` body lines are stdout. On a terminal both go to the same place and nothing shows; * redirect one and the notice tears in half — the reader keeps *"Run ended"* with no reason code * while the file keeps the reason code with no notice. * * So a notice takes its title and its lines together and writes them through one call. The split * cannot be reintroduced by a caller, because a caller no longer chooses per line. * * **stderr, because a notice is commentary on the run and not the run's output.** It is where * `displayWarning` already writes, and that is the only one of the ordinary helpers that does — * even `displayError`, the loudest of them, is red but goes to stdout. It is unbuffered, and it * leaves stdout carrying only what the command produced — so `gth ask … > answer.txt` gets an * answer file that is the answer, with the whole explanation of a bad ending still on the screen * and still collectable with `2>`. * It also keeps a notice on the same stream as the approval dialog it sits beside on the readline * surface ({@link displayDialogLine}); split across two, those two related blocks can arrive in an * order neither of them was written in. * * The session log gets every line UNCONDITIONALLY, gate or no gate, so a quieted console never * costs the transcript a notice it did not show. * * ## The gate is per NOTICE, never per line * * `gate` is checked once, before the first line is written, and decides the whole notice. That is * the property, not an implementation detail: the level filter applied per line is what let a * quieted console print a title with no body under it (and, at `display` level, a body with no * title over it), which still looks like a whole notice and is not one. * * `'always'` is for a notice whose absence cannot be recovered by the reader — the termination * notice carries the one token a bug report needs, and the session log that would otherwise hold it * is off by default. A notice the user asked for by typing a command is not that: it is gated at * its own tone's level, and re-running the command after un-quieting the console brings it back. */ export declare function displayNotice(title: string, lines: readonly string[], options?: { tone?: NoticeTone; gate?: NoticeGate; }): void; /** * Display a debug message to the console and log it. * This function also integrates with debugUtils to output logs when at debug level. * Note: There is also a dedicated debug() function in debugUtils for more detailed logging. * @param message - The message to display (string, Error, or undefined) */ export declare function displayDebug(message: string | Error | undefined): void; export declare const defaultStatusCallback: StatusUpdateCallback; /** * Result of attempting to parse a CLI value as boolean-or-string. * When kind === 'boolean', value is a boolean. * When kind === 'string', value is a non-empty string. * When kind === 'none', no usable value was provided (undefined/null/empty). */ export type BooleanOrStringParseResult = { kind: 'boolean'; value: boolean; } | { kind: 'string'; value: string; } | { kind: 'none'; }; /** * Parse a CLI option value into either: * - a boolean (when value looks like a true/false token), * - a non-empty string (otherwise), * - or none (when value is nullish or only whitespace). * * Recognized false-like tokens (case-insensitive): 'false', '0', 'n', 'no' * Recognized true-like tokens (case-insensitive): 'true', '1', 'y', 'yes' * * Examples: * parseBooleanOrString('n') => { kind: 'boolean', value: false } * parseBooleanOrString('0') => { kind: 'boolean', value: false } * parseBooleanOrString('true') => { kind: 'boolean', value: true } * parseBooleanOrString('1') => { kind: 'boolean', value: true } * parseBooleanOrString('review.md') => { kind: 'string', value: 'review.md' } * parseBooleanOrString(' ') => { kind: 'none' } * parseBooleanOrString(undefined) => { kind: 'none' } */ export declare function parseBooleanOrString(value: unknown): BooleanOrStringParseResult; /** * Convenience wrapper that returns a union directly instead of the tagged result. * * Returns: * - boolean when the input is a boolean-like token * - string when the input is non-empty and not a boolean-like token * - undefined when the input is nullish or empty/whitespace */ export declare function coerceBooleanOrString(value: unknown): boolean | string | undefined;