@overdeck/core 0.45.10 → 0.45.11

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 (219) hide show
  1. package/dist/{agent-state-KVbJEG5f.js → agent-state-RLhS7ckO.js} +1 -1
  2. package/dist/{agents-pp8FO7Uj.js → agents-By3u_fQ8.js} +1 -1
  3. package/dist/{agents-CQHK0CSA.js → agents-CgVr77Qq.js} +12 -12
  4. package/dist/{agents-CQHK0CSA.js.map → agents-CgVr77Qq.js.map} +1 -1
  5. package/dist/{backlog-auto-trigger-CyuoS0nl.js → backlog-auto-trigger-B_-1tk4e.js} +5 -5
  6. package/dist/{backlog-auto-trigger-CyuoS0nl.js.map → backlog-auto-trigger-B_-1tk4e.js.map} +1 -1
  7. package/dist/cli/index.js +45 -45
  8. package/dist/{cli-Cewlu3yU.js → cli-DGeSW85B.js} +2 -2
  9. package/dist/{cli-Cewlu3yU.js.map → cli-DGeSW85B.js.map} +1 -1
  10. package/dist/cli-MTB9IOoR.js +3 -0
  11. package/dist/{close-issue-BJGX9_z7.js → close-issue-Djajb6Sv.js} +2 -2
  12. package/dist/{close-issue-BJGX9_z7.js.map → close-issue-Djajb6Sv.js.map} +1 -1
  13. package/dist/{concurrency-Ca-fC7tA.js → concurrency-4rzjHAQA.js} +1 -1
  14. package/dist/{conversation-compaction-B_6s9EvM.js → conversation-compaction-BQvZh09I.js} +4 -4
  15. package/dist/{conversation-compaction-B_6s9EvM.js.map → conversation-compaction-BQvZh09I.js.map} +1 -1
  16. package/dist/dashboard/{advancing-selfheal-CMlGznKv.js → advancing-selfheal-BezNfM3P.js} +3 -3
  17. package/dist/dashboard/{advancing-selfheal-CMlGznKv.js.map → advancing-selfheal-BezNfM3P.js.map} +1 -1
  18. package/dist/dashboard/{agent-state-xk_G8t90.js → agent-state-BUANcaA7.js} +1 -1
  19. package/dist/dashboard/{agent-state-service-C1iUF9Ft.js → agent-state-service-DmFpIMbP.js} +1 -1
  20. package/dist/dashboard/{agent-state-service-5ge9xxhx.js → agent-state-service-tXUdp6UF.js} +2 -2
  21. package/dist/dashboard/{agent-state-service-5ge9xxhx.js.map → agent-state-service-tXUdp6UF.js.map} +1 -1
  22. package/dist/dashboard/{agents-BIggLvi_.js → agents-C-vqmKDi.js} +1 -1
  23. package/dist/dashboard/{agents-DHvsjsuP.js → agents-C7V4odQ6.js} +11 -11
  24. package/dist/dashboard/{agents-DHvsjsuP.js.map → agents-C7V4odQ6.js.map} +1 -1
  25. package/dist/dashboard/{backlog-auto-trigger-COm_R96V.js → backlog-auto-trigger-Cb8PR-5w.js} +2 -2
  26. package/dist/dashboard/{backlog-auto-trigger-COm_R96V.js.map → backlog-auto-trigger-Cb8PR-5w.js.map} +1 -1
  27. package/dist/dashboard/{cli-CvK9xuSS.js → cli-BgzbB6h3.js} +2 -2
  28. package/dist/dashboard/{cli-CvK9xuSS.js.map → cli-BgzbB6h3.js.map} +1 -1
  29. package/dist/dashboard/cli-DCqy_wFa.js +3 -0
  30. package/dist/dashboard/{close-issue-BnpErnD1.js → close-issue-BWf3pxn4.js} +2 -2
  31. package/dist/dashboard/{close-issue-BnpErnD1.js.map → close-issue-BWf3pxn4.js.map} +1 -1
  32. package/dist/dashboard/{closed-issue-reaper-DRqK5k39.js → closed-issue-reaper-D7XPq5pY.js} +4 -4
  33. package/dist/dashboard/{closed-issue-reaper-DRqK5k39.js.map → closed-issue-reaper-D7XPq5pY.js.map} +1 -1
  34. package/dist/dashboard/{closed-issue-reaper-BLCQwTpF.js → closed-issue-reaper-VSTSTROK.js} +1 -1
  35. package/dist/dashboard/{conflict-gate-JdFuhKuF.js → conflict-gate-DwOslTij.js} +1 -1
  36. package/dist/dashboard/{conflict-gate-BhKvrPxn.js → conflict-gate-FFEvTDVA.js} +3 -3
  37. package/dist/dashboard/{conflict-gate-BhKvrPxn.js.map → conflict-gate-FFEvTDVA.js.map} +1 -1
  38. package/dist/dashboard/{conversation-compaction-C5o_eKEm.js → conversation-compaction-CCqN4hWk.js} +4 -4
  39. package/dist/dashboard/{conversation-compaction-C5o_eKEm.js.map → conversation-compaction-CCqN4hWk.js.map} +1 -1
  40. package/dist/dashboard/{conversation-compaction-Ba5aZdrb.js → conversation-compaction-CL5Ti4j4.js} +1 -1
  41. package/dist/dashboard/{deacon-j3qSZ7--.js → deacon-CGHl90eC.js} +107 -50
  42. package/dist/dashboard/{deacon-j3qSZ7--.js.map → deacon-CGHl90eC.js.map} +1 -1
  43. package/dist/dashboard/{deacon-Cv2RMfHs.js → deacon-DMPh40Im.js} +2 -2
  44. package/dist/dashboard/deacon-swarm-CVTiNL0N.js +2 -0
  45. package/dist/dashboard/{deacon-swarm-DadWNi5J.js → deacon-swarm-aMMJTq6t.js} +4 -4
  46. package/dist/dashboard/{deacon-swarm-DadWNi5J.js.map → deacon-swarm-aMMJTq6t.js.map} +1 -1
  47. package/dist/dashboard/deacon.js +4 -4
  48. package/dist/dashboard/{feedback-target-oE4-Esxl.js → feedback-target-dJjFfITP.js} +4 -4
  49. package/dist/dashboard/{feedback-target-oE4-Esxl.js.map → feedback-target-dJjFfITP.js.map} +1 -1
  50. package/dist/dashboard/{feedback-target-C4DaDSZ8.js → feedback-target-nQSM6ygL.js} +1 -1
  51. package/dist/dashboard/{flywheel-ClMjGW_u.js → flywheel-BLoVNtJV.js} +6 -6
  52. package/dist/dashboard/{flywheel-ClMjGW_u.js.map → flywheel-BLoVNtJV.js.map} +1 -1
  53. package/dist/dashboard/{flywheel-DefHRzY4.js → flywheel-Cqf8vu7N.js} +6 -6
  54. package/dist/dashboard/{flywheel-DefHRzY4.js.map → flywheel-Cqf8vu7N.js.map} +1 -1
  55. package/dist/dashboard/{flywheel-BqDdGvrQ.js → flywheel-PJsbrXNY.js} +1 -1
  56. package/dist/dashboard/{flywheel-merge-order-CuDcqTRJ.js → flywheel-merge-order-B7BH8mZ3.js} +2 -2
  57. package/dist/dashboard/{flywheel-merge-order-CuDcqTRJ.js.map → flywheel-merge-order-B7BH8mZ3.js.map} +1 -1
  58. package/dist/dashboard/{flywheel-merge-order-B6YDSElh.js → flywheel-merge-order-CCwF60b-.js} +1 -1
  59. package/dist/dashboard/{harness-resolve-DKeSVsJL.js → harness-resolve-B3f9G1Kp.js} +2 -2
  60. package/dist/dashboard/{harness-resolve-DKeSVsJL.js.map → harness-resolve-B3f9G1Kp.js.map} +1 -1
  61. package/dist/dashboard/{inspect-agent-BKKc0XnB.js → inspect-agent-CKF5-SJr.js} +3 -3
  62. package/dist/dashboard/{inspect-agent-BKKc0XnB.js.map → inspect-agent-CKF5-SJr.js.map} +1 -1
  63. package/dist/dashboard/inspect-agent-CqpEWGWy.js +2 -0
  64. package/dist/dashboard/{issue-lifecycle-DnhQgddB.js → issue-lifecycle-5LbOcATP.js} +7 -7
  65. package/dist/dashboard/{issue-lifecycle-DnhQgddB.js.map → issue-lifecycle-5LbOcATP.js.map} +1 -1
  66. package/dist/dashboard/{issue-lifecycle-nY4esZn8.js → issue-lifecycle-CjYqQ669.js} +1 -1
  67. package/dist/dashboard/{issue-service-singleton-Bnqv1uaa.js → issue-service-singleton-B8iu_TKV.js} +1 -1
  68. package/dist/dashboard/{issue-service-singleton-_AquSBTl.js → issue-service-singleton-CDGt__oQ.js} +2 -2
  69. package/dist/dashboard/{issue-service-singleton-_AquSBTl.js.map → issue-service-singleton-CDGt__oQ.js.map} +1 -1
  70. package/dist/dashboard/{lifecycle-CGKm7doE.js → lifecycle-CEg4sHZH.js} +4 -4
  71. package/dist/dashboard/{lifecycle-CGKm7doE.js.map → lifecycle-CEg4sHZH.js.map} +1 -1
  72. package/dist/dashboard/{merge-agent-Dh8Y9PDO.js → merge-agent-7nBiCytp.js} +1 -1
  73. package/dist/dashboard/{merge-agent-BcgAYStl.js → merge-agent-C81xPIGd.js} +6 -6
  74. package/dist/dashboard/{merge-agent-BcgAYStl.js.map → merge-agent-C81xPIGd.js.map} +1 -1
  75. package/dist/dashboard/merge-ops-DE_6CnmZ.js +2 -0
  76. package/dist/dashboard/{merge-train-DmxlYbEo.js → merge-train-D3qzRccL.js} +2 -2
  77. package/dist/dashboard/{merge-train-DmxlYbEo.js.map → merge-train-D3qzRccL.js.map} +1 -1
  78. package/dist/dashboard/{merge-train-deps-DBHsOWt9.js → merge-train-deps-Be5ElC_P.js} +2 -2
  79. package/dist/dashboard/{merge-train-deps-DBHsOWt9.js.map → merge-train-deps-Be5ElC_P.js.map} +1 -1
  80. package/dist/dashboard/{orphan-proposed-reconciler-Db8tUhce.js → orphan-proposed-reconciler-Boq_XaRe.js} +3 -3
  81. package/dist/dashboard/{orphan-proposed-reconciler-Db8tUhce.js.map → orphan-proposed-reconciler-Boq_XaRe.js.map} +1 -1
  82. package/dist/dashboard/{orphan-proposed-reconciler-mXV--tcB.js → orphan-proposed-reconciler-C0sPnDq_.js} +1 -1
  83. package/dist/dashboard/{reconstruct-cache-_tDZ2D72.js → reconstruct-cache-C2pCltOq.js} +3 -3
  84. package/dist/dashboard/{reconstruct-cache-_tDZ2D72.js.map → reconstruct-cache-C2pCltOq.js.map} +1 -1
  85. package/dist/dashboard/{remote-completion-Bklh6loJ.js → remote-completion-BmxD5UMQ.js} +3 -3
  86. package/dist/dashboard/{remote-completion-Bklh6loJ.js.map → remote-completion-BmxD5UMQ.js.map} +1 -1
  87. package/dist/dashboard/resume-C-nxu9Y4.js +3 -0
  88. package/dist/dashboard/{review-agent-phzqNqIs.js → review-agent-D6P6d3pz.js} +26 -17
  89. package/dist/dashboard/review-agent-D6P6d3pz.js.map +1 -0
  90. package/dist/dashboard/review-agent-DTINEffB.js +3 -0
  91. package/dist/dashboard/{review-context-CCq56O_Y.js → review-context-Dyo0tsBa.js} +2 -2
  92. package/dist/dashboard/{review-context-CCq56O_Y.js.map → review-context-Dyo0tsBa.js.map} +1 -1
  93. package/dist/dashboard/{review-status-BQjqQXZG.js → review-status-B5ZASOo4.js} +18 -5
  94. package/dist/dashboard/review-status-B5ZASOo4.js.map +1 -0
  95. package/dist/dashboard/{review-status-bBkqUj5i.js → review-status-h7BXIA4z.js} +1 -1
  96. package/dist/dashboard/{review-verdict-feedback-wqnikhMK.js → review-verdict-feedback-B70VbfRL.js} +4 -4
  97. package/dist/dashboard/{review-verdict-feedback-wqnikhMK.js.map → review-verdict-feedback-B70VbfRL.js.map} +1 -1
  98. package/dist/dashboard/{review-verdict-feedback-cZh9Wi9G.js → review-verdict-feedback-CorgH49f.js} +1 -1
  99. package/dist/dashboard/{sequence-io-B2GmilSI.js → sequence-io-6YP8fVpH.js} +2 -2
  100. package/dist/dashboard/{sequence-io-B2GmilSI.js.map → sequence-io-6YP8fVpH.js.map} +1 -1
  101. package/dist/dashboard/{sequencer-agent-D8pW2aU_.js → sequencer-agent-ja-nkEc1.js} +5 -5
  102. package/dist/dashboard/{sequencer-agent-D8pW2aU_.js.map → sequencer-agent-ja-nkEc1.js.map} +1 -1
  103. package/dist/dashboard/server.js +66 -55
  104. package/dist/dashboard/server.js.map +1 -1
  105. package/dist/dashboard/{service-CILd-uOt.js → service-HKDrIy0h.js} +24 -24
  106. package/dist/dashboard/{service-CILd-uOt.js.map → service-HKDrIy0h.js.map} +1 -1
  107. package/dist/dashboard/{smart-compaction-Bgp_gwcA.js → smart-compaction-L0LSnF0_.js} +1 -1
  108. package/dist/dashboard/{smart-compaction-CrP90OFE.js → smart-compaction-uke1npUz.js} +2 -2
  109. package/dist/dashboard/{smart-compaction-CrP90OFE.js.map → smart-compaction-uke1npUz.js.map} +1 -1
  110. package/dist/dashboard/{spawn-planning-session-D15KbPOy.js → spawn-planning-session-CSMWco8B.js} +1 -1
  111. package/dist/dashboard/{spawn-planning-session-BmJWHSCu.js → spawn-planning-session-CXc0NkwV.js} +3 -3
  112. package/dist/dashboard/{spawn-planning-session-BmJWHSCu.js.map → spawn-planning-session-CXc0NkwV.js.map} +1 -1
  113. package/dist/dashboard/{specialist-context-CwKkcXL9.js → specialist-context-BGCJ24LH.js} +3 -3
  114. package/dist/dashboard/{specialist-context-CwKkcXL9.js.map → specialist-context-BGCJ24LH.js.map} +1 -1
  115. package/dist/dashboard/{specialist-logs-CvDxquV_.js → specialist-logs--Uz-r8ia.js} +2 -2
  116. package/dist/dashboard/{specialist-logs-CvDxquV_.js.map → specialist-logs--Uz-r8ia.js.map} +1 -1
  117. package/dist/dashboard/{specialists-BCjcG4uE.js → specialists-Ca9XSBCS.js} +1 -1
  118. package/dist/dashboard/{specialists-D07ybnam.js → specialists-DEfrAbWs.js} +36 -36
  119. package/dist/dashboard/{specialists-D07ybnam.js.map → specialists-DEfrAbWs.js.map} +1 -1
  120. package/dist/dashboard/{specialists-F2uMO4QS.js → specialists-DeZx9xom.js} +1 -1
  121. package/dist/dashboard/{specialists-BYi0k8CZ.js → specialists-nZ0mRwpZ.js} +12 -12
  122. package/dist/dashboard/{specialists-BYi0k8CZ.js.map → specialists-nZ0mRwpZ.js.map} +1 -1
  123. package/dist/dashboard/{summary-fork-DedqguZb.js → summary-fork-2a1L2DIU.js} +2 -2
  124. package/dist/dashboard/{summary-fork-EjvOkEPl.js → summary-fork-Xn0QUNmb.js} +3 -3
  125. package/dist/dashboard/{summary-fork-EjvOkEPl.js.map → summary-fork-Xn0QUNmb.js.map} +1 -1
  126. package/dist/dashboard/{teardown-workspace-5LCVbjfq.js → teardown-workspace-DhA6oAIK.js} +2 -2
  127. package/dist/dashboard/{teardown-workspace-5LCVbjfq.js.map → teardown-workspace-DhA6oAIK.js.map} +1 -1
  128. package/dist/dashboard/{test-agent-queue-qfsq6uaC.js → test-agent-queue-B_ukPyIK.js} +3 -3
  129. package/dist/dashboard/{test-agent-queue-qfsq6uaC.js.map → test-agent-queue-B_ukPyIK.js.map} +1 -1
  130. package/dist/dashboard/{uat-train-CtNGgXxj.js → uat-train-BLBAbJ8Y.js} +10 -10
  131. package/dist/dashboard/{uat-train-CtNGgXxj.js.map → uat-train-BLBAbJ8Y.js.map} +1 -1
  132. package/dist/dashboard/{uat-train-C3hWXtip.js → uat-train-DPfGR9_I.js} +1 -1
  133. package/dist/dashboard/{verification-runner-DuZRHjPU.js → verification-runner-KTGTNugM.js} +1 -1
  134. package/dist/dashboard/{verification-runner-BPAhPWR7.js → verification-runner-R2-4XgMO.js} +4 -4
  135. package/dist/dashboard/{verification-runner-BPAhPWR7.js.map → verification-runner-R2-4XgMO.js.map} +1 -1
  136. package/dist/dashboard/{workflows-H-COJ84X.js → workflows-CSKX5MhC.js} +7 -7
  137. package/dist/dashboard/{workflows-H-COJ84X.js.map → workflows-CSKX5MhC.js.map} +1 -1
  138. package/dist/dashboard/workflows-DVwXauef.js +2 -0
  139. package/dist/dashboard/{workspaces-CRU9_vRn.js → workspaces-DXLDgXo2.js} +32 -32
  140. package/dist/dashboard/{workspaces-CRU9_vRn.js.map → workspaces-DXLDgXo2.js.map} +1 -1
  141. package/dist/docs-index.sqlite +0 -0
  142. package/dist/{feedback-target-DTGAhFkM.js → feedback-target-BsKN4Tr_.js} +4 -4
  143. package/dist/{feedback-target-DTGAhFkM.js.map → feedback-target-BsKN4Tr_.js.map} +1 -1
  144. package/dist/{feedback-target-DutF088V.js → feedback-target-DM1WzOKy.js} +1 -1
  145. package/dist/{harness-resolve-Bz1prk6B.js → harness-resolve-B-YDNwNW.js} +2 -2
  146. package/dist/{harness-resolve-Bz1prk6B.js.map → harness-resolve-B-YDNwNW.js.map} +1 -1
  147. package/dist/{issue-lifecycle-fVqvCdKM.js → issue-lifecycle-Bc1l3U9f.js} +7 -7
  148. package/dist/{issue-lifecycle-fVqvCdKM.js.map → issue-lifecycle-Bc1l3U9f.js.map} +1 -1
  149. package/dist/{issue-service-singleton-CZm8p6Rj.js → issue-service-singleton-D-8Q6tdT.js} +1 -1
  150. package/dist/{issue-service-singleton-Cr73JAaR.js → issue-service-singleton-D1433I7n.js} +2 -2
  151. package/dist/{issue-service-singleton-Cr73JAaR.js.map → issue-service-singleton-D1433I7n.js.map} +1 -1
  152. package/dist/{lifecycle-CR6tZfl1.js → lifecycle-SmrqysDf.js} +7 -7
  153. package/dist/{lifecycle-CR6tZfl1.js.map → lifecycle-SmrqysDf.js.map} +1 -1
  154. package/dist/{lifecycle-D_EWiUjk.js → lifecycle-mRMyiIXs.js} +2 -2
  155. package/dist/{merge-agent-LM4avOtA.js → merge-agent-B9hIZ6Z0.js} +6 -6
  156. package/dist/{merge-agent-LM4avOtA.js.map → merge-agent-B9hIZ6Z0.js.map} +1 -1
  157. package/dist/{merge-agent-Bj046HE1.js → merge-agent-DUj22cXL.js} +1 -1
  158. package/dist/{merge-fulfillment-DrnC1Kmg.js → merge-fulfillment-__P4WE-T.js} +3 -3
  159. package/dist/{merge-fulfillment-DrnC1Kmg.js.map → merge-fulfillment-__P4WE-T.js.map} +1 -1
  160. package/dist/{reconstruct-cache-NPqoAUg-.js → reconstruct-cache-9SWp82SQ.js} +3 -3
  161. package/dist/{reconstruct-cache-NPqoAUg-.js.map → reconstruct-cache-9SWp82SQ.js.map} +1 -1
  162. package/dist/{records-BIkN1LQ4.js → records-CTmvuRzz.js} +14 -1
  163. package/dist/{records-BIkN1LQ4.js.map → records-CTmvuRzz.js.map} +1 -1
  164. package/dist/records-backfill-BQcmTmwF.js +2 -0
  165. package/dist/{records-backfill-HM0Pln6N.js → records-backfill-BrNsv_zT.js} +2 -2
  166. package/dist/{records-backfill-HM0Pln6N.js.map → records-backfill-BrNsv_zT.js.map} +1 -1
  167. package/dist/resume-Bn4kDk9x.js +3 -0
  168. package/dist/{review-agent-DFosQzCG.js → review-agent-PhqOhpx3.js} +24 -16
  169. package/dist/{review-agent-DFosQzCG.js.map → review-agent-PhqOhpx3.js.map} +1 -1
  170. package/dist/review-agent-hLbRRxZF.js +3 -0
  171. package/dist/{review-status-iJwfEoNX.js → review-status-B_XXomV0.js} +6 -6
  172. package/dist/{review-status-iJwfEoNX.js.map → review-status-B_XXomV0.js.map} +1 -1
  173. package/dist/{review-status-BbNVlXh1.js → review-status-Bo-EFVKh.js} +1 -1
  174. package/dist/{review-verdict-feedback-BGPw3z1X.js → review-verdict-feedback-CXHkoiKZ.js} +1 -1
  175. package/dist/{review-verdict-feedback-CCZ05atV.js → review-verdict-feedback-DGV13LDb.js} +4 -4
  176. package/dist/{review-verdict-feedback-CCZ05atV.js.map → review-verdict-feedback-DGV13LDb.js.map} +1 -1
  177. package/dist/{sequence-io-CcxZNHcD.js → sequence-io-Cg4NHAco.js} +1 -1
  178. package/dist/{sequence-io-Cx1usxG3.js → sequence-io-CyxvNHfA.js} +2 -2
  179. package/dist/{sequence-io-Cx1usxG3.js.map → sequence-io-CyxvNHfA.js.map} +1 -1
  180. package/dist/{smart-compaction-ByUEgQkF.js → smart-compaction-ByKXTQNy.js} +2 -2
  181. package/dist/{smart-compaction-ByUEgQkF.js.map → smart-compaction-ByKXTQNy.js.map} +1 -1
  182. package/dist/{smart-compaction-DfLe_CtH.js → smart-compaction-U6e_uB1E.js} +1 -1
  183. package/dist/{specialist-context-McuGkaeR.js → specialist-context-BUTadO-U.js} +3 -3
  184. package/dist/{specialist-context-McuGkaeR.js.map → specialist-context-BUTadO-U.js.map} +1 -1
  185. package/dist/{specialist-logs-CUUJ4eiB.js → specialist-logs-pEMCTtGZ.js} +2 -2
  186. package/dist/{specialist-logs-CUUJ4eiB.js.map → specialist-logs-pEMCTtGZ.js.map} +1 -1
  187. package/dist/{specialists-BSrylD1S.js → specialists-BGFnrQ8n.js} +1 -1
  188. package/dist/{specialists-B0elgInc.js → specialists-DeTkkp8b.js} +12 -12
  189. package/dist/{specialists-B0elgInc.js.map → specialists-DeTkkp8b.js.map} +1 -1
  190. package/dist/{summary-fork-DskMRnyb.js → summary-fork-CgzThE2-.js} +2 -2
  191. package/dist/{summary-fork-CPUTKcAT.js → summary-fork-Dx1RMuvU.js} +3 -3
  192. package/dist/{summary-fork-CPUTKcAT.js.map → summary-fork-Dx1RMuvU.js.map} +1 -1
  193. package/dist/{sync-BiNVQHBf.js → sync-Bsww9tuj.js} +2 -2
  194. package/dist/{sync-BiNVQHBf.js.map → sync-Bsww9tuj.js.map} +1 -1
  195. package/dist/sync-CylE_SjB.js +2 -0
  196. package/dist/{verdict-restore-DQiV7_fe.js → verdict-restore-DGpX0ZOJ.js} +5 -5
  197. package/dist/{verdict-restore-DQiV7_fe.js.map → verdict-restore-DGpX0ZOJ.js.map} +1 -1
  198. package/dist/{webhook-handlers-DHBSEDEm.js → webhook-handlers-BjsfIL7u.js} +3 -3
  199. package/dist/{webhook-handlers-DHBSEDEm.js.map → webhook-handlers-BjsfIL7u.js.map} +1 -1
  200. package/dist/{workspace-migrate-duUsWNpd.js → workspace-migrate-BBQ8nAnP.js} +2 -2
  201. package/dist/{workspace-migrate-duUsWNpd.js.map → workspace-migrate-BBQ8nAnP.js.map} +1 -1
  202. package/dist/{workspace-reap-DLCIoJmn.js → workspace-reap-12O9354k.js} +2 -2
  203. package/dist/{workspace-reap-DLCIoJmn.js.map → workspace-reap-12O9354k.js.map} +1 -1
  204. package/package.json +1 -1
  205. package/scripts/file-size-baseline.txt +1 -1
  206. package/dist/cli-DBWG12XK.js +0 -3
  207. package/dist/dashboard/cli-CJDWXE_Y.js +0 -3
  208. package/dist/dashboard/deacon-swarm-D1iAUX-P.js +0 -2
  209. package/dist/dashboard/inspect-agent-vm88mLYr.js +0 -2
  210. package/dist/dashboard/merge-ops-QdBiQ8XB.js +0 -2
  211. package/dist/dashboard/resume-DnIsmIgC.js +0 -3
  212. package/dist/dashboard/review-agent-DgySDb-G.js +0 -3
  213. package/dist/dashboard/review-agent-phzqNqIs.js.map +0 -1
  214. package/dist/dashboard/review-status-BQjqQXZG.js.map +0 -1
  215. package/dist/dashboard/workflows-Cz8OtiB4.js +0 -2
  216. package/dist/records-backfill-DEgtRyKL.js +0 -2
  217. package/dist/resume-DGymuXZM.js +0 -3
  218. package/dist/review-agent-DjVadURa.js +0 -3
  219. package/dist/sync-4jqukkxz.js +0 -2
