/**
 * Shared interactive step engine for `agents harness` create + edit.
 *
 * A single engine drives BOTH the create wizard (`agents harness add`/`fork`,
 * previously `runHarnessWizard`) and the new edit wizard (`agents harness edit`,
 * which was flag-only before). A "step" is a self-contained unit — decide whether
 * it runs for the current draft, then prompt/validate/apply — so the two modes
 * differ only in their step list, not in the runner.
 *
 * Design goals (RUSH-2219, parent RUSH-2218):
 *   - One runner, two modes. `create` builds a new harness from a source; `edit`
 *     loads an existing profile and re-asks each field pre-filled with its value.
 *   - Every step is skippable. A flag that already supplied the value pre-fills
 *     the draft and its step is not re-asked — so non-interactive scripting via
 *     flags is unchanged and the wizard only asks for what is missing.
 *   - Pure and injectable. The engine talks to the user through {@link WizardIO},
 *     an injected seam. Tests drive a scripted fake IO and assert which steps ran,
 *     with no TTY. {@link defaultWizardIO} is the production driver over
 *     `@inquirer/prompts`.
 *   - Typed extension points, not stubs. The three sibling subtasks plug in via
 *     {@link WizardHooks} without editing the engine: RUSH-2220 (model catalog +
 *     secrets surface) via `pickModel`, RUSH-2221 (connection test) via
 *     `connectionTest`, RUSH-2222 (edit matrix) via `editable`. Each hook is a
 *     real no-op extension point — absent, the scaffold falls back to today's
 *     behavior (free-text model, no test, resolver-sourced editability). None of
 *     them fakes a result. RUSH-2223 (cross-host portability, `fork --to-host`)
 *     extends the create source step; the seam is `HarnessDraft.toHost`.
 */
import type { AgentId } from '../lib/types.js';
import { type Profile } from '../lib/profiles.js';
import type { ConnectionTestResult } from '../lib/harness-connection-test.js';
export type { ConnectionTestResult } from '../lib/harness-connection-test.js';
/** Whether the wizard is creating a new harness or editing an existing one. */
export type WizardMode = 'create' | 'edit';
/** A single `select` choice. `disabled` greys the row (used by the edit matrix). */
export interface WizardChoice<T> {
    name: string;
    value: T;
    disabled?: boolean | string;
}
/**
 * The prompt seam the engine drives. Injected so the engine is testable with no
 * TTY: the production implementation ({@link defaultWizardIO}) wraps
 * `@inquirer/prompts`; a test passes a scripted fake that records calls and
 * returns canned answers.
 */
export interface WizardIO {
    select<T>(opts: {
        message: string;
        choices: WizardChoice<T>[];
        default?: T;
    }): Promise<T>;
    input(opts: {
        message: string;
        default?: string;
        validate?: (v: string) => true | string;
    }): Promise<string>;
    password(opts: {
        message: string;
    }): Promise<string>;
    confirm(opts: {
        message: string;
        default?: boolean;
    }): Promise<boolean>;
    /** Emit an informational line — a disabled field's reason, or a preset note. */
    note(message: string): void;
}
/**
 * The mutable draft threaded through every step. It is a superset of both modes'
 * fields; a step reads what it needs and records its answer here. `create` maps
 * the finished draft into `{ source, name, opts }` for `runForkFlow`; `edit` maps
 * it into the `EditOptions` shape the flag-driven edit path already persists — so
 * a wizard-built and a hand-written harness are byte-identical after save.
 */
export interface HarnessDraft {
    readonly mode: WizardMode;
    /** create: the fork source (a native agent id or an existing harness name). */
    source?: string;
    /** The resolved host CLI — drives the editability seams. edit: the profile host. */
    host?: AgentId;
    name?: string;
    model?: string;
    baseUrl?: string;
    authProvider?: string;
    account?: string;
    /** `<bundle>` or `<bundle>:<key>` — a value copied out of an agents secrets bundle. */
    fromSecrets?: string;
    version?: string;
    description?: string;
    fallbackModel?: string;
    /** edit: the profile being edited, providing current values. Read-only. */
    readonly original?: Profile;
    /**
     * RUSH-2223 seam (cross-host portability): the target host to re-key a cloned
     * harness onto (`fork --to-host <host>`). The scaffold never sets it; the
     * portability subtask reads it in an extended source step. Left here so the
     * draft shape is stable when that lands.
     */
    toHost?: AgentId;
    /** The user chose "build custom" over a preset (create only). */
    custom?: boolean;
    /** The preset a create run selected, if any. */
    preset?: string;
    /** Pre-computed default for the name prompt (source or preset name). */
    defaultName?: string;
    /** The provider step has run (distinguishes "no auth chosen" from "not asked"). */
    providerAsked?: boolean;
}
/**
 * What the engine does with a step for a given draft:
 *   - `'run'`             prompt the user, validate, and apply into the draft.
 *   - `'skip'`            value already supplied (by a flag) or step N/A — silent.
 *   - `{ disabled: … }`   the step does not apply to this host; surface the reason
 *                         (the field reads as greyed/disabled) but do not prompt.
 *                         This is the seam the edit matrix (RUSH-2222) drives.
 */
