@sienklogic/plan-build-run 2.19.0 → 2.19.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1287 -303
- package/CLAUDE.md +74 -39
- package/LICENSE +2 -1
- package/README.md +412 -177
- package/bin/install.js +2752 -0
- package/dashboard/bin/cli.cjs +96 -0
- package/dashboard/bin/stop.cjs +129 -0
- package/dashboard/eslint.config.js +37 -0
- package/dashboard/index.html +20 -0
- package/dashboard/package.json +27 -25
- package/dashboard/server/index.js +151 -0
- package/dashboard/server/lib/frontmatter.js +92 -0
- package/dashboard/server/middleware/static.js +35 -0
- package/dashboard/server/package.json +16 -0
- package/dashboard/server/routes/agents.js +234 -0
- package/dashboard/server/routes/config.js +64 -0
- package/dashboard/server/routes/health.js +98 -0
- package/dashboard/server/routes/incidents.js +78 -0
- package/dashboard/server/routes/intel.js +69 -0
- package/dashboard/server/routes/memory.js +107 -0
- package/dashboard/server/routes/planning.js +234 -0
- package/dashboard/server/routes/progress.js +77 -0
- package/dashboard/server/routes/projects.js +36 -0
- package/dashboard/server/routes/requirements.js +40 -0
- package/dashboard/server/routes/roadmap.js +69 -0
- package/dashboard/server/routes/sessions.js +70 -0
- package/dashboard/server/routes/status.js +25 -0
- package/dashboard/server/routes/telemetry.js +233 -0
- package/dashboard/server/services/file-watcher.js +105 -0
- package/dashboard/server/services/planning-reader.js +727 -0
- package/dashboard/server/test/cli.test.js +34 -0
- package/dashboard/server/test/frontmatter.test.js +104 -0
- package/dashboard/server/test/isolation.test.js +32 -0
- package/dashboard/server/test/planning-reader.test.js +151 -0
- package/dashboard/server/test/routes.test.js +91 -0
- package/dashboard/server/test/ws.test.js +81 -0
- package/dashboard/server/ws.js +96 -0
- package/dashboard/src/App.jsx +165 -0
- package/dashboard/src/components/charts/BudgetBars.jsx +42 -0
- package/dashboard/src/components/charts/ContextRadar.jsx +34 -0
- package/dashboard/src/components/charts/PhaseDonut.jsx +66 -0
- package/dashboard/src/components/charts/SuccessTrend.jsx +45 -0
- package/dashboard/src/components/charts/TokenChart.jsx +55 -0
- package/dashboard/src/components/charts/index.js +5 -0
- package/dashboard/src/components/config/CfgSection.jsx +93 -0
- package/dashboard/src/components/layout/Header.jsx +89 -0
- package/dashboard/src/components/layout/ProjectSwitcher.jsx +160 -0
- package/dashboard/src/components/layout/Sidebar.jsx +161 -0
- package/dashboard/src/components/ui/AutoModeBanner.jsx +138 -0
- package/dashboard/src/components/ui/BackButton.jsx +27 -0
- package/dashboard/src/components/ui/Badge.jsx +27 -0
- package/dashboard/src/components/ui/Card.jsx +23 -0
- package/dashboard/src/components/ui/ChartTooltip.jsx +48 -0
- package/dashboard/src/components/ui/CheckpointBox.jsx +110 -0
- package/dashboard/src/components/ui/CodeBlock.jsx +27 -0
- package/dashboard/src/components/ui/ConfidenceBadge.jsx +20 -0
- package/dashboard/src/components/ui/ConfirmModal.jsx +161 -0
- package/dashboard/src/components/ui/ConnectionBanner.jsx +60 -0
- package/dashboard/src/components/ui/ErrorBoundary.jsx +106 -0
- package/dashboard/src/components/ui/ErrorBox.jsx +107 -0
- package/dashboard/src/components/ui/KeyValue.jsx +33 -0
- package/dashboard/src/components/ui/LoadingSkeleton.jsx +84 -0
- package/dashboard/src/components/ui/MetricCard.jsx +58 -0
- package/dashboard/src/components/ui/NextUpBlock.jsx +92 -0
- package/dashboard/src/components/ui/NumberInput.jsx +44 -0
- package/dashboard/src/components/ui/PBRBanner.jsx +47 -0
- package/dashboard/src/components/ui/PipelineView.jsx +130 -0
- package/dashboard/src/components/ui/ProgressBar.jsx +28 -0
- package/dashboard/src/components/ui/ProgressDisplay.jsx +47 -0
- package/dashboard/src/components/ui/QualityGateBadge.jsx +15 -0
- package/dashboard/src/components/ui/SectionTitle.jsx +35 -0
- package/dashboard/src/components/ui/SelectInput.jsx +45 -0
- package/dashboard/src/components/ui/StatusDot.jsx +51 -0
- package/dashboard/src/components/ui/StatusSymbol.jsx +49 -0
- package/dashboard/src/components/ui/TabBar.jsx +41 -0
- package/dashboard/src/components/ui/TextInput.jsx +42 -0
- package/dashboard/src/components/ui/Toast.jsx +117 -0
- package/dashboard/src/components/ui/Toggle.jsx +70 -0
- package/dashboard/src/components/ui/index.js +29 -0
- package/dashboard/src/hooks/useDocumentTitle.js +16 -0
- package/dashboard/src/hooks/useFetch.js +50 -0
- package/dashboard/src/hooks/useToast.jsx +43 -0
- package/dashboard/src/hooks/useWebSocket.js +103 -0
- package/dashboard/src/lib/api.js +112 -0
- package/dashboard/src/lib/configSchema.js +189 -0
- package/dashboard/src/lib/constants.js +22 -0
- package/dashboard/src/main.jsx +15 -0
- package/dashboard/src/pages/AgentsPage.jsx +191 -0
- package/dashboard/src/pages/ConfigPage.jsx +298 -0
- package/dashboard/src/pages/HooksPage.jsx +412 -0
- package/dashboard/src/pages/IncidentsPage.jsx +135 -0
- package/dashboard/src/pages/IntelPage.jsx +193 -0
- package/dashboard/src/pages/LiveFeed.jsx +274 -0
- package/dashboard/src/pages/MemoryPage.jsx +107 -0
- package/dashboard/src/pages/OnboardingPage.jsx +117 -0
- package/dashboard/src/pages/Overview.jsx +360 -0
- package/dashboard/src/pages/PhaseDetailView.jsx +216 -0
- package/dashboard/src/pages/PlanningPage.jsx +181 -0
- package/dashboard/src/pages/ProgressPage.jsx +249 -0
- package/dashboard/src/pages/ResearchPage.jsx +129 -0
- package/dashboard/src/pages/RoadmapPage.jsx +251 -0
- package/dashboard/src/pages/SessionsPage.jsx +117 -0
- package/dashboard/src/pages/Telemetry.jsx +166 -0
- package/dashboard/src/pages/planning/DecisionsTab.jsx +153 -0
- package/dashboard/src/pages/planning/FilesTab.jsx +420 -0
- package/dashboard/src/pages/planning/MilestoneDetail.jsx +319 -0
- package/dashboard/src/pages/planning/MilestonesTab.jsx +151 -0
- package/dashboard/src/pages/planning/NotesTab.jsx +251 -0
- package/dashboard/src/pages/planning/PhasesTab.jsx +218 -0
- package/dashboard/src/pages/planning/QuickTab.jsx +50 -0
- package/dashboard/src/pages/planning/ResearchTab.jsx +103 -0
- package/dashboard/src/pages/planning/TodosTab.jsx +297 -0
- package/dashboard/src/theme/ThemeProvider.jsx +38 -0
- package/dashboard/src/theme/tokens.js +17 -0
- package/dashboard/tests/components/ConfirmModal.test.jsx +179 -0
- package/dashboard/tests/components/ConnectionBanner.test.jsx +37 -0
- package/dashboard/tests/components/ErrorBoundary.test.jsx +59 -0
- package/dashboard/tests/components/LoadingSkeleton.test.jsx +46 -0
- package/dashboard/tests/components/ToastContainer.test.jsx +47 -0
- package/dashboard/tests/components/Toggle.test.jsx +61 -0
- package/dashboard/tests/hooks/useFetch.test.jsx +77 -0
- package/dashboard/tests/hooks/useToast.test.jsx +78 -0
- package/dashboard/tests/hooks/useWebSocket.test.jsx +128 -0
- package/dashboard/tests/pages/ConfigPage.test.jsx +199 -0
- package/dashboard/tests/pages/PlanningPage.test.jsx +119 -0
- package/dashboard/tests/pages/planning/FilesTab.test.jsx +198 -0
- package/dashboard/tests/pages/planning/NotesTab.test.jsx +178 -0
- package/dashboard/tests/pages/planning/TodosTab.test.jsx +188 -0
- package/dashboard/tests/performance.test.jsx +46 -0
- package/dashboard/tests/routes/config.test.js +98 -0
- package/dashboard/tests/routes/health.test.js +40 -0
- package/dashboard/tests/routes/planning.test.js +112 -0
- package/dashboard/tests/routes/roadmap.test.js +91 -0
- package/dashboard/tests/routes/status.test.js +131 -0
- package/dashboard/tests/server/planning-reader.test.js +153 -0
- package/dashboard/tests/setup.js +7 -0
- package/dashboard/vite.config.js +41 -0
- package/package.json +55 -40
- package/plan-build-run/bin/config-schema.json +1298 -0
- package/plugins/pbr/.claude-plugin/plugin.json +1 -1
- package/plugins/pbr/CLAUDE.md +19 -0
- package/plugins/pbr/UI-CONSISTENCY-GAPS.md +1 -1
- package/plugins/pbr/agents/advisor-researcher.md +101 -0
- package/plugins/pbr/agents/audit.md +205 -89
- package/plugins/pbr/agents/codebase-mapper.md +158 -23
- package/plugins/pbr/agents/debugger.md +212 -34
- package/plugins/pbr/agents/dev-sync.md +206 -0
- package/plugins/pbr/agents/executor.md +717 -39
- package/plugins/pbr/agents/general.md +71 -6
- package/plugins/pbr/agents/integration-checker.md +146 -30
- package/plugins/pbr/agents/intel-updater.md +332 -0
- package/plugins/pbr/agents/nyquist-auditor.md +253 -0
- package/plugins/pbr/agents/plan-checker.md +265 -65
- package/plugins/pbr/agents/planner.md +440 -42
- package/plugins/pbr/agents/researcher.md +219 -36
- package/plugins/pbr/agents/roadmapper.md +397 -0
- package/plugins/pbr/agents/synthesizer.md +166 -26
- package/plugins/pbr/agents/ui-checker.md +203 -0
- package/plugins/pbr/agents/ui-researcher.md +224 -0
- package/plugins/pbr/agents/verifier.md +495 -47
- package/plugins/pbr/commands/add-phase.md +75 -0
- package/plugins/pbr/commands/add-todo.md +8 -0
- package/plugins/pbr/commands/audit-fix.md +5 -0
- package/plugins/pbr/commands/audit-milestone.md +8 -0
- package/plugins/pbr/commands/autonomous.md +5 -0
- package/plugins/pbr/commands/backlog.md +6 -0
- package/plugins/pbr/commands/check-todos.md +8 -0
- package/plugins/pbr/commands/complete-milestone.md +8 -0
- package/plugins/pbr/commands/config.md +1 -1
- package/plugins/pbr/commands/discuss-phase.md +6 -0
- package/plugins/pbr/commands/do.md +5 -0
- package/plugins/pbr/commands/execute-phase.md +6 -0
- package/plugins/pbr/commands/fast.md +6 -0
- package/plugins/pbr/commands/forensics.md +6 -0
- package/plugins/pbr/commands/import.md +1 -1
- package/plugins/pbr/commands/insert-phase.md +65 -0
- package/plugins/pbr/commands/intel.md +5 -0
- package/plugins/pbr/commands/join-discord.md +11 -0
- package/plugins/pbr/commands/list-phase-assumptions.md +5 -0
- package/plugins/pbr/commands/map-codebase.md +6 -0
- package/plugins/pbr/commands/milestone-summary.md +6 -0
- package/plugins/pbr/commands/new-milestone.md +8 -0
- package/plugins/pbr/commands/new-project.md +6 -0
- package/plugins/pbr/commands/pause-work.md +5 -0
- package/plugins/pbr/commands/plan-milestone-gaps.md +7 -0
- package/plugins/pbr/commands/plan-phase.md +6 -0
- package/plugins/pbr/commands/plant-seed.md +6 -0
- package/plugins/pbr/commands/profile-user.md +5 -0
- package/plugins/pbr/commands/profile.md +5 -0
- package/plugins/pbr/commands/progress.md +6 -0
- package/plugins/pbr/commands/quick.md +1 -1
- package/plugins/pbr/commands/reapply-patches.md +47 -0
- package/plugins/pbr/commands/release.md +6 -0
- package/plugins/pbr/commands/remove-phase.md +66 -0
- package/plugins/pbr/commands/research-phase.md +59 -0
- package/plugins/pbr/commands/resume-work.md +5 -0
- package/plugins/pbr/commands/seed.md +6 -0
- package/plugins/pbr/commands/session-report.md +5 -0
- package/plugins/pbr/commands/set-profile.md +6 -0
- package/plugins/pbr/commands/settings.md +5 -0
- package/plugins/pbr/commands/setup.md +1 -1
- package/plugins/pbr/commands/ship.md +5 -0
- package/plugins/pbr/commands/stats.md +6 -0
- package/plugins/pbr/commands/test.md +5 -0
- package/plugins/pbr/commands/thread.md +6 -0
- package/plugins/pbr/commands/todo.md +1 -1
- package/plugins/pbr/commands/ui-phase.md +5 -0
- package/plugins/pbr/commands/ui-review.md +5 -0
- package/plugins/pbr/commands/undo.md +5 -0
- package/plugins/pbr/commands/update.md +37 -0
- package/plugins/pbr/commands/validate-phase.md +5 -0
- package/plugins/pbr/commands/verify-work.md +6 -0
- package/plugins/pbr/dashboard/package-lock.json +6 -0
- package/plugins/pbr/dist/architecture-guard.js +59 -0
- package/plugins/pbr/dist/audit-dimensions.js +556 -0
- package/plugins/pbr/dist/auto-continue.js +277 -0
- package/plugins/pbr/dist/block-skill-self-read.js +124 -0
- package/plugins/pbr/dist/check-agent-state-write.js +63 -0
- package/plugins/pbr/dist/check-config-change.js +155 -0
- package/plugins/pbr/dist/check-cross-plugin-sync.js +93 -0
- package/plugins/pbr/dist/check-dangerous-commands.js +193 -0
- package/plugins/pbr/dist/check-direct-state-write.js +37 -0
- package/plugins/pbr/dist/check-doc-sprawl.js +102 -0
- package/plugins/pbr/dist/check-phase-boundary.js +191 -0
- package/plugins/pbr/dist/check-plan-format.js +209 -0
- package/plugins/pbr/dist/check-read-first.js +345 -0
- package/plugins/pbr/dist/check-roadmap-sync.js +507 -0
- package/plugins/pbr/dist/check-skill-workflow.js +354 -0
- package/plugins/pbr/dist/check-state-sync.js +658 -0
- package/plugins/pbr/dist/check-subagent-output.js +396 -0
- package/plugins/pbr/dist/check-summary-gate.js +188 -0
- package/plugins/pbr/dist/context-bridge.js +425 -0
- package/plugins/pbr/dist/context-budget-check.js +442 -0
- package/plugins/pbr/dist/context-quality.js +271 -0
- package/plugins/pbr/dist/enforce-context-budget.js +138 -0
- package/plugins/pbr/dist/enforce-pbr-workflow.js +277 -0
- package/plugins/pbr/dist/event-handler.js +202 -0
- package/plugins/pbr/dist/event-logger.js +125 -0
- package/plugins/pbr/dist/feedback-loop.js +155 -0
- package/plugins/pbr/dist/graph-update.js +422 -0
- package/plugins/pbr/dist/hook-logger.js +114 -0
- package/plugins/pbr/dist/hook-server-client.js +361 -0
- package/plugins/pbr/dist/hook-server.js +658 -0
- package/plugins/pbr/dist/hooks-schema.json +87 -0
- package/plugins/pbr/dist/instructions-loaded.js +173 -0
- package/plugins/pbr/dist/intercept-plan-mode.js +81 -0
- package/plugins/pbr/dist/log-notification.js +131 -0
- package/plugins/pbr/dist/log-subagent.js +349 -0
- package/plugins/pbr/dist/log-tool-failure.js +140 -0
- package/plugins/pbr/dist/milestone-learnings.js +519 -0
- package/plugins/pbr/dist/pbr-tools.js +1961 -0
- package/plugins/pbr/dist/post-bash-triage.js +96 -0
- package/plugins/pbr/dist/post-compact.js +135 -0
- package/plugins/pbr/dist/post-hoc.js +237 -0
- package/plugins/pbr/dist/post-write-dispatch.js +243 -0
- package/plugins/pbr/dist/post-write-quality.js +208 -0
- package/plugins/pbr/dist/pre-bash-dispatch.js +212 -0
- package/plugins/pbr/dist/pre-skill-dispatch.js +114 -0
- package/plugins/pbr/dist/pre-task-dispatch.js +269 -0
- package/plugins/pbr/dist/pre-write-dispatch.js +234 -0
- package/plugins/pbr/dist/progress-tracker.js +173 -0
- package/plugins/pbr/dist/prompt-guard.js +114 -0
- package/plugins/pbr/dist/prompt-routing.js +209 -0
- package/plugins/pbr/dist/quick-status.js +179 -0
- package/plugins/pbr/dist/record-incident.js +37 -0
- package/plugins/pbr/dist/run-hook.js +144 -0
- package/plugins/pbr/dist/session-cleanup.js +653 -0
- package/plugins/pbr/dist/session-tracker.js +124 -0
- package/plugins/pbr/dist/status-line.js +849 -0
- package/plugins/pbr/dist/suggest-compact.js +307 -0
- package/plugins/pbr/dist/sync-context-to-claude.js +100 -0
- package/plugins/pbr/dist/task-completed.js +206 -0
- package/plugins/pbr/dist/track-context-budget.js +432 -0
- package/plugins/pbr/dist/track-user-gates.js +88 -0
- package/plugins/pbr/dist/trust-tracker.js +193 -0
- package/plugins/pbr/dist/validate-commit.js +215 -0
- package/plugins/pbr/dist/validate-skill-args.js +222 -0
- package/plugins/pbr/dist/validate-task.js +271 -0
- package/plugins/pbr/dist/worktree-create.js +144 -0
- package/plugins/pbr/dist/worktree-remove.js +147 -0
- package/plugins/pbr/hooks/hooks.json +143 -60
- package/plugins/pbr/references/agent-contracts.md +39 -8
- package/plugins/pbr/references/agent-teams.md +3 -3
- package/plugins/pbr/references/archive/checkpoints.md +189 -0
- package/plugins/pbr/references/archive/context-quality-tiers.md +45 -0
- package/plugins/pbr/references/archive/hook-ordering.md +89 -0
- package/plugins/pbr/references/archive/limitations.md +106 -0
- package/plugins/pbr/references/archive/pbr-rules.md +194 -0
- package/plugins/pbr/references/archive/pbr-tools-cli.md +415 -0
- package/plugins/pbr/references/archive/pretooluse-jsonl-behavior.md +58 -0
- package/plugins/pbr/references/archive/signal-files.md +41 -0
- package/plugins/pbr/references/archive/tmux-setup.md +288 -0
- package/plugins/pbr/references/archive/verification-matrix.md +34 -0
- package/plugins/pbr/references/archive/verification-patterns.md +277 -0
- package/plugins/pbr/references/archive/worktree-sparse-checkout.md +86 -0
- package/plugins/pbr/references/checkpoints.md +723 -104
- package/plugins/pbr/references/config-reference.md +376 -10
- package/plugins/pbr/references/continuation-format.md +1 -0
- package/plugins/pbr/references/decimal-phase-calculation.md +65 -0
- package/plugins/pbr/references/deviation-rules.md +12 -0
- package/plugins/pbr/references/git-integration.md +110 -27
- package/plugins/pbr/references/git-planning-commit.md +35 -0
- package/plugins/pbr/references/model-profile-resolution.md +34 -0
- package/plugins/pbr/references/model-profiles.md +90 -7
- package/plugins/pbr/references/model-selection.md +1 -1
- package/plugins/pbr/references/node-repair.md +48 -0
- package/plugins/pbr/references/plan-authoring.md +65 -0
- package/plugins/pbr/references/plan-format.md +161 -10
- package/plugins/pbr/references/questioning.md +138 -49
- package/plugins/pbr/references/reading-verification.md +4 -4
- package/plugins/pbr/references/tdd.md +263 -0
- package/plugins/pbr/references/ui-brand.md +449 -0
- package/plugins/pbr/references/verification-overrides.md +39 -0
- package/plugins/pbr/references/verification-patterns.md +529 -113
- package/plugins/pbr/scripts/architecture-guard.js +59 -0
- package/plugins/pbr/scripts/audit-checks/behavioral-compliance.js +2098 -0
- package/plugins/pbr/scripts/audit-checks/error-analysis.js +989 -0
- package/plugins/pbr/scripts/audit-checks/feature-verification.js +723 -0
- package/plugins/pbr/scripts/audit-checks/index.js +433 -0
- package/plugins/pbr/scripts/audit-checks/infrastructure.js +816 -0
- package/plugins/pbr/scripts/audit-checks/quality-metrics.js +452 -0
- package/plugins/pbr/scripts/audit-checks/session-quality.js +980 -0
- package/plugins/pbr/scripts/audit-checks/si-agent-hook-config-checks.js +396 -0
- package/plugins/pbr/scripts/audit-checks/si-cross-cutting-checks.js +272 -0
- package/plugins/pbr/scripts/audit-checks/si-skill-checks.js +424 -0
- package/plugins/pbr/scripts/audit-checks/workflow-compliance.js +1175 -0
- package/plugins/pbr/scripts/audit-dimensions.js +556 -0
- package/plugins/pbr/scripts/auto-continue.js +192 -31
- package/plugins/pbr/scripts/block-skill-self-read.js +124 -0
- package/plugins/pbr/scripts/check-agent-state-write.js +63 -0
- package/plugins/pbr/scripts/check-config-change.js +155 -0
- package/plugins/pbr/scripts/check-cross-plugin-sync.js +93 -0
- package/plugins/pbr/scripts/check-dangerous-commands.js +18 -5
- package/plugins/pbr/scripts/check-direct-state-write.js +37 -0
- package/plugins/pbr/scripts/check-phase-boundary.js +3 -8
- package/plugins/pbr/scripts/check-plan-format.js +135 -278
- package/plugins/pbr/scripts/check-read-first.js +345 -0
- package/plugins/pbr/scripts/check-roadmap-sync.js +182 -21
- package/plugins/pbr/scripts/check-skill-workflow.js +24 -27
- package/plugins/pbr/scripts/check-state-sync.js +339 -215
- package/plugins/pbr/scripts/check-subagent-output.js +281 -275
- package/plugins/pbr/scripts/check-summary-gate.js +5 -15
- package/plugins/pbr/scripts/config-schema.json +1134 -95
- package/plugins/pbr/scripts/context-bridge.js +425 -0
- package/plugins/pbr/scripts/context-budget-check.js +169 -14
- package/plugins/pbr/scripts/context-quality.js +271 -0
- package/plugins/pbr/scripts/enforce-context-budget.js +138 -0
- package/plugins/pbr/scripts/enforce-pbr-workflow.js +277 -0
- package/plugins/pbr/scripts/event-handler.js +127 -87
- package/plugins/pbr/scripts/event-logger.js +58 -25
- package/plugins/pbr/scripts/feedback-loop.js +155 -0
- package/plugins/pbr/scripts/graph-update.js +422 -0
- package/plugins/pbr/scripts/hook-logger.js +69 -35
- package/plugins/pbr/scripts/hook-server-client.js +361 -0
- package/plugins/pbr/scripts/hook-server.js +658 -0
- package/plugins/pbr/scripts/hooks-schema.json +13 -5
- package/plugins/pbr/scripts/instructions-loaded.js +173 -0
- package/plugins/pbr/scripts/intent-router.cjs +147 -0
- package/plugins/pbr/scripts/intercept-plan-mode.js +52 -18
- package/plugins/pbr/scripts/lib/alternatives.js +203 -0
- package/plugins/pbr/scripts/lib/audit.js +65 -0
- package/plugins/pbr/scripts/lib/auto-cleanup.js +221 -0
- package/plugins/pbr/scripts/lib/auto-verify.js +103 -0
- package/plugins/pbr/scripts/lib/build.js +719 -0
- package/plugins/pbr/scripts/lib/ci-fix-loop.js +228 -0
- package/plugins/pbr/scripts/lib/commands.js +483 -0
- package/plugins/pbr/scripts/lib/compound.js +216 -0
- package/plugins/pbr/scripts/lib/config.js +1308 -0
- package/plugins/pbr/scripts/lib/context.js +254 -0
- package/plugins/pbr/scripts/lib/contextual-help.js +183 -0
- package/plugins/pbr/scripts/lib/convention-detector.js +413 -0
- package/plugins/pbr/scripts/lib/core.js +1569 -0
- package/plugins/pbr/scripts/lib/dashboard-launch.js +364 -0
- package/plugins/pbr/scripts/lib/data-hygiene.js +179 -0
- package/plugins/pbr/scripts/lib/decision-extraction.js +183 -0
- package/plugins/pbr/scripts/lib/decisions.js +194 -0
- package/plugins/pbr/scripts/lib/dependency-break.js +147 -0
- package/plugins/pbr/scripts/lib/format-validators.js +1025 -0
- package/plugins/pbr/scripts/lib/frontmatter.js +302 -0
- package/plugins/pbr/scripts/lib/gates/advisories.js +129 -0
- package/plugins/pbr/scripts/lib/gates/build-dependency.js +115 -0
- package/plugins/pbr/scripts/lib/gates/build-executor.js +104 -0
- package/plugins/pbr/scripts/lib/gates/doc-existence.js +46 -0
- package/plugins/pbr/scripts/lib/gates/helpers.js +93 -0
- package/plugins/pbr/scripts/lib/gates/inline-execution.js +185 -0
- package/plugins/pbr/scripts/lib/gates/milestone-complete.js +136 -0
- package/plugins/pbr/scripts/lib/gates/milestone-summary.js +119 -0
- package/plugins/pbr/scripts/lib/gates/multi-phase-loader.js +147 -0
- package/plugins/pbr/scripts/lib/gates/plan-executor.js +36 -0
- package/plugins/pbr/scripts/lib/gates/plan-validation.js +114 -0
- package/plugins/pbr/scripts/lib/gates/quick-executor.js +76 -0
- package/plugins/pbr/scripts/lib/gates/review-planner.js +61 -0
- package/plugins/pbr/scripts/lib/gates/review-verifier.js +69 -0
- package/plugins/pbr/scripts/lib/gates/rich-agent-context.js +137 -0
- package/plugins/pbr/scripts/lib/gates/user-confirmation.js +93 -0
- package/plugins/pbr/scripts/lib/graph-cli.js +89 -0
- package/plugins/pbr/scripts/lib/graph.js +553 -0
- package/plugins/pbr/scripts/lib/health-checks.js +107 -0
- package/plugins/pbr/scripts/lib/health-phase06.js +120 -0
- package/plugins/pbr/scripts/lib/health.js +132 -0
- package/plugins/pbr/scripts/lib/help.js +100 -0
- package/plugins/pbr/scripts/lib/history.js +150 -0
- package/plugins/pbr/scripts/lib/impact-analysis.js +319 -0
- package/plugins/pbr/scripts/lib/incidents.js +190 -0
- package/plugins/pbr/scripts/lib/init.js +643 -0
- package/plugins/pbr/scripts/lib/insights-parser.js +320 -0
- package/plugins/pbr/scripts/lib/intel.js +653 -0
- package/plugins/pbr/scripts/lib/learnings.js +511 -0
- package/plugins/pbr/scripts/lib/migrate.js +298 -0
- package/plugins/pbr/scripts/lib/milestone.js +306 -0
- package/plugins/pbr/scripts/lib/negative-knowledge.js +194 -0
- package/plugins/pbr/scripts/lib/notification-throttle.js +141 -0
- package/plugins/pbr/scripts/lib/onboarding-generator.js +288 -0
- package/plugins/pbr/scripts/lib/parse-args.js +134 -0
- package/plugins/pbr/scripts/lib/pattern-routing.js +55 -0
- package/plugins/pbr/scripts/lib/patterns.js +272 -0
- package/plugins/pbr/scripts/lib/perf.js +190 -0
- package/plugins/pbr/scripts/lib/phase.js +1025 -0
- package/plugins/pbr/scripts/lib/pid-lock.js +154 -0
- package/plugins/pbr/scripts/lib/post-hoc.js +160 -0
- package/plugins/pbr/scripts/lib/pre-commit-checks.js +220 -0
- package/plugins/pbr/scripts/lib/pre-research.js +126 -0
- package/plugins/pbr/scripts/lib/preview.js +174 -0
- package/plugins/pbr/scripts/lib/progress-visualization.js +296 -0
- package/plugins/pbr/scripts/lib/quick-init.js +131 -0
- package/plugins/pbr/scripts/lib/reference.js +236 -0
- package/plugins/pbr/scripts/lib/requirements.js +153 -0
- package/plugins/pbr/scripts/lib/resolve-root.js +66 -0
- package/plugins/pbr/scripts/lib/reverse-spec.js +259 -0
- package/plugins/pbr/scripts/lib/roadmap.js +1089 -0
- package/plugins/pbr/scripts/lib/security-scan.js +200 -0
- package/plugins/pbr/scripts/lib/session-briefing.js +895 -0
- package/plugins/pbr/scripts/lib/skill-section.js +99 -0
- package/plugins/pbr/scripts/lib/smart-next-task.js +198 -0
- package/plugins/pbr/scripts/lib/snapshot-manager.js +232 -0
- package/plugins/pbr/scripts/lib/spec-diff.js +209 -0
- package/plugins/pbr/scripts/lib/spec-engine.js +189 -0
- package/plugins/pbr/scripts/lib/spot-check.js +539 -0
- package/plugins/pbr/scripts/lib/state-queue.js +171 -0
- package/plugins/pbr/scripts/lib/state.js +1082 -0
- package/plugins/pbr/scripts/lib/status-render.js +511 -0
- package/plugins/pbr/scripts/lib/step-verify.js +149 -0
- package/plugins/pbr/scripts/lib/subagent-validators.js +1059 -0
- package/plugins/pbr/scripts/lib/suggest-next.js +435 -0
- package/plugins/pbr/scripts/lib/tech-debt-scanner.js +116 -0
- package/plugins/pbr/scripts/lib/templates.js +362 -0
- package/plugins/pbr/scripts/lib/test-selection.js +163 -0
- package/plugins/pbr/scripts/lib/todo.js +300 -0
- package/plugins/pbr/scripts/lib/verify.js +1483 -0
- package/plugins/pbr/scripts/log-notification.js +131 -0
- package/plugins/pbr/scripts/log-subagent.js +203 -18
- package/plugins/pbr/scripts/log-tool-failure.js +60 -8
- package/plugins/pbr/scripts/milestone-learnings.js +519 -0
- package/plugins/pbr/scripts/package.json +1 -1
- package/plugins/pbr/scripts/pbr-tools.js +1754 -1171
- package/plugins/pbr/scripts/post-bash-triage.js +96 -0
- package/plugins/pbr/scripts/post-compact.js +135 -0
- package/plugins/pbr/scripts/post-hoc.js +237 -0
- package/plugins/pbr/scripts/post-write-dispatch.js +201 -31
- package/plugins/pbr/scripts/post-write-quality.js +4 -3
- package/plugins/pbr/scripts/pre-bash-dispatch.js +147 -51
- package/plugins/pbr/scripts/pre-skill-dispatch.js +114 -0
- package/plugins/pbr/scripts/pre-task-dispatch.js +269 -0
- package/plugins/pbr/scripts/pre-write-dispatch.js +170 -73
- package/plugins/pbr/scripts/progress-tracker.js +122 -310
- package/plugins/pbr/scripts/prompt-guard.js +114 -0
- package/plugins/pbr/scripts/prompt-routing.js +209 -0
- package/plugins/pbr/scripts/quick-status.js +179 -0
- package/plugins/pbr/scripts/record-incident.js +37 -0
- package/plugins/pbr/scripts/risk-classifier.cjs +123 -0
- package/plugins/pbr/scripts/run-hook.js +62 -10
- package/plugins/pbr/scripts/session-cleanup.js +428 -29
- package/plugins/pbr/scripts/session-tracker.js +124 -0
- package/plugins/pbr/scripts/status-line.js +593 -32
- package/plugins/pbr/scripts/suggest-compact.js +201 -13
- package/plugins/pbr/scripts/sync-context-to-claude.js +100 -0
- package/plugins/pbr/scripts/task-completed.js +165 -4
- package/plugins/pbr/scripts/test/config.test.js +126 -0
- package/plugins/pbr/scripts/test/cross-platform.test.js +131 -0
- package/plugins/pbr/scripts/test/fixtures/config.json +20 -0
- package/plugins/pbr/scripts/test/fixtures/plan.md +54 -0
- package/plugins/pbr/scripts/test/fixtures/project.md +30 -0
- package/plugins/pbr/scripts/test/fixtures/roadmap.md +55 -0
- package/plugins/pbr/scripts/test/fixtures/state.md +60 -0
- package/plugins/pbr/scripts/test/fixtures/summary.md +35 -0
- package/plugins/pbr/scripts/test/fixtures.test.js +184 -0
- package/plugins/pbr/scripts/test/phase.test.js +142 -0
- package/plugins/pbr/scripts/test/roadmap.test.js +96 -0
- package/plugins/pbr/scripts/test/state.test.js +155 -0
- package/plugins/pbr/scripts/track-context-budget.js +368 -99
- package/plugins/pbr/scripts/track-user-gates.js +88 -0
- package/plugins/pbr/scripts/trust-tracker.js +193 -0
- package/plugins/pbr/scripts/validate-commit.js +41 -26
- package/plugins/pbr/scripts/validate-skill-args.js +87 -15
- package/plugins/pbr/scripts/validate-task.js +83 -627
- package/plugins/pbr/scripts/worktree-create.js +144 -0
- package/plugins/pbr/scripts/worktree-remove.js +147 -0
- package/plugins/pbr/skills/audit/SKILL.md +195 -24
- package/plugins/pbr/skills/audit-fix/SKILL.md +326 -0
- package/plugins/pbr/skills/autonomous/SKILL.md +545 -0
- package/plugins/pbr/skills/backlog/SKILL.md +56 -0
- package/plugins/pbr/skills/begin/SKILL.md +508 -153
- package/plugins/pbr/skills/begin/templates/STATE.md.tmpl +1 -2
- package/plugins/pbr/skills/begin/templates/config.json.tmpl +411 -36
- package/plugins/pbr/skills/begin/templates/researcher-prompt.md.tmpl +28 -0
- package/plugins/pbr/skills/begin/templates/roadmap-prompt.md.tmpl +28 -3
- package/plugins/pbr/skills/begin/templates/synthesis-prompt.md.tmpl +33 -5
- package/plugins/pbr/skills/build/SKILL.md +1040 -354
- package/plugins/pbr/skills/build/templates/continuation-prompt.md.tmpl +26 -0
- package/plugins/pbr/skills/build/templates/executor-prompt.md.tmpl +77 -0
- package/plugins/pbr/skills/build/templates/inline-verifier-prompt.md.tmpl +33 -0
- package/plugins/pbr/skills/config/SKILL.md +112 -9
- package/plugins/pbr/skills/continue/SKILL.md +113 -33
- package/plugins/pbr/skills/dashboard/SKILL.md +21 -9
- package/plugins/pbr/skills/debug/SKILL.md +70 -12
- package/plugins/pbr/skills/debug/templates/continuation-prompt.md.tmpl +12 -1
- package/plugins/pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +12 -5
- package/plugins/pbr/skills/discuss/SKILL.md +206 -25
- package/plugins/pbr/skills/discuss/templates/CONTEXT.md.tmpl +21 -1
- package/plugins/pbr/skills/do/SKILL.md +119 -24
- package/plugins/pbr/skills/explore/SKILL.md +95 -20
- package/plugins/pbr/skills/fast/SKILL.md +94 -0
- package/plugins/pbr/skills/forensics/SKILL.md +144 -0
- package/plugins/pbr/skills/health/SKILL.md +35 -117
- package/plugins/pbr/skills/help/SKILL.md +84 -101
- package/plugins/pbr/skills/import/SKILL.md +332 -13
- package/plugins/pbr/skills/intel/SKILL.md +131 -0
- package/plugins/pbr/skills/list-phase-assumptions/SKILL.md +231 -0
- package/plugins/pbr/skills/milestone/SKILL.md +421 -263
- package/plugins/pbr/skills/milestone/templates/audit-output.md.tmpl +76 -0
- package/plugins/pbr/skills/milestone/templates/complete-output.md.tmpl +32 -0
- package/plugins/pbr/skills/milestone/templates/edge-cases.md +54 -0
- package/plugins/pbr/skills/milestone/templates/gaps-output.md.tmpl +25 -0
- package/plugins/pbr/skills/milestone/templates/integration-checker-prompt.md.tmpl +25 -0
- package/plugins/pbr/skills/milestone/templates/new-output.md.tmpl +29 -0
- package/plugins/pbr/skills/milestone-summary/SKILL.md +86 -0
- package/plugins/pbr/skills/note/SKILL.md +20 -4
- package/plugins/pbr/skills/pause/SKILL.md +54 -14
- package/plugins/pbr/skills/pause/templates/continue-here.md.tmpl +33 -52
- package/plugins/pbr/skills/plan/SKILL.md +526 -280
- package/plugins/pbr/skills/plan/templates/checker-prompt.md.tmpl +5 -2
- package/plugins/pbr/skills/plan/templates/completion-output.md.tmpl +27 -0
- package/plugins/pbr/skills/plan/templates/planner-prompt.md.tmpl +27 -1
- package/plugins/pbr/skills/plan/templates/revision-prompt.md.tmpl +21 -5
- package/plugins/pbr/skills/profile/SKILL.md +185 -0
- package/plugins/pbr/skills/profile-user/SKILL.md +227 -0
- package/plugins/pbr/skills/quick/SKILL.md +435 -100
- package/plugins/pbr/skills/release/SKILL.md +206 -0
- package/plugins/pbr/skills/resume/SKILL.md +170 -46
- package/plugins/pbr/skills/review/SKILL.md +217 -164
- package/plugins/pbr/skills/review/templates/verifier-prompt.md.tmpl +7 -0
- package/plugins/pbr/skills/scan/SKILL.md +152 -106
- package/plugins/pbr/skills/scan/templates/mapper-prompt.md.tmpl +5 -56
- package/plugins/pbr/skills/seed/SKILL.md +87 -0
- package/plugins/pbr/skills/session-report/SKILL.md +130 -0
- package/plugins/pbr/skills/setup/SKILL.md +150 -202
- package/plugins/pbr/skills/shared/agent-context-enrichment.md +21 -0
- package/plugins/pbr/skills/shared/agent-type-resolution.md +32 -0
- package/plugins/pbr/skills/shared/commit-planning-docs.md +8 -0
- package/plugins/pbr/skills/shared/context-budget.md +66 -1
- package/plugins/pbr/skills/shared/context-loader-task.md +18 -11
- package/plugins/pbr/skills/shared/digest-select.md +2 -2
- package/plugins/pbr/skills/shared/domain-probes.md +1 -1
- package/plugins/pbr/skills/shared/error-reporting.md +38 -60
- package/plugins/pbr/skills/shared/gate-prompts.md +4 -2
- package/plugins/pbr/skills/shared/memory-capture.md +48 -0
- package/plugins/pbr/skills/shared/phase-argument-parsing.md +4 -4
- package/plugins/pbr/skills/shared/revision-loop.md +24 -6
- package/plugins/pbr/skills/shared/state-update.md +49 -56
- package/plugins/pbr/skills/shared/universal-anti-patterns.md +27 -4
- package/plugins/pbr/skills/ship/SKILL.md +155 -0
- package/plugins/pbr/skills/stats/SKILL.md +80 -0
- package/plugins/pbr/skills/status/SKILL.md +185 -119
- package/plugins/pbr/skills/test/SKILL.md +254 -0
- package/plugins/pbr/skills/thread/SKILL.md +73 -0
- package/plugins/pbr/skills/todo/SKILL.md +28 -72
- package/plugins/pbr/skills/ui-phase/SKILL.md +180 -0
- package/plugins/pbr/skills/ui-review/SKILL.md +206 -0
- package/plugins/pbr/skills/undo/SKILL.md +221 -0
- package/plugins/pbr/skills/validate-phase/SKILL.md +362 -0
- package/plugins/pbr/templates/CONTEXT.md.tmpl +45 -20
- package/plugins/pbr/templates/DISCOVERY.md.tmpl +29 -0
- package/plugins/pbr/templates/DISCUSSION-LOG.md.tmpl +49 -0
- package/plugins/pbr/templates/HANDOFF.json.tmpl +30 -0
- package/plugins/pbr/templates/INTEGRATION-REPORT.md.tmpl +18 -2
- package/plugins/pbr/templates/MILESTONE-AUDIT.md.tmpl +44 -0
- package/plugins/pbr/templates/PROJECT.md.tmpl +126 -0
- package/plugins/pbr/templates/REQUIREMENTS.md.tmpl +96 -0
- package/plugins/pbr/templates/RETROSPECTIVE.md.tmpl +43 -0
- package/plugins/pbr/templates/ROADMAP.md.tmpl +108 -14
- package/plugins/pbr/templates/SUMMARY-complex.md.tmpl +133 -0
- package/plugins/pbr/templates/SUMMARY-minimal.md.tmpl +55 -0
- package/plugins/pbr/templates/SUMMARY.md.tmpl +21 -0
- package/plugins/pbr/templates/UAT.md.tmpl +94 -0
- package/plugins/pbr/templates/UI-SPEC.md.tmpl +144 -0
- package/plugins/pbr/templates/VALIDATION.md.tmpl +94 -0
- package/plugins/pbr/templates/VERIFICATION-DETAIL.md.tmpl +49 -13
- package/plugins/pbr/templates/project-CONTEXT.md.tmpl +59 -0
- package/plugins/pbr/templates/research-outputs/ARCHITECTURE.md.tmpl +91 -0
- package/plugins/pbr/templates/research-outputs/FEATURES.md.tmpl +64 -0
- package/plugins/pbr/templates/research-outputs/PITFALLS.md.tmpl +50 -0
- package/plugins/pbr/templates/research-outputs/STACK.md.tmpl +63 -0
- package/plugins/pbr/templates/research-outputs/SUMMARY.md.tmpl +98 -0
- package/scripts/build-hooks.js +61 -0
- package/scripts/check-ci.js +100 -0
- package/scripts/clean-changelog.js +364 -0
- package/scripts/generate-derivatives.js +581 -0
- package/scripts/posttest.js +93 -0
- package/scripts/release.js +262 -0
- package/scripts/run-tests.cjs +29 -0
- package/scripts/test-wrapper.js +43 -0
- package/dashboard/bin/cli.js +0 -25
- package/dashboard/public/css/layout.css +0 -704
- package/dashboard/public/css/status-colors.css +0 -98
- package/dashboard/public/css/tokens.css +0 -59
- package/dashboard/public/js/htmx-title.js +0 -5
- package/dashboard/public/js/sidebar-toggle.js +0 -34
- package/dashboard/public/js/sse-client.js +0 -100
- package/dashboard/public/js/theme-toggle.js +0 -46
- package/dashboard/src/app.js +0 -91
- package/dashboard/src/middleware/current-phase.js +0 -24
- package/dashboard/src/middleware/errorHandler.js +0 -52
- package/dashboard/src/middleware/notFoundHandler.js +0 -9
- package/dashboard/src/repositories/planning.repository.js +0 -130
- package/dashboard/src/routes/events.routes.js +0 -45
- package/dashboard/src/routes/index.routes.js +0 -35
- package/dashboard/src/routes/pages.routes.js +0 -426
- package/dashboard/src/server.js +0 -42
- package/dashboard/src/services/analytics.service.js +0 -141
- package/dashboard/src/services/dashboard.service.js +0 -309
- package/dashboard/src/services/milestone.service.js +0 -222
- package/dashboard/src/services/notes.service.js +0 -50
- package/dashboard/src/services/phase.service.js +0 -232
- package/dashboard/src/services/project.service.js +0 -57
- package/dashboard/src/services/roadmap.service.js +0 -258
- package/dashboard/src/services/sse.service.js +0 -58
- package/dashboard/src/services/todo.service.js +0 -272
- package/dashboard/src/services/watcher.service.js +0 -48
- package/dashboard/src/utils/cache.js +0 -55
- package/dashboard/src/views/analytics.ejs +0 -5
- package/dashboard/src/views/coming-soon.ejs +0 -11
- package/dashboard/src/views/dependencies.ejs +0 -5
- package/dashboard/src/views/error.ejs +0 -20
- package/dashboard/src/views/index.ejs +0 -5
- package/dashboard/src/views/milestone-detail.ejs +0 -5
- package/dashboard/src/views/milestones.ejs +0 -5
- package/dashboard/src/views/notes.ejs +0 -5
- package/dashboard/src/views/partials/analytics-content.ejs +0 -90
- package/dashboard/src/views/partials/breadcrumbs.ejs +0 -14
- package/dashboard/src/views/partials/dashboard-content.ejs +0 -84
- package/dashboard/src/views/partials/dependencies-content.ejs +0 -48
- package/dashboard/src/views/partials/empty-state.ejs +0 -7
- package/dashboard/src/views/partials/footer.ejs +0 -3
- package/dashboard/src/views/partials/head.ejs +0 -30
- package/dashboard/src/views/partials/header.ejs +0 -21
- package/dashboard/src/views/partials/layout-bottom.ejs +0 -43
- package/dashboard/src/views/partials/layout-top.ejs +0 -16
- package/dashboard/src/views/partials/milestone-detail-content.ejs +0 -20
- package/dashboard/src/views/partials/milestones-content.ejs +0 -88
- package/dashboard/src/views/partials/notes-content.ejs +0 -23
- package/dashboard/src/views/partials/phase-content.ejs +0 -193
- package/dashboard/src/views/partials/phase-doc-content.ejs +0 -38
- package/dashboard/src/views/partials/phases-content.ejs +0 -124
- package/dashboard/src/views/partials/roadmap-content.ejs +0 -180
- package/dashboard/src/views/partials/sidebar.ejs +0 -99
- package/dashboard/src/views/partials/todo-create-content.ejs +0 -54
- package/dashboard/src/views/partials/todo-detail-content.ejs +0 -42
- package/dashboard/src/views/partials/todos-content.ejs +0 -97
- package/dashboard/src/views/phase-detail.ejs +0 -5
- package/dashboard/src/views/phase-doc.ejs +0 -5
- package/dashboard/src/views/phases.ejs +0 -5
- package/dashboard/src/views/roadmap.ejs +0 -5
- package/dashboard/src/views/todo-create.ejs +0 -5
- package/dashboard/src/views/todo-detail.ejs +0 -5
- package/dashboard/src/views/todos.ejs +0 -5
- package/plugins/copilot-pbr/CHANGELOG.md +0 -19
- package/plugins/copilot-pbr/README.md +0 -139
- package/plugins/copilot-pbr/agents/audit.agent.md +0 -113
- package/plugins/copilot-pbr/agents/codebase-mapper.agent.md +0 -151
- package/plugins/copilot-pbr/agents/debugger.agent.md +0 -182
- package/plugins/copilot-pbr/agents/executor.agent.md +0 -267
- package/plugins/copilot-pbr/agents/general.agent.md +0 -88
- package/plugins/copilot-pbr/agents/integration-checker.agent.md +0 -119
- package/plugins/copilot-pbr/agents/plan-checker.agent.md +0 -208
- package/plugins/copilot-pbr/agents/planner.agent.md +0 -238
- package/plugins/copilot-pbr/agents/researcher.agent.md +0 -186
- package/plugins/copilot-pbr/agents/synthesizer.agent.md +0 -126
- package/plugins/copilot-pbr/agents/verifier.agent.md +0 -228
- package/plugins/copilot-pbr/hooks/hooks.json +0 -156
- package/plugins/copilot-pbr/plugin.json +0 -30
- package/plugins/copilot-pbr/references/agent-anti-patterns.md +0 -25
- package/plugins/copilot-pbr/references/agent-contracts.md +0 -297
- package/plugins/copilot-pbr/references/agent-interactions.md +0 -135
- package/plugins/copilot-pbr/references/agent-teams.md +0 -55
- package/plugins/copilot-pbr/references/checkpoints.md +0 -158
- package/plugins/copilot-pbr/references/common-bug-patterns.md +0 -14
- package/plugins/copilot-pbr/references/config-reference.md +0 -442
- package/plugins/copilot-pbr/references/continuation-format.md +0 -213
- package/plugins/copilot-pbr/references/deviation-rules.md +0 -113
- package/plugins/copilot-pbr/references/git-integration.md +0 -227
- package/plugins/copilot-pbr/references/integration-patterns.md +0 -118
- package/plugins/copilot-pbr/references/model-profiles.md +0 -100
- package/plugins/copilot-pbr/references/model-selection.md +0 -32
- package/plugins/copilot-pbr/references/pbr-rules.md +0 -195
- package/plugins/copilot-pbr/references/pbr-tools-cli.md +0 -285
- package/plugins/copilot-pbr/references/plan-authoring.md +0 -182
- package/plugins/copilot-pbr/references/plan-format.md +0 -288
- package/plugins/copilot-pbr/references/planning-config.md +0 -214
- package/plugins/copilot-pbr/references/questioning.md +0 -215
- package/plugins/copilot-pbr/references/reading-verification.md +0 -128
- package/plugins/copilot-pbr/references/stub-patterns.md +0 -161
- package/plugins/copilot-pbr/references/subagent-coordination.md +0 -120
- package/plugins/copilot-pbr/references/ui-formatting.md +0 -444
- package/plugins/copilot-pbr/references/verification-patterns.md +0 -199
- package/plugins/copilot-pbr/references/wave-execution.md +0 -96
- package/plugins/copilot-pbr/rules/pbr-workflow.mdc +0 -48
- package/plugins/copilot-pbr/setup.ps1 +0 -93
- package/plugins/copilot-pbr/setup.sh +0 -93
- package/plugins/copilot-pbr/skills/audit/SKILL.md +0 -330
- package/plugins/copilot-pbr/skills/begin/SKILL.md +0 -589
- package/plugins/copilot-pbr/skills/begin/templates/PROJECT.md.tmpl +0 -34
- package/plugins/copilot-pbr/skills/begin/templates/REQUIREMENTS.md.tmpl +0 -19
- package/plugins/copilot-pbr/skills/begin/templates/STATE.md.tmpl +0 -50
- package/plugins/copilot-pbr/skills/begin/templates/config.json.tmpl +0 -64
- package/plugins/copilot-pbr/skills/begin/templates/researcher-prompt.md.tmpl +0 -20
- package/plugins/copilot-pbr/skills/begin/templates/roadmap-prompt.md.tmpl +0 -31
- package/plugins/copilot-pbr/skills/begin/templates/synthesis-prompt.md.tmpl +0 -17
- package/plugins/copilot-pbr/skills/build/SKILL.md +0 -960
- package/plugins/copilot-pbr/skills/config/SKILL.md +0 -250
- package/plugins/copilot-pbr/skills/continue/SKILL.md +0 -159
- package/plugins/copilot-pbr/skills/dashboard/SKILL.md +0 -43
- package/plugins/copilot-pbr/skills/debug/SKILL.md +0 -508
- package/plugins/copilot-pbr/skills/debug/templates/continuation-prompt.md.tmpl +0 -17
- package/plugins/copilot-pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +0 -28
- package/plugins/copilot-pbr/skills/discuss/SKILL.md +0 -353
- package/plugins/copilot-pbr/skills/discuss/templates/CONTEXT.md.tmpl +0 -62
- package/plugins/copilot-pbr/skills/discuss/templates/decision-categories.md +0 -10
- package/plugins/copilot-pbr/skills/do/SKILL.md +0 -66
- package/plugins/copilot-pbr/skills/explore/SKILL.md +0 -373
- package/plugins/copilot-pbr/skills/health/SKILL.md +0 -283
- package/plugins/copilot-pbr/skills/health/templates/check-pattern.md.tmpl +0 -31
- package/plugins/copilot-pbr/skills/health/templates/output-format.md.tmpl +0 -64
- package/plugins/copilot-pbr/skills/help/SKILL.md +0 -170
- package/plugins/copilot-pbr/skills/import/SKILL.md +0 -502
- package/plugins/copilot-pbr/skills/milestone/SKILL.md +0 -745
- package/plugins/copilot-pbr/skills/milestone/templates/audit-report.md.tmpl +0 -49
- package/plugins/copilot-pbr/skills/milestone/templates/stats-file.md.tmpl +0 -31
- package/plugins/copilot-pbr/skills/note/SKILL.md +0 -213
- package/plugins/copilot-pbr/skills/pause/SKILL.md +0 -247
- package/plugins/copilot-pbr/skills/pause/templates/continue-here.md.tmpl +0 -72
- package/plugins/copilot-pbr/skills/plan/SKILL.md +0 -662
- package/plugins/copilot-pbr/skills/plan/templates/checker-prompt.md.tmpl +0 -22
- package/plugins/copilot-pbr/skills/plan/templates/gap-closure-prompt.md.tmpl +0 -33
- package/plugins/copilot-pbr/skills/plan/templates/planner-prompt.md.tmpl +0 -39
- package/plugins/copilot-pbr/skills/plan/templates/researcher-prompt.md.tmpl +0 -20
- package/plugins/copilot-pbr/skills/plan/templates/revision-prompt.md.tmpl +0 -24
- package/plugins/copilot-pbr/skills/quick/SKILL.md +0 -376
- package/plugins/copilot-pbr/skills/resume/SKILL.md +0 -399
- package/plugins/copilot-pbr/skills/review/SKILL.md +0 -653
- package/plugins/copilot-pbr/skills/review/templates/debugger-prompt.md.tmpl +0 -61
- package/plugins/copilot-pbr/skills/review/templates/gap-planner-prompt.md.tmpl +0 -41
- package/plugins/copilot-pbr/skills/review/templates/verifier-prompt.md.tmpl +0 -116
- package/plugins/copilot-pbr/skills/scan/SKILL.md +0 -299
- package/plugins/copilot-pbr/skills/scan/templates/mapper-prompt.md.tmpl +0 -202
- package/plugins/copilot-pbr/skills/setup/SKILL.md +0 -296
- package/plugins/copilot-pbr/skills/shared/commit-planning-docs.md +0 -36
- package/plugins/copilot-pbr/skills/shared/config-loading.md +0 -103
- package/plugins/copilot-pbr/skills/shared/context-budget.md +0 -41
- package/plugins/copilot-pbr/skills/shared/context-loader-task.md +0 -87
- package/plugins/copilot-pbr/skills/shared/digest-select.md +0 -80
- package/plugins/copilot-pbr/skills/shared/domain-probes.md +0 -126
- package/plugins/copilot-pbr/skills/shared/error-reporting.md +0 -81
- package/plugins/copilot-pbr/skills/shared/gate-prompts.md +0 -389
- package/plugins/copilot-pbr/skills/shared/phase-argument-parsing.md +0 -46
- package/plugins/copilot-pbr/skills/shared/progress-display.md +0 -53
- package/plugins/copilot-pbr/skills/shared/revision-loop.md +0 -82
- package/plugins/copilot-pbr/skills/shared/state-loading.md +0 -63
- package/plugins/copilot-pbr/skills/shared/state-update.md +0 -162
- package/plugins/copilot-pbr/skills/shared/universal-anti-patterns.md +0 -38
- package/plugins/copilot-pbr/skills/status/SKILL.md +0 -362
- package/plugins/copilot-pbr/skills/statusline/SKILL.md +0 -149
- package/plugins/copilot-pbr/skills/todo/SKILL.md +0 -279
- package/plugins/copilot-pbr/templates/CONTEXT.md.tmpl +0 -53
- package/plugins/copilot-pbr/templates/INTEGRATION-REPORT.md.tmpl +0 -152
- package/plugins/copilot-pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -98
- package/plugins/copilot-pbr/templates/ROADMAP.md.tmpl +0 -41
- package/plugins/copilot-pbr/templates/SUMMARY.md.tmpl +0 -82
- package/plugins/copilot-pbr/templates/VERIFICATION-DETAIL.md.tmpl +0 -117
- package/plugins/copilot-pbr/templates/codebase/ARCHITECTURE.md.tmpl +0 -98
- package/plugins/copilot-pbr/templates/codebase/CONCERNS.md.tmpl +0 -93
- package/plugins/copilot-pbr/templates/codebase/CONVENTIONS.md.tmpl +0 -104
- package/plugins/copilot-pbr/templates/codebase/INTEGRATIONS.md.tmpl +0 -78
- package/plugins/copilot-pbr/templates/codebase/STACK.md.tmpl +0 -78
- package/plugins/copilot-pbr/templates/codebase/STRUCTURE.md.tmpl +0 -80
- package/plugins/copilot-pbr/templates/codebase/TESTING.md.tmpl +0 -107
- package/plugins/copilot-pbr/templates/continue-here.md.tmpl +0 -74
- package/plugins/copilot-pbr/templates/prompt-partials/phase-project-context.md.tmpl +0 -38
- package/plugins/copilot-pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
- package/plugins/copilot-pbr/templates/research/STACK.md.tmpl +0 -71
- package/plugins/copilot-pbr/templates/research/SUMMARY.md.tmpl +0 -112
- package/plugins/copilot-pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
- package/plugins/copilot-pbr/templates/research-outputs/project-research.md.tmpl +0 -99
- package/plugins/copilot-pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
- package/plugins/cursor-pbr/.cursor-plugin/plugin.json +0 -32
- package/plugins/cursor-pbr/CHANGELOG.md +0 -15
- package/plugins/cursor-pbr/README.md +0 -123
- package/plugins/cursor-pbr/agents/audit.md +0 -178
- package/plugins/cursor-pbr/agents/codebase-mapper.md +0 -150
- package/plugins/cursor-pbr/agents/debugger.md +0 -181
- package/plugins/cursor-pbr/agents/executor.md +0 -266
- package/plugins/cursor-pbr/agents/general.md +0 -87
- package/plugins/cursor-pbr/agents/integration-checker.md +0 -118
- package/plugins/cursor-pbr/agents/plan-checker.md +0 -207
- package/plugins/cursor-pbr/agents/planner.md +0 -237
- package/plugins/cursor-pbr/agents/researcher.md +0 -185
- package/plugins/cursor-pbr/agents/synthesizer.md +0 -125
- package/plugins/cursor-pbr/agents/verifier.md +0 -227
- package/plugins/cursor-pbr/assets/.gitkeep +0 -0
- package/plugins/cursor-pbr/assets/logo.svg +0 -21
- package/plugins/cursor-pbr/hooks/hooks.json +0 -213
- package/plugins/cursor-pbr/references/agent-anti-patterns.md +0 -25
- package/plugins/cursor-pbr/references/agent-contracts.md +0 -297
- package/plugins/cursor-pbr/references/agent-interactions.md +0 -135
- package/plugins/cursor-pbr/references/agent-teams.md +0 -55
- package/plugins/cursor-pbr/references/checkpoints.md +0 -158
- package/plugins/cursor-pbr/references/common-bug-patterns.md +0 -14
- package/plugins/cursor-pbr/references/config-reference.md +0 -442
- package/plugins/cursor-pbr/references/continuation-format.md +0 -213
- package/plugins/cursor-pbr/references/deviation-rules.md +0 -113
- package/plugins/cursor-pbr/references/git-integration.md +0 -227
- package/plugins/cursor-pbr/references/integration-patterns.md +0 -118
- package/plugins/cursor-pbr/references/model-profiles.md +0 -100
- package/plugins/cursor-pbr/references/model-selection.md +0 -32
- package/plugins/cursor-pbr/references/pbr-rules.md +0 -195
- package/plugins/cursor-pbr/references/pbr-tools-cli.md +0 -285
- package/plugins/cursor-pbr/references/plan-authoring.md +0 -182
- package/plugins/cursor-pbr/references/plan-format.md +0 -288
- package/plugins/cursor-pbr/references/planning-config.md +0 -214
- package/plugins/cursor-pbr/references/questioning.md +0 -215
- package/plugins/cursor-pbr/references/reading-verification.md +0 -128
- package/plugins/cursor-pbr/references/stub-patterns.md +0 -161
- package/plugins/cursor-pbr/references/subagent-coordination.md +0 -120
- package/plugins/cursor-pbr/references/ui-formatting.md +0 -444
- package/plugins/cursor-pbr/references/verification-patterns.md +0 -199
- package/plugins/cursor-pbr/references/wave-execution.md +0 -96
- package/plugins/cursor-pbr/rules/pbr-workflow.mdc +0 -48
- package/plugins/cursor-pbr/setup.ps1 +0 -78
- package/plugins/cursor-pbr/setup.sh +0 -83
- package/plugins/cursor-pbr/skills/audit/SKILL.md +0 -331
- package/plugins/cursor-pbr/skills/begin/SKILL.md +0 -589
- package/plugins/cursor-pbr/skills/begin/templates/PROJECT.md.tmpl +0 -34
- package/plugins/cursor-pbr/skills/begin/templates/REQUIREMENTS.md.tmpl +0 -19
- package/plugins/cursor-pbr/skills/begin/templates/STATE.md.tmpl +0 -50
- package/plugins/cursor-pbr/skills/begin/templates/config.json.tmpl +0 -64
- package/plugins/cursor-pbr/skills/begin/templates/researcher-prompt.md.tmpl +0 -20
- package/plugins/cursor-pbr/skills/begin/templates/roadmap-prompt.md.tmpl +0 -31
- package/plugins/cursor-pbr/skills/begin/templates/synthesis-prompt.md.tmpl +0 -17
- package/plugins/cursor-pbr/skills/build/SKILL.md +0 -961
- package/plugins/cursor-pbr/skills/config/SKILL.md +0 -252
- package/plugins/cursor-pbr/skills/continue/SKILL.md +0 -159
- package/plugins/cursor-pbr/skills/dashboard/SKILL.md +0 -44
- package/plugins/cursor-pbr/skills/debug/SKILL.md +0 -512
- package/plugins/cursor-pbr/skills/debug/templates/continuation-prompt.md.tmpl +0 -17
- package/plugins/cursor-pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +0 -28
- package/plugins/cursor-pbr/skills/discuss/SKILL.md +0 -354
- package/plugins/cursor-pbr/skills/discuss/templates/CONTEXT.md.tmpl +0 -62
- package/plugins/cursor-pbr/skills/discuss/templates/decision-categories.md +0 -10
- package/plugins/cursor-pbr/skills/do/SKILL.md +0 -67
- package/plugins/cursor-pbr/skills/explore/SKILL.md +0 -376
- package/plugins/cursor-pbr/skills/health/SKILL.md +0 -283
- package/plugins/cursor-pbr/skills/health/templates/check-pattern.md.tmpl +0 -31
- package/plugins/cursor-pbr/skills/health/templates/output-format.md.tmpl +0 -64
- package/plugins/cursor-pbr/skills/help/SKILL.md +0 -170
- package/plugins/cursor-pbr/skills/import/SKILL.md +0 -505
- package/plugins/cursor-pbr/skills/milestone/SKILL.md +0 -746
- package/plugins/cursor-pbr/skills/milestone/templates/audit-report.md.tmpl +0 -49
- package/plugins/cursor-pbr/skills/milestone/templates/stats-file.md.tmpl +0 -31
- package/plugins/cursor-pbr/skills/note/SKILL.md +0 -214
- package/plugins/cursor-pbr/skills/pause/SKILL.md +0 -248
- package/plugins/cursor-pbr/skills/pause/templates/continue-here.md.tmpl +0 -72
- package/plugins/cursor-pbr/skills/plan/SKILL.md +0 -663
- package/plugins/cursor-pbr/skills/plan/templates/checker-prompt.md.tmpl +0 -22
- package/plugins/cursor-pbr/skills/plan/templates/gap-closure-prompt.md.tmpl +0 -33
- package/plugins/cursor-pbr/skills/plan/templates/planner-prompt.md.tmpl +0 -39
- package/plugins/cursor-pbr/skills/plan/templates/researcher-prompt.md.tmpl +0 -20
- package/plugins/cursor-pbr/skills/plan/templates/revision-prompt.md.tmpl +0 -24
- package/plugins/cursor-pbr/skills/quick/SKILL.md +0 -376
- package/plugins/cursor-pbr/skills/resume/SKILL.md +0 -399
- package/plugins/cursor-pbr/skills/review/SKILL.md +0 -654
- package/plugins/cursor-pbr/skills/review/templates/debugger-prompt.md.tmpl +0 -61
- package/plugins/cursor-pbr/skills/review/templates/gap-planner-prompt.md.tmpl +0 -41
- package/plugins/cursor-pbr/skills/review/templates/verifier-prompt.md.tmpl +0 -116
- package/plugins/cursor-pbr/skills/scan/SKILL.md +0 -300
- package/plugins/cursor-pbr/skills/scan/templates/mapper-prompt.md.tmpl +0 -202
- package/plugins/cursor-pbr/skills/setup/SKILL.md +0 -296
- package/plugins/cursor-pbr/skills/shared/commit-planning-docs.md +0 -36
- package/plugins/cursor-pbr/skills/shared/config-loading.md +0 -103
- package/plugins/cursor-pbr/skills/shared/context-budget.md +0 -41
- package/plugins/cursor-pbr/skills/shared/context-loader-task.md +0 -87
- package/plugins/cursor-pbr/skills/shared/digest-select.md +0 -80
- package/plugins/cursor-pbr/skills/shared/domain-probes.md +0 -126
- package/plugins/cursor-pbr/skills/shared/error-reporting.md +0 -81
- package/plugins/cursor-pbr/skills/shared/gate-prompts.md +0 -389
- package/plugins/cursor-pbr/skills/shared/phase-argument-parsing.md +0 -46
- package/plugins/cursor-pbr/skills/shared/progress-display.md +0 -53
- package/plugins/cursor-pbr/skills/shared/revision-loop.md +0 -82
- package/plugins/cursor-pbr/skills/shared/state-loading.md +0 -63
- package/plugins/cursor-pbr/skills/shared/state-update.md +0 -162
- package/plugins/cursor-pbr/skills/shared/universal-anti-patterns.md +0 -38
- package/plugins/cursor-pbr/skills/status/SKILL.md +0 -362
- package/plugins/cursor-pbr/skills/statusline/SKILL.md +0 -150
- package/plugins/cursor-pbr/skills/todo/SKILL.md +0 -280
- package/plugins/cursor-pbr/templates/CONTEXT.md.tmpl +0 -53
- package/plugins/cursor-pbr/templates/INTEGRATION-REPORT.md.tmpl +0 -152
- package/plugins/cursor-pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -98
- package/plugins/cursor-pbr/templates/ROADMAP.md.tmpl +0 -41
- package/plugins/cursor-pbr/templates/SUMMARY.md.tmpl +0 -82
- package/plugins/cursor-pbr/templates/VERIFICATION-DETAIL.md.tmpl +0 -117
- package/plugins/cursor-pbr/templates/codebase/ARCHITECTURE.md.tmpl +0 -98
- package/plugins/cursor-pbr/templates/codebase/CONCERNS.md.tmpl +0 -93
- package/plugins/cursor-pbr/templates/codebase/CONVENTIONS.md.tmpl +0 -104
- package/plugins/cursor-pbr/templates/codebase/INTEGRATIONS.md.tmpl +0 -78
- package/plugins/cursor-pbr/templates/codebase/STACK.md.tmpl +0 -78
- package/plugins/cursor-pbr/templates/codebase/STRUCTURE.md.tmpl +0 -80
- package/plugins/cursor-pbr/templates/codebase/TESTING.md.tmpl +0 -107
- package/plugins/cursor-pbr/templates/continue-here.md.tmpl +0 -74
- package/plugins/cursor-pbr/templates/prompt-partials/phase-project-context.md.tmpl +0 -38
- package/plugins/cursor-pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
- package/plugins/cursor-pbr/templates/research/STACK.md.tmpl +0 -71
- package/plugins/cursor-pbr/templates/research/SUMMARY.md.tmpl +0 -112
- package/plugins/cursor-pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
- package/plugins/cursor-pbr/templates/research-outputs/project-research.md.tmpl +0 -99
- package/plugins/cursor-pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
- package/plugins/pbr/references/agent-interactions.md +0 -134
- package/plugins/pbr/references/pbr-rules.md +0 -194
- package/plugins/pbr/references/pbr-tools-cli.md +0 -285
- package/plugins/pbr/references/planning-config.md +0 -213
- package/plugins/pbr/references/subagent-coordination.md +0 -119
- package/plugins/pbr/references/ui-formatting.md +0 -444
- package/plugins/pbr/scripts/validate-plugin-structure.js +0 -183
- package/plugins/pbr/skills/milestone/templates/audit-report.md.tmpl +0 -48
- package/plugins/pbr/skills/shared/progress-display.md +0 -53
- package/plugins/pbr/skills/shared/state-loading.md +0 -62
- package/plugins/pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -97
- package/plugins/pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
- package/plugins/pbr/templates/research/STACK.md.tmpl +0 -71
- package/plugins/pbr/templates/research/SUMMARY.md.tmpl +0 -112
- package/plugins/pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
- package/plugins/pbr/templates/research-outputs/project-research.md.tmpl +0 -99
- package/plugins/pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
- /package/plugins/pbr/references/{agent-anti-patterns.md → archive/agent-anti-patterns.md} +0 -0
|
@@ -0,0 +1,1025 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Format validators extracted from check-plan-format.js.
|
|
5
|
+
* Validates planning artifact structure (PLAN, SUMMARY, VERIFICATION, STATE,
|
|
6
|
+
* ROADMAP, LEARNINGS, config.json, RESEARCH, CONTEXT).
|
|
7
|
+
*
|
|
8
|
+
* Each validate* function returns { errors: string[], warnings: string[] }.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const { logHook } = require('../hook-logger');
|
|
14
|
+
const { logEvent } = require('../event-logger');
|
|
15
|
+
const { lockedFileUpdate } = require('../pbr-tools');
|
|
16
|
+
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Must-haves
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Validate must_haves sub-field structure within frontmatter.
|
|
23
|
+
* Checks that truths, artifacts, and key_links sub-fields exist under must_haves.
|
|
24
|
+
* Uses warnings (not errors) during migration period.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} frontmatter - The frontmatter content (between --- delimiters)
|
|
27
|
+
* @returns {{ errors: string[], warnings: string[] }}
|
|
28
|
+
*/
|
|
29
|
+
function validateMustHaves(frontmatter) {
|
|
30
|
+
const warnings = [];
|
|
31
|
+
|
|
32
|
+
const mustHavesIdx = frontmatter.indexOf('must_haves:');
|
|
33
|
+
if (mustHavesIdx === -1) return { errors: [], warnings };
|
|
34
|
+
|
|
35
|
+
const afterMustHaves = frontmatter.substring(mustHavesIdx + 'must_haves:'.length);
|
|
36
|
+
const nextKeyMatch = afterMustHaves.match(/\n[a-zA-Z_][a-zA-Z0-9_]*:/);
|
|
37
|
+
const mustHavesBlock = nextKeyMatch
|
|
38
|
+
? afterMustHaves.substring(0, nextKeyMatch.index)
|
|
39
|
+
: afterMustHaves;
|
|
40
|
+
|
|
41
|
+
const requiredSubFields = ['truths', 'artifacts', 'key_links'];
|
|
42
|
+
for (const subField of requiredSubFields) {
|
|
43
|
+
const subFieldRegex = new RegExp(`^\\s+${subField}:`, 'm');
|
|
44
|
+
if (!subFieldRegex.test(mustHavesBlock)) {
|
|
45
|
+
warnings.push(`must_haves missing "${subField}" sub-field`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return { errors: [], warnings };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// PLAN validation
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
/** Canonical required fields for PLAN.md frontmatter. */
|
|
57
|
+
const PLAN_REQUIRED_FIELDS = ['phase', 'plan', 'wave', 'type', 'depends_on', 'files_modified', 'autonomous'];
|
|
58
|
+
|
|
59
|
+
/** Valid values for the type: field in PLAN.md frontmatter. */
|
|
60
|
+
const PLAN_VALID_TYPES = ['feature', 'bugfix', 'refactor', 'infrastructure', 'docs', 'chore'];
|
|
61
|
+
|
|
62
|
+
function validatePlan(content, _filePath) {
|
|
63
|
+
const errors = [];
|
|
64
|
+
const warnings = [];
|
|
65
|
+
|
|
66
|
+
// Check frontmatter
|
|
67
|
+
if (!content.startsWith('---')) {
|
|
68
|
+
errors.push('Missing YAML frontmatter');
|
|
69
|
+
} else {
|
|
70
|
+
const frontmatterEnd = content.indexOf('---', 3);
|
|
71
|
+
if (frontmatterEnd === -1) {
|
|
72
|
+
errors.push('Unclosed YAML frontmatter');
|
|
73
|
+
} else {
|
|
74
|
+
const frontmatter = content.substring(3, frontmatterEnd);
|
|
75
|
+
for (const field of PLAN_REQUIRED_FIELDS) {
|
|
76
|
+
if (!frontmatter.includes(`${field}:`)) {
|
|
77
|
+
errors.push(`Frontmatter missing "${field}" field`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Validate type enum value
|
|
82
|
+
const typeMatch = frontmatter.match(/^type:\s*["']?([^"'\r\n]+)["']?\s*$/m);
|
|
83
|
+
if (typeMatch) {
|
|
84
|
+
const typeValue = typeMatch[1].trim();
|
|
85
|
+
if (!PLAN_VALID_TYPES.includes(typeValue)) {
|
|
86
|
+
warnings.push(`Unexpected type value: "${typeValue}" (expected: ${PLAN_VALID_TYPES.join(', ')})`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (!frontmatter.includes('must_haves:')) {
|
|
90
|
+
errors.push('Frontmatter missing "must_haves" field (truths/artifacts/key_links required)');
|
|
91
|
+
} else {
|
|
92
|
+
const mhResult = validateMustHaves(frontmatter);
|
|
93
|
+
warnings.push(...mhResult.warnings);
|
|
94
|
+
}
|
|
95
|
+
// Blocking: implements:[] is required for REQ-ID traceability (Phase 66)
|
|
96
|
+
if (!frontmatter.includes('implements:')) {
|
|
97
|
+
errors.push('Frontmatter missing required "implements" field (use implements:[] if no requirements apply)');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Count tasks
|
|
103
|
+
const taskMatches = content.match(/<task\b[^>]*>/g) || [];
|
|
104
|
+
const taskCount = taskMatches.length;
|
|
105
|
+
|
|
106
|
+
if (taskCount === 0) {
|
|
107
|
+
errors.push('No <task> elements found');
|
|
108
|
+
} else if (taskCount > 3) {
|
|
109
|
+
errors.push(`Too many tasks: ${taskCount} (max 3 per plan)`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Check each task has required elements
|
|
113
|
+
const taskTags = content.match(/<task\b[^>]*>/g) || [];
|
|
114
|
+
const taskBlocks = content.split(/<task\b[^>]*>/).slice(1);
|
|
115
|
+
const requiredElements = ['name', 'read_first', 'files', 'action', 'acceptance_criteria', 'verify', 'done'];
|
|
116
|
+
|
|
117
|
+
taskBlocks.forEach((block, index) => {
|
|
118
|
+
const taskEnd = block.indexOf('</task>');
|
|
119
|
+
const taskContent = taskEnd !== -1 ? block.substring(0, taskEnd) : block;
|
|
120
|
+
|
|
121
|
+
// Skip checkpoint tasks - they have different required elements
|
|
122
|
+
const taskTag = taskTags[index] || '';
|
|
123
|
+
if (/\btype\s*=\s*["']?checkpoint/i.test(taskTag) || /\bcheckpoint\s*[:=]/i.test(taskTag)) {
|
|
124
|
+
return; // Checkpoint tasks have different structure
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
for (const elem of requiredElements) {
|
|
128
|
+
if (!taskContent.includes(`<${elem}>`) && !taskContent.includes(`<${elem} `)) {
|
|
129
|
+
errors.push(`Task ${index + 1}: missing <${elem}> element`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Validate read_first paths don't contain wildcards
|
|
134
|
+
const readFirstMatch = taskContent.match(/<read_first>([\s\S]*?)<\/read_first>/);
|
|
135
|
+
if (readFirstMatch) {
|
|
136
|
+
const rfPaths = readFirstMatch[1].split(/\n/).map(l => l.trim()).filter(Boolean);
|
|
137
|
+
for (const rfPath of rfPaths) {
|
|
138
|
+
if (rfPath.includes('*')) {
|
|
139
|
+
warnings.push(`Task ${index + 1}: read_first should use specific paths, not globs: "${rfPath}"`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Feature task validation: require <behavior> and <implementation> child elements
|
|
145
|
+
if (taskContent.includes('<feature>')) {
|
|
146
|
+
if (!taskContent.includes('<behavior>') && !taskContent.includes('<behavior ')) {
|
|
147
|
+
errors.push(`Task ${index + 1}: feature task missing <behavior> element`);
|
|
148
|
+
}
|
|
149
|
+
if (!taskContent.includes('<implementation>') && !taskContent.includes('<implementation ')) {
|
|
150
|
+
errors.push(`Task ${index + 1}: feature task missing <implementation> element`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Informational: automated verify wrapper advisory
|
|
155
|
+
const verifyMatch = taskContent.match(/<verify>([\s\S]*?)<\/verify>/);
|
|
156
|
+
if (verifyMatch && verifyMatch[1].includes('<automated>')) {
|
|
157
|
+
warnings.push(`Task ${index + 1}: uses automated verify wrapper (machine-parseable commands for auto_checkpoints mode)`);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Path traversal check: ensure <files> elements don't escape project root
|
|
162
|
+
const filesTags = content.match(/<files>([\s\S]*?)<\/files>/g) || [];
|
|
163
|
+
for (const filesTag of filesTags) {
|
|
164
|
+
const filesContent = filesTag.replace(/<\/?files>/g, '');
|
|
165
|
+
const paths = filesContent.split(/[\n,]/).map(p => p.trim()).filter(Boolean);
|
|
166
|
+
for (const p of paths) {
|
|
167
|
+
if (p.includes('..') || path.isAbsolute(p.replace(/^[A-Za-z]:/, ''))) {
|
|
168
|
+
warnings.push(`Path traversal risk in <files>: "${p}" — use relative paths without ".." segments`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return { errors, warnings };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
// SUMMARY validation
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
|
|
180
|
+
function validateSummary(content, _filePath) {
|
|
181
|
+
const errors = [];
|
|
182
|
+
const warnings = [];
|
|
183
|
+
|
|
184
|
+
// Check frontmatter
|
|
185
|
+
if (!content.startsWith('---')) {
|
|
186
|
+
errors.push('Missing YAML frontmatter');
|
|
187
|
+
} else {
|
|
188
|
+
const frontmatterEnd = content.indexOf('---', 3);
|
|
189
|
+
if (frontmatterEnd === -1) {
|
|
190
|
+
errors.push('Unclosed YAML frontmatter');
|
|
191
|
+
} else {
|
|
192
|
+
const frontmatter = content.substring(3, frontmatterEnd);
|
|
193
|
+
|
|
194
|
+
// Required fields -- structural errors
|
|
195
|
+
const requiredFields = ['phase', 'plan', 'status', 'provides', 'requires', 'key_files'];
|
|
196
|
+
for (const field of requiredFields) {
|
|
197
|
+
if (!frontmatter.includes(`${field}:`)) {
|
|
198
|
+
errors.push(`Frontmatter missing "${field}" field`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Optional but encouraged -- warnings
|
|
203
|
+
if (!frontmatter.includes('deferred:')) {
|
|
204
|
+
warnings.push('Frontmatter missing "deferred" field (forces executor to consciously record scope creep)');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Metrics fields -- warnings only
|
|
208
|
+
if (!frontmatter.includes('duration:')) {
|
|
209
|
+
warnings.push('Frontmatter missing "duration" field (minutes as number — dashboard depends on this)');
|
|
210
|
+
}
|
|
211
|
+
if (!frontmatter.includes('requirements-completed:')) {
|
|
212
|
+
warnings.push('Frontmatter missing "requirements-completed" field (array of REQ-IDs — status skill depends on this)');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Validate key_files paths exist on disk
|
|
216
|
+
const keyFilesMatch = frontmatter.match(/key_files:\s*\n((?:\s+-\s+.*\n?)*)/);
|
|
217
|
+
if (keyFilesMatch) {
|
|
218
|
+
const lines = keyFilesMatch[1].split('\n').filter(l => l.trim().startsWith('-'));
|
|
219
|
+
for (const line of lines) {
|
|
220
|
+
const entryMatch = line.match(/^\s*-\s+"?([^":]+?)(?::.*)?"?\s*$/);
|
|
221
|
+
if (entryMatch) {
|
|
222
|
+
const filePortion = entryMatch[1].trim();
|
|
223
|
+
if (filePortion && !fs.existsSync(filePortion)) {
|
|
224
|
+
warnings.push(`key_files path not found on disk: ${filePortion}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Validate deviations structure if present
|
|
231
|
+
const deviationsResult = validateDeviationsField(frontmatter);
|
|
232
|
+
errors.push(...deviationsResult.errors);
|
|
233
|
+
warnings.push(...deviationsResult.warnings);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Body section validation — check that required template sections exist
|
|
238
|
+
// Advisory only (warnings) since executors may use minimal template
|
|
239
|
+
const secondDash = content.indexOf('---', 3);
|
|
240
|
+
if (secondDash !== -1) {
|
|
241
|
+
const body = content.substring(secondDash + 3);
|
|
242
|
+
const hasWhatWasBuilt = /^##\s+What Was Built/m.test(body);
|
|
243
|
+
const hasTaskResults = /^##\s+Task Results/m.test(body);
|
|
244
|
+
const hasSelfCheck = /^##\s+Self-Check/m.test(body);
|
|
245
|
+
|
|
246
|
+
if (!hasWhatWasBuilt && !hasTaskResults) {
|
|
247
|
+
warnings.push('Body missing required section: "## What Was Built" or "## Task Results" (see SUMMARY.md template)');
|
|
248
|
+
}
|
|
249
|
+
if (!hasSelfCheck) {
|
|
250
|
+
warnings.push('Body missing required section: "## Self-Check" (required per all template tiers)');
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return { errors, warnings };
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// ---------------------------------------------------------------------------
|
|
258
|
+
// Deviations field validation
|
|
259
|
+
// ---------------------------------------------------------------------------
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Validate the deviations field structure in SUMMARY.md frontmatter.
|
|
263
|
+
* Deviations use a taxonomy: rule (1-4), action (auto|ask), description, justification.
|
|
264
|
+
*
|
|
265
|
+
* @param {string} frontmatter - The frontmatter content (between --- delimiters)
|
|
266
|
+
* @returns {{ errors: string[], warnings: string[] }}
|
|
267
|
+
*/
|
|
268
|
+
function validateDeviationsField(frontmatter) {
|
|
269
|
+
const errors = [];
|
|
270
|
+
const warnings = [];
|
|
271
|
+
|
|
272
|
+
const deviationsIdx = frontmatter.indexOf('deviations:');
|
|
273
|
+
if (deviationsIdx === -1) return { errors, warnings };
|
|
274
|
+
|
|
275
|
+
const afterDeviations = frontmatter.substring(deviationsIdx + 'deviations:'.length);
|
|
276
|
+
|
|
277
|
+
// Check if it's an empty/inline value
|
|
278
|
+
const firstLine = afterDeviations.split(/\r?\n/)[0].trim();
|
|
279
|
+
if (firstLine === '[]' || firstLine === 'none' || firstLine === '~' || firstLine === 'null') {
|
|
280
|
+
return { errors, warnings };
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const itemMatches = afterDeviations.match(/^\s+-\s+rule:/gm);
|
|
284
|
+
if (!itemMatches) return { errors, warnings };
|
|
285
|
+
|
|
286
|
+
const VALID_RULES = [1, 2, 3, 4];
|
|
287
|
+
const VALID_ACTIONS = ['auto', 'ask'];
|
|
288
|
+
|
|
289
|
+
const lines = afterDeviations.split(/\r?\n/);
|
|
290
|
+
let currentItem = null;
|
|
291
|
+
const items = [];
|
|
292
|
+
|
|
293
|
+
for (const line of lines) {
|
|
294
|
+
if (/^\s+-\s+rule:/.test(line)) {
|
|
295
|
+
if (currentItem) items.push(currentItem);
|
|
296
|
+
currentItem = { raw: line };
|
|
297
|
+
const ruleMatch = line.match(/rule:\s*(\d+)/);
|
|
298
|
+
if (ruleMatch) currentItem.rule = parseInt(ruleMatch[1], 10);
|
|
299
|
+
} else if (currentItem) {
|
|
300
|
+
if (/^[a-zA-Z_][a-zA-Z0-9_]*:/.test(line)) break;
|
|
301
|
+
const actionMatch = line.match(/^\s+action:\s*["']?(\w+)/);
|
|
302
|
+
if (actionMatch) currentItem.action = actionMatch[1];
|
|
303
|
+
const descMatch = line.match(/^\s+description:/);
|
|
304
|
+
if (descMatch) currentItem.hasDescription = true;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (currentItem) items.push(currentItem);
|
|
308
|
+
|
|
309
|
+
for (let i = 0; i < items.length; i++) {
|
|
310
|
+
const item = items[i];
|
|
311
|
+
if (item.rule !== undefined && !VALID_RULES.includes(item.rule)) {
|
|
312
|
+
errors.push(`deviations[${i}]: invalid rule "${item.rule}" (must be 1-4)`);
|
|
313
|
+
}
|
|
314
|
+
if (item.action && !VALID_ACTIONS.includes(item.action)) {
|
|
315
|
+
errors.push(`deviations[${i}]: invalid action "${item.action}" (must be auto|ask)`);
|
|
316
|
+
}
|
|
317
|
+
if (!item.hasDescription) {
|
|
318
|
+
warnings.push(`deviations[${i}]: missing "description" field`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return { errors, warnings };
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// ---------------------------------------------------------------------------
|
|
326
|
+
// checkPlanWrite (dispatcher entry point)
|
|
327
|
+
// ---------------------------------------------------------------------------
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Core plan/summary check logic for use by dispatchers.
|
|
331
|
+
* @param {Object} data - Parsed hook input (tool_input, etc.)
|
|
332
|
+
* @returns {Promise<null|{output: Object}>} null if pass or not applicable, result otherwise
|
|
333
|
+
*/
|
|
334
|
+
async function checkPlanWrite(data) {
|
|
335
|
+
const filePath = data.tool_input?.file_path || data.tool_input?.path || '';
|
|
336
|
+
const basename = path.basename(filePath);
|
|
337
|
+
const isPlan = /^PLAN.*\.md$/.test(basename);
|
|
338
|
+
const isSummary = basename.includes('SUMMARY') && basename.endsWith('.md');
|
|
339
|
+
const isVerification = basename === 'VERIFICATION.md';
|
|
340
|
+
const isRoadmap = basename === 'ROADMAP.md';
|
|
341
|
+
const isLearnings = basename === 'LEARNINGS.md';
|
|
342
|
+
const isConfig = basename === 'config.json' && filePath.includes('.planning');
|
|
343
|
+
const isResearch = basename === 'RESEARCH.md';
|
|
344
|
+
const isContext = basename === 'CONTEXT.md' && filePath.includes('.planning');
|
|
345
|
+
|
|
346
|
+
if (!isPlan && !isSummary && !isVerification && !isRoadmap && !isLearnings && !isConfig && !isResearch && !isContext) return null;
|
|
347
|
+
|
|
348
|
+
// Todo 015: First-write awareness -- downgrade errors to warnings on Write
|
|
349
|
+
// PostToolUse runs AFTER the write, so fs.existsSync() always returns true.
|
|
350
|
+
// Instead, detect Write vs Edit via tool_name: Write = full file creation/overwrite
|
|
351
|
+
// (likely first attempt), Edit = modifying existing content (refinement).
|
|
352
|
+
// On Write, downgrade blocking errors to advisory warnings so agents aren't
|
|
353
|
+
// blocked on first attempt, reducing false positive block-and-retry cycles.
|
|
354
|
+
const isWriteTool = (data.tool_name || '').toLowerCase() === 'write';
|
|
355
|
+
|
|
356
|
+
if (!fs.existsSync(filePath)) return null;
|
|
357
|
+
|
|
358
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
359
|
+
const result = isPlan
|
|
360
|
+
? validatePlan(content, filePath)
|
|
361
|
+
: isVerification
|
|
362
|
+
? validateVerification(content, filePath)
|
|
363
|
+
: isRoadmap
|
|
364
|
+
? validateRoadmap(content, filePath)
|
|
365
|
+
: isLearnings
|
|
366
|
+
? validateLearnings(content, filePath)
|
|
367
|
+
: isConfig
|
|
368
|
+
? validateConfig(content, filePath)
|
|
369
|
+
: isResearch
|
|
370
|
+
? validateResearch(content, filePath)
|
|
371
|
+
: isContext
|
|
372
|
+
? validateContext(content, filePath)
|
|
373
|
+
: validateSummary(content, filePath);
|
|
374
|
+
|
|
375
|
+
const eventType = isPlan ? 'plan-validated' : isVerification ? 'verification-validated' : isRoadmap ? 'roadmap-validated' : isLearnings ? 'learnings-validated' : isConfig ? 'config-validated' : isResearch ? 'research-validated' : isContext ? 'context-validated' : 'summary-validated';
|
|
376
|
+
|
|
377
|
+
if (result.errors.length > 0) {
|
|
378
|
+
// On Write tool (first creation), downgrade errors to warnings.
|
|
379
|
+
// The agent will see the advisory and can fix on next Edit without
|
|
380
|
+
// wasting a block-and-retry cycle.
|
|
381
|
+
if (isWriteTool) {
|
|
382
|
+
const allIssues = [...result.errors, ...result.warnings];
|
|
383
|
+
logHook('check-plan-format', 'PostToolUse', 'warn-downgraded', { file: basename, errors: result.errors, reason: 'Write tool (first creation)' });
|
|
384
|
+
logEvent('workflow', eventType, { file: basename, status: 'warn-downgraded', errorCount: result.errors.length });
|
|
385
|
+
return { output: { additionalContext: `${basename} advisory (fix on next edit):\n${allIssues.map(i => ` - ${i}`).join('\n')}` } };
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
logHook('check-plan-format', 'PostToolUse', 'block', { file: basename, errors: result.errors });
|
|
389
|
+
logEvent('workflow', eventType, { file: basename, status: 'block', errorCount: result.errors.length });
|
|
390
|
+
|
|
391
|
+
const summary = `${basename} has structural errors that must be fixed.`;
|
|
392
|
+
const explanation = result.errors.map(i => ` - ${i}`).join('\n') +
|
|
393
|
+
(result.warnings.length > 0 ? '\n\nWarnings (non-blocking):\n' + result.warnings.map(i => ` - ${i}`).join('\n') : '');
|
|
394
|
+
const remediation = 'Fix the listed issues and re-save the file.';
|
|
395
|
+
return { output: { decision: 'block', reason: `${summary}\n\n${explanation}\n\n${remediation}` } };
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (result.warnings.length > 0) {
|
|
399
|
+
logHook('check-plan-format', 'PostToolUse', 'warn', { file: basename, warnings: result.warnings });
|
|
400
|
+
logEvent('workflow', eventType, { file: basename, status: 'warn', warningCount: result.warnings.length });
|
|
401
|
+
return { output: { additionalContext: `${basename} warnings:\n${result.warnings.map(i => ` - ${i}`).join('\n')}` } };
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
logHook('check-plan-format', 'PostToolUse', 'pass', { file: basename });
|
|
405
|
+
logEvent('workflow', eventType, { file: basename, status: 'pass' });
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// ---------------------------------------------------------------------------
|
|
410
|
+
// STATE validation
|
|
411
|
+
// ---------------------------------------------------------------------------
|
|
412
|
+
|
|
413
|
+
/** All valid STATE.md status values (13 canonical + legacy aliases). */
|
|
414
|
+
const VALID_STATE_STATUSES = [
|
|
415
|
+
'not_started', 'discussed', 'ready_to_plan', 'planning',
|
|
416
|
+
'planned', 'ready_to_execute', 'building', 'built',
|
|
417
|
+
'partial', 'verified', 'needs_fixes', 'complete', 'skipped',
|
|
418
|
+
// Legacy aliases
|
|
419
|
+
'pending', 'reviewed', 'milestone_complete'
|
|
420
|
+
];
|
|
421
|
+
|
|
422
|
+
function validateState(content, _filePath) {
|
|
423
|
+
const errors = [];
|
|
424
|
+
const warnings = [];
|
|
425
|
+
|
|
426
|
+
// STATE.md uses warnings (not errors) because it's written by multiple hooks
|
|
427
|
+
// and auto-sync processes. Blocking would create feedback loops.
|
|
428
|
+
if (!content.startsWith('---')) {
|
|
429
|
+
warnings.push('Missing YAML frontmatter');
|
|
430
|
+
} else {
|
|
431
|
+
const frontmatterEnd = content.indexOf('---', 3);
|
|
432
|
+
if (frontmatterEnd === -1) {
|
|
433
|
+
warnings.push('Unclosed YAML frontmatter');
|
|
434
|
+
} else {
|
|
435
|
+
const frontmatter = content.substring(3, frontmatterEnd);
|
|
436
|
+
const requiredFields = ['version', 'current_phase', 'phase_slug', 'status'];
|
|
437
|
+
for (const field of requiredFields) {
|
|
438
|
+
if (!frontmatter.includes(`${field}:`)) {
|
|
439
|
+
warnings.push(`Frontmatter missing "${field}" field`);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Validate status value against the 13-state lifecycle + legacy aliases
|
|
444
|
+
const statusMatch = frontmatter.match(/^status:\s*["']?([^"'\r\n]+)["']?\s*$/m);
|
|
445
|
+
if (statusMatch) {
|
|
446
|
+
const statusValue = statusMatch[1].trim();
|
|
447
|
+
if (!VALID_STATE_STATUSES.includes(statusValue)) {
|
|
448
|
+
warnings.push(`Unknown status value: "${statusValue}" (valid: ${VALID_STATE_STATUSES.slice(0, 13).join(', ')})`);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
return { errors, warnings };
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// ---------------------------------------------------------------------------
|
|
458
|
+
// VERIFICATION validation
|
|
459
|
+
// ---------------------------------------------------------------------------
|
|
460
|
+
|
|
461
|
+
function validateVerification(content, filePath) {
|
|
462
|
+
const errors = [];
|
|
463
|
+
const warnings = [];
|
|
464
|
+
|
|
465
|
+
if (!content.startsWith('---')) {
|
|
466
|
+
errors.push('Missing YAML frontmatter');
|
|
467
|
+
} else {
|
|
468
|
+
const frontmatterEnd = content.indexOf('---', 3);
|
|
469
|
+
if (frontmatterEnd === -1) {
|
|
470
|
+
errors.push('Unclosed YAML frontmatter');
|
|
471
|
+
} else {
|
|
472
|
+
const frontmatter = content.substring(3, frontmatterEnd);
|
|
473
|
+
const requiredFields = ['status', 'phase', 'checked_at', 'must_haves_checked', 'must_haves_passed', 'must_haves_failed'];
|
|
474
|
+
for (const field of requiredFields) {
|
|
475
|
+
if (!frontmatter.includes(`${field}:`)) {
|
|
476
|
+
errors.push(`Frontmatter missing "${field}" field`);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Advisory: traceability fields
|
|
481
|
+
if (!/(?:^|\n)\s*satisfied:/.test(frontmatter)) {
|
|
482
|
+
warnings.push('Frontmatter missing "satisfied" field — add satisfied:[] listing REQ-IDs confirmed in this phase');
|
|
483
|
+
}
|
|
484
|
+
if (!frontmatter.includes('unsatisfied:')) {
|
|
485
|
+
warnings.push('Frontmatter missing "unsatisfied" field — add unsatisfied:[] listing REQ-IDs that failed verification');
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Advisory: fix_plans field when gaps are found
|
|
489
|
+
const statusMatch = frontmatter.match(/^status:\s*["']?([^"'\r\n]+)["']?\s*$/m);
|
|
490
|
+
const hasGaps = statusMatch && statusMatch[1].trim() === 'gaps_found';
|
|
491
|
+
if (hasGaps && !frontmatter.includes('fix_plans:')) {
|
|
492
|
+
warnings.push('Frontmatter has status "gaps_found" but no "fix_plans" field — add fix_plans with gap/effort/tasks for each gap');
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Advisory: gap severity classification
|
|
496
|
+
const gapsFoundMatch = frontmatter.match(/gaps_found:\s*(\d+)/);
|
|
497
|
+
if (gapsFoundMatch && parseInt(gapsFoundMatch[1], 10) > 0) {
|
|
498
|
+
if (!frontmatter.includes('severity:') && !frontmatter.includes('gap_severity:')) {
|
|
499
|
+
warnings.push('Gaps found but no severity classification — add severity (critical|non-critical) to gap entries');
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// Advisory: must_haves_checked: 0 with PLAN files that have must-haves
|
|
504
|
+
const mustHavesCheckedMatch = frontmatter.match(/must_haves_checked:\s*(\d+)/);
|
|
505
|
+
if (mustHavesCheckedMatch && parseInt(mustHavesCheckedMatch[1], 10) === 0 && filePath) {
|
|
506
|
+
try {
|
|
507
|
+
const phaseDir = path.dirname(filePath);
|
|
508
|
+
const planFiles = fs.readdirSync(phaseDir).filter(f => /^PLAN.*\.md$/i.test(f));
|
|
509
|
+
let totalMustHaves = 0;
|
|
510
|
+
for (const pf of planFiles) {
|
|
511
|
+
try {
|
|
512
|
+
const planContent = fs.readFileSync(path.join(phaseDir, pf), 'utf8');
|
|
513
|
+
const pfmEnd = planContent.indexOf('---', 3);
|
|
514
|
+
if (pfmEnd !== -1) {
|
|
515
|
+
const pfm = planContent.substring(3, pfmEnd);
|
|
516
|
+
// Count non-empty truths and artifacts entries
|
|
517
|
+
const truthsMatch = pfm.match(/truths:\s*\n((?:\s+-\s+.+\n)*)/);
|
|
518
|
+
const artifactsMatch = pfm.match(/artifacts:\s*\n((?:\s+-\s+.+\n)*)/);
|
|
519
|
+
if (truthsMatch && truthsMatch[1].trim()) totalMustHaves += truthsMatch[1].trim().split('\n').length;
|
|
520
|
+
if (artifactsMatch && artifactsMatch[1].trim()) totalMustHaves += artifactsMatch[1].trim().split('\n').length;
|
|
521
|
+
}
|
|
522
|
+
} catch (_planErr) { /* best-effort */ }
|
|
523
|
+
}
|
|
524
|
+
if (totalMustHaves > 0) {
|
|
525
|
+
warnings.push(`VERIFICATION.md has must_haves_checked: 0 but phase has ${totalMustHaves} must-haves in PLAN files. Run /pbr:verify-work to check them.`);
|
|
526
|
+
}
|
|
527
|
+
} catch (_dirErr) { /* best-effort — phase dir may not exist */ }
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Body section validation — check that required template sections exist
|
|
533
|
+
// Advisory only (warnings) since verifier output may vary
|
|
534
|
+
const secondDash = content.indexOf('---', 3);
|
|
535
|
+
if (secondDash !== -1) {
|
|
536
|
+
const body = content.substring(secondDash + 3);
|
|
537
|
+
const hasObservableTruths = /^##\s+Observable Truths/m.test(body);
|
|
538
|
+
const hasMustHaveVerification = /^##\s+Must-Have Verification/m.test(body);
|
|
539
|
+
const hasArtifactVerification = /^##\s+Artifact Verification/m.test(body);
|
|
540
|
+
const hasSummary = /^##\s+Summary/m.test(body);
|
|
541
|
+
|
|
542
|
+
if (!hasObservableTruths && !hasMustHaveVerification && !hasArtifactVerification) {
|
|
543
|
+
warnings.push('Body missing required section: "## Observable Truths", "## Must-Have Verification", or "## Artifact Verification" (see VERIFICATION template)');
|
|
544
|
+
}
|
|
545
|
+
if (!hasSummary) {
|
|
546
|
+
warnings.push('Body missing required section: "## Summary" (see VERIFICATION template)');
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// If status is gaps_found, check for a Gaps section
|
|
550
|
+
const fmEnd = content.indexOf('---', 3);
|
|
551
|
+
if (fmEnd !== -1) {
|
|
552
|
+
const fm = content.substring(3, fmEnd);
|
|
553
|
+
const statusMatch = fm.match(/^status:\s*["']?([^"'\r\n]+)["']?\s*$/m);
|
|
554
|
+
if (statusMatch && statusMatch[1].trim() === 'gaps_found') {
|
|
555
|
+
const hasGapsSection = /^##\s+(Gaps|Critical Gaps|Gap \d)/m.test(body);
|
|
556
|
+
if (!hasGapsSection) {
|
|
557
|
+
warnings.push('Status is "gaps_found" but body missing "## Gaps", "## Critical Gaps", or "## Gap N" section');
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
return { errors, warnings };
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// ---------------------------------------------------------------------------
|
|
567
|
+
// checkStateWrite (dispatcher entry point)
|
|
568
|
+
// ---------------------------------------------------------------------------
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Separate STATE.md validation for use by dispatchers.
|
|
572
|
+
* Kept separate from checkPlanWrite because STATE.md routing in the
|
|
573
|
+
* dispatcher must happen AFTER roadmap sync.
|
|
574
|
+
*/
|
|
575
|
+
function checkStateWrite(data) {
|
|
576
|
+
const filePath = data.tool_input?.file_path || data.tool_input?.path || '';
|
|
577
|
+
const basename = path.basename(filePath);
|
|
578
|
+
if (basename !== 'STATE.md') return null;
|
|
579
|
+
if (!fs.existsSync(filePath)) return null;
|
|
580
|
+
|
|
581
|
+
let content = fs.readFileSync(filePath, 'utf8');
|
|
582
|
+
const result = validateState(content, filePath);
|
|
583
|
+
|
|
584
|
+
// Auto-fix frontmatter/body drift
|
|
585
|
+
const bodyFixed = syncStateBody(content, filePath);
|
|
586
|
+
if (bodyFixed) {
|
|
587
|
+
content = bodyFixed.content;
|
|
588
|
+
result.warnings.push(bodyFixed.message);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Line count advisory
|
|
592
|
+
const lineCount = content.split('\n').length;
|
|
593
|
+
if (lineCount > 100) {
|
|
594
|
+
result.warnings.push(`Advisory: STATE.md exceeds 100-line cap (${lineCount} lines). Move history entries older than the current milestone to PROJECT.md or archive.`);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if (result.warnings.length > 0) {
|
|
598
|
+
logHook('check-plan-format', 'PostToolUse', 'warn', { file: basename, warnings: result.warnings });
|
|
599
|
+
logEvent('workflow', 'state-validated', { file: basename, status: 'warn', warningCount: result.warnings.length });
|
|
600
|
+
return { output: { additionalContext: `${basename} warnings:\n${result.warnings.map(i => ` - ${i}`).join('\n')}` } };
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
logHook('check-plan-format', 'PostToolUse', 'pass', { file: basename });
|
|
604
|
+
logEvent('workflow', 'state-validated', { file: basename, status: 'pass' });
|
|
605
|
+
return null;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// ---------------------------------------------------------------------------
|
|
609
|
+
// syncStateBody
|
|
610
|
+
// ---------------------------------------------------------------------------
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Detect and fix frontmatter/body drift in STATE.md.
|
|
614
|
+
*
|
|
615
|
+
* @param {string} content - Full STATE.md content
|
|
616
|
+
* @param {string} filePath - Absolute path to STATE.md
|
|
617
|
+
* @returns {null|{content: string, message: string}} null if in sync, otherwise the fixed content + message
|
|
618
|
+
*/
|
|
619
|
+
function syncStateBody(content, filePath) {
|
|
620
|
+
if (!content.startsWith('---')) return null;
|
|
621
|
+
const fmEnd = content.indexOf('---', 3);
|
|
622
|
+
if (fmEnd === -1) return null;
|
|
623
|
+
|
|
624
|
+
const fm = content.substring(3, fmEnd);
|
|
625
|
+
const fmPhaseMatch = fm.match(/^current_phase:\s*(\d+)/m);
|
|
626
|
+
const fmSlugMatch = fm.match(/^phase_slug:\s*"?([^"\r\n]+)"?/m);
|
|
627
|
+
const fmNameMatch = fm.match(/^phase_name:\s*"?([^"\r\n]+)"?/m);
|
|
628
|
+
const fmStatusMatch = fm.match(/^status:\s*"?([^"\r\n]+)"?/m);
|
|
629
|
+
const fmPlansMatch = fm.match(/^plans_complete:\s*(\d+)/m);
|
|
630
|
+
const fmProgressMatch = fm.match(/^progress_percent:\s*(\d+)/m);
|
|
631
|
+
const fmActivityMatch = fm.match(/^last_activity:\s*"?([^"\r\n]+)"?/m);
|
|
632
|
+
|
|
633
|
+
if (!fmPhaseMatch) return null;
|
|
634
|
+
|
|
635
|
+
const fmPhase = fmPhaseMatch[1];
|
|
636
|
+
const fmName = fmSlugMatch ? fmSlugMatch[1] : (fmNameMatch ? fmNameMatch[1] : null);
|
|
637
|
+
const fmStatus = fmStatusMatch ? fmStatusMatch[1] : null;
|
|
638
|
+
const fmPlans = fmPlansMatch ? fmPlansMatch[1] : null;
|
|
639
|
+
const fmProgress = fmProgressMatch ? parseInt(fmProgressMatch[1], 10) : null;
|
|
640
|
+
const fmActivity = fmActivityMatch ? fmActivityMatch[1] : null;
|
|
641
|
+
|
|
642
|
+
const bodyPhaseMatch = content.match(/^Phase:\s*(\d+)\s*of\s*(\d+)/m);
|
|
643
|
+
const bodyStatusMatch = content.match(/^Status:\s*(.+)/m);
|
|
644
|
+
const bodyPlansMatch = content.match(/^Plan:\s*(\d+)\s+of\s+(\d+)/m);
|
|
645
|
+
const bodyProgressMatch = content.match(/^Progress:\s*.*?(\d+)%/m);
|
|
646
|
+
const bodyActivityMatch = content.match(/^Last activity:\s*(.+)/im);
|
|
647
|
+
|
|
648
|
+
const drifts = [];
|
|
649
|
+
let updated = content;
|
|
650
|
+
|
|
651
|
+
// Fix phase line drift
|
|
652
|
+
if (bodyPhaseMatch && bodyPhaseMatch[1] !== fmPhase) {
|
|
653
|
+
const bodyTotal = bodyPhaseMatch[2];
|
|
654
|
+
const newPhaseLine = bodyTotal
|
|
655
|
+
? (fmName ? `Phase: ${fmPhase} of ${bodyTotal} (${fmName})` : `Phase: ${fmPhase} of ${bodyTotal}`)
|
|
656
|
+
: `Phase: ${fmPhase}`;
|
|
657
|
+
updated = updated.replace(/^Phase:\s*\d+\s*of\s*\d+.*/m, newPhaseLine);
|
|
658
|
+
drifts.push(`phase ${bodyPhaseMatch[1]}→${fmPhase}`);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// Fix status drift
|
|
662
|
+
if (fmStatus && bodyStatusMatch) {
|
|
663
|
+
const displayStatus = fmStatus.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
|
|
664
|
+
const bodyStatus = bodyStatusMatch[1].trim();
|
|
665
|
+
if (bodyStatus.toLowerCase() !== displayStatus.toLowerCase()) {
|
|
666
|
+
updated = updated.replace(/^Status:\s*.+/m, `Status: ${displayStatus}`);
|
|
667
|
+
drifts.push(`status ${bodyStatus}→${displayStatus}`);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// Fix plans_complete drift
|
|
672
|
+
if (fmPlans !== null && bodyPlansMatch && bodyPlansMatch[1] !== fmPlans) {
|
|
673
|
+
updated = updated.replace(/^(Plan:\s*)\d+/m, `$1${fmPlans}`);
|
|
674
|
+
drifts.push(`plans ${bodyPlansMatch[1]}→${fmPlans}`);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
// Fix progress_percent drift
|
|
678
|
+
if (fmProgress !== null && bodyProgressMatch) {
|
|
679
|
+
const bodyPct = parseInt(bodyProgressMatch[1], 10);
|
|
680
|
+
if (bodyPct !== fmProgress) {
|
|
681
|
+
const { buildProgressBar } = require('./state');
|
|
682
|
+
updated = updated.replace(/^Progress:\s*.+/m, `Progress: ${buildProgressBar(fmProgress)}`);
|
|
683
|
+
drifts.push(`progress ${bodyPct}%→${fmProgress}%`);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// Fix last_activity drift
|
|
688
|
+
if (fmActivity && bodyActivityMatch) {
|
|
689
|
+
const bodyActivity = bodyActivityMatch[1].trim();
|
|
690
|
+
if (bodyActivity !== fmActivity && !bodyActivity.startsWith(fmActivity)) {
|
|
691
|
+
updated = updated.replace(/^(Last activity:\s*).+/im, `$1${fmActivity}`);
|
|
692
|
+
drifts.push('last_activity');
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
if (drifts.length === 0) return null;
|
|
697
|
+
|
|
698
|
+
try {
|
|
699
|
+
lockedFileUpdate(filePath, () => updated);
|
|
700
|
+
logHook('check-plan-format', 'PostToolUse', 'body-sync', { drifts });
|
|
701
|
+
return {
|
|
702
|
+
content: updated,
|
|
703
|
+
message: `Auto-fixed body drift: ${drifts.join(', ')} (body now matches frontmatter)`
|
|
704
|
+
};
|
|
705
|
+
} catch (_e) {
|
|
706
|
+
return null;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// ---------------------------------------------------------------------------
|
|
711
|
+
// ROADMAP validation
|
|
712
|
+
// ---------------------------------------------------------------------------
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Validate ROADMAP.md structure.
|
|
716
|
+
*
|
|
717
|
+
* @param {string} content - Full ROADMAP.md content
|
|
718
|
+
* @param {string} _filePath - File path (unused)
|
|
719
|
+
* @returns {{ errors: string[], warnings: string[] }}
|
|
720
|
+
*/
|
|
721
|
+
function validateRoadmap(content, _filePath) {
|
|
722
|
+
const errors = [];
|
|
723
|
+
const warnings = [];
|
|
724
|
+
|
|
725
|
+
if (!/^#\s+(Roadmap|ROADMAP|Project Roadmap)(:\s*.+)?$/m.test(content)) {
|
|
726
|
+
errors.push('Missing "# Roadmap" heading');
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// Strip <details>/<summary> HTML tags
|
|
730
|
+
const strippedContent = content
|
|
731
|
+
.replace(/<\/?details>/gi, '')
|
|
732
|
+
.replace(/<\/?summary>/gi, '');
|
|
733
|
+
|
|
734
|
+
const milestoneMatches = strippedContent.match(/^##\s+Milestone:/gm);
|
|
735
|
+
if (!milestoneMatches || milestoneMatches.length === 0) {
|
|
736
|
+
errors.push('No "## Milestone:" sections found');
|
|
737
|
+
} else {
|
|
738
|
+
const milestoneBlocks = strippedContent.split(/^##\s+Milestone:/m).slice(1);
|
|
739
|
+
milestoneBlocks.forEach((block, idx) => {
|
|
740
|
+
const headingLine = block.split('\n')[0] || '';
|
|
741
|
+
|
|
742
|
+
// Skip all structural checks for completed milestones (collapsed format)
|
|
743
|
+
if (/--\s*COMPLETED/i.test(headingLine)) return;
|
|
744
|
+
|
|
745
|
+
if (!/\*\*Phases:\*\*/.test(block)) {
|
|
746
|
+
warnings.push(`Milestone ${idx + 1}: missing "**Phases:**" line`);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
if (!/###\s+Phase Checklist/.test(block) && !/- \[[ x]\] Phase/i.test(block)) {
|
|
750
|
+
warnings.push(`Milestone ${idx + 1}: missing Phase Checklist (expected "- [ ] Phase NN:" format)`);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
if (!/\*\*Requirement coverage:\*\*/.test(block)) {
|
|
754
|
+
warnings.push(`Milestone ${idx + 1}: missing "**Requirement coverage:**" line`);
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// Check each ### Phase NN: (only in active milestones)
|
|
760
|
+
// Extract content from active milestones only (skip COMPLETED blocks)
|
|
761
|
+
const activeMilestoneContent = strippedContent.split(/^##\s+Milestone:/m).slice(1)
|
|
762
|
+
.filter(block => {
|
|
763
|
+
const headingLine = block.split('\n')[0] || '';
|
|
764
|
+
return !/--\s*COMPLETED/i.test(headingLine);
|
|
765
|
+
})
|
|
766
|
+
.join('\n');
|
|
767
|
+
|
|
768
|
+
const phaseRegex = /^###\s+Phase\s+\d+:/gm;
|
|
769
|
+
const phaseMatches = activeMilestoneContent.match(phaseRegex);
|
|
770
|
+
|
|
771
|
+
// Check for sequential phase numbering (advisory)
|
|
772
|
+
if (phaseMatches && phaseMatches.length > 1) {
|
|
773
|
+
const phaseNums = phaseMatches
|
|
774
|
+
.map(m => parseInt(m.match(/\d+/)[0], 10))
|
|
775
|
+
.sort((a, b) => a - b);
|
|
776
|
+
// Check first phase starts at 1
|
|
777
|
+
if (phaseNums[0] > 1) {
|
|
778
|
+
warnings.push(`Phase numbering starts at ${phaseNums[0]} instead of 1 — phases should be numbered sequentially from 1`);
|
|
779
|
+
}
|
|
780
|
+
// Check for gaps
|
|
781
|
+
for (let i = 1; i < phaseNums.length; i++) {
|
|
782
|
+
if (phaseNums[i] !== phaseNums[i - 1] + 1) {
|
|
783
|
+
warnings.push(`Gap in phase numbering: Phase ${phaseNums[i - 1]} → Phase ${phaseNums[i]} (expected ${phaseNums[i - 1] + 1})`);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
if (phaseMatches) {
|
|
789
|
+
const phaseBlocks = activeMilestoneContent.split(/^###\s+Phase\s+\d+:/m).slice(1);
|
|
790
|
+
phaseBlocks.forEach((block, idx) => {
|
|
791
|
+
const nextHeading = block.search(/^#{2,3}\s+/m);
|
|
792
|
+
const section = nextHeading !== -1 ? block.substring(0, nextHeading) : block;
|
|
793
|
+
|
|
794
|
+
if (!/\*\*Goal:\*\*/.test(section)) {
|
|
795
|
+
warnings.push(`Phase ${idx + 1}: missing "**Goal:**"`);
|
|
796
|
+
}
|
|
797
|
+
if (!/\*\*Provides:\*\*/.test(section)) {
|
|
798
|
+
warnings.push(`Phase ${idx + 1}: missing "**Provides:**"`);
|
|
799
|
+
}
|
|
800
|
+
if (!/\*\*Depends on:\*\*/.test(section)) {
|
|
801
|
+
warnings.push(`Phase ${idx + 1}: missing "**Depends on:**"`);
|
|
802
|
+
}
|
|
803
|
+
if (!/\*\*Requirements:\*\*/.test(section)) {
|
|
804
|
+
warnings.push(`Phase ${idx + 1}: missing "**Requirements:**" (recommended for GSD alignment)`);
|
|
805
|
+
}
|
|
806
|
+
if (!/\*\*Success Criteria:\*\*/.test(section)) {
|
|
807
|
+
warnings.push(`Phase ${idx + 1}: missing "**Success Criteria:**" (recommended for GSD alignment)`);
|
|
808
|
+
}
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// Check Progress table syntax
|
|
813
|
+
const progressMatch = strippedContent.match(/^##\s+Progress/m);
|
|
814
|
+
if (progressMatch) {
|
|
815
|
+
const afterProgress = strippedContent.substring(progressMatch.index);
|
|
816
|
+
const headerLine = afterProgress.split('\n').find(l => l.includes('|') && /Plans?\s*Complete/i.test(l));
|
|
817
|
+
if (headerLine) {
|
|
818
|
+
const lines = afterProgress.split('\n');
|
|
819
|
+
const headerIdx = lines.findIndex(l => l.includes('|') && /Plans?\s*Complete/i.test(l));
|
|
820
|
+
if (headerIdx >= 0 && headerIdx + 1 < lines.length) {
|
|
821
|
+
const sepLine = lines[headerIdx + 1];
|
|
822
|
+
if (!/^\s*\|[\s-:|]+\|\s*$/.test(sepLine)) {
|
|
823
|
+
warnings.push('Progress table: missing or malformed separator row (expected |---|---|...)');
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
} else {
|
|
827
|
+
warnings.push('Progress table: header row with "Plans Complete" column not found');
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
return { errors, warnings };
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// ---------------------------------------------------------------------------
|
|
835
|
+
// LEARNINGS validation
|
|
836
|
+
// ---------------------------------------------------------------------------
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* Validate LEARNINGS.md structure.
|
|
840
|
+
* DEPRECATED: Per-phase LEARNINGS.md is deprecated in favor of .planning/KNOWLEDGE.md.
|
|
841
|
+
*/
|
|
842
|
+
function validateLearnings(content, _filePath) {
|
|
843
|
+
const errors = [];
|
|
844
|
+
const warnings = [];
|
|
845
|
+
|
|
846
|
+
warnings.push('Per-phase LEARNINGS.md is deprecated. Use project-scoped .planning/KNOWLEDGE.md instead.');
|
|
847
|
+
|
|
848
|
+
if (!content.startsWith('---')) {
|
|
849
|
+
warnings.push('Missing YAML frontmatter (recommended: phase, key_insights, patterns)');
|
|
850
|
+
return { errors, warnings };
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
const frontmatterEnd = content.indexOf('---', 3);
|
|
854
|
+
if (frontmatterEnd === -1) {
|
|
855
|
+
warnings.push('Unclosed YAML frontmatter');
|
|
856
|
+
return { errors, warnings };
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
const frontmatter = content.substring(3, frontmatterEnd);
|
|
860
|
+
|
|
861
|
+
if (!frontmatter.includes('phase:')) {
|
|
862
|
+
warnings.push('Frontmatter missing "phase" field');
|
|
863
|
+
}
|
|
864
|
+
if (!frontmatter.includes('key_insights:')) {
|
|
865
|
+
warnings.push('Frontmatter missing "key_insights" field');
|
|
866
|
+
}
|
|
867
|
+
if (!frontmatter.includes('patterns:')) {
|
|
868
|
+
warnings.push('Frontmatter missing "patterns" field');
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
const crossProjectMatch = frontmatter.match(/cross_project:\s*(.+)/);
|
|
872
|
+
if (crossProjectMatch) {
|
|
873
|
+
const value = crossProjectMatch[1].trim();
|
|
874
|
+
if (value !== 'true' && value !== 'false') {
|
|
875
|
+
warnings.push('cross_project field should be "true" or "false"');
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
return { errors, warnings };
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// ---------------------------------------------------------------------------
|
|
883
|
+
// Config validation
|
|
884
|
+
// ---------------------------------------------------------------------------
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* Validate .planning/config.json structure.
|
|
888
|
+
*/
|
|
889
|
+
function validateConfig(content, _filePath) {
|
|
890
|
+
const errors = [];
|
|
891
|
+
const warnings = [];
|
|
892
|
+
|
|
893
|
+
let parsed;
|
|
894
|
+
try {
|
|
895
|
+
parsed = JSON.parse(content);
|
|
896
|
+
} catch (e) {
|
|
897
|
+
errors.push(`Invalid JSON: ${e.message}`);
|
|
898
|
+
return { errors, warnings };
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
902
|
+
errors.push('config.json must be a JSON object (not array or primitive)');
|
|
903
|
+
return { errors, warnings };
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
if (parsed.depth !== undefined) {
|
|
907
|
+
if (!['quick', 'standard', 'comprehensive'].includes(parsed.depth)) {
|
|
908
|
+
warnings.push(`Unexpected depth value: "${parsed.depth}" (expected: quick, standard, or comprehensive)`);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
const knownKeys = ['version', 'schema_version', 'context_strategy', 'mode', 'depth', 'session_phase_limit', 'session_cycling', 'context_window_tokens', 'agent_checkpoint_pct', 'features', 'autonomy', 'models', 'model_profiles', 'parallelization', 'teams', 'planning', 'git', 'gates', 'safety', 'timeouts', 'hooks', 'prd', 'depth_profiles', 'debug', 'developer_profile', 'spinner_tips', 'dashboard', 'status_line', 'workflow', 'hook_server', 'intel', 'context_ledger', 'learnings', 'verification', 'context_budget', 'ui', 'worktree', 'ceremony_level', 'skip_rag_max_lines', 'orchestrator_budget_pct'];
|
|
913
|
+
for (const key of Object.keys(parsed)) {
|
|
914
|
+
if (!knownKeys.includes(key)) {
|
|
915
|
+
warnings.push(`Unknown top-level key: "${key}" (known: ${knownKeys.join(', ')})`);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
return { errors, warnings };
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// ---------------------------------------------------------------------------
|
|
923
|
+
// RESEARCH validation
|
|
924
|
+
// ---------------------------------------------------------------------------
|
|
925
|
+
|
|
926
|
+
/**
|
|
927
|
+
* Validate RESEARCH.md structure.
|
|
928
|
+
*/
|
|
929
|
+
function validateResearch(content, _filePath) {
|
|
930
|
+
const errors = [];
|
|
931
|
+
const warnings = [];
|
|
932
|
+
|
|
933
|
+
if (!content.startsWith('---')) {
|
|
934
|
+
errors.push('Missing YAML frontmatter (required: confidence, sources_checked)');
|
|
935
|
+
return { errors, warnings };
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
const frontmatterEnd = content.indexOf('---', 3);
|
|
939
|
+
if (frontmatterEnd === -1) {
|
|
940
|
+
errors.push('Unclosed YAML frontmatter');
|
|
941
|
+
return { errors, warnings };
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
const frontmatter = content.substring(3, frontmatterEnd);
|
|
945
|
+
|
|
946
|
+
if (!/confidence\s*:/i.test(frontmatter)) {
|
|
947
|
+
errors.push('Frontmatter missing "confidence" field (expected: high, medium, or low)');
|
|
948
|
+
}
|
|
949
|
+
if (!/sources_checked\s*:/i.test(frontmatter)) {
|
|
950
|
+
errors.push('Frontmatter missing "sources_checked" field');
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
if (!frontmatter.includes('phase:')) {
|
|
954
|
+
warnings.push('Frontmatter missing "phase" field — recommended for phase-level research');
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
return { errors, warnings };
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
// ---------------------------------------------------------------------------
|
|
961
|
+
// CONTEXT validation
|
|
962
|
+
// ---------------------------------------------------------------------------
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* Validate CONTEXT.md structure.
|
|
966
|
+
*/
|
|
967
|
+
function validateContext(content, _filePath) {
|
|
968
|
+
const errors = [];
|
|
969
|
+
const warnings = [];
|
|
970
|
+
|
|
971
|
+
if (!content || content.trim().length === 0) {
|
|
972
|
+
errors.push('CONTEXT.md is empty — expected frontmatter and section content');
|
|
973
|
+
return { errors, warnings };
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
if (!/<domain>/i.test(content) && !/^##\s+Domain/mi.test(content)) {
|
|
977
|
+
warnings.push('Missing <domain> section (or ## Domain heading) — recommended for phase context');
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
if (!/<decisions>/i.test(content) && !/^##\s+(Locked\s+)?Decisions/mi.test(content)) {
|
|
981
|
+
warnings.push('Missing <decisions> section (or ## Decisions heading) — recommended for locked decisions');
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
if (!/<canonical_refs>/i.test(content) && !/^##\s+Canonical\s+Ref/mi.test(content)) {
|
|
985
|
+
warnings.push('Missing <canonical_refs> section (or ## Canonical References heading) — recommended for reference docs');
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
if (!/<deferred>/i.test(content) && !/^##\s+Deferred/mi.test(content)) {
|
|
989
|
+
warnings.push('Missing <deferred> section (or ## Deferred heading) — recommended for excluded scope');
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
if (!/<specifics>/i.test(content) && !/^##\s+Specific\s+Ref/mi.test(content)) {
|
|
993
|
+
warnings.push('Missing <specifics> section (or ## Specific References heading) — recommended for GSD alignment');
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
if (!/<code_context>/i.test(content) && !/^##\s+Code\s+(Patterns?|Context)/mi.test(content)) {
|
|
997
|
+
warnings.push('Missing <code_context> section (or ## Code Patterns heading) — recommended for GSD alignment');
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
return { errors, warnings };
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
// ---------------------------------------------------------------------------
|
|
1004
|
+
// Exports
|
|
1005
|
+
// ---------------------------------------------------------------------------
|
|
1006
|
+
|
|
1007
|
+
module.exports = {
|
|
1008
|
+
validateMustHaves,
|
|
1009
|
+
PLAN_REQUIRED_FIELDS,
|
|
1010
|
+
PLAN_VALID_TYPES,
|
|
1011
|
+
validatePlan,
|
|
1012
|
+
validateSummary,
|
|
1013
|
+
validateDeviationsField,
|
|
1014
|
+
checkPlanWrite,
|
|
1015
|
+
VALID_STATE_STATUSES,
|
|
1016
|
+
validateState,
|
|
1017
|
+
validateVerification,
|
|
1018
|
+
checkStateWrite,
|
|
1019
|
+
syncStateBody,
|
|
1020
|
+
validateRoadmap,
|
|
1021
|
+
validateLearnings,
|
|
1022
|
+
validateConfig,
|
|
1023
|
+
validateResearch,
|
|
1024
|
+
validateContext
|
|
1025
|
+
};
|