// Appends unregistered docs/superpowers/**/*.md entries to manifest.yaml. // Uses yaml.parseDocument for comment-preserving round-trip. // Idempotent: re-running adds 0 entries when all docs are already registered. // Usage: node scripts/scaffold-manifest.mjs import { readFileSync, writeFileSync, readdirSync, existsSync } from 'node:fs'; import { dirname, resolve, join } from 'node:path'; import { fileURLToPath, pathToFileURL } from 'node:url'; import { createRequire } from 'node:module'; import { scaffoldEntryObject, findUnregistered } from './lib/design-index.mjs'; const __dirname = dirname(fileURLToPath(import.meta.url)); const SP = resolve(__dirname, '../docs/superpowers'); // `yaml` lives in ui/node_modules — same resolution pattern as validate-design-docs.mjs const require = createRequire(pathToFileURL(resolve(__dirname, '../ui/package.json'))); const YAML = await import(pathToFileURL(require.resolve('yaml')).href); const SUBDIRS = ['specs', 'plans', 'archived/specs', 'archived/plans']; function listDocs() { const out = []; for (const d of SUBDIRS) { const abs = join(SP, d); if (!existsSync(abs)) continue; for (const f of readdirSync(abs)) { if (f.endsWith('.md')) out.push(`${d}/${f}`); } } return out.sort(); } const mfPath = join(SP, 'manifest.yaml'); const rawYaml = existsSync(mfPath) ? readFileSync(mfPath, 'utf-8') : 'docs:\n'; const doc = YAML.parseDocument(rawYaml); // Ensure `docs` key exists as a sequence (handle null scalar from 'docs:\n' seed) const existingSeq = doc.get('docs', true); if (!(existingSeq instanceof YAML.YAMLSeq)) { doc.set('docs', new YAML.YAMLSeq()); } const seq = doc.get('docs', true); // true = return the node itself, not the JS value seq.flow = false; // force block style for human curability // Build the set of already-registered paths const registered = new Set( (seq.items ?? []).map((n) => n.get('path')) ); const unregistered = findUnregistered(listDocs(), registered); for (const rel of unregistered) { const md = readFileSync(join(SP, rel), 'utf-8'); const entry = scaffoldEntryObject(rel, md); const node = doc.createNode(entry); // Attach # TODO: verify topic comment to the topic scalar node const topicItem = node.get('topic', true); if (topicItem) topicItem.comment = ' TODO: verify topic'; seq.add(node); } writeFileSync(mfPath, String(doc), 'utf-8'); console.log(`scaffold: added ${unregistered.length} entries (total ${seq.items.length})`);