/** * Skill curator (Hermes-parity #32). Reflection (R7) promotes recurring procedures into SKILL.md files; * without curation they accumulate forever, bloating tool/context and raising per-turn cost. The curator * tracks usage of PROMOTED skills (frontmatter `promoted: true`) and PROPOSES — never auto-applies — * archiving stale ones and consolidating overlapping ones. Hand-authored user skills are never touched. * * Design (locked with agy): propose-only, session-start + idle triggers (not per-turn), restorable * archive (non-destructive), and consolidation is a flagged suggestion (never an auto-merge). */ /** Per-promoted-skill signal the proposal logic reasons over. Pure data — no I/O. */ export interface PromotedSkillInfo { name: string; /** When the skill file was created (ms epoch); guards a freshly-promoted skill from instant archival. */ createdMs: number; /** Last time the skill was loaded/used (ms epoch); 0 if never used. */ lastUsedMs: number; useCount: number; /** Tokens from name+description+body, for overlap detection. */ keywords: string[]; } export interface CuratorOptions { /** A promoted skill unused and older than this many days is proposed for archival. Default 30. */ staleDays: number; /** Token-Jaccard ≥ this between two promoted skills flags them for consolidation. Default 0.5. */ overlapThreshold: number; /** Current time (ms epoch); injected so the proposal logic stays pure/testable. */ now: number; } export declare const DEFAULT_CURATOR_OPTIONS: Omit; export interface CurationProposals { /** Promoted skills proposed for (restorable) archival, with a human reason. */ archive: Array<{ name: string; reason: string; }>; /** Pairs of promoted skills that overlap enough to consider merging (flag only, never auto-merge). */ consolidate: Array<{ names: [string, string]; overlap: number; }>; } /** * Pure proposal logic: decide which promoted skills to PROPOSE archiving (stale + unused) and which pairs * overlap enough to PROPOSE consolidating. Returns suggestions only; the caller applies them on approval. */ export declare function computeCurationProposals(skills: PromotedSkillInfo[], opts: CuratorOptions): CurationProposals; /** * Filesystem layer over {@link computeCurationProposals}: reads promoted SKILL.md files + the usage * sidecar, and archives/restores skills non-destructively. The current time is injected so callers (and * tests) control "now". */ export declare class SkillCurator { private readonly skillsDir; private readonly archiveDir; private readonly usageFile; constructor(skillsDir: string); /** * Record that a promoted skill was loaded/used (bumps count + last-used). Best-effort. * Load-mutate-write runs under a single exclusive lock so two concurrent uses (e.g. two sessions * loading the same skill around the same time) can't both read the old usage map and drop a count. */ recordUse(name: string, now: number): void; /** Build the proposals from the current promoted-skill corpus. */ proposeCuration(now: number, options?: Partial>): CurationProposals; /** * Auto-archive every stale promoted skill in ONE locked batch (#32 default-on). The lock serializes * curation across sessions sharing this `agentDir` so a concurrent session can't archive a folder * mid-rename (agy's race mitigation). Returns the names archived (for the host to announce). Never * throws; on lock contention it simply does nothing this run. */ autoArchiveStale(now: number, options?: Partial>): Promise; /** Move a promoted skill into `.archive/` (restorable). Returns true if archived. */ archiveSkill(name: string): boolean; /** Restore an archived skill back into the active skills dir. Returns true if restored. */ restoreSkill(name: string): boolean; loadPromotedSkills(): PromotedSkillInfo[]; private isPromoted; private loadUsage; } /** True if a SKILL.md's YAML frontmatter declares `promoted: true` (reflection-generated). */ export declare function isPromotedFrontmatter(content: string): boolean; //# sourceMappingURL=skill-curator.d.ts.map