UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

148 lines • 7.64 kB
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