#!/usr/bin/env node import { existsSync, readFileSync } from "node:fs"; import { join } from "node:path"; const root = process.cwd(); const errors = []; const localArtifacts = []; const info = []; const showLocalArtifacts = process.env.PROJECTBRAIN_AUDIT_VERBOSE_LOCAL_ARTIFACTS === "1"; const requireFile = (path, label = path) => { if (!existsSync(join(root, path))) errors.push(`Missing ${label}: ${path}`); }; const requireText = (path, text, label = text) => { const fullPath = join(root, path); if (!existsSync(fullPath)) { errors.push(`Missing file for text check: ${path}`); return; } const content = readFileSync(fullPath, "utf8"); if (!content.includes(text)) errors.push(`Missing ${label} in ${path}`); }; const warnIfExists = (path, label = path) => { if (existsSync(join(root, path))) localArtifacts.push(`Generated or legacy artifact present: ${label}`); }; const rootPackage = JSON.parse(readFileSync(join(root, "package.json"), "utf8")); const backendPackage = JSON.parse(readFileSync(join(root, "backend/package.json"), "utf8")); const parseWorkspaceAllowBuilds = (workspaceYaml) => { const allowed = new Set(); const allowBuildsIndex = workspaceYaml.indexOf("allowBuilds:"); if (allowBuildsIndex === -1) return allowed; const lines = workspaceYaml.slice(allowBuildsIndex).split("\n").slice(1); for (const line of lines) { if (/^[^\s#]/.test(line)) break; const match = line.match(/^\s*[\'"]?([^\'":]+)[\'"]?\s*:\s*(true|false)\s*(?:#.*)?$/); if (match && match[2] === "true") allowed.add(match[1].trim()); } return allowed; }; const workspaceAllowBuilds = existsSync(join(root, "pnpm-workspace.yaml")) ? parseWorkspaceAllowBuilds(readFileSync(join(root, "pnpm-workspace.yaml"), "utf8")) : new Set(); if (rootPackage.packageManager !== "pnpm@11.5.2") { errors.push("Root package.json must pin packageManager to pnpm@11.5.2 so Docker/Corepack does not float to a different pnpm release."); } const requiredPnpmBuiltDeps = ["@prisma/client", "@prisma/engines", "@swc/core", "esbuild", "prisma"]; for (const dependency of requiredPnpmBuiltDeps) { if (!workspaceAllowBuilds.has(dependency)) { errors.push(`pnpm-workspace.yaml allowBuilds must approve ${dependency} for Docker builds with pnpm 11.`); } } console.log("ProjectBrain doctor"); console.log("==================="); [ "README.md", ".env.example", "backend/.env.example", "docs/PROJECTBRAIN_DOCUMENTATION_INDEX.md", "docs/FULL_VERSION_ROADMAP.md", "docs/VERTICAL_SLICE_CORE_FLOW_PLAN.md", "docs/PROJECTBRAIN_STATUS_AND_GATES.md", "docs/P2_LOCAL_RUNTIME_VERIFICATION.md", "docs/RUNTIME_ROUND_5_BACKEND_HEALTH_AND_SUITE.md", "docs/PROJECTBRAIN_RUNTIME_COMMANDS.md", "backend/scripts/smoke-p2.mjs", "backend/scripts/smoke-fixture-api.mjs", "backend/scripts/smoke-real-read-pilot.mjs", "backend/scripts/smoke-vertical-slice.mjs", "backend/scripts/smoke-runtime-suite.mjs", "backend/scripts/docker-entrypoint.sh", "scripts/check-database-readiness.mjs", "public/site.webmanifest", "public/favicon.svg", "public/favicon.ico", ].forEach((file) => requireFile(file)); [ ["validate:all", "root validation"], ["audit:release", "release hygiene audit"], ["audit:runtime", "runtime readiness audit"], ["audit:database", "database readiness audit"], ["smoke:backend:fixtures", "fixture smoke"], ["smoke:backend:real-read-pilot", "real-read pilot smoke"], ["smoke:backend:vertical-slice", "vertical slice smoke"], ["smoke:backend:runtime-suite", "runtime suite smoke"], ["smoke:backend:database-suite", "database suite smoke"], ["smoke:backend:brainstorms", "Brainstorm CPU smoke"], ["smoke:backend:initiatives", "Initiative smoke"], ].forEach(([script, label]) => { if (!rootPackage.scripts?.[script]) errors.push(`Missing ${label} script: ${script}`); }); [ ["smoke:p2", "P2 database smoke"], ["smoke:fixtures", "fixture smoke"], ["smoke:real-read-pilot", "real read smoke"], ["smoke:vertical-slice", "vertical slice smoke"], ["smoke:runtime-suite", "runtime suite smoke"], ["smoke:database-suite", "database suite smoke"], ["smoke:brainstorms", "Brainstorm CPU smoke"], ["smoke:initiatives", "Initiative smoke"], ["db:deploy", "Prisma migrate deploy"], ["db:status", "Prisma migration status"], ["db:validate", "Prisma schema validate"], ].forEach(([script, label]) => { if (!backendPackage.scripts?.[script]) errors.push(`Missing backend ${label} script: ${script}`); }); requireText("index.html", "