@overdeck/desktop 0.45.23 → 0.45.24

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 (388) hide show
  1. package/drizzle/overdeck/0000_overdeck_init.sql +2 -0
  2. package/package.json +1 -1
  3. package/server/{acceptance-criteria-DOA0KgXx.js → acceptance-criteria-DDCnXF58.js} +2 -2
  4. package/server/{advancing-selfheal-BBu6DSNm.js → advancing-selfheal-BVwW4qRn.js} +6 -6
  5. package/server/{agent-gc-BV1q_2EV.js → agent-gc-CHcnvonI.js} +4 -4
  6. package/server/agent-state-Bc3tzUC8.js +3 -0
  7. package/server/{agent-state-service-HoK8U4jW.js → agent-state-service-BsgWxZuB.js} +5 -5
  8. package/server/{agent-state-service-CnzFKSAQ.js → agent-state-service-D5UGKIJL.js} +1 -1
  9. package/server/{agents-B4Bjbkfv.js → agents-EbI0zCJl.js} +4 -4
  10. package/server/agents-wi9NWzs2.js +3 -0
  11. package/server/{archive-planning-zkJb3BeM.js → archive-planning-BZDgzoEj.js} +1 -1
  12. package/server/{archive-planning-DYrYojxl.js → archive-planning-Du25Jtst.js} +4 -4
  13. package/server/{artifact-index-jobs-C-xy7Z5v.js → artifact-index-jobs-CbEDfCDu.js} +2 -2
  14. package/server/assemble-J2ZZ2C15.js +339 -0
  15. package/server/{backlog-auto-trigger-GtG71X8H.js → backlog-auto-trigger-2R2jog7n.js} +3 -3
  16. package/server/{behavior-B_-4EKF3.js → behavior-B3exJ42O.js} +2 -2
  17. package/server/{briefing-freshness-DWdW7vUm.js → briefing-freshness-D1wzUIWv.js} +2 -2
  18. package/server/{build-info-DgTqZkL5.js → build-info-CZk_TITh.js} +1 -1
  19. package/server/{build-info-BT096lEl.js → build-info-Ie_D0_BT.js} +3 -3
  20. package/server/{checkpoint-manager-DDqcGyu8.js → checkpoint-manager-BI1Wxoku.js} +2 -2
  21. package/server/{checkpoint-manager-B7Bt29J0.js → checkpoint-manager-DwbQoqrC.js} +1 -1
  22. package/server/checkpoint-worker.js +1 -1
  23. package/server/{checkpoints-CpgCjAlN.js → checkpoints-BJIs5QIA.js} +1 -1
  24. package/server/{checkpoints-C-AXLfYT.js → checkpoints-CQB1h765.js} +2 -2
  25. package/server/{claude-hooks-provision-C8wdRnN1.js → claude-hooks-provision-8Ngo8TpT.js} +1 -1
  26. package/server/{claude-hooks-provision-but-_qGY.js → claude-hooks-provision-D8GXF3_s.js} +2 -2
  27. package/server/{claude-permissions-H_5wHQZQ.js → claude-permissions-DNWEVV6z.js} +2 -2
  28. package/server/{claude-settings-overlay-CbSz0Dvb.js → claude-settings-overlay-CEdaqpWI.js} +2 -2
  29. package/server/{claude-settings-overlay-BTENVmYf.js → claude-settings-overlay-DWy-Bb4Y.js} +1 -1
  30. package/server/cli-B86rejVV.js +3 -0
  31. package/server/{cli-vBeXbPrq.js → cli-RoOx5DUf.js} +9 -9
  32. package/server/{cliproxy-Bgb2XCqi.js → cliproxy-C8a1vtTU.js} +2 -2
  33. package/server/{cliproxy-DW0V86F8.js → cliproxy-fHfIeiGd.js} +1 -1
  34. package/server/{close-issue-Dn_4c4G8.js → close-issue-DoOifFIK.js} +5 -5
  35. package/server/{closed-issue-reaper-hANY_ehE.js → closed-issue-reaper-Bk3SU4RC.js} +9 -9
  36. package/server/{closed-issue-reaper-CWpY2uBw.js → closed-issue-reaper-CktPXo8m.js} +1 -1
  37. package/server/{codex-TmSi-yTv.js → codex-BZXGhUVB.js} +7 -7
  38. package/server/{codex-Dg7Is5yb.js → codex-GcHuUF-k.js} +1 -1
  39. package/server/{codex-parser-C4gSH-IR.js → codex-parser-CFZ1_1Jl.js} +2 -2
  40. package/server/{config-CCvjQf27.js → config-BZ0sHTju.js} +2 -2
  41. package/server/{config-DjLOdbgT.js → config-CKxYiCmX.js} +2 -2
  42. package/server/{config-DUIhMN_T.js → config-DzV30TOm.js} +1 -1
  43. package/server/{config-yaml-DvyMuOle.js → config-yaml-DySPNmKN.js} +23 -9
  44. package/server/{conflict-gate-CmrYpa47.js → conflict-gate-BaCVrH-N.js} +3 -3
  45. package/server/{conflict-gate-BSJkNTdp.js → conflict-gate-BhAY7TUd.js} +1 -1
  46. package/server/context-layers-BrPmE__h.js +4 -0
  47. package/server/context-layers-igZ4FI4_.js +37 -0
  48. package/server/{control-settings-aP1ANIlI.js → control-settings-BQp7_4uD.js} +4 -4
  49. package/server/{conversation-compaction-CNbTLB86.js → conversation-compaction-CgrR8YYp.js} +8 -8
  50. package/server/{conversation-compaction-DiG5zWQq.js → conversation-compaction-eQB5CkOe.js} +1 -1
  51. package/server/{conversation-service-Up7FEzIC.js → conversation-service-BLd3MYsG.js} +1 -1
  52. package/server/{conversation-service-Du-MTNpJ.js → conversation-service-DPJ71F33.js} +329 -19
  53. package/server/{conversations-DbOs1e9Q.js → conversations-6AfUfbwc.js} +5 -5
  54. package/server/{conversations-6mPANqvL.js → conversations-CAsJF9kh.js} +1 -1
  55. package/server/{cost-Ca0YTWDw.js → cost-B2ddP6wq.js} +2 -2
  56. package/server/{cost-CW4WSe72.js → cost-R-m6Yi-W.js} +3 -3
  57. package/server/{cost-sync-C0VdGme1.js → cost-sync-BsN6ER0n.js} +3 -3
  58. package/server/{dag-CdOjJVDT.js → dag-B1ucnjDU.js} +2 -2
  59. package/server/{dangerous-git-ops-CT-IypG3.js → dangerous-git-ops-BXqeWVSf.js} +1 -1
  60. package/server/dashboard-db-worker.js +7 -7
  61. package/server/{deacon-pRnyD5w9.js → deacon-CU_cAYSR.js} +254 -144
  62. package/server/{deacon-DYSEJb48.js → deacon-kiQrb4ZT.js} +3 -3
  63. package/server/{deacon-nudge-log-Bjg8U4Y9.js → deacon-nudge-log-6wVqAaqz.js} +3 -3
  64. package/server/{deacon-swarm-DftYRDo8.js → deacon-swarm-BXZZ1Z2-.js} +13 -13
  65. package/server/deacon-swarm-C-GwfjJy.js +2 -0
  66. package/server/deacon.js +8 -8
  67. package/server/{deploy-patrol-Bjsho_ha.js → deploy-patrol-AiFoP8dw.js} +6 -6
  68. package/server/{deploy-window-DeP_OIRk.js → deploy-window-C3F-tihF.js} +6 -6
  69. package/server/{deploy-window-CM6W1-c6.js → deploy-window-DkZraDyj.js} +1 -1
  70. package/server/{dev-supervisor-BpMoHlkR.js → dev-supervisor-bcOWqdQE.js} +2 -2
  71. package/server/{devcontainer-renderer-CtUgrVKW.js → devcontainer-renderer-_d6XhyND.js} +3 -3
  72. package/server/dist-Bzy0y69j.js +3 -0
  73. package/server/{dist-DyRx4cI7.js → dist-Cb_0uvpS.js} +1 -1
  74. package/server/{docker-BK7HIcBj.js → docker-DcMTFTUC.js} +2 -2
  75. package/server/{dod-BrSfUHm0.js → dod-C6n9RV3G.js} +1 -1
  76. package/server/{ensure-devcontainer-DRqaAkBR.js → ensure-devcontainer-BZgOhRo7.js} +1 -1
  77. package/server/{ensure-devcontainer-DseivYEy.js → ensure-devcontainer-DNi-ono3.js} +4 -4
  78. package/server/{esm-shims-CbI3BVkl.js → esm-shims-OSHAYaS1.js} +1 -1
  79. package/server/{event-store-tdiY5eDZ.js → event-store-CQL6NeqB.js} +3 -3
  80. package/server/{event-store-Cr5PQwFC.js → event-store-EV2cMiXj.js} +1 -1
  81. package/server/{events-CvvGK6LT.js → events-BTdrdEq8.js} +1 -1
  82. package/server/{events-CC1dgUpx.js → events-DTfAe4My.js} +3 -3
  83. package/server/{factory-CynerjXO.js → factory-CFibJuaw.js} +4 -4
  84. package/server/{feature-registry-population-B0pmAz0a.js → feature-registry-population-DKZFMbFt.js} +4 -4
  85. package/server/{feature-registry-storage-_wUBRD3J.js → feature-registry-storage-BdPuLcBX.js} +2 -2
  86. package/server/{features-Dhxz-wLc.js → features-ez2271oH.js} +2 -2
  87. package/server/{feedback-target-CPS15Vte.js → feedback-target-7mqqwrX6.js} +7 -7
  88. package/server/{feedback-target-iygZwmMc.js → feedback-target-CoFDHiM8.js} +1 -1
  89. package/server/{feedback-writer-C9b6ccN1.js → feedback-writer-CY5L1lB7.js} +5 -5
  90. package/server/{feedback-writer-qmiMbqTZ.js → feedback-writer-D3a22RCd.js} +1 -1
  91. package/server/flywheel-DHrgCphM.js +1084 -0
  92. package/server/flywheel-DzGtWnJ1.js +477 -0
  93. package/server/flywheel-SVF02Jpq.js +2 -0
  94. package/server/{flywheel-merge-order-DxbQKE1d.js → flywheel-merge-order-UU0tiUld.js} +9 -8
  95. package/server/{flywheel-merge-order-C-6zRLvM.js → flywheel-merge-order-UUcsCDb6.js} +1 -1
  96. package/server/{forge-Ch9gCFod.js → forge-CNFnyqps.js} +2 -2
  97. package/server/forge-DXnS_YFH.js +2 -0
  98. package/server/{from-CJ_aH5jD.js → from-kNxT0bZC.js} +1 -1
  99. package/server/{fts-db-CKgg0VKg.js → fts-db-CE46vDkZ.js} +2 -2
  100. package/server/{fts-operations-BrL_VTRr.js → fts-operations-CqY6zl-i.js} +2 -2
  101. package/server/{git-utils-BVa07a4a.js → git-utils-CRw2zLPC.js} +68 -3
  102. package/server/git-utils-D0_yhCgF.js +3 -0
  103. package/server/{github-app-CMBdIFBQ.js → github-app-C3QrAUd0.js} +18 -7
  104. package/server/{github-app-CPfoFAdV.js → github-app-ClZ2lk8D.js} +1 -1
  105. package/server/{github-client--XVlDpwM.js → github-client-BnIsSrEN.js} +2 -2
  106. package/server/{github-client-B4QsdE-X.js → github-client-DfQYVUaw.js} +1 -1
  107. package/server/{github-pr-lookup-BRbDW-qk.js → github-pr-lookup-D16NGsSO.js} +2 -2
  108. package/server/{harness-binary-CVio2m-u.js → harness-binary-DPUi-Pv8.js} +32 -6
  109. package/server/{harness-resolve-qHJBhy3Z.js → harness-resolve-3lNZkyT4.js} +18 -9
  110. package/server/{health-events-C9B8y1Hm.js → health-events-BBcTYQKU.js} +2 -2
  111. package/server/{health-events-CpfvuVmm.js → health-events-BDOHby5Q.js} +1 -1
  112. package/server/{hooks-DUXw8A0-.js → hooks-CKZgXlJb.js} +2 -2
  113. package/server/{hooks-ltecuFqZ.js → hooks-DPVX1rwQ.js} +1 -1
  114. package/server/{hume-BEq0bUDg.js → hume-Cz8igP9E.js} +2 -2
  115. package/server/hume-ccTf4wTX.js +3 -0
  116. package/server/{idle-stack-reaper-D7w9t3fE.js → idle-stack-reaper-CuLF0j2H.js} +1 -1
  117. package/server/{idle-stack-reaper-w1ISSlhs.js → idle-stack-reaper-DDIRwxUY.js} +2 -2
  118. package/server/{in-flight-guard-aQ1IxeI3.js → in-flight-guard-CAAkqPLu.js} +2 -2
  119. package/server/{infra-CzaSOgul.js → infra-BEqFxlJc.js} +14 -4
  120. package/server/{injection-DZ0PfYa4.js → injection-C8aiVJrF.js} +191 -183
  121. package/server/{injection-oNZeoDhL.js → injection-CPUIqNhI.js} +1 -1
  122. package/server/{inspect-agent-DJKLWcVT.js → inspect-agent-BLuJ1AkT.js} +135 -79
  123. package/server/inspect-agent-Brtz0URj.js +2 -0
  124. package/server/{internal-token-DXdfprGr.js → internal-token-BrcU6qfe.js} +1 -1
  125. package/server/{internal-token-Bb4XeV2x.js → internal-token-s0-oKybJ.js} +2 -2
  126. package/server/{io-B3_AHDfr.js → io-C9kF1wtJ.js} +3 -3
  127. package/server/{issue-closed-zhdvQicO.js → issue-closed-CDJk4pIp.js} +7 -7
  128. package/server/{issue-lifecycle-Dy4vd0Oa.js → issue-lifecycle-B8sZHVHh.js} +1 -1
  129. package/server/{issue-lifecycle-CreaCkjW.js → issue-lifecycle-ojZAzDBP.js} +21 -21
  130. package/server/{issue-service-singleton-DabvBWUp.js → issue-service-singleton-BvJ09SaR.js} +1 -1
  131. package/server/{issue-service-singleton-B5ushCvE.js → issue-service-singleton-Yx5DdmVJ.js} +8 -8
  132. package/server/{issues-B6ToV6x1.js → issues-BMmP_77e.js} +2 -2
  133. package/server/{jsonl-parser-Dhflo1SH.js → jsonl-parser-BXSlHwEh.js} +3 -3
  134. package/server/{label-cleanup-BKPJm4Hv.js → label-cleanup-B0UJwnv5.js} +3 -3
  135. package/server/{label-reconciler-DdWbHEBu.js → label-reconciler-B4iOAjlC.js} +4 -4
  136. package/server/{launcher-generator-CHVm7bGT.js → launcher-generator-BBWG_SiS.js} +101 -7
  137. package/server/{lifecycle-io-D8iNBcux.js → lifecycle-io-BREGpnLk.js} +5 -5
  138. package/server/{lifecycle-io-Bsnr2K4F.js → lifecycle-io-DPo7x11I.js} +1 -1
  139. package/server/{lifecycle-sycO16hj.js → lifecycle-xmBfK2GJ.js} +6 -6
  140. package/server/{lifecycle-DfeyBDwA.js → lifecycle-yPd___5E.js} +2 -2
  141. package/server/{linear-client-D4zqMnX7.js → linear-client-BsuUvkdA.js} +2 -2
  142. package/server/{linear-client-DqhDQO9k.js → linear-client-CTskEeT_.js} +1 -1
  143. package/server/memory-fts-worker.js +1 -1
  144. package/server/{merge-DK23JEdS.js → merge-B1DiziGU.js} +1 -1
  145. package/server/{merge-C_ZEhbqI.js → merge-CefQNAnq.js} +3 -3
  146. package/server/{merge-agent-XrB80vfT.js → merge-agent-4WOWlSYA.js} +28 -28
  147. package/server/{merge-agent-BQM3a8z5.js → merge-agent-CKkgIBPB.js} +1 -1
  148. package/server/{merge-batch-Bwoyr8Je.js → merge-batch-ClFn2T-y.js} +1 -1
  149. package/server/merge-ops-CR44oU9-.js +2 -0
  150. package/server/{merge-rebase-C1KIVr0s.js → merge-rebase-BfaTyXsw.js} +2 -2
  151. package/server/merge-set-DJ8-UErs.js +83 -0
  152. package/server/{merge-set-DnSYdBEp.js → merge-set-bUqbm3yc.js} +1 -1
  153. package/server/{merge-sync-SSv3E-pl.js → merge-sync-BJYeOODr.js} +1 -1
  154. package/server/{merge-sync-DZ9dojJn.js → merge-sync-VPV28g0g.js} +2 -2
  155. package/server/{merge-train-DxDfBTjr.js → merge-train-CHopycP0.js} +3 -3
  156. package/server/{merge-train-deps-CyYQUksx.js → merge-train-deps-D1cOZzy2.js} +4 -4
  157. package/server/{merge-verification-CSizH3HY.js → merge-verification-BkaOqPsw.js} +4 -4
  158. package/server/{multipart-parser-Dt8YPN5S.js → multipart-parser-duPAfSBw.js} +2 -2
  159. package/server/{no-resume-mode-Cx3K0hHi.js → no-resume-mode-Nw29vaFb.js} +1 -1
  160. package/server/node_modules/.package-lock.json +8 -8
  161. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/package.json +3 -3
  162. package/server/node_modules/undici/README.md +5 -0
  163. package/server/node_modules/undici/docs/docs/api/Client.md +4 -0
  164. package/server/node_modules/undici/docs/docs/api/Dispatcher.md +6 -0
  165. package/server/node_modules/undici/docs/docs/api/Interceptors.md +59 -0
  166. package/server/node_modules/undici/docs/docs/api/MockAgent.md +27 -0
  167. package/server/node_modules/undici/docs/docs/api/MockPool.md +28 -1
  168. package/server/node_modules/undici/docs/docs/index.md +5 -0
  169. package/server/node_modules/undici/lib/core/request.js +1 -1
  170. package/server/node_modules/undici/lib/core/util.js +6 -1
  171. package/server/node_modules/undici/lib/dispatcher/agent.js +3 -3
  172. package/server/node_modules/undici/lib/dispatcher/client-h1.js +31 -6
  173. package/server/node_modules/undici/lib/dispatcher/client-h2.js +34 -43
  174. package/server/node_modules/undici/lib/handler/cache-handler.js +93 -5
  175. package/server/node_modules/undici/lib/handler/cache-revalidation-handler.js +10 -0
  176. package/server/node_modules/undici/lib/handler/redirect-handler.js +5 -2
  177. package/server/node_modules/undici/lib/handler/retry-handler.js +6 -4
  178. package/server/node_modules/undici/lib/interceptor/cache.js +21 -4
  179. package/server/node_modules/undici/lib/interceptor/decompress.js +4 -0
  180. package/server/node_modules/undici/lib/mock/mock-interceptor.js +25 -7
  181. package/server/node_modules/undici/lib/mock/mock-utils.js +39 -10
  182. package/server/node_modules/undici/lib/util/cache.js +49 -7
  183. package/server/node_modules/undici/lib/web/fetch/body.js +2 -1
  184. package/server/node_modules/undici/lib/web/fetch/response.js +1 -3
  185. package/server/node_modules/undici/package.json +2 -2
  186. package/server/node_modules/undici/types/client.d.ts +2 -2
  187. package/server/node_modules/undici/types/dispatcher.d.ts +3 -3
  188. package/server/node_modules/undici/types/mock-interceptor.d.ts +5 -1
  189. package/server/{orphan-proposed-reconciler-neK8dHQk.js → orphan-proposed-reconciler-BvKkWMJQ.js} +12 -12
  190. package/server/{orphan-proposed-reconciler-BTkDrl4R.js → orphan-proposed-reconciler-CTSGcK8p.js} +1 -1
  191. package/server/package-lock.json +9 -9
  192. package/server/package.json +1 -1
  193. package/server/{pan-dir-DeVUgwA7.js → pan-dir-B0c3w0Ya.js} +3 -3
  194. package/server/{paths-_zEts6wc.js → paths-D-xWGHdh.js} +2 -2
  195. package/server/{pickup-Dd0Znxxy.js → pickup-DUCLWrJY.js} +17 -16
  196. package/server/{pipeline-membership-0HaEGDlH.js → pipeline-membership-mY3GprlK.js} +7 -7
  197. package/server/{pipeline-notifier-6iCJplFZ.js → pipeline-notifier-BJr8gQX6.js} +1 -1
  198. package/server/{pipeline-notifier-D0ykk59O.js → pipeline-notifier-BXkJzDC4.js} +2 -2
  199. package/server/{project-pipelines-2sK1apsO.js → project-pipelines-C0MWUeCU.js} +2 -2
  200. package/server/project-repos-B6GycDh9.js +94 -0
  201. package/server/project-repos-DXKQsc_m.js +3 -0
  202. package/server/{projects-9SkRpES9.js → projects-vjjcmiN8.js} +1 -1
  203. package/server/{prompts-Dp4Tpk39.js → prompts-DxzFXuLl.js} +2 -2
  204. package/server/{providers-DV7ec8l7.js → providers-qQAwGQDW.js} +7 -7
  205. package/server/{providers-DKkBXhxU.js → providers-u4Ga0jOr.js} +1 -1
  206. package/server/public/assets/{chunk-BO2N2NFS-CltymLRg.js → chunk-BO2N2NFS-BamJdinX.js} +4 -4
  207. package/server/public/assets/{diagram-OG6HWLK6-D2f6pjgA.js → diagram-OG6HWLK6-DfOB8-w4.js} +1 -1
  208. package/server/public/assets/{dist-DEmlBBNQ.js → dist-ByIuzMQW.js} +3 -3
  209. package/server/public/assets/{dist-BWR4qFiV.js → dist-D7zYSEA6.js} +1 -1
  210. package/server/public/assets/{ganttDiagram-6RSMTGT7-DnfiViPK.js → ganttDiagram-6RSMTGT7-EdmRyXL3.js} +1 -1
  211. package/server/public/assets/{highlighted-body-OFNGDK62-B8Wrmj9H.js → highlighted-body-OFNGDK62-MerOfTX8.js} +1 -1
  212. package/server/public/assets/{index-CsSuZQBI.js → index-CWeMerGO.js} +146 -144
  213. package/server/public/assets/{index-CUr1xv8w.css → index-CenuJ3Cw.css} +1 -1
  214. package/server/public/assets/{linear-C9zFQpkX.js → linear-BBbArIcK.js} +1 -1
  215. package/server/public/assets/mermaid-GHXKKRXX-CpPWAFwE.js +1 -0
  216. package/server/public/assets/{pieDiagram-4H26LBE5-lR8H7Yjd.js → pieDiagram-4H26LBE5-BKIddiJN.js} +1 -1
  217. package/server/public/assets/{prod-B1jCQihw.js → prod-B8vYiu52.js} +4 -4
  218. package/server/public/assets/{quadrantDiagram-W4KKPZXB-CVQ2guem.js → quadrantDiagram-W4KKPZXB-D6RtoULk.js} +1 -1
  219. package/server/public/assets/{sankeyDiagram-5OEKKPKP-eD1RB4gm.js → sankeyDiagram-5OEKKPKP-CLrCedZX.js} +1 -1
  220. package/server/public/assets/{xychartDiagram-2RQKCTM6-ChEC6dQn.js → xychartDiagram-2RQKCTM6-hznR8DYl.js} +1 -1
  221. package/server/public/index.html +2 -2
  222. package/server/{pull-requests--Ib2jTgy.js → pull-requests-7N8WKseP.js} +1 -1
  223. package/server/{pull-requests-CXIhdCYD.js → pull-requests-_lHueOHW.js} +3 -3
  224. package/server/{queries-6d7Cdtm7.js → queries-CjNIf-Ub.js} +576 -166
  225. package/server/{rally-B708-nZn.js → rally-CyWT_lNO.js} +3 -3
  226. package/server/{rally-api-nY0ZANw3.js → rally-api-C8e_1JRi.js} +2 -2
  227. package/server/{rally-api-yjQ0TfHd.js → rally-api-ClOSd-Tt.js} +1 -1
  228. package/server/{rally-client-B1EJhfV0.js → rally-client-lc-nokqr.js} +4 -4
  229. package/server/{rally-client-CULK2XAY.js → rally-client-sgtVqzNU.js} +1 -1
  230. package/server/rally-zhhtXuDP.js +3 -0
  231. package/server/{reap-terminal-sessions-MWnqdLCJ.js → reap-terminal-sessions-7KeHv1R1.js} +1 -1
  232. package/server/{reap-terminal-sessions-N3BTkmX_.js → reap-terminal-sessions-BtHPo6Xc.js} +1 -1
  233. package/server/rebuild-stack-CFvcBHsS.js +4 -0
  234. package/server/{rebuild-stack-Dp4eLkt4.js → rebuild-stack-lwtsW0GO.js} +26 -35
  235. package/server/{reconstruct-cache-uWbZfjms.js → reconstruct-cache-C3Ui7ojV.js} +6 -6
  236. package/server/{record-t6V-3Dcj.js → record-CN0pj4_5.js} +1 -1
  237. package/server/{record-update-DACtKh6_.js → record-update-bLJxAXH4.js} +1 -1
  238. package/server/{record-update-Dq0t2uBG.js → record-update-dE1Aw83j.js} +2 -2
  239. package/server/{recovery-trip-BJtIQuag.js → recovery-trip-BvRWfUXM.js} +2 -2
  240. package/server/{release-engine-DZpmGGzb.js → release-engine-Cx48W7z8.js} +5 -5
  241. package/server/{release-set-hnXd_kga.js → release-set-CQfuN9-v.js} +3 -3
  242. package/server/{remote-Br-ZWVIP.js → remote-C_2hasl7.js} +3 -3
  243. package/server/{remote-4tiENDaI.js → remote-ChgimyYa.js} +3 -3
  244. package/server/{remote-agents-nmty1mLu.js → remote-agents-By1ige5O.js} +6 -6
  245. package/server/{remote-agents-CRCg1L4H.js → remote-agents-CA3Ihlxj.js} +1 -1
  246. package/server/{remote-completion-BbWNd10K.js → remote-completion-fVe9e_3u.js} +12 -12
  247. package/server/resume-BFv1PGpA.js +3 -0
  248. package/server/{review-agent-sKkE1FEL.js → review-agent-CIGOQYBD.js} +29 -25
  249. package/server/{review-agent-DJRO8EG8.js → review-agent-DNboMyW4.js} +1 -1
  250. package/server/{review-artifacts-BLbSC4ke.js → review-artifacts-nRDPuMxd.js} +5 -5
  251. package/server/{review-context-BgX3lcCx.js → review-context-2uj-YQ8J.js} +69 -25
  252. package/server/{review-status-C6n6-9f_.js → review-status-btEYlaxA.js} +1 -1
  253. package/server/{review-status-enrichment-tbOn_A_u.js → review-status-enrichment-Dci-ZwEt.js} +3 -3
  254. package/server/{review-status-A7quS5KJ.js → review-status-kZj_KyCk.js} +42 -26
  255. package/server/{review-status-sync-BhSQ0d0l.js → review-status-sync-BTOpxtTC.js} +10 -5
  256. package/server/{review-status-sync-To3-iS-N.js → review-status-sync-DSDK3OMy.js} +1 -1
  257. package/server/{review-verdict-feedback-CTRNtzXO.js → review-verdict-feedback-CCjVA7Uk.js} +6 -6
  258. package/server/{review-verdict-feedback-C1Kg8n7t.js → review-verdict-feedback-CTd4QMBu.js} +1 -1
  259. package/server/{rollup-B53Y81xK.js → rollup-BKQC7jp4.js} +1 -1
  260. package/server/{rollup-WA0VD-Rr.js → rollup-FGsKki9R.js} +8 -8
  261. package/server/{scanner-D2743cp8.js → scanner-CnqEZeDy.js} +41 -14
  262. package/server/{sequence-io-Cg0zYj_E.js → sequence-io-D909zgeH.js} +4 -4
  263. package/server/{sequencer-agent-BGY8gjg-.js → sequencer-agent-CzkcK6P5.js} +5 -5
  264. package/server/server.js +2194 -341
  265. package/server/{service-DCpB_SGd.js → service-CLeAoU6G.js} +51 -50
  266. package/server/{session-fork-BQ8_6H32.js → session-fork-CHI1XvL9.js} +2 -2
  267. package/server/{session-history-CVZDpS3c.js → session-history-BT3IvqhC.js} +4 -4
  268. package/server/settings-66A6uvIA.js +2 -0
  269. package/server/{settings-BZ5m1UCl.js → settings-BTMvpNFU.js} +3 -3
  270. package/server/{settings-ylxwqwQG.js → settings-C0zgxOGf.js} +2 -2
  271. package/server/{shadow-engineering-BlxG6Xye.js → shadow-engineering-BJfgm-hX.js} +2 -2
  272. package/server/{shadow-state-Dh-HzF2J.js → shadow-state-7a-524T8.js} +2 -2
  273. package/server/{shadow-state-C2_epgx2.js → shadow-state-DnDyjujH.js} +1 -1
  274. package/server/{shadow-utils-4bvjn9b3.js → shadow-utils-Db3oroFG.js} +2 -2
  275. package/server/{ship-log-ClSMIzZX.js → ship-log-D9MlVzYU.js} +1 -1
  276. package/server/{smart-compaction-CHIxLr_d.js → smart-compaction-CV2ukKND.js} +1 -1
  277. package/server/{smart-compaction-r4pHQBIr.js → smart-compaction-KCYScAU1.js} +7 -7
  278. package/server/{spawn-planning-session-DWAorh2B.js → spawn-planning-session-DKpdFyOC.js} +30 -23
  279. package/server/{spawn-planning-session-KC_UduxD.js → spawn-planning-session-qUC2VWu3.js} +1 -1
  280. package/server/{specialist-completion-BXhav38U.js → specialist-completion-Ky9wCDpb.js} +1 -1
  281. package/server/{specialist-context-DtrYvGJ-.js → specialist-context-Bn3dCGS2.js} +5 -5
  282. package/server/{specialist-handoff-logger-C45ouoZ6.js → specialist-handoff-logger-CMEwYxa2.js} +2 -2
  283. package/server/{specialist-logs-DJ3RzKxW.js → specialist-logs-C5p8G7tx.js} +3 -3
  284. package/server/{specialists-JVO00bs7.js → specialists-CC4r-c2s.js} +776 -347
  285. package/server/{specialists-D5fRZXmN.js → specialists-CShuVGWT.js} +1 -1
  286. package/server/{specialists-DVj0hvaL.js → specialists-DM6bWjsi.js} +1 -1
  287. package/server/{specialists-DyFeedjn.js → specialists-jiuuyVkp.js} +21 -19
  288. package/server/specs-C8Wsn2XO.js +3 -0
  289. package/server/{src-CG9mCkP6.js → src-CXmtj0im.js} +6 -6
  290. package/server/{src-CMTQGyCK.js → src-CdmnTM2m.js} +5 -5
  291. package/server/{src-U7_kTPEE.js → src-DtcUOZCq.js} +111 -18
  292. package/server/stack-health-Bn3o8FBX.js +3 -0
  293. package/server/{stack-health-puygdaMd.js → stack-health-DxSdG9cW.js} +63 -9
  294. package/server/{stale-task-claims-BbFwCTb0.js → stale-task-claims-KJKxxiiQ.js} +4 -4
  295. package/server/{staleness-Cbl_w4Bw.js → staleness-CT34nwr9.js} +1 -1
  296. package/server/{staleness-Bpy41ngS.js → staleness-DPm7ClwA.js} +1 -1
  297. package/server/{state-home-CIGjwNfJ.js → state-home-Cn_Qu8IX.js} +2 -2
  298. package/server/{state-migrate-Dkzaxvny.js → state-migrate-BGg2ZaOt.js} +4 -4
  299. package/server/{stuck-remediation-CzEov_fq.js → stuck-remediation-DYuPRYYw.js} +300 -23
  300. package/server/{stuck-remediation-sY_MHHgQ.js → stuck-remediation-s9_2qfi6.js} +1 -1
  301. package/server/{substrate-bug-weights-service-BH66lhm7.js → substrate-bug-weights-service-B-FwCs5V.js} +3 -3
  302. package/server/{summary-fork-DHhJIsAL.js → summary-fork-D1RAk9rJ.js} +78 -12
  303. package/server/{summary-fork-D8bXjCr7.js → summary-fork-DpcxN9tf.js} +2 -2
  304. package/server/supervisor/{injection-budget-C1iPirFS.js → injection-budget-Csw5tqfJ.js} +2 -41
  305. package/server/supervisor/pty-supervisor.js +2 -1
  306. package/server/supervisor/pty-token-x-ea28Us.js +43 -0
  307. package/server/supervisor-FTJAIsAK.js +2 -0
  308. package/server/{supervisor-BO-Zk_h-.js → supervisor-wM4ooB5O.js} +3 -3
  309. package/server/{swarm-readiness-CQ_fwUWF.js → swarm-readiness-DlP_UjHq.js} +3 -3
  310. package/server/{system-prerequisites-Bza0ffAh.js → system-prerequisites-DUDj1YHf.js} +56 -29
  311. package/server/{teardown-workspace-CEgauF4U.js → teardown-workspace-DeTTImn-.js} +15 -15
  312. package/server/{test-agent-queue-DXDt0Xa-.js → test-agent-queue-MbxX5vqq.js} +6 -6
  313. package/server/{test-verdict-CmUBK5cT.js → test-verdict-bWYBtqBg.js} +1 -1
  314. package/server/{test-verdict-DFjjIHR5.js → test-verdict-gscuksPv.js} +1 -1
  315. package/server/{tldr-daemon-DL566HbH.js → tldr-daemon-BYFkts95.js} +1 -1
  316. package/server/{tldr-daemon-BDtLOIlO.js → tldr-daemon-C-69c3OI.js} +2 -2
  317. package/server/{tmux-DoThH6aj.js → tmux-B6z7h_vZ.js} +1 -1
  318. package/server/{tmux-ftABRAmc.js → tmux-R7N7y-Mh.js} +2 -2
  319. package/server/{token-CsOhvw42.js → token-BK6t8BIT.js} +2 -2
  320. package/server/token-util-DuPuNriz.js +3 -0
  321. package/server/{token-util-CTmczIfW.js → token-util-DxXu-vd1.js} +1 -1
  322. package/server/{tracker-config-B4itFzDo.js → tracker-config-G6latr8C.js} +2 -2
  323. package/server/{tracker-utils-BePq_oj-.js → tracker-utils-B4ylXZQK.js} +1 -1
  324. package/server/{tracker-utils-tnxxqROg.js → tracker-utils-DHv5pSDT.js} +2 -2
  325. package/server/{traefik-connect-m73vGebA.js → traefik-connect-Df2uXPsQ.js} +1 -1
  326. package/server/{tunnel-B2vxjx_b.js → tunnel-CDVKJpRv.js} +3 -3
  327. package/server/{tunnel-Cgj-IGIl.js → tunnel-DGdUkGoZ.js} +1 -1
  328. package/server/{types-BBNjPcqU.js → types-5M0lupud.js} +1 -1
  329. package/server/{uat-train-cKfM-_WW.js → uat-train-B05BWkp-.js} +1 -1
  330. package/server/{uat-train-CuEn0t9M.js → uat-train-DDSrSoV1.js} +25 -25
  331. package/server/validate-IfDGkaVR.js +177 -0
  332. package/server/{validation-CIi6pnI2.js → validation-CC9OPqJZ.js} +1 -1
  333. package/server/{validation-B5JxoPUS.js → validation-Dw1pzDzr.js} +4 -4
  334. package/server/{verification-artifact-C-lIHfUa.js → verification-artifact-B3itKTxu.js} +1 -1
  335. package/server/{verification-artifact-BcnIbigL.js → verification-artifact-TVFSz_q1.js} +1 -1
  336. package/server/{verification-runner-CDj4lD4t.js → verification-runner-BW4HOKAz.js} +1 -1
  337. package/server/{verification-runner-Br0S_Ous.js → verification-runner-CkgX6EtI.js} +91 -106
  338. package/server/{vtt-parser-DKpNNW5i.js → vtt-parser-DYPbKcIJ.js} +1 -1
  339. package/server/{work-agent-prompt-Yb2bd3Fq.js → work-agent-prompt-Du8Vh2aJ.js} +9 -9
  340. package/server/workflows-BQu4RFQ-.js +2 -0
  341. package/server/{workflows-C9WmILql.js → workflows-mbQzh6mQ.js} +18 -18
  342. package/server/{workspace-DuUdndHe.js → workspace--8tnhDI0.js} +1 -1
  343. package/server/{workspace-BVl4rihN.js → workspace-BPUws1-_.js} +3 -3
  344. package/server/{workspace-config-cEGcO6UT.js → workspace-config-CIVWZOQr.js} +1 -1
  345. package/server/{workspace-manager-hLUv3ADC.js → workspace-manager-CBhNdzE4.js} +66 -15
  346. package/server/workspace-manager-CWT55qeI.js +3 -0
  347. package/server/{workspace-metadata-DNpMixRq.js → workspace-metadata-BzHnwwX4.js} +1 -1
  348. package/server/{workspace-metadata-CskwzzhL.js → workspace-metadata-_WygnyoX.js} +2 -2
  349. package/server/{workspaces-hWvy9eKs.js → workspaces-Do_9J0LQ.js} +130 -111
  350. package/sync-sources/hooks/record-cost-event.js +6 -4
  351. package/sync-sources/skills/okf/README.md +11 -3
  352. package/sync-sources/skills/okf/SKILL.md +12 -1
  353. package/sync-sources/skills/okf/docs/USAGE.md +15 -0
  354. package/sync-sources/skills/okf/references/overdeck.md +28 -0
  355. package/sync-sources/skills/pan-flywheel/SKILL.md +18 -1
  356. package/sync-sources/skills/pan-knowledge/SKILL.md +10 -0
  357. package/sync-sources/skills/pan-orders/SKILL.md +33 -0
  358. package/sync-sources/skills/pan-start/SKILL.md +4 -0
  359. package/sync-sources/templates/traefik/dynamic/overdeck.yml.template +10 -0
  360. package/server/agent-state-Bg0lhqwj.js +0 -3
  361. package/server/agents-FlIgQ3ql.js +0 -3
  362. package/server/cli-BsVIHwzC.js +0 -3
  363. package/server/context-layers-B3Nt58jl.js +0 -4
  364. package/server/context-layers-ZYFcWiyc.js +0 -165
  365. package/server/deacon-swarm-9jRLS5Ke.js +0 -2
  366. package/server/dist-Bd3vn0Hw.js +0 -3
  367. package/server/flywheel-DMCUzDWg.js +0 -2
  368. package/server/flywheel-DSSpWmqF.js +0 -522
  369. package/server/flywheel-DcBkQvgE.js +0 -207
  370. package/server/forge-B-ZWyTRm.js +0 -2
  371. package/server/git-utils-Dry_Ka_D.js +0 -3
  372. package/server/hume-B_DbflNM.js +0 -3
  373. package/server/inspect-agent-ch-F-5Ci.js +0 -2
  374. package/server/layers-DzxSTGNA.js +0 -93
  375. package/server/merge-blockers-BsFjGrQ8.js +0 -41
  376. package/server/merge-ops-DlB1IM0Y.js +0 -2
  377. package/server/merge-set-DLz0MkGT.js +0 -139
  378. package/server/public/assets/mermaid-GHXKKRXX-BUAB8hqt.js +0 -1
  379. package/server/rally-njs_mJrt.js +0 -3
  380. package/server/rebuild-stack-kA7XngID.js +0 -3
  381. package/server/resume-CcKqnTvE.js +0 -3
  382. package/server/settings-D0OSwos5.js +0 -2
  383. package/server/specs-nN45DG2X.js +0 -3
  384. package/server/stack-health-Df0YEZKa.js +0 -3
  385. package/server/supervisor-BPy-o1A8.js +0 -2
  386. package/server/token-util-DrHg8abn.js +0 -3
  387. package/server/workflows-D90rMOya.js +0 -2
  388. package/server/workspace-manager-ZTdJAy9M.js +0 -3
