import type { DoctorReport, DoctorScope, runDoctor } from "./Doctor.js"; import type { LinuxDistribution } from "./LinuxHopper.js"; import type { SetupClient } from "./SupportedClients.js"; import type { SetupFailureCode, SetupHopperInstallResult, } from "./SetupInstallFailure.js"; /** Exact non-secret provider variables propagated into managed registrations. */ export type SetupProviderEnvironment = Readonly>; /** Read-only host facts shared by the initial setup plan. */ export interface SetupInitialState { readonly hopperPath?: string; readonly providerEnvironment: SetupProviderEnvironment; readonly doctor: DoctorReport; } /** Result of one backup/write/readback transaction. */ export type ClientConfigurationResult = | { readonly status: "unchanged" | "configured" | "skipped"; readonly backupPath?: string; } | { readonly status: "failed"; readonly reason: "path" | "backup" | "write" | "readback"; }; /** Read-only state used to block unsafe setup plans before any mutation. */ export type ClientConfigurationInspection = | { readonly status: "already_current" } | { readonly status: "create" | "update"; readonly backupPath?: string; } | { readonly status: "invalid"; readonly remediation: string; }; /** Effects required by the idempotent, non-blocking setup workflow. */ export interface SetupHost { readonly platform: NodeJS.Platform; readonly nodeVersion: string; macosVersion(): Promise; linuxDistribution(): Promise; hopperPath(): Promise; initialSetupState?(scope?: DoctorScope): Promise; installHopper(replaceExisting: boolean): Promise; providerEnvironment?(): Promise; detectedClients(): Promise; supportedClients?(): Promise; configureClient( client: SetupClient, providerEnvironment: SetupProviderEnvironment, command: readonly string[], ): Promise; clientNeedsConfigure( client: SetupClient, providerEnvironment: SetupProviderEnvironment, command: readonly string[], ): Promise; inspectClientConfiguration?( client: SetupClient, providerEnvironment: SetupProviderEnvironment, command: readonly string[], ): Promise; skillNeedsInstall(): Promise; installSkill(): Promise<"installed" | "unchanged" | "failed">; doctor(scope?: DoctorScope): Promise>>; } /** Structured setup outcome carrying remediation instead of prompting. */ export interface SetupResult { readonly status: | "planned" | "cancelled" | "needs_confirmation" | "ready" | "needs_human"; readonly plannedActions: readonly SetupAction[]; readonly appliedActions: readonly string[]; readonly clients: Readonly>; readonly doctor: SetupDoctorSummary; /** Supported-client discovery state captured before setup mutations. */ readonly clientStates: readonly SetupClientState[]; readonly remediation?: string; readonly code?: SetupFailureCode; } /** Whether the requested setup actions still need approval or human repair. */ export const isSetupFailure = (result: SetupResult): boolean => { const status = result.status; switch (status) { case "planned": case "cancelled": case "ready": return false; case "needs_confirmation": case "needs_human": return true; default: { const exhaustive: never = status; throw new TypeError( `Unhandled setup result status: ${String(exhaustive)}`, ); } } }; /** Relevant health and identity evidence for the selected setup scope. */ export interface SetupDoctorSummary { readonly healthy: boolean; readonly environment_healthy: boolean; readonly scope: DoctorReport["scope"]; readonly hopperPath?: string; readonly availableProviders: readonly string[]; readonly providerInspections?: DoctorReport["providerInspections"]; readonly identity?: Pick< NonNullable, "skill" | "registrations" >; } /** Read-only state for one supported client location. */ export interface SetupClientState { readonly client: SetupClient; readonly detected: boolean; readonly configured: boolean; readonly status: "configured" | "missing" | "needs_configuration" | "invalid"; } /** One concrete setup mutation disclosed before approval. */ export interface SetupAction { readonly id: string; readonly kind: "install_hopper" | "configure_client" | "install_skill"; readonly label: string; readonly target: string; readonly detail: string; readonly external: boolean; readonly operation: "create" | "update" | "install"; readonly backupPath?: string; readonly networkOrigins?: readonly string[]; readonly commands?: readonly string[]; readonly integrity?: string; } /** Explicit authorization supplied by an interactive or unattended CLI adapter. */ export interface SetupOptions { readonly approved: boolean; readonly installHopper: boolean; readonly structured: boolean; readonly proposeHopper?: boolean; readonly clientIds?: readonly string[]; readonly installSkill?: boolean; readonly readinessScope?: DoctorScope; readonly dryRun?: boolean; readonly allDetectedClients?: boolean; readonly onProgress?: (event: SetupProgressEvent) => void; } /** One settled or active setup operation projected to the interactive adapter. */ export interface SetupProgressEvent { readonly actionId: string; readonly label: string; readonly state: "started" | "completed" | "warning" | "failed"; readonly detail?: string; } /** Interactive selection and final consent returned by the CLI adapter. */ export interface SetupConfirmationDecision { readonly approved: boolean; readonly selectedActionIds: readonly string[]; readonly cancelled?: boolean; } /** Read-only context shown while selecting clients or reviewing exact actions. */ export interface SetupConfirmationContext { readonly stage: "select" | "confirm"; readonly clientStates: readonly SetupClientState[]; readonly selectedClientIds: readonly string[]; readonly clientSelectionAllowed: boolean; } /** Adapter-owned selection and confirmation for the setup workflow. */ export type SetupConfirmation = ( actions: readonly SetupAction[], context?: SetupConfirmationContext, ) => Promise;