export type StepDecision = 'run' | 'skip' | {
    disabled: string;
};
/** One wizard step: decide, then (only when decided `'run'`) prompt + apply. */
export interface WizardStep {
    readonly id: string;
    decide(draft: HarnessDraft): StepDecision;
    run(io: WizardIO, draft: HarnessDraft, hooks: WizardHooks): Promise<void>;
}
/** Per-host editability — which params this host's API format lets you change. */
export interface HarnessEditable {
    model: boolean;
    baseUrl: boolean;
    auth: boolean;
    version: boolean;
    fallback: boolean;
}
/** One field's editability plus, when disabled, the one-line reason to surface. */
export interface EditableField {
    enabled: boolean;
    /** Set only when `enabled` is false — the greyed field's stated reason. */
    reason?: string;
}
/** Per-host editability with a reason attached to every disabled field. */
export interface HarnessEditability {
    model: EditableField;
    baseUrl: EditableField;
    auth: EditableField;
    version: EditableField;
    fallback: EditableField;
}
/**
 * The per-harness editability matrix (RUSH-2222). Which of a harness's params
 * this host's API format actually lets you change, each disabled field carrying
 * the reason the wizard greys it with.
 *
 * Sourced ENTIRELY from the same maps the run-time resolver reads —
 * `baseUrlEnvKeyForHost` (endpoint slot), `authEnvKeyForHost` (auth env), and
 * `isSelfUpdatingAgent` (pinnable version) — never a table hardcoded alongside
 * them, so the wizard's enable/disable can never drift from what a run actually
 * honors (repo rule: the capability table stays truthful, in lockstep with the
 * code). A disabled param is never a silent no-op — the wizard shows its reason
 * and the flag path fails loud (`forkProfile`'s base-URL throw is the precedent).
 */
export declare function harnessEditable(host: AgentId): HarnessEditability;
/**
 * The boolean projection of {@link harnessEditable} — the scaffold default behind
 * the RUSH-2222 {@link WizardHooks.editable} seam. Derived from the reason-carrying
 * matrix so the two can never disagree.
 */
export declare function defaultEditable(host: AgentId): HarnessEditable;
/**
 * Extension points the sibling subtasks fill without touching the engine. Each is
 * a real no-op-by-default seam: absent, the scaffold uses today's behavior; none
 * fabricates a result.
 */
export interface WizardHooks {
    /**
     * RUSH-2220 — model catalog pick. Given the resolved host (+ version and the
     * current value in edit), return a chosen model id, or `null` to fall through
     * to the free-text prompt. Absent → always free-text (today's behavior).
     */
    pickModel?: (io: WizardIO, host: AgentId | undefined, version: string | undefined, current: string | undefined) => Promise<string | null>;
    /**
     * RUSH-2221 — connection test after configure, before save. Absent → no test
     * (the wizard saves without one, exactly as today).
     */
    connectionTest?: (draft: HarnessDraft) => Promise<ConnectionTestResult>;
    /**
     * RUSH-2222 — per-host editability matrix. Absent → {@link defaultEditable}.
     */
    editable?: (host: AgentId) => HarnessEditable;
}
/** Resolve the host CLI a fork `source` runs under (the host `buildFork` will use). */
export declare function hostForSource(source: string | undefined): AgentId | undefined;
/**
 * The engine. Walk the steps in order; for each, ask `decide` what to do, then
 * prompt only when it says `'run'`. A `{ disabled }` decision surfaces the reason
 * and moves on; `'skip'` is silent. Returns the finished draft.
 */
export declare function runWizardSteps(steps: WizardStep[], draft: HarnessDraft, io: WizardIO, hooks?: WizardHooks): Promise<HarnessDraft>;
/**
 * The create step list — the shape of `agents harness add`/`fork`. Faithful to
 * the previous `runHarnessWizard` sequence (source → preset|custom → model →
 * provider → base URL → name → key source), re-expressed as engine steps so the
 * sibling subtasks can gate/replace individual steps. Produces the same
 * `{ source, name, opts }` draft the fork flow already persists.
 */
export declare function createSteps(): WizardStep[];
/**
 * The edit step list — `agents harness edit <name>` with no flags on a TTY. Each
 * step is pre-filled with the profile's current value and gated by the host's
 * editability matrix (RUSH-2222 seam): an unsupported param reads as disabled with
 * a reason instead of being silently accepted. Records into the same draft, which
 * `runEditWizard` maps to the `EditOptions` shape the flag path already persists.
 */
export declare function editSteps(original: Profile): WizardStep[];
/**
 * Run the connection-test hook against a finished draft, if one is wired
 * (RUSH-2221). Returns `null` when no hook is present (no test performed) so the
 * caller can distinguish "not tested" from "tested and passed". Separated from the
 * step list because the test needs the assembled profile, which the caller builds.
 */
export declare function runConnectionTest(draft: HarnessDraft, hooks: WizardHooks): Promise<ConnectionTestResult | null>;
/**
 * Production {@link WizardIO} over `@inquirer/prompts`, lazy-imported so the
 * dependency loads only when a wizard actually runs. `note` prints to stderr so it
 * never contaminates a `--json`/piped stdout.
 */
export declare function defaultWizardIO(): Promise<WizardIO>;
