@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
148 lines • 7.64 kB
TypeScript
import { LostPaths, OpRecord, RecordIndex, type Recorder, type RevisionsState } from './record.ts';
import type { PathSpec } from '../types.ts';
import { type Clock } from '../utils/clock.ts';
declare module '../context/session_context.ts' {
interface Caller {
readonly recording: Recorder | null;
readonly revisions: RevisionsState | null;
}
}
/**
* Collect the records the running command itself emits.
*
* `fn` gets a fresh list that {@link record} and {@link recordStream}
* append to, beside the line's records, while it runs. A nested call opens
* its own list, and where async context isolates tasks (node) a concurrent
* task keeps its own, so a pipeline stage never sees a sibling stage's
* records; the browser's shared frame stack cannot promise that (see
* `asyncContextIsolatesTasks`). Nothing is collected outside a recording
* scope. Each record also reaches the list of the nearest call made with
* `own`: a command's, which the dispatcher calls under it add to too, and
* which takes nothing for the call around it, so a command reading
* another's output is not charged with that command's reads. Mirrors
* python's `command_records`.
*/
export declare function commandRecords<T>(fn: (records: OpRecord[]) => Promise<T>, own?: boolean): Promise<T>;
/**
* The version the running line itself names for `key`, with whether the line
* knows `key` at all. A lost path names the version its write lost on;
* otherwise the newest version record does, a stamp its token and a
* retraction none. Mirrors Python's `line_version`.
*/
export declare function lineVersion(index: RecordIndex, lost: LostPaths | null, key: string): [boolean, string | null];
/** The version index of the line whose records these are; one per line. */
export declare function recordIndex(records: readonly OpRecord[]): RecordIndex;
/** The lost paths of the line whose records these are, null outside a line. */
export declare function lostPaths(records: readonly OpRecord[] | undefined): LostPaths | null;
/** Mark `key` lost on the running line, if one is recording. */
export declare function markLost(path: PathSpec, version?: string | null): void;
/** The running line's marks so far, for a later `liftLost`. Mirrors Python's `lost_count`. */
export declare function lostCount(): number;
/** Lift the running line's marks a removal or move of `key` ended. Mirrors Python's `lift_lost`. */
export declare function liftLost(path: PathSpec, upto: number, subtree?: boolean): void;
export declare function activeRecords(): readonly OpRecord[] | undefined;
/**
* Run `fn` recording its calls, and answer what it returned with what it
* recorded. `ledger` is the workspace ledger a line hands its records to,
* which a file call of that workspace made on the line joins; `clock` is
* the workspace clock its ops are timed and stamped on.
*/
export declare function runWithRecording<T>(fn: () => Promise<T>, ledger?: OpRecord[] | null, clock?: Clock): Promise<[T, OpRecord[]]>;
/**
* Run `fn` with `mountId` as the mount its records belong to.
*
* Derives a state for this async branch and shares only the records array,
* so two mounts consumed concurrently (`cat /s3/a & cat /db/b`) cannot see
* or clobber each other's mount. Mirrors python's `push_mount_context`,
* whose `Recorder` is frozen and re-set per task for the same reason.
* An undefined `mountId` inherits the enclosing frame's.
*
* Inert (runs `fn` unchanged) when no recording context is active.
*/
export declare function runWithMountContext<T>(fn: () => Promise<T>, mountId?: string | null): Promise<T>;
/**
* Wrap a stream so `mountId` is the active mount during each pull from the
* underlying source. A command may return a stream that defers its backend
* read to the first chunk request, by which point the mount's own scope has
* already exited, so without this the record lands under whatever frame
* drains it. An iterator rather than a generator: a generator queues `return`
* behind a pull waiting for the next chunk, so the close of an idle follow
* would never reach the source whose own close ends that wait. Mirrors
* python's `with_mount_context`.
*/
export declare function withMountContext(it: AsyncIterable<Uint8Array>, mountId?: string | null): AsyncIterableIterator<Uint8Array>;
export declare function recordingActive(): boolean;
export interface RecordOptions {
fingerprint?: string | null;
revision?: string | null;
}
/**
* A running stopwatch for one op, owned by the record path.
*
* Opened where the backend work begins and read once when the op
* finishes, so an op module hands this around instead of reading a
* clock of its own. The wall-clock stamp the record carries is taken at
* finish time, not here, on the same clock. Mirrors python's `OpTimer`.
*/
export declare class OpTimer {
readonly clock: Clock;
private readonly startMs;
constructor(clock: Clock);
/** Milliseconds elapsed since the timer was opened. */
get elapsedMs(): number;
}
/**
* Open the record path's stopwatch for one op. Hand the timer to
* {@link record} or {@link finishRecord} when the op completes. The timer
* runs on the clock of the line recording the op; outside a recording
* nothing keeps the record, and the system clock times it.
*/
export declare function startOp(): OpTimer;
/**
* Close `timer` and build the finished record.
*
* The one place an op's duration and wall-clock stamp are read, both on the
* timer's clock, shared
* by the recorder sink ({@link record}) and by the `Files` facade's own
* ledger, so the two cannot disagree about what a duration measures.
* `path` is stored as given.
*/
export declare function finishRecord(op: string, path: string, source: string, nbytes: number, timer: OpTimer, options?: RecordOptions): OpRecord;
/**
* Append a finished record to the active recording, if any.
*
* `path`: the full virtual path.
*/
export declare function record(op: string, path: string, source: string, nbytes: number, timer: OpTimer, options?: RecordOptions): void;
/**
* Append a streaming record whose bytes are filled in as it drains.
* Set `complete` after normal exhaustion, never after failure or early close.
*
* `path`: the full virtual path.
*/
export declare function recordStream(op: string, path: string, source: string, options?: RecordOptions): OpRecord | null;
/**
* Run `fn` inside a revisions context. Backend read functions inside
* `fn` (or any async chain it starts) can consult {@link revisionFor}
* to look up a pin. Independent of {@link runWithRecording} so that
* direct {@link Workspace.dispatch} calls (which don't open a recording
* scope) still honour installed pins.
*
* Task-isolated via AsyncLocalStorage: concurrent runs on different
* mounts each see their own pin map.
*/
export declare function runWithRevisions<T>(revisions: Map<string, string> | null, fn: () => Promise<T>): Promise<T>;
/**
* Look up the active revision pin for `path`, or null if no pin is
* installed (or no revisions context is active).
*
* Every live frame's map is searched, because pins are mount state
* threaded through the context only for reach: each bind hands over
* the mount's own map, keyed by full virtual path, so a hit is never
* another task's different pin — the same mount binds the same map,
* and another mount's map cannot hold this path. On the fallback
* storage this is what keeps a pinned read pinned while an unpinned
* op's frame shadows the newest slot.
*/
export declare function revisionFor(path: string): string | null;
//# sourceMappingURL=context.d.ts.map