db4ae19c0a
Move all 24 review entries from skills-review/catalog.js +
skills-review/submitted-catalog.js into a typed Astro content collection at
src/content/reviews/. Each entry is a Markdown file with frontmatter for the
review metadata (id, author, focus, wins, improve, extras, name, description)
and a body that holds the 'improved' SKILL.md content.
Re-point scripts/build-skill-review.mjs at the new collection. The generator
reads each .md file, parses its YAML frontmatter, and writes
skill-reviews/improved/{id}/SKILL.md in the same shape the legacy catalog
produced — verified byte-identical via 'git diff --exit-code skill-reviews/'.
The 'name' field is preserved separately from 'id' because two entries
renamed the skill during review (id angular-accessibility-root → name
angular-accessibility; id confectionary-skill-hub → name confectionery-orders).
Without it the generator output would drift on those two files.
Does not yet delete skills-review/catalog.js or submitted-catalog.js —
verify.mjs and the legacy review-desk page both still read them, so they
stay as a mirror until task 16 rewires the page to the collection. Adding a
new submission today requires editing both the .md file (new source of
truth) and the legacy catalog.js (until task 16).
Done-when:
- 24 entries under src/content/reviews/ ✓
- verify.mjs's id:' count assertion still passes ✓
- git diff --exit-code skill-reviews/ clean after regenerating ✓
- astro check passes (22 files: 0 errors, 0 warnings, 2 hints) ✓
Co-Authored-By: Claude Code <noreply@anthropic.com>
69 lines
2.9 KiB
JavaScript
69 lines
2.9 KiB
JavaScript
// Regenerate skill-reviews/improved/**/SKILL.md from the content collection.
|
|
//
|
|
// Source of truth: src/content/reviews/{id}.md. Each file's frontmatter holds
|
|
// the review metadata (id, author, focus, wins, improve, extras,
|
|
// description); its body is the Markdown that becomes the SKILL.md file.
|
|
// This script reconstructs the SKILL.md frontmatter (name + description) and
|
|
// concatenates it with the body, so the committed output stays byte-identical
|
|
// to what the legacy catalog produced:
|
|
//
|
|
// --- <- SKILL.md frontmatter starts
|
|
// name: <id>
|
|
// description: <description>
|
|
// ---
|
|
//
|
|
// # <id>
|
|
// <- body, as written in the .md file
|
|
// ...
|
|
//
|
|
// Run from the repository root:
|
|
//
|
|
// node scripts/build-skill-review.mjs && git diff --exit-code skill-reviews/
|
|
//
|
|
// A non-empty diff means the collection drifted from the committed output;
|
|
// regenerate after every entry edit.
|
|
|
|
import { mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
|
|
import { dirname, join } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
const root = dirname(here);
|
|
const REVIEWS_DIR = join(root, 'src', 'content', 'reviews');
|
|
const OUTPUT_DIR = join(root, 'skill-reviews', 'improved');
|
|
|
|
const parseFrontmatter = (text) => {
|
|
// Strict shape: starts with `---\n`, ends at the next `---\n`, then body.
|
|
if (!text.startsWith('---\n')) throw new Error('missing leading ---');
|
|
const end = text.indexOf('\n---\n', 4);
|
|
if (end === -1) throw new Error('missing closing ---');
|
|
const yaml = text.slice(4, end);
|
|
const body = text.slice(end + 5);
|
|
const id = yaml.match(/^id:\s*"?([^"\n]+)"?\s*$/m)?.[1];
|
|
const name = yaml.match(/^name:\s*"?([^"\n]+)"?\s*$/m)?.[1];
|
|
const description = yaml.match(/^description:\s*"?((?:\\.|[^"\\])*)"?\s*$/m)?.[1];
|
|
if (!id) throw new Error('frontmatter missing id');
|
|
if (!name) throw new Error('frontmatter missing name');
|
|
if (!description) throw new Error('frontmatter missing description');
|
|
return { id, name, description, body };
|
|
};
|
|
|
|
const files = readdirSync(REVIEWS_DIR)
|
|
.filter((f) => f.endsWith('.md'))
|
|
.sort();
|
|
let count = 0;
|
|
for (const file of files) {
|
|
const source = readFileSync(join(REVIEWS_DIR, file), 'utf8');
|
|
const { id, name, description, body } = parseFrontmatter(source);
|
|
// The body in the .md file starts with `# <name>\n\n` then the Markdown
|
|
// content; strip a single leading newline if present so the reconstructed
|
|
// SKILL.md matches the legacy `skill(...)` output exactly.
|
|
const stripped = body.startsWith('\n') ? body.slice(1) : body;
|
|
const output = `---\nname: ${name}\ndescription: ${description}\n---\n\n${stripped.trim()}\n`;
|
|
const outPath = join(OUTPUT_DIR, id, 'SKILL.md');
|
|
mkdirSync(dirname(outPath), { recursive: true });
|
|
writeFileSync(outPath, output);
|
|
count += 1;
|
|
}
|
|
console.log(`wrote ${count} improved skill drafts`);
|