@@ -1,44 +1,45 @@
1
1
  import { a as __toCommonJS } from "./rolldown-runtime-DNCzzKnI.js";
2
- import { A as canUseHarnessSync, Br as getOverdeckHome, D as resolveTieredExecutionEnabled, H as init_providers, I as UnknownModelError, Jn as extractPrefixSync, M as init_harness_policy, Nr as encodeClaudeProjectDir, O as resolveTieredExecutionEnabledForIssue, Qt as parsePorcelainStatusPaths, T as init_tier_table, Tn as init_projects, U as piProviderForModel, Ur as packageRoot, V as getProviderForModelSync, Vr as init_paths, Wr as resolveOhmypiExtensionPath, Yn as init_issue_id, Yt as init_state_plane, Zn as parseIssueIdSync, c as isClaudeCodeChannelsEnabled, f as loadConfigSync, in as shouldCommitLegacyWorkspaceArtifacts, ir as FsError, kn as listProjectsSync, mr as init_errors, nn as init_state_read_home, t as init_config_yaml, tt as resolveModel, yn as getProjectSync, zn as resolveProjectFromIssueSync } from "./config-yaml-DvyMuOle.js";
2
+ import { A as canUseHarnessSync, Br as getOverdeckHome, D as resolveTieredExecutionEnabled, H as init_providers, I as UnknownModelError, Jn as extractPrefixSync, M as init_harness_policy, Nr as encodeClaudeProjectDir, O as resolveTieredExecutionEnabledForIssue, Qt as parsePorcelainStatusPaths, T as init_tier_table, Tn as init_projects, U as piProviderForModel, Ur as packageRoot, V as getProviderForModelSync, Vr as init_paths, Wr as resolveOhmypiExtensionPath, Yn as init_issue_id, Yt as init_state_plane, Zn as parseIssueIdSync, c as isClaudeCodeChannelsEnabled, f as loadConfigSync, fn as findProjectByPathSync, in as shouldCommitLegacyWorkspaceArtifacts, ir as FsError, kn as listProjectsSync, mr as init_errors, nn as init_state_read_home, rn as resolveStateReadHomeSync, t as init_config_yaml, tt as resolveModel, yn as getProjectSync, zn as resolveProjectFromIssueSync } from "./config-yaml-DySPNmKN.js";
3
3
  import { a as init_activity_logger, n as emitActivityEntrySync } from "./activity-logger-DDlOIAML.js";
