/** * A skill that names a SIBLING SKILL that does not exist. * * ## The gap this closes * * `danglingRefs` (plugin-loader.ts) already reports broken intra-plugin * references — but it matches PATHS (`${CLAUDE_PLUGIN_ROOT}/scripts/x.sh`) in * EXECUTABLE sources, and it skips prose by design (`DOC_SOURCE_RE` → skip). A * skill referring to another skill BY NAME, in prose, was checked by nothing. * * That is the reference agents actually follow. Skills route to each other * constantly — "run `verify-citations` first", "compose with `find-venue`" — and * a rename breaks every mention SILENTLY. Nothing crashes: the model reads a * route to a skill that is not there and does something adjacent, which is the * failure mode this whole tool exists for. Found 2026-08-11 in a consumer repo * whose orchestrator skill listed the pipeline's stages by name; two stages had * been added and never listed, and one local hand-written harness was the only * thing that noticed. * * ## Precision first, and why it is a NEAR-MISS check rather than a name check * * The naive version — "every backticked kebab token must be a skill" — fires on * `claude-code`, `node-fetch`, `pull-request`, every hyphenated noun an author * writes. A checker that fires on clean input is muted within a day, which is * worse than one that misses, so this asks a narrower question: * * is this token ALMOST a skill that exists? * * A kebab token within a small edit distance of a real skill name, that is not * itself a real skill, is a rename or a typo with high probability — while * `node-fetch` in a repo of paper skills is far from all of them and stays * silent. The check is deliberately blind to a reference to a skill that never * existed under any similar name; that case is indistinguishable from ordinary * hyphenated prose without reading intent. * * Pure: takes names and contents, touches no filesystem, so the disk walker and * any in-browser twin can share it. */ /** One skill as this module needs to see it. */ export interface SkillRefSource { /** Skill id (directory name). */ readonly name: string; /** Repo-relative path of its SKILL.md, for the message. */ readonly path: string; /** Its markdown. */ readonly content: string; } export interface SkillRefIssue { /** The skill whose text carries the broken reference. */ readonly from: string; /** Path of the file to open. */ readonly path: string; /** The name it referred to. */ readonly missing: string; /** The existing skill it most resembles — the likely intended target. */ readonly didYouMean: string; } /** * Broken skill→skill references across a set of skills. * * Self-references are ignored (a skill naming itself is normal), and so is any * token that IS a skill — the check only speaks about near-misses. */ export declare function brokenSkillRefs(skills: readonly SkillRefSource[]): SkillRefIssue[]; /** One line per issue, in the report's voice. */ export declare function formatSkillRefIssue(i: SkillRefIssue): string; //# sourceMappingURL=skill-refs.d.ts.map