#!/usr/bin/env node import fs from "node:fs"; import path from "node:path"; const root = process.cwd(); const read = (file) => fs.readFileSync(path.join(root, file), "utf8"); const exists = (file) => fs.existsSync(path.join(root, file)); const failures = []; const requireFile = (file, reason) => { if (!exists(file)) failures.push(`${file}: ${reason}`); }; const requireIncludes = (file, needle, reason) => { if (!exists(file) || !read(file).includes(needle)) failures.push(`${file}: ${reason}`); }; const requireExcludes = (file, needle, reason) => { if (exists(file) && read(file).includes(needle)) failures.push(`${file}: ${reason}`); }; const requireBefore = (file, firstNeedle, secondNeedle, reason) => { if (!exists(file)) { failures.push(`${file}: ${reason}`); return; } const content = read(file); const firstIndex = content.indexOf(firstNeedle); const secondIndex = content.indexOf(secondNeedle); if (firstIndex < 0 || secondIndex < 0 || firstIndex > secondIndex) failures.push(`${file}: ${reason}`); }; requireFile("src/features/start/pages/GuidedStart.tsx", "Guided Start page must exist."); requireFile("src/shared/lib/guidedStart.ts", "Guided Start deterministic idea helper must exist."); requireFile("src/shared/lib/projectStartFlow.ts", "Unified project start flow helper must exist."); requireIncludes("src/app/routes.tsx", 'path="/start"', "Guided Start route must be registered."); requireIncludes("src/app/routes.tsx", 'path="/projects/new"', "Project setup compatibility route must stay registered."); requireIncludes("src/app/routes.tsx", '', "Root route should land on Guided Start."); requireIncludes("src/app/routes.tsx", "ProjectSetupFlow", "Project setup compatibility route should use the shared setup component."); requireIncludes("src/shared/lib/navigation.tsx", 'label: "Nieuw project"', "Navigation should expose the unified Start flow."); requireBefore("src/shared/lib/navigation.tsx", 'label: "Projecten"', 'label: "Nieuw project"', "Navigation should list Projects before Start for returning users."); requireIncludes("src/features/projects/pages/FirstRunProjectWizard.tsx", 'searchParams.get("projectType")', "Wizard should accept guided-start projectType prefill."); requireIncludes("src/features/projects/pages/FirstRunProjectWizard.tsx", 'searchParams.get("firstSlice")', "Wizard should accept first-slice prefill."); requireIncludes("src/features/projects/pages/FirstRunProjectWizard.tsx", "Project maken", "Project setup page should identify itself as part of the unified start flow."); requireIncludes("src/features/projects/pages/FirstRunProjectWizard.tsx", "recommendation.recommendedSkills.length", "Project setup should derive execution profiles automatically."); requireIncludes("src/shared/lib/guidedStart.ts", ".replace(/[-_/]+/g", "Guided Start should split hyphenated/slashed terms such as self-hosted and repo-builder."); requireIncludes("src/features/start/pages/GuidedStart.tsx", 'navigate(`/projects/new?', "All new project paths should use the shared setup route."); requireIncludes("src/features/start/pages/GuidedStart.tsx", "projectEntryPath(continuationProject.id)", "Existing project continuation should use the canonical project entry route."); requireIncludes("src/app/routes.tsx", "resolveProjectResume", "Canonical project entry should resolve to the live overview or next required project step."); requireIncludes("src/shared/lib/projectWizard.ts", "recommendSkillIdsForProjectProfile", "Project creation should use the Codex skill catalog for recommendations."); requireIncludes("src/shared/lib/model.ts", "recommendedSkills?: string[]", "First-run state should persist recommended Codex skills."); requireIncludes("src/features/projects/components/FirstRunLaunchpad.tsx", "firstImplementationTaskReady", "The guided launchpad should show status-aware first execution guidance."); requireIncludes("src/features/projects/components/FirstRunLaunchpad.tsx", "Eerste implementatietaak maken", "Launchpad should create the first implementation task."); requireIncludes("src/features/projects/components/FirstRunLaunchpad.tsx", "Eerste taak beoordelen", "Launchpad should become status-aware after the first task exists."); requireIncludes("src/features/projects/components/FirstRunLaunchpad.tsx", "firstImplementationTaskReady", "The launchpad should derive first-task status from project review data."); requireIncludes("src/shared/lib/projectFirstRunGenerationCommands.ts", "first-implementation-task-${projectId}", "First implementation task id should be stable per project."); requireIncludes("src/shared/contexts/ProjectContext.tsx", "decideStarterReviewItem", "Starter review decisions should persist back to project data."); requireIncludes("src/features/operations/pages/ReviewQueue.tsx", "item.attribution?.approvalState", "Review Queue should derive starter review status from project approval state."); requireIncludes("src/features/operations/pages/ReviewQueue.tsx", "decideStarterReviewItem", "Review Queue should persist starter item actions to ProjectContext."); requireIncludes("src/features/operations/pages/ReviewQueue.tsx", "Bij acceptatie kan dit:", "Review Queue should show an impact preview before accepting an item."); requireIncludes("src/features/projects/pages/Projects.tsx", "Projectcatalogus", "Projects page should present existing projects as the primary returning-user catalog."); requireIncludes("src/features/projects/pages/Projects.tsx", "Ga verder waar je stopte", "Projects page should surface the current project continuation path."); requireIncludes("src/features/projects/pages/Projects.tsx", "Nieuw project", "Projects page should send new projects to the unified Start flow."); requireIncludes("src/features/projects/pages/Projects.tsx", "sortedProjects", "Projects page should sort project memories by current relevance."); requireIncludes("src/features/projects/pages/Projects.tsx", "getProjectOperatingStep", "Projects page should use shared next-action logic."); requireIncludes("src/shared/lib/projectStartFlow.ts", "source-material", "Start flow must support source material."); requireIncludes("src/shared/lib/projectStartFlow.ts", "existing-repo", "Start flow must support existing repositories."); requireIncludes("src/shared/lib/projectStartFlow.ts", "direct-project", "Start flow must support direct project creation."); requireIncludes("src/shared/lib/projectStartFlow.ts", "newProjectStartFlowEntries", "New-project entries should be separated from existing-project continuation."); requireIncludes("src/shared/lib/projectStartFlow.ts", "Vaardigheden", "Start flow must include the Skills step."); requireIncludes("src/shared/lib/projectStartFlow.ts", "import-repository-state", "Existing repository projects should next-action into repository intake."); requireIncludes("src/shared/lib/projectStartFlow.ts", "Momentopname van repository maken", "Existing repository projects should progress from intake to repo state snapshot."); requireIncludes("src/shared/lib/projectWizard.ts", "Import repository state in Repo Builder", "Project setup should mention repository intake when an existing repo is provided."); requireIncludes("src/features/projects/pages/Workspace.tsx", "resolveProjectWorkState", "Workspace should derive continuation from canonical delivery and Auto state."); requireIncludes("src/features/projects/pages/Workspace.tsx", "onClick={() => navigate(workState.primaryRoute)}", "Workspace should route its primary continuation through the shared operating step."); requireIncludes("src/components/layout/Sidebar.tsx", "staticProjectStep", "Sidebar should prioritize explicit attention and defer live status to overview."); requireIncludes("src/app/routes.tsx", "/projects/:projectId/skills", "Unified project flow should include Skill Library route."); requireIncludes("src/shared/components/ProjectFlowRail.tsx", 'id: "skills"', "Unified project flow rail should include Codex Skills."); requireExcludes("src/features/projects/pages/Projects.tsx", "New Project Wizard", "Projects page should not keep the old competing wizard CTA."); requireExcludes("src/features/projects/pages/Projects.tsx", "Open Wizard", "Projects page should not keep a separate wizard CTA."); requireExcludes("src/features/start/pages/GuidedStart.tsx", "Skip to wizard", "Guided Start should not present a separate wizard escape hatch."); requireExcludes("src/features/brainstorm/pages/BrainstormLab.tsx", "Open wizard", "Brainstorm project conversion should open project setup, not a separate wizard concept."); requireExcludes("src/features/brainstorm/pages/BrainstormLab.tsx", "first-run wizard", "Brainstorm copy should use unified Start/project setup language."); requireIncludes("src/features/brainstorm/pages/BrainstormLab.tsx", "Open Review Queue", "Brainstorm review action should state that it opens Review Queue."); requireExcludes("src/features/projects/components/FirstRunLaunchpad.tsx", "The wizard created", "Launchpad should describe project setup output instead of a separate wizard."); requireExcludes("src/features/projects/pages/FirstRunProjectWizard.tsx", "The wizard will", "Project setup page should not reintroduce old wizard language."); if (failures.length) { console.error("ProjectBrain guided start readiness: FAIL"); failures.forEach((failure) => console.error(`- ${failure}`)); process.exit(1); } console.log("ProjectBrain guided start readiness: PASS");