#!/usr/bin/env node
import fs from "fs/promises";
import path from "path";
const SPECS_DIR = path.resolve(process.cwd(), "specs", "continual-improvement");
const OUT_PATH = path.join(SPECS_DIR, "INDEX.md");
function sanitizeNodeId(input) {
return input.replace(/[^a-zA-Z0-9_]/g, "_");
}
function extractValue(lines, key) {
const lower = key.toLowerCase();
const line = lines.find((l) => l.toLowerCase().includes(lower));
if (!line) return "";
const idx = line.indexOf(":");
return idx >= 0 ? line.slice(idx + 1).trim() : line.trim();
}
async function readSpec(filePath) {
const raw = await fs.readFile(filePath, "utf8");
const lines = raw.split(/\r?\n/).slice(0, 80);
const title = lines.find((l) => l.startsWith("#"))?.replace(/^#\s*/, "") ?? path.basename(filePath);
const status = extractValue(lines, "status");
const parent = extractValue(lines, "parent");
const dependencies = extractValue(lines, "dependencies");
return { filePath, title, status, parent, dependencies };
}
async function main() {
try {
await fs.access(SPECS_DIR);
} catch {
process.stdout.write(`No specs directory found at ${SPECS_DIR} — skipping index generation.\n`);
return;
}
const entries = await fs.readdir(SPECS_DIR, { withFileTypes: true });
const files = entries
.filter((e) => e.isFile() && e.name.endsWith(".md") && e.name !== "INDEX.md")
.map((e) => path.join(SPECS_DIR, e.name))
.sort();
const specs = [];
for (const file of files) specs.push(await readSpec(file));
const table = [
"| File | Status | Parent | Dependencies |",
"| --- | --- | --- | --- |",
...specs.map((s) => {
const rel = path.relative(SPECS_DIR, s.filePath);
return `| [${s.title}](${rel}) | ${s.status || ""} | ${s.parent || ""} | ${s.dependencies || ""} |`;
}),
].join("\n");
const edges = specs
.filter((s) => s.parent)
.map((s) => {
const child = sanitizeNodeId(path.basename(s.filePath));
const parent = sanitizeNodeId(s.parent);
return ` ${parent} --> ${child}`;
});
const mermaid = edges.length
? ["```mermaid", "flowchart TD", ...edges, "```"].join("\n")
: "_No explicit parent links found._";
const content = [
"# Continual Improvement Specs Index",
"",
table,
"",
"## Dependency Graph",
"",
mermaid,
"",
"_Generated by `scripts/utils/spec-index.mjs`._",
"",
].join("\n");
await fs.writeFile(OUT_PATH, content, "utf8");
process.stdout.write(`Wrote ${OUT_PATH}\n`);
}
main().catch((err) => {
console.error(err);
process.exit(1);
});