panopticon-cli 0.6.4 → 0.6.6

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 (311) hide show
  1. package/README.md +2 -2
  2. package/dist/{agents-DfYify9s.js → agents-CfFDs52G.js} +14 -14
  3. package/dist/{agents-DfYify9s.js.map → agents-CfFDs52G.js.map} +1 -1
  4. package/dist/{agents-BKsVoIc9.js → agents-D_2oRFVf.js} +1 -1
  5. package/dist/{archive-planning-BJrZ3tmN.js → archive-planning-D97ziGec.js} +3 -3
  6. package/dist/{archive-planning-BJrZ3tmN.js.map → archive-planning-D97ziGec.js.map} +1 -1
  7. package/dist/{archive-planning-C3m3hfa5.js → archive-planning-DK90wn9Q.js} +1 -1
  8. package/dist/{browser-Cvdznzc0.js → browser-CX7jXfXX.js} +1 -1
  9. package/dist/{browser-Cvdznzc0.js.map → browser-CX7jXfXX.js.map} +1 -1
  10. package/dist/{clean-planning-DvhZAUv4.js → clean-planning-D_lz4aQq.js} +2 -2
  11. package/dist/{clean-planning-DvhZAUv4.js.map → clean-planning-D_lz4aQq.js.map} +1 -1
  12. package/dist/clean-planning-x1S-JdmO.js +2 -0
  13. package/dist/cli/index.js +291 -760
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/{close-issue-Dr7yZmrr.js → close-issue-CaFE0stN.js} +11 -7
  16. package/dist/close-issue-CaFE0stN.js.map +1 -0
  17. package/dist/close-issue-CjcfZI9s.js +2 -0
  18. package/dist/compact-beads-B0_qE1w3.js +2 -0
  19. package/dist/{compact-beads-BCOtIIRl.js → compact-beads-CjFkteSU.js} +2 -2
  20. package/dist/{compact-beads-BCOtIIRl.js.map → compact-beads-CjFkteSU.js.map} +1 -1
  21. package/dist/{config-CRzMQRgA.js → config-BQNKsi9G.js} +2 -2
  22. package/dist/{config-CRzMQRgA.js.map → config-BQNKsi9G.js.map} +1 -1
  23. package/dist/{config-BYgUzQ21.js → config-agyKgF5C.js} +1 -1
  24. package/dist/{config-yaml-BgOACZAB.js → config-yaml-DGbLSMCa.js} +1 -1
  25. package/dist/{config-yaml-BgOACZAB.js.map → config-yaml-DGbLSMCa.js.map} +1 -1
  26. package/dist/{config-yaml-fdyvyL0S.js → config-yaml-Dqt4FWQH.js} +1 -1
  27. package/dist/dashboard/{acceptance-criteria-e5iiHlRx.js → acceptance-criteria-Dk9hhiYj.js} +1 -1
  28. package/dist/dashboard/{acceptance-criteria-e5iiHlRx.js.map → acceptance-criteria-Dk9hhiYj.js.map} +1 -1
  29. package/dist/dashboard/{agent-enrichment-C67LJBgD.js → agent-enrichment-DdO7ZqjI.js} +11 -7
  30. package/dist/dashboard/agent-enrichment-DdO7ZqjI.js.map +1 -0
  31. package/dist/dashboard/{agent-enrichment-Cq0P1cNZ.js → agent-enrichment-dLeGE1fX.js} +1 -1
  32. package/dist/dashboard/{agents-YyO6t5Xa.js → agents-DCpQQ_W5.js} +14 -14
  33. package/dist/dashboard/{agents-YyO6t5Xa.js.map → agents-DCpQQ_W5.js.map} +1 -1
  34. package/dist/dashboard/{agents-BVBVCyat.js → agents-Dgh2TjSp.js} +1 -1
  35. package/dist/dashboard/{archive-planning-h-hAjk0P.js → archive-planning-BmW9UDTr.js} +3 -3
  36. package/dist/dashboard/{archive-planning-h-hAjk0P.js.map → archive-planning-BmW9UDTr.js.map} +1 -1
  37. package/dist/dashboard/{archive-planning-CScs1MOC.js → archive-planning-C3Ebf9yC.js} +1 -1
  38. package/dist/dashboard/{beads-qNB0yAHV.js → beads-Bv-AdX7G.js} +3 -3
  39. package/dist/dashboard/{beads-qNB0yAHV.js.map → beads-Bv-AdX7G.js.map} +1 -1
  40. package/dist/dashboard/{beads-D_FRedEJ.js → beads-By6-X07V.js} +1 -1
  41. package/dist/dashboard/clean-planning-D60L8rPY.js +2 -0
  42. package/dist/dashboard/{clean-planning-qafw99vY.js → clean-planning-VEJu5suh.js} +2 -2
  43. package/dist/dashboard/{clean-planning-qafw99vY.js.map → clean-planning-VEJu5suh.js.map} +1 -1
  44. package/dist/dashboard/close-issue-C2KeSKKJ.js +2 -0
  45. package/dist/dashboard/{close-issue-DfIggeZD.js → close-issue-DtKdsSTm.js} +11 -7
  46. package/dist/dashboard/close-issue-DtKdsSTm.js.map +1 -0
  47. package/dist/dashboard/compact-beads-C7BN5N11.js +2 -0
  48. package/dist/dashboard/{compact-beads-Dt0qTqsC.js → compact-beads-D8Vt3qyv.js} +2 -2
  49. package/dist/dashboard/{compact-beads-Dt0qTqsC.js.map → compact-beads-D8Vt3qyv.js.map} +1 -1
  50. package/dist/dashboard/{config-CUREjHP7.js → config-CDkGjnwy.js} +2 -2
  51. package/dist/dashboard/{config-CUREjHP7.js.map → config-CDkGjnwy.js.map} +1 -1
  52. package/dist/dashboard/{config-BeI3uy-8.js → config-CTXkBATQ.js} +1 -1
  53. package/dist/dashboard/{database-CozA13Wy.js → database-DhqASALP.js} +1 -1
  54. package/dist/dashboard/{database-C0y0hXBx.js → database-cxmQryoh.js} +2 -2
  55. package/dist/dashboard/{database-C0y0hXBx.js.map → database-cxmQryoh.js.map} +1 -1
  56. package/dist/dashboard/{dist-src-oG2iHzgI.js → dist-src-DTm11oQr.js} +1 -1
  57. package/dist/dashboard/{dist-src-oG2iHzgI.js.map → dist-src-DTm11oQr.js.map} +1 -1
  58. package/dist/dashboard/{event-store-D7kLBd07.js → event-store-VWWUmOfn.js} +1 -1
  59. package/dist/dashboard/{event-store-O9q0Gweh.js → event-store-vSmAA3Zp.js} +9 -4
  60. package/dist/dashboard/event-store-vSmAA3Zp.js.map +1 -0
  61. package/dist/dashboard/{factory-BnLdiQW-.js → factory-C8nhLGHB.js} +3 -3
  62. package/dist/dashboard/{factory-BnLdiQW-.js.map → factory-C8nhLGHB.js.map} +1 -1
  63. package/dist/dashboard/{feedback-writer-DyovUANg.js → feedback-writer-CudSe1WK.js} +2 -2
  64. package/dist/dashboard/{feedback-writer-DyovUANg.js.map → feedback-writer-CudSe1WK.js.map} +1 -1
  65. package/dist/dashboard/{feedback-writer-gSUv_W0h.js → feedback-writer-Wgv1cd1r.js} +1 -1
  66. package/dist/dashboard/{git-utils-BJRioREj.js → git-utils-C1m4SwAe.js} +1 -1
  67. package/dist/dashboard/{git-utils-BJRioREj.js.map → git-utils-C1m4SwAe.js.map} +1 -1
  68. package/dist/dashboard/{git-utils-BtCRddq3.js → git-utils-DQI8EYoj.js} +1 -1
  69. package/dist/dashboard/{github-app-XO-LBUGk.js → github-app-DClWjjHr.js} +1 -1
  70. package/dist/dashboard/{github-app-XO-LBUGk.js.map → github-app-DClWjjHr.js.map} +1 -1
  71. package/dist/dashboard/{health-events-db-584nYgJB.js → health-events-db-BMXQfInV.js} +1 -1
  72. package/dist/dashboard/{health-events-db-B3ChzN65.js → health-events-db-Do4NrOhC.js} +2 -2
  73. package/dist/dashboard/{health-events-db-B3ChzN65.js.map → health-events-db-Do4NrOhC.js.map} +1 -1
  74. package/dist/dashboard/{hooks-CKhs3N68.js → hooks-CB4T47NC.js} +1 -1
  75. package/dist/dashboard/{hooks-CErbP8Oq.js → hooks-CjqXOlNb.js} +2 -2
  76. package/dist/dashboard/{hooks-CErbP8Oq.js.map → hooks-CjqXOlNb.js.map} +1 -1
  77. package/dist/dashboard/hume-CA2pftu_.js +3 -0
  78. package/dist/dashboard/{hume-CX_U3Qha.js → hume-JsAlMOJC.js} +2 -2
  79. package/dist/dashboard/{hume-CX_U3Qha.js.map → hume-JsAlMOJC.js.map} +1 -1
  80. package/dist/dashboard/{inspect-agent-B57kGDUV.js → inspect-agent-7eour7EA.js} +3 -3
  81. package/dist/dashboard/{inspect-agent-B57kGDUV.js.map → inspect-agent-7eour7EA.js.map} +1 -1
  82. package/dist/dashboard/{io-yGovuG4U.js → io-CWlFW78i.js} +1 -1
  83. package/dist/dashboard/{io-AJg-mzFi.js → io-DKS6359z.js} +1 -1
  84. package/dist/dashboard/{io-AJg-mzFi.js.map → io-DKS6359z.js.map} +1 -1
  85. package/dist/dashboard/issue-id-vwYJdsf8.js +62 -0
  86. package/dist/dashboard/issue-id-vwYJdsf8.js.map +1 -0
  87. package/dist/dashboard/{issue-service-singleton-DQK42EqH.js → issue-service-singleton-Co__-6kL.js} +1 -1
  88. package/dist/dashboard/{issue-service-singleton-sb2HkB9f.js → issue-service-singleton-Wv4xBm3y.js} +7 -7
  89. package/dist/dashboard/{issue-service-singleton-sb2HkB9f.js.map → issue-service-singleton-Wv4xBm3y.js.map} +1 -1
  90. package/dist/dashboard/{label-cleanup-CZEsbtq9.js → label-cleanup-nVKTmIIW.js} +7 -4
  91. package/dist/dashboard/label-cleanup-nVKTmIIW.js.map +1 -0
  92. package/dist/dashboard/lifecycle-BcUmtkR4.js +7 -0
  93. package/dist/dashboard/{merge-agent-GLtMEsTu.js → merge-agent-CGN3TT0a.js} +1 -1
  94. package/dist/dashboard/{merge-agent-twroFuAh.js → merge-agent-yudQOPZc.js} +148 -46
  95. package/dist/dashboard/merge-agent-yudQOPZc.js.map +1 -0
  96. package/dist/dashboard/{paths-COdEvoXR.js → paths-BDyJ7BiV.js} +19 -2
  97. package/dist/dashboard/{paths-COdEvoXR.js.map → paths-BDyJ7BiV.js.map} +1 -1
  98. package/dist/dashboard/{pipeline-notifier-DM5AHG5Q.js → pipeline-notifier-CCSN-jar.js} +1 -1
  99. package/dist/dashboard/{pipeline-notifier-DM5AHG5Q.js.map → pipeline-notifier-CCSN-jar.js.map} +1 -1
  100. package/dist/dashboard/{plan-utils-BkCIhn3B.js → plan-utils-Bkcsqr_s.js} +3 -3
  101. package/dist/dashboard/{plan-utils-BkCIhn3B.js.map → plan-utils-Bkcsqr_s.js.map} +1 -1
  102. package/dist/dashboard/{prd-draft-D09Afalc.js → prd-draft-BD8oMkZ1.js} +2 -2
  103. package/dist/dashboard/{prd-draft-D09Afalc.js.map → prd-draft-BD8oMkZ1.js.map} +1 -1
  104. package/dist/dashboard/{projection-cache-DQ9zegkK.js → projection-cache-C0EL8s8h.js} +1 -1
  105. package/dist/dashboard/{projection-cache-DQ9zegkK.js.map → projection-cache-C0EL8s8h.js.map} +1 -1
  106. package/dist/dashboard/{projects-DyT3vSy-.js → projects-C5ozxjwP.js} +1 -1
  107. package/dist/dashboard/{projects-Cq3TWdPS.js → projects-CFVl4oHn.js} +25 -13
  108. package/dist/dashboard/projects-CFVl4oHn.js.map +1 -0
  109. package/dist/dashboard/{providers-Ck2sQd_F.js → providers-B5Y4H2Mg.js} +4 -4
  110. package/dist/dashboard/providers-B5Y4H2Mg.js.map +1 -0
  111. package/dist/dashboard/{providers-DVQnDekG.js → providers-csVZVPkE.js} +1 -1
  112. package/dist/dashboard/public/assets/{dist-CCJbQrSB.js → dist-BaQPC-c6.js} +1 -1
  113. package/dist/dashboard/public/assets/index-ByLmYGhW.js +212 -0
  114. package/dist/dashboard/public/assets/index-OEEbThNN.css +1 -0
  115. package/dist/dashboard/public/index.html +2 -2
  116. package/dist/dashboard/rally-6McpKKRa.js +3 -0
  117. package/dist/dashboard/{rally-Cwuae-4C.js → rally-YjFRxIiC.js} +2 -2
  118. package/dist/dashboard/{rally-Cwuae-4C.js.map → rally-YjFRxIiC.js.map} +1 -1
  119. package/dist/dashboard/{rally-api-DSUxm7EO.js → rally-api-C0WqCSkT.js} +1 -1
  120. package/dist/dashboard/{rally-api-DSUxm7EO.js.map → rally-api-C0WqCSkT.js.map} +1 -1
  121. package/dist/dashboard/{rally-api-CEH5KZi4.js → rally-api-DNttdCW4.js} +1 -1
  122. package/dist/dashboard/{remote-BHTTMpJJ.js → remote-Cigqjj3f.js} +2 -2
  123. package/dist/dashboard/{remote-BXo_iIku.js → remote-ObpNZ7hF.js} +2 -2
  124. package/dist/dashboard/{remote-BXo_iIku.js.map → remote-ObpNZ7hF.js.map} +1 -1
  125. package/dist/dashboard/{remote-agents-CTKVhFFY.js → remote-agents-Bf3GuM7t.js} +1 -1
  126. package/dist/dashboard/{remote-agents-C0_0LLNd.js → remote-agents-DFyjT1Le.js} +1 -1
  127. package/dist/dashboard/{remote-agents-C0_0LLNd.js.map → remote-agents-DFyjT1Le.js.map} +1 -1
  128. package/dist/dashboard/{review-status-CK3eBGyb.js → review-status-BtXqWBhS.js} +1 -1
  129. package/dist/dashboard/{review-status-CV55Tl-n.js → review-status-Bymwzh2i.js} +44 -4
  130. package/dist/dashboard/{review-status-CV55Tl-n.js.map → review-status-Bymwzh2i.js.map} +1 -1
  131. package/dist/dashboard/server.js +565 -265
  132. package/dist/dashboard/server.js.map +1 -1
  133. package/dist/dashboard/{settings-CuHV-wcv.js → settings-BHlDG7TK.js} +2 -2
  134. package/dist/dashboard/settings-BHlDG7TK.js.map +1 -0
  135. package/dist/dashboard/settings-XWvDcj-D.js +2 -0
  136. package/dist/dashboard/{shadow-engineering-BUeZunaE.js → shadow-engineering-lIn1W_95.js} +1 -1
  137. package/dist/dashboard/{shadow-engineering-BUeZunaE.js.map → shadow-engineering-lIn1W_95.js.map} +1 -1
  138. package/dist/dashboard/{shadow-state-DHQ-kASN.js → shadow-state-BIexcxkv.js} +1 -1
  139. package/dist/dashboard/{shadow-state-DHQ-kASN.js.map → shadow-state-BIexcxkv.js.map} +1 -1
  140. package/dist/dashboard/{spawn-planning-session-8FFAqLdK.js → spawn-planning-session-33Jf-d5T.js} +6 -6
  141. package/dist/dashboard/{spawn-planning-session-8FFAqLdK.js.map → spawn-planning-session-33Jf-d5T.js.map} +1 -1
  142. package/dist/dashboard/{spawn-planning-session-U0Lqpjen.js → spawn-planning-session-D5hrVdWM.js} +1 -1
  143. package/dist/dashboard/{specialist-context-ColzlmGE.js → specialist-context-DGukHSn8.js} +6 -6
  144. package/dist/dashboard/{specialist-context-ColzlmGE.js.map → specialist-context-DGukHSn8.js.map} +1 -1
  145. package/dist/dashboard/{specialist-logs-BhmDpFIq.js → specialist-logs-CIw4qfTy.js} +1 -1
  146. package/dist/dashboard/{specialists-C6s3U6tX.js → specialists-B_zrayaP.js} +37 -36
  147. package/dist/dashboard/specialists-B_zrayaP.js.map +1 -0
  148. package/dist/dashboard/{specialists-Cny632-T.js → specialists-Cp-PgspS.js} +1 -1
  149. package/dist/dashboard/{test-agent-queue-tqI4VDsu.js → test-agent-queue-ypF_ecHo.js} +4 -4
  150. package/dist/dashboard/{test-agent-queue-tqI4VDsu.js.map → test-agent-queue-ypF_ecHo.js.map} +1 -1
  151. package/dist/dashboard/{tldr-daemon-BNFyS7W_.js → tldr-daemon-B_oLRD8z.js} +2 -2
  152. package/dist/dashboard/{tldr-daemon-BNFyS7W_.js.map → tldr-daemon-B_oLRD8z.js.map} +1 -1
  153. package/dist/dashboard/{tldr-daemon-A6JqC59u.js → tldr-daemon-Cfs0bXTi.js} +1 -1
  154. package/dist/dashboard/{tmux-DYGAVJfb.js → tmux-BzxdKItf.js} +1 -1
  155. package/dist/dashboard/{tmux-IlN1Slv-.js → tmux-LwG0tHhU.js} +2 -2
  156. package/dist/dashboard/{tmux-IlN1Slv-.js.map → tmux-LwG0tHhU.js.map} +1 -1
  157. package/dist/dashboard/{tracker-config-BzNLnmcE.js → tracker-config-BP59uH4V.js} +1 -1
  158. package/dist/dashboard/{tracker-config-CNM_5rEf.js → tracker-config-e7ph1QqT.js} +2 -2
  159. package/dist/dashboard/{tracker-config-CNM_5rEf.js.map → tracker-config-e7ph1QqT.js.map} +1 -1
  160. package/dist/dashboard/{tunnel-D2BkwU7k.js → tunnel-0RzzuXPf.js} +1 -1
  161. package/dist/dashboard/{tunnel-Dub2hiAA.js → tunnel-DldbBPWL.js} +2 -2
  162. package/dist/dashboard/{tunnel-Dub2hiAA.js.map → tunnel-DldbBPWL.js.map} +1 -1
  163. package/dist/dashboard/{types-CWA-o4UN.js → types-RKZjGE5N.js} +1 -1
  164. package/dist/dashboard/{types-CWA-o4UN.js.map → types-RKZjGE5N.js.map} +1 -1
  165. package/dist/dashboard/{vtt-parser-BAXygRf0.js → vtt-parser-99vFekRQ.js} +1 -1
  166. package/dist/dashboard/{vtt-parser-BAXygRf0.js.map → vtt-parser-99vFekRQ.js.map} +1 -1
  167. package/dist/dashboard/{work-agent-prompt-JYq_OugP.js → work-agent-prompt-fCg67nyo.js} +65 -10
  168. package/dist/dashboard/{work-agent-prompt-JYq_OugP.js.map → work-agent-prompt-fCg67nyo.js.map} +1 -1
  169. package/dist/dashboard/{work-type-router-Cxp8_ur2.js → work-type-router-CWVW2Wk_.js} +1 -1
  170. package/dist/dashboard/{work-type-router-Cxp8_ur2.js.map → work-type-router-CWVW2Wk_.js.map} +1 -1
  171. package/dist/dashboard/{work-type-router-Com2amST.js → work-type-router-Di5gCQwh.js} +1 -1
  172. package/dist/dashboard/{workflows-N1UTipYl.js → workflows-BSMipN07.js} +35 -17
  173. package/dist/dashboard/workflows-BSMipN07.js.map +1 -0
  174. package/dist/dashboard/workflows-DaYWQIS2.js +2 -0
  175. package/dist/dashboard/{workspace-config-cmp5_ipD.js → workspace-config-DVDR-Ukh.js} +1 -1
  176. package/dist/dashboard/workspace-config-DVDR-Ukh.js.map +1 -0
  177. package/dist/dashboard/{workspace-manager-CjpWPgzL.js → workspace-manager-BYfzs_t2.js} +1 -1
  178. package/dist/dashboard/{workspace-manager-D_y9ZmW_.js → workspace-manager-C7OfT62A.js} +44 -24
  179. package/dist/dashboard/workspace-manager-C7OfT62A.js.map +1 -0
  180. package/dist/{dns-BKzHm-2q.js → dns-D_aKQJjb.js} +1 -1
  181. package/dist/{dns-DZwOWvVO.js → dns-Yxq4NNS7.js} +1 -1
  182. package/dist/{dns-DZwOWvVO.js.map → dns-Yxq4NNS7.js.map} +1 -1
  183. package/dist/{factory-DFu3IT4r.js → factory-BRBGw6OB.js} +1 -1
  184. package/dist/{factory-DfzczxN1.js → factory-DzsOiZVc.js} +3 -3
  185. package/dist/{factory-DfzczxN1.js.map → factory-DzsOiZVc.js.map} +1 -1
  186. package/dist/{feedback-writer-CwdnOkPO.js → feedback-writer-ygXN5F9N.js} +2 -2
  187. package/dist/{feedback-writer-CwdnOkPO.js.map → feedback-writer-ygXN5F9N.js.map} +1 -1
  188. package/dist/{github-app-CHKwxOeQ.js → github-app-DykduJ0X.js} +1 -1
  189. package/dist/{github-app-CHKwxOeQ.js.map → github-app-DykduJ0X.js.map} +1 -1
  190. package/dist/hume-9nv1VmMV.js +3 -0
  191. package/dist/{hume-DnV-tDsh.js → hume-DoCbph2h.js} +2 -2
  192. package/dist/{hume-DnV-tDsh.js.map → hume-DoCbph2h.js.map} +1 -1
  193. package/dist/index.d.ts +17 -2
  194. package/dist/index.d.ts.map +1 -1
  195. package/dist/index.js +8 -7
  196. package/dist/issue-id-CAcekoIw.js +62 -0
  197. package/dist/issue-id-CAcekoIw.js.map +1 -0
  198. package/dist/{label-cleanup-31ElPqqv.js → label-cleanup-C8R9Rspn.js} +7 -4
  199. package/dist/label-cleanup-C8R9Rspn.js.map +1 -0
  200. package/dist/{manifest-DL0oDbpv.js → manifest-B4ghOD-V.js} +1 -1
  201. package/dist/{manifest-DL0oDbpv.js.map → manifest-B4ghOD-V.js.map} +1 -1
  202. package/dist/{merge-agent-VQH9z9t8.js → merge-agent-DlUiUanN.js} +86 -33
  203. package/dist/merge-agent-DlUiUanN.js.map +1 -0
  204. package/dist/{paths-lMaxrYtT.js → paths-CDJ_HsbN.js} +19 -2
  205. package/dist/{paths-lMaxrYtT.js.map → paths-CDJ_HsbN.js.map} +1 -1
  206. package/dist/{pipeline-notifier-OJ-d3Y60.js → pipeline-notifier-XgDdCdvT.js} +1 -1
  207. package/dist/{pipeline-notifier-OJ-d3Y60.js.map → pipeline-notifier-XgDdCdvT.js.map} +1 -1
  208. package/dist/{projects-CvLepaxC.js → projects-Bk-5QhFQ.js} +25 -13
  209. package/dist/projects-Bk-5QhFQ.js.map +1 -0
  210. package/dist/{projects-DMWmPeIU.js → projects-DhU7rAVN.js} +1 -1
  211. package/dist/{providers-DcCPZ5K4.js → providers-DSU1vfQF.js} +4 -4
  212. package/dist/providers-DSU1vfQF.js.map +1 -0
  213. package/dist/rally-DdPvGa-w.js +3 -0
  214. package/dist/{rally-uUUZXp1h.js → rally-Dy00NElU.js} +1 -1
  215. package/dist/{rally-uUUZXp1h.js.map → rally-Dy00NElU.js.map} +1 -1
  216. package/dist/{remote-CkLBqLJc.js → remote-CYiOJg0q.js} +2 -2
  217. package/dist/{remote-CkLBqLJc.js.map → remote-CYiOJg0q.js.map} +1 -1
  218. package/dist/{remote-agents-C5Bd2fgt.js → remote-agents-CZXrUF4f.js} +1 -1
  219. package/dist/{remote-agents-C5Bd2fgt.js.map → remote-agents-CZXrUF4f.js.map} +1 -1
  220. package/dist/{remote-agents-BTzD-wMQ.js → remote-agents-ycHHVsgf.js} +1 -1
  221. package/dist/{remote-workspace-Dxghqiti.js → remote-workspace-CA33UuVI.js} +4 -4
  222. package/dist/{remote-workspace-Dxghqiti.js.map → remote-workspace-CA33UuVI.js.map} +1 -1
  223. package/dist/{review-status-2TdtHNcs.js → review-status-D6H2WOw8.js} +1 -1
  224. package/dist/{review-status-Bm1bWNEa.js → review-status-DEDvCKMP.js} +44 -4
  225. package/dist/{review-status-Bm1bWNEa.js.map → review-status-DEDvCKMP.js.map} +1 -1
  226. package/dist/{tracker-C_62ukEq.js → settings-BcWPTrua.js} +7 -199
  227. package/dist/settings-BcWPTrua.js.map +1 -0
  228. package/dist/shadow-state-BZzxfEGw.js +2 -0
  229. package/dist/{shadow-state-CFFHf05M.js → shadow-state-CE3dQfll.js} +1 -1
  230. package/dist/{shadow-state-CFFHf05M.js.map → shadow-state-CE3dQfll.js.map} +1 -1
  231. package/dist/{specialist-context-BdNFsfMG.js → specialist-context-BAUWL1Fl.js} +6 -6
  232. package/dist/{specialist-context-BdNFsfMG.js.map → specialist-context-BAUWL1Fl.js.map} +1 -1
  233. package/dist/{specialist-logs-CLztE_bE.js → specialist-logs-DQKKQV9B.js} +1 -1
  234. package/dist/{specialists-aUoUVWsN.js → specialists-Bfb9ATzw.js} +1 -1
  235. package/dist/{specialists-DEKqgkxp.js → specialists-D7Kj5o6s.js} +35 -34
  236. package/dist/specialists-D7Kj5o6s.js.map +1 -0
  237. package/dist/sync-DMfgd389.js +693 -0
  238. package/dist/sync-DMfgd389.js.map +1 -0
  239. package/dist/sync-TL6y-8K6.js +2 -0
  240. package/dist/{tldr-daemon-BCEFPItr.js → tldr-daemon-CFx4LXAl.js} +2 -2
  241. package/dist/{tldr-daemon-BCEFPItr.js.map → tldr-daemon-CFx4LXAl.js.map} +1 -1
  242. package/dist/{tldr-daemon-xBAx4cBE.js → tldr-daemon-D_EooADG.js} +1 -1
  243. package/dist/{tmux-DN6H886Y.js → tmux-CBtui_Cl.js} +1 -1
  244. package/dist/{tmux-CKdNxxJx.js → tmux-D6Ah4I8z.js} +2 -2
  245. package/dist/{tmux-CKdNxxJx.js.map → tmux-D6Ah4I8z.js.map} +1 -1
  246. package/dist/tracker-BhYYvU3p.js +198 -0
  247. package/dist/tracker-BhYYvU3p.js.map +1 -0
  248. package/dist/{tracker-utils-CVU2W1sX.js → tracker-utils-ChQyut8w.js} +34 -12
  249. package/dist/tracker-utils-ChQyut8w.js.map +1 -0
  250. package/dist/{traefik-DHgBoWXX.js → traefik-C80EbDu_.js} +4 -4
  251. package/dist/{traefik-DHgBoWXX.js.map → traefik-C80EbDu_.js.map} +1 -1
  252. package/dist/{traefik-BR-edbZv.js → traefik-CgHl7Bge.js} +1 -1
  253. package/dist/{tunnel-BZO9Q5oe.js → tunnel-DXOJ1wMM.js} +1 -1
  254. package/dist/{tunnel-Bl1qNSyQ.js → tunnel-DzXEPwIc.js} +2 -2
  255. package/dist/{tunnel-Bl1qNSyQ.js.map → tunnel-DzXEPwIc.js.map} +1 -1
  256. package/dist/{types-DewGdaIP.js → types-BhJj1SP1.js} +1 -1
  257. package/dist/{types-DewGdaIP.js.map → types-BhJj1SP1.js.map} +1 -1
  258. package/dist/{work-type-router-CS2BB1vS.js → work-type-router-CHjciPyS.js} +3 -3
  259. package/dist/{work-type-router-CS2BB1vS.js.map → work-type-router-CHjciPyS.js.map} +1 -1
  260. package/dist/{workspace-config-CNXOpKuj.js → workspace-config-fUafvYMp.js} +1 -1
  261. package/dist/workspace-config-fUafvYMp.js.map +1 -0
  262. package/dist/workspace-manager-B9jS4Dsq.js +3 -0
  263. package/dist/{workspace-manager-CncdZkIy.js → workspace-manager-DuLhnzJV.js} +112 -27
  264. package/dist/workspace-manager-DuLhnzJV.js.map +1 -0
  265. package/package.json +2 -1
  266. package/scripts/post-merge-deploy.sh +25 -5
  267. package/scripts/record-cost-event.js +57 -7
  268. package/scripts/record-cost-event.js.map +1 -1
  269. package/skills/pan-help/SKILL.md +1 -1
  270. package/skills/pan-sync/SKILL.md +6 -6
  271. package/skills/workspace-add-repo/skill.md +46 -0
  272. package/templates/claude-md/sections/warnings.md +15 -2
  273. package/dist/clean-planning-sZXvy3Y5.js +0 -2
  274. package/dist/close-issue-Dml437qV.js +0 -2
  275. package/dist/close-issue-Dr7yZmrr.js.map +0 -1
  276. package/dist/compact-beads-iu218JcO.js +0 -2
  277. package/dist/dashboard/agent-enrichment-C67LJBgD.js.map +0 -1
  278. package/dist/dashboard/clean-planning-DCu3cOTu.js +0 -2
  279. package/dist/dashboard/close-issue-DfIggeZD.js.map +0 -1
  280. package/dist/dashboard/close-issue-DwdwYtar.js +0 -2
  281. package/dist/dashboard/compact-beads-DXY2fK2s.js +0 -2
  282. package/dist/dashboard/event-store-O9q0Gweh.js.map +0 -1
  283. package/dist/dashboard/hume-MZndNDVU.js +0 -3
  284. package/dist/dashboard/label-cleanup-CZEsbtq9.js.map +0 -1
  285. package/dist/dashboard/lifecycle-ZTYdrr2O.js +0 -7
  286. package/dist/dashboard/merge-agent-twroFuAh.js.map +0 -1
  287. package/dist/dashboard/projects-Cq3TWdPS.js.map +0 -1
  288. package/dist/dashboard/providers-Ck2sQd_F.js.map +0 -1
  289. package/dist/dashboard/public/assets/index-CpSmB2ts.css +0 -1
  290. package/dist/dashboard/public/assets/index-yarWhi0M.js +0 -214
  291. package/dist/dashboard/rally-CQ1OBJrJ.js +0 -3
  292. package/dist/dashboard/settings-CuHV-wcv.js.map +0 -1
  293. package/dist/dashboard/settings-DMeGBRsk.js +0 -2
  294. package/dist/dashboard/specialists-C6s3U6tX.js.map +0 -1
  295. package/dist/dashboard/workflows-B2ARUpOa.js +0 -2
  296. package/dist/dashboard/workflows-N1UTipYl.js.map +0 -1
  297. package/dist/dashboard/workspace-config-cmp5_ipD.js.map +0 -1
  298. package/dist/dashboard/workspace-manager-D_y9ZmW_.js.map +0 -1
  299. package/dist/hume-BjmwmJ9E.js +0 -3
  300. package/dist/label-cleanup-31ElPqqv.js.map +0 -1
  301. package/dist/merge-agent-VQH9z9t8.js.map +0 -1
  302. package/dist/projects-CvLepaxC.js.map +0 -1
  303. package/dist/providers-DcCPZ5K4.js.map +0 -1
  304. package/dist/rally-DR9x8--6.js +0 -3
  305. package/dist/shadow-state-p3jpGRPJ.js +0 -2
  306. package/dist/specialists-DEKqgkxp.js.map +0 -1
  307. package/dist/tracker-C_62ukEq.js.map +0 -1
  308. package/dist/tracker-utils-CVU2W1sX.js.map +0 -1
  309. package/dist/workspace-config-CNXOpKuj.js.map +0 -1
  310. package/dist/workspace-manager-CncdZkIy.js.map +0 -1
  311. package/dist/workspace-manager-Cx0r2Jnv.js +0 -3
