@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
142 lines • 7.11 kB
TypeScript
import type { Claimant, HandOff, Occurrence } from '../../policy/types.ts';
import type { TSNodeLike } from '../../shell/types.ts';
import type { SessionState } from '../session/session.ts';
/**
* What opens and closes a substitution's body, in the order the openers
* are tried; the body between them is the text a nested line is parsed
* from. A backtick region is not here: its body loses its backslashes
* before it is parsed, so it is lexed into lines (`segmentFrames`) rather
* than framed as one body.
*/
export declare const SUBSTITUTION_DELIMITERS: readonly (readonly [string, string])[];
/**
* The text a walk reads commands from, as the line that evaluates it
* will parse it.
*
* The pass walks one tree and computes for every command the occurrence
* the gate will compute when it runs, and the gate may be running a
* different parse of the same text: a substitution's body is parsed on
* its own by the nested line, at offsets that start from zero, while
* the pass reads it as a subtree of the outer line. The frame is what
* makes the two agree: `text` is what the nested line parses, `base` is
* where that text starts in the tree being walked, and `parent` is the
* occurrence its commands stand under. Mirrors the Python Frame.
*/
export interface Frame {
readonly text: string;
readonly base: number;
readonly parent: Occurrence | null;
}
/**
* The frame of the tree a node belongs to: the text its parse read, at
* that parse's own offsets.
*
* The one rule both readers share. The gate builds it from the node it
* runs, and the pass from the tree it walks, so a stored function body
* is placed relative to its definition. Reparsing that source in another
* worker gives its commands the same approval locations.
*/
export declare function rootFrame(node: TSNodeLike, parent: Occurrence | null): Frame;
/**
* The frame of a function body as a pass walks its definition. The body
* runs from its own parse of the stored source, so its commands stand at
* offsets from the definition, under the definition's own place on the
* line: two definitions of one text are two places, each needing a nod
* of its own. Mirrors Python's definition_frame.
*/
export declare function definitionFrame(node: TSNodeLike, frame: Frame): Frame;
/**
* The place a function definition the executor runs stands on its line,
* which the body's commands stand under when it is called; null outside
* a line. Mirrors Python's defined_at.
*/
export declare function definedAt(node: TSNodeLike, handed: HandOff | null): Occurrence | null;
/**
* The frame a node's gate will read it in, for a pass that reads it ahead
* of the gate: its own tree's, and for a node in a function body under the
* place the call runs the body under. Mirrors Python's gate_frame.
*/
export declare function gateFrame(node: TSNodeLike, line: TSNodeLike, session: SessionState, handed: HandOff): Frame;
/**
* The frame of a line a word runs (`eval`, `sh -c`), which the pass
* parses on its own exactly as the nested evaluation will.
*/
export declare function lineFrame(text: string, parent: Occurrence): Frame;
/**
* The frame of the line a command hands the evaluator for words it was
* given already split (`command`, `env`, `timeout`, `xargs`), spelled
* as those builtins spell it: joined with shellJoin, so an operand
* holding a space survives the re-parse as one word.
*
* The nested gate parses that spelling, so the pass has to compute the
* occurrence on it. Joined with a plain space, `cat '/data/secret
* file'` was read as `cat /data/secret file` and the gate could not
* find the grant claimed for it.
*/
export declare function argvFrame(argv: readonly string[], parent: Occurrence): Frame;
/** Where a node stands, as a parse of the frame's text would place it. */
export declare function occurrenceIn(node: TSNodeLike, frame: Frame): Occurrence;
/**
* The occurrence of a frame's whole text, for words a command runs
* without a parse of their own (`xargs cat`, `find -exec`).
*
* The end is the parser's own unit: it places a node here in UTF-16
* code units, which is what a string index counts, so no
* measuring is needed here. The Python parser counts bytes, and that
* side measures every span it computes from text (`byte_offset`).
*/
export declare function wholeOccurrence(frame: Frame): Occurrence;
/**
* The frame of a substitution's body, as the nested line that evaluates
* it will parse it: `$( )`, `<( )` or `>( )`, with the whitespace
* the parser folds into the opening token set aside as expansion sets
* it aside. Null for a node that is not a substitution the evaluator
* would run.
*/
export declare function bodyFrame(node: TSNodeLike, frame: Frame): Frame | null;
/**
* The occurrence of one span of a node's text, for a node whose line is
* not its whole text: a backtick region, which the evaluator lexes
* again. Each command is its own place on the line.
*/
export declare function partOf(occurrence: Occurrence, start: number, end: number): Occurrence;
/**
* The frames of the lines a backtick region runs, one per pair, each to
* be parsed on its own under the pair's own place on the line; empty
* for a node that is not a backtick region.
*
* The region's subtree is not what runs: bash removes a backtick body's
* backslashes before it parses it, so the pass reads the region as the
* evaluator does, split by the one lexer both share
* (`splitBacktickRegion`), with the folded whitespace set aside first as
* expansion sets it aside.
*/
export declare function segmentFrames(node: TSNodeLike, frame: Frame): Frame[];
/**
* Where a node the executor runs stands, on the line it runs in: the
* line's hand-off carries as `origin` the node the line's text was
* evaluated from. `span` is the part of the node's text that runs, when
* the node holds several lines.
*/
export declare function occurrenceOf(node: TSNodeLike, handed: HandOff, span?: readonly [number, number]): Occurrence;
/**
* The hand-off a line read from a node's text runs on.
*
* Every re-parse the executor runs is a line of its own: the body a
* substitution expands, the words `eval` or `xargs` hand on, the line an
* alias invocation rewrites to. It runs under the hand-off of the
* subtree reading it and stands at the node whose text it is, so its
* commands are placed where the outer pass placed them, and one text
* read from two nodes (`c && c` under one alias) is two places on the
* line, each needing a nod of its own. What its gates claim goes back
* to that hand-off when it ends (`Decisions.handUp`). `span` is the part
* of the node's text that runs, when the node holds several lines.
* Mirrors the Python `evaluated_from`.
*/
export declare function evaluatedFrom(node: TSNodeLike, handed: HandOff, span?: readonly [number, number]): HandOff;
/**
* The reader of the ledger for one command the executor runs, null
* outside a line.
*/
export declare function claimantFor(node: TSNodeLike, handed: HandOff | null | undefined): Claimant | null;
//# sourceMappingURL=occurrence.d.ts.map