#!/usr/bin/env node const fs = require("node:fs"); const path = require("node:path"); const root = path.resolve(__dirname, ".."); const publicDocs = [ "README.md", "SECURITY.md", "docs/getting-started.md", "docs/architecture.md", "docs/nodes.md", "docs/environments.md", "docs/artifacts.md", "docs/debugging.md", "docs/task-abi.md", "docs/self-hosting.md", "docs/security.md", ]; const privateDocs = [ "private/docs/hosted-deployment.md", "private/docs/authentik.md", "private/docs/community-policy.md", "private/docs/bandwidth-and-cost-controls.md", "private/docs/publishing.md", ]; const internalDocs = ["internal/finish_mvp_2.md"]; const filteredPublicTree = process.env.CLUSTERFLUX_FILTERED_PUBLIC_TREE === "1" || fs.existsSync(path.join(root, "CLUSTERFLUX_PUBLIC_TREE.json")); const failures = []; const expectExactMarkdownSet = (directory, expected) => { const actual = fs .readdirSync(path.join(root, directory), { withFileTypes: true }) .filter((entry) => entry.isFile() && entry.name.endsWith(".md")) .map((entry) => path.posix.join(directory, entry.name)) .sort(); const wanted = [...expected].sort(); if (JSON.stringify(actual) !== JSON.stringify(wanted)) { failures.push(`${directory} markdown set is ${actual.join(", ")}; expected ${wanted.join(", ")}`); } }; const requiredDocs = filteredPublicTree ? publicDocs : [...publicDocs, ...privateDocs, ...internalDocs]; for (const file of requiredDocs) { if (!fs.existsSync(path.join(root, file))) failures.push(`missing canonical document: ${file}`); } expectExactMarkdownSet("docs", publicDocs.filter((file) => file.startsWith("docs/"))); if (filteredPublicTree) { for (const directory of ["private", "internal"]) { if (fs.existsSync(path.join(root, directory))) { failures.push(`${directory}/ must not exist in the filtered public tree`); } } } const forbidden = [ [/\bmvp\b/i, "internal milestone term"], [/acceptance criteria/i, "internal gate language"], [/release verification/i, "internal release language"], [/public\/private source split/i, "source split narrative"], [/founder|business decisions/i, "business planning narrative"], [/hacker news|\bHN\b/, "launch-channel narrative"], [/\busers can\b/i, "indirect reader wording"], [/node\s+scripts\//i, "developer script instruction"], [/scripts\/[^\s)]*smoke/i, "smoke script instruction"], [/internal\/[^\s)]*/i, "internal tooling reference"], [/private\/[^\s)]*/i, "private source reference"], ]; const topLevelCommands = new Set([ "doctor", "login", "logout", "auth", "agent", "key", "project", "inspect", "build", "bundle", "run", "node", "process", "task", "logs", "artifact", "dap", "debug", "quota", "admin", ]); for (const file of publicDocs) { const absolute = path.join(root, file); const content = fs.readFileSync(absolute, "utf8"); for (const [pattern, description] of forbidden) { if (pattern.test(content)) failures.push(`${file}: contains ${description}`); } for (const match of content.matchAll(/\]\(([^)#]+)(?:#[^)]+)?\)/g)) { const target = match[1]; if (/^(?:https?:|mailto:)/.test(target)) continue; const resolved = path.resolve(path.dirname(absolute), target); if (!fs.existsSync(resolved)) failures.push(`${file}: broken link ${target}`); } for (const line of content.split(/\r?\n/)) { const command = line.trim().match(/^clusterflux\s+([a-z][a-z-]*)\b/); if (command && !topLevelCommands.has(command[1])) { failures.push(`${file}: unknown top-level CLI command ${command[1]}`); } } } const rootMarkdown = fs .readdirSync(root, { withFileTypes: true }) .filter((entry) => entry.isFile() && entry.name.endsWith(".md")) .map((entry) => entry.name) .sort(); if (JSON.stringify(rootMarkdown) !== JSON.stringify(["README.md", "SECURITY.md"])) { failures.push(`top-level markdown set is ${rootMarkdown.join(", ")}; expected README.md, SECURITY.md`); } if (failures.length) { for (const failure of failures) console.error(failure); process.exit(1); } console.log("documentation checks passed");