@overdeck/core 0.50.3 → 0.50.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/dist/agents-DNMRPC8n.js.map +1 -1
  2. package/dist/{build-info-BJuEVWOh.js → build-info-ioRdOmqT.js} +3 -3
  3. package/dist/{build-info-BJuEVWOh.js.map → build-info-ioRdOmqT.js.map} +1 -1
  4. package/dist/build-info-kMMitDOP.js +2 -0
  5. package/dist/cli/index.js +4 -4
  6. package/dist/conversation-compaction-GFfO5UZL.js.map +1 -1
  7. package/dist/dashboard/{advancing-selfheal-Bq8V0QUa.js → advancing-selfheal-Dp5_Gai3.js} +3 -3
  8. package/dist/dashboard/{advancing-selfheal-Bq8V0QUa.js.map → advancing-selfheal-Dp5_Gai3.js.map} +1 -1
  9. package/dist/dashboard/{agent-gc-Coz8zQt_.js → agent-gc-JzoSs5Pi.js} +3 -3
  10. package/dist/dashboard/{agent-gc-Coz8zQt_.js.map → agent-gc-JzoSs5Pi.js.map} +1 -1
  11. package/dist/dashboard/{agent-idle-CAwB-K6M.js → agent-idle-D-Qy5BN_.js} +2 -2
  12. package/dist/dashboard/{agent-idle-CAwB-K6M.js.map → agent-idle-D-Qy5BN_.js.map} +1 -1
  13. package/dist/dashboard/{agent-state-Ci6PhjOE.js → agent-state-B196fj1h.js} +38 -16
  14. package/dist/dashboard/agent-state-B196fj1h.js.map +1 -0
  15. package/dist/dashboard/{agent-state-CbUEwUEQ.js → agent-state-IpWnw8lv.js} +1 -1
  16. package/dist/dashboard/{agent-state-service-D6IVrX3B.js → agent-state-service-CCo5-9DR.js} +3 -3
  17. package/dist/dashboard/{agent-state-service-D6IVrX3B.js.map → agent-state-service-CCo5-9DR.js.map} +1 -1
  18. package/dist/dashboard/{agent-state-service-DcN1j6eK.js → agent-state-service-D_F3VZ23.js} +1 -1
  19. package/dist/dashboard/{agents-BVvL4o_4.js → agents-CkGhnAmu.js} +1 -1
  20. package/dist/dashboard/{backlog-auto-trigger-BuSBqG2V.js → backlog-auto-trigger-B5Z2zBtC.js} +2 -2
  21. package/dist/dashboard/{backlog-auto-trigger-BuSBqG2V.js.map → backlog-auto-trigger-B5Z2zBtC.js.map} +1 -1
  22. package/dist/dashboard/build-info-BTjOB0Xr.js +2 -0
  23. package/dist/dashboard/{build-info-Cj3Y0K87.js → build-info-D0EJNj6C.js} +3 -3
  24. package/dist/dashboard/{build-info-Cj3Y0K87.js.map → build-info-D0EJNj6C.js.map} +1 -1
  25. package/dist/dashboard/cli-CIznFrcE.js +2 -0
  26. package/dist/dashboard/{cli-DIhQieif.js → cli-DCbVrSsg.js} +2 -2
  27. package/dist/dashboard/{cli-DIhQieif.js.map → cli-DCbVrSsg.js.map} +1 -1
  28. package/dist/dashboard/{close-issue-CRlmrE5g.js → close-issue-Bmu9aOIx.js} +2 -2
  29. package/dist/dashboard/{close-issue-CRlmrE5g.js.map → close-issue-Bmu9aOIx.js.map} +1 -1
  30. package/dist/dashboard/{closed-issue-reaper-DrHyYgJR.js → closed-issue-reaper-COxfTtLz.js} +5 -5
  31. package/dist/dashboard/{closed-issue-reaper-DrHyYgJR.js.map → closed-issue-reaper-COxfTtLz.js.map} +1 -1
  32. package/dist/dashboard/{closed-issue-reaper-DWlw2EtL.js → closed-issue-reaper-DwMwG_Pz.js} +1 -1
  33. package/dist/dashboard/{compaction-continuation-DhYgsXmF.js → compaction-continuation-Bqc212Zm.js} +2 -2
  34. package/dist/dashboard/{compaction-continuation-DhYgsXmF.js.map → compaction-continuation-Bqc212Zm.js.map} +1 -1
  35. package/dist/dashboard/{conflict-gate-vczgdVTa.js → conflict-gate-9mPVg7-5.js} +1 -1
  36. package/dist/dashboard/{conflict-gate-Bt-lLgYf.js → conflict-gate-CGQTcR0I.js} +3 -3
  37. package/dist/dashboard/{conflict-gate-Bt-lLgYf.js.map → conflict-gate-CGQTcR0I.js.map} +1 -1
  38. package/dist/dashboard/{conversation-compaction-CsdCbcQB.js → conversation-compaction-C7P6V8Iw.js} +5 -5
  39. package/dist/dashboard/{conversation-compaction-CsdCbcQB.js.map → conversation-compaction-C7P6V8Iw.js.map} +1 -1
  40. package/dist/dashboard/{conversation-compaction-D0zgWM1f.js → conversation-compaction-Cck5oi-V.js} +1 -1
  41. package/dist/dashboard/{conversation-service-6LaymUV-.js → conversation-service-CsOpwI9Y.js} +37 -5
  42. package/dist/dashboard/{conversation-service-6LaymUV-.js.map → conversation-service-CsOpwI9Y.js.map} +1 -1
  43. package/dist/dashboard/conversation-service-plOFkoMo.js +3 -0
  44. package/dist/dashboard/dashboard-db-worker.js +1 -1
  45. package/dist/dashboard/{deacon-CU47dU7U.js → deacon-B8oMMIgN.js} +62 -62
  46. package/dist/dashboard/{deacon-CU47dU7U.js.map → deacon-B8oMMIgN.js.map} +1 -1
  47. package/dist/dashboard/{deacon-DYsOa_ss.js → deacon-b7J57Svt.js} +2 -2
  48. package/dist/dashboard/{deacon-pending-lifecycle-ijGX8wLb.js → deacon-pending-lifecycle-3NIJ7ew5.js} +2 -2
  49. package/dist/dashboard/{deacon-pending-lifecycle-ijGX8wLb.js.map → deacon-pending-lifecycle-3NIJ7ew5.js.map} +1 -1
  50. package/dist/dashboard/deacon.js +5 -5
  51. package/dist/dashboard/{delivery-DMYxIE0J.js → delivery-lnI-gQKo.js} +1 -1
  52. package/dist/dashboard/{deploy-patrol-C4eXco1S.js → deploy-patrol-u3v2krg9.js} +2 -2
  53. package/dist/dashboard/{deploy-patrol-C4eXco1S.js.map → deploy-patrol-u3v2krg9.js.map} +1 -1
  54. package/dist/dashboard/{feedback-stuck-retirement-Dd5XNrMr.js → feedback-stuck-retirement-CoFNqjCc.js} +2 -2
  55. package/dist/dashboard/{feedback-stuck-retirement-Dd5XNrMr.js.map → feedback-stuck-retirement-CoFNqjCc.js.map} +1 -1
  56. package/dist/dashboard/{feedback-target-BzdJ2wIR.js → feedback-target-BBCh3RRq.js} +1 -1
  57. package/dist/dashboard/{feedback-target-BcsA_GRV.js → feedback-target-CeCq6EhW.js} +5 -5
  58. package/dist/dashboard/{feedback-target-BcsA_GRV.js.map → feedback-target-CeCq6EhW.js.map} +1 -1
  59. package/dist/dashboard/{flywheel-Is3w2lcT.js → flywheel-DKldI63J.js} +7 -7
  60. package/dist/dashboard/{flywheel-Is3w2lcT.js.map → flywheel-DKldI63J.js.map} +1 -1
  61. package/dist/dashboard/{flywheel-D0guNqkh.js → flywheel-DpRPLErh.js} +7 -7
  62. package/dist/dashboard/{flywheel-D0guNqkh.js.map → flywheel-DpRPLErh.js.map} +1 -1
  63. package/dist/dashboard/{flywheel-B34cdfbd.js → flywheel-jeZFYvm-.js} +1 -1
  64. package/dist/dashboard/{flywheel-merge-order-6HiPR2WG.js → flywheel-merge-order-0OnoosaO.js} +1 -1
  65. package/dist/dashboard/{flywheel-merge-order-BsNPMu0S.js → flywheel-merge-order-PG5op4j7.js} +2 -2
  66. package/dist/dashboard/{flywheel-merge-order-BsNPMu0S.js.map → flywheel-merge-order-PG5op4j7.js.map} +1 -1
  67. package/dist/dashboard/{harness-resolve-CzTFVZ5l.js → harness-resolve-C0HWj3H9.js} +2 -2
  68. package/dist/dashboard/{harness-resolve-CzTFVZ5l.js.map → harness-resolve-C0HWj3H9.js.map} +1 -1
  69. package/dist/dashboard/{identity-Dc7rQLln.js → identity-Cot1Hg4G.js} +2 -2
  70. package/dist/dashboard/{identity-Dc7rQLln.js.map → identity-Cot1Hg4G.js.map} +1 -1
  71. package/dist/dashboard/{inspect-agent-CP7Bu47O.js → inspect-agent-BDmLWbGx.js} +3 -3
  72. package/dist/dashboard/{inspect-agent-CP7Bu47O.js.map → inspect-agent-BDmLWbGx.js.map} +1 -1
  73. package/dist/dashboard/inspect-agent-BcOkA-hC.js +2 -0
  74. package/dist/dashboard/{issue-lifecycle-BPbczKyy.js → issue-lifecycle-1B_v8Rf5.js} +6 -6
  75. package/dist/dashboard/{issue-lifecycle-BPbczKyy.js.map → issue-lifecycle-1B_v8Rf5.js.map} +1 -1
  76. package/dist/dashboard/{issue-lifecycle-FaugTi39.js → issue-lifecycle-CIrfbIbj.js} +1 -1
  77. package/dist/dashboard/{issue-service-singleton-Dsad9NTt.js → issue-service-singleton-BVwPzjwF.js} +1 -1
  78. package/dist/dashboard/{issue-service-singleton-BrZQJLRI.js → issue-service-singleton-KcRrOiFD.js} +2 -2
  79. package/dist/dashboard/{issue-service-singleton-BrZQJLRI.js.map → issue-service-singleton-KcRrOiFD.js.map} +1 -1
  80. package/dist/dashboard/{jsonl-resolver-DQEe0DHM.js → jsonl-resolver-jxbif7MD.js} +3 -3
  81. package/dist/dashboard/{jsonl-resolver-DQEe0DHM.js.map → jsonl-resolver-jxbif7MD.js.map} +1 -1
  82. package/dist/dashboard/{kimi-code-Cx5YUJpS.js → kimi-code-BZh3NgcN.js} +1 -1
  83. package/dist/dashboard/{lifecycle-DZFHmpGI.js → lifecycle-CvcZ4_fA.js} +4 -4
  84. package/dist/dashboard/{lifecycle-DZFHmpGI.js.map → lifecycle-CvcZ4_fA.js.map} +1 -1
  85. package/dist/dashboard/{linear-mcp-auth-DylPJABZ.js → linear-mcp-auth-CZoj_-d7.js} +1 -1
  86. package/dist/dashboard/{linear-mcp-auth-BFlpMvWh.js → linear-mcp-auth-Dx74yCAY.js} +2 -2
  87. package/dist/dashboard/{linear-mcp-auth-BFlpMvWh.js.map → linear-mcp-auth-Dx74yCAY.js.map} +1 -1
  88. package/dist/dashboard/{memory-governor-B7uDWRo9.js → memory-governor-Bv3LAqk3.js} +5 -5
  89. package/dist/dashboard/{memory-governor-B7uDWRo9.js.map → memory-governor-Bv3LAqk3.js.map} +1 -1
  90. package/dist/dashboard/{merge-agent-ddEcZDZD.js → merge-agent-1zVLl6k_.js} +1 -1
  91. package/dist/dashboard/{merge-agent-ttRY053V.js → merge-agent-8zrQu48t.js} +8 -8
  92. package/dist/dashboard/{merge-agent-ttRY053V.js.map → merge-agent-8zrQu48t.js.map} +1 -1
  93. package/dist/dashboard/merge-ops-CFJaMPLu.js +2 -0
  94. package/dist/dashboard/{merge-train-f_un38UJ.js → merge-train-BYH_cF7G.js} +2 -2
  95. package/dist/dashboard/{merge-train-f_un38UJ.js.map → merge-train-BYH_cF7G.js.map} +1 -1
  96. package/dist/dashboard/{merge-train-deps-GPlHOjK6.js → merge-train-deps-BTfXM5AR.js} +2 -2
  97. package/dist/dashboard/{merge-train-deps-GPlHOjK6.js.map → merge-train-deps-BTfXM5AR.js.map} +1 -1
  98. package/dist/dashboard/{messaging-BasbftDu.js → messaging-Bk6vGsMw.js} +1 -1
  99. package/dist/dashboard/{orphan-proposed-reconciler-DFHdQSEg.js → orphan-proposed-reconciler-B898fk26.js} +6 -6
  100. package/dist/dashboard/{orphan-proposed-reconciler-DFHdQSEg.js.map → orphan-proposed-reconciler-B898fk26.js.map} +1 -1
  101. package/dist/dashboard/{orphan-proposed-reconciler-DzAxrM99.js → orphan-proposed-reconciler-Bx_aWS4B.js} +1 -1
  102. package/dist/dashboard/{parked-residue-DMtbxJml.js → parked-residue-q2kzrYSm.js} +9 -9
  103. package/dist/dashboard/{parked-residue-DMtbxJml.js.map → parked-residue-q2kzrYSm.js.map} +1 -1
  104. package/dist/dashboard/{post-merge-lifecycle-worker-jzN2g_EY.js → post-merge-lifecycle-worker-Cl7-uf4g.js} +2 -2
  105. package/dist/dashboard/{post-merge-lifecycle-worker-jzN2g_EY.js.map → post-merge-lifecycle-worker-Cl7-uf4g.js.map} +1 -1
  106. package/dist/dashboard/{project-resource-refresh-queue-cqOeJ0fB.js → project-resource-refresh-queue-O_dRfPHn.js} +1 -1
  107. package/dist/dashboard/{project-resource-refresh-queue-DebwjPPA.js → project-resource-refresh-queue-se3T9IYP.js} +4 -4
  108. package/dist/dashboard/{project-resource-refresh-queue-DebwjPPA.js.map → project-resource-refresh-queue-se3T9IYP.js.map} +1 -1
  109. package/dist/dashboard/{reconstruct-cache-Bb2Jg2DZ.js → reconstruct-cache-XpWC9L0F.js} +2 -2
  110. package/dist/dashboard/{reconstruct-cache-Bb2Jg2DZ.js.map → reconstruct-cache-XpWC9L0F.js.map} +1 -1
  111. package/dist/dashboard/{release-engine-78iCajIc.js → release-engine-BuzxOamf.js} +2 -2
  112. package/dist/dashboard/{release-engine-78iCajIc.js.map → release-engine-BuzxOamf.js.map} +1 -1
  113. package/dist/dashboard/{remote-completion-D5wzZCte.js → remote-completion-BCZgeKPS.js} +3 -3
  114. package/dist/dashboard/{remote-completion-D5wzZCte.js.map → remote-completion-BCZgeKPS.js.map} +1 -1
  115. package/dist/dashboard/{resolver-BGZh3lXA.js → resolver-BeNrqNou.js} +5 -5
  116. package/dist/dashboard/{resolver-BGZh3lXA.js.map → resolver-BeNrqNou.js.map} +1 -1
  117. package/dist/dashboard/{resource-pressure-patrol-Bg23rPV-.js → resource-pressure-patrol-Ccg_aCgO.js} +3 -3
  118. package/dist/dashboard/{resource-pressure-patrol-Bg23rPV-.js.map → resource-pressure-patrol-Ccg_aCgO.js.map} +1 -1
  119. package/dist/dashboard/{resume-BKyB4hA1.js → resume-KGCrn0DV.js} +1 -1
  120. package/dist/dashboard/{review-agent-ZdP-HmwY.js → review-agent-BmM6YMZW.js} +1 -1
  121. package/dist/dashboard/{review-agent-DHs-JngN.js → review-agent-DRWVU8fP.js} +13 -13
  122. package/dist/dashboard/{review-agent-DHs-JngN.js.map → review-agent-DRWVU8fP.js.map} +1 -1
  123. package/dist/dashboard/{review-convoy-liveness-BTMvU4CA.js → review-convoy-liveness-EvCDv8Q_.js} +3 -3
  124. package/dist/dashboard/{review-convoy-liveness-BTMvU4CA.js.map → review-convoy-liveness-EvCDv8Q_.js.map} +1 -1
  125. package/dist/dashboard/{review-run-recovery-BYalQzbh.js → review-run-recovery-Ctm48Snt.js} +1 -1
  126. package/dist/dashboard/{review-run-recovery-BvVG3oUr.js → review-run-recovery-DNDI58cM.js} +2 -2
  127. package/dist/dashboard/{review-run-recovery-BvVG3oUr.js.map → review-run-recovery-DNDI58cM.js.map} +1 -1
  128. package/dist/dashboard/{review-status-DXTFzCmR.js → review-status-FnlvQuPI.js} +1 -1
  129. package/dist/dashboard/{review-status-emit-C9YW6SQL.js → review-status-emit-CeMS31DX.js} +2 -2
  130. package/dist/dashboard/{review-status-emit-C9YW6SQL.js.map → review-status-emit-CeMS31DX.js.map} +1 -1
  131. package/dist/dashboard/{review-status-BegAr86G.js → review-status-yY5qt7Rl.js} +5 -5
  132. package/dist/dashboard/{review-status-BegAr86G.js.map → review-status-yY5qt7Rl.js.map} +1 -1
  133. package/dist/dashboard/{review-verdict-feedback-qlVBi19-.js → review-verdict-feedback-BNgRj1e3.js} +4 -4
  134. package/dist/dashboard/{review-verdict-feedback-qlVBi19-.js.map → review-verdict-feedback-BNgRj1e3.js.map} +1 -1
  135. package/dist/dashboard/{review-verdict-feedback-Dp139Lmv.js → review-verdict-feedback-D39cuSV1.js} +1 -1
  136. package/dist/dashboard/{review-verdict-writer-CJr_Ob0Y.js → review-verdict-writer-DvFfKAn-.js} +2 -2
  137. package/dist/dashboard/{review-verdict-writer-CJr_Ob0Y.js.map → review-verdict-writer-DvFfKAn-.js.map} +1 -1
  138. package/dist/dashboard/{review-verdict-writer-BVco3WoI.js → review-verdict-writer-PcGBkvJ4.js} +1 -1
  139. package/dist/dashboard/{sequence-io-iljWlslY.js → sequence-io-DZyschsf.js} +2 -2
  140. package/dist/dashboard/{sequence-io-iljWlslY.js.map → sequence-io-DZyschsf.js.map} +1 -1
  141. package/dist/dashboard/{sequencer-agent-BGGVKxtw.js → sequencer-agent-BXDw5cNx.js} +5 -5
  142. package/dist/dashboard/{sequencer-agent-BGGVKxtw.js.map → sequencer-agent-BXDw5cNx.js.map} +1 -1
  143. package/dist/dashboard/server.js +79 -72
  144. package/dist/dashboard/server.js.map +1 -1
  145. package/dist/dashboard/{service-kzhN0DLg.js → service-DP50Omvn.js} +33 -33
  146. package/dist/dashboard/{service-kzhN0DLg.js.map → service-DP50Omvn.js.map} +1 -1
  147. package/dist/dashboard/{smart-compaction-owKHJDbL.js → smart-compaction-944GL8PN.js} +1 -1
  148. package/dist/dashboard/{smart-compaction-C96F2aFQ.js → smart-compaction-BzDfF6yb.js} +2 -2
  149. package/dist/dashboard/{smart-compaction-C96F2aFQ.js.map → smart-compaction-BzDfF6yb.js.map} +1 -1
  150. package/dist/dashboard/{spawn-planning-session-CiJdOHTD.js → spawn-planning-session-BcVnHJjm.js} +1 -1
  151. package/dist/dashboard/{spawn-planning-session-FmJa6PCS.js → spawn-planning-session-CH8IYli7.js} +3 -3
  152. package/dist/dashboard/{spawn-planning-session-FmJa6PCS.js.map → spawn-planning-session-CH8IYli7.js.map} +1 -1
  153. package/dist/dashboard/{specialist-context-_ootmzn2.js → specialist-context-DhDTXVht.js} +3 -3
  154. package/dist/dashboard/{specialist-context-_ootmzn2.js.map → specialist-context-DhDTXVht.js.map} +1 -1
  155. package/dist/dashboard/{specialist-logs-BbAX221-.js → specialist-logs-C1bcnZ-G.js} +2 -2
  156. package/dist/dashboard/{specialist-logs-BbAX221-.js.map → specialist-logs-C1bcnZ-G.js.map} +1 -1
  157. package/dist/dashboard/{specialists-COZoYaiz.js → specialists-BKmReEWT.js} +53 -53
  158. package/dist/dashboard/{specialists-COZoYaiz.js.map → specialists-BKmReEWT.js.map} +1 -1
  159. package/dist/dashboard/{specialists-RPLJnYc1.js → specialists-Bvrvt0br.js} +12 -12
  160. package/dist/dashboard/{specialists-RPLJnYc1.js.map → specialists-Bvrvt0br.js.map} +1 -1
  161. package/dist/dashboard/{specialists-DTAOVZpU.js → specialists-CD6GEKXk.js} +1 -1
  162. package/dist/dashboard/{specialists-D8sYZnPb.js → specialists-eFWpJRBc.js} +1 -1
  163. package/dist/dashboard/{stall-sweeper-9bRBZhrQ.js → stall-sweeper-D3fZvg7O.js} +3 -3
  164. package/dist/dashboard/{stall-sweeper-9bRBZhrQ.js.map → stall-sweeper-D3fZvg7O.js.map} +1 -1
  165. package/dist/dashboard/{state-migrate-J3tFJnbd.js → state-migrate-KZ2goscQ.js} +2 -2
  166. package/dist/dashboard/{state-migrate-J3tFJnbd.js.map → state-migrate-KZ2goscQ.js.map} +1 -1
  167. package/dist/dashboard/{stuck-remediation-BvTK_NYN.js → stuck-remediation-Cb2V1roj.js} +1 -1
  168. package/dist/dashboard/{stuck-remediation-4Rf_xMEb.js → stuck-remediation-CnoV0kcv.js} +5 -5
  169. package/dist/dashboard/{stuck-remediation-4Rf_xMEb.js.map → stuck-remediation-CnoV0kcv.js.map} +1 -1
  170. package/dist/dashboard/{summary-fork-PLcckTRE.js → summary-fork-CxuNBM0F.js} +2 -2
  171. package/dist/dashboard/{summary-fork-D-cylknJ.js → summary-fork-lC2vMXly.js} +4 -4
  172. package/dist/dashboard/{summary-fork-D-cylknJ.js.map → summary-fork-lC2vMXly.js.map} +1 -1
  173. package/dist/dashboard/{teardown-workspace-CTL16rnG.js → teardown-workspace-C-9murBw.js} +4 -4
  174. package/dist/dashboard/{teardown-workspace-CTL16rnG.js.map → teardown-workspace-C-9murBw.js.map} +1 -1
  175. package/dist/dashboard/{test-agent-queue-CMgYZiR_.js → test-agent-queue-YCBRzaAB.js} +3 -3
  176. package/dist/dashboard/{test-agent-queue-CMgYZiR_.js.map → test-agent-queue-YCBRzaAB.js.map} +1 -1
  177. package/dist/dashboard/{uat-failure-feedback-DS6W9X3I.js → uat-failure-feedback-B-1mL8Zp.js} +3 -3
  178. package/dist/dashboard/{uat-failure-feedback-DS6W9X3I.js.map → uat-failure-feedback-B-1mL8Zp.js.map} +1 -1
  179. package/dist/dashboard/{uat-promote-verification-CRsIHE_q.js → uat-promote-verification-BEBPcpPg.js} +2 -2
  180. package/dist/dashboard/{uat-promote-verification-CRsIHE_q.js.map → uat-promote-verification-BEBPcpPg.js.map} +1 -1
  181. package/dist/dashboard/{uat-train-BoA9r6_I.js → uat-train-BFo3OQUB.js} +1 -1
  182. package/dist/dashboard/{uat-train-Cd8CJeNe.js → uat-train-COgoJomz.js} +8 -8
  183. package/dist/dashboard/{uat-train-Cd8CJeNe.js.map → uat-train-COgoJomz.js.map} +1 -1
  184. package/dist/dashboard/{validate-BdmvTIym.js → validate-069_N1e2.js} +2 -2
  185. package/dist/dashboard/{validate-BdmvTIym.js.map → validate-069_N1e2.js.map} +1 -1
  186. package/dist/dashboard/{verification-runner-BO0K3xNA.js → verification-runner-CQnZyC5A.js} +1 -1
  187. package/dist/dashboard/{verification-runner-fEY1Qj-l.js → verification-runner-fy3wNrWn.js} +4 -4
  188. package/dist/dashboard/{verification-runner-fEY1Qj-l.js.map → verification-runner-fy3wNrWn.js.map} +1 -1
  189. package/dist/dashboard/workflows-Bk6Kt0ZQ.js +2 -0
  190. package/dist/dashboard/{workflows-CxVnygYU.js → workflows-N4QMkDzN.js} +10 -10
  191. package/dist/dashboard/{workflows-CxVnygYU.js.map → workflows-N4QMkDzN.js.map} +1 -1
  192. package/dist/dashboard/{workspaces-Cpz0xJWQ.js → workspaces-DmoyfHoU.js} +33 -33
  193. package/dist/dashboard/{workspaces-Cpz0xJWQ.js.map → workspaces-DmoyfHoU.js.map} +1 -1
  194. package/dist/{lifecycle-C6k0HWEO.js → lifecycle-DCFcjg7y.js} +1 -1
  195. package/dist/{lifecycle-D5oRpvvB.js → lifecycle-GkaHQJNK.js} +2 -2
  196. package/dist/{lifecycle-D5oRpvvB.js.map → lifecycle-GkaHQJNK.js.map} +1 -1
  197. package/dist/{merge-agent-Drufc7tU.js → merge-agent-CogNFasY.js} +2 -2
  198. package/dist/{merge-agent-Drufc7tU.js.map → merge-agent-CogNFasY.js.map} +1 -1
  199. package/dist/{merge-agent-CBOVY_eC.js → merge-agent-eteKQ9Rb.js} +1 -1
  200. package/package.json +1 -1
  201. package/dist/build-info-BgrwLUy6.js +0 -2
  202. package/dist/dashboard/agent-state-Ci6PhjOE.js.map +0 -1
  203. package/dist/dashboard/build-info-CYlxvZSQ.js +0 -2
  204. package/dist/dashboard/cli-ZAS502uC.js +0 -2
  205. package/dist/dashboard/conversation-service-Dlks_hSS.js +0 -3
  206. package/dist/dashboard/inspect-agent-DTuSg95i.js +0 -2
  207. package/dist/dashboard/merge-ops-Bgc-EScO.js +0 -2
  208. package/dist/dashboard/workflows-CgGNyl1z.js +0 -2
