import { type CommandSpec, type PlanContext } from "../internals/plan.js"; import { type SkillLockEntry } from "./lockfile.js"; /** * `aih skill inventory` — slice 3 of the skill lifecycle: the READ-ONLY join that * answers "which external skills are on disk, and which are approved?". It reuses * the same discovery contract `skillShape` uses (`collectSkillDirs` + * `promotedSkillRel`) and the committed `aih-skills.lock.json` approvals, so it * never re-derives state a write command already recorded. Pure fs — no spawns, no * git — so it is safe at plan/digest time (the plan-purity floor, #35) and is the * one join both this command and the report's "Skill governance" digest consume. */ /** One discovered skill, joined to its approval + drift state. */ export interface SkillInventoryRow { /** Logical skill name (matches the lockfile entry name). */ name: string; /** The root label the skill was discovered under. */ root: string; /** Absolute path of the skill directory on disk. */ abs: string; /** `quarantined` = disabled under `.aih/quarantine/` (approval kept, not graded). */ status: "approved" | "unapproved" | "stale-pin" | "quarantined"; /** Approval verdict from the lock entry, when the lock carries one for this name. */ verdict?: SkillLockEntry["verdict"]; /** Source string from the lock entry, when the lock carries one for this name. */ source?: string; /** Approved commit from the lock entry, when the lock carries one for this name. */ commit?: string; /** Skill pack from the lock entry, when the lock carries one for this name. */ pack?: string; /** True when the approval marks this a first-party (repo-relative local) skill. */ firstParty?: boolean; /** Committed card path from the lock entry, when the lock carries one for this name. */ card?: string; /** Whether the card the lock entry references is present on disk. */ cardPresent?: boolean; /** Why a stale-pin skill is stale (commit mismatch), when stale. */ driftReason?: string; } /** One scanned skill root and whether it exists on disk. */ export interface SkillInventoryRoot { label: string; abs: string; present: boolean; } export interface SkillInventory { roots: SkillInventoryRoot[]; skills: SkillInventoryRow[]; counts: { installed: number; approved: number; unapproved: number; stalePin: number; quarantined: number; }; } /** * The pure join: discover on-disk skills, match each against the committed approvals, * and grade approved skills for pin drift. No spawns, no git, no writes — reused by * both the `inventory` command and the report's "Skill governance" digest. */ export declare function skillInventory(ctx: PlanContext): SkillInventory; export declare const skillInventoryCommand: CommandSpec;