@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.
Files changed (983) hide show
  1. package/CHANGELOG.md +1331 -299
  2. package/CLAUDE.md +75 -40
  3. package/LICENSE +2 -1
  4. package/README.md +412 -177
  5. package/bin/install.js +2752 -0
  6. package/dashboard/bin/cli.cjs +96 -0
  7. package/dashboard/bin/stop.cjs +129 -0
  8. package/dashboard/eslint.config.js +37 -0
  9. package/dashboard/index.html +20 -0
  10. package/dashboard/package.json +27 -25
  11. package/dashboard/server/index.js +151 -0
  12. package/dashboard/server/lib/frontmatter.js +92 -0
  13. package/dashboard/server/middleware/static.js +35 -0
  14. package/dashboard/server/package.json +16 -0
  15. package/dashboard/server/routes/agents.js +234 -0
  16. package/dashboard/server/routes/config.js +64 -0
  17. package/dashboard/server/routes/health.js +98 -0
  18. package/dashboard/server/routes/incidents.js +78 -0
  19. package/dashboard/server/routes/intel.js +69 -0
  20. package/dashboard/server/routes/memory.js +107 -0
  21. package/dashboard/server/routes/planning.js +234 -0
  22. package/dashboard/server/routes/progress.js +77 -0
  23. package/dashboard/server/routes/projects.js +36 -0
  24. package/dashboard/server/routes/requirements.js +40 -0
  25. package/dashboard/server/routes/roadmap.js +69 -0
  26. package/dashboard/server/routes/sessions.js +70 -0
  27. package/dashboard/server/routes/status.js +25 -0
  28. package/dashboard/server/routes/telemetry.js +233 -0
  29. package/dashboard/server/services/file-watcher.js +105 -0
  30. package/dashboard/server/services/planning-reader.js +727 -0
  31. package/dashboard/server/test/cli.test.js +34 -0
  32. package/dashboard/server/test/frontmatter.test.js +104 -0
  33. package/dashboard/server/test/isolation.test.js +32 -0
  34. package/dashboard/server/test/planning-reader.test.js +151 -0
  35. package/dashboard/server/test/routes.test.js +91 -0
  36. package/dashboard/server/test/ws.test.js +81 -0
  37. package/dashboard/server/ws.js +96 -0
  38. package/dashboard/src/App.jsx +165 -0
  39. package/dashboard/src/components/charts/BudgetBars.jsx +42 -0
  40. package/dashboard/src/components/charts/ContextRadar.jsx +34 -0
  41. package/dashboard/src/components/charts/PhaseDonut.jsx +66 -0
  42. package/dashboard/src/components/charts/SuccessTrend.jsx +45 -0
  43. package/dashboard/src/components/charts/TokenChart.jsx +55 -0
  44. package/dashboard/src/components/charts/index.js +5 -0
  45. package/dashboard/src/components/config/CfgSection.jsx +93 -0
  46. package/dashboard/src/components/layout/Header.jsx +89 -0
  47. package/dashboard/src/components/layout/ProjectSwitcher.jsx +160 -0
  48. package/dashboard/src/components/layout/Sidebar.jsx +161 -0
  49. package/dashboard/src/components/ui/AutoModeBanner.jsx +138 -0
  50. package/dashboard/src/components/ui/BackButton.jsx +27 -0
  51. package/dashboard/src/components/ui/Badge.jsx +27 -0
  52. package/dashboard/src/components/ui/Card.jsx +23 -0
  53. package/dashboard/src/components/ui/ChartTooltip.jsx +48 -0
  54. package/dashboard/src/components/ui/CheckpointBox.jsx +110 -0
  55. package/dashboard/src/components/ui/CodeBlock.jsx +27 -0
  56. package/dashboard/src/components/ui/ConfidenceBadge.jsx +20 -0
  57. package/dashboard/src/components/ui/ConfirmModal.jsx +161 -0
  58. package/dashboard/src/components/ui/ConnectionBanner.jsx +60 -0
  59. package/dashboard/src/components/ui/ErrorBoundary.jsx +106 -0
  60. package/dashboard/src/components/ui/ErrorBox.jsx +107 -0
  61. package/dashboard/src/components/ui/KeyValue.jsx +33 -0
  62. package/dashboard/src/components/ui/LoadingSkeleton.jsx +84 -0
  63. package/dashboard/src/components/ui/MetricCard.jsx +58 -0
  64. package/dashboard/src/components/ui/NextUpBlock.jsx +92 -0
  65. package/dashboard/src/components/ui/NumberInput.jsx +44 -0
  66. package/dashboard/src/components/ui/PBRBanner.jsx +47 -0
  67. package/dashboard/src/components/ui/PipelineView.jsx +130 -0
  68. package/dashboard/src/components/ui/ProgressBar.jsx +28 -0
  69. package/dashboard/src/components/ui/ProgressDisplay.jsx +47 -0
  70. package/dashboard/src/components/ui/QualityGateBadge.jsx +15 -0
  71. package/dashboard/src/components/ui/SectionTitle.jsx +35 -0
  72. package/dashboard/src/components/ui/SelectInput.jsx +45 -0
  73. package/dashboard/src/components/ui/StatusDot.jsx +51 -0
  74. package/dashboard/src/components/ui/StatusSymbol.jsx +49 -0
  75. package/dashboard/src/components/ui/TabBar.jsx +41 -0
  76. package/dashboard/src/components/ui/TextInput.jsx +42 -0
  77. package/dashboard/src/components/ui/Toast.jsx +117 -0
  78. package/dashboard/src/components/ui/Toggle.jsx +70 -0
  79. package/dashboard/src/components/ui/index.js +29 -0
  80. package/dashboard/src/hooks/useDocumentTitle.js +16 -0
  81. package/dashboard/src/hooks/useFetch.js +50 -0
  82. package/dashboard/src/hooks/useToast.jsx +43 -0
  83. package/dashboard/src/hooks/useWebSocket.js +103 -0
  84. package/dashboard/src/lib/api.js +112 -0
  85. package/dashboard/src/lib/configSchema.js +189 -0
  86. package/dashboard/src/lib/constants.js +22 -0
  87. package/dashboard/src/main.jsx +15 -0
  88. package/dashboard/src/pages/AgentsPage.jsx +191 -0
  89. package/dashboard/src/pages/ConfigPage.jsx +298 -0
  90. package/dashboard/src/pages/HooksPage.jsx +412 -0
  91. package/dashboard/src/pages/IncidentsPage.jsx +135 -0
  92. package/dashboard/src/pages/IntelPage.jsx +193 -0
  93. package/dashboard/src/pages/LiveFeed.jsx +274 -0
  94. package/dashboard/src/pages/MemoryPage.jsx +107 -0
  95. package/dashboard/src/pages/OnboardingPage.jsx +117 -0
  96. package/dashboard/src/pages/Overview.jsx +360 -0
  97. package/dashboard/src/pages/PhaseDetailView.jsx +216 -0
  98. package/dashboard/src/pages/PlanningPage.jsx +181 -0
  99. package/dashboard/src/pages/ProgressPage.jsx +249 -0
  100. package/dashboard/src/pages/ResearchPage.jsx +129 -0
  101. package/dashboard/src/pages/RoadmapPage.jsx +251 -0
  102. package/dashboard/src/pages/SessionsPage.jsx +117 -0
  103. package/dashboard/src/pages/Telemetry.jsx +166 -0
  104. package/dashboard/src/pages/planning/DecisionsTab.jsx +153 -0
  105. package/dashboard/src/pages/planning/FilesTab.jsx +420 -0
  106. package/dashboard/src/pages/planning/MilestoneDetail.jsx +319 -0
  107. package/dashboard/src/pages/planning/MilestonesTab.jsx +151 -0
  108. package/dashboard/src/pages/planning/NotesTab.jsx +251 -0
  109. package/dashboard/src/pages/planning/PhasesTab.jsx +218 -0
  110. package/dashboard/src/pages/planning/QuickTab.jsx +50 -0
  111. package/dashboard/src/pages/planning/ResearchTab.jsx +103 -0
  112. package/dashboard/src/pages/planning/TodosTab.jsx +297 -0
  113. package/dashboard/src/theme/ThemeProvider.jsx +38 -0
  114. package/dashboard/src/theme/tokens.js +17 -0
  115. package/dashboard/tests/components/ConfirmModal.test.jsx +179 -0
  116. package/dashboard/tests/components/ConnectionBanner.test.jsx +37 -0
  117. package/dashboard/tests/components/ErrorBoundary.test.jsx +59 -0
  118. package/dashboard/tests/components/LoadingSkeleton.test.jsx +46 -0
  119. package/dashboard/tests/components/ToastContainer.test.jsx +47 -0
  120. package/dashboard/tests/components/Toggle.test.jsx +61 -0
  121. package/dashboard/tests/hooks/useFetch.test.jsx +77 -0
  122. package/dashboard/tests/hooks/useToast.test.jsx +78 -0
  123. package/dashboard/tests/hooks/useWebSocket.test.jsx +128 -0
  124. package/dashboard/tests/pages/ConfigPage.test.jsx +199 -0
  125. package/dashboard/tests/pages/PlanningPage.test.jsx +119 -0
  126. package/dashboard/tests/pages/planning/FilesTab.test.jsx +198 -0
  127. package/dashboard/tests/pages/planning/NotesTab.test.jsx +178 -0
  128. package/dashboard/tests/pages/planning/TodosTab.test.jsx +188 -0
  129. package/dashboard/tests/performance.test.jsx +46 -0
  130. package/dashboard/tests/routes/config.test.js +98 -0
  131. package/dashboard/tests/routes/health.test.js +40 -0
  132. package/dashboard/tests/routes/planning.test.js +112 -0
  133. package/dashboard/tests/routes/roadmap.test.js +91 -0
  134. package/dashboard/tests/routes/status.test.js +131 -0
  135. package/dashboard/tests/server/planning-reader.test.js +153 -0
  136. package/dashboard/tests/setup.js +7 -0
  137. package/dashboard/vite.config.js +41 -0
  138. package/package.json +56 -41
  139. package/plan-build-run/bin/config-schema.json +1298 -0
  140. package/plugins/pbr/.claude-plugin/plugin.json +1 -1
  141. package/plugins/pbr/CLAUDE.md +19 -0
  142. package/plugins/pbr/UI-CONSISTENCY-GAPS.md +1 -1
  143. package/plugins/pbr/agents/advisor-researcher.md +101 -0
  144. package/plugins/pbr/agents/audit.md +207 -89
  145. package/plugins/pbr/agents/codebase-mapper.md +158 -23
  146. package/plugins/pbr/agents/debugger.md +212 -34
  147. package/plugins/pbr/agents/dev-sync.md +206 -0
  148. package/plugins/pbr/agents/executor.md +737 -39
  149. package/plugins/pbr/agents/general.md +71 -6
  150. package/plugins/pbr/agents/integration-checker.md +148 -30
  151. package/plugins/pbr/agents/intel-updater.md +332 -0
  152. package/plugins/pbr/agents/nyquist-auditor.md +254 -0
  153. package/plugins/pbr/agents/plan-checker.md +268 -66
  154. package/plugins/pbr/agents/planner.md +451 -42
  155. package/plugins/pbr/agents/researcher.md +219 -36
  156. package/plugins/pbr/agents/roadmapper.md +398 -0
  157. package/plugins/pbr/agents/synthesizer.md +166 -26
  158. package/plugins/pbr/agents/ui-checker.md +204 -0
  159. package/plugins/pbr/agents/ui-researcher.md +224 -0
  160. package/plugins/pbr/agents/verifier.md +571 -47
  161. package/plugins/pbr/commands/add-phase.md +75 -0
  162. package/plugins/pbr/commands/add-todo.md +8 -0
  163. package/plugins/pbr/commands/audit-fix.md +5 -0
  164. package/plugins/pbr/commands/audit-milestone.md +8 -0
  165. package/plugins/pbr/commands/autonomous.md +5 -0
  166. package/plugins/pbr/commands/backlog.md +6 -0
  167. package/plugins/pbr/commands/check-todos.md +8 -0
  168. package/plugins/pbr/commands/complete-milestone.md +8 -0
  169. package/plugins/pbr/commands/config.md +1 -1
  170. package/plugins/pbr/commands/discuss-phase.md +6 -0
  171. package/plugins/pbr/commands/do.md +5 -0
  172. package/plugins/pbr/commands/execute-phase.md +6 -0
  173. package/plugins/pbr/commands/fast.md +6 -0
  174. package/plugins/pbr/commands/forensics.md +6 -0
  175. package/plugins/pbr/commands/import.md +1 -1
  176. package/plugins/pbr/commands/insert-phase.md +65 -0
  177. package/plugins/pbr/commands/intel.md +5 -0
  178. package/plugins/pbr/commands/join-discord.md +11 -0
  179. package/plugins/pbr/commands/list-phase-assumptions.md +5 -0
  180. package/plugins/pbr/commands/map-codebase.md +6 -0
  181. package/plugins/pbr/commands/milestone-summary.md +6 -0
  182. package/plugins/pbr/commands/new-milestone.md +8 -0
  183. package/plugins/pbr/commands/new-project.md +6 -0
  184. package/plugins/pbr/commands/pause-work.md +5 -0
  185. package/plugins/pbr/commands/plan-milestone-gaps.md +7 -0
  186. package/plugins/pbr/commands/plan-phase.md +6 -0
  187. package/plugins/pbr/commands/plant-seed.md +6 -0
  188. package/plugins/pbr/commands/profile-user.md +5 -0
  189. package/plugins/pbr/commands/profile.md +5 -0
  190. package/plugins/pbr/commands/progress.md +6 -0
  191. package/plugins/pbr/commands/quick.md +1 -1
  192. package/plugins/pbr/commands/reapply-patches.md +47 -0
  193. package/plugins/pbr/commands/release.md +6 -0
  194. package/plugins/pbr/commands/remove-phase.md +66 -0
  195. package/plugins/pbr/commands/research-phase.md +59 -0
  196. package/plugins/pbr/commands/resume-work.md +5 -0
  197. package/plugins/pbr/commands/seed.md +6 -0
  198. package/plugins/pbr/commands/session-report.md +5 -0
  199. package/plugins/pbr/commands/set-profile.md +6 -0
  200. package/plugins/pbr/commands/settings.md +5 -0
  201. package/plugins/pbr/commands/setup.md +1 -1
  202. package/plugins/pbr/commands/ship.md +5 -0
  203. package/plugins/pbr/commands/stats.md +6 -0
  204. package/plugins/pbr/commands/test.md +5 -0
  205. package/plugins/pbr/commands/thread.md +6 -0
  206. package/plugins/pbr/commands/todo.md +1 -1
  207. package/plugins/pbr/commands/ui-phase.md +5 -0
  208. package/plugins/pbr/commands/ui-review.md +5 -0
  209. package/plugins/pbr/commands/undo.md +5 -0
  210. package/plugins/pbr/commands/update.md +37 -0
  211. package/plugins/pbr/commands/validate-phase.md +5 -0
  212. package/plugins/pbr/commands/verify-work.md +6 -0
  213. package/plugins/pbr/dashboard/package-lock.json +6 -0
  214. package/plugins/pbr/dist/architecture-guard.js +76 -0
  215. package/plugins/pbr/dist/audit-dimensions.js +556 -0
  216. package/plugins/pbr/dist/auto-continue.js +277 -0
  217. package/plugins/pbr/dist/block-skill-self-read.js +124 -0
  218. package/plugins/pbr/dist/check-agent-state-write.js +63 -0
  219. package/plugins/pbr/dist/check-config-change.js +213 -0
  220. package/plugins/pbr/dist/check-cross-plugin-sync.js +93 -0
  221. package/plugins/pbr/dist/check-dangerous-commands.js +193 -0
  222. package/plugins/pbr/dist/check-direct-state-write.js +37 -0
  223. package/plugins/pbr/dist/check-doc-sprawl.js +102 -0
  224. package/plugins/pbr/dist/check-phase-boundary.js +191 -0
  225. package/plugins/pbr/dist/check-plan-format.js +227 -0
  226. package/plugins/pbr/dist/check-read-first.js +345 -0
  227. package/plugins/pbr/dist/check-roadmap-sync.js +507 -0
  228. package/plugins/pbr/dist/check-skill-workflow.js +354 -0
  229. package/plugins/pbr/dist/check-state-sync.js +676 -0
  230. package/plugins/pbr/dist/check-subagent-output.js +425 -0
  231. package/plugins/pbr/dist/check-summary-gate.js +188 -0
  232. package/plugins/pbr/dist/context-bridge.js +425 -0
  233. package/plugins/pbr/dist/context-budget-check.js +442 -0
  234. package/plugins/pbr/dist/context-quality.js +271 -0
  235. package/plugins/pbr/dist/enforce-context-budget.js +138 -0
  236. package/plugins/pbr/dist/enforce-pbr-workflow.js +277 -0
  237. package/plugins/pbr/dist/event-handler.js +212 -0
  238. package/plugins/pbr/dist/event-logger.js +125 -0
  239. package/plugins/pbr/dist/feedback-loop.js +155 -0
  240. package/plugins/pbr/dist/graph-update.js +422 -0
  241. package/plugins/pbr/dist/hook-logger.js +114 -0
  242. package/plugins/pbr/dist/hook-server-client.js +361 -0
  243. package/plugins/pbr/dist/hook-server.js +664 -0
  244. package/plugins/pbr/dist/hooks-schema.json +87 -0
  245. package/plugins/pbr/dist/instructions-loaded.js +173 -0
  246. package/plugins/pbr/dist/intercept-plan-mode.js +81 -0
  247. package/plugins/pbr/dist/log-notification.js +131 -0
  248. package/plugins/pbr/dist/log-subagent.js +367 -0
  249. package/plugins/pbr/dist/log-tool-failure.js +140 -0
  250. package/plugins/pbr/dist/milestone-learnings.js +519 -0
  251. package/plugins/pbr/dist/pbr-tools.js +493 -0
  252. package/plugins/pbr/dist/post-bash-triage.js +96 -0
  253. package/plugins/pbr/dist/post-compact.js +135 -0
  254. package/plugins/pbr/dist/post-hoc.js +237 -0
  255. package/plugins/pbr/dist/post-write-dispatch.js +243 -0
  256. package/plugins/pbr/dist/post-write-quality.js +208 -0
  257. package/plugins/pbr/dist/pre-bash-dispatch.js +212 -0
  258. package/plugins/pbr/dist/pre-skill-dispatch.js +114 -0
  259. package/plugins/pbr/dist/pre-task-dispatch.js +269 -0
  260. package/plugins/pbr/dist/pre-write-dispatch.js +234 -0
  261. package/plugins/pbr/dist/progress-tracker.js +173 -0
  262. package/plugins/pbr/dist/prompt-guard.js +114 -0
  263. package/plugins/pbr/dist/prompt-routing.js +209 -0
  264. package/plugins/pbr/dist/quick-status.js +179 -0
  265. package/plugins/pbr/dist/record-incident.js +37 -0
  266. package/plugins/pbr/dist/run-hook.js +132 -0
  267. package/plugins/pbr/dist/session-cleanup.js +653 -0
  268. package/plugins/pbr/dist/session-tracker.js +124 -0
  269. package/plugins/pbr/dist/status-line.js +849 -0
  270. package/plugins/pbr/dist/suggest-compact.js +307 -0
  271. package/plugins/pbr/dist/sync-context-to-claude.js +100 -0
  272. package/plugins/pbr/dist/task-completed.js +206 -0
  273. package/plugins/pbr/dist/track-context-budget.js +432 -0
  274. package/plugins/pbr/dist/track-user-gates.js +88 -0
  275. package/plugins/pbr/dist/trust-tracker.js +193 -0
  276. package/plugins/pbr/dist/validate-commit.js +233 -0
  277. package/plugins/pbr/dist/validate-skill-args.js +222 -0
  278. package/plugins/pbr/dist/validate-task.js +271 -0
  279. package/plugins/pbr/dist/worktree-create.js +144 -0
  280. package/plugins/pbr/dist/worktree-remove.js +147 -0
  281. package/plugins/pbr/hooks/hooks.json +137 -65
  282. package/plugins/pbr/references/agent-contracts.md +39 -8
  283. package/plugins/pbr/references/agent-teams.md +3 -3
  284. package/plugins/pbr/references/archive/checkpoints.md +189 -0
  285. package/plugins/pbr/references/archive/context-quality-tiers.md +45 -0
  286. package/plugins/pbr/references/archive/hook-ordering.md +89 -0
  287. package/plugins/pbr/references/archive/limitations.md +106 -0
  288. package/plugins/pbr/references/archive/pbr-rules.md +194 -0
  289. package/plugins/pbr/references/archive/pbr-tools-cli.md +415 -0
  290. package/plugins/pbr/references/archive/pretooluse-jsonl-behavior.md +58 -0
  291. package/plugins/pbr/references/archive/signal-files.md +41 -0
  292. package/plugins/pbr/references/archive/tmux-setup.md +288 -0
  293. package/plugins/pbr/references/archive/verification-matrix.md +34 -0
  294. package/plugins/pbr/references/archive/verification-patterns.md +277 -0
  295. package/plugins/pbr/references/archive/worktree-sparse-checkout.md +86 -0
  296. package/plugins/pbr/references/assumptions.md +42 -0
  297. package/plugins/pbr/references/checkpoints.md +723 -104
  298. package/plugins/pbr/references/config-reference.md +387 -10
  299. package/plugins/pbr/references/continuation-format.md +1 -0
  300. package/plugins/pbr/references/decimal-phase-calculation.md +65 -0
  301. package/plugins/pbr/references/deviation-rules.md +12 -0
  302. package/plugins/pbr/references/few-shot-examples/audit.md +77 -0
  303. package/plugins/pbr/references/few-shot-examples/check-plan-format.md +172 -0
  304. package/plugins/pbr/references/few-shot-examples/check-subagent-output.md +118 -0
  305. package/plugins/pbr/references/few-shot-examples/integration-checker.md +70 -0
  306. package/plugins/pbr/references/few-shot-examples/nyquist-auditor.md +83 -0
  307. package/plugins/pbr/references/few-shot-examples/plan-checker.md +73 -0
  308. package/plugins/pbr/references/few-shot-examples/ui-checker.md +71 -0
  309. package/plugins/pbr/references/few-shot-examples/verifier.md +109 -0
  310. package/plugins/pbr/references/git-integration.md +110 -27
  311. package/plugins/pbr/references/git-planning-commit.md +35 -0
  312. package/plugins/pbr/references/model-profile-resolution.md +34 -0
  313. package/plugins/pbr/references/model-profiles.md +90 -7
  314. package/plugins/pbr/references/model-selection.md +1 -1
  315. package/plugins/pbr/references/node-repair.md +48 -0
  316. package/plugins/pbr/references/plan-authoring.md +65 -0
  317. package/plugins/pbr/references/plan-format.md +184 -10
  318. package/plugins/pbr/references/questioning.md +138 -49
  319. package/plugins/pbr/references/reading-verification.md +4 -4
  320. package/plugins/pbr/references/tdd.md +263 -0
  321. package/plugins/pbr/references/thinking-models-planning.md +47 -0
  322. package/plugins/pbr/references/thinking-models-verification.md +44 -0
  323. package/plugins/pbr/references/ui-brand.md +449 -0
  324. package/plugins/pbr/references/verification-overrides.md +39 -0
  325. package/plugins/pbr/references/verification-patterns.md +529 -113
  326. package/plugins/pbr/scripts/architecture-guard.js +76 -0
  327. package/plugins/pbr/scripts/audit-checks/behavioral-compliance.js +2098 -0
  328. package/plugins/pbr/scripts/audit-checks/error-analysis.js +989 -0
  329. package/plugins/pbr/scripts/audit-checks/feature-verification.js +723 -0
  330. package/plugins/pbr/scripts/audit-checks/index.js +433 -0
  331. package/plugins/pbr/scripts/audit-checks/infrastructure.js +816 -0
  332. package/plugins/pbr/scripts/audit-checks/quality-metrics.js +455 -0
  333. package/plugins/pbr/scripts/audit-checks/session-quality.js +980 -0
  334. package/plugins/pbr/scripts/audit-checks/si-agent-hook-config-checks.js +396 -0
  335. package/plugins/pbr/scripts/audit-checks/si-cross-cutting-checks.js +272 -0
  336. package/plugins/pbr/scripts/audit-checks/si-skill-checks.js +424 -0
  337. package/plugins/pbr/scripts/audit-checks/workflow-compliance.js +1175 -0
  338. package/plugins/pbr/scripts/audit-dimensions.js +556 -0
  339. package/plugins/pbr/scripts/auto-continue.js +192 -37
  340. package/plugins/pbr/scripts/block-skill-self-read.js +124 -0
  341. package/plugins/pbr/scripts/check-agent-state-write.js +63 -0
  342. package/plugins/pbr/scripts/check-config-change.js +84 -1
  343. package/plugins/pbr/scripts/check-cross-plugin-sync.js +93 -0
  344. package/plugins/pbr/scripts/check-dangerous-commands.js +18 -5
  345. package/plugins/pbr/scripts/check-direct-state-write.js +37 -0
  346. package/plugins/pbr/scripts/check-phase-boundary.js +3 -8
  347. package/plugins/pbr/scripts/check-plan-format.js +153 -278
  348. package/plugins/pbr/scripts/check-read-first.js +345 -0
  349. package/plugins/pbr/scripts/check-roadmap-sync.js +174 -19
  350. package/plugins/pbr/scripts/check-skill-workflow.js +24 -27
  351. package/plugins/pbr/scripts/check-state-sync.js +360 -218
  352. package/plugins/pbr/scripts/check-subagent-output.js +308 -273
  353. package/plugins/pbr/scripts/check-summary-gate.js +5 -15
  354. package/plugins/pbr/scripts/commands/benchmarks.js +195 -0
  355. package/plugins/pbr/scripts/commands/calibrate.js +530 -0
  356. package/plugins/pbr/scripts/commands/config.js +72 -0
  357. package/plugins/pbr/scripts/commands/misc.js +779 -0
  358. package/plugins/pbr/scripts/commands/phase.js +293 -0
  359. package/plugins/pbr/scripts/commands/roadmap.js +75 -0
  360. package/plugins/pbr/scripts/commands/state.js +84 -0
  361. package/plugins/pbr/scripts/commands/stress-test.js +349 -0
  362. package/plugins/pbr/scripts/commands/todo.js +191 -0
  363. package/plugins/pbr/scripts/commands/verify.js +169 -0
  364. package/plugins/pbr/scripts/config-schema.json +1183 -95
  365. package/plugins/pbr/scripts/context-bridge.js +425 -0
  366. package/plugins/pbr/scripts/context-budget-check.js +171 -16
  367. package/plugins/pbr/scripts/context-quality.js +271 -0
  368. package/plugins/pbr/scripts/enforce-context-budget.js +138 -0
  369. package/plugins/pbr/scripts/enforce-pbr-workflow.js +277 -0
  370. package/plugins/pbr/scripts/event-handler.js +137 -87
  371. package/plugins/pbr/scripts/event-logger.js +58 -25
  372. package/plugins/pbr/scripts/feedback-loop.js +155 -0
  373. package/plugins/pbr/scripts/graph-update.js +422 -0
  374. package/plugins/pbr/scripts/hook-logger.js +69 -35
  375. package/plugins/pbr/scripts/hook-server-client.js +361 -0
  376. package/plugins/pbr/scripts/hook-server.js +664 -0
  377. package/plugins/pbr/scripts/hooks-schema.json +12 -5
  378. package/plugins/pbr/scripts/instructions-loaded.js +173 -0
  379. package/plugins/pbr/scripts/intent-router.cjs +147 -0
  380. package/plugins/pbr/scripts/intercept-plan-mode.js +52 -18
  381. package/plugins/pbr/scripts/lib/alternatives.js +203 -0
  382. package/plugins/pbr/scripts/lib/audit.js +65 -0
  383. package/plugins/pbr/scripts/lib/auto-cleanup.js +221 -0
  384. package/plugins/pbr/scripts/lib/auto-verify.js +123 -0
  385. package/plugins/pbr/scripts/lib/benchmark.js +190 -0
  386. package/plugins/pbr/scripts/lib/build.js +719 -0
  387. package/plugins/pbr/scripts/lib/ci-fix-loop.js +228 -0
  388. package/plugins/pbr/scripts/lib/commands.js +483 -0
  389. package/plugins/pbr/scripts/lib/compound.js +222 -0
  390. package/plugins/pbr/scripts/lib/config-cache.js +83 -0
  391. package/plugins/pbr/scripts/lib/config.js +1469 -0
  392. package/plugins/pbr/scripts/lib/context.js +254 -0
  393. package/plugins/pbr/scripts/lib/contextual-help.js +183 -0
  394. package/plugins/pbr/scripts/lib/convention-detector.js +413 -0
  395. package/plugins/pbr/scripts/lib/core.js +1585 -0
  396. package/plugins/pbr/scripts/lib/dashboard-launch.js +364 -0
  397. package/plugins/pbr/scripts/lib/data-hygiene.js +179 -0
  398. package/plugins/pbr/scripts/lib/decision-extraction.js +183 -0
  399. package/plugins/pbr/scripts/lib/decisions.js +194 -0
  400. package/plugins/pbr/scripts/lib/dependency-break.js +147 -0
  401. package/plugins/pbr/scripts/lib/format-validators.js +1049 -0
  402. package/plugins/pbr/scripts/lib/frontmatter.js +302 -0
  403. package/plugins/pbr/scripts/lib/gates/advisories.js +133 -0
  404. package/plugins/pbr/scripts/lib/gates/build-dependency.js +118 -0
  405. package/plugins/pbr/scripts/lib/gates/build-executor.js +106 -0
  406. package/plugins/pbr/scripts/lib/gates/doc-existence.js +46 -0
  407. package/plugins/pbr/scripts/lib/gates/helpers.js +98 -0
  408. package/plugins/pbr/scripts/lib/gates/inline-execution.js +187 -0
  409. package/plugins/pbr/scripts/lib/gates/milestone-complete.js +139 -0
  410. package/plugins/pbr/scripts/lib/gates/milestone-summary.js +121 -0
  411. package/plugins/pbr/scripts/lib/gates/multi-phase-loader.js +149 -0
  412. package/plugins/pbr/scripts/lib/gates/plan-executor.js +36 -0
  413. package/plugins/pbr/scripts/lib/gates/plan-validation.js +115 -0
  414. package/plugins/pbr/scripts/lib/gates/quick-executor.js +78 -0
  415. package/plugins/pbr/scripts/lib/gates/review-planner.js +63 -0
  416. package/plugins/pbr/scripts/lib/gates/review-verifier.js +71 -0
  417. package/plugins/pbr/scripts/lib/gates/rich-agent-context.js +148 -0
  418. package/plugins/pbr/scripts/lib/gates/sprint-preflight.js +30 -0
  419. package/plugins/pbr/scripts/lib/gates/user-confirmation.js +95 -0
  420. package/plugins/pbr/scripts/lib/graph-cli.js +89 -0
  421. package/plugins/pbr/scripts/lib/graph.js +553 -0
  422. package/plugins/pbr/scripts/lib/handoff-validators.js +224 -0
  423. package/plugins/pbr/scripts/lib/health-checks.js +107 -0
  424. package/plugins/pbr/scripts/lib/health-phase06.js +120 -0
  425. package/plugins/pbr/scripts/lib/health.js +132 -0
  426. package/plugins/pbr/scripts/lib/help.js +100 -0
  427. package/plugins/pbr/scripts/lib/history.js +150 -0
  428. package/plugins/pbr/scripts/lib/impact-analysis.js +319 -0
  429. package/plugins/pbr/scripts/lib/incidents.js +190 -0
  430. package/plugins/pbr/scripts/lib/init.js +643 -0
  431. package/plugins/pbr/scripts/lib/insights-parser.js +320 -0
  432. package/plugins/pbr/scripts/lib/intel.js +653 -0
  433. package/plugins/pbr/scripts/lib/learnings.js +511 -0
  434. package/plugins/pbr/scripts/lib/migrate.js +309 -0
  435. package/plugins/pbr/scripts/lib/milestone.js +306 -0
  436. package/plugins/pbr/scripts/lib/msys-path.js +20 -0
  437. package/plugins/pbr/scripts/lib/negative-knowledge.js +194 -0
  438. package/plugins/pbr/scripts/lib/notification-throttle.js +141 -0
  439. package/plugins/pbr/scripts/lib/onboarding-generator.js +288 -0
  440. package/plugins/pbr/scripts/lib/parse-args.js +134 -0
  441. package/plugins/pbr/scripts/lib/pattern-routing.js +55 -0
  442. package/plugins/pbr/scripts/lib/patterns.js +272 -0
  443. package/plugins/pbr/scripts/lib/perf.js +190 -0
  444. package/plugins/pbr/scripts/lib/phase.js +1043 -0
  445. package/plugins/pbr/scripts/lib/pid-lock.js +156 -0
  446. package/plugins/pbr/scripts/lib/post-hoc.js +160 -0
  447. package/plugins/pbr/scripts/lib/pre-commit-checks.js +220 -0
  448. package/plugins/pbr/scripts/lib/pre-research.js +126 -0
  449. package/plugins/pbr/scripts/lib/premature-completion.js +312 -0
  450. package/plugins/pbr/scripts/lib/preview.js +174 -0
  451. package/plugins/pbr/scripts/lib/progress-visualization.js +296 -0
  452. package/plugins/pbr/scripts/lib/quick-init.js +131 -0
  453. package/plugins/pbr/scripts/lib/reference.js +236 -0
  454. package/plugins/pbr/scripts/lib/requirements.js +153 -0
  455. package/plugins/pbr/scripts/lib/resolve-root.js +66 -0
  456. package/plugins/pbr/scripts/lib/reverse-spec.js +259 -0
  457. package/plugins/pbr/scripts/lib/roadmap.js +1089 -0
  458. package/plugins/pbr/scripts/lib/security-scan.js +200 -0
  459. package/plugins/pbr/scripts/lib/session-briefing.js +918 -0
  460. package/plugins/pbr/scripts/lib/skill-section.js +99 -0
  461. package/plugins/pbr/scripts/lib/smart-next-task.js +198 -0
  462. package/plugins/pbr/scripts/lib/snapshot-manager.js +232 -0
  463. package/plugins/pbr/scripts/lib/spec-diff.js +209 -0
  464. package/plugins/pbr/scripts/lib/spec-engine.js +189 -0
  465. package/plugins/pbr/scripts/lib/spot-check.js +539 -0
  466. package/plugins/pbr/scripts/lib/state-queue.js +171 -0
  467. package/plugins/pbr/scripts/lib/state.js +1082 -0
  468. package/plugins/pbr/scripts/lib/status-render.js +511 -0
  469. package/plugins/pbr/scripts/lib/step-verify.js +149 -0
  470. package/plugins/pbr/scripts/lib/subagent-validators.js +1119 -0
  471. package/plugins/pbr/scripts/lib/suggest-next.js +435 -0
  472. package/plugins/pbr/scripts/lib/tech-debt-scanner.js +116 -0
  473. package/plugins/pbr/scripts/lib/templates.js +362 -0
  474. package/plugins/pbr/scripts/lib/test-selection.js +163 -0
  475. package/plugins/pbr/scripts/lib/todo.js +300 -0
  476. package/plugins/pbr/scripts/lib/verify.js +1561 -0
  477. package/plugins/pbr/scripts/log-notification.js +131 -0
  478. package/plugins/pbr/scripts/log-subagent.js +221 -18
  479. package/plugins/pbr/scripts/log-tool-failure.js +60 -8
  480. package/plugins/pbr/scripts/milestone-learnings.js +519 -0
  481. package/plugins/pbr/scripts/package.json +1 -1
  482. package/plugins/pbr/scripts/pbr-tools.js +362 -1247
  483. package/plugins/pbr/scripts/post-bash-triage.js +96 -0
  484. package/plugins/pbr/scripts/post-compact.js +135 -0
  485. package/plugins/pbr/scripts/post-hoc.js +237 -0
  486. package/plugins/pbr/scripts/post-write-dispatch.js +201 -31
  487. package/plugins/pbr/scripts/post-write-quality.js +4 -3
  488. package/plugins/pbr/scripts/pre-bash-dispatch.js +147 -51
  489. package/plugins/pbr/scripts/pre-skill-dispatch.js +114 -0
  490. package/plugins/pbr/scripts/pre-task-dispatch.js +269 -0
  491. package/plugins/pbr/scripts/pre-write-dispatch.js +170 -73
  492. package/plugins/pbr/scripts/progress-tracker.js +121 -324
  493. package/plugins/pbr/scripts/prompt-guard.js +114 -0
  494. package/plugins/pbr/scripts/prompt-routing.js +209 -0
  495. package/plugins/pbr/scripts/quick-status.js +179 -0
  496. package/plugins/pbr/scripts/record-incident.js +37 -0
  497. package/plugins/pbr/scripts/risk-classifier.cjs +123 -0
  498. package/plugins/pbr/scripts/run-hook.js +63 -23
  499. package/plugins/pbr/scripts/session-cleanup.js +428 -29
  500. package/plugins/pbr/scripts/session-tracker.js +124 -0
  501. package/plugins/pbr/scripts/status-line.js +593 -32
  502. package/plugins/pbr/scripts/suggest-compact.js +201 -13
  503. package/plugins/pbr/scripts/sync-context-to-claude.js +100 -0
  504. package/plugins/pbr/scripts/task-completed.js +165 -4
  505. package/plugins/pbr/scripts/test/config.test.js +126 -0
  506. package/plugins/pbr/scripts/test/cross-platform.test.js +120 -0
  507. package/plugins/pbr/scripts/test/fixtures/config.json +20 -0
  508. package/plugins/pbr/scripts/test/fixtures/plan.md +54 -0
  509. package/plugins/pbr/scripts/test/fixtures/project.md +30 -0
  510. package/plugins/pbr/scripts/test/fixtures/roadmap.md +55 -0
  511. package/plugins/pbr/scripts/test/fixtures/state.md +60 -0
  512. package/plugins/pbr/scripts/test/fixtures/summary.md +35 -0
  513. package/plugins/pbr/scripts/test/fixtures.test.js +184 -0
  514. package/plugins/pbr/scripts/test/phase.test.js +142 -0
  515. package/plugins/pbr/scripts/test/roadmap.test.js +96 -0
  516. package/plugins/pbr/scripts/test/state.test.js +155 -0
  517. package/plugins/pbr/scripts/track-context-budget.js +368 -104
  518. package/plugins/pbr/scripts/track-user-gates.js +88 -0
  519. package/plugins/pbr/scripts/trust-tracker.js +193 -0
  520. package/plugins/pbr/scripts/validate-commit.js +59 -26
  521. package/plugins/pbr/scripts/validate-skill-args.js +87 -15
  522. package/plugins/pbr/scripts/validate-task.js +83 -627
  523. package/plugins/pbr/scripts/worktree-create.js +144 -0
  524. package/plugins/pbr/scripts/worktree-remove.js +147 -0
  525. package/plugins/pbr/skills/audit/SKILL.md +195 -24
  526. package/plugins/pbr/skills/audit-fix/SKILL.md +326 -0
  527. package/plugins/pbr/skills/autonomous/SKILL.md +551 -0
  528. package/plugins/pbr/skills/backlog/SKILL.md +56 -0
  529. package/plugins/pbr/skills/begin/SKILL.md +508 -153
  530. package/plugins/pbr/skills/begin/templates/STATE.md.tmpl +1 -2
  531. package/plugins/pbr/skills/begin/templates/config.json.tmpl +419 -36
  532. package/plugins/pbr/skills/begin/templates/researcher-prompt.md.tmpl +28 -0
  533. package/plugins/pbr/skills/begin/templates/roadmap-prompt.md.tmpl +28 -3
  534. package/plugins/pbr/skills/begin/templates/synthesis-prompt.md.tmpl +33 -5
  535. package/plugins/pbr/skills/build/SKILL.md +1180 -358
  536. package/plugins/pbr/skills/build/templates/continuation-prompt.md.tmpl +26 -0
  537. package/plugins/pbr/skills/build/templates/executor-prompt.md.tmpl +77 -0
  538. package/plugins/pbr/skills/build/templates/inline-verifier-prompt.md.tmpl +33 -0
  539. package/plugins/pbr/skills/build/templates/qa-round-context.md.tmpl +16 -0
  540. package/plugins/pbr/skills/config/SKILL.md +112 -9
  541. package/plugins/pbr/skills/continue/SKILL.md +113 -33
  542. package/plugins/pbr/skills/dashboard/SKILL.md +21 -9
  543. package/plugins/pbr/skills/debug/SKILL.md +70 -12
  544. package/plugins/pbr/skills/debug/templates/continuation-prompt.md.tmpl +12 -1
  545. package/plugins/pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +12 -5
  546. package/plugins/pbr/skills/discuss/SKILL.md +205 -24
  547. package/plugins/pbr/skills/discuss/templates/CONTEXT.md.tmpl +21 -1
  548. package/plugins/pbr/skills/do/SKILL.md +119 -24
  549. package/plugins/pbr/skills/explore/SKILL.md +95 -20
  550. package/plugins/pbr/skills/fast/SKILL.md +94 -0
  551. package/plugins/pbr/skills/forensics/SKILL.md +144 -0
  552. package/plugins/pbr/skills/health/SKILL.md +35 -117
  553. package/plugins/pbr/skills/help/SKILL.md +83 -123
  554. package/plugins/pbr/skills/import/SKILL.md +332 -13
  555. package/plugins/pbr/skills/intel/SKILL.md +131 -0
  556. package/plugins/pbr/skills/list-phase-assumptions/SKILL.md +231 -0
  557. package/plugins/pbr/skills/milestone/SKILL.md +383 -274
  558. package/plugins/pbr/skills/milestone/templates/audit-output.md.tmpl +76 -0
  559. package/plugins/pbr/skills/milestone/templates/complete-output.md.tmpl +32 -0
  560. package/plugins/pbr/skills/milestone/templates/edge-cases.md +54 -0
  561. package/plugins/pbr/skills/milestone/templates/gaps-output.md.tmpl +25 -0
  562. package/plugins/pbr/skills/milestone/templates/integration-checker-prompt.md.tmpl +25 -0
  563. package/plugins/pbr/skills/milestone/templates/new-output.md.tmpl +29 -0
  564. package/plugins/pbr/skills/milestone-summary/SKILL.md +86 -0
  565. package/plugins/pbr/skills/note/SKILL.md +20 -4
  566. package/plugins/pbr/skills/pause/SKILL.md +54 -14
  567. package/plugins/pbr/skills/pause/templates/continue-here.md.tmpl +33 -52
  568. package/plugins/pbr/skills/plan/SKILL.md +526 -280
  569. package/plugins/pbr/skills/plan/templates/checker-prompt.md.tmpl +20 -2
  570. package/plugins/pbr/skills/plan/templates/completion-output.md.tmpl +27 -0
  571. package/plugins/pbr/skills/plan/templates/planner-prompt.md.tmpl +43 -1
  572. package/plugins/pbr/skills/plan/templates/revision-prompt.md.tmpl +21 -5
  573. package/plugins/pbr/skills/profile/SKILL.md +185 -0
  574. package/plugins/pbr/skills/profile-user/SKILL.md +227 -0
  575. package/plugins/pbr/skills/quick/SKILL.md +435 -100
  576. package/plugins/pbr/skills/release/SKILL.md +206 -0
  577. package/plugins/pbr/skills/resume/SKILL.md +170 -46
  578. package/plugins/pbr/skills/review/SKILL.md +233 -165
  579. package/plugins/pbr/skills/review/templates/verifier-prompt.md.tmpl +7 -0
  580. package/plugins/pbr/skills/scan/SKILL.md +152 -106
  581. package/plugins/pbr/skills/scan/templates/mapper-prompt.md.tmpl +5 -56
  582. package/plugins/pbr/skills/seed/SKILL.md +87 -0
  583. package/plugins/pbr/skills/session-report/SKILL.md +130 -0
  584. package/plugins/pbr/skills/setup/SKILL.md +150 -202
  585. package/plugins/pbr/skills/shared/agent-context-enrichment.md +21 -0
  586. package/plugins/pbr/skills/shared/agent-type-resolution.md +32 -0
  587. package/plugins/pbr/skills/shared/commit-planning-docs.md +8 -0
  588. package/plugins/pbr/skills/shared/context-budget.md +66 -1
  589. package/plugins/pbr/skills/shared/context-loader-task.md +18 -11
  590. package/plugins/pbr/skills/shared/criterion-writing.md +58 -0
  591. package/plugins/pbr/skills/shared/digest-select.md +2 -2
  592. package/plugins/pbr/skills/shared/domain-probes.md +1 -1
  593. package/plugins/pbr/skills/shared/error-reporting.md +38 -60
  594. package/plugins/pbr/skills/shared/gate-prompts.md +4 -2
  595. package/plugins/pbr/skills/shared/memory-capture.md +48 -0
  596. package/plugins/pbr/skills/shared/phase-argument-parsing.md +4 -4
  597. package/plugins/pbr/skills/shared/revision-loop.md +24 -6
  598. package/plugins/pbr/skills/shared/state-update.md +49 -56
  599. package/plugins/pbr/skills/shared/universal-anti-patterns.md +27 -4
  600. package/plugins/pbr/skills/ship/SKILL.md +155 -0
  601. package/plugins/pbr/skills/stats/SKILL.md +110 -0
  602. package/plugins/pbr/skills/status/SKILL.md +185 -119
  603. package/plugins/pbr/skills/test/SKILL.md +254 -0
  604. package/plugins/pbr/skills/thread/SKILL.md +73 -0
  605. package/plugins/pbr/skills/todo/SKILL.md +28 -72
  606. package/plugins/pbr/skills/ui-phase/SKILL.md +180 -0
  607. package/plugins/pbr/skills/ui-review/SKILL.md +206 -0
  608. package/plugins/pbr/skills/undo/SKILL.md +221 -0
  609. package/plugins/pbr/skills/validate-phase/SKILL.md +362 -0
  610. package/plugins/pbr/templates/CONTEXT.md.tmpl +45 -20
  611. package/plugins/pbr/templates/DISCOVERY.md.tmpl +29 -0
  612. package/plugins/pbr/templates/DISCUSSION-LOG.md.tmpl +49 -0
  613. package/plugins/pbr/templates/HANDOFF.json.tmpl +30 -0
  614. package/plugins/pbr/templates/INTEGRATION-REPORT.md.tmpl +18 -2
  615. package/plugins/pbr/templates/MILESTONE-AUDIT.md.tmpl +44 -0
  616. package/plugins/pbr/templates/PROJECT.md.tmpl +126 -0
  617. package/plugins/pbr/templates/REQUIREMENTS.md.tmpl +96 -0
  618. package/plugins/pbr/templates/RETROSPECTIVE.md.tmpl +43 -0
  619. package/plugins/pbr/templates/ROADMAP.md.tmpl +108 -14
  620. package/plugins/pbr/templates/SUMMARY-complex.md.tmpl +133 -0
  621. package/plugins/pbr/templates/SUMMARY-minimal.md.tmpl +55 -0
  622. package/plugins/pbr/templates/SUMMARY.md.tmpl +21 -0
  623. package/plugins/pbr/templates/UAT.md.tmpl +94 -0
  624. package/plugins/pbr/templates/UI-SPEC.md.tmpl +144 -0
  625. package/plugins/pbr/templates/VALIDATION.md.tmpl +94 -0
  626. package/plugins/pbr/templates/VERIFICATION-DETAIL.md.tmpl +54 -13
  627. package/plugins/pbr/templates/project-CONTEXT.md.tmpl +59 -0
  628. package/plugins/pbr/templates/research-outputs/ARCHITECTURE.md.tmpl +91 -0
  629. package/plugins/pbr/templates/research-outputs/FEATURES.md.tmpl +64 -0
  630. package/plugins/pbr/templates/research-outputs/PITFALLS.md.tmpl +50 -0
  631. package/plugins/pbr/templates/research-outputs/STACK.md.tmpl +63 -0
  632. package/plugins/pbr/templates/research-outputs/SUMMARY.md.tmpl +98 -0
  633. package/scripts/build-hooks.js +61 -0
  634. package/scripts/check-ci.js +100 -0
  635. package/scripts/clean-changelog.js +364 -0
  636. package/scripts/generate-derivatives.js +581 -0
  637. package/scripts/posttest.js +93 -0
  638. package/scripts/release.js +262 -0
  639. package/scripts/run-tests.cjs +29 -0
  640. package/scripts/test-wrapper.js +43 -0
  641. package/dashboard/bin/cli.js +0 -25
  642. package/dashboard/public/css/layout.css +0 -704
  643. package/dashboard/public/css/status-colors.css +0 -98
  644. package/dashboard/public/css/tokens.css +0 -59
  645. package/dashboard/public/js/htmx-title.js +0 -5
  646. package/dashboard/public/js/sidebar-toggle.js +0 -34
  647. package/dashboard/public/js/sse-client.js +0 -100
  648. package/dashboard/public/js/theme-toggle.js +0 -46
  649. package/dashboard/src/app.js +0 -91
  650. package/dashboard/src/middleware/current-phase.js +0 -24
  651. package/dashboard/src/middleware/errorHandler.js +0 -52
  652. package/dashboard/src/middleware/notFoundHandler.js +0 -9
  653. package/dashboard/src/repositories/planning.repository.js +0 -130
  654. package/dashboard/src/routes/events.routes.js +0 -45
  655. package/dashboard/src/routes/index.routes.js +0 -35
  656. package/dashboard/src/routes/pages.routes.js +0 -426
  657. package/dashboard/src/server.js +0 -42
  658. package/dashboard/src/services/analytics.service.js +0 -141
  659. package/dashboard/src/services/dashboard.service.js +0 -309
  660. package/dashboard/src/services/milestone.service.js +0 -222
  661. package/dashboard/src/services/notes.service.js +0 -50
  662. package/dashboard/src/services/phase.service.js +0 -232
  663. package/dashboard/src/services/project.service.js +0 -57
  664. package/dashboard/src/services/roadmap.service.js +0 -258
  665. package/dashboard/src/services/sse.service.js +0 -58
  666. package/dashboard/src/services/todo.service.js +0 -272
  667. package/dashboard/src/services/watcher.service.js +0 -48
  668. package/dashboard/src/utils/cache.js +0 -55
  669. package/dashboard/src/views/analytics.ejs +0 -5
  670. package/dashboard/src/views/coming-soon.ejs +0 -11
  671. package/dashboard/src/views/dependencies.ejs +0 -5
  672. package/dashboard/src/views/error.ejs +0 -20
  673. package/dashboard/src/views/index.ejs +0 -5
  674. package/dashboard/src/views/milestone-detail.ejs +0 -5
  675. package/dashboard/src/views/milestones.ejs +0 -5
  676. package/dashboard/src/views/notes.ejs +0 -5
  677. package/dashboard/src/views/partials/analytics-content.ejs +0 -90
  678. package/dashboard/src/views/partials/breadcrumbs.ejs +0 -14
  679. package/dashboard/src/views/partials/dashboard-content.ejs +0 -84
  680. package/dashboard/src/views/partials/dependencies-content.ejs +0 -48
  681. package/dashboard/src/views/partials/empty-state.ejs +0 -7
  682. package/dashboard/src/views/partials/footer.ejs +0 -3
  683. package/dashboard/src/views/partials/head.ejs +0 -30
  684. package/dashboard/src/views/partials/header.ejs +0 -21
  685. package/dashboard/src/views/partials/layout-bottom.ejs +0 -43
  686. package/dashboard/src/views/partials/layout-top.ejs +0 -16
  687. package/dashboard/src/views/partials/milestone-detail-content.ejs +0 -20
  688. package/dashboard/src/views/partials/milestones-content.ejs +0 -88
  689. package/dashboard/src/views/partials/notes-content.ejs +0 -23
  690. package/dashboard/src/views/partials/phase-content.ejs +0 -193
  691. package/dashboard/src/views/partials/phase-doc-content.ejs +0 -38
  692. package/dashboard/src/views/partials/phases-content.ejs +0 -124
  693. package/dashboard/src/views/partials/roadmap-content.ejs +0 -180
  694. package/dashboard/src/views/partials/sidebar.ejs +0 -99
  695. package/dashboard/src/views/partials/todo-create-content.ejs +0 -54
  696. package/dashboard/src/views/partials/todo-detail-content.ejs +0 -42
  697. package/dashboard/src/views/partials/todos-content.ejs +0 -97
  698. package/dashboard/src/views/phase-detail.ejs +0 -5
  699. package/dashboard/src/views/phase-doc.ejs +0 -5
  700. package/dashboard/src/views/phases.ejs +0 -5
  701. package/dashboard/src/views/roadmap.ejs +0 -5
  702. package/dashboard/src/views/todo-create.ejs +0 -5
  703. package/dashboard/src/views/todo-detail.ejs +0 -5
  704. package/dashboard/src/views/todos.ejs +0 -5
  705. package/plugins/copilot-pbr/CHANGELOG.md +0 -19
  706. package/plugins/copilot-pbr/README.md +0 -139
  707. package/plugins/copilot-pbr/agents/audit.agent.md +0 -113
  708. package/plugins/copilot-pbr/agents/codebase-mapper.agent.md +0 -151
  709. package/plugins/copilot-pbr/agents/debugger.agent.md +0 -182
  710. package/plugins/copilot-pbr/agents/executor.agent.md +0 -267
  711. package/plugins/copilot-pbr/agents/general.agent.md +0 -88
  712. package/plugins/copilot-pbr/agents/integration-checker.agent.md +0 -119
  713. package/plugins/copilot-pbr/agents/plan-checker.agent.md +0 -208
  714. package/plugins/copilot-pbr/agents/planner.agent.md +0 -238
  715. package/plugins/copilot-pbr/agents/researcher.agent.md +0 -186
  716. package/plugins/copilot-pbr/agents/synthesizer.agent.md +0 -126
  717. package/plugins/copilot-pbr/agents/verifier.agent.md +0 -228
  718. package/plugins/copilot-pbr/hooks/hooks.json +0 -258
  719. package/plugins/copilot-pbr/plugin.json +0 -30
  720. package/plugins/copilot-pbr/references/agent-anti-patterns.md +0 -25
  721. package/plugins/copilot-pbr/references/agent-contracts.md +0 -297
  722. package/plugins/copilot-pbr/references/agent-interactions.md +0 -135
  723. package/plugins/copilot-pbr/references/agent-teams.md +0 -55
  724. package/plugins/copilot-pbr/references/checkpoints.md +0 -158
  725. package/plugins/copilot-pbr/references/common-bug-patterns.md +0 -14
  726. package/plugins/copilot-pbr/references/config-reference.md +0 -442
  727. package/plugins/copilot-pbr/references/continuation-format.md +0 -213
  728. package/plugins/copilot-pbr/references/deviation-rules.md +0 -113
  729. package/plugins/copilot-pbr/references/git-integration.md +0 -227
  730. package/plugins/copilot-pbr/references/integration-patterns.md +0 -118
  731. package/plugins/copilot-pbr/references/model-profiles.md +0 -100
  732. package/plugins/copilot-pbr/references/model-selection.md +0 -32
  733. package/plugins/copilot-pbr/references/pbr-rules.md +0 -195
  734. package/plugins/copilot-pbr/references/pbr-tools-cli.md +0 -285
  735. package/plugins/copilot-pbr/references/plan-authoring.md +0 -182
  736. package/plugins/copilot-pbr/references/plan-format.md +0 -288
  737. package/plugins/copilot-pbr/references/planning-config.md +0 -214
  738. package/plugins/copilot-pbr/references/questioning.md +0 -215
  739. package/plugins/copilot-pbr/references/reading-verification.md +0 -128
  740. package/plugins/copilot-pbr/references/stub-patterns.md +0 -161
  741. package/plugins/copilot-pbr/references/subagent-coordination.md +0 -120
  742. package/plugins/copilot-pbr/references/ui-formatting.md +0 -444
  743. package/plugins/copilot-pbr/references/verification-patterns.md +0 -199
  744. package/plugins/copilot-pbr/references/wave-execution.md +0 -96
  745. package/plugins/copilot-pbr/rules/pbr-workflow.mdc +0 -48
  746. package/plugins/copilot-pbr/setup.ps1 +0 -93
  747. package/plugins/copilot-pbr/setup.sh +0 -93
  748. package/plugins/copilot-pbr/skills/audit/SKILL.md +0 -330
  749. package/plugins/copilot-pbr/skills/begin/SKILL.md +0 -589
  750. package/plugins/copilot-pbr/skills/begin/templates/PROJECT.md.tmpl +0 -34
  751. package/plugins/copilot-pbr/skills/begin/templates/REQUIREMENTS.md.tmpl +0 -19
  752. package/plugins/copilot-pbr/skills/begin/templates/STATE.md.tmpl +0 -50
  753. package/plugins/copilot-pbr/skills/begin/templates/config.json.tmpl +0 -64
  754. package/plugins/copilot-pbr/skills/begin/templates/researcher-prompt.md.tmpl +0 -20
  755. package/plugins/copilot-pbr/skills/begin/templates/roadmap-prompt.md.tmpl +0 -31
  756. package/plugins/copilot-pbr/skills/begin/templates/synthesis-prompt.md.tmpl +0 -17
  757. package/plugins/copilot-pbr/skills/build/SKILL.md +0 -960
  758. package/plugins/copilot-pbr/skills/config/SKILL.md +0 -250
  759. package/plugins/copilot-pbr/skills/continue/SKILL.md +0 -159
  760. package/plugins/copilot-pbr/skills/dashboard/SKILL.md +0 -43
  761. package/plugins/copilot-pbr/skills/debug/SKILL.md +0 -508
  762. package/plugins/copilot-pbr/skills/debug/templates/continuation-prompt.md.tmpl +0 -17
  763. package/plugins/copilot-pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +0 -28
  764. package/plugins/copilot-pbr/skills/discuss/SKILL.md +0 -353
  765. package/plugins/copilot-pbr/skills/discuss/templates/CONTEXT.md.tmpl +0 -62
  766. package/plugins/copilot-pbr/skills/discuss/templates/decision-categories.md +0 -10
  767. package/plugins/copilot-pbr/skills/do/SKILL.md +0 -66
  768. package/plugins/copilot-pbr/skills/explore/SKILL.md +0 -373
  769. package/plugins/copilot-pbr/skills/health/SKILL.md +0 -283
  770. package/plugins/copilot-pbr/skills/health/templates/check-pattern.md.tmpl +0 -31
  771. package/plugins/copilot-pbr/skills/health/templates/output-format.md.tmpl +0 -64
  772. package/plugins/copilot-pbr/skills/help/SKILL.md +0 -193
  773. package/plugins/copilot-pbr/skills/import/SKILL.md +0 -502
  774. package/plugins/copilot-pbr/skills/milestone/SKILL.md +0 -806
  775. package/plugins/copilot-pbr/skills/milestone/templates/audit-report.md.tmpl +0 -49
  776. package/plugins/copilot-pbr/skills/milestone/templates/stats-file.md.tmpl +0 -31
  777. package/plugins/copilot-pbr/skills/note/SKILL.md +0 -213
  778. package/plugins/copilot-pbr/skills/pause/SKILL.md +0 -247
  779. package/plugins/copilot-pbr/skills/pause/templates/continue-here.md.tmpl +0 -72
  780. package/plugins/copilot-pbr/skills/plan/SKILL.md +0 -662
  781. package/plugins/copilot-pbr/skills/plan/templates/checker-prompt.md.tmpl +0 -22
  782. package/plugins/copilot-pbr/skills/plan/templates/gap-closure-prompt.md.tmpl +0 -33
  783. package/plugins/copilot-pbr/skills/plan/templates/planner-prompt.md.tmpl +0 -39
  784. package/plugins/copilot-pbr/skills/plan/templates/researcher-prompt.md.tmpl +0 -20
  785. package/plugins/copilot-pbr/skills/plan/templates/revision-prompt.md.tmpl +0 -24
  786. package/plugins/copilot-pbr/skills/quick/SKILL.md +0 -376
  787. package/plugins/copilot-pbr/skills/resume/SKILL.md +0 -399
  788. package/plugins/copilot-pbr/skills/review/SKILL.md +0 -653
  789. package/plugins/copilot-pbr/skills/review/templates/debugger-prompt.md.tmpl +0 -61
  790. package/plugins/copilot-pbr/skills/review/templates/gap-planner-prompt.md.tmpl +0 -41
  791. package/plugins/copilot-pbr/skills/review/templates/verifier-prompt.md.tmpl +0 -116
  792. package/plugins/copilot-pbr/skills/scan/SKILL.md +0 -299
  793. package/plugins/copilot-pbr/skills/scan/templates/mapper-prompt.md.tmpl +0 -202
  794. package/plugins/copilot-pbr/skills/setup/SKILL.md +0 -296
  795. package/plugins/copilot-pbr/skills/shared/commit-planning-docs.md +0 -36
  796. package/plugins/copilot-pbr/skills/shared/config-loading.md +0 -103
  797. package/plugins/copilot-pbr/skills/shared/context-budget.md +0 -41
  798. package/plugins/copilot-pbr/skills/shared/context-loader-task.md +0 -87
  799. package/plugins/copilot-pbr/skills/shared/digest-select.md +0 -80
  800. package/plugins/copilot-pbr/skills/shared/domain-probes.md +0 -126
  801. package/plugins/copilot-pbr/skills/shared/error-recovery-strategies.md +0 -51
  802. package/plugins/copilot-pbr/skills/shared/error-reporting.md +0 -81
  803. package/plugins/copilot-pbr/skills/shared/gate-prompts.md +0 -389
  804. package/plugins/copilot-pbr/skills/shared/phase-argument-parsing.md +0 -46
  805. package/plugins/copilot-pbr/skills/shared/progress-display.md +0 -53
  806. package/plugins/copilot-pbr/skills/shared/revision-loop.md +0 -82
  807. package/plugins/copilot-pbr/skills/shared/state-loading.md +0 -63
  808. package/plugins/copilot-pbr/skills/shared/state-update.md +0 -162
  809. package/plugins/copilot-pbr/skills/shared/universal-anti-patterns.md +0 -38
  810. package/plugins/copilot-pbr/skills/status/SKILL.md +0 -362
  811. package/plugins/copilot-pbr/skills/statusline/SKILL.md +0 -149
  812. package/plugins/copilot-pbr/skills/todo/SKILL.md +0 -279
  813. package/plugins/copilot-pbr/templates/CONTEXT.md.tmpl +0 -53
  814. package/plugins/copilot-pbr/templates/INTEGRATION-REPORT.md.tmpl +0 -152
  815. package/plugins/copilot-pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -98
  816. package/plugins/copilot-pbr/templates/ROADMAP.md.tmpl +0 -41
  817. package/plugins/copilot-pbr/templates/SUMMARY.md.tmpl +0 -82
  818. package/plugins/copilot-pbr/templates/VERIFICATION-DETAIL.md.tmpl +0 -117
  819. package/plugins/copilot-pbr/templates/codebase/ARCHITECTURE.md.tmpl +0 -98
  820. package/plugins/copilot-pbr/templates/codebase/CONCERNS.md.tmpl +0 -93
  821. package/plugins/copilot-pbr/templates/codebase/CONVENTIONS.md.tmpl +0 -104
  822. package/plugins/copilot-pbr/templates/codebase/INTEGRATIONS.md.tmpl +0 -78
  823. package/plugins/copilot-pbr/templates/codebase/STACK.md.tmpl +0 -78
  824. package/plugins/copilot-pbr/templates/codebase/STRUCTURE.md.tmpl +0 -80
  825. package/plugins/copilot-pbr/templates/codebase/TESTING.md.tmpl +0 -107
  826. package/plugins/copilot-pbr/templates/continue-here.md.tmpl +0 -74
  827. package/plugins/copilot-pbr/templates/prompt-partials/phase-project-context.md.tmpl +0 -38
  828. package/plugins/copilot-pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
  829. package/plugins/copilot-pbr/templates/research/STACK.md.tmpl +0 -71
  830. package/plugins/copilot-pbr/templates/research/SUMMARY.md.tmpl +0 -112
  831. package/plugins/copilot-pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
  832. package/plugins/copilot-pbr/templates/research-outputs/project-research.md.tmpl +0 -99
  833. package/plugins/copilot-pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
  834. package/plugins/cursor-pbr/.cursor-plugin/plugin.json +0 -32
  835. package/plugins/cursor-pbr/CHANGELOG.md +0 -15
  836. package/plugins/cursor-pbr/README.md +0 -123
  837. package/plugins/cursor-pbr/agents/audit.md +0 -178
  838. package/plugins/cursor-pbr/agents/codebase-mapper.md +0 -150
  839. package/plugins/cursor-pbr/agents/debugger.md +0 -181
  840. package/plugins/cursor-pbr/agents/executor.md +0 -266
  841. package/plugins/cursor-pbr/agents/general.md +0 -87
  842. package/plugins/cursor-pbr/agents/integration-checker.md +0 -118
  843. package/plugins/cursor-pbr/agents/plan-checker.md +0 -207
  844. package/plugins/cursor-pbr/agents/planner.md +0 -237
  845. package/plugins/cursor-pbr/agents/researcher.md +0 -185
  846. package/plugins/cursor-pbr/agents/synthesizer.md +0 -125
  847. package/plugins/cursor-pbr/agents/verifier.md +0 -227
  848. package/plugins/cursor-pbr/assets/.gitkeep +0 -0
  849. package/plugins/cursor-pbr/assets/logo.svg +0 -21
  850. package/plugins/cursor-pbr/hooks/hooks.json +0 -224
  851. package/plugins/cursor-pbr/references/agent-anti-patterns.md +0 -25
  852. package/plugins/cursor-pbr/references/agent-contracts.md +0 -297
  853. package/plugins/cursor-pbr/references/agent-interactions.md +0 -135
  854. package/plugins/cursor-pbr/references/agent-teams.md +0 -55
  855. package/plugins/cursor-pbr/references/checkpoints.md +0 -158
  856. package/plugins/cursor-pbr/references/common-bug-patterns.md +0 -14
  857. package/plugins/cursor-pbr/references/config-reference.md +0 -442
  858. package/plugins/cursor-pbr/references/continuation-format.md +0 -213
  859. package/plugins/cursor-pbr/references/deviation-rules.md +0 -113
  860. package/plugins/cursor-pbr/references/git-integration.md +0 -227
  861. package/plugins/cursor-pbr/references/integration-patterns.md +0 -118
  862. package/plugins/cursor-pbr/references/model-profiles.md +0 -100
  863. package/plugins/cursor-pbr/references/model-selection.md +0 -32
  864. package/plugins/cursor-pbr/references/pbr-rules.md +0 -195
  865. package/plugins/cursor-pbr/references/pbr-tools-cli.md +0 -285
  866. package/plugins/cursor-pbr/references/plan-authoring.md +0 -182
  867. package/plugins/cursor-pbr/references/plan-format.md +0 -288
  868. package/plugins/cursor-pbr/references/planning-config.md +0 -214
  869. package/plugins/cursor-pbr/references/questioning.md +0 -215
  870. package/plugins/cursor-pbr/references/reading-verification.md +0 -128
  871. package/plugins/cursor-pbr/references/stub-patterns.md +0 -161
  872. package/plugins/cursor-pbr/references/subagent-coordination.md +0 -120
  873. package/plugins/cursor-pbr/references/ui-formatting.md +0 -444
  874. package/plugins/cursor-pbr/references/verification-patterns.md +0 -199
  875. package/plugins/cursor-pbr/references/wave-execution.md +0 -96
  876. package/plugins/cursor-pbr/rules/pbr-workflow.mdc +0 -48
  877. package/plugins/cursor-pbr/setup.ps1 +0 -78
  878. package/plugins/cursor-pbr/setup.sh +0 -83
  879. package/plugins/cursor-pbr/skills/audit/SKILL.md +0 -331
  880. package/plugins/cursor-pbr/skills/begin/SKILL.md +0 -589
  881. package/plugins/cursor-pbr/skills/begin/templates/PROJECT.md.tmpl +0 -34
  882. package/plugins/cursor-pbr/skills/begin/templates/REQUIREMENTS.md.tmpl +0 -19
  883. package/plugins/cursor-pbr/skills/begin/templates/STATE.md.tmpl +0 -50
  884. package/plugins/cursor-pbr/skills/begin/templates/config.json.tmpl +0 -64
  885. package/plugins/cursor-pbr/skills/begin/templates/researcher-prompt.md.tmpl +0 -20
  886. package/plugins/cursor-pbr/skills/begin/templates/roadmap-prompt.md.tmpl +0 -31
  887. package/plugins/cursor-pbr/skills/begin/templates/synthesis-prompt.md.tmpl +0 -17
  888. package/plugins/cursor-pbr/skills/build/SKILL.md +0 -961
  889. package/plugins/cursor-pbr/skills/config/SKILL.md +0 -252
  890. package/plugins/cursor-pbr/skills/continue/SKILL.md +0 -159
  891. package/plugins/cursor-pbr/skills/dashboard/SKILL.md +0 -44
  892. package/plugins/cursor-pbr/skills/debug/SKILL.md +0 -512
  893. package/plugins/cursor-pbr/skills/debug/templates/continuation-prompt.md.tmpl +0 -17
  894. package/plugins/cursor-pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +0 -28
  895. package/plugins/cursor-pbr/skills/discuss/SKILL.md +0 -354
  896. package/plugins/cursor-pbr/skills/discuss/templates/CONTEXT.md.tmpl +0 -62
  897. package/plugins/cursor-pbr/skills/discuss/templates/decision-categories.md +0 -10
  898. package/plugins/cursor-pbr/skills/do/SKILL.md +0 -67
  899. package/plugins/cursor-pbr/skills/explore/SKILL.md +0 -376
  900. package/plugins/cursor-pbr/skills/health/SKILL.md +0 -283
  901. package/plugins/cursor-pbr/skills/health/templates/check-pattern.md.tmpl +0 -31
  902. package/plugins/cursor-pbr/skills/health/templates/output-format.md.tmpl +0 -64
  903. package/plugins/cursor-pbr/skills/help/SKILL.md +0 -193
  904. package/plugins/cursor-pbr/skills/import/SKILL.md +0 -505
  905. package/plugins/cursor-pbr/skills/milestone/SKILL.md +0 -807
  906. package/plugins/cursor-pbr/skills/milestone/templates/audit-report.md.tmpl +0 -49
  907. package/plugins/cursor-pbr/skills/milestone/templates/stats-file.md.tmpl +0 -31
  908. package/plugins/cursor-pbr/skills/note/SKILL.md +0 -214
  909. package/plugins/cursor-pbr/skills/pause/SKILL.md +0 -248
  910. package/plugins/cursor-pbr/skills/pause/templates/continue-here.md.tmpl +0 -72
  911. package/plugins/cursor-pbr/skills/plan/SKILL.md +0 -663
  912. package/plugins/cursor-pbr/skills/plan/templates/checker-prompt.md.tmpl +0 -22
  913. package/plugins/cursor-pbr/skills/plan/templates/gap-closure-prompt.md.tmpl +0 -33
  914. package/plugins/cursor-pbr/skills/plan/templates/planner-prompt.md.tmpl +0 -39
  915. package/plugins/cursor-pbr/skills/plan/templates/researcher-prompt.md.tmpl +0 -20
  916. package/plugins/cursor-pbr/skills/plan/templates/revision-prompt.md.tmpl +0 -24
  917. package/plugins/cursor-pbr/skills/quick/SKILL.md +0 -376
  918. package/plugins/cursor-pbr/skills/resume/SKILL.md +0 -399
  919. package/plugins/cursor-pbr/skills/review/SKILL.md +0 -654
  920. package/plugins/cursor-pbr/skills/review/templates/debugger-prompt.md.tmpl +0 -61
  921. package/plugins/cursor-pbr/skills/review/templates/gap-planner-prompt.md.tmpl +0 -41
  922. package/plugins/cursor-pbr/skills/review/templates/verifier-prompt.md.tmpl +0 -116
  923. package/plugins/cursor-pbr/skills/scan/SKILL.md +0 -300
  924. package/plugins/cursor-pbr/skills/scan/templates/mapper-prompt.md.tmpl +0 -202
  925. package/plugins/cursor-pbr/skills/setup/SKILL.md +0 -296
  926. package/plugins/cursor-pbr/skills/shared/commit-planning-docs.md +0 -36
  927. package/plugins/cursor-pbr/skills/shared/config-loading.md +0 -103
  928. package/plugins/cursor-pbr/skills/shared/context-budget.md +0 -41
  929. package/plugins/cursor-pbr/skills/shared/context-loader-task.md +0 -87
  930. package/plugins/cursor-pbr/skills/shared/digest-select.md +0 -80
  931. package/plugins/cursor-pbr/skills/shared/domain-probes.md +0 -126
  932. package/plugins/cursor-pbr/skills/shared/error-recovery-strategies.md +0 -51
  933. package/plugins/cursor-pbr/skills/shared/error-reporting.md +0 -81
  934. package/plugins/cursor-pbr/skills/shared/gate-prompts.md +0 -389
  935. package/plugins/cursor-pbr/skills/shared/phase-argument-parsing.md +0 -46
  936. package/plugins/cursor-pbr/skills/shared/progress-display.md +0 -53
  937. package/plugins/cursor-pbr/skills/shared/revision-loop.md +0 -82
  938. package/plugins/cursor-pbr/skills/shared/state-loading.md +0 -63
  939. package/plugins/cursor-pbr/skills/shared/state-update.md +0 -162
  940. package/plugins/cursor-pbr/skills/shared/universal-anti-patterns.md +0 -38
  941. package/plugins/cursor-pbr/skills/status/SKILL.md +0 -362
  942. package/plugins/cursor-pbr/skills/statusline/SKILL.md +0 -150
  943. package/plugins/cursor-pbr/skills/todo/SKILL.md +0 -280
  944. package/plugins/cursor-pbr/templates/CONTEXT.md.tmpl +0 -53
  945. package/plugins/cursor-pbr/templates/INTEGRATION-REPORT.md.tmpl +0 -152
  946. package/plugins/cursor-pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -98
  947. package/plugins/cursor-pbr/templates/ROADMAP.md.tmpl +0 -41
  948. package/plugins/cursor-pbr/templates/SUMMARY.md.tmpl +0 -82
  949. package/plugins/cursor-pbr/templates/VERIFICATION-DETAIL.md.tmpl +0 -117
  950. package/plugins/cursor-pbr/templates/codebase/ARCHITECTURE.md.tmpl +0 -98
  951. package/plugins/cursor-pbr/templates/codebase/CONCERNS.md.tmpl +0 -93
  952. package/plugins/cursor-pbr/templates/codebase/CONVENTIONS.md.tmpl +0 -104
  953. package/plugins/cursor-pbr/templates/codebase/INTEGRATIONS.md.tmpl +0 -78
  954. package/plugins/cursor-pbr/templates/codebase/STACK.md.tmpl +0 -78
  955. package/plugins/cursor-pbr/templates/codebase/STRUCTURE.md.tmpl +0 -80
  956. package/plugins/cursor-pbr/templates/codebase/TESTING.md.tmpl +0 -107
  957. package/plugins/cursor-pbr/templates/continue-here.md.tmpl +0 -74
  958. package/plugins/cursor-pbr/templates/prompt-partials/phase-project-context.md.tmpl +0 -38
  959. package/plugins/cursor-pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
  960. package/plugins/cursor-pbr/templates/research/STACK.md.tmpl +0 -71
  961. package/plugins/cursor-pbr/templates/research/SUMMARY.md.tmpl +0 -112
  962. package/plugins/cursor-pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
  963. package/plugins/cursor-pbr/templates/research-outputs/project-research.md.tmpl +0 -99
  964. package/plugins/cursor-pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
  965. package/plugins/pbr/references/agent-interactions.md +0 -134
  966. package/plugins/pbr/references/pbr-rules.md +0 -194
  967. package/plugins/pbr/references/pbr-tools-cli.md +0 -285
  968. package/plugins/pbr/references/planning-config.md +0 -213
  969. package/plugins/pbr/references/subagent-coordination.md +0 -119
  970. package/plugins/pbr/references/ui-formatting.md +0 -444
  971. package/plugins/pbr/scripts/validate-plugin-structure.js +0 -183
  972. package/plugins/pbr/skills/milestone/templates/audit-report.md.tmpl +0 -48
  973. package/plugins/pbr/skills/shared/error-recovery-strategies.md +0 -51
  974. package/plugins/pbr/skills/shared/progress-display.md +0 -53
  975. package/plugins/pbr/skills/shared/state-loading.md +0 -62
  976. package/plugins/pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -97
  977. package/plugins/pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
  978. package/plugins/pbr/templates/research/STACK.md.tmpl +0 -71
  979. package/plugins/pbr/templates/research/SUMMARY.md.tmpl +0 -112
  980. package/plugins/pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
  981. package/plugins/pbr/templates/research-outputs/project-research.md.tmpl +0 -99
  982. package/plugins/pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
  983. /package/plugins/pbr/references/{agent-anti-patterns.md → archive/agent-anti-patterns.md} +0 -0
