import { AcpMcpServer, StreamEvent, AcpPermissionResolution } from '@agentproto/acp';
import { SessionConfigOption, SessionMode } from '@agentproto/acp/client';
import { SandboxMode } from '@agentproto/command-sandbox';
import { z } from 'zod';

/**
 * AIP-45 AgentCliDefinition + AgentCliHandle.
 *
 * Mirrors `resources/aip-45/draft/AGENT-CLI.schema.json`. Top-level
 * fields cover the binary's install / version / auth / sandbox /
 * protocol surface; `protocol` discriminates between ACP, MCP, and
 * proprietary adapter arms.
 */

/** Outcome of a steer attempt — mirrors `@agentproto/acp/client`'s
 *  `SteerOutcome`: `"steered"` (injected into the running turn),
 *  `"promptRequired"` (no host turn in flight — deliver as a prompt),
 *  `"unsupported"` (the agent can't / refused to steer). */
type SteerOutcome = "steered" | "promptRequired" | "unsupported";

type AgentCliProtocol = "acp" | "mcp" | "proprietary" | "print";
type AgentCliSessionMode = "ephemeral" | "persistent" | "resumable";
interface AgentCliInstallMethod {
    method: "brew" | "apt" | "dnf" | "pacman" | "choco" | "scoop" | "npm" | "pip" | "cargo" | "go" | "curl" | "download" | "vendored";
    package?: string;
    url?: string;
    path?: string;
    extract_bin?: string;
    verify_sha256?: string;
    global?: boolean;
    user?: boolean;
    experimental?: boolean;
}
interface AgentCliVersionCheck {
    cmd: string;
    parse: string;
    range: string;
    timeout_ms?: number;
}
interface AgentCliAuth {
    ref?: string;
    state?: {
        paths?: string[];
        env?: string[];
    };
    login?: {
        cmd: string;
        interactive?: boolean;
        requires_callback_url?: boolean;
    };
    refresh?: {
        cmd: string;
        interval_s?: number;
    };
    expiry?: {
        parse?: string;
        grace_s?: number;
    };
}
/**
 * The `subscription` (OAuth / bearer) billing mode declaration — the ONE
 * axis of the billing-auth resolver that isn't a shared provider fact, so it
 * lives on the adapter manifest rather than in the model catalog. Its env var
 * is consumer-specific (claude CLI wrapper → `CLAUDE_CODE_OAUTH_TOKEN`;
 * claude-sdk → `ANTHROPIC_AUTH_TOKEN`). Presence of this field is what tells
 * the runtime "this adapter supports `subscription` mode"; an adapter without
 * it that's asked for `subscription` fails with `unsupported_auth_mode`.
 *
 * The api-key axis needs NO such declaration — its env var derives from the
 * catalog's `PROVIDER_KEY_ENV` via `providerEnvVar(provider)`; only the
 * runtime resolver reads it, never this manifest.
 */
interface AgentCliAuthSubscription {
    /** Env var SET to the resolved subscription credential (the OAuth/bearer
     *  token). Omitted for an {@link external} (file-based) subscription — that
     *  form injects NOTHING, so there is no var to set. */
    setEnv?: string;
    /**
     * File-based subscription: the CLI reads its OWN local-login file
     * (`~/.codex/auth.json`, `~/.gemini/oauth_creds.json`, …) rather than a
     * bearer the runtime injects. When true, the runtime SETS no credential env
     * var (there is none) — it only SCRUBS the conflicting api-key vars
     * ({@link conflictEnv} + the provider's api-key var) so a leftover key can't
     * silently flip the CLI to api-key billing, and the host verifies the login
     * is present (fail-loud) before the spawn. Money-safe by construction: an
     * OAuth bearer is NEVER injected into an api-key channel because no bearer is
     * injected at all. Mutually exclusive with {@link setEnv}.
     */
    external?: boolean;
    /**
     * Sibling billing-credential env vars the SAME consumer also honors and
     * that must therefore be scrubbed in EVERY resolved mode except when the
     * var IS the one being set — a leftover of one of these would silently
     * override the credential this spawn stated (the org-credit-leak class).
     * For anthropic: the generic bearer `ANTHROPIC_AUTH_TOKEN`, which the
     * claude binary honors above `ANTHROPIC_API_KEY`. Distinct from
     * {@link unsetEnvAdd} (which is native-mode-only gateway hygiene, not a
     * credential).
     */
    conflictEnv?: string[];
    /**
     * Extra env vars scrubbed ONLY in `subscription` (native) mode — gateway
     * hygiene, not credentials: cloud-provider redirect toggles
     * (`CLAUDE_CODE_USE_BEDROCK`/`_VERTEX`/…) + `ANTHROPIC_BASE_URL`, any of
     * which would reroute or 401 a natively-billed spawn. Left present in
     * api-key mode (a deliberate api-key + Bedrock combination is valid there),
     * which is why this is separate from {@link conflictEnv}.
     */
    unsetEnvAdd?: string[];
    /**
     * Scope this subscription surface to ONE billing provider — for a
     * multi-provider (`modelDerivedApiKey`) adapter whose bearer door is
     * provider-specific: pi reads `ANTHROPIC_OAUTH_TOKEN` as its documented
     * alternative to `ANTHROPIC_API_KEY`, an anthropic-only path that means
     * nothing for its openai/google/moonshot models. When set, the runtime
     * only treats subscription mode as supported (and only advertises
     * oauth-bearer eligibility) when the spawn's RESOLVED provider equals
     * this id — so an anthropic subscription profile lights up pi's
     * anthropic models without making, say, a codex OAuth profile look
     * eligible for pi's openai models. Omit for a fixed-provider adapter
     * (claude-code, codex): the descriptor-level `provider` already pins it.
     */
    provider?: string;
}
/**
 * Re-runnable health check that, when matching, skips the enclosing
 * setup step. Lets `agentproto setup <slug>` re-runs be idempotent
 * without storing extra completion-ledger state — when the cmd's
 * exit code matches `exit_code` (default 0), the step is treated as
 * already satisfied and the host moves on.
 */
interface AgentCliSetupSkipIf {
    cmd: string;
    exit_code?: number;
    timeout_ms?: number;
}
/**
 * Where a setup step's captured value lands so the runner can reuse
 * it on every spawn. Exactly one of the three forms — env / secret /
 * cmd — applies.
 */
type AgentCliSetupPersist = {
    /** Env var the runner injects on every spawn (lifted from the
     *  workspace secrets store, never logged). */
    env: string;
    secret_slug?: never;
    cmd?: never;
} | {
    env?: never;
    /** AIP-19 secret slug to write the value into. */
    secret_slug: string;
    cmd?: never;
} | {
    env?: never;
    secret_slug?: never;
    /** Run this command with `${value}` substituted by the captured
     *  value. Use for CLIs that expect their own config command
     *  (e.g. `openclaw config set gateway.remote.token ${value}`). */
    cmd: string;
};
/**
 * AIP-29 § Setup — one step in the post-install configuration
 * pipeline. Discriminated by `kind`; the host runs steps in declared
 * order and persists completion per (bundle.id, workspace.id, user.id).
 */
type AgentCliSetupStep = {
    id: string;
    kind: "cmd";
    cmd: string;
    description?: string;
    skip_if?: AgentCliSetupSkipIf;
    timeout_ms?: number;
    interactive?: boolean;
    persist?: AgentCliSetupPersist;
} | {
    id: string;
    kind: "prompt";
    prompt: string;
    description?: string;
    type?: "text" | "select" | "boolean" | "secret";
    default?: string;
    options?: string[] | {
        cmd: string;
        timeout_ms?: number;
    };
    skip_if?: AgentCliSetupSkipIf;
    persist?: AgentCliSetupPersist;
} | {
    id: string;
    kind: "oauth";
    secret_slug: string;
    description?: string;
    skip_if?: AgentCliSetupSkipIf;
} | {
    id: string;
    kind: "external";
    url: string;
    description?: string;
    callback?: {
        param?: string;
        timeout_ms?: number;
    };
    skip_if?: AgentCliSetupSkipIf;
    persist?: AgentCliSetupPersist;
};
interface AgentCliSession {
    mode?: AgentCliSessionMode;
    idle_timeout_ms?: number;
    /**
     * Per-turn silence watchdog (ms) — distinct from `idle_timeout_ms`,
     * which bounds time BETWEEN turns. This bounds true silence DURING a
     * single turn: if the adapter goes this long with no activity signal
     * and its `prompt` call still hasn't resolved, the ACP client
     * synthesizes a `turn-end` with `reason: "watchdog-timeout"` instead
     * of hanging forever (see `@agentproto/acp/client`'s
     * `AcpClientOptions.turnIdleTimeoutMs`). Undefined (the default)
     * disables the watchdog — set this only for adapters known to
     * sometimes drop the final `prompt` response (e.g. hermes).
     */
    turn_idle_timeout_ms?: number;
    max_turns?: number;
    context_carryover?: boolean;
}
/**
 * A `models.allowed` entry that states who serves/bills a model and how
 * this adapter reaches it — the structured alternative to a bare id
 * string. `provider` is *who* (a `ProviderPreset` id, or a direct
 * provider like "anthropic"); `mode` is *how this adapter* gets there
 * (its own `modes[].id`), which is NOT redundant with `provider`: an
 * adapter that routes by id prefix (opencode) needs no mode at all,
 * while one that needs `ANTHROPIC_BASE_URL` pre-wired (claude-sdk,
 * claude-code) does. Omit `mode` when the adapter routes on its own.
 */