@@ -1,10 +1,10 @@
1
1
  import { rn as init_auto_commit, tn as flushAllPendingAutoCommits } from "./config-yaml-DPAieL_G.js";
2
2
  import { a as init_activity_logger, o as setActivityEventStoreProvider } from "./activity-logger-pcbf-e30.js";
3
- import { c as init_review_status, s as getReviewStatusSync } from "./review-status-BQjqQXZG.js";
4
- import { Mn as getAgentState, t as init_agents } from "./agents-DHvsjsuP.js";
5
- import { r as setCloisterEventStoreProvider, t as getCloisterService } from "./service-CILd-uOt.js";
3
+ import { c as init_review_status, s as getReviewStatusSync } from "./review-status-B5ZASOo4.js";
4
+ import { Mn as getAgentState, t as init_agents } from "./agents-C7V4odQ6.js";
5
+ import { r as setCloisterEventStoreProvider, t as getCloisterService } from "./service-HKDrIy0h.js";
6
6
  import { i as ensureInternalTokenSync, s as init_internal_token, t as INTERNAL_TOKEN_HEADER } from "./internal-token-CQUx9YLc.js";
7
- import { F as setAgentStatusChangedNotifier, I as setAgentStoppedNotifier, L as setMergeReadyNotifier, M as resetPatrolHeartbeatForStartup, N as runPatrol } from "./deacon-j3qSZ7--.js";
7
+ import { F as setAgentStatusChangedNotifier, I as setAgentStoppedNotifier, L as setMergeReadyNotifier, M as resetPatrolHeartbeatForStartup, N as runPatrol } from "./deacon-CGHl90eC.js";
8
8
  import { t as enrichReviewStatus } from "./review-status-enrichment-CGlcApSn.js";
9
9
  import { Effect } from "effect";
10
10
  import { randomUUID } from "node:crypto";
