/**
 * EnrollmentWizard — mobile-first login orchestration (P2.1 of the Subscription
 * & Auth Standard). Sits on top of PendingLoginStore and turns a raw framework
 * login into a phone-friendly, expiry-resilient flow.
 *
 * The job (from the spec + the pi live-test specimen):
 *   - START a login: drive the framework's login flow, capture the PUBLIC
 *     device-code / auth URL, and store it with its TTL visible. (Codex →
 *     device-code; Claude → URL+paste-back-code.)
 *   - On EXPIRY: auto-reissue a fresh code/URL WITHOUT the operator asking — the
 *     exact gap the pi live-test exposed (the first code expired before Justin
 *     got to it and re-issuing took a manual round-trip).
 *   - COMPLETE when the operator approves at the provider + the account enrols.
 *
 * The interactive part — actually driving the framework's login CLI to obtain a
 * code/URL — is INJECTED (`driveLogin`), so this orchestrator is pure +
 * hermetically testable (no spawning, no network, no real OAuth). In production
 * the driver runs the framework's device-code/login flow and scrapes the code +
 * URL + TTL; here tests pass a stub. NEVER handles a credential — only the
 * public code/URL the operator types into the provider's own page.
 */
import { PendingLoginStore, type PendingLogin, type LoginFlowKind, type LoginProvider } from './PendingLoginStore.js';
import { type EnsureInteractiveReadyResult } from './ensureInteractiveReady.js';
/** The public artifact a framework login yields (no secret). */
export interface LoginArtifact {
    verificationUrl: string;
    userCode?: string;
    ttlMs?: number;
}
/** Injected: drive the framework's login flow, return its public code/URL. */
export type LoginDriver = (req: {
    provider: LoginProvider;
    framework: PendingLogin['framework'];
    kind: LoginFlowKind;
    /** The new account's CLAUDE_CONFIG_DIR — isolates this login to its own slot
     *  so enrolling a 2nd account never clobbers the 1st. */
    configHome?: string;
}) => Promise<LoginArtifact>;
export interface EnrollmentWizardConfig {
    store: PendingLoginStore;
    driveLogin: LoginDriver;
    now?: () => number;
    logger?: {
        log: (m: string) => void;
        warn: (m: string) => void;
    };
    /**
     * Onboarding-readiness seeder run when a claude-code enrollment completes
     * (2026-06-09 incident: `claude auth login` is headless-only — it stores
     * tokens but never sets the interactive first-launch flags, so the new
     * home wedges the first interactive session pinned/swapped onto it).
     * Injectable for hermetic tests; production uses the real util.
     */
    ensureReady?: (configHome: string) => EnsureInteractiveReadyResult;
}
export interface StartEnrollmentInput {
    id: string;
    label: string;
    provider: LoginProvider;
    framework: PendingLogin['framework'];
    /** device-code (Codex) or url-code-paste (Claude). Defaults per provider. */
    kind?: LoginFlowKind;
    /** The new account's CLAUDE_CONFIG_DIR — isolates the login to its own slot. */
    configHome?: string;
}
export declare class EnrollmentWizard {
    private readonly store;
    private readonly driveLogin;
    private readonly logger;
    private readonly ensureReady;
    constructor(cfg: EnrollmentWizardConfig);
    /** Default flow kind per provider: Codex/OpenAI = device-code (its endorsed
     *  flow); everyone else = url-code-paste (the phone-friendly Claude path). */
    static defaultKind(provider: LoginProvider): LoginFlowKind;
    /**
     * Operator-facing heads-up about a flow's quirks, surfaced on the pending login.
     * The url-code-paste (Claude) flow on a brand-new account slot frequently issues
     * TWO codes in sequence: Anthropic first emails an email-VERIFICATION code, then
     * (after that's accepted) the page shows the sign-in code to paste back. Enrolling
     * is always a new slot, so the operator should expect — and not be confused by —
     * the two-step sequence (this confusion was flagged in live testing, topic 20905).
     * device-code (Codex) is a single code, so no notice. Returns undefined when there
     * is nothing to warn about.
     */
    static flowNotice(kind: LoginFlowKind): string | undefined;
    /**
     * Start an enrollment: drive the login, capture the public code/URL, store it
     * as a pending login (TTL visible). Returns the stored PendingLogin — the
     * surface the operator's phone shows.
     */
    start(input: StartEnrollmentInput): Promise<PendingLogin>;
    /**
     * Auto-reissue every EXPIRED pending login without the operator asking — the
     * pi-live-test gap. For each expired login, re-drive the framework flow and
     * refresh the stored code/URL + TTL. Returns the reissued logins. Driver
     * failures are skipped (logged, left expired) so one bad re-drive doesn't
     * abort the sweep.
     */
    reissueExpired(): Promise<PendingLogin[]>;
    /**
     * Mark a login completed once the operator approved + the account enrolled.
     * For a claude-code enrollment with a per-account config home, also seed the
     * interactive onboarding flags — the login itself was headless, so without
     * this the freshly-enrolled home wedges the first interactive session that
     * pins/swaps onto it (2026-06-09 incident). Fail-safe: a seeding failure is
     * logged, never blocks completion (the launch paths re-ensure defensively).
     */
    complete(id: string): PendingLogin | null;
    /** The phone surface: still-valid logins awaiting approval. */
    pending(): PendingLogin[];
}
//# sourceMappingURL=EnrollmentWizard.d.ts.map