@overdeck/core 0.45.10 → 0.45.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-state-KVbJEG5f.js → agent-state-RLhS7ckO.js} +1 -1
- package/dist/{agents-pp8FO7Uj.js → agents-By3u_fQ8.js} +1 -1
- package/dist/{agents-CQHK0CSA.js → agents-CgVr77Qq.js} +12 -12
- package/dist/{agents-CQHK0CSA.js.map → agents-CgVr77Qq.js.map} +1 -1
- package/dist/{backlog-auto-trigger-CyuoS0nl.js → backlog-auto-trigger-B_-1tk4e.js} +5 -5
- package/dist/{backlog-auto-trigger-CyuoS0nl.js.map → backlog-auto-trigger-B_-1tk4e.js.map} +1 -1
- package/dist/cli/index.js +45 -45
- package/dist/{cli-Cewlu3yU.js → cli-DGeSW85B.js} +2 -2
- package/dist/{cli-Cewlu3yU.js.map → cli-DGeSW85B.js.map} +1 -1
- package/dist/cli-MTB9IOoR.js +3 -0
- package/dist/{close-issue-BJGX9_z7.js → close-issue-Djajb6Sv.js} +2 -2
- package/dist/{close-issue-BJGX9_z7.js.map → close-issue-Djajb6Sv.js.map} +1 -1
- package/dist/{concurrency-Ca-fC7tA.js → concurrency-4rzjHAQA.js} +1 -1
- package/dist/{conversation-compaction-B_6s9EvM.js → conversation-compaction-BQvZh09I.js} +4 -4
- package/dist/{conversation-compaction-B_6s9EvM.js.map → conversation-compaction-BQvZh09I.js.map} +1 -1
- package/dist/dashboard/{advancing-selfheal-CMlGznKv.js → advancing-selfheal-BezNfM3P.js} +3 -3
- package/dist/dashboard/{advancing-selfheal-CMlGznKv.js.map → advancing-selfheal-BezNfM3P.js.map} +1 -1
- package/dist/dashboard/{agent-state-xk_G8t90.js → agent-state-BUANcaA7.js} +1 -1
- package/dist/dashboard/{agent-state-service-C1iUF9Ft.js → agent-state-service-DmFpIMbP.js} +1 -1
- package/dist/dashboard/{agent-state-service-5ge9xxhx.js → agent-state-service-tXUdp6UF.js} +2 -2
- package/dist/dashboard/{agent-state-service-5ge9xxhx.js.map → agent-state-service-tXUdp6UF.js.map} +1 -1
- package/dist/dashboard/{agents-BIggLvi_.js → agents-C-vqmKDi.js} +1 -1
- package/dist/dashboard/{agents-DHvsjsuP.js → agents-C7V4odQ6.js} +11 -11
- package/dist/dashboard/{agents-DHvsjsuP.js.map → agents-C7V4odQ6.js.map} +1 -1
- package/dist/dashboard/{backlog-auto-trigger-COm_R96V.js → backlog-auto-trigger-Cb8PR-5w.js} +2 -2
- package/dist/dashboard/{backlog-auto-trigger-COm_R96V.js.map → backlog-auto-trigger-Cb8PR-5w.js.map} +1 -1
- package/dist/dashboard/{cli-CvK9xuSS.js → cli-BgzbB6h3.js} +2 -2
- package/dist/dashboard/{cli-CvK9xuSS.js.map → cli-BgzbB6h3.js.map} +1 -1
- package/dist/dashboard/cli-DCqy_wFa.js +3 -0
- package/dist/dashboard/{close-issue-BnpErnD1.js → close-issue-BWf3pxn4.js} +2 -2
- package/dist/dashboard/{close-issue-BnpErnD1.js.map → close-issue-BWf3pxn4.js.map} +1 -1
- package/dist/dashboard/{closed-issue-reaper-DRqK5k39.js → closed-issue-reaper-D7XPq5pY.js} +4 -4
- package/dist/dashboard/{closed-issue-reaper-DRqK5k39.js.map → closed-issue-reaper-D7XPq5pY.js.map} +1 -1
- package/dist/dashboard/{closed-issue-reaper-BLCQwTpF.js → closed-issue-reaper-VSTSTROK.js} +1 -1
- package/dist/dashboard/{conflict-gate-JdFuhKuF.js → conflict-gate-DwOslTij.js} +1 -1
- package/dist/dashboard/{conflict-gate-BhKvrPxn.js → conflict-gate-FFEvTDVA.js} +3 -3
- package/dist/dashboard/{conflict-gate-BhKvrPxn.js.map → conflict-gate-FFEvTDVA.js.map} +1 -1
- package/dist/dashboard/{conversation-compaction-C5o_eKEm.js → conversation-compaction-CCqN4hWk.js} +4 -4
- package/dist/dashboard/{conversation-compaction-C5o_eKEm.js.map → conversation-compaction-CCqN4hWk.js.map} +1 -1
- package/dist/dashboard/{conversation-compaction-Ba5aZdrb.js → conversation-compaction-CL5Ti4j4.js} +1 -1
- package/dist/dashboard/{deacon-j3qSZ7--.js → deacon-CGHl90eC.js} +107 -50
- package/dist/dashboard/{deacon-j3qSZ7--.js.map → deacon-CGHl90eC.js.map} +1 -1
- package/dist/dashboard/{deacon-Cv2RMfHs.js → deacon-DMPh40Im.js} +2 -2
- package/dist/dashboard/deacon-swarm-CVTiNL0N.js +2 -0
- package/dist/dashboard/{deacon-swarm-DadWNi5J.js → deacon-swarm-aMMJTq6t.js} +4 -4
- package/dist/dashboard/{deacon-swarm-DadWNi5J.js.map → deacon-swarm-aMMJTq6t.js.map} +1 -1
- package/dist/dashboard/deacon.js +4 -4
- package/dist/dashboard/{feedback-target-oE4-Esxl.js → feedback-target-dJjFfITP.js} +4 -4
- package/dist/dashboard/{feedback-target-oE4-Esxl.js.map → feedback-target-dJjFfITP.js.map} +1 -1
- package/dist/dashboard/{feedback-target-C4DaDSZ8.js → feedback-target-nQSM6ygL.js} +1 -1
- package/dist/dashboard/{flywheel-ClMjGW_u.js → flywheel-BLoVNtJV.js} +6 -6
- package/dist/dashboard/{flywheel-ClMjGW_u.js.map → flywheel-BLoVNtJV.js.map} +1 -1
- package/dist/dashboard/{flywheel-DefHRzY4.js → flywheel-Cqf8vu7N.js} +6 -6
- package/dist/dashboard/{flywheel-DefHRzY4.js.map → flywheel-Cqf8vu7N.js.map} +1 -1
- package/dist/dashboard/{flywheel-BqDdGvrQ.js → flywheel-PJsbrXNY.js} +1 -1
- package/dist/dashboard/{flywheel-merge-order-CuDcqTRJ.js → flywheel-merge-order-B7BH8mZ3.js} +2 -2
- package/dist/dashboard/{flywheel-merge-order-CuDcqTRJ.js.map → flywheel-merge-order-B7BH8mZ3.js.map} +1 -1
- package/dist/dashboard/{flywheel-merge-order-B6YDSElh.js → flywheel-merge-order-CCwF60b-.js} +1 -1
- package/dist/dashboard/{harness-resolve-DKeSVsJL.js → harness-resolve-B3f9G1Kp.js} +2 -2
- package/dist/dashboard/{harness-resolve-DKeSVsJL.js.map → harness-resolve-B3f9G1Kp.js.map} +1 -1
- package/dist/dashboard/{inspect-agent-BKKc0XnB.js → inspect-agent-CKF5-SJr.js} +3 -3
- package/dist/dashboard/{inspect-agent-BKKc0XnB.js.map → inspect-agent-CKF5-SJr.js.map} +1 -1
- package/dist/dashboard/inspect-agent-CqpEWGWy.js +2 -0
- package/dist/dashboard/{issue-lifecycle-DnhQgddB.js → issue-lifecycle-5LbOcATP.js} +7 -7
- package/dist/dashboard/{issue-lifecycle-DnhQgddB.js.map → issue-lifecycle-5LbOcATP.js.map} +1 -1
- package/dist/dashboard/{issue-lifecycle-nY4esZn8.js → issue-lifecycle-CjYqQ669.js} +1 -1
- package/dist/dashboard/{issue-service-singleton-Bnqv1uaa.js → issue-service-singleton-B8iu_TKV.js} +1 -1
- package/dist/dashboard/{issue-service-singleton-_AquSBTl.js → issue-service-singleton-CDGt__oQ.js} +2 -2
- package/dist/dashboard/{issue-service-singleton-_AquSBTl.js.map → issue-service-singleton-CDGt__oQ.js.map} +1 -1
- package/dist/dashboard/{lifecycle-CGKm7doE.js → lifecycle-CEg4sHZH.js} +4 -4
- package/dist/dashboard/{lifecycle-CGKm7doE.js.map → lifecycle-CEg4sHZH.js.map} +1 -1
- package/dist/dashboard/{merge-agent-Dh8Y9PDO.js → merge-agent-7nBiCytp.js} +1 -1
- package/dist/dashboard/{merge-agent-BcgAYStl.js → merge-agent-C81xPIGd.js} +6 -6
- package/dist/dashboard/{merge-agent-BcgAYStl.js.map → merge-agent-C81xPIGd.js.map} +1 -1
- package/dist/dashboard/merge-ops-DE_6CnmZ.js +2 -0
- package/dist/dashboard/{merge-train-DmxlYbEo.js → merge-train-D3qzRccL.js} +2 -2
- package/dist/dashboard/{merge-train-DmxlYbEo.js.map → merge-train-D3qzRccL.js.map} +1 -1
- package/dist/dashboard/{merge-train-deps-DBHsOWt9.js → merge-train-deps-Be5ElC_P.js} +2 -2
- package/dist/dashboard/{merge-train-deps-DBHsOWt9.js.map → merge-train-deps-Be5ElC_P.js.map} +1 -1
- package/dist/dashboard/{orphan-proposed-reconciler-Db8tUhce.js → orphan-proposed-reconciler-Boq_XaRe.js} +3 -3
- package/dist/dashboard/{orphan-proposed-reconciler-Db8tUhce.js.map → orphan-proposed-reconciler-Boq_XaRe.js.map} +1 -1
- package/dist/dashboard/{orphan-proposed-reconciler-mXV--tcB.js → orphan-proposed-reconciler-C0sPnDq_.js} +1 -1
- package/dist/dashboard/{reconstruct-cache-_tDZ2D72.js → reconstruct-cache-C2pCltOq.js} +3 -3
- package/dist/dashboard/{reconstruct-cache-_tDZ2D72.js.map → reconstruct-cache-C2pCltOq.js.map} +1 -1
- package/dist/dashboard/{remote-completion-Bklh6loJ.js → remote-completion-BmxD5UMQ.js} +3 -3
- package/dist/dashboard/{remote-completion-Bklh6loJ.js.map → remote-completion-BmxD5UMQ.js.map} +1 -1
- package/dist/dashboard/resume-C-nxu9Y4.js +3 -0
- package/dist/dashboard/{review-agent-phzqNqIs.js → review-agent-D6P6d3pz.js} +26 -17
- package/dist/dashboard/review-agent-D6P6d3pz.js.map +1 -0
- package/dist/dashboard/review-agent-DTINEffB.js +3 -0
- package/dist/dashboard/{review-context-CCq56O_Y.js → review-context-Dyo0tsBa.js} +2 -2
- package/dist/dashboard/{review-context-CCq56O_Y.js.map → review-context-Dyo0tsBa.js.map} +1 -1
- package/dist/dashboard/{review-status-BQjqQXZG.js → review-status-B5ZASOo4.js} +18 -5
- package/dist/dashboard/review-status-B5ZASOo4.js.map +1 -0
- package/dist/dashboard/{review-status-bBkqUj5i.js → review-status-h7BXIA4z.js} +1 -1
- package/dist/dashboard/{review-verdict-feedback-wqnikhMK.js → review-verdict-feedback-B70VbfRL.js} +4 -4
- package/dist/dashboard/{review-verdict-feedback-wqnikhMK.js.map → review-verdict-feedback-B70VbfRL.js.map} +1 -1
- package/dist/dashboard/{review-verdict-feedback-cZh9Wi9G.js → review-verdict-feedback-CorgH49f.js} +1 -1
- package/dist/dashboard/{sequence-io-B2GmilSI.js → sequence-io-6YP8fVpH.js} +2 -2
- package/dist/dashboard/{sequence-io-B2GmilSI.js.map → sequence-io-6YP8fVpH.js.map} +1 -1
- package/dist/dashboard/{sequencer-agent-D8pW2aU_.js → sequencer-agent-ja-nkEc1.js} +5 -5
- package/dist/dashboard/{sequencer-agent-D8pW2aU_.js.map → sequencer-agent-ja-nkEc1.js.map} +1 -1
- package/dist/dashboard/server.js +66 -55
- package/dist/dashboard/server.js.map +1 -1
- package/dist/dashboard/{service-CILd-uOt.js → service-HKDrIy0h.js} +24 -24
- package/dist/dashboard/{service-CILd-uOt.js.map → service-HKDrIy0h.js.map} +1 -1
- package/dist/dashboard/{smart-compaction-Bgp_gwcA.js → smart-compaction-L0LSnF0_.js} +1 -1
- package/dist/dashboard/{smart-compaction-CrP90OFE.js → smart-compaction-uke1npUz.js} +2 -2
- package/dist/dashboard/{smart-compaction-CrP90OFE.js.map → smart-compaction-uke1npUz.js.map} +1 -1
- package/dist/dashboard/{spawn-planning-session-D15KbPOy.js → spawn-planning-session-CSMWco8B.js} +1 -1
- package/dist/dashboard/{spawn-planning-session-BmJWHSCu.js → spawn-planning-session-CXc0NkwV.js} +3 -3
- package/dist/dashboard/{spawn-planning-session-BmJWHSCu.js.map → spawn-planning-session-CXc0NkwV.js.map} +1 -1
- package/dist/dashboard/{specialist-context-CwKkcXL9.js → specialist-context-BGCJ24LH.js} +3 -3
- package/dist/dashboard/{specialist-context-CwKkcXL9.js.map → specialist-context-BGCJ24LH.js.map} +1 -1
- package/dist/dashboard/{specialist-logs-CvDxquV_.js → specialist-logs--Uz-r8ia.js} +2 -2
- package/dist/dashboard/{specialist-logs-CvDxquV_.js.map → specialist-logs--Uz-r8ia.js.map} +1 -1
- package/dist/dashboard/{specialists-BCjcG4uE.js → specialists-Ca9XSBCS.js} +1 -1
- package/dist/dashboard/{specialists-D07ybnam.js → specialists-DEfrAbWs.js} +36 -36
- package/dist/dashboard/{specialists-D07ybnam.js.map → specialists-DEfrAbWs.js.map} +1 -1
- package/dist/dashboard/{specialists-F2uMO4QS.js → specialists-DeZx9xom.js} +1 -1
- package/dist/dashboard/{specialists-BYi0k8CZ.js → specialists-nZ0mRwpZ.js} +12 -12
- package/dist/dashboard/{specialists-BYi0k8CZ.js.map → specialists-nZ0mRwpZ.js.map} +1 -1
- package/dist/dashboard/{summary-fork-DedqguZb.js → summary-fork-2a1L2DIU.js} +2 -2
- package/dist/dashboard/{summary-fork-EjvOkEPl.js → summary-fork-Xn0QUNmb.js} +3 -3
- package/dist/dashboard/{summary-fork-EjvOkEPl.js.map → summary-fork-Xn0QUNmb.js.map} +1 -1
- package/dist/dashboard/{teardown-workspace-5LCVbjfq.js → teardown-workspace-DhA6oAIK.js} +2 -2
- package/dist/dashboard/{teardown-workspace-5LCVbjfq.js.map → teardown-workspace-DhA6oAIK.js.map} +1 -1
- package/dist/dashboard/{test-agent-queue-qfsq6uaC.js → test-agent-queue-B_ukPyIK.js} +3 -3
- package/dist/dashboard/{test-agent-queue-qfsq6uaC.js.map → test-agent-queue-B_ukPyIK.js.map} +1 -1
- package/dist/dashboard/{uat-train-CtNGgXxj.js → uat-train-BLBAbJ8Y.js} +10 -10
- package/dist/dashboard/{uat-train-CtNGgXxj.js.map → uat-train-BLBAbJ8Y.js.map} +1 -1
- package/dist/dashboard/{uat-train-C3hWXtip.js → uat-train-DPfGR9_I.js} +1 -1
- package/dist/dashboard/{verification-runner-DuZRHjPU.js → verification-runner-KTGTNugM.js} +1 -1
- package/dist/dashboard/{verification-runner-BPAhPWR7.js → verification-runner-R2-4XgMO.js} +4 -4
- package/dist/dashboard/{verification-runner-BPAhPWR7.js.map → verification-runner-R2-4XgMO.js.map} +1 -1
- package/dist/dashboard/{workflows-H-COJ84X.js → workflows-CSKX5MhC.js} +7 -7
- package/dist/dashboard/{workflows-H-COJ84X.js.map → workflows-CSKX5MhC.js.map} +1 -1
- package/dist/dashboard/workflows-DVwXauef.js +2 -0
- package/dist/dashboard/{workspaces-CRU9_vRn.js → workspaces-DXLDgXo2.js} +32 -32
- package/dist/dashboard/{workspaces-CRU9_vRn.js.map → workspaces-DXLDgXo2.js.map} +1 -1
- package/dist/docs-index.sqlite +0 -0
- package/dist/{feedback-target-DTGAhFkM.js → feedback-target-BsKN4Tr_.js} +4 -4
- package/dist/{feedback-target-DTGAhFkM.js.map → feedback-target-BsKN4Tr_.js.map} +1 -1
- package/dist/{feedback-target-DutF088V.js → feedback-target-DM1WzOKy.js} +1 -1
- package/dist/{harness-resolve-Bz1prk6B.js → harness-resolve-B-YDNwNW.js} +2 -2
- package/dist/{harness-resolve-Bz1prk6B.js.map → harness-resolve-B-YDNwNW.js.map} +1 -1
- package/dist/{issue-lifecycle-fVqvCdKM.js → issue-lifecycle-Bc1l3U9f.js} +7 -7
- package/dist/{issue-lifecycle-fVqvCdKM.js.map → issue-lifecycle-Bc1l3U9f.js.map} +1 -1
- package/dist/{issue-service-singleton-CZm8p6Rj.js → issue-service-singleton-D-8Q6tdT.js} +1 -1
- package/dist/{issue-service-singleton-Cr73JAaR.js → issue-service-singleton-D1433I7n.js} +2 -2
- package/dist/{issue-service-singleton-Cr73JAaR.js.map → issue-service-singleton-D1433I7n.js.map} +1 -1
- package/dist/{lifecycle-CR6tZfl1.js → lifecycle-SmrqysDf.js} +7 -7
- package/dist/{lifecycle-CR6tZfl1.js.map → lifecycle-SmrqysDf.js.map} +1 -1
- package/dist/{lifecycle-D_EWiUjk.js → lifecycle-mRMyiIXs.js} +2 -2
- package/dist/{merge-agent-LM4avOtA.js → merge-agent-B9hIZ6Z0.js} +6 -6
- package/dist/{merge-agent-LM4avOtA.js.map → merge-agent-B9hIZ6Z0.js.map} +1 -1
- package/dist/{merge-agent-Bj046HE1.js → merge-agent-DUj22cXL.js} +1 -1
- package/dist/{merge-fulfillment-DrnC1Kmg.js → merge-fulfillment-__P4WE-T.js} +3 -3
- package/dist/{merge-fulfillment-DrnC1Kmg.js.map → merge-fulfillment-__P4WE-T.js.map} +1 -1
- package/dist/{reconstruct-cache-NPqoAUg-.js → reconstruct-cache-9SWp82SQ.js} +3 -3
- package/dist/{reconstruct-cache-NPqoAUg-.js.map → reconstruct-cache-9SWp82SQ.js.map} +1 -1
- package/dist/{records-BIkN1LQ4.js → records-CTmvuRzz.js} +14 -1
- package/dist/{records-BIkN1LQ4.js.map → records-CTmvuRzz.js.map} +1 -1
- package/dist/records-backfill-BQcmTmwF.js +2 -0
- package/dist/{records-backfill-HM0Pln6N.js → records-backfill-BrNsv_zT.js} +2 -2
- package/dist/{records-backfill-HM0Pln6N.js.map → records-backfill-BrNsv_zT.js.map} +1 -1
- package/dist/resume-Bn4kDk9x.js +3 -0
- package/dist/{review-agent-DFosQzCG.js → review-agent-PhqOhpx3.js} +24 -16
- package/dist/{review-agent-DFosQzCG.js.map → review-agent-PhqOhpx3.js.map} +1 -1
- package/dist/review-agent-hLbRRxZF.js +3 -0
- package/dist/{review-status-iJwfEoNX.js → review-status-B_XXomV0.js} +6 -6
- package/dist/{review-status-iJwfEoNX.js.map → review-status-B_XXomV0.js.map} +1 -1
- package/dist/{review-status-BbNVlXh1.js → review-status-Bo-EFVKh.js} +1 -1
- package/dist/{review-verdict-feedback-BGPw3z1X.js → review-verdict-feedback-CXHkoiKZ.js} +1 -1
- package/dist/{review-verdict-feedback-CCZ05atV.js → review-verdict-feedback-DGV13LDb.js} +4 -4
- package/dist/{review-verdict-feedback-CCZ05atV.js.map → review-verdict-feedback-DGV13LDb.js.map} +1 -1
- package/dist/{sequence-io-CcxZNHcD.js → sequence-io-Cg4NHAco.js} +1 -1
- package/dist/{sequence-io-Cx1usxG3.js → sequence-io-CyxvNHfA.js} +2 -2
- package/dist/{sequence-io-Cx1usxG3.js.map → sequence-io-CyxvNHfA.js.map} +1 -1
- package/dist/{smart-compaction-ByUEgQkF.js → smart-compaction-ByKXTQNy.js} +2 -2
- package/dist/{smart-compaction-ByUEgQkF.js.map → smart-compaction-ByKXTQNy.js.map} +1 -1
- package/dist/{smart-compaction-DfLe_CtH.js → smart-compaction-U6e_uB1E.js} +1 -1
- package/dist/{specialist-context-McuGkaeR.js → specialist-context-BUTadO-U.js} +3 -3
- package/dist/{specialist-context-McuGkaeR.js.map → specialist-context-BUTadO-U.js.map} +1 -1
- package/dist/{specialist-logs-CUUJ4eiB.js → specialist-logs-pEMCTtGZ.js} +2 -2
- package/dist/{specialist-logs-CUUJ4eiB.js.map → specialist-logs-pEMCTtGZ.js.map} +1 -1
- package/dist/{specialists-BSrylD1S.js → specialists-BGFnrQ8n.js} +1 -1
- package/dist/{specialists-B0elgInc.js → specialists-DeTkkp8b.js} +12 -12
- package/dist/{specialists-B0elgInc.js.map → specialists-DeTkkp8b.js.map} +1 -1
- package/dist/{summary-fork-DskMRnyb.js → summary-fork-CgzThE2-.js} +2 -2
- package/dist/{summary-fork-CPUTKcAT.js → summary-fork-Dx1RMuvU.js} +3 -3
- package/dist/{summary-fork-CPUTKcAT.js.map → summary-fork-Dx1RMuvU.js.map} +1 -1
- package/dist/{sync-BiNVQHBf.js → sync-Bsww9tuj.js} +2 -2
- package/dist/{sync-BiNVQHBf.js.map → sync-Bsww9tuj.js.map} +1 -1
- package/dist/sync-CylE_SjB.js +2 -0
- package/dist/{verdict-restore-DQiV7_fe.js → verdict-restore-DGpX0ZOJ.js} +5 -5
- package/dist/{verdict-restore-DQiV7_fe.js.map → verdict-restore-DGpX0ZOJ.js.map} +1 -1
- package/dist/{webhook-handlers-DHBSEDEm.js → webhook-handlers-BjsfIL7u.js} +3 -3
- package/dist/{webhook-handlers-DHBSEDEm.js.map → webhook-handlers-BjsfIL7u.js.map} +1 -1
- package/dist/{workspace-migrate-duUsWNpd.js → workspace-migrate-BBQ8nAnP.js} +2 -2
- package/dist/{workspace-migrate-duUsWNpd.js.map → workspace-migrate-BBQ8nAnP.js.map} +1 -1
- package/dist/{workspace-reap-DLCIoJmn.js → workspace-reap-12O9354k.js} +2 -2
- package/dist/{workspace-reap-DLCIoJmn.js.map → workspace-reap-12O9354k.js.map} +1 -1
- package/package.json +1 -1
- package/scripts/file-size-baseline.txt +1 -1
- package/dist/cli-DBWG12XK.js +0 -3
- package/dist/dashboard/cli-CJDWXE_Y.js +0 -3
- package/dist/dashboard/deacon-swarm-D1iAUX-P.js +0 -2
- package/dist/dashboard/inspect-agent-vm88mLYr.js +0 -2
- package/dist/dashboard/merge-ops-QdBiQ8XB.js +0 -2
- package/dist/dashboard/resume-DnIsmIgC.js +0 -3
- package/dist/dashboard/review-agent-DgySDb-G.js +0 -3
- package/dist/dashboard/review-agent-phzqNqIs.js.map +0 -1
- package/dist/dashboard/review-status-BQjqQXZG.js.map +0 -1
- package/dist/dashboard/workflows-Cz8OtiB4.js +0 -2
- package/dist/records-backfill-DEgtRyKL.js +0 -2
- package/dist/resume-DGymuXZM.js +0 -3
- package/dist/review-agent-DjVadURa.js +0 -3
- package/dist/sync-4jqukkxz.js +0 -2
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { r as init_issue_id, t as extractNumberSync } from "./issue-id-DfZZfSZC.js";
|
|
2
2
|
import { A as resolveProjectFromIssueSync, f as getProjectSync, v as init_projects, w as loadProjectsConfigSync } from "./projects-D2nMJ9C4.js";
|
|
3
3
|
import { l as init_record, m as readIssueRecordSync, t as RECORD_DIRNAME } from "./record-osVNNpoC.js";
|
|
4
|
-
import { a as init_review_status, m as setReviewStatusSync } from "./review-status-
|
|
4
|
+
import { a as init_review_status, m as setReviewStatusSync } from "./review-status-B_XXomV0.js";
|
|
5
5
|
import { c as getPullRequestState, l as init_github_app, u as isGitHubAppConfigured } from "./github-app-gWjUXbe7.js";
|
|
6
|
-
import { t as WORKFLOW_LABELS } from "./close-issue-
|
|
6
|
+
import { t as WORKFLOW_LABELS } from "./close-issue-Djajb6Sv.js";
|
|
7
7
|
import { n as init_label_cleanup, t as cleanupMergedLabels } from "./label-cleanup-BBU-eswT.js";
|
|
8
8
|
import { Effect } from "effect";
|
|
9
9
|
import { existsSync } from "node:fs";
|
|
@@ -420,4 +420,4 @@ async function reconcileMergeFulfillment(options = {}, deps = {}) {
|
|
|
420
420
|
//#endregion
|
|
421
421
|
export { reconcileMergeFulfillment };
|
|
422
422
|
|
|
423
|
-
//# sourceMappingURL=merge-fulfillment-
|
|
423
|
+
//# sourceMappingURL=merge-fulfillment-__P4WE-T.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge-fulfillment-DrnC1Kmg.js","names":[],"sources":["../src/lib/pan-dir/merge-fulfillment.ts"],"sourcesContent":["import { exec } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { readdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\nimport { Effect } from 'effect';\n\nimport { getPullRequestState, isGitHubAppConfigured } from '../github-app.js';\nimport { extractNumberSync } from '../issue-id.js';\nimport { cleanupMergedLabels } from '../lifecycle/label-cleanup.js';\nimport type { LifecycleContext, StepResult } from '../lifecycle/types.js';\nimport { getProjectSync, loadProjectsConfigSync, resolveProjectFromIssueSync, type ProjectConfig } from '../projects.js';\nimport { setReviewStatusSync, type ReviewStatus } from '../review-status.js';\nimport { WORKFLOW_LABELS } from '../lifecycle/close-issue.js';\nimport { readIssueRecordSync, RECORD_DIRNAME, type PanIssueRecord } from './record.js';\n\nconst execAsync = promisify(exec);\n\nexport type MergeFulfillmentVerdict = 'merged' | 'stranded' | 'unknown';\n\nexport interface MergeFulfillmentResult {\n verdict: MergeFulfillmentVerdict;\n evidence: string;\n}\n\ninterface PullRequestMergeProbe {\n result: MergeFulfillmentResult | null;\n errorEvidence?: string;\n}\n\nexport interface MergeFulfillmentDeps {\n readRecord(project: ProjectConfig, issueId: string): PanIssueRecord | null;\n exec(command: string, options: { cwd: string }): Promise<{ stdout: string; stderr: string }>;\n isGitHubAppConfigured(): boolean;\n getPullRequestState(owner: string, repo: string, number: number): Promise<{ merged: boolean; state?: string }>;\n setReviewStatus?(issueId: string, update: Partial<ReviewStatus>): ReviewStatus;\n cleanupMergedLabels?(ctx: LifecycleContext): Promise<StepResult>;\n}\n\nconst defaultDeps: MergeFulfillmentDeps = {\n readRecord: readIssueRecordSync,\n exec: (command, options) => execAsync(command, options),\n isGitHubAppConfigured,\n getPullRequestState: async (owner, repo, number) => Effect.runPromise(getPullRequestState(owner, repo, number)),\n setReviewStatus: setReviewStatusSync,\n cleanupMergedLabels: (ctx) => Effect.runPromise(cleanupMergedLabels(ctx)),\n};\n\ntype ResolvedMergeFulfillmentDeps = MergeFulfillmentDeps & Required<Pick<MergeFulfillmentDeps, 'setReviewStatus' | 'cleanupMergedLabels'>>;\n\nexport interface ReconcileMergedIssueOptions {\n closed?: boolean;\n dryRun?: boolean;\n}\n\nexport interface ReconcileMergedIssueResult {\n issueId: string;\n dryRun: boolean;\n skipped: boolean;\n actions: string[];\n branchActions: Array<{\n branch: string;\n status: 'deleted' | 'kept' | 'missing' | 'planned-delete' | 'planned-keep';\n reason: string;\n }>;\n}\n\nexport interface ReconcileMergeFulfillmentOptions {\n issueId?: string;\n dryRun?: boolean;\n verbose?: boolean;\n}\n\nexport interface ReconcileMergeFulfillmentDetail {\n issueId: string;\n action: 'reconciled' | 'would-reconcile' | 'flagged' | 'skipped' | 'failed';\n verdict?: MergeFulfillmentVerdict;\n evidence?: string;\n reason?: string;\n}\n\nexport interface ReconcileMergeFulfillmentResult {\n reconciled: number;\n flagged: number;\n skipped: number;\n failed: number;\n details: ReconcileMergeFulfillmentDetail[];\n}\n\nconst CLOSED_OUT_LABEL = 'closed-out';\nconst CLOSED_OUT_COLOR = '1d4ed8';\n\nfunction shellQuote(value: string): string {\n return `'${value.replace(/'/g, `'\"'\"'`)}'`;\n}\n\nfunction mergeBranchRefs(issueId: string): string[] {\n const suffix = issueId.toLowerCase();\n return [\n `feature/${suffix}`,\n `strike/${suffix}`,\n `origin/feature/${suffix}`,\n `origin/strike/${suffix}`,\n ];\n}\n\nfunction remoteBranchName(ref: string): string {\n return ref.startsWith('origin/') ? ref.slice('origin/'.length) : ref;\n}\n\nfunction resolveDeps(deps: Partial<MergeFulfillmentDeps>): ResolvedMergeFulfillmentDeps {\n return { ...defaultDeps, ...deps } as ResolvedMergeFulfillmentDeps;\n}\n\nfunction parseGitHubPullRequestUrl(url: string | undefined): { owner: string; repo: string; number: number } | null {\n const match = url?.match(/github\\.com\\/([^/]+)\\/([^/]+)\\/pull\\/(\\d+)/i);\n if (!match) return null;\n return {\n owner: match[1]!,\n repo: match[2]!,\n number: Number.parseInt(match[3]!, 10),\n };\n}\n\nfunction prRefFromRecord(project: ProjectConfig, record: PanIssueRecord | null): { owner: string; repo: string; number: number } | null {\n const fromUrl = parseGitHubPullRequestUrl(record?.pipeline?.prUrl);\n if (fromUrl) return fromUrl;\n const prNumber = record?.pipeline?.prNumber;\n if (!prNumber || !project.github_repo) return null;\n const [owner, repo] = project.github_repo.split('/');\n return owner && repo ? { owner, repo, number: prNumber } : null;\n}\n\nfunction isExitOne(error: unknown): boolean {\n return typeof error === 'object' && error !== null && 'code' in error && (error as { code?: unknown }).code === 1;\n}\n\nasync function prMerged(\n issueId: string,\n project: ProjectConfig,\n record: PanIssueRecord | null,\n deps: MergeFulfillmentDeps,\n): Promise<PullRequestMergeProbe> {\n const pr = prRefFromRecord(project, record);\n if (!pr) return { result: null };\n\n if (deps.isGitHubAppConfigured()) {\n try {\n const state = await deps.getPullRequestState(pr.owner, pr.repo, pr.number);\n if (state.merged) {\n return { result: { verdict: 'merged', evidence: `${issueId} PR #${pr.number} reports merged via GitHub App` } };\n }\n return { result: null };\n } catch (err) {\n return {\n result: null,\n errorEvidence: `${issueId} PR #${pr.number} state could not be resolved via GitHub App: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n }\n\n try {\n const { stdout } = await deps.exec(\n `gh pr view ${pr.number} --repo ${shellQuote(`${pr.owner}/${pr.repo}`)} --json merged,mergedAt,mergeCommit,state`,\n { cwd: project.path },\n );\n const parsed = JSON.parse(stdout || '{}') as { merged?: boolean; mergedAt?: string | null; mergeCommit?: unknown; state?: string };\n if (parsed.merged === true || parsed.mergedAt || parsed.mergeCommit) {\n return { result: { verdict: 'merged', evidence: `${issueId} PR #${pr.number} reports merged via gh` } };\n }\n return { result: null };\n } catch (err) {\n return {\n result: null,\n errorEvidence: `${issueId} PR #${pr.number} state could not be resolved via gh: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n}\n\nasync function branchExists(branch: string, project: ProjectConfig, deps: MergeFulfillmentDeps): Promise<boolean | 'unknown'> {\n try {\n await deps.exec(`git rev-parse --verify ${shellQuote(branch)}`, { cwd: project.path });\n return true;\n } catch (err) {\n return isExitOne(err) ? false : 'unknown';\n }\n}\n\nasync function branchIsMerged(branch: string, project: ProjectConfig, deps: MergeFulfillmentDeps): Promise<boolean | 'unknown'> {\n try {\n await deps.exec(`git merge-base --is-ancestor ${shellQuote(branch)} origin/main`, { cwd: project.path });\n return true;\n } catch (err) {\n return isExitOne(err) ? false : 'unknown';\n }\n}\n\nfunction lifecycleContext(issueId: string, project: ProjectConfig): LifecycleContext {\n const github = project.github_repo && extractNumberSync(issueId) !== null\n ? (() => {\n const [owner, repo] = project.github_repo!.split('/');\n const number = extractNumberSync(issueId);\n return owner && repo && number !== null ? { owner, repo, number } : undefined;\n })()\n : undefined;\n\n return {\n issueId,\n projectPath: project.path,\n projectName: project.name,\n ...(github ? { github } : {}),\n };\n}\n\nasync function collectRecordIssueIdsFromDir(dir: string): Promise<Set<string>> {\n const ids = new Set<string>();\n if (!existsSync(dir)) return ids;\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isFile()) continue;\n const match = entry.name.match(/^([a-z]+-\\d+)\\.json$/i);\n if (match) ids.add(match[1]!.toUpperCase());\n }\n } catch {\n // Directory may be unreadable; skip it.\n }\n return ids;\n}\n\nasync function collectRecordIssueIds(projects: ProjectConfig[]): Promise<Set<string>> {\n const ids = new Set<string>();\n for (const project of projects) {\n for (const id of await collectRecordIssueIdsFromDir(join(project.path, '.pan', RECORD_DIRNAME))) ids.add(id);\n\n const workspacesDir = join(project.path, project.workspace?.workspaces_dir ?? 'workspaces');\n if (!existsSync(workspacesDir)) continue;\n try {\n const workspaces = await readdir(workspacesDir, { withFileTypes: true });\n for (const workspace of workspaces) {\n if (!workspace.isDirectory()) continue;\n const recordsDir = join(workspacesDir, workspace.name, '.pan', RECORD_DIRNAME);\n for (const id of await collectRecordIssueIdsFromDir(recordsDir)) ids.add(id);\n }\n } catch {\n // Workspaces directory may be absent or unreadable; skip it.\n }\n }\n return ids;\n}\n\nasync function readIssueRecordFromKnownPaths(project: ProjectConfig, issueId: string): Promise<PanIssueRecord | null> {\n const direct = readIssueRecordSync(project, issueId);\n if (direct) return direct;\n\n const workspacesDir = join(project.path, project.workspace?.workspaces_dir ?? 'workspaces');\n if (!existsSync(workspacesDir)) return null;\n try {\n const workspaces = await readdir(workspacesDir, { withFileTypes: true });\n for (const workspace of workspaces) {\n if (!workspace.isDirectory()) continue;\n const path = join(workspacesDir, workspace.name, '.pan', RECORD_DIRNAME, `${issueId.toLowerCase()}.json`);\n try {\n return JSON.parse(await readFile(path, 'utf-8')) as PanIssueRecord;\n } catch {\n // Try the next workspace.\n }\n }\n } catch {\n return null;\n }\n return null;\n}\n\nfunction shouldApplyClosedOutLabel(record: PanIssueRecord | null): boolean {\n return record?.pipeline?.closedOut === true || Boolean(record?.closeOut?.closedAt);\n}\n\nasync function issueIsClosed(issueId: string, project: ProjectConfig, record: PanIssueRecord, deps: MergeFulfillmentDeps): Promise<boolean | 'unknown'> {\n if (shouldApplyClosedOutLabel(record)) return true;\n if (!project.github_repo) return 'unknown';\n const number = extractNumberSync(issueId);\n if (number === null) return 'unknown';\n\n try {\n const { stdout } = await deps.exec(\n `gh issue view ${number} --repo ${shellQuote(project.github_repo)} --json state`,\n { cwd: project.path },\n );\n const parsed = JSON.parse(stdout || '{}') as { state?: string };\n if (parsed.state === 'CLOSED') return true;\n if (parsed.state === 'OPEN') return false;\n return 'unknown';\n } catch {\n return 'unknown';\n }\n}\n\nasync function applyClosedOutLabel(issueId: string, project: ProjectConfig, deps: MergeFulfillmentDeps): Promise<string> {\n if (!project.github_repo) {\n return 'skipped closed-out label: project has no GitHub repo';\n }\n const number = extractNumberSync(issueId);\n if (number === null) {\n return 'skipped closed-out label: issue number could not be parsed';\n }\n const [owner, repo] = project.github_repo.split('/');\n if (!owner || !repo) {\n return 'skipped closed-out label: project GitHub repo is invalid';\n }\n\n const repoSlug = `${owner}/${repo}`;\n await deps.exec(\n `gh label create ${shellQuote(CLOSED_OUT_LABEL)} --repo ${shellQuote(repoSlug)} --color ${shellQuote(CLOSED_OUT_COLOR)} --description ${shellQuote('Verified and closed out')} --force`,\n { cwd: project.path },\n );\n for (const label of WORKFLOW_LABELS) {\n await deps.exec(\n `gh issue edit ${number} --repo ${shellQuote(repoSlug)} --remove-label ${shellQuote(label)}`,\n { cwd: project.path },\n ).catch(() => ({ stdout: '', stderr: '' }));\n }\n await deps.exec(\n `gh issue edit ${number} --repo ${shellQuote(repoSlug)} --add-label ${shellQuote(CLOSED_OUT_LABEL)}`,\n { cwd: project.path },\n );\n return `applied closed-out label to ${issueId}`;\n}\n\nasync function reconcileBranch(\n branch: string,\n project: ProjectConfig,\n dryRun: boolean,\n deps: MergeFulfillmentDeps,\n): Promise<ReconcileMergedIssueResult['branchActions'][number]> {\n const exists = await branchExists(branch, project, deps);\n if (exists === 'unknown') {\n return { branch, status: 'kept', reason: 'branch existence could not be resolved' };\n }\n if (!exists) {\n return { branch, status: 'missing', reason: 'branch was not found' };\n }\n\n const merged = await branchIsMerged(branch, project, deps);\n if (merged !== true) {\n return {\n branch,\n status: dryRun ? 'planned-keep' : 'kept',\n reason: merged === 'unknown' ? 'branch ancestry could not be resolved' : 'branch is not an ancestor of origin/main',\n };\n }\n\n if (dryRun) {\n return { branch, status: 'planned-delete', reason: 'branch is an ancestor of origin/main' };\n }\n\n if (branch.startsWith('origin/')) {\n await deps.exec(`git push origin --delete ${shellQuote(remoteBranchName(branch))}`, { cwd: project.path }).catch(() => ({ stdout: '', stderr: '' }));\n } else {\n await deps.exec(`git branch -D ${shellQuote(branch)}`, { cwd: project.path });\n }\n return { branch, status: 'deleted', reason: 'branch is an ancestor of origin/main' };\n}\n\nexport async function verifyIssueMergeFulfillment(\n issueId: string,\n project: ProjectConfig,\n deps: Partial<MergeFulfillmentDeps> = {},\n): Promise<MergeFulfillmentResult> {\n const normalized = issueId.toUpperCase();\n const mergedDeps = resolveDeps(deps);\n const record = mergedDeps.readRecord(project, normalized);\n\n const prResult = await prMerged(normalized, project, record, mergedDeps);\n if (prResult.result) return prResult.result;\n\n let sawExistingBranch = false;\n for (const branch of mergeBranchRefs(normalized)) {\n const exists = await branchExists(branch, project, mergedDeps);\n if (exists === 'unknown') {\n return { verdict: 'unknown', evidence: `${normalized} branch ${branch} existence could not be resolved` };\n }\n if (!exists) continue;\n sawExistingBranch = true;\n\n const merged = await branchIsMerged(branch, project, mergedDeps);\n if (merged === true) {\n return { verdict: 'merged', evidence: `${branch} is an ancestor of origin/main` };\n }\n if (merged === 'unknown') {\n return { verdict: 'unknown', evidence: `${normalized} branch ${branch} ancestry could not be resolved` };\n }\n }\n\n if (sawExistingBranch) {\n if (prResult.errorEvidence) {\n return { verdict: 'unknown', evidence: prResult.errorEvidence };\n }\n return { verdict: 'stranded', evidence: `${normalized} has a branch that is not an ancestor of origin/main and no merged PR was found` };\n }\n\n if (prResult.errorEvidence) {\n return { verdict: 'unknown', evidence: prResult.errorEvidence };\n }\n\n return { verdict: 'unknown', evidence: `${normalized} has no resolvable merged PR and no feature/strike branch` };\n}\n\nexport async function reconcileMergedIssue(\n issueId: string,\n project: ProjectConfig,\n opts: ReconcileMergedIssueOptions = {},\n deps: Partial<MergeFulfillmentDeps> = {},\n): Promise<ReconcileMergedIssueResult> {\n const normalized = issueId.toUpperCase();\n const dryRun = opts.dryRun === true;\n const mergedDeps = resolveDeps(deps);\n const record = mergedDeps.readRecord(project, normalized);\n\n if (record?.pipeline?.mergeStatus === 'merged' && !opts.closed) {\n return {\n issueId: normalized,\n dryRun,\n skipped: true,\n actions: ['skipped: record already has mergeStatus=merged'],\n branchActions: [],\n };\n }\n\n const actions: string[] = [];\n if (dryRun) {\n if (record?.pipeline?.mergeStatus === 'merged') {\n actions.push('would skip status update: record already has mergeStatus=merged');\n } else {\n actions.push('would set mergeStatus=merged, reviewStatus=passed, readyForMerge=false');\n }\n actions.push('would apply merged label');\n if (opts.closed) actions.push('would apply closed-out label');\n } else {\n if (record?.pipeline?.mergeStatus === 'merged') {\n actions.push('skipped status update: record already has mergeStatus=merged');\n } else {\n mergedDeps.setReviewStatus(normalized, {\n mergeStatus: 'merged',\n reviewStatus: 'passed',\n readyForMerge: false,\n });\n actions.push('set mergeStatus=merged, reviewStatus=passed, readyForMerge=false');\n }\n\n const labelResult = await mergedDeps.cleanupMergedLabels(lifecycleContext(normalized, project));\n actions.push(labelResult.success ? 'applied merged label' : `merged label cleanup failed: ${labelResult.error ?? 'unknown error'}`);\n\n if (opts.closed) {\n actions.push(await applyClosedOutLabel(normalized, project, mergedDeps));\n }\n }\n\n const branchActions: ReconcileMergedIssueResult['branchActions'] = [];\n for (const branch of mergeBranchRefs(normalized)) {\n branchActions.push(await reconcileBranch(branch, project, dryRun, mergedDeps));\n }\n\n return {\n issueId: normalized,\n dryRun,\n skipped: false,\n actions,\n branchActions,\n };\n}\n\nasync function reconcileOneFulfilledMerge(\n issueId: string,\n options: ReconcileMergeFulfillmentOptions,\n deps: Partial<MergeFulfillmentDeps>,\n): Promise<ReconcileMergeFulfillmentDetail> {\n const normalized = issueId.toUpperCase();\n const resolved = resolveProjectFromIssueSync(normalized);\n if (!resolved) {\n return { issueId: normalized, action: 'failed', reason: 'could not resolve project' };\n }\n\n const project = getProjectSync(resolved.projectKey);\n if (!project) {\n return { issueId: normalized, action: 'failed', reason: 'project not found' };\n }\n\n const record = await readIssueRecordFromKnownPaths(project, normalized);\n if (!record) {\n return { issueId: normalized, action: 'skipped', reason: 'no record' };\n }\n if (record.pipeline?.mergeStatus === 'merged') {\n return { issueId: normalized, action: 'skipped', reason: 'record already has mergeStatus=merged' };\n }\n\n const closed = await issueIsClosed(normalized, project, record, resolveDeps(deps));\n if (closed !== true) {\n return {\n issueId: normalized,\n action: closed === false ? 'skipped' : 'flagged',\n reason: closed === false ? 'issue is not closed' : 'issue closed state could not be resolved',\n };\n }\n\n const verdict = await verifyIssueMergeFulfillment(normalized, project, {\n ...deps,\n readRecord: () => record,\n });\n if (verdict.verdict !== 'merged') {\n return {\n issueId: normalized,\n action: 'flagged',\n verdict: verdict.verdict,\n evidence: verdict.evidence,\n reason: `${verdict.verdict}: ${verdict.evidence}`,\n };\n }\n\n await reconcileMergedIssue(\n normalized,\n project,\n { closed: true, dryRun: options.dryRun },\n {\n ...deps,\n readRecord: () => record,\n },\n );\n\n return {\n issueId: normalized,\n action: options.dryRun ? 'would-reconcile' : 'reconciled',\n verdict: verdict.verdict,\n evidence: verdict.evidence,\n };\n}\n\nexport async function reconcileMergeFulfillment(\n options: ReconcileMergeFulfillmentOptions = {},\n deps: Partial<MergeFulfillmentDeps> = {},\n): Promise<ReconcileMergeFulfillmentResult> {\n const config = loadProjectsConfigSync();\n const projects = Object.values(config.projects);\n\n const issueIds = options.issueId\n ? new Set([options.issueId.toUpperCase()])\n : await collectRecordIssueIds(projects);\n\n const result: ReconcileMergeFulfillmentResult = {\n reconciled: 0,\n flagged: 0,\n skipped: 0,\n failed: 0,\n details: [],\n };\n\n for (const issueId of issueIds) {\n if (options.verbose) {\n console.log(`[merge-fulfillment] ${issueId} ...`);\n }\n\n const detail = await reconcileOneFulfilledMerge(issueId, options, deps);\n result.details.push(detail);\n\n if (detail.action === 'reconciled' || detail.action === 'would-reconcile') result.reconciled++;\n else if (detail.action === 'flagged') result.flagged++;\n else if (detail.action === 'skipped') result.skipped++;\n else result.failed++;\n\n if (options.verbose) {\n console.log(`[merge-fulfillment] ${issueId} -> ${detail.action}${detail.reason ? ` (${detail.reason})` : ''}`);\n }\n }\n\n return result;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"merge-fulfillment-__P4WE-T.js","names":[],"sources":["../src/lib/pan-dir/merge-fulfillment.ts"],"sourcesContent":["import { exec } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { readdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\nimport { Effect } from 'effect';\n\nimport { getPullRequestState, isGitHubAppConfigured } from '../github-app.js';\nimport { extractNumberSync } from '../issue-id.js';\nimport { cleanupMergedLabels } from '../lifecycle/label-cleanup.js';\nimport type { LifecycleContext, StepResult } from '../lifecycle/types.js';\nimport { getProjectSync, loadProjectsConfigSync, resolveProjectFromIssueSync, type ProjectConfig } from '../projects.js';\nimport { setReviewStatusSync, type ReviewStatus } from '../review-status.js';\nimport { WORKFLOW_LABELS } from '../lifecycle/close-issue.js';\nimport { readIssueRecordSync, RECORD_DIRNAME, type PanIssueRecord } from './record.js';\n\nconst execAsync = promisify(exec);\n\nexport type MergeFulfillmentVerdict = 'merged' | 'stranded' | 'unknown';\n\nexport interface MergeFulfillmentResult {\n verdict: MergeFulfillmentVerdict;\n evidence: string;\n}\n\ninterface PullRequestMergeProbe {\n result: MergeFulfillmentResult | null;\n errorEvidence?: string;\n}\n\nexport interface MergeFulfillmentDeps {\n readRecord(project: ProjectConfig, issueId: string): PanIssueRecord | null;\n exec(command: string, options: { cwd: string }): Promise<{ stdout: string; stderr: string }>;\n isGitHubAppConfigured(): boolean;\n getPullRequestState(owner: string, repo: string, number: number): Promise<{ merged: boolean; state?: string }>;\n setReviewStatus?(issueId: string, update: Partial<ReviewStatus>): ReviewStatus;\n cleanupMergedLabels?(ctx: LifecycleContext): Promise<StepResult>;\n}\n\nconst defaultDeps: MergeFulfillmentDeps = {\n readRecord: readIssueRecordSync,\n exec: (command, options) => execAsync(command, options),\n isGitHubAppConfigured,\n getPullRequestState: async (owner, repo, number) => Effect.runPromise(getPullRequestState(owner, repo, number)),\n setReviewStatus: setReviewStatusSync,\n cleanupMergedLabels: (ctx) => Effect.runPromise(cleanupMergedLabels(ctx)),\n};\n\ntype ResolvedMergeFulfillmentDeps = MergeFulfillmentDeps & Required<Pick<MergeFulfillmentDeps, 'setReviewStatus' | 'cleanupMergedLabels'>>;\n\nexport interface ReconcileMergedIssueOptions {\n closed?: boolean;\n dryRun?: boolean;\n}\n\nexport interface ReconcileMergedIssueResult {\n issueId: string;\n dryRun: boolean;\n skipped: boolean;\n actions: string[];\n branchActions: Array<{\n branch: string;\n status: 'deleted' | 'kept' | 'missing' | 'planned-delete' | 'planned-keep';\n reason: string;\n }>;\n}\n\nexport interface ReconcileMergeFulfillmentOptions {\n issueId?: string;\n dryRun?: boolean;\n verbose?: boolean;\n}\n\nexport interface ReconcileMergeFulfillmentDetail {\n issueId: string;\n action: 'reconciled' | 'would-reconcile' | 'flagged' | 'skipped' | 'failed';\n verdict?: MergeFulfillmentVerdict;\n evidence?: string;\n reason?: string;\n}\n\nexport interface ReconcileMergeFulfillmentResult {\n reconciled: number;\n flagged: number;\n skipped: number;\n failed: number;\n details: ReconcileMergeFulfillmentDetail[];\n}\n\nconst CLOSED_OUT_LABEL = 'closed-out';\nconst CLOSED_OUT_COLOR = '1d4ed8';\n\nfunction shellQuote(value: string): string {\n return `'${value.replace(/'/g, `'\"'\"'`)}'`;\n}\n\nfunction mergeBranchRefs(issueId: string): string[] {\n const suffix = issueId.toLowerCase();\n return [\n `feature/${suffix}`,\n `strike/${suffix}`,\n `origin/feature/${suffix}`,\n `origin/strike/${suffix}`,\n ];\n}\n\nfunction remoteBranchName(ref: string): string {\n return ref.startsWith('origin/') ? ref.slice('origin/'.length) : ref;\n}\n\nfunction resolveDeps(deps: Partial<MergeFulfillmentDeps>): ResolvedMergeFulfillmentDeps {\n return { ...defaultDeps, ...deps } as ResolvedMergeFulfillmentDeps;\n}\n\nfunction parseGitHubPullRequestUrl(url: string | undefined): { owner: string; repo: string; number: number } | null {\n const match = url?.match(/github\\.com\\/([^/]+)\\/([^/]+)\\/pull\\/(\\d+)/i);\n if (!match) return null;\n return {\n owner: match[1]!,\n repo: match[2]!,\n number: Number.parseInt(match[3]!, 10),\n };\n}\n\nfunction prRefFromRecord(project: ProjectConfig, record: PanIssueRecord | null): { owner: string; repo: string; number: number } | null {\n const fromUrl = parseGitHubPullRequestUrl(record?.pipeline?.prUrl);\n if (fromUrl) return fromUrl;\n const prNumber = record?.pipeline?.prNumber;\n if (!prNumber || !project.github_repo) return null;\n const [owner, repo] = project.github_repo.split('/');\n return owner && repo ? { owner, repo, number: prNumber } : null;\n}\n\nfunction isExitOne(error: unknown): boolean {\n return typeof error === 'object' && error !== null && 'code' in error && (error as { code?: unknown }).code === 1;\n}\n\nasync function prMerged(\n issueId: string,\n project: ProjectConfig,\n record: PanIssueRecord | null,\n deps: MergeFulfillmentDeps,\n): Promise<PullRequestMergeProbe> {\n const pr = prRefFromRecord(project, record);\n if (!pr) return { result: null };\n\n if (deps.isGitHubAppConfigured()) {\n try {\n const state = await deps.getPullRequestState(pr.owner, pr.repo, pr.number);\n if (state.merged) {\n return { result: { verdict: 'merged', evidence: `${issueId} PR #${pr.number} reports merged via GitHub App` } };\n }\n return { result: null };\n } catch (err) {\n return {\n result: null,\n errorEvidence: `${issueId} PR #${pr.number} state could not be resolved via GitHub App: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n }\n\n try {\n const { stdout } = await deps.exec(\n `gh pr view ${pr.number} --repo ${shellQuote(`${pr.owner}/${pr.repo}`)} --json merged,mergedAt,mergeCommit,state`,\n { cwd: project.path },\n );\n const parsed = JSON.parse(stdout || '{}') as { merged?: boolean; mergedAt?: string | null; mergeCommit?: unknown; state?: string };\n if (parsed.merged === true || parsed.mergedAt || parsed.mergeCommit) {\n return { result: { verdict: 'merged', evidence: `${issueId} PR #${pr.number} reports merged via gh` } };\n }\n return { result: null };\n } catch (err) {\n return {\n result: null,\n errorEvidence: `${issueId} PR #${pr.number} state could not be resolved via gh: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n}\n\nasync function branchExists(branch: string, project: ProjectConfig, deps: MergeFulfillmentDeps): Promise<boolean | 'unknown'> {\n try {\n await deps.exec(`git rev-parse --verify ${shellQuote(branch)}`, { cwd: project.path });\n return true;\n } catch (err) {\n return isExitOne(err) ? false : 'unknown';\n }\n}\n\nasync function branchIsMerged(branch: string, project: ProjectConfig, deps: MergeFulfillmentDeps): Promise<boolean | 'unknown'> {\n try {\n await deps.exec(`git merge-base --is-ancestor ${shellQuote(branch)} origin/main`, { cwd: project.path });\n return true;\n } catch (err) {\n return isExitOne(err) ? false : 'unknown';\n }\n}\n\nfunction lifecycleContext(issueId: string, project: ProjectConfig): LifecycleContext {\n const github = project.github_repo && extractNumberSync(issueId) !== null\n ? (() => {\n const [owner, repo] = project.github_repo!.split('/');\n const number = extractNumberSync(issueId);\n return owner && repo && number !== null ? { owner, repo, number } : undefined;\n })()\n : undefined;\n\n return {\n issueId,\n projectPath: project.path,\n projectName: project.name,\n ...(github ? { github } : {}),\n };\n}\n\nasync function collectRecordIssueIdsFromDir(dir: string): Promise<Set<string>> {\n const ids = new Set<string>();\n if (!existsSync(dir)) return ids;\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isFile()) continue;\n const match = entry.name.match(/^([a-z]+-\\d+)\\.json$/i);\n if (match) ids.add(match[1]!.toUpperCase());\n }\n } catch {\n // Directory may be unreadable; skip it.\n }\n return ids;\n}\n\nasync function collectRecordIssueIds(projects: ProjectConfig[]): Promise<Set<string>> {\n const ids = new Set<string>();\n for (const project of projects) {\n for (const id of await collectRecordIssueIdsFromDir(join(project.path, '.pan', RECORD_DIRNAME))) ids.add(id);\n\n const workspacesDir = join(project.path, project.workspace?.workspaces_dir ?? 'workspaces');\n if (!existsSync(workspacesDir)) continue;\n try {\n const workspaces = await readdir(workspacesDir, { withFileTypes: true });\n for (const workspace of workspaces) {\n if (!workspace.isDirectory()) continue;\n const recordsDir = join(workspacesDir, workspace.name, '.pan', RECORD_DIRNAME);\n for (const id of await collectRecordIssueIdsFromDir(recordsDir)) ids.add(id);\n }\n } catch {\n // Workspaces directory may be absent or unreadable; skip it.\n }\n }\n return ids;\n}\n\nasync function readIssueRecordFromKnownPaths(project: ProjectConfig, issueId: string): Promise<PanIssueRecord | null> {\n const direct = readIssueRecordSync(project, issueId);\n if (direct) return direct;\n\n const workspacesDir = join(project.path, project.workspace?.workspaces_dir ?? 'workspaces');\n if (!existsSync(workspacesDir)) return null;\n try {\n const workspaces = await readdir(workspacesDir, { withFileTypes: true });\n for (const workspace of workspaces) {\n if (!workspace.isDirectory()) continue;\n const path = join(workspacesDir, workspace.name, '.pan', RECORD_DIRNAME, `${issueId.toLowerCase()}.json`);\n try {\n return JSON.parse(await readFile(path, 'utf-8')) as PanIssueRecord;\n } catch {\n // Try the next workspace.\n }\n }\n } catch {\n return null;\n }\n return null;\n}\n\nfunction shouldApplyClosedOutLabel(record: PanIssueRecord | null): boolean {\n return record?.pipeline?.closedOut === true || Boolean(record?.closeOut?.closedAt);\n}\n\nasync function issueIsClosed(issueId: string, project: ProjectConfig, record: PanIssueRecord, deps: MergeFulfillmentDeps): Promise<boolean | 'unknown'> {\n if (shouldApplyClosedOutLabel(record)) return true;\n if (!project.github_repo) return 'unknown';\n const number = extractNumberSync(issueId);\n if (number === null) return 'unknown';\n\n try {\n const { stdout } = await deps.exec(\n `gh issue view ${number} --repo ${shellQuote(project.github_repo)} --json state`,\n { cwd: project.path },\n );\n const parsed = JSON.parse(stdout || '{}') as { state?: string };\n if (parsed.state === 'CLOSED') return true;\n if (parsed.state === 'OPEN') return false;\n return 'unknown';\n } catch {\n return 'unknown';\n }\n}\n\nasync function applyClosedOutLabel(issueId: string, project: ProjectConfig, deps: MergeFulfillmentDeps): Promise<string> {\n if (!project.github_repo) {\n return 'skipped closed-out label: project has no GitHub repo';\n }\n const number = extractNumberSync(issueId);\n if (number === null) {\n return 'skipped closed-out label: issue number could not be parsed';\n }\n const [owner, repo] = project.github_repo.split('/');\n if (!owner || !repo) {\n return 'skipped closed-out label: project GitHub repo is invalid';\n }\n\n const repoSlug = `${owner}/${repo}`;\n await deps.exec(\n `gh label create ${shellQuote(CLOSED_OUT_LABEL)} --repo ${shellQuote(repoSlug)} --color ${shellQuote(CLOSED_OUT_COLOR)} --description ${shellQuote('Verified and closed out')} --force`,\n { cwd: project.path },\n );\n for (const label of WORKFLOW_LABELS) {\n await deps.exec(\n `gh issue edit ${number} --repo ${shellQuote(repoSlug)} --remove-label ${shellQuote(label)}`,\n { cwd: project.path },\n ).catch(() => ({ stdout: '', stderr: '' }));\n }\n await deps.exec(\n `gh issue edit ${number} --repo ${shellQuote(repoSlug)} --add-label ${shellQuote(CLOSED_OUT_LABEL)}`,\n { cwd: project.path },\n );\n return `applied closed-out label to ${issueId}`;\n}\n\nasync function reconcileBranch(\n branch: string,\n project: ProjectConfig,\n dryRun: boolean,\n deps: MergeFulfillmentDeps,\n): Promise<ReconcileMergedIssueResult['branchActions'][number]> {\n const exists = await branchExists(branch, project, deps);\n if (exists === 'unknown') {\n return { branch, status: 'kept', reason: 'branch existence could not be resolved' };\n }\n if (!exists) {\n return { branch, status: 'missing', reason: 'branch was not found' };\n }\n\n const merged = await branchIsMerged(branch, project, deps);\n if (merged !== true) {\n return {\n branch,\n status: dryRun ? 'planned-keep' : 'kept',\n reason: merged === 'unknown' ? 'branch ancestry could not be resolved' : 'branch is not an ancestor of origin/main',\n };\n }\n\n if (dryRun) {\n return { branch, status: 'planned-delete', reason: 'branch is an ancestor of origin/main' };\n }\n\n if (branch.startsWith('origin/')) {\n await deps.exec(`git push origin --delete ${shellQuote(remoteBranchName(branch))}`, { cwd: project.path }).catch(() => ({ stdout: '', stderr: '' }));\n } else {\n await deps.exec(`git branch -D ${shellQuote(branch)}`, { cwd: project.path });\n }\n return { branch, status: 'deleted', reason: 'branch is an ancestor of origin/main' };\n}\n\nexport async function verifyIssueMergeFulfillment(\n issueId: string,\n project: ProjectConfig,\n deps: Partial<MergeFulfillmentDeps> = {},\n): Promise<MergeFulfillmentResult> {\n const normalized = issueId.toUpperCase();\n const mergedDeps = resolveDeps(deps);\n const record = mergedDeps.readRecord(project, normalized);\n\n const prResult = await prMerged(normalized, project, record, mergedDeps);\n if (prResult.result) return prResult.result;\n\n let sawExistingBranch = false;\n for (const branch of mergeBranchRefs(normalized)) {\n const exists = await branchExists(branch, project, mergedDeps);\n if (exists === 'unknown') {\n return { verdict: 'unknown', evidence: `${normalized} branch ${branch} existence could not be resolved` };\n }\n if (!exists) continue;\n sawExistingBranch = true;\n\n const merged = await branchIsMerged(branch, project, mergedDeps);\n if (merged === true) {\n return { verdict: 'merged', evidence: `${branch} is an ancestor of origin/main` };\n }\n if (merged === 'unknown') {\n return { verdict: 'unknown', evidence: `${normalized} branch ${branch} ancestry could not be resolved` };\n }\n }\n\n if (sawExistingBranch) {\n if (prResult.errorEvidence) {\n return { verdict: 'unknown', evidence: prResult.errorEvidence };\n }\n return { verdict: 'stranded', evidence: `${normalized} has a branch that is not an ancestor of origin/main and no merged PR was found` };\n }\n\n if (prResult.errorEvidence) {\n return { verdict: 'unknown', evidence: prResult.errorEvidence };\n }\n\n return { verdict: 'unknown', evidence: `${normalized} has no resolvable merged PR and no feature/strike branch` };\n}\n\nexport async function reconcileMergedIssue(\n issueId: string,\n project: ProjectConfig,\n opts: ReconcileMergedIssueOptions = {},\n deps: Partial<MergeFulfillmentDeps> = {},\n): Promise<ReconcileMergedIssueResult> {\n const normalized = issueId.toUpperCase();\n const dryRun = opts.dryRun === true;\n const mergedDeps = resolveDeps(deps);\n const record = mergedDeps.readRecord(project, normalized);\n\n if (record?.pipeline?.mergeStatus === 'merged' && !opts.closed) {\n return {\n issueId: normalized,\n dryRun,\n skipped: true,\n actions: ['skipped: record already has mergeStatus=merged'],\n branchActions: [],\n };\n }\n\n const actions: string[] = [];\n if (dryRun) {\n if (record?.pipeline?.mergeStatus === 'merged') {\n actions.push('would skip status update: record already has mergeStatus=merged');\n } else {\n actions.push('would set mergeStatus=merged, reviewStatus=passed, readyForMerge=false');\n }\n actions.push('would apply merged label');\n if (opts.closed) actions.push('would apply closed-out label');\n } else {\n if (record?.pipeline?.mergeStatus === 'merged') {\n actions.push('skipped status update: record already has mergeStatus=merged');\n } else {\n mergedDeps.setReviewStatus(normalized, {\n mergeStatus: 'merged',\n reviewStatus: 'passed',\n readyForMerge: false,\n });\n actions.push('set mergeStatus=merged, reviewStatus=passed, readyForMerge=false');\n }\n\n const labelResult = await mergedDeps.cleanupMergedLabels(lifecycleContext(normalized, project));\n actions.push(labelResult.success ? 'applied merged label' : `merged label cleanup failed: ${labelResult.error ?? 'unknown error'}`);\n\n if (opts.closed) {\n actions.push(await applyClosedOutLabel(normalized, project, mergedDeps));\n }\n }\n\n const branchActions: ReconcileMergedIssueResult['branchActions'] = [];\n for (const branch of mergeBranchRefs(normalized)) {\n branchActions.push(await reconcileBranch(branch, project, dryRun, mergedDeps));\n }\n\n return {\n issueId: normalized,\n dryRun,\n skipped: false,\n actions,\n branchActions,\n };\n}\n\nasync function reconcileOneFulfilledMerge(\n issueId: string,\n options: ReconcileMergeFulfillmentOptions,\n deps: Partial<MergeFulfillmentDeps>,\n): Promise<ReconcileMergeFulfillmentDetail> {\n const normalized = issueId.toUpperCase();\n const resolved = resolveProjectFromIssueSync(normalized);\n if (!resolved) {\n return { issueId: normalized, action: 'failed', reason: 'could not resolve project' };\n }\n\n const project = getProjectSync(resolved.projectKey);\n if (!project) {\n return { issueId: normalized, action: 'failed', reason: 'project not found' };\n }\n\n const record = await readIssueRecordFromKnownPaths(project, normalized);\n if (!record) {\n return { issueId: normalized, action: 'skipped', reason: 'no record' };\n }\n if (record.pipeline?.mergeStatus === 'merged') {\n return { issueId: normalized, action: 'skipped', reason: 'record already has mergeStatus=merged' };\n }\n\n const closed = await issueIsClosed(normalized, project, record, resolveDeps(deps));\n if (closed !== true) {\n return {\n issueId: normalized,\n action: closed === false ? 'skipped' : 'flagged',\n reason: closed === false ? 'issue is not closed' : 'issue closed state could not be resolved',\n };\n }\n\n const verdict = await verifyIssueMergeFulfillment(normalized, project, {\n ...deps,\n readRecord: () => record,\n });\n if (verdict.verdict !== 'merged') {\n return {\n issueId: normalized,\n action: 'flagged',\n verdict: verdict.verdict,\n evidence: verdict.evidence,\n reason: `${verdict.verdict}: ${verdict.evidence}`,\n };\n }\n\n await reconcileMergedIssue(\n normalized,\n project,\n { closed: true, dryRun: options.dryRun },\n {\n ...deps,\n readRecord: () => record,\n },\n );\n\n return {\n issueId: normalized,\n action: options.dryRun ? 'would-reconcile' : 'reconciled',\n verdict: verdict.verdict,\n evidence: verdict.evidence,\n };\n}\n\nexport async function reconcileMergeFulfillment(\n options: ReconcileMergeFulfillmentOptions = {},\n deps: Partial<MergeFulfillmentDeps> = {},\n): Promise<ReconcileMergeFulfillmentResult> {\n const config = loadProjectsConfigSync();\n const projects = Object.values(config.projects);\n\n const issueIds = options.issueId\n ? new Set([options.issueId.toUpperCase()])\n : await collectRecordIssueIds(projects);\n\n const result: ReconcileMergeFulfillmentResult = {\n reconciled: 0,\n flagged: 0,\n skipped: 0,\n failed: 0,\n details: [],\n };\n\n for (const issueId of issueIds) {\n if (options.verbose) {\n console.log(`[merge-fulfillment] ${issueId} ...`);\n }\n\n const detail = await reconcileOneFulfilledMerge(issueId, options, deps);\n result.details.push(detail);\n\n if (detail.action === 'reconciled' || detail.action === 'would-reconcile') result.reconciled++;\n else if (detail.action === 'flagged') result.flagged++;\n else if (detail.action === 'skipped') result.skipped++;\n else result.failed++;\n\n if (options.verbose) {\n console.log(`[merge-fulfillment] ${issueId} -> ${detail.action}${detail.reason ? ` (${detail.reason})` : ''}`);\n }\n }\n\n return result;\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __esmMin } from "./chunk-ruWRV7i3.js";
|
|
2
2
|
import { S as listProjectsSync, v as init_projects } from "./projects-D2nMJ9C4.js";
|
|
3
3
|
import { f as readIssueRecord, g as resolveProjectForIssue, l as init_record } from "./record-osVNNpoC.js";
|
|
4
|
-
import { V as listRunningAgents, t as init_agents } from "./agents-
|
|
4
|
+
import { V as listRunningAgents, t as init_agents } from "./agents-CgVr77Qq.js";
|
|
5
5
|
import { a as init_agents$1, n as backfillAgentsSync, o as listAllAgentsSync } from "./agents-BURDseV4.js";
|
|
6
6
|
import { Effect } from "effect";
|
|
7
7
|
import { join } from "node:path";
|
|
@@ -195,7 +195,7 @@ function isIssueClosed(issue) {
|
|
|
195
195
|
return false;
|
|
196
196
|
}
|
|
197
197
|
async function loadInFlightIssueIds(projects) {
|
|
198
|
-
const { getSharedIssueService, startSharedIssueService } = await import("./issue-service-singleton-
|
|
198
|
+
const { getSharedIssueService, startSharedIssueService } = await import("./issue-service-singleton-D-8Q6tdT.js");
|
|
199
199
|
const issueService = getSharedIssueService();
|
|
200
200
|
await startSharedIssueService({ skipPolling: true });
|
|
201
201
|
const issues = issueService.getIssues({ includeCompleted: true });
|
|
@@ -341,4 +341,4 @@ __esmMin((() => {
|
|
|
341
341
|
}))();
|
|
342
342
|
export { reconstructCache, reconstructCacheAuto };
|
|
343
343
|
|
|
344
|
-
//# sourceMappingURL=reconstruct-cache-
|
|
344
|
+
//# sourceMappingURL=reconstruct-cache-9SWp82SQ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconstruct-cache-NPqoAUg-.js","names":[],"sources":["../src/lib/reconstruct/enumerate-in-flight.ts","../src/lib/reconstruct/derive-phase.ts","../src/lib/reconstruct/reconstruct-cache.ts"],"sourcesContent":["/**\n * PAN-1920: source-of-truth enumerator for in-flight issues.\n *\n * In-flight = OPEN GitHub issue ∩ has a `feature/<id-lowercase>` workspace on disk.\n * Reads only git worktrees / the workspaces directory; never the SQLite cache.\n */\n\nimport { readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport type { ProjectConfig } from '../projects.js';\n\nconst execAsync = promisify(exec);\n\nconst FEATURE_DIR_RE = /^feature-([a-z0-9-]+)$/;\n\n/**\n * List the issue IDs that are both OPEN on GitHub and have a local\n * `feature/<id-lowercase>` workspace directory.\n */\nexport async function enumerateInFlightIssuesFromSources(\n projects: ProjectConfig[],\n openIssueIds: Set<string>,\n): Promise<Set<string>> {\n const inFlight = new Set<string>();\n const seen = new Set<string>();\n\n for (const project of projects) {\n const workspaceConfig = project.workspace || {};\n const workspacesDir = join(project.path, workspaceConfig.workspaces_dir || 'workspaces');\n\n // Primary source: scan the workspaces directory for feature-* folders.\n // This works for monorepos and polyrepos alike.\n try {\n const entries = await readdir(workspacesDir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const match = FEATURE_DIR_RE.exec(entry.name);\n if (!match) continue;\n const issueId = match[1]!.toUpperCase();\n if (seen.has(issueId)) continue;\n seen.add(issueId);\n if (openIssueIds.has(issueId)) {\n inFlight.add(issueId);\n }\n }\n } catch {\n // workspaces directory may not exist for this project\n }\n\n // Secondary source: git worktree list (useful when the workspace directory\n // is a git worktree but lives outside the configured workspaces_dir).\n try {\n const { stdout } = await execAsync('git worktree list --porcelain', {\n cwd: project.path,\n timeout: 10_000,\n });\n for (const line of stdout.split('\\n')) {\n const worktreeMatch = /^worktree\\s+(.+)$/.exec(line);\n if (!worktreeMatch) continue;\n const worktreePath = worktreeMatch[1]!;\n const baseName = worktreePath.split('/').pop() ?? worktreePath;\n const dirMatch = FEATURE_DIR_RE.exec(baseName);\n if (!dirMatch) continue;\n const issueId = dirMatch[1]!.toUpperCase();\n if (seen.has(issueId)) continue;\n seen.add(issueId);\n if (openIssueIds.has(issueId)) {\n inFlight.add(issueId);\n }\n }\n } catch {\n // project root may not be a git repo, or git is unavailable\n }\n }\n\n return inFlight;\n}\n","/**\n * PAN-1920: derive the dashboard pipeline phase from sources of truth only.\n *\n * The phase is a function of GitHub issue state, the per-issue git-tracked\n * record, and the GitHub PR reviewDecision. It never reads the SQLite cache.\n */\n\nimport type { PanIssueRecord } from '../pan-dir/record.js';\n\nexport type PipelinePhase = 'work' | 'review' | 'merge' | 'done';\n\nexport interface DerivePhaseArgs {\n /** True when the tracker issue itself is closed/done. */\n issueClosed: boolean;\n /** True when a PR exists for the feature branch. */\n hasPr: boolean;\n /** Per-issue git-tracked record (may be null while PAN-1919 is rolling out). */\n record: PanIssueRecord | null;\n /** GitHub `reviewDecision` from `gh pr view --json reviewDecision`. */\n reviewDecision: string | null;\n}\n\n/**\n * Derive the pipeline phase from sources.\n *\n * Rules (D3/D4):\n * - issue closed on tracker → done\n * - no PR → work\n * - approved (record readyForMerge / reviewStatus passed / GitHub APPROVED) → merge\n * - PR open but not approved → review\n */\nexport function derivePipelinePhase(args: DerivePhaseArgs): PipelinePhase {\n if (args.issueClosed) return 'done';\n if (!args.hasPr) return 'work';\n\n const approved =\n args.record?.pipeline?.readyForMerge === true ||\n args.record?.pipeline?.reviewStatus === 'passed' ||\n args.reviewDecision === 'APPROVED';\n\n return approved ? 'merge' : 'review';\n}\n","/**\n * PAN-1920: reconstruct the dashboard cache from sources of truth.\n *\n * Rebuilds the agents table from state.json + tmux, enumerates in-flight\n * issues from GitHub + workspaces, derives pipeline phases from the per-issue\n * record + GitHub PR state, and produces the AgentSnapshot / AgentRuntimeSnapshot\n * maps the dashboard bootstrap paths need.\n *\n * Reads NO SQLite cache tables: no events, no projection cache, no review_status.\n */\n\nimport { Effect } from 'effect';\nimport type {\n AgentRuntimeSnapshot,\n AgentSnapshot,\n ReviewStatusSnapshot,\n} from '@overdeck/contracts';\nimport { backfillAgentsSync, listAllAgentsSync } from '../overdeck/agents.js';\nimport { listRunningAgents, type AgentState } from '../agents.js';\nimport { listProjectsSync, type ProjectConfig } from '../projects.js';\nimport {\n readIssueRecord,\n resolveProjectForIssue,\n type PanIssueRecord,\n} from '../pan-dir/record.js';\nimport { enumerateInFlightIssuesFromSources } from './enumerate-in-flight.js';\nimport { derivePipelinePhase, type PipelinePhase } from './derive-phase.js';\n\nexport interface ReconstructOptions {\n verbose?: boolean;\n /** Override tmux session discovery for tests / headless environments. */\n listLiveSessions?: () => Set<string>;\n}\n\nexport interface ReconstructResult {\n issuesEnumerated: number;\n agentsRebuilt: number;\n phaseCounts: Record<PipelinePhase, number>;\n agentRuntimeById: Record<string, AgentRuntimeSnapshot>;\n agentsById: Record<string, AgentSnapshot>;\n reviewStatusByIssueId: Record<string, ReviewStatusSnapshot>;\n phaseByIssueId: Record<string, PipelinePhase>;\n}\n\nfunction toAgentStatus(status: string): AgentSnapshot['status'] {\n if (\n status === 'starting' ||\n status === 'running' ||\n status === 'stopped' ||\n status === 'error'\n ) {\n return status;\n }\n return 'unknown';\n}\n\nfunction toAgentRole(role: string): AgentSnapshot['role'] | undefined {\n if (\n role === 'plan' ||\n role === 'work' ||\n role === 'review' ||\n role === 'test' ||\n role === 'ship' ||\n role === 'flywheel' ||\n role === 'strike'\n ) {\n return role;\n }\n return undefined;\n}\n\nfunction toAgentSnapshot(state: AgentState & { tmuxActive?: boolean }): AgentSnapshot {\n return {\n id: state.id,\n issueId: state.issueId,\n workspace: state.workspace || undefined,\n runtime: state.harness || undefined,\n model: state.model || undefined,\n status: toAgentStatus(state.status),\n startedAt: state.startedAt || undefined,\n lastActivity: state.lastActivity || undefined,\n branch: state.branch || undefined,\n costSoFar: state.costSoFar,\n sessionId: state.sessionId || undefined,\n role: toAgentRole(state.role),\n phase: state.phase || undefined,\n workType: state.workType || undefined,\n roleRunHead: state.roleRunHead || undefined,\n hasLiveTmuxSession: state.tmuxActive,\n stoppedByUser: state.stoppedByUser,\n paused: state.paused,\n pausedReason: state.pausedReason,\n pausedAt: state.pausedAt,\n troubled: state.troubled,\n troubledAt: state.troubledAt,\n consecutiveFailures: state.consecutiveFailures,\n firstFailureInRunAt: state.firstFailureInRunAt,\n lastFailureAt: state.lastFailureAt,\n lastFailureReason: state.lastFailureReason,\n lastFailureNextRetryAt: state.lastFailureNextRetryAt,\n };\n}\n\nfunction toAgentRuntimeSnapshot(state: AgentState): AgentRuntimeSnapshot {\n const now = new Date().toISOString();\n const activity: AgentRuntimeSnapshot['activity'] =\n state.status === 'running' || state.status === 'starting'\n ? 'working'\n : state.status === 'stopped'\n ? 'stopped'\n : 'idle';\n\n return {\n id: state.id,\n activity,\n lastActivity: state.lastActivity || now,\n model: state.model || undefined,\n currentIssue: state.issueId,\n updatedAtSequence: 0,\n };\n}\n\nfunction toReviewStatusValue(\n value: string | undefined,\n): ReviewStatusSnapshot['reviewStatus'] {\n if (!value) return undefined;\n if (\n value === 'pending' ||\n value === 'reviewing' ||\n value === 'passed' ||\n value === 'failed' ||\n value === 'blocked'\n ) {\n return value;\n }\n return undefined;\n}\n\nfunction toTestStatusValue(\n value: string | undefined,\n): ReviewStatusSnapshot['testStatus'] {\n if (!value) return undefined;\n if (\n value === 'pending' ||\n value === 'testing' ||\n value === 'passed' ||\n value === 'failed' ||\n value === 'skipped' ||\n value === 'dispatch_failed'\n ) {\n return value;\n }\n return undefined;\n}\n\nfunction toMergeStatusValue(\n value: string | undefined,\n): ReviewStatusSnapshot['mergeStatus'] {\n if (!value) return undefined;\n if (\n value === 'pending' ||\n value === 'queued' ||\n value === 'merging' ||\n value === 'verifying' ||\n value === 'merged' ||\n value === 'failed'\n ) {\n return value;\n }\n return undefined;\n}\n\nfunction toVerificationStatusValue(\n value: string | undefined,\n): ReviewStatusSnapshot['verificationStatus'] {\n if (!value) return undefined;\n if (\n value === 'pending' ||\n value === 'running' ||\n value === 'passed' ||\n value === 'failed' ||\n value === 'skipped'\n ) {\n return value;\n }\n return undefined;\n}\n\nfunction recordToReviewStatusSnapshot(record: PanIssueRecord): ReviewStatusSnapshot {\n const pipeline = record.pipeline;\n return {\n issueId: record.issueId,\n reviewStatus: toReviewStatusValue(pipeline.reviewStatus),\n testStatus: toTestStatusValue(pipeline.testStatus),\n mergeStatus: toMergeStatusValue(pipeline.mergeStatus),\n verificationStatus: toVerificationStatusValue(pipeline.verificationStatus),\n readyForMerge: pipeline.readyForMerge ?? false,\n updatedAt: pipeline.updatedAt,\n prUrl: pipeline.prUrl,\n reviewedAtCommit: pipeline.reviewedAtCommit,\n lastVerifiedCommit: pipeline.lastVerifiedCommit,\n autoMerge: pipeline.autoMerge,\n blockerReasons: pipeline.blockerReasons as ReviewStatusSnapshot['blockerReasons'],\n mergeNotes: pipeline.mergeNotes,\n reviewRetryCount: undefined,\n testRetryCount: undefined,\n mergeRetryCount: undefined,\n };\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\nfunction isIssueClosed(issue: {\n completedAt?: unknown;\n state?: unknown;\n canonicalStatus?: unknown;\n status?: unknown;\n}): boolean {\n const state = String(issue.state ?? '').toLowerCase();\n const status = String(issue.status ?? '').toLowerCase();\n const canonicalStatus = String(issue.canonicalStatus ?? '').toLowerCase();\n if (issue.completedAt) return true;\n if (\n state === 'closed' ||\n state === 'done' ||\n state === 'completed'\n ) {\n return true;\n }\n if (\n status === 'done' ||\n status === 'closed' ||\n status === 'completed' ||\n status === 'cancelled' ||\n status === 'canceled'\n ) {\n return true;\n }\n if (\n canonicalStatus === 'done' ||\n canonicalStatus === 'closed' ||\n canonicalStatus === 'completed' ||\n canonicalStatus === 'cancelled' ||\n canonicalStatus === 'canceled'\n ) {\n return true;\n }\n return false;\n}\n\nasync function loadInFlightIssueIds(\n projects: ProjectConfig[],\n): Promise<Set<string>> {\n const { getSharedIssueService, startSharedIssueService } = await import(\n '../../dashboard/server/services/issue-service-singleton.js'\n );\n const issueService = getSharedIssueService();\n await startSharedIssueService({ skipPolling: true });\n\n const issues = issueService.getIssues({ includeCompleted: true });\n const openIssueIds = new Set<string>();\n for (const issue of issues) {\n if (!issue || typeof issue !== 'object') continue;\n const item = issue as { identifier?: unknown; id?: unknown };\n const issueId = normalizeIssueId(item.identifier) ?? normalizeIssueId(item.id);\n if (!issueId) continue;\n if (!isIssueClosed(issue as any)) {\n openIssueIds.add(issueId);\n }\n }\n\n return enumerateInFlightIssuesFromSources(projects, openIssueIds);\n}\n\nasync function fetchPrState(\n issueId: string,\n): Promise<{ hasPr: boolean; reviewDecision: string | null }> {\n const { fetchIssuePullRequest } = await import(\n '../overdeck/pull-requests.js'\n );\n const result = await fetchIssuePullRequest(issueId);\n if (!result.pr) return { hasPr: false, reviewDecision: null };\n return { hasPr: true, reviewDecision: result.pr.reviewDecision };\n}\n\n/**\n * Reconstruct the dashboard cache from durable sources only.\n *\n * The `_db` parameter is accepted for backward compatibility but is no longer\n * used — the cache now reads from the overdeck layer directly.\n */\nexport async function reconstructCache(\n _db?: unknown,\n opts?: ReconstructOptions,\n): Promise<ReconstructResult> {\n const verbose = opts?.verbose ?? false;\n\n // 1. Rebuild the agents table from state.json + tmux (sources-only).\n const { processed: agentsRebuilt } = backfillAgentsSync({\n verbose,\n listLiveSessions: opts?.listLiveSessions,\n });\n\n // 2. Build AgentSnapshot / AgentRuntimeSnapshot maps from the rebuilt table.\n let runningAgents: (AgentState & { tmuxActive: boolean })[] = [];\n try {\n runningAgents = await Effect.runPromise(listRunningAgents());\n } catch (err) {\n console.warn(\n '[reconstruct-cache] listRunningAgents failed, falling back to agents table:',\n (err as Error).message,\n );\n runningAgents = listAllAgentsSync().map((agent) => {\n const state = {\n id: agent.id,\n issueId: agent.issueId,\n workspace: agent.workspace ?? '',\n role: agent.role as AgentState['role'],\n model: agent.model ?? '',\n status: agent.status as AgentState['status'],\n startedAt: agent.startedAt ?? new Date().toISOString(),\n harness: agent.harness ? (agent.harness as AgentState['harness']) : undefined,\n lastActivity: agent.lastActivity ?? undefined,\n lastResumeAt: agent.lastResumeAt ?? undefined,\n stoppedAt: agent.stoppedAt ?? undefined,\n stoppedByUser: agent.stoppedByUser ?? undefined,\n stoppedByPause: agent.stoppedByPause ?? undefined,\n kickoffDelivered: agent.kickoffDelivered ?? undefined,\n paused: agent.paused ?? undefined,\n pausedReason: agent.pausedReason ?? undefined,\n pausedAt: agent.pausedAt ?? undefined,\n troubled: agent.troubled ?? undefined,\n troubledAt: agent.troubledAt ?? undefined,\n consecutiveFailures: agent.consecutiveFailures ?? undefined,\n firstFailureInRunAt: agent.firstFailureInRunAt ?? undefined,\n lastFailureAt: agent.lastFailureAt ?? undefined,\n lastFailureReason: agent.lastFailureReason ?? undefined,\n lastFailureNextRetryAt: agent.lastFailureNextRetryAt ?? undefined,\n branch: agent.branch ?? undefined,\n costSoFar: agent.costSoFar ?? undefined,\n sessionId: agent.sessionId ?? undefined,\n phase: agent.phase ? (agent.phase as AgentState['phase']) : undefined,\n workType: agent.workType ?? undefined,\n roleRunHead: agent.roleRunHead ?? undefined,\n channelsEnabled: agent.channelsEnabled ?? undefined,\n supervisorEnabled: agent.supervisorEnabled ?? undefined,\n deliveryMethod: agent.deliveryMethod\n ? (agent.deliveryMethod as AgentState['deliveryMethod'])\n : undefined,\n flywheelRunId: agent.flywheelRunId ?? undefined,\n reviewSubRole: agent.reviewSubRole ?? undefined,\n reviewRunId: agent.reviewRunId ?? undefined,\n reviewOutputPath: agent.reviewOutputPath ?? undefined,\n reviewSynthesisAgentId: agent.reviewSynthesisAgentId ?? undefined,\n reviewDeadlineAt: agent.reviewDeadlineAt ?? undefined,\n reviewMonitorSignaled: agent.reviewMonitorSignaled\n ? (agent.reviewMonitorSignaled as AgentState['reviewMonitorSignaled'])\n : undefined,\n reviewRetryAttempt: agent.reviewRetryAttempt ?? undefined,\n hostOverride: agent.hostOverride ?? undefined,\n inspectSubRole: agent.inspectSubRole ?? undefined,\n } satisfies AgentState;\n return { ...state, tmuxActive: false };\n });\n }\n\n const agentsById: Record<string, AgentSnapshot> = {};\n const agentRuntimeById: Record<string, AgentRuntimeSnapshot> = {};\n for (const a of runningAgents) {\n agentsById[a.id] = toAgentSnapshot(a);\n agentRuntimeById[a.id] = toAgentRuntimeSnapshot(a);\n }\n\n // 3. Enumerate in-flight issues from GitHub + workspaces.\n const projects = listProjectsSync().map(({ config }) => config);\n const inFlight = await loadInFlightIssueIds(projects);\n\n // 4. Derive phases and review-status snapshots from sources.\n const phaseCounts: Record<PipelinePhase, number> = {\n work: 0,\n review: 0,\n merge: 0,\n done: 0,\n };\n const phaseByIssueId: Record<string, PipelinePhase> = {};\n const reviewStatusByIssueId: Record<string, ReviewStatusSnapshot> = {};\n\n for (const issueId of inFlight) {\n const project = resolveProjectForIssue(issueId);\n const record = project ? await readIssueRecord(project, issueId) : null;\n const { hasPr, reviewDecision } = await fetchPrState(issueId);\n const phase = derivePipelinePhase({\n issueClosed: false,\n hasPr,\n record,\n reviewDecision,\n });\n phaseCounts[phase]++;\n phaseByIssueId[issueId] = phase;\n\n if (record) {\n reviewStatusByIssueId[issueId] = recordToReviewStatusSnapshot(record);\n }\n\n if (verbose) {\n console.log(`[reconstruct-cache] ${issueId} → ${phase}`);\n }\n }\n\n return {\n issuesEnumerated: inFlight.size,\n agentsRebuilt,\n phaseCounts,\n agentRuntimeById,\n agentsById,\n reviewStatusByIssueId,\n phaseByIssueId,\n };\n}\n\nexport function reconstructCacheAuto(opts?: ReconstructOptions): Promise<ReconstructResult> {\n return reconstructCache(undefined, opts);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,eAAsB,mCACpB,UACA,cACsB;CACtB,MAAM,2BAAW,IAAI,KAAa;CAClC,MAAM,uBAAO,IAAI,KAAa;AAE9B,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,kBAAkB,QAAQ,aAAa,EAAE;EAC/C,MAAM,gBAAgB,KAAK,QAAQ,MAAM,gBAAgB,kBAAkB,aAAa;AAIxF,MAAI;GACF,MAAM,UAAU,MAAM,QAAQ,eAAe,EAAE,eAAe,MAAM,CAAC;AACrE,QAAK,MAAM,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAM,aAAa,CAAE;IAC1B,MAAM,QAAQ,eAAe,KAAK,MAAM,KAAK;AAC7C,QAAI,CAAC,MAAO;IACZ,MAAM,UAAU,MAAM,GAAI,aAAa;AACvC,QAAI,KAAK,IAAI,QAAQ,CAAE;AACvB,SAAK,IAAI,QAAQ;AACjB,QAAI,aAAa,IAAI,QAAQ,CAC3B,UAAS,IAAI,QAAQ;;UAGnB;AAMR,MAAI;GACF,MAAM,EAAE,WAAW,MAAM,UAAU,iCAAiC;IAClE,KAAK,QAAQ;IACb,SAAS;IACV,CAAC;AACF,QAAK,MAAM,QAAQ,OAAO,MAAM,KAAK,EAAE;IACrC,MAAM,gBAAgB,oBAAoB,KAAK,KAAK;AACpD,QAAI,CAAC,cAAe;IACpB,MAAM,eAAe,cAAc;IACnC,MAAM,WAAW,aAAa,MAAM,IAAI,CAAC,KAAK,IAAI;IAClD,MAAM,WAAW,eAAe,KAAK,SAAS;AAC9C,QAAI,CAAC,SAAU;IACf,MAAM,UAAU,SAAS,GAAI,aAAa;AAC1C,QAAI,KAAK,IAAI,QAAQ,CAAE;AACvB,SAAK,IAAI,QAAQ;AACjB,QAAI,aAAa,IAAI,QAAQ,CAC3B,UAAS,IAAI,QAAQ;;UAGnB;;AAKV,QAAO;;;;AAhEH,aAAY,UAAU,KAAK;AAE3B,kBAAiB;;;;;;;;;;;;;ACgBvB,SAAgB,oBAAoB,MAAsC;AACxE,KAAI,KAAK,YAAa,QAAO;AAC7B,KAAI,CAAC,KAAK,MAAO,QAAO;AAOxB,QAJE,KAAK,QAAQ,UAAU,kBAAkB,QACzC,KAAK,QAAQ,UAAU,iBAAiB,YACxC,KAAK,mBAAmB,aAER,UAAU;;;;;;;;;;;;;;;ACI9B,SAAS,cAAc,QAAyC;AAC9D,KACE,WAAW,cACX,WAAW,aACX,WAAW,aACX,WAAW,QAEX,QAAO;AAET,QAAO;;AAGT,SAAS,YAAY,MAAiD;AACpE,KACE,SAAS,UACT,SAAS,UACT,SAAS,YACT,SAAS,UACT,SAAS,UACT,SAAS,cACT,SAAS,SAET,QAAO;;AAKX,SAAS,gBAAgB,OAA6D;AACpF,QAAO;EACL,IAAI,MAAM;EACV,SAAS,MAAM;EACf,WAAW,MAAM,aAAa,KAAA;EAC9B,SAAS,MAAM,WAAW,KAAA;EAC1B,OAAO,MAAM,SAAS,KAAA;EACtB,QAAQ,cAAc,MAAM,OAAO;EACnC,WAAW,MAAM,aAAa,KAAA;EAC9B,cAAc,MAAM,gBAAgB,KAAA;EACpC,QAAQ,MAAM,UAAU,KAAA;EACxB,WAAW,MAAM;EACjB,WAAW,MAAM,aAAa,KAAA;EAC9B,MAAM,YAAY,MAAM,KAAK;EAC7B,OAAO,MAAM,SAAS,KAAA;EACtB,UAAU,MAAM,YAAY,KAAA;EAC5B,aAAa,MAAM,eAAe,KAAA;EAClC,oBAAoB,MAAM;EAC1B,eAAe,MAAM;EACrB,QAAQ,MAAM;EACd,cAAc,MAAM;EACpB,UAAU,MAAM;EAChB,UAAU,MAAM;EAChB,YAAY,MAAM;EAClB,qBAAqB,MAAM;EAC3B,qBAAqB,MAAM;EAC3B,eAAe,MAAM;EACrB,mBAAmB,MAAM;EACzB,wBAAwB,MAAM;EAC/B;;AAGH,SAAS,uBAAuB,OAAyC;CACvE,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;CACpC,MAAM,WACJ,MAAM,WAAW,aAAa,MAAM,WAAW,aAC3C,YACA,MAAM,WAAW,YACf,YACA;AAER,QAAO;EACL,IAAI,MAAM;EACV;EACA,cAAc,MAAM,gBAAgB;EACpC,OAAO,MAAM,SAAS,KAAA;EACtB,cAAc,MAAM;EACpB,mBAAmB;EACpB;;AAGH,SAAS,oBACP,OACsC;AACtC,KAAI,CAAC,MAAO,QAAO,KAAA;AACnB,KACE,UAAU,aACV,UAAU,eACV,UAAU,YACV,UAAU,YACV,UAAU,UAEV,QAAO;;AAKX,SAAS,kBACP,OACoC;AACpC,KAAI,CAAC,MAAO,QAAO,KAAA;AACnB,KACE,UAAU,aACV,UAAU,aACV,UAAU,YACV,UAAU,YACV,UAAU,aACV,UAAU,kBAEV,QAAO;;AAKX,SAAS,mBACP,OACqC;AACrC,KAAI,CAAC,MAAO,QAAO,KAAA;AACnB,KACE,UAAU,aACV,UAAU,YACV,UAAU,aACV,UAAU,eACV,UAAU,YACV,UAAU,SAEV,QAAO;;AAKX,SAAS,0BACP,OAC4C;AAC5C,KAAI,CAAC,MAAO,QAAO,KAAA;AACnB,KACE,UAAU,aACV,UAAU,aACV,UAAU,YACV,UAAU,YACV,UAAU,UAEV,QAAO;;AAKX,SAAS,6BAA6B,QAA8C;CAClF,MAAM,WAAW,OAAO;AACxB,QAAO;EACL,SAAS,OAAO;EAChB,cAAc,oBAAoB,SAAS,aAAa;EACxD,YAAY,kBAAkB,SAAS,WAAW;EAClD,aAAa,mBAAmB,SAAS,YAAY;EACrD,oBAAoB,0BAA0B,SAAS,mBAAmB;EAC1E,eAAe,SAAS,iBAAiB;EACzC,WAAW,SAAS;EACpB,OAAO,SAAS;EAChB,kBAAkB,SAAS;EAC3B,oBAAoB,SAAS;EAC7B,WAAW,SAAS;EACpB,gBAAgB,SAAS;EACzB,YAAY,SAAS;EACrB,kBAAkB,KAAA;EAClB,gBAAgB,KAAA;EAChB,iBAAiB,KAAA;EAClB;;AAGH,SAAS,iBAAiB,OAA+B;AACvD,KAAI,OAAO,UAAU,SAAU,QAAO;CACtC,MAAM,UAAU,MAAM,MAAM;AAC5B,QAAO,UAAU,QAAQ,aAAa,GAAG;;AAG3C,SAAS,cAAc,OAKX;CACV,MAAM,QAAQ,OAAO,MAAM,SAAS,GAAG,CAAC,aAAa;CACrD,MAAM,SAAS,OAAO,MAAM,UAAU,GAAG,CAAC,aAAa;CACvD,MAAM,kBAAkB,OAAO,MAAM,mBAAmB,GAAG,CAAC,aAAa;AACzE,KAAI,MAAM,YAAa,QAAO;AAC9B,KACE,UAAU,YACV,UAAU,UACV,UAAU,YAEV,QAAO;AAET,KACE,WAAW,UACX,WAAW,YACX,WAAW,eACX,WAAW,eACX,WAAW,WAEX,QAAO;AAET,KACE,oBAAoB,UACpB,oBAAoB,YACpB,oBAAoB,eACpB,oBAAoB,eACpB,oBAAoB,WAEpB,QAAO;AAET,QAAO;;AAGT,eAAe,qBACb,UACsB;CACtB,MAAM,EAAE,uBAAuB,4BAA4B,MAAM,OAC/D;CAEF,MAAM,eAAe,uBAAuB;AAC5C,OAAM,wBAAwB,EAAE,aAAa,MAAM,CAAC;CAEpD,MAAM,SAAS,aAAa,UAAU,EAAE,kBAAkB,MAAM,CAAC;CACjE,MAAM,+BAAe,IAAI,KAAa;AACtC,MAAK,MAAM,SAAS,QAAQ;AAC1B,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU;EACzC,MAAM,OAAO;EACb,MAAM,UAAU,iBAAiB,KAAK,WAAW,IAAI,iBAAiB,KAAK,GAAG;AAC9E,MAAI,CAAC,QAAS;AACd,MAAI,CAAC,cAAc,MAAa,CAC9B,cAAa,IAAI,QAAQ;;AAI7B,QAAO,mCAAmC,UAAU,aAAa;;AAGnE,eAAe,aACb,SAC4D;CAC5D,MAAM,EAAE,0BAA0B,MAAM,OACtC;CAEF,MAAM,SAAS,MAAM,sBAAsB,QAAQ;AACnD,KAAI,CAAC,OAAO,GAAI,QAAO;EAAE,OAAO;EAAO,gBAAgB;EAAM;AAC7D,QAAO;EAAE,OAAO;EAAM,gBAAgB,OAAO,GAAG;EAAgB;;;;;;;;AASlE,eAAsB,iBACpB,KACA,MAC4B;CAC5B,MAAM,UAAU,MAAM,WAAW;CAGjC,MAAM,EAAE,WAAW,kBAAkB,mBAAmB;EACtD;EACA,kBAAkB,MAAM;EACzB,CAAC;CAGF,IAAI,gBAA0D,EAAE;AAChE,KAAI;AACF,kBAAgB,MAAM,OAAO,WAAW,mBAAmB,CAAC;UACrD,KAAK;AACZ,UAAQ,KACN,+EACC,IAAc,QAChB;AACD,kBAAgB,mBAAmB,CAAC,KAAK,UAAU;AAkDjD,UAAO;IAhDL,IAAI,MAAM;IACV,SAAS,MAAM;IACf,WAAW,MAAM,aAAa;IAC9B,MAAM,MAAM;IACZ,OAAO,MAAM,SAAS;IACtB,QAAQ,MAAM;IACd,WAAW,MAAM,8BAAa,IAAI,MAAM,EAAC,aAAa;IACtD,SAAS,MAAM,UAAW,MAAM,UAAoC,KAAA;IACpE,cAAc,MAAM,gBAAgB,KAAA;IACpC,cAAc,MAAM,gBAAgB,KAAA;IACpC,WAAW,MAAM,aAAa,KAAA;IAC9B,eAAe,MAAM,iBAAiB,KAAA;IACtC,gBAAgB,MAAM,kBAAkB,KAAA;IACxC,kBAAkB,MAAM,oBAAoB,KAAA;IAC5C,QAAQ,MAAM,UAAU,KAAA;IACxB,cAAc,MAAM,gBAAgB,KAAA;IACpC,UAAU,MAAM,YAAY,KAAA;IAC5B,UAAU,MAAM,YAAY,KAAA;IAC5B,YAAY,MAAM,cAAc,KAAA;IAChC,qBAAqB,MAAM,uBAAuB,KAAA;IAClD,qBAAqB,MAAM,uBAAuB,KAAA;IAClD,eAAe,MAAM,iBAAiB,KAAA;IACtC,mBAAmB,MAAM,qBAAqB,KAAA;IAC9C,wBAAwB,MAAM,0BAA0B,KAAA;IACxD,QAAQ,MAAM,UAAU,KAAA;IACxB,WAAW,MAAM,aAAa,KAAA;IAC9B,WAAW,MAAM,aAAa,KAAA;IAC9B,OAAO,MAAM,QAAS,MAAM,QAAgC,KAAA;IAC5D,UAAU,MAAM,YAAY,KAAA;IAC5B,aAAa,MAAM,eAAe,KAAA;IAClC,iBAAiB,MAAM,mBAAmB,KAAA;IAC1C,mBAAmB,MAAM,qBAAqB,KAAA;IAC9C,gBAAgB,MAAM,iBACjB,MAAM,iBACP,KAAA;IACJ,eAAe,MAAM,iBAAiB,KAAA;IACtC,eAAe,MAAM,iBAAiB,KAAA;IACtC,aAAa,MAAM,eAAe,KAAA;IAClC,kBAAkB,MAAM,oBAAoB,KAAA;IAC5C,wBAAwB,MAAM,0BAA0B,KAAA;IACxD,kBAAkB,MAAM,oBAAoB,KAAA;IAC5C,uBAAuB,MAAM,wBACxB,MAAM,wBACP,KAAA;IACJ,oBAAoB,MAAM,sBAAsB,KAAA;IAChD,cAAc,MAAM,gBAAgB,KAAA;IACpC,gBAAgB,MAAM,kBAAkB,KAAA;IAEvB,YAAY;IAAO;IACtC;;CAGJ,MAAM,aAA4C,EAAE;CACpD,MAAM,mBAAyD,EAAE;AACjE,MAAK,MAAM,KAAK,eAAe;AAC7B,aAAW,EAAE,MAAM,gBAAgB,EAAE;AACrC,mBAAiB,EAAE,MAAM,uBAAuB,EAAE;;CAKpD,MAAM,WAAW,MAAM,qBADN,kBAAkB,CAAC,KAAK,EAAE,aAAa,OACJ,CAAC;CAGrD,MAAM,cAA6C;EACjD,MAAM;EACN,QAAQ;EACR,OAAO;EACP,MAAM;EACP;CACD,MAAM,iBAAgD,EAAE;CACxD,MAAM,wBAA8D,EAAE;AAEtE,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,UAAU,uBAAuB,QAAQ;EAC/C,MAAM,SAAS,UAAU,MAAM,gBAAgB,SAAS,QAAQ,GAAG;EACnE,MAAM,EAAE,OAAO,mBAAmB,MAAM,aAAa,QAAQ;EAC7D,MAAM,QAAQ,oBAAoB;GAChC,aAAa;GACb;GACA;GACA;GACD,CAAC;AACF,cAAY;AACZ,iBAAe,WAAW;AAE1B,MAAI,OACF,uBAAsB,WAAW,6BAA6B,OAAO;AAGvE,MAAI,QACF,SAAQ,IAAI,uBAAuB,QAAQ,KAAK,QAAQ;;AAI5D,QAAO;EACL,kBAAkB,SAAS;EAC3B;EACA;EACA;EACA;EACA;EACA;EACD;;AAGH,SAAgB,qBAAqB,MAAuD;AAC1F,QAAO,iBAAiB,KAAA,GAAW,KAAK;;;;gBAxZoC;cACZ;gBACI;cAKxC;2BACgD;oBACF"}
|
|
1
|
+
{"version":3,"file":"reconstruct-cache-9SWp82SQ.js","names":[],"sources":["../src/lib/reconstruct/enumerate-in-flight.ts","../src/lib/reconstruct/derive-phase.ts","../src/lib/reconstruct/reconstruct-cache.ts"],"sourcesContent":["/**\n * PAN-1920: source-of-truth enumerator for in-flight issues.\n *\n * In-flight = OPEN GitHub issue ∩ has a `feature/<id-lowercase>` workspace on disk.\n * Reads only git worktrees / the workspaces directory; never the SQLite cache.\n */\n\nimport { readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport type { ProjectConfig } from '../projects.js';\n\nconst execAsync = promisify(exec);\n\nconst FEATURE_DIR_RE = /^feature-([a-z0-9-]+)$/;\n\n/**\n * List the issue IDs that are both OPEN on GitHub and have a local\n * `feature/<id-lowercase>` workspace directory.\n */\nexport async function enumerateInFlightIssuesFromSources(\n projects: ProjectConfig[],\n openIssueIds: Set<string>,\n): Promise<Set<string>> {\n const inFlight = new Set<string>();\n const seen = new Set<string>();\n\n for (const project of projects) {\n const workspaceConfig = project.workspace || {};\n const workspacesDir = join(project.path, workspaceConfig.workspaces_dir || 'workspaces');\n\n // Primary source: scan the workspaces directory for feature-* folders.\n // This works for monorepos and polyrepos alike.\n try {\n const entries = await readdir(workspacesDir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const match = FEATURE_DIR_RE.exec(entry.name);\n if (!match) continue;\n const issueId = match[1]!.toUpperCase();\n if (seen.has(issueId)) continue;\n seen.add(issueId);\n if (openIssueIds.has(issueId)) {\n inFlight.add(issueId);\n }\n }\n } catch {\n // workspaces directory may not exist for this project\n }\n\n // Secondary source: git worktree list (useful when the workspace directory\n // is a git worktree but lives outside the configured workspaces_dir).\n try {\n const { stdout } = await execAsync('git worktree list --porcelain', {\n cwd: project.path,\n timeout: 10_000,\n });\n for (const line of stdout.split('\\n')) {\n const worktreeMatch = /^worktree\\s+(.+)$/.exec(line);\n if (!worktreeMatch) continue;\n const worktreePath = worktreeMatch[1]!;\n const baseName = worktreePath.split('/').pop() ?? worktreePath;\n const dirMatch = FEATURE_DIR_RE.exec(baseName);\n if (!dirMatch) continue;\n const issueId = dirMatch[1]!.toUpperCase();\n if (seen.has(issueId)) continue;\n seen.add(issueId);\n if (openIssueIds.has(issueId)) {\n inFlight.add(issueId);\n }\n }\n } catch {\n // project root may not be a git repo, or git is unavailable\n }\n }\n\n return inFlight;\n}\n","/**\n * PAN-1920: derive the dashboard pipeline phase from sources of truth only.\n *\n * The phase is a function of GitHub issue state, the per-issue git-tracked\n * record, and the GitHub PR reviewDecision. It never reads the SQLite cache.\n */\n\nimport type { PanIssueRecord } from '../pan-dir/record.js';\n\nexport type PipelinePhase = 'work' | 'review' | 'merge' | 'done';\n\nexport interface DerivePhaseArgs {\n /** True when the tracker issue itself is closed/done. */\n issueClosed: boolean;\n /** True when a PR exists for the feature branch. */\n hasPr: boolean;\n /** Per-issue git-tracked record (may be null while PAN-1919 is rolling out). */\n record: PanIssueRecord | null;\n /** GitHub `reviewDecision` from `gh pr view --json reviewDecision`. */\n reviewDecision: string | null;\n}\n\n/**\n * Derive the pipeline phase from sources.\n *\n * Rules (D3/D4):\n * - issue closed on tracker → done\n * - no PR → work\n * - approved (record readyForMerge / reviewStatus passed / GitHub APPROVED) → merge\n * - PR open but not approved → review\n */\nexport function derivePipelinePhase(args: DerivePhaseArgs): PipelinePhase {\n if (args.issueClosed) return 'done';\n if (!args.hasPr) return 'work';\n\n const approved =\n args.record?.pipeline?.readyForMerge === true ||\n args.record?.pipeline?.reviewStatus === 'passed' ||\n args.reviewDecision === 'APPROVED';\n\n return approved ? 'merge' : 'review';\n}\n","/**\n * PAN-1920: reconstruct the dashboard cache from sources of truth.\n *\n * Rebuilds the agents table from state.json + tmux, enumerates in-flight\n * issues from GitHub + workspaces, derives pipeline phases from the per-issue\n * record + GitHub PR state, and produces the AgentSnapshot / AgentRuntimeSnapshot\n * maps the dashboard bootstrap paths need.\n *\n * Reads NO SQLite cache tables: no events, no projection cache, no review_status.\n */\n\nimport { Effect } from 'effect';\nimport type {\n AgentRuntimeSnapshot,\n AgentSnapshot,\n ReviewStatusSnapshot,\n} from '@overdeck/contracts';\nimport { backfillAgentsSync, listAllAgentsSync } from '../overdeck/agents.js';\nimport { listRunningAgents, type AgentState } from '../agents.js';\nimport { listProjectsSync, type ProjectConfig } from '../projects.js';\nimport {\n readIssueRecord,\n resolveProjectForIssue,\n type PanIssueRecord,\n} from '../pan-dir/record.js';\nimport { enumerateInFlightIssuesFromSources } from './enumerate-in-flight.js';\nimport { derivePipelinePhase, type PipelinePhase } from './derive-phase.js';\n\nexport interface ReconstructOptions {\n verbose?: boolean;\n /** Override tmux session discovery for tests / headless environments. */\n listLiveSessions?: () => Set<string>;\n}\n\nexport interface ReconstructResult {\n issuesEnumerated: number;\n agentsRebuilt: number;\n phaseCounts: Record<PipelinePhase, number>;\n agentRuntimeById: Record<string, AgentRuntimeSnapshot>;\n agentsById: Record<string, AgentSnapshot>;\n reviewStatusByIssueId: Record<string, ReviewStatusSnapshot>;\n phaseByIssueId: Record<string, PipelinePhase>;\n}\n\nfunction toAgentStatus(status: string): AgentSnapshot['status'] {\n if (\n status === 'starting' ||\n status === 'running' ||\n status === 'stopped' ||\n status === 'error'\n ) {\n return status;\n }\n return 'unknown';\n}\n\nfunction toAgentRole(role: string): AgentSnapshot['role'] | undefined {\n if (\n role === 'plan' ||\n role === 'work' ||\n role === 'review' ||\n role === 'test' ||\n role === 'ship' ||\n role === 'flywheel' ||\n role === 'strike'\n ) {\n return role;\n }\n return undefined;\n}\n\nfunction toAgentSnapshot(state: AgentState & { tmuxActive?: boolean }): AgentSnapshot {\n return {\n id: state.id,\n issueId: state.issueId,\n workspace: state.workspace || undefined,\n runtime: state.harness || undefined,\n model: state.model || undefined,\n status: toAgentStatus(state.status),\n startedAt: state.startedAt || undefined,\n lastActivity: state.lastActivity || undefined,\n branch: state.branch || undefined,\n costSoFar: state.costSoFar,\n sessionId: state.sessionId || undefined,\n role: toAgentRole(state.role),\n phase: state.phase || undefined,\n workType: state.workType || undefined,\n roleRunHead: state.roleRunHead || undefined,\n hasLiveTmuxSession: state.tmuxActive,\n stoppedByUser: state.stoppedByUser,\n paused: state.paused,\n pausedReason: state.pausedReason,\n pausedAt: state.pausedAt,\n troubled: state.troubled,\n troubledAt: state.troubledAt,\n consecutiveFailures: state.consecutiveFailures,\n firstFailureInRunAt: state.firstFailureInRunAt,\n lastFailureAt: state.lastFailureAt,\n lastFailureReason: state.lastFailureReason,\n lastFailureNextRetryAt: state.lastFailureNextRetryAt,\n };\n}\n\nfunction toAgentRuntimeSnapshot(state: AgentState): AgentRuntimeSnapshot {\n const now = new Date().toISOString();\n const activity: AgentRuntimeSnapshot['activity'] =\n state.status === 'running' || state.status === 'starting'\n ? 'working'\n : state.status === 'stopped'\n ? 'stopped'\n : 'idle';\n\n return {\n id: state.id,\n activity,\n lastActivity: state.lastActivity || now,\n model: state.model || undefined,\n currentIssue: state.issueId,\n updatedAtSequence: 0,\n };\n}\n\nfunction toReviewStatusValue(\n value: string | undefined,\n): ReviewStatusSnapshot['reviewStatus'] {\n if (!value) return undefined;\n if (\n value === 'pending' ||\n value === 'reviewing' ||\n value === 'passed' ||\n value === 'failed' ||\n value === 'blocked'\n ) {\n return value;\n }\n return undefined;\n}\n\nfunction toTestStatusValue(\n value: string | undefined,\n): ReviewStatusSnapshot['testStatus'] {\n if (!value) return undefined;\n if (\n value === 'pending' ||\n value === 'testing' ||\n value === 'passed' ||\n value === 'failed' ||\n value === 'skipped' ||\n value === 'dispatch_failed'\n ) {\n return value;\n }\n return undefined;\n}\n\nfunction toMergeStatusValue(\n value: string | undefined,\n): ReviewStatusSnapshot['mergeStatus'] {\n if (!value) return undefined;\n if (\n value === 'pending' ||\n value === 'queued' ||\n value === 'merging' ||\n value === 'verifying' ||\n value === 'merged' ||\n value === 'failed'\n ) {\n return value;\n }\n return undefined;\n}\n\nfunction toVerificationStatusValue(\n value: string | undefined,\n): ReviewStatusSnapshot['verificationStatus'] {\n if (!value) return undefined;\n if (\n value === 'pending' ||\n value === 'running' ||\n value === 'passed' ||\n value === 'failed' ||\n value === 'skipped'\n ) {\n return value;\n }\n return undefined;\n}\n\nfunction recordToReviewStatusSnapshot(record: PanIssueRecord): ReviewStatusSnapshot {\n const pipeline = record.pipeline;\n return {\n issueId: record.issueId,\n reviewStatus: toReviewStatusValue(pipeline.reviewStatus),\n testStatus: toTestStatusValue(pipeline.testStatus),\n mergeStatus: toMergeStatusValue(pipeline.mergeStatus),\n verificationStatus: toVerificationStatusValue(pipeline.verificationStatus),\n readyForMerge: pipeline.readyForMerge ?? false,\n updatedAt: pipeline.updatedAt,\n prUrl: pipeline.prUrl,\n reviewedAtCommit: pipeline.reviewedAtCommit,\n lastVerifiedCommit: pipeline.lastVerifiedCommit,\n autoMerge: pipeline.autoMerge,\n blockerReasons: pipeline.blockerReasons as ReviewStatusSnapshot['blockerReasons'],\n mergeNotes: pipeline.mergeNotes,\n reviewRetryCount: undefined,\n testRetryCount: undefined,\n mergeRetryCount: undefined,\n };\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\nfunction isIssueClosed(issue: {\n completedAt?: unknown;\n state?: unknown;\n canonicalStatus?: unknown;\n status?: unknown;\n}): boolean {\n const state = String(issue.state ?? '').toLowerCase();\n const status = String(issue.status ?? '').toLowerCase();\n const canonicalStatus = String(issue.canonicalStatus ?? '').toLowerCase();\n if (issue.completedAt) return true;\n if (\n state === 'closed' ||\n state === 'done' ||\n state === 'completed'\n ) {\n return true;\n }\n if (\n status === 'done' ||\n status === 'closed' ||\n status === 'completed' ||\n status === 'cancelled' ||\n status === 'canceled'\n ) {\n return true;\n }\n if (\n canonicalStatus === 'done' ||\n canonicalStatus === 'closed' ||\n canonicalStatus === 'completed' ||\n canonicalStatus === 'cancelled' ||\n canonicalStatus === 'canceled'\n ) {\n return true;\n }\n return false;\n}\n\nasync function loadInFlightIssueIds(\n projects: ProjectConfig[],\n): Promise<Set<string>> {\n const { getSharedIssueService, startSharedIssueService } = await import(\n '../../dashboard/server/services/issue-service-singleton.js'\n );\n const issueService = getSharedIssueService();\n await startSharedIssueService({ skipPolling: true });\n\n const issues = issueService.getIssues({ includeCompleted: true });\n const openIssueIds = new Set<string>();\n for (const issue of issues) {\n if (!issue || typeof issue !== 'object') continue;\n const item = issue as { identifier?: unknown; id?: unknown };\n const issueId = normalizeIssueId(item.identifier) ?? normalizeIssueId(item.id);\n if (!issueId) continue;\n if (!isIssueClosed(issue as any)) {\n openIssueIds.add(issueId);\n }\n }\n\n return enumerateInFlightIssuesFromSources(projects, openIssueIds);\n}\n\nasync function fetchPrState(\n issueId: string,\n): Promise<{ hasPr: boolean; reviewDecision: string | null }> {\n const { fetchIssuePullRequest } = await import(\n '../overdeck/pull-requests.js'\n );\n const result = await fetchIssuePullRequest(issueId);\n if (!result.pr) return { hasPr: false, reviewDecision: null };\n return { hasPr: true, reviewDecision: result.pr.reviewDecision };\n}\n\n/**\n * Reconstruct the dashboard cache from durable sources only.\n *\n * The `_db` parameter is accepted for backward compatibility but is no longer\n * used — the cache now reads from the overdeck layer directly.\n */\nexport async function reconstructCache(\n _db?: unknown,\n opts?: ReconstructOptions,\n): Promise<ReconstructResult> {\n const verbose = opts?.verbose ?? false;\n\n // 1. Rebuild the agents table from state.json + tmux (sources-only).\n const { processed: agentsRebuilt } = backfillAgentsSync({\n verbose,\n listLiveSessions: opts?.listLiveSessions,\n });\n\n // 2. Build AgentSnapshot / AgentRuntimeSnapshot maps from the rebuilt table.\n let runningAgents: (AgentState & { tmuxActive: boolean })[] = [];\n try {\n runningAgents = await Effect.runPromise(listRunningAgents());\n } catch (err) {\n console.warn(\n '[reconstruct-cache] listRunningAgents failed, falling back to agents table:',\n (err as Error).message,\n );\n runningAgents = listAllAgentsSync().map((agent) => {\n const state = {\n id: agent.id,\n issueId: agent.issueId,\n workspace: agent.workspace ?? '',\n role: agent.role as AgentState['role'],\n model: agent.model ?? '',\n status: agent.status as AgentState['status'],\n startedAt: agent.startedAt ?? new Date().toISOString(),\n harness: agent.harness ? (agent.harness as AgentState['harness']) : undefined,\n lastActivity: agent.lastActivity ?? undefined,\n lastResumeAt: agent.lastResumeAt ?? undefined,\n stoppedAt: agent.stoppedAt ?? undefined,\n stoppedByUser: agent.stoppedByUser ?? undefined,\n stoppedByPause: agent.stoppedByPause ?? undefined,\n kickoffDelivered: agent.kickoffDelivered ?? undefined,\n paused: agent.paused ?? undefined,\n pausedReason: agent.pausedReason ?? undefined,\n pausedAt: agent.pausedAt ?? undefined,\n troubled: agent.troubled ?? undefined,\n troubledAt: agent.troubledAt ?? undefined,\n consecutiveFailures: agent.consecutiveFailures ?? undefined,\n firstFailureInRunAt: agent.firstFailureInRunAt ?? undefined,\n lastFailureAt: agent.lastFailureAt ?? undefined,\n lastFailureReason: agent.lastFailureReason ?? undefined,\n lastFailureNextRetryAt: agent.lastFailureNextRetryAt ?? undefined,\n branch: agent.branch ?? undefined,\n costSoFar: agent.costSoFar ?? undefined,\n sessionId: agent.sessionId ?? undefined,\n phase: agent.phase ? (agent.phase as AgentState['phase']) : undefined,\n workType: agent.workType ?? undefined,\n roleRunHead: agent.roleRunHead ?? undefined,\n channelsEnabled: agent.channelsEnabled ?? undefined,\n supervisorEnabled: agent.supervisorEnabled ?? undefined,\n deliveryMethod: agent.deliveryMethod\n ? (agent.deliveryMethod as AgentState['deliveryMethod'])\n : undefined,\n flywheelRunId: agent.flywheelRunId ?? undefined,\n reviewSubRole: agent.reviewSubRole ?? undefined,\n reviewRunId: agent.reviewRunId ?? undefined,\n reviewOutputPath: agent.reviewOutputPath ?? undefined,\n reviewSynthesisAgentId: agent.reviewSynthesisAgentId ?? undefined,\n reviewDeadlineAt: agent.reviewDeadlineAt ?? undefined,\n reviewMonitorSignaled: agent.reviewMonitorSignaled\n ? (agent.reviewMonitorSignaled as AgentState['reviewMonitorSignaled'])\n : undefined,\n reviewRetryAttempt: agent.reviewRetryAttempt ?? undefined,\n hostOverride: agent.hostOverride ?? undefined,\n inspectSubRole: agent.inspectSubRole ?? undefined,\n } satisfies AgentState;\n return { ...state, tmuxActive: false };\n });\n }\n\n const agentsById: Record<string, AgentSnapshot> = {};\n const agentRuntimeById: Record<string, AgentRuntimeSnapshot> = {};\n for (const a of runningAgents) {\n agentsById[a.id] = toAgentSnapshot(a);\n agentRuntimeById[a.id] = toAgentRuntimeSnapshot(a);\n }\n\n // 3. Enumerate in-flight issues from GitHub + workspaces.\n const projects = listProjectsSync().map(({ config }) => config);\n const inFlight = await loadInFlightIssueIds(projects);\n\n // 4. Derive phases and review-status snapshots from sources.\n const phaseCounts: Record<PipelinePhase, number> = {\n work: 0,\n review: 0,\n merge: 0,\n done: 0,\n };\n const phaseByIssueId: Record<string, PipelinePhase> = {};\n const reviewStatusByIssueId: Record<string, ReviewStatusSnapshot> = {};\n\n for (const issueId of inFlight) {\n const project = resolveProjectForIssue(issueId);\n const record = project ? await readIssueRecord(project, issueId) : null;\n const { hasPr, reviewDecision } = await fetchPrState(issueId);\n const phase = derivePipelinePhase({\n issueClosed: false,\n hasPr,\n record,\n reviewDecision,\n });\n phaseCounts[phase]++;\n phaseByIssueId[issueId] = phase;\n\n if (record) {\n reviewStatusByIssueId[issueId] = recordToReviewStatusSnapshot(record);\n }\n\n if (verbose) {\n console.log(`[reconstruct-cache] ${issueId} → ${phase}`);\n }\n }\n\n return {\n issuesEnumerated: inFlight.size,\n agentsRebuilt,\n phaseCounts,\n agentRuntimeById,\n agentsById,\n reviewStatusByIssueId,\n phaseByIssueId,\n };\n}\n\nexport function reconstructCacheAuto(opts?: ReconstructOptions): Promise<ReconstructResult> {\n return reconstructCache(undefined, opts);\n}\n"],"mappings":"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"}
|
|
@@ -577,6 +577,18 @@ async function buildIssueRecord(project, issueId, opts = {}) {
|
|
|
577
577
|
};
|
|
578
578
|
}
|
|
579
579
|
/**
|
|
580
|
+
* PAN-2587: never regress the pipeline block during a whole-record rebuild. A
|
|
581
|
+
* concurrent writer (e.g. a reviewer's verdict landing between the rebuild's
|
|
582
|
+
* `existing` snapshot and its write) may have put a NEWER pipeline on disk than
|
|
583
|
+
* the status the rebuild projects — observed clobbering PAN-399's passed
|
|
584
|
+
* verdict back to a pre-verdict snapshot. Same newer-wins rule (ISO `updatedAt`
|
|
585
|
+
* comparison) the journal readers use.
|
|
586
|
+
*/
|
|
587
|
+
function pickNewerPipeline(rebuilt, fresh) {
|
|
588
|
+
if (!fresh?.updatedAt || !rebuilt?.updatedAt) return rebuilt;
|
|
589
|
+
return rebuilt.updatedAt < fresh.updatedAt ? fresh : rebuilt;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
580
592
|
* PAN-1908 / PAN-1919: rebuild and queue the per-issue permanent record for a
|
|
581
593
|
* given issue. Fire-and-forget: failures are logged, never thrown, so
|
|
582
594
|
* review-status writes stay synchronous and fast.
|
|
@@ -600,6 +612,7 @@ async function updateIssueRecordForIssue(issueId, reviewStatus) {
|
|
|
600
612
|
...record.statusOverrides,
|
|
601
613
|
...fresh.statusOverrides
|
|
602
614
|
};
|
|
615
|
+
record.pipeline = pickNewerPipeline(record.pipeline, fresh?.pipeline);
|
|
603
616
|
queueIssueRecordCommit(project, issueId, writeIssueRecordSync(project, issueId, record));
|
|
604
617
|
});
|
|
605
618
|
return true;
|
|
@@ -620,4 +633,4 @@ var init_records = __esmMin((() => {
|
|
|
620
633
|
//#endregion
|
|
621
634
|
export { listOverdeckAgentStatesSync as _, withIssueRecordLock as a, getReviewStatusFromDbSync as c, markWorkspaceStuck as d, upsertReviewStatusSync as f, init_agent_state_sync as g, getOverdeckAgentStateSync as h, init_record_lock as i, getReviewStatusesFromDb as l, normalizeReviewStatusSync as m, init_records as n, deleteReviewStatus as o, init_review_status_normalize as p, updateIssueRecordForIssue as r, getAllReviewStatusesFromDb as s, buildIssueRecord as t, init_review_status_sync as u, saveOverdeckAgentStateSync as v };
|
|
622
635
|
|
|
623
|
-
//# sourceMappingURL=records-
|
|
636
|
+
//# sourceMappingURL=records-CTmvuRzz.js.map
|