@overdeck/desktop 0.45.15 → 0.45.16

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 (331) hide show
  1. package/package.json +1 -1
  2. package/server/{acceptance-criteria-DHZk2ceV.js → acceptance-criteria-BZ_nQS1f.js} +2 -2
  3. package/server/{advancing-selfheal-CSuZ31bB.js → advancing-selfheal-DJYAvGv-.js} +6 -5
  4. package/server/{agent-gc-D_DxfBHR.js → agent-gc-D0wDIeV1.js} +3 -3
  5. package/server/{agent-state-EP2QFV9n.js → agent-state-lGvgPP4m.js} +1 -1
  6. package/server/{agent-state-service-C_2ZAQRP.js → agent-state-service-CZrayD_G.js} +1 -1
  7. package/server/{agent-state-service-BZkvgQf4.js → agent-state-service-DFslS5go.js} +9 -52
  8. package/server/{agents-CsOzAmRg.js → agents-B9GwfCyp.js} +99 -140
  9. package/server/{agents-DCvyTXNU.js → agents-CEcaxSkR.js} +1 -1
  10. package/server/{archive-planning-DkivCk1A.js → archive-planning-CbghE9-o.js} +5 -5
  11. package/server/{archive-planning-CTILQRnV.js → archive-planning-CoyIbgGK.js} +1 -1
  12. package/server/{artifact-index-jobs-CmsvQ1ey.js → artifact-index-jobs-CcSrUoSE.js} +2 -2
  13. package/server/{auto-commit-QAfsu3Sb.js → auto-commit-IW-eik_b.js} +1 -1
  14. package/server/{backlog-auto-trigger-ueRaT8Dy.js → backlog-auto-trigger-BfgDsII0.js} +3 -3
  15. package/server/{bd-process-lock-D3S4T4o-.js → bd-process-lock-XAXAet9O.js} +2 -2
  16. package/server/{beads-CYsLiyIM.js → beads-B1u04n3o.js} +1 -1
  17. package/server/{beads-BGGxrkZ5.js → beads-BeSMEjGT.js} +7 -7
  18. package/server/{beads-query-B1DlJVp9.js → beads-query-Dl4FhT8J.js} +2 -2
  19. package/server/{beads-restore-CyygSmmn.js → beads-restore-BUItPOjI.js} +2 -2
  20. package/server/behavior-BTpYbAv4.js +10 -0
  21. package/server/{briefing-freshness-Kh5V8RTh.js → briefing-freshness-DESTCWo-.js} +4 -4
  22. package/server/{checkpoint-manager-fu9oVsR-.js → checkpoint-manager-BwFdegJF.js} +2 -2
  23. package/server/{checkpoint-manager-CAFos8e1.js → checkpoint-manager-DWSXooZV.js} +1 -1
  24. package/server/checkpoint-worker.js +1 -1
  25. package/server/{checkpoints-1BqOlS4q.js → checkpoints-BtUonbs3.js} +2 -2
  26. package/server/{checkpoints-DvhGi8P_.js → checkpoints-fjadfOKF.js} +1 -1
  27. package/server/{claude-hooks-provision-s_wdpeVj.js → claude-hooks-provision-DAtxutOs.js} +132 -114
  28. package/server/claude-hooks-provision-DiK62u0k.js +3 -0
  29. package/server/{claude-permissions-CaWqysff.js → claude-permissions-CThLgf8d.js} +2 -2
  30. package/server/{claude-settings-overlay-CcTf0xzG.js → claude-settings-overlay-BF9MPIwx.js} +2 -2
  31. package/server/{claude-settings-overlay-BbA4FbVI.js → claude-settings-overlay-Dx_Uqcmv.js} +1 -1
  32. package/server/{cli-BwCvCUBK.js → cli-ByKIIMfT.js} +9 -9
  33. package/server/cli-D9cUTbBr.js +3 -0
  34. package/server/{cliproxy-BsoNNDAj.js → cliproxy-B4c1BUvs.js} +2 -2
  35. package/server/{cliproxy-C2xC-3vH.js → cliproxy-C_GuT5DU.js} +1 -1
  36. package/server/{close-issue-BleIwP3f.js → close-issue-BOuLKr6e.js} +5 -5
  37. package/server/{closed-issue-reaper-BwUUvjEW.js → closed-issue-reaper-CksfuiFD.js} +1 -1
  38. package/server/{closed-issue-reaper-mC5pujeb.js → closed-issue-reaper-DCAYzNXW.js} +9 -9
  39. package/server/{codex-B7DTpwEw.js → codex-BYPz6ZdF.js} +1 -1
  40. package/server/{codex-DW60_5j2.js → codex-BbqIRZjd.js} +6 -5
  41. package/server/{behavior-Cpj03N4v.js → codex-parser-mFYZh8vR.js} +3 -9
  42. package/server/{compact-beads-DKL54y6j.js → compact-beads-CyJtoXJi.js} +5 -5
  43. package/server/{compact-beads-CK_hHEnB.js → compact-beads-N00E4EVa.js} +1 -1
  44. package/server/{config-ZNnMpIlh.js → config-DVLdmnMJ.js} +2 -2
  45. package/server/{config-BRNQJXhA.js → config-Dj6N8EP9.js} +1 -1
  46. package/server/{config-yaml-Dcz-8uit.js → config-yaml-cNOZcEww.js} +91 -22
  47. package/server/{conflict-gate-DTje2Ll7.js → conflict-gate-BMKm_5DV.js} +3 -3
  48. package/server/{conflict-gate-DGT8jCLp.js → conflict-gate-CuXUv-bP.js} +1 -1
  49. package/server/{context-layers-ByOWUjUg.js → context-layers-CeAwSYNt.js} +2 -2
  50. package/server/{context-layers-BdUCQ-cl.js → context-layers-c0JqYHcS.js} +3 -3
  51. package/server/{control-settings-DwkAeooY.js → control-settings-D4EFsRBd.js} +4 -4
  52. package/server/{conversation-compaction-OTYgd6eg.js → conversation-compaction-BCggyih4.js} +8 -8
  53. package/server/{conversation-compaction-WYQZUVDm.js → conversation-compaction-kHVfVRg3.js} +1 -1
  54. package/server/{conversation-service-BR1OgvxO.js → conversation-service-B8LFQQm1.js} +6 -5
  55. package/server/{conversation-service-C_kNZPLx.js → conversation-service-BTzObqGi.js} +1 -1
  56. package/server/{conversations-DG2M8WnT.js → conversations-B-lcHv-5.js} +4 -4
  57. package/server/{conversations-izHvSoAR.js → conversations-BM7zlXjr.js} +1 -1
  58. package/server/{cost-B2mj17iG.js → cost-BcpRQ-7o.js} +3 -3
  59. package/server/{cost-DQ2ajr_m.js → cost-D9kPIY_5.js} +2 -2
  60. package/server/{cost-sync-gTayEuWP.js → cost-sync-DF6odxK9.js} +3 -3
  61. package/server/{dag-CqTehWpY.js → dag-DKI3sOmX.js} +3 -3
  62. package/server/{dangerous-git-ops-DDWQlPC3.js → dangerous-git-ops-Bn18PEcN.js} +1 -1
  63. package/server/dashboard-db-worker.js +6 -6
  64. package/server/{deacon-BqW9HMew.js → deacon-DONuopff.js} +3 -3
  65. package/server/{deacon-DrKDBeJL.js → deacon-DdARMjZq.js} +127 -107
  66. package/server/{deacon-nudge-log-D1wEK6zF.js → deacon-nudge-log-B-naf89q.js} +1 -1
  67. package/server/{deacon-swarm-CO_A7xyd.js → deacon-swarm-BNGkmYR_.js} +11 -11
  68. package/server/deacon-swarm-CvdFekIO.js +2 -0
  69. package/server/deacon.js +7 -7
  70. package/server/{devcontainer-renderer-BQolp_qZ.js → devcontainer-renderer-C-34Sxyz.js} +3 -3
  71. package/server/{dist-Bc32rWJB.js → dist-BMXvKiZP.js} +1 -1
  72. package/server/dist-BNwrgsUO.js +3 -0
  73. package/server/{dist-src-Byxt1ifL.js → dist-src-BgGUblXg.js} +1 -1
  74. package/server/{docker-s-esqZ__.js → docker-apZ9pBYw.js} +2 -2
  75. package/server/{ensure-devcontainer-DA4-jF6R.js → ensure-devcontainer-Bqi1EF1P.js} +4 -4
  76. package/server/{ensure-devcontainer-pUVaT0h3.js → ensure-devcontainer-Dq3KoOIl.js} +1 -1
  77. package/server/{esm-shims-CJHy8CZY.js → esm-shims-BEjvINX3.js} +1 -1
  78. package/server/{event-store-CcJAhKCl.js → event-store-CqDgfbAs.js} +1 -1
  79. package/server/{event-store-DRte2Rwt.js → event-store-D89fMfXS.js} +3 -3
  80. package/server/{events-Bej1w_k8.js → events-S_C0pvl6.js} +3 -3
  81. package/server/{events-CtsLScn8.js → events-rIGncmP1.js} +1 -1
  82. package/server/{export-Dx_qJ3h8.js → export-BJHSVwKP.js} +2 -2
  83. package/server/{factory-FN727tWr.js → factory-DV18m0rc.js} +5 -5
  84. package/server/{feature-registry-population-ie-yBcQC.js → feature-registry-population-CqZSnqQi.js} +4 -4
  85. package/server/{feature-registry-storage-CkZTFSsn.js → feature-registry-storage-BeXmNBwK.js} +2 -2
  86. package/server/{features-Dtm9ABuz.js → features-u5XeMaOK.js} +2 -2
  87. package/server/{feedback-target-BYtpyt1i.js → feedback-target-CwyWf0Dg.js} +6 -6
  88. package/server/{feedback-target-DVJQDiE4.js → feedback-target-DDG1PWl3.js} +1 -1
  89. package/server/{feedback-writer-DOUhyIW2.js → feedback-writer-BsJiw5aT.js} +1 -1
  90. package/server/{feedback-writer-fdE1BzeL.js → feedback-writer-D20HSXre.js} +4 -4
  91. package/server/{flywheel-CUErLAyN.js → flywheel-9Y1X7IM-.js} +13 -13
  92. package/server/{flywheel-Bv3wv2S6.js → flywheel-Dczmgchd.js} +12 -12
  93. package/server/{flywheel-Bi82iiNl.js → flywheel-RCnHAgc4.js} +1 -1
  94. package/server/{flywheel-merge-order-BaEN3iyN.js → flywheel-merge-order-CtCYsFJP.js} +7 -7
  95. package/server/{flywheel-merge-order-DXjeBnJ1.js → flywheel-merge-order-DEtEd3aK.js} +1 -1
  96. package/server/forge-8y6aEPTB.js +2 -0
  97. package/server/{forge-ButEdJ31.js → forge-DFDThFil.js} +2 -2
  98. package/server/{from-CbtTxftl.js → from-NSJypkI8.js} +1 -1
  99. package/server/{fts-db-CBgBLZcL.js → fts-db-C5A_TTOM.js} +2 -2
  100. package/server/{fts-operations-CI9Xuo_1.js → fts-operations-DvCSimfU.js} +2 -2
  101. package/server/{git-utils-BCLRWQ-y.js → git-utils-C0neHvQx.js} +1 -1
  102. package/server/{git-utils-ClfpP47N.js → git-utils-Dr0L7mFk.js} +2 -2
  103. package/server/{github-app-DRD2woO0.js → github-app-Bwt9lK4A.js} +1 -1
  104. package/server/{github-app-DscZ0_B6.js → github-app-u9-SX7Gc.js} +2 -2
  105. package/server/{github-client-DpiZnxGH.js → github-client-Btyy3uan.js} +3 -3
  106. package/server/{github-client-iFRw8f7e.js → github-client-Do3k-N1W.js} +1 -1
  107. package/server/{github-pr-lookup-D-EBexxC.js → github-pr-lookup-DOF1U2WW.js} +2 -2
  108. package/server/{harness-resolve-iMjyNUJ2.js → harness-resolve-C6g2R0Cd.js} +3 -3
  109. package/server/{health-events-CRdxDFN2.js → health-events-B4u-2a9m.js} +2 -2
  110. package/server/{health-events-B_WsQyYm.js → health-events-Bos3sk5g.js} +1 -1
  111. package/server/{hooks-C9b7Vqpw.js → hooks-BCoOjL_R.js} +2 -2
  112. package/server/{hooks-C1ScyVxP.js → hooks-uEr8WTx_.js} +1 -1
  113. package/server/{hume-TQ5pvOZ_.js → hume-BqxYKbUf.js} +2 -2
  114. package/server/hume-CerGi2RH.js +3 -0
  115. package/server/{idle-stack-reaper-B1kG7B_X.js → idle-stack-reaper-DbZ8ukMd.js} +2 -2
  116. package/server/{idle-stack-reaper-iFVOAoJy.js → idle-stack-reaper-H0W6XtHh.js} +1 -1
  117. package/server/{infra-bpq1MHKU.js → infra-Ba9mS6e6.js} +3 -3
  118. package/server/{injection-BLWfwTVZ.js → injection-C1DKXeIZ.js} +1 -1
  119. package/server/{injection-DJqWld1v.js → injection-yrMBxzVq.js} +7 -7
  120. package/server/{inspect-agent-DytCsltn.js → inspect-agent-B-mnb4uh.js} +9 -9
  121. package/server/inspect-agent-CWkeAB7J.js +2 -0
  122. package/server/{internal-token-CCaWaTwE.js → internal-token-BPYEaXFh.js} +1 -1
  123. package/server/{internal-token-CjlhdufS.js → internal-token-BtqSbKTx.js} +2 -2
  124. package/server/{io-BiQ2Cs3k.js → io-VEGSAqsd.js} +15 -22
  125. package/server/{issue-closed-FApNiOOs.js → issue-closed-BxcePXL-.js} +4 -4
  126. package/server/{issue-lifecycle-C-K53ASY.js → issue-lifecycle--8MRxrG1.js} +22 -22
  127. package/server/{issue-lifecycle-BkFWNjlD.js → issue-lifecycle-CdMUauyb.js} +1 -1
  128. package/server/{issue-service-singleton-CuHGpJJP.js → issue-service-singleton-CkTUI-eu.js} +10 -10
  129. package/server/{issue-service-singleton-bG1WdSdQ.js → issue-service-singleton-MZsDhAob.js} +1 -1
  130. package/server/{issues-CwQMphDH.js → issues-CBAsuoAO.js} +2 -2
  131. package/server/{jsonl-parser-dNIjHgym.js → jsonl-parser-BUW5_sSK.js} +3 -3
  132. package/server/{label-cleanup-DYvAZknd.js → label-cleanup-htK6fBRU.js} +3 -3
  133. package/server/{layers-CD6FysRU.js → layers-jjL16At6.js} +2 -2
  134. package/server/{lifecycle-C_73gi-C.js → lifecycle-Ck2UR27D.js} +7 -7
  135. package/server/{lifecycle-io-C_Wu0_i-.js → lifecycle-io-DXv8Utct.js} +1 -1
  136. package/server/{lifecycle-io-CeYxP3cE.js → lifecycle-io-IehcRt2v.js} +36 -47
  137. package/server/{linear-client-4qoKnuQu.js → linear-client-By7hjwuN.js} +1 -1
  138. package/server/{linear-client-EtVyblVz.js → linear-client-D9cSQfvD.js} +3 -3
  139. package/server/memory-fts-worker.js +1 -1
  140. package/server/{merge-brm721Es.js → merge-BLcEZNXz.js} +1 -1
  141. package/server/{merge-7rqkTUm2.js → merge-BN8FGJ2q.js} +3 -3
  142. package/server/{merge-agent-4Zhlgvqp.js → merge-agent-B3u2szOL.js} +29 -29
  143. package/server/{merge-agent-36wfYm2u.js → merge-agent-ejC7Wos8.js} +1 -1
  144. package/server/{merge-batch-itfnwdsT.js → merge-batch-DyqlgYGp.js} +1 -1
  145. package/server/{merge-blockers-Bto_Oe_o.js → merge-blockers-cq-aS2KG.js} +2 -2
  146. package/server/merge-ops-CFkQtXEj.js +2 -0
  147. package/server/{merge-rebase-Czfqfe4q.js → merge-rebase-Dl7yIxtV.js} +2 -2
  148. package/server/{merge-set-BIkGQL9j.js → merge-set-CZ9Nbay0.js} +3 -3
  149. package/server/{merge-set-G1RHcu3D.js → merge-set-Dy0D0r3i.js} +1 -1
  150. package/server/{merge-sync-DIrmlZUr.js → merge-sync-CG9kDCdT.js} +1 -1
  151. package/server/{merge-sync-B43Dybea.js → merge-sync-D7jWLgCC.js} +2 -2
  152. package/server/{merge-train-DGqVuNZV.js → merge-train-CH33XJOH.js} +3 -3
  153. package/server/{merge-train-deps-q15XLnAS.js → merge-train-deps-JoVdGnOg.js} +4 -4
  154. package/server/{merge-verification-Cqfxx6bE.js → merge-verification-D4wTChdX.js} +4 -4
  155. package/server/{multipart-parser-CiPxxfUH.js → multipart-parser-Csn8U-K9.js} +2 -2
  156. package/server/{no-resume-mode-yrPEQ_pC.js → no-resume-mode-Gh5R_YLF.js} +1 -1
  157. package/server/node_modules/.package-lock.json +1 -1
  158. package/server/{orphan-proposed-reconciler-DAD9FJtQ.js → orphan-proposed-reconciler-BIcNu4tl.js} +1 -1
  159. package/server/{orphan-proposed-reconciler-BWWHn4Lr.js → orphan-proposed-reconciler-DI_IS1p_.js} +10 -10
  160. package/server/package-lock.json +2 -2
  161. package/server/package.json +1 -1
  162. package/server/{pan-dir-Bj7Hy8iu.js → pan-dir-CQIfKG8c.js} +4 -4
  163. package/server/{paths-C9DkhIOT.js → paths-Blj6A9AJ.js} +2 -2
  164. package/server/{pickup-CKRuGDsB.js → pickup-BtvRBbvI.js} +1 -1
  165. package/server/{pipeline-notifier-BkKbQ8ji.js → pipeline-notifier-BH4PAi-w.js} +1 -1
  166. package/server/{pipeline-notifier-CAurUste.js → pipeline-notifier-D_WYtEwl.js} +2 -2
  167. package/server/{project-pipelines-BRWaGmI4.js → project-pipelines-jMTitpeO.js} +2 -2
  168. package/server/projects-CrBE6IhN.js +3 -0
  169. package/server/{prompts-DfI5qbTW.js → prompts-B3njaImU.js} +2 -2
  170. package/server/{providers-CWDXoaMA.js → providers-BbEyFhPX.js} +7 -7
  171. package/server/{providers-D-5txBRc.js → providers-DnPxkHoG.js} +1 -1
  172. package/server/public/assets/chunk-BO2N2NFS-3qh9TUJi.js +103 -0
  173. package/server/public/assets/{diagram-OG6HWLK6-Avtvq2qI.js → diagram-OG6HWLK6-D8UVTPj7.js} +1 -1
  174. package/server/public/assets/{dist-BEHQuasD.js → dist-BvLLn1YC.js} +3 -3
  175. package/server/public/assets/{dist-BvmY-qb1.js → dist-CyubL7Wj.js} +1 -1
  176. package/server/public/assets/{ganttDiagram-6RSMTGT7-7KhCd0fH.js → ganttDiagram-6RSMTGT7-BI4E1LbQ.js} +1 -1
  177. package/server/public/assets/{highlighted-body-OFNGDK62-iQoBMTf0.js → highlighted-body-OFNGDK62-D_bapWkF.js} +1 -1
  178. package/server/public/assets/index-BAZxZ-8I.js +796 -0
  179. package/server/public/assets/{index-DUFDmvmH.css → index-FBG3JBfq.css} +1 -1
  180. package/server/public/assets/{linear-CiJHW9g5.js → linear-CEdobObr.js} +1 -1
  181. package/server/public/assets/mermaid-GHXKKRXX-BYP8MI37.js +1 -0
  182. package/server/public/assets/{pieDiagram-4H26LBE5-BOhmvUhW.js → pieDiagram-4H26LBE5-DT79L01f.js} +1 -1
  183. package/server/public/assets/{prod-DmLBBqat.js → prod-CR_K2DFV.js} +4 -4
  184. package/server/public/assets/{quadrantDiagram-W4KKPZXB-Cjku660G.js → quadrantDiagram-W4KKPZXB-BEkKXXrL.js} +1 -1
  185. package/server/public/assets/{sankeyDiagram-5OEKKPKP-D52w5oPh.js → sankeyDiagram-5OEKKPKP-BxSCqn-j.js} +1 -1
  186. package/server/public/assets/{xychartDiagram-2RQKCTM6-BTO07_Iv.js → xychartDiagram-2RQKCTM6-DicwJGG_.js} +1 -1
  187. package/server/public/index.html +2 -2
  188. package/server/{pull-requests-CKZPWhjD.js → pull-requests-43LPDfM8.js} +1 -1
  189. package/server/{pull-requests-Bmre-Xlz.js → pull-requests-DyUkQl4W.js} +3 -3
  190. package/server/{rally-BBd9tQ__.js → rally-BtWjybOa.js} +3 -3
  191. package/server/{rally-api-DDc85HIz.js → rally-api-B-YA_oXx.js} +1 -1
  192. package/server/{rally-api-DxZFObI_.js → rally-api-B-osULNL.js} +2 -2
  193. package/server/{rally-client-BADHn0m_.js → rally-client-CzFymP7P.js} +1 -1
  194. package/server/{rally-client-DvvLiAQP.js → rally-client-sErNQBO0.js} +5 -5
  195. package/server/rally-oggyp4cs.js +3 -0
  196. package/server/{reap-terminal-sessions-D6JDJsqF.js → reap-terminal-sessions-2s-fvilz.js} +1 -1
  197. package/server/{reap-terminal-sessions-D_xvy-Mk.js → reap-terminal-sessions-DnDQ7pf9.js} +1 -1
  198. package/server/{rebuild-stack-D19i080j.js → rebuild-stack-CoU-HqZj.js} +6 -6
  199. package/server/{rebuild-stack-GOsWqXi3.js → rebuild-stack-nGD_nPZo.js} +1 -1
  200. package/server/{reconstruct-cache-lQrG4xGg.js → reconstruct-cache-Wj8GrYB0.js} +6 -6
  201. package/server/{record-pyB6VA32.js → record-lEYK__LD.js} +1 -1
  202. package/server/{recovery-trip-Dfh1tNHn.js → recovery-trip-BT7nb9OV.js} +2 -2
  203. package/server/{release-engine-DxcMWRuK.js → release-engine-CBLQXDlH.js} +5 -5
  204. package/server/{release-set-BYsgX7o6.js → release-set-BNiqi7hy.js} +3 -3
  205. package/server/{remote-DmeL21dF.js → remote-DW_TWQnr.js} +3 -3
  206. package/server/{remote-8W2Yhygw.js → remote-DcO9An_f.js} +3 -3
  207. package/server/{remote-agents-BfQBE6MN.js → remote-agents-C4cyxHQS.js} +6 -6
  208. package/server/{remote-agents-DlvbzO7m.js → remote-agents-Cv-U-_V8.js} +1 -1
  209. package/server/{remote-completion-BgkiSQmx.js → remote-completion-PhXGGFQy.js} +13 -13
  210. package/server/{resolver-dTpSSzaH.js → resolver-C7dLn8OK.js} +2 -2
  211. package/server/resume-BYZBIab-.js +3 -0
  212. package/server/{review-agent-D025Wt7w.js → review-agent-Dn-yn7Zj.js} +23 -23
  213. package/server/{review-agent-Rub0OpZc.js → review-agent-u5q3ip7H.js} +1 -1
  214. package/server/{review-artifacts-CX951jTU.js → review-artifacts-D4T04aYI.js} +6 -6
  215. package/server/{review-context-DGGGR_w5.js → review-context-Rc0VDLG_.js} +8 -8
  216. package/server/{review-monitor-0_qqMcnS.js → review-monitor-BC--miCO.js} +2 -2
  217. package/server/{review-status-Br6lAFGO.js → review-status-CG0iDuWa.js} +1 -1
  218. package/server/{review-status-4qqLkRMu.js → review-status-Dc1l4dVz.js} +18 -18
  219. package/server/{review-status-enrichment-Cr8m3uVL.js → review-status-enrichment-C1a1OG_1.js} +3 -3
  220. package/server/{review-status-sync-OC-l1lNt.js → review-status-sync-CAr-hfnJ.js} +2 -2
  221. package/server/{review-status-sync-D3KUhsdA.js → review-status-sync-CfSixhhX.js} +1 -1
  222. package/server/{review-verdict-feedback-DrWMuRaj.js → review-verdict-feedback-CVDbIDBe.js} +7 -7
  223. package/server/{review-verdict-feedback-YOzmsq9G.js → review-verdict-feedback-D2Q960wX.js} +1 -1
  224. package/server/{rollup-DmazRY0j.js → rollup-CakjztPl.js} +1 -1
  225. package/server/{rollup-CnxbwaLH.js → rollup-DctoIu-A.js} +8 -8
  226. package/server/{scanner-DE1MqAaF.js → scanner-BTM1jc_u.js} +7 -7
  227. package/server/{sequence-io-C0uoqfGx.js → sequence-io-pnoIDGv4.js} +4 -4
  228. package/server/{sequencer-agent-i-b2u4SJ.js → sequencer-agent-9Soi-WL-.js} +6 -6
  229. package/server/server.js +422 -1746
  230. package/server/{service-D0_gh2tl.js → service-DfTVoqJg.js} +46 -46
  231. package/server/{session-fork-DZ12vipL.js → session-fork-C4jAFHj8.js} +2 -2
  232. package/server/session-history-DanhhiCw.js +168 -0
  233. package/server/{settings-ByqjPtFO.js → settings-Cuc12oP_.js} +2 -2
  234. package/server/settings-Cy7SCFO9.js +2 -0
  235. package/server/{settings-DCC4BAqj.js → settings-DfT3f86D.js} +3 -3
  236. package/server/{shadow-engineering-BhnmtW5m.js → shadow-engineering-bKuKTCn-.js} +3 -3
  237. package/server/{shadow-state-ByXZehsy.js → shadow-state-CVHpRWlb.js} +1 -1
  238. package/server/{shadow-state-CKm8xWX9.js → shadow-state-DJz6_pb_.js} +2 -2
  239. package/server/{ship-log-DE_0Cv_i.js → ship-log-CwqPFfqx.js} +1 -1
  240. package/server/{smart-compaction-h4_ca6Uk.js → smart-compaction-B4KlpZGN.js} +1 -1
  241. package/server/{smart-compaction-D5Zen3AA.js → smart-compaction-CiWfGfRZ.js} +7 -7
  242. package/server/{spawn-planning-session-Dueit4WX.js → spawn-planning-session-CU-DwyDl.js} +15 -15
  243. package/server/{spawn-planning-session-Bgi7Ub02.js → spawn-planning-session-D5N3RuLG.js} +1 -1
  244. package/server/{specialist-completion-BZ8M-WZ0.js → specialist-completion-CJcv-NXH.js} +1 -1
  245. package/server/{specialist-context-BMq83C58.js → specialist-context-B2HlbNxS.js} +5 -5
  246. package/server/{specialist-handoff-logger-BxX1YefH.js → specialist-handoff-logger-CQyF1ygu.js} +2 -2
  247. package/server/{specialist-logs-BWZYcJ6P.js → specialist-logs-CdcUpfjj.js} +3 -3
  248. package/server/{specialists-BudKrjOu.js → specialists-CFgw_0Q6.js} +1657 -113
  249. package/server/{specialists-DrPrC9Y9.js → specialists-CwzFdapR.js} +18 -18
  250. package/server/{specialists-ZkW4Mb7U.js → specialists-D7AcFi1u.js} +1 -1
  251. package/server/{specialists-8ZAguXef.js → specialists-k22_Btaq.js} +1 -1
  252. package/server/specs-RzcDgozr.js +3 -0
  253. package/server/{src-DHn4Rd2F.js → src-B4TTzNSr.js} +72 -1
  254. package/server/{src-Dv6L03vW.js → src-BvpMg4EB.js} +3 -3
  255. package/server/{src-DNUUqkec.js → src-D4YUZrwR.js} +6 -6
  256. package/server/{stack-health-DxsTx7II.js → stack-health-CSgcYcr8.js} +2 -2
  257. package/server/{stack-health-Dclm7_tu.js → stack-health-DVN7zRnL.js} +1 -1
  258. package/server/{state-home-CRowbXqU.js → state-home-CEvD_v5F.js} +6 -6
  259. package/server/{state-mapping-BvAgFK8n.js → state-mapping-C13UaCL7.js} +1 -1
  260. package/server/{stuck-remediation-CFWUP8_I.js → stuck-remediation-CxsyxwFO.js} +43 -21
  261. package/server/{stuck-remediation-CLHd-lrF.js → stuck-remediation-nTIvhGOR.js} +1 -1
  262. package/server/{summary-fork-CKc01Our.js → summary-fork-CnRMPCYd.js} +2 -2
  263. package/server/{summary-fork-CtCwBJ2Z.js → summary-fork-gKSoFAnK.js} +8 -8
  264. package/server/{supervisor-BA5D72Qa.js → supervisor-CZMs8s0M.js} +2 -2
  265. package/server/supervisor-CfX192ma.js +2 -0
  266. package/server/{swarm-readiness-CL5sM9B1.js → swarm-readiness-h6-pwY8w.js} +3 -3
  267. package/server/{system-prerequisites-DmFSXIE5.js → system-prerequisites-DZZTi2G6.js} +1 -1
  268. package/server/{teardown-workspace-DWmFJzTw.js → teardown-workspace-B4D-oCVg.js} +17 -17
  269. package/server/{test-agent-queue-DjsQoV5X.js → test-agent-queue-CnuYku4B.js} +6 -6
  270. package/server/{test-verdict-BSqsQp3G.js → test-verdict-CRsPpByy.js} +1 -1
  271. package/server/{test-verdict-D1AmZ2c0.js → test-verdict-CXMLATGc.js} +1 -1
  272. package/server/{tldr-daemon-DD9rI5gA.js → tldr-daemon-CgZQ3jmZ.js} +1 -1
  273. package/server/{tldr-daemon-C-MGomL8.js → tldr-daemon-CuA8hz21.js} +2 -2
  274. package/server/{tmux-x291Gjjb.js → tmux-By8E_Yv_.js} +1 -1
  275. package/server/{tmux-C_d-lSIq.js → tmux-C3g9VFcg.js} +2 -2
  276. package/server/{token-DfBf1bsd.js → token-g_sJ19g3.js} +2 -2
  277. package/server/token-util-C9u4An3K.js +3 -0
  278. package/server/{token-util-CROoF5ic.js → token-util-DiwnnbJo.js} +1 -1
  279. package/server/{tracker-config-DItsdelv.js → tracker-config-BzfVj41Z.js} +1 -1
  280. package/server/{tracker-config-CNODpd11.js → tracker-config-dQxC15vH.js} +2 -2
  281. package/server/{tracker-utils-Ch2_5GGf.js → tracker-utils--z8FLSWn.js} +2 -2
  282. package/server/{tracker-utils-B9ZoVA9b.js → tracker-utils-DkKyRT0H.js} +1 -1
  283. package/server/{traefik-connect-BF4x_LUQ.js → traefik-connect-CZYB3dlm.js} +1 -1
  284. package/server/{tunnel-r_5nHAI6.js → tunnel-BpWZs0Jy.js} +3 -3
  285. package/server/{tunnel-YD80_IHr.js → tunnel-CN2px87h.js} +1 -1
  286. package/server/{typed-errors-DSPn_xWP.js → typed-errors-CrN1AByg.js} +1 -1
  287. package/server/{typed-errors-BEJhbjJg.js → typed-errors-sLpGfegz.js} +1 -1
  288. package/server/{types-CE1m_daD.js → types-BLS_Zbmd.js} +1 -1
  289. package/server/{types-33JEP4LZ.js → types-tlXf80x3.js} +1 -1
  290. package/server/{uat-train-DjkFWXge.js → uat-train-BRo6DM7p.js} +24 -24
  291. package/server/{uat-train-DDI00aqD.js → uat-train-utGVmqdm.js} +1 -1
  292. package/server/{validation-DUTiJnyz.js → validation-CsPVsoA0.js} +4 -4
  293. package/server/{validation-ict8hnXk.js → validation-Dq_wwcw3.js} +1 -1
  294. package/server/{verification-runner-inLgeQux.js → verification-runner-CMT5WRMS.js} +11 -11
  295. package/server/{verification-runner-ATaLbpr5.js → verification-runner-D0Uh-9jc.js} +1 -1
  296. package/server/{vtt-parser-QnRfcjiU.js → vtt-parser-C_XPlifj.js} +1 -1
  297. package/server/{work-agent-prompt-fZljjA1_.js → work-agent-prompt-ZTAb2Hyf.js} +11 -11
  298. package/server/workflows-BLwxUMP7.js +2 -0
  299. package/server/{workflows-oBnJ7Tm0.js → workflows-CXRwhw_o.js} +14 -14
  300. package/server/{workspace-B2WOW9Hw.js → workspace-9UEsKuiP.js} +1 -1
  301. package/server/{workspace-CNuW2j41.js → workspace-CNfuj1-5.js} +3 -3
  302. package/server/{workspace-config-CBgMGhWs.js → workspace-config-ChWOECy0.js} +1 -1
  303. package/server/{workspace-manager-DjUAJCSs.js → workspace-manager-BO-6k3sP.js} +1 -1
  304. package/server/{workspace-manager-CB-R07R3.js → workspace-manager-D8AByFIT.js} +13 -13
  305. package/server/{workspace-metadata-9Nn5kgRl.js → workspace-metadata-CvC268MN.js} +2 -2
  306. package/server/{workspace-metadata-Fd58uUQG.js → workspace-metadata-DZiJtnuF.js} +1 -1
  307. package/server/{workspaces-BjWXntty.js → workspaces-D-uIoqbg.js} +103 -95
  308. package/server/{writer-CQMGzEkw.js → writer-BUweuRPx.js} +1 -1
  309. package/server/{writer-fe1-8iGc.js → writer-CrP2xuBn.js} +3 -3
  310. package/sync-sources/hooks/ask-user-question-hook +7 -1
  311. package/sync-sources/hooks/record-cost-event.js +2 -2
  312. package/sync-sources/hooks/record-cost-event.js.map +1 -1
  313. package/server/agent-runtime-mirror-DrWxopNA.js +0 -37
  314. package/server/cli-ClIQwgMI.js +0 -3
  315. package/server/deacon-swarm-BY5hKNaU.js +0 -2
  316. package/server/dist-DGTwcZhI.js +0 -3
  317. package/server/forge-XlDgPQWs.js +0 -2
  318. package/server/hume-K1pi8jC4.js +0 -3
  319. package/server/inspect-agent-477VxQim.js +0 -2
  320. package/server/merge-ops-PzqsW69V.js +0 -2
  321. package/server/projects-KJ94e50I.js +0 -3
  322. package/server/public/assets/chunk-BO2N2NFS-ClukPsZQ.js +0 -103
  323. package/server/public/assets/index-DnTZ2QeN.js +0 -796
  324. package/server/public/assets/mermaid-GHXKKRXX-DZJOwgBG.js +0 -1
  325. package/server/rally-Dc2Wnxw2.js +0 -3
  326. package/server/resume-DhcIqsTm.js +0 -3
  327. package/server/settings-yydgaqhv.js +0 -2
  328. package/server/specs-DwoAEGrW.js +0 -3
  329. package/server/supervisor-DHjumXlL.js +0 -2
  330. package/server/token-util-xNaV-00f.js +0 -3
  331. package/server/workflows-tU7KKxQi.js +0 -2
