UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

66 lines (65 loc) • 4.64 kB
/** 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;