4
- import { d as getOverdeckDatabaseSync, f as init_infra } from "./infra-CzaSOgul.js";
5
- import { $ as init_child_env, B as sendKeysAsync, D as killSession, H as sessionExists, M as listSessionNames, N as listSessions, Q as buildChildEnvWithoutTmuxSync, T as isHarnessProcessAlive, U as sessionExistsSync, V as sendRawKeystroke, W as setOption, X as BLANKED_PROVIDER_ENV, g as findManagedServerPidSync, i as capturePane, m as exactPaneTarget, s as createSession, w as init_tmux } from "./tmux-ftABRAmc.js";
6
- import { a as init_event_store, n as getEventStore } from "./event-store-tdiY5eDZ.js";
7
- import { k as normalizeChannelReplyPayload, o as getHarnessBehavior, t as init_src, x as DomainEvent } from "./src-U7_kTPEE.js";
8
- import { E as init_agent_state_sync, b as setReviewStatusSync, c as getReviewStatusSync, d as loadReviewStatuses, i as clearWorkspaceStuck, k as stateToOverdeckParamsForDb, l as init_review_status, w as AGENT_COLUMNS_FOR_DB } from "./review-status-A7quS5KJ.js";
9
- import { a as EventStoreService, c as ReadModelService, d as init_read_model, i as init_issue_lifecycle, s as init_domain_services, t as IssueLifecycle, u as getClosedIssueIdsForReadSource } from "./issue-lifecycle-CreaCkjW.js";
10
- import { d as isTerminalIssueStage, o as init_agents, u as getIssueStageSync } from "./agents-B4Bjbkfv.js";
11
- import { n as ensureSessionContextBriefingFile, r as init_briefing_freshness } from "./briefing-freshness-DWdW7vUm.js";
12
- import { o as getPricingSync, s as init_cost, t as calculateCostSync } from "./cost-Ca0YTWDw.js";
13
- import { An as writeChannelsBridgeMcpConfig, Ar as init_codex_auth, At as deliverAgentPermissionDecision, Bn as getAgentDir, Cn as validateProviderHealth, Cr as getAgentRuntimeStateSync, F as init_tier_escalation, G as resumeAgent, Gt as transitionIssueToInProgress, H as restartAgent, Hn as getAgentState, In as clearAgentTroubled, Lt as BRIDGE_TOKEN_HEADER, Nt as setAgentDeliveryMethod, P as decideEscalation, Pn as clearAgentPaused, Q as operatorInterventionEvent, Rt as init_bridge_token, Sn as init_provider_health, Sr as getAgentRuntimeState, Tr as saveAgentRuntimeState, V as recoverAgent, Wn as getAgentStateSync, X as messageAgent, Xt as resolveStaffing, Z as init_operator_interventions, Zn as markAgentStoppedState, ar as setAgentPaused, at as saveSessionId, b as init_agents$1, bn as getProviderExportsForModel, cr as wipeAgentStateDirs, dn as piFifoPaths, et as getActivity, fn as init_ohmypi_fifo, fr as init_pty_token, ft as stopAgent, gr as clearReadySignal, hr as resolvePtySupervisorScriptPath, i as listRunningAgents, in as getProviderAuthMode, ir as saveAgentStateSync, kn as dismissDevChannelsDialog, kr as checkCodexAuthStatus, kt as deliverAgentMessage, lr as writeAgentStateJsonSync, mr as init_pty_supervisor_locate, nt as getLatestSessionIdSync, pn as ohmypiFifoPaths, pr as writePtyToken, qt as init_staffing, r as listAgentStates, rr as saveAgentState, rt as getSessionId, tn as getAgentRuntimeBaseCommand, tt as getLatestSessionId, un as init_pi_fifo, vn as determineModel, vr as normalizeAgentId, xr as waitForReadySignal, yn as getProviderEnvForModel, zt as writeBridgeTokenSync } from "./queries-6d7Cdtm7.js";
14
- import { a as performHandoff, i as checkAllTriggers, s as getAgentHealth, t as getCloisterService } from "./service-DCpB_SGd.js";
15
- import { o as init_persistent_logger, s as logAgentLifecycleSync } from "./session-history-CVZDpS3c.js";
16
- import { t as init_behavior } from "./behavior-B_-4EKF3.js";
17
- import { a as init_tracker_config, t as getGitHubConfig } from "./tracker-config-B4itFzDo.js";
18
- import { n as init_issue_service_singleton, r as issue_service_singleton_exports } from "./issue-service-singleton-B5ushCvE.js";
19
- import { o as getInternalTokenSync, s as init_internal_token } from "./internal-token-Bb4XeV2x.js";
4
+ import { d as getOverdeckDatabaseSync, f as init_infra } from "./infra-BEqFxlJc.js";
5
+ import { $ as init_child_env, B as sendKeysAsync, D as killSession, H as sessionExists, M as listSessionNames, N as listSessions, Q as buildChildEnvWithoutTmuxSync, T as isHarnessProcessAlive, U as sessionExistsSync, V as sendRawKeystroke, W as setOption, X as BLANKED_PROVIDER_ENV, g as findManagedServerPidSync, i as capturePane, m as exactPaneTarget, s as createSession, w as init_tmux } from "./tmux-R7N7y-Mh.js";
6
+ import { a as init_event_store, n as getEventStore } from "./event-store-CQL6NeqB.js";
7
+ import { M as normalizeChannelReplyPayload, o as getHarnessBehavior, t as init_src, w as DomainEvent } from "./src-DtcUOZCq.js";
8
+ import { E as init_agent_state_sync, b as setReviewStatusSync, c as getReviewStatusSync, d as loadReviewStatuses, i as clearWorkspaceStuck, k as stateToOverdeckParamsForDb, l as init_review_status, w as AGENT_COLUMNS_FOR_DB } from "./review-status-kZj_KyCk.js";
9
+ import { a as EventStoreService, c as ReadModelService, d as init_read_model, i as init_issue_lifecycle, s as init_domain_services, t as IssueLifecycle, u as getClosedIssueIdsForReadSource } from "./issue-lifecycle-ojZAzDBP.js";
10
+ import { d as isTerminalIssueStage, o as init_agents, u as getIssueStageSync } from "./agents-EbI0zCJl.js";
11
+ import { n as ensureSessionContextBriefingFile, r as init_briefing_freshness } from "./briefing-freshness-D1wzUIWv.js";
12
+ import { o as getPricingSync, s as init_cost, t as calculateCostSync } from "./cost-B2ddP6wq.js";
13
+ import { Ar as saveAgentRuntimeState, At as deliverAgentPermissionDecision, Bt as assertWorkspaceStackHealthyForSpawn, Cr as normalizeAgentId, Dn as validateProviderHealth, Dr as getAgentRuntimeState, En as init_provider_health, Er as waitForReadySignal, F as init_tier_escalation, Fn as writeChannelsBridgeMcpConfig, Fr as init_codex_auth, G as resumeAgent, Gn as getAgentDir, Gt as transitionIssueToInProgress, H as restartAgent, Lt as BRIDGE_TOKEN_HEADER, Nt as setAgentDeliveryMethod, Or as getAgentRuntimeStateSync, P as decideEscalation, Pn as dismissDevChannelsDialog, Pr as checkCodexAuthStatus, Q as operatorInterventionEvent, Rt as init_bridge_token, Sn as determineModel, Ut as init_spawn_prep, V as recoverAgent, Vn as clearAgentTroubled, X as messageAgent, Xt as resolveStaffing, Yn as getAgentStateSync, Z as init_operator_interventions, _r as init_pty_token, an as getProviderAuthMode, at as saveSessionId, b as init_agents$1, br as resolvePtySupervisorScriptPath, cr as saveAgentState, et as getActivity, fn as init_pi_fifo, ft as stopAgent, hn as ohmypiFifoPaths, i as listRunningAgents, kt as deliverAgentMessage, lr as saveAgentStateSync, mn as init_ohmypi_fifo, mr as writeAgentStateJsonSync, nn as getAgentRuntimeBaseCommand, nr as markAgentStoppedState, nt as getLatestSessionIdSync, pn as piFifoPaths, pr as wipeAgentStateDirs, qn as getAgentState, qt as init_staffing, r as listAgentStates, rt as getSessionId, sn as init_runtime_command, tn as getAcpLauncherFields, tt as getLatestSessionId, un as waitForAcpHostReady, ur as setAgentPaused, vr as writePtyToken, wn as getProviderExportsForModel, xr as clearReadySignal, yr as init_pty_supervisor_locate, zn as clearAgentPaused, zt as writeBridgeTokenSync } from "./queries-CjNIf-Ub.js";
14
+ import { a as performHandoff, i as checkAllTriggers, s as getAgentHealth, t as getCloisterService } from "./service-CLeAoU6G.js";
15
+ import { o as init_persistent_logger, s as logAgentLifecycleSync } from "./session-history-BT3IvqhC.js";
16
+ import { t as init_behavior } from "./behavior-B3exJ42O.js";
17
+ import { a as init_tracker_config, t as getGitHubConfig } from "./tracker-config-G6latr8C.js";
18
+ import { n as init_issue_service_singleton, r as issue_service_singleton_exports } from "./issue-service-singleton-Yx5DdmVJ.js";
19
+ import { o as getInternalTokenSync, s as init_internal_token } from "./internal-token-s0-oKybJ.js";
20
20
  import { a as PAN_DIRNAME, i as PAN_CONTINUE_FILENAME, p as init_types } from "./types-hraoaQIp.js";
21
- import { a as generateXBriefFilename, o as init_lifecycle } from "./lifecycle-DfeyBDwA.js";
22
- import { f as readTierOverrides, g as serializeXBriefDocument, h as recordTierPromotion, m as readWorkspacePlanSync, o as init_io, r as findPlan, u as readPlan } from "./io-B3_AHDfr.js";
23
- import { B as removeFavorite, E as hasOtherActiveConversationOnTmuxSession, F as markConversationEnded, G as setConversationHarness, K as setConversationModel, M as listConversations, P as markConversationActive, Q as updateConversationDeliveryMethod, S as getConversationByName, W as setConversationEffort, g as backfillConversationModel, h as archiveConversation, k as init_conversations, nt as updateLastAttached, rt as updateSpawnError, x as getConversationById, y as createConversation } from "./conversations-DbOs1e9Q.js";
24
- import { n as recordFeatureRegistryLifecycle, t as init_feature_registry_population } from "./feature-registry-population-B0pmAz0a.js";
25
- import { a as requireModelOverrideSync, i as normalizeModelOverrideSync, n as init_launcher_generator, r as init_model_validation, t as generateLauncherScriptSync } from "./launcher-generator-CHVm7bGT.js";
26
- import { a as init_claude_permissions, o as resolvePermissionModeSync, r as getClaudePermissionFlagsStringSync, t as BYPASS_PERMISSION_MODE } from "./claude-permissions-H_5wHQZQ.js";
27
- import { h as workspaceContextFile, l as piGlobalContextFile, o as init_layers } from "./layers-DzxSTGNA.js";
28
- import { n as init_harness_binary, r as prepareHarnessLaunch } from "./harness-binary-CVio2m-u.js";
29
- import { a as init_stack_health, i as getWorkspaceStackHealth } from "./stack-health-puygdaMd.js";
30
- import { l as init_dag, o as getDispatchableItems } from "./dag-CdOjJVDT.js";
31
- import { n as resolveHarness, t as init_harness_resolve } from "./harness-resolve-qHJBhy3Z.js";
32
- import { a as loadCloisterConfigSync, r as init_config } from "./config-DjLOdbgT.js";
33
- import { c as isStateMigrated, o as init_state_home } from "./state-home-CIGjwNfJ.js";
34
- import { a as init_lifecycle_io, c as updatePlanStatus, s as transitionXBriefOnMain } from "./lifecycle-io-D8iNBcux.js";
35
- import { _ as init_codex_conversation_parser, c as parseEntireConversation, d as init_pi_conversation_parser, g as parseOhmypiConversationMessages, m as init_ohmypi_conversation_parser, p as parsePiConversationMessages, t as init_conversation_service, v as parseCodexConversationMessages } from "./conversation-service-Du-MTNpJ.js";
36
- import { _ as parseCodexApprovalPrompt, d as getAgentPendingQuestions$1, f as getAgentWorkspace$1, g as normalizeAwaitingInputPrompt, m as detectAwaitingInputForAgent, o as getRuntimeForAgent, p as scanPendingInputsPromise, s as computeAgentEnrichment, u as getAgentJsonlPath$1 } from "./stuck-remediation-CzEov_fq.js";
37
- import { Dt as classifyMemoryPressure, It as getSystemHealthSnapshot, Pt as getResourceConfig } from "./deacon-pRnyD5w9.js";
38
- import { o as stopWorkspaceDocker, r as init_workspace_manager } from "./workspace-manager-hLUv3ADC.js";
39
- import { a as init_jsonl_parser, o as normalizeModelName } from "./jsonl-parser-Dhflo1SH.js";
40
- import { r as init_in_flight_guard, t as createInFlightGuard } from "./in-flight-guard-aQ1IxeI3.js";
41
- import { a as loadWorkspaceMetadataSync } from "./workspace-metadata-CskwzzhL.js";
21
+ import { a as generateXBriefFilename, o as init_lifecycle } from "./lifecycle-yPd___5E.js";
22
+ import { f as readTierOverrides, g as serializeXBriefDocument, h as recordTierPromotion, m as readWorkspacePlanSync, o as init_io, r as findPlan, u as readPlan } from "./io-C9kF1wtJ.js";
23
+ import { B as removeFavorite, E as hasOtherActiveConversationOnTmuxSession, F as markConversationEnded, G as setConversationHarness, K as setConversationModel, M as listConversations, P as markConversationActive, Q as updateConversationDeliveryMethod, S as getConversationByName, W as setConversationEffort, g as backfillConversationModel, h as archiveConversation, k as init_conversations, nt as updateLastAttached, rt as updateSpawnError, x as getConversationById, y as createConversation } from "./conversations-6AfUfbwc.js";
24
+ import { n as recordFeatureRegistryLifecycle, t as init_feature_registry_population } from "./feature-registry-population-DKZFMbFt.js";
25
+ import { a as normalizeModelOverrideSync, i as init_model_validation, n as init_launcher_generator, o as requireModelOverrideSync, r as MODEL_ID_PATTERN, t as generateLauncherScriptSync } from "./launcher-generator-BBWG_SiS.js";
26
+ import { a as init_claude_permissions, o as resolvePermissionModeSync, r as getClaudePermissionFlagsStringSync, t as BYPASS_PERMISSION_MODE } from "./claude-permissions-DNWEVV6z.js";
27
+ import { E as init_layers, I as workspaceContextFile, k as piGlobalContextFile } from "./assemble-J2ZZ2C15.js";
28
+ import { i as prepareHarnessLaunch, r as init_harness_binary } from "./harness-binary-DPUi-Pv8.js";
29
+ import { a as getWorkspaceStackHealth, s as init_stack_health } from "./stack-health-DxSdG9cW.js";
30
+ import { l as init_dag, o as getDispatchableItems } from "./dag-B1ucnjDU.js";
31
+ import { n as resolveHarness, t as init_harness_resolve } from "./harness-resolve-3lNZkyT4.js";
32
+ import { a as loadCloisterConfigSync, r as init_config } from "./config-CKxYiCmX.js";
33
+ import { c as isStateMigrated, o as init_state_home } from "./state-home-Cn_Qu8IX.js";
34
+ import { a as init_lifecycle_io, c as updatePlanStatus, s as transitionXBriefOnMain } from "./lifecycle-io-BREGpnLk.js";
35
+ import { _ as init_codex_conversation_parser, b as parseAcpConversationMessages, c as parseEntireConversation, d as init_pi_conversation_parser, g as parseOhmypiConversationMessages, m as init_ohmypi_conversation_parser, p as parsePiConversationMessages, t as init_conversation_service, v as parseCodexConversationMessages, y as init_acp_conversation_parser } from "./conversation-service-DPJ71F33.js";
36
+ import { _ as parseCodexApprovalPrompt, d as getAgentPendingQuestions$1, f as getAgentWorkspace$1, g as normalizeAwaitingInputPrompt, m as detectAwaitingInputForAgent, o as getRuntimeForAgent, p as scanPendingInputsPromise, s as computeAgentEnrichment, u as getAgentJsonlPath$1 } from "./stuck-remediation-DYuPRYYw.js";
37
+ import { B as getBook, H as liveOrderIssueLookup, T as resolveLiveFlywheelRunId, w as readFlywheelLaunchMetadata, y as getFlywheelRunDir, z as computeBookProgress } from "./flywheel-DHrgCphM.js";
38
+ import { Dt as classifyMemoryPressure, It as getSystemHealthSnapshot, Pt as getResourceConfig } from "./deacon-CU_cAYSR.js";
39
+ import { o as stopWorkspaceDocker, r as init_workspace_manager } from "./workspace-manager-CBhNdzE4.js";
40
+ import { a as init_jsonl_parser, o as normalizeModelName } from "./jsonl-parser-BXSlHwEh.js";
41
+ import { r as init_in_flight_guard, t as createInFlightGuard } from "./in-flight-guard-CAAkqPLu.js";
42
+ import { a as loadWorkspaceMetadataSync } from "./workspace-metadata-_WygnyoX.js";
42
43
  import { basename, delimiter, dirname, join, resolve } from "node:path";
43
44
  import { Cause, Data, Effect, Layer, Option, Schema, Stream } from "effect";
44
45
  import { join as join$1 } from "path";
@@ -200,10 +201,12 @@ init_layers();
200
201
  init_harness_binary();
201
202
  init_ohmypi_fifo();
202
203
  init_pi_fifo();
204
+ init_runtime_command();
203
205
  init_stack_health();
204
206
  init_launcher_generator();
205
207
  init_dag();
206
208
  init_staffing();
209
+ init_spawn_prep();
207
210
  init_harness_resolve();
208
211
  init_bridge_token();
209
212
  init_operator_interventions();
@@ -364,7 +367,215 @@ async function waitForSessionRespawn(sessionName, timeoutMs) {
364
367
  return Effect.runPromise(sessionExists(sessionName));
365
368
  }
366
369
  //#endregion
