@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 +1 @@
1
- {"version":3,"file":"stuck-remediation-4Rf_xMEb.js","names":[],"sources":["../../src/lib/cloister/agent-death.ts","../../src/lib/cloister/stuck-remediation-state.ts","../../src/lib/cloister/planning-wedge.ts","../../src/lib/cloister/stuck-remediation.ts"],"sourcesContent":["/**\n * Agent death diagnostics (PAN-2108).\n *\n * When an ohmypi/pi agent process dies, the launcher records its exit code +\n * timestamp to `<agentDir>/exit-status` (see buildOhmypiCommand in\n * launcher-generator.ts), and omp's stdout/stderr is captured to\n * `<agentDir>/output.log`. This module turns those into a one-line death reason\n * the deacon can log, replacing the opaque \"session is dead\" with an actual\n * cause — the gap that made the flywheel orchestrator's silent death\n * undiagnosable in RUN-30.\n */\nimport { existsSync, readFileSync } from 'fs';\nimport { join } from 'path';\nimport { getOverdeckHome } from '../paths.js';\nimport { listPaneValuesSync, sessionExistsSync } from '../tmux.js';\n\nfunction agentDir(agentId: string): string {\n return join(getOverdeckHome(), 'agents', agentId);\n}\n\n/** Read the launcher-recorded exit code + UTC timestamp, or null if absent. */\nexport function readAgentExitStatus(agentId: string): { code: string; at: string } | null {\n try {\n const p = join(agentDir(agentId), 'exit-status');\n if (!existsSync(p)) return null;\n const raw = readFileSync(p, 'utf-8').trim();\n if (!raw) return null;\n const [code, at = ''] = raw.split(/\\s+/);\n return { code: code ?? '?', at };\n } catch {\n return null;\n }\n}\n\n/**\n * Best-effort one-line description of why an agent process died: the\n * launcher-recorded exit status (preferred), the tmux pane exit status (fallback\n * when the dead pane corpse still exists), and the tail of output.log.\n */\nexport function describeAgentDeath(agentId: string): string {\n const parts: string[] = [];\n\n const exit = readAgentExitStatus(agentId);\n if (exit) {\n parts.push(`exit=${exit.code}${exit.at ? ` at ${exit.at}` : ''}`);\n } else if (sessionExistsSync(agentId)) {\n // No exit-status file (e.g. the launcher bash was SIGKILLed before it could\n // write) but the dead pane survives via remain-on-exit — tmux still knows the\n // exit code.\n const paneExit = listPaneValuesSync(agentId, '#{pane_exit_status}').find((v) => v !== '');\n if (paneExit) parts.push(`pane_exit=${paneExit}`);\n }\n\n try {\n const logPath = join(agentDir(agentId), 'output.log');\n if (existsSync(logPath)) {\n const tail = readFileSync(logPath, 'utf-8')\n .slice(-1500)\n .trim()\n .split('\\n')\n .slice(-6)\n .join(' | ')\n .trim();\n if (tail) parts.push(`output.log tail: ${tail}`);\n }\n } catch {\n /* best effort */\n }\n\n return parts.length ? parts.join('; ') : 'no exit trace (exit-status + output.log empty)';\n}\n","import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport { getOverdeckHome } from '../paths.js';\n\nexport type StuckRemediationStage = 0 | 1 | 2 | 3;\n\nexport interface StuckRemediationState {\n lastStage: StuckRemediationStage;\n lastStageAt: string;\n firstStuckAt: string;\n /**\n * PAN-2108: flywheel-orchestrator death-recovery guard. Counts auto-relaunches\n * within a rolling window so a crash-looping orchestrator escalates to\n * paused+troubled instead of respawning forever. Optional — only set on the\n * flywheel-orchestrator agent.\n */\n respawnCount?: number;\n lastRespawnAt?: string;\n}\n\nfunction agentStateDir(agentId: string): string {\n return join(getOverdeckHome(), 'agents', agentId);\n}\n\nfunction statePath(agentId: string): string {\n return join(agentStateDir(agentId), 'stuck-remediation.json');\n}\n\nexport function readStuckRemediationState(agentId: string): StuckRemediationState | null {\n const filePath = statePath(agentId);\n if (!existsSync(filePath)) return null;\n\n try {\n return JSON.parse(readFileSync(filePath, 'utf-8')) as StuckRemediationState;\n } catch (error) {\n console.warn(`Failed to read stuck-remediation state for ${agentId}:`, error);\n return null;\n }\n}\n\nexport function writeStuckRemediationState(agentId: string, state: StuckRemediationState): void {\n mkdirSync(agentStateDir(agentId), { recursive: true });\n writeFileSync(statePath(agentId), `${JSON.stringify(state, null, 2)}\\n`, 'utf-8');\n}\n\nexport function clearStuckRemediationState(agentId: string): void {\n const filePath = statePath(agentId);\n if (!existsSync(filePath)) return;\n unlinkSync(filePath);\n}\n","/**\n * PAN-3677: positive transcript proof of the planning background-task wedge.\n *\n * The incident: planning sessions (planning-min-888 / planning-min-889) hung on\n * the provider call that followed their background Explore children reaching a\n * terminal state — one run with both children finished, one with a child dead\n * from the 262,144-token model limit while its sibling finished. The mirror\n * stayed 'active' (the Stop hook never fired), the pane kept repainting its\n * spinner, and queued `pan tell` messages were never processed.\n *\n * Stuck-remediation must NEVER interrupt a turn it cannot prove is wedged: a\n * healthy long reasoning turn is also mirror-'active' with no tool calls for\n * a while. This module supplies the positive signature from the authoritative\n * source — the session JSONL:\n *\n * 1. the parent launched at least one background child IN THE CURRENT TURN\n * (Agent tool result: \"Async agent launched successfully. … agentId: X\");\n * 2. EVERY child launched since that boundary is proven terminal, via either\n * - a task-notification queue-operation carrying a terminal\n * `<status>` (completed / failed / cancelled / killed), or\n * - a TaskOutput tool result for that task id with a terminal `<status>`.\n *\n * TURN SCOPING: at each genuine prompt boundary — a `user` entry with\n * string/text content (kickoff, recovery-resume seed) or a queue-operation\n * `remove` of a non-task-notification message (a consumed `pan tell`) —\n * children already proven TERMINAL are retired from the evidence; a closed\n * explorer batch from earlier in the session can never keep `wedged` true\n * through a later healthy turn (historical poisoning). Children NOT yet\n * terminal carry across the boundary, because real background tasks outlive\n * user turns: in the MIN-888 transcript the operator's `pan tell` was consumed\n * while the API explorer was still running, and the wedge formed only after\n * that child finished. `user` entries carrying tool_result parts are turn\n * machinery, never boundaries.\n *\n * If proof is missing — no background children since the boundary, or any\n * child without terminal proof — the answer is NOT wedged and the caller must\n * not interrupt. The detector is deliberately blind to everything else\n * (model, prompt, wall clock): those judgments live in the remediation\n * ladder.\n *\n * Known limitation: a task id can notify more than once (a finished child can\n * be resumed and run again within the same turn). Re-resume is rare in\n * planning flows and the ladder's one-stage-per-episode guard bounds the cost\n * of a stale read; if it ever false-fires, the interrupt is an Escape —\n * recoverable, transcript-safe.\n */\nimport { readFileSync } from 'fs';\nimport { resolveLatestSessionIdSync } from '../agents/activity.js';\nimport { sessionFilePath } from '../paths.js';\n\n/** Terminal background-task statuses recognized in notifications / TaskOutput results. */\nconst TERMINAL_TASK_STATUSES = new Set(['completed', 'failed', 'cancelled', 'killed', 'error']);\n\nexport interface BackgroundTaskWedgeEvidence {\n /** Every async background child the parent launched, in launch order. */\n launchedTaskIds: string[];\n /** Children with terminal proof (notification or TaskOutput result). */\n terminalTaskIds: string[];\n /** Launched children with NO terminal proof — any non-empty list vetoes the wedge. */\n nonTerminalTaskIds: string[];\n /** Terminal children whose notification was enqueued but not yet consumed by the harness. */\n unconsumedTerminalTaskIds: string[];\n /** The positive signature: at least one child launched and every child terminal. */\n wedged: boolean;\n}\n\ninterface TaskNotification {\n taskId: string;\n status: string | null;\n}\n\nfunction extractText(content: unknown): string {\n if (typeof content === 'string') return content;\n if (Array.isArray(content)) {\n return content\n .map((part) => {\n if (part && typeof part === 'object') {\n const p = part as Record<string, unknown>;\n if (p.type === 'text' && typeof p.text === 'string') return p.text;\n if (p.type === 'tool_result') return extractText(p.content);\n }\n return '';\n })\n .join('\\n');\n }\n return '';\n}\n\nfunction parseTaskNotification(content: string): TaskNotification | null {\n if (!content.includes('<task-notification>')) return null;\n const taskId = /<task-id>\\s*([a-z0-9]+)\\s*<\\/task-id>/.exec(content)?.[1];\n if (!taskId) return null;\n const status = /<status>\\s*([a-z_-]+)\\s*<\\/status>/i.exec(content)?.[1]?.toLowerCase() ?? null;\n return { taskId, status };\n}\n\n/**\n * True when a JSONL entry opens a new genuine user turn: a `user` entry with\n * string or text-only content (the kickoff prompt, a recovery-resume seed),\n * or a queue-operation `remove` of a NON-task-notification message (a\n * consumed operator `pan tell` — the harness folds it into context at that\n * point without writing a user entry). `user` entries made of tool_result\n * parts are turn machinery and NEVER boundaries; task-notification\n * queue-operations are the wedge evidence itself, also never boundaries.\n */\nfunction isPromptBoundary(e: Record<string, unknown>): boolean {\n if (e.type === 'queue-operation') {\n const content = typeof e.content === 'string' ? e.content : '';\n return e.operation === 'remove' && !content.includes('<task-notification>');\n }\n if (e.type !== 'user') return false;\n const content = (e.message as Record<string, unknown> | undefined)?.content;\n if (typeof content === 'string') return content.trim().length > 0;\n if (Array.isArray(content)) {\n const hasToolResult = content.some(\n (p) => p && typeof p === 'object' && (p as Record<string, unknown>).type === 'tool_result',\n );\n const hasText = content.some(\n (p) => p && typeof p === 'object' && (p as Record<string, unknown>).type === 'text',\n );\n return hasText && !hasToolResult;\n }\n return false;\n}\n\n/**\n * Parse one session's JSONL entries (already-parsed JSON objects, in file\n * order) into the wedge evidence. At every genuine prompt boundary (see\n * isPromptBoundary), children already proven terminal are RETIRED — only\n * still-running children carry into the new turn, because real background\n * tasks outlive user turns. Unknown/malformed lines are ignored — a parser\n * miss always degrades to \"not wedged\", never to a false positive.\n */\nexport function parseBackgroundTaskWedge(entries: readonly unknown[]): BackgroundTaskWedgeEvidence {\n let launched: string[] = [];\n let terminal = new Map<string, string>(); // taskId -> terminal status\n let consumedNotifications = new Set<string>();\n\n for (const entry of entries) {\n if (!entry || typeof entry !== 'object') continue;\n const e = entry as Record<string, unknown>;\n\n if (isPromptBoundary(e)) {\n // Retire children already proven terminal — their episode is closed and\n // must not poison later turns. Keep only still-running children: real\n // background tasks outlive user turns (see the header's MIN-888 note).\n launched = launched.filter((id) => !terminal.has(id));\n terminal = new Map([...terminal].filter(([id]) => launched.includes(id)));\n consumedNotifications = new Set([...consumedNotifications].filter((id) => launched.includes(id)));\n continue;\n }\n\n if (e.type === 'queue-operation') {\n const notification = parseTaskNotification(typeof e.content === 'string' ? e.content : '');\n if (!notification) continue;\n if (e.operation === 'remove') consumedNotifications.add(notification.taskId);\n if (notification.status && TERMINAL_TASK_STATUSES.has(notification.status)) {\n terminal.set(notification.taskId, notification.status);\n }\n continue;\n }\n\n // tool_result entries arrive as role:'user' messages with content parts.\n const message = e.message as Record<string, unknown> | undefined;\n const content = message?.content;\n if (!Array.isArray(content)) continue;\n for (const part of content) {\n if (!part || typeof part !== 'object') continue;\n const p = part as Record<string, unknown>;\n if (p.type !== 'tool_result') continue;\n const text = extractText(p.content);\n\n // Background launch acknowledgment: \"Async agent launched successfully.\n // … agentId: <id> (internal ID …)\".\n if (text.includes('Async agent launched successfully')) {\n const agentId = /agentId:\\s*([a-z0-9]+)/.exec(text)?.[1];\n if (agentId && !launched.includes(agentId)) launched.push(agentId);\n continue;\n }\n\n // Explicit collection: TaskOutput result with <task_id> + <status>.\n if (text.includes('<retrieval_status>')) {\n const taskId = /<task_id>\\s*([a-z0-9]+)\\s*<\\/task_id>/.exec(text)?.[1];\n const status = /<status>\\s*([a-z_-]+)\\s*<\\/status>/i.exec(text)?.[1]?.toLowerCase();\n if (taskId && status && TERMINAL_TASK_STATUSES.has(status)) {\n terminal.set(taskId, status);\n consumedNotifications.add(taskId);\n }\n }\n }\n }\n\n const terminalTaskIds = launched.filter((id) => terminal.has(id));\n const nonTerminalTaskIds = launched.filter((id) => !terminal.has(id));\n const unconsumedTerminalTaskIds = terminalTaskIds.filter((id) => !consumedNotifications.has(id));\n return {\n launchedTaskIds: launched,\n terminalTaskIds,\n nonTerminalTaskIds,\n unconsumedTerminalTaskIds,\n wedged: launched.length > 0 && nonTerminalTaskIds.length === 0,\n };\n}\n\n/**\n * Read a session JSONL and return its wedge evidence, or null when the file\n * cannot be read/parsed — callers treat null as \"not proven\", never as wedged.\n */\nexport function readBackgroundTaskWedgeEvidence(sessionPath: string): BackgroundTaskWedgeEvidence | null {\n let raw: string;\n try {\n raw = readFileSync(sessionPath, 'utf-8');\n } catch {\n return null;\n }\n const entries: unknown[] = [];\n for (const line of raw.split('\\n')) {\n if (!line.trim()) continue;\n try {\n entries.push(JSON.parse(line));\n } catch {\n // Tolerate torn tail writes — a partially-written last line must not\n // discard the evidence parsed before it.\n }\n }\n return parseBackgroundTaskWedge(entries);\n}\n\n/**\n * Resolve an agent's CURRENT session through the production resolver\n * (resolveLatestSessionIdSync — the same door resumeAgent uses) and parse its\n * live JSONL. Returns null when there is no resumable session or no readable\n * transcript — always degrading to \"not proven\".\n */\nexport function readAgentBackgroundTaskWedgeEvidence(\n agentId: string,\n workspace: string,\n): BackgroundTaskWedgeEvidence | null {\n const sessionId = resolveLatestSessionIdSync(agentId).sessionId;\n if (!sessionId) return null;\n return readBackgroundTaskWedgeEvidence(sessionFilePath(workspace, sessionId));\n}\n","import { Effect } from 'effect';\nimport {\n getAgentRuntimeStateSync,\n listRunningAgentsSync,\n markAgentTroubled,\n messageAgent,\n resumeAgent,\n type AgentState,\n} from '../agents.js';\nimport { countPendingAskUserQuestionsForAgent } from '../agent-enrichment.js';\nimport { logDeaconEventSync } from '../persistent-logger.js';\nimport { getReviewStatusSync, type ReviewStatus } from '../review-status.js';\nimport { capturePaneSync, detectTerminalApiErrorSync, sessionExistsSync, killSession, killSessionSync, listPaneValuesSync, sendEscapeKeyAsync } from '../tmux.js';\nimport { loadCloisterConfigSync, DEFAULT_CLOISTER_CONFIG, type StuckRemediationConfig } from './config.js';\nimport { getAgentEffectiveLastActivityMs, getAgentWorkActivityMs, isAgentIdleForNudge } from './agent-idle.js';\nimport { describeAgentDeath } from './agent-death.js';\nimport { getFlywheelActiveRunId, isFlywheelGloballyPaused } from '../overdeck/control-settings.js';\nimport {\n clearStuckRemediationState,\n readStuckRemediationState,\n writeStuckRemediationState,\n type StuckRemediationState,\n} from './stuck-remediation-state.js';\nimport { readWorkspacePlanSync } from '../xbrief/io.js';\nimport { getDispatchableItems } from '../xbrief/dag.js';\nimport { recordRecoveryFailure } from './recovery-trip.js';\nimport { readAgentBackgroundTaskWedgeEvidence } from './planning-wedge.js';\n\nexport interface StuckRemediationOptions {\n now?: number;\n}\n\nfunction issueIdForAgent(agent: AgentState): string {\n return agent.issueId || agent.id.replace(/^agent-/, '').toUpperCase();\n}\n\nexport function shouldSkipReviewStatus(status: ReviewStatus | null): boolean {\n if (!status) return false;\n if (status.stuck || status.deaconIgnored || status.mergeStatus === 'merged' || status.readyForMerge) return true;\n if (status.reviewStatus === 'blocked' || status.reviewStatus === 'failed') return true;\n if (status.verificationStatus === 'failed' || status.testStatus === 'failed') return true;\n // PAN-2581: the pipeline OWNS the issue while review/test advance it — review in\n // flight, a passed review awaiting test, or an un-serviced durable review request\n // (`pan done` already ran; dispatch owns the next step). Warm-idle is the work\n // agent's intended state here (PAN-2579). Poking it told it to re-run `pan done`,\n // which re-armed review and clobbered landed verdicts (PAN-399 burned $63 on this).\n if (status.reviewStatus === 'reviewing' || status.reviewStatus === 'passed') return true;\n return status.reviewStatus === 'pending' && !!status.reviewRequestedAt;\n}\n\n/**\n * PAN-2581 (FR-2, residual): phase gate for the health-check poke loop\n * (service.ts pokeAgent → pokeAgentWithEscalation → idle-alive pause), the\n * SECOND independent idleness consumer besides stuck-remediation. A warm-idle\n * work agent on a pipeline-owned issue — and a warm-idle review/test agent\n * after its verdict — must never be poked (\"are you stuck?\") or idle-alive\n * paused: the poke spends tokens re-explaining the wait, and the pause\n * manufactures the paused-delivery-target deadlock PAN-2461 exists to undo.\n * A genuinely stalled mid-review parent is covered by the PAN-2584 liveness\n * deadline, not pokes. Owed-rework agents (review blocked/failed, tests\n * failed) are ALSO skipped here by design: shouldSkipReviewStatus returns\n * true for those because the PAN-2519 wedged-rework path owns their\n * escalation — the health-check poke loop must not double-drive them.\n * Roles outside work/review/test (plan, strike, flywheel, sequencer) keep\n * their existing idleness semantics.\n */\nexport function shouldSkipIdlePokeForAgent(\n agent: Pick<AgentState, 'id' | 'issueId' | 'role'> | null,\n readStatus: (issueId: string) => ReviewStatus | null = getReviewStatusSync,\n): boolean {\n if (!agent) return false;\n if (agent.role !== 'work' && agent.role !== 'review' && agent.role !== 'test') return false;\n const issueId = (agent.issueId\n || agent.id.replace(/^agent-/, '').replace(/-(review|test|ship)(-.*)?$/, '').replace(/-slot-\\d+$/, '')\n ).toUpperCase();\n return shouldSkipReviewStatus(readStatus(issueId));\n}\n\n// PAN-2519: the rework subset of shouldSkipReviewStatus — a work agent that OWES\n// a fix (review blocked/failed, verification failed, tests failed) and is NOT\n// already done/ignored (merged, readyForMerge, stuck, deaconIgnored). These are\n// exactly the agents the idle-escalation path skips (via shouldSkipReviewStatus)\n// AND the PAN-2209 dead-end respawn skips (session still exists) — so a\n// wedged-but-alive rework agent falls through both and stalls invisibly.\nfunction hasPendingRework(status: ReviewStatus | null): boolean {\n if (!status) return false;\n if (status.stuck || status.deaconIgnored || status.mergeStatus === 'merged' || status.readyForMerge) return false;\n return (\n status.reviewStatus === 'blocked' ||\n status.reviewStatus === 'failed' ||\n status.verificationStatus === 'failed' ||\n status.testStatus === 'failed'\n );\n}\n\n// Mirror of the deacon dead-end circuit breaker (deacon.ts: autoRequeueCount >= 25\n// halts respawn). Below the ceiling we kill a wedged rework agent so PAN-2209\n// respawns it fresh; at/above it, respawn would be refused, so we park it as\n// troubled instead — leaving a live operator signal rather than a dead session.\nconst STUCK_KILL_REQUEUE_CEILING = 25;\n\n// A wedged-but-alive work agent holding pending rework: kill its session so the\n// deacon's PAN-2209 dead-end path respawns a fresh agent whose kickoff prompt\n// drains .pan/feedback. Returns true when it handled the agent (caller returns).\nasync function evaluateWedgedReworkAgent(\n agent: AgentState,\n config: StuckRemediationConfig,\n now: number,\n actions: string[],\n): Promise<boolean> {\n const agentId = agent.id;\n if (agent.role !== 'work' || !agent.workspace) return false;\n\n const issueId = issueIdForAgent(agent);\n const status = getReviewStatusSync(issueId);\n if (!hasPendingRework(status)) return false;\n\n const lastActivityMs = getAgentEffectiveLastActivityMs(agentId);\n if (lastActivityMs === null || !Number.isFinite(lastActivityMs)) return false;\n\n const stuckState = readStuckRemediationState(agentId);\n if (stuckState) {\n const firstStuckMs = new Date(stuckState.firstStuckAt).getTime();\n if (Number.isFinite(firstStuckMs) && lastActivityMs > firstStuckMs) {\n // The agent resumed activity since we flagged it — clear and let the\n // normal path re-evaluate on a future tick.\n clearStuckRemediationState(agentId);\n return false;\n }\n }\n\n const idleMinutes = Math.floor((now - lastActivityMs) / 60_000);\n const lastStage = stuckState?.lastStage ?? 0;\n // One action per stuck episode (lastStage < 3). A successful respawn advances\n // activity and clears state above, so the next wedge is a fresh episode.\n if (idleMinutes < config.stage3_minutes || lastStage >= 3) return false;\n\n const firstStuck = firstStuckAt(new Date(lastActivityMs).toISOString(), stuckState);\n const requeues = status?.autoRequeueCount ?? 0;\n\n if (requeues >= STUCK_KILL_REQUEUE_CEILING) {\n // Chronic re-death: the deacon breaker would refuse another respawn, so\n // parking as troubled surfaces it for an operator instead of a dead session.\n markAgentTroubled(agentId);\n writeStuckRemediationState(agentId, stageState(3, now, firstStuck));\n logAction(actions, transitionAction(3, issueId, idleMinutes, 'rework-wedge-troubled'));\n await surfaceStuckNeedsYou(agent, issueId, firstStuck, actions);\n return true;\n }\n\n killSessionSync(agentId);\n writeStuckRemediationState(agentId, stageState(3, now, firstStuck));\n logAction(actions, transitionAction(3, issueId, idleMinutes, 'killed-for-respawn'));\n return true;\n}\n\nfunction shouldCheckReadyBeadsForAgent(agent: AgentState, now: number): boolean {\n const agentId = agent.id;\n if (!agentId) return false;\n if (agent.status !== 'running') return false;\n if (agent.role !== 'work') return false;\n if (!agent.workspace) return false;\n const completedAt = (agent as AgentState & { completedAt?: string }).completedAt;\n if (agent.paused || agent.troubled || completedAt) return false;\n if (!sessionExistsSync(agentId)) return false;\n if (shouldSkipReviewStatus(getReviewStatusSync(issueIdForAgent(agent)))) return false;\n return isAgentIdleForNudge(agentId, 5 * 60 * 1000, now);\n}\n\nfunction firstStuckAt(runtimeLastActivity: string, stuckState: StuckRemediationState | null): string {\n return stuckState?.firstStuckAt ?? runtimeLastActivity;\n}\n\nfunction stageState(\n stage: 1 | 2 | 3,\n now: number,\n firstStuck: string,\n prev?: StuckRemediationState | null,\n): StuckRemediationState {\n // Carry the flywheel respawn-cap accounting (respawnCount/lastRespawnAt) across\n // stage transitions — otherwise a stage1/stage2 write between relaunches would\n // reset the cap and the wedge-relaunch loop could never escalate (PAN-2160).\n return {\n lastStage: stage,\n lastStageAt: new Date(now).toISOString(),\n firstStuckAt: firstStuck,\n ...(prev?.respawnCount !== undefined ? { respawnCount: prev.respawnCount } : {}),\n ...(prev?.lastRespawnAt !== undefined ? { lastRespawnAt: prev.lastRespawnAt } : {}),\n };\n}\n\nfunction transitionAction(stage: 1 | 2 | 3, issueId: string, idleMinutes: number, action: string): string {\n return `[deacon] stuck-remediation stage=${stage} issue=${issueId} idleMin=${idleMinutes} action=${action}`;\n}\n\nfunction logAction(actions: string[], action: string): void {\n actions.push(action);\n console.log(action);\n logDeaconEventSync(action);\n}\n\nasync function surfaceStuckNeedsYou(agent: AgentState, issueId: string, generation: string, actions: string[]): Promise<void> {\n if (!agent.workspace) return;\n const failure = await recordRecoveryFailure(agent.workspace, issueId, 'stuck-remediation', generation, 1);\n if (failure.emitNeedsYou) logAction(actions, `[deacon] needs-you ${issueId}: stuck remediation exhausted`);\n}\n\nasync function evaluateAgent(\n agent: AgentState,\n config: StuckRemediationConfig,\n now: number,\n actions: string[],\n): Promise<void> {\n const agentId = agent.id;\n if (!agentId) return;\n if (agent.status !== 'running') return;\n const completedAt = (agent as AgentState & { completedAt?: string }).completedAt;\n if (agent.paused || agent.troubled || completedAt) return;\n\n // PAN-2108: evaluate the flywheel orchestrator BEFORE the session-exists guard.\n // Its recovery must be able to fresh-launch even when the session has fully\n // vanished (not just gone zombie); evaluateFlywheelOrchestrator does its own\n // liveness check.\n if (agent.role === 'flywheel') {\n await evaluateFlywheelOrchestrator(agent, config, now, actions);\n return;\n }\n if (!sessionExistsSync(agentId)) return;\n if (agent.role === 'plan') {\n await evaluatePlanningAgent(agent, config, now, actions);\n return;\n }\n // PAN-2519: catch wedged-but-alive work agents that OWE a rework fix before the\n // ready-beads gate skips them (shouldSkipReviewStatus is true for rework state).\n // These are invisible to both idle-escalation (skipped here) and PAN-2209\n // respawn (session still exists); killing the session bridges them to respawn.\n if (await evaluateWedgedReworkAgent(agent, config, now, actions)) return;\n if (!shouldCheckReadyBeadsForAgent(agent, now)) return;\n if (!agent.workspace) return;\n\n const issueId = issueIdForAgent(agent);\n const plan = readWorkspacePlanSync(agent.workspace);\n if (!plan) return;\n if (getDispatchableItems(plan, new Set()).length > 0) return;\n\n const lastActivityMs = getAgentEffectiveLastActivityMs(agentId);\n if (lastActivityMs === null) return;\n if (!Number.isFinite(lastActivityMs)) return;\n const lastActivity = new Date(lastActivityMs).toISOString();\n\n const stuckState = readStuckRemediationState(agentId);\n if (stuckState) {\n const firstStuckMs = new Date(stuckState.firstStuckAt).getTime();\n if (Number.isFinite(firstStuckMs) && lastActivityMs > firstStuckMs) {\n clearStuckRemediationState(agentId);\n return;\n }\n }\n\n const idleMinutes = Math.floor((now - lastActivityMs) / 60_000);\n const lastStage = stuckState?.lastStage ?? 0;\n const firstStuck = firstStuckAt(lastActivity, stuckState);\n\n const terminalProviderError = detectTerminalApiErrorSync(capturePaneSync(agentId, 80));\n if (terminalProviderError) {\n markAgentTroubled(agentId);\n writeStuckRemediationState(agentId, stageState(3, now, firstStuck));\n logAction(actions, `${agentId} provider-terminal: ${terminalProviderError.summary}`);\n await surfaceStuckNeedsYou(agent, issueId, firstStuck, actions);\n return;\n }\n\n if (idleMinutes >= config.stage3_minutes && lastStage < 3) {\n markAgentTroubled(agentId);\n writeStuckRemediationState(agentId, stageState(3, now, firstStuck));\n logAction(actions, transitionAction(3, issueId, idleMinutes, 'marked-troubled'));\n await surfaceStuckNeedsYou(agent, issueId, firstStuck, actions);\n return;\n }\n\n if (idleMinutes >= config.stage2_minutes && lastStage < 2) {\n const message = `Resuming after auto-detected stall (${idleMinutes} min idle). Review your last work and decide whether to continue or signal done with \\`pan done ${issueId}\\`.`;\n const result = await resumeAgent(agentId, message);\n if (result.success) {\n writeStuckRemediationState(agentId, stageState(2, now, firstStuck));\n logAction(actions, transitionAction(2, issueId, idleMinutes, 'resumed'));\n } else {\n // PAN-2108: surface WHY (exit code + output tail) instead of an opaque\n // \"resume-failed\" — a resume usually fails because the process died.\n const action = `${transitionAction(2, issueId, idleMinutes, 'resume-failed')} — death: ${describeAgentDeath(agentId)}`;\n console.warn(action);\n logDeaconEventSync(action);\n }\n return;\n }\n\n if (idleMinutes >= config.stage1_minutes && lastStage < 1) {\n const message = `You appear stuck — no tool calls for ${idleMinutes} min. If your implementation is complete, run \\`pan done ${issueId}\\`. Otherwise reply with a one-line summary of what you're waiting on, then continue.`;\n await messageAgent(agentId, message);\n writeStuckRemediationState(agentId, stageState(1, now, firstStuck));\n logAction(actions, transitionAction(1, issueId, idleMinutes, 'poked'));\n }\n}\n\n/**\n * PAN-3677: remediation decision for a planning session with no pending\n * AskUserQuestion. Pure — side effects live in evaluatePlanningAgent.\n *\n * The wedge this catches: a planning session whose turn never ends because the\n * provider call hung (observed on k3[1m] planning sessions right after\n * background Explore children reached a terminal state — all-finished AND\n * mixed failed/finished). The detector combines three signals: the runtime\n * mirror still says 'active' (the Stop hook never fired — the turn never\n * ended), work-product activity (hook events, transcript writes) has been\n * silent past the stage threshold, AND the session transcript positively\n * proves background children were in flight this turn with every child\n * terminal (planning-wedge.ts).\n *\n * Guards against interrupting healthy turns:\n * - mirror 'idle' means the Stop hook fired — the agent is at its prompt\n * (operator's turn in a manual session). Never interrupt.\n * - `wedgeProven` requires the transcript itself to prove background children\n * were in flight AND every child is terminal (parseBackgroundTaskWedge). A\n * silent 'active' turn without that proof is a healthy long\n * reasoning/provider turn — never interrupt it.\n * - work activity fresher than stage1_minutes means real work is flowing\n * (tool calls, transcript writes) — never interrupt, even though the pane\n * repaint alone would look identical. The detector never consults tmux\n * window_activity: the spinner/task panel repaints every second during a\n * hung call and would mask the wedge (see getAgentWorkActivityMs).\n *\n * The ladder is bounded by construction: interrupt → kill+resume → troubled.\n * No stage waits on anything after every child is terminal.\n */\nexport type PlanningWedgeDecision =\n | { kind: 'none' }\n | { kind: 'interrupt-nudge'; idleMinutes: number }\n | { kind: 'kill-resume'; idleMinutes: number }\n | { kind: 'troubled'; idleMinutes: number };\n\nexport function decidePlanningWedgeRemediation(opts: {\n mirrorState: string | null;\n pendingQuestions: number;\n /** Positive transcript proof (parseBackgroundTaskWedge): background children were in flight AND every one is terminal. */\n wedgeProven: boolean;\n workActivityMs: number | null;\n lastStage: number;\n now: number;\n config: StuckRemediationConfig;\n}): PlanningWedgeDecision {\n const { mirrorState, pendingQuestions, wedgeProven, workActivityMs, lastStage, now, config } = opts;\n // A pending AskUserQuestion is the operator's slot (auto sessions get the\n // default-choice nudge elsewhere) — never treat it as a wedge.\n if (pendingQuestions > 0) return { kind: 'none' };\n // Only a stale-'active' mirror is a mid-turn wedge. 'idle' means the Stop\n // hook fired (turn ended, agent at its prompt); 'suspended'/'stopped'/\n // 'waiting-on-human' are owned by other paths; null means the mirror never\n // came up and we cannot tell wedge from healthy.\n if (mirrorState !== 'active') return { kind: 'none' };\n // The positive signature: without transcript proof that background children\n // were in flight and ALL of them are terminal, a silent 'active' turn is a\n // healthy long reasoning/provider turn — never interrupt it.\n if (!wedgeProven) return { kind: 'none' };\n if (workActivityMs === null || !Number.isFinite(workActivityMs)) return { kind: 'none' };\n const idleMinutes = Math.floor((now - workActivityMs) / 60_000);\n if (idleMinutes >= config.stage3_minutes) {\n if (lastStage >= 3) return { kind: 'none' };\n return { kind: 'troubled', idleMinutes };\n }\n if (idleMinutes >= config.stage2_minutes) {\n if (lastStage >= 2) return { kind: 'none' };\n return { kind: 'kill-resume', idleMinutes };\n }\n if (idleMinutes >= config.stage1_minutes) {\n if (lastStage >= 1) return { kind: 'none' };\n return { kind: 'interrupt-nudge', idleMinutes };\n }\n return { kind: 'none' };\n}\n\n/**\n * Episode-clear rule for the planning wedge path, keyed on WORK activity only\n * (never pane repaints — the spinner would \"clear\" a still-wedged episode and\n * re-fire stage 1 every tick): work flowing after the episode opened means the\n * recovery worked.\n */\nexport function shouldClearPlanningWedgeEpisode(\n stuckState: StuckRemediationState | null,\n workActivityMs: number,\n): boolean {\n if (!stuckState) return false;\n const firstStuckMs = new Date(stuckState.firstStuckAt).getTime();\n return Number.isFinite(firstStuckMs) && workActivityMs > firstStuckMs;\n}\n\n/** Side-effecting doors the wedge executor needs — injected for tests. */\nexport interface PlanningWedgeEffectDeps {\n sendEscape: (agentId: string) => Promise<void>;\n message: (agentId: string, msg: string) => Promise<unknown>;\n /** Async tmux kill (Effect-based `killSession` from tmux.ts) — never the sync variant from server-reachable code. */\n killSession: (agentId: string) => Promise<void>;\n resume: (agentId: string, msg: string) => Promise<{ success: boolean; error?: string }>;\n markTroubled: (agentId: string) => void;\n writeState: (agentId: string, state: StuckRemediationState) => void;\n surfaceNeedsYou: () => Promise<void>;\n log: (msg: string) => void;\n}\n\n/**\n * Execute one wedge-ladder decision. Ordering is the contract: stage 1 sends\n * Escape BEFORE queueing its single nudge (the interrupt returns the prompt;\n * the nudge — and any queued operator messages — are processed after). Stage 2\n * kills the session and plain-resumes the SAME saved session id, so the\n * transcript (and every explorer's findings) survives — unlike the\n * compact-respawn path that lost conversation-only survey notes in the manual\n * MIN-889 recovery.\n */\nexport async function executePlanningWedgeDecision(\n agentId: string,\n issueId: string,\n decision: Exclude<PlanningWedgeDecision, { kind: 'none' }>,\n firstStuck: string,\n now: number,\n deps: PlanningWedgeEffectDeps,\n): Promise<void> {\n if (decision.kind === 'interrupt-nudge') {\n // Escape cancels the in-flight (hung) provider call. The harness returns to\n // its prompt and processes queued operator messages; the nudge below then\n // tells the planner how to continue without re-entering the blocking wait.\n try {\n await deps.sendEscape(agentId);\n } catch (err) {\n console.error(`[deacon] Failed to interrupt wedged planning session ${agentId}:`, err);\n return;\n }\n const message =\n `Your previous turn stalled for ${decision.idleMinutes} min with no progress and was interrupted (a hung provider call). ` +\n `Process any queued operator messages first. Then collect background-task results NON-blocking (TaskOutput with block:false) — ` +\n `every child that reached a terminal state already has its result or error available; do NOT re-enter a blocking wait. ` +\n `Continue planning now: write the PRD/xBRIEF artifacts and proceed to your instructed stopping point.`;\n // The Escape already landed — the interrupt happened whether or not the\n // nudge arrives. Record stage 1 either way: skipping the state write on a\n // delivery failure would let every patrol re-Escape an already-unwedged\n // session forever.\n let deliveryError: string | null = null;\n try {\n await deps.message(agentId, message);\n } catch (err) {\n deliveryError = err instanceof Error ? err.message : String(err);\n }\n deps.writeState(agentId, stageState(1, now, firstStuck));\n deps.log(deliveryError\n ? `${transitionAction(1, issueId, decision.idleMinutes, 'interrupted-wedged-turn')} — nudge delivery failed: ${deliveryError}`\n : transitionAction(1, issueId, decision.idleMinutes, 'interrupted-wedged-turn'));\n return;\n }\n\n if (decision.kind === 'kill-resume') {\n try {\n await deps.killSession(agentId);\n } catch {\n /* best effort — the resume below fails cleanly if the session lingers */\n }\n const message =\n `Resuming after an automated stall recovery (${decision.idleMinutes} min with no progress). ` +\n `Your transcript is intact — continue planning from where you left off. ` +\n `Collect background-task results NON-blocking (TaskOutput with block:false) and proceed.`;\n const result = await deps.resume(agentId, message);\n if (result.success) {\n deps.writeState(agentId, stageState(2, now, firstStuck));\n deps.log(transitionAction(2, issueId, decision.idleMinutes, 'kill-resumed-wedged-planning'));\n } else {\n deps.markTroubled(agentId);\n deps.writeState(agentId, stageState(3, now, firstStuck));\n deps.log(`${transitionAction(3, issueId, decision.idleMinutes, 'kill-resume-failed-troubled')} — ${result.error ?? 'unknown'}`);\n await deps.surfaceNeedsYou();\n }\n return;\n }\n\n // troubled\n deps.markTroubled(agentId);\n deps.writeState(agentId, stageState(3, now, firstStuck));\n deps.log(transitionAction(3, issueId, decision.idleMinutes, 'wedged-planning-troubled'));\n await deps.surfaceNeedsYou();\n}\n\nasync function evaluatePlanningAgent(\n agent: AgentState,\n config: StuckRemediationConfig,\n now: number,\n actions: string[],\n): Promise<void> {\n const agentId = agent.id;\n const issueId = issueIdForAgent(agent);\n const pendingQuestions = await Effect.runPromise(countPendingAskUserQuestionsForAgent(agentId));\n\n // An unanswered AskUserQuestion parks the session on the operator. Manual\n // sessions wait by design; --auto sessions get the default-choice nudge.\n if (pendingQuestions > 0) {\n if (!isAgentIdleForNudge(agentId, 5 * 60 * 1000, now)) return;\n if (agent.auto !== true) return;\n const lastActivityMs = getAgentEffectiveLastActivityMs(agentId);\n if (lastActivityMs === null || !Number.isFinite(lastActivityMs)) return;\n const lastActivity = new Date(lastActivityMs).toISOString();\n const stuckState = readStuckRemediationState(agentId);\n if (stuckState) {\n const firstStuckMs = new Date(stuckState.firstStuckAt).getTime();\n if (Number.isFinite(firstStuckMs) && lastActivityMs > firstStuckMs) {\n clearStuckRemediationState(agentId);\n return;\n }\n }\n const idleMinutes = Math.floor((now - lastActivityMs) / 60_000);\n const lastStage = stuckState?.lastStage ?? 0;\n if (idleMinutes < config.stage1_minutes || lastStage >= 1) return;\n const message =\n `This planning session was launched with \\`pan plan ${issueId} --auto\\`, so do not wait for operator input. ` +\n `Proceed with the most defensible default from the issue/PRD/comments, record the choice in \\`plan.autoDecisions[]\\` with rationale, and continue to \\`pan plan finalize\\`. ` +\n `Only halt for a genuine contradiction between authoritative inputs.`;\n await messageAgent(agentId, message);\n writeStuckRemediationState(agentId, stageState(1, now, firstStuckAt(lastActivity, stuckState)));\n logAction(actions, transitionAction(1, issueId, idleMinutes, 'auto-planning-default'));\n return;\n }\n\n // PAN-3677: mid-turn wedge. Every signal here is WORK activity (hook mirror +\n // transcript heartbeat), never tmux window_activity — Claude Code repaints\n // its spinner/task panel every second during a hung provider call, so the\n // pane looks alive while no work flows. Keying on the pane would (a) hide\n // the wedge entirely and (b) instantly \"clear\" the episode state,\n // re-firing stage 1 every tick.\n const workActivityMs = getAgentWorkActivityMs(agentId);\n if (workActivityMs === null || !Number.isFinite(workActivityMs)) return;\n\n const stuckState = readStuckRemediationState(agentId);\n if (shouldClearPlanningWedgeEpisode(stuckState, workActivityMs)) {\n clearStuckRemediationState(agentId);\n return;\n }\n\n const mirrorState = getAgentRuntimeStateSync(agentId)?.state ?? null;\n if (mirrorState !== 'active') return;\n const idleMinutesGate = Math.floor((now - workActivityMs) / 60_000);\n if (idleMinutesGate < config.stage1_minutes) return;\n\n // The positive signature (readAgentBackgroundTaskWedgeEvidence): the\n // transcript of the CURRENT turn must prove background children were in\n // flight and EVERY child is terminal. Without it, a silent 'active' turn is\n // a healthy long reasoning/provider turn and is never interrupted.\n const wedgeProven = agent.workspace\n ? readAgentBackgroundTaskWedgeEvidence(agentId, agent.workspace)?.wedged === true\n : false;\n\n const decision = decidePlanningWedgeRemediation({\n mirrorState,\n pendingQuestions,\n wedgeProven,\n workActivityMs,\n lastStage: stuckState?.lastStage ?? 0,\n now,\n config,\n });\n if (decision.kind === 'none') return;\n\n await executePlanningWedgeDecision(agentId, issueId, decision, firstStuckAt(new Date(workActivityMs).toISOString(), stuckState), now, {\n sendEscape: (id) => sendEscapeKeyAsync(id),\n message: (id, msg) => messageAgent(id, msg),\n killSession: (id) => Effect.runPromise(killSession(id)),\n resume: (id, msg) => resumeAgent(id, msg),\n markTroubled: (id) => markAgentTroubled(id),\n writeState: (id, state) => writeStuckRemediationState(id, state),\n surfaceNeedsYou: () => surfaceStuckNeedsYou(agent, issueId, firstStuckAt(new Date(workActivityMs).toISOString(), stuckState), actions),\n log: (msg) => logAction(actions, msg),\n });\n}\n\n// The flywheel orchestrator is a singleton with role 'flywheel'. It ticks\n// sub-minute by design (each tick produces a FlywheelStatus snapshot via\n// `pan flywheel emit-status`), so a long silence indicates a stuck model call\n// or a dropped tick loop — not the natural between-task idleness work agents\n// exhibit.\n//\n// PAN-2108: the orchestrator may run on the ohmypi (omp) harness (no\n// ScheduleWakeup tool); when its process DIES (RUN-30: silent crash mid-run)\n// the runtime mirror goes stale-but-\"active\", so a dead orchestrator must\n// self-heal: kill the zombie session and fresh-launch the run.\n//\n// PAN-2160: the orchestrator is the pipeline's last stand, so NEITHER death NOR\n// a wedged (alive-but-silent) tick loop may ever PARK it. Both recover the same\n// way — relaunch (capped); only a genuine crash/wedge loop past the cap escalates\n// to paused+troubled (operator needed). Two work-agent gates that used to wrongly\n// kill the orchestrator are removed:\n// 1. OVERDECK_NO_RESUME is NOT honored here — it gates *work-agent*\n// resurrection, not the controller. The operator stops the flywheel with\n// `pan flywheel stop` (clears the active run ⇒ `noop` below), or halts\n// everything with `pan admin cloister freeze` (suspends the whole patrol, so\n// this code never runs). That separation is the real kill-switch.\n// 2. The terminal idle stage relaunches instead of pause+troubled — a wedged\n// orchestrator must be restarted, not parked (RUN-36 was parked at\n// idleMin=205 and the entire pipeline stalled).\nconst FLYWHEEL_RESPAWN_WINDOW_MS = 30 * 60 * 1000;\nconst FLYWHEEL_MAX_RESPAWNS = 3;\nconst FLYWHEEL_ORCHESTRATOR_AGENT_ID = 'flywheel-orchestrator';\n\nexport type FlywheelRemediationDecision =\n | { kind: 'noop' }\n | { kind: 'relaunch'; respawnCount: number }\n | { kind: 'escalate'; respawnCount: number };\n\n/**\n * Pure decision for recovering a dead or wedged flywheel orchestrator (no I/O —\n * side effects live in remediateFlywheelOrchestrator). The respawn cap\n * (FLYWHEEL_MAX_RESPAWNS within FLYWHEEL_RESPAWN_WINDOW_MS) stops an infinite\n * relaunch loop: past the cap, escalate to paused+troubled. `hasActiveRun` false\n * ⇒ the operator stopped the flywheel deliberately ⇒ do not resurrect.\n */\nexport function decideFlywheelRemediation(opts: {\n hasActiveRun: boolean;\n prev: StuckRemediationState | null;\n now: number;\n}): FlywheelRemediationDecision {\n if (!opts.hasActiveRun) return { kind: 'noop' };\n const lastRespawnMs = opts.prev?.lastRespawnAt ? new Date(opts.prev.lastRespawnAt).getTime() : 0;\n const withinWindow = Number.isFinite(lastRespawnMs) && opts.now - lastRespawnMs < FLYWHEEL_RESPAWN_WINDOW_MS;\n const respawnCount = withinWindow ? opts.prev?.respawnCount ?? 0 : 0;\n if (respawnCount >= FLYWHEEL_MAX_RESPAWNS) return { kind: 'escalate', respawnCount };\n return { kind: 'relaunch', respawnCount: respawnCount + 1 };\n}\n\n/** True when the orchestrator's process is actually gone (session missing or dead pane). */\nfunction isFlywheelOrchestratorDead(agentId: string): boolean {\n if (!sessionExistsSync(agentId)) return true;\n return listPaneValuesSync(agentId, '#{pane_dead}').some((v) => v === '1');\n}\n\n/**\n * Recover a dead or wedged flywheel orchestrator: relaunch (capped) or, past the\n * cap, pause+trouble. `reason` describes why recovery fired (death vs wedge) for\n * the deacon log. NO_RESUME is intentionally NOT consulted (see header comment) —\n * the operator gate is the active run (`pan flywheel stop`) / patrol freeze.\n */\nasync function remediateFlywheelOrchestrator(\n agentId: string,\n now: number,\n actions: string[],\n reason: string,\n): Promise<void> {\n const decision = decideFlywheelRemediation({\n hasActiveRun: Boolean(getFlywheelActiveRunId()),\n prev: readStuckRemediationState(agentId),\n now,\n });\n if (decision.kind === 'noop') return;\n\n const { resumeFlywheel, pauseFlywheel } = await import('./flywheel.js');\n const prev = readStuckRemediationState(agentId);\n const nowIso = new Date(now).toISOString();\n\n if (decision.kind === 'escalate') {\n await pauseFlywheel();\n markAgentTroubled(agentId);\n writeStuckRemediationState(agentId, {\n lastStage: 3,\n lastStageAt: nowIso,\n firstStuckAt: prev?.firstStuckAt ?? nowIso,\n respawnCount: decision.respawnCount,\n lastRespawnAt: prev?.lastRespawnAt,\n });\n logAction(\n actions,\n `[deacon] FLYWHEEL orchestrator ${reason} and exceeded ${FLYWHEEL_MAX_RESPAWNS} relaunches in ${FLYWHEEL_RESPAWN_WINDOW_MS / 60_000}min — paused + troubled; operator needed`,\n );\n return;\n }\n\n // Clear the dead/zombie/wedged tmux session so the fresh new-session won't\n // collide (\"duplicate session\" — the failure that defeated recovery in RUN-30).\n try {\n killSessionSync(agentId);\n } catch {\n /* best effort — session may already be gone */\n }\n\n try {\n await resumeFlywheel({ resumeCause: 'system' });\n writeStuckRemediationState(agentId, {\n lastStage: 0,\n lastStageAt: nowIso,\n firstStuckAt: nowIso,\n respawnCount: decision.respawnCount,\n lastRespawnAt: nowIso,\n });\n logAction(\n actions,\n `[deacon] FLYWHEEL orchestrator ${reason} — fresh-launched (relaunch ${decision.respawnCount}/${FLYWHEEL_MAX_RESPAWNS})`,\n );\n } catch (error) {\n logAction(\n actions,\n `[deacon] FLYWHEEL orchestrator ${reason} — relaunch FAILED: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\nasync function evaluateFlywheelOrchestrator(\n agent: AgentState,\n config: StuckRemediationConfig,\n now: number,\n actions: string[],\n): Promise<void> {\n const agentId = agent.id;\n\n // Dead process ≠ idle agent. Check real liveness via tmux first — the runtime\n // mirror lies (stays \"active\") when omp dies without updating it (RUN-30).\n if (isFlywheelOrchestratorDead(agentId)) {\n await remediateFlywheelOrchestrator(agentId, now, actions, `DIED (${describeAgentDeath(agentId)})`);\n return;\n }\n\n if (!isAgentIdleForNudge(agentId, 5 * 60 * 1000, now)) return;\n\n const runtime = getAgentRuntimeStateSync(agentId);\n if (!runtime?.lastActivity) return;\n\n const lastActivityMs = new Date(runtime.lastActivity).getTime();\n if (!Number.isFinite(lastActivityMs)) return;\n\n const stuckState = readStuckRemediationState(agentId);\n if (stuckState) {\n const firstStuckMs = new Date(stuckState.firstStuckAt).getTime();\n if (Number.isFinite(firstStuckMs) && lastActivityMs > firstStuckMs) {\n clearStuckRemediationState(agentId);\n return;\n }\n }\n\n const idleMinutes = Math.floor((now - lastActivityMs) / 60_000);\n const lastStage = stuckState?.lastStage ?? 0;\n const firstStuck = firstStuckAt(runtime.lastActivity, stuckState);\n\n // PAN-2160: the terminal idle stage RELAUNCHES the wedged orchestrator (capped),\n // it never pause+troubles it. RUN-36 was parked here at idleMin=205 and the\n // whole pipeline stalled.\n if (idleMinutes >= config.flywheel_stage3_minutes && lastStage < 3) {\n await remediateFlywheelOrchestrator(agentId, now, actions, `wedged (idle ${idleMinutes}min)`);\n return;\n }\n\n if (idleMinutes >= config.flywheel_stage2_minutes && lastStage < 2) {\n const message = `Stage 2: idle ${idleMinutes} min — run a FULL flywheel tick NOW: inventory -> diagnose -> suggest -> launch ready work -> \\`pan flywheel emit-status\\`. Then call ScheduleWakeup(delaySeconds:1000) to arm the next tick. Do NOT ask the operator a question, do NOT wait, and do NOT just emit a stale status or pause.`;\n await messageAgent(agentId, message);\n writeStuckRemediationState(agentId, stageState(2, now, firstStuck, stuckState));\n logAction(actions, transitionAction(2, 'FLYWHEEL', idleMinutes, 'escalated-nudge'));\n return;\n }\n\n if (idleMinutes >= config.flywheel_stage1_minutes && lastStage < 1) {\n const message = `You appear stuck — ${idleMinutes} min since your last tick. Run a FULL flywheel tick NOW: inventory -> diagnose -> suggest -> launch ready work -> \\`pan flywheel emit-status\\`. Then call ScheduleWakeup(delaySeconds:1000) to arm the next tick. Do NOT ask the operator a question, do NOT wait, and do NOT just emit a stale status or pause.`;\n await messageAgent(agentId, message);\n writeStuckRemediationState(agentId, stageState(1, now, firstStuck, stuckState));\n logAction(actions, transitionAction(1, 'FLYWHEEL', idleMinutes, 'poked'));\n }\n}\n\nasync function reconcileActiveFlywheelWithoutRunningAgent(now: number, actions: string[]): Promise<void> {\n if (!getFlywheelActiveRunId()) return;\n if (isFlywheelGloballyPaused()) return;\n if (sessionExistsSync(FLYWHEEL_ORCHESTRATOR_AGENT_ID)) return;\n\n await remediateFlywheelOrchestrator(\n FLYWHEEL_ORCHESTRATOR_AGENT_ID,\n now,\n actions,\n `DIED (${describeAgentDeath(FLYWHEEL_ORCHESTRATOR_AGENT_ID)})`,\n );\n}\n\nexport async function checkStuckAgentRemediation(opts: StuckRemediationOptions = {}): Promise<string[]> {\n const config = loadCloisterConfigSync().stuck_remediation ?? DEFAULT_CLOISTER_CONFIG.stuck_remediation!;\n if (!config.enabled) return [];\n\n const actions: string[] = [];\n const now = opts.now ?? Date.now();\n const runningAgents = listRunningAgentsSync();\n let sawFlywheelOrchestrator = false;\n\n for (const agent of runningAgents) {\n if (agent.id === FLYWHEEL_ORCHESTRATOR_AGENT_ID || agent.role === 'flywheel') {\n sawFlywheelOrchestrator = true;\n }\n try {\n await evaluateAgent(agent, config, now, actions);\n } catch (error) {\n const agentId = agent.id || '(unknown)';\n const message = `[deacon] stuck-remediation agent=${agentId} error=${error instanceof Error ? error.message : String(error)}`;\n console.error(message, error);\n logDeaconEventSync(message);\n }\n }\n\n if (!sawFlywheelOrchestrator) {\n try {\n await reconcileActiveFlywheelWithoutRunningAgent(now, actions);\n } catch (error) {\n const message = `[deacon] stuck-remediation agent=${FLYWHEEL_ORCHESTRATOR_AGENT_ID} error=${error instanceof Error ? error.message : String(error)}`;\n console.error(message, error);\n logDeaconEventSync(message);\n }\n }\n\n return actions;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"stuck-remediation-CnoV0kcv.js","names":[],"sources":["../../src/lib/cloister/agent-death.ts","../../src/lib/cloister/stuck-remediation-state.ts","../../src/lib/cloister/planning-wedge.ts","../../src/lib/cloister/stuck-remediation.ts"],"sourcesContent":["/**\n * Agent death diagnostics (PAN-2108).\n *\n * When an ohmypi/pi agent process dies, the launcher records its exit code +\n * timestamp to `<agentDir>/exit-status` (see buildOhmypiCommand in\n * launcher-generator.ts), and omp's stdout/stderr is captured to\n * `<agentDir>/output.log`. This module turns those into a one-line death reason\n * the deacon can log, replacing the opaque \"session is dead\" with an actual\n * cause — the gap that made the flywheel orchestrator's silent death\n * undiagnosable in RUN-30.\n */\nimport { existsSync, readFileSync } from 'fs';\nimport { join } from 'path';\nimport { getOverdeckHome } from '../paths.js';\nimport { listPaneValuesSync, sessionExistsSync } from '../tmux.js';\n\nfunction agentDir(agentId: string): string {\n return join(getOverdeckHome(), 'agents', agentId);\n}\n\n/** Read the launcher-recorded exit code + UTC timestamp, or null if absent. */\nexport function readAgentExitStatus(agentId: string): { code: string; at: string } | null {\n try {\n const p = join(agentDir(agentId), 'exit-status');\n if (!existsSync(p)) return null;\n const raw = readFileSync(p, 'utf-8').trim();\n if (!raw) return null;\n const [code, at = ''] = raw.split(/\\s+/);\n return { code: code ?? '?', at };\n } catch {\n return null;\n }\n}\n\n/**\n * Best-effort one-line description of why an agent process died: the\n * launcher-recorded exit status (preferred), the tmux pane exit status (fallback\n * when the dead pane corpse still exists), and the tail of output.log.\n */\nexport function describeAgentDeath(agentId: string): string {\n const parts: string[] = [];\n\n const exit = readAgentExitStatus(agentId);\n if (exit) {\n parts.push(`exit=${exit.code}${exit.at ? ` at ${exit.at}` : ''}`);\n } else if (sessionExistsSync(agentId)) {\n // No exit-status file (e.g. the launcher bash was SIGKILLed before it could\n // write) but the dead pane survives via remain-on-exit — tmux still knows the\n // exit code.\n const paneExit = listPaneValuesSync(agentId, '#{pane_exit_status}').find((v) => v !== '');\n if (paneExit) parts.push(`pane_exit=${paneExit}`);\n }\n\n try {\n const logPath = join(agentDir(agentId), 'output.log');\n if (existsSync(logPath)) {\n const tail = readFileSync(logPath, 'utf-8')\n .slice(-1500)\n .trim()\n .split('\\n')\n .slice(-6)\n .join(' | ')\n .trim();\n if (tail) parts.push(`output.log tail: ${tail}`);\n }\n } catch {\n /* best effort */\n }\n\n return parts.length ? parts.join('; ') : 'no exit trace (exit-status + output.log empty)';\n}\n","import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport { getOverdeckHome } from '../paths.js';\n\nexport type StuckRemediationStage = 0 | 1 | 2 | 3;\n\nexport interface StuckRemediationState {\n lastStage: StuckRemediationStage;\n lastStageAt: string;\n firstStuckAt: string;\n /**\n * PAN-2108: flywheel-orchestrator death-recovery guard. Counts auto-relaunches\n * within a rolling window so a crash-looping orchestrator escalates to\n * paused+troubled instead of respawning forever. Optional — only set on the\n * flywheel-orchestrator agent.\n */\n respawnCount?: number;\n lastRespawnAt?: string;\n}\n\nfunction agentStateDir(agentId: string): string {\n return join(getOverdeckHome(), 'agents', agentId);\n}\n\nfunction statePath(agentId: string): string {\n return join(agentStateDir(agentId), 'stuck-remediation.json');\n}\n\nexport function readStuckRemediationState(agentId: string): StuckRemediationState | null {\n const filePath = statePath(agentId);\n if (!existsSync(filePath)) return null;\n\n try {\n return JSON.parse(readFileSync(filePath, 'utf-8')) as StuckRemediationState;\n } catch (error) {\n console.warn(`Failed to read stuck-remediation state for ${agentId}:`, error);\n return null;\n }\n}\n\nexport function writeStuckRemediationState(agentId: string, state: StuckRemediationState): void {\n mkdirSync(agentStateDir(agentId), { recursive: true });\n writeFileSync(statePath(agentId), `${JSON.stringify(state, null, 2)}\\n`, 'utf-8');\n}\n\nexport function clearStuckRemediationState(agentId: string): void {\n const filePath = statePath(agentId);\n if (!existsSync(filePath)) return;\n unlinkSync(filePath);\n}\n","/**\n * PAN-3677: positive transcript proof of the planning background-task wedge.\n *\n * The incident: planning sessions (planning-min-888 / planning-min-889) hung on\n * the provider call that followed their background Explore children reaching a\n * terminal state — one run with both children finished, one with a child dead\n * from the 262,144-token model limit while its sibling finished. The mirror\n * stayed 'active' (the Stop hook never fired), the pane kept repainting its\n * spinner, and queued `pan tell` messages were never processed.\n *\n * Stuck-remediation must NEVER interrupt a turn it cannot prove is wedged: a\n * healthy long reasoning turn is also mirror-'active' with no tool calls for\n * a while. This module supplies the positive signature from the authoritative\n * source — the session JSONL:\n *\n * 1. the parent launched at least one background child IN THE CURRENT TURN\n * (Agent tool result: \"Async agent launched successfully. … agentId: X\");\n * 2. EVERY child launched since that boundary is proven terminal, via either\n * - a task-notification queue-operation carrying a terminal\n * `<status>` (completed / failed / cancelled / killed), or\n * - a TaskOutput tool result for that task id with a terminal `<status>`.\n *\n * TURN SCOPING: at each genuine prompt boundary — a `user` entry with\n * string/text content (kickoff, recovery-resume seed) or a queue-operation\n * `remove` of a non-task-notification message (a consumed `pan tell`) —\n * children already proven TERMINAL are retired from the evidence; a closed\n * explorer batch from earlier in the session can never keep `wedged` true\n * through a later healthy turn (historical poisoning). Children NOT yet\n * terminal carry across the boundary, because real background tasks outlive\n * user turns: in the MIN-888 transcript the operator's `pan tell` was consumed\n * while the API explorer was still running, and the wedge formed only after\n * that child finished. `user` entries carrying tool_result parts are turn\n * machinery, never boundaries.\n *\n * If proof is missing — no background children since the boundary, or any\n * child without terminal proof — the answer is NOT wedged and the caller must\n * not interrupt. The detector is deliberately blind to everything else\n * (model, prompt, wall clock): those judgments live in the remediation\n * ladder.\n *\n * Known limitation: a task id can notify more than once (a finished child can\n * be resumed and run again within the same turn). Re-resume is rare in\n * planning flows and the ladder's one-stage-per-episode guard bounds the cost\n * of a stale read; if it ever false-fires, the interrupt is an Escape —\n * recoverable, transcript-safe.\n */\nimport { readFileSync } from 'fs';\nimport { resolveLatestSessionIdSync } from '../agents/activity.js';\nimport { sessionFilePath } from '../paths.js';\n\n/** Terminal background-task statuses recognized in notifications / TaskOutput results. */\nconst TERMINAL_TASK_STATUSES = new Set(['completed', 'failed', 'cancelled', 'killed', 'error']);\n\nexport interface BackgroundTaskWedgeEvidence {\n /** Every async background child the parent launched, in launch order. */\n launchedTaskIds: string[];\n /** Children with terminal proof (notification or TaskOutput result). */\n terminalTaskIds: string[];\n /** Launched children with NO terminal proof — any non-empty list vetoes the wedge. */\n nonTerminalTaskIds: string[];\n /** Terminal children whose notification was enqueued but not yet consumed by the harness. */\n unconsumedTerminalTaskIds: string[];\n /** The positive signature: at least one child launched and every child terminal. */\n wedged: boolean;\n}\n\ninterface TaskNotification {\n taskId: string;\n status: string | null;\n}\n\nfunction extractText(content: unknown): string {\n if (typeof content === 'string') return content;\n if (Array.isArray(content)) {\n return content\n .map((part) => {\n if (part && typeof part === 'object') {\n const p = part as Record<string, unknown>;\n if (p.type === 'text' && typeof p.text === 'string') return p.text;\n if (p.type === 'tool_result') return extractText(p.content);\n }\n return '';\n })\n .join('\\n');\n }\n return '';\n}\n\nfunction parseTaskNotification(content: string): TaskNotification | null {\n if (!content.includes('<task-notification>')) return null;\n const taskId = /<task-id>\\s*([a-z0-9]+)\\s*<\\/task-id>/.exec(content)?.[1];\n if (!taskId) return null;\n const status = /<status>\\s*([a-z_-]+)\\s*<\\/status>/i.exec(content)?.[1]?.toLowerCase() ?? null;\n return { taskId, status };\n}\n\n/**\n * True when a JSONL entry opens a new genuine user turn: a `user` entry with\n * string or text-only content (the kickoff prompt, a recovery-resume seed),\n * or a queue-operation `remove` of a NON-task-notification message (a\n * consumed operator `pan tell` — the harness folds it into context at that\n * point without writing a user entry). `user` entries made of tool_result\n * parts are turn machinery and NEVER boundaries; task-notification\n * queue-operations are the wedge evidence itself, also never boundaries.\n */\nfunction isPromptBoundary(e: Record<string, unknown>): boolean {\n if (e.type === 'queue-operation') {\n const content = typeof e.content === 'string' ? e.content : '';\n return e.operation === 'remove' && !content.includes('<task-notification>');\n }\n if (e.type !== 'user') return false;\n const content = (e.message as Record<string, unknown> | undefined)?.content;\n if (typeof content === 'string') return content.trim().length > 0;\n if (Array.isArray(content)) {\n const hasToolResult = content.some(\n (p) => p && typeof p === 'object' && (p as Record<string, unknown>).type === 'tool_result',\n );\n const hasText = content.some(\n (p) => p && typeof p === 'object' && (p as Record<string, unknown>).type === 'text',\n );\n return hasText && !hasToolResult;\n }\n return false;\n}\n\n/**\n * Parse one session's JSONL entries (already-parsed JSON objects, in file\n * order) into the wedge evidence. At every genuine prompt boundary (see\n * isPromptBoundary), children already proven terminal are RETIRED — only\n * still-running children carry into the new turn, because real background\n * tasks outlive user turns. Unknown/malformed lines are ignored — a parser\n * miss always degrades to \"not wedged\", never to a false positive.\n */\nexport function parseBackgroundTaskWedge(entries: readonly unknown[]): BackgroundTaskWedgeEvidence {\n let launched: string[] = [];\n let terminal = new Map<string, string>(); // taskId -> terminal status\n let consumedNotifications = new Set<string>();\n\n for (const entry of entries) {\n if (!entry || typeof entry !== 'object') continue;\n const e = entry as Record<string, unknown>;\n\n if (isPromptBoundary(e)) {\n // Retire children already proven terminal — their episode is closed and\n // must not poison later turns. Keep only still-running children: real\n // background tasks outlive user turns (see the header's MIN-888 note).\n launched = launched.filter((id) => !terminal.has(id));\n terminal = new Map([...terminal].filter(([id]) => launched.includes(id)));\n consumedNotifications = new Set([...consumedNotifications].filter((id) => launched.includes(id)));\n continue;\n }\n\n if (e.type === 'queue-operation') {\n const notification = parseTaskNotification(typeof e.content === 'string' ? e.content : '');\n if (!notification) continue;\n if (e.operation === 'remove') consumedNotifications.add(notification.taskId);\n if (notification.status && TERMINAL_TASK_STATUSES.has(notification.status)) {\n terminal.set(notification.taskId, notification.status);\n }\n continue;\n }\n\n // tool_result entries arrive as role:'user' messages with content parts.\n const message = e.message as Record<string, unknown> | undefined;\n const content = message?.content;\n if (!Array.isArray(content)) continue;\n for (const part of content) {\n if (!part || typeof part !== 'object') continue;\n const p = part as Record<string, unknown>;\n if (p.type !== 'tool_result') continue;\n const text = extractText(p.content);\n\n // Background launch acknowledgment: \"Async agent launched successfully.\n // … agentId: <id> (internal ID …)\".\n if (text.includes('Async agent launched successfully')) {\n const agentId = /agentId:\\s*([a-z0-9]+)/.exec(text)?.[1];\n if (agentId && !launched.includes(agentId)) launched.push(agentId);\n continue;\n }\n\n // Explicit collection: TaskOutput result with <task_id> + <status>.\n if (text.includes('<retrieval_status>')) {\n const taskId = /<task_id>\\s*([a-z0-9]+)\\s*<\\/task_id>/.exec(text)?.[1];\n const status = /<status>\\s*([a-z_-]+)\\s*<\\/status>/i.exec(text)?.[1]?.toLowerCase();\n if (taskId && status && TERMINAL_TASK_STATUSES.has(status)) {\n terminal.set(taskId, status);\n consumedNotifications.add(taskId);\n }\n }\n }\n }\n\n const terminalTaskIds = launched.filter((id) => terminal.has(id));\n const nonTerminalTaskIds = launched.filter((id) => !terminal.has(id));\n const unconsumedTerminalTaskIds = terminalTaskIds.filter((id) => !consumedNotifications.has(id));\n return {\n launchedTaskIds: launched,\n terminalTaskIds,\n nonTerminalTaskIds,\n unconsumedTerminalTaskIds,\n wedged: launched.length > 0 && nonTerminalTaskIds.length === 0,\n };\n}\n\n/**\n * Read a session JSONL and return its wedge evidence, or null when the file\n * cannot be read/parsed — callers treat null as \"not proven\", never as wedged.\n */\nexport function readBackgroundTaskWedgeEvidence(sessionPath: string): BackgroundTaskWedgeEvidence | null {\n let raw: string;\n try {\n raw = readFileSync(sessionPath, 'utf-8');\n } catch {\n return null;\n }\n const entries: unknown[] = [];\n for (const line of raw.split('\\n')) {\n if (!line.trim()) continue;\n try {\n entries.push(JSON.parse(line));\n } catch {\n // Tolerate torn tail writes — a partially-written last line must not\n // discard the evidence parsed before it.\n }\n }\n return parseBackgroundTaskWedge(entries);\n}\n\n/**\n * Resolve an agent's CURRENT session through the production resolver\n * (resolveLatestSessionIdSync — the same door resumeAgent uses) and parse its\n * live JSONL. Returns null when there is no resumable session or no readable\n * transcript — always degrading to \"not proven\".\n */\nexport function readAgentBackgroundTaskWedgeEvidence(\n agentId: string,\n workspace: string,\n): BackgroundTaskWedgeEvidence | null {\n const sessionId = resolveLatestSessionIdSync(agentId).sessionId;\n if (!sessionId) return null;\n return readBackgroundTaskWedgeEvidence(sessionFilePath(workspace, sessionId));\n}\n","import { Effect } from 'effect';\nimport {\n getAgentRuntimeStateSync,\n listRunningAgentsSync,\n markAgentTroubled,\n messageAgent,\n resumeAgent,\n type AgentState,\n} from '../agents.js';\nimport { countPendingAskUserQuestionsForAgent } from '../agent-enrichment.js';\nimport { logDeaconEventSync } from '../persistent-logger.js';\nimport { getReviewStatusSync, type ReviewStatus } from '../review-status.js';\nimport { capturePaneSync, detectTerminalApiErrorSync, sessionExistsSync, killSession, killSessionSync, listPaneValuesSync, sendEscapeKeyAsync } from '../tmux.js';\nimport { loadCloisterConfigSync, DEFAULT_CLOISTER_CONFIG, type StuckRemediationConfig } from './config.js';\nimport { getAgentEffectiveLastActivityMs, getAgentWorkActivityMs, isAgentIdleForNudge } from './agent-idle.js';\nimport { describeAgentDeath } from './agent-death.js';\nimport { getFlywheelActiveRunId, isFlywheelGloballyPaused } from '../overdeck/control-settings.js';\nimport {\n clearStuckRemediationState,\n readStuckRemediationState,\n writeStuckRemediationState,\n type StuckRemediationState,\n} from './stuck-remediation-state.js';\nimport { readWorkspacePlanSync } from '../xbrief/io.js';\nimport { getDispatchableItems } from '../xbrief/dag.js';\nimport { recordRecoveryFailure } from './recovery-trip.js';\nimport { readAgentBackgroundTaskWedgeEvidence } from './planning-wedge.js';\n\nexport interface StuckRemediationOptions {\n now?: number;\n}\n\nfunction issueIdForAgent(agent: AgentState): string {\n return agent.issueId || agent.id.replace(/^agent-/, '').toUpperCase();\n}\n\nexport function shouldSkipReviewStatus(status: ReviewStatus | null): boolean {\n if (!status) return false;\n if (status.stuck || status.deaconIgnored || status.mergeStatus === 'merged' || status.readyForMerge) return true;\n if (status.reviewStatus === 'blocked' || status.reviewStatus === 'failed') return true;\n if (status.verificationStatus === 'failed' || status.testStatus === 'failed') return true;\n // PAN-2581: the pipeline OWNS the issue while review/test advance it — review in\n // flight, a passed review awaiting test, or an un-serviced durable review request\n // (`pan done` already ran; dispatch owns the next step). Warm-idle is the work\n // agent's intended state here (PAN-2579). Poking it told it to re-run `pan done`,\n // which re-armed review and clobbered landed verdicts (PAN-399 burned $63 on this).\n if (status.reviewStatus === 'reviewing' || status.reviewStatus === 'passed') return true;\n return status.reviewStatus === 'pending' && !!status.reviewRequestedAt;\n}\n\n/**\n * PAN-2581 (FR-2, residual): phase gate for the health-check poke loop\n * (service.ts pokeAgent → pokeAgentWithEscalation → idle-alive pause), the\n * SECOND independent idleness consumer besides stuck-remediation. A warm-idle\n * work agent on a pipeline-owned issue — and a warm-idle review/test agent\n * after its verdict — must never be poked (\"are you stuck?\") or idle-alive\n * paused: the poke spends tokens re-explaining the wait, and the pause\n * manufactures the paused-delivery-target deadlock PAN-2461 exists to undo.\n * A genuinely stalled mid-review parent is covered by the PAN-2584 liveness\n * deadline, not pokes. Owed-rework agents (review blocked/failed, tests\n * failed) are ALSO skipped here by design: shouldSkipReviewStatus returns\n * true for those because the PAN-2519 wedged-rework path owns their\n * escalation — the health-check poke loop must not double-drive them.\n * Roles outside work/review/test (plan, strike, flywheel, sequencer) keep\n * their existing idleness semantics.\n */\nexport function shouldSkipIdlePokeForAgent(\n agent: Pick<AgentState, 'id' | 'issueId' | 'role'> | null,\n readStatus: (issueId: string) => ReviewStatus | null = getReviewStatusSync,\n): boolean {\n if (!agent) return false;\n if (agent.role !== 'work' && agent.role !== 'review' && agent.role !== 'test') return false;\n const issueId = (agent.issueId\n || agent.id.replace(/^agent-/, '').replace(/-(review|test|ship)(-.*)?$/, '').replace(/-slot-\\d+$/, '')\n ).toUpperCase();\n return shouldSkipReviewStatus(readStatus(issueId));\n}\n\n// PAN-2519: the rework subset of shouldSkipReviewStatus — a work agent that OWES\n// a fix (review blocked/failed, verification failed, tests failed) and is NOT\n// already done/ignored (merged, readyForMerge, stuck, deaconIgnored). These are\n// exactly the agents the idle-escalation path skips (via shouldSkipReviewStatus)\n// AND the PAN-2209 dead-end respawn skips (session still exists) — so a\n// wedged-but-alive rework agent falls through both and stalls invisibly.\nfunction hasPendingRework(status: ReviewStatus | null): boolean {\n if (!status) return false;\n if (status.stuck || status.deaconIgnored || status.mergeStatus === 'merged' || status.readyForMerge) return false;\n return (\n status.reviewStatus === 'blocked' ||\n status.reviewStatus === 'failed' ||\n status.verificationStatus === 'failed' ||\n status.testStatus === 'failed'\n );\n}\n\n// Mirror of the deacon dead-end circuit breaker (deacon.ts: autoRequeueCount >= 25\n// halts respawn). Below the ceiling we kill a wedged rework agent so PAN-2209\n// respawns it fresh; at/above it, respawn would be refused, so we park it as\n// troubled instead — leaving a live operator signal rather than a dead session.\nconst STUCK_KILL_REQUEUE_CEILING = 25;\n\n// A wedged-but-alive work agent holding pending rework: kill its session so the\n// deacon's PAN-2209 dead-end path respawns a fresh agent whose kickoff prompt\n// drains .pan/feedback. Returns true when it handled the agent (caller returns).\nasync function evaluateWedgedReworkAgent(\n agent: AgentState,\n config: StuckRemediationConfig,\n now: number,\n actions: string[],\n): Promise<boolean> {\n const agentId = agent.id;\n if (agent.role !== 'work' || !agent.workspace) return false;\n\n const issueId = issueIdForAgent(agent);\n const status = getReviewStatusSync(issueId);\n if (!hasPendingRework(status)) return false;\n\n const lastActivityMs = getAgentEffectiveLastActivityMs(agentId);\n if (lastActivityMs === null || !Number.isFinite(lastActivityMs)) return false;\n\n const stuckState = readStuckRemediationState(agentId);\n if (stuckState) {\n const firstStuckMs = new Date(stuckState.firstStuckAt).getTime();\n if (Number.isFinite(firstStuckMs) && lastActivityMs > firstStuckMs) {\n // The agent resumed activity since we flagged it — clear and let the\n // normal path re-evaluate on a future tick.\n clearStuckRemediationState(agentId);\n return false;\n }\n }\n\n const idleMinutes = Math.floor((now - lastActivityMs) / 60_000);\n const lastStage = stuckState?.lastStage ?? 0;\n // One action per stuck episode (lastStage < 3). A successful respawn advances\n // activity and clears state above, so the next wedge is a fresh episode.\n if (idleMinutes < config.stage3_minutes || lastStage >= 3) return false;\n\n const firstStuck = firstStuckAt(new Date(lastActivityMs).toISOString(), stuckState);\n const requeues = status?.autoRequeueCount ?? 0;\n\n if (requeues >= STUCK_KILL_REQUEUE_CEILING) {\n // Chronic re-death: the deacon breaker would refuse another respawn, so\n // parking as troubled surfaces it for an operator instead of a dead session.\n markAgentTroubled(agentId);\n writeStuckRemediationState(agentId, stageState(3, now, firstStuck));\n logAction(actions, transitionAction(3, issueId, idleMinutes, 'rework-wedge-troubled'));\n await surfaceStuckNeedsYou(agent, issueId, firstStuck, actions);\n return true;\n }\n\n killSessionSync(agentId);\n writeStuckRemediationState(agentId, stageState(3, now, firstStuck));\n logAction(actions, transitionAction(3, issueId, idleMinutes, 'killed-for-respawn'));\n return true;\n}\n\nfunction shouldCheckReadyBeadsForAgent(agent: AgentState, now: number): boolean {\n const agentId = agent.id;\n if (!agentId) return false;\n if (agent.status !== 'running') return false;\n if (agent.role !== 'work') return false;\n if (!agent.workspace) return false;\n const completedAt = (agent as AgentState & { completedAt?: string }).completedAt;\n if (agent.paused || agent.troubled || completedAt) return false;\n if (!sessionExistsSync(agentId)) return false;\n if (shouldSkipReviewStatus(getReviewStatusSync(issueIdForAgent(agent)))) return false;\n return isAgentIdleForNudge(agentId, 5 * 60 * 1000, now);\n}\n\nfunction firstStuckAt(runtimeLastActivity: string, stuckState: StuckRemediationState | null): string {\n return stuckState?.firstStuckAt ?? runtimeLastActivity;\n}\n\nfunction stageState(\n stage: 1 | 2 | 3,\n now: number,\n firstStuck: string,\n prev?: StuckRemediationState | null,\n): StuckRemediationState {\n // Carry the flywheel respawn-cap accounting (respawnCount/lastRespawnAt) across\n // stage transitions — otherwise a stage1/stage2 write between relaunches would\n // reset the cap and the wedge-relaunch loop could never escalate (PAN-2160).\n return {\n lastStage: stage,\n lastStageAt: new Date(now).toISOString(),\n firstStuckAt: firstStuck,\n ...(prev?.respawnCount !== undefined ? { respawnCount: prev.respawnCount } : {}),\n ...(prev?.lastRespawnAt !== undefined ? { lastRespawnAt: prev.lastRespawnAt } : {}),\n };\n}\n\nfunction transitionAction(stage: 1 | 2 | 3, issueId: string, idleMinutes: number, action: string): string {\n return `[deacon] stuck-remediation stage=${stage} issue=${issueId} idleMin=${idleMinutes} action=${action}`;\n}\n\nfunction logAction(actions: string[], action: string): void {\n actions.push(action);\n console.log(action);\n logDeaconEventSync(action);\n}\n\nasync function surfaceStuckNeedsYou(agent: AgentState, issueId: string, generation: string, actions: string[]): Promise<void> {\n if (!agent.workspace) return;\n const failure = await recordRecoveryFailure(agent.workspace, issueId, 'stuck-remediation', generation, 1);\n if (failure.emitNeedsYou) logAction(actions, `[deacon] needs-you ${issueId}: stuck remediation exhausted`);\n}\n\nasync function evaluateAgent(\n agent: AgentState,\n config: StuckRemediationConfig,\n now: number,\n actions: string[],\n): Promise<void> {\n const agentId = agent.id;\n if (!agentId) return;\n if (agent.status !== 'running') return;\n const completedAt = (agent as AgentState & { completedAt?: string }).completedAt;\n if (agent.paused || agent.troubled || completedAt) return;\n\n // PAN-2108: evaluate the flywheel orchestrator BEFORE the session-exists guard.\n // Its recovery must be able to fresh-launch even when the session has fully\n // vanished (not just gone zombie); evaluateFlywheelOrchestrator does its own\n // liveness check.\n if (agent.role === 'flywheel') {\n await evaluateFlywheelOrchestrator(agent, config, now, actions);\n return;\n }\n if (!sessionExistsSync(agentId)) return;\n if (agent.role === 'plan') {\n await evaluatePlanningAgent(agent, config, now, actions);\n return;\n }\n // PAN-2519: catch wedged-but-alive work agents that OWE a rework fix before the\n // ready-beads gate skips them (shouldSkipReviewStatus is true for rework state).\n // These are invisible to both idle-escalation (skipped here) and PAN-2209\n // respawn (session still exists); killing the session bridges them to respawn.\n if (await evaluateWedgedReworkAgent(agent, config, now, actions)) return;\n if (!shouldCheckReadyBeadsForAgent(agent, now)) return;\n if (!agent.workspace) return;\n\n const issueId = issueIdForAgent(agent);\n const plan = readWorkspacePlanSync(agent.workspace);\n if (!plan) return;\n if (getDispatchableItems(plan, new Set()).length > 0) return;\n\n const lastActivityMs = getAgentEffectiveLastActivityMs(agentId);\n if (lastActivityMs === null) return;\n if (!Number.isFinite(lastActivityMs)) return;\n const lastActivity = new Date(lastActivityMs).toISOString();\n\n const stuckState = readStuckRemediationState(agentId);\n if (stuckState) {\n const firstStuckMs = new Date(stuckState.firstStuckAt).getTime();\n if (Number.isFinite(firstStuckMs) && lastActivityMs > firstStuckMs) {\n clearStuckRemediationState(agentId);\n return;\n }\n }\n\n const idleMinutes = Math.floor((now - lastActivityMs) / 60_000);\n const lastStage = stuckState?.lastStage ?? 0;\n const firstStuck = firstStuckAt(lastActivity, stuckState);\n\n const terminalProviderError = detectTerminalApiErrorSync(capturePaneSync(agentId, 80));\n if (terminalProviderError) {\n markAgentTroubled(agentId);\n writeStuckRemediationState(agentId, stageState(3, now, firstStuck));\n logAction(actions, `${agentId} provider-terminal: ${terminalProviderError.summary}`);\n await surfaceStuckNeedsYou(agent, issueId, firstStuck, actions);\n return;\n }\n\n if (idleMinutes >= config.stage3_minutes && lastStage < 3) {\n markAgentTroubled(agentId);\n writeStuckRemediationState(agentId, stageState(3, now, firstStuck));\n logAction(actions, transitionAction(3, issueId, idleMinutes, 'marked-troubled'));\n await surfaceStuckNeedsYou(agent, issueId, firstStuck, actions);\n return;\n }\n\n if (idleMinutes >= config.stage2_minutes && lastStage < 2) {\n const message = `Resuming after auto-detected stall (${idleMinutes} min idle). Review your last work and decide whether to continue or signal done with \\`pan done ${issueId}\\`.`;\n const result = await resumeAgent(agentId, message);\n if (result.success) {\n writeStuckRemediationState(agentId, stageState(2, now, firstStuck));\n logAction(actions, transitionAction(2, issueId, idleMinutes, 'resumed'));\n } else {\n // PAN-2108: surface WHY (exit code + output tail) instead of an opaque\n // \"resume-failed\" — a resume usually fails because the process died.\n const action = `${transitionAction(2, issueId, idleMinutes, 'resume-failed')} — death: ${describeAgentDeath(agentId)}`;\n console.warn(action);\n logDeaconEventSync(action);\n }\n return;\n }\n\n if (idleMinutes >= config.stage1_minutes && lastStage < 1) {\n const message = `You appear stuck — no tool calls for ${idleMinutes} min. If your implementation is complete, run \\`pan done ${issueId}\\`. Otherwise reply with a one-line summary of what you're waiting on, then continue.`;\n await messageAgent(agentId, message);\n writeStuckRemediationState(agentId, stageState(1, now, firstStuck));\n logAction(actions, transitionAction(1, issueId, idleMinutes, 'poked'));\n }\n}\n\n/**\n * PAN-3677: remediation decision for a planning session with no pending\n * AskUserQuestion. Pure — side effects live in evaluatePlanningAgent.\n *\n * The wedge this catches: a planning session whose turn never ends because the\n * provider call hung (observed on k3[1m] planning sessions right after\n * background Explore children reached a terminal state — all-finished AND\n * mixed failed/finished). The detector combines three signals: the runtime\n * mirror still says 'active' (the Stop hook never fired — the turn never\n * ended), work-product activity (hook events, transcript writes) has been\n * silent past the stage threshold, AND the session transcript positively\n * proves background children were in flight this turn with every child\n * terminal (planning-wedge.ts).\n *\n * Guards against interrupting healthy turns:\n * - mirror 'idle' means the Stop hook fired — the agent is at its prompt\n * (operator's turn in a manual session). Never interrupt.\n * - `wedgeProven` requires the transcript itself to prove background children\n * were in flight AND every child is terminal (parseBackgroundTaskWedge). A\n * silent 'active' turn without that proof is a healthy long\n * reasoning/provider turn — never interrupt it.\n * - work activity fresher than stage1_minutes means real work is flowing\n * (tool calls, transcript writes) — never interrupt, even though the pane\n * repaint alone would look identical. The detector never consults tmux\n * window_activity: the spinner/task panel repaints every second during a\n * hung call and would mask the wedge (see getAgentWorkActivityMs).\n *\n * The ladder is bounded by construction: interrupt → kill+resume → troubled.\n * No stage waits on anything after every child is terminal.\n */\nexport type PlanningWedgeDecision =\n | { kind: 'none' }\n | { kind: 'interrupt-nudge'; idleMinutes: number }\n | { kind: 'kill-resume'; idleMinutes: number }\n | { kind: 'troubled'; idleMinutes: number };\n\nexport function decidePlanningWedgeRemediation(opts: {\n mirrorState: string | null;\n pendingQuestions: number;\n /** Positive transcript proof (parseBackgroundTaskWedge): background children were in flight AND every one is terminal. */\n wedgeProven: boolean;\n workActivityMs: number | null;\n lastStage: number;\n now: number;\n config: StuckRemediationConfig;\n}): PlanningWedgeDecision {\n const { mirrorState, pendingQuestions, wedgeProven, workActivityMs, lastStage, now, config } = opts;\n // A pending AskUserQuestion is the operator's slot (auto sessions get the\n // default-choice nudge elsewhere) — never treat it as a wedge.\n if (pendingQuestions > 0) return { kind: 'none' };\n // Only a stale-'active' mirror is a mid-turn wedge. 'idle' means the Stop\n // hook fired (turn ended, agent at its prompt); 'suspended'/'stopped'/\n // 'waiting-on-human' are owned by other paths; null means the mirror never\n // came up and we cannot tell wedge from healthy.\n if (mirrorState !== 'active') return { kind: 'none' };\n // The positive signature: without transcript proof that background children\n // were in flight and ALL of them are terminal, a silent 'active' turn is a\n // healthy long reasoning/provider turn — never interrupt it.\n if (!wedgeProven) return { kind: 'none' };\n if (workActivityMs === null || !Number.isFinite(workActivityMs)) return { kind: 'none' };\n const idleMinutes = Math.floor((now - workActivityMs) / 60_000);\n if (idleMinutes >= config.stage3_minutes) {\n if (lastStage >= 3) return { kind: 'none' };\n return { kind: 'troubled', idleMinutes };\n }\n if (idleMinutes >= config.stage2_minutes) {\n if (lastStage >= 2) return { kind: 'none' };\n return { kind: 'kill-resume', idleMinutes };\n }\n if (idleMinutes >= config.stage1_minutes) {\n if (lastStage >= 1) return { kind: 'none' };\n return { kind: 'interrupt-nudge', idleMinutes };\n }\n return { kind: 'none' };\n}\n\n/**\n * Episode-clear rule for the planning wedge path, keyed on WORK activity only\n * (never pane repaints — the spinner would \"clear\" a still-wedged episode and\n * re-fire stage 1 every tick): work flowing after the episode opened means the\n * recovery worked.\n */\nexport function shouldClearPlanningWedgeEpisode(\n stuckState: StuckRemediationState | null,\n workActivityMs: number,\n): boolean {\n if (!stuckState) return false;\n const firstStuckMs = new Date(stuckState.firstStuckAt).getTime();\n return Number.isFinite(firstStuckMs) && workActivityMs > firstStuckMs;\n}\n\n/** Side-effecting doors the wedge executor needs — injected for tests. */\nexport interface PlanningWedgeEffectDeps {\n sendEscape: (agentId: string) => Promise<void>;\n message: (agentId: string, msg: string) => Promise<unknown>;\n /** Async tmux kill (Effect-based `killSession` from tmux.ts) — never the sync variant from server-reachable code. */\n killSession: (agentId: string) => Promise<void>;\n resume: (agentId: string, msg: string) => Promise<{ success: boolean; error?: string }>;\n markTroubled: (agentId: string) => void;\n writeState: (agentId: string, state: StuckRemediationState) => void;\n surfaceNeedsYou: () => Promise<void>;\n log: (msg: string) => void;\n}\n\n/**\n * Execute one wedge-ladder decision. Ordering is the contract: stage 1 sends\n * Escape BEFORE queueing its single nudge (the interrupt returns the prompt;\n * the nudge — and any queued operator messages — are processed after). Stage 2\n * kills the session and plain-resumes the SAME saved session id, so the\n * transcript (and every explorer's findings) survives — unlike the\n * compact-respawn path that lost conversation-only survey notes in the manual\n * MIN-889 recovery.\n */\nexport async function executePlanningWedgeDecision(\n agentId: string,\n issueId: string,\n decision: Exclude<PlanningWedgeDecision, { kind: 'none' }>,\n firstStuck: string,\n now: number,\n deps: PlanningWedgeEffectDeps,\n): Promise<void> {\n if (decision.kind === 'interrupt-nudge') {\n // Escape cancels the in-flight (hung) provider call. The harness returns to\n // its prompt and processes queued operator messages; the nudge below then\n // tells the planner how to continue without re-entering the blocking wait.\n try {\n await deps.sendEscape(agentId);\n } catch (err) {\n console.error(`[deacon] Failed to interrupt wedged planning session ${agentId}:`, err);\n return;\n }\n const message =\n `Your previous turn stalled for ${decision.idleMinutes} min with no progress and was interrupted (a hung provider call). ` +\n `Process any queued operator messages first. Then collect background-task results NON-blocking (TaskOutput with block:false) — ` +\n `every child that reached a terminal state already has its result or error available; do NOT re-enter a blocking wait. ` +\n `Continue planning now: write the PRD/xBRIEF artifacts and proceed to your instructed stopping point.`;\n // The Escape already landed — the interrupt happened whether or not the\n // nudge arrives. Record stage 1 either way: skipping the state write on a\n // delivery failure would let every patrol re-Escape an already-unwedged\n // session forever.\n let deliveryError: string | null = null;\n try {\n await deps.message(agentId, message);\n } catch (err) {\n deliveryError = err instanceof Error ? err.message : String(err);\n }\n deps.writeState(agentId, stageState(1, now, firstStuck));\n deps.log(deliveryError\n ? `${transitionAction(1, issueId, decision.idleMinutes, 'interrupted-wedged-turn')} — nudge delivery failed: ${deliveryError}`\n : transitionAction(1, issueId, decision.idleMinutes, 'interrupted-wedged-turn'));\n return;\n }\n\n if (decision.kind === 'kill-resume') {\n try {\n await deps.killSession(agentId);\n } catch {\n /* best effort — the resume below fails cleanly if the session lingers */\n }\n const message =\n `Resuming after an automated stall recovery (${decision.idleMinutes} min with no progress). ` +\n `Your transcript is intact — continue planning from where you left off. ` +\n `Collect background-task results NON-blocking (TaskOutput with block:false) and proceed.`;\n const result = await deps.resume(agentId, message);\n if (result.success) {\n deps.writeState(agentId, stageState(2, now, firstStuck));\n deps.log(transitionAction(2, issueId, decision.idleMinutes, 'kill-resumed-wedged-planning'));\n } else {\n deps.markTroubled(agentId);\n deps.writeState(agentId, stageState(3, now, firstStuck));\n deps.log(`${transitionAction(3, issueId, decision.idleMinutes, 'kill-resume-failed-troubled')} — ${result.error ?? 'unknown'}`);\n await deps.surfaceNeedsYou();\n }\n return;\n }\n\n // troubled\n deps.markTroubled(agentId);\n deps.writeState(agentId, stageState(3, now, firstStuck));\n deps.log(transitionAction(3, issueId, decision.idleMinutes, 'wedged-planning-troubled'));\n await deps.surfaceNeedsYou();\n}\n\nasync function evaluatePlanningAgent(\n agent: AgentState,\n config: StuckRemediationConfig,\n now: number,\n actions: string[],\n): Promise<void> {\n const agentId = agent.id;\n const issueId = issueIdForAgent(agent);\n const pendingQuestions = await Effect.runPromise(countPendingAskUserQuestionsForAgent(agentId));\n\n // An unanswered AskUserQuestion parks the session on the operator. Manual\n // sessions wait by design; --auto sessions get the default-choice nudge.\n if (pendingQuestions > 0) {\n if (!isAgentIdleForNudge(agentId, 5 * 60 * 1000, now)) return;\n if (agent.auto !== true) return;\n const lastActivityMs = getAgentEffectiveLastActivityMs(agentId);\n if (lastActivityMs === null || !Number.isFinite(lastActivityMs)) return;\n const lastActivity = new Date(lastActivityMs).toISOString();\n const stuckState = readStuckRemediationState(agentId);\n if (stuckState) {\n const firstStuckMs = new Date(stuckState.firstStuckAt).getTime();\n if (Number.isFinite(firstStuckMs) && lastActivityMs > firstStuckMs) {\n clearStuckRemediationState(agentId);\n return;\n }\n }\n const idleMinutes = Math.floor((now - lastActivityMs) / 60_000);\n const lastStage = stuckState?.lastStage ?? 0;\n if (idleMinutes < config.stage1_minutes || lastStage >= 1) return;\n const message =\n `This planning session was launched with \\`pan plan ${issueId} --auto\\`, so do not wait for operator input. ` +\n `Proceed with the most defensible default from the issue/PRD/comments, record the choice in \\`plan.autoDecisions[]\\` with rationale, and continue to \\`pan plan finalize\\`. ` +\n `Only halt for a genuine contradiction between authoritative inputs.`;\n await messageAgent(agentId, message);\n writeStuckRemediationState(agentId, stageState(1, now, firstStuckAt(lastActivity, stuckState)));\n logAction(actions, transitionAction(1, issueId, idleMinutes, 'auto-planning-default'));\n return;\n }\n\n // PAN-3677: mid-turn wedge. Every signal here is WORK activity (hook mirror +\n // transcript heartbeat), never tmux window_activity — Claude Code repaints\n // its spinner/task panel every second during a hung provider call, so the\n // pane looks alive while no work flows. Keying on the pane would (a) hide\n // the wedge entirely and (b) instantly \"clear\" the episode state,\n // re-firing stage 1 every tick.\n const workActivityMs = getAgentWorkActivityMs(agentId);\n if (workActivityMs === null || !Number.isFinite(workActivityMs)) return;\n\n const stuckState = readStuckRemediationState(agentId);\n if (shouldClearPlanningWedgeEpisode(stuckState, workActivityMs)) {\n clearStuckRemediationState(agentId);\n return;\n }\n\n const mirrorState = getAgentRuntimeStateSync(agentId)?.state ?? null;\n if (mirrorState !== 'active') return;\n const idleMinutesGate = Math.floor((now - workActivityMs) / 60_000);\n if (idleMinutesGate < config.stage1_minutes) return;\n\n // The positive signature (readAgentBackgroundTaskWedgeEvidence): the\n // transcript of the CURRENT turn must prove background children were in\n // flight and EVERY child is terminal. Without it, a silent 'active' turn is\n // a healthy long reasoning/provider turn and is never interrupted.\n const wedgeProven = agent.workspace\n ? readAgentBackgroundTaskWedgeEvidence(agentId, agent.workspace)?.wedged === true\n : false;\n\n const decision = decidePlanningWedgeRemediation({\n mirrorState,\n pendingQuestions,\n wedgeProven,\n workActivityMs,\n lastStage: stuckState?.lastStage ?? 0,\n now,\n config,\n });\n if (decision.kind === 'none') return;\n\n await executePlanningWedgeDecision(agentId, issueId, decision, firstStuckAt(new Date(workActivityMs).toISOString(), stuckState), now, {\n sendEscape: (id) => sendEscapeKeyAsync(id),\n message: (id, msg) => messageAgent(id, msg),\n killSession: (id) => Effect.runPromise(killSession(id)),\n resume: (id, msg) => resumeAgent(id, msg),\n markTroubled: (id) => markAgentTroubled(id),\n writeState: (id, state) => writeStuckRemediationState(id, state),\n surfaceNeedsYou: () => surfaceStuckNeedsYou(agent, issueId, firstStuckAt(new Date(workActivityMs).toISOString(), stuckState), actions),\n log: (msg) => logAction(actions, msg),\n });\n}\n\n// The flywheel orchestrator is a singleton with role 'flywheel'. It ticks\n// sub-minute by design (each tick produces a FlywheelStatus snapshot via\n// `pan flywheel emit-status`), so a long silence indicates a stuck model call\n// or a dropped tick loop — not the natural between-task idleness work agents\n// exhibit.\n//\n// PAN-2108: the orchestrator may run on the ohmypi (omp) harness (no\n// ScheduleWakeup tool); when its process DIES (RUN-30: silent crash mid-run)\n// the runtime mirror goes stale-but-\"active\", so a dead orchestrator must\n// self-heal: kill the zombie session and fresh-launch the run.\n//\n// PAN-2160: the orchestrator is the pipeline's last stand, so NEITHER death NOR\n// a wedged (alive-but-silent) tick loop may ever PARK it. Both recover the same\n// way — relaunch (capped); only a genuine crash/wedge loop past the cap escalates\n// to paused+troubled (operator needed). Two work-agent gates that used to wrongly\n// kill the orchestrator are removed:\n// 1. OVERDECK_NO_RESUME is NOT honored here — it gates *work-agent*\n// resurrection, not the controller. The operator stops the flywheel with\n// `pan flywheel stop` (clears the active run ⇒ `noop` below), or halts\n// everything with `pan admin cloister freeze` (suspends the whole patrol, so\n// this code never runs). That separation is the real kill-switch.\n// 2. The terminal idle stage relaunches instead of pause+troubled — a wedged\n// orchestrator must be restarted, not parked (RUN-36 was parked at\n// idleMin=205 and the entire pipeline stalled).\nconst FLYWHEEL_RESPAWN_WINDOW_MS = 30 * 60 * 1000;\nconst FLYWHEEL_MAX_RESPAWNS = 3;\nconst FLYWHEEL_ORCHESTRATOR_AGENT_ID = 'flywheel-orchestrator';\n\nexport type FlywheelRemediationDecision =\n | { kind: 'noop' }\n | { kind: 'relaunch'; respawnCount: number }\n | { kind: 'escalate'; respawnCount: number };\n\n/**\n * Pure decision for recovering a dead or wedged flywheel orchestrator (no I/O —\n * side effects live in remediateFlywheelOrchestrator). The respawn cap\n * (FLYWHEEL_MAX_RESPAWNS within FLYWHEEL_RESPAWN_WINDOW_MS) stops an infinite\n * relaunch loop: past the cap, escalate to paused+troubled. `hasActiveRun` false\n * ⇒ the operator stopped the flywheel deliberately ⇒ do not resurrect.\n */\nexport function decideFlywheelRemediation(opts: {\n hasActiveRun: boolean;\n prev: StuckRemediationState | null;\n now: number;\n}): FlywheelRemediationDecision {\n if (!opts.hasActiveRun) return { kind: 'noop' };\n const lastRespawnMs = opts.prev?.lastRespawnAt ? new Date(opts.prev.lastRespawnAt).getTime() : 0;\n const withinWindow = Number.isFinite(lastRespawnMs) && opts.now - lastRespawnMs < FLYWHEEL_RESPAWN_WINDOW_MS;\n const respawnCount = withinWindow ? opts.prev?.respawnCount ?? 0 : 0;\n if (respawnCount >= FLYWHEEL_MAX_RESPAWNS) return { kind: 'escalate', respawnCount };\n return { kind: 'relaunch', respawnCount: respawnCount + 1 };\n}\n\n/** True when the orchestrator's process is actually gone (session missing or dead pane). */\nfunction isFlywheelOrchestratorDead(agentId: string): boolean {\n if (!sessionExistsSync(agentId)) return true;\n return listPaneValuesSync(agentId, '#{pane_dead}').some((v) => v === '1');\n}\n\n/**\n * Recover a dead or wedged flywheel orchestrator: relaunch (capped) or, past the\n * cap, pause+trouble. `reason` describes why recovery fired (death vs wedge) for\n * the deacon log. NO_RESUME is intentionally NOT consulted (see header comment) —\n * the operator gate is the active run (`pan flywheel stop`) / patrol freeze.\n */\nasync function remediateFlywheelOrchestrator(\n agentId: string,\n now: number,\n actions: string[],\n reason: string,\n): Promise<void> {\n const decision = decideFlywheelRemediation({\n hasActiveRun: Boolean(getFlywheelActiveRunId()),\n prev: readStuckRemediationState(agentId),\n now,\n });\n if (decision.kind === 'noop') return;\n\n const { resumeFlywheel, pauseFlywheel } = await import('./flywheel.js');\n const prev = readStuckRemediationState(agentId);\n const nowIso = new Date(now).toISOString();\n\n if (decision.kind === 'escalate') {\n await pauseFlywheel();\n markAgentTroubled(agentId);\n writeStuckRemediationState(agentId, {\n lastStage: 3,\n lastStageAt: nowIso,\n firstStuckAt: prev?.firstStuckAt ?? nowIso,\n respawnCount: decision.respawnCount,\n lastRespawnAt: prev?.lastRespawnAt,\n });\n logAction(\n actions,\n `[deacon] FLYWHEEL orchestrator ${reason} and exceeded ${FLYWHEEL_MAX_RESPAWNS} relaunches in ${FLYWHEEL_RESPAWN_WINDOW_MS / 60_000}min — paused + troubled; operator needed`,\n );\n return;\n }\n\n // Clear the dead/zombie/wedged tmux session so the fresh new-session won't\n // collide (\"duplicate session\" — the failure that defeated recovery in RUN-30).\n try {\n killSessionSync(agentId);\n } catch {\n /* best effort — session may already be gone */\n }\n\n try {\n await resumeFlywheel({ resumeCause: 'system' });\n writeStuckRemediationState(agentId, {\n lastStage: 0,\n lastStageAt: nowIso,\n firstStuckAt: nowIso,\n respawnCount: decision.respawnCount,\n lastRespawnAt: nowIso,\n });\n logAction(\n actions,\n `[deacon] FLYWHEEL orchestrator ${reason} — fresh-launched (relaunch ${decision.respawnCount}/${FLYWHEEL_MAX_RESPAWNS})`,\n );\n } catch (error) {\n logAction(\n actions,\n `[deacon] FLYWHEEL orchestrator ${reason} — relaunch FAILED: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\nasync function evaluateFlywheelOrchestrator(\n agent: AgentState,\n config: StuckRemediationConfig,\n now: number,\n actions: string[],\n): Promise<void> {\n const agentId = agent.id;\n\n // Dead process ≠ idle agent. Check real liveness via tmux first — the runtime\n // mirror lies (stays \"active\") when omp dies without updating it (RUN-30).\n if (isFlywheelOrchestratorDead(agentId)) {\n await remediateFlywheelOrchestrator(agentId, now, actions, `DIED (${describeAgentDeath(agentId)})`);\n return;\n }\n\n if (!isAgentIdleForNudge(agentId, 5 * 60 * 1000, now)) return;\n\n const runtime = getAgentRuntimeStateSync(agentId);\n if (!runtime?.lastActivity) return;\n\n const lastActivityMs = new Date(runtime.lastActivity).getTime();\n if (!Number.isFinite(lastActivityMs)) return;\n\n const stuckState = readStuckRemediationState(agentId);\n if (stuckState) {\n const firstStuckMs = new Date(stuckState.firstStuckAt).getTime();\n if (Number.isFinite(firstStuckMs) && lastActivityMs > firstStuckMs) {\n clearStuckRemediationState(agentId);\n return;\n }\n }\n\n const idleMinutes = Math.floor((now - lastActivityMs) / 60_000);\n const lastStage = stuckState?.lastStage ?? 0;\n const firstStuck = firstStuckAt(runtime.lastActivity, stuckState);\n\n // PAN-2160: the terminal idle stage RELAUNCHES the wedged orchestrator (capped),\n // it never pause+troubles it. RUN-36 was parked here at idleMin=205 and the\n // whole pipeline stalled.\n if (idleMinutes >= config.flywheel_stage3_minutes && lastStage < 3) {\n await remediateFlywheelOrchestrator(agentId, now, actions, `wedged (idle ${idleMinutes}min)`);\n return;\n }\n\n if (idleMinutes >= config.flywheel_stage2_minutes && lastStage < 2) {\n const message = `Stage 2: idle ${idleMinutes} min — run a FULL flywheel tick NOW: inventory -> diagnose -> suggest -> launch ready work -> \\`pan flywheel emit-status\\`. Then call ScheduleWakeup(delaySeconds:1000) to arm the next tick. Do NOT ask the operator a question, do NOT wait, and do NOT just emit a stale status or pause.`;\n await messageAgent(agentId, message);\n writeStuckRemediationState(agentId, stageState(2, now, firstStuck, stuckState));\n logAction(actions, transitionAction(2, 'FLYWHEEL', idleMinutes, 'escalated-nudge'));\n return;\n }\n\n if (idleMinutes >= config.flywheel_stage1_minutes && lastStage < 1) {\n const message = `You appear stuck — ${idleMinutes} min since your last tick. Run a FULL flywheel tick NOW: inventory -> diagnose -> suggest -> launch ready work -> \\`pan flywheel emit-status\\`. Then call ScheduleWakeup(delaySeconds:1000) to arm the next tick. Do NOT ask the operator a question, do NOT wait, and do NOT just emit a stale status or pause.`;\n await messageAgent(agentId, message);\n writeStuckRemediationState(agentId, stageState(1, now, firstStuck, stuckState));\n logAction(actions, transitionAction(1, 'FLYWHEEL', idleMinutes, 'poked'));\n }\n}\n\nasync function reconcileActiveFlywheelWithoutRunningAgent(now: number, actions: string[]): Promise<void> {\n if (!getFlywheelActiveRunId()) return;\n if (isFlywheelGloballyPaused()) return;\n if (sessionExistsSync(FLYWHEEL_ORCHESTRATOR_AGENT_ID)) return;\n\n await remediateFlywheelOrchestrator(\n FLYWHEEL_ORCHESTRATOR_AGENT_ID,\n now,\n actions,\n `DIED (${describeAgentDeath(FLYWHEEL_ORCHESTRATOR_AGENT_ID)})`,\n );\n}\n\nexport async function checkStuckAgentRemediation(opts: StuckRemediationOptions = {}): Promise<string[]> {\n const config = loadCloisterConfigSync().stuck_remediation ?? DEFAULT_CLOISTER_CONFIG.stuck_remediation!;\n if (!config.enabled) return [];\n\n const actions: string[] = [];\n const now = opts.now ?? Date.now();\n const runningAgents = listRunningAgentsSync();\n let sawFlywheelOrchestrator = false;\n\n for (const agent of runningAgents) {\n if (agent.id === FLYWHEEL_ORCHESTRATOR_AGENT_ID || agent.role === 'flywheel') {\n sawFlywheelOrchestrator = true;\n }\n try {\n await evaluateAgent(agent, config, now, actions);\n } catch (error) {\n const agentId = agent.id || '(unknown)';\n const message = `[deacon] stuck-remediation agent=${agentId} error=${error instanceof Error ? error.message : String(error)}`;\n console.error(message, error);\n logDeaconEventSync(message);\n }\n }\n\n if (!sawFlywheelOrchestrator) {\n try {\n await reconcileActiveFlywheelWithoutRunningAgent(now, actions);\n } catch (error) {\n const message = `[deacon] stuck-remediation agent=${FLYWHEEL_ORCHESTRATOR_AGENT_ID} error=${error instanceof Error ? error.message : String(error)}`;\n console.error(message, error);\n logDeaconEventSync(message);\n }\n }\n\n return actions;\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import "./smart-compaction-C96F2aFQ.js";
2
- import { a as generateFallbackSummary, l as init_summary_fork } from "./summary-fork-D-cylknJ.js";
1
+ import "./smart-compaction-BzDfF6yb.js";
2
+ import { a as generateFallbackSummary, l as init_summary_fork } from "./summary-fork-lC2vMXly.js";
3
3
  init_summary_fork();
4
4
  export { generateFallbackSummary };
@@ -1,13 +1,13 @@
1
1
  import { n as __esmMin } from "./rolldown-runtime-DNCzzKnI.js";
2
2
  import { $r as FsError, Fi as getHandoffsDir, Li as getOverdeckHome, Ri as init_paths, Ui as sessionFilePath, Vi as packageRoot, p as loadConfigSync, t as init_config_yaml, ui as init_errors } from "./config-yaml-Dce9VUd6.js";
3
3
  import { o as init_codex_rollout_message, s as readCodexRolloutMessage } from "./behavior-Bg3yC8jC.js";
4
- import { hn as findKimiWirePathAsync, q as init_agents, vn as init_kimi_code, wr as deliverAgentMessage } from "./agent-state-Ci6PhjOE.js";
4
+ import { hn as findKimiWirePathAsync, q as init_agents, vn as init_kimi_code, wr as deliverAgentMessage } from "./agent-state-B196fj1h.js";
5
5
  import { A as init_conversations } from "./conversations-CPXMv_JQ.js";
6
6
  import { a as resolveMuseSessionPath, t as init_muse_session } from "./muse-session-CrSRuauJ.js";
7
7
  import { c as init_stack_health, o as getWorkspaceStackHealth } from "./stack-health-Y8O3UuPe.js";
8
8
  import { r as parseMuseRecords, t as init_muse_parser } from "./muse-parser-CFchR2vh.js";
9
- import { o as resolveCodexRolloutPath, t as init_jsonl_resolver } from "./jsonl-resolver-DQEe0DHM.js";
10
- import { a as runModelSummary, i as parseEntries, o as serializeConversation, r as init_smart_compaction, s as summarizeSerializedText, t as generateSmartSummary } from "./smart-compaction-C96F2aFQ.js";
9
+ import { o as resolveCodexRolloutPath, t as init_jsonl_resolver } from "./jsonl-resolver-jxbif7MD.js";
10
+ import { a as runModelSummary, i as parseEntries, o as serializeConversation, r as init_smart_compaction, s as summarizeSerializedText, t as generateSmartSummary } from "./smart-compaction-BzDfF6yb.js";
11
11
  import { join } from "node:path";
12
12
  import { Effect } from "effect";
13
13
  import { join as join$1 } from "path";
@@ -788,4 +788,4 @@ var init_summary_fork = __esmMin((() => {
788
788
  //#endregion
789
789
  export { init_transcript_adapter as _, generateFallbackSummary as a, handoffPreconditionFallbackReason as c, prependFallbackFocus as d, requestHandoffFromAgent as f, getTranscriptAdapter as g, validateHandoffDoc as h, copySessionFromCompactBoundary as i, init_summary_fork as l, sanitizeHandoffDoc as m, HandoffValidationError as n, generateSummaryForFork as o, reserveSummaryForkSession as p, authorHandoffExternal as r, handoffFailureReason as s, HandoffStallError as t, logHandoffFallback as u };
790
790
 
791
- //# sourceMappingURL=summary-fork-D-cylknJ.js.map
791
+ //# sourceMappingURL=summary-fork-lC2vMXly.js.map