@sienklogic/plan-build-run 2.11.0 → 2.12.1

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 (1222) hide show
  1. package/CHANGELOG.md +1102 -220
  2. package/CLAUDE.md +54 -34
  3. package/LICENSE +2 -1
  4. package/README.md +261 -182
  5. package/agents/pbr-audit.md +266 -0
  6. package/agents/pbr-codebase-mapper.md +236 -0
  7. package/agents/pbr-debugger.md +312 -0
  8. package/agents/pbr-dev-sync.md +220 -0
  9. package/agents/pbr-executor.md +591 -0
  10. package/agents/pbr-general.md +191 -0
  11. package/agents/pbr-integration-checker.md +237 -0
  12. package/agents/pbr-intel-updater.md +296 -0
  13. package/agents/pbr-nyquist-auditor.md +252 -0
  14. package/agents/pbr-plan-checker.md +312 -0
  15. package/agents/pbr-planner.md +539 -0
  16. package/agents/pbr-researcher.md +314 -0
  17. package/agents/pbr-roadmapper.md +346 -0
  18. package/agents/pbr-synthesizer.md +271 -0
  19. package/agents/pbr-ui-checker.md +202 -0
  20. package/agents/pbr-ui-researcher.md +223 -0
  21. package/agents/pbr-verifier.md +495 -0
  22. package/bin/install.js +2752 -0
  23. package/commands/pbr/add-phase.md +75 -0
  24. package/commands/pbr/add-todo.md +8 -0
  25. package/commands/pbr/audit-milestone.md +8 -0
  26. package/commands/pbr/audit.md +5 -0
  27. package/commands/pbr/autonomous.md +5 -0
  28. package/commands/pbr/begin.md +5 -0
  29. package/commands/pbr/build.md +5 -0
  30. package/commands/pbr/check-todos.md +8 -0
  31. package/commands/pbr/complete-milestone.md +8 -0
  32. package/commands/pbr/config.md +5 -0
  33. package/commands/pbr/continue.md +5 -0
  34. package/commands/pbr/dashboard.md +5 -0
  35. package/commands/pbr/debug.md +5 -0
  36. package/commands/pbr/discuss-phase.md +6 -0
  37. package/commands/pbr/discuss.md +5 -0
  38. package/commands/pbr/do.md +5 -0
  39. package/commands/pbr/execute-phase.md +6 -0
  40. package/commands/pbr/explore.md +5 -0
  41. package/commands/pbr/health.md +5 -0
  42. package/commands/pbr/help.md +5 -0
  43. package/commands/pbr/import.md +5 -0
  44. package/commands/pbr/insert-phase.md +65 -0
  45. package/commands/pbr/intel.md +5 -0
  46. package/commands/pbr/join-discord.md +11 -0
  47. package/commands/pbr/list-phase-assumptions.md +69 -0
  48. package/commands/pbr/map-codebase.md +6 -0
  49. package/commands/pbr/milestone.md +5 -0
  50. package/commands/pbr/new-milestone.md +8 -0
  51. package/commands/pbr/new-project.md +6 -0
  52. package/commands/pbr/note.md +5 -0
  53. package/commands/pbr/pause-work.md +5 -0
  54. package/commands/pbr/pause.md +5 -0
  55. package/commands/pbr/plan-milestone-gaps.md +7 -0
  56. package/commands/pbr/plan-phase.md +6 -0
  57. package/commands/pbr/plan.md +5 -0
  58. package/commands/pbr/profile-user.md +5 -0
  59. package/commands/pbr/profile.md +5 -0
  60. package/commands/pbr/progress.md +6 -0
  61. package/commands/pbr/quick.md +5 -0
  62. package/commands/pbr/reapply-patches.md +47 -0
  63. package/commands/pbr/release.md +6 -0
  64. package/commands/pbr/remove-phase.md +66 -0
  65. package/commands/pbr/research-phase.md +59 -0
  66. package/commands/pbr/resume-work.md +5 -0
  67. package/commands/pbr/resume.md +5 -0
  68. package/commands/pbr/review.md +5 -0
  69. package/commands/pbr/scan.md +5 -0
  70. package/commands/pbr/session-report.md +5 -0
  71. package/commands/pbr/set-profile.md +6 -0
  72. package/commands/pbr/settings.md +5 -0
  73. package/commands/pbr/setup.md +5 -0
  74. package/commands/pbr/ship.md +5 -0
  75. package/commands/pbr/status.md +5 -0
  76. package/commands/pbr/statusline.md +5 -0
  77. package/commands/pbr/test.md +5 -0
  78. package/commands/pbr/todo.md +5 -0
  79. package/commands/pbr/ui-phase.md +5 -0
  80. package/commands/pbr/ui-review.md +5 -0
  81. package/commands/pbr/undo.md +5 -0
  82. package/commands/pbr/update.md +37 -0
  83. package/commands/pbr/validate-phase.md +5 -0
  84. package/commands/pbr/verify-work.md +6 -0
  85. package/dashboard/bin/cli.cjs +96 -0
  86. package/dashboard/bin/stop.cjs +129 -0
  87. package/dashboard/eslint.config.js +37 -0
  88. package/dashboard/index.html +20 -0
  89. package/dashboard/package.json +28 -23
  90. package/dashboard/server/index.js +136 -0
  91. package/dashboard/server/lib/frontmatter.js +92 -0
  92. package/dashboard/server/middleware/static.js +35 -0
  93. package/dashboard/server/package.json +16 -0
  94. package/dashboard/server/routes/agents.js +213 -0
  95. package/dashboard/server/routes/config.js +64 -0
  96. package/dashboard/server/routes/health.js +95 -0
  97. package/dashboard/server/routes/memory.js +107 -0
  98. package/dashboard/server/routes/planning.js +234 -0
  99. package/dashboard/server/routes/progress.js +77 -0
  100. package/dashboard/server/routes/projects.js +36 -0
  101. package/dashboard/server/routes/requirements.js +40 -0
  102. package/dashboard/server/routes/roadmap.js +69 -0
  103. package/dashboard/server/routes/status.js +25 -0
  104. package/dashboard/server/routes/telemetry.js +171 -0
  105. package/dashboard/server/services/file-watcher.js +105 -0
  106. package/dashboard/server/services/planning-reader.js +741 -0
  107. package/dashboard/server/test/cli.test.js +34 -0
  108. package/dashboard/server/test/frontmatter.test.js +104 -0
  109. package/dashboard/server/test/isolation.test.js +32 -0
  110. package/dashboard/server/test/planning-reader.test.js +151 -0
  111. package/dashboard/server/test/routes.test.js +91 -0
  112. package/dashboard/server/test/ws.test.js +81 -0
  113. package/dashboard/server/ws.js +96 -0
  114. package/dashboard/src/App.jsx +154 -0
  115. package/dashboard/src/components/charts/BudgetBars.jsx +42 -0
  116. package/dashboard/src/components/charts/ContextRadar.jsx +34 -0
  117. package/dashboard/src/components/charts/PhaseDonut.jsx +66 -0
  118. package/dashboard/src/components/charts/SuccessTrend.jsx +45 -0
  119. package/dashboard/src/components/charts/TokenChart.jsx +55 -0
  120. package/dashboard/src/components/charts/index.js +5 -0
  121. package/dashboard/src/components/config/CfgSection.jsx +93 -0
  122. package/dashboard/src/components/layout/Header.jsx +89 -0
  123. package/dashboard/src/components/layout/ProjectSwitcher.jsx +160 -0
  124. package/dashboard/src/components/layout/Sidebar.jsx +161 -0
  125. package/dashboard/src/components/ui/AutoModeBanner.jsx +138 -0
  126. package/dashboard/src/components/ui/BackButton.jsx +27 -0
  127. package/dashboard/src/components/ui/Badge.jsx +27 -0
  128. package/dashboard/src/components/ui/Card.jsx +23 -0
  129. package/dashboard/src/components/ui/ChartTooltip.jsx +48 -0
  130. package/dashboard/src/components/ui/CheckpointBox.jsx +110 -0
  131. package/dashboard/src/components/ui/CodeBlock.jsx +27 -0
  132. package/dashboard/src/components/ui/ConfidenceBadge.jsx +20 -0
  133. package/dashboard/src/components/ui/ConfirmModal.jsx +161 -0
  134. package/dashboard/src/components/ui/ConnectionBanner.jsx +60 -0
  135. package/dashboard/src/components/ui/ErrorBoundary.jsx +106 -0
  136. package/dashboard/src/components/ui/ErrorBox.jsx +107 -0
  137. package/dashboard/src/components/ui/KeyValue.jsx +33 -0
  138. package/dashboard/src/components/ui/LoadingSkeleton.jsx +84 -0
  139. package/dashboard/src/components/ui/MetricCard.jsx +58 -0
  140. package/dashboard/src/components/ui/NextUpBlock.jsx +92 -0
  141. package/dashboard/src/components/ui/NumberInput.jsx +44 -0
  142. package/dashboard/src/components/ui/PBRBanner.jsx +47 -0
  143. package/dashboard/src/components/ui/PipelineView.jsx +130 -0
  144. package/dashboard/src/components/ui/ProgressBar.jsx +28 -0
  145. package/dashboard/src/components/ui/ProgressDisplay.jsx +47 -0
  146. package/dashboard/src/components/ui/QualityGateBadge.jsx +15 -0
  147. package/dashboard/src/components/ui/SectionTitle.jsx +35 -0
  148. package/dashboard/src/components/ui/SelectInput.jsx +45 -0
  149. package/dashboard/src/components/ui/StatusDot.jsx +51 -0
  150. package/dashboard/src/components/ui/StatusSymbol.jsx +49 -0
  151. package/dashboard/src/components/ui/TabBar.jsx +41 -0
  152. package/dashboard/src/components/ui/TextInput.jsx +42 -0
  153. package/dashboard/src/components/ui/Toast.jsx +117 -0
  154. package/dashboard/src/components/ui/Toggle.jsx +70 -0
  155. package/dashboard/src/components/ui/index.js +29 -0
  156. package/dashboard/src/hooks/useDocumentTitle.js +16 -0
  157. package/dashboard/src/hooks/useFetch.js +50 -0
  158. package/dashboard/src/hooks/useToast.jsx +43 -0
  159. package/dashboard/src/hooks/useWebSocket.js +103 -0
  160. package/dashboard/src/lib/api.js +112 -0
  161. package/dashboard/src/lib/configSchema.js +189 -0
  162. package/dashboard/src/lib/constants.js +18 -0
  163. package/dashboard/src/main.jsx +15 -0
  164. package/dashboard/src/pages/AgentsPage.jsx +191 -0
  165. package/dashboard/src/pages/ConfigPage.jsx +298 -0
  166. package/dashboard/src/pages/HooksPage.jsx +412 -0
  167. package/dashboard/src/pages/LiveFeed.jsx +274 -0
  168. package/dashboard/src/pages/MemoryPage.jsx +107 -0
  169. package/dashboard/src/pages/OnboardingPage.jsx +117 -0
  170. package/dashboard/src/pages/Overview.jsx +360 -0
  171. package/dashboard/src/pages/PhaseDetailView.jsx +216 -0
  172. package/dashboard/src/pages/PlanningPage.jsx +181 -0
  173. package/dashboard/src/pages/ProgressPage.jsx +249 -0
  174. package/dashboard/src/pages/RoadmapPage.jsx +251 -0
  175. package/dashboard/src/pages/Telemetry.jsx +113 -0
  176. package/dashboard/src/pages/planning/DecisionsTab.jsx +153 -0
  177. package/dashboard/src/pages/planning/FilesTab.jsx +420 -0
  178. package/dashboard/src/pages/planning/MilestoneDetail.jsx +319 -0
  179. package/dashboard/src/pages/planning/MilestonesTab.jsx +151 -0
  180. package/dashboard/src/pages/planning/NotesTab.jsx +251 -0
  181. package/dashboard/src/pages/planning/PhasesTab.jsx +218 -0
  182. package/dashboard/src/pages/planning/QuickTab.jsx +50 -0
  183. package/dashboard/src/pages/planning/ResearchTab.jsx +103 -0
  184. package/dashboard/src/pages/planning/TodosTab.jsx +297 -0
  185. package/dashboard/src/theme/ThemeProvider.jsx +38 -0
  186. package/dashboard/src/theme/tokens.js +17 -0
  187. package/dashboard/tests/components/ConfirmModal.test.jsx +179 -0
  188. package/dashboard/tests/components/ConnectionBanner.test.jsx +37 -0
  189. package/dashboard/tests/components/ErrorBoundary.test.jsx +59 -0
  190. package/dashboard/tests/components/LoadingSkeleton.test.jsx +46 -0
  191. package/dashboard/tests/components/ToastContainer.test.jsx +47 -0
  192. package/dashboard/tests/components/Toggle.test.jsx +61 -0
  193. package/dashboard/tests/hooks/useFetch.test.jsx +77 -0
  194. package/dashboard/tests/hooks/useToast.test.jsx +78 -0
  195. package/dashboard/tests/hooks/useWebSocket.test.jsx +128 -0
  196. package/dashboard/tests/pages/ConfigPage.test.jsx +199 -0
  197. package/dashboard/tests/pages/PlanningPage.test.jsx +119 -0
  198. package/dashboard/tests/pages/planning/FilesTab.test.jsx +198 -0
  199. package/dashboard/tests/pages/planning/NotesTab.test.jsx +178 -0
  200. package/dashboard/tests/pages/planning/TodosTab.test.jsx +188 -0
  201. package/dashboard/tests/performance.test.jsx +46 -0
  202. package/dashboard/tests/routes/config.test.js +98 -0
  203. package/dashboard/tests/routes/health.test.js +40 -0
  204. package/dashboard/tests/routes/planning.test.js +112 -0
  205. package/dashboard/tests/routes/roadmap.test.js +91 -0
  206. package/dashboard/tests/routes/status.test.js +131 -0
  207. package/dashboard/tests/server/planning-reader.test.js +153 -0
  208. package/dashboard/tests/setup.js +7 -0
  209. package/dashboard/vite.config.js +41 -0
  210. package/hooks/dist/auto-continue.js +277 -0
  211. package/hooks/dist/block-skill-self-read.js +80 -0
  212. package/hooks/dist/check-agent-state-write.js +63 -0
  213. package/hooks/dist/check-config-change.js +188 -0
  214. package/hooks/dist/check-dangerous-commands.js +185 -0
  215. package/hooks/dist/check-doc-sprawl.js +102 -0
  216. package/hooks/dist/check-phase-boundary.js +191 -0
  217. package/hooks/dist/check-plan-format.js +227 -0
  218. package/hooks/dist/check-roadmap-sync.js +503 -0
  219. package/hooks/dist/check-skill-workflow.js +354 -0
  220. package/hooks/dist/check-state-sync.js +637 -0
  221. package/hooks/dist/check-subagent-output.js +401 -0
  222. package/hooks/dist/check-summary-gate.js +199 -0
  223. package/hooks/dist/context-bridge.js +406 -0
  224. package/hooks/dist/context-budget-check.js +442 -0
  225. package/hooks/dist/context-quality.js +271 -0
  226. package/hooks/dist/enforce-pbr-workflow.js +277 -0
  227. package/hooks/dist/event-handler.js +203 -0
  228. package/hooks/dist/event-logger.js +125 -0
  229. package/hooks/dist/hook-logger.js +112 -0
  230. package/hooks/dist/hook-server-client.js +342 -0
  231. package/hooks/dist/hook-server.js +352 -0
  232. package/hooks/dist/hooks-schema.json +85 -0
  233. package/hooks/dist/hooks.json +309 -0
  234. package/hooks/dist/instructions-loaded.js +107 -0
  235. package/hooks/dist/intel-queue.js +152 -0
  236. package/hooks/dist/intercept-plan-mode.js +50 -0
  237. package/hooks/dist/log-notification.js +125 -0
  238. package/hooks/dist/log-subagent.js +306 -0
  239. package/hooks/dist/log-tool-failure.js +140 -0
  240. package/hooks/dist/milestone-learnings.js +569 -0
  241. package/hooks/dist/pbr-tools.js +5 -0
  242. package/hooks/dist/post-bash-triage.js +152 -0
  243. package/hooks/dist/post-compact.js +135 -0
  244. package/hooks/dist/post-write-dispatch.js +277 -0
  245. package/hooks/dist/post-write-quality.js +208 -0
  246. package/hooks/dist/pre-bash-dispatch.js +158 -0
  247. package/hooks/dist/pre-write-dispatch.js +165 -0
  248. package/hooks/dist/progress-tracker.js +198 -0
  249. package/hooks/dist/prompt-routing.js +209 -0
  250. package/hooks/dist/run-hook.js +144 -0
  251. package/hooks/dist/session-cleanup.js +617 -0
  252. package/hooks/dist/session-tracker.js +124 -0
  253. package/hooks/dist/status-line.js +793 -0
  254. package/hooks/dist/suggest-compact.js +296 -0
  255. package/hooks/dist/sync-context-to-claude.js +100 -0
  256. package/hooks/dist/task-completed.js +206 -0
  257. package/hooks/dist/track-context-budget.js +405 -0
  258. package/hooks/dist/trust-tracker.js +193 -0
  259. package/hooks/dist/validate-commit.js +270 -0
  260. package/hooks/dist/validate-skill-args.js +222 -0
  261. package/hooks/dist/validate-task.js +272 -0
  262. package/hooks/dist/worktree-create.js +144 -0
  263. package/hooks/dist/worktree-remove.js +147 -0
  264. package/package.json +59 -40
  265. package/plan-build-run/bin/config-schema.json +1416 -0
  266. package/plan-build-run/bin/dashboard-launch.cjs +114 -0
  267. package/plan-build-run/bin/event-logger.cjs +92 -0
  268. package/plan-build-run/bin/lib/alternatives.cjs +198 -0
  269. package/plan-build-run/bin/lib/auto-cleanup.cjs +7 -0
  270. package/plan-build-run/bin/lib/build.cjs +717 -0
  271. package/plan-build-run/bin/lib/circuit-state.cjs +133 -0
  272. package/plan-build-run/bin/lib/commands.cjs +482 -0
  273. package/plan-build-run/bin/lib/config.cjs +770 -0
  274. package/plan-build-run/bin/lib/context.cjs +216 -0
  275. package/plan-build-run/bin/lib/contextual-help.cjs +207 -0
  276. package/plan-build-run/bin/lib/core.cjs +1563 -0
  277. package/plan-build-run/bin/lib/decisions.cjs +194 -0
  278. package/plan-build-run/bin/lib/frontmatter.cjs +299 -0
  279. package/plan-build-run/bin/lib/gates/advisories.cjs +129 -0
  280. package/plan-build-run/bin/lib/gates/build-dependency.cjs +115 -0
  281. package/plan-build-run/bin/lib/gates/build-executor.cjs +104 -0
  282. package/plan-build-run/bin/lib/gates/doc-existence.cjs +46 -0
  283. package/plan-build-run/bin/lib/gates/helpers.cjs +93 -0
  284. package/plan-build-run/bin/lib/gates/inline-execution.cjs +185 -0
  285. package/plan-build-run/bin/lib/gates/milestone-complete.cjs +136 -0
  286. package/plan-build-run/bin/lib/gates/milestone-summary.cjs +119 -0
  287. package/plan-build-run/bin/lib/gates/plan-executor.cjs +36 -0
  288. package/plan-build-run/bin/lib/gates/quick-executor.cjs +76 -0
  289. package/plan-build-run/bin/lib/gates/review-planner.cjs +61 -0
  290. package/plan-build-run/bin/lib/gates/review-verifier.cjs +69 -0
  291. package/plan-build-run/bin/lib/graph-cli.cjs +89 -0
  292. package/plan-build-run/bin/lib/graph.cjs +554 -0
  293. package/plan-build-run/bin/lib/health-phase06.cjs +120 -0
  294. package/plan-build-run/bin/lib/health.cjs +133 -0
  295. package/plan-build-run/bin/lib/history.cjs +147 -0
  296. package/plan-build-run/bin/lib/hypothesis-runner.cjs +127 -0
  297. package/plan-build-run/bin/lib/impact-analysis.cjs +319 -0
  298. package/plan-build-run/bin/lib/incidents.cjs +190 -0
  299. package/plan-build-run/bin/lib/init.cjs +367 -0
  300. package/plan-build-run/bin/lib/intel.cjs +653 -0
  301. package/plan-build-run/bin/lib/learnings.cjs +511 -0
  302. package/plan-build-run/bin/lib/local-llm/health.cjs +12 -0
  303. package/plan-build-run/bin/lib/local-llm/index.cjs +89 -0
  304. package/plan-build-run/bin/lib/local-llm/metrics.cjs +20 -0
  305. package/plan-build-run/bin/lib/local-llm/operations/classify-artifact.cjs +4 -0
  306. package/plan-build-run/bin/lib/local-llm/operations/classify-commit.cjs +4 -0
  307. package/plan-build-run/bin/lib/local-llm/operations/classify-error.cjs +4 -0
  308. package/plan-build-run/bin/lib/local-llm/operations/classify-file-intent.cjs +4 -0
  309. package/plan-build-run/bin/lib/local-llm/operations/triage-test-output.cjs +12 -0
  310. package/plan-build-run/bin/lib/local-llm/operations/validate-task.cjs +4 -0
  311. package/plan-build-run/bin/lib/migrate.cjs +298 -0
  312. package/plan-build-run/bin/lib/milestone.cjs +306 -0
  313. package/plan-build-run/bin/lib/negative-knowledge.cjs +194 -0
  314. package/plan-build-run/bin/lib/onboarding-generator.cjs +288 -0
  315. package/plan-build-run/bin/lib/parse-args.cjs +134 -0
  316. package/plan-build-run/bin/lib/patterns.cjs +272 -0
  317. package/plan-build-run/bin/lib/phase.cjs +1021 -0
  318. package/plan-build-run/bin/lib/post-hoc.cjs +160 -0
  319. package/plan-build-run/bin/lib/preview.cjs +174 -0
  320. package/plan-build-run/bin/lib/progress-visualization.cjs +296 -0
  321. package/plan-build-run/bin/lib/quick-init.cjs +131 -0
  322. package/plan-build-run/bin/lib/reference.cjs +234 -0
  323. package/plan-build-run/bin/lib/requirements.cjs +153 -0
  324. package/plan-build-run/bin/lib/reverse-spec.cjs +259 -0
  325. package/plan-build-run/bin/lib/roadmap.cjs +1097 -0
  326. package/plan-build-run/bin/lib/security-scan.cjs +200 -0
  327. package/plan-build-run/bin/lib/skill-section.cjs +98 -0
  328. package/plan-build-run/bin/lib/spec-diff.cjs +209 -0
  329. package/plan-build-run/bin/lib/spec-engine.cjs +189 -0
  330. package/plan-build-run/bin/lib/spot-check.cjs +510 -0
  331. package/plan-build-run/bin/lib/state.cjs +1050 -0
  332. package/plan-build-run/bin/lib/status-render.cjs +527 -0
  333. package/plan-build-run/bin/lib/step-verify.cjs +149 -0
  334. package/plan-build-run/bin/lib/suggest-next.cjs +316 -0
  335. package/plan-build-run/bin/lib/team-composer.cjs +85 -0
  336. package/plan-build-run/bin/lib/team-coordinator.cjs +151 -0
  337. package/plan-build-run/bin/lib/template.cjs +222 -0
  338. package/plan-build-run/bin/lib/templates.cjs +362 -0
  339. package/plan-build-run/bin/lib/test-selection.cjs +163 -0
  340. package/plan-build-run/bin/lib/todo.cjs +300 -0
  341. package/plan-build-run/bin/lib/validation.cjs +187 -0
  342. package/plan-build-run/bin/lib/verify.cjs +1451 -0
  343. package/plan-build-run/bin/pbr-tools.cjs +1877 -0
  344. package/plan-build-run/references/CLAUDE.md +7 -0
  345. package/plan-build-run/references/agent-contracts.md +326 -0
  346. package/plan-build-run/references/agent-teams.md +54 -0
  347. package/plan-build-run/references/behavioral-contexts.md +53 -0
  348. package/plan-build-run/references/checkpoints.md +776 -0
  349. package/plan-build-run/references/config-reference.md +613 -0
  350. package/plan-build-run/references/continuation-format.md +249 -0
  351. package/plan-build-run/references/debugging/CLAUDE.md +7 -0
  352. package/plan-build-run/references/decimal-phase-calculation.md +65 -0
  353. package/plan-build-run/references/git-integration.md +309 -0
  354. package/plan-build-run/references/git-planning-commit.md +38 -0
  355. package/plan-build-run/references/model-profile-resolution.md +34 -0
  356. package/plan-build-run/references/model-profiles.md +182 -0
  357. package/plan-build-run/references/model-selection.md +53 -0
  358. package/plan-build-run/references/phase-argument-parsing.md +61 -0
  359. package/plan-build-run/references/plan-authoring.md +246 -0
  360. package/plan-build-run/references/plan-format.md +351 -0
  361. package/plan-build-run/references/planning-config.md +200 -0
  362. package/plan-build-run/references/questioning.md +162 -0
  363. package/plan-build-run/references/reading-verification.md +127 -0
  364. package/plan-build-run/references/stub-patterns.md +160 -0
  365. package/plan-build-run/references/tdd.md +263 -0
  366. package/plan-build-run/references/ui-brand.md +187 -0
  367. package/plan-build-run/references/verification-overrides.md +38 -0
  368. package/plan-build-run/references/verification-patterns.md +612 -0
  369. package/plan-build-run/references/wave-execution.md +52 -0
  370. package/plan-build-run/skills/audit/SKILL.md +347 -0
  371. package/plan-build-run/skills/autonomous/SKILL.md +460 -0
  372. package/plan-build-run/skills/begin/SKILL.md +926 -0
  373. package/plan-build-run/skills/begin/templates/PROJECT.md.tmpl +33 -0
  374. package/plan-build-run/skills/begin/templates/REQUIREMENTS.md.tmpl +18 -0
  375. package/plan-build-run/skills/begin/templates/STATE.md.tmpl +48 -0
  376. package/plan-build-run/skills/begin/templates/config.json.tmpl +451 -0
  377. package/plan-build-run/skills/begin/templates/project-CONTEXT.md.tmpl +19 -0
  378. package/plan-build-run/skills/begin/templates/researcher-prompt.md.tmpl +47 -0
  379. package/plan-build-run/skills/begin/templates/roadmap-prompt.md.tmpl +49 -0
  380. package/plan-build-run/skills/begin/templates/synthesis-prompt.md.tmpl +44 -0
  381. package/plan-build-run/skills/build/SKILL.md +1655 -0
  382. package/plan-build-run/skills/build/templates/continuation-prompt.md.tmpl +26 -0
  383. package/plan-build-run/skills/build/templates/executor-prompt.md.tmpl +70 -0
  384. package/plan-build-run/skills/build/templates/inline-verifier-prompt.md.tmpl +33 -0
  385. package/plan-build-run/skills/config/SKILL.md +357 -0
  386. package/plan-build-run/skills/continue/SKILL.md +266 -0
  387. package/plan-build-run/skills/dashboard/SKILL.md +12 -0
  388. package/plan-build-run/skills/debug/SKILL.md +573 -0
  389. package/plan-build-run/skills/debug/templates/continuation-prompt.md.tmpl +27 -0
  390. package/plan-build-run/skills/debug/templates/initial-investigation-prompt.md.tmpl +34 -0
  391. package/plan-build-run/skills/discuss/SKILL.md +489 -0
  392. package/plan-build-run/skills/discuss/templates/CONTEXT.md.tmpl +61 -0
  393. package/plan-build-run/skills/discuss/templates/decision-categories.md +9 -0
  394. package/plan-build-run/skills/discuss/templates/project-CONTEXT.md.tmpl +19 -0
  395. package/plan-build-run/skills/do/SKILL.md +165 -0
  396. package/plan-build-run/skills/explore/SKILL.md +449 -0
  397. package/plan-build-run/skills/health/SKILL.md +332 -0
  398. package/plan-build-run/skills/health/templates/check-pattern.md.tmpl +30 -0
  399. package/plan-build-run/skills/health/templates/output-format.md.tmpl +63 -0
  400. package/plan-build-run/skills/help/SKILL.md +236 -0
  401. package/plan-build-run/skills/import/SKILL.md +827 -0
  402. package/plan-build-run/skills/intel/SKILL.md +131 -0
  403. package/plan-build-run/skills/milestone/SKILL.md +825 -0
  404. package/plan-build-run/skills/milestone/templates/audit-output.md.tmpl +76 -0
  405. package/plan-build-run/skills/milestone/templates/complete-output.md.tmpl +32 -0
  406. package/plan-build-run/skills/milestone/templates/edge-cases.md +54 -0
  407. package/plan-build-run/skills/milestone/templates/gaps-output.md.tmpl +25 -0
  408. package/plan-build-run/skills/milestone/templates/integration-checker-prompt.md.tmpl +25 -0
  409. package/plan-build-run/skills/milestone/templates/new-output.md.tmpl +29 -0
  410. package/plan-build-run/skills/milestone/templates/stats-file.md.tmpl +30 -0
  411. package/plan-build-run/skills/note/SKILL.md +221 -0
  412. package/plan-build-run/skills/pause/SKILL.md +259 -0
  413. package/plan-build-run/skills/pause/templates/continue-here.md.tmpl +71 -0
  414. package/plan-build-run/skills/plan/SKILL.md +852 -0
  415. package/plan-build-run/skills/plan/decimal-phase-calc.md +98 -0
  416. package/plan-build-run/skills/plan/templates/checker-prompt.md.tmpl +21 -0
  417. package/plan-build-run/skills/plan/templates/completion-output.md.tmpl +27 -0
  418. package/plan-build-run/skills/plan/templates/gap-closure-prompt.md.tmpl +32 -0
  419. package/plan-build-run/skills/plan/templates/planner-prompt.md.tmpl +38 -0
  420. package/plan-build-run/skills/plan/templates/prompt-partials/phase-project-context.md.tmpl +21 -0
  421. package/plan-build-run/skills/plan/templates/researcher-prompt.md.tmpl +19 -0
  422. package/plan-build-run/skills/plan/templates/revision-prompt.md.tmpl +23 -0
  423. package/plan-build-run/skills/profile/SKILL.md +173 -0
  424. package/plan-build-run/skills/profile-user/SKILL.md +220 -0
  425. package/plan-build-run/skills/quick/SKILL.md +727 -0
  426. package/plan-build-run/skills/release/SKILL.md +206 -0
  427. package/plan-build-run/skills/resume/SKILL.md +499 -0
  428. package/plan-build-run/skills/review/SKILL.md +763 -0
  429. package/plan-build-run/skills/review/templates/debugger-prompt.md.tmpl +60 -0
  430. package/plan-build-run/skills/review/templates/gap-planner-prompt.md.tmpl +40 -0
  431. package/plan-build-run/skills/review/templates/verifier-prompt.md.tmpl +115 -0
  432. package/plan-build-run/skills/scan/SKILL.md +330 -0
  433. package/plan-build-run/skills/scan/templates/mapper-prompt.md.tmpl +201 -0
  434. package/plan-build-run/skills/session-report/SKILL.md +128 -0
  435. package/plan-build-run/skills/setup/SKILL.md +246 -0
  436. package/plan-build-run/skills/shared/agent-type-resolution.md +20 -0
  437. package/plan-build-run/skills/shared/commit-planning-docs.md +43 -0
  438. package/plan-build-run/skills/shared/config-loading.md +102 -0
  439. package/plan-build-run/skills/shared/context-budget.md +105 -0
  440. package/plan-build-run/skills/shared/context-loader-task.md +91 -0
  441. package/plan-build-run/skills/shared/digest-select.md +79 -0
  442. package/plan-build-run/skills/shared/domain-probes.md +125 -0
  443. package/plan-build-run/skills/shared/error-reporting.md +59 -0
  444. package/plan-build-run/skills/shared/gate-prompts.md +390 -0
  445. package/plan-build-run/skills/shared/phase-argument-parsing.md +45 -0
  446. package/plan-build-run/skills/shared/revision-loop.md +81 -0
  447. package/plan-build-run/skills/shared/state-update.md +154 -0
  448. package/plan-build-run/skills/shared/universal-anti-patterns.md +59 -0
  449. package/plan-build-run/skills/ship/SKILL.md +154 -0
  450. package/plan-build-run/skills/status/SKILL.md +520 -0
  451. package/plan-build-run/skills/statusline/SKILL.md +151 -0
  452. package/plan-build-run/skills/test/SKILL.md +254 -0
  453. package/plan-build-run/skills/todo/SKILL.md +285 -0
  454. package/plan-build-run/skills/ui-phase/SKILL.md +177 -0
  455. package/plan-build-run/skills/ui-review/SKILL.md +204 -0
  456. package/plan-build-run/skills/undo/SKILL.md +216 -0
  457. package/plan-build-run/skills/validate-phase/SKILL.md +358 -0
  458. package/plan-build-run/templates/CLAUDE.md +7 -0
  459. package/plan-build-run/templates/DEBUG.md +164 -0
  460. package/plan-build-run/templates/UAT.md +247 -0
  461. package/plan-build-run/templates/VALIDATION.md +76 -0
  462. package/plan-build-run/templates/codebase/architecture.md +255 -0
  463. package/plan-build-run/templates/codebase/concerns.md +310 -0
  464. package/plan-build-run/templates/codebase/conventions.md +307 -0
  465. package/plan-build-run/templates/codebase/integrations.md +280 -0
  466. package/plan-build-run/templates/codebase/stack.md +186 -0
  467. package/plan-build-run/templates/codebase/structure.md +285 -0
  468. package/plan-build-run/templates/codebase/testing.md +480 -0
  469. package/plan-build-run/templates/config.json +37 -0
  470. package/plan-build-run/templates/context.md +297 -0
  471. package/plan-build-run/templates/continue-here.md +78 -0
  472. package/plan-build-run/templates/crud-flow-verification.md +277 -0
  473. package/plan-build-run/templates/debug-subagent-prompt.md +91 -0
  474. package/plan-build-run/templates/deferred-items.md +19 -0
  475. package/plan-build-run/templates/discovery.md +146 -0
  476. package/plan-build-run/templates/milestone-archive.md +123 -0
  477. package/plan-build-run/templates/milestone.md +115 -0
  478. package/plan-build-run/templates/phase-prompt.md +569 -0
  479. package/plan-build-run/templates/planner-subagent-prompt.md +117 -0
  480. package/plan-build-run/templates/project.md +184 -0
  481. package/plan-build-run/templates/requirements.md +231 -0
  482. package/plan-build-run/templates/research-outputs/ARCHITECTURE.md.tmpl +86 -0
  483. package/plan-build-run/templates/research-outputs/FEATURES.md.tmpl +77 -0
  484. package/plan-build-run/templates/research-outputs/PITFALLS.md.tmpl +65 -0
  485. package/plan-build-run/templates/research-outputs/STACK.md.tmpl +80 -0
  486. package/plan-build-run/templates/research-project/ARCHITECTURE.md +204 -0
  487. package/plan-build-run/templates/research-project/FEATURES.md +147 -0
  488. package/plan-build-run/templates/research-project/PITFALLS.md +200 -0
  489. package/plan-build-run/templates/research-project/STACK.md +120 -0
  490. package/plan-build-run/templates/research-project/SUMMARY.md +170 -0
  491. package/plan-build-run/templates/research.md +552 -0
  492. package/plan-build-run/templates/retrospective.md +54 -0
  493. package/plan-build-run/templates/roadmap.md +202 -0
  494. package/plan-build-run/templates/seed.md +16 -0
  495. package/plan-build-run/templates/state.md +176 -0
  496. package/plan-build-run/templates/summary-complex.md +59 -0
  497. package/plan-build-run/templates/summary-minimal.md +41 -0
  498. package/plan-build-run/templates/summary-standard.md +48 -0
  499. package/plan-build-run/templates/summary.md +248 -0
  500. package/plan-build-run/templates/user-setup.md +311 -0
  501. package/plan-build-run/templates/verification-report.md +322 -0
  502. package/plan-build-run/workflows/add-phase.md +111 -0
  503. package/plan-build-run/workflows/add-todo.md +157 -0
  504. package/plan-build-run/workflows/audit-milestone.md +241 -0
  505. package/plan-build-run/workflows/check-todos.md +176 -0
  506. package/plan-build-run/workflows/complete-milestone.md +644 -0
  507. package/plan-build-run/workflows/diagnose-issues.md +219 -0
  508. package/plan-build-run/workflows/discovery-phase.md +289 -0
  509. package/plan-build-run/workflows/discuss-phase.md +429 -0
  510. package/plan-build-run/workflows/execute-phase.md +439 -0
  511. package/plan-build-run/workflows/execute-plan.md +437 -0
  512. package/plan-build-run/workflows/explore.md +150 -0
  513. package/plan-build-run/workflows/help.md +470 -0
  514. package/plan-build-run/workflows/insert-phase.md +129 -0
  515. package/plan-build-run/workflows/list-phase-assumptions.md +178 -0
  516. package/plan-build-run/workflows/map-codebase.md +327 -0
  517. package/plan-build-run/workflows/new-milestone.md +373 -0
  518. package/plan-build-run/workflows/new-project.md +1009 -0
  519. package/plan-build-run/workflows/note.md +90 -0
  520. package/plan-build-run/workflows/pause-work.md +122 -0
  521. package/plan-build-run/workflows/plan-milestone-gaps.md +256 -0
  522. package/plan-build-run/workflows/plan-phase.md +376 -0
  523. package/plan-build-run/workflows/progress.md +431 -0
  524. package/plan-build-run/workflows/quick.md +230 -0
  525. package/plan-build-run/workflows/remove-phase.md +154 -0
  526. package/plan-build-run/workflows/research-phase.md +74 -0
  527. package/plan-build-run/workflows/resume-project.md +306 -0
  528. package/plan-build-run/workflows/set-profile.md +80 -0
  529. package/plan-build-run/workflows/settings.md +145 -0
  530. package/plan-build-run/workflows/transition.md +539 -0
  531. package/plan-build-run/workflows/update.md +212 -0
  532. package/plan-build-run/workflows/verify-phase.md +226 -0
  533. package/plan-build-run/workflows/verify-work.md +465 -0
  534. package/plugins/pbr/.claude-plugin/plugin.json +1 -1
  535. package/plugins/pbr/CLAUDE.md +19 -0
  536. package/plugins/pbr/UI-CONSISTENCY-GAPS.md +1 -1
  537. package/plugins/pbr/agents/audit.md +285 -0
  538. package/plugins/pbr/agents/codebase-mapper.md +110 -18
  539. package/plugins/pbr/agents/debugger.md +231 -29
  540. package/plugins/pbr/agents/dev-sync.md +206 -0
  541. package/plugins/pbr/agents/executor.md +601 -39
  542. package/plugins/pbr/agents/general.md +71 -6
  543. package/plugins/pbr/agents/integration-checker.md +146 -30
  544. package/plugins/pbr/agents/intel-updater.md +333 -0
  545. package/plugins/pbr/agents/nyquist-auditor.md +253 -0
  546. package/plugins/pbr/agents/plan-checker.md +177 -60
  547. package/plugins/pbr/agents/planner.md +404 -42
  548. package/plugins/pbr/agents/researcher.md +239 -36
  549. package/plugins/pbr/agents/roadmapper.md +384 -0
  550. package/plugins/pbr/agents/synthesizer.md +169 -26
  551. package/plugins/pbr/agents/ui-checker.md +203 -0
  552. package/plugins/pbr/agents/ui-researcher.md +224 -0
  553. package/plugins/pbr/agents/verifier.md +452 -48
  554. package/plugins/pbr/commands/add-phase.md +75 -0
  555. package/plugins/pbr/commands/add-todo.md +8 -0
  556. package/plugins/pbr/commands/audit-milestone.md +8 -0
  557. package/plugins/pbr/commands/audit.md +5 -0
  558. package/plugins/pbr/commands/autonomous.md +5 -0
  559. package/plugins/pbr/commands/begin.md +1 -1
  560. package/plugins/pbr/commands/build.md +1 -1
  561. package/plugins/pbr/commands/check-todos.md +8 -0
  562. package/plugins/pbr/commands/complete-milestone.md +8 -0
  563. package/plugins/pbr/commands/config.md +2 -2
  564. package/plugins/pbr/commands/continue.md +1 -1
  565. package/plugins/pbr/commands/dashboard.md +1 -1
  566. package/plugins/pbr/commands/debug.md +1 -1
  567. package/plugins/pbr/commands/discuss-phase.md +6 -0
  568. package/plugins/pbr/commands/discuss.md +1 -1
  569. package/plugins/pbr/commands/do.md +5 -0
  570. package/plugins/pbr/commands/execute-phase.md +6 -0
  571. package/plugins/pbr/commands/explore.md +1 -1
  572. package/plugins/pbr/commands/health.md +1 -1
  573. package/plugins/pbr/commands/help.md +1 -1
  574. package/plugins/pbr/commands/import.md +2 -2
  575. package/plugins/pbr/commands/insert-phase.md +65 -0
  576. package/plugins/pbr/commands/intel.md +5 -0
  577. package/plugins/pbr/commands/join-discord.md +11 -0
  578. package/plugins/pbr/commands/list-phase-assumptions.md +69 -0
  579. package/plugins/pbr/commands/map-codebase.md +6 -0
  580. package/plugins/pbr/commands/milestone.md +1 -1
  581. package/plugins/pbr/commands/new-milestone.md +8 -0
  582. package/plugins/pbr/commands/new-project.md +6 -0
  583. package/plugins/pbr/commands/note.md +1 -1
  584. package/plugins/pbr/commands/pause-work.md +5 -0
  585. package/plugins/pbr/commands/pause.md +1 -1
  586. package/plugins/pbr/commands/plan-milestone-gaps.md +7 -0
  587. package/plugins/pbr/commands/plan-phase.md +6 -0
  588. package/plugins/pbr/commands/plan.md +1 -1
  589. package/plugins/pbr/commands/profile-user.md +5 -0
  590. package/plugins/pbr/commands/profile.md +5 -0
  591. package/plugins/pbr/commands/progress.md +6 -0
  592. package/plugins/pbr/commands/quick.md +2 -2
  593. package/plugins/pbr/commands/reapply-patches.md +47 -0
  594. package/plugins/pbr/commands/release.md +6 -0
  595. package/plugins/pbr/commands/remove-phase.md +66 -0
  596. package/plugins/pbr/commands/research-phase.md +59 -0
  597. package/plugins/pbr/commands/resume-work.md +5 -0
  598. package/plugins/pbr/commands/resume.md +1 -1
  599. package/plugins/pbr/commands/review.md +1 -1
  600. package/plugins/pbr/commands/scan.md +1 -1
  601. package/plugins/pbr/commands/session-report.md +5 -0
  602. package/plugins/pbr/commands/set-profile.md +6 -0
  603. package/plugins/pbr/commands/settings.md +5 -0
  604. package/plugins/pbr/commands/setup.md +2 -2
  605. package/plugins/pbr/commands/ship.md +5 -0
  606. package/plugins/pbr/commands/status.md +1 -1
  607. package/plugins/pbr/commands/statusline.md +1 -1
  608. package/plugins/pbr/commands/test.md +5 -0
  609. package/plugins/pbr/commands/todo.md +2 -2
  610. package/plugins/pbr/commands/ui-phase.md +5 -0
  611. package/plugins/pbr/commands/ui-review.md +5 -0
  612. package/plugins/pbr/commands/undo.md +5 -0
  613. package/plugins/pbr/commands/update.md +37 -0
  614. package/plugins/pbr/commands/validate-phase.md +5 -0
  615. package/plugins/pbr/commands/verify-work.md +6 -0
  616. package/plugins/pbr/dashboard/package-lock.json +6 -0
  617. package/plugins/pbr/hooks/hooks.json +102 -13
  618. package/plugins/pbr/references/agent-contracts.md +37 -8
  619. package/plugins/pbr/references/agent-teams.md +3 -3
  620. package/plugins/pbr/references/archive/checkpoints.md +189 -0
  621. package/plugins/pbr/references/archive/context-quality-tiers.md +45 -0
  622. package/plugins/pbr/references/archive/pbr-rules.md +194 -0
  623. package/plugins/pbr/references/archive/verification-patterns.md +277 -0
  624. package/plugins/pbr/references/config-reference.md +182 -10
  625. package/plugins/pbr/references/continuation-format.md +1 -0
  626. package/plugins/pbr/references/deviation-rules.md +12 -0
  627. package/plugins/pbr/references/git-integration.md +110 -27
  628. package/plugins/pbr/references/hook-ordering.md +89 -0
  629. package/plugins/pbr/references/limitations.md +106 -0
  630. package/plugins/pbr/references/model-profiles.md +90 -7
  631. package/plugins/pbr/references/model-selection.md +1 -1
  632. package/plugins/pbr/references/node-repair.md +48 -0
  633. package/plugins/pbr/references/pbr-tools-cli.md +132 -2
  634. package/plugins/pbr/references/plan-authoring.md +65 -0
  635. package/plugins/pbr/references/plan-format.md +161 -10
  636. package/plugins/pbr/references/pretooluse-jsonl-behavior.md +58 -0
  637. package/plugins/pbr/references/questioning.md +138 -49
  638. package/plugins/pbr/references/reading-verification.md +4 -4
  639. package/plugins/pbr/references/signal-files.md +41 -0
  640. package/plugins/pbr/references/tmux-setup.md +288 -0
  641. package/plugins/pbr/references/ui-brand.md +449 -0
  642. package/plugins/pbr/references/worktree-sparse-checkout.md +86 -0
  643. package/plugins/pbr/scripts/architecture-guard.js +257 -0
  644. package/plugins/pbr/scripts/audit-checks/behavioral-compliance.js +2098 -0
  645. package/plugins/pbr/scripts/audit-checks/error-analysis.js +895 -0
  646. package/plugins/pbr/scripts/audit-checks/feature-verification.js +723 -0
  647. package/plugins/pbr/scripts/audit-checks/index.js +433 -0
  648. package/plugins/pbr/scripts/audit-checks/infrastructure.js +816 -0
  649. package/plugins/pbr/scripts/audit-checks/quality-metrics.js +452 -0
  650. package/plugins/pbr/scripts/audit-checks/session-quality.js +980 -0
  651. package/plugins/pbr/scripts/audit-checks/si-agent-hook-config-checks.js +467 -0
  652. package/plugins/pbr/scripts/audit-checks/si-cross-cutting-checks.js +272 -0
  653. package/plugins/pbr/scripts/audit-checks/si-skill-checks.js +424 -0
  654. package/plugins/pbr/scripts/audit-checks/workflow-compliance.js +1210 -0
  655. package/plugins/pbr/scripts/audit-dimensions.js +552 -0
  656. package/plugins/pbr/scripts/auto-continue.js +211 -32
  657. package/plugins/pbr/scripts/block-skill-self-read.js +85 -0
  658. package/plugins/pbr/scripts/check-agent-state-write.js +74 -0
  659. package/plugins/pbr/scripts/check-config-change.js +188 -0
  660. package/plugins/pbr/scripts/check-cross-plugin-sync.js +93 -0
  661. package/plugins/pbr/scripts/check-dangerous-commands.js +9 -5
  662. package/plugins/pbr/scripts/check-direct-state-write.js +37 -0
  663. package/plugins/pbr/scripts/check-phase-boundary.js +2 -8
  664. package/plugins/pbr/scripts/check-plan-format.js +149 -274
  665. package/plugins/pbr/scripts/check-roadmap-sync.js +175 -10
  666. package/plugins/pbr/scripts/check-skill-workflow.js +38 -34
  667. package/plugins/pbr/scripts/check-state-sync.js +344 -216
  668. package/plugins/pbr/scripts/check-subagent-output.js +297 -256
  669. package/plugins/pbr/scripts/check-summary-gate.js +1 -1
  670. package/plugins/pbr/scripts/config-schema.json +1252 -95
  671. package/plugins/pbr/scripts/context-bridge.js +439 -0
  672. package/plugins/pbr/scripts/context-budget-check.js +89 -9
  673. package/plugins/pbr/scripts/context-quality.js +272 -0
  674. package/plugins/pbr/scripts/enforce-pbr-workflow.js +277 -0
  675. package/plugins/pbr/scripts/event-handler.js +129 -77
  676. package/plugins/pbr/scripts/event-logger.js +61 -26
  677. package/plugins/pbr/scripts/feedback-loop.js +172 -0
  678. package/plugins/pbr/scripts/graph-update.js +199 -0
  679. package/plugins/pbr/scripts/hook-logger.js +76 -35
  680. package/plugins/pbr/scripts/hook-server-client.js +258 -0
  681. package/plugins/pbr/scripts/hook-server.js +334 -0
  682. package/plugins/pbr/scripts/hooks-schema.json +5 -1
  683. package/plugins/pbr/scripts/instructions-loaded.js +107 -0
  684. package/plugins/pbr/scripts/intel-queue.js +152 -0
  685. package/plugins/pbr/scripts/intent-router.cjs +147 -0
  686. package/plugins/pbr/scripts/intercept-plan-mode.js +52 -0
  687. package/plugins/pbr/scripts/lib/alternatives.js +203 -0
  688. package/plugins/pbr/scripts/lib/auto-cleanup.js +221 -0
  689. package/plugins/pbr/scripts/lib/auto-verify.js +103 -0
  690. package/plugins/pbr/scripts/lib/autonomy.js +91 -0
  691. package/plugins/pbr/scripts/lib/build.js +719 -0
  692. package/plugins/pbr/scripts/lib/ci-fix-loop.js +228 -0
  693. package/plugins/pbr/scripts/lib/circuit-state.js +133 -0
  694. package/plugins/pbr/scripts/lib/config.js +901 -0
  695. package/plugins/pbr/scripts/lib/context.js +254 -0
  696. package/plugins/pbr/scripts/lib/convention-detector.js +413 -0
  697. package/plugins/pbr/scripts/lib/core.js +939 -0
  698. package/plugins/pbr/scripts/lib/dashboard-launch.js +170 -0
  699. package/plugins/pbr/scripts/lib/decision-extraction.js +267 -0
  700. package/plugins/pbr/scripts/lib/dependency-break.js +147 -0
  701. package/plugins/pbr/scripts/lib/format-validators.js +947 -0
  702. package/plugins/pbr/scripts/lib/gates/advisories.js +129 -0
  703. package/plugins/pbr/scripts/lib/gates/build-dependency.js +115 -0
  704. package/plugins/pbr/scripts/lib/gates/build-executor.js +104 -0
  705. package/plugins/pbr/scripts/lib/gates/doc-existence.js +46 -0
  706. package/plugins/pbr/scripts/lib/gates/helpers.js +141 -0
  707. package/plugins/pbr/scripts/lib/gates/inline-execution.js +185 -0
  708. package/plugins/pbr/scripts/lib/gates/milestone-complete.js +136 -0
  709. package/plugins/pbr/scripts/lib/gates/milestone-summary.js +119 -0
  710. package/plugins/pbr/scripts/lib/gates/multi-phase-loader.js +147 -0
  711. package/plugins/pbr/scripts/lib/gates/plan-executor.js +36 -0
  712. package/plugins/pbr/scripts/lib/gates/quick-executor.js +76 -0
  713. package/plugins/pbr/scripts/lib/gates/review-planner.js +61 -0
  714. package/plugins/pbr/scripts/lib/gates/review-verifier.js +69 -0
  715. package/plugins/pbr/scripts/lib/gates/rich-agent-context.js +143 -0
  716. package/plugins/pbr/scripts/lib/health-checks.js +215 -0
  717. package/plugins/pbr/scripts/lib/history.js +150 -0
  718. package/plugins/pbr/scripts/lib/init.js +302 -0
  719. package/plugins/pbr/scripts/lib/learnings.js +432 -0
  720. package/plugins/pbr/scripts/lib/migrate.js +169 -0
  721. package/plugins/pbr/scripts/lib/parse-args.js +134 -0
  722. package/plugins/pbr/scripts/lib/pattern-routing.js +55 -0
  723. package/plugins/pbr/scripts/lib/phase.js +935 -0
  724. package/plugins/pbr/scripts/lib/pre-research.js +133 -0
  725. package/plugins/pbr/scripts/lib/preview.js +174 -0
  726. package/plugins/pbr/scripts/lib/quick-init.js +131 -0
  727. package/plugins/pbr/scripts/lib/reference.js +236 -0
  728. package/plugins/pbr/scripts/lib/resolve-root.js +66 -0
  729. package/plugins/pbr/scripts/lib/roadmap.js +784 -0
  730. package/plugins/pbr/scripts/lib/session-briefing.js +879 -0
  731. package/plugins/pbr/scripts/lib/skill-section.js +99 -0
  732. package/plugins/pbr/scripts/lib/smart-next-task.js +225 -0
  733. package/plugins/pbr/scripts/lib/snapshot-manager.js +225 -0
  734. package/plugins/pbr/scripts/lib/spot-check.js +509 -0
  735. package/plugins/pbr/scripts/lib/state.js +565 -0
  736. package/plugins/pbr/scripts/lib/status-render.js +511 -0
  737. package/plugins/pbr/scripts/lib/step-verify.js +149 -0
  738. package/plugins/pbr/scripts/lib/subagent-validators.js +1010 -0
  739. package/plugins/pbr/scripts/lib/suggest-next.js +316 -0
  740. package/plugins/pbr/scripts/lib/tech-debt-scanner.js +116 -0
  741. package/plugins/pbr/scripts/lib/test-cache.js +54 -0
  742. package/plugins/pbr/scripts/lib/todo.js +300 -0
  743. package/plugins/pbr/scripts/lib/trust-gate.js +84 -0
  744. package/plugins/pbr/scripts/local-llm/client.js +237 -0
  745. package/plugins/pbr/scripts/local-llm/health.js +220 -0
  746. package/plugins/pbr/scripts/local-llm/metrics.js +340 -0
  747. package/plugins/pbr/scripts/local-llm/operations/classify-artifact.js +76 -0
  748. package/plugins/pbr/scripts/local-llm/operations/classify-commit.js +137 -0
  749. package/plugins/pbr/scripts/local-llm/operations/classify-error.js +75 -0
  750. package/plugins/pbr/scripts/local-llm/operations/classify-file-intent.js +171 -0
  751. package/plugins/pbr/scripts/local-llm/operations/score-source.js +72 -0
  752. package/plugins/pbr/scripts/local-llm/operations/summarize-context.js +62 -0
  753. package/plugins/pbr/scripts/local-llm/operations/triage-test-output.js +72 -0
  754. package/plugins/pbr/scripts/local-llm/operations/validate-task.js +59 -0
  755. package/plugins/pbr/scripts/local-llm/router.js +101 -0
  756. package/plugins/pbr/scripts/local-llm/shadow.js +60 -0
  757. package/plugins/pbr/scripts/local-llm/threshold-tuner.js +118 -0
  758. package/plugins/pbr/scripts/log-subagent.js +129 -26
  759. package/plugins/pbr/scripts/log-tool-failure.js +58 -5
  760. package/plugins/pbr/scripts/milestone-learnings.js +569 -0
  761. package/plugins/pbr/scripts/package.json +1 -0
  762. package/plugins/pbr/scripts/pbr-tools.js +1361 -1214
  763. package/plugins/pbr/scripts/post-bash-triage.js +163 -0
  764. package/plugins/pbr/scripts/post-compact.js +135 -0
  765. package/plugins/pbr/scripts/post-hoc.js +286 -0
  766. package/plugins/pbr/scripts/post-write-dispatch.js +315 -30
  767. package/plugins/pbr/scripts/post-write-quality.js +3 -3
  768. package/plugins/pbr/scripts/pre-bash-dispatch.js +81 -4
  769. package/plugins/pbr/scripts/pre-write-dispatch.js +76 -20
  770. package/plugins/pbr/scripts/progress-tracker.js +145 -277
  771. package/plugins/pbr/scripts/quick-status.js +179 -0
  772. package/plugins/pbr/scripts/record-incident.js +37 -0
  773. package/plugins/pbr/scripts/risk-classifier.cjs +123 -0
  774. package/plugins/pbr/scripts/run-hook.js +49 -8
  775. package/plugins/pbr/scripts/session-cleanup.js +379 -7
  776. package/plugins/pbr/scripts/session-tracker.js +124 -0
  777. package/plugins/pbr/scripts/status-line.js +540 -27
  778. package/plugins/pbr/scripts/suggest-compact.js +183 -7
  779. package/plugins/pbr/scripts/sync-context-to-claude.js +100 -0
  780. package/plugins/pbr/scripts/task-completed.js +125 -3
  781. package/plugins/pbr/scripts/test/config.test.js +126 -0
  782. package/plugins/pbr/scripts/test/cross-platform.test.js +131 -0
  783. package/plugins/pbr/scripts/test/fixtures/config.json +20 -0
  784. package/plugins/pbr/scripts/test/fixtures/plan.md +54 -0
  785. package/plugins/pbr/scripts/test/fixtures/project.md +30 -0
  786. package/plugins/pbr/scripts/test/fixtures/roadmap.md +55 -0
  787. package/plugins/pbr/scripts/test/fixtures/state.md +60 -0
  788. package/plugins/pbr/scripts/test/fixtures/summary.md +35 -0
  789. package/plugins/pbr/scripts/test/fixtures.test.js +184 -0
  790. package/plugins/pbr/scripts/test/phase.test.js +142 -0
  791. package/plugins/pbr/scripts/test/roadmap.test.js +96 -0
  792. package/plugins/pbr/scripts/test/state.test.js +163 -0
  793. package/plugins/pbr/scripts/track-context-budget.js +323 -88
  794. package/plugins/pbr/scripts/trust-tracker.js +193 -0
  795. package/plugins/pbr/scripts/validate-commit.js +76 -11
  796. package/plugins/pbr/scripts/validate-skill-args.js +18 -14
  797. package/plugins/pbr/scripts/validate-task.js +93 -614
  798. package/plugins/pbr/scripts/worktree-create.js +144 -0
  799. package/plugins/pbr/scripts/worktree-remove.js +147 -0
  800. package/plugins/pbr/skills/audit/SKILL.md +478 -0
  801. package/plugins/pbr/skills/autonomous/SKILL.md +460 -0
  802. package/plugins/pbr/skills/begin/SKILL.md +447 -142
  803. package/plugins/pbr/skills/begin/templates/STATE.md.tmpl +1 -2
  804. package/plugins/pbr/skills/begin/templates/config.json.tmpl +423 -36
  805. package/plugins/pbr/skills/begin/templates/researcher-prompt.md.tmpl +28 -0
  806. package/plugins/pbr/skills/begin/templates/roadmap-prompt.md.tmpl +26 -3
  807. package/plugins/pbr/skills/begin/templates/synthesis-prompt.md.tmpl +33 -5
  808. package/plugins/pbr/skills/build/SKILL.md +1010 -327
  809. package/plugins/pbr/skills/build/templates/continuation-prompt.md.tmpl +26 -0
  810. package/plugins/pbr/skills/build/templates/executor-prompt.md.tmpl +77 -0
  811. package/plugins/pbr/skills/build/templates/inline-verifier-prompt.md.tmpl +33 -0
  812. package/plugins/pbr/skills/config/SKILL.md +108 -9
  813. package/plugins/pbr/skills/continue/SKILL.md +118 -19
  814. package/plugins/pbr/skills/dashboard/SKILL.md +21 -9
  815. package/plugins/pbr/skills/debug/SKILL.md +62 -10
  816. package/plugins/pbr/skills/debug/templates/continuation-prompt.md.tmpl +12 -1
  817. package/plugins/pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +12 -5
  818. package/plugins/pbr/skills/discuss/SKILL.md +155 -23
  819. package/plugins/pbr/skills/discuss/templates/CONTEXT.md.tmpl +21 -1
  820. package/plugins/pbr/skills/do/SKILL.md +119 -24
  821. package/plugins/pbr/skills/explore/SKILL.md +83 -16
  822. package/plugins/pbr/skills/health/SKILL.md +74 -17
  823. package/plugins/pbr/skills/help/SKILL.md +123 -39
  824. package/plugins/pbr/skills/import/SKILL.md +327 -13
  825. package/plugins/pbr/skills/intel/SKILL.md +131 -0
  826. package/plugins/pbr/skills/milestone/SKILL.md +342 -260
  827. package/plugins/pbr/skills/milestone/templates/audit-output.md.tmpl +76 -0
  828. package/plugins/pbr/skills/milestone/templates/complete-output.md.tmpl +32 -0
  829. package/plugins/pbr/skills/milestone/templates/edge-cases.md +54 -0
  830. package/plugins/pbr/skills/milestone/templates/gaps-output.md.tmpl +25 -0
  831. package/plugins/pbr/skills/milestone/templates/integration-checker-prompt.md.tmpl +25 -0
  832. package/plugins/pbr/skills/milestone/templates/new-output.md.tmpl +29 -0
  833. package/plugins/pbr/skills/note/SKILL.md +10 -2
  834. package/plugins/pbr/skills/pause/SKILL.md +51 -7
  835. package/plugins/pbr/skills/pause/templates/continue-here.md.tmpl +33 -52
  836. package/plugins/pbr/skills/plan/SKILL.md +418 -268
  837. package/plugins/pbr/skills/plan/templates/checker-prompt.md.tmpl +5 -2
  838. package/plugins/pbr/skills/plan/templates/completion-output.md.tmpl +27 -0
  839. package/plugins/pbr/skills/plan/templates/revision-prompt.md.tmpl +21 -5
  840. package/plugins/pbr/skills/profile/SKILL.md +183 -0
  841. package/plugins/pbr/skills/profile-user/SKILL.md +224 -0
  842. package/plugins/pbr/skills/quick/SKILL.md +440 -95
  843. package/plugins/pbr/skills/release/SKILL.md +206 -0
  844. package/plugins/pbr/skills/resume/SKILL.md +122 -27
  845. package/plugins/pbr/skills/review/SKILL.md +219 -154
  846. package/plugins/pbr/skills/review/templates/verifier-prompt.md.tmpl +7 -0
  847. package/plugins/pbr/skills/scan/SKILL.md +36 -12
  848. package/plugins/pbr/skills/scan/templates/mapper-prompt.md.tmpl +1 -1
  849. package/plugins/pbr/skills/session-report/SKILL.md +128 -0
  850. package/plugins/pbr/skills/setup/SKILL.md +149 -202
  851. package/plugins/pbr/skills/shared/agent-context-enrichment.md +21 -0
  852. package/plugins/pbr/skills/shared/agent-type-resolution.md +20 -0
  853. package/plugins/pbr/skills/shared/commit-planning-docs.md +8 -0
  854. package/plugins/pbr/skills/shared/context-budget.md +66 -1
  855. package/plugins/pbr/skills/shared/context-loader-task.md +15 -8
  856. package/plugins/pbr/skills/shared/digest-select.md +2 -2
  857. package/plugins/pbr/skills/shared/domain-probes.md +1 -1
  858. package/plugins/pbr/skills/shared/error-reporting.md +38 -60
  859. package/plugins/pbr/skills/shared/gate-prompts.md +4 -2
  860. package/plugins/pbr/skills/shared/memory-capture.md +48 -0
  861. package/plugins/pbr/skills/shared/phase-argument-parsing.md +4 -4
  862. package/plugins/pbr/skills/shared/revision-loop.md +24 -6
  863. package/plugins/pbr/skills/shared/state-update.md +47 -54
  864. package/plugins/pbr/skills/shared/universal-anti-patterns.md +27 -4
  865. package/plugins/pbr/skills/ship/SKILL.md +154 -0
  866. package/plugins/pbr/skills/status/SKILL.md +201 -53
  867. package/plugins/pbr/skills/test/SKILL.md +254 -0
  868. package/plugins/pbr/skills/todo/SKILL.md +13 -11
  869. package/plugins/pbr/skills/ui-phase/SKILL.md +179 -0
  870. package/plugins/pbr/skills/ui-review/SKILL.md +206 -0
  871. package/plugins/pbr/skills/undo/SKILL.md +218 -0
  872. package/plugins/pbr/skills/validate-phase/SKILL.md +358 -0
  873. package/plugins/pbr/templates/CONTEXT.md.tmpl +45 -20
  874. package/plugins/pbr/templates/DISCOVERY.md.tmpl +29 -0
  875. package/plugins/pbr/templates/HANDOFF.json.tmpl +30 -0
  876. package/plugins/pbr/templates/INTEGRATION-REPORT.md.tmpl +18 -2
  877. package/plugins/pbr/templates/KNOWLEDGE.md.tmpl +39 -0
  878. package/plugins/pbr/templates/MILESTONE-AUDIT.md.tmpl +44 -0
  879. package/plugins/pbr/templates/PROJECT.md.tmpl +126 -0
  880. package/plugins/pbr/templates/REQUIREMENTS.md.tmpl +96 -0
  881. package/plugins/pbr/templates/RETROSPECTIVE.md.tmpl +43 -0
  882. package/plugins/pbr/templates/ROADMAP.md.tmpl +108 -14
  883. package/plugins/pbr/templates/SUMMARY-complex.md.tmpl +133 -0
  884. package/plugins/pbr/templates/SUMMARY-minimal.md.tmpl +55 -0
  885. package/plugins/pbr/templates/SUMMARY.md.tmpl +21 -0
  886. package/plugins/pbr/templates/VERIFICATION-DETAIL.md.tmpl +49 -13
  887. package/plugins/pbr/templates/project-CONTEXT.md.tmpl +59 -0
  888. package/plugins/pbr/templates/research-outputs/ARCHITECTURE.md.tmpl +91 -0
  889. package/plugins/pbr/templates/research-outputs/FEATURES.md.tmpl +64 -0
  890. package/plugins/pbr/templates/research-outputs/PITFALLS.md.tmpl +50 -0
  891. package/plugins/pbr/templates/research-outputs/STACK.md.tmpl +63 -0
  892. package/plugins/pbr/templates/research-outputs/SUMMARY.md.tmpl +98 -0
  893. package/scripts/build-hooks.js +61 -0
  894. package/scripts/check-ci.js +100 -0
  895. package/scripts/clean-changelog.js +362 -0
  896. package/scripts/generate-derivatives.js +581 -0
  897. package/scripts/posttest.js +93 -0
  898. package/scripts/release.js +196 -0
  899. package/scripts/run-tests.cjs +29 -0
  900. package/dashboard/bin/cli.js +0 -25
  901. package/dashboard/public/css/layout.css +0 -472
  902. package/dashboard/public/css/status-colors.css +0 -98
  903. package/dashboard/public/js/htmx-title.js +0 -5
  904. package/dashboard/public/js/sidebar-toggle.js +0 -20
  905. package/dashboard/src/app.js +0 -78
  906. package/dashboard/src/middleware/errorHandler.js +0 -52
  907. package/dashboard/src/middleware/notFoundHandler.js +0 -9
  908. package/dashboard/src/repositories/planning.repository.js +0 -130
  909. package/dashboard/src/routes/events.routes.js +0 -40
  910. package/dashboard/src/routes/index.routes.js +0 -31
  911. package/dashboard/src/routes/pages.routes.js +0 -308
  912. package/dashboard/src/server.js +0 -42
  913. package/dashboard/src/services/dashboard.service.js +0 -309
  914. package/dashboard/src/services/milestone.service.js +0 -154
  915. package/dashboard/src/services/phase.service.js +0 -226
  916. package/dashboard/src/services/project.service.js +0 -57
  917. package/dashboard/src/services/roadmap.service.js +0 -171
  918. package/dashboard/src/services/sse.service.js +0 -58
  919. package/dashboard/src/services/todo.service.js +0 -254
  920. package/dashboard/src/services/watcher.service.js +0 -48
  921. package/dashboard/src/views/coming-soon.ejs +0 -11
  922. package/dashboard/src/views/error.ejs +0 -13
  923. package/dashboard/src/views/index.ejs +0 -5
  924. package/dashboard/src/views/layout.ejs +0 -1
  925. package/dashboard/src/views/milestone-detail.ejs +0 -5
  926. package/dashboard/src/views/milestones.ejs +0 -5
  927. package/dashboard/src/views/partials/dashboard-content.ejs +0 -77
  928. package/dashboard/src/views/partials/footer.ejs +0 -3
  929. package/dashboard/src/views/partials/head.ejs +0 -27
  930. package/dashboard/src/views/partials/header.ejs +0 -12
  931. package/dashboard/src/views/partials/layout-bottom.ejs +0 -15
  932. package/dashboard/src/views/partials/layout-top.ejs +0 -8
  933. package/dashboard/src/views/partials/milestone-detail-content.ejs +0 -19
  934. package/dashboard/src/views/partials/milestones-content.ejs +0 -44
  935. package/dashboard/src/views/partials/phase-content.ejs +0 -189
  936. package/dashboard/src/views/partials/phase-doc-content.ejs +0 -38
  937. package/dashboard/src/views/partials/phases-content.ejs +0 -117
  938. package/dashboard/src/views/partials/roadmap-content.ejs +0 -142
  939. package/dashboard/src/views/partials/sidebar.ejs +0 -46
  940. package/dashboard/src/views/partials/todo-create-content.ejs +0 -53
  941. package/dashboard/src/views/partials/todo-detail-content.ejs +0 -38
  942. package/dashboard/src/views/partials/todos-content.ejs +0 -53
  943. package/dashboard/src/views/phase-detail.ejs +0 -5
  944. package/dashboard/src/views/phase-doc.ejs +0 -5
  945. package/dashboard/src/views/phases.ejs +0 -5
  946. package/dashboard/src/views/roadmap.ejs +0 -5
  947. package/dashboard/src/views/todo-create.ejs +0 -5
  948. package/dashboard/src/views/todo-detail.ejs +0 -5
  949. package/dashboard/src/views/todos.ejs +0 -5
  950. package/plugins/copilot-pbr/CHANGELOG.md +0 -19
  951. package/plugins/copilot-pbr/README.md +0 -129
  952. package/plugins/copilot-pbr/agents/codebase-mapper.agent.md +0 -151
  953. package/plugins/copilot-pbr/agents/debugger.agent.md +0 -172
  954. package/plugins/copilot-pbr/agents/executor.agent.md +0 -267
  955. package/plugins/copilot-pbr/agents/general.agent.md +0 -88
  956. package/plugins/copilot-pbr/agents/integration-checker.agent.md +0 -119
  957. package/plugins/copilot-pbr/agents/plan-checker.agent.md +0 -199
  958. package/plugins/copilot-pbr/agents/planner.agent.md +0 -238
  959. package/plugins/copilot-pbr/agents/researcher.agent.md +0 -186
  960. package/plugins/copilot-pbr/agents/synthesizer.agent.md +0 -126
  961. package/plugins/copilot-pbr/agents/verifier.agent.md +0 -228
  962. package/plugins/copilot-pbr/hooks/hooks.json +0 -144
  963. package/plugins/copilot-pbr/plugin.json +0 -30
  964. package/plugins/copilot-pbr/references/agent-anti-patterns.md +0 -25
  965. package/plugins/copilot-pbr/references/agent-contracts.md +0 -297
  966. package/plugins/copilot-pbr/references/agent-interactions.md +0 -135
  967. package/plugins/copilot-pbr/references/agent-teams.md +0 -55
  968. package/plugins/copilot-pbr/references/checkpoints.md +0 -158
  969. package/plugins/copilot-pbr/references/common-bug-patterns.md +0 -14
  970. package/plugins/copilot-pbr/references/config-reference.md +0 -442
  971. package/plugins/copilot-pbr/references/continuation-format.md +0 -213
  972. package/plugins/copilot-pbr/references/deviation-rules.md +0 -113
  973. package/plugins/copilot-pbr/references/git-integration.md +0 -227
  974. package/plugins/copilot-pbr/references/integration-patterns.md +0 -118
  975. package/plugins/copilot-pbr/references/model-profiles.md +0 -100
  976. package/plugins/copilot-pbr/references/model-selection.md +0 -32
  977. package/plugins/copilot-pbr/references/pbr-rules.md +0 -195
  978. package/plugins/copilot-pbr/references/pbr-tools-cli.md +0 -285
  979. package/plugins/copilot-pbr/references/plan-authoring.md +0 -182
  980. package/plugins/copilot-pbr/references/plan-format.md +0 -288
  981. package/plugins/copilot-pbr/references/planning-config.md +0 -214
  982. package/plugins/copilot-pbr/references/questioning.md +0 -215
  983. package/plugins/copilot-pbr/references/reading-verification.md +0 -128
  984. package/plugins/copilot-pbr/references/stub-patterns.md +0 -161
  985. package/plugins/copilot-pbr/references/subagent-coordination.md +0 -120
  986. package/plugins/copilot-pbr/references/ui-formatting.md +0 -444
  987. package/plugins/copilot-pbr/references/verification-patterns.md +0 -199
  988. package/plugins/copilot-pbr/references/wave-execution.md +0 -96
  989. package/plugins/copilot-pbr/rules/pbr-workflow.mdc +0 -48
  990. package/plugins/copilot-pbr/setup.ps1 +0 -93
  991. package/plugins/copilot-pbr/setup.sh +0 -93
  992. package/plugins/copilot-pbr/skills/begin/SKILL.md +0 -589
  993. package/plugins/copilot-pbr/skills/begin/templates/PROJECT.md.tmpl +0 -34
  994. package/plugins/copilot-pbr/skills/begin/templates/REQUIREMENTS.md.tmpl +0 -19
  995. package/plugins/copilot-pbr/skills/begin/templates/STATE.md.tmpl +0 -50
  996. package/plugins/copilot-pbr/skills/begin/templates/config.json.tmpl +0 -64
  997. package/plugins/copilot-pbr/skills/begin/templates/researcher-prompt.md.tmpl +0 -20
  998. package/plugins/copilot-pbr/skills/begin/templates/roadmap-prompt.md.tmpl +0 -31
  999. package/plugins/copilot-pbr/skills/begin/templates/synthesis-prompt.md.tmpl +0 -17
  1000. package/plugins/copilot-pbr/skills/build/SKILL.md +0 -955
  1001. package/plugins/copilot-pbr/skills/config/SKILL.md +0 -250
  1002. package/plugins/copilot-pbr/skills/continue/SKILL.md +0 -159
  1003. package/plugins/copilot-pbr/skills/dashboard/SKILL.md +0 -43
  1004. package/plugins/copilot-pbr/skills/debug/SKILL.md +0 -508
  1005. package/plugins/copilot-pbr/skills/debug/templates/continuation-prompt.md.tmpl +0 -17
  1006. package/plugins/copilot-pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +0 -28
  1007. package/plugins/copilot-pbr/skills/discuss/SKILL.md +0 -353
  1008. package/plugins/copilot-pbr/skills/discuss/templates/CONTEXT.md.tmpl +0 -62
  1009. package/plugins/copilot-pbr/skills/discuss/templates/decision-categories.md +0 -10
  1010. package/plugins/copilot-pbr/skills/do/SKILL.md +0 -66
  1011. package/plugins/copilot-pbr/skills/explore/SKILL.md +0 -373
  1012. package/plugins/copilot-pbr/skills/health/SKILL.md +0 -274
  1013. package/plugins/copilot-pbr/skills/health/templates/check-pattern.md.tmpl +0 -31
  1014. package/plugins/copilot-pbr/skills/health/templates/output-format.md.tmpl +0 -64
  1015. package/plugins/copilot-pbr/skills/help/SKILL.md +0 -152
  1016. package/plugins/copilot-pbr/skills/import/SKILL.md +0 -502
  1017. package/plugins/copilot-pbr/skills/milestone/SKILL.md +0 -745
  1018. package/plugins/copilot-pbr/skills/milestone/templates/audit-report.md.tmpl +0 -49
  1019. package/plugins/copilot-pbr/skills/milestone/templates/stats-file.md.tmpl +0 -31
  1020. package/plugins/copilot-pbr/skills/note/SKILL.md +0 -213
  1021. package/plugins/copilot-pbr/skills/pause/SKILL.md +0 -247
  1022. package/plugins/copilot-pbr/skills/pause/templates/continue-here.md.tmpl +0 -72
  1023. package/plugins/copilot-pbr/skills/plan/SKILL.md +0 -662
  1024. package/plugins/copilot-pbr/skills/plan/templates/checker-prompt.md.tmpl +0 -22
  1025. package/plugins/copilot-pbr/skills/plan/templates/gap-closure-prompt.md.tmpl +0 -33
  1026. package/plugins/copilot-pbr/skills/plan/templates/planner-prompt.md.tmpl +0 -39
  1027. package/plugins/copilot-pbr/skills/plan/templates/researcher-prompt.md.tmpl +0 -20
  1028. package/plugins/copilot-pbr/skills/plan/templates/revision-prompt.md.tmpl +0 -24
  1029. package/plugins/copilot-pbr/skills/quick/SKILL.md +0 -376
  1030. package/plugins/copilot-pbr/skills/resume/SKILL.md +0 -399
  1031. package/plugins/copilot-pbr/skills/review/SKILL.md +0 -653
  1032. package/plugins/copilot-pbr/skills/review/templates/debugger-prompt.md.tmpl +0 -61
  1033. package/plugins/copilot-pbr/skills/review/templates/gap-planner-prompt.md.tmpl +0 -41
  1034. package/plugins/copilot-pbr/skills/review/templates/verifier-prompt.md.tmpl +0 -116
  1035. package/plugins/copilot-pbr/skills/scan/SKILL.md +0 -299
  1036. package/plugins/copilot-pbr/skills/scan/templates/mapper-prompt.md.tmpl +0 -202
  1037. package/plugins/copilot-pbr/skills/setup/SKILL.md +0 -296
  1038. package/plugins/copilot-pbr/skills/shared/commit-planning-docs.md +0 -36
  1039. package/plugins/copilot-pbr/skills/shared/config-loading.md +0 -103
  1040. package/plugins/copilot-pbr/skills/shared/context-budget.md +0 -41
  1041. package/plugins/copilot-pbr/skills/shared/context-loader-task.md +0 -87
  1042. package/plugins/copilot-pbr/skills/shared/digest-select.md +0 -80
  1043. package/plugins/copilot-pbr/skills/shared/domain-probes.md +0 -126
  1044. package/plugins/copilot-pbr/skills/shared/error-reporting.md +0 -81
  1045. package/plugins/copilot-pbr/skills/shared/gate-prompts.md +0 -389
  1046. package/plugins/copilot-pbr/skills/shared/phase-argument-parsing.md +0 -46
  1047. package/plugins/copilot-pbr/skills/shared/progress-display.md +0 -53
  1048. package/plugins/copilot-pbr/skills/shared/revision-loop.md +0 -82
  1049. package/plugins/copilot-pbr/skills/shared/state-loading.md +0 -63
  1050. package/plugins/copilot-pbr/skills/shared/state-update.md +0 -162
  1051. package/plugins/copilot-pbr/skills/shared/universal-anti-patterns.md +0 -38
  1052. package/plugins/copilot-pbr/skills/status/SKILL.md +0 -362
  1053. package/plugins/copilot-pbr/skills/statusline/SKILL.md +0 -149
  1054. package/plugins/copilot-pbr/skills/todo/SKILL.md +0 -279
  1055. package/plugins/copilot-pbr/templates/CONTEXT.md.tmpl +0 -53
  1056. package/plugins/copilot-pbr/templates/INTEGRATION-REPORT.md.tmpl +0 -152
  1057. package/plugins/copilot-pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -98
  1058. package/plugins/copilot-pbr/templates/ROADMAP.md.tmpl +0 -41
  1059. package/plugins/copilot-pbr/templates/SUMMARY.md.tmpl +0 -82
  1060. package/plugins/copilot-pbr/templates/VERIFICATION-DETAIL.md.tmpl +0 -117
  1061. package/plugins/copilot-pbr/templates/codebase/ARCHITECTURE.md.tmpl +0 -98
  1062. package/plugins/copilot-pbr/templates/codebase/CONCERNS.md.tmpl +0 -93
  1063. package/plugins/copilot-pbr/templates/codebase/CONVENTIONS.md.tmpl +0 -104
  1064. package/plugins/copilot-pbr/templates/codebase/INTEGRATIONS.md.tmpl +0 -78
  1065. package/plugins/copilot-pbr/templates/codebase/STACK.md.tmpl +0 -78
  1066. package/plugins/copilot-pbr/templates/codebase/STRUCTURE.md.tmpl +0 -80
  1067. package/plugins/copilot-pbr/templates/codebase/TESTING.md.tmpl +0 -107
  1068. package/plugins/copilot-pbr/templates/continue-here.md.tmpl +0 -74
  1069. package/plugins/copilot-pbr/templates/prompt-partials/phase-project-context.md.tmpl +0 -38
  1070. package/plugins/copilot-pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
  1071. package/plugins/copilot-pbr/templates/research/STACK.md.tmpl +0 -71
  1072. package/plugins/copilot-pbr/templates/research/SUMMARY.md.tmpl +0 -112
  1073. package/plugins/copilot-pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
  1074. package/plugins/copilot-pbr/templates/research-outputs/project-research.md.tmpl +0 -99
  1075. package/plugins/copilot-pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
  1076. package/plugins/cursor-pbr/.cursor-plugin/plugin.json +0 -32
  1077. package/plugins/cursor-pbr/CHANGELOG.md +0 -15
  1078. package/plugins/cursor-pbr/README.md +0 -118
  1079. package/plugins/cursor-pbr/agents/codebase-mapper.md +0 -150
  1080. package/plugins/cursor-pbr/agents/debugger.md +0 -171
  1081. package/plugins/cursor-pbr/agents/executor.md +0 -266
  1082. package/plugins/cursor-pbr/agents/general.md +0 -87
  1083. package/plugins/cursor-pbr/agents/integration-checker.md +0 -118
  1084. package/plugins/cursor-pbr/agents/plan-checker.md +0 -198
  1085. package/plugins/cursor-pbr/agents/planner.md +0 -237
  1086. package/plugins/cursor-pbr/agents/researcher.md +0 -185
  1087. package/plugins/cursor-pbr/agents/synthesizer.md +0 -125
  1088. package/plugins/cursor-pbr/agents/verifier.md +0 -227
  1089. package/plugins/cursor-pbr/assets/.gitkeep +0 -0
  1090. package/plugins/cursor-pbr/assets/logo.svg +0 -21
  1091. package/plugins/cursor-pbr/hooks/hooks.json +0 -203
  1092. package/plugins/cursor-pbr/references/agent-anti-patterns.md +0 -25
  1093. package/plugins/cursor-pbr/references/agent-contracts.md +0 -297
  1094. package/plugins/cursor-pbr/references/agent-interactions.md +0 -135
  1095. package/plugins/cursor-pbr/references/agent-teams.md +0 -55
  1096. package/plugins/cursor-pbr/references/checkpoints.md +0 -158
  1097. package/plugins/cursor-pbr/references/common-bug-patterns.md +0 -14
  1098. package/plugins/cursor-pbr/references/config-reference.md +0 -442
  1099. package/plugins/cursor-pbr/references/continuation-format.md +0 -213
  1100. package/plugins/cursor-pbr/references/deviation-rules.md +0 -113
  1101. package/plugins/cursor-pbr/references/git-integration.md +0 -227
  1102. package/plugins/cursor-pbr/references/integration-patterns.md +0 -118
  1103. package/plugins/cursor-pbr/references/model-profiles.md +0 -100
  1104. package/plugins/cursor-pbr/references/model-selection.md +0 -32
  1105. package/plugins/cursor-pbr/references/pbr-rules.md +0 -195
  1106. package/plugins/cursor-pbr/references/pbr-tools-cli.md +0 -285
  1107. package/plugins/cursor-pbr/references/plan-authoring.md +0 -182
  1108. package/plugins/cursor-pbr/references/plan-format.md +0 -288
  1109. package/plugins/cursor-pbr/references/planning-config.md +0 -214
  1110. package/plugins/cursor-pbr/references/questioning.md +0 -215
  1111. package/plugins/cursor-pbr/references/reading-verification.md +0 -128
  1112. package/plugins/cursor-pbr/references/stub-patterns.md +0 -161
  1113. package/plugins/cursor-pbr/references/subagent-coordination.md +0 -120
  1114. package/plugins/cursor-pbr/references/ui-formatting.md +0 -444
  1115. package/plugins/cursor-pbr/references/verification-patterns.md +0 -199
  1116. package/plugins/cursor-pbr/references/wave-execution.md +0 -96
  1117. package/plugins/cursor-pbr/rules/pbr-workflow.mdc +0 -48
  1118. package/plugins/cursor-pbr/setup.ps1 +0 -78
  1119. package/plugins/cursor-pbr/setup.sh +0 -83
  1120. package/plugins/cursor-pbr/skills/begin/SKILL.md +0 -589
  1121. package/plugins/cursor-pbr/skills/begin/templates/PROJECT.md.tmpl +0 -34
  1122. package/plugins/cursor-pbr/skills/begin/templates/REQUIREMENTS.md.tmpl +0 -19
  1123. package/plugins/cursor-pbr/skills/begin/templates/STATE.md.tmpl +0 -50
  1124. package/plugins/cursor-pbr/skills/begin/templates/config.json.tmpl +0 -64
  1125. package/plugins/cursor-pbr/skills/begin/templates/researcher-prompt.md.tmpl +0 -20
  1126. package/plugins/cursor-pbr/skills/begin/templates/roadmap-prompt.md.tmpl +0 -31
  1127. package/plugins/cursor-pbr/skills/begin/templates/synthesis-prompt.md.tmpl +0 -17
  1128. package/plugins/cursor-pbr/skills/build/SKILL.md +0 -956
  1129. package/plugins/cursor-pbr/skills/config/SKILL.md +0 -252
  1130. package/plugins/cursor-pbr/skills/continue/SKILL.md +0 -159
  1131. package/plugins/cursor-pbr/skills/dashboard/SKILL.md +0 -44
  1132. package/plugins/cursor-pbr/skills/debug/SKILL.md +0 -512
  1133. package/plugins/cursor-pbr/skills/debug/templates/continuation-prompt.md.tmpl +0 -17
  1134. package/plugins/cursor-pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +0 -28
  1135. package/plugins/cursor-pbr/skills/discuss/SKILL.md +0 -354
  1136. package/plugins/cursor-pbr/skills/discuss/templates/CONTEXT.md.tmpl +0 -62
  1137. package/plugins/cursor-pbr/skills/discuss/templates/decision-categories.md +0 -10
  1138. package/plugins/cursor-pbr/skills/do/SKILL.md +0 -67
  1139. package/plugins/cursor-pbr/skills/explore/SKILL.md +0 -376
  1140. package/plugins/cursor-pbr/skills/health/SKILL.md +0 -274
  1141. package/plugins/cursor-pbr/skills/health/templates/check-pattern.md.tmpl +0 -31
  1142. package/plugins/cursor-pbr/skills/health/templates/output-format.md.tmpl +0 -64
  1143. package/plugins/cursor-pbr/skills/help/SKILL.md +0 -152
  1144. package/plugins/cursor-pbr/skills/import/SKILL.md +0 -505
  1145. package/plugins/cursor-pbr/skills/milestone/SKILL.md +0 -746
  1146. package/plugins/cursor-pbr/skills/milestone/templates/audit-report.md.tmpl +0 -49
  1147. package/plugins/cursor-pbr/skills/milestone/templates/stats-file.md.tmpl +0 -31
  1148. package/plugins/cursor-pbr/skills/note/SKILL.md +0 -214
  1149. package/plugins/cursor-pbr/skills/pause/SKILL.md +0 -248
  1150. package/plugins/cursor-pbr/skills/pause/templates/continue-here.md.tmpl +0 -72
  1151. package/plugins/cursor-pbr/skills/plan/SKILL.md +0 -663
  1152. package/plugins/cursor-pbr/skills/plan/templates/checker-prompt.md.tmpl +0 -22
  1153. package/plugins/cursor-pbr/skills/plan/templates/gap-closure-prompt.md.tmpl +0 -33
  1154. package/plugins/cursor-pbr/skills/plan/templates/planner-prompt.md.tmpl +0 -39
  1155. package/plugins/cursor-pbr/skills/plan/templates/researcher-prompt.md.tmpl +0 -20
  1156. package/plugins/cursor-pbr/skills/plan/templates/revision-prompt.md.tmpl +0 -24
  1157. package/plugins/cursor-pbr/skills/quick/SKILL.md +0 -376
  1158. package/plugins/cursor-pbr/skills/resume/SKILL.md +0 -399
  1159. package/plugins/cursor-pbr/skills/review/SKILL.md +0 -654
  1160. package/plugins/cursor-pbr/skills/review/templates/debugger-prompt.md.tmpl +0 -61
  1161. package/plugins/cursor-pbr/skills/review/templates/gap-planner-prompt.md.tmpl +0 -41
  1162. package/plugins/cursor-pbr/skills/review/templates/verifier-prompt.md.tmpl +0 -116
  1163. package/plugins/cursor-pbr/skills/scan/SKILL.md +0 -300
  1164. package/plugins/cursor-pbr/skills/scan/templates/mapper-prompt.md.tmpl +0 -202
  1165. package/plugins/cursor-pbr/skills/setup/SKILL.md +0 -296
  1166. package/plugins/cursor-pbr/skills/shared/commit-planning-docs.md +0 -36
  1167. package/plugins/cursor-pbr/skills/shared/config-loading.md +0 -103
  1168. package/plugins/cursor-pbr/skills/shared/context-budget.md +0 -41
  1169. package/plugins/cursor-pbr/skills/shared/context-loader-task.md +0 -87
  1170. package/plugins/cursor-pbr/skills/shared/digest-select.md +0 -80
  1171. package/plugins/cursor-pbr/skills/shared/domain-probes.md +0 -126
  1172. package/plugins/cursor-pbr/skills/shared/error-reporting.md +0 -81
  1173. package/plugins/cursor-pbr/skills/shared/gate-prompts.md +0 -389
  1174. package/plugins/cursor-pbr/skills/shared/phase-argument-parsing.md +0 -46
  1175. package/plugins/cursor-pbr/skills/shared/progress-display.md +0 -53
  1176. package/plugins/cursor-pbr/skills/shared/revision-loop.md +0 -82
  1177. package/plugins/cursor-pbr/skills/shared/state-loading.md +0 -63
  1178. package/plugins/cursor-pbr/skills/shared/state-update.md +0 -162
  1179. package/plugins/cursor-pbr/skills/shared/universal-anti-patterns.md +0 -38
  1180. package/plugins/cursor-pbr/skills/status/SKILL.md +0 -362
  1181. package/plugins/cursor-pbr/skills/statusline/SKILL.md +0 -150
  1182. package/plugins/cursor-pbr/skills/todo/SKILL.md +0 -280
  1183. package/plugins/cursor-pbr/templates/CONTEXT.md.tmpl +0 -53
  1184. package/plugins/cursor-pbr/templates/INTEGRATION-REPORT.md.tmpl +0 -152
  1185. package/plugins/cursor-pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -98
  1186. package/plugins/cursor-pbr/templates/ROADMAP.md.tmpl +0 -41
  1187. package/plugins/cursor-pbr/templates/SUMMARY.md.tmpl +0 -82
  1188. package/plugins/cursor-pbr/templates/VERIFICATION-DETAIL.md.tmpl +0 -117
  1189. package/plugins/cursor-pbr/templates/codebase/ARCHITECTURE.md.tmpl +0 -98
  1190. package/plugins/cursor-pbr/templates/codebase/CONCERNS.md.tmpl +0 -93
  1191. package/plugins/cursor-pbr/templates/codebase/CONVENTIONS.md.tmpl +0 -104
  1192. package/plugins/cursor-pbr/templates/codebase/INTEGRATIONS.md.tmpl +0 -78
  1193. package/plugins/cursor-pbr/templates/codebase/STACK.md.tmpl +0 -78
  1194. package/plugins/cursor-pbr/templates/codebase/STRUCTURE.md.tmpl +0 -80
  1195. package/plugins/cursor-pbr/templates/codebase/TESTING.md.tmpl +0 -107
  1196. package/plugins/cursor-pbr/templates/continue-here.md.tmpl +0 -74
  1197. package/plugins/cursor-pbr/templates/prompt-partials/phase-project-context.md.tmpl +0 -38
  1198. package/plugins/cursor-pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
  1199. package/plugins/cursor-pbr/templates/research/STACK.md.tmpl +0 -71
  1200. package/plugins/cursor-pbr/templates/research/SUMMARY.md.tmpl +0 -112
  1201. package/plugins/cursor-pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
  1202. package/plugins/cursor-pbr/templates/research-outputs/project-research.md.tmpl +0 -99
  1203. package/plugins/cursor-pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
  1204. package/plugins/pbr/references/agent-interactions.md +0 -134
  1205. package/plugins/pbr/references/checkpoints.md +0 -157
  1206. package/plugins/pbr/references/pbr-rules.md +0 -194
  1207. package/plugins/pbr/references/planning-config.md +0 -213
  1208. package/plugins/pbr/references/subagent-coordination.md +0 -119
  1209. package/plugins/pbr/references/ui-formatting.md +0 -444
  1210. package/plugins/pbr/references/verification-patterns.md +0 -198
  1211. package/plugins/pbr/scripts/validate-plugin-structure.js +0 -183
  1212. package/plugins/pbr/skills/milestone/templates/audit-report.md.tmpl +0 -48
  1213. package/plugins/pbr/skills/shared/progress-display.md +0 -53
  1214. package/plugins/pbr/skills/shared/state-loading.md +0 -62
  1215. package/plugins/pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -97
  1216. package/plugins/pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
  1217. package/plugins/pbr/templates/research/STACK.md.tmpl +0 -71
  1218. package/plugins/pbr/templates/research/SUMMARY.md.tmpl +0 -112
  1219. package/plugins/pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
  1220. package/plugins/pbr/templates/research-outputs/project-research.md.tmpl +0 -99
  1221. package/plugins/pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
  1222. /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
+ // Skip malformed JSON lines
50
+ }
51
+ }
52
+ } catch (_e) {
53
+ // Skip unreadable files
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
+ // Budget file may not exist or be unreadable — not an error
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
+ };