370
+ //#region routes/dashboard-auth.ts
371
+ init_state_read_home();
372
+ init_state_plane();
373
+ init_types();
374
+ init_issue_lifecycle();
375
+ init_codex_auth();
376
+ init_config();
377
+ init_state_home();
378
+ init_internal_token();
379
+ const DASHBOARD_SESSION_COOKIE = "overdeck_session";
380
+ const DASHBOARD_CSRF_HEADER = "x-overdeck-csrf-token";
381
+ const DASHBOARD_SESSION_MAX_AGE_SECONDS = 3600 * 24 * 30;
382
+ let browserSessionToken;
383
+ let browserCsrfToken;
384
+ function getDashboardSessionToken() {
385
+ if (browserSessionToken) return browserSessionToken;
386
+ const override = process.env["OVERDECK_DASHBOARD_SESSION_TOKEN"];
387
+ if (override) {
388
+ browserSessionToken = override;
389
+ return browserSessionToken;
390
+ }
391
+ const internal = getInternalTokenSync();
392
+ browserSessionToken = internal ? createHmac("sha256", internal).update("overdeck-dashboard-session-v1").digest("base64url") : randomBytes(32).toString("base64url");
393
+ return browserSessionToken;
394
+ }
395
+ function dashboardCsrfToken() {
396
+ if (browserCsrfToken) return browserCsrfToken;
397
+ const override = process.env["OVERDECK_DASHBOARD_CSRF_TOKEN"];
398
+ if (override) {
399
+ browserCsrfToken = override;
400
+ return browserCsrfToken;
401
+ }
402
+ const internal = getInternalTokenSync();
403
+ browserCsrfToken = internal ? createHmac("sha256", internal).update("overdeck-dashboard-csrf-v1").digest("base64url") : randomBytes(32).toString("base64url");
404
+ return browserCsrfToken;
405
+ }
406
+ function constantTimeTokenEqual$1(provided, expected) {
407
+ if (!provided) return false;
408
+ return timingSafeEqual(createHash$1("sha256").update(provided).digest(), createHash$1("sha256").update(expected).digest());
409
+ }
410
+ function cookieValue(cookieHeader, name) {
411
+ if (!cookieHeader) return void 0;
412
+ for (const part of cookieHeader.split(";")) {
413
+ const [rawKey, ...rawValue] = part.trim().split("=");
414
+ if (rawKey !== name) continue;
415
+ try {
416
+ return decodeURIComponent(rawValue.join("="));
417
+ } catch {
418
+ return;
419
+ }
420
+ }
421
+ }
422
+ function dashboardSessionCookieHeader(options = {}) {
423
+ const secure = options.secure ? "; Secure" : "";
424
+ return `${DASHBOARD_SESSION_COOKIE}=${encodeURIComponent(getDashboardSessionToken())}; Path=/; HttpOnly; SameSite=Strict; Max-Age=${DASHBOARD_SESSION_MAX_AGE_SECONDS}${secure}`;
425
+ }
426
+ function hasDashboardInternalTokenHeaders(headers) {
427
+ const expected = getInternalTokenSync();
428
+ if (!expected) return false;
429
+ if (constantTimeTokenEqual$1(getHeaderFromMap(headers, "x-overdeck-internal-token"), expected)) return true;
430
+ const authorization = getHeaderFromMap(headers, "authorization");
431
+ if (authorization) {
432
+ const [scheme, token] = authorization.split(/\s+/);
433
+ if (scheme?.toLowerCase() === "bearer" && constantTimeTokenEqual$1(token, expected)) return true;
434
+ }
435
+ return false;
436
+ }
437
+ function hasDashboardInternalToken(request) {
438
+ return hasDashboardInternalTokenHeaders(request.headers);
439
+ }
440
+ function hasDashboardAuthHeaders(headers) {
441
+ return hasDashboardInternalTokenHeaders(headers) || constantTimeTokenEqual$1(cookieValue(getHeaderFromMap(headers, "cookie"), "overdeck_session"), getDashboardSessionToken());
442
+ }
443
+ function hasDashboardAuth(request) {
444
+ return hasDashboardAuthHeaders(request.headers);
445
+ }
446
+ function isJsonContentType(headers) {
447
+ const contentType = getHeaderFromMap(headers, "content-type");
448
+ if (!contentType) return false;
449
+ const [mime] = contentType.toLowerCase().split(";");
450
+ return mime.trim() === "application/json";
451
+ }
452
+ function hasTrustedExactOrigin(headers) {
453
+ const origin = getHeaderFromMap(headers, "origin");
454
+ if (!origin) return false;
455
+ const normalized = normalizeOrigin(origin);
456
+ return !!normalized && getTrustedOrigins().includes(normalized);
457
+ }
458
+ function hasValidCsrfToken(headers) {
459
+ return constantTimeTokenEqual$1(getHeaderFromMap(headers, DASHBOARD_CSRF_HEADER), dashboardCsrfToken());
460
+ }
461
+ function rejectUnsafeDashboardMutationRequest(request) {
462
+ const authError = rejectUnauthorizedDashboardRequest(request);
463
+ if (authError) return authError;
464
+ const headers = request.headers;
465
+ if (!isJsonContentType(headers)) return jsonResponse({ error: "Content-Type must be application/json" }, { status: 400 });
466
+ if (hasDashboardInternalToken(request)) return null;
467
+ if (getHeaderFromMap(headers, "origin") && !hasTrustedExactOrigin(headers)) return jsonResponse({ error: "Invalid origin" }, { status: 403 });
468
+ if (!hasValidCsrfToken(headers)) return jsonResponse({ error: "Invalid CSRF token" }, { status: 403 });
469
+ return null;
470
+ }
471
+ function ipv4ToInt(value) {
472
+ const parts = value.split(".");
473
+ if (parts.length !== 4) return null;
474
+ let result = 0;
475
+ for (const part of parts) {
476
+ const octet = Number(part);
477
+ if (!Number.isInteger(octet) || octet < 0 || octet > 255) return null;
478
+ result = (result << 8 | octet) >>> 0;
479
+ }
480
+ return result;
481
+ }
482
+ /** RFC1918 private ranges — Docker bridges always fall inside one of these. */
483
+ function isRfc1918(ip) {
484
+ return (ip & 4278190080) >>> 0 === 167772160 || (ip & 4293918720) >>> 0 === 2886729728 || (ip & 4294901760) >>> 0 === 3232235520;
485
+ }
486
+ /**
487
+ * True when `addr` is the IP of a container on one of THIS host's Docker bridge
488
+ * interfaces (docker0 / br-*). Such a peer can only be a process running on this
489
+ * machine — our own host-local Traefik fronting overdeck.localhost, or another
490
+ * Overdeck container — never a LAN client (a direct LAN hit to the 0.0.0.0
491
+ * API port arrives with a LAN peer that is not inside any Docker bridge subnet).
492
+ *
493
+ * Pure for testability: the interface map is injected. We only ever trust
494
+ * RFC1918 bridge subnets, so a misconfigured public-range br-* cannot widen
495
+ * trust beyond the local Docker fabric.
496
+ */
497
+ function peerIsHostLocalDockerBridge(addr, interfaces) {
498
+ const peer = ipv4ToInt(addr);
499
+ if (peer === null) return false;
500
+ for (const [name, addrs] of Object.entries(interfaces)) {
501
+ if (name !== "docker0" && !name.startsWith("br-")) continue;
502
+ for (const info of addrs ?? []) {
503
+ if (info.family !== "IPv4") continue;
504
+ const ifaceIp = ipv4ToInt(info.address);
505
+ const mask = ipv4ToInt(info.netmask);
506
+ if (ifaceIp === null || mask === null) continue;
507
+ const network = (ifaceIp & mask) >>> 0;
508
+ if (!isRfc1918(network)) continue;
509
+ if ((peer & mask) >>> 0 === network) return true;
510
+ }
511
+ }
512
+ return false;
513
+ }
514
+ /**
515
+ * True when `addr` shares an RFC1918 subnet with one of THIS process's own
516
+ * network interfaces. This is the in-container counterpart of
517
+ * peerIsHostLocalDockerBridge: inside a container the Docker bridge is
518
+ * invisible — the container sees only its veth endpoints (eth0/eth1), so the
519
+ * docker0/br-* name filter never matches and the host-local Traefik fronting
520
+ * the stack 401'd every session mint (first hit live on the PAN-1737 UAT
521
+ * stack). A peer inside one of the container's attached Docker-network
522
+ * subnets can only be another container on those networks — the server
523
+ * publishes no host port (Traefik labels only), so no LAN client can ever
524
+ * present such an address. Only consulted when running inside a container.
525
+ */
526
+ function peerIsLocalContainerNetwork(addr, interfaces) {
527
+ const peer = ipv4ToInt(addr);
528
+ if (peer === null) return false;
529
+ for (const addrs of Object.values(interfaces)) for (const info of addrs ?? []) {
530
+ if (info.family !== "IPv4" || info.internal) continue;
531
+ const ifaceIp = ipv4ToInt(info.address);
532
+ const mask = ipv4ToInt(info.netmask);
533
+ if (ifaceIp === null || mask === null) continue;
534
+ const network = (ifaceIp & mask) >>> 0;
535
+ if (!isRfc1918(network)) continue;
536
+ if ((peer & mask) >>> 0 === network) return true;
537
+ }
538
+ return false;
539
+ }
540
+ /** Docker creates /.dockerenv in every container — stable in-container signal. */
541
+ const runningInContainer = existsSync("/.dockerenv");
542
+ /**
543
+ * A request we trust to mint a session because it originated from this machine —
544
+ * the local browser hitting the dashboard directly (127.0.0.1), or the
545
+ * host-local Traefik that fronts overdeck.localhost. In Docker, that Traefik reaches
546
+ * the host server from a Docker-bridge IP (e.g. 172.18.0.2), NOT 127.0.0.1, so
547
+ * a literal-loopback check alone silently breaks the zero-step bootstrap for
548
+ * every overdeck.localhost user — their session mint 401s and no cookie is ever set.
549
+ *
550
+ * This is the auto-bootstrap that removes the manual one-time #overdeck_token
551
+ * step: any browser on overdeck.localhost gets a session with no user action. It is
552
+ * NOT a security downgrade for the LAN — the raw API ports bind 0.0.0.0, but a
553
+ * direct LAN hit has a non-loopback, non-Docker-bridge peer and is rejected. We
554
+ * read ONLY the real TCP peer (request.remoteAddress), never X-Forwarded-For,
555
+ * which a caller could spoof.
556
+ */
557
+ function isLoopbackPeer(request) {
558
+ const remoteAddress = request.remoteAddress;
559
+ const raw = remoteAddress && typeof remoteAddress === "object" && "_tag" in remoteAddress ? Option.getOrElse(remoteAddress, () => "") : typeof remoteAddress === "string" ? remoteAddress : "";
560
+ if (!raw) return false;
561
+ const addr = raw.startsWith("::ffff:") ? raw.slice(7) : raw;
562
+ if (addr === "127.0.0.1" || addr === "::1") return true;
563
+ if (peerIsHostLocalDockerBridge(addr, networkInterfaces())) return true;
564
+ return runningInContainer && peerIsLocalContainerNetwork(addr, networkInterfaces());
565
+ }
566
+ function rejectUnauthorizedDashboardSessionMintRequest(request) {
567
+ if (!getInternalTokenSync()) return jsonResponse({ error: "dashboard session token not configured" }, { status: 503 });
568
+ if (!hasDashboardInternalToken(request) && !isLoopbackPeer(request)) return jsonResponse({ error: "unauthorized" }, { status: 401 });
569
+ return null;
570
+ }
571
+ function rejectUnauthorizedDashboardRequest(request) {
572
+ if (!getInternalTokenSync()) return jsonResponse({ error: "dashboard session token not configured" }, { status: 503 });
573
+ if (!hasDashboardAuth(request)) return jsonResponse({ error: "unauthorized" }, { status: 401 });
574
+ return null;
575
+ }
576
+ //#endregion
367
577
  //#region routes/jsonl-resolver.ts
578
+ init_acp_conversation_parser();
368
579
  init_codex_conversation_parser();
369
580
  init_ohmypi_conversation_parser();
370
581
  init_pi_conversation_parser();
@@ -390,6 +601,8 @@ init_conversation_service();
390
601
  * order no longer reflects time-recency. We disambiguate
391
602
  * across all listed IDs by JSONL mtime.
392
603
  * 3. runtime state — in-process mirror, populated by hooks
604
+ * 4. agents registry — the DB row's session_id recorded at spawn; survives
605
+ * janitor removal of the agent directory
393
606
  *
394
607
  * Async-only (fs/promises) because this code path runs inside the dashboard
395
608
  * server's event loop.
@@ -475,6 +688,10 @@ async function resolveClaudeSessionId(agentId, opts = {}) {
475
688
  const runtimeState = await (opts.getRuntimeStateAsync ?? ((id) => Effect.runPromise(getAgentRuntimeState(id))))(agentId);
476
689
  if (runtimeState?.claudeSessionId) return runtimeState.claudeSessionId;
477
690
  } catch {}
691
+ if (!opts.agentsDirOverride) {
692
+ const registrySessionId = getAgentStateSync(agentId)?.sessionId?.trim();
693
+ if (registrySessionId) return registrySessionId;
694
+ }
478
695
  return null;
479
696
  }
480
697
  /**
@@ -532,7 +749,7 @@ async function readRecordedState(agentId, opts) {
532
749
  * Resolve the harness for transcript routing. Reads state.json, then
533
750
  * self-corrects when the recorded value is stale.
534
751
  *
535
- * Trust an explicit non-default harness (codex / pi / ohmypi) — it was chosen
752
+ * Trust an explicit non-default harness (codex / pi / ohmypi / acp) — it was chosen
536
753
  * by resolveHarness at spawn time and is not the generic fallback. The
537
754
  * 'claude-code' default, however, goes stale in one observed case: a
538
755
  * wipe-and-respawn that changed the provider-default harness left state.json
@@ -550,8 +767,9 @@ async function readRecordedState(agentId, opts) {
550
767
  */