interface AgentCliModelEntry {
    /** Model id, unchanged on the wire — this annotates, never renames. */
    id: string;
    /** Who serves/bills this model. Omit when unstated — an unstated
     *  provider must never be guessed downstream (a wrong-but-confident
     *  guess would bill the wrong account). */
    provider?: string;
    /** This adapter's mode id that routes to `provider`. Omit when the
     *  adapter routes on its own or the model needs no mode switch. */
    mode?: string;
}
interface AgentCliModels {
    default?: string;
    /**
     * Model ids the host MAY route to. A bare string keeps meaning exactly
     * what it means today (provider unstated, adapter default) — additive,
     * so no existing manifest breaks. A structured entry additionally
     * states `provider`/`mode` (see {@link AgentCliModelEntry}).
     */
    allowed?: Array<string | AgentCliModelEntry>;
    /**
     * Model-id patterns this adapter must NEVER route to, even when a caller
     * passes the id explicitly (the `model` option is free-form, so `allowed`
     * is only a curated menu and can't *prevent* an off-menu id). Each pattern
     * matches case-insensitively against the requested model id and supports a
     * single trailing `*` wildcard (prefix match); otherwise exact. A match is
     * refused at compose time (`RuntimeConfigError`, code `model_denied`).
     * Use to reserve a premium provider for a dedicated adapter — e.g. hermes
     * denies `["anthropic/*", "claude-*"]` so Anthropic models stay exclusive
     * to the claude-code adapter.
     */
    deny?: string[];
    env?: Record<string, string>;
    /**
     * How the host selects a model at session start:
     *   - "config"  (default) — apply via ACP `session/set_config_option`
     *     with `configId:"model"` right after `newSession`. Works for ACP
     *     wrappers that expose model as a session config (e.g. claude-code).
     *   - "command" — `set_config_option` is a no-op / silently rejected on
     *     this agent (e.g. hermes), so instead send a `/model <id>` control
     *     turn after `newSession` and drain it. The agent's reply is checked
     *     for a "switched" acknowledgement; a failure is warned, not fatal —
     *     EXCEPT for a `routeSelection:"derived-from-model"` adapter, where
     *     an unacknowledged switch refuses the spawn (the model id is the
     *     route and the bill; see the derived-from-model guard in
     *     `define-agent-cli.ts`, same contract as the "config" path).
     *   - "arg" — this CLI takes its model as a CLI argument, not an ACP
     *     session config or control turn.
     *     The requested model is composed into `bin_args` at spawn time via
     *     `bin_args_template` (below) — no post-`newSession` ACP call is
     *     made at all.
     * Omit → "config".
     */
    apply?: "config" | "command" | "arg";
    /**
     * Argv template composed into `bin_args` at spawn time when
     * `apply === "arg"` and a model was requested. The literal token
     * `{model}` is replaced with the requested model id, one-for-one per
     * array element (mirrors `AgentCliOption.bin_args_template`'s
     * `{value}` token). Appended after the manifest's default `bin_args`,
     * same position as an option's own `bin_args_template`. Required when
     * `apply === "arg"`; ignored otherwise.
     */
    bin_args_template?: string[];
}
interface AgentCliCapabilities {
    streaming?: boolean;
    tool_calls?: boolean;
    sub_agents?: boolean;
    file_io?: boolean;
    multimodal?: boolean;
    resumable?: boolean;
    bidirectional?: boolean;
    /**
     * Adapter can ingest a filesystem path that the host UI just placed
     * on disk (host-side drag-drop into a terminal pastes the path
     * here). Implies the adapter has a Read-file tool wired. Hosts gate
     * drag-drop UI on this flag — defaults to false (conservative).
     * Paired with the daemon's POST /files/upload route.
     */
    file_attach?: boolean;
    /**
     * The adapter has a verified native CLI resume path into a real
     * terminal / TUI session (e.g. `claude --resume <id>` or
     * `hermes --resume <id> --tui`). When true, the daemon MAY offer
     * provider-native terminal restart for this adapter. ACP-level
     * resumability (`resumable`) alone does NOT imply this — a JSON-RPC
     * session id is not a native TUI resume. Default false.
     */
    nativeTerminalResume?: boolean;
}
/**
 * Support status for a declared mode. Absent ⇒ treated as `"active"`.
 *   active  — the mode does what its description claims.
 *   noop    — declared and accepted, but measured to have no effect
 *             (argv/env compose fine, but the observable outcome is
 *             identical to not passing it). Kept declared for honesty
 *             and so a future fix can flip it back to `active`.
 *   planned — declared as an intended surface but not wired yet.
 */
type AgentCliModeStatus = "active" | "noop" | "planned";
/**
 * AIP-45 mode declaration — a mutually-exclusive operation profile
 * the CLI exposes. The host picks at most ONE mode per turn via
 * `OPERATOR.runtime.config.mode`. Mode patches apply AFTER the
 * manifest's default `bin_args` and BEFORE option patches.
 */
interface AgentCliMode {
    id: string;
    description?: string;
    /**
     * Which orthogonal session-config axis (SPEC-tracked in
     * `@agentproto/runtime`'s `session-config.ts`) this mode expresses. Narrowed
     * to the single value `"context"` (what enters context — e.g. claude-code's
     * `lean` env toggle), the only concern with no ACP-protocol home (SPEC §3.4a).
     *
     * Route and posture are NO LONGER manifest modes: `"route"` (endpoint/billing
     * rail) is derived from the model catalog (`@route` route-identity), and
     * `"posture"` (what the agent may DO — plan/accept-edits/bypass/read-only)
     * comes from the harness's own ACP mode registry
     * (`SessionModeState.availableModes`). The legacy `"posture"`/`"route"`
     * classification survives only inside the daemon's back-compat `decomposeMode`
     * shim (`@agentproto/runtime`'s `DeclaredAdapterMode`), which still maps the
     * old ids during migration — it is not a value the manifest may declare.
     * Omitted ⇒ inferred from the id.
     */
    kind?: "context";
    /**
     * Extra argv prepended BEFORE the manifest's default `bin_args` when
     * this mode is active. Needed for CLIs whose global flags must
     * precede a subcommand baked into `bin_args` (e.g. hermes'
     * `--ignore-user-config` must come before `acp`, where
     * `bin_args_append` would land it too late).
     */
    bin_args_prepend?: string[];
    bin_args_append?: string[];
    env?: Record<string, string>;
    /**
     * Env keys to DELETE from the spawn env when this mode is active.
     * Applied at the runtime's env-merge point (after the ambient
     * process.env + mode/option env are combined), so a mode can scrub a
     * credential that must never reach a non-native endpoint — e.g. a
     * gateway mode scrubbing `ANTHROPIC_API_KEY` so it can't leak to a
     * third-party Anthropic-compatible host (it would both 401 and expose
     * the real key). Unlike `env`, this can't be expressed as a static
     * set (a key set to "" is still present); deletion is the only safe
     * semantics. Mirrors the in-code scrub `claude-sdk` does in
     * `buildQueryOptions`; surfaced here so CLI-adapter gateway modes
     * get the same auth hygiene without per-adapter code.
     */
    env_unset?: string[];
    /**
     * Honest support status surfaced to clients (e.g. via `adapter_list`).
     * Lets an adapter admit that a declared mode is a measured no-op or
     * not-yet-wired instead of silently accepting it. Absent ⇒ `"active"`.
     */
    status?: AgentCliModeStatus;
    /** Human-readable reason backing `status` (e.g. what was measured). */
    status_note?: string;
    /**
     * How the host activates this mode at session start:
     *   - "bin_args" (default) — apply via this mode's `bin_args_prepend` /
     *     `bin_args_append` / `env`, composed into argv/env at spawn time.
     *     Preserves every existing adapter's behavior unchanged.
     *   - "config" — this CLI has no argv/env surface for mode selection;
     *     instead the mode id is forwarded to the ACP arm's `connect({mode})`
     *     and applied via `session/set_config_option` with `configId:"mode"`
     *     after `newSession` (e.g. opencode). `bin_args_prepend` /
     *     `bin_args_append` / `env` are ignored for a mode declaring this.
     * Omit → "bin_args".
     */
    apply?: "bin_args" | "config";
}
type AgentCliOptionType = "boolean" | "integer" | "string" | "enum";
/**
 * AIP-45 option declaration — an independent typed knob. Multiple
 * options may be active per turn; each option's patch is independent
 * and applied in declaration order, AFTER mode patches.
 */
interface AgentCliOption {
    id: string;
    type: AgentCliOptionType;
    description?: string;
    /** Required when type === "enum". */
    enum?: string[];
    default?: boolean | number | string;
    /** Inclusive lower bound when type === "integer". */
    min?: number;
    /** Inclusive upper bound when type === "integer". */
    max?: number;
    /**
     * Argv template prepended BEFORE the manifest's default `bin_args`
     * when the option has a non-default value. The literal token
     * `{value}` is replaced with the option's value (stringified). Use
     * for value-bearing global flags that must precede a subcommand
     * (e.g. hermes' `--skills {value}`).
     */
    bin_args_prepend?: string[];
    /**
     * Argv template appended when the option has a non-default value.
     * The literal token `{value}` is replaced with the option's value
     * (stringified). Use for value-bearing flags like `--model {value}`.
     */
    bin_args_template?: string[];
    /**
     * Argv appended when type === "boolean" AND value === true. Use for
     * bare flags like `--auto`.
     */
    bin_args_append_when_true?: string[];
    /**
     * Env vars to merge when the option has a non-default value. Values
     * may contain `{value}` for templating.
     */
    env?: Record<string, string>;
    /**
     * Env keys to DELETE from the spawn env when the option has a
     * non-default value. Symmetric with `AgentCliMode.env_unset` and
     * applied at the same runtime env-merge point. Lets a single option
     * carry both the value it sets AND the credential it must displace —
     * e.g. a `base_url` option pointing at a third-party Anthropic-
     * compatible gateway should scrub the ambient `ANTHROPIC_API_KEY`
     * so it can't leak, without forcing the operator to also pick a
     * preset mode. The deletion runs before operator-supplied `opts.env`
     * is merged, so a caller can still re-inject a specific key if they
     * truly intend to.
     */
    env_unset?: string[];
}
/**
 * AIP-45 gateway-preset declaration — a backend an Anthropic/OpenAI-
 * compatible client can front, declared by the adapter that knows how to
 * drive it. The manifest authoring shape; the runtime normalizes it to a
 * `ProviderPreset` (via the catalog's merge seam) so adapter-declared
 * presets appear in `agentproto presets list` / `list_provider_presets`
 * alongside the built-in registry. Data-only — no adapter projection
 * (`env`/`env_unset`/`bin_args`) here; that stays in the adapter's modes
 * and options, same as the built-in presets are projected today.
 */
interface AgentCliPresetDeclaration {
    /**
     * Stable preset id. SHOULD equal the mode id if the adapter projects
     * this preset as a mode (e.g. `moonshot`, `openrouter`). Catalog
     * dedupes built-in vs adapter-declared by id; an adapter-declared id
     * that collides with a built-in is ignored in favor of the built-in
     * (the registry is the source of truth for canonical providers).
     */
    id: string;
    /** Human label for the catalog UI ("Moonshot (Kimi)"). */
    label: string;
    /** Short description; surfaced in the catalog. */
    description?: string;
    /** API schema flavor — selects which adapter family can consume it. */
    schemaFlavor: "anthropic" | "openai";
    /** Base URL the client hits. */
    baseUrl: string;
    /**
     * Conventional env var holding this provider's API key
     * (e.g. MOONSHOT_API_KEY). Catalog status is derived from its presence
     * in the daemon's environment ("ready" vs "available").
     */
    keyEnv: string;
    /**
     * Env vars to scrub when this preset is active. Optional at the
     * manifest level — an adapter that scrubs in code (like claude-sdk)
     * may omit it. The catalog does not surface `scrubEnv` to clients.
     */
    scrubEnv?: string[];
    /** Conventional default model id for this provider, if any. */
    defaultModel?: string;
    /** Optional homepage/docs URL for the catalog UI. */
    homepage?: string;
}
/**
 * Built-in continuation strategy ids. Future custom strategies require
 * a follow-up AIP that opens this enum. Keep this in lockstep with
 * `continuationStrategyId` in `AGENT-CLI.schema.json`.
 */