@@ -1,33 +1,34 @@
1
1
  import { a as __toCommonJS, i as __require, o as __toESM, t as __commonJSMin } from "./chunk-DORXReHP.js";
2
- import { d as PROJECT_PRDS_COMPLETED_SUBDIR, f as PROJECT_PRDS_PLANNED_SUBDIR, g as init_paths, l as PROJECT_DOCS_SUBDIR, p as PROJECT_PRDS_SUBDIR, s as PANOPTICON_HOME, t as AGENTS_DIR, u as PROJECT_PRDS_ACTIVE_SUBDIR } from "./paths-COdEvoXR.js";
3
- import { i as initEventStore, n as getEventStore } from "./event-store-O9q0Gweh.js";
2
+ import { _ as init_paths, d as PROJECT_PRDS_COMPLETED_SUBDIR, f as PROJECT_PRDS_PLANNED_SUBDIR, h as encodeClaudeProjectDir, l as PROJECT_DOCS_SUBDIR, p as PROJECT_PRDS_SUBDIR, s as PANOPTICON_HOME, t as AGENTS_DIR, u as PROJECT_PRDS_ACTIVE_SUBDIR } from "./paths-BDyJ7BiV.js";
3
+ import { i as initEventStore, n as getEventStore } from "./event-store-vSmAA3Zp.js";
4
4
  import { a as MODEL_CAPABILITIES, c as init_model_capabilities, d as jsYaml, i as loadConfig$1, l as resolveModelId, o as MODEL_DEPRECATIONS, r as init_config_yaml, t as getGlobalConfigPath, u as init_js_yaml } from "./config-yaml-DSfYpzN6.js";
5
5
  import { t as require_dist } from "./dist-C667LLmq.js";
6
- import { a as findProjectByTeam, h as listProjects, i as findProjectByPath, p as init_projects, r as extractTeamPrefix, s as getIssuePrefix, y as resolveProjectFromIssue } from "./projects-Cq3TWdPS.js";
7
- import { i as init_tracker_config, n as getLinearApiKey, r as getRallyConfig, t as getGitHubConfig } from "./tracker-config-CNM_5rEf.js";
8
- import { d as runQualityGates, f as resolveGitHubIssue, l as syncMainIntoWorkspace, p as resolveTrackerType, u as DEFAULT_GATES } from "./merge-agent-twroFuAh.js";
9
- import { i as startSharedIssueService, n as init_issue_service_singleton, r as issue_service_singleton_exports, t as getSharedIssueService } from "./issue-service-singleton-sb2HkB9f.js";
10
- import { r as setPipelineHandler, t as init_pipeline_notifier } from "./pipeline-notifier-DM5AHG5Q.js";
11
- import { i as init_database, n as getDatabase, t as closeDatabase } from "./database-C0y0hXBx.js";
12
- import { a as loadReviewStatuses, i as init_review_status, n as clearStuckMergeStatuses, o as saveReviewStatuses, r as getReviewStatus, s as setReviewStatus$1, t as clearReviewStatus } from "./review-status-CV55Tl-n.js";
13
- import { At as getSessionFiles, Ct as getUnblockedItems, Dt as readSpecialistHandoffs, Et as init_specialist_handoff_logger, Ft as getPricing, It as init_cost, Mt as normalizeModelName, Nt as parseClaudeSession, O as getTmuxSessionName, Ot as getActiveSessionModel, Pt as calculateCost, Tt as getSpecialistHandoffStats, f as getAllProjectSpecialistStatuses, it as wakeSpecialistOrQueue, j as init_specialists, jt as init_jsonl_parser, kt as getProjectDirs, q as setSessionId, r as checkSpecialistQueue, w as getSessionId, wt as init_task_readiness } from "./specialists-C6s3U6tX.js";
14
- import { t as getAgentCommand } from "./settings-CuHV-wcv.js";
15
- import { a as init_providers, i as getProviderForModel, r as getProviderEnv } from "./providers-Ck2sQd_F.js";
16
- import { n as spawnPlanningSession } from "./spawn-planning-session-8FFAqLdK.js";
17
- import { c as loadWorkspaceMetadata, r as isRemoteAvailable, t as createFlyProviderFromConfig } from "./remote-BXo_iIku.js";
18
- import { d as sessionExistsAsync, i as createSession, l as sendKeysAsync, o as init_tmux, s as killSession, u as sessionExists } from "./tmux-IlN1Slv-.js";
19
- import { a as init_config, o as loadConfig$2 } from "./config-CUREjHP7.js";
20
- import { A as saveCloisterConfig, C as stopAgent, D as getHealthThresholdsMs, O as init_config$1, S as spawnAgent, T as transitionIssueToInReview, a as getAgentDir, b as saveAgentState, c as getAgentState, d as getProviderExportsForModel, f as getProviderTmuxFlags, g as messageAgent, h as listRunningAgents, i as getActivity, j as shouldAutoStart, k as loadCloisterConfig, l as getLatestSessionId, m as init_agents, p as getSessionId$1, s as getAgentRuntimeState, u as getProviderEnvForModel, v as resumeAgent, w as transitionIssueToInProgress, x as saveSessionId, y as saveAgentRuntimeState } from "./agents-YyO6t5Xa.js";
21
- import { c as writeHealthEvent } from "./health-events-db-B3ChzN65.js";
22
- import { s as init_hooks, t as checkHook } from "./hooks-CErbP8Oq.js";
23
- import { a as getModelId, s as init_work_type_router } from "./work-type-router-Cxp8_ur2.js";
24
- import { i as readWorkspacePlan, n as init_io, r as readPlan, t as findPlan } from "./io-AJg-mzFi.js";
25
- import { n as hasPRDDraft } from "./prd-draft-D09Afalc.js";
26
- import { a as getAgentPendingQuestions$1, r as getAgentJsonlMtime, t as computeAgentEnrichment } from "./agent-enrichment-C67LJBgD.js";
27
- import { n as writeFeedbackFile, t as init_feedback_writer } from "./feedback-writer-DyovUANg.js";
28
- import { n as getVBriefACStatus, r as syncBeadStatusToVBrief } from "./beads-qNB0yAHV.js";
29
- import { n as getTldrDaemonService, r as init_tldr_daemon } from "./tldr-daemon-BNFyS7W_.js";
30
- import { c as sendToRemoteAgent, i as killRemoteAgent, l as spawnRemoteAgent, o as loadRemoteAgentState, t as getRemoteAgentOutput } from "./remote-agents-C0_0LLNd.js";
6
+ import { n as extractPrefix, r as init_issue_id, t as extractNumber } from "./issue-id-vwYJdsf8.js";
7
+ import { a as findProjectByTeam, h as listProjects, i as findProjectByPath, p as init_projects, r as extractTeamPrefix, s as getIssuePrefix, y as resolveProjectFromIssue } from "./projects-CFVl4oHn.js";
8
+ import { i as init_tracker_config, n as getLinearApiKey, r as getRallyConfig, t as getGitHubConfig } from "./tracker-config-e7ph1QqT.js";
9
+ import { d as runQualityGates, f as emitDashboardLifecycle, l as syncMainIntoWorkspace, m as resolveTrackerType, p as resolveGitHubIssue, u as DEFAULT_GATES } from "./merge-agent-yudQOPZc.js";
10
+ import { i as startSharedIssueService, n as init_issue_service_singleton, r as issue_service_singleton_exports, t as getSharedIssueService } from "./issue-service-singleton-Wv4xBm3y.js";
11
+ import { r as setPipelineHandler, t as init_pipeline_notifier } from "./pipeline-notifier-CCSN-jar.js";
12
+ import { i as init_database, n as getDatabase, t as closeDatabase } from "./database-cxmQryoh.js";
13
+ import { a as loadReviewStatuses, i as init_review_status, n as clearStuckMergeStatuses, o as saveReviewStatuses, r as getReviewStatus, s as setReviewStatus$1, t as clearReviewStatus } from "./review-status-Bymwzh2i.js";
14
+ import { At as getSessionFiles, Ct as getUnblockedItems, Dt as readSpecialistHandoffs, Et as init_specialist_handoff_logger, Ft as getPricing, It as init_cost, Mt as normalizeModelName, Nt as parseClaudeSession, O as getTmuxSessionName, Ot as getActiveSessionModel, Pt as calculateCost, Tt as getSpecialistHandoffStats, f as getAllProjectSpecialistStatuses, it as wakeSpecialistOrQueue, j as init_specialists, jt as init_jsonl_parser, kt as getProjectDirs, q as setSessionId, r as checkSpecialistQueue, w as getSessionId, wt as init_task_readiness } from "./specialists-B_zrayaP.js";
15
+ import { t as getAgentCommand } from "./settings-BHlDG7TK.js";
16
+ import { a as init_providers, i as getProviderForModel, r as getProviderEnv } from "./providers-B5Y4H2Mg.js";
17
+ import { n as spawnPlanningSession } from "./spawn-planning-session-33Jf-d5T.js";
18
+ import { c as loadWorkspaceMetadata, r as isRemoteAvailable, t as createFlyProviderFromConfig } from "./remote-ObpNZ7hF.js";
19
+ import { d as sessionExistsAsync, i as createSession, l as sendKeysAsync, o as init_tmux, s as killSession, u as sessionExists } from "./tmux-LwG0tHhU.js";
20
+ import { a as init_config, o as loadConfig$2 } from "./config-CDkGjnwy.js";
21
+ import { A as saveCloisterConfig, C as stopAgent, D as getHealthThresholdsMs, O as init_config$1, S as spawnAgent, T as transitionIssueToInReview, a as getAgentDir, b as saveAgentState, c as getAgentState, d as getProviderExportsForModel, f as getProviderTmuxFlags, g as messageAgent, h as listRunningAgents, i as getActivity, j as shouldAutoStart, k as loadCloisterConfig, l as getLatestSessionId, m as init_agents, p as getSessionId$1, s as getAgentRuntimeState, u as getProviderEnvForModel, v as resumeAgent, w as transitionIssueToInProgress, x as saveSessionId, y as saveAgentRuntimeState } from "./agents-DCpQQ_W5.js";
22
+ import { c as writeHealthEvent } from "./health-events-db-Do4NrOhC.js";
23
+ import { s as init_hooks, t as checkHook } from "./hooks-CjqXOlNb.js";
24
+ import { a as getModelId, s as init_work_type_router } from "./work-type-router-CWVW2Wk_.js";
25
+ import { i as readWorkspacePlan, n as init_io, r as readPlan, t as findPlan } from "./io-DKS6359z.js";
26
+ import { n as hasPRDDraft } from "./prd-draft-BD8oMkZ1.js";
27
+ import { a as getAgentPendingQuestions$1, r as getAgentJsonlMtime, t as computeAgentEnrichment } from "./agent-enrichment-DdO7ZqjI.js";
28
+ import { n as writeFeedbackFile, t as init_feedback_writer } from "./feedback-writer-CudSe1WK.js";
29
+ import { n as getVBriefACStatus, r as syncBeadStatusToVBrief } from "./beads-Bv-AdX7G.js";
30
+ import { n as getTldrDaemonService, r as init_tldr_daemon } from "./tldr-daemon-B_oLRD8z.js";
31
+ import { c as sendToRemoteAgent, i as killRemoteAgent, l as spawnRemoteAgent, o as loadRemoteAgentState, t as getRemoteAgentOutput } from "./remote-agents-DFyjT1Le.js";
31
32
  import { Cause, Data, Duration, Effect, FileSystem, Layer, Option, Path, Queue, Schedule, Schema, ServiceMap, Stream } from "effect";
32
33
  import { cpus, freemem, homedir, totalmem } from "node:os";
