#!/usr/bin/env node import { existsSync, readFileSync } from "node:fs"; const requiredFiles = [ "src/shared/lib/model.ts", "src/shared/lib/codexSkills.ts", "src/shared/lib/repositoryIntake.ts", "src/shared/lib/codexHandoff.ts", "src/shared/lib/projectWizard.ts", "src/shared/lib/safeData.ts", "src/shared/contexts/ProjectContext.tsx", "src/features/skills/pages/SkillLibrary.tsx", "src/features/repo-builder/pages/RepoBuilder.tsx", "src/features/execution/pages/ExecutionCenter.tsx", "src/features/prompts/pages/PromptGenerator.tsx", "src/features/history/pages/ProjectHistory.tsx", "src/features/projects/pages/Workspace.tsx", "src/shared/components/ProjectFlowRail.tsx", "src/app/routes.tsx", "src/shared/lib/navigation.tsx", "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 fileText = Object.fromEntries(requiredFiles.filter(existsSync).map((file) => [file, read(file)])); const catalog = fileText["src/shared/lib/codexSkills.ts"] ?? ""; const repositoryIntake = fileText["src/shared/lib/repositoryIntake.ts"] ?? ""; const codexHandoff = fileText["src/shared/lib/codexHandoff.ts"] ?? ""; const model = fileText["src/shared/lib/model.ts"] ?? ""; const routes = fileText["src/app/routes.tsx"] ?? ""; const navigation = fileText["src/shared/lib/navigation.tsx"] ?? ""; const context = fileText["src/shared/contexts/ProjectContext.tsx"] ?? ""; const skillPage = fileText["src/features/skills/pages/SkillLibrary.tsx"] ?? ""; const repoBuilder = fileText["src/features/repo-builder/pages/RepoBuilder.tsx"] ?? ""; const execution = fileText["src/features/execution/pages/ExecutionCenter.tsx"] ?? ""; const promptBuilder = fileText["src/features/prompts/pages/PromptGenerator.tsx"] ?? ""; const history = fileText["src/features/history/pages/ProjectHistory.tsx"] ?? ""; const projectWizard = fileText["src/shared/lib/projectWizard.ts"] ?? ""; const safeData = fileText["src/shared/lib/safeData.ts"] ?? ""; const flowRail = fileText["src/shared/components/ProjectFlowRail.tsx"] ?? ""; const workspace = fileText["src/features/projects/pages/Workspace.tsx"] ?? ""; const pkg = fileText["package.json"] ?? ""; const mustContain = [ [model, "export interface CodexSkill", "CodexSkill model missing."], [model, "ProjectSkillSelection", "Project skill selection model missing."], [model, "codexSkills?: ProjectSkillSelection[]", "Project model must persist skill selections."], [catalog, "getBuiltInCodexSkills", "Built-in skill catalog helper missing."], [catalog, "recommendSkillsForProject", "Project skill recommendation helper missing."], [catalog, "formatSkillsForCodexHandoff", "Codex handoff formatter missing."], [safeData, "codexSkills: asArray(project.codexSkills)", "Runtime normalization must preserve project skills."], [projectWizard, "Recommended Codex skills", "Project creation output must include recommended Codex skills."], [context, "setProjectSkillEnabled", "ProjectContext must allow enabling/disabling project skills."], [context, "applyRecommendedProjectSkills", "ProjectContext must apply recommended skills."], [context, "codexSkillItems", "Global search must include Codex skills."], [routes, "/projects/:projectId/skills", "Skill Library route missing."], [routes, "SkillLibrary", "Skill Library page missing from routes."], [navigation, "Codex Skills", "Navigation must expose Codex Skills."], [flowRail, 'id: "skills"', "Project flow rail must include the Skills step."], [workspace, "Codex Skills", "Workspace must expose Codex Skills."], [skillPage, "Built-in skills", "Skill Library must show built-in skills."], [skillPage, "Recommended", "Skill Library must show recommended skills."], [skillPage, "Active project skills", "Skill Library must show active project skills."], [skillPage, "requiredContext", "Skill detail must expose required context."], [skillPage, "validationCommands", "Skill detail must expose validation commands."], [skillPage, "promptInstructions", "Skill detail must expose prompt instructions."], [repoBuilder, "Skill set", "Repo Builder must expose a Skill set panel."], [repoBuilder, "formatSkillsForCodexHandoff", "Repo Builder handoff/export must include skill blocks."], [repoBuilder, "skillIds", "Repo Builder artifacts must persist skill links."], [repositoryIntake, "mapRepositoryEntriesToSkills", "Repository intake must map imported repo evidence to Codex skills."], [repositoryIntake, "linkedSkillIds", "Repository intakes must retain linked skill ids."], [repoBuilder, "Matched skills", "Repository intake detail must show matched skills."], [codexHandoff, "promptInstructions", "Codex handoffs must include skill prompt instructions."], [codexHandoff, "qualityChecklist", "Codex handoffs must include skill quality checklist."], [codexHandoff, "riskNotes", "Codex handoffs must include skill risk notes."], [codexHandoff, "typicalFiles", "Codex handoffs must include skill typical files."], [execution, "Active Codex Skills", "Execution Center must show active skills."], [execution, "formatSkillsForCodexHandoff", "Execution brief must include skill blocks."], [promptBuilder, "Active Codex Skills", "Prompt Builder must show active skills."], [promptBuilder, "withSkillBlock", "Prompt Builder must append skill blocks to generated prompts."], [history, 'kind: "skill"', "History must include skill records."], [pkg, "audit:skills", "package.json must expose audit:skills."], [pkg, "check-skill-library-readiness.mjs", "package.json must wire the skill readiness script."], ]; for (const [haystack, needle, message] of mustContain) { if (!haystack.includes(needle)) failures.push(message); } const requiredSkillIds = [ "repo-foundation-build", "frontend-react-vite-build", "backend-api-build", "database-migration", "docker-runtime-hardening", "qa-qc-review", "documentation-system-build", "repo-expansion-planning", "codex-handoff-packaging", "ui-ux-polish-pass", "geoai-backend-build", "postgis-migration", "raster-pipeline", "frontend-maplibre", "geospatial-qa-qc-review", "ml-pipeline-prototyping", "etl-data-ingestion", "auth-security-hardening", ]; for (const skillId of requiredSkillIds) { if (!catalog.includes(`id: "${skillId}"`)) failures.push(`Built-in skill missing: ${skillId}`); } if (failures.length) { console.error("ProjectBrain skill library readiness: FAIL"); for (const failure of failures) console.error(`- ${failure}`); process.exit(1); } console.log("ProjectBrain skill library readiness: PASS");