@struktoai/mirage-core
Version:
A Unified Virtual Filesystem For AI Agents
139 lines • 7.44 kB
TypeScript
import { CommandSpec } from '../../../commands/spec/types.ts';
import { PathSpec, type Limit } from '../../../types.ts';
import type { ProcessView } from '../../../process/view.ts';
import type { CLI, CLIHandler } from '../../../commands/cli/types.ts';
import type { CommandFnResult, Context } from '../../../commands/config.ts';
import { type ShellFn } from '../../../runtime/types.ts';
import type { FollowOperands, SessionView } from '../../../view/types.ts';
import type { Files } from '../../files.ts';
import { type FlagValue } from '../../../commands/spec/types.ts';
import { IOResult, type ByteSource } from '../../../io/types.ts';
import type { CLIInstall } from '../../cli/types.ts';
import type { MountEntry } from '../../mount/mount.ts';
import type { SessionState } from '../../session/session.ts';
import { ExecutionNode } from '../../types.ts';
import type { RouteDecision } from '../../../runtime/types.ts';
import type { Runtime } from '../../../runtime/base.ts';
import type { IdSource } from '../../../utils/ids.ts';
/**
* Workspace facts the dispatcher can offer but most CLIs do not want: an API
* client needs no filesystem, while `git` is nothing but one. Forwarded whole
* onto the leaf's opts bag, so a leaf that does not read them ignores them and
* there is no allowlist of filesystem-aware CLIs to keep in step (the same rule
* `links` follows for mount commands).
*/
export interface CLIContext {
shell?: ShellFn;
signal?: AbortSignal;
commandLimits?: Readonly<Record<string, Limit>>;
/**
* The workspace's ordered runtime world, which a script leaf selects
* its interpreter from; absent (outside a workspace) refuses script
* installs.
*/
entries?: readonly Runtime[];
/**
* The session's files, run as the line's session with the command's gate,
* for a CLI whose subject is files rather than an API.
*/
vfs?: Files;
session?: SessionView;
processes?: ProcessView;
/** The line's placement, which a script leaf runs its program under. */
routing?: RouteDecision<Runtime>;
/**
* Lands what a script leaf's runtime holds and drops the caches its
* program may have gone past; absent outside a workspace.
*/
settle?: (runtime: Runtime) => Promise<void>;
/** The workspace's source, which the leaf's `ctx.ids` draws from. */
ids?: IdSource;
}
/**
* Whether this CLI reaches a service past the dispatcher.
*
* Its write verbs then go past the dispatcher's per-path invalidation, so the
* mounts its client may reach drop their caches after one
* (`MountRegistry.dropCaches`). Two roots do that: one with a `configModel`
* (an account CLI, initialized from it) and a script root, whose config is
* opaque by construction and whose program may reach anything. A root with
* neither (`git`) has no service to reach; its writes go through the
* dispatcher, which invalidates as it goes, so a blanket drop would only cost
* every other mount a reload. Mirrors Python's `reaches_service`.
*/
export declare function reachesService(spec: CLI): boolean;
/**
* Execute a line whose head word is an installed CLI.
*
* Dispatch is by NAME: the install resolves the program tree and the
* validated config; no mount is consulted and no operand path picks a
* backend (the one executor divergence from mount commands). The walk
* consumes subcommand words and group options; the leaf's own argv
* uses the shared CommandSpec parser. The leaf gets the line's one Context,
* built here and nowhere else: an fn leaf runs as
* `fn(accessor, paths, texts, ctx)`, a script
* leaf runs its embedded program on a workspace runtime
* (scriptOutput), so usage refusals, limits, and classification all
* happen in front of either tier. Help too, for every node that declared
* a grammar to render it from (parseSpecFor). The workspace facts in
* `context` reach a verb on its `ctx`, so a verb that never reads `ctx.vfs`
* cannot touch a mount.
*/
export declare function handleCli(install: CLIInstall, parts: readonly (string | PathSpec)[], session: SessionState, stdin?: ByteSource | null, context?: CLIContext, dropCaches?: (() => Promise<void>) | null): Promise<[ByteSource | null, IOResult, ExecutionNode]>;
/**
* A line a command tree's walk resolved to one leaf, parsed and ready to
* run. Mirrors Python's `LeafCall`.
*/
export interface LeafCall {
/** The line's words as typed, for the record. */
cmdStr: string;
/** The words after the head as typed. */
argv: readonly string[];
/** The head and the verb path, the name a message, a limit and the output guards read. */
prog: string;
/** The canonical verb path below the head. */
path: readonly string[];
leaf: CommandSpec;
handler: CLIHandler;
/** The group and leaf flags, one bag. */
flags: Record<string, FlagValue>;
paths: PathSpec[];
texts: string[];
/** What the parse warned about, said ahead of the leaf's own stderr. */
warnings: readonly string[];
}
/**
* Walk a line down a command tree to the leaf it names and parse the
* leaf's words, or answer the line without running anything.
*
* The walk consumes subcommand words and group options; the leaf's own argv
* uses the shared CommandSpec parser. Help, usage refusals and an operand
* base that is no directory are answered here, for an installed CLI and a
* tree a mount serves alike. Mirrors Python's `walk_leaf`.
*/
export declare function walkLeaf(name: string, cli: CLI, parts: readonly (string | PathSpec)[], session: SessionState, vfs: Files | undefined): Promise<LeafCall | [ByteSource | null, IOResult, ExecutionNode]>;
/**
* Execute a line whose head word names a command tree a mount serves.
*
* The tree a VFS was handed (or one registered on its mount) is walked
* exactly as an installed CLI's is (`walkLeaf`: verbs, help, usage
* refusals, the leaf's parse); the leaf then runs on the mount, on its
* accessor and under its refusals (`MountEntry.runLeaf`), with its own
* limit: the profile's, then the mount's and the workspace's entry for the
* verb path, then the leaf's declared one. A tree runs on the mount serving
* its name, never by operand path, and its leaf keys that mount's accessor by
* each operand: the operands the leaf parse resolved are followed through the
* link table as the router follows a mount command's (`follow`), and one
* another mount holds (`owner`) is refused before the leaf runs. Mirrors
* Python's `handle_mount_cli`.
*/
export declare function handleMountCli(mount: MountEntry, cli: CLI, parts: readonly (string | PathSpec)[], session: SessionState, stdin?: ByteSource | null, context?: CLIContext, owner?: (path: string) => MountEntry | null, follow?: FollowOperands, prepared?: LeafCall): Promise<[ByteSource | null, IOResult, ExecutionNode]>;
/**
* Run a walked leaf with the one Context a leaf gets, and record it.
*
* The leaf's declared limit caps its output, exactly like mount dispatch.
* A failure the runner framed is recorded as it is; an answer gets the
* parse's warnings ahead of its stderr. Mirrors Python's `run_walked`.
*/
export declare function runWalked(walked: LeafCall, session: SessionState, stdin: ByteSource | null, context: CLIContext, limit: Limit | null, run: (ctx: Context) => Promise<CommandFnResult>): Promise<[ByteSource | null, IOResult, ExecutionNode]>;
//# sourceMappingURL=cli.d.ts.map