@overdeck/core 0.50.3 → 0.50.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents-DNMRPC8n.js.map +1 -1
- package/dist/{build-info-BJuEVWOh.js → build-info-ioRdOmqT.js} +3 -3
- package/dist/{build-info-BJuEVWOh.js.map → build-info-ioRdOmqT.js.map} +1 -1
- package/dist/build-info-kMMitDOP.js +2 -0
- package/dist/cli/index.js +4 -4
- package/dist/conversation-compaction-GFfO5UZL.js.map +1 -1
- package/dist/dashboard/{advancing-selfheal-Bq8V0QUa.js → advancing-selfheal-Dp5_Gai3.js} +3 -3
- package/dist/dashboard/{advancing-selfheal-Bq8V0QUa.js.map → advancing-selfheal-Dp5_Gai3.js.map} +1 -1
- package/dist/dashboard/{agent-gc-Coz8zQt_.js → agent-gc-JzoSs5Pi.js} +3 -3
- package/dist/dashboard/{agent-gc-Coz8zQt_.js.map → agent-gc-JzoSs5Pi.js.map} +1 -1
- package/dist/dashboard/{agent-idle-CAwB-K6M.js → agent-idle-D-Qy5BN_.js} +2 -2
- package/dist/dashboard/{agent-idle-CAwB-K6M.js.map → agent-idle-D-Qy5BN_.js.map} +1 -1
- package/dist/dashboard/{agent-state-Ci6PhjOE.js → agent-state-B196fj1h.js} +38 -16
- package/dist/dashboard/agent-state-B196fj1h.js.map +1 -0
- package/dist/dashboard/{agent-state-CbUEwUEQ.js → agent-state-IpWnw8lv.js} +1 -1
- package/dist/dashboard/{agent-state-service-D6IVrX3B.js → agent-state-service-CCo5-9DR.js} +3 -3
- package/dist/dashboard/{agent-state-service-D6IVrX3B.js.map → agent-state-service-CCo5-9DR.js.map} +1 -1
- package/dist/dashboard/{agent-state-service-DcN1j6eK.js → agent-state-service-D_F3VZ23.js} +1 -1
- package/dist/dashboard/{agents-BVvL4o_4.js → agents-CkGhnAmu.js} +1 -1
- package/dist/dashboard/{backlog-auto-trigger-BuSBqG2V.js → backlog-auto-trigger-B5Z2zBtC.js} +2 -2
- package/dist/dashboard/{backlog-auto-trigger-BuSBqG2V.js.map → backlog-auto-trigger-B5Z2zBtC.js.map} +1 -1
- package/dist/dashboard/build-info-BTjOB0Xr.js +2 -0
- package/dist/dashboard/{build-info-Cj3Y0K87.js → build-info-D0EJNj6C.js} +3 -3
- package/dist/dashboard/{build-info-Cj3Y0K87.js.map → build-info-D0EJNj6C.js.map} +1 -1
- package/dist/dashboard/cli-CIznFrcE.js +2 -0
- package/dist/dashboard/{cli-DIhQieif.js → cli-DCbVrSsg.js} +2 -2
- package/dist/dashboard/{cli-DIhQieif.js.map → cli-DCbVrSsg.js.map} +1 -1
- package/dist/dashboard/{close-issue-CRlmrE5g.js → close-issue-Bmu9aOIx.js} +2 -2
- package/dist/dashboard/{close-issue-CRlmrE5g.js.map → close-issue-Bmu9aOIx.js.map} +1 -1
- package/dist/dashboard/{closed-issue-reaper-DrHyYgJR.js → closed-issue-reaper-COxfTtLz.js} +5 -5
- package/dist/dashboard/{closed-issue-reaper-DrHyYgJR.js.map → closed-issue-reaper-COxfTtLz.js.map} +1 -1
- package/dist/dashboard/{closed-issue-reaper-DWlw2EtL.js → closed-issue-reaper-DwMwG_Pz.js} +1 -1
- package/dist/dashboard/{compaction-continuation-DhYgsXmF.js → compaction-continuation-Bqc212Zm.js} +2 -2
- package/dist/dashboard/{compaction-continuation-DhYgsXmF.js.map → compaction-continuation-Bqc212Zm.js.map} +1 -1
- package/dist/dashboard/{conflict-gate-vczgdVTa.js → conflict-gate-9mPVg7-5.js} +1 -1
- package/dist/dashboard/{conflict-gate-Bt-lLgYf.js → conflict-gate-CGQTcR0I.js} +3 -3
- package/dist/dashboard/{conflict-gate-Bt-lLgYf.js.map → conflict-gate-CGQTcR0I.js.map} +1 -1
- package/dist/dashboard/{conversation-compaction-CsdCbcQB.js → conversation-compaction-C7P6V8Iw.js} +5 -5
- package/dist/dashboard/{conversation-compaction-CsdCbcQB.js.map → conversation-compaction-C7P6V8Iw.js.map} +1 -1
- package/dist/dashboard/{conversation-compaction-D0zgWM1f.js → conversation-compaction-Cck5oi-V.js} +1 -1
- package/dist/dashboard/{conversation-service-6LaymUV-.js → conversation-service-CsOpwI9Y.js} +37 -5
- package/dist/dashboard/{conversation-service-6LaymUV-.js.map → conversation-service-CsOpwI9Y.js.map} +1 -1
- package/dist/dashboard/conversation-service-plOFkoMo.js +3 -0
- package/dist/dashboard/dashboard-db-worker.js +1 -1
- package/dist/dashboard/{deacon-CU47dU7U.js → deacon-B8oMMIgN.js} +62 -62
- package/dist/dashboard/{deacon-CU47dU7U.js.map → deacon-B8oMMIgN.js.map} +1 -1
- package/dist/dashboard/{deacon-DYsOa_ss.js → deacon-b7J57Svt.js} +2 -2
- package/dist/dashboard/{deacon-pending-lifecycle-ijGX8wLb.js → deacon-pending-lifecycle-3NIJ7ew5.js} +2 -2
- package/dist/dashboard/{deacon-pending-lifecycle-ijGX8wLb.js.map → deacon-pending-lifecycle-3NIJ7ew5.js.map} +1 -1
- package/dist/dashboard/deacon.js +5 -5
- package/dist/dashboard/{delivery-DMYxIE0J.js → delivery-lnI-gQKo.js} +1 -1
- package/dist/dashboard/{deploy-patrol-C4eXco1S.js → deploy-patrol-u3v2krg9.js} +2 -2
- package/dist/dashboard/{deploy-patrol-C4eXco1S.js.map → deploy-patrol-u3v2krg9.js.map} +1 -1
- package/dist/dashboard/{feedback-stuck-retirement-Dd5XNrMr.js → feedback-stuck-retirement-CoFNqjCc.js} +2 -2
- package/dist/dashboard/{feedback-stuck-retirement-Dd5XNrMr.js.map → feedback-stuck-retirement-CoFNqjCc.js.map} +1 -1
- package/dist/dashboard/{feedback-target-BzdJ2wIR.js → feedback-target-BBCh3RRq.js} +1 -1
- package/dist/dashboard/{feedback-target-BcsA_GRV.js → feedback-target-CeCq6EhW.js} +5 -5
- package/dist/dashboard/{feedback-target-BcsA_GRV.js.map → feedback-target-CeCq6EhW.js.map} +1 -1
- package/dist/dashboard/{flywheel-Is3w2lcT.js → flywheel-DKldI63J.js} +7 -7
- package/dist/dashboard/{flywheel-Is3w2lcT.js.map → flywheel-DKldI63J.js.map} +1 -1
- package/dist/dashboard/{flywheel-D0guNqkh.js → flywheel-DpRPLErh.js} +7 -7
- package/dist/dashboard/{flywheel-D0guNqkh.js.map → flywheel-DpRPLErh.js.map} +1 -1
- package/dist/dashboard/{flywheel-B34cdfbd.js → flywheel-jeZFYvm-.js} +1 -1
- package/dist/dashboard/{flywheel-merge-order-6HiPR2WG.js → flywheel-merge-order-0OnoosaO.js} +1 -1
- package/dist/dashboard/{flywheel-merge-order-BsNPMu0S.js → flywheel-merge-order-PG5op4j7.js} +2 -2
- package/dist/dashboard/{flywheel-merge-order-BsNPMu0S.js.map → flywheel-merge-order-PG5op4j7.js.map} +1 -1
- package/dist/dashboard/{harness-resolve-CzTFVZ5l.js → harness-resolve-C0HWj3H9.js} +2 -2
- package/dist/dashboard/{harness-resolve-CzTFVZ5l.js.map → harness-resolve-C0HWj3H9.js.map} +1 -1
- package/dist/dashboard/{identity-Dc7rQLln.js → identity-Cot1Hg4G.js} +2 -2
- package/dist/dashboard/{identity-Dc7rQLln.js.map → identity-Cot1Hg4G.js.map} +1 -1
- package/dist/dashboard/{inspect-agent-CP7Bu47O.js → inspect-agent-BDmLWbGx.js} +3 -3
- package/dist/dashboard/{inspect-agent-CP7Bu47O.js.map → inspect-agent-BDmLWbGx.js.map} +1 -1
- package/dist/dashboard/inspect-agent-BcOkA-hC.js +2 -0
- package/dist/dashboard/{issue-lifecycle-BPbczKyy.js → issue-lifecycle-1B_v8Rf5.js} +6 -6
- package/dist/dashboard/{issue-lifecycle-BPbczKyy.js.map → issue-lifecycle-1B_v8Rf5.js.map} +1 -1
- package/dist/dashboard/{issue-lifecycle-FaugTi39.js → issue-lifecycle-CIrfbIbj.js} +1 -1
- package/dist/dashboard/{issue-service-singleton-Dsad9NTt.js → issue-service-singleton-BVwPzjwF.js} +1 -1
- package/dist/dashboard/{issue-service-singleton-BrZQJLRI.js → issue-service-singleton-KcRrOiFD.js} +2 -2
- package/dist/dashboard/{issue-service-singleton-BrZQJLRI.js.map → issue-service-singleton-KcRrOiFD.js.map} +1 -1
- package/dist/dashboard/{jsonl-resolver-DQEe0DHM.js → jsonl-resolver-jxbif7MD.js} +3 -3
- package/dist/dashboard/{jsonl-resolver-DQEe0DHM.js.map → jsonl-resolver-jxbif7MD.js.map} +1 -1
- package/dist/dashboard/{kimi-code-Cx5YUJpS.js → kimi-code-BZh3NgcN.js} +1 -1
- package/dist/dashboard/{lifecycle-DZFHmpGI.js → lifecycle-CvcZ4_fA.js} +4 -4
- package/dist/dashboard/{lifecycle-DZFHmpGI.js.map → lifecycle-CvcZ4_fA.js.map} +1 -1
- package/dist/dashboard/{linear-mcp-auth-DylPJABZ.js → linear-mcp-auth-CZoj_-d7.js} +1 -1
- package/dist/dashboard/{linear-mcp-auth-BFlpMvWh.js → linear-mcp-auth-Dx74yCAY.js} +2 -2
- package/dist/dashboard/{linear-mcp-auth-BFlpMvWh.js.map → linear-mcp-auth-Dx74yCAY.js.map} +1 -1
- package/dist/dashboard/{memory-governor-B7uDWRo9.js → memory-governor-Bv3LAqk3.js} +5 -5
- package/dist/dashboard/{memory-governor-B7uDWRo9.js.map → memory-governor-Bv3LAqk3.js.map} +1 -1
- package/dist/dashboard/{merge-agent-ddEcZDZD.js → merge-agent-1zVLl6k_.js} +1 -1
- package/dist/dashboard/{merge-agent-ttRY053V.js → merge-agent-8zrQu48t.js} +8 -8
- package/dist/dashboard/{merge-agent-ttRY053V.js.map → merge-agent-8zrQu48t.js.map} +1 -1
- package/dist/dashboard/merge-ops-CFJaMPLu.js +2 -0
- package/dist/dashboard/{merge-train-f_un38UJ.js → merge-train-BYH_cF7G.js} +2 -2
- package/dist/dashboard/{merge-train-f_un38UJ.js.map → merge-train-BYH_cF7G.js.map} +1 -1
- package/dist/dashboard/{merge-train-deps-GPlHOjK6.js → merge-train-deps-BTfXM5AR.js} +2 -2
- package/dist/dashboard/{merge-train-deps-GPlHOjK6.js.map → merge-train-deps-BTfXM5AR.js.map} +1 -1
- package/dist/dashboard/{messaging-BasbftDu.js → messaging-Bk6vGsMw.js} +1 -1
- package/dist/dashboard/{orphan-proposed-reconciler-DFHdQSEg.js → orphan-proposed-reconciler-B898fk26.js} +6 -6
- package/dist/dashboard/{orphan-proposed-reconciler-DFHdQSEg.js.map → orphan-proposed-reconciler-B898fk26.js.map} +1 -1
- package/dist/dashboard/{orphan-proposed-reconciler-DzAxrM99.js → orphan-proposed-reconciler-Bx_aWS4B.js} +1 -1
- package/dist/dashboard/{parked-residue-DMtbxJml.js → parked-residue-q2kzrYSm.js} +9 -9
- package/dist/dashboard/{parked-residue-DMtbxJml.js.map → parked-residue-q2kzrYSm.js.map} +1 -1
- package/dist/dashboard/{post-merge-lifecycle-worker-jzN2g_EY.js → post-merge-lifecycle-worker-Cl7-uf4g.js} +2 -2
- package/dist/dashboard/{post-merge-lifecycle-worker-jzN2g_EY.js.map → post-merge-lifecycle-worker-Cl7-uf4g.js.map} +1 -1
- package/dist/dashboard/{project-resource-refresh-queue-cqOeJ0fB.js → project-resource-refresh-queue-O_dRfPHn.js} +1 -1
- package/dist/dashboard/{project-resource-refresh-queue-DebwjPPA.js → project-resource-refresh-queue-se3T9IYP.js} +4 -4
- package/dist/dashboard/{project-resource-refresh-queue-DebwjPPA.js.map → project-resource-refresh-queue-se3T9IYP.js.map} +1 -1
- package/dist/dashboard/{reconstruct-cache-Bb2Jg2DZ.js → reconstruct-cache-XpWC9L0F.js} +2 -2
- package/dist/dashboard/{reconstruct-cache-Bb2Jg2DZ.js.map → reconstruct-cache-XpWC9L0F.js.map} +1 -1
- package/dist/dashboard/{release-engine-78iCajIc.js → release-engine-BuzxOamf.js} +2 -2
- package/dist/dashboard/{release-engine-78iCajIc.js.map → release-engine-BuzxOamf.js.map} +1 -1
- package/dist/dashboard/{remote-completion-D5wzZCte.js → remote-completion-BCZgeKPS.js} +3 -3
- package/dist/dashboard/{remote-completion-D5wzZCte.js.map → remote-completion-BCZgeKPS.js.map} +1 -1
- package/dist/dashboard/{resolver-BGZh3lXA.js → resolver-BeNrqNou.js} +5 -5
- package/dist/dashboard/{resolver-BGZh3lXA.js.map → resolver-BeNrqNou.js.map} +1 -1
- package/dist/dashboard/{resource-pressure-patrol-Bg23rPV-.js → resource-pressure-patrol-Ccg_aCgO.js} +3 -3
- package/dist/dashboard/{resource-pressure-patrol-Bg23rPV-.js.map → resource-pressure-patrol-Ccg_aCgO.js.map} +1 -1
- package/dist/dashboard/{resume-BKyB4hA1.js → resume-KGCrn0DV.js} +1 -1
- package/dist/dashboard/{review-agent-ZdP-HmwY.js → review-agent-BmM6YMZW.js} +1 -1
- package/dist/dashboard/{review-agent-DHs-JngN.js → review-agent-DRWVU8fP.js} +13 -13
- package/dist/dashboard/{review-agent-DHs-JngN.js.map → review-agent-DRWVU8fP.js.map} +1 -1
- package/dist/dashboard/{review-convoy-liveness-BTMvU4CA.js → review-convoy-liveness-EvCDv8Q_.js} +3 -3
- package/dist/dashboard/{review-convoy-liveness-BTMvU4CA.js.map → review-convoy-liveness-EvCDv8Q_.js.map} +1 -1
- package/dist/dashboard/{review-run-recovery-BYalQzbh.js → review-run-recovery-Ctm48Snt.js} +1 -1
- package/dist/dashboard/{review-run-recovery-BvVG3oUr.js → review-run-recovery-DNDI58cM.js} +2 -2
- package/dist/dashboard/{review-run-recovery-BvVG3oUr.js.map → review-run-recovery-DNDI58cM.js.map} +1 -1
- package/dist/dashboard/{review-status-DXTFzCmR.js → review-status-FnlvQuPI.js} +1 -1
- package/dist/dashboard/{review-status-emit-C9YW6SQL.js → review-status-emit-CeMS31DX.js} +2 -2
- package/dist/dashboard/{review-status-emit-C9YW6SQL.js.map → review-status-emit-CeMS31DX.js.map} +1 -1
- package/dist/dashboard/{review-status-BegAr86G.js → review-status-yY5qt7Rl.js} +5 -5
- package/dist/dashboard/{review-status-BegAr86G.js.map → review-status-yY5qt7Rl.js.map} +1 -1
- package/dist/dashboard/{review-verdict-feedback-qlVBi19-.js → review-verdict-feedback-BNgRj1e3.js} +4 -4
- package/dist/dashboard/{review-verdict-feedback-qlVBi19-.js.map → review-verdict-feedback-BNgRj1e3.js.map} +1 -1
- package/dist/dashboard/{review-verdict-feedback-Dp139Lmv.js → review-verdict-feedback-D39cuSV1.js} +1 -1
- package/dist/dashboard/{review-verdict-writer-CJr_Ob0Y.js → review-verdict-writer-DvFfKAn-.js} +2 -2
- package/dist/dashboard/{review-verdict-writer-CJr_Ob0Y.js.map → review-verdict-writer-DvFfKAn-.js.map} +1 -1
- package/dist/dashboard/{review-verdict-writer-BVco3WoI.js → review-verdict-writer-PcGBkvJ4.js} +1 -1
- package/dist/dashboard/{sequence-io-iljWlslY.js → sequence-io-DZyschsf.js} +2 -2
- package/dist/dashboard/{sequence-io-iljWlslY.js.map → sequence-io-DZyschsf.js.map} +1 -1
- package/dist/dashboard/{sequencer-agent-BGGVKxtw.js → sequencer-agent-BXDw5cNx.js} +5 -5
- package/dist/dashboard/{sequencer-agent-BGGVKxtw.js.map → sequencer-agent-BXDw5cNx.js.map} +1 -1
- package/dist/dashboard/server.js +79 -72
- package/dist/dashboard/server.js.map +1 -1
- package/dist/dashboard/{service-kzhN0DLg.js → service-DP50Omvn.js} +33 -33
- package/dist/dashboard/{service-kzhN0DLg.js.map → service-DP50Omvn.js.map} +1 -1
- package/dist/dashboard/{smart-compaction-owKHJDbL.js → smart-compaction-944GL8PN.js} +1 -1
- package/dist/dashboard/{smart-compaction-C96F2aFQ.js → smart-compaction-BzDfF6yb.js} +2 -2
- package/dist/dashboard/{smart-compaction-C96F2aFQ.js.map → smart-compaction-BzDfF6yb.js.map} +1 -1
- package/dist/dashboard/{spawn-planning-session-CiJdOHTD.js → spawn-planning-session-BcVnHJjm.js} +1 -1
- package/dist/dashboard/{spawn-planning-session-FmJa6PCS.js → spawn-planning-session-CH8IYli7.js} +3 -3
- package/dist/dashboard/{spawn-planning-session-FmJa6PCS.js.map → spawn-planning-session-CH8IYli7.js.map} +1 -1
- package/dist/dashboard/{specialist-context-_ootmzn2.js → specialist-context-DhDTXVht.js} +3 -3
- package/dist/dashboard/{specialist-context-_ootmzn2.js.map → specialist-context-DhDTXVht.js.map} +1 -1
- package/dist/dashboard/{specialist-logs-BbAX221-.js → specialist-logs-C1bcnZ-G.js} +2 -2
- package/dist/dashboard/{specialist-logs-BbAX221-.js.map → specialist-logs-C1bcnZ-G.js.map} +1 -1
- package/dist/dashboard/{specialists-COZoYaiz.js → specialists-BKmReEWT.js} +53 -53
- package/dist/dashboard/{specialists-COZoYaiz.js.map → specialists-BKmReEWT.js.map} +1 -1
- package/dist/dashboard/{specialists-RPLJnYc1.js → specialists-Bvrvt0br.js} +12 -12
- package/dist/dashboard/{specialists-RPLJnYc1.js.map → specialists-Bvrvt0br.js.map} +1 -1
- package/dist/dashboard/{specialists-DTAOVZpU.js → specialists-CD6GEKXk.js} +1 -1
- package/dist/dashboard/{specialists-D8sYZnPb.js → specialists-eFWpJRBc.js} +1 -1
- package/dist/dashboard/{stall-sweeper-9bRBZhrQ.js → stall-sweeper-D3fZvg7O.js} +3 -3
- package/dist/dashboard/{stall-sweeper-9bRBZhrQ.js.map → stall-sweeper-D3fZvg7O.js.map} +1 -1
- package/dist/dashboard/{state-migrate-J3tFJnbd.js → state-migrate-KZ2goscQ.js} +2 -2
- package/dist/dashboard/{state-migrate-J3tFJnbd.js.map → state-migrate-KZ2goscQ.js.map} +1 -1
- package/dist/dashboard/{stuck-remediation-BvTK_NYN.js → stuck-remediation-Cb2V1roj.js} +1 -1
- package/dist/dashboard/{stuck-remediation-4Rf_xMEb.js → stuck-remediation-CnoV0kcv.js} +5 -5
- package/dist/dashboard/{stuck-remediation-4Rf_xMEb.js.map → stuck-remediation-CnoV0kcv.js.map} +1 -1
- package/dist/dashboard/{summary-fork-PLcckTRE.js → summary-fork-CxuNBM0F.js} +2 -2
- package/dist/dashboard/{summary-fork-D-cylknJ.js → summary-fork-lC2vMXly.js} +4 -4
- package/dist/dashboard/{summary-fork-D-cylknJ.js.map → summary-fork-lC2vMXly.js.map} +1 -1
- package/dist/dashboard/{teardown-workspace-CTL16rnG.js → teardown-workspace-C-9murBw.js} +4 -4
- package/dist/dashboard/{teardown-workspace-CTL16rnG.js.map → teardown-workspace-C-9murBw.js.map} +1 -1
- package/dist/dashboard/{test-agent-queue-CMgYZiR_.js → test-agent-queue-YCBRzaAB.js} +3 -3
- package/dist/dashboard/{test-agent-queue-CMgYZiR_.js.map → test-agent-queue-YCBRzaAB.js.map} +1 -1
- package/dist/dashboard/{uat-failure-feedback-DS6W9X3I.js → uat-failure-feedback-B-1mL8Zp.js} +3 -3
- package/dist/dashboard/{uat-failure-feedback-DS6W9X3I.js.map → uat-failure-feedback-B-1mL8Zp.js.map} +1 -1
- package/dist/dashboard/{uat-promote-verification-CRsIHE_q.js → uat-promote-verification-BEBPcpPg.js} +2 -2
- package/dist/dashboard/{uat-promote-verification-CRsIHE_q.js.map → uat-promote-verification-BEBPcpPg.js.map} +1 -1
- package/dist/dashboard/{uat-train-BoA9r6_I.js → uat-train-BFo3OQUB.js} +1 -1
- package/dist/dashboard/{uat-train-Cd8CJeNe.js → uat-train-COgoJomz.js} +8 -8
- package/dist/dashboard/{uat-train-Cd8CJeNe.js.map → uat-train-COgoJomz.js.map} +1 -1
- package/dist/dashboard/{validate-BdmvTIym.js → validate-069_N1e2.js} +2 -2
- package/dist/dashboard/{validate-BdmvTIym.js.map → validate-069_N1e2.js.map} +1 -1
- package/dist/dashboard/{verification-runner-BO0K3xNA.js → verification-runner-CQnZyC5A.js} +1 -1
- package/dist/dashboard/{verification-runner-fEY1Qj-l.js → verification-runner-fy3wNrWn.js} +4 -4
- package/dist/dashboard/{verification-runner-fEY1Qj-l.js.map → verification-runner-fy3wNrWn.js.map} +1 -1
- package/dist/dashboard/workflows-Bk6Kt0ZQ.js +2 -0
- package/dist/dashboard/{workflows-CxVnygYU.js → workflows-N4QMkDzN.js} +10 -10
- package/dist/dashboard/{workflows-CxVnygYU.js.map → workflows-N4QMkDzN.js.map} +1 -1
- package/dist/dashboard/{workspaces-Cpz0xJWQ.js → workspaces-DmoyfHoU.js} +33 -33
- package/dist/dashboard/{workspaces-Cpz0xJWQ.js.map → workspaces-DmoyfHoU.js.map} +1 -1
- package/dist/{lifecycle-C6k0HWEO.js → lifecycle-DCFcjg7y.js} +1 -1
- package/dist/{lifecycle-D5oRpvvB.js → lifecycle-GkaHQJNK.js} +2 -2
- package/dist/{lifecycle-D5oRpvvB.js.map → lifecycle-GkaHQJNK.js.map} +1 -1
- package/dist/{merge-agent-Drufc7tU.js → merge-agent-CogNFasY.js} +2 -2
- package/dist/{merge-agent-Drufc7tU.js.map → merge-agent-CogNFasY.js.map} +1 -1
- package/dist/{merge-agent-CBOVY_eC.js → merge-agent-eteKQ9Rb.js} +1 -1
- package/package.json +1 -1
- package/dist/build-info-BgrwLUy6.js +0 -2
- package/dist/dashboard/agent-state-Ci6PhjOE.js.map +0 -1
- package/dist/dashboard/build-info-CYlxvZSQ.js +0 -2
- package/dist/dashboard/cli-ZAS502uC.js +0 -2
- package/dist/dashboard/conversation-service-Dlks_hSS.js +0 -3
- package/dist/dashboard/inspect-agent-DTuSg95i.js +0 -2
- package/dist/dashboard/merge-ops-Bgc-EScO.js +0 -2
- package/dist/dashboard/workflows-CgGNyl1z.js +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-migrate-J3tFJnbd.js","names":[],"sources":["../../src/lib/state-migration-manifest.ts","../../src/cli/commands/admin/agent-state-backfill.ts","../../src/cli/commands/admin/xbrief-state-migrate.ts","../../src/cli/commands/admin/state-migrate.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { createReadStream } from 'node:fs';\nimport { lstat } from 'node:fs/promises';\n\nexport interface StateMigrationManifestEntry {\n source: string;\n destination: string;\n mode: number;\n size: number;\n sha256: string;\n}\n\nasync function sha256(path: string, signal?: AbortSignal): Promise<string> {\n const hash = createHash('sha256');\n for await (const chunk of createReadStream(path, { signal })) {\n signal?.throwIfAborted();\n hash.update(chunk);\n }\n return hash.digest('hex');\n}\n\nexport async function manifestEntry(\n source: string,\n destination: string,\n signal?: AbortSignal,\n): Promise<StateMigrationManifestEntry> {\n signal?.throwIfAborted();\n const [stat, digest] = await Promise.all([\n lstat(source),\n sha256(source, signal),\n ]);\n signal?.throwIfAborted();\n return {\n source,\n destination,\n mode: stat.mode & 0o777,\n size: stat.size,\n sha256: digest,\n };\n}\n\nexport async function verifyStateMigrationManifest(\n entries: readonly StateMigrationManifestEntry[],\n): Promise<void> {\n for (const expected of entries) {\n const actual = await manifestEntry(expected.destination, expected.destination);\n // Compare modes the way git preserves them: only the executable bit is\n // tracked, so a checkout legitimately re-derives group/other bits from the\n // process umask (e.g. 0644 source vs 0664 worktree checkout). Content is\n // guaranteed by size + sha256.\n const executableMismatch = (actual.mode & 0o100) !== (expected.mode & 0o100);\n if (executableMismatch || actual.size !== expected.size || actual.sha256 !== expected.sha256) {\n throw new Error(`State migration no-loss mismatch: ${expected.source} -> ${expected.destination}`);\n }\n }\n}\n","import { existsSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport type { AgentState, Role } from '../../../lib/agents/agent-state.js';\nimport { getAgentStateSync, isRole } from '../../../lib/agents/agent-state.js';\nimport { getSessionId } from '../../../lib/agents/activity.js';\nimport { getAgentRuntimeStateSync } from '../../../lib/agents/runtime-state.js';\nimport { hasRetainedTranscriptsMarker } from '../../../lib/agents/state-dir-removal.js';\nimport { listAllAgentsSync } from '../../../lib/overdeck/agents.js';\nimport {\n listAgentRuntimeEventEvidenceSync,\n type AgentRuntimeEventEvidence,\n} from '../../../lib/overdeck/event-reads.js';\nimport {\n backfillAgentPlaneRecord,\n flushAgentPlaneWrites,\n readAgentPlaneRecordSync,\n type AgentPlaneSeed,\n type AgentPlaneSessionEntry,\n} from '../../../lib/pan-dir/agents.js';\nimport { claudeSessionTranscriptExists, getOverdeckHome } from '../../../lib/paths.js';\nimport { resolveProjectFromIssueSync } from '../../../lib/projects.js';\nimport type { RuntimeName } from '../../../lib/runtimes/types.js';\nimport { readSessionIdHistorySync } from '../../../lib/session-history.js';\n\nconst RUNTIME_NAMES = new Set<RuntimeName>([\n 'claude-code',\n 'ohmypi',\n 'codex',\n 'acp',\n 'kimi-code',\n]);\n\ntype DbAgent = ReturnType<typeof listAllAgentsSync>[number];\n\nexport type AgentPlaneBackfillStatus =\n | 'reconstructed'\n | 'recovered-partial'\n | 'skipped-live'\n | 'skipped';\n\nexport interface AgentPlaneBackfillResult {\n agentId: string;\n issueId?: string;\n status: AgentPlaneBackfillStatus;\n sessions: string[];\n reason?: string;\n}\n\nexport interface AgentPlaneBackfillDeps {\n listLocalAgentIds: () => string[];\n hasLocalState: (agentId: string) => boolean;\n hasRetainedMarker: (agentId: string) => Promise<boolean>;\n readAgentState: (agentId: string) => AgentState | null;\n listDbAgents: () => DbAgent[];\n listEventEvidence: () => AgentRuntimeEventEvidence[];\n readCurrentSessionId: (agentId: string) => string | null;\n readSessionHistory: (agentId: string) => string[];\n readRuntimeSessionId: (agentId: string) => string | null;\n transcriptExists: (workspace: string, sessionId: string) => boolean;\n resolveProject: typeof resolveProjectFromIssueSync;\n readPlaneRecord: typeof readAgentPlaneRecordSync;\n writePlaneRecord: typeof backfillAgentPlaneRecord;\n flushPlaneWrites: typeof flushAgentPlaneWrites;\n log: (message: string) => void;\n}\n\nfunction localAgentIds(): string[] {\n const agentsDir = join(getOverdeckHome(), 'agents');\n if (!existsSync(agentsDir)) return [];\n return readdirSync(agentsDir, { withFileTypes: true })\n .filter((entry) => entry.isDirectory())\n .map((entry) => entry.name);\n}\n\nfunction defaultDeps(): AgentPlaneBackfillDeps {\n const agentsDir = join(getOverdeckHome(), 'agents');\n return {\n listLocalAgentIds: localAgentIds,\n hasLocalState: (agentId) => existsSync(join(agentsDir, agentId, 'state.json')),\n hasRetainedMarker: (agentId) => hasRetainedTranscriptsMarker(join(agentsDir, agentId)),\n readAgentState: getAgentStateSync,\n listDbAgents: listAllAgentsSync,\n listEventEvidence: listAgentRuntimeEventEvidenceSync,\n readCurrentSessionId: getSessionId,\n readSessionHistory: readSessionIdHistorySync,\n readRuntimeSessionId: (agentId) => getAgentRuntimeStateSync(agentId)?.claudeSessionId ?? null,\n transcriptExists: claudeSessionTranscriptExists,\n resolveProject: resolveProjectFromIssueSync,\n readPlaneRecord: readAgentPlaneRecordSync,\n writePlaneRecord: backfillAgentPlaneRecord,\n flushPlaneWrites: flushAgentPlaneWrites,\n log: (message) => console.log(message),\n };\n}\n\nfunction runtimeName(value: unknown): RuntimeName | undefined {\n if (value === 'pi') return 'ohmypi';\n return typeof value === 'string' && RUNTIME_NAMES.has(value as RuntimeName)\n ? value as RuntimeName\n : undefined;\n}\n\nfunction usableString(...values: unknown[]): string | undefined {\n return values.find((value): value is string =>\n typeof value === 'string' && Boolean(value.trim()))?.trim();\n}\n\nfunction seedForAgent(\n agentId: string,\n state: AgentState | null,\n db: DbAgent | undefined,\n event: AgentRuntimeEventEvidence | undefined,\n): AgentPlaneSeed | null {\n const issueId = usableString(state?.issueId, db?.issueId, event?.issueId);\n const workspace = usableString(state?.workspace, db?.workspace, event?.workspace);\n const roleValue = state?.role ?? db?.role ?? event?.role;\n if (!issueId || !workspace || !isRole(roleValue)) return null;\n return {\n id: agentId,\n issueId,\n role: roleValue as Role,\n workspace,\n harness: runtimeName(state?.harness ?? db?.harness),\n model: usableString(state?.model, db?.model, event?.model),\n branch: usableString(state?.branch, db?.branch, event?.branch),\n startedAt: usableString(state?.startedAt, db?.startedAt, event?.startedAt),\n };\n}\n\nfunction appendSession(\n sessions: AgentPlaneSessionEntry[],\n seen: Set<string>,\n id: string | null | undefined,\n startedAt: string,\n reason: AgentPlaneSessionEntry['reason'],\n): void {\n const normalized = id?.trim();\n if (!normalized || seen.has(normalized)) return;\n seen.add(normalized);\n sessions.push({ id: normalized, startedAt, reason });\n}\n\nfunction sessionsForAgent(\n seed: AgentPlaneSeed,\n state: AgentState | null,\n db: DbAgent | undefined,\n event: AgentRuntimeEventEvidence | undefined,\n recovered: boolean,\n deps: AgentPlaneBackfillDeps,\n): AgentPlaneSessionEntry[] {\n const sessions: AgentPlaneSessionEntry[] = [];\n const seen = new Set<string>();\n const startedAt = seed.startedAt ?? new Date().toISOString();\n const localReason = recovered ? 'recovered' : 'spawn';\n const localCandidates = [\n deps.readCurrentSessionId(seed.id),\n ...deps.readSessionHistory(seed.id),\n deps.readRuntimeSessionId(seed.id),\n state?.sessionId,\n db?.sessionId,\n ];\n for (const sessionId of localCandidates) {\n const valid = seed.harness && seed.harness !== 'claude-code'\n ? true\n : Boolean(sessionId && deps.transcriptExists(seed.workspace, sessionId));\n if (valid) appendSession(sessions, seen, sessionId, startedAt, localReason);\n }\n for (const session of event?.sessions ?? []) {\n if (deps.transcriptExists(seed.workspace, session.id)) {\n appendSession(sessions, seen, session.id, session.startedAt, 'recovered');\n }\n }\n return sessions;\n}\n\nfunction isLiveStatus(state: AgentState | null, db: DbAgent | undefined): boolean {\n const status = state?.status ?? db?.status;\n return status === 'running' || status === 'starting';\n}\n\nexport async function backfillAgentRuntimePlane(\n options: { projectKey?: string; dryRun?: boolean } = {},\n deps: AgentPlaneBackfillDeps = defaultDeps(),\n): Promise<AgentPlaneBackfillResult[]> {\n const localIds = new Set(deps.listLocalAgentIds());\n const dbById = new Map(deps.listDbAgents().map((agent) => [agent.id, agent]));\n const eventById = new Map(deps.listEventEvidence().map((event) => [event.agentId, event]));\n const agentIds = new Set([...localIds, ...dbById.keys(), ...eventById.keys()]);\n const results: AgentPlaneBackfillResult[] = [];\n const flushTargets = new Map<string, { issueId: string; agentId: string }>();\n\n for (const agentId of [...agentIds].sort()) {\n const state = deps.readAgentState(agentId);\n const db = dbById.get(agentId);\n const event = eventById.get(agentId);\n const seed = seedForAgent(agentId, state, db, event);\n if (!seed) {\n results.push({\n agentId,\n status: 'skipped',\n sessions: [],\n reason: 'identity, role, or workspace metadata is incomplete',\n });\n continue;\n }\n const project = deps.resolveProject(seed.issueId);\n if (!project) {\n results.push({\n agentId,\n issueId: seed.issueId,\n status: 'skipped',\n sessions: [],\n reason: `no configured project resolves ${seed.issueId}`,\n });\n continue;\n }\n if (options.projectKey && project.projectKey !== options.projectKey) continue;\n\n const hasLocalState = deps.hasLocalState(agentId);\n const retained = await deps.hasRetainedMarker(agentId);\n const recovered = !hasLocalState || (retained && !deps.readCurrentSessionId(agentId));\n const existing = deps.readPlaneRecord(seed.issueId, agentId);\n if (isLiveStatus(state, db) && existing) {\n if (!options.dryRun) {\n flushTargets.set(project.projectKey, { issueId: seed.issueId, agentId });\n }\n results.push({\n agentId,\n issueId: seed.issueId,\n status: 'skipped-live',\n sessions: existing.sessions.map((session) => session.id),\n });\n continue;\n }\n\n const sessions = sessionsForAgent(seed, state, db, event, recovered, deps);\n if (options.dryRun) {\n results.push({\n agentId,\n issueId: seed.issueId,\n status: recovered ? 'recovered-partial' : 'reconstructed',\n sessions: sessions.map((session) => session.id),\n reason: 'dry run; durable record was not written',\n });\n continue;\n }\n try {\n const written = await deps.writePlaneRecord(\n seed,\n sessions,\n recovered,\n { deferCommit: true },\n );\n if (written || existing) {\n flushTargets.set(project.projectKey, { issueId: seed.issueId, agentId });\n }\n results.push({\n agentId,\n issueId: seed.issueId,\n status: !written && !existing\n ? 'skipped'\n : recovered ? 'recovered-partial' : 'reconstructed',\n sessions: (!written && existing ? existing.sessions : sessions)\n .map((session) => session.id),\n ...(!written ? {\n reason: existing\n ? 'existing durable record already contained equal or stronger history'\n : 'durable agent plane is unavailable for this project',\n } : {}),\n });\n } catch (error) {\n results.push({\n agentId,\n issueId: seed.issueId,\n status: 'skipped',\n sessions: [],\n reason: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n for (const [projectKey, target] of flushTargets) {\n const flush = await deps.flushPlaneWrites(target.issueId, target.agentId);\n if (!flush || flush.errored || flush.pushed !== true) {\n throw new Error(\n `Agent-plane backfill push failed for ${projectKey}: ${flush?.reason ?? 'no confirmed state-branch push'}`,\n );\n }\n }\n\n for (const result of results) {\n deps.log(\n `${result.agentId}: ${result.status}`\n + `${result.sessions.length > 0 ? ` (sessions: ${result.sessions.join(', ')})` : ''}`\n + `${result.reason ? ` — ${result.reason}` : ''}`,\n );\n }\n return results;\n}\n","import { execFile } from 'node:child_process';\nimport {\n existsSync,\n readFileSync,\n readdirSync,\n renameSync,\n writeFileSync,\n} from 'node:fs';\nimport { join, relative } from 'node:path';\nimport { promisify } from 'node:util';\nimport { Effect } from 'effect';\n\nimport { flushAutoCommits, queueAutoCommit } from '../../../lib/pan-dir/auto-commit.js';\nimport { getProjectSync, type ProjectConfig } from '../../../lib/projects.js';\nimport { MIGRATION_COMPLETE_MARKER, STATE_BRANCH, stateWorktreePath } from '../../../lib/state-home.js';\nimport {\n LEGACY_VBRIEF_FILENAME_SUFFIX,\n XBRIEF_FILENAME_SUFFIX,\n} from '../../../lib/xbrief/lifecycle.js';\n\nconst execFileAsync = promisify(execFile);\n\ninterface RewriteOperation {\n path: string;\n content: string;\n}\n\ninterface RenameOperation {\n from: string;\n to: string;\n}\n\nexport interface XBriefStateMigrationPlan {\n rewrites: RewriteOperation[];\n renames: RenameOperation[];\n files: string[];\n}\n\nexport interface XBriefStateMigrationResult {\n dryRun: boolean;\n filesMigrated: number;\n committed: boolean;\n}\n\nfunction canonicalPath(path: string): string {\n return `${path.slice(0, -LEGACY_VBRIEF_FILENAME_SUFFIX.length)}${XBRIEF_FILENAME_SUFFIX}`;\n}\n\nfunction migratedSpecContent(path: string): string | null {\n let parsed: Record<string, unknown>;\n try {\n const value = JSON.parse(readFileSync(path, 'utf8')) as unknown;\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('expected a JSON object');\n }\n parsed = value as Record<string, unknown>;\n } catch (error) {\n throw new Error(`Cannot migrate invalid xBRIEF JSON at ${path}: ${String(error)}`);\n }\n\n if (!Object.hasOwn(parsed, 'vBRIEFInfo')) return null;\n if (Object.hasOwn(parsed, 'xBRIEFInfo')) {\n if (JSON.stringify(parsed.xBRIEFInfo) !== JSON.stringify(parsed.vBRIEFInfo)) {\n throw new Error(`Cannot migrate conflicting vBRIEFInfo and xBRIEFInfo envelopes at ${path}`);\n }\n delete parsed.vBRIEFInfo;\n return `${JSON.stringify(parsed, null, 2)}\\n`;\n }\n\n const { vBRIEFInfo, ...document } = parsed;\n return `${JSON.stringify({ xBRIEFInfo: vBRIEFInfo, ...document }, null, 2)}\\n`;\n}\n\nfunction planDirectoryRenames(directory: string, renames: RenameOperation[], files: Set<string>): void {\n if (!existsSync(directory)) return;\n for (const entry of readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {\n if (!entry.isFile() || !entry.name.endsWith(LEGACY_VBRIEF_FILENAME_SUFFIX)) continue;\n const from = join(directory, entry.name);\n const to = canonicalPath(from);\n if (existsSync(to)) {\n throw new Error(`Cannot migrate ${from}: destination already exists at ${to}`);\n }\n renames.push({ from, to });\n files.add(from);\n }\n}\n\nexport function planXBriefStateMigration(stateRoot: string): XBriefStateMigrationPlan {\n const specsDir = join(stateRoot, 'specs');\n const continuesDir = join(stateRoot, 'continues');\n const rewrites: RewriteOperation[] = [];\n const renames: RenameOperation[] = [];\n const files = new Set<string>();\n\n if (existsSync(specsDir)) {\n for (const entry of readdirSync(specsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {\n if (!entry.isFile() || !entry.name.endsWith('.json')) continue;\n const path = join(specsDir, entry.name);\n const content = migratedSpecContent(path);\n if (content !== null) {\n rewrites.push({ path, content });\n files.add(path);\n }\n }\n }\n\n planDirectoryRenames(specsDir, renames, files);\n planDirectoryRenames(continuesDir, renames, files);\n\n return {\n rewrites,\n renames,\n files: [...files].sort(),\n };\n}\n\nasync function assertCleanStateWorktree(stateRoot: string): Promise<void> {\n if (!existsSync(join(stateRoot, '.git'))) {\n throw new Error(`State worktree is missing at ${stateRoot}`);\n }\n if (!existsSync(join(stateRoot, MIGRATION_COMPLETE_MARKER))) {\n throw new Error(`State worktree is not migration-complete: ${stateRoot}`);\n }\n\n const { stdout: branch } = await execFileAsync('git', ['branch', '--show-current'], {\n cwd: stateRoot,\n encoding: 'utf8',\n timeout: 15_000,\n });\n if (branch.trim() !== STATE_BRANCH) {\n throw new Error(`Expected ${STATE_BRANCH} at ${stateRoot}, found ${branch.trim() || 'detached HEAD'}`);\n }\n\n const { stdout: status } = await execFileAsync('git', ['status', '--porcelain'], {\n cwd: stateRoot,\n encoding: 'utf8',\n timeout: 15_000,\n });\n if (status.trim()) {\n throw new Error(`State worktree is dirty; commit or resolve existing changes before xBRIEF migration:\\n${status.trim()}`);\n }\n}\n\nfunction printPlan(projectKey: string, stateRoot: string, plan: XBriefStateMigrationPlan): void {\n console.log(`xBRIEF state migration plan for ${projectKey}:`);\n for (const rewrite of plan.rewrites) {\n console.log(` rewrite ${relative(stateRoot, rewrite.path)}: vBRIEFInfo -> xBRIEFInfo`);\n }\n for (const rename of plan.renames) {\n console.log(` rename ${relative(stateRoot, rename.from)} -> ${relative(stateRoot, rename.to)}`);\n }\n console.log(` ${plan.files.length} file(s) to migrate`);\n}\n\nexport async function migrateProjectXBriefState(\n projectKey: string,\n options: { dryRun?: boolean } = {},\n projectOverride?: ProjectConfig,\n): Promise<XBriefStateMigrationResult> {\n const project = projectOverride ?? getProjectSync(projectKey);\n if (!project) throw new Error(`Unknown project: ${projectKey}`);\n const stateRoot = stateWorktreePath(project, { projectKey });\n\n await assertCleanStateWorktree(stateRoot);\n const plan = planXBriefStateMigration(stateRoot);\n printPlan(projectKey, stateRoot, plan);\n\n if (options.dryRun || plan.files.length === 0) {\n return {\n dryRun: options.dryRun === true,\n filesMigrated: plan.files.length,\n committed: false,\n };\n }\n\n for (const rewrite of plan.rewrites) writeFileSync(rewrite.path, rewrite.content);\n for (const rename of plan.renames) renameSync(rename.from, rename.to);\n\n const paths = new Set<string>();\n for (const rewrite of plan.rewrites) paths.add(rewrite.path);\n for (const rename of plan.renames) {\n paths.add(rename.from);\n paths.add(rename.to);\n }\n queueAutoCommit({\n projectRoot: project.path,\n repoRoot: stateRoot,\n paths: [...paths],\n subject: 'chore(state): migrate xBRIEF documents (PAN-2829)',\n });\n const flush = await Effect.runPromise(flushAutoCommits(project.path));\n if (flush.errored || !flush.committed || flush.pushed === false) {\n throw new Error(`xBRIEF state migration commit failed: ${flush.reason ?? 'state writer did not commit and push'}`);\n }\n\n console.log(`Migrated ${plan.files.length} xBRIEF state file(s) in one commit.`);\n return {\n dryRun: false,\n filesMigrated: plan.files.length,\n committed: true,\n };\n}\n","import { execFile, type ChildProcess, type ExecFileException } from 'node:child_process';\nimport { createReadStream, createWriteStream, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';\nimport { chmod, lstat, mkdir, readdir, rename, rm, utimes } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { pipeline } from 'node:stream/promises';\nimport { Command } from 'commander';\nimport { Effect } from 'effect';\n\nimport { flushAutoCommits } from '../../../lib/pan-dir/auto-commit.js';\nimport { getProjectSync, resolveInfraRepo, type ProjectConfig } from '../../../lib/projects.js';\nimport { STATE_BRANCH, MIGRATION_COMPLETE_MARKER, clearStateMigrationCache, stateWorktreePath } from '../../../lib/state-home.js';\nimport { STATE_BRANCH_PATHS } from '../../../lib/state-plane.js';\nimport { acquireStateMigrationLock } from '../../../lib/state-migration-lock.js';\nimport { manifestEntry, verifyStateMigrationManifest, type StateMigrationManifestEntry } from '../../../lib/state-migration-manifest.js';\nimport { backfillAgentRuntimePlane } from './agent-state-backfill.js';\nimport { migrateProjectXBriefState } from './xbrief-state-migrate.js';\n\nconst GIT_COMMAND_TIMEOUT_MS = 30_000;\n\nconst execFileDetached = execFile as unknown as (\n file: string,\n args: string[],\n options: {\n cwd: string;\n env: NodeJS.ProcessEnv;\n encoding: BufferEncoding;\n maxBuffer: number;\n detached: boolean;\n },\n callback: (error: ExecFileException | null, stdout: string, stderr: string) => void,\n) => ChildProcess;\n\nfunction killProcessTree(child: ChildProcess | undefined): void {\n if (!child?.pid) return;\n try {\n if (process.platform === 'win32') child.kill('SIGKILL');\n else process.kill(-child.pid, 'SIGKILL');\n } catch {\n try { child.kill('SIGKILL'); } catch { /* process already exited */ }\n }\n}\n\nasync function git(\n cwd: string,\n args: string[],\n signal?: AbortSignal,\n env?: NodeJS.ProcessEnv,\n): Promise<string> {\n signal?.throwIfAborted();\n const command = `git ${args.join(' ')}`;\n return new Promise((resolve, reject) => {\n let child: ChildProcess | undefined;\n let termination: 'abort' | 'timeout' | undefined;\n const terminate = (kind: 'abort' | 'timeout') => {\n if (termination) return;\n termination = kind;\n killProcessTree(child);\n };\n const timeout = setTimeout(() => terminate('timeout'), GIT_COMMAND_TIMEOUT_MS);\n const onAbort = () => terminate('abort');\n signal?.addEventListener('abort', onAbort, { once: true });\n\n child = execFileDetached('git', args, {\n cwd,\n env: { ...process.env, ...env },\n encoding: 'utf8',\n maxBuffer: 32 * 1024 * 1024,\n detached: process.platform !== 'win32',\n }, (error, stdout, stderr) => {\n clearTimeout(timeout);\n signal?.removeEventListener('abort', onAbort);\n if (termination === 'abort') {\n reject(signal?.reason ?? new DOMException(`${command} was cancelled`, 'AbortError'));\n } else if (termination === 'timeout') {\n reject(new Error(`${command} timed out after ${GIT_COMMAND_TIMEOUT_MS / 1_000}s`));\n } else if (error) {\n reject(Object.assign(error, { stdout, stderr }));\n } else {\n resolve(stdout.trim());\n }\n });\n\n if (signal?.aborted) terminate('abort');\n });\n}\n\nfunction destinationForTracked(path: string): string | null {\n if (!path.startsWith('.pan/')) return null;\n const flat = path.slice('.pan/'.length);\n return STATE_BRANCH_PATHS.some((prefix) => flat.startsWith(prefix)) ? flat : null;\n}\n\nasync function trackedManifest(\n repo: string,\n sourceSha: string,\n stateRoot: string,\n signal?: AbortSignal,\n copyFile: CopyFileOperation = copyFileAbortable,\n): Promise<StateMigrationManifestEntry[]> {\n const paths = (await git(repo, ['ls-tree', '-r', '--name-only', sourceSha, '--', '.pan'], signal))\n .split('\\n').filter(Boolean);\n const manifest: StateMigrationManifestEntry[] = [];\n for (const path of paths) {\n signal?.throwIfAborted();\n const destination = destinationForTracked(path);\n if (!destination) continue;\n const source = join(repo, path);\n const target = join(stateRoot, destination);\n if (!existsSync(target)) await copyFile(source, target, signal);\n manifest.push(await manifestEntry(source, target, signal));\n }\n return manifest;\n}\n\nasync function createOrphanStateCommit(\n repo: string,\n sourceSha: string,\n signal?: AbortSignal,\n): Promise<string> {\n const index = join(tmpdir(), `overdeck-state-index-${process.pid}-${Date.now()}`);\n const env = { GIT_INDEX_FILE: index };\n try {\n await git(repo, ['read-tree', '--empty'], signal, env);\n const rows = (await git(repo, ['ls-tree', '-r', sourceSha, '--', '.pan'], signal)).split('\\n').filter(Boolean);\n for (const row of rows) {\n const match = row.match(/^(\\d+)\\s+\\w+\\s+([0-9a-f]+)\\t(.+)$/);\n if (!match) continue;\n const destination = destinationForTracked(match[3]);\n if (destination) {\n await git(repo, ['update-index', '--add', '--cacheinfo', `${match[1]},${match[2]},${destination}`], signal, env);\n }\n }\n const tree = await git(repo, ['write-tree'], signal, env);\n return await git(repo, ['commit-tree', tree, '-m', 'chore(state): seed overdeck-state'], signal, env);\n } finally {\n rmSync(index, { force: true });\n }\n}\n\ntype CopyFileOperation = (\n source: string,\n destination: string,\n signal?: AbortSignal,\n) => Promise<void>;\n\nlet copySequence = 0;\n\nasync function copyFileAbortable(\n source: string,\n destination: string,\n signal?: AbortSignal,\n): Promise<void> {\n signal?.throwIfAborted();\n const stat = await lstat(source);\n const temporary = join(\n dirname(destination),\n `.overdeck-migrate-${process.pid}-${copySequence++}`,\n );\n await mkdir(dirname(destination), { recursive: true });\n try {\n await pipeline(\n createReadStream(source, { signal }),\n createWriteStream(temporary, { mode: stat.mode & 0o777 }),\n { signal },\n );\n signal?.throwIfAborted();\n await chmod(temporary, stat.mode & 0o777);\n await utimes(temporary, stat.atime, stat.mtime);\n signal?.throwIfAborted();\n await rename(temporary, destination);\n } catch (error) {\n if (signal?.aborted) throw signal.reason;\n throw error;\n } finally {\n await rm(temporary, { force: true });\n }\n}\n\nasync function filesEqualAbortable(\n source: string,\n destination: string,\n signal?: AbortSignal,\n): Promise<boolean> {\n const [sourceEntry, destinationEntry] = await Promise.all([\n manifestEntry(source, source, signal),\n manifestEntry(destination, destination, signal),\n ]);\n return sourceEntry.size === destinationEntry.size\n && sourceEntry.sha256 === destinationEntry.sha256;\n}\n\nasync function preserveUntrackedNotes(\n legacyStateSource: string,\n stateRoot: string,\n paths: readonly string[],\n signal?: AbortSignal,\n copyFile: CopyFileOperation = copyFileAbortable,\n): Promise<StateMigrationManifestEntry[]> {\n const manifest: StateMigrationManifestEntry[] = [];\n for (const path of paths) {\n signal?.throwIfAborted();\n const source = join(legacyStateSource, path);\n let sourceStat;\n try {\n sourceStat = await lstat(source);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') continue;\n throw error;\n }\n if (sourceStat.isSymbolicLink()) {\n throw new Error(`Legacy state changed during migration: symbolic link appeared at ${source}`);\n }\n if (!sourceStat.isFile()) continue;\n\n const destination = join(stateRoot, 'notes', path.slice('.pan/'.length));\n if (existsSync(destination)) {\n // A byte-identical destination is this migration's own interrupted prior\n // copy. Stream both files so collision checks remain cancellable.\n if (!await filesEqualAbortable(source, destination, signal)) {\n throw new Error(`Untracked-note destination collision: ${destination}`);\n }\n } else {\n await copyFile(source, destination, signal);\n }\n manifest.push(await manifestEntry(source, destination, signal));\n }\n return manifest;\n}\n\nasync function assertNoLegacySymlinks(\n source: string,\n signal?: AbortSignal,\n allowMissing = false,\n): Promise<void> {\n signal?.throwIfAborted();\n let stat;\n try {\n stat = await lstat(source);\n } catch (error) {\n if (allowMissing && (error as NodeJS.ErrnoException).code === 'ENOENT') return;\n throw error;\n }\n if (stat.isSymbolicLink()) {\n throw new Error(\n `Legacy state contains unsupported symbolic link: ${source}. `\n + 'Resolve it before migrating so canonical state cannot depend on the legacy tree.',\n );\n }\n if (!stat.isDirectory()) return;\n for (const entry of await readdir(source, { withFileTypes: true })) {\n await assertNoLegacySymlinks(join(source, entry.name), signal);\n }\n}\n\nasync function copyLegacyState(\n sourceRoot: string,\n stateRoot: string,\n signal?: AbortSignal,\n copyFile: CopyFileOperation = copyFileAbortable,\n): Promise<StateMigrationManifestEntry[]> {\n const manifest: StateMigrationManifestEntry[] = [];\n const sources = STATE_BRANCH_PATHS\n .map((sourcePath) => ({\n source: join(sourceRoot, '.pan', sourcePath),\n destination: join(stateRoot, sourcePath),\n }))\n .filter(({ source }) => existsSync(source));\n\n // Symlinks cannot be made durable by the regular-file manifest: absolute\n // targets can still point into the legacy tree after cleanup, and relative\n // targets can resolve differently under the state worktree. Check the whole\n // legacy tree so ignored top-level entries cannot be deleted without notice.\n await assertNoLegacySymlinks(join(sourceRoot, '.pan'), signal, true);\n\n const visit = async (sourceDir: string, destinationDir: string): Promise<void> => {\n await mkdir(destinationDir, { recursive: true });\n for (const entry of await readdir(sourceDir, { withFileTypes: true })) {\n signal?.throwIfAborted();\n const sourceEntry = join(sourceDir, entry.name);\n const destinationEntry = join(destinationDir, entry.name);\n if (entry.isDirectory()) {\n await visit(sourceEntry, destinationEntry);\n } else if (entry.isFile()) {\n await copyFile(sourceEntry, destinationEntry, signal);\n signal?.throwIfAborted();\n manifest.push(await manifestEntry(sourceEntry, destinationEntry, signal));\n } else if (entry.isSymbolicLink()) {\n throw new Error(`Legacy state changed during migration: symbolic link appeared at ${sourceEntry}`);\n }\n }\n };\n\n for (const { source, destination } of sources) {\n signal?.throwIfAborted();\n await visit(source, destination);\n }\n return manifest;\n}\n\nfunction workspacePaths(repo: string): string[] {\n const root = join(repo, 'workspaces');\n if (!existsSync(root)) return [];\n return readdirSync(root, { withFileTypes: true })\n .filter((entry) => entry.isDirectory())\n .map((entry) => join(root, entry.name))\n // Only real git worktrees are workspaces. workspaces/ can contain stray\n // non-worktree directories (e.g. a root-owned node_modules left by a\n // container) that must not be touched — writing into them EACCES-aborts\n // the migration mid-flight.\n .filter((path) => existsSync(join(path, '.git')));\n}\n\nfunction hasNonStateDirtyState(porcelain: string): boolean {\n return porcelain.split('\\n').filter(Boolean).some((line) => {\n const path = line.slice(3).split(' -> ').at(-1) ?? '';\n if (path === '.pan' || path.startsWith('.pan/')) {\n return false;\n }\n return true;\n });\n}\n\nfunction dedupeManifest(entries: StateMigrationManifestEntry[]): StateMigrationManifestEntry[] {\n return [...new Map(entries.map((entry) => [entry.destination, entry])).values()];\n}\n\nconst GITIGNORE_MANAGED_LINES = [\n '# PAN-2541: permanent state is on overdeck-state; workspace runtime stays local.',\n '.pan/',\n '.overdeck/continue.json',\n '.overdeck/spec.vbrief.json',\n '.overdeck/sessions.jsonl',\n '.overdeck/feedback/',\n '.overdeck/review/',\n '.overdeck/test/',\n '.overdeck/kickoff.md',\n '.overdeck/agent-mcp.json',\n];\n\nfunction rewriteGitignore(repo: string): void {\n const path = join(repo, '.gitignore');\n const prior = existsSync(path) ? readFileSync(path, 'utf8') : '';\n // Idempotent: strip every line this function manages (plus the legacy bare\n // '.overdeck/' entry) before appending the block exactly once — an\n // interrupted migration must not accrete duplicate blocks on resume.\n const managed = new Set([...GITIGNORE_MANAGED_LINES, '.overdeck/']);\n const kept = prior.split('\\n').filter((line) => !managed.has(line.trim()));\n while (kept.length > 0 && kept[kept.length - 1]?.trim() === '') kept.pop();\n writeFileSync(path, [...kept, '', ...GITIGNORE_MANAGED_LINES, ''].join('\\n'));\n}\n\nexport async function migrateProjectState(\n projectKey: string,\n options: { dryRun?: boolean; signal?: AbortSignal } = {},\n projectOverride?: ProjectConfig,\n): Promise<void> {\n const project = projectOverride ?? getProjectSync(projectKey);\n if (!project) throw new Error(`Unknown project: ${projectKey}`);\n const { repoPath: repo } = resolveInfraRepo(project);\n const legacyStateSource = project.path;\n const sourceIsHostRepo = legacyStateSource === repo;\n const stateRoot = stateWorktreePath(project, { projectKey });\n console.log(`PAN-2541 state migration plan for ${projectKey}:`);\n console.log(` ${legacyStateSource}/.pan/{${STATE_BRANCH_PATHS.map((p) => p.slice(0, -1)).join(',')}} -> ${stateRoot}/`);\n console.log(` ${legacyStateSource}/.pan/context -> ${legacyStateSource}/.overdeck/context`);\n if (options.dryRun) return;\n\n options.signal?.throwIfAborted();\n const release = acquireStateMigrationLock(projectKey);\n try {\n // The reconciliation deadline owns the writer too: cancellation interrupts\n // every active or queued flush for this Git root and waits for settlement, so\n // migration can never proceed beside a detached commit or push.\n const flush = await Effect.runPromise(flushAutoCommits(repo, options.signal));\n if (flush.errored) {\n throw new Error(`State writer did not quiesce before migration: ${flush.reason ?? 'unknown error'}`);\n }\n options.signal?.throwIfAborted();\n // This read-only preflight runs before fetches, branch creation, worktree\n // creation, or destination writes. copyLegacyState repeats it immediately\n // before copying to defend against changes outside the migration lock.\n await assertNoLegacySymlinks(join(legacyStateSource, '.pan'), options.signal, true);\n if (hasNonStateDirtyState(await git(repo, ['status', '--porcelain'], options.signal))) {\n throw new Error('Primary checkout is dirty outside legacy state paths; migration refused before mutation');\n }\n await git(repo, ['fetch', '--prune', 'origin'], options.signal);\n const sourceMainSha = await git(repo, ['rev-parse', 'main'], options.signal);\n const remoteMainSha = await git(repo, ['rev-parse', 'origin/main'], options.signal);\n if (sourceMainSha !== remoteMainSha) throw new Error('main is not exactly at origin/main; migration refused');\n\n const existingMarker = await git(repo, ['show', `origin/${STATE_BRANCH}:${MIGRATION_COMPLETE_MARKER}`], options.signal)\n .catch(() => {\n options.signal?.throwIfAborted();\n return '';\n });\n if (existingMarker) {\n console.log('State migration already complete on origin; nothing to do.');\n return;\n }\n\n let stateSha = await git(repo, ['rev-parse', STATE_BRANCH], options.signal).catch(() => {\n options.signal?.throwIfAborted();\n return '';\n });\n const remoteStateSha = await git(repo, ['rev-parse', `origin/${STATE_BRANCH}`], options.signal).catch(() => {\n options.signal?.throwIfAborted();\n return '';\n });\n if (stateSha && remoteStateSha && stateSha !== remoteStateSha) {\n throw new Error('Local and remote overdeck-state diverged; refusing non-fast-forward migration');\n }\n if (!stateSha) {\n stateSha = remoteStateSha || await createOrphanStateCommit(repo, sourceMainSha, options.signal);\n await git(repo, ['update-ref', `refs/heads/${STATE_BRANCH}`, stateSha], options.signal);\n }\n if (!remoteStateSha) await git(repo, ['push', 'origin', STATE_BRANCH], options.signal);\n\n if (!existsSync(stateRoot)) {\n options.signal?.throwIfAborted();\n mkdirSync(dirname(stateRoot), { recursive: true });\n await git(repo, ['worktree', 'add', stateRoot, STATE_BRANCH], options.signal);\n }\n\n // A pipeline may have produced state after the last code commit (the PUZ-1\n // failure mode). Seed tracked blobs for historical fidelity, then overlay\n // the current working-tree state so untracked .pan/specs enter the verified\n // manifest before legacy paths are removed. Unrelated dirty code remains a\n // hard block above. Legacy .beads data is intentionally left untouched.\n const manifest = sourceIsHostRepo\n ? dedupeManifest([\n ...await trackedManifest(repo, sourceMainSha, stateRoot, options.signal),\n ...await copyLegacyState(legacyStateSource, stateRoot, options.signal),\n ])\n : await copyLegacyState(legacyStateSource, stateRoot, options.signal);\n if (manifest.length > 0) {\n await git(stateRoot, ['add', '--all'], options.signal);\n if (await git(stateRoot, ['diff', '--cached', '--name-only'], options.signal)) {\n await git(stateRoot, ['commit', '-m', 'chore(state): seed legacy project state'], options.signal);\n }\n await git(stateRoot, ['push', 'origin', STATE_BRANCH], options.signal);\n }\n const untracked = sourceIsHostRepo\n ? (await git(repo, ['ls-files', '--others', '--', '.pan'], options.signal)).split('\\n')\n .filter((path) => path.split('/').length === 2 && existsSync(join(repo, path)) && lstatSync(join(repo, path)).isFile())\n : existsSync(join(legacyStateSource, '.pan'))\n ? readdirSync(join(legacyStateSource, '.pan'), { withFileTypes: true })\n .filter((entry) => entry.isFile())\n .map((entry) => `.pan/${entry.name}`)\n : [];\n manifest.push(...await preserveUntrackedNotes(\n legacyStateSource,\n stateRoot,\n untracked,\n options.signal,\n ));\n if (untracked.length > 0) {\n await git(stateRoot, ['add', 'notes'], options.signal);\n // Resume tolerance: a prior interrupted attempt may have already\n // committed these notes — git commit exits 1 on an empty index.\n if (await git(stateRoot, ['diff', '--cached', '--name-only'], options.signal)) {\n await git(stateRoot, ['commit', '-m', 'chore(state): preserve untracked operator notes'], options.signal);\n }\n await git(stateRoot, ['push', 'origin', STATE_BRANCH], options.signal);\n }\n\n if (await git(repo, ['rev-parse', 'main'], options.signal) !== sourceMainSha) {\n throw new Error('main advanced during migration; refusing cleanup');\n }\n options.signal?.throwIfAborted();\n\n // From source cleanup through the atomic push, migration is one durability\n // boundary. Cancellation must await this resumable sequence instead of\n // leaving deleted legacy sources without a durable completion marker.\n if (sourceIsHostRepo) {\n await git(repo, ['rm', '-r', '--cached', '--ignore-unmatch', '.pan/records', '.pan/continues', '.pan/specs', '.pan/drafts', '.pan/review', '.pan/test', '.pan/feedback', '.pan/backlog', '.pan/notes']);\n }\n const oldContext = join(legacyStateSource, '.pan', 'context');\n const newContext = join(legacyStateSource, '.overdeck', 'context');\n let movedContext = false;\n if (existsSync(oldContext) && !existsSync(newContext)) {\n mkdirSync(dirname(newContext), { recursive: true });\n renameSync(oldContext, newContext);\n movedContext = true;\n }\n rewriteGitignore(legacyStateSource);\n // Resume tolerance: a prior attempt may already have committed the\n // context deletions — `git add -u` exits 128 on a pathspec with no\n // tracked entries left.\n if (sourceIsHostRepo) {\n if (await git(repo, ['ls-files', '--', '.pan/context'])) {\n await git(repo, ['add', '-u', '--', '.pan/context']);\n }\n const addPaths = ['.gitignore'];\n if (movedContext || existsSync(newContext)) addPaths.push('.overdeck/context');\n await git(repo, ['add', '--', ...addPaths]);\n // Resume tolerance: skip when a prior attempt already committed the cleanup.\n if (await git(repo, ['diff', '--cached', '--name-only'])) {\n await git(repo, ['commit', '-m', 'chore(state): move permanent state to overdeck-state']);\n }\n }\n\n await verifyStateMigrationManifest(manifest);\n for (const entry of manifest) rmSync(entry.source, { force: true });\n if (!sourceIsHostRepo) {\n rmSync(join(legacyStateSource, '.pan'), { recursive: true, force: true });\n }\n stateSha = await git(stateRoot, ['rev-parse', 'HEAD']);\n writeFileSync(join(stateRoot, MIGRATION_COMPLETE_MARKER), `${JSON.stringify({\n sourceMainSha,\n stateBranchSha: stateSha,\n completedAt: new Date().toISOString(),\n version: 1,\n }, null, 2)}\\n`);\n await git(stateRoot, ['add', MIGRATION_COMPLETE_MARKER]);\n await git(stateRoot, ['commit', '-m', 'chore(state): complete state migration']);\n\n await git(repo, ['push', '--atomic', '--dry-run', 'origin', 'main', STATE_BRANCH]);\n await git(repo, ['push', '--atomic', 'origin', 'main', STATE_BRANCH]);\n clearStateMigrationCache();\n } finally {\n release();\n }\n}\n\nexport const __testInternals = {\n copyFileAbortable,\n copyLegacyState,\n filesEqualAbortable,\n git,\n preserveUntrackedNotes,\n trackedManifest,\n};\n\nexport function registerStateMigrationCommand(admin: Command): void {\n const state = admin.command('state')\n .description('Permanent state administration');\n\n state.command('migrate <project>')\n .description('Move permanent state to the orphan overdeck-state branch')\n .option('--dry-run', 'Print the exact migration plan without mutating anything')\n .action((project: string, options: { dryRun?: boolean }) => migrateProjectState(project, options));\n\n state.command('migrate-xbrief <project>')\n .description('Rename state documents to .xbrief.json and migrate legacy envelopes')\n .option('--dry-run', 'Print the exact xBRIEF migration plan without mutating anything')\n .action(async (project: string, options: { dryRun?: boolean }) => {\n await migrateProjectXBriefState(project, options);\n });\n\n state.command('backfill-agents [project]')\n .description('Reconstruct durable agent runtime records from local and retained state')\n .option('--dry-run', 'Report the records and sessions that would be written')\n .action(async (project: string | undefined, options: { dryRun?: boolean }) => {\n await backfillAgentRuntimePlane({ projectKey: project, dryRun: options.dryRun });\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAYA,eAAA,OAAA,MAAA,QAAA;;AAEE,YAAA,MAAA,SAAA,iBAAA,MAAA,EAAA,QAAA,CAAA,EAAA;AACE,UAAA,gBAAA;AACA,OAAA,OAAA,MAAA;;AAEF,QAAA,KAAA,OAAA,MAAA;;AAGF,eAAA,cAAA,QAAA,aAAA,QAAA;AAKE,SAAA,gBAAA;;AAKA,SAAA,gBAAA;AACA,QAAA;;;;;;;;AASF,eAAA,6BAAA,SAAA;AAGE,MAAA,MAAA,YAAA,SAAA;;AAOE,OAAA,OAAA,OAAA,SAAA,SAAA,OAAA,OAAA,OAAA,SAAA,SAAA,QAAA,OAAA,WAAA,SAAA,OAAA,OAAA,IAAA,MAAA,qCAAA,SAAA,OAAA,MAAA,SAAA,cAAA;;;;;kBC/C2E;eAChB;oBACiB;wBACQ;aACpB;kBAItB;eAON;sBAImC;;;eCVG;gBAKpC;AAEpB,UAAU,SAAS;;;kBCX8B;eACyB;iBACkC;AAOlI,MAAM,yBAAyB;AAE/B,MAAM,mBAAmB;AAazB,SAAS,gBAAgB,OAAuC;AAC9D,KAAI,CAAC,OAAO,IAAK;AACjB,KAAI;AACF,MAAI,QAAQ,aAAa,QAAS,OAAM,KAAK,UAAU;MAClD,SAAQ,KAAK,CAAC,MAAM,KAAK,UAAU;SAClC;AACN,MAAI;AAAE,SAAM,KAAK,UAAU;UAAU;;;AAIzC,eAAe,IACb,KACA,MACA,QACA,KACiB;AACjB,SAAQ,gBAAgB;CACxB,MAAM,UAAU,OAAO,KAAK,KAAK,IAAI;AACrC,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,IAAI;EACJ,IAAI;EACJ,MAAM,aAAa,SAA8B;AAC/C,OAAI,YAAa;AACjB,iBAAc;AACd,mBAAgB,MAAM;;EAExB,MAAM,UAAU,iBAAiB,UAAU,UAAU,EAAE,uBAAuB;EAC9E,MAAM,gBAAgB,UAAU,QAAQ;AACxC,UAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,MAAM,CAAC;AAE1D,UAAQ,iBAAiB,OAAO,MAAM;GACpC;GACA,KAAK;IAAE,GAAG,QAAQ;IAAK,GAAG;IAAK;GAC/B,UAAU;GACV,WAAW,KAAK,OAAO;GACvB,UAAU,QAAQ,aAAa;GAChC,GAAG,OAAO,QAAQ,WAAW;AAC5B,gBAAa,QAAQ;AACrB,WAAQ,oBAAoB,SAAS,QAAQ;AAC7C,OAAI,gBAAgB,QAClB,QAAO,QAAQ,UAAU,IAAI,aAAa,GAAG,QAAQ,iBAAiB,aAAa,CAAC;YAC3E,gBAAgB,UACzB,wBAAO,IAAI,MAAM,GAAG,QAAQ,mBAAmB,yBAAyB,IAAM,GAAG,CAAC;YACzE,MACT,QAAO,OAAO,OAAO,OAAO;IAAE;IAAQ;IAAQ,CAAC,CAAC;OAEhD,SAAQ,OAAO,MAAM,CAAC;IAExB;AAEF,MAAI,QAAQ,QAAS,WAAU,QAAQ;GACvC;;AAGJ,SAAS,sBAAsB,MAA6B;AAC1D,KAAI,CAAC,KAAK,WAAW,QAAQ,CAAE,QAAO;CACtC,MAAM,OAAO,KAAK,MAAM,EAAe;AACvC,QAAO,mBAAmB,MAAM,WAAW,KAAK,WAAW,OAAO,CAAC,GAAG,OAAO;;AAG/E,eAAe,gBACb,MACA,WACA,WACA,QACA,WAA8B,mBACU;CACxC,MAAM,SAAS,MAAM,IAAI,MAAM;EAAC;EAAW;EAAM;EAAe;EAAW;EAAM;EAAO,EAAE,OAAO,EAC9F,MAAM,KAAK,CAAC,OAAO,QAAQ;CAC9B,MAAM,WAA0C,EAAE;AAClD,MAAK,MAAM,QAAQ,OAAO;AACxB,UAAQ,gBAAgB;EACxB,MAAM,cAAc,sBAAsB,KAAK;AAC/C,MAAI,CAAC,YAAa;EAClB,MAAM,SAAS,KAAK,MAAM,KAAK;EAC/B,MAAM,SAAS,KAAK,WAAW,YAAY;AAC3C,MAAI,CAAC,WAAW,OAAO,CAAE,OAAM,SAAS,QAAQ,QAAQ,OAAO;AAC/D,WAAS,KAAK,MAAM,cAAc,QAAQ,QAAQ,OAAO,CAAC;;AAE5D,QAAO;;AAGT,eAAe,wBACb,MACA,WACA,QACiB;CACjB,MAAM,QAAQ,KAAK,QAAQ,EAAE,wBAAwB,QAAQ,IAAI,GAAG,KAAK,KAAK,GAAG;CACjF,MAAM,MAAM,EAAE,gBAAgB,OAAO;AACrC,KAAI;AACF,QAAM,IAAI,MAAM,CAAC,aAAa,UAAU,EAAE,QAAQ,IAAI;EACtD,MAAM,QAAQ,MAAM,IAAI,MAAM;GAAC;GAAW;GAAM;GAAW;GAAM;GAAO,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC,OAAO,QAAQ;AAC9G,OAAK,MAAM,OAAO,MAAM;GACtB,MAAM,QAAQ,IAAI,MAAM,oCAAoC;AAC5D,OAAI,CAAC,MAAO;GACZ,MAAM,cAAc,sBAAsB,MAAM,GAAG;AACnD,OAAI,YACF,OAAM,IAAI,MAAM;IAAC;IAAgB;IAAS;IAAe,GAAG,MAAM,GAAG,GAAG,MAAM,GAAG,GAAG;IAAc,EAAE,QAAQ,IAAI;;AAIpH,SAAO,MAAM,IAAI,MAAM;GAAC;GAAe,MADpB,IAAI,MAAM,CAAC,aAAa,EAAE,QAAQ,IAAI;GACZ;GAAM;GAAoC,EAAE,QAAQ,IAAI;WAC7F;AACR,SAAO,OAAO,EAAE,OAAO,MAAM,CAAC;;;AAUlC,IAAI,eAAe;AAEnB,eAAe,kBACb,QACA,aACA,QACe;AACf,SAAQ,gBAAgB;CACxB,MAAM,OAAO,MAAM,MAAM,OAAO;CAChC,MAAM,YAAY,KAChB,QAAQ,YAAY,EACpB,qBAAqB,QAAQ,IAAI,GAAG,iBACrC;AACD,OAAM,MAAM,QAAQ,YAAY,EAAE,EAAE,WAAW,MAAM,CAAC;AACtD,KAAI;AACF,QAAM,SACJ,iBAAiB,QAAQ,EAAE,QAAQ,CAAC,EACpC,kBAAkB,WAAW,EAAE,MAAM,KAAK,OAAO,KAAO,CAAC,EACzD,EAAE,QAAQ,CACX;AACD,UAAQ,gBAAgB;AACxB,QAAM,MAAM,WAAW,KAAK,OAAO,IAAM;AACzC,QAAM,OAAO,WAAW,KAAK,OAAO,KAAK,MAAM;AAC/C,UAAQ,gBAAgB;AACxB,QAAM,OAAO,WAAW,YAAY;UAC7B,OAAO;AACd,MAAI,QAAQ,QAAS,OAAM,OAAO;AAClC,QAAM;WACE;AACR,QAAM,GAAG,WAAW,EAAE,OAAO,MAAM,CAAC;;;AAIxC,eAAe,oBACb,QACA,aACA,QACkB;CAClB,MAAM,CAAC,aAAa,oBAAoB,MAAM,QAAQ,IAAI,CACxD,cAAc,QAAQ,QAAQ,OAAO,EACrC,cAAc,aAAa,aAAa,OAAO,CAChD,CAAC;AACF,QAAO,YAAY,SAAS,iBAAiB,QACxC,YAAY,WAAW,iBAAiB;;AAG/C,eAAe,uBACb,mBACA,WACA,OACA,QACA,WAA8B,mBACU;CACxC,MAAM,WAA0C,EAAE;AAClD,MAAK,MAAM,QAAQ,OAAO;AACxB,UAAQ,gBAAgB;EACxB,MAAM,SAAS,KAAK,mBAAmB,KAAK;EAC5C,IAAI;AACJ,MAAI;AACF,gBAAa,MAAM,MAAM,OAAO;WACzB,OAAO;AACd,OAAK,MAAgC,SAAS,SAAU;AACxD,SAAM;;AAER,MAAI,WAAW,gBAAgB,CAC7B,OAAM,IAAI,MAAM,oEAAoE,SAAS;AAE/F,MAAI,CAAC,WAAW,QAAQ,CAAE;EAE1B,MAAM,cAAc,KAAK,WAAW,SAAS,KAAK,MAAM,EAAe,CAAC;AACxE,MAAI,WAAW,YAAY;OAGrB,CAAC,MAAM,oBAAoB,QAAQ,aAAa,OAAO,CACzD,OAAM,IAAI,MAAM,yCAAyC,cAAc;QAGzE,OAAM,SAAS,QAAQ,aAAa,OAAO;AAE7C,WAAS,KAAK,MAAM,cAAc,QAAQ,aAAa,OAAO,CAAC;;AAEjE,QAAO;;AAGT,eAAe,uBACb,QACA,QACA,eAAe,OACA;AACf,SAAQ,gBAAgB;CACxB,IAAI;AACJ,KAAI;AACF,SAAO,MAAM,MAAM,OAAO;UACnB,OAAO;AACd,MAAI,gBAAiB,MAAgC,SAAS,SAAU;AACxE,QAAM;;AAER,KAAI,KAAK,gBAAgB,CACvB,OAAM,IAAI,MACR,oDAAoD,OAAO,oFAE5D;AAEH,KAAI,CAAC,KAAK,aAAa,CAAE;AACzB,MAAK,MAAM,SAAS,MAAM,QAAQ,QAAQ,EAAE,eAAe,MAAM,CAAC,CAChE,OAAM,uBAAuB,KAAK,QAAQ,MAAM,KAAK,EAAE,OAAO;;AAIlE,eAAe,gBACb,YACA,WACA,QACA,WAA8B,mBACU;CACxC,MAAM,WAA0C,EAAE;CAClD,MAAM,UAAU,mBACb,KAAK,gBAAgB;EACpB,QAAQ,KAAK,YAAY,QAAQ,WAAW;EAC5C,aAAa,KAAK,WAAW,WAAW;EACzC,EAAE,CACF,QAAQ,EAAE,aAAa,WAAW,OAAO,CAAC;AAM7C,OAAM,uBAAuB,KAAK,YAAY,OAAO,EAAE,QAAQ,KAAK;CAEpE,MAAM,QAAQ,OAAO,WAAmB,mBAA0C;AAChF,QAAM,MAAM,gBAAgB,EAAE,WAAW,MAAM,CAAC;AAChD,OAAK,MAAM,SAAS,MAAM,QAAQ,WAAW,EAAE,eAAe,MAAM,CAAC,EAAE;AACrE,WAAQ,gBAAgB;GACxB,MAAM,cAAc,KAAK,WAAW,MAAM,KAAK;GAC/C,MAAM,mBAAmB,KAAK,gBAAgB,MAAM,KAAK;AACzD,OAAI,MAAM,aAAa,CACrB,OAAM,MAAM,aAAa,iBAAiB;YACjC,MAAM,QAAQ,EAAE;AACzB,UAAM,SAAS,aAAa,kBAAkB,OAAO;AACrD,YAAQ,gBAAgB;AACxB,aAAS,KAAK,MAAM,cAAc,aAAa,kBAAkB,OAAO,CAAC;cAChE,MAAM,gBAAgB,CAC/B,OAAM,IAAI,MAAM,oEAAoE,cAAc;;;AAKxG,MAAK,MAAM,EAAE,QAAQ,iBAAiB,SAAS;AAC7C,UAAQ,gBAAgB;AACxB,QAAM,MAAM,QAAQ,YAAY;;AAElC,QAAO;;AAgBT,SAAS,sBAAsB,WAA4B;AACzD,QAAO,UAAU,MAAM,KAAK,CAAC,OAAO,QAAQ,CAAC,MAAM,SAAS;EAC1D,MAAM,OAAO,KAAK,MAAM,EAAE,CAAC,MAAM,OAAO,CAAC,GAAG,GAAG,IAAI;AACnD,MAAI,SAAS,UAAU,KAAK,WAAW,QAAQ,CAC7C,QAAO;AAET,SAAO;GACP;;AAGJ,SAAS,eAAe,SAAuE;AAC7F,QAAO,CAAC,GAAG,IAAI,IAAI,QAAQ,KAAK,UAAU,CAAC,MAAM,aAAa,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;;AAGlF,MAAM,0BAA0B;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,SAAS,iBAAiB,MAAoB;CAC5C,MAAM,OAAO,KAAK,MAAM,aAAa;CACrC,MAAM,QAAQ,WAAW,KAAK,GAAG,aAAa,MAAM,OAAO,GAAG;CAI9D,MAAM,UAAU,IAAI,IAAI,CAAC,GAAG,yBAAyB,aAAa,CAAC;CACnE,MAAM,OAAO,MAAM,MAAM,KAAK,CAAC,QAAQ,SAAS,CAAC,QAAQ,IAAI,KAAK,MAAM,CAAC,CAAC;AAC1E,QAAO,KAAK,SAAS,KAAK,KAAK,KAAK,SAAS,IAAI,MAAM,KAAK,GAAI,MAAK,KAAK;AAC1E,eAAc,MAAM;EAAC,GAAG;EAAM;EAAI,GAAG;EAAyB;EAAG,CAAC,KAAK,KAAK,CAAC;;AAG/E,eAAsB,oBACpB,YACA,UAAsD,EAAE,EACxD,iBACe;CACf,MAAM,UAAU,mBAAmB,eAAe,WAAW;AAC7D,KAAI,CAAC,QAAS,OAAM,IAAI,MAAM,oBAAoB,aAAa;CAC/D,MAAM,EAAE,UAAU,SAAS,iBAAiB,QAAQ;CACpD,MAAM,oBAAoB,QAAQ;CAClC,MAAM,mBAAmB,sBAAsB;CAC/C,MAAM,YAAY,kBAAkB,SAAS,EAAE,YAAY,CAAC;AAC5D,SAAQ,IAAI,qCAAqC,WAAW,GAAG;AAC/D,SAAQ,IAAI,KAAK,kBAAkB,SAAS,mBAAmB,KAAK,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO,UAAU,GAAG;AACxH,SAAQ,IAAI,KAAK,kBAAkB,mBAAmB,kBAAkB,oBAAoB;AAC5F,KAAI,QAAQ,OAAQ;AAEpB,SAAQ,QAAQ,gBAAgB;CAChC,MAAM,UAAU,0BAA0B,WAAW;AACrD,KAAI;EAIF,MAAM,QAAQ,MAAM,OAAO,WAAW,iBAAiB,MAAM,QAAQ,OAAO,CAAC;AAC7E,MAAI,MAAM,QACR,OAAM,IAAI,MAAM,kDAAkD,MAAM,UAAU,kBAAkB;AAEtG,UAAQ,QAAQ,gBAAgB;AAIhC,QAAM,uBAAuB,KAAK,mBAAmB,OAAO,EAAE,QAAQ,QAAQ,KAAK;AACnF,MAAI,sBAAsB,MAAM,IAAI,MAAM,CAAC,UAAU,cAAc,EAAE,QAAQ,OAAO,CAAC,CACnF,OAAM,IAAI,MAAM,0FAA0F;AAE5G,QAAM,IAAI,MAAM;GAAC;GAAS;GAAW;GAAS,EAAE,QAAQ,OAAO;EAC/D,MAAM,gBAAgB,MAAM,IAAI,MAAM,CAAC,aAAa,OAAO,EAAE,QAAQ,OAAO;AAE5E,MAAI,kBAAkB,MADM,IAAI,MAAM,CAAC,aAAa,cAAc,EAAE,QAAQ,OAAO,CAC9C,OAAM,IAAI,MAAM,wDAAwD;AAO7G,MAAI,MALyB,IAAI,MAAM,CAAC,QAAQ,gDAAsD,EAAE,QAAQ,OAAO,CACpH,YAAY;AACX,WAAQ,QAAQ,gBAAgB;AAChC,UAAO;IACP,EACgB;AAClB,WAAQ,IAAI,6DAA6D;AACzE;;EAGF,IAAI,WAAW,MAAM,IAAI,MAAM,CAAC,aAAa,aAAa,EAAE,QAAQ,OAAO,CAAC,YAAY;AACtF,WAAQ,QAAQ,gBAAgB;AAChC,UAAO;IACP;EACF,MAAM,iBAAiB,MAAM,IAAI,MAAM,CAAC,aAAa,UAAU,eAAe,EAAE,QAAQ,OAAO,CAAC,YAAY;AAC1G,WAAQ,QAAQ,gBAAgB;AAChC,UAAO;IACP;AACF,MAAI,YAAY,kBAAkB,aAAa,eAC7C,OAAM,IAAI,MAAM,gFAAgF;AAElG,MAAI,CAAC,UAAU;AACb,cAAW,kBAAkB,MAAM,wBAAwB,MAAM,eAAe,QAAQ,OAAO;AAC/F,SAAM,IAAI,MAAM;IAAC;IAAc,cAAc;IAAgB;IAAS,EAAE,QAAQ,OAAO;;AAEzF,MAAI,CAAC,eAAgB,OAAM,IAAI,MAAM;GAAC;GAAQ;GAAU;GAAa,EAAE,QAAQ,OAAO;AAEtF,MAAI,CAAC,WAAW,UAAU,EAAE;AAC1B,WAAQ,QAAQ,gBAAgB;AAChC,aAAU,QAAQ,UAAU,EAAE,EAAE,WAAW,MAAM,CAAC;AAClD,SAAM,IAAI,MAAM;IAAC;IAAY;IAAO;IAAW;IAAa,EAAE,QAAQ,OAAO;;EAQ/E,MAAM,WAAW,mBACb,eAAe,CACb,GAAG,MAAM,gBAAgB,MAAM,eAAe,WAAW,QAAQ,OAAO,EACxE,GAAG,MAAM,gBAAgB,mBAAmB,WAAW,QAAQ,OAAO,CACvE,CAAC,GACF,MAAM,gBAAgB,mBAAmB,WAAW,QAAQ,OAAO;AACvE,MAAI,SAAS,SAAS,GAAG;AACvB,SAAM,IAAI,WAAW,CAAC,OAAO,QAAQ,EAAE,QAAQ,OAAO;AACtD,OAAI,MAAM,IAAI,WAAW;IAAC;IAAQ;IAAY;IAAc,EAAE,QAAQ,OAAO,CAC3E,OAAM,IAAI,WAAW;IAAC;IAAU;IAAM;IAA0C,EAAE,QAAQ,OAAO;AAEnG,SAAM,IAAI,WAAW;IAAC;IAAQ;IAAU;IAAa,EAAE,QAAQ,OAAO;;EAExE,MAAM,YAAY,oBACb,MAAM,IAAI,MAAM;GAAC;GAAY;GAAY;GAAM;GAAO,EAAE,QAAQ,OAAO,EAAE,MAAM,KAAK,CACpF,QAAQ,SAAS,KAAK,MAAM,IAAI,CAAC,WAAW,KAAK,WAAW,KAAK,MAAM,KAAK,CAAC,IAAI,UAAU,KAAK,MAAM,KAAK,CAAC,CAAC,QAAQ,CAAC,GACvH,WAAW,KAAK,mBAAmB,OAAO,CAAC,GACzC,YAAY,KAAK,mBAAmB,OAAO,EAAE,EAAE,eAAe,MAAM,CAAC,CACpE,QAAQ,UAAU,MAAM,QAAQ,CAAC,CACjC,KAAK,UAAU,QAAQ,MAAM,OAAO,GACrC,EAAE;AACR,WAAS,KAAK,GAAG,MAAM,uBACrB,mBACA,WACA,WACA,QAAQ,OACT,CAAC;AACF,MAAI,UAAU,SAAS,GAAG;AACxB,SAAM,IAAI,WAAW,CAAC,OAAO,QAAQ,EAAE,QAAQ,OAAO;AAGtD,OAAI,MAAM,IAAI,WAAW;IAAC;IAAQ;IAAY;IAAc,EAAE,QAAQ,OAAO,CAC3E,OAAM,IAAI,WAAW;IAAC;IAAU;IAAM;IAAkD,EAAE,QAAQ,OAAO;AAE3G,SAAM,IAAI,WAAW;IAAC;IAAQ;IAAU;IAAa,EAAE,QAAQ,OAAO;;AAGxE,MAAI,MAAM,IAAI,MAAM,CAAC,aAAa,OAAO,EAAE,QAAQ,OAAO,KAAK,cAC7D,OAAM,IAAI,MAAM,mDAAmD;AAErE,UAAQ,QAAQ,gBAAgB;AAKhC,MAAI,iBACF,OAAM,IAAI,MAAM;GAAC;GAAM;GAAM;GAAY;GAAoB;GAAgB;GAAkB;GAAc;GAAe;GAAe;GAAa;GAAiB;GAAgB;GAAa,CAAC;EAEzM,MAAM,aAAa,KAAK,mBAAmB,QAAQ,UAAU;EAC7D,MAAM,aAAa,KAAK,mBAAmB,aAAa,UAAU;EAClE,IAAI,eAAe;AACnB,MAAI,WAAW,WAAW,IAAI,CAAC,WAAW,WAAW,EAAE;AACrD,aAAU,QAAQ,WAAW,EAAE,EAAE,WAAW,MAAM,CAAC;AACnD,cAAW,YAAY,WAAW;AAClC,kBAAe;;AAEjB,mBAAiB,kBAAkB;AAInC,MAAI,kBAAkB;AACpB,OAAI,MAAM,IAAI,MAAM;IAAC;IAAY;IAAM;IAAe,CAAC,CACrD,OAAM,IAAI,MAAM;IAAC;IAAO;IAAM;IAAM;IAAe,CAAC;GAEtD,MAAM,WAAW,CAAC,aAAa;AAC/B,OAAI,gBAAgB,WAAW,WAAW,CAAE,UAAS,KAAK,oBAAoB;AAC9E,SAAM,IAAI,MAAM;IAAC;IAAO;IAAM,GAAG;IAAS,CAAC;AAE3C,OAAI,MAAM,IAAI,MAAM;IAAC;IAAQ;IAAY;IAAc,CAAC,CACtD,OAAM,IAAI,MAAM;IAAC;IAAU;IAAM;IAAuD,CAAC;;AAI7F,QAAM,6BAA6B,SAAS;AAC5C,OAAK,MAAM,SAAS,SAAU,QAAO,MAAM,QAAQ,EAAE,OAAO,MAAM,CAAC;AACnE,MAAI,CAAC,iBACH,QAAO,KAAK,mBAAmB,OAAO,EAAE;GAAE,WAAW;GAAM,OAAO;GAAM,CAAC;AAE3E,aAAW,MAAM,IAAI,WAAW,CAAC,aAAa,OAAO,CAAC;AACtD,gBAAc,KAAK,WAAW,0BAA0B,EAAE,GAAG,KAAK,UAAU;GAC1E;GACA,gBAAgB;GAChB,8BAAa,IAAI,MAAM,EAAC,aAAa;GACrC,SAAS;GACV,EAAE,MAAM,EAAE,CAAC,IAAI;AAChB,QAAM,IAAI,WAAW,CAAC,OAAO,0BAA0B,CAAC;AACxD,QAAM,IAAI,WAAW;GAAC;GAAU;GAAM;GAAyC,CAAC;AAEhF,QAAM,IAAI,MAAM;GAAC;GAAQ;GAAY;GAAa;GAAU;GAAQ;GAAa,CAAC;AAClF,QAAM,IAAI,MAAM;GAAC;GAAQ;GAAY;GAAU;GAAQ;GAAa,CAAC;AACrE,4BAA0B;WAClB;AACR,WAAS"}
|
|
1
|
+
{"version":3,"file":"state-migrate-KZ2goscQ.js","names":[],"sources":["../../src/lib/state-migration-manifest.ts","../../src/cli/commands/admin/agent-state-backfill.ts","../../src/cli/commands/admin/xbrief-state-migrate.ts","../../src/cli/commands/admin/state-migrate.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { createReadStream } from 'node:fs';\nimport { lstat } from 'node:fs/promises';\n\nexport interface StateMigrationManifestEntry {\n source: string;\n destination: string;\n mode: number;\n size: number;\n sha256: string;\n}\n\nasync function sha256(path: string, signal?: AbortSignal): Promise<string> {\n const hash = createHash('sha256');\n for await (const chunk of createReadStream(path, { signal })) {\n signal?.throwIfAborted();\n hash.update(chunk);\n }\n return hash.digest('hex');\n}\n\nexport async function manifestEntry(\n source: string,\n destination: string,\n signal?: AbortSignal,\n): Promise<StateMigrationManifestEntry> {\n signal?.throwIfAborted();\n const [stat, digest] = await Promise.all([\n lstat(source),\n sha256(source, signal),\n ]);\n signal?.throwIfAborted();\n return {\n source,\n destination,\n mode: stat.mode & 0o777,\n size: stat.size,\n sha256: digest,\n };\n}\n\nexport async function verifyStateMigrationManifest(\n entries: readonly StateMigrationManifestEntry[],\n): Promise<void> {\n for (const expected of entries) {\n const actual = await manifestEntry(expected.destination, expected.destination);\n // Compare modes the way git preserves them: only the executable bit is\n // tracked, so a checkout legitimately re-derives group/other bits from the\n // process umask (e.g. 0644 source vs 0664 worktree checkout). Content is\n // guaranteed by size + sha256.\n const executableMismatch = (actual.mode & 0o100) !== (expected.mode & 0o100);\n if (executableMismatch || actual.size !== expected.size || actual.sha256 !== expected.sha256) {\n throw new Error(`State migration no-loss mismatch: ${expected.source} -> ${expected.destination}`);\n }\n }\n}\n","import { existsSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport type { AgentState, Role } from '../../../lib/agents/agent-state.js';\nimport { getAgentStateSync, isRole } from '../../../lib/agents/agent-state.js';\nimport { getSessionId } from '../../../lib/agents/activity.js';\nimport { getAgentRuntimeStateSync } from '../../../lib/agents/runtime-state.js';\nimport { hasRetainedTranscriptsMarker } from '../../../lib/agents/state-dir-removal.js';\nimport { listAllAgentsSync } from '../../../lib/overdeck/agents.js';\nimport {\n listAgentRuntimeEventEvidenceSync,\n type AgentRuntimeEventEvidence,\n} from '../../../lib/overdeck/event-reads.js';\nimport {\n backfillAgentPlaneRecord,\n flushAgentPlaneWrites,\n readAgentPlaneRecordSync,\n type AgentPlaneSeed,\n type AgentPlaneSessionEntry,\n} from '../../../lib/pan-dir/agents.js';\nimport { claudeSessionTranscriptExists, getOverdeckHome } from '../../../lib/paths.js';\nimport { resolveProjectFromIssueSync } from '../../../lib/projects.js';\nimport type { RuntimeName } from '../../../lib/runtimes/types.js';\nimport { readSessionIdHistorySync } from '../../../lib/session-history.js';\n\nconst RUNTIME_NAMES = new Set<RuntimeName>([\n 'claude-code',\n 'ohmypi',\n 'codex',\n 'acp',\n 'kimi-code',\n]);\n\ntype DbAgent = ReturnType<typeof listAllAgentsSync>[number];\n\nexport type AgentPlaneBackfillStatus =\n | 'reconstructed'\n | 'recovered-partial'\n | 'skipped-live'\n | 'skipped';\n\nexport interface AgentPlaneBackfillResult {\n agentId: string;\n issueId?: string;\n status: AgentPlaneBackfillStatus;\n sessions: string[];\n reason?: string;\n}\n\nexport interface AgentPlaneBackfillDeps {\n listLocalAgentIds: () => string[];\n hasLocalState: (agentId: string) => boolean;\n hasRetainedMarker: (agentId: string) => Promise<boolean>;\n readAgentState: (agentId: string) => AgentState | null;\n listDbAgents: () => DbAgent[];\n listEventEvidence: () => AgentRuntimeEventEvidence[];\n readCurrentSessionId: (agentId: string) => string | null;\n readSessionHistory: (agentId: string) => string[];\n readRuntimeSessionId: (agentId: string) => string | null;\n transcriptExists: (workspace: string, sessionId: string) => boolean;\n resolveProject: typeof resolveProjectFromIssueSync;\n readPlaneRecord: typeof readAgentPlaneRecordSync;\n writePlaneRecord: typeof backfillAgentPlaneRecord;\n flushPlaneWrites: typeof flushAgentPlaneWrites;\n log: (message: string) => void;\n}\n\nfunction localAgentIds(): string[] {\n const agentsDir = join(getOverdeckHome(), 'agents');\n if (!existsSync(agentsDir)) return [];\n return readdirSync(agentsDir, { withFileTypes: true })\n .filter((entry) => entry.isDirectory())\n .map((entry) => entry.name);\n}\n\nfunction defaultDeps(): AgentPlaneBackfillDeps {\n const agentsDir = join(getOverdeckHome(), 'agents');\n return {\n listLocalAgentIds: localAgentIds,\n hasLocalState: (agentId) => existsSync(join(agentsDir, agentId, 'state.json')),\n hasRetainedMarker: (agentId) => hasRetainedTranscriptsMarker(join(agentsDir, agentId)),\n readAgentState: getAgentStateSync,\n listDbAgents: listAllAgentsSync,\n listEventEvidence: listAgentRuntimeEventEvidenceSync,\n readCurrentSessionId: getSessionId,\n readSessionHistory: readSessionIdHistorySync,\n readRuntimeSessionId: (agentId) => getAgentRuntimeStateSync(agentId)?.claudeSessionId ?? null,\n transcriptExists: claudeSessionTranscriptExists,\n resolveProject: resolveProjectFromIssueSync,\n readPlaneRecord: readAgentPlaneRecordSync,\n writePlaneRecord: backfillAgentPlaneRecord,\n flushPlaneWrites: flushAgentPlaneWrites,\n log: (message) => console.log(message),\n };\n}\n\nfunction runtimeName(value: unknown): RuntimeName | undefined {\n if (value === 'pi') return 'ohmypi';\n return typeof value === 'string' && RUNTIME_NAMES.has(value as RuntimeName)\n ? value as RuntimeName\n : undefined;\n}\n\nfunction usableString(...values: unknown[]): string | undefined {\n return values.find((value): value is string =>\n typeof value === 'string' && Boolean(value.trim()))?.trim();\n}\n\nfunction seedForAgent(\n agentId: string,\n state: AgentState | null,\n db: DbAgent | undefined,\n event: AgentRuntimeEventEvidence | undefined,\n): AgentPlaneSeed | null {\n const issueId = usableString(state?.issueId, db?.issueId, event?.issueId);\n const workspace = usableString(state?.workspace, db?.workspace, event?.workspace);\n const roleValue = state?.role ?? db?.role ?? event?.role;\n if (!issueId || !workspace || !isRole(roleValue)) return null;\n return {\n id: agentId,\n issueId,\n role: roleValue as Role,\n workspace,\n harness: runtimeName(state?.harness ?? db?.harness),\n model: usableString(state?.model, db?.model, event?.model),\n branch: usableString(state?.branch, db?.branch, event?.branch),\n startedAt: usableString(state?.startedAt, db?.startedAt, event?.startedAt),\n };\n}\n\nfunction appendSession(\n sessions: AgentPlaneSessionEntry[],\n seen: Set<string>,\n id: string | null | undefined,\n startedAt: string,\n reason: AgentPlaneSessionEntry['reason'],\n): void {\n const normalized = id?.trim();\n if (!normalized || seen.has(normalized)) return;\n seen.add(normalized);\n sessions.push({ id: normalized, startedAt, reason });\n}\n\nfunction sessionsForAgent(\n seed: AgentPlaneSeed,\n state: AgentState | null,\n db: DbAgent | undefined,\n event: AgentRuntimeEventEvidence | undefined,\n recovered: boolean,\n deps: AgentPlaneBackfillDeps,\n): AgentPlaneSessionEntry[] {\n const sessions: AgentPlaneSessionEntry[] = [];\n const seen = new Set<string>();\n const startedAt = seed.startedAt ?? new Date().toISOString();\n const localReason = recovered ? 'recovered' : 'spawn';\n const localCandidates = [\n deps.readCurrentSessionId(seed.id),\n ...deps.readSessionHistory(seed.id),\n deps.readRuntimeSessionId(seed.id),\n state?.sessionId,\n db?.sessionId,\n ];\n for (const sessionId of localCandidates) {\n const valid = seed.harness && seed.harness !== 'claude-code'\n ? true\n : Boolean(sessionId && deps.transcriptExists(seed.workspace, sessionId));\n if (valid) appendSession(sessions, seen, sessionId, startedAt, localReason);\n }\n for (const session of event?.sessions ?? []) {\n if (deps.transcriptExists(seed.workspace, session.id)) {\n appendSession(sessions, seen, session.id, session.startedAt, 'recovered');\n }\n }\n return sessions;\n}\n\nfunction isLiveStatus(state: AgentState | null, db: DbAgent | undefined): boolean {\n const status = state?.status ?? db?.status;\n return status === 'running' || status === 'starting';\n}\n\nexport async function backfillAgentRuntimePlane(\n options: { projectKey?: string; dryRun?: boolean } = {},\n deps: AgentPlaneBackfillDeps = defaultDeps(),\n): Promise<AgentPlaneBackfillResult[]> {\n const localIds = new Set(deps.listLocalAgentIds());\n const dbById = new Map(deps.listDbAgents().map((agent) => [agent.id, agent]));\n const eventById = new Map(deps.listEventEvidence().map((event) => [event.agentId, event]));\n const agentIds = new Set([...localIds, ...dbById.keys(), ...eventById.keys()]);\n const results: AgentPlaneBackfillResult[] = [];\n const flushTargets = new Map<string, { issueId: string; agentId: string }>();\n\n for (const agentId of [...agentIds].sort()) {\n const state = deps.readAgentState(agentId);\n const db = dbById.get(agentId);\n const event = eventById.get(agentId);\n const seed = seedForAgent(agentId, state, db, event);\n if (!seed) {\n results.push({\n agentId,\n status: 'skipped',\n sessions: [],\n reason: 'identity, role, or workspace metadata is incomplete',\n });\n continue;\n }\n const project = deps.resolveProject(seed.issueId);\n if (!project) {\n results.push({\n agentId,\n issueId: seed.issueId,\n status: 'skipped',\n sessions: [],\n reason: `no configured project resolves ${seed.issueId}`,\n });\n continue;\n }\n if (options.projectKey && project.projectKey !== options.projectKey) continue;\n\n const hasLocalState = deps.hasLocalState(agentId);\n const retained = await deps.hasRetainedMarker(agentId);\n const recovered = !hasLocalState || (retained && !deps.readCurrentSessionId(agentId));\n const existing = deps.readPlaneRecord(seed.issueId, agentId);\n if (isLiveStatus(state, db) && existing) {\n if (!options.dryRun) {\n flushTargets.set(project.projectKey, { issueId: seed.issueId, agentId });\n }\n results.push({\n agentId,\n issueId: seed.issueId,\n status: 'skipped-live',\n sessions: existing.sessions.map((session) => session.id),\n });\n continue;\n }\n\n const sessions = sessionsForAgent(seed, state, db, event, recovered, deps);\n if (options.dryRun) {\n results.push({\n agentId,\n issueId: seed.issueId,\n status: recovered ? 'recovered-partial' : 'reconstructed',\n sessions: sessions.map((session) => session.id),\n reason: 'dry run; durable record was not written',\n });\n continue;\n }\n try {\n const written = await deps.writePlaneRecord(\n seed,\n sessions,\n recovered,\n { deferCommit: true },\n );\n if (written || existing) {\n flushTargets.set(project.projectKey, { issueId: seed.issueId, agentId });\n }\n results.push({\n agentId,\n issueId: seed.issueId,\n status: !written && !existing\n ? 'skipped'\n : recovered ? 'recovered-partial' : 'reconstructed',\n sessions: (!written && existing ? existing.sessions : sessions)\n .map((session) => session.id),\n ...(!written ? {\n reason: existing\n ? 'existing durable record already contained equal or stronger history'\n : 'durable agent plane is unavailable for this project',\n } : {}),\n });\n } catch (error) {\n results.push({\n agentId,\n issueId: seed.issueId,\n status: 'skipped',\n sessions: [],\n reason: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n for (const [projectKey, target] of flushTargets) {\n const flush = await deps.flushPlaneWrites(target.issueId, target.agentId);\n if (!flush || flush.errored || flush.pushed !== true) {\n throw new Error(\n `Agent-plane backfill push failed for ${projectKey}: ${flush?.reason ?? 'no confirmed state-branch push'}`,\n );\n }\n }\n\n for (const result of results) {\n deps.log(\n `${result.agentId}: ${result.status}`\n + `${result.sessions.length > 0 ? ` (sessions: ${result.sessions.join(', ')})` : ''}`\n + `${result.reason ? ` — ${result.reason}` : ''}`,\n );\n }\n return results;\n}\n","import { execFile } from 'node:child_process';\nimport {\n existsSync,\n readFileSync,\n readdirSync,\n renameSync,\n writeFileSync,\n} from 'node:fs';\nimport { join, relative } from 'node:path';\nimport { promisify } from 'node:util';\nimport { Effect } from 'effect';\n\nimport { flushAutoCommits, queueAutoCommit } from '../../../lib/pan-dir/auto-commit.js';\nimport { getProjectSync, type ProjectConfig } from '../../../lib/projects.js';\nimport { MIGRATION_COMPLETE_MARKER, STATE_BRANCH, stateWorktreePath } from '../../../lib/state-home.js';\nimport {\n LEGACY_VBRIEF_FILENAME_SUFFIX,\n XBRIEF_FILENAME_SUFFIX,\n} from '../../../lib/xbrief/lifecycle.js';\n\nconst execFileAsync = promisify(execFile);\n\ninterface RewriteOperation {\n path: string;\n content: string;\n}\n\ninterface RenameOperation {\n from: string;\n to: string;\n}\n\nexport interface XBriefStateMigrationPlan {\n rewrites: RewriteOperation[];\n renames: RenameOperation[];\n files: string[];\n}\n\nexport interface XBriefStateMigrationResult {\n dryRun: boolean;\n filesMigrated: number;\n committed: boolean;\n}\n\nfunction canonicalPath(path: string): string {\n return `${path.slice(0, -LEGACY_VBRIEF_FILENAME_SUFFIX.length)}${XBRIEF_FILENAME_SUFFIX}`;\n}\n\nfunction migratedSpecContent(path: string): string | null {\n let parsed: Record<string, unknown>;\n try {\n const value = JSON.parse(readFileSync(path, 'utf8')) as unknown;\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('expected a JSON object');\n }\n parsed = value as Record<string, unknown>;\n } catch (error) {\n throw new Error(`Cannot migrate invalid xBRIEF JSON at ${path}: ${String(error)}`);\n }\n\n if (!Object.hasOwn(parsed, 'vBRIEFInfo')) return null;\n if (Object.hasOwn(parsed, 'xBRIEFInfo')) {\n if (JSON.stringify(parsed.xBRIEFInfo) !== JSON.stringify(parsed.vBRIEFInfo)) {\n throw new Error(`Cannot migrate conflicting vBRIEFInfo and xBRIEFInfo envelopes at ${path}`);\n }\n delete parsed.vBRIEFInfo;\n return `${JSON.stringify(parsed, null, 2)}\\n`;\n }\n\n const { vBRIEFInfo, ...document } = parsed;\n return `${JSON.stringify({ xBRIEFInfo: vBRIEFInfo, ...document }, null, 2)}\\n`;\n}\n\nfunction planDirectoryRenames(directory: string, renames: RenameOperation[], files: Set<string>): void {\n if (!existsSync(directory)) return;\n for (const entry of readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {\n if (!entry.isFile() || !entry.name.endsWith(LEGACY_VBRIEF_FILENAME_SUFFIX)) continue;\n const from = join(directory, entry.name);\n const to = canonicalPath(from);\n if (existsSync(to)) {\n throw new Error(`Cannot migrate ${from}: destination already exists at ${to}`);\n }\n renames.push({ from, to });\n files.add(from);\n }\n}\n\nexport function planXBriefStateMigration(stateRoot: string): XBriefStateMigrationPlan {\n const specsDir = join(stateRoot, 'specs');\n const continuesDir = join(stateRoot, 'continues');\n const rewrites: RewriteOperation[] = [];\n const renames: RenameOperation[] = [];\n const files = new Set<string>();\n\n if (existsSync(specsDir)) {\n for (const entry of readdirSync(specsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {\n if (!entry.isFile() || !entry.name.endsWith('.json')) continue;\n const path = join(specsDir, entry.name);\n const content = migratedSpecContent(path);\n if (content !== null) {\n rewrites.push({ path, content });\n files.add(path);\n }\n }\n }\n\n planDirectoryRenames(specsDir, renames, files);\n planDirectoryRenames(continuesDir, renames, files);\n\n return {\n rewrites,\n renames,\n files: [...files].sort(),\n };\n}\n\nasync function assertCleanStateWorktree(stateRoot: string): Promise<void> {\n if (!existsSync(join(stateRoot, '.git'))) {\n throw new Error(`State worktree is missing at ${stateRoot}`);\n }\n if (!existsSync(join(stateRoot, MIGRATION_COMPLETE_MARKER))) {\n throw new Error(`State worktree is not migration-complete: ${stateRoot}`);\n }\n\n const { stdout: branch } = await execFileAsync('git', ['branch', '--show-current'], {\n cwd: stateRoot,\n encoding: 'utf8',\n timeout: 15_000,\n });\n if (branch.trim() !== STATE_BRANCH) {\n throw new Error(`Expected ${STATE_BRANCH} at ${stateRoot}, found ${branch.trim() || 'detached HEAD'}`);\n }\n\n const { stdout: status } = await execFileAsync('git', ['status', '--porcelain'], {\n cwd: stateRoot,\n encoding: 'utf8',\n timeout: 15_000,\n });\n if (status.trim()) {\n throw new Error(`State worktree is dirty; commit or resolve existing changes before xBRIEF migration:\\n${status.trim()}`);\n }\n}\n\nfunction printPlan(projectKey: string, stateRoot: string, plan: XBriefStateMigrationPlan): void {\n console.log(`xBRIEF state migration plan for ${projectKey}:`);\n for (const rewrite of plan.rewrites) {\n console.log(` rewrite ${relative(stateRoot, rewrite.path)}: vBRIEFInfo -> xBRIEFInfo`);\n }\n for (const rename of plan.renames) {\n console.log(` rename ${relative(stateRoot, rename.from)} -> ${relative(stateRoot, rename.to)}`);\n }\n console.log(` ${plan.files.length} file(s) to migrate`);\n}\n\nexport async function migrateProjectXBriefState(\n projectKey: string,\n options: { dryRun?: boolean } = {},\n projectOverride?: ProjectConfig,\n): Promise<XBriefStateMigrationResult> {\n const project = projectOverride ?? getProjectSync(projectKey);\n if (!project) throw new Error(`Unknown project: ${projectKey}`);\n const stateRoot = stateWorktreePath(project, { projectKey });\n\n await assertCleanStateWorktree(stateRoot);\n const plan = planXBriefStateMigration(stateRoot);\n printPlan(projectKey, stateRoot, plan);\n\n if (options.dryRun || plan.files.length === 0) {\n return {\n dryRun: options.dryRun === true,\n filesMigrated: plan.files.length,\n committed: false,\n };\n }\n\n for (const rewrite of plan.rewrites) writeFileSync(rewrite.path, rewrite.content);\n for (const rename of plan.renames) renameSync(rename.from, rename.to);\n\n const paths = new Set<string>();\n for (const rewrite of plan.rewrites) paths.add(rewrite.path);\n for (const rename of plan.renames) {\n paths.add(rename.from);\n paths.add(rename.to);\n }\n queueAutoCommit({\n projectRoot: project.path,\n repoRoot: stateRoot,\n paths: [...paths],\n subject: 'chore(state): migrate xBRIEF documents (PAN-2829)',\n });\n const flush = await Effect.runPromise(flushAutoCommits(project.path));\n if (flush.errored || !flush.committed || flush.pushed === false) {\n throw new Error(`xBRIEF state migration commit failed: ${flush.reason ?? 'state writer did not commit and push'}`);\n }\n\n console.log(`Migrated ${plan.files.length} xBRIEF state file(s) in one commit.`);\n return {\n dryRun: false,\n filesMigrated: plan.files.length,\n committed: true,\n };\n}\n","import { execFile, type ChildProcess, type ExecFileException } from 'node:child_process';\nimport { createReadStream, createWriteStream, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';\nimport { chmod, lstat, mkdir, readdir, rename, rm, utimes } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { pipeline } from 'node:stream/promises';\nimport { Command } from 'commander';\nimport { Effect } from 'effect';\n\nimport { flushAutoCommits } from '../../../lib/pan-dir/auto-commit.js';\nimport { getProjectSync, resolveInfraRepo, type ProjectConfig } from '../../../lib/projects.js';\nimport { STATE_BRANCH, MIGRATION_COMPLETE_MARKER, clearStateMigrationCache, stateWorktreePath } from '../../../lib/state-home.js';\nimport { STATE_BRANCH_PATHS } from '../../../lib/state-plane.js';\nimport { acquireStateMigrationLock } from '../../../lib/state-migration-lock.js';\nimport { manifestEntry, verifyStateMigrationManifest, type StateMigrationManifestEntry } from '../../../lib/state-migration-manifest.js';\nimport { backfillAgentRuntimePlane } from './agent-state-backfill.js';\nimport { migrateProjectXBriefState } from './xbrief-state-migrate.js';\n\nconst GIT_COMMAND_TIMEOUT_MS = 30_000;\n\nconst execFileDetached = execFile as unknown as (\n file: string,\n args: string[],\n options: {\n cwd: string;\n env: NodeJS.ProcessEnv;\n encoding: BufferEncoding;\n maxBuffer: number;\n detached: boolean;\n },\n callback: (error: ExecFileException | null, stdout: string, stderr: string) => void,\n) => ChildProcess;\n\nfunction killProcessTree(child: ChildProcess | undefined): void {\n if (!child?.pid) return;\n try {\n if (process.platform === 'win32') child.kill('SIGKILL');\n else process.kill(-child.pid, 'SIGKILL');\n } catch {\n try { child.kill('SIGKILL'); } catch { /* process already exited */ }\n }\n}\n\nasync function git(\n cwd: string,\n args: string[],\n signal?: AbortSignal,\n env?: NodeJS.ProcessEnv,\n): Promise<string> {\n signal?.throwIfAborted();\n const command = `git ${args.join(' ')}`;\n return new Promise((resolve, reject) => {\n let child: ChildProcess | undefined;\n let termination: 'abort' | 'timeout' | undefined;\n const terminate = (kind: 'abort' | 'timeout') => {\n if (termination) return;\n termination = kind;\n killProcessTree(child);\n };\n const timeout = setTimeout(() => terminate('timeout'), GIT_COMMAND_TIMEOUT_MS);\n const onAbort = () => terminate('abort');\n signal?.addEventListener('abort', onAbort, { once: true });\n\n child = execFileDetached('git', args, {\n cwd,\n env: { ...process.env, ...env },\n encoding: 'utf8',\n maxBuffer: 32 * 1024 * 1024,\n detached: process.platform !== 'win32',\n }, (error, stdout, stderr) => {\n clearTimeout(timeout);\n signal?.removeEventListener('abort', onAbort);\n if (termination === 'abort') {\n reject(signal?.reason ?? new DOMException(`${command} was cancelled`, 'AbortError'));\n } else if (termination === 'timeout') {\n reject(new Error(`${command} timed out after ${GIT_COMMAND_TIMEOUT_MS / 1_000}s`));\n } else if (error) {\n reject(Object.assign(error, { stdout, stderr }));\n } else {\n resolve(stdout.trim());\n }\n });\n\n if (signal?.aborted) terminate('abort');\n });\n}\n\nfunction destinationForTracked(path: string): string | null {\n if (!path.startsWith('.pan/')) return null;\n const flat = path.slice('.pan/'.length);\n return STATE_BRANCH_PATHS.some((prefix) => flat.startsWith(prefix)) ? flat : null;\n}\n\nasync function trackedManifest(\n repo: string,\n sourceSha: string,\n stateRoot: string,\n signal?: AbortSignal,\n copyFile: CopyFileOperation = copyFileAbortable,\n): Promise<StateMigrationManifestEntry[]> {\n const paths = (await git(repo, ['ls-tree', '-r', '--name-only', sourceSha, '--', '.pan'], signal))\n .split('\\n').filter(Boolean);\n const manifest: StateMigrationManifestEntry[] = [];\n for (const path of paths) {\n signal?.throwIfAborted();\n const destination = destinationForTracked(path);\n if (!destination) continue;\n const source = join(repo, path);\n const target = join(stateRoot, destination);\n if (!existsSync(target)) await copyFile(source, target, signal);\n manifest.push(await manifestEntry(source, target, signal));\n }\n return manifest;\n}\n\nasync function createOrphanStateCommit(\n repo: string,\n sourceSha: string,\n signal?: AbortSignal,\n): Promise<string> {\n const index = join(tmpdir(), `overdeck-state-index-${process.pid}-${Date.now()}`);\n const env = { GIT_INDEX_FILE: index };\n try {\n await git(repo, ['read-tree', '--empty'], signal, env);\n const rows = (await git(repo, ['ls-tree', '-r', sourceSha, '--', '.pan'], signal)).split('\\n').filter(Boolean);\n for (const row of rows) {\n const match = row.match(/^(\\d+)\\s+\\w+\\s+([0-9a-f]+)\\t(.+)$/);\n if (!match) continue;\n const destination = destinationForTracked(match[3]);\n if (destination) {\n await git(repo, ['update-index', '--add', '--cacheinfo', `${match[1]},${match[2]},${destination}`], signal, env);\n }\n }\n const tree = await git(repo, ['write-tree'], signal, env);\n return await git(repo, ['commit-tree', tree, '-m', 'chore(state): seed overdeck-state'], signal, env);\n } finally {\n rmSync(index, { force: true });\n }\n}\n\ntype CopyFileOperation = (\n source: string,\n destination: string,\n signal?: AbortSignal,\n) => Promise<void>;\n\nlet copySequence = 0;\n\nasync function copyFileAbortable(\n source: string,\n destination: string,\n signal?: AbortSignal,\n): Promise<void> {\n signal?.throwIfAborted();\n const stat = await lstat(source);\n const temporary = join(\n dirname(destination),\n `.overdeck-migrate-${process.pid}-${copySequence++}`,\n );\n await mkdir(dirname(destination), { recursive: true });\n try {\n await pipeline(\n createReadStream(source, { signal }),\n createWriteStream(temporary, { mode: stat.mode & 0o777 }),\n { signal },\n );\n signal?.throwIfAborted();\n await chmod(temporary, stat.mode & 0o777);\n await utimes(temporary, stat.atime, stat.mtime);\n signal?.throwIfAborted();\n await rename(temporary, destination);\n } catch (error) {\n if (signal?.aborted) throw signal.reason;\n throw error;\n } finally {\n await rm(temporary, { force: true });\n }\n}\n\nasync function filesEqualAbortable(\n source: string,\n destination: string,\n signal?: AbortSignal,\n): Promise<boolean> {\n const [sourceEntry, destinationEntry] = await Promise.all([\n manifestEntry(source, source, signal),\n manifestEntry(destination, destination, signal),\n ]);\n return sourceEntry.size === destinationEntry.size\n && sourceEntry.sha256 === destinationEntry.sha256;\n}\n\nasync function preserveUntrackedNotes(\n legacyStateSource: string,\n stateRoot: string,\n paths: readonly string[],\n signal?: AbortSignal,\n copyFile: CopyFileOperation = copyFileAbortable,\n): Promise<StateMigrationManifestEntry[]> {\n const manifest: StateMigrationManifestEntry[] = [];\n for (const path of paths) {\n signal?.throwIfAborted();\n const source = join(legacyStateSource, path);\n let sourceStat;\n try {\n sourceStat = await lstat(source);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') continue;\n throw error;\n }\n if (sourceStat.isSymbolicLink()) {\n throw new Error(`Legacy state changed during migration: symbolic link appeared at ${source}`);\n }\n if (!sourceStat.isFile()) continue;\n\n const destination = join(stateRoot, 'notes', path.slice('.pan/'.length));\n if (existsSync(destination)) {\n // A byte-identical destination is this migration's own interrupted prior\n // copy. Stream both files so collision checks remain cancellable.\n if (!await filesEqualAbortable(source, destination, signal)) {\n throw new Error(`Untracked-note destination collision: ${destination}`);\n }\n } else {\n await copyFile(source, destination, signal);\n }\n manifest.push(await manifestEntry(source, destination, signal));\n }\n return manifest;\n}\n\nasync function assertNoLegacySymlinks(\n source: string,\n signal?: AbortSignal,\n allowMissing = false,\n): Promise<void> {\n signal?.throwIfAborted();\n let stat;\n try {\n stat = await lstat(source);\n } catch (error) {\n if (allowMissing && (error as NodeJS.ErrnoException).code === 'ENOENT') return;\n throw error;\n }\n if (stat.isSymbolicLink()) {\n throw new Error(\n `Legacy state contains unsupported symbolic link: ${source}. `\n + 'Resolve it before migrating so canonical state cannot depend on the legacy tree.',\n );\n }\n if (!stat.isDirectory()) return;\n for (const entry of await readdir(source, { withFileTypes: true })) {\n await assertNoLegacySymlinks(join(source, entry.name), signal);\n }\n}\n\nasync function copyLegacyState(\n sourceRoot: string,\n stateRoot: string,\n signal?: AbortSignal,\n copyFile: CopyFileOperation = copyFileAbortable,\n): Promise<StateMigrationManifestEntry[]> {\n const manifest: StateMigrationManifestEntry[] = [];\n const sources = STATE_BRANCH_PATHS\n .map((sourcePath) => ({\n source: join(sourceRoot, '.pan', sourcePath),\n destination: join(stateRoot, sourcePath),\n }))\n .filter(({ source }) => existsSync(source));\n\n // Symlinks cannot be made durable by the regular-file manifest: absolute\n // targets can still point into the legacy tree after cleanup, and relative\n // targets can resolve differently under the state worktree. Check the whole\n // legacy tree so ignored top-level entries cannot be deleted without notice.\n await assertNoLegacySymlinks(join(sourceRoot, '.pan'), signal, true);\n\n const visit = async (sourceDir: string, destinationDir: string): Promise<void> => {\n await mkdir(destinationDir, { recursive: true });\n for (const entry of await readdir(sourceDir, { withFileTypes: true })) {\n signal?.throwIfAborted();\n const sourceEntry = join(sourceDir, entry.name);\n const destinationEntry = join(destinationDir, entry.name);\n if (entry.isDirectory()) {\n await visit(sourceEntry, destinationEntry);\n } else if (entry.isFile()) {\n await copyFile(sourceEntry, destinationEntry, signal);\n signal?.throwIfAborted();\n manifest.push(await manifestEntry(sourceEntry, destinationEntry, signal));\n } else if (entry.isSymbolicLink()) {\n throw new Error(`Legacy state changed during migration: symbolic link appeared at ${sourceEntry}`);\n }\n }\n };\n\n for (const { source, destination } of sources) {\n signal?.throwIfAborted();\n await visit(source, destination);\n }\n return manifest;\n}\n\nfunction workspacePaths(repo: string): string[] {\n const root = join(repo, 'workspaces');\n if (!existsSync(root)) return [];\n return readdirSync(root, { withFileTypes: true })\n .filter((entry) => entry.isDirectory())\n .map((entry) => join(root, entry.name))\n // Only real git worktrees are workspaces. workspaces/ can contain stray\n // non-worktree directories (e.g. a root-owned node_modules left by a\n // container) that must not be touched — writing into them EACCES-aborts\n // the migration mid-flight.\n .filter((path) => existsSync(join(path, '.git')));\n}\n\nfunction hasNonStateDirtyState(porcelain: string): boolean {\n return porcelain.split('\\n').filter(Boolean).some((line) => {\n const path = line.slice(3).split(' -> ').at(-1) ?? '';\n if (path === '.pan' || path.startsWith('.pan/')) {\n return false;\n }\n return true;\n });\n}\n\nfunction dedupeManifest(entries: StateMigrationManifestEntry[]): StateMigrationManifestEntry[] {\n return [...new Map(entries.map((entry) => [entry.destination, entry])).values()];\n}\n\nconst GITIGNORE_MANAGED_LINES = [\n '# PAN-2541: permanent state is on overdeck-state; workspace runtime stays local.',\n '.pan/',\n '.overdeck/continue.json',\n '.overdeck/spec.vbrief.json',\n '.overdeck/sessions.jsonl',\n '.overdeck/feedback/',\n '.overdeck/review/',\n '.overdeck/test/',\n '.overdeck/kickoff.md',\n '.overdeck/agent-mcp.json',\n];\n\nfunction rewriteGitignore(repo: string): void {\n const path = join(repo, '.gitignore');\n const prior = existsSync(path) ? readFileSync(path, 'utf8') : '';\n // Idempotent: strip every line this function manages (plus the legacy bare\n // '.overdeck/' entry) before appending the block exactly once — an\n // interrupted migration must not accrete duplicate blocks on resume.\n const managed = new Set([...GITIGNORE_MANAGED_LINES, '.overdeck/']);\n const kept = prior.split('\\n').filter((line) => !managed.has(line.trim()));\n while (kept.length > 0 && kept[kept.length - 1]?.trim() === '') kept.pop();\n writeFileSync(path, [...kept, '', ...GITIGNORE_MANAGED_LINES, ''].join('\\n'));\n}\n\nexport async function migrateProjectState(\n projectKey: string,\n options: { dryRun?: boolean; signal?: AbortSignal } = {},\n projectOverride?: ProjectConfig,\n): Promise<void> {\n const project = projectOverride ?? getProjectSync(projectKey);\n if (!project) throw new Error(`Unknown project: ${projectKey}`);\n const { repoPath: repo } = resolveInfraRepo(project);\n const legacyStateSource = project.path;\n const sourceIsHostRepo = legacyStateSource === repo;\n const stateRoot = stateWorktreePath(project, { projectKey });\n console.log(`PAN-2541 state migration plan for ${projectKey}:`);\n console.log(` ${legacyStateSource}/.pan/{${STATE_BRANCH_PATHS.map((p) => p.slice(0, -1)).join(',')}} -> ${stateRoot}/`);\n console.log(` ${legacyStateSource}/.pan/context -> ${legacyStateSource}/.overdeck/context`);\n if (options.dryRun) return;\n\n options.signal?.throwIfAborted();\n const release = acquireStateMigrationLock(projectKey);\n try {\n // The reconciliation deadline owns the writer too: cancellation interrupts\n // every active or queued flush for this Git root and waits for settlement, so\n // migration can never proceed beside a detached commit or push.\n const flush = await Effect.runPromise(flushAutoCommits(repo, options.signal));\n if (flush.errored) {\n throw new Error(`State writer did not quiesce before migration: ${flush.reason ?? 'unknown error'}`);\n }\n options.signal?.throwIfAborted();\n // This read-only preflight runs before fetches, branch creation, worktree\n // creation, or destination writes. copyLegacyState repeats it immediately\n // before copying to defend against changes outside the migration lock.\n await assertNoLegacySymlinks(join(legacyStateSource, '.pan'), options.signal, true);\n if (hasNonStateDirtyState(await git(repo, ['status', '--porcelain'], options.signal))) {\n throw new Error('Primary checkout is dirty outside legacy state paths; migration refused before mutation');\n }\n await git(repo, ['fetch', '--prune', 'origin'], options.signal);\n const sourceMainSha = await git(repo, ['rev-parse', 'main'], options.signal);\n const remoteMainSha = await git(repo, ['rev-parse', 'origin/main'], options.signal);\n if (sourceMainSha !== remoteMainSha) throw new Error('main is not exactly at origin/main; migration refused');\n\n const existingMarker = await git(repo, ['show', `origin/${STATE_BRANCH}:${MIGRATION_COMPLETE_MARKER}`], options.signal)\n .catch(() => {\n options.signal?.throwIfAborted();\n return '';\n });\n if (existingMarker) {\n console.log('State migration already complete on origin; nothing to do.');\n return;\n }\n\n let stateSha = await git(repo, ['rev-parse', STATE_BRANCH], options.signal).catch(() => {\n options.signal?.throwIfAborted();\n return '';\n });\n const remoteStateSha = await git(repo, ['rev-parse', `origin/${STATE_BRANCH}`], options.signal).catch(() => {\n options.signal?.throwIfAborted();\n return '';\n });\n if (stateSha && remoteStateSha && stateSha !== remoteStateSha) {\n throw new Error('Local and remote overdeck-state diverged; refusing non-fast-forward migration');\n }\n if (!stateSha) {\n stateSha = remoteStateSha || await createOrphanStateCommit(repo, sourceMainSha, options.signal);\n await git(repo, ['update-ref', `refs/heads/${STATE_BRANCH}`, stateSha], options.signal);\n }\n if (!remoteStateSha) await git(repo, ['push', 'origin', STATE_BRANCH], options.signal);\n\n if (!existsSync(stateRoot)) {\n options.signal?.throwIfAborted();\n mkdirSync(dirname(stateRoot), { recursive: true });\n await git(repo, ['worktree', 'add', stateRoot, STATE_BRANCH], options.signal);\n }\n\n // A pipeline may have produced state after the last code commit (the PUZ-1\n // failure mode). Seed tracked blobs for historical fidelity, then overlay\n // the current working-tree state so untracked .pan/specs enter the verified\n // manifest before legacy paths are removed. Unrelated dirty code remains a\n // hard block above. Legacy .beads data is intentionally left untouched.\n const manifest = sourceIsHostRepo\n ? dedupeManifest([\n ...await trackedManifest(repo, sourceMainSha, stateRoot, options.signal),\n ...await copyLegacyState(legacyStateSource, stateRoot, options.signal),\n ])\n : await copyLegacyState(legacyStateSource, stateRoot, options.signal);\n if (manifest.length > 0) {\n await git(stateRoot, ['add', '--all'], options.signal);\n if (await git(stateRoot, ['diff', '--cached', '--name-only'], options.signal)) {\n await git(stateRoot, ['commit', '-m', 'chore(state): seed legacy project state'], options.signal);\n }\n await git(stateRoot, ['push', 'origin', STATE_BRANCH], options.signal);\n }\n const untracked = sourceIsHostRepo\n ? (await git(repo, ['ls-files', '--others', '--', '.pan'], options.signal)).split('\\n')\n .filter((path) => path.split('/').length === 2 && existsSync(join(repo, path)) && lstatSync(join(repo, path)).isFile())\n : existsSync(join(legacyStateSource, '.pan'))\n ? readdirSync(join(legacyStateSource, '.pan'), { withFileTypes: true })\n .filter((entry) => entry.isFile())\n .map((entry) => `.pan/${entry.name}`)\n : [];\n manifest.push(...await preserveUntrackedNotes(\n legacyStateSource,\n stateRoot,\n untracked,\n options.signal,\n ));\n if (untracked.length > 0) {\n await git(stateRoot, ['add', 'notes'], options.signal);\n // Resume tolerance: a prior interrupted attempt may have already\n // committed these notes — git commit exits 1 on an empty index.\n if (await git(stateRoot, ['diff', '--cached', '--name-only'], options.signal)) {\n await git(stateRoot, ['commit', '-m', 'chore(state): preserve untracked operator notes'], options.signal);\n }\n await git(stateRoot, ['push', 'origin', STATE_BRANCH], options.signal);\n }\n\n if (await git(repo, ['rev-parse', 'main'], options.signal) !== sourceMainSha) {\n throw new Error('main advanced during migration; refusing cleanup');\n }\n options.signal?.throwIfAborted();\n\n // From source cleanup through the atomic push, migration is one durability\n // boundary. Cancellation must await this resumable sequence instead of\n // leaving deleted legacy sources without a durable completion marker.\n if (sourceIsHostRepo) {\n await git(repo, ['rm', '-r', '--cached', '--ignore-unmatch', '.pan/records', '.pan/continues', '.pan/specs', '.pan/drafts', '.pan/review', '.pan/test', '.pan/feedback', '.pan/backlog', '.pan/notes']);\n }\n const oldContext = join(legacyStateSource, '.pan', 'context');\n const newContext = join(legacyStateSource, '.overdeck', 'context');\n let movedContext = false;\n if (existsSync(oldContext) && !existsSync(newContext)) {\n mkdirSync(dirname(newContext), { recursive: true });\n renameSync(oldContext, newContext);\n movedContext = true;\n }\n rewriteGitignore(legacyStateSource);\n // Resume tolerance: a prior attempt may already have committed the\n // context deletions — `git add -u` exits 128 on a pathspec with no\n // tracked entries left.\n if (sourceIsHostRepo) {\n if (await git(repo, ['ls-files', '--', '.pan/context'])) {\n await git(repo, ['add', '-u', '--', '.pan/context']);\n }\n const addPaths = ['.gitignore'];\n if (movedContext || existsSync(newContext)) addPaths.push('.overdeck/context');\n await git(repo, ['add', '--', ...addPaths]);\n // Resume tolerance: skip when a prior attempt already committed the cleanup.\n if (await git(repo, ['diff', '--cached', '--name-only'])) {\n await git(repo, ['commit', '-m', 'chore(state): move permanent state to overdeck-state']);\n }\n }\n\n await verifyStateMigrationManifest(manifest);\n for (const entry of manifest) rmSync(entry.source, { force: true });\n if (!sourceIsHostRepo) {\n rmSync(join(legacyStateSource, '.pan'), { recursive: true, force: true });\n }\n stateSha = await git(stateRoot, ['rev-parse', 'HEAD']);\n writeFileSync(join(stateRoot, MIGRATION_COMPLETE_MARKER), `${JSON.stringify({\n sourceMainSha,\n stateBranchSha: stateSha,\n completedAt: new Date().toISOString(),\n version: 1,\n }, null, 2)}\\n`);\n await git(stateRoot, ['add', MIGRATION_COMPLETE_MARKER]);\n await git(stateRoot, ['commit', '-m', 'chore(state): complete state migration']);\n\n await git(repo, ['push', '--atomic', '--dry-run', 'origin', 'main', STATE_BRANCH]);\n await git(repo, ['push', '--atomic', 'origin', 'main', STATE_BRANCH]);\n clearStateMigrationCache();\n } finally {\n release();\n }\n}\n\nexport const __testInternals = {\n copyFileAbortable,\n copyLegacyState,\n filesEqualAbortable,\n git,\n preserveUntrackedNotes,\n trackedManifest,\n};\n\nexport function registerStateMigrationCommand(admin: Command): void {\n const state = admin.command('state')\n .description('Permanent state administration');\n\n state.command('migrate <project>')\n .description('Move permanent state to the orphan overdeck-state branch')\n .option('--dry-run', 'Print the exact migration plan without mutating anything')\n .action((project: string, options: { dryRun?: boolean }) => migrateProjectState(project, options));\n\n state.command('migrate-xbrief <project>')\n .description('Rename state documents to .xbrief.json and migrate legacy envelopes')\n .option('--dry-run', 'Print the exact xBRIEF migration plan without mutating anything')\n .action(async (project: string, options: { dryRun?: boolean }) => {\n await migrateProjectXBriefState(project, options);\n });\n\n state.command('backfill-agents [project]')\n .description('Reconstruct durable agent runtime records from local and retained state')\n .option('--dry-run', 'Report the records and sessions that would be written')\n .action(async (project: string | undefined, options: { dryRun?: boolean }) => {\n await backfillAgentRuntimePlane({ projectKey: project, dryRun: options.dryRun });\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { o as shouldSkipIdlePokeForAgent } from "./stuck-remediation-
|
|
1
|
+
import { o as shouldSkipIdlePokeForAgent } from "./stuck-remediation-CnoV0kcv.js";
|
|
2
2
|
export { shouldSkipIdlePokeForAgent };
|
|
@@ -2,12 +2,12 @@ import { Li as getOverdeckHome, Ri as init_paths, Ui as sessionFilePath } from "
|
|
|
2
2
|
import { A as listPaneValuesSync, C as init_tmux, D as killSessionSync, E as killSession, W as sessionExistsSync, i as capturePaneSync, l as detectTerminalApiErrorSync, z as sendEscapeKeyAsync } from "./tmux-l-yvNWhg.js";
|
|
3
3
|
import { _ as logDeaconEventSync, h as init_persistent_logger } from "./agents-CkngXhQr.js";
|
|
4
4
|
import { c as init_control_settings, i as getFlywheelActiveRunId, p as isFlywheelGloballyPaused } from "./control-settings-BkaVFRdm.js";
|
|
5
|
-
import { C as markAgentTroubled, Ft as resumeAgent, Gt as messageAgent, Rn as listRunningAgentsSync, W as getAgentRuntimeStateSync, nn as resolveLatestSessionIdSync, q as init_agents, tn as init_activity, wt as init_agent_enrichment, yt as countPendingAskUserQuestionsForAgent } from "./agent-state-
|
|
5
|
+
import { C as markAgentTroubled, Ft as resumeAgent, Gt as messageAgent, Rn as listRunningAgentsSync, W as getAgentRuntimeStateSync, nn as resolveLatestSessionIdSync, q as init_agents, tn as init_activity, wt as init_agent_enrichment, yt as countPendingAskUserQuestionsForAgent } from "./agent-state-B196fj1h.js";
|
|
6
6
|
import { h as readWorkspacePlanSync, s as init_io } from "./io-Cm4Sf_6P.js";
|
|
7
7
|
import { a as getDispatchableItems, c as init_dag } from "./dag-Drz6Nrnf.js";
|
|
8
8
|
import { a as loadCloisterConfigSync, r as init_config, t as DEFAULT_CLOISTER_CONFIG } from "./config-B-MLcKSo.js";
|
|
9
|
-
import { d as getReviewStatusSync, p as init_review_status } from "./review-status-
|
|
10
|
-
import { n as getAgentWorkActivityMs, r as isAgentIdleForNudge, t as getAgentEffectiveLastActivityMs } from "./agent-idle-
|
|
9
|
+
import { d as getReviewStatusSync, p as init_review_status } from "./review-status-yY5qt7Rl.js";
|
|
10
|
+
import { n as getAgentWorkActivityMs, r as isAgentIdleForNudge, t as getAgentEffectiveLastActivityMs } from "./agent-idle-D-Qy5BN_.js";
|
|
11
11
|
import { i as recordRecoveryFailure, r as init_recovery_trip } from "./recovery-trip-7JFHFjeo.js";
|
|
12
12
|
import { Effect } from "effect";
|
|
13
13
|
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
|
|
@@ -665,7 +665,7 @@ async function remediateFlywheelOrchestrator(agentId, now, actions, reason) {
|
|
|
665
665
|
now
|
|
666
666
|
});
|
|
667
667
|
if (decision.kind === "noop") return;
|
|
668
|
-
const { resumeFlywheel, pauseFlywheel } = await import("./flywheel-
|
|
668
|
+
const { resumeFlywheel, pauseFlywheel } = await import("./flywheel-jeZFYvm-.js");
|
|
669
669
|
const prev = readStuckRemediationState(agentId);
|
|
670
670
|
const nowIso = new Date(now).toISOString();
|
|
671
671
|
if (decision.kind === "escalate") {
|
|
@@ -771,4 +771,4 @@ async function checkStuckAgentRemediation(opts = {}) {
|
|
|
771
771
|
//#endregion
|
|
772
772
|
export { shouldClearPlanningWedgeEpisode as a, executePlanningWedgeDecision as i, decideFlywheelRemediation as n, shouldSkipIdlePokeForAgent as o, decidePlanningWedgeRemediation as r, shouldSkipReviewStatus as s, checkStuckAgentRemediation as t };
|
|
773
773
|
|
|
774
|
-
//# sourceMappingURL=stuck-remediation-
|
|
774
|
+
//# sourceMappingURL=stuck-remediation-CnoV0kcv.js.map
|