package/server/server.js CHANGED
@@ -1,126 +1,124 @@
1
- import { a as __toCommonJS, i as __require, o as __toESM, t as __commonJSMin } from "./rolldown-runtime-DNCzzKnI.js";
2
- import { $ as MODEL_DEPRECATIONS, Ar as OVERDECK_HOME, B as piProviderForModel, Br as getDocsBudgetStatePath, C as init_tier_table, Cn as findProjectByTeamSync, D as canUseHarnessSync, Dt as getIssueWorkspacePath, E as validateTieredExecutionConfig, Er as CLAUDE_DIR, F as getBuiltInDefaultHarness, G as defaultBackgroundAiFeatures, Gn as resolveProjectFromIssue, Gr as getLegacyHome, Hr as getDocsIndexPath, I as getKimiAnthropicBaseUrl, J as DEFAULT_WORKHORSES, Jr as isDevMode, K as init_registry, Kn as resolveProjectFromIssueSync, Kr as getOverdeckHome, Ln as listProjects, Lr as SYNC_SOURCES, N as UnknownModelError, On as getProjectSync, Pn as init_projects, Q as MODEL_CAPABILITIES, R as getProviderForModelSync, Rn as listProjectsSync, S as TieredExecutionConfigError, Tn as getIssuePrefix, Un as registerProjectSync, Ur as getDocsTelemetryPath, Vr as getDocsDisableStatePath, Xn as setProjectAutoMergeDefaultSync, Xr as resolveOhmypiExtensionPath, Y as computeModelOrigin, Yr as packageRoot, Z as resolveModel, Zr as sessionFilePath, _ as getDefaultDocsConfig, at as resolveModelIdSync, br as init_errors, c as isClaudeCodeChannelsEnabled, d as loadConfigNoMigration, dt as ROLE_EFFORTS, er as extractPrefixSync, f as loadConfigSync, fr as GitHubApiError, g as mergeConfigs, gr as ProcessSpawnError, h as jsYaml, i as getConversationsConfig, in as init_auto_commit, it as modelSupportsImagesSync, k as init_harness_policy, kr as LOGS_DIR, kt as init_record, lt as COMPLIANCE_MODES, m as init_js_yaml, mn as resolveStateReadHomeSync, n as clearConfigCache, nn as flushAllPendingAutoCommits, nt as hasModelCapabilitySync, o as getGlobalConfigPath, or as require_dist$1, p as updateConversationsConfig, pn as init_state_read_home, q as DEFAULT_ROLES, qr as init_paths, r as getConversationSearchConfigSync, rn as flushAutoCommits, rr as parseIssueIdSync, rt as init_model_capabilities, s as init_load, t as init_config_yaml, tr as init_issue_id, tt as getModelEffortLevelsSync, u as isTldrEnabledSync, ur as FsError, ut as PARENT_MODEL_REF, v as getDefaultTtsDaemonConfig, vr as TrackerError, w as resolveTieredExecutionEnabled, xn as findProjectByPathSync, xr as AGENTS_DIR, y as mergeTtsDaemonConfigs, yn as extractTeamPrefix, z as init_providers, zr as encodeClaudeProjectDir } from "./config-yaml-Dcz-8uit.js";
3
- import { _ as getDashboardIdentity, b as shouldRefuseHostDashboardPort, c as startUatTrainReconciler, d as openFlywheelRunReportForDashboard, f as pauseFlywheelRunForDashboard, g as runDashboardDbJob, h as startFlywheelRunForDashboard, l as stopUatTrainReconciler, m as resumeFlywheelRunForDashboard, p as readCurrentFlywheelStatusForDashboard, u as abortFlywheelRunForDashboard, v as isWorkspaceRepoRoot, y as readHostDashboardApiPort } from "./uat-train-DjkFWXge.js";
4
- import { C as validateOrigin$1, D as jsonResponse, E as httpHandler, O as jsonStringResponse, T as checkCodexAuthStatus, _ as resolveJsonlPath, a as agentsRouteLayer, c as evaluateSpawnGuardrails, d as resolveConversationGitInfo, g as resolveCodexRolloutPath, h as resolveClaudeSessionId, l as invalidateAgentsCache, m as resolveAgentHarness, o as saveAgentStateAndEmitEvent, p as readLauncherPinnedSessionId, s as saveAgentStateAndEmitEventProgram, t as specialistsRouteLayer, u as resolveAgentGitInfo, v as resolvePiSessionPath, w as validateOriginHeaders, x as isTrustedOriginForHost, y as getHeaderFromMap } from "./specialists-BudKrjOu.js";
1
+ import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "./rolldown-runtime-DNCzzKnI.js";
2
+ import { $ as MODEL_DEPRECATIONS, Ar as LOGS_DIR, Br as encodeClaudeProjectDir, C as init_tier_table, D as canUseHarnessSync, Dr as CLAUDE_DIR, Dt as getIssueWorkspacePath, E as validateTieredExecutionConfig, En as getIssuePrefix, F as getBuiltInDefaultHarness, Fn as init_projects, G as defaultBackgroundAiFeatures, Hr as getDocsDisableStatePath, I as getKimiAnthropicBaseUrl, J as DEFAULT_WORKHORSES, Jr as init_paths, K as init_registry, Kn as resolveProjectFromIssue, Kr as getLegacyHome, N as UnknownModelError, Q as MODEL_CAPABILITIES, Qr as sessionFilePath, R as getProviderForModelSync, Rn as listProjects, Rr as SYNC_SOURCES, S as TieredExecutionConfigError, Sn as findProjectByPathSync, Sr as AGENTS_DIR, Ur as getDocsIndexPath, Vr as getDocsBudgetStatePath, Wn as registerProjectSync, Wr as getDocsTelemetryPath, Xr as packageRoot, Y as computeModelOrigin, Yr as isDevMode, Z as resolveModel, Zn as setProjectAutoMergeDefaultSync, _ as getDefaultDocsConfig, _r as ProcessSpawnError, at as resolveModelIdSync, bn as extractTeamPrefix, d as loadConfigNoMigration, dr as FsError, dt as ROLE_EFFORTS, f as loadConfigSync, g as mergeConfigs, h as jsYaml, hn as resolveStateReadHomeSync, i as getConversationsConfig, in as init_auto_commit, ir as parseIssueIdSync, it as modelSupportsImagesSync, jr as OVERDECK_HOME, k as init_harness_policy, kn as getProjectSync, kt as init_record, lt as COMPLIANCE_MODES, m as init_js_yaml, mn as init_state_read_home, n as clearConfigCache, nn as flushAllPendingAutoCommits, nr as init_issue_id, nt as hasModelCapabilitySync, o as getGlobalConfigPath, p as updateConversationsConfig, pr as GitHubApiError, q as DEFAULT_ROLES, qn as resolveProjectFromIssueSync, qr as getOverdeckHome, r as getConversationSearchConfigSync, rn as flushAutoCommits, rt as init_model_capabilities, s as init_load, sr as require_dist$1, t as init_config_yaml, tr as extractPrefixSync, tt as getModelEffortLevelsSync, u as isTldrEnabledSync, ut as PARENT_MODEL_REF, v as getDefaultTtsDaemonConfig, w as resolveTieredExecutionEnabled, wn as findProjectByTeamSync, xr as init_errors, y as mergeTtsDaemonConfigs, yr as TrackerError, z as init_providers, zn as listProjectsSync } from "./config-yaml-cNOZcEww.js";
3
+ import { _ as getDashboardIdentity, b as shouldRefuseHostDashboardPort, c as startUatTrainReconciler, d as openFlywheelRunReportForDashboard, f as pauseFlywheelRunForDashboard, g as runDashboardDbJob, h as startFlywheelRunForDashboard, l as stopUatTrainReconciler, m as resumeFlywheelRunForDashboard, p as readCurrentFlywheelStatusForDashboard, u as abortFlywheelRunForDashboard, v as isWorkspaceRepoRoot, y as readHostDashboardApiPort } from "./uat-train-BRo6DM7p.js";
4
+ import { $ as readLauncherPinnedSessionId, A as resolveAllowedHarness, B as cleanupUnreferencedConversationAttachments, C as handleConversationCreate, D as handleConversationStop, E as handleConversationResume, F as tmuxSessionExists, G as isManagedConversationAttachmentPath, H as extractConversationAttachmentPaths, I as waitForPiTuiReady, J as evaluateSpawnGuardrails, K as removeConversationAttachment, L as waitForTmuxSession$1, M as spawnConversationSession, N as startConversationModelBackfill, O as handleConversationSwitchModel, P as stopConversationRuntime, R as cleanupConversationAttachments, S as conversationSessionAliveFromState, T as handleConversationRestartAll, U as getConversationAttachmentsRoot, V as ensureConversationAttachmentDir, W as hasConversationAttachment, X as resolveAgentGitInfo, Y as invalidateAgentsCache, Z as resolveConversationGitInfo, _ as isPiControlChannelHarness, _t as jsonStringResponse, a as agentsRouteLayer, at as isRespawnPending, b as validateConversationControlAckOrigin, c as codexConversationPendingInput, d as handleConversationCodexApproval, dt as validateOrigin$1, et as resolveAgentHarness, f as handleConversationCompact, ft as validateOriginHeaders, g as handleConversationThinkingLevel, gt as jsonResponse, h as handleConversationPlanAction, ht as getDefaultCwd, it as resolvePiSessionPath, j as shouldReportUnresolvedLiveSession, k as isInsideGitWorkTree, l as deliverConversationViaControlChannel, lt as isTrustedOriginForHost, m as handleConversationDeliveryMethod, mt as httpHandler, nt as resolveCodexRolloutPath, o as saveAgentStateAndEmitEvent, ot as waitForSessionRespawn, p as handleConversationControlAck, pt as checkCodexAuthStatus, q as runInBatches, rt as resolveJsonlPath, s as saveAgentStateAndEmitEventProgram, st as getHeaderFromMap, t as specialistsRouteLayer, tt as resolveClaudeSessionId, u as handleConversationAbort, v as pickDeliverAs, w as handleConversationDelete, x as conversationNeedsRunningRepair, y as resolveConversationDeliveryMethod, z as cleanupOrphanedConversationAttachments } from "./specialists-CFgw_0Q6.js";
5
5
  import { a as init_activity_logger, i as emitDashboardLifecycleSync, n as emitActivityEntrySync, r as emitActivityTtsSync } from "./activity-logger-pcbf-e30.js";
6
- import { A as init_paths$1, O as OVERDECK_MIGRATION_PATH, d as getOverdeckDatabaseSync, f as init_infra, i as DbLive, k as getOverdeckDatabasePath, u as TmuxLive } from "./infra-bpq1MHKU.js";
6
+ import { A as init_paths$1, O as OVERDECK_MIGRATION_PATH, d as getOverdeckDatabaseSync, f as init_infra, i as DbLive, k as getOverdeckDatabasePath, u as TmuxLive } from "./infra-Ba9mS6e6.js";
7
7
  import { n as openDatabase, t as init_driver } from "./driver-D-HBOQa_.js";
8
- import { E as listPaneValues, F as sendKeysAsync, G as buildChildEnvSync, H as init_ui_theme, I as sendRawKeystroke, K as buildChildEnvWithoutTmuxSync, L as sessionExists, M as resizeWindow, O as listSessionNames, P as sendKeys, S as isHarnessProcessAlive, U as setUiTheme, W as BLANKED_PROVIDER_ENV, b as getWindowDimensions, c as ensureManagedTmuxContextOnce, d as exactPaneTarget, i as capturePane, k as listSessions, n as buildTmuxArgs, o as createSession, p as findManagedServerPidSync, q as init_child_env, w as killSession, x as init_tmux, z as setOption } from "./tmux-C_d-lSIq.js";
9
- import { a as init_event_store, i as initEventStore, n as getEventStore, r as getSharedDb } from "./event-store-DRte2Rwt.js";
10
- import { _ as FlywheelRunId, a as getHarnessBehavior, b as DomainEvent, c as FlywheelStats, g as WS_METHODS, h as PanRpcGroup, m as PanRpcError, o as ContextLayerSaveRequest, s as ContextPreviewRequest, t as init_src, v as FlywheelStatus, x as MemoryObservation, y as EDITORS } from "./src-DHn4Rd2F.js";
11
- import { a as fixStuckReadyForMerge, c as init_review_status, i as fixStuckCommentedReviews, l as loadReadyForMergeFlags, n as clearReviewStatus, o as getReviewStatus, r as clearStuckMergeStatuses, s as getReviewStatusSync, u as loadReviewStatuses, v as setReviewStatus, y as setReviewStatusSync } from "./review-status-4qqLkRMu.js";
12
- import { a as EventStoreService, c as ReadModelService, d as init_read_model, f as toAgentResolution, i as init_issue_lifecycle, l as ReadModelServiceLive, m as toRole, n as IssueLifecycleLive, o as EventStoreServiceLive, p as toAgentStatus, s as init_domain_services, t as IssueLifecycle } from "./issue-lifecycle-C-K53ASY.js";
13
- import { d as init_agents, i as recordBriefingSessionStart, n as ensureSessionContextBriefingFile, p as listAllAgentsSync, r as init_briefing_freshness, s as AgentsResolverLive, t as appendFreshBriefingUpdate } from "./briefing-freshness-Kh5V8RTh.js";
14
- import { i as init_paths$2, l as resolveObservationsFile, r as ensureParentDir, s as resolveIssueMemoryRoot, t as assertMemorySafeSegment } from "./paths-C9DkhIOT.js";
15
- import { n as listFeatureRegistryEntries, t as init_feature_registry_storage } from "./feature-registry-storage-CkZTFSsn.js";
16
- import { a as diffAgainstMain, c as diffCheckpoints, d as diffPatchSinceCommit, f as findCommitAtTime, h as listCheckpoints, l as diffFilesAgainstHead, m as init_checkpoint_manager, o as diffAgainstMainFiles, s as diffCheckpointFiles, t as captureCheckpoint, u as diffPatchFilesAgainstHead } from "./checkpoint-manager-fu9oVsR-.js";
17
- import { An as getAgentDir, At as init_bridge_token, Dt as captureTranscriptUserRecordSnapshot, Gt as getAgentRuntimeBaseCommand, Jn as saveAgentStateSync, Jt as getProviderAuthMode, M as init_operator_interventions, Mn as getAgentState, N as operatorInterventionEvent, Nn as getAgentStateFilePath, Ot as init_transcript_landing, Pn as getAgentStateSync, Q as listRunningAgentsSync, St as deliverAgentMessage, X as listAgentStates, Z as listRunningAgents, Zt as injectPiConversationMemory, _t as init_config, an as init_claude_auth, ar as init_pty_token, at as init_concurrency, bn as writeChannelsBridgeMcpConfig, bt as saveCloisterConfigSync, c as init_tier_supervisor, cr as resolvePtySupervisorScriptPath, dr as normalizeAgentId, en as init_pi_fifo, f as supervisorAgentId, gr as getAgentRuntimeStateSync, hn as init_openai_auth, hr as getAgentRuntimeState, in as getClaudeAuthStatus, ir as readAgentHarnessModelRecordSync, j as messageAgent, jt as writeBridgeTokenSync, kt as probeTranscriptSince, ln as getProviderEnvForModel, lr as clearReadySignal, mn as getOpenAIAuthStatus, mr as waitForReadySignal, nn as init_ohmypi_fifo, or as writePtyToken, rn as ohmypiFifoPaths, rr as init_agent_record_sync, rt as emergencyBrake, s as deliverCommitForReview, sr as init_pty_supervisor_locate, t as init_agents$1, tn as piFifoPaths, un as getProviderExportsForModel, vt as loadCloisterConfig, xt as shouldAutoStart, yn as dismissDevChannelsDialog, yt as loadCloisterConfigSync } from "./agents-CsOzAmRg.js";
18
- import { t as init_behavior } from "./behavior-Cpj03N4v.js";
19
- import { a as getCostForIssueAggregateSync, c as getDailyTrendsSync, d as init_cost_sync, l as getModelRollupSync, n as getBackgroundCostBySourceSync, p as queryCostEventsSync, r as getCavemanExperimentDataSync, s as getCostsByIssueSync, u as getTodayCostSync } from "./cost-sync-gTayEuWP.js";
20
- import { c as getAgentsNeedingAttention, d as CostResolverLive, f as CostWriter, l as CostDoorLive, n as readCloisterStateFile, o as generateHealthSummary, s as getAgentHealth, t as getCloisterService, u as CostResolver } from "./service-D0_gh2tl.js";
21
- import { n as AgentStateServiceLive } from "./agent-state-service-BZkvgQf4.js";
22
- import { a as init_tracker_config, i as initTrackerConfigCache, n as getLinearApiKey, r as getRallyConfig, t as getGitHubConfig } from "./tracker-config-CNODpd11.js";
23
- import { d as init_typed_errors, l as WorkspaceCreateError, n as AgentStartError, r as BeadsNotInitialized, s as TrackerApiError, t as AgentAlreadyRunning, u as WorkspaceNotFound } from "./typed-errors-BEJhbjJg.js";
24
- import { i as init_linear_client, r as LinearClientOptionalLive, t as LinearClient } from "./linear-client-EtVyblVz.js";
25
- import { i as init_github_client, r as GitHubClientOptionalLive, t as GitHubClient } from "./github-client-DpiZnxGH.js";
26
- import { i as init_rally_client, r as RallyClientOptionalLive, t as RallyClient } from "./rally-client-DvvLiAQP.js";
27
- import { a as resolveTrackerTypeSync, i as resolveGitHubIssueSync, n as init_tracker_utils } from "./tracker-utils-Ch2_5GGf.js";
28
- import { a as CacheService, i as startSharedIssueService, n as init_issue_service_singleton, o as init_cache_service, r as issue_service_singleton_exports, s as parseIntegerHeader, t as getSharedIssueService } from "./issue-service-singleton-CuHGpJJP.js";
29
- import { i as ensureInternalTokenSync, o as getInternalTokenSync, s as init_internal_token, t as INTERNAL_TOKEN_HEADER } from "./internal-token-CjlhdufS.js";
30
- import { a as setPipelineHandlerSync, t as init_pipeline_notifier } from "./pipeline-notifier-CAurUste.js";
31
- import { c as init_review_status_sync, i as getMergeBlockerReconcileCandidates } from "./review-status-sync-OC-l1lNt.js";
32
- import { a as PAN_DIRNAME, f as asPanSpecDocument, i as PAN_CONTINUE_FILENAME, p as init_types } from "./types-CE1m_daD.js";
33
- import { C as transitionToMerging, _ as markFailed, c as isFlywheelGloballyPaused, d as listDuePendingAutoMerges, f as listProblemAutoMerges, g as markBlocked, n as getActionableAutoMerge, o as init_merge_sync, t as cancelPending, u as listActiveAutoMerges, v as markMerged, x as scheduleAutoMergeWithResult, y as requeueToPending } from "./merge-sync-B43Dybea.js";
34
- import { C as findSpecByIssue, O as writeSpec, T as init_specs, a as findWorkspaceDraftPlan, b as init_types$1, k as writeSpecForIssue, m as readWorkspacePlanSync, o as init_io, p as readWorkspacePlan, r as findPlan, s as isPlanningComplete, u as readPlan, x as subItemsOf } from "./io-BiQ2Cs3k.js";
35
- import { C as restartCliproxy, S as readPidFile, T as stopCliproxy, b as isCliproxyInstalled, d as getCliproxyAuthDir, o as bridgeCodexAuthToCliproxy, v as init_cliproxy, w as startCliproxy, x as isCliproxyRunning, y as installCliproxy } from "./cliproxy-BsoNNDAj.js";
36
- import { f as init_config$1, m as loadConfigSync$1, s as getDashboardApiUrlSync } from "./config-ZNnMpIlh.js";
37
- import { n as require_auth_errors, r as require_token_error, t as require_token_util } from "./token-util-CROoF5ic.js";
38
- import { $ as updateConversationForkFallbackReason, A as isAgentConversationName, B as removeFavorite, C as getConversationByTmuxSession, D as importLegacyConversation, E as hasOtherActiveConversationOnTmuxSession, F as markConversationEnded, G as setConversationHarness, H as setClearedToConvId, I as markConversationRunning, J as setForkRequest, K as setConversationModel, M as listConversations, N as listFavoritedIds, O as incrementForkRetryCount, P as markConversationActive, Q as updateConversationDeliveryMethod, S as getConversationByName, T as getStuckForks, U as setConversationClaudeSessionId, W as setConversationEffort, X as unarchiveConversation, Y as setImportedConversationLinks, Z as updateConversationCost, _ as canRefineTitle, b as getConversationByClaudeSessionId, et as updateConversationTitle, g as backfillConversationModel, gt as getDiscoveredSessionBySessionId, h as archiveConversation, j as listArchivedConversationsWithEnrichment, k as init_conversations, nt as updateLastAttached, q as setFavorite, rt as updateSpawnError, tt as updateForkStatus, v as canReplaceTitle, w as getConversationLedgerCosts, x as getConversationById, y as createConversation, yt as init_discovered_sessions, z as recordConversationHandoff } from "./conversations-DG2M8WnT.js";
39
- import { _ as init_codex_conversation_parser, a as contextUsageFromParseResult, c as parseEntireConversation, d as init_pi_conversation_parser, f as isPiSessionFile, g as parseOhmypiConversationMessages, h as isOhmypiSessionFile, i as computeContextUsage, l as parseFromLastCompactBoundary, m as init_ohmypi_conversation_parser, n as gateSnapshotEmission, o as summarizeConversationActivity, p as parsePiConversationMessages, r as watchConversation, s as parseConversationMessages, t as init_conversation_service, v as parseCodexConversationMessages } from "./conversation-service-BR1OgvxO.js";
40
- import { n as isBackgroundFeatureEnabled, t as init_features } from "./features-Dtm9ABuz.js";
41
- import { i as init_settings, r as getMemoryWorkerConcurrency, t as areMemoryObservationsEnabled } from "./settings-DCC4BAqj.js";
42
- import { i as updateMemoryHealth, n as extractWithProviderPolicy, r as init_health, t as init_providers$1 } from "./providers-CWDXoaMA.js";
43
- import { a as init_launcher_generator, i as generateLauncherScriptSync, n as init_state_home, r as isStateMigrated } from "./state-home-CRowbXqU.js";
44
- import { a as init_claude_permissions, o as resolvePermissionModeSync, r as getClaudePermissionFlagsStringSync, t as BYPASS_PERMISSION_MODE } from "./claude-permissions-CaWqysff.js";
45
- import { a as globalContextFile$1, f as resolveProjectContextFile, h as workspaceContextFile, l as piGlobalContextFile, n as codexGlobalContextFile, o as init_layers, p as resolveWorkspaceContextFile, r as ensureProjectLayer } from "./layers-CD6FysRU.js";
46
- import { l as init_codex, s as findRolloutPath } from "./codex-DW60_5j2.js";
47
- import { C as setMergeTrainEnabled, S as setFlywheelRequireUatBeforeMerge, b as setFlywheelAutoPickupBacklog, c as isCloisterSpawnsPausedSync, d as isFlywheelAutoPickupBacklog, f as isFlywheelGloballyPaused$1, g as setCloisterSpawnsPausedSync, h as setBootReconciliationDecision, m as isMergeTrainEnabled, o as getSetting, p as isFlywheelRequireUatBeforeMerge, r as getBootReconciliationState, s as init_control_settings, u as isDeaconGloballyPausedSync, v as setDeaconGloballyPausedSync, w as setSetting } from "./control-settings-DwkAeooY.js";
48
- import { a as withBdProcessLock, n as init_bd_process_lock } from "./bd-process-lock-D3S4T4o-.js";
49
- import { n as init_resolver, t as createBeadsResolver } from "./resolver-dTpSSzaH.js";
50
- import { n as resolveHarness, t as init_harness_resolve } from "./harness-resolve-iMjyNUJ2.js";
51
- import { i as checkPrdGateSync, t as init_pan_dir } from "./pan-dir-Bj7Hy8iu.js";
52
- import { a as init_lifecycle_io, t as appendContinueSessionEntryForIssue } from "./lifecycle-io-CeYxP3cE.js";
53
- import { r as init_swarm_readiness, t as analyzeSwarmReadiness } from "./swarm-readiness-CL5sM9B1.js";
54
- import { _ as parseCodexApprovalPrompt, c as countPendingAskUserQuestionsForAgent, h as detectAwaitingInputFromPaneSync, l as getAgentJsonlMtime, m as detectAwaitingInputForAgent, o as getRuntimeForAgent, p as scanPendingInputsPromise, s as computeAgentEnrichment } from "./stuck-remediation-CFWUP8_I.js";
55
- import { i as CostThresholdError, l as embed, s as parseRelativeTime } from "./scanner-DE1MqAaF.js";
56
- import { c as tailEventsSync, n as deduplicateEventsSync, o as readEventsSync } from "./events-Bej1w_k8.js";
57
- import { n as recordBackgroundAiCost, t as init_cost } from "./cost-B2mj17iG.js";
58
- import { S as writeLatestFlywheelStatus, _ as readCurrentLatestFlywheelStatus, b as subscribeLatestFlywheelStatus, f as getFlywheelRunDetail, h as listFlywheelRuns, l as buildClassifyLookups, m as isFlywheelRunId, y as resolveLiveFlywheelRunId } from "./flywheel-Bv3wv2S6.js";
59
- import { C as hasDashboardInternalToken, D as getWorkspacePathForIssue, E as rejectUnsafeDashboardMutationRequest, S as dashboardSessionCookieHeader, T as rejectUnauthorizedDashboardSessionMintRequest, _ as syncCacheSync, b as resolveIssueHeadlineCost, d as reconcile, f as reconcilePiTranscripts, g as rebuildCacheSync, h as getCostsForIssueSync, l as resumeQueuedMerges, m as migrateAllSessionsSync, p as reclassifyUnknownCostEventsSync, t as workspacesRouteLayer, u as syncWalFromAllProjects, v as processPendingFeedbackDeliveries, w as rejectUnauthorizedDashboardRequest, x as dashboardCsrfToken, y as getCachedRunningAgents } from "./workspaces-BjWXntty.js";
60
- import { B as applyIssueBlocksMainLabel, Bt as getContainerHistory, F as setAgentStatusChangedNotifier, G as applyIssueVetoedLabel, Gt as startSmeeProcessSync, H as applyIssueParkedLabel, I as setAgentStoppedNotifier, J as removeIssueParkedLabel, K as removeIssueBlocksMainLabel, L as setMergeReadyNotifier, O as loadConfig, Q as createInFlightGuard, Rt as getResourceStacks, U as applyIssueReadyLabel, Ut as getSystemHealthSnapshot, V as applyIssueObjectionLabel, Vt as getCurrentDockerStats, W as applyIssueReleasedLabel, Wt as isSmeeConfiguredSync, X as removeIssueReleasedLabel, Y as removeIssueReadyLabel, Z as removeIssueVetoedLabel, _t as withConcurrencyLimit, at as listBootReconciliationCandidates, it as isBootReconciliationCandidate, k as loadState, n as assessDeaconPatrolFreshness, ot as startBootReconciliation, q as removeIssueObjectionLabel, t as applyBootReconciliationDecision, x as getDeaconLogs, zt as formatUptime } from "./deacon-DrKDBeJL.js";
61
- import { l as detectPlatform, u as init_platform } from "./workspace-manager-CB-R07R3.js";
62
- import { O as init_specialists, b as getReviewerSessionName } from "./specialists-DrPrC9Y9.js";
63
- import { c as findPrdAtStatusSync, l as init_prd_locations } from "./archive-planning-DkivCk1A.js";
64
- import { a as getShadowState, s as init_shadow_state } from "./shadow-state-CKm8xWX9.js";
65
- import { T as verifyAppCanMerge, d as getPullRequestState, f as init_github_app, l as getMergeBackendStatus, p as isGitHubAppConfigured } from "./github-app-DscZ0_B6.js";
66
- import { n as init_issue_closed, t as clearIssueClosedCache } from "./issue-closed-FApNiOOs.js";
67
- import { a as writeFeedbackFile, i as init_feedback_writer } from "./feedback-writer-fdE1BzeL.js";
68
- import { a as init_boot_gates, i as formatBootGateState, o as resolveBootGates } from "./no-resume-mode-yrPEQ_pC.js";
69
- import { c as computeCohort, d as computeStats, f as computeWaves, h as selectNeedsPlanning, l as computeEpicGroups, m as normalizeGate, s as classifyIssue, u as computeLanes } from "./pickup-CKRuGDsB.js";
70
- import { n as parseSequenceMd, r as writeSequenceMd, t as init_sequence_io } from "./sequence-io-C0uoqfGx.js";
71
- import { a as loadWorkspaceMetadataSync } from "./workspace-metadata-9Nn5kgRl.js";
72
- import { l as withBdMutex } from "./beads-BGGxrkZ5.js";
73
- import { i as resolveAutoSpawnOnFinalize, o as spawnPlanningSession } from "./spawn-planning-session-Dueit4WX.js";
74
- import { d as killRemoteAgent, m as loadRemoteAgentState, o as getRemoteAgentOutput, r as checkRemoteSpendCap, s as init_remote_agents, v as sendToRemoteAgent, y as spawnRemoteAgent } from "./remote-agents-BfQBE6MN.js";
75
- import { r as spawnInspectAgent } from "./inspect-agent-DytCsltn.js";
76
- import { a as init_telemetry, i as getBeadsHealth, o as recordBeadsPull, s as recordBeadsSyncError } from "./writer-fe1-8iGc.js";
77
- import { n as init_github_pr_lookup, r as lookupPullRequestNumberForBranch, t as githubPrLookupSource } from "./github-pr-lookup-D-EBexxC.js";
78
- import { a as init_pull_requests, c as getIssuePrTabCacheGeneration, i as fetchIssuePullRequestDiff, l as init_pr_tab_cache, n as fetchIssuePullRequest, o as bumpIssuePrTabCacheGeneration, r as fetchIssuePullRequestDetails, s as getCachedIssuePrTabResponse, t as fetchIssueCheckRuns, u as setCachedIssuePrTabResponse } from "./pull-requests-Bmre-Xlz.js";
79
- import { t as enrichReviewStatus } from "./review-status-enrichment-Cr8m3uVL.js";
80
- import { i as runMemoryFtsTransaction, n as init_fts_db, r as runMemoryFtsStatement, t as closeMemoryFtsDatabases } from "./fts-db-CBgBLZcL.js";
81
- import { c as init_pending, l as maybeTriggerStatusRollup, o as readRecentObservations, r as init_rollup, u as writePendingTurn } from "./rollup-CnxbwaLH.js";
82
- import { n as getTldrDaemonServiceSync, r as init_tldr_daemon } from "./tldr-daemon-C-MGomL8.js";
83
- import { T as listGitOperationsSync, w as init_git_activity } from "./merge-agent-4Zhlgvqp.js";
84
- import { t as getAgentCommandSync } from "./settings-ByqjPtFO.js";
85
- import { n as init_review_agent, r as isExtendedReviewEnabled } from "./review-agent-D025Wt7w.js";
86
- import { r as isRemoteAvailable, t as createFlyProviderFromConfig } from "./remote-8W2Yhygw.js";
87
- import { n as init_claude_settings_overlay, t as detectProviderEnvConflicts } from "./claude-settings-overlay-CcTf0xzG.js";
88
- import { a as init_query_expansion, i as clearQueryExpansionCache, n as init_injection, o as buildMatchQuery, r as injectPromptTimeMemory, s as init_search } from "./injection-DJqWld1v.js";
89
- import { _ as init_transcript_adapter, a as generateFallbackSummary, c as handoffPreconditionFallbackReason, d as prependFallbackFocus, f as requestHandoffFromAgent, g as getTranscriptAdapter, i as copySessionFromCompactBoundary, l as init_summary_fork, o as generateSummaryForFork, p as reserveSummaryForkSession, r as authorHandoffExternal, s as handoffFailureReason, u as logHandoffFallback } from "./summary-fork-CtCwBJ2Z.js";
90
- import { a as init_conversation_compaction, c as shouldInterceptManualCompact, n as compactConversationNative, o as isCompacting } from "./conversation-compaction-OTYgd6eg.js";
91
- import { a as init_render, d as validateTemplate, i as hasManagedRegion, l as init_harness, o as userContentOutsideRegion, t as init_context_layers, u as renderForHarness } from "./context-layers-BdUCQ-cl.js";
92
- import { r as parseArtifactRef } from "./forge-ButEdJ31.js";
93
- import { t as getMergeBlockersPayload } from "./merge-blockers-Bto_Oe_o.js";
94
- import { a as spawnSequencerAgent, i as init_sequencer_agent, n as clearFinishedSequencerRun, r as getSequencerRunStatus, t as SEQUENCER_AGENT_ID } from "./sequencer-agent-i-b2u4SJ.js";
95
- import "./supervisor-BA5D72Qa.js";
96
- import { i as listTranscriptCheckpoints, r as getTranscriptCheckpoint$1 } from "./checkpoints-1BqOlS4q.js";
8
+ import { E as listPaneValues, G as buildChildEnvSync, H as init_ui_theme, K as buildChildEnvWithoutTmuxSync, L as sessionExists, M as resizeWindow, O as listSessionNames, P as sendKeys, S as isHarnessProcessAlive, U as setUiTheme, b as getWindowDimensions, c as ensureManagedTmuxContextOnce, i as capturePane, k as listSessions, n as buildTmuxArgs, o as createSession, q as init_child_env, w as killSession, x as init_tmux } from "./tmux-C3g9VFcg.js";
9
+ import { a as init_event_store, i as initEventStore, n as getEventStore, r as getSharedDb } from "./event-store-D89fMfXS.js";
10
+ import { _ as FlywheelRunId, a as getHarnessBehavior, b as DomainEvent, c as FlywheelStats, g as WS_METHODS, h as PanRpcGroup, m as PanRpcError, o as ContextLayerSaveRequest, s as ContextPreviewRequest, t as init_src, v as FlywheelStatus, x as MemoryObservation, y as EDITORS } from "./src-B4TTzNSr.js";
11
+ import { a as fixStuckReadyForMerge, c as init_review_status, i as fixStuckCommentedReviews, l as loadReadyForMergeFlags, n as clearReviewStatus, o as getReviewStatus, r as clearStuckMergeStatuses, s as getReviewStatusSync, u as loadReviewStatuses, v as setReviewStatus, y as setReviewStatusSync } from "./review-status-Dc1l4dVz.js";
12
+ import { a as EventStoreService, c as ReadModelService, d as init_read_model, f as toAgentResolution, i as init_issue_lifecycle, l as ReadModelServiceLive, m as toRole, n as IssueLifecycleLive, o as EventStoreServiceLive, p as toAgentStatus, s as init_domain_services, t as IssueLifecycle } from "./issue-lifecycle--8MRxrG1.js";
13
+ import { d as init_agents, i as recordBriefingSessionStart, n as ensureSessionContextBriefingFile, p as listAllAgentsSync, r as init_briefing_freshness, s as AgentsResolverLive, t as appendFreshBriefingUpdate } from "./briefing-freshness-DESTCWo-.js";
14
+ import { i as init_paths$2, l as resolveObservationsFile, r as ensureParentDir, s as resolveIssueMemoryRoot, t as assertMemorySafeSegment } from "./paths-Blj6A9AJ.js";
15
+ import { n as listFeatureRegistryEntries, t as init_feature_registry_storage } from "./feature-registry-storage-BeXmNBwK.js";
16
+ import { a as diffAgainstMain, c as diffCheckpoints, d as diffPatchSinceCommit, f as findCommitAtTime, h as listCheckpoints, l as diffFilesAgainstHead, m as init_checkpoint_manager, o as diffAgainstMainFiles, s as diffCheckpointFiles, t as captureCheckpoint, u as diffPatchFilesAgainstHead } from "./checkpoint-manager-BwFdegJF.js";
17
+ import { An as getAgentDir, Dt as captureTranscriptUserRecordSnapshot, Jn as saveAgentStateSync, Jt as getProviderAuthMode, M as init_operator_interventions, Mn as getAgentState, N as operatorInterventionEvent, Nn as getAgentStateFilePath, Ot as init_transcript_landing, Pn as getAgentStateSync, Q as listRunningAgentsSync, St as deliverAgentMessage, X as listAgentStates, Z as listRunningAgents, Zt as injectPiConversationMemory, _t as init_config, an as init_claude_auth, at as init_concurrency, bt as saveCloisterConfigSync, c as init_tier_supervisor, cr as normalizeAgentId, dr as waitForReadySignal, er as init_agent_record_sync, f as supervisorAgentId, fr as getAgentRuntimeState, hn as init_openai_auth, in as getClaudeAuthStatus, j as messageAgent, kt as probeTranscriptSince, ln as getProviderEnvForModel, mn as getOpenAIAuthStatus, pr as getAgentRuntimeStateSync, rt as emergencyBrake, s as deliverCommitForReview, t as init_agents$1, tr as readAgentHarnessModelRecordSync, vt as loadCloisterConfig, xt as shouldAutoStart, yt as loadCloisterConfigSync } from "./agents-B9GwfCyp.js";
18
+ import { a as getCostForIssueAggregateSync, c as getDailyTrendsSync, d as init_cost_sync, l as getModelRollupSync, n as getBackgroundCostBySourceSync, p as queryCostEventsSync, r as getCavemanExperimentDataSync, s as getCostsByIssueSync, u as getTodayCostSync } from "./cost-sync-DF6odxK9.js";
19
+ import { c as getAgentsNeedingAttention, d as CostResolverLive, f as CostWriter, l as CostDoorLive, n as readCloisterStateFile, o as generateHealthSummary, s as getAgentHealth, t as getCloisterService, u as CostResolver } from "./service-DfTVoqJg.js";
20
+ import { t as init_behavior } from "./behavior-BTpYbAv4.js";
21
+ import { n as AgentStateServiceLive } from "./agent-state-service-DFslS5go.js";
22
+ import { a as init_tracker_config, i as initTrackerConfigCache, n as getLinearApiKey, r as getRallyConfig, t as getGitHubConfig } from "./tracker-config-dQxC15vH.js";
23
+ import { d as init_typed_errors, l as WorkspaceCreateError, n as AgentStartError, r as BeadsNotInitialized, s as TrackerApiError, t as AgentAlreadyRunning, u as WorkspaceNotFound } from "./typed-errors-sLpGfegz.js";
24
+ import { i as init_linear_client, r as LinearClientOptionalLive, t as LinearClient } from "./linear-client-D9cSQfvD.js";
25
+ import { i as init_github_client, r as GitHubClientOptionalLive, t as GitHubClient } from "./github-client-Btyy3uan.js";
26
+ import { i as init_rally_client, r as RallyClientOptionalLive, t as RallyClient } from "./rally-client-sErNQBO0.js";
27
+ import { a as resolveTrackerTypeSync, i as resolveGitHubIssueSync, n as init_tracker_utils } from "./tracker-utils--z8FLSWn.js";
28
+ import { a as CacheService, i as startSharedIssueService, n as init_issue_service_singleton, o as init_cache_service, r as issue_service_singleton_exports, s as parseIntegerHeader, t as getSharedIssueService } from "./issue-service-singleton-CkTUI-eu.js";
29
+ import { i as ensureInternalTokenSync, o as getInternalTokenSync, s as init_internal_token, t as INTERNAL_TOKEN_HEADER } from "./internal-token-BtqSbKTx.js";
30
+ import { a as setPipelineHandlerSync, t as init_pipeline_notifier } from "./pipeline-notifier-D_WYtEwl.js";
31
+ import { c as init_review_status_sync, i as getMergeBlockerReconcileCandidates } from "./review-status-sync-CAr-hfnJ.js";
32
+ import { a as PAN_DIRNAME, f as asPanSpecDocument, i as PAN_CONTINUE_FILENAME, p as init_types } from "./types-BLS_Zbmd.js";
33
+ import { C as transitionToMerging, _ as markFailed, c as isFlywheelGloballyPaused, d as listDuePendingAutoMerges, f as listProblemAutoMerges, g as markBlocked, n as getActionableAutoMerge, o as init_merge_sync, t as cancelPending, u as listActiveAutoMerges, v as markMerged, x as scheduleAutoMergeWithResult, y as requeueToPending } from "./merge-sync-D7jWLgCC.js";
34
+ import { C as findSpecByIssue, D as writeSpec, O as writeSpecForIssue, T as init_specs, a as findWorkspaceDraftPlan, b as init_types$1, m as readWorkspacePlanSync, o as init_io, p as readWorkspacePlan, r as findPlan, s as isPlanningComplete, u as readPlan, x as subItemsOf } from "./io-VEGSAqsd.js";
35
+ import { C as restartCliproxy, S as readPidFile, T as stopCliproxy, b as isCliproxyInstalled, d as getCliproxyAuthDir, o as bridgeCodexAuthToCliproxy, v as init_cliproxy, w as startCliproxy, x as isCliproxyRunning, y as installCliproxy } from "./cliproxy-B4c1BUvs.js";
36
+ import { f as init_config$1, m as loadConfigSync$1, s as getDashboardApiUrlSync } from "./config-DVLdmnMJ.js";
37
+ import { n as require_auth_errors, r as require_token_error, t as require_token_util } from "./token-util-DiwnnbJo.js";
38
+ import { $ as updateConversationForkFallbackReason, A as isAgentConversationName, B as removeFavorite, C as getConversationByTmuxSession, D as importLegacyConversation, F as markConversationEnded, H as setClearedToConvId, I as markConversationRunning, J as setForkRequest, M as listConversations, N as listFavoritedIds, O as incrementForkRetryCount, P as markConversationActive, S as getConversationByName, T as getStuckForks, U as setConversationClaudeSessionId, X as unarchiveConversation, Y as setImportedConversationLinks, Z as updateConversationCost, _ as canRefineTitle, b as getConversationByClaudeSessionId, et as updateConversationTitle, gt as getDiscoveredSessionBySessionId, h as archiveConversation, j as listArchivedConversationsWithEnrichment, k as init_conversations, q as setFavorite, tt as updateForkStatus, v as canReplaceTitle, w as getConversationLedgerCosts, x as getConversationById, y as createConversation, yt as init_discovered_sessions, z as recordConversationHandoff } from "./conversations-B-lcHv-5.js";
39
+ import { _ as init_codex_conversation_parser, a as contextUsageFromParseResult, c as parseEntireConversation, d as init_pi_conversation_parser, f as isPiSessionFile, g as parseOhmypiConversationMessages, h as isOhmypiSessionFile, i as computeContextUsage, l as parseFromLastCompactBoundary, m as init_ohmypi_conversation_parser, n as gateSnapshotEmission, o as summarizeConversationActivity, p as parsePiConversationMessages, r as watchConversation, s as parseConversationMessages, t as init_conversation_service, v as parseCodexConversationMessages } from "./conversation-service-B8LFQQm1.js";
40
+ import { n as isBackgroundFeatureEnabled, t as init_features } from "./features-u5XeMaOK.js";
41
+ import { i as init_settings, r as getMemoryWorkerConcurrency, t as areMemoryObservationsEnabled } from "./settings-DfT3f86D.js";
42
+ import { i as updateMemoryHealth, n as extractWithProviderPolicy, r as init_health, t as init_providers$1 } from "./providers-BbEyFhPX.js";
43
+ import { a as init_launcher_generator, i as generateLauncherScriptSync, n as init_state_home, r as isStateMigrated } from "./state-home-CEvD_v5F.js";
44
+ import { a as init_claude_permissions, r as getClaudePermissionFlagsStringSync } from "./claude-permissions-CThLgf8d.js";
45
+ import { a as globalContextFile$1, f as resolveProjectContextFile, h as workspaceContextFile, n as codexGlobalContextFile, o as init_layers, p as resolveWorkspaceContextFile, r as ensureProjectLayer } from "./layers-jjL16At6.js";
46
+ import { l as init_codex, s as findRolloutPath } from "./codex-BbqIRZjd.js";
47
+ import { C as setMergeTrainEnabled, S as setFlywheelRequireUatBeforeMerge, b as setFlywheelAutoPickupBacklog, c as isCloisterSpawnsPausedSync, d as isFlywheelAutoPickupBacklog, f as isFlywheelGloballyPaused$1, g as setCloisterSpawnsPausedSync, h as setBootReconciliationDecision, m as isMergeTrainEnabled, o as getSetting, p as isFlywheelRequireUatBeforeMerge, r as getBootReconciliationState, s as init_control_settings, u as isDeaconGloballyPausedSync, v as setDeaconGloballyPausedSync, w as setSetting } from "./control-settings-D4EFsRBd.js";
48
+ import { a as withBdProcessLock, n as init_bd_process_lock } from "./bd-process-lock-XAXAet9O.js";
49
+ import { n as init_resolver, t as createBeadsResolver } from "./resolver-C7dLn8OK.js";
50
+ import { i as checkPrdGateSync, t as init_pan_dir } from "./pan-dir-CQIfKG8c.js";
51
+ import { a as init_lifecycle_io, t as appendContinueSessionEntryForIssue } from "./lifecycle-io-IehcRt2v.js";
52
+ import { r as init_swarm_readiness, t as analyzeSwarmReadiness } from "./swarm-readiness-h6-pwY8w.js";
53
+ import { c as countPendingAskUserQuestionsForAgent, h as detectAwaitingInputFromPaneSync, l as getAgentJsonlMtime, m as detectAwaitingInputForAgent, o as getRuntimeForAgent, p as scanPendingInputsPromise, s as computeAgentEnrichment } from "./stuck-remediation-CxsyxwFO.js";
54
+ import { i as CostThresholdError, l as embed, s as parseRelativeTime } from "./scanner-BTM1jc_u.js";
55
+ import { c as tailEventsSync, n as deduplicateEventsSync, o as readEventsSync } from "./events-S_C0pvl6.js";
56
+ import { n as recordBackgroundAiCost, t as init_cost } from "./cost-BcpRQ-7o.js";
57
+ import { S as writeLatestFlywheelStatus, _ as readCurrentLatestFlywheelStatus, b as subscribeLatestFlywheelStatus, f as getFlywheelRunDetail, h as listFlywheelRuns, l as buildClassifyLookups, m as isFlywheelRunId, y as resolveLiveFlywheelRunId } from "./flywheel-Dczmgchd.js";
58
+ import { C as hasDashboardInternalToken, D as getWorkspacePathForIssue, E as rejectUnsafeDashboardMutationRequest, S as dashboardSessionCookieHeader, T as rejectUnauthorizedDashboardSessionMintRequest, _ as syncCacheSync, b as resolveIssueHeadlineCost, d as reconcile, f as reconcilePiTranscripts, g as rebuildCacheSync, h as getCostsForIssueSync, l as resumeQueuedMerges, m as migrateAllSessionsSync, p as reclassifyUnknownCostEventsSync, t as workspacesRouteLayer, u as syncWalFromAllProjects, v as processPendingFeedbackDeliveries, w as rejectUnauthorizedDashboardRequest, x as dashboardCsrfToken, y as getCachedRunningAgents } from "./workspaces-D-uIoqbg.js";
59
+ import { B as applyIssueBlocksMainLabel, Bt as getContainerHistory, F as setAgentStatusChangedNotifier, G as applyIssueVetoedLabel, Gt as startSmeeProcessSync, H as applyIssueParkedLabel, I as setAgentStoppedNotifier, J as removeIssueParkedLabel, K as removeIssueBlocksMainLabel, L as setMergeReadyNotifier, O as loadConfig, Q as createInFlightGuard, Rt as getResourceStacks, U as applyIssueReadyLabel, Ut as getSystemHealthSnapshot, V as applyIssueObjectionLabel, Vt as getCurrentDockerStats, W as applyIssueReleasedLabel, Wt as isSmeeConfiguredSync, X as removeIssueReleasedLabel, Y as removeIssueReadyLabel, Z as removeIssueVetoedLabel, _t as withConcurrencyLimit, at as listBootReconciliationCandidates, it as isBootReconciliationCandidate, k as loadState, n as assessDeaconPatrolFreshness, ot as startBootReconciliation, q as removeIssueObjectionLabel, t as applyBootReconciliationDecision, x as getDeaconLogs, zt as formatUptime } from "./deacon-DdARMjZq.js";
60
+ import { l as detectPlatform, u as init_platform } from "./workspace-manager-D8AByFIT.js";
61
+ import { O as init_specialists, b as getReviewerSessionName } from "./specialists-CwzFdapR.js";
62
+ import { c as findPrdAtStatusSync, l as init_prd_locations } from "./archive-planning-CbghE9-o.js";
63
+ import { a as getShadowState, s as init_shadow_state } from "./shadow-state-DJz6_pb_.js";
64
+ import { T as verifyAppCanMerge, d as getPullRequestState, f as init_github_app, l as getMergeBackendStatus, p as isGitHubAppConfigured } from "./github-app-u9-SX7Gc.js";
65
+ import { n as init_issue_closed, t as clearIssueClosedCache } from "./issue-closed-BxcePXL-.js";
66
+ import { a as writeFeedbackFile, i as init_feedback_writer } from "./feedback-writer-D20HSXre.js";
67
+ import { a as init_boot_gates, i as formatBootGateState, o as resolveBootGates } from "./no-resume-mode-Gh5R_YLF.js";
68
+ import { c as computeCohort, d as computeStats, f as computeWaves, h as selectNeedsPlanning, l as computeEpicGroups, m as normalizeGate, s as classifyIssue, u as computeLanes } from "./pickup-BtvRBbvI.js";
69
+ import { n as parseSequenceMd, r as writeSequenceMd, t as init_sequence_io } from "./sequence-io-pnoIDGv4.js";
70
+ import { a as loadWorkspaceMetadataSync } from "./workspace-metadata-CvC268MN.js";
71
+ import { l as withBdMutex } from "./beads-BeSMEjGT.js";
72
+ import { i as resolveAutoSpawnOnFinalize, o as spawnPlanningSession } from "./spawn-planning-session-CU-DwyDl.js";
73
+ import { d as killRemoteAgent, m as loadRemoteAgentState, o as getRemoteAgentOutput, r as checkRemoteSpendCap, s as init_remote_agents, v as sendToRemoteAgent, y as spawnRemoteAgent } from "./remote-agents-C4cyxHQS.js";
74
+ import { r as spawnInspectAgent } from "./inspect-agent-B-mnb4uh.js";
75
+ import { a as init_telemetry, i as getBeadsHealth, o as recordBeadsPull, s as recordBeadsSyncError } from "./writer-CrP2xuBn.js";
76
+ import { n as init_github_pr_lookup, r as lookupPullRequestNumberForBranch, t as githubPrLookupSource } from "./github-pr-lookup-DOF1U2WW.js";
77
+ import { a as init_pull_requests, c as getIssuePrTabCacheGeneration, i as fetchIssuePullRequestDiff, l as init_pr_tab_cache, n as fetchIssuePullRequest, o as bumpIssuePrTabCacheGeneration, r as fetchIssuePullRequestDetails, s as getCachedIssuePrTabResponse, t as fetchIssueCheckRuns, u as setCachedIssuePrTabResponse } from "./pull-requests-DyUkQl4W.js";
78
+ import { t as enrichReviewStatus } from "./review-status-enrichment-C1a1OG_1.js";
79
+ import { i as runMemoryFtsTransaction, n as init_fts_db, r as runMemoryFtsStatement, t as closeMemoryFtsDatabases } from "./fts-db-C5A_TTOM.js";
80
+ import { c as init_pending, l as maybeTriggerStatusRollup, o as readRecentObservations, r as init_rollup, u as writePendingTurn } from "./rollup-DctoIu-A.js";
81
+ import { n as getTldrDaemonServiceSync, r as init_tldr_daemon } from "./tldr-daemon-CuA8hz21.js";
82
+ import { T as listGitOperationsSync, w as init_git_activity } from "./merge-agent-B3u2szOL.js";
83
+ import { t as getAgentCommandSync } from "./settings-Cuc12oP_.js";
84
+ import { n as init_review_agent, r as isExtendedReviewEnabled } from "./review-agent-Dn-yn7Zj.js";
85
+ import { r as isRemoteAvailable, t as createFlyProviderFromConfig } from "./remote-DcO9An_f.js";
86
+ import { n as init_claude_settings_overlay, t as detectProviderEnvConflicts } from "./claude-settings-overlay-BF9MPIwx.js";
87
+ import { a as init_query_expansion, i as clearQueryExpansionCache, n as init_injection, o as buildMatchQuery, r as injectPromptTimeMemory, s as init_search } from "./injection-yrMBxzVq.js";
88
+ import { _ as init_transcript_adapter, a as generateFallbackSummary, c as handoffPreconditionFallbackReason, d as prependFallbackFocus, f as requestHandoffFromAgent, g as getTranscriptAdapter, i as copySessionFromCompactBoundary, l as init_summary_fork, o as generateSummaryForFork, p as reserveSummaryForkSession, r as authorHandoffExternal, s as handoffFailureReason, u as logHandoffFallback } from "./summary-fork-gKSoFAnK.js";
89
+ import { a as init_conversation_compaction, c as shouldInterceptManualCompact, n as compactConversationNative, o as isCompacting } from "./conversation-compaction-BCggyih4.js";
90
+ import { a as init_render, d as validateTemplate, i as hasManagedRegion, l as init_harness, o as userContentOutsideRegion, t as init_context_layers, u as renderForHarness } from "./context-layers-c0JqYHcS.js";
91
+ import { r as parseArtifactRef } from "./forge-DFDThFil.js";
92
+ import { t as getMergeBlockersPayload } from "./merge-blockers-cq-aS2KG.js";
93
+ import { a as spawnSequencerAgent, i as init_sequencer_agent, n as clearFinishedSequencerRun, r as getSequencerRunStatus, t as SEQUENCER_AGENT_ID } from "./sequencer-agent-9Soi-WL-.js";
94
+ import "./supervisor-CZMs8s0M.js";
95
+ import { i as listTranscriptCheckpoints, r as getTranscriptCheckpoint$1 } from "./checkpoints-BtUonbs3.js";
97
96
  import { createRequire } from "node:module";
