@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,1569 @@
1
+ /**
2
+ * lib/core.cjs — Foundation utilities for Plan-Build-Run tools.
3
+ *
4
+ * Pure utility functions with no dependencies on other lib modules.
5
+ * Provides: output/error formatting, YAML frontmatter parsing, status transitions,
6
+ * file operations (atomicWrite, lockedFileUpdate, findFiles, tailLines),
7
+ * session management, phase claiming, path utilities, and shared constants.
8
+ *
9
+ * Hybrid module merging PBR reference features with GSD-unique utilities.
10
+ */
11
+
12
+ const fs = require('fs');
13
+ const os = require('os');
14
+ const path = require('path');
15
+ const { execSync } = require('child_process');
16
+
17
+ // ─── Module-level planningDir with MSYS path bridging ─────────────────────────
18
+
19
+ let cwd = process.env.PBR_PROJECT_ROOT || process.cwd();
20
+
21
+ // MSYS path bridging: convert /c/Users/... to C:\Users\... on Windows
22
+ const msysMatch = cwd.match(/^\/([a-zA-Z])\/(.*)/);
23
+ if (msysMatch) cwd = msysMatch[1] + ':' + path.sep + msysMatch[2];
24
+
25
+ let planningDir = path.join(cwd, '.planning');
26
+
27
+ /**
28
+ * Override the working directory for subagent use.
29
+ * Updates both cwd and planningDir.
30
+ *
31
+ * @param {string} newCwd - New working directory path
32
+ */
33
+ function setCwd(newCwd) {
34
+ cwd = newCwd;
35
+ // Apply MSYS bridging to the new cwd as well
36
+ const m = cwd.match(/^\/([a-zA-Z])\/(.*)/);
37
+ if (m) cwd = m[1] + ':' + path.sep + m[2];
38
+ planningDir = path.join(cwd, '.planning');
39
+ }
40
+
41
+ // ─── Canonical agent list ─────────────────────────────────────────────────────
42
+
43
+ /**
44
+ * Canonical list of known PBR agent types.
45
+ * Used by validate-task and check-subagent-output to avoid drift.
46
+ */
47
+ const KNOWN_AGENTS = [
48
+ 'executor',
49
+ 'planner',
50
+ 'verifier',
51
+ 'researcher',
52
+ 'synthesizer',
53
+ 'plan-checker',
54
+ 'integration-checker',
55
+ 'debugger',
56
+ 'codebase-mapper',
57
+ 'audit',
58
+ 'general',
59
+ 'dev-sync',
60
+ 'roadmapper',
61
+ 'nyquist-auditor',
62
+ 'intel-updater',
63
+ 'ui-checker',
64
+ 'ui-researcher'
65
+ ];
66
+
67
+ // ─── Phase status transition state machine ────────────────────────────────────
68
+
69
+ /**
70
+ * Valid phase status transitions. Each key is a current status, and its value
71
+ * is an array of statuses that are legal to transition to. This is advisory —
72
+ * invalid transitions produce a stderr warning but are not blocked.
73
+ *
74
+ * State machine:
75
+ * pending -> planned, skipped
76
+ * planned -> building
77
+ * building -> built, partial, needs_fixes
78
+ * built -> verified, needs_fixes
79
+ * partial -> building, needs_fixes
80
+ * verified -> building (re-execution)
81
+ * needs_fixes -> planned, building
82
+ * skipped -> pending (unskip)
83
+ */
84
+ const VALID_STATUS_TRANSITIONS = {
85
+ not_started: ['discussed', 'ready_to_plan', 'planned', 'skipped'],
86
+ discussed: ['ready_to_plan', 'planning'],
87
+ ready_to_plan: ['planning', 'planned'],
88
+ planning: ['planned'],
89
+ planned: ['ready_to_execute', 'building'],
90
+ ready_to_execute: ['building'],
91
+ building: ['built', 'partial', 'needs_fixes'],
92
+ built: ['verified', 'needs_fixes'],
93
+ partial: ['building', 'needs_fixes'],
94
+ verified: ['complete', 'building'],
95
+ needs_fixes: ['planned', 'building', 'ready_to_plan'],
96
+ complete: [],
97
+ skipped: ['not_started', 'pending'],
98
+ // Legacy aliases (backward compat)
99
+ pending: ['planned', 'discussed', 'skipped', 'not_started']
100
+ };
101
+
102
+ /**
103
+ * Human-readable labels for plan/phase statuses.
104
+ */
105
+ const STATUS_LABELS = {
106
+ not_started: 'Not Started',
107
+ discussed: 'Discussed',
108
+ ready_to_plan: 'Ready to Plan',
109
+ planning: 'Planning',
110
+ planned: 'Planned',
111
+ ready_to_execute: 'Ready to Execute',
112
+ building: 'Building',
113
+ built: 'Built',
114
+ partial: 'Partial',
115
+ verified: 'Verified',
116
+ needs_fixes: 'Needs Fixes',
117
+ complete: 'Complete',
118
+ skipped: 'Skipped',
119
+ // Legacy aliases
120
+ pending: 'Not Started',
121
+ reviewed: 'Verified'
122
+ };
123
+
124
+ /**
125
+ * Check whether a phase status transition is valid according to the state machine.
126
+ * Returns { valid, warning? } — never blocks, only advises.
127
+ *
128
+ * @param {string} oldStatus - Current phase status
129
+ * @param {string} newStatus - Desired phase status
130
+ * @returns {{ valid: boolean, warning?: string }}
131
+ */
132
+ function validateStatusTransition(oldStatus, newStatus) {
133
+ const from = (oldStatus || '').trim().toLowerCase();
134
+ const to = (newStatus || '').trim().toLowerCase();
135
+
136
+ if (from === to) return { valid: true };
137
+
138
+ if (!VALID_STATUS_TRANSITIONS[from]) return { valid: true };
139
+
140
+ const allowed = VALID_STATUS_TRANSITIONS[from];
141
+ if (allowed.includes(to)) return { valid: true };
142
+
143
+ return {
144
+ valid: false,
145
+ warning: `Suspicious status transition: "${from}" -> "${to}". Expected one of: [${allowed.join(', ')}]. Proceeding anyway (advisory).`
146
+ };
147
+ }
148
+
149
+ // ─── Model Profile Table ─────────────────────────────────────────────────────
150
+
151
+ const MODEL_PROFILES = {
152
+ 'pbr-planner': { quality: 'opus', balanced: 'opus', budget: 'sonnet' },
153
+ 'pbr-roadmapper': { quality: 'opus', balanced: 'sonnet', budget: 'sonnet' },
154
+ 'pbr-executor': { quality: 'opus', balanced: 'sonnet', budget: 'sonnet' },
155
+ 'pbr-researcher': { quality: 'opus', balanced: 'sonnet', budget: 'haiku' },
156
+ 'pbr-synthesizer': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
157
+ 'pbr-debugger': { quality: 'opus', balanced: 'sonnet', budget: 'sonnet' },
158
+ 'pbr-codebase-mapper': { quality: 'sonnet', balanced: 'haiku', budget: 'haiku' },
159
+ 'pbr-verifier': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
160
+ 'pbr-plan-checker': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
161
+ 'pbr-integration-checker': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
162
+ 'pbr-nyquist-auditor': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
163
+ };
164
+
165
+ // ─── Path helpers ─────────────────────────────────────────────────────────────
166
+
167
+ /** Normalize a path to always use forward slashes (cross-platform). */
168
+ function toPosixPath(p) {
169
+ return p.split(path.sep).join('/');
170
+ }
171
+
172
+ // ─── Output helpers ───────────────────────────────────────────────────────────
173
+
174
+ function output(data, raw, rawValue) {
175
+ if (raw && rawValue !== undefined) {
176
+ process.stdout.write(String(rawValue));
177
+ } else {
178
+ const json = JSON.stringify(data, null, 2);
179
+ if (json.length > 8192) {
180
+ const tmpPath = path.join(os.tmpdir(), `pbr-${Date.now()}.json`);
181
+ fs.writeFileSync(tmpPath, json, 'utf8');
182
+ process.stdout.write('@file:' + tmpPath + '\n');
183
+ } else {
184
+ process.stdout.write(json + '\n');
185
+ }
186
+ }
187
+ process.exit(0);
188
+ }
189
+
190
+ function error(msg) {
191
+ process.stderr.write('Error: ' + msg + '\n');
192
+ process.exit(1);
193
+ }
194
+
195
+ // ─── File & path utilities ────────────────────────────────────────────────────
196
+
197
+ /**
198
+ * Read a file safely, returning null on any error.
199
+ *
200
+ * @param {string} filePath - Absolute path to the file
201
+ * @returns {string|null} File contents or null
202
+ */
203
+ function safeReadFile(filePath) {
204
+ try {
205
+ return fs.readFileSync(filePath, 'utf8');
206
+ } catch {
207
+ return null;
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Ensure a directory exists, creating it recursively if needed.
213
+ *
214
+ * @param {string} dirPath - Directory path to ensure
215
+ */
216
+ function ensureDir(dirPath) {
217
+ fs.mkdirSync(dirPath, { recursive: true });
218
+ }
219
+
220
+ /**
221
+ * Find files in a directory matching a regex pattern.
222
+ *
223
+ * @param {string} dir - Directory to search
224
+ * @param {RegExp} pattern - Pattern to match filenames against
225
+ * @returns {string[]} Sorted array of matching filenames
226
+ */
227
+ function findFiles(dir, pattern) {
228
+ try {
229
+ return fs.readdirSync(dir).filter(f => pattern.test(f)).sort();
230
+ } catch (_) {
231
+ return [];
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Read the last N lines from a file.
237
+ *
238
+ * @param {string} filePath - Absolute path to the file
239
+ * @param {number} n - Number of trailing lines to return
240
+ * @returns {string[]} Array of line strings
241
+ */
242
+ function tailLines(filePath, n) {
243
+ try {
244
+ if (!fs.existsSync(filePath)) return [];
245
+ const content = fs.readFileSync(filePath, 'utf8').trim();
246
+ if (!content) return [];
247
+ const lines = content.replace(/\r\n/g, '\n').split('\n');
248
+ if (lines.length <= n) return lines;
249
+ return lines.slice(lines.length - n);
250
+ } catch (_e) {
251
+ return [];
252
+ }
253
+ }
254
+
255
+ // ─── Git utilities ────────────────────────────────────────────────────────────
256
+
257
+ /**
258
+ * Execute a git command and return the result.
259
+ *
260
+ * @param {string} gitCwd - Working directory for git
261
+ * @param {string[]} args - Git command arguments
262
+ * @returns {{ exitCode: number, stdout: string, stderr: string }}
263
+ */
264
+ function execGit(gitCwd, args) {
265
+ try {
266
+ const escaped = args.map(a => {
267
+ if (/^[a-zA-Z0-9._\-/=:@]+$/.test(a)) return a;
268
+ return "'" + a.replace(/'/g, "'\\''") + "'";
269
+ });
270
+ const stdout = execSync('git ' + escaped.join(' '), {
271
+ cwd: gitCwd,
272
+ stdio: 'pipe',
273
+ encoding: 'utf-8',
274
+ });
275
+ return { exitCode: 0, stdout: stdout.trim(), stderr: '' };
276
+ } catch (err) {
277
+ return {
278
+ exitCode: err.status ?? 1,
279
+ stdout: (err.stdout ?? '').toString().trim(),
280
+ stderr: (err.stderr ?? '').toString().trim(),
281
+ };
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Check if a path is git-ignored.
287
+ *
288
+ * @param {string} gitCwd - Working directory
289
+ * @param {string} targetPath - Path to check
290
+ * @returns {boolean}
291
+ */
292
+ function isGitIgnored(gitCwd, targetPath) {
293
+ try {
294
+ execSync('git check-ignore -q --no-index -- ' + targetPath.replace(/[^a-zA-Z0-9._\-/]/g, ''), {
295
+ cwd: gitCwd,
296
+ stdio: 'pipe',
297
+ });
298
+ return true;
299
+ } catch {
300
+ return false;
301
+ }
302
+ }
303
+
304
+ // ─── YAML frontmatter parsing ─────────────────────────────────────────────────
305
+
306
+ /**
307
+ * Parse YAML frontmatter from markdown content.
308
+ * Handles flat key-value pairs, inline arrays, and multi-line arrays.
309
+ *
310
+ * @param {string} content - Markdown content with optional frontmatter
311
+ * @returns {object} Parsed frontmatter as a plain object
312
+ */
313
+ function parseYamlFrontmatter(content) {
314
+ const normalized = content.replace(/\r\n/g, '\n');
315
+ const match = normalized.match(/^---\s*\n([\s\S]*?)\n---/);
316
+ if (!match) return {};
317
+
318
+ const yaml = match[1];
319
+ const result = {};
320
+
321
+ const lines = yaml.split('\n');
322
+ let currentKey = null;
323
+
324
+ for (const line of lines) {
325
+ // Array item
326
+ if (/^\s+-\s+/.test(line) && currentKey) {
327
+ const val = line.replace(/^\s+-\s+/, '').trim().replace(/^["']|["']$/g, '');
328
+ if (!result[currentKey]) result[currentKey] = [];
329
+ if (Array.isArray(result[currentKey])) {
330
+ result[currentKey].push(val);
331
+ }
332
+ continue;
333
+ }
334
+
335
+ // Key-value pair
336
+ const kvMatch = line.match(/^(\w[\w_]*)\s*:\s*(.*)/);
337
+ if (kvMatch) {
338
+ currentKey = kvMatch[1];
339
+ let val = kvMatch[2].trim();
340
+
341
+ if (val === '' || val === '|') continue;
342
+
343
+ // Handle arrays on same line: [a, b, c]
344
+ if (val.startsWith('[') && val.endsWith(']')) {
345
+ result[currentKey] = val.slice(1, -1).split(',')
346
+ .map(v => v.trim().replace(/^["']|["']$/g, ''))
347
+ .filter(Boolean);
348
+ continue;
349
+ }
350
+
351
+ // Clean quotes
352
+ val = val.replace(/^["']|["']$/g, '');
353
+
354
+ // Type coercion
355
+ if (val === 'true') val = true;
356
+ else if (val === 'false') val = false;
357
+ else if (/^\d+$/.test(val)) val = parseInt(val, 10);
358
+
359
+ result[currentKey] = val;
360
+ }
361
+ }
362
+
363
+ // Handle must_haves as a nested object
364
+ if (yaml.includes('must_haves:')) {
365
+ result.must_haves = parseMustHaves(yaml);
366
+ }
367
+
368
+ return result;
369
+ }
370
+
371
+ /**
372
+ * Parse the must_haves section from YAML frontmatter.
373
+ *
374
+ * @param {string} yaml - Raw YAML content (without --- delimiters)
375
+ * @returns {{ truths: string[], artifacts: string[], key_links: string[] }}
376
+ */
377
+ function parseMustHaves(yaml) {
378
+ const result = { truths: [], artifacts: [], key_links: [] };
379
+ let section = null;
380
+
381
+ const inMustHaves = yaml.replace(/\r\n/g, '\n').split('\n');
382
+ let collecting = false;
383
+
384
+ for (const line of inMustHaves) {
385
+ if (/^\s*must_haves:/.test(line)) {
386
+ collecting = true;
387
+ continue;
388
+ }
389
+ if (collecting) {
390
+ if (/^\s{2}truths:/.test(line)) { section = 'truths'; continue; }
391
+ if (/^\s{2}artifacts:/.test(line)) { section = 'artifacts'; continue; }
392
+ if (/^\s{2}key_links:/.test(line)) { section = 'key_links'; continue; }
393
+ if (/^\w/.test(line)) break;
394
+
395
+ if (section && /^\s+-\s+/.test(line)) {
396
+ result[section].push(line.replace(/^\s+-\s+/, '').trim().replace(/^["']|["']$/g, ''));
397
+ }
398
+ }
399
+ }
400
+
401
+ return result;
402
+ }
403
+
404
+ /**
405
+ * Set/update YAML frontmatter fields in markdown content.
406
+ * Creates frontmatter block if none exists.
407
+ *
408
+ * @param {string} content - Markdown content
409
+ * @param {object} updates - Key-value pairs to set in frontmatter
410
+ * @returns {string} Updated content
411
+ */
412
+ function setYamlFrontmatter(content, updates) {
413
+ const normalized = content.replace(/\r\n/g, '\n');
414
+ const match = normalized.match(/^---\s*\n([\s\S]*?)\n---/);
415
+
416
+ if (!match) {
417
+ // No existing frontmatter — create one
418
+ const lines = Object.entries(updates).map(([k, v]) => {
419
+ if (Array.isArray(v)) {
420
+ return `${k}:\n${v.map(item => ` - ${item}`).join('\n')}`;
421
+ }
422
+ if (typeof v === 'string' && (v.includes(':') || v.includes('#'))) {
423
+ return `${k}: "${v}"`;
424
+ }
425
+ return `${k}: ${v}`;
426
+ });
427
+ return `---\n${lines.join('\n')}\n---\n${normalized}`;
428
+ }
429
+
430
+ let yaml = match[1];
431
+
432
+ for (const [key, value] of Object.entries(updates)) {
433
+ const keyRegex = new RegExp(`^(${key})\\s*:.*$`, 'm');
434
+ const formatted = typeof value === 'string' && (value.includes(':') || value.includes('#'))
435
+ ? `"${value}"`
436
+ : String(value);
437
+
438
+ if (keyRegex.test(yaml)) {
439
+ yaml = yaml.replace(keyRegex, `${key}: ${formatted}`);
440
+ } else {
441
+ yaml += `\n${key}: ${formatted}`;
442
+ }
443
+ }
444
+
445
+ return normalized.replace(/^---\s*\n[\s\S]*?\n---/, `---\n${yaml}\n---`);
446
+ }
447
+
448
+ // ─── Misc utilities ───────────────────────────────────────────────────────────
449
+
450
+ function countMustHaves(mustHaves) {
451
+ if (!mustHaves) return 0;
452
+ return (mustHaves.truths || []).length +
453
+ (mustHaves.artifacts || []).length +
454
+ (mustHaves.key_links || []).length;
455
+ }
456
+
457
+ function determinePhaseStatus(planCount, completedCount, summaryCount, hasVerification, phaseDir) {
458
+ if (planCount === 0) {
459
+ if (fs.existsSync(path.join(phaseDir, 'CONTEXT.md'))) return 'discussed';
460
+ return 'not_started';
461
+ }
462
+ if (completedCount === 0 && summaryCount === 0) return 'planned';
463
+ if (completedCount < planCount) return 'building';
464
+ if (!hasVerification) return 'built';
465
+ try {
466
+ const vContent = fs.readFileSync(path.join(phaseDir, 'VERIFICATION.md'), 'utf8');
467
+ if (/status:\s*["']?passed/i.test(vContent)) return 'verified';
468
+ if (/status:\s*["']?gaps_found/i.test(vContent)) return 'needs_fixes';
469
+ return 'reviewed';
470
+ } catch (_) {
471
+ return 'built';
472
+ }
473
+ }
474
+
475
+ function calculateProgress(pDir) {
476
+ const phasesDir = path.join(pDir, 'phases');
477
+ if (!fs.existsSync(phasesDir)) {
478
+ return { total: 0, completed: 0, percentage: 0 };
479
+ }
480
+
481
+ let total = 0;
482
+ let completed = 0;
483
+
484
+ const entries = fs.readdirSync(phasesDir, { withFileTypes: true })
485
+ .filter(e => e.isDirectory());
486
+
487
+ for (const entry of entries) {
488
+ const dir = path.join(phasesDir, entry.name);
489
+ const plans = findFiles(dir, /PLAN.*\.md$/i);
490
+ total += plans.length;
491
+
492
+ const summaries = findFiles(dir, /^SUMMARY-.*\.md$/);
493
+ for (const s of summaries) {
494
+ const content = fs.readFileSync(path.join(dir, s), 'utf8');
495
+ if (/status:\s*["']?complete/i.test(content)) completed++;
496
+ }
497
+ }
498
+
499
+ return {
500
+ total,
501
+ completed,
502
+ percentage: total > 0 ? Math.round((completed / total) * 100) : 0
503
+ };
504
+ }
505
+
506
+ /**
507
+ * Return an ISO 8601 UTC timestamp string.
508
+ *
509
+ * @returns {string} ISO timestamp
510
+ */
511
+ function currentTimestamp() {
512
+ return new Date().toISOString();
513
+ }
514
+
515
+ /**
516
+ * Generate a URL-safe slug from a string.
517
+ *
518
+ * @param {string} text - Input text
519
+ * @returns {string|null} Slugified string or null
520
+ */
521
+ function generateSlug(text) {
522
+ if (!text) return null;
523
+ return text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
524
+ }
525
+
526
+ /**
527
+ * Resolve the model name for an agent type based on config.
528
+ *
529
+ * @param {string} agentType - Agent type key (e.g., 'pbr-executor')
530
+ * @param {object} config - Config object with model_profile and optional model_overrides
531
+ * @returns {string} Resolved model name
532
+ */
533
+ function resolveModel(agentType, config) {
534
+ // Check per-agent override first
535
+ const override = config && config.model_overrides && config.model_overrides[agentType];
536
+ if (override) {
537
+ return override === 'opus' ? 'inherit' : override;
538
+ }
539
+
540
+ // Fall back to profile lookup
541
+ const profile = (config && config.model_profile) || 'balanced';
542
+ const agentModels = MODEL_PROFILES[agentType];
543
+ if (!agentModels) return 'sonnet';
544
+ const resolved = agentModels[profile] || agentModels['balanced'] || 'sonnet';
545
+ return resolved === 'opus' ? 'inherit' : resolved;
546
+ }
547
+
548
+ // ─── Regex and phase utilities ────────────────────────────────────────────────
549
+
550
+ function escapeRegex(value) {
551
+ return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
552
+ }
553
+
554
+ function normalizePhaseName(phase) {
555
+ const match = String(phase).match(/^(\d+)([A-Z])?((?:\.\d+)*)/i);
556
+ if (!match) return phase;
557
+ const padded = match[1].padStart(2, '0');
558
+ const letter = match[2] ? match[2].toUpperCase() : '';
559
+ const decimal = match[3] || '';
560
+ return padded + letter + decimal;
561
+ }
562
+
563
+ function comparePhaseNum(a, b) {
564
+ const pa = String(a).match(/^(\d+)([A-Z])?((?:\.\d+)*)/i);
565
+ const pb = String(b).match(/^(\d+)([A-Z])?((?:\.\d+)*)/i);
566
+ if (!pa || !pb) return String(a).localeCompare(String(b));
567
+ const intDiff = parseInt(pa[1], 10) - parseInt(pb[1], 10);
568
+ if (intDiff !== 0) return intDiff;
569
+ const la = (pa[2] || '').toUpperCase();
570
+ const lb = (pb[2] || '').toUpperCase();
571
+ if (la !== lb) {
572
+ if (!la) return -1;
573
+ if (!lb) return 1;
574
+ return la < lb ? -1 : 1;
575
+ }
576
+ const aDecParts = pa[3] ? pa[3].slice(1).split('.').map(p => parseInt(p, 10)) : [];
577
+ const bDecParts = pb[3] ? pb[3].slice(1).split('.').map(p => parseInt(p, 10)) : [];
578
+ const maxLen = Math.max(aDecParts.length, bDecParts.length);
579
+ if (aDecParts.length === 0 && bDecParts.length > 0) return -1;
580
+ if (bDecParts.length === 0 && aDecParts.length > 0) return 1;
581
+ for (let i = 0; i < maxLen; i++) {
582
+ const av = Number.isFinite(aDecParts[i]) ? aDecParts[i] : 0;
583
+ const bv = Number.isFinite(bDecParts[i]) ? bDecParts[i] : 0;
584
+ if (av !== bv) return av - bv;
585
+ }
586
+ return 0;
587
+ }
588
+
589
+ function searchPhaseInDir(baseDir, relBase, normalized) {
590
+ try {
591
+ const entries = fs.readdirSync(baseDir, { withFileTypes: true });
592
+ const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).sort((a, b) => comparePhaseNum(a, b));
593
+ const match = dirs.find(d => d.startsWith(normalized));
594
+ if (!match) return null;
595
+
596
+ const dirMatch = match.match(/^(\d+[A-Z]?(?:\.\d+)*)-?(.*)/i);
597
+ const phaseNumber = dirMatch ? dirMatch[1] : normalized;
598
+ const phaseName = dirMatch && dirMatch[2] ? dirMatch[2] : null;
599
+ const phaseDir = path.join(baseDir, match);
600
+ const phaseFiles = fs.readdirSync(phaseDir);
601
+
602
+ const plans = phaseFiles.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md').sort();
603
+ const summaries = phaseFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md').sort();
604
+ const hasResearch = phaseFiles.some(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
605
+ const hasContext = phaseFiles.some(f => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md');
606
+ const hasVerification = phaseFiles.some(f => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md');
607
+
608
+ const completedPlanIds = new Set(
609
+ summaries.map(s => s.replace('-SUMMARY.md', '').replace('SUMMARY.md', ''))
610
+ );
611
+ const incompletePlans = plans.filter(p => {
612
+ const planId = p.replace('-PLAN.md', '').replace('PLAN.md', '');
613
+ return !completedPlanIds.has(planId);
614
+ });
615
+
616
+ return {
617
+ found: true,
618
+ directory: toPosixPath(path.join(relBase, match)),
619
+ phase_number: phaseNumber,
620
+ phase_name: phaseName,
621
+ phase_slug: phaseName ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') : null,
622
+ plans,
623
+ summaries,
624
+ incomplete_plans: incompletePlans,
625
+ has_research: hasResearch,
626
+ has_context: hasContext,
627
+ has_verification: hasVerification,
628
+ };
629
+ } catch {
630
+ return null;
631
+ }
632
+ }
633
+
634
+ function findPhaseInternal(phaseCwd, phase) {
635
+ if (!phase) return null;
636
+
637
+ const phasesDir = path.join(phaseCwd, '.planning', 'phases');
638
+ const normalized = normalizePhaseName(phase);
639
+
640
+ const current = searchPhaseInDir(phasesDir, '.planning/phases', normalized);
641
+ if (current) return current;
642
+
643
+ const milestonesDir = path.join(phaseCwd, '.planning', 'milestones');
644
+ if (!fs.existsSync(milestonesDir)) return null;
645
+
646
+ try {
647
+ const milestoneEntries = fs.readdirSync(milestonesDir, { withFileTypes: true });
648
+ const archiveDirs = milestoneEntries
649
+ .filter(e => e.isDirectory() && /^v[\d.]+-phases$/.test(e.name))
650
+ .map(e => e.name)
651
+ .sort()
652
+ .reverse();
653
+
654
+ for (const archiveName of archiveDirs) {
655
+ const version = archiveName.match(/^(v[\d.]+)-phases$/)[1];
656
+ const archivePath = path.join(milestonesDir, archiveName);
657
+ const relBase = '.planning/milestones/' + archiveName;
658
+ const result = searchPhaseInDir(archivePath, relBase, normalized);
659
+ if (result) {
660
+ result.archived = version;
661
+ return result;
662
+ }
663
+ }
664
+ } catch { /* best effort */ }
665
+
666
+ return null;
667
+ }
668
+
669
+ function getArchivedPhaseDirs(archCwd) {
670
+ const milestonesDir = path.join(archCwd, '.planning', 'milestones');
671
+ const results = [];
672
+
673
+ if (!fs.existsSync(milestonesDir)) return results;
674
+
675
+ try {
676
+ const milestoneEntries = fs.readdirSync(milestonesDir, { withFileTypes: true });
677
+ const phaseDirs = milestoneEntries
678
+ .filter(e => e.isDirectory() && /^v[\d.]+-phases$/.test(e.name))
679
+ .map(e => e.name)
680
+ .sort()
681
+ .reverse();
682
+
683
+ for (const archiveName of phaseDirs) {
684
+ const version = archiveName.match(/^(v[\d.]+)-phases$/)[1];
685
+ const archivePath = path.join(milestonesDir, archiveName);
686
+ const entries = fs.readdirSync(archivePath, { withFileTypes: true });
687
+ const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).sort((a, b) => comparePhaseNum(a, b));
688
+
689
+ for (const dir of dirs) {
690
+ results.push({
691
+ name: dir,
692
+ milestone: version,
693
+ basePath: path.join('.planning', 'milestones', archiveName),
694
+ fullPath: path.join(archivePath, dir),
695
+ });
696
+ }
697
+ }
698
+ } catch { /* best effort */ }
699
+
700
+ return results;
701
+ }
702
+
703
+ // ─── Roadmap & milestone utilities ────────────────────────────────────────────
704
+
705
+ function getRoadmapPhaseInternal(rmCwd, phaseNum) {
706
+ if (!phaseNum) return null;
707
+ const roadmapPath = path.join(rmCwd, '.planning', 'ROADMAP.md');
708
+ if (!fs.existsSync(roadmapPath)) return null;
709
+
710
+ try {
711
+ const content = fs.readFileSync(roadmapPath, 'utf8');
712
+ const escapedPhase = escapeRegex(phaseNum.toString());
713
+ const phasePattern = new RegExp(`#{2,4}\\s*Phase\\s+${escapedPhase}:\\s*([^\\n]+)`, 'i');
714
+ const headerMatch = content.match(phasePattern);
715
+ if (!headerMatch) return null;
716
+
717
+ const phaseName = headerMatch[1].trim();
718
+ const headerIndex = headerMatch.index;
719
+ const restOfContent = content.slice(headerIndex);
720
+ const nextHeaderMatch = restOfContent.match(/\n#{2,4}\s+Phase\s+\d/i);
721
+ const sectionEnd = nextHeaderMatch ? headerIndex + nextHeaderMatch.index : content.length;
722
+ const section = content.slice(headerIndex, sectionEnd).trim();
723
+
724
+ const goalMatch = section.match(/\*\*Goal:\*\*\s*([^\n]+)/i);
725
+ const goal = goalMatch ? goalMatch[1].trim() : null;
726
+
727
+ return {
728
+ found: true,
729
+ phase_number: phaseNum.toString(),
730
+ phase_name: phaseName,
731
+ goal,
732
+ section,
733
+ };
734
+ } catch {
735
+ return null;
736
+ }
737
+ }
738
+
739
+ function getMilestoneInfo(miCwd) {
740
+ try {
741
+ const roadmap = fs.readFileSync(path.join(miCwd, '.planning', 'ROADMAP.md'), 'utf8');
742
+
743
+ const inProgressMatch = roadmap.match(/\u{1F6A7}\s*\*\*v(\d+\.\d+)\s+([^*]+)\*\*/u);
744
+ if (inProgressMatch) {
745
+ return {
746
+ version: 'v' + inProgressMatch[1],
747
+ name: inProgressMatch[2].trim(),
748
+ };
749
+ }
750
+
751
+ const cleaned = roadmap.replace(/<details>[\s\S]*?<\/details>/gi, '');
752
+ const headingMatch = cleaned.match(/## .*v(\d+\.\d+)[:\s]+([^\n(]+)/);
753
+ if (headingMatch) {
754
+ return {
755
+ version: 'v' + headingMatch[1],
756
+ name: headingMatch[2].trim(),
757
+ };
758
+ }
759
+ const versionMatch = cleaned.match(/v(\d+\.\d+)/);
760
+ return {
761
+ version: versionMatch ? versionMatch[0] : 'v1.0',
762
+ name: 'milestone',
763
+ };
764
+ } catch {
765
+ return { version: 'v1.0', name: 'milestone' };
766
+ }
767
+ }
768
+
769
+ /**
770
+ * Returns a filter function that checks whether a phase directory belongs
771
+ * to the current milestone based on ROADMAP.md phase headings.
772
+ */
773
+ function getMilestonePhaseFilter(filterCwd) {
774
+ const milestonePhaseNums = new Set();
775
+ try {
776
+ const roadmap = fs.readFileSync(path.join(filterCwd, '.planning', 'ROADMAP.md'), 'utf8');
777
+ const phasePattern = /#{2,4}\s*Phase\s+(\d+[A-Z]?(?:\.\d+)*)\s*:/gi;
778
+ let m;
779
+ while ((m = phasePattern.exec(roadmap)) !== null) {
780
+ milestonePhaseNums.add(m[1]);
781
+ }
782
+ } catch { /* best effort */ }
783
+
784
+ if (milestonePhaseNums.size === 0) {
785
+ const passAll = () => true;
786
+ passAll.phaseCount = 0;
787
+ return passAll;
788
+ }
789
+
790
+ const normalized = new Set(
791
+ [...milestonePhaseNums].map(n => (n.replace(/^0+/, '') || '0').toLowerCase())
792
+ );
793
+
794
+ function isDirInMilestone(dirName) {
795
+ const dm = dirName.match(/^0*(\d+[A-Za-z]?(?:\.\d+)*)/);
796
+ if (!dm) return false;
797
+ return normalized.has(dm[1].toLowerCase());
798
+ }
799
+ isDirInMilestone.phaseCount = milestonePhaseNums.size;
800
+ return isDirInMilestone;
801
+ }
802
+
803
+ // ─── Atomic file operations ───────────────────────────────────────────────────
804
+
805
+ /**
806
+ * Write content to a file atomically: write to .tmp, backup original to .bak,
807
+ * rename .tmp over original. On failure, restore from .bak if available.
808
+ *
809
+ * @param {string} filePath - Target file path
810
+ * @param {string} content - Content to write
811
+ * @returns {{success: boolean, error?: string}} Result
812
+ */
813
+ function atomicWrite(filePath, content) {
814
+ const tmpPath = filePath + '.tmp';
815
+ const bakPath = filePath + '.bak';
816
+
817
+ try {
818
+ fs.writeFileSync(tmpPath, content, 'utf8');
819
+
820
+ if (fs.existsSync(filePath)) {
821
+ try { fs.copyFileSync(filePath, bakPath); } catch (_e) { /* non-fatal */ }
822
+ }
823
+
824
+ fs.renameSync(tmpPath, filePath);
825
+
826
+ try {
827
+ if (fs.existsSync(bakPath)) fs.unlinkSync(bakPath);
828
+ } catch (_e) { /* non-fatal */ }
829
+
830
+ return { success: true };
831
+ } catch (e) {
832
+ try {
833
+ if (fs.existsSync(bakPath)) fs.copyFileSync(bakPath, filePath);
834
+ } catch (_restoreErr) { /* nothing more we can do */ }
835
+ try {
836
+ if (fs.existsSync(tmpPath)) fs.unlinkSync(tmpPath);
837
+ } catch (_cleanupErr) { /* best effort */ }
838
+
839
+ return { success: false, error: e.message };
840
+ }
841
+ }
842
+
843
+ /**
844
+ * Locked file update: read-modify-write with exclusive lockfile.
845
+ * Prevents concurrent writes to STATE.md and ROADMAP.md.
846
+ *
847
+ * @param {string} filePath - Absolute path to the file to update
848
+ * @param {function} updateFn - Receives current content, returns new content
849
+ * @param {object} opts - Options: { retries: 3, retryDelayMs: 100, timeoutMs: 5000 }
850
+ * @returns {object} { success, content?, error? }
851
+ */
852
+ function lockedFileUpdate(filePath, updateFn, opts = {}) {
853
+ const retries = opts.retries || 10;
854
+ const retryDelayMs = opts.retryDelayMs || 50;
855
+ const timeoutMs = opts.timeoutMs || 10000;
856
+ const lockPath = filePath + '.lock';
857
+
858
+ let lockFd = null;
859
+ let lockAcquired = false;
860
+
861
+ try {
862
+ for (let attempt = 0; attempt < retries; attempt++) {
863
+ try {
864
+ lockFd = fs.openSync(lockPath, 'wx');
865
+ lockAcquired = true;
866
+ break;
867
+ } catch (e) {
868
+ if (e.code === 'EEXIST') {
869
+ try {
870
+ const stats = fs.statSync(lockPath);
871
+ if (Date.now() - stats.mtimeMs > timeoutMs) {
872
+ fs.unlinkSync(lockPath);
873
+ continue;
874
+ }
875
+ } catch (_statErr) {
876
+ continue;
877
+ }
878
+
879
+ if (attempt < retries - 1) {
880
+ const baseWait = retryDelayMs * Math.pow(2, attempt);
881
+ const jitter = Math.floor(Math.random() * retryDelayMs);
882
+ const waitMs = Math.min(baseWait + jitter, 2000);
883
+ try {
884
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, waitMs);
885
+ } catch (_atomicsErr) {
886
+ const end = Date.now() + waitMs;
887
+ while (Date.now() < end) { /* last-resort fallback */ }
888
+ }
889
+ continue;
890
+ }
891
+ // Last retry exhausted — break to fall through to last-resort write
892
+ break;
893
+ }
894
+ throw e;
895
+ }
896
+ }
897
+
898
+ if (!lockAcquired) {
899
+ process.stderr.write(`[pbr] WARN: lock contention on ${path.basename(filePath)} after ${retries} attempts — writing without lock\n`);
900
+ // Fall through to read-modify-write below (last-resort write)
901
+ }
902
+
903
+ if (lockAcquired) {
904
+ fs.writeSync(lockFd, `${process.pid}`);
905
+ fs.closeSync(lockFd);
906
+ lockFd = null;
907
+ }
908
+
909
+ let content = '';
910
+ if (fs.existsSync(filePath)) {
911
+ content = fs.readFileSync(filePath, 'utf8');
912
+ }
913
+
914
+ const newContent = updateFn(content);
915
+
916
+ const writeResult = atomicWrite(filePath, newContent);
917
+ if (!writeResult.success) {
918
+ return { success: false, error: writeResult.error };
919
+ }
920
+
921
+ return { success: true, content: newContent };
922
+ } catch (e) {
923
+ return { success: false, error: e.message };
924
+ } finally {
925
+ try {
926
+ if (lockFd !== null) fs.closeSync(lockFd);
927
+ } catch (_e) { /* ignore */ }
928
+ if (lockAcquired) {
929
+ try { fs.unlinkSync(lockPath); } catch (_e) { /* ignore */ }
930
+ }
931
+ }
932
+ }
933
+
934
+ // ─── Lightweight JSON Schema validator ────────────────────────────────────────
935
+
936
+ /**
937
+ * Validate an object against a simple JSON Schema subset.
938
+ * Supports type, enum, properties, additionalProperties, minimum, maximum.
939
+ *
940
+ * @param {*} value - Value to validate
941
+ * @param {object} schema - JSON Schema subset
942
+ * @param {string} prefix - Path prefix for error messages
943
+ * @param {string[]} errors - Array to push errors to
944
+ * @param {string[]} warnings - Array to push warnings to
945
+ */
946
+ function validateObject(value, schema, prefix, errors, warnings) {
947
+ if (schema.type) {
948
+ const types = Array.isArray(schema.type) ? schema.type : [schema.type];
949
+ const actualType = typeof value;
950
+ const typeMatch = types.some(t => {
951
+ if (t === 'integer') return actualType === 'number' && Number.isInteger(value);
952
+ return actualType === t;
953
+ });
954
+ if (!typeMatch) {
955
+ errors.push(`${prefix || 'root'}: expected ${types.join('|')}, got ${actualType}`);
956
+ return;
957
+ }
958
+ }
959
+
960
+ if (schema.enum && !schema.enum.includes(value)) {
961
+ errors.push(`${prefix || 'root'}: value "${value}" not in allowed values [${schema.enum.join(', ')}]`);
962
+ return;
963
+ }
964
+
965
+ if (schema.minimum !== undefined && value < schema.minimum) {
966
+ errors.push(`${prefix || 'root'}: value ${value} is below minimum ${schema.minimum}`);
967
+ }
968
+ if (schema.maximum !== undefined && value > schema.maximum) {
969
+ errors.push(`${prefix || 'root'}: value ${value} is above maximum ${schema.maximum}`);
970
+ }
971
+
972
+ if (schema.type === 'object' && schema.properties) {
973
+ const knownKeys = new Set(Object.keys(schema.properties));
974
+ for (const key of Object.keys(value)) {
975
+ const fullKey = prefix ? `${prefix}.${key}` : key;
976
+ if (!knownKeys.has(key)) {
977
+ if (schema.additionalProperties === false) {
978
+ warnings.push(`${fullKey}: unrecognized key (possible typo?)`);
979
+ }
980
+ continue;
981
+ }
982
+ validateObject(value[key], schema.properties[key], fullKey, errors, warnings);
983
+ }
984
+ }
985
+ }
986
+
987
+ // ─── Session-scoped path resolution ───────────────────────────────────────────
988
+
989
+ const STALE_SESSION_MS = 4 * 60 * 60 * 1000; // 4 hours
990
+
991
+ /**
992
+ * Resolve a session-scoped file path.
993
+ *
994
+ * @param {string} pDir - Path to .planning/ directory
995
+ * @param {string} filename - Filename to resolve
996
+ * @param {string} sessionId - Session identifier
997
+ * @returns {string} Resolved path
998
+ */
999
+ function resolveSessionPath(pDir, filename, sessionId) {
1000
+ return path.join(pDir, '.sessions', sessionId, filename);
1001
+ }
1002
+
1003
+ /**
1004
+ * Ensure session directory exists and write meta.json.
1005
+ *
1006
+ * @param {string} pDir - Path to .planning/ directory
1007
+ * @param {string} sessionId - Session identifier
1008
+ */
1009
+ function ensureSessionDir(pDir, sessionId) {
1010
+ const dirPath = path.join(pDir, '.sessions', sessionId);
1011
+ fs.mkdirSync(dirPath, { recursive: true });
1012
+ const metaPath = path.join(dirPath, 'meta.json');
1013
+ if (!fs.existsSync(metaPath)) {
1014
+ fs.writeFileSync(metaPath, JSON.stringify({
1015
+ session_id: sessionId,
1016
+ created: new Date().toISOString(),
1017
+ pid: process.pid
1018
+ }, null, 2), 'utf8');
1019
+ }
1020
+ }
1021
+
1022
+ /**
1023
+ * Remove a session directory and all its contents.
1024
+ *
1025
+ * @param {string} pDir - Path to .planning/ directory
1026
+ * @param {string} sessionId - Session identifier
1027
+ */
1028
+ function removeSessionDir(pDir, sessionId) {
1029
+ const dirPath = path.join(pDir, '.sessions', sessionId);
1030
+ if (fs.existsSync(dirPath)) {
1031
+ fs.rmSync(dirPath, { recursive: true, force: true });
1032
+ }
1033
+ }
1034
+
1035
+ /**
1036
+ * Remove stale session directories older than STALE_SESSION_MS.
1037
+ *
1038
+ * @param {string} pDir - Path to .planning/ directory
1039
+ * @returns {Array<{sessionId: string, age: number}>} Removed sessions
1040
+ */
1041
+ function cleanStaleSessions(pDir) {
1042
+ const sessionsDir = path.join(pDir, '.sessions');
1043
+ if (!fs.existsSync(sessionsDir)) return [];
1044
+
1045
+ const removed = [];
1046
+ try {
1047
+ const entries = fs.readdirSync(sessionsDir, { withFileTypes: true });
1048
+ for (const entry of entries) {
1049
+ if (!entry.isDirectory()) continue;
1050
+ const dirPath = path.join(sessionsDir, entry.name);
1051
+ let ageMs = 0;
1052
+
1053
+ const metaPath = path.join(dirPath, 'meta.json');
1054
+ try {
1055
+ const meta = JSON.parse(fs.readFileSync(metaPath, 'utf8'));
1056
+ ageMs = Date.now() - new Date(meta.created).getTime();
1057
+ } catch (_e) {
1058
+ try {
1059
+ const stats = fs.statSync(dirPath);
1060
+ ageMs = Date.now() - stats.mtimeMs;
1061
+ } catch (_statErr) {
1062
+ continue;
1063
+ }
1064
+ }
1065
+
1066
+ if (ageMs > STALE_SESSION_MS) {
1067
+ fs.rmSync(dirPath, { recursive: true, force: true });
1068
+ removed.push({ sessionId: entry.name, age: ageMs });
1069
+ }
1070
+ }
1071
+ } catch (_e) { /* best effort */ }
1072
+
1073
+ return removed;
1074
+ }
1075
+
1076
+ // ─── Session state management ─────────────────────────────────────────────────
1077
+
1078
+ const SESSION_ALLOWED_KEYS = ['activeSkill', 'compactCounter', 'sessionStart', 'activeOperation', 'activePlan'];
1079
+
1080
+ /**
1081
+ * Load .session.json from .planning/ directory.
1082
+ *
1083
+ * @param {string} dir - Path to .planning/ directory
1084
+ * @param {string} [sessionId] - Session identifier for session-scoped path
1085
+ * @returns {object} Parsed session data or empty object
1086
+ */
1087
+ function sessionLoad(dir, sessionId) {
1088
+ const sessionPath = sessionId
1089
+ ? resolveSessionPath(dir, '.session.json', sessionId)
1090
+ : path.join(dir, '.session.json');
1091
+ try {
1092
+ if (!fs.existsSync(sessionPath)) return {};
1093
+ const content = fs.readFileSync(sessionPath, 'utf8');
1094
+ return JSON.parse(content);
1095
+ } catch (_e) {
1096
+ return {};
1097
+ }
1098
+ }
1099
+
1100
+ /**
1101
+ * Save data to .session.json using atomic write.
1102
+ * Merges provided data with existing session data.
1103
+ *
1104
+ * @param {string} dir - Path to .planning/ directory
1105
+ * @param {object} data - Key-value pairs to merge into session
1106
+ * @param {string} [sessionId] - Session identifier for session-scoped path
1107
+ * @returns {{ success: boolean, error?: string }}
1108
+ */
1109
+ function sessionSave(dir, data, sessionId) {
1110
+ const sessionPath = sessionId
1111
+ ? resolveSessionPath(dir, '.session.json', sessionId)
1112
+ : path.join(dir, '.session.json');
1113
+ const tmpPath = sessionPath + '.tmp';
1114
+ try {
1115
+ if (sessionId) ensureSessionDir(dir, sessionId);
1116
+ const existing = sessionLoad(dir, sessionId);
1117
+ const merged = Object.assign(existing, data);
1118
+ fs.writeFileSync(tmpPath, JSON.stringify(merged, null, 2), 'utf8');
1119
+ fs.renameSync(tmpPath, sessionPath);
1120
+ return { success: true };
1121
+ } catch (e) {
1122
+ try { if (fs.existsSync(tmpPath)) fs.unlinkSync(tmpPath); } catch (_) { /* cleanup */ }
1123
+ return { success: false, error: e.message };
1124
+ }
1125
+ }
1126
+
1127
+ /**
1128
+ * Clear session data by removing the .session.json file.
1129
+ *
1130
+ * @param {string} dir - Path to .planning/ directory
1131
+ * @param {string} [sessionId] - Session identifier for session-scoped path
1132
+ * @returns {{ success: boolean, error?: string }}
1133
+ */
1134
+ function sessionClear(dir, sessionId) {
1135
+ const sessionPath = sessionId
1136
+ ? resolveSessionPath(dir, '.session.json', sessionId)
1137
+ : path.join(dir, '.session.json');
1138
+ try {
1139
+ if (fs.existsSync(sessionPath)) fs.unlinkSync(sessionPath);
1140
+ return { success: true };
1141
+ } catch (e) {
1142
+ return { success: false, error: e.message };
1143
+ }
1144
+ }
1145
+
1146
+ /**
1147
+ * Dump all session data as a JSON object for debugging.
1148
+ *
1149
+ * @param {string} dir - Path to .planning/ directory
1150
+ * @param {string} [sessionId] - Session identifier for session-scoped path
1151
+ * @returns {object} Session data including metadata
1152
+ */
1153
+ function sessionDump(dir, sessionId) {
1154
+ const data = sessionLoad(dir, sessionId);
1155
+ const sessionPath = sessionId
1156
+ ? resolveSessionPath(dir, '.session.json', sessionId)
1157
+ : path.join(dir, '.session.json');
1158
+ return {
1159
+ path: sessionPath,
1160
+ exists: fs.existsSync(sessionPath),
1161
+ data,
1162
+ keys: Object.keys(data)
1163
+ };
1164
+ }
1165
+
1166
+ /**
1167
+ * Write .active-skill with OS-level mutual exclusion.
1168
+ *
1169
+ * @param {string} pDir - Path to .planning/ directory
1170
+ * @param {string} skillName - Skill name to write
1171
+ * @param {string} [sessionId] - Session identifier for session-scoped path
1172
+ * @returns {{success: boolean, warning?: string}} Result
1173
+ */
1174
+ function writeActiveSkill(pDir, skillName, sessionId) {
1175
+ const skillFile = sessionId
1176
+ ? resolveSessionPath(pDir, '.active-skill', sessionId)
1177
+ : path.join(pDir, '.active-skill');
1178
+ const lockFile = skillFile + '.lock';
1179
+ const staleThresholdMs = 60 * 60 * 1000;
1180
+
1181
+ if (sessionId) ensureSessionDir(pDir, sessionId);
1182
+
1183
+ let lockFd = null;
1184
+ try {
1185
+ lockFd = fs.openSync(lockFile, 'wx');
1186
+ fs.writeSync(lockFd, `${process.pid}`);
1187
+ fs.closeSync(lockFd);
1188
+ lockFd = null;
1189
+
1190
+ let warning = null;
1191
+ if (fs.existsSync(skillFile)) {
1192
+ try {
1193
+ const stats = fs.statSync(skillFile);
1194
+ const ageMs = Date.now() - stats.mtimeMs;
1195
+ if (ageMs < staleThresholdMs) {
1196
+ const existing = fs.readFileSync(skillFile, 'utf8').trim();
1197
+ warning = `.active-skill already set to "${existing}" (${Math.round(ageMs / 60000)}min ago). Overwriting.`;
1198
+ }
1199
+ } catch (_e) { /* file disappeared */ }
1200
+ }
1201
+
1202
+ fs.writeFileSync(skillFile, skillName, 'utf8');
1203
+ try { sessionSave(pDir, { activeSkill: skillName }, sessionId); } catch (_e) { /* non-fatal */ }
1204
+ try { fs.unlinkSync(lockFile); } catch (_e) { /* best effort */ }
1205
+
1206
+ return { success: true, warning };
1207
+ } catch (e) {
1208
+ try { if (lockFd !== null) fs.closeSync(lockFd); } catch (_e) { /* ignore */ }
1209
+
1210
+ if (e.code === 'EEXIST') {
1211
+ try {
1212
+ const lockStats = fs.statSync(lockFile);
1213
+ const lockAgeMs = Date.now() - lockStats.mtimeMs;
1214
+ if (lockAgeMs > staleThresholdMs) {
1215
+ fs.unlinkSync(lockFile);
1216
+ return writeActiveSkill(pDir, skillName, sessionId);
1217
+ }
1218
+ } catch (_statErr) {
1219
+ return writeActiveSkill(pDir, skillName, sessionId);
1220
+ }
1221
+ return { success: false, warning: `.active-skill.lock held by another process.` };
1222
+ }
1223
+
1224
+ try {
1225
+ fs.writeFileSync(skillFile, skillName, 'utf8');
1226
+ return { success: true, warning: `Lock failed (${e.code}), wrote without lock` };
1227
+ } catch (writeErr) {
1228
+ return { success: false, warning: `Failed to write .active-skill: ${writeErr.message}` };
1229
+ }
1230
+ }
1231
+ }
1232
+
1233
+ // ─── Phase claiming ───────────────────────────────────────────────────────────
1234
+
1235
+ /**
1236
+ * Check whether a claim is stale (its session directory no longer exists).
1237
+ *
1238
+ * @param {object} claimData - Parsed .claim JSON (must have session_id)
1239
+ * @param {string} pDir - Path to .planning/ directory
1240
+ * @returns {{ stale: boolean, reason?: string }}
1241
+ */
1242
+ function isClaimStale(claimData, pDir) {
1243
+ const sessionDir = path.join(pDir, '.sessions', claimData.session_id);
1244
+ if (!fs.existsSync(sessionDir)) {
1245
+ return { stale: true, reason: 'session_dir_missing' };
1246
+ }
1247
+ return { stale: false };
1248
+ }
1249
+
1250
+ /**
1251
+ * Acquire a phase claim for a session. Auto-releases stale claims.
1252
+ *
1253
+ * @param {string} pDir - Path to .planning/ directory
1254
+ * @param {string} phaseDir - Absolute path to the phase directory
1255
+ * @param {string} sessionId - Session identifier
1256
+ * @param {string} skill - Skill name acquiring the claim
1257
+ * @returns {{ acquired: boolean, conflict?: object, auto_released?: object }}
1258
+ */
1259
+ function acquireClaim(pDir, phaseDir, sessionId, skill) {
1260
+ const claimPath = path.join(phaseDir, '.claim');
1261
+ let autoReleased = null;
1262
+
1263
+ if (fs.existsSync(claimPath)) {
1264
+ try {
1265
+ const existing = JSON.parse(fs.readFileSync(claimPath, 'utf8'));
1266
+ if (existing.session_id !== sessionId) {
1267
+ const staleCheck = isClaimStale(existing, pDir);
1268
+ if (staleCheck.stale) {
1269
+ fs.unlinkSync(claimPath);
1270
+ autoReleased = existing;
1271
+ } else {
1272
+ return {
1273
+ acquired: false,
1274
+ conflict: {
1275
+ session_id: existing.session_id,
1276
+ skill: existing.skill,
1277
+ started: existing.started,
1278
+ pid: existing.pid
1279
+ },
1280
+ auto_released: null
1281
+ };
1282
+ }
1283
+ }
1284
+ } catch (_e) {
1285
+ try { fs.unlinkSync(claimPath); } catch (_unlinkErr) { /* best effort */ }
1286
+ }
1287
+ }
1288
+
1289
+ const claimData = {
1290
+ session_id: sessionId,
1291
+ skill: skill,
1292
+ started: new Date().toISOString(),
1293
+ pid: process.pid
1294
+ };
1295
+ fs.writeFileSync(claimPath, JSON.stringify(claimData, null, 2), 'utf8');
1296
+
1297
+ return { acquired: true, conflict: null, auto_released: autoReleased };
1298
+ }
1299
+
1300
+ /**
1301
+ * Release a phase claim owned by a specific session.
1302
+ *
1303
+ * @param {string} _pDir - Path to .planning/ directory (unused, for API consistency)
1304
+ * @param {string} phaseDir - Absolute path to the phase directory
1305
+ * @param {string} sessionId - Session identifier
1306
+ * @returns {{ released: boolean, reason?: string, owner?: string }}
1307
+ */
1308
+ function releaseClaim(_pDir, phaseDir, sessionId) {
1309
+ const claimPath = path.join(phaseDir, '.claim');
1310
+
1311
+ if (!fs.existsSync(claimPath)) {
1312
+ return { released: false, reason: 'no_claim' };
1313
+ }
1314
+
1315
+ try {
1316
+ const claim = JSON.parse(fs.readFileSync(claimPath, 'utf8'));
1317
+ if (claim.session_id !== sessionId) {
1318
+ return { released: false, reason: 'not_owner', owner: claim.session_id };
1319
+ }
1320
+ fs.unlinkSync(claimPath);
1321
+ return { released: true };
1322
+ } catch (_e) {
1323
+ try { fs.unlinkSync(claimPath); } catch (_unlinkErr) { /* best effort */ }
1324
+ return { released: true };
1325
+ }
1326
+ }
1327
+
1328
+ /**
1329
+ * List all active phase claims.
1330
+ *
1331
+ * @param {string} pDir - Path to .planning/ directory
1332
+ * @returns {{ claims: Array<object> }}
1333
+ */
1334
+ function listClaims(pDir) {
1335
+ const phasesDir = path.join(pDir, 'phases');
1336
+ if (!fs.existsSync(phasesDir)) {
1337
+ return { claims: [] };
1338
+ }
1339
+
1340
+ const results = [];
1341
+ try {
1342
+ const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
1343
+ for (const entry of entries) {
1344
+ if (!entry.isDirectory()) continue;
1345
+ const claimPath = path.join(phasesDir, entry.name, '.claim');
1346
+ if (!fs.existsSync(claimPath)) continue;
1347
+ try {
1348
+ const claimData = JSON.parse(fs.readFileSync(claimPath, 'utf8'));
1349
+ results.push({
1350
+ phase: entry.name,
1351
+ ...claimData,
1352
+ stale: isClaimStale(claimData, pDir).stale
1353
+ });
1354
+ } catch (_e) { /* skip malformed */ }
1355
+ }
1356
+ } catch (_e) { /* best effort */ }
1357
+
1358
+ return { claims: results };
1359
+ }
1360
+
1361
+ /**
1362
+ * Release all claims held by a specific session across all phase directories.
1363
+ *
1364
+ * @param {string} pDir - Path to .planning/ directory
1365
+ * @param {string} sessionId - Session identifier
1366
+ * @returns {{ released: string[] }}
1367
+ */
1368
+ function releaseSessionClaims(pDir, sessionId) {
1369
+ const phasesDir = path.join(pDir, 'phases');
1370
+ if (!fs.existsSync(phasesDir)) {
1371
+ return { released: [] };
1372
+ }
1373
+
1374
+ const released = [];
1375
+ try {
1376
+ const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
1377
+ for (const entry of entries) {
1378
+ if (!entry.isDirectory()) continue;
1379
+ const claimPath = path.join(phasesDir, entry.name, '.claim');
1380
+ if (!fs.existsSync(claimPath)) continue;
1381
+ try {
1382
+ const claimData = JSON.parse(fs.readFileSync(claimPath, 'utf8'));
1383
+ if (claimData.session_id === sessionId) {
1384
+ fs.unlinkSync(claimPath);
1385
+ released.push(entry.name);
1386
+ }
1387
+ } catch (_e) { /* skip malformed */ }
1388
+ }
1389
+ } catch (_e) { /* best effort */ }
1390
+
1391
+ return { released };
1392
+ }
1393
+
1394
+ // ─── Config loader (lightweight, used by core only) ───────────────────────────
1395
+
1396
+ function loadConfig(configCwd) {
1397
+ const configPath = path.join(configCwd, '.planning', 'config.json');
1398
+ const defaults = {
1399
+ model_profile: 'balanced',
1400
+ commit_docs: true,
1401
+ search_gitignored: false,
1402
+ branching_strategy: 'none',
1403
+ phase_branch_template: 'pbr/phase-{phase}-{slug}',
1404
+ milestone_branch_template: 'pbr/{milestone}-{slug}',
1405
+ research: true,
1406
+ plan_checker: true,
1407
+ verifier: true,
1408
+ nyquist_validation: true,
1409
+ parallelization: true,
1410
+ brave_search: false,
1411
+ };
1412
+
1413
+ try {
1414
+ const raw = fs.readFileSync(configPath, 'utf8');
1415
+ const parsed = JSON.parse(raw);
1416
+
1417
+ if ('depth' in parsed && !('granularity' in parsed)) {
1418
+ const depthToGranularity = { quick: 'coarse', standard: 'standard', comprehensive: 'fine' };
1419
+ parsed.granularity = depthToGranularity[parsed.depth] || parsed.depth;
1420
+ delete parsed.depth;
1421
+ try { fs.writeFileSync(configPath, JSON.stringify(parsed, null, 2), 'utf8'); } catch { /* best effort */ }
1422
+ }
1423
+
1424
+ const get = (key, nested) => {
1425
+ if (parsed[key] !== undefined) return parsed[key];
1426
+ if (nested && parsed[nested.section] && parsed[nested.section][nested.field] !== undefined) {
1427
+ return parsed[nested.section][nested.field];
1428
+ }
1429
+ return undefined;
1430
+ };
1431
+
1432
+ const parallelization = (() => {
1433
+ const val = get('parallelization');
1434
+ if (typeof val === 'boolean') return val;
1435
+ if (typeof val === 'object' && val !== null && 'enabled' in val) return val.enabled;
1436
+ return defaults.parallelization;
1437
+ })();
1438
+
1439
+ return {
1440
+ model_profile: get('model_profile') ?? defaults.model_profile,
1441
+ commit_docs: get('commit_docs', { section: 'planning', field: 'commit_docs' }) ?? defaults.commit_docs,
1442
+ search_gitignored: get('search_gitignored', { section: 'planning', field: 'search_gitignored' }) ?? defaults.search_gitignored,
1443
+ branching_strategy: get('branching_strategy', { section: 'git', field: 'branching_strategy' }) ?? defaults.branching_strategy,
1444
+ phase_branch_template: get('phase_branch_template', { section: 'git', field: 'phase_branch_template' }) ?? defaults.phase_branch_template,
1445
+ milestone_branch_template: get('milestone_branch_template', { section: 'git', field: 'milestone_branch_template' }) ?? defaults.milestone_branch_template,
1446
+ research: get('research', { section: 'workflow', field: 'research' }) ?? defaults.research,
1447
+ plan_checker: get('plan_checker', { section: 'workflow', field: 'plan_check' }) ?? defaults.plan_checker,
1448
+ verifier: get('verifier', { section: 'workflow', field: 'verifier' }) ?? defaults.verifier,
1449
+ nyquist_validation: get('nyquist_validation', { section: 'workflow', field: 'nyquist_validation' }) ?? defaults.nyquist_validation,
1450
+ parallelization,
1451
+ brave_search: get('brave_search') ?? defaults.brave_search,
1452
+ model_overrides: parsed.model_overrides || null,
1453
+ };
1454
+ } catch {
1455
+ return defaults;
1456
+ }
1457
+ }
1458
+
1459
+ /**
1460
+ * Check if a path is git-ignored, scoped to a cwd.
1461
+ *
1462
+ * @param {string} igCwd - Working directory
1463
+ * @param {string} targetPath - Path to check
1464
+ * @returns {boolean}
1465
+ */
1466
+ function pathExistsInternal(peCwd, targetPath) {
1467
+ const fullPath = path.isAbsolute(targetPath) ? targetPath : path.join(peCwd, targetPath);
1468
+ try {
1469
+ fs.statSync(fullPath);
1470
+ return true;
1471
+ } catch {
1472
+ return false;
1473
+ }
1474
+ }
1475
+
1476
+ function resolveModelInternal(rmCwd, agentType) {
1477
+ const config = loadConfig(rmCwd);
1478
+ return resolveModel(agentType, config);
1479
+ }
1480
+
1481
+ // ─── Exports ──────────────────────────────────────────────────────────────────
1482
+
1483
+ module.exports = {
1484
+ // Module-level state
1485
+ setCwd,
1486
+
1487
+ // Constants
1488
+ KNOWN_AGENTS,
1489
+ VALID_STATUS_TRANSITIONS,
1490
+ STATUS_LABELS,
1491
+ MODEL_PROFILES,
1492
+ SESSION_ALLOWED_KEYS,
1493
+ STALE_SESSION_MS,
1494
+
1495
+ // Status transitions
1496
+ validateStatusTransition,
1497
+
1498
+ // Output
1499
+ output,
1500
+ error,
1501
+
1502
+ // Path & file utilities
1503
+ toPosixPath,
1504
+ safeReadFile,
1505
+ ensureDir,
1506
+ findFiles,
1507
+ tailLines,
1508
+ escapeRegex,
1509
+
1510
+ // Git utilities
1511
+ execGit,
1512
+ isGitIgnored,
1513
+
1514
+ // YAML frontmatter
1515
+ parseYamlFrontmatter,
1516
+ parseMustHaves,
1517
+ setYamlFrontmatter,
1518
+
1519
+ // Misc utilities
1520
+ countMustHaves,
1521
+ determinePhaseStatus,
1522
+ calculateProgress,
1523
+ currentTimestamp,
1524
+ generateSlug,
1525
+ resolveModel,
1526
+
1527
+ // Phase utilities
1528
+ normalizePhaseName,
1529
+ comparePhaseNum,
1530
+ searchPhaseInDir,
1531
+ findPhaseInternal,
1532
+ getArchivedPhaseDirs,
1533
+
1534
+ // Roadmap & milestone
1535
+ getRoadmapPhaseInternal,
1536
+ getMilestoneInfo,
1537
+ getMilestonePhaseFilter,
1538
+
1539
+ // Config loader (lightweight)
1540
+ loadConfig,
1541
+ pathExistsInternal,
1542
+ resolveModelInternal,
1543
+ generateSlugInternal: generateSlug,
1544
+
1545
+ // Atomic operations
1546
+ atomicWrite,
1547
+ lockedFileUpdate,
1548
+
1549
+ // Schema validation
1550
+ validateObject,
1551
+
1552
+ // Session management
1553
+ resolveSessionPath,
1554
+ ensureSessionDir,
1555
+ removeSessionDir,
1556
+ cleanStaleSessions,
1557
+ sessionLoad,
1558
+ sessionSave,
1559
+ sessionClear,
1560
+ sessionDump,
1561
+ writeActiveSkill,
1562
+
1563
+ // Phase claiming
1564
+ isClaimStale,
1565
+ acquireClaim,
1566
+ releaseClaim,
1567
+ listClaims,
1568
+ releaseSessionClaims,
1569
+ };