@@ -1 +1 @@
1
- {"version":3,"file":"flywheel-merge-order-BsNPMu0S.js","names":[],"sources":["../../src/lib/flywheel-merge-order.ts"],"sourcesContent":["import { Effect } from 'effect';\nimport { ChildProcess, ChildProcessSpawner } from 'effect/unstable/process';\nimport type { FlywheelPipelineItem } from '@overdeck/contracts';\nimport { getReviewStatusSync, loadReviewStatuses, mergeGateEligibility, type MergeGateEligibility } from './review-status.js';\nimport { resolveGitHubIssueSync } from './tracker-utils.js';\nimport type { SequenceNode } from './backlog/types.js';\nimport { classifyIssue, isAutoPickable, type ClassifyLookups } from './backlog/pickup.js';\nimport { compileGlob, type CompiledGlob } from './xbrief/dag.js';\nimport { computeIssueFootprint } from './xbrief/swarm-readiness.js';\nimport type { XBriefDocument } from './xbrief/types.js';\nimport { findProjectByPathSync, getProjectSwarmHotspots, resolveProjectFromIssueSync } from './projects.js';\nimport type { ResolvedProjectRepo } from './project-repos.js';\n\nexport interface MergeQueueItem {\n issueId: string;\n title: string;\n branchName: string;\n pr?: number;\n prUrl?: string;\n mergeOrder: number;\n conflictsWith: string[];\n /** PAN-1691: 'batch' = disjoint, mergeable together in one pass; 'serialize' = conflicts, must go one at a time. */\n batchGroup?: 'batch' | 'serialize';\n}\n\nfunction issueNumber(issueId: string): number {\n const match = issueId.match(/\\d+$/);\n return match ? parseInt(match[0], 10) : 0;\n}\n\nexport interface MergeCandidateMeta {\n issueId: string;\n /** Number of files this branch changes vs main. */\n footprint: number;\n /** How many other ready branches this one overlaps files with. */\n conflictCount: number;\n}\n\nexport type FootprintSource = 'declared' | 'actual';\n\nexport interface IssueFileFootprint {\n issueId: string;\n files: Iterable<string>;\n source: FootprintSource;\n}\n\nexport interface PredictedConflictSignal extends MergeCandidateMeta {\n source: FootprintSource;\n conflictsWith: string[];\n}\n\n/**\n * PAN-1691 conflict-aware merge order. Disjoint (no-conflict) items come first\n * so they can batch through in a single verification pass; then conflicting\n * items broadest-file-footprint first, so the remaining cluster members rebase\n * once onto the worst offender instead of repeatedly. Issue number is the\n * stable tiebreak within each tier. Pure — exported for testing.\n */\nexport function orderMergeCandidates<T extends MergeCandidateMeta>(items: ReadonlyArray<T>): T[] {\n return [...items].sort((a, b) => {\n const aConf = a.conflictCount > 0 ? 1 : 0;\n const bConf = b.conflictCount > 0 ? 1 : 0;\n if (aConf !== bConf) return aConf - bConf;\n if (aConf === 1 && a.footprint !== b.footprint) return b.footprint - a.footprint;\n return issueNumber(a.issueId) - issueNumber(b.issueId);\n });\n}\n\nexport interface MergeTrainPlan {\n /** Disjoint candidates that can merge together in one verification pass. */\n batch: string[];\n /** Conflicting candidates that must serialize, broadest-footprint first. */\n serialize: string[];\n /** Full ordered list (batch, then serialize). */\n order: string[];\n}\n\n/**\n * PAN-1691 merge-train plan. Partitions the conflict-aware order into the run of\n * disjoint candidates — which can all merge in a single verification pass — and\n * the conflicting remainder, which must serialize broadest-footprint first.\n * Pure; the executor consumes this once the merge-train flag is enabled.\n */\nexport function planMergeTrain<T extends MergeCandidateMeta>(candidates: ReadonlyArray<T>): MergeTrainPlan {\n const ordered = orderMergeCandidates(candidates);\n return {\n batch: ordered.filter((c) => c.conflictCount === 0).map((c) => c.issueId),\n serialize: ordered.filter((c) => c.conflictCount > 0).map((c) => c.issueId),\n order: ordered.map((c) => c.issueId),\n };\n}\n\nexport function declaredIssueFootprint(issueId: string, doc: XBriefDocument): IssueFileFootprint {\n return { issueId, files: computeIssueFootprint(doc), source: 'declared' };\n}\n\nfunction pathMatchesAnyCompiled(filePath: string, patterns: CompiledGlob[]): boolean {\n return patterns.some(pattern => pattern.regex.test(filePath) || pattern.exactDirectory === filePath);\n}\n\nfunction normalizedFootprintFiles(files: Iterable<string>, hotspots: CompiledGlob[]): Set<string> {\n const normalized = new Set<string>();\n for (const file of files) {\n if (!file || pathMatchesAnyCompiled(file, hotspots)) continue;\n normalized.add(file);\n }\n return normalized;\n}\n\nfunction sourcePriority(source: FootprintSource): number {\n return source === 'actual' ? 2 : 1;\n}\n\nexport function computePredictedConflictSignals(\n footprints: ReadonlyArray<IssueFileFootprint>,\n options: { hotspots?: string[] } = {},\n): PredictedConflictSignal[] {\n const hotspots = (options.hotspots ?? []).map(compileGlob);\n const byIssue = new Map<string, { issueId: string; source: FootprintSource; files: Set<string> }>();\n\n for (const footprint of footprints) {\n const files = normalizedFootprintFiles(footprint.files, hotspots);\n const current = byIssue.get(footprint.issueId);\n if (!current || sourcePriority(footprint.source) > sourcePriority(current.source)) {\n byIssue.set(footprint.issueId, { issueId: footprint.issueId, source: footprint.source, files });\n continue;\n }\n if (sourcePriority(footprint.source) === sourcePriority(current.source)) {\n for (const file of files) current.files.add(file);\n }\n }\n\n const conflictsMap = new Map<string, Set<string>>();\n const entries = Array.from(byIssue.values());\n for (let i = 0; i < entries.length; i++) {\n for (let j = i + 1; j < entries.length; j++) {\n const left = entries[i]!;\n const right = entries[j]!;\n if (![...left.files].some(file => right.files.has(file))) continue;\n if (!conflictsMap.has(left.issueId)) conflictsMap.set(left.issueId, new Set());\n if (!conflictsMap.has(right.issueId)) conflictsMap.set(right.issueId, new Set());\n conflictsMap.get(left.issueId)!.add(right.issueId);\n conflictsMap.get(right.issueId)!.add(left.issueId);\n }\n }\n\n return entries.map(entry => {\n const conflictsWith = [...(conflictsMap.get(entry.issueId) ?? [])]\n .sort((a, b) => issueNumber(a) - issueNumber(b));\n return {\n issueId: entry.issueId,\n source: entry.source,\n footprint: entry.files.size,\n conflictCount: conflictsWith.length,\n conflictsWith,\n };\n });\n}\n\nexport interface UatCandidatePlan {\n /** Branch name for the on-demand UAT candidate (auto-merge-OFF mode). */\n branchName: string;\n /** Issue IDs bundled onto the candidate — the disjoint, mergeable-together batch. */\n bundled: string[];\n}\n\n/**\n * PAN-1691 on-demand UAT candidate. In auto-merge-OFF mode the disjoint \"batch\"\n * (everything that can merge together in one verification pass) is bundled onto\n * a single throwaway branch the human UATs in one sitting. Pure — `dateIso` is\n * injected, and it reads the already-computed `batchGroup` off the merge queue.\n */\nexport function planUatCandidate(\n queue: ReadonlyArray<MergeQueueItem>,\n opts: { dateIso: string; label?: string },\n): UatCandidatePlan {\n const bundled = queue.filter((i) => i.batchGroup === 'batch').map((i) => i.issueId);\n const day = opts.dateIso.slice(0, 10);\n return { branchName: `uat/${opts.label ?? 'candidate'}-${day}`, bundled };\n}\n\nconst branchExists = (branch: string, cwd: string) =>\n Effect.gen(function*() {\n const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;\n const cmd = ChildProcess.make('git', ['rev-parse', '--verify', branch], { cwd });\n return yield* spawner.exitCode(cmd).pipe(\n Effect.map((code) => code === 0),\n Effect.orElseSucceed(() => false),\n );\n });\n\nexport const changedFilesVsMain = (branch: string, cwd: string, base = 'main') =>\n Effect.gen(function*() {\n const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;\n const cmd = ChildProcess.make('git', ['diff', '--name-only', `${base}...${branch}`], { cwd });\n return yield* spawner.string(cmd).pipe(\n Effect.map((stdout) => new Set(stdout.trim().split('\\n').filter(Boolean))),\n Effect.orElseSucceed(() => new Set<string>()),\n );\n });\n\nexport const MERGE_QUEUE_GIT_CONCURRENCY = 4;\n\nexport interface ComputeMergeQueueOptions {\n getPrUrl?: (item: { issueId: string; pr?: number }) => string | undefined;\n gitConcurrency?: number;\n /**\n * Authoritative merge eligibility per issue (PAN-1759). Defaults to the\n * review-status DB predicate; injectable for tests. The verb filter alone is\n * the orchestrator's INTENT — an LLM emission that has tagged mid-review\n * issues as merge-bound. Only verb ∩ eligibility enters the queue.\n */\n eligibility?: (issueId: string) => MergeGateEligibility;\n /** Called for each verb-tagged item the eligibility gate rejects. */\n onIneligible?: (issueId: string, reason: string) => void;\n /** Files treated as common hotspots and excluded from predicted-conflict math. */\n hotspots?: string[];\n}\n\n/** Default eligibility: the issue's review-status record, read synchronously. */\nexport function reviewRecordEligibility(issueId: string): MergeGateEligibility {\n return mergeGateEligibility(getReviewStatusSync(issueId.toUpperCase()));\n}\n\n/**\n * Server-side PR URL resolution for merge-queue items: prefer the review\n * status record, fall back to the GitHub repo + PR number — the browser never\n * guesses repo slugs.\n */\nexport function resolveMergeQueuePrUrl(item: { issueId: string; pr?: number }): string | undefined {\n const issueId = item.issueId.toUpperCase();\n const reviewStatus = getReviewStatusSync(issueId);\n if (reviewStatus?.prUrl) return reviewStatus.prUrl;\n\n const prNumber = reviewStatus?.prNumber ?? item.pr;\n if (prNumber === undefined) return undefined;\n\n const githubIssue = resolveGitHubIssueSync(issueId);\n if (!githubIssue.isGitHub) return undefined;\n return `https://github.com/${githubIssue.owner}/${githubIssue.repo}/pull/${prNumber}`;\n}\n\n/**\n * PAN-1696 ready-set-source: List all merge-eligible candidates from review-status DB for a given project.\n * No flywheel run required — sources directly from persistent pipeline state.\n * Returns an array of candidate items compatible with computeMergeQueueFromCandidates.\n */\nexport async function listEligibleCandidatesByProject(projectRoot: string): Promise<Array<{ issueId: string; title: string; pr?: number }>> {\n const project = findProjectByPathSync(projectRoot);\n if (!project) return [];\n\n const allStatuses = loadReviewStatuses();\n const readyStatuses = Object.entries(allStatuses).filter(([issueId, rs]) => {\n const issueProject = resolveProjectFromIssueSync(issueId);\n return issueProject?.projectPath === project.path &&\n rs.deaconIgnored !== true && rs.readyForMerge === true && mergeGateEligibility(rs).eligible;\n });\n const { gatherMergeEligibility, isMergeEligible } = await import('./cloister/merge-eligibility.js');\n const memberships = await gatherMergeEligibility(readyStatuses.map(([issueId]) => issueId));\n const candidates: Array<{ issueId: string; title: string; pr?: number }> = [];\n\n for (const [issueId, rs] of readyStatuses) {\n const membership = memberships.get(issueId.toUpperCase());\n if (!membership || !isMergeEligible(membership)) continue;\n\n // AC 10: title resolved downstream by computeMergeQueueFromCandidates; here use issue ID\n candidates.push({ issueId, title: issueId, pr: rs.prNumber });\n }\n\n return candidates;\n}\n\n/**\n * PAN-1696 ready-set-source: Compute merge queue from a pre-filtered candidate list.\n * Accepts candidates from review-status or flywheel pipeline — decouples the source.\n * This refactored version extracts the core conflict-analysis logic from computeMergeQueue.\n */\nexport const computeMergeQueueFromCandidates = (\n candidates: ReadonlyArray<{ issueId: string; title: string; pr?: number }>,\n projectRoot: string,\n options: ComputeMergeQueueOptions = {},\n) =>\n Effect.gen(function*() {\n if (candidates.length === 0) return [] as MergeQueueItem[];\n const gitConcurrency = Math.max(1, Math.floor(options.gitConcurrency ?? MERGE_QUEUE_GIT_CONCURRENCY));\n\n const branches = candidates.map((item) => `feature/${item.issueId.toLowerCase()}`);\n\n const existsFlags = yield* Effect.all(\n branches.map((branch) => branchExists(branch, projectRoot)),\n { concurrency: gitConcurrency },\n );\n\n const existing = candidates\n .map((item, i) => ({ item, branch: branches[i]!, exists: existsFlags[i]! }))\n .filter(({ exists }) => exists);\n\n if (existing.length === 0) return [] as MergeQueueItem[];\n\n const fileSets = yield* Effect.all(\n existing.map(({ branch }) => changedFilesVsMain(branch, projectRoot)),\n { concurrency: gitConcurrency },\n );\n const hotspots = options.hotspots ?? getProjectSwarmHotspots(findProjectByPathSync(projectRoot));\n const conflictSignals = computePredictedConflictSignals(\n existing.map((e, i) => ({ issueId: e.item.issueId, source: 'actual' as const, files: fileSets[i]! })),\n { hotspots },\n );\n const signalByIssue = new Map(conflictSignals.map(signal => [signal.issueId, signal]));\n const conflictsMap = new Map(conflictSignals.map(signal => [signal.issueId, new Set(signal.conflictsWith)]));\n\n const sorted = orderMergeCandidates(\n existing.map((e, i) => ({\n item: e.item,\n issueId: e.item.issueId,\n footprint: signalByIssue.get(e.item.issueId)?.footprint ?? fileSets[i]!.size,\n conflictCount: signalByIssue.get(e.item.issueId)?.conflictCount ?? 0,\n })),\n );\n\n return sorted.map(({ item, conflictCount }, idx) => ({\n issueId: item.issueId,\n title: item.title,\n branchName: `feature/${item.issueId.toLowerCase()}`,\n pr: item.pr,\n prUrl: options.getPrUrl?.(item),\n mergeOrder: idx + 1,\n conflictsWith: [...(conflictsMap.get(item.issueId) ?? [])],\n batchGroup: (conflictCount === 0 ? 'batch' : 'serialize') as 'batch' | 'serialize',\n }));\n });\n\n/** One member repo a candidate actually has a feature branch in. */\nexport interface PolyrepoRepoContribution {\n repoKey: string;\n repoPath: string;\n /**\n * The LOGICAL feature branch, always `feature/<issue>` — never\n * origin-qualified. Assembly hands this straight to `GenerationGitDeps`,\n * whose `safeBranchName(branch, 'feature')` accepts only `feature/…` and\n * which already resolves origin-first internally. Passing `origin/feature/…`\n * here makes every merge throw and every feature get held out.\n */\n branch: string;\n /** Branch this repo merges into, from the repo's own config. */\n targetBranch: string;\n /** Configured merge order for this repo within the project. */\n mergeOrder: number;\n}\n\nexport interface PolyrepoMergeQueueItem extends MergeQueueItem {\n repoContributions: PolyrepoRepoContribution[];\n}\n\nexport interface ComputePolyrepoMergeQueueOptions extends ComputeMergeQueueOptions {\n /** Called for each candidate dropped because no member repo has its branch. */\n onExcluded?: (issueId: string, reason: string) => void;\n /**\n * Called once with the repo paths whose ref refresh failed, if any.\n *\n * An empty queue caused by an outage is NOT the same fact as a verified empty\n * ready set, and the caller must not conflate them: the reconciler treats an\n * empty array as authoritative, marks every live member departed, invalidates\n * the generation, and tears its stack down. A transport or auth blip would\n * then destroy the current testable batch even though no feature left the\n * queue. Callers should report unavailability (null) instead.\n */\n onRefreshUnavailable?: (repoPaths: readonly string[]) => void;\n}\n\n/** The `feature/` (or configured) namespace a source branch lives in. */\nfunction branchNamespace(sourceBranch: string): string {\n const slash = sourceBranch.lastIndexOf('/');\n return slash >= 0 ? sourceBranch.slice(0, slash + 1) : '';\n}\n\n/**\n * Refresh every feature-branch tracking ref in one repo with ONE remote\n * negotiation, and report whether it succeeded.\n *\n * Three things this must get right, each of which caused a real defect:\n *\n * - **One fetch per repo, not per candidate.** Fetching per candidate/repo pair\n * performs F x R remote negotiations every reconciler minute, which on a\n * large ready set can outrun the interval and hold the project's\n * single-flight slot permanently.\n * - **Force (`+`) the refspec.** Without it a force-with-lease rebase on the\n * feature branch makes the update non-fast-forward, so the fetch fails and\n * the stale tracking ref survives — assembly would then test and promote\n * obsolete code.\n * - **Prune.** A deleted remote branch must drop its tracking ref, or the\n * probe keeps reporting a contribution that no longer exists.\n *\n * Returns false on ANY operational failure (transport, auth, bad repo). The\n * caller must fail closed: a stale ref is indistinguishable from a current one\n * once the fetch is gone, so silently continuing risks assembling old code.\n */\nconst refreshFeatureRefs = (namespaces: readonly string[], cwd: string) =>\n Effect.gen(function*() {\n if (namespaces.length === 0) return true;\n const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;\n const refspecs = namespaces.map((ns) => `+refs/heads/${ns}*:refs/remotes/origin/${ns}*`);\n const cmd = ChildProcess.make('git', ['fetch', '--prune', 'origin', ...refspecs], { cwd });\n return yield* spawner.exitCode(cmd).pipe(\n Effect.map((code) => Number(code) === 0),\n Effect.orElseSucceed(() => false),\n );\n });\n\n/**\n * Origin-first feature-branch probe, matching branchHeadSha in\n * uat-generation-deps.ts: work agents push their branches, so the local ref can\n * lag or be missing entirely in a repo the operator never checked out.\n * Returns the ref that exists, or null when neither does.\n *\n * Purely local — refreshFeatureRefs has already contacted the remote for this\n * repo, so `git rev-parse origin/<branch>` now reads a ref that is known\n * current rather than whatever was cached.\n */\nconst resolveFeatureRef = (branch: string, repoPath: string) =>\n Effect.gen(function*() {\n const originRef = `origin/${branch}`;\n if (yield* branchExists(originRef, repoPath)) return originRef;\n if (yield* branchExists(branch, repoPath)) return branch;\n return null;\n });\n\n/**\n * PAN-3093 polyrepo ready set. The monorepo sibling\n * (computeMergeQueueFromCandidates) derives one `feature/<issue>` branch and\n * runs git against one project root; a polyrepo candidate instead contributes\n * to some subset of the project's member repos, and only those repos with a\n * real feature branch belong in the generation.\n *\n * Conflict prediction runs over the union of each candidate's per-repo changed\n * files, prefixed `<repoKey>:` so the same path in two repos cannot read as an\n * overlap. Hotspot globs are applied per repo BEFORE prefixing — a glob like\n * `package.json` would never match `fe:package.json`.\n */\nexport const computePolyrepoMergeQueueFromCandidates = (\n candidates: ReadonlyArray<{ issueId: string; title: string; pr?: number }>,\n reposByIssue: ReadonlyMap<string, ReadonlyArray<ResolvedProjectRepo>>,\n projectRoot: string,\n options: ComputePolyrepoMergeQueueOptions = {},\n) =>\n Effect.gen(function*() {\n if (candidates.length === 0) return [] as PolyrepoMergeQueueItem[];\n const gitConcurrency = Math.max(1, Math.floor(options.gitConcurrency ?? MERGE_QUEUE_GIT_CONCURRENCY));\n\n // A repo configured `readonly: true` (required === false) must never become\n // a UAT target: assembly pushes branches to it, promote pushes merges, and\n // cleanup deletes remote branches. Excluding it here keeps it out of every\n // one of those write paths.\n const perCandidate = candidates.map((item) => {\n const configured = reposByIssue.get(item.issueId) ?? [];\n return {\n item,\n configured,\n repos: configured.filter((repo) => repo.required),\n readOnlySkipped: configured.filter((repo) => !repo.required),\n };\n });\n\n // ONE remote refresh per repo, before any probing. Doing it per\n // candidate/repo pair made F x R remote negotiations every minute.\n const namespacesByRepo = new Map<string, { repoPath: string; namespaces: Set<string> }>();\n for (const entry of perCandidate) {\n for (const repo of entry.repos) {\n const existing = namespacesByRepo.get(repo.repoPath) ?? { repoPath: repo.repoPath, namespaces: new Set<string>() };\n existing.namespaces.add(branchNamespace(repo.sourceBranch));\n namespacesByRepo.set(repo.repoPath, existing);\n }\n }\n const refreshResults = yield* Effect.all(\n [...namespacesByRepo.values()].map(({ repoPath, namespaces }) =>\n refreshFeatureRefs([...namespaces], repoPath).pipe(\n Effect.map((ok) => ({ repoPath, ok })),\n ),\n ),\n { concurrency: gitConcurrency },\n );\n const staleRepoPaths = new Set(refreshResults.filter((r) => !r.ok).map((r) => r.repoPath));\n if (staleRepoPaths.size > 0) options.onRefreshUnavailable?.([...staleRepoPaths]);\n\n // One flat, concurrency-governed collection: nesting Effect.all inside\n // Effect.all applies the limit at both levels, making the real ceiling\n // gitConcurrency² git subprocesses per project.\n // Repos whose refresh failed are skipped entirely — their tracking refs may\n // be arbitrarily old, and a stale ref is indistinguishable from a current\n // one, so probing them could assemble obsolete code.\n const probeJobs = perCandidate.flatMap((entry, candidateIndex) =>\n entry.repos\n .filter((repo) => !staleRepoPaths.has(repo.repoPath))\n .map((repo) => ({ candidateIndex, repo })),\n );\n const probeResults = yield* Effect.all(\n probeJobs.map(({ candidateIndex, repo }) =>\n resolveFeatureRef(repo.sourceBranch, repo.repoPath).pipe(\n Effect.map((ref) => ({ candidateIndex, repo, ref })),\n ),\n ),\n { concurrency: gitConcurrency },\n );\n\n const foundByCandidate = perCandidate.map(() => [] as Array<{ repo: ResolvedProjectRepo; ref: string }>);\n for (const { candidateIndex, repo, ref } of probeResults) {\n if (ref !== null) foundByCandidate[candidateIndex]!.push({ repo, ref });\n }\n\n const resolved = perCandidate.map((entry, candidateIndex) => {\n const found = [...foundByCandidate[candidateIndex]!].sort(\n (a, b) => a.repo.mergeOrder - b.repo.mergeOrder || a.repo.repoKey.localeCompare(b.repo.repoKey),\n );\n return {\n ...entry,\n contributions: found.map(({ repo }) => ({\n repoKey: repo.repoKey,\n repoPath: repo.repoPath,\n // Logical name only — see PolyrepoRepoContribution.branch.\n branch: repo.sourceBranch,\n targetBranch: repo.targetBranch,\n mergeOrder: repo.mergeOrder,\n })) as PolyrepoRepoContribution[],\n // The resolved ref is for THIS function's diffing only; it never leaves\n // as part of the contribution contract.\n diffRefs: found.map(({ ref }) => ref),\n };\n });\n\n const contributing: Array<{\n item: typeof candidates[number];\n contributions: PolyrepoRepoContribution[];\n diffRefs: string[];\n }> = [];\n for (const entry of resolved) {\n // Fail closed. Including this candidate would assemble it from whatever\n // its unrefreshed repos happen to hold, and excluding only the failed repo\n // would silently build a partial batch from a feature that spans more.\n const unrefreshed = entry.repos.filter((repo) => staleRepoPaths.has(repo.repoPath));\n if (unrefreshed.length > 0) {\n options.onExcluded?.(\n entry.item.issueId,\n `could not refresh feature refs in ${unrefreshed.map((r) => r.repoKey).join(', ')} — ` +\n `excluding rather than risk assembling stale code`,\n );\n continue;\n }\n if (entry.contributions.length === 0) {\n const readOnlyNote = entry.readOnlySkipped.length > 0\n ? ` (${entry.readOnlySkipped.map((r) => r.repoKey).join(', ')} excluded as read-only)`\n : '';\n options.onExcluded?.(\n entry.item.issueId,\n entry.repos.length === 0\n ? `no writable member repos resolved for this issue${readOnlyNote}`\n : `no feature branch in any of ${entry.repos.length} writable member repo(s): ${entry.repos.map((r) => r.repoKey).join(', ')}${readOnlyNote}`,\n );\n continue;\n }\n contributing.push({\n item: entry.item,\n contributions: entry.contributions,\n diffRefs: entry.diffRefs,\n });\n }\n\n if (contributing.length === 0) return [] as PolyrepoMergeQueueItem[];\n\n const hotspots = (options.hotspots ?? getProjectSwarmHotspots(findProjectByPathSync(projectRoot))).map(compileGlob);\n\n // Flattened to ONE concurrency-governed collection: nesting Effect.all\n // inside Effect.all applies the limit at both levels, so the real ceiling\n // was gitConcurrency² subprocesses per project.\n const diffJobs = contributing.flatMap(({ contributions, diffRefs }, candidateIndex) =>\n contributions.map((c, repoIndex) => ({ candidateIndex, contribution: c, ref: diffRefs[repoIndex]! })),\n );\n const diffResults = yield* Effect.all(\n // The diff uses the RESOLVED ref (possibly origin-qualified); the\n // contribution keeps the logical name for assembly.\n diffJobs.map(({ candidateIndex, contribution, ref }) =>\n changedFilesVsMain(ref, contribution.repoPath, contribution.targetBranch).pipe(\n // Filter hotspots against the real path, then namespace by repo so\n // fe/src/x.ts and api/src/x.ts are not mistaken for one file.\n Effect.map((files) => ({\n candidateIndex,\n files: [...normalizedFootprintFiles(files, hotspots)].map((f) => `${contribution.repoKey}:${f}`),\n })),\n ),\n ),\n { concurrency: gitConcurrency },\n );\n\n const fileSets = contributing.map(() => new Set<string>());\n for (const { candidateIndex, files } of diffResults) {\n for (const file of files) fileSets[candidateIndex]!.add(file);\n }\n\n // Hotspots were already applied per repo above; re-applying them to prefixed\n // paths would silently match nothing.\n const conflictSignals = computePredictedConflictSignals(\n contributing.map((c, i) => ({ issueId: c.item.issueId, source: 'actual' as const, files: fileSets[i]! })),\n );\n const signalByIssue = new Map(conflictSignals.map((signal) => [signal.issueId, signal]));\n const conflictsMap = new Map(conflictSignals.map((signal) => [signal.issueId, new Set(signal.conflictsWith)]));\n\n const sorted = orderMergeCandidates(\n contributing.map((c, i) => ({\n item: c.item,\n contributions: c.contributions,\n issueId: c.item.issueId,\n footprint: signalByIssue.get(c.item.issueId)?.footprint ?? fileSets[i]!.size,\n conflictCount: signalByIssue.get(c.item.issueId)?.conflictCount ?? 0,\n })),\n );\n\n return sorted.map(({ item, contributions, conflictCount }, idx) => ({\n issueId: item.issueId,\n title: item.title,\n // The per-repo refs live in repoContributions; this stays the logical\n // feature-branch name so the field means the same thing as monorepo.\n branchName: `feature/${item.issueId.toLowerCase()}`,\n pr: item.pr,\n prUrl: options.getPrUrl?.(item),\n mergeOrder: idx + 1,\n conflictsWith: [...(conflictsMap.get(item.issueId) ?? [])],\n batchGroup: (conflictCount === 0 ? 'batch' : 'serialize') as 'batch' | 'serialize',\n repoContributions: contributions,\n }));\n });\n\nexport interface SequencePickResult {\n issueId: string;\n rank: number;\n gate: string;\n planning: string;\n predictedConflictCount?: number;\n predictedConflictsWith?: string[];\n}\n\n\n/**\n * PAN-1866: Pick the highest-ranked eligible issue from a sequence node list.\n *\n * Eligibility rules:\n * - gate must not be 'blocked' (the `vetoed` pickup state)\n * - no `vetoed` label — an absolute operator hard-stop (PAN-2006)\n * - not in-pipeline (active review/work/test)\n * - no parked labels (`parked`; legacy `needs-design`/`needs-discussion`)\n * - not in the optional exclusion set (e.g. already running agents)\n * - FR-14: must have an xBRIEF spec (ready) or a PRD draft (hasPrd)\n *\n * Returns null when no eligible issue is found.\n */\nexport function pickFromSequence(\n nodes: ReadonlyArray<SequenceNode>,\n opts?: {\n excludeIssueIds?: ReadonlySet<string>;\n issueLabels?: (issueId: string) => ReadonlyArray<string>;\n /** Flywheel author/assignee safety gate. Return false to skip an issue. When\n * absent every issue passes (backward-compatible default). */\n isAuthorizedIssue?: (issueId: string) => boolean;\n /** FR-14 eligibility gate. Return true if the issue has an xBRIEF spec (ready)\n * or a PRD draft (hasPrd). When absent every issue passes (backward-compatible\n * default). */\n isReadyOrHasPrd?: (issueId: string) => boolean;\n /** Supplement the built-in review-status inPipeline check with live workspace/agent\n * state. Return true to treat an issue as in-pipeline and skip it. When absent only\n * review_status is checked (backward-compatible default). */\n isInPipeline?: (issueId: string) => boolean;\n /** PAN-2006 Definition of Ready: when true, only issues carrying the `ready`\n * label are eligible (the hard entry gate). The live Flywheel passes true;\n * legacy callers omit it and keep their pre-DoR behavior. */\n requireReady?: boolean;\n /** PAN-2059 + vision.mdx blanket release: when auto-pickup is ON the toggle\n * satisfies the per-issue `released` gate for the whole backlog. The live Flywheel\n * passes its auto_pickup_backlog setting; legacy callers omit it (default OFF). */\n autoPickupBacklog?: boolean;\n /** Operator-released scope supplied by the active order book. */\n activeBookMembership?: ReadonlySet<string>;\n /**\n * Advisory pre-branch conflict signal. When present, lower predicted-conflict\n * counts sort first among otherwise pickable issues; no issue is filtered out.\n */\n predictedConflictSignals?: ReadonlyArray<PredictedConflictSignal>;\n },\n): SequencePickResult | null {\n // Single source of truth: the same classifier the Forecast UI uses (PAN-2006).\n // `isReadyOrHasPrd` maps to the module's `planned` gate; review_status + the\n // optional callback feed the `inPipeline` gate; vetoed / parked / gate-blocked are\n // derived from labels + the node's gate inside classifyIssue.\n const lookups: ClassifyLookups = {\n labels: opts?.issueLabels ?? (() => []),\n isPlanned: opts?.isReadyOrHasPrd ?? (() => true),\n isInPipeline: (issueId) => {\n const reviewStatus = getReviewStatusSync(issueId.toUpperCase());\n return (reviewStatus !== null && reviewStatus.reviewStatus !== 'pending') ||\n (opts?.isInPipeline?.(issueId) ?? false);\n },\n };\n\n const signalByIssue = new Map((opts?.predictedConflictSignals ?? []).map(signal => [signal.issueId.toUpperCase(), signal]));\n const eligible = [...nodes]\n .sort((a, b) => a.rank - b.rank)\n .filter((node) => {\n const state = classifyIssue(node, lookups);\n // DoR is conditional: when not required, treat readiness as satisfied so the\n // remaining gates (planned / parked / vetoed / in-pipeline) still apply.\n const activeBookMember = opts?.activeBookMembership?.has(node.issue.toUpperCase()) ?? false;\n if (!isAutoPickable(opts?.requireReady ? state : { ...state, ready: true }, opts?.autoPickupBacklog ?? false, activeBookMember)) return false;\n if (opts?.excludeIssueIds?.has(node.issue)) return false;\n if (opts?.isAuthorizedIssue && !opts.isAuthorizedIssue(node.issue)) return false;\n return true;\n });\n\n if (signalByIssue.size > 0) {\n eligible.sort((a, b) => {\n const aSignal = signalByIssue.get(a.issue.toUpperCase());\n const bSignal = signalByIssue.get(b.issue.toUpperCase());\n const aConflicts = aSignal?.conflictCount ?? 0;\n const bConflicts = bSignal?.conflictCount ?? 0;\n if (aConflicts !== bConflicts) return aConflicts - bConflicts;\n return a.rank - b.rank;\n });\n }\n\n for (const node of eligible) {\n const state = classifyIssue(node, lookups);\n const signal = signalByIssue.get(node.issue.toUpperCase());\n return {\n issueId: node.issue,\n rank: node.rank,\n gate: node.gate,\n planning: node.planning,\n predictedConflictCount: signal?.conflictCount,\n predictedConflictsWith: signal?.conflictsWith,\n };\n }\n return null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"flywheel-merge-order-PG5op4j7.js","names":[],"sources":["../../src/lib/flywheel-merge-order.ts"],"sourcesContent":["import { Effect } from 'effect';\nimport { ChildProcess, ChildProcessSpawner } from 'effect/unstable/process';\nimport type { FlywheelPipelineItem } from '@overdeck/contracts';\nimport { getReviewStatusSync, loadReviewStatuses, mergeGateEligibility, type MergeGateEligibility } from './review-status.js';\nimport { resolveGitHubIssueSync } from './tracker-utils.js';\nimport type { SequenceNode } from './backlog/types.js';\nimport { classifyIssue, isAutoPickable, type ClassifyLookups } from './backlog/pickup.js';\nimport { compileGlob, type CompiledGlob } from './xbrief/dag.js';\nimport { computeIssueFootprint } from './xbrief/swarm-readiness.js';\nimport type { XBriefDocument } from './xbrief/types.js';\nimport { findProjectByPathSync, getProjectSwarmHotspots, resolveProjectFromIssueSync } from './projects.js';\nimport type { ResolvedProjectRepo } from './project-repos.js';\n\nexport interface MergeQueueItem {\n issueId: string;\n title: string;\n branchName: string;\n pr?: number;\n prUrl?: string;\n mergeOrder: number;\n conflictsWith: string[];\n /** PAN-1691: 'batch' = disjoint, mergeable together in one pass; 'serialize' = conflicts, must go one at a time. */\n batchGroup?: 'batch' | 'serialize';\n}\n\nfunction issueNumber(issueId: string): number {\n const match = issueId.match(/\\d+$/);\n return match ? parseInt(match[0], 10) : 0;\n}\n\nexport interface MergeCandidateMeta {\n issueId: string;\n /** Number of files this branch changes vs main. */\n footprint: number;\n /** How many other ready branches this one overlaps files with. */\n conflictCount: number;\n}\n\nexport type FootprintSource = 'declared' | 'actual';\n\nexport interface IssueFileFootprint {\n issueId: string;\n files: Iterable<string>;\n source: FootprintSource;\n}\n\nexport interface PredictedConflictSignal extends MergeCandidateMeta {\n source: FootprintSource;\n conflictsWith: string[];\n}\n\n/**\n * PAN-1691 conflict-aware merge order. Disjoint (no-conflict) items come first\n * so they can batch through in a single verification pass; then conflicting\n * items broadest-file-footprint first, so the remaining cluster members rebase\n * once onto the worst offender instead of repeatedly. Issue number is the\n * stable tiebreak within each tier. Pure — exported for testing.\n */\nexport function orderMergeCandidates<T extends MergeCandidateMeta>(items: ReadonlyArray<T>): T[] {\n return [...items].sort((a, b) => {\n const aConf = a.conflictCount > 0 ? 1 : 0;\n const bConf = b.conflictCount > 0 ? 1 : 0;\n if (aConf !== bConf) return aConf - bConf;\n if (aConf === 1 && a.footprint !== b.footprint) return b.footprint - a.footprint;\n return issueNumber(a.issueId) - issueNumber(b.issueId);\n });\n}\n\nexport interface MergeTrainPlan {\n /** Disjoint candidates that can merge together in one verification pass. */\n batch: string[];\n /** Conflicting candidates that must serialize, broadest-footprint first. */\n serialize: string[];\n /** Full ordered list (batch, then serialize). */\n order: string[];\n}\n\n/**\n * PAN-1691 merge-train plan. Partitions the conflict-aware order into the run of\n * disjoint candidates — which can all merge in a single verification pass — and\n * the conflicting remainder, which must serialize broadest-footprint first.\n * Pure; the executor consumes this once the merge-train flag is enabled.\n */\nexport function planMergeTrain<T extends MergeCandidateMeta>(candidates: ReadonlyArray<T>): MergeTrainPlan {\n const ordered = orderMergeCandidates(candidates);\n return {\n batch: ordered.filter((c) => c.conflictCount === 0).map((c) => c.issueId),\n serialize: ordered.filter((c) => c.conflictCount > 0).map((c) => c.issueId),\n order: ordered.map((c) => c.issueId),\n };\n}\n\nexport function declaredIssueFootprint(issueId: string, doc: XBriefDocument): IssueFileFootprint {\n return { issueId, files: computeIssueFootprint(doc), source: 'declared' };\n}\n\nfunction pathMatchesAnyCompiled(filePath: string, patterns: CompiledGlob[]): boolean {\n return patterns.some(pattern => pattern.regex.test(filePath) || pattern.exactDirectory === filePath);\n}\n\nfunction normalizedFootprintFiles(files: Iterable<string>, hotspots: CompiledGlob[]): Set<string> {\n const normalized = new Set<string>();\n for (const file of files) {\n if (!file || pathMatchesAnyCompiled(file, hotspots)) continue;\n normalized.add(file);\n }\n return normalized;\n}\n\nfunction sourcePriority(source: FootprintSource): number {\n return source === 'actual' ? 2 : 1;\n}\n\nexport function computePredictedConflictSignals(\n footprints: ReadonlyArray<IssueFileFootprint>,\n options: { hotspots?: string[] } = {},\n): PredictedConflictSignal[] {\n const hotspots = (options.hotspots ?? []).map(compileGlob);\n const byIssue = new Map<string, { issueId: string; source: FootprintSource; files: Set<string> }>();\n\n for (const footprint of footprints) {\n const files = normalizedFootprintFiles(footprint.files, hotspots);\n const current = byIssue.get(footprint.issueId);\n if (!current || sourcePriority(footprint.source) > sourcePriority(current.source)) {\n byIssue.set(footprint.issueId, { issueId: footprint.issueId, source: footprint.source, files });\n continue;\n }\n if (sourcePriority(footprint.source) === sourcePriority(current.source)) {\n for (const file of files) current.files.add(file);\n }\n }\n\n const conflictsMap = new Map<string, Set<string>>();\n const entries = Array.from(byIssue.values());\n for (let i = 0; i < entries.length; i++) {\n for (let j = i + 1; j < entries.length; j++) {\n const left = entries[i]!;\n const right = entries[j]!;\n if (![...left.files].some(file => right.files.has(file))) continue;\n if (!conflictsMap.has(left.issueId)) conflictsMap.set(left.issueId, new Set());\n if (!conflictsMap.has(right.issueId)) conflictsMap.set(right.issueId, new Set());\n conflictsMap.get(left.issueId)!.add(right.issueId);\n conflictsMap.get(right.issueId)!.add(left.issueId);\n }\n }\n\n return entries.map(entry => {\n const conflictsWith = [...(conflictsMap.get(entry.issueId) ?? [])]\n .sort((a, b) => issueNumber(a) - issueNumber(b));\n return {\n issueId: entry.issueId,\n source: entry.source,\n footprint: entry.files.size,\n conflictCount: conflictsWith.length,\n conflictsWith,\n };\n });\n}\n\nexport interface UatCandidatePlan {\n /** Branch name for the on-demand UAT candidate (auto-merge-OFF mode). */\n branchName: string;\n /** Issue IDs bundled onto the candidate — the disjoint, mergeable-together batch. */\n bundled: string[];\n}\n\n/**\n * PAN-1691 on-demand UAT candidate. In auto-merge-OFF mode the disjoint \"batch\"\n * (everything that can merge together in one verification pass) is bundled onto\n * a single throwaway branch the human UATs in one sitting. Pure — `dateIso` is\n * injected, and it reads the already-computed `batchGroup` off the merge queue.\n */\nexport function planUatCandidate(\n queue: ReadonlyArray<MergeQueueItem>,\n opts: { dateIso: string; label?: string },\n): UatCandidatePlan {\n const bundled = queue.filter((i) => i.batchGroup === 'batch').map((i) => i.issueId);\n const day = opts.dateIso.slice(0, 10);\n return { branchName: `uat/${opts.label ?? 'candidate'}-${day}`, bundled };\n}\n\nconst branchExists = (branch: string, cwd: string) =>\n Effect.gen(function*() {\n const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;\n const cmd = ChildProcess.make('git', ['rev-parse', '--verify', branch], { cwd });\n return yield* spawner.exitCode(cmd).pipe(\n Effect.map((code) => code === 0),\n Effect.orElseSucceed(() => false),\n );\n });\n\nexport const changedFilesVsMain = (branch: string, cwd: string, base = 'main') =>\n Effect.gen(function*() {\n const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;\n const cmd = ChildProcess.make('git', ['diff', '--name-only', `${base}...${branch}`], { cwd });\n return yield* spawner.string(cmd).pipe(\n Effect.map((stdout) => new Set(stdout.trim().split('\\n').filter(Boolean))),\n Effect.orElseSucceed(() => new Set<string>()),\n );\n });\n\nexport const MERGE_QUEUE_GIT_CONCURRENCY = 4;\n\nexport interface ComputeMergeQueueOptions {\n getPrUrl?: (item: { issueId: string; pr?: number }) => string | undefined;\n gitConcurrency?: number;\n /**\n * Authoritative merge eligibility per issue (PAN-1759). Defaults to the\n * review-status DB predicate; injectable for tests. The verb filter alone is\n * the orchestrator's INTENT — an LLM emission that has tagged mid-review\n * issues as merge-bound. Only verb ∩ eligibility enters the queue.\n */\n eligibility?: (issueId: string) => MergeGateEligibility;\n /** Called for each verb-tagged item the eligibility gate rejects. */\n onIneligible?: (issueId: string, reason: string) => void;\n /** Files treated as common hotspots and excluded from predicted-conflict math. */\n hotspots?: string[];\n}\n\n/** Default eligibility: the issue's review-status record, read synchronously. */\nexport function reviewRecordEligibility(issueId: string): MergeGateEligibility {\n return mergeGateEligibility(getReviewStatusSync(issueId.toUpperCase()));\n}\n\n/**\n * Server-side PR URL resolution for merge-queue items: prefer the review\n * status record, fall back to the GitHub repo + PR number — the browser never\n * guesses repo slugs.\n */\nexport function resolveMergeQueuePrUrl(item: { issueId: string; pr?: number }): string | undefined {\n const issueId = item.issueId.toUpperCase();\n const reviewStatus = getReviewStatusSync(issueId);\n if (reviewStatus?.prUrl) return reviewStatus.prUrl;\n\n const prNumber = reviewStatus?.prNumber ?? item.pr;\n if (prNumber === undefined) return undefined;\n\n const githubIssue = resolveGitHubIssueSync(issueId);\n if (!githubIssue.isGitHub) return undefined;\n return `https://github.com/${githubIssue.owner}/${githubIssue.repo}/pull/${prNumber}`;\n}\n\n/**\n * PAN-1696 ready-set-source: List all merge-eligible candidates from review-status DB for a given project.\n * No flywheel run required — sources directly from persistent pipeline state.\n * Returns an array of candidate items compatible with computeMergeQueueFromCandidates.\n */\nexport async function listEligibleCandidatesByProject(projectRoot: string): Promise<Array<{ issueId: string; title: string; pr?: number }>> {\n const project = findProjectByPathSync(projectRoot);\n if (!project) return [];\n\n const allStatuses = loadReviewStatuses();\n const readyStatuses = Object.entries(allStatuses).filter(([issueId, rs]) => {\n const issueProject = resolveProjectFromIssueSync(issueId);\n return issueProject?.projectPath === project.path &&\n rs.deaconIgnored !== true && rs.readyForMerge === true && mergeGateEligibility(rs).eligible;\n });\n const { gatherMergeEligibility, isMergeEligible } = await import('./cloister/merge-eligibility.js');\n const memberships = await gatherMergeEligibility(readyStatuses.map(([issueId]) => issueId));\n const candidates: Array<{ issueId: string; title: string; pr?: number }> = [];\n\n for (const [issueId, rs] of readyStatuses) {\n const membership = memberships.get(issueId.toUpperCase());\n if (!membership || !isMergeEligible(membership)) continue;\n\n // AC 10: title resolved downstream by computeMergeQueueFromCandidates; here use issue ID\n candidates.push({ issueId, title: issueId, pr: rs.prNumber });\n }\n\n return candidates;\n}\n\n/**\n * PAN-1696 ready-set-source: Compute merge queue from a pre-filtered candidate list.\n * Accepts candidates from review-status or flywheel pipeline — decouples the source.\n * This refactored version extracts the core conflict-analysis logic from computeMergeQueue.\n */\nexport const computeMergeQueueFromCandidates = (\n candidates: ReadonlyArray<{ issueId: string; title: string; pr?: number }>,\n projectRoot: string,\n options: ComputeMergeQueueOptions = {},\n) =>\n Effect.gen(function*() {\n if (candidates.length === 0) return [] as MergeQueueItem[];\n const gitConcurrency = Math.max(1, Math.floor(options.gitConcurrency ?? MERGE_QUEUE_GIT_CONCURRENCY));\n\n const branches = candidates.map((item) => `feature/${item.issueId.toLowerCase()}`);\n\n const existsFlags = yield* Effect.all(\n branches.map((branch) => branchExists(branch, projectRoot)),\n { concurrency: gitConcurrency },\n );\n\n const existing = candidates\n .map((item, i) => ({ item, branch: branches[i]!, exists: existsFlags[i]! }))\n .filter(({ exists }) => exists);\n\n if (existing.length === 0) return [] as MergeQueueItem[];\n\n const fileSets = yield* Effect.all(\n existing.map(({ branch }) => changedFilesVsMain(branch, projectRoot)),\n { concurrency: gitConcurrency },\n );\n const hotspots = options.hotspots ?? getProjectSwarmHotspots(findProjectByPathSync(projectRoot));\n const conflictSignals = computePredictedConflictSignals(\n existing.map((e, i) => ({ issueId: e.item.issueId, source: 'actual' as const, files: fileSets[i]! })),\n { hotspots },\n );\n const signalByIssue = new Map(conflictSignals.map(signal => [signal.issueId, signal]));\n const conflictsMap = new Map(conflictSignals.map(signal => [signal.issueId, new Set(signal.conflictsWith)]));\n\n const sorted = orderMergeCandidates(\n existing.map((e, i) => ({\n item: e.item,\n issueId: e.item.issueId,\n footprint: signalByIssue.get(e.item.issueId)?.footprint ?? fileSets[i]!.size,\n conflictCount: signalByIssue.get(e.item.issueId)?.conflictCount ?? 0,\n })),\n );\n\n return sorted.map(({ item, conflictCount }, idx) => ({\n issueId: item.issueId,\n title: item.title,\n branchName: `feature/${item.issueId.toLowerCase()}`,\n pr: item.pr,\n prUrl: options.getPrUrl?.(item),\n mergeOrder: idx + 1,\n conflictsWith: [...(conflictsMap.get(item.issueId) ?? [])],\n batchGroup: (conflictCount === 0 ? 'batch' : 'serialize') as 'batch' | 'serialize',\n }));\n });\n\n/** One member repo a candidate actually has a feature branch in. */\nexport interface PolyrepoRepoContribution {\n repoKey: string;\n repoPath: string;\n /**\n * The LOGICAL feature branch, always `feature/<issue>` — never\n * origin-qualified. Assembly hands this straight to `GenerationGitDeps`,\n * whose `safeBranchName(branch, 'feature')` accepts only `feature/…` and\n * which already resolves origin-first internally. Passing `origin/feature/…`\n * here makes every merge throw and every feature get held out.\n */\n branch: string;\n /** Branch this repo merges into, from the repo's own config. */\n targetBranch: string;\n /** Configured merge order for this repo within the project. */\n mergeOrder: number;\n}\n\nexport interface PolyrepoMergeQueueItem extends MergeQueueItem {\n repoContributions: PolyrepoRepoContribution[];\n}\n\nexport interface ComputePolyrepoMergeQueueOptions extends ComputeMergeQueueOptions {\n /** Called for each candidate dropped because no member repo has its branch. */\n onExcluded?: (issueId: string, reason: string) => void;\n /**\n * Called once with the repo paths whose ref refresh failed, if any.\n *\n * An empty queue caused by an outage is NOT the same fact as a verified empty\n * ready set, and the caller must not conflate them: the reconciler treats an\n * empty array as authoritative, marks every live member departed, invalidates\n * the generation, and tears its stack down. A transport or auth blip would\n * then destroy the current testable batch even though no feature left the\n * queue. Callers should report unavailability (null) instead.\n */\n onRefreshUnavailable?: (repoPaths: readonly string[]) => void;\n}\n\n/** The `feature/` (or configured) namespace a source branch lives in. */\nfunction branchNamespace(sourceBranch: string): string {\n const slash = sourceBranch.lastIndexOf('/');\n return slash >= 0 ? sourceBranch.slice(0, slash + 1) : '';\n}\n\n/**\n * Refresh every feature-branch tracking ref in one repo with ONE remote\n * negotiation, and report whether it succeeded.\n *\n * Three things this must get right, each of which caused a real defect:\n *\n * - **One fetch per repo, not per candidate.** Fetching per candidate/repo pair\n * performs F x R remote negotiations every reconciler minute, which on a\n * large ready set can outrun the interval and hold the project's\n * single-flight slot permanently.\n * - **Force (`+`) the refspec.** Without it a force-with-lease rebase on the\n * feature branch makes the update non-fast-forward, so the fetch fails and\n * the stale tracking ref survives — assembly would then test and promote\n * obsolete code.\n * - **Prune.** A deleted remote branch must drop its tracking ref, or the\n * probe keeps reporting a contribution that no longer exists.\n *\n * Returns false on ANY operational failure (transport, auth, bad repo). The\n * caller must fail closed: a stale ref is indistinguishable from a current one\n * once the fetch is gone, so silently continuing risks assembling old code.\n */\nconst refreshFeatureRefs = (namespaces: readonly string[], cwd: string) =>\n Effect.gen(function*() {\n if (namespaces.length === 0) return true;\n const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;\n const refspecs = namespaces.map((ns) => `+refs/heads/${ns}*:refs/remotes/origin/${ns}*`);\n const cmd = ChildProcess.make('git', ['fetch', '--prune', 'origin', ...refspecs], { cwd });\n return yield* spawner.exitCode(cmd).pipe(\n Effect.map((code) => Number(code) === 0),\n Effect.orElseSucceed(() => false),\n );\n });\n\n/**\n * Origin-first feature-branch probe, matching branchHeadSha in\n * uat-generation-deps.ts: work agents push their branches, so the local ref can\n * lag or be missing entirely in a repo the operator never checked out.\n * Returns the ref that exists, or null when neither does.\n *\n * Purely local — refreshFeatureRefs has already contacted the remote for this\n * repo, so `git rev-parse origin/<branch>` now reads a ref that is known\n * current rather than whatever was cached.\n */\nconst resolveFeatureRef = (branch: string, repoPath: string) =>\n Effect.gen(function*() {\n const originRef = `origin/${branch}`;\n if (yield* branchExists(originRef, repoPath)) return originRef;\n if (yield* branchExists(branch, repoPath)) return branch;\n return null;\n });\n\n/**\n * PAN-3093 polyrepo ready set. The monorepo sibling\n * (computeMergeQueueFromCandidates) derives one `feature/<issue>` branch and\n * runs git against one project root; a polyrepo candidate instead contributes\n * to some subset of the project's member repos, and only those repos with a\n * real feature branch belong in the generation.\n *\n * Conflict prediction runs over the union of each candidate's per-repo changed\n * files, prefixed `<repoKey>:` so the same path in two repos cannot read as an\n * overlap. Hotspot globs are applied per repo BEFORE prefixing — a glob like\n * `package.json` would never match `fe:package.json`.\n */\nexport const computePolyrepoMergeQueueFromCandidates = (\n candidates: ReadonlyArray<{ issueId: string; title: string; pr?: number }>,\n reposByIssue: ReadonlyMap<string, ReadonlyArray<ResolvedProjectRepo>>,\n projectRoot: string,\n options: ComputePolyrepoMergeQueueOptions = {},\n) =>\n Effect.gen(function*() {\n if (candidates.length === 0) return [] as PolyrepoMergeQueueItem[];\n const gitConcurrency = Math.max(1, Math.floor(options.gitConcurrency ?? MERGE_QUEUE_GIT_CONCURRENCY));\n\n // A repo configured `readonly: true` (required === false) must never become\n // a UAT target: assembly pushes branches to it, promote pushes merges, and\n // cleanup deletes remote branches. Excluding it here keeps it out of every\n // one of those write paths.\n const perCandidate = candidates.map((item) => {\n const configured = reposByIssue.get(item.issueId) ?? [];\n return {\n item,\n configured,\n repos: configured.filter((repo) => repo.required),\n readOnlySkipped: configured.filter((repo) => !repo.required),\n };\n });\n\n // ONE remote refresh per repo, before any probing. Doing it per\n // candidate/repo pair made F x R remote negotiations every minute.\n const namespacesByRepo = new Map<string, { repoPath: string; namespaces: Set<string> }>();\n for (const entry of perCandidate) {\n for (const repo of entry.repos) {\n const existing = namespacesByRepo.get(repo.repoPath) ?? { repoPath: repo.repoPath, namespaces: new Set<string>() };\n existing.namespaces.add(branchNamespace(repo.sourceBranch));\n namespacesByRepo.set(repo.repoPath, existing);\n }\n }\n const refreshResults = yield* Effect.all(\n [...namespacesByRepo.values()].map(({ repoPath, namespaces }) =>\n refreshFeatureRefs([...namespaces], repoPath).pipe(\n Effect.map((ok) => ({ repoPath, ok })),\n ),\n ),\n { concurrency: gitConcurrency },\n );\n const staleRepoPaths = new Set(refreshResults.filter((r) => !r.ok).map((r) => r.repoPath));\n if (staleRepoPaths.size > 0) options.onRefreshUnavailable?.([...staleRepoPaths]);\n\n // One flat, concurrency-governed collection: nesting Effect.all inside\n // Effect.all applies the limit at both levels, making the real ceiling\n // gitConcurrency² git subprocesses per project.\n // Repos whose refresh failed are skipped entirely — their tracking refs may\n // be arbitrarily old, and a stale ref is indistinguishable from a current\n // one, so probing them could assemble obsolete code.\n const probeJobs = perCandidate.flatMap((entry, candidateIndex) =>\n entry.repos\n .filter((repo) => !staleRepoPaths.has(repo.repoPath))\n .map((repo) => ({ candidateIndex, repo })),\n );\n const probeResults = yield* Effect.all(\n probeJobs.map(({ candidateIndex, repo }) =>\n resolveFeatureRef(repo.sourceBranch, repo.repoPath).pipe(\n Effect.map((ref) => ({ candidateIndex, repo, ref })),\n ),\n ),\n { concurrency: gitConcurrency },\n );\n\n const foundByCandidate = perCandidate.map(() => [] as Array<{ repo: ResolvedProjectRepo; ref: string }>);\n for (const { candidateIndex, repo, ref } of probeResults) {\n if (ref !== null) foundByCandidate[candidateIndex]!.push({ repo, ref });\n }\n\n const resolved = perCandidate.map((entry, candidateIndex) => {\n const found = [...foundByCandidate[candidateIndex]!].sort(\n (a, b) => a.repo.mergeOrder - b.repo.mergeOrder || a.repo.repoKey.localeCompare(b.repo.repoKey),\n );\n return {\n ...entry,\n contributions: found.map(({ repo }) => ({\n repoKey: repo.repoKey,\n repoPath: repo.repoPath,\n // Logical name only — see PolyrepoRepoContribution.branch.\n branch: repo.sourceBranch,\n targetBranch: repo.targetBranch,\n mergeOrder: repo.mergeOrder,\n })) as PolyrepoRepoContribution[],\n // The resolved ref is for THIS function's diffing only; it never leaves\n // as part of the contribution contract.\n diffRefs: found.map(({ ref }) => ref),\n };\n });\n\n const contributing: Array<{\n item: typeof candidates[number];\n contributions: PolyrepoRepoContribution[];\n diffRefs: string[];\n }> = [];\n for (const entry of resolved) {\n // Fail closed. Including this candidate would assemble it from whatever\n // its unrefreshed repos happen to hold, and excluding only the failed repo\n // would silently build a partial batch from a feature that spans more.\n const unrefreshed = entry.repos.filter((repo) => staleRepoPaths.has(repo.repoPath));\n if (unrefreshed.length > 0) {\n options.onExcluded?.(\n entry.item.issueId,\n `could not refresh feature refs in ${unrefreshed.map((r) => r.repoKey).join(', ')} — ` +\n `excluding rather than risk assembling stale code`,\n );\n continue;\n }\n if (entry.contributions.length === 0) {\n const readOnlyNote = entry.readOnlySkipped.length > 0\n ? ` (${entry.readOnlySkipped.map((r) => r.repoKey).join(', ')} excluded as read-only)`\n : '';\n options.onExcluded?.(\n entry.item.issueId,\n entry.repos.length === 0\n ? `no writable member repos resolved for this issue${readOnlyNote}`\n : `no feature branch in any of ${entry.repos.length} writable member repo(s): ${entry.repos.map((r) => r.repoKey).join(', ')}${readOnlyNote}`,\n );\n continue;\n }\n contributing.push({\n item: entry.item,\n contributions: entry.contributions,\n diffRefs: entry.diffRefs,\n });\n }\n\n if (contributing.length === 0) return [] as PolyrepoMergeQueueItem[];\n\n const hotspots = (options.hotspots ?? getProjectSwarmHotspots(findProjectByPathSync(projectRoot))).map(compileGlob);\n\n // Flattened to ONE concurrency-governed collection: nesting Effect.all\n // inside Effect.all applies the limit at both levels, so the real ceiling\n // was gitConcurrency² subprocesses per project.\n const diffJobs = contributing.flatMap(({ contributions, diffRefs }, candidateIndex) =>\n contributions.map((c, repoIndex) => ({ candidateIndex, contribution: c, ref: diffRefs[repoIndex]! })),\n );\n const diffResults = yield* Effect.all(\n // The diff uses the RESOLVED ref (possibly origin-qualified); the\n // contribution keeps the logical name for assembly.\n diffJobs.map(({ candidateIndex, contribution, ref }) =>\n changedFilesVsMain(ref, contribution.repoPath, contribution.targetBranch).pipe(\n // Filter hotspots against the real path, then namespace by repo so\n // fe/src/x.ts and api/src/x.ts are not mistaken for one file.\n Effect.map((files) => ({\n candidateIndex,\n files: [...normalizedFootprintFiles(files, hotspots)].map((f) => `${contribution.repoKey}:${f}`),\n })),\n ),\n ),\n { concurrency: gitConcurrency },\n );\n\n const fileSets = contributing.map(() => new Set<string>());\n for (const { candidateIndex, files } of diffResults) {\n for (const file of files) fileSets[candidateIndex]!.add(file);\n }\n\n // Hotspots were already applied per repo above; re-applying them to prefixed\n // paths would silently match nothing.\n const conflictSignals = computePredictedConflictSignals(\n contributing.map((c, i) => ({ issueId: c.item.issueId, source: 'actual' as const, files: fileSets[i]! })),\n );\n const signalByIssue = new Map(conflictSignals.map((signal) => [signal.issueId, signal]));\n const conflictsMap = new Map(conflictSignals.map((signal) => [signal.issueId, new Set(signal.conflictsWith)]));\n\n const sorted = orderMergeCandidates(\n contributing.map((c, i) => ({\n item: c.item,\n contributions: c.contributions,\n issueId: c.item.issueId,\n footprint: signalByIssue.get(c.item.issueId)?.footprint ?? fileSets[i]!.size,\n conflictCount: signalByIssue.get(c.item.issueId)?.conflictCount ?? 0,\n })),\n );\n\n return sorted.map(({ item, contributions, conflictCount }, idx) => ({\n issueId: item.issueId,\n title: item.title,\n // The per-repo refs live in repoContributions; this stays the logical\n // feature-branch name so the field means the same thing as monorepo.\n branchName: `feature/${item.issueId.toLowerCase()}`,\n pr: item.pr,\n prUrl: options.getPrUrl?.(item),\n mergeOrder: idx + 1,\n conflictsWith: [...(conflictsMap.get(item.issueId) ?? [])],\n batchGroup: (conflictCount === 0 ? 'batch' : 'serialize') as 'batch' | 'serialize',\n repoContributions: contributions,\n }));\n });\n\nexport interface SequencePickResult {\n issueId: string;\n rank: number;\n gate: string;\n planning: string;\n predictedConflictCount?: number;\n predictedConflictsWith?: string[];\n}\n\n\n/**\n * PAN-1866: Pick the highest-ranked eligible issue from a sequence node list.\n *\n * Eligibility rules:\n * - gate must not be 'blocked' (the `vetoed` pickup state)\n * - no `vetoed` label — an absolute operator hard-stop (PAN-2006)\n * - not in-pipeline (active review/work/test)\n * - no parked labels (`parked`; legacy `needs-design`/`needs-discussion`)\n * - not in the optional exclusion set (e.g. already running agents)\n * - FR-14: must have an xBRIEF spec (ready) or a PRD draft (hasPrd)\n *\n * Returns null when no eligible issue is found.\n */\nexport function pickFromSequence(\n nodes: ReadonlyArray<SequenceNode>,\n opts?: {\n excludeIssueIds?: ReadonlySet<string>;\n issueLabels?: (issueId: string) => ReadonlyArray<string>;\n /** Flywheel author/assignee safety gate. Return false to skip an issue. When\n * absent every issue passes (backward-compatible default). */\n isAuthorizedIssue?: (issueId: string) => boolean;\n /** FR-14 eligibility gate. Return true if the issue has an xBRIEF spec (ready)\n * or a PRD draft (hasPrd). When absent every issue passes (backward-compatible\n * default). */\n isReadyOrHasPrd?: (issueId: string) => boolean;\n /** Supplement the built-in review-status inPipeline check with live workspace/agent\n * state. Return true to treat an issue as in-pipeline and skip it. When absent only\n * review_status is checked (backward-compatible default). */\n isInPipeline?: (issueId: string) => boolean;\n /** PAN-2006 Definition of Ready: when true, only issues carrying the `ready`\n * label are eligible (the hard entry gate). The live Flywheel passes true;\n * legacy callers omit it and keep their pre-DoR behavior. */\n requireReady?: boolean;\n /** PAN-2059 + vision.mdx blanket release: when auto-pickup is ON the toggle\n * satisfies the per-issue `released` gate for the whole backlog. The live Flywheel\n * passes its auto_pickup_backlog setting; legacy callers omit it (default OFF). */\n autoPickupBacklog?: boolean;\n /** Operator-released scope supplied by the active order book. */\n activeBookMembership?: ReadonlySet<string>;\n /**\n * Advisory pre-branch conflict signal. When present, lower predicted-conflict\n * counts sort first among otherwise pickable issues; no issue is filtered out.\n */\n predictedConflictSignals?: ReadonlyArray<PredictedConflictSignal>;\n },\n): SequencePickResult | null {\n // Single source of truth: the same classifier the Forecast UI uses (PAN-2006).\n // `isReadyOrHasPrd` maps to the module's `planned` gate; review_status + the\n // optional callback feed the `inPipeline` gate; vetoed / parked / gate-blocked are\n // derived from labels + the node's gate inside classifyIssue.\n const lookups: ClassifyLookups = {\n labels: opts?.issueLabels ?? (() => []),\n isPlanned: opts?.isReadyOrHasPrd ?? (() => true),\n isInPipeline: (issueId) => {\n const reviewStatus = getReviewStatusSync(issueId.toUpperCase());\n return (reviewStatus !== null && reviewStatus.reviewStatus !== 'pending') ||\n (opts?.isInPipeline?.(issueId) ?? false);\n },\n };\n\n const signalByIssue = new Map((opts?.predictedConflictSignals ?? []).map(signal => [signal.issueId.toUpperCase(), signal]));\n const eligible = [...nodes]\n .sort((a, b) => a.rank - b.rank)\n .filter((node) => {\n const state = classifyIssue(node, lookups);\n // DoR is conditional: when not required, treat readiness as satisfied so the\n // remaining gates (planned / parked / vetoed / in-pipeline) still apply.\n const activeBookMember = opts?.activeBookMembership?.has(node.issue.toUpperCase()) ?? false;\n if (!isAutoPickable(opts?.requireReady ? state : { ...state, ready: true }, opts?.autoPickupBacklog ?? false, activeBookMember)) return false;\n if (opts?.excludeIssueIds?.has(node.issue)) return false;\n if (opts?.isAuthorizedIssue && !opts.isAuthorizedIssue(node.issue)) return false;\n return true;\n });\n\n if (signalByIssue.size > 0) {\n eligible.sort((a, b) => {\n const aSignal = signalByIssue.get(a.issue.toUpperCase());\n const bSignal = signalByIssue.get(b.issue.toUpperCase());\n const aConflicts = aSignal?.conflictCount ?? 0;\n const bConflicts = bSignal?.conflictCount ?? 0;\n if (aConflicts !== bConflicts) return aConflicts - bConflicts;\n return a.rank - b.rank;\n });\n }\n\n for (const node of eligible) {\n const state = classifyIssue(node, lookups);\n const signal = signalByIssue.get(node.issue.toUpperCase());\n return {\n issueId: node.issue,\n rank: node.rank,\n gate: node.gate,\n planning: node.planning,\n predictedConflictCount: signal?.conflictCount,\n predictedConflictsWith: signal?.conflictsWith,\n };\n }\n return null;\n}\n"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { fr as getProviderForModelSync, lr as getBuiltInDefaultHarness, nr as ca
3
3
  import { n as harnessBinaryName, o as resolveHarnessBinary, r as init_harness_binary, t as configuredHarnessBinaryPath } from "./harness-binary-DnRGvN6T.js";
4
4
  //#region ../../lib/harness-resolve.ts
5
5
  async function getProviderAuthModeForModel(model) {
6
- const { getProviderAuthMode } = await import("./agents-BVvL4o_4.js");
6
+ const { getProviderAuthMode } = await import("./agents-CkGhnAmu.js");
7
7
  return getProviderAuthMode(model);
8
8
  }
9
9
  function assertHarnessProviderSupported(harness, provider) {
@@ -74,4 +74,4 @@ var init_harness_resolve = __esmMin((() => {
74
74
  //#endregion
75
75
  export { resolveHarness as n, init_harness_resolve as t };
76
76
 
77
- //# sourceMappingURL=harness-resolve-CzTFVZ5l.js.map
77
+ //# sourceMappingURL=harness-resolve-C0HWj3H9.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"harness-resolve-CzTFVZ5l.js","names":["loadYamlConfig"],"sources":["../../src/lib/harness-resolve.ts"],"sourcesContent":["import { canUseHarnessSync, canUseModelWithAuthSync } from './harness-policy.js';\nimport {\n configuredHarnessBinaryPath,\n harnessBinaryName,\n resolveHarnessBinary,\n} from './harness-binary.js';\nimport { getBuiltInDefaultHarness, getProviderForModelSync } from './providers.js';\nimport type { RuntimeName } from './runtimes/types.js';\nimport type { Role } from './agents.js';\nimport { loadConfigSync as loadYamlConfig } from './config-yaml.js';\n\nconst harnessAvailabilityCache = new Map<string, Promise<boolean>>();\nconst builtInDefaultNoticeProviders = new Set<string>();\n\nexport function resetHarnessResolveCachesForTests(): void {\n if (process.env.NODE_ENV !== 'test') return;\n harnessAvailabilityCache.clear();\n builtInDefaultNoticeProviders.clear();\n}\n\nexport type ResolveHarnessInput = {\n explicit?: RuntimeName;\n role?: Role;\n model: string;\n};\n\nexport class HarnessResolutionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'HarnessResolutionError';\n }\n}\n\nasync function getProviderAuthModeForModel(model: string) {\n const { getProviderAuthMode } = await import('./agents.js');\n return getProviderAuthMode(model);\n}\n\nfunction assertHarnessProviderSupported(harness: RuntimeName, provider: string): void {\n if (harness === 'acp' && provider !== 'kimi') {\n throw new HarnessResolutionError(`ACP provider ${provider} is not supported; Kimi is the only ACP provider in v1.`);\n }\n}\n\nasync function hasHarnessBinary(harness: RuntimeName): Promise<boolean> {\n // Claude Code availability is enforced by the shared launch preflight. Keep\n // the native fallback decision here independent of whether Claude is installed.\n if (harness === 'claude-code') return true;\n\n const executablePath = configuredHarnessBinaryPath(harness);\n const cacheKey = `${harness}\\0${executablePath ?? ''}`;\n const cached = harnessAvailabilityCache.get(cacheKey);\n if (cached) return cached;\n\n const check = resolveHarnessBinary(\n harness,\n executablePath ? { executablePath } : undefined,\n ).then((resolved) => resolved !== null);\n harnessAvailabilityCache.set(cacheKey, check);\n return check;\n}\n\nfunction logBuiltInDefaultNotice(provider: string, harness: RuntimeName): void {\n if (builtInDefaultNoticeProviders.has(provider)) return;\n builtInDefaultNoticeProviders.add(provider);\n console.info(`harness ${harness} chosen by provider default — override in Settings → Providers`);\n}\n\nexport async function resolveHarness(input: ResolveHarnessInput): Promise<RuntimeName> {\n const provider = getProviderForModelSync(input.model).name;\n const { config } = loadYamlConfig();\n // Harness is provider-default UNLESS an explicit pick arrives (PAN-1984 plus\n // the 2026-08-02 explicit-pick refinement). Without `input.explicit`, the\n // harness derives solely from the model's provider — the per-provider default\n // (Settings → Providers) else the built-in default — which kills the class of\n // harness↔model mismatch bugs (e.g. Pi+GPT-5.5 selected when Codex is\n // GPT-5.5's real provider default) and the stale-harness-on-resume bug.\n // `input.role` is accepted for signature compatibility but INTENTIONALLY\n // IGNORED.\n //\n // `input.explicit` IS honored: surfaces that let the operator choose the\n // harness directly (the model picker's harness-labeled rows — \"Kimi K3 (1M)\n // — Kimi Code CLI\" vs \"… — Claude Code\" vs \"… — ACP\") pass it through, and\n // silently discarding it would launch a harness the operator did not pick.\n // The pick is still policy-gated (canUseHarnessSync) and fail-loud: a denied\n // combo or a missing binary throws instead of rerouting to the provider\n // default.\n const providerHarness = config.providerHarnesses?.[provider];\n const builtInHarness = getBuiltInDefaultHarness(provider);\n const explicit = input.explicit;\n\n const winner = explicit ?? providerHarness ?? builtInHarness ?? 'claude-code';\n\n if (!providerHarness && !explicit) {\n logBuiltInDefaultNotice(provider, winner);\n }\n\n const authMode = await getProviderAuthModeForModel(input.model);\n const modelDecision = canUseModelWithAuthSync(input.model, authMode);\n if (!modelDecision.allowed) {\n throw new HarnessResolutionError(modelDecision.reason ?? `Model ${input.model} is not allowed with the current auth mode`);\n }\n\n const decision = canUseHarnessSync(winner, input.model, authMode);\n if (!decision.allowed) {\n if (explicit) {\n throw new HarnessResolutionError(\n `Harness ${explicit} denied for ${input.model} (${decision.reason ?? 'policy denied'}) — refusing to silently reroute an explicit harness pick to the provider default.`,\n );\n }\n // PAN-1871 — only fall back to claude-code when it is the model's NATIVE\n // harness (Anthropic). For CLIProxy-routed models (kimi, gpt-5.5, …) the\n // provider default is pi/codex; claude-code would route them through\n // CLIProxy and hit the 200k-window-illusion deadlock. Silently degrading\n // there is worse than failing, so refuse it loudly.\n if (builtInHarness && builtInHarness !== 'claude-code') {\n throw new HarnessResolutionError(\n `Harness ${winner} denied for ${input.model} (${decision.reason ?? 'policy denied'}); ${input.model} is not native to claude-code (provider default is ${builtInHarness}), so refusing to silently fall back to claude-code/CLIProxy. Resolve ${winner} availability/auth and retry.`,\n );\n }\n\n const fallbackDecision = canUseHarnessSync('claude-code', input.model, authMode);\n if (!fallbackDecision.allowed) {\n throw new HarnessResolutionError(decision.reason ?? fallbackDecision.reason ?? `Harness ${winner} is not allowed for ${input.model}`);\n }\n\n console.warn(`harness ${winner} denied for ${provider}: ${decision.reason ?? 'policy denied'} — falling back to native claude-code`);\n return 'claude-code';\n }\n\n assertHarnessProviderSupported(winner, provider);\n\n if (!(await hasHarnessBinary(winner))) {\n const binary = configuredHarnessBinaryPath(winner) ?? harnessBinaryName(winner);\n // PAN-1871 — never silently fall back to claude-code from a non-native\n // (CLIProxy) model whose own binary is missing at spawn. An explicitly\n // configured ACP harness — or any explicit operator pick — has the same\n // fail-loud contract: falling back would silently ignore the operator's\n // transport choice.\n if (explicit || winner === 'acp' || (builtInHarness && builtInHarness !== 'claude-code')) {\n const remediation = configuredHarnessBinaryPath(winner)\n ? `Fix the configured executable path ${binary} and retry.`\n : `Install ${binary} (check its PATH) and retry.`;\n throw new HarnessResolutionError(\n `Harness ${winner} for ${input.model} has no installed ${binary} binary at spawn — refusing to silently fall back to claude-code. ${remediation}`,\n );\n }\n console.warn(`harness ${winner} requested for ${provider}, but ${binary} is not installed — falling back to native claude-code`);\n return 'claude-code';\n }\n\n return winner;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"harness-resolve-C0HWj3H9.js","names":["loadYamlConfig"],"sources":["../../src/lib/harness-resolve.ts"],"sourcesContent":["import { canUseHarnessSync, canUseModelWithAuthSync } from './harness-policy.js';\nimport {\n configuredHarnessBinaryPath,\n harnessBinaryName,\n resolveHarnessBinary,\n} from './harness-binary.js';\nimport { getBuiltInDefaultHarness, getProviderForModelSync } from './providers.js';\nimport type { RuntimeName } from './runtimes/types.js';\nimport type { Role } from './agents.js';\nimport { loadConfigSync as loadYamlConfig } from './config-yaml.js';\n\nconst harnessAvailabilityCache = new Map<string, Promise<boolean>>();\nconst builtInDefaultNoticeProviders = new Set<string>();\n\nexport function resetHarnessResolveCachesForTests(): void {\n if (process.env.NODE_ENV !== 'test') return;\n harnessAvailabilityCache.clear();\n builtInDefaultNoticeProviders.clear();\n}\n\nexport type ResolveHarnessInput = {\n explicit?: RuntimeName;\n role?: Role;\n model: string;\n};\n\nexport class HarnessResolutionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'HarnessResolutionError';\n }\n}\n\nasync function getProviderAuthModeForModel(model: string) {\n const { getProviderAuthMode } = await import('./agents.js');\n return getProviderAuthMode(model);\n}\n\nfunction assertHarnessProviderSupported(harness: RuntimeName, provider: string): void {\n if (harness === 'acp' && provider !== 'kimi') {\n throw new HarnessResolutionError(`ACP provider ${provider} is not supported; Kimi is the only ACP provider in v1.`);\n }\n}\n\nasync function hasHarnessBinary(harness: RuntimeName): Promise<boolean> {\n // Claude Code availability is enforced by the shared launch preflight. Keep\n // the native fallback decision here independent of whether Claude is installed.\n if (harness === 'claude-code') return true;\n\n const executablePath = configuredHarnessBinaryPath(harness);\n const cacheKey = `${harness}\\0${executablePath ?? ''}`;\n const cached = harnessAvailabilityCache.get(cacheKey);\n if (cached) return cached;\n\n const check = resolveHarnessBinary(\n harness,\n executablePath ? { executablePath } : undefined,\n ).then((resolved) => resolved !== null);\n harnessAvailabilityCache.set(cacheKey, check);\n return check;\n}\n\nfunction logBuiltInDefaultNotice(provider: string, harness: RuntimeName): void {\n if (builtInDefaultNoticeProviders.has(provider)) return;\n builtInDefaultNoticeProviders.add(provider);\n console.info(`harness ${harness} chosen by provider default — override in Settings → Providers`);\n}\n\nexport async function resolveHarness(input: ResolveHarnessInput): Promise<RuntimeName> {\n const provider = getProviderForModelSync(input.model).name;\n const { config } = loadYamlConfig();\n // Harness is provider-default UNLESS an explicit pick arrives (PAN-1984 plus\n // the 2026-08-02 explicit-pick refinement). Without `input.explicit`, the\n // harness derives solely from the model's provider — the per-provider default\n // (Settings → Providers) else the built-in default — which kills the class of\n // harness↔model mismatch bugs (e.g. Pi+GPT-5.5 selected when Codex is\n // GPT-5.5's real provider default) and the stale-harness-on-resume bug.\n // `input.role` is accepted for signature compatibility but INTENTIONALLY\n // IGNORED.\n //\n // `input.explicit` IS honored: surfaces that let the operator choose the\n // harness directly (the model picker's harness-labeled rows — \"Kimi K3 (1M)\n // — Kimi Code CLI\" vs \"… — Claude Code\" vs \"… — ACP\") pass it through, and\n // silently discarding it would launch a harness the operator did not pick.\n // The pick is still policy-gated (canUseHarnessSync) and fail-loud: a denied\n // combo or a missing binary throws instead of rerouting to the provider\n // default.\n const providerHarness = config.providerHarnesses?.[provider];\n const builtInHarness = getBuiltInDefaultHarness(provider);\n const explicit = input.explicit;\n\n const winner = explicit ?? providerHarness ?? builtInHarness ?? 'claude-code';\n\n if (!providerHarness && !explicit) {\n logBuiltInDefaultNotice(provider, winner);\n }\n\n const authMode = await getProviderAuthModeForModel(input.model);\n const modelDecision = canUseModelWithAuthSync(input.model, authMode);\n if (!modelDecision.allowed) {\n throw new HarnessResolutionError(modelDecision.reason ?? `Model ${input.model} is not allowed with the current auth mode`);\n }\n\n const decision = canUseHarnessSync(winner, input.model, authMode);\n if (!decision.allowed) {\n if (explicit) {\n throw new HarnessResolutionError(\n `Harness ${explicit} denied for ${input.model} (${decision.reason ?? 'policy denied'}) — refusing to silently reroute an explicit harness pick to the provider default.`,\n );\n }\n // PAN-1871 — only fall back to claude-code when it is the model's NATIVE\n // harness (Anthropic). For CLIProxy-routed models (kimi, gpt-5.5, …) the\n // provider default is pi/codex; claude-code would route them through\n // CLIProxy and hit the 200k-window-illusion deadlock. Silently degrading\n // there is worse than failing, so refuse it loudly.\n if (builtInHarness && builtInHarness !== 'claude-code') {\n throw new HarnessResolutionError(\n `Harness ${winner} denied for ${input.model} (${decision.reason ?? 'policy denied'}); ${input.model} is not native to claude-code (provider default is ${builtInHarness}), so refusing to silently fall back to claude-code/CLIProxy. Resolve ${winner} availability/auth and retry.`,\n );\n }\n\n const fallbackDecision = canUseHarnessSync('claude-code', input.model, authMode);\n if (!fallbackDecision.allowed) {\n throw new HarnessResolutionError(decision.reason ?? fallbackDecision.reason ?? `Harness ${winner} is not allowed for ${input.model}`);\n }\n\n console.warn(`harness ${winner} denied for ${provider}: ${decision.reason ?? 'policy denied'} — falling back to native claude-code`);\n return 'claude-code';\n }\n\n assertHarnessProviderSupported(winner, provider);\n\n if (!(await hasHarnessBinary(winner))) {\n const binary = configuredHarnessBinaryPath(winner) ?? harnessBinaryName(winner);\n // PAN-1871 — never silently fall back to claude-code from a non-native\n // (CLIProxy) model whose own binary is missing at spawn. An explicitly\n // configured ACP harness — or any explicit operator pick — has the same\n // fail-loud contract: falling back would silently ignore the operator's\n // transport choice.\n if (explicit || winner === 'acp' || (builtInHarness && builtInHarness !== 'claude-code')) {\n const remediation = configuredHarnessBinaryPath(winner)\n ? `Fix the configured executable path ${binary} and retry.`\n : `Install ${binary} (check its PATH) and retry.`;\n throw new HarnessResolutionError(\n `Harness ${winner} for ${input.model} has no installed ${binary} binary at spawn — refusing to silently fall back to claude-code. ${remediation}`,\n );\n }\n console.warn(`harness ${winner} requested for ${provider}, but ${binary} is not installed — falling back to native claude-code`);\n return 'claude-code';\n }\n\n return winner;\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { Ri as init_paths, hi as CONFIG_FILE } from "./config-yaml-Dce9VUd6.js";
2
2
  import { t as require_toml } from "./toml-CeLDATih.js";
3
- import { t as getBuildInfo } from "./build-info-Cj3Y0K87.js";
3
+ import { t as getBuildInfo } from "./build-info-D0EJNj6C.js";
4
4
  import { relative, resolve, sep } from "node:path";
5
5
  import { existsSync, readFileSync, statSync } from "node:fs";
6
6
  import { cwd } from "node:process";
@@ -55,4 +55,4 @@ function shouldRefuseHostDashboardPort(input) {
55
55
  //#endregion
56
56
  export { shouldRefuseHostDashboardPort as i, isNonPrimaryCheckoutRoot as n, readHostDashboardApiPort as r, getDashboardIdentity as t };
57
57
 
58
- //# sourceMappingURL=identity-Dc7rQLln.js.map
58
+ //# sourceMappingURL=identity-Cot1Hg4G.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"identity-Dc7rQLln.js","names":[],"sources":["../../src/dashboard/server/identity.ts"],"sourcesContent":["import { existsSync, readFileSync, statSync } from 'node:fs';\nimport { cwd } from 'node:process';\nimport { relative, resolve, sep } from 'node:path';\n\nimport { parse as parseToml } from '@iarna/toml';\n\nimport { CONFIG_FILE } from '../../lib/paths.js';\nimport { getBuildInfo, type BuildInfo } from '../../lib/deploy/build-info.js';\n\nexport type DashboardMode = 'primary' | 'peer';\n\nexport interface DashboardIdentity extends BuildInfo {\n readonly repoRoot: string;\n readonly mode: DashboardMode;\n readonly pid: number;\n}\n\nexport function getDashboardIdentity(): DashboardIdentity {\n return {\n repoRoot: resolve(cwd()),\n mode: process.env.OVERDECK_DISABLE_DEACON === '1' ? 'peer' : 'primary',\n pid: process.pid,\n ...getBuildInfo(),\n };\n}\n\nexport function isWorkspaceRepoRoot(repoRoot: string): boolean {\n return /(^|\\/)workspaces\\/feature-[^/]+$/i.test(repoRoot.replaceAll('\\\\', '/'));\n}\n\nexport function isLinkedWorktreeRoot(repoRoot: string): boolean {\n try {\n return statSync(resolve(repoRoot, '.git')).isFile();\n } catch {\n return false;\n }\n}\n\nexport function primaryRootFromLinkedWorktree(repoRoot: string): string | null {\n try {\n const match = readFileSync(resolve(repoRoot, '.git'), 'utf-8').match(/^gitdir:\\s*(.+)$/m);\n const gitDir = match?.[1]?.trim().replaceAll('\\\\', '/');\n if (!gitDir) return null;\n\n const worktreeMarker = '/.git/worktrees/';\n const markerIndex = gitDir.indexOf(worktreeMarker);\n return markerIndex === -1 ? null : gitDir.slice(0, markerIndex);\n } catch {\n return null;\n }\n}\n\nfunction isSameOrInside(parent: string, candidate: string): boolean {\n const rel = relative(resolve(parent), resolve(candidate));\n return rel === '' || (!rel.startsWith('..') && !rel.startsWith(sep));\n}\n\nexport function isNonPrimaryCheckoutRoot(repoRoot: string): boolean {\n const resolvedRoot = resolve(repoRoot);\n return isLinkedWorktreeRoot(resolvedRoot) || isWorkspaceRepoRoot(resolvedRoot);\n}\n\nexport function readHostDashboardApiPort(defaultPort = 3011): number {\n if (!existsSync(CONFIG_FILE)) return defaultPort;\n try {\n const config = parseToml(readFileSync(CONFIG_FILE, 'utf-8')) as {\n dashboard?: { api_port?: unknown };\n };\n const value = config.dashboard?.api_port;\n return typeof value === 'number' && Number.isFinite(value) ? value : defaultPort;\n } catch {\n return defaultPort;\n }\n}\n\nexport function shouldRefuseHostDashboardPort(input: {\n readonly repoRoot: string;\n readonly mode: DashboardMode;\n readonly port: number;\n readonly hostDashboardApiPort?: number;\n readonly runningInContainer?: boolean;\n}): boolean {\n const hostDashboardApiPort = input.hostDashboardApiPort ?? readHostDashboardApiPort();\n if (input.port !== hostDashboardApiPort) return false;\n\n const repoRoot = resolve(input.repoRoot);\n const runningInContainer =\n input.runningInContainer ?? (existsSync('/.dockerenv') || repoRoot === '/workspaces/overdeck');\n if (runningInContainer) {\n return false;\n }\n if (input.mode === 'peer') return true;\n if (isNonPrimaryCheckoutRoot(repoRoot)) return true;\n\n const workspacesDir = resolve(repoRoot, '..');\n return workspacesDir.endsWith(`${sep}workspaces`) && isSameOrInside(workspacesDir, repoRoot);\n}\n"],"mappings":";;;;;;;;YAMiD;AAWjD,SAAgB,uBAA0C;AACxD,QAAO;EACL,UAAU,QAAQ,KAAK,CAAC;EACxB,MAAM,QAAQ,IAAI,4BAA4B,MAAM,SAAS;EAC7D,KAAK,QAAQ;EACb,GAAG,cAAc;EAClB;;AAGH,SAAgB,oBAAoB,UAA2B;AAC7D,QAAO,oCAAoC,KAAK,SAAS,WAAW,MAAM,IAAI,CAAC;;AAGjF,SAAgB,qBAAqB,UAA2B;AAC9D,KAAI;AACF,SAAO,SAAS,QAAQ,UAAU,OAAO,CAAC,CAAC,QAAQ;SAC7C;AACN,SAAO;;;AAkBX,SAAS,eAAe,QAAgB,WAA4B;CAClE,MAAM,MAAM,SAAS,QAAQ,OAAO,EAAE,QAAQ,UAAU,CAAC;AACzD,QAAO,QAAQ,MAAO,CAAC,IAAI,WAAW,KAAK,IAAI,CAAC,IAAI,WAAW,IAAI;;AAGrE,SAAgB,yBAAyB,UAA2B;CAClE,MAAM,eAAe,QAAQ,SAAS;AACtC,QAAO,qBAAqB,aAAa,IAAI,oBAAoB,aAAa;;AAGhF,SAAgB,yBAAyB,cAAc,MAAc;AACnE,KAAI,CAAC,WAAW,YAAY,CAAE,QAAO;AACrC,KAAI;EAIF,MAAM,SAAA,GAAA,YAAA,OAHmB,aAAa,aAAa,QAAQ,CAGvC,CAAC,WAAW;AAChC,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,MAAM,GAAG,QAAQ;SAC/D;AACN,SAAO;;;AAIX,SAAgB,8BAA8B,OAMlC;CACV,MAAM,uBAAuB,MAAM,wBAAwB,0BAA0B;AACrF,KAAI,MAAM,SAAS,qBAAsB,QAAO;CAEhD,MAAM,WAAW,QAAQ,MAAM,SAAS;AAGxC,KADE,MAAM,uBAAuB,WAAW,cAAc,IAAI,aAAa,wBAEvE,QAAO;AAET,KAAI,MAAM,SAAS,OAAQ,QAAO;AAClC,KAAI,yBAAyB,SAAS,CAAE,QAAO;CAE/C,MAAM,gBAAgB,QAAQ,UAAU,KAAK;AAC7C,QAAO,cAAc,SAAS,GAAG,IAAI,YAAY,IAAI,eAAe,eAAe,SAAS"}
1
+ {"version":3,"file":"identity-Cot1Hg4G.js","names":[],"sources":["../../src/dashboard/server/identity.ts"],"sourcesContent":["import { existsSync, readFileSync, statSync } from 'node:fs';\nimport { cwd } from 'node:process';\nimport { relative, resolve, sep } from 'node:path';\n\nimport { parse as parseToml } from '@iarna/toml';\n\nimport { CONFIG_FILE } from '../../lib/paths.js';\nimport { getBuildInfo, type BuildInfo } from '../../lib/deploy/build-info.js';\n\nexport type DashboardMode = 'primary' | 'peer';\n\nexport interface DashboardIdentity extends BuildInfo {\n readonly repoRoot: string;\n readonly mode: DashboardMode;\n readonly pid: number;\n}\n\nexport function getDashboardIdentity(): DashboardIdentity {\n return {\n repoRoot: resolve(cwd()),\n mode: process.env.OVERDECK_DISABLE_DEACON === '1' ? 'peer' : 'primary',\n pid: process.pid,\n ...getBuildInfo(),\n };\n}\n\nexport function isWorkspaceRepoRoot(repoRoot: string): boolean {\n return /(^|\\/)workspaces\\/feature-[^/]+$/i.test(repoRoot.replaceAll('\\\\', '/'));\n}\n\nexport function isLinkedWorktreeRoot(repoRoot: string): boolean {\n try {\n return statSync(resolve(repoRoot, '.git')).isFile();\n } catch {\n return false;\n }\n}\n\nexport function primaryRootFromLinkedWorktree(repoRoot: string): string | null {\n try {\n const match = readFileSync(resolve(repoRoot, '.git'), 'utf-8').match(/^gitdir:\\s*(.+)$/m);\n const gitDir = match?.[1]?.trim().replaceAll('\\\\', '/');\n if (!gitDir) return null;\n\n const worktreeMarker = '/.git/worktrees/';\n const markerIndex = gitDir.indexOf(worktreeMarker);\n return markerIndex === -1 ? null : gitDir.slice(0, markerIndex);\n } catch {\n return null;\n }\n}\n\nfunction isSameOrInside(parent: string, candidate: string): boolean {\n const rel = relative(resolve(parent), resolve(candidate));\n return rel === '' || (!rel.startsWith('..') && !rel.startsWith(sep));\n}\n\nexport function isNonPrimaryCheckoutRoot(repoRoot: string): boolean {\n const resolvedRoot = resolve(repoRoot);\n return isLinkedWorktreeRoot(resolvedRoot) || isWorkspaceRepoRoot(resolvedRoot);\n}\n\nexport function readHostDashboardApiPort(defaultPort = 3011): number {\n if (!existsSync(CONFIG_FILE)) return defaultPort;\n try {\n const config = parseToml(readFileSync(CONFIG_FILE, 'utf-8')) as {\n dashboard?: { api_port?: unknown };\n };\n const value = config.dashboard?.api_port;\n return typeof value === 'number' && Number.isFinite(value) ? value : defaultPort;\n } catch {\n return defaultPort;\n }\n}\n\nexport function shouldRefuseHostDashboardPort(input: {\n readonly repoRoot: string;\n readonly mode: DashboardMode;\n readonly port: number;\n readonly hostDashboardApiPort?: number;\n readonly runningInContainer?: boolean;\n}): boolean {\n const hostDashboardApiPort = input.hostDashboardApiPort ?? readHostDashboardApiPort();\n if (input.port !== hostDashboardApiPort) return false;\n\n const repoRoot = resolve(input.repoRoot);\n const runningInContainer =\n input.runningInContainer ?? (existsSync('/.dockerenv') || repoRoot === '/workspaces/overdeck');\n if (runningInContainer) {\n return false;\n }\n if (input.mode === 'peer') return true;\n if (isNonPrimaryCheckoutRoot(repoRoot)) return true;\n\n const workspacesDir = resolve(repoRoot, '..');\n return workspacesDir.endsWith(`${sep}workspaces`) && isSameOrInside(workspacesDir, repoRoot);\n}\n"],"mappings":";;;;;;;;YAMiD;AAWjD,SAAgB,uBAA0C;AACxD,QAAO;EACL,UAAU,QAAQ,KAAK,CAAC;EACxB,MAAM,QAAQ,IAAI,4BAA4B,MAAM,SAAS;EAC7D,KAAK,QAAQ;EACb,GAAG,cAAc;EAClB;;AAGH,SAAgB,oBAAoB,UAA2B;AAC7D,QAAO,oCAAoC,KAAK,SAAS,WAAW,MAAM,IAAI,CAAC;;AAGjF,SAAgB,qBAAqB,UAA2B;AAC9D,KAAI;AACF,SAAO,SAAS,QAAQ,UAAU,OAAO,CAAC,CAAC,QAAQ;SAC7C;AACN,SAAO;;;AAkBX,SAAS,eAAe,QAAgB,WAA4B;CAClE,MAAM,MAAM,SAAS,QAAQ,OAAO,EAAE,QAAQ,UAAU,CAAC;AACzD,QAAO,QAAQ,MAAO,CAAC,IAAI,WAAW,KAAK,IAAI,CAAC,IAAI,WAAW,IAAI;;AAGrE,SAAgB,yBAAyB,UAA2B;CAClE,MAAM,eAAe,QAAQ,SAAS;AACtC,QAAO,qBAAqB,aAAa,IAAI,oBAAoB,aAAa;;AAGhF,SAAgB,yBAAyB,cAAc,MAAc;AACnE,KAAI,CAAC,WAAW,YAAY,CAAE,QAAO;AACrC,KAAI;EAIF,MAAM,SAAA,GAAA,YAAA,OAHmB,aAAa,aAAa,QAAQ,CAGvC,CAAC,WAAW;AAChC,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,MAAM,GAAG,QAAQ;SAC/D;AACN,SAAO;;;AAIX,SAAgB,8BAA8B,OAMlC;CACV,MAAM,uBAAuB,MAAM,wBAAwB,0BAA0B;AACrF,KAAI,MAAM,SAAS,qBAAsB,QAAO;CAEhD,MAAM,WAAW,QAAQ,MAAM,SAAS;AAGxC,KADE,MAAM,uBAAuB,WAAW,cAAc,IAAI,aAAa,wBAEvE,QAAO;AAET,KAAI,MAAM,SAAS,OAAQ,QAAO;AAClC,KAAI,yBAAyB,SAAS,CAAE,QAAO;CAE/C,MAAM,gBAAgB,QAAQ,UAAU,KAAK;AAC7C,QAAO,cAAc,SAAS,GAAG,IAAI,YAAY,IAAI,eAAe,eAAe,SAAS"}
@@ -1,13 +1,13 @@
1
1
  import { E as init_tier_table, O as resolveTieredExecutionEnabled, cr as clearCredentialFileAuthSync, fr as getProviderForModelSync, kr as resolveModel, oi as ProcessSpawnError, p as loadConfigSync, pr as init_providers, t as init_config_yaml, ui as init_errors, vr as setupCredentialFileAuthSync } from "./config-yaml-Dce9VUd6.js";
2
2
  import { C as init_tmux, E as killSession, U as sessionExists, s as createSession } from "./tmux-l-yvNWhg.js";
3
- import { $ as deliverCommitForReview, Ji as getProviderEnvForModel, K as saveAgentRuntimeState, Or as init_delivery, et as init_tier_supervisor, it as supervisorAgentId, k as saveAgentState, mi as init_runtime_command, q as init_agents, rt as spawnTierSupervisor, tt as loadPrdDraft, wr as deliverAgentMessage, yi as claudeSystemPromptFiles } from "./agent-state-Ci6PhjOE.js";
3
+ import { $ as deliverCommitForReview, K as saveAgentRuntimeState, Or as init_delivery, Xi as getProviderEnvForModel, et as init_tier_supervisor, gi as init_runtime_command, it as supervisorAgentId, k as saveAgentState, q as init_agents, rt as spawnTierSupervisor, tt as loadPrdDraft, wr as deliverAgentMessage, xi as claudeSystemPromptFiles } from "./agent-state-B196fj1h.js";
4
4
  import { C as generateLauncherScriptSync, w as init_launcher_generator } from "./auto-spawn-consent-CJeQM5e0.js";
5
5
  import { a as init_claude_permissions, i as getClaudePermissionFlagsSync } from "./claude-permissions-DX5BSnMH.js";
6
6
  import { i as prepareHarnessLaunch, r as init_harness_binary } from "./harness-binary-DnRGvN6T.js";
7
7
  import { h as readWorkspacePlanSync, s as init_io } from "./io-Cm4Sf_6P.js";
8
8
  import { a as init_git_utils, o as parseCompositeSnapshot, u as snapshotWorkspaceHeadsPromise } from "./git-utils-D96xW28f.js";
9
9
  import { d as resolveWorkspaceRepoRootsSync, i as init_project_repos } from "./project-repos-J6jc42uD.js";
10
- import { p as init_review_status, w as setReviewStatusSync } from "./review-status-BegAr86G.js";
10
+ import { p as init_review_status, w as setReviewStatusSync } from "./review-status-yY5qt7Rl.js";
11
11
  import { n as init_issue_closed, r as isIssueClosed } from "./issue-closed-D7aMUeMq.js";
12
12
  import { Effect } from "effect";
13
13
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -400,4 +400,4 @@ function onInspectComplete(projectKey, issueId, itemId, status, workspacePath, n
400
400
  //#endregion
401
401
  export { onInspectComplete as n, spawnInspectAgent as r, buildInspectPrompt as t };
402
402
 
403
- //# sourceMappingURL=inspect-agent-CP7Bu47O.js.map
403
+ //# sourceMappingURL=inspect-agent-BDmLWbGx.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"inspect-agent-CP7Bu47O.js","names":["loadYamlConfig"],"sources":["../../src/lib/cloister/inspect-checkpoints.ts","../../src/lib/cloister/inspect-agent.ts"],"sourcesContent":["/**\n * PAN-382: Inspection checkpoint system.\n *\n * Tracks commit SHAs where inspections passed. The active inspection diff is\n * scoped to the parent of HEAD because the work role contract is one bead per\n * commit; checkpoints remain the durable record after a pass.\n */\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport { Effect } from 'effect';\nimport { resolveWorkspaceRepoRootsSync, type WorkspaceRepoRoot } from '../project-repos.js';\nimport { parseCompositeSnapshot, snapshotWorkspaceHeadsPromise } from '../git-utils.js';\n\nconst execAsync = promisify(exec);\n\nconst OVERDECK_HOME = join(homedir(), '.overdeck');\n\nexport interface InspectCheckpoint {\n itemId: string;\n commitSha: string;\n passedAt: string; // ISO 8601\n}\n\nexport interface InspectCheckpointFile {\n issueId: string;\n checkpoints: InspectCheckpoint[];\n}\n\n/**\n * Get the directory for a project's inspect checkpoints.\n */\nfunction getCheckpointDir(projectKey: string): string {\n return join(OVERDECK_HOME, 'specialists', projectKey, 'inspect-agent', 'checkpoints');\n}\n\n/**\n * Get the checkpoint file path for an issue.\n */\nfunction getCheckpointPath(projectKey: string, issueId: string): string {\n return join(getCheckpointDir(projectKey), `${issueId.toUpperCase()}.json`);\n}\n\n/**\n * Load checkpoints for an issue. Returns null if no checkpoints exist.\n */\nexport function loadCheckpoints(projectKey: string, issueId: string): InspectCheckpointFile | null {\n const filePath = getCheckpointPath(projectKey, issueId);\n if (!existsSync(filePath)) return null;\n\n try {\n return JSON.parse(readFileSync(filePath, 'utf-8'));\n } catch {\n return null;\n }\n}\n\n/**\n * Get the last checkpoint for an issue, or null if none exist.\n */\nexport function getLastCheckpoint(projectKey: string, issueId: string): InspectCheckpoint | null {\n const data = loadCheckpoints(projectKey, issueId);\n if (!data || data.checkpoints.length === 0) return null;\n return data.checkpoints[data.checkpoints.length - 1];\n}\n\n/**\n * Save a new checkpoint after a successful inspection.\n */\nexport function saveCheckpoint(\n projectKey: string,\n issueId: string,\n itemId: string,\n commitSha: string\n): InspectCheckpoint {\n const dir = getCheckpointDir(projectKey);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n const data = loadCheckpoints(projectKey, issueId) || {\n issueId: issueId.toUpperCase(),\n checkpoints: [],\n };\n\n const checkpoint: InspectCheckpoint = {\n itemId,\n commitSha,\n passedAt: new Date().toISOString(),\n };\n\n data.checkpoints.push(checkpoint);\n writeFileSync(getCheckpointPath(projectKey, issueId), JSON.stringify(data, null, 2));\n\n return checkpoint;\n}\n\nexport interface InspectDiffRepo {\n repoKey: string;\n dir: string;\n headSha: string;\n diffBase: string;\n}\n\nexport interface InspectDiffContext {\n currentHead: string;\n checkpoint: string;\n diffStats: string;\n diffCommand: string;\n repos: InspectDiffRepo[];\n}\n\nfunction shellQuote(value: string): string {\n return `'${value.replace(/'/g, `'\"'\"'`)}'`;\n}\n\nasync function readHead(root: WorkspaceRepoRoot): Promise<string | null> {\n try {\n const { stdout } = await execAsync('git rev-parse HEAD', {\n cwd: root.dir,\n encoding: 'utf-8',\n timeout: 10_000,\n });\n return stdout.trim() || null;\n } catch {\n return null;\n }\n}\n\nasync function resolveTargetBase(root: WorkspaceRepoRoot): Promise<string> {\n for (const target of [`origin/${root.targetBranch}`, root.targetBranch]) {\n try {\n const { stdout } = await execAsync(`git merge-base ${shellQuote(target)} HEAD`, {\n cwd: root.dir,\n encoding: 'utf-8',\n timeout: 10_000,\n });\n const base = stdout.trim();\n if (base) return base;\n } catch { /* try the next target */ }\n }\n try {\n const { stdout } = await execAsync('git rev-parse HEAD^', {\n cwd: root.dir,\n encoding: 'utf-8',\n timeout: 10_000,\n });\n return stdout.trim();\n } catch {\n return root.targetBranch;\n }\n}\n\n/**\n * Resolve the per-item inspection diff across the actual workspace repositories.\n * Polyrepo checkpoints store composite `repo@sha` snapshots so unchanged repos\n * are omitted instead of reviewing their previous, unrelated commit.\n */\nasync function getInspectDiffContextPromise(\n projectKey: string,\n issueId: string,\n workspacePath: string,\n): Promise<InspectDiffContext> {\n const roots = resolveWorkspaceRepoRootsSync(issueId, workspacePath);\n const isPolyrepo = roots.some(root => root.isPolyrepo);\n const previousHeads = isPolyrepo\n ? parseCompositeSnapshot(getLastCheckpoint(projectKey, issueId)?.commitSha)\n : new Map<string, string>();\n const repos: InspectDiffRepo[] = [];\n\n for (const root of roots) {\n const headSha = await readHead(root);\n if (!headSha) continue;\n\n let diffBase: string;\n if (isPolyrepo) {\n const previousHead = previousHeads.get(root.repoKey);\n if (previousHead === headSha) continue;\n diffBase = previousHead ?? await resolveTargetBase(root);\n if (diffBase === headSha) continue;\n } else {\n try {\n const { stdout } = await execAsync('git rev-parse HEAD^', {\n cwd: root.dir,\n encoding: 'utf-8',\n timeout: 10_000,\n });\n diffBase = stdout.trim();\n } catch {\n diffBase = root.targetBranch;\n }\n }\n\n repos.push({ repoKey: root.repoKey, dir: root.dir, headSha, diffBase });\n }\n\n const statSections: string[] = [];\n const commands: string[] = [];\n for (const repo of repos) {\n let stat = 'Unable to compute diff stats';\n try {\n const { stdout } = await execAsync(`git diff --stat ${shellQuote(repo.diffBase)}...HEAD`, {\n cwd: repo.dir,\n encoding: 'utf-8',\n timeout: 15_000,\n });\n stat = stdout.trim() || 'No changes detected';\n } catch { /* retain the human-readable fallback */ }\n\n statSections.push(isPolyrepo ? `── ${repo.repoKey} ──\\n${stat}` : stat);\n commands.push(\n `${isPolyrepo ? `printf '\\\\n── ${repo.repoKey} ──\\\\n'\\n` : ''}` +\n `git -C ${shellQuote(repo.dir)} diff ${shellQuote(repo.diffBase)}...HEAD`,\n );\n }\n\n const currentHead = await snapshotWorkspaceHeadsPromise(issueId, workspacePath) ?? 'unknown';\n return {\n currentHead,\n checkpoint: repos.length > 0\n ? repos.map(repo => isPolyrepo ? `${repo.repoKey}@${repo.diffBase.slice(0, 8)}` : repo.diffBase).join(' ')\n : currentHead,\n diffStats: statSections.join('\\n') || 'No changes detected across workspace repositories',\n diffCommand: commands.join('\\n') || `printf '%s\\\\n' 'No changes detected across workspace repositories'`,\n repos,\n };\n}\n\nexport function getInspectDiffContext(\n projectKey: string,\n issueId: string,\n workspacePath: string,\n): Effect.Effect<InspectDiffContext> {\n return Effect.promise(() => getInspectDiffContextPromise(projectKey, issueId, workspacePath));\n}\n\n/** Resolve the code HEAD(s), never the polyrepo wrapper commit. */\nexport function getCurrentHead(issueId: string, workspacePath: string): Effect.Effect<string> {\n return Effect.promise(async () =>\n await snapshotWorkspaceHeadsPromise(issueId, workspacePath) ?? 'unknown'\n );\n}\n","/**\n * PAN-382: Inspect Agent — Per-step verification specialist.\n *\n * Spawns after each item completion to verify the implementation matches\n * its specification and architectural constraints before the agent\n * proceeds to the next item.\n */\n\nimport { readFileSync, existsSync, writeFileSync, mkdirSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { homedir } from 'os';\nimport { randomUUID } from 'crypto';\nimport { fileURLToPath } from 'url';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport { Effect } from 'effect';\nimport { ProcessSpawnError } from '../errors.js';\nimport {\n getInspectDiffContext,\n getCurrentHead,\n saveCheckpoint,\n} from './inspect-checkpoints.js';\nimport { setReviewStatusSync } from '../review-status.js';\nimport { prepareHarnessLaunch } from '../harness-binary.js';\nimport { generateLauncherScriptSync } from '../launcher-generator.js';\nimport { claudeSystemPromptFiles } from '../agents/runtime-command.js';\nimport {\n createSession,\n killSession,\n sessionExists,\n} from '../tmux.js';\nimport { loadConfigSync as loadYamlConfig, resolveModel } from '../config-yaml.js';\nimport { getClaudePermissionFlagsSync } from '../claude-permissions.js';\nimport {\n getProviderForModelSync,\n setupCredentialFileAuthSync,\n clearCredentialFileAuthSync,\n} from '../providers.js';\nimport type { ModelId } from '../settings.js';\nimport { getProviderEnvForModel, saveAgentRuntimeState, saveAgentState } from '../agents.js';\nimport { isIssueClosed } from './issue-closed.js';\nimport { readWorkspacePlanSync } from '../xbrief/io.js';\nimport { resolveTieredExecutionEnabled } from '../agents/tier-table.js';\nimport {\n deliverCommitForReview,\n loadPrdDraft,\n spawnTierSupervisor,\n supervisorAgentId,\n} from '../agents/tier-supervisor.js';\nimport { deliverAgentMessage } from '../agents/delivery.js';\n\nconst execAsync = promisify(exec);\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Context for an inspection request\n */\nexport interface InspectContext {\n projectKey: string;\n projectPath: string;\n issueId: string;\n /** Canonical xBRIEF item id being inspected. */\n itemId: string;\n workspace: string;\n branch?: string;\n}\n\n/**\n * Result of inspection\n */\nexport interface InspectResult {\n success: boolean;\n inspectResult: 'PASS' | 'BLOCKED';\n itemId: string;\n notes?: string;\n}\n\nasync function buildInspectPromptPromise(context: InspectContext): Promise<string> {\n const templatePath = join(__dirname, 'prompts', 'inspect-agent.md');\n\n if (!existsSync(templatePath)) {\n throw new Error(`Inspect agent prompt template not found at ${templatePath}`);\n }\n\n const template = readFileSync(templatePath, 'utf-8');\n\n const doc = readWorkspacePlanSync(context.workspace);\n const item = doc?.plan.items.find(candidate => candidate.id === context.itemId);\n if (!item) throw new Error(`Item ${context.itemId} requires a readable xBRIEF entry in ${context.workspace}.`);\n const itemDescription = `**Title:** ${item.title}\\n\\n**Action:** ${item.narrative?.Action ?? 'No narrative provided.'}`;\n\n // Resolve the item diff from the code repo(s), never the polyrepo wrapper.\n const diffContext = await Effect.runPromise(\n getInspectDiffContext(context.projectKey, context.issueId, context.workspace),\n );\n\n const apiUrl = process.env.OVERDECK_DASHBOARD_URL || process.env.DASHBOARD_URL || `http://localhost:${process.env.API_PORT || process.env.PORT || '3011'}`;\n\n const prompt = template\n .replace(/\\{\\{apiUrl\\}\\}/g, apiUrl)\n .replace(/\\{\\{projectPath\\}\\}/g, context.projectPath)\n .replace(/\\{\\{issueId\\}\\}/g, context.issueId)\n .replace(/\\{\\{itemId\\}\\}/g, context.itemId)\n .replace(/\\{\\{workspacePath\\}\\}/g, context.workspace)\n .replace(/\\{\\{checkpoint\\}\\}/g, diffContext.checkpoint)\n .replace(/\\{\\{diffCommand\\}\\}/g, diffContext.diffCommand)\n .replace(/\\{\\{diffStats\\}\\}/g, diffContext.diffStats)\n .replace(/\\{\\{itemDescription\\}\\}/g, itemDescription)\n .replace(/\\{\\{resultStatus\\}\\}/g, '${RESULT_STATUS}')\n .replace(/\\{\\{resultNotes\\}\\}/g, '${RESULT_NOTES}');\n\n return `<!-- overdeck:orchestration-context-start -->\\n${prompt}\\n<!-- overdeck:orchestration-context-end -->`;\n}\n\nasync function routeInspectToStandingSupervisorIfEnabled(\n context: InspectContext,\n): Promise<{\n success: boolean;\n tmuxSession?: string;\n message: string;\n error?: string;\n} | undefined> {\n const { config } = loadYamlConfig();\n const tiered = config.tieredExecution;\n if (!tiered?.supervisor?.owns_inspection) return undefined;\n\n const doc = readWorkspacePlanSync(context.workspace);\n const enabled = resolveTieredExecutionEnabled(tiered, doc?.plan.metadata);\n if (!enabled) return undefined;\n\n const item = doc?.plan.items.find(candidate => candidate.id === context.itemId);\n if (!doc || !item) {\n throw new Error(\n `Standing supervisor inspection for ${context.issueId} item ${context.itemId} requires a readable xBRIEF item in ${context.workspace}.`,\n );\n }\n\n const agentId = supervisorAgentId(context.issueId);\n if (!await Effect.runPromise(sessionExists(agentId))) {\n await spawnTierSupervisor(context.issueId, tiered.supervisor, { workspace: context.workspace });\n }\n\n setReviewStatusSync(context.issueId.toUpperCase(), {\n inspectStatus: 'inspecting',\n inspectNotes: `Inspecting item ${context.itemId}`,\n inspectStartedAt: new Date().toISOString(),\n inspectBeadId: context.itemId,\n inspectOwnerSession: agentId,\n });\n\n const sha = await Effect.runPromise(getCurrentHead(context.issueId, context.workspace));\n const prdMarkdown = await loadPrdDraft(context.projectPath, context.issueId);\n await deliverCommitForReview({\n supervisorAgentId: agentId,\n workspacePath: context.workspace,\n issueId: context.issueId,\n item,\n sha,\n itemId: context.itemId,\n prdMarkdown,\n });\n\n return {\n success: true,\n tmuxSession: agentId,\n message: `Routed inspect for ${context.issueId} item ${context.itemId} to standing supervisor`,\n };\n}\n\nasync function spawnInspectAgentPromise(\n context: InspectContext,\n opts: { deep?: boolean } = {},\n): Promise<{\n success: boolean;\n skipped?: boolean;\n runId?: string;\n tmuxSession?: string;\n message: string;\n error?: string;\n}> {\n const subRole = opts.deep ? 'inspect-deep' : 'inspect';\n const issueLower = context.issueId.toLowerCase();\n const itemSlug = context.itemId.replace(/[^a-z0-9-]/gi, '-').toLowerCase().slice(0, 24);\n const tmuxSession = `inspect-${issueLower}-${itemSlug}`;\n\n try {\n if (await isIssueClosed(context.issueId.toUpperCase())) {\n const message = `${context.issueId.toUpperCase()}: skipping inspect dispatch — issue is closed`;\n console.log(`[cloister] ${message}`);\n return {\n success: true,\n skipped: true,\n tmuxSession,\n message,\n };\n }\n\n const supervisorRoute = await routeInspectToStandingSupervisorIfEnabled(context);\n if (supervisorRoute) return supervisorRoute;\n\n const harnessLaunch = await prepareHarnessLaunch('claude-code');\n\n if (await Effect.runPromise(sessionExists(tmuxSession))) {\n // Stale session left behind by a previous inspection run — clear it.\n await Effect.runPromise(killSession(tmuxSession)).catch(() => {});\n }\n\n const prompt = await Effect.runPromise(buildInspectPrompt(context));\n setReviewStatusSync(context.issueId.toUpperCase(), {\n inspectStatus: 'inspecting',\n inspectNotes: `Inspecting item ${context.itemId}`,\n inspectStartedAt: new Date().toISOString(),\n inspectBeadId: context.itemId,\n inspectOwnerSession: tmuxSession,\n });\n\n // Resolve model via the role primitive: work.<inspect|inspect-deep>.\n const { config } = loadYamlConfig();\n const model = resolveModel('work', subRole, config);\n // PAN-3077: never omit --effort — this launcher bypasses the role-file\n // injection path, so omission inherits the harness default (xhigh on\n // Opus 5), violating the effort-defaults-to-high policy.\n const effort = config.roles?.work?.effort ?? 'high';\n\n // Provider env (BASE_URL/AUTH_TOKEN) for non-Anthropic models routed via cliproxy.\n const providerEnv = await getProviderEnvForModel(model);\n const provider = getProviderForModelSync(model as ModelId);\n if (provider.authType === 'credential-file') {\n setupCredentialFileAuthSync(provider, context.workspace);\n } else {\n clearCredentialFileAuthSync(context.workspace);\n }\n\n // Per-agent dir for prompt + launcher artifacts.\n const agentDir = join(homedir(), '.overdeck', 'agents', tmuxSession);\n mkdirSync(agentDir, { recursive: true });\n\n const promptFile = join(agentDir, 'task-prompt.md');\n writeFileSync(promptFile, prompt);\n\n const launcherScript = join(agentDir, 'launcher.sh');\n const sessionId = randomUUID();\n writeFileSync(\n launcherScript,\n generateLauncherScriptSync({\n role: 'work',\n workingDir: context.workspace,\n setTerminalEnv: true,\n unsetProviderEnv: true,\n extraEnvExports: [harnessLaunch.pathExport],\n providerExports: Object.entries(providerEnv)\n .map(([k, v]) => `export ${k}='${v.replace(/'/g, \"'\\\"'\\\"'\")}'`)\n .join('\\n') + (Object.keys(providerEnv).length ? '\\n' : ''),\n overdeckEnv: {\n agentId: tmuxSession,\n issueId: context.issueId,\n sessionType: subRole,\n },\n promptFile,\n // Inspect prompts are workflow-injected templates, not ambient .claude/agents\n // definitions. Passing --agent here skips launcher permission flags and can\n // strand the inspector at a permission dialog before it can send its verdict.\n baseCommand: 'claude',\n sessionId,\n model,\n appendSystemPromptFiles: await claudeSystemPromptFiles(context.workspace, 'claude-code'),\n extraArgs: `--effort ${effort}`,\n permissionFlags: getClaudePermissionFlagsSync(),\n }),\n { mode: 0o755 },\n );\n\n const envForTmux: Record<string, string> = {\n OVERDECK_AGENT_ID: tmuxSession,\n OVERDECK_ISSUE_ID: context.issueId,\n OVERDECK_SESSION_TYPE: subRole,\n ...providerEnv,\n };\n\n await Effect.runPromise(createSession(\n tmuxSession,\n context.workspace,\n `bash '${launcherScript}'`,\n { env: envForTmux },\n ));\n\n saveAgentRuntimeState(tmuxSession, {\n state: 'active',\n lastActivity: new Date().toISOString(),\n currentIssue: context.issueId,\n });\n\n // PAN-1834 — write a minimal state.json so inspect agents are enumerated by\n // listRunningAgents and scanned by the enrichment poller for pending input.\n await Effect.runPromise(saveAgentState({\n id: tmuxSession,\n issueId: context.issueId,\n workspace: context.workspace,\n role: 'work',\n // The inspect launcher hardcodes `baseCommand: 'claude'` (above), so the\n // agent always runs under claude-code — record it. `harness` is optional on\n // AgentState but maps to a NOT NULL column; omitting it made the cache\n // backfill skip the agent (invisible) or, pre-PAN-1972, crash the boot\n // decode. PAN-1973.\n harness: 'claude-code',\n model,\n status: 'starting',\n startedAt: new Date().toISOString(),\n inspectSubRole: subRole,\n }));\n\n return {\n success: true,\n runId: sessionId,\n tmuxSession,\n message: `Spawned ${subRole} for ${context.issueId} item ${context.itemId}`,\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n tmuxSession,\n message: `Failed to spawn ${subRole}: ${message}`,\n error: message,\n };\n }\n}async function onInspectCompletePromise(\n projectKey: string,\n issueId: string,\n itemId: string,\n status: 'passed' | 'failed',\n workspacePath: string,\n notes?: string,\n deps: { deliver?: typeof deliverAgentMessage } = {},\n): Promise<void> {\n if (status === 'passed') {\n const commitSha = await Effect.runPromise(getCurrentHead(issueId, workspacePath));\n saveCheckpoint(projectKey, issueId, itemId, commitSha);\n console.log(`[inspect] Checkpoint saved for ${issueId} item ${itemId} at ${commitSha.substring(0, 8)}`);\n\n } else {\n console.log(`[inspect] Item ${itemId} blocked for ${issueId} — no checkpoint saved`);\n }\n\n // PAN-3078: the verdict must reach the work agent. An agent that parks\n // waiting for its inspection result deadlocks forever without this — the\n // status is persisted to review_status, but nothing reads it back to the\n // waiting session.\n const workAgentId = `agent-${issueId.toLowerCase()}`;\n const message = status === 'passed'\n ? `Inspection verdict for xBRIEF item ${itemId}: PASSED. The checkpoint is saved — continue to your next item.`\n : `Inspection verdict for xBRIEF item ${itemId}: BLOCKED. Do not build on this item's changes until the finding is addressed.${notes ? ` Finding: ${notes}` : ''}`;\n try {\n const deliver = deps.deliver ?? deliverAgentMessage;\n const result = await deliver(workAgentId, message, 'inspect-verdict');\n if (!result.ok) {\n console.error(`[inspect] FAILED to deliver ${status} verdict for ${issueId} item ${itemId} to ${workAgentId}: ${result.failure ?? 'unknown'}`);\n }\n } catch (err) {\n console.error(`[inspect] FAILED to deliver ${status} verdict for ${issueId} item ${itemId} to ${workAgentId}: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\n// ─── PAN-1249: additive Effect variants ───────────────────────────────────────\n\n/**\n * Effect-typed variant of {@link buildInspectPrompt}.\n * Fails with `ProcessSpawnError` when the prompt template is missing or the\n * underlying git/bd helpers throw (the legacy Promise version throws on the\n * missing-template path).\n */\nexport function buildInspectPrompt(\n context: InspectContext,\n): Effect.Effect<string, ProcessSpawnError> {\n return Effect.tryPromise({\n try: () => buildInspectPromptPromise(context),\n catch: (cause) =>\n new ProcessSpawnError({\n command: 'inspect-agent',\n args: ['buildInspectPrompt', context.itemId],\n message: cause instanceof Error ? cause.message : String(cause),\n cause,\n }),\n });\n}\n\n/**\n * Effect-typed variant of {@link spawnInspectAgent}. Never fails — the legacy\n * Promise returns `{ success: false, error }` instead of throwing.\n */\nexport function spawnInspectAgent(\n context: InspectContext,\n opts: { deep?: boolean } = {},\n): Effect.Effect<{\n success: boolean;\n skipped?: boolean;\n runId?: string;\n tmuxSession?: string;\n message: string;\n error?: string;\n}> {\n return Effect.promise(() => spawnInspectAgentPromise(context, opts));\n}\n\n/**\n * Effect-typed variant of {@link onInspectComplete}. Never fails.\n */\nexport function onInspectComplete(\n projectKey: string,\n issueId: string,\n itemId: string,\n status: 'passed' | 'failed',\n workspacePath: string,\n notes?: string,\n deps: { deliver?: typeof deliverAgentMessage } = {},\n): Effect.Effect<void> {\n return Effect.promise(() => onInspectCompletePromise(projectKey, issueId, itemId, status, workspacePath, notes, deps));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"inspect-agent-BDmLWbGx.js","names":["loadYamlConfig"],"sources":["../../src/lib/cloister/inspect-checkpoints.ts","../../src/lib/cloister/inspect-agent.ts"],"sourcesContent":["/**\n * PAN-382: Inspection checkpoint system.\n *\n * Tracks commit SHAs where inspections passed. The active inspection diff is\n * scoped to the parent of HEAD because the work role contract is one bead per\n * commit; checkpoints remain the durable record after a pass.\n */\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport { Effect } from 'effect';\nimport { resolveWorkspaceRepoRootsSync, type WorkspaceRepoRoot } from '../project-repos.js';\nimport { parseCompositeSnapshot, snapshotWorkspaceHeadsPromise } from '../git-utils.js';\n\nconst execAsync = promisify(exec);\n\nconst OVERDECK_HOME = join(homedir(), '.overdeck');\n\nexport interface InspectCheckpoint {\n itemId: string;\n commitSha: string;\n passedAt: string; // ISO 8601\n}\n\nexport interface InspectCheckpointFile {\n issueId: string;\n checkpoints: InspectCheckpoint[];\n}\n\n/**\n * Get the directory for a project's inspect checkpoints.\n */\nfunction getCheckpointDir(projectKey: string): string {\n return join(OVERDECK_HOME, 'specialists', projectKey, 'inspect-agent', 'checkpoints');\n}\n\n/**\n * Get the checkpoint file path for an issue.\n */\nfunction getCheckpointPath(projectKey: string, issueId: string): string {\n return join(getCheckpointDir(projectKey), `${issueId.toUpperCase()}.json`);\n}\n\n/**\n * Load checkpoints for an issue. Returns null if no checkpoints exist.\n */\nexport function loadCheckpoints(projectKey: string, issueId: string): InspectCheckpointFile | null {\n const filePath = getCheckpointPath(projectKey, issueId);\n if (!existsSync(filePath)) return null;\n\n try {\n return JSON.parse(readFileSync(filePath, 'utf-8'));\n } catch {\n return null;\n }\n}\n\n/**\n * Get the last checkpoint for an issue, or null if none exist.\n */\nexport function getLastCheckpoint(projectKey: string, issueId: string): InspectCheckpoint | null {\n const data = loadCheckpoints(projectKey, issueId);\n if (!data || data.checkpoints.length === 0) return null;\n return data.checkpoints[data.checkpoints.length - 1];\n}\n\n/**\n * Save a new checkpoint after a successful inspection.\n */\nexport function saveCheckpoint(\n projectKey: string,\n issueId: string,\n itemId: string,\n commitSha: string\n): InspectCheckpoint {\n const dir = getCheckpointDir(projectKey);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n const data = loadCheckpoints(projectKey, issueId) || {\n issueId: issueId.toUpperCase(),\n checkpoints: [],\n };\n\n const checkpoint: InspectCheckpoint = {\n itemId,\n commitSha,\n passedAt: new Date().toISOString(),\n };\n\n data.checkpoints.push(checkpoint);\n writeFileSync(getCheckpointPath(projectKey, issueId), JSON.stringify(data, null, 2));\n\n return checkpoint;\n}\n\nexport interface InspectDiffRepo {\n repoKey: string;\n dir: string;\n headSha: string;\n diffBase: string;\n}\n\nexport interface InspectDiffContext {\n currentHead: string;\n checkpoint: string;\n diffStats: string;\n diffCommand: string;\n repos: InspectDiffRepo[];\n}\n\nfunction shellQuote(value: string): string {\n return `'${value.replace(/'/g, `'\"'\"'`)}'`;\n}\n\nasync function readHead(root: WorkspaceRepoRoot): Promise<string | null> {\n try {\n const { stdout } = await execAsync('git rev-parse HEAD', {\n cwd: root.dir,\n encoding: 'utf-8',\n timeout: 10_000,\n });\n return stdout.trim() || null;\n } catch {\n return null;\n }\n}\n\nasync function resolveTargetBase(root: WorkspaceRepoRoot): Promise<string> {\n for (const target of [`origin/${root.targetBranch}`, root.targetBranch]) {\n try {\n const { stdout } = await execAsync(`git merge-base ${shellQuote(target)} HEAD`, {\n cwd: root.dir,\n encoding: 'utf-8',\n timeout: 10_000,\n });\n const base = stdout.trim();\n if (base) return base;\n } catch { /* try the next target */ }\n }\n try {\n const { stdout } = await execAsync('git rev-parse HEAD^', {\n cwd: root.dir,\n encoding: 'utf-8',\n timeout: 10_000,\n });\n return stdout.trim();\n } catch {\n return root.targetBranch;\n }\n}\n\n/**\n * Resolve the per-item inspection diff across the actual workspace repositories.\n * Polyrepo checkpoints store composite `repo@sha` snapshots so unchanged repos\n * are omitted instead of reviewing their previous, unrelated commit.\n */\nasync function getInspectDiffContextPromise(\n projectKey: string,\n issueId: string,\n workspacePath: string,\n): Promise<InspectDiffContext> {\n const roots = resolveWorkspaceRepoRootsSync(issueId, workspacePath);\n const isPolyrepo = roots.some(root => root.isPolyrepo);\n const previousHeads = isPolyrepo\n ? parseCompositeSnapshot(getLastCheckpoint(projectKey, issueId)?.commitSha)\n : new Map<string, string>();\n const repos: InspectDiffRepo[] = [];\n\n for (const root of roots) {\n const headSha = await readHead(root);\n if (!headSha) continue;\n\n let diffBase: string;\n if (isPolyrepo) {\n const previousHead = previousHeads.get(root.repoKey);\n if (previousHead === headSha) continue;\n diffBase = previousHead ?? await resolveTargetBase(root);\n if (diffBase === headSha) continue;\n } else {\n try {\n const { stdout } = await execAsync('git rev-parse HEAD^', {\n cwd: root.dir,\n encoding: 'utf-8',\n timeout: 10_000,\n });\n diffBase = stdout.trim();\n } catch {\n diffBase = root.targetBranch;\n }\n }\n\n repos.push({ repoKey: root.repoKey, dir: root.dir, headSha, diffBase });\n }\n\n const statSections: string[] = [];\n const commands: string[] = [];\n for (const repo of repos) {\n let stat = 'Unable to compute diff stats';\n try {\n const { stdout } = await execAsync(`git diff --stat ${shellQuote(repo.diffBase)}...HEAD`, {\n cwd: repo.dir,\n encoding: 'utf-8',\n timeout: 15_000,\n });\n stat = stdout.trim() || 'No changes detected';\n } catch { /* retain the human-readable fallback */ }\n\n statSections.push(isPolyrepo ? `── ${repo.repoKey} ──\\n${stat}` : stat);\n commands.push(\n `${isPolyrepo ? `printf '\\\\n── ${repo.repoKey} ──\\\\n'\\n` : ''}` +\n `git -C ${shellQuote(repo.dir)} diff ${shellQuote(repo.diffBase)}...HEAD`,\n );\n }\n\n const currentHead = await snapshotWorkspaceHeadsPromise(issueId, workspacePath) ?? 'unknown';\n return {\n currentHead,\n checkpoint: repos.length > 0\n ? repos.map(repo => isPolyrepo ? `${repo.repoKey}@${repo.diffBase.slice(0, 8)}` : repo.diffBase).join(' ')\n : currentHead,\n diffStats: statSections.join('\\n') || 'No changes detected across workspace repositories',\n diffCommand: commands.join('\\n') || `printf '%s\\\\n' 'No changes detected across workspace repositories'`,\n repos,\n };\n}\n\nexport function getInspectDiffContext(\n projectKey: string,\n issueId: string,\n workspacePath: string,\n): Effect.Effect<InspectDiffContext> {\n return Effect.promise(() => getInspectDiffContextPromise(projectKey, issueId, workspacePath));\n}\n\n/** Resolve the code HEAD(s), never the polyrepo wrapper commit. */\nexport function getCurrentHead(issueId: string, workspacePath: string): Effect.Effect<string> {\n return Effect.promise(async () =>\n await snapshotWorkspaceHeadsPromise(issueId, workspacePath) ?? 'unknown'\n );\n}\n","/**\n * PAN-382: Inspect Agent — Per-step verification specialist.\n *\n * Spawns after each item completion to verify the implementation matches\n * its specification and architectural constraints before the agent\n * proceeds to the next item.\n */\n\nimport { readFileSync, existsSync, writeFileSync, mkdirSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { homedir } from 'os';\nimport { randomUUID } from 'crypto';\nimport { fileURLToPath } from 'url';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport { Effect } from 'effect';\nimport { ProcessSpawnError } from '../errors.js';\nimport {\n getInspectDiffContext,\n getCurrentHead,\n saveCheckpoint,\n} from './inspect-checkpoints.js';\nimport { setReviewStatusSync } from '../review-status.js';\nimport { prepareHarnessLaunch } from '../harness-binary.js';\nimport { generateLauncherScriptSync } from '../launcher-generator.js';\nimport { claudeSystemPromptFiles } from '../agents/runtime-command.js';\nimport {\n createSession,\n killSession,\n sessionExists,\n} from '../tmux.js';\nimport { loadConfigSync as loadYamlConfig, resolveModel } from '../config-yaml.js';\nimport { getClaudePermissionFlagsSync } from '../claude-permissions.js';\nimport {\n getProviderForModelSync,\n setupCredentialFileAuthSync,\n clearCredentialFileAuthSync,\n} from '../providers.js';\nimport type { ModelId } from '../settings.js';\nimport { getProviderEnvForModel, saveAgentRuntimeState, saveAgentState } from '../agents.js';\nimport { isIssueClosed } from './issue-closed.js';\nimport { readWorkspacePlanSync } from '../xbrief/io.js';\nimport { resolveTieredExecutionEnabled } from '../agents/tier-table.js';\nimport {\n deliverCommitForReview,\n loadPrdDraft,\n spawnTierSupervisor,\n supervisorAgentId,\n} from '../agents/tier-supervisor.js';\nimport { deliverAgentMessage } from '../agents/delivery.js';\n\nconst execAsync = promisify(exec);\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Context for an inspection request\n */\nexport interface InspectContext {\n projectKey: string;\n projectPath: string;\n issueId: string;\n /** Canonical xBRIEF item id being inspected. */\n itemId: string;\n workspace: string;\n branch?: string;\n}\n\n/**\n * Result of inspection\n */\nexport interface InspectResult {\n success: boolean;\n inspectResult: 'PASS' | 'BLOCKED';\n itemId: string;\n notes?: string;\n}\n\nasync function buildInspectPromptPromise(context: InspectContext): Promise<string> {\n const templatePath = join(__dirname, 'prompts', 'inspect-agent.md');\n\n if (!existsSync(templatePath)) {\n throw new Error(`Inspect agent prompt template not found at ${templatePath}`);\n }\n\n const template = readFileSync(templatePath, 'utf-8');\n\n const doc = readWorkspacePlanSync(context.workspace);\n const item = doc?.plan.items.find(candidate => candidate.id === context.itemId);\n if (!item) throw new Error(`Item ${context.itemId} requires a readable xBRIEF entry in ${context.workspace}.`);\n const itemDescription = `**Title:** ${item.title}\\n\\n**Action:** ${item.narrative?.Action ?? 'No narrative provided.'}`;\n\n // Resolve the item diff from the code repo(s), never the polyrepo wrapper.\n const diffContext = await Effect.runPromise(\n getInspectDiffContext(context.projectKey, context.issueId, context.workspace),\n );\n\n const apiUrl = process.env.OVERDECK_DASHBOARD_URL || process.env.DASHBOARD_URL || `http://localhost:${process.env.API_PORT || process.env.PORT || '3011'}`;\n\n const prompt = template\n .replace(/\\{\\{apiUrl\\}\\}/g, apiUrl)\n .replace(/\\{\\{projectPath\\}\\}/g, context.projectPath)\n .replace(/\\{\\{issueId\\}\\}/g, context.issueId)\n .replace(/\\{\\{itemId\\}\\}/g, context.itemId)\n .replace(/\\{\\{workspacePath\\}\\}/g, context.workspace)\n .replace(/\\{\\{checkpoint\\}\\}/g, diffContext.checkpoint)\n .replace(/\\{\\{diffCommand\\}\\}/g, diffContext.diffCommand)\n .replace(/\\{\\{diffStats\\}\\}/g, diffContext.diffStats)\n .replace(/\\{\\{itemDescription\\}\\}/g, itemDescription)\n .replace(/\\{\\{resultStatus\\}\\}/g, '${RESULT_STATUS}')\n .replace(/\\{\\{resultNotes\\}\\}/g, '${RESULT_NOTES}');\n\n return `<!-- overdeck:orchestration-context-start -->\\n${prompt}\\n<!-- overdeck:orchestration-context-end -->`;\n}\n\nasync function routeInspectToStandingSupervisorIfEnabled(\n context: InspectContext,\n): Promise<{\n success: boolean;\n tmuxSession?: string;\n message: string;\n error?: string;\n} | undefined> {\n const { config } = loadYamlConfig();\n const tiered = config.tieredExecution;\n if (!tiered?.supervisor?.owns_inspection) return undefined;\n\n const doc = readWorkspacePlanSync(context.workspace);\n const enabled = resolveTieredExecutionEnabled(tiered, doc?.plan.metadata);\n if (!enabled) return undefined;\n\n const item = doc?.plan.items.find(candidate => candidate.id === context.itemId);\n if (!doc || !item) {\n throw new Error(\n `Standing supervisor inspection for ${context.issueId} item ${context.itemId} requires a readable xBRIEF item in ${context.workspace}.`,\n );\n }\n\n const agentId = supervisorAgentId(context.issueId);\n if (!await Effect.runPromise(sessionExists(agentId))) {\n await spawnTierSupervisor(context.issueId, tiered.supervisor, { workspace: context.workspace });\n }\n\n setReviewStatusSync(context.issueId.toUpperCase(), {\n inspectStatus: 'inspecting',\n inspectNotes: `Inspecting item ${context.itemId}`,\n inspectStartedAt: new Date().toISOString(),\n inspectBeadId: context.itemId,\n inspectOwnerSession: agentId,\n });\n\n const sha = await Effect.runPromise(getCurrentHead(context.issueId, context.workspace));\n const prdMarkdown = await loadPrdDraft(context.projectPath, context.issueId);\n await deliverCommitForReview({\n supervisorAgentId: agentId,\n workspacePath: context.workspace,\n issueId: context.issueId,\n item,\n sha,\n itemId: context.itemId,\n prdMarkdown,\n });\n\n return {\n success: true,\n tmuxSession: agentId,\n message: `Routed inspect for ${context.issueId} item ${context.itemId} to standing supervisor`,\n };\n}\n\nasync function spawnInspectAgentPromise(\n context: InspectContext,\n opts: { deep?: boolean } = {},\n): Promise<{\n success: boolean;\n skipped?: boolean;\n runId?: string;\n tmuxSession?: string;\n message: string;\n error?: string;\n}> {\n const subRole = opts.deep ? 'inspect-deep' : 'inspect';\n const issueLower = context.issueId.toLowerCase();\n const itemSlug = context.itemId.replace(/[^a-z0-9-]/gi, '-').toLowerCase().slice(0, 24);\n const tmuxSession = `inspect-${issueLower}-${itemSlug}`;\n\n try {\n if (await isIssueClosed(context.issueId.toUpperCase())) {\n const message = `${context.issueId.toUpperCase()}: skipping inspect dispatch — issue is closed`;\n console.log(`[cloister] ${message}`);\n return {\n success: true,\n skipped: true,\n tmuxSession,\n message,\n };\n }\n\n const supervisorRoute = await routeInspectToStandingSupervisorIfEnabled(context);\n if (supervisorRoute) return supervisorRoute;\n\n const harnessLaunch = await prepareHarnessLaunch('claude-code');\n\n if (await Effect.runPromise(sessionExists(tmuxSession))) {\n // Stale session left behind by a previous inspection run — clear it.\n await Effect.runPromise(killSession(tmuxSession)).catch(() => {});\n }\n\n const prompt = await Effect.runPromise(buildInspectPrompt(context));\n setReviewStatusSync(context.issueId.toUpperCase(), {\n inspectStatus: 'inspecting',\n inspectNotes: `Inspecting item ${context.itemId}`,\n inspectStartedAt: new Date().toISOString(),\n inspectBeadId: context.itemId,\n inspectOwnerSession: tmuxSession,\n });\n\n // Resolve model via the role primitive: work.<inspect|inspect-deep>.\n const { config } = loadYamlConfig();\n const model = resolveModel('work', subRole, config);\n // PAN-3077: never omit --effort — this launcher bypasses the role-file\n // injection path, so omission inherits the harness default (xhigh on\n // Opus 5), violating the effort-defaults-to-high policy.\n const effort = config.roles?.work?.effort ?? 'high';\n\n // Provider env (BASE_URL/AUTH_TOKEN) for non-Anthropic models routed via cliproxy.\n const providerEnv = await getProviderEnvForModel(model);\n const provider = getProviderForModelSync(model as ModelId);\n if (provider.authType === 'credential-file') {\n setupCredentialFileAuthSync(provider, context.workspace);\n } else {\n clearCredentialFileAuthSync(context.workspace);\n }\n\n // Per-agent dir for prompt + launcher artifacts.\n const agentDir = join(homedir(), '.overdeck', 'agents', tmuxSession);\n mkdirSync(agentDir, { recursive: true });\n\n const promptFile = join(agentDir, 'task-prompt.md');\n writeFileSync(promptFile, prompt);\n\n const launcherScript = join(agentDir, 'launcher.sh');\n const sessionId = randomUUID();\n writeFileSync(\n launcherScript,\n generateLauncherScriptSync({\n role: 'work',\n workingDir: context.workspace,\n setTerminalEnv: true,\n unsetProviderEnv: true,\n extraEnvExports: [harnessLaunch.pathExport],\n providerExports: Object.entries(providerEnv)\n .map(([k, v]) => `export ${k}='${v.replace(/'/g, \"'\\\"'\\\"'\")}'`)\n .join('\\n') + (Object.keys(providerEnv).length ? '\\n' : ''),\n overdeckEnv: {\n agentId: tmuxSession,\n issueId: context.issueId,\n sessionType: subRole,\n },\n promptFile,\n // Inspect prompts are workflow-injected templates, not ambient .claude/agents\n // definitions. Passing --agent here skips launcher permission flags and can\n // strand the inspector at a permission dialog before it can send its verdict.\n baseCommand: 'claude',\n sessionId,\n model,\n appendSystemPromptFiles: await claudeSystemPromptFiles(context.workspace, 'claude-code'),\n extraArgs: `--effort ${effort}`,\n permissionFlags: getClaudePermissionFlagsSync(),\n }),\n { mode: 0o755 },\n );\n\n const envForTmux: Record<string, string> = {\n OVERDECK_AGENT_ID: tmuxSession,\n OVERDECK_ISSUE_ID: context.issueId,\n OVERDECK_SESSION_TYPE: subRole,\n ...providerEnv,\n };\n\n await Effect.runPromise(createSession(\n tmuxSession,\n context.workspace,\n `bash '${launcherScript}'`,\n { env: envForTmux },\n ));\n\n saveAgentRuntimeState(tmuxSession, {\n state: 'active',\n lastActivity: new Date().toISOString(),\n currentIssue: context.issueId,\n });\n\n // PAN-1834 — write a minimal state.json so inspect agents are enumerated by\n // listRunningAgents and scanned by the enrichment poller for pending input.\n await Effect.runPromise(saveAgentState({\n id: tmuxSession,\n issueId: context.issueId,\n workspace: context.workspace,\n role: 'work',\n // The inspect launcher hardcodes `baseCommand: 'claude'` (above), so the\n // agent always runs under claude-code — record it. `harness` is optional on\n // AgentState but maps to a NOT NULL column; omitting it made the cache\n // backfill skip the agent (invisible) or, pre-PAN-1972, crash the boot\n // decode. PAN-1973.\n harness: 'claude-code',\n model,\n status: 'starting',\n startedAt: new Date().toISOString(),\n inspectSubRole: subRole,\n }));\n\n return {\n success: true,\n runId: sessionId,\n tmuxSession,\n message: `Spawned ${subRole} for ${context.issueId} item ${context.itemId}`,\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n tmuxSession,\n message: `Failed to spawn ${subRole}: ${message}`,\n error: message,\n };\n }\n}async function onInspectCompletePromise(\n projectKey: string,\n issueId: string,\n itemId: string,\n status: 'passed' | 'failed',\n workspacePath: string,\n notes?: string,\n deps: { deliver?: typeof deliverAgentMessage } = {},\n): Promise<void> {\n if (status === 'passed') {\n const commitSha = await Effect.runPromise(getCurrentHead(issueId, workspacePath));\n saveCheckpoint(projectKey, issueId, itemId, commitSha);\n console.log(`[inspect] Checkpoint saved for ${issueId} item ${itemId} at ${commitSha.substring(0, 8)}`);\n\n } else {\n console.log(`[inspect] Item ${itemId} blocked for ${issueId} — no checkpoint saved`);\n }\n\n // PAN-3078: the verdict must reach the work agent. An agent that parks\n // waiting for its inspection result deadlocks forever without this — the\n // status is persisted to review_status, but nothing reads it back to the\n // waiting session.\n const workAgentId = `agent-${issueId.toLowerCase()}`;\n const message = status === 'passed'\n ? `Inspection verdict for xBRIEF item ${itemId}: PASSED. The checkpoint is saved — continue to your next item.`\n : `Inspection verdict for xBRIEF item ${itemId}: BLOCKED. Do not build on this item's changes until the finding is addressed.${notes ? ` Finding: ${notes}` : ''}`;\n try {\n const deliver = deps.deliver ?? deliverAgentMessage;\n const result = await deliver(workAgentId, message, 'inspect-verdict');\n if (!result.ok) {\n console.error(`[inspect] FAILED to deliver ${status} verdict for ${issueId} item ${itemId} to ${workAgentId}: ${result.failure ?? 'unknown'}`);\n }\n } catch (err) {\n console.error(`[inspect] FAILED to deliver ${status} verdict for ${issueId} item ${itemId} to ${workAgentId}: ${err instanceof Error ? err.message : String(err)}`);\n }\n}\n\n// ─── PAN-1249: additive Effect variants ───────────────────────────────────────\n\n/**\n * Effect-typed variant of {@link buildInspectPrompt}.\n * Fails with `ProcessSpawnError` when the prompt template is missing or the\n * underlying git/bd helpers throw (the legacy Promise version throws on the\n * missing-template path).\n */\nexport function buildInspectPrompt(\n context: InspectContext,\n): Effect.Effect<string, ProcessSpawnError> {\n return Effect.tryPromise({\n try: () => buildInspectPromptPromise(context),\n catch: (cause) =>\n new ProcessSpawnError({\n command: 'inspect-agent',\n args: ['buildInspectPrompt', context.itemId],\n message: cause instanceof Error ? cause.message : String(cause),\n cause,\n }),\n });\n}\n\n/**\n * Effect-typed variant of {@link spawnInspectAgent}. Never fails — the legacy\n * Promise returns `{ success: false, error }` instead of throwing.\n */\nexport function spawnInspectAgent(\n context: InspectContext,\n opts: { deep?: boolean } = {},\n): Effect.Effect<{\n success: boolean;\n skipped?: boolean;\n runId?: string;\n tmuxSession?: string;\n message: string;\n error?: string;\n}> {\n return Effect.promise(() => spawnInspectAgentPromise(context, opts));\n}\n\n/**\n * Effect-typed variant of {@link onInspectComplete}. Never fails.\n */\nexport function onInspectComplete(\n projectKey: string,\n issueId: string,\n itemId: string,\n status: 'passed' | 'failed',\n workspacePath: string,\n notes?: string,\n deps: { deliver?: typeof deliverAgentMessage } = {},\n): Effect.Effect<void> {\n return Effect.promise(() => onInspectCompletePromise(projectKey, issueId, itemId, status, workspacePath, notes, deps));\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { n as onInspectComplete } from "./inspect-agent-BDmLWbGx.js";
2
+ export { onInspectComplete };
@@ -14,7 +14,7 @@ import { r as LinearClientOptionalLive, t as LinearClient } from "./linear-clien
14
14
  import { r as GitHubClientOptionalLive, t as GitHubClient } from "./github-client-DJVl4iDm.js";
15
15
  import { r as RallyClientOptionalLive, t as RallyClient } from "./rally-client-CAQtSqJJ.js";
16
16
  import { n as resolveGitHubIssueSync, r as resolveTrackerTypeSync, t as init_tracker_utils } from "./tracker-utils-McMENyKj.js";
17
- import { n as init_issue_service_singleton, t as getSharedIssueService } from "./issue-service-singleton-BrZQJLRI.js";
17
+ import { n as init_issue_service_singleton, t as getSharedIssueService } from "./issue-service-singleton-KcRrOiFD.js";
18
18
  import { dirname } from "node:path";
19
19
  import { Context, Effect, Layer, Option, Queue, Stream } from "effect";
20
20
  import { basename as basename$1, dirname as dirname$1, join as join$1, resolve as resolve$1 } from "path";
@@ -445,7 +445,7 @@ const ReadModelServiceLive = Layer.effect(ReadModelService, Effect.gen(function*
445
445
  };
446
446
  const getSnapshot = Effect.gen(function* () {
447
447
  try {
448
- const { getSharedIssueService } = yield* Effect.promise(() => import("./issue-service-singleton-Dsad9NTt.js"));
448
+ const { getSharedIssueService } = yield* Effect.promise(() => import("./issue-service-singleton-BVwPzjwF.js"));
449
449
  const currentIssues = cleanIssues(getSharedIssueService().getIssues());
450
450
  if (currentIssues.length > 0 || state.issuesRaw.length === 0) state = {
451
451
  ...state,
@@ -478,7 +478,7 @@ const ReadModelServiceLive = Layer.effect(ReadModelService, Effect.gen(function*
478
478
  const getAgentIdBySessionId = (sessionId) => Effect.sync(() => state.agentIdBySessionId[sessionId] ?? null);
479
479
  const agentsResolver = yield* AgentsResolver;
480
480
  yield* Effect.gen(function* () {
481
- const { reconstructCacheAuto } = yield* Effect.promise(() => import("./reconstruct-cache-Bb2Jg2DZ.js"));
481
+ const { reconstructCacheAuto } = yield* Effect.promise(() => import("./reconstruct-cache-XpWC9L0F.js"));
482
482
  const result = yield* Effect.promise(() => reconstructCacheAuto());
483
483
  const overdeckAgents = yield* agentsResolver.list({});
484
484
  let dbOnlyReviewStatusByIssueId = {};
@@ -571,7 +571,7 @@ const ReadModelServiceLive = Layer.effect(ReadModelService, Effect.gen(function*
571
571
  }
572
572
  })();
573
573
  try {
574
- const { getSharedIssueService } = yield* Effect.promise(() => import("./issue-service-singleton-Dsad9NTt.js"));
574
+ const { getSharedIssueService } = yield* Effect.promise(() => import("./issue-service-singleton-BVwPzjwF.js"));
575
575
  const issueService = getSharedIssueService();
576
576
  const mergeT0 = performance.now();
577
577
  const currentIssues = cleanIssues(issueService.getIssues());
@@ -613,7 +613,7 @@ const ReadModelServiceLive = Layer.effect(ReadModelService, Effect.gen(function*
613
613
  payload: delta
614
614
  });
615
615
  } catch {}
616
- import("./backlog-auto-trigger-BuSBqG2V.js").then(({ triggerDebouncedIncrementalPass }) => {
616
+ import("./backlog-auto-trigger-B5Z2zBtC.js").then(({ triggerDebouncedIncrementalPass }) => {
617
617
  triggerDebouncedIncrementalPass(process.cwd());
618
618
  }).catch(() => {});
619
619
  });
@@ -1719,4 +1719,4 @@ const IssueLifecycleWithClientLive = IssueLifecycleLive.pipe(Layer.provide(Linea
1719
1719
  //#endregion
1720
1720
  export { EventStoreServiceLive as a, ReadModelService as c, getClosedIssueIdsForReadSource as d, toAgentResolution as f, findPositionInQueueSync as g, computeQueuePositionFromStatusSync as h, EventStoreService as i, ReadModelServiceLive as l, toRole as m, IssueLifecycleLive as n, startProjectCiRefillAfterProjectionReady as o, toAgentStatus as p, IssueLifecycleWithClientLive as r, resolveDefaultBranchHead as s, IssueLifecycle as t, activityEntriesFromStoredEvents as u };
1721
1721
 
1722
- //# sourceMappingURL=issue-lifecycle-BPbczKyy.js.map
1722
+ //# sourceMappingURL=issue-lifecycle-1B_v8Rf5.js.map