feat: add paperclip-dev skill with optional bundled skill support

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Devin FoleyandPaperclip committed 2026-04-16 19:19:41 -07:00
1 parent b8725c52ef
commit d5afd4eacb
3 files changed
+460 -7

No files matched your search

@@ -35,6 +35,34 @@ describe("paperclip skill utils", () => {
expect(entries[0]?.source).toBe(path.join(root, "skills", "paperclip"));
});
it("marks skills with required: false in SKILL.md frontmatter as optional", async () => {
const root = await makeTempDir("paperclip-skill-optional-");
cleanupDirs.add(root);
const moduleDir = path.join(root, "a", "b", "c", "d", "e");
await fs.mkdir(moduleDir, { recursive: true });
// Required skill (no frontmatter flag)
const requiredDir = path.join(root, "skills", "paperclip");
await fs.mkdir(requiredDir, { recursive: true });
await fs.writeFile(path.join(requiredDir, "SKILL.md"), "---\nname: paperclip\n---\n\n# Paperclip\n");
// Optional skill (required: false)
const optionalDir = path.join(root, "skills", "paperclip-dev");
await fs.mkdir(optionalDir, { recursive: true });
await fs.writeFile(path.join(optionalDir, "SKILL.md"), "---\nname: paperclip-dev\nrequired: false\n---\n\n# Dev\n");
const entries = await listPaperclipSkillEntries(moduleDir);
entries.sort((a, b) => a.runtimeName.localeCompare(b.runtimeName));
expect(entries).toHaveLength(2);
expect(entries[0]?.runtimeName).toBe("paperclip");
expect(entries[0]?.required).toBe(true);
expect(entries[1]?.runtimeName).toBe("paperclip-dev");
expect(entries[1]?.required).toBe(false);
expect(entries[1]?.requiredReason).toBeNull();
});
it("removes stale maintainer-only symlinks from a shared skills home", async () => {
const root = await makeTempDir("paperclip-skill-cleanup-");
cleanupDirs.add(root);