@sienklogic/plan-build-run 2.21.1 → 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 (982) hide show
  1. package/CHANGELOG.md +1331 -323
  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 +210 -34
  147. package/plugins/pbr/agents/dev-sync.md +206 -0
  148. package/plugins/pbr/agents/executor.md +734 -38
  149. package/plugins/pbr/agents/general.md +69 -5
  150. package/plugins/pbr/agents/integration-checker.md +147 -31
  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 -65
  154. package/plugins/pbr/agents/planner.md +449 -41
  155. package/plugins/pbr/agents/researcher.md +218 -37
  156. package/plugins/pbr/agents/roadmapper.md +398 -0
  157. package/plugins/pbr/agents/synthesizer.md +166 -25
  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 +570 -46
  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/execute-phase.md +6 -0
  172. package/plugins/pbr/commands/fast.md +6 -0
  173. package/plugins/pbr/commands/forensics.md +6 -0
  174. package/plugins/pbr/commands/import.md +1 -1
  175. package/plugins/pbr/commands/insert-phase.md +65 -0
  176. package/plugins/pbr/commands/intel.md +5 -0
  177. package/plugins/pbr/commands/join-discord.md +11 -0
  178. package/plugins/pbr/commands/list-phase-assumptions.md +5 -0
  179. package/plugins/pbr/commands/map-codebase.md +6 -0
  180. package/plugins/pbr/commands/milestone-summary.md +6 -0
  181. package/plugins/pbr/commands/new-milestone.md +8 -0
  182. package/plugins/pbr/commands/new-project.md +6 -0
  183. package/plugins/pbr/commands/pause-work.md +5 -0
  184. package/plugins/pbr/commands/plan-milestone-gaps.md +7 -0
  185. package/plugins/pbr/commands/plan-phase.md +6 -0
  186. package/plugins/pbr/commands/plant-seed.md +6 -0
  187. package/plugins/pbr/commands/profile-user.md +5 -0
  188. package/plugins/pbr/commands/profile.md +5 -0
  189. package/plugins/pbr/commands/progress.md +6 -0
  190. package/plugins/pbr/commands/quick.md +1 -1
  191. package/plugins/pbr/commands/reapply-patches.md +47 -0
  192. package/plugins/pbr/commands/release.md +6 -0
  193. package/plugins/pbr/commands/remove-phase.md +66 -0
  194. package/plugins/pbr/commands/research-phase.md +59 -0
  195. package/plugins/pbr/commands/resume-work.md +5 -0
  196. package/plugins/pbr/commands/seed.md +6 -0
  197. package/plugins/pbr/commands/session-report.md +5 -0
  198. package/plugins/pbr/commands/set-profile.md +6 -0
  199. package/plugins/pbr/commands/settings.md +5 -0
  200. package/plugins/pbr/commands/setup.md +1 -1
  201. package/plugins/pbr/commands/ship.md +5 -0
  202. package/plugins/pbr/commands/stats.md +6 -0
  203. package/plugins/pbr/commands/test.md +5 -0
  204. package/plugins/pbr/commands/thread.md +6 -0
  205. package/plugins/pbr/commands/todo.md +1 -1
  206. package/plugins/pbr/commands/ui-phase.md +5 -0
  207. package/plugins/pbr/commands/ui-review.md +5 -0
  208. package/plugins/pbr/commands/undo.md +5 -0
  209. package/plugins/pbr/commands/update.md +37 -0
  210. package/plugins/pbr/commands/validate-phase.md +5 -0
  211. package/plugins/pbr/commands/verify-work.md +6 -0
  212. package/plugins/pbr/dashboard/package-lock.json +6 -0
  213. package/plugins/pbr/dist/architecture-guard.js +76 -0
  214. package/plugins/pbr/dist/audit-dimensions.js +556 -0
  215. package/plugins/pbr/dist/auto-continue.js +277 -0
  216. package/plugins/pbr/dist/block-skill-self-read.js +124 -0
  217. package/plugins/pbr/dist/check-agent-state-write.js +63 -0
  218. package/plugins/pbr/dist/check-config-change.js +213 -0
  219. package/plugins/pbr/dist/check-cross-plugin-sync.js +93 -0
  220. package/plugins/pbr/dist/check-dangerous-commands.js +193 -0
  221. package/plugins/pbr/dist/check-direct-state-write.js +37 -0
  222. package/plugins/pbr/dist/check-doc-sprawl.js +102 -0
  223. package/plugins/pbr/dist/check-phase-boundary.js +191 -0
  224. package/plugins/pbr/dist/check-plan-format.js +227 -0
  225. package/plugins/pbr/dist/check-read-first.js +345 -0
  226. package/plugins/pbr/dist/check-roadmap-sync.js +507 -0
  227. package/plugins/pbr/dist/check-skill-workflow.js +354 -0
  228. package/plugins/pbr/dist/check-state-sync.js +676 -0
  229. package/plugins/pbr/dist/check-subagent-output.js +425 -0
  230. package/plugins/pbr/dist/check-summary-gate.js +188 -0
  231. package/plugins/pbr/dist/context-bridge.js +425 -0
  232. package/plugins/pbr/dist/context-budget-check.js +442 -0
  233. package/plugins/pbr/dist/context-quality.js +271 -0
  234. package/plugins/pbr/dist/enforce-context-budget.js +138 -0
  235. package/plugins/pbr/dist/enforce-pbr-workflow.js +277 -0
  236. package/plugins/pbr/dist/event-handler.js +212 -0
  237. package/plugins/pbr/dist/event-logger.js +125 -0
  238. package/plugins/pbr/dist/feedback-loop.js +155 -0
  239. package/plugins/pbr/dist/graph-update.js +422 -0
  240. package/plugins/pbr/dist/hook-logger.js +114 -0
  241. package/plugins/pbr/dist/hook-server-client.js +361 -0
  242. package/plugins/pbr/dist/hook-server.js +664 -0
  243. package/plugins/pbr/dist/hooks-schema.json +87 -0
  244. package/plugins/pbr/dist/instructions-loaded.js +173 -0
  245. package/plugins/pbr/dist/intercept-plan-mode.js +81 -0
  246. package/plugins/pbr/dist/log-notification.js +131 -0
  247. package/plugins/pbr/dist/log-subagent.js +367 -0
  248. package/plugins/pbr/dist/log-tool-failure.js +140 -0
  249. package/plugins/pbr/dist/milestone-learnings.js +519 -0
  250. package/plugins/pbr/dist/pbr-tools.js +493 -0
  251. package/plugins/pbr/dist/post-bash-triage.js +96 -0
  252. package/plugins/pbr/dist/post-compact.js +135 -0
  253. package/plugins/pbr/dist/post-hoc.js +237 -0
  254. package/plugins/pbr/dist/post-write-dispatch.js +243 -0
  255. package/plugins/pbr/dist/post-write-quality.js +208 -0
  256. package/plugins/pbr/dist/pre-bash-dispatch.js +212 -0
  257. package/plugins/pbr/dist/pre-skill-dispatch.js +114 -0
  258. package/plugins/pbr/dist/pre-task-dispatch.js +269 -0
  259. package/plugins/pbr/dist/pre-write-dispatch.js +234 -0
  260. package/plugins/pbr/dist/progress-tracker.js +173 -0
  261. package/plugins/pbr/dist/prompt-guard.js +114 -0
  262. package/plugins/pbr/dist/prompt-routing.js +209 -0
  263. package/plugins/pbr/dist/quick-status.js +179 -0
  264. package/plugins/pbr/dist/record-incident.js +37 -0
  265. package/plugins/pbr/dist/run-hook.js +132 -0
  266. package/plugins/pbr/dist/session-cleanup.js +653 -0
  267. package/plugins/pbr/dist/session-tracker.js +124 -0
  268. package/plugins/pbr/dist/status-line.js +849 -0
  269. package/plugins/pbr/dist/suggest-compact.js +307 -0
  270. package/plugins/pbr/dist/sync-context-to-claude.js +100 -0
  271. package/plugins/pbr/dist/task-completed.js +206 -0
  272. package/plugins/pbr/dist/track-context-budget.js +432 -0
  273. package/plugins/pbr/dist/track-user-gates.js +88 -0
  274. package/plugins/pbr/dist/trust-tracker.js +193 -0
  275. package/plugins/pbr/dist/validate-commit.js +233 -0
  276. package/plugins/pbr/dist/validate-skill-args.js +222 -0
  277. package/plugins/pbr/dist/validate-task.js +271 -0
  278. package/plugins/pbr/dist/worktree-create.js +144 -0
  279. package/plugins/pbr/dist/worktree-remove.js +147 -0
  280. package/plugins/pbr/hooks/hooks.json +137 -65
  281. package/plugins/pbr/references/agent-contracts.md +39 -8
  282. package/plugins/pbr/references/agent-teams.md +3 -3
  283. package/plugins/pbr/references/archive/checkpoints.md +189 -0
  284. package/plugins/pbr/references/archive/context-quality-tiers.md +45 -0
  285. package/plugins/pbr/references/archive/hook-ordering.md +89 -0
  286. package/plugins/pbr/references/archive/limitations.md +106 -0
  287. package/plugins/pbr/references/archive/pbr-rules.md +194 -0
  288. package/plugins/pbr/references/archive/pbr-tools-cli.md +415 -0
  289. package/plugins/pbr/references/archive/pretooluse-jsonl-behavior.md +58 -0
  290. package/plugins/pbr/references/archive/signal-files.md +41 -0
  291. package/plugins/pbr/references/archive/tmux-setup.md +288 -0
  292. package/plugins/pbr/references/archive/verification-matrix.md +34 -0
  293. package/plugins/pbr/references/archive/verification-patterns.md +277 -0
  294. package/plugins/pbr/references/archive/worktree-sparse-checkout.md +86 -0
  295. package/plugins/pbr/references/assumptions.md +42 -0
  296. package/plugins/pbr/references/checkpoints.md +723 -104
  297. package/plugins/pbr/references/config-reference.md +387 -10
  298. package/plugins/pbr/references/continuation-format.md +1 -0
  299. package/plugins/pbr/references/decimal-phase-calculation.md +65 -0
  300. package/plugins/pbr/references/deviation-rules.md +12 -0
  301. package/plugins/pbr/references/few-shot-examples/audit.md +77 -0
  302. package/plugins/pbr/references/few-shot-examples/check-plan-format.md +172 -0
  303. package/plugins/pbr/references/few-shot-examples/check-subagent-output.md +118 -0
  304. package/plugins/pbr/references/few-shot-examples/integration-checker.md +70 -0
  305. package/plugins/pbr/references/few-shot-examples/nyquist-auditor.md +83 -0
  306. package/plugins/pbr/references/few-shot-examples/plan-checker.md +73 -0
  307. package/plugins/pbr/references/few-shot-examples/ui-checker.md +71 -0
  308. package/plugins/pbr/references/few-shot-examples/verifier.md +109 -0
  309. package/plugins/pbr/references/git-integration.md +110 -27
  310. package/plugins/pbr/references/git-planning-commit.md +35 -0
  311. package/plugins/pbr/references/model-profile-resolution.md +34 -0
  312. package/plugins/pbr/references/model-profiles.md +90 -7
  313. package/plugins/pbr/references/model-selection.md +1 -1
  314. package/plugins/pbr/references/node-repair.md +48 -0
  315. package/plugins/pbr/references/plan-authoring.md +65 -0
  316. package/plugins/pbr/references/plan-format.md +184 -10
  317. package/plugins/pbr/references/questioning.md +138 -49
  318. package/plugins/pbr/references/reading-verification.md +4 -4
  319. package/plugins/pbr/references/tdd.md +263 -0
  320. package/plugins/pbr/references/thinking-models-planning.md +47 -0
  321. package/plugins/pbr/references/thinking-models-verification.md +44 -0
  322. package/plugins/pbr/references/ui-brand.md +449 -0
  323. package/plugins/pbr/references/verification-overrides.md +39 -0
  324. package/plugins/pbr/references/verification-patterns.md +529 -113
  325. package/plugins/pbr/scripts/architecture-guard.js +76 -0
  326. package/plugins/pbr/scripts/audit-checks/behavioral-compliance.js +2098 -0
  327. package/plugins/pbr/scripts/audit-checks/error-analysis.js +989 -0
  328. package/plugins/pbr/scripts/audit-checks/feature-verification.js +723 -0
  329. package/plugins/pbr/scripts/audit-checks/index.js +433 -0
  330. package/plugins/pbr/scripts/audit-checks/infrastructure.js +816 -0
  331. package/plugins/pbr/scripts/audit-checks/quality-metrics.js +455 -0
  332. package/plugins/pbr/scripts/audit-checks/session-quality.js +980 -0
  333. package/plugins/pbr/scripts/audit-checks/si-agent-hook-config-checks.js +396 -0
  334. package/plugins/pbr/scripts/audit-checks/si-cross-cutting-checks.js +272 -0
  335. package/plugins/pbr/scripts/audit-checks/si-skill-checks.js +424 -0
  336. package/plugins/pbr/scripts/audit-checks/workflow-compliance.js +1175 -0
  337. package/plugins/pbr/scripts/audit-dimensions.js +556 -0
  338. package/plugins/pbr/scripts/auto-continue.js +192 -37
  339. package/plugins/pbr/scripts/block-skill-self-read.js +124 -0
  340. package/plugins/pbr/scripts/check-agent-state-write.js +63 -0
  341. package/plugins/pbr/scripts/check-config-change.js +84 -1
  342. package/plugins/pbr/scripts/check-cross-plugin-sync.js +93 -0
  343. package/plugins/pbr/scripts/check-dangerous-commands.js +18 -5
  344. package/plugins/pbr/scripts/check-direct-state-write.js +37 -0
  345. package/plugins/pbr/scripts/check-phase-boundary.js +3 -2
  346. package/plugins/pbr/scripts/check-plan-format.js +153 -354
  347. package/plugins/pbr/scripts/check-read-first.js +345 -0
  348. package/plugins/pbr/scripts/check-roadmap-sync.js +174 -19
  349. package/plugins/pbr/scripts/check-skill-workflow.js +21 -16
  350. package/plugins/pbr/scripts/check-state-sync.js +352 -220
  351. package/plugins/pbr/scripts/check-subagent-output.js +296 -333
  352. package/plugins/pbr/scripts/check-summary-gate.js +5 -15
  353. package/plugins/pbr/scripts/commands/benchmarks.js +195 -0
  354. package/plugins/pbr/scripts/commands/calibrate.js +530 -0
  355. package/plugins/pbr/scripts/commands/config.js +72 -0
  356. package/plugins/pbr/scripts/commands/misc.js +779 -0
  357. package/plugins/pbr/scripts/commands/phase.js +293 -0
  358. package/plugins/pbr/scripts/commands/roadmap.js +75 -0
  359. package/plugins/pbr/scripts/commands/state.js +84 -0
  360. package/plugins/pbr/scripts/commands/stress-test.js +349 -0
  361. package/plugins/pbr/scripts/commands/todo.js +191 -0
  362. package/plugins/pbr/scripts/commands/verify.js +169 -0
  363. package/plugins/pbr/scripts/config-schema.json +1183 -95
  364. package/plugins/pbr/scripts/context-bridge.js +425 -0
  365. package/plugins/pbr/scripts/context-budget-check.js +171 -16
  366. package/plugins/pbr/scripts/context-quality.js +271 -0
  367. package/plugins/pbr/scripts/enforce-context-budget.js +138 -0
  368. package/plugins/pbr/scripts/enforce-pbr-workflow.js +277 -0
  369. package/plugins/pbr/scripts/event-handler.js +137 -87
  370. package/plugins/pbr/scripts/event-logger.js +58 -25
  371. package/plugins/pbr/scripts/feedback-loop.js +155 -0
  372. package/plugins/pbr/scripts/graph-update.js +422 -0
  373. package/plugins/pbr/scripts/hook-logger.js +69 -35
  374. package/plugins/pbr/scripts/hook-server-client.js +361 -0
  375. package/plugins/pbr/scripts/hook-server.js +664 -0
  376. package/plugins/pbr/scripts/hooks-schema.json +12 -5
  377. package/plugins/pbr/scripts/instructions-loaded.js +173 -0
  378. package/plugins/pbr/scripts/intent-router.cjs +147 -0
  379. package/plugins/pbr/scripts/intercept-plan-mode.js +52 -18
  380. package/plugins/pbr/scripts/lib/alternatives.js +203 -0
  381. package/plugins/pbr/scripts/lib/audit.js +65 -0
  382. package/plugins/pbr/scripts/lib/auto-cleanup.js +221 -0
  383. package/plugins/pbr/scripts/lib/auto-verify.js +123 -0
  384. package/plugins/pbr/scripts/lib/benchmark.js +190 -0
  385. package/plugins/pbr/scripts/lib/build.js +719 -0
  386. package/plugins/pbr/scripts/lib/ci-fix-loop.js +228 -0
  387. package/plugins/pbr/scripts/lib/commands.js +483 -0
  388. package/plugins/pbr/scripts/lib/compound.js +222 -0
  389. package/plugins/pbr/scripts/lib/config-cache.js +83 -0
  390. package/plugins/pbr/scripts/lib/config.js +1469 -0
  391. package/plugins/pbr/scripts/lib/context.js +254 -0
  392. package/plugins/pbr/scripts/lib/contextual-help.js +183 -0
  393. package/plugins/pbr/scripts/lib/convention-detector.js +413 -0
  394. package/plugins/pbr/scripts/lib/core.js +1585 -0
  395. package/plugins/pbr/scripts/lib/dashboard-launch.js +364 -0
  396. package/plugins/pbr/scripts/lib/data-hygiene.js +179 -0
  397. package/plugins/pbr/scripts/lib/decision-extraction.js +183 -0
  398. package/plugins/pbr/scripts/lib/decisions.js +194 -0
  399. package/plugins/pbr/scripts/lib/dependency-break.js +147 -0
  400. package/plugins/pbr/scripts/lib/format-validators.js +1049 -0
  401. package/plugins/pbr/scripts/lib/frontmatter.js +302 -0
  402. package/plugins/pbr/scripts/lib/gates/advisories.js +133 -0
  403. package/plugins/pbr/scripts/lib/gates/build-dependency.js +118 -0
  404. package/plugins/pbr/scripts/lib/gates/build-executor.js +106 -0
  405. package/plugins/pbr/scripts/lib/gates/doc-existence.js +46 -0
  406. package/plugins/pbr/scripts/lib/gates/helpers.js +98 -0
  407. package/plugins/pbr/scripts/lib/gates/inline-execution.js +187 -0
  408. package/plugins/pbr/scripts/lib/gates/milestone-complete.js +139 -0
  409. package/plugins/pbr/scripts/lib/gates/milestone-summary.js +121 -0
  410. package/plugins/pbr/scripts/lib/gates/multi-phase-loader.js +149 -0
  411. package/plugins/pbr/scripts/lib/gates/plan-executor.js +36 -0
  412. package/plugins/pbr/scripts/lib/gates/plan-validation.js +115 -0
  413. package/plugins/pbr/scripts/lib/gates/quick-executor.js +78 -0
  414. package/plugins/pbr/scripts/lib/gates/review-planner.js +63 -0
  415. package/plugins/pbr/scripts/lib/gates/review-verifier.js +71 -0
  416. package/plugins/pbr/scripts/lib/gates/rich-agent-context.js +148 -0
  417. package/plugins/pbr/scripts/lib/gates/sprint-preflight.js +30 -0
  418. package/plugins/pbr/scripts/lib/gates/user-confirmation.js +95 -0
  419. package/plugins/pbr/scripts/lib/graph-cli.js +89 -0
  420. package/plugins/pbr/scripts/lib/graph.js +553 -0
  421. package/plugins/pbr/scripts/lib/handoff-validators.js +224 -0
  422. package/plugins/pbr/scripts/lib/health-checks.js +107 -0
  423. package/plugins/pbr/scripts/lib/health-phase06.js +120 -0
  424. package/plugins/pbr/scripts/lib/health.js +132 -0
  425. package/plugins/pbr/scripts/lib/help.js +100 -0
  426. package/plugins/pbr/scripts/lib/history.js +150 -0
  427. package/plugins/pbr/scripts/lib/impact-analysis.js +319 -0
  428. package/plugins/pbr/scripts/lib/incidents.js +190 -0
  429. package/plugins/pbr/scripts/lib/init.js +643 -0
  430. package/plugins/pbr/scripts/lib/insights-parser.js +320 -0
  431. package/plugins/pbr/scripts/lib/intel.js +653 -0
  432. package/plugins/pbr/scripts/lib/learnings.js +511 -0
  433. package/plugins/pbr/scripts/lib/migrate.js +309 -0
  434. package/plugins/pbr/scripts/lib/milestone.js +306 -0
  435. package/plugins/pbr/scripts/lib/msys-path.js +20 -0
  436. package/plugins/pbr/scripts/lib/negative-knowledge.js +194 -0
  437. package/plugins/pbr/scripts/lib/notification-throttle.js +141 -0
  438. package/plugins/pbr/scripts/lib/onboarding-generator.js +288 -0
  439. package/plugins/pbr/scripts/lib/parse-args.js +134 -0
  440. package/plugins/pbr/scripts/lib/pattern-routing.js +55 -0
  441. package/plugins/pbr/scripts/lib/patterns.js +272 -0
  442. package/plugins/pbr/scripts/lib/perf.js +190 -0
  443. package/plugins/pbr/scripts/lib/phase.js +1043 -0
  444. package/plugins/pbr/scripts/lib/pid-lock.js +156 -0
  445. package/plugins/pbr/scripts/lib/post-hoc.js +160 -0
  446. package/plugins/pbr/scripts/lib/pre-commit-checks.js +220 -0
  447. package/plugins/pbr/scripts/lib/pre-research.js +126 -0
  448. package/plugins/pbr/scripts/lib/premature-completion.js +312 -0
  449. package/plugins/pbr/scripts/lib/preview.js +174 -0
  450. package/plugins/pbr/scripts/lib/progress-visualization.js +296 -0
  451. package/plugins/pbr/scripts/lib/quick-init.js +131 -0
  452. package/plugins/pbr/scripts/lib/reference.js +236 -0
  453. package/plugins/pbr/scripts/lib/requirements.js +153 -0
  454. package/plugins/pbr/scripts/lib/resolve-root.js +66 -0
  455. package/plugins/pbr/scripts/lib/reverse-spec.js +259 -0
  456. package/plugins/pbr/scripts/lib/roadmap.js +1089 -0
  457. package/plugins/pbr/scripts/lib/security-scan.js +200 -0
  458. package/plugins/pbr/scripts/lib/session-briefing.js +918 -0
  459. package/plugins/pbr/scripts/lib/skill-section.js +99 -0
  460. package/plugins/pbr/scripts/lib/smart-next-task.js +198 -0
  461. package/plugins/pbr/scripts/lib/snapshot-manager.js +232 -0
  462. package/plugins/pbr/scripts/lib/spec-diff.js +209 -0
  463. package/plugins/pbr/scripts/lib/spec-engine.js +189 -0
  464. package/plugins/pbr/scripts/lib/spot-check.js +539 -0
  465. package/plugins/pbr/scripts/lib/state-queue.js +171 -0
  466. package/plugins/pbr/scripts/lib/state.js +1082 -0
  467. package/plugins/pbr/scripts/lib/status-render.js +511 -0
  468. package/plugins/pbr/scripts/lib/step-verify.js +149 -0
  469. package/plugins/pbr/scripts/lib/subagent-validators.js +1119 -0
  470. package/plugins/pbr/scripts/lib/suggest-next.js +435 -0
  471. package/plugins/pbr/scripts/lib/tech-debt-scanner.js +116 -0
  472. package/plugins/pbr/scripts/lib/templates.js +362 -0
  473. package/plugins/pbr/scripts/lib/test-selection.js +163 -0
  474. package/plugins/pbr/scripts/lib/todo.js +300 -0
  475. package/plugins/pbr/scripts/lib/verify.js +1561 -0
  476. package/plugins/pbr/scripts/log-notification.js +131 -0
  477. package/plugins/pbr/scripts/log-subagent.js +221 -18
  478. package/plugins/pbr/scripts/log-tool-failure.js +60 -5
  479. package/plugins/pbr/scripts/milestone-learnings.js +519 -0
  480. package/plugins/pbr/scripts/package.json +1 -1
  481. package/plugins/pbr/scripts/pbr-tools.js +362 -1247
  482. package/plugins/pbr/scripts/post-bash-triage.js +96 -0
  483. package/plugins/pbr/scripts/post-compact.js +135 -0
  484. package/plugins/pbr/scripts/post-hoc.js +237 -0
  485. package/plugins/pbr/scripts/post-write-dispatch.js +201 -31
  486. package/plugins/pbr/scripts/post-write-quality.js +4 -3
  487. package/plugins/pbr/scripts/pre-bash-dispatch.js +147 -51
  488. package/plugins/pbr/scripts/pre-skill-dispatch.js +114 -0
  489. package/plugins/pbr/scripts/pre-task-dispatch.js +269 -0
  490. package/plugins/pbr/scripts/pre-write-dispatch.js +170 -72
  491. package/plugins/pbr/scripts/progress-tracker.js +121 -324
  492. package/plugins/pbr/scripts/prompt-guard.js +114 -0
  493. package/plugins/pbr/scripts/prompt-routing.js +209 -0
  494. package/plugins/pbr/scripts/quick-status.js +179 -0
  495. package/plugins/pbr/scripts/record-incident.js +37 -0
  496. package/plugins/pbr/scripts/risk-classifier.cjs +123 -0
  497. package/plugins/pbr/scripts/run-hook.js +63 -23
  498. package/plugins/pbr/scripts/session-cleanup.js +428 -29
  499. package/plugins/pbr/scripts/session-tracker.js +124 -0
  500. package/plugins/pbr/scripts/status-line.js +571 -43
  501. package/plugins/pbr/scripts/suggest-compact.js +201 -13
  502. package/plugins/pbr/scripts/sync-context-to-claude.js +100 -0
  503. package/plugins/pbr/scripts/task-completed.js +165 -4
  504. package/plugins/pbr/scripts/test/config.test.js +126 -0
  505. package/plugins/pbr/scripts/test/cross-platform.test.js +120 -0
  506. package/plugins/pbr/scripts/test/fixtures/config.json +20 -0
  507. package/plugins/pbr/scripts/test/fixtures/plan.md +54 -0
  508. package/plugins/pbr/scripts/test/fixtures/project.md +30 -0
  509. package/plugins/pbr/scripts/test/fixtures/roadmap.md +55 -0
  510. package/plugins/pbr/scripts/test/fixtures/state.md +60 -0
  511. package/plugins/pbr/scripts/test/fixtures/summary.md +35 -0
  512. package/plugins/pbr/scripts/test/fixtures.test.js +184 -0
  513. package/plugins/pbr/scripts/test/phase.test.js +142 -0
  514. package/plugins/pbr/scripts/test/roadmap.test.js +96 -0
  515. package/plugins/pbr/scripts/test/state.test.js +155 -0
  516. package/plugins/pbr/scripts/track-context-budget.js +368 -104
  517. package/plugins/pbr/scripts/track-user-gates.js +88 -0
  518. package/plugins/pbr/scripts/trust-tracker.js +193 -0
  519. package/plugins/pbr/scripts/validate-commit.js +51 -19
  520. package/plugins/pbr/scripts/validate-skill-args.js +85 -14
  521. package/plugins/pbr/scripts/validate-task.js +83 -622
  522. package/plugins/pbr/scripts/worktree-create.js +144 -0
  523. package/plugins/pbr/scripts/worktree-remove.js +147 -0
  524. package/plugins/pbr/skills/audit/SKILL.md +195 -24
  525. package/plugins/pbr/skills/audit-fix/SKILL.md +326 -0
  526. package/plugins/pbr/skills/autonomous/SKILL.md +551 -0
  527. package/plugins/pbr/skills/backlog/SKILL.md +56 -0
  528. package/plugins/pbr/skills/begin/SKILL.md +508 -153
  529. package/plugins/pbr/skills/begin/templates/STATE.md.tmpl +1 -2
  530. package/plugins/pbr/skills/begin/templates/config.json.tmpl +419 -36
  531. package/plugins/pbr/skills/begin/templates/researcher-prompt.md.tmpl +28 -0
  532. package/plugins/pbr/skills/begin/templates/roadmap-prompt.md.tmpl +28 -3
  533. package/plugins/pbr/skills/begin/templates/synthesis-prompt.md.tmpl +33 -5
  534. package/plugins/pbr/skills/build/SKILL.md +1180 -357
  535. package/plugins/pbr/skills/build/templates/continuation-prompt.md.tmpl +26 -0
  536. package/plugins/pbr/skills/build/templates/executor-prompt.md.tmpl +77 -0
  537. package/plugins/pbr/skills/build/templates/inline-verifier-prompt.md.tmpl +33 -0
  538. package/plugins/pbr/skills/build/templates/qa-round-context.md.tmpl +16 -0
  539. package/plugins/pbr/skills/config/SKILL.md +112 -9
  540. package/plugins/pbr/skills/continue/SKILL.md +113 -33
  541. package/plugins/pbr/skills/dashboard/SKILL.md +21 -9
  542. package/plugins/pbr/skills/debug/SKILL.md +70 -12
  543. package/plugins/pbr/skills/debug/templates/continuation-prompt.md.tmpl +12 -1
  544. package/plugins/pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +12 -5
  545. package/plugins/pbr/skills/discuss/SKILL.md +205 -24
  546. package/plugins/pbr/skills/discuss/templates/CONTEXT.md.tmpl +21 -1
  547. package/plugins/pbr/skills/do/SKILL.md +119 -24
  548. package/plugins/pbr/skills/explore/SKILL.md +95 -20
  549. package/plugins/pbr/skills/fast/SKILL.md +94 -0
  550. package/plugins/pbr/skills/forensics/SKILL.md +144 -0
  551. package/plugins/pbr/skills/health/SKILL.md +35 -115
  552. package/plugins/pbr/skills/help/SKILL.md +83 -123
  553. package/plugins/pbr/skills/import/SKILL.md +332 -13
  554. package/plugins/pbr/skills/intel/SKILL.md +131 -0
  555. package/plugins/pbr/skills/list-phase-assumptions/SKILL.md +231 -0
  556. package/plugins/pbr/skills/milestone/SKILL.md +383 -274
  557. package/plugins/pbr/skills/milestone/templates/audit-output.md.tmpl +76 -0
  558. package/plugins/pbr/skills/milestone/templates/complete-output.md.tmpl +32 -0
  559. package/plugins/pbr/skills/milestone/templates/edge-cases.md +54 -0
  560. package/plugins/pbr/skills/milestone/templates/gaps-output.md.tmpl +25 -0
  561. package/plugins/pbr/skills/milestone/templates/integration-checker-prompt.md.tmpl +25 -0
  562. package/plugins/pbr/skills/milestone/templates/new-output.md.tmpl +29 -0
  563. package/plugins/pbr/skills/milestone-summary/SKILL.md +86 -0
  564. package/plugins/pbr/skills/note/SKILL.md +20 -4
  565. package/plugins/pbr/skills/pause/SKILL.md +54 -14
  566. package/plugins/pbr/skills/pause/templates/continue-here.md.tmpl +33 -52
  567. package/plugins/pbr/skills/plan/SKILL.md +526 -280
  568. package/plugins/pbr/skills/plan/templates/checker-prompt.md.tmpl +20 -2
  569. package/plugins/pbr/skills/plan/templates/completion-output.md.tmpl +27 -0
  570. package/plugins/pbr/skills/plan/templates/planner-prompt.md.tmpl +43 -1
  571. package/plugins/pbr/skills/plan/templates/revision-prompt.md.tmpl +21 -5
  572. package/plugins/pbr/skills/profile/SKILL.md +185 -0
  573. package/plugins/pbr/skills/profile-user/SKILL.md +227 -0
  574. package/plugins/pbr/skills/quick/SKILL.md +435 -100
  575. package/plugins/pbr/skills/release/SKILL.md +206 -0
  576. package/plugins/pbr/skills/resume/SKILL.md +170 -46
  577. package/plugins/pbr/skills/review/SKILL.md +233 -165
  578. package/plugins/pbr/skills/review/templates/verifier-prompt.md.tmpl +7 -0
  579. package/plugins/pbr/skills/scan/SKILL.md +152 -106
  580. package/plugins/pbr/skills/scan/templates/mapper-prompt.md.tmpl +5 -56
  581. package/plugins/pbr/skills/seed/SKILL.md +87 -0
  582. package/plugins/pbr/skills/session-report/SKILL.md +130 -0
  583. package/plugins/pbr/skills/setup/SKILL.md +150 -202
  584. package/plugins/pbr/skills/shared/agent-context-enrichment.md +21 -0
  585. package/plugins/pbr/skills/shared/agent-type-resolution.md +32 -0
  586. package/plugins/pbr/skills/shared/commit-planning-docs.md +8 -0
  587. package/plugins/pbr/skills/shared/context-budget.md +66 -1
  588. package/plugins/pbr/skills/shared/context-loader-task.md +18 -11
  589. package/plugins/pbr/skills/shared/criterion-writing.md +58 -0
  590. package/plugins/pbr/skills/shared/digest-select.md +2 -2
  591. package/plugins/pbr/skills/shared/domain-probes.md +1 -1
  592. package/plugins/pbr/skills/shared/error-reporting.md +38 -60
  593. package/plugins/pbr/skills/shared/gate-prompts.md +4 -2
  594. package/plugins/pbr/skills/shared/memory-capture.md +48 -0
  595. package/plugins/pbr/skills/shared/phase-argument-parsing.md +4 -4
  596. package/plugins/pbr/skills/shared/revision-loop.md +24 -6
  597. package/plugins/pbr/skills/shared/state-update.md +46 -61
  598. package/plugins/pbr/skills/shared/universal-anti-patterns.md +27 -4
  599. package/plugins/pbr/skills/ship/SKILL.md +155 -0
  600. package/plugins/pbr/skills/stats/SKILL.md +110 -0
  601. package/plugins/pbr/skills/status/SKILL.md +185 -119
  602. package/plugins/pbr/skills/test/SKILL.md +254 -0
  603. package/plugins/pbr/skills/thread/SKILL.md +73 -0
  604. package/plugins/pbr/skills/todo/SKILL.md +28 -72
  605. package/plugins/pbr/skills/ui-phase/SKILL.md +180 -0
  606. package/plugins/pbr/skills/ui-review/SKILL.md +206 -0
  607. package/plugins/pbr/skills/undo/SKILL.md +221 -0
  608. package/plugins/pbr/skills/validate-phase/SKILL.md +362 -0
  609. package/plugins/pbr/templates/CONTEXT.md.tmpl +45 -20
  610. package/plugins/pbr/templates/DISCOVERY.md.tmpl +29 -0
  611. package/plugins/pbr/templates/DISCUSSION-LOG.md.tmpl +49 -0
  612. package/plugins/pbr/templates/HANDOFF.json.tmpl +30 -0
  613. package/plugins/pbr/templates/INTEGRATION-REPORT.md.tmpl +18 -2
  614. package/plugins/pbr/templates/MILESTONE-AUDIT.md.tmpl +44 -0
  615. package/plugins/pbr/templates/PROJECT.md.tmpl +126 -0
  616. package/plugins/pbr/templates/REQUIREMENTS.md.tmpl +96 -0
  617. package/plugins/pbr/templates/RETROSPECTIVE.md.tmpl +43 -0
  618. package/plugins/pbr/templates/ROADMAP.md.tmpl +106 -14
  619. package/plugins/pbr/templates/SUMMARY-complex.md.tmpl +133 -0
  620. package/plugins/pbr/templates/SUMMARY-minimal.md.tmpl +55 -0
  621. package/plugins/pbr/templates/SUMMARY.md.tmpl +21 -0
  622. package/plugins/pbr/templates/UAT.md.tmpl +94 -0
  623. package/plugins/pbr/templates/UI-SPEC.md.tmpl +144 -0
  624. package/plugins/pbr/templates/VALIDATION.md.tmpl +94 -0
  625. package/plugins/pbr/templates/VERIFICATION-DETAIL.md.tmpl +54 -13
  626. package/plugins/pbr/templates/project-CONTEXT.md.tmpl +59 -0
  627. package/plugins/pbr/templates/research-outputs/ARCHITECTURE.md.tmpl +91 -0
  628. package/plugins/pbr/templates/research-outputs/FEATURES.md.tmpl +64 -0
  629. package/plugins/pbr/templates/research-outputs/PITFALLS.md.tmpl +50 -0
  630. package/plugins/pbr/templates/research-outputs/STACK.md.tmpl +63 -0
  631. package/plugins/pbr/templates/research-outputs/SUMMARY.md.tmpl +98 -0
  632. package/scripts/build-hooks.js +61 -0
  633. package/scripts/check-ci.js +100 -0
  634. package/scripts/clean-changelog.js +364 -0
  635. package/scripts/generate-derivatives.js +581 -0
  636. package/scripts/posttest.js +93 -0
  637. package/scripts/release.js +262 -0
  638. package/scripts/run-tests.cjs +29 -0
  639. package/scripts/test-wrapper.js +43 -0
  640. package/dashboard/bin/cli.js +0 -25
  641. package/dashboard/public/css/layout.css +0 -704
  642. package/dashboard/public/css/status-colors.css +0 -98
  643. package/dashboard/public/css/tokens.css +0 -59
  644. package/dashboard/public/js/htmx-title.js +0 -5
  645. package/dashboard/public/js/sidebar-toggle.js +0 -34
  646. package/dashboard/public/js/sse-client.js +0 -100
  647. package/dashboard/public/js/theme-toggle.js +0 -46
  648. package/dashboard/src/app.js +0 -91
  649. package/dashboard/src/middleware/current-phase.js +0 -24
  650. package/dashboard/src/middleware/errorHandler.js +0 -52
  651. package/dashboard/src/middleware/notFoundHandler.js +0 -9
  652. package/dashboard/src/repositories/planning.repository.js +0 -130
  653. package/dashboard/src/routes/events.routes.js +0 -45
  654. package/dashboard/src/routes/index.routes.js +0 -35
  655. package/dashboard/src/routes/pages.routes.js +0 -426
  656. package/dashboard/src/server.js +0 -42
  657. package/dashboard/src/services/analytics.service.js +0 -141
  658. package/dashboard/src/services/dashboard.service.js +0 -309
  659. package/dashboard/src/services/milestone.service.js +0 -222
  660. package/dashboard/src/services/notes.service.js +0 -50
  661. package/dashboard/src/services/phase.service.js +0 -232
  662. package/dashboard/src/services/project.service.js +0 -57
  663. package/dashboard/src/services/roadmap.service.js +0 -258
  664. package/dashboard/src/services/sse.service.js +0 -58
  665. package/dashboard/src/services/todo.service.js +0 -272
  666. package/dashboard/src/services/watcher.service.js +0 -48
  667. package/dashboard/src/utils/cache.js +0 -55
  668. package/dashboard/src/views/analytics.ejs +0 -5
  669. package/dashboard/src/views/coming-soon.ejs +0 -11
  670. package/dashboard/src/views/dependencies.ejs +0 -5
  671. package/dashboard/src/views/error.ejs +0 -20
  672. package/dashboard/src/views/index.ejs +0 -5
  673. package/dashboard/src/views/milestone-detail.ejs +0 -5
  674. package/dashboard/src/views/milestones.ejs +0 -5
  675. package/dashboard/src/views/notes.ejs +0 -5
  676. package/dashboard/src/views/partials/analytics-content.ejs +0 -90
  677. package/dashboard/src/views/partials/breadcrumbs.ejs +0 -14
  678. package/dashboard/src/views/partials/dashboard-content.ejs +0 -84
  679. package/dashboard/src/views/partials/dependencies-content.ejs +0 -48
  680. package/dashboard/src/views/partials/empty-state.ejs +0 -7
  681. package/dashboard/src/views/partials/footer.ejs +0 -3
  682. package/dashboard/src/views/partials/head.ejs +0 -30
  683. package/dashboard/src/views/partials/header.ejs +0 -21
  684. package/dashboard/src/views/partials/layout-bottom.ejs +0 -43
  685. package/dashboard/src/views/partials/layout-top.ejs +0 -16
  686. package/dashboard/src/views/partials/milestone-detail-content.ejs +0 -20
  687. package/dashboard/src/views/partials/milestones-content.ejs +0 -88
  688. package/dashboard/src/views/partials/notes-content.ejs +0 -23
  689. package/dashboard/src/views/partials/phase-content.ejs +0 -193
  690. package/dashboard/src/views/partials/phase-doc-content.ejs +0 -38
  691. package/dashboard/src/views/partials/phases-content.ejs +0 -124
  692. package/dashboard/src/views/partials/roadmap-content.ejs +0 -180
  693. package/dashboard/src/views/partials/sidebar.ejs +0 -99
  694. package/dashboard/src/views/partials/todo-create-content.ejs +0 -54
  695. package/dashboard/src/views/partials/todo-detail-content.ejs +0 -42
  696. package/dashboard/src/views/partials/todos-content.ejs +0 -97
  697. package/dashboard/src/views/phase-detail.ejs +0 -5
  698. package/dashboard/src/views/phase-doc.ejs +0 -5
  699. package/dashboard/src/views/phases.ejs +0 -5
  700. package/dashboard/src/views/roadmap.ejs +0 -5
  701. package/dashboard/src/views/todo-create.ejs +0 -5
  702. package/dashboard/src/views/todo-detail.ejs +0 -5
  703. package/dashboard/src/views/todos.ejs +0 -5
  704. package/plugins/copilot-pbr/CHANGELOG.md +0 -19
  705. package/plugins/copilot-pbr/README.md +0 -139
  706. package/plugins/copilot-pbr/agents/audit.agent.md +0 -113
  707. package/plugins/copilot-pbr/agents/codebase-mapper.agent.md +0 -151
  708. package/plugins/copilot-pbr/agents/debugger.agent.md +0 -184
  709. package/plugins/copilot-pbr/agents/executor.agent.md +0 -269
  710. package/plugins/copilot-pbr/agents/general.agent.md +0 -89
  711. package/plugins/copilot-pbr/agents/integration-checker.agent.md +0 -121
  712. package/plugins/copilot-pbr/agents/plan-checker.agent.md +0 -208
  713. package/plugins/copilot-pbr/agents/planner.agent.md +0 -240
  714. package/plugins/copilot-pbr/agents/researcher.agent.md +0 -188
  715. package/plugins/copilot-pbr/agents/synthesizer.agent.md +0 -126
  716. package/plugins/copilot-pbr/agents/verifier.agent.md +0 -228
  717. package/plugins/copilot-pbr/hooks/hooks.json +0 -258
  718. package/plugins/copilot-pbr/plugin.json +0 -30
  719. package/plugins/copilot-pbr/references/agent-anti-patterns.md +0 -25
  720. package/plugins/copilot-pbr/references/agent-contracts.md +0 -297
  721. package/plugins/copilot-pbr/references/agent-interactions.md +0 -135
  722. package/plugins/copilot-pbr/references/agent-teams.md +0 -55
  723. package/plugins/copilot-pbr/references/checkpoints.md +0 -158
  724. package/plugins/copilot-pbr/references/common-bug-patterns.md +0 -14
  725. package/plugins/copilot-pbr/references/config-reference.md +0 -442
  726. package/plugins/copilot-pbr/references/continuation-format.md +0 -213
  727. package/plugins/copilot-pbr/references/deviation-rules.md +0 -113
  728. package/plugins/copilot-pbr/references/git-integration.md +0 -227
  729. package/plugins/copilot-pbr/references/integration-patterns.md +0 -118
  730. package/plugins/copilot-pbr/references/model-profiles.md +0 -100
  731. package/plugins/copilot-pbr/references/model-selection.md +0 -32
  732. package/plugins/copilot-pbr/references/pbr-rules.md +0 -195
  733. package/plugins/copilot-pbr/references/pbr-tools-cli.md +0 -285
  734. package/plugins/copilot-pbr/references/plan-authoring.md +0 -182
  735. package/plugins/copilot-pbr/references/plan-format.md +0 -288
  736. package/plugins/copilot-pbr/references/planning-config.md +0 -214
  737. package/plugins/copilot-pbr/references/questioning.md +0 -215
  738. package/plugins/copilot-pbr/references/reading-verification.md +0 -128
  739. package/plugins/copilot-pbr/references/stub-patterns.md +0 -161
  740. package/plugins/copilot-pbr/references/subagent-coordination.md +0 -120
  741. package/plugins/copilot-pbr/references/ui-formatting.md +0 -444
  742. package/plugins/copilot-pbr/references/verification-patterns.md +0 -199
  743. package/plugins/copilot-pbr/references/wave-execution.md +0 -96
  744. package/plugins/copilot-pbr/rules/pbr-workflow.mdc +0 -48
  745. package/plugins/copilot-pbr/setup.ps1 +0 -93
  746. package/plugins/copilot-pbr/setup.sh +0 -93
  747. package/plugins/copilot-pbr/skills/audit/SKILL.md +0 -330
  748. package/plugins/copilot-pbr/skills/begin/SKILL.md +0 -589
  749. package/plugins/copilot-pbr/skills/begin/templates/PROJECT.md.tmpl +0 -34
  750. package/plugins/copilot-pbr/skills/begin/templates/REQUIREMENTS.md.tmpl +0 -19
  751. package/plugins/copilot-pbr/skills/begin/templates/STATE.md.tmpl +0 -50
  752. package/plugins/copilot-pbr/skills/begin/templates/config.json.tmpl +0 -64
  753. package/plugins/copilot-pbr/skills/begin/templates/researcher-prompt.md.tmpl +0 -20
  754. package/plugins/copilot-pbr/skills/begin/templates/roadmap-prompt.md.tmpl +0 -31
  755. package/plugins/copilot-pbr/skills/begin/templates/synthesis-prompt.md.tmpl +0 -17
  756. package/plugins/copilot-pbr/skills/build/SKILL.md +0 -959
  757. package/plugins/copilot-pbr/skills/config/SKILL.md +0 -250
  758. package/plugins/copilot-pbr/skills/continue/SKILL.md +0 -159
  759. package/plugins/copilot-pbr/skills/dashboard/SKILL.md +0 -43
  760. package/plugins/copilot-pbr/skills/debug/SKILL.md +0 -508
  761. package/plugins/copilot-pbr/skills/debug/templates/continuation-prompt.md.tmpl +0 -17
  762. package/plugins/copilot-pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +0 -28
  763. package/plugins/copilot-pbr/skills/discuss/SKILL.md +0 -353
  764. package/plugins/copilot-pbr/skills/discuss/templates/CONTEXT.md.tmpl +0 -62
  765. package/plugins/copilot-pbr/skills/discuss/templates/decision-categories.md +0 -10
  766. package/plugins/copilot-pbr/skills/do/SKILL.md +0 -66
  767. package/plugins/copilot-pbr/skills/explore/SKILL.md +0 -373
  768. package/plugins/copilot-pbr/skills/health/SKILL.md +0 -283
  769. package/plugins/copilot-pbr/skills/health/templates/check-pattern.md.tmpl +0 -31
  770. package/plugins/copilot-pbr/skills/health/templates/output-format.md.tmpl +0 -64
  771. package/plugins/copilot-pbr/skills/help/SKILL.md +0 -193
  772. package/plugins/copilot-pbr/skills/import/SKILL.md +0 -502
  773. package/plugins/copilot-pbr/skills/milestone/SKILL.md +0 -806
  774. package/plugins/copilot-pbr/skills/milestone/templates/audit-report.md.tmpl +0 -49
  775. package/plugins/copilot-pbr/skills/milestone/templates/stats-file.md.tmpl +0 -31
  776. package/plugins/copilot-pbr/skills/note/SKILL.md +0 -213
  777. package/plugins/copilot-pbr/skills/pause/SKILL.md +0 -247
  778. package/plugins/copilot-pbr/skills/pause/templates/continue-here.md.tmpl +0 -72
  779. package/plugins/copilot-pbr/skills/plan/SKILL.md +0 -662
  780. package/plugins/copilot-pbr/skills/plan/templates/checker-prompt.md.tmpl +0 -22
  781. package/plugins/copilot-pbr/skills/plan/templates/gap-closure-prompt.md.tmpl +0 -33
  782. package/plugins/copilot-pbr/skills/plan/templates/planner-prompt.md.tmpl +0 -39
  783. package/plugins/copilot-pbr/skills/plan/templates/researcher-prompt.md.tmpl +0 -20
  784. package/plugins/copilot-pbr/skills/plan/templates/revision-prompt.md.tmpl +0 -24
  785. package/plugins/copilot-pbr/skills/quick/SKILL.md +0 -376
  786. package/plugins/copilot-pbr/skills/resume/SKILL.md +0 -399
  787. package/plugins/copilot-pbr/skills/review/SKILL.md +0 -653
  788. package/plugins/copilot-pbr/skills/review/templates/debugger-prompt.md.tmpl +0 -61
  789. package/plugins/copilot-pbr/skills/review/templates/gap-planner-prompt.md.tmpl +0 -41
  790. package/plugins/copilot-pbr/skills/review/templates/verifier-prompt.md.tmpl +0 -116
  791. package/plugins/copilot-pbr/skills/scan/SKILL.md +0 -299
  792. package/plugins/copilot-pbr/skills/scan/templates/mapper-prompt.md.tmpl +0 -202
  793. package/plugins/copilot-pbr/skills/setup/SKILL.md +0 -296
  794. package/plugins/copilot-pbr/skills/shared/commit-planning-docs.md +0 -36
  795. package/plugins/copilot-pbr/skills/shared/config-loading.md +0 -103
  796. package/plugins/copilot-pbr/skills/shared/context-budget.md +0 -41
  797. package/plugins/copilot-pbr/skills/shared/context-loader-task.md +0 -87
  798. package/plugins/copilot-pbr/skills/shared/digest-select.md +0 -80
  799. package/plugins/copilot-pbr/skills/shared/domain-probes.md +0 -126
  800. package/plugins/copilot-pbr/skills/shared/error-recovery-strategies.md +0 -51
  801. package/plugins/copilot-pbr/skills/shared/error-reporting.md +0 -81
  802. package/plugins/copilot-pbr/skills/shared/gate-prompts.md +0 -389
  803. package/plugins/copilot-pbr/skills/shared/phase-argument-parsing.md +0 -46
  804. package/plugins/copilot-pbr/skills/shared/progress-display.md +0 -53
  805. package/plugins/copilot-pbr/skills/shared/revision-loop.md +0 -82
  806. package/plugins/copilot-pbr/skills/shared/state-loading.md +0 -63
  807. package/plugins/copilot-pbr/skills/shared/state-update.md +0 -170
  808. package/plugins/copilot-pbr/skills/shared/universal-anti-patterns.md +0 -38
  809. package/plugins/copilot-pbr/skills/status/SKILL.md +0 -362
  810. package/plugins/copilot-pbr/skills/statusline/SKILL.md +0 -149
  811. package/plugins/copilot-pbr/skills/todo/SKILL.md +0 -279
  812. package/plugins/copilot-pbr/templates/CONTEXT.md.tmpl +0 -53
  813. package/plugins/copilot-pbr/templates/INTEGRATION-REPORT.md.tmpl +0 -152
  814. package/plugins/copilot-pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -98
  815. package/plugins/copilot-pbr/templates/ROADMAP.md.tmpl +0 -48
  816. package/plugins/copilot-pbr/templates/SUMMARY.md.tmpl +0 -82
  817. package/plugins/copilot-pbr/templates/VERIFICATION-DETAIL.md.tmpl +0 -117
  818. package/plugins/copilot-pbr/templates/codebase/ARCHITECTURE.md.tmpl +0 -98
  819. package/plugins/copilot-pbr/templates/codebase/CONCERNS.md.tmpl +0 -93
  820. package/plugins/copilot-pbr/templates/codebase/CONVENTIONS.md.tmpl +0 -104
  821. package/plugins/copilot-pbr/templates/codebase/INTEGRATIONS.md.tmpl +0 -78
  822. package/plugins/copilot-pbr/templates/codebase/STACK.md.tmpl +0 -78
  823. package/plugins/copilot-pbr/templates/codebase/STRUCTURE.md.tmpl +0 -80
  824. package/plugins/copilot-pbr/templates/codebase/TESTING.md.tmpl +0 -107
  825. package/plugins/copilot-pbr/templates/continue-here.md.tmpl +0 -74
  826. package/plugins/copilot-pbr/templates/prompt-partials/phase-project-context.md.tmpl +0 -38
  827. package/plugins/copilot-pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
  828. package/plugins/copilot-pbr/templates/research/STACK.md.tmpl +0 -71
  829. package/plugins/copilot-pbr/templates/research/SUMMARY.md.tmpl +0 -112
  830. package/plugins/copilot-pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
  831. package/plugins/copilot-pbr/templates/research-outputs/project-research.md.tmpl +0 -99
  832. package/plugins/copilot-pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
  833. package/plugins/cursor-pbr/.cursor-plugin/plugin.json +0 -32
  834. package/plugins/cursor-pbr/CHANGELOG.md +0 -15
  835. package/plugins/cursor-pbr/README.md +0 -123
  836. package/plugins/cursor-pbr/agents/audit.md +0 -178
  837. package/plugins/cursor-pbr/agents/codebase-mapper.md +0 -150
  838. package/plugins/cursor-pbr/agents/debugger.md +0 -183
  839. package/plugins/cursor-pbr/agents/executor.md +0 -268
  840. package/plugins/cursor-pbr/agents/general.md +0 -88
  841. package/plugins/cursor-pbr/agents/integration-checker.md +0 -120
  842. package/plugins/cursor-pbr/agents/plan-checker.md +0 -207
  843. package/plugins/cursor-pbr/agents/planner.md +0 -239
  844. package/plugins/cursor-pbr/agents/researcher.md +0 -187
  845. package/plugins/cursor-pbr/agents/synthesizer.md +0 -125
  846. package/plugins/cursor-pbr/agents/verifier.md +0 -227
  847. package/plugins/cursor-pbr/assets/.gitkeep +0 -0
  848. package/plugins/cursor-pbr/assets/logo.svg +0 -21
  849. package/plugins/cursor-pbr/hooks/hooks.json +0 -224
  850. package/plugins/cursor-pbr/references/agent-anti-patterns.md +0 -25
  851. package/plugins/cursor-pbr/references/agent-contracts.md +0 -297
  852. package/plugins/cursor-pbr/references/agent-interactions.md +0 -135
  853. package/plugins/cursor-pbr/references/agent-teams.md +0 -55
  854. package/plugins/cursor-pbr/references/checkpoints.md +0 -158
  855. package/plugins/cursor-pbr/references/common-bug-patterns.md +0 -14
  856. package/plugins/cursor-pbr/references/config-reference.md +0 -442
  857. package/plugins/cursor-pbr/references/continuation-format.md +0 -213
  858. package/plugins/cursor-pbr/references/deviation-rules.md +0 -113
  859. package/plugins/cursor-pbr/references/git-integration.md +0 -227
  860. package/plugins/cursor-pbr/references/integration-patterns.md +0 -118
  861. package/plugins/cursor-pbr/references/model-profiles.md +0 -100
  862. package/plugins/cursor-pbr/references/model-selection.md +0 -32
  863. package/plugins/cursor-pbr/references/pbr-rules.md +0 -195
  864. package/plugins/cursor-pbr/references/pbr-tools-cli.md +0 -285
  865. package/plugins/cursor-pbr/references/plan-authoring.md +0 -182
  866. package/plugins/cursor-pbr/references/plan-format.md +0 -288
  867. package/plugins/cursor-pbr/references/planning-config.md +0 -214
  868. package/plugins/cursor-pbr/references/questioning.md +0 -215
  869. package/plugins/cursor-pbr/references/reading-verification.md +0 -128
  870. package/plugins/cursor-pbr/references/stub-patterns.md +0 -161
  871. package/plugins/cursor-pbr/references/subagent-coordination.md +0 -120
  872. package/plugins/cursor-pbr/references/ui-formatting.md +0 -444
  873. package/plugins/cursor-pbr/references/verification-patterns.md +0 -199
  874. package/plugins/cursor-pbr/references/wave-execution.md +0 -96
  875. package/plugins/cursor-pbr/rules/pbr-workflow.mdc +0 -48
  876. package/plugins/cursor-pbr/setup.ps1 +0 -78
  877. package/plugins/cursor-pbr/setup.sh +0 -83
  878. package/plugins/cursor-pbr/skills/audit/SKILL.md +0 -331
  879. package/plugins/cursor-pbr/skills/begin/SKILL.md +0 -589
  880. package/plugins/cursor-pbr/skills/begin/templates/PROJECT.md.tmpl +0 -34
  881. package/plugins/cursor-pbr/skills/begin/templates/REQUIREMENTS.md.tmpl +0 -19
  882. package/plugins/cursor-pbr/skills/begin/templates/STATE.md.tmpl +0 -50
  883. package/plugins/cursor-pbr/skills/begin/templates/config.json.tmpl +0 -64
  884. package/plugins/cursor-pbr/skills/begin/templates/researcher-prompt.md.tmpl +0 -20
  885. package/plugins/cursor-pbr/skills/begin/templates/roadmap-prompt.md.tmpl +0 -31
  886. package/plugins/cursor-pbr/skills/begin/templates/synthesis-prompt.md.tmpl +0 -17
  887. package/plugins/cursor-pbr/skills/build/SKILL.md +0 -960
  888. package/plugins/cursor-pbr/skills/config/SKILL.md +0 -252
  889. package/plugins/cursor-pbr/skills/continue/SKILL.md +0 -159
  890. package/plugins/cursor-pbr/skills/dashboard/SKILL.md +0 -44
  891. package/plugins/cursor-pbr/skills/debug/SKILL.md +0 -512
  892. package/plugins/cursor-pbr/skills/debug/templates/continuation-prompt.md.tmpl +0 -17
  893. package/plugins/cursor-pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +0 -28
  894. package/plugins/cursor-pbr/skills/discuss/SKILL.md +0 -354
  895. package/plugins/cursor-pbr/skills/discuss/templates/CONTEXT.md.tmpl +0 -62
  896. package/plugins/cursor-pbr/skills/discuss/templates/decision-categories.md +0 -10
  897. package/plugins/cursor-pbr/skills/do/SKILL.md +0 -67
  898. package/plugins/cursor-pbr/skills/explore/SKILL.md +0 -376
  899. package/plugins/cursor-pbr/skills/health/SKILL.md +0 -283
  900. package/plugins/cursor-pbr/skills/health/templates/check-pattern.md.tmpl +0 -31
  901. package/plugins/cursor-pbr/skills/health/templates/output-format.md.tmpl +0 -64
  902. package/plugins/cursor-pbr/skills/help/SKILL.md +0 -193
  903. package/plugins/cursor-pbr/skills/import/SKILL.md +0 -505
  904. package/plugins/cursor-pbr/skills/milestone/SKILL.md +0 -807
  905. package/plugins/cursor-pbr/skills/milestone/templates/audit-report.md.tmpl +0 -49
  906. package/plugins/cursor-pbr/skills/milestone/templates/stats-file.md.tmpl +0 -31
  907. package/plugins/cursor-pbr/skills/note/SKILL.md +0 -214
  908. package/plugins/cursor-pbr/skills/pause/SKILL.md +0 -248
  909. package/plugins/cursor-pbr/skills/pause/templates/continue-here.md.tmpl +0 -72
  910. package/plugins/cursor-pbr/skills/plan/SKILL.md +0 -663
  911. package/plugins/cursor-pbr/skills/plan/templates/checker-prompt.md.tmpl +0 -22
  912. package/plugins/cursor-pbr/skills/plan/templates/gap-closure-prompt.md.tmpl +0 -33
  913. package/plugins/cursor-pbr/skills/plan/templates/planner-prompt.md.tmpl +0 -39
  914. package/plugins/cursor-pbr/skills/plan/templates/researcher-prompt.md.tmpl +0 -20
  915. package/plugins/cursor-pbr/skills/plan/templates/revision-prompt.md.tmpl +0 -24
  916. package/plugins/cursor-pbr/skills/quick/SKILL.md +0 -376
  917. package/plugins/cursor-pbr/skills/resume/SKILL.md +0 -399
  918. package/plugins/cursor-pbr/skills/review/SKILL.md +0 -654
  919. package/plugins/cursor-pbr/skills/review/templates/debugger-prompt.md.tmpl +0 -61
  920. package/plugins/cursor-pbr/skills/review/templates/gap-planner-prompt.md.tmpl +0 -41
  921. package/plugins/cursor-pbr/skills/review/templates/verifier-prompt.md.tmpl +0 -116
  922. package/plugins/cursor-pbr/skills/scan/SKILL.md +0 -300
  923. package/plugins/cursor-pbr/skills/scan/templates/mapper-prompt.md.tmpl +0 -202
  924. package/plugins/cursor-pbr/skills/setup/SKILL.md +0 -296
  925. package/plugins/cursor-pbr/skills/shared/commit-planning-docs.md +0 -36
  926. package/plugins/cursor-pbr/skills/shared/config-loading.md +0 -103
  927. package/plugins/cursor-pbr/skills/shared/context-budget.md +0 -41
  928. package/plugins/cursor-pbr/skills/shared/context-loader-task.md +0 -87
  929. package/plugins/cursor-pbr/skills/shared/digest-select.md +0 -80
  930. package/plugins/cursor-pbr/skills/shared/domain-probes.md +0 -126
  931. package/plugins/cursor-pbr/skills/shared/error-recovery-strategies.md +0 -51
  932. package/plugins/cursor-pbr/skills/shared/error-reporting.md +0 -81
  933. package/plugins/cursor-pbr/skills/shared/gate-prompts.md +0 -389
  934. package/plugins/cursor-pbr/skills/shared/phase-argument-parsing.md +0 -46
  935. package/plugins/cursor-pbr/skills/shared/progress-display.md +0 -53
  936. package/plugins/cursor-pbr/skills/shared/revision-loop.md +0 -82
  937. package/plugins/cursor-pbr/skills/shared/state-loading.md +0 -63
  938. package/plugins/cursor-pbr/skills/shared/state-update.md +0 -170
  939. package/plugins/cursor-pbr/skills/shared/universal-anti-patterns.md +0 -38
  940. package/plugins/cursor-pbr/skills/status/SKILL.md +0 -362
  941. package/plugins/cursor-pbr/skills/statusline/SKILL.md +0 -150
  942. package/plugins/cursor-pbr/skills/todo/SKILL.md +0 -280
  943. package/plugins/cursor-pbr/templates/CONTEXT.md.tmpl +0 -53
  944. package/plugins/cursor-pbr/templates/INTEGRATION-REPORT.md.tmpl +0 -152
  945. package/plugins/cursor-pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -98
  946. package/plugins/cursor-pbr/templates/ROADMAP.md.tmpl +0 -48
  947. package/plugins/cursor-pbr/templates/SUMMARY.md.tmpl +0 -82
  948. package/plugins/cursor-pbr/templates/VERIFICATION-DETAIL.md.tmpl +0 -117
  949. package/plugins/cursor-pbr/templates/codebase/ARCHITECTURE.md.tmpl +0 -98
  950. package/plugins/cursor-pbr/templates/codebase/CONCERNS.md.tmpl +0 -93
  951. package/plugins/cursor-pbr/templates/codebase/CONVENTIONS.md.tmpl +0 -104
  952. package/plugins/cursor-pbr/templates/codebase/INTEGRATIONS.md.tmpl +0 -78
  953. package/plugins/cursor-pbr/templates/codebase/STACK.md.tmpl +0 -78
  954. package/plugins/cursor-pbr/templates/codebase/STRUCTURE.md.tmpl +0 -80
  955. package/plugins/cursor-pbr/templates/codebase/TESTING.md.tmpl +0 -107
  956. package/plugins/cursor-pbr/templates/continue-here.md.tmpl +0 -74
  957. package/plugins/cursor-pbr/templates/prompt-partials/phase-project-context.md.tmpl +0 -38
  958. package/plugins/cursor-pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
  959. package/plugins/cursor-pbr/templates/research/STACK.md.tmpl +0 -71
  960. package/plugins/cursor-pbr/templates/research/SUMMARY.md.tmpl +0 -112
  961. package/plugins/cursor-pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
  962. package/plugins/cursor-pbr/templates/research-outputs/project-research.md.tmpl +0 -99
  963. package/plugins/cursor-pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
  964. package/plugins/pbr/references/agent-interactions.md +0 -134
  965. package/plugins/pbr/references/pbr-rules.md +0 -194
  966. package/plugins/pbr/references/pbr-tools-cli.md +0 -285
  967. package/plugins/pbr/references/planning-config.md +0 -213
  968. package/plugins/pbr/references/subagent-coordination.md +0 -119
  969. package/plugins/pbr/references/ui-formatting.md +0 -444
  970. package/plugins/pbr/scripts/validate-plugin-structure.js +0 -183
  971. package/plugins/pbr/skills/milestone/templates/audit-report.md.tmpl +0 -48
  972. package/plugins/pbr/skills/shared/error-recovery-strategies.md +0 -51
  973. package/plugins/pbr/skills/shared/progress-display.md +0 -53
  974. package/plugins/pbr/skills/shared/state-loading.md +0 -62
  975. package/plugins/pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -97
  976. package/plugins/pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
  977. package/plugins/pbr/templates/research/STACK.md.tmpl +0 -71
  978. package/plugins/pbr/templates/research/SUMMARY.md.tmpl +0 -112
  979. package/plugins/pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
  980. package/plugins/pbr/templates/research-outputs/project-research.md.tmpl +0 -99
  981. package/plugins/pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
  982. /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
+ };