@sienklogic/plan-build-run 2.19.0 → 2.19.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 (977) hide show
  1. package/CHANGELOG.md +1265 -320
  2. package/CLAUDE.md +56 -34
  3. package/LICENSE +2 -1
  4. package/README.md +412 -177
  5. package/bin/install.js +2752 -0
  6. package/dashboard/bin/cli.cjs +96 -0
  7. package/dashboard/bin/stop.cjs +129 -0
  8. package/dashboard/eslint.config.js +37 -0
  9. package/dashboard/index.html +20 -0
  10. package/dashboard/package.json +27 -25
  11. package/dashboard/server/index.js +142 -0
  12. package/dashboard/server/lib/frontmatter.js +92 -0
  13. package/dashboard/server/middleware/static.js +35 -0
  14. package/dashboard/server/package.json +16 -0
  15. package/dashboard/server/routes/agents.js +213 -0
  16. package/dashboard/server/routes/config.js +64 -0
  17. package/dashboard/server/routes/health.js +95 -0
  18. package/dashboard/server/routes/incidents.js +78 -0
  19. package/dashboard/server/routes/intel.js +69 -0
  20. package/dashboard/server/routes/memory.js +107 -0
  21. package/dashboard/server/routes/planning.js +234 -0
  22. package/dashboard/server/routes/progress.js +77 -0
  23. package/dashboard/server/routes/projects.js +36 -0
  24. package/dashboard/server/routes/requirements.js +40 -0
  25. package/dashboard/server/routes/roadmap.js +69 -0
  26. package/dashboard/server/routes/sessions.js +70 -0
  27. package/dashboard/server/routes/status.js +25 -0
  28. package/dashboard/server/routes/telemetry.js +214 -0
  29. package/dashboard/server/services/file-watcher.js +105 -0
  30. package/dashboard/server/services/planning-reader.js +741 -0
  31. package/dashboard/server/test/cli.test.js +34 -0
  32. package/dashboard/server/test/frontmatter.test.js +104 -0
  33. package/dashboard/server/test/isolation.test.js +32 -0
  34. package/dashboard/server/test/planning-reader.test.js +151 -0
  35. package/dashboard/server/test/routes.test.js +91 -0
  36. package/dashboard/server/test/ws.test.js +81 -0
  37. package/dashboard/server/ws.js +96 -0
  38. package/dashboard/src/App.jsx +165 -0
  39. package/dashboard/src/components/charts/BudgetBars.jsx +42 -0
  40. package/dashboard/src/components/charts/ContextRadar.jsx +34 -0
  41. package/dashboard/src/components/charts/PhaseDonut.jsx +66 -0
  42. package/dashboard/src/components/charts/SuccessTrend.jsx +45 -0
  43. package/dashboard/src/components/charts/TokenChart.jsx +55 -0
  44. package/dashboard/src/components/charts/index.js +5 -0
  45. package/dashboard/src/components/config/CfgSection.jsx +93 -0
  46. package/dashboard/src/components/layout/Header.jsx +89 -0
  47. package/dashboard/src/components/layout/ProjectSwitcher.jsx +160 -0
  48. package/dashboard/src/components/layout/Sidebar.jsx +161 -0
  49. package/dashboard/src/components/ui/AutoModeBanner.jsx +138 -0
  50. package/dashboard/src/components/ui/BackButton.jsx +27 -0
  51. package/dashboard/src/components/ui/Badge.jsx +27 -0
  52. package/dashboard/src/components/ui/Card.jsx +23 -0
  53. package/dashboard/src/components/ui/ChartTooltip.jsx +48 -0
  54. package/dashboard/src/components/ui/CheckpointBox.jsx +110 -0
  55. package/dashboard/src/components/ui/CodeBlock.jsx +27 -0
  56. package/dashboard/src/components/ui/ConfidenceBadge.jsx +20 -0
  57. package/dashboard/src/components/ui/ConfirmModal.jsx +161 -0
  58. package/dashboard/src/components/ui/ConnectionBanner.jsx +60 -0
  59. package/dashboard/src/components/ui/ErrorBoundary.jsx +106 -0
  60. package/dashboard/src/components/ui/ErrorBox.jsx +107 -0
  61. package/dashboard/src/components/ui/KeyValue.jsx +33 -0
  62. package/dashboard/src/components/ui/LoadingSkeleton.jsx +84 -0
  63. package/dashboard/src/components/ui/MetricCard.jsx +58 -0
  64. package/dashboard/src/components/ui/NextUpBlock.jsx +92 -0
  65. package/dashboard/src/components/ui/NumberInput.jsx +44 -0
  66. package/dashboard/src/components/ui/PBRBanner.jsx +47 -0
  67. package/dashboard/src/components/ui/PipelineView.jsx +130 -0
  68. package/dashboard/src/components/ui/ProgressBar.jsx +28 -0
  69. package/dashboard/src/components/ui/ProgressDisplay.jsx +47 -0
  70. package/dashboard/src/components/ui/QualityGateBadge.jsx +15 -0
  71. package/dashboard/src/components/ui/SectionTitle.jsx +35 -0
  72. package/dashboard/src/components/ui/SelectInput.jsx +45 -0
  73. package/dashboard/src/components/ui/StatusDot.jsx +51 -0
  74. package/dashboard/src/components/ui/StatusSymbol.jsx +49 -0
  75. package/dashboard/src/components/ui/TabBar.jsx +41 -0
  76. package/dashboard/src/components/ui/TextInput.jsx +42 -0
  77. package/dashboard/src/components/ui/Toast.jsx +117 -0
  78. package/dashboard/src/components/ui/Toggle.jsx +70 -0
  79. package/dashboard/src/components/ui/index.js +29 -0
  80. package/dashboard/src/hooks/useDocumentTitle.js +16 -0
  81. package/dashboard/src/hooks/useFetch.js +50 -0
  82. package/dashboard/src/hooks/useToast.jsx +43 -0
  83. package/dashboard/src/hooks/useWebSocket.js +103 -0
  84. package/dashboard/src/lib/api.js +112 -0
  85. package/dashboard/src/lib/configSchema.js +189 -0
  86. package/dashboard/src/lib/constants.js +22 -0
  87. package/dashboard/src/main.jsx +15 -0
  88. package/dashboard/src/pages/AgentsPage.jsx +191 -0
  89. package/dashboard/src/pages/ConfigPage.jsx +298 -0
  90. package/dashboard/src/pages/HooksPage.jsx +412 -0
  91. package/dashboard/src/pages/IncidentsPage.jsx +135 -0
  92. package/dashboard/src/pages/IntelPage.jsx +193 -0
  93. package/dashboard/src/pages/LiveFeed.jsx +274 -0
  94. package/dashboard/src/pages/MemoryPage.jsx +107 -0
  95. package/dashboard/src/pages/OnboardingPage.jsx +117 -0
  96. package/dashboard/src/pages/Overview.jsx +360 -0
  97. package/dashboard/src/pages/PhaseDetailView.jsx +216 -0
  98. package/dashboard/src/pages/PlanningPage.jsx +181 -0
  99. package/dashboard/src/pages/ProgressPage.jsx +249 -0
  100. package/dashboard/src/pages/ResearchPage.jsx +129 -0
  101. package/dashboard/src/pages/RoadmapPage.jsx +251 -0
  102. package/dashboard/src/pages/SessionsPage.jsx +117 -0
  103. package/dashboard/src/pages/Telemetry.jsx +166 -0
  104. package/dashboard/src/pages/planning/DecisionsTab.jsx +153 -0
  105. package/dashboard/src/pages/planning/FilesTab.jsx +420 -0
  106. package/dashboard/src/pages/planning/MilestoneDetail.jsx +319 -0
  107. package/dashboard/src/pages/planning/MilestonesTab.jsx +151 -0
  108. package/dashboard/src/pages/planning/NotesTab.jsx +251 -0
  109. package/dashboard/src/pages/planning/PhasesTab.jsx +218 -0
  110. package/dashboard/src/pages/planning/QuickTab.jsx +50 -0
  111. package/dashboard/src/pages/planning/ResearchTab.jsx +103 -0
  112. package/dashboard/src/pages/planning/TodosTab.jsx +297 -0
  113. package/dashboard/src/theme/ThemeProvider.jsx +38 -0
  114. package/dashboard/src/theme/tokens.js +17 -0
  115. package/dashboard/tests/components/ConfirmModal.test.jsx +179 -0
  116. package/dashboard/tests/components/ConnectionBanner.test.jsx +37 -0
  117. package/dashboard/tests/components/ErrorBoundary.test.jsx +59 -0
  118. package/dashboard/tests/components/LoadingSkeleton.test.jsx +46 -0
  119. package/dashboard/tests/components/ToastContainer.test.jsx +47 -0
  120. package/dashboard/tests/components/Toggle.test.jsx +61 -0
  121. package/dashboard/tests/hooks/useFetch.test.jsx +77 -0
  122. package/dashboard/tests/hooks/useToast.test.jsx +78 -0
  123. package/dashboard/tests/hooks/useWebSocket.test.jsx +128 -0
  124. package/dashboard/tests/pages/ConfigPage.test.jsx +199 -0
  125. package/dashboard/tests/pages/PlanningPage.test.jsx +119 -0
  126. package/dashboard/tests/pages/planning/FilesTab.test.jsx +198 -0
  127. package/dashboard/tests/pages/planning/NotesTab.test.jsx +178 -0
  128. package/dashboard/tests/pages/planning/TodosTab.test.jsx +188 -0
  129. package/dashboard/tests/performance.test.jsx +46 -0
  130. package/dashboard/tests/routes/config.test.js +98 -0
  131. package/dashboard/tests/routes/health.test.js +40 -0
  132. package/dashboard/tests/routes/planning.test.js +112 -0
  133. package/dashboard/tests/routes/roadmap.test.js +91 -0
  134. package/dashboard/tests/routes/status.test.js +131 -0
  135. package/dashboard/tests/server/planning-reader.test.js +153 -0
  136. package/dashboard/tests/setup.js +7 -0
  137. package/dashboard/vite.config.js +41 -0
  138. package/package.json +55 -40
  139. package/plan-build-run/bin/config-schema.json +1420 -0
  140. package/plugins/pbr/.claude-plugin/plugin.json +1 -1
  141. package/plugins/pbr/CLAUDE.md +19 -0
  142. package/plugins/pbr/UI-CONSISTENCY-GAPS.md +1 -1
  143. package/plugins/pbr/agents/advisor-researcher.md +100 -0
  144. package/plugins/pbr/agents/audit.md +205 -89
  145. package/plugins/pbr/agents/codebase-mapper.md +158 -23
  146. package/plugins/pbr/agents/debugger.md +216 -34
  147. package/plugins/pbr/agents/dev-sync.md +206 -0
  148. package/plugins/pbr/agents/executor.md +717 -39
  149. package/plugins/pbr/agents/general.md +71 -6
  150. package/plugins/pbr/agents/integration-checker.md +146 -30
  151. package/plugins/pbr/agents/intel-updater.md +332 -0
  152. package/plugins/pbr/agents/nyquist-auditor.md +253 -0
  153. package/plugins/pbr/agents/plan-checker.md +265 -65
  154. package/plugins/pbr/agents/planner.md +440 -42
  155. package/plugins/pbr/agents/researcher.md +223 -36
  156. package/plugins/pbr/agents/roadmapper.md +397 -0
  157. package/plugins/pbr/agents/synthesizer.md +170 -26
  158. package/plugins/pbr/agents/ui-checker.md +203 -0
  159. package/plugins/pbr/agents/ui-researcher.md +224 -0
  160. package/plugins/pbr/agents/verifier.md +495 -47
  161. package/plugins/pbr/commands/add-phase.md +75 -0
  162. package/plugins/pbr/commands/add-todo.md +8 -0
  163. package/plugins/pbr/commands/audit-fix.md +5 -0
  164. package/plugins/pbr/commands/audit-milestone.md +8 -0
  165. package/plugins/pbr/commands/autonomous.md +5 -0
  166. package/plugins/pbr/commands/backlog.md +6 -0
  167. package/plugins/pbr/commands/check-todos.md +8 -0
  168. package/plugins/pbr/commands/complete-milestone.md +8 -0
  169. package/plugins/pbr/commands/config.md +1 -1
  170. package/plugins/pbr/commands/discuss-phase.md +6 -0
  171. package/plugins/pbr/commands/do.md +5 -0
  172. package/plugins/pbr/commands/execute-phase.md +6 -0
  173. package/plugins/pbr/commands/fast.md +6 -0
  174. package/plugins/pbr/commands/forensics.md +6 -0
  175. package/plugins/pbr/commands/import.md +1 -1
  176. package/plugins/pbr/commands/insert-phase.md +65 -0
  177. package/plugins/pbr/commands/intel.md +5 -0
  178. package/plugins/pbr/commands/join-discord.md +11 -0
  179. package/plugins/pbr/commands/list-phase-assumptions.md +5 -0
  180. package/plugins/pbr/commands/map-codebase.md +6 -0
  181. package/plugins/pbr/commands/milestone-summary.md +6 -0
  182. package/plugins/pbr/commands/new-milestone.md +8 -0
  183. package/plugins/pbr/commands/new-project.md +6 -0
  184. package/plugins/pbr/commands/pause-work.md +5 -0
  185. package/plugins/pbr/commands/plan-milestone-gaps.md +7 -0
  186. package/plugins/pbr/commands/plan-phase.md +6 -0
  187. package/plugins/pbr/commands/plant-seed.md +6 -0
  188. package/plugins/pbr/commands/profile-user.md +5 -0
  189. package/plugins/pbr/commands/profile.md +5 -0
  190. package/plugins/pbr/commands/progress.md +6 -0
  191. package/plugins/pbr/commands/quick.md +1 -1
  192. package/plugins/pbr/commands/reapply-patches.md +47 -0
  193. package/plugins/pbr/commands/release.md +6 -0
  194. package/plugins/pbr/commands/remove-phase.md +66 -0
  195. package/plugins/pbr/commands/research-phase.md +59 -0
  196. package/plugins/pbr/commands/resume-work.md +5 -0
  197. package/plugins/pbr/commands/seed.md +6 -0
  198. package/plugins/pbr/commands/session-report.md +5 -0
  199. package/plugins/pbr/commands/set-profile.md +6 -0
  200. package/plugins/pbr/commands/settings.md +5 -0
  201. package/plugins/pbr/commands/setup.md +1 -1
  202. package/plugins/pbr/commands/ship.md +5 -0
  203. package/plugins/pbr/commands/stats.md +6 -0
  204. package/plugins/pbr/commands/test.md +5 -0
  205. package/plugins/pbr/commands/thread.md +6 -0
  206. package/plugins/pbr/commands/todo.md +1 -1
  207. package/plugins/pbr/commands/ui-phase.md +5 -0
  208. package/plugins/pbr/commands/ui-review.md +5 -0
  209. package/plugins/pbr/commands/undo.md +5 -0
  210. package/plugins/pbr/commands/update.md +37 -0
  211. package/plugins/pbr/commands/validate-phase.md +5 -0
  212. package/plugins/pbr/commands/verify-work.md +6 -0
  213. package/plugins/pbr/dashboard/package-lock.json +6 -0
  214. package/plugins/pbr/dist/architecture-guard.js +59 -0
  215. package/plugins/pbr/dist/audit-dimensions.js +556 -0
  216. package/plugins/pbr/dist/auto-continue.js +277 -0
  217. package/plugins/pbr/dist/block-skill-self-read.js +124 -0
  218. package/plugins/pbr/dist/check-agent-state-write.js +63 -0
  219. package/plugins/pbr/dist/check-config-change.js +162 -0
  220. package/plugins/pbr/dist/check-cross-plugin-sync.js +93 -0
  221. package/plugins/pbr/dist/check-dangerous-commands.js +193 -0
  222. package/plugins/pbr/dist/check-direct-state-write.js +37 -0
  223. package/plugins/pbr/dist/check-doc-sprawl.js +102 -0
  224. package/plugins/pbr/dist/check-phase-boundary.js +191 -0
  225. package/plugins/pbr/dist/check-plan-format.js +241 -0
  226. package/plugins/pbr/dist/check-read-first.js +345 -0
  227. package/plugins/pbr/dist/check-roadmap-sync.js +503 -0
  228. package/plugins/pbr/dist/check-skill-workflow.js +354 -0
  229. package/plugins/pbr/dist/check-state-sync.js +658 -0
  230. package/plugins/pbr/dist/check-subagent-output.js +452 -0
  231. package/plugins/pbr/dist/check-summary-gate.js +199 -0
  232. package/plugins/pbr/dist/context-bridge.js +425 -0
  233. package/plugins/pbr/dist/context-budget-check.js +442 -0
  234. package/plugins/pbr/dist/context-quality.js +271 -0
  235. package/plugins/pbr/dist/enforce-context-budget.js +138 -0
  236. package/plugins/pbr/dist/enforce-pbr-workflow.js +277 -0
  237. package/plugins/pbr/dist/event-handler.js +202 -0
  238. package/plugins/pbr/dist/event-logger.js +125 -0
  239. package/plugins/pbr/dist/feedback-loop.js +172 -0
  240. package/plugins/pbr/dist/graph-update.js +422 -0
  241. package/plugins/pbr/dist/hook-logger.js +114 -0
  242. package/plugins/pbr/dist/hook-server-client.js +361 -0
  243. package/plugins/pbr/dist/hook-server.js +606 -0
  244. package/plugins/pbr/dist/hooks-schema.json +87 -0
  245. package/plugins/pbr/dist/instructions-loaded.js +173 -0
  246. package/plugins/pbr/dist/intercept-plan-mode.js +81 -0
  247. package/plugins/pbr/dist/log-notification.js +131 -0
  248. package/plugins/pbr/dist/log-subagent.js +349 -0
  249. package/plugins/pbr/dist/log-tool-failure.js +140 -0
  250. package/plugins/pbr/dist/milestone-learnings.js +569 -0
  251. package/plugins/pbr/dist/pbr-tools.js +2044 -0
  252. package/plugins/pbr/dist/post-bash-triage.js +154 -0
  253. package/plugins/pbr/dist/post-compact.js +135 -0
  254. package/plugins/pbr/dist/post-hoc.js +286 -0
  255. package/plugins/pbr/dist/post-write-dispatch.js +279 -0
  256. package/plugins/pbr/dist/post-write-quality.js +208 -0
  257. package/plugins/pbr/dist/pre-bash-dispatch.js +218 -0
  258. package/plugins/pbr/dist/pre-skill-dispatch.js +114 -0
  259. package/plugins/pbr/dist/pre-task-dispatch.js +297 -0
  260. package/plugins/pbr/dist/pre-write-dispatch.js +234 -0
  261. package/plugins/pbr/dist/progress-tracker.js +198 -0
  262. package/plugins/pbr/dist/prompt-guard.js +114 -0
  263. package/plugins/pbr/dist/prompt-routing.js +209 -0
  264. package/plugins/pbr/dist/quick-status.js +179 -0
  265. package/plugins/pbr/dist/record-incident.js +37 -0
  266. package/plugins/pbr/dist/run-hook.js +144 -0
  267. package/plugins/pbr/dist/session-cleanup.js +683 -0
  268. package/plugins/pbr/dist/session-tracker.js +124 -0
  269. package/plugins/pbr/dist/status-line.js +847 -0
  270. package/plugins/pbr/dist/suggest-compact.js +315 -0
  271. package/plugins/pbr/dist/sync-context-to-claude.js +100 -0
  272. package/plugins/pbr/dist/task-completed.js +206 -0
  273. package/plugins/pbr/dist/track-context-budget.js +432 -0
  274. package/plugins/pbr/dist/track-user-gates.js +88 -0
  275. package/plugins/pbr/dist/trust-tracker.js +193 -0
  276. package/plugins/pbr/dist/validate-commit.js +271 -0
  277. package/plugins/pbr/dist/validate-skill-args.js +222 -0
  278. package/plugins/pbr/dist/validate-task.js +301 -0
  279. package/plugins/pbr/dist/worktree-create.js +144 -0
  280. package/plugins/pbr/dist/worktree-remove.js +147 -0
  281. package/plugins/pbr/hooks/hooks.json +143 -60
  282. package/plugins/pbr/references/agent-contracts.md +39 -8
  283. package/plugins/pbr/references/agent-teams.md +3 -3
  284. package/plugins/pbr/references/archive/checkpoints.md +189 -0
  285. package/plugins/pbr/references/archive/context-quality-tiers.md +45 -0
  286. package/plugins/pbr/references/archive/hook-ordering.md +89 -0
  287. package/plugins/pbr/references/archive/limitations.md +106 -0
  288. package/plugins/pbr/references/archive/pbr-rules.md +194 -0
  289. package/plugins/pbr/references/archive/pbr-tools-cli.md +415 -0
  290. package/plugins/pbr/references/archive/pretooluse-jsonl-behavior.md +58 -0
  291. package/plugins/pbr/references/archive/signal-files.md +41 -0
  292. package/plugins/pbr/references/archive/tmux-setup.md +288 -0
  293. package/plugins/pbr/references/archive/verification-matrix.md +34 -0
  294. package/plugins/pbr/references/archive/verification-patterns.md +277 -0
  295. package/plugins/pbr/references/archive/worktree-sparse-checkout.md +86 -0
  296. package/plugins/pbr/references/behavioral-contexts.md +53 -0
  297. package/plugins/pbr/references/checkpoints.md +723 -104
  298. package/plugins/pbr/references/config-reference.md +472 -10
  299. package/plugins/pbr/references/continuation-format.md +1 -0
  300. package/plugins/pbr/references/decimal-phase-calculation.md +65 -0
  301. package/plugins/pbr/references/deviation-rules.md +12 -0
  302. package/plugins/pbr/references/git-integration.md +110 -27
  303. package/plugins/pbr/references/git-planning-commit.md +35 -0
  304. package/plugins/pbr/references/model-profile-resolution.md +34 -0
  305. package/plugins/pbr/references/model-profiles.md +90 -7
  306. package/plugins/pbr/references/model-selection.md +1 -1
  307. package/plugins/pbr/references/node-repair.md +48 -0
  308. package/plugins/pbr/references/plan-authoring.md +65 -0
  309. package/plugins/pbr/references/plan-format.md +161 -10
  310. package/plugins/pbr/references/questioning.md +138 -49
  311. package/plugins/pbr/references/reading-verification.md +4 -4
  312. package/plugins/pbr/references/tdd.md +263 -0
  313. package/plugins/pbr/references/ui-brand.md +449 -0
  314. package/plugins/pbr/references/verification-overrides.md +39 -0
  315. package/plugins/pbr/references/verification-patterns.md +529 -113
  316. package/plugins/pbr/scripts/architecture-guard.js +59 -0
  317. package/plugins/pbr/scripts/audit-checks/behavioral-compliance.js +2098 -0
  318. package/plugins/pbr/scripts/audit-checks/error-analysis.js +989 -0
  319. package/plugins/pbr/scripts/audit-checks/feature-verification.js +723 -0
  320. package/plugins/pbr/scripts/audit-checks/index.js +433 -0
  321. package/plugins/pbr/scripts/audit-checks/infrastructure.js +816 -0
  322. package/plugins/pbr/scripts/audit-checks/quality-metrics.js +452 -0
  323. package/plugins/pbr/scripts/audit-checks/session-quality.js +980 -0
  324. package/plugins/pbr/scripts/audit-checks/si-agent-hook-config-checks.js +466 -0
  325. package/plugins/pbr/scripts/audit-checks/si-cross-cutting-checks.js +272 -0
  326. package/plugins/pbr/scripts/audit-checks/si-skill-checks.js +424 -0
  327. package/plugins/pbr/scripts/audit-checks/workflow-compliance.js +1211 -0
  328. package/plugins/pbr/scripts/audit-dimensions.js +556 -0
  329. package/plugins/pbr/scripts/auto-continue.js +192 -31
  330. package/plugins/pbr/scripts/block-skill-self-read.js +124 -0
  331. package/plugins/pbr/scripts/check-agent-state-write.js +63 -0
  332. package/plugins/pbr/scripts/check-config-change.js +162 -0
  333. package/plugins/pbr/scripts/check-cross-plugin-sync.js +93 -0
  334. package/plugins/pbr/scripts/check-dangerous-commands.js +18 -5
  335. package/plugins/pbr/scripts/check-direct-state-write.js +37 -0
  336. package/plugins/pbr/scripts/check-phase-boundary.js +3 -8
  337. package/plugins/pbr/scripts/check-plan-format.js +166 -277
  338. package/plugins/pbr/scripts/check-read-first.js +345 -0
  339. package/plugins/pbr/scripts/check-roadmap-sync.js +167 -10
  340. package/plugins/pbr/scripts/check-skill-workflow.js +24 -27
  341. package/plugins/pbr/scripts/check-state-sync.js +339 -215
  342. package/plugins/pbr/scripts/check-subagent-output.js +338 -276
  343. package/plugins/pbr/scripts/check-summary-gate.js +2 -1
  344. package/plugins/pbr/scripts/config-schema.json +1247 -95
  345. package/plugins/pbr/scripts/context-bridge.js +425 -0
  346. package/plugins/pbr/scripts/context-budget-check.js +169 -14
  347. package/plugins/pbr/scripts/context-quality.js +271 -0
  348. package/plugins/pbr/scripts/enforce-context-budget.js +138 -0
  349. package/plugins/pbr/scripts/enforce-pbr-workflow.js +277 -0
  350. package/plugins/pbr/scripts/event-handler.js +127 -87
  351. package/plugins/pbr/scripts/event-logger.js +58 -25
  352. package/plugins/pbr/scripts/feedback-loop.js +172 -0
  353. package/plugins/pbr/scripts/graph-update.js +422 -0
  354. package/plugins/pbr/scripts/hook-logger.js +69 -35
  355. package/plugins/pbr/scripts/hook-server-client.js +361 -0
  356. package/plugins/pbr/scripts/hook-server.js +606 -0
  357. package/plugins/pbr/scripts/hooks-schema.json +13 -5
  358. package/plugins/pbr/scripts/instructions-loaded.js +173 -0
  359. package/plugins/pbr/scripts/intent-router.cjs +147 -0
  360. package/plugins/pbr/scripts/intercept-plan-mode.js +52 -18
  361. package/plugins/pbr/scripts/lib/alternatives.js +203 -0
  362. package/plugins/pbr/scripts/lib/audit.js +65 -0
  363. package/plugins/pbr/scripts/lib/auto-cleanup.js +221 -0
  364. package/plugins/pbr/scripts/lib/auto-verify.js +103 -0
  365. package/plugins/pbr/scripts/lib/autonomy.js +91 -0
  366. package/plugins/pbr/scripts/lib/build.js +719 -0
  367. package/plugins/pbr/scripts/lib/ci-fix-loop.js +228 -0
  368. package/plugins/pbr/scripts/lib/circuit-state.js +133 -0
  369. package/plugins/pbr/scripts/lib/commands.js +483 -0
  370. package/plugins/pbr/scripts/lib/completion.js +377 -0
  371. package/plugins/pbr/scripts/lib/compound.js +216 -0
  372. package/plugins/pbr/scripts/lib/config.js +1315 -0
  373. package/plugins/pbr/scripts/lib/context.js +254 -0
  374. package/plugins/pbr/scripts/lib/contextual-help.js +207 -0
  375. package/plugins/pbr/scripts/lib/convention-detector.js +413 -0
  376. package/plugins/pbr/scripts/lib/core.js +1569 -0
  377. package/plugins/pbr/scripts/lib/dashboard-launch.js +364 -0
  378. package/plugins/pbr/scripts/lib/data-hygiene.js +179 -0
  379. package/plugins/pbr/scripts/lib/decision-extraction.js +183 -0
  380. package/plugins/pbr/scripts/lib/decisions.js +194 -0
  381. package/plugins/pbr/scripts/lib/dependency-break.js +147 -0
  382. package/plugins/pbr/scripts/lib/format-validators.js +1050 -0
  383. package/plugins/pbr/scripts/lib/frontmatter.js +302 -0
  384. package/plugins/pbr/scripts/lib/gates/advisories.js +129 -0
  385. package/plugins/pbr/scripts/lib/gates/build-dependency.js +115 -0
  386. package/plugins/pbr/scripts/lib/gates/build-executor.js +104 -0
  387. package/plugins/pbr/scripts/lib/gates/doc-existence.js +46 -0
  388. package/plugins/pbr/scripts/lib/gates/helpers.js +93 -0
  389. package/plugins/pbr/scripts/lib/gates/inline-execution.js +185 -0
  390. package/plugins/pbr/scripts/lib/gates/milestone-complete.js +136 -0
  391. package/plugins/pbr/scripts/lib/gates/milestone-summary.js +119 -0
  392. package/plugins/pbr/scripts/lib/gates/multi-phase-loader.js +147 -0
  393. package/plugins/pbr/scripts/lib/gates/plan-executor.js +36 -0
  394. package/plugins/pbr/scripts/lib/gates/plan-validation.js +114 -0
  395. package/plugins/pbr/scripts/lib/gates/quick-executor.js +76 -0
  396. package/plugins/pbr/scripts/lib/gates/review-planner.js +61 -0
  397. package/plugins/pbr/scripts/lib/gates/review-verifier.js +69 -0
  398. package/plugins/pbr/scripts/lib/gates/rich-agent-context.js +143 -0
  399. package/plugins/pbr/scripts/lib/gates/user-confirmation.js +93 -0
  400. package/plugins/pbr/scripts/lib/graph-cli.js +89 -0
  401. package/plugins/pbr/scripts/lib/graph.js +553 -0
  402. package/plugins/pbr/scripts/lib/health-checks.js +107 -0
  403. package/plugins/pbr/scripts/lib/health-phase06.js +120 -0
  404. package/plugins/pbr/scripts/lib/health.js +133 -0
  405. package/plugins/pbr/scripts/lib/help.js +151 -0
  406. package/plugins/pbr/scripts/lib/history.js +150 -0
  407. package/plugins/pbr/scripts/lib/hypothesis-runner.js +127 -0
  408. package/plugins/pbr/scripts/lib/impact-analysis.js +319 -0
  409. package/plugins/pbr/scripts/lib/incidents.js +190 -0
  410. package/plugins/pbr/scripts/lib/init.js +643 -0
  411. package/plugins/pbr/scripts/lib/insights-parser.js +320 -0
  412. package/plugins/pbr/scripts/lib/intel.js +653 -0
  413. package/plugins/pbr/scripts/lib/learnings.js +511 -0
  414. package/plugins/pbr/scripts/lib/local-llm/client.js +237 -0
  415. package/plugins/pbr/scripts/lib/local-llm/health.js +12 -0
  416. package/plugins/pbr/scripts/lib/local-llm/index.js +89 -0
  417. package/plugins/pbr/scripts/lib/local-llm/metrics.js +20 -0
  418. package/plugins/pbr/scripts/lib/local-llm/operations/classify-artifact.js +4 -0
  419. package/plugins/pbr/scripts/lib/local-llm/operations/classify-commit.js +4 -0
  420. package/plugins/pbr/scripts/lib/local-llm/operations/classify-error.js +4 -0
  421. package/plugins/pbr/scripts/lib/local-llm/operations/classify-file-intent.js +4 -0
  422. package/plugins/pbr/scripts/lib/local-llm/operations/score-source.js +72 -0
  423. package/plugins/pbr/scripts/lib/local-llm/operations/summarize-context.js +62 -0
  424. package/plugins/pbr/scripts/lib/local-llm/operations/triage-test-output.js +12 -0
  425. package/plugins/pbr/scripts/lib/local-llm/operations/validate-task.js +4 -0
  426. package/plugins/pbr/scripts/lib/local-llm/router.js +101 -0
  427. package/plugins/pbr/scripts/lib/local-llm/shadow.js +60 -0
  428. package/plugins/pbr/scripts/lib/local-llm/threshold-tuner.js +118 -0
  429. package/plugins/pbr/scripts/lib/migrate.js +298 -0
  430. package/plugins/pbr/scripts/lib/milestone.js +306 -0
  431. package/plugins/pbr/scripts/lib/negative-knowledge.js +194 -0
  432. package/plugins/pbr/scripts/lib/notification-throttle.js +141 -0
  433. package/plugins/pbr/scripts/lib/onboarding-generator.js +288 -0
  434. package/plugins/pbr/scripts/lib/parse-args.js +134 -0
  435. package/plugins/pbr/scripts/lib/pattern-routing.js +55 -0
  436. package/plugins/pbr/scripts/lib/patterns.js +272 -0
  437. package/plugins/pbr/scripts/lib/perf.js +190 -0
  438. package/plugins/pbr/scripts/lib/phase.js +1027 -0
  439. package/plugins/pbr/scripts/lib/pid-lock.js +154 -0
  440. package/plugins/pbr/scripts/lib/post-hoc.js +160 -0
  441. package/plugins/pbr/scripts/lib/pre-commit-checks.js +220 -0
  442. package/plugins/pbr/scripts/lib/pre-research.js +133 -0
  443. package/plugins/pbr/scripts/lib/preview.js +174 -0
  444. package/plugins/pbr/scripts/lib/progress-visualization.js +296 -0
  445. package/plugins/pbr/scripts/lib/quick-init.js +131 -0
  446. package/plugins/pbr/scripts/lib/reference.js +236 -0
  447. package/plugins/pbr/scripts/lib/requirements.js +153 -0
  448. package/plugins/pbr/scripts/lib/resolve-root.js +66 -0
  449. package/plugins/pbr/scripts/lib/reverse-spec.js +259 -0
  450. package/plugins/pbr/scripts/lib/roadmap.js +1113 -0
  451. package/plugins/pbr/scripts/lib/security-scan.js +200 -0
  452. package/plugins/pbr/scripts/lib/session-briefing.js +895 -0
  453. package/plugins/pbr/scripts/lib/skill-section.js +99 -0
  454. package/plugins/pbr/scripts/lib/smart-next-task.js +207 -0
  455. package/plugins/pbr/scripts/lib/snapshot-manager.js +232 -0
  456. package/plugins/pbr/scripts/lib/spec-diff.js +209 -0
  457. package/plugins/pbr/scripts/lib/spec-engine.js +189 -0
  458. package/plugins/pbr/scripts/lib/spot-check.js +642 -0
  459. package/plugins/pbr/scripts/lib/state-queue.js +171 -0
  460. package/plugins/pbr/scripts/lib/state.js +1187 -0
  461. package/plugins/pbr/scripts/lib/status-render.js +511 -0
  462. package/plugins/pbr/scripts/lib/step-verify.js +149 -0
  463. package/plugins/pbr/scripts/lib/subagent-validators.js +1059 -0
  464. package/plugins/pbr/scripts/lib/suggest-next.js +435 -0
  465. package/plugins/pbr/scripts/lib/team-composer.js +87 -0
  466. package/plugins/pbr/scripts/lib/team-coordinator.js +153 -0
  467. package/plugins/pbr/scripts/lib/tech-debt-scanner.js +116 -0
  468. package/plugins/pbr/scripts/lib/template.js +222 -0
  469. package/plugins/pbr/scripts/lib/templates.js +362 -0
  470. package/plugins/pbr/scripts/lib/test-cache.js +54 -0
  471. package/plugins/pbr/scripts/lib/test-selection.js +163 -0
  472. package/plugins/pbr/scripts/lib/todo.js +300 -0
  473. package/plugins/pbr/scripts/lib/trust-gate.js +84 -0
  474. package/plugins/pbr/scripts/lib/verify.js +1473 -0
  475. package/plugins/pbr/scripts/lib/wiring-check.js +196 -0
  476. package/plugins/pbr/scripts/log-notification.js +131 -0
  477. package/plugins/pbr/scripts/log-subagent.js +203 -18
  478. package/plugins/pbr/scripts/log-tool-failure.js +60 -8
  479. package/plugins/pbr/scripts/milestone-learnings.js +569 -0
  480. package/plugins/pbr/scripts/package.json +1 -1
  481. package/plugins/pbr/scripts/pbr-tools.js +1833 -1167
  482. package/plugins/pbr/scripts/post-bash-triage.js +154 -0
  483. package/plugins/pbr/scripts/post-compact.js +135 -0
  484. package/plugins/pbr/scripts/post-hoc.js +286 -0
  485. package/plugins/pbr/scripts/post-write-dispatch.js +237 -31
  486. package/plugins/pbr/scripts/post-write-quality.js +4 -3
  487. package/plugins/pbr/scripts/pre-bash-dispatch.js +154 -52
  488. package/plugins/pbr/scripts/pre-skill-dispatch.js +114 -0
  489. package/plugins/pbr/scripts/pre-task-dispatch.js +297 -0
  490. package/plugins/pbr/scripts/pre-write-dispatch.js +170 -73
  491. package/plugins/pbr/scripts/progress-tracker.js +144 -307
  492. package/plugins/pbr/scripts/prompt-guard.js +114 -0
  493. package/plugins/pbr/scripts/prompt-routing.js +209 -0
  494. package/plugins/pbr/scripts/quick-status.js +179 -0
  495. package/plugins/pbr/scripts/record-incident.js +37 -0
  496. package/plugins/pbr/scripts/risk-classifier.cjs +123 -0
  497. package/plugins/pbr/scripts/run-hook.js +62 -10
  498. package/plugins/pbr/scripts/session-cleanup.js +458 -29
  499. package/plugins/pbr/scripts/session-tracker.js +124 -0
  500. package/plugins/pbr/scripts/status-line.js +591 -32
  501. package/plugins/pbr/scripts/suggest-compact.js +203 -7
  502. package/plugins/pbr/scripts/sync-context-to-claude.js +100 -0
  503. package/plugins/pbr/scripts/task-completed.js +165 -4
  504. package/plugins/pbr/scripts/test/config.test.js +126 -0
  505. package/plugins/pbr/scripts/test/cross-platform.test.js +131 -0
  506. package/plugins/pbr/scripts/test/fixtures/config.json +20 -0
  507. package/plugins/pbr/scripts/test/fixtures/plan.md +54 -0
  508. package/plugins/pbr/scripts/test/fixtures/project.md +30 -0
  509. package/plugins/pbr/scripts/test/fixtures/roadmap.md +55 -0
  510. package/plugins/pbr/scripts/test/fixtures/state.md +60 -0
  511. package/plugins/pbr/scripts/test/fixtures/summary.md +35 -0
  512. package/plugins/pbr/scripts/test/fixtures.test.js +184 -0
  513. package/plugins/pbr/scripts/test/phase.test.js +142 -0
  514. package/plugins/pbr/scripts/test/roadmap.test.js +96 -0
  515. package/plugins/pbr/scripts/test/state.test.js +163 -0
  516. package/plugins/pbr/scripts/track-context-budget.js +368 -99
  517. package/plugins/pbr/scripts/track-user-gates.js +88 -0
  518. package/plugins/pbr/scripts/trust-tracker.js +193 -0
  519. package/plugins/pbr/scripts/validate-commit.js +97 -26
  520. package/plugins/pbr/scripts/validate-skill-args.js +87 -15
  521. package/plugins/pbr/scripts/validate-task.js +112 -626
  522. package/plugins/pbr/scripts/worktree-create.js +144 -0
  523. package/plugins/pbr/scripts/worktree-remove.js +147 -0
  524. package/plugins/pbr/skills/audit/SKILL.md +195 -24
  525. package/plugins/pbr/skills/audit-fix/SKILL.md +326 -0
  526. package/plugins/pbr/skills/autonomous/SKILL.md +545 -0
  527. package/plugins/pbr/skills/backlog/SKILL.md +56 -0
  528. package/plugins/pbr/skills/begin/SKILL.md +507 -153
  529. package/plugins/pbr/skills/begin/templates/STATE.md.tmpl +1 -2
  530. package/plugins/pbr/skills/begin/templates/config.json.tmpl +415 -36
  531. package/plugins/pbr/skills/begin/templates/researcher-prompt.md.tmpl +28 -0
  532. package/plugins/pbr/skills/begin/templates/roadmap-prompt.md.tmpl +28 -3
  533. package/plugins/pbr/skills/begin/templates/synthesis-prompt.md.tmpl +33 -5
  534. package/plugins/pbr/skills/build/SKILL.md +1040 -354
  535. package/plugins/pbr/skills/build/templates/continuation-prompt.md.tmpl +26 -0
  536. package/plugins/pbr/skills/build/templates/executor-prompt.md.tmpl +77 -0
  537. package/plugins/pbr/skills/build/templates/inline-verifier-prompt.md.tmpl +33 -0
  538. package/plugins/pbr/skills/config/SKILL.md +111 -9
  539. package/plugins/pbr/skills/continue/SKILL.md +113 -33
  540. package/plugins/pbr/skills/dashboard/SKILL.md +21 -9
  541. package/plugins/pbr/skills/debug/SKILL.md +70 -12
  542. package/plugins/pbr/skills/debug/templates/continuation-prompt.md.tmpl +12 -1
  543. package/plugins/pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +12 -5
  544. package/plugins/pbr/skills/discuss/SKILL.md +206 -25
  545. package/plugins/pbr/skills/discuss/templates/CONTEXT.md.tmpl +21 -1
  546. package/plugins/pbr/skills/do/SKILL.md +119 -24
  547. package/plugins/pbr/skills/explore/SKILL.md +95 -20
  548. package/plugins/pbr/skills/fast/SKILL.md +94 -0
  549. package/plugins/pbr/skills/forensics/SKILL.md +144 -0
  550. package/plugins/pbr/skills/health/SKILL.md +35 -117
  551. package/plugins/pbr/skills/help/SKILL.md +83 -101
  552. package/plugins/pbr/skills/import/SKILL.md +332 -13
  553. package/plugins/pbr/skills/intel/SKILL.md +131 -0
  554. package/plugins/pbr/skills/list-phase-assumptions/SKILL.md +231 -0
  555. package/plugins/pbr/skills/milestone/SKILL.md +421 -263
  556. package/plugins/pbr/skills/milestone/templates/audit-output.md.tmpl +76 -0
  557. package/plugins/pbr/skills/milestone/templates/complete-output.md.tmpl +32 -0
  558. package/plugins/pbr/skills/milestone/templates/edge-cases.md +54 -0
  559. package/plugins/pbr/skills/milestone/templates/gaps-output.md.tmpl +25 -0
  560. package/plugins/pbr/skills/milestone/templates/integration-checker-prompt.md.tmpl +25 -0
  561. package/plugins/pbr/skills/milestone/templates/new-output.md.tmpl +29 -0
  562. package/plugins/pbr/skills/milestone-summary/SKILL.md +86 -0
  563. package/plugins/pbr/skills/note/SKILL.md +20 -4
  564. package/plugins/pbr/skills/pause/SKILL.md +53 -14
  565. package/plugins/pbr/skills/pause/templates/continue-here.md.tmpl +33 -52
  566. package/plugins/pbr/skills/plan/SKILL.md +526 -280
  567. package/plugins/pbr/skills/plan/templates/checker-prompt.md.tmpl +5 -2
  568. package/plugins/pbr/skills/plan/templates/completion-output.md.tmpl +27 -0
  569. package/plugins/pbr/skills/plan/templates/planner-prompt.md.tmpl +27 -1
  570. package/plugins/pbr/skills/plan/templates/revision-prompt.md.tmpl +21 -5
  571. package/plugins/pbr/skills/profile/SKILL.md +185 -0
  572. package/plugins/pbr/skills/profile-user/SKILL.md +226 -0
  573. package/plugins/pbr/skills/quick/SKILL.md +434 -100
  574. package/plugins/pbr/skills/release/SKILL.md +206 -0
  575. package/plugins/pbr/skills/resume/SKILL.md +169 -46
  576. package/plugins/pbr/skills/review/SKILL.md +217 -164
  577. package/plugins/pbr/skills/review/templates/verifier-prompt.md.tmpl +7 -0
  578. package/plugins/pbr/skills/scan/SKILL.md +151 -106
  579. package/plugins/pbr/skills/scan/templates/mapper-prompt.md.tmpl +5 -56
  580. package/plugins/pbr/skills/seed/SKILL.md +87 -0
  581. package/plugins/pbr/skills/session-report/SKILL.md +130 -0
  582. package/plugins/pbr/skills/setup/SKILL.md +149 -202
  583. package/plugins/pbr/skills/shared/agent-context-enrichment.md +21 -0
  584. package/plugins/pbr/skills/shared/agent-type-resolution.md +32 -0
  585. package/plugins/pbr/skills/shared/commit-planning-docs.md +8 -0
  586. package/plugins/pbr/skills/shared/context-budget.md +66 -1
  587. package/plugins/pbr/skills/shared/context-loader-task.md +18 -11
  588. package/plugins/pbr/skills/shared/digest-select.md +2 -2
  589. package/plugins/pbr/skills/shared/domain-probes.md +1 -1
  590. package/plugins/pbr/skills/shared/error-reporting.md +38 -60
  591. package/plugins/pbr/skills/shared/gate-prompts.md +4 -2
  592. package/plugins/pbr/skills/shared/memory-capture.md +48 -0
  593. package/plugins/pbr/skills/shared/phase-argument-parsing.md +4 -4
  594. package/plugins/pbr/skills/shared/revision-loop.md +24 -6
  595. package/plugins/pbr/skills/shared/state-update.md +47 -54
  596. package/plugins/pbr/skills/shared/universal-anti-patterns.md +27 -4
  597. package/plugins/pbr/skills/ship/SKILL.md +155 -0
  598. package/plugins/pbr/skills/stats/SKILL.md +80 -0
  599. package/plugins/pbr/skills/status/SKILL.md +184 -119
  600. package/plugins/pbr/skills/test/SKILL.md +254 -0
  601. package/plugins/pbr/skills/thread/SKILL.md +73 -0
  602. package/plugins/pbr/skills/todo/SKILL.md +28 -72
  603. package/plugins/pbr/skills/ui-phase/SKILL.md +180 -0
  604. package/plugins/pbr/skills/ui-review/SKILL.md +206 -0
  605. package/plugins/pbr/skills/undo/SKILL.md +221 -0
  606. package/plugins/pbr/skills/validate-phase/SKILL.md +362 -0
  607. package/plugins/pbr/templates/CONTEXT.md.tmpl +45 -20
  608. package/plugins/pbr/templates/DISCOVERY.md.tmpl +29 -0
  609. package/plugins/pbr/templates/DISCUSSION-LOG.md.tmpl +49 -0
  610. package/plugins/pbr/templates/HANDOFF.json.tmpl +30 -0
  611. package/plugins/pbr/templates/INTEGRATION-REPORT.md.tmpl +18 -2
  612. package/plugins/pbr/templates/MILESTONE-AUDIT.md.tmpl +44 -0
  613. package/plugins/pbr/templates/PROJECT.md.tmpl +126 -0
  614. package/plugins/pbr/templates/REQUIREMENTS.md.tmpl +96 -0
  615. package/plugins/pbr/templates/RETROSPECTIVE.md.tmpl +43 -0
  616. package/plugins/pbr/templates/ROADMAP.md.tmpl +108 -14
  617. package/plugins/pbr/templates/SUMMARY-complex.md.tmpl +133 -0
  618. package/plugins/pbr/templates/SUMMARY-minimal.md.tmpl +55 -0
  619. package/plugins/pbr/templates/SUMMARY.md.tmpl +21 -0
  620. package/plugins/pbr/templates/UAT.md.tmpl +94 -0
  621. package/plugins/pbr/templates/UI-SPEC.md.tmpl +144 -0
  622. package/plugins/pbr/templates/VALIDATION.md.tmpl +94 -0
  623. package/plugins/pbr/templates/VERIFICATION-DETAIL.md.tmpl +49 -13
  624. package/plugins/pbr/templates/project-CONTEXT.md.tmpl +59 -0
  625. package/plugins/pbr/templates/research-outputs/ARCHITECTURE.md.tmpl +91 -0
  626. package/plugins/pbr/templates/research-outputs/FEATURES.md.tmpl +64 -0
  627. package/plugins/pbr/templates/research-outputs/PITFALLS.md.tmpl +50 -0
  628. package/plugins/pbr/templates/research-outputs/STACK.md.tmpl +63 -0
  629. package/plugins/pbr/templates/research-outputs/SUMMARY.md.tmpl +98 -0
  630. package/scripts/build-hooks.js +61 -0
  631. package/scripts/check-ci.js +100 -0
  632. package/scripts/clean-changelog.js +364 -0
  633. package/scripts/generate-derivatives.js +581 -0
  634. package/scripts/posttest.js +93 -0
  635. package/scripts/release.js +262 -0
  636. package/scripts/run-tests.cjs +29 -0
  637. package/scripts/test-wrapper.js +43 -0
  638. package/dashboard/bin/cli.js +0 -25
  639. package/dashboard/public/css/layout.css +0 -704
  640. package/dashboard/public/css/status-colors.css +0 -98
  641. package/dashboard/public/css/tokens.css +0 -59
  642. package/dashboard/public/js/htmx-title.js +0 -5
  643. package/dashboard/public/js/sidebar-toggle.js +0 -34
  644. package/dashboard/public/js/sse-client.js +0 -100
  645. package/dashboard/public/js/theme-toggle.js +0 -46
  646. package/dashboard/src/app.js +0 -91
  647. package/dashboard/src/middleware/current-phase.js +0 -24
  648. package/dashboard/src/middleware/errorHandler.js +0 -52
  649. package/dashboard/src/middleware/notFoundHandler.js +0 -9
  650. package/dashboard/src/repositories/planning.repository.js +0 -130
  651. package/dashboard/src/routes/events.routes.js +0 -45
  652. package/dashboard/src/routes/index.routes.js +0 -35
  653. package/dashboard/src/routes/pages.routes.js +0 -426
  654. package/dashboard/src/server.js +0 -42
  655. package/dashboard/src/services/analytics.service.js +0 -141
  656. package/dashboard/src/services/dashboard.service.js +0 -309
  657. package/dashboard/src/services/milestone.service.js +0 -222
  658. package/dashboard/src/services/notes.service.js +0 -50
  659. package/dashboard/src/services/phase.service.js +0 -232
  660. package/dashboard/src/services/project.service.js +0 -57
  661. package/dashboard/src/services/roadmap.service.js +0 -258
  662. package/dashboard/src/services/sse.service.js +0 -58
  663. package/dashboard/src/services/todo.service.js +0 -272
  664. package/dashboard/src/services/watcher.service.js +0 -48
  665. package/dashboard/src/utils/cache.js +0 -55
  666. package/dashboard/src/views/analytics.ejs +0 -5
  667. package/dashboard/src/views/coming-soon.ejs +0 -11
  668. package/dashboard/src/views/dependencies.ejs +0 -5
  669. package/dashboard/src/views/error.ejs +0 -20
  670. package/dashboard/src/views/index.ejs +0 -5
  671. package/dashboard/src/views/milestone-detail.ejs +0 -5
  672. package/dashboard/src/views/milestones.ejs +0 -5
  673. package/dashboard/src/views/notes.ejs +0 -5
  674. package/dashboard/src/views/partials/analytics-content.ejs +0 -90
  675. package/dashboard/src/views/partials/breadcrumbs.ejs +0 -14
  676. package/dashboard/src/views/partials/dashboard-content.ejs +0 -84
  677. package/dashboard/src/views/partials/dependencies-content.ejs +0 -48
  678. package/dashboard/src/views/partials/empty-state.ejs +0 -7
  679. package/dashboard/src/views/partials/footer.ejs +0 -3
  680. package/dashboard/src/views/partials/head.ejs +0 -30
  681. package/dashboard/src/views/partials/header.ejs +0 -21
  682. package/dashboard/src/views/partials/layout-bottom.ejs +0 -43
  683. package/dashboard/src/views/partials/layout-top.ejs +0 -16
  684. package/dashboard/src/views/partials/milestone-detail-content.ejs +0 -20
  685. package/dashboard/src/views/partials/milestones-content.ejs +0 -88
  686. package/dashboard/src/views/partials/notes-content.ejs +0 -23
  687. package/dashboard/src/views/partials/phase-content.ejs +0 -193
  688. package/dashboard/src/views/partials/phase-doc-content.ejs +0 -38
  689. package/dashboard/src/views/partials/phases-content.ejs +0 -124
  690. package/dashboard/src/views/partials/roadmap-content.ejs +0 -180
  691. package/dashboard/src/views/partials/sidebar.ejs +0 -99
  692. package/dashboard/src/views/partials/todo-create-content.ejs +0 -54
  693. package/dashboard/src/views/partials/todo-detail-content.ejs +0 -42
  694. package/dashboard/src/views/partials/todos-content.ejs +0 -97
  695. package/dashboard/src/views/phase-detail.ejs +0 -5
  696. package/dashboard/src/views/phase-doc.ejs +0 -5
  697. package/dashboard/src/views/phases.ejs +0 -5
  698. package/dashboard/src/views/roadmap.ejs +0 -5
  699. package/dashboard/src/views/todo-create.ejs +0 -5
  700. package/dashboard/src/views/todo-detail.ejs +0 -5
  701. package/dashboard/src/views/todos.ejs +0 -5
  702. package/plugins/copilot-pbr/CHANGELOG.md +0 -19
  703. package/plugins/copilot-pbr/README.md +0 -139
  704. package/plugins/copilot-pbr/agents/audit.agent.md +0 -113
  705. package/plugins/copilot-pbr/agents/codebase-mapper.agent.md +0 -151
  706. package/plugins/copilot-pbr/agents/debugger.agent.md +0 -182
  707. package/plugins/copilot-pbr/agents/executor.agent.md +0 -267
  708. package/plugins/copilot-pbr/agents/general.agent.md +0 -88
  709. package/plugins/copilot-pbr/agents/integration-checker.agent.md +0 -119
  710. package/plugins/copilot-pbr/agents/plan-checker.agent.md +0 -208
  711. package/plugins/copilot-pbr/agents/planner.agent.md +0 -238
  712. package/plugins/copilot-pbr/agents/researcher.agent.md +0 -186
  713. package/plugins/copilot-pbr/agents/synthesizer.agent.md +0 -126
  714. package/plugins/copilot-pbr/agents/verifier.agent.md +0 -228
  715. package/plugins/copilot-pbr/hooks/hooks.json +0 -156
  716. package/plugins/copilot-pbr/plugin.json +0 -30
  717. package/plugins/copilot-pbr/references/agent-anti-patterns.md +0 -25
  718. package/plugins/copilot-pbr/references/agent-contracts.md +0 -297
  719. package/plugins/copilot-pbr/references/agent-interactions.md +0 -135
  720. package/plugins/copilot-pbr/references/agent-teams.md +0 -55
  721. package/plugins/copilot-pbr/references/checkpoints.md +0 -158
  722. package/plugins/copilot-pbr/references/common-bug-patterns.md +0 -14
  723. package/plugins/copilot-pbr/references/config-reference.md +0 -442
  724. package/plugins/copilot-pbr/references/continuation-format.md +0 -213
  725. package/plugins/copilot-pbr/references/deviation-rules.md +0 -113
  726. package/plugins/copilot-pbr/references/git-integration.md +0 -227
  727. package/plugins/copilot-pbr/references/integration-patterns.md +0 -118
  728. package/plugins/copilot-pbr/references/model-profiles.md +0 -100
  729. package/plugins/copilot-pbr/references/model-selection.md +0 -32
  730. package/plugins/copilot-pbr/references/pbr-rules.md +0 -195
  731. package/plugins/copilot-pbr/references/pbr-tools-cli.md +0 -285
  732. package/plugins/copilot-pbr/references/plan-authoring.md +0 -182
  733. package/plugins/copilot-pbr/references/plan-format.md +0 -288
  734. package/plugins/copilot-pbr/references/planning-config.md +0 -214
  735. package/plugins/copilot-pbr/references/questioning.md +0 -215
  736. package/plugins/copilot-pbr/references/reading-verification.md +0 -128
  737. package/plugins/copilot-pbr/references/stub-patterns.md +0 -161
  738. package/plugins/copilot-pbr/references/subagent-coordination.md +0 -120
  739. package/plugins/copilot-pbr/references/ui-formatting.md +0 -444
  740. package/plugins/copilot-pbr/references/verification-patterns.md +0 -199
  741. package/plugins/copilot-pbr/references/wave-execution.md +0 -96
  742. package/plugins/copilot-pbr/rules/pbr-workflow.mdc +0 -48
  743. package/plugins/copilot-pbr/setup.ps1 +0 -93
  744. package/plugins/copilot-pbr/setup.sh +0 -93
  745. package/plugins/copilot-pbr/skills/audit/SKILL.md +0 -330
  746. package/plugins/copilot-pbr/skills/begin/SKILL.md +0 -589
  747. package/plugins/copilot-pbr/skills/begin/templates/PROJECT.md.tmpl +0 -34
  748. package/plugins/copilot-pbr/skills/begin/templates/REQUIREMENTS.md.tmpl +0 -19
  749. package/plugins/copilot-pbr/skills/begin/templates/STATE.md.tmpl +0 -50
  750. package/plugins/copilot-pbr/skills/begin/templates/config.json.tmpl +0 -64
  751. package/plugins/copilot-pbr/skills/begin/templates/researcher-prompt.md.tmpl +0 -20
  752. package/plugins/copilot-pbr/skills/begin/templates/roadmap-prompt.md.tmpl +0 -31
  753. package/plugins/copilot-pbr/skills/begin/templates/synthesis-prompt.md.tmpl +0 -17
  754. package/plugins/copilot-pbr/skills/build/SKILL.md +0 -960
  755. package/plugins/copilot-pbr/skills/config/SKILL.md +0 -250
  756. package/plugins/copilot-pbr/skills/continue/SKILL.md +0 -159
  757. package/plugins/copilot-pbr/skills/dashboard/SKILL.md +0 -43
  758. package/plugins/copilot-pbr/skills/debug/SKILL.md +0 -508
  759. package/plugins/copilot-pbr/skills/debug/templates/continuation-prompt.md.tmpl +0 -17
  760. package/plugins/copilot-pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +0 -28
  761. package/plugins/copilot-pbr/skills/discuss/SKILL.md +0 -353
  762. package/plugins/copilot-pbr/skills/discuss/templates/CONTEXT.md.tmpl +0 -62
  763. package/plugins/copilot-pbr/skills/discuss/templates/decision-categories.md +0 -10
  764. package/plugins/copilot-pbr/skills/do/SKILL.md +0 -66
  765. package/plugins/copilot-pbr/skills/explore/SKILL.md +0 -373
  766. package/plugins/copilot-pbr/skills/health/SKILL.md +0 -283
  767. package/plugins/copilot-pbr/skills/health/templates/check-pattern.md.tmpl +0 -31
  768. package/plugins/copilot-pbr/skills/health/templates/output-format.md.tmpl +0 -64
  769. package/plugins/copilot-pbr/skills/help/SKILL.md +0 -170
  770. package/plugins/copilot-pbr/skills/import/SKILL.md +0 -502
  771. package/plugins/copilot-pbr/skills/milestone/SKILL.md +0 -745
  772. package/plugins/copilot-pbr/skills/milestone/templates/audit-report.md.tmpl +0 -49
  773. package/plugins/copilot-pbr/skills/milestone/templates/stats-file.md.tmpl +0 -31
  774. package/plugins/copilot-pbr/skills/note/SKILL.md +0 -213
  775. package/plugins/copilot-pbr/skills/pause/SKILL.md +0 -247
  776. package/plugins/copilot-pbr/skills/pause/templates/continue-here.md.tmpl +0 -72
  777. package/plugins/copilot-pbr/skills/plan/SKILL.md +0 -662
  778. package/plugins/copilot-pbr/skills/plan/templates/checker-prompt.md.tmpl +0 -22
  779. package/plugins/copilot-pbr/skills/plan/templates/gap-closure-prompt.md.tmpl +0 -33
  780. package/plugins/copilot-pbr/skills/plan/templates/planner-prompt.md.tmpl +0 -39
  781. package/plugins/copilot-pbr/skills/plan/templates/researcher-prompt.md.tmpl +0 -20
  782. package/plugins/copilot-pbr/skills/plan/templates/revision-prompt.md.tmpl +0 -24
  783. package/plugins/copilot-pbr/skills/quick/SKILL.md +0 -376
  784. package/plugins/copilot-pbr/skills/resume/SKILL.md +0 -399
  785. package/plugins/copilot-pbr/skills/review/SKILL.md +0 -653
  786. package/plugins/copilot-pbr/skills/review/templates/debugger-prompt.md.tmpl +0 -61
  787. package/plugins/copilot-pbr/skills/review/templates/gap-planner-prompt.md.tmpl +0 -41
  788. package/plugins/copilot-pbr/skills/review/templates/verifier-prompt.md.tmpl +0 -116
  789. package/plugins/copilot-pbr/skills/scan/SKILL.md +0 -299
  790. package/plugins/copilot-pbr/skills/scan/templates/mapper-prompt.md.tmpl +0 -202
  791. package/plugins/copilot-pbr/skills/setup/SKILL.md +0 -296
  792. package/plugins/copilot-pbr/skills/shared/commit-planning-docs.md +0 -36
  793. package/plugins/copilot-pbr/skills/shared/config-loading.md +0 -103
  794. package/plugins/copilot-pbr/skills/shared/context-budget.md +0 -41
  795. package/plugins/copilot-pbr/skills/shared/context-loader-task.md +0 -87
  796. package/plugins/copilot-pbr/skills/shared/digest-select.md +0 -80
  797. package/plugins/copilot-pbr/skills/shared/domain-probes.md +0 -126
  798. package/plugins/copilot-pbr/skills/shared/error-reporting.md +0 -81
  799. package/plugins/copilot-pbr/skills/shared/gate-prompts.md +0 -389
  800. package/plugins/copilot-pbr/skills/shared/phase-argument-parsing.md +0 -46
  801. package/plugins/copilot-pbr/skills/shared/progress-display.md +0 -53
  802. package/plugins/copilot-pbr/skills/shared/revision-loop.md +0 -82
  803. package/plugins/copilot-pbr/skills/shared/state-loading.md +0 -63
  804. package/plugins/copilot-pbr/skills/shared/state-update.md +0 -162
  805. package/plugins/copilot-pbr/skills/shared/universal-anti-patterns.md +0 -38
  806. package/plugins/copilot-pbr/skills/status/SKILL.md +0 -362
  807. package/plugins/copilot-pbr/skills/statusline/SKILL.md +0 -149
  808. package/plugins/copilot-pbr/skills/todo/SKILL.md +0 -279
  809. package/plugins/copilot-pbr/templates/CONTEXT.md.tmpl +0 -53
  810. package/plugins/copilot-pbr/templates/INTEGRATION-REPORT.md.tmpl +0 -152
  811. package/plugins/copilot-pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -98
  812. package/plugins/copilot-pbr/templates/ROADMAP.md.tmpl +0 -41
  813. package/plugins/copilot-pbr/templates/SUMMARY.md.tmpl +0 -82
  814. package/plugins/copilot-pbr/templates/VERIFICATION-DETAIL.md.tmpl +0 -117
  815. package/plugins/copilot-pbr/templates/codebase/ARCHITECTURE.md.tmpl +0 -98
  816. package/plugins/copilot-pbr/templates/codebase/CONCERNS.md.tmpl +0 -93
  817. package/plugins/copilot-pbr/templates/codebase/CONVENTIONS.md.tmpl +0 -104
  818. package/plugins/copilot-pbr/templates/codebase/INTEGRATIONS.md.tmpl +0 -78
  819. package/plugins/copilot-pbr/templates/codebase/STACK.md.tmpl +0 -78
  820. package/plugins/copilot-pbr/templates/codebase/STRUCTURE.md.tmpl +0 -80
  821. package/plugins/copilot-pbr/templates/codebase/TESTING.md.tmpl +0 -107
  822. package/plugins/copilot-pbr/templates/continue-here.md.tmpl +0 -74
  823. package/plugins/copilot-pbr/templates/prompt-partials/phase-project-context.md.tmpl +0 -38
  824. package/plugins/copilot-pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
  825. package/plugins/copilot-pbr/templates/research/STACK.md.tmpl +0 -71
  826. package/plugins/copilot-pbr/templates/research/SUMMARY.md.tmpl +0 -112
  827. package/plugins/copilot-pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
  828. package/plugins/copilot-pbr/templates/research-outputs/project-research.md.tmpl +0 -99
  829. package/plugins/copilot-pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
  830. package/plugins/cursor-pbr/.cursor-plugin/plugin.json +0 -32
  831. package/plugins/cursor-pbr/CHANGELOG.md +0 -15
  832. package/plugins/cursor-pbr/README.md +0 -123
  833. package/plugins/cursor-pbr/agents/audit.md +0 -178
  834. package/plugins/cursor-pbr/agents/codebase-mapper.md +0 -150
  835. package/plugins/cursor-pbr/agents/debugger.md +0 -181
  836. package/plugins/cursor-pbr/agents/executor.md +0 -266
  837. package/plugins/cursor-pbr/agents/general.md +0 -87
  838. package/plugins/cursor-pbr/agents/integration-checker.md +0 -118
  839. package/plugins/cursor-pbr/agents/plan-checker.md +0 -207
  840. package/plugins/cursor-pbr/agents/planner.md +0 -237
  841. package/plugins/cursor-pbr/agents/researcher.md +0 -185
  842. package/plugins/cursor-pbr/agents/synthesizer.md +0 -125
  843. package/plugins/cursor-pbr/agents/verifier.md +0 -227
  844. package/plugins/cursor-pbr/assets/.gitkeep +0 -0
  845. package/plugins/cursor-pbr/assets/logo.svg +0 -21
  846. package/plugins/cursor-pbr/hooks/hooks.json +0 -213
  847. package/plugins/cursor-pbr/references/agent-anti-patterns.md +0 -25
  848. package/plugins/cursor-pbr/references/agent-contracts.md +0 -297
  849. package/plugins/cursor-pbr/references/agent-interactions.md +0 -135
  850. package/plugins/cursor-pbr/references/agent-teams.md +0 -55
  851. package/plugins/cursor-pbr/references/checkpoints.md +0 -158
  852. package/plugins/cursor-pbr/references/common-bug-patterns.md +0 -14
  853. package/plugins/cursor-pbr/references/config-reference.md +0 -442
  854. package/plugins/cursor-pbr/references/continuation-format.md +0 -213
  855. package/plugins/cursor-pbr/references/deviation-rules.md +0 -113
  856. package/plugins/cursor-pbr/references/git-integration.md +0 -227
  857. package/plugins/cursor-pbr/references/integration-patterns.md +0 -118
  858. package/plugins/cursor-pbr/references/model-profiles.md +0 -100
  859. package/plugins/cursor-pbr/references/model-selection.md +0 -32
  860. package/plugins/cursor-pbr/references/pbr-rules.md +0 -195
  861. package/plugins/cursor-pbr/references/pbr-tools-cli.md +0 -285
  862. package/plugins/cursor-pbr/references/plan-authoring.md +0 -182
  863. package/plugins/cursor-pbr/references/plan-format.md +0 -288
  864. package/plugins/cursor-pbr/references/planning-config.md +0 -214
  865. package/plugins/cursor-pbr/references/questioning.md +0 -215
  866. package/plugins/cursor-pbr/references/reading-verification.md +0 -128
  867. package/plugins/cursor-pbr/references/stub-patterns.md +0 -161
  868. package/plugins/cursor-pbr/references/subagent-coordination.md +0 -120
  869. package/plugins/cursor-pbr/references/ui-formatting.md +0 -444
  870. package/plugins/cursor-pbr/references/verification-patterns.md +0 -199
  871. package/plugins/cursor-pbr/references/wave-execution.md +0 -96
  872. package/plugins/cursor-pbr/rules/pbr-workflow.mdc +0 -48
  873. package/plugins/cursor-pbr/setup.ps1 +0 -78
  874. package/plugins/cursor-pbr/setup.sh +0 -83
  875. package/plugins/cursor-pbr/skills/audit/SKILL.md +0 -331
  876. package/plugins/cursor-pbr/skills/begin/SKILL.md +0 -589
  877. package/plugins/cursor-pbr/skills/begin/templates/PROJECT.md.tmpl +0 -34
  878. package/plugins/cursor-pbr/skills/begin/templates/REQUIREMENTS.md.tmpl +0 -19
  879. package/plugins/cursor-pbr/skills/begin/templates/STATE.md.tmpl +0 -50
  880. package/plugins/cursor-pbr/skills/begin/templates/config.json.tmpl +0 -64
  881. package/plugins/cursor-pbr/skills/begin/templates/researcher-prompt.md.tmpl +0 -20
  882. package/plugins/cursor-pbr/skills/begin/templates/roadmap-prompt.md.tmpl +0 -31
  883. package/plugins/cursor-pbr/skills/begin/templates/synthesis-prompt.md.tmpl +0 -17
  884. package/plugins/cursor-pbr/skills/build/SKILL.md +0 -961
  885. package/plugins/cursor-pbr/skills/config/SKILL.md +0 -252
  886. package/plugins/cursor-pbr/skills/continue/SKILL.md +0 -159
  887. package/plugins/cursor-pbr/skills/dashboard/SKILL.md +0 -44
  888. package/plugins/cursor-pbr/skills/debug/SKILL.md +0 -512
  889. package/plugins/cursor-pbr/skills/debug/templates/continuation-prompt.md.tmpl +0 -17
  890. package/plugins/cursor-pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +0 -28
  891. package/plugins/cursor-pbr/skills/discuss/SKILL.md +0 -354
  892. package/plugins/cursor-pbr/skills/discuss/templates/CONTEXT.md.tmpl +0 -62
  893. package/plugins/cursor-pbr/skills/discuss/templates/decision-categories.md +0 -10
  894. package/plugins/cursor-pbr/skills/do/SKILL.md +0 -67
  895. package/plugins/cursor-pbr/skills/explore/SKILL.md +0 -376
  896. package/plugins/cursor-pbr/skills/health/SKILL.md +0 -283
  897. package/plugins/cursor-pbr/skills/health/templates/check-pattern.md.tmpl +0 -31
  898. package/plugins/cursor-pbr/skills/health/templates/output-format.md.tmpl +0 -64
  899. package/plugins/cursor-pbr/skills/help/SKILL.md +0 -170
  900. package/plugins/cursor-pbr/skills/import/SKILL.md +0 -505
  901. package/plugins/cursor-pbr/skills/milestone/SKILL.md +0 -746
  902. package/plugins/cursor-pbr/skills/milestone/templates/audit-report.md.tmpl +0 -49
  903. package/plugins/cursor-pbr/skills/milestone/templates/stats-file.md.tmpl +0 -31
  904. package/plugins/cursor-pbr/skills/note/SKILL.md +0 -214
  905. package/plugins/cursor-pbr/skills/pause/SKILL.md +0 -248
  906. package/plugins/cursor-pbr/skills/pause/templates/continue-here.md.tmpl +0 -72
  907. package/plugins/cursor-pbr/skills/plan/SKILL.md +0 -663
  908. package/plugins/cursor-pbr/skills/plan/templates/checker-prompt.md.tmpl +0 -22
  909. package/plugins/cursor-pbr/skills/plan/templates/gap-closure-prompt.md.tmpl +0 -33
  910. package/plugins/cursor-pbr/skills/plan/templates/planner-prompt.md.tmpl +0 -39
  911. package/plugins/cursor-pbr/skills/plan/templates/researcher-prompt.md.tmpl +0 -20
  912. package/plugins/cursor-pbr/skills/plan/templates/revision-prompt.md.tmpl +0 -24
  913. package/plugins/cursor-pbr/skills/quick/SKILL.md +0 -376
  914. package/plugins/cursor-pbr/skills/resume/SKILL.md +0 -399
  915. package/plugins/cursor-pbr/skills/review/SKILL.md +0 -654
  916. package/plugins/cursor-pbr/skills/review/templates/debugger-prompt.md.tmpl +0 -61
  917. package/plugins/cursor-pbr/skills/review/templates/gap-planner-prompt.md.tmpl +0 -41
  918. package/plugins/cursor-pbr/skills/review/templates/verifier-prompt.md.tmpl +0 -116
  919. package/plugins/cursor-pbr/skills/scan/SKILL.md +0 -300
  920. package/plugins/cursor-pbr/skills/scan/templates/mapper-prompt.md.tmpl +0 -202
  921. package/plugins/cursor-pbr/skills/setup/SKILL.md +0 -296
  922. package/plugins/cursor-pbr/skills/shared/commit-planning-docs.md +0 -36
  923. package/plugins/cursor-pbr/skills/shared/config-loading.md +0 -103
  924. package/plugins/cursor-pbr/skills/shared/context-budget.md +0 -41
  925. package/plugins/cursor-pbr/skills/shared/context-loader-task.md +0 -87
  926. package/plugins/cursor-pbr/skills/shared/digest-select.md +0 -80
  927. package/plugins/cursor-pbr/skills/shared/domain-probes.md +0 -126
  928. package/plugins/cursor-pbr/skills/shared/error-reporting.md +0 -81
  929. package/plugins/cursor-pbr/skills/shared/gate-prompts.md +0 -389
  930. package/plugins/cursor-pbr/skills/shared/phase-argument-parsing.md +0 -46
  931. package/plugins/cursor-pbr/skills/shared/progress-display.md +0 -53
  932. package/plugins/cursor-pbr/skills/shared/revision-loop.md +0 -82
  933. package/plugins/cursor-pbr/skills/shared/state-loading.md +0 -63
  934. package/plugins/cursor-pbr/skills/shared/state-update.md +0 -162
  935. package/plugins/cursor-pbr/skills/shared/universal-anti-patterns.md +0 -38
  936. package/plugins/cursor-pbr/skills/status/SKILL.md +0 -362
  937. package/plugins/cursor-pbr/skills/statusline/SKILL.md +0 -150
  938. package/plugins/cursor-pbr/skills/todo/SKILL.md +0 -280
  939. package/plugins/cursor-pbr/templates/CONTEXT.md.tmpl +0 -53
  940. package/plugins/cursor-pbr/templates/INTEGRATION-REPORT.md.tmpl +0 -152
  941. package/plugins/cursor-pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -98
  942. package/plugins/cursor-pbr/templates/ROADMAP.md.tmpl +0 -41
  943. package/plugins/cursor-pbr/templates/SUMMARY.md.tmpl +0 -82
  944. package/plugins/cursor-pbr/templates/VERIFICATION-DETAIL.md.tmpl +0 -117
  945. package/plugins/cursor-pbr/templates/codebase/ARCHITECTURE.md.tmpl +0 -98
  946. package/plugins/cursor-pbr/templates/codebase/CONCERNS.md.tmpl +0 -93
  947. package/plugins/cursor-pbr/templates/codebase/CONVENTIONS.md.tmpl +0 -104
  948. package/plugins/cursor-pbr/templates/codebase/INTEGRATIONS.md.tmpl +0 -78
  949. package/plugins/cursor-pbr/templates/codebase/STACK.md.tmpl +0 -78
  950. package/plugins/cursor-pbr/templates/codebase/STRUCTURE.md.tmpl +0 -80
  951. package/plugins/cursor-pbr/templates/codebase/TESTING.md.tmpl +0 -107
  952. package/plugins/cursor-pbr/templates/continue-here.md.tmpl +0 -74
  953. package/plugins/cursor-pbr/templates/prompt-partials/phase-project-context.md.tmpl +0 -38
  954. package/plugins/cursor-pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
  955. package/plugins/cursor-pbr/templates/research/STACK.md.tmpl +0 -71
  956. package/plugins/cursor-pbr/templates/research/SUMMARY.md.tmpl +0 -112
  957. package/plugins/cursor-pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
  958. package/plugins/cursor-pbr/templates/research-outputs/project-research.md.tmpl +0 -99
  959. package/plugins/cursor-pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
  960. package/plugins/pbr/references/agent-interactions.md +0 -134
  961. package/plugins/pbr/references/pbr-rules.md +0 -194
  962. package/plugins/pbr/references/pbr-tools-cli.md +0 -285
  963. package/plugins/pbr/references/planning-config.md +0 -213
  964. package/plugins/pbr/references/subagent-coordination.md +0 -119
  965. package/plugins/pbr/references/ui-formatting.md +0 -444
  966. package/plugins/pbr/scripts/validate-plugin-structure.js +0 -183
  967. package/plugins/pbr/skills/milestone/templates/audit-report.md.tmpl +0 -48
  968. package/plugins/pbr/skills/shared/progress-display.md +0 -53
  969. package/plugins/pbr/skills/shared/state-loading.md +0 -62
  970. package/plugins/pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -97
  971. package/plugins/pbr/templates/research/ARCHITECTURE.md.tmpl +0 -124
  972. package/plugins/pbr/templates/research/STACK.md.tmpl +0 -71
  973. package/plugins/pbr/templates/research/SUMMARY.md.tmpl +0 -112
  974. package/plugins/pbr/templates/research-outputs/phase-research.md.tmpl +0 -81
  975. package/plugins/pbr/templates/research-outputs/project-research.md.tmpl +0 -99
  976. package/plugins/pbr/templates/research-outputs/synthesis.md.tmpl +0 -36
  977. /package/plugins/pbr/references/{agent-anti-patterns.md → archive/agent-anti-patterns.md} +0 -0
