/** * Host-installation convergence for `h2a doctor`. * * The h2a plugin is the canonical host integration. A direct `mcp-serve` * configuration alongside that plugin starts a second endpoint, and the old * standalone Track MCP starts a competing projection of `track_*` tools. This * module treats both as an incoherent installation rather than a warning. * * Host plugin CLIs retain authority over their own installation registries. * Doctor repairs their plain configuration/cache residue itself, then asks the * native CLI to install/update the canonical `h2a@sentropic` plugin. A command * failure is retained as an unrepaired finding; it must never become a clean * result merely because a config file was edited. */ import type { H2ASession } from "../session.js"; export declare const H2A_PLUGIN_SELECTOR = "h2a@sentropic"; export declare const H2A_MARKETPLACE_NAME = "sentropic"; export declare const H2A_MARKETPLACE_REPOSITORY = "rhanka/h2a"; export declare const H2A_MARKETPLACE_GIT_URL = "https://github.com/rhanka/h2a.git"; export declare const HOST_REPAIR_FRESHNESS_GUARANTEE = "doctor guarantees the coherence of the repairs it performed. It does not detect installation changes made by other tools; after changing your installation by hand, restart your sessions."; export declare const HOST_REPAIR_NATIVE_COMMAND_FAILURE_LIMIT = "If a native host CLI fails after it has already changed the installation, doctor reports the failure as host-command-failed and does not undo what that CLI already did. Doctor's own configuration writes are atomic. It has no snapshot of third-party state and does not simulate one: a partial restore would promise a recovery it cannot deliver. After a reported native failure, verify the host installation before relying on it."; type Host = "claude" | "codex"; export interface HostCommandResult { readonly ok: boolean; readonly message?: string; } export type HostCommandRunner = (command: "claude" | "codex", args: readonly string[]) => HostCommandResult; export interface HostInstallationDoctorOptions { readonly home?: string; /** `false` is inspect-only. `true` performs the documented repair. */ readonly repair?: boolean; /** Injectable for hermetic tests; production uses the running CLI version. */ readonly version?: string; /** Injectable for hermetic tests; production invokes the native host CLI. */ readonly runHostCommand?: HostCommandRunner; /** Test-only native-CLI reachability override; configuration artifacts decide host installation. */ readonly testHostCliReachable?: (host: Host) => boolean; /** Test-only responses from the known-good and candidate Codex configuration probes. */ readonly testCodexConfigurationOracle?: { readonly knownGood: HostCommandResult; readonly candidate: HostCommandResult; }; /** Test-only responses from the known-good and candidate Claude configuration probes. */ readonly testClaudeConfigurationOracle?: { readonly knownGood: HostCommandResult; readonly candidate: HostCommandResult; }; /** Injectable for hermetic tests; production writes the durable repair marker. */ readonly writeRepairMarker?: (path: string, content: string) => void; /** Report host repair findings and planned actions without mutating the host. */ readonly dryRun?: boolean; /** Test-only Claude uninstall requests used to exercise the native-command boundary. */ readonly testClaudePluginUninstalls?: readonly string[]; /** Test-only fault injection for the atomic configuration-write boundary. */ readonly testConfigurationWrite?: { readonly mutateRendered?: (path: string, format: "json" | "toml", rendered: string) => string; readonly beforeRename?: (path: string, temporaryPath: string) => void; readonly rename?: (temporaryPath: string, path: string) => void; }; } export interface HostInstallationFinding { readonly code: "config-preserved" | "config-invalid" | "marketplace-missing" | "marketplace-stale" | "plugin-missing" | "plugin-stale" | "version-skew" | "orphan-cache" | "h2a-endpoint-count" | "standalone-track-mcp" | "host-command-failed" | "host-command-refused" | "host-command-unavailable" | "host-cli-unreachable" | "host-cli-unavailable" | "host-config-unavailable" | "host-config-unverifiable" | "host-not-installed" | "ownership-unverified" | "repair-marker-unavailable" | "repair-marker-write-failed" | "runtime-artifact-unavailable"; readonly message: string; readonly path?: string; } export interface HostRepairMarker { readonly path: string; readonly repairedAt: string; /** Concrete paths that a completed repair actually changed. */ readonly repairedPaths: readonly string[]; } export interface HostInstallationReport { readonly host: Host; readonly ok: boolean; readonly findings: readonly HostInstallationFinding[]; /** Non-blocking inspection notes; never a host-health or session-freshness verdict. */ readonly diagnostics: readonly HostInstallationFinding[]; readonly changed: readonly string[]; /** Deliberately retained host state, named precisely and never a health failure. */ readonly preserved: readonly HostInstallationFinding[]; /** Operations doctor attempted but could not complete; always prevent a healthy host verdict. */ readonly failures: readonly HostInstallationFinding[]; /** State doctor needed to verify but could not establish safely; always prevents a healthy host verdict. */ readonly unverifiable: readonly HostInstallationFinding[]; /** Backward-compatible flat view of blocking failures and unverifiable state. */ readonly unrepaired: readonly HostInstallationFinding[]; /** Declared artifacts retained for diagnostics and to determine precisely what a repair rewrote. */ readonly coherencePaths: readonly string[]; /** Host actions proposed by doctor; legacy-plugin transitions retain their prior value. */ readonly plannedActions: readonly string[]; /** Expected durable repair-marker location, whether or not it currently exists. */ readonly repairMarkerPath: string; /** Durable fact recorded after this host installation was repaired. */ readonly repairMarker?: HostRepairMarker; } export interface HostInstallationDoctorReport { readonly ok: boolean; readonly repair: boolean; readonly dryRun: boolean; /** Exact boundary of the live-session restart guarantee. */ readonly sessionFreshnessGuarantee: string; /** Exact boundary of recovery from a native host CLI failure. */ readonly nativeCommandFailureLimit: string; readonly version: string; readonly hosts: readonly HostInstallationReport[]; } export interface LiveHostSessionFinding { readonly host: Host; readonly sessionId: string; readonly startedAt: string; readonly configPath: string; readonly message: string; } export interface LegacyAccountArtifactsDiagnostic { /** This diagnostic is informational: retained files are inert in current H2A. */ readonly ok: true; readonly inert: true; /** Paths checked by existence only; their contents are never opened. */ readonly inspected: readonly string[]; readonly found: readonly string[]; readonly message: string; } /** * Detect files written by the removed H2A account pool without reading or * parsing them. They may contain secrets, so doctor only reports their paths * and never mutates them. */ export declare function inspectLegacyAccountArtifacts(home?: string): LegacyAccountArtifactsDiagnostic; /** Inspect, and optionally repair, the H2A installation state of both supported hosts. */ export declare function doctorHostInstallations(options?: HostInstallationDoctorOptions): HostInstallationDoctorReport; /** * A host repair cannot rewire an already-open stdio connection. A recorded * repair marker is authoritative for our repairs. Doctor does not infer the * complete runtime load graph, so externally modified artifacts are diagnostic * only and never become a live-session freshness verdict. */ export declare function findLiveSessionsPredatingHostConfig(sessions: readonly H2ASession[], hosts: readonly HostInstallationReport[]): LiveHostSessionFinding[]; export {}; //# sourceMappingURL=installation-doctor.d.ts.map