import type { HarnessAdapter } from "./core/adapter.js"; import type { HarnessDeclaration } from "./core/types.js"; /** The default adapter when detection finds no harness markers. */ export declare const defaultAdapter: HarnessAdapter; /** * All registered adapters. detect() specificity (not order) breaks ties. * * 🔴 `as const satisfies`, NOT a `readonly HarnessAdapter[]` ANNOTATION, and the * difference is the whole of {@link HarnessName}. An annotation widens * `name: "claude-code"` to `string`, so the registry cannot say which names * exist and every consumer that needed to know had to write the list out again * — which is how `ProbeHarness = "claude-code" | "codex"` and the lint rule's * `DEFAULT_NAMES` came to be hand-maintained copies of this array. `satisfies` * keeps the literal types while still checking each element against the port. */ export declare const ADAPTERS: readonly [{ readonly name: "claude-code"; readonly harnessTesting: true; readonly shellHooks: true; readonly subagents: true; readonly dialect: import("./adapter.js").HarnessDialect; readonly layout: import("./adapter.js").PluginLayout; readonly runtime: import("./adapter.js").HarnessRuntime; readonly hookProtocol: import("./adapter.js").HookProtocol; readonly modelMock: import("./adapter.js").ModelMock; readonly harnessTestDriver: () => Promise; readonly liveDriver: () => Promise; readonly claims: (path: string) => boolean; readonly detect: (exists: (repoRelative: string) => boolean) => import("./core/adapter.js").DetectSignal; readonly advisories: (read: import("./core/adapter.js").InstallReader) => readonly string[]; }, { readonly name: "codex"; readonly harnessTesting: true; readonly shellHooks: true; readonly subagents: false; readonly dialect: import("./adapter.js").HarnessDialect; readonly layout: import("./adapter.js").PluginLayout; readonly runtime: import("./adapter.js").HarnessRuntime; readonly hookProtocol: import("./adapter.js").HookProtocol; readonly modelMock: import("./adapter.js").ModelMock; readonly harnessTestDriver: () => Promise; readonly liveDriver: () => Promise; readonly claims: (path: string) => boolean; readonly detect: (exists: (repoRelative: string) => boolean) => import("./core/adapter.js").DetectSignal; readonly advisories: () => readonly string[]; }]; /** * Every registered harness name, derived from {@link ADAPTERS} — `"claude-code" * | "codex"` today, and whatever the array holds tomorrow. * * ⚠️ WHAT THIS DOES NOT CATCH, stated because the type looks stronger than it * is: two adapters declaring the SAME name collapse the union silently (a union * of duplicates is that one member), so this type would still read * `"claude-code" | "codex"` with three adapters registered and two of them * called `codex`. `adapter-contract.test.ts` asserts the set size instead — * a test, because there is no type-level cardinality to assert against. * * ⚠️ AND IT IS NOT A CEILING ON COMPARING NAMES. A branded or literal string is * still comparable to a string literal in TypeScript (`===` uses comparability, * not assignability — measured in the redesign's section 7), so this type cannot * make `adapter.name === "codex"` an error. What stops that is the * `local/no-harness-names` lint rule; what this type does is remove the REASON * to write such a comparison, by letting the one list be the only list. */ export type HarnessName = (typeof ADAPTERS)[number]["name"]; /** The result of auto-detecting a harness from a repo's layout. */ export interface DetectResult { readonly adapter: HarnessAdapter; /** True when detection found no harness markers and fell back to the default. */ readonly fallback: boolean; /** * Other adapters that matched at the same top specificity — a non-empty list * means the repo looks like more than one harness (e.g. a CLAUDE.md + an * AGENTS.md), so the pick is ambiguous; resolve with `--harness`. */ readonly ambiguousWith: readonly string[]; } /** * Auto-detect the harness for a repo at `root` by highest detect() specificity. * * SCOPE (2026-07-21): `vigiles audit` is CLAUDE-CODE-FOCUSED for now. This is * file-marker detection (a specificity score); it picks ONE harness (or the CC * default) and reports `ambiguousWith` when several genuinely match. Mirror-collapse * (below) is done; the rest — treating a LONE `AGENTS.md` (an AAIF cross-tool * standard, not a Codex signal) as harness-agnostic, and auditing ALL detected * harnesses (shared-once + per-harness slice) — is DEFERRED. Full design + research: * `research/audit-harness-dx.md`. */ export declare function detectAdapterResult(root: string): DetectResult; /** The detected adapter (highest specificity), else the default (Claude Code). */ export declare function detectAdapter(root: string): HarnessAdapter; /** Lower-case, trim, and map a short alias to its canonical adapter name. */ export declare function normalizeHarnessName(name: string): string; /** Look up a registered adapter by `name` (alias-aware, e.g. `claude`). */ export declare function getAdapter(name: string): HarnessAdapter | undefined; /** * The adapter whose instruction file is `filename` (e.g. `AGENTS.md` → codex, * `CLAUDE.md` → claude-code), if any. The per-spec disambiguation signal: a * `.spec.ts` compiles a `` instruction file, so the filename names * the harness more specifically than config/detect for THAT spec. */ export declare function adapterForInstructionFile(filename: string): HarnessAdapter | undefined; /** * Resolve the adapter for a command: an explicit `--harness ` wins (throws * if unknown); otherwise auto-detect from `root`. The single entry point the CLI * uses so detection + override live in one place. */ export declare function resolveAdapter(root: string, harness?: string): HarnessAdapter; /** Normalize a config `harness` value (string | string[]) to a canonical list. */ export declare function normalizeHarnessList(harness?: string | readonly string[]): string[]; /** * The adapter chosen for a single-dialect operation. A discriminated union so an * invalid state — a "notice" with no message, or a clean pick carrying a stray * string — is unrepresentable: `kind: "ok"` has no `notice`, `kind: "notice"` * always carries a non-empty one. Both variants carry the `adapter`. */ export type HarnessSelection = { readonly kind: "ok"; readonly adapter: HarnessAdapter; } | { readonly kind: "notice"; readonly adapter: HarnessAdapter; readonly notice: string; }; /** * Resolve the single harness a compile/lint operation should use, with explicit * precedence — the deterministic replacement for sniffing the cwd: * * 1. `--harness=` flag (wins; throws if unknown). * 2. config `harness` resolving to a single entry → use it. * 3. config `harness` with multiple entries → use the first, with a loud notice. * 4. no config → auto-detect, with a loud notice when the repo is ambiguous. * * `configHarness` is parsed once (alias-normalized) at the call site and passed * in; this function re-normalizes idempotently so it's safe either way. Pure * (besides reading `root`'s layout for detection) so the precedence is * unit-testable without a real compile. See research/multi-harness-compile.md. */ export declare function resolveHarnessSelection(opts: { root: string; flag?: string; configHarness?: string | readonly string[]; }): HarnessSelection; /** * The FULL adapter set a compile-time INSTALL should fan out to. Unlike * `resolveHarnessSelection` (which picks ONE dialect for a single-output compile, * since you emit a markdown file in one harness's format), an install writes the * SAME artifact into EVERY enabled harness's native config — so a repo targeting * both harnesses gets a compiled hook in `.claude/settings.json` AND * `.codex/config.toml`, not just the first. Precedence mirrors the single picker: * * 1. `--harness=` flag → just that one (an explicit override is singular). * 2. config `harness` list → ALL of them (the multi-harness fan-out). * 3. no config → auto-detect → the one detected. * * Returns ≥1 adapter, de-duplicated by name (a config that lists a harness twice, * or an alias + its canonical, collapses to one install). */ export declare function resolveHarnessAdapters(opts: { root: string; flag?: string; configHarness?: string | readonly string[]; }): HarnessAdapter[]; /** * One declared harness, resolved: the adapter its KEY names, and the extra * surface roots declared under it, normalized. * * The pair is the whole point of the nested shape. Under the two flat keys the * roots were global and the harness list was ordered, so the layout a root was * read under was decided by array position; here the layout comes from the key * the root sits under, so there is no order to get wrong and nothing to guess. */ export interface DeclaredHarness { readonly adapter: HarnessAdapter; /** Normalized `.vigilesrc.json#harnesses..roots`, in declaration order. */ readonly roots: readonly string[]; } /** * The declared harness NAMES, in declaration order — the `string[]` every * existing single-dialect picker already takes. * * Deliberately NOT resolving adapters: `resolveHarnessSelection` / * `resolveHarnessAdapters` resolve (and throw on) an unknown name themselves, * and two places deciding what an unknown name means is how the two error * wordings would drift. */ export declare function declaredHarnessNames(harnesses?: Readonly>): string[]; /** * Every declared harness with its roots, in declaration order. * * Throws on an unknown key, through the SAME `resolveAdapter` the `--harness=` * flag goes through — so `{"claud-code": {}}` fails with the identical * `Unknown harness "claud-code". Known: claude-code, codex.` a bad flag gets. * That was already the loud half of the old shape and it is kept verbatim. * * Aliases collapse: `{"claude": {"roots":["a"]}, "claude-code": {"roots":["b"]}}` * is ONE Claude Code declaration reading both roots, not two competing ones — * the same de-duplication `resolveHarnessAdapters` does, extended to carry the * union of what each spelling declared. */ export declare function resolveDeclaredHarnesses(root: string, harnesses?: Readonly>): DeclaredHarness[]; //# sourceMappingURL=adapter-registry.d.ts.map