@@ -0,0 +1,1187 @@
1
+ /**
2
+ * lib/state.cjs — STATE.md operations for Plan-Build-Run tools.
3
+ *
4
+ * Handles loading, parsing, updating, patching, and advancing STATE.md.
5
+ * Pure-function API: all operations take planningDir as a parameter.
6
+ *
7
+ * Hybrid module merging PBR reference features with GSD-unique utilities.
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const {
13
+ parseYamlFrontmatter,
14
+ findFiles,
15
+ lockedFileUpdate,
16
+ calculateProgress,
17
+ determinePhaseStatus
18
+ } = require('./core');
19
+
20
+ // --- Status enum ---
21
+
22
+ const STATUS_VALUES = ['idle', 'planned', 'building', 'built', 'verifying', 'verified', 'complete'];
23
+
24
+ const STATUS_ALIASES = {
25
+ 'planning': 'planned',
26
+ 'executing': 'building',
27
+ 'done': 'complete',
28
+ 'completed': 'complete'
29
+ };
30
+
31
+ /**
32
+ * Normalize a status value to the canonical 7-value enum.
33
+ * Returns null if the value is not a valid status or alias.
34
+ *
35
+ * @param {string} value
36
+ * @returns {string|null}
37
+ */
38
+ function normalizeStatus(value) {
39
+ if (!value || typeof value !== 'string') return null;
40
+ const lower = value.toLowerCase().trim();
41
+ if (STATUS_VALUES.includes(lower)) return lower;
42
+ return STATUS_ALIASES[lower] || null;
43
+ }
44
+
45
+ /**
46
+ * Auto-regenerate STATE.md frontmatter fields from disk scan.
47
+ * Overwrites plans_total, plans_complete, progress_percent from filesystem truth.
48
+ * Normalizes status to the 7-value enum.
49
+ *
50
+ * @param {string} content - Current STATE.md content
51
+ * @param {string} planningDir - Path to .planning directory
52
+ * @returns {string} Updated content
53
+ */
54
+ function syncStateFrontmatter(content, planningDir) {
55
+ const fm = parseYamlFrontmatter(content);
56
+ if (fm.version !== 2 && fm.current_phase === undefined) return content;
57
+
58
+ const progress = stateCheckProgress(planningDir);
59
+ let updated = content;
60
+
61
+ updated = updateFrontmatterField(updated, 'plans_total', String(progress.total_plans));
62
+ updated = updateFrontmatterField(updated, 'plans_complete', String(progress.completed_plans));
63
+ updated = updateFrontmatterField(updated, 'progress_percent', String(progress.percentage));
64
+
65
+ // Normalize status if present
66
+ if (fm.status) {
67
+ const normalized = normalizeStatus(fm.status);
68
+ if (normalized && normalized !== fm.status) {
69
+ updated = updateFrontmatterField(updated, 'status', normalized);
70
+ }
71
+ }
72
+
73
+ return updated;
74
+ }
75
+
76
+ // --- Parsers ---
77
+
78
+ function parseStateMd(content) {
79
+ // Normalize CRLF to LF at parse boundary for cross-platform support
80
+ const normalized = content.replace(/\r\n/g, '\n');
81
+ const result = {
82
+ current_phase: null,
83
+ phase_name: null,
84
+ progress: null,
85
+ status: null,
86
+ line_count: normalized.split('\n').length,
87
+ format: 'legacy' // 'legacy' or 'frontmatter'
88
+ };
89
+
90
+ // Check for YAML frontmatter (version 2 format)
91
+ const frontmatter = parseYamlFrontmatter(normalized);
92
+ if (frontmatter.version === 2 || frontmatter.current_phase !== undefined) {
93
+ result.format = 'frontmatter';
94
+ result.current_phase = frontmatter.current_phase || null;
95
+ result.phase_name = frontmatter.phase_slug || frontmatter.phase_name || null;
96
+ result.status = frontmatter.status || null;
97
+ result.progress = frontmatter.progress_percent !== undefined ? frontmatter.progress_percent : null;
98
+ result.plans_total = frontmatter.plans_total || null;
99
+ result.plans_complete = frontmatter.plans_complete || null;
100
+ result.last_activity = frontmatter.last_activity || null;
101
+ result.last_command = frontmatter.last_command || null;
102
+ result.blockers = frontmatter.blockers || [];
103
+ result.velocity = frontmatter.velocity || null;
104
+ result.session_last = frontmatter.session_last || null;
105
+ result.session_stopped_at = frontmatter.session_stopped_at || null;
106
+ result.session_resume = frontmatter.session_resume || null;
107
+ return result;
108
+ }
109
+
110
+ // Legacy regex-based parsing (version 1 format, no frontmatter)
111
+ // DEPRECATED (2026-02): v1 STATE.md format (no YAML frontmatter) is deprecated.
112
+ // New projects should use v2 (frontmatter) format, generated by /pbr:setup.
113
+ // v1 support will be removed in a future major version.
114
+ process.stderr.write('[pbr] WARNING: STATE.md uses legacy v1 format. Run /pbr:setup to migrate to v2 format.\n');
115
+
116
+ // Extract "Phase: N of M"
117
+ const phaseMatch = normalized.match(/Phase:\s*(\d+)\s+of\s+(\d+)/);
118
+ if (phaseMatch) {
119
+ result.current_phase = parseInt(phaseMatch[1], 10);
120
+ result.total_phases = parseInt(phaseMatch[2], 10);
121
+ }
122
+
123
+ // Extract phase name (line after "Phase:")
124
+ const nameMatch = normalized.match(/--\s+(.+?)(?:\n|$)/);
125
+ if (nameMatch) {
126
+ result.phase_name = nameMatch[1].trim();
127
+ }
128
+
129
+ // Extract progress percentage
130
+ const progressMatch = normalized.match(/(\d+)%/);
131
+ if (progressMatch) {
132
+ result.progress = parseInt(progressMatch[1], 10);
133
+ }
134
+
135
+ // Extract plan status
136
+ const statusMatch = normalized.match(/Status:\s*(.+?)(?:\n|$)/i);
137
+ if (statusMatch) {
138
+ result.status = statusMatch[1].trim();
139
+ }
140
+
141
+ return result;
142
+ }
143
+
144
+ // --- Mutation helpers ---
145
+
146
+ /**
147
+ * Update a field in legacy (non-frontmatter) STATE.md content.
148
+ * Pure function: content in, content out.
149
+ */
150
+ function updateLegacyStateField(content, field, value) {
151
+ const lines = content.replace(/\r\n/g, '\n').split('\n');
152
+
153
+ switch (field) {
154
+ case 'current_phase': {
155
+ const idx = lines.findIndex(l => /Phase:\s*\d+\s+of\s+\d+/.test(l));
156
+ if (idx !== -1) {
157
+ lines[idx] = lines[idx].replace(/(Phase:\s*)\d+/, (_, prefix) => `${prefix}${value}`);
158
+ }
159
+ break;
160
+ }
161
+ case 'status': {
162
+ const idx = lines.findIndex(l => /^Status:/i.test(l));
163
+ if (idx !== -1) {
164
+ lines[idx] = `Status: ${value}`;
165
+ } else {
166
+ const phaseIdx = lines.findIndex(l => /Phase:/.test(l));
167
+ if (phaseIdx !== -1) {
168
+ lines.splice(phaseIdx + 1, 0, `Status: ${value}`);
169
+ } else {
170
+ lines.push(`Status: ${value}`);
171
+ }
172
+ }
173
+ break;
174
+ }
175
+ case 'plans_complete': {
176
+ const idx = lines.findIndex(l => /Plan:\s*\d+\s+of\s+\d+/.test(l));
177
+ if (idx !== -1) {
178
+ lines[idx] = lines[idx].replace(/(Plan:\s*)\d+/, (_, prefix) => `${prefix}${value}`);
179
+ }
180
+ break;
181
+ }
182
+ case 'last_activity': {
183
+ const idx = lines.findIndex(l => /^Last Activity:/i.test(l));
184
+ if (idx !== -1) {
185
+ lines[idx] = `Last Activity: ${value}`;
186
+ } else {
187
+ const statusIdx = lines.findIndex(l => /^Status:/i.test(l));
188
+ if (statusIdx !== -1) {
189
+ lines.splice(statusIdx + 1, 0, `Last Activity: ${value}`);
190
+ } else {
191
+ lines.push(`Last Activity: ${value}`);
192
+ }
193
+ }
194
+ break;
195
+ }
196
+ }
197
+
198
+ return lines.join('\n');
199
+ }
200
+
201
+ /**
202
+ * Update a field in YAML frontmatter content.
203
+ * Pure function: content in, content out.
204
+ */
205
+ function updateFrontmatterField(content, field, value) {
206
+ const match = content.match(/^(---\s*\n)([\s\S]*?)(\n---)/);
207
+ if (!match) return content;
208
+
209
+ const before = match[1];
210
+ let yaml = match[2];
211
+ const after = match[3];
212
+ const rest = content.slice(match[0].length);
213
+
214
+ // Format value: null stays bare, integers stay bare, strings get quotes
215
+ const isNull = value === null || value === 'null';
216
+ const isNum = !isNull && /^\d+$/.test(String(value));
217
+ const formatted = isNull ? 'null' : isNum ? value : `"${value}"`;
218
+
219
+ const fieldRegex = new RegExp(`^(${field})\\s*:.*$`, 'm');
220
+ if (fieldRegex.test(yaml)) {
221
+ yaml = yaml.replace(fieldRegex, () => `${field}: ${formatted}`);
222
+ } else {
223
+ yaml = yaml + `\n${field}: ${formatted}`;
224
+ }
225
+
226
+ return before + yaml + after + rest;
227
+ }
228
+
229
+ // --- Body sync ---
230
+
231
+ /**
232
+ * Build a text progress bar: [####::::::::::::::::] 20%
233
+ * @param {number} pct - Percentage 0-100
234
+ * @returns {string}
235
+ */
236
+ function buildProgressBar(pct) {
237
+ const width = 20;
238
+ const filled = Math.round((pct / 100) * width);
239
+ const empty = width - filled;
240
+ return `[${'█'.repeat(filled)}${'░'.repeat(empty)}] ${pct}%`;
241
+ }
242
+
243
+ /**
244
+ * After updating a frontmatter field, also update the corresponding body line
245
+ * so both representations stay in sync. Pure function: content in, content out.
246
+ *
247
+ * Field-to-body mapping:
248
+ * status -> "Status: {value}"
249
+ * plans_complete -> "Plan: {N} of ..." (replaces the number before "of")
250
+ * progress_percent-> "Progress: [{bar}] {N}%"
251
+ * last_activity -> "Last activity: {value}"
252
+ * current_phase -> "Phase: {N} of ..." (replaces the number before "of")
253
+ * phase_slug -> "Phase: N of M ({Name})" (replaces the parenthesized name)
254
+ *
255
+ * Fields without body equivalents (last_command, blockers) are no-ops.
256
+ *
257
+ * @param {string} content - Full STATE.md content (frontmatter already updated)
258
+ * @param {string} field - The field that was updated
259
+ * @param {string} value - The new value
260
+ * @returns {string} Content with body line also updated
261
+ */
262
+ function syncBodyLine(content, field, value) {
263
+ switch (field) {
264
+ case 'status': {
265
+ const display = String(value).replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
266
+ return content.replace(/^Status:\s*.+/m, `Status: ${display}`);
267
+ }
268
+ case 'plans_complete': {
269
+ return content.replace(/^(Plan:\s*)\d+/m, `$1${value}`);
270
+ }
271
+ case 'plans_total': {
272
+ return content.replace(/^(Plan:\s*\d+\s+of\s+)\d+/m, `$1${value}`);
273
+ }
274
+ case 'progress_percent': {
275
+ const pct = parseInt(value, 10);
276
+ if (isNaN(pct)) return content;
277
+ return content.replace(/^Progress:\s*.+/m, `Progress: ${buildProgressBar(pct)}`);
278
+ }
279
+ case 'last_activity': {
280
+ return content.replace(/^(Last activity:\s*).+/im, `$1${value}`);
281
+ }
282
+ case 'current_phase': {
283
+ return content.replace(/^(Phase:\s*)\d+/m, `$1${value}`);
284
+ }
285
+ case 'phase_slug': {
286
+ const name = String(value).replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
287
+ // Replace "(OldName)" or "-- OldName" in the Phase line
288
+ const withParens = content.replace(/^(Phase:\s*\d+\s+of\s+\d+\s*)\(.*?\)/m, `$1(${name})`);
289
+ if (withParens !== content) return withParens;
290
+ return content.replace(/^(Phase:\s*\d+\s+of\s+\d+\s*)--\s*.+/m, `$1-- ${name}`);
291
+ }
292
+ case 'session_last': {
293
+ const pattern = /^Last session:\s*.+/im;
294
+ if (pattern.test(content)) return content.replace(pattern, `Last session: ${value}`);
295
+ return content;
296
+ }
297
+ case 'session_stopped_at': {
298
+ const pattern = /^Stopped at:\s*.+/im;
299
+ if (pattern.test(content)) return content.replace(pattern, `Stopped at: ${value}`);
300
+ return content;
301
+ }
302
+ case 'session_resume': {
303
+ const pattern = /^Resume:\s*.+/im;
304
+ if (pattern.test(content)) return content.replace(pattern, `Resume: ${value}`);
305
+ return content;
306
+ }
307
+ default:
308
+ return content;
309
+ }
310
+ }
311
+
312
+ // --- Commands ---
313
+
314
+ /**
315
+ * Load full project state from .planning/ directory.
316
+ *
317
+ * @param {string} [planningDir] - Path to .planning directory
318
+ * @returns {object} Full state object
319
+ */
320
+ function stateLoad(planningDir) {
321
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
322
+ const { parseRoadmapMd } = require('./roadmap');
323
+
324
+ const result = {
325
+ exists: false,
326
+ config: null,
327
+ state: null,
328
+ roadmap: null,
329
+ phase_count: 0,
330
+ current_phase: null,
331
+ progress: null
332
+ };
333
+
334
+ if (!fs.existsSync(dir)) {
335
+ return result;
336
+ }
337
+ result.exists = true;
338
+
339
+ // Load config.json
340
+ const configPath = path.join(dir, 'config.json');
341
+ if (fs.existsSync(configPath)) {
342
+ try {
343
+ result.config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
344
+ } catch (_) {
345
+ result.config = { _error: 'Failed to parse config.json' };
346
+ }
347
+ }
348
+
349
+ // Load STATE.md
350
+ const statePath = path.join(dir, 'STATE.md');
351
+ if (fs.existsSync(statePath)) {
352
+ const content = fs.readFileSync(statePath, 'utf8');
353
+ result.state = parseStateMd(content);
354
+ }
355
+
356
+ // Load ROADMAP.md
357
+ const roadmapPath = path.join(dir, 'ROADMAP.md');
358
+ if (fs.existsSync(roadmapPath)) {
359
+ const content = fs.readFileSync(roadmapPath, 'utf8');
360
+ result.roadmap = parseRoadmapMd(content);
361
+ result.phase_count = result.roadmap.phases.length;
362
+ }
363
+
364
+ // Extract current phase
365
+ if (result.state && result.state.current_phase) {
366
+ result.current_phase = result.state.current_phase;
367
+ }
368
+
369
+ // Calculate progress
370
+ result.progress = calculateProgress(dir);
371
+
372
+ return result;
373
+ }
374
+
375
+ /**
376
+ * Recalculate progress from filesystem.
377
+ *
378
+ * @param {string} [planningDir] - Path to .planning directory
379
+ * @returns {object} Progress object
380
+ */
381
+ function stateCheckProgress(planningDir) {
382
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
383
+ const phasesDir = path.join(dir, 'phases');
384
+ if (!fs.existsSync(phasesDir)) {
385
+ return { phases: [], total_plans: 0, completed_plans: 0, percentage: 0 };
386
+ }
387
+
388
+ const phases = [];
389
+ let totalPlans = 0;
390
+ let completedPlans = 0;
391
+
392
+ const entries = fs.readdirSync(phasesDir, { withFileTypes: true })
393
+ .filter(e => e.isDirectory())
394
+ .sort((a, b) => a.name.localeCompare(b.name));
395
+
396
+ for (const entry of entries) {
397
+ const phaseDir = path.join(phasesDir, entry.name);
398
+ const plans = findFiles(phaseDir, /PLAN.*\.md$/i);
399
+ const summaries = findFiles(phaseDir, /^SUMMARY-.*\.md$/);
400
+ const verification = fs.existsSync(path.join(phaseDir, 'VERIFICATION.md'));
401
+
402
+ const completedSummaries = summaries.filter(s => {
403
+ const content = fs.readFileSync(path.join(phaseDir, s), 'utf8');
404
+ return /status:\s*["']?complete/i.test(content);
405
+ });
406
+
407
+ const phaseInfoObj = {
408
+ directory: entry.name,
409
+ plans: plans.length,
410
+ summaries: summaries.length,
411
+ completed: completedSummaries.length,
412
+ has_verification: verification,
413
+ status: determinePhaseStatus(plans.length, completedSummaries.length, summaries.length, verification, phaseDir)
414
+ };
415
+
416
+ phases.push(phaseInfoObj);
417
+ totalPlans += plans.length;
418
+ completedPlans += completedSummaries.length;
419
+ }
420
+
421
+ return {
422
+ phases,
423
+ total_plans: totalPlans,
424
+ completed_plans: completedPlans,
425
+ percentage: totalPlans > 0 ? Math.round((completedPlans / totalPlans) * 100) : 0
426
+ };
427
+ }
428
+
429
+ /**
430
+ * Atomically update a field in STATE.md using lockedFileUpdate.
431
+ * Supports both legacy and frontmatter (v2) formats.
432
+ *
433
+ * @param {string} field - One of: current_phase, status, plans_complete, last_activity,
434
+ * progress_percent, phase_slug, total_phases, last_command, blockers
435
+ * @param {string} value - New value (use 'now' for last_activity to auto-timestamp)
436
+ * @param {string} [planningDir] - Path to .planning directory
437
+ */
438
+ function stateUpdate(field, value, planningDir) {
439
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
440
+ const statePath = path.join(dir, 'STATE.md');
441
+ if (!fs.existsSync(statePath)) {
442
+ return { success: false, error: 'STATE.md not found' };
443
+ }
444
+
445
+ // All 13 STATE.md frontmatter fields supported by stateUpdate
446
+ const validFields = [
447
+ 'current_phase',
448
+ 'status',
449
+ 'plans_complete',
450
+ 'plans_total',
451
+ 'last_activity',
452
+ 'progress_percent',
453
+ 'phase_slug',
454
+ 'last_command',
455
+ 'blockers',
456
+ 'velocity',
457
+ 'session_last',
458
+ 'session_stopped_at',
459
+ 'session_resume'
460
+ ];
461
+ if (!validFields.includes(field)) {
462
+ return { success: false, error: `Invalid field: ${field}. Valid fields: ${validFields.join(', ')}` };
463
+ }
464
+
465
+ // Auto-timestamp
466
+ if (field === 'last_activity' && value === 'now') {
467
+ value = new Date().toISOString().slice(0, 19).replace('T', ' ');
468
+ }
469
+
470
+ const result = lockedFileUpdate(statePath, (content) => {
471
+ const fm = parseYamlFrontmatter(content);
472
+ if (fm.version === 2 || fm.current_phase !== undefined) {
473
+ let updated = updateFrontmatterField(content, field, value);
474
+ updated = syncBodyLine(updated, field, value);
475
+ return updated;
476
+ }
477
+ return updateLegacyStateField(content, field, value);
478
+ });
479
+
480
+ if (result.success) {
481
+ return { success: true, field, value };
482
+ }
483
+ return { success: false, error: result.error };
484
+ }
485
+
486
+ /**
487
+ * Batch-update multiple STATE.md fields at once.
488
+ *
489
+ * @param {string} jsonStr - JSON string of field:value pairs
490
+ * @param {string} [planningDir] - Path to .planning directory
491
+ */
492
+ function statePatch(jsonStr, planningDir) {
493
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
494
+ const statePath = path.join(dir, 'STATE.md');
495
+ if (!fs.existsSync(statePath)) return { success: false, error: "STATE.md not found" };
496
+ let fields;
497
+ try { fields = JSON.parse(jsonStr); } catch (_e) { return { success: false, error: "Invalid JSON" }; }
498
+ const validFields = ["current_phase", "status", "plans_complete", "plans_total", "last_activity", "progress_percent", "phase_slug", "last_command", "blockers", "velocity", "session_last", "session_stopped_at", "session_resume"];
499
+ const invalidFields = Object.keys(fields).filter(f => !validFields.includes(f));
500
+ if (invalidFields.length > 0) return { success: false, error: "Unknown fields: " + invalidFields.join(", ") };
501
+
502
+ const result = lockedFileUpdate(statePath, (content) => {
503
+ let updated = content;
504
+ const fm = parseYamlFrontmatter(updated);
505
+ const isFrontmatter = fm.version === 2 || fm.current_phase !== undefined;
506
+ for (const [field, value] of Object.entries(fields)) {
507
+ let val = String(value);
508
+ if (field === 'last_activity' && val === 'now') {
509
+ val = new Date().toISOString().slice(0, 19).replace('T', ' ');
510
+ }
511
+ if (isFrontmatter) {
512
+ updated = updateFrontmatterField(updated, field, val);
513
+ updated = syncBodyLine(updated, field, val);
514
+ } else {
515
+ updated = updateLegacyStateField(updated, field, val);
516
+ }
517
+ }
518
+ return updated;
519
+ });
520
+
521
+ if (!result.success) return { success: false, error: result.error };
522
+ return { success: true, updated: Object.keys(fields) };
523
+ }
524
+
525
+ /**
526
+ * Advance the plan counter in STATE.md by 1.
527
+ *
528
+ * @param {string} [planningDir] - Path to .planning directory
529
+ */
530
+ function stateAdvancePlan(planningDir) {
531
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
532
+ const statePath = path.join(dir, 'STATE.md');
533
+ if (!fs.existsSync(statePath)) return { success: false, error: "STATE.md not found" };
534
+
535
+ let resultData = {};
536
+ const result = lockedFileUpdate(statePath, (content) => {
537
+ const planMatch = content.match(/Plan:\s*(\d+)\s+of\s+(\d+)/);
538
+ if (!planMatch) {
539
+ resultData = { error: "Could not find Plan: N of M in STATE.md" };
540
+ return content;
541
+ }
542
+ const current = parseInt(planMatch[1], 10);
543
+ const total = parseInt(planMatch[2], 10);
544
+ const next = Math.min(current + 1, total);
545
+ const progressPct = total > 0 ? Math.round((next / total) * 100) : 0;
546
+ resultData = { previous_plan: current, current_plan: next, total_plans: total, progress_percent: progressPct };
547
+
548
+ let updated = content;
549
+ const fm = parseYamlFrontmatter(content);
550
+ if (fm.version === 2 || fm.current_phase !== undefined) {
551
+ updated = updateFrontmatterField(updated, 'plans_complete', String(next));
552
+ updated = syncBodyLine(updated, 'plans_complete', String(next));
553
+ updated = updateFrontmatterField(updated, 'progress_percent', String(progressPct));
554
+ updated = syncBodyLine(updated, 'progress_percent', String(progressPct));
555
+ } else {
556
+ updated = updateLegacyStateField(updated, 'plans_complete', String(next));
557
+ }
558
+ return updated;
559
+ });
560
+
561
+ if (resultData.error) return { success: false, error: resultData.error };
562
+ if (!result.success) return { success: false, error: result.error };
563
+ return { success: true, ...resultData };
564
+ }
565
+
566
+ /**
567
+ * Record a session metric in STATE.md (history section).
568
+ *
569
+ * @param {string[]} metricArgs - CLI args like ['--duration', '30m', '--plans-completed', '3']
570
+ * @param {string} [planningDir] - Path to .planning directory
571
+ */
572
+ function stateRecordMetric(metricArgs, planningDir) {
573
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
574
+ let duration = null, plansCompleted = null;
575
+ for (let i = 0; i < metricArgs.length; i++) {
576
+ if (metricArgs[i] === "--duration" && metricArgs[i + 1]) {
577
+ const match = metricArgs[i + 1].match(/(\d+)(m|s|h)/);
578
+ if (match) { const val = parseInt(match[1], 10); const unit = match[2]; duration = unit === "h" ? val * 60 : unit === "s" ? Math.round(val / 60) : val; }
579
+ i++;
580
+ } else if (metricArgs[i] === "--plans-completed" && metricArgs[i + 1]) {
581
+ plansCompleted = parseInt(metricArgs[i + 1], 10); i++;
582
+ }
583
+ }
584
+ const parts = [];
585
+ if (duration !== null) parts.push("duration: " + duration + "m");
586
+ if (plansCompleted !== null) parts.push("plans_completed: " + plansCompleted);
587
+
588
+ // Append metric to STATE.md metrics table if present
589
+ if (parts.length > 0) {
590
+ const statePath = path.join(dir, 'STATE.md');
591
+ if (fs.existsSync(statePath)) {
592
+ lockedFileUpdate(statePath, (content) => {
593
+ const metricsPattern = /(##\s*Performance Metrics[\s\S]*?\n\|[^\n]+\n\|[-|\s]+\n)([\s\S]*?)(?=\n##|\n$|$)/i;
594
+ const metricsMatch = content.match(metricsPattern);
595
+ if (metricsMatch) {
596
+ let tableBody = metricsMatch[2].trimEnd();
597
+ const newRow = `| Metric | ${parts.join(', ')} |`;
598
+ if (tableBody.trim() === '' || tableBody.includes('None yet')) {
599
+ tableBody = newRow;
600
+ } else {
601
+ tableBody = tableBody + '\n' + newRow;
602
+ }
603
+ return content.replace(metricsPattern, (_match, header) => `${header}${tableBody}\n`);
604
+ }
605
+ return content;
606
+ });
607
+ }
608
+ }
609
+
610
+ stateUpdate("last_activity", "now", dir);
611
+ return { success: true, duration_minutes: duration, plans_completed: plansCompleted };
612
+ }
613
+
614
+ /**
615
+ * Record a velocity metric in STATE.md frontmatter.
616
+ * Stores metrics as a JSON string in the `velocity` field.
617
+ * Tracks last 5 entries per metric type and calculates trend.
618
+ *
619
+ * @param {string} metricType - Metric type (e.g., 'plan_duration', 'phase_duration')
620
+ * @param {number|string} value - Metric value
621
+ * @param {string} [planningDir] - Path to .planning directory
622
+ * @returns {object} { success, metricType, value, trend }
623
+ */
624
+ function stateRecordVelocity(metricType, value, planningDir) {
625
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
626
+ const statePath = path.join(dir, 'STATE.md');
627
+ if (!fs.existsSync(statePath)) {
628
+ return { success: false, error: 'STATE.md not found' };
629
+ }
630
+
631
+ // Read current velocity from frontmatter
632
+ const content = fs.readFileSync(statePath, 'utf8');
633
+ const parsed = parseStateMd(content);
634
+ let velocity = {};
635
+ if (parsed.velocity) {
636
+ try {
637
+ velocity = typeof parsed.velocity === 'string' ? JSON.parse(parsed.velocity) : parsed.velocity;
638
+ } catch (_) {
639
+ velocity = {};
640
+ }
641
+ }
642
+
643
+ // Initialize metric history if needed
644
+ if (!velocity[metricType]) {
645
+ velocity[metricType] = { history: [], trend: 'stable' };
646
+ }
647
+
648
+ const numValue = Number(value);
649
+ const entry = { value: numValue, timestamp: new Date().toISOString() };
650
+ velocity[metricType].history.push(entry);
651
+
652
+ // Keep last 5 entries
653
+ if (velocity[metricType].history.length > 5) {
654
+ velocity[metricType].history = velocity[metricType].history.slice(-5);
655
+ }
656
+
657
+ // Calculate trend from history
658
+ const hist = velocity[metricType].history;
659
+ if (hist.length >= 2) {
660
+ const recent = hist.slice(-3).map(h => h.value);
661
+ const avg = recent.reduce((a, b) => a + b, 0) / recent.length;
662
+ const first = hist[0].value;
663
+ if (avg < first * 0.85) {
664
+ velocity[metricType].trend = 'improving';
665
+ } else if (avg > first * 1.15) {
666
+ velocity[metricType].trend = 'degrading';
667
+ } else {
668
+ velocity[metricType].trend = 'stable';
669
+ }
670
+ }
671
+
672
+ // Write back via stateUpdate
673
+ const result = stateUpdate('velocity', JSON.stringify(velocity), dir);
674
+ if (!result.success) return result;
675
+ return { success: true, metricType, value: numValue, trend: velocity[metricType].trend };
676
+ }
677
+
678
+ /**
679
+ * Record session continuity info in STATE.md.
680
+ * Updates session_last, session_stopped_at, and session_resume fields.
681
+ *
682
+ * @param {string} stoppedAt - Description of where the session stopped
683
+ * @param {string} resumeFile - Path to resume file (e.g., .PROGRESS-02-01)
684
+ * @param {string} [planningDir] - Path to .planning directory
685
+ * @returns {object} { success, session_last, session_stopped_at, session_resume }
686
+ */
687
+ function stateRecordSession(stoppedAt, resumeFile, planningDir) {
688
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
689
+ const now = new Date().toISOString().slice(0, 19).replace('T', ' ');
690
+
691
+ const r1 = stateUpdate('session_last', now, dir);
692
+ if (!r1.success) return r1;
693
+
694
+ const r2 = stateUpdate('session_stopped_at', stoppedAt, dir);
695
+ if (!r2.success) return r2;
696
+
697
+ const r3 = stateUpdate('session_resume', resumeFile, dir);
698
+ if (!r3.success) return r3;
699
+
700
+ return { success: true, session_last: now, session_stopped_at: stoppedAt, session_resume: resumeFile };
701
+ }
702
+
703
+ /**
704
+ * Record an activity description with today's date in STATE.md last_activity.
705
+ *
706
+ * @param {string} description - Activity description (e.g., "Built phase 3")
707
+ * @param {string} [planningDir] - Path to .planning directory
708
+ * @returns {object} { success: true, last_activity: "YYYY-MM-DD description" }
709
+ */
710
+ function stateRecordActivity(description, planningDir) {
711
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
712
+ const today = new Date().toISOString().slice(0, 10);
713
+ const value = `${today} ${description}`;
714
+ const result = stateUpdate('last_activity', value, dir);
715
+ if (!result.success) return result;
716
+ return { success: true, last_activity: value };
717
+ }
718
+
719
+ /**
720
+ * Recalculate progress from filesystem and atomically update STATE.md
721
+ * with progress_percent, plans_complete, and plans_total.
722
+ *
723
+ * @param {string} [planningDir] - Path to .planning directory
724
+ * @returns {object} { success, percent, completed_plans, total_plans }
725
+ */
726
+ function stateUpdateProgress(planningDir) {
727
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
728
+ const statePath = path.join(dir, 'STATE.md');
729
+ if (!fs.existsSync(statePath)) {
730
+ return { success: false, error: 'STATE.md not found' };
731
+ }
732
+
733
+ const progress = stateCheckProgress(dir);
734
+ const { percentage, completed_plans, total_plans } = progress;
735
+
736
+ const result = lockedFileUpdate(statePath, (content) => {
737
+ let updated = content;
738
+ // Update frontmatter fields
739
+ updated = updateFrontmatterField(updated, 'progress_percent', percentage);
740
+ updated = updateFrontmatterField(updated, 'plans_complete', completed_plans);
741
+ updated = updateFrontmatterField(updated, 'plans_total', total_plans);
742
+ // Update body lines
743
+ updated = syncBodyLine(updated, 'progress_percent', percentage);
744
+ updated = syncBodyLine(updated, 'plans_complete', completed_plans);
745
+ updated = syncBodyLine(updated, 'plans_total', total_plans);
746
+ return updated;
747
+ });
748
+
749
+ if (!result.success) return { success: false, error: result.error };
750
+ return { success: true, percent: percentage, completed_plans, total_plans };
751
+ }
752
+
753
+ /**
754
+ * Get current state status summary (minimal, for quick checks).
755
+ *
756
+ * @param {string} [planningDir] - Path to .planning directory
757
+ * @returns {object} { status, current_phase, phase_name }
758
+ */
759
+ function stateGetStatus(planningDir) {
760
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
761
+ const statePath = path.join(dir, 'STATE.md');
762
+ if (!fs.existsSync(statePath)) {
763
+ return { error: 'STATE.md not found' };
764
+ }
765
+ const content = fs.readFileSync(statePath, 'utf8');
766
+ const parsed = parseStateMd(content);
767
+ return {
768
+ status: parsed.status,
769
+ current_phase: parsed.current_phase,
770
+ phase_name: parsed.phase_name,
771
+ progress: parsed.progress,
772
+ format: parsed.format
773
+ };
774
+ }
775
+
776
+ /**
777
+ * Take a comprehensive snapshot of project state for display/reporting.
778
+ * Extracts all fields, decisions, blockers, and session info from STATE.md.
779
+ *
780
+ * @param {string} [planningDir] - Path to .planning directory
781
+ * @returns {object} Full state snapshot
782
+ */
783
+ function stateSnapshot(planningDir) {
784
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
785
+ const statePath = path.join(dir, 'STATE.md');
786
+ if (!fs.existsSync(statePath)) {
787
+ return { error: 'STATE.md not found' };
788
+ }
789
+
790
+ const content = fs.readFileSync(statePath, 'utf8');
791
+ const parsed = parseStateMd(content);
792
+
793
+ // Extract decisions
794
+ const decisions = [];
795
+ const decisionsMatch = content.match(/###?\s*(?:Decisions|Decisions Made)[\s\S]*?\n([\s\S]*?)(?=\n###?|\n##[^#]|$)/i);
796
+ if (decisionsMatch) {
797
+ const items = decisionsMatch[1].match(/^-\s+(.+)$/gm) || [];
798
+ for (const item of items) {
799
+ decisions.push(item.replace(/^-\s+/, '').trim());
800
+ }
801
+ }
802
+
803
+ // Extract blockers
804
+ const blockers = [];
805
+ const blockersMatch = content.match(/###?\s*(?:Blockers|Blockers\/Concerns|Concerns)[\s\S]*?\n([\s\S]*?)(?=\n###?|\n##[^#]|$)/i);
806
+ if (blockersMatch) {
807
+ const items = blockersMatch[1].match(/^-\s+(.+)$/gm) || [];
808
+ for (const item of items) {
809
+ const text = item.replace(/^-\s+/, '').trim();
810
+ if (text && !text.match(/^None\.?$/i)) {
811
+ blockers.push(text);
812
+ }
813
+ }
814
+ }
815
+
816
+ // Extract session info
817
+ const session = { last_date: null, stopped_at: null, resume_file: null };
818
+ const lastSessionMatch = content.match(/Last session:\s*(.+)/i);
819
+ if (lastSessionMatch) session.last_date = lastSessionMatch[1].trim();
820
+ const stoppedMatch = content.match(/Stopped at:\s*(.+)/i);
821
+ if (stoppedMatch) session.stopped_at = stoppedMatch[1].trim();
822
+ const resumeMatch = content.match(/Resume file:\s*(.+)/i);
823
+ if (resumeMatch) session.resume_file = resumeMatch[1].trim();
824
+
825
+ return {
826
+ ...parsed,
827
+ decisions,
828
+ blockers: blockers.length > 0 ? blockers : (parsed.blockers || []),
829
+ session
830
+ };
831
+ }
832
+
833
+ /**
834
+ * Atomically mark a phase as complete in STATE.md.
835
+ * Updates status to "complete" and records phase completion in last_activity,
836
+ * all within a single lockedFileUpdate call for atomicity.
837
+ *
838
+ * @param {number|string} phaseNum - Phase number to mark complete
839
+ * @param {string} [planningDir] - Path to .planning directory
840
+ * @returns {object} { success: true, phase, status } or { success: false, error }
841
+ */
842
+ function statePhaseComplete(phaseNum, planningDir) {
843
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
844
+ const statePath = path.join(dir, 'STATE.md');
845
+ if (!fs.existsSync(statePath)) {
846
+ return { success: false, error: 'STATE.md not found' };
847
+ }
848
+
849
+ const today = new Date().toISOString().slice(0, 10);
850
+ const activityValue = `${today} Phase ${phaseNum} complete`;
851
+
852
+ const result = lockedFileUpdate(statePath, (content) => {
853
+ let updated = content;
854
+ // Update frontmatter fields
855
+ updated = updateFrontmatterField(updated, 'status', 'complete');
856
+ updated = updateFrontmatterField(updated, 'last_activity', activityValue);
857
+ // Sync body lines
858
+ updated = syncBodyLine(updated, 'status', 'complete');
859
+ updated = syncBodyLine(updated, 'last_activity', activityValue);
860
+ updated = syncStateFrontmatter(updated, dir);
861
+ return updated;
862
+ });
863
+
864
+ if (!result.success) {
865
+ return { success: false, error: result.error };
866
+ }
867
+ return { success: true, phase: Number(phaseNum), status: 'complete' };
868
+ }
869
+
870
+ /**
871
+ * Re-derive state from filesystem and correct any drift in STATE.md.
872
+ * Compares plans_complete, plans_total, and progress_percent between
873
+ * the current STATE.md and the filesystem-derived values from stateCheckProgress.
874
+ * Corrects any differences atomically via lockedFileUpdate.
875
+ *
876
+ * @param {string} [planningDir] - Path to .planning directory
877
+ * @returns {object} { success, corrected: [...fieldNames], derived: { plans_complete, plans_total, progress_percent } }
878
+ */
879
+ function stateRederive(planningDir) {
880
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
881
+ const statePath = path.join(dir, 'STATE.md');
882
+ if (!fs.existsSync(statePath)) {
883
+ return { success: false, error: 'STATE.md not found' };
884
+ }
885
+
886
+ // Derive current state from filesystem
887
+ const progress = stateCheckProgress(dir);
888
+ const derived = {
889
+ plans_complete: progress.completed_plans,
890
+ plans_total: progress.total_plans,
891
+ progress_percent: progress.percentage
892
+ };
893
+
894
+ // Read current STATE.md values
895
+ const content = fs.readFileSync(statePath, 'utf8');
896
+ const current = parseStateMd(content);
897
+
898
+ // Compare and find drifted fields
899
+ const corrected = [];
900
+ if (Number(current.plans_complete || 0) !== derived.plans_complete) {
901
+ corrected.push('plans_complete');
902
+ }
903
+ if (Number(current.plans_total || 0) !== derived.plans_total) {
904
+ corrected.push('plans_total');
905
+ }
906
+ if (Number(current.progress || 0) !== derived.progress_percent) {
907
+ corrected.push('progress_percent');
908
+ }
909
+
910
+ // If drift detected, correct atomically
911
+ if (corrected.length > 0) {
912
+ const result = lockedFileUpdate(statePath, (fileContent) => {
913
+ let updated = fileContent;
914
+ for (const field of corrected) {
915
+ const value = derived[field];
916
+ updated = updateFrontmatterField(updated, field, value);
917
+ updated = syncBodyLine(updated, field, value);
918
+ }
919
+ return updated;
920
+ });
921
+
922
+ if (!result.success) {
923
+ return { success: false, error: result.error };
924
+ }
925
+ }
926
+
927
+ return { success: true, corrected, derived };
928
+ }
929
+
930
+ /**
931
+ * Signal that the project is waiting on an external action.
932
+ * Creates a WAITING.json file in the .planning directory.
933
+ *
934
+ * @param {string} reason - Why the project is waiting
935
+ * @param {string} [expectedDuration] - Expected wait duration (e.g., 'minutes', 'hours', 'unknown')
936
+ * @param {string} [planningDir] - Path to .planning directory
937
+ * @returns {object} { success, path }
938
+ */
939
+ function stateSignalWaiting(reason, expectedDuration, planningDir) {
940
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
941
+ const waitingPath = path.join(dir, 'WAITING.json');
942
+ const data = {
943
+ status: 'waiting',
944
+ reason,
945
+ expected_duration: expectedDuration || 'unknown',
946
+ created_at: new Date().toISOString(),
947
+ signal: 'waiting'
948
+ };
949
+ fs.writeFileSync(waitingPath, JSON.stringify(data, null, 2), 'utf-8');
950
+ return { success: true, path: waitingPath };
951
+ }
952
+
953
+ /**
954
+ * Clear the waiting signal by removing WAITING.json.
955
+ *
956
+ * @param {string} [planningDir] - Path to .planning directory
957
+ * @returns {object} { success, was_waiting }
958
+ */
959
+ function stateSignalResume(planningDir) {
960
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
961
+ const waitingPath = path.join(dir, 'WAITING.json');
962
+ if (fs.existsSync(waitingPath)) {
963
+ fs.unlinkSync(waitingPath);
964
+ return { success: true, was_waiting: true };
965
+ }
966
+ return { success: true, was_waiting: false };
967
+ }
968
+
969
+ /**
970
+ * Check if the project is currently in a waiting state.
971
+ *
972
+ * @param {string} [planningDir] - Path to .planning directory
973
+ * @returns {object|null} Parsed WAITING.json contents, or null if not waiting
974
+ */
975
+ function stateCheckWaiting(planningDir) {
976
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
977
+ const waitingPath = path.join(dir, 'WAITING.json');
978
+ if (!fs.existsSync(waitingPath)) return null;
979
+ try {
980
+ return JSON.parse(fs.readFileSync(waitingPath, 'utf-8'));
981
+ } catch (_) { return null; }
982
+ }
983
+
984
+ /**
985
+ * Reconcile STATE.md with ROADMAP.md by re-deriving phases_total and
986
+ * current_phase from the active milestone, and detecting phantom phase
987
+ * rows (ROADMAP.md progress rows with no directory on disk).
988
+ *
989
+ * @param {string} [planningDir] - Path to .planning directory
990
+ * @returns {object} { corrected: boolean, changes: string[], phantoms: string[] }
991
+ */
992
+ function stateReconcile(planningDir) {
993
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
994
+ const statePath = path.join(dir, 'STATE.md');
995
+ const roadmapPath = path.join(dir, 'ROADMAP.md');
996
+ const phasesDir = path.join(dir, 'phases');
997
+
998
+ const changes = [];
999
+ const phantoms = [];
1000
+
1001
+ if (!fs.existsSync(statePath)) {
1002
+ return { corrected: false, changes: [], phantoms: [], error: 'STATE.md not found' };
1003
+ }
1004
+ if (!fs.existsSync(roadmapPath)) {
1005
+ return { corrected: false, changes: [], phantoms: [], error: 'ROADMAP.md not found' };
1006
+ }
1007
+
1008
+ // Parse ROADMAP.md to get phase list
1009
+ const { parseRoadmapMd } = require('./roadmap');
1010
+ const roadmapContent = fs.readFileSync(roadmapPath, 'utf8');
1011
+ const roadmap = parseRoadmapMd(roadmapContent);
1012
+
1013
+ // Get actual phase directories on disk
1014
+ const dirsOnDisk = new Set();
1015
+ if (fs.existsSync(phasesDir)) {
1016
+ for (const entry of fs.readdirSync(phasesDir, { withFileTypes: true })) {
1017
+ if (entry.isDirectory() && /^\d{2}-/.test(entry.name)) {
1018
+ const numMatch = entry.name.match(/^(\d+)/);
1019
+ if (numMatch) dirsOnDisk.add(parseInt(numMatch[1], 10));
1020
+ }
1021
+ }
1022
+ }
1023
+
1024
+ // Filter roadmap phases to active milestone (non-complete/shipped phases,
1025
+ // or all phases if no milestone distinction is available)
1026
+ const completeStatuses = new Set(['complete', 'completed', 'verified', 'shipped']);
1027
+ const activePhases = [];
1028
+
1029
+ for (const phase of roadmap.phases) {
1030
+ const numMatch = String(phase.number).match(/^(\d+)/);
1031
+ if (!numMatch) continue;
1032
+ const phaseNum = parseInt(numMatch[1], 10);
1033
+ const status = (phase.status || '').toLowerCase().trim();
1034
+
1035
+ activePhases.push({ num: phaseNum, status });
1036
+ }
1037
+
1038
+ // Derive correct phases_total: count of phases with directories on disk
1039
+ // (active milestone phases that actually exist)
1040
+ // Fallback: if roadmap parser found no phases (e.g., heading-only format
1041
+ // not yet in table), use raw disk directory count to avoid writing 0
1042
+ let phasesTotal = activePhases.filter(p => dirsOnDisk.has(p.num)).length;
1043
+ if (phasesTotal === 0 && dirsOnDisk.size > 0) {
1044
+ phasesTotal = dirsOnDisk.size;
1045
+ }
1046
+
1047
+ // Derive correct current_phase: lowest phase that is NOT complete/verified/shipped
1048
+ const nonCompletePhasesOnDisk = activePhases
1049
+ .filter(p => dirsOnDisk.has(p.num) && !completeStatuses.has(p.status))
1050
+ .sort((a, b) => a.num - b.num);
1051
+ const currentPhase = nonCompletePhasesOnDisk.length > 0 ? nonCompletePhasesOnDisk[0].num : null;
1052
+
1053
+ // Detect phantom phases: roadmap rows with no corresponding directory
1054
+ for (const phase of activePhases) {
1055
+ if (!dirsOnDisk.has(phase.num)) {
1056
+ const label = `Phase ${String(phase.num).padStart(2, '0')} (status: ${phase.status || 'unknown'})`;
1057
+ phantoms.push(label);
1058
+ }
1059
+ }
1060
+
1061
+ // Read current STATE.md and compute corrections
1062
+ const stateContent = fs.readFileSync(statePath, 'utf8');
1063
+ const parsed = parseStateMd(stateContent);
1064
+
1065
+ const fieldsToUpdate = {};
1066
+ if (phasesTotal !== Number(parsed.plans_total || 0)) {
1067
+ fieldsToUpdate.plans_total = phasesTotal;
1068
+ changes.push(`plans_total: ${parsed.plans_total || 0} -> ${phasesTotal}`);
1069
+ }
1070
+
1071
+ // When no active phases remain (e.g., after milestone complete archives all phases),
1072
+ // reset STATE.md to idle state so downstream consumers don't read stale data.
1073
+ // Read raw frontmatter for accurate field checks since parseStateMd remaps some fields.
1074
+ const rawFm = parseYamlFrontmatter(stateContent);
1075
+
1076
+ if (currentPhase === null && phasesTotal === 0) {
1077
+ const currentPhaseVal = parsed.current_phase;
1078
+ if (currentPhaseVal !== null && currentPhaseVal !== undefined && String(currentPhaseVal) !== 'null') {
1079
+ fieldsToUpdate.current_phase = 'null';
1080
+ changes.push(`current_phase: ${currentPhaseVal} -> null`);
1081
+ }
1082
+ if (rawFm.phase_slug && String(rawFm.phase_slug) !== 'null') {
1083
+ fieldsToUpdate.phase_slug = 'null';
1084
+ changes.push(`phase_slug: ${rawFm.phase_slug} -> null`);
1085
+ }
1086
+ if (rawFm.phase_name && String(rawFm.phase_name) !== 'null') {
1087
+ fieldsToUpdate.phase_name = 'null';
1088
+ changes.push(`phase_name: ${rawFm.phase_name} -> null`);
1089
+ }
1090
+ const currentStatus = (parsed.status || '').toLowerCase();
1091
+ if (currentStatus && currentStatus !== 'idle') {
1092
+ fieldsToUpdate.status = 'idle';
1093
+ changes.push(`status: ${parsed.status} -> idle`);
1094
+ }
1095
+ if (Number(rawFm.progress_percent || 0) !== 0) {
1096
+ fieldsToUpdate.progress_percent = 0;
1097
+ changes.push(`progress_percent: ${rawFm.progress_percent || 0} -> 0`);
1098
+ }
1099
+ if (Number(parsed.plans_complete || 0) !== 0) {
1100
+ fieldsToUpdate.plans_complete = 0;
1101
+ changes.push(`plans_complete: ${parsed.plans_complete || 0} -> 0`);
1102
+ }
1103
+ if (Number(rawFm.phases_total || 0) !== 0) {
1104
+ fieldsToUpdate.phases_total = 0;
1105
+ changes.push(`phases_total: ${rawFm.phases_total || 0} -> 0`);
1106
+ }
1107
+ } else if (currentPhase !== null && currentPhase !== Number(parsed.current_phase || 0)) {
1108
+ fieldsToUpdate.current_phase = currentPhase;
1109
+ changes.push(`current_phase: ${parsed.current_phase || 0} -> ${currentPhase}`);
1110
+ }
1111
+
1112
+ // Apply corrections atomically
1113
+ if (Object.keys(fieldsToUpdate).length > 0) {
1114
+ lockedFileUpdate(statePath, (content) => {
1115
+ let updated = content;
1116
+ for (const [field, value] of Object.entries(fieldsToUpdate)) {
1117
+ updated = updateFrontmatterField(updated, field, value);
1118
+ updated = syncBodyLine(updated, field, value);
1119
+ }
1120
+ return updated;
1121
+ });
1122
+ }
1123
+
1124
+ return { corrected: changes.length > 0, changes, phantoms };
1125
+ }
1126
+
1127
+ /**
1128
+ * Create a timestamped backup of STATE.md and ROADMAP.md.
1129
+ * Writes a JSON file to .planning/.state-backup-{timestamp}.json
1130
+ * containing the raw content of both files plus metadata.
1131
+ * @param {string} [planningDir] - Path to .planning directory
1132
+ * @returns {{ backed_up: boolean, path: string|null, files: string[] }}
1133
+ */
1134
+ function stateBackup(planningDir) {
1135
+ const dir = planningDir || path.join(process.env.PBR_PROJECT_ROOT || process.cwd(), '.planning');
1136
+ const statePath = path.join(dir, 'STATE.md');
1137
+ const roadmapPath = path.join(dir, 'ROADMAP.md');
1138
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
1139
+ const backupPath = path.join(dir, `.state-backup-${timestamp}.json`);
1140
+
1141
+ const backup = { timestamp: new Date().toISOString(), files: {} };
1142
+ let fileCount = 0;
1143
+
1144
+ for (const [name, filePath] of [['STATE.md', statePath], ['ROADMAP.md', roadmapPath]]) {
1145
+ if (fs.existsSync(filePath)) {
1146
+ backup.files[name] = fs.readFileSync(filePath, 'utf8');
1147
+ fileCount++;
1148
+ }
1149
+ }
1150
+
1151
+ if (fileCount === 0) {
1152
+ return { backed_up: false, path: null, files: [] };
1153
+ }
1154
+
1155
+ fs.writeFileSync(backupPath, JSON.stringify(backup, null, 2));
1156
+ return { backed_up: true, path: backupPath, files: Object.keys(backup.files) };
1157
+ }
1158
+
1159
+ module.exports = {
1160
+ parseStateMd,
1161
+ updateLegacyStateField,
1162
+ updateFrontmatterField,
1163
+ syncBodyLine,
1164
+ buildProgressBar,
1165
+ stateLoad,
1166
+ stateCheckProgress,
1167
+ stateUpdate,
1168
+ statePatch,
1169
+ stateAdvancePlan,
1170
+ stateRecordMetric,
1171
+ stateRecordActivity,
1172
+ stateUpdateProgress,
1173
+ stateGetStatus,
1174
+ stateSnapshot,
1175
+ statePhaseComplete,
1176
+ stateRederive,
1177
+ stateRecordVelocity,
1178
+ stateRecordSession,
1179
+ stateSignalWaiting,
1180
+ stateSignalResume,
1181
+ stateCheckWaiting,
1182
+ stateReconcile,
1183
+ stateBackup,
1184
+ syncStateFrontmatter,
1185
+ normalizeStatus,
1186
+ STATUS_VALUES
1187
+ };