@@ -0,0 +1,2098 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ // ---------------------------------------------------------------------------
7
+ // Shared JSONL Helpers
8
+ // ---------------------------------------------------------------------------
9
+
10
+ /**
11
+ * Return the logs directory for a given .planning directory.
12
+ * @param {string} planningDir - Path to .planning/
13
+ * @returns {string}
14
+ */
15
+ function getLogsDir(planningDir) {
16
+ return path.join(planningDir, 'logs');
17
+ }
18
+
19
+ /**
20
+ * Read all JSONL files matching `{prefix}-*.jsonl` in a directory.
21
+ * Parses each line as JSON, skipping malformed lines.
22
+ * Returns array sorted by timestamp (ts field).
23
+ *
24
+ * @param {string} dir - Directory to scan
25
+ * @param {string} prefix - File prefix (e.g., 'events', 'hooks')
26
+ * @returns {Array<Object>} Parsed entries sorted by timestamp
27
+ */
28
+ function readJsonlFiles(dir, prefix) {
29
+ if (!fs.existsSync(dir)) return [];
30
+
31
+ const entries = [];
32
+ const pattern = new RegExp(`^${prefix}-.*\\.jsonl$`);
33
+
34
+ let files;
35
+ try {
36
+ files = fs.readdirSync(dir).filter(f => pattern.test(f)).sort();
37
+ } catch (_e) {
38
+ return [];
39
+ }
40
+
41
+ for (const file of files) {
42
+ try {
43
+ const content = fs.readFileSync(path.join(dir, file), 'utf8');
44
+ const lines = content.split('\n').filter(l => l.trim());
45
+ for (const line of lines) {
46
+ try {
47
+ entries.push(JSON.parse(line));
48
+ } catch (_e) {
49
+ // intentionally silent: skip malformed JSONL lines
50
+ }
51
+ }
52
+ } catch (_e) {
53
+ // intentionally silent: file may not exist or be unreadable
54
+ }
55
+ }
56
+
57
+ // Sort by timestamp
58
+ entries.sort((a, b) => {
59
+ const ta = a.ts || a.timestamp || '';
60
+ const tb = b.ts || b.timestamp || '';
61
+ return ta < tb ? -1 : ta > tb ? 1 : 0;
62
+ });
63
+
64
+ return entries;
65
+ }
66
+
67
+ /**
68
+ * Read session event logs from .planning/logs/events-*.jsonl.
69
+ * @param {string} planningDir - Path to .planning/
70
+ * @returns {Array<Object>}
71
+ */
72
+ function readSessionEvents(planningDir) {
73
+ return readJsonlFiles(getLogsDir(planningDir), 'events');
74
+ }
75
+
76
+ /**
77
+ * Read hook logs from .planning/logs/hooks-*.jsonl.
78
+ * @param {string} planningDir - Path to .planning/
79
+ * @returns {Array<Object>}
80
+ */
81
+ function readHookLogs(planningDir) {
82
+ return readJsonlFiles(getLogsDir(planningDir), 'hooks');
83
+ }
84
+
85
+ // ---------------------------------------------------------------------------
86
+ // BC-01: Skill Sequence Compliance
87
+ // ---------------------------------------------------------------------------
88
+
89
+ /**
90
+ * Known PBR skill names relevant to workflow ordering.
91
+ */
92
+ const WORKFLOW_SKILLS = ['plan', 'build', 'verify', 'review', 'begin', 'autonomous', 'continue'];
93
+
94
+ /**
95
+ * Valid skill ordering within a phase: plan < build < verify.
96
+ * Lower index = must come first.
97
+ */
98
+ const SKILL_ORDER = { plan: 0, build: 1, verify: 2, review: 3 };
99
+
100
+ /**
101
+ * Extract phase number from an event entry.
102
+ * Looks in various fields for phase references.
103
+ * @param {Object} entry - JSONL entry
104
+ * @returns {string|null} Phase number or null
105
+ */
106
+ function extractPhaseFromEntry(entry) {
107
+ // Check direct phase field
108
+ if (entry.phase) return String(entry.phase);
109
+
110
+ // Check details object
111
+ if (entry.details && entry.details.phase) return String(entry.details.phase);
112
+
113
+ // Check event string for phase references like "phase 3" or "03-"
114
+ const searchStr = JSON.stringify(entry);
115
+ const phaseMatch = searchStr.match(/phase[- _]?(\d+)/i) || searchStr.match(/(\d{2})-\d{2}/);
116
+ if (phaseMatch) return String(parseInt(phaseMatch[1], 10));
117
+
118
+ return null;
119
+ }
120
+
121
+ /**
122
+ * Extract skill name from an event entry.
123
+ * @param {Object} entry - JSONL entry
124
+ * @returns {string|null}
125
+ */
126
+ function extractSkillFromEntry(entry) {
127
+ // Direct event field matching skill names
128
+ if (entry.event && WORKFLOW_SKILLS.includes(entry.event)) return entry.event;
129
+
130
+ // Category-based skill detection
131
+ if (entry.cat === 'skill' && entry.event) return entry.event;
132
+
133
+ // Check for skill in hook entries (check-skill-workflow)
134
+ if (entry.hook === 'check-skill-workflow' && entry.details) {
135
+ const skill = entry.details.skill || entry.details.active_skill;
136
+ if (skill) return skill;
137
+ }
138
+
139
+ // Check for pbr: prefix in event names
140
+ if (entry.event && entry.event.startsWith('pbr:')) {
141
+ const name = entry.event.replace('pbr:', '').split('-')[0];
142
+ if (WORKFLOW_SKILLS.includes(name)) return name;
143
+ }
144
+
145
+ return null;
146
+ }
147
+
148
+ /**
149
+ * BC-01: Check that skills are invoked in valid order within each phase.
150
+ * plan must precede build, build must precede verify.
151
+ *
152
+ * @param {string} planningDir - Path to .planning/
153
+ * @param {Object} [_config] - Config object (unused, for API consistency)
154
+ * @returns {{ status: string, evidence: Array<string>, message: string }}
155
+ */
156
+ function checkSkillSequenceCompliance(planningDir, _config) {
157
+ const events = readSessionEvents(planningDir);
158
+ const hookLogs = readHookLogs(planningDir);
159
+ const allEntries = [...events, ...hookLogs].sort((a, b) => {
160
+ const ta = a.ts || a.timestamp || '';
161
+ const tb = b.ts || b.timestamp || '';
162
+ return ta < tb ? -1 : ta > tb ? 1 : 0;
163
+ });
164
+
165
+ if (allEntries.length === 0) {
166
+ return {
167
+ status: 'pass',
168
+ evidence: [],
169
+ message: 'BC-01: No session data available — cannot assess skill sequence'
170
+ };
171
+ }
172
+
173
+ // Build per-phase skill invocation timeline
174
+ // Map<phase, Array<{ skill, ts }>>
175
+ const phaseSkills = new Map();
176
+
177
+ for (const entry of allEntries) {
178
+ const skill = extractSkillFromEntry(entry);
179
+ const phase = extractPhaseFromEntry(entry);
180
+ if (!skill || !phase) continue;
181
+ if (!(skill in SKILL_ORDER)) continue;
182
+
183
+ if (!phaseSkills.has(phase)) phaseSkills.set(phase, []);
184
+ phaseSkills.get(phase).push({
185
+ skill,
186
+ ts: entry.ts || entry.timestamp || ''
187
+ });
188
+ }
189
+
190
+ const evidence = [];
191
+
192
+ for (const [phase, invocations] of phaseSkills) {
193
+ // Check ordering: for each pair, later skills should not appear before earlier ones
194
+ for (let i = 0; i < invocations.length; i++) {
195
+ for (let j = i + 1; j < invocations.length; j++) {
196
+ const earlier = invocations[i];
197
+ const later = invocations[j];
198
+ if (SKILL_ORDER[later.skill] < SKILL_ORDER[earlier.skill]) {
199
+ const time = later.ts ? ` at ${later.ts}` : '';
200
+ evidence.push(
201
+ `Phase ${phase}: ${later.skill} invoked before ${earlier.skill}` +
202
+ ` (${later.skill}${time}, no prior ${earlier.skill} event)`
203
+ );
204
+ }
205
+ }
206
+ }
207
+ }
208
+
209
+ if (evidence.length > 0) {
210
+ return {
211
+ status: 'fail',
212
+ evidence,
213
+ message: `BC-01: Found ${evidence.length} skill ordering violation(s)`
214
+ };
215
+ }
216
+
217
+ return {
218
+ status: 'pass',
219
+ evidence: [],
220
+ message: 'BC-01: All skill invocations follow valid ordering (plan < build < verify)'
221
+ };
222
+ }
223
+
224
+ // ---------------------------------------------------------------------------
225
+ // BC-02: State Machine Transition Validation
226
+ // ---------------------------------------------------------------------------
227
+
228
+ /**
229
+ * Valid state transitions in PBR workflow.
230
+ * Key = from status, Value = set of valid "to" statuses.
231
+ */
232
+ const VALID_TRANSITIONS = {
233
+ not_started: new Set(['discussed', 'ready_to_plan', 'planning']),
234
+ discussed: new Set(['ready_to_plan', 'planning']),
235
+ ready_to_plan: new Set(['planning']),
236
+ planning: new Set(['planned', 'building']), // building = inline execution skips planned
237
+ planned: new Set(['ready_to_execute', 'building']),
238
+ ready_to_execute: new Set(['building']),
239
+ building: new Set(['built', 'partial']),
240
+ built: new Set(['verified', 'needs_fixes']),
241
+ partial: new Set(['building', 'needs_fixes']),
242
+ verified: new Set(['complete']),
243
+ needs_fixes: new Set(['building', 'planning']),
244
+ complete: new Set([]), // terminal
245
+ skipped: new Set([]), // terminal
246
+ };
247
+
248
+ /**
249
+ * Extract status value from a JSONL entry that represents a state write.
250
+ * @param {Object} entry - JSONL entry
251
+ * @returns {string|null} Status value or null
252
+ */
253
+ function extractStatusFromEntry(entry) {
254
+ // Hook log entries from check-state-sync
255
+ if (entry.hook === 'check-state-sync' && entry.details) {
256
+ return entry.details.status || entry.details.new_status || null;
257
+ }
258
+
259
+ // Event logger entries for state writes
260
+ if (entry.event === 'state-update' || entry.event === 'status-change') {
261
+ return (entry.details && entry.details.status) || entry.status || null;
262
+ }
263
+
264
+ // Generic: look for status in tool_input targeting STATE.md
265
+ if (entry.tool_input && typeof entry.tool_input === 'string') {
266
+ if (entry.tool_input.includes('STATE.md')) {
267
+ const statusMatch = entry.tool_input.match(/status:\s*["']?(\w+)/);
268
+ if (statusMatch) return statusMatch[1];
269
+ }
270
+ }
271
+
272
+ // Check details.content for STATE.md writes
273
+ if (entry.details && entry.details.content && typeof entry.details.content === 'string') {
274
+ if (entry.details.file && entry.details.file.includes('STATE.md')) {
275
+ const statusMatch = entry.details.content.match(/status:\s*["']?(\w+)/);
276
+ if (statusMatch) return statusMatch[1];
277
+ }
278
+ }
279
+
280
+ return null;
281
+ }
282
+
283
+ /**
284
+ * BC-02: Check that state transitions follow the valid state machine.
285
+ * Detects invalid transitions like planning->verified (skipping building).
286
+ *
287
+ * @param {string} planningDir - Path to .planning/
288
+ * @param {Object} [_config] - Config object (unused, for API consistency)
289
+ * @returns {{ status: string, evidence: Array<string>, message: string }}
290
+ */
291
+ function checkStateMachineTransitions(planningDir, _config) {
292
+ const events = readSessionEvents(planningDir);
293
+ const hookLogs = readHookLogs(planningDir);
294
+ const allEntries = [...events, ...hookLogs].sort((a, b) => {
295
+ const ta = a.ts || a.timestamp || '';
296
+ const tb = b.ts || b.timestamp || '';
297
+ return ta < tb ? -1 : ta > tb ? 1 : 0;
298
+ });
299
+
300
+ if (allEntries.length === 0) {
301
+ return {
302
+ status: 'pass',
303
+ evidence: [],
304
+ message: 'BC-02: No session data available — cannot assess state transitions'
305
+ };
306
+ }
307
+
308
+ // Collect status transitions per phase
309
+ // Map<phase, Array<{ status, ts }>>
310
+ const phaseTransitions = new Map();
311
+
312
+ for (const entry of allEntries) {
313
+ const status = extractStatusFromEntry(entry);
314
+ const phase = extractPhaseFromEntry(entry);
315
+ if (!status || !phase) continue;
316
+
317
+ if (!phaseTransitions.has(phase)) phaseTransitions.set(phase, []);
318
+ const transitions = phaseTransitions.get(phase);
319
+
320
+ // Deduplicate consecutive identical statuses
321
+ if (transitions.length > 0 && transitions[transitions.length - 1].status === status) continue;
322
+
323
+ transitions.push({
324
+ status,
325
+ ts: entry.ts || entry.timestamp || ''
326
+ });
327
+ }
328
+
329
+ const evidence = [];
330
+
331
+ for (const [phase, transitions] of phaseTransitions) {
332
+ for (let i = 0; i < transitions.length - 1; i++) {
333
+ const from = transitions[i].status;
334
+ const to = transitions[i + 1].status;
335
+ const validTargets = VALID_TRANSITIONS[from];
336
+
337
+ if (!validTargets || !validTargets.has(to)) {
338
+ const time = transitions[i + 1].ts ? ` at ${transitions[i + 1].ts}` : '';
339
+ evidence.push(
340
+ `Phase ${phase}: ${from}->${to} (invalid transition${time})`
341
+ );
342
+ }
343
+ }
344
+ }
345
+
346
+ if (evidence.length > 0) {
347
+ return {
348
+ status: 'fail',
349
+ evidence,
350
+ message: `BC-02: Found ${evidence.length} invalid state transition(s)`
351
+ };
352
+ }
353
+
354
+ return {
355
+ status: 'pass',
356
+ evidence: [],
357
+ message: 'BC-02: All state transitions follow valid state machine'
358
+ };
359
+ }
360
+
361
+ // ---------------------------------------------------------------------------
362
+ // BC-03: Pre-Condition Verification
363
+ // ---------------------------------------------------------------------------
364
+
365
+ /**
366
+ * Check if a file write event targets a specific pattern.
367
+ * @param {Object} entry - JSONL entry
368
+ * @param {RegExp} pattern - Pattern to match against file paths
369
+ * @returns {boolean}
370
+ */
371
+ function entryTargetsFile(entry, pattern) {
372
+ // Check tool_input for file path
373
+ if (entry.tool_input) {
374
+ const input = typeof entry.tool_input === 'string' ? entry.tool_input : JSON.stringify(entry.tool_input);
375
+ if (pattern.test(input)) return true;
376
+ }
377
+
378
+ // Check details for file path
379
+ if (entry.details) {
380
+ const details = typeof entry.details === 'string' ? entry.details : JSON.stringify(entry.details);
381
+ if (pattern.test(details)) return true;
382
+ }
383
+
384
+ // Check file/path fields directly
385
+ if (entry.file && pattern.test(entry.file)) return true;
386
+ if (entry.path && pattern.test(entry.path)) return true;
387
+
388
+ return false;
389
+ }
390
+
391
+ /**
392
+ * Check if an entry represents a build-start event.
393
+ * @param {Object} entry - JSONL entry
394
+ * @returns {boolean}
395
+ */
396
+ function isBuildStart(entry) {
397
+ // Skill invocation of build
398
+ if (entry.event === 'build' || entry.event === 'pbr:build') return true;
399
+ if (entry.cat === 'skill' && entry.event === 'build') return true;
400
+
401
+ // Task spawn with executor agent
402
+ if (entry.event === 'task-spawn' && entry.details) {
403
+ if (entry.details.agent === 'executor' || entry.details.subagent_type === 'pbr:executor') return true;
404
+ }
405
+
406
+ // Hook log from validate-task with buildExecutorGate
407
+ if (entry.hook === 'validate-task' && entry.details) {
408
+ if (entry.details.gate === 'buildExecutorGate' || entry.details.check === 'buildExecutorGate') return true;
409
+ }
410
+
411
+ return false;
412
+ }
413
+
414
+ /**
415
+ * Check if an entry represents a verify-start event.
416
+ * @param {Object} entry - JSONL entry
417
+ * @returns {boolean}
418
+ */
419
+ function isVerifyStart(entry) {
420
+ if (entry.event === 'verify' || entry.event === 'pbr:verify') return true;
421
+ if (entry.cat === 'skill' && entry.event === 'verify') return true;
422
+
423
+ // Task spawn with verifier agent
424
+ if (entry.event === 'task-spawn' && entry.details) {
425
+ if (entry.details.agent === 'verifier' || entry.details.subagent_type === 'pbr:verifier') return true;
426
+ }
427
+
428
+ return false;
429
+ }
430
+
431
+ /**
432
+ * BC-03: Check that pre-conditions are met before skill execution.
433
+ * Build requires PLAN-*.md to exist, verify requires SUMMARY*.md to exist.
434
+ *
435
+ * @param {string} planningDir - Path to .planning/
436
+ * @param {Object} [_config] - Config object (unused, for API consistency)
437
+ * @returns {{ status: string, evidence: Array<string>, message: string }}
438
+ */
439
+ function checkPreConditionVerification(planningDir, _config) {
440
+ const events = readSessionEvents(planningDir);
441
+ const hookLogs = readHookLogs(planningDir);
442
+ const allEntries = [...events, ...hookLogs].sort((a, b) => {
443
+ const ta = a.ts || a.timestamp || '';
444
+ const tb = b.ts || b.timestamp || '';
445
+ return ta < tb ? -1 : ta > tb ? 1 : 0;
446
+ });
447
+
448
+ if (allEntries.length === 0) {
449
+ return {
450
+ status: 'pass',
451
+ evidence: [],
452
+ message: 'BC-03: No session data available — cannot assess pre-conditions'
453
+ };
454
+ }
455
+
456
+ const evidence = [];
457
+ const planPattern = /PLAN-?\d*\.md/i;
458
+ const summaryPattern = /SUMMARY/i;
459
+
460
+ // Track which file patterns have been written so far
461
+ let planWriteSeen = false;
462
+ let summaryWriteSeen = false;
463
+
464
+ // Also check hook logs for validate-task entries that confirm pre-conditions
465
+ const gateChecks = hookLogs.filter(e =>
466
+ e.hook === 'validate-task' && e.details &&
467
+ (e.details.gate === 'buildExecutorGate' || e.details.check === 'buildExecutorGate')
468
+ );
469
+ const gateBlocks = gateChecks.filter(e =>
470
+ e.details && (e.details.decision === 'block' || e.details.result === 'block')
471
+ );
472
+
473
+ for (const entry of allEntries) {
474
+ // Track file writes
475
+ if (entryTargetsFile(entry, planPattern)) {
476
+ planWriteSeen = true;
477
+ }
478
+ if (entryTargetsFile(entry, summaryPattern)) {
479
+ summaryWriteSeen = true;
480
+ }
481
+
482
+ // Check build pre-conditions
483
+ if (isBuildStart(entry)) {
484
+ const phase = extractPhaseFromEntry(entry);
485
+ if (!planWriteSeen) {
486
+ // Check if validate-task gate caught this
487
+ const wasCaught = gateBlocks.some(g => {
488
+ const gPhase = extractPhaseFromEntry(g);
489
+ return gPhase === phase;
490
+ });
491
+ if (wasCaught) continue; // Gate caught it, not a violation
492
+
493
+ const time = entry.ts || entry.timestamp || '';
494
+ evidence.push(
495
+ `${phase ? `Phase ${phase} ` : ''}build started but no PLAN-*.md write event found in prior session activity` +
496
+ (time ? ` (build at ${time})` : '')
497
+ );
498
+ }
499
+ }
500
+
501
+ // Check verify pre-conditions
502
+ if (isVerifyStart(entry)) {
503
+ const phase = extractPhaseFromEntry(entry);
504
+ if (!summaryWriteSeen) {
505
+ const time = entry.ts || entry.timestamp || '';
506
+ evidence.push(
507
+ `${phase ? `Phase ${phase} ` : ''}verify started but no SUMMARY.md write event found in prior session activity` +
508
+ (time ? ` (verify at ${time})` : '')
509
+ );
510
+ }
511
+ }
512
+ }
513
+
514
+ if (evidence.length > 0) {
515
+ // Use 'warn' for ambiguous cases (session data might be incomplete)
516
+ const hasAmbiguity = evidence.some(e => e.includes('no') && e.includes('write event'));
517
+ return {
518
+ status: hasAmbiguity ? 'warn' : 'fail',
519
+ evidence,
520
+ message: `BC-03: Found ${evidence.length} pre-condition concern(s) — data may be incomplete`
521
+ };
522
+ }
523
+
524
+ return {
525
+ status: 'pass',
526
+ evidence: [],
527
+ message: 'BC-03: All pre-conditions verified (PLAN before build, SUMMARY before verify)'
528
+ };
529
+ }
530
+
531
+ // ---------------------------------------------------------------------------
532
+ // BC-04: Post-Condition Verification
533
+ // ---------------------------------------------------------------------------
534
+
535
+ /**
536
+ * Check if an entry represents a build-complete event.
537
+ * @param {Object} entry - JSONL entry
538
+ * @returns {boolean}
539
+ */
540
+ function isBuildComplete(entry) {
541
+ // Task completion for executor agent
542
+ if (entry.event === 'task-complete' && entry.details) {
543
+ if (entry.details.agent === 'executor' || entry.details.subagent_type === 'pbr:executor') return true;
544
+ }
545
+
546
+ // Subagent stop for executor
547
+ if (entry.event === 'subagent-stop' && entry.details) {
548
+ if (entry.details.agent === 'executor' || entry.details.subagent_type === 'pbr:executor') return true;
549
+ }
550
+
551
+ // Hook log from check-subagent-output indicating build completion
552
+ if (entry.hook === 'check-subagent-output' && entry.details) {
553
+ if (entry.details.skill === 'build') return true;
554
+ }
555
+
556
+ return false;
557
+ }
558
+
559
+ /**
560
+ * Check if an entry represents a verify-complete event.
561
+ * @param {Object} entry - JSONL entry
562
+ * @returns {boolean}
563
+ */
564
+ function isVerifyComplete(entry) {
565
+ if (entry.event === 'task-complete' && entry.details) {
566
+ if (entry.details.agent === 'verifier' || entry.details.subagent_type === 'pbr:verifier') return true;
567
+ }
568
+
569
+ if (entry.event === 'subagent-stop' && entry.details) {
570
+ if (entry.details.agent === 'verifier' || entry.details.subagent_type === 'pbr:verifier') return true;
571
+ }
572
+
573
+ if (entry.hook === 'check-subagent-output' && entry.details) {
574
+ if (entry.details.skill === 'verify') return true;
575
+ }
576
+
577
+ return false;
578
+ }
579
+
580
+ /**
581
+ * BC-04: Check that post-conditions are met after skill execution.
582
+ * Build must produce SUMMARY.md, verify must produce VERIFICATION.md.
583
+ *
584
+ * @param {string} planningDir - Path to .planning/
585
+ * @param {Object} [_config] - Config object (unused, for API consistency)
586
+ * @returns {{ status: string, evidence: Array<string>, message: string }}
587
+ */
588
+ function checkPostConditionVerification(planningDir, _config) {
589
+ const events = readSessionEvents(planningDir);
590
+ const hookLogs = readHookLogs(planningDir);
591
+ const allEntries = [...events, ...hookLogs].sort((a, b) => {
592
+ const ta = a.ts || a.timestamp || '';
593
+ const tb = b.ts || b.timestamp || '';
594
+ return ta < tb ? -1 : ta > tb ? 1 : 0;
595
+ });
596
+
597
+ if (allEntries.length === 0) {
598
+ return {
599
+ status: 'pass',
600
+ evidence: [],
601
+ message: 'BC-04: No session data available — cannot assess post-conditions'
602
+ };
603
+ }
604
+
605
+ const evidence = [];
606
+ const summaryPattern = /SUMMARY.*\.md/i;
607
+ const verificationPattern = /VERIFICATION.*\.md/i;
608
+
609
+ // Track build-complete and verify-complete events, then look for subsequent artifact writes
610
+ const buildCompletes = [];
611
+ const verifyCompletes = [];
612
+
613
+ for (const entry of allEntries) {
614
+ if (isBuildComplete(entry)) {
615
+ const phase = extractPhaseFromEntry(entry);
616
+ buildCompletes.push({ phase, ts: entry.ts || entry.timestamp || '' });
617
+ }
618
+ if (isVerifyComplete(entry)) {
619
+ const phase = extractPhaseFromEntry(entry);
620
+ verifyCompletes.push({ phase, ts: entry.ts || entry.timestamp || '' });
621
+ }
622
+ }
623
+
624
+ // For each build-complete, check if SUMMARY.md was written in the session
625
+ for (const bc of buildCompletes) {
626
+ const summaryWritten = allEntries.some(e => entryTargetsFile(e, summaryPattern));
627
+ if (!summaryWritten) {
628
+ const phaseLabel = bc.phase ? `Phase ${bc.phase}` : 'Unknown phase';
629
+ evidence.push(`${phaseLabel}: build completed but no SUMMARY.md written in session`);
630
+ }
631
+ }
632
+
633
+ // For each verify-complete, check if VERIFICATION.md was written in the session
634
+ for (const vc of verifyCompletes) {
635
+ const verificationWritten = allEntries.some(e => entryTargetsFile(e, verificationPattern));
636
+ if (!verificationWritten) {
637
+ const phaseLabel = vc.phase ? `Phase ${vc.phase}` : 'Unknown phase';
638
+ evidence.push(`${phaseLabel}: verify completed but no VERIFICATION.md written in session`);
639
+ }
640
+ }
641
+
642
+ if (evidence.length > 0) {
643
+ return {
644
+ status: 'warn',
645
+ evidence,
646
+ message: `BC-04: Found ${evidence.length} missing post-condition artifact(s)`
647
+ };
648
+ }
649
+
650
+ return {
651
+ status: 'pass',
652
+ evidence: [],
653
+ message: 'BC-04: All post-conditions verified (SUMMARY after build, VERIFICATION after verify)'
654
+ };
655
+ }
656
+
657
+ // ---------------------------------------------------------------------------
658
+ // BC-05: Orchestrator Budget Discipline
659
+ // ---------------------------------------------------------------------------
660
+
661
+ /**
662
+ * Check if an event appears to be from orchestrator context (not inside a Task subagent).
663
+ * Events inside Task() typically have subagent markers or task_id fields.
664
+ * @param {Object} entry - JSONL entry
665
+ * @returns {boolean} true if this looks like an orchestrator-level event
666
+ */
667
+ function isOrchestratorLevel(entry) {
668
+ // Events with subagent or task markers are inside Task() contexts
669
+ if (entry.task_id) return false;
670
+ if (entry.subagent) return false;
671
+ if (entry.details && entry.details.subagent_type) return false;
672
+ if (entry.details && entry.details.task_id) return false;
673
+ if (entry.cat === 'subagent') return false;
674
+
675
+ // Hook logs from within subagents
676
+ if (entry.hook && entry.details && entry.details.inside_task) return false;
677
+
678
+ return true;
679
+ }
680
+
681
+ /**
682
+ * Check if a file path is an executor-level file that the orchestrator should not read.
683
+ * @param {string} filePath - File path to check
684
+ * @returns {boolean}
685
+ */
686
+ function isExecutorLevelFile(filePath) {
687
+ if (!filePath) return false;
688
+ const normalized = filePath.replace(/\\/g, '/');
689
+
690
+ // Source files that should be delegated to executor
691
+ if (/plugins\/pbr\/scripts\//.test(normalized)) return true;
692
+ if (/\/src\//.test(normalized)) return true;
693
+
694
+ // Plan action details (the executor reads these, not the orchestrator)
695
+ if (/PLAN-?\d+\.md$/i.test(normalized)) return true;
696
+
697
+ return false;
698
+ }
699
+
700
+ /**
701
+ * BC-05: Check that the orchestrator stays within its context budget.
702
+ * Flags orchestrator-level reads of executor files and budget overruns.
703
+ *
704
+ * @param {string} planningDir - Path to .planning/
705
+ * @param {Object} [config] - Config object with orchestrator_budget_pct
706
+ * @returns {{ status: string, evidence: Array<string>, message: string }}
707
+ */
708
+ function checkOrchestratorBudgetDiscipline(planningDir, config) {
709
+ const events = readSessionEvents(planningDir);
710
+ const hookLogs = readHookLogs(planningDir);
711
+ const allEntries = [...events, ...hookLogs].sort((a, b) => {
712
+ const ta = a.ts || a.timestamp || '';
713
+ const tb = b.ts || b.timestamp || '';
714
+ return ta < tb ? -1 : ta > tb ? 1 : 0;
715
+ });
716
+
717
+ if (allEntries.length === 0) {
718
+ return {
719
+ status: 'pass',
720
+ evidence: [],
721
+ message: 'BC-05: No session data available — cannot assess orchestrator budget'
722
+ };
723
+ }
724
+
725
+ const evidence = [];
726
+ const budgetPct = (config && config.orchestrator_budget_pct) || 35;
727
+
728
+ // Find orchestrator-level Read events targeting executor files
729
+ const orchestratorSourceReads = [];
730
+ for (const entry of allEntries) {
731
+ if (!isOrchestratorLevel(entry)) continue;
732
+
733
+ // Look for Read tool events
734
+ const isRead = entry.tool === 'Read' || entry.event === 'read' ||
735
+ (entry.details && entry.details.tool === 'Read');
736
+ if (!isRead) continue;
737
+
738
+ // Extract file path
739
+ const filePath = (entry.tool_input && entry.tool_input.file_path) ||
740
+ (entry.details && entry.details.file_path) ||
741
+ entry.file || entry.path || '';
742
+
743
+ if (isExecutorLevelFile(filePath)) {
744
+ orchestratorSourceReads.push(filePath);
745
+ }
746
+ }
747
+
748
+ if (orchestratorSourceReads.length > 0) {
749
+ evidence.push(
750
+ `Orchestrator read ${orchestratorSourceReads.length} executor-level file(s) directly: ` +
751
+ orchestratorSourceReads.slice(0, 5).map(f => path.basename(f)).join(', ') +
752
+ (orchestratorSourceReads.length > 5 ? ` (+${orchestratorSourceReads.length - 5} more)` : '')
753
+ );
754
+ }
755
+
756
+ // Check context budget data from .context-budget.json
757
+ const budgetPath = path.join(planningDir, '.context-budget.json');
758
+ try {
759
+ if (fs.existsSync(budgetPath)) {
760
+ const budgetData = JSON.parse(fs.readFileSync(budgetPath, 'utf8'));
761
+ const pctUsed = budgetData.pct_used || budgetData.estimated_percent || 0;
762
+ if (pctUsed > budgetPct) {
763
+ evidence.push(
764
+ `Orchestrator context budget exceeded: ${pctUsed}% used (threshold: ${budgetPct}%)`
765
+ );
766
+ }
767
+ }
768
+ } catch (_e) {
769
+ // intentionally silent: budget file may not exist
770
+ }
771
+
772
+ if (evidence.length > 0) {
773
+ return {
774
+ status: 'warn',
775
+ evidence,
776
+ message: `BC-05: Orchestrator budget discipline concern(s) found`
777
+ };
778
+ }
779
+
780
+ return {
781
+ status: 'pass',
782
+ evidence: [],
783
+ message: `BC-05: Orchestrator stayed within budget (threshold: ${budgetPct}%)`
784
+ };
785
+ }
786
+
787
+ // ---------------------------------------------------------------------------
788
+ // BC-06: Artifact Creation Order
789
+ // ---------------------------------------------------------------------------
790
+
791
+ /**
792
+ * Artifact types in expected creation order within a phase.
793
+ * Lower index = must be created first.
794
+ */
795
+ const ARTIFACT_ORDER = {
796
+ 'PLAN': 0,
797
+ 'SUMMARY': 1,
798
+ 'VERIFICATION': 2,
799
+ };
800
+
801
+ /**
802
+ * Extract artifact type and phase directory from a file path.
803
+ * @param {string} filePath - File path from event
804
+ * @returns {{ artifact: string, phaseDir: string }|null}
805
+ */
806
+ function extractArtifactInfo(filePath) {
807
+ if (!filePath) return null;
808
+ const normalized = filePath.replace(/\\/g, '/');
809
+
810
+ // Match phase directory patterns like phases/03-something/PLAN-01.md
811
+ const phaseMatch = normalized.match(/phases\/(\d{2}-[^/]+)\//);
812
+ if (!phaseMatch) return null;
813
+
814
+ const phaseDir = phaseMatch[1];
815
+ const basename = path.basename(normalized);
816
+
817
+ if (/^PLAN/i.test(basename)) return { artifact: 'PLAN', phaseDir };
818
+ if (/^SUMMARY/i.test(basename)) return { artifact: 'SUMMARY', phaseDir };
819
+ if (/^VERIFICATION/i.test(basename)) return { artifact: 'VERIFICATION', phaseDir };
820
+
821
+ return null;
822
+ }
823
+
824
+ /**
825
+ * Check if an entry is a git commit event (Bash tool running git commit).
826
+ * @param {Object} entry - JSONL entry
827
+ * @returns {string|null} Phase directory if commit is phase-related, null otherwise
828
+ */
829
+ function extractCommitPhase(entry) {
830
+ // Look for Bash tool events containing "git commit"
831
+ const input = entry.tool_input || (entry.details && entry.details.command) || '';
832
+ const inputStr = typeof input === 'string' ? input : JSON.stringify(input);
833
+
834
+ if (!/git\s+commit/i.test(inputStr)) return null;
835
+
836
+ // Try to extract phase from the commit message or context
837
+ const phaseMatch = inputStr.match(/(\d{2})-(\d{2})/);
838
+ if (phaseMatch) {
839
+ // This gives us a phase-plan reference; return just the phase part
840
+ return phaseMatch[1];
841
+ }
842
+
843
+ return null;
844
+ }
845
+
846
+ /**
847
+ * BC-06: Check that artifacts are created in the expected order within each phase.
848
+ * Expected: PLAN write < commit(s) < SUMMARY write < VERIFICATION write.
849
+ *
850
+ * @param {string} planningDir - Path to .planning/
851
+ * @param {Object} [_config] - Config object (unused, for API consistency)
852
+ * @returns {{ status: string, evidence: Array<string>, message: string }}
853
+ */
854
+ function checkArtifactCreationOrder(planningDir, _config) {
855
+ const events = readSessionEvents(planningDir);
856
+ const hookLogs = readHookLogs(planningDir);
857
+ const allEntries = [...events, ...hookLogs].sort((a, b) => {
858
+ const ta = a.ts || a.timestamp || '';
859
+ const tb = b.ts || b.timestamp || '';
860
+ return ta < tb ? -1 : ta > tb ? 1 : 0;
861
+ });
862
+
863
+ if (allEntries.length === 0) {
864
+ return {
865
+ status: 'pass',
866
+ evidence: [],
867
+ message: 'BC-06: No session data available — cannot assess artifact order'
868
+ };
869
+ }
870
+
871
+ // Collect artifact write timestamps per phase directory
872
+ // Map<phaseDir, Map<artifactType, { ts: string, index: number }>>
873
+ const phaseArtifacts = new Map();
874
+
875
+ let eventIndex = 0;
876
+ for (const entry of allEntries) {
877
+ eventIndex++;
878
+ const ts = entry.ts || entry.timestamp || '';
879
+
880
+ // Check for Write/Edit events targeting artifact files
881
+ const isWrite = entry.tool === 'Write' || entry.tool === 'Edit' ||
882
+ (entry.details && (entry.details.tool === 'Write' || entry.details.tool === 'Edit'));
883
+
884
+ if (isWrite) {
885
+ const filePath = (entry.tool_input && (entry.tool_input.file_path || entry.tool_input.filePath)) ||
886
+ (entry.details && (entry.details.file_path || entry.details.file)) ||
887
+ entry.file || entry.path || '';
888
+
889
+ const info = extractArtifactInfo(filePath);
890
+ if (info) {
891
+ if (!phaseArtifacts.has(info.phaseDir)) phaseArtifacts.set(info.phaseDir, new Map());
892
+ const artifacts = phaseArtifacts.get(info.phaseDir);
893
+ // Record first occurrence only (the initial write matters for ordering)
894
+ if (!artifacts.has(info.artifact)) {
895
+ artifacts.set(info.artifact, { ts, index: eventIndex });
896
+ }
897
+ }
898
+ }
899
+
900
+ // Also check entryTargetsFile for artifact patterns
901
+ if (!isWrite) {
902
+ for (const [artifactName, _order] of Object.entries(ARTIFACT_ORDER)) {
903
+ const pattern = new RegExp(`${artifactName}.*\\.md`, 'i');
904
+ if (entryTargetsFile(entry, pattern)) {
905
+ // Try to extract phase from the entry
906
+ const searchStr = JSON.stringify(entry);
907
+ const pdMatch = searchStr.match(/phases\/(\d{2}-[^/"]+)\//);
908
+ if (pdMatch) {
909
+ const phaseDir = pdMatch[1];
910
+ if (!phaseArtifacts.has(phaseDir)) phaseArtifacts.set(phaseDir, new Map());
911
+ const artifacts = phaseArtifacts.get(phaseDir);
912
+ if (!artifacts.has(artifactName)) {
913
+ artifacts.set(artifactName, { ts, index: eventIndex });
914
+ }
915
+ }
916
+ }
917
+ }
918
+ }
919
+ }
920
+
921
+ const evidence = [];
922
+
923
+ // Check ordering within each phase
924
+ for (const [phaseDir, artifacts] of phaseArtifacts) {
925
+ const entries = Array.from(artifacts.entries())
926
+ .map(([name, data]) => ({ name, ...data, order: ARTIFACT_ORDER[name] }))
927
+ .sort((a, b) => a.index - b.index); // Sort by actual occurrence order
928
+
929
+ // Compare each pair: if a later-ordered artifact appears before an earlier one
930
+ for (let i = 0; i < entries.length; i++) {
931
+ for (let j = i + 1; j < entries.length; j++) {
932
+ if (entries[j].order < entries[i].order) {
933
+ const timeA = entries[i].ts ? ` (${entries[i].ts.substring(11, 16)})` : '';
934
+ const timeB = entries[j].ts ? ` (${entries[j].ts.substring(11, 16)})` : '';
935
+ evidence.push(
936
+ `${phaseDir}: ${entries[j].name}.md written${timeB} before ${entries[i].name}.md${timeA} — out of order`
937
+ );
938
+ }
939
+ }
940
+ }
941
+ }
942
+
943
+ if (evidence.length > 0) {
944
+ return {
945
+ status: 'warn',
946
+ evidence,
947
+ message: `BC-06: Found ${evidence.length} out-of-order artifact creation(s)`
948
+ };
949
+ }
950
+
951
+ return {
952
+ status: 'pass',
953
+ evidence: [],
954
+ message: 'BC-06: All artifacts created in expected order (PLAN < SUMMARY < VERIFICATION)'
955
+ };
956
+ }
957
+
958
+ // ---------------------------------------------------------------------------
959
+ // BC-07: CRITICAL Marker Compliance
960
+ // ---------------------------------------------------------------------------
961
+
962
+ /**
963
+ * Known CRITICAL steps keyed by skill name.
964
+ * Each entry maps a skill to the file patterns that MUST be written after invocation.
965
+ */
966
+ const CRITICAL_STEPS = {
967
+ build: [
968
+ { description: 'SUMMARY.md written after build', pattern: /SUMMARY.*\.md/i },
969
+ ],
970
+ quick: [
971
+ { description: 'quick task directory created', pattern: /\.planning\/quick\/\d{3}-[^/]+\//i },
972
+ ],
973
+ begin: [
974
+ { description: '.planning/ directory and STATE.md created', pattern: /STATE\.md/i },
975
+ ],
976
+ };
977
+
978
+ /**
979
+ * Check if an entry represents a skill invocation.
980
+ * @param {Object} entry - JSONL entry
981
+ * @returns {string|null} skill name or null
982
+ */
983
+ function extractSkillInvocation(entry) {
984
+ // Direct skill event
985
+ if (entry.cat === 'skill' && entry.event) return entry.event;
986
+
987
+ // pbr: prefix events
988
+ if (entry.event && entry.event.startsWith('pbr:')) {
989
+ return entry.event.replace('pbr:', '').split('-')[0];
990
+ }
991
+
992
+ // Skill field in details
993
+ if (entry.details && entry.details.skill) return entry.details.skill;
994
+
995
+ return null;
996
+ }
997
+
998
+ /**
999
+ * BC-07: Check that CRITICAL/STOP markers in skills were followed by the LLM.
1000
+ * Detects when expected artifact writes are missing after skill invocations.
1001
+ *
1002
+ * @param {string} planningDir - Path to .planning/
1003
+ * @param {Object} [_config] - Config object (unused, for API consistency)
1004
+ * @returns {{ status: string, evidence: Array<string>, message: string }}
1005
+ */
1006
+ function checkCriticalMarkerCompliance(planningDir, _config) {
1007
+ const events = readSessionEvents(planningDir);
1008
+ const hookLogs = readHookLogs(planningDir);
1009
+ const allEntries = [...events, ...hookLogs].sort((a, b) => {
1010
+ const ta = a.ts || a.timestamp || '';
1011
+ const tb = b.ts || b.timestamp || '';
1012
+ return ta < tb ? -1 : ta > tb ? 1 : 0;
1013
+ });
1014
+
1015
+ if (allEntries.length === 0) {
1016
+ return {
1017
+ status: 'pass',
1018
+ evidence: [],
1019
+ message: 'BC-07: No session data available — cannot assess CRITICAL marker compliance'
1020
+ };
1021
+ }
1022
+
1023
+ const evidence = [];
1024
+
1025
+ // Collect skill invocations and all write targets
1026
+ const skillInvocations = []; // { skill, ts, index }
1027
+ const writeTargets = []; // { target: string, index }
1028
+
1029
+ let idx = 0;
1030
+ for (const entry of allEntries) {
1031
+ idx++;
1032
+ const skill = extractSkillInvocation(entry);
1033
+ if (skill && CRITICAL_STEPS[skill]) {
1034
+ skillInvocations.push({ skill, ts: entry.ts || entry.timestamp || '', index: idx });
1035
+ }
1036
+
1037
+ // Collect all write events
1038
+ const isWrite = entry.tool === 'Write' || entry.tool === 'Edit' ||
1039
+ (entry.details && (entry.details.tool === 'Write' || entry.details.tool === 'Edit'));
1040
+
1041
+ if (isWrite) {
1042
+ const filePath = (entry.tool_input && (entry.tool_input.file_path || entry.tool_input.filePath)) ||
1043
+ (entry.details && (entry.details.file_path || entry.details.file)) ||
1044
+ entry.file || entry.path || '';
1045
+ if (filePath) writeTargets.push({ target: filePath, index: idx });
1046
+ }
1047
+
1048
+ // Also check entry details for file references
1049
+ if (entryTargetsFile(entry, /\.(md|json)$/i)) {
1050
+ const filePath = (entry.tool_input && (entry.tool_input.file_path || entry.tool_input.filePath)) ||
1051
+ (entry.details && (entry.details.file_path || entry.details.file)) ||
1052
+ entry.file || entry.path || '';
1053
+ if (filePath) writeTargets.push({ target: filePath, index: idx });
1054
+ }
1055
+ }
1056
+
1057
+ // For each skill invocation, check if CRITICAL writes occurred afterward
1058
+ for (const invocation of skillInvocations) {
1059
+ const steps = CRITICAL_STEPS[invocation.skill];
1060
+ for (const step of steps) {
1061
+ const hasWrite = writeTargets.some(
1062
+ w => w.index > invocation.index && step.pattern.test(w.target)
1063
+ );
1064
+ if (!hasWrite) {
1065
+ const time = invocation.ts ? ` at ${invocation.ts}` : '';
1066
+ evidence.push(
1067
+ `${invocation.skill} skill invoked${time} but ${step.description} — CRITICAL step may have been skipped`
1068
+ );
1069
+ }
1070
+ }
1071
+ }
1072
+
1073
+ if (evidence.length > 0) {
1074
+ return {
1075
+ status: 'warn',
1076
+ evidence,
1077
+ message: `BC-07: Found ${evidence.length} potentially skipped CRITICAL step(s)`
1078
+ };
1079
+ }
1080
+
1081
+ return {
1082
+ status: 'pass',
1083
+ evidence: [],
1084
+ message: 'BC-07: All CRITICAL marker steps appear to have been followed'
1085
+ };
1086
+ }
1087
+
1088
+ // ---------------------------------------------------------------------------
1089
+ // BC-08: Gate Compliance
1090
+ // ---------------------------------------------------------------------------
1091
+
1092
+ /**
1093
+ * BC-08: Check that gate behavior matches config settings.
1094
+ * In autonomous mode with gates disabled, AskUserQuestion should not be used for gate prompts.
1095
+ * In interactive mode with gates enabled, AskUserQuestion should be present.
1096
+ *
1097
+ * @param {string} planningDir - Path to .planning/
1098
+ * @param {Object} [config] - Config object with mode and gates settings
1099
+ * @returns {{ status: string, evidence: Array<string>, message: string }}
1100
+ */
1101
+ function checkGateCompliance(planningDir, config) {
1102
+ const events = readSessionEvents(planningDir);
1103
+ const hookLogs = readHookLogs(planningDir);
1104
+ const allEntries = [...events, ...hookLogs].sort((a, b) => {
1105
+ const ta = a.ts || a.timestamp || '';
1106
+ const tb = b.ts || b.timestamp || '';
1107
+ return ta < tb ? -1 : ta > tb ? 1 : 0;
1108
+ });
1109
+
1110
+ if (allEntries.length === 0) {
1111
+ return {
1112
+ status: 'pass',
1113
+ evidence: [],
1114
+ message: 'BC-08: No session data available — cannot assess gate compliance'
1115
+ };
1116
+ }
1117
+
1118
+ // Determine mode and gate settings
1119
+ const mode = (config && config.mode) || 'interactive';
1120
+ const gates = (config && config.gates) || {};
1121
+ const isAutonomous = mode === 'autonomous';
1122
+ const allGatesFalse = Object.keys(gates).length > 0 &&
1123
+ Object.keys(gates).filter(k => k.startsWith('confirm_')).every(k => !gates[k]);
1124
+
1125
+ const evidence = [];
1126
+
1127
+ // Find AskUserQuestion events that look gate-like
1128
+ const gatePatterns = /\b(confirm|proceed|approve|accept|continue\s+with|go\s+ahead)\b/i;
1129
+ const gateAskEvents = [];
1130
+
1131
+ for (const entry of allEntries) {
1132
+ const isAsk = entry.tool === 'AskUserQuestion' ||
1133
+ (entry.details && entry.details.tool === 'AskUserQuestion');
1134
+ if (!isAsk) continue;
1135
+
1136
+ // Extract the question content
1137
+ const question = (entry.tool_input && (entry.tool_input.question || entry.tool_input.message)) ||
1138
+ (entry.details && (entry.details.question || entry.details.message)) || '';
1139
+ const questionStr = typeof question === 'string' ? question : JSON.stringify(question);
1140
+
1141
+ if (gatePatterns.test(questionStr)) {
1142
+ gateAskEvents.push({
1143
+ question: questionStr.substring(0, 100),
1144
+ ts: entry.ts || entry.timestamp || ''
1145
+ });
1146
+ }
1147
+ }
1148
+
1149
+ if (isAutonomous && allGatesFalse && gateAskEvents.length > 0) {
1150
+ for (const ask of gateAskEvents) {
1151
+ const time = ask.ts ? ` at ${ask.ts}` : '';
1152
+ evidence.push(
1153
+ `Autonomous mode with gates disabled but AskUserQuestion asked "${ask.question}"${time}`
1154
+ );
1155
+ }
1156
+ }
1157
+
1158
+ if (!isAutonomous && Object.keys(gates).some(k => k.startsWith('confirm_') && gates[k])) {
1159
+ // Interactive mode with some gates enabled — check if gates were actually used
1160
+ const enabledGates = Object.keys(gates).filter(k => k.startsWith('confirm_') && gates[k]);
1161
+ if (gateAskEvents.length === 0 && enabledGates.length > 0) {
1162
+ evidence.push(
1163
+ `Interactive mode with ${enabledGates.length} gate(s) enabled (${enabledGates.join(', ')}) ` +
1164
+ `but no gate-like AskUserQuestion events detected — gates may have been skipped`
1165
+ );
1166
+ }
1167
+ }
1168
+
1169
+ if (evidence.length > 0) {
1170
+ return {
1171
+ status: 'warn',
1172
+ evidence,
1173
+ message: `BC-08: Gate behavior does not match config (${evidence.length} concern(s))`
1174
+ };
1175
+ }
1176
+
1177
+ return {
1178
+ status: 'pass',
1179
+ evidence: [],
1180
+ message: `BC-08: Gate behavior aligned with config (mode=${mode}, gates=${isAutonomous && allGatesFalse ? 'all disabled' : 'active'})`
1181
+ };
1182
+ }
1183
+
1184
+ // ---------------------------------------------------------------------------
1185
+ // BC-09: Enforce-PBR-Workflow Advisory Tracking
1186
+ // ---------------------------------------------------------------------------
1187
+
1188
+ /**
1189
+ * BC-09: Track enforce-PBR-workflow hook advisories and whether they were addressed.
1190
+ * Reads hook logs for prompt-routing and check-skill-workflow advisory entries,
1191
+ * then checks if the advised PBR skill was subsequently used.
1192
+ *
1193
+ * @param {string} planningDir - Path to .planning/
1194
+ * @param {Object} [config] - Config object with workflow.enforce_pbr_skills setting
1195
+ * @returns {{ status: string, evidence: Array<string>, message: string }}
1196
+ */
1197
+ function checkEnforceWorkflowAdvisory(planningDir, config) {
1198
+ // Check enforce_pbr_skills setting
1199
+ const enforceSetting = (config && config.workflow && config.workflow.enforce_pbr_skills) || 'off';
1200
+
1201
+ if (enforceSetting === 'off') {
1202
+ return {
1203
+ status: 'pass',
1204
+ evidence: [],
1205
+ message: 'BC-09: enforce_pbr_skills is disabled — advisory tracking skipped'
1206
+ };
1207
+ }
1208
+
1209
+ const hookLogs = readHookLogs(planningDir);
1210
+ const events = readSessionEvents(planningDir);
1211
+ const allEntries = [...events, ...hookLogs].sort((a, b) => {
1212
+ const ta = a.ts || a.timestamp || '';
1213
+ const tb = b.ts || b.timestamp || '';
1214
+ return ta < tb ? -1 : ta > tb ? 1 : 0;
1215
+ });
1216
+
1217
+ if (allEntries.length === 0) {
1218
+ return {
1219
+ status: 'info',
1220
+ evidence: [],
1221
+ message: 'BC-09: No session data available — cannot assess workflow advisory compliance'
1222
+ };
1223
+ }
1224
+
1225
+ // Collect advisory entries from prompt-routing and check-skill-workflow hooks
1226
+ const advisories = [];
1227
+ const skillUsages = []; // Track actual PBR skill invocations
1228
+
1229
+ for (const entry of allEntries) {
1230
+ // Detect advisory warnings from relevant hooks
1231
+ const isAdvisoryHook = entry.hook === 'prompt-routing' ||
1232
+ entry.hook === 'check-skill-workflow' ||
1233
+ entry.hook === 'enforce-pbr-workflow';
1234
+
1235
+ if (isAdvisoryHook && entry.details) {
1236
+ const isAdvisory = entry.details.level === 'advisory' ||
1237
+ entry.details.decision === 'allow' ||
1238
+ entry.details.type === 'advisory' ||
1239
+ (entry.details.message && /suggest|consider|recommend|use \/pbr:/i.test(entry.details.message));
1240
+
1241
+ if (isAdvisory) {
1242
+ // Extract the suggested command if available
1243
+ const suggestedCommand = entry.details.suggested_command ||
1244
+ entry.details.command || '';
1245
+ const message = entry.details.message || entry.details.reason || '';
1246
+ const cmdMatch = message.match(/\/pbr:(\w+)/);
1247
+ const suggestedSkill = cmdMatch ? cmdMatch[1] : (suggestedCommand.replace('/pbr:', '') || null);
1248
+
1249
+ advisories.push({
1250
+ ts: entry.ts || entry.timestamp || '',
1251
+ suggestedSkill,
1252
+ message: message.substring(0, 120),
1253
+ index: allEntries.indexOf(entry)
1254
+ });
1255
+ }
1256
+ }
1257
+
1258
+ // Track PBR skill usages
1259
+ const skill = extractSkillInvocation(entry);
1260
+ if (skill) {
1261
+ skillUsages.push({
1262
+ skill,
1263
+ ts: entry.ts || entry.timestamp || '',
1264
+ index: allEntries.indexOf(entry)
1265
+ });
1266
+ }
1267
+ }
1268
+
1269
+ if (advisories.length === 0) {
1270
+ return {
1271
+ status: 'info',
1272
+ evidence: [],
1273
+ message: `BC-09: No workflow advisories issued (enforce_pbr_skills=${enforceSetting})`
1274
+ };
1275
+ }
1276
+
1277
+ // For each advisory, check if the suggested skill was used afterward
1278
+ let heeded = 0;
1279
+ let ignored = 0;
1280
+ const ignoredExamples = [];
1281
+
1282
+ for (const advisory of advisories) {
1283
+ if (!advisory.suggestedSkill) {
1284
+ // Cannot determine if heeded without a specific suggestion
1285
+ continue;
1286
+ }
1287
+
1288
+ const wasHeeded = skillUsages.some(
1289
+ s => s.index > advisory.index && s.skill === advisory.suggestedSkill
1290
+ );
1291
+
1292
+ if (wasHeeded) {
1293
+ heeded++;
1294
+ } else {
1295
+ ignored++;
1296
+ if (ignoredExamples.length < 3) {
1297
+ const time = advisory.ts ? ` at ${advisory.ts}` : '';
1298
+ ignoredExamples.push(
1299
+ `Advisory to use /pbr:${advisory.suggestedSkill} was ignored${time}: "${advisory.message}"`
1300
+ );
1301
+ }
1302
+ }
1303
+ }
1304
+
1305
+ const total = heeded + ignored;
1306
+ const complianceRate = total > 0 ? Math.round((heeded / total) * 100) : 100;
1307
+
1308
+ const evidence = [
1309
+ `${advisories.length} workflow advisories issued, ${heeded} heeded, ${ignored} ignored (${complianceRate}% compliance rate)`,
1310
+ ...ignoredExamples
1311
+ ];
1312
+
1313
+ return {
1314
+ status: 'info',
1315
+ evidence,
1316
+ message: `BC-09: ${total} trackable advisories — ${complianceRate}% compliance rate (enforce_pbr_skills=${enforceSetting})`
1317
+ };
1318
+ }
1319
+
1320
+ // ---------------------------------------------------------------------------
1321
+ // BC-10: Unmanaged Commit Detection
1322
+ // ---------------------------------------------------------------------------
1323
+
1324
+ /**
1325
+ * BC-10: Detect git commits made outside PBR skill context.
1326
+ * Cross-references .active-skill state against git commit Bash events.
1327
+ * Commits without an active PBR skill context are "unmanaged".
1328
+ *
1329
+ * @param {string} planningDir - Path to .planning/
1330
+ * @param {Object} [_config] - Config object (unused, for API consistency)
1331
+ * @returns {{ status: string, evidence: Array<string>, message: string }}
1332
+ */
1333
+ function checkUnmanagedCommitDetection(planningDir, _config) {
1334
+ const events = readSessionEvents(planningDir);
1335
+ const hookLogs = readHookLogs(planningDir);
1336
+ const allEntries = [...events, ...hookLogs].sort((a, b) => {
1337
+ const ta = a.ts || a.timestamp || '';
1338
+ const tb = b.ts || b.timestamp || '';
1339
+ return ta < tb ? -1 : ta > tb ? 1 : 0;
1340
+ });
1341
+
1342
+ if (allEntries.length === 0) {
1343
+ return {
1344
+ status: 'pass',
1345
+ evidence: [],
1346
+ message: 'BC-10: No session data available — cannot assess commit management'
1347
+ };
1348
+ }
1349
+
1350
+ const evidence = [];
1351
+ const commitFormatPattern = /^(feat|fix|refactor|test|docs|chore|wip|revert)\([a-zA-Z0-9._-]+\):\s+.+/;
1352
+
1353
+ // Track active-skill state over time from hook logs
1354
+ // Hook logs from validate-commit contain the commit validation context
1355
+ const activeSkillEntries = [];
1356
+ for (const entry of allEntries) {
1357
+ // Detect active-skill state changes from hook logs
1358
+ if (entry.hook && entry.details && entry.details.active_skill != null) {
1359
+ activeSkillEntries.push({
1360
+ skill: entry.details.active_skill,
1361
+ ts: entry.ts || entry.timestamp || '',
1362
+ });
1363
+ }
1364
+ // Also detect skill invocations as implicit active-skill markers
1365
+ const skill = extractSkillInvocation(entry);
1366
+ if (skill) {
1367
+ activeSkillEntries.push({ skill, ts: entry.ts || entry.timestamp || '' });
1368
+ }
1369
+ }
1370
+
1371
+ // Find all git commit Bash events
1372
+ for (const entry of allEntries) {
1373
+ const command = (entry.tool_input && entry.tool_input.command) ||
1374
+ (entry.details && entry.details.command) || '';
1375
+ const commandStr = typeof command === 'string' ? command : JSON.stringify(command);
1376
+
1377
+ if (!/\bgit\s+commit\b/i.test(commandStr)) continue;
1378
+
1379
+ const ts = entry.ts || entry.timestamp || '';
1380
+ const time = ts ? ts.substring(11, 16) : 'unknown';
1381
+
1382
+ // Extract commit message for format check
1383
+ const msgMatch = commandStr.match(/-m\s+["']([^"']+)["']/) ||
1384
+ commandStr.match(/<<'?EOF'?\s*\n([\s\S]*?)\nEOF/);
1385
+ const commitMsg = msgMatch ? msgMatch[1].trim().split('\n')[0].trim() : '';
1386
+
1387
+ // Check if there was an active PBR skill at the time of this commit
1388
+ // Look at the most recent active-skill entry before this commit timestamp
1389
+ const priorSkills = activeSkillEntries.filter(s => s.ts <= ts || !ts);
1390
+ const lastSkill = priorSkills.length > 0 ? priorSkills[priorSkills.length - 1] : null;
1391
+
1392
+ // Also check validate-commit hook logs for this commit — if the hook fired,
1393
+ // there may be active-skill info
1394
+ const commitHookEntry = allEntries.find(e =>
1395
+ e.hook === 'validate-commit' &&
1396
+ e.details && e.details.message === commitMsg
1397
+ );
1398
+ const hookActiveSkill = commitHookEntry && commitHookEntry.details &&
1399
+ commitHookEntry.details.active_skill;
1400
+
1401
+ const hasActiveSkill = (lastSkill && lastSkill.skill) || hookActiveSkill;
1402
+
1403
+ if (!hasActiveSkill) {
1404
+ // No active skill context detected
1405
+ const hasGoodFormat = commitFormatPattern.test(commitMsg);
1406
+ const formatNote = hasGoodFormat ? '' : ' (also lacks conventional format)';
1407
+ evidence.push(
1408
+ `Commit '${commitMsg || '(unparseable)'}' at ${time} — no active PBR skill context detected${formatNote}`
1409
+ );
1410
+ }
1411
+ }
1412
+
1413
+ if (evidence.length > 0) {
1414
+ return {
1415
+ status: 'warn',
1416
+ evidence,
1417
+ message: `BC-10: Found ${evidence.length} unmanaged commit(s) outside PBR skill context`
1418
+ };
1419
+ }
1420
+
1421
+ return {
1422
+ status: 'pass',
1423
+ evidence: [],
1424
+ message: 'BC-10: All commits were within PBR skill context'
1425
+ };
1426
+ }
1427
+
1428
+ // ---------------------------------------------------------------------------
1429
+ // BC-11: Context Delegation Threshold
1430
+ // ---------------------------------------------------------------------------
1431
+
1432
+ /**
1433
+ * BC-11: Detect when context exceeded inline_context_cap_pct but no subagent was spawned.
1434
+ * Uses config.workflow.inline_context_cap_pct threshold.
1435
+ *
1436
+ * @param {string} planningDir - Path to .planning/
1437
+ * @param {Object} [config] - Config object with workflow.inline_context_cap_pct
1438
+ * @returns {{ status: string, evidence: Array<string>, message: string }}
1439
+ */
1440
+ function checkContextDelegationThreshold(planningDir, config) {
1441
+ const hookLogs = readHookLogs(planningDir);
1442
+ const events = readSessionEvents(planningDir);
1443
+ const allEntries = [...events, ...hookLogs].sort((a, b) => {
1444
+ const ta = a.ts || a.timestamp || '';
1445
+ const tb = b.ts || b.timestamp || '';
1446
+ return ta < tb ? -1 : ta > tb ? 1 : 0;
1447
+ });
1448
+
1449
+ if (allEntries.length === 0) {
1450
+ return {
1451
+ status: 'pass',
1452
+ evidence: [],
1453
+ message: 'BC-11: No session data available — cannot assess context delegation'
1454
+ };
1455
+ }
1456
+
1457
+ // Read inline_context_cap_pct from config (default 50)
1458
+ const capPct = (config && config.workflow && config.workflow.inline_context_cap_pct != null)
1459
+ ? config.workflow.inline_context_cap_pct
1460
+ : 50;
1461
+
1462
+ const evidence = [];
1463
+
1464
+ // Find context usage reports from suggest-compact or track-context-budget hooks
1465
+ for (let i = 0; i < allEntries.length; i++) {
1466
+ const entry = allEntries[i];
1467
+
1468
+ // Look for context percentage reports
1469
+ const isContextHook = entry.hook === 'suggest-compact' ||
1470
+ entry.hook === 'track-context-budget' ||
1471
+ entry.hook === 'context-budget-check';
1472
+
1473
+ if (!isContextHook) continue;
1474
+
1475
+ // Extract context percentage from entry details
1476
+ let pctUsed = null;
1477
+ if (entry.details) {
1478
+ pctUsed = entry.details.pct_used || entry.details.estimated_percent ||
1479
+ entry.details.percent || entry.details.context_pct || null;
1480
+ // Also check tier info — DEGRADING is typically >=50%, POOR >=70%
1481
+ if (pctUsed == null && entry.details.tier) {
1482
+ if (entry.details.tier === 'POOR' || entry.details.tier === 'CRITICAL') pctUsed = 70;
1483
+ else if (entry.details.tier === 'DEGRADING') pctUsed = 55;
1484
+ }
1485
+ }
1486
+
1487
+ if (pctUsed == null || pctUsed <= capPct) continue;
1488
+
1489
+ const ts = entry.ts || entry.timestamp || '';
1490
+ const time = ts ? ts.substring(11, 16) : 'unknown';
1491
+
1492
+ // Check if a Task (subagent) was spawned in the next 5 events
1493
+ const lookAhead = allEntries.slice(i + 1, i + 6);
1494
+ const taskSpawned = lookAhead.some(e =>
1495
+ e.tool === 'Task' ||
1496
+ e.event === 'subagent-start' ||
1497
+ e.event === 'task-start' ||
1498
+ (e.details && e.details.tool === 'Task') ||
1499
+ (e.details && e.details.subagent_type)
1500
+ );
1501
+
1502
+ if (!taskSpawned) {
1503
+ evidence.push(
1504
+ `Context at ${pctUsed}% (cap: ${capPct}%) at ${time} but no subagent spawned in next 5 tool calls`
1505
+ );
1506
+ }
1507
+ }
1508
+
1509
+ if (evidence.length > 0) {
1510
+ return {
1511
+ status: 'warn',
1512
+ evidence,
1513
+ message: `BC-11: Context delegation threshold breached ${evidence.length} time(s) without subagent spawn`
1514
+ };
1515
+ }
1516
+
1517
+ return {
1518
+ status: 'pass',
1519
+ evidence: [],
1520
+ message: `BC-11: Context delegation threshold (${capPct}%) respected — subagents spawned when needed`
1521
+ };
1522
+ }
1523
+
1524
+ // ---------------------------------------------------------------------------
1525
+ // BC-12: Skill Self-Read Prevention
1526
+ // ---------------------------------------------------------------------------
1527
+
1528
+ /**
1529
+ * BC-12: Detect skills that wasted tokens reading their own SKILL.md.
1530
+ * Claude Code auto-loads SKILL.md for the active skill, so reading it again
1531
+ * is a token waste.
1532
+ *
1533
+ * @param {string} planningDir - Path to .planning/
1534
+ * @param {Object} [_config] - Config object (unused, for API consistency)
1535
+ * @returns {{ status: string, evidence: Array<string>, message: string }}
1536
+ */
1537
+ function checkSkillSelfReadPrevention(planningDir, _config) {
1538
+ const events = readSessionEvents(planningDir);
1539
+ const hookLogs = readHookLogs(planningDir);
1540
+ const allEntries = [...events, ...hookLogs].sort((a, b) => {
1541
+ const ta = a.ts || a.timestamp || '';
1542
+ const tb = b.ts || b.timestamp || '';
1543
+ return ta < tb ? -1 : ta > tb ? 1 : 0;
1544
+ });
1545
+
1546
+ if (allEntries.length === 0) {
1547
+ return {
1548
+ status: 'pass',
1549
+ evidence: [],
1550
+ message: 'BC-12: No session data available — cannot assess skill self-reads'
1551
+ };
1552
+ }
1553
+
1554
+ const evidence = [];
1555
+
1556
+ // Track active-skill state and detect Read events for SKILL.md files
1557
+ let currentSkill = null;
1558
+
1559
+ for (const entry of allEntries) {
1560
+ // Update current active skill from hook logs
1561
+ if (entry.hook && entry.details && entry.details.active_skill != null) {
1562
+ currentSkill = entry.details.active_skill;
1563
+ }
1564
+ // Also update from skill invocations
1565
+ const invokedSkill = extractSkillInvocation(entry);
1566
+ if (invokedSkill) {
1567
+ currentSkill = invokedSkill;
1568
+ }
1569
+
1570
+ // Skip entries from agent contexts (agents may legitimately read skill files)
1571
+ if (entry.task_id || entry.subagent ||
1572
+ (entry.details && (entry.details.subagent_type || entry.details.task_id || entry.details.inside_task))) {
1573
+ continue;
1574
+ }
1575
+
1576
+ // Detect Read tool events targeting SKILL.md files
1577
+ const isRead = entry.tool === 'Read' ||
1578
+ (entry.details && entry.details.tool === 'Read');
1579
+ if (!isRead) continue;
1580
+
1581
+ const filePath = (entry.tool_input && entry.tool_input.file_path) ||
1582
+ (entry.details && (entry.details.file_path || entry.details.file)) ||
1583
+ entry.file || entry.path || '';
1584
+ const normalized = filePath.replace(/\\/g, '/');
1585
+
1586
+ // Check if this is a SKILL.md file under /skills/
1587
+ if (!/\/skills\//.test(normalized) || !/SKILL\.md$/i.test(normalized)) continue;
1588
+
1589
+ // Extract skill name from path: skills/{skill-name}/SKILL.md
1590
+ const skillMatch = normalized.match(/\/skills\/([^/]+)\/SKILL\.md$/i);
1591
+ if (!skillMatch) continue;
1592
+ const readSkillName = skillMatch[1];
1593
+
1594
+ // Check if the active skill matches the SKILL.md being read
1595
+ if (currentSkill && readSkillName === currentSkill) {
1596
+ const ts = entry.ts || entry.timestamp || '';
1597
+ const time = ts ? ts.substring(11, 16) : 'unknown';
1598
+ evidence.push(
1599
+ `${currentSkill} skill read its own skills/${currentSkill}/SKILL.md at ${time} — wasted tokens`
1600
+ );
1601
+ }
1602
+ }
1603
+
1604
+ if (evidence.length > 0) {
1605
+ return {
1606
+ status: 'info',
1607
+ evidence,
1608
+ message: `BC-12: Found ${evidence.length} skill self-read(s) — token waste detected`
1609
+ };
1610
+ }
1611
+
1612
+ return {
1613
+ status: 'pass',
1614
+ evidence: [],
1615
+ message: 'BC-12: No skill self-reads detected'
1616
+ };
1617
+ }
1618
+
1619
+ // ---------------------------------------------------------------------------
1620
+ // BC-13: Hook Output Effectiveness
1621
+ // ---------------------------------------------------------------------------
1622
+
1623
+ /**
1624
+ * BC-13: Check whether hook advisory outputs were actually followed by the LLM.
1625
+ * Reads hook logs for additionalContext/warning outputs, then checks subsequent
1626
+ * session events to see if the LLM's next action aligned with the advisory.
1627
+ *
1628
+ * @param {string} planningDir - Path to .planning/
1629
+ * @param {Object} [_config] - Config object (unused, for API consistency)
1630
+ * @returns {{ status: string, evidence: Array<string>, message: string }}
1631
+ */
1632
+ function checkHookOutputEffectiveness(planningDir, _config) {
1633
+ const hookLogs = readHookLogs(planningDir);
1634
+ const events = readSessionEvents(planningDir);
1635
+ const allEntries = [...events, ...hookLogs].sort((a, b) => {
1636
+ const ta = a.ts || a.timestamp || '';
1637
+ const tb = b.ts || b.timestamp || '';
1638
+ return ta < tb ? -1 : ta > tb ? 1 : 0;
1639
+ });
1640
+
1641
+ if (allEntries.length === 0) {
1642
+ return {
1643
+ status: 'pass',
1644
+ evidence: [],
1645
+ message: 'BC-13: No session data available — cannot assess hook output effectiveness'
1646
+ };
1647
+ }
1648
+
1649
+ // Find hook entries that produced advisory output (additionalContext, warnings)
1650
+ const advisoryHookEntries = [];
1651
+ for (let i = 0; i < allEntries.length; i++) {
1652
+ const entry = allEntries[i];
1653
+ if (!entry.hook) continue;
1654
+
1655
+ const hasAdvisory =
1656
+ (entry.details && entry.details.additionalContext) ||
1657
+ (entry.details && entry.details.warning) ||
1658
+ (entry.details && entry.details.level === 'advisory') ||
1659
+ (entry.output && typeof entry.output === 'string' && entry.output.includes('additionalContext'));
1660
+
1661
+ if (hasAdvisory) {
1662
+ // Extract advisory content
1663
+ const advisory = (entry.details && entry.details.additionalContext) ||
1664
+ (entry.details && entry.details.warning) ||
1665
+ (entry.details && entry.details.message) || '';
1666
+ advisoryHookEntries.push({ index: i, hook: entry.hook, advisory, ts: entry.ts || entry.timestamp || '' });
1667
+ }
1668
+ }
1669
+
1670
+ if (advisoryHookEntries.length === 0) {
1671
+ return {
1672
+ status: 'info',
1673
+ evidence: ['No hook advisory outputs found in logs'],
1674
+ message: 'BC-13: No hook advisories detected — nothing to measure effectiveness against'
1675
+ };
1676
+ }
1677
+
1678
+ // For each advisory, check if the next LLM action appears to comply
1679
+ // Heuristic: if the advisory mentions "block" or "stop" and the next tool call
1680
+ // is in the same file/area, the advisory was ignored
1681
+ let followed = 0;
1682
+ let ignored = 0;
1683
+ const evidence = [];
1684
+
1685
+ for (const adv of advisoryHookEntries) {
1686
+ // Look at next 3 entries after the advisory
1687
+ const lookAhead = allEntries.slice(adv.index + 1, adv.index + 4);
1688
+
1689
+ // Check if advisory suggested stopping/blocking and LLM continued same action
1690
+ const advisoryStr = typeof adv.advisory === 'string' ? adv.advisory : JSON.stringify(adv.advisory);
1691
+ const suggestsStop = /\b(stop|block|avoid|do not|don't|warning|caution)\b/i.test(advisoryStr);
1692
+
1693
+ if (suggestsStop) {
1694
+ // If the LLM's next action is a Write/Edit to the same area, advisory was ignored
1695
+ const nextWrite = lookAhead.find(e =>
1696
+ e.tool === 'Write' || e.tool === 'Edit' ||
1697
+ (e.details && (e.details.tool === 'Write' || e.details.tool === 'Edit'))
1698
+ );
1699
+ if (nextWrite) {
1700
+ ignored++;
1701
+ if (evidence.length < 3) {
1702
+ const time = adv.ts ? ` at ${adv.ts.substring(11, 16)}` : '';
1703
+ evidence.push(`${adv.hook} advisory${time} suggested caution but LLM proceeded with write`);
1704
+ }
1705
+ } else {
1706
+ followed++;
1707
+ }
1708
+ } else {
1709
+ // Non-blocking advisory — assume followed unless we see contradictory evidence
1710
+ followed++;
1711
+ }
1712
+ }
1713
+
1714
+ const total = followed + ignored;
1715
+ const complianceRate = total > 0 ? Math.round((followed / total) * 100) : 100;
1716
+
1717
+ evidence.unshift(`Hook advisories: ${total} total, ${followed} followed, ${ignored} ignored (${complianceRate}% compliance)`);
1718
+
1719
+ let status;
1720
+ if (complianceRate >= 70) {
1721
+ status = 'pass';
1722
+ } else {
1723
+ status = 'warn';
1724
+ }
1725
+
1726
+ return {
1727
+ status,
1728
+ evidence,
1729
+ message: `BC-13: Hook output effectiveness: ${complianceRate}% of advisories followed (${followed}/${total})`
1730
+ };
1731
+ }
1732
+
1733
+ // ---------------------------------------------------------------------------
1734
+ // BC-14: Agent Scope Compliance
1735
+ // ---------------------------------------------------------------------------
1736
+
1737
+ /**
1738
+ * BC-14: Check that agents only modified files listed in their PLAN.md files_modified.
1739
+ * Compares SUMMARY.md key_files against PLAN.md files_modified for each phase.
1740
+ *
1741
+ * @param {string} planningDir - Path to .planning/
1742
+ * @param {Object} [_config] - Config object (unused, for API consistency)
1743
+ * @returns {{ status: string, evidence: Array<string>, message: string }}
1744
+ */
1745
+ function checkAgentScopeCompliance(planningDir, _config) {
1746
+ const phasesDir = path.join(planningDir, 'phases');
1747
+ if (!fs.existsSync(phasesDir)) {
1748
+ return {
1749
+ status: 'info',
1750
+ evidence: ['No phases directory found'],
1751
+ message: 'BC-14: No phases directory — cannot assess agent scope compliance'
1752
+ };
1753
+ }
1754
+
1755
+ let phaseDirs;
1756
+ try {
1757
+ phaseDirs = fs.readdirSync(phasesDir, { withFileTypes: true })
1758
+ .filter(d => d.isDirectory())
1759
+ .map(d => d.name);
1760
+ } catch (_e) {
1761
+ return {
1762
+ status: 'info',
1763
+ evidence: ['Could not read phases directory'],
1764
+ message: 'BC-14: Could not read phases directory'
1765
+ };
1766
+ }
1767
+
1768
+ const evidence = [];
1769
+ let totalPlans = 0;
1770
+ let outOfScope = 0;
1771
+
1772
+ for (const phaseDir of phaseDirs) {
1773
+ const phaseFullPath = path.join(phasesDir, phaseDir);
1774
+
1775
+ // Find PLAN files
1776
+ let files;
1777
+ try {
1778
+ files = fs.readdirSync(phaseFullPath).filter(f => /^PLAN.*\.md$/i.test(f));
1779
+ } catch (_e) {
1780
+ continue;
1781
+ }
1782
+
1783
+ for (const planFile of files) {
1784
+ // Extract plan ID from filename (e.g., PLAN-01.md -> 01)
1785
+ const planIdMatch = planFile.match(/PLAN-?(\d+)/i);
1786
+ if (!planIdMatch) continue;
1787
+ const planId = planIdMatch[1];
1788
+
1789
+ // Read PLAN file for files_modified
1790
+ let planContent;
1791
+ try {
1792
+ planContent = fs.readFileSync(path.join(phaseFullPath, planFile), 'utf8');
1793
+ } catch (_e) {
1794
+ continue;
1795
+ }
1796
+
1797
+ // Extract files_modified from YAML frontmatter
1798
+ const fmMatch = planContent.match(/^---\r?\n([\s\S]*?)\r?\n---/);
1799
+ if (!fmMatch) continue;
1800
+ const fm = fmMatch[1];
1801
+
1802
+ const plannedFiles = [];
1803
+ const fmLines = fm.split(/\r?\n/);
1804
+ let inFilesModified = false;
1805
+ for (const line of fmLines) {
1806
+ if (/^\s*files_modified\s*:/.test(line)) {
1807
+ inFilesModified = true;
1808
+ continue;
1809
+ }
1810
+ if (inFilesModified) {
1811
+ if (/^\s*-\s+"?(.+?)"?\s*$/.test(line)) {
1812
+ const fileMatch = line.match(/^\s*-\s+"?(.+?)"?\s*$/);
1813
+ if (fileMatch) plannedFiles.push(fileMatch[1].trim());
1814
+ } else if (/^\s*\w/.test(line)) {
1815
+ inFilesModified = false;
1816
+ }
1817
+ }
1818
+ }
1819
+
1820
+ if (plannedFiles.length === 0) continue;
1821
+
1822
+ // Find matching SUMMARY file
1823
+ const summaryPattern = new RegExp(`SUMMARY.*${planId}.*\\.md$`, 'i');
1824
+ let summaryFiles;
1825
+ try {
1826
+ summaryFiles = fs.readdirSync(phaseFullPath).filter(f => summaryPattern.test(f));
1827
+ } catch (_e) {
1828
+ continue;
1829
+ }
1830
+
1831
+ for (const summaryFile of summaryFiles) {
1832
+ let summaryContent;
1833
+ try {
1834
+ summaryContent = fs.readFileSync(path.join(phaseFullPath, summaryFile), 'utf8');
1835
+ } catch (_e) {
1836
+ continue;
1837
+ }
1838
+
1839
+ // Extract key_files from SUMMARY frontmatter
1840
+ const sfmMatch = summaryContent.match(/^---\r?\n([\s\S]*?)\r?\n---/);
1841
+ if (!sfmMatch) continue;
1842
+ const sfm = sfmMatch[1];
1843
+
1844
+ const actualFiles = [];
1845
+ const sfmLines = sfm.split(/\r?\n/);
1846
+ let inKeyFiles = false;
1847
+ for (const line of sfmLines) {
1848
+ if (/^\s*key_files\s*:/.test(line)) {
1849
+ inKeyFiles = true;
1850
+ continue;
1851
+ }
1852
+ if (inKeyFiles) {
1853
+ if (/^\s*-\s+"?(.+?)"?\s*$/.test(line)) {
1854
+ const fileMatch = line.match(/^\s*-\s+"?(.+?)"?\s*$/);
1855
+ if (fileMatch) {
1856
+ // key_files may have ": description" suffix, strip it
1857
+ const filePath = fileMatch[1].split(':')[0].trim();
1858
+ actualFiles.push(filePath);
1859
+ }
1860
+ } else if (/^\s*\w/.test(line)) {
1861
+ inKeyFiles = false;
1862
+ }
1863
+ }
1864
+ }
1865
+
1866
+ totalPlans++;
1867
+
1868
+ // Compare: any actualFiles not in plannedFiles?
1869
+ const outOfScopeFiles = actualFiles.filter(af =>
1870
+ !plannedFiles.some(pf => af.includes(pf) || pf.includes(af))
1871
+ );
1872
+
1873
+ if (outOfScopeFiles.length > 0) {
1874
+ outOfScope++;
1875
+ evidence.push(
1876
+ `${phaseDir}/${planFile}: ${outOfScopeFiles.length} file(s) modified outside plan scope: ${outOfScopeFiles.slice(0, 3).join(', ')}`
1877
+ );
1878
+ }
1879
+ }
1880
+ }
1881
+ }
1882
+
1883
+ if (totalPlans === 0) {
1884
+ return {
1885
+ status: 'info',
1886
+ evidence: ['No PLAN/SUMMARY pairs found to compare'],
1887
+ message: 'BC-14: No plan/summary pairs found — cannot assess scope compliance'
1888
+ };
1889
+ }
1890
+
1891
+ evidence.unshift(`Checked ${totalPlans} plan(s): ${outOfScope} had out-of-scope modifications`);
1892
+
1893
+ if (outOfScope > 0) {
1894
+ return {
1895
+ status: 'warn',
1896
+ evidence,
1897
+ message: `BC-14: ${outOfScope}/${totalPlans} plan(s) had files modified outside declared scope`
1898
+ };
1899
+ }
1900
+
1901
+ return {
1902
+ status: 'pass',
1903
+ evidence,
1904
+ message: `BC-14: All ${totalPlans} plan(s) stayed within declared file scope`
1905
+ };
1906
+ }
1907
+
1908
+ // ---------------------------------------------------------------------------
1909
+ // BC-15: Agent Plan Adherence
1910
+ // ---------------------------------------------------------------------------
1911
+
1912
+ /**
1913
+ * BC-15: Check that executor task completion counts match planned task counts.
1914
+ * Compares SUMMARY.md tasks_completed against PLAN.md <task> block count.
1915
+ *
1916
+ * @param {string} planningDir - Path to .planning/
1917
+ * @param {Object} [_config] - Config object (unused, for API consistency)
1918
+ * @returns {{ status: string, evidence: Array<string>, message: string }}
1919
+ */
1920
+ function checkAgentPlanAdherence(planningDir, _config) {
1921
+ const phasesDir = path.join(planningDir, 'phases');
1922
+ if (!fs.existsSync(phasesDir)) {
1923
+ return {
1924
+ status: 'info',
1925
+ evidence: ['No phases directory found'],
1926
+ message: 'BC-15: No phases directory — cannot assess plan adherence'
1927
+ };
1928
+ }
1929
+
1930
+ let phaseDirs;
1931
+ try {
1932
+ phaseDirs = fs.readdirSync(phasesDir, { withFileTypes: true })
1933
+ .filter(d => d.isDirectory())
1934
+ .map(d => d.name);
1935
+ } catch (_e) {
1936
+ return {
1937
+ status: 'info',
1938
+ evidence: ['Could not read phases directory'],
1939
+ message: 'BC-15: Could not read phases directory'
1940
+ };
1941
+ }
1942
+
1943
+ const evidence = [];
1944
+ let totalPlans = 0;
1945
+ let mismatches = 0;
1946
+
1947
+ for (const phaseDir of phaseDirs) {
1948
+ const phaseFullPath = path.join(phasesDir, phaseDir);
1949
+
1950
+ let files;
1951
+ try {
1952
+ files = fs.readdirSync(phaseFullPath).filter(f => /^PLAN.*\.md$/i.test(f));
1953
+ } catch (_e) {
1954
+ continue;
1955
+ }
1956
+
1957
+ for (const planFile of files) {
1958
+ const planIdMatch = planFile.match(/PLAN-?(\d+)/i);
1959
+ if (!planIdMatch) continue;
1960
+ const planId = planIdMatch[1];
1961
+
1962
+ // Count <task> blocks in PLAN
1963
+ let planContent;
1964
+ try {
1965
+ planContent = fs.readFileSync(path.join(phaseFullPath, planFile), 'utf8');
1966
+ } catch (_e) {
1967
+ continue;
1968
+ }
1969
+
1970
+ const taskMatches = planContent.match(/<task\s/g);
1971
+ const plannedTasks = taskMatches ? taskMatches.length : 0;
1972
+ if (plannedTasks === 0) continue;
1973
+
1974
+ // Find matching SUMMARY
1975
+ const summaryPattern = new RegExp(`SUMMARY.*${planId}.*\\.md$`, 'i');
1976
+ let summaryFiles;
1977
+ try {
1978
+ summaryFiles = fs.readdirSync(phaseFullPath).filter(f => summaryPattern.test(f));
1979
+ } catch (_e) {
1980
+ continue;
1981
+ }
1982
+
1983
+ for (const summaryFile of summaryFiles) {
1984
+ let summaryContent;
1985
+ try {
1986
+ summaryContent = fs.readFileSync(path.join(phaseFullPath, summaryFile), 'utf8');
1987
+ } catch (_e) {
1988
+ continue;
1989
+ }
1990
+
1991
+ totalPlans++;
1992
+
1993
+ // Extract tasks_completed from SUMMARY frontmatter
1994
+ const fmMatch = summaryContent.match(/^---\r?\n([\s\S]*?)\r?\n---/);
1995
+ if (!fmMatch) {
1996
+ mismatches++;
1997
+ evidence.push(`${phaseDir}/${summaryFile}: no frontmatter — cannot determine tasks_completed`);
1998
+ continue;
1999
+ }
2000
+
2001
+ const fm = fmMatch[1];
2002
+ const completedMatch = fm.match(/tasks_completed\s*:\s*(\d+)/);
2003
+ const totalMatch = fm.match(/tasks_total\s*:\s*(\d+)/);
2004
+
2005
+ const completedTasks = completedMatch ? parseInt(completedMatch[1], 10) : null;
2006
+ const reportedTotal = totalMatch ? parseInt(totalMatch[1], 10) : null;
2007
+
2008
+ if (completedTasks === null) {
2009
+ // Check status field as fallback
2010
+ const statusMatch = fm.match(/status\s*:\s*["']?(\w+)/);
2011
+ const status = statusMatch ? statusMatch[1] : 'unknown';
2012
+ if (status === 'complete') {
2013
+ // Assume all tasks completed if status is complete
2014
+ continue;
2015
+ }
2016
+ mismatches++;
2017
+ evidence.push(`${phaseDir}/${summaryFile}: no tasks_completed field (status: ${status})`);
2018
+ continue;
2019
+ }
2020
+
2021
+ // Check: planned == completed?
2022
+ if (completedTasks !== plannedTasks) {
2023
+ mismatches++;
2024
+ evidence.push(
2025
+ `${phaseDir}/${planFile}: planned ${plannedTasks} tasks, completed ${completedTasks}` +
2026
+ (reportedTotal ? ` (reported total: ${reportedTotal})` : '')
2027
+ );
2028
+ }
2029
+ }
2030
+ }
2031
+ }
2032
+
2033
+ if (totalPlans === 0) {
2034
+ return {
2035
+ status: 'info',
2036
+ evidence: ['No PLAN/SUMMARY pairs found to compare'],
2037
+ message: 'BC-15: No plan/summary pairs found — cannot assess plan adherence'
2038
+ };
2039
+ }
2040
+
2041
+ evidence.unshift(`Checked ${totalPlans} plan(s): ${mismatches} had task count mismatches`);
2042
+
2043
+ if (mismatches > 0) {
2044
+ return {
2045
+ status: 'warn',
2046
+ evidence,
2047
+ message: `BC-15: ${mismatches}/${totalPlans} plan(s) had task completion mismatches`
2048
+ };
2049
+ }
2050
+
2051
+ return {
2052
+ status: 'pass',
2053
+ evidence,
2054
+ message: `BC-15: All ${totalPlans} plan(s) completed their planned task counts`
2055
+ };
2056
+ }
2057
+
2058
+ // ---------------------------------------------------------------------------
2059
+ // Exports
2060
+ // ---------------------------------------------------------------------------
2061
+
2062
+ module.exports = {
2063
+ // Shared helpers
2064
+ getLogsDir,
2065
+ readJsonlFiles,
2066
+ readSessionEvents,
2067
+ readHookLogs,
2068
+ // BC-01
2069
+ checkSkillSequenceCompliance,
2070
+ // BC-02
2071
+ checkStateMachineTransitions,
2072
+ // BC-03
2073
+ checkPreConditionVerification,
2074
+ // BC-04
2075
+ checkPostConditionVerification,
2076
+ // BC-05
2077
+ checkOrchestratorBudgetDiscipline,
2078
+ // BC-06
2079
+ checkArtifactCreationOrder,
2080
+ // BC-07
2081
+ checkCriticalMarkerCompliance,
2082
+ // BC-08
2083
+ checkGateCompliance,
2084
+ // BC-09
2085
+ checkEnforceWorkflowAdvisory,
2086
+ // BC-10
2087
+ checkUnmanagedCommitDetection,
2088
+ // BC-11
2089
+ checkContextDelegationThreshold,
2090
+ // BC-12
2091
+ checkSkillSelfReadPrevention,
2092
+ // BC-13
2093
+ checkHookOutputEffectiveness,
2094
+ // BC-14
2095
+ checkAgentScopeCompliance,
2096
+ // BC-15
2097
+ checkAgentPlanAdherence,
2098
+ };