import { type Cli } from "../internals/clis.js"; import { type DigestAction, type PlanContext } from "../internals/plan.js"; import { type CliLoadability } from "./cli-loadability.js"; /** * PER-CLI WIRING — the truth model behind "AI CLI coverage". The legacy surfaces * ask ONE global, Claude-shaped question (`.mcp.json` exists? `CLAUDE.md` exists?) * and so lie for every other tool. This scores each TARGETED CLI on its own terms, * derived entirely from the single {@link entry} registry (bootloader file(s), MCP * config path/key/support level, settings file), so it can never drift from what * `aih bootstrap-ai` / `aih mcp` actually write. * * Four cell states, three of which the legacy boolean conflated: * - `wired` — the tool's own artifact exists AND carries the expected content; * - `missing` — aih can write it, but it isn't there (a real gap → graded); * - `manual` — aih intentionally does NOT write it (`fallback` MCP: TOML, * a global path, or a different server shape) — guidance only, so * file existence is not a fair signal → NOT graded; * - `na` — the tool has no such capability (e.g. settings for non-Claude). * * Scoring counts only `wired`+`missing` cells across TARGETED rows, so a Kiro-only * repo scores 100 when Kiro is wired — never docked for a `.mcp.json`/Claude file * it doesn't use. Pure fs reads (existsSync / read) — no spawn, no network. */ /** A capability cell's state. `manual`/`na` are excluded from the graded score. */ export type CellState = "wired" | "missing" | "manual" | "na"; export interface CliCell { state: CellState; /** The file this capability lives in (registry-derived), when one applies. */ path?: string; /** Human one-liner: how it loads / why manual / why n/a. */ detail: string; /** Exact `aih …` command to close a `missing`/`manual` gap, when one applies. */ fix?: string; /** MCP-cell only: is the config repo-committed (portable, team-shared) or a global ~/home file? */ scope?: "repo" | "global"; /** MCP-cell only: configured server count (a `~/.codex` global with 16 ≠ a repo `.mcp.json` with 5). */ count?: number; } export interface CliCoverageRow { cli: Cli; label: string; /** True when this CLI is in the resolved target set (graded); else a muted row. */ targeted: boolean; bootloader: CliCell; mcp: CliCell; settings: CliCell; /** Will the (present) bootloader actually load + route to canon? (Phase 1.5) */ load: CliLoadability; } /** Which arm of the target-resolution precedence won — surfaced to the user. */ export type TargetSource = "marker" | "ctx" | "flag" | "detect" | "wired" | "default-claude"; export interface CliCoverageModel { /** Targeted rows first (canonical order), then installed-but-untargeted ones. */ rows: CliCoverageRow[]; targeted: Cli[]; targetSource: TargetSource; /** % of GRADEABLE (wired|missing) cells across TARGETED rows that are wired. */ score: number; /** Targeted CLIs with NO `missing` cell (manual/na/wired all count as ok). */ structurallyConfigured: number; /** Targeted CLIs that are structurallyConfigured AND proven to load (`loads`). */ provenLoadable: number; totalTargeted: number; } /** * Resolve the target CLI set AND where it came from — marker-authoritative, the * same precedence `doctor` honors. The committed `.aih-config.json` wins so a * fresh clone reports against the tools the repo was bootstrapped for, not the * Claude default; `targetSource` lets the report distinguish a real gap from a * row that only exists because nothing was targeted (`default-claude`). */ export declare function resolveTargetSet(ctx: PlanContext): { targeted: Cli[]; source: TargetSource; }; /** * Build the per-CLI coverage model: targeted rows first (canonical order), then * any installed-but-not-targeted CLIs as muted rows (so nothing on the machine is * hidden). Identical dry-run vs `--verify` — pure fs reads, no spawn/network. */ export declare function scanCliCoverage(ctx: PlanContext): CliCoverageModel; /** Terminal/markdown body: a compact per-CLI matrix + a remediation list. */ export declare function renderCliCoverage(model: CliCoverageModel): string; /** * The "AI CLI wiring" digest — per-CLI bootloader/MCP/settings truth, scoped to * the targeted set. The stable `AI CLI wiring` describe prefix routes it to the * dashboard matrix panel. Always returns a digest (never undefined): a repo with * no marker still has a `default-claude` target to report against. */ export declare function cliCoverageDigest(ctx: PlanContext): DigestAction;