/** * Global delivery audit/repair — does every harness on this machine actually * load CLEO? One surface for the three things that silently break it: * * 1. `~/.cleo` — must link to the platform data dir ({@link auditCleoLink}). * 2. The global hub `~/.agents/AGENTS.md` — its reference must resolve, or it * must carry the protocol embedded. * 3. Skill installs in every harness skills dir — each CLEO skill entry must * resolve. Links written through `~/.cleo/skills/` (the pre-T12598 * install target) break all at once when `~/.cleo` dangles: measured * 2026-09-28 on macOS, 96 dangling `ct-*` links across six harness dirs. * * Repairs relink skill entries to the physical `/skills/` * (symlink, verified; copy when a link cannot be made or does not resolve) * and append one receipt per run to `/audit/global-delivery.jsonl`. * * @task T12596 * @task T12598 */ import * as path from 'node:path'; import { type CleoLinkAudit, type CleoLinkOptions, type CleoLinkRepairReceipt } from './cleo-link.js'; /** Repair command printed in remedies. */ export declare const GLOBAL_DELIVERY_REPAIR_COMMAND = "cleo doctor global-delivery --repair"; /** * Skill dirs scanned in addition to the provider registry, relative to the * home directory, so their stale links are reported and repaired rather than * left dangling forever: * - `.kimi-code/skills` — written by an older release; the registry no * longer lists it. * - `.config/opencode/skills` — the registry resolves OpenCode's dir through * `XDG_CONFIG_HOME`, so when that is set elsewhere (or the registry entry * changes) the home-relative dir that older installs populated would be * missed. Measured on macOS 2026-09-28: 16 `ct-*` links there, all routed * through `~/.cleo`. */ export declare const LEGACY_HARNESS_SKILL_DIRS: readonly string[]; /** * State of one harness skill entry: * - `ok` — resolves directly to the canonical skill (or is a real copy). * - `dangling` — a link that resolves to nothing; repairable when the * canonical skill exists. * - `legacy-route` — resolves today but only THROUGH `~/.cleo`, so it breaks * whenever that link does; relinked to the physical path on repair. * - `orphan` — dangling, and no canonical skill of that name exists. */ export type SkillInstallState = 'ok' | 'dangling' | 'legacy-route' | 'orphan'; /** One CLEO-managed entry in a harness skills directory. */ export interface SkillInstallEntry { /** Harness skills directory. */ dir: string; /** Entry name (skill name). */ name: string; /** Absolute entry path. */ path: string; /** Link target as written, or null for a real directory. */ target: string | null; /** Classified state. */ state: SkillInstallState; } /** Hub state. */ export interface HubAudit { /** `~/.agents/AGENTS.md` path. */ path: string; /** * - `reference` — carries the canonical reference and it resolves. * - `embedded` — carries the protocol text inline (T12596 fallback). * - `unresolved` — carries the reference but it resolves to nothing. * - `missing` — no hub file, or no CLEO reference in it. */ state: 'reference' | 'embedded' | 'unresolved' | 'missing'; } /** Full audit. */ export interface GlobalDeliveryAudit { /** `~/.cleo` link state. */ link: CleoLinkAudit; /** Hub state. */ hub: HubAudit; /** Canonical skills root the entries should resolve to. */ skillsRoot: string; /** Every CLEO-managed skill entry found. */ skills: SkillInstallEntry[]; /** Per-state counts over {@link GlobalDeliveryAudit.skills}. */ skillCounts: Record; /** True when the link, hub and every skill entry resolve. */ healthy: boolean; /** Exact repair command, or null when healthy. */ remedy: string | null; } /** Per-entry repair outcome recorded in the receipt. */ export interface SkillRepairOutcome { /** Entry path. */ path: string; /** State before. */ before: SkillInstallState; /** Previous link target. */ previousTarget: string | null; /** What was written: a verified symlink, a copy, or nothing. */ action: 'symlink' | 'copy' | 'skipped'; /** Why the entry was skipped, when it was. */ reason: string | null; } /** Receipt for one {@link repairGlobalDelivery} run. */ export interface GlobalDeliveryReceipt { /** Unique receipt id. */ receiptId: string; /** ISO timestamp. */ at: string; /** Dry run: nothing was written. */ dryRun: boolean; /** * `intent` is appended BEFORE the first skill entry changes (it carries * {@link GlobalDeliveryReceipt.planned}); the run then appends `completed` * or `failed`. `planned` receipts (dry run) are returned, never written. */ phase: 'planned' | 'intent' | 'completed' | 'failed'; /** Every entry the run will change, with its previous link target. */ planned: Array<{ path: string; previousTarget: string | null; state: SkillInstallState; }>; /** The error that stopped the run, when `phase === 'failed'`. */ error: string | null; /** The `~/.cleo` link repair receipt. */ link: CleoLinkRepairReceipt; /** Skill entry outcomes. */ skills: SkillRepairOutcome[]; /** JSONL file the receipt was appended to, or null on a dry run. */ receiptLog: string | null; } /** Injection points (tests). */ export interface GlobalDeliveryOptions extends CleoLinkOptions { /** Home directory. Defaults to `homedir()`. */ home?: string; /** Hub path. Defaults to `/AGENTS.md`. */ hubPath?: string; /** Canonical skills root. Defaults to {@link resolveSkillsRoot}. */ skillsRoot?: string; /** Harness skill dirs. Defaults to every provider's global dirs + legacy dirs. */ skillDirs?: string[]; /** Receipt log dir. Defaults to `/audit`. */ auditDir?: string; } /** * Every harness skills directory the provider registry knows (global scope), * plus {@link LEGACY_HARNESS_SKILL_DIRS}. Only directories that exist. * * @param home - Home directory. * @returns Unique absolute directories. */ export declare function discoverHarnessSkillDirs(home?: string): Promise; /** The subset of `node:path` the classifier needs (posix or win32). */ export type PathApi = Pick; /** * True when a link target routes through `~/.cleo` — the pre-T12598 install * target that breaks every link at once when `~/.cleo` dangles. * * Pure over `pathApi` so macOS, Linux and Windows path shapes can be checked * on any host. * * @param target - Link target as written (relative or absolute). * @param linkDir - Directory holding the link. * @param cleoLink - Absolute `~/.cleo` path. * @param pathApi - `path.posix` or `path.win32`; defaults to the host. */ export declare function routesThroughCleoLink(target: string, linkDir: string, cleoLink: string, pathApi?: PathApi): boolean; /** * Classify every CLEO-managed entry in the given harness skill dirs. * * An entry is CLEO-managed when a canonical skill of the same name exists in * `skillsRoot`, or when it is a link routed through `~/.cleo` or into * `skillsRoot`. Links owned by other tools (e.g. `~/.claude/skills/x -> * ../../.agents/skills/x`) are never reported or touched. * * @param dirs - Harness skills directories. * @param skillsRoot - Canonical skills root. * @param cleoLink - Absolute `~/.cleo` path. * @returns Managed entries. */ export declare function auditSkillInstalls(dirs: readonly string[], skillsRoot: string, cleoLink: string): SkillInstallEntry[]; /** * Audit `~/.cleo`, the global hub and every harness skill install. * * @param opts - Injection points (tests). * @returns The audit, with the exact remedy when unhealthy. * @task T12598 */ export declare function auditGlobalDelivery(opts?: GlobalDeliveryOptions): Promise; /** * Repair everything {@link auditGlobalDelivery} reports: relink `~/.cleo`, * then relink every `dangling` / `legacy-route` skill entry to the physical * canonical path. `orphan` entries are reported, never deleted. The hub needs * no rewrite once `~/.cleo` resolves; `cleo install-global` refreshes it. * * @param opts - `dryRun` plans without writing; plus injection points. * @returns The post-repair audit and the receipt. * @task T12598 */ export declare function repairGlobalDelivery(opts?: GlobalDeliveryOptions & { dryRun?: boolean; }): Promise<{ audit: GlobalDeliveryAudit; receipt: GlobalDeliveryReceipt; }>; //# sourceMappingURL=global-delivery.d.ts.map