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.
This commit is contained in:
Miguel Ángel
2026-09-10 03:49:21 +00:00
committed by GitHub
parent 0f8eb892e3
commit 622ea5b38c
3 changed files with 20 additions and 7 deletions
@@ -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
+1 -1
View File
@@ -30,7 +30,7 @@
"files": 7
},
"hyperframes-cli": {
"hash": "03b1b65f35a1be63",
"hash": "bc52d3d36b7cd934",
"files": 11
},
"hyperframes-core": {
@@ -1,5 +1,7 @@
# init, capture, skills
<!-- registry-items: allow=blank,landscape-4k,portrait-4k,square-4k,product-launch-video,hyperframes-core,media-use -->
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