@overdeck/core 0.50.3 → 0.50.4

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 (208) hide show
  1. package/dist/agents-DNMRPC8n.js.map +1 -1
  2. package/dist/{build-info-BJuEVWOh.js → build-info-ioRdOmqT.js} +3 -3
  3. package/dist/{build-info-BJuEVWOh.js.map → build-info-ioRdOmqT.js.map} +1 -1
  4. package/dist/build-info-kMMitDOP.js +2 -0
  5. package/dist/cli/index.js +4 -4
  6. package/dist/conversation-compaction-GFfO5UZL.js.map +1 -1
  7. package/dist/dashboard/{advancing-selfheal-Bq8V0QUa.js → advancing-selfheal-Dp5_Gai3.js} +3 -3
  8. package/dist/dashboard/{advancing-selfheal-Bq8V0QUa.js.map → advancing-selfheal-Dp5_Gai3.js.map} +1 -1
  9. package/dist/dashboard/{agent-gc-Coz8zQt_.js → agent-gc-JzoSs5Pi.js} +3 -3
  10. package/dist/dashboard/{agent-gc-Coz8zQt_.js.map → agent-gc-JzoSs5Pi.js.map} +1 -1
  11. package/dist/dashboard/{agent-idle-CAwB-K6M.js → agent-idle-D-Qy5BN_.js} +2 -2
  12. package/dist/dashboard/{agent-idle-CAwB-K6M.js.map → agent-idle-D-Qy5BN_.js.map} +1 -1
  13. package/dist/dashboard/{agent-state-Ci6PhjOE.js → agent-state-B196fj1h.js} +38 -16
  14. package/dist/dashboard/agent-state-B196fj1h.js.map +1 -0
  15. package/dist/dashboard/{agent-state-CbUEwUEQ.js → agent-state-IpWnw8lv.js} +1 -1
  16. package/dist/dashboard/{agent-state-service-D6IVrX3B.js → agent-state-service-CCo5-9DR.js} +3 -3
  17. package/dist/dashboard/{agent-state-service-D6IVrX3B.js.map → agent-state-service-CCo5-9DR.js.map} +1 -1
  18. package/dist/dashboard/{agent-state-service-DcN1j6eK.js → agent-state-service-D_F3VZ23.js} +1 -1
  19. package/dist/dashboard/{agents-BVvL4o_4.js → agents-CkGhnAmu.js} +1 -1
  20. package/dist/dashboard/{backlog-auto-trigger-BuSBqG2V.js → backlog-auto-trigger-B5Z2zBtC.js} +2 -2
  21. package/dist/dashboard/{backlog-auto-trigger-BuSBqG2V.js.map → backlog-auto-trigger-B5Z2zBtC.js.map} +1 -1
  22. package/dist/dashboard/build-info-BTjOB0Xr.js +2 -0
  23. package/dist/dashboard/{build-info-Cj3Y0K87.js → build-info-D0EJNj6C.js} +3 -3
  24. package/dist/dashboard/{build-info-Cj3Y0K87.js.map → build-info-D0EJNj6C.js.map} +1 -1
  25. package/dist/dashboard/cli-CIznFrcE.js +2 -0
  26. package/dist/dashboard/{cli-DIhQieif.js → cli-DCbVrSsg.js} +2 -2
  27. package/dist/dashboard/{cli-DIhQieif.js.map → cli-DCbVrSsg.js.map} +1 -1
  28. package/dist/dashboard/{close-issue-CRlmrE5g.js → close-issue-Bmu9aOIx.js} +2 -2
  29. package/dist/dashboard/{close-issue-CRlmrE5g.js.map → close-issue-Bmu9aOIx.js.map} +1 -1
  30. package/dist/dashboard/{closed-issue-reaper-DrHyYgJR.js → closed-issue-reaper-COxfTtLz.js} +5 -5
  31. package/dist/dashboard/{closed-issue-reaper-DrHyYgJR.js.map → closed-issue-reaper-COxfTtLz.js.map} +1 -1
  32. package/dist/dashboard/{closed-issue-reaper-DWlw2EtL.js → closed-issue-reaper-DwMwG_Pz.js} +1 -1
  33. package/dist/dashboard/{compaction-continuation-DhYgsXmF.js → compaction-continuation-Bqc212Zm.js} +2 -2
  34. package/dist/dashboard/{compaction-continuation-DhYgsXmF.js.map → compaction-continuation-Bqc212Zm.js.map} +1 -1
  35. package/dist/dashboard/{conflict-gate-vczgdVTa.js → conflict-gate-9mPVg7-5.js} +1 -1
  36. package/dist/dashboard/{conflict-gate-Bt-lLgYf.js → conflict-gate-CGQTcR0I.js} +3 -3
  37. package/dist/dashboard/{conflict-gate-Bt-lLgYf.js.map → conflict-gate-CGQTcR0I.js.map} +1 -1
  38. package/dist/dashboard/{conversation-compaction-CsdCbcQB.js → conversation-compaction-C7P6V8Iw.js} +5 -5
  39. package/dist/dashboard/{conversation-compaction-CsdCbcQB.js.map → conversation-compaction-C7P6V8Iw.js.map} +1 -1
  40. package/dist/dashboard/{conversation-compaction-D0zgWM1f.js → conversation-compaction-Cck5oi-V.js} +1 -1
  41. package/dist/dashboard/{conversation-service-6LaymUV-.js → conversation-service-CsOpwI9Y.js} +37 -5
  42. package/dist/dashboard/{conversation-service-6LaymUV-.js.map → conversation-service-CsOpwI9Y.js.map} +1 -1
  43. package/dist/dashboard/conversation-service-plOFkoMo.js +3 -0
  44. package/dist/dashboard/dashboard-db-worker.js +1 -1
  45. package/dist/dashboard/{deacon-CU47dU7U.js → deacon-B8oMMIgN.js} +62 -62
  46. package/dist/dashboard/{deacon-CU47dU7U.js.map → deacon-B8oMMIgN.js.map} +1 -1
  47. package/dist/dashboard/{deacon-DYsOa_ss.js → deacon-b7J57Svt.js} +2 -2
  48. package/dist/dashboard/{deacon-pending-lifecycle-ijGX8wLb.js → deacon-pending-lifecycle-3NIJ7ew5.js} +2 -2
  49. package/dist/dashboard/{deacon-pending-lifecycle-ijGX8wLb.js.map → deacon-pending-lifecycle-3NIJ7ew5.js.map} +1 -1
  50. package/dist/dashboard/deacon.js +5 -5
  51. package/dist/dashboard/{delivery-DMYxIE0J.js → delivery-lnI-gQKo.js} +1 -1
  52. package/dist/dashboard/{deploy-patrol-C4eXco1S.js → deploy-patrol-u3v2krg9.js} +2 -2
  53. package/dist/dashboard/{deploy-patrol-C4eXco1S.js.map → deploy-patrol-u3v2krg9.js.map} +1 -1
  54. package/dist/dashboard/{feedback-stuck-retirement-Dd5XNrMr.js → feedback-stuck-retirement-CoFNqjCc.js} +2 -2
  55. package/dist/dashboard/{feedback-stuck-retirement-Dd5XNrMr.js.map → feedback-stuck-retirement-CoFNqjCc.js.map} +1 -1
  56. package/dist/dashboard/{feedback-target-BzdJ2wIR.js → feedback-target-BBCh3RRq.js} +1 -1
  57. package/dist/dashboard/{feedback-target-BcsA_GRV.js → feedback-target-CeCq6EhW.js} +5 -5
  58. package/dist/dashboard/{feedback-target-BcsA_GRV.js.map → feedback-target-CeCq6EhW.js.map} +1 -1
  59. package/dist/dashboard/{flywheel-Is3w2lcT.js → flywheel-DKldI63J.js} +7 -7
  60. package/dist/dashboard/{flywheel-Is3w2lcT.js.map → flywheel-DKldI63J.js.map} +1 -1
  61. package/dist/dashboard/{flywheel-D0guNqkh.js → flywheel-DpRPLErh.js} +7 -7
  62. package/dist/dashboard/{flywheel-D0guNqkh.js.map → flywheel-DpRPLErh.js.map} +1 -1
  63. package/dist/dashboard/{flywheel-B34cdfbd.js → flywheel-jeZFYvm-.js} +1 -1
  64. package/dist/dashboard/{flywheel-merge-order-6HiPR2WG.js → flywheel-merge-order-0OnoosaO.js} +1 -1
  65. package/dist/dashboard/{flywheel-merge-order-BsNPMu0S.js → flywheel-merge-order-PG5op4j7.js} +2 -2
  66. package/dist/dashboard/{flywheel-merge-order-BsNPMu0S.js.map → flywheel-merge-order-PG5op4j7.js.map} +1 -1
  67. package/dist/dashboard/{harness-resolve-CzTFVZ5l.js → harness-resolve-C0HWj3H9.js} +2 -2
  68. package/dist/dashboard/{harness-resolve-CzTFVZ5l.js.map → harness-resolve-C0HWj3H9.js.map} +1 -1
  69. package/dist/dashboard/{identity-Dc7rQLln.js → identity-Cot1Hg4G.js} +2 -2
  70. package/dist/dashboard/{identity-Dc7rQLln.js.map → identity-Cot1Hg4G.js.map} +1 -1
  71. package/dist/dashboard/{inspect-agent-CP7Bu47O.js → inspect-agent-BDmLWbGx.js} +3 -3
  72. package/dist/dashboard/{inspect-agent-CP7Bu47O.js.map → inspect-agent-BDmLWbGx.js.map} +1 -1
  73. package/dist/dashboard/inspect-agent-BcOkA-hC.js +2 -0
  74. package/dist/dashboard/{issue-lifecycle-BPbczKyy.js → issue-lifecycle-1B_v8Rf5.js} +6 -6
  75. package/dist/dashboard/{issue-lifecycle-BPbczKyy.js.map → issue-lifecycle-1B_v8Rf5.js.map} +1 -1
  76. package/dist/dashboard/{issue-lifecycle-FaugTi39.js → issue-lifecycle-CIrfbIbj.js} +1 -1
  77. package/dist/dashboard/{issue-service-singleton-Dsad9NTt.js → issue-service-singleton-BVwPzjwF.js} +1 -1
  78. package/dist/dashboard/{issue-service-singleton-BrZQJLRI.js → issue-service-singleton-KcRrOiFD.js} +2 -2
  79. package/dist/dashboard/{issue-service-singleton-BrZQJLRI.js.map → issue-service-singleton-KcRrOiFD.js.map} +1 -1
  80. package/dist/dashboard/{jsonl-resolver-DQEe0DHM.js → jsonl-resolver-jxbif7MD.js} +3 -3
  81. package/dist/dashboard/{jsonl-resolver-DQEe0DHM.js.map → jsonl-resolver-jxbif7MD.js.map} +1 -1
  82. package/dist/dashboard/{kimi-code-Cx5YUJpS.js → kimi-code-BZh3NgcN.js} +1 -1
  83. package/dist/dashboard/{lifecycle-DZFHmpGI.js → lifecycle-CvcZ4_fA.js} +4 -4
  84. package/dist/dashboard/{lifecycle-DZFHmpGI.js.map → lifecycle-CvcZ4_fA.js.map} +1 -1
  85. package/dist/dashboard/{linear-mcp-auth-DylPJABZ.js → linear-mcp-auth-CZoj_-d7.js} +1 -1
  86. package/dist/dashboard/{linear-mcp-auth-BFlpMvWh.js → linear-mcp-auth-Dx74yCAY.js} +2 -2
  87. package/dist/dashboard/{linear-mcp-auth-BFlpMvWh.js.map → linear-mcp-auth-Dx74yCAY.js.map} +1 -1
  88. package/dist/dashboard/{memory-governor-B7uDWRo9.js → memory-governor-Bv3LAqk3.js} +5 -5
  89. package/dist/dashboard/{memory-governor-B7uDWRo9.js.map → memory-governor-Bv3LAqk3.js.map} +1 -1
  90. package/dist/dashboard/{merge-agent-ddEcZDZD.js → merge-agent-1zVLl6k_.js} +1 -1
  91. package/dist/dashboard/{merge-agent-ttRY053V.js → merge-agent-8zrQu48t.js} +8 -8
  92. package/dist/dashboard/{merge-agent-ttRY053V.js.map → merge-agent-8zrQu48t.js.map} +1 -1
  93. package/dist/dashboard/merge-ops-CFJaMPLu.js +2 -0
  94. package/dist/dashboard/{merge-train-f_un38UJ.js → merge-train-BYH_cF7G.js} +2 -2
  95. package/dist/dashboard/{merge-train-f_un38UJ.js.map → merge-train-BYH_cF7G.js.map} +1 -1
  96. package/dist/dashboard/{merge-train-deps-GPlHOjK6.js → merge-train-deps-BTfXM5AR.js} +2 -2
  97. package/dist/dashboard/{merge-train-deps-GPlHOjK6.js.map → merge-train-deps-BTfXM5AR.js.map} +1 -1
  98. package/dist/dashboard/{messaging-BasbftDu.js → messaging-Bk6vGsMw.js} +1 -1
  99. package/dist/dashboard/{orphan-proposed-reconciler-DFHdQSEg.js → orphan-proposed-reconciler-B898fk26.js} +6 -6
  100. package/dist/dashboard/{orphan-proposed-reconciler-DFHdQSEg.js.map → orphan-proposed-reconciler-B898fk26.js.map} +1 -1
  101. package/dist/dashboard/{orphan-proposed-reconciler-DzAxrM99.js → orphan-proposed-reconciler-Bx_aWS4B.js} +1 -1
  102. package/dist/dashboard/{parked-residue-DMtbxJml.js → parked-residue-q2kzrYSm.js} +9 -9
  103. package/dist/dashboard/{parked-residue-DMtbxJml.js.map → parked-residue-q2kzrYSm.js.map} +1 -1
  104. package/dist/dashboard/{post-merge-lifecycle-worker-jzN2g_EY.js → post-merge-lifecycle-worker-Cl7-uf4g.js} +2 -2
  105. package/dist/dashboard/{post-merge-lifecycle-worker-jzN2g_EY.js.map → post-merge-lifecycle-worker-Cl7-uf4g.js.map} +1 -1
  106. package/dist/dashboard/{project-resource-refresh-queue-cqOeJ0fB.js → project-resource-refresh-queue-O_dRfPHn.js} +1 -1
  107. package/dist/dashboard/{project-resource-refresh-queue-DebwjPPA.js → project-resource-refresh-queue-se3T9IYP.js} +4 -4
  108. package/dist/dashboard/{project-resource-refresh-queue-DebwjPPA.js.map → project-resource-refresh-queue-se3T9IYP.js.map} +1 -1
  109. package/dist/dashboard/{reconstruct-cache-Bb2Jg2DZ.js → reconstruct-cache-XpWC9L0F.js} +2 -2
  110. package/dist/dashboard/{reconstruct-cache-Bb2Jg2DZ.js.map → reconstruct-cache-XpWC9L0F.js.map} +1 -1
  111. package/dist/dashboard/{release-engine-78iCajIc.js → release-engine-BuzxOamf.js} +2 -2
  112. package/dist/dashboard/{release-engine-78iCajIc.js.map → release-engine-BuzxOamf.js.map} +1 -1
  113. package/dist/dashboard/{remote-completion-D5wzZCte.js → remote-completion-BCZgeKPS.js} +3 -3
  114. package/dist/dashboard/{remote-completion-D5wzZCte.js.map → remote-completion-BCZgeKPS.js.map} +1 -1
  115. package/dist/dashboard/{resolver-BGZh3lXA.js → resolver-BeNrqNou.js} +5 -5
  116. package/dist/dashboard/{resolver-BGZh3lXA.js.map → resolver-BeNrqNou.js.map} +1 -1
  117. package/dist/dashboard/{resource-pressure-patrol-Bg23rPV-.js → resource-pressure-patrol-Ccg_aCgO.js} +3 -3
  118. package/dist/dashboard/{resource-pressure-patrol-Bg23rPV-.js.map → resource-pressure-patrol-Ccg_aCgO.js.map} +1 -1
  119. package/dist/dashboard/{resume-BKyB4hA1.js → resume-KGCrn0DV.js} +1 -1
  120. package/dist/dashboard/{review-agent-ZdP-HmwY.js → review-agent-BmM6YMZW.js} +1 -1
  121. package/dist/dashboard/{review-agent-DHs-JngN.js → review-agent-DRWVU8fP.js} +13 -13
  122. package/dist/dashboard/{review-agent-DHs-JngN.js.map → review-agent-DRWVU8fP.js.map} +1 -1
  123. package/dist/dashboard/{review-convoy-liveness-BTMvU4CA.js → review-convoy-liveness-EvCDv8Q_.js} +3 -3
  124. package/dist/dashboard/{review-convoy-liveness-BTMvU4CA.js.map → review-convoy-liveness-EvCDv8Q_.js.map} +1 -1
  125. package/dist/dashboard/{review-run-recovery-BYalQzbh.js → review-run-recovery-Ctm48Snt.js} +1 -1
  126. package/dist/dashboard/{review-run-recovery-BvVG3oUr.js → review-run-recovery-DNDI58cM.js} +2 -2
  127. package/dist/dashboard/{review-run-recovery-BvVG3oUr.js.map → review-run-recovery-DNDI58cM.js.map} +1 -1
  128. package/dist/dashboard/{review-status-DXTFzCmR.js → review-status-FnlvQuPI.js} +1 -1
  129. package/dist/dashboard/{review-status-emit-C9YW6SQL.js → review-status-emit-CeMS31DX.js} +2 -2
  130. package/dist/dashboard/{review-status-emit-C9YW6SQL.js.map → review-status-emit-CeMS31DX.js.map} +1 -1
  131. package/dist/dashboard/{review-status-BegAr86G.js → review-status-yY5qt7Rl.js} +5 -5
  132. package/dist/dashboard/{review-status-BegAr86G.js.map → review-status-yY5qt7Rl.js.map} +1 -1
  133. package/dist/dashboard/{review-verdict-feedback-qlVBi19-.js → review-verdict-feedback-BNgRj1e3.js} +4 -4
  134. package/dist/dashboard/{review-verdict-feedback-qlVBi19-.js.map → review-verdict-feedback-BNgRj1e3.js.map} +1 -1
  135. package/dist/dashboard/{review-verdict-feedback-Dp139Lmv.js → review-verdict-feedback-D39cuSV1.js} +1 -1
  136. package/dist/dashboard/{review-verdict-writer-CJr_Ob0Y.js → review-verdict-writer-DvFfKAn-.js} +2 -2
  137. package/dist/dashboard/{review-verdict-writer-CJr_Ob0Y.js.map → review-verdict-writer-DvFfKAn-.js.map} +1 -1
  138. package/dist/dashboard/{review-verdict-writer-BVco3WoI.js → review-verdict-writer-PcGBkvJ4.js} +1 -1
  139. package/dist/dashboard/{sequence-io-iljWlslY.js → sequence-io-DZyschsf.js} +2 -2
  140. package/dist/dashboard/{sequence-io-iljWlslY.js.map → sequence-io-DZyschsf.js.map} +1 -1
  141. package/dist/dashboard/{sequencer-agent-BGGVKxtw.js → sequencer-agent-BXDw5cNx.js} +5 -5
  142. package/dist/dashboard/{sequencer-agent-BGGVKxtw.js.map → sequencer-agent-BXDw5cNx.js.map} +1 -1
  143. package/dist/dashboard/server.js +79 -72
  144. package/dist/dashboard/server.js.map +1 -1
  145. package/dist/dashboard/{service-kzhN0DLg.js → service-DP50Omvn.js} +33 -33
  146. package/dist/dashboard/{service-kzhN0DLg.js.map → service-DP50Omvn.js.map} +1 -1
  147. package/dist/dashboard/{smart-compaction-owKHJDbL.js → smart-compaction-944GL8PN.js} +1 -1
  148. package/dist/dashboard/{smart-compaction-C96F2aFQ.js → smart-compaction-BzDfF6yb.js} +2 -2
  149. package/dist/dashboard/{smart-compaction-C96F2aFQ.js.map → smart-compaction-BzDfF6yb.js.map} +1 -1
  150. package/dist/dashboard/{spawn-planning-session-CiJdOHTD.js → spawn-planning-session-BcVnHJjm.js} +1 -1
  151. package/dist/dashboard/{spawn-planning-session-FmJa6PCS.js → spawn-planning-session-CH8IYli7.js} +3 -3
  152. package/dist/dashboard/{spawn-planning-session-FmJa6PCS.js.map → spawn-planning-session-CH8IYli7.js.map} +1 -1
  153. package/dist/dashboard/{specialist-context-_ootmzn2.js → specialist-context-DhDTXVht.js} +3 -3
  154. package/dist/dashboard/{specialist-context-_ootmzn2.js.map → specialist-context-DhDTXVht.js.map} +1 -1
  155. package/dist/dashboard/{specialist-logs-BbAX221-.js → specialist-logs-C1bcnZ-G.js} +2 -2
  156. package/dist/dashboard/{specialist-logs-BbAX221-.js.map → specialist-logs-C1bcnZ-G.js.map} +1 -1
  157. package/dist/dashboard/{specialists-COZoYaiz.js → specialists-BKmReEWT.js} +53 -53
  158. package/dist/dashboard/{specialists-COZoYaiz.js.map → specialists-BKmReEWT.js.map} +1 -1
  159. package/dist/dashboard/{specialists-RPLJnYc1.js → specialists-Bvrvt0br.js} +12 -12
  160. package/dist/dashboard/{specialists-RPLJnYc1.js.map → specialists-Bvrvt0br.js.map} +1 -1
  161. package/dist/dashboard/{specialists-DTAOVZpU.js → specialists-CD6GEKXk.js} +1 -1
  162. package/dist/dashboard/{specialists-D8sYZnPb.js → specialists-eFWpJRBc.js} +1 -1
  163. package/dist/dashboard/{stall-sweeper-9bRBZhrQ.js → stall-sweeper-D3fZvg7O.js} +3 -3
  164. package/dist/dashboard/{stall-sweeper-9bRBZhrQ.js.map → stall-sweeper-D3fZvg7O.js.map} +1 -1
  165. package/dist/dashboard/{state-migrate-J3tFJnbd.js → state-migrate-KZ2goscQ.js} +2 -2
  166. package/dist/dashboard/{state-migrate-J3tFJnbd.js.map → state-migrate-KZ2goscQ.js.map} +1 -1
  167. package/dist/dashboard/{stuck-remediation-BvTK_NYN.js → stuck-remediation-Cb2V1roj.js} +1 -1
  168. package/dist/dashboard/{stuck-remediation-4Rf_xMEb.js → stuck-remediation-CnoV0kcv.js} +5 -5
  169. package/dist/dashboard/{stuck-remediation-4Rf_xMEb.js.map → stuck-remediation-CnoV0kcv.js.map} +1 -1
  170. package/dist/dashboard/{summary-fork-PLcckTRE.js → summary-fork-CxuNBM0F.js} +2 -2
  171. package/dist/dashboard/{summary-fork-D-cylknJ.js → summary-fork-lC2vMXly.js} +4 -4
  172. package/dist/dashboard/{summary-fork-D-cylknJ.js.map → summary-fork-lC2vMXly.js.map} +1 -1
  173. package/dist/dashboard/{teardown-workspace-CTL16rnG.js → teardown-workspace-C-9murBw.js} +4 -4
  174. package/dist/dashboard/{teardown-workspace-CTL16rnG.js.map → teardown-workspace-C-9murBw.js.map} +1 -1
  175. package/dist/dashboard/{test-agent-queue-CMgYZiR_.js → test-agent-queue-YCBRzaAB.js} +3 -3
  176. package/dist/dashboard/{test-agent-queue-CMgYZiR_.js.map → test-agent-queue-YCBRzaAB.js.map} +1 -1
  177. package/dist/dashboard/{uat-failure-feedback-DS6W9X3I.js → uat-failure-feedback-B-1mL8Zp.js} +3 -3
  178. package/dist/dashboard/{uat-failure-feedback-DS6W9X3I.js.map → uat-failure-feedback-B-1mL8Zp.js.map} +1 -1
  179. package/dist/dashboard/{uat-promote-verification-CRsIHE_q.js → uat-promote-verification-BEBPcpPg.js} +2 -2
  180. package/dist/dashboard/{uat-promote-verification-CRsIHE_q.js.map → uat-promote-verification-BEBPcpPg.js.map} +1 -1
  181. package/dist/dashboard/{uat-train-BoA9r6_I.js → uat-train-BFo3OQUB.js} +1 -1
  182. package/dist/dashboard/{uat-train-Cd8CJeNe.js → uat-train-COgoJomz.js} +8 -8
  183. package/dist/dashboard/{uat-train-Cd8CJeNe.js.map → uat-train-COgoJomz.js.map} +1 -1
  184. package/dist/dashboard/{validate-BdmvTIym.js → validate-069_N1e2.js} +2 -2
  185. package/dist/dashboard/{validate-BdmvTIym.js.map → validate-069_N1e2.js.map} +1 -1
  186. package/dist/dashboard/{verification-runner-BO0K3xNA.js → verification-runner-CQnZyC5A.js} +1 -1
  187. package/dist/dashboard/{verification-runner-fEY1Qj-l.js → verification-runner-fy3wNrWn.js} +4 -4
  188. package/dist/dashboard/{verification-runner-fEY1Qj-l.js.map → verification-runner-fy3wNrWn.js.map} +1 -1
  189. package/dist/dashboard/workflows-Bk6Kt0ZQ.js +2 -0
  190. package/dist/dashboard/{workflows-CxVnygYU.js → workflows-N4QMkDzN.js} +10 -10
  191. package/dist/dashboard/{workflows-CxVnygYU.js.map → workflows-N4QMkDzN.js.map} +1 -1
  192. package/dist/dashboard/{workspaces-Cpz0xJWQ.js → workspaces-DmoyfHoU.js} +33 -33
  193. package/dist/dashboard/{workspaces-Cpz0xJWQ.js.map → workspaces-DmoyfHoU.js.map} +1 -1
  194. package/dist/{lifecycle-C6k0HWEO.js → lifecycle-DCFcjg7y.js} +1 -1
  195. package/dist/{lifecycle-D5oRpvvB.js → lifecycle-GkaHQJNK.js} +2 -2
  196. package/dist/{lifecycle-D5oRpvvB.js.map → lifecycle-GkaHQJNK.js.map} +1 -1
  197. package/dist/{merge-agent-Drufc7tU.js → merge-agent-CogNFasY.js} +2 -2
  198. package/dist/{merge-agent-Drufc7tU.js.map → merge-agent-CogNFasY.js.map} +1 -1
  199. package/dist/{merge-agent-CBOVY_eC.js → merge-agent-eteKQ9Rb.js} +1 -1
  200. package/package.json +1 -1
  201. package/dist/build-info-BgrwLUy6.js +0 -2
  202. package/dist/dashboard/agent-state-Ci6PhjOE.js.map +0 -1
  203. package/dist/dashboard/build-info-CYlxvZSQ.js +0 -2
  204. package/dist/dashboard/cli-ZAS502uC.js +0 -2
  205. package/dist/dashboard/conversation-service-Dlks_hSS.js +0 -3
  206. package/dist/dashboard/inspect-agent-DTuSg95i.js +0 -2
  207. package/dist/dashboard/merge-ops-Bgc-EScO.js +0 -2
  208. package/dist/dashboard/workflows-CgGNyl1z.js +0 -2
