import type { SessionView } from '../../view/types.ts';
import { type Policies } from '../../policy/index.ts';
import type { CallStack } from '../../shell/call_stack.ts';
import { type ShellArray } from '../../shell/array.ts';
import type { ArithResult, ElementOps } from '../../shell/types.ts';
import type { ShellValue, ShellVar } from '../../shell/variable.ts';
import { VarAttr } from '../../shell/variable.ts';
import type { SessionState } from './session.ts';
/**
 * The one copy-out of a session's environment.
 *
 * Every tier that hands the env onward as a process view (a command's or
 * CLI's or a runtime's `ctx.env`, the `env` builtin) copies
 * through here, so the hidden-vars filter lands on all of them by
 * construction rather than on however many hand-rolled copies someone
 * remembers. The copy keeps the null prototype session records carry.
 *
 * *Exported* names only, which is what makes this the process view
 * rather than a second spelling of `visibleEnv`. bash puts a variable
 * in a child's environment when it carries the export attribute, not
 * when it happens to hold a string: `X=hello` is absent from `env` and
 * `export Y=world` is present. An unset name carrying the attribute
 * (`export Z`) is absent too, which falls out of the value check
 * rather than needing its own arm.
 *
 * Diverges from bash on one point: bash also carries each function
 * `export -f` marked, as a `BASH_FUNC_NAME%%` entry. mirage hands those to
 * a nested shell directly (`SessionState.newShell`), so neither `env` nor a
 * runtime lists them.
 */
export declare function envSnapshot(session: SessionState): Record<string, string>;
/**
 * The name a `declare -n` reference points at, null otherwise. Null
 * also for a reference declared but not yet aimed (`declare -n r`
 * before `r=v`): bash treats the first assignment as naming the target,
 * so until then it stands for nothing.
 */
export declare function namerefTarget(session: SessionState, name: string): string | null;
/**
 * The variable a name stands for, following `declare -n` chains. A name
 * that is not a reference is its own answer. A chain that comes back to
 * itself (`declare -n a=b; declare -n b=a`) is bash's circular name
 * reference, read as unset: it resolves to the empty name, which no
 * record has, so a reader sees unset and a writer falls back to the
 * reference's own record. The warning line is the one part not
 * reproduced.
 */
export declare function deref(session: SessionState, name: string): string;
/** The variable's value, null when unset or hidden. Sync on purpose:
 * `$X` expansion is the hot path, so a read stays a record lookup plus
 * the hidden check. A name reference reads its target. */
export declare function envGet(session: SessionState, name: string): string | null;
/**
 * Whether `readonly` has marked the name.
 *
 * A hidden name answers false: isReadonly speaks about the session's
 * visible world, and calling a name that reads as unset "readonly"
 * would leak it. `followRef` asks about what a `declare -n` reference
 * points at; a write to the reference itself (`declare -n r=w`,
 * `unset -n r`) asks about the reference.
 */
export declare function envIsReadonly(session: SessionState, name: string, followRef?: boolean): boolean;
/**
 * The env mapping a reader tier should resolve names against.
 *
 * Always a filtered copy, never `session.env`: that getter is itself a
 * projection built fresh per access, so handing it out would copy the
 * store anyway and freeze the answer at that moment. TS diverges from
 * python's lazy mapping view deliberately: expansion sites read records
 * with plain property access, so a copy is the shape they already
 * consume, and env sizes make the copy cost noise.
 *
 * The *shell* view, and no longer a synonym for `envSnapshot`: this is
 * what `$X`, arithmetic, `[[ ]]`, `IFS` and the bare `set` listing
 * resolve against, and they see every variable, exported or not. The
 * two were the same function while the process view was also "every
 * string", and reusing it once the process view narrowed would have
 * stopped `$X` resolving a plain assignment. python kept them separate
 * all along (`_VisibleEnv` beside `env_snapshot`); this is TS catching
 * up to it.
 */
export declare function visibleEnv(session: SessionState): Record<string, string>;
/**
 * The arrays mapping a reader tier should resolve names against.
 *
 * The arrays twin of `visibleEnv`: the embedder can seed
 * `session.arrays` before narrowing, so a hidden name can hold an
 * array and array reads need the same filter env reads get.
 */
export declare function visibleArrays(session: SessionState): Record<string, ShellArray>;
/**
 * The associative arrays a reader tier should resolve names against.
 *
 * The third sibling beside `visibleEnv` and `visibleArrays`, for the
 * same reason both exist: the embedder can seed a hidden name with any
 * value shape, so every reader tier filters the same way.
 */