551
768
  async function resolveAgentHarness(agentId, opts = {}) {
552
769
  const recorded = (await readRecordedState(agentId, opts)).harness;
553
- if (recorded === "codex" || recorded === "pi" || recorded === "ohmypi") return recorded;
770
+ if (recorded === "codex" || recorded === "pi" || recorded === "ohmypi" || recorded === "acp") return recorded;
554
771
  if (await agentHasClaudeTranscript(agentId, opts)) return recorded ?? "claude-code";
772
+ if (await resolveAcpTranscriptPath(agentId, opts)) return "acp";
555
773
  if (await resolveCodexRolloutPath(agentId, opts)) return "codex";
556
774
  if (await resolvePiSessionPath(agentId, opts)) return "ohmypi";
557
775
  return recorded;
@@ -581,7 +799,7 @@ async function resolveCodexRolloutPath(agentId, opts = {}) {
581
799
  const agentDir = join(opts.agentsDirOverride ?? join(getOverdeckHome(), "agents"), agentId);
582
800
  const codexHome = join(agentDir, "codex-home");
583
801
  if (!await pathExists$1(codexHome)) return null;
584
- const { findRolloutPath, findLatestRollout } = await import("./codex-Dg7Is5yb.js");
802
+ const { findRolloutPath, findLatestRollout } = await import("./codex-GcHuUF-k.js");
585
803
  const threadId = (await readOptional(join(agentDir, "codex-thread-id")))?.trim();
586
804
  if (threadId) {
587
805
  const rollout = findRolloutPath(codexHome, threadId);
@@ -589,6 +807,11 @@ async function resolveCodexRolloutPath(agentId, opts = {}) {
589
807
  }
590
808
  return findLatestRollout(codexHome);
591
809
  }
810
+ /** Resolve the normalized transcript written by the persistent ACP host. */
811
+ async function resolveAcpTranscriptPath(agentId, opts = {}) {
812
+ const transcriptPath = join(opts.agentsDirOverride ?? join(getOverdeckHome(), "agents"), agentId, "acp-session.jsonl");
813
+ return await pathExists$1(transcriptPath) ? transcriptPath : null;
814
+ }
592
815
  /**
593
816
  * Resolve the pi/kimi session JSONL (PAN-1908). Pi writes its session transcript
594
817
  * as `<iso-ts>_<session-id>.jsonl` either in the agent dir's `sessions/` subdir
@@ -599,6 +822,7 @@ async function resolveCodexRolloutPath(agentId, opts = {}) {
599
822
  async function resolvePiSessionPath(agentId, opts = {}) {
600
823
  const agentDir = join(opts.agentsDirOverride ?? join(getOverdeckHome(), "agents"), agentId);
601
824
  const NON_TRANSCRIPT = new Set([
825
+ "acp-session.jsonl",
602
826
  "cost-events.jsonl",
603
827
  "activity.jsonl",
604
828
  "pending-events.jsonl"
@@ -637,6 +861,7 @@ async function resolveJsonlPath(agentId, workspacePath, opts = {}) {
637
861
  const behavior = behaviorForHarness(harness);
638
862
  if (behavior.transcriptKind === "codex-rollout-jsonl") return resolveCodexRolloutPath(agentId, opts);
639
863
  if (behavior.transcriptKind === "ohmypi-jsonl") return resolvePiSessionPath(agentId, opts);
864
+ if (behavior.transcriptKind === "acp-jsonl") return resolveAcpTranscriptPath(agentId, opts);
640
865
  const claudeSessionId = await resolveClaudeSessionId(agentId, opts);
641
866
  if (!claudeSessionId) {
642
867
  logTranscriptResolution(agentId, `missing-session-id:${harness ?? "unknown"}`, `failed harness=${harness ?? "unknown"} reason=no-session-id checked=session.id,sessions.json,runtime-state`, opts);
@@ -808,7 +1033,7 @@ async function getWorkAgentLifecycleStateSnapshot(agentOrIssueId) {
808
1033
  runtimeState: runtime,
809
1034
  agentStatus,
810
1035
  canStartFresh: (!hasLiveTmuxSession || hasLiveTmuxSession && isStopped) && (!requiresSessionResetBeforeFreshStart || isOrphaned),
811
- canResumeSession: !isRunning && hasResumableBackingState && (isStopped || isCrashed),
1036
+ canResumeSession: !isRunning && hasSavedSession && hasResumableBackingState && (isStopped || isCrashed),
812
1037
  canRestartWithContext: hasAgentState && hasWorkspace,
813
1038
  canResetSession: hasSavedSession && hasResumableBackingState,
814
1039
  requiresSessionResetBeforeFreshStart,
@@ -974,7 +1199,8 @@ function buildPanStartArgs(input) {
974
1199
  "--model",
975
1200
  input.model,
976
1201
  ...input.harness ? ["--harness", input.harness] : [],
977
- ...input.allowHost ? ["--host", "--yes"] : []
1202
+ ...input.allowHost ? ["--host", "--yes"] : [],
1203
+ ...input.offBook ? ["--off-book"] : []
978
1204
  ];
979
1205
  }
980
1206
  /**
@@ -1083,7 +1309,7 @@ function emitStartAgentPhase(issueId, phase, status, reason, details = {}) {
1083
1309
  });
1084
1310
  }
1085
1311
  const INTERNAL_TOKEN_HEADER = "x-overdeck-internal-token";
1086
- function constantTimeTokenEqual$1(provided, expected) {
1312
+ function constantTimeTokenEqual(provided, expected) {
1087
1313
  if (!provided) return false;
1088
1314
  const providedBuffer = Buffer.from(provided, "utf8");
1089
1315
  const expectedBuffer = Buffer.from(expected, "utf8");
@@ -1109,7 +1335,7 @@ async function validateAgentRuntimeEventAuth(request) {
1109
1335
  error: "internal token not configured"
1110
1336
  }, { status: 503 })
1111
1337
  };
1112
- if (constantTimeTokenEqual$1(getHeaderFromMap(request.headers, INTERNAL_TOKEN_HEADER), expected)) return { ok: true };
1338
+ if (constantTimeTokenEqual(getHeaderFromMap(request.headers, INTERNAL_TOKEN_HEADER), expected)) return { ok: true };
1113
1339
  return {
1114
1340
  ok: false,
1115
1341
  response: jsonResponse({
@@ -1725,7 +1951,7 @@ const getAgentOutputRoute = HttpRouter.add("GET", "/api/agents/:id/output", http
1725
1951
  } catch {}
1726
1952
  let stdout;
1727
1953
  if (isRemote && vmName) {
1728
- const { getRemoteAgentOutput } = await import("./remote-agents-CRCg1L4H.js");
1954
+ const { getRemoteAgentOutput } = await import("./remote-agents-CA3Ihlxj.js");
1729
1955
  stdout = await getRemoteAgentOutput(id, vmName, parseInt(String(lines), 10) || 100);
1730
1956
  } else stdout = await Effect.runPromise(capturePane(id, parseInt(String(lines), 10) || 100));
1731
1957
  if (!stdout || stdout.trim() === "" || stdout.trim() === "Session not found") {
@@ -1790,6 +2016,20 @@ async function buildConversationResponse(id) {
1790
2016
  streaming: false
1791
2017
  };
1792
2018
  }
2019
+ if (harness === "acp") {
2020
+ const sessionFile = await resolveAcpTranscriptPath(id);
2021
+ if (!sessionFile || !existsSync(sessionFile)) return EMPTY_CONVERSATION;
2022
+ const result = await parseAcpConversationMessages(sessionFile);
2023
+ return {
2024
+ ...result,
2025
+ messages: result.messages.map((message) => message.role === "assistant" ? {
2026
+ ...message,
2027
+ completedAt: message.completedAt ?? message.createdAt,
2028
+ streaming: false
2029
+ } : message),
2030
+ streaming: false
2031
+ };
2032
+ }
1793
2033
  let jsonlPath = null;
1794
2034
  const pinnedSessionId = await readLauncherPinnedSessionId(id);
1795
2035
  if (pinnedSessionId) {
@@ -2146,7 +2386,7 @@ async function cleanupConversationAttachments(name) {
2146
2386
  * sessions that the lifecycle poller missed. */
2147
2387
  async function cleanupOrphanedConversationAttachments() {
2148
2388
  try {
2149
- const { listConversations } = await import("./conversations-6mPANqvL.js");
2389
+ const { listConversations } = await import("./conversations-CAsJF9kh.js");
2150
2390
  const convNames = new Set(listConversations().map((c) => c.name));
2151
2391
  const root = getConversationAttachmentsRoot();
2152
2392
  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, {
@@ -2424,7 +2664,7 @@ async function stopConversationRuntime(conv, name) {
2424
2664
  function shellQuote(str) {
2425
2665
  return "'" + str.replace(/'/g, "'\"'\"'") + "'";
2426
2666
  }
2427
- const SAFE_MODEL_PATTERN = /^[a-zA-Z0-9_.:\/-]+$/;
2667
+ const SAFE_MODEL_PATTERN = MODEL_ID_PATTERN;
2428
2668
  const SAFE_EFFORT_PATTERN = /^(low|medium|high)$/;
2429
2669
  const SAFE_ISSUE_ID_PATTERN = /^[A-Z0-9]+-[0-9]+$/;
2430
2670
  const PI_CONVERSATION_SOURCE_CONTRACT = [
@@ -2436,7 +2676,7 @@ async function resolveAllowedHarness(requested, model) {
2436
2676
  if (!model) return "claude-code";
2437
2677
  return resolveHarness({
2438
2678
  model,
2439
- explicit: requested === "ohmypi" || requested === "claude-code" || requested === "codex" ? requested : void 0
2679
+ explicit: requested === "ohmypi" || requested === "claude-code" || requested === "codex" || requested === "acp" ? requested : void 0
2440
2680
  });
2441
2681
  }
2442
2682
  async function isInsideGitWorkTree(dir) {
@@ -2518,6 +2758,10 @@ function shouldUseSupervisorForConversation(harness, options = {}) {
2518
2758
  return getHarnessBehavior(harness).supportsPtySupervisor && process.env.OVERDECK_DOCKER_WORKSPACE !== "1" && process.env.PAN_DOCKER !== "1";
2519
2759
  }
2520
2760
  async function waitForConversationRuntimeReady(tmuxSession, harness, mode) {
2761
+ if (harness === "acp") {
2762
+ await waitForAcpHostReady(tmuxSession);
2763
+ return;
2764
+ }
2521
2765
  const transcriptKind = getHarnessBehavior(harness).transcriptKind;
2522
2766
  if (transcriptKind === "ohmypi-jsonl") {
2523
2767
  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.`);
@@ -2533,7 +2777,7 @@ async function handleConversationSwitchModel(name, body) {
2533
2777
  const currentHarness = conv.harness ?? "claude-code";
2534
2778
  const requestedHarness = body["harness"];
2535
2779
  let harness = currentHarness;
2536
- if (requestedHarness === "ohmypi" || requestedHarness === "pi" || requestedHarness === "claude-code" || requestedHarness === "codex") {
2780
+ if (requestedHarness === "ohmypi" || requestedHarness === "pi" || requestedHarness === "claude-code" || requestedHarness === "codex" || requestedHarness === "acp") {
2537
2781
  const requestedRuntime = requestedHarness === "pi" ? "ohmypi" : requestedHarness;
2538
2782
  if (requestedRuntime !== currentHarness) {
2539
2783
  const policyModel = model ?? conv.model ?? "";
@@ -2686,14 +2930,25 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
2686
2930
  let providerExportsStr = "";
2687
2931
  let piFields;
2688
2932
  let codexFields;
2933
+ let acpFields;
2689
2934
  let codexTransport;
2690
- if (model) {
2935
+ if (behavior.launchCommandKind === "acp-host") {
2936
+ if (!model) throw new Error("ACP conversation requires a model");
2937
+ if (!SAFE_MODEL_PATTERN.test(model)) throw new Error("Invalid model name");
2938
+ const sessionIdPath = join(getOverdeckHome(), "agents", tmuxSession, "acp-session-id");
2939
+ const resumeSessionId = resume ? await readFile(sessionIdPath, "utf-8").then((value) => value.trim() || void 0).catch(() => void 0) : void 0;
2940
+ await rm(sessionIdPath, { force: true });
2941
+ acpFields = {
2942
+ ...getAcpLauncherFields(tmuxSession, model, cwd, harnessLaunch.binaryPath, "work"),
2943
+ resumeSessionId
2944
+ };
2945
+ runtimeCommand = "acp-host";
2946
+ } else if (model) {
2691
2947
  if (!SAFE_MODEL_PATTERN.test(model)) throw new Error("Invalid model name");
2692
2948
  runtimeCommand = await getAgentRuntimeBaseCommand(model, void 0, void 0, harness);
2693
2949
  const mode = resolvePermissionModeSync();
2694
2950
  if (!runtimeCommand.includes("--permission-mode")) runtimeCommand = `${runtimeCommand} --permission-mode ${mode === "auto" ? "auto" : BYPASS_PERMISSION_MODE}`;
2695
2951
  providerExportsStr = (await getProviderExportsForModel(model)).trim();
2696
- await getProviderEnvForModel(model);
2697
2952
  if (behavior.transcriptKind === "ohmypi-jsonl") {
2698
2953
  if (getProviderForModelSync(model).name === "openai") {
2699
2954
  const auth = await getOhmypiCodexAuthStatus({ refreshIfExpired: true });
@@ -2725,7 +2980,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
2725
2980
  const codexApprovalPolicy = codexPermMode === "full-access" ? "never" : "on-request";
2726
2981
  const codexSandboxMode = codexPermMode === "full-access" ? "danger-full-access" : codexPermMode === "read-only" ? "read-only" : "workspace-write";
2727
2982
  const codexApprovalsReviewer = codexPermMode === "auto-review" ? "auto_review" : void 0;
2728
- const { initCodexHome, extractThreadIdFromRollout } = await import("./codex-Dg7Is5yb.js");
2983
+ const { initCodexHome, extractThreadIdFromRollout } = await import("./codex-GcHuUF-k.js");
2729
2984
  initCodexHome(codexHome, {
2730
2985
  trustedDir: cwd,
2731
2986
  approvalPolicy: codexApprovalPolicy,
@@ -2755,7 +3010,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
2755
3010
  await writePtyToken(tmuxSession);
2756
3011
  }
2757
3012
  let channelsBridgeMcpConfig;
2758
- 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") {
3013
+ if (!piFields && !codexFields && !acpFields && !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") {
2759
3014
  channelsBridgeMcpConfig = join(stateDir, "agent-mcp.json");
2760
3015
  writeBridgeTokenSync(tmuxSession);
2761
3016
  await writeChannelsBridgeMcpConfig(channelsBridgeMcpConfig, tmuxSession);
@@ -2769,19 +3024,19 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
2769
3024
  unsetProviderEnv: true,
2770
3025
  overdeckEnv: {
2771
3026
  ...issueId ? { issueId } : {},
2772
- ...piFields || codexFields || useSupervisor ? { agentId: tmuxSession } : {}
3027
+ ...piFields || codexFields || acpFields || useSupervisor ? { agentId: tmuxSession } : {}
2773
3028
  },
2774
3029
  extraEnvExports: [harnessLaunch.pathExport, `export OVERDECK_DASHBOARD_URL="http://127.0.0.1:${process.env["API_PORT"] ?? process.env["PORT"] ?? "3011"}"`],
2775
3030
  providerExports: providerExportsStr || void 0,
2776
3031
  trapHup: true,
2777
3032
  baseCommand: runtimeCommand,
2778
- appendSystemPromptFiles: piFields ? await piConversationSystemPromptFiles(cwd) : codexFields ? [] : await claudeConversationSystemPromptFiles(cwd),
3033
+ appendSystemPromptFiles: piFields ? await piConversationSystemPromptFiles(cwd) : codexFields || acpFields ? [] : await claudeConversationSystemPromptFiles(cwd),
2779
3034
  model: launcherModel,
2780
- ...piFields ?? codexFields ?? {
3035
+ ...piFields ?? codexFields ?? acpFields ?? {
2781
3036
  resumeSessionId: resume ? claudeSessionId : void 0,
2782
3037
  sessionId: resume ? void 0 : claudeSessionId
2783
3038
  },
2784
- extraArgs: !piFields && effort ? `--effort "${effort}"` : void 0,
3039
+ extraArgs: !piFields && !acpFields && effort ? `--effort "${effort}"` : void 0,
2785
3040
  keepAlive: true,
2786
3041
  fileMode: 448,
2787
3042
  channelsBridgeMcpConfig,
@@ -2794,7 +3049,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
2794
3049
  } catch {}
2795
3050
  console.log(`[claude-invoke] purpose=conversation-session | model=${model || "default"} | source=conversations.ts:spawnConversationSession | session=${tmuxSession} | resume=${resume} | command="${runtimeCommand}"`);
2796
3051
  try {
2797
- const { preTrustDirectory } = await import("./workspace-manager-ZTdJAy9M.js");
3052
+ const { preTrustDirectory } = await import("./workspace-manager-CWT55qeI.js");
2798
3053
  preTrustDirectory(cwd);
2799
3054
  } catch {}
2800
3055
  try {
@@ -2811,7 +3066,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
2811
3066
  const codexHomeDir = codexFields.codexHome;
2812
3067
  (async () => {
2813
3068
  try {
2814
- const { waitForCodexRollout, extractThreadIdFromRollout, writeThreadId } = await import("./codex-Dg7Is5yb.js");
3069
+ const { waitForCodexRollout, extractThreadIdFromRollout, writeThreadId } = await import("./codex-GcHuUF-k.js");
2815
3070
  const rollout = await waitForCodexRollout(codexHomeDir, 12e4);
2816
3071
  if (rollout) {
2817
3072
  const threadId = extractThreadIdFromRollout(rollout);
@@ -2887,10 +3142,14 @@ async function handleConversationCreate(body, deps) {
2887
3142
  await spawnConversationSession(tmuxSession, cwd, claudeSessionId, model, effort, issueId, false, harness);
2888
3143
  console.log(`[conversations] tmux session ${tmuxSession} spawned, sessionId: ${claudeSessionId}`);
2889
3144
  await waitForConversationRuntimeReady(tmuxSession, harness, "spawn");
2890
- if (message) await deliverAgentMessage(tmuxSession, message, "conversation-message", resolveConversationDeliveryMethod(conv));
3145
+ if (message) {
3146
+ const delivery = await deliverAgentMessage(tmuxSession, message, "conversation-message", resolveConversationDeliveryMethod(conv));
3147
+ if (harness === "acp" && !delivery.ok) throw new Error(`ACP initial prompt did not land: ${delivery.failure ?? "unknown failure"}`);
3148
+ }
2891
3149
  } catch (spawnErr) {
2892
3150
  const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
2893
3151
  console.error(`[conversations] background spawn failed for ${tmuxSession}: ${msg}`);
3152
+ if (harness === "acp") await stopConversationRuntime(conv, name);
2894
3153
  updateSpawnError(name, msg);
2895
3154
  getEventStore().emitOnly({
2896
3155
  type: "conversation.created",
@@ -2976,6 +3235,9 @@ async function handleConversationResume(name, body, deps) {
2976
3235
  reattached: false,
2977
3236
  sessionAlive: true
2978
3237
  });
3238
+ } catch (error) {
3239
+ if (harness === "acp") await stopConversationRuntime(conv, name);
3240
+ throw error;
2979
3241
  } finally {
2980
3242
  respawn.done();
2981
3243
  }
@@ -3010,13 +3272,16 @@ async function handleConversationRestartAll(deps) {
3010
3272
  const results = [];
3011
3273
  for (const conv of convs) {
3012
3274
  const respawn = markRespawnPending(conv.tmuxSession);
3275
+ let attemptedHarness = conv.harness ?? "claude-code";
3013
3276
  try {
3014
3277
  await Effect.runPromise(killSession(conv.tmuxSession).pipe(Effect.catch(() => Effect.succeed(void 0))));
3015
3278
  const oldSessionId = conv.claudeSessionId;
3016
3279
  const sessionFileForResume = await deps.resolveSessionFile(conv);
3017
3280
  const canResume = !!oldSessionId && !!sessionFileForResume && existsSync(sessionFileForResume);
3018
3281
  const harness = await resolveAllowedHarness(conv.harness, conv.model);
3282
+ attemptedHarness = harness;
3019
3283
  await spawnConversationSession(conv.tmuxSession, conv.cwd, oldSessionId ?? randomUUID$1(), conv.model ?? void 0, conv.effort ?? void 0, conv.issueId ?? void 0, canResume, harness);
3284
+ if (harness === "acp") await waitForConversationRuntimeReady(conv.tmuxSession, harness, "respawn");
3020
3285
  setConversationHarness(conv.name, harness);
3021
3286
  markConversationActive(conv.name);
3022
3287
  results.push({
@@ -3027,6 +3292,7 @@ async function handleConversationRestartAll(deps) {
3027
3292
  } catch (err) {
3028
3293
  const msg = err instanceof Error ? err.message : String(err);
3029
3294
  console.error(`[conversations] Failed to restart ${conv.name}:`, msg);
3295
+ if (attemptedHarness === "acp") await stopConversationRuntime(conv, conv.name);
3030
3296
  results.push({
3031
3297
  name: conv.name,
3032
3298
  model: conv.model,
@@ -3230,6 +3496,7 @@ function pickDeliverAs(bodyDeliverAs) {
3230
3496
  }
3231
3497
  function resolveConversationDeliveryMethod(conv) {
3232
3498
  const harness = conv.harness ?? "claude-code";
3499
+ if (harness === "acp") return "auto";
3233
3500
  if (isPiControlChannelHarness(harness)) return "auto";
3234
3501
  if (harness === "codex" && loadConfigSync().config.codex?.transport !== "tui") return "auto";
3235
3502
  return conv.deliveryMethod ?? (getHarnessBehavior(harness).deliveryKind === "rpc-fifo" ? "tmux" : "auto");
@@ -3690,14 +3957,14 @@ const postInternalAgentPermissionRequestRoute = HttpRouter.add("POST", "/api/int
3690
3957
  error: "missing agent id"
3691
3958
  }, { status: 400 });
3692
3959
  const request = yield* HttpServerRequest.HttpServerRequest;
3693
- const { INTERNAL_TOKEN_HEADER, getInternalTokenSync } = yield* Effect.promise(() => import("./internal-token-DXdfprGr.js"));
3960
+ const { INTERNAL_TOKEN_HEADER, getInternalTokenSync } = yield* Effect.promise(() => import("./internal-token-BrcU6qfe.js"));
3694
3961
  const expected = getInternalTokenSync();
3695
3962
  if (!expected) return jsonResponse({
3696
3963
  ok: false,
3697
3964
  error: "internal token not configured"
3698
3965
  }, { status: 503 });
3699
3966
  const rawHeader = request.headers[INTERNAL_TOKEN_HEADER];
3700
- if (!constantTimeTokenEqual$1(Array.isArray(rawHeader) ? rawHeader[0] : rawHeader, expected)) return jsonResponse({
3967
+ if (!constantTimeTokenEqual(Array.isArray(rawHeader) ? rawHeader[0] : rawHeader, expected)) return jsonResponse({
3701
3968
  ok: false,
3702
3969
  error: "forbidden"
3703
3970
  }, { status: 403 });
@@ -3957,7 +4224,7 @@ const getAgentHealthHistoryRoute = HttpRouter.add("GET", "/api/agents/:id/health
3957
4224
  const request = yield* HttpServerRequest.HttpServerRequest;
3958
4225
  const urlOpt = HttpServerRequest.toURL(request);
3959
4226
  const hours = Option.isSome(urlOpt) ? urlOpt.value.searchParams.get("hours") ?? "24" : "24";
3960
- const { getHealthHistory } = yield* Effect.promise(() => import("./health-events-CpfvuVmm.js"));
4227
+ const { getHealthHistory } = yield* Effect.promise(() => import("./health-events-BDOHby5Q.js"));
3961
4228
  const endTime = /* @__PURE__ */ new Date();
3962
4229
  const startTime = /* @__PURE__ */ new Date(endTime.getTime() - parseInt(hours) * 60 * 60 * 1e3);
3963
4230
  const events = getHealthHistory(id, startTime.toISOString(), endTime.toISOString());
@@ -3998,7 +4265,7 @@ function emitAgentRuntimeEvent(id, body, timestamp) {
3998
4265
  detail: String(decoded.failure)
3999
4266
  }, { status: 400 })
4000
4267
  };
4001
- const { AgentStateService } = yield* Effect.promise(() => import("./agent-state-service-CnzFKSAQ.js"));
4268
+ const { AgentStateService } = yield* Effect.promise(() => import("./agent-state-service-D5UGKIJL.js"));
4002
4269
  yield* (yield* AgentStateService).emit(decoded.success);
4003
4270
  return {
4004
4271
  ok: true,
@@ -4080,7 +4347,7 @@ const getAgentRuntimeRoute = HttpRouter.add("GET", "/api/agents/:id/runtime", ht
4080
4347
  success: false,
4081
4348
  error: "missing agent id"
4082
4349
  }, { status: 400 });
4083
- const { AgentStateService } = yield* Effect.promise(() => import("./agent-state-service-CnzFKSAQ.js"));
4350
+ const { AgentStateService } = yield* Effect.promise(() => import("./agent-state-service-D5UGKIJL.js"));
4084
4351
  const snapshot = yield* (yield* AgentStateService).get(id);
4085
4352
  if (!snapshot) return jsonResponse({
4086
4353
  success: false,
@@ -4265,8 +4532,8 @@ function createAgentStopHandler(lifecycleEvent) {
4265
4532
  yield* stopAgent(id);
4266
4533
  if (stateBeforeStop?.issueId) yield* Effect.promise(async () => {
4267
4534
  try {
4268
- const { resolveProjectFromIssueSync } = await import("./projects-9SkRpES9.js");
4269
- const { findWorkspacePath } = await import("./archive-planning-zkJb3BeM.js");
4535
+ const { resolveProjectFromIssueSync } = await import("./projects-vjjcmiN8.js");
4536
+ const { findWorkspacePath } = await import("./archive-planning-BZDgzoEj.js");
4270
4537
  const issueLower = stateBeforeStop.issueId.toLowerCase();
4271
4538
  const workspacePath = findWorkspacePath(resolveProjectFromIssueSync(stateBeforeStop.issueId)?.projectPath ?? process.cwd(), issueLower);
4272
4539
  if (workspacePath) {
@@ -4402,9 +4669,18 @@ const postAgentUnpauseRoute = HttpRouter.add("POST", "/api/agents/:id/unpause",
4402
4669
  payload: buildAgentControlEventPayload(updatedState, toAgentStatusPayload(stateBeforeUnpause.status), hasLiveTmuxSession)
4403
4670
  });
4404
4671
  invalidateAgentsCache();
4672
+ let resumeTriggered = false;
4673
+ if ((yield* getWorkAgentLifecycleState(id)).canResumeSession && updatedState.troubled !== true) {
4674
+ resumeTriggered = true;
4675
+ yield* Effect.promise(() => appendAgentLifecycleLog(id, "agent.unpause_immediate_resume_triggered"));
4676
+ import("./resume-BFv1PGpA.js").then(({ resumeAgent }) => resumeAgent(id)).then((result) => {
4677
+ if (!result.success) console.warn(`[agents] immediate resume after unpause failed for ${id}: ${result.error}`);
4678
+ }).catch((err) => console.warn(`[agents] immediate resume after unpause errored for ${id}:`, err));
4679
+ }
4405
4680
  return jsonResponse({
4406
4681
  success: true,
4407
- agent: updatedState
4682
+ agent: updatedState,
4683
+ resumeTriggered
4408
4684
  });
4409
4685
  })));
4410
4686
  const postAgentUntroubledRoute = HttpRouter.add("POST", "/api/agents/:id/untroubled", httpHandler(Effect.gen(function* () {
@@ -4442,6 +4718,7 @@ const postAgentUntroubledRoute = HttpRouter.add("POST", "/api/agents/:id/untroub
4442
4718
  init_config_yaml();
4443
4719
  init_agents$1();
4444
4720
  init_harness_policy();
4721
+ init_model_validation();
4445
4722
  init_operator_interventions();
4446
4723
  init_projects();
4447
4724
  init_tmux();
@@ -5090,7 +5367,6 @@ const postAgentsRestartWithConfigRoute = HttpRouter.add("POST", "/api/agents/res
5090
5367
  })));
5091
5368
  //#endregion
5092
5369
  //#region routes/agents/control.ts
5093
- init_config();
5094
5370
  init_jsonl_parser();
5095
5371
  init_model_validation();
5096
5372
  init_paths();
@@ -5244,35 +5520,351 @@ const postAgentSwitchModelRoute = HttpRouter.add("POST", "/api/agents/:id/switch
5244
5520
  return jsonResponse({ error: `Agent ${(yield* HttpRouter.params)["id"] ?? ""} model is locked once the agent is spawned` }, { status: 409 });
5245
5521
  })));
5246
5522
  //#endregion
5247
- //#region ../../lib/xbrief/auto-synthesize.ts
5248
- init_state_read_home();
5249
- init_state_plane();
5250
- init_types();
5251
- init_codex_auth();
5252
- init_state_home();
5253
- init_io();
5254
- function cleanMarkdownLine(line) {
5255
- return line.replace(/^[-*+]\s+\[[ xX]\]\s+/, "").replace(/^[-*+]\s+/, "").replace(/^#+\s+/, "").replace(/`([^`]+)`/g, "$1").trim();
5256
- }
5257
- function extractAcceptanceCriteriaFromIssue(title, body) {
5258
- const text = body?.trim() ?? "";
5259
- if (!text) return [`Implement ${title}`];
5260
- const lines = text.split(/\r?\n/);
5261
- const headingIndex = lines.findIndex((line) => /^#{1,6}\s+.*acceptance(\s+criteria)?\b/i.test(line) || /^\s*\*{0,2}acceptance criteria\*{0,2}:?\s*$/i.test(line));
5262
- if (headingIndex >= 0) {
5263
- const sectionEndIndex = lines.findIndex((line, idx) => idx > headingIndex && /^#+\s+/.test(line));
5264
- const endIndex = sectionEndIndex >= 0 ? sectionEndIndex : lines.length;
5265
- const sectionLines = lines.slice(headingIndex + 1, endIndex);
5266
- const checklist = sectionLines.filter((line) => /^\s*[-*+]\s+\[[ xX]\]\s+/.test(line)).map(cleanMarkdownLine).filter(Boolean);
5267
- if (checklist.length > 0) return checklist;
5268
- const bullets = sectionLines.filter((line) => /^\s*[-*+]\s+/.test(line)).map(cleanMarkdownLine).filter(Boolean).slice(0, 8);
5269
- if (bullets.length > 0) return bullets;
5523
+ //#region ../../lib/orders/eligibility.ts
5524
+ function evaluateOrderDispatchEligibility(input) {
5525
+ const issueId = input.issueId.toUpperCase();
5526
+ const item = input.book.items.find((candidate) => candidate.issue.toUpperCase() === issueId);
5527
+ if (!item) {
5528
+ const overrideUsed = input.offBook === true;
5529
+ return {
5530
+ eligible: overrideUsed,
5531
+ overrideUsed,
5532
+ ...overrideUsed ? {} : {
5533
+ code: "off-book",
5534
+ message: `Issue ${issueId} is not in active order book ${input.book.id}; work-agent dispatch is blocked. Retry with --off-book only for an intentional exception.`
5535
+ },
5536
+ conditions: [{
5537
+ key: "book-membership",
5538
+ met: overrideUsed,
5539
+ detail: overrideUsed ? `Issue ${issueId} is outside the book and the operator supplied --off-book.` : `Issue ${issueId} is not a member of ${input.book.id}.`
5540
+ }]
5541
+ };
5270
5542
  }
5271
- return [`Issue's stated fix implemented with tests`];
5272
- }
5273
- function synthesizeMinimalXBrief(issue) {
5274
- const issueId = issue.issueId.toUpperCase();
5275
- const issueLabel = issueId.toLowerCase();
5543
+ const terminalByIssue = new Map(input.progress.items.map((progress) => [progress.issue.toUpperCase(), progress.terminal]));
5544
+ for (const [issue, terminal] of input.prerequisiteTerminal ?? []) if (!terminalByIssue.has(issue.toUpperCase())) terminalByIssue.set(issue.toUpperCase(), terminal);
5545
+ const unmetPrereq = item.prereqs.find((prereq) => terminalByIssue.get(prereq.toUpperCase()) !== true);
5546
+ const prereqsMet = unmetPrereq === void 0;
5547
+ const otherInFlight = input.book.items.filter((candidate) => candidate.issue.toUpperCase() !== issueId && input.inFlightIssues.has(candidate.issue.toUpperCase()));
5548
+ const laneBBlocker = item.lane === "B" ? otherInFlight.find((candidate) => candidate.lane === "B") : void 0;
5549
+ const laneAInFlight = otherInFlight.filter((candidate) => candidate.lane === "A").length;
5550
+ const laneSlotFree = item.lane === "B" ? laneBBlocker === void 0 : laneAInFlight < input.book.settings.laneAConcurrency;
5551
+ const postureOpen = input.book.settings.posture === "open";
5552
+ const prdReverified = !item.reVerify;
5553
+ const conditions = [
5554
+ {
5555
+ key: "book-membership",
5556
+ met: true,
5557
+ detail: `${issueId} is a member of ${input.book.id}.`
5558
+ },
5559
+ {
5560
+ key: "pickup-posture",
5561
+ met: postureOpen,
5562
+ detail: postureOpen ? "Order-book pickup posture is OPEN." : "Order-book pickup posture is DRAIN."
5563
+ },
5564
+ {
5565
+ key: "lane-slot",
5566
+ met: laneSlotFree,
5567
+ detail: item.lane === "B" ? laneBBlocker ? `Lane B is occupied by ${laneBBlocker.issue}.` : "Lane B has no issue in flight." : `${laneAInFlight}/${input.book.settings.laneAConcurrency} Lane A slots are in flight.`
5568
+ },
5569
+ {
5570
+ key: "prerequisites",
5571
+ met: prereqsMet,
5572
+ detail: unmetPrereq ? `Prerequisite ${unmetPrereq.toUpperCase()} is not terminal.` : "Every prerequisite is landed or parked."
5573
+ },
5574
+ {
5575
+ key: "prd-reverified",
5576
+ met: prdReverified,
5577
+ detail: prdReverified ? "No PRD re-verification is pending." : `${issueId} requires PRD re-verification before dispatch.`
5578
+ }
5579
+ ];
5580
+ if (!postureOpen) return {
5581
+ eligible: false,
5582
+ overrideUsed: false,
5583
+ code: "book-draining",
5584
+ message: `Issue ${issueId} cannot start because order book ${input.book.id} is in DRAIN posture; no new book items may dispatch.`,
5585
+ conditions
5586
+ };
5587
+ if (unmetPrereq) return {
5588
+ eligible: false,
5589
+ overrideUsed: false,
5590
+ code: "prerequisite-unmet",
5591
+ message: `Issue ${issueId} cannot start because prerequisite ${unmetPrereq.toUpperCase()} has not landed or been parked.`,
5592
+ conditions
5593
+ };
5594
+ if (!prdReverified) return {
5595
+ eligible: false,
5596
+ overrideUsed: false,
5597
+ code: "reverify-required",
5598
+ message: `Issue ${issueId} cannot start until its PRD has been re-verified against current main.`,
5599
+ conditions
5600
+ };
5601
+ if (laneBBlocker) return {
5602
+ eligible: false,
5603
+ overrideUsed: false,
5604
+ code: "lane-b-busy",
5605
+ message: `Issue ${issueId} cannot start in Lane B because ${laneBBlocker.issue} is still in flight; Lane B allows one active issue at a time.`,
5606
+ conditions
5607
+ };
5608
+ if (item.lane === "A" && !laneSlotFree) return {
5609
+ eligible: false,
5610
+ overrideUsed: false,
5611
+ code: "lane-a-full",
5612
+ message: `Issue ${issueId} cannot start in Lane A because ${laneAInFlight} issues are already in flight and laneAConcurrency is ${input.book.settings.laneAConcurrency}.`,
5613
+ conditions
5614
+ };
5615
+ return {
5616
+ eligible: true,
5617
+ overrideUsed: false,
5618
+ conditions
5619
+ };
5620
+ }
5621
+ //#endregion
5622
+ //#region ../../lib/orders/dispatch-gate.ts
5623
+ init_review_status();
5624
+ init_projects();
5625
+ function stateRootFor(projectRoot) {
5626
+ const project = findProjectByPathSync(projectRoot);
5627
+ if (!project) throw new Error(`No configured project contains ${projectRoot}`);
5628
+ return resolveStateReadHomeSync(project).root;
5629
+ }
5630
+ function defaultInFlightIssues(_bookId, issueIds) {
5631
+ const inFlight = /* @__PURE__ */ new Set();
5632
+ for (const issueId of issueIds) {
5633
+ const lifecycle = getWorkAgentLifecycleStateSync(issueId);
5634
+ const review = getReviewStatusSync(issueId);
5635
+ if (lifecycle.isRunning || review !== null && review.reviewStatus !== "pending") inFlight.add(issueId.toUpperCase());
5636
+ }
5637
+ return inFlight;
5638
+ }
5639
+ const booklessDecision = {
5640
+ eligible: true,
5641
+ overrideUsed: false,
5642
+ conditions: []
5643
+ };
5644
+ async function checkActiveOrderDispatch(projectRoot, issueId, options = {}, deps = {}) {
5645
+ const runId = await (deps.resolveRunId ?? resolveLiveFlywheelRunId)();
5646
+ if (!runId) return {
5647
+ ordersBound: false,
5648
+ decision: booklessDecision
5649
+ };
5650
+ const launch = await (deps.readLaunch ?? readFlywheelLaunchMetadata)(runId);
5651
+ const bookId = launch?.orders?.bookId;
5652
+ if (!bookId) return {
5653
+ ordersBound: false,
5654
+ runId,
5655
+ decision: booklessDecision
5656
+ };
5657
+ const stateRoot = (deps.stateRoot ?? stateRootFor)(launch?.workspace ?? projectRoot);
5658
+ const book = (deps.getOrderBook ?? getBook)(stateRoot, bookId);
5659
+ if (!book) throw new Error(`Active Flywheel run ${runId} references missing order book ${bookId}`);
5660
+ const progress = (deps.computeProgress ?? computeBookProgress)(book);
5661
+ const prerequisiteIds = [...new Set(book.items.flatMap((item) => item.prereqs.map((prereq) => prereq.toUpperCase())))];
5662
+ const prerequisiteState = (deps.issueLookup ?? liveOrderIssueLookup)(prerequisiteIds);
5663
+ const prerequisiteTerminal = new Map(prerequisiteIds.map((prereq) => {
5664
+ const state = prerequisiteState.get(prereq);
5665
+ return [prereq, state ? !state.open || state.parked : false];
5666
+ }));
5667
+ const inFlightIssues = new Set((deps.inFlightIssues ?? defaultInFlightIssues)(book.id, book.items.filter((item) => !progress.items.find((entry) => entry.issue === item.issue)?.terminal).map((item) => item.issue)));
5668
+ for (const reserved of deps.reservedIssues ?? []) inFlightIssues.add(reserved.toUpperCase());
5669
+ return {
5670
+ ordersBound: true,
5671
+ runId,
5672
+ bookId,
5673
+ decision: evaluateOrderDispatchEligibility({
5674
+ book,
5675
+ progress,
5676
+ issueId,
5677
+ inFlightIssues,
5678
+ prerequisiteTerminal,
5679
+ offBook: options.offBook
5680
+ })
5681
+ };
5682
+ }
5683
+ async function recordOffBookOverride(runId, bookId, issueId, actor = process.env["OVERDECK_AGENT_ID"] ?? "operator") {
5684
+ const runDir = getFlywheelRunDir(runId);
5685
+ const path = join(runDir, "orders-overrides.jsonl");
5686
+ await mkdir(runDir, { recursive: true });
5687
+ await appendFile(path, `${JSON.stringify({
5688
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
5689
+ runId,
5690
+ bookId,
5691
+ issueId: issueId.toUpperCase(),
5692
+ actor,
5693
+ override: "off-book"
5694
+ })}\n`, "utf8");
5695
+ return path;
5696
+ }
5697
+ //#endregion
5698
+ //#region ../../lib/orders/dispatch-reservation.ts
5699
+ var OrderDispatchReservationError = class extends Error {
5700
+ constructor(check) {
5701
+ super(check.decision.message ?? "Order-book dispatch is blocked.");
5702
+ this.check = check;
5703
+ this.name = "OrderDispatchReservationError";
5704
+ }
5705
+ };
5706
+ const DEFAULT_STALE_MS = 900 * 1e3;
5707
+ const processLocks = /* @__PURE__ */ new Map();
5708
+ let reservationSequence = 0;
5709
+ async function withProcessLock(key, action) {
5710
+ const previous = processLocks.get(key) ?? Promise.resolve();
5711
+ let release;
5712
+ const current = new Promise((resolve) => {
5713
+ release = resolve;
5714
+ });
5715
+ const tail = previous.then(() => current);
5716
+ processLocks.set(key, tail);
5717
+ await previous;
5718
+ try {
5719
+ return await action();
5720
+ } finally {
5721
+ release();
5722
+ if (processLocks.get(key) === tail) processLocks.delete(key);
5723
+ }
5724
+ }
5725
+ function paths(root) {
5726
+ return {
5727
+ state: join(root, "orders-dispatch-reservations.json"),
5728
+ temp: join(root, `orders-dispatch-reservations.${process.pid}.tmp`),
5729
+ lock: join(root, "orders-dispatch-reservations.lock")
5730
+ };
5731
+ }
5732
+ async function acquireFileLock(path, staleMs, now) {
5733
+ try {
5734
+ await mkdir(path);
5735
+ return;
5736
+ } catch (error) {
5737
+ if ((typeof error === "object" && error !== null && "code" in error ? error.code : void 0) !== "EEXIST") throw error;
5738
+ }
5739
+ if (await stat$1(path).then((value) => now.getTime() - value.mtimeMs).catch(() => 0) <= staleMs) throw new Error("Another order-book dispatch admission is in progress; retry after it finishes.");
5740
+ await rm(path, {
5741
+ recursive: true,
5742
+ force: true
5743
+ });
5744
+ await mkdir(path);
5745
+ }
5746
+ async function readReservations(path) {
5747
+ try {
5748
+ const parsed = JSON.parse(await readFile(path, "utf8"));
5749
+ return Array.isArray(parsed) ? parsed : [];
5750
+ } catch (error) {
5751
+ if ((typeof error === "object" && error !== null && "code" in error ? error.code : void 0) === "ENOENT") return [];
5752
+ throw error;
5753
+ }
5754
+ }
5755
+ async function writeReservations(path, tempPath, reservations) {
5756
+ await writeFile(tempPath, `${JSON.stringify(reservations, null, 2)}\n`, {
5757
+ encoding: "utf8",
5758
+ mode: 384
5759
+ });
5760
+ await rename(tempPath, path);
5761
+ }
5762
+ function freshReservations(reservations, now, staleMs) {
5763
+ return reservations.filter((reservation) => {
5764
+ const reservedAt = Date.parse(reservation.reservedAt);
5765
+ return Number.isFinite(reservedAt) && now.getTime() - reservedAt <= staleMs;
5766
+ });
5767
+ }
5768
+ async function reserveActiveOrderDispatch(projectRoot, issueId, options = {}, deps = {}) {
5769
+ const initial = await checkActiveOrderDispatch(projectRoot, issueId, options, deps);
5770
+ if (!initial.ordersBound || !initial.runId || !initial.bookId || !initial.decision.eligible) return {
5771
+ check: initial,
5772
+ release: async () => {}
5773
+ };
5774
+ const root = (deps.reservationRoot ?? getFlywheelRunDir)(initial.runId);
5775
+ await mkdir(root, { recursive: true });
5776
+ const reservationPaths = paths(root);
5777
+ const staleMs = deps.staleMs ?? DEFAULT_STALE_MS;
5778
+ const now = (deps.now ?? (() => /* @__PURE__ */ new Date()))();
5779
+ const reservationId = `${process.pid}-${now.getTime()}-${reservationSequence++}`;
5780
+ let check = initial;
5781
+ await withProcessLock(reservationPaths.lock, async () => {
5782
+ await acquireFileLock(reservationPaths.lock, staleMs, now);
5783
+ try {
5784
+ const current = freshReservations(await readReservations(reservationPaths.state), now, staleMs);
5785
+ check = await checkActiveOrderDispatch(projectRoot, issueId, options, {
5786
+ ...deps,
5787
+ reservedIssues: new Set(current.filter((reservation) => reservation.bookId === initial.bookId).map((reservation) => reservation.issueId))
5788
+ });
5789
+ if (!check.decision.eligible) return;
5790
+ current.push({
5791
+ id: reservationId,
5792
+ bookId: initial.bookId,
5793
+ issueId: issueId.toUpperCase(),
5794
+ reservedAt: now.toISOString()
5795
+ });
5796
+ await writeReservations(reservationPaths.state, reservationPaths.temp, current);
5797
+ } finally {
5798
+ await rm(reservationPaths.lock, {
5799
+ recursive: true,
5800
+ force: true
5801
+ });
5802
+ }
5803
+ });
5804
+ if (!check.decision.eligible) return {
5805
+ check,
5806
+ release: async () => {}
5807
+ };
5808
+ if (options.recordOverride && check.decision.overrideUsed) await (deps.recordOverride ?? recordOffBookOverride)(initial.runId, initial.bookId, issueId);
5809
+ let released = false;
5810
+ return {
5811
+ check,
5812
+ release: async () => {
5813
+ if (released) return;
5814
+ released = true;
5815
+ const releasedAt = (deps.now ?? (() => /* @__PURE__ */ new Date()))();
5816
+ await withProcessLock(reservationPaths.lock, async () => {
5817
+ await acquireFileLock(reservationPaths.lock, staleMs, releasedAt);
5818
+ try {
5819
+ const current = freshReservations(await readReservations(reservationPaths.state), releasedAt, staleMs).filter((reservation) => reservation.id !== reservationId);
5820
+ await writeReservations(reservationPaths.state, reservationPaths.temp, current);
5821
+ } finally {
5822
+ await rm(reservationPaths.lock, {
5823
+ recursive: true,
5824
+ force: true
5825
+ });
5826
+ }
5827
+ });
5828
+ }
5829
+ };
5830
+ }
5831
+ async function withActiveOrderDispatchReservation(projectRoot, issueId, options, action, deps = {}) {
5832
+ const reservation = await reserveActiveOrderDispatch(projectRoot, issueId, options, deps);
5833
+ if (!reservation.check.decision.eligible) return { check: reservation.check };
5834
+ try {
5835
+ return {
5836
+ check: reservation.check,
5837
+ result: await action()
5838
+ };
5839
+ } finally {
5840
+ await reservation.release();
5841
+ }
5842
+ }
5843
+ //#endregion
5844
+ //#region ../../lib/xbrief/auto-synthesize.ts
5845
+ init_io();
5846
+ function cleanMarkdownLine(line) {
5847
+ return line.replace(/^[-*+]\s+\[[ xX]\]\s+/, "").replace(/^[-*+]\s+/, "").replace(/^#+\s+/, "").replace(/`([^`]+)`/g, "$1").trim();
5848
+ }
5849
+ function extractAcceptanceCriteriaFromIssue(title, body) {
5850
+ const text = body?.trim() ?? "";
5851
+ if (!text) return [`Implement ${title}`];
5852
+ const lines = text.split(/\r?\n/);
5853
+ const headingIndex = lines.findIndex((line) => /^#{1,6}\s+.*acceptance(\s+criteria)?\b/i.test(line) || /^\s*\*{0,2}acceptance criteria\*{0,2}:?\s*$/i.test(line));
5854
+ if (headingIndex >= 0) {
5855
+ const sectionEndIndex = lines.findIndex((line, idx) => idx > headingIndex && /^#+\s+/.test(line));
5856
+ const endIndex = sectionEndIndex >= 0 ? sectionEndIndex : lines.length;
5857
+ const sectionLines = lines.slice(headingIndex + 1, endIndex);
5858
+ const checklist = sectionLines.filter((line) => /^\s*[-*+]\s+\[[ xX]\]\s+/.test(line)).map(cleanMarkdownLine).filter(Boolean);
5859
+ if (checklist.length > 0) return checklist;
5860
+ const bullets = sectionLines.filter((line) => /^\s*[-*+]\s+/.test(line)).map(cleanMarkdownLine).filter(Boolean).slice(0, 8);
5861
+ if (bullets.length > 0) return bullets;
5862
+ }
5863
+ return [`Issue's stated fix implemented with tests`];
5864
+ }
5865
+ function synthesizeMinimalXBrief(issue) {
5866
+ const issueId = issue.issueId.toUpperCase();
5867
+ const issueLabel = issueId.toLowerCase();
5276
5868
  const now = (/* @__PURE__ */ new Date()).toISOString();
5277
5869
  const items = extractAcceptanceCriteriaFromIssue(issue.title, issue.body).map((criterion, index) => ({
5278
5870
  id: `auto-start.ac${index + 1}`,
@@ -5365,222 +5957,21 @@ const writeAutoStartXBrief = (projectRoot, workspacePath, issue) => Effect.tryPr
5365
5957
  })
5366
5958
  });
5367
5959
  //#endregion
5368
- //#region routes/dashboard-auth.ts
5369
- init_issue_lifecycle();
5370
- init_internal_token();
5371
- const DASHBOARD_SESSION_COOKIE = "overdeck_session";
5372
- const DASHBOARD_CSRF_HEADER = "x-overdeck-csrf-token";
5373
- const DASHBOARD_SESSION_MAX_AGE_SECONDS = 3600 * 24 * 30;
5374
- let browserSessionToken;
5375
- let browserCsrfToken;
5376
- function getDashboardSessionToken() {
5377
- if (browserSessionToken) return browserSessionToken;
5378
- const override = process.env["OVERDECK_DASHBOARD_SESSION_TOKEN"];
5379
- if (override) {
5380
- browserSessionToken = override;
5381
- return browserSessionToken;
5382
- }
5383
- const internal = getInternalTokenSync();
5384
- browserSessionToken = internal ? createHmac("sha256", internal).update("overdeck-dashboard-session-v1").digest("base64url") : randomBytes(32).toString("base64url");
5385
- return browserSessionToken;
5386
- }
5387
- function dashboardCsrfToken() {
5388
- if (browserCsrfToken) return browserCsrfToken;
5389
- const override = process.env["OVERDECK_DASHBOARD_CSRF_TOKEN"];
5390
- if (override) {
5391
- browserCsrfToken = override;
5392
- return browserCsrfToken;
5393
- }
5394
- const internal = getInternalTokenSync();
5395
- browserCsrfToken = internal ? createHmac("sha256", internal).update("overdeck-dashboard-csrf-v1").digest("base64url") : randomBytes(32).toString("base64url");
5396
- return browserCsrfToken;
5397
- }
5398
- function constantTimeTokenEqual(provided, expected) {
5399
- if (!provided) return false;
5400
- return timingSafeEqual(createHash$1("sha256").update(provided).digest(), createHash$1("sha256").update(expected).digest());
5401
- }
5402
- function cookieValue(cookieHeader, name) {
5403
- if (!cookieHeader) return void 0;
5404
- for (const part of cookieHeader.split(";")) {
5405
- const [rawKey, ...rawValue] = part.trim().split("=");
5406
- if (rawKey !== name) continue;
5407
- try {
5408
- return decodeURIComponent(rawValue.join("="));
5409
- } catch {
5410
- return;
5411
- }
5412
- }
5413
- }
5414
- function dashboardSessionCookieHeader(options = {}) {
5415
- const secure = options.secure ? "; Secure" : "";
5416
- return `${DASHBOARD_SESSION_COOKIE}=${encodeURIComponent(getDashboardSessionToken())}; Path=/; HttpOnly; SameSite=Strict; Max-Age=${DASHBOARD_SESSION_MAX_AGE_SECONDS}${secure}`;
5417
- }
5418
- function hasDashboardInternalTokenHeaders(headers) {
5419
- const expected = getInternalTokenSync();
5420
- if (!expected) return false;
5421
- if (constantTimeTokenEqual(getHeaderFromMap(headers, "x-overdeck-internal-token"), expected)) return true;
5422
- const authorization = getHeaderFromMap(headers, "authorization");
5423
- if (authorization) {
5424
- const [scheme, token] = authorization.split(/\s+/);
5425
- if (scheme?.toLowerCase() === "bearer" && constantTimeTokenEqual(token, expected)) return true;
5426
- }
5427
- return false;
5428
- }
5429
- function hasDashboardInternalToken(request) {
5430
- return hasDashboardInternalTokenHeaders(request.headers);
5431
- }
5432
- function hasDashboardAuthHeaders(headers) {
5433
- return hasDashboardInternalTokenHeaders(headers) || constantTimeTokenEqual(cookieValue(getHeaderFromMap(headers, "cookie"), "overdeck_session"), getDashboardSessionToken());
5434
- }
5435
- function hasDashboardAuth(request) {
5436
- return hasDashboardAuthHeaders(request.headers);
5437
- }
5438
- function isJsonContentType(headers) {
5439
- const contentType = getHeaderFromMap(headers, "content-type");
5440
- if (!contentType) return false;
5441
- const [mime] = contentType.toLowerCase().split(";");
5442
- return mime.trim() === "application/json";
5443
- }
5444
- function hasTrustedExactOrigin(headers) {
5445
- const origin = getHeaderFromMap(headers, "origin");
5446
- if (!origin) return false;
5447
- const normalized = normalizeOrigin(origin);
5448
- return !!normalized && getTrustedOrigins().includes(normalized);
5449
- }
5450
- function hasValidCsrfToken(headers) {
5451
- return constantTimeTokenEqual(getHeaderFromMap(headers, DASHBOARD_CSRF_HEADER), dashboardCsrfToken());
5452
- }
5453
- function rejectUnsafeDashboardMutationRequest(request) {
5454
- const authError = rejectUnauthorizedDashboardRequest(request);
5455
- if (authError) return authError;
5456
- const headers = request.headers;
5457
- if (!isJsonContentType(headers)) return jsonResponse({ error: "Content-Type must be application/json" }, { status: 400 });
5458
- if (hasDashboardInternalToken(request)) return null;
5459
- if (getHeaderFromMap(headers, "origin") && !hasTrustedExactOrigin(headers)) return jsonResponse({ error: "Invalid origin" }, { status: 403 });
5460
- if (!hasValidCsrfToken(headers)) return jsonResponse({ error: "Invalid CSRF token" }, { status: 403 });
5461
- return null;
5462
- }
5463
- function ipv4ToInt(value) {
5464
- const parts = value.split(".");
5465
- if (parts.length !== 4) return null;
5466
- let result = 0;
5467
- for (const part of parts) {
5468
- const octet = Number(part);
5469
- if (!Number.isInteger(octet) || octet < 0 || octet > 255) return null;
5470
- result = (result << 8 | octet) >>> 0;
5471
- }
5472
- return result;
5473
- }
5474
- /** RFC1918 private ranges — Docker bridges always fall inside one of these. */
5475
- function isRfc1918(ip) {
5476
- return (ip & 4278190080) >>> 0 === 167772160 || (ip & 4293918720) >>> 0 === 2886729728 || (ip & 4294901760) >>> 0 === 3232235520;
5477
- }
5478
- /**
5479
- * True when `addr` is the IP of a container on one of THIS host's Docker bridge
5480
- * interfaces (docker0 / br-*). Such a peer can only be a process running on this
5481
- * machine — our own host-local Traefik fronting overdeck.localhost, or another
5482
- * Overdeck container — never a LAN client (a direct LAN hit to the 0.0.0.0
5483
- * API port arrives with a LAN peer that is not inside any Docker bridge subnet).
5484
- *
5485
- * Pure for testability: the interface map is injected. We only ever trust
5486
- * RFC1918 bridge subnets, so a misconfigured public-range br-* cannot widen
5487
- * trust beyond the local Docker fabric.
5488
- */
5489
- function peerIsHostLocalDockerBridge(addr, interfaces) {
5490
- const peer = ipv4ToInt(addr);
5491
- if (peer === null) return false;
5492
- for (const [name, addrs] of Object.entries(interfaces)) {
5493
- if (name !== "docker0" && !name.startsWith("br-")) continue;
5494
- for (const info of addrs ?? []) {
5495
- if (info.family !== "IPv4") continue;
5496
- const ifaceIp = ipv4ToInt(info.address);
5497
- const mask = ipv4ToInt(info.netmask);
5498
- if (ifaceIp === null || mask === null) continue;
5499
- const network = (ifaceIp & mask) >>> 0;
5500
- if (!isRfc1918(network)) continue;
5501
- if ((peer & mask) >>> 0 === network) return true;
5502
- }
5503
- }
5504
- return false;
5505
- }
5506
- /**
5507
- * True when `addr` shares an RFC1918 subnet with one of THIS process's own
5508
- * network interfaces. This is the in-container counterpart of
5509
- * peerIsHostLocalDockerBridge: inside a container the Docker bridge is
5510
- * invisible — the container sees only its veth endpoints (eth0/eth1), so the
5511
- * docker0/br-* name filter never matches and the host-local Traefik fronting
5512
- * the stack 401'd every session mint (first hit live on the PAN-1737 UAT
5513
- * stack). A peer inside one of the container's attached Docker-network
5514
- * subnets can only be another container on those networks — the server
5515
- * publishes no host port (Traefik labels only), so no LAN client can ever
5516
- * present such an address. Only consulted when running inside a container.
5517
- */
5518
- function peerIsLocalContainerNetwork(addr, interfaces) {
5519
- const peer = ipv4ToInt(addr);
5520
- if (peer === null) return false;
5521
- for (const addrs of Object.values(interfaces)) for (const info of addrs ?? []) {
5522
- if (info.family !== "IPv4" || info.internal) continue;
5523
- const ifaceIp = ipv4ToInt(info.address);
5524
- const mask = ipv4ToInt(info.netmask);
5525
- if (ifaceIp === null || mask === null) continue;
5526
- const network = (ifaceIp & mask) >>> 0;
5527
- if (!isRfc1918(network)) continue;
5528
- if ((peer & mask) >>> 0 === network) return true;
5529
- }
5530
- return false;
5531
- }
5532
- /** Docker creates /.dockerenv in every container — stable in-container signal. */
5533
- const runningInContainer = existsSync("/.dockerenv");
5534
- /**
5535
- * A request we trust to mint a session because it originated from this machine —
5536
- * the local browser hitting the dashboard directly (127.0.0.1), or the
5537
- * host-local Traefik that fronts overdeck.localhost. In Docker, that Traefik reaches
5538
- * the host server from a Docker-bridge IP (e.g. 172.18.0.2), NOT 127.0.0.1, so
5539
- * a literal-loopback check alone silently breaks the zero-step bootstrap for
5540
- * every overdeck.localhost user — their session mint 401s and no cookie is ever set.
5541
- *
5542
- * This is the auto-bootstrap that removes the manual one-time #overdeck_token
5543
- * step: any browser on overdeck.localhost gets a session with no user action. It is
5544
- * NOT a security downgrade for the LAN — the raw API ports bind 0.0.0.0, but a
5545
- * direct LAN hit has a non-loopback, non-Docker-bridge peer and is rejected. We
5546
- * read ONLY the real TCP peer (request.remoteAddress), never X-Forwarded-For,
5547
- * which a caller could spoof.
5548
- */
5549
- function isLoopbackPeer(request) {
5550
- const remoteAddress = request.remoteAddress;
5551
- const raw = remoteAddress && typeof remoteAddress === "object" && "_tag" in remoteAddress ? Option.getOrElse(remoteAddress, () => "") : typeof remoteAddress === "string" ? remoteAddress : "";
5552
- if (!raw) return false;
5553
- const addr = raw.startsWith("::ffff:") ? raw.slice(7) : raw;
5554
- if (addr === "127.0.0.1" || addr === "::1") return true;
5555
- if (peerIsHostLocalDockerBridge(addr, networkInterfaces())) return true;
5556
- return runningInContainer && peerIsLocalContainerNetwork(addr, networkInterfaces());
5557
- }
5558
- function rejectUnauthorizedDashboardSessionMintRequest(request) {
5559
- if (!getInternalTokenSync()) return jsonResponse({ error: "dashboard session token not configured" }, { status: 503 });
5560
- if (!hasDashboardInternalToken(request) && !isLoopbackPeer(request)) return jsonResponse({ error: "unauthorized" }, { status: 401 });
5561
- return null;
5562
- }
5563
- function rejectUnauthorizedDashboardRequest(request) {
5564
- if (!getInternalTokenSync()) return jsonResponse({ error: "dashboard session token not configured" }, { status: 503 });
5565
- if (!hasDashboardAuth(request)) return jsonResponse({ error: "unauthorized" }, { status: 401 });
5566
- return null;
5567
- }
5568
- //#endregion
5569
5960
  //#region routes/agents/spawn-helpers.ts
5570
5961
  init_child_env();
5571
5962
  init_agents$1();
5572
5963
  function handleRemoteAgentSpawn(input) {
5573
5964
  return Effect.gen(function* () {
5574
5965
  const { issueId, workspacePath, workspaceMetadata, spawnModel, projectPath, spawnGuardrails, lifecycle } = input;
5575
- const { spawnRemoteAgent, checkRemoteSpendCap } = yield* Effect.promise(() => import("./remote-agents-CRCg1L4H.js"));
5576
- const { createFlyProviderFromConfig } = yield* Effect.promise(() => import("./remote-4tiENDaI.js"));
5577
- const { loadConfigSync: loadPanConfig } = yield* Effect.promise(() => import("./config-DUIhMN_T.js"));
5966
+ const { spawnRemoteAgent, checkRemoteSpendCap } = yield* Effect.promise(() => import("./remote-agents-CA3Ihlxj.js"));
5967
+ const { createFlyProviderFromConfig } = yield* Effect.promise(() => import("./remote-ChgimyYa.js"));
5968
+ const { loadConfigSync: loadPanConfig } = yield* Effect.promise(() => import("./config-DzV30TOm.js"));
5578
5969
  const panConfig = loadPanConfig();
5579
5970
  const spendCap = checkRemoteSpendCap(panConfig);
5580
5971
  if (!spendCap.allowed) return jsonResponse({ error: spendCap.message }, { status: 429 });
5581
5972
  const fly = createFlyProviderFromConfig(panConfig.remote);
5582
5973
  yield* Effect.promise(() => fly.syncAllCredentials(workspaceMetadata.vmName));
5583
- const { buildWorkAgentPrompt, getTrackerContext } = yield* Effect.promise(() => import("./work-agent-prompt-Yb2bd3Fq.js"));
5974
+ const { buildWorkAgentPrompt, getTrackerContext } = yield* Effect.promise(() => import("./work-agent-prompt-Du8Vh2aJ.js"));
5584
5975
  const trackerContext = yield* Effect.promise(() => getTrackerContext(issueId, workspacePath));
5585
5976
  const agentPrompt = yield* Effect.promise(() => buildWorkAgentPrompt({
5586
5977
  issueId,
@@ -5902,10 +6293,22 @@ init_harness_policy();
5902
6293
  init_activity_logger();
5903
6294
  init_projects();
5904
6295
  init_review_status();
6296
+ init_state_read_home();
5905
6297
  init_io();
5906
6298
  init_read_model();
5907
6299
  init_domain_services();
5908
6300
  init_tmux();
6301
+ function orderDispatchConflict(decision) {
6302
+ if (decision.eligible) return null;
6303
+ return {
6304
+ status: 409,
6305
+ body: {
6306
+ error: decision.message ?? "Order-book dispatch is blocked.",
6307
+ code: decision.code ?? "order-dispatch-blocked",
6308
+ conditions: decision.conditions
6309
+ }
6310
+ };
6311
+ }
5909
6312
  /**
5910
6313
  * PAN-2386: emit a dashboard activity event when start-agent refuses to spawn
5911
6314
  * because the workspace is dirty. Kept as a pure function so the refusal path
@@ -5974,6 +6377,7 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
5974
6377
  const { issueId, projectId } = body;
5975
6378
  const autoStart = body.auto === true;
5976
6379
  const guardrailAcknowledged = body.guardrailAcknowledged === true;
6380
+ const offBook = body.offBook === true;
5977
6381
  const requestedHostOverride = body.host === true || body.allowHost === true;
5978
6382
  if (!issueId) return jsonResponse({ error: "issueId required" }, { status: 400 });
5979
6383
  const legacyFields = [
@@ -6029,6 +6433,8 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
6029
6433
  const resolvedProject = resolveProjectFromIssueSync(String(issueId));
6030
6434
  const projectConfig = resolvedProject ? getProjectSync(resolvedProject.projectKey) : null;
6031
6435
  const projectPath = projectConfig?.path ?? getProjectPath(projectId, issuePrefix);
6436
+ const orderConflict = orderDispatchConflict((yield* Effect.promise(() => checkActiveOrderDispatch(projectPath, issueId, { offBook }))).decision);
6437
+ if (orderConflict) return jsonResponse(orderConflict.body, { status: orderConflict.status });
6032
6438
  const workspacePath = join(projectPath, "workspaces", `feature-${issueLower}`);
6033
6439
  if (!existsSync(workspacePath)) try {
6034
6440
  const nodeDir = dirname(process.execPath);
@@ -6173,10 +6579,18 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
6173
6579
  }
6174
6580
  if (!isRemote) {
6175
6581
  emitStartAgentPhase(issueId, "stackHealthGate", "start", "checking workspace docker stack health", { workspacePath });
6176
- const stackHealth = yield* getWorkspaceStackHealth(issueId, {
6582
+ let stackHealth = yield* getWorkspaceStackHealth(issueId, {
6177
6583
  projectConfig,
6178
6584
  workspacePath
6179
6585
  });
6586
+ if (!stackHealth.healthy && !allowHost) {
6587
+ emitStartAgentPhase(issueId, "stackHealthGate", "start", "stack unhealthy — attempting workspace stack rebuild", { workspacePath });
6588
+ yield* Effect.promise(() => assertWorkspaceStackHealthyForSpawn(issueId, "work", false, workspacePath).catch(() => void 0));
6589
+ stackHealth = yield* getWorkspaceStackHealth(issueId, {
6590
+ projectConfig,
6591
+ workspacePath
6592
+ });
6593
+ }
6180
6594
  if (!stackHealth.healthy) {
6181
6595
  yield* Effect.promise(() => appendAgentLifecycleLog(agentSessionName, "agent.start_blocked_stack_unhealthy", {
6182
6596
  issueId,
@@ -6278,7 +6692,7 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
6278
6692
  console.warn(`[start-agent] Failed to set plan.status=running (non-fatal): ${planStatusErr?.message ?? planStatusErr}`);
6279
6693
  }
6280
6694
  try {
6281
- const { appendSessionEntry, getProjectConfigFromWorkspacePath, resolveProjectForIssue } = await import("./record-t6V-3Dcj.js");
6695
+ const { appendSessionEntry, getProjectConfigFromWorkspacePath, resolveProjectForIssue } = await import("./record-CN0pj4_5.js");
6282
6696
  await appendSessionEntry(resolveProjectForIssue(issueId) ?? getProjectConfigFromWorkspacePath(workspacePath), issueId, {
6283
6697
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
6284
6698
  reason: "start",
@@ -6291,7 +6705,10 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
6291
6705
  if (getReviewStatusSync(issueId)?.stuckReason === "planning_auto_handoff_failed") clearWorkspaceStuck(issueId);
6292
6706
  };
6293
6707
  if (isRemote && workspaceMetadata) {
6294
- const response = yield* Effect.promise(() => spawnAfterClearingStartGates({
6708
+ const admitted = yield* Effect.promise(() => withActiveOrderDispatchReservation(projectPath, issueId, {
6709
+ offBook,
6710
+ recordOverride: true
6711
+ }, () => spawnAfterClearingStartGates({
6295
6712
  agentSessionName,
6296
6713
  gate: startGateBlock,
6297
6714
  initialState: initialAgentState,
@@ -6305,7 +6722,10 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
6305
6722
  lifecycle
6306
6723
  })),
6307
6724
  isSuccessful: (remoteResponse) => remoteResponse.status >= 200 && remoteResponse.status < 300
6308
- }));
6725
+ })));
6726
+ const admittedConflict = orderDispatchConflict(admitted.check.decision);
6727
+ if (admittedConflict) return jsonResponse(admittedConflict.body, { status: admittedConflict.status });
6728
+ const response = admitted.result;
6309
6729
  if (response.status < 200 || response.status >= 300) return response;
6310
6730
  yield* Effect.promise(commitClearedGates);
6311
6731
  yield* Effect.promise(markWorkStartAccepted);
@@ -6373,11 +6793,14 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
6373
6793
  console.warn(`[start-agent] Failed to check workspace status for ${issueId}: ${message}`);
6374
6794
  }
6375
6795
  const bodyHarness = body.harness;
6376
- const userPickedHarness = bodyHarness === "ohmypi" || bodyHarness === "claude-code" || bodyHarness === "codex" ? bodyHarness : null;
6796
+ const userPickedHarness = bodyHarness === "ohmypi" || bodyHarness === "claude-code" || bodyHarness === "codex" || bodyHarness === "acp" ? bodyHarness : null;
6377
6797
  let effectiveHarness = null;
6378
6798
  if (userPickedHarness !== null) effectiveHarness = (yield* Effect.promise(async () => canUseHarnessSync(userPickedHarness, spawnModel, await getProviderAuthMode(spawnModel)))).allowed ? userPickedHarness : "claude-code";
6379
6799
  const spawnPanCommand = async (args, cwd) => {
6380
- const activityId = await spawnAfterClearingStartGates({
6800
+ const admitted = await withActiveOrderDispatchReservation(projectPath, issueId, {
6801
+ offBook,
6802
+ recordOverride: false
6803
+ }, () => spawnAfterClearingStartGates({
6381
6804
  agentSessionName,
6382
6805
  gate: gatesCommitted ? null : startGateBlock,
6383
6806
  initialState: initialAgentState,
@@ -6389,9 +6812,10 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
6389
6812
  args,
6390
6813
  cwd
6391
6814
  })
6392
- });
6815
+ }));
6816
+ if (!admitted.check.decision.eligible || !admitted.result) throw new OrderDispatchReservationError(admitted.check);
6393
6817
  await commitClearedGates();
6394
- return activityId;
6818
+ return admitted.result;
6395
6819
  };
6396
6820
  const updateIssueStatus = async () => {
6397
6821
  await Effect.runPromise(lifecycle.transitionTo(issueId, "in_progress").pipe(Effect.catch(() => Effect.void)));
@@ -6475,7 +6899,8 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
6475
6899
  issueId,
6476
6900
  model: spawnModel,
6477
6901
  harness: effectiveHarness,
6478
- allowHost
6902
+ allowHost,
6903
+ offBook
6479
6904
  }), workspacePath));
6480
6905
  yield* Effect.promise(markWorkStartAccepted);
6481
6906
  emitStartAgentPhase(issueId, "spawn", "success", "local work agent spawn requested", {
@@ -6506,6 +6931,10 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
6506
6931
  fallbackStatus: fallbackState.status
6507
6932
  }));
6508
6933
  invalidateAgentsCache();
6934
+ if (error instanceof OrderDispatchReservationError) {
6935
+ const conflict = orderDispatchConflict(error.check.decision);
6936
+ return jsonResponse(conflict.body, { status: conflict.status });
6937
+ }
6509
6938
  const output = String(error?.output ?? error?.message ?? "");
6510
6939
  if (output.includes(`Workspace docker stack for ${issueId}`) && output.includes("is not healthy")) {
6511
6940
  const failedStackHealth = yield* getWorkspaceStackHealth(issueId, {
@@ -6715,10 +7144,10 @@ const _serverManagedMerges = /* @__PURE__ */ new Set();
6715
7144
  function firePostMergeLifecycle(issueId, options) {
6716
7145
  const started = postMergeGuard.run(issueId, async () => {
6717
7146
  const projectPath = getProjectPathForIssue(extractPrefixSync(issueId) ?? issueId.split("-")[0]);
6718
- const { postMergeLifecycle } = await import("./merge-agent-BQM3a8z5.js");
7147
+ const { postMergeLifecycle } = await import("./merge-agent-CKkgIBPB.js");
6719
7148
  await postMergeLifecycle(issueId, projectPath, options?.sourceBranch, options?.verifiedMergedRef ? { verifiedMergedRef: options.verifiedMergedRef } : void 0);
6720
7149
  console.log(`[merge] post-merge lifecycle completed for ${issueId}`);
6721
- const { runMergeTrainReconcile } = await import("./merge-train-DxDfBTjr.js");
7150
+ const { runMergeTrainReconcile } = await import("./merge-train-CHopycP0.js");
6722
7151
  const outcomes = await runMergeTrainReconcile(issueId);
6723
7152
  if (outcomes.length > 0) console.log(`[merge-train] reconciled ${outcomes.length} sibling(s) after ${issueId}: ` + outcomes.map((o) => `${o.issueId}=${o.result}`).join(", "));
6724
7153
  }, (err) => console.error(`[merge] post-merge lifecycle failed for ${issueId}:`, err));
@@ -6739,15 +7168,15 @@ init_io();
6739
7168
  init_domain_services();
6740
7169
  init_tmux();
6741
7170
  const getSpecialistsRoute = HttpRouter.add("GET", "/api/specialists", httpHandler(Effect.gen(function* () {
6742
- const { getAllSpecialistStatus, getAllProjectSpecialistStatuses } = yield* Effect.promise(() => import("./specialists-DVj0hvaL.js"));
7171
+ const { getAllSpecialistStatus, getAllProjectSpecialistStatuses } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
6743
7172
  return jsonResponse({
6744
7173
  specialists: yield* Effect.promise(() => getAllSpecialistStatus()),
6745
7174
  projects: yield* Effect.promise(() => getAllProjectSpecialistStatuses())
6746
7175
  });
6747
7176
  })));
6748
7177
  const postSpecialistsResetAllRoute = HttpRouter.add("POST", "/api/specialists/reset-all", httpHandler(Effect.gen(function* () {
6749
- const { getAllSpecialists, isRunning, getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-DVj0hvaL.js"));
6750
- const { clearHookSync } = yield* Effect.promise(() => import("./hooks-ltecuFqZ.js"));
7178
+ const { getAllSpecialists, isRunning, getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
7179
+ const { clearHookSync } = yield* Effect.promise(() => import("./hooks-DPVX1rwQ.js"));
6751
7180
  const specialists = getAllSpecialists();
6752
7181
  const results = [];
6753
7182
  for (const specialist of specialists) {
@@ -6803,7 +7232,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
6803
7232
  }
6804
7233
  console.log(`[specialists/done] ${specialist} signaling ${status} for ${normalizedIssueId}`);
6805
7234
  if (specialist === "merge") {
6806
- const { reportSpecialistCompletion } = yield* Effect.promise(() => import("./specialist-completion-BXhav38U.js"));
7235
+ const { reportSpecialistCompletion } = yield* Effect.promise(() => import("./specialist-completion-Ky9wCDpb.js"));
6807
7236
  if (yield* reportSpecialistCompletion(normalizedIssueId, {
6808
7237
  status,
6809
7238
  notes
@@ -6850,7 +7279,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
6850
7279
  if (specialist === "inspect" && status === "failed") yield* Effect.promise(() => reportTieredInspectFailureEscalation(normalizedIssueId, notes));
6851
7280
  yield* Effect.promise(async () => {
6852
7281
  try {
6853
- const { getTmuxSessionName, updateRunMetadata, makeSpecialistRegistryKey } = await import("./specialists-DVj0hvaL.js");
7282
+ const { getTmuxSessionName, updateRunMetadata, makeSpecialistRegistryKey } = await import("./specialists-DM6bWjsi.js");
6854
7283
  const projectKey = resolveProjectFromIssueSync(normalizedIssueId)?.projectKey;
6855
7284
  const tmuxSession = projectKey ? getTmuxSessionName(`${specialist}-agent`, projectKey, normalizedIssueId) : getTmuxSessionName(`${specialist}-agent`);
6856
7285
  saveAgentRuntimeState(tmuxSession, {
@@ -6869,7 +7298,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
6869
7298
  });
6870
7299
  console.log(`[specialists/done] Cleared registry lock for ${registryKey} (${projectKey})`);
6871
7300
  }
6872
- const { updateSpecialistHandoffStatus } = await import("./specialist-handoff-logger-C45ouoZ6.js");
7301
+ const { updateSpecialistHandoffStatus } = await import("./specialist-handoff-logger-CMEwYxa2.js");
6873
7302
  if (await Effect.runPromise(updateSpecialistHandoffStatus(normalizedIssueId, `${specialist}-agent`, status === "passed" ? "completed" : "failed", status === "passed" ? "success" : "failure"))) console.log(`[specialists/done] Updated handoff log: ${specialist}-agent ${normalizedIssueId} → ${status}`);
6874
7303
  } catch (err) {
6875
7304
  console.error(`[specialists/done] Error managing specialist state:`, err);
@@ -6881,7 +7310,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
6881
7310
  if (project) {
6882
7311
  const workspacePath = join(project.projectPath, "workspaces", `feature-${normalizedIssueId.toLowerCase()}`);
6883
7312
  if (existsSync(workspacePath)) {
6884
- const { getWorkspaceGitInfo } = await import("./git-utils-Dry_Ka_D.js");
7313
+ const { getWorkspaceGitInfo } = await import("./git-utils-D0_yhCgF.js");
6885
7314
  const { HEAD } = await Effect.runPromise(getWorkspaceGitInfo(workspacePath));
6886
7315
  setReviewStatusSync(normalizedIssueId, { reviewedAtCommit: HEAD });
6887
7316
  console.log(`[specialists/done] Snapshotted reviewedAtCommit=${HEAD.substring(0, 8)} for ${normalizedIssueId}`);
@@ -6893,7 +7322,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
6893
7322
  });
6894
7323
  if (specialist === "inspect" && status === "passed") yield* Effect.promise(async () => {
6895
7324
  try {
6896
- const { onInspectComplete } = await import("./inspect-agent-ch-F-5Ci.js");
7325
+ const { onInspectComplete } = await import("./inspect-agent-Brtz0URj.js");
6897
7326
  const project = resolveProjectFromIssueSync(normalizedIssueId);
6898
7327
  if (project) {
6899
7328
  const workspacePath = join(project.projectPath, "workspaces", `feature-${normalizedIssueId.toLowerCase()}`);
@@ -6909,7 +7338,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
6909
7338
  if (project) {
6910
7339
  if (existsSync(join(project.projectPath, "workspaces", `feature-${normalizedIssueId.toLowerCase()}`))) {
6911
7340
  setReviewStatusSync(normalizedIssueId, { testStatus: "passed" });
6912
- const { initEventStore } = await import("./event-store-Cr5PQwFC.js");
7341
+ const { initEventStore } = await import("./event-store-EV2cMiXj.js");
6913
7342
  await (await initEventStore()).appendAsync({
6914
7343
  type: "test.passed",
6915
7344
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -6962,8 +7391,8 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
6962
7391
  if (notes?.toLowerCase().includes("conflict")) yield* Effect.promise(async () => {
6963
7392
  try {
6964
7393
  const workAgentId = `agent-${normalizedIssueId.toLowerCase()}`;
6965
- const { sessionExists } = await import("./tmux-DoThH6aj.js");
6966
- const { messageAgent, spawnAgent, getAgentStateSync } = await import("./agents-FlIgQ3ql.js");
7394
+ const { sessionExists } = await import("./tmux-B6z7h_vZ.js");
7395
+ const { messageAgent, spawnAgent, getAgentStateSync } = await import("./agents-wi9NWzs2.js");
6967
7396
  if (await Effect.runPromise(sessionExists(workAgentId))) {
6968
7397
  await messageAgent(workAgentId, `MERGE CONFLICT: The merge-agent could not rebase your branch onto main due to conflicts. Please fix this now:\n\n1. git fetch origin main\n2. git rebase origin/main\n3. Resolve any conflicts (git add <file> && git rebase --continue)\n4. git push --force-with-lease\n5. Resubmit: curl -s -X POST http://localhost:3011/api/review/${normalizedIssueId}/request -H "Content-Type: application/json" -d "{}"\n\nConflict details: ${notes}`);
6969
7398
  console.log(`[specialists/done] Sent rebase instructions to ${workAgentId}`);
@@ -6977,7 +7406,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
6977
7406
  try {
6978
7407
  const project = resolveProjectFromIssueSync(normalizedIssueId);
6979
7408
  const workspacePath = project ? join(project.projectPath, "workspaces", `feature-${normalizedIssueId.toLowerCase()}`) : void 0;
6980
- const { deliverReviewVerdictFeedback } = await import("./review-verdict-feedback-C1Kg8n7t.js");
7409
+ const { deliverReviewVerdictFeedback } = await import("./review-verdict-feedback-CTd4QMBu.js");
6981
7410
  const result = await Effect.runPromise(deliverReviewVerdictFeedback({
6982
7411
  issueId: normalizedIssueId,
6983
7412
  verdict: status === "failed" ? "failed" : "blocked",
@@ -7018,7 +7447,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
7018
7447
  });
7019
7448
  })));
7020
7449
  const postSpecialistsLogsCleanupAllRoute = HttpRouter.add("POST", "/api/specialists/logs/cleanup-all", httpHandler(Effect.gen(function* () {
7021
- const { cleanupAllLogsSync } = yield* Effect.promise(() => import("./specialist-logs-DJ3RzKxW.js"));
7450
+ const { cleanupAllLogsSync } = yield* Effect.promise(() => import("./specialist-logs-C5p8G7tx.js"));
7022
7451
  const results = cleanupAllLogsSync();
7023
7452
  return jsonResponse({
7024
7453
  success: true,
@@ -7028,7 +7457,7 @@ const postSpecialistsLogsCleanupAllRoute = HttpRouter.add("POST", "/api/speciali
7028
7457
  });
7029
7458
  })));
7030
7459
  const getSpecialistsProjectsRoute = HttpRouter.add("GET", "/api/specialists/projects", httpHandler(Effect.gen(function* () {
7031
- const { getAllProjectSpecialistStatuses } = yield* Effect.promise(() => import("./specialists-DVj0hvaL.js"));
7460
+ const { getAllProjectSpecialistStatuses } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
7032
7461
  return jsonResponse(yield* Effect.promise(() => getAllProjectSpecialistStatuses()));
7033
7462
  })));
7034
7463
  const postSpecialistWakeRoute = HttpRouter.add("POST", "/api/specialists/:name/wake", httpHandler(Effect.gen(function* () {
@@ -7072,7 +7501,7 @@ const postSpecialistReportStatusRoute = HttpRouter.add("POST", "/api/specialists
7072
7501
  "blocked",
7073
7502
  "failed"
7074
7503
  ].includes(status)) {
7075
- const { getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-DVj0hvaL.js"));
7504
+ const { getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
7076
7505
  saveAgentRuntimeState(getTmuxSessionName(name), {
7077
7506
  state: "idle",
7078
7507
  lastActivity: (/* @__PURE__ */ new Date()).toISOString()
@@ -7193,7 +7622,7 @@ const postProjectSpecialistKillRoute = HttpRouter.add("POST", "/api/specialists/
7193
7622
  const issueId = params["issueId"];
7194
7623
  const type = params["type"];
7195
7624
  if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
7196
- const { getTmuxSessionName, makeSpecialistRegistryKey, getRunMetadata } = yield* Effect.promise(() => import("./specialists-DVj0hvaL.js"));
7625
+ const { getTmuxSessionName, makeSpecialistRegistryKey, getRunMetadata } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
7197
7626
  const tmuxSession = getRunMetadata(project, makeSpecialistRegistryKey(type, issueId)).tmuxSession ?? getTmuxSessionName(type, project, issueId);
7198
7627
  yield* Effect.promise(() => Effect.runPromise(killSession(tmuxSession)).catch(() => {}));
7199
7628
  saveAgentRuntimeState(tmuxSession, {
@@ -7220,7 +7649,7 @@ const getProjectSpecialistRunsRoute = HttpRouter.add("GET", "/api/specialists/:p
7220
7649
  if (limitParam) limit = parseInt(limitParam, 10);
7221
7650
  if (offsetParam) offset = parseInt(offsetParam, 10);
7222
7651
  }
7223
- const { listRunLogsSync } = yield* Effect.promise(() => import("./specialist-logs-DJ3RzKxW.js"));
7652
+ const { listRunLogsSync } = yield* Effect.promise(() => import("./specialist-logs-C5p8G7tx.js"));
7224
7653
  return jsonResponse(listRunLogsSync(project, type, {
7225
7654
  limit,
7226
7655
  offset
@@ -7231,7 +7660,7 @@ const getProjectSpecialistRunStreamRoute = HttpRouter.add("GET", "/api/specialis
7231
7660
  const project = params["project"];
7232
7661
  const type = params["type"];
7233
7662
  const runId = params["runId"];
7234
- const { getRunLogPath, isRunLogActive } = yield* Effect.promise(() => import("./specialist-logs-DJ3RzKxW.js"));
7663
+ const { getRunLogPath, isRunLogActive } = yield* Effect.promise(() => import("./specialist-logs-C5p8G7tx.js"));
7235
7664
  const logPath = getRunLogPath(project, type, runId);
7236
7665
  if (!existsSync(logPath)) return jsonResponse({ error: "Run log not found" }, { status: 404 });
7237
7666
  const encoder = new TextEncoder();
@@ -7290,7 +7719,7 @@ const getProjectSpecialistRunRoute = HttpRouter.add("GET", "/api/specialists/:pr
7290
7719
  const project = params["project"];
7291
7720
  const type = params["type"];
7292
7721
  const runId = params["runId"];
7293
- const { getRunLogSync, parseLogMetadata } = yield* Effect.promise(() => import("./specialist-logs-DJ3RzKxW.js"));
7722
+ const { getRunLogSync, parseLogMetadata } = yield* Effect.promise(() => import("./specialist-logs-C5p8G7tx.js"));
7294
7723
  const content = getRunLogSync(project, type, runId);
7295
7724
  if (!content) return jsonResponse({ error: "Run log not found" }, { status: 404 });
7296
7725
  return jsonResponse({
@@ -7304,7 +7733,7 @@ const postProjectSpecialistRunTerminateRoute = HttpRouter.add("POST", "/api/spec
7304
7733
  const project = params["project"];
7305
7734
  const type = params["type"];
7306
7735
  if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
7307
- const { terminateSpecialist } = yield* Effect.promise(() => import("./specialists-DVj0hvaL.js"));
7736
+ const { terminateSpecialist } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
7308
7737
  yield* Effect.promise(() => terminateSpecialist(project, type));
7309
7738
  return jsonResponse({
7310
7739
  success: true,
@@ -7316,7 +7745,7 @@ const postProjectSpecialistGracePauseRoute = HttpRouter.add("POST", "/api/specia
7316
7745
  const project = params["project"];
7317
7746
  const type = params["type"];
7318
7747
  if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
7319
- const { pauseGracePeriod } = yield* Effect.promise(() => import("./specialists-DVj0hvaL.js"));
7748
+ const { pauseGracePeriod } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
7320
7749
  if (pauseGracePeriod(project, type)) return jsonResponse({
7321
7750
  success: true,
7322
7751
  message: "Grace period paused"
@@ -7328,7 +7757,7 @@ const postProjectSpecialistGraceResumeRoute = HttpRouter.add("POST", "/api/speci
7328
7757
  const project = params["project"];
7329
7758
  const type = params["type"];
7330
7759
  if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
7331
- const { resumeGracePeriod } = yield* Effect.promise(() => import("./specialists-DVj0hvaL.js"));
7760
+ const { resumeGracePeriod } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
7332
7761
  if (resumeGracePeriod(project, type)) return jsonResponse({
7333
7762
  success: true,
7334
7763
  message: "Grace period resumed"
@@ -7340,7 +7769,7 @@ const postProjectSpecialistGraceExitRoute = HttpRouter.add("POST", "/api/special
7340
7769
  const project = params["project"];
7341
7770
  const type = params["type"];
7342
7771
  if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
7343
- const { exitGracePeriod } = yield* Effect.promise(() => import("./specialists-DVj0hvaL.js"));
7772
+ const { exitGracePeriod } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
7344
7773
  exitGracePeriod(project, type);
7345
7774
  return jsonResponse({
7346
7775
  success: true,
@@ -7352,7 +7781,7 @@ const getProjectSpecialistGraceRoute = HttpRouter.add("GET", "/api/specialists/:
7352
7781
  const project = params["project"];
7353
7782
  const type = params["type"];
7354
7783
  if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
7355
- const { getGracePeriodState } = yield* Effect.promise(() => import("./specialists-DVj0hvaL.js"));
7784
+ const { getGracePeriodState } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
7356
7785
  const state = getGracePeriodState(project, type);
7357
7786
  if (state) return jsonResponse(state);
7358
7787
  else return jsonResponse({ error: "No active grace period" }, { status: 404 });
@@ -7361,7 +7790,7 @@ const getProjectSpecialistContextRoute = HttpRouter.add("GET", "/api/specialists
7361
7790
  const params = yield* HttpRouter.params;
7362
7791
  const project = params["project"];
7363
7792
  const type = params["type"];
7364
- const { loadContextDigest } = yield* Effect.promise(() => import("./specialist-context-DtrYvGJ-.js"));
7793
+ const { loadContextDigest } = yield* Effect.promise(() => import("./specialist-context-Bn3dCGS2.js"));
7365
7794
  const digest = loadContextDigest(project, type);
7366
7795
  if (digest) return jsonResponse({ digest });
7367
7796
  else return jsonResponse({ error: "No context digest found" }, { status: 404 });
@@ -7370,7 +7799,7 @@ const postProjectSpecialistContextRegenerateRoute = HttpRouter.add("POST", "/api
7370
7799
  const params = yield* HttpRouter.params;
7371
7800
  const project = params["project"];
7372
7801
  const type = params["type"];
7373
- const { regenerateContextDigest } = yield* Effect.promise(() => import("./specialist-context-DtrYvGJ-.js"));
7802
+ const { regenerateContextDigest } = yield* Effect.promise(() => import("./specialist-context-Bn3dCGS2.js"));
7374
7803
  const digest = yield* Effect.promise(() => regenerateContextDigest(project, type));
7375
7804
  if (digest) return jsonResponse({
7376
7805
  digest,
@@ -7389,7 +7818,7 @@ const postProjectSpecialistCompleteRoute = HttpRouter.add("POST", "/api/speciali
7389
7818
  "blocked"
7390
7819
  ].includes(status)) return jsonResponse({ error: "Valid status (passed/failed/blocked) is required" }, { status: 400 });
7391
7820
  if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
7392
- const { signalSpecialistCompletion } = yield* Effect.promise(() => import("./specialists-DVj0hvaL.js"));
7821
+ const { signalSpecialistCompletion } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
7393
7822
  signalSpecialistCompletion(project, type, {
7394
7823
  status,
7395
7824
  notes
@@ -7423,8 +7852,8 @@ const postProjectSpecialistLogsCleanupRoute = HttpRouter.add("POST", "/api/speci
7423
7852
  const params = yield* HttpRouter.params;
7424
7853
  const project = params["project"];
7425
7854
  const type = params["type"];
7426
- const { cleanupOldLogsSync } = yield* Effect.promise(() => import("./specialist-logs-DJ3RzKxW.js"));
7427
- const { getSpecialistRetention } = yield* Effect.promise(() => import("./projects-9SkRpES9.js"));
7855
+ const { cleanupOldLogsSync } = yield* Effect.promise(() => import("./specialist-logs-C5p8G7tx.js"));
7856
+ const { getSpecialistRetention } = yield* Effect.promise(() => import("./projects-vjjcmiN8.js"));
7428
7857
  const retention = getSpecialistRetention(project);
7429
7858
  const deleted = cleanupOldLogsSync(project, type, {
7430
7859
  maxDays: retention.max_days,
@@ -7445,7 +7874,7 @@ const postProjectReviewRestartRoute = HttpRouter.add("POST", "/api/specialists/:
7445
7874
  const project = params["project"];
7446
7875
  const issueId = params["issueId"];
7447
7876
  const { model, harness } = yield* readJsonBody;
7448
- const { killAllReviewerSessions } = yield* Effect.promise(() => import("./review-agent-DJRO8EG8.js"));
7877
+ const { killAllReviewerSessions } = yield* Effect.promise(() => import("./review-agent-DNboMyW4.js"));
7449
7878
  const killResult = yield* killAllReviewerSessions(project, issueId);
7450
7879
  const projectConfig = resolveProjectFromIssueSync(issueId);
7451
7880
  if (!projectConfig) return jsonResponse({ error: `Cannot resolve project for ${issueId}` }, { status: 404 });
@@ -7459,7 +7888,7 @@ const postProjectReviewRestartRoute = HttpRouter.add("POST", "/api/specialists/:
7459
7888
  }));
7460
7889
  branch = stdout.trim() || "unknown";
7461
7890
  } catch {}
7462
- const { spawnReviewRoleForIssue } = yield* Effect.promise(() => import("./review-agent-DJRO8EG8.js"));
7891
+ const { spawnReviewRoleForIssue } = yield* Effect.promise(() => import("./review-agent-DNboMyW4.js"));
7463
7892
  const prUrl = getReviewStatusSync(issueId)?.prUrl;
7464
7893
  const result = yield* spawnReviewRoleForIssue({
7465
7894
  issueId,
@@ -7608,6 +8037,6 @@ const specialistsProjectRouteLayer = Layer.mergeAll(getProjectSpecialistStatusRo
7608
8037
  */
7609
8038
  const specialistsRouteLayer = Layer.mergeAll(specialistsLegacyRouteLayer, specialistsProjectRouteLayer);
7610
8039
  //#endregion
7611
- export { runInBatches as $, handleConversationDelete as A, stopConversationRuntime as B, isPiControlChannelHarness as C, conversationNeedsRunningRepair as D, validateConversationControlAckOrigin as E, isInsideGitWorkTree as F, cleanupOrphanedConversationAttachments as G, waitForPiTuiReady as H, resolveAllowedHarness as I, extractConversationAttachmentPaths as J, cleanupUnreferencedConversationAttachments as K, shouldReportUnresolvedLiveSession as L, handleConversationResume as M, handleConversationStop as N, conversationSessionAliveFromState as O, handleConversationSwitchModel as P, removeConversationAttachment as Q, spawnConversationSession as R, handleConversationThinkingLevel as S, jsonStringResponse as St, resolveConversationDeliveryMethod as T, waitForTmuxSession as U, tmuxSessionExists as V, cleanupConversationAttachments as W, hasConversationAttachment as X, getConversationAttachmentsRoot as Y, isManagedConversationAttachmentPath as Z, handleConversationCodexApproval as _, validateOrigin as _t, agentsRouteLayer as a, panCliInvocation as at, handleConversationDeliveryMethod as b, getDefaultCwd as bt, hasDashboardInternalToken as c, resolveAgentHarness as ct, rejectUnsafeDashboardMutationRequest as d, resolveJsonlPath as dt, evaluateSpawnGuardrails as et, saveAgentStateAndEmitEvent as f, resolvePiSessionPath as ft, handleConversationAbort as g, isTrustedOriginForHost as gt, deliverConversationViaControlChannel as h, getHeaderFromMap as ht, validateSpecialistAutoCompleteMetadata as i, getWorkAgentLifecycleStateSync as it, handleConversationRestartAll as j, handleConversationCreate as k, rejectUnauthorizedDashboardRequest as l, resolveClaudeSessionId as lt, codexConversationPendingInput as m, waitForSessionRespawn as mt, _serverManagedMerges as n, resolveAgentGitInfo as nt, dashboardCsrfToken as o, spawnPanCli as ot, saveAgentStateAndEmitEventProgram as p, isRespawnPending as pt, ensureConversationAttachmentDir as q, firePostMergeLifecycle as r, resolveConversationGitInfo as rt, dashboardSessionCookieHeader as s, readLauncherPinnedSessionId as st, specialistsRouteLayer as t, invalidateAgentsCache as tt, rejectUnauthorizedDashboardSessionMintRequest as u, resolveCodexRolloutPath as ut, handleConversationCompact as v, validateOriginHeaders as vt, pickDeliverAs as w, handleConversationPlanAction as x, jsonResponse as xt, handleConversationControlAck as y, httpHandler as yt, startConversationModelBackfill as z };
8040
+ export { panCliInvocation as $, resolveAllowedHarness as A, cleanupUnreferencedConversationAttachments as B, handleConversationCreate as C, jsonStringResponse as Ct, handleConversationStop as D, handleConversationResume as E, tmuxSessionExists as F, isManagedConversationAttachmentPath as G, extractConversationAttachmentPaths as H, waitForPiTuiReady as I, evaluateSpawnGuardrails as J, removeConversationAttachment as K, waitForTmuxSession as L, spawnConversationSession as M, startConversationModelBackfill as N, handleConversationSwitchModel as O, stopConversationRuntime as P, getWorkAgentLifecycleStateSync as Q, cleanupConversationAttachments as R, conversationSessionAliveFromState as S, jsonResponse as St, handleConversationRestartAll as T, getConversationAttachmentsRoot as U, ensureConversationAttachmentDir as V, hasConversationAttachment as W, resolveAgentGitInfo as X, invalidateAgentsCache as Y, resolveConversationGitInfo as Z, isPiControlChannelHarness as _, isTrustedOriginForHost as _t, agentsRouteLayer as a, resolveCodexRolloutPath as at, validateConversationControlAckOrigin as b, httpHandler as bt, codexConversationPendingInput as c, dashboardCsrfToken as ct, handleConversationCodexApproval as d, rejectUnauthorizedDashboardRequest as dt, spawnPanCli as et, handleConversationCompact as f, rejectUnauthorizedDashboardSessionMintRequest as ft, handleConversationThinkingLevel as g, getHeaderFromMap as gt, handleConversationPlanAction as h, waitForSessionRespawn as ht, validateSpecialistAutoCompleteMetadata as i, resolveClaudeSessionId as it, shouldReportUnresolvedLiveSession as j, isInsideGitWorkTree as k, deliverConversationViaControlChannel as l, dashboardSessionCookieHeader as lt, handleConversationDeliveryMethod as m, isRespawnPending as mt, _serverManagedMerges as n, resolveAcpTranscriptPath as nt, saveAgentStateAndEmitEvent as o, resolveJsonlPath as ot, handleConversationControlAck as p, rejectUnsafeDashboardMutationRequest as pt, runInBatches as q, firePostMergeLifecycle as r, resolveAgentHarness as rt, saveAgentStateAndEmitEventProgram as s, resolvePiSessionPath as st, specialistsRouteLayer as t, readLauncherPinnedSessionId as tt, handleConversationAbort as u, hasDashboardInternalToken as ut, pickDeliverAs as v, validateOrigin as vt, handleConversationDelete as w, conversationNeedsRunningRepair as x, getDefaultCwd as xt, resolveConversationDeliveryMethod as y, validateOriginHeaders as yt, cleanupOrphanedConversationAttachments as z };
7612
8041
 
7613
- //# sourceMappingURL=specialists-JVO00bs7.js.map
8042
+ //# sourceMappingURL=specialists-CC4r-c2s.js.map