@overdeck/desktop 0.45.21 → 0.45.23

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 (387) hide show
  1. package/package.json +1 -1
  2. package/server/{acceptance-criteria-CJIFA8Vg.js → acceptance-criteria-DOA0KgXx.js} +5 -5
  3. package/server/{advancing-selfheal-CPOBO5ZS.js → advancing-selfheal-BBu6DSNm.js} +6 -6
  4. package/server/{agent-gc-D6PUckBB.js → agent-gc-BV1q_2EV.js} +4 -4
  5. package/server/agent-state-Bg0lhqwj.js +3 -0
  6. package/server/{agent-state-service-DHwemt96.js → agent-state-service-CnzFKSAQ.js} +1 -1
  7. package/server/{agent-state-service-6MFQqnFy.js → agent-state-service-HoK8U4jW.js} +5 -5
  8. package/server/{agents-DbrHWunF.js → agents-B4Bjbkfv.js} +4 -4
  9. package/server/agents-FlIgQ3ql.js +3 -0
  10. package/server/{archive-planning-BOnwJq8M.js → archive-planning-DYrYojxl.js} +31 -7
  11. package/server/{archive-planning-MPpvQJL4.js → archive-planning-zkJb3BeM.js} +1 -1
  12. package/server/{artifact-index-jobs-BOoySTKD.js → artifact-index-jobs-C-xy7Z5v.js} +2 -2
  13. package/server/{backlog-auto-trigger-BUaFI44J.js → backlog-auto-trigger-GtG71X8H.js} +3 -3
  14. package/server/{behavior-Dg-D8eBG.js → behavior-B_-4EKF3.js} +2 -2
  15. package/server/{briefing-freshness-OouGbJ7d.js → briefing-freshness-DWdW7vUm.js} +2 -2
  16. package/server/{build-info-27NlbKhV.js → build-info-BT096lEl.js} +3 -3
  17. package/server/{build-info-Cv6CI7Gu.js → build-info-DgTqZkL5.js} +1 -1
  18. package/server/{checkpoint-manager-C7mFCY_E.js → checkpoint-manager-B7Bt29J0.js} +1 -1
  19. package/server/{checkpoint-manager-D64fCC4p.js → checkpoint-manager-DDqcGyu8.js} +2 -2
  20. package/server/checkpoint-worker.js +1 -1
  21. package/server/{checkpoints-Vh-J15ge.js → checkpoints-C-AXLfYT.js} +2 -2
  22. package/server/{checkpoints-DwZqT2qQ.js → checkpoints-CpgCjAlN.js} +1 -1
  23. package/server/{claude-hooks-provision-CS5W_dhI.js → claude-hooks-provision-C8wdRnN1.js} +1 -1
  24. package/server/{claude-hooks-provision-BVLGfHrv.js → claude-hooks-provision-but-_qGY.js} +2 -2
  25. package/server/{claude-permissions-C2OrLYKL.js → claude-permissions-H_5wHQZQ.js} +2 -2
  26. package/server/{claude-settings-overlay-DWXjafJh.js → claude-settings-overlay-BTENVmYf.js} +1 -1
  27. package/server/{claude-settings-overlay-DX-fMFpC.js → claude-settings-overlay-CbSz0Dvb.js} +2 -2
  28. package/server/cli-BsVIHwzC.js +3 -0
  29. package/server/{cli-mvpEOb3w.js → cli-vBeXbPrq.js} +9 -9
  30. package/server/{cliproxy-Dvsr4ZkW.js → cliproxy-Bgb2XCqi.js} +2 -2
  31. package/server/{cliproxy-7g1nObvB.js → cliproxy-DW0V86F8.js} +1 -1
  32. package/server/{close-issue-8F6uawYj.js → close-issue-Dn_4c4G8.js} +5 -5
  33. package/server/{closed-issue-reaper-BhV-r-tC.js → closed-issue-reaper-CWpY2uBw.js} +1 -1
  34. package/server/{closed-issue-reaper-BaYQYF6w.js → closed-issue-reaper-hANY_ehE.js} +9 -9
  35. package/server/codex-Dg7Is5yb.js +3 -0
  36. package/server/{codex-D_UBEOwL.js → codex-TmSi-yTv.js} +30 -8
  37. package/server/{codex-parser-BTzlOZiV.js → codex-parser-C4gSH-IR.js} +2 -2
  38. package/server/{config-CrduXs4a.js → config-CCvjQf27.js} +2 -2
  39. package/server/{config-nAB_F-Gp.js → config-DUIhMN_T.js} +1 -1
  40. package/server/{config-G1TOMJZA.js → config-DjLOdbgT.js} +2 -2
  41. package/server/{config-yaml-Ciyp2mYe.js → config-yaml-DvyMuOle.js} +177 -211
  42. package/server/{conflict-gate-BKalpcjL.js → conflict-gate-BSJkNTdp.js} +1 -1
  43. package/server/{conflict-gate-BLUNMs1i.js → conflict-gate-CmrYpa47.js} +3 -3
  44. package/server/{context-layers-YNpf6Q_I.js → context-layers-B3Nt58jl.js} +2 -2
  45. package/server/{context-layers-Cg9ZgVfx.js → context-layers-ZYFcWiyc.js} +3 -3
  46. package/server/{control-settings-D_79A6gp.js → control-settings-aP1ANIlI.js} +4 -4
  47. package/server/{conversation-compaction-DiuZbIUB.js → conversation-compaction-CNbTLB86.js} +8 -8
  48. package/server/{conversation-compaction-CMIeWW4_.js → conversation-compaction-DiG5zWQq.js} +1 -1
  49. package/server/{conversation-service-DQybSPUK.js → conversation-service-Du-MTNpJ.js} +6 -6
  50. package/server/{conversation-service-CWk8mEym.js → conversation-service-Up7FEzIC.js} +1 -1
  51. package/server/{conversations-BJ-t3BRm.js → conversations-6mPANqvL.js} +1 -1
  52. package/server/{conversations-BUgGvqVL.js → conversations-DbOs1e9Q.js} +4 -4
  53. package/server/{cost-jJ2cgDcG.js → cost-CW4WSe72.js} +3 -3
  54. package/server/{cost-Drm7qeD5.js → cost-Ca0YTWDw.js} +18 -2
  55. package/server/{cost-sync-DzHP6zaR.js → cost-sync-C0VdGme1.js} +3 -3
  56. package/server/{dag-DIji6O2b.js → dag-CdOjJVDT.js} +9 -9
  57. package/server/{dangerous-git-ops-BebB-61h.js → dangerous-git-ops-CT-IypG3.js} +1 -1
  58. package/server/dashboard-db-worker.js +7 -7
  59. package/server/{deacon-pleYrvIm.js → deacon-DYSEJb48.js} +3 -3
  60. package/server/{deacon-nudge-log-C5VCKtyi.js → deacon-nudge-log-Bjg8U4Y9.js} +3 -3
  61. package/server/{deacon-1s7bM5zn.js → deacon-pRnyD5w9.js} +1133 -474
  62. package/server/deacon-swarm-9jRLS5Ke.js +2 -0
  63. package/server/{deacon-swarm-DmA3rJ7k.js → deacon-swarm-DftYRDo8.js} +17 -17
  64. package/server/deacon.js +8 -8
  65. package/server/{deploy-patrol-DmM6F-yw.js → deploy-patrol-Bjsho_ha.js} +136 -19
  66. package/server/{deploy-window-ClLq1RYf.js → deploy-window-CM6W1-c6.js} +1 -1
  67. package/server/{deploy-window-jw4S_Y-c.js → deploy-window-DeP_OIRk.js} +77 -10
  68. package/server/{dev-supervisor-Do2Stz49.js → dev-supervisor-BpMoHlkR.js} +2 -2
  69. package/server/{devcontainer-renderer-D8ylupco.js → devcontainer-renderer-CtUgrVKW.js} +3 -3
  70. package/server/dist-Bd3vn0Hw.js +3 -0
  71. package/server/{dist-yfR7G1BL.js → dist-DyRx4cI7.js} +1 -1
  72. package/server/{docker-ClwPQaba.js → docker-BK7HIcBj.js} +2 -2
  73. package/server/{dod-BLphkhjs.js → dod-BrSfUHm0.js} +1 -1
  74. package/server/{ensure-devcontainer-BA3bICoY.js → ensure-devcontainer-DRqaAkBR.js} +1 -1
  75. package/server/{ensure-devcontainer-CFpQatOc.js → ensure-devcontainer-DseivYEy.js} +4 -4
  76. package/server/{esm-shims-BZw-fTQ6.js → esm-shims-CbI3BVkl.js} +1 -1
  77. package/server/{event-store-DABarGNz.js → event-store-Cr5PQwFC.js} +1 -1
  78. package/server/{event-store-BVnON3vf.js → event-store-tdiY5eDZ.js} +3 -3
  79. package/server/{events-CmERlnwn.js → events-CC1dgUpx.js} +3 -3
  80. package/server/{events-LGeUehYW.js → events-CvvGK6LT.js} +1 -1
  81. package/server/{factory-CQNprtHe.js → factory-CynerjXO.js} +50 -13
  82. package/server/{feature-registry-population-D9Z3tYSa.js → feature-registry-population-B0pmAz0a.js} +4 -4
  83. package/server/{feature-registry-storage-BWymOgXE.js → feature-registry-storage-_wUBRD3J.js} +2 -2
  84. package/server/{features--fOza5g5.js → features-Dhxz-wLc.js} +2 -2
  85. package/server/{feedback-target-Dqik2WTe.js → feedback-target-CPS15Vte.js} +7 -7
  86. package/server/{feedback-target-Dn9vfPpz.js → feedback-target-iygZwmMc.js} +1 -1
  87. package/server/{feedback-writer-Wlq5-qgS.js → feedback-writer-C9b6ccN1.js} +6 -5
  88. package/server/{feedback-writer-DDQNV8uc.js → feedback-writer-qmiMbqTZ.js} +1 -1
  89. package/server/{flywheel-Q-38YhZG.js → flywheel-DMCUzDWg.js} +1 -1
  90. package/server/{flywheel-1Wd8WDlh.js → flywheel-DSSpWmqF.js} +13 -13
  91. package/server/{flywheel-DPUc8r3V.js → flywheel-DcBkQvgE.js} +14 -14
  92. package/server/{flywheel-merge-order-CeBuX0EJ.js → flywheel-merge-order-C-6zRLvM.js} +1 -1
  93. package/server/{flywheel-merge-order-4SqOXFAr.js → flywheel-merge-order-DxbQKE1d.js} +8 -8
  94. package/server/forge-B-ZWyTRm.js +2 -0
  95. package/server/{forge-DBbDpiYc.js → forge-Ch9gCFod.js} +2 -2
  96. package/server/{from-hh6vTBGl.js → from-CJ_aH5jD.js} +1 -1
  97. package/server/{fts-db-6ponMie2.js → fts-db-CKgg0VKg.js} +2 -2
  98. package/server/{fts-operations-KIRK165y.js → fts-operations-BrL_VTRr.js} +2 -2
  99. package/server/git-utils-BVa07a4a.js +198 -0
  100. package/server/{git-utils-DmF5xkj8.js → git-utils-Dry_Ka_D.js} +1 -1
  101. package/server/{github-app-B3yfECo8.js → github-app-CMBdIFBQ.js} +11 -3
  102. package/server/{github-app-CeSVFL6C.js → github-app-CPfoFAdV.js} +1 -1
  103. package/server/{github-client-Dslipypz.js → github-client--XVlDpwM.js} +2 -2
  104. package/server/{github-client-4A6FgA8O.js → github-client-B4QsdE-X.js} +1 -1
  105. package/server/{github-pr-lookup-DBP0YHMr.js → github-pr-lookup-BRbDW-qk.js} +2 -2
  106. package/server/harness-binary-CVio2m-u.js +106 -0
  107. package/server/{harness-resolve-BGpO-OVM.js → harness-resolve-qHJBhy3Z.js} +9 -15
  108. package/server/{health-events-CZGZ5I-A.js → health-events-C9B8y1Hm.js} +2 -2
  109. package/server/{health-events-CnwV_SSz.js → health-events-CpfvuVmm.js} +1 -1
  110. package/server/{hooks-CoNscX84.js → hooks-DUXw8A0-.js} +2 -2
  111. package/server/{hooks-DvX33gY_.js → hooks-ltecuFqZ.js} +1 -1
  112. package/server/{hume-DSJt5eA_.js → hume-BEq0bUDg.js} +2 -2
  113. package/server/hume-B_DbflNM.js +3 -0
  114. package/server/{idle-stack-reaper-5DVRoY6P.js → idle-stack-reaper-D7w9t3fE.js} +1 -1
  115. package/server/{idle-stack-reaper-BfL8HqYy.js → idle-stack-reaper-w1ISSlhs.js} +2 -2
  116. package/server/{in-flight-guard-tVGiI5ee.js → in-flight-guard-aQ1IxeI3.js} +2 -2
  117. package/server/{infra-DN2wSxle.js → infra-CzaSOgul.js} +4 -4
  118. package/server/{injection-DtlT8Akv.js → injection-DZ0PfYa4.js} +7 -7
  119. package/server/{injection-DK9zh_HL.js → injection-oNZeoDhL.js} +1 -1
  120. package/server/{inspect-agent-DKByUS_F.js → inspect-agent-DJKLWcVT.js} +15 -11
  121. package/server/inspect-agent-ch-F-5Ci.js +2 -0
  122. package/server/{internal-token-DhfFiwW7.js → internal-token-Bb4XeV2x.js} +2 -2
  123. package/server/{internal-token-7bYL5v6K.js → internal-token-DXdfprGr.js} +1 -1
  124. package/server/{io-BiM-7Zsx.js → io-B3_AHDfr.js} +160 -184
  125. package/server/{issue-closed-Dfw3QDyZ.js → issue-closed-zhdvQicO.js} +7 -7
  126. package/server/{issue-lifecycle-B7HZWnTA.js → issue-lifecycle-CreaCkjW.js} +22 -22
  127. package/server/{issue-lifecycle-ytsEdDlK.js → issue-lifecycle-Dy4vd0Oa.js} +1 -1
  128. package/server/{issue-service-singleton-CPESc4Or.js → issue-service-singleton-B5ushCvE.js} +8 -8
  129. package/server/{issue-service-singleton-D5EB5eYr.js → issue-service-singleton-DabvBWUp.js} +1 -1
  130. package/server/{issues-XYtFMxrH.js → issues-B6ToV6x1.js} +2 -2
  131. package/server/{jsonl-parser-DJV2eZUP.js → jsonl-parser-Dhflo1SH.js} +3 -3
  132. package/server/{label-cleanup-CJ4m8iRU.js → label-cleanup-BKPJm4Hv.js} +3 -3
  133. package/server/{label-reconciler-CNf3Ylm3.js → label-reconciler-DdWbHEBu.js} +4 -4
  134. package/server/{launcher-generator-5DJRiovn.js → launcher-generator-CHVm7bGT.js} +10 -9
  135. package/server/{layers-cZx7ibtV.js → layers-DzxSTGNA.js} +2 -2
  136. package/server/lifecycle-DfeyBDwA.js +121 -0
  137. package/server/lifecycle-io-Bsnr2K4F.js +3 -0
  138. package/server/{lifecycle-io-DMurK4oM.js → lifecycle-io-D8iNBcux.js} +37 -37
  139. package/server/{lifecycle-CE7619Xw.js → lifecycle-sycO16hj.js} +6 -6
  140. package/server/{linear-client-BLyN-NiP.js → linear-client-D4zqMnX7.js} +2 -2
  141. package/server/{linear-client-Bj1l4FOA.js → linear-client-DqhDQO9k.js} +1 -1
  142. package/server/memory-fts-worker.js +1 -1
  143. package/server/{merge-hSC2BENe.js → merge-C_ZEhbqI.js} +3 -3
  144. package/server/{merge-CwX2_AWm.js → merge-DK23JEdS.js} +1 -1
  145. package/server/{merge-agent-CnORPiri.js → merge-agent-BQM3a8z5.js} +1 -1
  146. package/server/{merge-agent-DnBsms_V.js → merge-agent-XrB80vfT.js} +369 -213
  147. package/server/{merge-batch-C2w2U2eK.js → merge-batch-Bwoyr8Je.js} +1 -1
  148. package/server/{merge-blockers-DhRgh76x.js → merge-blockers-BsFjGrQ8.js} +2 -2
  149. package/server/merge-ops-DlB1IM0Y.js +2 -0
  150. package/server/{merge-rebase-CE-ZyOMY.js → merge-rebase-C1KIVr0s.js} +2 -2
  151. package/server/{merge-set-D7YNU1ZB.js → merge-set-DLz0MkGT.js} +3 -3
  152. package/server/{merge-set-DHkzPCJU.js → merge-set-DnSYdBEp.js} +1 -1
  153. package/server/{merge-sync-De1FYva5.js → merge-sync-DZ9dojJn.js} +2 -2
  154. package/server/{merge-sync-CpGA9Kg7.js → merge-sync-SSv3E-pl.js} +1 -1
  155. package/server/{merge-train-SvkRJZ-k.js → merge-train-DxDfBTjr.js} +3 -3
  156. package/server/{merge-train-deps-CECJTElu.js → merge-train-deps-CyYQUksx.js} +4 -4
  157. package/server/{merge-verification-B3meGcXF.js → merge-verification-CSizH3HY.js} +4 -4
  158. package/server/{multipart-parser-ByTMgYV5.js → multipart-parser-Dt8YPN5S.js} +2 -2
  159. package/server/{no-resume-mode-BnInAFKs.js → no-resume-mode-Cx3K0hHi.js} +11 -8
  160. package/server/node_modules/.package-lock.json +5 -5
  161. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/README.md +3 -3
  162. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeChildProcessSpawner.d.ts.map +1 -1
  163. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeChildProcessSpawner.js +2 -2
  164. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeChildProcessSpawner.js.map +1 -1
  165. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/package.json +5 -5
  166. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/src/NodeChildProcessSpawner.ts +6 -8
  167. package/server/{orphan-proposed-reconciler-CAfuWTA1.js → orphan-proposed-reconciler-BTkDrl4R.js} +1 -1
  168. package/server/{orphan-proposed-reconciler-AxAGUouN.js → orphan-proposed-reconciler-neK8dHQk.js} +23 -14
  169. package/server/package-lock.json +6 -6
  170. package/server/package.json +1 -1
  171. package/server/{pan-dir-Rw17YjT1.js → pan-dir-DeVUgwA7.js} +78 -58
  172. package/server/{paths-FP8v3lTz.js → paths-_zEts6wc.js} +2 -2
  173. package/server/{pickup-xi3KTLaJ.js → pickup-Dd0Znxxy.js} +2 -2
  174. package/server/{pipeline-membership-BtKMNY7v.js → pipeline-membership-0HaEGDlH.js} +190 -68
  175. package/server/{pipeline-notifier-dQ-U4NSb.js → pipeline-notifier-6iCJplFZ.js} +1 -1
  176. package/server/{pipeline-notifier-BM2HLF7B.js → pipeline-notifier-D0ykk59O.js} +2 -2
  177. package/server/{project-pipelines-B59NfN44.js → project-pipelines-2sK1apsO.js} +2 -2
  178. package/server/projects-9SkRpES9.js +3 -0
  179. package/server/{prompts-CbqaVjbe.js → prompts-Dp4Tpk39.js} +2 -2
  180. package/server/providers-DKkBXhxU.js +3 -0
  181. package/server/{providers-d3pwXGVE.js → providers-DV7ec8l7.js} +7 -7
  182. package/server/public/assets/{chunk-BO2N2NFS-BxYSL7J-.js → chunk-BO2N2NFS-CltymLRg.js} +4 -4
  183. package/server/public/assets/{diagram-OG6HWLK6-C_F9Q2as.js → diagram-OG6HWLK6-D2f6pjgA.js} +1 -1
  184. package/server/public/assets/{dist-DQNg4CiF.js → dist-BWR4qFiV.js} +1 -1
  185. package/server/public/assets/{dist-CLSlc6cV.js → dist-DEmlBBNQ.js} +3 -3
  186. package/server/public/assets/{ganttDiagram-6RSMTGT7-Cq0my-0C.js → ganttDiagram-6RSMTGT7-DnfiViPK.js} +1 -1
  187. package/server/public/assets/{highlighted-body-OFNGDK62-eZC03dGh.js → highlighted-body-OFNGDK62-B8Wrmj9H.js} +1 -1
  188. package/server/public/assets/index-CUr1xv8w.css +1 -0
  189. package/server/public/assets/{index-SLYGA8AQ.js → index-CsSuZQBI.js} +148 -145
  190. package/server/public/assets/{linear-6Fi3qnGg.js → linear-C9zFQpkX.js} +1 -1
  191. package/server/public/assets/mermaid-GHXKKRXX-BUAB8hqt.js +1 -0
  192. package/server/public/assets/{pieDiagram-4H26LBE5-Dpmc6xsv.js → pieDiagram-4H26LBE5-lR8H7Yjd.js} +1 -1
  193. package/server/public/assets/{prod-ojHllFvN.js → prod-B1jCQihw.js} +4 -4
  194. package/server/public/assets/{quadrantDiagram-W4KKPZXB-Ulr9gON5.js → quadrantDiagram-W4KKPZXB-CVQ2guem.js} +1 -1
  195. package/server/public/assets/{sankeyDiagram-5OEKKPKP-CwdHGXfL.js → sankeyDiagram-5OEKKPKP-eD1RB4gm.js} +1 -1
  196. package/server/public/assets/{xychartDiagram-2RQKCTM6-r-bEDzJh.js → xychartDiagram-2RQKCTM6-ChEC6dQn.js} +1 -1
  197. package/server/public/index.html +54 -10
  198. package/server/{pull-requests-D3N6HQzI.js → pull-requests--Ib2jTgy.js} +1 -1
  199. package/server/{pull-requests-CjjPj7v6.js → pull-requests-CXIhdCYD.js} +13 -11
  200. package/server/{queries-B5hl7lMQ.js → queries-6d7Cdtm7.js} +723 -110
  201. package/server/{rally-Dp0Gb1DN.js → rally-B708-nZn.js} +3 -3
  202. package/server/{rally-api-DGaFz5L5.js → rally-api-nY0ZANw3.js} +2 -2
  203. package/server/{rally-api-CKr0O4DJ.js → rally-api-yjQ0TfHd.js} +1 -1
  204. package/server/{rally-client-SVbjGvqj.js → rally-client-B1EJhfV0.js} +4 -4
  205. package/server/{rally-client-Cqf6EX_r.js → rally-client-CULK2XAY.js} +1 -1
  206. package/server/rally-njs_mJrt.js +3 -0
  207. package/server/reap-terminal-sessions-MWnqdLCJ.js +4 -0
  208. package/server/{reap-terminal-sessions-CjqRAGw7.js → reap-terminal-sessions-N3BTkmX_.js} +11 -28
  209. package/server/{rebuild-stack-DHqCLvLX.js → rebuild-stack-Dp4eLkt4.js} +6 -6
  210. package/server/{rebuild-stack-DjdpALr1.js → rebuild-stack-kA7XngID.js} +1 -1
  211. package/server/{reconstruct-cache-BqrCQt0o.js → reconstruct-cache-uWbZfjms.js} +6 -6
  212. package/server/record-t6V-3Dcj.js +3 -0
  213. package/server/{record-update-BlB8mpKO.js → record-update-DACtKh6_.js} +1 -1
  214. package/server/record-update-Dq0t2uBG.js +310 -0
  215. package/server/{recovery-trip-l1Hsi37x.js → recovery-trip-BJtIQuag.js} +2 -2
  216. package/server/{release-engine-CSI4K6Oj.js → release-engine-DZpmGGzb.js} +5 -5
  217. package/server/{release-set-BywwggrE.js → release-set-hnXd_kga.js} +3 -3
  218. package/server/{remote-DYziAkiZ.js → remote-4tiENDaI.js} +3 -3
  219. package/server/{remote-cnoeuDWn.js → remote-Br-ZWVIP.js} +3 -3
  220. package/server/{remote-agents-BNORDWAX.js → remote-agents-CRCg1L4H.js} +1 -1
  221. package/server/{remote-agents-CZ2rc8I0.js → remote-agents-nmty1mLu.js} +6 -6
  222. package/server/{remote-completion-W67FNQ-A.js → remote-completion-BbWNd10K.js} +13 -13
  223. package/server/resume-CcKqnTvE.js +3 -0
  224. package/server/{review-agent-CSswH985.js → review-agent-DJRO8EG8.js} +1 -1
  225. package/server/{review-agent-CqSqSHkU.js → review-agent-sKkE1FEL.js} +23 -23
  226. package/server/{review-artifacts-BBgnd5df.js → review-artifacts-BLbSC4ke.js} +5 -5
  227. package/server/{review-context-Ctp9BdNJ.js → review-context-BgX3lcCx.js} +9 -9
  228. package/server/{review-status-CCgPVK1h.js → review-status-A7quS5KJ.js} +56 -39
  229. package/server/review-status-C6n6-9f_.js +3 -0
  230. package/server/{review-status-enrichment-DtDRGpst.js → review-status-enrichment-tbOn_A_u.js} +3 -3
  231. package/server/review-status-source-CxuEjLGg.js +39 -0
  232. package/server/{review-status-sync-jnLgd04F.js → review-status-sync-BhSQ0d0l.js} +2 -2
  233. package/server/{review-status-sync-C792ksoJ.js → review-status-sync-To3-iS-N.js} +1 -1
  234. package/server/{review-verdict-feedback-D5lW0o3k.js → review-verdict-feedback-C1Kg8n7t.js} +1 -1
  235. package/server/{review-verdict-feedback-CMsIpTpy.js → review-verdict-feedback-CTRNtzXO.js} +7 -7
  236. package/server/{rollup-B3kQmNpl.js → rollup-B53Y81xK.js} +1 -1
  237. package/server/{rollup-CLj_AK9f.js → rollup-WA0VD-Rr.js} +8 -8
  238. package/server/{scanner-C4NeC4FE.js → scanner-D2743cp8.js} +11 -7
  239. package/server/{sequence-io-Ce-6grIY.js → sequence-io-Cg0zYj_E.js} +4 -4
  240. package/server/{sequencer-agent-Bpz0yGmG.js → sequencer-agent-BGY8gjg-.js} +5 -5
  241. package/server/server.js +1348 -963
  242. package/server/{service-CqAY8Kmk.js → service-DCpB_SGd.js} +154 -51
  243. package/server/{session-fork-uNo4rMRA.js → session-fork-BQ8_6H32.js} +2 -2
  244. package/server/{session-history-DUehL3KN.js → session-history-CVZDpS3c.js} +4 -4
  245. package/server/{settings-DP2OYLXL.js → settings-BZ5m1UCl.js} +3 -3
  246. package/server/settings-D0OSwos5.js +2 -0
  247. package/server/{settings-D9grjmaP.js → settings-ylxwqwQG.js} +2 -2
  248. package/server/{shadow-engineering-Bi_oIMtF.js → shadow-engineering-BlxG6Xye.js} +3 -3
  249. package/server/{shadow-state-CDxEuPlE.js → shadow-state-C2_epgx2.js} +1 -1
  250. package/server/{shadow-state-a_ztFBJe.js → shadow-state-Dh-HzF2J.js} +2 -2
  251. package/server/{shadow-utils-CyOg6_Xq.js → shadow-utils-4bvjn9b3.js} +2 -2
  252. package/server/{ship-log-DDcueaIR.js → ship-log-ClSMIzZX.js} +1 -1
  253. package/server/{smart-compaction-C1_VVLEd.js → smart-compaction-CHIxLr_d.js} +1 -1
  254. package/server/{smart-compaction--Oj65Uov.js → smart-compaction-r4pHQBIr.js} +7 -7
  255. package/server/{spawn-planning-session-AiUSsBnH.js → spawn-planning-session-DWAorh2B.js} +25 -20
  256. package/server/{spawn-planning-session-LFtK2QCE.js → spawn-planning-session-KC_UduxD.js} +1 -1
  257. package/server/{specialist-completion-qOgqdqXH.js → specialist-completion-BXhav38U.js} +1 -1
  258. package/server/{specialist-context-gjj8Z4Ii.js → specialist-context-DtrYvGJ-.js} +5 -5
  259. package/server/{specialist-handoff-logger-BsBNvVZv.js → specialist-handoff-logger-C45ouoZ6.js} +2 -2
  260. package/server/{specialist-logs-CSLtvPx6.js → specialist-logs-DJ3RzKxW.js} +3 -3
  261. package/server/{specialists-D0VBf8g_.js → specialists-D5fRZXmN.js} +1 -1
  262. package/server/specialists-DVj0hvaL.js +3 -0
  263. package/server/{specialists-CYRwELzc.js → specialists-DyFeedjn.js} +66 -76
  264. package/server/{specialists-DAegTvRt.js → specialists-JVO00bs7.js} +374 -220
  265. package/server/specs-nN45DG2X.js +3 -0
  266. package/server/{src-OLoJhUiJ.js → src-CG9mCkP6.js} +6 -6
  267. package/server/{src-BqTcrfO_.js → src-CMTQGyCK.js} +3 -3
  268. package/server/{src-Dpq1yFIl.js → src-U7_kTPEE.js} +338 -4
  269. package/server/{stack-health-I713ELld.js → stack-health-Df0YEZKa.js} +1 -1
  270. package/server/{stack-health-DV_f-lK0.js → stack-health-puygdaMd.js} +2 -2
  271. package/server/{stale-task-claims-CQSKZVq0.js → stale-task-claims-BbFwCTb0.js} +4 -4
  272. package/server/{staleness-BbsGxmF2.js → staleness-Bpy41ngS.js} +15 -3
  273. package/server/{staleness-zGp4P1hd.js → staleness-Cbl_w4Bw.js} +1 -1
  274. package/server/{state-home-DixkE-up.js → state-home-CIGjwNfJ.js} +119 -54
  275. package/server/state-migrate-Dkzaxvny.js +487 -0
  276. package/server/{stuck-remediation-BWkK_O7A.js → stuck-remediation-CzEov_fq.js} +27 -21
  277. package/server/{stuck-remediation-CTPRC2S5.js → stuck-remediation-sY_MHHgQ.js} +1 -1
  278. package/server/{substrate-bug-weights-service-DXd0ID83.js → substrate-bug-weights-service-BH66lhm7.js} +3 -3
  279. package/server/{summary-fork-CdLn8Chr.js → summary-fork-D8bXjCr7.js} +2 -2
  280. package/server/{summary-fork-f3DpgjXh.js → summary-fork-DHhJIsAL.js} +8 -8
  281. package/server/{supervisor-Ch8CDuoF.js → supervisor-BO-Zk_h-.js} +3 -3
  282. package/server/supervisor-BPy-o1A8.js +2 -0
  283. package/server/{swarm-readiness-C9P2iPap.js → swarm-readiness-CQ_fwUWF.js} +4 -4
  284. package/server/{system-prerequisites-DkoQBn1q.js → system-prerequisites-Bza0ffAh.js} +24 -44
  285. package/server/{teardown-workspace-D-5yMyit.js → teardown-workspace-CEgauF4U.js} +15 -15
  286. package/server/{test-agent-queue-BwpUpu-o.js → test-agent-queue-DXDt0Xa-.js} +7 -7
  287. package/server/{test-verdict-BRiSu7eW.js → test-verdict-CmUBK5cT.js} +1 -1
  288. package/server/{test-verdict-BQ1yx7d4.js → test-verdict-DFjjIHR5.js} +1 -1
  289. package/server/{tldr-daemon-DjxP5g6Y.js → tldr-daemon-BDtLOIlO.js} +2 -2
  290. package/server/{tldr-daemon-BJA7TkqS.js → tldr-daemon-DL566HbH.js} +1 -1
  291. package/server/tmux-DoThH6aj.js +3 -0
  292. package/server/{tmux-y1blSxks.js → tmux-ftABRAmc.js} +76 -44
  293. package/server/{token-LUrbM9sU.js → token-CsOhvw42.js} +2 -2
  294. package/server/{token-util-BZaDAQ8S.js → token-util-CTmczIfW.js} +1 -1
  295. package/server/token-util-DrHg8abn.js +3 -0
  296. package/server/{tracker-config-DSFZBdXP.js → tracker-config-B4itFzDo.js} +2 -2
  297. package/server/{tracker-utils-WtP_V-yn.js → tracker-utils-BePq_oj-.js} +1 -1
  298. package/server/{tracker-utils-DiceZN3a.js → tracker-utils-tnxxqROg.js} +2 -2
  299. package/server/{traefik-connect-BXqfOP4-.js → traefik-connect-m73vGebA.js} +1 -1
  300. package/server/{tunnel-DTng1rfQ.js → tunnel-B2vxjx_b.js} +3 -3
  301. package/server/{tunnel-WcJImbAC.js → tunnel-Cgj-IGIl.js} +1 -1
  302. package/server/{types-BjaZ1oqH.js → types-BBNjPcqU.js} +1 -1
  303. package/server/{types-DqeBMmJN.js → types-hraoaQIp.js} +1 -1
  304. package/server/{uat-train-BpLnp7Cx.js → uat-train-CuEn0t9M.js} +28 -28
  305. package/server/{uat-train-Wismge7h.js → uat-train-cKfM-_WW.js} +1 -1
  306. package/server/{validation-BA4e5EGm.js → validation-B5JxoPUS.js} +259 -9
  307. package/server/{validation-CUWamZ4X.js → validation-CIi6pnI2.js} +1 -1
  308. package/server/{verification-artifact-Dr_0g9nb.js → verification-artifact-BcnIbigL.js} +1 -1
  309. package/server/{verification-artifact-CrbI4tJE.js → verification-artifact-C-lIHfUa.js} +1 -1
  310. package/server/{verification-runner-gAzh3cVD.js → verification-runner-Br0S_Ous.js} +103 -37
  311. package/server/{verification-runner-Dcksl_P-.js → verification-runner-CDj4lD4t.js} +1 -1
  312. package/server/{vtt-parser-3VZKsmSm.js → vtt-parser-DKpNNW5i.js} +1 -1
  313. package/server/{work-agent-prompt-ULdcANl5.js → work-agent-prompt-Yb2bd3Fq.js} +16 -15
  314. package/server/{workflows-B8ROFlfw.js → workflows-C9WmILql.js} +39 -77
  315. package/server/workflows-D90rMOya.js +2 -0
  316. package/server/{workspace-DhTDA8nB.js → workspace-BVl4rihN.js} +3 -3
  317. package/server/{workspace-DSjUJaJN.js → workspace-DuUdndHe.js} +1 -1
  318. package/server/{workspace-config-BAAsAv-o.js → workspace-config-cEGcO6UT.js} +1 -1
  319. package/server/{workspace-manager-CcujONCR.js → workspace-manager-ZTdJAy9M.js} +1 -1
  320. package/server/{workspace-manager-DsN52IMG.js → workspace-manager-hLUv3ADC.js} +23 -16
  321. package/server/{workspace-metadata-DIL5_U4c.js → workspace-metadata-CskwzzhL.js} +2 -2
  322. package/server/{workspace-metadata-CftOpNLs.js → workspace-metadata-DNpMixRq.js} +1 -1
  323. package/server/{workspaces-Dmlh1YXm.js → workspaces-hWvy9eKs.js} +276 -110
  324. package/sync-sources/agents/pan-inspect-agent.md +1 -1
  325. package/sync-sources/agents/pan-merge-agent.md +1 -1
  326. package/sync-sources/agents/pan-planning-agent.md +4 -4
  327. package/sync-sources/agents/pan-work-agent.md +1 -1
  328. package/sync-sources/dev-skills/pan-commit/SKILL.md +1 -1
  329. package/sync-sources/dev-skills/test-specialist-workflow/SKILL.md +1 -1
  330. package/sync-sources/hooks/record-cost-event.js +363 -71
  331. package/sync-sources/hooks/session-start-hook +7 -0
  332. package/sync-sources/hooks/work-agent-stop-hook +1 -1
  333. package/sync-sources/rules/per-bead-durability.md +1 -1
  334. package/sync-sources/rules/prd-authoring.md +1 -1
  335. package/sync-sources/skills/feature-work/SKILL.md +1 -1
  336. package/sync-sources/skills/pan/SKILL.md +2 -2
  337. package/sync-sources/skills/pan-admin-config/SKILL.md +1 -0
  338. package/sync-sources/skills/pan-approve/SKILL.md +1 -1
  339. package/sync-sources/skills/pan-close/SKILL.md +1 -1
  340. package/sync-sources/skills/pan-doctor/SKILL.md +1 -1
  341. package/sync-sources/skills/pan-new-project/SKILL.md +9 -11
  342. package/sync-sources/skills/pan-oversee/SKILL.md +5 -5
  343. package/sync-sources/skills/pan-plan/SKILL.md +6 -6
  344. package/sync-sources/skills/pan-quickstart/SKILL.md +1 -1
  345. package/sync-sources/skills/pan-recap/SKILL.md +2 -2
  346. package/sync-sources/skills/pan-review/SKILL.md +1 -1
  347. package/sync-sources/skills/pan-start/SKILL.md +26 -3
  348. package/sync-sources/skills/pan-swarm/SKILL.md +1 -1
  349. package/sync-sources/skills/pan-sync/SKILL.md +1 -1
  350. package/sync-sources/skills/pan-task/SKILL.md +2 -2
  351. package/sync-sources/skills/pan-wipe/SKILL.md +2 -2
  352. package/sync-sources/skills/pipeline-list/SKILL.md +1 -1
  353. package/sync-sources/skills/pipeline-status/SKILL.md +2 -2
  354. package/sync-sources/skills/plan/SKILL.md +11 -11
  355. package/sync-sources/skills/write-vbrief/SKILL.md +7 -282
  356. package/sync-sources/skills/write-xbrief/SKILL.md +295 -0
  357. package/sync-sources/templates/claude-md/sections/warnings.md +1 -1
  358. package/server/agent-state-BV_6RHnO.js +0 -3
  359. package/server/agents-Czz6R57Z.js +0 -3
  360. package/server/cli-ChErG518.js +0 -3
  361. package/server/codex-BBeZ8c3s.js +0 -3
  362. package/server/deacon-swarm-uudlSCLM.js +0 -2
  363. package/server/dist-BEDL2alY.js +0 -3
  364. package/server/forge-DbhJyH6u.js +0 -2
  365. package/server/git-utils-Bkxzr1Xf.js +0 -129
  366. package/server/hume-BrA1tUuk.js +0 -3
  367. package/server/inspect-agent-CyXNo9fM.js +0 -2
  368. package/server/lifecycle-io-CUpsxG0p.js +0 -3
  369. package/server/merge-ops-BpTtuO8x.js +0 -2
  370. package/server/projects-IRHJIPYC.js +0 -3
  371. package/server/providers-BqCdTryq.js +0 -3
  372. package/server/public/assets/index-C6NLz_1S.css +0 -1
  373. package/server/public/assets/mermaid-GHXKKRXX-BNwFoQsf.js +0 -1
  374. package/server/rally-DGimSRBQ.js +0 -3
  375. package/server/reap-terminal-sessions-C1mfzoZo.js +0 -3
  376. package/server/record-update-RviRDSNs.js +0 -168
  377. package/server/record-us0YECMO.js +0 -3
  378. package/server/resume-OyN3dEXE.js +0 -3
  379. package/server/review-status-DXeqFpk5.js +0 -3
  380. package/server/settings-BaPXXJsT.js +0 -2
  381. package/server/specialists-C6WkeKFK.js +0 -3
  382. package/server/specs-BsNcum0h.js +0 -3
  383. package/server/state-migrate-_zJJ6XKE.js +0 -362
  384. package/server/supervisor-Qy1QecAs.js +0 -2
  385. package/server/tmux-HQLgwo_C.js +0 -3
  386. package/server/token-util-Cg-QnowA.js +0 -3
  387. package/server/workflows-C5c-RPsY.js +0 -2
package/server/server.js CHANGED
@@ -1,107 +1,110 @@
1
1
  import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "./rolldown-runtime-DNCzzKnI.js";
2
- import { $ as MODEL_CAPABILITIES, $n as resolveProjectFromIssueSync, $r as getLegacyHome, A as init_harness_policy, An as getIssuePrefix, At as init_record, B as init_providers, C as init_tier_table, D as validateTieredExecutionConfig, En as findProjectByPathSync, Er as TrackerError, Ft as readIssueRecordSync, Gr as SYNC_SOURCES, Hn as listProjects, I as getBuiltInDefaultHarness, J as DEFAULT_ROLES, Jn as registerProjectSync, Jr as getDocsBudgetStatePath, K as defaultBackgroundAiFeatures, L as getKimiAnthropicBaseUrl, Lr as LOGS_DIR, Nn as getProjectSync, O as canUseHarnessSync, On as findProjectByTeamSync, Or as init_errors, Ot as getIssueWorkspacePath, P as UnknownModelError, Pr as CLAUDE_DIR, Q as resolveModel, Qn as resolveProjectFromIssue, Rr as OVERDECK_HOME, S as TieredExecutionConfigError, Sn as ProjectRenameError, T as resolveTieredExecutionEnabled, Un as listProjectsSync, X as computeModelOrigin, Xr as getDocsIndexPath, Y as DEFAULT_WORKHORSES, Yn as renameProject, Yr as getDocsDisableStatePath, Zn as resolveInfraRepo, Zr as getDocsTelemetryPath, _ as getDefaultDocsConfig, ai as sessionFilePath, an as init_auto_commit, at as modelSupportsImagesSync, br as GitHubApiError, cr as extractPrefixSync, d as loadConfigNoMigration, dr as parseIssueIdSync, dt as PARENT_MODEL_REF, ei as getOverdeckHome, et as MODEL_DEPRECATIONS, f as loadConfigSync, ft as ROLE_EFFORTS, g as mergeConfigs, h as jsYaml, i as getConversationsConfig, in as flushAutoCommits, ir as setProjectSwarmPolicySync, it as init_model_capabilities, kr as AGENTS_DIR, lr as init_issue_id, m as init_js_yaml, mr as require_dist$1, n as clearConfigCache, ni as isDevMode, nt as getModelEffortLevelsSync, o as getGlobalConfigPath, ot as resolveModelIdSync, p as updateConversationsConfig, q as init_registry, qr as encodeClaudeProjectDir, r as getConversationSearchConfigSync, ri as packageRoot, rn as flushAllPendingAutoCommits, rr as setProjectAutoMergeDefaultSync, rt as hasModelCapabilitySync, s as init_load, t as init_config_yaml, ti as init_paths, u as isTldrEnabledSync, ut as COMPLIANCE_MODES, v as getDefaultTtsDaemonConfig, vr as FsError, w as resolveTieredExecutionBlock, wn as extractTeamPrefix, wr as ProcessSpawnError, y as mergeTtsDaemonConfigs, z as getProviderForModelSync, zn as init_projects } from "./config-yaml-Ciyp2mYe.js";
3
- import { a as shouldRefuseHostDashboardPort, i as readHostDashboardApiPort, n as getDashboardIdentity, r as isNonPrimaryCheckoutRoot } from "./deacon-nudge-log-C5VCKtyi.js";
4
- import { $ as runInBatches, A as handleConversationDelete, B as stopConversationRuntime, C as isPiControlChannelHarness, D as conversationNeedsRunningRepair, E as validateConversationControlAckOrigin, F as isInsideGitWorkTree, G as cleanupOrphanedConversationAttachments, H as waitForPiTuiReady, I as resolveAllowedHarness, J as extractConversationAttachmentPaths, K as cleanupUnreferencedConversationAttachments, L as shouldReportUnresolvedLiveSession, M as handleConversationResume, N as handleConversationStop, O as conversationSessionAliveFromState, P as handleConversationSwitchModel, Q as removeConversationAttachment, R as spawnConversationSession, S as handleConversationThinkingLevel, T as resolveConversationDeliveryMethod, U as waitForTmuxSession$1, V as tmuxSessionExists, W as cleanupConversationAttachments, X as hasConversationAttachment, Y as getConversationAttachmentsRoot, Z as isManagedConversationAttachmentPath, _ as handleConversationCodexApproval, _t as validateOrigin$1, a as agentsRouteLayer, at as panCliInvocation, b as handleConversationDeliveryMethod, bt as getDefaultCwd, c as hasDashboardInternalToken, ct as resolveAgentHarness, d as rejectUnsafeDashboardMutationRequest, dt as resolveJsonlPath, et as evaluateSpawnGuardrails, f as saveAgentStateAndEmitEvent, ft as resolvePiSessionPath, g as handleConversationAbort, gt as isTrustedOriginForHost, h as deliverConversationViaControlChannel, ht as getHeaderFromMap, j as handleConversationRestartAll, k as handleConversationCreate, l as rejectUnauthorizedDashboardRequest, lt as resolveClaudeSessionId, m as codexConversationPendingInput, mt as waitForSessionRespawn, nt as resolveAgentGitInfo, o as dashboardCsrfToken, p as saveAgentStateAndEmitEventProgram, pt as isRespawnPending, q as ensureConversationAttachmentDir, rt as resolveConversationGitInfo, s as dashboardSessionCookieHeader, st as readLauncherPinnedSessionId, t as specialistsRouteLayer, tt as invalidateAgentsCache, u as rejectUnauthorizedDashboardSessionMintRequest, ut as resolveCodexRolloutPath, v as handleConversationCompact, vt as validateOriginHeaders, w as pickDeliverAs, x as handleConversationPlanAction, xt as jsonResponse, y as handleConversationControlAck, yt as httpHandler, z as startConversationModelBackfill } from "./specialists-DAegTvRt.js";
2
+ import { A as canUseHarnessSync, Br as getOverdeckHome, Cr as LOGS_DIR, D as resolveTieredExecutionEnabled, E as resolveTieredExecutionBlock, Et as getIssueWorkspacePath, Fn as renameProject, Fr as getDocsDisableStatePath, Gr as sessionFilePath, H as init_providers, Hr as isDevMode, Ht as flushAutoCommits, I as UnknownModelError, Ir as getDocsIndexPath, J as defaultBackgroundAiFeatures, Jn as extractPrefixSync, Ln as resolveInfraRepo, Lr as getDocsTelemetryPath, M as init_harness_policy, Nr as encodeClaudeProjectDir, Nt as readIssueRecordSync, On as listProjects, Ot as init_record, Pn as registerProjectSync, Pr as getDocsBudgetStatePath, Q as computeModelOrigin, R as getBuiltInDefaultHarness, Rn as resolveProjectFromIssue, T as init_tier_table, Tn as init_projects, Un as setProjectAutoMergeDefaultSync, Ur as packageRoot, Ut as init_auto_commit, V as getProviderForModelSync, Vr as init_paths, Vt as flushAllPendingAutoCommits, Wn as setProjectSwarmPolicySync, X as DEFAULT_ROLES, Y as init_registry, Yn as init_issue_id, Z as DEFAULT_WORKHORSES, Zn as parseIssueIdSync, _ as getDefaultDocsConfig, at as getModelEffortLevelsSync, br as CLAUDE_DIR, cn as ProjectRenameError, ct as modelSupportsImagesSync, d as loadConfigNoMigration, er as require_dist$1, f as loadConfigSync, fn as findProjectByPathSync, fr as TrackerError, g as mergeConfigs, gn as getIssuePrefix, h as jsYaml, hr as AGENTS_DIR, ht as ROLE_EFFORTS, i as getConversationsConfig, ir as FsError, jr as SYNC_SOURCES, k as validateTieredExecutionConfig, kn as listProjectsSync, lt as resolveModelIdSync, m as init_js_yaml, mn as findProjectByTeamSync, mr as init_errors, mt as PARENT_MODEL_REF, n as clearConfigCache, nt as MODEL_CAPABILITIES, o as getGlobalConfigPath, or as GitHubApiError, ot as hasModelCapabilitySync, p as updateConversationsConfig, pt as COMPLIANCE_MODES, r as getConversationSearchConfigSync, rt as MODEL_DEPRECATIONS, s as init_load, st as init_model_capabilities, t as init_config_yaml, tt as resolveModel, u as isTldrEnabledSync, un as extractTeamPrefix, ur as ProcessSpawnError, v as getDefaultTtsDaemonConfig, w as TieredExecutionConfigError, wr as OVERDECK_HOME, y as mergeTtsDaemonConfigs, yn as getProjectSync, z as getKimiAnthropicBaseUrl, zn as resolveProjectFromIssueSync, zr as getLegacyHome } from "./config-yaml-DvyMuOle.js";
3
+ import { a as shouldRefuseHostDashboardPort, i as readHostDashboardApiPort, n as getDashboardIdentity, r as isNonPrimaryCheckoutRoot } from "./deacon-nudge-log-Bjg8U4Y9.js";
4
+ import { $ as runInBatches, A as handleConversationDelete, B as stopConversationRuntime, C as isPiControlChannelHarness, D as conversationNeedsRunningRepair, E as validateConversationControlAckOrigin, F as isInsideGitWorkTree, G as cleanupOrphanedConversationAttachments, H as waitForPiTuiReady, I as resolveAllowedHarness, J as extractConversationAttachmentPaths, K as cleanupUnreferencedConversationAttachments, L as shouldReportUnresolvedLiveSession, M as handleConversationResume, N as handleConversationStop, O as conversationSessionAliveFromState, P as handleConversationSwitchModel, Q as removeConversationAttachment, R as spawnConversationSession, S as handleConversationThinkingLevel, St as jsonStringResponse, T as resolveConversationDeliveryMethod, U as waitForTmuxSession$1, V as tmuxSessionExists, W as cleanupConversationAttachments, X as hasConversationAttachment, Y as getConversationAttachmentsRoot, Z as isManagedConversationAttachmentPath, _ as handleConversationCodexApproval, _t as validateOrigin$1, a as agentsRouteLayer, at as panCliInvocation, b as handleConversationDeliveryMethod, bt as getDefaultCwd, c as hasDashboardInternalToken, ct as resolveAgentHarness, d as rejectUnsafeDashboardMutationRequest, dt as resolveJsonlPath, et as evaluateSpawnGuardrails, f as saveAgentStateAndEmitEvent, ft as resolvePiSessionPath, g as handleConversationAbort, gt as isTrustedOriginForHost, h as deliverConversationViaControlChannel, ht as getHeaderFromMap, j as handleConversationRestartAll, k as handleConversationCreate, l as rejectUnauthorizedDashboardRequest, lt as resolveClaudeSessionId, m as codexConversationPendingInput, mt as waitForSessionRespawn, nt as resolveAgentGitInfo, o as dashboardCsrfToken, p as saveAgentStateAndEmitEventProgram, pt as isRespawnPending, q as ensureConversationAttachmentDir, rt as resolveConversationGitInfo, s as dashboardSessionCookieHeader, st as readLauncherPinnedSessionId, t as specialistsRouteLayer, tt as invalidateAgentsCache, u as rejectUnauthorizedDashboardSessionMintRequest, ut as resolveCodexRolloutPath, v as handleConversationCompact, vt as validateOriginHeaders, w as pickDeliverAs, x as handleConversationPlanAction, xt as jsonResponse, y as handleConversationControlAck, yt as httpHandler, z as startConversationModelBackfill } from "./specialists-JVO00bs7.js";
5
5
  import { a as init_activity_logger, i as emitDashboardLifecycleSync, n as emitActivityEntrySync, r as emitActivityTtsSync } from "./activity-logger-DDlOIAML.js";
6
- import { A as init_paths$1, O as OVERDECK_MIGRATION_PATH, f as init_infra, i as DbLive, k as getOverdeckDatabasePath, u as TmuxLive } from "./infra-DN2wSxle.js";
6
+ import { A as init_paths$1, O as OVERDECK_MIGRATION_PATH, f as init_infra, i as DbLive, k as getOverdeckDatabasePath, u as TmuxLive } from "./infra-CzaSOgul.js";
7
7
  import { n as openDatabase, t as init_driver } from "./driver-CKVGi51s.js";
8
- import { n as updateIssueRecord, t as init_record_update } from "./record-update-RviRDSNs.js";
9
- import { C as getWindowDimensions, D as killSession, I as resizeWindow, K as init_ui_theme, M as listSessions, R as sendKeys, T as isHarnessProcessAlive, V as sessionExists, X as buildChildEnvWithoutTmuxSync, Y as buildChildEnvSync, Z as init_child_env, d as ensureManagedTmuxContextOnce, i as capturePane, j as listSessionNames, k as listPaneValues, l as deliveryVerifyLine, n as buildTmuxArgs, o as capturePaneText, q as setUiTheme, s as createSession, w as init_tmux, z as sendKeysAsync } from "./tmux-y1blSxks.js";
10
- import { a as init_event_store, i as initEventStore, n as getEventStore } from "./event-store-BVnON3vf.js";
11
- import { _ as FlywheelRunId, a as getHarnessBehavior, b as DomainEvent, c as FlywheelStats, g as WS_METHODS, h as PanRpcGroup, m as PanRpcError, o as ContextLayerSaveRequest, s as ContextPreviewRequest, t as init_src, v as FlywheelStatus, x as MemoryObservation, y as EDITORS } from "./src-Dpq1yFIl.js";
12
- import { a as fixStuckReadyForMerge, c as init_review_status, i as fixStuckCommentedReviews, l as loadReadyForMergeFlags, n as clearReviewStatus, o as getReviewStatus, r as clearStuckMergeStatuses, s as getReviewStatusSync, u as loadReviewStatuses, v as setReviewStatus, y as setReviewStatusSync } from "./review-status-CCgPVK1h.js";
13
- import { a as EventStoreService, c as ReadModelService, d as init_read_model, f as toAgentResolution, i as init_issue_lifecycle, l as ReadModelServiceLive, m as toRole, n as IssueLifecycleLive, o as EventStoreServiceLive, p as toAgentStatus, s as init_domain_services, t as IssueLifecycle } from "./issue-lifecycle-B7HZWnTA.js";
14
- import { c as listAllAgentsSync, n as AgentsResolverLive, o as init_agents } from "./agents-DbrHWunF.js";
15
- import { i as init_paths$2, l as resolveObservationsFile, r as ensureParentDir, s as resolveIssueMemoryRoot, t as assertMemorySafeSegment } from "./paths-FP8v3lTz.js";
16
- import { i as recordBriefingSessionStart, n as ensureSessionContextBriefingFile, r as init_briefing_freshness, t as appendFreshBriefingUpdate } from "./briefing-freshness-OouGbJ7d.js";
17
- import { n as listFeatureRegistryEntries, t as init_feature_registry_storage } from "./feature-registry-storage-BWymOgXE.js";
18
- import { a as diffAgainstMain, c as diffCheckpoints, d as diffPatchSinceCommit, f as findCommitAtTime, h as listCheckpoints, l as diffFilesAgainstHead, m as init_checkpoint_manager, o as diffAgainstMainFiles, s as diffCheckpointFiles, t as captureCheckpoint, u as diffPatchFilesAgainstHead } from "./checkpoint-manager-D64fCC4p.js";
19
- import { An as getAgentStateFilePath, Ct as probeTranscriptSince, Dn as getAgentDir, Gn as saveAgentStateSync, Gt as getProviderAuthMode, It as resolveImplicitStaffing, Jt as injectPiConversationMemory, L as messageAgent, Pt as init_staffing, Qn as readAgentHarnessModelRecordSync, R as init_operator_interventions, St as init_transcript_landing, Zn as init_agent_record_sync, _r as init_codex_auth, a as listRunningAgentsSync, ar as normalizeAgentId, cr as waitForReadySignal, dn as getOpenAIAuthStatus, fn as init_openai_auth, gr as checkCodexAuthStatus, gt as deliverAgentMessage, i as listRunningAgents, it as emergencyBrake, jn as getAgentStateSync, kn as getAgentState, lr as getAgentRuntimeState, m as init_tier_supervisor, n as init_queries, nn as init_claude_auth, on as getProviderEnvForModel, ot as init_concurrency, p as deliverCommitForReview, r as listAgentStates, s as init_agents$1, tn as getClaudeAuthStatus, ur as getAgentRuntimeStateSync, v as supervisorAgentId, xt as captureTranscriptUserRecordSnapshot, z as operatorInterventionEvent } from "./queries-B5hl7lMQ.js";
20
- import { a as getCostForIssueAggregateSync, c as getDailyTrendsSync, d as init_cost_sync, l as getModelRollupSync, n as getBackgroundCostBySourceSync, p as queryCostEventsSync, r as getCavemanExperimentDataSync, s as getCostsByIssueSync, u as getTodayCostSync } from "./cost-sync-DzHP6zaR.js";
21
- import { c as getAgentsNeedingAttention, d as CostResolverLive, f as CostWriter, l as CostDoorLive, n as readCloisterStateFile, o as generateHealthSummary, s as getAgentHealth, t as getCloisterService, u as CostResolver } from "./service-CqAY8Kmk.js";
22
- import { t as init_behavior } from "./behavior-Dg-D8eBG.js";
23
- import { n as AgentStateServiceLive } from "./agent-state-service-6MFQqnFy.js";
24
- import { a as init_tracker_config, i as initTrackerConfigCache, n as getLinearApiKey, r as getRallyConfig, t as getGitHubConfig } from "./tracker-config-DSFZBdXP.js";
8
+ import { n as updateIssueRecord, t as init_record_update } from "./record-update-Dq0t2uBG.js";
9
+ import { $ as init_child_env, B as sendKeysAsync, C as getWindowDimensions, D as killSession, H as sessionExists, J as init_ui_theme, L as resizeWindow, M as listSessionNames, Q as buildChildEnvWithoutTmuxSync, T as isHarnessProcessAlive, Y as setUiTheme, Z as buildChildEnvSync, d as ensureManagedTmuxContextOnce, i as capturePane, l as deliveryVerifyLine, n as buildTmuxArgs, o as capturePaneText, s as createSession, w as init_tmux, z as sendKeys } from "./tmux-ftABRAmc.js";
10
+ import { a as init_event_store, i as initEventStore, n as getEventStore } from "./event-store-tdiY5eDZ.js";
11
+ import { D as AgentSnapshot, E as AgentRuntimeSnapshot, O as ReviewStatusSnapshot, S as SystemHealthSnapshot, _ as WS_METHODS, b as EDITORS, c as ContextPreviewRequest, g as PanRpcGroup, h as PanRpcError, l as FlywheelStats, n as compareIssueIds, o as getHarnessBehavior, s as ContextLayerSaveRequest, t as init_src, v as FlywheelRunId, w as MemoryObservation, x as DomainEvent, y as FlywheelStatus } from "./src-U7_kTPEE.js";
12
+ import { a as fixStuckCommentedReviews, b as setReviewStatusSync, c as getReviewStatusSync, d as loadReviewStatuses, l as init_review_status, n as clearReviewStatus, o as fixStuckReadyForMerge, p as markWorkspaceStuck, r as clearStuckMergeStatuses, s as getReviewStatus, u as loadReadyForMergeFlags, y as setReviewStatus } from "./review-status-A7quS5KJ.js";
13
+ import { a as EventStoreService, c as ReadModelService, d as init_read_model, f as toAgentResolution, i as init_issue_lifecycle, l as ReadModelServiceLive, m as toRole, n as IssueLifecycleLive, o as EventStoreServiceLive, p as toAgentStatus, s as init_domain_services, t as IssueLifecycle } from "./issue-lifecycle-CreaCkjW.js";
14
+ import { c as listAllAgentsSync, n as AgentsResolverLive, o as init_agents } from "./agents-B4Bjbkfv.js";
15
+ import { i as init_paths$2, l as resolveObservationsFile, r as ensureParentDir, s as resolveIssueMemoryRoot, t as assertMemorySafeSegment } from "./paths-_zEts6wc.js";
16
+ import { i as recordBriefingSessionStart, n as ensureSessionContextBriefingFile, r as init_briefing_freshness, t as appendFreshBriefingUpdate } from "./briefing-freshness-DWdW7vUm.js";
17
+ import { n as listFeatureRegistryEntries, t as init_feature_registry_storage } from "./feature-registry-storage-_wUBRD3J.js";
18
+ import { a as diffAgainstMain, c as diffCheckpoints, d as diffPatchSinceCommit, f as findCommitAtTime, h as listCheckpoints, l as diffFilesAgainstHead, m as init_checkpoint_manager, o as diffAgainstMainFiles, s as diffCheckpointFiles, t as captureCheckpoint, u as diffPatchFilesAgainstHead } from "./checkpoint-manager-DDqcGyu8.js";
19
+ import { Ar as init_codex_auth, Bn as getAgentDir, Cr as getAgentRuntimeStateSync, D as init_tier_supervisor, E as deliverCommitForReview, Ft as init_transcript_landing, Hn as getAgentState, It as probeTranscriptSince, Pt as captureTranscriptUserRecordSnapshot, Q as operatorInterventionEvent, Sr as getAgentRuntimeState, Tn as init_openai_auth, Wn as getAgentStateSync, X as messageAgent, Yt as resolveImplicitStaffing, Z as init_operator_interventions, _t as emergencyBrake, a as listRunningAgentsSync, b as init_agents$1, c as getRuntimeCensus, d as panePidsForSession, dr as readAgentHarnessModelRecordSync, f as refreshRuntimeCensus, hn as init_claude_auth, i as listRunningAgents, in as getProviderAuthMode, ir as saveAgentStateSync, j as supervisorAgentId, kr as checkCodexAuthStatus, kt as deliverAgentMessage, l as getRuntimeCensusSnapshot, mn as getClaudeAuthStatus, n as init_queries, p as runtimeCensusHasHarnessProcess, qt as init_staffing, r as listAgentStates, sn as injectPiConversationMemory, u as init_runtime_census, ur as init_agent_record_sync, vr as normalizeAgentId, wn as getOpenAIAuthStatus, xr as waitForReadySignal, yn as getProviderEnvForModel, yt as init_concurrency } from "./queries-6d7Cdtm7.js";
20
+ import { a as getCostForIssueAggregateSync, c as getDailyTrendsSync, d as init_cost_sync, l as getModelRollupSync, n as getBackgroundCostBySourceSync, p as queryCostEventsSync, r as getCavemanExperimentDataSync, s as getCostsByIssueSync, u as getTodayCostSync } from "./cost-sync-C0VdGme1.js";
21
+ import { c as getAgentsNeedingAttention, d as CostResolverLive, f as CostWriter, l as CostDoorLive, n as readCloisterStateFile, o as generateHealthSummary, s as getAgentHealth, t as getCloisterService, u as CostResolver } from "./service-DCpB_SGd.js";
22
+ import { u as init_agent_runtime_mirror } from "./session-history-CVZDpS3c.js";
23
+ import { t as init_behavior } from "./behavior-B_-4EKF3.js";
24
+ import { n as AgentStateServiceLive } from "./agent-state-service-HoK8U4jW.js";
25
+ import { a as init_tracker_config, i as initTrackerConfigCache, n as getLinearApiKey, r as getRallyConfig, t as getGitHubConfig } from "./tracker-config-B4itFzDo.js";
25
26
  import { d as init_typed_errors, i as PlanEmpty, l as WorkspaceCreateError, n as AgentStartError, s as TrackerApiError, t as AgentAlreadyRunning, u as WorkspaceNotFound } from "./typed-errors-2BTMxkZq.js";
26
- import { i as init_linear_client, r as LinearClientOptionalLive, t as LinearClient } from "./linear-client-BLyN-NiP.js";
27
- import { i as init_github_client, r as GitHubClientOptionalLive, t as GitHubClient } from "./github-client-Dslipypz.js";
28
- import { i as init_rally_client, r as RallyClientOptionalLive, t as RallyClient } from "./rally-client-SVbjGvqj.js";
29
- import { a as resolveTrackerTypeSync, i as resolveGitHubIssueSync, n as init_tracker_utils } from "./tracker-utils-DiceZN3a.js";
30
- import { a as CacheService, i as startSharedIssueService, n as init_issue_service_singleton, o as init_cache_service, r as issue_service_singleton_exports, s as parseIntegerHeader, t as getSharedIssueService } from "./issue-service-singleton-CPESc4Or.js";
31
- import { i as ensureInternalTokenSync, s as init_internal_token } from "./internal-token-DhfFiwW7.js";
32
- import { a as setPipelineHandlerSync, t as init_pipeline_notifier } from "./pipeline-notifier-BM2HLF7B.js";
33
- import { c as init_review_status_sync, i as getMergeBlockerReconcileCandidates } from "./review-status-sync-jnLgd04F.js";
34
- import { a as PAN_DIRNAME, d as WORKSPACE_RUNTIME_DIRNAME, f as asPanSpecDocument, i as PAN_CONTINUE_FILENAME, p as init_types } from "./types-DqeBMmJN.js";
35
- import { C as transitionToMerging, _ as markFailed, c as isFlywheelGloballyPaused, d as listDuePendingAutoMerges, f as listProblemAutoMerges, g as markBlocked, n as getActionableAutoMerge, o as init_merge_sync, t as cancelPending, u as listActiveAutoMerges, v as markMerged, x as scheduleAutoMergeWithResult, y as requeueToPending } from "./merge-sync-De1FYva5.js";
36
- import { C as init_specs, D as writeSpecDocument, O as writeSpecForIssue, a as findWorkspaceDraftPlan, m as readWorkspacePlanSync, o as init_io, p as readWorkspacePlan, r as findPlan, s as isPlanningComplete, u as readPlan, v as init_types$1, x as findSpecByIssue, y as subItemsOf } from "./io-BiM-7Zsx.js";
37
- import { C as restartCliproxy, S as readPidFile, T as stopCliproxy, b as isCliproxyInstalled, d as getCliproxyAuthDir, o as bridgeCodexAuthToCliproxy, v as init_cliproxy, w as startCliproxy, x as isCliproxyRunning, y as installCliproxy } from "./cliproxy-Dvsr4ZkW.js";
38
- import { $ as updateConversationForkFallbackReason, A as isAgentConversationName, B as removeFavorite, C as getConversationByTmuxSession, D as importLegacyConversation, F as markConversationEnded, H as setClearedToConvId, I as markConversationRunning, J as setForkRequest, M as listConversations, N as listFavoritedIds, O as incrementForkRetryCount, P as markConversationActive, S as getConversationByName, T as getStuckForks, U as setConversationClaudeSessionId, X as unarchiveConversation, Y as setImportedConversationLinks, Z as updateConversationCost, _ as canRefineTitle, b as getConversationByClaudeSessionId, et as updateConversationTitle, gt as getDiscoveredSessionBySessionId, h as archiveConversation, j as listArchivedConversationsWithEnrichment, k as init_conversations, q as setFavorite, tt as updateForkStatus, v as canReplaceTitle, w as getConversationLedgerCosts, x as getConversationById, y as createConversation, yt as init_discovered_sessions, z as recordConversationHandoff } from "./conversations-BUgGvqVL.js";
39
- import { n as isBackgroundFeatureEnabled, t as init_features } from "./features--fOza5g5.js";
40
- import { i as init_settings, r as getMemoryWorkerConcurrency, t as areMemoryObservationsEnabled } from "./settings-DP2OYLXL.js";
41
- import { i as updateMemoryHealth, n as extractWithProviderPolicy, r as init_health, t as init_providers$1 } from "./providers-d3pwXGVE.js";
42
- import { i as normalizeModelOverrideSync, n as init_launcher_generator, r as init_model_validation, t as generateLauncherScriptSync } from "./launcher-generator-5DJRiovn.js";
43
- import { a as init_claude_permissions, r as getClaudePermissionFlagsStringSync } from "./claude-permissions-C2OrLYKL.js";
44
- import { a as globalContextFile$1, f as resolveProjectContextFile, h as workspaceContextFile, n as codexGlobalContextFile, o as init_layers, p as resolveWorkspaceContextFile, r as ensureProjectLayer } from "./layers-cZx7ibtV.js";
45
- import { l as init_codex, s as findRolloutPath } from "./codex-D_UBEOwL.js";
46
- import { f as init_config, m as loadConfigSync$1, s as getDashboardApiUrlSync } from "./config-CrduXs4a.js";
47
- import { C as setMergeTrainEnabled, S as setFlywheelRequireUatBeforeMerge, b as setFlywheelAutoPickupBacklog, c as isCloisterSpawnsPausedSync, d as isFlywheelAutoPickupBacklog, f as isFlywheelGloballyPaused$1, g as setCloisterSpawnsPausedSync, h as setBootReconciliationDecision, m as isMergeTrainEnabled, o as getSetting, p as isFlywheelRequireUatBeforeMerge, r as getBootReconciliationState, s as init_control_settings, u as isDeaconGloballyPausedSync, v as setDeaconGloballyPausedSync, w as setSetting } from "./control-settings-D_79A6gp.js";
48
- import { l as init_dag, r as compileGlob } from "./dag-DIji6O2b.js";
49
- import { a as loadCloisterConfigSync, i as loadCloisterConfig, o as saveCloisterConfigSync, r as init_config$1, s as shouldAutoStart } from "./config-G1TOMJZA.js";
50
- import { c as isStateMigrated, i as ensureStateWorktree, o as init_state_home, r as clearStateMigrationCache, s as inspectStateMigration } from "./state-home-DixkE-up.js";
51
- import { i as checkPrdGateSync, t as init_pan_dir } from "./pan-dir-Rw17YjT1.js";
52
- import { a as init_lifecycle_io, t as appendContinueSessionEntryForIssue } from "./lifecycle-io-DMurK4oM.js";
53
- import { r as init_swarm_readiness, t as analyzeSwarmReadiness } from "./swarm-readiness-C9P2iPap.js";
54
- import { n as require_auth_errors, r as require_token_error, t as require_token_util } from "./token-util-BZaDAQ8S.js";
55
- import { _ as init_codex_conversation_parser, a as contextUsageFromParseResult, c as parseEntireConversation, d as init_pi_conversation_parser, f as isPiSessionFile, g as parseOhmypiConversationMessages, h as isOhmypiSessionFile, i as computeContextUsage, l as parseFromLastCompactBoundary, m as init_ohmypi_conversation_parser, n as gateSnapshotEmission, o as summarizeConversationActivity, p as parsePiConversationMessages, r as watchConversation, s as parseConversationMessages, t as init_conversation_service, v as parseCodexConversationMessages } from "./conversation-service-DQybSPUK.js";
56
- import { c as countPendingAskUserQuestionsForAgent, h as detectAwaitingInputFromPaneSync, l as getAgentJsonlMtime, m as detectAwaitingInputForAgent, o as getRuntimeForAgent, p as scanPendingInputsPromise, s as computeAgentEnrichment } from "./stuck-remediation-BWkK_O7A.js";
57
- import { i as CostThresholdError, l as embed, s as parseRelativeTime } from "./scanner-C4NeC4FE.js";
58
- import { c as tailEventsSync, n as deduplicateEventsSync, o as readEventsSync } from "./events-CmERlnwn.js";
59
- import { n as recordBackgroundAiCost, t as init_cost } from "./cost-jJ2cgDcG.js";
60
- import { a as getByIssueId, i as parseFlywheelStatsWindow, n as derivePipelineRunStatsInputs, o as markFixed, r as computeFlywheelStats, s as upsert } from "./substrate-bug-weights-service-DXd0ID83.js";
61
- import { c as startUatTrainReconciler, d as openFlywheelRunReportForDashboard, f as pauseFlywheelRunForDashboard, g as runDashboardDbJob, h as startFlywheelRunForDashboard, l as stopUatTrainReconciler, m as resumeFlywheelRunForDashboard, p as readCurrentFlywheelStatusForDashboard, u as abortFlywheelRunForDashboard } from "./uat-train-BpLnp7Cx.js";
62
- import { C as writeLatestFlywheelStatus, b as resolveLiveFlywheelRunId, g as listFlywheelRuns, h as isFlywheelRunId, p as getFlywheelRunDetail, u as buildClassifyLookups, v as readCurrentLatestFlywheelStatus, x as subscribeLatestFlywheelStatus } from "./flywheel-1Wd8WDlh.js";
63
- import { C as getWorkspacePathForIssue, S as resolveIssueHeadlineCost, _ as getCostsForIssueSync, b as processPendingFeedbackDeliveries, d as resumeQueuedMerges, f as syncWalFromAllProjects, g as migrateAllSessionsSync, h as reclassifyUnknownCostEventsSync, l as internalEventsRouteLayer, m as reconcilePiTranscripts, p as reconcile$1, t as workspacesRouteLayer, u as eventsRouteLayer, v as rebuildCacheSync, x as getCachedRunningAgents, y as syncCacheSync } from "./workspaces-Dmlh1YXm.js";
64
- import { At as getSystemHealthSnapshot, Dt as getContainerHistory, Et as formatUptime, F as setAgentStatusChangedNotifier, G as isBootReconciliationCandidate, I as setAgentStoppedNotifier, K as listBootReconciliationCandidates, L as setMergeReadyNotifier, Mt as startSmeeProcessSync, O as loadConfig, Ot as getCurrentDockerStats, Tt as getResourceStacks, jt as isSmeeConfiguredSync, k as loadState, n as assessDeaconPatrolFreshness, q as startBootReconciliation, t as applyBootReconciliationDecision, x as getDeaconLogs, xt as paneShowsClaudeBootBlockingScreen } from "./deacon-1s7bM5zn.js";
65
- import { l as detectPlatform, u as init_platform } from "./workspace-manager-DsN52IMG.js";
66
- import { a as writeFeedbackFile, i as init_feedback_writer } from "./feedback-writer-Wlq5-qgS.js";
67
- import { r as init_in_flight_guard, t as createInFlightGuard } from "./in-flight-guard-tVGiI5ee.js";
68
- import { t as init_specialists, z as getReviewerSessionName } from "./specialists-CYRwELzc.js";
69
- import { c as findPrdAtStatusSync, l as init_prd_locations } from "./archive-planning-BOnwJq8M.js";
70
- import { a as getShadowState, s as init_shadow_state } from "./shadow-state-a_ztFBJe.js";
71
- import { A as withConcurrencyLimit, D as createPromiseConcurrencyLimiter, E as verifyAppCanMerge, O as createSettledTtlPromiseCache, d as getPullRequestState, f as init_github_app, k as init_concurrency$1, l as getMergeBackendStatus, p as isGitHubAppConfigured } from "./github-app-B3yfECo8.js";
72
- import { n as init_issue_closed, t as clearIssueClosedCache } from "./issue-closed-Dfw3QDyZ.js";
73
- import { b as resolveSwarmPolicy } from "./deacon-swarm-DmA3rJ7k.js";
74
- import { a as init_boot_gates, i as formatBootGateState, o as resolveBootGates } from "./no-resume-mode-BnInAFKs.js";
75
- import { c as computeCohort, d as computeStats, f as computeWaves, g as selectNeedsPlanning, h as normalizeGate, l as computeEpicGroups, p as init_pickup, s as classifyIssue, u as computeLanes } from "./pickup-xi3KTLaJ.js";
76
- import { a as applyIssueObjectionLabel, c as applyIssueReleasedLabel, d as removeIssueBlocksMainLabel, f as removeIssueObjectionLabel, g as removeIssueVetoedLabel, h as removeIssueReleasedLabel, i as applyIssueBlocksMainLabel, l as applyIssueVetoedLabel, m as removeIssueReadyLabel, o as applyIssueParkedLabel, p as removeIssueParkedLabel, s as applyIssueReadyLabel, u as init_label_ops } from "./label-reconciler-CNf3Ylm3.js";
77
- import { n as parseSequenceMd, r as writeSequenceMd, t as init_sequence_io } from "./sequence-io-Ce-6grIY.js";
78
- import { a as init_pipeline_membership_gather, c as parseIssueIdFromTextSync, n as resolvePipelineMembership, o as listOpenPullRequestsSnapshot, r as gatherProjectLensSignals, s as init_resource_utils, t as init_pipeline_membership } from "./pipeline-membership-BtKMNY7v.js";
79
- import { a as loadWorkspaceMetadataSync } from "./workspace-metadata-DIL5_U4c.js";
80
- import { i as resolveAutoSpawnOnFinalize, o as spawnPlanningSession } from "./spawn-planning-session-AiUSsBnH.js";
81
- import { d as killRemoteAgent, m as loadRemoteAgentState, o as getRemoteAgentOutput, r as checkRemoteSpendCap, s as init_remote_agents, v as sendToRemoteAgent, y as spawnRemoteAgent } from "./remote-agents-CZ2rc8I0.js";
82
- import { r as spawnInspectAgent } from "./inspect-agent-DKByUS_F.js";
83
- import { n as init_github_pr_lookup, r as lookupPullRequestNumberForBranch, t as githubPrLookupSource } from "./github-pr-lookup-DBP0YHMr.js";
84
- import { a as fetchIssuePullRequestDiff, c as getCachedIssuePrTabResponse, d as setCachedIssuePrTabResponse, i as fetchIssuePullRequestDetails, l as getIssuePrTabCacheGeneration, n as fetchIssueCheckRuns, o as init_pull_requests, r as fetchIssuePullRequest, s as bumpIssuePrTabCacheGeneration, u as init_pr_tab_cache } from "./pull-requests-CjjPj7v6.js";
85
- import { t as DOD_ROWS } from "./dod-BLphkhjs.js";
86
- import { t as enrichReviewStatus } from "./review-status-enrichment-DtDRGpst.js";
87
- import { i as runMemoryFtsTransaction, n as init_fts_db, r as runMemoryFtsStatement, t as closeMemoryFtsDatabases } from "./fts-db-6ponMie2.js";
88
- import { c as init_pending, l as maybeTriggerStatusRollup, o as readRecentObservations, r as init_rollup, u as writePendingTurn } from "./rollup-CLj_AK9f.js";
89
- import { n as getTldrDaemonServiceSync, r as init_tldr_daemon } from "./tldr-daemon-DjxP5g6Y.js";
90
- import { T as listGitOperationsSync, w as init_git_activity } from "./merge-agent-DnBsms_V.js";
91
- import { t as readVerificationArtifact } from "./verification-artifact-Dr_0g9nb.js";
92
- import { t as getAgentCommandSync } from "./settings-D9grjmaP.js";
93
- import { n as init_review_agent, r as isExtendedReviewEnabled } from "./review-agent-CqSqSHkU.js";
94
- import { r as isRemoteAvailable, t as createFlyProviderFromConfig } from "./remote-cnoeuDWn.js";
95
- import { n as init_claude_settings_overlay, t as detectProviderEnvConflicts } from "./claude-settings-overlay-DX-fMFpC.js";
96
- import { a as init_query_expansion, i as clearQueryExpansionCache, n as init_injection, o as buildMatchQuery, r as injectPromptTimeMemory, s as init_search } from "./injection-DtlT8Akv.js";
97
- import { _ as init_transcript_adapter, a as generateFallbackSummary, c as handoffPreconditionFallbackReason, d as prependFallbackFocus, f as requestHandoffFromAgent, g as getTranscriptAdapter, i as copySessionFromCompactBoundary, l as init_summary_fork, o as generateSummaryForFork, p as reserveSummaryForkSession, r as authorHandoffExternal, s as handoffFailureReason, u as logHandoffFallback } from "./summary-fork-f3DpgjXh.js";
98
- import { a as init_conversation_compaction, c as shouldInterceptManualCompact, n as compactConversationNative, o as isCompacting } from "./conversation-compaction-DiuZbIUB.js";
99
- import { a as init_render, d as validateTemplate, i as hasManagedRegion, l as init_harness, o as userContentOutsideRegion, t as init_context_layers, u as renderForHarness } from "./context-layers-Cg9ZgVfx.js";
100
- import { r as parseArtifactRef } from "./forge-DBbDpiYc.js";
101
- import { t as getMergeBlockersPayload } from "./merge-blockers-DhRgh76x.js";
102
- import { a as spawnSequencerAgent, i as init_sequencer_agent, n as clearFinishedSequencerRun, r as getSequencerRunStatus, t as SEQUENCER_AGENT_ID } from "./sequencer-agent-Bpz0yGmG.js";
103
- import "./supervisor-Ch8CDuoF.js";
104
- import { i as listTranscriptCheckpoints, r as getTranscriptCheckpoint$1 } from "./checkpoints-Vh-J15ge.js";
27
+ import { i as init_linear_client, r as LinearClientOptionalLive, t as LinearClient } from "./linear-client-D4zqMnX7.js";
28
+ import { i as init_github_client, r as GitHubClientOptionalLive, t as GitHubClient } from "./github-client--XVlDpwM.js";
29
+ import { i as init_rally_client, r as RallyClientOptionalLive, t as RallyClient } from "./rally-client-B1EJhfV0.js";
30
+ import { a as resolveTrackerTypeSync, i as resolveGitHubIssueSync, n as init_tracker_utils } from "./tracker-utils-tnxxqROg.js";
31
+ import { a as CacheService, i as startSharedIssueService, n as init_issue_service_singleton, o as init_cache_service, r as issue_service_singleton_exports, s as parseIntegerHeader, t as getSharedIssueService } from "./issue-service-singleton-B5ushCvE.js";
32
+ import { i as ensureInternalTokenSync, o as getInternalTokenSync, s as init_internal_token, t as INTERNAL_TOKEN_HEADER } from "./internal-token-Bb4XeV2x.js";
33
+ import { a as setPipelineHandlerSync, t as init_pipeline_notifier } from "./pipeline-notifier-D0ykk59O.js";
34
+ import { c as init_review_status_sync, i as getMergeBlockerReconcileCandidates } from "./review-status-sync-BhSQ0d0l.js";
35
+ import { n as init_review_status_source, t as classifyAdvancingSessionLifecycle } from "./review-status-source-CxuEjLGg.js";
36
+ import { a as PAN_DIRNAME, d as WORKSPACE_RUNTIME_DIRNAME, f as asPanSpecDocument, i as PAN_CONTINUE_FILENAME, p as init_types } from "./types-hraoaQIp.js";
37
+ import { C as transitionToMerging, _ as markFailed, c as isFlywheelGloballyPaused, d as listDuePendingAutoMerges, f as listProblemAutoMerges, g as markBlocked, n as getActionableAutoMerge, o as init_merge_sync, t as cancelPending, u as listActiveAutoMerges, v as markMerged, x as scheduleAutoMergeWithResult, y as requeueToPending } from "./merge-sync-DZ9dojJn.js";
38
+ import { C as init_specs, D as writeSpecDocument, O as writeSpecForIssue, a as findWorkspaceDraftPlan, m as readWorkspacePlanSync, o as init_io, p as readWorkspacePlan, r as findPlan, s as isPlanningComplete, u as readPlan, v as init_types$1, x as findSpecByIssue, y as subItemsOf } from "./io-B3_AHDfr.js";
39
+ import { C as restartCliproxy, S as readPidFile, T as stopCliproxy, b as isCliproxyInstalled, d as getCliproxyAuthDir, o as bridgeCodexAuthToCliproxy, v as init_cliproxy, w as startCliproxy, x as isCliproxyRunning, y as installCliproxy } from "./cliproxy-Bgb2XCqi.js";
40
+ import { $ as updateConversationForkFallbackReason, A as isAgentConversationName, B as removeFavorite, C as getConversationByTmuxSession, D as importLegacyConversation, F as markConversationEnded, H as setClearedToConvId, I as markConversationRunning, J as setForkRequest, M as listConversations, N as listFavoritedIds, O as incrementForkRetryCount, P as markConversationActive, S as getConversationByName, T as getStuckForks, U as setConversationClaudeSessionId, X as unarchiveConversation, Y as setImportedConversationLinks, Z as updateConversationCost, _ as canRefineTitle, b as getConversationByClaudeSessionId, et as updateConversationTitle, gt as getDiscoveredSessionBySessionId, h as archiveConversation, j as listArchivedConversationsWithEnrichment, k as init_conversations, q as setFavorite, tt as updateForkStatus, v as canReplaceTitle, w as getConversationLedgerCosts, x as getConversationById, y as createConversation, yt as init_discovered_sessions, z as recordConversationHandoff } from "./conversations-DbOs1e9Q.js";
41
+ import { n as isBackgroundFeatureEnabled, t as init_features } from "./features-Dhxz-wLc.js";
42
+ import { i as init_settings, r as getMemoryWorkerConcurrency, t as areMemoryObservationsEnabled } from "./settings-BZ5m1UCl.js";
43
+ import { i as updateMemoryHealth, n as extractWithProviderPolicy, r as init_health, t as init_providers$1 } from "./providers-DV7ec8l7.js";
44
+ import { i as normalizeModelOverrideSync, n as init_launcher_generator, r as init_model_validation, t as generateLauncherScriptSync } from "./launcher-generator-CHVm7bGT.js";
45
+ import { a as init_claude_permissions, r as getClaudePermissionFlagsStringSync } from "./claude-permissions-H_5wHQZQ.js";
46
+ import { a as globalContextFile$1, f as resolveProjectContextFile, h as workspaceContextFile, n as codexGlobalContextFile, o as init_layers, p as resolveWorkspaceContextFile, r as ensureProjectLayer } from "./layers-DzxSTGNA.js";
47
+ import { l as init_codex, s as findRolloutPath } from "./codex-TmSi-yTv.js";
48
+ import { n as init_harness_binary, r as prepareHarnessLaunch } from "./harness-binary-CVio2m-u.js";
49
+ import { f as init_config, m as loadConfigSync$1, s as getDashboardApiUrlSync } from "./config-CCvjQf27.js";
50
+ import { C as setMergeTrainEnabled, S as setFlywheelRequireUatBeforeMerge, b as setFlywheelAutoPickupBacklog, c as isCloisterSpawnsPausedSync, d as isFlywheelAutoPickupBacklog, f as isFlywheelGloballyPaused$1, g as setCloisterSpawnsPausedSync, h as setBootReconciliationDecision, m as isMergeTrainEnabled, o as getSetting, p as isFlywheelRequireUatBeforeMerge, r as getBootReconciliationState, s as init_control_settings, u as isDeaconGloballyPausedSync, v as setDeaconGloballyPausedSync, w as setSetting } from "./control-settings-aP1ANIlI.js";
51
+ import { l as init_dag, r as compileGlob } from "./dag-CdOjJVDT.js";
52
+ import { a as loadCloisterConfigSync, o as saveCloisterConfigSync, r as init_config$1, s as shouldAutoStart } from "./config-DjLOdbgT.js";
53
+ import { c as isStateMigrated, i as ensureStateWorktree, o as init_state_home, r as clearStateMigrationCache, s as inspectStateMigration } from "./state-home-CIGjwNfJ.js";
54
+ import { i as checkPrdGateSync, s as promoteWorkspacePrdDraft, t as init_pan_dir } from "./pan-dir-DeVUgwA7.js";
55
+ import { a as init_lifecycle_io, t as appendContinueSessionEntryForIssue } from "./lifecycle-io-D8iNBcux.js";
56
+ import { r as init_swarm_readiness, t as analyzeSwarmReadiness } from "./swarm-readiness-CQ_fwUWF.js";
57
+ import { n as require_auth_errors, r as require_token_error, t as require_token_util } from "./token-util-CTmczIfW.js";
58
+ import { A as withConcurrencyLimit, D as createPromiseConcurrencyLimiter, E as verifyAppCanMerge, O as createSettledTtlPromiseCache, d as getPullRequestState, f as init_github_app, k as init_concurrency$1, l as getMergeBackendStatus, p as isGitHubAppConfigured } from "./github-app-CMBdIFBQ.js";
59
+ import { C as getWorkspacePathForIssue, E as stopAgentOutputService, S as resolveIssueHeadlineCost, T as startAgentOutputService, _ as getCostsForIssueSync, b as processPendingFeedbackDeliveries, d as resumeQueuedMerges, f as syncWalFromAllProjects, g as migrateAllSessionsSync, h as reclassifyUnknownCostEventsSync, l as internalEventsRouteLayer, m as reconcilePiTranscripts, p as reconcile$1, t as workspacesRouteLayer, u as eventsRouteLayer, v as rebuildCacheSync, w as retainAgentOutputInterest, x as getCachedRunningAgents, y as syncCacheSync } from "./workspaces-hWvy9eKs.js";
60
+ import { _ as init_codex_conversation_parser, a as contextUsageFromParseResult, c as parseEntireConversation, d as init_pi_conversation_parser, f as isPiSessionFile, g as parseOhmypiConversationMessages, h as isOhmypiSessionFile, i as computeContextUsage, l as parseFromLastCompactBoundary, m as init_ohmypi_conversation_parser, n as gateSnapshotEmission, o as summarizeConversationActivity, p as parsePiConversationMessages, r as watchConversation, s as parseConversationMessages, t as init_conversation_service, v as parseCodexConversationMessages } from "./conversation-service-Du-MTNpJ.js";
61
+ import { c as countPendingAskUserQuestionsForAgent, h as detectAwaitingInputFromPaneSync, l as getAgentJsonlMtime, m as detectAwaitingInputForAgent, o as getRuntimeForAgent, p as scanPendingInputsPromise, s as computeAgentEnrichment } from "./stuck-remediation-CzEov_fq.js";
62
+ import { i as CostThresholdError, l as embed, s as parseRelativeTime } from "./scanner-D2743cp8.js";
63
+ import { c as tailEventsSync, n as deduplicateEventsSync, o as readEventsSync } from "./events-CC1dgUpx.js";
64
+ import { n as recordBackgroundAiCost, t as init_cost } from "./cost-CW4WSe72.js";
65
+ import { a as getByIssueId, i as parseFlywheelStatsWindow, n as derivePipelineRunStatsInputs, o as markFixed, r as computeFlywheelStats, s as upsert } from "./substrate-bug-weights-service-BH66lhm7.js";
66
+ import { c as startUatTrainReconciler, d as openFlywheelRunReportForDashboard, f as pauseFlywheelRunForDashboard, g as runDashboardDbJob, h as startFlywheelRunForDashboard, l as stopUatTrainReconciler, m as resumeFlywheelRunForDashboard, p as readCurrentFlywheelStatusForDashboard, u as abortFlywheelRunForDashboard } from "./uat-train-CuEn0t9M.js";
67
+ import { C as writeLatestFlywheelStatus, b as resolveLiveFlywheelRunId, g as listFlywheelRuns, h as isFlywheelRunId, p as getFlywheelRunDetail, u as buildClassifyLookups, v as readCurrentLatestFlywheelStatus, x as subscribeLatestFlywheelStatus } from "./flywheel-DSSpWmqF.js";
68
+ import { At as getContainerHistory, Ct as paneShowsClaudeBootBlockingScreen, F as setAgentStatusChangedNotifier, Ft as getSystemHealthEvidenceSnapshot, I as setAgentStoppedNotifier, J as startBootReconciliation, K as isBootReconciliationCandidate, L as setMergeReadyNotifier, Lt as isSmeeConfiguredSync, Mt as getAcceptedSystemHealthSnapshot, Nt as getDeployStaleness, O as loadConfig, Ot as getResourceStacks, Rt as startSmeeProcessSync, jt as getCurrentDockerStats, k as loadState, kt as formatUptime, n as assessDeaconPatrolFreshness, q as listBootReconciliationCandidates, t as applyBootReconciliationDecision, x as getDeaconLogs, zt as classifyAgentHealth } from "./deacon-pRnyD5w9.js";
69
+ import { l as detectPlatform, u as init_platform } from "./workspace-manager-hLUv3ADC.js";
70
+ import { a as writeFeedbackFile, i as init_feedback_writer } from "./feedback-writer-C9b6ccN1.js";
71
+ import { r as init_in_flight_guard, t as createInFlightGuard } from "./in-flight-guard-aQ1IxeI3.js";
72
+ import { V as getReviewerSessionName, t as init_specialists } from "./specialists-DyFeedjn.js";
73
+ import { c as findPrdAnywhereSync, l as init_prd_locations } from "./archive-planning-DYrYojxl.js";
74
+ import { a as getShadowState, s as init_shadow_state } from "./shadow-state-Dh-HzF2J.js";
75
+ import { n as init_issue_closed, t as clearIssueClosedCache } from "./issue-closed-zhdvQicO.js";
76
+ import { b as resolveSwarmPolicy } from "./deacon-swarm-DftYRDo8.js";
77
+ import { a as init_boot_gates, i as formatBootGateState, o as resolveBootGates } from "./no-resume-mode-Cx3K0hHi.js";
78
+ import { _ as selectNeedsPlanning, c as classifyIssue, d as computeLanes, f as computeStats, g as normalizeGate, l as computeCohort, m as init_pickup, p as computeWaves, u as computeEpicGroups } from "./pickup-Dd0Znxxy.js";
79
+ import { a as applyIssueObjectionLabel, c as applyIssueReleasedLabel, d as removeIssueBlocksMainLabel, f as removeIssueObjectionLabel, g as removeIssueVetoedLabel, h as removeIssueReleasedLabel, i as applyIssueBlocksMainLabel, l as applyIssueVetoedLabel, m as removeIssueReadyLabel, o as applyIssueParkedLabel, p as removeIssueParkedLabel, s as applyIssueReadyLabel, u as init_label_ops } from "./label-reconciler-DdWbHEBu.js";
80
+ import { n as parseSequenceMd, r as writeSequenceMd, t as init_sequence_io } from "./sequence-io-Cg0zYj_E.js";
81
+ import { c as init_resource_utils, i as gatherProjectLensSignals, l as parseIssueIdFromTextSync, n as init_pipeline_membership, o as init_pipeline_membership_gather, r as resolvePipelineMembership, s as listOpenPullRequestsSnapshot } from "./pipeline-membership-0HaEGDlH.js";
82
+ import { a as loadWorkspaceMetadataSync } from "./workspace-metadata-CskwzzhL.js";
83
+ import { i as resolveAutoSpawnOnFinalize, o as spawnPlanningSession } from "./spawn-planning-session-DWAorh2B.js";
84
+ import { d as killRemoteAgent, m as loadRemoteAgentState, o as getRemoteAgentOutput, r as checkRemoteSpendCap, s as init_remote_agents, v as sendToRemoteAgent, y as spawnRemoteAgent } from "./remote-agents-nmty1mLu.js";
85
+ import { r as spawnInspectAgent } from "./inspect-agent-DJKLWcVT.js";
86
+ import { n as init_github_pr_lookup, r as lookupPullRequestNumberForBranch, t as githubPrLookupSource } from "./github-pr-lookup-BRbDW-qk.js";
87
+ import { a as fetchIssuePullRequestDiff, c as getCachedIssuePrTabResponse, d as setCachedIssuePrTabResponse, i as fetchIssuePullRequestDetails, l as getIssuePrTabCacheGeneration, n as fetchIssueCheckRuns, o as init_pull_requests, r as fetchIssuePullRequest, s as bumpIssuePrTabCacheGeneration, u as init_pr_tab_cache } from "./pull-requests-CXIhdCYD.js";
88
+ import { t as DOD_ROWS } from "./dod-BrSfUHm0.js";
89
+ import { t as enrichReviewStatus } from "./review-status-enrichment-tbOn_A_u.js";
90
+ import { i as runMemoryFtsTransaction, n as init_fts_db, r as runMemoryFtsStatement, t as closeMemoryFtsDatabases } from "./fts-db-CKgg0VKg.js";
91
+ import { c as init_pending, l as maybeTriggerStatusRollup, o as readRecentObservations, r as init_rollup, u as writePendingTurn } from "./rollup-WA0VD-Rr.js";
92
+ import { n as getTldrDaemonServiceSync, r as init_tldr_daemon } from "./tldr-daemon-BDtLOIlO.js";
93
+ import { T as listGitOperationsSync, w as init_git_activity } from "./merge-agent-XrB80vfT.js";
94
+ import { t as readVerificationArtifact } from "./verification-artifact-BcnIbigL.js";
95
+ import { t as getAgentCommandSync } from "./settings-ylxwqwQG.js";
96
+ import { n as init_review_agent, r as isExtendedReviewEnabled } from "./review-agent-sKkE1FEL.js";
97
+ import { r as isRemoteAvailable, t as createFlyProviderFromConfig } from "./remote-Br-ZWVIP.js";
98
+ import { n as init_claude_settings_overlay, t as detectProviderEnvConflicts } from "./claude-settings-overlay-CbSz0Dvb.js";
99
+ import { a as init_query_expansion, i as clearQueryExpansionCache, n as init_injection, o as buildMatchQuery, r as injectPromptTimeMemory, s as init_search } from "./injection-DZ0PfYa4.js";
100
+ import { _ as init_transcript_adapter, a as generateFallbackSummary, c as handoffPreconditionFallbackReason, d as prependFallbackFocus, f as requestHandoffFromAgent, g as getTranscriptAdapter, i as copySessionFromCompactBoundary, l as init_summary_fork, o as generateSummaryForFork, p as reserveSummaryForkSession, r as authorHandoffExternal, s as handoffFailureReason, u as logHandoffFallback } from "./summary-fork-DHhJIsAL.js";
101
+ import { a as init_conversation_compaction, c as shouldInterceptManualCompact, n as compactConversationNative, o as isCompacting } from "./conversation-compaction-CNbTLB86.js";
102
+ import { a as init_render, d as validateTemplate, i as hasManagedRegion, l as init_harness, o as userContentOutsideRegion, t as init_context_layers, u as renderForHarness } from "./context-layers-ZYFcWiyc.js";
103
+ import { r as parseArtifactRef } from "./forge-Ch9gCFod.js";
104
+ import { t as getMergeBlockersPayload } from "./merge-blockers-BsFjGrQ8.js";
105
+ import { a as spawnSequencerAgent, i as init_sequencer_agent, n as clearFinishedSequencerRun, r as getSequencerRunStatus, t as SEQUENCER_AGENT_ID } from "./sequencer-agent-BGY8gjg-.js";
106
+ import "./supervisor-BO-Zk_h-.js";
107
+ import { i as listTranscriptCheckpoints, r as getTranscriptCheckpoint$1 } from "./checkpoints-C-AXLfYT.js";
105
108
  import { createRequire } from "node:module";
106
109
  import * as sp from "node:path";
107
110
  import { basename, delimiter, dirname, extname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
@@ -109,7 +112,7 @@ import { Cause, Context, Data, Duration, Effect, Exit, Fiber, FileSystem, Layer,
109
112
  import { createReadStream, createWriteStream, existsSync, fstatSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
110
113
  import { basename as basename$1, dirname as dirname$1, join as join$1, resolve as resolve$1 } from "path";
111
114
  import { homedir } from "os";
112
- import { freemem as freemem$1, homedir as homedir$1, loadavg as loadavg$1, totalmem as totalmem$1, type } from "node:os";
115
+ import { homedir as homedir$1, type } from "node:os";
113
116
  import { constants, createReadStream as createReadStream$1, existsSync as existsSync$1, mkdirSync as mkdirSync$1, promises as promises$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, readlinkSync, renameSync as renameSync$1, rmSync as rmSync$1, stat, statSync as statSync$1, symlinkSync as symlinkSync$1, unwatchFile, watch, watchFile } from "node:fs";
114
117
  import { FetchHttpClient, HttpRouter, HttpServer, HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
115
118
  import { EventEmitter } from "node:events";
@@ -355,6 +358,24 @@ const ServerConfigLayer = Layer.effect(ServerConfig, Effect.sync(() => {
355
358
  };
356
359
  }));
357
360
  //#endregion
361
+ //#region dashboard-listening.ts
362
+ let resolveListening;
363
+ let listening = false;
364
+ let listeningPromise = createListeningPromise();
365
+ function createListeningPromise() {
366
+ return new Promise((resolve) => {
367
+ resolveListening = resolve;
368
+ });
369
+ }
370
+ function markDashboardListening() {
371
+ if (listening) return;
372
+ listening = true;
373
+ resolveListening();
374
+ }
375
+ function whenDashboardListening() {
376
+ return listeningPromise;
377
+ }
378
+ //#endregion
358
379
  //#region services/terminal-service.ts
359
380
  init_activity_logger();
360
381
  init_paths$1();
@@ -688,7 +709,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
688
709
  if (!existsSync$1(workspacePath)) throw new WorkspaceNotFound({ id: issueId });
689
710
  const plan = readWorkspacePlanSync(workspacePath);
690
711
  if (!plan || plan.plan.items.length === 0) throw new PlanEmpty({ id: issueId });
691
- const { getAgentState, spawnAgent, normalizeAgentId } = await import("./agents-Czz6R57Z.js");
712
+ const { getAgentState, spawnAgent, normalizeAgentId } = await import("./agents-FlIgQ3ql.js");
692
713
  const normalizedId = normalizeAgentId(issueId);
693
714
  if ((await Effect.runPromise(getAgentState(normalizedId)))?.status === "running") throw new AgentAlreadyRunning({ id: issueId });
694
715
  return {
@@ -719,7 +740,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
719
740
  const { workspacePath, projectPath, issue } = opts;
720
741
  if (!existsSync$1(workspacePath)) throw new WorkspaceNotFound({ id: issueId });
721
742
  const sessionName = opts.sessionName ?? `planning-${issueId.toLowerCase()}`;
722
- const { spawnPlanningSession } = await import("./spawn-planning-session-LFtK2QCE.js");
743
+ const { spawnPlanningSession } = await import("./spawn-planning-session-KC_UduxD.js");
723
744
  const result = await spawnPlanningSession({
724
745
  issue: {
725
746
  id: issue.id,
@@ -752,14 +773,14 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
752
773
  }),
753
774
  kill: (agentId) => Effect.tryPromise({
754
775
  try: async () => {
755
- const { stopAgent } = await import("./agents-Czz6R57Z.js");
776
+ const { stopAgent } = await import("./agents-FlIgQ3ql.js");
756
777
  await Effect.runPromise(stopAgent(agentId));
757
778
  },
758
779
  catch: () => void 0
759
780
  }).pipe(Effect.ignore),
760
781
  message: (agentId, msg) => Effect.tryPromise({
761
782
  try: async () => {
762
- const { messageAgent } = await import("./agents-Czz6R57Z.js");
783
+ const { messageAgent } = await import("./agents-FlIgQ3ql.js");
763
784
  await messageAgent(agentId, msg);
764
785
  },
765
786
  catch: (err) => new AgentStartError({
@@ -770,8 +791,8 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
770
791
  }),
771
792
  deepWipe: (issueId, opts) => Effect.tryPromise({
772
793
  try: async () => {
773
- const { deepWipe } = await import("./workflows-C5c-RPsY.js");
774
- const { resolveProjectFromIssueSync } = await import("./projects-IRHJIPYC.js");
794
+ const { deepWipe } = await import("./workflows-D90rMOya.js");
795
+ const { resolveProjectFromIssueSync } = await import("./projects-9SkRpES9.js");
775
796
  const project = resolveProjectFromIssueSync(issueId);
776
797
  const projectPath = project?.projectPath ?? process.cwd();
777
798
  await Effect.runPromise(deepWipe({
@@ -830,8 +851,8 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
830
851
  const { workspacePath, branch } = getWorkspacePath(issueId);
831
852
  const issueLower = issueId.toLowerCase();
832
853
  if (existsSync$1(workspacePath)) return workspacePath;
833
- const { createWorkspace } = await import("./workspace-manager-CcujONCR.js");
834
- const { loadProjectsConfigSync } = await import("./projects-IRHJIPYC.js");
854
+ const { createWorkspace } = await import("./workspace-manager-ZTdJAy9M.js");
855
+ const { loadProjectsConfigSync } = await import("./projects-9SkRpES9.js");
835
856
  const { projects } = loadProjectsConfigSync();
836
857
  const project = resolveProjectFromIssueSync(issueId);
837
858
  if (!project) throw new WorkspaceCreateError({
@@ -866,7 +887,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
866
887
  const { workspacePath } = getWorkspacePath(issueId);
867
888
  const issueLower = issueId.toLowerCase();
868
889
  if (!existsSync$1(workspacePath)) throw new WorkspaceNotFound({ id: issueId });
869
- const { removeWorkspace } = await import("./workspace-manager-CcujONCR.js");
890
+ const { removeWorkspace } = await import("./workspace-manager-ZTdJAy9M.js");
870
891
  const project = resolveProjectFromIssueSync(issueId);
871
892
  if (!project) throw new WorkspaceCreateError({
872
893
  id: issueId,
@@ -897,7 +918,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
897
918
  try: async () => {
898
919
  const { workspacePath } = getWorkspacePath(issueId);
899
920
  const issueLower = issueId.toLowerCase();
900
- const { stopWorkspaceDocker } = await import("./workspace-manager-CcujONCR.js");
921
+ const { stopWorkspaceDocker } = await import("./workspace-manager-ZTdJAy9M.js");
901
922
  await Effect.runPromise(stopWorkspaceDocker(workspacePath, issueLower));
902
923
  },
903
924
  catch: () => void 0
@@ -966,7 +987,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
966
987
  join(workspacePath, ".devcontainer", "docker-compose.devcontainer.yml")
967
988
  ];
968
989
  if (!composePaths.find((p) => existsSync$1(p))) {
969
- const { ensureDevcontainerSync } = await import("./ensure-devcontainer-BA3bICoY.js");
990
+ const { ensureDevcontainerSync } = await import("./ensure-devcontainer-DRqaAkBR.js");
970
991
  const ensure = ensureDevcontainerSync({
971
992
  workspacePath,
972
993
  issueId
@@ -5451,6 +5472,7 @@ function setupTerminalWebSocket(server) {
5451
5472
  //#endregion
5452
5473
  //#region ../../../node_modules/.bun/@ai-sdk+provider@3.0.10/node_modules/@ai-sdk/provider/dist/index.mjs
5453
5474
  init_briefing_freshness();
5475
+ init_agent_runtime_mirror();
5454
5476
  init_behavior();
5455
5477
  init_discovered_sessions();
5456
5478
  init_conversations();
@@ -5460,11 +5482,13 @@ init_openai_auth();
5460
5482
  init_claude_permissions();
5461
5483
  init_claude_auth();
5462
5484
  init_layers();
5485
+ init_harness_binary();
5463
5486
  init_codex();
5464
5487
  init_launcher_generator();
5465
5488
  init_transcript_landing();
5466
5489
  init_operator_interventions();
5467
5490
  init_agents$1();
5491
+ init_runtime_census();
5468
5492
  var marker$2 = "vercel.ai.error";
5469
5493
  var symbol$3 = Symbol.for(marker$2);
5470
5494
  var _a$5, _b$2;
@@ -15944,7 +15968,7 @@ var require_get_vercel_oidc_token = /* @__PURE__ */ __commonJSMin(((exports, mod
15944
15968
  err = error;
15945
15969
  }
15946
15970
  try {
15947
- const [{ getTokenPayload, isExpired }, { refreshToken }] = await Promise.all([await import("./token-util-Cg-QnowA.js").then((m) => /* @__PURE__ */ __toESM(m.default)), await import("./token-LUrbM9sU.js").then((m) => /* @__PURE__ */ __toESM(m.default))]);
15971
+ const [{ getTokenPayload, isExpired }, { refreshToken }] = await Promise.all([await import("./token-util-DrHg8abn.js").then((m) => /* @__PURE__ */ __toESM(m.default)), await import("./token-CsOhvw42.js").then((m) => /* @__PURE__ */ __toESM(m.default))]);
15948
15972
  if (!token || isExpired(getTokenPayload(token), options?.expirationBufferMs)) {
15949
15973
  await refreshToken(options);
15950
15974
  token = getVercelOidcTokenSync();
@@ -27778,7 +27802,7 @@ function randomId() {
27778
27802
  function randomNonce() {
27779
27803
  return Math.floor(Math.random() * 2147483647);
27780
27804
  }
27781
- function finiteNumber(value, fallback) {
27805
+ function finiteNumber$1(value, fallback) {
27782
27806
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
27783
27807
  }
27784
27808
  function normalizeExcalidrawElement(element) {
@@ -27786,12 +27810,12 @@ function normalizeExcalidrawElement(element) {
27786
27810
  ...element,
27787
27811
  id: typeof element.id === "string" && element.id ? element.id : randomId(),
27788
27812
  type: typeof element.type === "string" && element.type ? element.type : "rectangle",
27789
- x: finiteNumber(element.x, 0),
27790
- y: finiteNumber(element.y, 0),
27791
- width: Math.max(1, finiteNumber(element.width, 100)),
27792
- height: Math.max(1, finiteNumber(element.height, 100)),
27793
- version: Math.max(1, Math.trunc(finiteNumber(element.version, 1))),
27794
- versionNonce: Math.trunc(finiteNumber(element.versionNonce, randomNonce())),
27813
+ x: finiteNumber$1(element.x, 0),
27814
+ y: finiteNumber$1(element.y, 0),
27815
+ width: Math.max(1, finiteNumber$1(element.width, 100)),
27816
+ height: Math.max(1, finiteNumber$1(element.height, 100)),
27817
+ version: Math.max(1, Math.trunc(finiteNumber$1(element.version, 1))),
27818
+ versionNonce: Math.trunc(finiteNumber$1(element.versionNonce, randomNonce())),
27795
27819
  isDeleted: element.isDeleted === true
27796
27820
  };
27797
27821
  if (Math.abs(normalized.x) > VISIBLE_CANVAS_LIMIT || Math.abs(normalized.y) > VISIBLE_CANVAS_LIMIT) console.warn(`Excalidraw element ${normalized.id} has coordinates outside visible canvas range`);
@@ -28261,7 +28285,7 @@ var GoogleCloudTranscription = class {
28261
28285
  }
28262
28286
  async start(apiKey, model) {
28263
28287
  try {
28264
- const { SpeechClient } = await import("./src-OLoJhUiJ.js").then((m) => /* @__PURE__ */ __toESM(m.default, 1)).then((module) => module.v1p1beta1 ?? module.v1);
28288
+ const { SpeechClient } = await import("./src-CG9mCkP6.js").then((m) => /* @__PURE__ */ __toESM(m.default, 1)).then((module) => module.v1p1beta1 ?? module.v1);
28265
28289
  if (this.closed) return;
28266
28290
  const stream = new SpeechClient({ apiKey }).streamingRecognize({
28267
28291
  config: {
@@ -28926,6 +28950,21 @@ function setupAutoPresoWebSocket(server) {
28926
28950
  });
28927
28951
  }
28928
28952
  //#endregion
28953
+ //#region services/agent-output-stream.ts
28954
+ function shouldBroadcastDashboardEvent(event) {
28955
+ return event.type !== "agent.output_received";
28956
+ }
28957
+ /** Dedicated, scoped stream for one agent's ephemeral output. */
28958
+ function streamAgentOutput(eventStore, agentId) {
28959
+ return Stream.unwrap(Effect.acquireRelease(Effect.sync(() => retainAgentOutputInterest(agentId)), (release) => Effect.sync(release)).pipe(Effect.map(() => eventStore.streamEvents.pipe(Stream.filter((event) => event.type === "agent.output_received" && event.payload["agentId"] === agentId), Stream.flatMap((event) => {
28960
+ const payload = event.payload;
28961
+ return Stream.fromIterable(payload.lines.map((line) => ({
28962
+ agentId: payload.agentId,
28963
+ line
28964
+ })));
28965
+ })))));
28966
+ }
28967
+ //#endregion
28929
28968
  //#region services/read-workspace-file.ts
28930
28969
  init_codex_conversation_parser();
28931
28970
  init_ohmypi_conversation_parser();
@@ -28972,7 +29011,7 @@ const LANGUAGE_BY_EXTENSION = {
28972
29011
  function isInsidePath(parent, child) {
28973
29012
  return child === parent || child.startsWith(`${parent}${sep}`);
28974
29013
  }
28975
- function splitLines$1(text) {
29014
+ function splitLines(text) {
28976
29015
  if (text.length === 0) return [];
28977
29016
  const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
28978
29017
  return normalized.endsWith("\n") ? normalized.slice(0, -1).split("\n") : normalized.split("\n");
@@ -28986,7 +29025,7 @@ function validateIntegerAtLeast(value, name, min) {
28986
29025
  return value;
28987
29026
  }
28988
29027
  function selectRequestedLines(text, line, contextLines) {
28989
- const lines = splitLines$1(text);
29028
+ const lines = splitLines(text);
28990
29029
  const totalLines = lines.length;
28991
29030
  if (!line) return {
28992
29031
  text: contextLines === void 0 ? text : lines.slice(0, contextLines).join("\n"),
@@ -29273,7 +29312,6 @@ function normalizeSessionsFeedFilter(input) {
29273
29312
  */
29274
29313
  init_src();
29275
29314
  init_paths();
29276
- init_tmux();
29277
29315
  init_projects();
29278
29316
  function storedToDomainEvent(stored) {
29279
29317
  return {
@@ -29286,7 +29324,8 @@ function storedToDomainEvent(stored) {
29286
29324
  const isKnownDomainEvent = Schema.is(DomainEvent);
29287
29325
  function passesDomainEventSchema(event) {
29288
29326
  if (isKnownDomainEvent(event)) return true;
29289
- console.error(`[ws-rpc] dropping domain event that fails DomainEvent schema validation — add it to the contracts union: type=${event.type} seq=${event.sequence}`);
29327
+ const candidate = event;
29328
+ console.error(`[ws-rpc] dropping domain event that fails DomainEvent schema validation — add it to the contracts union: type=${String(candidate.type)} seq=${String(candidate.sequence)}`);
29290
29329
  return false;
29291
29330
  }
29292
29331
  function createSystemHeartbeatEvent() {
@@ -29657,8 +29696,9 @@ function startSharedPresencePoller() {
29657
29696
  if (sharedPresencePoller.interval) return;
29658
29697
  const tick = async () => {
29659
29698
  try {
29660
- const sessions = await Effect.runPromise(listSessionNames());
29661
- const current = new Set(sessions.filter((s) => s.trim()));
29699
+ const census = await getRuntimeCensus();
29700
+ if (!census.available) return;
29701
+ const current = new Set(census.sessionNames);
29662
29702
  for (const s of sharedPresencePoller.knownSessions) if (!current.has(s)) {
29663
29703
  const issueId = extractIssueIdFromSession(s);
29664
29704
  if (issueId) {
@@ -29722,7 +29762,7 @@ const PanRpcLayer = PanRpcGroup.toLayer(Effect.gen(function* () {
29722
29762
  [WS_METHODS.subscribeDomainEvents]: (_input) => {
29723
29763
  console.log("[ws-rpc] subscribeDomainEvents invoked");
29724
29764
  const heartbeats = Stream.tick("15 seconds").pipe(Stream.map(createSystemHeartbeatEvent));
29725
- return eventStore.streamEvents.pipe(Stream.map(storedToDomainEvent), Stream.filter(passesDomainEventSchema), Stream.merge(heartbeats));
29765
+ return eventStore.streamEvents.pipe(Stream.filter(shouldBroadcastDashboardEvent), Stream.map(storedToDomainEvent), Stream.filter(passesDomainEventSchema), Stream.merge(heartbeats));
29726
29766
  },
29727
29767
  [WS_METHODS.subscribeFlywheelStatus]: (_input) => Stream.callback((queue) => Effect.acquireRelease(Effect.promise(async () => {
29728
29768
  const latest = await readCurrentLatestFlywheelStatus({ activeRunId: await runDashboardDbJob("getSetting", "flywheel.active_run_id") });
@@ -29733,16 +29773,10 @@ const PanRpcLayer = PanRpcGroup.toLayer(Effect.gen(function* () {
29733
29773
  }), (unsubscribe) => Effect.sync(() => unsubscribe()))),
29734
29774
  [WS_METHODS.subscribeIssueEvents]: (input) => {
29735
29775
  console.log(`[ws-rpc] subscribeIssueEvents invoked issueId=${input.issueId}`);
29736
- return eventStore.streamEvents.pipe(Stream.map(storedToDomainEvent), Stream.filter(passesDomainEventSchema), Stream.mapEffect((event) => getCachedAgentIssueLookup(readModel).pipe(Effect.map((lookup) => filterDomainEventForIssue(event, input.issueId, lookup)))), Stream.filter((event) => event !== null));
29776
+ return eventStore.streamEvents.pipe(Stream.filter(shouldBroadcastDashboardEvent), Stream.map(storedToDomainEvent), Stream.filter(passesDomainEventSchema), Stream.mapEffect((event) => getCachedAgentIssueLookup(readModel).pipe(Effect.map((lookup) => filterDomainEventForIssue(event, input.issueId, lookup)))), Stream.filter((event) => event !== null));
29737
29777
  },
29738
29778
  [WS_METHODS.subscribeTerminal]: (input) => terminalService.streamSession(input.sessionName, input.cols, input.rows),
29739
- [WS_METHODS.subscribeAgentOutput]: (input) => eventStore.streamEvents.pipe(Stream.filter((e) => e.type === "agent.output_received" && e.payload["agentId"] === input.agentId), Stream.flatMap((e) => {
29740
- const payload = e.payload;
29741
- return Stream.fromIterable(payload.lines.map((line) => ({
29742
- agentId: payload.agentId,
29743
- line
29744
- })));
29745
- })),
29779
+ [WS_METHODS.subscribeAgentOutput]: (input) => streamAgentOutput(eventStore, input.agentId),
29746
29780
  [WS_METHODS.getSnapshot]: (_input) => Effect.gen(function* () {
29747
29781
  const t0 = Date.now();
29748
29782
  console.log("[ws-rpc] getSnapshot invoked");
@@ -30039,7 +30073,11 @@ const websocketRpcRouteLayer = Layer.unwrap(Effect.gen(function* () {
30039
30073
  }));
30040
30074
  }));
30041
30075
  //#endregion
30042
- //#region ../../lib/vbrief/quality-lint.ts
30076
+ //#region ../../lib/xbrief/quality-lint.ts
30077
+ init_internal_token();
30078
+ init_pipeline_notifier();
30079
+ init_review_status_sync();
30080
+ init_review_status();
30043
30081
  init_state_home();
30044
30082
  init_pan_dir();
30045
30083
  init_in_flight_guard();
@@ -30048,7 +30086,7 @@ init_dag();
30048
30086
  init_swarm_readiness();
30049
30087
  var PlanQualityLintError = class extends Error {
30050
30088
  constructor(issues) {
30051
- super(`vBRIEF quality lint failed with ${issues.length} issue${issues.length === 1 ? "" : "s"}`);
30089
+ super(`xBRIEF quality lint failed with ${issues.length} issue${issues.length === 1 ? "" : "s"}`);
30052
30090
  this.issues = issues;
30053
30091
  this.name = "PlanQualityLintError";
30054
30092
  }
@@ -30411,28 +30449,80 @@ function assertPlanQuality(doc, options = {}) {
30411
30449
  return issues;
30412
30450
  }
30413
30451
  //#endregion
30452
+ //#region services/resource-discovery-shared.ts
30453
+ init_conversations();
30454
+ init_runtime_census();
30455
+ const execFileAsync$18 = promisify(execFile);
30456
+ async function loadTrackerIssues() {
30457
+ const map = /* @__PURE__ */ new Map();
30458
+ try {
30459
+ const { getSharedIssueService } = await import("./issue-service-singleton-DabvBWUp.js");
30460
+ const issues = (await getSharedIssueService()).getIssues();
30461
+ for (const issue of issues) if (issue.identifier) map.set(issue.identifier.toUpperCase(), issue);
30462
+ } catch {}
30463
+ return map;
30464
+ }
30465
+ async function loadDockerContainers() {
30466
+ try {
30467
+ const { stdout } = await execFileAsync$18("docker", [
30468
+ "ps",
30469
+ "--format",
30470
+ "{{.Names}}"
30471
+ ], {
30472
+ encoding: "utf-8",
30473
+ timeout: 5e3
30474
+ });
30475
+ return stdout.split("\n").map((line) => line.trim()).filter(Boolean);
30476
+ } catch {
30477
+ return [];
30478
+ }
30479
+ }
30480
+ async function loadActiveRemoteAgentStates() {
30481
+ try {
30482
+ const { listActiveRemoteAgentStates } = await import("./remote-agents-CRCg1L4H.js");
30483
+ return listActiveRemoteAgentStates();
30484
+ } catch {
30485
+ return [];
30486
+ }
30487
+ }
30488
+ async function captureSharedResourceSignals() {
30489
+ const [trackerIssues, runtimeCensus, dockerContainers, remoteAgentStates] = await Promise.all([
30490
+ loadTrackerIssues(),
30491
+ getRuntimeCensus(),
30492
+ loadDockerContainers(),
30493
+ loadActiveRemoteAgentStates()
30494
+ ]);
30495
+ const tmuxSessions = [...runtimeCensus.sessionNames];
30496
+ let conversations = [];
30497
+ try {
30498
+ conversations = listConversations();
30499
+ } catch {}
30500
+ return {
30501
+ trackerIssues,
30502
+ tmuxSessions,
30503
+ dockerContainers,
30504
+ conversations,
30505
+ remoteAgentStates
30506
+ };
30507
+ }
30508
+ //#endregion
30414
30509
  //#region review-status.ts
30415
30510
  init_concurrency$1();
30416
30511
  init_github_app();
30417
30512
  init_resource_utils();
30418
30513
  init_pipeline_membership_gather();
30419
- init_review_status();
30514
+ init_pipeline_membership();
30420
30515
  //#endregion
30421
30516
  //#region services/pipeline-membership.ts
30422
- init_internal_token();
30423
- init_pipeline_notifier();
30424
- init_review_status_sync();
30425
- init_pipeline_membership();
30426
30517
  const PIPELINE_MEMBERSHIP_TTL_MS = 3e4;
30427
30518
  function createPipelineMembershipService(deps = {
30428
30519
  gather: gatherProjectLensSignals,
30429
30520
  now: Date.now
30430
30521
  }) {
30431
30522
  const cachedGather = createSettledTtlPromiseCache(PIPELINE_MEMBERSHIP_TTL_MS, deps.now);
30432
- return async (project) => {
30433
- if (!project.github_repo) return [];
30434
- return cachedGather(project.path, () => deps.gather(project).then((signals) => signals.map(resolvePipelineMembership)));
30435
- };
30523
+ const service = async (project) => cachedGather(project.path, () => deps.gather(project).then((signals) => signals.map(resolvePipelineMembership)));
30524
+ service.invalidate = (projectPath) => cachedGather.invalidate(projectPath);
30525
+ return service;
30436
30526
  }
30437
30527
  const getProjectPipelineMembership = createPipelineMembershipService();
30438
30528
  const membershipSnapshots = /* @__PURE__ */ new Map();
@@ -30447,22 +30537,10 @@ function refreshMembershipSnapshot(project, snapshot, getMembership, now) {
30447
30537
  });
30448
30538
  return snapshot.refresh;
30449
30539
  }
30450
- /** Return the latest successful snapshot immediately and refresh stale/missing projects in the background. */
30451
- function getPipelineMembershipSnapshotsForProjects(projects, getMembership = getProjectPipelineMembership, now = Date.now) {
30540
+ /** Read the latest successful snapshots without scheduling tracker or git work. */
30541
+ function readPipelineMembershipSnapshotsForProjects(projects) {
30452
30542
  return projects.map((project) => {
30453
- if (!project.github_repo) return {
30454
- project,
30455
- error: /* @__PURE__ */ new Error("Pipeline membership unavailable: missing github_repo")
30456
- };
30457
30543
  const snapshot = membershipSnapshots.get(project.path);
30458
- if (!snapshot?.refresh && (!snapshot || now() - snapshot.refreshedAt >= 3e5)) {
30459
- const current = snapshot ?? {
30460
- value: [],
30461
- refreshedAt: 0
30462
- };
30463
- membershipSnapshots.set(project.path, current);
30464
- refreshMembershipSnapshot(project, current, getMembership, now);
30465
- }
30466
30544
  return snapshot?.refreshedAt ? {
30467
30545
  project,
30468
30546
  memberships: snapshot.value
@@ -30472,34 +30550,26 @@ function getPipelineMembershipSnapshotsForProjects(projects, getMembership = get
30472
30550
  };
30473
30551
  });
30474
30552
  }
30475
- /** Await only the first snapshot; later resource refreshes consume stale data while revalidating. */
30476
- async function getPipelineMembershipSnapshotsForResourceDiscovery(projects, getMembership = getProjectPipelineMembership, now = Date.now) {
30477
- return Promise.all(projects.map(async (project) => {
30478
- if (!project.github_repo) return {
30479
- project,
30480
- error: /* @__PURE__ */ new Error("Pipeline membership unavailable: missing github_repo")
30481
- };
30482
- const existing = membershipSnapshots.get(project.path);
30483
- if (existing?.refreshedAt) {
30484
- if (now() - existing.refreshedAt >= 3e5) refreshMembershipSnapshot(project, existing, getMembership, now);
30485
- return {
30486
- project,
30487
- memberships: existing.value
30488
- };
30489
- }
30490
- const snapshot = existing ?? {
30553
+ /**
30554
+ * PAN-2893 — event-driven refresh. Invalidate the per-project TTL cache and
30555
+ * force a snapshot re-gather NOW for the given projects, so agent lifecycle
30556
+ * changes reach membership consumers without waiting out the 5-minute TTL.
30557
+ * Refresh failures keep the last good snapshot (same policy as TTL refreshes).
30558
+ */
30559
+ async function refreshMembershipSnapshotsForProjects(projects, getMembership = getProjectPipelineMembership, now = Date.now) {
30560
+ await Promise.all(projects.map(async (project) => {
30561
+ getMembership.invalidate(project.path);
30562
+ const snapshot = membershipSnapshots.get(project.path) ?? {
30491
30563
  value: [],
30492
30564
  refreshedAt: 0
30493
30565
  };
30494
30566
  membershipSnapshots.set(project.path, snapshot);
30567
+ const inFlight = snapshot.refresh;
30568
+ if (inFlight) {
30569
+ await inFlight;
30570
+ getMembership.invalidate(project.path);
30571
+ }
30495
30572
  await refreshMembershipSnapshot(project, snapshot, getMembership, now);
30496
- return snapshot.refreshedAt ? {
30497
- project,
30498
- memberships: snapshot.value
30499
- } : {
30500
- project,
30501
- error: /* @__PURE__ */ new Error("Pipeline membership snapshot failed to load")
30502
- };
30503
30573
  }));
30504
30574
  }
30505
30575
  function summarizePipelineMembership(membership) {
@@ -30520,16 +30590,15 @@ function unavailablePipelineMembership() {
30520
30590
  }
30521
30591
  //#endregion
30522
30592
  //#region services/resource-discovery.ts
30523
- init_conversations();
30593
+ init_src();
30524
30594
  init_projects();
30595
+ init_pipeline_membership();
30525
30596
  init_pipeline_membership_gather();
30526
- init_tmux();
30527
- const execFileAsync$18 = promisify(execFile);
30528
- const RESOURCE_DISCOVERY_TTL_MS = 3e4;
30597
+ const execFileAsync$17 = promisify(execFile);
30529
30598
  const RECENT_ACTIVITY_WINDOW_MS = 5e3;
30599
+ const projectResourceSnapshots = /* @__PURE__ */ new Map();
30530
30600
  let cachedResourceIssues = null;
30531
30601
  let cachedDetailedResourceIssues = null;
30532
- let resourceIssuesRefreshPromise = null;
30533
30602
  function projectPrefixes(project) {
30534
30603
  const prefixes = /* @__PURE__ */ new Set();
30535
30604
  if (project.config.issue_prefix) prefixes.add(project.config.issue_prefix.toUpperCase());
@@ -30569,7 +30638,7 @@ function summarizeResourceDetails(details) {
30569
30638
  state: pr.state,
30570
30639
  isDraft: pr.isDraft
30571
30640
  })),
30572
- hasVbrief: details.vbriefPath !== null,
30641
+ hasXbrief: details.xbriefPath !== null,
30573
30642
  hasTasks: details.tasksPath !== null,
30574
30643
  dockerContainerCount: details.dockerContainers.length,
30575
30644
  actualBranch: details.actualBranch,
@@ -30636,46 +30705,6 @@ const DISCOVERABLE_SESSION_PREFIXES = [
30636
30705
  function isDiscoverableAgentSession(sessionName) {
30637
30706
  return DISCOVERABLE_SESSION_PREFIXES.some((prefix) => sessionName.startsWith(prefix));
30638
30707
  }
30639
- async function loadTrackerIssues() {
30640
- const map = /* @__PURE__ */ new Map();
30641
- try {
30642
- const { getSharedIssueService } = await import("./issue-service-singleton-D5EB5eYr.js");
30643
- const issues = (await getSharedIssueService()).getIssues();
30644
- for (const issue of issues) if (issue.identifier) map.set(issue.identifier.toUpperCase(), issue);
30645
- } catch {
30646
- return map;
30647
- }
30648
- return map;
30649
- }
30650
- async function loadTmuxSessions() {
30651
- try {
30652
- return (await Effect.runPromise(listSessionNames())).map((name) => name.trim()).filter(Boolean);
30653
- } catch {
30654
- return [];
30655
- }
30656
- }
30657
- function loadConversations() {
30658
- try {
30659
- return listConversations();
30660
- } catch {
30661
- return [];
30662
- }
30663
- }
30664
- async function loadDockerContainers() {
30665
- try {
30666
- const { stdout } = await execFileAsync$18("docker", [
30667
- "ps",
30668
- "--format",
30669
- "{{.Names}}"
30670
- ], {
30671
- encoding: "utf-8",
30672
- timeout: 5e3
30673
- });
30674
- return stdout.split("\n").map((line) => line.trim()).filter(Boolean);
30675
- } catch {
30676
- return [];
30677
- }
30678
- }
30679
30708
  async function loadOpenPullRequests(projects) {
30680
30709
  const pullRequests = /* @__PURE__ */ new Map();
30681
30710
  await Promise.all(projects.map(async (project) => {
@@ -30706,80 +30735,31 @@ async function loadOpenPullRequests(projects) {
30706
30735
  for (const [issueId, prs] of pullRequests) pullRequests.set(issueId, sortPullRequests(prs));
30707
30736
  return pullRequests;
30708
30737
  }
30709
- async function loadProjectBranches(projectPath) {
30710
- try {
30711
- const [localFeature, remoteFeature, localBypass, remoteBypass] = await Promise.all([
30712
- execFileAsync$18("git", [
30713
- "for-each-ref",
30714
- "refs/heads/feature/*",
30715
- "--format=%(refname:short)"
30716
- ], {
30717
- cwd: projectPath,
30718
- encoding: "utf-8",
30719
- timeout: 1e4
30720
- }).catch(() => ({ stdout: "" })),
30721
- execFileAsync$18("git", [
30722
- "for-each-ref",
30723
- "refs/remotes/origin/feature/*",
30724
- "--format=%(refname:short)"
30725
- ], {
30726
- cwd: projectPath,
30727
- encoding: "utf-8",
30728
- timeout: 1e4
30729
- }).catch(() => ({ stdout: "" })),
30730
- execFileAsync$18("git", [
30731
- "for-each-ref",
30732
- "refs/heads/bypass/*",
30733
- "--format=%(refname:short)"
30734
- ], {
30735
- cwd: projectPath,
30736
- encoding: "utf-8",
30737
- timeout: 1e4
30738
- }).catch(() => ({ stdout: "" })),
30739
- execFileAsync$18("git", [
30740
- "for-each-ref",
30741
- "refs/remotes/origin/bypass/*",
30742
- "--format=%(refname:short)"
30743
- ], {
30744
- cwd: projectPath,
30745
- encoding: "utf-8",
30746
- timeout: 1e4
30747
- }).catch(() => ({ stdout: "" }))
30748
- ]);
30749
- return {
30750
- local: [...localFeature.stdout.split("\n").map((line) => line.trim()).filter(Boolean), ...localBypass.stdout.split("\n").map((line) => line.trim()).filter(Boolean)],
30751
- remote: [...remoteFeature.stdout.split("\n").map((line) => line.trim()).filter(Boolean), ...remoteBypass.stdout.split("\n").map((line) => line.trim()).filter(Boolean)]
30752
- };
30753
- } catch {
30754
- return {
30755
- local: [],
30756
- remote: []
30757
- };
30758
- }
30759
- }
30760
- async function loadBranchesAheadOfMain(projectPath) {
30761
- const ahead = /* @__PURE__ */ new Set();
30762
- const run = async (patterns) => {
30763
- if (patterns.length === 0) return;
30764
- try {
30765
- const { stdout } = await execFileAsync$18("git", [
30766
- "for-each-ref",
30767
- "--format=%(refname:short)",
30768
- ...patterns,
30769
- "--no-merged=main"
30770
- ], {
30771
- cwd: projectPath,
30772
- encoding: "utf-8",
30773
- timeout: 1e4
30774
- });
30775
- for (const line of stdout.split("\n")) {
30776
- const branch = line.trim();
30777
- if (branch) ahead.add(branch);
30778
- }
30779
- } catch {}
30738
+ const PROJECT_BRANCH_PATTERNS = [
30739
+ "refs/heads/feature/*",
30740
+ "refs/remotes/origin/feature/*",
30741
+ "refs/heads/bypass/*",
30742
+ "refs/remotes/origin/bypass/*"
30743
+ ];
30744
+ async function loadProjectBranchSnapshot(projectPath) {
30745
+ const run = (extraArgs = []) => execFileAsync$17("git", [
30746
+ "for-each-ref",
30747
+ "--format=%(refname:short)",
30748
+ ...extraArgs,
30749
+ ...PROJECT_BRANCH_PATTERNS
30750
+ ], {
30751
+ cwd: projectPath,
30752
+ encoding: "utf-8",
30753
+ timeout: 1e4
30754
+ }).catch(() => ({ stdout: "" }));
30755
+ const [allRefs, unmergedRefs] = await Promise.all([run(), run(["--no-merged=main"])]);
30756
+ const branches = allRefs.stdout.split("\n").map((line) => line.trim()).filter(Boolean);
30757
+ const ahead = new Set(unmergedRefs.stdout.split("\n").map((line) => line.trim()).filter(Boolean));
30758
+ return {
30759
+ local: branches.filter((branch) => !branch.startsWith("origin/")),
30760
+ remote: branches.filter((branch) => branch.startsWith("origin/")),
30761
+ ahead
30780
30762
  };
30781
- await Promise.all([run(["refs/heads/feature/*", "refs/heads/bypass/*"]), run(["refs/remotes/origin/feature/*", "refs/remotes/origin/bypass/*"])]);
30782
- return ahead;
30783
30763
  }
30784
30764
  async function scanWorkspace(workspacesDir, workspaceName) {
30785
30765
  const workspacePath = join(workspacesDir, workspaceName);
@@ -30789,46 +30769,43 @@ async function scanWorkspace(workspacesDir, workspaceName) {
30789
30769
  const issueMatch = workspaceName.match(/^feature-([a-z]+-\d+)$/i);
30790
30770
  const issueId = issueMatch ? issueMatch[1].toUpperCase() : null;
30791
30771
  const specEntry = issueId ? await Effect.runPromise(findSpecByIssue(projectRoot, issueId)).catch(() => null) : null;
30792
- const vbriefPath = specEntry ? specEntry.path : null;
30793
- let vbriefMtime = null;
30794
- if (vbriefPath) try {
30795
- vbriefMtime = (await stat$1(vbriefPath)).mtimeMs;
30772
+ const xbriefPath = specEntry ? specEntry.path : null;
30773
+ let xbriefMtime = null;
30774
+ if (xbriefPath) try {
30775
+ xbriefMtime = (await stat$1(xbriefPath)).mtimeMs;
30796
30776
  } catch {
30797
- vbriefMtime = null;
30777
+ xbriefMtime = null;
30798
30778
  }
30799
30779
  return {
30800
30780
  workspacePath,
30801
30781
  hasPlanning: workspaceEntries.has(PAN_DIRNAME),
30802
30782
  hasPrd: panEntries.has("prd.md"),
30803
30783
  hasState: panEntries.has(PAN_CONTINUE_FILENAME),
30804
- hasVbrief: vbriefPath !== null,
30805
- vbriefPath,
30806
- vbriefMtime,
30807
- hasTasks: vbriefPath !== null
30784
+ hasXbrief: xbriefPath !== null,
30785
+ xbriefPath,
30786
+ xbriefMtime,
30787
+ hasTasks: xbriefPath !== null
30808
30788
  };
30809
30789
  }
30810
- async function computeResourceAllocatedIssues() {
30811
- const projects = listProjectsSync();
30812
- const [trackerIssues, tmuxSessions, dockerContainers, pullRequests] = await Promise.all([
30813
- loadTrackerIssues(),
30814
- loadTmuxSessions(),
30815
- loadDockerContainers(),
30816
- loadOpenPullRequests(projects)
30817
- ]);
30790
+ async function computeResourceAllocatedIssues(projectConfigs, sharedSignals) {
30791
+ const registeredProjects = listProjectsSync();
30792
+ const projects = projectConfigs.map((config) => registeredProjects.find((entry) => entry.config.path === config.path) ?? {
30793
+ key: config.name ?? config.path,
30794
+ config
30795
+ });
30796
+ const { trackerIssues, tmuxSessions, dockerContainers, conversations, remoteAgentStates } = sharedSignals ?? await captureSharedResourceSignals();
30797
+ const pullRequests = await loadOpenPullRequests(projects);
30818
30798
  const issueMap = /* @__PURE__ */ new Map();
30819
30799
  const projectByPrefix = /* @__PURE__ */ new Map();
30820
30800
  for (const project of projects) for (const prefix of projectPrefixes(project)) projectByPrefix.set(prefix, project);
30821
- const projectRefFromResolved = (resolvedProject) => ({
30822
- key: resolvedProject.projectKey,
30823
- config: {
30824
- name: resolvedProject.projectName,
30825
- path: resolvedProject.projectPath
30826
- }
30827
- });
30801
+ const projectRefFromResolved = (resolvedProject) => projects.find((project) => project.key === resolvedProject.projectKey || project.config.path === resolvedProject.projectPath) ?? null;
30828
30802
  const resolveProjectRef = (issueId, preferredProject) => {
30829
30803
  if (preferredProject) return preferredProject;
30830
30804
  const resolvedProject = resolveProjectFromIssueSync(issueId);
30831
- if (resolvedProject) return projectRefFromResolved(resolvedProject);
30805
+ if (resolvedProject) {
30806
+ const project = projectRefFromResolved(resolvedProject);
30807
+ if (project) return project;
30808
+ }
30832
30809
  const prefix = issueId.toUpperCase().match(/^([A-Z]+)-\d+$/)?.[1] ?? "";
30833
30810
  return projectByPrefix.get(prefix) ?? null;
30834
30811
  };
@@ -30861,8 +30838,8 @@ async function computeResourceAllocatedIssues() {
30861
30838
  localBranches: [],
30862
30839
  remoteBranches: [],
30863
30840
  prs: [],
30864
- vbriefPath: null,
30865
- vbriefMtime: null,
30841
+ xbriefPath: null,
30842
+ xbriefMtime: null,
30866
30843
  tasksPath: null,
30867
30844
  dockerContainers: [],
30868
30845
  actualBranch: null,
@@ -30895,7 +30872,6 @@ async function computeResourceAllocatedIssues() {
30895
30872
  issue.resourceSources.add("tmux");
30896
30873
  if (!issue.resourceDetails.tmuxSessions.includes(sessionName)) issue.resourceDetails.tmuxSessions.push(sessionName);
30897
30874
  }
30898
- const conversations = loadConversations();
30899
30875
  for (const conv of conversations) {
30900
30876
  if (!conv.issueId || conv.archivedAt) continue;
30901
30877
  const issue = ensureIssue(conv.issueId);
@@ -30909,21 +30885,18 @@ async function computeResourceAllocatedIssues() {
30909
30885
  tmuxSession: conv.tmuxSession
30910
30886
  });
30911
30887
  }
30912
- try {
30913
- const { listActiveRemoteAgentStates } = await import("./remote-agents-BNORDWAX.js");
30914
- for (const remoteState of listActiveRemoteAgentStates()) {
30915
- const issue = ensureIssue(remoteState.issueId);
30916
- if (!issue) continue;
30917
- issue.resourceSources.add("remote-agent");
30918
- issue.resourceDetails.remoteAgent = {
30919
- vmName: remoteState.vmName,
30920
- status: remoteState.status,
30921
- model: remoteState.model,
30922
- startedAt: remoteState.startedAt
30923
- };
30924
- if (!issue.agentStatus) issue.agentStatus = "active";
30925
- }
30926
- } catch {}
30888
+ for (const remoteState of remoteAgentStates) {
30889
+ const issue = ensureIssue(remoteState.issueId);
30890
+ if (!issue) continue;
30891
+ issue.resourceSources.add("remote-agent");
30892
+ issue.resourceDetails.remoteAgent = {
30893
+ vmName: remoteState.vmName,
30894
+ status: remoteState.status,
30895
+ model: remoteState.model,
30896
+ startedAt: remoteState.startedAt
30897
+ };
30898
+ if (!issue.agentStatus) issue.agentStatus = "active";
30899
+ }
30927
30900
  for (const containerName of dockerContainers) {
30928
30901
  const issueId = parseIssueIdFromTextSync(containerName.replace(/feature\//g, "feature-"));
30929
30902
  if (!issueId) continue;
@@ -30935,8 +30908,7 @@ async function computeResourceAllocatedIssues() {
30935
30908
  await Promise.all(projects.map(async (project) => {
30936
30909
  const projectPath = project.config.path;
30937
30910
  const workspacesDir = join(projectPath, "workspaces");
30938
- const [workspaceEntries, branches] = await Promise.all([readdir(workspacesDir, { withFileTypes: true }).catch(() => []), loadProjectBranches(projectPath)]);
30939
- const aheadBranches = await loadBranchesAheadOfMain(projectPath);
30911
+ const [workspaceEntries, branches] = await Promise.all([readdir(workspacesDir, { withFileTypes: true }).catch(() => []), loadProjectBranchSnapshot(projectPath)]);
30940
30912
  await Promise.all(workspaceEntries.map(async (entry) => {
30941
30913
  if (!entry.isDirectory() || !entry.name.startsWith("feature-")) return;
30942
30914
  const issue = ensureIssue(entry.name.replace(/^feature-/, "").toUpperCase(), project);
@@ -30947,10 +30919,10 @@ async function computeResourceAllocatedIssues() {
30947
30919
  issue.hasPlanning = workspace.hasPlanning;
30948
30920
  issue.hasPrd = workspace.hasPrd;
30949
30921
  issue.hasState = workspace.hasState;
30950
- if (workspace.vbriefPath) {
30922
+ if (workspace.xbriefPath) {
30951
30923
  issue.resourceSources.add("vbrief");
30952
- issue.resourceDetails.vbriefPath = workspace.vbriefPath;
30953
- issue.resourceDetails.vbriefMtime = workspace.vbriefMtime;
30924
+ issue.resourceDetails.xbriefPath = workspace.xbriefPath;
30925
+ issue.resourceDetails.xbriefMtime = workspace.xbriefMtime;
30954
30926
  }
30955
30927
  if (workspace.hasTasks) {
30956
30928
  issue.resourceSources.add("tasks");
@@ -30968,7 +30940,7 @@ async function computeResourceAllocatedIssues() {
30968
30940
  if (!issue) continue;
30969
30941
  issue.resourceSources.add("branch");
30970
30942
  if (!issue.resourceDetails[key].includes(branch)) issue.resourceDetails[key].push(branch);
30971
- if (aheadBranches.has(branch)) issue.resourceDetails.branchAheadOfMain = true;
30943
+ if (branches.ahead.has(branch)) issue.resourceDetails.branchAheadOfMain = true;
30972
30944
  }
30973
30945
  }));
30974
30946
  for (const [issueId, prs] of pullRequests) {
@@ -30993,14 +30965,18 @@ async function computeResourceAllocatedIssues() {
30993
30965
  for (const issue of issueMap.values()) issue.readyForMerge = readyForMergeFlags.get(issue.issueId) ?? false;
30994
30966
  }
30995
30967
  const memberships = /* @__PURE__ */ new Map();
30996
- const projectMemberships = await getPipelineMembershipSnapshotsForResourceDiscovery(projects.map((project) => project.config));
30997
- for (const result of projectMemberships) for (const membership of result.memberships ?? []) {
30998
- ensureIssue(membership.issueId);
30999
- memberships.set(membership.issueId, membership);
30968
+ const unavailableProjects = /* @__PURE__ */ new Set();
30969
+ const projectMemberships = readPipelineMembershipSnapshotsForProjects(projects.map((project) => project.config));
30970
+ for (const result of projectMemberships) {
30971
+ if (result.error) unavailableProjects.add(result.project.name);
30972
+ for (const membership of result.memberships ?? []) {
30973
+ ensureIssue(membership.issueId);
30974
+ memberships.set(membership.issueId, membership);
30975
+ }
31000
30976
  }
31001
30977
  return [...issueMap.values()].filter((issue) => issue.resourceSources.size > 0).filter((issue) => {
31002
30978
  const membership = memberships.get(issue.issueId);
31003
- return membership?.inPipeline === true || membership?.bucket === "clean_terminal" && isLiveResource(issue);
30979
+ return membership?.inPipeline === true || membership?.bucket === "clean_terminal" && isLiveResource(issue) || !membership && unavailableProjects.has(issue.projectName) && isLiveResource(issue);
31004
30980
  }).map((issue) => {
31005
30981
  const membership = memberships.get(issue.issueId);
31006
30982
  const hasTmux = issue.resourceDetails.tmuxSessions.length > 0;
@@ -31029,10 +31005,11 @@ async function computeResourceAllocatedIssues() {
31029
31005
  resourceSources: new Set([...issue.resourceSources].sort()),
31030
31006
  resourceDetails: issue.resourceDetails,
31031
31007
  taskTotals: issue.taskTotals,
31032
- pipelineBucket: membership.bucket,
31033
- resourceDrift: !membership.inPipeline
31008
+ pipelineBucket: membership?.bucket,
31009
+ specOnlyPlanned: membership ? membership.bucket === "planned_backlog" && membership.reasons.includes("open issue with an xBRIEF spec but no branch/PR — planned work whose plan encodes code paths that age; needs starting or re-planning") : void 0,
31010
+ resourceDrift: membership ? !membership.inPipeline : void 0
31034
31011
  };
31035
- }).sort((a, b) => a.issueId.localeCompare(b.issueId));
31012
+ }).sort((a, b) => compareIssueIds(a.issueId, b.issueId));
31036
31013
  }
31037
31014
  function toPublicResourceIssue(issue) {
31038
31015
  return {
@@ -31041,28 +31018,42 @@ function toPublicResourceIssue(issue) {
31041
31018
  resourceDetails: summarizeResourceDetails(issue.resourceDetails)
31042
31019
  };
31043
31020
  }
31044
- function refreshResourceAllocatedIssues() {
31045
- if (resourceIssuesRefreshPromise) return resourceIssuesRefreshPromise;
31046
- resourceIssuesRefreshPromise = computeResourceAllocatedIssues().then((issues) => {
31047
- cachedDetailedResourceIssues = issues;
31048
- const publicIssues = issues.map(toPublicResourceIssue);
31049
- cachedResourceIssues = {
31050
- value: publicIssues,
31051
- computedAt: Date.now()
31052
- };
31053
- return publicIssues;
31054
- }).finally(() => {
31055
- resourceIssuesRefreshPromise = null;
31021
+ function rebuildCombinedResourceSnapshot() {
31022
+ const detailed = [...projectResourceSnapshots.values()].flatMap((snapshot) => snapshot.detailed).sort((a, b) => compareIssueIds(a.issueId, b.issueId));
31023
+ const publicIssues = detailed.map(toPublicResourceIssue);
31024
+ cachedDetailedResourceIssues = detailed;
31025
+ cachedResourceIssues = {
31026
+ value: publicIssues,
31027
+ computedAt: Math.max(0, ...[...projectResourceSnapshots.values()].map((snapshot) => snapshot.computedAt))
31028
+ };
31029
+ return publicIssues;
31030
+ }
31031
+ function publishProjectResourceSnapshot(project, issues) {
31032
+ projectResourceSnapshots.set(project.path, {
31033
+ detailed: issues,
31034
+ public: issues.map(toPublicResourceIssue),
31035
+ computedAt: Date.now()
31056
31036
  });
31057
- return resourceIssuesRefreshPromise;
31037
+ rebuildCombinedResourceSnapshot();
31058
31038
  }
31059
- async function getCachedResourceAllocatedIssues() {
31060
- if (cachedResourceIssues && Date.now() - cachedResourceIssues.computedAt < RESOURCE_DISCOVERY_TTL_MS) return cachedResourceIssues.value;
31061
- if (cachedResourceIssues) {
31062
- refreshResourceAllocatedIssues().catch(() => {});
31063
- return cachedResourceIssues.value;
31039
+ /** Refresh only the requested projects, capturing fleet-wide signals once for the batch. */
31040
+ async function refreshResourceAllocatedProjects(projects, options = {}) {
31041
+ if (projects.length === 0) return cachedResourceIssues?.value ?? [];
31042
+ const sharedSignals = await captureSharedResourceSignals();
31043
+ const failures = [];
31044
+ for (const project of projects) try {
31045
+ if (options.refreshMembership !== false) await refreshMembershipSnapshotsForProjects([project]);
31046
+ publishProjectResourceSnapshot(project, await computeResourceAllocatedIssues([project], sharedSignals));
31047
+ } catch (error) {
31048
+ const failure = error instanceof Error ? error : new Error(String(error));
31049
+ failures.push(failure);
31050
+ console.warn(`[resource-discovery] refresh failed for ${project.name ?? project.path}; keeping last-good snapshot:`, failure.message);
31064
31051
  }
31065
- return refreshResourceAllocatedIssues();
31052
+ if (failures.length > 0) throw new AggregateError(failures, `${failures.length} project resource refresh(es) failed`);
31053
+ return cachedResourceIssues?.value ?? [];
31054
+ }
31055
+ async function getCachedResourceAllocatedIssues() {
31056
+ return cachedResourceIssues?.value ?? [];
31066
31057
  }
31067
31058
  function sanitizeResourceAllocatedIssues(issues) {
31068
31059
  return issues.map((issue) => ({
@@ -31078,7 +31069,7 @@ function sanitizeResourceAllocatedIssues(issues) {
31078
31069
  state: pr.state,
31079
31070
  isDraft: pr.isDraft
31080
31071
  })),
31081
- hasVbrief: issue.resourceDetails.hasVbrief,
31072
+ hasXbrief: issue.resourceDetails.hasXbrief,
31082
31073
  hasTasks: issue.resourceDetails.hasTasks,
31083
31074
  dockerContainerCount: issue.resourceDetails.dockerContainerCount,
31084
31075
  actualBranch: issue.resourceDetails.actualBranch,
@@ -31101,10 +31092,7 @@ function toPublicResourceDetailIdentifiers(details) {
31101
31092
  async function getResourceDetailIdentifiers(issueId) {
31102
31093
  const normalizedIssueId = issueId.toUpperCase();
31103
31094
  const cachedMatch = cachedDetailedResourceIssues?.find((entry) => entry.issueId === normalizedIssueId);
31104
- if (cachedMatch) return toPublicResourceDetailIdentifiers(cachedMatch.resourceDetails);
31105
- await refreshResourceAllocatedIssues();
31106
- const refreshedMatch = cachedDetailedResourceIssues?.find((entry) => entry.issueId === normalizedIssueId);
31107
- return refreshedMatch ? toPublicResourceDetailIdentifiers(refreshedMatch.resourceDetails) : null;
31095
+ return cachedMatch ? toPublicResourceDetailIdentifiers(cachedMatch.resourceDetails) : null;
31108
31096
  }
31109
31097
  function groupResourceAllocatedIssuesByProject(issues) {
31110
31098
  const projectTree = /* @__PURE__ */ new Map();
@@ -31122,7 +31110,7 @@ function groupResourceAllocatedIssuesByProject(issues) {
31122
31110
  }
31123
31111
  return [...projectTree.values()].map((project) => ({
31124
31112
  ...project,
31125
- features: project.features.sort((a, b) => a.issueId.localeCompare(b.issueId))
31113
+ features: project.features.sort((a, b) => compareIssueIds(a.issueId, b.issueId))
31126
31114
  })).sort((a, b) => a.name.localeCompare(b.name));
31127
31115
  }
31128
31116
  //#endregion
@@ -31308,7 +31296,7 @@ function getIssueTasks(id) {
31308
31296
  };
31309
31297
  });
31310
31298
  const doc = workspacePath ? readWorkspacePlanSync(workspacePath) : null;
31311
- if (!doc) return jsonResponse({ error: `The vBRIEF for ${id} is missing or unreadable.` }, { status: 404 });
31299
+ if (!doc) return jsonResponse({ error: `The xBRIEF for ${id} is missing or unreadable.` }, { status: 404 });
31312
31300
  const record = projectPath ? readIssueRecordSync({
31313
31301
  name: resolvedProject?.projectName ?? id,
31314
31302
  path: projectPath
@@ -31401,11 +31389,12 @@ init_tracker_config();
31401
31389
  init_agents$1();
31402
31390
  init_pan_dir();
31403
31391
  init_projects();
31392
+ init_review_status();
31404
31393
  init_remote_agents();
31405
31394
  init_tracker_utils();
31406
31395
  init_tmux();
31407
31396
  init_io();
31408
- const execFileAsync$17 = promisify(execFile);
31397
+ const execFileAsync$16 = promisify(execFile);
31409
31398
  function getIssueDataService$9() {
31410
31399
  return getSharedIssueService();
31411
31400
  }
@@ -31462,12 +31451,12 @@ async function completePlanningArtifacts(options) {
31462
31451
  const workspacePlanPath = await Effect.runPromise(Effect.gen(function* () {
31463
31452
  return (yield* findWorkspaceDraftPlan(workspacePath)) ?? (yield* findPlan(workspacePath));
31464
31453
  }));
31465
- if (!workspacePlanPath) throw new Error(`No workspace vBRIEF found for ${upperIssueId} at ${workspacePath}/.pan/spec.vbrief.json`);
31454
+ if (!workspacePlanPath) throw new Error(`No workspace xBRIEF found for ${upperIssueId} at ${workspacePath}/.overdeck/spec.vbrief.json`);
31466
31455
  const workspaceDoc = await Effect.runPromise(readPlan(workspacePlanPath));
31467
31456
  const workspaceIssueId = workspaceDoc.plan?.id;
31468
- if (workspaceIssueId && workspaceIssueId.toLowerCase() !== issueLower) throw new Error(`Workspace vBRIEF is for ${workspaceIssueId.toUpperCase()}, not ${upperIssueId}`);
31457
+ if (workspaceIssueId && workspaceIssueId.toLowerCase() !== issueLower) throw new Error(`Workspace xBRIEF is for ${workspaceIssueId.toUpperCase()}, not ${upperIssueId}`);
31469
31458
  assertPlanQuality(workspaceDoc);
31470
- emitCompletePlanningPhase(upperIssueId, "specWrite", "start", "writing proposed vBRIEF spec", { projectPath });
31459
+ emitCompletePlanningPhase(upperIssueId, "specWrite", "start", "writing proposed xBRIEF spec", { projectPath });
31471
31460
  const existingSpec = await Effect.runPromise(findSpecByIssue(projectPath, upperIssueId));
31472
31461
  let proposed;
31473
31462
  try {
@@ -31482,7 +31471,7 @@ async function completePlanningArtifacts(options) {
31482
31471
  path: e.path,
31483
31472
  filename: e.filename
31484
31473
  }));
31485
- emitCompletePlanningPhase(upperIssueId, "specWrite", "success", "proposed vBRIEF spec written", {
31474
+ emitCompletePlanningPhase(upperIssueId, "specWrite", "success", "proposed xBRIEF spec written", {
31486
31475
  path: proposed.path,
31487
31476
  filename: proposed.filename
31488
31477
  });
@@ -31491,7 +31480,7 @@ async function completePlanningArtifacts(options) {
31491
31480
  throw error;
31492
31481
  }
31493
31482
  const planItemCount = workspaceDoc.plan.items?.length ?? 0;
31494
- if (planItemCount === 0) throw new Error(`The vBRIEF for ${upperIssueId} contains no implementation items.`);
31483
+ if (planItemCount === 0) throw new Error(`The xBRIEF for ${upperIssueId} contains no implementation items.`);
31495
31484
  return {
31496
31485
  proposed,
31497
31486
  taskCount: planItemCount,
@@ -31531,7 +31520,7 @@ async function commitWorkspaceRecordBeforeAutoSpawn(gitRoot, issueId) {
31531
31520
  } catch {}
31532
31521
  const recordPath = join(".pan", "records", `${issueLower}.json`);
31533
31522
  try {
31534
- const { stdout: statusOut } = await execFileAsync$17("git", [
31523
+ const { stdout: statusOut } = await execFileAsync$16("git", [
31535
31524
  "status",
31536
31525
  "--porcelain",
31537
31526
  "--",
@@ -31541,7 +31530,7 @@ async function commitWorkspaceRecordBeforeAutoSpawn(gitRoot, issueId) {
31541
31530
  encoding: "utf-8"
31542
31531
  });
31543
31532
  if (!statusOut.trim()) return;
31544
- await execFileAsync$17("git", [
31533
+ await execFileAsync$16("git", [
31545
31534
  "add",
31546
31535
  "--",
31547
31536
  recordPath
@@ -31550,7 +31539,7 @@ async function commitWorkspaceRecordBeforeAutoSpawn(gitRoot, issueId) {
31550
31539
  encoding: "utf-8"
31551
31540
  });
31552
31541
  try {
31553
- await execFileAsync$17("git", [
31542
+ await execFileAsync$16("git", [
31554
31543
  "diff",
31555
31544
  "--cached",
31556
31545
  "--quiet",
@@ -31562,7 +31551,7 @@ async function commitWorkspaceRecordBeforeAutoSpawn(gitRoot, issueId) {
31562
31551
  });
31563
31552
  return;
31564
31553
  } catch {}
31565
- await execFileAsync$17("git", [
31554
+ await execFileAsync$16("git", [
31566
31555
  "commit",
31567
31556
  "-m",
31568
31557
  `chore(records): update ${issueId.toUpperCase()} per-issue record before auto-start`,
@@ -31584,25 +31573,59 @@ function getInternalDashboardOrigin() {
31584
31573
  }
31585
31574
  function classifyAutoSpawnSkip(status, body) {
31586
31575
  const error = typeof body["error"] === "string" ? body["error"] : "";
31576
+ if (status === 401 || status === 403) return "unauthorized";
31587
31577
  if (body["stackHealth"] || /workspace docker stack/i.test(error)) return "stack-unhealthy";
31588
31578
  if (body["paused"] === true) return "paused";
31589
31579
  if (body["troubled"] === true) return "troubled";
31590
31580
  if (body["guardrails"] || body["requiresAcknowledgement"] === true || status === 409) return "guardrails";
31591
31581
  return "spawn-failed";
31592
31582
  }
31583
+ function resolveCompletePlanningTerminalStatus(autoSpawnRequested, autoSpawnResult) {
31584
+ return autoSpawnRequested && autoSpawnResult?.workAgentSpawned !== true ? "failure" : "success";
31585
+ }
31586
+ async function recordPlanningAutoHandoffFailure(options) {
31587
+ const skipReason = options.result.workAgentSkipReason ?? "spawn-failed";
31588
+ const error = options.result.workAgentError ?? `Work agent startup failed: ${skipReason}`;
31589
+ const details = {
31590
+ workAgentSkipReason: skipReason,
31591
+ workAgentError: error
31592
+ };
31593
+ await Effect.runPromise(options.eventStore.append({
31594
+ type: "planning.failed",
31595
+ timestamp: (options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString()))(),
31596
+ payload: {
31597
+ issueId: options.issueId,
31598
+ error,
31599
+ stage: "auto-handoff",
31600
+ ...details
31601
+ }
31602
+ }));
31603
+ (options.markStuck ?? markWorkspaceStuck)(options.issueId, "planning_auto_handoff_failed", details);
31604
+ (options.emitActivity ?? emitActivityEntrySync)({
31605
+ source: "plan",
31606
+ level: "error",
31607
+ message: `${options.issueId} planning complete, but work-agent startup failed: ${error}`,
31608
+ issueId: options.issueId,
31609
+ details: JSON.stringify(details)
31610
+ });
31611
+ return error;
31612
+ }
31593
31613
  async function completePlanningAutoSpawn(options) {
31594
31614
  if (options.autoSpawn !== true) {
31595
31615
  emitCompletePlanningPhase(options.issueId, "autoSpawn", "skipped", "autoSpawn not requested");
31596
31616
  return null;
31597
31617
  }
31598
31618
  const dashboardOrigin = options.dashboardOrigin ?? getInternalDashboardOrigin();
31619
+ const internalToken = getInternalTokenSync();
31620
+ const internalTokenHeaders = internalToken ? { [INTERNAL_TOKEN_HEADER]: internalToken } : {};
31599
31621
  emitCompletePlanningPhase(options.issueId, "autoSpawn", "start", "posting work-agent spawn request", { dashboardOrigin });
31600
31622
  try {
31601
31623
  const response = await (options.fetchImpl ?? fetch)(new URL("/api/agents", dashboardOrigin), {
31602
31624
  method: "POST",
31603
31625
  headers: {
31604
31626
  "content-type": "application/json",
31605
- origin: dashboardOrigin
31627
+ origin: dashboardOrigin,
31628
+ ...internalTokenHeaders
31606
31629
  },
31607
31630
  body: JSON.stringify({
31608
31631
  issueId: options.issueId,
@@ -31623,7 +31646,10 @@ async function completePlanningAutoSpawn(options) {
31623
31646
  if (skipReason === "stack-unhealthy") {
31624
31647
  const recovery = await (options.fetchImpl ?? fetch)(new URL(`/api/workspaces/${encodeURIComponent(options.issueId)}/rebuild-and-start`, dashboardOrigin), {
31625
31648
  method: "POST",
31626
- headers: { origin: dashboardOrigin }
31649
+ headers: {
31650
+ origin: dashboardOrigin,
31651
+ ...internalTokenHeaders
31652
+ }
31627
31653
  });
31628
31654
  const recoveryBody = await recovery.json().catch(() => ({}));
31629
31655
  if (recovery.ok && recoveryBody["success"] !== false) {
@@ -31766,6 +31792,19 @@ async function completePlanningForIssue(options) {
31766
31792
  }
31767
31793
  emitCompletePlanningPhase(id, "prdGate", "success", `found ${prdGate.path} (${prdGate.lineCount} lines)`);
31768
31794
  }
31795
+ try {
31796
+ const draftPromotion = await Effect.runPromise(promoteWorkspacePrdDraft({
31797
+ projectRoot: projectPath,
31798
+ workspacePath,
31799
+ issueId: id
31800
+ }));
31801
+ if (draftPromotion.promoted) emitCompletePlanningPhase(id, "prdPromote", "success", `promoted ${draftPromotion.source} -> ${draftPromotion.path}`);
31802
+ else emitCompletePlanningPhase(id, "prdPromote", "skipped", draftPromotion.reason);
31803
+ } catch (error) {
31804
+ const reason = error instanceof Error ? error.message : String(error);
31805
+ emitCompletePlanningPhase(id, "prdPromote", "failure", reason);
31806
+ return jsonResponse({ error: `PRD draft promotion failed for ${id.toUpperCase()}: ${reason}` }, { status: 500 });
31807
+ }
31769
31808
  const workspacePlanPath = await (async () => await Effect.runPromise(findWorkspaceDraftPlan(workspacePath)) ?? await Effect.runPromise(findPlan(workspacePath)))();
31770
31809
  if (workspacePlanPath) {
31771
31810
  const workspaceDoc = await Effect.runPromise(readPlan(workspacePlanPath));
@@ -31773,7 +31812,7 @@ async function completePlanningForIssue(options) {
31773
31812
  assertPlanQuality(workspaceDoc);
31774
31813
  } catch (error) {
31775
31814
  if (error instanceof PlanQualityLintError) return jsonResponse({
31776
- error: "vBRIEF quality lint failed",
31815
+ error: "xBRIEF quality lint failed",
31777
31816
  qualityIssues: error.issues
31778
31817
  }, { status: 422 });
31779
31818
  throw error;
@@ -31790,7 +31829,7 @@ async function completePlanningForIssue(options) {
31790
31829
  issueId: id
31791
31830
  });
31792
31831
  console.log(`[complete-planning] Wrote pan spec to ${proposed.path}`);
31793
- console.log(`[complete-planning] Finalized ${taskCount} vBRIEF tasks for ${upperIssueId}`);
31832
+ console.log(`[complete-planning] Finalized ${taskCount} xBRIEF tasks for ${upperIssueId}`);
31794
31833
  const project = findProjectByPathSync(projectPath);
31795
31834
  const migrated = project ? await isStateMigrated(project) : false;
31796
31835
  const filesToStage = completePlanningFilesToStage(projectPath, proposed.filename, migrated);
@@ -31798,7 +31837,7 @@ async function completePlanningForIssue(options) {
31798
31837
  if (migrated) await Effect.runPromise(flushAutoCommits(projectPath));
31799
31838
  else if (!projectIsGitRepo) console.log(`[complete-planning] Project root ${projectPath} is not a git repository (polyrepo) — pan spec updated on disk but not committed`);
31800
31839
  else {
31801
- const { stdout: branchStdout } = await execFileAsync$17("git", [
31840
+ const { stdout: branchStdout } = await execFileAsync$16("git", [
31802
31841
  "rev-parse",
31803
31842
  "--abbrev-ref",
31804
31843
  "HEAD"
@@ -31808,7 +31847,7 @@ async function completePlanningForIssue(options) {
31808
31847
  });
31809
31848
  const currentBranch = branchStdout.trim();
31810
31849
  if (currentBranch === "main") {
31811
- await execFileAsync$17("git", [
31850
+ await execFileAsync$16("git", [
31812
31851
  "add",
31813
31852
  "--",
31814
31853
  ...filesToStage
@@ -31817,7 +31856,7 @@ async function completePlanningForIssue(options) {
31817
31856
  encoding: "utf-8"
31818
31857
  });
31819
31858
  try {
31820
- await execFileAsync$17("git", [
31859
+ await execFileAsync$16("git", [
31821
31860
  "diff",
31822
31861
  "--cached",
31823
31862
  "--quiet",
@@ -31828,10 +31867,10 @@ async function completePlanningForIssue(options) {
31828
31867
  encoding: "utf-8"
31829
31868
  });
31830
31869
  } catch {
31831
- await execFileAsync$17("git", [
31870
+ await execFileAsync$16("git", [
31832
31871
  "commit",
31833
31872
  "-m",
31834
- `chore(scope): propose ${upperIssueId} vBRIEF`,
31873
+ `chore(scope): propose ${upperIssueId} xBRIEF`,
31835
31874
  "--no-verify",
31836
31875
  "--",
31837
31876
  ...filesToStage
@@ -31841,7 +31880,7 @@ async function completePlanningForIssue(options) {
31841
31880
  });
31842
31881
  console.log(`[complete-planning] Committed pan spec on main for ${upperIssueId}`);
31843
31882
  try {
31844
- const { stdout: remotes } = await execFileAsync$17("git", ["remote"], {
31883
+ const { stdout: remotes } = await execFileAsync$16("git", ["remote"], {
31845
31884
  cwd: projectPath,
31846
31885
  encoding: "utf-8"
31847
31886
  });
@@ -31854,16 +31893,16 @@ async function completePlanningForIssue(options) {
31854
31893
  }
31855
31894
  } else console.log(`[complete-planning] Project root not on main (${currentBranch}) — pan spec updated on disk but not committed on main`);
31856
31895
  }
31857
- if (!existsSync$1(join(gitRoot, ".git"))) await execFileAsync$17("git", ["init"], {
31896
+ if (!existsSync$1(join(gitRoot, ".git"))) await execFileAsync$16("git", ["init"], {
31858
31897
  cwd: gitRoot,
31859
31898
  encoding: "utf-8"
31860
31899
  });
31861
- for (const args of completePlanningWorkspaceGitAddCommands(gitRoot, migrated)) await execFileAsync$17("git", args, {
31900
+ for (const args of completePlanningWorkspaceGitAddCommands(gitRoot, migrated)) await execFileAsync$16("git", args, {
31862
31901
  cwd: gitRoot,
31863
31902
  encoding: "utf-8"
31864
31903
  });
31865
31904
  try {
31866
- await execFileAsync$17("git", [
31905
+ await execFileAsync$16("git", [
31867
31906
  "diff",
31868
31907
  "--cached",
31869
31908
  "--quiet"
@@ -31872,7 +31911,7 @@ async function completePlanningForIssue(options) {
31872
31911
  encoding: "utf-8"
31873
31912
  });
31874
31913
  } catch {
31875
- await execFileAsync$17("git", [
31914
+ await execFileAsync$16("git", [
31876
31915
  "commit",
31877
31916
  "-m",
31878
31917
  `chore(plan): complete planning for ${id}`,
@@ -31883,7 +31922,7 @@ async function completePlanningForIssue(options) {
31883
31922
  });
31884
31923
  }
31885
31924
  try {
31886
- const { stdout: remotes } = await execFileAsync$17("git", ["remote"], {
31925
+ const { stdout: remotes } = await execFileAsync$16("git", ["remote"], {
31887
31926
  cwd: gitRoot,
31888
31927
  encoding: "utf-8"
31889
31928
  });
@@ -31948,19 +31987,6 @@ async function completePlanningForIssue(options) {
31948
31987
  });
31949
31988
  } catch {}
31950
31989
  invalidateAgentsCache();
31951
- emitActivityEntrySync({
31952
- source: "plan",
31953
- level: "info",
31954
- message: `${id} planning complete — ready for work`,
31955
- issueId: id
31956
- });
31957
- emitActivityTtsSync({
31958
- utterance: `${id} planning complete, ready for work`,
31959
- priority: 2,
31960
- issueId: id,
31961
- source: "planning-agent",
31962
- eventType: "planning.complete"
31963
- });
31964
31990
  const effectiveAutoSpawn = autoSpawn || completePlanningLease.autoSpawnRequested();
31965
31991
  if (effectiveAutoSpawn && workspacePath) await commitWorkspaceRecordBeforeAutoSpawn(workspacePath, id);
31966
31992
  const autoSpawnResult = await completePlanningAutoSpawnAndKill({
@@ -31969,7 +31995,29 @@ async function completePlanningForIssue(options) {
31969
31995
  skipKill,
31970
31996
  sessionName
31971
31997
  });
31972
- emitCompletePlanningPhase(id, "terminal", "success", autoSpawnResult?.workAgentSpawned ? "planning complete and work agent spawn requested" : autoSpawnResult?.workAgentSkipReason ?? "planning complete", {
31998
+ const autoHandoffFailed = effectiveAutoSpawn && autoSpawnResult?.workAgentSpawned !== true;
31999
+ let autoHandoffError;
32000
+ if (autoHandoffFailed && autoSpawnResult) autoHandoffError = await recordPlanningAutoHandoffFailure({
32001
+ issueId: id,
32002
+ result: autoSpawnResult,
32003
+ eventStore
32004
+ });
32005
+ else {
32006
+ emitActivityEntrySync({
32007
+ source: "plan",
32008
+ level: "info",
32009
+ message: autoSpawnResult?.workAgentSpawned ? `${id} planning complete — work-agent startup accepted` : `${id} planning complete — ready for work`,
32010
+ issueId: id
32011
+ });
32012
+ emitActivityTtsSync({
32013
+ utterance: autoSpawnResult?.workAgentSpawned ? `${id} planning complete, work agent starting` : `${id} planning complete, ready for work`,
32014
+ priority: 2,
32015
+ issueId: id,
32016
+ source: "planning-agent",
32017
+ eventType: "planning.complete"
32018
+ });
32019
+ }
32020
+ emitCompletePlanningPhase(id, "terminal", resolveCompletePlanningTerminalStatus(effectiveAutoSpawn, autoSpawnResult), autoSpawnResult?.workAgentSpawned ? "planning complete and work agent spawn requested" : autoSpawnResult?.workAgentSkipReason ?? "planning complete", {
31973
32021
  autoSpawn: effectiveAutoSpawn,
31974
32022
  workAgentSpawned: autoSpawnResult?.workAgentSpawned ?? false,
31975
32023
  workAgentSkipReason: autoSpawnResult?.workAgentSkipReason
@@ -31981,7 +32029,7 @@ async function completePlanningForIssue(options) {
31981
32029
  gitPushed,
31982
32030
  ...taskWarning ? { taskWarning } : {},
31983
32031
  ...autoSpawnResult ?? {},
31984
- message: autoSpawnResult?.workAgentSpawned ? "Planning complete and work agent spawn requested" : gitPushed ? "Planning complete and pushed to git - ready for execution" : "Planning complete - ready for execution"
32032
+ message: autoHandoffFailed ? `Planning complete, but work-agent startup failed (${autoSpawnResult?.workAgentSkipReason ?? "spawn-failed"}): ${autoHandoffError}` : autoSpawnResult?.workAgentSpawned ? "Planning complete and work agent spawn requested" : gitPushed ? "Planning complete and pushed to git - ready for execution" : "Planning complete - ready for execution"
31985
32033
  });
31986
32034
  } finally {
31987
32035
  completePlanningLease.release();
@@ -32063,7 +32111,7 @@ init_tracker_utils();
32063
32111
  init_agents$1();
32064
32112
  init_issue_id();
32065
32113
  const execAsync$8 = promisify(exec);
32066
- const execFileAsync$16 = promisify(execFile);
32114
+ const execFileAsync$15 = promisify(execFile);
32067
32115
  function isGitHubIssue$4(issueId) {
32068
32116
  const resolved = resolveGitHubIssueSync(issueId);
32069
32117
  if (resolved.isGitHub) return {
@@ -32102,7 +32150,7 @@ async function closeIssuePullRequest(issueId, reason = "Canceled via Overdeck")
32102
32150
  if (!githubCheck.isGitHub || !githubCheck.owner || !githubCheck.repo) return ["No GitHub PR to close"];
32103
32151
  const branchName = `feature/${issueId.toLowerCase()}`;
32104
32152
  try {
32105
- const { stdout: prListRaw } = await execFileAsync$16("gh", [
32153
+ const { stdout: prListRaw } = await execFileAsync$15("gh", [
32106
32154
  "pr",
32107
32155
  "list",
32108
32156
  "--repo",
@@ -32121,7 +32169,7 @@ async function closeIssuePullRequest(issueId, reason = "Canceled via Overdeck")
32121
32169
  });
32122
32170
  const prNumber = prListRaw.trim();
32123
32171
  if (!prNumber) return ["No open PR found for branch"];
32124
- await execFileAsync$16("gh", [
32172
+ await execFileAsync$15("gh", [
32125
32173
  "pr",
32126
32174
  "close",
32127
32175
  prNumber,
@@ -32134,7 +32182,7 @@ async function closeIssuePullRequest(issueId, reason = "Canceled via Overdeck")
32134
32182
  timeout: 15e3
32135
32183
  });
32136
32184
  try {
32137
- const { setReviewStatusSync } = await import("./review-status-DXeqFpk5.js");
32185
+ const { setReviewStatusSync } = await import("./review-status-C6n6-9f_.js");
32138
32186
  setReviewStatusSync(issueId.toUpperCase(), { prUrl: void 0 });
32139
32187
  } catch {}
32140
32188
  return [`Closed PR #${prNumber} on ${githubCheck.owner}/${githubCheck.repo}`];
@@ -32188,7 +32236,7 @@ async function runDestructiveIssueLifecycle(id, mode, opts = {}) {
32188
32236
  const { ctx, projectConfig } = buildLifecycleContext(id, getIssueDataService$8().getIssueSource(id) ?? void 0);
32189
32237
  const deleteWorkspace = opts.deleteWorkspace ?? true;
32190
32238
  cleanupLog.push(...await closeIssuePullRequest(id, mode === "cancel" ? "Canceled via Overdeck" : "Reset to Todo via Overdeck"));
32191
- const { resetToTodo, cancelIssueWorkflow } = await import("./lifecycle-CE7619Xw.js");
32239
+ const { resetToTodo, cancelIssueWorkflow } = await import("./lifecycle-sycO16hj.js");
32192
32240
  const workflow = mode === "cancel" ? cancelIssueWorkflow : resetToTodo;
32193
32241
  const result = await Effect.runPromise(workflow(ctx, {
32194
32242
  deleteWorkspace,
@@ -32203,16 +32251,16 @@ async function runDestructiveIssueLifecycle(id, mode, opts = {}) {
32203
32251
  }));
32204
32252
  cleanupLog.push(...result.steps.flatMap((step) => step.details || [step.error].filter(Boolean)));
32205
32253
  if (mode === "cancel") try {
32206
- const { transitionVBriefOnMain } = await import("./lifecycle-io-CUpsxG0p.js");
32207
- const tx = await Effect.runPromise(transitionVBriefOnMain(ctx.projectPath, id, "cancelled", "cancelled", `scope: cancel ${id.toUpperCase()} vBRIEF`));
32208
- if (tx.moved) cleanupLog.push(`vBRIEF moved ${tx.fromDir} → cancelled`);
32209
- if (tx.committed) cleanupLog.push(`Committed vBRIEF cancellation on main`);
32254
+ const { transitionXBriefOnMain } = await import("./lifecycle-io-Bsnr2K4F.js");
32255
+ const tx = await Effect.runPromise(transitionXBriefOnMain(ctx.projectPath, id, "cancelled", "cancelled", `scope: cancel ${id.toUpperCase()} xBRIEF`));
32256
+ if (tx.moved) cleanupLog.push(`xBRIEF moved ${tx.fromDir} → cancelled`);
32257
+ if (tx.committed) cleanupLog.push(`Committed xBRIEF cancellation on main`);
32210
32258
  } catch (err) {
32211
- cleanupLog.push(`vBRIEF cancel transition failed (non-fatal): ${err?.message ?? err}`);
32259
+ cleanupLog.push(`xBRIEF cancel transition failed (non-fatal): ${err?.message ?? err}`);
32212
32260
  }
32213
32261
  try {
32214
- const { killAllReviewerSessions } = await import("./review-agent-CSswH985.js");
32215
- const { resolveProjectFromIssueSync } = await import("./projects-IRHJIPYC.js");
32262
+ const { killAllReviewerSessions } = await import("./review-agent-DJRO8EG8.js");
32263
+ const { resolveProjectFromIssueSync } = await import("./projects-9SkRpES9.js");
32216
32264
  const projectKey = resolveProjectFromIssueSync(id)?.projectKey;
32217
32265
  if (projectKey) {
32218
32266
  const { killed } = await Effect.runPromise(killAllReviewerSessions(projectKey, id.toUpperCase()));
@@ -32226,7 +32274,7 @@ async function runDestructiveIssueLifecycle(id, mode, opts = {}) {
32226
32274
  cleanupLog.push("Cleared review status");
32227
32275
  } catch {}
32228
32276
  try {
32229
- const { resetPostMergeState } = await import("./merge-agent-CnORPiri.js");
32277
+ const { resetPostMergeState } = await import("./merge-agent-BQM3a8z5.js");
32230
32278
  resetPostMergeState(id);
32231
32279
  resetPostMergeState(id.toUpperCase());
32232
32280
  cleanupLog.push("Cleared merge state");
@@ -32246,7 +32294,7 @@ function closeIssueTransition(options) {
32246
32294
  const { issueId, body, eventStore } = options;
32247
32295
  const { reason } = body;
32248
32296
  const projectPath = getProjectPath$3(void 0, extractPrefixSync(issueId) ?? issueId.split("-")[0]);
32249
- const { close: closeWorkflow } = yield* Effect.promise(() => import("./lifecycle-CE7619Xw.js"));
32297
+ const { close: closeWorkflow } = yield* Effect.promise(() => import("./lifecycle-sycO16hj.js"));
32250
32298
  const githubCheck = isGitHubIssue$4(issueId);
32251
32299
  const issueDataService = getIssueDataService$8();
32252
32300
  const issueSource = issueDataService.getIssueSource(issueId);
@@ -32513,7 +32561,7 @@ function reopenIssueTransition(options) {
32513
32561
  else clearReviewStatus(id.toUpperCase());
32514
32562
  } catch {}
32515
32563
  try {
32516
- const { resetPostMergeState } = await import("./merge-agent-CnORPiri.js");
32564
+ const { resetPostMergeState } = await import("./merge-agent-BQM3a8z5.js");
32517
32565
  resetPostMergeState(id);
32518
32566
  resetPostMergeState(id.toUpperCase());
32519
32567
  } catch {}
@@ -32577,7 +32625,7 @@ function moveIssueStatus(options) {
32577
32625
  "done"
32578
32626
  ];
32579
32627
  if (!targetStatus || !validStatuses.includes(targetStatus)) return jsonResponse({ error: `Invalid targetStatus. Must be one of: ${validStatuses.join(", ")}` }, { status: 400 });
32580
- const { updateShadowState } = yield* Effect.promise(() => import("./shadow-state-CDxEuPlE.js"));
32628
+ const { updateShadowState } = yield* Effect.promise(() => import("./shadow-state-C2_epgx2.js"));
32581
32629
  const issueState = {
32582
32630
  backlog: "open",
32583
32631
  todo: "open",
@@ -32804,7 +32852,7 @@ async function copySettingsToWorkspace(id) {
32804
32852
  success: false,
32805
32853
  error: "Workspace not found"
32806
32854
  }, { status: 404 });
32807
- const { copyOverdeckSettingsToWorkspaceSync } = await import("./workspace-manager-CcujONCR.js");
32855
+ const { copyOverdeckSettingsToWorkspaceSync } = await import("./workspace-manager-ZTdJAy9M.js");
32808
32856
  const result = copyOverdeckSettingsToWorkspaceSync(workspacePath);
32809
32857
  return jsonResponse({
32810
32858
  success: result.errors.length === 0 || result.copied.length > 0,
@@ -32835,7 +32883,7 @@ function generateTasksForIssue(id) {
32835
32883
  const plan = readWorkspacePlanSync(join(projectPath, "workspaces", `feature-${issueLower}`));
32836
32884
  if (!plan) return jsonResponse({
32837
32885
  success: false,
32838
- error: `No vBRIEF spec found on main for ${id} — run planning first.`
32886
+ error: `No xBRIEF spec found on main for ${id} — run planning first.`
32839
32887
  }, { status: 409 });
32840
32888
  return jsonResponse({
32841
32889
  success: true,
@@ -32858,7 +32906,7 @@ init_tracker_utils();
32858
32906
  init_tmux();
32859
32907
  init_typed_errors();
32860
32908
  const execAsync$6 = promisify(exec);
32861
- const execFileAsync$15 = promisify(execFile);
32909
+ const execFileAsync$14 = promisify(execFile);
32862
32910
  function getIssueDataService$6() {
32863
32911
  return getSharedIssueService();
32864
32912
  }
@@ -33158,7 +33206,7 @@ function abortPlanningForIssue(options) {
33158
33206
  const featureWorkspacePath = join(projectPath, "workspaces", `feature-${issueIdentifier.toLowerCase()}`);
33159
33207
  const plainWorkspacePath = join(projectPath, "workspaces", issueIdentifier.toLowerCase());
33160
33208
  if (existsSync$1(existsSync$1(featureWorkspacePath) ? featureWorkspacePath : plainWorkspacePath)) {
33161
- await execFileAsync$15("pan", [
33209
+ await execFileAsync$14("pan", [
33162
33210
  "workspace",
33163
33211
  "destroy",
33164
33212
  issueIdentifier.toLowerCase(),
@@ -33267,7 +33315,7 @@ function restartFromPlan(options) {
33267
33315
  });
33268
33316
  const resetResult = yield* Effect.promise(async () => {
33269
33317
  try {
33270
- const { runGitResetHard } = await import("./dangerous-git-ops-BebB-61h.js");
33318
+ const { runGitResetHard } = await import("./dangerous-git-ops-CT-IypG3.js");
33271
33319
  async function findPlanningCommit(grep, label) {
33272
33320
  try {
33273
33321
  const { stdout } = await execAsync$6(`git log --grep="${grep.replace(/"/g, "\\\"")}" --format=%H -1`, {
@@ -33720,7 +33768,7 @@ function closeOutIssue(id, opts = {}) {
33720
33768
  }
33721
33769
  const closeOutResult = yield* Effect.promise(async () => {
33722
33770
  try {
33723
- const { closeOut } = await import("./lifecycle-CE7619Xw.js");
33771
+ const { closeOut } = await import("./lifecycle-sycO16hj.js");
33724
33772
  return {
33725
33773
  ok: true,
33726
33774
  result: await Effect.runPromise(closeOut(ctx, {
@@ -33809,7 +33857,7 @@ function bulkCloseOut(body) {
33809
33857
  const invalidIds = issueIds.filter((id) => !isValidIssueId(id));
33810
33858
  if (invalidIds.length > 0) return jsonResponse({ error: `Invalid issue ID format: ${invalidIds.join(", ")}` }, { status: 400 });
33811
33859
  const eventStore = yield* EventStoreService;
33812
- const { closeOut } = yield* Effect.promise(() => import("./lifecycle-CE7619Xw.js"));
33860
+ const { closeOut } = yield* Effect.promise(() => import("./lifecycle-sycO16hj.js"));
33813
33861
  const issueDataService = getIssueDataService$5();
33814
33862
  const tasks = [];
33815
33863
  const agentChecks = yield* withConcurrencyLimit(issueIds.map((id) => Effect.promise(async () => {
@@ -33973,7 +34021,7 @@ init_issue_service_singleton();
33973
34021
  init_domain_services();
33974
34022
  init_linear_client();
33975
34023
  promisify(exec);
33976
- const execFileAsync$14 = promisify(execFile);
34024
+ const execFileAsync$13 = promisify(execFile);
33977
34025
  function getIssueDataService$4() {
33978
34026
  return getSharedIssueService();
33979
34027
  }
@@ -34008,7 +34056,7 @@ const getIssuesRoute = HttpRouter.add("GET", "/api/issues", httpHandler(Effect.g
34008
34056
  }
34009
34057
  }
34010
34058
  const membershipByIssue = /* @__PURE__ */ new Map();
34011
- const results = getPipelineMembershipSnapshotsForProjects([...projects.values()]);
34059
+ const results = readPipelineMembershipSnapshotsForProjects([...projects.values()]);
34012
34060
  const successfulPaths = /* @__PURE__ */ new Set();
34013
34061
  const failedPaths = /* @__PURE__ */ new Set();
34014
34062
  for (const result of results) {
@@ -34035,8 +34083,8 @@ const getIssueShipLogRoute = HttpRouter.add("GET", "/api/issues/:id/ship-log", h
34035
34083
  const id = (yield* HttpRouter.params)["id"] ?? "";
34036
34084
  if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
34037
34085
  return yield* Effect.promise(async () => {
34038
- const { getShipLog } = await import("./ship-log-DDcueaIR.js");
34039
- const { getReviewStatusSync } = await import("./review-status-DXeqFpk5.js");
34086
+ const { getShipLog } = await import("./ship-log-ClSMIzZX.js");
34087
+ const { getReviewStatusSync } = await import("./review-status-C6n6-9f_.js");
34040
34088
  const log = getShipLog(id);
34041
34089
  const rs = getReviewStatusSync(id);
34042
34090
  return jsonResponse({
@@ -34051,8 +34099,8 @@ const getIssueVerificationRoute = HttpRouter.add("GET", "/api/issues/:id/verific
34051
34099
  const id = (yield* HttpRouter.params)["id"] ?? "";
34052
34100
  if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
34053
34101
  return yield* Effect.promise(async () => {
34054
- const { readVerificationArtifact } = await import("./verification-artifact-CrbI4tJE.js");
34055
- const { getReviewStatusSync } = await import("./review-status-DXeqFpk5.js");
34102
+ const { readVerificationArtifact } = await import("./verification-artifact-C-lIHfUa.js");
34103
+ const { getReviewStatusSync } = await import("./review-status-C6n6-9f_.js");
34056
34104
  const { join } = await import("node:path");
34057
34105
  const resolved = resolveProjectFromIssueSync(id);
34058
34106
  const workspacePath = resolved ? join(resolved.projectPath, "workspaces", `feature-${id.toLowerCase()}`) : null;
@@ -34137,7 +34185,7 @@ const postIssueResetToPlannedRoute = HttpRouter.add("POST", "/api/issues/:id/res
34137
34185
  if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
34138
34186
  try {
34139
34187
  const invocation = panCliInvocation(["reset-to-planned", id]);
34140
- const { stdout } = yield* Effect.promise(() => execFileAsync$14(invocation.command, invocation.args, { encoding: "utf8" }));
34188
+ const { stdout } = yield* Effect.promise(() => execFileAsync$13(invocation.command, invocation.args, { encoding: "utf8" }));
34141
34189
  invalidateAgentsCache();
34142
34190
  return jsonResponse({
34143
34191
  success: true,
@@ -34376,7 +34424,9 @@ const getPipelineMembershipRoute = HttpRouter.add("GET", "/api/pipeline/membersh
34376
34424
  if (!projectKey) return jsonResponse({ error: "project query parameter is required" }, { status: 400 });
34377
34425
  const project = getProjectSync(projectKey);
34378
34426
  if (!project) return jsonResponse({ error: `Project not found: ${projectKey}` }, { status: 404 });
34379
- return jsonResponse(yield* Effect.promise(() => getProjectPipelineMembership(project)));
34427
+ const snapshot = readPipelineMembershipSnapshotsForProjects([project])[0];
34428
+ if (snapshot?.memberships) return jsonResponse(snapshot.memberships);
34429
+ return jsonResponse({ error: "Pipeline membership snapshot is loading" }, { status: 503 });
34380
34430
  })));
34381
34431
  const getIssueResourceDetailsRoute = HttpRouter.add("GET", "/api/issues/:id/resource-details", httpHandler(Effect.gen(function* () {
34382
34432
  return yield* getIssueResourceDetails((yield* HttpRouter.params)["id"] ?? "");
@@ -35048,8 +35098,7 @@ const cloisterRouteLayer = Layer.mergeAll(getCloisterStatusRoute, postCloisterSt
35048
35098
  //#region routes/resources/agents-stats.ts
35049
35099
  init_agents$1();
35050
35100
  init_cost_sync();
35051
- init_tmux();
35052
- const execFileAsync$13 = promisify(execFile);
35101
+ init_runtime_census();
35053
35102
  const BURN_WINDOW_MS = 1800 * 1e3;
35054
35103
  function buildAgentStatsSnapshot(options) {
35055
35104
  const nowMs = options.nowMs ?? Date.now();
@@ -35116,27 +35165,19 @@ function getAgentStatsSnapshotEffect(deps = {}) {
35116
35165
  });
35117
35166
  });
35118
35167
  }
35119
- function parseProcessTable(psTable) {
35120
- return psTable.split("\n").map((line) => line.trim()).filter(Boolean).flatMap((line) => {
35121
- const match = line.match(/^(\d+)\s+(\d+)\s+([0-9.]+)\s+(\d+)$/);
35122
- if (!match) return [];
35123
- return [{
35124
- pid: Number(match[1]),
35125
- ppid: Number(match[2]),
35126
- cpuPercent: Number(match[3]),
35127
- rssBytes: Number(match[4]) * 1024
35128
- }];
35129
- });
35130
- }
35131
35168
  async function readBatchedProcessTable() {
35132
- const { stdout } = await execFileAsync$13("ps", ["-eo", "pid=,ppid=,pcpu=,rss="], { encoding: "utf8" });
35133
- return parseProcessTable(stdout);
35169
+ return [...(await getRuntimeCensus()).processesByPid.values()].map((process) => ({
35170
+ pid: process.pid,
35171
+ ppid: process.ppid,
35172
+ cpuPercent: process.cpuPercent,
35173
+ rssBytes: process.rssBytes
35174
+ }));
35134
35175
  }
35135
35176
  function defaultListSessionNames() {
35136
- return listSessions().pipe(Effect.map((sessions) => sessions.map((session) => session.name)));
35177
+ return Effect.promise(async () => [...(await getRuntimeCensus()).sessionNames]);
35137
35178
  }
35138
35179
  function defaultListPanePids(sessionName) {
35139
- return listPaneValues(sessionName, "#{pane_pid}").pipe(Effect.map((values) => values.map((value) => Number(value.trim())).filter((value) => Number.isFinite(value) && value > 0)));
35180
+ return Effect.promise(async () => panePidsForSession(await getRuntimeCensus(), sessionName));
35140
35181
  }
35141
35182
  function buildProcessTotalsByRoot(roots, processes) {
35142
35183
  const processByPid = new Map(processes.map((process) => [process.pid, process]));
@@ -35165,7 +35206,7 @@ function buildProcessTotalsByRoot(roots, processes) {
35165
35206
  }
35166
35207
  totals.set(root.rootPid, {
35167
35208
  processCount: seen.size,
35168
- cpuPercent: roundOneDecimal$3(cpuPercent),
35209
+ cpuPercent: roundOneDecimal$2(cpuPercent),
35169
35210
  memoryBytes
35170
35211
  });
35171
35212
  }
@@ -35199,7 +35240,7 @@ function getIdleMinutes(lastActivity, nowMs) {
35199
35240
  if (!Number.isFinite(lastActivityMs)) return 0;
35200
35241
  return Math.max(0, Math.floor((nowMs - lastActivityMs) / 6e4));
35201
35242
  }
35202
- function roundOneDecimal$3(value) {
35243
+ function roundOneDecimal$2(value) {
35203
35244
  return Math.round(value * 10) / 10;
35204
35245
  }
35205
35246
  function roundCurrency(value) {
@@ -35207,7 +35248,6 @@ function roundCurrency(value) {
35207
35248
  }
35208
35249
  //#endregion
35209
35250
  //#region services/event-loop-monitor.ts
35210
- init_activity_logger();
35211
35251
  const EVENT_LOOP_MONITOR_WINDOW_MS = 6e4;
35212
35252
  let lastSample = {
35213
35253
  p50: 0,
@@ -35227,7 +35267,6 @@ function sampleEventLoopDelay(histogram, deps = {}) {
35227
35267
  const warnThresholdMs = deps.warnThresholdMs ?? 100;
35228
35268
  const now = deps.now ?? (() => /* @__PURE__ */ new Date());
35229
35269
  const warn = deps.warn ?? ((message) => console.warn(message));
35230
- const emit = deps.emit ?? emitActivityEntrySync;
35231
35270
  const sample = {
35232
35271
  p50: nsToRoundedMs(histogram.percentile(50)),
35233
35272
  p99: nsToRoundedMs(histogram.percentile(99)),
@@ -35237,16 +35276,7 @@ function sampleEventLoopDelay(histogram, deps = {}) {
35237
35276
  windowMs: EVENT_LOOP_MONITOR_WINDOW_MS
35238
35277
  };
35239
35278
  lastSample = sample;
35240
- if (sample.p99 > warnThresholdMs) {
35241
- const message = `Dashboard event loop p99 delay ${sample.p99}ms exceeded ${warnThresholdMs}ms`;
35242
- warn(`[event-loop-monitor] ${message}`);
35243
- emit({
35244
- source: "dashboard",
35245
- level: "warn",
35246
- message,
35247
- details: `p50=${sample.p50}ms p99=${sample.p99}ms max=${sample.max}ms over ${sample.windowMs}ms`
35248
- });
35249
- }
35279
+ if (sample.p99 > warnThresholdMs) warn(`[event-loop-monitor] Dashboard event loop p99 delay ${sample.p99}ms exceeded ${warnThresholdMs}ms`);
35250
35280
  histogram.reset();
35251
35281
  return sample;
35252
35282
  }
@@ -35357,7 +35387,7 @@ function aggregateSupportFleet(processes) {
35357
35387
  const supportProcesses = processes.filter(isSupportFleetProcess);
35358
35388
  const members = supportProcesses.map((process) => process.command);
35359
35389
  return {
35360
- cpuPercent: roundOneDecimal$2(supportProcesses.reduce((sum, process) => sum + process.cpuPercent, 0)),
35390
+ cpuPercent: roundOneDecimal$1(supportProcesses.reduce((sum, process) => sum + process.cpuPercent, 0)),
35361
35391
  memoryBytes: supportProcesses.reduce((sum, process) => sum + process.memoryBytes, 0),
35362
35392
  memberCount: supportProcesses.length,
35363
35393
  members
@@ -35384,7 +35414,7 @@ function formatDuration(totalSeconds) {
35384
35414
  if (minutes > 0) return `${minutes}m ${seconds}s`;
35385
35415
  return `${seconds}s`;
35386
35416
  }
35387
- function roundOneDecimal$2(value) {
35417
+ function roundOneDecimal$1(value) {
35388
35418
  return Math.round(value * 10) / 10;
35389
35419
  }
35390
35420
  //#endregion
@@ -35410,7 +35440,7 @@ function buildCapacityForecast(stacks, options) {
35410
35440
  }),
35411
35441
  headroom: {
35412
35442
  freeRamBytes: options.hostVitals.mem.availableBytes,
35413
- loadHeadroom: Math.max(0, 100 - options.hostVitals.cpu.percent)
35443
+ loadHeadroom: options.hostVitals.cpu.percent === null ? null : Math.max(0, 100 - options.hostVitals.cpu.percent)
35414
35444
  }
35415
35445
  };
35416
35446
  }
@@ -35481,8 +35511,8 @@ function buildHostProcesses(processes, options = {}) {
35481
35511
  const row = {
35482
35512
  ...group,
35483
35513
  pids: group.pids.sort((a, b) => a - b),
35484
- cpuPercent: roundOneDecimal$1(group.cpuPercent),
35485
- peakCpuPercent: roundOneDecimal$1(peakCpuPercent),
35514
+ cpuPercent: roundOneDecimal(group.cpuPercent),
35515
+ peakCpuPercent: roundOneDecimal(peakCpuPercent),
35486
35516
  peakMemoryBytes
35487
35517
  };
35488
35518
  if (peakCpuPercent >= burstCpuThreshold) retainedBursts.set(group.id, {
@@ -35557,7 +35587,7 @@ function selectTopRows(rows, limit) {
35557
35587
  for (const row of [...topByCpu, ...topByMemory]) merged.set(row.id, row);
35558
35588
  return [...merged.values()].sort((a, b) => b.cpuPercent - a.cpuPercent || b.peakCpuPercent - a.peakCpuPercent).slice(0, limit);
35559
35589
  }
35560
- function roundOneDecimal$1(value) {
35590
+ function roundOneDecimal(value) {
35561
35591
  return Math.round(value * 10) / 10;
35562
35592
  }
35563
35593
  //#endregion
@@ -35575,12 +35605,20 @@ let cachedDockerCounts = {
35575
35605
  }
35576
35606
  };
35577
35607
  function buildHostVitalsSnapshot(options = {}) {
35578
- const cpuPercent = roundOneDecimal(options.cpuPercent ?? 0);
35579
- cpuSpark.push(cpuPercent);
35580
- cpuSpark = cpuSpark.slice(-CPU_SPARK_MAX);
35608
+ const metrics = options.hostMetrics;
35609
+ const cpuPercent = metrics?.cpuPercent ?? null;
35610
+ if (cpuPercent !== null) {
35611
+ cpuSpark.push(cpuPercent);
35612
+ cpuSpark = cpuSpark.slice(-CPU_SPARK_MAX);
35613
+ }
35581
35614
  const dockerCounts = options.dockerStale ? cachedDockerCounts : computeDockerCounts(options.containers ?? [], options.networkCount ?? 0, options.networkPoolTotal ?? 31);
35582
35615
  if (!options.dockerStale) cachedDockerCounts = dockerCounts;
35583
- const memory = options.mem ?? getDefaultMemoryVitals();
35616
+ const memory = {
35617
+ usedBytes: metrics?.usedMemoryBytes ?? null,
35618
+ availableBytes: metrics?.availableMemoryBytes ?? null,
35619
+ swapUsedBytes: metrics?.swapUsedBytes ?? null,
35620
+ swapTotalBytes: metrics?.swapTotalBytes ?? null
35621
+ };
35584
35622
  const disk = options.disk ?? {
35585
35623
  usedBytes: 0,
35586
35624
  freeBytes: 0,
@@ -35591,7 +35629,11 @@ function buildHostVitalsSnapshot(options = {}) {
35591
35629
  stale: options.dockerStale === true,
35592
35630
  cpu: {
35593
35631
  percent: cpuPercent,
35594
- load: options.load ?? normalizeLoad(loadavg$1()),
35632
+ load: [
35633
+ metrics?.loadAverage1m ?? null,
35634
+ null,
35635
+ null
35636
+ ],
35595
35637
  spark: [...cpuSpark]
35596
35638
  },
35597
35639
  mem: memory,
@@ -35637,26 +35679,6 @@ function computeAgentCounts(agents, fleet, nowMs) {
35637
35679
  totalUsd: fleet.totalUsd ?? 0
35638
35680
  };
35639
35681
  }
35640
- function getDefaultMemoryVitals() {
35641
- const total = totalmem$1();
35642
- const available = freemem$1();
35643
- return {
35644
- usedBytes: Math.max(0, total - available),
35645
- availableBytes: available,
35646
- swapUsedBytes: 0,
35647
- swapTotalBytes: 0
35648
- };
35649
- }
35650
- function normalizeLoad(load) {
35651
- return [
35652
- roundOneDecimal(load[0] ?? 0),
35653
- roundOneDecimal(load[1] ?? 0),
35654
- roundOneDecimal(load[2] ?? 0)
35655
- ];
35656
- }
35657
- function roundOneDecimal(value) {
35658
- return Math.round(value * 10) / 10;
35659
- }
35660
35682
  //#endregion
35661
35683
  //#region routes/resources/limits.ts
35662
35684
  const OOM_WINDOW_MS = 1440 * 60 * 1e3;
@@ -35767,52 +35789,122 @@ function isClosedReviewStatus(issueId) {
35767
35789
  }
35768
35790
  //#endregion
35769
35791
  //#region routes/resources/spawn-gate.ts
35770
- let readSystemHealthSnapshot = () => getSystemHealthSnapshot();
35771
- function mapSpawnGateDecision(decision) {
35772
- const reason = decision.error ?? decision.warnings[0]?.message ?? "";
35792
+ let readSystemHealthEvidenceSnapshot = () => getSystemHealthEvidenceSnapshot();
35793
+ function mapSpawnGateDecision(decision, accepted) {
35794
+ if (decision.health.freshness.status !== "fresh") {
35795
+ const reason = decision.health.freshness.status === "stale" ? {
35796
+ code: "admission.snapshot.stale",
35797
+ domain: "admission",
35798
+ severity: "critical",
35799
+ message: decision.error ?? `Spawn gate health is stale: ${decision.health.freshness.reason.message}`
35800
+ } : {
35801
+ code: "admission.snapshot.measuring",
35802
+ domain: "admission",
35803
+ severity: "info",
35804
+ message: decision.error ?? "Spawn gate health is still measuring."
35805
+ };
35806
+ return unavailableSpawnGate(accepted ?? null, reason, decision.warnings);
35807
+ }
35808
+ const admission = accepted?.admission;
35809
+ const state = admission ? strongestAdmissionState(admission.state, decision.blocked ? "blocked" : decision.requiresAcknowledgement ? "soft" : "open") : decision.blocked ? "blocked" : decision.requiresAcknowledgement ? "soft" : "open";
35810
+ const reasons = mergeAdmissionReasons(admission?.reasons ?? [], decision.warnings.map((warning) => ({
35811
+ code: warning.code,
35812
+ domain: "admission",
35813
+ severity: warning.severity,
35814
+ message: warning.message
35815
+ })));
35773
35816
  return {
35774
- state: decision.blocked ? "BLOCKED" : decision.requiresAcknowledgement ? "SOFT" : "OPEN",
35775
- reason,
35817
+ state,
35818
+ reason: decision.error ?? decision.warnings[0]?.message ?? reasons[0]?.message ?? "",
35819
+ reasons,
35820
+ admittedWorkAgentCount: admission?.admittedWorkAgentCount ?? decision.health.summary.workAgentCount,
35776
35821
  warnings: decision.warnings,
35777
- pressure: spawnGatePressure(decision)
35822
+ pressure: spawnGatePressure(state)
35778
35823
  };
35779
35824
  }
35780
- function getSpawnGatePayloadEffect() {
35825
+ function getResourcesHealthEvidenceEffect() {
35781
35826
  return Effect.tryPromise({
35782
- try: () => readSystemHealthSnapshot(),
35827
+ try: () => readSystemHealthEvidenceSnapshot(),
35783
35828
  catch: (error) => error
35784
- }).pipe(Effect.map((health) => mapSpawnGateDecision(evaluateSpawnGuardrails(health))), Effect.catch(() => Effect.succeed({
35785
- state: "SOFT",
35786
- reason: "Spawn gate health is unavailable.",
35787
- warnings: [],
35829
+ }).pipe(Effect.map(({ accepted, compatibility }) => ({
35830
+ accepted,
35831
+ decision: evaluateSpawnGuardrails(compatibility)
35832
+ })), Effect.catch(() => Effect.succeed({
35833
+ accepted: null,
35834
+ decision: null
35835
+ })));
35836
+ }
35837
+ function getSpawnGatePayloadEffect(evidence) {
35838
+ return (evidence ? Effect.succeed(evidence) : getResourcesHealthEvidenceEffect()).pipe(Effect.map(({ accepted, decision }) => {
35839
+ if (!accepted || !decision) return unavailableSpawnGate(accepted);
35840
+ return mapSpawnGateDecision(decision, accepted);
35841
+ }));
35842
+ }
35843
+ function unavailableSpawnGate(accepted, unavailableReason, warnings = []) {
35844
+ const reasons = unavailableReason ? [unavailableReason] : accepted?.admission.reasons.length ? [...accepted.admission.reasons] : [{
35845
+ code: "admission.snapshot.unavailable",
35846
+ domain: "admission",
35847
+ severity: "critical",
35848
+ message: "Spawn gate health is unavailable."
35849
+ }];
35850
+ return {
35851
+ state: "unavailable",
35852
+ reason: reasons[0]?.message ?? "Spawn gate health is unavailable.",
35853
+ reasons,
35854
+ admittedWorkAgentCount: accepted?.admission.admittedWorkAgentCount ?? null,
35855
+ warnings,
35788
35856
  pressure: 0,
35789
35857
  stale: true
35790
- })));
35858
+ };
35791
35859
  }
35792
- function spawnGatePressure(decision) {
35793
- if (decision.blocked) return 100;
35794
- if (decision.requiresAcknowledgement) return 67;
35795
- return 12;
35860
+ function mergeAdmissionReasons(...reasonGroups) {
35861
+ const seen = /* @__PURE__ */ new Set();
35862
+ return reasonGroups.flatMap((reasons) => reasons).filter((reason) => {
35863
+ const key = `${reason.code}::${reason.message}`;
35864
+ if (seen.has(key)) return false;
35865
+ seen.add(key);
35866
+ return true;
35867
+ });
35868
+ }
35869
+ function strongestAdmissionState(accepted, enforced) {
35870
+ if (accepted === "unavailable") return accepted;
35871
+ const rank = {
35872
+ open: 0,
35873
+ soft: 1,
35874
+ blocked: 2
35875
+ };
35876
+ return rank[accepted] >= rank[enforced] ? accepted : enforced;
35877
+ }
35878
+ function spawnGatePressure(state) {
35879
+ if (state === "blocked") return 100;
35880
+ if (state === "soft") return 67;
35881
+ if (state === "open") return 12;
35882
+ return 0;
35796
35883
  }
35797
35884
  //#endregion
35798
35885
  //#region routes/resources/snapshot.ts
35799
35886
  init_agents$1();
35800
- init_tmux();
35801
- /** Build the GET /api/resources response from the SQLite agents table. */
35802
- function getResourcesEffect() {
35887
+ init_runtime_census();
35888
+ const RESOURCES_SNAPSHOT_INTERVAL_MS = 3e3;
35889
+ let resourcesSnapshotJson = null;
35890
+ let resourcesSnapshotRefresh = null;
35891
+ let resourcesSnapshotTimer = null;
35892
+ /** Build the resources payload from cached collectors and the SQLite agents table. */
35893
+ function buildResourcesPayloadEffect() {
35803
35894
  return Effect.gen(function* () {
35804
35895
  const containers = enrichContainersWithLimits(getCurrentDockerStats());
35805
35896
  const agentStats = yield* getAgentStatsSnapshotEffect();
35806
- const spawnGate = yield* getSpawnGatePayloadEffect();
35897
+ const healthEvidence = yield* getResourcesHealthEvidenceEffect();
35898
+ const spawnGate = yield* getSpawnGatePayloadEffect(healthEvidence);
35807
35899
  const stoppedContainers = [];
35808
- const sessions = yield* listSessions().pipe(Effect.catch(() => Effect.succeed([])));
35809
- const tmuxSessionNames = new Set(sessions.map((s) => s.name));
35900
+ const tmuxSessionNames = (yield* Effect.promise(() => getRuntimeCensus()).pipe(Effect.catch(() => Effect.succeed(null))))?.sessionNames ?? /* @__PURE__ */ new Set();
35810
35901
  const agents = listAgentStates().filter((state) => state.status !== "stopped").map((state) => ({
35811
35902
  ...state,
35812
35903
  hasLiveTmuxSession: tmuxSessionNames.has(state.id)
35813
35904
  }));
35814
35905
  const agentStatsById = new Map(agentStats.agents.map((agent) => [agent.id, agent]));
35815
35906
  const baseHostVitals = buildHostVitalsSnapshot({
35907
+ hostMetrics: healthEvidence.accepted?.host.metrics,
35816
35908
  containers,
35817
35909
  agents: agents.map((agent) => ({
35818
35910
  id: String(agent.id),
@@ -35830,7 +35922,7 @@ function getResourcesEffect() {
35830
35922
  reclaimableBytes: reclaim.reclaimTotals.diskBytes
35831
35923
  }
35832
35924
  };
35833
- return jsonResponse({
35925
+ return {
35834
35926
  agents: agents.map((agent) => ({
35835
35927
  ...agent,
35836
35928
  resourceStats: agentStatsById.get(String(agent.id)) ?? null
@@ -35849,10 +35941,39 @@ function getResourcesEffect() {
35849
35941
  stacks,
35850
35942
  volumes: [],
35851
35943
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
35852
- });
35944
+ };
35945
+ });
35946
+ }
35947
+ function refreshResourcesSnapshot() {
35948
+ if (resourcesSnapshotRefresh) return resourcesSnapshotRefresh;
35949
+ resourcesSnapshotRefresh = Effect.runPromise(buildResourcesPayloadEffect()).then((payload) => {
35950
+ resourcesSnapshotJson = JSON.stringify(payload);
35951
+ }).finally(() => {
35952
+ resourcesSnapshotRefresh = null;
35853
35953
  });
35954
+ return resourcesSnapshotRefresh;
35955
+ }
35956
+ function getResourcesSnapshotEffect() {
35957
+ return Effect.sync(() => resourcesSnapshotJson ? jsonStringResponse(resourcesSnapshotJson) : jsonResponse({ error: "Resources snapshot is warming" }, 503));
35854
35958
  }
35855
- const getResourcesRoute = HttpRouter.add("GET", "/api/resources", httpHandler(getResourcesEffect()));
35959
+ function startResourcesSnapshotService() {
35960
+ if (resourcesSnapshotTimer) return stopResourcesSnapshotService;
35961
+ refreshResourcesSnapshot().catch((error) => {
35962
+ console.warn("[resources-snapshot] initial refresh failed:", error instanceof Error ? error.message : error);
35963
+ });
35964
+ resourcesSnapshotTimer = setInterval(() => {
35965
+ refreshResourcesSnapshot().catch((error) => {
35966
+ console.warn("[resources-snapshot] refresh failed; keeping last-good snapshot:", error instanceof Error ? error.message : error);
35967
+ });
35968
+ }, RESOURCES_SNAPSHOT_INTERVAL_MS);
35969
+ resourcesSnapshotTimer.unref?.();
35970
+ return stopResourcesSnapshotService;
35971
+ }
35972
+ function stopResourcesSnapshotService() {
35973
+ if (resourcesSnapshotTimer) clearInterval(resourcesSnapshotTimer);
35974
+ resourcesSnapshotTimer = null;
35975
+ }
35976
+ const getResourcesRoute = HttpRouter.add("GET", "/api/resources", httpHandler(getResourcesSnapshotEffect()));
35856
35977
  //#endregion
35857
35978
  //#region routes/resources/containers.ts
35858
35979
  init_domain_services();
@@ -38292,7 +38413,7 @@ async function fetchPlanningData(issueId, options = {}) {
38292
38413
  }
38293
38414
  } catch {}
38294
38415
  if (!hasPlanningDir && !hasPanContinue) {
38295
- const prd = await readPrdContent(findPrdAtStatusSync(projectPath, issueId, "active"));
38416
+ const prd = await readPrdContent(findPrdAnywhereSync(projectPath, issueId));
38296
38417
  if (prd) {
38297
38418
  result.prd = prd;
38298
38419
  result.hasPrd = true;
@@ -38320,16 +38441,11 @@ async function fetchPlanningData(issueId, options = {}) {
38320
38441
  const fileStat = await stat$1(statusReviewPath).catch(() => null);
38321
38442
  if (fileStat) result.statusReviewedAt = fileStat.mtime.toISOString();
38322
38443
  }
38323
- if (!result.prd) for (const status of [
38324
- "active",
38325
- "planned",
38326
- "completed"
38327
- ]) {
38328
- const content = await readPrdContent(findPrdAtStatusSync(projectPath, issueId, status));
38444
+ if (!result.prd) {
38445
+ const content = await readPrdContent(findPrdAnywhereSync(projectPath, issueId));
38329
38446
  if (content) {
38330
38447
  result.prd = content;
38331
38448
  result.hasPrd = true;
38332
- break;
38333
38449
  }
38334
38450
  }
38335
38451
  if (!result.prd && result.state) result.prd = result.state;
@@ -38532,7 +38648,7 @@ ${issueContext ? `\n${issueContext}\n` : ""}
38532
38648
  - Review: ${reviewStatus}
38533
38649
  - Tests: ${testStatus}
38534
38650
 
38535
- ## Planning Context (continue.vbrief.json)
38651
+ ## Planning Context (.overdeck/continue.json)
38536
38652
  ${state ? state.slice(0, 4e3) : "(No planning state available)"}
38537
38653
 
38538
38654
  ## Files Changed
@@ -38574,7 +38690,7 @@ Be specific: reference actual file names, function names, requirement text, disc
38574
38690
  const { command: cliCmd, args: cliArgs } = getAgentCommandSync(statusModelId);
38575
38691
  const modelFlag = cliArgs.length > 0 ? ` ${cliArgs.join(" ")}` : "";
38576
38692
  const promptFile = join(planningDir, ".status-review-prompt.tmp");
38577
- const { getProviderForModelSync, getProviderEnvSync } = await import("./providers-BqCdTryq.js");
38693
+ const { getProviderForModelSync, getProviderEnvSync } = await import("./providers-DKkBXhxU.js");
38578
38694
  let providerEnvStr = "";
38579
38695
  let providerEnv = {};
38580
38696
  const statusProvider = getProviderForModelSync(statusModelId);
@@ -38657,7 +38773,7 @@ const postMissionControlUploadRoute = HttpRouter.add("POST", "/api/command-deck/
38657
38773
  let safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "-");
38658
38774
  let processedContent = content;
38659
38775
  if (safeName.endsWith(".vtt")) {
38660
- const { vttToMarkdown } = yield* Effect.promise(() => import("./vtt-parser-3VZKsmSm.js"));
38776
+ const { vttToMarkdown } = yield* Effect.promise(() => import("./vtt-parser-DKpNNW5i.js"));
38661
38777
  processedContent = vttToMarkdown(content);
38662
38778
  safeName = safeName.replace(/\.vtt$/, ".md");
38663
38779
  }
@@ -44484,7 +44600,7 @@ const postRallyValidateRoute = HttpRouter.add("POST", "/api/rally/validate", Eff
44484
44600
  }, { status: 400 });
44485
44601
  return yield* Effect.promise(async () => {
44486
44602
  try {
44487
- const { RallyRestApi } = await import("./rally-api-CKr0O4DJ.js");
44603
+ const { RallyRestApi } = await import("./rally-api-yjQ0TfHd.js");
44488
44604
  const api = new RallyRestApi({
44489
44605
  apiKey,
44490
44606
  server: server || "https://rally1.rallydev.com"
@@ -44516,15 +44632,9 @@ const postRallyValidateRoute = HttpRouter.add("POST", "/api/rally/validate", Eff
44516
44632
  const trackersRouteLayer = Layer.mergeAll(postTrackersRefreshRoute, getTrackerStatusRoute, postRallyValidateRoute);
44517
44633
  //#endregion
44518
44634
  //#region ../lib/health-filtering.ts
44519
- /**
44520
- * Health filtering logic for dashboard health API
44521
- * Determines which agents should be visible in health checks
44522
- */
44523
- init_config$1();
44524
44635
  init_tmux();
44525
- const KICKOFF_STALL_GRACE_MS = 300 * 1e3;
44526
44636
  /**
44527
- * Check if agent tmux session is alive
44637
+ * Check if agent tmux session is alive.
44528
44638
  */
44529
44639
  const checkAgentHealth = (agentId) => Effect.gen(function* () {
44530
44640
  if (!(yield* sessionExists(agentId))) return { alive: false };
@@ -44533,133 +44643,196 @@ const checkAgentHealth = (agentId) => Effect.gen(function* () {
44533
44643
  lastOutput: (yield* capturePane(agentId, 5)).trim()
44534
44644
  };
44535
44645
  }).pipe(Effect.catch(() => Effect.succeed({ alive: false })));
44536
- /**
44537
- * Determine health status based on activity
44538
- * Returns null if agent should be hidden (completed/stopped/no state.json)
44539
- *
44540
- * `liveSessions` is REQUIRED — pass the session list fetched once per request.
44541
- * Iterating ~150 agent dirs and spawning a tmux subprocess per agent was pinning
44542
- * the dashboard process at 100% CPU on every 5s `/api/health/agents` poll.
44543
- * State is also read before the tmux check so stopped/completed/missing
44544
- * agents short-circuit without any extra work.
44545
- */
44546
- const determineHealthStatus = (agentId, stateFile, liveSessions) => Effect.gen(function* () {
44547
- let agentStatus;
44548
- let lastActivity = null;
44549
- let contextSaturatedAt;
44550
- if (!existsSync(stateFile)) return null;
44551
- const state = yield* Effect.tryPromise({
44552
- try: () => readFile$1(stateFile, "utf-8").then((content) => JSON.parse(content)),
44553
- catch: () => null
44554
- }).pipe(Effect.catch(() => Effect.succeed(null)));
44555
- if (state === null) return null;
44556
- agentStatus = state.status;
44557
- lastActivity = state.lastActivity ? new Date(state.lastActivity) : null;
44558
- if (!agentStatus) return null;
44559
- if (agentStatus === "stopped" || agentStatus === "completed") return null;
44560
- const runtimeFile = stateFile.replace("state.json", "runtime.json");
44561
- if (existsSync(runtimeFile)) {
44562
- const runtime = yield* Effect.tryPromise({
44563
- try: () => readFile$1(runtimeFile, "utf-8").then((content) => JSON.parse(content)),
44564
- catch: () => null
44565
- }).pipe(Effect.catch(() => Effect.succeed(null)));
44566
- if (runtime?.lastActivity) {
44567
- const runtimeDate = new Date(runtime.lastActivity);
44568
- if (!lastActivity || runtimeDate > lastActivity) lastActivity = runtimeDate;
44569
- }
44570
- if (runtime?.contextSaturatedAt) contextSaturatedAt = runtime.contextSaturatedAt;
44571
- }
44572
- if (!liveSessions.has(agentId)) {
44573
- const STALE_THRESHOLD_MS = ((yield* loadCloisterConfig()).retention?.health_staleness_hours ?? 24) * 60 * 60 * 1e3;
44574
- if (lastActivity) {
44575
- if (Date.now() - lastActivity.getTime() > STALE_THRESHOLD_MS) return null;
44576
- } else return null;
44577
- return {
44578
- status: "dead",
44579
- reason: "Agent crashed unexpectedly"
44580
- };
44581
- }
44582
- if (contextSaturatedAt) return {
44583
- status: "wedged",
44584
- reason: "Context window exhausted (400) — recovery in progress"
44585
- };
44586
- const startedAtMs = typeof state.startedAt === "string" ? Date.parse(state.startedAt) : NaN;
44587
- if (state.role === "work" && agentStatus === "running" && state.kickoffDelivered === false && Number.isFinite(startedAtMs) && Date.now() - startedAtMs > KICKOFF_STALL_GRACE_MS) return {
44588
- status: "stalled",
44589
- reason: "Work agent running with no kickoff delivered since spawn"
44590
- };
44591
- if (lastActivity) {
44592
- const ageMinutes = (Date.now() - lastActivity.getTime()) / (1e3 * 60);
44593
- if (ageMinutes > 30) return {
44594
- status: "stuck",
44595
- reason: `No activity for ${Math.round(ageMinutes)} minutes`
44596
- };
44597
- else if (ageMinutes > 15) return {
44598
- status: "warning",
44599
- reason: `Low activity (${Math.round(ageMinutes)} minutes)`
44600
- };
44601
- }
44602
- return { status: "healthy" };
44603
- });
44604
44646
  //#endregion
44605
44647
  //#region routes/misc/health.ts
44606
- init_agents$1();
44607
- init_tmux();
44648
+ init_src();
44649
+ init_review_status_source();
44650
+ init_paths();
44651
+ init_runtime_census();
44608
44652
  init_read_model();
44609
- const getSystemHealthRoute = HttpRouter.add("GET", "/api/system/health", httpHandler(Effect.gen(function* () {
44610
- return jsonResponse(yield* (yield* ReadModelService).getSnapshot.pipe(Effect.flatMap((snapshot) => Effect.promise(() => getSystemHealthSnapshot(snapshot)))));
44611
- })));
44612
- const getGodviewSystemHealthRoute = HttpRouter.add("GET", "/api/godview/system-health", httpHandler(Effect.gen(function* () {
44613
- const health = yield* (yield* ReadModelService).getSnapshot.pipe(Effect.flatMap((snapshot) => Effect.promise(() => getSystemHealthSnapshot(snapshot))));
44653
+ function readHealthSessionNames(readSnapshot = getRuntimeCensusSnapshot) {
44654
+ const census = readSnapshot();
44655
+ if (!census) throw new Error("Runtime census snapshot is warming");
44656
+ return [...census.sessionNames];
44657
+ }
44658
+ function unavailableSystemHealthResponse() {
44614
44659
  return jsonResponse({
44615
- cpu: health.summary.cpuPercent,
44616
- memPercent: health.summary.memoryUsedPercent,
44617
- memUsed: health.summary.usedMemoryBytes,
44618
- memTotal: health.summary.totalMemoryBytes,
44619
- updatedAt: health.updatedAt
44660
+ status: "unavailable",
44661
+ reasons: [{
44662
+ code: "system.health_snapshot.unavailable",
44663
+ domain: "host",
44664
+ severity: "critical",
44665
+ message: "The accepted system health snapshot could not be produced or decoded."
44666
+ }]
44667
+ }, { status: 503 });
44668
+ }
44669
+ function decodeAcceptedSystemHealth(value) {
44670
+ const decoded = Schema.decodeUnknownResult(SystemHealthSnapshot)(value);
44671
+ if (decoded._tag === "Failure") throw new Error("The accepted system health snapshot failed shared-contract decoding.");
44672
+ return decoded.success;
44673
+ }
44674
+ function buildSystemHealthResponse(dependencies) {
44675
+ return dependencies.snapshot.pipe(Effect.map((snapshot) => jsonResponse(decodeAcceptedSystemHealth(snapshot))), Effect.catchCause(() => Effect.succeed(unavailableSystemHealthResponse())));
44676
+ }
44677
+ function buildGodviewSystemHealthResponse(dependencies) {
44678
+ return dependencies.snapshot.pipe(Effect.map((snapshot) => {
44679
+ const health = decodeAcceptedSystemHealth(snapshot);
44680
+ return jsonResponse({
44681
+ ...health,
44682
+ cpu: health.summary.cpuPercent,
44683
+ memPercent: health.summary.memoryUsedPercent,
44684
+ memUsed: health.summary.usedMemoryBytes,
44685
+ memTotal: health.summary.totalMemoryBytes,
44686
+ updatedAt: health.updatedAt
44687
+ });
44688
+ }), Effect.catchCause(() => Effect.succeed(unavailableSystemHealthResponse())));
44689
+ }
44690
+ const getSystemHealthRoute = HttpRouter.add("GET", "/api/system/health", httpHandler(buildSystemHealthResponse({ snapshot: Effect.promise(() => getAcceptedSystemHealthSnapshot()) })));
44691
+ const getGodviewSystemHealthRoute = HttpRouter.add("GET", "/api/godview/system-health", httpHandler(buildGodviewSystemHealthResponse({ snapshot: Effect.promise(() => getAcceptedSystemHealthSnapshot()) })));
44692
+ const getDeployStalenessRoute = HttpRouter.add("GET", "/api/deploy/staleness", Effect.promise(async () => jsonResponse(await getDeployStaleness())));
44693
+ function finiteNumber(value) {
44694
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
44695
+ }
44696
+ async function readAgentHealthObservations(agentId) {
44697
+ if (!/^[A-Za-z0-9._-]+$/.test(agentId) || agentId.includes("..")) return {};
44698
+ const agentDir = join(getOverdeckHome(), "agents", agentId);
44699
+ const observations = {};
44700
+ try {
44701
+ const stored = JSON.parse(await readFile(join(agentDir, "health.json"), "utf-8"));
44702
+ if (stored && typeof stored === "object" && !Array.isArray(stored)) {
44703
+ const record = stored;
44704
+ const consecutiveFailures = finiteNumber(record["consecutiveFailures"]);
44705
+ const killCount = finiteNumber(record["killCount"]);
44706
+ if (consecutiveFailures !== void 0) observations.consecutiveFailures = consecutiveFailures;
44707
+ if (killCount !== void 0) observations.killCount = killCount;
44708
+ }
44709
+ } catch {}
44710
+ try {
44711
+ const raw = (await readFile(join(agentDir, "context-pct"), "utf-8")).trim();
44712
+ const contextPercent = raw === "" ? NaN : Number(raw);
44713
+ if (Number.isFinite(contextPercent)) observations.contextPercent = contextPercent;
44714
+ } catch {}
44715
+ return observations;
44716
+ }
44717
+ function runtimeHealthState(runtime) {
44718
+ if (!runtime) return null;
44719
+ switch (runtime.activity) {
44720
+ case "working":
44721
+ case "thinking": return {
44722
+ state: "active",
44723
+ lastActivity: runtime.lastActivity,
44724
+ contextSaturatedAt: runtime.contextSaturatedAt
44725
+ };
44726
+ case "waiting": return {
44727
+ state: "waiting-on-human",
44728
+ lastActivity: runtime.lastActivity,
44729
+ contextSaturatedAt: runtime.contextSaturatedAt
44730
+ };
44731
+ case "idle": return {
44732
+ state: "idle",
44733
+ lastActivity: runtime.lastActivity,
44734
+ contextSaturatedAt: runtime.contextSaturatedAt
44735
+ };
44736
+ case "stopped": return {
44737
+ state: "stopped",
44738
+ lastActivity: runtime.lastActivity,
44739
+ contextSaturatedAt: runtime.contextSaturatedAt
44740
+ };
44741
+ }
44742
+ }
44743
+ function decodeReviewStatuses(value) {
44744
+ const statuses = /* @__PURE__ */ new Map();
44745
+ for (const candidate of value ?? []) {
44746
+ const decoded = Schema.decodeUnknownResult(ReviewStatusSnapshot)(candidate);
44747
+ if (decoded._tag === "Success") statuses.set(decoded.success.issueId.toUpperCase(), decoded.success);
44748
+ }
44749
+ return statuses;
44750
+ }
44751
+ function reviewLifecycle(agent, statuses, tmuxActive) {
44752
+ if (agent.role !== "review" && agent.role !== "test" && agent.role !== "ship") return "unknown";
44753
+ return classifyAdvancingSessionLifecycle(agent.role, statuses.get(agent.issueId.toUpperCase()), tmuxActive);
44754
+ }
44755
+ function snapshotSource(value) {
44756
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("The canonical read model did not return an object.");
44757
+ const candidate = value;
44758
+ if (!Array.isArray(candidate["agents"])) throw new Error("The canonical read model did not return an agent array.");
44759
+ return {
44760
+ agents: candidate["agents"],
44761
+ agentRuntimeById: candidate["agentRuntimeById"],
44762
+ reviewStatuses: Array.isArray(candidate["reviewStatuses"]) ? candidate["reviewStatuses"] : void 0
44763
+ };
44764
+ }
44765
+ function runtimeRecord(value) {
44766
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
44767
+ }
44768
+ async function projectAgentHealth(snapshotValue, sessionNames, readObservations, nowMs) {
44769
+ const snapshot = snapshotSource(snapshotValue);
44770
+ const liveSessions = new Set(sessionNames);
44771
+ const runtimes = runtimeRecord(snapshot.agentRuntimeById);
44772
+ const reviewStatuses = decodeReviewStatuses(snapshot.reviewStatuses);
44773
+ return Promise.all(snapshot.agents.map(async (candidate, index) => {
44774
+ const decoded = Schema.decodeUnknownResult(AgentSnapshot)(candidate);
44775
+ if (decoded._tag === "Failure") {
44776
+ const candidateId = candidate && typeof candidate === "object" && !Array.isArray(candidate) ? candidate["id"] : void 0;
44777
+ return classifyAgentHealth({
44778
+ agentId: typeof candidateId === "string" ? candidateId : `unavailable-agent-${index + 1}`,
44779
+ persisted: {
44780
+ status: "unavailable",
44781
+ reason: "The canonical agent snapshot could not be decoded."
44782
+ },
44783
+ runtime: null,
44784
+ liveSessions,
44785
+ reviewLifecycle: "unknown",
44786
+ nowMs
44787
+ });
44788
+ }
44789
+ const agent = decoded.success;
44790
+ const runtimeCandidate = Schema.decodeUnknownResult(AgentRuntimeSnapshot)(runtimes[agent.id]);
44791
+ const runtime = runtimeCandidate._tag === "Success" ? runtimeCandidate.success : null;
44792
+ const observations = await readObservations(agent.id).catch(() => ({}));
44793
+ return classifyAgentHealth({
44794
+ agentId: agent.id,
44795
+ persisted: {
44796
+ status: "available",
44797
+ value: {
44798
+ id: agent.id,
44799
+ issueId: agent.issueId,
44800
+ role: agent.role,
44801
+ status: agent.status,
44802
+ startedAt: agent.startedAt,
44803
+ lastActivity: agent.lastActivity,
44804
+ paused: agent.paused,
44805
+ stoppedByUser: agent.stoppedByUser,
44806
+ consecutiveFailures: agent.consecutiveFailures
44807
+ }
44808
+ },
44809
+ runtime: runtimeHealthState(runtime),
44810
+ liveSessions,
44811
+ reviewLifecycle: reviewLifecycle(agent, reviewStatuses, liveSessions.has(agent.id)),
44812
+ observations,
44813
+ nowMs
44814
+ });
44815
+ }));
44816
+ }
44817
+ function buildHealthAgentsResponse(dependencies) {
44818
+ return Effect.all({
44819
+ snapshot: dependencies.snapshot,
44820
+ sessionNames: dependencies.sessionNames
44821
+ }).pipe(Effect.flatMap(({ snapshot, sessionNames }) => Effect.promise(async () => jsonResponse(await projectAgentHealth(snapshot, sessionNames, dependencies.readObservations ?? readAgentHealthObservations, dependencies.nowMs ?? Date.now())))), Effect.catchCause(() => Effect.succeed(jsonResponse({
44822
+ status: "unavailable",
44823
+ reasons: [{
44824
+ code: "agent.health_snapshot.unavailable",
44825
+ domain: "agent",
44826
+ severity: "critical",
44827
+ message: "The canonical agent health snapshot could not be loaded."
44828
+ }]
44829
+ }, { status: 503 }))));
44830
+ }
44831
+ const getHealthAgentsRoute = HttpRouter.add("GET", "/api/health/agents", Effect.gen(function* () {
44832
+ return yield* buildHealthAgentsResponse({
44833
+ snapshot: (yield* ReadModelService).getSnapshot,
44834
+ sessionNames: Effect.sync(() => readHealthSessionNames())
44620
44835
  });
44621
- })));
44622
- const getHealthAgentsRoute = HttpRouter.add("GET", "/api/health/agents", Effect.promise(async () => {
44623
- try {
44624
- const agentsDir = join(homedir$1(), ".overdeck", "agents");
44625
- if (!existsSync$1(agentsDir)) return jsonResponse([]);
44626
- const agentNames = (await readdir(agentsDir)).filter((name) => name.startsWith("agent-") || name.startsWith("planning-") || name.startsWith("specialist-"));
44627
- const liveSessions = new Set(await Effect.runPromise(listSessionNames()));
44628
- return jsonResponse((await Promise.all(agentNames.map(async (name) => {
44629
- const stateFile = getAgentStateFilePath(name);
44630
- const healthFile = join(agentsDir, name, "health.json");
44631
- const healthStatus = await Effect.runPromise(determineHealthStatus(name, stateFile, liveSessions));
44632
- if (!healthStatus) return null;
44633
- let storedHealth = {
44634
- consecutiveFailures: 0,
44635
- killCount: 0
44636
- };
44637
- try {
44638
- const healthContent = await readFile(healthFile, "utf-8");
44639
- storedHealth = {
44640
- ...storedHealth,
44641
- ...JSON.parse(healthContent)
44642
- };
44643
- } catch {}
44644
- let contextPercent = null;
44645
- try {
44646
- const ctxContent = await readFile(join(agentsDir, name, "context-pct"), "utf-8");
44647
- contextPercent = parseInt(ctxContent.trim(), 10) || null;
44648
- } catch {}
44649
- return {
44650
- agentId: name,
44651
- status: healthStatus.status,
44652
- reason: healthStatus.reason,
44653
- lastPing: (/* @__PURE__ */ new Date()).toISOString(),
44654
- consecutiveFailures: storedHealth.consecutiveFailures,
44655
- killCount: storedHealth.killCount,
44656
- contextPercent
44657
- };
44658
- }))).filter((agent) => agent !== null));
44659
- } catch (error) {
44660
- console.error("Error fetching health:", error);
44661
- return jsonResponse([]);
44662
- }
44663
44836
  }));
44664
44837
  const postHealthAgentPingRoute = HttpRouter.add("POST", "/api/health/agents/:id/ping", Effect.gen(function* () {
44665
44838
  const request = yield* HttpServerRequest.HttpServerRequest;
@@ -44681,7 +44854,7 @@ const postHealthAgentPingRoute = HttpRouter.add("POST", "/api/health/agents/:id/
44681
44854
  }
44682
44855
  });
44683
44856
  }));
44684
- const healthRouteLayer$1 = Layer.mergeAll(getSystemHealthRoute, getGodviewSystemHealthRoute, getHealthAgentsRoute, postHealthAgentPingRoute);
44857
+ const healthRouteLayer$1 = Layer.mergeAll(getSystemHealthRoute, getGodviewSystemHealthRoute, getDeployStalenessRoute, getHealthAgentsRoute, postHealthAgentPingRoute);
44685
44858
  //#endregion
44686
44859
  //#region routes/misc/deacon.ts
44687
44860
  init_control_settings();
@@ -44812,7 +44985,7 @@ const getPlanningStatusRoute = HttpRouter.add("GET", "/api/planning/:issueId/sta
44812
44985
  const remoteState = loadRemoteAgentState(sessionName);
44813
44986
  const isRemote = !!remoteState;
44814
44987
  const vmName = remoteState?.vmName ?? "";
44815
- const { getAgentStateSync } = await import("./agents-Czz6R57Z.js");
44988
+ const { getAgentStateSync } = await import("./agents-FlIgQ3ql.js");
44816
44989
  const agentStarting = getAgentStateSync(sessionName)?.status === "starting";
44817
44990
  let tmuxSessionAlive = false;
44818
44991
  if (!isRemote) try {
@@ -44932,7 +45105,7 @@ const postPlanningMessageRoute = HttpRouter.add("POST", "/api/planning/:issueId/
44932
45105
  **YOU SHOULD ONLY:**
44933
45106
  - Ask clarifying questions
44934
45107
  - Explore the codebase to understand context
44935
- - Generate planning artifacts (\`.pan/continue.json\`, \`.pan/spec.vbrief.json\`)
45108
+ - Generate planning artifacts (\`.overdeck/continue.json\`, \`.overdeck/spec.vbrief.json\`)
44936
45109
  - Present options and tradeoffs
44937
45110
 
44938
45111
  ---
@@ -44954,8 +45127,9 @@ ${message}
44954
45127
  Continue the PLANNING session. Do NOT implement anything.
44955
45128
  `);
44956
45129
  const agentCwd = workspacePath;
45130
+ const harnessLaunch = await prepareHarnessLaunch("claude-code");
44957
45131
  if (existsSync$1(outputFile)) await rename(outputFile, join(planningDir, `output-${Date.now()}.jsonl`));
44958
- const { getAgentCommandSync } = await import("./settings-BaPXXJsT.js");
45132
+ const { getAgentCommandSync } = await import("./settings-D0OSwos5.js");
44959
45133
  let msgPlanningModel = "claude-sonnet-5";
44960
45134
  try {
44961
45135
  msgPlanningModel = resolveModel("plan", void 0, loadConfigSync().config);
@@ -44969,6 +45143,7 @@ Continue the PLANNING session. Do NOT implement anything.
44969
45143
  role: "plan",
44970
45144
  workingDir: agentCwd,
44971
45145
  baseCommand: msgCmdWithArgs,
45146
+ extraEnvExports: [harnessLaunch.pathExport],
44972
45147
  appendSystemPromptFiles: await claudePlanningSystemPromptFiles(agentCwd),
44973
45148
  promptInline: `Please read the continuation prompt at ${continuationPromptPath} and continue the planning session.`
44974
45149
  }), { mode: 493 });
@@ -45076,7 +45251,7 @@ async function getIndexStats(rootPath, isMain) {
45076
45251
  }
45077
45252
  const getTldrStatusRoute = HttpRouter.add("GET", "/api/services/tldr/status", Effect.promise(async () => {
45078
45253
  try {
45079
- const { getTldrDaemonServiceSync } = await import("./tldr-daemon-BJA7TkqS.js");
45254
+ const { getTldrDaemonServiceSync } = await import("./tldr-daemon-DL566HbH.js");
45080
45255
  const projectRoot = process.cwd();
45081
45256
  const venvPath = join(projectRoot, ".venv");
45082
45257
  const results = [];
@@ -45121,7 +45296,7 @@ const getTldrStatusRoute = HttpRouter.add("GET", "/api/services/tldr/status", Ef
45121
45296
  }));
45122
45297
  const postTldrStartRoute = HttpRouter.add("POST", "/api/services/tldr/start", Effect.promise(async () => {
45123
45298
  try {
45124
- const { getTldrDaemonServiceSync } = await import("./tldr-daemon-BJA7TkqS.js");
45299
+ const { getTldrDaemonServiceSync } = await import("./tldr-daemon-DL566HbH.js");
45125
45300
  const projectRoot = process.cwd();
45126
45301
  const venvPath = join(projectRoot, ".venv");
45127
45302
  if (!existsSync$1(venvPath)) return jsonResponse({ error: "No .venv found in project root" }, { status: 404 });
@@ -45138,7 +45313,7 @@ const postTldrStartRoute = HttpRouter.add("POST", "/api/services/tldr/start", Ef
45138
45313
  }));
45139
45314
  const postTldrStopRoute = HttpRouter.add("POST", "/api/services/tldr/stop", Effect.promise(async () => {
45140
45315
  try {
45141
- const { getTldrDaemonServiceSync } = await import("./tldr-daemon-BJA7TkqS.js");
45316
+ const { getTldrDaemonServiceSync } = await import("./tldr-daemon-DL566HbH.js");
45142
45317
  const projectRoot = process.cwd();
45143
45318
  const venvPath = join(projectRoot, ".venv");
45144
45319
  if (!existsSync$1(venvPath)) return jsonResponse({ error: "No .venv found in project root" }, { status: 404 });
@@ -45155,7 +45330,7 @@ const postTldrStopRoute = HttpRouter.add("POST", "/api/services/tldr/stop", Effe
45155
45330
  }));
45156
45331
  const postTldrReloadRoute = HttpRouter.add("POST", "/api/services/tldr/reload", Effect.promise(async () => {
45157
45332
  try {
45158
- const { getTldrDaemonServiceSync } = await import("./tldr-daemon-BJA7TkqS.js");
45333
+ const { getTldrDaemonServiceSync } = await import("./tldr-daemon-DL566HbH.js");
45159
45334
  const enabled = isTldrEnabledSync();
45160
45335
  const projectRoot = process.cwd();
45161
45336
  const targets = [];
@@ -45343,7 +45518,7 @@ const getVersionRoute = HttpRouter.add("GET", "/api/version", Effect.promise(asy
45343
45518
  const version = await getOverdeckVersion();
45344
45519
  let supervisorUrl = null;
45345
45520
  try {
45346
- const { getSupervisorUrlSync } = await import("./supervisor-Qy1QecAs.js");
45521
+ const { getSupervisorUrlSync } = await import("./supervisor-BPy-o1A8.js");
45347
45522
  supervisorUrl = getSupervisorUrlSync();
45348
45523
  } catch {}
45349
45524
  return jsonResponse({
@@ -45353,11 +45528,11 @@ const getVersionRoute = HttpRouter.add("GET", "/api/version", Effect.promise(asy
45353
45528
  });
45354
45529
  }));
45355
45530
  const getPrerequisitesRoute = HttpRouter.add("GET", "/api/prerequisites", Effect.promise(async () => {
45356
- const { checkSystemPrerequisites } = await import("./system-prerequisites-DkoQBn1q.js");
45531
+ const { checkSystemPrerequisites } = await import("./system-prerequisites-Bza0ffAh.js");
45357
45532
  return jsonResponse(await checkSystemPrerequisites());
45358
45533
  }));
45359
45534
  const getSetupDiagnosticsRoute = HttpRouter.add("GET", "/api/diagnostics/setup", Effect.promise(async () => {
45360
- const { collectSetupDiagnostics } = await import("./system-prerequisites-DkoQBn1q.js");
45535
+ const { collectSetupDiagnostics } = await import("./system-prerequisites-Bza0ffAh.js");
45361
45536
  return jsonResponse(await collectSetupDiagnostics(await getOverdeckVersion()));
45362
45537
  }));
45363
45538
  const getSyncStatusRoute = HttpRouter.add("GET", "/api/sync-status", Effect.sync(() => {
@@ -45537,7 +45712,7 @@ const postShadowMonitorRoute = HttpRouter.add("POST", "/api/shadow/:issueId/moni
45537
45712
  const projectPath = await getProjectPath(issuePrefix);
45538
45713
  const workspacePath = join(projectPath, "workspaces", `feature-${issueLower}`);
45539
45714
  if (!existsSync$1(workspacePath)) return jsonResponse({ error: "Workspace not found" }, { status: 404 });
45540
- const { gatherArtifacts, generateBasicInference, updateInferenceDocumentSync } = await import("./shadow-engineering-Bi_oIMtF.js");
45715
+ const { gatherArtifacts, generateBasicInference, updateInferenceDocumentSync } = await import("./shadow-engineering-BlxG6Xye.js");
45541
45716
  const config = {
45542
45717
  issueId,
45543
45718
  workspacePath,
@@ -45567,7 +45742,7 @@ const postShadowObserveRoute = HttpRouter.add("POST", "/api/shadow/:issueId/obse
45567
45742
  if (!existsSync$1(workspacePath)) return jsonResponse({ error: "Workspace not found" }, { status: 404 });
45568
45743
  const ghConfig = getGitHubConfig();
45569
45744
  if (!ghConfig) return jsonResponse({ error: "GitHub not configured - Observer requires GitHub" }, { status: 400 });
45570
- const { runObserverCycle } = await import("./shadow-engineering-Bi_oIMtF.js");
45745
+ const { runObserverCycle } = await import("./shadow-engineering-BlxG6Xye.js");
45571
45746
  const firstRepo = ghConfig.repos[0];
45572
45747
  const config = {
45573
45748
  issueId,
@@ -46103,9 +46278,9 @@ const PAN_COMMANDS = [
46103
46278
  },
46104
46279
  {
46105
46280
  name: "pan plan <id>",
46106
- description: "Plan an issue (interactive vBRIEF + tasks)",
46281
+ description: "Plan an issue (interactive xBRIEF + tasks)",
46107
46282
  group: "Issues",
46108
- keywords: ["planning", "vbrief"]
46283
+ keywords: ["planning", "xbrief"]
46109
46284
  },
46110
46285
  {
46111
46286
  name: "pan plan <id> --auto",
@@ -46807,6 +46982,17 @@ async function diffFilesSinceBase(repoRoot, baseCommit, filePaths) {
46807
46982
  }
46808
46983
  return diffs;
46809
46984
  }
46985
+ async function diffPatchForFiles(repoRoot, createdAt, filePaths) {
46986
+ const baseCommit = await Effect.runPromise(findCommitAtTime(repoRoot, createdAt));
46987
+ if (!baseCommit) return Effect.runPromise(diffPatchFilesAgainstHead(repoRoot, filePaths));
46988
+ const quotedPaths = filePaths.map((p) => JSON.stringify(p)).join(" ");
46989
+ const { stdout } = await promisify(exec)(`git diff --patch --minimal --no-color ${baseCommit} -- ${quotedPaths}`, {
46990
+ cwd: repoRoot,
46991
+ encoding: "utf-8",
46992
+ maxBuffer: 50 * 1024 * 1024
46993
+ });
46994
+ return stdout;
46995
+ }
46810
46996
  async function getConversationDiffs(name, deps) {
46811
46997
  try {
46812
46998
  const conv = lookupConversation(name);
@@ -46852,22 +47038,28 @@ async function getConversationDiffFull(name, deps) {
46852
47038
  const conv = getConversationByName(name);
46853
47039
  if (!conv) return result$1({ error: "Conversation not found" }, 404);
46854
47040
  const cwd = conv.cwd;
46855
- if (existsSync$1(join(cwd, ".git"))) {
46856
- const baseCommit = await Effect.runPromise(findCommitAtTime(cwd, conv.createdAt));
46857
- if (!baseCommit) return result$1({ diff: "" });
46858
- return result$1({ diff: await Effect.runPromise(diffPatchSinceCommit(cwd, baseCommit)) });
47041
+ const cwdRepoRoot = existsSync$1(join(cwd, ".git")) ? cwd : null;
47042
+ const patches = [];
47043
+ if (cwdRepoRoot) {
47044
+ const baseCommit = await Effect.runPromise(findCommitAtTime(cwdRepoRoot, conv.createdAt));
47045
+ if (baseCommit) {
47046
+ const patch = await Effect.runPromise(diffPatchSinceCommit(cwdRepoRoot, baseCommit));
47047
+ if (patch) patches.push(patch);
47048
+ }
46859
47049
  }
46860
47050
  const sessionFile = await deps.resolveSessionFile(conv);
46861
- if (!sessionFile || !existsSync$1(sessionFile)) return result$1({ diff: "" });
47051
+ if (!sessionFile || !existsSync$1(sessionFile)) return result$1({ diff: patches.join("\n") });
46862
47052
  const { fileEditsByAssistantId } = await deps.getCachedMessages(sessionFile, false);
46863
- if (!fileEditsByAssistantId || fileEditsByAssistantId.size === 0) return result$1({ diff: "" });
47053
+ if (!fileEditsByAssistantId || fileEditsByAssistantId.size === 0) return result$1({ diff: patches.join("\n") });
46864
47054
  const repoRootCache = /* @__PURE__ */ new Map();
46865
47055
  const filesByRepo = await groupFilesByRepo([...fileEditsByAssistantId.values()].flat(), repoRootCache);
46866
- const patches = [];
46867
- for (const [repoRoot, filePaths] of filesByRepo) try {
46868
- const patch = await Effect.runPromise(diffPatchFilesAgainstHead(repoRoot, filePaths));
46869
- if (patch) patches.push(patch);
46870
- } catch {}
47056
+ for (const [repoRoot, filePaths] of filesByRepo) {
47057
+ if (repoRoot === cwdRepoRoot) continue;
47058
+ try {
47059
+ const patch = await diffPatchForFiles(repoRoot, conv.createdAt, filePaths);
47060
+ if (patch) patches.push(patch);
47061
+ } catch {}
47062
+ }
46871
47063
  return result$1({ diff: patches.join("\n") });
46872
47064
  } catch (error) {
46873
47065
  const msg = error instanceof Error ? error.message : String(error);
@@ -46880,35 +47072,34 @@ async function getConversationDiffTurn(name, turnId, fileFilter, deps) {
46880
47072
  const conv = lookupConversation(name);
46881
47073
  if (!conv) return result$1({ error: "Conversation not found" }, 404);
46882
47074
  const cwd = conv.cwd;
46883
- if (existsSync$1(join(cwd, ".git"))) {
46884
- const baseCommit = await Effect.runPromise(findCommitAtTime(cwd, conv.createdAt));
46885
- if (baseCommit) return result$1({
46886
- turnId,
46887
- diff: await Effect.runPromise(diffPatchSinceCommit(cwd, baseCommit, fileFilter))
46888
- });
47075
+ const cwdRepoRoot = existsSync$1(join(cwd, ".git")) ? cwd : null;
47076
+ const patches = [];
47077
+ if (cwdRepoRoot) {
47078
+ const baseCommit = await Effect.runPromise(findCommitAtTime(cwdRepoRoot, conv.createdAt));
47079
+ if (baseCommit) {
47080
+ const patch = await Effect.runPromise(diffPatchSinceCommit(cwdRepoRoot, baseCommit, fileFilter));
47081
+ if (patch) patches.push(patch);
47082
+ }
46889
47083
  }
46890
47084
  const assistantId = turnId.startsWith("conv-turn-") ? turnId.slice(10) : turnId;
46891
47085
  const sessionFile = await deps.resolveSessionFile(conv);
46892
- if (!sessionFile || !existsSync$1(sessionFile)) return result$1({ diff: "" });
47086
+ if (!sessionFile || !existsSync$1(sessionFile)) return result$1({
47087
+ turnId,
47088
+ diff: patches.join("\n")
47089
+ });
46893
47090
  const edits = (await deps.getCachedMessages(sessionFile, false)).fileEditsByAssistantId?.get(assistantId);
46894
- if (!edits || edits.length === 0) return result$1({ diff: "" });
47091
+ if (!edits || edits.length === 0) return result$1({
47092
+ turnId,
47093
+ diff: patches.join("\n")
47094
+ });
46895
47095
  const filesByRepo = await groupFilesByRepo(edits, /* @__PURE__ */ new Map(), fileFilter);
46896
- const baseCommitByRepo = /* @__PURE__ */ new Map();
46897
- const patches = [];
46898
- for (const [repoRoot, filePaths] of filesByRepo) try {
46899
- if (!baseCommitByRepo.has(repoRoot)) baseCommitByRepo.set(repoRoot, await Effect.runPromise(findCommitAtTime(repoRoot, conv.createdAt)));
46900
- const baseCommit = baseCommitByRepo.get(repoRoot) ?? null;
46901
- let patch;
46902
- if (baseCommit) {
46903
- const { stdout } = await promisify(exec)(`git diff --patch --minimal --no-color ${baseCommit} -- ${filePaths.map((p) => JSON.stringify(p)).join(" ")}`, {
46904
- cwd: repoRoot,
46905
- encoding: "utf-8",
46906
- maxBuffer: 50 * 1024 * 1024
46907
- });
46908
- patch = stdout;
46909
- } else patch = await Effect.runPromise(diffPatchFilesAgainstHead(repoRoot, filePaths));
46910
- if (patch) patches.push(patch);
46911
- } catch {}
47096
+ for (const [repoRoot, filePaths] of filesByRepo) {
47097
+ if (repoRoot === cwdRepoRoot) continue;
47098
+ try {
47099
+ const patch = await diffPatchForFiles(repoRoot, conv.createdAt, filePaths);
47100
+ if (patch) patches.push(patch);
47101
+ } catch {}
47102
+ }
46912
47103
  return result$1({
46913
47104
  turnId,
46914
47105
  diff: patches.join("\n")
@@ -48735,7 +48926,7 @@ async function refreshMergeStateFromGitHub(issueId, repo, prNumber) {
48735
48926
  let mergeState;
48736
48927
  let isDraft;
48737
48928
  let checksFailed;
48738
- const { isGitHubAppConfigured, getPullRequestState } = await import("./github-app-CeSVFL6C.js");
48929
+ const { isGitHubAppConfigured, getPullRequestState } = await import("./github-app-CPfoFAdV.js");
48739
48930
  if (isGitHubAppConfigured()) {
48740
48931
  const prState = await Effect.runPromise(getPullRequestState(owner, repoName, prNumber));
48741
48932
  mergeable = prState.mergeable === null ? "UNKNOWN" : prState.mergeable ? "MERGEABLE" : "CONFLICTING";
@@ -48884,8 +49075,8 @@ async function handlePullRequestPromise(payload) {
48884
49075
  bumpIssuePrTabCacheGeneration(issueId);
48885
49076
  const repo = payload.repository.full_name;
48886
49077
  if (payload.action === "closed" && pr.merged === true) try {
48887
- const { postMergeLifecycle } = await import("./merge-agent-CnORPiri.js");
48888
- const { resolveProjectFromIssueSync } = await import("./projects-IRHJIPYC.js");
49078
+ const { postMergeLifecycle } = await import("./merge-agent-BQM3a8z5.js");
49079
+ const { resolveProjectFromIssueSync } = await import("./projects-9SkRpES9.js");
48889
49080
  const project = resolveProjectFromIssueSync(issueId);
48890
49081
  if (project) {
48891
49082
  const branchName = pr.head.ref;
@@ -50281,7 +50472,7 @@ async function registerProjectFromPath(opts) {
50281
50472
  registerProjectSync(key, projectConfig);
50282
50473
  const seededContextLayer = ensureProjectLayer(fullPath);
50283
50474
  try {
50284
- const { preTrustDirectorySync } = await import("./workspace-manager-CcujONCR.js");
50475
+ const { preTrustDirectorySync } = await import("./workspace-manager-ZTdJAy9M.js");
50285
50476
  preTrustDirectorySync(fullPath);
50286
50477
  } catch {}
50287
50478
  let hooksInstalled = 0;
@@ -50311,6 +50502,7 @@ init_issue_id();
50311
50502
  init_tmux();
50312
50503
  init_concurrency$1();
50313
50504
  init_read_model();
50505
+ init_src();
50314
50506
  init_agents$1();
50315
50507
  init_pan_dir();
50316
50508
  init_io();
@@ -50318,7 +50510,7 @@ init_specs();
50318
50510
  init_paths();
50319
50511
  const execAsync$2 = promisify(exec);
50320
50512
  async function getIssueDataService() {
50321
- const { getSharedIssueService } = await import("./issue-service-singleton-D5EB5eYr.js");
50513
+ const { getSharedIssueService } = await import("./issue-service-singleton-DabvBWUp.js");
50322
50514
  return getSharedIssueService();
50323
50515
  }
50324
50516
  /** Returns true if the path exists (any type). */
@@ -50373,9 +50565,9 @@ function getSlotWorkSessionNumber(sessionId, issueLower) {
50373
50565
  return Number.parseInt(match[1], 10);
50374
50566
  }
50375
50567
  function getSessionTreeWorkspacePath(issueLower, baseWorkspacePath, projectPath, sessionId) {
50568
+ if (sessionId.toLowerCase() === `strike-${issueLower.toLowerCase()}`) return join(projectPath, "workspaces", `feature-${issueLower}-strike`);
50376
50569
  const slotNumber = getSlotWorkSessionNumber(sessionId, issueLower);
50377
- if (slotNumber === null) return baseWorkspacePath;
50378
- return join(projectPath, "workspaces", `feature-${issueLower}-slot-${slotNumber}`);
50570
+ return slotNumber === null ? baseWorkspacePath : join(projectPath, "workspaces", `feature-${issueLower}-slot-${slotNumber}`);
50379
50571
  }
50380
50572
  function compareSessionTreeSessionIds(a, b, issueLower) {
50381
50573
  const planningAgentId = `planning-${issueLower}`;
@@ -50733,7 +50925,7 @@ async function fetchProjectSessionTree(projectKey, sharedContext) {
50733
50925
  })), 15));
50734
50926
  features.push(...results.filter((f) => f !== null));
50735
50927
  }
50736
- features.sort((a, b) => a.issueId.localeCompare(b.issueId));
50928
+ features.sort((a, b) => compareIssueIds(a.issueId, b.issueId));
50737
50929
  return {
50738
50930
  projectKey,
50739
50931
  features
@@ -50775,7 +50967,7 @@ const getProjectReleaseStatusRoute = HttpRouter.add("GET", "/api/projects/:proje
50775
50967
  const projectKey = (yield* HttpRouter.params)["projectKey"] ?? "";
50776
50968
  return jsonResponse(yield* Effect.tryPromise({
50777
50969
  try: async () => {
50778
- const { fetchProjectReleaseStatus } = await import("./project-pipelines-B59NfN44.js");
50970
+ const { fetchProjectReleaseStatus } = await import("./project-pipelines-2sK1apsO.js");
50779
50971
  return fetchProjectReleaseStatus(projectKey);
50780
50972
  },
50781
50973
  catch: (err) => new Error(err instanceof Error ? err.message : String(err))
@@ -51290,7 +51482,7 @@ function fullPromptPreview(previews) {
51290
51482
  "## Runtime-only sections",
51291
51483
  "",
51292
51484
  "- Memory retrieval: injected at agent spawn when enabled; unavailable in this layer editor preview.",
51293
- "- Issue briefing and vBRIEF excerpts: injected per agent run; unavailable until a specific issue/session is selected.",
51485
+ "- Issue briefing and xBRIEF excerpts: injected per agent run; unavailable until a specific issue/session is selected.",
51294
51486
  "- Status and tool output: produced during the live session; not part of static context layers."
51295
51487
  ].join("\n");
51296
51488
  }
@@ -51590,6 +51782,35 @@ async function checkCommand(cmd, args = ["--version"]) {
51590
51782
  return false;
51591
51783
  }
51592
51784
  }
51785
+ const LINUX_PACKAGE_MANAGERS = [
51786
+ "pacman",
51787
+ "dnf",
51788
+ "zypper",
51789
+ "apk",
51790
+ "apt-get"
51791
+ ];
51792
+ async function detectLinuxPackageManager(commandAvailable = checkCommand) {
51793
+ for (const packageManager of LINUX_PACKAGE_MANAGERS) if (await commandAvailable(packageManager)) return packageManager;
51794
+ return null;
51795
+ }
51796
+ function getLinuxInstallCommand(tool, packageManager) {
51797
+ switch (packageManager) {
51798
+ case "pacman": return `sudo pacman -S --noconfirm ${tool}`;
51799
+ case "dnf": return `sudo dnf install -y ${tool}`;
51800
+ case "zypper": return `sudo zypper install -y ${tool}`;
51801
+ case "apk": return `sudo apk add ${tool}`;
51802
+ case "apt-get": return `sudo apt-get update && sudo apt-get install -y ${tool}`;
51803
+ }
51804
+ }
51805
+ function getLinuxManualInstallHint(tool, packageManager) {
51806
+ if (packageManager) return getLinuxInstallCommand(tool, packageManager);
51807
+ return `${tool} — download from ${tool === "jq" ? "https://jqlang.github.io/jq/download/" : "https://github.com/tmux/tmux/wiki/Installing"}`;
51808
+ }
51809
+ async function installLinuxPackage(tool) {
51810
+ const packageManager = await detectLinuxPackageManager();
51811
+ if (!packageManager) throw new Error(`No supported Linux package manager found. Install ${getLinuxManualInstallHint(tool, null)}`);
51812
+ await execAsync$1(getLinuxInstallCommand(tool, packageManager), { timeout: 12e4 });
51813
+ }
51593
51814
  async function isToolInstalled(tool) {
51594
51815
  if (tool === "docker") return checkCommand("docker", ["info"]);
51595
51816
  if (tool === "traefik") try {
@@ -51632,7 +51853,7 @@ async function installTool(tool) {
51632
51853
  }
51633
51854
  async function installTmux() {
51634
51855
  if (await Effect.runPromise(detectPlatform()) === "darwin") await execAsync$1("brew install tmux", { timeout: 12e4 });
51635
- else await execAsync$1("sudo apt-get update && sudo apt-get install -y tmux", { timeout: 12e4 });
51856
+ else await installLinuxPackage("tmux");
51636
51857
  return {
51637
51858
  tool: "tmux",
51638
51859
  success: true,
@@ -51682,7 +51903,7 @@ async function installMkcert() {
51682
51903
  }
51683
51904
  async function installJq() {
51684
51905
  if (await Effect.runPromise(detectPlatform()) === "darwin") await execAsync$1("brew install jq", { timeout: 12e4 });
51685
- else await execAsync$1("sudo apt-get update && sudo apt-get install -y jq", { timeout: 12e4 });
51906
+ else await installLinuxPackage("jq");
51686
51907
  return {
51687
51908
  tool: "jq",
51688
51909
  success: true,
@@ -52417,7 +52638,7 @@ function getCheckpointWorker() {
52417
52638
  return worker;
52418
52639
  }
52419
52640
  async function runInline(operation, payload) {
52420
- const { claimTranscriptRange, commitTranscriptRange, releaseTranscriptRange, getTranscriptCheckpoint, listTranscriptCheckpoints } = await import("./checkpoints-DwZqT2qQ.js");
52641
+ const { claimTranscriptRange, commitTranscriptRange, releaseTranscriptRange, getTranscriptCheckpoint, listTranscriptCheckpoints } = await import("./checkpoints-CpgCjAlN.js");
52421
52642
  switch (operation) {
52422
52643
  case "claimTranscriptRange": return claimTranscriptRange(payload);
52423
52644
  case "commitTranscriptRange": return commitTranscriptRange(payload);
@@ -53571,7 +53792,7 @@ function buildPendingTurn(input, fromOffset, toOffset, compressed) {
53571
53792
  };
53572
53793
  }
53573
53794
  async function emitMemoryObservationCreated(observation, timestamp) {
53574
- const { initEventStore } = await import("./event-store-DABarGNz.js");
53795
+ const { initEventStore } = await import("./event-store-Cr5PQwFC.js");
53575
53796
  await (await initEventStore()).appendAsync({
53576
53797
  type: "memory.observation_created",
53577
53798
  timestamp,
@@ -56583,7 +56804,7 @@ async function getFlywheelConversationPayload() {
56583
56804
  };
56584
56805
  }
56585
56806
  async function postFlywheelReportPayload() {
56586
- const { flywheelReportCommand } = await import("./flywheel-DPUc8r3V.js");
56807
+ const { flywheelReportCommand } = await import("./flywheel-DcBkQvgE.js");
56587
56808
  await flywheelReportCommand({ cwd: process.cwd() });
56588
56809
  return {
56589
56810
  status: 200,
@@ -56741,11 +56962,11 @@ const getMergeBlockersRoute = HttpRouter.add("GET", "/api/flywheel/merge-blocker
56741
56962
  async function defaultGetOrderedIssueIds() {
56742
56963
  const status = await readCurrentFlywheelStatusForDashboard();
56743
56964
  if (!status) return [];
56744
- const { computeMergeQueue } = await import("./flywheel-merge-order-CeBuX0EJ.js");
56965
+ const { computeMergeQueue } = await import("./flywheel-merge-order-C-6zRLvM.js");
56745
56966
  return (await Effect.runPromise(computeMergeQueue(status.activePipeline, process.cwd()).pipe(Effect.provide(layer)))).map((i) => i.issueId);
56746
56967
  }
56747
56968
  async function defaultMergeOne(issueId) {
56748
- const { triggerMerge } = await import("./merge-ops-BpTtuO8x.js");
56969
+ const { triggerMerge } = await import("./merge-ops-DlB1IM0Y.js");
56749
56970
  const r = await triggerMerge(issueId);
56750
56971
  return r.success ? { ok: true } : {
56751
56972
  ok: false,
@@ -56765,7 +56986,7 @@ async function postFlywheelMergeNextPayload(payload, deps = {}) {
56765
56986
  body: { error: "n must be a positive integer" }
56766
56987
  };
56767
56988
  const issueIds = (await (deps.getOrderedIssueIds ?? defaultGetOrderedIssueIds)()).slice(0, n);
56768
- const { shipMergeBatch } = await import("./merge-batch-C2w2U2eK.js");
56989
+ const { shipMergeBatch } = await import("./merge-batch-Bwoyr8Je.js");
56769
56990
  return {
56770
56991
  status: 200,
56771
56992
  body: { outcomes: await shipMergeBatch(issueIds, { merge: deps.merge ?? defaultMergeOne }) }
@@ -56922,7 +57143,7 @@ const getFlywheelMergeQueueRoute = HttpRouter.add("GET", "/api/flywheel/merge-qu
56922
57143
  return yield* Effect.promise(async () => {
56923
57144
  const status = await readCurrentFlywheelStatusForDashboard();
56924
57145
  if (!status) return jsonResponse([]);
56925
- const { computeMergeQueue, resolveMergeQueuePrUrl } = await import("./flywheel-merge-order-CeBuX0EJ.js");
57146
+ const { computeMergeQueue, resolveMergeQueuePrUrl } = await import("./flywheel-merge-order-C-6zRLvM.js");
56926
57147
  return jsonResponse(await Effect.runPromise(computeMergeQueue(status.activePipeline, process.cwd(), { getPrUrl: resolveMergeQueuePrUrl }).pipe(Effect.provide(layer))));
56927
57148
  });
56928
57149
  })));
@@ -56936,18 +57157,18 @@ function uatGenerationNameFromParam(param) {
56936
57157
  return decoded.startsWith("uat/") ? decoded : `uat/${decoded}`;
56937
57158
  }
56938
57159
  const getUatGenerationsRoute = HttpRouter.add("GET", "/api/flywheel/uat-generations", httpHandler(Effect.gen(function* () {
56939
- const { getUatGenerationsPayload } = yield* Effect.promise(() => import("./uat-train-Wismge7h.js"));
57160
+ const { getUatGenerationsPayload } = yield* Effect.promise(() => import("./uat-train-cKfM-_WW.js"));
56940
57161
  return jsonResponse(yield* Effect.promise(() => getUatGenerationsPayload()));
56941
57162
  })));
56942
57163
  const getUatCandidateRoute = HttpRouter.add("GET", "/api/flywheel/uat-candidate", httpHandler(Effect.gen(function* () {
56943
- const { getUatCandidatePayload } = yield* Effect.promise(() => import("./uat-train-Wismge7h.js"));
57164
+ const { getUatCandidatePayload } = yield* Effect.promise(() => import("./uat-train-cKfM-_WW.js"));
56944
57165
  return jsonResponse(yield* Effect.promise(() => getUatCandidatePayload()));
56945
57166
  })));
56946
57167
  const postUatGenerationStackRoute = HttpRouter.add("POST", "/api/flywheel/uat-generations/:name/stack", httpHandler(Effect.gen(function* () {
56947
57168
  const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
56948
57169
  if (authError) return authError;
56949
57170
  const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
56950
- const { postUatGenerationStackPayload } = yield* Effect.promise(() => import("./uat-train-Wismge7h.js"));
57171
+ const { postUatGenerationStackPayload } = yield* Effect.promise(() => import("./uat-train-cKfM-_WW.js"));
56951
57172
  const result = yield* Effect.promise(() => postUatGenerationStackPayload(name));
56952
57173
  if (!result.ok) return jsonResponse({ error: result.error }, { status: result.status });
56953
57174
  return jsonResponse({
@@ -56959,8 +57180,8 @@ const postUatGenerationPromoteRoute = HttpRouter.add("POST", "/api/flywheel/uat-
56959
57180
  const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
56960
57181
  if (authError) return authError;
56961
57182
  const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
56962
- const { postUatGenerationPromotePayload } = yield* Effect.promise(() => import("./uat-train-Wismge7h.js"));
56963
- const { firePostMergeLifecycle } = yield* Effect.promise(() => import("./specialists-D0VBf8g_.js"));
57183
+ const { postUatGenerationPromotePayload } = yield* Effect.promise(() => import("./uat-train-cKfM-_WW.js"));
57184
+ const { firePostMergeLifecycle } = yield* Effect.promise(() => import("./specialists-D5fRZXmN.js"));
56964
57185
  const result = yield* Effect.promise(() => postUatGenerationPromotePayload(name, firePostMergeLifecycle));
56965
57186
  if (!result.success) return jsonResponse(result, { status: result.reason === "not-found" ? 404 : result.reason === "merge-failed" ? 500 : 409 });
56966
57187
  return jsonResponse(result);
@@ -56973,7 +57194,7 @@ const postUatGenerationPromoteRoute = HttpRouter.add("POST", "/api/flywheel/uat-
56973
57194
  const postFlywheelAssembleUatRoute = HttpRouter.add("POST", "/api/flywheel/assemble-uat", httpHandler(Effect.gen(function* () {
56974
57195
  const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
56975
57196
  if (authError) return authError;
56976
- const { runUatTrainReconcile } = yield* Effect.promise(() => import("./uat-train-Wismge7h.js"));
57197
+ const { runUatTrainReconcile } = yield* Effect.promise(() => import("./uat-train-cKfM-_WW.js"));
56977
57198
  return jsonResponse(yield* Effect.promise(() => runUatTrainReconcile({ force: true })));
56978
57199
  })));
56979
57200
  const getFlywheelStateRoute = HttpRouter.add("GET", "/api/flywheel/state", httpHandler(Effect.gen(function* () {
@@ -59796,6 +60017,27 @@ const postTieredCalloutsRoute = HttpRouter.add("POST", "/api/tiered/callouts", h
59796
60017
  })));
59797
60018
  const tieredCalloutsRouteLayer = Layer.mergeAll(postTieredCalloutsRoute);
59798
60019
  //#endregion
60020
+ //#region server-bind.ts
60021
+ function isAddressInUseError(error) {
60022
+ if (!error || typeof error !== "object") return false;
60023
+ if ("code" in error && error.code === "EADDRINUSE") return true;
60024
+ return "cause" in error && isAddressInUseError(error.cause);
60025
+ }
60026
+ const BIND_RETRY_DELAY_MS = 250;
60027
+ const BIND_RETRY_COUNT = 3;
60028
+ function retryDashboardBind(bind, onRetry) {
60029
+ let failures = 0;
60030
+ const observedBind = Effect.tapError(bind, (error) => Effect.sync(() => {
60031
+ failures += 1;
60032
+ if (failures <= BIND_RETRY_COUNT && isAddressInUseError(error)) onRetry?.(failures, BIND_RETRY_DELAY_MS);
60033
+ }));
60034
+ return Effect.retry(observedBind, {
60035
+ times: BIND_RETRY_COUNT,
60036
+ schedule: Schedule.spaced(Duration.millis(BIND_RETRY_DELAY_MS)),
60037
+ while: isAddressInUseError
60038
+ });
60039
+ }
60040
+ //#endregion
59799
60041
  //#region server.ts
59800
60042
  /**
59801
60043
  * Dashboard HTTP server — Effect-based with dual-runtime support (PAN-428 B5)
@@ -59821,14 +60063,19 @@ init_activity_logger();
59821
60063
  const HttpServerLive = Layer.unwrap(Effect.gen(function* () {
59822
60064
  const config = yield* ServerConfig;
59823
60065
  const [NodeHttpServer, NodeHttp] = yield* Effect.all([Effect.promise(() => import("@effect/platform-node/NodeHttpServer")), Effect.promise(() => import("node:http"))]);
59824
- const nodeServer = NodeHttp.createServer();
59825
- setupTerminalWebSocket(nodeServer);
59826
- setupVoiceWebSocket(nodeServer);
59827
- setupAutoPresoWebSocket(nodeServer);
59828
- return NodeHttpServer.layer(() => nodeServer, {
60066
+ const bind = retryDashboardBind(NodeHttpServer.make(() => {
60067
+ const nodeServer = NodeHttp.createServer();
60068
+ setupTerminalWebSocket(nodeServer);
60069
+ setupVoiceWebSocket(nodeServer);
60070
+ setupAutoPresoWebSocket(nodeServer);
60071
+ return nodeServer;
60072
+ }, {
59829
60073
  host: config.host,
59830
60074
  port: config.port
60075
+ }), (attempt, delayMs) => {
60076
+ console.warn(`[overdeck] HTTP bind failed with EADDRINUSE; retry ${attempt}/3 in ${delayMs}ms`);
59831
60077
  });
60078
+ return Layer.mergeAll(Layer.effect(HttpServer.HttpServer)(bind), NodeHttpServer.layerHttpServices);
59832
60079
  }));
59833
60080
  const PlatformServicesLive = Layer.unwrap(Effect.gen(function* () {
59834
60081
  const { layer } = yield* Effect.promise(() => import("@effect/platform-node/NodeServices"));
@@ -59920,6 +60167,7 @@ const makeServerLayer = Layer.unwrap(Effect.gen(function* () {
59920
60167
  const httpListeningLayer = Layer.effectDiscard(Effect.gen(function* () {
59921
60168
  yield* HttpServer.HttpServer;
59922
60169
  yield* Effect.sync(() => {
60170
+ markDashboardListening();
59923
60171
  console.log(`[boot-timing] HTTP server listening at +${Math.round(performance.now())}ms (since process start)`);
59924
60172
  console.log(`[overdeck] Dashboard listening on http://${config.host}:${config.port}`);
59925
60173
  const mode = process.env["OVERDECK_MODE"] === "production" ? "production mode" : "development mode";
@@ -59978,7 +60226,7 @@ function buildAwaitingInputActivityMessage(agentId, issueId, kinds) {
59978
60226
  const kindList = kinds.length > 0 ? kinds.join(", ") : "input";
59979
60227
  return issueId ? `${agentId} on ${issueId} is waiting for ${kindList}` : `${agentId} is waiting for ${kindList}`;
59980
60228
  }
59981
- async function pollOnce$1(state) {
60229
+ async function pollOnce(state) {
59982
60230
  let runningAgents;
59983
60231
  try {
59984
60232
  runningAgents = await Effect.runPromise(listRunningAgents());
@@ -60108,8 +60356,8 @@ async function pollOnce$1(state) {
60108
60356
  /** Poll interval: 10 seconds (was 3s). The enrichment data changes slowly —
60109
60357
  * pending questions, resolution state, phase — none of these need sub-second
60110
60358
  * latency. 10s eliminates ~70% of poller I/O without any user-visible lag. */
60111
- const POLL_INTERVAL_MS$4 = 1e4;
60112
- const serviceState$3 = {
60359
+ const POLL_INTERVAL_MS$3 = 1e4;
60360
+ const serviceState$2 = {
60113
60361
  timer: null,
60114
60362
  lastEnrichment: /* @__PURE__ */ new Map(),
60115
60363
  lastScan: /* @__PURE__ */ new Map(),
@@ -60117,18 +60365,18 @@ const serviceState$3 = {
60117
60365
  reconciledAgentIds: /* @__PURE__ */ new Set()
60118
60366
  };
60119
60367
  function startAgentEnrichmentService() {
60120
- if (serviceState$3.timer !== null) return;
60121
- serviceState$3.timer = setInterval(() => {
60122
- pollOnce$1(serviceState$3).catch(() => {});
60123
- }, POLL_INTERVAL_MS$4);
60368
+ if (serviceState$2.timer !== null) return;
60369
+ serviceState$2.timer = setInterval(() => {
60370
+ pollOnce(serviceState$2).catch(() => {});
60371
+ }, POLL_INTERVAL_MS$3);
60124
60372
  }
60125
60373
  function stopAgentEnrichmentService() {
60126
- if (serviceState$3.timer !== null) {
60127
- clearInterval(serviceState$3.timer);
60128
- serviceState$3.timer = null;
60374
+ if (serviceState$2.timer !== null) {
60375
+ clearInterval(serviceState$2.timer);
60376
+ serviceState$2.timer = null;
60129
60377
  }
60130
- serviceState$3.lastEnrichment.clear();
60131
- serviceState$3.lastScan.clear();
60378
+ serviceState$2.lastEnrichment.clear();
60379
+ serviceState$2.lastScan.clear();
60132
60380
  }
60133
60381
  //#endregion
60134
60382
  //#region services/merge-blocker-reconcile-service.ts
@@ -60148,7 +60396,7 @@ function stopAgentEnrichmentService() {
60148
60396
  * Bounded + cheap: each issue has a throttle. Ready/no-blocker rows use the PAN-1620
60149
60397
  * 3-minute cadence; already-blocked mergeability rows use a 10-minute cadence.
60150
60398
  */
60151
- const POLL_INTERVAL_MS$3 = 6e4;
60399
+ const POLL_INTERVAL_MS$2 = 6e4;
60152
60400
  /** Re-check each ready-to-merge PR at most this often, to bound `gh` calls. */
60153
60401
  const RECHECK_INTERVAL_MS = 18e4;
60154
60402
  /** Re-check already-flagged mergeability blockers less often; they are not mergeable yet. */
@@ -60159,7 +60407,7 @@ const MERGEABILITY_BLOCKERS = new Set([
60159
60407
  "failing_checks"
60160
60408
  ]);
60161
60409
  const MAX_REFRESH_CONCURRENCY = 4;
60162
- const serviceState$2 = {
60410
+ const serviceState$1 = {
60163
60411
  timer: null,
60164
60412
  lastChecked: /* @__PURE__ */ new Map(),
60165
60413
  blockerLastChecked: /* @__PURE__ */ new Map(),
@@ -60214,11 +60462,11 @@ async function reconcileOnce(state) {
60214
60462
  for (const id of [...state.blockerLastChecked.keys()]) if (!hasMergeabilityBlocker(candidateById.get(id)?.blockerReasons)) state.blockerLastChecked.delete(id);
60215
60463
  }
60216
60464
  function startMergeBlockerReconcileService() {
60217
- if (serviceState$2.timer !== null) return;
60218
- serviceState$2.timer = setInterval(() => {
60219
- reconcileOnce(serviceState$2).catch(() => {});
60220
- }, POLL_INTERVAL_MS$3);
60221
- serviceState$2.timer.unref?.();
60465
+ if (serviceState$1.timer !== null) return;
60466
+ serviceState$1.timer = setInterval(() => {
60467
+ reconcileOnce(serviceState$1).catch(() => {});
60468
+ }, POLL_INTERVAL_MS$2);
60469
+ serviceState$1.timer.unref?.();
60222
60470
  }
60223
60471
  function enqueueRefresh(state, task) {
60224
60472
  if (state.refreshInFlight.has(task.issueId)) return;
@@ -60241,6 +60489,174 @@ function drainRefreshQueue(state) {
60241
60489
  }
60242
60490
  }
60243
60491
  //#endregion
60492
+ //#region services/project-resource-refresh-queue.ts
60493
+ init_projects();
60494
+ const PROJECT_RESOURCE_CONVERGENCE_INTERVAL_MS = 5 * 6e4;
60495
+ function createProjectResourceRefreshQueue(deps) {
60496
+ const debounceMs = deps.debounceMs ?? 1e3;
60497
+ const now = deps.now ?? Date.now;
60498
+ const pending = /* @__PURE__ */ new Map();
60499
+ const reasons = /* @__PURE__ */ new Map();
60500
+ const idleWaiters = /* @__PURE__ */ new Set();
60501
+ let activeProjectPaths = [];
60502
+ let timer = null;
60503
+ let running = false;
60504
+ let stopped = false;
60505
+ let lastStartedAt = null;
60506
+ let lastCompletedAt = null;
60507
+ let lastError = null;
60508
+ const isIdle = () => !running && timer === null && pending.size === 0;
60509
+ const resolveIdleWaiters = () => {
60510
+ if (!isIdle()) return;
60511
+ for (const resolve of idleWaiters) resolve();
60512
+ idleWaiters.clear();
60513
+ };
60514
+ const drain = async () => {
60515
+ timer = null;
60516
+ if (running || stopped) return;
60517
+ running = true;
60518
+ try {
60519
+ while (!stopped && pending.size > 0) {
60520
+ const projects = [...pending.values()];
60521
+ const reasonsByProjectPath = /* @__PURE__ */ new Map();
60522
+ for (const project of projects) {
60523
+ reasonsByProjectPath.set(project.path, new Set(reasons.get(project.path) ?? []));
60524
+ reasons.delete(project.path);
60525
+ }
60526
+ pending.clear();
60527
+ activeProjectPaths = projects.map((project) => project.path);
60528
+ lastStartedAt = now();
60529
+ try {
60530
+ await deps.refreshProjects(projects, { reasonsByProjectPath });
60531
+ lastError = null;
60532
+ } catch (error) {
60533
+ lastError = error instanceof Error ? error.message : String(error);
60534
+ console.warn("[project-resource-refresh] batch failed:", lastError);
60535
+ } finally {
60536
+ activeProjectPaths = [];
60537
+ lastCompletedAt = now();
60538
+ }
60539
+ }
60540
+ } finally {
60541
+ running = false;
60542
+ resolveIdleWaiters();
60543
+ }
60544
+ };
60545
+ const schedule = () => {
60546
+ if (stopped || running || timer) return;
60547
+ timer = setTimeout(() => void drain(), debounceMs);
60548
+ timer.unref?.();
60549
+ };
60550
+ const enqueueProject = (project, reason) => {
60551
+ if (stopped) return;
60552
+ pending.set(project.path, project);
60553
+ const projectReasons = reasons.get(project.path) ?? /* @__PURE__ */ new Set();
60554
+ projectReasons.add(reason);
60555
+ reasons.set(project.path, projectReasons);
60556
+ schedule();
60557
+ };
60558
+ return {
60559
+ enqueueProject,
60560
+ enqueueProjects(projects, reason) {
60561
+ for (const project of projects) enqueueProject(project, reason);
60562
+ },
60563
+ whenIdle() {
60564
+ if (isIdle()) return Promise.resolve();
60565
+ return new Promise((resolve) => idleWaiters.add(resolve));
60566
+ },
60567
+ getState() {
60568
+ return {
60569
+ running,
60570
+ activeProjectPaths: [...activeProjectPaths],
60571
+ pendingProjectPaths: [...pending.keys()],
60572
+ lastStartedAt,
60573
+ lastCompletedAt,
60574
+ lastError
60575
+ };
60576
+ },
60577
+ stop() {
60578
+ stopped = true;
60579
+ if (timer) clearTimeout(timer);
60580
+ timer = null;
60581
+ pending.clear();
60582
+ reasons.clear();
60583
+ resolveIdleWaiters();
60584
+ }
60585
+ };
60586
+ }
60587
+ const MEMBERSHIP_REFRESH_REASONS = new Set(["boot-warm", "periodic-convergence"]);
60588
+ const projectResourceRefreshQueue = createProjectResourceRefreshQueue({ refreshProjects: (projects, context) => refreshResourceAllocatedProjects(projects, { refreshMembership: [...context.reasonsByProjectPath.values()].some((projectReasons) => [...projectReasons].some((reason) => MEMBERSHIP_REFRESH_REASONS.has(reason))) }) });
60589
+ function enqueueProjectsResourceRefresh(projects, reason) {
60590
+ projectResourceRefreshQueue.enqueueProjects(projects, reason);
60591
+ }
60592
+ function whenProjectResourceRefreshIdle() {
60593
+ return projectResourceRefreshQueue.whenIdle();
60594
+ }
60595
+ function getProjectResourceRefreshQueueState() {
60596
+ return projectResourceRefreshQueue.getState();
60597
+ }
60598
+ function stopProjectResourceRefreshQueue() {
60599
+ projectResourceRefreshQueue.stop();
60600
+ }
60601
+ function startProjectResourceConvergence() {
60602
+ const timer = setInterval(() => {
60603
+ enqueueProjectsResourceRefresh(listProjectsSync().map((entry) => entry.config), "periodic-convergence");
60604
+ }, PROJECT_RESOURCE_CONVERGENCE_INTERVAL_MS);
60605
+ timer.unref?.();
60606
+ return () => clearInterval(timer);
60607
+ }
60608
+ //#endregion
60609
+ //#region services/resource-refresh-triggers.ts
60610
+ init_agents$1();
60611
+ init_projects();
60612
+ init_event_store();
60613
+ const TRIGGER_EVENT_TYPES = new Set([
60614
+ "agent.created",
60615
+ "agent.started",
60616
+ "agent.stopped",
60617
+ "agent.completed",
60618
+ "agent.heartbeat_dead"
60619
+ ]);
60620
+ function createResourceRefreshTriggers(deps) {
60621
+ const warn = deps.warn ?? ((message) => console.warn(message));
60622
+ return deps.subscribe((event) => {
60623
+ if (!TRIGGER_EVENT_TYPES.has(event.type)) return;
60624
+ const payload = event.payload;
60625
+ let project = null;
60626
+ if (typeof payload?.projectKey === "string") project = deps.projectForKey(payload.projectKey);
60627
+ if (!project && typeof payload?.issueId === "string") project = deps.projectForIssue(payload.issueId);
60628
+ if (!project && typeof payload?.agentId === "string") {
60629
+ const issueId = deps.issueForAgent(payload.agentId);
60630
+ if (issueId) project = deps.projectForIssue(issueId);
60631
+ }
60632
+ if (!project) {
60633
+ warn(`[resource-refresh] skipped ${event.type}: affected project could not be resolved`);
60634
+ return;
60635
+ }
60636
+ deps.enqueueProjects([project], event.type);
60637
+ });
60638
+ }
60639
+ function startResourceRefreshTriggers() {
60640
+ const entries = () => listProjectsSync();
60641
+ return createResourceRefreshTriggers({
60642
+ subscribe: (fn) => getEventStore().subscribe(fn),
60643
+ projectForIssue: (issueId) => {
60644
+ const resolved = resolveProjectFromIssueSync(issueId);
60645
+ if (!resolved) return null;
60646
+ return entries().find((entry) => entry.key === resolved.projectKey)?.config ?? null;
60647
+ },
60648
+ projectForKey: (projectKey) => entries().find((entry) => entry.key === projectKey)?.config ?? null,
60649
+ issueForAgent: (agentId) => {
60650
+ try {
60651
+ return getAgentStateSync(agentId)?.issueId ?? null;
60652
+ } catch {
60653
+ return null;
60654
+ }
60655
+ },
60656
+ enqueueProjects: enqueueProjectsResourceRefresh
60657
+ });
60658
+ }
60659
+ //#endregion
60244
60660
  //#region ../../lib/cloister/stale-check-classifier.ts
60245
60661
  /**
60246
60662
  * Pure classification for stale PR checks inherited from a red main branch.
@@ -60426,12 +60842,12 @@ async function rerunFailedRun(repo, runId) {
60426
60842
  //#endregion
60427
60843
  //#region services/stale-check-retrigger-service.ts
60428
60844
  init_review_status_sync();
60429
- const POLL_INTERVAL_MS$2 = 6e4;
60845
+ const POLL_INTERVAL_MS$1 = 6e4;
60430
60846
  const MAIN_PROBE_INTERVAL_MS = 3 * 6e4;
60431
60847
  const EVAL_INTERVAL_MS = 10 * 6e4;
60432
60848
  const MAX_RERUNS_PER_TICK = 5;
60433
60849
  const RUN_STATE_RETENTION_MS = 1440 * 6e4;
60434
- const serviceState$1 = {
60850
+ const serviceState = {
60435
60851
  timer: null,
60436
60852
  repoWindows: /* @__PURE__ */ new Map(),
60437
60853
  lastEvaluated: /* @__PURE__ */ new Map(),
@@ -60577,120 +60993,21 @@ async function runTickIfIdle(state) {
60577
60993
  }
60578
60994
  }
60579
60995
  function startStaleCheckRetriggerService() {
60580
- if (serviceState$1.timer !== null) return;
60581
- serviceState$1.timer = setInterval(() => void runTickIfIdle(serviceState$1), POLL_INTERVAL_MS$2);
60582
- serviceState$1.timer.unref?.();
60996
+ if (serviceState.timer !== null) return;
60997
+ serviceState.timer = setInterval(() => void runTickIfIdle(serviceState), POLL_INTERVAL_MS$1);
60998
+ serviceState.timer.unref?.();
60583
60999
  }
60584
61000
  function shouldStartStaleCheckRetriggerService(env = process.env) {
60585
61001
  return env.OVERDECK_DISABLE_DEACON !== "1";
60586
61002
  }
60587
61003
  function stopStaleCheckRetriggerService() {
60588
- if (serviceState$1.timer !== null) clearInterval(serviceState$1.timer);
60589
- serviceState$1.timer = null;
60590
- serviceState$1.repoWindows.clear();
60591
- serviceState$1.lastEvaluated.clear();
60592
- serviceState$1.successfulRunIds.clear();
60593
- serviceState$1.failedRunsByIssue.clear();
60594
- serviceState$1.loggedSkips.clear();
60595
- }
60596
- //#endregion
60597
- //#region services/agent-output-service.ts
60598
- /**
60599
- * Agent Output Service (PAN-1221 F3)
60600
- *
60601
- * Background poller that captures tmux pane output for each running agent
60602
- * every ~3 seconds and emits `agent.output_received` domain events when
60603
- * new lines appear.
60604
- *
60605
- * This restores the event-driven output pipeline that DrawerActiveAgent
60606
- * expects — the reducer and WebSocket subscription already exist, but no
60607
- * server code was emitting the events.
60608
- */
60609
- init_agents$1();
60610
- init_tmux();
60611
- init_concurrency$1();
60612
- init_event_store();
60613
- function splitLines(text) {
60614
- const lines = text.split("\n");
60615
- if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
60616
- return lines;
60617
- }
60618
- /**
60619
- * Find new lines by looking for the longest suffix of `previous` that matches
60620
- * a prefix of `current`. The non-overlapping prefix of `current` is returned.
60621
- * If there is no overlap, all of `current` is new (pane was cleared or scrolled
60622
- * past the overlap window).
60623
- */
60624
- function diffLines(previous, current) {
60625
- if (previous.length === 0) return current;
60626
- for (let start = 0; start < previous.length; start++) {
60627
- const suffix = previous.slice(start);
60628
- if (suffix.length > current.length) continue;
60629
- if (suffix.every((line, i) => line === current[i])) return current.slice(suffix.length);
60630
- }
60631
- return current;
60632
- }
60633
- async function pollOnce(state) {
60634
- let runningAgents;
60635
- try {
60636
- runningAgents = await Effect.runPromise(listRunningAgents());
60637
- } catch {
60638
- return;
60639
- }
60640
- const eventStore = getEventStore();
60641
- const activeAgents = runningAgents.filter((a) => a.tmuxActive);
60642
- await Effect.runPromise(withConcurrencyLimit(activeAgents.map((agent) => Effect.tryPromise({
60643
- try: async () => {
60644
- const { id: agentId } = agent;
60645
- let stdout;
60646
- try {
60647
- const remoteState = await readFile(join(homedir$1(), ".overdeck", "agents", agentId, "remote-state.json"), "utf-8").then((text) => JSON.parse(text)).catch(() => null);
60648
- if (remoteState?.location === "remote" && remoteState?.vmName) {
60649
- const { getRemoteAgentOutput } = await import("./remote-agents-BNORDWAX.js");
60650
- stdout = await getRemoteAgentOutput(agentId, remoteState.vmName, 50);
60651
- } else stdout = await Effect.runPromise(capturePane(agentId, 50));
60652
- } catch {
60653
- stdout = await Effect.runPromise(capturePane(agentId, 50).pipe(Effect.catch(() => Effect.succeed(""))));
60654
- }
60655
- if (!stdout || stdout.trim() === "" || stdout.trim() === "Session not found") return;
60656
- const previousOutput = state.lastOutput.get(agentId) ?? "";
60657
- if (stdout === previousOutput) return;
60658
- const newLines = diffLines(splitLines(previousOutput), splitLines(stdout));
60659
- state.lastOutput.set(agentId, stdout);
60660
- if (newLines.length === 0) return;
60661
- const event = {
60662
- type: "agent.output_received",
60663
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
60664
- payload: {
60665
- agentId,
60666
- lines: newLines
60667
- }
60668
- };
60669
- eventStore.emitOnly(event);
60670
- },
60671
- catch: (cause) => cause
60672
- })), 4));
60673
- const activeIds = new Set(activeAgents.map((a) => a.id));
60674
- for (const id of state.lastOutput.keys()) if (!activeIds.has(id)) state.lastOutput.delete(id);
60675
- }
60676
- /** Poll interval: 3 seconds. Output is high-frequency and latency-sensitive. */
60677
- const POLL_INTERVAL_MS$1 = 3e3;
60678
- const serviceState = {
60679
- timer: null,
60680
- lastOutput: /* @__PURE__ */ new Map()
60681
- };
60682
- function startAgentOutputService() {
60683
- if (serviceState.timer !== null) return;
60684
- serviceState.timer = setInterval(() => {
60685
- pollOnce(serviceState).catch(() => {});
60686
- }, POLL_INTERVAL_MS$1);
60687
- }
60688
- function stopAgentOutputService() {
60689
- if (serviceState.timer !== null) {
60690
- clearInterval(serviceState.timer);
60691
- serviceState.timer = null;
60692
- }
60693
- serviceState.lastOutput.clear();
61004
+ if (serviceState.timer !== null) clearInterval(serviceState.timer);
61005
+ serviceState.timer = null;
61006
+ serviceState.repoWindows.clear();
61007
+ serviceState.lastEvaluated.clear();
61008
+ serviceState.successfulRunIds.clear();
61009
+ serviceState.failedRunsByIssue.clear();
61010
+ serviceState.loggedSkips.clear();
60694
61011
  }
60695
61012
  //#endregion
60696
61013
  //#region services/conversation-lifecycle.ts
@@ -60710,7 +61027,7 @@ function stopAgentOutputService() {
60710
61027
  * spawn-only.
60711
61028
  */
60712
61029
  init_conversations();
60713
- init_tmux();
61030
+ init_runtime_census();
60714
61031
  init_paths();
60715
61032
  init_behavior();
60716
61033
  const POLL_INTERVAL_MS = 1e4;
@@ -60754,12 +61071,10 @@ async function tailFile(path, maxBytes) {
60754
61071
  * a "; "-prefixed suffix for the log line, or "" when nothing is available.
60755
61072
  * Every probe is independently guarded so a diagnostics failure never throws.
60756
61073
  */
60757
- async function captureCorpseDiagnostics(tmuxSession) {
61074
+ async function captureCorpseDiagnostics(tmuxSession, census) {
60758
61075
  const parts = [];
60759
- try {
60760
- const status = (await Effect.runPromise(listPaneValues(tmuxSession, "#{pane_dead_status}"))).find((v) => v.trim() !== "")?.trim();
60761
- if (status) parts.push(`exitStatus=${status}`);
60762
- } catch {}
61076
+ const status = (census.panesBySession.get(tmuxSession) ?? []).map((pane) => pane.paneDeadStatus).find((value) => value !== null);
61077
+ if (status !== void 0) parts.push(`exitStatus=${status}`);
60763
61078
  try {
60764
61079
  const logPath = join$1(getOverdeckHome(), "agents", tmuxSession, "output.log");
60765
61080
  if (existsSync(logPath)) {
@@ -60779,7 +61094,10 @@ async function pollConversations() {
60779
61094
  try {
60780
61095
  const conversations = listConversations();
60781
61096
  if (conversations.length === 0) return;
60782
- const aliveSessions = new Set(await Effect.runPromise(listSessionNames()));
61097
+ const census = await getRuntimeCensus();
61098
+ if (!census.available) return;
61099
+ const aliveSessions = new Set(census.sessionNames);
61100
+ let revalidationCensus = null;
60783
61101
  const endedConversations = [];
60784
61102
  let sessionGoneCount = 0;
60785
61103
  let keepAliveCorpseCount = 0;
@@ -60787,8 +61105,8 @@ async function pollConversations() {
60787
61105
  const now = Date.now();
60788
61106
  for (const conv of conversations) {
60789
61107
  if (now - new Date(conv.createdAt).getTime() < SPAWN_GRACE_PERIOD_MS) continue;
60790
- const sessionGone = !aliveSessions.has(conv.tmuxSession);
60791
- const harnessGone = !sessionGone && !await isHarnessProcessAlive(conv.tmuxSession);
61108
+ let sessionGone = !aliveSessions.has(conv.tmuxSession);
61109
+ let harnessGone = !sessionGone && !await runtimeCensusHasHarnessProcess(census, conv.tmuxSession);
60792
61110
  if (!sessionGone && !harnessGone) {
60793
61111
  if (conv.status === "ended") {
60794
61112
  console.log(`[conversation-lifecycle] Session ${conv.tmuxSession} alive but row marked ended — resurrecting to active`);
@@ -60801,9 +61119,14 @@ async function pollConversations() {
60801
61119
  const fresh = getConversationByName(conv.name) ?? conv;
60802
61120
  const lastAliveSignalMs = Math.max(new Date(fresh.createdAt).getTime() || 0, fresh.lastAttachedAt ? new Date(fresh.lastAttachedAt).getTime() || 0 : 0);
60803
61121
  if (Date.now() - lastAliveSignalMs < SPAWN_GRACE_PERIOD_MS) continue;
61122
+ revalidationCensus ??= await refreshRuntimeCensus();
61123
+ if (!revalidationCensus.available) continue;
61124
+ sessionGone = !revalidationCensus.sessionNames.has(conv.tmuxSession);
61125
+ harnessGone = !sessionGone && !await runtimeCensusHasHarnessProcess(revalidationCensus, conv.tmuxSession);
61126
+ if (!sessionGone && !harnessGone) continue;
60804
61127
  if (process.env.DEBUG?.includes("conversation-lifecycle")) console.log(sessionGone ? `[conversation-lifecycle] Session ${conv.tmuxSession} gone — marking ended` : `[conversation-lifecycle] Session ${conv.tmuxSession} alive but harness exited (keep-alive corpse) — marking ended`);
60805
61128
  if (!sessionGone) {
60806
- const diag = await captureCorpseDiagnostics(conv.tmuxSession);
61129
+ const diag = await captureCorpseDiagnostics(conv.tmuxSession, revalidationCensus);
60807
61130
  if (diag) keepAliveCorpseDiagnostics.push(`${conv.tmuxSession}${diag}`);
60808
61131
  }
60809
61132
  markConversationEnded(conv.name);
@@ -61458,7 +61781,8 @@ init_event_store();
61458
61781
  init_tracker_config();
61459
61782
  const DEFAULT_INTERVAL_MS = 6e4;
61460
61783
  const DEFAULT_LOOKBACK_MS = 5 * 6e4;
61461
- const BOT_LOGIN = "panopticon-agent[bot]";
61784
+ const FLYWHEEL_FILED_BY_TRAILER = "\"Flywheel-Filed-By:\" in:body";
61785
+ const LEGACY_BOT_LOGIN = "panopticon-agent[bot]";
61462
61786
  var CacheServiceRateLimitStore = class {
61463
61787
  cache = null;
61464
61788
  getCache() {
@@ -61564,14 +61888,14 @@ function createSubstrateBugPoller(options = {}) {
61564
61888
  const since = isoLookback(now(), lookbackMs);
61565
61889
  for (const repo of config.repos) try {
61566
61890
  const repoQualifier = `repo:${repo.owner}/${repo.repo}`;
61567
- const authorResults = await fetchSearch(config.token, searchQuery([
61891
+ const trailerResults = await fetchSearch(config.token, searchQuery([
61568
61892
  repoQualifier,
61569
61893
  "is:issue",
61570
61894
  "-is:pr",
61571
- `author:${BOT_LOGIN}`,
61895
+ FLYWHEEL_FILED_BY_TRAILER,
61572
61896
  `updated:>=${since}`
61573
61897
  ]));
61574
- if (authorResults === null) return;
61898
+ if (trailerResults === null) return;
61575
61899
  const substrateResults = await fetchSearch(config.token, searchQuery([
61576
61900
  repoQualifier,
61577
61901
  "is:issue",
@@ -61581,12 +61905,12 @@ function createSubstrateBugPoller(options = {}) {
61581
61905
  ]));
61582
61906
  if (substrateResults === null) return;
61583
61907
  const byNumber = /* @__PURE__ */ new Map();
61584
- for (const issue of [...authorResults, ...substrateResults]) byNumber.set(issue.number, issue);
61908
+ for (const issue of [...trailerResults, ...substrateResults]) byNumber.set(issue.number, issue);
61585
61909
  for (const issue of byNumber.values()) {
61586
61910
  const issueId = issueIdFor(repo.prefix, issue.number);
61587
61911
  if (!issueId) continue;
61588
61912
  const trailer = parseSubstrateBugTrailer(issue.body);
61589
- const filedBy = trailer.filedBy ?? (issue.user?.login === BOT_LOGIN ? "agent" : "operator");
61913
+ const filedBy = trailer.filedBy ?? (issue.user?.login === LEGACY_BOT_LOGIN ? "agent" : "operator");
61590
61914
  const labelNames = (issue.labels ?? []).map((label) => typeof label === "string" ? label : label.name ?? "");
61591
61915
  const affectedCriteria = parseAffectedCriteria(issue.body, labelNames);
61592
61916
  const existing = repository.getByIssueId(issueId);
@@ -61852,7 +62176,7 @@ const RESTART_MARKER = join$1(homedir(), ".overdeck", "dashboard-restarting.json
61852
62176
  * loads new content-hashed chunk filenames (no ERR_MODULE_NOT_FOUND after rebuild).
61853
62177
  */
61854
62178
  async function defaultLifecycleRunner(pending) {
61855
- const { postMergeLifecycle, notifyTldrDaemon } = await import("./merge-agent-CnORPiri.js");
62179
+ const { postMergeLifecycle, notifyTldrDaemon } = await import("./merge-agent-BQM3a8z5.js");
61856
62180
  await postMergeLifecycle(pending.issueId, pending.projectPath, pending.sourceBranch, { skipDeploy: true });
61857
62181
  if (pending.sourceBranch) await notifyTldrDaemon(pending.projectPath, pending.sourceBranch);
61858
62182
  }
@@ -62173,7 +62497,7 @@ function failureReason(result) {
62173
62497
  return result.error ?? result.message ?? `merge returned status ${result.statusCode ?? "unknown"}`;
62174
62498
  }
62175
62499
  async function defaultMergeIssue(issueId) {
62176
- const { triggerMerge } = await import("./merge-ops-BpTtuO8x.js");
62500
+ const { triggerMerge } = await import("./merge-ops-DlB1IM0Y.js");
62177
62501
  return triggerMerge(issueId);
62178
62502
  }
62179
62503
  function defaultAnnounceFailure(issueId, reason) {
@@ -62401,24 +62725,27 @@ init_projects();
62401
62725
  init_state_home();
62402
62726
  const execFileAsync = promisify(execFile);
62403
62727
  const inFlight = /* @__PURE__ */ new Map();
62404
- async function pathIsGitWorkTree(path) {
62728
+ async function pathIsGitWorkTree(path, signal) {
62405
62729
  try {
62730
+ signal?.throwIfAborted();
62406
62731
  const { stdout } = await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], {
62407
62732
  cwd: path,
62408
62733
  encoding: "utf8",
62409
- timeout: 15e3
62734
+ timeout: 15e3,
62735
+ signal
62410
62736
  });
62411
62737
  return stdout.trim() === "true";
62412
62738
  } catch {
62739
+ signal?.throwIfAborted();
62413
62740
  return false;
62414
62741
  }
62415
62742
  }
62416
62743
  const defaultDependencies = {
62417
62744
  inspect: inspectStateMigration,
62418
62745
  ensureWorktree: ensureStateWorktree,
62419
- migrate: async (projectKey, project) => {
62420
- const { migrateProjectState } = await import("./state-migrate-_zJJ6XKE.js");
62421
- await migrateProjectState(projectKey, {}, project);
62746
+ migrate: async (projectKey, project, signal) => {
62747
+ const { migrateProjectState } = await import("./state-migrate-Dkzaxvny.js");
62748
+ await migrateProjectState(projectKey, { signal }, project);
62422
62749
  },
62423
62750
  clearCache: clearStateMigrationCache,
62424
62751
  isGitWorkTree: pathIsGitWorkTree
@@ -62445,24 +62772,28 @@ function blocked(projectKey, error) {
62445
62772
  function worktreeBlockReason(status) {
62446
62773
  return `The canonical overdeck-state worktree is ${status.status}: ${status.detail}`;
62447
62774
  }
62448
- async function reconcile(projectKey, project, dependencies) {
62775
+ async function reconcile(projectKey, project, dependencies, signal) {
62449
62776
  try {
62450
- if (!(await dependencies.inspect(project)).migrated) {
62777
+ if (!(await dependencies.inspect(project, { signal })).migrated) {
62451
62778
  const { repoPath } = resolveInfraRepo(project);
62452
- if (!await dependencies.isGitWorkTree(repoPath)) return blocked(projectKey, describeUnmigratableProjectPath(projectKey, project, repoPath));
62453
- await dependencies.migrate(projectKey, project);
62779
+ if (!await dependencies.isGitWorkTree(repoPath, signal)) return blocked(projectKey, describeUnmigratableProjectPath(projectKey, project, repoPath));
62780
+ await dependencies.migrate(projectKey, project, signal);
62454
62781
  dependencies.clearCache();
62455
- if (!(await dependencies.inspect(project)).migrated) return blocked(projectKey, "Migration completed without a valid marker on origin/overdeck-state.");
62782
+ if (!(await dependencies.inspect(project, { signal })).migrated) return blocked(projectKey, "Migration completed without a valid marker on origin/overdeck-state.");
62456
62783
  }
62457
- const worktree = await dependencies.ensureWorktree(project, { projectKey });
62784
+ const worktree = await dependencies.ensureWorktree(project, {
62785
+ projectKey,
62786
+ signal
62787
+ });
62458
62788
  if (worktree.status === "dirty" || worktree.status === "error") return blocked(projectKey, worktreeBlockReason(worktree));
62459
- if (worktree.status === "legacy") return blocked(projectKey, "The remote migration marker is valid but the local state worktree still resolves to the legacy project checkout.");
62789
+ if (worktree.status === "legacy") return blocked(projectKey, worktree.detail);
62460
62790
  return {
62461
62791
  status: "ready",
62462
62792
  projectKey,
62463
62793
  worktree: worktree.status
62464
62794
  };
62465
62795
  } catch (error) {
62796
+ signal.throwIfAborted();
62466
62797
  return blocked(projectKey, error);
62467
62798
  }
62468
62799
  }
@@ -62471,12 +62802,39 @@ async function reconcile(projectKey, project, dependencies) {
62471
62802
  * state. Concurrent dashboard/CLI callers on this process share one attempt;
62472
62803
  * the migration command supplies the cross-process lock and no-loss gates.
62473
62804
  */
62474
- function ensureAutomaticStateMigration(projectKey, project, dependencies = defaultDependencies) {
62475
- const existing = inFlight.get(projectKey);
62476
- if (existing) return existing;
62477
- const task = reconcile(projectKey, project, dependencies).finally(() => inFlight.delete(projectKey));
62478
- inFlight.set(projectKey, task);
62479
- return task;
62805
+ function ensureAutomaticStateMigration(projectKey, project, dependencies = defaultDependencies, signal) {
62806
+ signal?.throwIfAborted();
62807
+ let entry = inFlight.get(projectKey);
62808
+ if (!entry) {
62809
+ const controller = new AbortController();
62810
+ const task = reconcile(projectKey, project, dependencies, controller.signal).finally(() => inFlight.delete(projectKey));
62811
+ entry = {
62812
+ controller,
62813
+ persistentOwner: signal === void 0,
62814
+ waiters: /* @__PURE__ */ new Map(),
62815
+ task
62816
+ };
62817
+ inFlight.set(projectKey, entry);
62818
+ } else if (!signal) entry.persistentOwner = true;
62819
+ if (!signal) return entry.task;
62820
+ const token = Symbol(projectKey);
62821
+ entry.waiters.set(token, false);
62822
+ const maybeAbortSharedMigration = () => {
62823
+ entry?.waiters.set(token, true);
62824
+ if (!entry?.persistentOwner && [...entry.waiters.values()].every(Boolean)) entry.controller.abort(signal.reason);
62825
+ };
62826
+ signal.addEventListener("abort", maybeAbortSharedMigration, { once: true });
62827
+ if (signal.aborted) maybeAbortSharedMigration();
62828
+ return entry.task.then((result) => {
62829
+ signal.throwIfAborted();
62830
+ return result;
62831
+ }, (error) => {
62832
+ signal.throwIfAborted();
62833
+ throw error;
62834
+ }).finally(() => {
62835
+ signal.removeEventListener("abort", maybeAbortSharedMigration);
62836
+ entry?.waiters.delete(token);
62837
+ });
62480
62838
  }
62481
62839
  function formatAutomaticStateMigrationBlock(result) {
62482
62840
  return `State migration for ${result.projectKey} is blocked: ${result.reason} Overdeck will not start pipeline work because that would write permanent state into the legacy project checkout. Resolve the stated prerequisite, then run "pan sync"; do not commit project-root .pan/ or .beads/ files.`;
@@ -62514,6 +62872,7 @@ function decideDeaconBootGate(migrations) {
62514
62872
  //#region main.ts
62515
62873
  init_issue_service_singleton();
62516
62874
  init_tracker_config();
62875
+ init_internal_token();
62517
62876
  init_review_status();
62518
62877
  init_event_store();
62519
62878
  init_activity_logger();
@@ -62528,16 +62887,34 @@ init_projects();
62528
62887
  initDashboardLogFile();
62529
62888
  console.log(`[boot-timing] module graph loaded at +${Math.round(performance.now())}ms (since process start)`);
62530
62889
  console.log(`[overdeck] Boot gates: ${formatBootGateState(resolveBootGates())}`);
62531
- startEventLoopMonitor();
62532
- console.log("[overdeck] Event loop delay monitor started");
62533
62890
  await mkdir(getOverdeckHome(), { recursive: true });
62534
62891
  ensureInternalTokenSync();
62535
- warnIfAutonomousMergeBackendUnavailable();
62536
- warnIfAppCannotMerge();
62537
62892
  await ensureManagedTmuxContextOnce();
62538
62893
  await initTrackerConfigCache().catch((err) => {
62539
62894
  console.log("[tracker-config] Warning: failed to cache .overdeck.env:", err.message);
62540
62895
  });
62896
+ try {
62897
+ const overdeckDbPath = getOverdeckDatabasePath();
62898
+ if (!existsSync$1(overdeckDbPath)) {
62899
+ createOverdeckDatabase({ dbPath: overdeckDbPath });
62900
+ console.log(`[overdeck] Created overdeck.db at ${overdeckDbPath}`);
62901
+ }
62902
+ } catch (err) {
62903
+ console.warn("[overdeck] Overdeck db init failed (non-fatal):", err);
62904
+ }
62905
+ const main = runServer.pipe(Effect.provide(ServerConfigLayer));
62906
+ if (typeof Bun !== "undefined") {
62907
+ const { runMain } = await import("@effect/platform-bun/BunRuntime");
62908
+ runMain(main);
62909
+ } else {
62910
+ const { runMain } = await import("@effect/platform-node/NodeRuntime");
62911
+ runMain(main);
62912
+ }
62913
+ await whenDashboardListening();
62914
+ startEventLoopMonitor();
62915
+ console.log("[overdeck] Event loop delay monitor started");
62916
+ warnIfAutonomousMergeBackendUnavailable();
62917
+ warnIfAppCannotMerge();
62541
62918
  const isPeerDashboard = process.env.OVERDECK_DISABLE_DEACON === "1";
62542
62919
  if (isPeerDashboard) {
62543
62920
  startSharedIssueService({ skipPolling: true });
@@ -62575,7 +62952,7 @@ if (shouldStartStaleCheckRetriggerService()) {
62575
62952
  }
62576
62953
  if (process.env.OVERDECK_MODE === "desktop") (async () => {
62577
62954
  try {
62578
- const { provisionClaudeHooks } = await import("./claude-hooks-provision-CS5W_dhI.js");
62955
+ const { provisionClaudeHooks } = await import("./claude-hooks-provision-C8wdRnN1.js");
62579
62956
  const result = await provisionClaudeHooks();
62580
62957
  if (!result.ok) console.warn(`[overdeck] Claude hook provisioning skipped: ${result.reason}`);
62581
62958
  else if (result.changed) console.log(`[overdeck] Claude hooks provisioned: ${result.binariesSynced} scripts, registered ${result.registered.length} hook(s)${result.pruned.length ? `, pruned ${result.pruned.length} stale` : ""}`);
@@ -62802,7 +63179,8 @@ setMergeReadyNotifier((issueId) => {
62802
63179
  console.log("[overdeck] Merge-ready notifier → domain events wired");
62803
63180
  startConversationLifecycleService();
62804
63181
  console.log("[overdeck] ConversationLifecycleService started");
62805
- startSubstrateBugPoller();
63182
+ if (isPeerDashboard) console.log("[overdeck] SubstrateBugPoller skipped — peer dashboard does not poll trackers");
63183
+ else startSubstrateBugPoller();
62806
63184
  if (startUatTrainReconciler()) console.log("[overdeck] UAT batch-train reconciler started");
62807
63185
  else console.log("[overdeck] UAT batch-train reconciler skipped — non-primary dashboard process");
62808
63186
  const attachmentCleanupTimer = setInterval(() => {
@@ -62821,8 +63199,31 @@ startCostReconcileService();
62821
63199
  console.log("[overdeck] Cost reconciler started");
62822
63200
  const conversationSearchWatcher = startConversationSearchWatcher();
62823
63201
  console.log(conversationSearchWatcher ? "[overdeck] Conversation search watcher started" : "[overdeck] Conversation search watcher skipped (conversationSearch.enabled=false)");
63202
+ let stopResourceRefreshServices = () => void 0;
62824
63203
  (async () => {
62825
- (await initEventStore()).subscribe((event) => {
63204
+ const store = await initEventStore();
63205
+ whenDashboardListening().then(async () => {
63206
+ await new Promise((resolve) => setTimeout(resolve, 0));
63207
+ const stopTriggers = startResourceRefreshTriggers();
63208
+ const stopConvergence = startProjectResourceConvergence();
63209
+ const stopResourcesSnapshot = startResourcesSnapshotService();
63210
+ stopResourceRefreshServices = () => {
63211
+ stopTriggers();
63212
+ stopConvergence();
63213
+ stopResourcesSnapshot();
63214
+ stopProjectResourceRefreshQueue();
63215
+ };
63216
+ console.log("[overdeck] Project resource refresh queue and resources snapshot service started");
63217
+ const warmStart = Date.now();
63218
+ enqueueProjectsResourceRefresh(listProjectsSync().map((entry) => entry.config), "boot-warm");
63219
+ await whenProjectResourceRefreshIdle();
63220
+ const queueState = getProjectResourceRefreshQueueState();
63221
+ if (queueState.lastError) console.warn("[overdeck] Boot cache warm completed with errors:", queueState.lastError);
63222
+ else console.log(`[overdeck] Boot cache warm complete in ${Math.round((Date.now() - warmStart) / 1e3)}s`);
63223
+ }).catch((err) => {
63224
+ console.warn("[overdeck] Resource refresh startup failed:", err instanceof Error ? err.message : String(err));
63225
+ });
63226
+ store.subscribe((event) => {
62826
63227
  if (event.type === "agent.stopped" || event.type === "agent.heartbeat_dead") {
62827
63228
  const agentId = typeof event.payload.agentId === "string" ? event.payload.agentId : null;
62828
63229
  if (agentId) reconcileAgentMemory(agentId).catch((err) => console.warn("[memory-reconciliation] agent sweep failed:", err?.message ?? err));
@@ -62878,6 +63279,7 @@ const handleShutdownSignal = async (signal) => {
62878
63279
  if (forkGrace.count > 0) if (forkGrace.completed) console.log(`[overdeck] Waited for ${forkGrace.count} in-flight fork pipeline(s) before shutdown`);
62879
63280
  else console.warn(`[overdeck] ${forkGrace.count} in-flight fork pipeline(s) still running after shutdown grace window`);
62880
63281
  clearInterval(attachmentCleanupTimer);
63282
+ stopResourceRefreshServices();
62881
63283
  stopAgentEnrichmentService();
62882
63284
  stopAgentOutputService();
62883
63285
  stopConversationLifecycleService();
@@ -62893,7 +63295,7 @@ const handleShutdownSignal = async (signal) => {
62893
63295
  stopRestartAnnouncer();
62894
63296
  await stopDeaconChild().catch((err) => console.warn("[deacon-supervisor] child shutdown failed:", err?.message ?? err));
62895
63297
  try {
62896
- const { killAllGateProcessGroups } = await import("./validation-CUWamZ4X.js");
63298
+ const { killAllGateProcessGroups } = await import("./validation-CIi6pnI2.js");
62897
63299
  const reaped = killAllGateProcessGroups();
62898
63300
  if (reaped > 0) console.log(`[overdeck] reaped ${reaped} in-flight gate process group(s)`);
62899
63301
  } catch (err) {
@@ -62948,7 +63350,7 @@ reconcileStaleGitHubBlockers().then((n) => {
62948
63350
  }
62949
63351
  }).catch((err) => console.warn(`[overdeck] Startup blocker reconciliation failed: ${err.message}`));
62950
63352
  try {
62951
- const { resetProcessingToQueued } = await import("./merge-sync-CpGA9Kg7.js");
63353
+ const { resetProcessingToQueued } = await import("./merge-sync-SSv3E-pl.js");
62952
63354
  const resetCount = resetProcessingToQueued();
62953
63355
  if (resetCount > 0) {
62954
63356
  console.log(`[overdeck] Reset ${resetCount} stuck merge queue entries to queued`);
@@ -62970,7 +63372,7 @@ else {
62970
63372
  console.log("[overdeck] Auto-merge executor started");
62971
63373
  }
62972
63374
  try {
62973
- const { reconcileInterruptedVerifications } = await import("./verification-runner-Dcksl_P-.js");
63375
+ const { reconcileInterruptedVerifications } = await import("./verification-runner-CDj4lD4t.js");
62974
63376
  const interrupted = reconcileInterruptedVerifications();
62975
63377
  if (interrupted > 0) console.log(`[overdeck] recovered ${interrupted} orphaned verification worker(s)`);
62976
63378
  } catch (err) {
@@ -63009,7 +63411,9 @@ if (process.env.OVERDECK_DISABLE_DEACON === "1") {
63009
63411
  message: summary
63010
63412
  });
63011
63413
  }
63012
- if (startBootReconciliation({ onGraceExpired: applyBootReconciliationDecision }).decision !== "pending") applyBootReconciliationDecision();
63414
+ if (startBootReconciliation({ onGraceExpired: async () => {
63415
+ await applyBootReconciliationDecision();
63416
+ } }).decision !== "pending") applyBootReconciliationDecision();
63013
63417
  startDeaconChild().catch((err) => {
63014
63418
  console.error("[overdeck] Cloister auto-start failed:", err);
63015
63419
  emitActivityEntrySync({
@@ -63059,25 +63463,6 @@ async function pruneClosedIssueReviewStatuses() {
63059
63463
  } catch {}
63060
63464
  if (removed > 0) console.log(`[overdeck] Pruned ${removed} stale review-status entr${removed === 1 ? "y" : "ies"} for closed issues`);
63061
63465
  }
63062
- await (async () => {
63063
- try {
63064
- const overdeckDbPath = getOverdeckDatabasePath();
63065
- if (!existsSync$1(overdeckDbPath)) {
63066
- createOverdeckDatabase({ dbPath: overdeckDbPath });
63067
- console.log(`[overdeck] Created overdeck.db at ${overdeckDbPath}`);
63068
- }
63069
- } catch (err) {
63070
- console.warn("[overdeck] Overdeck db init failed (non-fatal):", err);
63071
- }
63072
- })();
63073
- const main = runServer.pipe(Effect.provide(ServerConfigLayer));
63074
- if (typeof Bun !== "undefined") {
63075
- const { runMain } = await import("@effect/platform-bun/BunRuntime");
63076
- runMain(main);
63077
- } else {
63078
- const { runMain } = await import("@effect/platform-node/NodeRuntime");
63079
- runMain(main);
63080
- }
63081
63466
  //#endregion
63082
63467
  export {};
63083
63468