@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,1175 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Workflow Compliance Check Module
|
|
5
|
+
*
|
|
6
|
+
* Implements WC-02, WC-03, WC-04, WC-05, WC-06, WC-08, WC-09, WC-12
|
|
7
|
+
* workflow compliance dimensions for the PBR audit system. Each check
|
|
8
|
+
* returns a structured result: { dimension, status, message, evidence }.
|
|
9
|
+
*
|
|
10
|
+
* Checks:
|
|
11
|
+
* WC-01: CI verification after push (gh run list/view/watch after git push)
|
|
12
|
+
* WC-02: State file integrity (STATE.md matches disk)
|
|
13
|
+
* WC-03: STATE.md frontmatter integrity (valid YAML, required fields)
|
|
14
|
+
* WC-04: ROADMAP sync validation (ROADMAP.md matches phase directories)
|
|
15
|
+
* WC-05: Planning artifact completeness (SUMMARY + VERIFICATION)
|
|
16
|
+
* WC-06: Artifact format validation (required fields, task blocks)
|
|
17
|
+
* WC-07: Compaction quality (STATE.md preservation after compact events)
|
|
18
|
+
* WC-08: Naming convention compliance (PLAN-{NN}.md format)
|
|
19
|
+
* WC-09: Commit pattern validation (heredoc, --no-verify detection)
|
|
20
|
+
* WC-10: Model selection compliance (agent model vs config.models)
|
|
21
|
+
* WC-11: Git branching compliance (phase branches when git.branching=phase)
|
|
22
|
+
* WC-12: Test health baseline comparison
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const fs = require('fs');
|
|
26
|
+
const path = require('path');
|
|
27
|
+
const { execSync } = require('child_process');
|
|
28
|
+
const { extractFrontmatter } = require('../lib/frontmatter');
|
|
29
|
+
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Result helper
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Build a structured check result.
|
|
36
|
+
* @param {string} dimCode - Dimension code (e.g. "WC-02")
|
|
37
|
+
* @param {'pass'|'warn'|'fail'} status
|
|
38
|
+
* @param {string} message
|
|
39
|
+
* @param {string[]} [evidence]
|
|
40
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
41
|
+
*/
|
|
42
|
+
function result(dimCode, status, message, evidence) {
|
|
43
|
+
return {
|
|
44
|
+
dimension: dimCode,
|
|
45
|
+
status,
|
|
46
|
+
message,
|
|
47
|
+
evidence: evidence || [],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
// Session log helper (shared by WC-01, WC-07, WC-09, WC-10)
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Find session JSONL log files for the current project.
|
|
57
|
+
* Returns an array of absolute paths to the most recent log files.
|
|
58
|
+
* @param {string} planningDir - Path to .planning/ directory
|
|
59
|
+
* @param {number} [maxFiles=5] - Maximum number of log files to return
|
|
60
|
+
* @returns {string[]}
|
|
61
|
+
*/
|
|
62
|
+
function findSessionLogs(planningDir, maxFiles) {
|
|
63
|
+
if (maxFiles === undefined) maxFiles = 5;
|
|
64
|
+
const projectRoot = path.resolve(planningDir, '..');
|
|
65
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || '';
|
|
66
|
+
const encodedPath = projectRoot.replace(/[/\\:]/g, '-').replace(/^-+/, '');
|
|
67
|
+
const claudeProjectsDir = path.join(homeDir, '.claude', 'projects');
|
|
68
|
+
const sessionLogs = [];
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
const projectDirs = fs.readdirSync(claudeProjectsDir);
|
|
72
|
+
for (const dir of projectDirs) {
|
|
73
|
+
if (encodedPath.includes(dir) || dir.includes('plan-build-run')) {
|
|
74
|
+
const fullDir = path.join(claudeProjectsDir, dir);
|
|
75
|
+
try {
|
|
76
|
+
const stat = fs.statSync(fullDir);
|
|
77
|
+
if (!stat.isDirectory()) continue;
|
|
78
|
+
const files = fs.readdirSync(fullDir);
|
|
79
|
+
const jsonlFiles = files.filter(f => f.endsWith('.jsonl'));
|
|
80
|
+
const paths = jsonlFiles
|
|
81
|
+
.sort()
|
|
82
|
+
.slice(-maxFiles)
|
|
83
|
+
.map(f => path.join(fullDir, f));
|
|
84
|
+
sessionLogs.push(...paths);
|
|
85
|
+
} catch (_e) {
|
|
86
|
+
// skip
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} catch (_e) {
|
|
91
|
+
// No session logs directory
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return sessionLogs;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Parse session JSONL entries from a list of log files.
|
|
99
|
+
* Returns an array of parsed JSON objects.
|
|
100
|
+
* @param {string[]} logFiles
|
|
101
|
+
* @returns {object[]}
|
|
102
|
+
*/
|
|
103
|
+
function parseSessionEntries(logFiles) {
|
|
104
|
+
const entries = [];
|
|
105
|
+
for (const logFile of logFiles) {
|
|
106
|
+
try {
|
|
107
|
+
const content = fs.readFileSync(logFile, 'utf8');
|
|
108
|
+
const lines = content.split('\n').filter(l => l.trim());
|
|
109
|
+
for (const line of lines) {
|
|
110
|
+
try {
|
|
111
|
+
entries.push(JSON.parse(line));
|
|
112
|
+
} catch (_e) {
|
|
113
|
+
// skip malformed lines
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
} catch (_e) {
|
|
117
|
+
// skip unreadable files
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return entries;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
// WC-01: CI Verification After Push
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Detect git push commands not followed by CI verification (gh run list/view/watch).
|
|
129
|
+
* Scans session JSONL logs for Bash tool_use entries.
|
|
130
|
+
*
|
|
131
|
+
* @param {string} planningDir - Path to .planning/ directory
|
|
132
|
+
* @param {object} _config - Parsed config.json (unused)
|
|
133
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
134
|
+
*/
|
|
135
|
+
function checkCiVerifyAfterPush(planningDir, _config) {
|
|
136
|
+
const logFiles = findSessionLogs(planningDir);
|
|
137
|
+
|
|
138
|
+
if (logFiles.length === 0) {
|
|
139
|
+
return result('WC-01', 'pass', 'No session logs available');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const entries = parseSessionEntries(logFiles);
|
|
143
|
+
const evidence = [];
|
|
144
|
+
|
|
145
|
+
// Find all Bash tool_use entries and index them
|
|
146
|
+
const bashEntries = [];
|
|
147
|
+
for (let i = 0; i < entries.length; i++) {
|
|
148
|
+
const entry = entries[i];
|
|
149
|
+
const command = entry.command ||
|
|
150
|
+
(entry.input && entry.input.command ? entry.input.command : '');
|
|
151
|
+
if (command && (entry.type === 'tool_use' || entry.type === 'assistant')) {
|
|
152
|
+
bashEntries.push({ index: i, command });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// For each git push, look for CI check in next 10 tool calls
|
|
157
|
+
for (let b = 0; b < bashEntries.length; b++) {
|
|
158
|
+
const { command } = bashEntries[b];
|
|
159
|
+
if (!command.includes('git push')) continue;
|
|
160
|
+
|
|
161
|
+
let foundCiCheck = false;
|
|
162
|
+
const lookAhead = Math.min(b + 10, bashEntries.length);
|
|
163
|
+
for (let j = b + 1; j < lookAhead; j++) {
|
|
164
|
+
const nextCmd = bashEntries[j].command;
|
|
165
|
+
if (/gh\s+run\s+(list|view|watch)/.test(nextCmd)) {
|
|
166
|
+
foundCiCheck = true;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (!foundCiCheck) {
|
|
172
|
+
const snippet = command.substring(0, 120);
|
|
173
|
+
evidence.push(`git push at entry ${bashEntries[b].index} not followed by CI check: "${snippet}"`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (evidence.length === 0) {
|
|
178
|
+
return result('WC-01', 'pass', 'All git pushes followed by CI verification');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return result('WC-01', 'warn',
|
|
182
|
+
`${evidence.length} git push(es) without CI verification`,
|
|
183
|
+
evidence
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// ---------------------------------------------------------------------------
|
|
188
|
+
// WC-07: Compaction Quality
|
|
189
|
+
// ---------------------------------------------------------------------------
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Detect STATE.md content loss after compaction events.
|
|
193
|
+
* Scans session JSONL for compact events and checks STATE.md integrity.
|
|
194
|
+
*
|
|
195
|
+
* @param {string} planningDir - Path to .planning/ directory
|
|
196
|
+
* @param {object} _config - Parsed config.json (unused)
|
|
197
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
198
|
+
*/
|
|
199
|
+
function checkCompactionQuality(planningDir, _config) {
|
|
200
|
+
const logFiles = findSessionLogs(planningDir);
|
|
201
|
+
|
|
202
|
+
if (logFiles.length === 0) {
|
|
203
|
+
return result('WC-07', 'pass', 'No session logs available');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const entries = parseSessionEntries(logFiles);
|
|
207
|
+
const evidence = [];
|
|
208
|
+
|
|
209
|
+
// Find compact events
|
|
210
|
+
const compactIndices = [];
|
|
211
|
+
for (let i = 0; i < entries.length; i++) {
|
|
212
|
+
const entry = entries[i];
|
|
213
|
+
const toolName = entry.tool || entry.name ||
|
|
214
|
+
(entry.input && entry.input.tool ? entry.input.tool : '');
|
|
215
|
+
const content = typeof entry.content === 'string' ? entry.content : '';
|
|
216
|
+
|
|
217
|
+
if (toolName === 'Compact' ||
|
|
218
|
+
(entry.type === 'tool_use' && content.includes('compact')) ||
|
|
219
|
+
(entry.type === 'system' && content.includes('compact'))) {
|
|
220
|
+
compactIndices.push(i);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (compactIndices.length === 0) {
|
|
225
|
+
return result('WC-07', 'pass', 'No compaction events detected in session');
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// For each compact event, check if STATE.md is read/written after it
|
|
229
|
+
for (const ci of compactIndices) {
|
|
230
|
+
let statePreserved = false;
|
|
231
|
+
const lookAhead = Math.min(ci + 15, entries.length);
|
|
232
|
+
for (let j = ci + 1; j < lookAhead; j++) {
|
|
233
|
+
const entry = entries[j];
|
|
234
|
+
const filePath = entry.file_path ||
|
|
235
|
+
(entry.input && entry.input.file_path ? entry.input.file_path : '') ||
|
|
236
|
+
(typeof entry.content === 'string' ? entry.content : '');
|
|
237
|
+
if (filePath.includes('STATE.md')) {
|
|
238
|
+
statePreserved = true;
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (!statePreserved) {
|
|
244
|
+
evidence.push(`Compact event at entry ${ci} — no STATE.md read/write detected within next 15 entries`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Also check STATE.md itself for missing fields (sign of content loss)
|
|
249
|
+
const statePath = path.join(planningDir, 'STATE.md');
|
|
250
|
+
try {
|
|
251
|
+
const stateContent = fs.readFileSync(statePath, 'utf8');
|
|
252
|
+
const fm = extractFrontmatter(stateContent);
|
|
253
|
+
const criticalFields = ['current_phase', 'status', 'last_activity'];
|
|
254
|
+
const missing = criticalFields.filter(f => fm[f] === undefined || fm[f] === '');
|
|
255
|
+
if (missing.length > 0) {
|
|
256
|
+
evidence.push(`STATE.md missing critical fields after compaction: ${missing.join(', ')}`);
|
|
257
|
+
}
|
|
258
|
+
} catch (_e) {
|
|
259
|
+
evidence.push('STATE.md not readable — possible compaction content loss');
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (evidence.length === 0) {
|
|
263
|
+
return result('WC-07', 'pass',
|
|
264
|
+
`${compactIndices.length} compaction event(s) — STATE.md intact`);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return result('WC-07', 'warn',
|
|
268
|
+
`${evidence.length} compaction quality concern(s)`,
|
|
269
|
+
evidence
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// ---------------------------------------------------------------------------
|
|
274
|
+
// WC-02: State File Integrity
|
|
275
|
+
// ---------------------------------------------------------------------------
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Check STATE.md integrity against actual phase directories.
|
|
279
|
+
* Cross-references current_phase, phases_total, and status against disk.
|
|
280
|
+
*
|
|
281
|
+
* @param {string} planningDir - Path to .planning/ directory
|
|
282
|
+
* @param {object} _config - Parsed config.json (unused)
|
|
283
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
284
|
+
*/
|
|
285
|
+
function checkStateFileIntegrity(planningDir, _config) {
|
|
286
|
+
const statePath = path.join(planningDir, 'STATE.md');
|
|
287
|
+
let content;
|
|
288
|
+
|
|
289
|
+
try {
|
|
290
|
+
content = fs.readFileSync(statePath, 'utf8');
|
|
291
|
+
} catch (_e) {
|
|
292
|
+
return result('WC-02', 'fail', 'STATE.md not found', [
|
|
293
|
+
`Expected at: ${statePath}`,
|
|
294
|
+
]);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const fm = extractFrontmatter(content);
|
|
298
|
+
const evidence = [];
|
|
299
|
+
|
|
300
|
+
// Get actual phase directories
|
|
301
|
+
const phasesDir = path.join(planningDir, 'phases');
|
|
302
|
+
let actualDirs = [];
|
|
303
|
+
try {
|
|
304
|
+
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
|
305
|
+
actualDirs = entries
|
|
306
|
+
.filter(e => e.isDirectory() && /^\d{2}-/.test(e.name))
|
|
307
|
+
.map(e => e.name)
|
|
308
|
+
.sort();
|
|
309
|
+
} catch (_e) {
|
|
310
|
+
evidence.push('Could not read phases/ directory');
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const actualCount = actualDirs.length;
|
|
314
|
+
|
|
315
|
+
// Check phases_total against actual directory count
|
|
316
|
+
const phasesTotal = parseInt(fm.phases_total, 10);
|
|
317
|
+
if (!isNaN(phasesTotal) && phasesTotal !== actualCount) {
|
|
318
|
+
evidence.push(
|
|
319
|
+
`phases_total=${phasesTotal} but ${actualCount} phase directories on disk`
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Check current_phase refers to existing directory
|
|
324
|
+
const currentPhase = parseInt(fm.current_phase, 10);
|
|
325
|
+
if (!isNaN(currentPhase)) {
|
|
326
|
+
const prefix = String(currentPhase).padStart(2, '0') + '-';
|
|
327
|
+
const hasDir = actualDirs.some(d => d.startsWith(prefix));
|
|
328
|
+
if (!hasDir && actualDirs.length > 0) {
|
|
329
|
+
evidence.push(
|
|
330
|
+
`current_phase=${currentPhase} but no directory starting with "${prefix}" in phases/`
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// If status is building/built, verify current phase dir has PLAN files
|
|
336
|
+
const status = fm.status;
|
|
337
|
+
if (status === 'building' || status === 'built') {
|
|
338
|
+
const prefix = String(currentPhase).padStart(2, '0') + '-';
|
|
339
|
+
const phaseDir = actualDirs.find(d => d.startsWith(prefix));
|
|
340
|
+
if (phaseDir) {
|
|
341
|
+
const phasePath = path.join(phasesDir, phaseDir);
|
|
342
|
+
try {
|
|
343
|
+
const files = fs.readdirSync(phasePath);
|
|
344
|
+
const planFiles = files.filter(f => /^PLAN.*\.md$/i.test(f));
|
|
345
|
+
if (planFiles.length === 0) {
|
|
346
|
+
evidence.push(
|
|
347
|
+
`Status is "${status}" but phase dir "${phaseDir}" has no PLAN files`
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
} catch (_e) {
|
|
351
|
+
evidence.push(`Could not read phase dir "${phaseDir}"`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (evidence.length === 0) {
|
|
357
|
+
return result('WC-02', 'pass', 'STATE.md aligns with disk state');
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Critical mismatches (missing dirs, wrong phase) = fail; minor = warn
|
|
361
|
+
const hasCritical = evidence.some(
|
|
362
|
+
e => e.includes('not found') || e.includes('no directory')
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
return result(
|
|
366
|
+
'WC-02',
|
|
367
|
+
hasCritical ? 'fail' : 'warn',
|
|
368
|
+
`STATE.md has ${evidence.length} mismatch(es) with disk`,
|
|
369
|
+
evidence
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// ---------------------------------------------------------------------------
|
|
374
|
+
// WC-03: STATE.md Frontmatter Integrity
|
|
375
|
+
// ---------------------------------------------------------------------------
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Validate STATE.md YAML frontmatter for required fields and correct types.
|
|
379
|
+
*
|
|
380
|
+
* @param {string} planningDir - Path to .planning/ directory
|
|
381
|
+
* @param {object} _config - Parsed config.json (unused)
|
|
382
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
383
|
+
*/
|
|
384
|
+
function checkStateFrontmatterIntegrity(planningDir, _config) {
|
|
385
|
+
const statePath = path.join(planningDir, 'STATE.md');
|
|
386
|
+
let content;
|
|
387
|
+
|
|
388
|
+
try {
|
|
389
|
+
content = fs.readFileSync(statePath, 'utf8');
|
|
390
|
+
} catch (_e) {
|
|
391
|
+
return result('WC-03', 'fail', 'STATE.md not found', [
|
|
392
|
+
`Expected at: ${statePath}`,
|
|
393
|
+
]);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const fm = extractFrontmatter(content);
|
|
397
|
+
const evidence = [];
|
|
398
|
+
|
|
399
|
+
// Required fields
|
|
400
|
+
const requiredFields = [
|
|
401
|
+
'version', 'current_phase', 'phase_slug', 'status',
|
|
402
|
+
'phases_total', 'plans_total', 'last_activity',
|
|
403
|
+
];
|
|
404
|
+
|
|
405
|
+
const missingFields = [];
|
|
406
|
+
for (const field of requiredFields) {
|
|
407
|
+
if (fm[field] === undefined || fm[field] === '') {
|
|
408
|
+
missingFields.push(field);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (missingFields.length > 0) {
|
|
413
|
+
evidence.push(`Missing required fields: ${missingFields.join(', ')}`);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Type validations
|
|
417
|
+
const validStatuses = [
|
|
418
|
+
'not_started', 'discussed', 'ready_to_plan', 'planning', 'planned',
|
|
419
|
+
'ready_to_execute', 'building', 'built', 'partial', 'verified',
|
|
420
|
+
'needs_fixes', 'complete', 'skipped',
|
|
421
|
+
];
|
|
422
|
+
|
|
423
|
+
if (fm.version !== undefined) {
|
|
424
|
+
const ver = Number(fm.version);
|
|
425
|
+
if (isNaN(ver)) {
|
|
426
|
+
evidence.push(`version "${fm.version}" is not a number`);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (fm.current_phase !== undefined) {
|
|
431
|
+
const cp = Number(fm.current_phase);
|
|
432
|
+
if (isNaN(cp)) {
|
|
433
|
+
evidence.push(`current_phase "${fm.current_phase}" is not a number`);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (fm.status !== undefined && !validStatuses.includes(fm.status)) {
|
|
438
|
+
evidence.push(
|
|
439
|
+
`status "${fm.status}" is not a valid status (expected one of: ${validStatuses.join(', ')})`
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (fm.phases_total !== undefined) {
|
|
444
|
+
const pt = Number(fm.phases_total);
|
|
445
|
+
if (isNaN(pt)) {
|
|
446
|
+
evidence.push(`phases_total "${fm.phases_total}" is not numeric`);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (fm.plans_total !== undefined) {
|
|
451
|
+
const plt = Number(fm.plans_total);
|
|
452
|
+
if (isNaN(plt)) {
|
|
453
|
+
evidence.push(`plans_total "${fm.plans_total}" is not numeric`);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (evidence.length === 0) {
|
|
458
|
+
return result('WC-03', 'pass', 'STATE.md frontmatter is valid');
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Missing required fields = fail, type issues = warn
|
|
462
|
+
const hasMissing = missingFields.length > 0;
|
|
463
|
+
|
|
464
|
+
return result(
|
|
465
|
+
'WC-03',
|
|
466
|
+
hasMissing ? 'fail' : 'warn',
|
|
467
|
+
`STATE.md frontmatter has ${evidence.length} issue(s)`,
|
|
468
|
+
evidence
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// ---------------------------------------------------------------------------
|
|
473
|
+
// WC-04: ROADMAP Sync Validation
|
|
474
|
+
// ---------------------------------------------------------------------------
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Validate ROADMAP.md phase entries match actual phase directories on disk.
|
|
478
|
+
* Detects orphan directories (on disk but not in ROADMAP) and phantom phases
|
|
479
|
+
* (in ROADMAP but not on disk).
|
|
480
|
+
*
|
|
481
|
+
* @param {string} planningDir - Path to .planning/ directory
|
|
482
|
+
* @param {object} _config - Parsed config.json (unused)
|
|
483
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
484
|
+
*/
|
|
485
|
+
function checkRoadmapSyncValidation(planningDir, _config) {
|
|
486
|
+
const roadmapPath = path.join(planningDir, 'ROADMAP.md');
|
|
487
|
+
let content;
|
|
488
|
+
|
|
489
|
+
try {
|
|
490
|
+
content = fs.readFileSync(roadmapPath, 'utf8');
|
|
491
|
+
} catch (_e) {
|
|
492
|
+
return result('WC-04', 'fail', 'ROADMAP.md not found', [
|
|
493
|
+
`Expected at: ${roadmapPath}`,
|
|
494
|
+
]);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Get actual phase directories
|
|
498
|
+
const phasesDir = path.join(planningDir, 'phases');
|
|
499
|
+
let actualDirs = [];
|
|
500
|
+
try {
|
|
501
|
+
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
|
502
|
+
actualDirs = entries
|
|
503
|
+
.filter(e => e.isDirectory() && /^\d{2}-/.test(e.name))
|
|
504
|
+
.map(e => e.name)
|
|
505
|
+
.sort();
|
|
506
|
+
} catch (_e) {
|
|
507
|
+
return result('WC-04', 'warn', 'Could not read phases/ directory', [
|
|
508
|
+
`Expected at: ${phasesDir}`,
|
|
509
|
+
]);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// Extract actual phase numbers from disk
|
|
513
|
+
const diskPhaseNums = new Set();
|
|
514
|
+
for (const dir of actualDirs) {
|
|
515
|
+
const num = parseInt(dir.substring(0, 2), 10);
|
|
516
|
+
if (!isNaN(num)) diskPhaseNums.add(num);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Extract phase entries from ROADMAP.md
|
|
520
|
+
// Look for patterns like:
|
|
521
|
+
// "| N. Name |" in progress tables
|
|
522
|
+
// "### Phase N: Name"
|
|
523
|
+
// "| {N}. {name} |"
|
|
524
|
+
const lines = content.replace(/\r\n/g, '\n').split('\n');
|
|
525
|
+
const roadmapPhaseNums = new Set();
|
|
526
|
+
|
|
527
|
+
// Find the active milestone section (look for "## Progress" or most recent non-COMPLETED milestone)
|
|
528
|
+
// We scan the entire file for phase references under the active milestone
|
|
529
|
+
let inActiveMilestone = false;
|
|
530
|
+
for (const line of lines) {
|
|
531
|
+
// Detect active milestone sections (not COMPLETED)
|
|
532
|
+
if (/^##\s+Milestone:.*(?:ACTIVE|COMPLETED)/i.test(line)) {
|
|
533
|
+
inActiveMilestone = !line.includes('COMPLETED');
|
|
534
|
+
}
|
|
535
|
+
if (/^##\s+Progress\b/.test(line)) {
|
|
536
|
+
inActiveMilestone = true;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (!inActiveMilestone) continue;
|
|
540
|
+
|
|
541
|
+
// Match table rows: "| N. Name |" or "|N. Name|"
|
|
542
|
+
const tableMatch = line.match(/\|\s*(\d{1,2})\.\s+/);
|
|
543
|
+
if (tableMatch) {
|
|
544
|
+
roadmapPhaseNums.add(parseInt(tableMatch[1], 10));
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// Match headers: "### Phase N: Name" or "### Phase NN: Name"
|
|
548
|
+
const headerMatch = line.match(/^###\s+Phase\s+(\d{1,2})\b/);
|
|
549
|
+
if (headerMatch) {
|
|
550
|
+
roadmapPhaseNums.add(parseInt(headerMatch[1], 10));
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
const evidence = [];
|
|
555
|
+
|
|
556
|
+
// Orphan directories: on disk but not in ROADMAP
|
|
557
|
+
for (const num of diskPhaseNums) {
|
|
558
|
+
if (!roadmapPhaseNums.has(num)) {
|
|
559
|
+
const dirName = actualDirs.find(d => parseInt(d.substring(0, 2), 10) === num);
|
|
560
|
+
evidence.push(`Orphan directory: "${dirName}" (phase ${num}) not in ROADMAP`);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// Phantom phases: in ROADMAP but not on disk
|
|
565
|
+
for (const num of roadmapPhaseNums) {
|
|
566
|
+
if (!diskPhaseNums.has(num)) {
|
|
567
|
+
evidence.push(`Phantom phase: phase ${num} in ROADMAP but no directory on disk`);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
if (evidence.length === 0) {
|
|
572
|
+
return result('WC-04', 'pass', 'ROADMAP.md aligns with phase directories');
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
return result('WC-04', 'fail',
|
|
576
|
+
`ROADMAP has ${evidence.length} sync issue(s) with disk`,
|
|
577
|
+
evidence
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// ---------------------------------------------------------------------------
|
|
582
|
+
// WC-08: Naming Convention Compliance
|
|
583
|
+
// ---------------------------------------------------------------------------
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Scan all phase directories for PLAN files and verify they follow
|
|
587
|
+
* the PLAN-{NN}.md naming convention.
|
|
588
|
+
*
|
|
589
|
+
* @param {string} planningDir - Path to .planning/ directory
|
|
590
|
+
* @param {object} _config - Parsed config.json (unused)
|
|
591
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
592
|
+
*/
|
|
593
|
+
function checkNamingConventionCompliance(planningDir, _config) {
|
|
594
|
+
const phasesDir = path.join(planningDir, 'phases');
|
|
595
|
+
let phaseDirs;
|
|
596
|
+
|
|
597
|
+
try {
|
|
598
|
+
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
|
599
|
+
phaseDirs = entries
|
|
600
|
+
.filter(e => e.isDirectory() && /^\d{2}-/.test(e.name))
|
|
601
|
+
.map(e => e.name)
|
|
602
|
+
.sort();
|
|
603
|
+
} catch (_e) {
|
|
604
|
+
return result('WC-08', 'warn', 'Could not read phases/ directory');
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
const conformingPattern = /^PLAN-\d{2}\.md$/;
|
|
608
|
+
const planFilePattern = /^PLAN.*\.md$/i;
|
|
609
|
+
const evidence = [];
|
|
610
|
+
|
|
611
|
+
for (const dir of phaseDirs) {
|
|
612
|
+
const dirPath = path.join(phasesDir, dir);
|
|
613
|
+
let files;
|
|
614
|
+
try {
|
|
615
|
+
files = fs.readdirSync(dirPath);
|
|
616
|
+
} catch (_e) {
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
const planFiles = files.filter(f => planFilePattern.test(f));
|
|
621
|
+
for (const planFile of planFiles) {
|
|
622
|
+
if (!conformingPattern.test(planFile)) {
|
|
623
|
+
evidence.push(`${dir}/${planFile} does not match PLAN-{NN}.md convention`);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
if (evidence.length === 0) {
|
|
629
|
+
return result('WC-08', 'pass', 'All PLAN files follow naming convention');
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
return result('WC-08', 'warn',
|
|
633
|
+
`${evidence.length} PLAN file(s) do not follow naming convention`,
|
|
634
|
+
evidence
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// ---------------------------------------------------------------------------
|
|
639
|
+
// WC-05: Planning Artifact Completeness
|
|
640
|
+
// ---------------------------------------------------------------------------
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Check that built phases have both SUMMARY and VERIFICATION artifacts.
|
|
644
|
+
* Detects phases marked as built/complete that are missing required artifacts.
|
|
645
|
+
*
|
|
646
|
+
* @param {string} planningDir - Path to .planning/ directory
|
|
647
|
+
* @param {object} _config - Parsed config.json (unused)
|
|
648
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
649
|
+
*/
|
|
650
|
+
function checkPlanningArtifactCompleteness(planningDir, _config) {
|
|
651
|
+
const phasesDir = path.join(planningDir, 'phases');
|
|
652
|
+
let phaseDirs;
|
|
653
|
+
|
|
654
|
+
try {
|
|
655
|
+
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
|
656
|
+
phaseDirs = entries
|
|
657
|
+
.filter(e => e.isDirectory() && /^\d{2}-/.test(e.name))
|
|
658
|
+
.map(e => e.name)
|
|
659
|
+
.sort();
|
|
660
|
+
} catch (_e) {
|
|
661
|
+
return result('WC-05', 'warn', 'Could not read phases/ directory');
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// Read ROADMAP.md to detect phases marked as complete/verified
|
|
665
|
+
const roadmapPath = path.join(planningDir, 'ROADMAP.md');
|
|
666
|
+
let roadmapContent = '';
|
|
667
|
+
try {
|
|
668
|
+
roadmapContent = fs.readFileSync(roadmapPath, 'utf8').replace(/\r\n/g, '\n');
|
|
669
|
+
} catch (_e) {
|
|
670
|
+
// No roadmap — can only check by artifact presence
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
const evidence = [];
|
|
674
|
+
|
|
675
|
+
for (const dir of phaseDirs) {
|
|
676
|
+
const dirPath = path.join(phasesDir, dir);
|
|
677
|
+
let files;
|
|
678
|
+
try {
|
|
679
|
+
files = fs.readdirSync(dirPath);
|
|
680
|
+
} catch (_e) {
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
const summaryFiles = files.filter(f => /^SUMMARY.*\.md$/i.test(f));
|
|
685
|
+
const verificationFiles = files.filter(f => /^VERIFICATION.*\.md$/i.test(f));
|
|
686
|
+
const planFiles = files.filter(f => /^PLAN.*\.md$/i.test(f));
|
|
687
|
+
|
|
688
|
+
// If SUMMARY exists (indicates phase was built) but no VERIFICATION
|
|
689
|
+
if (summaryFiles.length > 0 && verificationFiles.length === 0) {
|
|
690
|
+
evidence.push(
|
|
691
|
+
`Phase "${dir}" built (has SUMMARY) but missing VERIFICATION.md`
|
|
692
|
+
);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// Check ROADMAP for phases marked complete/verified but missing artifacts
|
|
696
|
+
if (roadmapContent) {
|
|
697
|
+
const phaseNum = parseInt(dir.substring(0, 2), 10);
|
|
698
|
+
// Look for phase in roadmap marked as Complete or Verified
|
|
699
|
+
const completePat = new RegExp(
|
|
700
|
+
`\\|\\s*${phaseNum}\\.\\s+[^|]*\\|[^|]*(?:Complete|Verified|Built)`,
|
|
701
|
+
'i'
|
|
702
|
+
);
|
|
703
|
+
if (completePat.test(roadmapContent)) {
|
|
704
|
+
if (planFiles.length > 0 && summaryFiles.length === 0) {
|
|
705
|
+
evidence.push(
|
|
706
|
+
`Phase "${dir}" marked complete in ROADMAP but has no SUMMARY files`
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
if (evidence.length === 0) {
|
|
714
|
+
return result('WC-05', 'pass', 'All built phases have required artifacts');
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
return result('WC-05', 'warn',
|
|
718
|
+
`${evidence.length} artifact completeness gap(s) found`,
|
|
719
|
+
evidence
|
|
720
|
+
);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// ---------------------------------------------------------------------------
|
|
724
|
+
// WC-06: Artifact Format Validation
|
|
725
|
+
// ---------------------------------------------------------------------------
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Validate SUMMARY.md required fields and PLAN.md task block structure.
|
|
729
|
+
* Checks SUMMARY frontmatter for requires, key_files, deferred fields
|
|
730
|
+
* and PLAN files for at least one <task XML block.
|
|
731
|
+
*
|
|
732
|
+
* @param {string} planningDir - Path to .planning/ directory
|
|
733
|
+
* @param {object} _config - Parsed config.json (unused)
|
|
734
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
735
|
+
*/
|
|
736
|
+
function checkArtifactFormatValidation(planningDir, _config) {
|
|
737
|
+
const phasesDir = path.join(planningDir, 'phases');
|
|
738
|
+
let phaseDirs;
|
|
739
|
+
|
|
740
|
+
try {
|
|
741
|
+
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
|
742
|
+
phaseDirs = entries
|
|
743
|
+
.filter(e => e.isDirectory() && /^\d{2}-/.test(e.name))
|
|
744
|
+
.map(e => e.name)
|
|
745
|
+
.sort();
|
|
746
|
+
} catch (_e) {
|
|
747
|
+
return result('WC-06', 'warn', 'Could not read phases/ directory');
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
const evidence = [];
|
|
751
|
+
|
|
752
|
+
for (const dir of phaseDirs) {
|
|
753
|
+
const dirPath = path.join(phasesDir, dir);
|
|
754
|
+
let files;
|
|
755
|
+
try {
|
|
756
|
+
files = fs.readdirSync(dirPath);
|
|
757
|
+
} catch (_e) {
|
|
758
|
+
continue;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// Validate SUMMARY files
|
|
762
|
+
const summaryFiles = files.filter(f => /^SUMMARY.*\.md$/i.test(f));
|
|
763
|
+
for (const sf of summaryFiles) {
|
|
764
|
+
try {
|
|
765
|
+
const content = fs.readFileSync(path.join(dirPath, sf), 'utf8');
|
|
766
|
+
const fm = extractFrontmatter(content);
|
|
767
|
+
const missingFields = [];
|
|
768
|
+
|
|
769
|
+
if (fm.requires === undefined) missingFields.push('requires');
|
|
770
|
+
if (fm.key_files === undefined) missingFields.push('key_files');
|
|
771
|
+
if (fm.deferred === undefined) missingFields.push('deferred');
|
|
772
|
+
|
|
773
|
+
if (missingFields.length > 0) {
|
|
774
|
+
evidence.push(
|
|
775
|
+
`${dir}/${sf}: missing required fields: ${missingFields.join(', ')}`
|
|
776
|
+
);
|
|
777
|
+
}
|
|
778
|
+
} catch (_e) {
|
|
779
|
+
evidence.push(`${dir}/${sf}: could not read file`);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// Validate PLAN files have at least one <task block
|
|
784
|
+
const planFiles = files.filter(f => /^PLAN.*\.md$/i.test(f));
|
|
785
|
+
for (const pf of planFiles) {
|
|
786
|
+
try {
|
|
787
|
+
const content = fs.readFileSync(path.join(dirPath, pf), 'utf8');
|
|
788
|
+
if (!/<task\s/.test(content)) {
|
|
789
|
+
evidence.push(`${dir}/${pf}: no <task XML block found`);
|
|
790
|
+
}
|
|
791
|
+
} catch (_e) {
|
|
792
|
+
evidence.push(`${dir}/${pf}: could not read file`);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
if (evidence.length === 0) {
|
|
798
|
+
return result('WC-06', 'pass', 'All artifacts conform to format requirements');
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
return result('WC-06', 'warn',
|
|
802
|
+
`${evidence.length} format violation(s) found`,
|
|
803
|
+
evidence
|
|
804
|
+
);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
// ---------------------------------------------------------------------------
|
|
808
|
+
// WC-09: Commit Pattern Validation
|
|
809
|
+
// ---------------------------------------------------------------------------
|
|
810
|
+
|
|
811
|
+
/**
|
|
812
|
+
* Detect git commit commands using heredoc, missing -m flag, or --no-verify.
|
|
813
|
+
* Scans session JSONL logs for the current project. Falls back to git log
|
|
814
|
+
* format validation if session logs are unavailable.
|
|
815
|
+
*
|
|
816
|
+
* @param {string} planningDir - Path to .planning/ directory
|
|
817
|
+
* @param {object} _config - Parsed config.json (unused)
|
|
818
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
819
|
+
*/
|
|
820
|
+
function checkCommitPatternValidation(planningDir, _config) {
|
|
821
|
+
const evidence = [];
|
|
822
|
+
const sessionLogs = findSessionLogs(planningDir);
|
|
823
|
+
|
|
824
|
+
if (sessionLogs.length > 0) {
|
|
825
|
+
const entries = parseSessionEntries(sessionLogs);
|
|
826
|
+
|
|
827
|
+
for (const entry of entries) {
|
|
828
|
+
if (entry.type !== 'tool_use' && entry.type !== 'assistant') continue;
|
|
829
|
+
|
|
830
|
+
const command = entry.command ||
|
|
831
|
+
(entry.content && typeof entry.content === 'string' ? entry.content : '') ||
|
|
832
|
+
(entry.input && entry.input.command ? entry.input.command : '');
|
|
833
|
+
|
|
834
|
+
if (!command || !command.includes('git commit')) continue;
|
|
835
|
+
|
|
836
|
+
// Flag heredoc usage
|
|
837
|
+
if (command.includes('<<')) {
|
|
838
|
+
const snippet = command.substring(0, 120);
|
|
839
|
+
evidence.push(`Heredoc in commit: "${snippet}..."`);
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// Flag missing -m flag (but not --amend which may not need -m)
|
|
843
|
+
if (!command.includes('-m') && !command.includes('--amend')) {
|
|
844
|
+
const snippet = command.substring(0, 120);
|
|
845
|
+
evidence.push(`Missing -m flag: "${snippet}..."`);
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// Flag --no-verify
|
|
849
|
+
if (command.includes('--no-verify')) {
|
|
850
|
+
const snippet = command.substring(0, 120);
|
|
851
|
+
evidence.push(`Uses --no-verify: "${snippet}..."`);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
if (evidence.length === 0) {
|
|
856
|
+
return result('WC-09', 'pass', 'No commit pattern violations in session logs');
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
return result('WC-09', 'warn',
|
|
860
|
+
`${evidence.length} commit pattern violation(s) found`,
|
|
861
|
+
evidence
|
|
862
|
+
);
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// Fallback: validate recent git log commit messages match convention
|
|
866
|
+
const conventionPattern = /^[a-z]+\([^)]+\):\s.+$/;
|
|
867
|
+
try {
|
|
868
|
+
const _projectRoot = path.resolve(planningDir, '..');
|
|
869
|
+
const log = execSync('git log --oneline -20', {
|
|
870
|
+
cwd: _projectRoot,
|
|
871
|
+
timeout: 10000,
|
|
872
|
+
encoding: 'utf8',
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
const commits = log.trim().split('\n');
|
|
876
|
+
for (const commit of commits) {
|
|
877
|
+
// Strip SHA prefix
|
|
878
|
+
const msg = commit.replace(/^[a-f0-9]+\s+/, '');
|
|
879
|
+
// Skip merge commits
|
|
880
|
+
if (msg.startsWith('Merge')) continue;
|
|
881
|
+
if (!conventionPattern.test(msg)) {
|
|
882
|
+
evidence.push(`Non-conventional commit: "${msg.substring(0, 120)}"`);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
} catch (_e) {
|
|
886
|
+
return result('WC-09', 'pass', 'No session logs available for analysis');
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
if (evidence.length === 0) {
|
|
890
|
+
return result('WC-09', 'pass', 'All recent commits follow convention format');
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
return result('WC-09', 'warn',
|
|
894
|
+
`${evidence.length} non-conventional commit(s) in recent history`,
|
|
895
|
+
evidence
|
|
896
|
+
);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
// ---------------------------------------------------------------------------
|
|
900
|
+
// WC-12: Test Health Baseline
|
|
901
|
+
// ---------------------------------------------------------------------------
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Compare current test failures against a known baseline.
|
|
905
|
+
* Detects new test failures that were not previously known.
|
|
906
|
+
*
|
|
907
|
+
* @param {string} planningDir - Path to .planning/ directory
|
|
908
|
+
* @param {object} _config - Parsed config.json (unused)
|
|
909
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
910
|
+
*/
|
|
911
|
+
function checkTestHealthBaseline(planningDir, _config) {
|
|
912
|
+
const projectRoot = path.resolve(planningDir, '..');
|
|
913
|
+
|
|
914
|
+
// Run tests and detect pass/fail
|
|
915
|
+
let testOutput = '';
|
|
916
|
+
let hasFailures = false;
|
|
917
|
+
|
|
918
|
+
try {
|
|
919
|
+
testOutput = execSync('npm test -- --ci --silent 2>&1', {
|
|
920
|
+
cwd: projectRoot,
|
|
921
|
+
timeout: 60000,
|
|
922
|
+
encoding: 'utf8',
|
|
923
|
+
});
|
|
924
|
+
hasFailures = testOutput.includes('FAIL');
|
|
925
|
+
} catch (_e) {
|
|
926
|
+
// Non-zero exit = test failures
|
|
927
|
+
hasFailures = true;
|
|
928
|
+
if (_e.stdout) testOutput = _e.stdout.toString();
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
const currentStatus = hasFailures ? 'HAS_FAILURES' : 'ALL_PASS';
|
|
932
|
+
|
|
933
|
+
// Read baseline file
|
|
934
|
+
const baselinePath = path.join(planningDir, 'test-baseline.json');
|
|
935
|
+
let baseline = null;
|
|
936
|
+
|
|
937
|
+
try {
|
|
938
|
+
const raw = fs.readFileSync(baselinePath, 'utf8');
|
|
939
|
+
baseline = JSON.parse(raw);
|
|
940
|
+
} catch (_e) {
|
|
941
|
+
// No baseline file
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
if (!baseline) {
|
|
945
|
+
return result('WC-12', 'info',
|
|
946
|
+
'No test baseline established yet',
|
|
947
|
+
[`Current test status: ${currentStatus}`]
|
|
948
|
+
);
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
// Compare against baseline
|
|
952
|
+
const evidence = [];
|
|
953
|
+
const knownFailures = baseline.known_failures || [];
|
|
954
|
+
|
|
955
|
+
if (hasFailures && knownFailures.length === 0) {
|
|
956
|
+
evidence.push('Tests have failures but baseline shows no known failures — new regressions detected');
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// Extract failing test names if possible
|
|
960
|
+
const failLines = testOutput.split('\n').filter(l => /FAIL\s/.test(l));
|
|
961
|
+
for (const fl of failLines) {
|
|
962
|
+
const trimmed = fl.trim().substring(0, 120);
|
|
963
|
+
const isKnown = knownFailures.some(kf => trimmed.includes(kf));
|
|
964
|
+
if (!isKnown) {
|
|
965
|
+
evidence.push(`New failure: ${trimmed}`);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
if (evidence.length === 0) {
|
|
970
|
+
return result('WC-12', 'pass',
|
|
971
|
+
`Test health matches baseline (${currentStatus})`,
|
|
972
|
+
[`Known failures: ${knownFailures.length}`]
|
|
973
|
+
);
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
return result('WC-12', 'warn',
|
|
977
|
+
`${evidence.length} new test issue(s) beyond baseline`,
|
|
978
|
+
evidence
|
|
979
|
+
);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// ---------------------------------------------------------------------------
|
|
983
|
+
// WC-10: Model Selection Compliance
|
|
984
|
+
// ---------------------------------------------------------------------------
|
|
985
|
+
|
|
986
|
+
/**
|
|
987
|
+
* Cross-reference agent spawns in session logs against config.models settings.
|
|
988
|
+
* Detects agents using models that differ from configured preferences.
|
|
989
|
+
*
|
|
990
|
+
* @param {string} planningDir - Path to .planning/ directory
|
|
991
|
+
* @param {object} config - Parsed config.json
|
|
992
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
993
|
+
*/
|
|
994
|
+
function checkModelSelectionCompliance(planningDir, config) {
|
|
995
|
+
const models = (config && config.models) || {};
|
|
996
|
+
const logFiles = findSessionLogs(planningDir);
|
|
997
|
+
|
|
998
|
+
if (logFiles.length === 0) {
|
|
999
|
+
return result('WC-10', 'pass', 'No session logs available for model verification');
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
const entries = parseSessionEntries(logFiles);
|
|
1003
|
+
const evidence = [];
|
|
1004
|
+
let totalSpawns = 0;
|
|
1005
|
+
let compliant = 0;
|
|
1006
|
+
|
|
1007
|
+
for (const entry of entries) {
|
|
1008
|
+
// Look for Task tool_use entries with subagent_type or model fields
|
|
1009
|
+
if (entry.type !== 'tool_use' && entry.type !== 'assistant') continue;
|
|
1010
|
+
|
|
1011
|
+
const input = entry.input || {};
|
|
1012
|
+
const subagentType = input.subagent_type || input.agent_type || '';
|
|
1013
|
+
const usedModel = input.model || '';
|
|
1014
|
+
|
|
1015
|
+
// Only care about pbr agent spawns
|
|
1016
|
+
if (!subagentType.startsWith('pbr:')) continue;
|
|
1017
|
+
|
|
1018
|
+
totalSpawns++;
|
|
1019
|
+
const agentName = subagentType.replace('pbr:', '');
|
|
1020
|
+
|
|
1021
|
+
// Check if config has a model preference for this agent type
|
|
1022
|
+
const configuredModel = models[agentName];
|
|
1023
|
+
if (!configuredModel || configuredModel === 'inherit') {
|
|
1024
|
+
// No specific model configured or set to inherit — always compliant
|
|
1025
|
+
compliant++;
|
|
1026
|
+
continue;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
if (usedModel && usedModel !== configuredModel) {
|
|
1030
|
+
evidence.push(
|
|
1031
|
+
`Agent "${agentName}" used model "${usedModel}" but config specifies "${configuredModel}"`
|
|
1032
|
+
);
|
|
1033
|
+
} else {
|
|
1034
|
+
compliant++;
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
if (totalSpawns === 0) {
|
|
1039
|
+
return result('WC-10', 'pass', 'No agent spawns detected for model verification');
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
const pct = Math.round((compliant / totalSpawns) * 100);
|
|
1043
|
+
|
|
1044
|
+
if (evidence.length === 0) {
|
|
1045
|
+
return result('WC-10', 'pass',
|
|
1046
|
+
`${totalSpawns} agent spawn(s), ${pct}% model-compliant`);
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
return result('WC-10', 'info',
|
|
1050
|
+
`${evidence.length} model mismatch(es) across ${totalSpawns} spawns (${pct}% compliant)`,
|
|
1051
|
+
evidence
|
|
1052
|
+
);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
// ---------------------------------------------------------------------------
|
|
1056
|
+
// WC-11: Git Branching Compliance
|
|
1057
|
+
// ---------------------------------------------------------------------------
|
|
1058
|
+
|
|
1059
|
+
/**
|
|
1060
|
+
* Verify phase branches exist when git.branching is set to "phase".
|
|
1061
|
+
* Reads config.json git settings and checks git branch list.
|
|
1062
|
+
*
|
|
1063
|
+
* @param {string} planningDir - Path to .planning/ directory
|
|
1064
|
+
* @param {object} config - Parsed config.json
|
|
1065
|
+
* @returns {{ dimension: string, status: string, message: string, evidence: string[] }}
|
|
1066
|
+
*/
|
|
1067
|
+
function checkGitBranchingCompliance(planningDir, config) {
|
|
1068
|
+
const gitConfig = (config && config.git) || {};
|
|
1069
|
+
const branching = gitConfig.branching || 'none';
|
|
1070
|
+
|
|
1071
|
+
if (branching === 'none' || branching === 'disabled') {
|
|
1072
|
+
return result('WC-11', 'pass', 'Git branching not configured');
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
if (branching !== 'phase') {
|
|
1076
|
+
return result('WC-11', 'pass',
|
|
1077
|
+
`Git branching mode "${branching}" — phase branch check not applicable`);
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
const projectRoot = path.resolve(planningDir, '..');
|
|
1081
|
+
const template = gitConfig.phase_branch_template ||
|
|
1082
|
+
'plan-build-run/phase-{phase}-{slug}';
|
|
1083
|
+
|
|
1084
|
+
// Get list of git branches
|
|
1085
|
+
let branches;
|
|
1086
|
+
try {
|
|
1087
|
+
const branchOutput = execSync('git branch --list --all', {
|
|
1088
|
+
cwd: projectRoot,
|
|
1089
|
+
timeout: 10000,
|
|
1090
|
+
encoding: 'utf8',
|
|
1091
|
+
});
|
|
1092
|
+
branches = branchOutput
|
|
1093
|
+
.split('\n')
|
|
1094
|
+
.map(b => b.replace(/^\*?\s+/, '').trim())
|
|
1095
|
+
.filter(b => b.length > 0);
|
|
1096
|
+
} catch (_e) {
|
|
1097
|
+
return result('WC-11', 'pass', 'Git not available');
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
// Get active phase directories
|
|
1101
|
+
const phasesDir = path.join(planningDir, 'phases');
|
|
1102
|
+
let phaseDirs;
|
|
1103
|
+
try {
|
|
1104
|
+
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
|
1105
|
+
phaseDirs = entries
|
|
1106
|
+
.filter(e => e.isDirectory() && /^\d{2}-/.test(e.name))
|
|
1107
|
+
.map(e => e.name)
|
|
1108
|
+
.sort();
|
|
1109
|
+
} catch (_e) {
|
|
1110
|
+
return result('WC-11', 'pass', 'No phases/ directory');
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
const evidence = [];
|
|
1114
|
+
|
|
1115
|
+
for (const dir of phaseDirs) {
|
|
1116
|
+
// Check if this phase has PLAN files (indicates active work)
|
|
1117
|
+
const dirPath = path.join(phasesDir, dir);
|
|
1118
|
+
let hasPlan = false;
|
|
1119
|
+
try {
|
|
1120
|
+
const files = fs.readdirSync(dirPath);
|
|
1121
|
+
hasPlan = files.some(f => /^PLAN.*\.md$/i.test(f));
|
|
1122
|
+
} catch (_e) {
|
|
1123
|
+
continue;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
if (!hasPlan) continue;
|
|
1127
|
+
|
|
1128
|
+
// Build expected branch name from template
|
|
1129
|
+
const phaseNum = dir.substring(0, 2);
|
|
1130
|
+
const slug = dir.substring(3); // everything after "NN-"
|
|
1131
|
+
const expectedBranch = template
|
|
1132
|
+
.replace('{phase}', phaseNum)
|
|
1133
|
+
.replace('{slug}', slug);
|
|
1134
|
+
|
|
1135
|
+
// Check if any branch matches (local or remote)
|
|
1136
|
+
const hasBranch = branches.some(b =>
|
|
1137
|
+
b === expectedBranch ||
|
|
1138
|
+
b.endsWith('/' + expectedBranch) ||
|
|
1139
|
+
b.includes(expectedBranch)
|
|
1140
|
+
);
|
|
1141
|
+
|
|
1142
|
+
if (!hasBranch) {
|
|
1143
|
+
evidence.push(`Phase "${dir}" missing expected branch "${expectedBranch}"`);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
if (evidence.length === 0) {
|
|
1148
|
+
return result('WC-11', 'pass',
|
|
1149
|
+
`All active phases have corresponding git branches`);
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
return result('WC-11', 'info',
|
|
1153
|
+
`${evidence.length} phase(s) missing expected git branches`,
|
|
1154
|
+
evidence
|
|
1155
|
+
);
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
// ---------------------------------------------------------------------------
|
|
1159
|
+
// Exports
|
|
1160
|
+
// ---------------------------------------------------------------------------
|
|
1161
|
+
|
|
1162
|
+
module.exports = {
|
|
1163
|
+
checkCiVerifyAfterPush,
|
|
1164
|
+
checkStateFileIntegrity,
|
|
1165
|
+
checkStateFrontmatterIntegrity,
|
|
1166
|
+
checkRoadmapSyncValidation,
|
|
1167
|
+
checkPlanningArtifactCompleteness,
|
|
1168
|
+
checkArtifactFormatValidation,
|
|
1169
|
+
checkCompactionQuality,
|
|
1170
|
+
checkNamingConventionCompliance,
|
|
1171
|
+
checkCommitPatternValidation,
|
|
1172
|
+
checkModelSelectionCompliance,
|
|
1173
|
+
checkGitBranchingCompliance,
|
|
1174
|
+
checkTestHealthBaseline,
|
|
1175
|
+
};
|