type ContinuationStrategyId = "none" | "pinned-session" | "transcript" | "native-resume";
/**
 * AIP-45 continuation declaration — declares HOW prior turns reach the
 * CLI on subsequent invocations. Hosts MUST refuse to dispatch with a
 * strategy outside `supported`; the operator MAY override `default` via
 * `OPERATOR.runtime.config.continuation` provided the chosen id is in
 * `supported`.
 */
interface AgentCliContinuation {
    default: ContinuationStrategyId;
    supported: ContinuationStrategyId[];
    pinned_session?: AgentCliPinnedSessionTuning;
}
/** Tuning for the `pinned-session` strategy. Ignored by other strategies. */
interface AgentCliPinnedSessionTuning {
    /** How long an idle pinned session is kept alive before the driver
     *  closes it. Applies in addition to the CLI's own
     *  `session.idle_timeout_ms`. Default 1_800_000 (30 min). */
    idle_timeout_ms?: number;
    /**
     * Composite key that uniquely identifies a pinned session. Default
     * `["conversation", "operator"]` — different conversations get
     * different child processes; one operator per conversation reuses
     * one process across turns.
     */
    key_scope?: ContinuationKeyScope[];
}
type ContinuationKeyScope = "conversation" | "operator" | "user" | "guild" | "workspace";
interface AgentCliMcpBlock {
    command?: string;
    args?: string[];
    transport: "stdio" | "http" | "sse";
    url?: string;
}
interface AgentCliRequires {
    os?: ("darwin" | "linux" | "windows")[];
    arch?: ("x64" | "arm64" | "x86" | "arm")[];
    min_disk_mb?: number;
    min_memory_mb?: number;
}
interface AgentCliExample {
    goal: string;
    prompt: string;
    note?: string;
}
/**
 * AIP-45 § Print protocol configuration.
 *
 * When `protocol: "print"`, this block declares the CLI's one-shot
 * headless surface so the print arm can construct the correct argv and
 * map the CLI's wire events to {@link StreamEvent}. Omit to use
 * Claude Code defaults (backward-compatible).
 */
interface AgentCliPrintConfig {
    /**
     * How the prompt text is passed to the binary.
     * - absent / `"positional"` — appended as the last positional arg
     *   (Claude: `claude --print ... <prompt>`).
     * - a string — passed as `--<prompt_flag> <text>` before any trailing
     *   positional args (Mastra Code: `--prompt`).
     */
    prompt_flag?: string;
    /**
     * Output format flags appended before the prompt. Defaults to
     * `["--output-format", "stream-json"]` (Claude Code).
     *
     * Mastra Code uses `["--output", "jsonl"]`.
     */
    output_format?: string[];
    /**
     * Extra flags inserted between `output_format` and the prompt.
     * Claude Code uses `["--no-interactive"]`; Mastra Code omits this.
     */
    pre_prompt?: string[];
    /**
     * Resume / continue flag for reattaching to a prior session.
     *
     * Claude:  `{ flag: "--resume", kind: "value" }`
     * Mastra:  `{ flag: "--continue", kind: "boolean" }` — OR
     *          `{ flag: "--thread", kind: "value" }` for explicit thread id
     */
    resume?: {
        flag: string;
        /** "value" = `--flag <sessionId>`, "boolean" = `--flag` (bare). */
        kind: "value" | "boolean";
    };
    /**
     * Which event taxonomy the CLI emits on stdout (JSONL / stream-json).
     * The print arm picks the matching event mapper.
     *
     * - `"claude-stream-json"` (default) — Claude Code's
     *   `--output-format stream-json` taxonomy.
     * - `"mastra-jsonl"` — Mastra Code's `--output jsonl` taxonomy
     *   (`AgentControllerEvent` shapes).
     * - `"antigravity-stream-json"` — Google Antigravity's (`agy`)
     *   `--output-format stream-json` taxonomy. Superficially it mirrors
     *   Claude Code's headless flag surface (`-p`, `--output-format
     *   stream-json`, `--continue`), but the WIRE events do NOT: each line
     *   is discriminated by an `event` field ("init" | "step_update" |
     *   "result"), the payload is nested under a matching key, and the
     *   session id is a nested `conversation_id` — so it needs its own
     *   mapper, not the Claude one.
     * - `"jcode-ndjson"` — jcode's `run --ndjson` taxonomy. Lines are
     *   discriminated by a `type` field ("start" | "text_delta" |
     *   "tool_start" | "tool_input" | "tool_exec" | "tool_done" |
     *   "tokens" | "done" | connection noise), with tool arguments
     *   streamed as JSON-string `tool_input` deltas between `tool_start`
     *   and `tool_exec`.
     */
    event_schema?: "claude-stream-json" | "mastra-jsonl" | "antigravity-stream-json" | "jcode-ndjson";
}
/**
 * How a spawn's ROUTE (billing endpoint / gateway) relates to the chosen
 * model — the UI-facing route-choice axis a capability-derived spawn
 * drill-down dispatches off (AIP-45 launch-menu drill-down, WP1). See
 * {@link AgentCliDefinition.routeSelection}.
 */
type AgentCliRouteSelection = "free" | "derived-from-model";
interface AgentCliDefinition {
    name: string;
    id: string;
    description: string;
    version: string;
    bin: string;
    bin_args?: string[];
    /**
     * Static environment variables always merged into the spawn env,
     * before any mode/option env patch (so those can still override).
     * The always-on counterpart to `modes[].env` / `options[].env`, which
     * only apply when the corresponding mode/option is selected. Primary
     * user is a generic ACP agent (`acpHandleFromSpec`) whose whole config
     * surface is bin + args + env; a native adapter can use it too for env
     * that should apply on every spawn regardless of mode.
     */
    env?: Record<string, string>;
    install: AgentCliInstallMethod[];
    version_check: AgentCliVersionCheck;
    /** AIP-29 § Setup — post-install configuration pipeline. Optional. */
    setup?: AgentCliSetupStep[];
    auth?: AgentCliAuth;
    /**
     * FIXED billing provider for a single-provider adapter (`claude-code` /
     * `claude-sdk` → `"anthropic"`, `codex` → `"openai"`, `hermes` →
     * `"openrouter"`). A `CatalogProvider` id (typed as `string` here to keep
     * this generic AIP-45 doctype decoupled from `@agentproto/model-catalog` —
     * the runtime resolver validates it against the catalog and derives the
     * api-key env via `providerEnvVar`). Omitted for by-model routers, whose
     * provider the resolver derives from the requested model
     * (`getModelProvider`). Consumed by the runtime billing-auth resolver, NOT
     * by this driver (which stays mechanical).
     */
    provider?: string;
    /**
     * Declares that this adapter supports `subscription` billing mode and how
     * (which env var to set + what to scrub). Presence = supported; absence
     * means a `subscription` request is rejected with `unsupported_auth_mode`.
     * A SINGLE surface for a fixed/single-provider subscription (claude-code),
     * or an ARRAY of surfaces for an adapter with more than one native OAuth
     * login (mastracode: both an anthropic and an openai `provider`-scoped
     * entry) — the runtime matches the spawn's resolved provider against each
     * entry's `provider` scope (see `subscriptionSurfaceFor` in
     * `@agentproto/runtime`'s `spawn-defaults.ts`). See
     * {@link AgentCliAuthSubscription}.
     */
    authSubscription?: AgentCliAuthSubscription | AgentCliAuthSubscription[];
    /**
     * Declares how THIS adapter receives a GATEWAY-routed bearer credential —
     * distinct from a gateway preset's own `keyEnv`
     * (`@agentproto/provider-presets` — the var the OPERATOR's `providers.json`
     * store is keyed under) and from {@link authSubscription}'s `setEnv` (this
     * adapter's OWN native/subscription bearer, unrelated to a third-party
     * gateway). When a `route.gateway` preset/custom route resolves AND this is
     * declared, the runtime's `resolveAuthSpec` injects the resolved gateway
     * credential into `setEnv` here INSTEAD of the preset's `keyEnv` — e.g.
     * claude-code/claude-sdk read a gateway bearer via `ANTHROPIC_AUTH_TOKEN`
     * (the Anthropic SDK's `Authorization: Bearer` var), never a preset's own
     * conventional key-env name (`OPENROUTER_API_KEY`, `MOONSHOT_API_KEY`, …).
     * Omit when the adapter reads a gateway credential directly off the
     * preset's own `keyEnv` (e.g. hermes, which genuinely reads
     * `OPENROUTER_API_KEY`) — the fix is adapter-driven, never a blanket
     * rename of every adapter's gateway var.
     */
    gatewayAuth?: {
        setEnv: string;
    };
    /**
     * True when the adapter's api-key auth is derived from the requested model
     * rather than a fixed `provider` (e.g. `pi`, `opencode`). When set, the
     * runtime resolver allows `"api-key"` mode on the model-derived direct
     * endpoint and includes it in eligibility manifests for by-model routers.
     */
    modelDerivedApiKey?: boolean;
    /**
     * How this adapter's spawn ROUTE (billing endpoint / gateway) relates to
     * the chosen model — the UI-facing route-choice axis a capability-derived
     * spawn drill-down dispatches off (AIP-45 launch-menu drill-down, WP1):
     *
     *   - `"free"` (default) — the same model can take different routes; the
     *     route is an independent user choice. The Claude adapters route to a
     *     gateway by pre-wiring `ANTHROPIC_BASE_URL` through a mode, so e.g.
     *     `claude-opus-4-8` can go direct-Anthropic OR via any gateway.
     *   - `"derived-from-model"` — the endpoint falls out of the model id's
     *     own vendor prefix, so there is nothing independent to choose. A
     *     by-model router (`hermes`, `mastracode`, `pi`, `opencode`) reads the
     *     provider straight off the `<provider>/<id>` prefix; picking the model
     *     already fixes the route, so the connection step is a read-only badge
     *     rather than a choice.
     *
     * Absent ⇒ `"free"` (back-compat: an adapter that never declared this axis
     * keeps presenting a route choice). This is the ROUTE-CHOICE axis and is
     * DISTINCT from {@link modelDerivedApiKey} (the AUTH-derivation axis, #553):
     * an adapter can derive its route from the model without deriving its
     * api-key from it, and vice versa. Where both apply they agree — a
     * model-derived-auth by-model router is also route-derived.
     */
    routeSelection?: AgentCliRouteSelection;
    /**
     * When the runtime billing-auth resolver ENGAGES credential injection:
     *   - `"when-configured"` (default) — only when an operator explicitly set
     *     `auth` (per-spawn or in `defaults.adapters.<slug>.auth`). Non-breaking:
     *     an adapter with no auth config runs ambient, unchanged.
     *   - `"always"` — every spawn, even with nothing configured (then it
     *     fails fast with `missing_auth_credential`). Only `claude-code` sets
     *     this, preserving its #312 fail-fast contract.
     */
    authEnforce?: "always" | "when-configured";
    sandbox: string | Record<string, unknown>;
    runner?: string | Record<string, unknown>;
    protocol: AgentCliProtocol;
    /** REQUIRED when protocol=acp. Workspace-relative ref to AIP-44 ACP.md. */
    acp?: string;
    /** REQUIRED when protocol=mcp. */
    mcp?: AgentCliMcpBlock;
    /** REQUIRED when protocol=proprietary. NPM package implementing AgentCliClient. */
    adapter?: string;
    /** OPTIONAL when protocol=print. Declares the one-shot CLI surface. */
    print?: AgentCliPrintConfig;
    session?: AgentCliSession;
    models?: AgentCliModels;
    capabilities?: AgentCliCapabilities;
    /** AIP-45 modes (mutually-exclusive operation profiles). */
    modes?: AgentCliMode[];
    /** AIP-45 options (independent typed knobs). */
    options?: AgentCliOption[];
    /**
     * AIP-45 gateway presets this adapter can drive. Adapter-declared
     * presets are merged into the provider-preset catalog
     * (`agentproto presets list` / `list_provider_presets`) alongside the
     * built-in registry, deduped by id (built-in wins on collision). Lets
     * an external adapter surface a gateway the built-in registry doesn't
     * know about without patching `@agentproto/provider-presets`.
     */
    presets?: AgentCliPresetDeclaration[];
    /** AIP-45 continuation policy (how prior turns reach the CLI). */
    continuation?: AgentCliContinuation;
    requires?: AgentCliRequires;
    examples?: AgentCliExample[];
    tags?: string[];
    metadata?: Record<string, unknown>;
}
type AgentCliHandle = Readonly<AgentCliDefinition>;
/**
 * Connection options handed to a protocol arm by the runner. Sandbox
 * resolution + secrets injection happen *before* this point — the arm
 * receives a flat env map and a working dir.
 */
