@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
127 lines • 6.1 kB
TypeScript
import type { Context } from '../commands/config.ts';
import type { PathSpec } from '../types.ts';
import { type WorkspaceBinding } from './binding.ts';
import { type RuntimeConfig, type RuntimeOptions } from './config.ts';
import type { ExecutionKind, FilesystemOperation, OutputFn, RunResult, RuntimeReach } from './types.ts';
/**
* An engine the workspace can route commands or whole lines to.
*
* A runtime is to its commands what the regex engine is to grep: the
* machinery inside a handler, invisible to the dispatcher. Each runtime
* declares the command names it captures; a command binds to the first
* runtime in the workspace's ordered list that captures it. Its hooks take
* what a handler takes, `(engine, paths, texts, ctx)`: the engine (`E`) is
* built once by `openEngine`; a runtime with none declares
* `Runtime<undefined>`.
*
* The base holds only what every tier shares: the registry name, the
* captured command names, the coerced config and the engine. What a
* runtime can DO is declared by its tier and mixins, detected by type and
* never by probing: LanguageRuntime interprets code in its language
* (run), LineExecutorMixin takes whole lines (runLine), ProcessExecutorMixin runs
* an argv (runProcess).
*
* Every runtime is constructed the same way (captures, config); each
* subclass hands the base its class-default captures and its config key
* list, so a config field the runtime does not have fails loud
* (config_cls in Python).
*/
export declare abstract class Runtime<E = unknown> {
abstract readonly name: string;
readonly captures: readonly string[];
/**
* Which entry points this runtime's code has to the outside world (see
* RuntimeReach): 'workspace' when the workspace dispatch is its only one,
* as the bridged engines (monty, pyodide, quickjs) and the workspace
* routing marker declare, 'process' or 'remote' when the code can
* act around that gate. The default is 'process', the no-promise
* claim, so a custom runtime must declare a narrower reach
* explicitly rather than inherit it. Embedders read the aggregate:
* only a world in which every runtime reaches 'workspace' makes "agent
* code cannot bypass mount modes and policy" a true statement,
* which is what the dsh adapter's sandbox claim is built from; one
* wider runtime voids it.
*/
readonly reach: RuntimeReach;
readonly filesystem: readonly FilesystemOperation[];
/** The runtime's coerced implementation knobs. */
config: RuntimeConfig;
protected binding: WorkspaceBinding | null;
private readonly activity;
private retired;
private opening;
private closing;
constructor(options?: RuntimeOptions<RuntimeConfig>, defaultCaptures?: readonly string[], configKeys?: readonly string[]);
/** Whether workspace file mutations already invalidate through dispatch. */
get fileEffectsDispatched(): boolean;
/**
* Land the file writes this runtime still holds for a line. The executor
* calls it when a line ends, however it ended, so the line's writes are
* in the workspace by the time it returns. Holds none by default; a
* sandbox serving the workspace over SFTP lands what its servers hold.
*/
settle(): Promise<void>;
/** Attach workspace services; a runtime instance belongs to one workspace. */
bind(binding: WorkspaceBinding): void;
/**
* Run once, as the session the bound workspace captures. The capture
* supplies the files (`ctx.vfs`, judged as the program's own calls) and
* the session; the caller's `ctx` the rest.
*
* @param paths the path operands (a script).
* @param texts the text operands (argv; a process's program first).
* @param ctx the run's context.
* @param opts `kind`: code in the runtime's language (the default), a
* whole line (`sh -c` with `ctx.flags.c`), or a process; `output`:
* where the run writes its output as it comes, absent to collect it in
* the result; `errors`: the same for its stderr.
*/
execute(paths: readonly PathSpec[], texts: readonly string[], ctx: Context, opts?: {
kind?: ExecutionKind;
output?: OutputFn;
errors?: OutputFn;
}): Promise<RunResult>;
/** Hand the run to the capability its kind asks for. */
private runAs;
/**
* Run code in this runtime's language; only a language runtime has one.
*
* @param _engine the install's engine.
* @param _paths the script operand, if any.
* @param _texts the program's argv.
* @param _ctx the run's context.
* @param _output receives stdout as it comes; undefined returns it in
* the result.
* @param _errors the same for stderr.
*/
run(_engine: E, _paths: PathSpec[], _texts: string[], _ctx: Context, _output?: OutputFn, _errors?: OutputFn): Promise<RunResult>;
/** Build the engine every run reuses, once; the default is none. */
protected openEngine(): Promise<E>;
/**
* Release what `openEngine` built.
*
* @param _engine the engine.
*/
protected closeEngine(_engine: E): Promise<void>;
/** The engine, opened once and shared; a failed open is retried. */
engine(): Promise<E>;
/**
* Whether every restricted mount is served through this caller's gate.
*
* @param _restrictedMounts the mounts the session restricts.
*/
protected servesSession(_restrictedMounts: readonly string[]): boolean;
/** Count one unit of work, refused once the runtime is retired. */
admit(): () => void;
/** Refuse new executions and binds, then wait for running ones. */
retire(): Promise<void>;
/**
* Close the engine, when one was opened. A close that comes while another
* runs waits for that one rather than finding nothing left to close.
*/
close(): Promise<void>;
private dropEngine;
}
/** A workspace runtimes-list entry: an instance or a name shorthand. */
export type RuntimeEntry = Runtime | string;
//# sourceMappingURL=base.d.ts.map