export declare function visibleAssocs(session: SessionState): Record<string, Record<string, string>>;
/**
 * Write one variable through the session plane's gate.
 *
 * General over variable shapes: a string stores a scalar, a ShellArray
 * stores a whole array, and the two storages stay exclusive. Semantics
 * live here once — the hidden refusal, readonly refusal, the
 * `preSession` policy gate (whose context value renders an array as
 * its present elements joined by spaces), then the store — so every
 * writer states them the same way whichever tier or spelling asked.
 * Writers with richer mechanics (subscripts, appends, holes) compute
 * the resulting value on a copy and hand it here, so a denial never
 * leaves a half-applied write. Null policies gate nothing (a writer
 * outside a workspace). Throws PolicyDenied when the name is hidden
 * for this session (a landed write would clobber the real value the
 * host's wiring still reads; a swallowed one would gaslight the
 * writer — the vars twin of EACCES on a create into hidden path
 * space), ReadonlyVariableError when the name is readonly, and
 * PolicyDenied when a preSession policy refuses the write.
 */
/**
 * Refuse a write that names a hidden variable.
 *
 * The sync half of `setVar`'s hidden gate, shared with the
 * expansion-time writers that land on the raw env (`${X:=d}`,
 * `$((X=5))`, `printf -v`): a landed write would clobber the real
 * value the host's wiring still reads, and a swallowed one would
 * gaslight the writer; refuse loudly instead, the vars twin of EACCES
 * on a create into hidden path space.
 */
/**
 * Remove one surrounding quote pair from an associative subscript.
 *
 * An arithmetic reference carries its subscript verbatim, so `m["x"]`
 * arrives with the quotes bash would have removed; one layer comes off
 * and anything else is the key itself.
 */
export declare function stripKeyQuotes(text: string): string;
/** Element callbacks bound to one session, for `evaluateArith`. */
export declare function sessionElements(session: SessionState): ElementOps;
/**
 * An indexed subscript resolved outside an arithmetic expression:
 * `${a[i]}`, `a[i]=v`, `unset 'a[i]'`, `[[ -v a[i] ]]`.
 *
 * The subscript is arithmetic, so it may assign (`a[x=3]`) and seed
 * (`a[RANDOM=42]`), and bash binds those as it evaluates them. Each
 * lands through the session view once the index is known, then the `RANDOM`
 * reader replays the draws made after the seed. A subscript that fails
 * to evaluate lands what it assigned before failing and then throws, the
 * subscript text leading the message, since bash aborts the line on it
 * (`${a[1/0]}` is `1/0: division by 0`) rather than reading element 0.
 * `view` is the gated session view; null lands the writes ungated, outside a
 * workspace. Throws what the session view throws too: a PolicyDenied, or an
 * ArithError from a `-i` name refusing the value; a readonly name ends the
 * shell wherever a subscript is (`${a[R=3]}`): ExitSignal.
 */
export declare function subscriptIndex(session: SessionState, subscript: string, view?: SessionView | null): Promise<number>;
/**
 * The `-i` coercion: evaluate the incoming text as arithmetic.
 *
 * Reads resolve against the visible env, so `n=x+1` sees `x`, and
 * element references resolve through the session's resolver, so
 * `n=a[1]+1` and `n=m[k]+1` see the element; an unresolvable name is 0
 * (`n=abc` stores `0`), which is the arithmetic rule, not a refusal. A
 * malformed expression throws ArithError with the offending text led,
 * which is how every caller voices it (`bash: 1+: syntax error: operand
 * expected`), so it is spelled once here rather than at each of the
 * sites that catch it.
 */
/** Evaluate a host-supplied seed; invalid arithmetic propagates. Read
 * without the generator on offer: a host word naming `RANDOM` would
 * otherwise draw, and the draw reseed, without end. */
export declare function seedFrom(word: string, session: SessionState): number;
/** Draw from the session generator, or null after RANDOM is unset.
 * Shell assignments validate and seed at the session view. A host-seeded
 * variable is consumed here on its first read. Reseeding resets repeat
 * suppression to zero independently of the stored word. */
export declare function nextRandom(session: SessionState, stored: string | undefined): number | null;
/**
 * Arithmetic's reads of `$RANDOM`, bound to one session.
 *
 * A read before the expression assigns `RANDOM` draws from the session
 * generator. bash seeds at the instant of an assignment and every later
 * read draws from the new seed (`$((RANDOM=42, RANDOM))` is the first
 * draw after seeding with 42). Here the assignment is still pending at
 * the session view, which lands it gated after evaluation, so the
 * evaluator tells the reader of each assignment as it is made (`wrote`),
 * the reader seeds a scratch generator the way the session view will and draws
 * from that, and `settle` replays the draws on the session once the
 * session view has seeded it: the session ends where bash's does, seeded and
 * advanced by every read since the last assignment, and the write still
 * reaches the gate as the assignment it is. Each assignment restarts
 * the scratch generator and the count, since the session view lands only the
 * last value written, and the draws are replayed only if the session view did
 * land it: an assignment the caller never applied leaves the session as
 * it was.
 *
 * Lives beside the session view rather than with the generator because the
 * session view needs it too: `RANDOM=RANDOM` draws once while the seed is
 * evaluated, then seeds with the draw, as bash does: it reads an
 * assigned seed as an arithmetic expression.
 */