@@ -1,4 +1,4 @@
1
1
  import "./config-yaml-Dce9VUd6.js";
2
- import { E as handleAgentStoppedForOrphanReviewerSessions, T as handleAgentStoppedEvent, ct as handleWorkCompleted, st as handleReviewCoordinatorDied, w as handleAgentHeartbeatDeadEvent } from "./deacon-CU47dU7U.js";
3
- import "./parked-residue-DMtbxJml.js";
2
+ import { E as handleAgentStoppedForOrphanReviewerSessions, T as handleAgentStoppedEvent, ct as handleWorkCompleted, st as handleReviewCoordinatorDied, w as handleAgentHeartbeatDeadEvent } from "./deacon-B8oMMIgN.js";
3
+ import "./parked-residue-q2kzrYSm.js";
4
4
  export { handleAgentHeartbeatDeadEvent, handleAgentStoppedEvent, handleAgentStoppedForOrphanReviewerSessions, handleReviewCoordinatorDied, handleWorkCompleted };
@@ -18,7 +18,7 @@ async function processPendingLifecycleForPatrol(pendingFile) {
18
18
  }
19
19
  console.log(`[deacon] Processing pending post-merge lifecycle for ${pending.issueId} (age: ${Math.round(age / 1e3)}s)`);
20
20
  try {
21
- const { postMergeLifecycle } = await import("./merge-agent-ddEcZDZD.js");
21
+ const { postMergeLifecycle } = await import("./merge-agent-1zVLl6k_.js");
22
22
  await postMergeLifecycle(pending.issueId, pending.projectPath, pending.sourceBranch, { skipDeploy: true });
23
23
  await settlePendingLifecycleClaim(claim, pending.issueId, true);
24
24
  return `Processed pending post-merge lifecycle for ${pending.issueId}`;
@@ -30,4 +30,4 @@ async function processPendingLifecycleForPatrol(pendingFile) {
30
30
  //#endregion
31
31
  export { processPendingLifecycleForPatrol };
32
32
 
33
- //# sourceMappingURL=deacon-pending-lifecycle-ijGX8wLb.js.map
33
+ //# sourceMappingURL=deacon-pending-lifecycle-3NIJ7ew5.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"deacon-pending-lifecycle-ijGX8wLb.js","names":[],"sources":["../../src/lib/cloister/deacon-pending-lifecycle.ts"],"sourcesContent":["import {\n claimPendingLifecycleFile,\n settlePendingLifecycleClaim,\n} from './pending-lifecycle-claim.js';\n\ninterface PendingLifecycleData {\n issueId: string;\n projectPath: string;\n sourceBranch?: string;\n timestamp?: number;\n}\n\nexport async function processPendingLifecycleForPatrol(\n pendingFile: string,\n): Promise<string | null> {\n const claim = await claimPendingLifecycleFile(pendingFile);\n if (!claim) return null;\n\n let pending: PendingLifecycleData;\n try {\n pending = JSON.parse(claim.raw) as PendingLifecycleData;\n } catch (error) {\n await claim.discard();\n throw error;\n }\n\n const age = Date.now() - (pending.timestamp ?? 0);\n if (age >= 60 * 60 * 1000) {\n await claim.discard();\n console.log(`[deacon] Discarded stale pending post-merge claim (age: ${Math.round(age / 60000)}m)`);\n return null;\n }\n\n console.log(`[deacon] Processing pending post-merge lifecycle for ${pending.issueId} (age: ${Math.round(age / 1000)}s)`);\n try {\n const { postMergeLifecycle } = await import('./merge-agent.js');\n await postMergeLifecycle(pending.issueId, pending.projectPath, pending.sourceBranch, { skipDeploy: true });\n await settlePendingLifecycleClaim(claim, pending.issueId, true);\n return `Processed pending post-merge lifecycle for ${pending.issueId}`;\n } catch (error) {\n await settlePendingLifecycleClaim(claim, pending.issueId, false);\n throw error;\n }\n}\n"],"mappings":";;AAYA,eAAsB,iCACpB,aACwB;CACxB,MAAM,QAAQ,MAAM,0BAA0B,YAAY;AAC1D,KAAI,CAAC,MAAO,QAAO;CAEnB,IAAI;AACJ,KAAI;AACF,YAAU,KAAK,MAAM,MAAM,IAAI;UACxB,OAAO;AACd,QAAM,MAAM,SAAS;AACrB,QAAM;;CAGR,MAAM,MAAM,KAAK,KAAK,IAAI,QAAQ,aAAa;AAC/C,KAAI,OAAO,OAAU,KAAM;AACzB,QAAM,MAAM,SAAS;AACrB,UAAQ,IAAI,2DAA2D,KAAK,MAAM,MAAM,IAAM,CAAC,IAAI;AACnG,SAAO;;AAGT,SAAQ,IAAI,wDAAwD,QAAQ,QAAQ,SAAS,KAAK,MAAM,MAAM,IAAK,CAAC,IAAI;AACxH,KAAI;EACF,MAAM,EAAE,uBAAuB,MAAM,OAAO;AAC5C,QAAM,mBAAmB,QAAQ,SAAS,QAAQ,aAAa,QAAQ,cAAc,EAAE,YAAY,MAAM,CAAC;AAC1G,QAAM,4BAA4B,OAAO,QAAQ,SAAS,KAAK;AAC/D,SAAO,8CAA8C,QAAQ;UACtD,OAAO;AACd,QAAM,4BAA4B,OAAO,QAAQ,SAAS,MAAM;AAChE,QAAM"}
1
+ {"version":3,"file":"deacon-pending-lifecycle-3NIJ7ew5.js","names":[],"sources":["../../src/lib/cloister/deacon-pending-lifecycle.ts"],"sourcesContent":["import {\n claimPendingLifecycleFile,\n settlePendingLifecycleClaim,\n} from './pending-lifecycle-claim.js';\n\ninterface PendingLifecycleData {\n issueId: string;\n projectPath: string;\n sourceBranch?: string;\n timestamp?: number;\n}\n\nexport async function processPendingLifecycleForPatrol(\n pendingFile: string,\n): Promise<string | null> {\n const claim = await claimPendingLifecycleFile(pendingFile);\n if (!claim) return null;\n\n let pending: PendingLifecycleData;\n try {\n pending = JSON.parse(claim.raw) as PendingLifecycleData;\n } catch (error) {\n await claim.discard();\n throw error;\n }\n\n const age = Date.now() - (pending.timestamp ?? 0);\n if (age >= 60 * 60 * 1000) {\n await claim.discard();\n console.log(`[deacon] Discarded stale pending post-merge claim (age: ${Math.round(age / 60000)}m)`);\n return null;\n }\n\n console.log(`[deacon] Processing pending post-merge lifecycle for ${pending.issueId} (age: ${Math.round(age / 1000)}s)`);\n try {\n const { postMergeLifecycle } = await import('./merge-agent.js');\n await postMergeLifecycle(pending.issueId, pending.projectPath, pending.sourceBranch, { skipDeploy: true });\n await settlePendingLifecycleClaim(claim, pending.issueId, true);\n return `Processed pending post-merge lifecycle for ${pending.issueId}`;\n } catch (error) {\n await settlePendingLifecycleClaim(claim, pending.issueId, false);\n throw error;\n }\n}\n"],"mappings":";;AAYA,eAAsB,iCACpB,aACwB;CACxB,MAAM,QAAQ,MAAM,0BAA0B,YAAY;AAC1D,KAAI,CAAC,MAAO,QAAO;CAEnB,IAAI;AACJ,KAAI;AACF,YAAU,KAAK,MAAM,MAAM,IAAI;UACxB,OAAO;AACd,QAAM,MAAM,SAAS;AACrB,QAAM;;CAGR,MAAM,MAAM,KAAK,KAAK,IAAI,QAAQ,aAAa;AAC/C,KAAI,OAAO,OAAU,KAAM;AACzB,QAAM,MAAM,SAAS;AACrB,UAAQ,IAAI,2DAA2D,KAAK,MAAM,MAAM,IAAM,CAAC,IAAI;AACnG,SAAO;;AAGT,SAAQ,IAAI,wDAAwD,QAAQ,QAAQ,SAAS,KAAK,MAAM,MAAM,IAAK,CAAC,IAAI;AACxH,KAAI;EACF,MAAM,EAAE,uBAAuB,MAAM,OAAO;AAC5C,QAAM,mBAAmB,QAAQ,SAAS,QAAQ,aAAa,QAAQ,cAAc,EAAE,YAAY,MAAM,CAAC;AAC1G,QAAM,4BAA4B,OAAO,QAAQ,SAAS,KAAK;AAC/D,SAAO,8CAA8C,QAAQ;UACtD,OAAO;AACd,QAAM,4BAA4B,OAAO,QAAQ,SAAS,MAAM;AAChE,QAAM"}
@@ -1,12 +1,12 @@
1
1
  import { Ct as flushAllPendingAutoCommits, Tt as init_auto_commit } from "./config-yaml-Dce9VUd6.js";
2
2
  import { l as init_activity_logger, u as setActivityEventStoreProvider } from "./activity-logger-DNYDzAOU.js";
3
- import { m as getAgentState, q as init_agents } from "./agent-state-Ci6PhjOE.js";
3
+ import { m as getAgentState, q as init_agents } from "./agent-state-B196fj1h.js";
4
4
  import { i as ensureInternalTokenSync, s as init_internal_token } from "./internal-token-Ci0LxMIq.js";
5
- import { d as getReviewStatusSync, p as init_review_status } from "./review-status-BegAr86G.js";
6
- import { F as setAgentStatusChangedNotifier, I as setAgentStoppedNotifier, L as setMergeReadyNotifier, M as resetPatrolHeartbeatForStartup, N as runPatrol } from "./deacon-CU47dU7U.js";
7
- import { t as getCloisterService } from "./service-kzhN0DLg.js";
5
+ import { d as getReviewStatusSync, p as init_review_status } from "./review-status-yY5qt7Rl.js";
6
+ import { F as setAgentStatusChangedNotifier, I as setAgentStoppedNotifier, L as setMergeReadyNotifier, M as resetPatrolHeartbeatForStartup, N as runPatrol } from "./deacon-B8oMMIgN.js";
7
+ import { t as getCloisterService } from "./service-DP50Omvn.js";
8
8
  import { n as setCloisterEventStoreProvider } from "./event-store-provider-B2PMoaap.js";
9
- import { t as emitReviewStatusChanged } from "./review-status-emit-C9YW6SQL.js";
9
+ import { t as emitReviewStatusChanged } from "./review-status-emit-CeMS31DX.js";
10
10
  import { n as init_deacon_event_client, t as createDeaconEventClient } from "./deacon-event-client-DY8U1EbU.js";
11
11
  import { Effect } from "effect";
12
12
  import { randomUUID } from "node:crypto";
@@ -1,3 +1,3 @@
1
- import { Or as init_delivery, wr as deliverAgentMessage } from "./agent-state-Ci6PhjOE.js";
1
+ import { Or as init_delivery, wr as deliverAgentMessage } from "./agent-state-B196fj1h.js";
2
2
  init_delivery();
3
3
  export { deliverAgentMessage };
@@ -1,5 +1,5 @@
1
1
  import { Ri as init_paths, vi as OVERDECK_HOME } from "./config-yaml-Dce9VUd6.js";
2
- import { t as getBuildInfo } from "./build-info-Cj3Y0K87.js";
2
+ import { t as getBuildInfo } from "./build-info-D0EJNj6C.js";
3
3
  import { l as init_activity_logger, o as emitActivityEntrySync, s as emitActivityTtsSync } from "./activity-logger-DNYDzAOU.js";
4
4
  import { a as loadCloisterConfigSync, r as init_config } from "./config-B-MLcKSo.js";
5
5
  import { r as computeBuildStaleness } from "./staleness-CyM7ACHv.js";
@@ -342,4 +342,4 @@ async function runScheduledDeployPatrol() {
342
342
  //#endregion
343
343
  export { runScheduledDeployPatrol };
344
344
 
345
- //# sourceMappingURL=deploy-patrol-C4eXco1S.js.map
345
+ //# sourceMappingURL=deploy-patrol-u3v2krg9.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"deploy-patrol-C4eXco1S.js","names":[],"sources":["../../src/lib/cloister/deploy-patrol.ts"],"sourcesContent":["import { open, mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { execFile, spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\n\nimport { emitActivityEntrySync, emitActivityTtsSync } from '../activity-logger.js';\nimport { getBuildInfo } from '../deploy/build-info.js';\nimport {\n clearPendingDeploy,\n markPendingDeployEscalated,\n readPendingDeploy,\n recordDeployIntent,\n type PendingDeploy,\n} from '../deploy/deploy-queue.js';\nimport {\n getDeployWindowAssessment,\n type DeployWindowAssessment,\n} from '../deploy/deploy-window.js';\nimport { computeBuildStaleness, type BuildStaleness } from '../deploy/staleness.js';\nimport { OVERDECK_HOME } from '../paths.js';\nimport { loadCloisterConfigSync, type DeployConfig } from './config.js';\n\nconst OBSERVATION_INTERVAL_MS = 30 * 60 * 1000;\nconst DEPLOY_SPAWN_COOLDOWN_MS = 10 * 60 * 1000;\nconst DEPLOY_PATROL_INITIATOR = 'deploy-patrol';\nconst CI_WORKFLOW_FILE = 'ci.yml';\nconst CI_RUN_FIELDS = 'databaseId,status,conclusion,headSha,attempt,createdAt';\nconst SYSTEMD_ENV_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\ninterface DeployPatrolState {\n lastObservedBehind: number | null;\n lastObservationAt: number;\n lastDeferralReason: string | null;\n lastDeferralAt: number;\n lastDeploySpawnAt: number;\n lastEscalationReason: string | null;\n lastEscalationAt: number;\n unknownObserved: boolean;\n}\n\nconst state: DeployPatrolState = {\n lastObservedBehind: null,\n lastObservationAt: 0,\n lastDeferralReason: null,\n lastDeferralAt: 0,\n lastDeploySpawnAt: 0,\n lastEscalationReason: null,\n lastEscalationAt: 0,\n unknownObserved: false,\n};\n\ntype EmitEntry = typeof emitActivityEntrySync;\ntype EmitTts = typeof emitActivityTtsSync;\n\nexport interface DeployCiState {\n readonly status: 'green' | 'pending' | 'red' | 'unknown';\n readonly reason?: string;\n}\n\ninterface DeployCiRun {\n readonly databaseId: number;\n readonly status: string;\n readonly conclusion: string | null;\n readonly headSha: string;\n readonly attempt: number;\n readonly createdAt: string;\n}\n\nexport interface DeployPatrolContext {\n readonly repoRoot: string;\n readonly config: DeployConfig;\n readonly computeStaleness?: () => Promise<BuildStaleness>;\n readonly getCiState?: (sha: string) => Promise<DeployCiState>;\n readonly getWindowAssessment?: () => Promise<DeployWindowAssessment>;\n readonly readQueue?: typeof readPendingDeploy;\n readonly clearQueue?: typeof clearPendingDeploy;\n readonly recordIntent?: typeof recordDeployIntent;\n readonly markQueueEscalated?: typeof markPendingDeployEscalated;\n readonly spawnReload?: (request: ReloadRequest) => Promise<void>;\n readonly emitEntry?: EmitEntry;\n readonly emitTts?: EmitTts;\n readonly now?: () => number;\n}\n\nexport interface ReloadRequest {\n readonly command: string;\n readonly args: readonly string[];\n readonly cwd: string;\n readonly detached: true;\n readonly initiator: string;\n}\n\nfunction reloadEnvironment(request: ReloadRequest, env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n return { ...env, OVERDECK_AGENT_ID: request.initiator };\n}\n\nfunction execGh(args: readonly string[], cwd: string): Promise<string> {\n return new Promise((resolve, reject) => {\n execFile('gh', [...args], { cwd, encoding: 'utf8', timeout: 30_000 }, (error, stdout) => {\n if (error) reject(error);\n else resolve(stdout);\n });\n });\n}\n\nexport async function getDeployCiState(\n repoRoot: string,\n sha: string,\n runGh: (args: readonly string[], cwd: string) => Promise<string> = execGh,\n): Promise<DeployCiState> {\n try {\n const runs = JSON.parse(await runGh([\n 'run', 'list',\n '--branch', 'main',\n '--commit', sha,\n '--workflow', CI_WORKFLOW_FILE,\n '--limit', '10',\n '--json', CI_RUN_FIELDS,\n ], repoRoot)) as DeployCiRun[];\n const run = runs.find((candidate) => candidate.headSha === sha);\n const tip = shortSha(sha);\n\n if (!run) {\n return {\n status: 'pending',\n reason: `Automatic deployment deferred because CI has not started for origin/main ${tip}.`,\n };\n }\n if (run.status !== 'completed') {\n return {\n status: 'pending',\n reason: `Automatic deployment deferred because CI is ${run.status} for origin/main ${tip}.`,\n };\n }\n if (run.conclusion !== 'success') {\n return {\n status: 'red',\n reason: `Automatic deployment blocked because CI concluded ${run.conclusion || 'without a result'} for origin/main ${tip}.`,\n };\n }\n return { status: 'green' };\n } catch (error) {\n return {\n status: 'unknown',\n reason: `Automatic deployment deferred because CI status for origin/main ${shortSha(sha)} could not be read: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n}\n\nexport function buildSystemdReloadArgs(\n request: ReloadRequest,\n now: number,\n logPath: string,\n env: NodeJS.ProcessEnv = process.env,\n): string[] {\n const setenvArgs = Object.entries(reloadEnvironment(request, env))\n .filter(([name, value]) => value !== undefined && SYSTEMD_ENV_NAME_RE.test(name))\n .flatMap(([name, value]) => ['--setenv', `${name}=${value}`]);\n\n return [\n '--user', '--unit', `overdeck-auto-deploy-${now}`,\n '--collect', '--quiet',\n '--property=Restart=on-failure',\n '--property=RestartSec=10s',\n '--property=StartLimitIntervalSec=0',\n `--property=StandardOutput=append:${logPath}`,\n `--property=StandardError=append:${logPath}`,\n `--property=WorkingDirectory=${request.cwd}`,\n ...setenvArgs,\n request.command,\n ...request.args,\n ];\n}\n\nfunction shortSha(sha: string | null): string {\n return sha?.slice(0, 8) || 'unknown';\n}\n\nexport async function waitForChildSpawn(\n child: Pick<ChildProcess, 'once' | 'removeListener' | 'unref'>,\n): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const onSpawn = () => {\n cleanup();\n child.unref();\n resolve();\n };\n const onError = (error: Error) => {\n cleanup();\n reject(error);\n };\n const cleanup = () => {\n child.removeListener('spawn', onSpawn);\n child.removeListener('error', onError);\n };\n\n child.once('spawn', onSpawn);\n child.once('error', onError);\n });\n}\n\nasync function waitForChildExit(child: ChildProcess): Promise<number> {\n return new Promise<number>((resolve, reject) => {\n child.once('error', reject);\n child.once('close', (code) => resolve(code ?? 1));\n });\n}\n\nasync function spawnDetachedReload(request: ReloadRequest, now: number): Promise<void> {\n const logsDir = join(OVERDECK_HOME, 'logs');\n const logPath = join(logsDir, 'auto-deploy.log');\n await mkdir(logsDir, { recursive: true });\n await writeFile(\n join(OVERDECK_HOME, 'dashboard-restarting.json'),\n JSON.stringify({ reason: 'auto-deploy', trigger: 'deacon', timestamp: now }, null, 2),\n 'utf8',\n );\n\n const log = await open(logPath, 'a');\n try {\n if (process.platform === 'linux') {\n let systemdFailure: string | null = null;\n try {\n const launcher = spawn(\n 'systemd-run',\n buildSystemdReloadArgs(request, now, logPath),\n {\n cwd: request.cwd,\n stdio: ['ignore', log.fd, log.fd],\n },\n );\n const exitCode = await waitForChildExit(launcher);\n if (exitCode === 0) return;\n systemdFailure = `systemd-run exited ${exitCode}`;\n } catch (error) {\n systemdFailure = error instanceof Error ? error.message : String(error);\n }\n throw new Error(\n `Automatic deploy requires an independent systemd unit before it can stop the dashboard: ${systemdFailure}`,\n );\n }\n\n const child = spawn(\n request.command,\n [...request.args],\n {\n cwd: request.cwd,\n detached: request.detached,\n env: reloadEnvironment(request, process.env),\n stdio: ['ignore', log.fd, log.fd],\n },\n );\n await waitForChildSpawn(child);\n } finally {\n await log.close();\n }\n}\n\nfunction clearState(): void {\n state.lastObservedBehind = null;\n state.lastObservationAt = 0;\n state.lastDeferralReason = null;\n state.lastDeferralAt = 0;\n state.lastDeploySpawnAt = 0;\n state.lastEscalationReason = null;\n state.lastEscalationAt = 0;\n state.unknownObserved = false;\n}\n\nfunction emitDeferral(reason: string, now: number, emitEntry: EmitEntry): void {\n if (\n state.lastDeferralReason === reason &&\n now - state.lastDeferralAt < OBSERVATION_INTERVAL_MS\n ) return;\n\n emitEntry({\n source: 'deploy-script',\n level: 'warn',\n message: reason,\n });\n state.lastDeferralReason = reason;\n state.lastDeferralAt = now;\n}\n\nasync function refreshQueuedDeployReason(\n queuedDeploy: PendingDeploy | null,\n reason: string,\n context: DeployPatrolContext,\n): Promise<void> {\n if (!queuedDeploy) return;\n await (context.recordIntent ?? recordDeployIntent)({\n requestedBy: DEPLOY_PATROL_INITIATOR,\n reason,\n blockedBy: [],\n });\n}\n\nasync function escalateOverdueQueue(\n queuedDeploy: PendingDeploy | null,\n blockReason: string,\n context: DeployPatrolContext,\n now: number,\n emitEntry: EmitEntry,\n emitTts: EmitTts,\n): Promise<void> {\n if (\n !queuedDeploy\n || queuedDeploy.escalated\n || now - Date.parse(queuedDeploy.requestedAt) <= context.config.queue_deadline_minutes * 60_000\n ) return;\n\n const ageMinutes = Math.floor((now - Date.parse(queuedDeploy.requestedAt)) / 60_000);\n const message = `Queued dashboard deploy has waited ${ageMinutes} minutes; current block: ${blockReason}`;\n if (\n state.lastEscalationReason !== blockReason\n || now - state.lastEscalationAt >= OBSERVATION_INTERVAL_MS\n ) {\n emitEntry({ source: 'deploy-script', level: 'error', message });\n emitTts({\n utterance: `Dashboard deploy has been queued for ${ageMinutes} minutes and needs attention.`,\n priority: 1,\n source: 'deploy-script',\n eventType: 'deploy_queue_stuck',\n });\n state.lastEscalationReason = blockReason;\n state.lastEscalationAt = now;\n }\n\n await (context.markQueueEscalated ?? markPendingDeployEscalated)();\n}\n\nexport async function runDeployPatrol(context: DeployPatrolContext): Promise<void> {\n const now = (context.now ?? Date.now)();\n const emitEntry = context.emitEntry ?? emitActivityEntrySync;\n const emitTts = context.emitTts ?? emitActivityTtsSync;\n const staleness = await (context.computeStaleness ?? (() => computeBuildStaleness({\n repoRoot: context.repoRoot,\n buildCommit: getBuildInfo().buildCommit,\n })))();\n const queuedDeploy = await (context.readQueue ?? readPendingDeploy)();\n\n if (staleness.status === 'unknown') {\n const reason = `Automatic deployment cannot compare the running build with origin/main: ${staleness.reason ?? 'build staleness is unknown'}`;\n if (!state.unknownObserved) {\n emitEntry({\n source: 'deploy-script',\n level: 'warn',\n message: reason,\n });\n state.unknownObserved = true;\n }\n await refreshQueuedDeployReason(queuedDeploy, reason, context);\n await escalateOverdueQueue(queuedDeploy, reason, context, now, emitEntry, emitTts);\n return;\n }\n\n if (staleness.status === 'fresh') {\n clearState();\n await (context.clearQueue ?? clearPendingDeploy)();\n return;\n }\n\n state.unknownObserved = false;\n const behind = staleness.behindBuildInputs ?? 0;\n if (\n state.lastObservedBehind !== behind ||\n now - state.lastObservationAt >= OBSERVATION_INTERVAL_MS\n ) {\n emitEntry({\n source: 'deploy-script',\n level: 'warn',\n message: `The running build ${shortSha(staleness.buildCommit)} is ${behind} build-input commit(s) behind origin/main ${shortSha(staleness.originMainSha)}. ${context.config.auto_deploy || queuedDeploy ? 'Automatic deployment will start after the merge debounce and safety checks clear.' : 'Automatic deployment is disabled, so operator action is required.'}`,\n });\n state.lastObservedBehind = behind;\n state.lastObservationAt = now;\n }\n\n if (!context.config.auto_deploy && !queuedDeploy) return;\n if (\n staleness.originMainLastBuildInputCommitAt !== null\n && now - staleness.originMainLastBuildInputCommitAt < context.config.debounce_minutes * 60 * 1000\n ) {\n const reason = 'Automatic deployment deferred because the merge debounce has not elapsed.';\n await refreshQueuedDeployReason(queuedDeploy, reason, context);\n await escalateOverdueQueue(queuedDeploy, reason, context, now, emitEntry, emitTts);\n return;\n }\n if (state.lastDeploySpawnAt > 0 && now - state.lastDeploySpawnAt < DEPLOY_SPAWN_COOLDOWN_MS) {\n const reason = 'Automatic deployment deferred because a recent deploy is still inside the spawn cooldown.';\n await refreshQueuedDeployReason(queuedDeploy, reason, context);\n await escalateOverdueQueue(queuedDeploy, reason, context, now, emitEntry, emitTts);\n return;\n }\n\n if (!staleness.originMainSha) {\n const reason = 'Automatic deployment deferred because the origin/main commit is unknown.';\n emitDeferral(reason, now, emitEntry);\n await refreshQueuedDeployReason(queuedDeploy, reason, context);\n await escalateOverdueQueue(queuedDeploy, reason, context, now, emitEntry, emitTts);\n return;\n }\n const ciState = await (context.getCiState ?? ((sha) => getDeployCiState(context.repoRoot, sha)))(staleness.originMainSha);\n if (ciState.status !== 'green') {\n const reason = ciState.reason\n ?? `Automatic deployment deferred because CI is ${ciState.status} for origin/main ${shortSha(staleness.originMainSha)}.`;\n emitDeferral(reason, now, emitEntry);\n await refreshQueuedDeployReason(queuedDeploy, reason, context);\n await escalateOverdueQueue(queuedDeploy, reason, context, now, emitEntry, emitTts);\n return;\n }\n\n const assessment = await (context.getWindowAssessment ?? getDeployWindowAssessment)();\n if (assessment.reason) {\n emitDeferral(assessment.reason, now, emitEntry);\n if (context.config.auto_deploy || queuedDeploy) {\n await (context.recordIntent ?? recordDeployIntent)({\n requestedBy: DEPLOY_PATROL_INITIATOR,\n reason: assessment.reason,\n blockedBy: [],\n });\n }\n await escalateOverdueQueue(\n queuedDeploy,\n assessment.reason,\n context,\n now,\n emitEntry,\n emitTts,\n );\n return;\n }\n\n const reloadRequest: ReloadRequest = {\n command: process.execPath,\n args: [join(context.repoRoot, 'dist/cli/index.js'), 'reload', '--health-timeout', '120000'],\n cwd: context.repoRoot,\n detached: true,\n initiator: DEPLOY_PATROL_INITIATOR,\n };\n await (context.spawnReload ?? ((request) => spawnDetachedReload(request, now)))(reloadRequest);\n state.lastDeploySpawnAt = now;\n state.lastDeferralReason = null;\n state.lastDeferralAt = 0;\n emitEntry({\n source: 'deploy-script',\n level: 'info',\n message: `Automatic deployment started for origin/main ${shortSha(staleness.originMainSha)}; the dashboard will rebuild and restart with a 120-second health timeout.${queuedDeploy ? ` This was a queued deploy requested by ${queuedDeploy.requestedBy.join(', ')}.` : ''}`,\n });\n emitTts({\n utterance: 'Automatic dashboard deployment started.',\n priority: 2,\n source: 'deploy-script',\n eventType: 'auto_deploy_started',\n });\n}\n\nexport function _resetDeployPatrolForTests(): void {\n clearState();\n}\n\nexport async function runScheduledDeployPatrol(): Promise<void> {\n try {\n await runDeployPatrol({\n repoRoot: process.cwd(),\n config: loadCloisterConfigSync().deploy,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.warn(`[deacon] Automatic deploy patrol failed: ${message}`);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"deploy-patrol-u3v2krg9.js","names":[],"sources":["../../src/lib/cloister/deploy-patrol.ts"],"sourcesContent":["import { open, mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { execFile, spawn } from 'node:child_process';\nimport type { ChildProcess } from 'node:child_process';\n\nimport { emitActivityEntrySync, emitActivityTtsSync } from '../activity-logger.js';\nimport { getBuildInfo } from '../deploy/build-info.js';\nimport {\n clearPendingDeploy,\n markPendingDeployEscalated,\n readPendingDeploy,\n recordDeployIntent,\n type PendingDeploy,\n} from '../deploy/deploy-queue.js';\nimport {\n getDeployWindowAssessment,\n type DeployWindowAssessment,\n} from '../deploy/deploy-window.js';\nimport { computeBuildStaleness, type BuildStaleness } from '../deploy/staleness.js';\nimport { OVERDECK_HOME } from '../paths.js';\nimport { loadCloisterConfigSync, type DeployConfig } from './config.js';\n\nconst OBSERVATION_INTERVAL_MS = 30 * 60 * 1000;\nconst DEPLOY_SPAWN_COOLDOWN_MS = 10 * 60 * 1000;\nconst DEPLOY_PATROL_INITIATOR = 'deploy-patrol';\nconst CI_WORKFLOW_FILE = 'ci.yml';\nconst CI_RUN_FIELDS = 'databaseId,status,conclusion,headSha,attempt,createdAt';\nconst SYSTEMD_ENV_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\ninterface DeployPatrolState {\n lastObservedBehind: number | null;\n lastObservationAt: number;\n lastDeferralReason: string | null;\n lastDeferralAt: number;\n lastDeploySpawnAt: number;\n lastEscalationReason: string | null;\n lastEscalationAt: number;\n unknownObserved: boolean;\n}\n\nconst state: DeployPatrolState = {\n lastObservedBehind: null,\n lastObservationAt: 0,\n lastDeferralReason: null,\n lastDeferralAt: 0,\n lastDeploySpawnAt: 0,\n lastEscalationReason: null,\n lastEscalationAt: 0,\n unknownObserved: false,\n};\n\ntype EmitEntry = typeof emitActivityEntrySync;\ntype EmitTts = typeof emitActivityTtsSync;\n\nexport interface DeployCiState {\n readonly status: 'green' | 'pending' | 'red' | 'unknown';\n readonly reason?: string;\n}\n\ninterface DeployCiRun {\n readonly databaseId: number;\n readonly status: string;\n readonly conclusion: string | null;\n readonly headSha: string;\n readonly attempt: number;\n readonly createdAt: string;\n}\n\nexport interface DeployPatrolContext {\n readonly repoRoot: string;\n readonly config: DeployConfig;\n readonly computeStaleness?: () => Promise<BuildStaleness>;\n readonly getCiState?: (sha: string) => Promise<DeployCiState>;\n readonly getWindowAssessment?: () => Promise<DeployWindowAssessment>;\n readonly readQueue?: typeof readPendingDeploy;\n readonly clearQueue?: typeof clearPendingDeploy;\n readonly recordIntent?: typeof recordDeployIntent;\n readonly markQueueEscalated?: typeof markPendingDeployEscalated;\n readonly spawnReload?: (request: ReloadRequest) => Promise<void>;\n readonly emitEntry?: EmitEntry;\n readonly emitTts?: EmitTts;\n readonly now?: () => number;\n}\n\nexport interface ReloadRequest {\n readonly command: string;\n readonly args: readonly string[];\n readonly cwd: string;\n readonly detached: true;\n readonly initiator: string;\n}\n\nfunction reloadEnvironment(request: ReloadRequest, env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n return { ...env, OVERDECK_AGENT_ID: request.initiator };\n}\n\nfunction execGh(args: readonly string[], cwd: string): Promise<string> {\n return new Promise((resolve, reject) => {\n execFile('gh', [...args], { cwd, encoding: 'utf8', timeout: 30_000 }, (error, stdout) => {\n if (error) reject(error);\n else resolve(stdout);\n });\n });\n}\n\nexport async function getDeployCiState(\n repoRoot: string,\n sha: string,\n runGh: (args: readonly string[], cwd: string) => Promise<string> = execGh,\n): Promise<DeployCiState> {\n try {\n const runs = JSON.parse(await runGh([\n 'run', 'list',\n '--branch', 'main',\n '--commit', sha,\n '--workflow', CI_WORKFLOW_FILE,\n '--limit', '10',\n '--json', CI_RUN_FIELDS,\n ], repoRoot)) as DeployCiRun[];\n const run = runs.find((candidate) => candidate.headSha === sha);\n const tip = shortSha(sha);\n\n if (!run) {\n return {\n status: 'pending',\n reason: `Automatic deployment deferred because CI has not started for origin/main ${tip}.`,\n };\n }\n if (run.status !== 'completed') {\n return {\n status: 'pending',\n reason: `Automatic deployment deferred because CI is ${run.status} for origin/main ${tip}.`,\n };\n }\n if (run.conclusion !== 'success') {\n return {\n status: 'red',\n reason: `Automatic deployment blocked because CI concluded ${run.conclusion || 'without a result'} for origin/main ${tip}.`,\n };\n }\n return { status: 'green' };\n } catch (error) {\n return {\n status: 'unknown',\n reason: `Automatic deployment deferred because CI status for origin/main ${shortSha(sha)} could not be read: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n}\n\nexport function buildSystemdReloadArgs(\n request: ReloadRequest,\n now: number,\n logPath: string,\n env: NodeJS.ProcessEnv = process.env,\n): string[] {\n const setenvArgs = Object.entries(reloadEnvironment(request, env))\n .filter(([name, value]) => value !== undefined && SYSTEMD_ENV_NAME_RE.test(name))\n .flatMap(([name, value]) => ['--setenv', `${name}=${value}`]);\n\n return [\n '--user', '--unit', `overdeck-auto-deploy-${now}`,\n '--collect', '--quiet',\n '--property=Restart=on-failure',\n '--property=RestartSec=10s',\n '--property=StartLimitIntervalSec=0',\n `--property=StandardOutput=append:${logPath}`,\n `--property=StandardError=append:${logPath}`,\n `--property=WorkingDirectory=${request.cwd}`,\n ...setenvArgs,\n request.command,\n ...request.args,\n ];\n}\n\nfunction shortSha(sha: string | null): string {\n return sha?.slice(0, 8) || 'unknown';\n}\n\nexport async function waitForChildSpawn(\n child: Pick<ChildProcess, 'once' | 'removeListener' | 'unref'>,\n): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const onSpawn = () => {\n cleanup();\n child.unref();\n resolve();\n };\n const onError = (error: Error) => {\n cleanup();\n reject(error);\n };\n const cleanup = () => {\n child.removeListener('spawn', onSpawn);\n child.removeListener('error', onError);\n };\n\n child.once('spawn', onSpawn);\n child.once('error', onError);\n });\n}\n\nasync function waitForChildExit(child: ChildProcess): Promise<number> {\n return new Promise<number>((resolve, reject) => {\n child.once('error', reject);\n child.once('close', (code) => resolve(code ?? 1));\n });\n}\n\nasync function spawnDetachedReload(request: ReloadRequest, now: number): Promise<void> {\n const logsDir = join(OVERDECK_HOME, 'logs');\n const logPath = join(logsDir, 'auto-deploy.log');\n await mkdir(logsDir, { recursive: true });\n await writeFile(\n join(OVERDECK_HOME, 'dashboard-restarting.json'),\n JSON.stringify({ reason: 'auto-deploy', trigger: 'deacon', timestamp: now }, null, 2),\n 'utf8',\n );\n\n const log = await open(logPath, 'a');\n try {\n if (process.platform === 'linux') {\n let systemdFailure: string | null = null;\n try {\n const launcher = spawn(\n 'systemd-run',\n buildSystemdReloadArgs(request, now, logPath),\n {\n cwd: request.cwd,\n stdio: ['ignore', log.fd, log.fd],\n },\n );\n const exitCode = await waitForChildExit(launcher);\n if (exitCode === 0) return;\n systemdFailure = `systemd-run exited ${exitCode}`;\n } catch (error) {\n systemdFailure = error instanceof Error ? error.message : String(error);\n }\n throw new Error(\n `Automatic deploy requires an independent systemd unit before it can stop the dashboard: ${systemdFailure}`,\n );\n }\n\n const child = spawn(\n request.command,\n [...request.args],\n {\n cwd: request.cwd,\n detached: request.detached,\n env: reloadEnvironment(request, process.env),\n stdio: ['ignore', log.fd, log.fd],\n },\n );\n await waitForChildSpawn(child);\n } finally {\n await log.close();\n }\n}\n\nfunction clearState(): void {\n state.lastObservedBehind = null;\n state.lastObservationAt = 0;\n state.lastDeferralReason = null;\n state.lastDeferralAt = 0;\n state.lastDeploySpawnAt = 0;\n state.lastEscalationReason = null;\n state.lastEscalationAt = 0;\n state.unknownObserved = false;\n}\n\nfunction emitDeferral(reason: string, now: number, emitEntry: EmitEntry): void {\n if (\n state.lastDeferralReason === reason &&\n now - state.lastDeferralAt < OBSERVATION_INTERVAL_MS\n ) return;\n\n emitEntry({\n source: 'deploy-script',\n level: 'warn',\n message: reason,\n });\n state.lastDeferralReason = reason;\n state.lastDeferralAt = now;\n}\n\nasync function refreshQueuedDeployReason(\n queuedDeploy: PendingDeploy | null,\n reason: string,\n context: DeployPatrolContext,\n): Promise<void> {\n if (!queuedDeploy) return;\n await (context.recordIntent ?? recordDeployIntent)({\n requestedBy: DEPLOY_PATROL_INITIATOR,\n reason,\n blockedBy: [],\n });\n}\n\nasync function escalateOverdueQueue(\n queuedDeploy: PendingDeploy | null,\n blockReason: string,\n context: DeployPatrolContext,\n now: number,\n emitEntry: EmitEntry,\n emitTts: EmitTts,\n): Promise<void> {\n if (\n !queuedDeploy\n || queuedDeploy.escalated\n || now - Date.parse(queuedDeploy.requestedAt) <= context.config.queue_deadline_minutes * 60_000\n ) return;\n\n const ageMinutes = Math.floor((now - Date.parse(queuedDeploy.requestedAt)) / 60_000);\n const message = `Queued dashboard deploy has waited ${ageMinutes} minutes; current block: ${blockReason}`;\n if (\n state.lastEscalationReason !== blockReason\n || now - state.lastEscalationAt >= OBSERVATION_INTERVAL_MS\n ) {\n emitEntry({ source: 'deploy-script', level: 'error', message });\n emitTts({\n utterance: `Dashboard deploy has been queued for ${ageMinutes} minutes and needs attention.`,\n priority: 1,\n source: 'deploy-script',\n eventType: 'deploy_queue_stuck',\n });\n state.lastEscalationReason = blockReason;\n state.lastEscalationAt = now;\n }\n\n await (context.markQueueEscalated ?? markPendingDeployEscalated)();\n}\n\nexport async function runDeployPatrol(context: DeployPatrolContext): Promise<void> {\n const now = (context.now ?? Date.now)();\n const emitEntry = context.emitEntry ?? emitActivityEntrySync;\n const emitTts = context.emitTts ?? emitActivityTtsSync;\n const staleness = await (context.computeStaleness ?? (() => computeBuildStaleness({\n repoRoot: context.repoRoot,\n buildCommit: getBuildInfo().buildCommit,\n })))();\n const queuedDeploy = await (context.readQueue ?? readPendingDeploy)();\n\n if (staleness.status === 'unknown') {\n const reason = `Automatic deployment cannot compare the running build with origin/main: ${staleness.reason ?? 'build staleness is unknown'}`;\n if (!state.unknownObserved) {\n emitEntry({\n source: 'deploy-script',\n level: 'warn',\n message: reason,\n });\n state.unknownObserved = true;\n }\n await refreshQueuedDeployReason(queuedDeploy, reason, context);\n await escalateOverdueQueue(queuedDeploy, reason, context, now, emitEntry, emitTts);\n return;\n }\n\n if (staleness.status === 'fresh') {\n clearState();\n await (context.clearQueue ?? clearPendingDeploy)();\n return;\n }\n\n state.unknownObserved = false;\n const behind = staleness.behindBuildInputs ?? 0;\n if (\n state.lastObservedBehind !== behind ||\n now - state.lastObservationAt >= OBSERVATION_INTERVAL_MS\n ) {\n emitEntry({\n source: 'deploy-script',\n level: 'warn',\n message: `The running build ${shortSha(staleness.buildCommit)} is ${behind} build-input commit(s) behind origin/main ${shortSha(staleness.originMainSha)}. ${context.config.auto_deploy || queuedDeploy ? 'Automatic deployment will start after the merge debounce and safety checks clear.' : 'Automatic deployment is disabled, so operator action is required.'}`,\n });\n state.lastObservedBehind = behind;\n state.lastObservationAt = now;\n }\n\n if (!context.config.auto_deploy && !queuedDeploy) return;\n if (\n staleness.originMainLastBuildInputCommitAt !== null\n && now - staleness.originMainLastBuildInputCommitAt < context.config.debounce_minutes * 60 * 1000\n ) {\n const reason = 'Automatic deployment deferred because the merge debounce has not elapsed.';\n await refreshQueuedDeployReason(queuedDeploy, reason, context);\n await escalateOverdueQueue(queuedDeploy, reason, context, now, emitEntry, emitTts);\n return;\n }\n if (state.lastDeploySpawnAt > 0 && now - state.lastDeploySpawnAt < DEPLOY_SPAWN_COOLDOWN_MS) {\n const reason = 'Automatic deployment deferred because a recent deploy is still inside the spawn cooldown.';\n await refreshQueuedDeployReason(queuedDeploy, reason, context);\n await escalateOverdueQueue(queuedDeploy, reason, context, now, emitEntry, emitTts);\n return;\n }\n\n if (!staleness.originMainSha) {\n const reason = 'Automatic deployment deferred because the origin/main commit is unknown.';\n emitDeferral(reason, now, emitEntry);\n await refreshQueuedDeployReason(queuedDeploy, reason, context);\n await escalateOverdueQueue(queuedDeploy, reason, context, now, emitEntry, emitTts);\n return;\n }\n const ciState = await (context.getCiState ?? ((sha) => getDeployCiState(context.repoRoot, sha)))(staleness.originMainSha);\n if (ciState.status !== 'green') {\n const reason = ciState.reason\n ?? `Automatic deployment deferred because CI is ${ciState.status} for origin/main ${shortSha(staleness.originMainSha)}.`;\n emitDeferral(reason, now, emitEntry);\n await refreshQueuedDeployReason(queuedDeploy, reason, context);\n await escalateOverdueQueue(queuedDeploy, reason, context, now, emitEntry, emitTts);\n return;\n }\n\n const assessment = await (context.getWindowAssessment ?? getDeployWindowAssessment)();\n if (assessment.reason) {\n emitDeferral(assessment.reason, now, emitEntry);\n if (context.config.auto_deploy || queuedDeploy) {\n await (context.recordIntent ?? recordDeployIntent)({\n requestedBy: DEPLOY_PATROL_INITIATOR,\n reason: assessment.reason,\n blockedBy: [],\n });\n }\n await escalateOverdueQueue(\n queuedDeploy,\n assessment.reason,\n context,\n now,\n emitEntry,\n emitTts,\n );\n return;\n }\n\n const reloadRequest: ReloadRequest = {\n command: process.execPath,\n args: [join(context.repoRoot, 'dist/cli/index.js'), 'reload', '--health-timeout', '120000'],\n cwd: context.repoRoot,\n detached: true,\n initiator: DEPLOY_PATROL_INITIATOR,\n };\n await (context.spawnReload ?? ((request) => spawnDetachedReload(request, now)))(reloadRequest);\n state.lastDeploySpawnAt = now;\n state.lastDeferralReason = null;\n state.lastDeferralAt = 0;\n emitEntry({\n source: 'deploy-script',\n level: 'info',\n message: `Automatic deployment started for origin/main ${shortSha(staleness.originMainSha)}; the dashboard will rebuild and restart with a 120-second health timeout.${queuedDeploy ? ` This was a queued deploy requested by ${queuedDeploy.requestedBy.join(', ')}.` : ''}`,\n });\n emitTts({\n utterance: 'Automatic dashboard deployment started.',\n priority: 2,\n source: 'deploy-script',\n eventType: 'auto_deploy_started',\n });\n}\n\nexport function _resetDeployPatrolForTests(): void {\n clearState();\n}\n\nexport async function runScheduledDeployPatrol(): Promise<void> {\n try {\n await runDeployPatrol({\n repoRoot: process.cwd(),\n config: loadCloisterConfigSync().deploy,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.warn(`[deacon] Automatic deploy patrol failed: ${message}`);\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { h as loadReviewStatuses, o as clearWorkspaceStuck, p as init_review_status } from "./review-status-BegAr86G.js";
1
+ import { h as loadReviewStatuses, o as clearWorkspaceStuck, p as init_review_status } from "./review-status-yY5qt7Rl.js";
2
2
  //#region ../../lib/cloister/feedback-stuck-retirement.ts
3
3
  init_review_status();
4
4
  /**
@@ -18,4 +18,4 @@ function retireResolvedFeedbackDeliveryStuckFlags() {
18
18
  //#endregion
19
19
  export { retireResolvedFeedbackDeliveryStuckFlags };
20
20
 
21
- //# sourceMappingURL=feedback-stuck-retirement-Dd5XNrMr.js.map
21
+ //# sourceMappingURL=feedback-stuck-retirement-CoFNqjCc.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"feedback-stuck-retirement-Dd5XNrMr.js","names":[],"sources":["../../src/lib/cloister/feedback-stuck-retirement.ts"],"sourcesContent":["import {\n clearWorkspaceStuck,\n FEEDBACK_DELIVERY_STUCK_REASON,\n loadReviewStatuses,\n} from '../review-status.js';\n\n/**\n * Retire feedback-delivery stuck flags whose triggering condition can no longer\n * block progress. Successful feedback delivery clears the flag at the delivery\n * site; this patrol safety net handles rows that became terminal without another\n * delivery attempt.\n */\nexport function retireResolvedFeedbackDeliveryStuckFlags(): string[] {\n const actions: string[] = [];\n for (const status of Object.values(loadReviewStatuses())) {\n if (\n status.stuck === true\n && status.stuckReason === FEEDBACK_DELIVERY_STUCK_REASON\n && status.mergeStatus === 'merged'\n ) {\n clearWorkspaceStuck(status.issueId);\n actions.push(`Retired stale feedback-delivery stuck flag for ${status.issueId}: issue is merged`);\n }\n }\n return actions;\n}\n"],"mappings":";;oBAI6B;;;;;;;AAQ7B,SAAgB,2CAAqD;CACnE,MAAM,UAAoB,EAAE;AAC5B,MAAK,MAAM,UAAU,OAAO,OAAO,oBAAoB,CAAC,CACtD,KACE,OAAO,UAAU,QACd,OAAO,gBAAA,iCACP,OAAO,gBAAgB,UAC1B;AACA,sBAAoB,OAAO,QAAQ;AACnC,UAAQ,KAAK,kDAAkD,OAAO,QAAQ,mBAAmB;;AAGrG,QAAO"}
1
+ {"version":3,"file":"feedback-stuck-retirement-CoFNqjCc.js","names":[],"sources":["../../src/lib/cloister/feedback-stuck-retirement.ts"],"sourcesContent":["import {\n clearWorkspaceStuck,\n FEEDBACK_DELIVERY_STUCK_REASON,\n loadReviewStatuses,\n} from '../review-status.js';\n\n/**\n * Retire feedback-delivery stuck flags whose triggering condition can no longer\n * block progress. Successful feedback delivery clears the flag at the delivery\n * site; this patrol safety net handles rows that became terminal without another\n * delivery attempt.\n */\nexport function retireResolvedFeedbackDeliveryStuckFlags(): string[] {\n const actions: string[] = [];\n for (const status of Object.values(loadReviewStatuses())) {\n if (\n status.stuck === true\n && status.stuckReason === FEEDBACK_DELIVERY_STUCK_REASON\n && status.mergeStatus === 'merged'\n ) {\n clearWorkspaceStuck(status.issueId);\n actions.push(`Retired stale feedback-delivery stuck flag for ${status.issueId}: issue is merged`);\n }\n }\n return actions;\n}\n"],"mappings":";;oBAI6B;;;;;;;AAQ7B,SAAgB,2CAAqD;CACnE,MAAM,UAAoB,EAAE;AAC5B,MAAK,MAAM,UAAU,OAAO,OAAO,oBAAoB,CAAC,CACtD,KACE,OAAO,UAAU,QACd,OAAO,gBAAA,iCACP,OAAO,gBAAgB,UAC1B;AACA,sBAAoB,OAAO,QAAQ;AACnC,UAAQ,KAAK,kDAAkD,OAAO,QAAQ,mBAAmB;;AAGrG,QAAO"}
@@ -1,3 +1,3 @@
1
- import { n as resolveIssueFeedbackTarget, r as surfaceIssueFeedbackNeedsYou, t as init_feedback_target } from "./feedback-target-BcsA_GRV.js";
1
+ import { n as resolveIssueFeedbackTarget, r as surfaceIssueFeedbackNeedsYou, t as init_feedback_target } from "./feedback-target-CeCq6EhW.js";
2
2
  init_feedback_target();
3
3
  export { resolveIssueFeedbackTarget, surfaceIssueFeedbackNeedsYou };
@@ -146,7 +146,7 @@ async function startAgentForFeedback(agentId, issueId, workspacePath) {
146
146
  }
147
147
  async function resurrectAgentForFeedback(agentId, issueId, workspacePath) {
148
148
  try {
149
- const { getAgentStateSync, clearAgentPausedSync, clearAgentTroubledSync } = await import("./agent-state-CbUEwUEQ.js");
149
+ const { getAgentStateSync, clearAgentPausedSync, clearAgentTroubledSync } = await import("./agent-state-IpWnw8lv.js");
150
150
  const state = getAgentStateSync(agentId);
151
151
  if (!state) {
152
152
  console.warn(`[feedback-target] Cannot resume ${agentId} for ${issueId} feedback: agent registry row is missing; trying the start path`);
@@ -165,7 +165,7 @@ async function resurrectAgentForFeedback(agentId, issueId, workspacePath) {
165
165
  console.warn(`[feedback-target] ${agentId} is gated (troubled=${state.troubled === true}, failures=${state.consecutiveFailures ?? 0}) — clearing for one resurrection attempt to deliver ${issueId} feedback; failure tracking re-trips the gate on another crash`);
166
166
  clearAgentTroubledSync(agentId);
167
167
  }
168
- const { resumeAgent } = await import("./resume-BKyB4hA1.js");
168
+ const { resumeAgent } = await import("./resume-KGCrn0DV.js");
169
169
  const result = await resumeAgent(agentId);
170
170
  if (!result.success) {
171
171
  console.warn(`[feedback-target] Failed to resume ${agentId} for ${issueId} feedback: ${result.error}; trying the start path`);
@@ -181,9 +181,9 @@ async function resurrectAgentForFeedback(agentId, issueId, workspacePath) {
181
181
  }
182
182
  async function surfaceIssueFeedbackNeedsYou(issueId, reason, details = {}) {
183
183
  try {
184
- const { markWorkspaceStuck, FEEDBACK_DELIVERY_STUCK_REASON } = await import("./review-status-DXTFzCmR.js");
184
+ const { markWorkspaceStuck, FEEDBACK_DELIVERY_STUCK_REASON } = await import("./review-status-FnlvQuPI.js");
185
185
  try {
186
- const [{ getAgentStateSync }, { readLatestSynthesisVerdictAsync }] = await Promise.all([import("./agent-state-CbUEwUEQ.js"), import("./synthesis-verdict-b1uY2m9Q.js")]);
186
+ const [{ getAgentStateSync }, { readLatestSynthesisVerdictAsync }] = await Promise.all([import("./agent-state-IpWnw8lv.js"), import("./synthesis-verdict-b1uY2m9Q.js")]);
187
187
  const state = getAgentStateSync(`agent-${issueId.toLowerCase()}-review`);
188
188
  const artifact = await readLatestSynthesisVerdictAsync(issueId, {
189
189
  runId: state?.reviewRunId,
@@ -213,4 +213,4 @@ var init_feedback_target = __esmMin((() => {
213
213
  //#endregion
214
214
  export { resolveIssueFeedbackTarget as n, surfaceIssueFeedbackNeedsYou as r, init_feedback_target as t };
215
215
 
216
- //# sourceMappingURL=feedback-target-BcsA_GRV.js.map
216
+ //# sourceMappingURL=feedback-target-CeCq6EhW.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"feedback-target-BcsA_GRV.js","names":[],"sources":["../../src/lib/cloister/feedback-target.ts"],"sourcesContent":["import { existsSync } from 'fs';\nimport { join } from 'path';\nimport { Effect } from 'effect';\n\nimport { readFeedbackAgentStates } from '../agents/agent-state-source.js';\nimport { getReadableWorkspacePanPaths } from '../pan-dir/continue.js';\nimport { getProjectSync, resolveProjectFromIssueSync } from '../projects.js';\nimport { readIssueRecordSync, type PanIssueRecord } from '../pan-dir/record.js';\nimport { updateIssueRecord } from '../pan-dir/record-update.js';\nimport { listSessionNames, sessionExists } from '../tmux.js';\n\nexport type IssueFeedbackTarget =\n | { agentId: string }\n | { needsYou: true; reason: string };\n\nexport interface ResolveIssueFeedbackTargetOptions {\n itemId?: string;\n /** Test hook — replaces the default resurrection attempt for non-live targets. */\n revivePipelinePausedAgent?: (agentId: string, issueId: string) => Promise<boolean>;\n}\n\nasync function isLiveSession(agentId: string): Promise<boolean> {\n return Effect.runPromise(sessionExists(agentId));\n}\n\nfunction isWorkFeedbackTarget(role: string): boolean {\n return role === 'work';\n}\n\nfunction slotAgentId(issueId: string, slotIndex: number, assignedAgentId?: string): string {\n return assignedAgentId ?? `agent-${issueId.toLowerCase()}-slot-${slotIndex}`;\n}\n\nasync function findLiveUnregisteredSlot(issueId: string): Promise<{ agentId: string; slotIndex: number } | null> {\n const prefix = `agent-${issueId.toLowerCase()}-slot-`;\n const sessions = await Effect.runPromise(listSessionNames());\n for (const session of sessions) {\n if (!session.startsWith(prefix)) continue;\n const slotIndex = Number.parseInt(session.slice(prefix.length), 10);\n if (!Number.isInteger(slotIndex) || slotIndex < 1) continue;\n if (await isLiveSession(session)) return { agentId: session, slotIndex };\n }\n return null;\n}\n\nfunction selfHealSlotAssignment(record: PanIssueRecord, agentId: string, slotIndex: number, itemId?: string): PanIssueRecord {\n const assignments = record.swarm?.slotAssignments ?? [];\n const existing = assignments.find((assignment) => assignment.slotIndex === slotIndex || assignment.agentId === agentId);\n const assignedAt = new Date().toISOString();\n const slotAssignments = existing\n ? assignments.map((assignment) => assignment === existing\n ? { ...assignment, agentId, itemId: itemId ?? assignment.itemId, assignedAt: assignment.assignedAt ?? assignedAt }\n : assignment)\n : [\n ...assignments,\n {\n slotIndex,\n itemId: itemId ?? `slot-${slotIndex}`,\n agentId,\n assignedAt,\n },\n ];\n\n return {\n ...record,\n swarm: {\n ...record.swarm,\n slotAssignments,\n },\n };\n}\n\nexport async function resolveIssueFeedbackTarget(\n issueId: string,\n opts: ResolveIssueFeedbackTargetOptions = {},\n): Promise<IssueFeedbackTarget> {\n const normalizedIssue = issueId.toUpperCase();\n const issueLower = normalizedIssue.toLowerCase();\n const wholeIssueAgentId = `agent-${issueLower}`;\n\n if (await isLiveSession(wholeIssueAgentId)) {\n return { agentId: wholeIssueAgentId };\n }\n\n const resolved = resolveProjectFromIssueSync(normalizedIssue);\n const project = resolved ? getProjectSync(resolved.projectKey) : null;\n const record = project ? readIssueRecordSync(project, normalizedIssue) : null;\n const assignments = record?.swarm?.slotAssignments ?? [];\n\n const requestedItemId = opts.itemId?.trim();\n if (requestedItemId) {\n const assigned = assignments.find(a => a.itemId === requestedItemId);\n if (assigned) {\n const agentId = slotAgentId(normalizedIssue, assigned.slotIndex, assigned.agentId);\n if (await isLiveSession(agentId)) return { agentId };\n }\n }\n\n for (const assignment of assignments) {\n const agentId = slotAgentId(normalizedIssue, assignment.slotIndex, assignment.agentId);\n if (await isLiveSession(agentId)) return { agentId };\n }\n\n if (project && record) {\n const fallback = await findLiveUnregisteredSlot(normalizedIssue);\n if (fallback) {\n await updateIssueRecord(project, normalizedIssue, (current) => selfHealSlotAssignment(current, fallback.agentId, fallback.slotIndex, requestedItemId));\n return { agentId: fallback.agentId };\n }\n }\n\n const registeredAgents = readFeedbackAgentStates();\n if (registeredAgents) {\n for (const agent of registeredAgents) {\n if (agent.issueId.toUpperCase() !== normalizedIssue) continue;\n if (!isWorkFeedbackTarget(agent.role)) continue;\n if (await isLiveSession(agent.id)) return { agentId: agent.id };\n }\n }\n\n // PAN-2209 + PAN-2461 — resurrection-first delivery (operator directive 2026-07-11):\n // feedback with no live target is NOT an operator problem until resurrection has been\n // tried. The verification gate pausing the only delivery target (PAN-2461), a\n // governor/scheduler yield, a crash, or a plain stopped work agent after a BLOCKED\n // verdict (PAN-2209) must all self-heal by bringing the agent back and delivering.\n // Operator pauses are the one gate never overridden. Escalating to a human (or any\n // mailbox-style deferred delivery, PAN-2255) is strictly the last resort after\n // resurrection of every candidate has failed.\n const workspacePath = resolved\n ? join(resolved.projectPath, 'workspaces', `feature-${issueLower}`)\n : undefined;\n const revive = opts.revivePipelinePausedAgent\n ?? ((agentId, reviveIssueId) => resurrectAgentForFeedback(agentId, reviveIssueId, workspacePath));\n const candidates: string[] = [wholeIssueAgentId];\n if (requestedItemId) {\n const assigned = assignments.find(a => a.itemId === requestedItemId);\n if (assigned) candidates.push(slotAgentId(normalizedIssue, assigned.slotIndex, assigned.agentId));\n }\n for (const assignment of assignments) {\n candidates.push(slotAgentId(normalizedIssue, assignment.slotIndex, assignment.agentId));\n }\n const attempted = new Set<string>();\n for (const candidate of candidates) {\n if (attempted.has(candidate)) continue;\n attempted.add(candidate);\n if (await revive(candidate, normalizedIssue)) return { agentId: candidate };\n }\n\n const suffix = requestedItemId ? ` for item ${requestedItemId}` : '';\n return {\n needsYou: true,\n reason: `No live feedback target for ${normalizedIssue}${suffix}: ${wholeIssueAgentId} is not running, no assigned swarm slot has a live tmux session, and resurrection of ${attempted.size} candidate agent(s) failed.`,\n };\n}\n\n/**\n * PAN-2209 + PAN-2461: bring a non-running agent back to life so feedback can be\n * delivered to it. Returns true when the agent is live again. Gate handling:\n *\n * - Pipeline pauses (`needs-you:*`, `[governor-slot]*`, scheduler yields) → unpause +\n * resume. A gate the pipeline set must never deadlock the pipeline's own delivery\n * (PAN-2461); the operator explicitly prefers briefly exceeding memory targets over\n * undelivered work↔review feedback.\n * - Troubled / failure-backoff → clear the gate loudly and attempt ONE resume. The\n * failure-tracking machinery re-trips the gate if the agent crashes again, so this\n * cannot loop unboundedly.\n * - Plain stopped/completed/crashed → resume, then canonical start if resume fails.\n * - Missing registry row + healthy workspace continue state → canonical start.\n * - OPERATOR pauses (pan pause, any non-pipeline pausedReason) are never overridden.\n */\nasync function startAgentForFeedback(\n agentId: string,\n issueId: string,\n workspacePath: string | undefined,\n): Promise<boolean> {\n if (agentId !== `agent-${issueId.toLowerCase()}`) return false;\n if (!workspacePath) {\n console.warn(`[feedback-target] Cannot start ${agentId} for ${issueId} feedback: no configured project workspace`);\n return false;\n }\n\n const continuePath = getReadableWorkspacePanPaths(workspacePath).continuePath;\n if (!existsSync(workspacePath) || !existsSync(continuePath)) {\n console.warn(\n `[feedback-target] Cannot start ${agentId} for ${issueId} feedback: ` +\n `workspace=${existsSync(workspacePath) ? 'present' : 'missing'}, continue=${existsSync(continuePath) ? 'present' : 'missing'}`,\n );\n return false;\n }\n\n console.warn(`[feedback-target] Starting ${agentId} for ${issueId} feedback through the canonical work-agent start path`);\n const { spawnWorkAgentThroughAgentsEndpoint } = await import('./work-agent-start.js');\n const result = await spawnWorkAgentThroughAgentsEndpoint(issueId, undefined, false, 'resume-agent');\n if (!result.spawned) {\n console.warn(\n `[feedback-target] Failed to start ${agentId} for ${issueId} feedback: ` +\n `${result.error ?? result.skippedReason ?? 'unknown start failure'}`,\n );\n return false;\n }\n\n const live = await isLiveSession(agentId);\n if (!live) {\n console.warn(`[feedback-target] Start path accepted ${agentId} for ${issueId} feedback, but no live tmux session appeared`);\n }\n return live;\n}\n\nasync function resurrectAgentForFeedback(\n agentId: string,\n issueId: string,\n workspacePath: string | undefined,\n): Promise<boolean> {\n try {\n const { getAgentStateSync, clearAgentPausedSync, clearAgentTroubledSync } = await import('../agents/agent-state.js');\n const state = getAgentStateSync(agentId);\n if (!state) {\n console.warn(`[feedback-target] Cannot resume ${agentId} for ${issueId} feedback: agent registry row is missing; trying the start path`);\n return startAgentForFeedback(agentId, issueId, workspacePath);\n }\n\n if (state.paused === true) {\n const reason = state.pausedReason ?? '';\n const pipelinePause = reason.startsWith('needs-you:')\n || reason.startsWith('[governor-slot]')\n || state.yieldedByScheduler === true;\n if (!pipelinePause) {\n console.log(`[feedback-target] ${agentId} is operator-paused (${reason || 'no reason'}) — not overriding to deliver ${issueId} feedback`);\n return false;\n }\n console.log(`[feedback-target] ${agentId} is pipeline-paused (${reason || 'scheduler yield'}) — unpausing to deliver feedback for ${issueId}`);\n clearAgentPausedSync(agentId);\n }\n\n if (state.troubled === true || (state.consecutiveFailures ?? 0) > 0) {\n console.warn(\n `[feedback-target] ${agentId} is gated (troubled=${state.troubled === true}, ` +\n `failures=${state.consecutiveFailures ?? 0}) — clearing for one resurrection attempt to ` +\n `deliver ${issueId} feedback; failure tracking re-trips the gate on another crash`,\n );\n clearAgentTroubledSync(agentId);\n }\n\n const { resumeAgent } = await import('../agents/resume.js');\n const result = await resumeAgent(agentId);\n if (!result.success) {\n console.warn(`[feedback-target] Failed to resume ${agentId} for ${issueId} feedback: ${result.error}; trying the start path`);\n return startAgentForFeedback(agentId, issueId, workspacePath);\n }\n if (await isLiveSession(agentId)) return true;\n\n console.warn(`[feedback-target] Resume reported success for ${agentId}, but no live tmux session appeared; trying the start path`);\n return startAgentForFeedback(agentId, issueId, workspacePath);\n } catch (err) {\n console.warn(`[feedback-target] resurrectAgentForFeedback(${agentId}) failed: ${err instanceof Error ? err.message : String(err)}`);\n return false;\n }\n}\n\nexport async function surfaceIssueFeedbackNeedsYou(\n issueId: string,\n reason: string,\n details: Record<string, unknown> = {},\n): Promise<void> {\n try {\n const { markWorkspaceStuck, FEEDBACK_DELIVERY_STUCK_REASON } = await import('../review-status.js');\n // PAN-3511: consult evidence from the host-recorded active review run\n // before mutating the row. A workspace artifact never authorizes a terminal\n // verdict; the canonical review done signal owns that transition, so a\n // delivery failure still receives its protective stuck mark.\n try {\n const [{ getAgentStateSync }, { readLatestSynthesisVerdictAsync }] = await Promise.all([\n import('../agents/agent-state.js'),\n import('./synthesis-verdict.js'),\n ]);\n const state = getAgentStateSync(`agent-${issueId.toLowerCase()}-review`);\n const artifact = await readLatestSynthesisVerdictAsync(issueId, {\n runId: state?.reviewRunId,\n workspacePath: state?.workspace,\n });\n if (artifact) console.warn(`[feedback-target] ${issueId}: found fresh ${artifact.verdict} artifact for the active run; awaiting canonical review signal. ${reason}`);\n } catch (err) {\n console.warn(`[feedback-target] Artifact consult failed for ${issueId}: ${err instanceof Error ? err.message : String(err)}; proceeding with the stuck mark`);\n }\n markWorkspaceStuck(issueId, FEEDBACK_DELIVERY_STUCK_REASON, {\n reason,\n ...details,\n });\n } catch (err) {\n console.warn(`[feedback-target] Failed to mark ${issueId} as needing human attention: ${err instanceof Error ? err.message : String(err)}`);\n }\n console.warn(`[feedback-target] ${reason}`);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"feedback-target-CeCq6EhW.js","names":[],"sources":["../../src/lib/cloister/feedback-target.ts"],"sourcesContent":["import { existsSync } from 'fs';\nimport { join } from 'path';\nimport { Effect } from 'effect';\n\nimport { readFeedbackAgentStates } from '../agents/agent-state-source.js';\nimport { getReadableWorkspacePanPaths } from '../pan-dir/continue.js';\nimport { getProjectSync, resolveProjectFromIssueSync } from '../projects.js';\nimport { readIssueRecordSync, type PanIssueRecord } from '../pan-dir/record.js';\nimport { updateIssueRecord } from '../pan-dir/record-update.js';\nimport { listSessionNames, sessionExists } from '../tmux.js';\n\nexport type IssueFeedbackTarget =\n | { agentId: string }\n | { needsYou: true; reason: string };\n\nexport interface ResolveIssueFeedbackTargetOptions {\n itemId?: string;\n /** Test hook — replaces the default resurrection attempt for non-live targets. */\n revivePipelinePausedAgent?: (agentId: string, issueId: string) => Promise<boolean>;\n}\n\nasync function isLiveSession(agentId: string): Promise<boolean> {\n return Effect.runPromise(sessionExists(agentId));\n}\n\nfunction isWorkFeedbackTarget(role: string): boolean {\n return role === 'work';\n}\n\nfunction slotAgentId(issueId: string, slotIndex: number, assignedAgentId?: string): string {\n return assignedAgentId ?? `agent-${issueId.toLowerCase()}-slot-${slotIndex}`;\n}\n\nasync function findLiveUnregisteredSlot(issueId: string): Promise<{ agentId: string; slotIndex: number } | null> {\n const prefix = `agent-${issueId.toLowerCase()}-slot-`;\n const sessions = await Effect.runPromise(listSessionNames());\n for (const session of sessions) {\n if (!session.startsWith(prefix)) continue;\n const slotIndex = Number.parseInt(session.slice(prefix.length), 10);\n if (!Number.isInteger(slotIndex) || slotIndex < 1) continue;\n if (await isLiveSession(session)) return { agentId: session, slotIndex };\n }\n return null;\n}\n\nfunction selfHealSlotAssignment(record: PanIssueRecord, agentId: string, slotIndex: number, itemId?: string): PanIssueRecord {\n const assignments = record.swarm?.slotAssignments ?? [];\n const existing = assignments.find((assignment) => assignment.slotIndex === slotIndex || assignment.agentId === agentId);\n const assignedAt = new Date().toISOString();\n const slotAssignments = existing\n ? assignments.map((assignment) => assignment === existing\n ? { ...assignment, agentId, itemId: itemId ?? assignment.itemId, assignedAt: assignment.assignedAt ?? assignedAt }\n : assignment)\n : [\n ...assignments,\n {\n slotIndex,\n itemId: itemId ?? `slot-${slotIndex}`,\n agentId,\n assignedAt,\n },\n ];\n\n return {\n ...record,\n swarm: {\n ...record.swarm,\n slotAssignments,\n },\n };\n}\n\nexport async function resolveIssueFeedbackTarget(\n issueId: string,\n opts: ResolveIssueFeedbackTargetOptions = {},\n): Promise<IssueFeedbackTarget> {\n const normalizedIssue = issueId.toUpperCase();\n const issueLower = normalizedIssue.toLowerCase();\n const wholeIssueAgentId = `agent-${issueLower}`;\n\n if (await isLiveSession(wholeIssueAgentId)) {\n return { agentId: wholeIssueAgentId };\n }\n\n const resolved = resolveProjectFromIssueSync(normalizedIssue);\n const project = resolved ? getProjectSync(resolved.projectKey) : null;\n const record = project ? readIssueRecordSync(project, normalizedIssue) : null;\n const assignments = record?.swarm?.slotAssignments ?? [];\n\n const requestedItemId = opts.itemId?.trim();\n if (requestedItemId) {\n const assigned = assignments.find(a => a.itemId === requestedItemId);\n if (assigned) {\n const agentId = slotAgentId(normalizedIssue, assigned.slotIndex, assigned.agentId);\n if (await isLiveSession(agentId)) return { agentId };\n }\n }\n\n for (const assignment of assignments) {\n const agentId = slotAgentId(normalizedIssue, assignment.slotIndex, assignment.agentId);\n if (await isLiveSession(agentId)) return { agentId };\n }\n\n if (project && record) {\n const fallback = await findLiveUnregisteredSlot(normalizedIssue);\n if (fallback) {\n await updateIssueRecord(project, normalizedIssue, (current) => selfHealSlotAssignment(current, fallback.agentId, fallback.slotIndex, requestedItemId));\n return { agentId: fallback.agentId };\n }\n }\n\n const registeredAgents = readFeedbackAgentStates();\n if (registeredAgents) {\n for (const agent of registeredAgents) {\n if (agent.issueId.toUpperCase() !== normalizedIssue) continue;\n if (!isWorkFeedbackTarget(agent.role)) continue;\n if (await isLiveSession(agent.id)) return { agentId: agent.id };\n }\n }\n\n // PAN-2209 + PAN-2461 — resurrection-first delivery (operator directive 2026-07-11):\n // feedback with no live target is NOT an operator problem until resurrection has been\n // tried. The verification gate pausing the only delivery target (PAN-2461), a\n // governor/scheduler yield, a crash, or a plain stopped work agent after a BLOCKED\n // verdict (PAN-2209) must all self-heal by bringing the agent back and delivering.\n // Operator pauses are the one gate never overridden. Escalating to a human (or any\n // mailbox-style deferred delivery, PAN-2255) is strictly the last resort after\n // resurrection of every candidate has failed.\n const workspacePath = resolved\n ? join(resolved.projectPath, 'workspaces', `feature-${issueLower}`)\n : undefined;\n const revive = opts.revivePipelinePausedAgent\n ?? ((agentId, reviveIssueId) => resurrectAgentForFeedback(agentId, reviveIssueId, workspacePath));\n const candidates: string[] = [wholeIssueAgentId];\n if (requestedItemId) {\n const assigned = assignments.find(a => a.itemId === requestedItemId);\n if (assigned) candidates.push(slotAgentId(normalizedIssue, assigned.slotIndex, assigned.agentId));\n }\n for (const assignment of assignments) {\n candidates.push(slotAgentId(normalizedIssue, assignment.slotIndex, assignment.agentId));\n }\n const attempted = new Set<string>();\n for (const candidate of candidates) {\n if (attempted.has(candidate)) continue;\n attempted.add(candidate);\n if (await revive(candidate, normalizedIssue)) return { agentId: candidate };\n }\n\n const suffix = requestedItemId ? ` for item ${requestedItemId}` : '';\n return {\n needsYou: true,\n reason: `No live feedback target for ${normalizedIssue}${suffix}: ${wholeIssueAgentId} is not running, no assigned swarm slot has a live tmux session, and resurrection of ${attempted.size} candidate agent(s) failed.`,\n };\n}\n\n/**\n * PAN-2209 + PAN-2461: bring a non-running agent back to life so feedback can be\n * delivered to it. Returns true when the agent is live again. Gate handling:\n *\n * - Pipeline pauses (`needs-you:*`, `[governor-slot]*`, scheduler yields) → unpause +\n * resume. A gate the pipeline set must never deadlock the pipeline's own delivery\n * (PAN-2461); the operator explicitly prefers briefly exceeding memory targets over\n * undelivered work↔review feedback.\n * - Troubled / failure-backoff → clear the gate loudly and attempt ONE resume. The\n * failure-tracking machinery re-trips the gate if the agent crashes again, so this\n * cannot loop unboundedly.\n * - Plain stopped/completed/crashed → resume, then canonical start if resume fails.\n * - Missing registry row + healthy workspace continue state → canonical start.\n * - OPERATOR pauses (pan pause, any non-pipeline pausedReason) are never overridden.\n */\nasync function startAgentForFeedback(\n agentId: string,\n issueId: string,\n workspacePath: string | undefined,\n): Promise<boolean> {\n if (agentId !== `agent-${issueId.toLowerCase()}`) return false;\n if (!workspacePath) {\n console.warn(`[feedback-target] Cannot start ${agentId} for ${issueId} feedback: no configured project workspace`);\n return false;\n }\n\n const continuePath = getReadableWorkspacePanPaths(workspacePath).continuePath;\n if (!existsSync(workspacePath) || !existsSync(continuePath)) {\n console.warn(\n `[feedback-target] Cannot start ${agentId} for ${issueId} feedback: ` +\n `workspace=${existsSync(workspacePath) ? 'present' : 'missing'}, continue=${existsSync(continuePath) ? 'present' : 'missing'}`,\n );\n return false;\n }\n\n console.warn(`[feedback-target] Starting ${agentId} for ${issueId} feedback through the canonical work-agent start path`);\n const { spawnWorkAgentThroughAgentsEndpoint } = await import('./work-agent-start.js');\n const result = await spawnWorkAgentThroughAgentsEndpoint(issueId, undefined, false, 'resume-agent');\n if (!result.spawned) {\n console.warn(\n `[feedback-target] Failed to start ${agentId} for ${issueId} feedback: ` +\n `${result.error ?? result.skippedReason ?? 'unknown start failure'}`,\n );\n return false;\n }\n\n const live = await isLiveSession(agentId);\n if (!live) {\n console.warn(`[feedback-target] Start path accepted ${agentId} for ${issueId} feedback, but no live tmux session appeared`);\n }\n return live;\n}\n\nasync function resurrectAgentForFeedback(\n agentId: string,\n issueId: string,\n workspacePath: string | undefined,\n): Promise<boolean> {\n try {\n const { getAgentStateSync, clearAgentPausedSync, clearAgentTroubledSync } = await import('../agents/agent-state.js');\n const state = getAgentStateSync(agentId);\n if (!state) {\n console.warn(`[feedback-target] Cannot resume ${agentId} for ${issueId} feedback: agent registry row is missing; trying the start path`);\n return startAgentForFeedback(agentId, issueId, workspacePath);\n }\n\n if (state.paused === true) {\n const reason = state.pausedReason ?? '';\n const pipelinePause = reason.startsWith('needs-you:')\n || reason.startsWith('[governor-slot]')\n || state.yieldedByScheduler === true;\n if (!pipelinePause) {\n console.log(`[feedback-target] ${agentId} is operator-paused (${reason || 'no reason'}) — not overriding to deliver ${issueId} feedback`);\n return false;\n }\n console.log(`[feedback-target] ${agentId} is pipeline-paused (${reason || 'scheduler yield'}) — unpausing to deliver feedback for ${issueId}`);\n clearAgentPausedSync(agentId);\n }\n\n if (state.troubled === true || (state.consecutiveFailures ?? 0) > 0) {\n console.warn(\n `[feedback-target] ${agentId} is gated (troubled=${state.troubled === true}, ` +\n `failures=${state.consecutiveFailures ?? 0}) — clearing for one resurrection attempt to ` +\n `deliver ${issueId} feedback; failure tracking re-trips the gate on another crash`,\n );\n clearAgentTroubledSync(agentId);\n }\n\n const { resumeAgent } = await import('../agents/resume.js');\n const result = await resumeAgent(agentId);\n if (!result.success) {\n console.warn(`[feedback-target] Failed to resume ${agentId} for ${issueId} feedback: ${result.error}; trying the start path`);\n return startAgentForFeedback(agentId, issueId, workspacePath);\n }\n if (await isLiveSession(agentId)) return true;\n\n console.warn(`[feedback-target] Resume reported success for ${agentId}, but no live tmux session appeared; trying the start path`);\n return startAgentForFeedback(agentId, issueId, workspacePath);\n } catch (err) {\n console.warn(`[feedback-target] resurrectAgentForFeedback(${agentId}) failed: ${err instanceof Error ? err.message : String(err)}`);\n return false;\n }\n}\n\nexport async function surfaceIssueFeedbackNeedsYou(\n issueId: string,\n reason: string,\n details: Record<string, unknown> = {},\n): Promise<void> {\n try {\n const { markWorkspaceStuck, FEEDBACK_DELIVERY_STUCK_REASON } = await import('../review-status.js');\n // PAN-3511: consult evidence from the host-recorded active review run\n // before mutating the row. A workspace artifact never authorizes a terminal\n // verdict; the canonical review done signal owns that transition, so a\n // delivery failure still receives its protective stuck mark.\n try {\n const [{ getAgentStateSync }, { readLatestSynthesisVerdictAsync }] = await Promise.all([\n import('../agents/agent-state.js'),\n import('./synthesis-verdict.js'),\n ]);\n const state = getAgentStateSync(`agent-${issueId.toLowerCase()}-review`);\n const artifact = await readLatestSynthesisVerdictAsync(issueId, {\n runId: state?.reviewRunId,\n workspacePath: state?.workspace,\n });\n if (artifact) console.warn(`[feedback-target] ${issueId}: found fresh ${artifact.verdict} artifact for the active run; awaiting canonical review signal. ${reason}`);\n } catch (err) {\n console.warn(`[feedback-target] Artifact consult failed for ${issueId}: ${err instanceof Error ? err.message : String(err)}; proceeding with the stuck mark`);\n }\n markWorkspaceStuck(issueId, FEEDBACK_DELIVERY_STUCK_REASON, {\n reason,\n ...details,\n });\n } catch (err) {\n console.warn(`[feedback-target] Failed to mark ${issueId} as needing human attention: ${err instanceof Error ? err.message : String(err)}`);\n }\n console.warn(`[feedback-target] ${reason}`);\n}\n"],"mappings":"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"}
@@ -3,15 +3,15 @@ import { $t as findProjectByPathSync, Dt as queueAutoCommit, Ht as init_state_re
3
3
  import { C as FlywheelRunId, d as OrderBook, f as OrderBookIndexEntry, t as init_src, w as FlywheelStatus } from "./src-tnFSfiXX.js";
4
4
  import { c as init_agents, o as countAgentsByStatusRole } from "./agents-CkngXhQr.js";
5
5
  import { C as setFlywheelGloballyPaused, c as init_control_settings, f as isFlywheelAutoPickupBacklog, i as getFlywheelActiveRunId, m as isFlywheelRequireUatBeforeMerge, p as isFlywheelGloballyPaused, x as setFlywheelActiveRunId } from "./control-settings-BkaVFRdm.js";
6
- import { Mn as stopAgent, f as getAgentDir, la as buildResumeContract, ln as spawnRun, q as init_agents$1, ua as init_resume_contract } from "./agent-state-Ci6PhjOE.js";
6
+ import { Mn as stopAgent, da as buildResumeContract, f as getAgentDir, fa as init_resume_contract, ln as spawnRun, q as init_agents$1 } from "./agent-state-B196fj1h.js";
7
7
  import { o as getInternalTokenSync, s as init_internal_token, t as INTERNAL_TOKEN_HEADER } from "./internal-token-Ci0LxMIq.js";
8
8
  import { N as getProjectPanPaths, P as init_paths$1 } from "./io-Cm4Sf_6P.js";
9
- import { i as issue_service_singleton_exports, n as init_issue_service_singleton } from "./issue-service-singleton-BrZQJLRI.js";
10
- import { d as getReviewStatusSync, p as init_review_status } from "./review-status-BegAr86G.js";
11
- import { t as parseSequenceMd } from "./sequence-io-iljWlslY.js";
9
+ import { i as issue_service_singleton_exports, n as init_issue_service_singleton } from "./issue-service-singleton-KcRrOiFD.js";
10
+ import { d as getReviewStatusSync, p as init_review_status } from "./review-status-yY5qt7Rl.js";
11
+ import { t as parseSequenceMd } from "./sequence-io-DZyschsf.js";
12
12
  import { h as init_pickup, r as LEGACY_PARKED_LABELS, u as computeCohort } from "./pickup-TwHZNJn4.js";
13
13
  import { a as gatherProjectLensSignals, s as init_pipeline_membership_gather } from "./pipeline-membership-gather-QYMqf_Wf.js";
14
- import { a as computePredictedConflictSignals, l as pickFromSequence, o as declaredIssueFootprint } from "./flywheel-merge-order-BsNPMu0S.js";
14
+ import { a as computePredictedConflictSignals, l as pickFromSequence, o as declaredIssueFootprint } from "./flywheel-merge-order-PG5op4j7.js";
15
15
  import { n as init_pipeline_membership, r as resolvePipelineMembership } from "./pipeline-membership-DxJOJOjn.js";
16
16
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
17
17
  import { Effect, Schema } from "effect";
@@ -218,7 +218,7 @@ function loadIssueServiceModuleSync() {
218
218
  }
219
219
  async function loadIssueServiceModule() {
220
220
  if (issueServiceModule) return issueServiceModule;
221
- issueServiceModule = await import("./issue-service-singleton-Dsad9NTt.js");
221
+ issueServiceModule = await import("./issue-service-singleton-BVwPzjwF.js");
222
222
  return issueServiceModule;
223
223
  }
224
224
  function labelNames(issue) {
@@ -1195,4 +1195,4 @@ async function resumeFlywheel(options = {}) {
1195
1195
  //#endregion
1196
1196
  export { advanceQueue as A, ensureOrderIssueStore as B, readCurrentLatestFlywheelStatus as C, writeFlywheelLaunchMetadata as D, subscribeLatestFlywheelStatus as E, setItemRequirements as F, liveOrderIssueLookup as G, getBook as H, setSettings as I, normalizeOrderIssueId as K, setStatus as L, moveItem as M, removeItem as N, writeLatestFlywheelStatus as O, renameBook as P, backlogCandidates as R, nextFlywheelRunId as S, resolveLiveFlywheelRunId as T, getBookAsync as U, firstReadyBookInQueue as V, listBooks as W, clearFlywheelGate as _, isFlywheelDevcontainerRuntime as a, isFlywheelRunId as b, pauseFlywheel as c, spawnFlywheel as d, spawnFlywheelAgent as f, abortFlywheelRun as g, resolvePrimaryWorktreeRoot as h, buildFlywheelResumePrompt as i, createBook as j, addItems as k, resumeFlywheel as l, requireFlywheelBrief as m, abortSpawnedFlywheel as n, isIssueInResolvedPipeline as o, buildClassifyLookups as p, orderIssueStoreStatus as q, activeOrderBookIssues as r, loadResumeSessionId as s, FLYWHEEL_ORCHESTRATOR_AGENT_ID as t, saveResumeSessionId as u, getFlywheelRunDetail as v, readFlywheelLaunchMetadata as w, listFlywheelRuns as x, getFlywheelRunDir as y, computeBookProgress as z };
1197
1197
 
1198
- //# sourceMappingURL=flywheel-Is3w2lcT.js.map
1198
+ //# sourceMappingURL=flywheel-DKldI63J.js.map