@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":"issue-lifecycle-BPbczKyy.js","names":["applyEvent","applyEventReducer","resolve","basename","join","dirname","readFile","stat"],"sources":["../../src/lib/queue-position.ts","../../src/dashboard/server/read-model.ts","../../src/lib/briefing-assembler.ts","../../src/dashboard/server/services/session-context-writer.ts","../../src/lib/ci/project-ci-github.ts","../../src/lib/overdeck/project-ci-fill.ts","../../src/dashboard/server/services/project-ci-refill-startup.ts","../../src/dashboard/server/services/domain-services.ts","../../src/dashboard/server/services/issue-lifecycle.ts"],"sourcesContent":["/**\n * Queue position utilities for the specialist pipeline (PAN-366).\n *\n * These pure helpers are extracted from the review-status API handler so they\n * can be unit-tested independently of the Express server.\n */\n\nimport { Effect } from 'effect';\nimport type { ReviewStatus } from './review-status.js';\nimport type { HookItem } from './hooks.js';\n\n/** Sentinel value meaning the specialist is actively processing this issue now. */\nexport const SPECIALIST_ACTIVE_POSITION = 0;\n\nexport interface QueuePositionResult {\n /** null = not queued; 0 = actively processing; 1+ = position in queue */\n queuePosition: number | null;\n /** Which specialist is handling (or will handle) this issue */\n activeSpecialist: 'review' | 'test' | 'merge' | null;\n}\n\n/**\n * Derive queue position from the persisted review status fields alone.\n * Returns {0, specialist} when the status indicates active processing,\n * or {null, null} when no active phase is detected (caller must check queues).\n */\nexport function computeQueuePositionFromStatusSync(\n status: Pick<ReviewStatus, 'reviewStatus' | 'testStatus' | 'mergeStatus'> | null\n): QueuePositionResult {\n if (status?.reviewStatus === 'reviewing') {\n return { queuePosition: SPECIALIST_ACTIVE_POSITION, activeSpecialist: 'review' };\n }\n if (status?.testStatus === 'testing') {\n return { queuePosition: SPECIALIST_ACTIVE_POSITION, activeSpecialist: 'test' };\n }\n if (status?.mergeStatus === 'merging') {\n return { queuePosition: SPECIALIST_ACTIVE_POSITION, activeSpecialist: 'merge' };\n }\n return { queuePosition: null, activeSpecialist: null };\n}\n\n/**\n * Find this issueId's 1-based position in a specialist's pending queue.\n * Returns -1 if not found (caller interprets as \"not queued\").\n */\nexport function findPositionInQueueSync(issueId: string, items: HookItem[]): number {\n const upper = issueId.toUpperCase();\n const idx = items.findIndex(\n (item) => item.payload?.issueId?.toUpperCase() === upper\n );\n return idx >= 0 ? idx + 1 : -1;\n}\n\n// ─── Effect variants (PAN-1249) ───────────────────────────────────────────────\n\n/** Effect variant of {@link computeQueuePositionFromStatusSync}. Pure; cannot fail. */\nexport const computeQueuePositionFromStatus = (\n status: Pick<ReviewStatus, 'reviewStatus' | 'testStatus' | 'mergeStatus'> | null,\n): Effect.Effect<QueuePositionResult, never> =>\n Effect.sync(() => computeQueuePositionFromStatusSync(status));\n\n/** Effect variant of {@link findPositionInQueueSync}. Pure; cannot fail. */\nexport const findPositionInQueue = (\n issueId: string,\n items: HookItem[],\n): Effect.Effect<number, never> =>\n Effect.sync(() => findPositionInQueueSync(issueId, items));\n","/**\n * Server-side Read Model — clean data architecture (PAN-433)\n *\n * Holds an in-memory projection of the dashboard state, bootstrapped once from\n * existing lib modules (JSON-cleaned), then maintained incrementally by domain\n * events via the shared applyEvent reducer.\n *\n * getSnapshot() returns the read model directly — no lib calls, no dirty data,\n * no Schema crashes. This is the T3Code pattern.\n */\n\nimport { Effect, Layer, Context } from 'effect';\nimport type { DashboardSnapshot, DomainEvent, TurnDiffSummary } from '@overdeck/contracts';\nimport {\n type ReadModelState,\n INITIAL_READ_MODEL_STATE,\n applyEvent as applyEventReducer,\n createIssueDelta,\n getMaxTurnDiffSummariesPerAgent,\n isTerminalTurnDiffSummaryStatus,\n trimTurnDiffSummaries,\n} from '@overdeck/contracts';\nimport type { AgentSnapshot, AgentStatus, Role, AgentResolution, ReviewStatusSnapshot, ReviewStatusValue, TestStatusValue, UatStatusValue, MergeStatusValue, VerificationStatusValue } from '@overdeck/contracts';\nimport type { ReviewStatus } from '../../lib/review-status.js';\nimport { listOverdeckAgentStatesSync } from '../../lib/overdeck/agent-state-sync.js';\nimport { computeQueuePositionFromStatusSync } from '../../lib/queue-position.js'\nimport { AgentsResolver, type Agent as OverdeckAgent } from '../../lib/overdeck/agents.js';\nimport { emitBootReconciledStopEvents } from './services/boot-reconciled-stop-events.js';\n\n// ─── Exported async helpers (used by bootstrap Effect + tests) ───────────────\n\nconst MAX_SNAPSHOT_ACTIVITY_ENTRIES = 50;\n\ntype DashboardSnapshotWithActivity = DashboardSnapshot & {\n recentActivity?: unknown[];\n};\n\nexport function activityEntriesFromStoredEvents(\n events: ReadonlyArray<{ timestamp: string; payload: unknown }>,\n limit = MAX_SNAPSHOT_ACTIVITY_ENTRIES,\n): unknown[] {\n const entries: Record<string, unknown>[] = [];\n for (const event of events) {\n const entry = event.payload && typeof event.payload === 'object'\n ? event.payload as Record<string, unknown>\n : {};\n const previousIndex = entries.findIndex(candidate => candidate.id === entry.id);\n const previous = previousIndex >= 0 ? entries[previousIndex] : undefined;\n if (previousIndex >= 0) entries.splice(previousIndex, 1);\n entries.unshift({ ...previous, id: entry.id, timestamp: event.timestamp, ...entry });\n }\n return entries.slice(0, limit);\n}\n\n\n// PAN-1510: bootstrap previously only seeded `issuesRaw` from the projection\n// cache or replaced it wholesale from `issueService.getIssues()`. Both paths\n// missed issues filed during the previous dashboard's poll-write window — the\n// projection cache flush is debounced at 2s, so a fresh `cache.set('github',\n// 'issues', ...)` in IssueDataService can survive a restart while the\n// projection cache entry remains stale. The helpers below mirror PAN-1506's\n// `discoverNewAgentIds`/merge pattern for issues.\n\nexport function getIssueIdentifierKey(issue: unknown): string | null {\n if (!issue || typeof issue !== 'object') return null;\n const item = issue as { identifier?: unknown; id?: unknown };\n if (typeof item.identifier === 'string' && item.identifier.length > 0) {\n return item.identifier.toLowerCase();\n }\n if (typeof item.id === 'string' && item.id.length > 0) {\n return item.id.toLowerCase();\n }\n return null;\n}\n\nexport function discoverNewIssues(\n cachedIssues: unknown[],\n currentIssues: unknown[],\n): unknown[] {\n const cachedIds = new Set<string>();\n for (const issue of cachedIssues) {\n const id = getIssueIdentifierKey(issue);\n if (id !== null) cachedIds.add(id);\n }\n const newIssues: unknown[] = [];\n for (const issue of currentIssues) {\n const id = getIssueIdentifierKey(issue);\n if (id !== null && !cachedIds.has(id)) newIssues.push(issue);\n }\n return newIssues;\n}\n\nexport function mergeIssuesByIdentifier(\n cachedIssues: unknown[],\n currentIssues: unknown[],\n): unknown[] {\n const merged = new Map<string, unknown>();\n const unidentified: unknown[] = [];\n for (const issue of cachedIssues) {\n const id = getIssueIdentifierKey(issue);\n if (id !== null) merged.set(id, issue);\n else unidentified.push(issue);\n }\n for (const issue of currentIssues) {\n const id = getIssueIdentifierKey(issue);\n if (id !== null) merged.set(id, issue);\n }\n return [...unidentified, ...merged.values()];\n}\n\nexport function shouldSkipCheckpointReconciliation(agent: Pick<AgentSnapshot, 'status' | 'workspace'>): boolean {\n return !agent.workspace || isTerminalTurnDiffSummaryStatus(agent.status)\n}\n\ntype IssueReadSourceState = {\n identifier?: unknown;\n id?: unknown;\n status?: unknown;\n state?: unknown;\n canonicalStatus?: unknown;\n rawTrackerState?: unknown;\n completedAt?: unknown;\n}\n\nfunction normalizeIssueId(value: unknown): string | null {\n if (typeof value !== 'string') return null;\n const trimmed = value.trim();\n return trimmed ? trimmed.toUpperCase() : null;\n}\n\nexport function getClosedIssueIdsForReadSource(issues: unknown[]): Set<string> {\n const closed = new Set<string>();\n for (const issue of issues) {\n if (!issue || typeof issue !== 'object') continue;\n const item = issue as IssueReadSourceState;\n const issueId = normalizeIssueId(item.identifier) ?? normalizeIssueId(item.id);\n if (!issueId) continue;\n const state = String(item.state ?? '').toLowerCase();\n const status = String(item.status ?? '').toLowerCase();\n const canonicalStatus = String(item.canonicalStatus ?? '').toLowerCase();\n const rawTrackerState = String(item.rawTrackerState ?? '').toLowerCase();\n if (\n item.completedAt ||\n state === 'closed' ||\n status === 'done' ||\n status === 'closed' ||\n status === 'cancelled' ||\n status === 'canceled' ||\n status === 'completed' ||\n canonicalStatus === 'done' ||\n canonicalStatus === 'closed' ||\n canonicalStatus === 'cancelled' ||\n canonicalStatus === 'canceled' ||\n canonicalStatus === 'completed' ||\n rawTrackerState === 'closed' ||\n rawTrackerState === 'done' ||\n rawTrackerState === 'completed'\n ) {\n closed.add(issueId);\n }\n }\n return closed;\n}\n\nexport function pruneAgentsForReadSource(\n agentsById: Record<string, AgentSnapshot>,\n issues: unknown[],\n): { agentsById: Record<string, AgentSnapshot>; prunedCount: number } {\n const closedIssueIds = getClosedIssueIdsForReadSource(issues);\n // PAN-1908: authoritative membership is the SQLite agents table, not state.json.\n const liveAgentIds = new Set(listOverdeckAgentStatesSync().map(a => a.id));\n const nextAgentsById: Record<string, AgentSnapshot> = {};\n let prunedCount = 0;\n\n for (const agent of Object.values(agentsById)) {\n if (closedIssueIds.has(agent.issueId.toUpperCase())) {\n prunedCount++;\n continue;\n }\n if (!liveAgentIds.has(agent.id)) {\n prunedCount++;\n continue;\n }\n nextAgentsById[agent.id] = agent;\n }\n\n return { agentsById: nextAgentsById, prunedCount };\n}\n\n/**\n * Prunes review-status entries for closed issues on every snapshot request —\n * not just at boot (review finding, PAN-3362 UAT cycle 3). mergeDbOnlyReviewStatuses()\n * can hydrate a review_status row for an issue reconstructCacheAuto() never\n * covered (e.g. the FIX-1 UAT fixture, which has no per-issue record). If\n * that issue is later closed, close-out deletes the DB row but emits no\n * read-model removal event, so the in-memory snapshot would otherwise keep\n * showing it as reviewing/ready-to-merge indefinitely. Reusing\n * getClosedIssueIdsForReadSource() here — the same live, per-request signal\n * pruneAgentsForReadSource() already uses — means a mid-session close is\n * caught on the very next snapshot, not only after a restart.\n */\nexport function pruneReviewStatusesForReadSource(\n reviewStatusByIssueId: Record<string, ReviewStatusSnapshot>,\n issues: unknown[],\n): { reviewStatusByIssueId: Record<string, ReviewStatusSnapshot>; prunedCount: number } {\n const closedIssueIds = getClosedIssueIdsForReadSource(issues);\n const nextReviewStatusByIssueId: Record<string, ReviewStatusSnapshot> = {};\n let prunedCount = 0;\n\n for (const [issueId, status] of Object.entries(reviewStatusByIssueId)) {\n if (closedIssueIds.has(issueId.toUpperCase())) {\n prunedCount++;\n continue;\n }\n nextReviewStatusByIssueId[issueId] = status;\n }\n\n return { reviewStatusByIssueId: nextReviewStatusByIssueId, prunedCount };\n}\n\n// ─── Cached event store reference (avoids async dynamic import on each pushUpdated) ──\nlet _cachedEventStore: any = null;\n\ntype Jsonish = null | boolean | number | string | Jsonish[] | { [key: string]: Jsonish };\n\nfunction toJsonish(value: unknown, seen = new WeakSet<object>()): Jsonish | undefined {\n if (value == null) return null;\n if (typeof value === 'string' || typeof value === 'boolean') return value;\n if (typeof value === 'number') return Number.isFinite(value) ? value : null;\n if (value instanceof Date) return value.toISOString();\n if (Array.isArray(value)) {\n const next: Jsonish[] = [];\n for (const item of value) {\n const clean = toJsonish(item, seen);\n if (clean !== undefined) next.push(clean);\n }\n return next;\n }\n if (typeof value === 'object') {\n if (seen.has(value)) return null;\n seen.add(value);\n const next: { [key: string]: Jsonish } = {};\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n const clean = toJsonish(item, seen);\n if (clean !== undefined) next[key] = clean;\n }\n seen.delete(value);\n return next;\n }\n return undefined;\n}\n\nfunction cleanIssues(issues: unknown[]): unknown[] {\n return issues.map((issue) => toJsonish(issue) ?? null);\n}\n\n// ─── Value validators for strict literal types ──────────────────────────────\n\nconst VALID_AGENT_STATUSES = new Set<AgentStatus>([\"starting\", \"running\", \"stopped\", \"error\", \"unknown\"]);\nconst VALID_ROLES = new Set<Role>([\"plan\", \"work\", \"review\", \"test\", \"ship\", \"flywheel\", \"strike\", \"sequencer\", \"knowledge\"]);\nconst VALID_RESOLUTIONS = new Set<AgentResolution>([\"working\", \"done\", \"needs_input\", \"stuck\", \"completed\", \"unclear\", \"abandoned\", \"api_error\"]);\ntype SpecialistAgentName = 'review-agent' | 'test-agent' | 'merge-agent' | 'inspect-agent' | 'uat-agent';\ntype SpecialistLifecycleState = 'active' | 'sleeping' | 'uninitialized';\n\nconst VALID_SPECIALIST_NAMES = new Set<SpecialistAgentName>([\"review-agent\", \"test-agent\", \"merge-agent\", \"inspect-agent\", \"uat-agent\"]);\nconst VALID_SPECIALIST_LIFECYCLE_STATES = new Set<SpecialistLifecycleState>([\"active\", \"sleeping\", \"uninitialized\"]);\nconst VALID_REVIEW_STATUSES = new Set<ReviewStatusValue>([\"pending\", \"reviewing\", \"passed\", \"failed\", \"blocked\", \"skipped\"]);\nconst VALID_TEST_STATUSES = new Set<TestStatusValue>([\"pending\", \"testing\", \"passed\", \"failed\", \"skipped\", \"dispatch_failed\"]);\nconst VALID_UAT_STATUSES = new Set<UatStatusValue>([\"pending\", \"testing\", \"passed\", \"failed\"]);\nconst VALID_MERGE_STATUSES = new Set<MergeStatusValue>([\"pending\", \"queued\", \"merging\", \"verifying\", \"merged\", \"failed\"]);\nconst VALID_VERIFICATION_STATUSES = new Set<VerificationStatusValue>([\"pending\", \"running\", \"passed\", \"failed\", \"skipped\"]);\n\nexport function toAgentStatus(v: unknown): AgentStatus {\n return VALID_AGENT_STATUSES.has(v as AgentStatus) ? v as AgentStatus : \"unknown\";\n}\n\nexport function toRole(v: unknown): Role | undefined {\n return v && VALID_ROLES.has(v as Role) ? v as Role : undefined;\n}\n\nexport function toAgentResolution(v: unknown): AgentResolution | undefined {\n return v && VALID_RESOLUTIONS.has(v as AgentResolution) ? v as AgentResolution : undefined;\n}\nexport function toSpecialistAgentName(v: unknown): SpecialistAgentName | undefined {\n return VALID_SPECIALIST_NAMES.has(v as SpecialistAgentName) ? v as SpecialistAgentName : undefined;\n}\nexport function toSpecialistLifecycleState(v: unknown): SpecialistLifecycleState {\n return VALID_SPECIALIST_LIFECYCLE_STATES.has(v as SpecialistLifecycleState) ? v as SpecialistLifecycleState : \"uninitialized\";\n}\nexport function toReviewStatus(v: unknown): ReviewStatusValue | undefined {\n return v && VALID_REVIEW_STATUSES.has(v as ReviewStatusValue) ? v as ReviewStatusValue : undefined;\n}\nexport function toTestStatus(v: unknown): TestStatusValue | undefined {\n return v && VALID_TEST_STATUSES.has(v as TestStatusValue) ? v as TestStatusValue : undefined;\n}\nexport function toUatStatus(v: unknown): UatStatusValue | undefined {\n return v && VALID_UAT_STATUSES.has(v as UatStatusValue) ? v as UatStatusValue : undefined;\n}\nexport function toMergeStatus(v: unknown): MergeStatusValue | undefined {\n return v && VALID_MERGE_STATUSES.has(v as MergeStatusValue) ? v as MergeStatusValue : undefined;\n}\nexport function toVerificationStatus(v: unknown): VerificationStatusValue | undefined {\n return v && VALID_VERIFICATION_STATUSES.has(v as VerificationStatusValue) ? v as VerificationStatusValue : undefined;\n}\n\nexport type ReviewStatusSnapshotInput = ReviewStatus & {\n reviewCoordinatorSessionName?: string;\n reviewSessionNames?: string[];\n reviewSubStatuses?: Record<string, 'running' | 'done'>;\n activeSpecialist?: string;\n};\n\nexport function toReviewStatusSnapshot(status: ReviewStatusSnapshotInput): ReviewStatusSnapshot {\n return {\n issueId: status.issueId,\n reviewStatus: toReviewStatus(status.reviewStatus),\n testStatus: toTestStatus(status.testStatus),\n uatStatus: toUatStatus(status.uatStatus),\n uatNotes: status.uatNotes || undefined,\n mergeStatus: toMergeStatus(status.mergeStatus),\n releaseStatus: status.releaseStatus ?? undefined,\n releaseNotes: status.releaseNotes || undefined,\n verificationStatus: toVerificationStatus(status.verificationStatus),\n verificationNotes: status.verificationNotes || undefined,\n verificationCycleCount: typeof status.verificationCycleCount === 'number' ? status.verificationCycleCount : undefined,\n readyForMerge: !!status.readyForMerge,\n updatedAt: status.updatedAt,\n prUrl: status.prUrl || undefined,\n stuck: !!status.stuck ? true : undefined,\n stuckReason: status.stuckReason || undefined,\n stuckAt: status.stuckAt || undefined,\n stuckDetails: status.stuckDetails || undefined,\n reviewCycleHistory: status.reviewCycleHistory && status.reviewCycleHistory.length > 0\n ? status.reviewCycleHistory\n : undefined,\n reviewedAtCommit: status.reviewedAtCommit || undefined,\n reviewSpawnedAt: typeof status.reviewSpawnedAt === 'number'\n ? new Date(status.reviewSpawnedAt).toISOString()\n : status.reviewSpawnedAt || undefined,\n testRetryCount: typeof status.testRetryCount === 'number' ? status.testRetryCount : undefined,\n reviewRetryCount: typeof status.reviewRetryCount === 'number' ? status.reviewRetryCount : undefined,\n recoveryStartedAt: status.recoveryStartedAt || undefined,\n deaconIgnored: !!status.deaconIgnored ? true : undefined,\n deaconIgnoredAt: status.deaconIgnoredAt || undefined,\n deaconIgnoredReason: status.deaconIgnoredReason || undefined,\n // PAN-1691: tri-state routing key — preserve true/false/undefined as-is.\n autoMerge: status.autoMerge,\n reviewCoordinatorSessionName: status.reviewCoordinatorSessionName || undefined,\n reviewSessionNames: status.reviewSessionNames && status.reviewSessionNames.length > 0 ? status.reviewSessionNames : undefined,\n reviewSubStatuses: status.reviewSubStatuses,\n queuePosition: computeQueuePositionFromStatusSync(status).queuePosition ?? undefined,\n activeSpecialist: status.activeSpecialist || undefined,\n mergeRetryCount: typeof status.mergeRetryCount === 'number' ? status.mergeRetryCount : undefined,\n mergeNotes: status.mergeNotes || undefined,\n blockerReasons: status.blockerReasons && status.blockerReasons.length > 0 ? status.blockerReasons : undefined,\n autoRequeueCount: typeof status.autoRequeueCount === 'number' ? status.autoRequeueCount : undefined,\n };\n}\n\n/**\n * Layers DB-only review_status rows into a boot snapshot for issues\n * reconstructCacheAuto() didn't already cover (PAN-3362).\n *\n * reconstructCacheAuto() deliberately enumerates only tracker-backed\n * in-flight issues (it reads NO SQLite cache tables — sources of truth\n * only), so an issue with a review_status row but no real per-issue record\n * (e.g. the obviously-fake FIX-1 UAT fixture) is never included in\n * `trackerDerived`. This is a supplementary, additive source — a DB-only\n * row NEVER overrides a tracker-derived entry for the same issueId, the\n * same posture agentsById already takes by layering AgentsResolver's\n * DB-backed list alongside reconstructCacheAuto's result rather than\n * folding it in.\n */\nexport function mergeDbOnlyReviewStatuses(\n trackerDerived: Record<string, ReviewStatusSnapshot>,\n dbReviewStatuses: Record<string, ReviewStatusSnapshotInput>,\n): Record<string, ReviewStatusSnapshot> {\n const dbOnly: Record<string, ReviewStatusSnapshot> = {};\n for (const [issueId, dbStatus] of Object.entries(dbReviewStatuses)) {\n if (!(issueId in trackerDerived)) {\n dbOnly[issueId] = toReviewStatusSnapshot(dbStatus);\n }\n }\n return dbOnly;\n}\n\n// ─── ReadModelService ────────────────────────────────────────────────────────\n\nexport interface ReadModelServiceShape {\n /** Return the current read model state as a DashboardSnapshot. */\n readonly getSnapshot: Effect.Effect<DashboardSnapshotWithActivity>;\n /** Return a single pending channel permission request without rebuilding a full snapshot. */\n readonly getChannelPermissionRequest: (\n requestId: string,\n ) => Effect.Effect<import('@overdeck/contracts').ChannelPermissionRequestSnapshot | null>;\n /** Return a recent resolved channel permission decision for safe delivery retries. */\n readonly getResolvedChannelPermissionDecision: (\n requestId: string,\n ) => Effect.Effect<import('@overdeck/contracts').ResolvedChannelPermissionDecision | null>;\n /** Return in-memory turn diff summaries for a single agent. */\n readonly getTurnDiffSummaries: (agentId: string) => Effect.Effect<TurnDiffSummary[]>;\n /** Return the agentId for a given sessionId (from agent snapshot or runtime claudeSessionId). */\n readonly getAgentIdBySessionId: (sessionId: string) => Effect.Effect<string | null>;\n /** Apply a domain event to the read model (called by event store on append). */\n readonly applyEvent: (event: DomainEvent) => void;\n /** Bootstrap the read model from existing lib module state. */\n readonly bootstrap: Effect.Effect<void>;\n}\n\n// ─── Overdeck → legacy AgentSnapshot adapter ─────────────────────────────────\n//\n// Maps overdeck's 18-field Agent (durable config only) to the legacy\n// AgentSnapshot wire format. Runtime/ephemeral fields (lastActivity, branch,\n// costSoFar, phase, hasPendingQuestion, etc.) start undefined and are filled\n// by in-memory events from the enrichment poller and domain event stream.\n\nfunction overdeckStatusToLegacy(\n status: OverdeckAgent['status'],\n): AgentStatus {\n if (status === 'crashed') return 'error';\n // 'idle'/'waiting' = agent is alive but waiting (tool-call paused, AUQ, etc.)\n if (status === 'idle' || status === 'waiting') return 'running';\n return status; // 'starting' | 'running' | 'stopped' are 1:1\n}\n\nfunction agentSnapshotFromOverdeck(agent: OverdeckAgent): AgentSnapshot {\n return {\n id: agent.id,\n issueId: agent.issueId,\n workspace: agent.workspace || undefined,\n runtime: agent.harness,\n model: agent.model,\n status: overdeckStatusToLegacy(agent.status),\n startedAt: agent.startedAt?.toISOString(),\n sessionId: agent.sessionId ?? undefined,\n role: agent.role,\n stoppedByUser: agent.stoppedByUser ?? undefined,\n paused: agent.paused ?? undefined,\n pausedReason: agent.pausedReason ?? undefined,\n troubled: agent.troubled ?? undefined,\n consecutiveFailures: agent.consecutiveFailures,\n firstFailureInRunAt: agent.firstFailureInRunAt?.toISOString(),\n lastFailureNextRetryAt: agent.lastFailureNextRetryAt?.toISOString(),\n };\n}\n\nexport class ReadModelService extends Context.Service<\n ReadModelService,\n ReadModelServiceShape\n>()('overdeck/dashboard/ReadModelService') {}\n\n// ─── Live implementation ─────────────────────────────────────────────────────\n\nexport const ReadModelServiceLive = Layer.effect(\n ReadModelService,\n Effect.gen(function* () {\n let state: ReadModelState = { ...INITIAL_READ_MODEL_STATE };\n\n function cloneTurnDiffSummaries(summaries: TurnDiffSummary[] | undefined): TurnDiffSummary[] {\n if (!summaries || summaries.length === 0) return [];\n return summaries.map(summary => ({\n ...summary,\n files: summary.files.map(file => ({ ...file })),\n assistantMessageId: summary.assistantMessageId ?? undefined,\n checkpointRef: summary.checkpointRef ?? undefined,\n }));\n }\n\n function buildSnapshot(): DashboardSnapshotWithActivity {\n // turnDiffSummariesByAgentId is intentionally excluded from the snapshot.\n //\n // Per-agent checkpoint history can grow to thousands of turns × hundreds\n // of files; in production we measured 484 MB across 44 agents, which the\n // browser's WebSocket client rejects as \"Max payload size exceeded\" and\n // closes the socket with code 1006 — leaving the kanban and command deck\n // perpetually empty. The data is still maintained in `state` and served\n // on-demand via GET /api/agents/:id/diffs, so chat-timeline components\n // fetch it only for the agent the user is actually viewing.\n return {\n sequence: state.sequence,\n agents: Object.values(state.agentsById),\n // PAN-1048 — specialistsByName projection retired. The DashboardSnapshot\n // schema still has a `specialists` field for backward compat with the\n // wire format; we always send an empty array and clients derive the\n // same data from agentsById filtered by role.\n specialists: [],\n reviewStatuses: Object.values(state.reviewStatusByIssueId),\n agentRuntimeById: state.agentRuntimeById,\n channelPermissionRequests: Object.values(state.channelPermissionRequestsById ?? {}),\n issues: state.issuesRaw,\n recentActivity: state.recentActivity,\n resources: state.resources ?? undefined,\n memory: {\n observationsByIssueId: state.observationsByIssueId,\n statusByIssueId: state.statusByIssueId,\n rollupsByIssueId: state.rollupsByIssueId,\n resetMarkersByScopeId: state.resetMarkersByScopeId,\n healthByIssueId: state.healthByIssueId,\n },\n scanProgress: state.scanProgress,\n enrichStats: state.enrichStats,\n enrichProgressBySessionId: state.enrichProgressBySessionId,\n embedProgressBySessionId: state.embedProgressBySessionId,\n ciByProjectKey: state.ciByProjectKey,\n // PAN-3729: the restart-approval banner reads the gate from the\n // snapshot on connect and from restart_gate.changed events after that\n // — the frontend never polls the gate endpoints.\n restartGate: state.restartGate ?? undefined,\n timestamp: new Date().toISOString(),\n };\n }\n\n const applyEvent = (event: DomainEvent): void => {\n state = applyEventReducer(state, event);\n };\n\n const getSnapshot: Effect.Effect<DashboardSnapshotWithActivity> = Effect.gen(function* () {\n // Refresh issues from the shared issue service before building snapshot.\n // IssueDataService polls trackers in the background; its cached issues are\n // the freshest available without blocking on API calls.\n //\n // PAN-1510: merge issueService's view with the current state.issuesRaw\n // so a hard browser reload always reflects the union of (projection\n // cache + freshest issueService data). issueService entries win on\n // identifier conflicts (fresher status, labels, etc.), and cached\n // entries that issueService is missing (transient empty fetch,\n // partial poll, single-tracker failure) are preserved instead of\n // dropped. Identifier-based merge is the same shape PAN-1506 used to\n // surface newly-spawned agents through the bootstrap fast-path.\n try {\n const { getSharedIssueService } = yield* Effect.promise(\n () => import('./services/issue-service-singleton.js'),\n );\n const issueService = getSharedIssueService();\n const currentIssues = cleanIssues(issueService.getIssues());\n if (currentIssues.length > 0 || state.issuesRaw.length === 0) {\n state = {\n ...state,\n issuesRaw: mergeIssuesByIdentifier(state.issuesRaw, currentIssues),\n };\n }\n } catch (err) {\n console.error('[ReadModel] Failed to refresh issues for snapshot:', err);\n }\n\n const pruned = pruneAgentsForReadSource(state.agentsById, state.issuesRaw);\n if (pruned.prunedCount > 0) {\n state = { ...state, agentsById: pruned.agentsById };\n console.log(`[ReadModel] Pruned ${pruned.prunedCount} stale agent${pruned.prunedCount === 1 ? '' : 's'} from read source`);\n }\n\n const prunedReviewStatuses = pruneReviewStatusesForReadSource(state.reviewStatusByIssueId, state.issuesRaw);\n if (prunedReviewStatuses.prunedCount > 0) {\n state = { ...state, reviewStatusByIssueId: prunedReviewStatuses.reviewStatusByIssueId };\n console.log(`[ReadModel] Pruned ${prunedReviewStatuses.prunedCount} stale review status${prunedReviewStatuses.prunedCount === 1 ? '' : 'es'} from read source`);\n }\n\n return buildSnapshot();\n });\n\n const getChannelPermissionRequest = (\n requestId: string,\n ): Effect.Effect<import('@overdeck/contracts').ChannelPermissionRequestSnapshot | null> =>\n Effect.succeed(state.channelPermissionRequestsById?.[requestId] ?? null);\n\n const getResolvedChannelPermissionDecision = (\n requestId: string,\n ): Effect.Effect<import('@overdeck/contracts').ResolvedChannelPermissionDecision | null> =>\n Effect.succeed(state.resolvedChannelPermissionDecisionsById?.[requestId] ?? null);\n\n const getTurnDiffSummaries = (agentId: string): Effect.Effect<TurnDiffSummary[]> =>\n Effect.sync(() => cloneTurnDiffSummaries(state.turnDiffSummariesByAgentId[agentId]));\n\n const getAgentIdBySessionId = (sessionId: string): Effect.Effect<string | null> =>\n Effect.sync(() => state.agentIdBySessionId[sessionId] ?? null);\n\n // ── Bootstrap inline during layer construction ───────────────────────────\n const agentsResolver = yield* AgentsResolver;\n yield* Effect.gen(function* () {\n // Agents come from AgentsResolver; reconstructCache supplies git-backed review status and boot side effects.\n const { reconstructCacheAuto } = yield* Effect.promise(() =>\n import('../../lib/reconstruct/reconstruct-cache.js'),\n );\n\n const result = yield* Effect.promise(() => reconstructCacheAuto());\n const overdeckAgents = yield* agentsResolver.list({});\n\n // See mergeDbOnlyReviewStatuses() doc comment — reconstructCacheAuto()\n // only enumerates tracker-backed issues, so DB-only review_status rows\n // (e.g. the FIX-1 UAT fixture, PAN-3362) need a supplementary source.\n let dbOnlyReviewStatusByIssueId: Record<string, ReviewStatusSnapshot> = {};\n try {\n const { getAllReviewStatusesFromDb } = yield* Effect.promise(\n () => import('../../lib/overdeck/review-status-sync.js'),\n );\n dbOnlyReviewStatusByIssueId = mergeDbOnlyReviewStatuses(result.reviewStatusByIssueId, getAllReviewStatusesFromDb());\n } catch (err) {\n console.error('[ReadModel] Failed to layer in DB-only review statuses:', err);\n }\n\n const agentsById: Record<string, AgentSnapshot> = Object.fromEntries(\n overdeckAgents.map((a) => [a.id, agentSnapshotFromOverdeck(a)]),\n );\n\n // ── Sequence from event store (labels the snapshot, not a replay source) ─\n let sequence = 0;\n let recentActivity: unknown[] = [];\n try {\n const { getEventStore } = yield* Effect.promise(\n () => import('./event-store.js'),\n );\n const eventStore = getEventStore();\n yield* Effect.promise(() => emitBootReconciledStopEvents(eventStore, result.markedStoppedIds, result.agentsById, '[ReadModel] Failed to emit boot-reconciled stop events:'));\n sequence = eventStore.getLatestSequence();\n recentActivity = activityEntriesFromStoredEvents(\n eventStore.queryByType('activity.entry', MAX_SNAPSHOT_ACTIVITY_ENTRIES),\n );\n } catch (err) {\n console.error('[ReadModel] Failed to emit boot-reconciled stop events:', err);\n }\n\n state = {\n ...INITIAL_READ_MODEL_STATE,\n sequence,\n agentsById,\n reviewStatusByIssueId: { ...dbOnlyReviewStatusByIssueId, ...result.reviewStatusByIssueId },\n issuesRaw: [],\n recentActivity,\n };\n\n console.log(\n `[ReadModel] Bootstrapped from local database: ` +\n `${Object.keys(agentsById).length} agents, ` +\n `${Object.keys(result.reviewStatusByIssueId).length} review statuses, ` +\n `${result.issuesEnumerated} in-flight issue(s), seq=${sequence}`,\n );\n\n // ── Checkpoint reconciliation (deferred — non-blocking) ──────────────────\n // Fire-and-forget: scan workspaces for git checkpoints in the background\n // so the ReadModel layer resolves immediately and the dashboard starts fast.\n void (async () => {\n try {\n const { listCheckpoints, diffCheckpointFiles, getCheckpointTimestamp, deleteLegacyCheckpointRefs } = await import('../../lib/checkpoint/checkpoint-manager.js');\n\n const agents = Object.values(state.agentsById);\n\n // One-time: clean up unscoped legacy refs from before per-agent namespacing.\n // Run against the first agent's workspace (all worktrees share the same parent .git).\n const firstAgentWithWorkspace = agents.find(a => a.workspace);\n if (firstAgentWithWorkspace?.workspace) {\n const deleted = await Effect.runPromise(deleteLegacyCheckpointRefs(firstAgentWithWorkspace.workspace));\n if (deleted > 0) {\n console.log(`[ReadModel] Deleted ${deleted} legacy unscoped checkpoint refs`);\n }\n }\n let reconciled = 0;\n for (const agent of agents) {\n if (shouldSkipCheckpointReconciliation(agent)) continue;\n\n const workspace = agent.workspace;\n if (!workspace) continue;\n const existingSummaries = state.turnDiffSummariesByAgentId[agent.id];\n if (existingSummaries && existingSummaries.length > 0) continue;\n\n try {\n const checkpoints = await Effect.runPromise(listCheckpoints(workspace, agent.id));\n if (checkpoints.length === 0) continue;\n\n const maxRetainedSummaries = getMaxTurnDiffSummariesPerAgent();\n const retainedCheckpoints = checkpoints.length > maxRetainedSummaries\n ? checkpoints.slice(-maxRetainedSummaries)\n : checkpoints;\n const checkpointOffset = checkpoints.length - retainedCheckpoints.length;\n\n const summaries: Array<{\n turnId: string;\n completedAt: string;\n files: Array<{ path: string; kind?: string; additions?: number; deletions?: number }>;\n checkpointRef?: string;\n assistantMessageId?: string;\n checkpointTurnCount?: number;\n }> = [];\n\n for (let i = 0; i < retainedCheckpoints.length; i++) {\n const absoluteIndex = checkpointOffset + i;\n const turnId = retainedCheckpoints[i];\n if (!turnId) continue;\n const prevTurnId = absoluteIndex > 0 ? checkpoints[absoluteIndex - 1] ?? null : null;\n let files: Array<{ path: string; kind?: string; additions?: number; deletions?: number }> = [];\n if (prevTurnId) {\n try {\n files = await Effect.runPromise(diffCheckpointFiles(workspace, agent.id, prevTurnId, turnId));\n } catch { /* checkpoint might be stale */ }\n }\n const completedAt = await Effect.runPromise(getCheckpointTimestamp(workspace, agent.id, turnId));\n summaries.push({\n turnId,\n completedAt,\n files,\n checkpointRef: `refs/pan/turn/${agent.id}/${turnId}`,\n checkpointTurnCount: absoluteIndex + 1,\n });\n }\n\n if (summaries.length > 0) {\n state = {\n ...state,\n turnDiffSummariesByAgentId: {\n ...state.turnDiffSummariesByAgentId,\n [agent.id]: trimTurnDiffSummaries(summaries),\n },\n };\n reconciled++;\n }\n } catch { /* agent workspace may not be a git repo */ }\n }\n\n if (reconciled > 0) {\n console.log(`[ReadModel] Reconciled checkpoints for ${reconciled} agent(s)`);\n }\n } catch (err) {\n console.warn('[ReadModel] Checkpoint reconciliation failed:', err);\n }\n })();\n\n // ── Issue listener (always) ──────────────────────────────────────────────\n // Issues come from external trackers (Linear/GitHub) with unpredictable shapes.\n // JSON round-trip strips undefined values that can't be serialized over WebSocket.\n try {\n const { getSharedIssueService } = yield* Effect.promise(\n () => import('./services/issue-service-singleton.js'),\n );\n const issueService = getSharedIssueService();\n\n // PAN-1510: merge issueService's view with whatever the projection\n // cache loaded so newly-filed issues (filed during the previous\n // session's debounced-flush window, or already loaded into\n // IssueDataService's in-memory cache before the read model bootstrap\n // wired its onIssuesChanged callback) reach `issuesRaw`. Without the\n // merge, the bootstrap window between issueService.start() loading\n // its SQLite cache and read-model wiring `onIssuesChanged` could\n // strand fresh issues — the subsequent `pushSnapshot` would either\n // hit a null callback or be skipped by `issuesChanged()` because\n // `lastFetchedIssues` already matched the new GitHub fetch.\n const mergeT0 = performance.now();\n const currentIssues = cleanIssues(issueService.getIssues());\n if (currentIssues.length > 0 || state.issuesRaw.length === 0) {\n const newIssues = discoverNewIssues(state.issuesRaw, currentIssues);\n if (newIssues.length > 0) {\n const sample = newIssues\n .slice(0, 5)\n .map(i => getIssueIdentifierKey(i) ?? 'unknown')\n .join(', ');\n const more = newIssues.length > 5 ? `, +${newIssues.length - 5} more` : '';\n console.log(\n `[ReadModel] Bootstrap: merging ${newIssues.length} new issue(s) from issueService not in projection cache (${sample}${more})`,\n );\n }\n state = {\n ...state,\n issuesRaw: mergeIssuesByIdentifier(state.issuesRaw, currentIssues),\n };\n }\n console.log(`[boot-timing] ReadModel bootstrap merge completed at +${Math.round(performance.now() - mergeT0)}ms`);\n\n // Wire live issue updates — when IssueDataService polls new data,\n // update the read model directly AND emit to event store for\n // WebSocket subscribers (PAN-433).\n issueService.onIssuesChanged((issues) => {\n const cleaned = cleanIssues(issues);\n const delta = createIssueDelta(state.issuesRaw, cleaned);\n if (!delta) return;\n state = { ...state, issuesRaw: cleaned };\n\n // Initial/reconnect snapshots retain every field. Subsequent updates\n // send complete changed rows only, preserving descriptions and order.\n // These cache projections must never enter the durable event log.\n // Uses cached reference to avoid async dynamic import delay\n // (delay caused frontend to miss updates after patchIssue)\n try {\n if (!_cachedEventStore) {\n import('./event-store.js').then(({ getEventStore }) => {\n _cachedEventStore = getEventStore();\n try {\n _cachedEventStore.emitOnly({\n type: 'issues.delta',\n timestamp: new Date().toISOString(),\n payload: delta,\n } as any);\n } catch { /* event store not ready */ }\n }).catch(() => {});\n } else {\n _cachedEventStore.emitOnly({\n type: 'issues.delta',\n timestamp: new Date().toISOString(),\n payload: delta,\n } as any);\n }\n } catch { /* event store not ready yet */ }\n\n // PAN-1866: debounced incremental sequencer pass on every backlog delta\n import('../../lib/backlog/backlog-auto-trigger.js').then(({ triggerDebouncedIncrementalPass }) => {\n triggerDebouncedIncrementalPass(process.cwd());\n }).catch(() => {});\n });\n } catch {\n console.warn('[ReadModel] IssueDataService not available at bootstrap, starting with empty issues');\n }\n });\n\n return {\n getSnapshot,\n getChannelPermissionRequest,\n getResolvedChannelPermissionDecision,\n getTurnDiffSummaries,\n getAgentIdBySessionId,\n applyEvent,\n bootstrap: Effect.void,\n };\n }),\n);\n","import { readFile, stat } from 'fs/promises';\nimport { basename, dirname, join, resolve } from 'path';\nimport type { DashboardSnapshot, FeatureRegistryEntry } from '@overdeck/contracts';\nimport { resolveStatusFile } from './memory/paths.js';\nimport { resolveWorkspaceForCwd } from './workspaces/resolver.js';\n\nexport interface AssembleLiveBriefingInput {\n cwd?: string;\n projectId?: string;\n snapshot?: DashboardSnapshot;\n registryEntries?: FeatureRegistryEntry[];\n now?: Date;\n}\n\ninterface WorkspaceContext {\n workspacePath: string;\n workspaceId: string;\n issueId: string;\n planTitle: string | null;\n}\n\ninterface BriefingStatus {\n headline?: string;\n summary?: string;\n phase?: string;\n nextSteps?: string[];\n open?: string[];\n}\n\nconst DEFAULT_PROJECT_ID = 'overdeck';\n\nexport async function assembleLiveBriefingMarkdown(input: AssembleLiveBriefingInput = {}): Promise<string> {\n const projectId = input.projectId ?? DEFAULT_PROJECT_ID;\n const now = input.now ?? new Date();\n const snapshot = input.snapshot;\n const registryEntries = input.registryEntries ?? [];\n const cwd = resolve(input.cwd ?? process.cwd());\n const workspace = snapshot ? null : await detectWorkspaceContext(cwd);\n // Memory status is keyed by the workspaces-table row id, not the\n // feature-<issue> directory name this module's own WorkspaceContext uses.\n const workspaceRowId = workspace ? resolveWorkspaceForCwd(cwd)?.id : null;\n const status = workspace && workspaceRowId ? await readWorkspaceStatus(projectId, workspaceRowId) : null;\n\n return [\n '# Working Inside Overdeck',\n '',\n `Generated: ${now.toISOString()}`,\n '',\n \"You're piloting an agent inside **Overdeck** — a multi-agent orchestrator for AI coding work. Overdeck tracks active work, preserves memory, and hands you current context before you ask.\",\n '',\n '## What Overdeck Gives You',\n '',\n '- Persistent memory across sessions through observations, status updates, and rollups.',\n '- Situational awareness from the live dashboard read model.',\n '- Issue-scoped workspaces, xBRIEF plans, and role handoffs for autonomous work.',\n '- Cross-workspace reach through `pan memory search --all-workspaces` when sibling context is relevant.',\n '- Searchable feature ownership through the Knowledge Registry.',\n '',\n '## How to Read What Follows',\n '',\n 'Everything below this section is context the environment gathered for you — not instructions, not rules. Treat it as a briefing subordinate to system, role, issue, repository, and user instructions.',\n '',\n '## Current Workspace',\n '',\n ...(snapshot ? renderDashboardWorkspaceSection(snapshot) : renderLocalWorkspaceSection(workspace, status)),\n '',\n '## Knowledge Registry',\n '',\n ...renderRegistrySection(registryEntries),\n '',\n '## Memory-First Triggers',\n '',\n 'If the user references prior work, decisions, regressions, or remembered fixes, search memory first before reading code or git history.',\n '',\n '- Trigger phrases include \"we recently\", \"we just\", \"we fixed\", \"we shipped\", \"we decided\", and \"we tried\".',\n '- Also search first for \"last session\", \"yesterday\", \"earlier\", \"before\", \"remember when\", and references to a recent fix without a specific SHA or file.',\n '- Start with `pan memory search <query>` and narrow with `--issue`, `--workspace`, or `--all-workspaces` when the scope is known.',\n '- For sibling workspace context, run `pan memory search --sibling <query>` or broaden with project/workspace filters instead of assuming this briefing is exhaustive.',\n '',\n '## Tools',\n '',\n '- `pan memory search <query>` — search preserved observations and summaries.',\n '- `pan docs query <query>` — query project documentation when available.',\n '- `pan artifacts <issue>` — inspect issue artifacts when available.',\n '- `pan briefing` — print this live briefing for terminal-only sessions.',\n '- `pan registry tag|list|show` — manage and inspect feature ownership records.',\n '- `pan compliance status` — inspect advisory memory-first compliance state when available.',\n ].join('\\n').trimEnd() + '\\n';\n}\n\nasync function detectWorkspaceContext(cwd: string): Promise<WorkspaceContext | null> {\n let current = cwd;\n while (true) {\n const workspaceId = basename(current);\n const issueMatch = workspaceId.match(/^feature-([a-z]+-\\d+)$/i);\n if (issueMatch && await pathExists(join(current, '.git'))) {\n return {\n workspacePath: current,\n workspaceId,\n issueId: issueMatch[1].toUpperCase(),\n planTitle: await readWorkspacePlanTitle(current),\n };\n }\n const parent = dirname(current);\n if (parent === current) return null;\n current = parent;\n }\n}\n\nasync function readWorkspacePlanTitle(workspacePath: string): Promise<string | null> {\n const path = join(workspacePath, '.pan', 'spec.vbrief.json');\n try {\n const parsed = JSON.parse(await readFile(path, 'utf8')) as { plan?: { title?: unknown } };\n return typeof parsed.plan?.title === 'string' ? parsed.plan.title : null;\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n}\n\nasync function readWorkspaceStatus(projectId: string, workspaceId: string): Promise<BriefingStatus | null> {\n try {\n const parsed = JSON.parse(await readFile(resolveStatusFile(projectId, workspaceId), 'utf8')) as BriefingStatus;\n return parsed && typeof parsed === 'object' ? parsed : null;\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n}\n\nfunction renderLocalWorkspaceSection(workspace: WorkspaceContext | null, status: BriefingStatus | null): string[] {\n if (!workspace) {\n return [\n '- No Overdeck workspace was detected from the current directory.',\n '- Run `pan briefing` from inside a `workspaces/feature-<issue>` checkout to include workspace-specific context.',\n ];\n }\n\n const lines = [\n `- Workspace: ${workspace.workspaceId}`,\n `- Issue: ${workspace.issueId}`,\n `- Path: ${workspace.workspacePath}`,\n ];\n if (workspace.planTitle) lines.push(`- Plan: ${workspace.planTitle}`);\n if (status?.phase) lines.push(`- Phase: ${status.phase}`);\n if (status?.headline) lines.push(`- Headline: ${status.headline}`);\n if (status?.summary) lines.push(`- Summary: ${status.summary}`);\n if (status?.nextSteps?.length) lines.push(`- Next steps: ${status.nextSteps.join('; ')}`);\n if (status?.open?.length) lines.push(`- Open questions: ${status.open.join('; ')}`);\n return lines;\n}\n\nfunction renderDashboardWorkspaceSection(snapshot: DashboardSnapshot): string[] {\n const runningAgents = snapshot.agents.filter((agent) => agent.status === 'running' || agent.hasLiveTmuxSession);\n const pausedAgents = snapshot.agents.filter((agent) => agent.paused);\n const troubledAgents = snapshot.agents.filter((agent) => agent.troubled === true);\n const activeIssues = new Set(snapshot.agents.map((agent) => agent.issueId).filter(Boolean));\n const failedReviews = snapshot.reviewStatuses.filter((status) =>\n status.testStatus === 'failed' ||\n status.uatStatus === 'failed' ||\n status.verificationStatus === 'failed' ||\n status.reviewStatus === 'failed' ||\n (status.blockerReasons?.length ?? 0) > 0,\n );\n\n const lines = [\n `- Running agents: ${runningAgents.length}`,\n `- Active issues with agents: ${activeIssues.size}`,\n `- Paused gates: ${pausedAgents.length}`,\n `- Troubled agents: ${troubledAgents.length}`,\n `- Failed verification/review states needing attention: ${failedReviews.length}`,\n ];\n\n const recentStatuses = Object.entries(readStatusByIssue(snapshot))\n .slice(0, 8)\n .map(([issueId, status]) => {\n const headline = typeof status.headline === 'string' && status.headline.trim()\n ? status.headline.trim()\n : 'No headline recorded';\n const phase = typeof status.phase === 'string' && status.phase.trim()\n ? ` (${status.phase.trim()})`\n : '';\n return `- ${issueId}${phase}: ${headline}`;\n });\n\n if (recentStatuses.length > 0) {\n lines.push('', 'Recent workspace statuses:', ...recentStatuses);\n } else {\n lines.push('', '- No workspace status summaries are currently available.');\n }\n\n return lines;\n}\n\nfunction readStatusByIssue(snapshot: DashboardSnapshot): Record<string, { headline?: unknown; phase?: unknown }> {\n const memory = (snapshot as { memory?: { statusByIssueId?: unknown } }).memory;\n return memory?.statusByIssueId && typeof memory.statusByIssueId === 'object'\n ? memory.statusByIssueId as Record<string, { headline?: unknown; phase?: unknown }>\n : {};\n}\n\nfunction renderRegistrySection(entries: FeatureRegistryEntry[]): string[] {\n if (entries.length === 0) {\n return [\n '- No feature registry entries are currently available.',\n '- Use `pan registry tag <issueId> <feature>` to add manual ownership records.',\n '- Use `pan registry list` and `pan registry show <feature>` to inspect ownership from terminal-only sessions.',\n ];\n }\n\n return [\n '| Feature | Issue | Workspace | Agent | Status | Tags |',\n '|---|---|---|---|---|---|',\n ...entries.slice(0, 25).map((entry) => [\n entry.featureName,\n entry.owningIssueId ?? '—',\n entry.owningWorkspaceId ?? '—',\n entry.owningAgentId ?? '—',\n entry.status,\n entry.tags.length > 0 ? entry.tags.join(', ') : '—',\n ].map(markdownCell).join(' | ')).map((row) => `| ${row} |`),\n ];\n}\n\nfunction markdownCell(value: string): string {\n return value.replaceAll('|', '\\\\|').replace(/\\s+/g, ' ').trim();\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch (error) {\n if (isNotFound(error)) return false;\n throw error;\n }\n}\n\nfunction isNotFound(error: unknown): boolean {\n return typeof error === 'object' && error !== null && 'code' in error && error.code === 'ENOENT';\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport type { DashboardSnapshot, FeatureRegistryEntry } from '@overdeck/contracts';\nimport { assembleLiveBriefingMarkdown } from '../../../lib/briefing-assembler.js';\nimport { resolveSessionContextBriefingPath } from '../../../lib/briefing-freshness.js';\nimport { listFeatureRegistryEntries } from '../../../lib/registry/feature-registry-storage.js';\n\nexport interface SessionContextWriter {\n schedule(): void;\n writeNow(): Promise<void>;\n stop(): void;\n}\n\nexport interface StartSessionContextWriterOptions {\n readSnapshot: () => Promise<DashboardSnapshot>;\n subscribe: (listener: () => void) => () => void;\n debounceMs?: number;\n path?: string;\n now?: () => Date;\n mkdir?: typeof mkdir;\n writeFile?: typeof writeFile;\n listRegistryEntries?: () => Promise<FeatureRegistryEntry[]>;\n setTimeout?: typeof setTimeout;\n clearTimeout?: typeof clearTimeout;\n logger?: Pick<Console, 'error' | 'warn'>;\n}\n\nexport function startSessionContextWriter(options: StartSessionContextWriterOptions): SessionContextWriter {\n const debounceMs = options.debounceMs ?? 500;\n const path = options.path ?? resolveSessionContextBriefingPath();\n const mkdirFn = options.mkdir ?? mkdir;\n const writeFileFn = options.writeFile ?? writeFile;\n const listRegistryEntriesFn = options.listRegistryEntries ?? (() => listFeatureRegistryEntries({ limit: 50 }));\n const setTimeoutFn = options.setTimeout ?? setTimeout;\n const clearTimeoutFn = options.clearTimeout ?? clearTimeout;\n const now = options.now ?? (() => new Date());\n const logger = options.logger ?? console;\n\n let timer: ReturnType<typeof setTimeout> | null = null;\n let stopped = false;\n let writing = false;\n let pendingAfterWrite = false;\n\n const writeLatest = async (): Promise<void> => {\n if (stopped) return;\n if (writing) {\n pendingAfterWrite = true;\n return;\n }\n\n writing = true;\n try {\n const [snapshot, registryEntries] = await Promise.all([\n options.readSnapshot(),\n readRegistryEntries(listRegistryEntriesFn, logger),\n ]);\n const content = await assembleLiveBriefingMarkdown({ snapshot, registryEntries, now: now() });\n await mkdirFn(dirname(path), { recursive: true });\n await writeFileFn(path, content, 'utf8');\n } catch (error) {\n logger.error('[session-context] Failed to write live briefing:', error);\n } finally {\n writing = false;\n if (pendingAfterWrite && !stopped) {\n pendingAfterWrite = false;\n schedule();\n }\n }\n };\n\n const schedule = (): void => {\n if (stopped) return;\n if (timer) clearTimeoutFn(timer);\n timer = setTimeoutFn(() => {\n timer = null;\n void writeLatest();\n }, debounceMs);\n };\n\n const unsubscribe = options.subscribe(schedule);\n void writeLatest();\n\n return {\n schedule,\n writeNow: writeLatest,\n stop() {\n stopped = true;\n if (timer) {\n clearTimeoutFn(timer);\n timer = null;\n }\n unsubscribe();\n },\n };\n}\n\nasync function readRegistryEntries(\n listRegistryEntries: () => Promise<FeatureRegistryEntry[]>,\n logger: Pick<Console, 'warn'>,\n): Promise<FeatureRegistryEntry[]> {\n try {\n return await listRegistryEntries();\n } catch (error) {\n logger.warn('[session-context] Failed to load feature registry entries:', error);\n return [];\n }\n}\n","import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execFileAsync = promisify(execFile);\n\nexport type ProjectCiGhApi = (path: string) => Promise<unknown>;\n\nexport const projectCiGhApi: ProjectCiGhApi = async (path) => {\n const { stdout } = await execFileAsync(\n 'gh',\n ['api', path, '-H', 'Accept: application/vnd.github+json'],\n { encoding: 'utf-8', timeout: 15_000, maxBuffer: 8 * 1024 * 1024 },\n );\n return JSON.parse(stdout);\n};\n\nexport async function resolveDefaultBranchHead(\n repo: string,\n branch: string,\n ghApi: ProjectCiGhApi = projectCiGhApi,\n): Promise<string | null> {\n const response = await ghApi(\n `repos/${repo}/branches/${encodeURIComponent(branch)}`,\n ) as { commit?: { sha?: string } };\n return response.commit?.sha ?? null;\n}\n","import type {\n ProjectCiHeadObservedEvent,\n ProjectCiSuite,\n} from '@overdeck/contracts';\nimport { appendDomainEventAsync } from '../activity-logger.js';\nimport {\n projectCiGhApi,\n resolveDefaultBranchHead,\n type ProjectCiGhApi,\n} from '../ci/project-ci-github.js';\nimport { listProjectsSync, type ProjectConfig } from '../projects.js';\n\ntype Project = { key: string; config: ProjectConfig };\ntype HeadObservation = ProjectCiHeadObservedEvent['payload'];\n\ninterface WorkflowRun {\n head_sha?: string;\n check_suite_id?: number;\n status?: string;\n conclusion?: string | null;\n html_url?: string;\n updated_at?: string;\n}\n\ninterface ProjectCiFillState {\n fingerprints: Map<string, string>;\n}\n\nexport function createProjectCiFillState(): ProjectCiFillState {\n return { fingerprints: new Map() };\n}\n\nfunction projectionFingerprint(observation: HeadObservation): string {\n const suites = Object.entries(observation.suites)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([suiteId, suite]) => [\n suiteId,\n suite.status,\n suite.conclusion,\n suite.htmlUrl ?? null,\n ]);\n return JSON.stringify([\n observation.repo,\n observation.branch,\n observation.headSha,\n suites,\n ]);\n}\n\n/** Fetch a complete Actions projection for the independently-resolved default\n * branch head. The second branch lookup prevents publishing a projection when\n * the branch advances while workflow pages are being collected. */\nexport async function fillProjectCiObservation(\n project: Project,\n deps: { ghApi?: ProjectCiGhApi; now?: () => string } = {},\n): Promise<HeadObservation | null> {\n const repo = project.config.github_repo;\n if (!repo) return null;\n const branch = project.config.workspace?.default_branch ?? 'main';\n const ghApi = deps.ghApi ?? projectCiGhApi;\n\n try {\n const headSha = await resolveDefaultBranchHead(repo, branch, ghApi);\n if (!headSha) return null;\n\n const runs: WorkflowRun[] = [];\n for (let page = 1; ; page += 1) {\n const response = await ghApi(\n `repos/${repo}/actions/runs?branch=${encodeURIComponent(branch)}`\n + `&head_sha=${encodeURIComponent(headSha)}&per_page=100&page=${page}`,\n ) as { workflow_runs?: WorkflowRun[] };\n const pageRuns = response.workflow_runs ?? [];\n runs.push(...pageRuns);\n if (pageRuns.length < 100) break;\n }\n\n const verifiedHeadSha = await resolveDefaultBranchHead(repo, branch, ghApi);\n if (verifiedHeadSha !== headSha) return null;\n\n const observedAt = deps.now?.() ?? new Date().toISOString();\n const suites: Record<string, ProjectCiSuite> = {};\n for (const run of runs) {\n if (run.head_sha !== headSha || run.check_suite_id == null) continue;\n const suiteId = String(run.check_suite_id);\n const suiteObservedAt = run.updated_at ?? observedAt;\n const existing = suites[suiteId];\n if (existing?.observedAt && existing.observedAt > suiteObservedAt) continue;\n suites[suiteId] = {\n status: run.status ?? 'queued',\n conclusion: run.conclusion ?? null,\n htmlUrl: run.html_url,\n observedAt: suiteObservedAt,\n };\n }\n\n return {\n projectKey: project.key,\n repo,\n branch,\n headSha,\n suites,\n observedAt,\n };\n } catch {\n return null;\n }\n}\n\n/** Fill every project through one complete, idempotent projection event. */\nexport async function fillAllProjectCi(\n deps: {\n ghApi?: ProjectCiGhApi;\n append?: typeof appendDomainEventAsync;\n projects?: Project[];\n state?: ProjectCiFillState;\n now?: () => string;\n } = {},\n): Promise<number> {\n const append = deps.append ?? appendDomainEventAsync;\n const projects = deps.projects ?? listProjectsSync();\n const state = deps.state ?? createProjectCiFillState();\n let appended = 0;\n\n for (const project of projects) {\n if (!project.config.github_repo) continue;\n const observation = await fillProjectCiObservation(project, {\n ghApi: deps.ghApi,\n now: deps.now,\n });\n if (!observation) continue;\n\n const fingerprint = projectionFingerprint(observation);\n if (state.fingerprints.get(project.key) === fingerprint) continue;\n if (await append({\n type: 'project.ci_head_observed',\n timestamp: observation.observedAt,\n payload: observation,\n })) {\n state.fingerprints.set(project.key, fingerprint);\n appended += 1;\n }\n }\n\n return appended;\n}\n\nexport function startProjectCiRefill(\n intervalMs: number,\n deps: {\n fill?: () => Promise<number>;\n warn?: (message: string) => void;\n setIntervalFn?: typeof setInterval;\n } = {},\n): ReturnType<typeof setInterval> {\n const state = createProjectCiFillState();\n const fill = deps.fill ?? (() => fillAllProjectCi({ state }));\n const warn = deps.warn ?? ((message: string) => console.warn(message));\n let running = false;\n\n const run = (): void => {\n if (running) return;\n running = true;\n void fill()\n .catch((err: unknown) => {\n const message = err instanceof Error ? err.message : String(err);\n warn(`[overdeck] Project CI fill failed: ${message}`);\n })\n .finally(() => {\n running = false;\n });\n };\n\n run();\n const timer = (deps.setIntervalFn ?? setInterval)(run, intervalMs);\n timer.unref();\n return timer;\n}\n","import { startProjectCiRefill } from '../../../lib/overdeck/project-ci-fill.js';\n\nlet resolveProjectionReady!: () => void;\nlet projectionReady = false;\nlet projectionReadyPromise = createProjectionReadyPromise();\n\nfunction createProjectionReadyPromise(): Promise<void> {\n return new Promise<void>((resolve) => {\n resolveProjectionReady = resolve;\n });\n}\n\n/** Mark the event-store → read-model subscription as installed. */\nexport function markEventStoreProjectionReady(): void {\n if (projectionReady) return;\n projectionReady = true;\n resolveProjectionReady();\n}\n\n/** Wait until events appended by background services can reach the read model. */\nexport function whenEventStoreProjectionReady(): Promise<void> {\n return projectionReadyPromise;\n}\n\nexport async function startProjectCiRefillAfterProjectionReady(\n intervalMs: number,\n deps: {\n whenReady?: () => Promise<void>;\n start?: typeof startProjectCiRefill;\n } = {},\n): Promise<ReturnType<typeof setInterval>> {\n await (deps.whenReady ?? whenEventStoreProjectionReady)();\n return (deps.start ?? startProjectCiRefill)(intervalMs);\n}\n\nexport function resetEventStoreProjectionReadyForTests(): void {\n projectionReady = false;\n projectionReadyPromise = createProjectionReadyPromise();\n}\n","/**\n * Domain service wrappers — Effect services over existing lib modules (PAN-428 B5, PAN-433)\n *\n * EventStoreService: wraps the SQLite event store in Effect.\n * SnapshotService was removed in PAN-433 — replaced by ReadModelService (read-model.ts).\n *\n * The EventStoreServiceLive layer also wires event store → read model: every\n * appended event is pushed to ReadModelService.applyEvent() so the in-memory\n * projection stays current.\n */\n\nimport { Effect, Layer, Queue, Context, Stream } from 'effect';\nimport { initEventStore } from '../event-store.js';\nimport type { StoredEvent } from '../event-store.js';\nimport { ReadModelService } from '../read-model.js';\nimport { startSessionContextWriter } from './session-context-writer.js';\nimport { markEventStoreProjectionReady } from './project-ci-refill-startup.js';\nimport { emitActivityDetailedSync } from '../../../lib/activity-logger.js';\nimport { captureCheckpoint, diffCheckpointFiles, isCheckpointTargetDisabled, listCheckpoints } from '../../../lib/checkpoint/checkpoint-manager.js';\nimport { isTerminalTurnDiffSummaryStatus } from '@overdeck/contracts';\nimport { randomUUID } from 'crypto';\n\n// ─── EventStoreService ────────────────────────────────────────────────────────\n\nexport interface EventStoreServiceShape {\n /** Append a domain event; returns the assigned sequence number. */\n readonly append: (event: Record<string, unknown>) => Effect.Effect<number>;\n /** Queue a domain event append without blocking the HTTP/WebSocket hot path. */\n readonly appendAsync: (event: Record<string, unknown>) => Effect.Effect<number>;\n /** Return all stored events with sequence > fromSequence. */\n readonly readFrom: (fromSequence: number) => Effect.Effect<StoredEvent[]>;\n /** Return events of a given type, most recent first, capped at limit. */\n readonly queryByType: (type: string, limit?: number) => Effect.Effect<StoredEvent[]>;\n /** Return the latest sequence number (0 if empty). */\n readonly getLatestSequence: Effect.Effect<number>;\n /** Subscribe to live events as an Effect Stream. */\n readonly streamEvents: Stream.Stream<StoredEvent>;\n}\n\nexport class EventStoreService extends Context.Service<\n EventStoreService,\n EventStoreServiceShape\n>()('overdeck/dashboard/EventStoreService') {}\n\n/** Map a domain event to a detailed activity log entry. Returns null for uninteresting events. */\nfunction shouldRefreshSessionContext(type: string): boolean {\n return type === 'issues.snapshot' || type === 'issues.delta' ||\n type.startsWith('agent.') ||\n type.startsWith('review.') ||\n type.startsWith('pipeline.') ||\n type.startsWith('planning.') ||\n type.startsWith('plan.') ||\n type.startsWith('workspace.') ||\n type.startsWith('issue.') ||\n type.startsWith('memory.') ||\n type.startsWith('cost.') ||\n type.startsWith('merge.') ||\n type.startsWith('system.health_');\n}\n\n/**\n * Resolve the workspace a checkpoint may be captured in, or null when capture\n * must be skipped (PAN-3725).\n *\n * Skipped when the agent has no workspace, when the agent has reached a\n * terminal status (a stopped/done/archived/closed agent produces no new turns,\n * so capturing is pure waste — same rule the read model's checkpoint\n * reconciliation uses), or when the workspace was already found not to be a git\n * repository.\n */\nexport function checkpointCaptureTarget(\n agent: { status?: unknown; workspace?: unknown } | undefined,\n): string | null {\n const workspace = typeof agent?.workspace === 'string' ? agent.workspace : '';\n if (!workspace) return null;\n if (isTerminalTurnDiffSummaryStatus(agent?.status)) return null;\n if (isCheckpointTargetDisabled(workspace)) return null;\n return workspace;\n}\n\nexport function mapDomainEventToDetailed(event: StoredEvent): {\n source: string;\n level: 'info' | 'warn' | 'error' | 'success';\n message: string;\n issueId?: string;\n triggeringEvent: string;\n} | null {\n const p = (event.payload ?? {}) as Record<string, unknown>;\n const issueId = (p['issueId'] as string) ?? undefined;\n\n switch (event.type) {\n case 'agent.created':\n return { source: 'cloister', level: 'info', message: `Agent created for ${p['agentId']}`, issueId, triggeringEvent: event.type };\n case 'agent.started':\n return { source: 'cloister', level: 'info', message: `Agent started: ${p['agentId']}`, issueId, triggeringEvent: event.type };\n case 'agent.stopped':\n return { source: 'cloister', level: 'info', message: `Agent stopped: ${p['agentId']}`, issueId, triggeringEvent: event.type };\n case 'agent.status_changed': {\n const prev = p['previousStatus'] ? ` (was ${p['previousStatus']})` : '';\n return { source: 'cloister', level: 'info', message: `Agent ${p['agentId']} status → ${p['status']}${prev}`, issueId, triggeringEvent: event.type };\n }\n case 'agent.enrichment_changed': {\n const parts: string[] = [];\n if (p['agentPhase']) parts.push(`phase=${p['agentPhase']}`);\n if (p['resolution']) parts.push(`resolution=${p['resolution']}`);\n if (p['hasPendingQuestion']) parts.push(`questions=${p['pendingQuestionCount']}`);\n if (parts.length === 0) return null;\n return { source: 'cloister', level: 'info', message: `Agent ${p['agentId']} enrichment: ${parts.join(', ')}`, issueId, triggeringEvent: event.type };\n }\n case 'planning.started':\n return { source: 'planning', level: 'info', message: `Planning started: ${p['sessionName']}`, issueId, triggeringEvent: event.type };\n case 'planning.failed':\n return { source: 'planning', level: 'error', message: `Planning failed: ${p['error']}`, issueId, triggeringEvent: event.type };\n case 'planning.sync':\n return { source: 'planning', level: 'info', message: `Planning sync: ${p['status']}${p['progress'] !== undefined ? ` (${p['progress']}%)` : ''}`, issueId, triggeringEvent: event.type };\n case 'plan.item_status_changed':\n return { source: 'plan', level: 'info', message: `Plan item ${p['itemId']} → ${p['status']}`, issueId, triggeringEvent: event.type };\n case 'plan.subitem_status_changed':\n return { source: 'plan', level: 'info', message: `Plan sub-item ${p['subItemId']} → ${p['status']}`, issueId, triggeringEvent: event.type };\n case 'plan.items_unblocked': {\n const items = p['items'] as string[] | undefined;\n if (!items || items.length === 0) return null;\n return { source: 'plan', level: 'success', message: `${items.length} plan item(s) unblocked`, issueId, triggeringEvent: event.type };\n }\n case 'pipeline.status_changed':\n return { source: 'pipeline', level: 'info', message: `Pipeline status updated for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'review.status_changed':\n return { source: 'review', level: 'info', message: `Review status updated for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'pipeline.verification-started':\n return { source: 'verification', level: 'info', message: `Verification started for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'pipeline.verification-failed':\n return { source: 'verification', level: 'error', message: `Verification failed for ${issueId}${p['failedCheck'] ? `: ${p['failedCheck']}` : ''}`, issueId, triggeringEvent: event.type };\n case 'pipeline.review-started':\n return { source: 'review', level: 'info', message: `Review specialist started for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'pipeline.review-completed':\n return { source: 'review', level: p['passed'] ? 'success' : 'error', message: `Review ${p['passed'] ? 'passed' : 'failed'} for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'pipeline.test-started':\n return { source: 'test', level: 'info', message: `Test specialist started for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'pipeline.test-completed':\n return { source: 'test', level: p['passed'] ? 'success' : 'error', message: `Tests ${p['passed'] ? 'passed' : 'failed'} for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'specialist.started':\n return { source: 'cloister', level: 'info', message: `Specialist ${p['name'] ?? '?'} started${p['currentIssue'] ? ` for ${p['currentIssue']}` : ''}`, issueId, triggeringEvent: event.type };\n case 'specialist.completed':\n return { source: 'cloister', level: 'success', message: `Specialist ${p['name']} completed`, issueId, triggeringEvent: event.type };\n case 'specialist.failed':\n return { source: 'cloister', level: 'error', message: `Specialist ${p['name']} failed: ${p['error']}`, issueId, triggeringEvent: event.type };\n case 'workspace.created':\n return { source: 'workspace', level: 'info', message: `Workspace created at ${p['workspacePath']}`, issueId, triggeringEvent: event.type };\n case 'workspace.wipe_started':\n return { source: 'workspace', level: 'warn', message: `Deep-wipe started for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'workspace.destroyed':\n return { source: 'workspace', level: 'info', message: `Workspace destroyed for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'workspace.deleted':\n return { source: 'workspace', level: 'info', message: `Workspace deleted for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'workspace.aborted':\n return { source: 'workspace', level: 'warn', message: `Workspace aborted for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'issue.statusChanged':\n return { source: 'tracker', level: 'info', message: `Issue ${p['issueId']} status → ${p['canonicalStatus']}`, issueId: p['issueId'] as string, triggeringEvent: event.type };\n case 'dashboard.lifecycle_started':\n return { source: 'dashboard', level: 'info', message: `Dashboard lifecycle started: ${p['reason']}`, issueId, triggeringEvent: event.type };\n case 'dashboard.lifecycle_completed':\n return { source: 'dashboard', level: 'success', message: `Dashboard lifecycle completed: ${p['reason']}`, issueId, triggeringEvent: event.type };\n case 'dashboard.lifecycle_failed':\n return { source: 'dashboard', level: 'error', message: `Dashboard lifecycle failed: ${p['reason']} — ${p['error']}`, issueId, triggeringEvent: event.type };\n case 'merge.ready':\n return { source: 'ship', level: 'success', message: `Issue ${issueId} ready for merge`, issueId, triggeringEvent: event.type };\n case 'system.health_severity_changed':\n return {\n source: 'system-health',\n level: p['severity'] === 'critical' ? 'error' : p['severity'] === 'warning' ? 'warn' : 'info',\n message: `System health ${p['previousSeverity']} → ${p['severity']}`,\n issueId,\n triggeringEvent: event.type,\n };\n case 'cost.event_recorded': {\n const cost = Number(p['cost']);\n if (Number.isFinite(cost) && cost <= 0) return null;\n return { source: 'costs', level: 'info', message: `Cost event: $${(p['cost'] as number)?.toFixed?.(2) ?? p['cost']} for ${p['agentId']}`, issueId, triggeringEvent: event.type };\n }\n default:\n return null;\n }\n}\n\nexport const EventStoreServiceLive = Layer.effect(\n EventStoreService,\n Effect.gen(function* () {\n const store = yield* Effect.promise(() => initEventStore());\n const readModel = yield* ReadModelService;\n\n // Wire event store → read model: every appended event updates the projection.\n // The EventEmitter subscription is sync, so applyEvent runs inline on append.\n store.subscribe((event) => {\n readModel.applyEvent({\n type: event.type,\n sequence: event.sequence,\n timestamp: event.timestamp,\n payload: event.payload,\n } as any);\n });\n markEventStoreProjectionReady();\n\n startSessionContextWriter({\n readSnapshot: () => Effect.runPromise(readModel.getSnapshot),\n subscribe: (listener) => store.subscribe((event) => {\n if (shouldRefreshSessionContext(event.type)) listener();\n }),\n });\n\n // Auto-emit detailed activity entries for state-change domain events.\n // Skip activity.* events to avoid infinite loops.\n store.subscribe((event) => {\n if (event.type.startsWith('activity.')) return;\n const detailed = mapDomainEventToDetailed(event);\n if (detailed) emitActivityDetailedSync(detailed);\n });\n\n // Capture checkpoints when agent activity changes.\n // Fires async (non-blocking) on every agent.activity_changed event for agents\n // with a workspace. Creates a git checkpoint, computes file changes since the\n // previous checkpoint, and emits agent.turn_diff_completed.\n // Rate-limited to one checkpoint per agent per 10 seconds.\n const checkpointCooldown = new Map<string, number>(); // agentId → last checkpoint timestamp\n store.subscribe((event) => {\n if (event.type !== 'agent.activity_changed') return;\n const p = (event.payload ?? {}) as Record<string, unknown>;\n const agentId = p['agentId'] as string | undefined;\n if (!agentId) return;\n\n // Rate limit: skip if last checkpoint was <10s ago\n const lastCheckpoint = checkpointCooldown.get(agentId) ?? 0;\n if (Date.now() - lastCheckpoint < 10_000) return;\n checkpointCooldown.set(agentId, Date.now());\n\n // Fire-and-forget async checkpoint — don't block the event loop\n (async () => {\n try {\n // Look up agent workspace from read model snapshot\n const snapshot = await Effect.runPromise(readModel.getSnapshot);\n const agent = (snapshot.agents as any[]).find((a: any) => a.id === agentId);\n const workspace = checkpointCaptureTarget(agent);\n if (!workspace) return;\n\n const turnId = `turn-${Date.now()}-${randomUUID().slice(0, 8)}`;\n\n // Capture checkpoint (git tag at current working tree state)\n await Effect.runPromise(captureCheckpoint(workspace, agentId, turnId));\n\n // Compute file changes from previous checkpoint\n const checkpoints = await Effect.runPromise(listCheckpoints(workspace, agentId));\n const prevCheckpoint = checkpoints.length >= 2 ? checkpoints[checkpoints.length - 2] : null;\n let files: Array<{ path: string; kind?: string; additions?: number; deletions?: number }> = [];\n if (prevCheckpoint) {\n files = await Effect.runPromise(diffCheckpointFiles(workspace, agentId, prevCheckpoint, turnId));\n }\n\n // Only emit if there are actual changes\n if (files.length === 0) return;\n\n // Emit turn_diff_completed event\n store.appendAsync({\n type: 'agent.turn_diff_completed',\n timestamp: new Date().toISOString(),\n payload: {\n agentId,\n turnId,\n completedAt: new Date().toISOString(),\n files,\n checkpointRef: `refs/pan/turn/${agentId}/${turnId}`,\n assistantMessageId: undefined,\n checkpointTurnCount: checkpoints.length,\n },\n } as any);\n } catch (err) {\n // Checkpoint capture is best-effort — log but don't crash\n console.error('[checkpoint] Failed to capture checkpoint for', agentId, err);\n }\n })();\n });\n\n // PAN-1635: bridge Claude-native compaction to the conversation \"compacting\"\n // flag. Only the Overdeck-native path emits conversation.compacting_changed\n // directly; a built-in Claude Code /compact is invisible to it. But the\n // PreCompact hook emits activity{tool:\"compact\"} and PostCompact emits\n // activity{idle} for *both* paths, so mirror that signal here. This gives the\n // dashboard a live \"Compacting…\" indicator during Claude's own /compact (and\n // visibly explains a prompt eaten by submit-time compaction). Conversation\n // agentIds (`conv-*`) double as the conversation name.\n const compactingConvs = new Set<string>();\n store.subscribe((event) => {\n if (event.type !== 'agent.activity_changed') return;\n const p = (event.payload ?? {}) as Record<string, unknown>;\n const agentId = p['agentId'] as string | undefined;\n if (!agentId || !agentId.startsWith('conv-')) return;\n const compacting = p['currentTool'] === 'compact';\n if (compacting === compactingConvs.has(agentId)) return;\n if (compacting) compactingConvs.add(agentId);\n else compactingConvs.delete(agentId);\n store.emitOnly({\n type: 'conversation.compacting_changed',\n timestamp: event.timestamp ?? new Date().toISOString(),\n payload: { conversationName: agentId, compacting },\n } as never);\n });\n\n const streamEvents = Stream.callback<StoredEvent>((queue) =>\n Effect.acquireRelease(\n Effect.sync(() =>\n store.subscribe((event) => Queue.offerUnsafe(queue, event)),\n ),\n (unsubscribe) => Effect.sync(unsubscribe),\n ),\n );\n\n return {\n append: (event) => Effect.sync(() => store.append(event as never)),\n appendAsync: (event) => Effect.promise(() => store.appendAsync(event as never)),\n readFrom: (fromSequence) => Effect.sync(() => store.readFrom(fromSequence)),\n queryByType: (type, limit) => Effect.sync(() => store.queryByType(type, limit)),\n getLatestSequence: Effect.sync(() => store.getLatestSequence()),\n streamEvents,\n };\n }),\n);\n","/**\n * IssueLifecycle Effect service (PAN-449)\n *\n * High-level issue state management that dispatches to the correct tracker\n * client (Linear, GitHub, Rally) based on the issue ID prefix.\n *\n * Routes should use IssueLifecycle instead of calling tracker clients directly.\n * The service handles:\n * - State transitions (In Planning, In Progress, In Review, Done)\n * - Label add/remove (GitHub only; no-op for Linear/Rally)\n * - Issue close with label cleanup\n */\n\nimport { Effect, Layer, Option, Context } from 'effect';\nimport { resolveGitHubIssueSync, resolveTrackerTypeSync } from '../../../lib/tracker-utils.js';\nimport { GitHubClient } from './github-client.js';\nimport { GitHubClientOptionalLive } from './github-client.js';\nimport { LinearClient } from './linear-client.js';\nimport { LinearClientOptionalLive } from './linear-client.js';\nimport { RallyClient } from './rally-client.js';\nimport { RallyClientOptionalLive } from './rally-client.js';\nimport type { LinearState } from './linear-client.js';\nimport { TrackerNotConfigured, TrackerApiError, IssueNotFound, RateLimited } from './typed-errors.js';\nimport { EventStoreService } from './domain-services.js';\nimport { getSharedIssueService } from './issue-service-singleton.js';\n\n// ─── Event emission helper ────────────────────────────────────────────────────\n\n/**\n * Attempt to emit a domain event via the shared event store.\n * Non-fatal: silently no-ops if EventStoreService is absent (e.g. in unit tests).\n */\nfunction emitEvent(event: Record<string, unknown>): Effect.Effect<void, never> {\n return Effect.gen(function* () {\n const storeOption = yield* Effect.serviceOption(EventStoreService);\n if (Option.isSome(storeOption)) {\n yield* storeOption.value.append(event);\n }\n });\n}\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type IssueState = 'open' | 'in_planning' | 'in_progress' | 'in_review' | 'verifying_on_main' | 'closed' | 'canceled';\n\n// ─── Service interface ────────────────────────────────────────────────────────\n\nexport interface IssueLifecycleShape {\n /**\n * Transition an issue to a new lifecycle state.\n *\n * For Linear: resolves the Linear state ID from team workflow.\n * For GitHub: adds/removes workflow labels (state change via labels).\n * For Rally: delegates to RallyClient.updateState.\n */\n readonly transitionTo: (\n issueId: string,\n state: IssueState,\n ) => Effect.Effect<\n void,\n TrackerNotConfigured | IssueNotFound | TrackerApiError | RateLimited\n >;\n\n /**\n * Add a label to an issue.\n * GitHub only: creates the label if it doesn't exist, then adds it.\n * Linear / Rally: no-op (trackers don't use workflow labels the same way).\n */\n readonly addLabel: (\n issueId: string,\n label: string,\n ) => Effect.Effect<void, TrackerNotConfigured | TrackerApiError | RateLimited>;\n\n /**\n * Remove a label from an issue.\n * GitHub only; non-fatal if label is not present.\n * Linear / Rally: no-op.\n */\n readonly removeLabel: (\n issueId: string,\n label: string,\n ) => Effect.Effect<void, TrackerNotConfigured | TrackerApiError | RateLimited>;\n\n /**\n * Close an issue and clean up workflow labels.\n *\n * - Transitions issue to 'closed' state.\n * - For GitHub: removes in-progress/in-review/planned labels.\n */\n readonly close: (\n issueId: string,\n ) => Effect.Effect<\n void,\n TrackerNotConfigured | IssueNotFound | TrackerApiError | RateLimited\n >;\n}\n\n// ─── Service tag ──────────────────────────────────────────────────────────────\n\nexport class IssueLifecycle extends Context.Service<IssueLifecycle, IssueLifecycleShape>()(\n 'overdeck/dashboard/IssueLifecycle',\n) {}\n\n// ─── Linear state helpers ─────────────────────────────────────────────────────\n\n/** Map a normalized IssueState to a Linear state type string. */\nfunction linearStateType(state: IssueState): string {\n switch (state) {\n case 'open':\n return 'unstarted';\n case 'in_planning':\n case 'in_progress':\n case 'in_review':\n case 'verifying_on_main':\n return 'started';\n case 'closed':\n return 'completed';\n case 'canceled':\n return 'canceled';\n }\n}\n\n/** Find the best matching Linear state from a list given a target normalized state. */\nfunction findLinearState(states: ReadonlyArray<LinearState>, state: IssueState): LinearState | null {\n if (state === 'in_review' || state === 'verifying_on_main') {\n const names = state === 'verifying_on_main'\n ? ['verifying on main', 'verifying', 'in review']\n : ['in review'];\n const explicit = states.find((s) => names.includes(s.name.toLowerCase()));\n if (explicit) return explicit;\n // Fall back to first \"started\" state\n return states.filter((s) => s.type === 'started')[0] ?? null;\n }\n\n if (state === 'in_planning') {\n // Prefer a state named \"In Planning\" or \"Planning\"\n const explicit = states.find(\n (s) => s.name.toLowerCase() === 'in planning' || s.name.toLowerCase() === 'planning',\n );\n if (explicit) return explicit;\n // Fall back to first \"started\" state\n return states.filter((s) => s.type === 'started')[0] ?? null;\n }\n\n const targetType = linearStateType(state);\n const matching = states.filter((s) => s.type === targetType);\n return matching[0] ?? null;\n}\n\n// ─── GitHub label helpers ─────────────────────────────────────────────────────\n\nconst GITHUB_STATE_LABELS: Record<IssueState, { add: string[]; remove: string[] }> = {\n open: { add: [], remove: ['in-progress', 'in-review', 'planned', 'in-planning', 'review-ready', 'done', 'merged', 'verifying-on-main', 'needs-close-out', 'closed-out', 'wontfix', 'duplicate'] },\n in_planning: { add: ['planned'], remove: ['in-progress', 'in-review', 'review-ready', 'done', 'merged', 'verifying-on-main', 'needs-close-out', 'closed-out', 'wontfix', 'duplicate'] },\n in_progress: { add: ['in-progress'], remove: ['planned', 'in-planning', 'in-review', 'review-ready', 'done', 'merged', 'verifying-on-main', 'needs-close-out', 'closed-out', 'wontfix', 'duplicate'] },\n in_review: { add: ['in-review'], remove: ['in-progress', 'planned', 'in-planning', 'done', 'merged', 'verifying-on-main', 'needs-close-out', 'closed-out', 'wontfix', 'duplicate'] },\n verifying_on_main: { add: ['verifying-on-main'], remove: ['in-progress', 'in-review', 'planned', 'in-planning', 'review-ready', 'ready-for-merge', 'done', 'needs-close-out', 'closed-out', 'wontfix', 'duplicate'] },\n closed: { add: [], remove: ['in-progress', 'in-review', 'planned', 'in-planning', 'review-ready', 'done', 'merged', 'verifying-on-main', 'needs-close-out', 'closed-out', 'wontfix', 'duplicate'] },\n canceled: { add: ['wontfix'], remove: ['in-progress', 'in-review', 'planned', 'in-planning', 'review-ready', 'done', 'merged', 'verifying-on-main', 'needs-close-out', 'closed-out', 'duplicate'] },\n};\n\nconst GITHUB_LABEL_METADATA: Record<string, { color: string; description: string }> = {\n 'planned': { color: 'cfd3d7', description: 'Planning complete' },\n 'in-progress': { color: 'fbca04', description: 'Implementation in progress' },\n 'in-review': { color: 'd4c5f9', description: 'Under review' },\n 'verifying-on-main': { color: 'fbca04', description: 'Merged — awaiting verification on main' },\n 'wontfix': { color: 'ffffff', description: 'Will not be fixed' },\n};\n\nfunction githubLabelMetadata(label: string): { color: string; description: string } {\n return GITHUB_LABEL_METADATA[label] ?? { color: '0075ca', description: '' };\n}\n\n// ─── Live layer implementation ────────────────────────────────────────────────\n\n/** Map IssueState to canonical status string for cache patching. */\nfunction canonicalStatus(state: IssueState): string {\n switch (state) {\n case 'open': return 'open';\n case 'in_planning': return 'in_planning';\n case 'in_progress': return 'in_progress';\n case 'in_review': return 'in_review';\n case 'verifying_on_main': return 'verifying_on_main';\n case 'closed': return 'closed';\n case 'canceled': return 'canceled';\n }\n}\n\nexport const IssueLifecycleLive = Layer.effect(\n IssueLifecycle,\n Effect.gen(function* () {\n const linear = yield* LinearClient;\n const github = yield* GitHubClient;\n const rally = yield* RallyClient;\n\n const impl: IssueLifecycleShape = {\n transitionTo: (issueId, state) =>\n Effect.gen(function* () {\n const trackerType = resolveTrackerTypeSync(issueId);\n\n if (trackerType === 'github') {\n // GitHub state is managed via labels\n const ghInfo = resolveGitHubIssueSync(issueId);\n if (!ghInfo.isGitHub) return;\n const labelOps = GITHUB_STATE_LABELS[state];\n for (const label of labelOps.add) {\n const metadata = githubLabelMetadata(label);\n yield* github.ensureLabel(ghInfo.owner, ghInfo.repo, label, metadata.color, metadata.description);\n yield* github.addLabel(ghInfo.owner, ghInfo.repo, ghInfo.number, label);\n }\n for (const label of labelOps.remove) {\n yield* github.removeLabel(ghInfo.owner, ghInfo.repo, ghInfo.number, label);\n }\n if (state === 'closed' || state === 'canceled') {\n yield* github.closeIssue(ghInfo.owner, ghInfo.repo, ghInfo.number);\n } else {\n // Reopen the issue if it's currently closed (e.g. reopening after incorrect merge)\n yield* github.reopenIssue(ghInfo.owner, ghInfo.repo, ghInfo.number).pipe(\n Effect.catch(() => Effect.void) // Non-fatal if already open\n );\n }\n } else if (trackerType === 'rally') {\n const normalizedState =\n state === 'in_planning' || state === 'open' ? 'open'\n : state === 'in_progress' || state === 'in_review' || state === 'verifying_on_main' ? 'in_progress'\n : 'closed';\n yield* rally.updateState(issueId, normalizedState);\n } else {\n // Linear\n const issue = yield* linear.getIssue(issueId);\n const states = yield* linear.getTeamStates(issue.team.id);\n const target = findLinearState(states, state);\n // No-op if the issue is already in the target state\n if (target && issue.state?.id !== target.id) {\n yield* linear.updateState(issue.id, target.id);\n }\n }\n\n // Patch the in-memory cache and emit a domain event (non-fatal)\n yield* Effect.try({ try: () => getSharedIssueService().patchIssue(issueId, { canonicalStatus: canonicalStatus(state) }), catch: () => void 0 }).pipe(Effect.ignore);\n yield* emitEvent({\n type: 'issue.transitioned',\n timestamp: new Date().toISOString(),\n payload: { issueId, state },\n });\n }),\n\n addLabel: (issueId, label) =>\n Effect.gen(function* () {\n const trackerType = resolveTrackerTypeSync(issueId);\n if (trackerType !== 'github') return; // no-op for Linear/Rally\n\n const ghInfo = resolveGitHubIssueSync(issueId);\n if (!ghInfo.isGitHub) return;\n yield* github.addLabel(ghInfo.owner, ghInfo.repo, ghInfo.number, label);\n }),\n\n removeLabel: (issueId, label) =>\n Effect.gen(function* () {\n const trackerType = resolveTrackerTypeSync(issueId);\n if (trackerType !== 'github') return; // no-op for Linear/Rally\n\n const ghInfo = resolveGitHubIssueSync(issueId);\n if (!ghInfo.isGitHub) return;\n yield* github.removeLabel(ghInfo.owner, ghInfo.repo, ghInfo.number, label);\n }),\n\n close: (issueId) =>\n Effect.gen(function* () {\n const trackerType = resolveTrackerTypeSync(issueId);\n\n if (trackerType === 'github') {\n const ghInfo = resolveGitHubIssueSync(issueId);\n if (!ghInfo.isGitHub) return;\n // Remove workflow labels then close\n for (const label of ['in-progress', 'in-review', 'planned', 'in-planning', 'verifying-on-main', 'ready-for-merge']) {\n yield* github.removeLabel(ghInfo.owner, ghInfo.repo, ghInfo.number, label);\n }\n yield* github.closeIssue(ghInfo.owner, ghInfo.repo, ghInfo.number);\n } else if (trackerType === 'rally') {\n yield* rally.updateState(issueId, 'closed');\n } else {\n // Linear\n const issue = yield* linear.getIssue(issueId);\n const states = yield* linear.getTeamStates(issue.team.id);\n const target = findLinearState(states, 'closed');\n if (target) {\n yield* linear.updateState(issue.id, target.id);\n }\n }\n\n // Patch the in-memory cache and emit issue.closed domain event (non-fatal)\n yield* Effect.try({ try: () => getSharedIssueService().patchIssue(issueId, { canonicalStatus: 'closed' }), catch: () => void 0 }).pipe(Effect.ignore);\n yield* emitEvent({\n type: 'issue.closed',\n timestamp: new Date().toISOString(),\n payload: { issueId },\n });\n }),\n };\n\n return impl;\n }),\n);\n\n/**\n * Convenience layer that wires all tracker client dependencies.\n * Use this to provide IssueLifecycle without manually composing layers.\n */\nexport const IssueLifecycleWithClientLive = IssueLifecycleLive.pipe(\n Layer.provide(LinearClientOptionalLive),\n Layer.provide(GitHubClientOptionalLive),\n Layer.provide(RallyClientOptionalLive),\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"issue-lifecycle-1B_v8Rf5.js","names":["applyEvent","applyEventReducer","resolve","basename","join","dirname","readFile","stat"],"sources":["../../src/lib/queue-position.ts","../../src/dashboard/server/read-model.ts","../../src/lib/briefing-assembler.ts","../../src/dashboard/server/services/session-context-writer.ts","../../src/lib/ci/project-ci-github.ts","../../src/lib/overdeck/project-ci-fill.ts","../../src/dashboard/server/services/project-ci-refill-startup.ts","../../src/dashboard/server/services/domain-services.ts","../../src/dashboard/server/services/issue-lifecycle.ts"],"sourcesContent":["/**\n * Queue position utilities for the specialist pipeline (PAN-366).\n *\n * These pure helpers are extracted from the review-status API handler so they\n * can be unit-tested independently of the Express server.\n */\n\nimport { Effect } from 'effect';\nimport type { ReviewStatus } from './review-status.js';\nimport type { HookItem } from './hooks.js';\n\n/** Sentinel value meaning the specialist is actively processing this issue now. */\nexport const SPECIALIST_ACTIVE_POSITION = 0;\n\nexport interface QueuePositionResult {\n /** null = not queued; 0 = actively processing; 1+ = position in queue */\n queuePosition: number | null;\n /** Which specialist is handling (or will handle) this issue */\n activeSpecialist: 'review' | 'test' | 'merge' | null;\n}\n\n/**\n * Derive queue position from the persisted review status fields alone.\n * Returns {0, specialist} when the status indicates active processing,\n * or {null, null} when no active phase is detected (caller must check queues).\n */\nexport function computeQueuePositionFromStatusSync(\n status: Pick<ReviewStatus, 'reviewStatus' | 'testStatus' | 'mergeStatus'> | null\n): QueuePositionResult {\n if (status?.reviewStatus === 'reviewing') {\n return { queuePosition: SPECIALIST_ACTIVE_POSITION, activeSpecialist: 'review' };\n }\n if (status?.testStatus === 'testing') {\n return { queuePosition: SPECIALIST_ACTIVE_POSITION, activeSpecialist: 'test' };\n }\n if (status?.mergeStatus === 'merging') {\n return { queuePosition: SPECIALIST_ACTIVE_POSITION, activeSpecialist: 'merge' };\n }\n return { queuePosition: null, activeSpecialist: null };\n}\n\n/**\n * Find this issueId's 1-based position in a specialist's pending queue.\n * Returns -1 if not found (caller interprets as \"not queued\").\n */\nexport function findPositionInQueueSync(issueId: string, items: HookItem[]): number {\n const upper = issueId.toUpperCase();\n const idx = items.findIndex(\n (item) => item.payload?.issueId?.toUpperCase() === upper\n );\n return idx >= 0 ? idx + 1 : -1;\n}\n\n// ─── Effect variants (PAN-1249) ───────────────────────────────────────────────\n\n/** Effect variant of {@link computeQueuePositionFromStatusSync}. Pure; cannot fail. */\nexport const computeQueuePositionFromStatus = (\n status: Pick<ReviewStatus, 'reviewStatus' | 'testStatus' | 'mergeStatus'> | null,\n): Effect.Effect<QueuePositionResult, never> =>\n Effect.sync(() => computeQueuePositionFromStatusSync(status));\n\n/** Effect variant of {@link findPositionInQueueSync}. Pure; cannot fail. */\nexport const findPositionInQueue = (\n issueId: string,\n items: HookItem[],\n): Effect.Effect<number, never> =>\n Effect.sync(() => findPositionInQueueSync(issueId, items));\n","/**\n * Server-side Read Model — clean data architecture (PAN-433)\n *\n * Holds an in-memory projection of the dashboard state, bootstrapped once from\n * existing lib modules (JSON-cleaned), then maintained incrementally by domain\n * events via the shared applyEvent reducer.\n *\n * getSnapshot() returns the read model directly — no lib calls, no dirty data,\n * no Schema crashes. This is the T3Code pattern.\n */\n\nimport { Effect, Layer, Context } from 'effect';\nimport type { DashboardSnapshot, DomainEvent, TurnDiffSummary } from '@overdeck/contracts';\nimport {\n type ReadModelState,\n INITIAL_READ_MODEL_STATE,\n applyEvent as applyEventReducer,\n createIssueDelta,\n getMaxTurnDiffSummariesPerAgent,\n isTerminalTurnDiffSummaryStatus,\n trimTurnDiffSummaries,\n} from '@overdeck/contracts';\nimport type { AgentSnapshot, AgentStatus, Role, AgentResolution, ReviewStatusSnapshot, ReviewStatusValue, TestStatusValue, UatStatusValue, MergeStatusValue, VerificationStatusValue } from '@overdeck/contracts';\nimport type { ReviewStatus } from '../../lib/review-status.js';\nimport { listOverdeckAgentStatesSync } from '../../lib/overdeck/agent-state-sync.js';\nimport { computeQueuePositionFromStatusSync } from '../../lib/queue-position.js'\nimport { AgentsResolver, type Agent as OverdeckAgent } from '../../lib/overdeck/agents.js';\nimport { emitBootReconciledStopEvents } from './services/boot-reconciled-stop-events.js';\n\n// ─── Exported async helpers (used by bootstrap Effect + tests) ───────────────\n\nconst MAX_SNAPSHOT_ACTIVITY_ENTRIES = 50;\n\ntype DashboardSnapshotWithActivity = DashboardSnapshot & {\n recentActivity?: unknown[];\n};\n\nexport function activityEntriesFromStoredEvents(\n events: ReadonlyArray<{ timestamp: string; payload: unknown }>,\n limit = MAX_SNAPSHOT_ACTIVITY_ENTRIES,\n): unknown[] {\n const entries: Record<string, unknown>[] = [];\n for (const event of events) {\n const entry = event.payload && typeof event.payload === 'object'\n ? event.payload as Record<string, unknown>\n : {};\n const previousIndex = entries.findIndex(candidate => candidate.id === entry.id);\n const previous = previousIndex >= 0 ? entries[previousIndex] : undefined;\n if (previousIndex >= 0) entries.splice(previousIndex, 1);\n entries.unshift({ ...previous, id: entry.id, timestamp: event.timestamp, ...entry });\n }\n return entries.slice(0, limit);\n}\n\n\n// PAN-1510: bootstrap previously only seeded `issuesRaw` from the projection\n// cache or replaced it wholesale from `issueService.getIssues()`. Both paths\n// missed issues filed during the previous dashboard's poll-write window — the\n// projection cache flush is debounced at 2s, so a fresh `cache.set('github',\n// 'issues', ...)` in IssueDataService can survive a restart while the\n// projection cache entry remains stale. The helpers below mirror PAN-1506's\n// `discoverNewAgentIds`/merge pattern for issues.\n\nexport function getIssueIdentifierKey(issue: unknown): string | null {\n if (!issue || typeof issue !== 'object') return null;\n const item = issue as { identifier?: unknown; id?: unknown };\n if (typeof item.identifier === 'string' && item.identifier.length > 0) {\n return item.identifier.toLowerCase();\n }\n if (typeof item.id === 'string' && item.id.length > 0) {\n return item.id.toLowerCase();\n }\n return null;\n}\n\nexport function discoverNewIssues(\n cachedIssues: unknown[],\n currentIssues: unknown[],\n): unknown[] {\n const cachedIds = new Set<string>();\n for (const issue of cachedIssues) {\n const id = getIssueIdentifierKey(issue);\n if (id !== null) cachedIds.add(id);\n }\n const newIssues: unknown[] = [];\n for (const issue of currentIssues) {\n const id = getIssueIdentifierKey(issue);\n if (id !== null && !cachedIds.has(id)) newIssues.push(issue);\n }\n return newIssues;\n}\n\nexport function mergeIssuesByIdentifier(\n cachedIssues: unknown[],\n currentIssues: unknown[],\n): unknown[] {\n const merged = new Map<string, unknown>();\n const unidentified: unknown[] = [];\n for (const issue of cachedIssues) {\n const id = getIssueIdentifierKey(issue);\n if (id !== null) merged.set(id, issue);\n else unidentified.push(issue);\n }\n for (const issue of currentIssues) {\n const id = getIssueIdentifierKey(issue);\n if (id !== null) merged.set(id, issue);\n }\n return [...unidentified, ...merged.values()];\n}\n\nexport function shouldSkipCheckpointReconciliation(agent: Pick<AgentSnapshot, 'status' | 'workspace'>): boolean {\n return !agent.workspace || isTerminalTurnDiffSummaryStatus(agent.status)\n}\n\ntype IssueReadSourceState = {\n identifier?: unknown;\n id?: unknown;\n status?: unknown;\n state?: unknown;\n canonicalStatus?: unknown;\n rawTrackerState?: unknown;\n completedAt?: unknown;\n}\n\nfunction normalizeIssueId(value: unknown): string | null {\n if (typeof value !== 'string') return null;\n const trimmed = value.trim();\n return trimmed ? trimmed.toUpperCase() : null;\n}\n\nexport function getClosedIssueIdsForReadSource(issues: unknown[]): Set<string> {\n const closed = new Set<string>();\n for (const issue of issues) {\n if (!issue || typeof issue !== 'object') continue;\n const item = issue as IssueReadSourceState;\n const issueId = normalizeIssueId(item.identifier) ?? normalizeIssueId(item.id);\n if (!issueId) continue;\n const state = String(item.state ?? '').toLowerCase();\n const status = String(item.status ?? '').toLowerCase();\n const canonicalStatus = String(item.canonicalStatus ?? '').toLowerCase();\n const rawTrackerState = String(item.rawTrackerState ?? '').toLowerCase();\n if (\n item.completedAt ||\n state === 'closed' ||\n status === 'done' ||\n status === 'closed' ||\n status === 'cancelled' ||\n status === 'canceled' ||\n status === 'completed' ||\n canonicalStatus === 'done' ||\n canonicalStatus === 'closed' ||\n canonicalStatus === 'cancelled' ||\n canonicalStatus === 'canceled' ||\n canonicalStatus === 'completed' ||\n rawTrackerState === 'closed' ||\n rawTrackerState === 'done' ||\n rawTrackerState === 'completed'\n ) {\n closed.add(issueId);\n }\n }\n return closed;\n}\n\nexport function pruneAgentsForReadSource(\n agentsById: Record<string, AgentSnapshot>,\n issues: unknown[],\n): { agentsById: Record<string, AgentSnapshot>; prunedCount: number } {\n const closedIssueIds = getClosedIssueIdsForReadSource(issues);\n // PAN-1908: authoritative membership is the SQLite agents table, not state.json.\n const liveAgentIds = new Set(listOverdeckAgentStatesSync().map(a => a.id));\n const nextAgentsById: Record<string, AgentSnapshot> = {};\n let prunedCount = 0;\n\n for (const agent of Object.values(agentsById)) {\n if (closedIssueIds.has(agent.issueId.toUpperCase())) {\n prunedCount++;\n continue;\n }\n if (!liveAgentIds.has(agent.id)) {\n prunedCount++;\n continue;\n }\n nextAgentsById[agent.id] = agent;\n }\n\n return { agentsById: nextAgentsById, prunedCount };\n}\n\n/**\n * Prunes review-status entries for closed issues on every snapshot request —\n * not just at boot (review finding, PAN-3362 UAT cycle 3). mergeDbOnlyReviewStatuses()\n * can hydrate a review_status row for an issue reconstructCacheAuto() never\n * covered (e.g. the FIX-1 UAT fixture, which has no per-issue record). If\n * that issue is later closed, close-out deletes the DB row but emits no\n * read-model removal event, so the in-memory snapshot would otherwise keep\n * showing it as reviewing/ready-to-merge indefinitely. Reusing\n * getClosedIssueIdsForReadSource() here — the same live, per-request signal\n * pruneAgentsForReadSource() already uses — means a mid-session close is\n * caught on the very next snapshot, not only after a restart.\n */\nexport function pruneReviewStatusesForReadSource(\n reviewStatusByIssueId: Record<string, ReviewStatusSnapshot>,\n issues: unknown[],\n): { reviewStatusByIssueId: Record<string, ReviewStatusSnapshot>; prunedCount: number } {\n const closedIssueIds = getClosedIssueIdsForReadSource(issues);\n const nextReviewStatusByIssueId: Record<string, ReviewStatusSnapshot> = {};\n let prunedCount = 0;\n\n for (const [issueId, status] of Object.entries(reviewStatusByIssueId)) {\n if (closedIssueIds.has(issueId.toUpperCase())) {\n prunedCount++;\n continue;\n }\n nextReviewStatusByIssueId[issueId] = status;\n }\n\n return { reviewStatusByIssueId: nextReviewStatusByIssueId, prunedCount };\n}\n\n// ─── Cached event store reference (avoids async dynamic import on each pushUpdated) ──\nlet _cachedEventStore: any = null;\n\ntype Jsonish = null | boolean | number | string | Jsonish[] | { [key: string]: Jsonish };\n\nfunction toJsonish(value: unknown, seen = new WeakSet<object>()): Jsonish | undefined {\n if (value == null) return null;\n if (typeof value === 'string' || typeof value === 'boolean') return value;\n if (typeof value === 'number') return Number.isFinite(value) ? value : null;\n if (value instanceof Date) return value.toISOString();\n if (Array.isArray(value)) {\n const next: Jsonish[] = [];\n for (const item of value) {\n const clean = toJsonish(item, seen);\n if (clean !== undefined) next.push(clean);\n }\n return next;\n }\n if (typeof value === 'object') {\n if (seen.has(value)) return null;\n seen.add(value);\n const next: { [key: string]: Jsonish } = {};\n for (const [key, item] of Object.entries(value as Record<string, unknown>)) {\n const clean = toJsonish(item, seen);\n if (clean !== undefined) next[key] = clean;\n }\n seen.delete(value);\n return next;\n }\n return undefined;\n}\n\nfunction cleanIssues(issues: unknown[]): unknown[] {\n return issues.map((issue) => toJsonish(issue) ?? null);\n}\n\n// ─── Value validators for strict literal types ──────────────────────────────\n\nconst VALID_AGENT_STATUSES = new Set<AgentStatus>([\"starting\", \"running\", \"stopped\", \"error\", \"unknown\"]);\nconst VALID_ROLES = new Set<Role>([\"plan\", \"work\", \"review\", \"test\", \"ship\", \"flywheel\", \"strike\", \"sequencer\", \"knowledge\"]);\nconst VALID_RESOLUTIONS = new Set<AgentResolution>([\"working\", \"done\", \"needs_input\", \"stuck\", \"completed\", \"unclear\", \"abandoned\", \"api_error\"]);\ntype SpecialistAgentName = 'review-agent' | 'test-agent' | 'merge-agent' | 'inspect-agent' | 'uat-agent';\ntype SpecialistLifecycleState = 'active' | 'sleeping' | 'uninitialized';\n\nconst VALID_SPECIALIST_NAMES = new Set<SpecialistAgentName>([\"review-agent\", \"test-agent\", \"merge-agent\", \"inspect-agent\", \"uat-agent\"]);\nconst VALID_SPECIALIST_LIFECYCLE_STATES = new Set<SpecialistLifecycleState>([\"active\", \"sleeping\", \"uninitialized\"]);\nconst VALID_REVIEW_STATUSES = new Set<ReviewStatusValue>([\"pending\", \"reviewing\", \"passed\", \"failed\", \"blocked\", \"skipped\"]);\nconst VALID_TEST_STATUSES = new Set<TestStatusValue>([\"pending\", \"testing\", \"passed\", \"failed\", \"skipped\", \"dispatch_failed\"]);\nconst VALID_UAT_STATUSES = new Set<UatStatusValue>([\"pending\", \"testing\", \"passed\", \"failed\"]);\nconst VALID_MERGE_STATUSES = new Set<MergeStatusValue>([\"pending\", \"queued\", \"merging\", \"verifying\", \"merged\", \"failed\"]);\nconst VALID_VERIFICATION_STATUSES = new Set<VerificationStatusValue>([\"pending\", \"running\", \"passed\", \"failed\", \"skipped\"]);\n\nexport function toAgentStatus(v: unknown): AgentStatus {\n return VALID_AGENT_STATUSES.has(v as AgentStatus) ? v as AgentStatus : \"unknown\";\n}\n\nexport function toRole(v: unknown): Role | undefined {\n return v && VALID_ROLES.has(v as Role) ? v as Role : undefined;\n}\n\nexport function toAgentResolution(v: unknown): AgentResolution | undefined {\n return v && VALID_RESOLUTIONS.has(v as AgentResolution) ? v as AgentResolution : undefined;\n}\nexport function toSpecialistAgentName(v: unknown): SpecialistAgentName | undefined {\n return VALID_SPECIALIST_NAMES.has(v as SpecialistAgentName) ? v as SpecialistAgentName : undefined;\n}\nexport function toSpecialistLifecycleState(v: unknown): SpecialistLifecycleState {\n return VALID_SPECIALIST_LIFECYCLE_STATES.has(v as SpecialistLifecycleState) ? v as SpecialistLifecycleState : \"uninitialized\";\n}\nexport function toReviewStatus(v: unknown): ReviewStatusValue | undefined {\n return v && VALID_REVIEW_STATUSES.has(v as ReviewStatusValue) ? v as ReviewStatusValue : undefined;\n}\nexport function toTestStatus(v: unknown): TestStatusValue | undefined {\n return v && VALID_TEST_STATUSES.has(v as TestStatusValue) ? v as TestStatusValue : undefined;\n}\nexport function toUatStatus(v: unknown): UatStatusValue | undefined {\n return v && VALID_UAT_STATUSES.has(v as UatStatusValue) ? v as UatStatusValue : undefined;\n}\nexport function toMergeStatus(v: unknown): MergeStatusValue | undefined {\n return v && VALID_MERGE_STATUSES.has(v as MergeStatusValue) ? v as MergeStatusValue : undefined;\n}\nexport function toVerificationStatus(v: unknown): VerificationStatusValue | undefined {\n return v && VALID_VERIFICATION_STATUSES.has(v as VerificationStatusValue) ? v as VerificationStatusValue : undefined;\n}\n\nexport type ReviewStatusSnapshotInput = ReviewStatus & {\n reviewCoordinatorSessionName?: string;\n reviewSessionNames?: string[];\n reviewSubStatuses?: Record<string, 'running' | 'done'>;\n activeSpecialist?: string;\n};\n\nexport function toReviewStatusSnapshot(status: ReviewStatusSnapshotInput): ReviewStatusSnapshot {\n return {\n issueId: status.issueId,\n reviewStatus: toReviewStatus(status.reviewStatus),\n testStatus: toTestStatus(status.testStatus),\n uatStatus: toUatStatus(status.uatStatus),\n uatNotes: status.uatNotes || undefined,\n mergeStatus: toMergeStatus(status.mergeStatus),\n releaseStatus: status.releaseStatus ?? undefined,\n releaseNotes: status.releaseNotes || undefined,\n verificationStatus: toVerificationStatus(status.verificationStatus),\n verificationNotes: status.verificationNotes || undefined,\n verificationCycleCount: typeof status.verificationCycleCount === 'number' ? status.verificationCycleCount : undefined,\n readyForMerge: !!status.readyForMerge,\n updatedAt: status.updatedAt,\n prUrl: status.prUrl || undefined,\n stuck: !!status.stuck ? true : undefined,\n stuckReason: status.stuckReason || undefined,\n stuckAt: status.stuckAt || undefined,\n stuckDetails: status.stuckDetails || undefined,\n reviewCycleHistory: status.reviewCycleHistory && status.reviewCycleHistory.length > 0\n ? status.reviewCycleHistory\n : undefined,\n reviewedAtCommit: status.reviewedAtCommit || undefined,\n reviewSpawnedAt: typeof status.reviewSpawnedAt === 'number'\n ? new Date(status.reviewSpawnedAt).toISOString()\n : status.reviewSpawnedAt || undefined,\n testRetryCount: typeof status.testRetryCount === 'number' ? status.testRetryCount : undefined,\n reviewRetryCount: typeof status.reviewRetryCount === 'number' ? status.reviewRetryCount : undefined,\n recoveryStartedAt: status.recoveryStartedAt || undefined,\n deaconIgnored: !!status.deaconIgnored ? true : undefined,\n deaconIgnoredAt: status.deaconIgnoredAt || undefined,\n deaconIgnoredReason: status.deaconIgnoredReason || undefined,\n // PAN-1691: tri-state routing key — preserve true/false/undefined as-is.\n autoMerge: status.autoMerge,\n reviewCoordinatorSessionName: status.reviewCoordinatorSessionName || undefined,\n reviewSessionNames: status.reviewSessionNames && status.reviewSessionNames.length > 0 ? status.reviewSessionNames : undefined,\n reviewSubStatuses: status.reviewSubStatuses,\n queuePosition: computeQueuePositionFromStatusSync(status).queuePosition ?? undefined,\n activeSpecialist: status.activeSpecialist || undefined,\n mergeRetryCount: typeof status.mergeRetryCount === 'number' ? status.mergeRetryCount : undefined,\n mergeNotes: status.mergeNotes || undefined,\n blockerReasons: status.blockerReasons && status.blockerReasons.length > 0 ? status.blockerReasons : undefined,\n autoRequeueCount: typeof status.autoRequeueCount === 'number' ? status.autoRequeueCount : undefined,\n };\n}\n\n/**\n * Layers DB-only review_status rows into a boot snapshot for issues\n * reconstructCacheAuto() didn't already cover (PAN-3362).\n *\n * reconstructCacheAuto() deliberately enumerates only tracker-backed\n * in-flight issues (it reads NO SQLite cache tables — sources of truth\n * only), so an issue with a review_status row but no real per-issue record\n * (e.g. the obviously-fake FIX-1 UAT fixture) is never included in\n * `trackerDerived`. This is a supplementary, additive source — a DB-only\n * row NEVER overrides a tracker-derived entry for the same issueId, the\n * same posture agentsById already takes by layering AgentsResolver's\n * DB-backed list alongside reconstructCacheAuto's result rather than\n * folding it in.\n */\nexport function mergeDbOnlyReviewStatuses(\n trackerDerived: Record<string, ReviewStatusSnapshot>,\n dbReviewStatuses: Record<string, ReviewStatusSnapshotInput>,\n): Record<string, ReviewStatusSnapshot> {\n const dbOnly: Record<string, ReviewStatusSnapshot> = {};\n for (const [issueId, dbStatus] of Object.entries(dbReviewStatuses)) {\n if (!(issueId in trackerDerived)) {\n dbOnly[issueId] = toReviewStatusSnapshot(dbStatus);\n }\n }\n return dbOnly;\n}\n\n// ─── ReadModelService ────────────────────────────────────────────────────────\n\nexport interface ReadModelServiceShape {\n /** Return the current read model state as a DashboardSnapshot. */\n readonly getSnapshot: Effect.Effect<DashboardSnapshotWithActivity>;\n /** Return a single pending channel permission request without rebuilding a full snapshot. */\n readonly getChannelPermissionRequest: (\n requestId: string,\n ) => Effect.Effect<import('@overdeck/contracts').ChannelPermissionRequestSnapshot | null>;\n /** Return a recent resolved channel permission decision for safe delivery retries. */\n readonly getResolvedChannelPermissionDecision: (\n requestId: string,\n ) => Effect.Effect<import('@overdeck/contracts').ResolvedChannelPermissionDecision | null>;\n /** Return in-memory turn diff summaries for a single agent. */\n readonly getTurnDiffSummaries: (agentId: string) => Effect.Effect<TurnDiffSummary[]>;\n /** Return the agentId for a given sessionId (from agent snapshot or runtime claudeSessionId). */\n readonly getAgentIdBySessionId: (sessionId: string) => Effect.Effect<string | null>;\n /** Apply a domain event to the read model (called by event store on append). */\n readonly applyEvent: (event: DomainEvent) => void;\n /** Bootstrap the read model from existing lib module state. */\n readonly bootstrap: Effect.Effect<void>;\n}\n\n// ─── Overdeck → legacy AgentSnapshot adapter ─────────────────────────────────\n//\n// Maps overdeck's 18-field Agent (durable config only) to the legacy\n// AgentSnapshot wire format. Runtime/ephemeral fields (lastActivity, branch,\n// costSoFar, phase, hasPendingQuestion, etc.) start undefined and are filled\n// by in-memory events from the enrichment poller and domain event stream.\n\nfunction overdeckStatusToLegacy(\n status: OverdeckAgent['status'],\n): AgentStatus {\n if (status === 'crashed') return 'error';\n // 'idle'/'waiting' = agent is alive but waiting (tool-call paused, AUQ, etc.)\n if (status === 'idle' || status === 'waiting') return 'running';\n return status; // 'starting' | 'running' | 'stopped' are 1:1\n}\n\nfunction agentSnapshotFromOverdeck(agent: OverdeckAgent): AgentSnapshot {\n return {\n id: agent.id,\n issueId: agent.issueId,\n workspace: agent.workspace || undefined,\n runtime: agent.harness,\n model: agent.model,\n status: overdeckStatusToLegacy(agent.status),\n startedAt: agent.startedAt?.toISOString(),\n sessionId: agent.sessionId ?? undefined,\n role: agent.role,\n stoppedByUser: agent.stoppedByUser ?? undefined,\n paused: agent.paused ?? undefined,\n pausedReason: agent.pausedReason ?? undefined,\n troubled: agent.troubled ?? undefined,\n consecutiveFailures: agent.consecutiveFailures,\n firstFailureInRunAt: agent.firstFailureInRunAt?.toISOString(),\n lastFailureNextRetryAt: agent.lastFailureNextRetryAt?.toISOString(),\n };\n}\n\nexport class ReadModelService extends Context.Service<\n ReadModelService,\n ReadModelServiceShape\n>()('overdeck/dashboard/ReadModelService') {}\n\n// ─── Live implementation ─────────────────────────────────────────────────────\n\nexport const ReadModelServiceLive = Layer.effect(\n ReadModelService,\n Effect.gen(function* () {\n let state: ReadModelState = { ...INITIAL_READ_MODEL_STATE };\n\n function cloneTurnDiffSummaries(summaries: TurnDiffSummary[] | undefined): TurnDiffSummary[] {\n if (!summaries || summaries.length === 0) return [];\n return summaries.map(summary => ({\n ...summary,\n files: summary.files.map(file => ({ ...file })),\n assistantMessageId: summary.assistantMessageId ?? undefined,\n checkpointRef: summary.checkpointRef ?? undefined,\n }));\n }\n\n function buildSnapshot(): DashboardSnapshotWithActivity {\n // turnDiffSummariesByAgentId is intentionally excluded from the snapshot.\n //\n // Per-agent checkpoint history can grow to thousands of turns × hundreds\n // of files; in production we measured 484 MB across 44 agents, which the\n // browser's WebSocket client rejects as \"Max payload size exceeded\" and\n // closes the socket with code 1006 — leaving the kanban and command deck\n // perpetually empty. The data is still maintained in `state` and served\n // on-demand via GET /api/agents/:id/diffs, so chat-timeline components\n // fetch it only for the agent the user is actually viewing.\n return {\n sequence: state.sequence,\n agents: Object.values(state.agentsById),\n // PAN-1048 — specialistsByName projection retired. The DashboardSnapshot\n // schema still has a `specialists` field for backward compat with the\n // wire format; we always send an empty array and clients derive the\n // same data from agentsById filtered by role.\n specialists: [],\n reviewStatuses: Object.values(state.reviewStatusByIssueId),\n agentRuntimeById: state.agentRuntimeById,\n channelPermissionRequests: Object.values(state.channelPermissionRequestsById ?? {}),\n issues: state.issuesRaw,\n recentActivity: state.recentActivity,\n resources: state.resources ?? undefined,\n memory: {\n observationsByIssueId: state.observationsByIssueId,\n statusByIssueId: state.statusByIssueId,\n rollupsByIssueId: state.rollupsByIssueId,\n resetMarkersByScopeId: state.resetMarkersByScopeId,\n healthByIssueId: state.healthByIssueId,\n },\n scanProgress: state.scanProgress,\n enrichStats: state.enrichStats,\n enrichProgressBySessionId: state.enrichProgressBySessionId,\n embedProgressBySessionId: state.embedProgressBySessionId,\n ciByProjectKey: state.ciByProjectKey,\n // PAN-3729: the restart-approval banner reads the gate from the\n // snapshot on connect and from restart_gate.changed events after that\n // — the frontend never polls the gate endpoints.\n restartGate: state.restartGate ?? undefined,\n timestamp: new Date().toISOString(),\n };\n }\n\n const applyEvent = (event: DomainEvent): void => {\n state = applyEventReducer(state, event);\n };\n\n const getSnapshot: Effect.Effect<DashboardSnapshotWithActivity> = Effect.gen(function* () {\n // Refresh issues from the shared issue service before building snapshot.\n // IssueDataService polls trackers in the background; its cached issues are\n // the freshest available without blocking on API calls.\n //\n // PAN-1510: merge issueService's view with the current state.issuesRaw\n // so a hard browser reload always reflects the union of (projection\n // cache + freshest issueService data). issueService entries win on\n // identifier conflicts (fresher status, labels, etc.), and cached\n // entries that issueService is missing (transient empty fetch,\n // partial poll, single-tracker failure) are preserved instead of\n // dropped. Identifier-based merge is the same shape PAN-1506 used to\n // surface newly-spawned agents through the bootstrap fast-path.\n try {\n const { getSharedIssueService } = yield* Effect.promise(\n () => import('./services/issue-service-singleton.js'),\n );\n const issueService = getSharedIssueService();\n const currentIssues = cleanIssues(issueService.getIssues());\n if (currentIssues.length > 0 || state.issuesRaw.length === 0) {\n state = {\n ...state,\n issuesRaw: mergeIssuesByIdentifier(state.issuesRaw, currentIssues),\n };\n }\n } catch (err) {\n console.error('[ReadModel] Failed to refresh issues for snapshot:', err);\n }\n\n const pruned = pruneAgentsForReadSource(state.agentsById, state.issuesRaw);\n if (pruned.prunedCount > 0) {\n state = { ...state, agentsById: pruned.agentsById };\n console.log(`[ReadModel] Pruned ${pruned.prunedCount} stale agent${pruned.prunedCount === 1 ? '' : 's'} from read source`);\n }\n\n const prunedReviewStatuses = pruneReviewStatusesForReadSource(state.reviewStatusByIssueId, state.issuesRaw);\n if (prunedReviewStatuses.prunedCount > 0) {\n state = { ...state, reviewStatusByIssueId: prunedReviewStatuses.reviewStatusByIssueId };\n console.log(`[ReadModel] Pruned ${prunedReviewStatuses.prunedCount} stale review status${prunedReviewStatuses.prunedCount === 1 ? '' : 'es'} from read source`);\n }\n\n return buildSnapshot();\n });\n\n const getChannelPermissionRequest = (\n requestId: string,\n ): Effect.Effect<import('@overdeck/contracts').ChannelPermissionRequestSnapshot | null> =>\n Effect.succeed(state.channelPermissionRequestsById?.[requestId] ?? null);\n\n const getResolvedChannelPermissionDecision = (\n requestId: string,\n ): Effect.Effect<import('@overdeck/contracts').ResolvedChannelPermissionDecision | null> =>\n Effect.succeed(state.resolvedChannelPermissionDecisionsById?.[requestId] ?? null);\n\n const getTurnDiffSummaries = (agentId: string): Effect.Effect<TurnDiffSummary[]> =>\n Effect.sync(() => cloneTurnDiffSummaries(state.turnDiffSummariesByAgentId[agentId]));\n\n const getAgentIdBySessionId = (sessionId: string): Effect.Effect<string | null> =>\n Effect.sync(() => state.agentIdBySessionId[sessionId] ?? null);\n\n // ── Bootstrap inline during layer construction ───────────────────────────\n const agentsResolver = yield* AgentsResolver;\n yield* Effect.gen(function* () {\n // Agents come from AgentsResolver; reconstructCache supplies git-backed review status and boot side effects.\n const { reconstructCacheAuto } = yield* Effect.promise(() =>\n import('../../lib/reconstruct/reconstruct-cache.js'),\n );\n\n const result = yield* Effect.promise(() => reconstructCacheAuto());\n const overdeckAgents = yield* agentsResolver.list({});\n\n // See mergeDbOnlyReviewStatuses() doc comment — reconstructCacheAuto()\n // only enumerates tracker-backed issues, so DB-only review_status rows\n // (e.g. the FIX-1 UAT fixture, PAN-3362) need a supplementary source.\n let dbOnlyReviewStatusByIssueId: Record<string, ReviewStatusSnapshot> = {};\n try {\n const { getAllReviewStatusesFromDb } = yield* Effect.promise(\n () => import('../../lib/overdeck/review-status-sync.js'),\n );\n dbOnlyReviewStatusByIssueId = mergeDbOnlyReviewStatuses(result.reviewStatusByIssueId, getAllReviewStatusesFromDb());\n } catch (err) {\n console.error('[ReadModel] Failed to layer in DB-only review statuses:', err);\n }\n\n const agentsById: Record<string, AgentSnapshot> = Object.fromEntries(\n overdeckAgents.map((a) => [a.id, agentSnapshotFromOverdeck(a)]),\n );\n\n // ── Sequence from event store (labels the snapshot, not a replay source) ─\n let sequence = 0;\n let recentActivity: unknown[] = [];\n try {\n const { getEventStore } = yield* Effect.promise(\n () => import('./event-store.js'),\n );\n const eventStore = getEventStore();\n yield* Effect.promise(() => emitBootReconciledStopEvents(eventStore, result.markedStoppedIds, result.agentsById, '[ReadModel] Failed to emit boot-reconciled stop events:'));\n sequence = eventStore.getLatestSequence();\n recentActivity = activityEntriesFromStoredEvents(\n eventStore.queryByType('activity.entry', MAX_SNAPSHOT_ACTIVITY_ENTRIES),\n );\n } catch (err) {\n console.error('[ReadModel] Failed to emit boot-reconciled stop events:', err);\n }\n\n state = {\n ...INITIAL_READ_MODEL_STATE,\n sequence,\n agentsById,\n reviewStatusByIssueId: { ...dbOnlyReviewStatusByIssueId, ...result.reviewStatusByIssueId },\n issuesRaw: [],\n recentActivity,\n };\n\n console.log(\n `[ReadModel] Bootstrapped from local database: ` +\n `${Object.keys(agentsById).length} agents, ` +\n `${Object.keys(result.reviewStatusByIssueId).length} review statuses, ` +\n `${result.issuesEnumerated} in-flight issue(s), seq=${sequence}`,\n );\n\n // ── Checkpoint reconciliation (deferred — non-blocking) ──────────────────\n // Fire-and-forget: scan workspaces for git checkpoints in the background\n // so the ReadModel layer resolves immediately and the dashboard starts fast.\n void (async () => {\n try {\n const { listCheckpoints, diffCheckpointFiles, getCheckpointTimestamp, deleteLegacyCheckpointRefs } = await import('../../lib/checkpoint/checkpoint-manager.js');\n\n const agents = Object.values(state.agentsById);\n\n // One-time: clean up unscoped legacy refs from before per-agent namespacing.\n // Run against the first agent's workspace (all worktrees share the same parent .git).\n const firstAgentWithWorkspace = agents.find(a => a.workspace);\n if (firstAgentWithWorkspace?.workspace) {\n const deleted = await Effect.runPromise(deleteLegacyCheckpointRefs(firstAgentWithWorkspace.workspace));\n if (deleted > 0) {\n console.log(`[ReadModel] Deleted ${deleted} legacy unscoped checkpoint refs`);\n }\n }\n let reconciled = 0;\n for (const agent of agents) {\n if (shouldSkipCheckpointReconciliation(agent)) continue;\n\n const workspace = agent.workspace;\n if (!workspace) continue;\n const existingSummaries = state.turnDiffSummariesByAgentId[agent.id];\n if (existingSummaries && existingSummaries.length > 0) continue;\n\n try {\n const checkpoints = await Effect.runPromise(listCheckpoints(workspace, agent.id));\n if (checkpoints.length === 0) continue;\n\n const maxRetainedSummaries = getMaxTurnDiffSummariesPerAgent();\n const retainedCheckpoints = checkpoints.length > maxRetainedSummaries\n ? checkpoints.slice(-maxRetainedSummaries)\n : checkpoints;\n const checkpointOffset = checkpoints.length - retainedCheckpoints.length;\n\n const summaries: Array<{\n turnId: string;\n completedAt: string;\n files: Array<{ path: string; kind?: string; additions?: number; deletions?: number }>;\n checkpointRef?: string;\n assistantMessageId?: string;\n checkpointTurnCount?: number;\n }> = [];\n\n for (let i = 0; i < retainedCheckpoints.length; i++) {\n const absoluteIndex = checkpointOffset + i;\n const turnId = retainedCheckpoints[i];\n if (!turnId) continue;\n const prevTurnId = absoluteIndex > 0 ? checkpoints[absoluteIndex - 1] ?? null : null;\n let files: Array<{ path: string; kind?: string; additions?: number; deletions?: number }> = [];\n if (prevTurnId) {\n try {\n files = await Effect.runPromise(diffCheckpointFiles(workspace, agent.id, prevTurnId, turnId));\n } catch { /* checkpoint might be stale */ }\n }\n const completedAt = await Effect.runPromise(getCheckpointTimestamp(workspace, agent.id, turnId));\n summaries.push({\n turnId,\n completedAt,\n files,\n checkpointRef: `refs/pan/turn/${agent.id}/${turnId}`,\n checkpointTurnCount: absoluteIndex + 1,\n });\n }\n\n if (summaries.length > 0) {\n state = {\n ...state,\n turnDiffSummariesByAgentId: {\n ...state.turnDiffSummariesByAgentId,\n [agent.id]: trimTurnDiffSummaries(summaries),\n },\n };\n reconciled++;\n }\n } catch { /* agent workspace may not be a git repo */ }\n }\n\n if (reconciled > 0) {\n console.log(`[ReadModel] Reconciled checkpoints for ${reconciled} agent(s)`);\n }\n } catch (err) {\n console.warn('[ReadModel] Checkpoint reconciliation failed:', err);\n }\n })();\n\n // ── Issue listener (always) ──────────────────────────────────────────────\n // Issues come from external trackers (Linear/GitHub) with unpredictable shapes.\n // JSON round-trip strips undefined values that can't be serialized over WebSocket.\n try {\n const { getSharedIssueService } = yield* Effect.promise(\n () => import('./services/issue-service-singleton.js'),\n );\n const issueService = getSharedIssueService();\n\n // PAN-1510: merge issueService's view with whatever the projection\n // cache loaded so newly-filed issues (filed during the previous\n // session's debounced-flush window, or already loaded into\n // IssueDataService's in-memory cache before the read model bootstrap\n // wired its onIssuesChanged callback) reach `issuesRaw`. Without the\n // merge, the bootstrap window between issueService.start() loading\n // its SQLite cache and read-model wiring `onIssuesChanged` could\n // strand fresh issues — the subsequent `pushSnapshot` would either\n // hit a null callback or be skipped by `issuesChanged()` because\n // `lastFetchedIssues` already matched the new GitHub fetch.\n const mergeT0 = performance.now();\n const currentIssues = cleanIssues(issueService.getIssues());\n if (currentIssues.length > 0 || state.issuesRaw.length === 0) {\n const newIssues = discoverNewIssues(state.issuesRaw, currentIssues);\n if (newIssues.length > 0) {\n const sample = newIssues\n .slice(0, 5)\n .map(i => getIssueIdentifierKey(i) ?? 'unknown')\n .join(', ');\n const more = newIssues.length > 5 ? `, +${newIssues.length - 5} more` : '';\n console.log(\n `[ReadModel] Bootstrap: merging ${newIssues.length} new issue(s) from issueService not in projection cache (${sample}${more})`,\n );\n }\n state = {\n ...state,\n issuesRaw: mergeIssuesByIdentifier(state.issuesRaw, currentIssues),\n };\n }\n console.log(`[boot-timing] ReadModel bootstrap merge completed at +${Math.round(performance.now() - mergeT0)}ms`);\n\n // Wire live issue updates — when IssueDataService polls new data,\n // update the read model directly AND emit to event store for\n // WebSocket subscribers (PAN-433).\n issueService.onIssuesChanged((issues) => {\n const cleaned = cleanIssues(issues);\n const delta = createIssueDelta(state.issuesRaw, cleaned);\n if (!delta) return;\n state = { ...state, issuesRaw: cleaned };\n\n // Initial/reconnect snapshots retain every field. Subsequent updates\n // send complete changed rows only, preserving descriptions and order.\n // These cache projections must never enter the durable event log.\n // Uses cached reference to avoid async dynamic import delay\n // (delay caused frontend to miss updates after patchIssue)\n try {\n if (!_cachedEventStore) {\n import('./event-store.js').then(({ getEventStore }) => {\n _cachedEventStore = getEventStore();\n try {\n _cachedEventStore.emitOnly({\n type: 'issues.delta',\n timestamp: new Date().toISOString(),\n payload: delta,\n } as any);\n } catch { /* event store not ready */ }\n }).catch(() => {});\n } else {\n _cachedEventStore.emitOnly({\n type: 'issues.delta',\n timestamp: new Date().toISOString(),\n payload: delta,\n } as any);\n }\n } catch { /* event store not ready yet */ }\n\n // PAN-1866: debounced incremental sequencer pass on every backlog delta\n import('../../lib/backlog/backlog-auto-trigger.js').then(({ triggerDebouncedIncrementalPass }) => {\n triggerDebouncedIncrementalPass(process.cwd());\n }).catch(() => {});\n });\n } catch {\n console.warn('[ReadModel] IssueDataService not available at bootstrap, starting with empty issues');\n }\n });\n\n return {\n getSnapshot,\n getChannelPermissionRequest,\n getResolvedChannelPermissionDecision,\n getTurnDiffSummaries,\n getAgentIdBySessionId,\n applyEvent,\n bootstrap: Effect.void,\n };\n }),\n);\n","import { readFile, stat } from 'fs/promises';\nimport { basename, dirname, join, resolve } from 'path';\nimport type { DashboardSnapshot, FeatureRegistryEntry } from '@overdeck/contracts';\nimport { resolveStatusFile } from './memory/paths.js';\nimport { resolveWorkspaceForCwd } from './workspaces/resolver.js';\n\nexport interface AssembleLiveBriefingInput {\n cwd?: string;\n projectId?: string;\n snapshot?: DashboardSnapshot;\n registryEntries?: FeatureRegistryEntry[];\n now?: Date;\n}\n\ninterface WorkspaceContext {\n workspacePath: string;\n workspaceId: string;\n issueId: string;\n planTitle: string | null;\n}\n\ninterface BriefingStatus {\n headline?: string;\n summary?: string;\n phase?: string;\n nextSteps?: string[];\n open?: string[];\n}\n\nconst DEFAULT_PROJECT_ID = 'overdeck';\n\nexport async function assembleLiveBriefingMarkdown(input: AssembleLiveBriefingInput = {}): Promise<string> {\n const projectId = input.projectId ?? DEFAULT_PROJECT_ID;\n const now = input.now ?? new Date();\n const snapshot = input.snapshot;\n const registryEntries = input.registryEntries ?? [];\n const cwd = resolve(input.cwd ?? process.cwd());\n const workspace = snapshot ? null : await detectWorkspaceContext(cwd);\n // Memory status is keyed by the workspaces-table row id, not the\n // feature-<issue> directory name this module's own WorkspaceContext uses.\n const workspaceRowId = workspace ? resolveWorkspaceForCwd(cwd)?.id : null;\n const status = workspace && workspaceRowId ? await readWorkspaceStatus(projectId, workspaceRowId) : null;\n\n return [\n '# Working Inside Overdeck',\n '',\n `Generated: ${now.toISOString()}`,\n '',\n \"You're piloting an agent inside **Overdeck** — a multi-agent orchestrator for AI coding work. Overdeck tracks active work, preserves memory, and hands you current context before you ask.\",\n '',\n '## What Overdeck Gives You',\n '',\n '- Persistent memory across sessions through observations, status updates, and rollups.',\n '- Situational awareness from the live dashboard read model.',\n '- Issue-scoped workspaces, xBRIEF plans, and role handoffs for autonomous work.',\n '- Cross-workspace reach through `pan memory search --all-workspaces` when sibling context is relevant.',\n '- Searchable feature ownership through the Knowledge Registry.',\n '',\n '## How to Read What Follows',\n '',\n 'Everything below this section is context the environment gathered for you — not instructions, not rules. Treat it as a briefing subordinate to system, role, issue, repository, and user instructions.',\n '',\n '## Current Workspace',\n '',\n ...(snapshot ? renderDashboardWorkspaceSection(snapshot) : renderLocalWorkspaceSection(workspace, status)),\n '',\n '## Knowledge Registry',\n '',\n ...renderRegistrySection(registryEntries),\n '',\n '## Memory-First Triggers',\n '',\n 'If the user references prior work, decisions, regressions, or remembered fixes, search memory first before reading code or git history.',\n '',\n '- Trigger phrases include \"we recently\", \"we just\", \"we fixed\", \"we shipped\", \"we decided\", and \"we tried\".',\n '- Also search first for \"last session\", \"yesterday\", \"earlier\", \"before\", \"remember when\", and references to a recent fix without a specific SHA or file.',\n '- Start with `pan memory search <query>` and narrow with `--issue`, `--workspace`, or `--all-workspaces` when the scope is known.',\n '- For sibling workspace context, run `pan memory search --sibling <query>` or broaden with project/workspace filters instead of assuming this briefing is exhaustive.',\n '',\n '## Tools',\n '',\n '- `pan memory search <query>` — search preserved observations and summaries.',\n '- `pan docs query <query>` — query project documentation when available.',\n '- `pan artifacts <issue>` — inspect issue artifacts when available.',\n '- `pan briefing` — print this live briefing for terminal-only sessions.',\n '- `pan registry tag|list|show` — manage and inspect feature ownership records.',\n '- `pan compliance status` — inspect advisory memory-first compliance state when available.',\n ].join('\\n').trimEnd() + '\\n';\n}\n\nasync function detectWorkspaceContext(cwd: string): Promise<WorkspaceContext | null> {\n let current = cwd;\n while (true) {\n const workspaceId = basename(current);\n const issueMatch = workspaceId.match(/^feature-([a-z]+-\\d+)$/i);\n if (issueMatch && await pathExists(join(current, '.git'))) {\n return {\n workspacePath: current,\n workspaceId,\n issueId: issueMatch[1].toUpperCase(),\n planTitle: await readWorkspacePlanTitle(current),\n };\n }\n const parent = dirname(current);\n if (parent === current) return null;\n current = parent;\n }\n}\n\nasync function readWorkspacePlanTitle(workspacePath: string): Promise<string | null> {\n const path = join(workspacePath, '.pan', 'spec.vbrief.json');\n try {\n const parsed = JSON.parse(await readFile(path, 'utf8')) as { plan?: { title?: unknown } };\n return typeof parsed.plan?.title === 'string' ? parsed.plan.title : null;\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n}\n\nasync function readWorkspaceStatus(projectId: string, workspaceId: string): Promise<BriefingStatus | null> {\n try {\n const parsed = JSON.parse(await readFile(resolveStatusFile(projectId, workspaceId), 'utf8')) as BriefingStatus;\n return parsed && typeof parsed === 'object' ? parsed : null;\n } catch (error) {\n if (isNotFound(error)) return null;\n throw error;\n }\n}\n\nfunction renderLocalWorkspaceSection(workspace: WorkspaceContext | null, status: BriefingStatus | null): string[] {\n if (!workspace) {\n return [\n '- No Overdeck workspace was detected from the current directory.',\n '- Run `pan briefing` from inside a `workspaces/feature-<issue>` checkout to include workspace-specific context.',\n ];\n }\n\n const lines = [\n `- Workspace: ${workspace.workspaceId}`,\n `- Issue: ${workspace.issueId}`,\n `- Path: ${workspace.workspacePath}`,\n ];\n if (workspace.planTitle) lines.push(`- Plan: ${workspace.planTitle}`);\n if (status?.phase) lines.push(`- Phase: ${status.phase}`);\n if (status?.headline) lines.push(`- Headline: ${status.headline}`);\n if (status?.summary) lines.push(`- Summary: ${status.summary}`);\n if (status?.nextSteps?.length) lines.push(`- Next steps: ${status.nextSteps.join('; ')}`);\n if (status?.open?.length) lines.push(`- Open questions: ${status.open.join('; ')}`);\n return lines;\n}\n\nfunction renderDashboardWorkspaceSection(snapshot: DashboardSnapshot): string[] {\n const runningAgents = snapshot.agents.filter((agent) => agent.status === 'running' || agent.hasLiveTmuxSession);\n const pausedAgents = snapshot.agents.filter((agent) => agent.paused);\n const troubledAgents = snapshot.agents.filter((agent) => agent.troubled === true);\n const activeIssues = new Set(snapshot.agents.map((agent) => agent.issueId).filter(Boolean));\n const failedReviews = snapshot.reviewStatuses.filter((status) =>\n status.testStatus === 'failed' ||\n status.uatStatus === 'failed' ||\n status.verificationStatus === 'failed' ||\n status.reviewStatus === 'failed' ||\n (status.blockerReasons?.length ?? 0) > 0,\n );\n\n const lines = [\n `- Running agents: ${runningAgents.length}`,\n `- Active issues with agents: ${activeIssues.size}`,\n `- Paused gates: ${pausedAgents.length}`,\n `- Troubled agents: ${troubledAgents.length}`,\n `- Failed verification/review states needing attention: ${failedReviews.length}`,\n ];\n\n const recentStatuses = Object.entries(readStatusByIssue(snapshot))\n .slice(0, 8)\n .map(([issueId, status]) => {\n const headline = typeof status.headline === 'string' && status.headline.trim()\n ? status.headline.trim()\n : 'No headline recorded';\n const phase = typeof status.phase === 'string' && status.phase.trim()\n ? ` (${status.phase.trim()})`\n : '';\n return `- ${issueId}${phase}: ${headline}`;\n });\n\n if (recentStatuses.length > 0) {\n lines.push('', 'Recent workspace statuses:', ...recentStatuses);\n } else {\n lines.push('', '- No workspace status summaries are currently available.');\n }\n\n return lines;\n}\n\nfunction readStatusByIssue(snapshot: DashboardSnapshot): Record<string, { headline?: unknown; phase?: unknown }> {\n const memory = (snapshot as { memory?: { statusByIssueId?: unknown } }).memory;\n return memory?.statusByIssueId && typeof memory.statusByIssueId === 'object'\n ? memory.statusByIssueId as Record<string, { headline?: unknown; phase?: unknown }>\n : {};\n}\n\nfunction renderRegistrySection(entries: FeatureRegistryEntry[]): string[] {\n if (entries.length === 0) {\n return [\n '- No feature registry entries are currently available.',\n '- Use `pan registry tag <issueId> <feature>` to add manual ownership records.',\n '- Use `pan registry list` and `pan registry show <feature>` to inspect ownership from terminal-only sessions.',\n ];\n }\n\n return [\n '| Feature | Issue | Workspace | Agent | Status | Tags |',\n '|---|---|---|---|---|---|',\n ...entries.slice(0, 25).map((entry) => [\n entry.featureName,\n entry.owningIssueId ?? '—',\n entry.owningWorkspaceId ?? '—',\n entry.owningAgentId ?? '—',\n entry.status,\n entry.tags.length > 0 ? entry.tags.join(', ') : '—',\n ].map(markdownCell).join(' | ')).map((row) => `| ${row} |`),\n ];\n}\n\nfunction markdownCell(value: string): string {\n return value.replaceAll('|', '\\\\|').replace(/\\s+/g, ' ').trim();\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch (error) {\n if (isNotFound(error)) return false;\n throw error;\n }\n}\n\nfunction isNotFound(error: unknown): boolean {\n return typeof error === 'object' && error !== null && 'code' in error && error.code === 'ENOENT';\n}\n","import { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport type { DashboardSnapshot, FeatureRegistryEntry } from '@overdeck/contracts';\nimport { assembleLiveBriefingMarkdown } from '../../../lib/briefing-assembler.js';\nimport { resolveSessionContextBriefingPath } from '../../../lib/briefing-freshness.js';\nimport { listFeatureRegistryEntries } from '../../../lib/registry/feature-registry-storage.js';\n\nexport interface SessionContextWriter {\n schedule(): void;\n writeNow(): Promise<void>;\n stop(): void;\n}\n\nexport interface StartSessionContextWriterOptions {\n readSnapshot: () => Promise<DashboardSnapshot>;\n subscribe: (listener: () => void) => () => void;\n debounceMs?: number;\n path?: string;\n now?: () => Date;\n mkdir?: typeof mkdir;\n writeFile?: typeof writeFile;\n listRegistryEntries?: () => Promise<FeatureRegistryEntry[]>;\n setTimeout?: typeof setTimeout;\n clearTimeout?: typeof clearTimeout;\n logger?: Pick<Console, 'error' | 'warn'>;\n}\n\nexport function startSessionContextWriter(options: StartSessionContextWriterOptions): SessionContextWriter {\n const debounceMs = options.debounceMs ?? 500;\n const path = options.path ?? resolveSessionContextBriefingPath();\n const mkdirFn = options.mkdir ?? mkdir;\n const writeFileFn = options.writeFile ?? writeFile;\n const listRegistryEntriesFn = options.listRegistryEntries ?? (() => listFeatureRegistryEntries({ limit: 50 }));\n const setTimeoutFn = options.setTimeout ?? setTimeout;\n const clearTimeoutFn = options.clearTimeout ?? clearTimeout;\n const now = options.now ?? (() => new Date());\n const logger = options.logger ?? console;\n\n let timer: ReturnType<typeof setTimeout> | null = null;\n let stopped = false;\n let writing = false;\n let pendingAfterWrite = false;\n\n const writeLatest = async (): Promise<void> => {\n if (stopped) return;\n if (writing) {\n pendingAfterWrite = true;\n return;\n }\n\n writing = true;\n try {\n const [snapshot, registryEntries] = await Promise.all([\n options.readSnapshot(),\n readRegistryEntries(listRegistryEntriesFn, logger),\n ]);\n const content = await assembleLiveBriefingMarkdown({ snapshot, registryEntries, now: now() });\n await mkdirFn(dirname(path), { recursive: true });\n await writeFileFn(path, content, 'utf8');\n } catch (error) {\n logger.error('[session-context] Failed to write live briefing:', error);\n } finally {\n writing = false;\n if (pendingAfterWrite && !stopped) {\n pendingAfterWrite = false;\n schedule();\n }\n }\n };\n\n const schedule = (): void => {\n if (stopped) return;\n if (timer) clearTimeoutFn(timer);\n timer = setTimeoutFn(() => {\n timer = null;\n void writeLatest();\n }, debounceMs);\n };\n\n const unsubscribe = options.subscribe(schedule);\n void writeLatest();\n\n return {\n schedule,\n writeNow: writeLatest,\n stop() {\n stopped = true;\n if (timer) {\n clearTimeoutFn(timer);\n timer = null;\n }\n unsubscribe();\n },\n };\n}\n\nasync function readRegistryEntries(\n listRegistryEntries: () => Promise<FeatureRegistryEntry[]>,\n logger: Pick<Console, 'warn'>,\n): Promise<FeatureRegistryEntry[]> {\n try {\n return await listRegistryEntries();\n } catch (error) {\n logger.warn('[session-context] Failed to load feature registry entries:', error);\n return [];\n }\n}\n","import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execFileAsync = promisify(execFile);\n\nexport type ProjectCiGhApi = (path: string) => Promise<unknown>;\n\nexport const projectCiGhApi: ProjectCiGhApi = async (path) => {\n const { stdout } = await execFileAsync(\n 'gh',\n ['api', path, '-H', 'Accept: application/vnd.github+json'],\n { encoding: 'utf-8', timeout: 15_000, maxBuffer: 8 * 1024 * 1024 },\n );\n return JSON.parse(stdout);\n};\n\nexport async function resolveDefaultBranchHead(\n repo: string,\n branch: string,\n ghApi: ProjectCiGhApi = projectCiGhApi,\n): Promise<string | null> {\n const response = await ghApi(\n `repos/${repo}/branches/${encodeURIComponent(branch)}`,\n ) as { commit?: { sha?: string } };\n return response.commit?.sha ?? null;\n}\n","import type {\n ProjectCiHeadObservedEvent,\n ProjectCiSuite,\n} from '@overdeck/contracts';\nimport { appendDomainEventAsync } from '../activity-logger.js';\nimport {\n projectCiGhApi,\n resolveDefaultBranchHead,\n type ProjectCiGhApi,\n} from '../ci/project-ci-github.js';\nimport { listProjectsSync, type ProjectConfig } from '../projects.js';\n\ntype Project = { key: string; config: ProjectConfig };\ntype HeadObservation = ProjectCiHeadObservedEvent['payload'];\n\ninterface WorkflowRun {\n head_sha?: string;\n check_suite_id?: number;\n status?: string;\n conclusion?: string | null;\n html_url?: string;\n updated_at?: string;\n}\n\ninterface ProjectCiFillState {\n fingerprints: Map<string, string>;\n}\n\nexport function createProjectCiFillState(): ProjectCiFillState {\n return { fingerprints: new Map() };\n}\n\nfunction projectionFingerprint(observation: HeadObservation): string {\n const suites = Object.entries(observation.suites)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([suiteId, suite]) => [\n suiteId,\n suite.status,\n suite.conclusion,\n suite.htmlUrl ?? null,\n ]);\n return JSON.stringify([\n observation.repo,\n observation.branch,\n observation.headSha,\n suites,\n ]);\n}\n\n/** Fetch a complete Actions projection for the independently-resolved default\n * branch head. The second branch lookup prevents publishing a projection when\n * the branch advances while workflow pages are being collected. */\nexport async function fillProjectCiObservation(\n project: Project,\n deps: { ghApi?: ProjectCiGhApi; now?: () => string } = {},\n): Promise<HeadObservation | null> {\n const repo = project.config.github_repo;\n if (!repo) return null;\n const branch = project.config.workspace?.default_branch ?? 'main';\n const ghApi = deps.ghApi ?? projectCiGhApi;\n\n try {\n const headSha = await resolveDefaultBranchHead(repo, branch, ghApi);\n if (!headSha) return null;\n\n const runs: WorkflowRun[] = [];\n for (let page = 1; ; page += 1) {\n const response = await ghApi(\n `repos/${repo}/actions/runs?branch=${encodeURIComponent(branch)}`\n + `&head_sha=${encodeURIComponent(headSha)}&per_page=100&page=${page}`,\n ) as { workflow_runs?: WorkflowRun[] };\n const pageRuns = response.workflow_runs ?? [];\n runs.push(...pageRuns);\n if (pageRuns.length < 100) break;\n }\n\n const verifiedHeadSha = await resolveDefaultBranchHead(repo, branch, ghApi);\n if (verifiedHeadSha !== headSha) return null;\n\n const observedAt = deps.now?.() ?? new Date().toISOString();\n const suites: Record<string, ProjectCiSuite> = {};\n for (const run of runs) {\n if (run.head_sha !== headSha || run.check_suite_id == null) continue;\n const suiteId = String(run.check_suite_id);\n const suiteObservedAt = run.updated_at ?? observedAt;\n const existing = suites[suiteId];\n if (existing?.observedAt && existing.observedAt > suiteObservedAt) continue;\n suites[suiteId] = {\n status: run.status ?? 'queued',\n conclusion: run.conclusion ?? null,\n htmlUrl: run.html_url,\n observedAt: suiteObservedAt,\n };\n }\n\n return {\n projectKey: project.key,\n repo,\n branch,\n headSha,\n suites,\n observedAt,\n };\n } catch {\n return null;\n }\n}\n\n/** Fill every project through one complete, idempotent projection event. */\nexport async function fillAllProjectCi(\n deps: {\n ghApi?: ProjectCiGhApi;\n append?: typeof appendDomainEventAsync;\n projects?: Project[];\n state?: ProjectCiFillState;\n now?: () => string;\n } = {},\n): Promise<number> {\n const append = deps.append ?? appendDomainEventAsync;\n const projects = deps.projects ?? listProjectsSync();\n const state = deps.state ?? createProjectCiFillState();\n let appended = 0;\n\n for (const project of projects) {\n if (!project.config.github_repo) continue;\n const observation = await fillProjectCiObservation(project, {\n ghApi: deps.ghApi,\n now: deps.now,\n });\n if (!observation) continue;\n\n const fingerprint = projectionFingerprint(observation);\n if (state.fingerprints.get(project.key) === fingerprint) continue;\n if (await append({\n type: 'project.ci_head_observed',\n timestamp: observation.observedAt,\n payload: observation,\n })) {\n state.fingerprints.set(project.key, fingerprint);\n appended += 1;\n }\n }\n\n return appended;\n}\n\nexport function startProjectCiRefill(\n intervalMs: number,\n deps: {\n fill?: () => Promise<number>;\n warn?: (message: string) => void;\n setIntervalFn?: typeof setInterval;\n } = {},\n): ReturnType<typeof setInterval> {\n const state = createProjectCiFillState();\n const fill = deps.fill ?? (() => fillAllProjectCi({ state }));\n const warn = deps.warn ?? ((message: string) => console.warn(message));\n let running = false;\n\n const run = (): void => {\n if (running) return;\n running = true;\n void fill()\n .catch((err: unknown) => {\n const message = err instanceof Error ? err.message : String(err);\n warn(`[overdeck] Project CI fill failed: ${message}`);\n })\n .finally(() => {\n running = false;\n });\n };\n\n run();\n const timer = (deps.setIntervalFn ?? setInterval)(run, intervalMs);\n timer.unref();\n return timer;\n}\n","import { startProjectCiRefill } from '../../../lib/overdeck/project-ci-fill.js';\n\nlet resolveProjectionReady!: () => void;\nlet projectionReady = false;\nlet projectionReadyPromise = createProjectionReadyPromise();\n\nfunction createProjectionReadyPromise(): Promise<void> {\n return new Promise<void>((resolve) => {\n resolveProjectionReady = resolve;\n });\n}\n\n/** Mark the event-store → read-model subscription as installed. */\nexport function markEventStoreProjectionReady(): void {\n if (projectionReady) return;\n projectionReady = true;\n resolveProjectionReady();\n}\n\n/** Wait until events appended by background services can reach the read model. */\nexport function whenEventStoreProjectionReady(): Promise<void> {\n return projectionReadyPromise;\n}\n\nexport async function startProjectCiRefillAfterProjectionReady(\n intervalMs: number,\n deps: {\n whenReady?: () => Promise<void>;\n start?: typeof startProjectCiRefill;\n } = {},\n): Promise<ReturnType<typeof setInterval>> {\n await (deps.whenReady ?? whenEventStoreProjectionReady)();\n return (deps.start ?? startProjectCiRefill)(intervalMs);\n}\n\nexport function resetEventStoreProjectionReadyForTests(): void {\n projectionReady = false;\n projectionReadyPromise = createProjectionReadyPromise();\n}\n","/**\n * Domain service wrappers — Effect services over existing lib modules (PAN-428 B5, PAN-433)\n *\n * EventStoreService: wraps the SQLite event store in Effect.\n * SnapshotService was removed in PAN-433 — replaced by ReadModelService (read-model.ts).\n *\n * The EventStoreServiceLive layer also wires event store → read model: every\n * appended event is pushed to ReadModelService.applyEvent() so the in-memory\n * projection stays current.\n */\n\nimport { Effect, Layer, Queue, Context, Stream } from 'effect';\nimport { initEventStore } from '../event-store.js';\nimport type { StoredEvent } from '../event-store.js';\nimport { ReadModelService } from '../read-model.js';\nimport { startSessionContextWriter } from './session-context-writer.js';\nimport { markEventStoreProjectionReady } from './project-ci-refill-startup.js';\nimport { emitActivityDetailedSync } from '../../../lib/activity-logger.js';\nimport { captureCheckpoint, diffCheckpointFiles, isCheckpointTargetDisabled, listCheckpoints } from '../../../lib/checkpoint/checkpoint-manager.js';\nimport { isTerminalTurnDiffSummaryStatus } from '@overdeck/contracts';\nimport { randomUUID } from 'crypto';\n\n// ─── EventStoreService ────────────────────────────────────────────────────────\n\nexport interface EventStoreServiceShape {\n /** Append a domain event; returns the assigned sequence number. */\n readonly append: (event: Record<string, unknown>) => Effect.Effect<number>;\n /** Queue a domain event append without blocking the HTTP/WebSocket hot path. */\n readonly appendAsync: (event: Record<string, unknown>) => Effect.Effect<number>;\n /** Return all stored events with sequence > fromSequence. */\n readonly readFrom: (fromSequence: number) => Effect.Effect<StoredEvent[]>;\n /** Return events of a given type, most recent first, capped at limit. */\n readonly queryByType: (type: string, limit?: number) => Effect.Effect<StoredEvent[]>;\n /** Return the latest sequence number (0 if empty). */\n readonly getLatestSequence: Effect.Effect<number>;\n /** Subscribe to live events as an Effect Stream. */\n readonly streamEvents: Stream.Stream<StoredEvent>;\n}\n\nexport class EventStoreService extends Context.Service<\n EventStoreService,\n EventStoreServiceShape\n>()('overdeck/dashboard/EventStoreService') {}\n\n/** Map a domain event to a detailed activity log entry. Returns null for uninteresting events. */\nfunction shouldRefreshSessionContext(type: string): boolean {\n return type === 'issues.snapshot' || type === 'issues.delta' ||\n type.startsWith('agent.') ||\n type.startsWith('review.') ||\n type.startsWith('pipeline.') ||\n type.startsWith('planning.') ||\n type.startsWith('plan.') ||\n type.startsWith('workspace.') ||\n type.startsWith('issue.') ||\n type.startsWith('memory.') ||\n type.startsWith('cost.') ||\n type.startsWith('merge.') ||\n type.startsWith('system.health_');\n}\n\n/**\n * Resolve the workspace a checkpoint may be captured in, or null when capture\n * must be skipped (PAN-3725).\n *\n * Skipped when the agent has no workspace, when the agent has reached a\n * terminal status (a stopped/done/archived/closed agent produces no new turns,\n * so capturing is pure waste — same rule the read model's checkpoint\n * reconciliation uses), or when the workspace was already found not to be a git\n * repository.\n */\nexport function checkpointCaptureTarget(\n agent: { status?: unknown; workspace?: unknown } | undefined,\n): string | null {\n const workspace = typeof agent?.workspace === 'string' ? agent.workspace : '';\n if (!workspace) return null;\n if (isTerminalTurnDiffSummaryStatus(agent?.status)) return null;\n if (isCheckpointTargetDisabled(workspace)) return null;\n return workspace;\n}\n\nexport function mapDomainEventToDetailed(event: StoredEvent): {\n source: string;\n level: 'info' | 'warn' | 'error' | 'success';\n message: string;\n issueId?: string;\n triggeringEvent: string;\n} | null {\n const p = (event.payload ?? {}) as Record<string, unknown>;\n const issueId = (p['issueId'] as string) ?? undefined;\n\n switch (event.type) {\n case 'agent.created':\n return { source: 'cloister', level: 'info', message: `Agent created for ${p['agentId']}`, issueId, triggeringEvent: event.type };\n case 'agent.started':\n return { source: 'cloister', level: 'info', message: `Agent started: ${p['agentId']}`, issueId, triggeringEvent: event.type };\n case 'agent.stopped':\n return { source: 'cloister', level: 'info', message: `Agent stopped: ${p['agentId']}`, issueId, triggeringEvent: event.type };\n case 'agent.status_changed': {\n const prev = p['previousStatus'] ? ` (was ${p['previousStatus']})` : '';\n return { source: 'cloister', level: 'info', message: `Agent ${p['agentId']} status → ${p['status']}${prev}`, issueId, triggeringEvent: event.type };\n }\n case 'agent.enrichment_changed': {\n const parts: string[] = [];\n if (p['agentPhase']) parts.push(`phase=${p['agentPhase']}`);\n if (p['resolution']) parts.push(`resolution=${p['resolution']}`);\n if (p['hasPendingQuestion']) parts.push(`questions=${p['pendingQuestionCount']}`);\n if (parts.length === 0) return null;\n return { source: 'cloister', level: 'info', message: `Agent ${p['agentId']} enrichment: ${parts.join(', ')}`, issueId, triggeringEvent: event.type };\n }\n case 'planning.started':\n return { source: 'planning', level: 'info', message: `Planning started: ${p['sessionName']}`, issueId, triggeringEvent: event.type };\n case 'planning.failed':\n return { source: 'planning', level: 'error', message: `Planning failed: ${p['error']}`, issueId, triggeringEvent: event.type };\n case 'planning.sync':\n return { source: 'planning', level: 'info', message: `Planning sync: ${p['status']}${p['progress'] !== undefined ? ` (${p['progress']}%)` : ''}`, issueId, triggeringEvent: event.type };\n case 'plan.item_status_changed':\n return { source: 'plan', level: 'info', message: `Plan item ${p['itemId']} → ${p['status']}`, issueId, triggeringEvent: event.type };\n case 'plan.subitem_status_changed':\n return { source: 'plan', level: 'info', message: `Plan sub-item ${p['subItemId']} → ${p['status']}`, issueId, triggeringEvent: event.type };\n case 'plan.items_unblocked': {\n const items = p['items'] as string[] | undefined;\n if (!items || items.length === 0) return null;\n return { source: 'plan', level: 'success', message: `${items.length} plan item(s) unblocked`, issueId, triggeringEvent: event.type };\n }\n case 'pipeline.status_changed':\n return { source: 'pipeline', level: 'info', message: `Pipeline status updated for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'review.status_changed':\n return { source: 'review', level: 'info', message: `Review status updated for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'pipeline.verification-started':\n return { source: 'verification', level: 'info', message: `Verification started for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'pipeline.verification-failed':\n return { source: 'verification', level: 'error', message: `Verification failed for ${issueId}${p['failedCheck'] ? `: ${p['failedCheck']}` : ''}`, issueId, triggeringEvent: event.type };\n case 'pipeline.review-started':\n return { source: 'review', level: 'info', message: `Review specialist started for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'pipeline.review-completed':\n return { source: 'review', level: p['passed'] ? 'success' : 'error', message: `Review ${p['passed'] ? 'passed' : 'failed'} for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'pipeline.test-started':\n return { source: 'test', level: 'info', message: `Test specialist started for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'pipeline.test-completed':\n return { source: 'test', level: p['passed'] ? 'success' : 'error', message: `Tests ${p['passed'] ? 'passed' : 'failed'} for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'specialist.started':\n return { source: 'cloister', level: 'info', message: `Specialist ${p['name'] ?? '?'} started${p['currentIssue'] ? ` for ${p['currentIssue']}` : ''}`, issueId, triggeringEvent: event.type };\n case 'specialist.completed':\n return { source: 'cloister', level: 'success', message: `Specialist ${p['name']} completed`, issueId, triggeringEvent: event.type };\n case 'specialist.failed':\n return { source: 'cloister', level: 'error', message: `Specialist ${p['name']} failed: ${p['error']}`, issueId, triggeringEvent: event.type };\n case 'workspace.created':\n return { source: 'workspace', level: 'info', message: `Workspace created at ${p['workspacePath']}`, issueId, triggeringEvent: event.type };\n case 'workspace.wipe_started':\n return { source: 'workspace', level: 'warn', message: `Deep-wipe started for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'workspace.destroyed':\n return { source: 'workspace', level: 'info', message: `Workspace destroyed for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'workspace.deleted':\n return { source: 'workspace', level: 'info', message: `Workspace deleted for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'workspace.aborted':\n return { source: 'workspace', level: 'warn', message: `Workspace aborted for ${issueId}`, issueId, triggeringEvent: event.type };\n case 'issue.statusChanged':\n return { source: 'tracker', level: 'info', message: `Issue ${p['issueId']} status → ${p['canonicalStatus']}`, issueId: p['issueId'] as string, triggeringEvent: event.type };\n case 'dashboard.lifecycle_started':\n return { source: 'dashboard', level: 'info', message: `Dashboard lifecycle started: ${p['reason']}`, issueId, triggeringEvent: event.type };\n case 'dashboard.lifecycle_completed':\n return { source: 'dashboard', level: 'success', message: `Dashboard lifecycle completed: ${p['reason']}`, issueId, triggeringEvent: event.type };\n case 'dashboard.lifecycle_failed':\n return { source: 'dashboard', level: 'error', message: `Dashboard lifecycle failed: ${p['reason']} — ${p['error']}`, issueId, triggeringEvent: event.type };\n case 'merge.ready':\n return { source: 'ship', level: 'success', message: `Issue ${issueId} ready for merge`, issueId, triggeringEvent: event.type };\n case 'system.health_severity_changed':\n return {\n source: 'system-health',\n level: p['severity'] === 'critical' ? 'error' : p['severity'] === 'warning' ? 'warn' : 'info',\n message: `System health ${p['previousSeverity']} → ${p['severity']}`,\n issueId,\n triggeringEvent: event.type,\n };\n case 'cost.event_recorded': {\n const cost = Number(p['cost']);\n if (Number.isFinite(cost) && cost <= 0) return null;\n return { source: 'costs', level: 'info', message: `Cost event: $${(p['cost'] as number)?.toFixed?.(2) ?? p['cost']} for ${p['agentId']}`, issueId, triggeringEvent: event.type };\n }\n default:\n return null;\n }\n}\n\nexport const EventStoreServiceLive = Layer.effect(\n EventStoreService,\n Effect.gen(function* () {\n const store = yield* Effect.promise(() => initEventStore());\n const readModel = yield* ReadModelService;\n\n // Wire event store → read model: every appended event updates the projection.\n // The EventEmitter subscription is sync, so applyEvent runs inline on append.\n store.subscribe((event) => {\n readModel.applyEvent({\n type: event.type,\n sequence: event.sequence,\n timestamp: event.timestamp,\n payload: event.payload,\n } as any);\n });\n markEventStoreProjectionReady();\n\n startSessionContextWriter({\n readSnapshot: () => Effect.runPromise(readModel.getSnapshot),\n subscribe: (listener) => store.subscribe((event) => {\n if (shouldRefreshSessionContext(event.type)) listener();\n }),\n });\n\n // Auto-emit detailed activity entries for state-change domain events.\n // Skip activity.* events to avoid infinite loops.\n store.subscribe((event) => {\n if (event.type.startsWith('activity.')) return;\n const detailed = mapDomainEventToDetailed(event);\n if (detailed) emitActivityDetailedSync(detailed);\n });\n\n // Capture checkpoints when agent activity changes.\n // Fires async (non-blocking) on every agent.activity_changed event for agents\n // with a workspace. Creates a git checkpoint, computes file changes since the\n // previous checkpoint, and emits agent.turn_diff_completed.\n // Rate-limited to one checkpoint per agent per 10 seconds.\n const checkpointCooldown = new Map<string, number>(); // agentId → last checkpoint timestamp\n store.subscribe((event) => {\n if (event.type !== 'agent.activity_changed') return;\n const p = (event.payload ?? {}) as Record<string, unknown>;\n const agentId = p['agentId'] as string | undefined;\n if (!agentId) return;\n\n // Rate limit: skip if last checkpoint was <10s ago\n const lastCheckpoint = checkpointCooldown.get(agentId) ?? 0;\n if (Date.now() - lastCheckpoint < 10_000) return;\n checkpointCooldown.set(agentId, Date.now());\n\n // Fire-and-forget async checkpoint — don't block the event loop\n (async () => {\n try {\n // Look up agent workspace from read model snapshot\n const snapshot = await Effect.runPromise(readModel.getSnapshot);\n const agent = (snapshot.agents as any[]).find((a: any) => a.id === agentId);\n const workspace = checkpointCaptureTarget(agent);\n if (!workspace) return;\n\n const turnId = `turn-${Date.now()}-${randomUUID().slice(0, 8)}`;\n\n // Capture checkpoint (git tag at current working tree state)\n await Effect.runPromise(captureCheckpoint(workspace, agentId, turnId));\n\n // Compute file changes from previous checkpoint\n const checkpoints = await Effect.runPromise(listCheckpoints(workspace, agentId));\n const prevCheckpoint = checkpoints.length >= 2 ? checkpoints[checkpoints.length - 2] : null;\n let files: Array<{ path: string; kind?: string; additions?: number; deletions?: number }> = [];\n if (prevCheckpoint) {\n files = await Effect.runPromise(diffCheckpointFiles(workspace, agentId, prevCheckpoint, turnId));\n }\n\n // Only emit if there are actual changes\n if (files.length === 0) return;\n\n // Emit turn_diff_completed event\n store.appendAsync({\n type: 'agent.turn_diff_completed',\n timestamp: new Date().toISOString(),\n payload: {\n agentId,\n turnId,\n completedAt: new Date().toISOString(),\n files,\n checkpointRef: `refs/pan/turn/${agentId}/${turnId}`,\n assistantMessageId: undefined,\n checkpointTurnCount: checkpoints.length,\n },\n } as any);\n } catch (err) {\n // Checkpoint capture is best-effort — log but don't crash\n console.error('[checkpoint] Failed to capture checkpoint for', agentId, err);\n }\n })();\n });\n\n // PAN-1635: bridge Claude-native compaction to the conversation \"compacting\"\n // flag. Only the Overdeck-native path emits conversation.compacting_changed\n // directly; a built-in Claude Code /compact is invisible to it. But the\n // PreCompact hook emits activity{tool:\"compact\"} and PostCompact emits\n // activity{idle} for *both* paths, so mirror that signal here. This gives the\n // dashboard a live \"Compacting…\" indicator during Claude's own /compact (and\n // visibly explains a prompt eaten by submit-time compaction). Conversation\n // agentIds (`conv-*`) double as the conversation name.\n const compactingConvs = new Set<string>();\n store.subscribe((event) => {\n if (event.type !== 'agent.activity_changed') return;\n const p = (event.payload ?? {}) as Record<string, unknown>;\n const agentId = p['agentId'] as string | undefined;\n if (!agentId || !agentId.startsWith('conv-')) return;\n const compacting = p['currentTool'] === 'compact';\n if (compacting === compactingConvs.has(agentId)) return;\n if (compacting) compactingConvs.add(agentId);\n else compactingConvs.delete(agentId);\n store.emitOnly({\n type: 'conversation.compacting_changed',\n timestamp: event.timestamp ?? new Date().toISOString(),\n payload: { conversationName: agentId, compacting },\n } as never);\n });\n\n const streamEvents = Stream.callback<StoredEvent>((queue) =>\n Effect.acquireRelease(\n Effect.sync(() =>\n store.subscribe((event) => Queue.offerUnsafe(queue, event)),\n ),\n (unsubscribe) => Effect.sync(unsubscribe),\n ),\n );\n\n return {\n append: (event) => Effect.sync(() => store.append(event as never)),\n appendAsync: (event) => Effect.promise(() => store.appendAsync(event as never)),\n readFrom: (fromSequence) => Effect.sync(() => store.readFrom(fromSequence)),\n queryByType: (type, limit) => Effect.sync(() => store.queryByType(type, limit)),\n getLatestSequence: Effect.sync(() => store.getLatestSequence()),\n streamEvents,\n };\n }),\n);\n","/**\n * IssueLifecycle Effect service (PAN-449)\n *\n * High-level issue state management that dispatches to the correct tracker\n * client (Linear, GitHub, Rally) based on the issue ID prefix.\n *\n * Routes should use IssueLifecycle instead of calling tracker clients directly.\n * The service handles:\n * - State transitions (In Planning, In Progress, In Review, Done)\n * - Label add/remove (GitHub only; no-op for Linear/Rally)\n * - Issue close with label cleanup\n */\n\nimport { Effect, Layer, Option, Context } from 'effect';\nimport { resolveGitHubIssueSync, resolveTrackerTypeSync } from '../../../lib/tracker-utils.js';\nimport { GitHubClient } from './github-client.js';\nimport { GitHubClientOptionalLive } from './github-client.js';\nimport { LinearClient } from './linear-client.js';\nimport { LinearClientOptionalLive } from './linear-client.js';\nimport { RallyClient } from './rally-client.js';\nimport { RallyClientOptionalLive } from './rally-client.js';\nimport type { LinearState } from './linear-client.js';\nimport { TrackerNotConfigured, TrackerApiError, IssueNotFound, RateLimited } from './typed-errors.js';\nimport { EventStoreService } from './domain-services.js';\nimport { getSharedIssueService } from './issue-service-singleton.js';\n\n// ─── Event emission helper ────────────────────────────────────────────────────\n\n/**\n * Attempt to emit a domain event via the shared event store.\n * Non-fatal: silently no-ops if EventStoreService is absent (e.g. in unit tests).\n */\nfunction emitEvent(event: Record<string, unknown>): Effect.Effect<void, never> {\n return Effect.gen(function* () {\n const storeOption = yield* Effect.serviceOption(EventStoreService);\n if (Option.isSome(storeOption)) {\n yield* storeOption.value.append(event);\n }\n });\n}\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type IssueState = 'open' | 'in_planning' | 'in_progress' | 'in_review' | 'verifying_on_main' | 'closed' | 'canceled';\n\n// ─── Service interface ────────────────────────────────────────────────────────\n\nexport interface IssueLifecycleShape {\n /**\n * Transition an issue to a new lifecycle state.\n *\n * For Linear: resolves the Linear state ID from team workflow.\n * For GitHub: adds/removes workflow labels (state change via labels).\n * For Rally: delegates to RallyClient.updateState.\n */\n readonly transitionTo: (\n issueId: string,\n state: IssueState,\n ) => Effect.Effect<\n void,\n TrackerNotConfigured | IssueNotFound | TrackerApiError | RateLimited\n >;\n\n /**\n * Add a label to an issue.\n * GitHub only: creates the label if it doesn't exist, then adds it.\n * Linear / Rally: no-op (trackers don't use workflow labels the same way).\n */\n readonly addLabel: (\n issueId: string,\n label: string,\n ) => Effect.Effect<void, TrackerNotConfigured | TrackerApiError | RateLimited>;\n\n /**\n * Remove a label from an issue.\n * GitHub only; non-fatal if label is not present.\n * Linear / Rally: no-op.\n */\n readonly removeLabel: (\n issueId: string,\n label: string,\n ) => Effect.Effect<void, TrackerNotConfigured | TrackerApiError | RateLimited>;\n\n /**\n * Close an issue and clean up workflow labels.\n *\n * - Transitions issue to 'closed' state.\n * - For GitHub: removes in-progress/in-review/planned labels.\n */\n readonly close: (\n issueId: string,\n ) => Effect.Effect<\n void,\n TrackerNotConfigured | IssueNotFound | TrackerApiError | RateLimited\n >;\n}\n\n// ─── Service tag ──────────────────────────────────────────────────────────────\n\nexport class IssueLifecycle extends Context.Service<IssueLifecycle, IssueLifecycleShape>()(\n 'overdeck/dashboard/IssueLifecycle',\n) {}\n\n// ─── Linear state helpers ─────────────────────────────────────────────────────\n\n/** Map a normalized IssueState to a Linear state type string. */\nfunction linearStateType(state: IssueState): string {\n switch (state) {\n case 'open':\n return 'unstarted';\n case 'in_planning':\n case 'in_progress':\n case 'in_review':\n case 'verifying_on_main':\n return 'started';\n case 'closed':\n return 'completed';\n case 'canceled':\n return 'canceled';\n }\n}\n\n/** Find the best matching Linear state from a list given a target normalized state. */\nfunction findLinearState(states: ReadonlyArray<LinearState>, state: IssueState): LinearState | null {\n if (state === 'in_review' || state === 'verifying_on_main') {\n const names = state === 'verifying_on_main'\n ? ['verifying on main', 'verifying', 'in review']\n : ['in review'];\n const explicit = states.find((s) => names.includes(s.name.toLowerCase()));\n if (explicit) return explicit;\n // Fall back to first \"started\" state\n return states.filter((s) => s.type === 'started')[0] ?? null;\n }\n\n if (state === 'in_planning') {\n // Prefer a state named \"In Planning\" or \"Planning\"\n const explicit = states.find(\n (s) => s.name.toLowerCase() === 'in planning' || s.name.toLowerCase() === 'planning',\n );\n if (explicit) return explicit;\n // Fall back to first \"started\" state\n return states.filter((s) => s.type === 'started')[0] ?? null;\n }\n\n const targetType = linearStateType(state);\n const matching = states.filter((s) => s.type === targetType);\n return matching[0] ?? null;\n}\n\n// ─── GitHub label helpers ─────────────────────────────────────────────────────\n\nconst GITHUB_STATE_LABELS: Record<IssueState, { add: string[]; remove: string[] }> = {\n open: { add: [], remove: ['in-progress', 'in-review', 'planned', 'in-planning', 'review-ready', 'done', 'merged', 'verifying-on-main', 'needs-close-out', 'closed-out', 'wontfix', 'duplicate'] },\n in_planning: { add: ['planned'], remove: ['in-progress', 'in-review', 'review-ready', 'done', 'merged', 'verifying-on-main', 'needs-close-out', 'closed-out', 'wontfix', 'duplicate'] },\n in_progress: { add: ['in-progress'], remove: ['planned', 'in-planning', 'in-review', 'review-ready', 'done', 'merged', 'verifying-on-main', 'needs-close-out', 'closed-out', 'wontfix', 'duplicate'] },\n in_review: { add: ['in-review'], remove: ['in-progress', 'planned', 'in-planning', 'done', 'merged', 'verifying-on-main', 'needs-close-out', 'closed-out', 'wontfix', 'duplicate'] },\n verifying_on_main: { add: ['verifying-on-main'], remove: ['in-progress', 'in-review', 'planned', 'in-planning', 'review-ready', 'ready-for-merge', 'done', 'needs-close-out', 'closed-out', 'wontfix', 'duplicate'] },\n closed: { add: [], remove: ['in-progress', 'in-review', 'planned', 'in-planning', 'review-ready', 'done', 'merged', 'verifying-on-main', 'needs-close-out', 'closed-out', 'wontfix', 'duplicate'] },\n canceled: { add: ['wontfix'], remove: ['in-progress', 'in-review', 'planned', 'in-planning', 'review-ready', 'done', 'merged', 'verifying-on-main', 'needs-close-out', 'closed-out', 'duplicate'] },\n};\n\nconst GITHUB_LABEL_METADATA: Record<string, { color: string; description: string }> = {\n 'planned': { color: 'cfd3d7', description: 'Planning complete' },\n 'in-progress': { color: 'fbca04', description: 'Implementation in progress' },\n 'in-review': { color: 'd4c5f9', description: 'Under review' },\n 'verifying-on-main': { color: 'fbca04', description: 'Merged — awaiting verification on main' },\n 'wontfix': { color: 'ffffff', description: 'Will not be fixed' },\n};\n\nfunction githubLabelMetadata(label: string): { color: string; description: string } {\n return GITHUB_LABEL_METADATA[label] ?? { color: '0075ca', description: '' };\n}\n\n// ─── Live layer implementation ────────────────────────────────────────────────\n\n/** Map IssueState to canonical status string for cache patching. */\nfunction canonicalStatus(state: IssueState): string {\n switch (state) {\n case 'open': return 'open';\n case 'in_planning': return 'in_planning';\n case 'in_progress': return 'in_progress';\n case 'in_review': return 'in_review';\n case 'verifying_on_main': return 'verifying_on_main';\n case 'closed': return 'closed';\n case 'canceled': return 'canceled';\n }\n}\n\nexport const IssueLifecycleLive = Layer.effect(\n IssueLifecycle,\n Effect.gen(function* () {\n const linear = yield* LinearClient;\n const github = yield* GitHubClient;\n const rally = yield* RallyClient;\n\n const impl: IssueLifecycleShape = {\n transitionTo: (issueId, state) =>\n Effect.gen(function* () {\n const trackerType = resolveTrackerTypeSync(issueId);\n\n if (trackerType === 'github') {\n // GitHub state is managed via labels\n const ghInfo = resolveGitHubIssueSync(issueId);\n if (!ghInfo.isGitHub) return;\n const labelOps = GITHUB_STATE_LABELS[state];\n for (const label of labelOps.add) {\n const metadata = githubLabelMetadata(label);\n yield* github.ensureLabel(ghInfo.owner, ghInfo.repo, label, metadata.color, metadata.description);\n yield* github.addLabel(ghInfo.owner, ghInfo.repo, ghInfo.number, label);\n }\n for (const label of labelOps.remove) {\n yield* github.removeLabel(ghInfo.owner, ghInfo.repo, ghInfo.number, label);\n }\n if (state === 'closed' || state === 'canceled') {\n yield* github.closeIssue(ghInfo.owner, ghInfo.repo, ghInfo.number);\n } else {\n // Reopen the issue if it's currently closed (e.g. reopening after incorrect merge)\n yield* github.reopenIssue(ghInfo.owner, ghInfo.repo, ghInfo.number).pipe(\n Effect.catch(() => Effect.void) // Non-fatal if already open\n );\n }\n } else if (trackerType === 'rally') {\n const normalizedState =\n state === 'in_planning' || state === 'open' ? 'open'\n : state === 'in_progress' || state === 'in_review' || state === 'verifying_on_main' ? 'in_progress'\n : 'closed';\n yield* rally.updateState(issueId, normalizedState);\n } else {\n // Linear\n const issue = yield* linear.getIssue(issueId);\n const states = yield* linear.getTeamStates(issue.team.id);\n const target = findLinearState(states, state);\n // No-op if the issue is already in the target state\n if (target && issue.state?.id !== target.id) {\n yield* linear.updateState(issue.id, target.id);\n }\n }\n\n // Patch the in-memory cache and emit a domain event (non-fatal)\n yield* Effect.try({ try: () => getSharedIssueService().patchIssue(issueId, { canonicalStatus: canonicalStatus(state) }), catch: () => void 0 }).pipe(Effect.ignore);\n yield* emitEvent({\n type: 'issue.transitioned',\n timestamp: new Date().toISOString(),\n payload: { issueId, state },\n });\n }),\n\n addLabel: (issueId, label) =>\n Effect.gen(function* () {\n const trackerType = resolveTrackerTypeSync(issueId);\n if (trackerType !== 'github') return; // no-op for Linear/Rally\n\n const ghInfo = resolveGitHubIssueSync(issueId);\n if (!ghInfo.isGitHub) return;\n yield* github.addLabel(ghInfo.owner, ghInfo.repo, ghInfo.number, label);\n }),\n\n removeLabel: (issueId, label) =>\n Effect.gen(function* () {\n const trackerType = resolveTrackerTypeSync(issueId);\n if (trackerType !== 'github') return; // no-op for Linear/Rally\n\n const ghInfo = resolveGitHubIssueSync(issueId);\n if (!ghInfo.isGitHub) return;\n yield* github.removeLabel(ghInfo.owner, ghInfo.repo, ghInfo.number, label);\n }),\n\n close: (issueId) =>\n Effect.gen(function* () {\n const trackerType = resolveTrackerTypeSync(issueId);\n\n if (trackerType === 'github') {\n const ghInfo = resolveGitHubIssueSync(issueId);\n if (!ghInfo.isGitHub) return;\n // Remove workflow labels then close\n for (const label of ['in-progress', 'in-review', 'planned', 'in-planning', 'verifying-on-main', 'ready-for-merge']) {\n yield* github.removeLabel(ghInfo.owner, ghInfo.repo, ghInfo.number, label);\n }\n yield* github.closeIssue(ghInfo.owner, ghInfo.repo, ghInfo.number);\n } else if (trackerType === 'rally') {\n yield* rally.updateState(issueId, 'closed');\n } else {\n // Linear\n const issue = yield* linear.getIssue(issueId);\n const states = yield* linear.getTeamStates(issue.team.id);\n const target = findLinearState(states, 'closed');\n if (target) {\n yield* linear.updateState(issue.id, target.id);\n }\n }\n\n // Patch the in-memory cache and emit issue.closed domain event (non-fatal)\n yield* Effect.try({ try: () => getSharedIssueService().patchIssue(issueId, { canonicalStatus: 'closed' }), catch: () => void 0 }).pipe(Effect.ignore);\n yield* emitEvent({\n type: 'issue.closed',\n timestamp: new Date().toISOString(),\n payload: { issueId },\n });\n }),\n };\n\n return impl;\n }),\n);\n\n/**\n * Convenience layer that wires all tracker client dependencies.\n * Use this to provide IssueLifecycle without manually composing layers.\n */\nexport const IssueLifecycleWithClientLive = IssueLifecycleLive.pipe(\n Layer.provide(LinearClientOptionalLive),\n Layer.provide(GitHubClientOptionalLive),\n Layer.provide(RallyClientOptionalLive),\n);\n"],"mappings":"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"}