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