interface AgentCliConnectOptions {
    cwd: string;
    env: Record<string, string>;
    abortSignal: AbortSignal;
    /**
     * When set, the protocol arm reattaches to the agent's existing
     * session with this id (ACP `loadSession`, MCP equivalent, or argv
     * `--resume`) instead of starting a fresh one. The agent decides
     * the wire mechanics; the host is responsible for having stored the
     * id from a prior `connect → newSession`.
     *
     * Drives the `native-resume` continuation strategy. Arms that don't
     * support resume MAY ignore this field; the runner won't reject it
     * because per-protocol semantics aren't visible at this layer.
     */
    resumeSessionId?: string;
    /**
     * MCP servers to mount into the agent's session at spawn time. For
     * the ACP arm these are forwarded verbatim into
     * `session/new.mcpServers` (and `session/load.mcpServers` on resume),
     * giving the child agent a scoped toolset the host chose — e.g. the
     * daemon's own orchestration gateway so a spawned agent can itself
     * spawn + supervise sub-agents. Arms that don't model MCP mounting
     * ignore this field.
     */
    mcpServers?: AcpMcpServer[];
    /**
     * Model to activate at session start. For the ACP arm this is
     * applied via `session/set_config_option` with `configId:"model"`
     * immediately after `newSession` — the ACP wrapper (claude-agent-acp)
     * does not forward CLI flags to the underlying claude process so
     * bin_args_template alone cannot change the model.
     */
    model?: string;
    /**
     * Effort level to apply at session start. Effort is model-dependent:
     * the same label ("high", "xhigh", …) maps to different underlying
     * computation budgets per model, and the default differs by model
     * (e.g. Sonnet 4.6 / Opus 4.8 default to "high"; Opus 4.7 to
     * "xhigh"). Omit to keep the model's own default. Applied via
     * `session/set_config_option` with `configId:"effort"` on ACP arms.
     */
    effort?: string;
    /**
     * Mode to activate at session start, for ACP arms whose CLI models
     * mode selection as a session config option rather than an argv/env
     * surface (`AgentCliMode.apply === "config"`, e.g. opencode). Applied
     * via `session/set_config_option` with `configId:"mode"` immediately
     * after `newSession`, best-effort like `model`/`effort`. Adapters that
     * apply mode via `bin_args`/`env` instead (claude-code) leave this
     * unset and are unaffected.
     */
    mode?: string;
    /**
     * Called on ANY adapter-process activity observed by the protocol
     * arm — incoming ACP `session/update` notifications (even ones that
     * don't translate into a `StreamEvent`) and outbound RPC calls
     * (`newSession`/`loadSession`/`prompt`/`cancel`/`setSessionConfigOption`).
     * Distinct from ring-buffer output: fires during long internal
     * tool-call chains where no `StreamEvent` reaches the host, so a
     * supervisor can tell "still working" apart from "gone quiet."
     * Arms that don't model a stdio JSON-RPC channel (proprietary
     * one-shots) MAY ignore this field.
     */
    onActivity?: () => void;
    /**
     * When true, the ACP arm surfaces each `session/request_permission` as an
     * `agent-prompt` StreamEvent and HOLDS the RPC until the host calls
     * `respondPermission` — forwarded to the arm's
     * `createAcpProtocolArm({ permissionHold })`. Arms with no permission
     * surface (non-ACP) ignore it. Default false (auto-answer, unchanged).
     */
    permissionHold?: boolean;
    /**
     * Turn-idle watchdog, forwarded verbatim to the ACP arm's
     * `createAcpClient({ turnIdleTimeoutMs })` (see
     * `@agentproto/acp/client`'s `AcpClientOptions.turnIdleTimeoutMs` for
     * the full contract). If a turn goes this many ms with no activity
     * signal and the underlying adapter call still hasn't resolved, the
     * arm synthesizes a `turn-end` event with `reason: "watchdog-timeout"`
     * instead of hanging forever. Undefined disables the watchdog. Arms
     * that don't model a stdio JSON-RPC channel MAY ignore this field.
     */
    turnIdleTimeoutMs?: number;
}
/**
 * Result of a mid-session model-switch attempt — see
 * {@link AgentCliRuntimeSession.setModel}. Mirrors
 * `@agentproto/acp/client`'s `SetConfigOptionResult` (this package stays
 * decoupled from `@agentproto/acp`'s client subpath by not importing its
 * type, hence the structural duplicate) plus the applied model id, so a
 * caller can echo back exactly what took effect.
 */
interface SetModelResult {
    applied: boolean;
    /** The model id that took effect. Present only when `applied` is true. */
    model?: string;
    /**
     * Present only when `applied` is false. Canonical values:
     *   - `"requires-restart"` — this adapter's `models.apply` is `"arg"`;
     *     the model is baked into argv at spawn time and cannot change on a
     *     live session.
     *   - `"not-supported"` — the protocol arm has no mid-session config
     *     surface (e.g. the print arm, or an ACP arm with no connected
     *     session yet).
     *   - anything else — the agent's own rejection detail, verbatim from
     *     `configOptionErrorDetail` (ACP `config` strategy) or the `/model`
     *     control-turn failure (`command` strategy).
     */
    reason?: string;
}
/**
 * Result of a mid-session `setSessionMode` attempt — see
 * {@link AgentCliRuntimeSession.setSessionMode}. Same shape convention as
 * {@link SetModelResult}: `applied` + the value that took effect on
 * success, or a `reason` on failure. Never thrown — a mode switch the
 * wrapper rejects (unknown/stale mode id, no native mode registry) always
 * resolves structurally.
 */
interface SetSessionModeResult {
    applied: boolean;
    /** The mode id that took effect. Present only when `applied` is true. */
    modeId?: string;
    /**
     * Present only when `applied` is false. Canonical values:
     *   - `"not-supported"` — the protocol arm has no `setSessionMode`
     *     surface at all (e.g. the print/proprietary arms, or a non-ACP
     *     wrapper with no native mode registry).
     *   - `"not-connected"` — the ACP arm has no live session yet.
     *   - anything else — the wrapper's own rejection detail (a mode id not
     *     in `availableModes`, or a stale/version-mismatched offer).
     */
    reason?: string;
}
/**
 * Result of a mid-session `setEffort` attempt — see
 * {@link AgentCliRuntimeSession.setEffort}. Same shape convention as
 * {@link SetModelResult}/{@link SetSessionModeResult}: `applied` + the value
 * that took effect on success, or a `reason` on failure. Effort is a per-model
 * capability (SPEC §3.9) — a label the current model doesn't accept resolves
 * `{applied:false, reason}` best-effort, never thrown (SPEC risk R7).
 */
interface SetEffortResult {
    applied: boolean;
    /** The effort label that took effect. Present only when `applied` is true. */
    effort?: string;
    /**
     * Present only when `applied` is false. Canonical values:
     *   - `"not-supported"` — the protocol arm has no `setConfigOption` surface
     *     at all (e.g. the print/proprietary arms, or an ACP arm with no
     *     connected session yet).
     *   - anything else — the wrapper's own rejection detail (an effort label
     *     the current model doesn't accept, or a stale/version-mismatched
     *     offer), verbatim from `configOptionErrorDetail`.
     */
    reason?: string;
}
/**
 * Per-turn dispatch shape. Implemented by every protocol arm
 * (ACP, MCP, proprietary). The runner is the only call site for
 * these methods; consumers see {@link AgentCliSession} instead.
 */
