import type { ToolDef } from "./types.js"; export type SkillPackSource = "packaged" | "project" | "plugin"; /** What a pack declares about the world it needs, from its sidecar. */ export interface SkillDeclarations { /** Category tools the workflow drives. */ categories: string[]; /** Fully-qualified `category.action` names the workflow depends on. */ actions: string[]; /** Unreal plugins that must be enabled for the workflow to run at all. */ uePlugins: string[]; /** Engine types the workflow is about, for orientation and search. */ unrealClasses: string[]; /** Words that should make an agent reach for this pack. */ triggers: string[]; /** Engine range the pack applies to, e.g. ">=5.8". */ engine?: string; } export interface SkillPack { /** Directory name, which is also the installed skill's identity. */ name: string; dir: string; file: string; source: SkillPackSource; /** The package that contributed it, for a plugin-sourced pack. */ contributor?: string; /** `name:` from the SKILL.md frontmatter. */ frontmatterName?: string; /** `description:` from the SKILL.md frontmatter - the text an agent reads to * decide whether to load the pack, so its absence is a real defect. */ description?: string; declarations: SkillDeclarations; /** Every `category(action="x")` the body teaches, deduplicated and sorted. */ referenced: string[]; bytes: number; } export interface SkillProblem { skill: string; /** Which copy of the pack the defect is in. The installed copy under a * project can lag the packaged one, so naming the source is what makes the * report actionable. */ source: SkillPackSource; /** What kind of defect: a missing frontmatter field, an action that does not * exist, a declaration that does not match the body. */ kind: "missing_description" | "name_mismatch" | "unknown_action" | "unknown_category" | "undeclared_dependency" | "unparsable_sidecar"; detail: string; /** Closest real spellings, when the defect is a name that does not resolve. */ didYouMean?: string[]; } /** The `skills/` directory shipped in this package (sibling of `dist/`). */ export declare function packagedSkillsRoot(): string; /** Where installed packs live for a project. */ export declare function projectSkillsRoot(projectDir: string): string; /** * Read every pack under one root. A directory with no `SKILL.md` is not a * pack and is skipped silently: `.claude/skills/` legitimately holds skills * this server knows nothing about. */ export declare function readSkillRoot(root: string, source: SkillPackSource, contributor?: string): SkillPack[]; /** The sidecar that carries what the prose cannot. */ export declare function sidecarPath(skillDir: string): string; /** Parse one pack directory. Never throws: an unreadable pack is reported as * a pack with a problem, because a discovery call that dies on one bad file * hides the other twenty. */ export declare function readSkillPack(dir: string, source: SkillPackSource, contributor?: string): SkillPack; /** Split a `---`-delimited YAML frontmatter block off the head of a document. */ export declare function splitFrontmatter(text: string): { frontmatter: Record; content: string; }; /** * Every action a pack body teaches. * * The prevailing spelling in these documents is `category(action="name", ...)`, * which is also how an agent writes the call, so matching it is matching the * thing that has to be true. Fenced code and inline code are included on * purpose: a dead call inside a code block is the one most likely to be copied * verbatim. */ export declare function extractActionReferences(body: string): string[]; /** * One pack per name, preferring the source the server is responsible for. * * A project's installed copy is usually the packaged one, so checking both * reports every defect twice and doubles a listing for no information. The * installed copy is kept only when nothing available carries that name, which * is exactly the case where it is the only copy there is. */ export declare function dedupePacks(packs: SkillPack[]): SkillPack[]; export interface SkillCheckResult { skillCount: number; problemCount: number; problems: SkillProblem[]; /** * Actions a pack teaches that this build cannot verify either way. * * Empty in practice now. Unreal's wrapped tools used to land here, because * they only existed once a live editor had been read at startup, so a pack * teaching one could not be checked against anything. They are declared * actions now and resolve like any other; the field stays because a plugin * category that this session did not load is the same situation, and * reporting "cannot say" has to remain distinct from reporting "wrong". */ enrichmentOnly: string[]; } /** * Check every pack against a tool graph. * * `tools` is whatever the caller considers the live surface: the pristine * declaration off-server, or the enriched per-session graph on one. Passing * the enriched graph is what makes `epic_*` references verifiable too. */ export declare function checkSkillPacks(packs: SkillPack[], tools: ToolDef[]): SkillCheckResult; export interface PackInstallResult { skillsDir: string; /** Packs written for the first time or overwritten with new content. */ installed: string[]; /** Packs whose destination was already byte-identical. */ unchanged: string[]; /** Directories that carried no SKILL.md and are therefore not packs. */ skipped: string[]; error?: string; } /** * Copy packs into a destination root, `SKILL.md` and sidecar together. * * Idempotent and honest about it: a pack whose destination already holds the * same bytes is reported as `unchanged` rather than counted as an install, so * a caller can tell a real update from a no-op. Files in the destination that * did not come from a pack are never touched. */ export declare function installPacks(packs: SkillPack[], destRoot: string): PackInstallResult; export interface PackRemoveResult { skillsDir: string; removed: string[]; /** Names that were asked for and were not installed. Not an error: removing * a pack twice has to be safe. */ absent: string[]; } /** * Remove installed packs by name. Deletes the `SKILL.md` and the sidecar, then * the containing directory only if it ends up empty, then the skills root only * if that ends up empty too, so anything the user added alongside survives. */ export declare function uninstallPacks(names: string[], destRoot: string): PackRemoveResult; /** A pack trimmed to a listing row. */ export declare function summarisePack(pack: SkillPack): Record; /** A pack in full, including the body, for an agent that wants to read it * without leaving the tool surface. */ export declare function detailPack(pack: SkillPack, includeBody: boolean): Record;