@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
179 lines • 8.09 kB
TypeScript
import type { ShellArray } from './array.ts';
/** What a shell variable can hold. */
export type ShellValue = string | ShellArray | Record<string, string>;
export type Coercer = (text: string) => string;
/**
* One bash variable attribute, spelled as its `declare` letter.
*
* Declaration order is the order `declare -p` prints a cluster in,
* pinned exhaustively against bash 5.2.37 over all 72 ordered pairs of
* `a A i l n r t u x`: `a`/`A` first, then `i n r t x`, then `l`/`u`. It
* is bash's own internal order, not the order the letters were typed in
* (`declare -xri` prints `-irx`), and not alphabetical.
*
* `-a` and `-A` are deliberately absent: whether a variable is an
* indexed array, an associative array or a scalar is what its value
* *is*, so storing it a second time as an attribute would let the two
* contradict each other. `attrLetters` derives them from the value.
*/
export declare enum VarAttr {
Integer = "i",
Nameref = "n",
Readonly = "r",
Trace = "t",
Export = "x",
Lower = "l",
Upper = "u"
}
/** What a variable's value is, derived from the value itself. */
export declare enum VarKind {
Scalar = "scalar",
Indexed = "indexed",
Assoc = "assoc"
}
/**
* Where a managed variable's value comes from.
*
* A managed variable is an ordinary `ShellVar` carrying one of these:
* the pointer is host configuration (a YAML/in-app env entry), never
* something an agent line can spell, and it is what serializes -- the
* fetched value never does. All fill-step state rides here so a
* session can carry managed entries the workspace never declared.
*
* `source` is the registered source name (`env`, `dotenv`, `aws-sm`,
* or a user-registered one); `ref` the source's address for one secret
* (a secret id, a dotenv path; `''` where the source has no
* sub-address); `key` which field of the fetched secret this variable
* reads (the variable's own name at declaration by default); `eager`
* joins every line's fetch set instead of waiting for a line that
* references the name.
*/
export interface ManagedRef {
readonly source: string;
readonly ref: string;
readonly key: string;
readonly eager: boolean;
}
/**
* One shell variable: a value plus the attributes set on it.
*
* Readonly on purpose. Every writer already computes its result on a
* copy and hands the finished value to the session view (`[...arr]`
* before an element write, and so on), precisely so a refused write
* leaves nothing half-applied. Making the record immutable turns that
* convention into something the type enforces: the only way to change a
* variable is to hand the session view a new record, so a policy gate cannot be
* walked around by reaching into storage.
*
* `value` is null in bash's third state: declared with attributes but
* *unset*, which `readonly NAME` and `export NAME` on a fresh name both
* produce. It is not the empty string -- GNU prints `declare -r ONLY`
* for one and `declare -r EMPTY=""` for the other, `${ONLY-d}` expands
* to `d` while `${EMPTY-d}` does not, and `env` carries the empty one
* but not the unset one.
*/
export interface ShellVar {
readonly value: ShellValue | null;
readonly attrs: ReadonlySet<VarAttr>;
/**
* Set when the value comes from a secrets source. Unfetched is
* exactly the third state above: value null with attributes, so
* `envSnapshot`'s existing value check already omits it. `withValue`
* deliberately carries this field (the fill step writes through it)
* and `detach` is the agent-write arm.
*/
readonly managed?: ManagedRef;
}
/**
* The records a prefix assignment shadowed for one function call.
*
* bash runs `x=1 f` with `x` in a scope of its own around the function,
* its temporary environment: the caller's value comes back when the call
* returns, `unset x` inside reveals it, and an `export` or `readonly` of
* the name lets the value outlive the call. A frame of this type on the
* call path is that scope; a plain frame holds a function's `local`
* shadows.
*/
export declare class TempEnv extends Map<string, ShellVar | null> {
}
/** Build a variable record. */
export declare function makeVar(value?: ShellValue | null, attrs?: ReadonlySet<VarAttr>): ShellVar;
/**
* What kind of variable this is, read off its value.
*
* An unset variable reads as a scalar: bash renders `declare -i n` with
* no `-a`, so nothing but an actual array value earns the letter.
*/
export declare function varKind(v: ShellVar): VarKind;
/** Copy a variable and its mutable array value for a child shell. */
export declare function copyVar(v: ShellVar): ShellVar;
/**
* The variable with a new value and the same attributes, but a reference's
* under an array: bash's reference cannot hold one, so `declare -n r;
* r=(x)` leaves `declare -a r`.
*/
export declare function withValue(v: ShellVar, value: ShellValue | null): ShellVar;
/**
* The variable with its managed pointer dropped, value kept.
*
* An agent write to a managed name shadows session-locally: the record
* becomes a plain variable for this session only, so the fill step
* never clobbers it and the declaration (new sessions fetch fresh) and
* the remote store are untouched by construction.
*/
export declare function detach(v: ShellVar): ShellVar;
/**
* The variable with one attribute turned on or off. `+attr` is the off
* direction, which is why this takes a flag rather than being two
* functions.
*/
export declare function withAttr(v: ShellVar, attr: VarAttr, on?: boolean): ShellVar;
/**
* The stored attribute letters, in `declare -p` print order.
*
* The tail of `attrLetters` without the `a`/`A` kind lead, which is
* derived rather than stored. Split out because two callers want the
* stored half alone: the serializer, which must not write a letter it
* would then read back as an attribute the value already implies, and
* `attrLetters` itself.
*/
/**
* Apply the value-shaping attributes to one scalar being stored.
*
* bash applies these at assignment, not at read: `declare -l s; s=ABC`
* stores `abc`, and `declare -i n; n=2+2` stores `4`, so `declare -p`
* and `$s` agree with no per-read work. Order is integer first, then
* case, which only matters for hex digits and is what GNU does
* (`declare -il n=0xA` stores `10`). `-l` and `-u` cannot both hold; a
* declaration that sets one clears the other, so at most one applies.
*/
export declare function coerceScalar(text: string, attrs: ReadonlySet<VarAttr>, integer: Coercer | null): string;
/**
* `coerceScalar` lifted over every value shape. An array applies the
* attribute per element, which is GNU's `declare -ai a=(1+1 2*3)` giving
* `([0]="2" [1]="6")`. A write that assigns some elements only (`a[1]=x`,
* `a=x`) names them in `assigned`, and the others are carried over as
* stored: bash shapes a value when it is assigned, so `declare -i a;
* a[0]=9` never re-evaluates a stored `a[1]`.
*/
export declare function coerceValue(value: ShellValue, attrs: ReadonlySet<VarAttr>, integer: Coercer | null, assigned?: ReadonlySet<number | string> | null): ShellValue;
export declare function storedAttrs(v: ShellVar): string;
/**
* The attribute set a stored letter cluster spells, the inverse of
* `storedAttrs`, used when a persisted session is read back. A letter
* that names no attribute is ignored rather than throwing: the store is
* shared with the other language and with future versions, and refusing
* to load a session because one letter is unknown loses far more than
* the letter.
*/
export declare function attrsFromLetters(letters: string): ReadonlySet<VarAttr>;
/**
* The attribute cluster `declare -p` prints for this variable.
*
* `-a`/`-A` come from the value's kind and lead, then the stored
* attributes in print order. bash prints `--` for a plain scalar with
* nothing set, which is the caller's to render since only it knows it is
* writing a `declare` line.
*/
export declare function attrLetters(v: ShellVar): string;
//# sourceMappingURL=variable.d.ts.map