Files
projectbrain-Public/scripts/check-codex-handoff-readiness.mjs
T

148 lines
9.7 KiB
JavaScript

#!/usr/bin/env node
import { existsSync, readFileSync } from "node:fs";
const requiredFiles = [
"src/shared/lib/model.ts",
"src/shared/lib/codexHandoff.ts",
"src/shared/lib/codexSessionPack.ts",
"src/shared/lib/safeData.ts",
"src/shared/api/realClient.ts",
"src/shared/hooks/useProjectData.ts",
"src/shared/contexts/ProjectContext.tsx",
"src/app/routes.tsx",
"src/shared/lib/navigation.tsx",
"src/shared/components/ProjectFlowRail.tsx",
"src/features/handoffs/pages/CodexHandoffs.tsx",
"src/features/execution-feedback/pages/ExecutionFeedback.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/audit/pages/ProjectAuditCenter.tsx",
"src/features/projects/pages/Workspace.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 text = Object.fromEntries(requiredFiles.filter(existsSync).map((file) => [file, read(file)]));
const model = text["src/shared/lib/model.ts"] ?? "";
const helper = text["src/shared/lib/codexHandoff.ts"] ?? "";
const sessionPackHelper = text["src/shared/lib/codexSessionPack.ts"] ?? "";
const safeData = text["src/shared/lib/safeData.ts"] ?? "";
const realClient = text["src/shared/api/realClient.ts"] ?? "";
const hooks = text["src/shared/hooks/useProjectData.ts"] ?? "";
const context = text["src/shared/contexts/ProjectContext.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 handoffPage = text["src/features/handoffs/pages/CodexHandoffs.tsx"] ?? "";
const feedbackPage = text["src/features/execution-feedback/pages/ExecutionFeedback.tsx"] ?? "";
const repoBuilder = text["src/features/repo-builder/pages/RepoBuilder.tsx"] ?? "";
const execution = text["src/features/execution/pages/ExecutionCenter.tsx"] ?? "";
const promptBuilder = text["src/features/prompts/pages/PromptGenerator.tsx"] ?? "";
const history = text["src/features/history/pages/ProjectHistory.tsx"] ?? "";
const audit = text["src/features/audit/pages/ProjectAuditCenter.tsx"] ?? "";
const workspace = text["src/features/projects/pages/Workspace.tsx"] ?? "";
const pkg = text["package.json"] ?? "";
const mustContain = [
[model, "export interface CodexHandoff", "CodexHandoff model missing."],
[model, "export interface CodexHandoffValidationItem", "CodexHandoffValidationItem model missing."],
[model, "export interface CodexHandoffRisk", "CodexHandoffRisk model missing."],
[model, "export interface CodexHandoffScope", "CodexHandoffScope model missing."],
[model, "export interface CodexHandoffQualityScore", "CodexHandoffQualityScore model missing."],
[model, "codexHandoffs?: CodexHandoff[]", "Project model must persist Codex handoffs."],
[model, "codexSessionPacks?: CodexSessionPack[]", "Project model must persist Codex session packs."],
[safeData, "codexHandoffs: asArray(project.codexHandoffs)", "Runtime normalization must preserve Codex handoffs."],
[realClient, "createHandoffBundle", "Real client must expose backend handoff bundle creation."],
[realClient, "createCodexTaskFromHandoff", "Real client must expose backend Codex task creation from handoff bundles."],
[hooks, "useProjectHandoffBundlesData", "Async hooks must expose backend handoff bundles."],
[hooks, "useProjectCodexTasksData", "Async hooks must expose backend Codex tasks."],
[helper, "generateCodexHandoffFromDeliveryPackage", "Handoff helper must generate from delivery packages."],
[helper, "generateCodexHandoffFromRepoGap", "Handoff helper must generate from repository gaps."],
[helper, "generateCodexHandoffFromWorkPlan", "Handoff helper must generate from work plans."],
[helper, "generateCodexHandoffFromRepoState", "Handoff helper must generate from repo state snapshots."],
[helper, "buildAllowedFiles", "Handoff helper must build allowed files."],
[helper, "buildForbiddenChanges", "Handoff helper must build forbidden changes."],
[helper, "buildValidationMatrix", "Handoff helper must build validation matrix."],
[helper, "buildRollbackPlan", "Handoff helper must build rollback plan."],
[helper, "buildDoneCriteria", "Handoff helper must build done criteria."],
[helper, "formatCodexHandoffMarkdown", "Handoff helper must format markdown."],
[helper, "scoreCodexHandoffQuality", "Handoff helper must score quality."],
[helper, "getHandoffWarnings", "Handoff helper must produce warnings."],
[helper, "promptInstructions", "Skill prompt instructions must be included."],
[helper, "validationCommands", "Skill validation commands must be included."],
[helper, "qualityChecklist", "Skill quality checklist must be included."],
[helper, "riskNotes", "Skill risk notes must be included."],
[helper, "This is derived from imported repository evidence, not live filesystem truth", "Repo-gap handoffs must label imported evidence boundary."],
[sessionPackHelper, "generateCodexSessionPack", "Session pack helper must generate packs from handoffs."],
[routes, "/projects/:projectId/handoffs", "Codex Handoffs route missing."],
[routes, "CodexHandoffs", "Codex Handoffs page must be imported in routes."],
[navigation, "Codex Handoffs", "Navigation must expose Codex Handoffs."],
[flowRail, 'id: "handoffs"', "Project Flow Rail must include Handoffs."],
[handoffPage, "Codex Handoffs", "Handoff page must exist."],
[handoffPage, "Live backend handoff path", "Handoff page must expose the live backend handoff bridge."],
[handoffPage, "Create live handoff", "Handoff page must support creating backend-persisted handoff bundles."],
[handoffPage, "Create Codex task", "Handoff page must support creating backend-persisted Codex tasks from handoff bundles."],
[handoffPage, "useProjectHandoffBundlesData", "Handoff page must read backend handoff bundles in real mode."],
[handoffPage, "quality", "Handoff page must show quality score."],
[handoffPage, "Allowed files", "Handoff page must show allowed files."],
[handoffPage, "Forbidden changes", "Handoff page must show forbidden changes."],
[handoffPage, "Validation matrix", "Handoff page must show validation matrix."],
[handoffPage, "Rollback", "Handoff page must show rollback."],
[handoffPage, "Generated prompt", "Handoff page must show generated prompt."],
[handoffPage, "Copy next Codex prompt", "Handoff page must support copying prompts."],
[handoffPage, "Generate impact review", "Handoff page must support impact review generation."],
[handoffPage, "ProjectBrain-derived impact simulation, not a live git diff", "Handoff page must distinguish simulated review from live git diff."],
[handoffPage, "Add execution feedback", "Handoff page must link to execution feedback intake."],
[handoffPage, "Create session pack", "Handoff page must create session packs."],
[handoffPage, "Open session pack", "Handoff page must open session packs."],
[handoffPage, "Copy session pack", "Handoff page must copy session packs."],
[handoffPage, "Download session pack", "Handoff page must download session packs."],
[handoffPage, "Download ZIP", "Handoff page must download session pack ZIP."],
[handoffPage, "Export session pack files", "Handoff page must export session pack files."],
[handoffPage, "controlled input for a Codex build session", "Handoff page must explain session pack purpose."],
[handoffPage, "View in Build Loop", "Handoff page must link to Build Loop."],
[feedbackPage, "Execution Feedback", "Execution feedback page must exist for post-handoff evidence intake."],
[repoBuilder, "Create Codex handoff", "Repo Builder must generate handoffs."],
[repoBuilder, "Create handoff from work plan", "Repo Builder must generate handoffs from work plans."],
[repoBuilder, "Create handoff from repo state", "Repo Builder must generate handoffs from repo state."],
[execution, "Codex Handoff Quality Engine", "Execution Center must show handoff engine."],
[execution, "Copy next Codex prompt", "Execution Center must copy next prompt."],
[execution, "Open Codex Handoff", "Execution Center must link to Handoffs."],
[promptBuilder, "Codex Handoff source", "Prompt Builder must expose handoff source."],
[promptBuilder, "Use handoff promptText", "Prompt Builder must use handoff promptText."],
[context, "generateCodexHandoff", "ProjectContext must expose generateCodexHandoff."],
[context, "generateCodexSessionPack", "ProjectContext must expose generateCodexSessionPack."],
[context, "archiveCodexHandoff", "ProjectContext must expose archiveCodexHandoff."],
[context, "codexHandoffItems", "Project search must index Codex handoffs."],
[history, 'kind: "handoff"', "Project History must include handoff records."],
[audit, "Codex handoff quality", "Audit Center must show handoff quality."],
[workspace, "codexHandoffCount", "Workspace must count Codex handoffs."],
[workspace, "Codex Handoffs", "Workspace must expose Codex Handoffs."],
[pkg, "audit:handoffs", "package.json must expose audit:handoffs."],
[pkg, "check-codex-handoff-readiness.mjs", "package.json must wire handoff readiness script."],
];
for (const [haystack, needle, message] of mustContain) {
if (!haystack.includes(needle)) failures.push(message);
}
if (!pkg.includes("audit:handoffs") || !pkg.includes("audit:all")) {
failures.push("audit:all must include the Codex handoff readiness check.");
}
if (failures.length) {
console.error("ProjectBrain Codex handoff readiness: FAIL");
for (const failure of failures) console.error(`- ${failure}`);
process.exit(1);
}
console.log("ProjectBrain Codex handoff readiness: PASS");