UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

94 lines • 4.3 kB
import type { Accessor } from '../../accessor/base.ts'; import type { CLI } from '../../commands/cli/types.ts'; import { type Clock } from '../../utils/clock.ts'; import type { CLIInstall } from './types.ts'; /** * Installed CLIs, keyed by head word. * * Fully separate from the mount registry: a CLI exists because it was * installed (YAML `clis:` section or registerCli), never because * storage was mounted. Install is fail-loud: a bad name, a colliding * name, or a config the spec's configModel rejects throws at install * time, so a workspace that loads has only valid entries. * * The lifecycle is host-side only, and must stay that way: install and * uninstall are called by the program embedding mirage, never by a line * the agent types, so an agent cannot take away the tools it was given. * Do not add an `install`/`uninstall` shell builtin. What an agent can * do is shadow a head word with a shell function, which is bash's own * rule, reversible with `unset -f`, bypassable with `command <name>`, * and visible through `type -a`. Pinning a head word against that * belongs in the policy layer's `preCommand`, since it is a * per-deployment call rather than a property of the registry. */ export declare class CLIRegistry { private readonly peers; private readonly clock; private readonly installs; private readonly retiring; private shutdown; private clocksBound; /** * @param peers the mounts' accessors, which an install may share an account with. * @param clock the workspace's clock, which each install's accessor reads * time and waits on. */ constructor(peers?: () => readonly Accessor[], clock?: Clock); /** * Refuse a head word no CLI may be installed under: not a single word, * or one that collides with a shell builtin, a keyword or a general * command. Mirrors Python's `CLIRegistry.check_name`. */ checkName(name: string): void; /** * Install a CLI under a head word. The name must be a single word and * must not collide with another installed CLI, a shell builtin, or a * general command (a runtime capture of the same name is fine: the * policy steers per line). */ install(name: string, spec: CLI, config?: Record<string, unknown> | null): CLIInstall; private validateConfig; /** * Hand every install's accessor the workspace clock, once the workspace is * built; an install made later takes it at once. Each install holds on its * own, so removing one leaves another that shares its client holding. * Mirrors Python's `CLIRegistry.bind_clocks`. * * @throws Error when another workspace holds a client on another clock; * nothing stays bound. */ bindClocks(): void; /** * Let go of the workspace clock on every install's accessor, as the * workspace closes or fails to come to be. Mirrors Python's * `CLIRegistry.release_clocks`. */ releaseClocks(): void; /** * Remove an installed CLI now and close its accessor once the lines running * on it and their output streams are done; its head word stops resolving * (127) at once. */ uninstall(name: string): Promise<void>; /** * Close every install's accessor, including the ones still being removed, * as the workspace closes; one failed close does not skip the rest. * * The workspace aborts its lines before this runs, so a leaf still on an * install is unwinding (or ignoring its abort): it gets `ABORT_JOIN_MS` to * settle before its accessor goes, rather than meeting a closed client * mid-request, and no longer, so one that never settles cannot hold the * workspace open. Each close is tracked, as a removal is, so a second close * waits for the clients the first is still closing. */ close(): Promise<void>; /** Keep `closing` in `retiring` until it settles, so `close` waits for it. */ private track; /** Look up an installation by head word. */ get(name: string): CLIInstall | null; /** Snapshot of the installed CLIs keyed by head word. */ items(): Map<string, CLIInstall>; /** The installed head words. */ names(): ReadonlySet<string>; } //# sourceMappingURL=registry.d.ts.map