interface AgentCliClient {
    connect(opts: AgentCliConnectOptions): Promise<void>;
    send(turnId: string, message: unknown): Promise<void>;
    events(): AsyncIterable<StreamEvent>;
    cancel(turnId: string): Promise<void>;
    /**
     * Apply a session config option (e.g. `configId:"model"`) on the LIVE,
     * already-connected session — only the ACP arm implements this (its
     * connection exposes `session/set_config_option` mid-session); other
     * arms (print, proprietary) omit it, and `define-agent-cli.ts`'s
     * `setModel` treats its absence as `{applied:false,
     * reason:"not-supported"}`. Non-fatal: a server rejection resolves
     * `{applied:false, reason}` rather than throwing.
     */
    setConfigOption?(configId: string, value: string): Promise<{
        applied: boolean;
        reason?: string;
    }>;
    /**
     * Switch this session's mode on the LIVE, already-connected session via
     * ACP `session/set_mode` — only the ACP arm implements this (its
     * connection exposes `setSessionMode` mid-session); other arms (print,
     * proprietary) omit it, and `define-agent-cli.ts`'s `setSessionMode`
     * treats its absence as `{applied:false, reason:"not-supported"}`.
     * Non-fatal: a rejection resolves `{applied:false, reason}` rather than
     * throwing — mirrors `setConfigOption`'s contract exactly.
     */
    setSessionMode?(modeId: string): Promise<{
        applied: boolean;
        reason?: string;
    }>;
    /**
     * The wrapper's advertised session configuration options, captured at
     * connect time (`newSession`/`loadSession` response `configOptions`) —
     * see `@agentproto/acp/client`'s `AcpClientSession.availableConfigOptions`
     * for the full contract. Only the ACP arm populates this; other arms
     * leave it undefined (treated as empty by `define-agent-cli.ts`).
     */
    readonly availableConfigOptions?: SessionConfigOption[];
    /**
     * Set when the connect-time `model` apply was rejected by the ACP server
     * — the session is live but on the agent's own DEFAULT model, not the
     * requested one (see `@agentproto/acp/client`'s
     * `AcpClientSession.modelApplyRejection` for the full contract). Only the
     * ACP arm populates this; other arms leave it undefined. Read by
     * `define-agent-cli.ts` right after `connect()`: for a
     * `routeSelection:"derived-from-model"` adapter (opencode & co. — the
     * model id IS the route and the bill) a rejected explicit model is a
     * spawn-fatal misroute, not a cosmetic default.
     */
    readonly modelApplyRejection?: {
        requested: string;
        reason: string;
    };
    /**
     * The wrapper's advertised session modes, captured at connect time
     * (`SessionModeState.availableModes`) — see `@agentproto/acp/client`'s
     * `AcpClientSession.availableModes`. Only the ACP arm populates this;
     * other arms leave it undefined.
     */
    readonly availableModes?: SessionMode[];
    /**
     * The mode id the wrapper reported as active at connect time
     * (`SessionModeState.currentModeId`). Only the ACP arm populates this.
     */
    readonly currentModeId?: string;
    /**
     * Resolve a permission request parked by permission-hold mode — `requestId`
     * is the `toolCallId` carried on the `agent-prompt` StreamEvent that
     * surfaced it. Returns true when a matching parked request was found and
     * resolved. Only the ACP arm implements this; other arms omit it.
     */
    respondPermission?(requestId: string, resolution: AcpPermissionResolution): boolean;
    /**
     * Subscribe to events the agent emits while no turn is in flight (an
     * autonomous background-task wake, a late task lifecycle edge) — see
     * `@agentproto/acp`'s `AcpClientSession.onOutOfTurnEvent`. Returns an
     * unsubscribe function. Only the ACP arm implements this.
     */
    onOutOfTurnEvent?(listener: (event: StreamEvent) => void): () => void;
    /**
     * Whether the agent accepts ACP steering (`_session/steering`,
     * advertised as `InitializeResponse._meta.steering.supported`). Read
     * after `connect()`. Only the ACP arm populates this.
     */
    readonly steeringSupported?: boolean;
    /**
     * Inject `content` into the turn in flight — see `@agentproto/acp/client`'s
     * `AcpClientSession.steer` for the full contract (host-turn gate,
     * `idleBehavior:"promptRequired"`, never throws). Only the ACP arm
     * implements this.
     */
    steer?(content: unknown): Promise<SteerOutcome>;
    close(): Promise<void>;
    /**
     * The session id the protocol arm holds. Populated after `connect()`
     * resolves — for `newSession` calls it's whatever the agent assigned;
     * for `loadSession` (resume) calls it's the same id the host passed
     * in. Hosts persist this so a future cold start can resume.
     *
     * Empty string before connect or for protocols that don't have a
     * session concept (proprietary one-shots).
     */
    readonly sessionId?: string;
    /**
     * Whether this arm's transport to the agent is still usable — a FRESH
     * read, never a cached flag (the ACP arm asks the SDK connection's own
     * abort signal). `true` before `connect()` resolves: nothing has died
     * yet, so "not connected" would be a lie.
     *
     * Only the ACP arm implements this; arms with no long-lived connection
     * (print — a fresh subprocess per turn; proprietary in-process) omit it,
     * and every caller treats absence as "no transport to lose."
     */
    isConnected?(): boolean;
    /**
     * Subscribe to transport death — the push half of the liveness surface
     * whose pull half is {@link isConnected}. Fires at most once, and fires
     * synchronously if the transport is ALREADY gone when you subscribe, so a
     * host that only gets the handle after `connect()` can never miss it.
     *
     * Only the ACP arm implements this; arms with no long-lived connection
     * omit it (there is no transport to lose). Also fires on an orderly
     * `close()` — the "was this death expected?" judgement belongs to the
     * host, which knows whether it asked for the teardown.
     */
    onDisconnect?(listener: (err: Error) => void): void;
    /**
     * Diagnostic hook — returns the last N lines of the child's stderr,
     * joined with newlines. Set by the runner after spawn; read by
     * `promptTurn` to enrich error events with process-level context.
     * Not part of the protocol; internal to the runner.
     */
    _stderrTail?: () => string;
}
/**
 * The runtime handle returned by `defineAgentCli` — call `.start()`
 * to spawn the binary and obtain a {@link AgentCliRuntimeSession}.
 */
interface AgentCliRuntime {
    readonly definition: AgentCliHandle;
    start(opts?: AgentCliStartOptions): Promise<AgentCliRuntimeSession>;
}
interface AgentCliStartOptions {
    cwd?: string;
    env?: Record<string, string>;
    signal?: AbortSignal;
    /**
     * Per-turn runtime configuration — selects a manifest mode, sets
     * options, and picks the continuation strategy. Validated against
     * the manifest's declarations before spawn; unknown ids reject.
     */
    config?: RuntimeConfig;
    /**
     * Identity context the host hands to the continuation strategy.
     * The pinned-session strategy uses this to derive its session-pin
     * key (per `manifest.continuation.pinned_session.key_scope`); other
     * strategies may ignore. Hosts SHOULD always pass this when in a
     * conversation context — without it, pinning can't be keyed and
     * the strategy falls back to per-spawn behaviour.
     */
    turnCtx?: TurnContext;
    /**
     * Reattach to an existing protocol session (ACP `loadSession`, MCP
     * equivalent, argv `--resume`) instead of spawning fresh. The
     * `native-resume` strategy populates this from the host's persisted
     * (turnCtx → sessionId) lookup. Other strategies leave undefined.
     * Forwarded verbatim to `protocolArm.connect({ resumeSessionId })`.
     */
    resumeSessionId?: string;
    /**
     * Persistent location for the adapter's ISOLATED config dir (claude-code's
     * `CLAUDE_CONFIG_DIR`), replacing the default throwaway `mkdtemp` under
     * `os.tmpdir()`. The driver creates it (recursive) and seeds/re-asserts the
     * same isolation content either way — explicit empty `mcpServers` in
     * `.claude.json`, attribution suppression + permission mode in
     * `settings.json` — so this changes WHERE the isolation lives, never
     * WHETHER it applies. The point: the SDK's conversation store
     * (`projects/<cwd-slug>/<uuid>.jsonl`) lands somewhere a later respawn can
     * point back at, making `resumeSessionId` actually able to restore full
     * context after the adapter process was reaped (a temp dir dies with the
     * process's run; the transcript inside it is what native resume needs).
     * The daemon keys this per session lineage — see the runtime's
     * `SessionDescriptor.adapterConfigDir`. Adapters that don't isolate a
     * config dir ignore it.
     */
    configDir?: string;
    /**
     * MCP servers to mount into the spawned agent's session. Threaded
     * through to `protocolArm.connect({ mcpServers })` → the ACP arm's
     * `session/new.mcpServers`. Lets the host inject a scoped toolset
     * (e.g. the daemon's orchestration gateway) at spawn time.
     */
    mcpServers?: AcpMcpServer[];
    /**
     * Called on any adapter-process activity (ACP JSON-RPC traffic in
     * either direction). Forwarded verbatim to
     * `protocolArm.connect({ onActivity })` — see
     * {@link AgentCliConnectOptions.onActivity} for the full contract.
     * Lets a host track session liveness independent of ring-buffer
     * output, e.g. during a long internal tool-call chain.
     */
    onActivity?: () => void;
    /**
     * Turn-idle watchdog timeout in ms, forwarded to
     * `protocolArm.connect({ turnIdleTimeoutMs })` — see
     * {@link AgentCliConnectOptions.turnIdleTimeoutMs}. When omitted here,
     * `createAgentCliRuntime(...).start()` falls back to the manifest's
     * `session.turn_idle_timeout_ms` (if the adapter declares one), so a
     * host doesn't have to opt in per-call for an adapter that always
     * wants this protection.
     */
    turnIdleTimeoutMs?: number;
    /**
     * When true, the spawned session runs in permission-hold mode: the ACP arm
     * surfaces each permission request as an `agent-prompt` StreamEvent and
     * HOLDS the RPC until the host calls `respondPermission`. Forwarded to
     * `protocolArm.connect({ permissionHold })`. Default false (unchanged
     * auto-answer behaviour for every existing caller).
     */
    permissionHold?: boolean;
    /**
     * FULLY-RESOLVED billing-auth spec, computed by the runtime resolver
     * (`@agentproto/runtime`'s `spawn-defaults`/`session-spawn`) and applied
     * MECHANICALLY here — this driver does no provider lookup, mode selection,
     * or catalog import of its own. EXPLICIT credential selection, not
     * scrub-by-absence: the resolver already decided the mode (ordered
     * preference — subscription over api-key when a subscription credential is
     * present), the env var to SET (`setEnv`), the conflicting vars to SCRUB
     * (`unsetEnv`), and resolved the `credential` from a NAMED config/store
     * ref (never the ambient shell env).
     *
     * `createAgentCliRuntime(...).start()` ENGAGES this spec when
     * `enforce === "always"` OR `explicit === true`; on engage it deletes every
     * `unsetEnv` key (unless this spawn's own mode/option patch explicitly set
     * it) then SETS `setEnv = credential`. When engaged with no `credential`, it
     * FAILS FAST with `RuntimeConfigError` (`missing_auth_credential`) — never a
     * fallback to another or ambient credential. When absent (the resolver
     * produced no spec — e.g. a by-model adapter whose provider didn't resolve),
     * this driver injects nothing and runs ambient.
     */
    auth?: ResolvedAuthSpec;
    /**
     * Decomposed posture axis (SPEC §3.4a) — what the agent may DO, in the
     * agentproto-canonical vocabulary (`"plan"`, `"accept-edits"`, `"bypass"`,
     * `"read-only"`, `"default"`). Applied at spawn-time via the adapter's
     * existing mechanism (e.g. claude-code's CLAUDE_CONFIG_DIR permission
     * settings), independently of a legacy `config.mode`. When undefined, the
     * adapter spawns in its own default posture.
     */
    posture?: string;
    /**
     * Decomposed contextProfile axis (SPEC §3.1) — what enters context. When it
     * matches a manifest-declared mode with `kind: "context"` (e.g. claude-code's
     * `"lean"`), that mode's env/argv patches are applied at spawn. Distinct from
     * both `posture` and legacy `config.mode` — each axis is independent.
     */
    contextProfile?: string;
    /**
     * Absolute paths OUTSIDE `cwd` the adapter's workspace toolset may READ
     * (never write). Daemon-authored only (`spawnAgentSession` hands it down
     * for the exact AGENTS.md an inherited pointer prompt names). Threaded two
     * ways: onto the child env (`AGENTPROTO_ADDITIONAL_READ_PATHS`, for
     * adapters that build their own toolset from it) and onto the
     * `commandSandbox` confinement as extra READ paths — writes and sibling
     * reads stay denied either way. Adapters that can't model the grant
     * ignore it.
     */
    additionalReadPaths?: string[];
    /**
     * OS-level confinement for the spawned child itself (macOS Seatbelt /
     * Linux bubblewrap, `@agentproto/command-sandbox`) — confines the
     * adapter's own process tree, unlike `posture`/`contextProfile` which
     * only shape what the adapter is TOLD to do. This is a SEPARATE axis
     * from AIP-36 `sandbox` (the remote-box session provider,
     * `resolveSandboxProvider`/`SandboxProviderHandle` in
     * `@agentproto/runtime`): that boots a whole nested daemon on a
     * different machine/box; this wraps THIS host's spawn argv so even an
     * in-process Bash tool the ACP permission seam can't see is denied
     * out-of-workspace reads/writes (and, under `"strict"`, network).
     * Undefined ⇒ falls back to the workspace's `.agentproto/
     * command-sandbox.json` `adapterSpawn` key (see `wrapAgentCliSpawn`'s
     * doc), or stays unconfined if that's unset too — unchanged behaviour
     * for every caller that never engages this axis at all. `"workspace"`/
     * `"strict"` with no backend available for this platform is a
     * FAIL-CLOSED refusal to spawn, mirroring `command_execute`'s own
     * fail-closed contract in `@agentproto/runtime`'s `command-tools.ts` —
     * see `define-agent-cli.ts` / `print-arm.ts` for where this is applied.
     */
    commandSandbox?: SandboxMode;
    /**
     * Host-declared filesystem zones for an app boundary (`app_run` / app
     * workflow sessions). Engages the OS sandbox unconditionally (Seatbelt /
     * bwrap; fail-closed when no backend exists, and incompatible with
     * `commandSandbox: "off"`) and switches it to: cwd + `readOnly` readable,
     * only `writable` (plus toolchain/config scratch) writable, `hidden`
     * unreadable. See `SandboxZones` in `@agentproto/command-sandbox`.
     * For claude-code the writable zones are also registered as
     * `permissions.additionalDirectories` so the harness doesn't prompt for
     * writes the sandbox already allows.
     */
    fsZones?: AgentCliFsZones;
    /**
     * Keep the host repo's instruction files out of the session's context.
     * claude-code: every ANCESTOR directory of `cwd` gets its CLAUDE.md /
     * CLAUDE.local.md / .claude/CLAUDE.md / .claude/rules/** added to the
     * isolated `settings.json`'s `claudeMdExcludes` (the app's own CLAUDE.md,
     * in `cwd`, still loads). Adapters with no such switch ignore this; the
     * caller is expected to warn (see `agentCliSupportsHostContextIsolation`).
     */
    isolateHostContext?: boolean;
}
/** Filesystem zones handed to the driver — see {@link AgentCliStartOptions.fsZones}. */
interface AgentCliFsZones {
    readOnly: string[];
    writable: string[];
    hidden?: string[];
}
/**
 * The resolved billing-auth spec the runtime hands the driver — see
 * {@link AgentCliStartOptions.auth}. Every field is pre-decided; the driver
 * only applies it.
 */
