1382e3f66f
Cover readSkillBody, formatBlock, appendSuffix, and expandSkill per SPEC §12.1. Co-authored-by: Cursor <cursoragent@cursor.com>
118 lines
3.1 KiB
TypeScript
118 lines
3.1 KiB
TypeScript
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "fs";
|
|
import { tmpdir } from "os";
|
|
import { join } from "path";
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
import {
|
|
appendSuffix,
|
|
expandSkill,
|
|
formatBlock,
|
|
readSkillBody,
|
|
type SkillBlockMeta,
|
|
} from "../src/expand";
|
|
|
|
const tempDirs: string[] = [];
|
|
|
|
afterEach(() => {
|
|
for (const dir of tempDirs.splice(0)) {
|
|
rmSync(dir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
function writeSkillMd(dir: string, name: string, content: string): SkillBlockMeta {
|
|
const baseDir = join(dir, name);
|
|
const filePath = join(baseDir, "SKILL.md");
|
|
mkdirSync(baseDir, { recursive: true });
|
|
writeFileSync(filePath, content, "utf-8");
|
|
return { name, filePath, baseDir };
|
|
}
|
|
|
|
describe("readSkillBody", () => {
|
|
it("strips YAML frontmatter and trims body", () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "pi-skill-reinject-expand-"));
|
|
tempDirs.push(dir);
|
|
const meta = writeSkillMd(
|
|
dir,
|
|
"demo-skill",
|
|
`---
|
|
name: demo-skill
|
|
description: Demo
|
|
---
|
|
|
|
# Instructions
|
|
|
|
Do the thing.
|
|
`,
|
|
);
|
|
|
|
expect(readSkillBody(meta.filePath)).toBe("# Instructions\n\nDo the thing.");
|
|
});
|
|
|
|
it("returns trimmed body when frontmatter is absent", () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "pi-skill-reinject-expand-"));
|
|
tempDirs.push(dir);
|
|
const meta = writeSkillMd(dir, "plain", " hello world \n");
|
|
|
|
expect(readSkillBody(meta.filePath)).toBe("hello world");
|
|
});
|
|
});
|
|
|
|
describe("formatBlock", () => {
|
|
it("embeds name, location, baseDir, and body", () => {
|
|
const meta: SkillBlockMeta = {
|
|
name: "brave-search",
|
|
filePath: "/home/user/.pi/skills/brave-search/SKILL.md",
|
|
baseDir: "/home/user/.pi/skills/brave-search",
|
|
};
|
|
|
|
expect(formatBlock(meta, "Search the web.")).toBe(
|
|
`<skill name="brave-search" location="/home/user/.pi/skills/brave-search/SKILL.md">
|
|
References are relative to /home/user/.pi/skills/brave-search.
|
|
|
|
Search the web.
|
|
</skill>`,
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("appendSuffix", () => {
|
|
it("appends suffix after a blank line", () => {
|
|
const block = "<skill>body</skill>";
|
|
expect(appendSuffix(block, "[skill-reinject] note")).toBe(
|
|
`${block}\n\n[skill-reinject] note`,
|
|
);
|
|
});
|
|
|
|
it("returns block unchanged for empty or whitespace suffix", () => {
|
|
const block = "<skill>body</skill>";
|
|
expect(appendSuffix(block, undefined)).toBe(block);
|
|
expect(appendSuffix(block, " ")).toBe(block);
|
|
});
|
|
});
|
|
|
|
describe("expandSkill", () => {
|
|
it("produces full injectable text with optional suffix", () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "pi-skill-reinject-expand-"));
|
|
tempDirs.push(dir);
|
|
const meta = writeSkillMd(
|
|
dir,
|
|
"pdf-tools",
|
|
`---
|
|
name: pdf-tools
|
|
---
|
|
|
|
Extract pages from PDFs.
|
|
`,
|
|
);
|
|
|
|
const withoutSuffix = expandSkill(meta);
|
|
expect(withoutSuffix).toContain('name="pdf-tools"');
|
|
expect(withoutSuffix).toContain(`location="${meta.filePath}"`);
|
|
expect(withoutSuffix).toContain(`References are relative to ${meta.baseDir}.`);
|
|
expect(withoutSuffix).toContain("Extract pages from PDFs.");
|
|
|
|
expect(expandSkill(meta, "[skill-reinject] Re-applied.")).toBe(
|
|
`${withoutSuffix}\n\n[skill-reinject] Re-applied.`,
|
|
);
|
|
});
|
|
});
|