From 622ea5b38c29fa082f98fbd00b41432853ae306f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Wed, 9 Sep 2026 23:49:21 -0400 Subject: [PATCH] test(skills): pin the catalog exemption as a capability and lint the templates list (#3838) The two skills exempt from the catalog search were pinned only by the sentence that declares the exemption, so the exemption would go stale the day either gained a way to install a registry item. The test now also asserts neither skill contains an install command or a registry path. The templates list in the scaffold reference claimed to be lint-checked but lacked the marker that arms the check, so a misspelt template would have passed. It now carries the marker with its presets and skill names allowlisted, and a misspelt template fails the lint. --- .../cli/src/commands/coreSkillContent.test.ts | 23 ++++++++++++++----- skills-manifest.json | 2 +- .../references/init-and-scaffold.md | 2 ++ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/commands/coreSkillContent.test.ts b/packages/cli/src/commands/coreSkillContent.test.ts index 64324a3fd3..f850c3f079 100644 --- a/packages/cli/src/commands/coreSkillContent.test.ts +++ b/packages/cli/src/commands/coreSkillContent.test.ts @@ -1,11 +1,15 @@ // @vitest-environment node -import { readFileSync } from "node:fs"; +import { readdirSync, readFileSync } from "node:fs"; import { join } from "node:path"; import { fileURLToPath } from "node:url"; import { describe, expect, it } from "vitest"; const REPO_ROOT = join(fileURLToPath(new URL(".", import.meta.url)), "..", "..", "..", ".."); const read = (...parts: string[]): string => readFileSync(join(REPO_ROOT, ...parts), "utf8"); +const skillTextFiles = (dir: string): string[] => + readdirSync(dir, { recursive: true, withFileTypes: true }) + .filter((entry) => entry.isFile() && /\.(md|mjs|cjs|js|ts|json|html)$/.test(entry.name)) + .map((entry) => join(entry.parentPath, entry.name)); describe("hyperframes-core contract docs", () => { it("keeps a runnable root in the minimal composition skeleton", () => { @@ -183,13 +187,20 @@ describe("media treatment routing documentation", () => { // registry item is a standalone composition with no place to mount. The // exemption is written into each skill so the next reader does not close // the gap with an instruction that would be false there. - for (const file of [ - ["skills", "embedded-captions", "SKILL.md"], - ["skills", "talking-head-recut", "SKILL.md"], - ]) { - expect(read(...file), file.join("/")).toContain( + for (const skill of ["embedded-captions", "talking-head-recut"]) { + expect(read("skills", skill, "SKILL.md"), skill).toContain( "does not search the HyperFrames component registry", ); + // The exemption is a capability claim, so pin the capability and not only + // the sentence: the day either skill gains a way to install a registry item, + // this fails and the exemption has to be reconsidered. `data-composition-src` + // is deliberately not the signal; talking-head-recut mounts its own chapters + // with it, which is not a registry item. + for (const file of skillTextFiles(join(REPO_ROOT, "skills", skill))) { + expect(readFileSync(file, "utf8"), file).not.toMatch( + /hyperframes add\b|registry\/(blocks|components)\//, + ); + } } // The symptom-triggered description is the other half of the fix: the skill diff --git a/skills-manifest.json b/skills-manifest.json index 50188d976b..e7a0a823c0 100644 --- a/skills-manifest.json +++ b/skills-manifest.json @@ -30,7 +30,7 @@ "files": 7 }, "hyperframes-cli": { - "hash": "03b1b65f35a1be63", + "hash": "bc52d3d36b7cd934", "files": 11 }, "hyperframes-core": { diff --git a/skills/hyperframes-cli/references/init-and-scaffold.md b/skills/hyperframes-cli/references/init-and-scaffold.md index 5e04614094..0e4c85d2a8 100644 --- a/skills/hyperframes-cli/references/init-and-scaffold.md +++ b/skills/hyperframes-cli/references/init-and-scaffold.md @@ -1,5 +1,7 @@ # init, capture, skills + + Scaffolding commands. Use these instead of creating files by hand — they set up the right file structure, copy media, run transcription, and install AI coding skills. ## init