interface ResolvedAuthSpec {
    /** The resolved billing mode (already ordered/validated by the runtime). */
    mode: "subscription" | "api-key";
    /** The resolved secret value for `mode`, or absent when nothing resolved
     *  (⇒ fail-fast on engage). Never read ambiently. */
    credential?: string;
    /** Env var SET to `credential` on engage. Empty string for an
     *  {@link externalCredential} subscription (nothing is set). */
    setEnv: string;
    /** File-based subscription (see `AgentCliAuthSubscription.external`): the CLI
     *  reads its OWN local-login file, so the driver injects NO credential — it
     *  only applies {@link unsetEnv} (the api-key scrub) and does NOT fail-fast on
     *  a missing `credential` (there deliberately is none). Money-safe: no bearer
     *  ever reaches an env var. Absent/false ⇒ today's inject-a-credential path. */
    externalCredential?: boolean;
    /** Conflicting billing-credential (and, in native mode, gateway-hygiene)
     *  env vars DELETED on engage — unless this spawn's own mode/option patch
     *  explicitly set the key. */
    unsetEnv: string[];
    /** True when an operator explicitly configured `auth` (per-spawn or in
     *  `defaults.adapters.<slug>.auth`) — half the engage condition. */
    explicit: boolean;
    /** The adapter's enforcement policy — the other half of engage. */
    enforce: "always" | "when-configured";
    /** True when NEITHER subscription nor api-key had any credential
     *  available and `mode` above is an arbitrary fallback pick, not a real
     *  signal. The fail-fast message reads this to enumerate BOTH auth paths
     *  instead of presenting the fallback mode as though it were chosen. */
    neitherConfigured?: boolean;
    /** Non-authenticating hint: true when `providers.json` has a key for the
     *  resolved provider that's currently being ignored for want of a
     *  `defaults.adapters.<slug>.auth` block. Never used to authenticate —
     *  only read by the fail-fast message. */
    ignoredApiKeyInStore?: boolean;
    /** Present ONLY when the runtime resolved an explicit gateway route (a
     *  preset/custom route) — the `base_url` it also routes into the adapter's
     *  base_url option. Its PRESENCE is the driver's signal that this api-key
     *  credential is COUPLED to that gateway base_url (they were resolved
     *  together), so billing-auth must engage even though ANTHROPIC_BASE_URL is
     *  already in the spawn env — distinguishing it from a base_url set MANUALLY
     *  via option with a native credential (no baseUrl), where engaging would
     *  leak a native credential to a foreign host. Never set for native/
     *  subscription specs. The driver reads only its presence, not its value
     *  (the value reaches the child via the base_url option). */
    baseUrl?: string;
}
/**
 * Operator-side runtime configuration. Mirrors the `runtime.config`
 * block in AIP-9 OPERATOR.md. Every field is optional; omitted fields
 * fall back to the manifest's declared defaults.
 */
interface RuntimeConfig {
    /** Manifest-declared mode id. Unknown ids reject at validation time. */
    mode?: string;
    /** Manifest-declared option ids → values. Type / enum / bound checked. */
    options?: Record<string, boolean | number | string>;
    /** Continuation strategy id. Must be in `manifest.continuation.supported`. */
    continuation?: ContinuationStrategyId;
}
/**
 * Identity scope for continuation key derivation. The host populates
 * the fields it knows; the pinned-session strategy's `key_scope` array
 * picks which to actually combine. Missing fields the scope asked for
 * downgrade the strategy to per-spawn behaviour with a console warning
 * (rather than silently colliding pins across operators / conversations).
 */
interface TurnContext {
    conversation?: string;
    operator?: string;
    user?: string;
    guild?: string;
    workspace?: string;
}
interface AgentCliRuntimeSession {
    readonly sessionId: string;
    /**
     * OS-level process id of the spawned child, when the runtime owns a
     * real subprocess (every current arm — ACP, print — does). Lets a
     * host compute a cheap `processAlive` liveness check
     * (`process.kill(pid, 0)`) without adapter-specific forensics.
     * Undefined for a future arm with no owned process (e.g. a
     * WebSocket transport).
     */
    readonly pid?: number;
    /**
     * Whether the adapter's transport is still usable, read FRESH at call
     * time. The pull half of the transport-liveness surface (the push half is
     * {@link AgentCliStartOptions.onDisconnect}) and the answer to a question
     * `pid` cannot: the wrapper process can be alive and reported by
     * `process.kill(pid, 0)` while its stdio JSON-RPC stream is closed, at
     * which point every RPC rejects with "ACP connection closed" and the
     * session is dead in every way that matters.
     *
     * `true` before anything has died, and for arms that hold no long-lived
     * connection at all (the print arm re-spawns per turn — there is no
     * transport to lose between turns). A host must therefore treat only an
     * explicit `false` as evidence of death, never the absence of `true`.
     */
    isConnected?(): boolean;
    /**
     * Subscribe to transport death — the push half of the surface whose pull
     * half is {@link isConnected}. Fires at most once, and SYNCHRONOUSLY if
     * the transport already died before you subscribed, so a host that wires
     * this up after `start()` resolves cannot miss a connection that failed in
     * between.
     *
     * Fires for an orderly `close()` too: only the host knows whether it asked
     * for the teardown, so the "was this expected?" judgement stays there (the
     * daemon makes it by refusing to crash-mark a row that isn't `running`).
     * Absent for arms with no long-lived connection.
     */
    onDisconnect?(listener: (err: Error) => void): void;
    send(message: unknown): AsyncIterable<StreamEvent>;
    cancel(): Promise<void>;
    /**
     * Resolve a permission request parked by permission-hold mode (see
     * `AgentCliStartOptions.permissionHold`). Delegates to the protocol arm's
     * `respondPermission`; returns true when a matching parked request was
     * resolved. Absent for arms that don't model held permissions.
     */
    respondPermission?(requestId: string, resolution: AcpPermissionResolution): boolean;
    /**
     * Subscribe to events the agent emits while no turn is in flight —
     * Claude Code's autonomous wake when a background task settles, and the
     * AIR `asyncTasks` lifecycle (`background-task` events) that precedes it.
     * Delegates to the protocol arm; absent for arms that can't produce them.
     * Returns an unsubscribe function.
     */
    onOutOfTurnEvent?(listener: (event: StreamEvent) => void): () => void;
    /** Whether this session's agent accepts steering — delegates to the
     *  protocol arm; absent for arms that can't steer. */
    readonly steeringSupported?: boolean;
    /** Steer the turn in flight — delegates to the protocol arm's `steer`
     *  (see {@link SteerOutcome}); absent for arms that can't steer. */
    steer?(content: unknown): Promise<SteerOutcome>;
    /**
     * Switch the active model on this LIVE, already-running session,
     * honoring the manifest's `models.apply` strategy:
     *   - `"config"`  — `session/set_config_option(configId:"model")` on the
     *     retained ACP connection (via the arm's `setConfigOption`).
     *   - `"command"` — the same `/model <id>` control turn `models.apply:
     *     "command"` uses at spawn time (`applyModelCommand`), drained and
     *     checked for a switch acknowledgement.
     *   - `"arg"`     — always `{applied:false, reason:"requires-restart"}`:
     *     this CLI takes its model as a spawn-time argv token, so a live
     *     switch is impossible without restarting the session.
     * Always resolves — never throws and never kills the session, even when
     * the underlying agent rejects the request. See {@link SetModelResult}
     * for the full reason vocabulary.
     */
    setModel(modelId: string): Promise<SetModelResult>;
    /**
     * Switch the active mode on this LIVE, already-running session via ACP
     * `session/set_mode` (SDK `setSessionMode`) — the native-posture
     * counterpart to `setModel`, a distinct axis (SPEC §3.4a: posture comes
     * from the harness's own mode registry, not a manifest mode list).
     * Always resolves — never throws and never kills the session, even when
     * the wrapper rejects the request (unknown mode id, no native mode
     * registry). Resolves `{applied:false, reason:"not-supported"}` for any
     * arm that doesn't implement `AgentCliClient.setSessionMode` (print,
     * proprietary, or a non-ACP wrapper with no mode surface). See
     * {@link SetSessionModeResult} for the full reason vocabulary.
     */
    setSessionMode(modeId: string): Promise<SetSessionModeResult>;
    /**
     * Switch the reasoning/compute budget on this LIVE, already-running session
     * via ACP `session/set_config_option(configId:"effort")` — the effort-axis
     * counterpart to `setModel`'s `"config"` strategy (SPEC §4.2, build step 5).
     * Effort is model-dependent (SPEC §3.9): the same label maps to a different
     * budget across models and some labels are model-gated (opus offers
     * `ultracode`, haiku doesn't), so a value the current model rejects resolves
     * `{applied:false, reason}` best-effort (SPEC risk R7) rather than throwing.
     * Resolves `{applied:false, reason:"not-supported"}` for any arm with no
     * `setConfigOption` surface (print, proprietary, non-ACP). Always resolves —
     * never throws and never tears down the session. See {@link SetEffortResult}
     * for the full reason vocabulary.
     */
    setEffort(effort: string): Promise<SetEffortResult>;
    /**
     * The wrapper's advertised session configuration options, captured once
     * at connect time (SPEC §3.9 capability read-surface) — the per-model
     * value lists a caller can resolve BEFORE attempting to apply a
     * model/effort value, instead of discovering the accepted vocabulary
     * only by catching a `setModel`/`setConfigOption` rejection. Empty
     * (`[]`) for arms that don't populate `AgentCliClient.
     * availableConfigOptions` (print, proprietary). Snapshot at connect
     * time; not live-updated by a later `setModel`/`setSessionMode` call.
     */
    readonly availableConfigOptions: SessionConfigOption[];
    /**
     * The wrapper's advertised session modes (SDK `SessionModeState.
     * availableModes`), captured at connect time. Empty (`[]`) when the
     * wrapper has no native mode registry, or for arms that don't populate
     * `AgentCliClient.availableModes` — the read-surface signal a caller
     * uses to fall back to a portable/prompt-injected posture instead of a
     * native `setSessionMode` switch.
     */
    readonly availableModes: SessionMode[];
    /**
     * The mode id the wrapper reported as active at connect time. Undefined
     * when the wrapper advertised no mode state.
     */
    readonly currentModeId: string | undefined;
    close(): Promise<void>;
}

