export async function createSkill(
name: string,
description: string,
instructions: string,
skillsDir: string,
db: AutomatonDatabase,
conway: ConwayClient,
): Promise<Skill> {
// Validate name to prevent path traversal
if (!/^[a-zA-Z0-9-]+$/.test(name)) {
throw new Error(`Invalid skill name: "${name}"`);
}
// Enforce size limits
const safeDescription = description.slice(0, 500);
const safeInstructions = instructions.slice(0, 10_000);
const targetDir = path.join(skillsDir, name);
fs.mkdirSync(targetDir, { recursive: true });
// Generate YAML frontmatter safely
const frontmatter = yaml.stringify({
name,
description: safeDescription,
"auto-activate": true,
});
const content = `---\n${frontmatter}---\n\n${safeInstructions}`;
const skillMdPath = path.join(targetDir, "SKILL.md");
await conway.writeFile(skillMdPath, content);
const skill: Skill = {
name,
description: safeDescription,
autoActivate: true,
instructions: safeInstructions,
source: "self",
path: skillMdPath,
enabled: true,
installedAt: new Date().toISOString(),
};
db.upsertSkill(skill);
return skill;
}