75 lines
2.0 KiB
TypeScript
75 lines
2.0 KiB
TypeScript
import type { Skill } from './types.js';
|
|
|
|
/**
|
|
* SkillRegistry holds loaded skills and generates system prompt additions.
|
|
*
|
|
* Skills are keyed by name. Managed/workspace skills may override bundled
|
|
* skills by registering with the same name.
|
|
*/
|
|
export class SkillRegistry {
|
|
private skills: Map<string, Skill> = new Map();
|
|
|
|
/** Replace all registered skills with the provided set. */
|
|
reset(skills: Skill[]): void {
|
|
this.skills.clear();
|
|
for (const skill of skills) {
|
|
this.skills.set(skill.manifest.name, skill);
|
|
}
|
|
}
|
|
|
|
/** Register a skill. Replaces any existing skill with the same name. */
|
|
register(skill: Skill): void {
|
|
this.skills.set(skill.manifest.name, skill);
|
|
console.log(
|
|
`Skill '${skill.manifest.name}' registered (${skill.manifest.tier}, ${skill.available ? 'available' : 'unavailable'})`,
|
|
);
|
|
}
|
|
|
|
/** Unregister a skill by name. Returns true if the skill existed. */
|
|
unregister(name: string): boolean {
|
|
return this.skills.delete(name);
|
|
}
|
|
|
|
/** Look up a skill by name. */
|
|
get(name: string): Skill | undefined {
|
|
return this.skills.get(name);
|
|
}
|
|
|
|
/** Return all registered skills. */
|
|
list(): Skill[] {
|
|
return Array.from(this.skills.values());
|
|
}
|
|
|
|
/** Return only skills whose requirements are met (available === true). */
|
|
listAvailable(): Skill[] {
|
|
return this.list().filter(skill => skill.available);
|
|
}
|
|
|
|
/**
|
|
* Generate system prompt additions from all available skills.
|
|
*
|
|
* Each skill's SKILL.md content is formatted as a markdown section:
|
|
* ```
|
|
* ## Skill: <name>
|
|
* <instructions>
|
|
* ```
|
|
*
|
|
* Returns an empty string if no skills are available.
|
|
*/
|
|
getSystemPromptAdditions(): string {
|
|
const available = this.listAvailable();
|
|
if (available.length === 0) {
|
|
return '';
|
|
}
|
|
|
|
return available
|
|
.map(skill => `## Skill: ${skill.manifest.name}\n${skill.instructions}`)
|
|
.join('\n\n');
|
|
}
|
|
|
|
/** Return the names of all available skills. */
|
|
getSkillNames(): string[] {
|
|
return this.listAvailable().map(skill => skill.manifest.name);
|
|
}
|
|
}
|