/**
 * AIP-45 AGENT-CLI.md frontmatter zod schema.
 *
 * Mirrors `resources/aip-45/draft/AGENT-CLI.schema.json`. AIP-45 is a
 * sibling of AIP-29 (CLI.md, tool CLIs) covering interactive
 * agent-as-process binaries. The `protocol` discriminator (acp / mcp
 * / proprietary) selects the wire arm; cross-field rules ensure the
 * matching arm-specific block is present.
 *
 * Both authoring paths (`define-agent-cli.ts` and
 * `manifest/index.ts`) validate against this schema, so every
 * field-level constraint runs in both paths from a single source of
 * truth.
 */

declare const agentCliFrontmatterSchema: z.ZodObject<{
    name: z.ZodString;
    id: z.ZodString;
    description: z.ZodString;
    version: z.ZodString;
    bin: z.ZodString;
    bin_args: z.ZodOptional<z.ZodArray<z.ZodString>>;
    env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
    install: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
        method: z.ZodLiteral<"brew">;
        package: z.ZodString;
        experimental: z.ZodOptional<z.ZodBoolean>;
    }, z.core.$strict>, z.ZodObject<{
        method: z.ZodLiteral<"apt">;
        package: z.ZodString;
        experimental: z.ZodOptional<z.ZodBoolean>;
    }, z.core.$strict>, z.ZodObject<{
        method: z.ZodLiteral<"dnf">;
        package: z.ZodString;
        experimental: z.ZodOptional<z.ZodBoolean>;
    }, z.core.$strict>, z.ZodObject<{
        method: z.ZodLiteral<"pacman">;
        package: z.ZodString;
        experimental: z.ZodOptional<z.ZodBoolean>;
    }, z.core.$strict>, z.ZodObject<{
        method: z.ZodLiteral<"choco">;
        package: z.ZodString;
        experimental: z.ZodOptional<z.ZodBoolean>;
    }, z.core.$strict>, z.ZodObject<{
        method: z.ZodLiteral<"scoop">;
        package: z.ZodString;
        experimental: z.ZodOptional<z.ZodBoolean>;
    }, z.core.$strict>, z.ZodObject<{
        method: z.ZodLiteral<"npm">;
        package: z.ZodString;
        global: z.ZodOptional<z.ZodBoolean>;
        experimental: z.ZodOptional<z.ZodBoolean>;
    }, z.core.$strict>, z.ZodObject<{
        method: z.ZodLiteral<"pip">;
        package: z.ZodString;
        user: z.ZodOptional<z.ZodBoolean>;
        experimental: z.ZodOptional<z.ZodBoolean>;
    }, z.core.$strict>, z.ZodObject<{
        method: z.ZodLiteral<"cargo">;
        package: z.ZodString;
        experimental: z.ZodOptional<z.ZodBoolean>;
    }, z.core.$strict>, z.ZodObject<{
        method: z.ZodLiteral<"go">;
        package: z.ZodString;
        experimental: z.ZodOptional<z.ZodBoolean>;
    }, z.core.$strict>, z.ZodObject<{
        method: z.ZodLiteral<"curl">;
        url: z.ZodString;
        verify_sha256: z.ZodOptional<z.ZodString>;
        experimental: z.ZodOptional<z.ZodBoolean>;
    }, z.core.$strict>, z.ZodObject<{
        method: z.ZodLiteral<"download">;
        url: z.ZodString;
        extract_bin: z.ZodString;
        verify_sha256: z.ZodOptional<z.ZodString>;
        experimental: z.ZodOptional<z.ZodBoolean>;
    }, z.core.$strict>, z.ZodObject<{
        method: z.ZodLiteral<"vendored">;
        path: z.ZodString;
        experimental: z.ZodOptional<z.ZodBoolean>;
    }, z.core.$strict>], "method">>;
    version_check: z.ZodObject<{
        cmd: z.ZodString;
        parse: z.ZodString;
        range: z.ZodString;
        timeout_ms: z.ZodDefault<z.ZodNumber>;
    }, z.core.$strict>;
    setup: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
        id: z.ZodString;
        kind: z.ZodLiteral<"cmd">;
        cmd: z.ZodString;
        description: z.ZodOptional<z.ZodString>;
        skip_if: z.ZodOptional<z.ZodObject<{
            cmd: z.ZodString;
            exit_code: z.ZodDefault<z.ZodNumber>;
            timeout_ms: z.ZodDefault<z.ZodNumber>;
        }, z.core.$strict>>;
        timeout_ms: z.ZodDefault<z.ZodNumber>;
        interactive: z.ZodDefault<z.ZodBoolean>;
        persist: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
            env: z.ZodString;
        }, z.core.$strict>, z.ZodObject<{
            secret_slug: z.ZodString;
        }, z.core.$strict>, z.ZodObject<{
            cmd: z.ZodString;
        }, z.core.$strict>]>>;
    }, z.core.$strict>, z.ZodObject<{
        id: z.ZodString;
        kind: z.ZodLiteral<"prompt">;
        prompt: z.ZodString;
        description: z.ZodOptional<z.ZodString>;
        type: z.ZodDefault<z.ZodEnum<{
            boolean: "boolean";
            text: "text";
            select: "select";
            secret: "secret";
        }>>;
        default: z.ZodOptional<z.ZodString>;
        options: z.ZodOptional<z.ZodUnion<readonly [z.ZodArray<z.ZodString>, z.ZodObject<{
            cmd: z.ZodString;
            timeout_ms: z.ZodDefault<z.ZodNumber>;
        }, z.core.$strict>]>>;
        skip_if: z.ZodOptional<z.ZodObject<{
            cmd: z.ZodString;
            exit_code: z.ZodDefault<z.ZodNumber>;
            timeout_ms: z.ZodDefault<z.ZodNumber>;
        }, z.core.$strict>>;
        persist: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
            env: z.ZodString;
        }, z.core.$strict>, z.ZodObject<{
            secret_slug: z.ZodString;
        }, z.core.$strict>, z.ZodObject<{
            cmd: z.ZodString;
        }, z.core.$strict>]>>;
    }, z.core.$strict>, z.ZodObject<{
        id: z.ZodString;
        kind: z.ZodLiteral<"oauth">;
        secret_slug: z.ZodString;
        description: z.ZodOptional<z.ZodString>;
        skip_if: z.ZodOptional<z.ZodObject<{
            cmd: z.ZodString;
            exit_code: z.ZodDefault<z.ZodNumber>;
            timeout_ms: z.ZodDefault<z.ZodNumber>;
        }, z.core.$strict>>;
    }, z.core.$strict>, z.ZodObject<{
        id: z.ZodString;
        kind: z.ZodLiteral<"external">;
        url: z.ZodString;
        description: z.ZodOptional<z.ZodString>;
        callback: z.ZodOptional<z.ZodObject<{
            param: z.ZodOptional<z.ZodString>;
            timeout_ms: z.ZodDefault<z.ZodNumber>;
        }, z.core.$strict>>;
        skip_if: z.ZodOptional<z.ZodObject<{
            cmd: z.ZodString;
            exit_code: z.ZodDefault<z.ZodNumber>;
            timeout_ms: z.ZodDefault<z.ZodNumber>;
        }, z.core.$strict>>;
        persist: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
            env: z.ZodString;
        }, z.core.$strict>, z.ZodObject<{
            secret_slug: z.ZodString;
        }, z.core.$strict>, z.ZodObject<{
            cmd: z.ZodString;
        }, z.core.$strict>]>>;
    }, z.core.$strict>], "kind">>>;
    auth: z.ZodOptional<z.ZodObject<{
        ref: z.ZodOptional<z.ZodString>;
        state: z.ZodOptional<z.ZodObject<{
            paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
            env: z.ZodOptional<z.ZodArray<z.ZodString>>;
        }, z.core.$strict>>;
        login: z.ZodOptional<z.ZodObject<{
            cmd: z.ZodString;
            interactive: z.ZodOptional<z.ZodBoolean>;
            requires_callback_url: z.ZodOptional<z.ZodBoolean>;
        }, z.core.$strict>>;
        refresh: z.ZodOptional<z.ZodObject<{
            cmd: z.ZodString;
            interval_s: z.ZodOptional<z.ZodNumber>;
        }, z.core.$strict>>;
        expiry: z.ZodOptional<z.ZodObject<{
            parse: z.ZodOptional<z.ZodString>;
            grace_s: z.ZodOptional<z.ZodNumber>;
        }, z.core.$strict>>;
    }, z.core.$strict>>;
    provider: z.ZodOptional<z.ZodString>;
    authSubscription: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
        setEnv: z.ZodOptional<z.ZodString>;
        external: z.ZodOptional<z.ZodBoolean>;
        conflictEnv: z.ZodOptional<z.ZodArray<z.ZodString>>;
        unsetEnvAdd: z.ZodOptional<z.ZodArray<z.ZodString>>;
        provider: z.ZodOptional<z.ZodString>;
    }, z.core.$strict>, z.ZodArray<z.ZodObject<{
        setEnv: z.ZodOptional<z.ZodString>;
        external: z.ZodOptional<z.ZodBoolean>;
        conflictEnv: z.ZodOptional<z.ZodArray<z.ZodString>>;
        unsetEnvAdd: z.ZodOptional<z.ZodArray<z.ZodString>>;
        provider: z.ZodOptional<z.ZodString>;
    }, z.core.$strict>>]>>;
    gatewayAuth: z.ZodOptional<z.ZodObject<{
        setEnv: z.ZodString;
    }, z.core.$strict>>;
    modelDerivedApiKey: z.ZodOptional<z.ZodBoolean>;
    routeSelection: z.ZodOptional<z.ZodEnum<{
        free: "free";
        "derived-from-model": "derived-from-model";
    }>>;
    authEnforce: z.ZodOptional<z.ZodEnum<{
        always: "always";
        "when-configured": "when-configured";
    }>>;
    sandbox: z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>]>;
    runner: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
    protocol: z.ZodEnum<{
        print: "print";
        acp: "acp";
        mcp: "mcp";
        proprietary: "proprietary";
    }>;
    acp: z.ZodOptional<z.ZodString>;
    mcp: z.ZodOptional<z.ZodObject<{
        command: z.ZodOptional<z.ZodString>;
        args: z.ZodOptional<z.ZodArray<z.ZodString>>;
        transport: z.ZodEnum<{
            stdio: "stdio";
            http: "http";
            sse: "sse";
        }>;
        url: z.ZodOptional<z.ZodString>;
    }, z.core.$strict>>;
    adapter: z.ZodOptional<z.ZodString>;
    print: z.ZodOptional<z.ZodObject<{
        prompt_flag: z.ZodOptional<z.ZodString>;
        output_format: z.ZodOptional<z.ZodArray<z.ZodString>>;
        pre_prompt: z.ZodOptional<z.ZodArray<z.ZodString>>;
        resume: z.ZodOptional<z.ZodObject<{
            flag: z.ZodString;
            kind: z.ZodEnum<{
                boolean: "boolean";
                value: "value";
            }>;
        }, z.core.$strict>>;
        event_schema: z.ZodOptional<z.ZodEnum<{
            "claude-stream-json": "claude-stream-json";
            "mastra-jsonl": "mastra-jsonl";
            "antigravity-stream-json": "antigravity-stream-json";
            "jcode-ndjson": "jcode-ndjson";
        }>>;
    }, z.core.$strict>>;
    session: z.ZodOptional<z.ZodObject<{
        mode: z.ZodDefault<z.ZodEnum<{
            ephemeral: "ephemeral";
            persistent: "persistent";
            resumable: "resumable";
        }>>;
        idle_timeout_ms: z.ZodDefault<z.ZodNumber>;
        turn_idle_timeout_ms: z.ZodOptional<z.ZodNumber>;
        max_turns: z.ZodOptional<z.ZodNumber>;
        context_carryover: z.ZodDefault<z.ZodBoolean>;
    }, z.core.$strict>>;
    models: z.ZodOptional<z.ZodObject<{
        default: z.ZodOptional<z.ZodString>;
        allowed: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
            id: z.ZodString;
            provider: z.ZodOptional<z.ZodString>;
            mode: z.ZodOptional<z.ZodString>;
        }, z.core.$strict>]>>>;
        deny: z.ZodOptional<z.ZodArray<z.ZodString>>;
        env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
        apply: z.ZodOptional<z.ZodEnum<{
            config: "config";
            command: "command";
            arg: "arg";
        }>>;
        bin_args_template: z.ZodOptional<z.ZodArray<z.ZodString>>;
    }, z.core.$strict>>;
    capabilities: z.ZodOptional<z.ZodObject<{
        streaming: z.ZodOptional<z.ZodBoolean>;
        tool_calls: z.ZodOptional<z.ZodBoolean>;
        sub_agents: z.ZodOptional<z.ZodBoolean>;
        file_io: z.ZodOptional<z.ZodBoolean>;
        multimodal: z.ZodOptional<z.ZodBoolean>;
        resumable: z.ZodOptional<z.ZodBoolean>;
        bidirectional: z.ZodOptional<z.ZodBoolean>;
        nativeTerminalResume: z.ZodOptional<z.ZodBoolean>;
        file_attach: z.ZodOptional<z.ZodBoolean>;
    }, z.core.$strict>>;
    modes: z.ZodOptional<z.ZodArray<z.ZodObject<{
        id: z.ZodString;
        description: z.ZodOptional<z.ZodString>;
        kind: z.ZodOptional<z.ZodEnum<{
            context: "context";
        }>>;
        bin_args_prepend: z.ZodOptional<z.ZodArray<z.ZodString>>;
        bin_args_append: z.ZodOptional<z.ZodArray<z.ZodString>>;
        env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
        env_unset: z.ZodOptional<z.ZodArray<z.ZodString>>;
        status: z.ZodOptional<z.ZodEnum<{
            active: "active";
            noop: "noop";
            planned: "planned";
        }>>;
        status_note: z.ZodOptional<z.ZodString>;
        apply: z.ZodOptional<z.ZodEnum<{
            config: "config";
            bin_args: "bin_args";
        }>>;
    }, z.core.$strict>>>;
    options: z.ZodOptional<z.ZodArray<z.ZodObject<{
        id: z.ZodString;
        type: z.ZodEnum<{
            string: "string";
            boolean: "boolean";
            enum: "enum";
            integer: "integer";
        }>;
        description: z.ZodOptional<z.ZodString>;
        enum: z.ZodOptional<z.ZodArray<z.ZodString>>;
        default: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodNumber, z.ZodString]>>;
        min: z.ZodOptional<z.ZodNumber>;
        max: z.ZodOptional<z.ZodNumber>;
        bin_args_prepend: z.ZodOptional<z.ZodArray<z.ZodString>>;
        bin_args_template: z.ZodOptional<z.ZodArray<z.ZodString>>;
        bin_args_append_when_true: z.ZodOptional<z.ZodArray<z.ZodString>>;
        env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
        env_unset: z.ZodOptional<z.ZodArray<z.ZodString>>;
    }, z.core.$strict>>>;
    presets: z.ZodOptional<z.ZodArray<z.ZodObject<{
        id: z.ZodString;
        label: z.ZodString;
        description: z.ZodOptional<z.ZodString>;
        schemaFlavor: z.ZodEnum<{
            anthropic: "anthropic";
            openai: "openai";
        }>;
        baseUrl: z.ZodString;
        keyEnv: z.ZodString;
        scrubEnv: z.ZodOptional<z.ZodArray<z.ZodString>>;
        defaultModel: z.ZodOptional<z.ZodString>;
        homepage: z.ZodOptional<z.ZodString>;
    }, z.core.$strict>>>;
    continuation: z.ZodOptional<z.ZodObject<{
        default: z.ZodEnum<{
            none: "none";
            "pinned-session": "pinned-session";
            transcript: "transcript";
            "native-resume": "native-resume";
        }>;
        supported: z.ZodArray<z.ZodEnum<{
            none: "none";
            "pinned-session": "pinned-session";
            transcript: "transcript";
            "native-resume": "native-resume";
        }>>;
        pinned_session: z.ZodOptional<z.ZodObject<{
            idle_timeout_ms: z.ZodDefault<z.ZodNumber>;
            key_scope: z.ZodDefault<z.ZodArray<z.ZodEnum<{
                conversation: "conversation";
                operator: "operator";
                user: "user";
                guild: "guild";
                workspace: "workspace";
            }>>>;
        }, z.core.$strict>>;
    }, z.core.$strict>>;
    requires: z.ZodOptional<z.ZodObject<{
        os: z.ZodOptional<z.ZodArray<z.ZodEnum<{
            darwin: "darwin";
            linux: "linux";
            windows: "windows";
        }>>>;
        arch: z.ZodOptional<z.ZodArray<z.ZodEnum<{
            x64: "x64";
            arm64: "arm64";
            x86: "x86";
            arm: "arm";
        }>>>;
        min_disk_mb: z.ZodOptional<z.ZodNumber>;
        min_memory_mb: z.ZodOptional<z.ZodNumber>;
    }, z.core.$strict>>;
    examples: z.ZodOptional<z.ZodArray<z.ZodObject<{
        goal: z.ZodString;
        prompt: z.ZodString;
        note: z.ZodOptional<z.ZodString>;
    }, z.core.$strict>>>;
    tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
    metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
}, z.core.$strict>;
type AgentCliFrontmatter = z.infer<typeof agentCliFrontmatterSchema>;
declare const runtimeConfigSchema: z.ZodObject<{
    mode: z.ZodOptional<z.ZodString>;
    options: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodBoolean, z.ZodNumber, z.ZodString]>>>;
    continuation: z.ZodOptional<z.ZodEnum<{
        none: "none";
        "pinned-session": "pinned-session";
        transcript: "transcript";
        "native-resume": "native-resume";
    }>>;
}, z.core.$strict>;
type RuntimeConfigInput = z.infer<typeof runtimeConfigSchema>;

