import assert from "node:assert/strict"; import { mkdtemp, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join, sep } from "node:path"; import test from "node:test"; import { type AuditUsedSkill, loadSkillsRegistry, parseSkillsRegistry, toAuditUsedSkill, SKILL_CATEGORIES, } from "../lib/skills-registry"; function assertIncludes(values: readonly string[], value: string) { assert.ok(values.includes(value), `Expected ${value} in [${values.join(", ")}]`); } function withTempProjectRegistry( source: string, run: () => Promise | void, ) { return mkdtemp(`${tmpdir()}${sep}`).then(async (projectRoot) => { const registryPath = join(projectRoot, "skills.md"); const originalCwd = process.cwd(); await writeFile(registryPath, source, "utf8"); process.chdir(projectRoot); try { await run(); } finally { process.chdir(originalCwd); await rm(projectRoot, { recursive: true, force: true }); } }); } test("parseSkillsRegistry parses valid entries, trims whitespace, and normalizes category", async () => { const registrySource = ` ## Design Audit Purpose: Evaluate layout, visual hierarchy, and CTA clarity. When to use: Use when a homepage is available and should be assessed for conversion quality. When not to use: Don't run during technical outages or non-web touchpoints. Required input: Homepage URL, top-level page sections, style language, brand context. Expected output: Prioritized improvement list with concrete design changes. Category: design Version: 2026.06 Source: skills/design-audit.md `; const parsed = parseSkillsRegistry(registrySource); assert.equal(parsed.length, 1); const entry = parsed.at(0); assert.ok(entry); assert.equal(entry!.name, "Design Audit"); assert.equal(entry!.purpose, "Evaluate layout, visual hierarchy, and CTA clarity."); assert.equal(entry!.category, "design"); assert.equal(entry!.version, "2026.06"); assert.equal(entry!.source, "skills/design-audit.md"); }); test("parseSkillsRegistry accepts indented field labels", () => { const registrySource = ` ## Local SEO Boost Purpose: Evaluate visibility for local search with nearby intent. When to use: Use for local business pages and service locations. When not to use: Avoid for non-local marketing pages. Required input: City, address, NAP consistency. Expected output: Prioritized local SEO recommendations. Category: seo `; const parsed = parseSkillsRegistry(registrySource); assert.equal(parsed.length, 1); const entry = parsed.at(0); assert.ok(entry); assert.equal(entry!.name, "Local SEO Boost"); assert.equal(entry!.purpose, "Evaluate visibility for local search with nearby intent."); assert.equal(entry!.category, "seo"); }); test("parseSkillsRegistry throws for missing required fields", () => { const registrySource = ` ## UX Friction Review Purpose: Review interaction patterns for friction points. When to use: Use for lead capture and booking flows. When not to use: Use only when there is a user journey. Required input: Session flow and target action. Category: ux `; assert.throws( () => parseSkillsRegistry(registrySource), /missing required field "Expected output"/i, ); }); test("parseSkillsRegistry throws for unknown category", () => { const registrySource = ` ## Bad Category Example Purpose: Example. When to use: Example scenario. When not to use: Never for this case. Required input: Example data. Expected output: Example output. Category: analytics `; assert.throws( () => parseSkillsRegistry(registrySource), /unknown category "analytics"/i, ); }); test("parseSkillsRegistry throws for duplicate skill names", () => { const registrySource = ` ## Local SEO Boost Purpose: Strengthen local SERPs. When to use: Use for local service businesses. When not to use: Not for international-only landing pages. Required input: Name, address, service area. Expected output: Local SEO gaps and quick wins. Category: seo ## Local SEO Boost Purpose: Another local SEO pass. When to use: Use for new regions. When not to use: Skip for pure lead-gen pages. Required input: Name, address, service area. Expected output: Competitor baseline. Category: seo `; assert.throws( () => parseSkillsRegistry(registrySource), /duplicate skill name "Local SEO Boost"/i, ); }); test("parseSkillsRegistry accepts all configured categories", () => { assertIncludes(SKILL_CATEGORIES, "design"); assertIncludes(SKILL_CATEGORIES, "ux"); assertIncludes(SKILL_CATEGORIES, "marketing"); assertIncludes(SKILL_CATEGORIES, "copy"); assertIncludes(SKILL_CATEGORIES, "seo"); assertIncludes(SKILL_CATEGORIES, "offer"); const registrySource = SKILL_CATEGORIES.map( (category) => ` ## ${category}-skill Purpose: Valid for ${category}. When to use: Use for ${category} tasks. When not to use: Skip when ${category} is not in scope. Required input: Category inputs. Expected output: Category-specific recommendations. Category: ${category} `, ).join("\n\n"); const parsed = parseSkillsRegistry(registrySource); assert.equal(parsed.length, SKILL_CATEGORIES.length); for (const category of SKILL_CATEGORIES) { const match = parsed.find((entry) => entry.name === `${category}-skill`); assert.ok(match, `Expected parsed entry for ${category}`); assert.equal(match.category, category); } }); test("loadSkillsRegistry reads skills.md from process.cwd() by default", async () => { await withTempProjectRegistry( ` ## Offer Writing Purpose: Build offer-focused copy for outreach. When to use: Use before drafting proposals. When not to use: Avoid when no offer exists. Required input: Offer structure and pricing envelope. Expected output: Offer draft and pricing emphasis. Category: offer `, async () => { const parsed = await loadSkillsRegistry(); const parsedEntry = parsed.find((entry) => entry.name === "Offer Writing"); assert.ok(parsedEntry); assert.equal(parsedEntry.category, "offer"); }, ); }); test("loadSkillsRegistry accepts an explicit registry path", async () => { const projectRoot = await mkdtemp(`${tmpdir()}${sep}`); const registryPath = join(projectRoot, "seed-skills.md"); await writeFile( registryPath, ` ## Design Audit Purpose: Validate design quality for local business pages. When to use: Use for a quick visual prioritization pass. When not to use: Skip when no public page exists. Required input: Homepage URL and target conversion goal. Expected output: Ranked design actions with confidence. Category: design `, "utf8", ); try { const parsed = await loadSkillsRegistry(registryPath); assert.equal(parsed.at(0)?.name, "Design Audit"); } finally { await rm(projectRoot, { recursive: true, force: true }); } }); test("toAuditUsedSkill returns only required audit-facing fields", () => { const skill = { name: "Copy Clarity", purpose: "Reduce complexity and improve readability.", whenToUse: "When existing copy is verbose.", whenNotToUse: "Skip if website is plain text-only.", requiredInput: "Page sections and CTAs.", expectedOutput: "A concise writing pass.", category: "copy", version: "1.0", source: "skills/copy-clarity.md", } satisfies { name: string; purpose: string; whenToUse: string; whenNotToUse: string; requiredInput: string; expectedOutput: string; category: "copy"; version: string; source: string; }; const auditUsed = toAuditUsedSkill(skill); const expected: AuditUsedSkill = { name: "Copy Clarity", category: "copy", version: "1.0", source: "skills/copy-clarity.md", }; assert.deepEqual(auditUsed, expected); });