export declare class RandomReader {
    private readonly session;
    private seeded;
    private state;
    private last;
    private draws;
    constructor(session: SessionState);
    private special;
    /** The dynamic value of a name, null for a name that has none. */
    readonly read: (name: string) => string | null;
    /** Note an assignment the expression made: the name and its value, an
     * integer's text. */
    readonly wrote: (name: string, value: string) => void;
    /** Replay the scratch draws on the session generator, once the session view
     * has seeded it with the value the expression assigned. */
    settle(): void;
}
/**
 * End `RANDOM`'s special meaning when a non-string lands on it.
 *
 * Once bash turns `RANDOM` into an array it neither draws nor seeds,
 * so `RANDOM=(1 2)`, `declare -a RANDOM`, `RANDOM[1]=5` and
 * `RANDOM+=(3)` all leave an ordinary array that `$RANDOM` reads element
 * 0 of, for good, as `unset RANDOM` does. Every store entry point calls this,
 * gated or not, since a host seeding an array onto the name means the
 * same thing.
 */
export declare function noteRandomKind(session: SessionState, name: string, value: ShellValue): void;
/**
 * The scalar an array conversion keeps as element 0.
 *
 * When bash turns a variable into an array, its current value becomes
 * element 0, and for a live `RANDOM` looking the name up is what draws:
 * `RANDOM[1]=5` leaves `[0]` holding one draw and `declare -a RANDOM` one
 * alone, after which the array is ordinary.
 */
export declare function conversionScalar(session: SessionState, name: string): string | undefined;
/** Bind arithmetic `$RANDOM` reads to a session. */
export declare function randomReader(session: SessionState): RandomReader;
/**
 * Evaluate `text` as every arithmetic context of the shell does: against
 * the visible env and the session's elements, drawing through `reader`, and
 * stopping at a write to a readonly name, as bash's evaluation does
 * (`(( X=5, R=3 ))` binds X and refuses R). Throws ArithError when the text
 * does not evaluate, and ReadonlyVariableError, carrying the writes made before it,
 * for a readonly name. `added` is an integer `+=`'s added text, read after
 * `text` in the same evaluation and added to it.
 */
export declare function sessionArith(session: SessionState, text: string, reader: RandomReader, nounset?: boolean, added?: string | null): ArithResult;
/**
 * Evaluate `text` as an `-i` write coerces it, land what it assigns through
 * `view`, and give back the value: a `declare -ni r=M` value, which bash
 * evaluates before refusing the reference (`M='X=5'` sets X), and its
 * `r+=M` form, whose `added` text evaluates after `text` in the same
 * evaluation and adds to it. Inside a `declare -g` it reads the
 * function's scope, as the coercion does. A hidden name throws
 * PolicyDenied and a readonly one ExitSignal, which ends the shell as
 * bash's does, the assignments before it landed; a malformed text throws
 * ArithError once the ones before the error land.
 */
export declare function evaluateInteger(session: SessionState, view: SessionView, text: string, added?: string | null): Promise<string>;
/**
 * What a `+=` hands `setVar`: the held text then the added one, or on an
 * integer the held text with the added one as `added`, the two evaluating
 * there in turn and summing behind the store's refusals. The held value
 * evaluates too, so `n='x=5'; declare -i n; n+=x` stores 10, and an empty
 * side counts as 0. An array extends element 0 and a map key `"0"`
 * (`S=x; declare -a S+=y` gives `([0]="xy")`), and `held` is null when unset.
 */
export declare function appended(held: ShellValue | null, added: string, integer: boolean): [string, string | null];
export declare function ensureVarVisible(session: SessionState, name: string): void;
/**
 * Put each name's global record in place for a `declare -g`, and return the
 * call that puts the running locals back. Outside a function, or for a name
 * no frame on the call path shadows, the global record is already in place.
 * Otherwise the running local lives in `session.vars` and the global is
 * what the *outermost* shadowing frame saved, so the two swap for the
 * declaration: its writes, marks and kind checks reach the global, and the
 * local comes back untouched, which is what GNU shows (`local G=5; declare
 * -gr G=1` leaves `$G` at 5 and writable in the function, 1 and frozen
 * outside, and a nested `declare -g` reaches past the caller's local too).
 * Arithmetic it runs still reads the locals (`stepBack`).
 */
export declare function reachGlobal(session: SessionState, names: readonly string[]): () => void;
/**
 * Let a temporary-environment variable outlive its call.
 *
 * bash keeps a name that `x=1 f` put in front of a function once
 * something inside runs `export x` or `readonly x`: x still holds its
 * value after f returns, where otherwise the caller's comes back.
 */