33
34
  import { appendFileSync, closeSync, existsSync, fstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "fs";
@@ -553,6 +554,53 @@ const ActivityUpdatedEvent = Schema.Struct({
553
554
  timestamp: Schema.String,
554
555
  payload: Schema.Struct({ events: Schema.Array(Schema.Unknown) })
555
556
  });
557
+ /** Individual activity log entry — emitted by merge-agent, cloister, specialists (PAN-520) */
558
+ const ActivityEntryEvent = Schema.Struct({
559
+ type: Schema.Literal("activity.entry"),
560
+ sequence: SequenceNumber,
561
+ timestamp: Schema.String,
562
+ payload: Schema.Struct({
563
+ id: Schema.String,
564
+ source: Schema.String,
565
+ level: Schema.String,
566
+ message: Schema.String,
567
+ details: Schema.optional(Schema.String),
568
+ issueId: Schema.optional(IssueId)
569
+ })
570
+ });
571
+ /** Dashboard is restarting (post-merge deploy, pan restart, etc.) (PAN-520) */
572
+ const DashboardLifecycleStartedEvent = Schema.Struct({
573
+ type: Schema.Literal("dashboard.lifecycle_started"),
574
+ sequence: SequenceNumber,
575
+ timestamp: Schema.String,
576
+ payload: Schema.Struct({
577
+ reason: Schema.String,
578
+ issueId: Schema.optional(IssueId),
579
+ trigger: Schema.String
580
+ })
581
+ });
582
+ /** Dashboard restarted successfully after a lifecycle event (PAN-520) */
583
+ const DashboardLifecycleCompletedEvent = Schema.Struct({
584
+ type: Schema.Literal("dashboard.lifecycle_completed"),
585
+ sequence: SequenceNumber,
586
+ timestamp: Schema.String,
587
+ payload: Schema.Struct({
588
+ reason: Schema.String,
589
+ issueId: Schema.optional(IssueId),
590
+ durationMs: Schema.Number
591
+ })
592
+ });
593
+ /** Dashboard restart failed (PAN-520) */
594
+ const DashboardLifecycleFailedEvent = Schema.Struct({
595
+ type: Schema.Literal("dashboard.lifecycle_failed"),
596
+ sequence: SequenceNumber,
597
+ timestamp: Schema.String,
598
+ payload: Schema.Struct({
599
+ reason: Schema.String,
600
+ issueId: Schema.optional(IssueId),
601
+ error: Schema.String
602
+ })
603
+ });
556
604
  /** Replaces socket.io `shadow:inference-update` */
557
605
  const ShadowInferenceUpdateEvent = Schema.Struct({
558
606
  type: Schema.Literal("shadow.inference_update"),
@@ -646,13 +694,17 @@ const DomainEvent = Schema.Union([
646
694
  IssuesUpdatedEvent,
647
695
  IssueStatusChangedEvent,
648
696
  ActivityUpdatedEvent,
697
+ ActivityEntryEvent,
649
698
  ShadowInferenceUpdateEvent,
650
699
  CostEventRecordedEvent,
651
700
  WorkspaceCreatedEvent,
652
701
  WorkspaceWipeStartedEvent,
653
702
  WorkspaceDestroyedEvent,
654
703
  WorkspaceDeletedEvent,
655
- WorkspaceAbortedEvent
704
+ WorkspaceAbortedEvent,
705
+ DashboardLifecycleStartedEvent,
706
+ DashboardLifecycleCompletedEvent,
707
+ DashboardLifecycleFailedEvent
656
708
  ]);
657
709
  //#endregion
658
710
  //#region ../../../packages/contracts/src/rpc.ts
@@ -859,7 +911,17 @@ const INITIAL_READ_MODEL_STATE = {
859
911
  agentOutputById: {},
860
912
  issuesRaw: [],
861
913
  recentActivity: [],
862
- shadowInferenceByIssueId: {}
914
+ shadowInferenceByIssueId: {},
915
+ dashboardLifecycle: {
916
+ active: false,
917
+ reason: null,
918
+ issueId: null,
919
+ trigger: null,
920
+ startedAt: null,
921
+ completedAt: null,
922
+ failedAt: null,
923
+ error: null
924
+ }
863
925
  };
864
926
  const MAX_AGENT_OUTPUT_LINES = 200;
865
927
  const MAX_ACTIVITY_ENTRIES = 50;
@@ -1122,6 +1184,65 @@ function applyEvent(state, event) {
1122
1184
  ...state,
1123
1185
  sequence: Math.max(state.sequence, event.sequence)
1124
1186
  };
1187
+ case "activity.entry": {
1188
+ const entry = event.payload;
1189
+ const updated = [{
1190
+ id: entry.id,
1191
+ timestamp: event.timestamp,
1192
+ ...entry
1193
+ }, ...state.recentActivity].slice(0, MAX_ACTIVITY_ENTRIES);
1194
+ return {
1195
+ ...state,
1196
+ sequence: Math.max(state.sequence, event.sequence),
1197
+ recentActivity: updated
1198
+ };
1199
+ }
1200
+ case "dashboard.lifecycle_started": {
1201
+ const { reason, issueId, trigger } = event.payload;
1202
+ return {
1203
+ ...state,
1204
+ sequence: Math.max(state.sequence, event.sequence),
1205
+ dashboardLifecycle: {
1206
+ active: true,
1207
+ reason,
1208
+ issueId,
1209
+ trigger,
1210
+ startedAt: event.timestamp,
1211
+ completedAt: null,
1212
+ failedAt: null,
1213
+ error: null
1214
+ }
1215
+ };
1216
+ }
1217
+ case "dashboard.lifecycle_completed": {
1218
+ const { reason, issueId } = event.payload;
1219
+ return {
1220
+ ...state,
1221
+ sequence: Math.max(state.sequence, event.sequence),
1222
+ dashboardLifecycle: {
1223
+ ...state.dashboardLifecycle,
1224
+ active: false,
1225
+ reason: reason ?? state.dashboardLifecycle.reason,
1226
+ issueId: issueId ?? state.dashboardLifecycle.issueId,
1227
+ completedAt: event.timestamp
1228
+ }
1229
+ };
1230
+ }
1231
+ case "dashboard.lifecycle_failed": {
1232
+ const { reason, issueId, error } = event.payload;
1233
+ return {
1234
+ ...state,
1235
+ sequence: Math.max(state.sequence, event.sequence),
1236
+ dashboardLifecycle: {
1237
+ ...state.dashboardLifecycle,
1238
+ active: false,
1239
+ reason: reason ?? state.dashboardLifecycle.reason,
1240
+ issueId: issueId ?? state.dashboardLifecycle.issueId,
1241
+ failedAt: event.timestamp,
1242
+ error
1243
+ }
1244
+ };
1245
+ }
1125
1246
  default: return state;
1126
1247
  }
1127
1248
  }
@@ -1242,7 +1363,7 @@ const ReadModelServiceLive = Layer.effect(ReadModelService, Effect.gen(function*
1242
1363
  yield* Effect.gen(function* () {
1243
1364
  let usedProjectionCache = false;
1244
1365
  try {
1245
- const { getProjectionCache } = yield* Effect.promise(() => import("./projection-cache-DQ9zegkK.js"));
1366
+ const { getProjectionCache } = yield* Effect.promise(() => import("./projection-cache-C0EL8s8h.js"));
1246
1367
  projectionCache = getProjectionCache();
1247
1368
  const cached = projectionCache.load();
1248
1369
  if (cached && cached.sequence > 0) {
@@ -1285,10 +1406,10 @@ const ReadModelServiceLive = Layer.effect(ReadModelService, Effect.gen(function*
1285
1406
  } catch {}
1286
1407
  if (!usedProjectionCache) {
1287
1408
  const [{ listRunningAgents, warnOnBareNumericIssueIds }, { getAllSpecialists, getSpecialistState }, { loadReviewStatuses, getReviewStatus }, { computeAgentEnrichment }] = yield* Effect.all([
1288
- Effect.promise(() => import("./agents-BVBVCyat.js")),
1289
- Effect.promise(() => import("./specialists-Cny632-T.js")),
1290
- Effect.promise(() => import("./review-status-CK3eBGyb.js")),
1291
- Effect.promise(() => import("./agent-enrichment-Cq0P1cNZ.js"))
1409
+ Effect.promise(() => import("./agents-Dgh2TjSp.js")),
1410
+ Effect.promise(() => import("./specialists-Cp-PgspS.js")),
1411
+ Effect.promise(() => import("./review-status-BtXqWBhS.js")),
1412
+ Effect.promise(() => import("./agent-enrichment-dLeGE1fX.js"))
1292
1413
  ]);
1293
1414
  warnOnBareNumericIssueIds();
1294
1415
  const running = listRunningAgents();
@@ -1354,7 +1475,7 @@ const ReadModelServiceLive = Layer.effect(ReadModelService, Effect.gen(function*
1354
1475
  };
1355
1476
  let sequence = 0;
1356
1477
  try {
1357
- const { getEventStore } = yield* Effect.promise(() => import("./event-store-D7kLBd07.js"));
1478
+ const { getEventStore } = yield* Effect.promise(() => import("./event-store-VWWUmOfn.js"));
1358
1479
  sequence = getEventStore().getLatestSequence();
1359
1480
  } catch {}
1360
1481
  state = {
@@ -1368,7 +1489,7 @@ const ReadModelServiceLive = Layer.effect(ReadModelService, Effect.gen(function*
1368
1489
  console.log(`[ReadModel] Bootstrapped: ${Object.keys(agentsById).length} agents, ${Object.keys(specialistsByName).length} specialists, ${Object.keys(reviewStatusByIssueId).length} review statuses, seq=${sequence}`);
1369
1490
  }
1370
1491
  try {
1371
- const { getSharedIssueService } = yield* Effect.promise(() => import("./issue-service-singleton-DQK42EqH.js"));
1492
+ const { getSharedIssueService } = yield* Effect.promise(() => import("./issue-service-singleton-Co__-6kL.js"));
1372
1493
  const issueService = getSharedIssueService();
1373
1494
  const currentIssues = JSON.parse(JSON.stringify(issueService.getIssues()));
1374
1495
  if (currentIssues.length > 0 || !usedProjectionCache) state = {
@@ -1383,7 +1504,7 @@ const ReadModelServiceLive = Layer.effect(ReadModelService, Effect.gen(function*
1383
1504
  };
1384
1505
  projectionCache?.save(buildSnapshot());
1385
1506
  try {
1386
- if (!_cachedEventStore) import("./event-store-D7kLBd07.js").then(({ getEventStore }) => {
1507
+ if (!_cachedEventStore) import("./event-store-VWWUmOfn.js").then(({ getEventStore }) => {
1387
1508
  _cachedEventStore = getEventStore();
1388
1509
  try {
1389
1510
  _cachedEventStore.append({
@@ -1438,6 +1559,7 @@ const EventStoreServiceLive = Layer.effect(EventStoreService, Effect.gen(functio
1438
1559
  return {
1439
1560
  append: (event) => Effect.sync(() => store.append(event)),
1440
1561
  readFrom: (fromSequence) => Effect.sync(() => store.readFrom(fromSequence)),
1562
+ queryByType: (type, limit) => Effect.sync(() => store.queryByType(type, limit)),
1441
1563
  getLatestSequence: Effect.sync(() => store.getLatestSequence()),
1442
1564
  streamEvents
1443
1565
  };
@@ -1730,6 +1852,7 @@ init_js_yaml();
1730
1852
  init_model_capabilities();
1731
1853
  init_config_yaml();
1732
1854
  var import_dist = /* @__PURE__ */ __toESM(require_dist(), 1);
1855
+ init_issue_id();
1733
1856
  init_projects();
1734
1857
  init_tracker_config();
1735
1858
  /**
@@ -2167,7 +2290,7 @@ function wrapRallyError(err) {
2167
2290
  const RallyClientLive = Layer.effect(RallyClient, Effect.gen(function* () {
2168
2291
  const config = getRallyConfig();
2169
2292
  if (!config) return yield* Effect.fail(new TrackerNotConfigured({ tracker: "rally" }));
2170
- const { RallyTracker } = yield* Effect.promise(() => import("./rally-CQ1OBJrJ.js"));
2293
+ const { RallyTracker } = yield* Effect.promise(() => import("./rally-6McpKKRa.js"));
2171
2294
  const tracker = new RallyTracker({
2172
2295
  apiKey: config.apiKey,
2173
2296
  server: config.server,
@@ -2404,7 +2527,7 @@ const IssueLifecycleLive = Layer.effect(IssueLifecycle, Effect.gen(function* ()
2404
2527
  }));
2405
2528
  IssueLifecycleLive.pipe(Layer.provide(LinearClientOptionalLive), Layer.provide(GitHubClientOptionalLive), Layer.provide(Layer.effect(RallyClient, Effect.gen(function* () {
2406
2529
  return yield* Effect.gen(function* () {
2407
- const { getRallyConfig } = yield* Effect.promise(() => import("./tracker-config-BzNLnmcE.js"));
2530
+ const { getRallyConfig } = yield* Effect.promise(() => import("./tracker-config-BP59uH4V.js"));
2408
2531
  if (!getRallyConfig()) {
2409
2532
  const fail = Effect.fail(new TrackerNotConfigured({ tracker: "rally" }));
2410
2533
  return {
@@ -2437,7 +2560,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
2437
2560
  const beadsDir = join$1(workspacePath, ".beads");
2438
2561
  const projectBeadsDir = join$1(workspacePath, "..", "..", ".beads");
2439
2562
  if (!(existsSync$1(beadsDir) || existsSync$1(projectBeadsDir))) throw new BeadsNotInitialized({ workspace: workspacePath });
2440
- const { getAgentState, spawnAgent, normalizeAgentId } = await import("./agents-BVBVCyat.js");
2563
+ const { getAgentState, spawnAgent, normalizeAgentId } = await import("./agents-Dgh2TjSp.js");
2441
2564
  const normalizedId = normalizeAgentId(issueId);
2442
2565
  if (getAgentState(normalizedId)?.status === "running") throw new AgentAlreadyRunning({ id: issueId });
2443
2566
  return {
@@ -2474,7 +2597,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
2474
2597
  const { writeFile } = fsp;
2475
2598
  await writeFile(planningPromptPath, opts.issue.description ?? "", "utf-8");
2476
2599
  const sessionName = opts.sessionName ?? `planning-${issueId.toLowerCase()}`;
2477
- const { spawnPlanningSession } = await import("./spawn-planning-session-U0Lqpjen.js");
2600
+ const { spawnPlanningSession } = await import("./spawn-planning-session-D5hrVdWM.js");
2478
2601
  const result = await spawnPlanningSession({
2479
2602
  issue: {
2480
2603
  id: issue.id,
@@ -2506,14 +2629,14 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
2506
2629
  }),
2507
2630
  kill: (agentId) => Effect.tryPromise({
2508
2631
  try: async () => {
2509
- const { stopAgent } = await import("./agents-BVBVCyat.js");
2632
+ const { stopAgent } = await import("./agents-Dgh2TjSp.js");
2510
2633
  stopAgent(agentId);
2511
2634
  },
2512
2635
  catch: () => void 0
2513
2636
  }).pipe(Effect.ignore),
2514
2637
  message: (agentId, msg) => Effect.tryPromise({
2515
2638
  try: async () => {
2516
- const { messageAgent } = await import("./agents-BVBVCyat.js");
2639
+ const { messageAgent } = await import("./agents-Dgh2TjSp.js");
2517
2640
  await messageAgent(agentId, msg);
2518
2641
  },
2519
2642
  catch: (err) => new AgentStartError({
@@ -2524,8 +2647,8 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
2524
2647
  }),
2525
2648
  deepWipe: (issueId, opts) => Effect.tryPromise({
2526
2649
  try: async () => {
2527
- const { deepWipe } = await import("./workflows-B2ARUpOa.js");
2528
- const { resolveProjectFromIssue } = await import("./projects-DyT3vSy-.js");
2650
+ const { deepWipe } = await import("./workflows-DaYWQIS2.js");
2651
+ const { resolveProjectFromIssue } = await import("./projects-C5ozxjwP.js");
2529
2652
  const project = resolveProjectFromIssue(issueId);
2530
2653
  await deepWipe({
2531
2654
  issueId,
@@ -2579,8 +2702,8 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
2579
2702
  const { workspacePath, branch } = getWorkspacePath(issueId);
2580
2703
  const issueLower = issueId.toLowerCase();
2581
2704
  if (existsSync$1(workspacePath)) return workspacePath;
2582
- const { createWorkspace } = await import("./workspace-manager-CjpWPgzL.js");
2583
- const { loadProjectsConfig } = await import("./projects-DyT3vSy-.js");
2705
+ const { createWorkspace } = await import("./workspace-manager-BYfzs_t2.js");
2706
+ const { loadProjectsConfig } = await import("./projects-C5ozxjwP.js");
2584
2707
  const { projects } = loadProjectsConfig();
2585
2708
  const project = resolveProjectFromIssue(issueId);
2586
2709
  if (!project) throw new WorkspaceCreateError({
@@ -2615,7 +2738,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
2615
2738
  const { workspacePath } = getWorkspacePath(issueId);
2616
2739
  const issueLower = issueId.toLowerCase();
2617
2740
  if (!existsSync$1(workspacePath)) throw new WorkspaceNotFound({ id: issueId });
2618
- const { removeWorkspace } = await import("./workspace-manager-CjpWPgzL.js");
2741
+ const { removeWorkspace } = await import("./workspace-manager-BYfzs_t2.js");
2619
2742
  const project = resolveProjectFromIssue(issueId);
2620
2743
  if (!project) throw new WorkspaceCreateError({
2621
2744
  id: issueId,
@@ -2647,7 +2770,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
2647
2770
  const { workspacePath } = getWorkspacePath(issueId);
2648
2771
  const issueLower = issueId.toLowerCase();
2649
2772
  const projectName = resolveProjectFromIssue(issueId)?.name ?? issueId;
2650
- const { stopWorkspaceDocker } = await import("./workspace-manager-CjpWPgzL.js");
2773
+ const { stopWorkspaceDocker } = await import("./workspace-manager-BYfzs_t2.js");
2651
2774
  await stopWorkspaceDocker(workspacePath, projectName, issueLower);
2652
2775
  },
2653
2776
  catch: () => void 0
@@ -2716,7 +2839,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
2716
2839
  join$1(workspacePath, ".devcontainer", "docker-compose.devcontainer.yml")
2717
2840
  ];
2718
2841
  if (!composePaths.find((p) => existsSync$1(p))) {
2719
- const { loadProjectsConfig } = await import("./projects-DyT3vSy-.js");
2842
+ const { loadProjectsConfig } = await import("./projects-C5ozxjwP.js");
2720
2843
  const { projects } = loadProjectsConfig();
2721
2844
  const project = resolveProjectFromIssue(issueId);
2722
2845
  if (!project) throw new WorkspaceCreateError({
@@ -2724,7 +2847,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
2724
2847
  message: `No project configured for issue ${issueId} — cannot generate docker-compose.yml`
2725
2848
  });
2726
2849
  const projectName = Object.entries(projects).find(([, p]) => p.path === project.path)?.[0] ?? "unknown";
2727
- const { createWorkspace } = await import("./workspace-manager-CjpWPgzL.js");
2850
+ const { createWorkspace } = await import("./workspace-manager-BYfzs_t2.js");
2728
2851
  const createResult = await createWorkspace({
2729
2852
  projectConfig: {
2730
2853
  ...project,
@@ -6408,10 +6531,18 @@ var import_websocket_server = /* @__PURE__ */ __toESM(require_websocket_server()
6408
6531
  /** Shared registry of active PTY hubs, keyed by tmux session name. */
6409
6532
  const activePtyHubs = /* @__PURE__ */ new Map();
6410
6533
  /**
6411
- * Broadcast data to all open clients in the hub.
6534
+ * Broadcast data to all open clients in the hub, respecting per-client blackout periods.
6535
+ * Clients that are still within their 200ms blackout window receive nothing — this
6536
+ * prevents scrollback flooding when a browser tab reconnects to an existing hub.
6412
6537
  */
6413
6538
  function broadcastToHub(hub, data) {
6414
- for (const client of hub.clients) if (client.readyState === import_websocket.default.OPEN) client.send(data);
6539
+ const now = Date.now();
6540
+ for (const client of hub.clients) {
6541
+ if (client.readyState !== import_websocket.default.OPEN) continue;
6542
+ const blackoutUntil = hub.clientBlackout.get(client);
6543
+ if (blackoutUntil && now < blackoutUntil) continue;
6544
+ client.send(data);
6545
+ }
6415
6546
  }
6416
6547
  /**
6417
6548
  * Remove a client from its hub. If it was the last client, delete the hub entry
@@ -6426,6 +6557,7 @@ function removeClientFromHub(hubs, sessionName, ws) {
6426
6557
  const hub = hubs.get(sessionName);
6427
6558
  if (!hub) return false;
6428
6559
  hub.clients.delete(ws);
6560
+ hub.clientBlackout.delete(ws);
6429
6561
  if (hub.clients.size === 0) {
6430
6562
  hubs.delete(sessionName);
6431
6563
  return true;
@@ -6493,6 +6625,7 @@ function setupTerminalWebSocket(server) {
6493
6625
  console.log(`[ws-terminal] Joining existing PTY hub for ${sessionName} (${existingHub.clients.size} existing clients)`);
6494
6626
  existingHub.clients.add(ws);
6495
6627
  existingHub.inputClient = ws;
6628
+ existingHub.clientBlackout.set(ws, Date.now() + 200);
6496
6629
  const { cols, rows } = existingHub;
6497
6630
  setTimeout(() => {
6498
6631
  if (existingHub.clients.has(ws) && ws.readyState === import_websocket.default.OPEN) try {
@@ -6551,7 +6684,8 @@ function setupTerminalWebSocket(server) {
6551
6684
  clients: new Set([ws]),
6552
6685
  cols: 120,
6553
6686
  rows: 29,
6554
- inputClient: ws
6687
+ inputClient: ws,
6688
+ clientBlackout: new Map([[ws, Date.now() + 200]])
6555
6689
  };
6556
6690
  const startLocalPty = async (cols, rows) => {
6557
6691
  if (ptyStarted) return;
@@ -6751,6 +6885,7 @@ function canReplaceTitle(conv) {
6751
6885
  * All file I/O uses fs/promises (no sync calls).
6752
6886
  */
6753
6887
  init_cost();
6888
+ init_paths();
6754
6889
  /** Detect AI provider from model name */
6755
6890
  function providerFromModel(model) {
6756
6891
  if (model.includes("gpt")) return "openai";
@@ -7357,7 +7492,7 @@ const DEFAULT_EVENTS_SUBDIR$1 = ".pan/events";
7357
7492
  */
7358
7493
  function resolveWalDir(issueId) {
7359
7494
  const projects = listProjects();
7360
- const issuePrefix = issueId.split("-")[0]?.toUpperCase();
7495
+ const issuePrefix = extractPrefix(issueId);
7361
7496
  if (!issuePrefix) return null;
7362
7497
  for (const { key, config } of projects) {
7363
7498
  const projectKey = key.toUpperCase();
@@ -7750,6 +7885,7 @@ function getCostsForIssue(issueId) {
7750
7885
  * Migrates historical session data to the event-sourced format.
7751
7886
  * Includes both main session files and subagent session files.
7752
7887
  */
7888
+ init_paths();
7753
7889
  init_cost();
7754
7890
  function getAgentsDir$1() {
7755
7891
  return join(process.env.HOME || homedir$1(), ".panopticon", "agents");
@@ -7882,7 +8018,7 @@ function usageToCostEvents(usages, context) {
7882
8018
  * Find session directory for a workspace
7883
8019
  */
7884
8020
  function getSessionDir(workspacePath) {
7885
- const sessionDirName = `-${workspacePath.replace(/^\//, "").replace(/\//g, "-")}`;
8021
+ const sessionDirName = encodeClaudeProjectDir(workspacePath);
7886
8022
  const sessionDir = join(getClaudeProjectsDir$1(), sessionDirName);
7887
8023
  if (existsSync(sessionDir)) return sessionDir;
7888
8024
  return null;
@@ -8507,6 +8643,7 @@ function getHandoffStats() {
8507
8643
  * GET /api/issues/:id/costs
8508
8644
  */
8509
8645
  init_projects();
8646
+ init_issue_id();
8510
8647
  init_tracker_config();
8511
8648
  init_tmux();
8512
8649
  const execAsync$16 = promisify(exec);
@@ -8658,9 +8795,8 @@ const postIssuePlanRoute = HttpRouter.add("POST", "/api/issues/:id/plan", httpHa
8658
8795
  if (!tasks || !Array.isArray(tasks) || tasks.length === 0) return jsonResponse({ error: "Tasks are required" }, { status: 400 });
8659
8796
  const issue = yield* Effect.promise(() => Effect.runPromise(linear.getIssue(id).pipe(Effect.catch(() => Effect.succeed(null)))));
8660
8797
  if (!issue) return jsonResponse({ error: "Issue not found" }, { status: 404 });
8661
- const issuePrefix = issue.identifier.split("-")[0];
8662
- const projectPath = getProjectPath$4(void 0, issuePrefix);
8663
- const { findPRDFiles, analyzeComplexity, executePlan } = yield* Effect.promise(() => import("./plan-utils-BkCIhn3B.js"));
8798
+ const projectPath = getProjectPath$4(void 0, extractPrefix(issue.identifier) ?? issue.identifier.split("-")[0]);
8799
+ const { findPRDFiles, analyzeComplexity, executePlan } = yield* Effect.promise(() => import("./plan-utils-Bkcsqr_s.js"));
8664
8800
  const prdFiles = yield* Effect.promise(() => findPRDFiles(issue.identifier, projectPath));
8665
8801
  const planIssue = {
8666
8802
  id: issue.id,
@@ -8717,9 +8853,8 @@ const postIssueCloseRoute = HttpRouter.add("POST", "/api/issues/:issueId/close",
8717
8853
  const body = yield* readJsonBody$9;
8718
8854
  const eventStore = yield* EventStoreService;
8719
8855
  const { reason } = body;
8720
- const issuePrefix = issueId.split("-")[0];
8721
- const projectPath = getProjectPath$4(void 0, issuePrefix);
8722
- const { close: closeWorkflow } = yield* Effect.promise(() => import("./lifecycle-ZTYdrr2O.js"));
8856
+ const projectPath = getProjectPath$4(void 0, extractPrefix(issueId) ?? issueId.split("-")[0]);
8857
+ const { close: closeWorkflow } = yield* Effect.promise(() => import("./lifecycle-BcUmtkR4.js"));
8723
8858
  const githubCheck = isGitHubIssue$1(issueId);
8724
8859
  const issueDataService = getIssueDataService$3();
8725
8860
  const issueSource = issueDataService.getIssueSource(issueId);
@@ -8823,8 +8958,7 @@ const postIssueStartPlanningRoute = HttpRouter.add("POST", "/api/issues/:id/star
8823
8958
  };
8824
8959
  yield* Effect.promise(() => Effect.runPromise(lifecycle.transitionTo(id, "in_planning").pipe(Effect.catch(() => Effect.void))));
8825
8960
  }
8826
- const issuePrefix = issue.identifier.split("-")[0];
8827
- const projectPath = getProjectPath$4(void 0, issuePrefix);
8961
+ const projectPath = getProjectPath$4(void 0, extractPrefix(issue.identifier) ?? issue.identifier.split("-")[0]);
8828
8962
  const issueLower = issue.identifier.toLowerCase();
8829
8963
  const workspacePath = join$1(projectPath, "workspaces", `feature-${issueLower}`);
8830
8964
  const sessionName = `planning-${issueLower}`;
@@ -9003,7 +9137,7 @@ const postIssueAbortPlanningRoute = HttpRouter.add("POST", "/api/issues/:id/abor
9003
9137
  let projectPath;
9004
9138
  if (githubCheck.isGitHub && githubCheck.owner && githubCheck.repo) projectPath = getGitHubLocalPaths$1()[`${githubCheck.owner}/${githubCheck.repo}`];
9005
9139
  if (!projectPath) {
9006
- const projConfig = findProjectByTeam(issueIdentifier.split("-")[0].toUpperCase());
9140
+ const projConfig = findProjectByTeam(extractPrefix(issueIdentifier) ?? issueIdentifier.split("-")[0].toUpperCase());
9007
9141
  if (projConfig) projectPath = projConfig.path;
9008
9142
  }
9009
9143
  if (projectPath) {
@@ -9143,8 +9277,8 @@ const postIssueCompletePlanningRoute = HttpRouter.add("POST", "/api/issues/:id/c
9143
9277
  try {
9144
9278
  const gitRoot = planningDir.includes("/workspaces/") ? join$1(projectPath, "workspaces", `feature-${issueLower}`) : projectPath;
9145
9279
  let beadsWarning = null;
9146
- const { findPlan } = await import("./io-yGovuG4U.js");
9147
- const { createBeadsFromVBrief } = await import("./beads-D_FRedEJ.js");
9280
+ const { findPlan } = await import("./io-CWlFW78i.js");
9281
+ const { createBeadsFromVBrief } = await import("./beads-By6-X07V.js");
9148
9282
  if (findPlan(gitRoot)) try {
9149
9283
  const beadsResult = await createBeadsFromVBrief(gitRoot);
9150
9284
  if (beadsResult.created.length > 0) console.log(`[complete-planning] Created ${beadsResult.created.length} beads from vBRIEF plan`);
@@ -9305,7 +9439,7 @@ const postIssueResetRoute = HttpRouter.add("POST", "/api/issues/:id/reset", http
9305
9439
  cleanupLog.push(`Deleted agent state: ${dir}`);
9306
9440
  }
9307
9441
  try {
9308
- const { removeShadowState } = await import("./shadow-state-DHQ-kASN.js");
9442
+ const { removeShadowState } = await import("./shadow-state-BIexcxkv.js");
9309
9443
  if (removeShadowState(id).success) cleanupLog.push(`Cleared shadow state for ${id}`);
9310
9444
  } catch {}
9311
9445
  try {
@@ -9401,14 +9535,14 @@ const postIssueCancelRoute = HttpRouter.add("POST", "/api/issues/:id/cancel", ht
9401
9535
  cleanupLog.push("Cleared review status");
9402
9536
  } catch {}
9403
9537
  try {
9404
- const { removeShadowState } = await import("./shadow-state-DHQ-kASN.js");
9538
+ const { removeShadowState } = await import("./shadow-state-BIexcxkv.js");
9405
9539
  removeShadowState(id);
9406
9540
  cleanupLog.push("Cleared shadow state");
9407
9541
  } catch {}
9408
9542
  });
9409
9543
  if (wipeWorkspace) yield* Effect.promise(async () => {
9410
9544
  try {
9411
- const { deepWipe } = await import("./lifecycle-ZTYdrr2O.js");
9545
+ const { deepWipe } = await import("./lifecycle-BcUmtkR4.js");
9412
9546
  const issuePrefix = extractTeamPrefix(id);
9413
9547
  const projectPath = getProjectPath$4(void 0, issuePrefix);
9414
9548
  const projectConfig = findProjectByTeam(issuePrefix);
@@ -9510,7 +9644,7 @@ const postIssueReopenRoute = HttpRouter.add("POST", "/api/issues/:id/reopen", ht
9510
9644
  yield* Effect.promise(async () => {
9511
9645
  try {
9512
9646
  clearReviewStatus(id.toUpperCase());
9513
- const { checkSpecialistQueue, completeSpecialistTask } = await import("./specialists-Cny632-T.js");
9647
+ const { checkSpecialistQueue, completeSpecialistTask } = await import("./specialists-Cp-PgspS.js");
9514
9648
  for (const specialist of [
9515
9649
  "review-agent",
9516
9650
  "test-agent",
@@ -9521,7 +9655,7 @@ const postIssueReopenRoute = HttpRouter.add("POST", "/api/issues/:id/reopen", ht
9521
9655
  }
9522
9656
  } catch {}
9523
9657
  try {
9524
- const { resetPostMergeState } = await import("./merge-agent-GLtMEsTu.js");
9658
+ const { resetPostMergeState } = await import("./merge-agent-CGN3TT0a.js");
9525
9659
  resetPostMergeState(id);
9526
9660
  resetPostMergeState(id.toUpperCase());
9527
9661
  } catch {}
@@ -9543,8 +9677,8 @@ const postIssueReopenRoute = HttpRouter.add("POST", "/api/issues/:id/reopen", ht
9543
9677
  const projectPath = (teamPrefix ? findProjectByTeam(teamPrefix) : null)?.path || "";
9544
9678
  if (projectPath) {
9545
9679
  const workspacePath = join$1(projectPath, "workspaces", `feature-${issueLower}`);
9546
- const { findPlan } = await import("./io-yGovuG4U.js");
9547
- const { createBeadsFromVBrief } = await import("./beads-D_FRedEJ.js");
9680
+ const { findPlan } = await import("./io-CWlFW78i.js");
9681
+ const { createBeadsFromVBrief } = await import("./beads-By6-X07V.js");
9548
9682
  if (existsSync$1(workspacePath) && findPlan(workspacePath)) try {
9549
9683
  const { stdout: bdCheck } = await execAsync$16(`bd list --json -l ${issueLower} --limit 1`, {
9550
9684
  cwd: workspacePath,
@@ -9615,7 +9749,7 @@ const postIssueMoveStatusRoute = HttpRouter.add("POST", "/api/issues/:id/move-st
9615
9749
  "done"
9616
9750
  ];
9617
9751
  if (!targetStatus || !validStatuses.includes(targetStatus)) return jsonResponse({ error: `Invalid targetStatus. Must be one of: ${validStatuses.join(", ")}` }, { status: 400 });
9618
- const { updateShadowState } = yield* Effect.promise(() => import("./shadow-state-DHQ-kASN.js"));
9752
+ const { updateShadowState } = yield* Effect.promise(() => import("./shadow-state-BIexcxkv.js"));
9619
9753
  const issueState = {
9620
9754
  backlog: "open",
9621
9755
  todo: "open",
@@ -9737,7 +9871,7 @@ const postIssueDeepWipeRoute = HttpRouter.add("POST", "/api/issues/:id/deep-wipe
9737
9871
  const body = yield* readJsonBody$9;
9738
9872
  const eventStore = yield* EventStoreService;
9739
9873
  const { deleteWorkspace = false } = body || {};
9740
- const { deepWipe } = yield* Effect.promise(() => import("./lifecycle-ZTYdrr2O.js"));
9874
+ const { deepWipe } = yield* Effect.promise(() => import("./lifecycle-BcUmtkR4.js"));
9741
9875
  const githubCheck = isGitHubIssue$1(id);
9742
9876
  let projectPath = "";
9743
9877
  let projectName = "";
@@ -9747,7 +9881,7 @@ const postIssueDeepWipeRoute = HttpRouter.add("POST", "/api/issues/:id/deep-wipe
9747
9881
  projectName = githubCheck.repo || "";
9748
9882
  }
9749
9883
  if (!projectPath) {
9750
- projectConfig = findProjectByTeam(id.split("-")[0].toUpperCase());
9884
+ projectConfig = findProjectByTeam(extractPrefix(id) ?? id.split("-")[0].toUpperCase());
9751
9885
  if (projectConfig) {
9752
9886
  projectPath = projectConfig.path;
9753
9887
  projectName = projectConfig.name;
@@ -9838,11 +9972,11 @@ const postIssueDeepWipeRoute = HttpRouter.add("POST", "/api/issues/:id/deep-wipe
9838
9972
  const postIssueCloseOutRoute = HttpRouter.add("POST", "/api/issues/:id/close-out", httpHandler(Effect.gen(function* () {
9839
9973
  const id = (yield* HttpRouter.params)["id"] ?? "";
9840
9974
  const eventStore = yield* EventStoreService;
9841
- const { closeOut } = yield* Effect.promise(() => import("./lifecycle-ZTYdrr2O.js"));
9975
+ const { closeOut } = yield* Effect.promise(() => import("./lifecycle-BcUmtkR4.js"));
9842
9976
  const githubCheck = isGitHubIssue$1(id);
9843
9977
  let projectPath = "";
9844
9978
  if (githubCheck.isGitHub && githubCheck.owner && githubCheck.repo) projectPath = getGitHubLocalPaths$1()[`${githubCheck.owner}/${githubCheck.repo}`] || "";
9845
- if (!projectPath) projectPath = getProjectPath$4(void 0, id.split("-")[0].toUpperCase());
9979
+ if (!projectPath) projectPath = getProjectPath$4(void 0, extractPrefix(id) ?? id.split("-")[0].toUpperCase());
9846
9980
  if (!projectPath) return jsonResponse({ error: `Could not resolve project path for ${id}` }, { status: 400 });
9847
9981
  const ctx = {
9848
9982
  issueId: id,
@@ -9901,7 +10035,7 @@ const getIssueBeadsRoute = HttpRouter.add("GET", "/api/issues/:id/beads", httpHa
9901
10035
  let projectPath = "";
9902
10036
  if (githubCheck.isGitHub && githubCheck.owner && githubCheck.repo) projectPath = getGitHubLocalPaths$1()[`${githubCheck.owner}/${githubCheck.repo}`] || "";
9903
10037
  if (!projectPath) {
9904
- const issuePrefix = id.split("-")[0];
10038
+ const issuePrefix = extractPrefix(id) ?? id.split("-")[0];
9905
10039
  try {
9906
10040
  projectPath = getProjectPath$4(void 0, issuePrefix);
9907
10041
  } catch {
@@ -12148,10 +12282,10 @@ async function checkOrphanedReviewStatuses() {
12148
12282
  const workspace = getAgentState(agentIdForCheck)?.workspace;
12149
12283
  if (workspace) {
12150
12284
  const branch = `feature/${issueId.toLowerCase()}`;
12151
- const { resolveProjectFromIssue } = await import("./projects-DyT3vSy-.js");
12285
+ const { resolveProjectFromIssue } = await import("./projects-C5ozxjwP.js");
12152
12286
  const resolved = resolveProjectFromIssue(issueId);
12153
12287
  if (resolved) {
12154
- const { spawnEphemeralSpecialist } = await import("./specialists-Cny632-T.js");
12288
+ const { spawnEphemeralSpecialist } = await import("./specialists-Cp-PgspS.js");
12155
12289
  const result = await spawnEphemeralSpecialist(resolved.projectKey, "review-agent", {
12156
12290
  issueId,
12157
12291
  workspace,
@@ -12164,7 +12298,7 @@ async function checkOrphanedReviewStatuses() {
12164
12298
  actions.push(`Re-dispatched pending review for ${issueId} via ${resolved.projectKey}/review-agent (deacon-orphan-recovery)`);
12165
12299
  console.log(`[deacon] Re-dispatched review for ${issueId} after orphan/pending detection (project: ${resolved.projectKey})`);
12166
12300
  } else if (result.error === "specialist_busy") {
12167
- const { submitToSpecialistQueue } = await import("./specialists-Cny632-T.js");
12301
+ const { submitToSpecialistQueue } = await import("./specialists-Cp-PgspS.js");
12168
12302
  submitToSpecialistQueue("review-agent", {
12169
12303
  priority: "high",
12170
12304
  source: "deacon-orphan-recovery",
@@ -12202,10 +12336,10 @@ async function checkOrphanedReviewStatuses() {
12202
12336
  const workspace = getAgentState(`agent-${issueId.toLowerCase()}`)?.workspace;
12203
12337
  if (workspace) {
12204
12338
  const branch = `feature/${issueId.toLowerCase()}`;
12205
- const { resolveProjectFromIssue } = await import("./projects-DyT3vSy-.js");
12339
+ const { resolveProjectFromIssue } = await import("./projects-C5ozxjwP.js");
12206
12340
  const resolved = resolveProjectFromIssue(issueId);
12207
12341
  if (resolved) {
12208
- const { spawnEphemeralSpecialist } = await import("./specialists-Cny632-T.js");
12342
+ const { spawnEphemeralSpecialist } = await import("./specialists-Cp-PgspS.js");
12209
12343
  const result = await spawnEphemeralSpecialist(resolved.projectKey, "test-agent", {
12210
12344
  issueId,
12211
12345
  workspace,
@@ -12217,7 +12351,7 @@ async function checkOrphanedReviewStatuses() {
12217
12351
  actions.push(`Re-dispatched orphaned test for ${issueId} via ${resolved.projectKey}/test-agent (deacon-orphan-recovery)`);
12218
12352
  console.log(`[deacon] Re-dispatched test for ${issueId} after orphan detection (project: ${resolved.projectKey})`);
12219
12353
  } else if (result.error === "specialist_busy") {
12220
- const { submitToSpecialistQueue } = await import("./specialists-Cny632-T.js");
12354
+ const { submitToSpecialistQueue } = await import("./specialists-Cp-PgspS.js");
12221
12355
  submitToSpecialistQueue("test-agent", {
12222
12356
  priority: "high",
12223
12357
  source: "deacon-orphan-recovery",
@@ -12273,7 +12407,7 @@ async function checkPostReviewCommits() {
12273
12407
  const actions = [];
12274
12408
  try {
12275
12409
  const statuses = loadReviewStatuses();
12276
- const { resolveProjectFromIssue } = await import("./projects-DyT3vSy-.js");
12410
+ const { resolveProjectFromIssue } = await import("./projects-C5ozxjwP.js");
12277
12411
  for (const [issueId, status] of Object.entries(statuses)) {
12278
12412
  if (status.mergeStatus === "merged") continue;
12279
12413
  if (!status.reviewedAtCommit) continue;
@@ -12586,9 +12720,9 @@ async function patrolWorkAgentResolutions() {
12586
12720
  async function checkSpecialistQueues() {
12587
12721
  const actions = [];
12588
12722
  try {
12589
- const { checkSpecialistQueue, spawnEphemeralSpecialist, getTmuxSessionName, isRunning } = await import("./specialists-Cny632-T.js");
12590
- const { getAgentRuntimeState } = await import("./agents-BVBVCyat.js");
12591
- const { resolveProjectFromIssue } = await import("./projects-DyT3vSy-.js");
12723
+ const { checkSpecialistQueue, spawnEphemeralSpecialist, getTmuxSessionName, isRunning } = await import("./specialists-Cp-PgspS.js");
12724
+ const { getAgentRuntimeState } = await import("./agents-Dgh2TjSp.js");
12725
+ const { resolveProjectFromIssue } = await import("./projects-C5ozxjwP.js");
12592
12726
  for (const specialistType of [
12593
12727
  "review-agent",
12594
12728
  "test-agent",
@@ -12622,7 +12756,7 @@ async function checkSpecialistQueues() {
12622
12756
  if (!isIdle) continue;
12623
12757
  console.log(`[deacon] Dispatching queued ${specialistType} work for ${issueId} (project: ${resolved.projectKey})`);
12624
12758
  try {
12625
- const { findWorkspacePath } = await import("./archive-planning-CScs1MOC.js");
12759
+ const { findWorkspacePath } = await import("./archive-planning-C3Ebf9yC.js");
12626
12760
  const workspacePath = findWorkspacePath(resolved.projectPath, issueId.toLowerCase());
12627
12761
  const queuePayload = item.payload;
12628
12762
  await spawnEphemeralSpecialist(resolved.projectKey, specialistType, {
@@ -12758,7 +12892,7 @@ async function runPatrol() {
12758
12892
  if (!existsSync(REVIEW_STATUS_FILE)) continue;
12759
12893
  const statuses = JSON.parse(readFileSync(REVIEW_STATUS_FILE, "utf-8"));
12760
12894
  if (statuses[issueId]?.mergeStatus === "merging") {
12761
- const { resolveProjectFromIssue } = await import("./projects-DyT3vSy-.js");
12895
+ const { resolveProjectFromIssue } = await import("./projects-C5ozxjwP.js");
12762
12896
  const resolved = resolveProjectFromIssue(issueId);
12763
12897
  if (resolved) {
12764
12898
  const branch = `feature/${issueId.toLowerCase()}`;
@@ -12768,7 +12902,7 @@ async function runPatrol() {
12768
12902
  statuses[issueId].mergeStatus = "merged";
12769
12903
  statuses[issueId].readyForMerge = false;
12770
12904
  writeFileSync(REVIEW_STATUS_FILE, JSON.stringify(statuses, null, 2), "utf-8");
12771
- const { postMergeLifecycle } = await import("./merge-agent-GLtMEsTu.js");
12905
+ const { postMergeLifecycle } = await import("./merge-agent-CGN3TT0a.js");
12772
12906
  postMergeLifecycle(issueId, resolved.projectPath).catch((err) => console.warn(`[deacon] postMergeLifecycle failed for ${issueId}: ${err}`));
12773
12907
  actions.push(`Auto-completed stale merge for ${issueId}`);
12774
12908
  } else {
@@ -13026,7 +13160,7 @@ var CloisterService = class {
13026
13160
  }
13027
13161
  try {
13028
13162
  if (existsSync(AGENTS_DIR)) {
13029
- const { isRunning: isSpecialistRunning } = await import("./specialists-Cny632-T.js");
13163
+ const { isRunning: isSpecialistRunning } = await import("./specialists-Cp-PgspS.js");
13030
13164
  const specialistPattern = /^specialist-(.+)-(review-agent|test-agent|merge-agent)$/;
13031
13165
  const entries = readdirSync(AGENTS_DIR, { withFileTypes: true });
13032
13166
  for (const entry of entries) {
@@ -13057,8 +13191,8 @@ var CloisterService = class {
13057
13191
  }
13058
13192
  try {
13059
13193
  const reviewStatuses = loadReviewStatuses();
13060
- const { resolveProjectFromIssue } = await import("./projects-DyT3vSy-.js");
13061
- const { submitToSpecialistQueue, getTmuxSessionName, getAllProjectSpecialistStatuses } = await import("./specialists-Cny632-T.js");
13194
+ const { resolveProjectFromIssue } = await import("./projects-C5ozxjwP.js");
13195
+ const { submitToSpecialistQueue, getTmuxSessionName, getAllProjectSpecialistStatuses } = await import("./specialists-Cp-PgspS.js");
13062
13196
  const activeReviewIssues = /* @__PURE__ */ new Set();
13063
13197
  try {
13064
13198
  const projSpecs = await getAllProjectSpecialistStatuses();
@@ -13282,7 +13416,7 @@ var CloisterService = class {
13282
13416
  const retryCount = this.processedCompletions.get(dir.name) || 0;
13283
13417
  if (retryCount >= 3) continue;
13284
13418
  const issueId = dir.name.replace("agent-", "").toUpperCase();
13285
- const { getReviewStatus } = await import("./review-status-CK3eBGyb.js");
13419
+ const { getReviewStatus } = await import("./review-status-BtXqWBhS.js");
13286
13420
  const existingReview = getReviewStatus(issueId);
13287
13421
  if (existingReview && ["reviewing", "passed"].includes(existingReview.reviewStatus || "")) {
13288
13422
  console.log(`🔔 Cloister: Completion marker for ${issueId} — review already ${existingReview.reviewStatus}, marking processed`);
@@ -14005,10 +14139,11 @@ function buildResumePrompt(workspacePath, issueId, agentDir, userMessage) {
14005
14139
  * GET /api/agents/:id/cost
14006
14140
  * POST /api/agents
14007
14141
  */
14142
+ init_paths();
14008
14143
  init_config$1();
14009
14144
  init_agents();
14010
- init_paths();
14011
14145
  init_projects();
14146
+ init_issue_id();
14012
14147
  init_tracker_config();
14013
14148
  init_cost();
14014
14149
  init_jsonl_parser();
@@ -14419,7 +14554,7 @@ const getAgentHealthHistoryRoute = HttpRouter.add("GET", "/api/agents/:id/health
14419
14554
  const request = yield* HttpServerRequest.HttpServerRequest;
14420
14555
  const urlOpt = HttpServerRequest.toURL(request);
14421
14556
  const hours = Option.isSome(urlOpt) ? urlOpt.value.searchParams.get("hours") ?? "24" : "24";
14422
- const { getHealthHistory } = yield* Effect.promise(() => import("./health-events-db-584nYgJB.js"));
14557
+ const { getHealthHistory } = yield* Effect.promise(() => import("./health-events-db-BMXQfInV.js"));
14423
14558
  const endTime = /* @__PURE__ */ new Date();
14424
14559
  const startTime = /* @__PURE__ */ new Date(endTime.getTime() - parseInt(hours) * 60 * 60 * 1e3);
14425
14560
  const events = getHealthHistory(id, startTime.toISOString(), endTime.toISOString());
@@ -14649,7 +14784,7 @@ const getAgentCostRoute = HttpRouter.add("GET", "/api/agents/:id/cost", httpHand
14649
14784
  const claudeProjectsDir = join$1(process.env.HOME || homedir(), ".claude", "projects");
14650
14785
  const workspacePath = agentState.workspace;
14651
14786
  if (workspacePath) {
14652
- const projectDir = join$1(claudeProjectsDir, `-${workspacePath.replace(/^\//, "").replace(/\//g, "-")}`);
14787
+ const projectDir = join$1(claudeProjectsDir, encodeClaudeProjectDir(workspacePath));
14653
14788
  const sessionsIndexPath = join$1(projectDir, "sessions-index.json");
14654
14789
  const parseJsonlCost = async (filePath) => {
14655
14790
  const lines = (await readFile(filePath, "utf-8")).split("\n").filter((l) => l.trim());
@@ -14710,8 +14845,7 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
14710
14845
  const issueLower = issueId.toLowerCase();
14711
14846
  const workspaceMetadata = loadWorkspaceMetadata(issueId);
14712
14847
  const isRemote = workspaceMetadata?.location === "remote";
14713
- const issuePrefix = issueId.split("-")[0];
14714
- const projectPath = getProjectPath$3(projectId, issuePrefix);
14848
+ const projectPath = getProjectPath$3(projectId, extractPrefix(issueId) ?? issueId.split("-")[0]);
14715
14849
  const workspaceExists = existsSync$1(join$1(projectPath, "workspaces", `feature-${issueLower}`));
14716
14850
  const hasPrd = existsSync$1(join$1(projectPath, PROJECT_DOCS_SUBDIR, PROJECT_PRDS_SUBDIR, PROJECT_PRDS_ACTIVE_SUBDIR, `${issueLower}-plan.md`));
14717
14851
  const hasDraftPrd = hasPRDDraft(issueId);
@@ -14768,7 +14902,7 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
14768
14902
  issueId
14769
14903
  }, { status: 422 });
14770
14904
  try {
14771
- const { readPlan } = yield* Effect.promise(() => import("./io-yGovuG4U.js"));
14905
+ const { readPlan } = yield* Effect.promise(() => import("./io-CWlFW78i.js"));
14772
14906
  if ((readPlan(planPath)?.plan?.items?.length ?? 0) === 0) return jsonResponse({
14773
14907
  error: "Plan exists but contains no items. Planning may have failed or produced an empty plan.",
14774
14908
  hint: "Re-run planning to produce a plan with tasks and acceptance criteria.",
@@ -14788,7 +14922,7 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
14788
14922
  if (!hasBeads) {
14789
14923
  console.log(`[agents] No beads for ${issueId} — attempting auto-recovery via createBeadsFromVBrief`);
14790
14924
  try {
14791
- const { createBeadsFromVBrief } = yield* Effect.promise(() => import("./beads-D_FRedEJ.js"));
14925
+ const { createBeadsFromVBrief } = yield* Effect.promise(() => import("./beads-By6-X07V.js"));
14792
14926
  const recovery = yield* Effect.promise(() => createBeadsFromVBrief(workspacePath));
14793
14927
  hasBeads = recovery.created.length > 0;
14794
14928
  if (hasBeads) console.log(`[agents] Auto-recovery created ${recovery.created.length} beads for ${issueId}`);
@@ -14837,12 +14971,12 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
14837
14971
  yield* Effect.promise(() => rename(planningPromptPath, planningPromptPath + ".archived"));
14838
14972
  } catch {}
14839
14973
  if (isRemote && workspaceMetadata) {
14840
- const { spawnRemoteAgent } = yield* Effect.promise(() => import("./remote-agents-CTKVhFFY.js"));
14841
- const { createFlyProviderFromConfig } = yield* Effect.promise(() => import("./remote-BHTTMpJJ.js"));
14842
- const { loadConfig: loadPanConfig } = yield* Effect.promise(() => import("./config-BeI3uy-8.js"));
14974
+ const { spawnRemoteAgent } = yield* Effect.promise(() => import("./remote-agents-Bf3GuM7t.js"));
14975
+ const { createFlyProviderFromConfig } = yield* Effect.promise(() => import("./remote-Cigqjj3f.js"));
14976
+ const { loadConfig: loadPanConfig } = yield* Effect.promise(() => import("./config-CTXkBATQ.js"));
14843
14977
  const fly = createFlyProviderFromConfig(loadPanConfig().remote);
14844
14978
  yield* Effect.promise(() => fly.syncAllCredentials(workspaceMetadata.vmName));
14845
- const { buildWorkAgentPrompt, getTrackerContext } = yield* Effect.promise(() => import("./work-agent-prompt-JYq_OugP.js"));
14979
+ const { buildWorkAgentPrompt, getTrackerContext } = yield* Effect.promise(() => import("./work-agent-prompt-fCg67nyo.js"));
14846
14980
  const agentPrompt = buildWorkAgentPrompt({
14847
14981
  issueId,
14848
14982
  env: "REMOTE",
@@ -14909,7 +15043,7 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
14909
15043
  yield* Effect.promise(() => writeFile(resumePromptFile, resumePrompt));
14910
15044
  let agentModel = existingAgentState.model || "claude-sonnet-4-6";
14911
15045
  try {
14912
- const { getModelId } = yield* Effect.promise(() => import("./work-type-router-Com2amST.js"));
15046
+ const { getModelId } = yield* Effect.promise(() => import("./work-type-router-Di5gCQwh.js"));
14913
15047
  agentModel = getModelId(`issue-agent:${phase}`);
14914
15048
  } catch {}
14915
15049
  const resumeContent = `#!/bin/bash\n${getProviderExportsForModel(agentModel)}prompt=$(cat "${resumePromptFile}")\nexec claude --dangerously-skip-permissions --model ${agentModel} -p "$prompt"\n`;
@@ -15351,6 +15485,68 @@ async function runVerificationForIssue(issueId, workspacePath, workspaceInfo, lo
15351
15485
  setReviewStatus$1(issueId, { verificationStatus: "running" });
15352
15486
  console.log(`[${logPrefix}] Running verification gate for ${issueId} (attempt ${currentCycles + 1}/10)`);
15353
15487
  try {
15488
+ try {
15489
+ console.log(`[${logPrefix}] Syncing main into workspace for ${issueId}...`);
15490
+ await execAsync$10("git fetch origin main", {
15491
+ cwd: workspacePath,
15492
+ encoding: "utf-8",
15493
+ timeout: 3e4
15494
+ });
15495
+ const mergeResult = await execAsync$10("git merge origin/main --no-edit", {
15496
+ cwd: workspacePath,
15497
+ encoding: "utf-8",
15498
+ timeout: 6e4
15499
+ });
15500
+ const mergeOut = (mergeResult.stdout || "") + (mergeResult.stderr || "");
15501
+ if (mergeOut.includes("Already up to date") || mergeOut.includes("Already up-to-date")) console.log(`[${logPrefix}] Already up to date with main`);
15502
+ else console.log(`[${logPrefix}] Merged latest main into workspace`);
15503
+ } catch (mergeErr) {
15504
+ const mergeOut = (mergeErr.stdout || "") + (mergeErr.stderr || "");
15505
+ if (mergeOut.includes("CONFLICT") || mergeOut.includes("Merge conflict")) {
15506
+ try {
15507
+ await execAsync$10("git merge --abort", {
15508
+ cwd: workspacePath,
15509
+ encoding: "utf-8"
15510
+ });
15511
+ } catch {}
15512
+ const conflictLines = mergeOut.split("\n").filter((line) => line.startsWith("CONFLICT")).map((line) => line.replace(/^CONFLICT \([^)]+\): /, "").replace(/Merge conflict in /, "")).join("\n - ");
15513
+ const newCycleCount = currentCycles + 1;
15514
+ const failedCheck = "sync-main";
15515
+ const summary = `Sync with main FAILED — merge conflicts detected:\n - ${conflictLines}`;
15516
+ setReviewStatus$1(issueId, {
15517
+ reviewStatus: "pending",
15518
+ verificationStatus: "failed",
15519
+ verificationNotes: summary,
15520
+ verificationCycleCount: newCycleCount,
15521
+ verificationMaxCycles: 10
15522
+ });
15523
+ const feedbackBody = `VERIFICATION FAILED for ${issueId} (attempt ${newCycleCount}/10):\n\nFailed check: ${failedCheck}\n\n${summary}\n\n## REQUIRED: Resolve merge conflicts with main BEFORE resubmitting\n\nThe main branch has advanced since you started working. Your branch has merge conflicts that must be resolved.\n\n1. Run: git fetch origin main && git merge origin/main\n2. Resolve all conflicts in the listed files\n3. Run the project's build and tests to verify nothing broke\n4. Commit and push ALL changes\n5. ONLY THEN resubmit:\ncurl -X POST ${process.env.DASHBOARD_URL || `http://localhost:${process.env.API_PORT || process.env.PORT || "3011"}`}/api/workspaces/${issueId}/request-review -H "Content-Type: application/json" -d '{}'\n\nDo NOT resubmit until all conflicts are resolved and tests pass.`;
15524
+ try {
15525
+ const fileResult = await writeFeedbackFile({
15526
+ issueId,
15527
+ workspacePath,
15528
+ specialist: "verification-gate",
15529
+ outcome: "failed",
15530
+ summary: `Sync with main FAILED — merge conflicts (attempt ${newCycleCount}/10)`,
15531
+ markdownBody: feedbackBody
15532
+ });
15533
+ if (fileResult.success) {
15534
+ const agentId = `agent-${issueId.toLowerCase()}`;
15535
+ await messageAgent(agentId, `VERIFICATION FAILED for ${issueId}.\nFailed check: ${failedCheck} — merge conflicts with main\nRead and address: ${fileResult.relativePath}`);
15536
+ console.log(`[${logPrefix}] Sync-main failed for ${issueId} — sent conflict feedback to ${agentId}`);
15537
+ }
15538
+ } catch (feedbackErr) {
15539
+ console.error(`[${logPrefix}] Failed to write sync-main feedback for ${issueId}:`, feedbackErr);
15540
+ }
15541
+ return {
15542
+ outcome: "failed",
15543
+ failedCheck,
15544
+ cycleCount: newCycleCount,
15545
+ maxCycles: 10
15546
+ };
15547
+ }
15548
+ console.warn(`[${logPrefix}] Sync-main warning for ${issueId}: ${mergeErr.message} (continuing)`);
15549
+ }
15354
15550
  const projectConfig = findProjectByPath(workspacePath);
15355
15551
  const gates = projectConfig?.quality_gates && Object.keys(projectConfig.quality_gates).length > 0 ? projectConfig.quality_gates : DEFAULT_GATES;
15356
15552
  console.log(`[${logPrefix}] Project: ${projectConfig?.name || "NOT FOUND"}, gates: [${Object.keys(gates).join(", ")}], workspace: ${workspacePath}`);
@@ -15532,6 +15728,7 @@ init_agents();
15532
15728
  init_jsonl_parser();
15533
15729
  init_specialists();
15534
15730
  init_tldr_daemon();
15731
+ init_issue_id();
15535
15732
  const execAsync$9 = promisify(exec);
15536
15733
  const PORT = parseInt(process.env.API_PORT || process.env.PORT || "3011", 10);
15537
15734
  const MAX_AUTO_REQUEUE = 7;
@@ -15610,7 +15807,7 @@ function getWorkspaceInfoForIssue(issueId) {
15610
15807
  agentId: meta.agentId
15611
15808
  };
15612
15809
  } catch {}
15613
- const issuePrefix = issueId.split("-")[0];
15810
+ const issuePrefix = extractPrefix(issueId) ?? issueId.split("-")[0];
15614
15811
  const issueLower = issueId.toLowerCase();
15615
15812
  const numericSuffix = issueLower.replace(/^[a-z]+-/, "");
15616
15813
  for (const { config } of listProjects()) {
@@ -15753,7 +15950,7 @@ async function getMrUrlAsync(issueId, workspacePath) {
15753
15950
  */
15754
15951
  async function buildRichPRBody(issueId, workspacePath) {
15755
15952
  const lines = [];
15756
- lines.push(`Closes #${issueId.split("-")[1] || issueId}`);
15953
+ lines.push(`Closes #${extractNumber(issueId) ?? issueId}`);
15757
15954
  lines.push("");
15758
15955
  try {
15759
15956
  const planPath = join$1(workspacePath, ".planning", "plan.vbrief.json");
@@ -15996,7 +16193,7 @@ const readJsonBody$7 = Effect.gen(function* () {
15996
16193
  });
15997
16194
  const getWorkspaceRoute = HttpRouter.add("GET", "/api/workspaces/:issueId", httpHandler(Effect.gen(function* () {
15998
16195
  const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
15999
- const issuePrefix = issueId.split("-")[0];
16196
+ const issuePrefix = extractPrefix(issueId) ?? issueId.split("-")[0];
16000
16197
  const projectPath = getProjectPath$2(void 0, issuePrefix);
16001
16198
  const issueLower = issueId.toLowerCase();
16002
16199
  const workspaceInfo = getWorkspaceInfoForIssue(issueId);
@@ -16109,8 +16306,7 @@ const getWorkspaceRoute = HttpRouter.add("GET", "/api/workspaces/:issueId", http
16109
16306
  const postWorkspacesRoute = HttpRouter.add("POST", "/api/workspaces", httpHandler(Effect.gen(function* () {
16110
16307
  const { issueId, projectId } = yield* readJsonBody$7;
16111
16308
  if (!issueId) return jsonResponse({ error: "issueId required" }, { status: 400 });
16112
- const issuePrefix = issueId.split("-")[0];
16113
- const projectPath = getProjectPath$2(projectId, issuePrefix);
16309
+ const projectPath = getProjectPath$2(projectId, extractPrefix(issueId) ?? issueId.split("-")[0]);
16114
16310
  const activityId = spawnPanCommand([
16115
16311
  "workspace",
16116
16312
  "create",
@@ -16125,8 +16321,7 @@ const postWorkspacesRoute = HttpRouter.add("POST", "/api/workspaces", httpHandle
16125
16321
  })));
16126
16322
  const getWorkspacePlanRoute = HttpRouter.add("GET", "/api/workspaces/:issueId/plan", httpHandler(Effect.gen(function* () {
16127
16323
  const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
16128
- const issuePrefix = issueId.split("-")[0];
16129
- const planPath = findPlan(join$1(getProjectPath$2(void 0, issuePrefix), "workspaces", `feature-${issueId.toLowerCase()}`));
16324
+ const planPath = findPlan(join$1(getProjectPath$2(void 0, extractPrefix(issueId) ?? issueId.split("-")[0]), "workspaces", `feature-${issueId.toLowerCase()}`));
16130
16325
  if (!planPath) return jsonResponse({ error: "No vBRIEF plan found for this workspace" }, { status: 404 });
16131
16326
  const doc = readPlan(planPath);
16132
16327
  const cp = criticalPath(doc);
@@ -16137,8 +16332,7 @@ const getWorkspacePlanRoute = HttpRouter.add("GET", "/api/workspaces/:issueId/pl
16137
16332
  })));
16138
16333
  const getWorkspaceCleanPreviewRoute = HttpRouter.add("GET", "/api/workspaces/:issueId/clean/preview", httpHandler(Effect.gen(function* () {
16139
16334
  const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
16140
- const issuePrefix = issueId.split("-")[0];
16141
- const projectPath = getProjectPath$2(void 0, issuePrefix);
16335
+ const projectPath = getProjectPath$2(void 0, extractPrefix(issueId) ?? issueId.split("-")[0]);
16142
16336
  const issueLower = issueId.toLowerCase();
16143
16337
  const workspaceName = `feature-${issueLower}`;
16144
16338
  const workspacePath = join$1(projectPath, "workspaces", workspaceName);
@@ -16277,8 +16471,7 @@ const getWorkspaceCleanPreviewRoute = HttpRouter.add("GET", "/api/workspaces/:is
16277
16471
  const postWorkspaceCleanRoute = HttpRouter.add("POST", "/api/workspaces/:issueId/clean", httpHandler(Effect.gen(function* () {
16278
16472
  const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
16279
16473
  const { createBackup } = yield* readJsonBody$7;
16280
- const issuePrefix = issueId.split("-")[0];
16281
- const projectPath = getProjectPath$2(void 0, issuePrefix);
16474
+ const projectPath = getProjectPath$2(void 0, extractPrefix(issueId) ?? issueId.split("-")[0]);
16282
16475
  const workspaceName = `feature-${issueId.toLowerCase()}`;
16283
16476
  const workspacePath = join$1(projectPath, "workspaces", workspaceName);
16284
16477
  if (!existsSync$1(workspacePath)) return jsonResponse({ error: "Workspace does not exist" }, { status: 404 });
@@ -16320,8 +16513,7 @@ const postWorkspaceCleanRoute = HttpRouter.add("POST", "/api/workspaces/:issueId
16320
16513
  })));
16321
16514
  const postWorkspaceContainerizeRoute = HttpRouter.add("POST", "/api/workspaces/:issueId/containerize", httpHandler(Effect.gen(function* () {
16322
16515
  const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
16323
- const issuePrefix = issueId.split("-")[0];
16324
- const projectPath = getProjectPath$2(void 0, issuePrefix);
16516
+ const projectPath = getProjectPath$2(void 0, extractPrefix(issueId) ?? issueId.split("-")[0]);
16325
16517
  const issueLower = issueId.toLowerCase();
16326
16518
  if (!existsSync$1(join$1(projectPath, "infra", "new-feature"))) return jsonResponse({ error: "Project does not support containerization (no infra/new-feature script)" }, { status: 400 });
16327
16519
  const workspacePath = join$1(projectPath, "workspaces", `feature-${issueLower}`);
@@ -16419,8 +16611,7 @@ const postWorkspaceContainerizeRoute = HttpRouter.add("POST", "/api/workspaces/:
16419
16611
  })));
16420
16612
  const postWorkspaceStartRoute = HttpRouter.add("POST", "/api/workspaces/:issueId/start", httpHandler(Effect.gen(function* () {
16421
16613
  const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
16422
- const issuePrefix = issueId.split("-")[0];
16423
- const projectPath = getProjectPath$2(void 0, issuePrefix);
16614
+ const projectPath = getProjectPath$2(void 0, extractPrefix(issueId) ?? issueId.split("-")[0]);
16424
16615
  const issueLower = issueId.toLowerCase();
16425
16616
  const workspacePath = join$1(projectPath, "workspaces", `feature-${issueLower}`);
16426
16617
  if (!existsSync$1(workspacePath)) return jsonResponse({ error: "Workspace does not exist" }, { status: 400 });
@@ -16833,7 +17024,7 @@ const postWorkspaceReviewStatusRoute = HttpRouter.add("POST", "/api/workspaces/:
16833
17024
  if (testNotes) update.testNotes = testNotes;
16834
17025
  const status = setReviewStatus(issueId, update);
16835
17026
  console.log(`[review-status] Updated ${issueId}:`, status);
16836
- const { getTmuxSessionName, checkSpecialistQueue: cSQ, completeSpecialistTask } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
17027
+ const { getTmuxSessionName, checkSpecialistQueue: cSQ, completeSpecialistTask } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
16837
17028
  const projectKey = resolveProjectFromIssue(issueId)?.projectKey;
16838
17029
  if (reviewStatus && [
16839
17030
  "passed",
@@ -16857,7 +17048,7 @@ const postWorkspaceReviewStatusRoute = HttpRouter.add("POST", "/api/workspaces/:
16857
17048
  const apiUrl = process.env.DASHBOARD_URL || `http://localhost:${process.env.API_PORT || process.env.PORT || "3011"}`;
16858
17049
  const feedbackBody = `CODE REVIEW ${reviewStatus.toUpperCase()} for ${issueId}:\n\n${reviewNotes}\n\n## REQUIRED: Fix ALL issues above BEFORE resubmitting\n\n1. Read each blocking issue carefully\n2. Fix the code for EVERY issue listed\n3. Run tests to verify your fixes\n4. Commit and push ALL changes\n5. ONLY THEN resubmit:\ncurl -X POST ${apiUrl}/api/workspaces/${issueId}/request-review -H "Content-Type: application/json" -d '{}'\n\nDo NOT run the curl command until steps 1-4 are complete. Do NOT stop until review passes.`;
16859
17050
  try {
16860
- const { writeFeedbackFile } = yield* Effect.promise(() => import("./feedback-writer-gSUv_W0h.js"));
17051
+ const { writeFeedbackFile } = yield* Effect.promise(() => import("./feedback-writer-Wgv1cd1r.js"));
16861
17052
  const wsInfo = getWorkspaceInfoForIssue(issueId);
16862
17053
  const fileResult = yield* Effect.promise(() => writeFeedbackFile({
16863
17054
  issueId,
@@ -16887,11 +17078,10 @@ const postWorkspaceReviewStatusRoute = HttpRouter.add("POST", "/api/workspaces/:
16887
17078
  }
16888
17079
  })));
16889
17080
  const issueLower = issueId.toLowerCase();
16890
- const issuePrefix = issueId.split("-")[0];
16891
- const projectPath = getProjectPath$2(void 0, issuePrefix);
17081
+ const projectPath = getProjectPath$2(void 0, extractPrefix(issueId) ?? issueId.split("-")[0]);
16892
17082
  const testWorkspace = body.workspace || join$1(projectPath, "workspaces", `feature-${issueLower}`);
16893
17083
  const testBranch = body.branch || `feature/${issueLower}`;
16894
- const { autoQueueTestAgentAndNotify } = yield* Effect.promise(() => import("./test-agent-queue-tqI4VDsu.js"));
17084
+ const { autoQueueTestAgentAndNotify } = yield* Effect.promise(() => import("./test-agent-queue-ypF_ecHo.js"));
16895
17085
  try {
16896
17086
  yield* Effect.promise(() => autoQueueTestAgentAndNotify(issueId, testWorkspace, testBranch, messageAgent));
16897
17087
  yield* Effect.promise(() => Effect.runPromise(eventStore.append({
@@ -16940,7 +17130,7 @@ const postWorkspaceReviewStatusRoute = HttpRouter.add("POST", "/api/workspaces/:
16940
17130
  const agentId = `agent-${issueId.toLowerCase()}`;
16941
17131
  const feedbackBody = `TESTS FAILED for ${issueId}:\n\n${testNotes}\n\n## REQUIRED: Fix ALL test failures BEFORE resubmitting\n\n1. Read each test failure carefully\n2. Fix the code causing EVERY failure\n3. Run the test suite to verify your fixes pass\n4. Commit and push ALL changes\n5. ONLY THEN resubmit:\ncurl -X POST ${process.env.DASHBOARD_URL || `http://localhost:${process.env.API_PORT || process.env.PORT || "3011"}`}/api/workspaces/${issueId}/request-review -H "Content-Type: application/json" -d '{}'\n\nDo NOT run the curl command until steps 1-4 are complete. Do NOT stop until review passes.`;
16942
17132
  try {
16943
- const { writeFeedbackFile } = yield* Effect.promise(() => import("./feedback-writer-gSUv_W0h.js"));
17133
+ const { writeFeedbackFile } = yield* Effect.promise(() => import("./feedback-writer-Wgv1cd1r.js"));
16944
17134
  const wsInfo = getWorkspaceInfoForIssue(issueId);
16945
17135
  const fileResult = yield* Effect.promise(() => writeFeedbackFile({
16946
17136
  issueId,
@@ -16986,8 +17176,7 @@ const postWorkspaceReviewRoute = HttpRouter.add("POST", "/api/workspaces/:issueI
16986
17176
  const body = yield* readJsonBody$7;
16987
17177
  const urlOpt = HttpServerRequest.toURL(request);
16988
17178
  const forceReview = Option.isSome(urlOpt) && urlOpt.value.searchParams.get("force") === "true" || body?.force === true;
16989
- const issuePrefix = issueId.split("-")[0];
16990
- const projectPath = getProjectPath$2(void 0, issuePrefix);
17179
+ const projectPath = getProjectPath$2(void 0, extractPrefix(issueId) ?? issueId.split("-")[0]);
16991
17180
  const issueLower = issueId.toLowerCase();
16992
17181
  const branchName = `feature/${issueLower}`;
16993
17182
  const workspaceInfo = getWorkspaceInfoForIssue(issueId);
@@ -17064,7 +17253,7 @@ const postWorkspaceReviewRoute = HttpRouter.add("POST", "/api/workspaces/:issueI
17064
17253
  console.log(`Feature branch push note: ${pushErr.message}`);
17065
17254
  }
17066
17255
  if (!workspaceInfo.isRemote) try {
17067
- const { getWorkspaceGitInfo } = await import("./git-utils-BtCRddq3.js");
17256
+ const { getWorkspaceGitInfo } = await import("./git-utils-DQI8EYoj.js");
17068
17257
  setReviewStatus(issueId, { lastReviewCommits: await getWorkspaceGitInfo(workspacePath) });
17069
17258
  } catch {}
17070
17259
  try {
@@ -17097,7 +17286,7 @@ const postWorkspaceReviewRoute = HttpRouter.add("POST", "/api/workspaces/:issueI
17097
17286
  });
17098
17287
  return;
17099
17288
  }
17100
- const { spawnEphemeralSpecialist: spawnEphemeral, isRunning, getTmuxSessionName, submitToSpecialistQueue } = await import("./specialists-Cny632-T.js");
17289
+ const { spawnEphemeralSpecialist: spawnEphemeral, isRunning, getTmuxSessionName, submitToSpecialistQueue } = await import("./specialists-Cp-PgspS.js");
17101
17290
  const reviewProjectKey = resolveProjectFromIssue(issueId)?.projectKey ?? null;
17102
17291
  const reviewSession = getTmuxSessionName("review-agent", reviewProjectKey ?? void 0);
17103
17292
  const reviewRunning = await isRunning("review-agent", reviewProjectKey ?? void 0);
@@ -17182,7 +17371,7 @@ ${workspaceAccessInstructions}
17182
17371
  if (!reviewResult.success) {
17183
17372
  if (reviewResult.error === "specialist_busy") {
17184
17373
  console.log(`[review] review-agent busy for ${issueId} — queuing for deacon dispatch`);
17185
- const { submitToSpecialistQueue } = await import("./specialists-Cny632-T.js");
17374
+ const { submitToSpecialistQueue } = await import("./specialists-Cp-PgspS.js");
17186
17375
  submitToSpecialistQueue("review-agent", {
17187
17376
  priority: "high",
17188
17377
  source: "review-pipeline",
@@ -17250,7 +17439,7 @@ const postWorkspaceRequestReviewRoute = HttpRouter.add("POST", "/api/workspaces/
17250
17439
  const workspacePath = join$1(resolved.projectPath, "workspaces", `feature-${issueId.toLowerCase()}`);
17251
17440
  const branchName = `feature/${issueId.toLowerCase()}`;
17252
17441
  setReviewStatus(issueId, { testStatus: "testing" });
17253
- const { spawnEphemeralSpecialist } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
17442
+ const { spawnEphemeralSpecialist } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
17254
17443
  const testResult = yield* Effect.promise(() => spawnEphemeralSpecialist(resolved.projectKey, "test-agent", {
17255
17444
  issueId,
17256
17445
  workspace: workspacePath,
@@ -17289,8 +17478,7 @@ const postWorkspaceRequestReviewRoute = HttpRouter.add("POST", "/api/workspaces/
17289
17478
  hint: "A human must click the Review button to continue."
17290
17479
  }, { status: 429 });
17291
17480
  }
17292
- const issuePrefix = issueId.split("-")[0];
17293
- const projectPath = getProjectPath$2(void 0, issuePrefix);
17481
+ const projectPath = getProjectPath$2(void 0, extractPrefix(issueId) ?? issueId.split("-")[0]);
17294
17482
  const issueLower = issueId.toLowerCase();
17295
17483
  const branchName = `feature/${issueLower}`;
17296
17484
  const workspaceInfo = getWorkspaceInfoForIssue(issueId);
@@ -17306,7 +17494,7 @@ const postWorkspaceRequestReviewRoute = HttpRouter.add("POST", "/api/workspaces/
17306
17494
  const reviewNotes = message ? `Agent re-review request (${newCount}/${MAX_AUTO_REQUEUE}): ${message}` : void 0;
17307
17495
  let requestReviewCommits;
17308
17496
  if (!workspaceInfo.isRemote) try {
17309
- const { getWorkspaceGitInfo } = yield* Effect.promise(() => import("./git-utils-BtCRddq3.js"));
17497
+ const { getWorkspaceGitInfo } = yield* Effect.promise(() => import("./git-utils-DQI8EYoj.js"));
17310
17498
  requestReviewCommits = yield* Effect.promise(() => getWorkspaceGitInfo(workspacePath));
17311
17499
  } catch {}
17312
17500
  const reqVerifyOutcome = yield* Effect.promise(() => runVerificationForIssue(issueId, workspacePath, workspaceInfo, "request-review"));
@@ -17332,7 +17520,7 @@ const postWorkspaceRequestReviewRoute = HttpRouter.add("POST", "/api/workspaces/
17332
17520
  });
17333
17521
  console.log(`[request-review] Agent requested re-review for ${issueId} (${newCount}/${MAX_AUTO_REQUEUE})${workspaceInfo.isRemote ? ` (remote: ${workspaceInfo.vmName})` : ""}`);
17334
17522
  try {
17335
- const { spawnEphemeralSpecialist } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
17523
+ const { spawnEphemeralSpecialist } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
17336
17524
  const resolved = resolveProjectFromIssue(issueId);
17337
17525
  if (!resolved) return jsonResponse({
17338
17526
  success: false,
@@ -17361,7 +17549,7 @@ const postWorkspaceRequestReviewRoute = HttpRouter.add("POST", "/api/workspaces/
17361
17549
  });
17362
17550
  } else if (result.error === "specialist_busy") {
17363
17551
  console.log(`[request-review] Review specialist busy for ${issueId} — queuing for deacon dispatch`);
17364
- const { submitToSpecialistQueue } = yield* Effect.promise(async () => import("./specialists-Cny632-T.js"));
17552
+ const { submitToSpecialistQueue } = yield* Effect.promise(async () => import("./specialists-Cp-PgspS.js"));
17365
17553
  submitToSpecialistQueue("review-agent", {
17366
17554
  priority: "high",
17367
17555
  source: "request-review",
@@ -17409,7 +17597,7 @@ const postWorkspaceResetReviewRoute = HttpRouter.add("POST", "/api/workspaces/:i
17409
17597
  error: "Workspace does not exist"
17410
17598
  }, { status: 400 });
17411
17599
  console.log(`[reset-review] Human-initiated pipeline reset for ${issueId}`);
17412
- const { checkSpecialistQueue: cSQ, completeSpecialistTask } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
17600
+ const { checkSpecialistQueue: cSQ, completeSpecialistTask } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
17413
17601
  for (const specialist of [
17414
17602
  "review-agent",
17415
17603
  "test-agent",
@@ -17435,13 +17623,13 @@ const postWorkspaceResetReviewRoute = HttpRouter.add("POST", "/api/workspaces/:i
17435
17623
  verificationCycleCount: 0
17436
17624
  });
17437
17625
  try {
17438
- const { resetPostMergeState } = yield* Effect.promise(() => import("./merge-agent-GLtMEsTu.js"));
17626
+ const { resetPostMergeState } = yield* Effect.promise(() => import("./merge-agent-CGN3TT0a.js"));
17439
17627
  resetPostMergeState(issueId);
17440
17628
  } catch {}
17441
17629
  console.log(`[reset-review] Pipeline state reset for ${issueId} — awaiting agent to request review`);
17442
17630
  const rerun = body?.rerun === true;
17443
17631
  if (rerun) try {
17444
- const { dispatchToSpecialist } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
17632
+ const { dispatchToSpecialist } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
17445
17633
  const resolved = resolveProjectFromIssue(issueId);
17446
17634
  if (resolved) {
17447
17635
  const wsInfo = getWorkspaceInfoForIssue(issueId);
@@ -17476,8 +17664,7 @@ const postWorkspaceResetReviewRoute = HttpRouter.add("POST", "/api/workspaces/:i
17476
17664
  })));
17477
17665
  const postWorkspaceSyncMainRoute = HttpRouter.add("POST", "/api/workspaces/:issueId/sync-main", httpHandler(Effect.gen(function* () {
17478
17666
  const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
17479
- const issuePrefix = issueId.split("-")[0];
17480
- const projectPath = getProjectPath$2(void 0, issuePrefix);
17667
+ const projectPath = getProjectPath$2(void 0, extractPrefix(issueId) ?? issueId.split("-")[0]);
17481
17668
  const issueLower = issueId.toLowerCase();
17482
17669
  const workspaceInfo = getWorkspaceInfoForIssue(issueId);
17483
17670
  if (workspaceInfo.isRemote) return jsonResponse({
@@ -17522,7 +17709,7 @@ async function triggerMerge(issueId) {
17522
17709
  testStatus: reviewStatus?.testStatus || "pending"
17523
17710
  };
17524
17711
  if (reviewStatus.prUrl) try {
17525
- const { isGitHubAppConfigured, reportCommitStatus } = await import("./github-app-XO-LBUGk.js");
17712
+ const { isGitHubAppConfigured, reportCommitStatus } = await import("./github-app-DClWjjHr.js");
17526
17713
  if (isGitHubAppConfigured()) {
17527
17714
  const prMatch = reviewStatus.prUrl.match(/\/pull\/(\d+)/);
17528
17715
  if (prMatch) {
@@ -17558,7 +17745,7 @@ async function triggerMerge(issueId) {
17558
17745
  error: "Already merged",
17559
17746
  mergeStatus: "merged"
17560
17747
  };
17561
- const issuePrefix = issueId.split("-")[0];
17748
+ const issuePrefix = extractPrefix(issueId) ?? issueId.split("-")[0];
17562
17749
  const projectPath = getProjectPath$2(void 0, issuePrefix);
17563
17750
  const issueLower = issueId.toLowerCase();
17564
17751
  const workspaceInfo = getWorkspaceInfoForIssue(issueId);
@@ -17604,7 +17791,7 @@ async function triggerMerge(issueId) {
17604
17791
  readyForMerge: false
17605
17792
  });
17606
17793
  completePendingOperation(issueId, null);
17607
- const { postMergeLifecycle } = await import("./merge-agent-GLtMEsTu.js");
17794
+ const { postMergeLifecycle } = await import("./merge-agent-CGN3TT0a.js");
17608
17795
  await postMergeLifecycle(issueId, projectPath);
17609
17796
  return {
17610
17797
  success: true,
@@ -17678,7 +17865,7 @@ async function triggerMerge(issueId) {
17678
17865
  console.log(`[merge] Push note for ${repo.name}: ${pushErr.message}`);
17679
17866
  }
17680
17867
  try {
17681
- const { spawnMergeAgentForBranches } = await import("./merge-agent-GLtMEsTu.js");
17868
+ const { spawnMergeAgentForBranches } = await import("./merge-agent-CGN3TT0a.js");
17682
17869
  const mergeResult = await spawnMergeAgentForBranches(repoMainPath, branchName, defaultBranch, issueId, { skipDoneReport: true });
17683
17870
  if (mergeResult.success) mergeResults.push({
17684
17871
  repo: repo.name,
@@ -17719,7 +17906,7 @@ async function triggerMerge(issueId) {
17719
17906
  readyForMerge: false
17720
17907
  });
17721
17908
  completePendingOperation(issueId, null);
17722
- const { postMergeLifecycle } = await import("./merge-agent-GLtMEsTu.js");
17909
+ const { postMergeLifecycle } = await import("./merge-agent-CGN3TT0a.js");
17723
17910
  await postMergeLifecycle(issueId, projectPath);
17724
17911
  return {
17725
17912
  success: true,
@@ -17754,7 +17941,7 @@ async function triggerMerge(issueId) {
17754
17941
  };
17755
17942
  }
17756
17943
  const prNumber = prMatch[1];
17757
- const { spawnRebaseAgentForBranch, postMergeLifecycle } = await import("./merge-agent-GLtMEsTu.js");
17944
+ const { spawnRebaseAgentForBranch, postMergeLifecycle } = await import("./merge-agent-CGN3TT0a.js");
17758
17945
  console.log(`[merge] Rebasing ${branchName} onto main for ${issueId}...`);
17759
17946
  const rebaseResult = await spawnRebaseAgentForBranch(workspacePath, branchName, "main", issueId);
17760
17947
  if (!rebaseResult.success) {
@@ -17838,8 +18025,7 @@ const postWorkspaceApproveRoute = HttpRouter.add("POST", "/api/workspaces/:issue
17838
18025
  }
17839
18026
  }
17840
18027
  return yield* Effect.promise(async () => {
17841
- const issuePrefix = issueId.split("-")[0];
17842
- const projectPath = getProjectPath$2(void 0, issuePrefix);
18028
+ const projectPath = getProjectPath$2(void 0, extractPrefix(issueId) ?? issueId.split("-")[0]);
17843
18029
  const issueLower = issueId.toLowerCase();
17844
18030
  const workspacePath = join$1(projectPath, "workspaces", `feature-${issueLower}`);
17845
18031
  const branchName = `feature/${issueLower}`;
@@ -17890,7 +18076,7 @@ const postWorkspaceApproveRoute = HttpRouter.add("POST", "/api/workspaces/:issue
17890
18076
  completePendingOperation(issueId, error);
17891
18077
  return jsonResponse({ error }, { status: 400 });
17892
18078
  }
17893
- const { wakeSpecialist, spawnEphemeralSpecialist: spawnApproveEphemeral } = await import("./specialists-Cny632-T.js");
18079
+ const { wakeSpecialist, spawnEphemeralSpecialist: spawnApproveEphemeral } = await import("./specialists-Cp-PgspS.js");
17894
18080
  const approveProjectKey = resolveProjectFromIssue(issueId)?.projectKey ?? null;
17895
18081
  console.log(`[approve] Starting specialist pipeline for ${issueId}...`);
17896
18082
  const pipelinePrompt = `STRICT REVIEW WORKFLOW for ${issueId}
@@ -17969,7 +18155,7 @@ curl -X POST http://localhost:${PORT}/api/specialists/test-agent/queue -H "Conte
17969
18155
  }
17970
18156
  console.log(`[approve] Step 3/3: Waking merge-agent for ${issueId}...`);
17971
18157
  try {
17972
- const { spawnMergeAgentForBranches } = await import("./merge-agent-GLtMEsTu.js");
18158
+ const { spawnMergeAgentForBranches } = await import("./merge-agent-CGN3TT0a.js");
17973
18159
  const mergeResult = await spawnMergeAgentForBranches(projectPath, branchName, "main", issueId);
17974
18160
  if (mergeResult.success && mergeResult.testsStatus === "PASS") console.log(`merge-agent successfully merged ${issueId}`);
17975
18161
  else if (mergeResult.success && mergeResult.testsStatus === "SKIP") console.log(`merge-agent merged ${issueId} (tests skipped)`);
@@ -18027,7 +18213,7 @@ curl -X POST http://localhost:${PORT}/api/specialists/test-agent/queue -H "Conte
18027
18213
  completePendingOperation(issueId, error);
18028
18214
  return jsonResponse({ error }, { status: 400 });
18029
18215
  }
18030
- const { approve: lifecycleApprove } = await import("./lifecycle-ZTYdrr2O.js");
18216
+ const { approve: lifecycleApprove } = await import("./lifecycle-BcUmtkR4.js");
18031
18217
  const ghResolved = resolveGitHubIssue(issueId);
18032
18218
  const isGitHubIssueFlag = ghResolved.isGitHub;
18033
18219
  const lifecycleResult = await lifecycleApprove({
@@ -18086,9 +18272,8 @@ const getWorkspaceTldrRoute = HttpRouter.add("GET", "/api/workspaces/:issueId/tl
18086
18272
  const postWorkspaceRefreshTokenRoute = HttpRouter.add("POST", "/api/workspaces/:issueId/refresh-token", httpHandler(Effect.gen(function* () {
18087
18273
  const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
18088
18274
  const issueLower = issueId.toLowerCase();
18089
- const issuePrefix = issueId.split("-")[0];
18090
- const workspacePath = join$1(getProjectPath$2(void 0, issuePrefix), "workspaces", `feature-${issueLower}`);
18091
- const { refreshWorkspaceToken, isGitHubAppConfigured } = yield* Effect.promise(() => import("./github-app-XO-LBUGk.js"));
18275
+ const workspacePath = join$1(getProjectPath$2(void 0, extractPrefix(issueId) ?? issueId.split("-")[0]), "workspaces", `feature-${issueLower}`);
18276
+ const { refreshWorkspaceToken, isGitHubAppConfigured } = yield* Effect.promise(() => import("./github-app-DClWjjHr.js"));
18092
18277
  if (!isGitHubAppConfigured()) return jsonResponse({
18093
18278
  success: false,
18094
18279
  error: "GitHub App not configured"
@@ -18140,12 +18325,14 @@ const workspacesRouteLayer = Layer.mergeAll(getWorkspaceRoute, postWorkspacesRou
18140
18325
  * GET /api/specialists/:project/:type/latest-log
18141
18326
  * POST /api/specialists/:project/:type/logs/cleanup
18142
18327
  */
18328
+ init_paths();
18143
18329
  init_projects();
18144
18330
  init_review_status();
18145
18331
  init_agents();
18146
18332
  init_cost();
18147
18333
  init_jsonl_parser();
18148
18334
  init_io();
18335
+ init_issue_id();
18149
18336
  const execAsync$8 = promisify(exec);
18150
18337
  const VALID_SPECIALIST_NAMES = [
18151
18338
  "merge-agent",
@@ -18172,12 +18359,11 @@ function firePostMergeLifecycle(issueId) {
18172
18359
  console.log(`[merge] firePostMergeLifecycle: skipping ${issueId} — already in flight`);
18173
18360
  return;
18174
18361
  }
18175
- const issuePrefix = issueId.split("-")[0];
18176
- const projectPath = getProjectPathForIssue(issuePrefix);
18362
+ const projectPath = getProjectPathForIssue(extractPrefix(issueId) ?? issueId.split("-")[0]);
18177
18363
  _postMergeInFlight.add(issueId);
18178
18364
  (async () => {
18179
18365
  try {
18180
- const { postMergeLifecycle } = await import("./merge-agent-GLtMEsTu.js");
18366
+ const { postMergeLifecycle } = await import("./merge-agent-CGN3TT0a.js");
18181
18367
  await postMergeLifecycle(issueId, projectPath);
18182
18368
  console.log(`[merge] post-merge lifecycle completed for ${issueId}`);
18183
18369
  } catch (err) {
@@ -18193,15 +18379,15 @@ function getProjectPathForIssue(issuePrefix) {
18193
18379
  return join$1(homedir(), "Projects");
18194
18380
  }
18195
18381
  const getSpecialistsRoute = HttpRouter.add("GET", "/api/specialists", httpHandler(Effect.gen(function* () {
18196
- const { getAllSpecialistStatus, getAllProjectSpecialistStatuses } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
18382
+ const { getAllSpecialistStatus, getAllProjectSpecialistStatuses } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18197
18383
  return jsonResponse({
18198
18384
  specialists: yield* Effect.promise(() => getAllSpecialistStatus()),
18199
18385
  projects: yield* Effect.promise(() => getAllProjectSpecialistStatuses())
18200
18386
  });
18201
18387
  })));
18202
18388
  const postSpecialistsResetAllRoute = HttpRouter.add("POST", "/api/specialists/reset-all", httpHandler(Effect.gen(function* () {
18203
- const { getAllSpecialists, clearSessionId, isRunning, getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
18204
- const { clearHook } = yield* Effect.promise(() => import("./hooks-CKhs3N68.js"));
18389
+ const { getAllSpecialists, clearSessionId, isRunning, getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18390
+ const { clearHook } = yield* Effect.promise(() => import("./hooks-CB4T47NC.js"));
18205
18391
  const specialists = getAllSpecialists();
18206
18392
  const results = [];
18207
18393
  for (const specialist of specialists) {
@@ -18292,7 +18478,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
18292
18478
  const updatedStatus = setReviewStatus$1(normalizedIssueId, update);
18293
18479
  yield* Effect.promise(async () => {
18294
18480
  try {
18295
- const { getTmuxSessionName, checkSpecialistQueue, completeSpecialistTask } = await import("./specialists-Cny632-T.js");
18481
+ const { getTmuxSessionName, checkSpecialistQueue, completeSpecialistTask } = await import("./specialists-Cp-PgspS.js");
18296
18482
  saveAgentRuntimeState(getTmuxSessionName(`${specialist}-agent`), {
18297
18483
  state: "idle",
18298
18484
  lastActivity: (/* @__PURE__ */ new Date()).toISOString()
@@ -18313,7 +18499,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
18313
18499
  if (project) {
18314
18500
  const workspacePath = join$1(project.projectPath, "workspaces", `feature-${normalizedIssueId.toLowerCase()}`);
18315
18501
  if (existsSync$1(workspacePath)) {
18316
- const { getWorkspaceGitInfo } = await import("./git-utils-BtCRddq3.js");
18502
+ const { getWorkspaceGitInfo } = await import("./git-utils-DQI8EYoj.js");
18317
18503
  const { HEAD } = await getWorkspaceGitInfo(workspacePath);
18318
18504
  setReviewStatus$1(normalizedIssueId, { reviewedAtCommit: HEAD });
18319
18505
  console.log(`[specialists/done] Snapshotted reviewedAtCommit=${HEAD.substring(0, 8)} for ${normalizedIssueId}`);
@@ -18325,7 +18511,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
18325
18511
  });
18326
18512
  if (specialist === "inspect" && status === "passed") yield* Effect.promise(async () => {
18327
18513
  try {
18328
- const { onInspectComplete } = await import("./inspect-agent-B57kGDUV.js");
18514
+ const { onInspectComplete } = await import("./inspect-agent-7eour7EA.js");
18329
18515
  const beadId = (notes?.match(/[Bb]ead\s+(\S+)/))?.[1] || "unknown";
18330
18516
  const project = resolveProjectFromIssue(normalizedIssueId);
18331
18517
  if (project) {
@@ -18392,13 +18578,13 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
18392
18578
  if (specialist === "merge" && status === "failed" && notes?.toLowerCase().includes("conflict")) yield* Effect.promise(async () => {
18393
18579
  try {
18394
18580
  const workAgentId = `agent-${normalizedIssueId.toLowerCase()}`;
18395
- const { sessionExists } = await import("./tmux-DYGAVJfb.js");
18396
- const { messageAgent } = await import("./agents-BVBVCyat.js");
18581
+ const { sessionExists } = await import("./tmux-BzxdKItf.js");
18582
+ const { messageAgent } = await import("./agents-Dgh2TjSp.js");
18397
18583
  if (sessionExists(workAgentId)) {
18398
18584
  await messageAgent(workAgentId, `MERGE CONFLICT: The merge-agent could not rebase your branch onto main due to conflicts. Please fix this now:\n\n1. git fetch origin main\n2. git rebase origin/main\n3. Resolve any conflicts (git add <file> && git rebase --continue)\n4. git push --force-with-lease\n5. Resubmit: curl -s -X POST http://localhost:3011/api/workspaces/${normalizedIssueId}/request-review -H "Content-Type: application/json" -d "{}"\n\nConflict details: ${notes}`);
18399
18585
  console.log(`[specialists/done] Sent rebase instructions to ${workAgentId}`);
18400
18586
  } else try {
18401
- const { resumeAgent } = await import("./agents-BVBVCyat.js");
18587
+ const { resumeAgent } = await import("./agents-Dgh2TjSp.js");
18402
18588
  const result = await resumeAgent(workAgentId, `MERGE CONFLICT: Your branch has conflicts with main. Run: git fetch origin main && git rebase origin/main, resolve conflicts, push with --force-with-lease, then resubmit for review.`);
18403
18589
  if (result.success) console.log(`[specialists/done] Resumed ${workAgentId} with rebase instructions`);
18404
18590
  else console.log(`[specialists/done] Could not resume ${workAgentId}: ${result.error}`);
@@ -18412,8 +18598,8 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
18412
18598
  if (specialist === "review" && status === "failed" && notes) yield* Effect.promise(async () => {
18413
18599
  try {
18414
18600
  const workAgentId = `agent-${normalizedIssueId.toLowerCase()}`;
18415
- const { sessionExists } = await import("./tmux-DYGAVJfb.js");
18416
- const { messageAgent } = await import("./agents-BVBVCyat.js");
18601
+ const { sessionExists } = await import("./tmux-BzxdKItf.js");
18602
+ const { messageAgent } = await import("./agents-Dgh2TjSp.js");
18417
18603
  if (sessionExists(workAgentId)) {
18418
18604
  await messageAgent(workAgentId, `REVIEW FEEDBACK: The review specialist found issues that must be fixed:\n\n${notes}\n\nPlease address all issues, push your changes, then resubmit: curl -s -X POST http://localhost:3011/api/workspaces/${normalizedIssueId}/request-review -H "Content-Type: application/json" -d "{}"`);
18419
18605
  console.log(`[specialists/done] Sent review feedback to ${workAgentId}`);
@@ -18449,7 +18635,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
18449
18635
  });
18450
18636
  })));
18451
18637
  const postSpecialistsLogsCleanupAllRoute = HttpRouter.add("POST", "/api/specialists/logs/cleanup-all", httpHandler(Effect.gen(function* () {
18452
- const { cleanupAllLogs } = yield* Effect.promise(() => import("./specialist-logs-BhmDpFIq.js"));
18638
+ const { cleanupAllLogs } = yield* Effect.promise(() => import("./specialist-logs-CIw4qfTy.js"));
18453
18639
  const results = cleanupAllLogs();
18454
18640
  return jsonResponse({
18455
18641
  success: true,
@@ -18459,7 +18645,7 @@ const postSpecialistsLogsCleanupAllRoute = HttpRouter.add("POST", "/api/speciali
18459
18645
  });
18460
18646
  })));
18461
18647
  const getSpecialistQueuesRoute = HttpRouter.add("GET", "/api/specialists/queues", httpHandler(Effect.gen(function* () {
18462
- const { getAllSpecialists, checkSpecialistQueue } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
18648
+ const { getAllSpecialists, checkSpecialistQueue } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18463
18649
  return jsonResponse({ queues: getAllSpecialists().map((specialist) => {
18464
18650
  const queue = checkSpecialistQueue(specialist.name);
18465
18651
  return {
@@ -18472,14 +18658,14 @@ const getSpecialistQueuesRoute = HttpRouter.add("GET", "/api/specialists/queues"
18472
18658
  }) });
18473
18659
  })));
18474
18660
  const getSpecialistsProjectsRoute = HttpRouter.add("GET", "/api/specialists/projects", httpHandler(Effect.gen(function* () {
18475
- const { getAllProjectSpecialistStatuses } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
18661
+ const { getAllProjectSpecialistStatuses } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18476
18662
  return jsonResponse(yield* Effect.promise(() => getAllProjectSpecialistStatuses()));
18477
18663
  })));
18478
18664
  const postSpecialistWakeRoute = HttpRouter.add("POST", "/api/specialists/:name/wake", httpHandler(Effect.gen(function* () {
18479
18665
  const name = (yield* HttpRouter.params)["name"];
18480
18666
  const { sessionId } = yield* readJsonBody$6;
18481
18667
  const eventStore = yield* EventStoreService;
18482
- const { getTmuxSessionName, getSessionId, recordWake, isRunning } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
18668
+ const { getTmuxSessionName, getSessionId, recordWake, isRunning } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18483
18669
  if (yield* Effect.promise(() => isRunning(name))) return jsonResponse({ error: `Specialist ${name} is already running` }, { status: 400 });
18484
18670
  const existingSessionId = getSessionId(name);
18485
18671
  const tmuxSession = getTmuxSessionName(name);
@@ -18487,7 +18673,7 @@ const postSpecialistWakeRoute = HttpRouter.add("POST", "/api/specialists/:name/w
18487
18673
  const useSessionId = sessionId || existingSessionId;
18488
18674
  let specModel = "claude-sonnet-4-6";
18489
18675
  try {
18490
- const { getModelId } = yield* Effect.promise(() => import("./work-type-router-Com2amST.js"));
18676
+ const { getModelId } = yield* Effect.promise(() => import("./work-type-router-Di5gCQwh.js"));
18491
18677
  specModel = getModelId(`specialist-${name}`);
18492
18678
  } catch {}
18493
18679
  const specCmd = getAgentCommand(specModel);
@@ -18515,7 +18701,7 @@ const postSpecialistWakeRoute = HttpRouter.add("POST", "/api/specialists/:name/w
18515
18701
  const postSpecialistResetRoute = HttpRouter.add("POST", "/api/specialists/:name/reset", httpHandler(Effect.gen(function* () {
18516
18702
  const name = (yield* HttpRouter.params)["name"];
18517
18703
  const { reinitialize = false } = yield* readJsonBody$6;
18518
- const { clearSessionId, isRunning, getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
18704
+ const { clearSessionId, isRunning, getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18519
18705
  if (yield* Effect.promise(() => isRunning(name))) return jsonResponse({ error: `Specialist ${name} is currently running. Stop it first (tmux kill-session -t ${getTmuxSessionName(name)})` }, { status: 400 });
18520
18706
  const wasDeleted = clearSessionId(name);
18521
18707
  if (reinitialize) {}
@@ -18527,7 +18713,7 @@ const postSpecialistResetRoute = HttpRouter.add("POST", "/api/specialists/:name/
18527
18713
  })));
18528
18714
  const postSpecialistInitRoute = HttpRouter.add("POST", "/api/specialists/:name/init", httpHandler(Effect.gen(function* () {
18529
18715
  const name = (yield* HttpRouter.params)["name"];
18530
- const { initializeSpecialist } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
18716
+ const { initializeSpecialist } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18531
18717
  const result = yield* Effect.promise(() => initializeSpecialist(name));
18532
18718
  if (!result.success) return jsonResponse({ error: result.message }, { status: 400 });
18533
18719
  return jsonResponse({
@@ -18566,7 +18752,7 @@ const postSpecialistReportStatusRoute = HttpRouter.add("POST", "/api/specialists
18566
18752
  "blocked",
18567
18753
  "failed"
18568
18754
  ].includes(status)) {
18569
- const { getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
18755
+ const { getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18570
18756
  saveAgentRuntimeState(getTmuxSessionName(name), {
18571
18757
  state: "idle",
18572
18758
  lastActivity: (/* @__PURE__ */ new Date()).toISOString()
@@ -18593,7 +18779,7 @@ const postSpecialistReportStatusRoute = HttpRouter.add("POST", "/api/specialists
18593
18779
  })));
18594
18780
  const getSpecialistCostRoute = HttpRouter.add("GET", "/api/specialists/:name/cost", httpHandler(Effect.gen(function* () {
18595
18781
  const name = (yield* HttpRouter.params)["name"];
18596
- const { getSessionId } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
18782
+ const { getSessionId } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18597
18783
  const sessionId = getSessionId(name);
18598
18784
  if (!sessionId) return jsonResponse({
18599
18785
  cost: 0,
@@ -18601,7 +18787,7 @@ const getSpecialistCostRoute = HttpRouter.add("GET", "/api/specialists/:name/cos
18601
18787
  outputTokens: 0
18602
18788
  });
18603
18789
  const homeDir = process.env.HOME || homedir();
18604
- const sessionsIndexPath = join$1(join$1(join$1(homeDir, ".claude", "projects"), `-${homeDir.replace(/^\//, "").replace(/\//g, "-")}`), "sessions-index.json");
18790
+ const sessionsIndexPath = join$1(join$1(join$1(homeDir, ".claude", "projects"), encodeClaudeProjectDir(homeDir)), "sessions-index.json");
18605
18791
  let cost = 0;
18606
18792
  let inputTokens = 0;
18607
18793
  let outputTokens = 0;
@@ -18648,7 +18834,7 @@ const getSpecialistCostRoute = HttpRouter.add("GET", "/api/specialists/:name/cos
18648
18834
  const getSpecialistQueueRoute = HttpRouter.add("GET", "/api/specialists/:name/queue", httpHandler(Effect.gen(function* () {
18649
18835
  const name = (yield* HttpRouter.params)["name"];
18650
18836
  if (!VALID_SPECIALIST_NAMES.includes(name)) return jsonResponse({ error: `Invalid specialist name: ${name}` }, { status: 400 });
18651
- const { checkSpecialistQueue } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
18837
+ const { checkSpecialistQueue } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18652
18838
  const queue = checkSpecialistQueue(name);
18653
18839
  return jsonResponse({
18654
18840
  specialistName: name,
@@ -18663,7 +18849,7 @@ const postSpecialistQueueRoute = HttpRouter.add("POST", "/api/specialists/:name/
18663
18849
  const { issueId, workspace, branch, customPrompt, priority = "normal" } = yield* readJsonBody$6;
18664
18850
  if (!VALID_SPECIALIST_NAMES.includes(name)) return jsonResponse({ error: `Invalid specialist name: ${name}` }, { status: 400 });
18665
18851
  if (!issueId) return jsonResponse({ error: "issueId is required" }, { status: 400 });
18666
- const { spawnEphemeralSpecialist, submitToSpecialistQueue } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
18852
+ const { spawnEphemeralSpecialist, submitToSpecialistQueue } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18667
18853
  const resolved = resolveProjectFromIssue(issueId);
18668
18854
  if (!resolved) return jsonResponse({ error: `No project configured for ${issueId}. Add it to projects.yaml.` }, { status: 400 });
18669
18855
  const result = yield* Effect.promise(() => spawnEphemeralSpecialist(resolved.projectKey, name, {
@@ -18697,7 +18883,7 @@ const deleteSpecialistQueueItemRoute = HttpRouter.add("DELETE", "/api/specialist
18697
18883
  const name = params["name"];
18698
18884
  const itemId = params["itemId"];
18699
18885
  if (!VALID_SPECIALIST_NAMES.includes(name)) return jsonResponse({ error: `Invalid specialist name: ${name}` }, { status: 400 });
18700
- const { completeSpecialistTask } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
18886
+ const { completeSpecialistTask } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18701
18887
  if (!completeSpecialistTask(name, itemId)) return jsonResponse({ error: `Item ${itemId} not found in queue for ${name}` }, { status: 404 });
18702
18888
  return jsonResponse({
18703
18889
  success: true,
@@ -18709,7 +18895,7 @@ const putSpecialistQueueReorderRoute = HttpRouter.add("PUT", "/api/specialists/:
18709
18895
  const { itemIds } = yield* readJsonBody$6;
18710
18896
  if (!Array.isArray(itemIds)) return jsonResponse({ error: "itemIds must be an array" }, { status: 400 });
18711
18897
  if (!VALID_SPECIALIST_NAMES.includes(name)) return jsonResponse({ error: `Invalid specialist name: ${name}` }, { status: 400 });
18712
- const { reorderHookItems } = yield* Effect.promise(() => import("./hooks-CKhs3N68.js"));
18898
+ const { reorderHookItems } = yield* Effect.promise(() => import("./hooks-CB4T47NC.js"));
18713
18899
  if (!reorderHookItems(name, itemIds)) return jsonResponse({ error: "Failed to reorder queue. Check that all item IDs are valid." }, { status: 400 });
18714
18900
  return jsonResponse({
18715
18901
  success: true,
@@ -18724,7 +18910,7 @@ const postSpecialistAutoCompleteRoute = HttpRouter.add("POST", "/api/specialists
18724
18910
  if (!issueId || !status) return jsonResponse({ error: "issueId and status required" }, { status: 400 });
18725
18911
  console.log(`[specialists] Auto-detected completion for ${name}: ${issueId} -> ${status}`);
18726
18912
  if (!VALID_SPECIALIST_NAMES.includes(name)) return jsonResponse({ error: `Invalid specialist name: ${name}` }, { status: 400 });
18727
- const { getTmuxSessionName, completeSpecialistTask, wakeSpecialistWithTask, checkSpecialistQueue, submitToSpecialistQueue } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
18913
+ const { getTmuxSessionName, completeSpecialistTask, wakeSpecialistWithTask, checkSpecialistQueue, submitToSpecialistQueue } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18728
18914
  saveAgentRuntimeState(getTmuxSessionName(name), {
18729
18915
  state: "idle",
18730
18916
  lastActivity: (/* @__PURE__ */ new Date()).toISOString(),
@@ -18824,7 +19010,7 @@ const getProjectSpecialistStatusRoute = HttpRouter.add("GET", "/api/specialists/
18824
19010
  const project = params["project"];
18825
19011
  const type = params["type"];
18826
19012
  if (!validateSpecialistType(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
18827
- const { getSpecialistStatus } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
19013
+ const { getSpecialistStatus } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18828
19014
  return jsonResponse(yield* Effect.promise(() => getSpecialistStatus(type, project)));
18829
19015
  })));
18830
19016
  const postProjectSpecialistKillRoute = HttpRouter.add("POST", "/api/specialists/:project/:type/kill", httpHandler(Effect.gen(function* () {
@@ -18832,7 +19018,7 @@ const postProjectSpecialistKillRoute = HttpRouter.add("POST", "/api/specialists/
18832
19018
  const project = params["project"];
18833
19019
  const type = params["type"];
18834
19020
  if (!validateSpecialistType(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
18835
- const { getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
19021
+ const { getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18836
19022
  const tmuxSession = getTmuxSessionName(type, project);
18837
19023
  yield* Effect.promise(() => execAsync$8(`tmux kill-session -t "${tmuxSession}"`).catch(() => {}));
18838
19024
  saveAgentRuntimeState(tmuxSession, {
@@ -18847,7 +19033,7 @@ const postProjectSpecialistKillRoute = HttpRouter.add("POST", "/api/specialists/
18847
19033
  const getProjectSpecialistQueueRoute = HttpRouter.add("GET", "/api/specialists/:project/:type/queue", httpHandler(Effect.gen(function* () {
18848
19034
  const type = (yield* HttpRouter.params)["type"];
18849
19035
  if (!validateSpecialistType(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
18850
- const { checkSpecialistQueue } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
19036
+ const { checkSpecialistQueue } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18851
19037
  return jsonResponse(checkSpecialistQueue(type));
18852
19038
  })));
18853
19039
  const postProjectSpecialistSpawnRoute = HttpRouter.add("POST", "/api/specialists/:project/:type/spawn", httpHandler(Effect.gen(function* () {
@@ -18857,7 +19043,7 @@ const postProjectSpecialistSpawnRoute = HttpRouter.add("POST", "/api/specialists
18857
19043
  const { issueId, branch, workspace, prUrl, context } = yield* readJsonBody$6;
18858
19044
  if (!issueId) return jsonResponse({ error: "issueId is required" }, { status: 400 });
18859
19045
  if (!validateSpecialistType(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
18860
- const { spawnEphemeralSpecialist } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
19046
+ const { spawnEphemeralSpecialist } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18861
19047
  const result = yield* Effect.promise(() => spawnEphemeralSpecialist(project, type, {
18862
19048
  issueId,
18863
19049
  branch,
@@ -18883,7 +19069,7 @@ const getProjectSpecialistRunsRoute = HttpRouter.add("GET", "/api/specialists/:p
18883
19069
  if (limitParam) limit = parseInt(limitParam, 10);
18884
19070
  if (offsetParam) offset = parseInt(offsetParam, 10);
18885
19071
  }
18886
- const { listRunLogs } = yield* Effect.promise(() => import("./specialist-logs-BhmDpFIq.js"));
19072
+ const { listRunLogs } = yield* Effect.promise(() => import("./specialist-logs-CIw4qfTy.js"));
18887
19073
  return jsonResponse(listRunLogs(project, type, {
18888
19074
  limit,
18889
19075
  offset
@@ -18894,7 +19080,7 @@ const getProjectSpecialistRunStreamRoute = HttpRouter.add("GET", "/api/specialis
18894
19080
  const project = params["project"];
18895
19081
  const type = params["type"];
18896
19082
  const runId = params["runId"];
18897
- const { getRunLogPath, isRunLogActive } = yield* Effect.promise(() => import("./specialist-logs-BhmDpFIq.js"));
19083
+ const { getRunLogPath, isRunLogActive } = yield* Effect.promise(() => import("./specialist-logs-CIw4qfTy.js"));
18898
19084
  const logPath = getRunLogPath(project, type, runId);
18899
19085
  if (!existsSync$1(logPath)) return jsonResponse({ error: "Run log not found" }, { status: 404 });
18900
19086
  const encoder = new TextEncoder();
@@ -18953,7 +19139,7 @@ const getProjectSpecialistRunRoute = HttpRouter.add("GET", "/api/specialists/:pr
18953
19139
  const project = params["project"];
18954
19140
  const type = params["type"];
18955
19141
  const runId = params["runId"];
18956
- const { getRunLog, parseLogMetadata } = yield* Effect.promise(() => import("./specialist-logs-BhmDpFIq.js"));
19142
+ const { getRunLog, parseLogMetadata } = yield* Effect.promise(() => import("./specialist-logs-CIw4qfTy.js"));
18957
19143
  const content = getRunLog(project, type, runId);
18958
19144
  if (!content) return jsonResponse({ error: "Run log not found" }, { status: 404 });
18959
19145
  return jsonResponse({
@@ -18967,7 +19153,7 @@ const postProjectSpecialistRunTerminateRoute = HttpRouter.add("POST", "/api/spec
18967
19153
  const project = params["project"];
18968
19154
  const type = params["type"];
18969
19155
  if (!validateSpecialistType(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
18970
- const { terminateSpecialist } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
19156
+ const { terminateSpecialist } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18971
19157
  yield* Effect.promise(() => terminateSpecialist(project, type));
18972
19158
  return jsonResponse({
18973
19159
  success: true,
@@ -18979,7 +19165,7 @@ const postProjectSpecialistGracePauseRoute = HttpRouter.add("POST", "/api/specia
18979
19165
  const project = params["project"];
18980
19166
  const type = params["type"];
18981
19167
  if (!validateSpecialistType(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
18982
- const { pauseGracePeriod } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
19168
+ const { pauseGracePeriod } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18983
19169
  if (pauseGracePeriod(project, type)) return jsonResponse({
18984
19170
  success: true,
18985
19171
  message: "Grace period paused"
@@ -18991,7 +19177,7 @@ const postProjectSpecialistGraceResumeRoute = HttpRouter.add("POST", "/api/speci
18991
19177
  const project = params["project"];
18992
19178
  const type = params["type"];
18993
19179
  if (!validateSpecialistType(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
18994
- const { resumeGracePeriod } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
19180
+ const { resumeGracePeriod } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
18995
19181
  if (resumeGracePeriod(project, type)) return jsonResponse({
18996
19182
  success: true,
18997
19183
  message: "Grace period resumed"
@@ -19003,7 +19189,7 @@ const postProjectSpecialistGraceExitRoute = HttpRouter.add("POST", "/api/special
19003
19189
  const project = params["project"];
19004
19190
  const type = params["type"];
19005
19191
  if (!validateSpecialistType(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
19006
- const { exitGracePeriod } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
19192
+ const { exitGracePeriod } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
19007
19193
  exitGracePeriod(project, type);
19008
19194
  return jsonResponse({
19009
19195
  success: true,
@@ -19015,7 +19201,7 @@ const getProjectSpecialistGraceRoute = HttpRouter.add("GET", "/api/specialists/:
19015
19201
  const project = params["project"];
19016
19202
  const type = params["type"];
19017
19203
  if (!validateSpecialistType(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
19018
- const { getGracePeriodState } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
19204
+ const { getGracePeriodState } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
19019
19205
  const state = getGracePeriodState(project, type);
19020
19206
  if (state) return jsonResponse(state);
19021
19207
  else return jsonResponse({ error: "No active grace period" }, { status: 404 });
@@ -19024,7 +19210,7 @@ const getProjectSpecialistContextRoute = HttpRouter.add("GET", "/api/specialists
19024
19210
  const params = yield* HttpRouter.params;
19025
19211
  const project = params["project"];
19026
19212
  const type = params["type"];
19027
- const { loadContextDigest } = yield* Effect.promise(() => import("./specialist-context-ColzlmGE.js"));
19213
+ const { loadContextDigest } = yield* Effect.promise(() => import("./specialist-context-DGukHSn8.js"));
19028
19214
  const digest = loadContextDigest(project, type);
19029
19215
  if (digest) return jsonResponse({ digest });
19030
19216
  else return jsonResponse({ error: "No context digest found" }, { status: 404 });
@@ -19033,7 +19219,7 @@ const postProjectSpecialistContextRegenerateRoute = HttpRouter.add("POST", "/api
19033
19219
  const params = yield* HttpRouter.params;
19034
19220
  const project = params["project"];
19035
19221
  const type = params["type"];
19036
- const { regenerateContextDigest } = yield* Effect.promise(() => import("./specialist-context-ColzlmGE.js"));
19222
+ const { regenerateContextDigest } = yield* Effect.promise(() => import("./specialist-context-DGukHSn8.js"));
19037
19223
  const digest = yield* Effect.promise(() => regenerateContextDigest(project, type));
19038
19224
  if (digest) return jsonResponse({
19039
19225
  digest,
@@ -19052,7 +19238,7 @@ const postProjectSpecialistCompleteRoute = HttpRouter.add("POST", "/api/speciali
19052
19238
  "blocked"
19053
19239
  ].includes(status)) return jsonResponse({ error: "Valid status (passed/failed/blocked) is required" }, { status: 400 });
19054
19240
  if (!validateSpecialistType(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
19055
- const { signalSpecialistCompletion } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
19241
+ const { signalSpecialistCompletion } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
19056
19242
  signalSpecialistCompletion(project, type, {
19057
19243
  status,
19058
19244
  notes
@@ -19086,8 +19272,8 @@ const postProjectSpecialistLogsCleanupRoute = HttpRouter.add("POST", "/api/speci
19086
19272
  const params = yield* HttpRouter.params;
19087
19273
  const project = params["project"];
19088
19274
  const type = params["type"];
19089
- const { cleanupOldLogs } = yield* Effect.promise(() => import("./specialist-logs-BhmDpFIq.js"));
19090
- const { getSpecialistRetention } = yield* Effect.promise(() => import("./projects-DyT3vSy-.js"));
19275
+ const { cleanupOldLogs } = yield* Effect.promise(() => import("./specialist-logs-CIw4qfTy.js"));
19276
+ const { getSpecialistRetention } = yield* Effect.promise(() => import("./projects-C5ozxjwP.js"));
19091
19277
  const deleted = cleanupOldLogs(project, type, getSpecialistRetention(project));
19092
19278
  return jsonResponse({
19093
19279
  success: true,
@@ -19099,7 +19285,7 @@ const postProjectSpecialistResetSessionRoute = HttpRouter.add("POST", "/api/spec
19099
19285
  const params = yield* HttpRouter.params;
19100
19286
  const projectKey = params["project"] ?? "";
19101
19287
  const name = params["name"] ?? "";
19102
- const { bumpSessionGeneration } = yield* Effect.promise(() => import("./specialists-Cny632-T.js"));
19288
+ const { bumpSessionGeneration } = yield* Effect.promise(() => import("./specialists-Cp-PgspS.js"));
19103
19289
  const newGen = bumpSessionGeneration(name, projectKey);
19104
19290
  const tmuxSession = `specialist-${projectKey}-${name}`;
19105
19291
  try {
@@ -20050,6 +20236,7 @@ function getOpenRouterFavorites() {
20050
20236
  init_agents();
20051
20237
  init_paths();
20052
20238
  init_projects();
20239
+ init_issue_id();
20053
20240
  init_specialists();
20054
20241
  init_tracker_config();
20055
20242
  const execAsync$5 = promisify(exec);
@@ -20100,7 +20287,7 @@ const getMissionControlActivityRoute = HttpRouter.add("GET", "/api/command-deck/
20100
20287
  })));
20101
20288
  async function fetchActivityData(issueId) {
20102
20289
  const issueLower = issueId.toLowerCase();
20103
- const issuePrefix = issueId.split("-")[0];
20290
+ const issuePrefix = extractPrefix(issueId) ?? issueId.split("-")[0];
20104
20291
  const sections = [];
20105
20292
  const agentId = `agent-${issueLower}`;
20106
20293
  const planningAgentId = `planning-${issueLower}`;
@@ -20293,8 +20480,7 @@ const getMissionControlPlanningRoute = HttpRouter.add("GET", "/api/command-deck/
20293
20480
  })));
20294
20481
  async function fetchPlanningData(issueId) {
20295
20482
  const issueLower = issueId.toLowerCase();
20296
- const issuePrefix = issueId.split("-")[0];
20297
- const projectPath = getProjectPath$1(issuePrefix);
20483
+ const projectPath = getProjectPath$1(extractPrefix(issueId) ?? issueId.split("-")[0]);
20298
20484
  const planningDir = join$1(join$1(projectPath, "workspaces", `feature-${issueLower}`), ".planning");
20299
20485
  const result = {
20300
20486
  transcripts: [],
@@ -20377,8 +20563,7 @@ const postMissionControlStatusReviewRoute = HttpRouter.add("POST", "/api/command
20377
20563
  })));
20378
20564
  async function generateStatusReview(issueId) {
20379
20565
  const issueLower = issueId.toLowerCase();
20380
- const issuePrefix = issueId.split("-")[0];
20381
- const workspacePath = join$1(getProjectPath$1(issuePrefix), "workspaces", `feature-${issueLower}`);
20566
+ const workspacePath = join$1(getProjectPath$1(extractPrefix(issueId) ?? issueId.split("-")[0]), "workspaces", `feature-${issueLower}`);
20382
20567
  const planningDir = join$1(workspacePath, ".planning");
20383
20568
  if (!await pathExists(planningDir)) return {
20384
20569
  type: "err",
@@ -20526,7 +20711,7 @@ Be specific: reference actual file names, function names, requirement text, disc
20526
20711
  const { command: cliCmd, args: cliArgs } = getAgentCommand(statusModelId);
20527
20712
  const modelFlag = cliArgs.length > 0 ? ` ${cliArgs.join(" ")}` : "";
20528
20713
  const promptFile = join$1(planningDir, ".status-review-prompt.tmp");
20529
- const { getProviderForModel, getProviderEnv } = await import("./providers-DVQnDekG.js");
20714
+ const { getProviderForModel, getProviderEnv } = await import("./providers-csVZVPkE.js");
20530
20715
  const { loadConfig: loadYamlConfig } = await import("./config-yaml-DkresmrS.js");
20531
20716
  let providerEnvStr = "";
20532
20717
  const statusProvider = getProviderForModel(statusModelId);
@@ -20599,13 +20784,13 @@ const postMissionControlUploadRoute = HttpRouter.add("POST", "/api/command-deck/
20599
20784
  const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
20600
20785
  const { type, filename, content } = yield* readJsonBody$4;
20601
20786
  const issueLower = issueId.toLowerCase();
20602
- const issuePrefix = issueId.split("-")[0];
20787
+ const issuePrefix = extractPrefix(issueId) ?? issueId.split("-")[0];
20603
20788
  if (!type || !filename || !content) return jsonResponse({ error: "type, filename, and content are required" }, { status: 400 });
20604
20789
  if (!["transcript", "note"].includes(type)) return jsonResponse({ error: "type must be transcript or note" }, { status: 400 });
20605
20790
  let safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "-");
20606
20791
  let processedContent = content;
20607
20792
  if (safeName.endsWith(".vtt")) {
20608
- const { vttToMarkdown } = yield* Effect.promise(() => import("./vtt-parser-BAXygRf0.js"));
20793
+ const { vttToMarkdown } = yield* Effect.promise(() => import("./vtt-parser-99vFekRQ.js"));
20609
20794
  processedContent = vttToMarkdown(content);
20610
20795
  safeName = safeName.replace(/\.vtt$/, ".md");
20611
20796
  }
@@ -20629,7 +20814,7 @@ const postMissionControlSyncDiscussionsRoute = HttpRouter.add("POST", "/api/comm
20629
20814
  const linear = yield* LinearClient$1;
20630
20815
  const { tracker } = body;
20631
20816
  const issueLower = issueId.toLowerCase();
20632
- const issuePrefix = issueId.split("-")[0];
20817
+ const issuePrefix = extractPrefix(issueId) ?? issueId.split("-")[0];
20633
20818
  if (!tracker || ![
20634
20819
  "github",
20635
20820
  "linear",
@@ -20738,8 +20923,7 @@ const postMissionControlPlanningInitRoute = HttpRouter.add("POST", "/api/command
20738
20923
  const eventStore = yield* EventStoreService;
20739
20924
  const { shadow } = body;
20740
20925
  const issueLower = issueId.toLowerCase();
20741
- const issuePrefix = issueId.split("-")[0];
20742
- const planningDir = join$1(join$1(getProjectPath$1(issuePrefix), "workspaces", `feature-${issueLower}`), ".planning");
20926
+ const planningDir = join$1(join$1(getProjectPath$1(extractPrefix(issueId) ?? issueId.split("-")[0]), "workspaces", `feature-${issueLower}`), ".planning");
20743
20927
  yield* Effect.tryPromise({
20744
20928
  try: async () => {
20745
20929
  await Promise.all([
@@ -21227,12 +21411,7 @@ const MODEL_API_IDS = {
21227
21411
  "kimi-k2": { apiModel: "moonshot-v1-8k" },
21228
21412
  "kimi-k2.5": { apiModel: "moonshot-v1-32k" },
21229
21413
  "kimi-k2-turbo": { apiModel: "moonshot-v1-8k" },
21230
- "glm-4.7": { apiModel: "glm-4" },
21231
- "glm-4.7-flash": { apiModel: "glm-4-flash" },
21232
- "glm-4-plus": { apiModel: "glm-4" },
21233
- "glm-4-air": { apiModel: "glm-4-air" },
21234
- "glm-4-flash": { apiModel: "glm-4-flash" },
21235
- "glm-4-long": { apiModel: "glm-4-long" }
21414
+ "glm-4.7-flash": { apiModel: "glm-4.7-flash" }
21236
21415
  };
21237
21416
  const getSettingsRoute = HttpRouter.add("GET", "/api/settings", httpHandler(Effect.try({
21238
21417
  try: () => jsonResponse(loadSettingsApi()),
@@ -21349,7 +21528,7 @@ const postTestApiKeyRoute = HttpRouter.add("POST", "/api/settings/test-api-key",
21349
21528
  break;
21350
21529
  }
21351
21530
  case "zai": {
21352
- const apiModel = model ? MODEL_API_IDS[model]?.apiModel || "glm-4-flash" : "glm-4-flash";
21531
+ const apiModel = model ? MODEL_API_IDS[model]?.apiModel || "glm-4.7-flash" : "glm-4.7-flash";
21353
21532
  try {
21354
21533
  const resp = await fetch("https://open.bigmodel.cn/api/paas/v4/chat/completions", {
21355
21534
  method: "POST",
@@ -21476,7 +21655,7 @@ const postValidateApiKeyRoute = HttpRouter.add("POST", "/api/settings/validate-a
21476
21655
  if (resp.ok) {
21477
21656
  const data = await resp.json();
21478
21657
  valid = true;
21479
- models = data.data?.map((m) => m.id) || ["glm-4.7", "glm-4.7-flash"];
21658
+ models = data.data?.map((m) => m.id) || ["glm-4.7-flash"];
21480
21659
  } else if (resp.status === 401) error = "Invalid API key";
21481
21660
  else if (resp.status === 429) error = "Rate limit exceeded";
21482
21661
  else error = `HTTP error: ${resp.status}`;
@@ -21923,7 +22102,6 @@ async function stopConvoy(convoyId) {
21923
22102
  * POST /api/convoys/:id/stop
21924
22103
  * GET /api/convoys/:id/output
21925
22104
  */
21926
- const activities = [];
21927
22105
  const getMetricsSummaryRoute = HttpRouter.add("GET", "/api/metrics/summary", httpHandler(Effect.try({
21928
22106
  try: () => {
21929
22107
  const status = getCloisterService().getStatus();
@@ -21985,13 +22163,33 @@ const getMetricsStuckRoute = HttpRouter.add("GET", "/api/metrics/stuck", httpHan
21985
22163
  },
21986
22164
  catch: (err) => new Error(err instanceof Error ? err.message : String(err))
21987
22165
  })));
21988
- const getActivityRoute = HttpRouter.add("GET", "/api/activity", Effect.succeed(jsonResponse(activities)));
21989
- const getActivityByIdRoute = HttpRouter.add("GET", "/api/activity/:id", Effect.gen(function* () {
21990
- const id = (yield* HttpRouter.params)["id"] ?? "";
21991
- const activity = activities.find((a) => a.id === id);
22166
+ const getActivityRoute = HttpRouter.add("GET", "/api/activity", httpHandler(Effect.gen(function* () {
22167
+ return jsonResponse((yield* (yield* EventStoreService).queryByType("activity.entry", 100)).map((e) => ({
22168
+ id: e.payload["id"],
22169
+ timestamp: e.timestamp,
22170
+ source: e.payload["source"],
22171
+ level: e.payload["level"],
22172
+ message: e.payload["message"],
22173
+ details: e.payload["details"],
22174
+ issueId: e.payload["issueId"]
22175
+ })));
22176
+ })));
22177
+ const getActivityByIdRoute = HttpRouter.add("GET", "/api/activity/:id", httpHandler(Effect.gen(function* () {
22178
+ const params = yield* HttpRouter.params;
22179
+ const eventStore = yield* EventStoreService;
22180
+ const id = params["id"] ?? "";
22181
+ const activity = (yield* eventStore.queryByType("activity.entry", 1e3)).find((e) => e.payload["id"] === id);
21992
22182
  if (!activity) return jsonResponse({ error: "Activity not found" }, { status: 404 });
21993
- return jsonResponse(activity);
21994
- }));
22183
+ return jsonResponse({
22184
+ id: activity.payload["id"],
22185
+ timestamp: activity.timestamp,
22186
+ source: activity.payload["source"],
22187
+ level: activity.payload["level"],
22188
+ message: activity.payload["message"],
22189
+ details: activity.payload["details"],
22190
+ issueId: activity.payload["issueId"]
22191
+ });
22192
+ })));
21995
22193
  const getConvoysRoute = HttpRouter.add("GET", "/api/convoys", httpHandler(Effect.try({
21996
22194
  try: () => jsonResponse({ convoys: listConvoys() }),
21997
22195
  catch: (err) => new Error(err instanceof Error ? err.message : String(err))
@@ -22160,33 +22358,39 @@ async function determineHealthStatusAsync(agentId, stateFile) {
22160
22358
  * GET /api/metrics/tasks
22161
22359
  * POST /api/shadow/:issueId/monitor
22162
22360
  * POST /api/shadow/:issueId/observe
22361
+ * POST /api/dev/rebuild
22163
22362
  */
22164
22363
  init_tmux();
22165
22364
  init_projects();
22166
22365
  init_tracker_config();
22167
22366
  init_config_yaml();
22168
22367
  init_config();
22368
+ init_issue_id();
22169
22369
  const execAsync$2 = promisify(exec);
22170
22370
  function readPackageVersion() {
22171
- const base = dirname$1(fileURLToPath(import.meta.url));
22172
- for (const levels of [[
22173
- "..",
22174
- "..",
22175
- ".."
22176
- ], [
22177
- "..",
22178
- "..",
22179
- "..",
22180
- ".."
22181
- ]]) {
22182
- const candidate = join$1(base, ...levels, "package.json");
22371
+ let dir = dirname$1(fileURLToPath(import.meta.url));
22372
+ for (let i = 0; i < 8; i++) {
22373
+ const candidate = join$1(dir, "package.json");
22183
22374
  try {
22184
22375
  return JSON.parse(readFileSync$1(candidate, "utf-8")).version;
22185
22376
  } catch {}
22377
+ const parent = dirname$1(dir);
22378
+ if (parent === dir) break;
22379
+ dir = parent;
22186
22380
  }
22187
22381
  return "0.0.0";
22188
22382
  }
22189
22383
  const panopticonVersion = readPackageVersion();
22384
+ const panopticonDevMode = (() => {
22385
+ let dir = dirname$1(fileURLToPath(import.meta.url));
22386
+ for (let i = 0; i < 8; i++) {
22387
+ if (existsSync$1(join$1(dir, "package.json")) && existsSync$1(join$1(dir, "src", "dashboard"))) return true;
22388
+ const parent = dirname$1(dir);
22389
+ if (parent === dir) break;
22390
+ dir = parent;
22391
+ }
22392
+ return false;
22393
+ })();
22190
22394
  function getIssueDataService() {
22191
22395
  const { getSharedIssueService } = (init_issue_service_singleton(), __toCommonJS(issue_service_singleton_exports));
22192
22396
  return getSharedIssueService();
@@ -22523,7 +22727,7 @@ const postRallyValidateRoute = HttpRouter.add("POST", "/api/rally/validate", Eff
22523
22727
  }, { status: 400 });
22524
22728
  return yield* Effect.promise(async () => {
22525
22729
  try {
22526
- const { RallyRestApi } = await import("./rally-api-CEH5KZi4.js");
22730
+ const { RallyRestApi } = await import("./rally-api-DNttdCW4.js");
22527
22731
  return jsonResponse({
22528
22732
  valid: true,
22529
22733
  message: "Rally connection successful",
@@ -22596,7 +22800,10 @@ const postDeaconPatrolRoute = HttpRouter.add("POST", "/api/deacon/patrol", Effec
22596
22800
  return jsonResponse({ error: "Failed to run patrol: " + msg }, { status: 500 });
22597
22801
  }
22598
22802
  }));
22599
- const getVersionRoute = HttpRouter.add("GET", "/api/version", Effect.sync(() => jsonResponse({ version: panopticonVersion })));
22803
+ const getVersionRoute = HttpRouter.add("GET", "/api/version", Effect.sync(() => jsonResponse({
22804
+ version: panopticonVersion,
22805
+ isDev: panopticonDevMode
22806
+ })));
22600
22807
  const getRegisteredProjectsRoute = HttpRouter.add("GET", "/api/registered-projects", Effect.try({
22601
22808
  try: () => {
22602
22809
  return jsonResponse(listProjects().map((p) => ({
@@ -22735,7 +22942,7 @@ const getPlanningStatusRoute = HttpRouter.add("GET", "/api/planning/:issueId/sta
22735
22942
  const issueId = new URL(request.url, "http://localhost").pathname.split("/")[3] || "";
22736
22943
  const sessionName = `planning-${issueId.toLowerCase()}`;
22737
22944
  const issueLower = issueId.toLowerCase();
22738
- const issuePrefix = issueId.split("-")[0];
22945
+ const issuePrefix = extractPrefix(issueId) ?? issueId.split("-")[0];
22739
22946
  return yield* Effect.promise(async () => {
22740
22947
  try {
22741
22948
  const projectPath = await getProjectPath(issuePrefix);
@@ -22902,10 +23109,10 @@ Continue the PLANNING session. Do NOT implement anything.
22902
23109
  `);
22903
23110
  const agentCwd = workspacePath;
22904
23111
  if (existsSync$1(outputFile)) await rename(outputFile, join$1(planningDir, `output-${Date.now()}.jsonl`));
22905
- const { getAgentCommand } = await import("./settings-DMeGBRsk.js");
23112
+ const { getAgentCommand } = await import("./settings-XWvDcj-D.js");
22906
23113
  let msgPlanningModel = "claude-sonnet-4-6";
22907
23114
  try {
22908
- const { getModelId } = await import("./work-type-router-Com2amST.js");
23115
+ const { getModelId } = await import("./work-type-router-Di5gCQwh.js");
22909
23116
  msgPlanningModel = getModelId("planning-agent");
22910
23117
  } catch {}
22911
23118
  const msgAgentCmd = getAgentCommand(msgPlanningModel);
@@ -22952,7 +23159,7 @@ const deletePlanningSessionRoute = HttpRouter.add("DELETE", "/api/planning/:issu
22952
23159
  }));
22953
23160
  const getTldrStatusRoute = HttpRouter.add("GET", "/api/services/tldr/status", Effect.promise(async () => {
22954
23161
  try {
22955
- const { getTldrDaemonService } = await import("./tldr-daemon-A6JqC59u.js");
23162
+ const { getTldrDaemonService } = await import("./tldr-daemon-Cfs0bXTi.js");
22956
23163
  const projectRoot = process.cwd();
22957
23164
  const venvPath = join$1(projectRoot, ".venv");
22958
23165
  const results = [];
@@ -22997,7 +23204,7 @@ const getTldrStatusRoute = HttpRouter.add("GET", "/api/services/tldr/status", Ef
22997
23204
  }));
22998
23205
  const postTldrStartRoute = HttpRouter.add("POST", "/api/services/tldr/start", Effect.promise(async () => {
22999
23206
  try {
23000
- const { getTldrDaemonService } = await import("./tldr-daemon-A6JqC59u.js");
23207
+ const { getTldrDaemonService } = await import("./tldr-daemon-Cfs0bXTi.js");
23001
23208
  const projectRoot = process.cwd();
23002
23209
  const venvPath = join$1(projectRoot, ".venv");
23003
23210
  if (!existsSync$1(venvPath)) return jsonResponse({ error: "No .venv found in project root" }, { status: 404 });
@@ -23014,7 +23221,7 @@ const postTldrStartRoute = HttpRouter.add("POST", "/api/services/tldr/start", Ef
23014
23221
  }));
23015
23222
  const postTldrStopRoute = HttpRouter.add("POST", "/api/services/tldr/stop", Effect.promise(async () => {
23016
23223
  try {
23017
- const { getTldrDaemonService } = await import("./tldr-daemon-A6JqC59u.js");
23224
+ const { getTldrDaemonService } = await import("./tldr-daemon-Cfs0bXTi.js");
23018
23225
  const projectRoot = process.cwd();
23019
23226
  const venvPath = join$1(projectRoot, ".venv");
23020
23227
  if (!existsSync$1(venvPath)) return jsonResponse({ error: "No .venv found in project root" }, { status: 404 });
@@ -23103,13 +23310,13 @@ const postShadowMonitorRoute = HttpRouter.add("POST", "/api/shadow/:issueId/moni
23103
23310
  const request = yield* HttpServerRequest.HttpServerRequest;
23104
23311
  const issueId = new URL(request.url, "http://localhost").pathname.split("/")[3] || "";
23105
23312
  const issueLower = issueId.toLowerCase();
23106
- const issuePrefix = issueId.split("-")[0];
23313
+ const issuePrefix = extractPrefix(issueId) ?? issueId.split("-")[0];
23107
23314
  return yield* Effect.promise(async () => {
23108
23315
  try {
23109
23316
  const projectPath = await getProjectPath(issuePrefix);
23110
23317
  const workspacePath = join$1(projectPath, "workspaces", `feature-${issueLower}`);
23111
23318
  if (!existsSync$1(workspacePath)) return jsonResponse({ error: "Workspace not found" }, { status: 404 });
23112
- const { gatherArtifacts, generateBasicInference, updateInferenceDocument } = await import("./shadow-engineering-BUeZunaE.js");
23319
+ const { gatherArtifacts, generateBasicInference, updateInferenceDocument } = await import("./shadow-engineering-lIn1W_95.js");
23113
23320
  const config = {
23114
23321
  issueId,
23115
23322
  workspacePath,
@@ -23130,7 +23337,7 @@ const postShadowObserveRoute = HttpRouter.add("POST", "/api/shadow/:issueId/obse
23130
23337
  const request = yield* HttpServerRequest.HttpServerRequest;
23131
23338
  const issueId = new URL(request.url, "http://localhost").pathname.split("/")[3] || "";
23132
23339
  const issueLower = issueId.toLowerCase();
23133
- const issuePrefix = issueId.split("-")[0];
23340
+ const issuePrefix = extractPrefix(issueId) ?? issueId.split("-")[0];
23134
23341
  const { mode } = yield* readJsonBody$1;
23135
23342
  return yield* Effect.promise(async () => {
23136
23343
  try {
@@ -23139,7 +23346,7 @@ const postShadowObserveRoute = HttpRouter.add("POST", "/api/shadow/:issueId/obse
23139
23346
  if (!existsSync$1(workspacePath)) return jsonResponse({ error: "Workspace not found" }, { status: 404 });
23140
23347
  const ghConfig = getGitHubConfig();
23141
23348
  if (!ghConfig) return jsonResponse({ error: "GitHub not configured - Observer requires GitHub" }, { status: 400 });
23142
- const { runObserverCycle } = await import("./shadow-engineering-BUeZunaE.js");
23349
+ const { runObserverCycle } = await import("./shadow-engineering-lIn1W_95.js");
23143
23350
  const firstRepo = ghConfig.repos[0];
23144
23351
  return jsonResponse({
23145
23352
  success: true,
@@ -23156,7 +23363,35 @@ const postShadowObserveRoute = HttpRouter.add("POST", "/api/shadow/:issueId/obse
23156
23363
  }
23157
23364
  });
23158
23365
  }));
23159
- const miscRouteLayer = Layer.mergeAll(postTrackersRefreshRoute, getProjectMappingsRoute, putProjectMappingsRoute, postProjectMappingsRoute, getGodviewSystemHealthRoute, getHealthAgentsRoute, postHealthAgentPingRoute, getTrackerStatusRoute, postRallyValidateRoute, getDeaconStatusRoute, getDeaconLogsRoute, postDeaconPatrolRoute, getVersionRoute, getRegisteredProjectsRoute, getConfirmationsRoute, postConfirmationRespondRoute, getHandoffsRoute, getHandoffsStatsRoute, getSpecialistHandoffsRoute, getSpecialistHandoffsStatsRoute, getSkillsRoute, getPlanningStatusRoute, postPlanningMessageRoute, deletePlanningSessionRoute, getTldrStatusRoute, postTldrStartRoute, postTldrStopRoute, getCacheStatusRoute, clearCacheRoute, getMetricsRuntimesRoute, getMetricsTasksRoute, postShadowMonitorRoute, postShadowObserveRoute);
23366
+ const panopticonProjectRoot = (() => {
23367
+ let dir = dirname$1(fileURLToPath(import.meta.url));
23368
+ for (let i = 0; i < 8; i++) {
23369
+ if (existsSync$1(join$1(dir, "package.json")) && existsSync$1(join$1(dir, "src", "dashboard"))) return dir;
23370
+ const parent = dirname$1(dir);
23371
+ if (parent === dir) break;
23372
+ dir = parent;
23373
+ }
23374
+ return null;
23375
+ })();
23376
+ const postDevRebuildRoute = HttpRouter.add("POST", "/api/dev/rebuild", Effect.gen(function* () {
23377
+ if (!panopticonDevMode || !panopticonProjectRoot) return jsonResponse({ error: "Rebuild only available in dev mode" }, { status: 403 });
23378
+ return yield* Effect.promise(async () => {
23379
+ try {
23380
+ const { stdout, stderr } = await execAsync$2("npm run build", {
23381
+ cwd: panopticonProjectRoot,
23382
+ timeout: 12e4
23383
+ });
23384
+ return jsonResponse({
23385
+ ok: true,
23386
+ stdout: stdout.slice(-2e3),
23387
+ stderr: stderr.slice(-2e3)
23388
+ });
23389
+ } catch (error) {
23390
+ return jsonResponse({ error: `Build failed: ${error instanceof Error ? error.message : String(error)}` }, { status: 500 });
23391
+ }
23392
+ });
23393
+ }));
23394
+ const miscRouteLayer = Layer.mergeAll(postTrackersRefreshRoute, getProjectMappingsRoute, putProjectMappingsRoute, postProjectMappingsRoute, getGodviewSystemHealthRoute, getHealthAgentsRoute, postHealthAgentPingRoute, getTrackerStatusRoute, postRallyValidateRoute, getDeaconStatusRoute, getDeaconLogsRoute, postDeaconPatrolRoute, getVersionRoute, getRegisteredProjectsRoute, getConfirmationsRoute, postConfirmationRespondRoute, getHandoffsRoute, getHandoffsStatsRoute, getSpecialistHandoffsRoute, getSpecialistHandoffsStatsRoute, getSkillsRoute, getPlanningStatusRoute, postPlanningMessageRoute, deletePlanningSessionRoute, getTldrStatusRoute, postTldrStartRoute, postTldrStopRoute, getCacheStatusRoute, clearCacheRoute, getMetricsRuntimesRoute, getMetricsTasksRoute, postShadowMonitorRoute, postShadowObserveRoute, postDevRebuildRoute);
23160
23395
  //#endregion
23161
23396
  //#region routes/conversations.ts
23162
23397
  /**
@@ -23170,6 +23405,7 @@ const miscRouteLayer = Layer.mergeAll(postTrackersRefreshRoute, getProjectMappin
23170
23405
  */
23171
23406
  init_tmux();
23172
23407
  init_config_yaml();
23408
+ init_paths();
23173
23409
  const execAsync$1 = promisify(exec);
23174
23410
  /**
23175
23411
  * Wait for Claude Code to show its input prompt (❯) in the tmux pane.
@@ -23191,7 +23427,7 @@ async function waitForClaudeReady(tmuxSession) {
23191
23427
  }
23192
23428
  /** Compute the deterministic JSONL session file path from cwd + session UUID. */
23193
23429
  function sessionFilePath(cwd, sessionId) {
23194
- const encodedCwd = cwd.replace(/\//g, "-");
23430
+ const encodedCwd = encodeClaudeProjectDir(cwd);
23195
23431
  return join$1(homedir(), ".claude", "projects", encodedCwd, `${sessionId}.jsonl`);
23196
23432
  }
23197
23433
  const readJsonBody = Effect.gen(function* () {
@@ -23427,10 +23663,13 @@ const deleteConversationRoute = HttpRouter.add("DELETE", "/api/conversations/:na
23427
23663
  }));
23428
23664
  const postConversationResumeRoute = HttpRouter.add("POST", "/api/conversations/:name/resume", Effect.gen(function* () {
23429
23665
  const name = (yield* HttpRouter.params)["name"] ?? "";
23666
+ const body = yield* readJsonBody;
23430
23667
  return yield* Effect.promise(async () => {
23431
23668
  try {
23432
23669
  const conv = getConversationByName(name);
23433
23670
  if (!conv) return jsonResponse({ error: "Conversation not found" }, { status: 404 });
23671
+ const model = typeof body["model"] === "string" && body["model"].trim() ? body["model"].trim() : conv.model ?? void 0;
23672
+ const effort = typeof body["effort"] === "string" && body["effort"].trim() ? body["effort"].trim() : conv.effort ?? void 0;
23434
23673
  if (await tmuxSessionExists$1(conv.tmuxSession)) {
23435
23674
  updateLastAttached(name);
23436
23675
  markConversationActive(name);
@@ -23441,7 +23680,7 @@ const postConversationResumeRoute = HttpRouter.add("POST", "/api/conversations/:
23441
23680
  });
23442
23681
  }
23443
23682
  const oldSessionId = conv.sessionFile ? conv.sessionFile.split("/").pop()?.replace(".jsonl", "") ?? void 0 : void 0;
23444
- spawnConversationSession(conv.tmuxSession, conv.cwd, oldSessionId ?? randomUUID(), conv.model ?? void 0, conv.effort ?? void 0, conv.issueId ?? void 0, !!oldSessionId).catch((err) => {
23683
+ spawnConversationSession(conv.tmuxSession, conv.cwd, oldSessionId ?? randomUUID(), model, effort, conv.issueId ?? void 0, !!oldSessionId).catch((err) => {
23445
23684
  console.error(`[conversations] Failed to respawn session ${conv.tmuxSession}:`, err);
23446
23685
  });
23447
23686
  markConversationActive(name);
@@ -23455,6 +23694,32 @@ const postConversationResumeRoute = HttpRouter.add("POST", "/api/conversations/:
23455
23694
  }
23456
23695
  });
23457
23696
  }));
23697
+ const postConversationSwitchModelRoute = HttpRouter.add("POST", "/api/conversations/:name/switch-model", Effect.gen(function* () {
23698
+ const name = (yield* HttpRouter.params)["name"] ?? "";
23699
+ const body = yield* readJsonBody;
23700
+ return yield* Effect.promise(async () => {
23701
+ try {
23702
+ const conv = getConversationByName(name);
23703
+ if (!conv) return jsonResponse({ error: "Conversation not found" }, { status: 404 });
23704
+ const model = typeof body["model"] === "string" && body["model"].trim() ? body["model"].trim() : conv.model ?? void 0;
23705
+ await execAsync$1(`tmux kill-session -t ${conv.tmuxSession} 2>/dev/null || true`, { encoding: "utf-8" });
23706
+ if (model) updateConversationModel(name, model);
23707
+ const oldSessionId = conv.sessionFile ? conv.sessionFile.split("/").pop()?.replace(".jsonl", "") ?? void 0 : void 0;
23708
+ spawnConversationSession(conv.tmuxSession, conv.cwd, oldSessionId ?? randomUUID(), model, conv.effort ?? void 0, conv.issueId ?? void 0, !!oldSessionId).catch((err) => {
23709
+ console.error(`[conversations] Failed to respawn session after model switch ${conv.tmuxSession}:`, err);
23710
+ });
23711
+ markConversationActive(name);
23712
+ return jsonResponse({
23713
+ ...conv,
23714
+ status: "active",
23715
+ model,
23716
+ reattached: false
23717
+ });
23718
+ } catch (error) {
23719
+ return jsonResponse({ error: "Failed to switch model: " + (error instanceof Error ? error.message : String(error)) }, { status: 500 });
23720
+ }
23721
+ });
23722
+ }));
23458
23723
  const getConversationMessagesRoute = HttpRouter.add("GET", "/api/conversations/:name/messages", Effect.gen(function* () {
23459
23724
  const name = (yield* HttpRouter.params)["name"] ?? "";
23460
23725
  return yield* Effect.promise(async () => {
@@ -23592,7 +23857,7 @@ const postConversationRestartAllRoute = HttpRouter.add("POST", "/api/conversatio
23592
23857
  }
23593
23858
  });
23594
23859
  }));
23595
- const conversationsRouteLayer = Layer.mergeAll(getConversationsRoute, postConversationRoute, patchConversationRoute, deleteConversationRoute, postConversationResumeRoute, postConversationRestartAllRoute, postConversationArchiveRoute, getConversationMessagesRoute, postConversationMessageRoute);
23860
+ const conversationsRouteLayer = Layer.mergeAll(getConversationsRoute, postConversationRoute, patchConversationRoute, deleteConversationRoute, postConversationResumeRoute, postConversationSwitchModelRoute, postConversationRestartAllRoute, postConversationArchiveRoute, getConversationMessagesRoute, postConversationMessageRoute);
23596
23861
  //#endregion
23597
23862
  //#region server.ts
23598
23863
  /**
@@ -23858,19 +24123,24 @@ function stopConversationLifecycleService() {
23858
24123
  //#endregion
23859
24124
  //#region pending-lifecycle.ts
23860
24125
  /**
23861
- * Pending post-merge lifecycle handler (PAN-444).
24126
+ * Pending post-merge lifecycle handler (PAN-444, PAN-520).
23862
24127
  *
23863
24128
  * After a merge-triggered rebuild+restart, the old server writes a pending file
23864
- * before dying. The fresh process calls processPendingLifecycle() on startup
23865
- * dynamic imports resolve to new chunk hashes, so no ERR_MODULE_NOT_FOUND.
24129
+ * before dying. The fresh process reads the pending file on startup and runs the
24130
+ * lifecycle steps with correct module chunk references (no ERR_MODULE_NOT_FOUND after rebuild).
24131
+ *
24132
+ * Lifecycle events (dashboard.lifecycle_started, _completed, _failed) are emitted
24133
+ * at startup so the ActivityPanel shows restart progress and App.tsx can show
24134
+ * the "restarting" banner.
23866
24135
  */
23867
24136
  const PENDING_FILE = join(homedir$1(), ".panopticon", "pending-post-merge.json");
24137
+ const RESTART_MARKER = join(homedir$1(), ".panopticon", "dashboard-restarting.json");
23868
24138
  /**
23869
24139
  * Default lifecycle runner: dynamically imports merge-agent so the fresh process
23870
24140
  * loads new content-hashed chunk filenames (no ERR_MODULE_NOT_FOUND after rebuild).
23871
24141
  */
23872
24142
  async function defaultLifecycleRunner(pending) {
23873
- const { postMergeLifecycle, notifyTldrDaemon } = await import("./merge-agent-GLtMEsTu.js");
24143
+ const { postMergeLifecycle, notifyTldrDaemon } = await import("./merge-agent-CGN3TT0a.js");
23874
24144
  await postMergeLifecycle(pending.issueId, pending.projectPath, pending.sourceBranch, { skipDeploy: true });
23875
24145
  if (pending.sourceBranch) await notifyTldrDaemon(pending.projectPath, pending.sourceBranch);
23876
24146
  }
@@ -23878,13 +24148,33 @@ async function defaultLifecycleRunner(pending) {
23878
24148
  * Check for and process a pending post-merge lifecycle file.
23879
24149
  * Reads, validates, deletes the file, then schedules lifecycle execution.
23880
24150
  * Safe to call unconditionally on server startup — no-op if file absent.
24151
+ *
24152
+ * Also checks for a RESTART_MARKER file (written by deploy script before killing
24153
+ * the old server) and emits dashboard.lifecycle_started if found.
23881
24154
  */
23882
24155
  async function processPendingLifecycle(options) {
23883
24156
  const pendingFile = options?.pendingFile ?? PENDING_FILE;
24157
+ const restartMarker = options?.restartMarker ?? RESTART_MARKER;
23884
24158
  const staleThresholdMs = options?.staleThresholdMs ?? 36e5;
23885
24159
  const lifecycleDelayMs = options?.lifecycleDelayMs ?? 3e3;
23886
24160
  const runner = options?._runner ?? defaultLifecycleRunner;
24161
+ if (existsSync(restartMarker)) try {
24162
+ const raw = await readFile$1(restartMarker, "utf-8");
24163
+ const marker = JSON.parse(raw);
24164
+ await unlink$1(restartMarker);
24165
+ if ((options?.now ?? Date.now()) - (marker.timestamp ?? 0) <= staleThresholdMs) {
24166
+ emitDashboardLifecycle("started", {
24167
+ reason: marker.reason ?? "post-merge",
24168
+ issueId: marker.issueId,
24169
+ trigger: marker.trigger ?? "deploy-script"
24170
+ });
24171
+ console.log(`[panopticon] Detected planned restart (${marker.reason}) — lifecycle_started event emitted`);
24172
+ }
24173
+ } catch (err) {
24174
+ console.warn(`[panopticon] Failed to process restart marker: ${err.message}`);
24175
+ }
23887
24176
  if (!existsSync(pendingFile)) return;
24177
+ const startTime = Date.now();
23888
24178
  try {
23889
24179
  const raw = await readFile$1(pendingFile, "utf-8");
23890
24180
  await unlink$1(pendingFile);
@@ -23898,8 +24188,18 @@ async function processPendingLifecycle(options) {
23898
24188
  setTimeout(async () => {
23899
24189
  try {
23900
24190
  await runner(pending);
24191
+ emitDashboardLifecycle("completed", {
24192
+ reason: pending.reason ?? "post-merge",
24193
+ issueId: pending.issueId,
24194
+ durationMs: Date.now() - startTime
24195
+ });
23901
24196
  } catch (err) {
23902
24197
  console.error(`[panopticon] Post-merge lifecycle failed for ${pending.issueId}: ${err.message}`);
24198
+ emitDashboardLifecycle("failed", {
24199
+ reason: pending.reason ?? "post-merge",
24200
+ issueId: pending.issueId,
24201
+ error: err.message
24202
+ });
23903
24203
  }
23904
24204
  }, lifecycleDelayMs);
23905
24205
  } catch (err) {