import type { Skill, SkillChain, SkillDisclosureLevel, SkillLoadResult } from '../types/skills/index.js'; import { type Logger } from '../utils/logger.js'; export declare class SkillRegistry { private skills; private stamps; private readonly log; /** * Bound once, at construction — not per call and not at module scope. * Per-call construction (what `register`/`registerAll` did before this) * still reads `getRootLogger()` on every call with no way for a caller to * override it; module scope is worse still, for the reason `loadSkill` * and `discoverSkills` document. A host that wants its own destination * passes `log` here once. */ constructor(log?: Logger); register(dirPath: string, level?: SkillDisclosureLevel): Promise; /** Record what the file looked like, so a later read can tell it changed. */ private stamp; registerAll(parentDir: string, level?: SkillDisclosureLevel): Promise; get(name: string): Skill | undefined; /** * Register a skill already loaded, under a name the caller chose. * * The plugin path needs this: it namespaces a plugin's skills so two * plugins shipping `reconcile` do not silently overwrite each other, and * the name a skill is filed under is then not the name in its own * frontmatter. `register(dirPath)` cannot express that. */ add(name: string, skill: Skill): void; /** * Forget one. Reports whether it was there. * * Needed by anything that can UNDO a registration — a plugin rollback, * a plugin disable. Without it a plugin that failed halfway through * enabling left its skills in the registry with nothing that could * remove them, so the model kept being offered skills from a plugin the * runtime had marked `error`. */ unregister(name: string): boolean; /** * Load a skill, re-reading it if the file changed since we last did. * * The cache was permanent: once a body had been read, `existing.body` * short-circuited every later call, so an edited SKILL.md could not reach * the model without restarting the process. That is fine for a turn and * wrong for a long-lived one — a skill is a file an author is editing * WHILE the agent is running, which is the whole reason it is a file and * not a constant. * * One `stat` per lookup, not a hash and not a watcher. A watcher is a * resource with a lifetime, and this registry has no teardown to hang one * on; a hash means reading every skill on every lookup, which is the cost * the cache exists to avoid. */ load(name: string, level?: SkillDisclosureLevel): Promise; /** `same`, `changed`, or `gone`. */ private hasChanged; list(): Skill[]; /** * The model-facing catalog, keyed by what this registry actually accepts. * * Reading the Map key is load-bearing for host namespaces. A plugin may file * `reconcile` as `ledger__reconcile`; reconstructing the name from the skill * body would advertise a call that cannot resolve (and could collide with a * different plugin's unqualified name). */ catalog(): Promise; /** * Every registered name. * * So a lookup that misses can name what IS there. A bare "not found" * sends the model guessing at spellings, and it is guessing from a * manifest already in its own prompt. */ names(): readonly string[]; get size(): number; has(name: string): boolean; } export declare function resolveSkillChain(categorySkillsDir: string | undefined, agentSkillsDir: string | undefined, level?: SkillDisclosureLevel, log?: Logger): Promise; //# sourceMappingURL=registry.d.ts.map