@sienklogic/plan-build-run 2.21.0 → 2.21.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 +1331 -299
- package/CLAUDE.md +75 -40
- 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 +56 -41
- 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 +207 -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 +737 -39
- package/plugins/pbr/agents/general.md +71 -6
- package/plugins/pbr/agents/integration-checker.md +148 -30
- package/plugins/pbr/agents/intel-updater.md +332 -0
- package/plugins/pbr/agents/nyquist-auditor.md +254 -0
- package/plugins/pbr/agents/plan-checker.md +268 -66
- package/plugins/pbr/agents/planner.md +451 -42
- package/plugins/pbr/agents/researcher.md +219 -36
- package/plugins/pbr/agents/roadmapper.md +398 -0
- package/plugins/pbr/agents/synthesizer.md +166 -26
- package/plugins/pbr/agents/ui-checker.md +204 -0
- package/plugins/pbr/agents/ui-researcher.md +224 -0
- package/plugins/pbr/agents/verifier.md +571 -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 +76 -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 +213 -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 +227 -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 +676 -0
- package/plugins/pbr/dist/check-subagent-output.js +425 -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 +212 -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 +664 -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 +367 -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 +493 -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 +132 -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 +233 -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 +137 -65
- 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/assumptions.md +42 -0
- package/plugins/pbr/references/checkpoints.md +723 -104
- package/plugins/pbr/references/config-reference.md +387 -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/few-shot-examples/audit.md +77 -0
- package/plugins/pbr/references/few-shot-examples/check-plan-format.md +172 -0
- package/plugins/pbr/references/few-shot-examples/check-subagent-output.md +118 -0
- package/plugins/pbr/references/few-shot-examples/integration-checker.md +70 -0
- package/plugins/pbr/references/few-shot-examples/nyquist-auditor.md +83 -0
- package/plugins/pbr/references/few-shot-examples/plan-checker.md +73 -0
- package/plugins/pbr/references/few-shot-examples/ui-checker.md +71 -0
- package/plugins/pbr/references/few-shot-examples/verifier.md +109 -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 +184 -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/thinking-models-planning.md +47 -0
- package/plugins/pbr/references/thinking-models-verification.md +44 -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 +76 -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 +455 -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 -37
- 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 +84 -1
- 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 +153 -278
- package/plugins/pbr/scripts/check-read-first.js +345 -0
- package/plugins/pbr/scripts/check-roadmap-sync.js +174 -19
- package/plugins/pbr/scripts/check-skill-workflow.js +24 -27
- package/plugins/pbr/scripts/check-state-sync.js +360 -218
- package/plugins/pbr/scripts/check-subagent-output.js +308 -273
- package/plugins/pbr/scripts/check-summary-gate.js +5 -15
- package/plugins/pbr/scripts/commands/benchmarks.js +195 -0
- package/plugins/pbr/scripts/commands/calibrate.js +530 -0
- package/plugins/pbr/scripts/commands/config.js +72 -0
- package/plugins/pbr/scripts/commands/misc.js +779 -0
- package/plugins/pbr/scripts/commands/phase.js +293 -0
- package/plugins/pbr/scripts/commands/roadmap.js +75 -0
- package/plugins/pbr/scripts/commands/state.js +84 -0
- package/plugins/pbr/scripts/commands/stress-test.js +349 -0
- package/plugins/pbr/scripts/commands/todo.js +191 -0
- package/plugins/pbr/scripts/commands/verify.js +169 -0
- package/plugins/pbr/scripts/config-schema.json +1183 -95
- package/plugins/pbr/scripts/context-bridge.js +425 -0
- package/plugins/pbr/scripts/context-budget-check.js +171 -16
- 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 +137 -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 +664 -0
- package/plugins/pbr/scripts/hooks-schema.json +12 -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 +123 -0
- package/plugins/pbr/scripts/lib/benchmark.js +190 -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 +222 -0
- package/plugins/pbr/scripts/lib/config-cache.js +83 -0
- package/plugins/pbr/scripts/lib/config.js +1469 -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 +1585 -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 +1049 -0
- package/plugins/pbr/scripts/lib/frontmatter.js +302 -0
- package/plugins/pbr/scripts/lib/gates/advisories.js +133 -0
- package/plugins/pbr/scripts/lib/gates/build-dependency.js +118 -0
- package/plugins/pbr/scripts/lib/gates/build-executor.js +106 -0
- package/plugins/pbr/scripts/lib/gates/doc-existence.js +46 -0
- package/plugins/pbr/scripts/lib/gates/helpers.js +98 -0
- package/plugins/pbr/scripts/lib/gates/inline-execution.js +187 -0
- package/plugins/pbr/scripts/lib/gates/milestone-complete.js +139 -0
- package/plugins/pbr/scripts/lib/gates/milestone-summary.js +121 -0
- package/plugins/pbr/scripts/lib/gates/multi-phase-loader.js +149 -0
- package/plugins/pbr/scripts/lib/gates/plan-executor.js +36 -0
- package/plugins/pbr/scripts/lib/gates/plan-validation.js +115 -0
- package/plugins/pbr/scripts/lib/gates/quick-executor.js +78 -0
- package/plugins/pbr/scripts/lib/gates/review-planner.js +63 -0
- package/plugins/pbr/scripts/lib/gates/review-verifier.js +71 -0
- package/plugins/pbr/scripts/lib/gates/rich-agent-context.js +148 -0
- package/plugins/pbr/scripts/lib/gates/sprint-preflight.js +30 -0
- package/plugins/pbr/scripts/lib/gates/user-confirmation.js +95 -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/handoff-validators.js +224 -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 +309 -0
- package/plugins/pbr/scripts/lib/milestone.js +306 -0
- package/plugins/pbr/scripts/lib/msys-path.js +20 -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 +1043 -0
- package/plugins/pbr/scripts/lib/pid-lock.js +156 -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/premature-completion.js +312 -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 +918 -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 +1119 -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 +1561 -0
- package/plugins/pbr/scripts/log-notification.js +131 -0
- package/plugins/pbr/scripts/log-subagent.js +221 -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 +362 -1247
- 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 +121 -324
- 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 +63 -23
- 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 +120 -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 -104
- 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 +59 -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 +551 -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 +419 -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 +1180 -358
- 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/build/templates/qa-round-context.md.tmpl +16 -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 +205 -24
- 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 +83 -123
- 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 +383 -274
- 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 +20 -2
- package/plugins/pbr/skills/plan/templates/completion-output.md.tmpl +27 -0
- package/plugins/pbr/skills/plan/templates/planner-prompt.md.tmpl +43 -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 +233 -165
- 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/criterion-writing.md +58 -0
- 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 +110 -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 +54 -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 -258
- 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 -193
- package/plugins/copilot-pbr/skills/import/SKILL.md +0 -502
- package/plugins/copilot-pbr/skills/milestone/SKILL.md +0 -806
- 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-recovery-strategies.md +0 -51
- 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 -224
- 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 -193
- package/plugins/cursor-pbr/skills/import/SKILL.md +0 -505
- package/plugins/cursor-pbr/skills/milestone/SKILL.md +0 -807
- 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-recovery-strategies.md +0 -51
- 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/error-recovery-strategies.md +0 -51
- 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,1119 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* lib/subagent-validators.js — Extracted validator functions and constants
|
|
5
|
+
* from check-subagent-output.js.
|
|
6
|
+
*
|
|
7
|
+
* Contains: AGENT_TO_SKILL, AGENT_OUTPUTS, SKILL_CHECKS, and all helper
|
|
8
|
+
* functions used for subagent output validation.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const { logHook } = require('../hook-logger');
|
|
14
|
+
const { KNOWN_AGENTS, sessionLoad } = require('../pbr-tools');
|
|
15
|
+
const { detectConventions, writeConventions } = require('./convention-detector');
|
|
16
|
+
const { resolveSessionPath } = require('./core');
|
|
17
|
+
const handoff = require('./handoff-validators');
|
|
18
|
+
|
|
19
|
+
// Agent-type to skill mapping for .active-skill auto-creation
|
|
20
|
+
const AGENT_TO_SKILL = {
|
|
21
|
+
'pbr:executor': 'build', 'pbr:planner': 'plan', 'pbr:verifier': 'review',
|
|
22
|
+
'pbr:researcher': 'plan', 'pbr:synthesizer': 'plan', 'pbr:audit': 'audit',
|
|
23
|
+
'pbr:debugger': 'debug', 'pbr:codebase-mapper': 'begin', 'pbr:roadmapper': 'begin',
|
|
24
|
+
'pbr:nyquist-auditor': 'validate', 'pbr:intel-updater': 'intel',
|
|
25
|
+
'pbr:ui-checker': 'ui-review', 'pbr:ui-researcher': 'ui-phase'
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Load a feature flag value from config.json.
|
|
30
|
+
* @param {string} planningDir - Path to .planning directory
|
|
31
|
+
* @param {string} flagName - Feature flag name (e.g. 'trust_tracking')
|
|
32
|
+
* @returns {*} Flag value or undefined if not found
|
|
33
|
+
*/
|
|
34
|
+
function loadFeatureFlag(planningDir, flagName) {
|
|
35
|
+
try {
|
|
36
|
+
const configPath = path.join(planningDir, 'config.json');
|
|
37
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
38
|
+
return config.features?.[flagName];
|
|
39
|
+
} catch (_e) { // intentionally silent: config may not exist
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Check whether trust tracking is enabled in config.
|
|
46
|
+
* @param {string} planningDir - Path to .planning directory
|
|
47
|
+
* @returns {boolean} True if trust_tracking is not explicitly disabled
|
|
48
|
+
*/
|
|
49
|
+
function shouldTrackTrust(planningDir) {
|
|
50
|
+
const flag = loadFeatureFlag(planningDir, 'trust_tracking');
|
|
51
|
+
return flag !== false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Extract verification outcome from the most recent VERIFICATION.md
|
|
56
|
+
* in the current phase directory.
|
|
57
|
+
* @param {string} planningDir - Path to .planning directory
|
|
58
|
+
* @returns {{ passed: boolean, category: string, mustHavesPassed: number|undefined, mustHavesTotal: number|undefined }|null}
|
|
59
|
+
*/
|
|
60
|
+
function extractVerificationOutcome(planningDir) {
|
|
61
|
+
try {
|
|
62
|
+
const verFiles = findInPhaseDir(planningDir, /^VERIFICATION(-R\d+)?\.md$/i);
|
|
63
|
+
if (verFiles.length === 0) return null;
|
|
64
|
+
|
|
65
|
+
// Use the latest verification file (highest round number, or base VERIFICATION.md)
|
|
66
|
+
const sorted = verFiles.sort();
|
|
67
|
+
const verPath = path.join(planningDir, sorted[sorted.length - 1]);
|
|
68
|
+
const content = fs.readFileSync(verPath, 'utf8');
|
|
69
|
+
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
70
|
+
if (!fmMatch) return null;
|
|
71
|
+
|
|
72
|
+
const fm = fmMatch[1];
|
|
73
|
+
const statusMatch = fm.match(/^status:\s*(\S+)/mi);
|
|
74
|
+
if (!statusMatch) return null;
|
|
75
|
+
|
|
76
|
+
const status = statusMatch[1];
|
|
77
|
+
const passed = status === 'passed';
|
|
78
|
+
|
|
79
|
+
// Extract must_haves counts
|
|
80
|
+
const passedMatch = fm.match(/^must_haves_passed:\s*(\d+)/mi);
|
|
81
|
+
const totalMatch = fm.match(/^must_haves_total:\s*(\d+)/mi);
|
|
82
|
+
const mustHavesPassed = passedMatch ? parseInt(passedMatch[1], 10) : undefined;
|
|
83
|
+
const mustHavesTotal = totalMatch ? parseInt(totalMatch[1], 10) : undefined;
|
|
84
|
+
|
|
85
|
+
// Extract category from STATE.md phase_slug
|
|
86
|
+
let category = 'unknown';
|
|
87
|
+
const stateFile = path.join(planningDir, 'STATE.md');
|
|
88
|
+
if (fs.existsSync(stateFile)) {
|
|
89
|
+
const stateContent = fs.readFileSync(stateFile, 'utf8');
|
|
90
|
+
const slugMatch = stateContent.match(/^phase_slug:\s*"?([^"\n]+)"?/mi);
|
|
91
|
+
if (slugMatch) {
|
|
92
|
+
category = slugMatch[1].trim();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return { passed, category, mustHavesPassed, mustHavesTotal };
|
|
97
|
+
} catch (_e) { // intentionally silent: verification data may not exist
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Check if a file was modified recently (within thresholdMs).
|
|
104
|
+
* Returns false if file doesn't exist or on error.
|
|
105
|
+
*/
|
|
106
|
+
function isRecent(filePath, thresholdMs = 1800000) {
|
|
107
|
+
try {
|
|
108
|
+
const stat = fs.statSync(filePath);
|
|
109
|
+
return (Date.now() - stat.mtimeMs) < thresholdMs;
|
|
110
|
+
} catch (_e) { // intentionally silent: file may not exist
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Extract current phase number from STATE.md, preferring frontmatter over body.
|
|
117
|
+
* @param {string} stateContent - Full STATE.md content
|
|
118
|
+
* @returns {string|null} Phase number string or null
|
|
119
|
+
*/
|
|
120
|
+
function getCurrentPhase(stateContent) {
|
|
121
|
+
// Prefer frontmatter (always up-to-date)
|
|
122
|
+
const fmMatch = stateContent.match(/^current_phase:\s*(\d+)/m);
|
|
123
|
+
if (fmMatch) return fmMatch[1];
|
|
124
|
+
// Fall back to body text
|
|
125
|
+
const bodyMatch = stateContent.match(/Phase:\s*(\d+)\s+of\s+\d+/);
|
|
126
|
+
return bodyMatch ? bodyMatch[1] : null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function findInPhaseDir(planningDir, pattern) {
|
|
130
|
+
const matches = [];
|
|
131
|
+
const phasesDir = path.join(planningDir, 'phases');
|
|
132
|
+
if (!fs.existsSync(phasesDir)) return matches;
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
// Find the active phase from STATE.md (prefer frontmatter over body)
|
|
136
|
+
const stateFile = path.join(planningDir, 'STATE.md');
|
|
137
|
+
if (!fs.existsSync(stateFile)) return matches;
|
|
138
|
+
|
|
139
|
+
const stateContent = fs.readFileSync(stateFile, 'utf8');
|
|
140
|
+
const phaseNum = getCurrentPhase(stateContent);
|
|
141
|
+
if (!phaseNum) return matches;
|
|
142
|
+
|
|
143
|
+
const currentPhase = phaseNum.padStart(2, '0');
|
|
144
|
+
const dirs = fs.readdirSync(phasesDir).filter(d => d.startsWith(currentPhase));
|
|
145
|
+
if (dirs.length === 0) return matches;
|
|
146
|
+
|
|
147
|
+
const phaseDir = path.join(phasesDir, dirs[0]);
|
|
148
|
+
const files = fs.readdirSync(phaseDir);
|
|
149
|
+
for (const file of files) {
|
|
150
|
+
if (pattern.test(file)) {
|
|
151
|
+
// Check it's non-empty
|
|
152
|
+
const filePath = path.join(phaseDir, file);
|
|
153
|
+
const stat = fs.statSync(filePath);
|
|
154
|
+
if (stat.size > 0) {
|
|
155
|
+
matches.push(path.join('phases', dirs[0], file));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
} catch (_e) { logHook('subagent-validators', 'debug', 'Failed to search phase directory');
|
|
160
|
+
// best-effort
|
|
161
|
+
}
|
|
162
|
+
return matches;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function findInQuickDir(planningDir, pattern) {
|
|
166
|
+
const matches = [];
|
|
167
|
+
const quickDir = path.join(planningDir, 'quick');
|
|
168
|
+
if (!fs.existsSync(quickDir)) return matches;
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
// Find the most recent quick task directory (highest NNN)
|
|
172
|
+
const dirs = fs.readdirSync(quickDir)
|
|
173
|
+
.filter(d => /^\d{3}-/.test(d))
|
|
174
|
+
.sort()
|
|
175
|
+
.reverse();
|
|
176
|
+
if (dirs.length === 0) return matches;
|
|
177
|
+
|
|
178
|
+
const latestDir = path.join(quickDir, dirs[0]);
|
|
179
|
+
const stat = fs.statSync(latestDir);
|
|
180
|
+
if (!stat.isDirectory()) return matches;
|
|
181
|
+
|
|
182
|
+
const files = fs.readdirSync(latestDir);
|
|
183
|
+
for (const file of files) {
|
|
184
|
+
if (pattern.test(file)) {
|
|
185
|
+
const filePath = path.join(latestDir, file);
|
|
186
|
+
const fileStat = fs.statSync(filePath);
|
|
187
|
+
if (fileStat.size > 0) {
|
|
188
|
+
matches.push(path.join('quick', dirs[0], file));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
} catch (_e) { logHook('subagent-validators', 'debug', 'Failed to search quick directory');
|
|
193
|
+
// best-effort
|
|
194
|
+
}
|
|
195
|
+
return matches;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function checkSummaryCommits(planningDir, foundFiles, warnings) {
|
|
199
|
+
// Look for SUMMARY files in found list
|
|
200
|
+
const summaryFiles = foundFiles.filter(f => /SUMMARY/i.test(f));
|
|
201
|
+
for (const relPath of summaryFiles) {
|
|
202
|
+
try {
|
|
203
|
+
const fullPath = path.join(planningDir, relPath);
|
|
204
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
205
|
+
// Parse frontmatter for commits field
|
|
206
|
+
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
207
|
+
if (!fmMatch) continue;
|
|
208
|
+
const fm = fmMatch[1];
|
|
209
|
+
const commitsMatch = fm.match(/commits:\s*(\[.*?\]|.*)/);
|
|
210
|
+
if (!commitsMatch) {
|
|
211
|
+
warnings.push(`${relPath}: No "commits" field in frontmatter. Executor should record commit hashes.`);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
const commitsVal = commitsMatch[1].trim();
|
|
215
|
+
if (commitsVal === '[]' || commitsVal === '' || commitsVal === '~' || commitsVal === 'null') {
|
|
216
|
+
warnings.push(`${relPath}: "commits" field is empty. Executor may have failed to commit changes.`);
|
|
217
|
+
}
|
|
218
|
+
} catch (_e) { logHook('subagent-validators', 'debug', 'Failed to check summary commits'); }
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Check SUMMARY.md deviations for Rule 3/4 (action: "ask") that require user review.
|
|
224
|
+
* These deviations were flagged by the executor as needing human decision.
|
|
225
|
+
*
|
|
226
|
+
* @param {string} planningDir - Path to .planning/
|
|
227
|
+
* @param {string[]} foundFiles - List of found output files (relative to planningDir)
|
|
228
|
+
* @param {string[]} warnings - Array to push warnings into
|
|
229
|
+
*/
|
|
230
|
+
function checkDeviationsRequiringReview(planningDir, foundFiles, warnings) {
|
|
231
|
+
const summaryFiles = foundFiles.filter(f => /SUMMARY/i.test(f));
|
|
232
|
+
for (const relPath of summaryFiles) {
|
|
233
|
+
try {
|
|
234
|
+
const fullPath = path.join(planningDir, relPath);
|
|
235
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
236
|
+
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
237
|
+
if (!fmMatch) continue;
|
|
238
|
+
const fm = fmMatch[1];
|
|
239
|
+
|
|
240
|
+
// Parse deviations block for items with action: "ask"
|
|
241
|
+
const deviationsIdx = fm.indexOf('deviations:');
|
|
242
|
+
if (deviationsIdx === -1) continue;
|
|
243
|
+
|
|
244
|
+
const afterDeviations = fm.substring(deviationsIdx + 'deviations:'.length);
|
|
245
|
+
const firstLine = afterDeviations.split(/\r?\n/)[0].trim();
|
|
246
|
+
if (firstLine === '[]' || firstLine === 'none' || firstLine === '~' || firstLine === 'null') continue;
|
|
247
|
+
|
|
248
|
+
const askDeviations = [];
|
|
249
|
+
const lines = afterDeviations.split(/\r?\n/);
|
|
250
|
+
let currentItem = null;
|
|
251
|
+
|
|
252
|
+
for (const line of lines) {
|
|
253
|
+
if (/^\s+-\s+rule:/.test(line)) {
|
|
254
|
+
if (currentItem && currentItem.action === 'ask') askDeviations.push(currentItem);
|
|
255
|
+
currentItem = {};
|
|
256
|
+
const ruleMatch = line.match(/rule:\s*(\d+)/);
|
|
257
|
+
if (ruleMatch) currentItem.rule = ruleMatch[1];
|
|
258
|
+
} else if (currentItem) {
|
|
259
|
+
if (/^[a-zA-Z_][a-zA-Z0-9_]*:/.test(line)) {
|
|
260
|
+
if (currentItem.action === 'ask') askDeviations.push(currentItem);
|
|
261
|
+
currentItem = null;
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
const actionMatch = line.match(/^\s+action:\s*["']?(\w+)/);
|
|
265
|
+
if (actionMatch) currentItem.action = actionMatch[1];
|
|
266
|
+
const descMatch = line.match(/^\s+description:\s*["']?(.+?)["']?\s*$/);
|
|
267
|
+
if (descMatch) currentItem.description = descMatch[1];
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
if (currentItem && currentItem.action === 'ask') askDeviations.push(currentItem);
|
|
271
|
+
|
|
272
|
+
if (askDeviations.length > 0) {
|
|
273
|
+
const descriptions = askDeviations
|
|
274
|
+
.map(d => d.description || `Rule ${d.rule || '?'}`)
|
|
275
|
+
.join('; ');
|
|
276
|
+
warnings.push(`Executor flagged ${askDeviations.length} deviation(s) requiring review: ${descriptions}`);
|
|
277
|
+
}
|
|
278
|
+
} catch (_e) { logHook('subagent-validators', 'debug', 'Failed to check deviations in summary'); }
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Log a compliance violation to .planning/logs/compliance.jsonl.
|
|
284
|
+
* These are surfaced to the user at session end by session-cleanup.js.
|
|
285
|
+
* @param {string} planningDir - Path to .planning/
|
|
286
|
+
* @param {string} agentType - Agent that violated
|
|
287
|
+
* @param {string} violation - What was missing or wrong
|
|
288
|
+
* @param {string} severity - 'required' or 'advisory'
|
|
289
|
+
*/
|
|
290
|
+
function logCompliance(planningDir, agentType, violation, severity) {
|
|
291
|
+
try {
|
|
292
|
+
const logsDir = path.join(planningDir, 'logs');
|
|
293
|
+
if (!fs.existsSync(logsDir)) fs.mkdirSync(logsDir, { recursive: true });
|
|
294
|
+
const logFile = path.join(logsDir, 'compliance.jsonl');
|
|
295
|
+
const entry = JSON.stringify({
|
|
296
|
+
ts: new Date().toISOString(),
|
|
297
|
+
agent: agentType,
|
|
298
|
+
violation,
|
|
299
|
+
severity
|
|
300
|
+
});
|
|
301
|
+
fs.appendFileSync(logFile, entry + '\n', 'utf8');
|
|
302
|
+
} catch (_e) { // intentionally silent: compliance logging must not crash hooks
|
|
303
|
+
// Best-effort — never crash the hook
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Check for seeds whose trigger matches the completed phase slug.
|
|
309
|
+
* When an executor completes, check if any seed files in .planning/seeds/
|
|
310
|
+
* have a trigger field matching the current phase slug.
|
|
311
|
+
* @param {string} planningDir - Path to .planning/
|
|
312
|
+
* @param {string[]} warnings - Mutable warnings array to push into
|
|
313
|
+
*/
|
|
314
|
+
function checkTriggeredSeeds(planningDir, warnings) {
|
|
315
|
+
try {
|
|
316
|
+
const seedsDir = path.join(planningDir, 'seeds');
|
|
317
|
+
if (!fs.existsSync(seedsDir)) return;
|
|
318
|
+
|
|
319
|
+
// Get current phase slug from STATE.md
|
|
320
|
+
const stateFile = path.join(planningDir, 'STATE.md');
|
|
321
|
+
if (!fs.existsSync(stateFile)) return;
|
|
322
|
+
const stateContent = fs.readFileSync(stateFile, 'utf8');
|
|
323
|
+
const slugMatch = stateContent.match(/^phase_slug:\s*"?([^"\n]+)"?/mi);
|
|
324
|
+
if (!slugMatch) return;
|
|
325
|
+
const phaseSlug = slugMatch[1].trim();
|
|
326
|
+
|
|
327
|
+
const seeds = fs.readdirSync(seedsDir).filter(f => f.endsWith('.md'));
|
|
328
|
+
const triggered = [];
|
|
329
|
+
for (const seed of seeds) {
|
|
330
|
+
try {
|
|
331
|
+
const content = fs.readFileSync(path.join(seedsDir, seed), 'utf-8');
|
|
332
|
+
const triggerMatch = content.match(/trigger:\s*"([^"]+)"/);
|
|
333
|
+
if (triggerMatch && phaseSlug.includes(triggerMatch[1])) {
|
|
334
|
+
const idMatch = seed.match(/SEED-(\d+)/);
|
|
335
|
+
triggered.push({ id: idMatch ? idMatch[1] : seed, trigger: triggerMatch[1] });
|
|
336
|
+
}
|
|
337
|
+
} catch (_e) { /* intentionally silent: seed file may be unreadable */ }
|
|
338
|
+
}
|
|
339
|
+
if (triggered.length > 0) {
|
|
340
|
+
const seedList = triggered.map(s => `SEED-${s.id} (trigger: ${s.trigger})`).join(', ');
|
|
341
|
+
warnings.push(`Seed(s) triggered by phase completion: ${seedList}. Review with /pbr:explore.`);
|
|
342
|
+
}
|
|
343
|
+
} catch (_e) { logHook('subagent-validators', 'debug', 'Failed to check triggered seeds'); }
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Check that LEARNINGS.md exists in the current phase directory.
|
|
348
|
+
* LEARNINGS.md is REQUIRED for all agents — every agent must document what it learned.
|
|
349
|
+
* @param {string} planningDir - Path to .planning/
|
|
350
|
+
* @param {string[]} warnings - Mutable warnings array to push into
|
|
351
|
+
* @param {string} agentLabel - Human-readable agent label for the warning message
|
|
352
|
+
*/
|
|
353
|
+
function checkLearningsRequired(planningDir, warnings, agentLabel) {
|
|
354
|
+
const learningsFiles = findInPhaseDir(planningDir, /^LEARNINGS\.md$/i);
|
|
355
|
+
if (learningsFiles.length === 0) {
|
|
356
|
+
warnings.push(`[REQUIRED] No LEARNINGS.md found in phase directory. The ${agentLabel} agent MUST write LEARNINGS.md documenting what it learned — patterns discovered, pitfalls avoided, decisions made. This is required for cross-phase knowledge transfer.`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Agent type -> expected output patterns
|
|
361
|
+
const AGENT_OUTPUTS = {
|
|
362
|
+
'pbr:executor': {
|
|
363
|
+
description: 'SUMMARY.md in the phase or quick directory',
|
|
364
|
+
check: (planningDir) => {
|
|
365
|
+
// Check phase directory first, then quick directory
|
|
366
|
+
const phaseMatches = findInPhaseDir(planningDir, /^SUMMARY.*\.md$/i);
|
|
367
|
+
if (phaseMatches.length > 0) return phaseMatches;
|
|
368
|
+
return findInQuickDir(planningDir, /^SUMMARY.*\.md$/i);
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
'pbr:planner': {
|
|
372
|
+
description: 'PLAN.md in the phase directory',
|
|
373
|
+
check: (planningDir) => findInPhaseDir(planningDir, /^PLAN.*\.md$/i)
|
|
374
|
+
},
|
|
375
|
+
'pbr:verifier': {
|
|
376
|
+
description: 'VERIFICATION.md or VERIFICATION-R{N}.md in the phase directory',
|
|
377
|
+
check: (planningDir) => findInPhaseDir(planningDir, /^VERIFICATION(-R\d+)?\.md$/i)
|
|
378
|
+
},
|
|
379
|
+
'pbr:researcher': {
|
|
380
|
+
description: 'research file in .planning/research/',
|
|
381
|
+
check: (planningDir) => {
|
|
382
|
+
const researchDir = path.join(planningDir, 'research');
|
|
383
|
+
if (!fs.existsSync(researchDir)) return [];
|
|
384
|
+
try {
|
|
385
|
+
const allFiles = fs.readdirSync(researchDir)
|
|
386
|
+
.filter(f => f.endsWith('.md'))
|
|
387
|
+
.map(f => path.join('research', f));
|
|
388
|
+
if (allFiles.length === 0) return [];
|
|
389
|
+
const recentFiles = allFiles.filter(f => isRecent(path.join(planningDir, f)));
|
|
390
|
+
if (recentFiles.length === 0) {
|
|
391
|
+
// Files exist but none are recent — return them but flag staleness
|
|
392
|
+
allFiles._stale = true;
|
|
393
|
+
}
|
|
394
|
+
return allFiles;
|
|
395
|
+
} catch (_e) { // intentionally silent: directory listing may fail
|
|
396
|
+
return [];
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
'pbr:synthesizer': {
|
|
401
|
+
description: 'synthesis file in .planning/research/ or CONTEXT.md update',
|
|
402
|
+
check: (planningDir) => {
|
|
403
|
+
const researchDir = path.join(planningDir, 'research');
|
|
404
|
+
if (fs.existsSync(researchDir)) {
|
|
405
|
+
try {
|
|
406
|
+
const files = fs.readdirSync(researchDir).filter(f => f.endsWith('.md'));
|
|
407
|
+
if (files.length > 0) {
|
|
408
|
+
const allFiles = files.map(f => path.join('research', f));
|
|
409
|
+
const recentFiles = allFiles.filter(f => isRecent(path.join(planningDir, f)));
|
|
410
|
+
if (recentFiles.length === 0) {
|
|
411
|
+
allFiles._stale = true;
|
|
412
|
+
}
|
|
413
|
+
return allFiles;
|
|
414
|
+
}
|
|
415
|
+
} catch (_e) { /* intentionally silent: directory listing may fail */ }
|
|
416
|
+
}
|
|
417
|
+
const contextFile = path.join(planningDir, 'CONTEXT.md');
|
|
418
|
+
if (fs.existsSync(contextFile)) {
|
|
419
|
+
try {
|
|
420
|
+
const stat = fs.statSync(contextFile);
|
|
421
|
+
if (stat.size > 0) {
|
|
422
|
+
const result = ['CONTEXT.md'];
|
|
423
|
+
if (!isRecent(contextFile)) {
|
|
424
|
+
result._stale = true;
|
|
425
|
+
}
|
|
426
|
+
return result;
|
|
427
|
+
}
|
|
428
|
+
} catch (_e) { /* intentionally silent: directory listing may fail */ }
|
|
429
|
+
}
|
|
430
|
+
return [];
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
'pbr:plan-checker': {
|
|
434
|
+
description: 'advisory output (no file expected)',
|
|
435
|
+
noFileExpected: true,
|
|
436
|
+
check: () => []
|
|
437
|
+
},
|
|
438
|
+
'pbr:integration-checker': {
|
|
439
|
+
description: 'INTEGRATION-REPORT.md in the phase directory',
|
|
440
|
+
check: (planningDir) => findInPhaseDir(planningDir, /^INTEGRATION-REPORT\.md$/i)
|
|
441
|
+
},
|
|
442
|
+
'pbr:debugger': {
|
|
443
|
+
description: 'debug file in .planning/debug/',
|
|
444
|
+
check: (planningDir) => {
|
|
445
|
+
const debugDir = path.join(planningDir, 'debug');
|
|
446
|
+
if (!fs.existsSync(debugDir)) return [];
|
|
447
|
+
try {
|
|
448
|
+
return fs.readdirSync(debugDir)
|
|
449
|
+
.filter(f => f.endsWith('.md'))
|
|
450
|
+
.map(f => path.join('debug', f));
|
|
451
|
+
} catch (_e) { // intentionally silent: directory listing may fail
|
|
452
|
+
return [];
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
'pbr:codebase-mapper': {
|
|
457
|
+
description: 'codebase map in .planning/codebase/',
|
|
458
|
+
check: (planningDir) => {
|
|
459
|
+
const codebaseDir = path.join(planningDir, 'codebase');
|
|
460
|
+
if (!fs.existsSync(codebaseDir)) return [];
|
|
461
|
+
try {
|
|
462
|
+
return fs.readdirSync(codebaseDir)
|
|
463
|
+
.filter(f => f.endsWith('.md'))
|
|
464
|
+
.map(f => path.join('codebase', f));
|
|
465
|
+
} catch (_e) { // intentionally silent: directory listing may fail
|
|
466
|
+
return [];
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
},
|
|
470
|
+
'pbr:general': {
|
|
471
|
+
description: 'advisory output (no file expected)',
|
|
472
|
+
noFileExpected: true,
|
|
473
|
+
check: () => []
|
|
474
|
+
},
|
|
475
|
+
'pbr:audit': {
|
|
476
|
+
description: 'audit report in .planning/audits/',
|
|
477
|
+
check: (planningDir) => {
|
|
478
|
+
const auditsDir = path.join(planningDir, 'audits');
|
|
479
|
+
if (!fs.existsSync(auditsDir)) return [];
|
|
480
|
+
try {
|
|
481
|
+
return fs.readdirSync(auditsDir)
|
|
482
|
+
.filter(f => f.endsWith('.md'))
|
|
483
|
+
.map(f => path.join('audits', f));
|
|
484
|
+
} catch (_e) { // intentionally silent: directory listing may fail
|
|
485
|
+
return [];
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
},
|
|
489
|
+
'pbr:dev-sync': {
|
|
490
|
+
description: 'advisory output (no file expected)',
|
|
491
|
+
noFileExpected: true,
|
|
492
|
+
check: () => []
|
|
493
|
+
},
|
|
494
|
+
'pbr:intel-updater': {
|
|
495
|
+
description: 'intel files in .planning/intel/',
|
|
496
|
+
check: (planningDir) => {
|
|
497
|
+
const intelDir = path.join(planningDir, 'intel');
|
|
498
|
+
if (!fs.existsSync(intelDir)) return [];
|
|
499
|
+
try {
|
|
500
|
+
return fs.readdirSync(intelDir)
|
|
501
|
+
.filter(f => f.endsWith('.md') || f.endsWith('.json'))
|
|
502
|
+
.map(f => path.join('intel', f));
|
|
503
|
+
} catch (_e) { // intentionally silent: directory listing may fail
|
|
504
|
+
return [];
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
},
|
|
508
|
+
'pbr:ui-checker': {
|
|
509
|
+
description: 'UI-REVIEW.md in the phase directory',
|
|
510
|
+
check: (planningDir) => findInPhaseDir(planningDir, /^UI-REVIEW\.md$/i)
|
|
511
|
+
},
|
|
512
|
+
'pbr:ui-researcher': {
|
|
513
|
+
description: 'UI-SPEC.md in the phase directory',
|
|
514
|
+
check: (planningDir) => findInPhaseDir(planningDir, /^UI-SPEC\.md$/i)
|
|
515
|
+
},
|
|
516
|
+
'pbr:roadmapper': {
|
|
517
|
+
description: 'ROADMAP.md in .planning/',
|
|
518
|
+
check: (planningDir) => {
|
|
519
|
+
const roadmapPath = path.join(planningDir, 'ROADMAP.md');
|
|
520
|
+
if (fs.existsSync(roadmapPath)) {
|
|
521
|
+
const result = ['ROADMAP.md'];
|
|
522
|
+
if (!isRecent(roadmapPath)) {
|
|
523
|
+
result._stale = true;
|
|
524
|
+
}
|
|
525
|
+
return result;
|
|
526
|
+
}
|
|
527
|
+
return [];
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
'pbr:nyquist-auditor': {
|
|
531
|
+
description: 'VALIDATION.md in the phase directory',
|
|
532
|
+
check: (planningDir) => {
|
|
533
|
+
const phaseMatches = findInPhaseDir(planningDir, /^VALIDATION\.md$/i);
|
|
534
|
+
return phaseMatches;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Check if ROADMAP.md is stale after executor/verifier completion.
|
|
541
|
+
* Detects: (1) no Progress table for current milestone, (2) table exists but
|
|
542
|
+
* phase row is out of date vs. phase artifacts on disk.
|
|
543
|
+
*
|
|
544
|
+
* @param {string} planningDir - Path to .planning/
|
|
545
|
+
* @returns {string|null} Warning message or null if in sync
|
|
546
|
+
*/
|
|
547
|
+
function checkRoadmapStaleness(planningDir) {
|
|
548
|
+
const roadmapPath = path.join(planningDir, 'ROADMAP.md');
|
|
549
|
+
if (!fs.existsSync(roadmapPath)) return null;
|
|
550
|
+
|
|
551
|
+
try {
|
|
552
|
+
const content = fs.readFileSync(roadmapPath, 'utf8');
|
|
553
|
+
|
|
554
|
+
// Check if there's a Progress table at all
|
|
555
|
+
const hasProgressTable = /Plans\s*Complete/i.test(content);
|
|
556
|
+
if (!hasProgressTable) {
|
|
557
|
+
return 'ROADMAP.md has no Progress table for the current milestone. The orchestrator should add a Progress table with columns: Phase | Plans Complete | Status | Completed. See skills/shared/state-update.md for format.';
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// If table exists, check if current phase row is present
|
|
561
|
+
const stateFile = path.join(planningDir, 'STATE.md');
|
|
562
|
+
if (fs.existsSync(stateFile)) {
|
|
563
|
+
const stateContent = fs.readFileSync(stateFile, 'utf8');
|
|
564
|
+
const currentPhase = getCurrentPhase(stateContent);
|
|
565
|
+
if (currentPhase) {
|
|
566
|
+
const paddedPhase = currentPhase.padStart(2, '0');
|
|
567
|
+
const phaseInTable = new RegExp(`\\|\\s*${paddedPhase}\\.`).test(content) ||
|
|
568
|
+
new RegExp(`\\|\\s*${parseInt(currentPhase, 10)}\\.`).test(content);
|
|
569
|
+
if (!phaseInTable) {
|
|
570
|
+
return `ROADMAP.md Progress table exists but has no row for Phase ${currentPhase}. Add a row for the current phase.`;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
} catch (_e) { // intentionally silent: roadmap check is best-effort
|
|
575
|
+
// best-effort
|
|
576
|
+
}
|
|
577
|
+
return null;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Skill-specific check lookup table keyed by 'activeSkill:agentType'
|
|
581
|
+
const SKILL_CHECKS = {
|
|
582
|
+
'begin:pbr:planner': {
|
|
583
|
+
description: 'begin planner core files',
|
|
584
|
+
check: (planningDir, _found, warnings) => {
|
|
585
|
+
const coreFiles = ['REQUIREMENTS.md', 'ROADMAP.md', 'STATE.md'];
|
|
586
|
+
for (const f of coreFiles) {
|
|
587
|
+
if (!fs.existsSync(path.join(planningDir, f))) {
|
|
588
|
+
warnings.push(`Begin planner: ${f} was not created. The project may be in an incomplete state.`);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
'plan:pbr:researcher': {
|
|
594
|
+
description: 'plan researcher phase-level RESEARCH.md and LEARNINGS.md',
|
|
595
|
+
check: (planningDir, found, warnings) => {
|
|
596
|
+
const phaseResearch = findInPhaseDir(planningDir, /^RESEARCH\.md$/i);
|
|
597
|
+
if (found.length === 0 && phaseResearch.length === 0) {
|
|
598
|
+
warnings.push('Plan researcher: No research output found in .planning/research/ or in the phase directory.');
|
|
599
|
+
}
|
|
600
|
+
checkLearningsRequired(planningDir, warnings, 'researcher');
|
|
601
|
+
}
|
|
602
|
+
},
|
|
603
|
+
'plan:pbr:planner': {
|
|
604
|
+
description: 'plan planner LEARNINGS.md and handoff completeness',
|
|
605
|
+
check: (planningDir, found, warnings) => {
|
|
606
|
+
checkLearningsRequired(planningDir, warnings, 'planner');
|
|
607
|
+
// Handoff completeness check (REQ-HI-03)
|
|
608
|
+
const planFiles = (found || []).filter(f => /PLAN/i.test(f));
|
|
609
|
+
for (const relPath of planFiles) {
|
|
610
|
+
try {
|
|
611
|
+
const fullPath = path.join(planningDir, relPath);
|
|
612
|
+
const result = handoff.validatePlanCompleteness(fullPath);
|
|
613
|
+
if (!result.adequate) {
|
|
614
|
+
warnings.push(...result.warnings.map(w => `Handoff: ${w}`));
|
|
615
|
+
}
|
|
616
|
+
} catch (_e) { /* intentionally silent: handoff check must not crash hooks */ }
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
},
|
|
620
|
+
'scan:pbr:codebase-mapper': {
|
|
621
|
+
description: 'scan codebase-mapper 4 focus areas',
|
|
622
|
+
check: (planningDir, _found, warnings) => {
|
|
623
|
+
const expectedAreas = ['tech', 'arch', 'quality', 'concerns'];
|
|
624
|
+
const codebaseDir = path.join(planningDir, 'codebase');
|
|
625
|
+
if (fs.existsSync(codebaseDir)) {
|
|
626
|
+
try {
|
|
627
|
+
const files = fs.readdirSync(codebaseDir).map(f => f.toLowerCase());
|
|
628
|
+
for (const area of expectedAreas) {
|
|
629
|
+
if (!files.some(f => f.includes(area))) {
|
|
630
|
+
warnings.push(`Scan mapper: No output file containing "${area}" found in .planning/codebase/. One of the 4 mappers may have failed.`);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
} catch (_e) { /* intentionally silent: directory listing may fail */ }
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
},
|
|
637
|
+
'review:pbr:verifier': {
|
|
638
|
+
description: 'review verifier VERIFICATION.md status, LEARNINGS.md, and trust update',
|
|
639
|
+
check: (planningDir, _found, warnings) => {
|
|
640
|
+
const verFiles = findInPhaseDir(planningDir, /^VERIFICATION(-R\d+)?\.md$/i);
|
|
641
|
+
for (const vf of verFiles) {
|
|
642
|
+
logHook('subagent-validators', 'debug', 'Found verification file: ' + vf);
|
|
643
|
+
try {
|
|
644
|
+
const content = fs.readFileSync(path.join(planningDir, vf), 'utf8');
|
|
645
|
+
const statusMatch = content.match(/^status:\s*(\S+)/mi);
|
|
646
|
+
if (statusMatch && statusMatch[1] === 'gaps_found') {
|
|
647
|
+
warnings.push('Review verifier: VERIFICATION.md has status "gaps_found" — ensure gaps are surfaced to the user.');
|
|
648
|
+
}
|
|
649
|
+
} catch (_e) { logHook('subagent-validators', 'debug', 'Skill check failed in review:pbr:verifier'); }
|
|
650
|
+
}
|
|
651
|
+
checkLearningsRequired(planningDir, warnings, 'verifier');
|
|
652
|
+
// Handoff completeness check (REQ-HI-03)
|
|
653
|
+
for (const vf of verFiles) {
|
|
654
|
+
try {
|
|
655
|
+
const fullPath = path.join(planningDir, vf);
|
|
656
|
+
const result = handoff.validateVerificationCompleteness(fullPath);
|
|
657
|
+
if (!result.adequate) {
|
|
658
|
+
warnings.push(...result.warnings.map(w => `Handoff: ${w}`));
|
|
659
|
+
}
|
|
660
|
+
} catch (_e) { /* intentionally silent: handoff check must not crash hooks */ }
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// Trust score update: record verification outcome
|
|
664
|
+
try {
|
|
665
|
+
if (!shouldTrackTrust(planningDir)) return;
|
|
666
|
+
const outcome = extractVerificationOutcome(planningDir);
|
|
667
|
+
if (!outcome) return;
|
|
668
|
+
const { recordOutcome } = require('../trust-tracker');
|
|
669
|
+
recordOutcome(planningDir, 'pbr:executor', outcome.category, outcome.passed);
|
|
670
|
+
recordOutcome(planningDir, 'pbr:verifier', outcome.category, true);
|
|
671
|
+
logHook('check-subagent-output', 'PostToolUse', 'trust-updated', {
|
|
672
|
+
agent: 'pbr:executor',
|
|
673
|
+
category: outcome.category,
|
|
674
|
+
passed: outcome.passed
|
|
675
|
+
});
|
|
676
|
+
} catch (_e) { logHook('subagent-validators', 'debug', 'Skill check error in review:pbr:verifier');
|
|
677
|
+
// Never crash the hook for trust tracking failures
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
},
|
|
681
|
+
'build:pbr:executor': {
|
|
682
|
+
description: 'build executor SUMMARY commits, self-check, LEARNINGS.md, and convention update',
|
|
683
|
+
check: (planningDir, found, warnings) => {
|
|
684
|
+
// Warn if no SUMMARY.md was created by the executor
|
|
685
|
+
if (found.length === 0) {
|
|
686
|
+
warnings.push('Build executor completed but no SUMMARY.md was found in the phase or quick directory. The executor may have skipped artifact creation. Re-run the build skill to generate the missing artifact.');
|
|
687
|
+
}
|
|
688
|
+
checkSummaryCommits(planningDir, found, warnings);
|
|
689
|
+
// Check for deviations requiring user review (Rule 3/4 with action: "ask")
|
|
690
|
+
checkDeviationsRequiringReview(planningDir, found, warnings);
|
|
691
|
+
// Validate self-verification ran when feature is enabled
|
|
692
|
+
const summaryFiles = found.filter(f => /SUMMARY/i.test(f));
|
|
693
|
+
for (const relPath of summaryFiles) {
|
|
694
|
+
try {
|
|
695
|
+
const fullPath = path.join(planningDir, relPath);
|
|
696
|
+
const { resolveConfig } = require('./config');
|
|
697
|
+
const config = resolveConfig(planningDir);
|
|
698
|
+
const selfCheckWarnings = validateSelfCheck(fullPath, config);
|
|
699
|
+
warnings.push(...selfCheckWarnings);
|
|
700
|
+
} catch (_e) { logHook('subagent-validators', 'debug', 'Skill check failed in build:pbr:executor'); }
|
|
701
|
+
}
|
|
702
|
+
// Handoff completeness check (REQ-HI-03)
|
|
703
|
+
for (const relPath of summaryFiles) {
|
|
704
|
+
try {
|
|
705
|
+
const fullPath = path.join(planningDir, relPath);
|
|
706
|
+
const result = handoff.validateSummaryCompleteness(fullPath);
|
|
707
|
+
if (!result.adequate) {
|
|
708
|
+
warnings.push(...result.warnings.map(w => `Handoff: ${w}`));
|
|
709
|
+
}
|
|
710
|
+
} catch (_e) { /* intentionally silent: handoff check must not crash hooks */ }
|
|
711
|
+
}
|
|
712
|
+
// Extract feedback for agent prompt enrichment
|
|
713
|
+
try {
|
|
714
|
+
const { extractFeedback, isEnabled } = require('../feedback-loop');
|
|
715
|
+
if (isEnabled(planningDir)) {
|
|
716
|
+
const phaseDirMatches = found.filter(f => /^phases[/\\]/.test(f));
|
|
717
|
+
const phaseDir = phaseDirMatches.length > 0
|
|
718
|
+
? path.join(planningDir, phaseDirMatches[0].split(/[/\\]/).slice(0, 2).join(path.sep))
|
|
719
|
+
: null;
|
|
720
|
+
if (phaseDir) {
|
|
721
|
+
const feedback = extractFeedback(phaseDir);
|
|
722
|
+
if (feedback) {
|
|
723
|
+
warnings.push(`Feedback loop: ${feedback.summary || 'verification feedback recorded'}`);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
} catch (_e) { logHook('subagent-validators', 'debug', 'Skill check failed in build:pbr:executor'); }
|
|
728
|
+
checkLearningsRequired(planningDir, warnings, 'executor');
|
|
729
|
+
// Check for seeds triggered by this phase completion
|
|
730
|
+
checkTriggeredSeeds(planningDir, warnings);
|
|
731
|
+
// Log post-hoc skip for non-quick executors (audit evidence)
|
|
732
|
+
const { logEvent } = require('../event-logger');
|
|
733
|
+
logEvent('post_hoc', 'post_hoc_skipped', { reason: 'not_quick_task', feature: 'post_hoc_artifacts' });
|
|
734
|
+
// Update conventions after successful build
|
|
735
|
+
updateConventionsAfterBuild(planningDir);
|
|
736
|
+
// Log inline execution decision for audit
|
|
737
|
+
try {
|
|
738
|
+
const inlineSignal = path.join(planningDir, '.inline-active');
|
|
739
|
+
const wasInline = fs.existsSync(inlineSignal);
|
|
740
|
+
logInlineDecision(planningDir, {
|
|
741
|
+
inline: wasInline,
|
|
742
|
+
decision: wasInline ? 'inline' : 'delegate',
|
|
743
|
+
reason: wasInline ? 'signal file present' : 'normal task spawn',
|
|
744
|
+
taskCount: found.filter(f => /SUMMARY/i.test(f)).length,
|
|
745
|
+
fileCount: 0
|
|
746
|
+
});
|
|
747
|
+
} catch (_e) { /* intentionally silent: audit logging must not crash hooks */ }
|
|
748
|
+
}
|
|
749
|
+
},
|
|
750
|
+
'quick:pbr:executor': {
|
|
751
|
+
description: 'quick executor SUMMARY commits and post-hoc generation',
|
|
752
|
+
check: (planningDir, found, warnings) => {
|
|
753
|
+
checkSummaryCommits(planningDir, found, warnings);
|
|
754
|
+
// Post-hoc SUMMARY.md generation for quick tasks
|
|
755
|
+
const postHocEnabled = loadFeatureFlag(planningDir, 'post_hoc_artifacts');
|
|
756
|
+
if (postHocEnabled === false) {
|
|
757
|
+
const { logEvent } = require('../event-logger');
|
|
758
|
+
logEvent('post_hoc', 'post_hoc_skipped', { reason: 'feature_disabled', feature: 'post_hoc_artifacts' });
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
// Check if SUMMARY.md is missing in the quick dir
|
|
762
|
+
const quickSummaries = findInQuickDir(planningDir, /^SUMMARY.*\.md$/i);
|
|
763
|
+
if (quickSummaries.length > 0) return; // Already exists, no need for post-hoc
|
|
764
|
+
// Find the latest quick task directory
|
|
765
|
+
const quickDir = path.join(planningDir, 'quick');
|
|
766
|
+
if (!fs.existsSync(quickDir)) return;
|
|
767
|
+
try {
|
|
768
|
+
const dirs = fs.readdirSync(quickDir)
|
|
769
|
+
.filter(d => /^\d{3}-/.test(d))
|
|
770
|
+
.sort()
|
|
771
|
+
.reverse();
|
|
772
|
+
if (dirs.length === 0) return;
|
|
773
|
+
const taskDir = path.join(quickDir, dirs[0]);
|
|
774
|
+
const taskSlug = dirs[0];
|
|
775
|
+
// Attempt post-hoc generation
|
|
776
|
+
try {
|
|
777
|
+
const { generateSummary } = require(path.join(__dirname, 'post-hoc'));
|
|
778
|
+
const projectRoot = path.resolve(planningDir, '..');
|
|
779
|
+
const result = generateSummary(projectRoot, taskDir, {
|
|
780
|
+
commitPattern: taskSlug.replace(/^(\d{3})-.*/, 'quick-$1')
|
|
781
|
+
});
|
|
782
|
+
const { logEvent } = require('../event-logger');
|
|
783
|
+
logEvent('post_hoc', 'post_hoc_summary_generated', {
|
|
784
|
+
taskDir: taskSlug,
|
|
785
|
+
commitCount: result.commitCount,
|
|
786
|
+
feature: 'post_hoc_artifacts',
|
|
787
|
+
timestamp: new Date().toISOString()
|
|
788
|
+
});
|
|
789
|
+
warnings.push(`SUMMARY.md auto-generated post-hoc for quick task ${taskSlug} (${result.commitCount} commits found)`);
|
|
790
|
+
} catch (_genErr) { // error logged via logEvent below
|
|
791
|
+
const { logEvent } = require('../event-logger');
|
|
792
|
+
logEvent('post_hoc', 'post_hoc_generation_failed', {
|
|
793
|
+
taskDir: taskSlug,
|
|
794
|
+
error: _genErr.message,
|
|
795
|
+
feature: 'post_hoc_artifacts'
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
} catch (_e) { logHook('subagent-validators', 'debug', 'Failed in quick executor post-hoc check'); }
|
|
799
|
+
}
|
|
800
|
+
},
|
|
801
|
+
'begin:pbr:researcher': {
|
|
802
|
+
description: 'begin researcher YAML frontmatter validation',
|
|
803
|
+
check: (planningDir, found, warnings) => {
|
|
804
|
+
const EXPECTED_NAMES = ['STACK.md', 'FEATURES.md', 'ARCHITECTURE.md', 'PITFALLS.md'];
|
|
805
|
+
for (const relPath of found) {
|
|
806
|
+
const basename = path.basename(relPath);
|
|
807
|
+
// Skip SUMMARY.md -- that's synthesizer output
|
|
808
|
+
if (basename.toUpperCase() === 'SUMMARY.MD') continue;
|
|
809
|
+
try {
|
|
810
|
+
// Warn if unexpected filename
|
|
811
|
+
if (!EXPECTED_NAMES.includes(basename)) {
|
|
812
|
+
warnings.push(`${basename}: unexpected research file name. Expected one of: ${EXPECTED_NAMES.join(', ')}`);
|
|
813
|
+
}
|
|
814
|
+
// Read and validate YAML frontmatter
|
|
815
|
+
const fullPath = path.join(planningDir, relPath);
|
|
816
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
817
|
+
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
818
|
+
if (!fmMatch) {
|
|
819
|
+
warnings.push(`${basename}: YAML frontmatter is missing. Researcher output must include frontmatter with confidence and sources_checked fields.`);
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
const fm = fmMatch[1];
|
|
823
|
+
if (!/confidence\s*:/i.test(fm)) {
|
|
824
|
+
warnings.push(`${basename}: frontmatter missing "confidence" field.`);
|
|
825
|
+
}
|
|
826
|
+
if (!/sources_checked\s*:/i.test(fm)) {
|
|
827
|
+
warnings.push(`${basename}: frontmatter missing "sources_checked" field.`);
|
|
828
|
+
}
|
|
829
|
+
} catch (_e) { /* intentionally silent: directory listing may fail */ }
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
},
|
|
833
|
+
'begin:pbr:roadmapper': {
|
|
834
|
+
description: 'begin roadmapper LEARNINGS.md',
|
|
835
|
+
check: (planningDir, _found, warnings) => {
|
|
836
|
+
checkLearningsRequired(planningDir, warnings, 'roadmapper');
|
|
837
|
+
}
|
|
838
|
+
},
|
|
839
|
+
'debug:pbr:debugger': {
|
|
840
|
+
description: 'debug agent LEARNINGS.md',
|
|
841
|
+
check: (planningDir, _found, warnings) => {
|
|
842
|
+
// Debugger writes to .planning/debug/ — check LEARNINGS there
|
|
843
|
+
const debugDir = path.join(planningDir, 'debug');
|
|
844
|
+
if (!fs.existsSync(debugDir)) return;
|
|
845
|
+
try {
|
|
846
|
+
const files = fs.readdirSync(debugDir);
|
|
847
|
+
const hasLearnings = files.some(f => /^LEARNINGS/i.test(f));
|
|
848
|
+
if (!hasLearnings) {
|
|
849
|
+
warnings.push('[REQUIRED] No LEARNINGS.md found in .planning/debug/. The debugger agent MUST document what it learned — root causes found, debugging approaches that worked, environment quirks discovered.');
|
|
850
|
+
}
|
|
851
|
+
} catch (_e) { /* intentionally silent: directory listing may fail */ }
|
|
852
|
+
}
|
|
853
|
+
},
|
|
854
|
+
'begin:pbr:synthesizer': {
|
|
855
|
+
description: 'begin synthesizer SUMMARY.md structure validation',
|
|
856
|
+
check: (planningDir, _found, warnings) => {
|
|
857
|
+
// Check for SUMMARY.md in research directory
|
|
858
|
+
const researchDir = path.join(planningDir, 'research');
|
|
859
|
+
const summaryPath = path.join(researchDir, 'SUMMARY.md');
|
|
860
|
+
try {
|
|
861
|
+
if (!fs.existsSync(summaryPath)) {
|
|
862
|
+
warnings.push('SUMMARY.md not found in .planning/research/. Synthesizer must produce a SUMMARY.md.');
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
const content = fs.readFileSync(summaryPath, 'utf8');
|
|
866
|
+
// Check for Research Coverage table
|
|
867
|
+
if (!/research\s+coverage/i.test(content)) {
|
|
868
|
+
warnings.push('SUMMARY.md missing "Research Coverage" table.');
|
|
869
|
+
}
|
|
870
|
+
// Check for Confidence Assessment table
|
|
871
|
+
if (!/confidence\s+assessment/i.test(content)) {
|
|
872
|
+
warnings.push('SUMMARY.md missing "Confidence Assessment" table.');
|
|
873
|
+
}
|
|
874
|
+
// Check all 4 dimensions are referenced
|
|
875
|
+
const dimensions = ['Stack', 'Features', 'Architecture', 'Pitfalls'];
|
|
876
|
+
for (const dim of dimensions) {
|
|
877
|
+
if (!new RegExp(dim, 'i').test(content)) {
|
|
878
|
+
warnings.push(`SUMMARY.md missing dimension: ${dim}. All 4 research dimensions must be covered.`);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
} catch (_e) { /* intentionally silent: directory listing may fail */ }
|
|
882
|
+
}
|
|
883
|
+
},
|
|
884
|
+
'milestone:pbr:general': {
|
|
885
|
+
description: 'milestone archive completeness validation',
|
|
886
|
+
check: (planningDir, _found, warnings) => {
|
|
887
|
+
// After milestone completion, verify the archive structure
|
|
888
|
+
const milestonesDir = path.join(planningDir, 'milestones');
|
|
889
|
+
if (!fs.existsSync(milestonesDir)) return;
|
|
890
|
+
|
|
891
|
+
try {
|
|
892
|
+
// Find the most recent milestone archive (highest version)
|
|
893
|
+
const archiveDirs = fs.readdirSync(milestonesDir)
|
|
894
|
+
.filter(d => d.startsWith('v') && fs.statSync(path.join(milestonesDir, d)).isDirectory())
|
|
895
|
+
.sort()
|
|
896
|
+
.reverse();
|
|
897
|
+
|
|
898
|
+
if (archiveDirs.length === 0) return;
|
|
899
|
+
|
|
900
|
+
const latestArchive = path.join(milestonesDir, archiveDirs[0]);
|
|
901
|
+
const archiveFiles = fs.readdirSync(latestArchive);
|
|
902
|
+
|
|
903
|
+
// Check for required archive files
|
|
904
|
+
if (!archiveFiles.includes('ROADMAP.md')) {
|
|
905
|
+
warnings.push(`[REQUIRED] Milestone archive ${archiveDirs[0]}: missing ROADMAP.md snapshot`);
|
|
906
|
+
}
|
|
907
|
+
if (!archiveFiles.includes('STATS.md')) {
|
|
908
|
+
warnings.push(`[REQUIRED] Milestone archive ${archiveDirs[0]}: missing STATS.md summary`);
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
// Check for phases/ subdirectory with per-phase artifacts
|
|
912
|
+
const archivePhasesDir = path.join(latestArchive, 'phases');
|
|
913
|
+
if (fs.existsSync(archivePhasesDir)) {
|
|
914
|
+
const phaseDirs = fs.readdirSync(archivePhasesDir)
|
|
915
|
+
.filter(d => fs.statSync(path.join(archivePhasesDir, d)).isDirectory());
|
|
916
|
+
|
|
917
|
+
for (const pd of phaseDirs) {
|
|
918
|
+
const phaseFiles = fs.readdirSync(path.join(archivePhasesDir, pd));
|
|
919
|
+
const hasPlan = phaseFiles.some(f => /^PLAN/i.test(f));
|
|
920
|
+
const hasSummary = phaseFiles.some(f => /^SUMMARY/i.test(f));
|
|
921
|
+
const hasVerification = phaseFiles.some(f => f === 'VERIFICATION.md');
|
|
922
|
+
|
|
923
|
+
if (!hasPlan) warnings.push(`[REQUIRED] Archive phase ${pd}: missing PLAN.md`);
|
|
924
|
+
if (!hasSummary) warnings.push(`[REQUIRED] Archive phase ${pd}: missing SUMMARY.md`);
|
|
925
|
+
if (!hasVerification) warnings.push(`[REQUIRED] Archive phase ${pd}: missing VERIFICATION.md`);
|
|
926
|
+
}
|
|
927
|
+
} else {
|
|
928
|
+
warnings.push(`[REQUIRED] Milestone archive ${archiveDirs[0]}: missing phases/ subdirectory`);
|
|
929
|
+
}
|
|
930
|
+
} catch (_e) { logHook('subagent-validators', 'debug', 'Failed in milestone archive validation'); }
|
|
931
|
+
}
|
|
932
|
+
},
|
|
933
|
+
'autonomous:pbr:executor': {
|
|
934
|
+
description: 'autonomous executor reminder to verify phase before completion',
|
|
935
|
+
check: (planningDir, _found, warnings) => {
|
|
936
|
+
// When executor completes during autonomous mode, remind the orchestrator
|
|
937
|
+
// to run Step 3d (verification) before proceeding to Step 3e (phase complete).
|
|
938
|
+
// This catches the known failure mode where the LLM skips verification.
|
|
939
|
+
try {
|
|
940
|
+
const statePath = path.join(planningDir, 'STATE.md');
|
|
941
|
+
if (!fs.existsSync(statePath)) return;
|
|
942
|
+
const stateContent = fs.readFileSync(statePath, 'utf8');
|
|
943
|
+
const phase = getCurrentPhase(stateContent);
|
|
944
|
+
if (!phase) return;
|
|
945
|
+
const padded = String(phase).padStart(2, '0');
|
|
946
|
+
const phasesDir = path.join(planningDir, 'phases');
|
|
947
|
+
if (!fs.existsSync(phasesDir)) return;
|
|
948
|
+
const phaseDirEntry = fs.readdirSync(phasesDir).find(d => d.startsWith(padded + '-'));
|
|
949
|
+
if (!phaseDirEntry) return;
|
|
950
|
+
const fullPhaseDir = path.join(phasesDir, phaseDirEntry);
|
|
951
|
+
const hasVerification = fs.readdirSync(fullPhaseDir).some(f => /^VERIFICATION(-R\d+)?\.md$/i.test(f));
|
|
952
|
+
if (!hasVerification) {
|
|
953
|
+
warnings.push(`CRITICAL REMINDER: Phase ${phase} build complete but VERIFICATION.md is missing. You MUST execute Step 3d (Verify Phase) NOW before proceeding to Step 3e. Do NOT skip verification.`);
|
|
954
|
+
}
|
|
955
|
+
} catch (_e) { logHook('subagent-validators', 'debug', 'Failed in autonomous executor verification check'); }
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
};
|
|
959
|
+
|
|
960
|
+
/**
|
|
961
|
+
* Update convention patterns after a build executor completes.
|
|
962
|
+
* Gated by features.convention_memory config toggle.
|
|
963
|
+
* Non-fatal — convention detection failure never crashes the hook.
|
|
964
|
+
*
|
|
965
|
+
* @param {string} planningDir - Path to .planning directory
|
|
966
|
+
*/
|
|
967
|
+
function updateConventionsAfterBuild(planningDir) {
|
|
968
|
+
try {
|
|
969
|
+
const config = loadFeatureFlag(planningDir, 'convention_memory');
|
|
970
|
+
if (config === false) return;
|
|
971
|
+
|
|
972
|
+
const cwd = process.env.PBR_PROJECT_ROOT || process.cwd();
|
|
973
|
+
const conventions = detectConventions(cwd);
|
|
974
|
+
const totalPatterns = Object.values(conventions).reduce((sum, arr) => sum + arr.length, 0);
|
|
975
|
+
if (totalPatterns > 0) {
|
|
976
|
+
writeConventions(planningDir, conventions);
|
|
977
|
+
logHook('check-subagent-output', 'PostToolUse', 'conventions-updated', { patterns: totalPatterns });
|
|
978
|
+
}
|
|
979
|
+
} catch (_e) {
|
|
980
|
+
// Convention detection failure is non-fatal
|
|
981
|
+
logHook('check-subagent-output', 'PostToolUse', 'conventions-failed', { error: _e.message });
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* Log an inline execution decision to .planning/logs/hooks.jsonl for audit evidence.
|
|
987
|
+
* Called by the build skill orchestrator after running shouldInlineExecution.
|
|
988
|
+
*
|
|
989
|
+
* @param {string} planningDir - Path to .planning/ directory
|
|
990
|
+
* @param {object} decision - Result from shouldInlineExecution
|
|
991
|
+
* @param {boolean} decision.inline - Whether inline execution was chosen
|
|
992
|
+
* @param {string} [decision.reason] - Reason for the decision
|
|
993
|
+
* @param {number} [decision.taskCount] - Number of tasks in the plan
|
|
994
|
+
* @param {number} [decision.fileCount] - Number of files in the plan
|
|
995
|
+
* @param {number} [decision.estimatedLines] - Estimated lines of code
|
|
996
|
+
*/
|
|
997
|
+
function logInlineDecision(planningDir, decision) {
|
|
998
|
+
try {
|
|
999
|
+
const logsDir = path.join(planningDir, 'logs');
|
|
1000
|
+
if (!fs.existsSync(logsDir)) fs.mkdirSync(logsDir, { recursive: true });
|
|
1001
|
+
const logFile = path.join(logsDir, 'hooks.jsonl');
|
|
1002
|
+
const entry = JSON.stringify({
|
|
1003
|
+
timestamp: new Date().toISOString(),
|
|
1004
|
+
hook: 'inline-execution-gate',
|
|
1005
|
+
decision: decision.inline ? 'inline' : 'delegate',
|
|
1006
|
+
reason: decision.reason || null,
|
|
1007
|
+
taskCount: decision.taskCount || 0,
|
|
1008
|
+
fileCount: decision.fileCount || 0,
|
|
1009
|
+
estimatedLines: decision.estimatedLines || 0
|
|
1010
|
+
});
|
|
1011
|
+
fs.appendFileSync(logFile, entry + '\n', 'utf8');
|
|
1012
|
+
} catch (_e) { // intentionally silent: audit logging must not crash hooks
|
|
1013
|
+
// Best-effort — never crash the caller
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
/**
|
|
1018
|
+
* Validate self-verification data in an executor SUMMARY.md file.
|
|
1019
|
+
*/
|
|
1020
|
+
function validateSelfCheck(summaryPath, config) {
|
|
1021
|
+
if (!config || !config.features || !config.features.self_verification) {
|
|
1022
|
+
return [];
|
|
1023
|
+
}
|
|
1024
|
+
const warnings = [];
|
|
1025
|
+
try {
|
|
1026
|
+
const content = fs.readFileSync(summaryPath, 'utf8');
|
|
1027
|
+
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
1028
|
+
if (!fmMatch) {
|
|
1029
|
+
warnings.push('Executor SUMMARY.md missing self_check field — self-verification may not have run');
|
|
1030
|
+
return warnings;
|
|
1031
|
+
}
|
|
1032
|
+
const fm = fmMatch[1];
|
|
1033
|
+
if (!/self_check\s*:/i.test(fm)) {
|
|
1034
|
+
warnings.push('Executor SUMMARY.md missing self_check field — self-verification may not have run');
|
|
1035
|
+
return warnings;
|
|
1036
|
+
}
|
|
1037
|
+
const failedMatch = fm.match(/failed\s*:\s*(\d+)/);
|
|
1038
|
+
const retriesMatch = fm.match(/retries\s*:\s*(\d+)/);
|
|
1039
|
+
if (failedMatch && parseInt(failedMatch[1], 10) > 0) {
|
|
1040
|
+
const failed = failedMatch[1];
|
|
1041
|
+
const retries = retriesMatch ? retriesMatch[1] : '0';
|
|
1042
|
+
warnings.push(`Executor self-check reported ${failed} failed must-haves after ${retries} retries`);
|
|
1043
|
+
}
|
|
1044
|
+
} catch (_e) { /* intentionally silent: self-check parse error is non-fatal */ }
|
|
1045
|
+
return warnings;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* Skills that require AskUserQuestion gate prompts.
|
|
1050
|
+
* Value = minimum expected calls (0 = conditional, warn only if zero).
|
|
1051
|
+
*/
|
|
1052
|
+
const SKILLS_REQUIRING_GATES = {
|
|
1053
|
+
health: 1,
|
|
1054
|
+
milestone: 1,
|
|
1055
|
+
import: 1,
|
|
1056
|
+
review: 1,
|
|
1057
|
+
discuss: 1,
|
|
1058
|
+
build: 0
|
|
1059
|
+
};
|
|
1060
|
+
|
|
1061
|
+
/**
|
|
1062
|
+
* Check whether a gate-requiring skill completed without any AskUserQuestion calls.
|
|
1063
|
+
* Called by check-subagent-output.js after subagent completion.
|
|
1064
|
+
*
|
|
1065
|
+
* @param {string} planningDir - Path to .planning/ directory
|
|
1066
|
+
* @param {string} skillName - Active skill name
|
|
1067
|
+
* @returns {string|null} Warning message or null if compliant
|
|
1068
|
+
*/
|
|
1069
|
+
function checkUserGateCompliance(planningDir, skillName) {
|
|
1070
|
+
if (!skillName || !Object.prototype.hasOwnProperty.call(SKILLS_REQUIRING_GATES, skillName)) {
|
|
1071
|
+
return null; // Not a gate-requiring skill
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
const signalPath = path.join(planningDir, '.user-gate-passed');
|
|
1075
|
+
|
|
1076
|
+
try {
|
|
1077
|
+
if (!fs.existsSync(signalPath)) {
|
|
1078
|
+
return `Skill '${skillName}' completed without any AskUserQuestion calls. This skill has gate-prompt references that should require user confirmation.`;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
const signalData = JSON.parse(fs.readFileSync(signalPath, 'utf8'));
|
|
1082
|
+
|
|
1083
|
+
// Check if signal matches current skill
|
|
1084
|
+
if (signalData.skill !== skillName) {
|
|
1085
|
+
return `Skill '${skillName}' completed without any AskUserQuestion calls. This skill has gate-prompt references that should require user confirmation.`;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
// Signal exists and matches — clean up
|
|
1089
|
+
try { fs.unlinkSync(signalPath); } catch (_e) { /* intentionally silent: signal file cleanup */ }
|
|
1090
|
+
return null;
|
|
1091
|
+
} catch (_e) { logHook('subagent-validators', 'debug', 'Failed to check user gate compliance');
|
|
1092
|
+
// If signal file exists but can't be parsed, treat as missing
|
|
1093
|
+
return `Skill '${skillName}' completed without any AskUserQuestion calls. This skill has gate-prompt references that should require user confirmation.`;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
module.exports = {
|
|
1098
|
+
AGENT_TO_SKILL,
|
|
1099
|
+
AGENT_OUTPUTS,
|
|
1100
|
+
SKILL_CHECKS,
|
|
1101
|
+
findInPhaseDir,
|
|
1102
|
+
findInQuickDir,
|
|
1103
|
+
checkSummaryCommits,
|
|
1104
|
+
checkDeviationsRequiringReview,
|
|
1105
|
+
logCompliance,
|
|
1106
|
+
checkTriggeredSeeds,
|
|
1107
|
+
checkLearningsRequired,
|
|
1108
|
+
isRecent,
|
|
1109
|
+
getCurrentPhase,
|
|
1110
|
+
checkRoadmapStaleness,
|
|
1111
|
+
logInlineDecision,
|
|
1112
|
+
extractVerificationOutcome,
|
|
1113
|
+
shouldTrackTrust,
|
|
1114
|
+
loadFeatureFlag,
|
|
1115
|
+
updateConventionsAfterBuild,
|
|
1116
|
+
validateSelfCheck,
|
|
1117
|
+
checkUserGateCompliance,
|
|
1118
|
+
SKILLS_REQUIRING_GATES
|
|
1119
|
+
};
|