#!/usr/bin/env node import { existsSync, readFileSync } from "node:fs"; const requiredFiles = [ "src/shared/lib/buildLoop.ts", "src/features/build-loop/pages/BuildLoopDashboard.tsx", "src/app/routes.tsx", "src/shared/lib/navigation.tsx", "src/shared/components/ProjectFlowRail.tsx", "src/features/projects/pages/Workspace.tsx", "src/features/projects/pages/Projects.tsx", "src/features/execution/pages/ExecutionCenter.tsx", "src/features/repo-builder/pages/RepoBuilder.tsx", "src/features/handoffs/pages/CodexHandoffs.tsx", "src/features/execution-feedback/pages/ExecutionFeedback.tsx", "src/features/audit/pages/ProjectAuditCenter.tsx", "src/shared/lib/projectOperatingStep.ts", "src/shared/lib/projectSearch.ts", "src/shared/lib/routeRegistry.ts", "package.json", ]; const failures = []; for (const file of requiredFiles) { if (!existsSync(file)) failures.push(`Missing required file: ${file}`); } const read = (file) => readFileSync(file, "utf8"); const text = Object.fromEntries(requiredFiles.filter(existsSync).map((file) => [file, read(file)])); const helper = text["src/shared/lib/buildLoop.ts"] ?? ""; const page = text["src/features/build-loop/pages/BuildLoopDashboard.tsx"] ?? ""; const routes = text["src/app/routes.tsx"] ?? ""; const navigation = text["src/shared/lib/navigation.tsx"] ?? ""; const flowRail = text["src/shared/components/ProjectFlowRail.tsx"] ?? ""; const workspace = text["src/features/projects/pages/Workspace.tsx"] ?? ""; const projects = text["src/features/projects/pages/Projects.tsx"] ?? ""; const execution = text["src/features/execution/pages/ExecutionCenter.tsx"] ?? ""; const repoBuilder = text["src/features/repo-builder/pages/RepoBuilder.tsx"] ?? ""; const handoffs = text["src/features/handoffs/pages/CodexHandoffs.tsx"] ?? ""; const feedback = text["src/features/execution-feedback/pages/ExecutionFeedback.tsx"] ?? ""; const audit = text["src/features/audit/pages/ProjectAuditCenter.tsx"] ?? ""; const operatingStep = text["src/shared/lib/projectOperatingStep.ts"] ?? ""; const projectSearch = text["src/shared/lib/projectSearch.ts"] ?? ""; const routeRegistry = text["src/shared/lib/routeRegistry.ts"] ?? ""; const pkg = text["package.json"] ?? ""; const mustContain = [ [helper, "getBuildLoopStatus", "buildLoop helper must expose getBuildLoopStatus."], [helper, "getCurrentBuildLoopPhase", "buildLoop helper must derive current phase."], [helper, "getRecommendedBuildLoopAction", "buildLoop helper must recommend next action."], [helper, "getBuildLoopRisks", "buildLoop helper must derive risks."], [helper, "getBuildLoopValidationSummary", "buildLoop helper must summarize validation."], [helper, "getBuildLoopSkillCoverage", "buildLoop helper must summarize skill coverage."], [helper, "getBuildLoopProgress", "buildLoop helper must calculate progress."], [helper, "formatBuildLoopMarkdown", "buildLoop helper must export markdown."], [helper, "repositoryIntakes", "buildLoop helper must use repository intakes/gaps."], [helper, "codexHandoffs", "buildLoop helper must use Codex handoffs."], [helper, "handoffReviews", "buildLoop helper must use handoff reviews."], [helper, "codexSessionPacks", "buildLoop helper must use session packs."], [helper, "Create Codex session pack", "buildLoop helper must recommend creating session packs."], [helper, "Run session and add feedback", "buildLoop helper must recommend feedback after session packs."], [helper, "latestSessionPack", "buildLoop helper must expose latest session pack."], [helper, "codexExecutionFeedback", "buildLoop helper must use execution feedback."], [helper, "getActiveProjectSkills", "buildLoop helper must use Codex skills."], [routes, "/projects/:projectId/build-loop", "Build Loop route missing."], [routes, "BuildLoopDashboard", "Build Loop page must be imported in routes."], [navigation, "getPrimaryPathNavigationItems", "Primary navigation must expose the workspace that owns the Build Loop entry."], [routeRegistry, 'key: "workspace"', "Canonical route registry must expose the workspace that owns the Build Loop entry."], [flowRail, 'id: "build-loop"', "Project Flow Rail must include Build Loop."], [navigation, '`${base}/build-loop`', "Technical navigation must expose Build Loop."], [workspace, "Technische details", "Workspace must progressively disclose technical execution."], [page, "getBuildLoopStatus", "Technical Build Loop must use the shared helper."], [projects, "resolveProjectListOperatingState", "Projects must combine daily guidance with live Auto state."], [projects, "getProjectOperatingStep", "Projects cards must derive the central next safe action."], [projects, "operatingState.label", "Projects must render the central operating-state label."], [projects, "operatingState.description", "Projects must render the central operating-state explanation."], [execution, "View build loop", "Execution Center must link to Build Loop."], [execution, "getBuildLoopStatus", "Execution Center must use Build Loop recommended action."], [repoBuilder, "Naar de buildloop", "Repo Builder must link back to the Build Loop from its task-first header."], [handoffs, "View in Build Loop", "Codex Handoffs must link to Build Loop."], [feedback, "Linked session pack", "Execution Feedback must link session packs."], [feedback, "Return to Build Loop", "Execution Feedback must link back to Build Loop."], [audit, "Build Loop cockpit", "Audit Center must show Build Loop coverage."], [audit, "Codex session pack readiness", "Audit Center must show session pack coverage."], [projectSearch, 'type: "buildLoop"', "Search index must include Build Loop result."], [page, "Technische uitvoeringsstatus", "Build Loop page must show status summary."], [page, "Interne fasen", "Build Loop page must show timeline."], [page, "Geslaagde controles", "Build Loop page must show safety and validation."], [page, "Repositorytoestand", "Build Loop page must show repo health."], [page, "uitvoeringsprofielen", "Build Loop page must show skill coverage."], [helper, "latestSessionPack", "Build Loop data must retain session pack readiness."], [helper, "codexExecutionFeedback", "Build Loop data must retain execution feedback."], [page, "Recente technische gebeurtenissen", "Build Loop page must show recent events."], [helper, "formatBuildLoopMarkdown", "Build Loop must retain its export formatter."], [pkg, "audit:build-loop", "package.json must expose audit:build-loop."], [pkg, "check-build-loop-readiness.mjs", "package.json must wire Build Loop readiness script."], ]; for (const [haystack, needle, message] of mustContain) { if (!haystack.includes(needle)) failures.push(message); } const scripts = JSON.parse(pkg || "{}").scripts ?? {}; const experienceAudit = scripts["audit:experience"] ?? ""; const allAudit = scripts["audit:all"] ?? ""; if (!experienceAudit.includes("audit:build-loop") || !allAudit.includes("audit:experience")) { failures.push("audit:all must include the experience gate with Build Loop readiness."); } if (failures.length) { console.error("ProjectBrain build loop readiness: FAIL"); for (const failure of failures) console.error(`- ${failure}`); process.exit(1); } console.log("ProjectBrain build loop readiness: PASS");