export { type AgentCliHandle as A, type AgentCliSetupPersist as B, type ContinuationStrategyId as C, type AgentCliSetupSkipIf as D, type AgentCliSetupStep as E, type AgentCliVersionCheck as F, type RuntimeConfigInput as G, type SetEffortResult as H, type SetSessionModeResult as I, type SteerOutcome as J, agentCliFrontmatterSchema as K, runtimeConfigSchema as L, type RuntimeConfig as R, type SetModelResult as S, type TurnContext as T, type AgentCliRuntime as a, type AgentCliDefinition as b, type AgentCliRuntimeSession as c, type AgentCliClient as d, type AgentCliPrintConfig as e, type AgentCliStartOptions as f, type ContinuationKeyScope as g, type AgentCliAuth as h, type AgentCliCapabilities as i, type AgentCliConnectOptions as j, type AgentCliContinuation as k, type AgentCliFrontmatter as l, type AgentCliFsZones as m, type AgentCliInstallMethod as n, type AgentCliMcpBlock as o, type AgentCliMode as p, type AgentCliModelEntry as q, type AgentCliModels as r, type AgentCliOption as s, type AgentCliOptionType as t, type AgentCliPinnedSessionTuning as u, type AgentCliPresetDeclaration as v, type AgentCliProtocol as w, type AgentCliRouteSelection as x, type AgentCliSession as y, type AgentCliSessionMode as z };
