/** * Core-by-reference = the REGISTERED-REFERENCE CLOSURE (design v3 §5), recomputed at every publish: * * seeds every `skill_ref` of every runtime-registered def (the user's and crew's seams', * `adapter.listRuntimeWorkflows()`), required; and the engine's built-in presets' refs * (`builtinPresetSkillRefs`), core when the catalog holds them (`coreSkillRefs`, X-MIG M11); * closure plus each referenced skill's mandates, transitively. A skill mandates another in two * ways, and BOTH are read (a mandate that is missed is a phase the engine refuses): * * declared the frontmatter `mandates:` list — consumed from the PARSED YAML * (`parseFrontmatter().mandates`, frontmatter.ts): each entry's decoded * scalar names a catalog skill, so `"wicked-garden-gamma"` mandates * `wicked-garden-gamma` exactly as the parser reads it (codex round 4: the * closure used to find mandates by a regex over the RAW text, which an * escaped scalar slipped past). The frontmatter block is never regex-scanned. * prose the BODY's qualified-name mentions (`repo-learn/SKILL.md:79` "Use the * **wicked-garden-search** skill", `:113` "`wicked-garden-mem` `recall`") — * the live catalog declares no `mandates:` today (0/142), so its real * dependencies live in prose. Scanned over the body only * (`bodyWithFrontmatterBlanked`): a frontmatter scalar is a parser's * business, not a prose mention. * * Two kinds of ABSENCE are reported, and both block a publish (codex review of #480 — the closure * used to fail open, warning on a missing registered ref and dropping an absent mandate silently): * * missing a registered ref that names no catalog skill — a run dispatching that phase * would find no skill in the snapshot; * absentMandates a name a CORE skill mandates (declared or in prose) that no catalog skill * answers to — the mandated method is missing, with file:line. * * What counts as a qualified-name MENTION in prose is deliberately narrow so prose does not * masquerade as a mandate: `wicked-garden-` / `wicked-garden:` not glued to a preceding name * character; a token ending in `-`/`_` is a glob or prefix (`wicked-garden-qe-acceptance-test-*`), * not a name; a token continued by `:` is a Claude subagent type (`wicked-garden:crew:implementer`), * not a skill. A DECLARED mandate is taken verbatim (normalized from the Claude colon form) — the * operator wrote it as a requirement, so a name the catalog lacks is absent, never ignored. */ import type { WorkflowDef } from '../core/types.js'; /** One qualified name a SKILL.md requires: the catalog name it spells and the 1-based line. */ export interface NameMention { name: string; line: number; } /** The non-null `skill_ref`s across a set of workflow defs. */ export declare function registeredSkillRefs(workflows: ReadonlyArray): Set; /** The non-empty `skill_ref`s across a set of presets' steps. */ export declare function presetSkillRefs(presets: ReadonlyArray<{ steps: ReadonlyArray; }>): Set; /** * (crew#935, codex r5 on #938) The skill_refs of the engine's BUILT-IN presets, read once at boot: * a workflow that became a preset registers no def, so `registeredSkillRefs(listWorkflows())` no * longer sees its skills, and a skill a preset ALWAYS requires (`wicked-garden-draft` on the * interactive-* presets) could be disabled and published, failing every run that needs it. The * built-ins are compiled into the engine, so one read holds until restart. An addon without presets, * or a read that fails, answers the empty set (logged): the registered defs still count. */ export declare function builtinPresetSkillRefs(adapter: { presetsSupported(): boolean; listPresets(): Promise; }>>; }, warn: (msg: string) => void): Promise>; /** * (crew#935) The core reference set: the registered defs' refs plus the built-in presets' refs the * catalog HOLDS. A held preset skill cannot be disabled out from under its preset; one the catalog * lacks is not a publish blocker (an older garden still publishes for every other workflow, and a run * of that preset fails at admission naming the skill). */ export declare function coreSkillRefs(defRefs: ReadonlySet, presetRefs: ReadonlySet, held: ReadonlySet): Set; /** * Every well-formed qualified-name token in `text` with its line — catalog-agnostic, PROSE only. * Glob/prefix tokens (trailing `-`/`_`) and `:`-continued subagent types are not names and are not * returned. Callers hand this the body (`bodyWithFrontmatterBlanked`), never the frontmatter. */ export declare function mentionedTokens(text: string): NameMention[]; /** * Everything a SKILL.md mandates, in file order: the DECLARED `mandates:` entries as the YAML parser * decoded them (positioned by node range), then the body's prose mentions (positioned by line). A * frontmatter that does not parse declares nothing here — the frontmatter guard blocks it on its own. */ export declare function mandateMentions(skillMd: string): NameMention[]; /** Catalog names `skillMd` mandates (declared + prose), excluding `self`. */ export declare function mentionedSkillNames(skillMd: string, catalogNames: ReadonlySet, self: string): Set; export interface AbsentMandate { /** The core skill whose SKILL.md names the absent skill. */ from: string; /** The qualified name no catalog skill answers to. */ name: string; /** 1-based line in `from`'s SKILL.md. */ line: number; } export interface CoreClosure { core: Set; /** Registered refs that name no catalog skill. */ missing: string[]; /** Names core skills mandate (declared or in prose) that no catalog skill answers to, with file:line. */ absentMandates: AbsentMandate[]; } /** * BFS from `refs` over "SKILL.md mandates" (`mandateMentions`). `catalog` maps every catalog name * (disabled skills included — disabling does not remove a skill from the catalog) to its SKILL.md * text. */ export declare function coreClosure(refs: Iterable, catalog: ReadonlyMap): CoreClosure; //# sourceMappingURL=core-closure.d.ts.map