/** * First-run doctor — environment probes + actionable install hints. * * The CLI runs onboarding on first launch (no `~/.gg/auth.json` and no * `~/.gg/onboarded-ggeditor` marker). The same checks are exposed via * `ggeditor doctor` so users can re-run it any time. * * Design rules: * - Probes only. We never auto-install anything — surprise sudo * prompts are worse than a missing dep. * - Each check carries `severity`: * block — nothing meaningful works without it (none currently; * the agent can run with zero deps) * required — most tools need it (ffmpeg / ffprobe) * optional — unlocks a feature group (openai-key, resolve, * premiere, whisper-cpp, whisperx) * info — purely informational (auth status) * - Each check tells the user EXACTLY what to do to fix it, including * the platform-appropriate install command. * - Pure module — no I/O writes, no side effects beyond `spawnSync` / * `existsSync` probes. */ export type CheckSeverity = "block" | "required" | "optional" | "info"; export type CheckStatus = "ok" | "missing" | "warn"; /** * Structured install hint. When present, the doctor's interactive flow * can offer to spawn this command after a Y/N confirmation — no copy- * paste, no shell injection (we never run a string through `sh -c`). * * Only attached to checks where the install is a single packaged step * (Homebrew formula, winget id, apt package). Items that need manual * sign-up (API keys), license acceptance (Resolve installer), or * multi-step setup (whisperx + HF_TOKEN) carry a `fix` string instead. */ export interface InstallableHint { /** Human label shown in the prompt: "Install ffmpeg via Homebrew". */ label: string; /** Executable on PATH. */ command: string; /** Argument vector — NEVER a shell string. */ args: string[]; /** * What managed manager this uses. Used by the renderer to decide * whether to show "requires sudo" copy. */ manager: "homebrew" | "winget" | "apt" | "pip" | "npm"; /** True when the command requires elevated privileges (sudo / admin). */ needsSudo?: boolean; } /** * Structured prompt action. When present, the doctor's interactive * screen can capture a secret (API key, token) directly and persist * it to the api-keys store — no "open another terminal and run * export X=..." busywork. * * Persistence is on the runner side; this struct just describes WHAT * to capture and WHERE to put it (`store` is a stable id used by * `setStoredApiKey`). */ export interface PromptHint { /** Title shown above the input: "Paste your OpenAI API key". */ label: string; /** Optional one-line guidance under the title (URL where to get it). */ hint?: string; /** ApiKeyName from auth/api-keys.ts — "openai" | "huggingface". */ store: "openai" | "huggingface"; /** Lightweight format check; rejects obviously-wrong input. */ validate?: (value: string) => string | undefined; } export interface DoctorCheck { /** Stable id (also the check key). */ id: string; /** ≤30 char display label. */ label: string; status: CheckStatus; severity: CheckSeverity; /** One-line current state ("v6.1.1 found", "not on PATH", …). */ detail: string; /** * What this check unlocks for the user. Always present, even when * status=ok — gives the user the mental model. */ unlocks: string; /** * Optional structured install command for items where a single * package-manager invocation does the job. The CLI offers Y/N * confirmation and spawns it directly. */ installable?: InstallableHint; /** * Optional inline secret prompt (API key / token). When the user hits * Enter on this item the doctor captures the value and persists it * to ~/.gg/api-keys.json. Mutually exclusive with `installable` per * action; if both are present, install runs first then prompt. */ prompt?: PromptHint; /** * Free-form fix copy for the static `--all` / non-interactive path. * The interactive screen IGNORES this — it uses installable/prompt. * Multi-line is fine here; only `--all` renders it. */ fix?: string; } export interface DoctorReport { checks: DoctorCheck[]; /** True when no `severity=required` check is missing. */ ready: boolean; /** Where the marker file was/should be written. */ markerPath: string; /** Whether onboarding has been completed before. */ onboarded: boolean; } export declare function onboardedMarkerPath(home?: string): string; export declare function isOnboarded(home?: string): boolean; /** * Run every check. Synchronous and quick — only spawns short-lived * `--version` style probes. */ export declare function runDoctor(home?: string): DoctorReport; //# sourceMappingURL=doctor.d.ts.map