98
97
  import * as sp from "node:path";
99
98
  import { basename, delimiter, dirname, extname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
100
99
  import { Cause, Context, Data, Duration, Effect, Exit, Fiber, FileSystem, Layer, Option, Path, Queue, Result, Schedule, Schema, Stream } from "effect";
101
- import { createReadStream, createWriteStream, existsSync, fstatSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
100
+ import { createReadStream, createWriteStream, existsSync, fstatSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
102
101
  import { basename as basename$1, dirname as dirname$1, join as join$1, resolve as resolve$1 } from "path";
103
102
  import { homedir } from "os";
104
103
  import { freemem as freemem$1, homedir as homedir$1, loadavg as loadavg$1, totalmem as totalmem$1, type } from "node:os";
105
- import { constants, createReadStream as createReadStream$1, existsSync as existsSync$1, mkdirSync as mkdirSync$1, promises as promises$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, readlinkSync, realpathSync as realpathSync$1, renameSync as renameSync$1, rmSync as rmSync$1, stat, statSync as statSync$1, symlinkSync as symlinkSync$1, unwatchFile, watch, watchFile, writeFileSync as writeFileSync$1 } from "node:fs";
104
+ import { constants, createReadStream as createReadStream$1, existsSync as existsSync$1, mkdirSync as mkdirSync$1, promises as promises$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, readlinkSync, renameSync as renameSync$1, rmSync as rmSync$1, stat, statSync as statSync$1, symlinkSync as symlinkSync$1, unwatchFile, watch, watchFile } from "node:fs";
106
105
  import { FetchHttpClient, HttpRouter, HttpServer, HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
107
106
  import { EventEmitter } from "node:events";
108
107
  import { access, appendFile, chmod, lstat, mkdir, open, readFile, readdir, realpath, rename, rm, stat as stat$1, unlink, writeFile } from "node:fs/promises";
109
108
  import { createHash, randomUUID } from "crypto";
110
109
  import { appendFile as appendFile$1, chmod as chmod$1, mkdir as mkdir$1, open as open$1, readFile as readFile$1, readdir as readdir$1, rename as rename$1, stat as stat$2, unlink as unlink$1, writeFile as writeFile$1 } from "fs/promises";
111
- import { exec, execFile, execFileSync, execSync, fork, spawn } from "node:child_process";
110
+ import { exec, execFile, execFileSync, fork, spawn } from "node:child_process";
112
111
  import { promisify } from "node:util";
113
112
  import { createHmac, randomBytes, randomUUID as randomUUID$1, timingSafeEqual } from "node:crypto";
114
113
  import * as pty from "@homebridge/node-pty-prebuilt-multiarch";
115
114
  import { Buffer as Buffer$1 } from "node:buffer";
116
115
  import { PassThrough, Readable } from "node:stream";
117
- import { fileURLToPath, pathToFileURL } from "node:url";
116
+ import { fileURLToPath } from "node:url";
118
117
  import { RpcSerialization, RpcServer } from "effect/unstable/rpc";
119
118
  import { layer } from "@effect/platform-node/NodeServices";
120
119
  import { createInterface } from "readline";
121
120
  import { Worker } from "node:worker_threads";
122
121
  import { monitorEventLoopDelay } from "node:perf_hooks";
123
- import { createInterface as createInterface$1 } from "node:readline";
124
122
  import * as Multipart from "effect/unstable/http/Multipart";
125
123
  //#region path-env.ts
126
124
  /**
@@ -458,7 +456,7 @@ var NodePtyProcess = class {
458
456
  };
459
457
  }
460
458
  };
461
- async function waitForTmuxSession$1(sessionName, timeoutMs = 6e4) {
459
+ async function waitForTmuxSession(sessionName, timeoutMs = 6e4) {
462
460
  const start = Date.now();
463
461
  while (Date.now() - start < timeoutMs) {
464
462
  if (await Effect.runPromise(sessionExists(sessionName))) return;
@@ -523,7 +521,7 @@ const TerminalServiceLive = Layer.effect(TerminalService, Effect.sync(() => {
523
521
  state.lastCols = cols;
524
522
  state.lastRows = rows;
525
523
  console.log(`[terminal-service] Spawning PTY for ${state.sessionName} at ${cols}x${rows}`);
526
- Promise.all([waitForTmuxSession$1(state.sessionName), getNodePty()]).then(() => {
524
+ Promise.all([waitForTmuxSession(state.sessionName), getNodePty()]).then(() => {
527
525
  const proc = spawnPtyImmediate(state.sessionName, cols, rows);
528
526
  state.ptyProcess = proc;
529
527
  let chunkCount = 0;
@@ -680,7 +678,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
680
678
  const beadsDir = join(workspacePath, ".beads");
681
679
  const projectBeadsDir = join(workspacePath, "..", "..", ".beads");
682
680
  if (!(existsSync$1(beadsDir) || existsSync$1(projectBeadsDir))) throw new BeadsNotInitialized({ workspace: workspacePath });
683
- const { getAgentState, spawnAgent, normalizeAgentId } = await import("./agents-DCvyTXNU.js");
681
+ const { getAgentState, spawnAgent, normalizeAgentId } = await import("./agents-CEcaxSkR.js");
684
682
  const normalizedId = normalizeAgentId(issueId);
685
683
  if ((await Effect.runPromise(getAgentState(normalizedId)))?.status === "running") throw new AgentAlreadyRunning({ id: issueId });
686
684
  return {
@@ -711,7 +709,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
711
709
  const { workspacePath, projectPath, issue } = opts;
712
710
  if (!existsSync$1(workspacePath)) throw new WorkspaceNotFound({ id: issueId });
713
711
  const sessionName = opts.sessionName ?? `planning-${issueId.toLowerCase()}`;
714
- const { spawnPlanningSession } = await import("./spawn-planning-session-Bgi7Ub02.js");
712
+ const { spawnPlanningSession } = await import("./spawn-planning-session-D5N3RuLG.js");
715
713
  const result = await spawnPlanningSession({
716
714
  issue: {
717
715
  id: issue.id,
@@ -744,14 +742,14 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
744
742
  }),
745
743
  kill: (agentId) => Effect.tryPromise({
746
744
  try: async () => {
747
- const { stopAgent } = await import("./agents-DCvyTXNU.js");
745
+ const { stopAgent } = await import("./agents-CEcaxSkR.js");
748
746
  await Effect.runPromise(stopAgent(agentId));
749
747
  },
750
748
  catch: () => void 0
751
749
  }).pipe(Effect.ignore),
752
750
  message: (agentId, msg) => Effect.tryPromise({
753
751
  try: async () => {
754
- const { messageAgent } = await import("./agents-DCvyTXNU.js");
752
+ const { messageAgent } = await import("./agents-CEcaxSkR.js");
755
753
  await messageAgent(agentId, msg);
756
754
  },
757
755
  catch: (err) => new AgentStartError({
@@ -762,8 +760,8 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
762
760
  }),
763
761
  deepWipe: (issueId, opts) => Effect.tryPromise({
764
762
  try: async () => {
765
- const { deepWipe } = await import("./workflows-tU7KKxQi.js");
766
- const { resolveProjectFromIssueSync } = await import("./projects-KJ94e50I.js");
763
+ const { deepWipe } = await import("./workflows-BLwxUMP7.js");
764
+ const { resolveProjectFromIssueSync } = await import("./projects-CrBE6IhN.js");
767
765
  const project = resolveProjectFromIssueSync(issueId);
768
766
  const projectPath = project?.projectPath ?? process.cwd();
769
767
  await Effect.runPromise(deepWipe({
@@ -792,7 +790,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
792
790
  * Route handlers and AgentSpawner use this instead of calling workspace-manager directly.
793
791
  */
794
792
  init_typed_errors();
795
- const execAsync$11 = promisify(exec);
793
+ const execAsync$10 = promisify(exec);
796
794
  var WorkspaceService = class extends Context.Service()("overdeck/dashboard/WorkspaceService") {};
797
795
  const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
798
796
  function getWorkspacePath(issueId) {
@@ -819,8 +817,8 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
819
817
  const { workspacePath, branch } = getWorkspacePath(issueId);
820
818
  const issueLower = issueId.toLowerCase();
821
819
  if (existsSync$1(workspacePath)) return workspacePath;
822
- const { createWorkspace } = await import("./workspace-manager-DjUAJCSs.js");
823
- const { loadProjectsConfigSync } = await import("./projects-KJ94e50I.js");
820
+ const { createWorkspace } = await import("./workspace-manager-BO-6k3sP.js");
821
+ const { loadProjectsConfigSync } = await import("./projects-CrBE6IhN.js");
824
822
  const { projects } = loadProjectsConfigSync();
825
823
  const project = resolveProjectFromIssueSync(issueId);
826
824
  if (!project) throw new WorkspaceCreateError({
@@ -855,7 +853,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
855
853
  const { workspacePath } = getWorkspacePath(issueId);
856
854
  const issueLower = issueId.toLowerCase();
857
855
  if (!existsSync$1(workspacePath)) throw new WorkspaceNotFound({ id: issueId });
858
- const { removeWorkspace } = await import("./workspace-manager-DjUAJCSs.js");
856
+ const { removeWorkspace } = await import("./workspace-manager-BO-6k3sP.js");
859
857
  const project = resolveProjectFromIssueSync(issueId);
860
858
  if (!project) throw new WorkspaceCreateError({
861
859
  id: issueId,
@@ -886,7 +884,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
886
884
  try: async () => {
887
885
  const { workspacePath } = getWorkspacePath(issueId);
888
886
  const issueLower = issueId.toLowerCase();
889
- const { stopWorkspaceDocker } = await import("./workspace-manager-DjUAJCSs.js");
887
+ const { stopWorkspaceDocker } = await import("./workspace-manager-BO-6k3sP.js");
890
888
  await Effect.runPromise(stopWorkspaceDocker(workspacePath, issueLower));
891
889
  },
892
890
  catch: () => void 0
@@ -955,7 +953,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
955
953
  join(workspacePath, ".devcontainer", "docker-compose.devcontainer.yml")
956
954
  ];
957
955
  if (!composePaths.find((p) => existsSync$1(p))) {
958
- const { ensureDevcontainerSync } = await import("./ensure-devcontainer-pUVaT0h3.js");
956
+ const { ensureDevcontainerSync } = await import("./ensure-devcontainer-Dq3KoOIl.js");
959
957
  const ensure = ensureDevcontainerSync({
960
958
  workspacePath,
961
959
  issueId
@@ -966,7 +964,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
966
964
  });
967
965
  }
968
966
  const finalComposePath = composePaths.find((p) => existsSync$1(p));
969
- if (finalComposePath) await execAsync$11(`docker compose -f "${finalComposePath}" up -d --build`, {
967
+ if (finalComposePath) await execAsync$10(`docker compose -f "${finalComposePath}" up -d --build`, {
970
968
  cwd: dirname(finalComposePath),
971
969
  timeout: 3e5
972
970
  });
@@ -1110,26 +1108,9 @@ const OpenRouterServiceLive = Layer.effect(OpenRouterService, Effect.sync(() =>
1110
1108
  };
1111
1109
  }));
1112
1110
  //#endregion
1113
- //#region ../../lib/default-cwd.ts
1114
- /**
1115
- * Resolve the default cwd used when no project is selected — the "devroot"
1116
- * fallback. Prefers `~/Projects` if it exists, otherwise the user's home
1117
- * directory.
1118
- *
1119
- * Replaces the deprecated `sync.devroot` config (PAN-1201) for the runtime
1120
- * code paths that still need a sensible default working directory:
1121
- *
1122
- * - New conversations created without a `projectKey` (conversations.ts)
1123
- * - The global editor-launcher in the dashboard top bar (PanOpenInPicker)
1124
- */
1125
- function getDefaultCwd() {
1126
- const candidate = join(homedir$1(), "Projects");
1127
- return existsSync$1(candidate) ? candidate : homedir$1();
1128
- }
1129
- //#endregion
1130
1111
  //#region services/open.ts
1131
1112
  init_src();
1132
- const execAsync$10 = promisify(exec);
1113
+ const execAsync$9 = promisify(exec);
1133
1114
  function getFileManagerCommand() {
1134
1115
  switch (process.platform) {
1135
1116
  case "linux": return "xdg-open";
@@ -1162,7 +1143,7 @@ function launchDetached(launch) {
1162
1143
  }
1163
1144
  async function isCommandAvailable(command) {
1164
1145
  try {
1165
- await execAsync$10(`${process.platform === "win32" ? "where" : "which"} ${command}`);
1146
+ await execAsync$9(`${process.platform === "win32" ? "where" : "which"} ${command}`);
1166
1147
  return true;
1167
1148
  } catch {
1168
1149
  return false;
@@ -4975,71 +4956,6 @@ const postCodexReauthStatusRoute = HttpRouter.add("POST", "/api/settings/codex-r
4975
4956
  })));
4976
4957
  const codexAuthRouteLayer = Layer.mergeAll(getCodexAuthRoute, postCodexReauthRoute, postCodexReauthStatusRoute);
4977
4958
  //#endregion
4978
- //#region services/pending-respawn.ts
4979
- /**
4980
- * Tracks tmux sessions that are mid-respawn so that `/ws/terminal`
4981
- * reconnects landing in the kill→spawn gap don't get a fatal 4404.
4982
- *
4983
- * Background: switch-model, resume, and restart-all all do
4984
- *
4985
- * await killSessionAsync(name) // old tmux dies, PTY exits,
4986
- * // ws-terminal closes clients with 1000
4987
- * await spawnConversationSession(...) // new tmux session with same name
4988
- * await waitForTmuxSession(name)
4989
- * await waitForReadySignal(name, 30) // up to 30s
4990
- *
4991
- * The terminal frontend (`XTerminal.tsx`) reconnects on close 1000 with
4992
- * exponential backoff (1s, 2s, 4s, 8s, 16s). Every reconnect re-enters
4993
- * `ws-terminal.ts`, which checks the tmux session list upfront and
4994
- * `close(4404, 'session-not-found')` if the name isn't there yet.
4995
- * 4404 is treated as fatal on the client (no retry — the session is
4996
- * presumed gone), so the panel sticks on "Could not reconnect" even
4997
- * after the respawn completes a moment later.
4998
- *
4999
- * This registry lets `ws-terminal.ts` distinguish "transient absence
5000
- * during respawn" from "session is actually gone". Respawn sites mark
5001
- * the name with `markRespawnPending()` for the duration of their kill+
5002
- * spawn block; ws-terminal calls `waitForSessionRespawn()` instead of
5003
- * 4404-ing immediately when the session is missing AND
5004
- * `isRespawnPending()` is true.
5005
- */
5006
- init_tmux();
5007
- const pendingRespawns = /* @__PURE__ */ new Set();
5008
- /**
5009
- * Mark a tmux session as mid-respawn. The returned `done()` must run in
5010
- * a `finally` so the marker is cleared even if the respawn throws.
5011
- */
5012
- function markRespawnPending(sessionName) {
5013
- pendingRespawns.add(sessionName);
5014
- return { done: () => {
5015
- pendingRespawns.delete(sessionName);
5016
- } };
5017
- }
5018
- /** True if a respawn is currently in progress for this session name. */
5019
- function isRespawnPending(sessionName) {
5020
- return pendingRespawns.has(sessionName);
5021
- }
5022
- const POLL_INTERVAL_MS$4 = 200;
5023
- /**
5024
- * Poll for the session to come back, up to `timeoutMs`. Returns whether
5025
- * it did. Bails early once `pendingRespawns` no longer contains the name
5026
- * (the wrapping respawn block finished, success or failure) and the
5027
- * session still isn't there — at that point the absence is real.
5028
- *
5029
- * `timeoutMs` should comfortably exceed the longest respawn window. The
5030
- * dominant cost is `waitForReadySignal`'s 30s ceiling in the conversation
5031
- * routes, so 35s is the right default for those callers.
5032
- */
5033
- async function waitForSessionRespawn(sessionName, timeoutMs) {
5034
- const deadline = Date.now() + timeoutMs;
5035
- while (Date.now() < deadline) {
5036
- if (await Effect.runPromise(sessionExists(sessionName))) return true;
5037
- if (!pendingRespawns.has(sessionName)) return Effect.runPromise(sessionExists(sessionName));
5038
- await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS$4));
5039
- }
5040
- return Effect.runPromise(sessionExists(sessionName));
5041
- }
5042
- //#endregion
5043
4959
  //#region ws-terminal.ts
5044
4960
  init_tmux();
5045
4961
  init_child_env();
@@ -15973,7 +15889,7 @@ var require_get_vercel_oidc_token = /* @__PURE__ */ __commonJSMin(((exports, mod
15973
15889
  err = error;
15974
15890
  }
15975
15891
  try {
15976
- const [{ getTokenPayload, isExpired }, { refreshToken }] = await Promise.all([await import("./token-util-xNaV-00f.js").then((m) => /* @__PURE__ */ __toESM(m.default)), await import("./token-DfBf1bsd.js").then((m) => /* @__PURE__ */ __toESM(m.default))]);
15892
+ const [{ getTokenPayload, isExpired }, { refreshToken }] = await Promise.all([await import("./token-util-C9u4An3K.js").then((m) => /* @__PURE__ */ __toESM(m.default)), await import("./token-g_sJ19g3.js").then((m) => /* @__PURE__ */ __toESM(m.default))]);
15977
15893
  if (!token || isExpired(getTokenPayload(token), options?.expirationBufferMs)) {
15978
15894
  await refreshToken(options);
15979
15895
  token = getVercelOidcTokenSync();
@@ -28290,7 +28206,7 @@ var GoogleCloudTranscription = class {
28290
28206
  }
28291
28207
  async start(apiKey, model) {
28292
28208
  try {
28293
- const { SpeechClient } = await import("./src-DNUUqkec.js").then((m) => /* @__PURE__ */ __toESM(m.default, 1)).then((module) => module.v1p1beta1 ?? module.v1);
28209
+ const { SpeechClient } = await import("./src-D4YUZrwR.js").then((m) => /* @__PURE__ */ __toESM(m.default, 1)).then((module) => module.v1p1beta1 ?? module.v1);
28294
28210
  if (this.closed) return;
28295
28211
  const stream = new SpeechClient({ apiKey }).streamingRecognize({
28296
28212
  config: {
@@ -28956,9 +28872,9 @@ function setupAutoPresoWebSocket(server) {
28956
28872
  }
28957
28873
  //#endregion
28958
28874
  //#region services/read-workspace-file.ts
28875
+ init_behavior();
28959
28876
  init_discovered_sessions();
28960
28877
  init_conversations();
28961
- init_behavior();
28962
28878
  init_codex_conversation_parser();
28963
28879
  init_ohmypi_conversation_parser();
28964
28880
  init_pi_conversation_parser();
@@ -30076,18 +29992,13 @@ init_briefing_freshness();
30076
29992
  init_types();
30077
29993
  init_specs();
30078
29994
  init_io();
30079
- init_pty_supervisor_locate();
30080
- init_pty_token();
30081
29995
  init_agent_record_sync();
30082
29996
  init_openai_auth();
30083
29997
  init_claude_permissions();
30084
29998
  init_claude_auth();
30085
29999
  init_layers();
30086
30000
  init_codex();
30087
- init_ohmypi_fifo();
30088
- init_pi_fifo();
30089
30001
  init_launcher_generator();
30090
- init_bridge_token();
30091
30002
  init_transcript_landing();
30092
30003
  init_state_home();
30093
30004
  init_operator_interventions();
@@ -30418,7 +30329,7 @@ function parseIssueIdFromTextSync(value) {
30418
30329
  //#region services/resource-discovery.ts
30419
30330
  init_projects();
30420
30331
  init_tmux();
30421
- const execFileAsync$14 = promisify(execFile);
30332
+ const execFileAsync$15 = promisify(execFile);
30422
30333
  const RESOURCE_DISCOVERY_TTL_MS = 3e4;
30423
30334
  const RECENT_ACTIVITY_WINDOW_MS = 5e3;
30424
30335
  let cachedResourceIssues = null;
@@ -30526,7 +30437,7 @@ function isDiscoverableAgentSession(sessionName) {
30526
30437
  async function loadTrackerIssues() {
30527
30438
  const map = /* @__PURE__ */ new Map();
30528
30439
  try {
30529
- const { getSharedIssueService } = await import("./issue-service-singleton-bG1WdSdQ.js");
30440
+ const { getSharedIssueService } = await import("./issue-service-singleton-MZsDhAob.js");
30530
30441
  const issues = (await getSharedIssueService()).getIssues();
30531
30442
  for (const issue of issues) if (issue.identifier) map.set(issue.identifier.toUpperCase(), issue);
30532
30443
  } catch {
@@ -30543,7 +30454,7 @@ async function loadTmuxSessions() {
30543
30454
  }
30544
30455
  async function loadDockerContainers() {
30545
30456
  try {
30546
- const { stdout } = await execFileAsync$14("docker", [
30457
+ const { stdout } = await execFileAsync$15("docker", [
30547
30458
  "ps",
30548
30459
  "--format",
30549
30460
  "{{.Names}}"
@@ -30561,7 +30472,7 @@ async function loadOpenPullRequests() {
30561
30472
  const repos = getGitHubConfig()?.repos ?? [];
30562
30473
  await Promise.all(repos.map(async (repo) => {
30563
30474
  try {
30564
- const { stdout } = await execFileAsync$14("gh", [
30475
+ const { stdout } = await execFileAsync$15("gh", [
30565
30476
  "pr",
30566
30477
  "list",
30567
30478
  "--repo",
@@ -30592,7 +30503,7 @@ async function loadOpenPullRequests() {
30592
30503
  }
30593
30504
  async function loadProjectBranches(projectPath) {
30594
30505
  try {
30595
- const [localResult, remoteResult] = await Promise.all([execFileAsync$14("git", [
30506
+ const [localResult, remoteResult] = await Promise.all([execFileAsync$15("git", [
30596
30507
  "for-each-ref",
30597
30508
  "refs/heads/feature/*",
30598
30509
  "--format=%(refname:short)"
@@ -30600,7 +30511,7 @@ async function loadProjectBranches(projectPath) {
30600
30511
  cwd: projectPath,
30601
30512
  encoding: "utf-8",
30602
30513
  timeout: 1e4
30603
- }).catch(() => ({ stdout: "" })), execFileAsync$14("git", [
30514
+ }).catch(() => ({ stdout: "" })), execFileAsync$15("git", [
30604
30515
  "for-each-ref",
30605
30516
  "refs/remotes/origin/feature/*",
30606
30517
  "--format=%(refname:short)"
@@ -30725,7 +30636,7 @@ async function computeResourceAllocatedIssues() {
30725
30636
  if (!issue.resourceDetails.tmuxSessions.includes(sessionName)) issue.resourceDetails.tmuxSessions.push(sessionName);
30726
30637
  }
30727
30638
  try {
30728
- const { listActiveRemoteAgentStates } = await import("./remote-agents-DlvbzO7m.js");
30639
+ const { listActiveRemoteAgentStates } = await import("./remote-agents-Cv-U-_V8.js");
30729
30640
  for (const remoteState of listActiveRemoteAgentStates()) {
30730
30641
  const issue = ensureIssue(remoteState.issueId);
30731
30642
  if (!issue) continue;
@@ -31221,7 +31132,7 @@ init_projects();
31221
31132
  init_remote_agents();
31222
31133
  init_tracker_utils();
31223
31134
  init_tmux();
31224
- const execFileAsync$13 = promisify(execFile);
31135
+ const execFileAsync$14 = promisify(execFile);
31225
31136
  function getIssueDataService$9() {
31226
31137
  return getSharedIssueService();
31227
31138
  }
@@ -31284,7 +31195,7 @@ async function completePlanningArtifacts(options) {
31284
31195
  if (workspaceIssueId && workspaceIssueId.toLowerCase() !== issueLower) throw new Error(`Workspace vBRIEF is for ${workspaceIssueId.toUpperCase()}, not ${upperIssueId}`);
31285
31196
  assertPlanQuality(workspaceDoc);
31286
31197
  const createBeads = options.createBeads ?? (async (path) => {
31287
- const mod = await import("./beads-CYsLiyIM.js");
31198
+ const mod = await import("./beads-B1u04n3o.js");
31288
31199
  return await Effect.runPromise(mod.createBeadsFromVBrief(path));
31289
31200
  });
31290
31201
  emitCompletePlanningPhase(upperIssueId, "specWrite", "start", "writing proposed vBRIEF spec", { projectPath });
@@ -31376,7 +31287,7 @@ async function commitWorkspaceRecordBeforeAutoSpawn(gitRoot, issueId) {
31376
31287
  } catch {}
31377
31288
  const recordPath = join(".pan", "records", `${issueLower}.json`);
31378
31289
  try {
31379
- const { stdout: statusOut } = await execFileAsync$13("git", [
31290
+ const { stdout: statusOut } = await execFileAsync$14("git", [
31380
31291
  "status",
31381
31292
  "--porcelain",
31382
31293
  "--",
@@ -31386,7 +31297,7 @@ async function commitWorkspaceRecordBeforeAutoSpawn(gitRoot, issueId) {
31386
31297
  encoding: "utf-8"
31387
31298
  });
31388
31299
  if (!statusOut.trim()) return;
31389
- await execFileAsync$13("git", [
31300
+ await execFileAsync$14("git", [
31390
31301
  "add",
31391
31302
  "--",
31392
31303
  recordPath
@@ -31395,7 +31306,7 @@ async function commitWorkspaceRecordBeforeAutoSpawn(gitRoot, issueId) {
31395
31306
  encoding: "utf-8"
31396
31307
  });
31397
31308
  try {
31398
- await execFileAsync$13("git", [
31309
+ await execFileAsync$14("git", [
31399
31310
  "diff",
31400
31311
  "--cached",
31401
31312
  "--quiet",
@@ -31407,7 +31318,7 @@ async function commitWorkspaceRecordBeforeAutoSpawn(gitRoot, issueId) {
31407
31318
  });
31408
31319
  return;
31409
31320
  } catch {}
31410
- await execFileAsync$13("git", [
31321
+ await execFileAsync$14("git", [
31411
31322
  "commit",
31412
31323
  "-m",
31413
31324
  `chore(records): update ${issueId.toUpperCase()} per-issue record before auto-start`,
@@ -31626,7 +31537,7 @@ async function completePlanningForIssue(options) {
31626
31537
  if (migrated) await Effect.runPromise(flushAutoCommits(projectPath));
31627
31538
  else if (!projectIsGitRepo) console.log(`[complete-planning] Project root ${projectPath} is not a git repository (polyrepo) — pan spec updated on disk but not committed`);
31628
31539
  else {
31629
- const { stdout: branchStdout } = await execFileAsync$13("git", [
31540
+ const { stdout: branchStdout } = await execFileAsync$14("git", [
31630
31541
  "rev-parse",
31631
31542
  "--abbrev-ref",
31632
31543
  "HEAD"
@@ -31636,7 +31547,7 @@ async function completePlanningForIssue(options) {
31636
31547
  });
31637
31548
  const currentBranch = branchStdout.trim();
31638
31549
  if (currentBranch === "main") {
31639
- await execFileAsync$13("git", [
31550
+ await execFileAsync$14("git", [
31640
31551
  "add",
31641
31552
  "--",
31642
31553
  ...filesToStage
@@ -31645,7 +31556,7 @@ async function completePlanningForIssue(options) {
31645
31556
  encoding: "utf-8"
31646
31557
  });
31647
31558
  try {
31648
- await execFileAsync$13("git", [
31559
+ await execFileAsync$14("git", [
31649
31560
  "diff",
31650
31561
  "--cached",
31651
31562
  "--quiet",
@@ -31656,7 +31567,7 @@ async function completePlanningForIssue(options) {
31656
31567
  encoding: "utf-8"
31657
31568
  });
31658
31569
  } catch {
31659
- await execFileAsync$13("git", [
31570
+ await execFileAsync$14("git", [
31660
31571
  "commit",
31661
31572
  "-m",
31662
31573
  `chore(scope): propose ${upperIssueId} vBRIEF`,
@@ -31669,7 +31580,7 @@ async function completePlanningForIssue(options) {
31669
31580
  });
31670
31581
  console.log(`[complete-planning] Committed pan spec on main for ${upperIssueId}`);
31671
31582
  try {
31672
- const { stdout: remotes } = await execFileAsync$13("git", ["remote"], {
31583
+ const { stdout: remotes } = await execFileAsync$14("git", ["remote"], {
31673
31584
  cwd: projectPath,
31674
31585
  encoding: "utf-8"
31675
31586
  });
@@ -31682,16 +31593,16 @@ async function completePlanningForIssue(options) {
31682
31593
  }
31683
31594
  } else console.log(`[complete-planning] Project root not on main (${currentBranch}) — pan spec updated on disk but not committed on main`);
31684
31595
  }
31685
- if (!existsSync$1(join(gitRoot, ".git"))) await execFileAsync$13("git", ["init"], {
31596
+ if (!existsSync$1(join(gitRoot, ".git"))) await execFileAsync$14("git", ["init"], {
31686
31597
  cwd: gitRoot,
31687
31598
  encoding: "utf-8"
31688
31599
  });
31689
- for (const args of completePlanningWorkspaceGitAddCommands(gitRoot, migrated)) await execFileAsync$13("git", args, {
31600
+ for (const args of completePlanningWorkspaceGitAddCommands(gitRoot, migrated)) await execFileAsync$14("git", args, {
31690
31601
  cwd: gitRoot,
31691
31602
  encoding: "utf-8"
31692
31603
  });
31693
31604
  try {
31694
- await execFileAsync$13("git", [
31605
+ await execFileAsync$14("git", [
31695
31606
  "diff",
31696
31607
  "--cached",
31697
31608
  "--quiet"
@@ -31700,7 +31611,7 @@ async function completePlanningForIssue(options) {
31700
31611
  encoding: "utf-8"
31701
31612
  });
31702
31613
  } catch {
31703
- await execFileAsync$13("git", [
31614
+ await execFileAsync$14("git", [
31704
31615
  "commit",
31705
31616
  "-m",
31706
31617
  `chore(plan): complete planning for ${id}`,
@@ -31711,7 +31622,7 @@ async function completePlanningForIssue(options) {
31711
31622
  });
31712
31623
  }
31713
31624
  try {
31714
- const { stdout: remotes } = await execFileAsync$13("git", ["remote"], {
31625
+ const { stdout: remotes } = await execFileAsync$14("git", ["remote"], {
31715
31626
  cwd: gitRoot,
31716
31627
  encoding: "utf-8"
31717
31628
  });
@@ -31891,8 +31802,8 @@ init_tracker_utils();
31891
31802
  init_agents$1();
31892
31803
  init_issue_id();
31893
31804
  init_io();
31894
- const execAsync$9 = promisify(exec);
31895
- const execFileAsync$12 = promisify(execFile);
31805
+ const execAsync$8 = promisify(exec);
31806
+ const execFileAsync$13 = promisify(execFile);
31896
31807
  function isGitHubIssue$4(issueId) {
31897
31808
  const resolved = resolveGitHubIssueSync(issueId);
31898
31809
  if (resolved.isGitHub) return {
@@ -31931,7 +31842,7 @@ async function closeIssuePullRequest(issueId, reason = "Canceled via Overdeck")
31931
31842
  if (!githubCheck.isGitHub || !githubCheck.owner || !githubCheck.repo) return ["No GitHub PR to close"];
31932
31843
  const branchName = `feature/${issueId.toLowerCase()}`;
31933
31844
  try {
31934
- const { stdout: prListRaw } = await execFileAsync$12("gh", [
31845
+ const { stdout: prListRaw } = await execFileAsync$13("gh", [
31935
31846
  "pr",
31936
31847
  "list",
31937
31848
  "--repo",
@@ -31950,7 +31861,7 @@ async function closeIssuePullRequest(issueId, reason = "Canceled via Overdeck")
31950
31861
  });
31951
31862
  const prNumber = prListRaw.trim();
31952
31863
  if (!prNumber) return ["No open PR found for branch"];
31953
- await execFileAsync$12("gh", [
31864
+ await execFileAsync$13("gh", [
31954
31865
  "pr",
31955
31866
  "close",
31956
31867
  prNumber,
@@ -31963,7 +31874,7 @@ async function closeIssuePullRequest(issueId, reason = "Canceled via Overdeck")
31963
31874
  timeout: 15e3
31964
31875
  });
31965
31876
  try {
31966
- const { setReviewStatusSync } = await import("./review-status-Br6lAFGO.js");
31877
+ const { setReviewStatusSync } = await import("./review-status-CG0iDuWa.js");
31967
31878
  setReviewStatusSync(issueId.toUpperCase(), { prUrl: void 0 });
31968
31879
  } catch {}
31969
31880
  return [`Closed PR #${prNumber} on ${githubCheck.owner}/${githubCheck.repo}`];
@@ -32017,7 +31928,7 @@ async function runDestructiveIssueLifecycle(id, mode, opts = {}) {
32017
31928
  const { ctx, projectConfig } = buildLifecycleContext(id, getIssueDataService$8().getIssueSource(id) ?? void 0);
32018
31929
  const deleteWorkspace = opts.deleteWorkspace ?? true;
32019
31930
  cleanupLog.push(...await closeIssuePullRequest(id, mode === "cancel" ? "Canceled via Overdeck" : "Reset to Todo via Overdeck"));
32020
- const { resetToTodo, cancelIssueWorkflow } = await import("./lifecycle-C_73gi-C.js");
31931
+ const { resetToTodo, cancelIssueWorkflow } = await import("./lifecycle-Ck2UR27D.js");
32021
31932
  const workflow = mode === "cancel" ? cancelIssueWorkflow : resetToTodo;
32022
31933
  const result = await Effect.runPromise(workflow(ctx, {
32023
31934
  deleteWorkspace,
@@ -32032,7 +31943,7 @@ async function runDestructiveIssueLifecycle(id, mode, opts = {}) {
32032
31943
  }));
32033
31944
  cleanupLog.push(...result.steps.flatMap((step) => step.details || [step.error].filter(Boolean)));
32034
31945
  if (mode === "cancel") try {
32035
- const { transitionVBriefOnMain } = await import("./lifecycle-io-C_Wu0_i-.js");
31946
+ const { transitionVBriefOnMain } = await import("./lifecycle-io-DXv8Utct.js");
32036
31947
  const tx = await Effect.runPromise(transitionVBriefOnMain(ctx.projectPath, id, "cancelled", "cancelled", `scope: cancel ${id.toUpperCase()} vBRIEF`));
32037
31948
  if (tx.moved) cleanupLog.push(`vBRIEF moved ${tx.fromDir} → cancelled`);
32038
31949
  if (tx.committed) cleanupLog.push(`Committed vBRIEF cancellation on main`);
@@ -32040,8 +31951,8 @@ async function runDestructiveIssueLifecycle(id, mode, opts = {}) {
32040
31951
  cleanupLog.push(`vBRIEF cancel transition failed (non-fatal): ${err?.message ?? err}`);
32041
31952
  }
32042
31953
  try {
32043
- const { killAllReviewerSessions } = await import("./review-agent-Rub0OpZc.js");
32044
- const { resolveProjectFromIssueSync } = await import("./projects-KJ94e50I.js");
31954
+ const { killAllReviewerSessions } = await import("./review-agent-u5q3ip7H.js");
31955
+ const { resolveProjectFromIssueSync } = await import("./projects-CrBE6IhN.js");
32045
31956
  const projectKey = resolveProjectFromIssueSync(id)?.projectKey;
32046
31957
  if (projectKey) {
32047
31958
  const { killed } = await Effect.runPromise(killAllReviewerSessions(projectKey, id.toUpperCase()));
@@ -32055,7 +31966,7 @@ async function runDestructiveIssueLifecycle(id, mode, opts = {}) {
32055
31966
  cleanupLog.push("Cleared review status");
32056
31967
  } catch {}
32057
31968
  try {
32058
- const { resetPostMergeState } = await import("./merge-agent-36wfYm2u.js");
31969
+ const { resetPostMergeState } = await import("./merge-agent-ejC7Wos8.js");
32059
31970
  resetPostMergeState(id);
32060
31971
  resetPostMergeState(id.toUpperCase());
32061
31972
  cleanupLog.push("Cleared merge state");
@@ -32075,7 +31986,7 @@ function closeIssueTransition(options) {
32075
31986
  const { issueId, body, eventStore } = options;
32076
31987
  const { reason } = body;
32077
31988
  const projectPath = getProjectPath$3(void 0, extractPrefixSync(issueId) ?? issueId.split("-")[0]);
32078
- const { close: closeWorkflow } = yield* Effect.promise(() => import("./lifecycle-C_73gi-C.js"));
31989
+ const { close: closeWorkflow } = yield* Effect.promise(() => import("./lifecycle-Ck2UR27D.js"));
32079
31990
  const githubCheck = isGitHubIssue$4(issueId);
32080
31991
  const issueDataService = getIssueDataService$8();
32081
31992
  const issueSource = issueDataService.getIssueSource(issueId);
@@ -32098,7 +32009,7 @@ function closeIssueTransition(options) {
32098
32009
  };
32099
32010
  }
32100
32011
  const result = yield* closeWorkflow(ctx, { reason });
32101
- if (githubCheck.isGitHub) execAsync$9("pan sync", {
32012
+ if (githubCheck.isGitHub) execAsync$8("pan sync", {
32102
32013
  encoding: "utf-8",
32103
32014
  timeout: 3e4
32104
32015
  }).catch(() => {});
@@ -32309,13 +32220,13 @@ function reopenIssueTransition(options) {
32309
32220
  }
32310
32221
  yield* Effect.promise(async () => {
32311
32222
  try {
32312
- const { stdout } = await execAsync$9(`gh pr list --head ${`feature/${id.toLowerCase()}`} --state closed --json number,mergedAt --limit 1`, {
32223
+ const { stdout } = await execAsync$8(`gh pr list --head ${`feature/${id.toLowerCase()}`} --state closed --json number,mergedAt --limit 1`, {
32313
32224
  encoding: "utf-8",
32314
32225
  timeout: 15e3
32315
32226
  });
32316
32227
  const prs = JSON.parse(stdout.trim() || "[]");
32317
32228
  if (prs.length > 0 && !prs[0].mergedAt) {
32318
- await execAsync$9(`gh pr reopen ${prs[0].number}`, {
32229
+ await execAsync$8(`gh pr reopen ${prs[0].number}`, {
32319
32230
  encoding: "utf-8",
32320
32231
  timeout: 15e3
32321
32232
  });
@@ -32342,7 +32253,7 @@ function reopenIssueTransition(options) {
32342
32253
  else clearReviewStatus(id.toUpperCase());
32343
32254
  } catch {}
32344
32255
  try {
32345
- const { resetPostMergeState } = await import("./merge-agent-36wfYm2u.js");
32256
+ const { resetPostMergeState } = await import("./merge-agent-ejC7Wos8.js");
32346
32257
  resetPostMergeState(id);
32347
32258
  resetPostMergeState(id.toUpperCase());
32348
32259
  } catch {}
@@ -32362,9 +32273,9 @@ function reopenIssueTransition(options) {
32362
32273
  const projectPath = (teamPrefix ? findProjectByTeamSync(teamPrefix) : null)?.path || "";
32363
32274
  if (projectPath) {
32364
32275
  const workspacePath = join(projectPath, "workspaces", `feature-${issueLower}`);
32365
- const { createBeadsFromVBrief } = await import("./beads-CYsLiyIM.js");
32276
+ const { createBeadsFromVBrief } = await import("./beads-B1u04n3o.js");
32366
32277
  if (existsSync$1(workspacePath) && await Effect.runPromise(findPlan(workspacePath))) try {
32367
- const { stdout: bdCheck } = await Effect.runPromise(withBdMutex(() => Effect.promise(() => execFileAsync$12("bd", [
32278
+ const { stdout: bdCheck } = await Effect.runPromise(withBdMutex(() => Effect.promise(() => execFileAsync$13("bd", [
32368
32279
  "list",
32369
32280
  "--json",
32370
32281
  "-l",
@@ -32439,7 +32350,7 @@ function moveIssueStatus(options) {
32439
32350
  "done"
32440
32351
  ];
32441
32352
  if (!targetStatus || !validStatuses.includes(targetStatus)) return jsonResponse({ error: `Invalid targetStatus. Must be one of: ${validStatuses.join(", ")}` }, { status: 400 });
32442
- const { updateShadowState } = yield* Effect.promise(() => import("./shadow-state-ByXZehsy.js"));
32353
+ const { updateShadowState } = yield* Effect.promise(() => import("./shadow-state-CVHpRWlb.js"));
32443
32354
  const issueState = {
32444
32355
  backlog: "open",
32445
32356
  todo: "open",
@@ -32502,7 +32413,7 @@ function moveIssueStatus(options) {
32502
32413
  init_issue_service_singleton();
32503
32414
  init_issue_id();
32504
32415
  init_agents$1();
32505
- const execAsync$8 = promisify(exec);
32416
+ const execAsync$7 = promisify(exec);
32506
32417
  function getIssueDataService$7() {
32507
32418
  return getSharedIssueService();
32508
32419
  }
@@ -32527,28 +32438,28 @@ async function cleanupWorkspaceForIssue(rawId, eventStore) {
32527
32438
  if (projectRoot) {
32528
32439
  const workspacePath = join(projectRoot, "workspaces", `feature-${issueLower}`);
32529
32440
  try {
32530
- if ((await execAsync$8("git worktree list --porcelain", {
32441
+ if ((await execAsync$7("git worktree list --porcelain", {
32531
32442
  cwd: projectRoot,
32532
32443
  encoding: "utf-8"
32533
32444
  })).stdout.includes(workspacePath)) {
32534
- await execAsync$8(`git worktree remove "${workspacePath}" --force`, {
32445
+ await execAsync$7(`git worktree remove "${workspacePath}" --force`, {
32535
32446
  cwd: projectRoot,
32536
32447
  encoding: "utf-8"
32537
32448
  });
32538
32449
  cleanupLog.push(`Removed git worktree: ${workspacePath}`);
32539
32450
  } else if (existsSync$1(workspacePath)) {
32540
- await execAsync$8(`rm -rf "${workspacePath}"`, { encoding: "utf-8" });
32451
+ await execAsync$7(`rm -rf "${workspacePath}"`, { encoding: "utf-8" });
32541
32452
  cleanupLog.push(`Removed directory: ${workspacePath}`);
32542
32453
  }
32543
32454
  } catch {
32544
32455
  if (existsSync$1(workspacePath)) {
32545
- await execAsync$8(`rm -rf "${workspacePath}"`, { encoding: "utf-8" });
32456
+ await execAsync$7(`rm -rf "${workspacePath}"`, { encoding: "utf-8" });
32546
32457
  cleanupLog.push(`Removed directory: ${workspacePath}`);
32547
32458
  }
32548
32459
  }
32549
32460
  const branchName = `feature/${issueLower}`;
32550
32461
  try {
32551
- await execAsync$8(`git branch -D "${branchName}" 2>/dev/null || true`, {
32462
+ await execAsync$7(`git branch -D "${branchName}" 2>/dev/null || true`, {
32552
32463
  cwd: projectRoot,
32553
32464
  encoding: "utf-8"
32554
32465
  });
@@ -32557,7 +32468,7 @@ async function cleanupWorkspaceForIssue(rawId, eventStore) {
32557
32468
  }
32558
32469
  const agentDir = join(homedir$1(), ".overdeck", "agents", `agent-${issueLower}`);
32559
32470
  if (existsSync$1(agentDir)) {
32560
- await execAsync$8(`rm -rf "${agentDir}"`, { encoding: "utf-8" });
32471
+ await execAsync$7(`rm -rf "${agentDir}"`, { encoding: "utf-8" });
32561
32472
  cleanupLog.push(`Removed agent state: ${agentDir}`);
32562
32473
  }
32563
32474
  await Effect.runPromise(eventStore.append({
@@ -32666,7 +32577,7 @@ async function copySettingsToWorkspace(id) {
32666
32577
  success: false,
32667
32578
  error: "Workspace not found"
32668
32579
  }, { status: 404 });
32669
- const { copyOverdeckSettingsToWorkspaceSync } = await import("./workspace-manager-DjUAJCSs.js");
32580
+ const { copyOverdeckSettingsToWorkspaceSync } = await import("./workspace-manager-BO-6k3sP.js");
32670
32581
  const result = copyOverdeckSettingsToWorkspaceSync(workspacePath);
32671
32582
  return jsonResponse({
32672
32583
  success: result.errors.length === 0 || result.copied.length > 0,
@@ -32701,7 +32612,7 @@ function generateTasksForIssue(id) {
32701
32612
  success: false,
32702
32613
  error: `No vBRIEF spec found on main for ${id} — run planning first.`
32703
32614
  }, { status: 409 });
32704
- const { createBeadsFromVBrief } = yield* Effect.promise(() => import("./beads-CYsLiyIM.js"));
32615
+ const { createBeadsFromVBrief } = yield* Effect.promise(() => import("./beads-B1u04n3o.js"));
32705
32616
  const result = yield* createBeadsFromVBrief(workspacePath);
32706
32617
  if (!result.success || result.created.length === 0) {
32707
32618
  const errors = result.errors.length > 0 ? result.errors : ["Beads creation produced no tasks"];
@@ -32731,8 +32642,8 @@ init_projects();
32731
32642
  init_tracker_utils();
32732
32643
  init_tmux();
32733
32644
  init_typed_errors();
32734
- const execAsync$7 = promisify(exec);
32735
- const execFileAsync$11 = promisify(execFile);
32645
+ const execAsync$6 = promisify(exec);
32646
+ const execFileAsync$12 = promisify(execFile);
32736
32647
  function getIssueDataService$6() {
32737
32648
  return getSharedIssueService();
32738
32649
  }
@@ -33032,7 +32943,7 @@ function abortPlanningForIssue(options) {
33032
32943
  const featureWorkspacePath = join(projectPath, "workspaces", `feature-${issueIdentifier.toLowerCase()}`);
33033
32944
  const plainWorkspacePath = join(projectPath, "workspaces", issueIdentifier.toLowerCase());
33034
32945
  if (existsSync$1(existsSync$1(featureWorkspacePath) ? featureWorkspacePath : plainWorkspacePath)) {
33035
- await execFileAsync$11("pan", [
32946
+ await execFileAsync$12("pan", [
33036
32947
  "workspace",
33037
32948
  "destroy",
33038
32949
  issueIdentifier.toLowerCase(),
@@ -33141,10 +33052,10 @@ function restartFromPlan(options) {
33141
33052
  });
33142
33053
  const resetResult = yield* Effect.promise(async () => {
33143
33054
  try {
33144
- const { runGitResetHard } = await import("./dangerous-git-ops-DDWQlPC3.js");
33055
+ const { runGitResetHard } = await import("./dangerous-git-ops-Bn18PEcN.js");
33145
33056
  async function findPlanningCommit(grep, label) {
33146
33057
  try {
33147
- const { stdout } = await execAsync$7(`git log --grep="${grep.replace(/"/g, "\\\"")}" --format=%H -1`, {
33058
+ const { stdout } = await execAsync$6(`git log --grep="${grep.replace(/"/g, "\\\"")}" --format=%H -1`, {
33148
33059
  cwd: workspacePath,
33149
33060
  encoding: "utf-8",
33150
33061
  timeout: 1e4
@@ -33160,7 +33071,7 @@ function restartFromPlan(options) {
33160
33071
  }
33161
33072
  const found = await findPlanningCommit(`Complete planning for ${id}`, "complete-planning message") ?? await findPlanningCommit(`chore: planning artifacts for ${id}`, "agent-start message") ?? await (async () => {
33162
33073
  try {
33163
- const { stdout } = await execAsync$7(`git log --diff-filter=A --format=%H -1 -- .pan/spec.vbrief.json`, {
33074
+ const { stdout } = await execAsync$6(`git log --diff-filter=A --format=%H -1 -- .pan/spec.vbrief.json`, {
33164
33075
  cwd: workspacePath,
33165
33076
  encoding: "utf-8",
33166
33077
  timeout: 1e4
@@ -33294,7 +33205,7 @@ init_github_pr_lookup();
33294
33205
  init_tracker_utils();
33295
33206
  init_tracker_config();
33296
33207
  init_pr_tab_cache();
33297
- const execAsync$6 = promisify(exec);
33208
+ const execAsync$5 = promisify(exec);
33298
33209
  function isGitHubIssue$2(issueId) {
33299
33210
  const resolved = resolveGitHubIssueSync(issueId);
33300
33211
  if (resolved.isGitHub) return {
@@ -33342,7 +33253,7 @@ async function fetchIssueDiscussions(issueId, deps = {}) {
33342
33253
  if (githubCheck.isGitHub && githubCheck.owner && githubCheck.repo && githubCheck.number) {
33343
33254
  const { owner, repo, number } = githubCheck;
33344
33255
  try {
33345
- const { stdout } = await execAsync$6(`gh api "repos/${owner}/${repo}/issues/${number}/comments?per_page=100"`, {
33256
+ const { stdout } = await execAsync$5(`gh api "repos/${owner}/${repo}/issues/${number}/comments?per_page=100"`, {
33346
33257
  encoding: "utf-8",
33347
33258
  timeout: 15e3,
33348
33259
  maxBuffer: 8 * 1024 * 1024
@@ -33405,7 +33316,7 @@ async function fetchIssueDiscussions(issueId, deps = {}) {
33405
33316
  const collectedItems = [];
33406
33317
  const prConversation = (async () => {
33407
33318
  try {
33408
- const { stdout } = await execAsync$6(`gh api "repos/${prOwner}/${prRepo}/issues/${prNumber}/comments?per_page=100"`, {
33319
+ const { stdout } = await execAsync$5(`gh api "repos/${prOwner}/${prRepo}/issues/${prNumber}/comments?per_page=100"`, {
33409
33320
  encoding: "utf-8",
33410
33321
  timeout: 15e3,
33411
33322
  maxBuffer: 8 * 1024 * 1024
@@ -33426,7 +33337,7 @@ async function fetchIssueDiscussions(issueId, deps = {}) {
33426
33337
  })();
33427
33338
  const prReviews = (async () => {
33428
33339
  try {
33429
- const { stdout } = await execAsync$6(`gh api "repos/${prOwner}/${prRepo}/pulls/${prNumber}/reviews?per_page=100"`, {
33340
+ const { stdout } = await execAsync$5(`gh api "repos/${prOwner}/${prRepo}/pulls/${prNumber}/reviews?per_page=100"`, {
33430
33341
  encoding: "utf-8",
33431
33342
  timeout: 15e3,
33432
33343
  maxBuffer: 8 * 1024 * 1024
@@ -33451,7 +33362,7 @@ async function fetchIssueDiscussions(issueId, deps = {}) {
33451
33362
  })();
33452
33363
  const prInlineComments = (async () => {
33453
33364
  try {
33454
- const { stdout } = await execAsync$6(`gh api "repos/${prOwner}/${prRepo}/pulls/${prNumber}/comments?per_page=100"`, {
33365
+ const { stdout } = await execAsync$5(`gh api "repos/${prOwner}/${prRepo}/pulls/${prNumber}/comments?per_page=100"`, {
33455
33366
  encoding: "utf-8",
33456
33367
  timeout: 15e3,
33457
33368
  maxBuffer: 8 * 1024 * 1024
@@ -33593,7 +33504,7 @@ function closeOutIssue(id) {
33593
33504
  }
33594
33505
  const closeOutResult = yield* Effect.promise(async () => {
33595
33506
  try {
33596
- const { closeOut } = await import("./lifecycle-C_73gi-C.js");
33507
+ const { closeOut } = await import("./lifecycle-Ck2UR27D.js");
33597
33508
  return {
33598
33509
  ok: true,
33599
33510
  result: await Effect.runPromise(closeOut(ctx))
@@ -33679,7 +33590,7 @@ function bulkCloseOut(body) {
33679
33590
  const invalidIds = issueIds.filter((id) => !isValidIssueId(id));
33680
33591
  if (invalidIds.length > 0) return jsonResponse({ error: `Invalid issue ID format: ${invalidIds.join(", ")}` }, { status: 400 });
33681
33592
  const eventStore = yield* EventStoreService;
33682
- const { closeOut } = yield* Effect.promise(() => import("./lifecycle-C_73gi-C.js"));
33593
+ const { closeOut } = yield* Effect.promise(() => import("./lifecycle-Ck2UR27D.js"));
33683
33594
  const issueDataService = getIssueDataService$5();
33684
33595
  const tasks = [];
33685
33596
  const agentChecks = yield* withConcurrencyLimit(issueIds.map((id) => Effect.promise(async () => {
@@ -33875,8 +33786,8 @@ const getIssueShipLogRoute = HttpRouter.add("GET", "/api/issues/:id/ship-log", h
33875
33786
  const id = (yield* HttpRouter.params)["id"] ?? "";
33876
33787
  if (!parseIssueIdSync(id)) return jsonResponse({ error: "Invalid issue ID" }, { status: 400 });
33877
33788
  return yield* Effect.promise(async () => {
33878
- const { getShipLog } = await import("./ship-log-DE_0Cv_i.js");
33879
- const { getReviewStatusSync } = await import("./review-status-Br6lAFGO.js");
33789
+ const { getShipLog } = await import("./ship-log-CwqPFfqx.js");
33790
+ const { getReviewStatusSync } = await import("./review-status-CG0iDuWa.js");
33880
33791
  const log = getShipLog(id);
33881
33792
  const rs = getReviewStatusSync(id);
33882
33793
  return jsonResponse({
@@ -34832,7 +34743,7 @@ const cloisterRouteLayer = Layer.mergeAll(getCloisterStatusRoute, postCloisterSt
34832
34743
  init_agents$1();
34833
34744
  init_cost_sync();
34834
34745
  init_tmux();
34835
- const execFileAsync$10 = promisify(execFile);
34746
+ const execFileAsync$11 = promisify(execFile);
34836
34747
  const BURN_WINDOW_MS = 1800 * 1e3;
34837
34748
  function buildAgentStatsSnapshot(options) {
34838
34749
  const nowMs = options.nowMs ?? Date.now();
@@ -34905,7 +34816,7 @@ function getAgentStatsSnapshotEffect(deps = {}) {
34905
34816
  });
34906
34817
  });
34907
34818
  }
34908
- function parseProcessTable$1(psTable) {
34819
+ function parseProcessTable(psTable) {
34909
34820
  return psTable.split("\n").map((line) => line.trim()).filter(Boolean).flatMap((line) => {
34910
34821
  const match = line.match(/^(\d+)\s+(\d+)\s+([0-9.]+)\s+(\d+)$/);
34911
34822
  if (!match) return [];
@@ -34918,8 +34829,8 @@ function parseProcessTable$1(psTable) {
34918
34829
  });
34919
34830
  }
34920
34831
  async function readBatchedProcessTable() {
34921
- const { stdout } = await execFileAsync$10("ps", ["-eo", "pid=,ppid=,pcpu=,rss="], { encoding: "utf8" });
34922
- return parseProcessTable$1(stdout);
34832
+ const { stdout } = await execFileAsync$11("ps", ["-eo", "pid=,ppid=,pcpu=,rss="], { encoding: "utf8" });
34833
+ return parseProcessTable(stdout);
34923
34834
  }
34924
34835
  function defaultListSessionNames() {
34925
34836
  return listSessions().pipe(Effect.map((sessions) => sessions.map((session) => session.name)));
@@ -35845,11 +35756,11 @@ const postUnpauseContainerRoute = HttpRouter.add("POST", "/api/resources/docker/
35845
35756
  //#endregion
35846
35757
  //#region routes/resources/prune.ts
35847
35758
  init_domain_services();
35848
- const execFileAsync$8 = promisify(execFile);
35759
+ const execFileAsync$9 = promisify(execFile);
35849
35760
  const postPruneContainersRoute = HttpRouter.add("POST", "/api/resources/docker/prune-containers", httpHandler(Effect.gen(function* () {
35850
35761
  const eventStore = yield* EventStoreService;
35851
35762
  const { stdout } = yield* Effect.tryPromise({
35852
- try: () => execFileAsync$8("docker", [
35763
+ try: () => execFileAsync$9("docker", [
35853
35764
  "container",
35854
35765
  "prune",
35855
35766
  "-f"
@@ -35874,7 +35785,7 @@ const deleteDockerNetworkRoute = HttpRouter.add("DELETE", "/api/resources/docker
35874
35785
  const eventStore = yield* EventStoreService;
35875
35786
  if (!/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(name)) return jsonResponse({ error: "Invalid network name" }, { status: 400 });
35876
35787
  yield* Effect.tryPromise({
35877
- try: () => execFileAsync$8("docker", [
35788
+ try: () => execFileAsync$9("docker", [
35878
35789
  "network",
35879
35790
  "rm",
35880
35791
  name
@@ -35896,7 +35807,7 @@ const deleteDockerVolumeRoute = HttpRouter.add("DELETE", "/api/resources/docker/
35896
35807
  const eventStore = yield* EventStoreService;
35897
35808
  if (!/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(name)) return jsonResponse({ error: "Invalid volume name" }, { status: 400 });
35898
35809
  yield* Effect.tryPromise({
35899
- try: () => execFileAsync$8("docker", [
35810
+ try: () => execFileAsync$9("docker", [
35900
35811
  "volume",
35901
35812
  "rm",
35902
35813
  name
@@ -35916,7 +35827,7 @@ const deleteDockerVolumeRoute = HttpRouter.add("DELETE", "/api/resources/docker/
35916
35827
  const postPruneVolumesRoute = HttpRouter.add("POST", "/api/resources/docker/prune-volumes", httpHandler(Effect.gen(function* () {
35917
35828
  const eventStore = yield* EventStoreService;
35918
35829
  const { stdout } = yield* Effect.tryPromise({
35919
- try: () => execFileAsync$8("docker", [
35830
+ try: () => execFileAsync$9("docker", [
35920
35831
  "volume",
35921
35832
  "prune",
35922
35833
  "-f"
@@ -36101,9 +36012,9 @@ function findStack$1(issueId) {
36101
36012
  //#region routes/resources/teardown.ts
36102
36013
  init_activity_logger();
36103
36014
  init_domain_services();
36104
- const execFileAsync$6 = promisify(execFile);
36015
+ const execFileAsync$7 = promisify(execFile);
36105
36016
  const CONFIRM_TOKEN_TTL_MS = 300 * 1e3;
36106
- let dockerTeardownExec = execFileAsync$6;
36017
+ let dockerTeardownExec = execFileAsync$7;
36107
36018
  let teardownTokenGenerator = () => `td-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
36108
36019
  let activityEmitter = emitActivityEntrySync;
36109
36020
  const teardownTokens = /* @__PURE__ */ new Map();
@@ -37572,8 +37483,8 @@ init_linear_client();
37572
37483
  init_config_yaml();
37573
37484
  init_issue_service_singleton();
37574
37485
  init_io();
37575
- const execAsync$5 = promisify(exec);
37576
- const execFileAsync$5 = promisify(execFile);
37486
+ const execAsync$4 = promisify(exec);
37487
+ const execFileAsync$6 = promisify(execFile);
37577
37488
  function getIssueDataService$3() {
37578
37489
  return getSharedIssueService();
37579
37490
  }
@@ -38115,7 +38026,7 @@ async function fetchPlanningData(issueId, options = {}) {
38115
38026
  const cached = stashCountCache.get(cacheKey);
38116
38027
  if (cached && cached.timestamp > Date.now() - STASH_COUNT_CACHE_TTL_MS) result.stashCount = cached.count;
38117
38028
  else {
38118
- const { stdout: stashList } = await execAsync$5("git stash list", {
38029
+ const { stdout: stashList } = await execAsync$4("git stash list", {
38119
38030
  cwd: workspacePath,
38120
38031
  encoding: "utf-8"
38121
38032
  });
@@ -38203,7 +38114,7 @@ async function generateStatusReview(issueId) {
38203
38114
  };
38204
38115
  const execSafe = async (cmd, opts) => {
38205
38116
  try {
38206
- const { stdout } = await execAsync$5(cmd, {
38117
+ const { stdout } = await execAsync$4(cmd, {
38207
38118
  encoding: "utf-8",
38208
38119
  timeout: 1e4,
38209
38120
  ...opts
@@ -38305,7 +38216,7 @@ Be specific: reference actual file names, function names, requirement text, disc
38305
38216
  const { command: cliCmd, args: cliArgs } = getAgentCommandSync(statusModelId);
38306
38217
  const modelFlag = cliArgs.length > 0 ? ` ${cliArgs.join(" ")}` : "";
38307
38218
  const promptFile = join(planningDir, ".status-review-prompt.tmp");
38308
- const { getProviderForModelSync, getProviderEnvSync } = await import("./providers-D-5txBRc.js");
38219
+ const { getProviderForModelSync, getProviderEnvSync } = await import("./providers-DnPxkHoG.js");
38309
38220
  let providerEnvStr = "";
38310
38221
  let providerEnv = {};
38311
38222
  const statusProvider = getProviderForModelSync(statusModelId);
@@ -38322,7 +38233,7 @@ Be specific: reference actual file names, function names, requirement text, disc
38322
38233
  try {
38323
38234
  const env = buildChildEnvSync(process.env, providerEnv);
38324
38235
  const promptContent = await readFile(promptFile, "utf-8");
38325
- const { stdout: aiReview } = await execAsync$5(`${cliCmd} -p${modelFlag} --no-session-persistence`, {
38236
+ const { stdout: aiReview } = await execAsync$4(`${cliCmd} -p${modelFlag} --no-session-persistence`, {
38326
38237
  encoding: "utf-8",
38327
38238
  timeout: 12e4,
38328
38239
  maxBuffer: 1024 * 1024,
@@ -38388,7 +38299,7 @@ const postMissionControlUploadRoute = HttpRouter.add("POST", "/api/command-deck/
38388
38299
  let safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "-");
38389
38300
  let processedContent = content;
38390
38301
  if (safeName.endsWith(".vtt")) {
38391
- const { vttToMarkdown } = yield* Effect.promise(() => import("./vtt-parser-QnRfcjiU.js"));
38302
+ const { vttToMarkdown } = yield* Effect.promise(() => import("./vtt-parser-C_XPlifj.js"));
38392
38303
  processedContent = vttToMarkdown(content);
38393
38304
  safeName = safeName.replace(/\.vtt$/, ".md");
38394
38305
  }
@@ -38430,7 +38341,7 @@ const postMissionControlSyncDiscussionsRoute = HttpRouter.add("POST", "/api/comm
38430
38341
  if (!ghConfig) return jsonResponse({ error: "GitHub not configured" }, { status: 400 });
38431
38342
  yield* Effect.promise(async () => {
38432
38343
  try {
38433
- const { stdout } = await execFileAsync$5("gh", [
38344
+ const { stdout } = await execFileAsync$6("gh", [
38434
38345
  "issue",
38435
38346
  "view",
38436
38347
  issueId.replace(/^[A-Z]+-/, ""),
@@ -38453,7 +38364,7 @@ const postMissionControlSyncDiscussionsRoute = HttpRouter.add("POST", "/api/comm
38453
38364
  console.warn(`Failed to sync GitHub comments for ${issueId}:`, err);
38454
38365
  }
38455
38366
  try {
38456
- const { stdout: prList } = await execFileAsync$5("gh", [
38367
+ const { stdout: prList } = await execFileAsync$6("gh", [
38457
38368
  "pr",
38458
38369
  "list",
38459
38370
  "--repo",
@@ -38469,7 +38380,7 @@ const postMissionControlSyncDiscussionsRoute = HttpRouter.add("POST", "/api/comm
38469
38380
  timeout: 15e3
38470
38381
  });
38471
38382
  for (const prNum of prList.trim().split("\n").filter(Boolean)) try {
38472
- const { stdout: prComments } = await execFileAsync$5("gh", [
38383
+ const { stdout: prComments } = await execFileAsync$6("gh", [
38473
38384
  "pr",
38474
38385
  "view",
38475
38386
  prNum,
@@ -38600,7 +38511,6 @@ async function fetchProjectTree() {
38600
38511
  const commandDeckRouteLayer = Layer.mergeAll(getMissionControlActivityRoute, getMissionControlPlanningRoute, postMissionControlStatusReviewRoute, postMissionControlUploadRoute, postMissionControlSyncDiscussionsRoute, postMissionControlPlanningInitRoute, getMissionControlProjectsRoute);
38601
38512
  //#endregion
38602
38513
  //#region routes/remote.ts
38603
- init_harness_resolve();
38604
38514
  /**
38605
38515
  * Remote route module — Effect HttpRouter.Layer (PAN-428 B14)
38606
38516
  *
@@ -38933,7 +38843,7 @@ async function refreshTtsRuntimeConfig() {
38933
38843
  init_paths();
38934
38844
  init_config_yaml();
38935
38845
  init_errors();
38936
- const execFileAsync$4 = promisify(execFile);
38846
+ const execFileAsync$5 = promisify(execFile);
38937
38847
  const QWEN_TTS_PID_PATH = join(OVERDECK_HOME, "pids", "qwen-tts.pid");
38938
38848
  const QWEN_TTS_STATE_PATH = join(OVERDECK_HOME, "pids", "qwen-tts.json");
38939
38849
  const QWEN_TTS_START_LOCK_PATH = join(OVERDECK_HOME, "pids", "qwen-tts.start.lock");
@@ -39120,7 +39030,7 @@ function isWithinStartupGrace(state, now = Date.now()) {
39120
39030
  const deadline = Date.parse(state.startupDeadlineAt);
39121
39031
  return Number.isFinite(deadline) && now < deadline;
39122
39032
  }
39123
- function isProcessAlive$2(pid) {
39033
+ function isProcessAlive$1(pid) {
39124
39034
  try {
39125
39035
  process.kill(pid, 0);
39126
39036
  return true;
@@ -39150,7 +39060,7 @@ async function buildManagedProcessIdentity(pid, scriptPath) {
39150
39060
  };
39151
39061
  }
39152
39062
  async function isManagedProcessAlive(state) {
39153
- if (!state || !isProcessAlive$2(state.pid)) return false;
39063
+ if (!state || !isProcessAlive$1(state.pid)) return false;
39154
39064
  if (!state.scriptPath || !state.processStartTimeTicks) return false;
39155
39065
  const identity = await readProcessIdentity(state.pid);
39156
39066
  return identity !== null && identity.startTimeTicks === state.processStartTimeTicks && identity.cmdline.includes(state.scriptPath);
@@ -39172,7 +39082,7 @@ async function terminateManagedProcess(state, timeoutMs) {
39172
39082
  }
39173
39083
  async function sampleGpuMemoryUsedMb(pid) {
39174
39084
  try {
39175
- const { stdout } = await execFileAsync$4("nvidia-smi", ["--query-compute-apps=pid,used_memory", "--format=csv,noheader,nounits"], { timeout: 2e3 });
39085
+ const { stdout } = await execFileAsync$5("nvidia-smi", ["--query-compute-apps=pid,used_memory", "--format=csv,noheader,nounits"], { timeout: 2e3 });
39176
39086
  for (const line of stdout.split("\n")) {
39177
39087
  const [rawPid, rawMemory] = line.split(",").map((part) => part?.trim());
39178
39088
  if (Number.parseInt(rawPid ?? "", 10) === pid) {
@@ -43630,14 +43540,14 @@ const postOpenRouterTestKeyRoute = HttpRouter.add("POST", "/api/settings/openrou
43630
43540
  if (!apiKey) return jsonResponse({ error: "apiKey is required" }, { status: 400 });
43631
43541
  return jsonResponse(yield* (yield* OpenRouterService).validateApiKey(apiKey));
43632
43542
  })));
43633
- const SAFE_MODEL_PATTERN$2 = /^[a-zA-Z0-9_.:\/-]+$/;
43543
+ const SAFE_MODEL_PATTERN$1 = /^[a-zA-Z0-9_.:\/-]+$/;
43634
43544
  const MAX_HARNESS_POLICY_MODELS = 250;
43635
43545
  const MAX_HARNESS_POLICY_MODEL_LENGTH = 200;
43636
43546
  const getHarnessPolicyRoute = HttpRouter.add("GET", "/api/settings/harness-policy", httpHandler(Effect.gen(function* () {
43637
43547
  const request = yield* HttpServerRequest.HttpServerRequest;
43638
43548
  return yield* Effect.promise(async () => {
43639
43549
  const models = (new URL(request.url, "http://localhost").searchParams.get("models") ?? "").split(",").map((model) => model.trim()).filter(Boolean);
43640
- if (models.length === 0 || models.length > MAX_HARNESS_POLICY_MODELS || models.some((model) => model.length > MAX_HARNESS_POLICY_MODEL_LENGTH || !SAFE_MODEL_PATTERN$2.test(model))) return jsonResponse({ error: "Valid models parameter is required" }, { status: 400 });
43550
+ if (models.length === 0 || models.length > MAX_HARNESS_POLICY_MODELS || models.some((model) => model.length > MAX_HARNESS_POLICY_MODEL_LENGTH || !SAFE_MODEL_PATTERN$1.test(model))) return jsonResponse({ error: "Valid models parameter is required" }, { status: 400 });
43641
43551
  return jsonResponse({ decisions: await buildHarnessPolicyDecisions(models, getProviderAuthMode) });
43642
43552
  });
43643
43553
  })));
@@ -43645,7 +43555,7 @@ const getProviderEnvConflictsRoute = HttpRouter.add("GET", "/api/settings/provid
43645
43555
  const request = yield* HttpServerRequest.HttpServerRequest;
43646
43556
  return yield* Effect.promise(async () => {
43647
43557
  const model = new URL(request.url, "http://localhost").searchParams.get("model");
43648
- if (!model || !SAFE_MODEL_PATTERN$2.test(model)) return jsonResponse({ error: "Valid model parameter is required" }, { status: 400 });
43558
+ if (!model || !SAFE_MODEL_PATTERN$1.test(model)) return jsonResponse({ error: "Valid model parameter is required" }, { status: 400 });
43649
43559
  try {
43650
43560
  const providerEnv = await getProviderEnvForModel(model);
43651
43561
  return jsonResponse({ conflicts: await Effect.runPromise(detectProviderEnvConflicts(providerEnv)) });
@@ -44216,7 +44126,7 @@ const postRallyValidateRoute = HttpRouter.add("POST", "/api/rally/validate", Eff
44216
44126
  }, { status: 400 });
44217
44127
  return yield* Effect.promise(async () => {
44218
44128
  try {
44219
- const { RallyRestApi } = await import("./rally-api-DDc85HIz.js");
44129
+ const { RallyRestApi } = await import("./rally-api-B-YA_oXx.js");
44220
44130
  const api = new RallyRestApi({
44221
44131
  apiKey,
44222
44132
  server: server || "https://rally1.rallydev.com"
@@ -44544,7 +44454,7 @@ const getPlanningStatusRoute = HttpRouter.add("GET", "/api/planning/:issueId/sta
44544
44454
  const remoteState = loadRemoteAgentState(sessionName);
44545
44455
  const isRemote = !!remoteState;
44546
44456
  const vmName = remoteState?.vmName ?? "";
44547
- const { getAgentStateSync } = await import("./agents-DCvyTXNU.js");
44457
+ const { getAgentStateSync } = await import("./agents-CEcaxSkR.js");
44548
44458
  const agentStarting = getAgentStateSync(sessionName)?.status === "starting";
44549
44459
  let tmuxSessionAlive = false;
44550
44460
  if (!isRemote) try {
@@ -44583,12 +44493,12 @@ async function claudePlanningSystemPromptFiles(workspacePath) {
44583
44493
  await stat$1(contextFile);
44584
44494
  files.push(contextFile);
44585
44495
  } catch (error) {
44586
- if (!isNotFound$1(error)) throw error;
44496
+ if (!isNotFound(error)) throw error;
44587
44497
  }
44588
44498
  files.push(await ensureSessionContextBriefingFile());
44589
44499
  return files;
44590
44500
  }
44591
- function isNotFound$1(error) {
44501
+ function isNotFound(error) {
44592
44502
  return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
44593
44503
  }
44594
44504
  const postPlanningMessageRoute = HttpRouter.add("POST", "/api/planning/:issueId/message", Effect.gen(function* () {
@@ -44687,7 +44597,7 @@ Continue the PLANNING session. Do NOT implement anything.
44687
44597
  `);
44688
44598
  const agentCwd = workspacePath;
44689
44599
  if (existsSync$1(outputFile)) await rename(outputFile, join(planningDir, `output-${Date.now()}.jsonl`));
44690
- const { getAgentCommandSync } = await import("./settings-yydgaqhv.js");
44600
+ const { getAgentCommandSync } = await import("./settings-Cy7SCFO9.js");
44691
44601
  let msgPlanningModel = "claude-sonnet-5";
44692
44602
  try {
44693
44603
  msgPlanningModel = resolveModel("plan", void 0, loadConfigSync().config);
@@ -44808,7 +44718,7 @@ async function getIndexStats(rootPath, isMain) {
44808
44718
  }
44809
44719
  const getTldrStatusRoute = HttpRouter.add("GET", "/api/services/tldr/status", Effect.promise(async () => {
44810
44720
  try {
44811
- const { getTldrDaemonServiceSync } = await import("./tldr-daemon-DD9rI5gA.js");
44721
+ const { getTldrDaemonServiceSync } = await import("./tldr-daemon-CgZQ3jmZ.js");
44812
44722
  const projectRoot = process.cwd();
44813
44723
  const venvPath = join(projectRoot, ".venv");
44814
44724
  const results = [];
@@ -44853,7 +44763,7 @@ const getTldrStatusRoute = HttpRouter.add("GET", "/api/services/tldr/status", Ef
44853
44763
  }));
44854
44764
  const postTldrStartRoute = HttpRouter.add("POST", "/api/services/tldr/start", Effect.promise(async () => {
44855
44765
  try {
44856
- const { getTldrDaemonServiceSync } = await import("./tldr-daemon-DD9rI5gA.js");
44766
+ const { getTldrDaemonServiceSync } = await import("./tldr-daemon-CgZQ3jmZ.js");
44857
44767
  const projectRoot = process.cwd();
44858
44768
  const venvPath = join(projectRoot, ".venv");
44859
44769
  if (!existsSync$1(venvPath)) return jsonResponse({ error: "No .venv found in project root" }, { status: 404 });
@@ -44870,7 +44780,7 @@ const postTldrStartRoute = HttpRouter.add("POST", "/api/services/tldr/start", Ef
44870
44780
  }));
44871
44781
  const postTldrStopRoute = HttpRouter.add("POST", "/api/services/tldr/stop", Effect.promise(async () => {
44872
44782
  try {
44873
- const { getTldrDaemonServiceSync } = await import("./tldr-daemon-DD9rI5gA.js");
44783
+ const { getTldrDaemonServiceSync } = await import("./tldr-daemon-CgZQ3jmZ.js");
44874
44784
  const projectRoot = process.cwd();
44875
44785
  const venvPath = join(projectRoot, ".venv");
44876
44786
  if (!existsSync$1(venvPath)) return jsonResponse({ error: "No .venv found in project root" }, { status: 404 });
@@ -44887,7 +44797,7 @@ const postTldrStopRoute = HttpRouter.add("POST", "/api/services/tldr/stop", Effe
44887
44797
  }));
44888
44798
  const postTldrReloadRoute = HttpRouter.add("POST", "/api/services/tldr/reload", Effect.promise(async () => {
44889
44799
  try {
44890
- const { getTldrDaemonServiceSync } = await import("./tldr-daemon-DD9rI5gA.js");
44800
+ const { getTldrDaemonServiceSync } = await import("./tldr-daemon-CgZQ3jmZ.js");
44891
44801
  const enabled = isTldrEnabledSync();
44892
44802
  const projectRoot = process.cwd();
44893
44803
  const targets = [];
@@ -44934,12 +44844,123 @@ const postTldrReloadRoute = HttpRouter.add("POST", "/api/services/tldr/reload",
44934
44844
  }));
44935
44845
  const tldrRouteLayer = Layer.mergeAll(getTldrStatusRoute, postTldrStartRoute, postTldrStopRoute, postTldrReloadRoute);
44936
44846
  //#endregion
44847
+ //#region ../../lib/sync-startup-gate.ts
44848
+ var sync_startup_gate_exports = /* @__PURE__ */ __exportAll({
44849
+ isStartupSyncNeededSync: () => isStartupSyncNeededSync,
44850
+ writeSyncManifestSync: () => writeSyncManifestSync
44851
+ });
44852
+ /**
44853
+ * Compute a deterministic hash of every input that can change the output of
44854
+ * `pan sync`. Missing a sync input is treated as an error by the caller so
44855
+ * that the conservative fallback is always a full sync.
44856
+ */
44857
+ function computeSyncInputHash() {
44858
+ const hash = createHash("sha256");
44859
+ hash.update(String(isDevMode()));
44860
+ hash.update(process.cwd());
44861
+ const cwdSkillsRoot = resolveTopLevelSkillsRoot(process.cwd());
44862
+ if (cwdSkillsRoot) updateHashFromDirectory(hash, join$1(cwdSkillsRoot, "skills"));
44863
+ for (const [key, dir] of Object.entries(SYNC_SOURCES)) {
44864
+ if (!existsSync(dir)) throw new Error(`missing sync input: ${key} at ${dir}`);
44865
+ updateHashFromDirectory(hash, dir);
44866
+ }
44867
+ const globalMd = join$1(OVERDECK_HOME, "context", "global.md");
44868
+ if (!existsSync(globalMd)) throw new Error("missing global context layer");
44869
+ updateHashFromFile(hash, globalMd);
44870
+ for (const { config } of listProjectsSync()) {
44871
+ const projectMd = resolveProjectContextFile(config.path);
44872
+ if (existsSync(projectMd)) updateHashFromFile(hash, projectMd);
44873
+ const projectSkills = join$1(config.path, ".pan", "skills");
44874
+ if (existsSync(projectSkills)) updateHashFromDirectory(hash, projectSkills);
44875
+ }
44876
+ return hash.digest("hex");
44877
+ }
44878
+ function resolveTopLevelSkillsRoot(startDir) {
44879
+ let dir = startDir;
44880
+ while (true) {
44881
+ if (containsSkillDefinitions(join$1(dir, "skills"))) return dir;
44882
+ const parent = dirname$1(dir);
44883
+ if (parent === dir) return null;
44884
+ dir = parent;
44885
+ }
44886
+ }
44887
+ function containsSkillDefinitions(dir) {
44888
+ if (!existsSync(dir)) return false;
44889
+ try {
44890
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
44891
+ if (!entry.isDirectory()) continue;
44892
+ if (existsSync(join$1(dir, entry.name, "SKILL.md")) || existsSync(join$1(dir, entry.name, "skill.md"))) return true;
44893
+ }
44894
+ } catch {
44895
+ return false;
44896
+ }
44897
+ return false;
44898
+ }
44899
+ function updateHashFromDirectory(hash, dir) {
44900
+ const entries = readdirSync(dir, { withFileTypes: true });
44901
+ entries.sort((a, b) => a.name.localeCompare(b.name));
44902
+ for (const entry of entries) {
44903
+ const entryPath = join$1(dir, entry.name);
44904
+ if (entry.isDirectory()) updateHashFromDirectory(hash, entryPath);
44905
+ else if (entry.isFile()) updateHashFromFile(hash, entryPath);
44906
+ }
44907
+ }
44908
+ function updateHashFromFile(hash, filePath) {
44909
+ hash.update(filePath);
44910
+ hash.update(readFileSync(filePath));
44911
+ }
44912
+ /**
44913
+ * Decide whether the startup sync has work to do. Returns `{ needed: false }`
44914
+ * only when the persisted manifest at ~/.overdeck/.sync-manifest.json matches
44915
+ * the current input hash. Any uncertainty (missing input, unreadable manifest,
44916
+ * hash computation error) falls back to `{ needed: true }`.
44917
+ */
44918
+ function isStartupSyncNeededSync() {
44919
+ const manifestPath = join$1(OVERDECK_HOME, ".sync-manifest.json");
44920
+ try {
44921
+ const currentHash = computeSyncInputHash();
44922
+ if (existsSync(manifestPath)) {
44923
+ if (JSON.parse(readFileSync(manifestPath, "utf-8")).hash === currentHash) return {
44924
+ needed: false,
44925
+ reason: "inputs unchanged"
44926
+ };
44927
+ }
44928
+ return {
44929
+ needed: true,
44930
+ reason: "inputs changed or no manifest"
44931
+ };
44932
+ } catch (err) {
44933
+ return {
44934
+ needed: true,
44935
+ reason: `hash computation failed: ${err instanceof Error ? err.message : String(err)}`
44936
+ };
44937
+ }
44938
+ }
44939
+ /**
44940
+ * Write the current sync input hash to ~/.overdeck/.sync-manifest.json.
44941
+ * Call after a full sync so the next startup skip gate can succeed.
44942
+ */
44943
+ function writeSyncManifestSync() {
44944
+ const manifestPath = join$1(OVERDECK_HOME, ".sync-manifest.json");
44945
+ const hash = computeSyncInputHash();
44946
+ writeFileSync(manifestPath, JSON.stringify({
44947
+ hash,
44948
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString()
44949
+ }, null, 2) + "\n", "utf-8");
44950
+ }
44951
+ var init_sync_startup_gate = __esmMin((() => {
44952
+ init_paths();
44953
+ init_projects();
44954
+ init_layers();
44955
+ }));
44956
+ //#endregion
44937
44957
  //#region routes/misc/meta.ts
44938
44958
  init_tracker_config();
44939
44959
  init_issue_id();
44940
44960
  init_projects();
44941
44961
  init_tmux();
44942
- const execAsync$4 = promisify(exec);
44962
+ const execAsync$3 = promisify(exec);
44963
+ const execFileAsync$4 = promisify(execFile);
44943
44964
  function getIssueDataService$1() {
44944
44965
  const { getSharedIssueService } = (init_issue_service_singleton(), __toCommonJS(issue_service_singleton_exports));
44945
44966
  return getSharedIssueService();
@@ -44963,7 +44984,7 @@ const getVersionRoute = HttpRouter.add("GET", "/api/version", Effect.promise(asy
44963
44984
  const version = await getOverdeckVersion();
44964
44985
  let supervisorUrl = null;
44965
44986
  try {
44966
- const { getSupervisorUrlSync } = await import("./supervisor-DHjumXlL.js");
44987
+ const { getSupervisorUrlSync } = await import("./supervisor-CfX192ma.js");
44967
44988
  supervisorUrl = getSupervisorUrlSync();
44968
44989
  } catch {}
44969
44990
  return jsonResponse({
@@ -44973,9 +44994,30 @@ const getVersionRoute = HttpRouter.add("GET", "/api/version", Effect.promise(asy
44973
44994
  });
44974
44995
  }));
44975
44996
  const getPrerequisitesRoute = HttpRouter.add("GET", "/api/prerequisites", Effect.promise(async () => {
44976
- const { checkSystemPrerequisites } = await import("./system-prerequisites-DmFSXIE5.js");
44997
+ const { checkSystemPrerequisites } = await import("./system-prerequisites-DZZTi2G6.js");
44977
44998
  return jsonResponse(await checkSystemPrerequisites());
44978
44999
  }));
45000
+ const getSyncStatusRoute = HttpRouter.add("GET", "/api/sync-status", Effect.sync(() => {
45001
+ const { isStartupSyncNeededSync } = (init_sync_startup_gate(), __toCommonJS(sync_startup_gate_exports));
45002
+ return jsonResponse(isStartupSyncNeededSync());
45003
+ }));
45004
+ const postRunSyncRoute = HttpRouter.add("POST", "/api/system/sync", Effect.promise(async () => {
45005
+ try {
45006
+ const { stdout, stderr } = await execFileAsync$4("pan", ["sync"], {
45007
+ encoding: "utf-8",
45008
+ timeout: 18e4
45009
+ });
45010
+ return jsonResponse({
45011
+ ok: true,
45012
+ output: `${stdout}${stderr}`.trim()
45013
+ });
45014
+ } catch (error) {
45015
+ return jsonResponse({
45016
+ ok: false,
45017
+ error: `pan sync failed: ${String(error?.stderr || error?.message || error)}`
45018
+ }, { status: 500 });
45019
+ }
45020
+ }));
44979
45021
  const getRegisteredProjectsRoute = HttpRouter.add("GET", "/api/registered-projects", Effect.try({
44980
45022
  try: () => {
44981
45023
  return jsonResponse(listProjectsSync().map((p) => ({
@@ -45131,7 +45173,7 @@ const postShadowMonitorRoute = HttpRouter.add("POST", "/api/shadow/:issueId/moni
45131
45173
  const projectPath = await getProjectPath(issuePrefix);
45132
45174
  const workspacePath = join(projectPath, "workspaces", `feature-${issueLower}`);
45133
45175
  if (!existsSync$1(workspacePath)) return jsonResponse({ error: "Workspace not found" }, { status: 404 });
45134
- const { gatherArtifacts, generateBasicInference, updateInferenceDocumentSync } = await import("./shadow-engineering-BhnmtW5m.js");
45176
+ const { gatherArtifacts, generateBasicInference, updateInferenceDocumentSync } = await import("./shadow-engineering-bKuKTCn-.js");
45135
45177
  const config = {
45136
45178
  issueId,
45137
45179
  workspacePath,
@@ -45161,7 +45203,7 @@ const postShadowObserveRoute = HttpRouter.add("POST", "/api/shadow/:issueId/obse
45161
45203
  if (!existsSync$1(workspacePath)) return jsonResponse({ error: "Workspace not found" }, { status: 404 });
45162
45204
  const ghConfig = getGitHubConfig();
45163
45205
  if (!ghConfig) return jsonResponse({ error: "GitHub not configured - Observer requires GitHub" }, { status: 400 });
45164
- const { runObserverCycle } = await import("./shadow-engineering-BhnmtW5m.js");
45206
+ const { runObserverCycle } = await import("./shadow-engineering-bKuKTCn-.js");
45165
45207
  const firstRepo = ghConfig.repos[0];
45166
45208
  const config = {
45167
45209
  issueId,
@@ -45193,7 +45235,7 @@ const postDevRebuildRoute = HttpRouter.add("POST", "/api/dev/rebuild", Effect.ge
45193
45235
  if (!overdeckDevMode || !overdeckProjectRoot) return jsonResponse({ error: "Rebuild only available in dev mode" }, { status: 403 });
45194
45236
  return yield* Effect.promise(async () => {
45195
45237
  try {
45196
- const { stdout, stderr } = await execAsync$4("npm run build", {
45238
+ const { stdout, stderr } = await execAsync$3("npm run build", {
45197
45239
  cwd: overdeckProjectRoot,
45198
45240
  timeout: 12e4
45199
45241
  });
@@ -45225,7 +45267,7 @@ const postRestartDashboardRoute = HttpRouter.add("POST", "/api/system/restart-da
45225
45267
  return jsonResponse({ error: "Restart failed: " + (error instanceof Error ? error.message : String(error)) }, { status: 500 });
45226
45268
  }
45227
45269
  }));
45228
- const metaRouteLayer = Layer.mergeAll(getVersionRoute, getPrerequisitesRoute, getRegisteredProjectsRoute, getConfirmationsRoute, postConfirmationRespondRoute, getSkillsRoute, getCacheStatusRoute, clearCacheRoute, getMetricsRuntimesRoute, getMetricsTasksRoute, postShadowMonitorRoute, postShadowObserveRoute, postDevRebuildRoute, postRestartDashboardRoute);
45270
+ const metaRouteLayer = Layer.mergeAll(getVersionRoute, getPrerequisitesRoute, getSyncStatusRoute, postRunSyncRoute, getRegisteredProjectsRoute, getConfirmationsRoute, postConfirmationRespondRoute, getSkillsRoute, getCacheStatusRoute, clearCacheRoute, getMetricsRuntimesRoute, getMetricsTasksRoute, postShadowMonitorRoute, postShadowObserveRoute, postDevRebuildRoute, postRestartDashboardRoute);
45229
45271
  //#endregion
45230
45272
  //#region routes/misc.ts
45231
45273
  /**
@@ -46020,1401 +46062,6 @@ const getPaletteSearchRoute = HttpRouter.add("GET", "/api/palette/search", Effec
46020
46062
  }));
46021
46063
  const paletteRouteLayer = Layer.mergeAll(getPaletteCommandsRoute, getPaletteSearchRoute);
46022
46064
  //#endregion
46023
- //#region ../../lib/ohmypi-codex-auth.ts
46024
- /**
46025
- * oh-my-pi (omp) OAuth helpers for the openai-codex (ChatGPT subscription) provider.
46026
- * Forked from pi-codex-auth.ts (PAN-1520) for the omp migration (PAN-1989).
46027
- *
46028
- * omp stores its general credentials in ~/.omp/agent/agent.db (SQLite). The
46029
- * openai-codex OAuth credential is persisted separately at ~/.omp/agent/auth.json
46030
- * (same JSON format as Pi's ~/.pi/agent/auth.json) so that this helper's
46031
- * read/write logic is unchanged from the Pi side.
46032
- *
46033
- * This module:
46034
- * - reads/writes the openai-codex credential under ~/.omp/agent/auth.json,
46035
- * - reports auth status (for `pan doctor` and the conversation spawn gate),
46036
- * - refreshes an expired-but-recoverable token, and
46037
- * - drives omp's headless device-code login to re-authenticate.
46038
- *
46039
- * The OAuth module is loaded from the installed `omp` package dynamically.
46040
- * A missing or relocated omp OAuth module degrades to 'unavailable' — never throws.
46041
- */
46042
- const PI_CODEX_PROVIDER = "openai-codex";
46043
- function getOhmypiAuthPath() {
46044
- return join(homedir$1(), ".omp", "agent", "auth.json");
46045
- }
46046
- function readAuthFile() {
46047
- const path = getOhmypiAuthPath();
46048
- if (!existsSync$1(path)) return {};
46049
- try {
46050
- const parsed = JSON.parse(readFileSync$1(path, "utf-8"));
46051
- return parsed && typeof parsed === "object" ? parsed : {};
46052
- } catch {
46053
- return {};
46054
- }
46055
- }
46056
- function readOhmypiCodexCredential() {
46057
- const cred = readAuthFile()[PI_CODEX_PROVIDER];
46058
- if (cred && typeof cred === "object" && typeof cred["access"] === "string" && typeof cred["refresh"] === "string") return cred;
46059
- return null;
46060
- }
46061
- /** Atomically merge a fresh codex credential into auth.json (mode 0600). */
46062
- function writeOhmypiCodexCredential(tokens) {
46063
- const path = getOhmypiAuthPath();
46064
- mkdirSync$1(dirname(path), { recursive: true });
46065
- const auth = readAuthFile();
46066
- const stored = {
46067
- type: "oauth",
46068
- access: tokens.access,
46069
- refresh: tokens.refresh,
46070
- expires: tokens.expires,
46071
- accountId: tokens.accountId
46072
- };
46073
- auth[PI_CODEX_PROVIDER] = stored;
46074
- const tmp = `${path}.tmp-${process.pid}`;
46075
- writeFileSync$1(tmp, JSON.stringify(auth, null, 2), { mode: 384 });
46076
- renameSync$1(tmp, path);
46077
- return stored;
46078
- }
46079
- /** Locate the `omp` executable on PATH (no subprocess — event-loop safe). */
46080
- function findOmpBinary() {
46081
- for (const dir of (process.env["PATH"] ?? "").split(delimiter)) {
46082
- if (!dir) continue;
46083
- const candidate = join(dir, "omp");
46084
- if (existsSync$1(candidate)) return candidate;
46085
- }
46086
- return null;
46087
- }
46088
- /** omp is @oh-my-pi/pi-coding-agent; the oauth submodule path mirrors pi-ai's layout. */
46089
- const OMP_AI_OAUTH_SUBPATH = join("@oh-my-pi", "pi-ai", "dist", "utils", "oauth", "openai-codex.js");
46090
- /**
46091
- * Resolve omp's openai-codex OAuth submodule by walking node_modules upward
46092
- * from the real omp binary. Returns null when not found — the caller degrades
46093
- * gracefully to 'unavailable' status.
46094
- */
46095
- function resolveOmpCodexOAuthFile(ompBin) {
46096
- let dir = dirname(realpathSync$1(ompBin));
46097
- for (let i = 0; i < 10; i++) {
46098
- const candidate = join(dir, "node_modules", OMP_AI_OAUTH_SUBPATH);
46099
- if (existsSync$1(candidate)) return candidate;
46100
- const parent = dirname(dir);
46101
- if (parent === dir) break;
46102
- dir = parent;
46103
- }
46104
- return null;
46105
- }
46106
- let cachedModule = null;
46107
- /**
46108
- * Dynamically load omp's openai-codex OAuth submodule from the installed `omp`
46109
- * package. Returns null on any failure so callers can degrade gracefully.
46110
- */
46111
- async function loadOhmypiCodexOAuth() {
46112
- if (cachedModule) return cachedModule;
46113
- cachedModule = (async () => {
46114
- try {
46115
- const ompBin = findOmpBinary();
46116
- if (!ompBin) return null;
46117
- const oauthFile = resolveOmpCodexOAuthFile(ompBin);
46118
- if (!oauthFile) return null;
46119
- const mod = await import(pathToFileURL(oauthFile).href);
46120
- if (typeof mod.refreshOpenAICodexToken !== "function" || typeof mod.loginOpenAICodexDeviceCode !== "function") return null;
46121
- return mod;
46122
- } catch {
46123
- return null;
46124
- }
46125
- })();
46126
- return cachedModule;
46127
- }
46128
- const EXPIRY_MARGIN_MS = 6e4;
46129
- async function getOhmypiCodexAuthStatus(opts) {
46130
- const cred = readOhmypiCodexCredential();
46131
- if (!cred) return { status: "missing" };
46132
- if (cred.expires > Date.now() + EXPIRY_MARGIN_MS) return {
46133
- status: "ok",
46134
- expiresAt: cred.expires
46135
- };
46136
- if (opts?.refreshIfExpired) {
46137
- const refreshed = await refreshOhmypiCodexAuth();
46138
- if (refreshed) return {
46139
- status: "ok",
46140
- expiresAt: refreshed.expires
46141
- };
46142
- return {
46143
- status: "expired",
46144
- expiresAt: cred.expires,
46145
- refreshFailed: true
46146
- };
46147
- }
46148
- return {
46149
- status: "expired",
46150
- expiresAt: cred.expires,
46151
- refreshFailed: false
46152
- };
46153
- }
46154
- async function refreshOhmypiCodexAuth() {
46155
- const cred = readOhmypiCodexCredential();
46156
- if (!cred?.refresh) return null;
46157
- const mod = await loadOhmypiCodexOAuth();
46158
- if (!mod) return null;
46159
- try {
46160
- return writeOhmypiCodexCredential(await mod.refreshOpenAICodexToken(cred.refresh));
46161
- } catch {
46162
- return null;
46163
- }
46164
- }
46165
- //#endregion
46166
- //#region services/conversation-attachments.ts
46167
- init_paths();
46168
- const CONVERSATION_ATTACHMENTS_DIR = "conversation-attachments";
46169
- /** Run async tasks in bounded batches to avoid unbounded Promise.all
46170
- * that can exhaust file descriptors or memory under heavy load. */
46171
- async function runInBatches(items, batchSize, fn) {
46172
- for (let i = 0; i < items.length; i += batchSize) {
46173
- const batch = items.slice(i, i + batchSize);
46174
- await Promise.all(batch.map(fn));
46175
- }
46176
- }
46177
- /** Max JSONL line length to process. Lines larger than this are skipped to
46178
- * prevent readline from stalling permanently on oversized input (e.g. a
46179
- * single-line base64 payload >15 MB). */
46180
- const MAX_JSONL_LINE_LENGTH = 15 * 1024 * 1024;
46181
- /** Bounded LRU cache for readSessionAttachmentBasenames to avoid full JSONL
46182
- * rescans when the session file has not changed. Key = sessionFile:mtimeMs. */
46183
- const SESSION_ATTACHMENT_CACHE_MAX = 100;
46184
- const sessionAttachmentCache = /* @__PURE__ */ new Map();
46185
- function getAttachmentCacheKey(sessionFile, mtimeMs) {
46186
- return `${sessionFile}:${mtimeMs}`;
46187
- }
46188
- function setAttachmentCache(sessionFile, mtimeMs, basenames) {
46189
- const key = getAttachmentCacheKey(sessionFile, mtimeMs);
46190
- sessionAttachmentCache.set(key, basenames);
46191
- if (sessionAttachmentCache.size > SESSION_ATTACHMENT_CACHE_MAX) {
46192
- const firstKey = sessionAttachmentCache.keys().next().value;
46193
- if (firstKey !== void 0) sessionAttachmentCache.delete(firstKey);
46194
- }
46195
- }
46196
- function getAttachmentCache(sessionFile, mtimeMs) {
46197
- const key = getAttachmentCacheKey(sessionFile, mtimeMs);
46198
- return sessionAttachmentCache.get(key);
46199
- }
46200
- /** Conversation names are sanitized to [a-zA-Z0-9_-]{1,64} on creation.
46201
- * Re-validate here for defense-in-depth against path traversal. */
46202
- function assertSafeName(name) {
46203
- if (!/^[a-zA-Z0-9_-]{1,64}$/.test(name)) throw new Error("Invalid conversation name");
46204
- }
46205
- function getConversationAttachmentsRoot() {
46206
- return join(getOverdeckHome(), CONVERSATION_ATTACHMENTS_DIR);
46207
- }
46208
- function getConversationAttachmentDir(name) {
46209
- assertSafeName(name);
46210
- return join(getConversationAttachmentsRoot(), name);
46211
- }
46212
- async function ensureConversationAttachmentDir(name) {
46213
- const dir = getConversationAttachmentDir(name);
46214
- await mkdir(dir, { recursive: true });
46215
- return dir;
46216
- }
46217
- async function cleanupConversationAttachments(name) {
46218
- assertSafeName(name);
46219
- await rm(getConversationAttachmentDir(name), {
46220
- recursive: true,
46221
- force: true
46222
- });
46223
- }
46224
- /** Safety-net cleanup: remove attachment directories for conversations that no
46225
- * longer exist in the database. Catches orphaned files from abandoned/crashed
46226
- * sessions that the lifecycle poller missed. */
46227
- async function cleanupOrphanedConversationAttachments() {
46228
- try {
46229
- const { listConversations } = await import("./conversations-izHvSoAR.js");
46230
- const convNames = new Set(listConversations().map((c) => c.name));
46231
- const root = getConversationAttachmentsRoot();
46232
- await runInBatches((await readdir(root, { withFileTypes: true })).filter((entry) => entry.isDirectory() && !convNames.has(entry.name)).map((entry) => join(root, entry.name)), 10, (path) => rm(path, {
46233
- recursive: true,
46234
- force: true
46235
- }).catch(() => {}));
46236
- } catch {}
46237
- }
46238
- async function listConversationAttachmentPaths(name) {
46239
- const dir = getConversationAttachmentDir(name);
46240
- try {
46241
- return (await readdir(dir, { withFileTypes: true })).filter((entry) => entry.isFile()).map((entry) => join(dir, entry.name));
46242
- } catch {
46243
- return [];
46244
- }
46245
- }
46246
- /** Synchronous containment check: does the normalized path start with the
46247
- * pre-resolved attachment directory prefix? Uses resolve() (not realpath)
46248
- * so the check is I/O-free — safe because we are only cataloguing references
46249
- * in the JSONL, not accessing the filesystem. */
46250
- function isUnderAttachmentDir(resolvedAttachmentDir, attachmentPath) {
46251
- try {
46252
- return resolve(attachmentPath).startsWith(`${resolvedAttachmentDir}/`);
46253
- } catch {
46254
- return false;
46255
- }
46256
- }
46257
- async function readSessionAttachmentBasenames(sessionFile, name) {
46258
- try {
46259
- let mtimeMs;
46260
- try {
46261
- mtimeMs = (await stat$1(sessionFile)).mtimeMs;
46262
- } catch {
46263
- return /* @__PURE__ */ new Set();
46264
- }
46265
- const cached = getAttachmentCache(sessionFile, mtimeMs);
46266
- if (cached) return cached;
46267
- let resolvedAttachmentDir;
46268
- try {
46269
- resolvedAttachmentDir = await realpath(getConversationAttachmentDir(name));
46270
- } catch {
46271
- resolvedAttachmentDir = resolve(getConversationAttachmentDir(name));
46272
- }
46273
- const referenced = /* @__PURE__ */ new Set();
46274
- const stream = createReadStream$1(sessionFile, { encoding: "utf-8" });
46275
- const rl = createInterface$1({
46276
- input: stream,
46277
- crlfDelay: Infinity
46278
- });
46279
- try {
46280
- for await (const line of rl) {
46281
- if (!line.trim()) continue;
46282
- if (line.length > MAX_JSONL_LINE_LENGTH) continue;
46283
- let text;
46284
- let structuredFoundPaths = false;
46285
- try {
46286
- const entry = JSON.parse(line);
46287
- if (typeof entry?.message?.content === "string") text = entry.message.content;
46288
- else if (Array.isArray(entry?.message?.content)) text = entry.message.content.map((c) => typeof c === "string" ? c : c?.text ?? "").join("");
46289
- else if (typeof entry?.message?.text === "string") text = entry.message.text;
46290
- else if (typeof entry?.text === "string") text = entry.text;
46291
- } catch {
46292
- text = line;
46293
- }
46294
- if (text) {
46295
- for (const attachmentPath of extractConversationAttachmentPaths(text)) if (isUnderAttachmentDir(resolvedAttachmentDir, attachmentPath)) {
46296
- referenced.add(basename(attachmentPath));
46297
- structuredFoundPaths = true;
46298
- }
46299
- }
46300
- if (!structuredFoundPaths) for (const match of line.matchAll(/"@([^"]+)"/g)) {
46301
- const rawValue = match[1];
46302
- if (!rawValue.startsWith("/") && !rawValue.startsWith("\\/")) continue;
46303
- let attachmentPath;
46304
- try {
46305
- attachmentPath = JSON.parse(`"${rawValue}"`);
46306
- } catch {
46307
- attachmentPath = rawValue;
46308
- }
46309
- if (typeof attachmentPath === "string" && attachmentPath.startsWith("/")) {
46310
- if (isUnderAttachmentDir(resolvedAttachmentDir, attachmentPath)) referenced.add(basename(attachmentPath));
46311
- }
46312
- }
46313
- }
46314
- } finally {
46315
- rl.close();
46316
- stream.destroy();
46317
- }
46318
- setAttachmentCache(sessionFile, mtimeMs, referenced);
46319
- return referenced;
46320
- } catch {
46321
- return /* @__PURE__ */ new Set();
46322
- }
46323
- }
46324
- async function cleanupUnreferencedConversationAttachments(conversation) {
46325
- const attachmentPaths = await listConversationAttachmentPaths(conversation.name);
46326
- if (attachmentPaths.length === 0) return;
46327
- if (!conversation.sessionFile) {
46328
- await runInBatches(attachmentPaths, 10, async (attachmentPath) => {
46329
- await rm(attachmentPath, { force: true });
46330
- });
46331
- return;
46332
- }
46333
- let sessionMtimeMs;
46334
- try {
46335
- sessionMtimeMs = (await stat$1(conversation.sessionFile)).mtimeMs;
46336
- } catch {
46337
- return;
46338
- }
46339
- const referencedBasenames = await readSessionAttachmentBasenames(conversation.sessionFile, conversation.name);
46340
- try {
46341
- const freshStats = await stat$1(conversation.sessionFile);
46342
- if (freshStats.mtimeMs > sessionMtimeMs) sessionMtimeMs = freshStats.mtimeMs;
46343
- } catch {}
46344
- await runInBatches(attachmentPaths, 10, async (attachmentPath) => {
46345
- if (referencedBasenames.has(basename(attachmentPath))) return;
46346
- try {
46347
- if ((await stat$1(attachmentPath)).mtimeMs >= sessionMtimeMs) return;
46348
- } catch {
46349
- return;
46350
- }
46351
- await rm(attachmentPath, { force: true });
46352
- });
46353
- }
46354
- function extractConversationAttachmentPaths(message) {
46355
- return Array.from(message.matchAll(/(?<!\S)@(\/[^\s]+)/g), ([, attachmentPath]) => {
46356
- let path = attachmentPath;
46357
- while (path.length > 1 && /[.,;:!?)\]}+"']$/.test(path)) path = path.slice(0, -1);
46358
- return path;
46359
- });
46360
- }
46361
- /** Resolve a path for containment checking, walking parent directories with
46362
- * realpath to preserve symlink detection even when the target file is missing. */
46363
- async function resolveForContainment(attachmentPath) {
46364
- try {
46365
- return await realpath(attachmentPath);
46366
- } catch {
46367
- let dir = dirname(attachmentPath);
46368
- const remaining = [basename(attachmentPath)];
46369
- while (dir !== "/" && dir !== ".") try {
46370
- return join(await realpath(dir), ...remaining);
46371
- } catch {
46372
- remaining.unshift(basename(dir));
46373
- dir = dirname(dir);
46374
- }
46375
- return resolve(attachmentPath);
46376
- }
46377
- }
46378
- async function isManagedConversationAttachmentPath(attachmentPath) {
46379
- try {
46380
- const attachmentsRoot = await realpath(getConversationAttachmentsRoot());
46381
- return (await resolveForContainment(attachmentPath)).startsWith(`${attachmentsRoot}/`);
46382
- } catch {
46383
- return false;
46384
- }
46385
- }
46386
- async function isConversationAttachmentPath(name, attachmentPath) {
46387
- try {
46388
- const attachmentDir = resolve(getConversationAttachmentDir(name));
46389
- return (await resolveForContainment(attachmentPath)).startsWith(`${attachmentDir}/`);
46390
- } catch {
46391
- return false;
46392
- }
46393
- }
46394
- async function hasConversationAttachment(name, attachmentPath) {
46395
- try {
46396
- const attachmentDir = await realpath(getConversationAttachmentDir(name));
46397
- const candidate = await resolveForContainment(attachmentPath);
46398
- if (!candidate.startsWith(`${attachmentDir}/`)) return false;
46399
- return existsSync$1(candidate);
46400
- } catch {
46401
- return false;
46402
- }
46403
- }
46404
- async function removeConversationAttachment(name, attachmentPath) {
46405
- if (!await isConversationAttachmentPath(name, attachmentPath)) return false;
46406
- await rm(attachmentPath, { force: true });
46407
- return true;
46408
- }
46409
- //#endregion
46410
- //#region ../../lib/runtimes/conversation-control.ts
46411
- function conversationControlPaths(agentId, home) {
46412
- const { agentDir } = ohmypiFifoPaths(agentId, home);
46413
- return {
46414
- agentDir,
46415
- controlDir: join(agentDir, "control")
46416
- };
46417
- }
46418
- async function writeConversationControlCommand(agentId, command, home) {
46419
- const paths = conversationControlPaths(agentId, home);
46420
- await mkdir(paths.controlDir, {
46421
- recursive: true,
46422
- mode: 448
46423
- });
46424
- await chmod(paths.controlDir, 448);
46425
- const finalPath = join(paths.controlDir, `${Date.now()}-${command.id}-${randomUUID$1()}.json`);
46426
- const tempPath = `${finalPath}.tmp`;
46427
- await writeFile(tempPath, `${JSON.stringify(command)}\n`, {
46428
- encoding: "utf8",
46429
- mode: 384
46430
- });
46431
- await chmod(tempPath, 384);
46432
- await rename(tempPath, finalPath);
46433
- await chmod(finalPath, 384);
46434
- return finalPath;
46435
- }
46436
- //#endregion
46437
- //#region ../../lib/overdeck/conversation-delivery.ts
46438
- init_conversations();
46439
- init_behavior();
46440
- init_tmux();
46441
- init_agents$1();
46442
- const CONTROL_ACK_TIMEOUT_MS = 1e4;
46443
- const pendingConversationControlAcks = /* @__PURE__ */ new Map();
46444
- const PLAN_ACTION_KEYSTROKES = {
46445
- "approve-auto": "1",
46446
- "approve-manual": "2",
46447
- "reject-ultraplan": "3"
46448
- };
46449
- function registerConversationControlAck(commandId, timeoutMs = CONTROL_ACK_TIMEOUT_MS) {
46450
- const existing = pendingConversationControlAcks.get(commandId);
46451
- if (existing) {
46452
- clearTimeout(existing.timer);
46453
- existing.reject(/* @__PURE__ */ new Error(`Replaced pending conversation control ack ${commandId}`));
46454
- pendingConversationControlAcks.delete(commandId);
46455
- }
46456
- return new Promise((resolve, reject) => {
46457
- const timer = setTimeout(() => {
46458
- pendingConversationControlAcks.delete(commandId);
46459
- reject(/* @__PURE__ */ new Error(`Timed out waiting for conversation control ack ${commandId}`));
46460
- }, timeoutMs);
46461
- pendingConversationControlAcks.set(commandId, {
46462
- resolve: () => {
46463
- clearTimeout(timer);
46464
- pendingConversationControlAcks.delete(commandId);
46465
- resolve();
46466
- },
46467
- reject: (error) => {
46468
- clearTimeout(timer);
46469
- pendingConversationControlAcks.delete(commandId);
46470
- reject(error);
46471
- },
46472
- timer
46473
- });
46474
- });
46475
- }
46476
- function resolveConversationControlAck(ack) {
46477
- const pending = pendingConversationControlAcks.get(ack.id);
46478
- if (!pending) return "unknown";
46479
- if (ack.ok) {
46480
- pending.resolve();
46481
- return "resolved";
46482
- }
46483
- pending.reject(new Error(ack.error || `Conversation control command ${ack.id} failed`));
46484
- return "rejected";
46485
- }
46486
- function handleConversationControlAck(body) {
46487
- const id = typeof body["id"] === "string" ? body["id"].trim() : "";
46488
- if (!id) return {
46489
- status: 400,
46490
- body: { error: "id is required" }
46491
- };
46492
- const ok = body["ok"] === true;
46493
- const error = typeof body["error"] === "string" ? body["error"] : void 0;
46494
- return {
46495
- status: 200,
46496
- body: {
46497
- ok: true,
46498
- outcome: resolveConversationControlAck({
46499
- id,
46500
- ok,
46501
- ...error !== void 0 ? { error } : {}
46502
- })
46503
- }
46504
- };
46505
- }
46506
- function validateConversationControlAckOrigin(headers, method = "POST") {
46507
- const origin = getHeaderFromMap(headers, "origin");
46508
- const referer = getHeaderFromMap(headers, "referer");
46509
- if (!origin && !referer) return { ok: true };
46510
- return validateOriginHeaders(headers, method);
46511
- }
46512
- async function handleConversationCodexApproval(rawId, body) {
46513
- try {
46514
- const optionNumber = Number(body.optionNumber);
46515
- if (!Number.isInteger(optionNumber) || optionNumber < 1 || optionNumber > 9) return jsonResponse({ error: "optionNumber must be an integer 1-9" }, { status: 400 });
46516
- const numericId = Number(rawId);
46517
- const conv = !Number.isNaN(numericId) && /^\d+$/.test(rawId) ? getConversationById(numericId) : getConversationByName(rawId);
46518
- if (!conv) return jsonResponse({ error: "Conversation not found" }, { status: 404 });
46519
- if (getHarnessBehavior(conv.harness).transcriptKind !== "codex-rollout-jsonl") return jsonResponse({ error: "Not a Codex conversation" }, { status: 400 });
46520
- if (!await tmuxSessionExists(conv.tmuxSession)) return jsonResponse({ error: "Conversation session is not running" }, { status: 409 });
46521
- const detection = await Effect.runPromise(detectAwaitingInputForAgent(conv.tmuxSession, {
46522
- isPlanning: false,
46523
- cache: false
46524
- }));
46525
- const parsed = detection ? parseCodexApprovalPrompt(detection.prompt) : null;
46526
- if (!parsed) return jsonResponse({ error: "No Codex approval prompt is currently pending" }, { status: 409 });
46527
- if (optionNumber > parsed.options.length) return jsonResponse({ error: `optionNumber out of range (1-${parsed.options.length})` }, { status: 400 });
46528
- await deliverCodexApprovalChoice(conv.tmuxSession, optionNumber);
46529
- return jsonResponse({
46530
- ok: true,
46531
- optionNumber
46532
- });
46533
- } catch (error) {
46534
- const msg = error instanceof Error ? error.message : String(error);
46535
- console.error("[conversations] codex approval failed:", msg);
46536
- return jsonResponse({ error: "Internal server error" }, { status: 500 });
46537
- }
46538
- }
46539
- async function handleConversationPlanAction(name, body) {
46540
- try {
46541
- const conv = getConversationByName(name);
46542
- if (!conv) return jsonResponse({ error: "Conversation not found" }, { status: 404 });
46543
- const action = typeof body["action"] === "string" ? body["action"] : "";
46544
- const feedback = typeof body["feedback"] === "string" ? body["feedback"].trim() : "";
46545
- if (action === "reject-feedback") {
46546
- await Effect.runPromise(sendRawKeystroke(conv.tmuxSession, "4", "plan-action-reject"));
46547
- if (feedback) {
46548
- await new Promise((r) => setTimeout(r, 300));
46549
- await deliverAgentMessage(conv.tmuxSession, feedback, "plan-action-feedback", resolveConversationDeliveryMethod(conv));
46550
- }
46551
- return jsonResponse({ ok: true });
46552
- }
46553
- const keystroke = PLAN_ACTION_KEYSTROKES[action];
46554
- if (!keystroke) return jsonResponse({ error: `Invalid action: ${action}` }, { status: 400 });
46555
- await Effect.runPromise(sendRawKeystroke(conv.tmuxSession, keystroke, `plan-action-${action}`));
46556
- return jsonResponse({ ok: true });
46557
- } catch (error) {
46558
- const msg = error instanceof Error ? error.message : String(error);
46559
- console.error("[conversations] plan action failed:", msg);
46560
- return jsonResponse({ error: "Internal server error" }, { status: 500 });
46561
- }
46562
- }
46563
- const THINKING_LEVELS = [
46564
- "off",
46565
- "minimal",
46566
- "low",
46567
- "medium",
46568
- "high",
46569
- "xhigh"
46570
- ];
46571
- const PI_CONVERSATION_ABORT_KEY = "Escape";
46572
- function isPiControlChannelHarness(harness) {
46573
- return harness === "ohmypi" || harness === "pi";
46574
- }
46575
- function parseThinkingLevel(value) {
46576
- return typeof value === "string" && THINKING_LEVELS.includes(value) ? value : null;
46577
- }
46578
- function pickDeliverAs(bodyDeliverAs) {
46579
- if (bodyDeliverAs === "follow_up") return "follow_up";
46580
- return "steer";
46581
- }
46582
- function resolveConversationDeliveryMethod(conv) {
46583
- const harness = conv.harness ?? "claude-code";
46584
- if (isPiControlChannelHarness(harness)) return "auto";
46585
- return conv.deliveryMethod ?? (getHarnessBehavior(harness).deliveryKind === "rpc-fifo" ? "tmux" : "auto");
46586
- }
46587
- async function sendConversationControlCommand(conv, commandInput) {
46588
- const id = randomUUID$1();
46589
- const ackPromise = registerConversationControlAck(id);
46590
- const command = {
46591
- id,
46592
- ...commandInput
46593
- };
46594
- try {
46595
- await writeConversationControlCommand(conv.tmuxSession, command);
46596
- } catch (err) {
46597
- resolveConversationControlAck({
46598
- id,
46599
- ok: false,
46600
- error: err instanceof Error ? err.message : String(err)
46601
- });
46602
- }
46603
- await ackPromise;
46604
- }
46605
- async function deliverConversationViaControlChannel(conv, message, options) {
46606
- await sendConversationControlCommand(conv, {
46607
- type: options.deliverAs,
46608
- message,
46609
- source: options.source
46610
- });
46611
- }
46612
- async function handleConversationThinkingLevel(name, body) {
46613
- const conv = getConversationByName(name);
46614
- if (!conv) return jsonResponse({ error: "Conversation not found" }, { status: 404 });
46615
- if (!isPiControlChannelHarness(conv.harness ?? "claude-code")) return jsonResponse({ error: "Thinking level control is only supported for Pi conversations" }, { status: 400 });
46616
- if (conv.status === "ended") return jsonResponse({ error: "Session has ended — start a new run to interact" }, { status: 422 });
46617
- const level = parseThinkingLevel(body["level"]);
46618
- if (!level) return jsonResponse({ error: "Invalid thinking level" }, { status: 400 });
46619
- await sendConversationControlCommand(conv, {
46620
- type: "set_thinking_level",
46621
- level
46622
- });
46623
- setConversationEffort(name, level);
46624
- return jsonResponse({
46625
- ok: true,
46626
- effort: (getConversationByName(name) ?? conv).effort ?? level
46627
- });
46628
- }
46629
- async function handleConversationCompact(name) {
46630
- const conv = getConversationByName(name);
46631
- if (!conv) return jsonResponse({ error: "Conversation not found" }, { status: 404 });
46632
- if (!isPiControlChannelHarness(conv.harness ?? "claude-code")) return jsonResponse({ error: "Compact control endpoint is only supported for Pi conversations" }, { status: 400 });
46633
- if (conv.status === "ended") return jsonResponse({ error: "Session has ended — start a new run to interact" }, { status: 422 });
46634
- await sendConversationControlCommand(conv, { type: "compact" });
46635
- return jsonResponse({ ok: true });
46636
- }
46637
- async function handleConversationAbort(name) {
46638
- const conv = getConversationByName(name);
46639
- if (!conv) return jsonResponse({ error: "Conversation not found" }, { status: 404 });
46640
- if (!isPiControlChannelHarness(conv.harness ?? "claude-code")) return jsonResponse({ error: "Abort control endpoint is only supported for Pi conversations" }, { status: 400 });
46641
- if (conv.status === "ended") return jsonResponse({ error: "Session has ended — start a new run to interact" }, { status: 422 });
46642
- await sendKeysAsync(conv.tmuxSession, PI_CONVERSATION_ABORT_KEY, "conversation-abort");
46643
- return jsonResponse({
46644
- ok: true,
46645
- key: PI_CONVERSATION_ABORT_KEY
46646
- });
46647
- }
46648
- async function handleConversationDeliveryMethod(name, body) {
46649
- if (!getConversationByName(name)) return jsonResponse({ error: "Conversation not found" }, { status: 404 });
46650
- const deliveryMethod = body["deliveryMethod"] ?? body["method"];
46651
- if (deliveryMethod !== "auto" && deliveryMethod !== "channels" && deliveryMethod !== "tmux" && deliveryMethod !== null) return jsonResponse({ error: "deliveryMethod must be 'auto', 'channels', 'tmux', or null" }, { status: 400 });
46652
- updateConversationDeliveryMethod(name, deliveryMethod);
46653
- return jsonResponse({
46654
- ok: true,
46655
- deliveryMethod
46656
- });
46657
- }
46658
- const CODEX_APPROVAL_TOOL_PREFIX = "codex-approval:";
46659
- async function codexConversationPendingInput(conv, sessionAlive, askedAt) {
46660
- if (!sessionAlive || getHarnessBehavior(conv.harness).transcriptKind !== "codex-rollout-jsonl") return { kinds: [] };
46661
- try {
46662
- const detection = await Effect.runPromise(detectAwaitingInputForAgent(conv.tmuxSession, { isPlanning: false }));
46663
- if (!detection) return { kinds: [] };
46664
- if (detection.reason === "session_resume") return { kinds: ["sessionResume"] };
46665
- const parsed = parseCodexApprovalPrompt(detection.prompt);
46666
- if (parsed) return {
46667
- kinds: ["permissionRequest"],
46668
- approval: {
46669
- toolUseId: `${CODEX_APPROVAL_TOOL_PREFIX}${conv.tmuxSession}`,
46670
- askedAt,
46671
- questions: [{
46672
- question: parsed.detail ? `${parsed.header}\n\n${parsed.detail}` : parsed.header,
46673
- header: "Codex approval",
46674
- multiSelect: false,
46675
- options: parsed.options.map((o) => ({ label: `${o.number}. ${o.label}` }))
46676
- }]
46677
- }
46678
- };
46679
- return { kinds: ["permissionRequest"] };
46680
- } catch {
46681
- return { kinds: [] };
46682
- }
46683
- }
46684
- async function deliverCodexApprovalChoice(tmuxSession, optionNumber) {
46685
- for (let i = 1; i < optionNumber; i += 1) {
46686
- await Effect.runPromise(sendRawKeystroke(tmuxSession, "Down", "codex-approval"));
46687
- await new Promise((r) => setTimeout(r, 60));
46688
- }
46689
- await Effect.runPromise(sendRawKeystroke(tmuxSession, "Enter", "codex-approval"));
46690
- }
46691
- //#endregion
46692
- //#region ../../lib/overdeck/conversation-runtime.ts
46693
- init_child_env();
46694
- init_claude_permissions();
46695
- init_projects();
46696
- init_conversations();
46697
- init_tmux();
46698
- init_agents$1();
46699
- init_config_yaml();
46700
- init_harness_policy();
46701
- init_providers();
46702
- init_behavior();
46703
- init_launcher_generator();
46704
- init_layers();
46705
- init_briefing_freshness();
46706
- init_paths();
46707
- init_event_store();
46708
- const execAsync$3 = promisify(exec);
46709
- const execFileAsync$3 = promisify(execFile);
46710
- const PROCESS_CLEANUP_GRACE_MS = 750;
46711
- const PTY_SUPERVISOR_SOCKET_WAIT_MS = 3e4;
46712
- function parseProcessTable(output) {
46713
- return output.split("\n").map((line) => {
46714
- const match = line.match(/^\s*(\d+)\s+(\d+)\s+(.*)$/);
46715
- if (!match) return null;
46716
- return {
46717
- pid: Number(match[1]),
46718
- ppid: Number(match[2]),
46719
- args: match[3] ?? ""
46720
- };
46721
- }).filter((row) => row !== null && Number.isFinite(row.pid) && Number.isFinite(row.ppid));
46722
- }
46723
- async function readProcessTable() {
46724
- const { stdout } = await execFileAsync$3("ps", ["-eo", "pid=,ppid=,args="], {
46725
- encoding: "utf-8",
46726
- maxBuffer: 10 * 1024 * 1024
46727
- });
46728
- return parseProcessTable(stdout);
46729
- }
46730
- function collectProcessTree(rootPids, rows) {
46731
- const childrenByParent = /* @__PURE__ */ new Map();
46732
- for (const row of rows) {
46733
- const children = childrenByParent.get(row.ppid) ?? [];
46734
- children.push(row.pid);
46735
- childrenByParent.set(row.ppid, children);
46736
- }
46737
- const seen = /* @__PURE__ */ new Set();
46738
- const ordered = [];
46739
- const visit = (pid) => {
46740
- if (seen.has(pid) || pid === process.pid) return;
46741
- seen.add(pid);
46742
- for (const child of childrenByParent.get(pid) ?? []) visit(child);
46743
- ordered.push(pid);
46744
- };
46745
- for (const pid of rootPids) visit(pid);
46746
- return ordered;
46747
- }
46748
- function isProcessAlive$1(pid) {
46749
- try {
46750
- process.kill(pid, 0);
46751
- return true;
46752
- } catch {
46753
- return false;
46754
- }
46755
- }
46756
- async function terminatePids(pids) {
46757
- if (pids.length === 0) return;
46758
- for (const pid of pids) try {
46759
- process.kill(pid, "SIGTERM");
46760
- } catch {}
46761
- await new Promise((resolve) => setTimeout(resolve, PROCESS_CLEANUP_GRACE_MS));
46762
- for (const pid of pids) {
46763
- if (!isProcessAlive$1(pid)) continue;
46764
- try {
46765
- process.kill(pid, "SIGKILL");
46766
- } catch {}
46767
- }
46768
- }
46769
- function conversationRuntimeRootPids(conv, rows) {
46770
- const launcherScript = join(getOverdeckHome(), "conversations", conv.tmuxSession, "launcher.sh");
46771
- const sessionId = conv.claudeSessionId?.trim();
46772
- const sessionNeedles = sessionId ? [`--resume ${sessionId}`, `--session-id ${sessionId}`] : [];
46773
- const serverPid = findManagedServerPidSync();
46774
- return rows.filter((row) => {
46775
- if (row.pid === process.pid) return false;
46776
- if (serverPid !== void 0 && row.pid === serverPid) return false;
46777
- if (row.args.includes(launcherScript)) return true;
46778
- return sessionNeedles.some((needle) => row.args.includes(needle));
46779
- }).map((row) => row.pid);
46780
- }
46781
- async function killConversationRuntimeProcesses(conv) {
46782
- const rows = await readProcessTable();
46783
- await terminatePids(collectProcessTree(conversationRuntimeRootPids(conv, rows), rows));
46784
- }
46785
- async function stopConversationRuntime(conv, name) {
46786
- if (hasOtherActiveConversationOnTmuxSession(conv.tmuxSession, name)) return;
46787
- await Effect.runPromise(killSession(conv.tmuxSession).pipe(Effect.catch(() => Effect.succeed(void 0))));
46788
- try {
46789
- await killConversationRuntimeProcesses(conv);
46790
- } catch (error) {
46791
- const msg = error instanceof Error ? error.message : String(error);
46792
- console.warn(`[conversations] failed to cleanup runtime processes for ${name}: ${msg}`);
46793
- }
46794
- }
46795
- /** Quote a string for safe use in a bash script using single-quote wrapping. */
46796
- function shellQuote(str) {
46797
- return "'" + str.replace(/'/g, "'\"'\"'") + "'";
46798
- }
46799
- const SAFE_MODEL_PATTERN$1 = /^[a-zA-Z0-9_.:\/-]+$/;
46800
- const SAFE_EFFORT_PATTERN = /^(low|medium|high)$/;
46801
- const SAFE_ISSUE_ID_PATTERN = /^[A-Z0-9]+-[0-9]+$/;
46802
- const PI_CONVERSATION_SOURCE_CONTRACT = [
46803
- "Pi conversation source contract:",
46804
- "A message marked source:'extension' was injected by the Overdeck orchestrator or another agent, not typed by the human operator.",
46805
- "Treat it as coordination guidance; do not attribute it to the human operator."
46806
- ].join(" ");
46807
- async function resolveAllowedHarness(requested, model) {
46808
- if (!model) return "claude-code";
46809
- return resolveHarness({
46810
- model,
46811
- explicit: requested === "ohmypi" || requested === "claude-code" || requested === "codex" ? requested : void 0
46812
- });
46813
- }
46814
- async function isInsideGitWorkTree(dir) {
46815
- try {
46816
- const { stdout } = await execAsync$3("git rev-parse --is-inside-work-tree", {
46817
- cwd: dir,
46818
- encoding: "utf-8"
46819
- });
46820
- return stdout.trim() === "true";
46821
- } catch {
46822
- return false;
46823
- }
46824
- }
46825
- async function validateCwdContainment$1(cwd) {
46826
- if (!cwd.startsWith("/")) return false;
46827
- if (cwd.split("/").filter(Boolean).includes("..")) return false;
46828
- try {
46829
- const resolved = await realpath(cwd);
46830
- if (!(await stat$1(resolved)).isDirectory()) return false;
46831
- const home = homedir$1();
46832
- return resolved.startsWith(`${home}/`) || resolved === home;
46833
- } catch {
46834
- return false;
46835
- }
46836
- }
46837
- async function waitForClaudeReady(tmuxSession) {
46838
- const deadline = Date.now() + 3e4;
46839
- while (Date.now() < deadline) {
46840
- if ((await Effect.runPromise(capturePane(tmuxSession, 200))).includes("❯")) {
46841
- console.log(`[conversations] Claude Code ready in ${tmuxSession}`);
46842
- return;
46843
- }
46844
- await new Promise((r) => setTimeout(r, 500));
46845
- }
46846
- console.warn(`[conversations] Timed out waiting for Claude Code prompt in ${tmuxSession}`);
46847
- }
46848
- function isPiTuiInputReady(snapshot) {
46849
- return /^\s*[❯›>]\s/m.test(snapshot) || /(?:^|\s)0(?:\.\d+)?%\s+context\s+used\b/i.test(snapshot) || /⬢[^\n]*◕/.test(snapshot);
46850
- }
46851
- async function waitForPiTuiReady(tmuxSession, timeoutMs = 6e4) {
46852
- const deadline = Date.now() + timeoutMs;
46853
- while (Date.now() < deadline) {
46854
- if (isPiTuiInputReady(await Effect.runPromise(capturePane(tmuxSession, 40).pipe(Effect.catch(() => Effect.succeed("")))))) {
46855
- console.log(`[conversations] Pi TUI ready for ${tmuxSession}`);
46856
- return true;
46857
- }
46858
- await new Promise((r) => setTimeout(r, 250));
46859
- }
46860
- console.warn(`[conversations] Timed out waiting for Pi TUI to render in ${tmuxSession}`);
46861
- return false;
46862
- }
46863
- function shouldReportUnresolvedLiveSession(conv) {
46864
- if (!conv || conv.status !== "active") return false;
46865
- return getHarnessBehavior(conv.harness).transcriptKind === "claude-jsonl";
46866
- }
46867
- function conversationSessionAliveFromState(conv, tmuxSessionAlive) {
46868
- return conv.status === "active" && !conv.forkStatus && tmuxSessionAlive;
46869
- }
46870
- function conversationNeedsRunningRepair(conv, tmuxSessionAlive, harnessProcessAlive) {
46871
- return conv.status === "ended" && !conv.forkStatus && tmuxSessionAlive && harnessProcessAlive;
46872
- }
46873
- /** Generate a default conversation name, e.g. 20260404-1234 */
46874
- function generateConversationName() {
46875
- return `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10).replace(/-/g, "")}-${Math.floor(Math.random() * 9e3 + 1e3)}`;
46876
- }
46877
- async function tmuxSessionExists(sessionName) {
46878
- return Effect.runPromise(sessionExists(sessionName));
46879
- }
46880
- async function waitForTmuxSession(sessionName, timeoutMs = 3e4) {
46881
- const start = Date.now();
46882
- while (Date.now() - start < timeoutMs) {
46883
- if (await Effect.runPromise(sessionExists(sessionName))) return;
46884
- await new Promise((r) => setTimeout(r, 250));
46885
- }
46886
- throw new Error(`Timed out waiting for tmux session ${sessionName}`);
46887
- }
46888
- function shouldUseSupervisorForConversation(harness) {
46889
- return getHarnessBehavior(harness).supportsPtySupervisor && process.env.OVERDECK_DOCKER_WORKSPACE !== "1" && process.env.PAN_DOCKER !== "1";
46890
- }
46891
- async function waitForConversationRuntimeReady(tmuxSession, harness, mode) {
46892
- const transcriptKind = getHarnessBehavior(harness).transcriptKind;
46893
- if (transcriptKind === "ohmypi-jsonl") {
46894
- if (!await waitForPiTuiReady(tmuxSession)) throw new Error(`Pi (ohmypi) did not become interactive in ${tmuxSession} within the startup window — MCP server connections are likely still in progress. Retry once MCP servers finish connecting, or check ~/.claude/mcp.json for a slow/hanging server.`);
46895
- } else if (transcriptKind !== "codex-rollout-jsonl" && mode === "spawn") {
46896
- await waitForClaudeReady(tmuxSession);
46897
- console.log(`[conversations] Claude ready in ${tmuxSession}`);
46898
- } else if (transcriptKind !== "codex-rollout-jsonl") await waitForReadySignal(tmuxSession, 30);
46899
- }
46900
- async function handleConversationSwitchModel(name, body) {
46901
- const conv = getConversationByName(name);
46902
- if (!conv) return jsonResponse({ error: "Conversation not found" }, { status: 404 });
46903
- const model = typeof body["model"] === "string" && body["model"].trim() ? body["model"].trim() : conv.model ?? void 0;
46904
- const currentHarness = conv.harness ?? "claude-code";
46905
- const requestedHarness = body["harness"];
46906
- let harness = currentHarness;
46907
- if (requestedHarness === "ohmypi" || requestedHarness === "pi" || requestedHarness === "claude-code" || requestedHarness === "codex") {
46908
- const requestedRuntime = requestedHarness === "pi" ? "ohmypi" : requestedHarness;
46909
- if (requestedRuntime !== currentHarness) {
46910
- const policyModel = model ?? conv.model ?? "";
46911
- const decision = canUseHarnessSync(requestedRuntime, policyModel, await getProviderAuthMode(policyModel));
46912
- if (!decision.allowed) return jsonResponse({ error: decision.reason ?? "Harness not allowed for this model" }, { status: 400 });
46913
- }
46914
- harness = requestedRuntime;
46915
- }
46916
- const harnessChanged = harness !== currentHarness;
46917
- if (!await validateCwdContainment$1(conv.cwd)) return jsonResponse({ error: "Invalid cwd" }, { status: 400 });
46918
- if (model && !SAFE_MODEL_PATTERN$1.test(model)) return jsonResponse({ error: "Invalid model" }, { status: 400 });
46919
- const livePiSwitch = isPiControlChannelHarness(currentHarness) && conv.status !== "ended";
46920
- if (conv.claudeSessionId && harnessChanged) return jsonResponse({ error: "Conversation harness is locked once a conversation has started" }, { status: 409 });
46921
- if (conv.claudeSessionId && !livePiSwitch) return jsonResponse({ error: "Conversation model is locked once a conversation has started" }, { status: 409 });
46922
- if (model) {
46923
- if (livePiSwitch) await sendConversationControlCommand(conv, {
46924
- type: "set_model",
46925
- model
46926
- });
46927
- setConversationModel(name, model);
46928
- }
46929
- if (harnessChanged) setConversationHarness(name, harness);
46930
- const updated = getConversationByName(name) ?? conv;
46931
- return jsonResponse({
46932
- ...updated,
46933
- model: model ?? updated.model,
46934
- harness,
46935
- sessionAlive: false
46936
- });
46937
- }
46938
- function getPtySupervisorSocketPath(agentId) {
46939
- return join(getOverdeckHome(), "sockets", `pty-${agentId}.sock`);
46940
- }
46941
- async function waitForPtySupervisorSocket(agentId, timeoutMs = PTY_SUPERVISOR_SOCKET_WAIT_MS) {
46942
- const socketPath = getPtySupervisorSocketPath(agentId);
46943
- const start = Date.now();
46944
- while (Date.now() - start < timeoutMs) {
46945
- try {
46946
- if (((await stat$1(socketPath)).mode & 511) === 384) return;
46947
- } catch {}
46948
- await new Promise((r) => setTimeout(r, 250));
46949
- }
46950
- throw new Error(`Timed out waiting for PTY supervisor socket ${socketPath}`);
46951
- }
46952
- async function extractModelFromSessionFile(sessionFile) {
46953
- try {
46954
- if (!existsSync$1(sessionFile)) return null;
46955
- const stream = createReadStream$1(sessionFile, { encoding: "utf-8" });
46956
- const rl = createInterface$1({
46957
- input: stream,
46958
- crlfDelay: Infinity
46959
- });
46960
- try {
46961
- for await (const line of rl) {
46962
- if (!line.trim()) continue;
46963
- const entry = JSON.parse(line);
46964
- if (entry.type === "assistant" && entry.message?.model) return entry.message.model;
46965
- }
46966
- } finally {
46967
- rl.close();
46968
- stream.destroy();
46969
- }
46970
- } catch {}
46971
- return null;
46972
- }
46973
- let backfillRunning = false;
46974
- async function backfillConversationModels(resolveSessionFile) {
46975
- if (backfillRunning) return;
46976
- backfillRunning = true;
46977
- try {
46978
- const convs = listConversations();
46979
- const probe = await Promise.all(convs.map(async (conv) => !conv.model ? await resolveSessionFile(conv) : null));
46980
- const candidates = convs.filter((_, i) => probe[i] !== null);
46981
- const BATCH_SIZE = 10;
46982
- let backfilled = 0;
46983
- for (let i = 0; i < candidates.length; i += BATCH_SIZE) {
46984
- const batch = candidates.slice(i, i + BATCH_SIZE);
46985
- const results = await Promise.all(batch.map(async (conv) => {
46986
- const sessionFile = await resolveSessionFile(conv);
46987
- if (!sessionFile) return false;
46988
- const model = await extractModelFromSessionFile(sessionFile);
46989
- if (model && SAFE_MODEL_PATTERN$1.test(model)) {
46990
- backfillConversationModel(conv.name, model);
46991
- return true;
46992
- }
46993
- return false;
46994
- }));
46995
- backfilled += results.filter(Boolean).length;
46996
- }
46997
- if (backfilled > 0) console.log(`[conversations] Backfilled model for ${backfilled} conversation(s)`);
46998
- } finally {
46999
- backfillRunning = false;
47000
- }
47001
- }
47002
- function startConversationModelBackfill(resolveSessionFile) {
47003
- backfillConversationModels(resolveSessionFile).catch((err) => {
47004
- console.error("[conversations] Model backfill failed:", err);
47005
- });
47006
- }
47007
- async function claudeConversationSystemPromptFiles(cwd) {
47008
- const files = [];
47009
- const contextFile = workspaceContextFile(cwd);
47010
- try {
47011
- await stat$1(contextFile);
47012
- files.push(contextFile);
47013
- } catch (error) {
47014
- if (!isNotFound(error)) throw error;
47015
- }
47016
- files.push(await ensureSessionContextBriefingFile());
47017
- return files;
47018
- }
47019
- async function ensurePiConversationSourceContractFile() {
47020
- const contextDir = join(getOverdeckHome(), "context");
47021
- await mkdir(contextDir, { recursive: true });
47022
- const path = join(contextDir, "pi-conversation-source-contract.md");
47023
- await writeFile(path, `${PI_CONVERSATION_SOURCE_CONTRACT}\n`, "utf-8");
47024
- return path;
47025
- }
47026
- async function piConversationSystemPromptFiles(cwd) {
47027
- const files = [];
47028
- const globalFile = piGlobalContextFile();
47029
- try {
47030
- await stat$1(globalFile);
47031
- files.push(globalFile);
47032
- } catch (error) {
47033
- if (!isNotFound(error)) throw error;
47034
- }
47035
- files.push(await ensurePiConversationSourceContractFile());
47036
- const contextFile = workspaceContextFile(cwd);
47037
- try {
47038
- await stat$1(contextFile);
47039
- files.push(contextFile);
47040
- } catch (error) {
47041
- if (!isNotFound(error)) throw error;
47042
- }
47043
- files.push(await ensureSessionContextBriefingFile());
47044
- return files;
47045
- }
47046
- function isNotFound(error) {
47047
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
47048
- }
47049
- async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model, effort, issueId, resume = false, harness = "claude-code", plainFork = false) {
47050
- const behavior = getHarnessBehavior(harness);
47051
- const stateDir = join(getOverdeckHome(), "conversations", tmuxSession);
47052
- await mkdir(stateDir, { recursive: true });
47053
- clearReadySignal(tmuxSession);
47054
- const launcherScript = join(stateDir, "launcher.sh");
47055
- let runtimeCommand = `claude ${getClaudePermissionFlagsStringSync()}`;
47056
- let providerExportsStr = "";
47057
- let piFields;
47058
- let codexFields;
47059
- if (model) {
47060
- if (!SAFE_MODEL_PATTERN$1.test(model)) throw new Error("Invalid model name");
47061
- runtimeCommand = await getAgentRuntimeBaseCommand(model, void 0, void 0, harness);
47062
- const mode = resolvePermissionModeSync();
47063
- if (!runtimeCommand.includes("--permission-mode")) runtimeCommand = `${runtimeCommand} --permission-mode ${mode === "auto" ? "auto" : BYPASS_PERMISSION_MODE}`;
47064
- providerExportsStr = (await getProviderExportsForModel(model)).trim();
47065
- await getProviderEnvForModel(model);
47066
- if (behavior.transcriptKind === "ohmypi-jsonl") {
47067
- if (getProviderForModelSync(model).name === "openai") {
47068
- const auth = await getOhmypiCodexAuthStatus({ refreshIfExpired: true });
47069
- if (auth.status === "missing" || auth.status === "expired") throw new Error("ohmypi ChatGPT/Codex login (openai-codex) has expired and could not be refreshed. Re-authenticate with `pan pi-auth login`, then retry.");
47070
- }
47071
- const paths = piFifoPaths(tmuxSession);
47072
- const piSessionDir = join(paths.agentDir, "sessions");
47073
- await mkdir(paths.agentDir, {
47074
- recursive: true,
47075
- mode: 448
47076
- });
47077
- await mkdir(piSessionDir, {
47078
- recursive: true,
47079
- mode: 448
47080
- });
47081
- const storedPiSessionId = resume ? await readFile(join(paths.agentDir, "session.id"), "utf-8").then((s) => s.trim()).catch(() => void 0) : void 0;
47082
- piFields = {
47083
- harness: "ohmypi",
47084
- piMode: "tui",
47085
- piExtensionPath: resolveOhmypiExtensionPath() ?? resolve(process.cwd(), "packages/ohmypi-extension/dist/index.js"),
47086
- piSessionDir,
47087
- resumeSessionId: storedPiSessionId || void 0
47088
- };
47089
- } else if (behavior.usesCodexHome) {
47090
- const codexHome = join(getOverdeckHome(), "agents", tmuxSession, "codex-home");
47091
- const codexPermMode = loadConfigSync().config.codex?.permissionMode ?? "workspace";
47092
- const codexApprovalPolicy = codexPermMode === "full-access" ? "never" : "on-request";
47093
- const codexSandboxMode = codexPermMode === "full-access" ? "danger-full-access" : codexPermMode === "read-only" ? "read-only" : "workspace-write";
47094
- const codexApprovalsReviewer = codexPermMode === "auto-review" ? "auto_review" : void 0;
47095
- const { initCodexHome, extractThreadIdFromRollout } = await import("./codex-B7DTpwEw.js");
47096
- initCodexHome(codexHome, {
47097
- trustedDir: cwd,
47098
- approvalPolicy: codexApprovalPolicy,
47099
- sandboxMode: codexSandboxMode,
47100
- approvalsReviewer: codexApprovalsReviewer
47101
- });
47102
- const resumeSessionId = resume ? await resolveCodexRolloutPath(tmuxSession, { agentsDirOverride: join(getOverdeckHome(), "agents") }).then((rollout) => rollout ? extractThreadIdFromRollout(rollout) ?? void 0 : void 0) : void 0;
47103
- codexFields = {
47104
- harness: "codex",
47105
- codexMode: "tui",
47106
- codexHome,
47107
- codexSessionDir: join(codexHome, "sessions"),
47108
- resumeSessionId
47109
- };
47110
- }
47111
- }
47112
- let launcherModel = model;
47113
- if (behavior.contextLayerKind === "pi" && model) {
47114
- const piProvider = piProviderForModel(model);
47115
- if (piProvider) launcherModel = `${piProvider}/${model}`;
47116
- }
47117
- if (effort && !SAFE_EFFORT_PATTERN.test(effort)) throw new Error("Invalid effort level");
47118
- const useSupervisor = shouldUseSupervisorForConversation(harness);
47119
- let supervisorScriptPath;
47120
- if (useSupervisor) {
47121
- supervisorScriptPath = resolvePtySupervisorScriptPath();
47122
- await writePtyToken(tmuxSession);
47123
- }
47124
- let channelsBridgeMcpConfig;
47125
- if (!piFields && !codexFields && !plainFork && isClaudeCodeChannelsEnabled() && (!model || getProviderForModelSync(model).name === "anthropic") && process.env.CLAUDE_CODE_USE_BEDROCK !== "1" && process.env.CLAUDE_CODE_USE_VERTEX !== "1" && process.env.CLAUDE_CODE_USE_FOUNDRY !== "1" && process.env.OVERDECK_DOCKER_WORKSPACE !== "1" && process.env.PAN_DOCKER !== "1") {
47126
- channelsBridgeMcpConfig = join(stateDir, "agent-mcp.json");
47127
- writeBridgeTokenSync(tmuxSession);
47128
- await writeChannelsBridgeMcpConfig(channelsBridgeMcpConfig, tmuxSession);
47129
- }
47130
- const launcherTmp = `${launcherScript}.${randomUUID$1()}.tmp`;
47131
- await writeFile(launcherTmp, generateLauncherScriptSync({
47132
- role: "work",
47133
- spawnMode: "conversation",
47134
- workingDir: cwd,
47135
- setTerminalEnv: true,
47136
- unsetProviderEnv: true,
47137
- overdeckEnv: {
47138
- ...issueId ? { issueId } : {},
47139
- ...piFields || codexFields || useSupervisor ? { agentId: tmuxSession } : {}
47140
- },
47141
- extraEnvExports: [`export OVERDECK_DASHBOARD_URL="http://127.0.0.1:${process.env["API_PORT"] ?? process.env["PORT"] ?? "3011"}"`],
47142
- providerExports: providerExportsStr || void 0,
47143
- trapHup: true,
47144
- baseCommand: runtimeCommand,
47145
- appendSystemPromptFiles: piFields ? await piConversationSystemPromptFiles(cwd) : codexFields ? [] : await claudeConversationSystemPromptFiles(cwd),
47146
- model: launcherModel,
47147
- ...piFields ?? codexFields ?? {
47148
- resumeSessionId: resume ? claudeSessionId : void 0,
47149
- sessionId: resume ? void 0 : claudeSessionId
47150
- },
47151
- extraArgs: !piFields && effort ? `--effort "${effort}"` : void 0,
47152
- keepAlive: true,
47153
- fileMode: 448,
47154
- channelsBridgeMcpConfig,
47155
- useSupervisor,
47156
- supervisorScriptPath
47157
- }), { mode: 448 });
47158
- await rename(launcherTmp, launcherScript);
47159
- try {
47160
- await Effect.runPromise(killSession(tmuxSession));
47161
- } catch {}
47162
- console.log(`[claude-invoke] purpose=conversation-session | model=${model || "default"} | source=conversations.ts:spawnConversationSession | session=${tmuxSession} | resume=${resume} | command="${runtimeCommand}"`);
47163
- try {
47164
- const { preTrustDirectory } = await import("./workspace-manager-DjUAJCSs.js");
47165
- preTrustDirectory(cwd);
47166
- } catch {}
47167
- try {
47168
- await Effect.runPromise(createSession(tmuxSession, cwd, `bash ${shellQuote(launcherScript)}`, { env: {
47169
- ...BLANKED_PROVIDER_ENV,
47170
- TERM: "xterm-256color"
47171
- } }));
47172
- } catch (err) {
47173
- if (err?.code === "ENOENT") throw new Error("tmux is not installed. Install it with: brew install tmux (macOS) or sudo apt-get install tmux (Linux)");
47174
- throw err;
47175
- }
47176
- if (useSupervisor) await waitForPtySupervisorSocket(tmuxSession);
47177
- if (behavior.usesCodexHome && codexFields?.codexHome) {
47178
- const codexHomeDir = codexFields.codexHome;
47179
- (async () => {
47180
- try {
47181
- const { waitForCodexRollout, extractThreadIdFromRollout, writeThreadId } = await import("./codex-B7DTpwEw.js");
47182
- const rollout = await waitForCodexRollout(codexHomeDir, 12e4);
47183
- if (rollout) {
47184
- const threadId = extractThreadIdFromRollout(rollout);
47185
- if (threadId) writeThreadId(tmuxSession, threadId);
47186
- }
47187
- } catch {}
47188
- })();
47189
- }
47190
- if (channelsBridgeMcpConfig) dismissDevChannelsDialog(tmuxSession).catch((err) => {
47191
- const msg = err instanceof Error ? err.message : String(err);
47192
- console.error(`[conversations] dismissDevChannelsDialog failed for ${tmuxSession}: ${msg}`);
47193
- });
47194
- await Effect.runPromise(setOption(tmuxSession, "destroy-unattached", "off"));
47195
- await Effect.runPromise(setOption(exactPaneTarget(tmuxSession), "remain-on-exit", "on"));
47196
- }
47197
- /**
47198
- * Resolve a conversation's cwd from a project identifier.
47199
- *
47200
- * The Command Deck identifies projects by display name, not yaml key
47201
- * (PAN-2590) — accept either, like GET /api/session-trees does.
47202
- */
47203
- function resolveProjectCwd(projectKey) {
47204
- const projectConfig = getProjectSync(projectKey) ?? listProjectsSync().find((p) => p.config.name === projectKey)?.config ?? null;
47205
- if (!projectConfig) return { error: `Unknown project: ${projectKey}` };
47206
- if (!projectConfig.path || !existsSync$1(projectConfig.path)) return { error: `Project path does not exist: ${projectConfig.path || "(unset)"} (project: ${projectKey})` };
47207
- return { cwd: projectConfig.path };
47208
- }
47209
- async function handleConversationCreate(body, deps) {
47210
- try {
47211
- const message = typeof body["message"] === "string" ? body["message"].trim() : "";
47212
- const model = typeof body["model"] === "string" ? body["model"].trim() : void 0;
47213
- const effort = typeof body["effort"] === "string" ? body["effort"].trim() : void 0;
47214
- const harness = await resolveAllowedHarness(body["harness"], model);
47215
- const issueId = typeof body["issueId"] === "string" ? body["issueId"] : void 0;
47216
- const projectKey = typeof body["projectKey"] === "string" ? body["projectKey"].trim() : void 0;
47217
- if (issueId && !SAFE_ISSUE_ID_PATTERN.test(issueId)) return jsonResponse({ error: "Invalid issueId" }, { status: 400 });
47218
- if (model && !SAFE_MODEL_PATTERN$1.test(model)) return jsonResponse({ error: "Invalid model" }, { status: 400 });
47219
- if (effort && !SAFE_EFFORT_PATTERN.test(effort)) return jsonResponse({ error: "Invalid effort" }, { status: 400 });
47220
- let cwd = getDefaultCwd();
47221
- if (projectKey) {
47222
- const resolved = resolveProjectCwd(projectKey);
47223
- if ("error" in resolved) return jsonResponse({ error: resolved.error }, { status: 400 });
47224
- cwd = resolved.cwd;
47225
- }
47226
- if (message && message.length > 5e4) return jsonResponse({ error: "message exceeds maximum length of 50000 characters" }, { status: 400 });
47227
- let name = generateConversationName();
47228
- for (let i = 0; i < 5 && getConversationByName(name); i++) name = generateConversationName();
47229
- const tmuxSession = `conv-${name}`;
47230
- const claudeSessionId = randomUUID$1();
47231
- console.log(`[conversations] Creating conversation "${name}" with model=${model ?? "default"} effort=${effort ?? "default"} cwd=${cwd}`);
47232
- const MAX_TITLE_LEN = 60;
47233
- const title = message ? message.slice(0, MAX_TITLE_LEN) + (message.length > MAX_TITLE_LEN ? "…" : "") : "New conversation";
47234
- const conv = createConversation({
47235
- name,
47236
- tmuxSession,
47237
- cwd,
47238
- issueId,
47239
- claudeSessionId,
47240
- title,
47241
- titleSource: message ? "auto" : "default",
47242
- titleSeed: title,
47243
- model,
47244
- effort,
47245
- harness
47246
- });
47247
- getEventStore().emitOnly({
47248
- type: "conversation.created",
47249
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
47250
- payload: { conversationName: name }
47251
- });
47252
- (async () => {
47253
- try {
47254
- await spawnConversationSession(tmuxSession, cwd, claudeSessionId, model, effort, issueId, false, harness);
47255
- console.log(`[conversations] tmux session ${tmuxSession} spawned, sessionId: ${claudeSessionId}`);
47256
- await waitForConversationRuntimeReady(tmuxSession, harness, "spawn");
47257
- if (message) await deliverAgentMessage(tmuxSession, message, "conversation-message", resolveConversationDeliveryMethod(conv));
47258
- } catch (spawnErr) {
47259
- const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
47260
- console.error(`[conversations] background spawn failed for ${tmuxSession}: ${msg}`);
47261
- updateSpawnError(name, msg);
47262
- getEventStore().emitOnly({
47263
- type: "conversation.created",
47264
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
47265
- payload: { conversationName: name }
47266
- });
47267
- }
47268
- })();
47269
- if (message) deps.generateAiTitle(name, message).catch((err) => {
47270
- const msg = err instanceof Error ? err.message : String(err);
47271
- console.error(`[TITLE-GEN-FAILED] AI title generation FAILED for "${name}" — NO RETRY, NO FALLBACK:`, msg);
47272
- });
47273
- return jsonResponse({
47274
- ...conv,
47275
- sessionAlive: false
47276
- }, { status: 201 });
47277
- } catch (error) {
47278
- const msg = error instanceof Error ? error.message : String(error);
47279
- console.error("[conversations] create conversation failed:", msg);
47280
- return jsonResponse({ error: msg || "Internal server error" }, { status: error instanceof UnknownModelError ? 400 : 500 });
47281
- }
47282
- }
47283
- async function handleConversationStop(name, deps) {
47284
- try {
47285
- const conv = getConversationByName(name);
47286
- if (!conv) return jsonResponse({ error: "Conversation not found" }, { status: 404 });
47287
- await stopConversationRuntime(conv, name);
47288
- markConversationEnded(name);
47289
- (async () => {
47290
- await new Promise((r) => setTimeout(r, 500));
47291
- await cleanupUnreferencedConversationAttachments({
47292
- name: conv.name,
47293
- sessionFile: deps.resolveSessionFileForCleanup?.(conv) ?? null
47294
- });
47295
- })();
47296
- return jsonResponse({ success: true });
47297
- } catch (error) {
47298
- const msg = error instanceof Error ? error.message : String(error);
47299
- console.error("[conversations] stop conversation failed:", msg);
47300
- return jsonResponse({ error: "Internal server error" }, { status: 500 });
47301
- }
47302
- }
47303
- async function handleConversationResume(name, body, deps) {
47304
- try {
47305
- const conv = getConversationByName(name);
47306
- if (!conv) return jsonResponse({ error: "Conversation not found" }, { status: 404 });
47307
- const model = typeof body["model"] === "string" && body["model"].trim() ? body["model"].trim() : conv.model ?? void 0;
47308
- const effort = typeof body["effort"] === "string" && body["effort"].trim() ? body["effort"].trim() : conv.effort ?? void 0;
47309
- if (await isHarnessProcessAlive(conv.tmuxSession)) {
47310
- updateLastAttached(name);
47311
- markConversationActive(name);
47312
- return jsonResponse({
47313
- ...conv,
47314
- status: "active",
47315
- reattached: true
47316
- });
47317
- }
47318
- const oldSessionId = conv.claudeSessionId;
47319
- const harness = conv.harness ?? "claude-code";
47320
- const modelChanged = !!model && model !== conv.model;
47321
- if (!await validateCwdContainment$1(conv.cwd)) return jsonResponse({ error: "Invalid cwd" }, { status: 400 });
47322
- if (model && modelChanged && !SAFE_MODEL_PATTERN$1.test(model)) return jsonResponse({ error: "Invalid model" }, { status: 400 });
47323
- if (model && modelChanged) setConversationModel(name, model);
47324
- let canResume = !!oldSessionId;
47325
- if (oldSessionId) {
47326
- const resumeFile = await deps.resolveSessionFile(conv);
47327
- if (!resumeFile || !existsSync$1(resumeFile)) {
47328
- canResume = false;
47329
- console.error(`[conversations] SESSION-LOST ${name} harness=${harness} claudeSessionId=${oldSessionId} resolved=${resumeFile ?? "null"} — resuming with a fresh session`);
47330
- }
47331
- }
47332
- const respawn = markRespawnPending(conv.tmuxSession);
47333
- try {
47334
- await spawnConversationSession(conv.tmuxSession, conv.cwd, oldSessionId ?? randomUUID$1(), model, effort, conv.issueId ?? void 0, canResume, harness);
47335
- await waitForTmuxSession(conv.tmuxSession);
47336
- await waitForConversationRuntimeReady(conv.tmuxSession, harness, "respawn");
47337
- markConversationActive(name);
47338
- return jsonResponse({
47339
- ...conv,
47340
- status: "active",
47341
- model: model ?? conv.model,
47342
- harness,
47343
- reattached: false,
47344
- sessionAlive: true
47345
- });
47346
- } finally {
47347
- respawn.done();
47348
- }
47349
- } catch (error) {
47350
- const msg = error instanceof Error ? error.message : String(error);
47351
- console.error("[conversations] resume conversation failed:", msg);
47352
- return jsonResponse({ error: msg || "Internal server error" }, { status: 500 });
47353
- }
47354
- }
47355
- async function handleConversationDelete(name, deps) {
47356
- try {
47357
- const conv = getConversationByName(name);
47358
- if (!conv) return jsonResponse({ error: "Conversation not found" }, { status: 404 });
47359
- await stopConversationRuntime(conv, name);
47360
- markConversationEnded(name);
47361
- archiveConversation(name);
47362
- removeFavorite("conversation", name);
47363
- deps.invalidateFavoritesCache();
47364
- await cleanupConversationAttachments(name);
47365
- return jsonResponse({ success: true });
47366
- } catch (error) {
47367
- const msg = error instanceof Error ? error.message : String(error);
47368
- console.error("[conversations] delete conversation failed:", msg);
47369
- return jsonResponse({ error: "Internal server error" }, { status: 500 });
47370
- }
47371
- }
47372
- async function handleConversationRestartAll(deps) {
47373
- try {
47374
- const allConvs = listConversations();
47375
- const liveSessionNames = new Set(await Effect.runPromise(listSessionNames()));
47376
- const convs = allConvs.filter((c) => liveSessionNames.has(c.tmuxSession));
47377
- const results = [];
47378
- for (const conv of convs) {
47379
- const respawn = markRespawnPending(conv.tmuxSession);
47380
- try {
47381
- await Effect.runPromise(killSession(conv.tmuxSession).pipe(Effect.catch(() => Effect.succeed(void 0))));
47382
- const oldSessionId = conv.claudeSessionId;
47383
- const sessionFileForResume = await deps.resolveSessionFile(conv);
47384
- const canResume = !!oldSessionId && !!sessionFileForResume && existsSync$1(sessionFileForResume);
47385
- const harness = await resolveAllowedHarness(conv.harness, conv.model);
47386
- await spawnConversationSession(conv.tmuxSession, conv.cwd, oldSessionId ?? randomUUID$1(), conv.model ?? void 0, conv.effort ?? void 0, conv.issueId ?? void 0, canResume, harness);
47387
- setConversationHarness(conv.name, harness);
47388
- markConversationActive(conv.name);
47389
- results.push({
47390
- name: conv.name,
47391
- model: conv.model,
47392
- status: "restarted"
47393
- });
47394
- } catch (err) {
47395
- const msg = err instanceof Error ? err.message : String(err);
47396
- console.error(`[conversations] Failed to restart ${conv.name}:`, msg);
47397
- results.push({
47398
- name: conv.name,
47399
- model: conv.model,
47400
- status: "failed"
47401
- });
47402
- } finally {
47403
- respawn.done();
47404
- }
47405
- }
47406
- console.log(`[conversations] Restarted ${results.filter((r) => r.status === "restarted").length}/${convs.length} conversations`);
47407
- return jsonResponse({
47408
- restarted: results.length,
47409
- results
47410
- });
47411
- } catch (error) {
47412
- const msg = error instanceof Error ? error.message : String(error);
47413
- console.error("[conversations] restart conversations failed:", msg);
47414
- return jsonResponse({ error: "Internal server error" }, { status: 500 });
47415
- }
47416
- }
47417
- //#endregion
47418
46065
  //#region ../../lib/overdeck/conversation-archive.ts
47419
46066
  init_paths();
47420
46067
  init_conversations();
@@ -48237,25 +46884,29 @@ async function getConversationsPendingInputFeed(deps) {
48237
46884
  return result((await Effect.runPromise(withConcurrencyLimit(alive.map((conv) => Effect.promise(async () => {
48238
46885
  const convSf = await deps.resolveSessionFile(conv);
48239
46886
  let pending;
46887
+ let pendingPlan;
48240
46888
  let lastActivityAt = null;
48241
46889
  if (convSf && existsSync$1(convSf)) {
48242
46890
  try {
48243
46891
  lastActivityAt = new Date((await stat$1(convSf)).mtimeMs).toISOString();
48244
46892
  } catch {}
48245
46893
  try {
48246
- pending = askUserQuestionSnapshotFromScan(await scanPendingInputsPromise(convSf));
46894
+ const scan = await scanPendingInputsPromise(convSf);
46895
+ pending = askUserQuestionSnapshotFromScan(scan);
46896
+ pendingPlan = scan.pendingProposedPlan;
48247
46897
  } catch {}
48248
46898
  }
48249
46899
  if (!pending) {
48250
46900
  const codex = await codexConversationPendingInput(conv, true, lastActivityAt ?? (/* @__PURE__ */ new Date()).toISOString());
48251
46901
  if (codex.approval) pending = codex.approval;
48252
46902
  }
48253
- if (!pending) return null;
46903
+ if (!pending && !pendingPlan) return null;
48254
46904
  return {
48255
46905
  name: conv.name,
48256
46906
  title: conv.title ?? null,
48257
46907
  issueId: conv.issueId ?? null,
48258
- pendingAskUserQuestion: pending
46908
+ ...pending ? { pendingAskUserQuestion: pending } : {},
46909
+ ...pendingPlan ? { pendingProposedPlan: pendingPlan } : {}
48259
46910
  };
48260
46911
  })), 8))).filter((row) => row !== null));
48261
46912
  } catch (error) {
@@ -49174,7 +47825,7 @@ async function forkSpawnConversationSession(...args) {
49174
47825
  return (forkPipelineRuntimeOverrides.spawnConversationSession ?? spawnConversationSession)(...args);
49175
47826
  }
49176
47827
  async function forkWaitForTmuxSession(...args) {
49177
- return (forkPipelineRuntimeOverrides.waitForTmuxSession ?? waitForTmuxSession)(...args);
47828
+ return (forkPipelineRuntimeOverrides.waitForTmuxSession ?? waitForTmuxSession$1)(...args);
49178
47829
  }
49179
47830
  async function confirmForkPromptAccepted(tmuxSession, timeoutMs) {
49180
47831
  const deadline = Date.now() + timeoutMs;
@@ -50209,7 +48860,7 @@ async function registerProjectFromPath(opts) {
50209
48860
  registerProjectSync(key, projectConfig);
50210
48861
  const seededContextLayer = ensureProjectLayer(fullPath);
50211
48862
  try {
50212
- const { preTrustDirectorySync } = await import("./workspace-manager-DjUAJCSs.js");
48863
+ const { preTrustDirectorySync } = await import("./workspace-manager-BO-6k3sP.js");
50213
48864
  preTrustDirectorySync(fullPath);
50214
48865
  } catch {}
50215
48866
  let hooksInstalled = 0;
@@ -50245,7 +48896,7 @@ init_pan_dir();
50245
48896
  init_paths();
50246
48897
  const execAsync$2 = promisify(exec);
50247
48898
  async function getIssueDataService() {
50248
- const { getSharedIssueService } = await import("./issue-service-singleton-bG1WdSdQ.js");
48899
+ const { getSharedIssueService } = await import("./issue-service-singleton-MZsDhAob.js");
50249
48900
  return getSharedIssueService();
50250
48901
  }
50251
48902
  /** Returns true if the path exists (any type). */
@@ -50641,7 +49292,7 @@ const getProjectReleaseStatusRoute = HttpRouter.add("GET", "/api/projects/:proje
50641
49292
  const projectKey = (yield* HttpRouter.params)["projectKey"] ?? "";
50642
49293
  return jsonResponse(yield* Effect.tryPromise({
50643
49294
  try: async () => {
50644
- const { fetchProjectReleaseStatus } = await import("./project-pipelines-BRWaGmI4.js");
49295
+ const { fetchProjectReleaseStatus } = await import("./project-pipelines-jMTitpeO.js");
50645
49296
  return fetchProjectReleaseStatus(projectKey);
50646
49297
  },
50647
49298
  catch: (err) => new Error(err instanceof Error ? err.message : String(err))
@@ -50793,7 +49444,7 @@ const PREVIEW_HARNESSES = [
50793
49444
  "codex"
50794
49445
  ];
50795
49446
  const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
50796
- const execFileAsync$2 = promisify(execFile);
49447
+ const execFileAsync$3 = promisify(execFile);
50797
49448
  const decodePreviewRequest = Schema.decodeUnknownSync(ContextPreviewRequest);
50798
49449
  const decodeSaveRequest = Schema.decodeUnknownSync(ContextLayerSaveRequest);
50799
49450
  function globalContextFile(overdeckHome = getOverdeckHome()) {
@@ -51123,7 +49774,7 @@ async function saveContextLayer(projects, requestOrTarget, maybeContentOrOverdec
51123
49774
  };
51124
49775
  }
51125
49776
  async function runPanContextSync() {
51126
- const { stdout, stderr } = await execFileAsync$2("pan", ["context", "sync"], { encoding: "utf-8" });
49777
+ const { stdout, stderr } = await execFileAsync$3("pan", ["context", "sync"], { encoding: "utf-8" });
51127
49778
  return {
51128
49779
  stdout,
51129
49780
  stderr
@@ -51327,6 +49978,7 @@ const adminRouteLayer = Layer.mergeAll(getAdminTldrRoute, postAdminBackfillTitle
51327
49978
  */
51328
49979
  init_platform();
51329
49980
  const execAsync$1 = promisify(exec);
49981
+ const execFileAsync$2 = promisify(execFile);
51330
49982
  const PREREQ_REGISTRY = {
51331
49983
  addGitHubProject: ["gh"],
51332
49984
  addGitLabProject: ["glab"],
@@ -51338,6 +49990,7 @@ const PREREQ_REGISTRY = {
51338
49990
  "traefik"
51339
49991
  ],
51340
49992
  enableBeads: ["bd"],
49993
+ runClaudeCodeHooks: ["jq"],
51341
49994
  useClaudeCodeRoutedAgents: [],
51342
49995
  useOxAgents: ["ox"]
51343
49996
  };
@@ -51347,19 +50000,31 @@ const INSTALLABLE_TOOLS = [
51347
50000
  "ttyd",
51348
50001
  "mkcert",
51349
50002
  "bd",
50003
+ "jq",
51350
50004
  "ox"
51351
50005
  ];
51352
- function checkCommand(cmd) {
50006
+ async function checkCommand(cmd, args = ["--version"]) {
51353
50007
  try {
51354
- execSync(`which ${cmd}`, { stdio: "pipe" });
50008
+ await execFileAsync$2(cmd, args, { timeout: 1e4 });
51355
50009
  return true;
51356
50010
  } catch {
51357
50011
  return false;
51358
50012
  }
51359
50013
  }
51360
50014
  async function isToolInstalled(tool) {
51361
- if (tool === "traefik") return checkCommand("docker");
51362
- if (tool === "ttyd") return checkCommand("ttyd") || existsSync$1(join(homedir$1(), "bin", "ttyd"));
50015
+ if (tool === "docker") return checkCommand("docker", ["info"]);
50016
+ if (tool === "traefik") try {
50017
+ const { stdout } = await execFileAsync$2("docker", [
50018
+ "inspect",
50019
+ "--format",
50020
+ "{{.State.Running}}",
50021
+ "overdeck-traefik"
50022
+ ], { timeout: 1e4 });
50023
+ return stdout.trim() === "true";
50024
+ } catch {
50025
+ return false;
50026
+ }
50027
+ if (tool === "ttyd") return await checkCommand("ttyd", ["--version"]) || existsSync$1(join(homedir$1(), "bin", "ttyd"));
51363
50028
  return checkCommand(tool);
51364
50029
  }
51365
50030
  /** Install a single tool. Returns a result object (never throws). */
@@ -51370,6 +50035,7 @@ async function installTool(tool) {
51370
50035
  case "ttyd": return await installTtyd();
51371
50036
  case "mkcert": return await installMkcert();
51372
50037
  case "bd": return await installBeads();
50038
+ case "jq": return await installJq();
51373
50039
  case "ox": return await installOx();
51374
50040
  default: return {
51375
50041
  tool,
@@ -51451,6 +50117,15 @@ async function installBeads() {
51451
50117
  message: "beads installed via install script"
51452
50118
  };
51453
50119
  }
50120
+ async function installJq() {
50121
+ if (await Effect.runPromise(detectPlatform()) === "darwin") await execAsync$1("brew install jq", { timeout: 12e4 });
50122
+ else await execAsync$1("sudo apt-get update && sudo apt-get install -y jq", { timeout: 12e4 });
50123
+ return {
50124
+ tool: "jq",
50125
+ success: true,
50126
+ message: "jq installed"
50127
+ };
50128
+ }
51454
50129
  async function installOx() {
51455
50130
  const plat = await Effect.runPromise(detectPlatform());
51456
50131
  const arch = process.arch === "x64" ? "amd64" : process.arch;
@@ -52255,7 +50930,7 @@ async function refreshMergeStateFromGitHub(issueId, repo, prNumber) {
52255
50930
  let mergeState;
52256
50931
  let isDraft;
52257
50932
  let checksFailed;
52258
- const { isGitHubAppConfigured, getPullRequestState } = await import("./github-app-DRD2woO0.js");
50933
+ const { isGitHubAppConfigured, getPullRequestState } = await import("./github-app-Bwt9lK4A.js");
52259
50934
  if (isGitHubAppConfigured()) {
52260
50935
  const prState = await Effect.runPromise(getPullRequestState(owner, repoName, prNumber));
52261
50936
  mergeable = prState.mergeable === null ? "UNKNOWN" : prState.mergeable ? "MERGEABLE" : "CONFLICTING";
@@ -52404,8 +51079,8 @@ async function handlePullRequestPromise(payload) {
52404
51079
  bumpIssuePrTabCacheGeneration(issueId);
52405
51080
  const repo = payload.repository.full_name;
52406
51081
  if (payload.action === "closed" && pr.merged === true) try {
52407
- const { postMergeLifecycle } = await import("./merge-agent-36wfYm2u.js");
52408
- const { resolveProjectFromIssueSync } = await import("./projects-KJ94e50I.js");
51082
+ const { postMergeLifecycle } = await import("./merge-agent-ejC7Wos8.js");
51083
+ const { resolveProjectFromIssueSync } = await import("./projects-CrBE6IhN.js");
52409
51084
  const project = resolveProjectFromIssueSync(issueId);
52410
51085
  if (project) {
52411
51086
  const branchName = pr.head.ref;
@@ -52970,7 +51645,7 @@ function getCheckpointWorker() {
52970
51645
  return worker;
52971
51646
  }
52972
51647
  async function runInline(operation, payload) {
52973
- const { claimTranscriptRange, commitTranscriptRange, releaseTranscriptRange, getTranscriptCheckpoint, listTranscriptCheckpoints } = await import("./checkpoints-DvhGi8P_.js");
51648
+ const { claimTranscriptRange, commitTranscriptRange, releaseTranscriptRange, getTranscriptCheckpoint, listTranscriptCheckpoints } = await import("./checkpoints-fjadfOKF.js");
52974
51649
  switch (operation) {
52975
51650
  case "claimTranscriptRange": return claimTranscriptRange(payload);
52976
51651
  case "commitTranscriptRange": return commitTranscriptRange(payload);
@@ -54124,7 +52799,7 @@ function buildPendingTurn(input, fromOffset, toOffset, compressed) {
54124
52799
  };
54125
52800
  }
54126
52801
  async function emitMemoryObservationCreated(observation, timestamp) {
54127
- const { initEventStore } = await import("./event-store-CcJAhKCl.js");
52802
+ const { initEventStore } = await import("./event-store-CqDgfbAs.js");
54128
52803
  await (await initEventStore()).appendAsync({
54129
52804
  type: "memory.observation_created",
54130
52805
  timestamp,
@@ -57778,7 +56453,7 @@ async function getFlywheelConversationPayload() {
57778
56453
  };
57779
56454
  }
57780
56455
  async function postFlywheelReportPayload() {
57781
- const { flywheelReportCommand } = await import("./flywheel-CUErLAyN.js");
56456
+ const { flywheelReportCommand } = await import("./flywheel-9Y1X7IM-.js");
57782
56457
  await flywheelReportCommand({ cwd: process.cwd() });
57783
56458
  return {
57784
56459
  status: 200,
@@ -57936,11 +56611,11 @@ const getMergeBlockersRoute = HttpRouter.add("GET", "/api/flywheel/merge-blocker
57936
56611
  async function defaultGetOrderedIssueIds() {
57937
56612
  const status = await readCurrentFlywheelStatusForDashboard();
57938
56613
  if (!status) return [];
57939
- const { computeMergeQueue } = await import("./flywheel-merge-order-DXjeBnJ1.js");
56614
+ const { computeMergeQueue } = await import("./flywheel-merge-order-DEtEd3aK.js");
57940
56615
  return (await Effect.runPromise(computeMergeQueue(status.activePipeline, process.cwd()).pipe(Effect.provide(layer)))).map((i) => i.issueId);
57941
56616
  }
57942
56617
  async function defaultMergeOne(issueId) {
57943
- const { triggerMerge } = await import("./merge-ops-PzqsW69V.js");
56618
+ const { triggerMerge } = await import("./merge-ops-CFkQtXEj.js");
57944
56619
  const r = await triggerMerge(issueId);
57945
56620
  return r.success ? { ok: true } : {
57946
56621
  ok: false,
@@ -57960,7 +56635,7 @@ async function postFlywheelMergeNextPayload(payload, deps = {}) {
57960
56635
  body: { error: "n must be a positive integer" }
57961
56636
  };
57962
56637
  const issueIds = (await (deps.getOrderedIssueIds ?? defaultGetOrderedIssueIds)()).slice(0, n);
57963
- const { shipMergeBatch } = await import("./merge-batch-itfnwdsT.js");
56638
+ const { shipMergeBatch } = await import("./merge-batch-DyqlgYGp.js");
57964
56639
  return {
57965
56640
  status: 200,
57966
56641
  body: { outcomes: await shipMergeBatch(issueIds, { merge: deps.merge ?? defaultMergeOne }) }
@@ -58117,7 +56792,7 @@ const getFlywheelMergeQueueRoute = HttpRouter.add("GET", "/api/flywheel/merge-qu
58117
56792
  return yield* Effect.promise(async () => {
58118
56793
  const status = await readCurrentFlywheelStatusForDashboard();
58119
56794
  if (!status) return jsonResponse([]);
58120
- const { computeMergeQueue, resolveMergeQueuePrUrl } = await import("./flywheel-merge-order-DXjeBnJ1.js");
56795
+ const { computeMergeQueue, resolveMergeQueuePrUrl } = await import("./flywheel-merge-order-DEtEd3aK.js");
58121
56796
  return jsonResponse(await Effect.runPromise(computeMergeQueue(status.activePipeline, process.cwd(), { getPrUrl: resolveMergeQueuePrUrl }).pipe(Effect.provide(layer))));
58122
56797
  });
58123
56798
  })));
@@ -58131,18 +56806,18 @@ function uatGenerationNameFromParam(param) {
58131
56806
  return decoded.startsWith("uat/") ? decoded : `uat/${decoded}`;
58132
56807
  }
58133
56808
  const getUatGenerationsRoute = HttpRouter.add("GET", "/api/flywheel/uat-generations", httpHandler(Effect.gen(function* () {
58134
- const { getUatGenerationsPayload } = yield* Effect.promise(() => import("./uat-train-DDI00aqD.js"));
56809
+ const { getUatGenerationsPayload } = yield* Effect.promise(() => import("./uat-train-utGVmqdm.js"));
58135
56810
  return jsonResponse(yield* Effect.promise(() => getUatGenerationsPayload()));
58136
56811
  })));
58137
56812
  const getUatCandidateRoute = HttpRouter.add("GET", "/api/flywheel/uat-candidate", httpHandler(Effect.gen(function* () {
58138
- const { getUatCandidatePayload } = yield* Effect.promise(() => import("./uat-train-DDI00aqD.js"));
56813
+ const { getUatCandidatePayload } = yield* Effect.promise(() => import("./uat-train-utGVmqdm.js"));
58139
56814
  return jsonResponse(yield* Effect.promise(() => getUatCandidatePayload()));
58140
56815
  })));
58141
56816
  const postUatGenerationStackRoute = HttpRouter.add("POST", "/api/flywheel/uat-generations/:name/stack", httpHandler(Effect.gen(function* () {
58142
56817
  const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
58143
56818
  if (authError) return authError;
58144
56819
  const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
58145
- const { postUatGenerationStackPayload } = yield* Effect.promise(() => import("./uat-train-DDI00aqD.js"));
56820
+ const { postUatGenerationStackPayload } = yield* Effect.promise(() => import("./uat-train-utGVmqdm.js"));
58146
56821
  const result = yield* Effect.promise(() => postUatGenerationStackPayload(name));
58147
56822
  if (!result.ok) return jsonResponse({ error: result.error }, { status: result.status });
58148
56823
  return jsonResponse({
@@ -58154,8 +56829,8 @@ const postUatGenerationPromoteRoute = HttpRouter.add("POST", "/api/flywheel/uat-
58154
56829
  const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
58155
56830
  if (authError) return authError;
58156
56831
  const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
58157
- const { postUatGenerationPromotePayload } = yield* Effect.promise(() => import("./uat-train-DDI00aqD.js"));
58158
- const { firePostMergeLifecycle } = yield* Effect.promise(() => import("./specialists-ZkW4Mb7U.js"));
56832
+ const { postUatGenerationPromotePayload } = yield* Effect.promise(() => import("./uat-train-utGVmqdm.js"));
56833
+ const { firePostMergeLifecycle } = yield* Effect.promise(() => import("./specialists-D7AcFi1u.js"));
58159
56834
  const result = yield* Effect.promise(() => postUatGenerationPromotePayload(name, firePostMergeLifecycle));
58160
56835
  if (!result.success) return jsonResponse(result, { status: result.reason === "not-found" ? 404 : result.reason === "merge-failed" ? 500 : 409 });
58161
56836
  return jsonResponse(result);
@@ -58168,7 +56843,7 @@ const postUatGenerationPromoteRoute = HttpRouter.add("POST", "/api/flywheel/uat-
58168
56843
  const postFlywheelAssembleUatRoute = HttpRouter.add("POST", "/api/flywheel/assemble-uat", httpHandler(Effect.gen(function* () {
58169
56844
  const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
58170
56845
  if (authError) return authError;
58171
- const { runUatTrainReconcile } = yield* Effect.promise(() => import("./uat-train-DDI00aqD.js"));
56846
+ const { runUatTrainReconcile } = yield* Effect.promise(() => import("./uat-train-utGVmqdm.js"));
58172
56847
  return jsonResponse(yield* Effect.promise(() => runUatTrainReconcile({ force: true })));
58173
56848
  })));
58174
56849
  const getFlywheelStateRoute = HttpRouter.add("GET", "/api/flywheel/state", httpHandler(Effect.gen(function* () {
@@ -61463,7 +60138,7 @@ init_activity_logger();
61463
60138
  init_read_model();
61464
60139
  function enrichmentChanged(prev, next) {
61465
60140
  if (!prev) return true;
61466
- return prev.role !== next.role || prev.hasPendingQuestion !== next.hasPendingQuestion || prev.pendingQuestionCount !== next.pendingQuestionCount || prev.pendingQuestionPrompt !== next.pendingQuestionPrompt || prev.pendingQuestionReason !== next.pendingQuestionReason || prev.pendingInputCount !== next.pendingInputCount || prev.pendingInputKinds.join(",") !== next.pendingInputKinds.join(",") || prev.pendingAskUserQuestion?.toolUseId !== next.pendingAskUserQuestion?.toolUseId || prev.resolution !== next.resolution || prev.resolutionCount !== next.resolutionCount;
60141
+ return prev.role !== next.role || prev.hasPendingQuestion !== next.hasPendingQuestion || prev.pendingQuestionCount !== next.pendingQuestionCount || prev.pendingQuestionPrompt !== next.pendingQuestionPrompt || prev.pendingQuestionReason !== next.pendingQuestionReason || prev.pendingInputCount !== next.pendingInputCount || prev.pendingInputKinds.join(",") !== next.pendingInputKinds.join(",") || prev.pendingAskUserQuestion?.toolUseId !== next.pendingAskUserQuestion?.toolUseId || prev.pendingProposedPlan?.toolUseId !== next.pendingProposedPlan?.toolUseId || prev.resolution !== next.resolution || prev.resolutionCount !== next.resolutionCount;
61467
60142
  }
61468
60143
  function isAwaitingInputRisingEdge(previous, current) {
61469
60144
  return (previous?.pendingInputCount ?? 0) === 0 && current.pendingInputCount > 0;
@@ -61580,6 +60255,7 @@ async function pollOnce$1(state) {
61580
60255
  pendingInputCount: enrichment.pendingInputCount,
61581
60256
  pendingInputKinds: enrichment.pendingInputKinds,
61582
60257
  pendingAskUserQuestion: enrichment.pendingAskUserQuestion,
60258
+ pendingProposedPlan: enrichment.pendingProposedPlan,
61583
60259
  resolution: enrichment.resolution,
61584
60260
  resolutionCount: enrichment.resolutionCount
61585
60261
  }
@@ -61777,7 +60453,7 @@ async function pollOnce(state) {
61777
60453
  try {
61778
60454
  const remoteState = await readFile(join(homedir$1(), ".overdeck", "agents", agentId, "remote-state.json"), "utf-8").then((text) => JSON.parse(text)).catch(() => null);
61779
60455
  if (remoteState?.location === "remote" && remoteState?.vmName) {
61780
- const { getRemoteAgentOutput } = await import("./remote-agents-DlvbzO7m.js");
60456
+ const { getRemoteAgentOutput } = await import("./remote-agents-Cv-U-_V8.js");
61781
60457
  stdout = await getRemoteAgentOutput(agentId, remoteState.vmName, 50);
61782
60458
  } else stdout = await Effect.runPromise(capturePane(agentId, 50));
61783
60459
  } catch {
@@ -63084,7 +61760,7 @@ const RESTART_MARKER = join$1(homedir(), ".overdeck", "dashboard-restarting.json
63084
61760
  * loads new content-hashed chunk filenames (no ERR_MODULE_NOT_FOUND after rebuild).
63085
61761
  */
63086
61762
  async function defaultLifecycleRunner(pending) {
63087
- const { postMergeLifecycle, notifyTldrDaemon } = await import("./merge-agent-36wfYm2u.js");
61763
+ const { postMergeLifecycle, notifyTldrDaemon } = await import("./merge-agent-ejC7Wos8.js");
63088
61764
  await postMergeLifecycle(pending.issueId, pending.projectPath, pending.sourceBranch, { skipDeploy: true });
63089
61765
  if (pending.sourceBranch) await notifyTldrDaemon(pending.projectPath, pending.sourceBranch);
63090
61766
  }
@@ -63405,7 +62081,7 @@ function failureReason(result) {
63405
62081
  return result.error ?? result.message ?? `merge returned status ${result.statusCode ?? "unknown"}`;
63406
62082
  }
63407
62083
  async function defaultMergeIssue(issueId) {
63408
- const { triggerMerge } = await import("./merge-ops-PzqsW69V.js");
62084
+ const { triggerMerge } = await import("./merge-ops-CFkQtXEj.js");
63409
62085
  return triggerMerge(issueId);
63410
62086
  }
63411
62087
  function defaultAnnounceFailure(issueId, reason) {
@@ -63688,7 +62364,7 @@ startMergeBlockerReconcileService();
63688
62364
  console.log("[overdeck] MergeBlockerReconcileService started");
63689
62365
  if (process.env.OVERDECK_MODE === "desktop") (async () => {
63690
62366
  try {
63691
- const { provisionClaudeHooks } = await import("./claude-hooks-provision-s_wdpeVj.js");
62367
+ const { provisionClaudeHooks } = await import("./claude-hooks-provision-DiK62u0k.js");
63692
62368
  const result = await provisionClaudeHooks();
63693
62369
  if (!result.ok) console.warn(`[overdeck] Claude hook provisioning skipped: ${result.reason}`);
63694
62370
  else if (result.changed) console.log(`[overdeck] Claude hooks provisioned: ${result.binariesSynced} scripts, registered ${result.registered.length} hook(s)${result.pruned.length ? `, pruned ${result.pruned.length} stale` : ""}`);
@@ -64052,7 +62728,7 @@ reconcileStaleGitHubBlockers().then((n) => {
64052
62728
  }
64053
62729
  }).catch((err) => console.warn(`[overdeck] Startup blocker reconciliation failed: ${err.message}`));
64054
62730
  try {
64055
- const { resetProcessingToQueued } = await import("./merge-sync-DIrmlZUr.js");
62731
+ const { resetProcessingToQueued } = await import("./merge-sync-CG9kDCdT.js");
64056
62732
  const resetCount = resetProcessingToQueued();
64057
62733
  if (resetCount > 0) {
64058
62734
  console.log(`[overdeck] Reset ${resetCount} stuck merge queue entries to queued`);