@@ -107,7 +107,7 @@ async function resolveIssueFeedbackTarget(issueId, opts = {}) {
107
107
  */
108
108
  async function resurrectAgentForFeedback(agentId, issueId) {
109
109
  try {
110
- const { getAgentStateSync, clearAgentPausedSync, clearAgentTroubledSync } = await import("./agent-state-xk_G8t90.js");
110
+ const { getAgentStateSync, clearAgentPausedSync, clearAgentTroubledSync } = await import("./agent-state-BUANcaA7.js");
111
111
  const state = getAgentStateSync(agentId);
112
112
  if (!state) return false;
113
113
  if (state.paused === true) {
@@ -123,7 +123,7 @@ async function resurrectAgentForFeedback(agentId, issueId) {
123
123
  console.warn(`[feedback-target] ${agentId} is gated (troubled=${state.troubled === true}, failures=${state.consecutiveFailures ?? 0}) — clearing for one resurrection attempt to deliver ${issueId} feedback; failure tracking re-trips the gate on another crash`);
124
124
  clearAgentTroubledSync(agentId);
125
125
  }
126
- const { resumeAgent } = await import("./resume-DnIsmIgC.js");
126
+ const { resumeAgent } = await import("./resume-C-nxu9Y4.js");
127
127
  const result = await resumeAgent(agentId);
128
128
  if (!result.success) {
129
129
  console.warn(`[feedback-target] Failed to resurrect ${agentId} for ${issueId} feedback: ${result.error}`);
@@ -137,7 +137,7 @@ async function resurrectAgentForFeedback(agentId, issueId) {
137
137
  }
138
138
  async function surfaceIssueFeedbackNeedsYou(issueId, reason, details = {}) {
139
139
  try {
140
- const { markWorkspaceStuck } = await import("./review-status-bBkqUj5i.js");
140
+ const { markWorkspaceStuck } = await import("./review-status-h7BXIA4z.js");
141
141
  markWorkspaceStuck(issueId, "feedback_delivery_needs_you", {
142
142
  reason,
143
143
  ...details
@@ -155,4 +155,4 @@ var init_feedback_target = __esmMin((() => {
155
155
  //#endregion
156
156
  export { resolveIssueFeedbackTarget as n, surfaceIssueFeedbackNeedsYou as r, init_feedback_target as t };
157
157
 
158
- //# sourceMappingURL=feedback-target-oE4-Esxl.js.map
158
+ //# sourceMappingURL=feedback-target-dJjFfITP.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"feedback-target-oE4-Esxl.js","names":[],"sources":["../../src/lib/cloister/feedback-target.ts"],"sourcesContent":["import { Effect } from 'effect';\n\nimport { getProjectSync, resolveProjectFromIssueSync } from '../projects.js';\nimport { readIssueRecordSync, writeIssueRecordSync, type PanIssueRecord } from '../pan-dir/record.js';\nimport { listSessionNames, sessionExists } from '../tmux.js';\n\nexport type IssueFeedbackTarget =\n | { agentId: string }\n | { needsYou: true; reason: string };\n\nexport interface ResolveIssueFeedbackTargetOptions {\n itemId?: string;\n /** Test hook — replaces the default resurrection attempt for non-live targets. */\n revivePipelinePausedAgent?: (agentId: string, issueId: string) => Promise<boolean>;\n}\n\nasync function isLiveSession(agentId: string): Promise<boolean> {\n return Effect.runPromise(sessionExists(agentId));\n}\n\nfunction slotAgentId(issueId: string, slotIndex: number, assignedAgentId?: string): string {\n return assignedAgentId ?? `agent-${issueId.toLowerCase()}-slot-${slotIndex}`;\n}\n\nasync function findLiveUnregisteredSlot(issueId: string): Promise<{ agentId: string; slotIndex: number } | null> {\n const prefix = `agent-${issueId.toLowerCase()}-slot-`;\n const sessions = await Effect.runPromise(listSessionNames());\n for (const session of sessions) {\n if (!session.startsWith(prefix)) continue;\n const slotIndex = Number.parseInt(session.slice(prefix.length), 10);\n if (!Number.isInteger(slotIndex) || slotIndex < 1) continue;\n if (await isLiveSession(session)) return { agentId: session, slotIndex };\n }\n return null;\n}\n\nfunction selfHealSlotAssignment(record: PanIssueRecord, agentId: string, slotIndex: number, itemId?: string): PanIssueRecord {\n const assignments = record.swarm?.slotAssignments ?? [];\n const existing = assignments.find((assignment) => assignment.slotIndex === slotIndex || assignment.agentId === agentId);\n const assignedAt = new Date().toISOString();\n const slotAssignments = existing\n ? assignments.map((assignment) => assignment === existing\n ? { ...assignment, agentId, itemId: itemId ?? assignment.itemId, assignedAt: assignment.assignedAt ?? assignedAt }\n : assignment)\n : [\n ...assignments,\n {\n slotIndex,\n itemId: itemId ?? `slot-${slotIndex}`,\n agentId,\n assignedAt,\n },\n ];\n\n return {\n ...record,\n swarm: {\n ...record.swarm,\n slotAssignments,\n },\n };\n}\n\nexport async function resolveIssueFeedbackTarget(\n issueId: string,\n opts: ResolveIssueFeedbackTargetOptions = {},\n): Promise<IssueFeedbackTarget> {\n const normalizedIssue = issueId.toUpperCase();\n const issueLower = normalizedIssue.toLowerCase();\n const wholeIssueAgentId = `agent-${issueLower}`;\n\n if (await isLiveSession(wholeIssueAgentId)) {\n return { agentId: wholeIssueAgentId };\n }\n\n const resolved = resolveProjectFromIssueSync(normalizedIssue);\n const project = resolved ? getProjectSync(resolved.projectKey) : null;\n const record = project ? readIssueRecordSync(project, normalizedIssue) : null;\n const assignments = record?.swarm?.slotAssignments ?? [];\n\n const requestedItemId = opts.itemId?.trim();\n if (requestedItemId) {\n const assigned = assignments.find(a => a.itemId === requestedItemId);\n if (assigned) {\n const agentId = slotAgentId(normalizedIssue, assigned.slotIndex, assigned.agentId);\n if (await isLiveSession(agentId)) return { agentId };\n }\n }\n\n for (const assignment of assignments) {\n const agentId = slotAgentId(normalizedIssue, assignment.slotIndex, assignment.agentId);\n if (await isLiveSession(agentId)) return { agentId };\n }\n\n if (project && record) {\n const fallback = await findLiveUnregisteredSlot(normalizedIssue);\n if (fallback) {\n writeIssueRecordSync(project, normalizedIssue, selfHealSlotAssignment(record, fallback.agentId, fallback.slotIndex, requestedItemId));\n return { agentId: fallback.agentId };\n }\n }\n\n // PAN-2209 + PAN-2461 — resurrection-first delivery (operator directive 2026-07-11):\n // feedback with no live target is NOT an operator problem until resurrection has been\n // tried. The verification gate pausing the only delivery target (PAN-2461), a\n // governor/scheduler yield, a crash, or a plain stopped work agent after a BLOCKED\n // verdict (PAN-2209) must all self-heal by bringing the agent back and delivering.\n // Operator pauses are the one gate never overridden. Escalating to a human (or any\n // mailbox-style deferred delivery, PAN-2255) is strictly the last resort after\n // resurrection of every candidate has failed.\n const revive = opts.revivePipelinePausedAgent ?? resurrectAgentForFeedback;\n const candidates: string[] = [wholeIssueAgentId];\n if (requestedItemId) {\n const assigned = assignments.find(a => a.itemId === requestedItemId);\n if (assigned) candidates.push(slotAgentId(normalizedIssue, assigned.slotIndex, assigned.agentId));\n }\n for (const assignment of assignments) {\n candidates.push(slotAgentId(normalizedIssue, assignment.slotIndex, assignment.agentId));\n }\n const attempted = new Set<string>();\n for (const candidate of candidates) {\n if (attempted.has(candidate)) continue;\n attempted.add(candidate);\n if (await revive(candidate, normalizedIssue)) return { agentId: candidate };\n }\n\n const suffix = requestedItemId ? ` for item ${requestedItemId}` : '';\n return {\n needsYou: true,\n reason: `No live feedback target for ${normalizedIssue}${suffix}: ${wholeIssueAgentId} is not running, no assigned swarm slot has a live tmux session, and resurrection of ${attempted.size} candidate agent(s) failed.`,\n };\n}\n\n/**\n * PAN-2209 + PAN-2461: bring a non-running agent back to life so feedback can be\n * delivered to it. Returns true when the agent is live again. Gate handling:\n *\n * - Pipeline pauses (`needs-you:*`, `[governor-slot]*`, scheduler yields) → unpause +\n * resume. A gate the pipeline set must never deadlock the pipeline's own delivery\n * (PAN-2461); the operator explicitly prefers briefly exceeding memory targets over\n * undelivered work↔review feedback.\n * - Troubled / failure-backoff → clear the gate loudly and attempt ONE resume. The\n * failure-tracking machinery re-trips the gate if the agent crashes again, so this\n * cannot loop unboundedly.\n * - Plain stopped/completed/crashed → resume.\n * - OPERATOR pauses (pan pause, any non-pipeline pausedReason) are never overridden.\n */\nasync function resurrectAgentForFeedback(agentId: string, issueId: string): Promise<boolean> {\n try {\n const { getAgentStateSync, clearAgentPausedSync, clearAgentTroubledSync } = await import('../agents/agent-state.js');\n const state = getAgentStateSync(agentId);\n if (!state) return false;\n\n if (state.paused === true) {\n const reason = state.pausedReason ?? '';\n const pipelinePause = reason.startsWith('needs-you:')\n || reason.startsWith('[governor-slot]')\n || state.yieldedByScheduler === true;\n if (!pipelinePause) {\n console.log(`[feedback-target] ${agentId} is operator-paused (${reason || 'no reason'}) — not overriding to deliver ${issueId} feedback`);\n return false;\n }\n console.log(`[feedback-target] ${agentId} is pipeline-paused (${reason || 'scheduler yield'}) — unpausing to deliver feedback for ${issueId}`);\n clearAgentPausedSync(agentId);\n }\n\n if (state.troubled === true || (state.consecutiveFailures ?? 0) > 0) {\n console.warn(\n `[feedback-target] ${agentId} is gated (troubled=${state.troubled === true}, ` +\n `failures=${state.consecutiveFailures ?? 0}) — clearing for one resurrection attempt to ` +\n `deliver ${issueId} feedback; failure tracking re-trips the gate on another crash`,\n );\n clearAgentTroubledSync(agentId);\n }\n\n const { resumeAgent } = await import('../agents/resume.js');\n const result = await resumeAgent(agentId);\n if (!result.success) {\n console.warn(`[feedback-target] Failed to resurrect ${agentId} for ${issueId} feedback: ${result.error}`);\n return false;\n }\n return isLiveSession(agentId);\n } catch (err) {\n console.warn(`[feedback-target] resurrectAgentForFeedback(${agentId}) failed: ${err instanceof Error ? err.message : String(err)}`);\n return false;\n }\n}\n\nexport async function surfaceIssueFeedbackNeedsYou(\n issueId: string,\n reason: string,\n details: Record<string, unknown> = {},\n): Promise<void> {\n try {\n const { markWorkspaceStuck } = await import('../review-status.js');\n markWorkspaceStuck(issueId, 'feedback_delivery_needs_you', {\n reason,\n ...details,\n });\n } catch (err) {\n console.warn(`[feedback-target] Failed to mark ${issueId} as needing human attention: ${err instanceof Error ? err.message : String(err)}`);\n }\n console.warn(`[feedback-target] ${reason}`);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"feedback-target-dJjFfITP.js","names":[],"sources":["../../src/lib/cloister/feedback-target.ts"],"sourcesContent":["import { Effect } from 'effect';\n\nimport { getProjectSync, resolveProjectFromIssueSync } from '../projects.js';\nimport { readIssueRecordSync, writeIssueRecordSync, type PanIssueRecord } from '../pan-dir/record.js';\nimport { listSessionNames, sessionExists } from '../tmux.js';\n\nexport type IssueFeedbackTarget =\n | { agentId: string }\n | { needsYou: true; reason: string };\n\nexport interface ResolveIssueFeedbackTargetOptions {\n itemId?: string;\n /** Test hook — replaces the default resurrection attempt for non-live targets. */\n revivePipelinePausedAgent?: (agentId: string, issueId: string) => Promise<boolean>;\n}\n\nasync function isLiveSession(agentId: string): Promise<boolean> {\n return Effect.runPromise(sessionExists(agentId));\n}\n\nfunction slotAgentId(issueId: string, slotIndex: number, assignedAgentId?: string): string {\n return assignedAgentId ?? `agent-${issueId.toLowerCase()}-slot-${slotIndex}`;\n}\n\nasync function findLiveUnregisteredSlot(issueId: string): Promise<{ agentId: string; slotIndex: number } | null> {\n const prefix = `agent-${issueId.toLowerCase()}-slot-`;\n const sessions = await Effect.runPromise(listSessionNames());\n for (const session of sessions) {\n if (!session.startsWith(prefix)) continue;\n const slotIndex = Number.parseInt(session.slice(prefix.length), 10);\n if (!Number.isInteger(slotIndex) || slotIndex < 1) continue;\n if (await isLiveSession(session)) return { agentId: session, slotIndex };\n }\n return null;\n}\n\nfunction selfHealSlotAssignment(record: PanIssueRecord, agentId: string, slotIndex: number, itemId?: string): PanIssueRecord {\n const assignments = record.swarm?.slotAssignments ?? [];\n const existing = assignments.find((assignment) => assignment.slotIndex === slotIndex || assignment.agentId === agentId);\n const assignedAt = new Date().toISOString();\n const slotAssignments = existing\n ? assignments.map((assignment) => assignment === existing\n ? { ...assignment, agentId, itemId: itemId ?? assignment.itemId, assignedAt: assignment.assignedAt ?? assignedAt }\n : assignment)\n : [\n ...assignments,\n {\n slotIndex,\n itemId: itemId ?? `slot-${slotIndex}`,\n agentId,\n assignedAt,\n },\n ];\n\n return {\n ...record,\n swarm: {\n ...record.swarm,\n slotAssignments,\n },\n };\n}\n\nexport async function resolveIssueFeedbackTarget(\n issueId: string,\n opts: ResolveIssueFeedbackTargetOptions = {},\n): Promise<IssueFeedbackTarget> {\n const normalizedIssue = issueId.toUpperCase();\n const issueLower = normalizedIssue.toLowerCase();\n const wholeIssueAgentId = `agent-${issueLower}`;\n\n if (await isLiveSession(wholeIssueAgentId)) {\n return { agentId: wholeIssueAgentId };\n }\n\n const resolved = resolveProjectFromIssueSync(normalizedIssue);\n const project = resolved ? getProjectSync(resolved.projectKey) : null;\n const record = project ? readIssueRecordSync(project, normalizedIssue) : null;\n const assignments = record?.swarm?.slotAssignments ?? [];\n\n const requestedItemId = opts.itemId?.trim();\n if (requestedItemId) {\n const assigned = assignments.find(a => a.itemId === requestedItemId);\n if (assigned) {\n const agentId = slotAgentId(normalizedIssue, assigned.slotIndex, assigned.agentId);\n if (await isLiveSession(agentId)) return { agentId };\n }\n }\n\n for (const assignment of assignments) {\n const agentId = slotAgentId(normalizedIssue, assignment.slotIndex, assignment.agentId);\n if (await isLiveSession(agentId)) return { agentId };\n }\n\n if (project && record) {\n const fallback = await findLiveUnregisteredSlot(normalizedIssue);\n if (fallback) {\n writeIssueRecordSync(project, normalizedIssue, selfHealSlotAssignment(record, fallback.agentId, fallback.slotIndex, requestedItemId));\n return { agentId: fallback.agentId };\n }\n }\n\n // PAN-2209 + PAN-2461 — resurrection-first delivery (operator directive 2026-07-11):\n // feedback with no live target is NOT an operator problem until resurrection has been\n // tried. The verification gate pausing the only delivery target (PAN-2461), a\n // governor/scheduler yield, a crash, or a plain stopped work agent after a BLOCKED\n // verdict (PAN-2209) must all self-heal by bringing the agent back and delivering.\n // Operator pauses are the one gate never overridden. Escalating to a human (or any\n // mailbox-style deferred delivery, PAN-2255) is strictly the last resort after\n // resurrection of every candidate has failed.\n const revive = opts.revivePipelinePausedAgent ?? resurrectAgentForFeedback;\n const candidates: string[] = [wholeIssueAgentId];\n if (requestedItemId) {\n const assigned = assignments.find(a => a.itemId === requestedItemId);\n if (assigned) candidates.push(slotAgentId(normalizedIssue, assigned.slotIndex, assigned.agentId));\n }\n for (const assignment of assignments) {\n candidates.push(slotAgentId(normalizedIssue, assignment.slotIndex, assignment.agentId));\n }\n const attempted = new Set<string>();\n for (const candidate of candidates) {\n if (attempted.has(candidate)) continue;\n attempted.add(candidate);\n if (await revive(candidate, normalizedIssue)) return { agentId: candidate };\n }\n\n const suffix = requestedItemId ? ` for item ${requestedItemId}` : '';\n return {\n needsYou: true,\n reason: `No live feedback target for ${normalizedIssue}${suffix}: ${wholeIssueAgentId} is not running, no assigned swarm slot has a live tmux session, and resurrection of ${attempted.size} candidate agent(s) failed.`,\n };\n}\n\n/**\n * PAN-2209 + PAN-2461: bring a non-running agent back to life so feedback can be\n * delivered to it. Returns true when the agent is live again. Gate handling:\n *\n * - Pipeline pauses (`needs-you:*`, `[governor-slot]*`, scheduler yields) → unpause +\n * resume. A gate the pipeline set must never deadlock the pipeline's own delivery\n * (PAN-2461); the operator explicitly prefers briefly exceeding memory targets over\n * undelivered work↔review feedback.\n * - Troubled / failure-backoff → clear the gate loudly and attempt ONE resume. The\n * failure-tracking machinery re-trips the gate if the agent crashes again, so this\n * cannot loop unboundedly.\n * - Plain stopped/completed/crashed → resume.\n * - OPERATOR pauses (pan pause, any non-pipeline pausedReason) are never overridden.\n */\nasync function resurrectAgentForFeedback(agentId: string, issueId: string): Promise<boolean> {\n try {\n const { getAgentStateSync, clearAgentPausedSync, clearAgentTroubledSync } = await import('../agents/agent-state.js');\n const state = getAgentStateSync(agentId);\n if (!state) return false;\n\n if (state.paused === true) {\n const reason = state.pausedReason ?? '';\n const pipelinePause = reason.startsWith('needs-you:')\n || reason.startsWith('[governor-slot]')\n || state.yieldedByScheduler === true;\n if (!pipelinePause) {\n console.log(`[feedback-target] ${agentId} is operator-paused (${reason || 'no reason'}) — not overriding to deliver ${issueId} feedback`);\n return false;\n }\n console.log(`[feedback-target] ${agentId} is pipeline-paused (${reason || 'scheduler yield'}) — unpausing to deliver feedback for ${issueId}`);\n clearAgentPausedSync(agentId);\n }\n\n if (state.troubled === true || (state.consecutiveFailures ?? 0) > 0) {\n console.warn(\n `[feedback-target] ${agentId} is gated (troubled=${state.troubled === true}, ` +\n `failures=${state.consecutiveFailures ?? 0}) — clearing for one resurrection attempt to ` +\n `deliver ${issueId} feedback; failure tracking re-trips the gate on another crash`,\n );\n clearAgentTroubledSync(agentId);\n }\n\n const { resumeAgent } = await import('../agents/resume.js');\n const result = await resumeAgent(agentId);\n if (!result.success) {\n console.warn(`[feedback-target] Failed to resurrect ${agentId} for ${issueId} feedback: ${result.error}`);\n return false;\n }\n return isLiveSession(agentId);\n } catch (err) {\n console.warn(`[feedback-target] resurrectAgentForFeedback(${agentId}) failed: ${err instanceof Error ? err.message : String(err)}`);\n return false;\n }\n}\n\nexport async function surfaceIssueFeedbackNeedsYou(\n issueId: string,\n reason: string,\n details: Record<string, unknown> = {},\n): Promise<void> {\n try {\n const { markWorkspaceStuck } = await import('../review-status.js');\n markWorkspaceStuck(issueId, 'feedback_delivery_needs_you', {\n reason,\n ...details,\n });\n } catch (err) {\n console.warn(`[feedback-target] Failed to mark ${issueId} as needing human attention: ${err instanceof Error ? err.message : String(err)}`);\n }\n console.warn(`[feedback-target] ${reason}`);\n}\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { n as resolveIssueFeedbackTarget, r as surfaceIssueFeedbackNeedsYou, t as init_feedback_target } from "./feedback-target-oE4-Esxl.js";
1
+ import { n as resolveIssueFeedbackTarget, r as surfaceIssueFeedbackNeedsYou, t as init_feedback_target } from "./feedback-target-dJjFfITP.js";
2
2
  init_feedback_target();
3
3
  export { resolveIssueFeedbackTarget, surfaceIssueFeedbackNeedsYou };
@@ -1,14 +1,14 @@
1
1
  import { a as __toCommonJS } from "./rolldown-runtime-DNCzzKnI.js";
2
2
  import { En as getProjectSwarmHotspots, Nn as init_projects, bn as findProjectByPathSync } from "./config-yaml-DPAieL_G.js";
3
3
  import { _ as FlywheelRunId, t as init_src, v as FlywheelStatus } from "./src-fgbU-jJ-.js";
4
- import { c as init_review_status, s as getReviewStatusSync } from "./review-status-BQjqQXZG.js";
4
+ import { c as init_review_status, s as getReviewStatusSync } from "./review-status-B5ZASOo4.js";
5
5
  import { d as init_agents, u as countAgentsByStatusRole } from "./briefing-freshness-CXhZdnB8.js";
6
- import { An as getAgentDir, K as stopAgent, W as spawnRun, t as init_agents$1 } from "./agents-DHvsjsuP.js";
7
- import { n as init_issue_service_singleton, r as issue_service_singleton_exports } from "./issue-service-singleton-_AquSBTl.js";
6
+ import { An as getAgentDir, K as stopAgent, W as spawnRun, t as init_agents$1 } from "./agents-C7V4odQ6.js";
7
+ import { n as init_issue_service_singleton, r as issue_service_singleton_exports } from "./issue-service-singleton-CDGt__oQ.js";
8
8
  import { o as getInternalTokenSync, s as init_internal_token, t as INTERNAL_TOKEN_HEADER } from "./internal-token-CQUx9YLc.js";
9
9
  import { d as isFlywheelAutoPickupBacklog, f as isFlywheelGloballyPaused, i as getFlywheelActiveRunId, p as isFlywheelRequireUatBeforeMerge, s as init_control_settings, x as setFlywheelGloballyPaused, y as setFlywheelActiveRunId } from "./control-settings-BMqUkXmR.js";
10
- import { n as parseSequenceMd, t as init_sequence_io } from "./sequence-io-B2GmilSI.js";
11
- import { a as declaredIssueFootprint, i as computePredictedConflictSignals, s as pickFromSequence } from "./flywheel-merge-order-CuDcqTRJ.js";
10
+ import { n as parseSequenceMd, t as init_sequence_io } from "./sequence-io-6YP8fVpH.js";
11
+ import { a as declaredIssueFootprint, i as computePredictedConflictSignals, s as pickFromSequence } from "./flywheel-merge-order-B7BH8mZ3.js";
12
12
  import { Effect, Schema } from "effect";
13
13
  import { homedir } from "node:os";
14
14
  import { existsSync, readFileSync, readdirSync } from "node:fs";
@@ -513,4 +513,4 @@ async function resumeFlywheel(options = {}) {
513
513
  //#endregion
514
514
  export { writeLatestFlywheelStatus as S, readCurrentLatestFlywheelStatus as _, pauseFlywheel as a, subscribeLatestFlywheelStatus as b, spawnFlywheelAgent as c, clearFlywheelGate as d, getFlywheelRunDetail as f, nextFlywheelRunId as g, listFlywheelRuns as h, loadResumeSessionId as i, buildClassifyLookups as l, isFlywheelRunId as m, buildFlywheelResumePrompt as n, resumeFlywheel as o, getFlywheelRunDir as p, isFlywheelDevcontainerRuntime as r, saveResumeSessionId as s, FLYWHEEL_ORCHESTRATOR_AGENT_ID as t, abortFlywheelRun as u, readFlywheelLaunchMetadata as v, writeFlywheelLaunchMetadata as x, resolveLiveFlywheelRunId as y };
515
515
 
516
- //# sourceMappingURL=flywheel-ClMjGW_u.js.map
516
+ //# sourceMappingURL=flywheel-BLoVNtJV.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"flywheel-ClMjGW_u.js","names":["decodeFlywheelRunId","stat"],"sources":["../../src/dashboard/server/services/flywheel-run-state.ts","../../src/lib/backlog/lookups.ts","../../src/lib/cloister/flywheel.ts"],"sourcesContent":["import type { Dirent } from 'node:fs';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { mkdir, readdir, readFile, rename, stat, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { Schema } from 'effect';\nimport { FlywheelRunId, FlywheelStatus } from '@overdeck/contracts';\nimport {\n getFlywheelActiveRunId,\n isFlywheelGloballyPaused,\n setFlywheelActiveRunId,\n setFlywheelGloballyPaused,\n} from '../../../lib/overdeck/control-settings.js';\nimport { countAgentsByStatusRole } from '../../../lib/overdeck/agents.js';\n\nexport type FlywheelRunStatus = 'running' | 'paused' | 'complete' | 'aborted';\n\nexport interface FlywheelRunStateOptions {\n overdeckHome?: string;\n}\n\nexport interface FlywheelRunListOptions extends FlywheelRunStateOptions {\n limit?: number;\n}\n\nexport interface FlywheelCurrentStatusOptions extends FlywheelRunStateOptions {\n activeRunId?: string | null;\n}\n\nexport interface FlywheelRunSummary {\n id: string;\n startedAt: string;\n status: FlywheelRunStatus;\n}\n\nexport interface FlywheelRunDetail extends FlywheelRunSummary {\n latest: FlywheelStatus | null;\n paths: {\n latest: string;\n report?: string;\n openedPr?: string;\n };\n}\n\nexport interface FlywheelLaunchMetadata {\n version: 1;\n runId: string;\n workspace: string;\n briefPath: string;\n briefDisplayPath: string;\n}\n\nconst decodeFlywheelStatus = Schema.decodeUnknownSync(FlywheelStatus);\nconst decodeFlywheelRunId = Schema.decodeUnknownSync(FlywheelRunId);\nconst RUN_ID_PATTERN = /^RUN-(\\d+)$/;\nconst DEFAULT_RUNS_LIMIT = 20;\nconst MAX_RUNS_LIMIT = 100;\nconst RUN_SUMMARY_CONCURRENCY = 4;\ntype FlywheelStatusSnapshot = FlywheelStatus | null;\ntype FlywheelStatusListener = (status: FlywheelStatusSnapshot) => void;\nconst flywheelStatusListeners = new Set<FlywheelStatusListener>();\n\nexport function subscribeLatestFlywheelStatus(listener: FlywheelStatusListener): () => void {\n flywheelStatusListeners.add(listener);\n return () => {\n flywheelStatusListeners.delete(listener);\n };\n}\n\nfunction publishLatestFlywheelStatus(status: FlywheelStatusSnapshot): void {\n for (const listener of flywheelStatusListeners) {\n listener(status);\n }\n}\n\nexport function publishFlywheelStatusCleared(): void {\n publishLatestFlywheelStatus(null);\n}\n\nexport function parseFlywheelRunId(runId: string): FlywheelRunId {\n return decodeFlywheelRunId(runId);\n}\n\nexport function isFlywheelRunId(runId: string): runId is FlywheelRunId {\n return RUN_ID_PATTERN.test(runId);\n}\n\nfunction runNumber(runId: string): number {\n const match = RUN_ID_PATTERN.exec(runId);\n return match ? Number(match[1]) : 0;\n}\n\nfunction normalizeLimit(limit: number | undefined): number {\n if (limit === undefined) return DEFAULT_RUNS_LIMIT;\n if (!Number.isFinite(limit) || limit <= 0) return DEFAULT_RUNS_LIMIT;\n return Math.min(Math.floor(limit), MAX_RUNS_LIMIT);\n}\n\nasync function mapWithConcurrency<T, R>(items: readonly T[], concurrency: number, mapper: (item: T) => Promise<R>): Promise<R[]> {\n const results: R[] = new Array(items.length);\n let index = 0;\n await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, async () => {\n while (index < items.length) {\n const current = index;\n index += 1;\n results[current] = await mapper(items[current]!);\n }\n }));\n return results;\n}\n\nexport function getFlywheelHome(options: FlywheelRunStateOptions = {}): string {\n return join(options.overdeckHome ?? process.env['OVERDECK_HOME'] ?? join(homedir(), '.overdeck'), 'flywheel');\n}\n\nexport function getFlywheelRunsDir(options: FlywheelRunStateOptions = {}): string {\n return join(getFlywheelHome(options), 'runs');\n}\n\nexport function getFlywheelRunDir(runId: string, options: FlywheelRunStateOptions = {}): string {\n return join(getFlywheelRunsDir(options), parseFlywheelRunId(runId));\n}\n\n// ─── Run cohort (PAN-2006 WI-7: drain-to-quiescence) ──────────────────────────\n// A Run commits to draining a frozen cohort snapshotted at start: everything\n// in-flight ∪ the auto-pickable issues in the current + next wave. The Run is\n// complete when every cohort member reaches a terminal state; issues picked up\n// mid-run (e.g. unblockers) do NOT extend the cohort.\n\n/** Persist the run's cohort (issue ids) at run start. */\nexport function saveRunCohort(runId: string, issueIds: readonly string[], options: FlywheelRunStateOptions = {}): void {\n const dir = getFlywheelRunDir(runId, options);\n mkdirSync(dir, { recursive: true });\n writeFileSync(join(dir, 'cohort.json'), JSON.stringify({ issueIds: [...issueIds], snapshotAt: new Date().toISOString() }, null, 2), 'utf-8');\n}\n\n/** Load the run's cohort issue ids, or null when no snapshot exists. */\nexport function loadRunCohort(runId: string, options: FlywheelRunStateOptions = {}): string[] | null {\n const path = join(getFlywheelRunDir(runId, options), 'cohort.json');\n if (!existsSync(path)) return null;\n try {\n const parsed = JSON.parse(readFileSync(path, 'utf-8')) as { issueIds?: unknown };\n return Array.isArray(parsed.issueIds) ? parsed.issueIds.filter((x): x is string => typeof x === 'string') : null;\n } catch {\n return null;\n }\n}\n\n/**\n * True when every cohort member is terminal (the Run has drained). Returns false\n * when there is no cohort snapshot or it is empty (nothing to declare drained).\n */\nexport function isCohortDrained(runId: string, isTerminal: (issueId: string) => boolean, options: FlywheelRunStateOptions = {}): boolean {\n const cohort = loadRunCohort(runId, options);\n if (!cohort || cohort.length === 0) return false;\n return cohort.every((id) => isTerminal(id));\n}\n\nexport async function nextFlywheelRunId(options: FlywheelRunStateOptions = {}): Promise<FlywheelRunId> {\n const runsDir = getFlywheelRunsDir(options);\n await mkdir(runsDir, { recursive: true });\n const entries = await readdir(runsDir, { withFileTypes: true });\n const maxRunNumber = entries.reduce((max, entry) => {\n if (!entry.isDirectory()) return max;\n const match = RUN_ID_PATTERN.exec(entry.name);\n if (!match) return max;\n return Math.max(max, Number(match[1]));\n }, 0);\n return parseFlywheelRunId(`RUN-${maxRunNumber + 1}`);\n}\n\nasync function writeJsonAtomic(path: string, payload: unknown): Promise<string> {\n const tmpPath = join(dirname(path), `.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`);\n await mkdir(dirname(path), { recursive: true });\n await writeFile(tmpPath, `${JSON.stringify(payload, null, 2)}\\n`, 'utf8');\n await rename(tmpPath, path);\n return path;\n}\n\nexport async function writeLatestFlywheelStatus(status: FlywheelStatus, options: FlywheelRunStateOptions = {}): Promise<string> {\n const latestPath = join(getFlywheelRunDir(status.runId, options), 'latest.json');\n await writeJsonAtomic(latestPath, status);\n publishLatestFlywheelStatus(status);\n return latestPath;\n}\n\nfunction decodeLaunchMetadata(payload: unknown): FlywheelLaunchMetadata {\n if (typeof payload !== 'object' || payload === null) throw new Error('Invalid Flywheel launch metadata');\n const record = payload as Record<string, unknown>;\n if (record.version !== 1) throw new Error('Invalid Flywheel launch metadata version');\n for (const key of ['runId', 'workspace', 'briefPath', 'briefDisplayPath']) {\n if (typeof record[key] !== 'string' || !record[key]) throw new Error(`Invalid Flywheel launch metadata: ${key}`);\n }\n return record as unknown as FlywheelLaunchMetadata;\n}\n\nexport async function writeFlywheelLaunchMetadata(metadata: FlywheelLaunchMetadata, options: FlywheelRunStateOptions = {}): Promise<string> {\n const runId = parseFlywheelRunId(metadata.runId);\n const launchPath = join(getFlywheelRunDir(runId, options), 'launch.json');\n return writeJsonAtomic(launchPath, { ...metadata, runId });\n}\n\nexport async function readFlywheelLaunchMetadata(runId: string, options: FlywheelRunStateOptions = {}): Promise<FlywheelLaunchMetadata | null> {\n const launchPath = join(getFlywheelRunDir(runId, options), 'launch.json');\n try {\n return decodeLaunchMetadata(JSON.parse(await readFile(launchPath, 'utf8')) as unknown);\n } catch (error) {\n const code = typeof error === 'object' && error !== null && 'code' in error ? error.code : undefined;\n if (code === 'ENOENT') return null;\n throw error;\n }\n}\n\nexport async function readLatestFlywheelStatus(runId: string, options: FlywheelRunStateOptions = {}): Promise<FlywheelStatus | null> {\n const latestPath = join(getFlywheelRunDir(runId, options), 'latest.json');\n try {\n const payload = JSON.parse(await readFile(latestPath, 'utf8')) as unknown;\n return decodeFlywheelStatus(payload);\n } catch (error) {\n const code = typeof error === 'object' && error !== null && 'code' in error ? error.code : undefined;\n if (code === 'ENOENT') return null;\n throw error;\n }\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n const info = await stat(path);\n return info.isFile();\n } catch (error) {\n const code = typeof error === 'object' && error !== null && 'code' in error ? error.code : undefined;\n if (code === 'ENOENT') return false;\n throw error;\n }\n}\n\nasync function deriveRunStatus(runDir: string, runId: string, activeRunId: string | null): Promise<FlywheelRunStatus> {\n if (await fileExists(join(runDir, 'aborted.json'))) return 'aborted';\n if (await fileExists(join(runDir, 'report.md'))) return 'complete';\n // PAN-2108: only the CURRENT active run can be live. A run that is no longer the\n // active run but has no terminal marker was abandoned — its orchestrator died or\n // was killed before writing report.md/aborted.json. It is NOT running; reporting\n // it as such lit the sidebar \"live\" badge for every stale run forever. Treat an\n // orphaned non-active run as aborted.\n if (activeRunId !== runId) return 'aborted';\n return isFlywheelGloballyPaused() ? 'paused' : 'running';\n}\n\nasync function summarizeRun(\n runId: string,\n options: FlywheelRunStateOptions,\n activeRunId: string | null,\n): Promise<FlywheelRunSummary> {\n const runDir = getFlywheelRunDir(runId, options);\n const latest = await readLatestFlywheelStatus(runId, options);\n const status = await deriveRunStatus(runDir, runId, activeRunId);\n return {\n id: runId,\n startedAt: latest?.startedAt ?? '',\n status,\n };\n}\n\nexport async function readCurrentLatestFlywheelStatus(options: FlywheelCurrentStatusOptions = {}): Promise<FlywheelStatus | null> {\n const activeRunId = options.activeRunId === undefined ? getFlywheelActiveRunId() : options.activeRunId;\n if (!activeRunId || !isFlywheelRunId(activeRunId)) return null;\n const activeRun = await getFlywheelRunDetail(activeRunId, options);\n return (activeRun?.status === 'running' || activeRun?.status === 'paused') ? activeRun.latest : null;\n}\n\nfunction selectLatestRunIds(entries: Dirent[], limit: number): string[] {\n const selected: string[] = [];\n for (const entry of entries) {\n if (!entry.isDirectory() || !isFlywheelRunId(entry.name)) continue;\n selected.push(entry.name);\n selected.sort((a, b) => runNumber(b) - runNumber(a));\n if (selected.length > limit) selected.length = limit;\n }\n return selected;\n}\n\nexport async function listFlywheelRuns(options: FlywheelRunListOptions = {}): Promise<FlywheelRunSummary[]> {\n const runsDir = getFlywheelRunsDir(options);\n let entries: Dirent[];\n try {\n entries = await readdir(runsDir, { withFileTypes: true });\n } catch (error) {\n const code = typeof error === 'object' && error !== null && 'code' in error ? error.code : undefined;\n if (code === 'ENOENT') return [];\n throw error;\n }\n const runIds = selectLatestRunIds(entries, normalizeLimit(options.limit));\n const activeRunId = getFlywheelActiveRunId();\n const summaries = await mapWithConcurrency(runIds, RUN_SUMMARY_CONCURRENCY, (runId) => summarizeRun(runId, options, activeRunId));\n return summaries.sort((a, b) => b.startedAt.localeCompare(a.startedAt));\n}\n\n/**\n * PAN-1528/PAN-1908: overlay the flywheel capacity gauge from the indexed\n * agents table. This status path must not enumerate state.json files.\n */\nasync function countLiveWorkAgents(_options: FlywheelRunStateOptions = {}): Promise<number> {\n return countAgentsByStatusRole('running', 'work');\n}\n\nfunction withLiveAgentsActive(latest: FlywheelStatus, liveCount: number): FlywheelStatus {\n if (latest.system.agentsActive === liveCount) return latest;\n return {\n ...latest,\n system: {\n ...latest.system,\n agentsActive: liveCount,\n },\n };\n}\n\nexport async function getFlywheelRunDetail(runId: string, options: FlywheelCurrentStatusOptions = {}): Promise<FlywheelRunDetail | null> {\n const runDir = getFlywheelRunDir(runId, options);\n const latest = await readLatestFlywheelStatus(runId, options);\n if (!latest) return null;\n const activeRunId = options.activeRunId !== undefined ? options.activeRunId : getFlywheelActiveRunId();\n const status = await deriveRunStatus(runDir, runId, activeRunId);\n const reportPath = join(runDir, 'report.md');\n const openedPrPath = join(runDir, 'opened-pr.json');\n // PAN-1528: overlay the live work-agent count so the field reflects reality\n // rather than the orchestrator's stale initial value.\n const liveCount = await countLiveWorkAgents(options);\n return {\n id: runId,\n startedAt: latest.startedAt,\n status,\n latest: withLiveAgentsActive(latest, liveCount),\n paths: {\n latest: join(runDir, 'latest.json'),\n ...((await fileExists(reportPath)) ? { report: reportPath } : {}),\n ...((await fileExists(openedPrPath)) ? { openedPr: openedPrPath } : {}),\n },\n };\n}\n\n// Clear the SQLite \"active run\" gate and the pause flag, and notify subscribers.\n// Exported so callers in CLI and dashboard share a single clearing primitive\n// (PAN-1245: gate previously cleared in three different places that drifted).\nexport function clearFlywheelGate(): void {\n setFlywheelActiveRunId(null);\n setFlywheelGloballyPaused(false);\n publishFlywheelStatusCleared();\n}\n\n// Single source of truth for \"is a flywheel run live?\". Reads the SQLite gate,\n// validates it against on-disk run state, and self-heals if the gate points at\n// a run that has already ended (report.md / aborted.json present), at a run\n// whose state was wiped, or at a malformed value. Both `pan flywheel start`\n// and the dashboard Start path consult this — they cannot disagree (PAN-1245).\nexport async function resolveLiveFlywheelRunId(options: FlywheelRunStateOptions = {}): Promise<string | null> {\n const candidate = getFlywheelActiveRunId();\n if (!candidate) return null;\n if (!isFlywheelRunId(candidate)) {\n clearFlywheelGate();\n return null;\n }\n const latest = await readLatestFlywheelStatus(candidate, options);\n if (!latest) {\n // The gate points at a run with no snapshot on disk — the run dir was\n // wiped or never fully initialized. Treat as dead.\n clearFlywheelGate();\n return null;\n }\n const runDir = getFlywheelRunDir(candidate, options);\n // `candidate` is the active run id (read above), so pass it as activeRunId.\n const status = await deriveRunStatus(runDir, candidate, candidate);\n if (status === 'complete' || status === 'aborted') {\n clearFlywheelGate();\n return null;\n }\n return candidate;\n}\n\n// Mark a flywheel run as aborted and clear the gate if it still points at this\n// run. Writes `aborted.json` so `deriveRunStatus` reports the run as aborted on\n// subsequent reads, mirroring the report.md → complete convention.\nexport async function abortFlywheelRun(runId: string, options: FlywheelRunStateOptions = {}): Promise<void> {\n const parsed = parseFlywheelRunId(runId);\n const abortedPath = join(getFlywheelRunDir(parsed, options), 'aborted.json');\n await writeJsonAtomic(abortedPath, { runId: parsed, abortedAt: new Date().toISOString() });\n if (getFlywheelActiveRunId() === parsed) {\n clearFlywheelGate();\n }\n}\n","import { existsSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { getReviewStatusSync } from '../review-status.js';\nimport type { ClassifyLookups } from './pickup.js';\n\n/**\n * Build the {@link ClassifyLookups} the shared pickup module needs from live project\n * state: labels (in-memory issue service), planned (vBRIEF spec + beads), and\n * in-pipeline (review status / live workspace). Shared by the dashboard forecast\n * route and the Flywheel run-cohort snapshot so both classify issues identically\n * (PAN-2006 single source of truth). The issue service is lazy-required to avoid a\n * static lib → dashboard layering edge.\n */\nexport function buildClassifyLookups(\n projectRoot: string,\n opts?: { labels?: (id: string) => readonly string[] },\n): ClassifyLookups {\n // Labels come from the in-memory issue service (server-side). A CLI/sandbox process cannot\n // reach that singleton, so callers there must pass `opts.labels` (e.g. gh-derived) — without\n // it, a CLI would silently classify every issue as label-less, making ready/released/parked/\n // objection/vetoed/blocksMain all false (the `pan backlog forecast` undercount bug).\n const labelsByIssue = new Map<string, string[]>();\n if (!opts?.labels) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { getSharedIssueService } = require('../../dashboard/server/services/issue-service-singleton.js') as typeof import('../../dashboard/server/services/issue-service-singleton.js');\n for (const issue of getSharedIssueService().getIssues() as Array<Record<string, unknown>>) {\n const id = typeof issue['identifier'] === 'string' ? issue['identifier'].toUpperCase() : '';\n if (!id) continue;\n const raw = Array.isArray(issue['labels']) ? (issue['labels'] as unknown[]) : [];\n const names = raw\n .map((l) => (typeof l === 'string' ? l : ((l as { name?: string })?.name ?? '')))\n .filter((s): s is string => Boolean(s));\n labelsByIssue.set(id, names);\n }\n } catch { /* issue service not ready — treat as no labels */ }\n }\n\n const specsDir = join(projectRoot, '.pan', 'specs');\n const specIssues = new Set<string>();\n if (existsSync(specsDir)) {\n for (const f of readdirSync(specsDir)) {\n const m = /^[\\d-]+-([A-Z]+-\\d+)-/i.exec(f);\n if (m) specIssues.add(m[1]!.toUpperCase());\n }\n }\n const workspacesDir = join(projectRoot, 'workspaces');\n const beadsIssues = new Set<string>();\n if (existsSync(workspacesDir)) {\n for (const dir of readdirSync(workspacesDir)) {\n const m = /^feature-([a-z]+-\\d+)$/i.exec(dir);\n if (m && existsSync(join(workspacesDir, dir, '.beads', 'issues.jsonl'))) beadsIssues.add(m[1]!.toUpperCase());\n }\n }\n\n return {\n labels: opts?.labels ?? ((id) => labelsByIssue.get(id.toUpperCase()) ?? []),\n isPlanned: (id) => {\n const u = id.toUpperCase();\n return specIssues.has(u) && beadsIssues.has(u);\n },\n isInPipeline: (id) => {\n const u = id.toUpperCase();\n const rs = getReviewStatusSync(u);\n return (rs !== null && rs.reviewStatus !== 'pending') || existsSync(join(workspacesDir, `feature-${id.toLowerCase()}`));\n },\n };\n}\n","import { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { Effect, Schema } from 'effect';\nimport type { FlywheelRunId } from '@overdeck/contracts';\nimport type { AgentState } from '../agents.js';\nimport type { FlywheelScope, RoleEffort } from '../config-yaml.js';\nimport { getInternalTokenSync, INTERNAL_TOKEN_HEADER } from '../internal-token.js';\nimport { getAgentDir, spawnRun, stopAgent } from '../agents.js';\nimport { parseSequenceMd } from '../backlog/sequence-io.js';\nimport { computePredictedConflictSignals, declaredIssueFootprint, pickFromSequence, type IssueFileFootprint } from '../flywheel-merge-order.js';\nimport { findProjectByPathSync, getProjectSwarmHotspots } from '../projects.js';\nimport type { VBriefDocument } from '../vbrief/types.js';\nimport {\n getFlywheelActiveRunId,\n isFlywheelAutoPickupBacklog,\n isFlywheelRequireUatBeforeMerge,\n setFlywheelActiveRunId,\n setFlywheelGloballyPaused,\n} from '../overdeck/control-settings.js';\nimport { resolveLiveFlywheelRunId, saveRunCohort } from '../../dashboard/server/services/flywheel-run-state.js';\nimport { buildClassifyLookups } from '../backlog/lookups.js';\nimport { computeCohort } from '../backlog/pickup.js';\n\nexport const FLYWHEEL_ORCHESTRATOR_AGENT_ID = 'flywheel-orchestrator';\n\nconst FlywheelRunIdSchema = Schema.String.check(Schema.isPattern(/^RUN-\\d+$/));\nconst decodeFlywheelRunId = Schema.decodeUnknownSync(FlywheelRunIdSchema);\n\nexport interface FlywheelLifecycleOptions {\n runId?: FlywheelRunId;\n workspace?: string;\n briefPath?: string;\n prompt?: string;\n model?: string;\n harness?: 'claude-code' | 'ohmypi' | 'codex';\n effort?: RoleEffort;\n minAgents?: number;\n maxAgents?: number;\n scope?: FlywheelScope;\n autoPickupBacklog?: boolean;\n requireUatBeforeMerge?: boolean;\n env?: NodeJS.ProcessEnv;\n resumeSessionId?: string;\n}\n\nexport interface FlywheelPauseResult {\n activeRunId: string | null;\n}\n\nexport interface FlywheelResumeResult {\n activeRunId: string;\n agent: AgentState;\n}\n\nfunction parseRunId(runId: string): FlywheelRunId {\n return decodeFlywheelRunId(runId);\n}\n\nfunction defaultFlywheelRunId(): FlywheelRunId {\n return parseRunId(`RUN-${Date.now()}`);\n}\n\nfunction internalDashboardOrigin(): string {\n const port = Number.parseInt(process.env['API_PORT'] ?? process.env['PORT'] ?? '3011', 10);\n return process.env['OVERDECK_INTERNAL_DASHBOARD_URL'] ?? `http://127.0.0.1:${port}`;\n}\n\nasync function fetchIssueRowsFromDashboard(): Promise<Array<{ ref?: string; identifier?: string; labels?: string[]; author?: string; assignee?: { name?: string } | string }>> {\n const dashboardOrigin = internalDashboardOrigin();\n const token = getInternalTokenSync();\n if (!token) {\n console.error('[flywheel] Cannot load issue metadata: internal dashboard token is unavailable');\n return [];\n }\n try {\n const response = await fetch(new URL('/api/issues?cycle=all&includeCompleted=true', dashboardOrigin), {\n headers: {\n [INTERNAL_TOKEN_HEADER]: token,\n origin: dashboardOrigin,\n },\n });\n if (!response.ok) {\n console.error(`[flywheel] Cannot load issue metadata from dashboard: HTTP ${response.status}`);\n return [];\n }\n const body = await response.json();\n if (!Array.isArray(body)) {\n console.error('[flywheel] Cannot load issue metadata from dashboard: response was not an array');\n return [];\n }\n return body as Array<{ ref?: string; identifier?: string; labels?: string[]; author?: string; assignee?: { name?: string } | string }>;\n } catch (error) {\n console.error('[flywheel] Cannot load issue metadata from dashboard:', error);\n return [];\n }\n}\n\nasync function flywheelRunConfigurationSection(options: FlywheelLifecycleOptions): Promise<string> {\n const configLines = [\n options.harness ? `Harness: ${options.harness}` : undefined,\n options.effort ? `Effort: ${options.effort}` : undefined,\n options.minAgents ? `Min concurrent agents (target): ${options.minAgents}` : undefined,\n options.maxAgents ? `Max concurrent agents (ceiling): ${options.maxAgents}` : undefined,\n options.scope ? `Scope: ${options.scope}` : undefined,\n typeof options.autoPickupBacklog === 'boolean'\n ? `Auto-pickup backlog: ${options.autoPickupBacklog}`\n : undefined,\n typeof options.requireUatBeforeMerge === 'boolean'\n ? `Require UAT before merge: ${options.requireUatBeforeMerge}`\n : undefined,\n ].filter(Boolean).join('\\n');\n\n let sequenceSection = '';\n if (options.autoPickupBacklog) {\n const seqPath = join(process.cwd(), '.pan', 'backlog', 'sequence.md');\n if (existsSync(seqPath)) {\n try {\n const md = readFileSync(seqPath, 'utf-8');\n const parsed = parseSequenceMd(md);\n if (parsed.ok) {\n // Build issue lookups through the dashboard read path. A deacon child\n // cannot safely import the dashboard's per-process issue singleton.\n type IssueRow = { ref?: string; identifier?: string; labels?: string[]; author?: string; assignee?: { name?: string } | string };\n const getIssueRows = async (): Promise<IssueRow[]> => fetchIssueRowsFromDashboard();\n const issueRowMap = new Map<string, IssueRow>(\n (await getIssueRows()).map((i) => [i.ref ?? i.identifier ?? '', i]),\n );\n\n const issueLabelsLookup = (issueId: string): string[] =>\n issueRowMap.get(issueId)?.labels ?? [];\n\n const AUTHORIZED_AUTHORS = new Set(['eltmon', 'panopticon-agent[bot]']);\n const isAuthorizedIssue = (issueId: string): boolean => {\n const row = issueRowMap.get(issueId);\n if (!row) return false; // unknown issue — skip (safe default)\n if (row.author && AUTHORIZED_AUTHORS.has(row.author)) return true;\n const assigneeName = typeof row.assignee === 'string' ? row.assignee : row.assignee?.name;\n return assigneeName === 'eltmon';\n };\n\n const projectRoot = process.cwd();\n const specsDir = join(projectRoot, '.pan', 'specs');\n const workspacesDir = join(projectRoot, 'workspaces');\n const issuesWithSpecs = new Set<string>();\n const declaredFootprints: IssueFileFootprint[] = [];\n if (existsSync(specsDir)) {\n for (const f of readdirSync(specsDir)) {\n const match = /^[\\d-]+-([A-Z]+-\\d+)-/i.exec(f);\n if (!match) continue;\n const issueId = match[1]!.toUpperCase();\n issuesWithSpecs.add(issueId);\n try {\n const doc = JSON.parse(readFileSync(join(specsDir, f), 'utf-8')) as VBriefDocument;\n declaredFootprints.push(declaredIssueFootprint(issueId, doc));\n } catch {\n // A malformed spec should not break flywheel startup; planned-ness\n // still comes from the filename and the normal plan gate handles parse errors.\n }\n }\n }\n const predictedConflictSignals = computePredictedConflictSignals(declaredFootprints, {\n hotspots: getProjectSwarmHotspots(findProjectByPathSync(projectRoot)),\n });\n const isReadyOrHasPrd = (issueId: string): boolean => {\n const id = issueId.toUpperCase();\n // ready = spec AND beads exist in the workspace\n if (issuesWithSpecs.has(id) &&\n existsSync(join(workspacesDir, `feature-${id.toLowerCase()}`, '.beads', 'issues.jsonl'))) {\n return true;\n }\n return existsSync(join(projectRoot, '.pan', 'drafts', `${id}.md`));\n };\n const isInPipeline = (issueId: string): boolean =>\n existsSync(join(workspacesDir, `feature-${issueId.toLowerCase()}`));\n\n const top10 = parsed.doc.nodes.slice(0, 10).map((n) =>\n ` #${n.rank} ${n.issue}: ${n.why.slice(0, 100)} [gate:${n.gate}]`,\n );\n const nextPick = pickFromSequence(parsed.doc.nodes, { issueLabels: issueLabelsLookup, isAuthorizedIssue, isReadyOrHasPrd, isInPipeline, requireReady: true, autoPickupBacklog: options.autoPickupBacklog, predictedConflictSignals });\n let nextLine: string;\n let pickInstruction: string;\n if (!nextPick) {\n nextLine = 'No eligible issue found in sequence — fall back to normal priority';\n pickInstruction = '';\n } else if (nextPick.planning === 'interactive') {\n // FR-17: interactive planning requires operator presence — must NOT be auto-started\n nextLine = `NEEDS OPERATOR ACTION: ${nextPick.issueId} (rank ${nextPick.rank}) has planning=interactive — do NOT auto-start; operator must run 'pan plan ${nextPick.issueId}'`;\n pickInstruction = `\\n\\nIMPORTANT: auto_pickup_backlog=true. The top-ranked issue requires interactive planning and MUST NOT be auto-started. Surface it to the operator for manual 'pan plan' invocation instead of auto-picking it.`;\n } else {\n const conflictSuffix = typeof nextPick.predictedConflictCount === 'number'\n ? `, predictedConflicts=${nextPick.predictedConflictCount}${nextPick.predictedConflictsWith?.length ? ` with ${nextPick.predictedConflictsWith.join(', ')}` : ''}`\n : '';\n nextLine = `MUST start next: ${nextPick.issueId} (rank ${nextPick.rank}, planning=${nextPick.planning}${conflictSuffix})`;\n pickInstruction = `\\n\\nIMPORTANT: auto_pickup_backlog=true. You MUST pick the \"MUST start next\" issue above as your next startup target. Do NOT apply your own P0-P3/oldest-first ranking while a sequence is available.`;\n }\n sequenceSection = `\\n\\nBacklog sequence (${parsed.doc.nodes.length} issues ranked):\\n${top10.join('\\n')}\\n${nextLine}${pickInstruction}`;\n }\n } catch {\n // sequence.md exists but couldn't be parsed — skip enrichment\n }\n }\n }\n\n return (configLines ? `\\n\\nRun configuration:\\n${configLines}` : '') + sequenceSection;\n}\n\nasync function defaultFlywheelPrompt(runId: string, options: FlywheelLifecycleOptions, briefContent?: string): Promise<string> {\n const configSection = await flywheelRunConfigurationSection(options);\n const briefSection = options.briefPath\n ? `\\n\\nBrief path: ${options.briefPath}\\n\\n${briefContent ?? ''}`\n : '';\n return `FLYWHEEL ORCHESTRATOR TASK for ${runId}:\n\nRun the Fix-All Flywheel loop. Keep status snapshots current, coordinate Overdeck roles through the normal pipeline surfaces, respect the configured run scope and agent cap, and wait for explicit lifecycle instructions when the run is paused or complete.${configSection}${briefSection}`;\n}\n\nfunction getLocalFlywheelRunDir(runId: string): string {\n const overdeckHome = process.env.OVERDECK_HOME ?? join(homedir(), '.overdeck');\n return join(overdeckHome, 'flywheel', 'runs', runId);\n}\n\nexport async function saveResumeSessionId(runId: string, sessionId: string): Promise<void> {\n const runDir = getLocalFlywheelRunDir(runId);\n await mkdir(runDir, { recursive: true });\n await writeFile(\n join(runDir, 'resume-session.json'),\n JSON.stringify({ sessionId, pausedAt: new Date().toISOString() }),\n 'utf-8',\n );\n}\n\nexport async function loadResumeSessionId(runId: string): Promise<string | null> {\n try {\n const raw = await readFile(join(getLocalFlywheelRunDir(runId), 'resume-session.json'), 'utf-8');\n const parsed = JSON.parse(raw) as { sessionId?: unknown };\n return typeof parsed.sessionId === 'string' ? parsed.sessionId : null;\n } catch {\n return null;\n }\n}\n\nexport function isFlywheelDevcontainerRuntime(env: NodeJS.ProcessEnv = process.env): boolean {\n const disabledDeacon = env.OVERDECK_DISABLE_DEACON?.toLowerCase();\n if (disabledDeacon === '1' || disabledDeacon === 'true') return true;\n\n const hostname = env.HOSTNAME?.toLowerCase() ?? '';\n return hostname.includes('devcontainer') || hostname.startsWith('api-feature-') || hostname.startsWith('workspace-');\n}\n\n/**\n * Resume prompt. PAN-2006 FR-8: re-attach the standing brief on resume so its\n * directives (pipeline-unblock override, never-block, red-main-first) survive a\n * resume + context compaction — the pre-PAN-2006 resume prompt only pointed at\n * FLYWHEEL-STATE.md and a long-running orchestrator could drift off-brief.\n */\nexport function buildFlywheelResumePrompt(configSection: string, briefContent?: string): string {\n const base =\n 'FLYWHEEL RESUME: You were paused by the operator. Resume the tick loop from your prior ' +\n 'state. Check `docs/FLYWHEEL-STATE.md` and the latest status snapshot for context.';\n const brief = briefContent\n ? `\\n\\n--- Standing brief (re-read it — it governs pickup, unblocking, and never-block) ---\\n\\n${briefContent}`\n : '';\n return `${base}${configSection}${brief}`;\n}\n\nexport async function spawnFlywheelAgent(runId: string, options: FlywheelLifecycleOptions = {}): Promise<AgentState> {\n const workspace = options.workspace ?? process.cwd();\n // Re-read the brief on every spawn (fresh AND resume) so its directives survive\n // resume/compaction. Default to the standard brief path when none is supplied.\n const briefPath = options.briefPath ?? join(workspace, 'docs', 'flywheel-brief.md');\n const briefContent = await readFile(briefPath, 'utf8').catch(() => undefined);\n const prompt = options.resumeSessionId\n ? buildFlywheelResumePrompt(await flywheelRunConfigurationSection(options), briefContent)\n : (options.prompt ?? (await defaultFlywheelPrompt(runId, options, briefContent)));\n return spawnRun(runId, 'flywheel', {\n agentId: FLYWHEEL_ORCHESTRATOR_AGENT_ID,\n workspace,\n prompt,\n model: options.model,\n harness: options.harness,\n effort: options.effort,\n allowHost: true,\n registerConversation: true,\n resumeSessionId: options.resumeSessionId,\n flywheelRunId: runId,\n });\n}\n\nfunction withFlywheelAutonomyOptions(options: FlywheelLifecycleOptions): FlywheelLifecycleOptions {\n return {\n ...options,\n autoPickupBacklog: options.autoPickupBacklog ?? isFlywheelAutoPickupBacklog(),\n requireUatBeforeMerge: options.requireUatBeforeMerge ?? isFlywheelRequireUatBeforeMerge(),\n };\n}\n\nexport async function spawnFlywheel(options: FlywheelLifecycleOptions = {}): Promise<AgentState> {\n if (isFlywheelDevcontainerRuntime(options.env)) {\n throw new Error('Refusing to spawn flywheel-orchestrator inside a workspace devcontainer');\n }\n\n // Self-healing gate check (PAN-1245): if the SQLite gate points at a run\n // that has already ended (report.md/aborted.json) or whose on-disk state is\n // gone (post-reboot, post-wipe), resolveLiveFlywheelRunId clears the gate\n // and returns null. Only a genuinely live prior run blocks a new start.\n const activeRunId = await resolveLiveFlywheelRunId();\n if (activeRunId) {\n throw new Error(`Flywheel run ${activeRunId} is already active; pause, resume, or report it before starting another run`);\n }\n\n const runId = options.runId ? parseRunId(options.runId) : defaultFlywheelRunId();\n const agent = await spawnFlywheelAgent(runId, withFlywheelAutonomyOptions(options));\n setFlywheelActiveRunId(runId);\n setFlywheelGloballyPaused(false);\n\n // PAN-2006 WI-7: freeze the run's cohort (in-flight ∪ current+next wave) at start.\n // The Run is complete once this cohort drains; mid-run pickups don't extend it.\n // Best-effort — a missing/unparseable sequence just means no cohort gate yet.\n try {\n const workspace = options.workspace ?? process.cwd();\n const seqPath = join(workspace, '.pan', 'backlog', 'sequence.md');\n if (existsSync(seqPath)) {\n const parsed = parseSequenceMd(readFileSync(seqPath, 'utf-8'));\n if (parsed.ok) {\n saveRunCohort(runId, computeCohort(parsed.doc.nodes, buildClassifyLookups(workspace), options.maxAgents ?? 5, options.autoPickupBacklog ?? isFlywheelAutoPickupBacklog()));\n }\n }\n } catch { /* cohort snapshot is best-effort */ }\n\n return agent;\n}\n\nexport async function pauseFlywheel(): Promise<FlywheelPauseResult> {\n const activeRunId = getFlywheelActiveRunId();\n if (activeRunId) {\n try {\n const sessionId = (await readFile(join(getAgentDir(FLYWHEEL_ORCHESTRATOR_AGENT_ID), 'session.id'), 'utf-8')).trim();\n if (sessionId) await saveResumeSessionId(activeRunId, sessionId);\n } catch { /* non-fatal: resume falls back to fresh if session.id is missing */ }\n }\n setFlywheelGloballyPaused(true);\n await Effect.runPromise(stopAgent(FLYWHEEL_ORCHESTRATOR_AGENT_ID));\n return { activeRunId };\n}\n\nexport async function resumeFlywheel(options: FlywheelLifecycleOptions = {}): Promise<FlywheelResumeResult> {\n if (isFlywheelDevcontainerRuntime(options.env)) {\n throw new Error('Refusing to resume flywheel-orchestrator inside a workspace devcontainer');\n }\n\n const activeRunId = getFlywheelActiveRunId();\n if (!activeRunId) {\n throw new Error('No active flywheel run to resume');\n }\n const runId = parseRunId(activeRunId);\n\n const resumeSessionId = options.resumeSessionId ?? await loadResumeSessionId(runId) ?? undefined;\n const agent = await spawnFlywheelAgent(runId, withFlywheelAutonomyOptions({ ...options, resumeSessionId }));\n setFlywheelGloballyPaused(false);\n return { activeRunId, agent };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"flywheel-BLoVNtJV.js","names":["decodeFlywheelRunId","stat"],"sources":["../../src/dashboard/server/services/flywheel-run-state.ts","../../src/lib/backlog/lookups.ts","../../src/lib/cloister/flywheel.ts"],"sourcesContent":["import type { Dirent } from 'node:fs';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { mkdir, readdir, readFile, rename, stat, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { Schema } from 'effect';\nimport { FlywheelRunId, FlywheelStatus } from '@overdeck/contracts';\nimport {\n getFlywheelActiveRunId,\n isFlywheelGloballyPaused,\n setFlywheelActiveRunId,\n setFlywheelGloballyPaused,\n} from '../../../lib/overdeck/control-settings.js';\nimport { countAgentsByStatusRole } from '../../../lib/overdeck/agents.js';\n\nexport type FlywheelRunStatus = 'running' | 'paused' | 'complete' | 'aborted';\n\nexport interface FlywheelRunStateOptions {\n overdeckHome?: string;\n}\n\nexport interface FlywheelRunListOptions extends FlywheelRunStateOptions {\n limit?: number;\n}\n\nexport interface FlywheelCurrentStatusOptions extends FlywheelRunStateOptions {\n activeRunId?: string | null;\n}\n\nexport interface FlywheelRunSummary {\n id: string;\n startedAt: string;\n status: FlywheelRunStatus;\n}\n\nexport interface FlywheelRunDetail extends FlywheelRunSummary {\n latest: FlywheelStatus | null;\n paths: {\n latest: string;\n report?: string;\n openedPr?: string;\n };\n}\n\nexport interface FlywheelLaunchMetadata {\n version: 1;\n runId: string;\n workspace: string;\n briefPath: string;\n briefDisplayPath: string;\n}\n\nconst decodeFlywheelStatus = Schema.decodeUnknownSync(FlywheelStatus);\nconst decodeFlywheelRunId = Schema.decodeUnknownSync(FlywheelRunId);\nconst RUN_ID_PATTERN = /^RUN-(\\d+)$/;\nconst DEFAULT_RUNS_LIMIT = 20;\nconst MAX_RUNS_LIMIT = 100;\nconst RUN_SUMMARY_CONCURRENCY = 4;\ntype FlywheelStatusSnapshot = FlywheelStatus | null;\ntype FlywheelStatusListener = (status: FlywheelStatusSnapshot) => void;\nconst flywheelStatusListeners = new Set<FlywheelStatusListener>();\n\nexport function subscribeLatestFlywheelStatus(listener: FlywheelStatusListener): () => void {\n flywheelStatusListeners.add(listener);\n return () => {\n flywheelStatusListeners.delete(listener);\n };\n}\n\nfunction publishLatestFlywheelStatus(status: FlywheelStatusSnapshot): void {\n for (const listener of flywheelStatusListeners) {\n listener(status);\n }\n}\n\nexport function publishFlywheelStatusCleared(): void {\n publishLatestFlywheelStatus(null);\n}\n\nexport function parseFlywheelRunId(runId: string): FlywheelRunId {\n return decodeFlywheelRunId(runId);\n}\n\nexport function isFlywheelRunId(runId: string): runId is FlywheelRunId {\n return RUN_ID_PATTERN.test(runId);\n}\n\nfunction runNumber(runId: string): number {\n const match = RUN_ID_PATTERN.exec(runId);\n return match ? Number(match[1]) : 0;\n}\n\nfunction normalizeLimit(limit: number | undefined): number {\n if (limit === undefined) return DEFAULT_RUNS_LIMIT;\n if (!Number.isFinite(limit) || limit <= 0) return DEFAULT_RUNS_LIMIT;\n return Math.min(Math.floor(limit), MAX_RUNS_LIMIT);\n}\n\nasync function mapWithConcurrency<T, R>(items: readonly T[], concurrency: number, mapper: (item: T) => Promise<R>): Promise<R[]> {\n const results: R[] = new Array(items.length);\n let index = 0;\n await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, async () => {\n while (index < items.length) {\n const current = index;\n index += 1;\n results[current] = await mapper(items[current]!);\n }\n }));\n return results;\n}\n\nexport function getFlywheelHome(options: FlywheelRunStateOptions = {}): string {\n return join(options.overdeckHome ?? process.env['OVERDECK_HOME'] ?? join(homedir(), '.overdeck'), 'flywheel');\n}\n\nexport function getFlywheelRunsDir(options: FlywheelRunStateOptions = {}): string {\n return join(getFlywheelHome(options), 'runs');\n}\n\nexport function getFlywheelRunDir(runId: string, options: FlywheelRunStateOptions = {}): string {\n return join(getFlywheelRunsDir(options), parseFlywheelRunId(runId));\n}\n\n// ─── Run cohort (PAN-2006 WI-7: drain-to-quiescence) ──────────────────────────\n// A Run commits to draining a frozen cohort snapshotted at start: everything\n// in-flight ∪ the auto-pickable issues in the current + next wave. The Run is\n// complete when every cohort member reaches a terminal state; issues picked up\n// mid-run (e.g. unblockers) do NOT extend the cohort.\n\n/** Persist the run's cohort (issue ids) at run start. */\nexport function saveRunCohort(runId: string, issueIds: readonly string[], options: FlywheelRunStateOptions = {}): void {\n const dir = getFlywheelRunDir(runId, options);\n mkdirSync(dir, { recursive: true });\n writeFileSync(join(dir, 'cohort.json'), JSON.stringify({ issueIds: [...issueIds], snapshotAt: new Date().toISOString() }, null, 2), 'utf-8');\n}\n\n/** Load the run's cohort issue ids, or null when no snapshot exists. */\nexport function loadRunCohort(runId: string, options: FlywheelRunStateOptions = {}): string[] | null {\n const path = join(getFlywheelRunDir(runId, options), 'cohort.json');\n if (!existsSync(path)) return null;\n try {\n const parsed = JSON.parse(readFileSync(path, 'utf-8')) as { issueIds?: unknown };\n return Array.isArray(parsed.issueIds) ? parsed.issueIds.filter((x): x is string => typeof x === 'string') : null;\n } catch {\n return null;\n }\n}\n\n/**\n * True when every cohort member is terminal (the Run has drained). Returns false\n * when there is no cohort snapshot or it is empty (nothing to declare drained).\n */\nexport function isCohortDrained(runId: string, isTerminal: (issueId: string) => boolean, options: FlywheelRunStateOptions = {}): boolean {\n const cohort = loadRunCohort(runId, options);\n if (!cohort || cohort.length === 0) return false;\n return cohort.every((id) => isTerminal(id));\n}\n\nexport async function nextFlywheelRunId(options: FlywheelRunStateOptions = {}): Promise<FlywheelRunId> {\n const runsDir = getFlywheelRunsDir(options);\n await mkdir(runsDir, { recursive: true });\n const entries = await readdir(runsDir, { withFileTypes: true });\n const maxRunNumber = entries.reduce((max, entry) => {\n if (!entry.isDirectory()) return max;\n const match = RUN_ID_PATTERN.exec(entry.name);\n if (!match) return max;\n return Math.max(max, Number(match[1]));\n }, 0);\n return parseFlywheelRunId(`RUN-${maxRunNumber + 1}`);\n}\n\nasync function writeJsonAtomic(path: string, payload: unknown): Promise<string> {\n const tmpPath = join(dirname(path), `.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`);\n await mkdir(dirname(path), { recursive: true });\n await writeFile(tmpPath, `${JSON.stringify(payload, null, 2)}\\n`, 'utf8');\n await rename(tmpPath, path);\n return path;\n}\n\nexport async function writeLatestFlywheelStatus(status: FlywheelStatus, options: FlywheelRunStateOptions = {}): Promise<string> {\n const latestPath = join(getFlywheelRunDir(status.runId, options), 'latest.json');\n await writeJsonAtomic(latestPath, status);\n publishLatestFlywheelStatus(status);\n return latestPath;\n}\n\nfunction decodeLaunchMetadata(payload: unknown): FlywheelLaunchMetadata {\n if (typeof payload !== 'object' || payload === null) throw new Error('Invalid Flywheel launch metadata');\n const record = payload as Record<string, unknown>;\n if (record.version !== 1) throw new Error('Invalid Flywheel launch metadata version');\n for (const key of ['runId', 'workspace', 'briefPath', 'briefDisplayPath']) {\n if (typeof record[key] !== 'string' || !record[key]) throw new Error(`Invalid Flywheel launch metadata: ${key}`);\n }\n return record as unknown as FlywheelLaunchMetadata;\n}\n\nexport async function writeFlywheelLaunchMetadata(metadata: FlywheelLaunchMetadata, options: FlywheelRunStateOptions = {}): Promise<string> {\n const runId = parseFlywheelRunId(metadata.runId);\n const launchPath = join(getFlywheelRunDir(runId, options), 'launch.json');\n return writeJsonAtomic(launchPath, { ...metadata, runId });\n}\n\nexport async function readFlywheelLaunchMetadata(runId: string, options: FlywheelRunStateOptions = {}): Promise<FlywheelLaunchMetadata | null> {\n const launchPath = join(getFlywheelRunDir(runId, options), 'launch.json');\n try {\n return decodeLaunchMetadata(JSON.parse(await readFile(launchPath, 'utf8')) as unknown);\n } catch (error) {\n const code = typeof error === 'object' && error !== null && 'code' in error ? error.code : undefined;\n if (code === 'ENOENT') return null;\n throw error;\n }\n}\n\nexport async function readLatestFlywheelStatus(runId: string, options: FlywheelRunStateOptions = {}): Promise<FlywheelStatus | null> {\n const latestPath = join(getFlywheelRunDir(runId, options), 'latest.json');\n try {\n const payload = JSON.parse(await readFile(latestPath, 'utf8')) as unknown;\n return decodeFlywheelStatus(payload);\n } catch (error) {\n const code = typeof error === 'object' && error !== null && 'code' in error ? error.code : undefined;\n if (code === 'ENOENT') return null;\n throw error;\n }\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n const info = await stat(path);\n return info.isFile();\n } catch (error) {\n const code = typeof error === 'object' && error !== null && 'code' in error ? error.code : undefined;\n if (code === 'ENOENT') return false;\n throw error;\n }\n}\n\nasync function deriveRunStatus(runDir: string, runId: string, activeRunId: string | null): Promise<FlywheelRunStatus> {\n if (await fileExists(join(runDir, 'aborted.json'))) return 'aborted';\n if (await fileExists(join(runDir, 'report.md'))) return 'complete';\n // PAN-2108: only the CURRENT active run can be live. A run that is no longer the\n // active run but has no terminal marker was abandoned — its orchestrator died or\n // was killed before writing report.md/aborted.json. It is NOT running; reporting\n // it as such lit the sidebar \"live\" badge for every stale run forever. Treat an\n // orphaned non-active run as aborted.\n if (activeRunId !== runId) return 'aborted';\n return isFlywheelGloballyPaused() ? 'paused' : 'running';\n}\n\nasync function summarizeRun(\n runId: string,\n options: FlywheelRunStateOptions,\n activeRunId: string | null,\n): Promise<FlywheelRunSummary> {\n const runDir = getFlywheelRunDir(runId, options);\n const latest = await readLatestFlywheelStatus(runId, options);\n const status = await deriveRunStatus(runDir, runId, activeRunId);\n return {\n id: runId,\n startedAt: latest?.startedAt ?? '',\n status,\n };\n}\n\nexport async function readCurrentLatestFlywheelStatus(options: FlywheelCurrentStatusOptions = {}): Promise<FlywheelStatus | null> {\n const activeRunId = options.activeRunId === undefined ? getFlywheelActiveRunId() : options.activeRunId;\n if (!activeRunId || !isFlywheelRunId(activeRunId)) return null;\n const activeRun = await getFlywheelRunDetail(activeRunId, options);\n return (activeRun?.status === 'running' || activeRun?.status === 'paused') ? activeRun.latest : null;\n}\n\nfunction selectLatestRunIds(entries: Dirent[], limit: number): string[] {\n const selected: string[] = [];\n for (const entry of entries) {\n if (!entry.isDirectory() || !isFlywheelRunId(entry.name)) continue;\n selected.push(entry.name);\n selected.sort((a, b) => runNumber(b) - runNumber(a));\n if (selected.length > limit) selected.length = limit;\n }\n return selected;\n}\n\nexport async function listFlywheelRuns(options: FlywheelRunListOptions = {}): Promise<FlywheelRunSummary[]> {\n const runsDir = getFlywheelRunsDir(options);\n let entries: Dirent[];\n try {\n entries = await readdir(runsDir, { withFileTypes: true });\n } catch (error) {\n const code = typeof error === 'object' && error !== null && 'code' in error ? error.code : undefined;\n if (code === 'ENOENT') return [];\n throw error;\n }\n const runIds = selectLatestRunIds(entries, normalizeLimit(options.limit));\n const activeRunId = getFlywheelActiveRunId();\n const summaries = await mapWithConcurrency(runIds, RUN_SUMMARY_CONCURRENCY, (runId) => summarizeRun(runId, options, activeRunId));\n return summaries.sort((a, b) => b.startedAt.localeCompare(a.startedAt));\n}\n\n/**\n * PAN-1528/PAN-1908: overlay the flywheel capacity gauge from the indexed\n * agents table. This status path must not enumerate state.json files.\n */\nasync function countLiveWorkAgents(_options: FlywheelRunStateOptions = {}): Promise<number> {\n return countAgentsByStatusRole('running', 'work');\n}\n\nfunction withLiveAgentsActive(latest: FlywheelStatus, liveCount: number): FlywheelStatus {\n if (latest.system.agentsActive === liveCount) return latest;\n return {\n ...latest,\n system: {\n ...latest.system,\n agentsActive: liveCount,\n },\n };\n}\n\nexport async function getFlywheelRunDetail(runId: string, options: FlywheelCurrentStatusOptions = {}): Promise<FlywheelRunDetail | null> {\n const runDir = getFlywheelRunDir(runId, options);\n const latest = await readLatestFlywheelStatus(runId, options);\n if (!latest) return null;\n const activeRunId = options.activeRunId !== undefined ? options.activeRunId : getFlywheelActiveRunId();\n const status = await deriveRunStatus(runDir, runId, activeRunId);\n const reportPath = join(runDir, 'report.md');\n const openedPrPath = join(runDir, 'opened-pr.json');\n // PAN-1528: overlay the live work-agent count so the field reflects reality\n // rather than the orchestrator's stale initial value.\n const liveCount = await countLiveWorkAgents(options);\n return {\n id: runId,\n startedAt: latest.startedAt,\n status,\n latest: withLiveAgentsActive(latest, liveCount),\n paths: {\n latest: join(runDir, 'latest.json'),\n ...((await fileExists(reportPath)) ? { report: reportPath } : {}),\n ...((await fileExists(openedPrPath)) ? { openedPr: openedPrPath } : {}),\n },\n };\n}\n\n// Clear the SQLite \"active run\" gate and the pause flag, and notify subscribers.\n// Exported so callers in CLI and dashboard share a single clearing primitive\n// (PAN-1245: gate previously cleared in three different places that drifted).\nexport function clearFlywheelGate(): void {\n setFlywheelActiveRunId(null);\n setFlywheelGloballyPaused(false);\n publishFlywheelStatusCleared();\n}\n\n// Single source of truth for \"is a flywheel run live?\". Reads the SQLite gate,\n// validates it against on-disk run state, and self-heals if the gate points at\n// a run that has already ended (report.md / aborted.json present), at a run\n// whose state was wiped, or at a malformed value. Both `pan flywheel start`\n// and the dashboard Start path consult this — they cannot disagree (PAN-1245).\nexport async function resolveLiveFlywheelRunId(options: FlywheelRunStateOptions = {}): Promise<string | null> {\n const candidate = getFlywheelActiveRunId();\n if (!candidate) return null;\n if (!isFlywheelRunId(candidate)) {\n clearFlywheelGate();\n return null;\n }\n const latest = await readLatestFlywheelStatus(candidate, options);\n if (!latest) {\n // The gate points at a run with no snapshot on disk — the run dir was\n // wiped or never fully initialized. Treat as dead.\n clearFlywheelGate();\n return null;\n }\n const runDir = getFlywheelRunDir(candidate, options);\n // `candidate` is the active run id (read above), so pass it as activeRunId.\n const status = await deriveRunStatus(runDir, candidate, candidate);\n if (status === 'complete' || status === 'aborted') {\n clearFlywheelGate();\n return null;\n }\n return candidate;\n}\n\n// Mark a flywheel run as aborted and clear the gate if it still points at this\n// run. Writes `aborted.json` so `deriveRunStatus` reports the run as aborted on\n// subsequent reads, mirroring the report.md → complete convention.\nexport async function abortFlywheelRun(runId: string, options: FlywheelRunStateOptions = {}): Promise<void> {\n const parsed = parseFlywheelRunId(runId);\n const abortedPath = join(getFlywheelRunDir(parsed, options), 'aborted.json');\n await writeJsonAtomic(abortedPath, { runId: parsed, abortedAt: new Date().toISOString() });\n if (getFlywheelActiveRunId() === parsed) {\n clearFlywheelGate();\n }\n}\n","import { existsSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { getReviewStatusSync } from '../review-status.js';\nimport type { ClassifyLookups } from './pickup.js';\n\n/**\n * Build the {@link ClassifyLookups} the shared pickup module needs from live project\n * state: labels (in-memory issue service), planned (vBRIEF spec + beads), and\n * in-pipeline (review status / live workspace). Shared by the dashboard forecast\n * route and the Flywheel run-cohort snapshot so both classify issues identically\n * (PAN-2006 single source of truth). The issue service is lazy-required to avoid a\n * static lib → dashboard layering edge.\n */\nexport function buildClassifyLookups(\n projectRoot: string,\n opts?: { labels?: (id: string) => readonly string[] },\n): ClassifyLookups {\n // Labels come from the in-memory issue service (server-side). A CLI/sandbox process cannot\n // reach that singleton, so callers there must pass `opts.labels` (e.g. gh-derived) — without\n // it, a CLI would silently classify every issue as label-less, making ready/released/parked/\n // objection/vetoed/blocksMain all false (the `pan backlog forecast` undercount bug).\n const labelsByIssue = new Map<string, string[]>();\n if (!opts?.labels) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { getSharedIssueService } = require('../../dashboard/server/services/issue-service-singleton.js') as typeof import('../../dashboard/server/services/issue-service-singleton.js');\n for (const issue of getSharedIssueService().getIssues() as Array<Record<string, unknown>>) {\n const id = typeof issue['identifier'] === 'string' ? issue['identifier'].toUpperCase() : '';\n if (!id) continue;\n const raw = Array.isArray(issue['labels']) ? (issue['labels'] as unknown[]) : [];\n const names = raw\n .map((l) => (typeof l === 'string' ? l : ((l as { name?: string })?.name ?? '')))\n .filter((s): s is string => Boolean(s));\n labelsByIssue.set(id, names);\n }\n } catch { /* issue service not ready — treat as no labels */ }\n }\n\n const specsDir = join(projectRoot, '.pan', 'specs');\n const specIssues = new Set<string>();\n if (existsSync(specsDir)) {\n for (const f of readdirSync(specsDir)) {\n const m = /^[\\d-]+-([A-Z]+-\\d+)-/i.exec(f);\n if (m) specIssues.add(m[1]!.toUpperCase());\n }\n }\n const workspacesDir = join(projectRoot, 'workspaces');\n const beadsIssues = new Set<string>();\n if (existsSync(workspacesDir)) {\n for (const dir of readdirSync(workspacesDir)) {\n const m = /^feature-([a-z]+-\\d+)$/i.exec(dir);\n if (m && existsSync(join(workspacesDir, dir, '.beads', 'issues.jsonl'))) beadsIssues.add(m[1]!.toUpperCase());\n }\n }\n\n return {\n labels: opts?.labels ?? ((id) => labelsByIssue.get(id.toUpperCase()) ?? []),\n isPlanned: (id) => {\n const u = id.toUpperCase();\n return specIssues.has(u) && beadsIssues.has(u);\n },\n isInPipeline: (id) => {\n const u = id.toUpperCase();\n const rs = getReviewStatusSync(u);\n return (rs !== null && rs.reviewStatus !== 'pending') || existsSync(join(workspacesDir, `feature-${id.toLowerCase()}`));\n },\n };\n}\n","import { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { Effect, Schema } from 'effect';\nimport type { FlywheelRunId } from '@overdeck/contracts';\nimport type { AgentState } from '../agents.js';\nimport type { FlywheelScope, RoleEffort } from '../config-yaml.js';\nimport { getInternalTokenSync, INTERNAL_TOKEN_HEADER } from '../internal-token.js';\nimport { getAgentDir, spawnRun, stopAgent } from '../agents.js';\nimport { parseSequenceMd } from '../backlog/sequence-io.js';\nimport { computePredictedConflictSignals, declaredIssueFootprint, pickFromSequence, type IssueFileFootprint } from '../flywheel-merge-order.js';\nimport { findProjectByPathSync, getProjectSwarmHotspots } from '../projects.js';\nimport type { VBriefDocument } from '../vbrief/types.js';\nimport {\n getFlywheelActiveRunId,\n isFlywheelAutoPickupBacklog,\n isFlywheelRequireUatBeforeMerge,\n setFlywheelActiveRunId,\n setFlywheelGloballyPaused,\n} from '../overdeck/control-settings.js';\nimport { resolveLiveFlywheelRunId, saveRunCohort } from '../../dashboard/server/services/flywheel-run-state.js';\nimport { buildClassifyLookups } from '../backlog/lookups.js';\nimport { computeCohort } from '../backlog/pickup.js';\n\nexport const FLYWHEEL_ORCHESTRATOR_AGENT_ID = 'flywheel-orchestrator';\n\nconst FlywheelRunIdSchema = Schema.String.check(Schema.isPattern(/^RUN-\\d+$/));\nconst decodeFlywheelRunId = Schema.decodeUnknownSync(FlywheelRunIdSchema);\n\nexport interface FlywheelLifecycleOptions {\n runId?: FlywheelRunId;\n workspace?: string;\n briefPath?: string;\n prompt?: string;\n model?: string;\n harness?: 'claude-code' | 'ohmypi' | 'codex';\n effort?: RoleEffort;\n minAgents?: number;\n maxAgents?: number;\n scope?: FlywheelScope;\n autoPickupBacklog?: boolean;\n requireUatBeforeMerge?: boolean;\n env?: NodeJS.ProcessEnv;\n resumeSessionId?: string;\n}\n\nexport interface FlywheelPauseResult {\n activeRunId: string | null;\n}\n\nexport interface FlywheelResumeResult {\n activeRunId: string;\n agent: AgentState;\n}\n\nfunction parseRunId(runId: string): FlywheelRunId {\n return decodeFlywheelRunId(runId);\n}\n\nfunction defaultFlywheelRunId(): FlywheelRunId {\n return parseRunId(`RUN-${Date.now()}`);\n}\n\nfunction internalDashboardOrigin(): string {\n const port = Number.parseInt(process.env['API_PORT'] ?? process.env['PORT'] ?? '3011', 10);\n return process.env['OVERDECK_INTERNAL_DASHBOARD_URL'] ?? `http://127.0.0.1:${port}`;\n}\n\nasync function fetchIssueRowsFromDashboard(): Promise<Array<{ ref?: string; identifier?: string; labels?: string[]; author?: string; assignee?: { name?: string } | string }>> {\n const dashboardOrigin = internalDashboardOrigin();\n const token = getInternalTokenSync();\n if (!token) {\n console.error('[flywheel] Cannot load issue metadata: internal dashboard token is unavailable');\n return [];\n }\n try {\n const response = await fetch(new URL('/api/issues?cycle=all&includeCompleted=true', dashboardOrigin), {\n headers: {\n [INTERNAL_TOKEN_HEADER]: token,\n origin: dashboardOrigin,\n },\n });\n if (!response.ok) {\n console.error(`[flywheel] Cannot load issue metadata from dashboard: HTTP ${response.status}`);\n return [];\n }\n const body = await response.json();\n if (!Array.isArray(body)) {\n console.error('[flywheel] Cannot load issue metadata from dashboard: response was not an array');\n return [];\n }\n return body as Array<{ ref?: string; identifier?: string; labels?: string[]; author?: string; assignee?: { name?: string } | string }>;\n } catch (error) {\n console.error('[flywheel] Cannot load issue metadata from dashboard:', error);\n return [];\n }\n}\n\nasync function flywheelRunConfigurationSection(options: FlywheelLifecycleOptions): Promise<string> {\n const configLines = [\n options.harness ? `Harness: ${options.harness}` : undefined,\n options.effort ? `Effort: ${options.effort}` : undefined,\n options.minAgents ? `Min concurrent agents (target): ${options.minAgents}` : undefined,\n options.maxAgents ? `Max concurrent agents (ceiling): ${options.maxAgents}` : undefined,\n options.scope ? `Scope: ${options.scope}` : undefined,\n typeof options.autoPickupBacklog === 'boolean'\n ? `Auto-pickup backlog: ${options.autoPickupBacklog}`\n : undefined,\n typeof options.requireUatBeforeMerge === 'boolean'\n ? `Require UAT before merge: ${options.requireUatBeforeMerge}`\n : undefined,\n ].filter(Boolean).join('\\n');\n\n let sequenceSection = '';\n if (options.autoPickupBacklog) {\n const seqPath = join(process.cwd(), '.pan', 'backlog', 'sequence.md');\n if (existsSync(seqPath)) {\n try {\n const md = readFileSync(seqPath, 'utf-8');\n const parsed = parseSequenceMd(md);\n if (parsed.ok) {\n // Build issue lookups through the dashboard read path. A deacon child\n // cannot safely import the dashboard's per-process issue singleton.\n type IssueRow = { ref?: string; identifier?: string; labels?: string[]; author?: string; assignee?: { name?: string } | string };\n const getIssueRows = async (): Promise<IssueRow[]> => fetchIssueRowsFromDashboard();\n const issueRowMap = new Map<string, IssueRow>(\n (await getIssueRows()).map((i) => [i.ref ?? i.identifier ?? '', i]),\n );\n\n const issueLabelsLookup = (issueId: string): string[] =>\n issueRowMap.get(issueId)?.labels ?? [];\n\n const AUTHORIZED_AUTHORS = new Set(['eltmon', 'panopticon-agent[bot]']);\n const isAuthorizedIssue = (issueId: string): boolean => {\n const row = issueRowMap.get(issueId);\n if (!row) return false; // unknown issue — skip (safe default)\n if (row.author && AUTHORIZED_AUTHORS.has(row.author)) return true;\n const assigneeName = typeof row.assignee === 'string' ? row.assignee : row.assignee?.name;\n return assigneeName === 'eltmon';\n };\n\n const projectRoot = process.cwd();\n const specsDir = join(projectRoot, '.pan', 'specs');\n const workspacesDir = join(projectRoot, 'workspaces');\n const issuesWithSpecs = new Set<string>();\n const declaredFootprints: IssueFileFootprint[] = [];\n if (existsSync(specsDir)) {\n for (const f of readdirSync(specsDir)) {\n const match = /^[\\d-]+-([A-Z]+-\\d+)-/i.exec(f);\n if (!match) continue;\n const issueId = match[1]!.toUpperCase();\n issuesWithSpecs.add(issueId);\n try {\n const doc = JSON.parse(readFileSync(join(specsDir, f), 'utf-8')) as VBriefDocument;\n declaredFootprints.push(declaredIssueFootprint(issueId, doc));\n } catch {\n // A malformed spec should not break flywheel startup; planned-ness\n // still comes from the filename and the normal plan gate handles parse errors.\n }\n }\n }\n const predictedConflictSignals = computePredictedConflictSignals(declaredFootprints, {\n hotspots: getProjectSwarmHotspots(findProjectByPathSync(projectRoot)),\n });\n const isReadyOrHasPrd = (issueId: string): boolean => {\n const id = issueId.toUpperCase();\n // ready = spec AND beads exist in the workspace\n if (issuesWithSpecs.has(id) &&\n existsSync(join(workspacesDir, `feature-${id.toLowerCase()}`, '.beads', 'issues.jsonl'))) {\n return true;\n }\n return existsSync(join(projectRoot, '.pan', 'drafts', `${id}.md`));\n };\n const isInPipeline = (issueId: string): boolean =>\n existsSync(join(workspacesDir, `feature-${issueId.toLowerCase()}`));\n\n const top10 = parsed.doc.nodes.slice(0, 10).map((n) =>\n ` #${n.rank} ${n.issue}: ${n.why.slice(0, 100)} [gate:${n.gate}]`,\n );\n const nextPick = pickFromSequence(parsed.doc.nodes, { issueLabels: issueLabelsLookup, isAuthorizedIssue, isReadyOrHasPrd, isInPipeline, requireReady: true, autoPickupBacklog: options.autoPickupBacklog, predictedConflictSignals });\n let nextLine: string;\n let pickInstruction: string;\n if (!nextPick) {\n nextLine = 'No eligible issue found in sequence — fall back to normal priority';\n pickInstruction = '';\n } else if (nextPick.planning === 'interactive') {\n // FR-17: interactive planning requires operator presence — must NOT be auto-started\n nextLine = `NEEDS OPERATOR ACTION: ${nextPick.issueId} (rank ${nextPick.rank}) has planning=interactive — do NOT auto-start; operator must run 'pan plan ${nextPick.issueId}'`;\n pickInstruction = `\\n\\nIMPORTANT: auto_pickup_backlog=true. The top-ranked issue requires interactive planning and MUST NOT be auto-started. Surface it to the operator for manual 'pan plan' invocation instead of auto-picking it.`;\n } else {\n const conflictSuffix = typeof nextPick.predictedConflictCount === 'number'\n ? `, predictedConflicts=${nextPick.predictedConflictCount}${nextPick.predictedConflictsWith?.length ? ` with ${nextPick.predictedConflictsWith.join(', ')}` : ''}`\n : '';\n nextLine = `MUST start next: ${nextPick.issueId} (rank ${nextPick.rank}, planning=${nextPick.planning}${conflictSuffix})`;\n pickInstruction = `\\n\\nIMPORTANT: auto_pickup_backlog=true. You MUST pick the \"MUST start next\" issue above as your next startup target. Do NOT apply your own P0-P3/oldest-first ranking while a sequence is available.`;\n }\n sequenceSection = `\\n\\nBacklog sequence (${parsed.doc.nodes.length} issues ranked):\\n${top10.join('\\n')}\\n${nextLine}${pickInstruction}`;\n }\n } catch {\n // sequence.md exists but couldn't be parsed — skip enrichment\n }\n }\n }\n\n return (configLines ? `\\n\\nRun configuration:\\n${configLines}` : '') + sequenceSection;\n}\n\nasync function defaultFlywheelPrompt(runId: string, options: FlywheelLifecycleOptions, briefContent?: string): Promise<string> {\n const configSection = await flywheelRunConfigurationSection(options);\n const briefSection = options.briefPath\n ? `\\n\\nBrief path: ${options.briefPath}\\n\\n${briefContent ?? ''}`\n : '';\n return `FLYWHEEL ORCHESTRATOR TASK for ${runId}:\n\nRun the Fix-All Flywheel loop. Keep status snapshots current, coordinate Overdeck roles through the normal pipeline surfaces, respect the configured run scope and agent cap, and wait for explicit lifecycle instructions when the run is paused or complete.${configSection}${briefSection}`;\n}\n\nfunction getLocalFlywheelRunDir(runId: string): string {\n const overdeckHome = process.env.OVERDECK_HOME ?? join(homedir(), '.overdeck');\n return join(overdeckHome, 'flywheel', 'runs', runId);\n}\n\nexport async function saveResumeSessionId(runId: string, sessionId: string): Promise<void> {\n const runDir = getLocalFlywheelRunDir(runId);\n await mkdir(runDir, { recursive: true });\n await writeFile(\n join(runDir, 'resume-session.json'),\n JSON.stringify({ sessionId, pausedAt: new Date().toISOString() }),\n 'utf-8',\n );\n}\n\nexport async function loadResumeSessionId(runId: string): Promise<string | null> {\n try {\n const raw = await readFile(join(getLocalFlywheelRunDir(runId), 'resume-session.json'), 'utf-8');\n const parsed = JSON.parse(raw) as { sessionId?: unknown };\n return typeof parsed.sessionId === 'string' ? parsed.sessionId : null;\n } catch {\n return null;\n }\n}\n\nexport function isFlywheelDevcontainerRuntime(env: NodeJS.ProcessEnv = process.env): boolean {\n const disabledDeacon = env.OVERDECK_DISABLE_DEACON?.toLowerCase();\n if (disabledDeacon === '1' || disabledDeacon === 'true') return true;\n\n const hostname = env.HOSTNAME?.toLowerCase() ?? '';\n return hostname.includes('devcontainer') || hostname.startsWith('api-feature-') || hostname.startsWith('workspace-');\n}\n\n/**\n * Resume prompt. PAN-2006 FR-8: re-attach the standing brief on resume so its\n * directives (pipeline-unblock override, never-block, red-main-first) survive a\n * resume + context compaction — the pre-PAN-2006 resume prompt only pointed at\n * FLYWHEEL-STATE.md and a long-running orchestrator could drift off-brief.\n */\nexport function buildFlywheelResumePrompt(configSection: string, briefContent?: string): string {\n const base =\n 'FLYWHEEL RESUME: You were paused by the operator. Resume the tick loop from your prior ' +\n 'state. Check `docs/FLYWHEEL-STATE.md` and the latest status snapshot for context.';\n const brief = briefContent\n ? `\\n\\n--- Standing brief (re-read it — it governs pickup, unblocking, and never-block) ---\\n\\n${briefContent}`\n : '';\n return `${base}${configSection}${brief}`;\n}\n\nexport async function spawnFlywheelAgent(runId: string, options: FlywheelLifecycleOptions = {}): Promise<AgentState> {\n const workspace = options.workspace ?? process.cwd();\n // Re-read the brief on every spawn (fresh AND resume) so its directives survive\n // resume/compaction. Default to the standard brief path when none is supplied.\n const briefPath = options.briefPath ?? join(workspace, 'docs', 'flywheel-brief.md');\n const briefContent = await readFile(briefPath, 'utf8').catch(() => undefined);\n const prompt = options.resumeSessionId\n ? buildFlywheelResumePrompt(await flywheelRunConfigurationSection(options), briefContent)\n : (options.prompt ?? (await defaultFlywheelPrompt(runId, options, briefContent)));\n return spawnRun(runId, 'flywheel', {\n agentId: FLYWHEEL_ORCHESTRATOR_AGENT_ID,\n workspace,\n prompt,\n model: options.model,\n harness: options.harness,\n effort: options.effort,\n allowHost: true,\n registerConversation: true,\n resumeSessionId: options.resumeSessionId,\n flywheelRunId: runId,\n });\n}\n\nfunction withFlywheelAutonomyOptions(options: FlywheelLifecycleOptions): FlywheelLifecycleOptions {\n return {\n ...options,\n autoPickupBacklog: options.autoPickupBacklog ?? isFlywheelAutoPickupBacklog(),\n requireUatBeforeMerge: options.requireUatBeforeMerge ?? isFlywheelRequireUatBeforeMerge(),\n };\n}\n\nexport async function spawnFlywheel(options: FlywheelLifecycleOptions = {}): Promise<AgentState> {\n if (isFlywheelDevcontainerRuntime(options.env)) {\n throw new Error('Refusing to spawn flywheel-orchestrator inside a workspace devcontainer');\n }\n\n // Self-healing gate check (PAN-1245): if the SQLite gate points at a run\n // that has already ended (report.md/aborted.json) or whose on-disk state is\n // gone (post-reboot, post-wipe), resolveLiveFlywheelRunId clears the gate\n // and returns null. Only a genuinely live prior run blocks a new start.\n const activeRunId = await resolveLiveFlywheelRunId();\n if (activeRunId) {\n throw new Error(`Flywheel run ${activeRunId} is already active; pause, resume, or report it before starting another run`);\n }\n\n const runId = options.runId ? parseRunId(options.runId) : defaultFlywheelRunId();\n const agent = await spawnFlywheelAgent(runId, withFlywheelAutonomyOptions(options));\n setFlywheelActiveRunId(runId);\n setFlywheelGloballyPaused(false);\n\n // PAN-2006 WI-7: freeze the run's cohort (in-flight ∪ current+next wave) at start.\n // The Run is complete once this cohort drains; mid-run pickups don't extend it.\n // Best-effort — a missing/unparseable sequence just means no cohort gate yet.\n try {\n const workspace = options.workspace ?? process.cwd();\n const seqPath = join(workspace, '.pan', 'backlog', 'sequence.md');\n if (existsSync(seqPath)) {\n const parsed = parseSequenceMd(readFileSync(seqPath, 'utf-8'));\n if (parsed.ok) {\n saveRunCohort(runId, computeCohort(parsed.doc.nodes, buildClassifyLookups(workspace), options.maxAgents ?? 5, options.autoPickupBacklog ?? isFlywheelAutoPickupBacklog()));\n }\n }\n } catch { /* cohort snapshot is best-effort */ }\n\n return agent;\n}\n\nexport async function pauseFlywheel(): Promise<FlywheelPauseResult> {\n const activeRunId = getFlywheelActiveRunId();\n if (activeRunId) {\n try {\n const sessionId = (await readFile(join(getAgentDir(FLYWHEEL_ORCHESTRATOR_AGENT_ID), 'session.id'), 'utf-8')).trim();\n if (sessionId) await saveResumeSessionId(activeRunId, sessionId);\n } catch { /* non-fatal: resume falls back to fresh if session.id is missing */ }\n }\n setFlywheelGloballyPaused(true);\n await Effect.runPromise(stopAgent(FLYWHEEL_ORCHESTRATOR_AGENT_ID));\n return { activeRunId };\n}\n\nexport async function resumeFlywheel(options: FlywheelLifecycleOptions = {}): Promise<FlywheelResumeResult> {\n if (isFlywheelDevcontainerRuntime(options.env)) {\n throw new Error('Refusing to resume flywheel-orchestrator inside a workspace devcontainer');\n }\n\n const activeRunId = getFlywheelActiveRunId();\n if (!activeRunId) {\n throw new Error('No active flywheel run to resume');\n }\n const runId = parseRunId(activeRunId);\n\n const resumeSessionId = options.resumeSessionId ?? await loadResumeSessionId(runId) ?? undefined;\n const agent = await spawnFlywheelAgent(runId, withFlywheelAutonomyOptions({ ...options, resumeSessionId }));\n setFlywheelGloballyPaused(false);\n return { activeRunId, agent };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAoDA,MAAA,uBAAA,OAAA,kBAAA,eAAA;AACA,MAAA,wBAAA,OAAA,kBAAA,cAAA;AACA,MAAA,iBAAA;AACA,MAAA,qBAAA;AACA,MAAA,iBAAA;AACA,MAAA,0BAAA;AAGA,MAAA,0CAAA,IAAA,KAAA;AAEA,SAAA,8BAAA,UAAA;AACE,yBAAA,IAAA,SAAA;AACA,cAAA;AACE,0BAAA,OAAA,SAAA;;;AAIJ,SAAA,4BAAA,QAAA;AACE,MAAA,MAAA,YAAA,wBAAA,UAAA,OAAA;;AAKF,SAAA,+BAAA;AACE,6BAAA,KAAA;;AAGF,SAAA,mBAAA,OAAA;AACE,QAAA,sBAAA,MAAA;;AAGF,SAAA,gBAAA,OAAA;AACE,QAAA,eAAA,KAAA,MAAA;;AAGF,SAAA,UAAA,OAAA;;AAEE,QAAA,QAAA,OAAA,MAAA,GAAA,GAAA;;AAGF,SAAA,eAAA,OAAA;AACE,KAAA,UAAA,KAAA,EAAA,QAAA;AACA,KAAA,CAAA,OAAA,SAAA,MAAA,IAAA,SAAA,EAAA,QAAA;AACA,QAAA,KAAA,IAAA,KAAA,MAAA,MAAA,EAAA,eAAA;;AAGF,eAAA,mBAAA,OAAA,aAAA,QAAA;;;AAGE,OAAA,QAAA,IAAA,MAAA,KAAA,EAAA,QAAA,KAAA,IAAA,aAAA,MAAA,OAAA,EAAA,EAAA,YAAA;AACE,SAAA,QAAA,MAAA,QAAA;;AAEE,YAAA;AACA,WAAA,WAAA,MAAA,OAAA,MAAA,SAAA;;;AAGJ,QAAA;;AAGF,SAAA,gBAAA,UAAA,EAAA,EAAA;AACE,QAAA,KAAA,QAAA,gBAAA,QAAA,IAAA,oBAAA,KAAA,SAAA,EAAA,YAAA,EAAA,WAAA;;AAGF,SAAA,mBAAA,UAAA,EAAA,EAAA;AACE,QAAA,KAAA,gBAAA,QAAA,EAAA,OAAA;;AAGF,SAAA,kBAAA,OAAA,UAAA,EAAA,EAAA;AACE,QAAA,KAAA,mBAAA,QAAA,EAAA,mBAAA,MAAA,CAAA;;AAsCF,eAAA,kBAAA,UAAA,EAAA,EAAA;;AAEE,OAAA,MAAA,SAAA,EAAA,WAAA,MAAA,CAAA;AAQA,QAAA,mBAAA,QAAA,MAAA,QAAA,SAAA,EAAA,eAAA,MAAA,CAAA,EAAA,QAAA,KAAA,UAAA;AALE,MAAA,CAAA,MAAA,aAAA,CAAA,QAAA;;AAEA,MAAA,CAAA,MAAA,QAAA;AACA,SAAA,KAAA,IAAA,KAAA,OAAA,MAAA,GAAA,CAAA;;;AAKJ,eAAA,gBAAA,MAAA,SAAA;;AAEE,OAAA,MAAA,QAAA,KAAA,EAAA,EAAA,WAAA,MAAA,CAAA;AACA,OAAA,UAAA,SAAA,GAAA,KAAA,UAAA,SAAA,MAAA,EAAA,CAAA,KAAA,OAAA;AACA,OAAA,OAAA,SAAA,KAAA;AACA,QAAA;;AAGF,eAAA,0BAAA,QAAA,UAAA,EAAA,EAAA;;AAEE,OAAA,gBAAA,YAAA,OAAA;AACA,6BAAA,OAAA;AACA,QAAA;;AAGF,SAAA,qBAAA,SAAA;AACE,KAAA,OAAA,YAAA,YAAA,YAAA,KAAA,OAAA,IAAA,MAAA,mCAAA;;AAEA,KAAA,OAAA,YAAA,EAAA,OAAA,IAAA,MAAA,2CAAA;AACA,MAAA,MAAA,OAAA;;;;;;AAGA,QAAA;;AAGF,eAAA,4BAAA,UAAA,UAAA,EAAA,EAAA;;AAGE,QAAA,gBAAA,KAAA,kBAAA,OAAA,QAAA,EAAA,cAAA,EAAA;;;;;AAGF,eAAA,2BAAA,OAAA,UAAA,EAAA,EAAA;;AAEE,KAAA;AACE,SAAA,qBAAA,KAAA,MAAA,MAAA,SAAA,YAAA,OAAA,CAAA,CAAA;;AAGA,OAAA,OAAA,UAAA,YAAA,UAAA,QAAA,UAAA,QAAA,MAAA,OAAA,KAAA,OAAA,SAAA,QAAA;AACA,QAAA;;;AAIJ,eAAA,yBAAA,OAAA,UAAA,EAAA,EAAA;;AAEE,KAAA;AAEE,SAAA,qBAAA,KAAA,MAAA,MAAA,SAAA,YAAA,OAAA,CAAA,CAAA;;AAGA,OAAA,OAAA,UAAA,YAAA,UAAA,QAAA,UAAA,QAAA,MAAA,OAAA,KAAA,OAAA,SAAA,QAAA;AACA,QAAA;;;AAIJ,eAAA,WAAA,MAAA;AACE,KAAA;AAEE,UAAA,MAAA,OAAA,KAAA,EAAA,QAAA;;AAGA,OAAA,OAAA,UAAA,YAAA,UAAA,QAAA,UAAA,QAAA,MAAA,OAAA,KAAA,OAAA,SAAA,QAAA;AACA,QAAA;;;AAIJ,eAAA,gBAAA,QAAA,OAAA,aAAA;AACE,KAAA,MAAA,WAAA,KAAA,QAAA,eAAA,CAAA,CAAA,QAAA;AACA,KAAA,MAAA,WAAA,KAAA,QAAA,YAAA,CAAA,CAAA,QAAA;AAMA,KAAA,gBAAA,MAAA,QAAA;AACA,QAAA,0BAAA,GAAA,WAAA;;AAGF,eAAA,aAAA,OAAA,SAAA,aAAA;;;;AAQE,QAAA;;;;;;AAOF,eAAA,gCAAA,UAAA,EAAA,EAAA;;AAEE,KAAA,CAAA,eAAA,CAAA,gBAAA,YAAA,CAAA,QAAA;;AAEA,QAAA,WAAA,WAAA,aAAA,WAAA,WAAA,WAAA,UAAA,SAAA;;AAGF,SAAA,mBAAA,SAAA,OAAA;;AAEE,MAAA,MAAA,SAAA,SAAA;AACE,MAAA,CAAA,MAAA,aAAA,IAAA,CAAA,gBAAA,MAAA,KAAA,CAAA;AACA,WAAA,KAAA,MAAA,KAAA;AACA,WAAA,MAAA,GAAA,MAAA,UAAA,EAAA,GAAA,UAAA,EAAA,CAAA;AACA,MAAA,SAAA,SAAA,MAAA,UAAA,SAAA;;AAEF,QAAA;;AAGF,eAAA,iBAAA,UAAA,EAAA,EAAA;;;AAGE,KAAA;AACE,YAAA,MAAA,QAAA,SAAA,EAAA,eAAA,MAAA,CAAA;;AAGA,OAAA,OAAA,UAAA,YAAA,UAAA,QAAA,UAAA,QAAA,MAAA,OAAA,KAAA,OAAA,SAAA,QAAA,EAAA;AACA,QAAA;;;;AAKF,SAAA,MAAA,mBAAA,QAAA,0BAAA,UAAA,aAAA,OAAA,SAAA,YAAA,CAAA,EAAA,MAAA,GAAA,MAAA,EAAA,UAAA,cAAA,EAAA,UAAA,CAAA;;;;;;AAOF,eAAA,oBAAA,WAAA,EAAA,EAAA;AACE,QAAA,wBAAA,WAAA,OAAA;;AAGF,SAAA,qBAAA,QAAA,WAAA;AACE,KAAA,OAAA,OAAA,iBAAA,UAAA,QAAA;AACA,QAAA;;;;;;;;AASF,eAAA,qBAAA,OAAA,UAAA,EAAA,EAAA;;;AAGE,KAAA,CAAA,OAAA,QAAA;;;;;AAQA,QAAA;;;;;;;;;;;;AAgBF,SAAA,oBAAA;AACE,wBAAA,KAAA;AACA,2BAAA,MAAA;AACA,+BAAA;;AAQF,eAAA,yBAAA,UAAA,EAAA,EAAA;;AAEE,KAAA,CAAA,UAAA,QAAA;AACA,KAAA,CAAA,gBAAA,UAAA,EAAA;AACE,qBAAA;AACA,SAAA;;AAGF,KAAA,CAAA,MAAA,yBAAA,WAAA,QAAA,EAAA;AAGE,qBAAA;AACA,SAAA;;;AAKF,KAAA,WAAA,cAAA,WAAA,WAAA;AACE,qBAAA;AACA,SAAA;;AAEF,QAAA;;AAMF,eAAA,iBAAA,OAAA,UAAA,EAAA,EAAA;;AAGE,OAAA,gBAAA,KAAA,kBAAA,QAAA,QAAA,EAAA,eAAA,EAAA;;;;AACA,KAAA,wBAAA,KAAA,OAAA,oBAAA;;;;;;;;;;;;;ACpXF,SAAA,qBAAA,aAAA,MAAA;;AASE,KAAA,CAAA,MAAA,OAAA,KAAA;;AAII,OAAA,MAAA,SAAA,uBAAA,CAAA,WAAA,EAAA;;AAEE,OAAA,CAAA,GAAA;;AAKA,iBAAA,IAAA,IAAA,MAAA;;;;;AAON,KAAA,WAAA,SAAA,CAAA,MAAA,MAAA,KAAA,YAAA,SAAA,EAAA;;AAGI,MAAA,EAAA,YAAA,IAAA,EAAA,GAAA,aAAA,CAAA;;;;AAKJ,KAAA,WAAA,cAAA,CAAA,MAAA,MAAA,OAAA,YAAA,cAAA,EAAA;;AAGI,MAAA,KAAA,WAAA,KAAA,eAAA,KAAA,UAAA,eAAA,CAAA,CAAA,aAAA,IAAA,EAAA,GAAA,aAAA,CAAA;;AAIJ,QAAA;;;;AAII,UAAA,WAAA,IAAA,EAAA,IAAA,YAAA,IAAA,EAAA;;;;AAKA,UAAA,OAAA,QAAA,GAAA,iBAAA,aAAA,WAAA,KAAA,eAAA,WAAA,GAAA,aAAA,GAAA,CAAA;;;;;;uBC5CmC;AAKzC,MAAa,iCAAiC;AAE9C,MAAM,sBAAsB,OAAO,OAAO,MAAM,OAAO,UAAU,YAAY,CAAC;AAC9E,MAAM,sBAAsB,OAAO,kBAAkB,oBAAoB;AA4BzE,SAAS,WAAW,OAA8B;AAChD,QAAO,oBAAoB,MAAM;;AAOnC,SAAS,0BAAkC;CACzC,MAAM,OAAO,OAAO,SAAS,QAAQ,IAAI,eAAe,QAAQ,IAAI,WAAW,QAAQ,GAAG;AAC1F,QAAO,QAAQ,IAAI,sCAAsC,oBAAoB;;AAG/E,eAAe,8BAAgK;CAC7K,MAAM,kBAAkB,yBAAyB;CACjD,MAAM,QAAQ,sBAAsB;AACpC,KAAI,CAAC,OAAO;AACV,UAAQ,MAAM,iFAAiF;AAC/F,SAAO,EAAE;;AAEX,KAAI;EACF,MAAM,WAAW,MAAM,MAAM,IAAI,IAAI,+CAA+C,gBAAgB,EAAE,EACpG,SAAS;IACN,wBAAwB;GACzB,QAAQ;GACT,EACF,CAAC;AACF,MAAI,CAAC,SAAS,IAAI;AAChB,WAAQ,MAAM,8DAA8D,SAAS,SAAS;AAC9F,UAAO,EAAE;;EAEX,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAE;AACxB,WAAQ,MAAM,kFAAkF;AAChG,UAAO,EAAE;;AAEX,SAAO;UACA,OAAO;AACd,UAAQ,MAAM,yDAAyD,MAAM;AAC7E,SAAO,EAAE;;;AAIb,eAAe,gCAAgC,SAAoD;CACjG,MAAM,cAAc;EAClB,QAAQ,UAAU,YAAY,QAAQ,YAAY,KAAA;EAClD,QAAQ,SAAS,WAAW,QAAQ,WAAW,KAAA;EAC/C,QAAQ,YAAY,mCAAmC,QAAQ,cAAc,KAAA;EAC7E,QAAQ,YAAY,oCAAoC,QAAQ,cAAc,KAAA;EAC9E,QAAQ,QAAQ,UAAU,QAAQ,UAAU,KAAA;EAC5C,OAAO,QAAQ,sBAAsB,YACjC,wBAAwB,QAAQ,sBAChC,KAAA;EACJ,OAAO,QAAQ,0BAA0B,YACrC,6BAA6B,QAAQ,0BACrC,KAAA;EACL,CAAC,OAAO,QAAQ,CAAC,KAAK,KAAK;CAE5B,IAAI,kBAAkB;AACtB,KAAI,QAAQ,mBAAmB;EAC7B,MAAM,UAAU,KAAK,QAAQ,KAAK,EAAE,QAAQ,WAAW,cAAc;AACrE,MAAI,WAAW,QAAQ,CACrB,KAAI;GAEF,MAAM,SAAS,gBADJ,aAAa,SAAS,QACA,CAAC;AAClC,OAAI,OAAO,IAAI;IAIb,MAAM,eAAe,YAAiC,6BAA6B;IACnF,MAAM,cAAc,IAAI,KACrB,MAAM,cAAc,EAAE,KAAK,MAAM,CAAC,EAAE,OAAO,EAAE,cAAc,IAAI,EAAE,CAAC,CACpE;IAED,MAAM,qBAAqB,YACzB,YAAY,IAAI,QAAQ,EAAE,UAAU,EAAE;IAExC,MAAM,qBAAqB,IAAI,IAAI,CAAC,UAAU,wBAAwB,CAAC;IACvE,MAAM,qBAAqB,YAA6B;KACtD,MAAM,MAAM,YAAY,IAAI,QAAQ;AACpC,SAAI,CAAC,IAAK,QAAO;AACjB,SAAI,IAAI,UAAU,mBAAmB,IAAI,IAAI,OAAO,CAAE,QAAO;AAE7D,aADqB,OAAO,IAAI,aAAa,WAAW,IAAI,WAAW,IAAI,UAAU,UAC7D;;IAG1B,MAAM,cAAc,QAAQ,KAAK;IACjC,MAAM,WAAW,KAAK,aAAa,QAAQ,QAAQ;IACnD,MAAM,gBAAgB,KAAK,aAAa,aAAa;IACrD,MAAM,kCAAkB,IAAI,KAAa;IACzC,MAAM,qBAA2C,EAAE;AACnD,QAAI,WAAW,SAAS,CACtB,MAAK,MAAM,KAAK,YAAY,SAAS,EAAE;KACrC,MAAM,QAAQ,yBAAyB,KAAK,EAAE;AAC9C,SAAI,CAAC,MAAO;KACZ,MAAM,UAAU,MAAM,GAAI,aAAa;AACvC,qBAAgB,IAAI,QAAQ;AAC5B,SAAI;MACF,MAAM,MAAM,KAAK,MAAM,aAAa,KAAK,UAAU,EAAE,EAAE,QAAQ,CAAC;AAChE,yBAAmB,KAAK,uBAAuB,SAAS,IAAI,CAAC;aACvD;;IAMZ,MAAM,2BAA2B,gCAAgC,oBAAoB,EACnF,UAAU,wBAAwB,sBAAsB,YAAY,CAAC,EACtE,CAAC;IACF,MAAM,mBAAmB,YAA6B;KACpD,MAAM,KAAK,QAAQ,aAAa;AAEhC,SAAI,gBAAgB,IAAI,GAAG,IACvB,WAAW,KAAK,eAAe,WAAW,GAAG,aAAa,IAAI,UAAU,eAAe,CAAC,CAC1F,QAAO;AAET,YAAO,WAAW,KAAK,aAAa,QAAQ,UAAU,GAAG,GAAG,KAAK,CAAC;;IAEpE,MAAM,gBAAgB,YACpB,WAAW,KAAK,eAAe,WAAW,QAAQ,aAAa,GAAG,CAAC;IAErE,MAAM,QAAQ,OAAO,IAAI,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,MAC/C,MAAM,EAAE,KAAK,GAAG,EAAE,MAAM,IAAI,EAAE,IAAI,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,GACjE;IACD,MAAM,WAAW,iBAAiB,OAAO,IAAI,OAAO;KAAE,aAAa;KAAmB;KAAmB;KAAiB;KAAc,cAAc;KAAM,mBAAmB,QAAQ;KAAmB;KAA0B,CAAC;IACrO,IAAI;IACJ,IAAI;AACJ,QAAI,CAAC,UAAU;AACb,gBAAW;AACX,uBAAkB;eACT,SAAS,aAAa,eAAe;AAE9C,gBAAW,0BAA0B,SAAS,QAAQ,SAAS,SAAS,KAAK,8EAA8E,SAAS,QAAQ;AAC5K,uBAAkB;WACb;KACL,MAAM,iBAAiB,OAAO,SAAS,2BAA2B,WAC9D,wBAAwB,SAAS,yBAAyB,SAAS,wBAAwB,SAAS,SAAS,SAAS,uBAAuB,KAAK,KAAK,KAAK,OAC5J;AACJ,gBAAW,oBAAoB,SAAS,QAAQ,SAAS,SAAS,KAAK,aAAa,SAAS,WAAW,eAAe;AACvH,uBAAkB;;AAEpB,sBAAkB,yBAAyB,OAAO,IAAI,MAAM,OAAO,oBAAoB,MAAM,KAAK,KAAK,CAAC,IAAI,WAAW;;UAEnH;;AAMZ,SAAQ,cAAc,2BAA2B,gBAAgB,MAAM;;AAGzE,eAAe,sBAAsB,OAAe,SAAmC,cAAwC;AAK7H,QAAO,kCAAkC,MAAM;;gQAE+M,MANlO,gCAAgC,QAAQ,GAC/C,QAAQ,YACzB,mBAAmB,QAAQ,UAAU,MAAM,gBAAgB,OAC3D;;AAMN,SAAS,uBAAuB,OAAuB;AAErD,QAAO,KADc,QAAQ,IAAI,iBAAiB,KAAK,SAAS,EAAE,YAAY,EACpD,YAAY,QAAQ,MAAM;;AAGtD,eAAsB,oBAAoB,OAAe,WAAkC;CACzF,MAAM,SAAS,uBAAuB,MAAM;AAC5C,OAAM,MAAM,QAAQ,EAAE,WAAW,MAAM,CAAC;AACxC,OAAM,UACJ,KAAK,QAAQ,sBAAsB,EACnC,KAAK,UAAU;EAAE;EAAW,2BAAU,IAAI,MAAM,EAAC,aAAa;EAAE,CAAC,EACjE,QACD;;AAGH,eAAsB,oBAAoB,OAAuC;AAC/E,KAAI;EACF,MAAM,MAAM,MAAM,SAAS,KAAK,uBAAuB,MAAM,EAAE,sBAAsB,EAAE,QAAQ;EAC/F,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,SAAO,OAAO,OAAO,cAAc,WAAW,OAAO,YAAY;SAC3D;AACN,SAAO;;;AAIX,SAAgB,8BAA8B,MAAyB,QAAQ,KAAc;CAC3F,MAAM,iBAAiB,IAAI,yBAAyB,aAAa;AACjE,KAAI,mBAAmB,OAAO,mBAAmB,OAAQ,QAAO;CAEhE,MAAM,WAAW,IAAI,UAAU,aAAa,IAAI;AAChD,QAAO,SAAS,SAAS,eAAe,IAAI,SAAS,WAAW,eAAe,IAAI,SAAS,WAAW,aAAa;;;;;;;;AAStH,SAAgB,0BAA0B,eAAuB,cAA+B;AAO9F,QAAO,6KAAU,gBAHH,eACV,+FAA+F,iBAC/F;;AAIN,eAAsB,mBAAmB,OAAe,UAAoC,EAAE,EAAuB;CACnH,MAAM,YAAY,QAAQ,aAAa,QAAQ,KAAK;CAIpD,MAAM,eAAe,MAAM,SADT,QAAQ,aAAa,KAAK,WAAW,QAAQ,oBAAoB,EACpC,OAAO,CAAC,YAAY,KAAA,EAAU;AAI7E,QAAO,SAAS,OAAO,YAAY;EACjC,SAAS;EACT;EACA,QANa,QAAQ,kBACnB,0BAA0B,MAAM,gCAAgC,QAAQ,EAAE,aAAa,GACtF,QAAQ,UAAW,MAAM,sBAAsB,OAAO,SAAS,aAAa;EAK/E,OAAO,QAAQ;EACf,SAAS,QAAQ;EACjB,QAAQ,QAAQ;EAChB,WAAW;EACX,sBAAsB;EACtB,iBAAiB,QAAQ;EACzB,eAAe;EAChB,CAAC;;AAGJ,SAAS,4BAA4B,SAA6D;AAChG,QAAO;EACL,GAAG;EACH,mBAAmB,QAAQ,qBAAqB,6BAA6B;EAC7E,uBAAuB,QAAQ,yBAAyB,iCAAiC;EAC1F;;AAuCH,eAAsB,gBAA8C;CAClE,MAAM,cAAc,wBAAwB;AAC5C,KAAI,YACF,KAAI;EACF,MAAM,aAAa,MAAM,SAAS,KAAK,YAAY,+BAA+B,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM;AACnH,MAAI,UAAW,OAAM,oBAAoB,aAAa,UAAU;SAC1D;AAEV,2BAA0B,KAAK;AAC/B,OAAM,OAAO,WAAW,UAAU,+BAA+B,CAAC;AAClE,QAAO,EAAE,aAAa;;AAGxB,eAAsB,eAAe,UAAoC,EAAE,EAAiC;AAC1G,KAAI,8BAA8B,QAAQ,IAAI,CAC5C,OAAM,IAAI,MAAM,2EAA2E;CAG7F,MAAM,cAAc,wBAAwB;AAC5C,KAAI,CAAC,YACH,OAAM,IAAI,MAAM,mCAAmC;CAErD,MAAM,QAAQ,WAAW,YAAY;CAErC,MAAM,kBAAkB,QAAQ,mBAAmB,MAAM,oBAAoB,MAAM,IAAI,KAAA;CACvF,MAAM,QAAQ,MAAM,mBAAmB,OAAO,4BAA4B;EAAE,GAAG;EAAS;EAAiB,CAAC,CAAC;AAC3G,2BAA0B,MAAM;AAChC,QAAO;EAAE;EAAa;EAAO"}
@@ -1,14 +1,14 @@
1
1
  import { t as init_config_yaml } from "./config-yaml-DPAieL_G.js";
2
2
  import { L as sessionExists, x as init_tmux } from "./tmux-ePNhMIMU.js";
3
3
  import { c as FlywheelStats, t as init_src, v as FlywheelStatus } from "./src-fgbU-jJ-.js";
4
- import { t as init_agents } from "./agents-DHvsjsuP.js";
4
+ import { t as init_agents } from "./agents-C7V4odQ6.js";
5
5
  import { s as init_internal_token } from "./internal-token-CQUx9YLc.js";
6
6
  import { i as getFlywheelActiveRunId, s as init_control_settings } from "./control-settings-BMqUkXmR.js";
7
- import { t as init_harness_resolve } from "./harness-resolve-DKeSVsJL.js";
8
- import { d as clearFlywheelGate, f as getFlywheelRunDetail, h as listFlywheelRuns, p as getFlywheelRunDir } from "./flywheel-ClMjGW_u.js";
7
+ import { t as init_harness_resolve } from "./harness-resolve-B3f9G1Kp.js";
8
+ import { d as clearFlywheelGate, f as getFlywheelRunDetail, h as listFlywheelRuns, p as getFlywheelRunDir } from "./flywheel-BLoVNtJV.js";
9
9
  import { f as init_github_app } from "./github-app-FMXgo3vK.js";
10
- import { t as init_sequence_io } from "./sequence-io-B2GmilSI.js";
11
- import { r as computeMergeQueue } from "./flywheel-merge-order-CuDcqTRJ.js";
10
+ import { t as init_sequence_io } from "./sequence-io-6YP8fVpH.js";
11
+ import { r as computeMergeQueue } from "./flywheel-merge-order-B7BH8mZ3.js";
12
12
  import "./merge-blockers-DwdQNsYD.js";
13
13
  import { Effect, Schema } from "effect";
14
14
  import "node:os";
@@ -203,4 +203,4 @@ async function flywheelReportCommand(options = {}) {
203
203
  //#endregion
204
204
  export { flywheelReportCommand };
205
205
 
206
- //# sourceMappingURL=flywheel-DefHRzY4.js.map
206
+ //# sourceMappingURL=flywheel-Cqf8vu7N.js.map