/** One argv word as the lexer read it. */
export interface ShellWord {
    /** The word's value with quotes and escapes removed — meaningful only when `expands` is `false`. */
    readonly text: string;
    /** The unquoted source spelling (assignment and wrapper-flag tests read this, never `text`). */
    readonly raw: string;
    /** `false`: a literal word. `"one"`: carries an expansion but yields exactly ONE word (it was double-quoted).
     *  `"many"`: an unquoted expansion, glob or brace pattern, or a quoted `"$@"` / array expansion — may
     *  yield zero, one or several words. */
    readonly expands: false | "one" | "many";
}
/** One redirection of a segment, as read: the operator and its operand word (a heredoc's operand is its
 *  delimiter; the IO number or `{name}` before the operator is folded into the operator's meaning and not
 *  kept). The tightening reader never reads these — a rule speaks about program runs; the read-only
 *  reader does (an output redirection is a write). */
export interface ShellRedirection {
    readonly op: string;
    readonly target: ShellWord;
}
/** One program run the lexer found, after keyword stripping. */
export interface ShellSegment {
    /** The run as SPELLED (a leading keyword removed): the first candidate a rule is compared against. */
    readonly argv: readonly ShellWord[];
    /** The segment's redirections in source order (see {@link ShellRedirection}); empty when it has none. */
    readonly redirections: readonly ShellRedirection[];
    /** The deeper candidates, one per peeled layer (leading assignments, then each wrapper of the table):
     *  `sudo -u root rm -r x` ⇒ `[[rm, -r, x]]`. Empty when nothing peeled. */
    readonly peeled: readonly (readonly ShellWord[])[];
    /** Present when this segment's program runs cannot be known from the text at all; `argv` then holds
     *  whatever was read before the failure and must not be matched as a run. */
    readonly unreadable?: string;
    /** Present when the segment's program runs are NOT fully known although its candidates could be read:
     *  a peel that stopped before the wrapped program could be named (its options carry an expansion, a
     *  command string, an option of unknown arity), or a command/process substitution anywhere in the
     *  segment (it runs a program the lexer does not read). The candidates stand — a rule they reach is
     *  reached — and every other rule reads `unreadable`. */
    readonly peelUnreadable?: string;
}
/** A command line as the tightening reader sees it. */
export interface ShellCommandShape {
    readonly segments: readonly ShellSegment[];
    /** The connector BETWEEN each consecutive pair of segments (`;` `&&` `||` `|` `|&` `&` `\n`). */
    readonly connectors: readonly string[];
    /** A subshell, group, control-structure keyword or dropped empty piece bounded the segments: the
     *  connector list is not one flat chain a compound rule could spell. */
    readonly grouped: boolean;
    /** A `&` connector anywhere — between two segments or after the last one (`ls &`): some segment runs in the
     *  background, past any approval-time reading of the line. The connector list alone cannot say so for a
     *  trailing `&` (a connector rides BETWEEN segments). */
    readonly backgrounded: boolean;
    /** A redirection on a piece that runs NO program (`> x` alone, `[ -f a ] > x`, a keyword's own redirection):
     *  such a piece is dropped from `segments` (the tightening reader asks about program runs, and it runs
     *  none) — but the shell still opens the target, so a reader that asks about EFFECTS must refuse the line. */
    readonly strayRedirection: boolean;
}
export { SHELL_WRAPPER_TABLE, type ShellWrapperName } from "./shell-wrapper-table.js";
/** Longer than this and the command is not read at all (one unreadable segment): every pass is linear,
 *  but a substitution nested inside quoting re-enters the quote reader once per nesting level, and the
 *  cap is what bounds that on model-supplied text. Upstream's own reader stops at the same size. */
export declare const MAX_SHELL_READ_CHARS = 10000;
/** Read `source` as the tightening reader must: every program run the text could perform, or why it cannot be read. */
export declare function readShellCommand(source: string): ShellCommandShape;
/** Every program run of `shape` can be NAMED from the text: no segment is unreadable, no peel stopped,
 *  and every run candidate's program word is literal. The offer/mint side's "judgeable" question. */
export declare function isFullyReadable(shape: ShellCommandShape): boolean;
