127 lines
6.6 KiB
JavaScript
127 lines
6.6 KiB
JavaScript
#!/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");
|