// Validates docs/superpowers/manifest.yaml against files on disk. // Usage: node scripts/validate-design-docs.mjs [--check] import { readFileSync, readdirSync, existsSync } from 'node:fs'; import { dirname, resolve, join } from 'node:path'; import { fileURLToPath, pathToFileURL } from 'node:url'; import { createRequire } from 'node:module'; import { validateManifest } from './lib/design-index.mjs'; import { buildIndex } from './gen-design-index.mjs'; const __dirname = dirname(fileURLToPath(import.meta.url)); const SP = resolve(__dirname, '../docs/superpowers'); // `yaml` lives in ui/node_modules — resolve relative to ui/package.json, // exactly like scripts/validate-help-docs.mjs does. let parseYaml; try { const require = createRequire(pathToFileURL(resolve(__dirname, '../ui/package.json'))); ({ parse: parseYaml } = await import(pathToFileURL(require.resolve('yaml')).href)); } catch { console.error("design-docs validation: cannot load 'yaml' from ui/node_modules — run `npm --prefix ui install`"); process.exit(1); } const SUBDIRS = ['specs', 'plans', 'archived/specs', 'archived/plans']; export 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(); } // Main guard: only run validation side-effects when executed directly. // Importing this module (e.g. to use listDocs) will NOT trigger the block below. if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { // FIX I-1: guard against missing manifest.yaml (Task 3 hasn't generated it yet) const manifestRaw = existsSync(join(SP, 'manifest.yaml')) ? readFileSync(join(SP, 'manifest.yaml'), 'utf-8') : 'docs: []'; const manifest = parseYaml(manifestRaw) ?? { docs: [] }; const { errors, warnings } = validateManifest(manifest.docs ?? [], listDocs()); for (const w of warnings) console.warn(`[warn] ${w}`); for (const e of errors) console.error(`[error] ${e}`); if (process.argv.includes('--check')) { const cur = existsSync(join(SP, 'index.md')) ? readFileSync(join(SP, 'index.md'), 'utf-8') : ''; if (cur !== buildIndex()) { console.error('[error] index.md is stale — run node scripts/gen-design-index.mjs'); process.exit(1); } } if (errors.length) { console.error(`design-docs validation FAILED (${errors.length} errors)`); process.exit(1); } console.log(`design-docs validation OK (${(manifest.docs ?? []).length} entries, ${warnings.length} warnings)`); }