export declare function outliveCall(session: SessionState, name: string): void;
/**
 * Whether the running function's call assigned `name` in front.
 *
 * `x=1 f` puts `x` in f's temporary environment, which sits right under
 * f's own frame of locals.
 */
export declare function inCallEnv(session: SessionState, name: string): boolean;
/**
 * The positional parameters in scope.
 *
 * Inside a function they are the function's own, even when it was called
 * with none: bash's `f` run bare sees `$#` as 0, never its caller's
 * count. Outside every function they are the shell's.
 */
export declare function positionalParams(session: SessionState, callStack: CallStack | null): string[];
/**
 * Replace the positional parameters in scope.
 *
 * `set --` and `shift` inside a function change the function's own and
 * leave the caller's alone, as bash's do.
 */
export declare function setPositionalParams(session: SessionState, callStack: CallStack | null, values: string[]): void;
/**
 * Record the caller's record before a `local` shadows it, once per frame.
 *
 * `RANDOM` parks its generator marker too: a local `RANDOM` is an ordinary
 * variable for the function's extent (`local RANDOM=5; echo $RANDOM`
 * prints 5, and `local RANDOM=(7)` leaves the caller's generator alone),
 * and `restoreLocals` hands the marker back.
 */
export declare function shadowLocal(session: SessionState, locals: Map<string, ShellVar | null>, name: string): void;
/**
 * Put a returning function's shadowed records back.
 *
 * Deliberate divergence: bash reseeds the global generator when a local
 * `RANDOM` is popped (`RANDOM=42; f(){ local RANDOM; }; f; echo $RANDOM`
 * prints 11074 where 17772 was next); mirage resumes the caller's
 * sequence where it left off.
 */
export declare function restoreLocals(session: SessionState, locals: Map<string, ShellVar | null>): void;
/**
 * The session plane's view: five facts bound to one session.
 *
 * The one constructor every tier uses — builtins, the command
 * dispatcher, a bare unit test — so the gate cannot be skipped by
 * picking a different entry point. The view is the whole capability: it
 * carries no handle back to the raw session.
 */
/**
 * Write a variable without consulting the gate.
 *
 * For seeding a session before it is handed out -- the embedder
 * populating an environment, a test arranging state. `visibleArrays`
 * already names this case ("the embedder can seed session.arrays before
 * narrowing"). Anything reached from a command line goes through
 * `SessionView.set` instead, which is the whole point of the store being
 * read-only from outside.
 */
export declare function seedVar(session: SessionState, name: string, value: ShellValue): void;
/**
 * Turn one attribute on or off, creating the name if needed.
 *
 * bash's `readonly NAME` / `export NAME` on a name that does not exist
 * yet marks it anyway, and the name stays *unset*: GNU prints
 * `declare -r ONLY` with no value and `${ONLY-d}` still expands to `d`.
 * So the record is created with no value, not with an empty string.
 *
 * A null attribute changes no attribute and only ensures the name
 * exists, which is what a bare `local L` / `declare D` does: GNU answers
 * `declare -- L` and `${L-d}` still expands to `d`, so those two cannot
 * route through a value writer either.
 */
export declare function setAttr(session: SessionState, name: string, attr: VarAttr | null, on?: boolean): void;
export declare function sessionView(session: SessionState, policies?: Policies | null, diagnostics?: (string | Uint8Array)[]): SessionView;
export declare const SHELL_BOOKKEEPING: ReadonlySet<string>;
/**
 * The value a `preSession` method is shown for one variable: a scalar as
 * itself, an indexed array as its present elements joined by spaces, an
 * associative one in sorted-key order, and null for a variable that is
 * declared but unset. One rendering, so a rule reads the same text whether
 * the write came from a typed line or a restore. Mirrors Python
 * `gate_rendering`.
 */
export declare function gateRendering(value: ShellValue | null): string | null;
/**
 * Vet a variable table a snapshot restores through the session gate.
 *
 * A snapshot is the one env input the deployment did not author, so the
 * `preSession` rule that refuses a name on a typed line has to see the
 * restore too. Every restored variable fires the gate as a `set` of its
 * rendered value before any of them lands, and a refusal aborts the load
 * with the `PolicyDenied` a live `export` of that name reports, rather
 * than dropping the one variable: a partial restore is a workspace whose
 * state matches no snapshot. The shell's own bookkeeping
 * (`SHELL_BOOKKEEPING`) is exempt here as it is live. Null policies gate
 * nothing. Mirrors Python `gate_restored_vars`.
 */
export declare function gateRestoredVars(policies: Policies | null, sessionId: string, table: Record<string, ShellVar>): Promise<void>;
//# sourceMappingURL=state.d.ts.map