@overdeck/core 0.45.10 → 0.45.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-state-KVbJEG5f.js → agent-state-RLhS7ckO.js} +1 -1
- package/dist/{agents-pp8FO7Uj.js → agents-By3u_fQ8.js} +1 -1
- package/dist/{agents-CQHK0CSA.js → agents-CgVr77Qq.js} +12 -12
- package/dist/{agents-CQHK0CSA.js.map → agents-CgVr77Qq.js.map} +1 -1
- package/dist/{backlog-auto-trigger-CyuoS0nl.js → backlog-auto-trigger-B_-1tk4e.js} +5 -5
- package/dist/{backlog-auto-trigger-CyuoS0nl.js.map → backlog-auto-trigger-B_-1tk4e.js.map} +1 -1
- package/dist/cli/index.js +45 -45
- package/dist/{cli-Cewlu3yU.js → cli-DGeSW85B.js} +2 -2
- package/dist/{cli-Cewlu3yU.js.map → cli-DGeSW85B.js.map} +1 -1
- package/dist/cli-MTB9IOoR.js +3 -0
- package/dist/{close-issue-BJGX9_z7.js → close-issue-Djajb6Sv.js} +2 -2
- package/dist/{close-issue-BJGX9_z7.js.map → close-issue-Djajb6Sv.js.map} +1 -1
- package/dist/{concurrency-Ca-fC7tA.js → concurrency-4rzjHAQA.js} +1 -1
- package/dist/{conversation-compaction-B_6s9EvM.js → conversation-compaction-BQvZh09I.js} +4 -4
- package/dist/{conversation-compaction-B_6s9EvM.js.map → conversation-compaction-BQvZh09I.js.map} +1 -1
- package/dist/dashboard/{advancing-selfheal-CMlGznKv.js → advancing-selfheal-BezNfM3P.js} +3 -3
- package/dist/dashboard/{advancing-selfheal-CMlGznKv.js.map → advancing-selfheal-BezNfM3P.js.map} +1 -1
- package/dist/dashboard/{agent-state-xk_G8t90.js → agent-state-BUANcaA7.js} +1 -1
- package/dist/dashboard/{agent-state-service-C1iUF9Ft.js → agent-state-service-DmFpIMbP.js} +1 -1
- package/dist/dashboard/{agent-state-service-5ge9xxhx.js → agent-state-service-tXUdp6UF.js} +2 -2
- package/dist/dashboard/{agent-state-service-5ge9xxhx.js.map → agent-state-service-tXUdp6UF.js.map} +1 -1
- package/dist/dashboard/{agents-BIggLvi_.js → agents-C-vqmKDi.js} +1 -1
- package/dist/dashboard/{agents-DHvsjsuP.js → agents-C7V4odQ6.js} +11 -11
- package/dist/dashboard/{agents-DHvsjsuP.js.map → agents-C7V4odQ6.js.map} +1 -1
- package/dist/dashboard/{backlog-auto-trigger-COm_R96V.js → backlog-auto-trigger-Cb8PR-5w.js} +2 -2
- package/dist/dashboard/{backlog-auto-trigger-COm_R96V.js.map → backlog-auto-trigger-Cb8PR-5w.js.map} +1 -1
- package/dist/dashboard/{cli-CvK9xuSS.js → cli-BgzbB6h3.js} +2 -2
- package/dist/dashboard/{cli-CvK9xuSS.js.map → cli-BgzbB6h3.js.map} +1 -1
- package/dist/dashboard/cli-DCqy_wFa.js +3 -0
- package/dist/dashboard/{close-issue-BnpErnD1.js → close-issue-BWf3pxn4.js} +2 -2
- package/dist/dashboard/{close-issue-BnpErnD1.js.map → close-issue-BWf3pxn4.js.map} +1 -1
- package/dist/dashboard/{closed-issue-reaper-DRqK5k39.js → closed-issue-reaper-D7XPq5pY.js} +4 -4
- package/dist/dashboard/{closed-issue-reaper-DRqK5k39.js.map → closed-issue-reaper-D7XPq5pY.js.map} +1 -1
- package/dist/dashboard/{closed-issue-reaper-BLCQwTpF.js → closed-issue-reaper-VSTSTROK.js} +1 -1
- package/dist/dashboard/{conflict-gate-JdFuhKuF.js → conflict-gate-DwOslTij.js} +1 -1
- package/dist/dashboard/{conflict-gate-BhKvrPxn.js → conflict-gate-FFEvTDVA.js} +3 -3
- package/dist/dashboard/{conflict-gate-BhKvrPxn.js.map → conflict-gate-FFEvTDVA.js.map} +1 -1
- package/dist/dashboard/{conversation-compaction-C5o_eKEm.js → conversation-compaction-CCqN4hWk.js} +4 -4
- package/dist/dashboard/{conversation-compaction-C5o_eKEm.js.map → conversation-compaction-CCqN4hWk.js.map} +1 -1
- package/dist/dashboard/{conversation-compaction-Ba5aZdrb.js → conversation-compaction-CL5Ti4j4.js} +1 -1
- package/dist/dashboard/{deacon-j3qSZ7--.js → deacon-CGHl90eC.js} +107 -50
- package/dist/dashboard/{deacon-j3qSZ7--.js.map → deacon-CGHl90eC.js.map} +1 -1
- package/dist/dashboard/{deacon-Cv2RMfHs.js → deacon-DMPh40Im.js} +2 -2
- package/dist/dashboard/deacon-swarm-CVTiNL0N.js +2 -0
- package/dist/dashboard/{deacon-swarm-DadWNi5J.js → deacon-swarm-aMMJTq6t.js} +4 -4
- package/dist/dashboard/{deacon-swarm-DadWNi5J.js.map → deacon-swarm-aMMJTq6t.js.map} +1 -1
- package/dist/dashboard/deacon.js +4 -4
- package/dist/dashboard/{feedback-target-oE4-Esxl.js → feedback-target-dJjFfITP.js} +4 -4
- package/dist/dashboard/{feedback-target-oE4-Esxl.js.map → feedback-target-dJjFfITP.js.map} +1 -1
- package/dist/dashboard/{feedback-target-C4DaDSZ8.js → feedback-target-nQSM6ygL.js} +1 -1
- package/dist/dashboard/{flywheel-ClMjGW_u.js → flywheel-BLoVNtJV.js} +6 -6
- package/dist/dashboard/{flywheel-ClMjGW_u.js.map → flywheel-BLoVNtJV.js.map} +1 -1
- package/dist/dashboard/{flywheel-DefHRzY4.js → flywheel-Cqf8vu7N.js} +6 -6
- package/dist/dashboard/{flywheel-DefHRzY4.js.map → flywheel-Cqf8vu7N.js.map} +1 -1
- package/dist/dashboard/{flywheel-BqDdGvrQ.js → flywheel-PJsbrXNY.js} +1 -1
- package/dist/dashboard/{flywheel-merge-order-CuDcqTRJ.js → flywheel-merge-order-B7BH8mZ3.js} +2 -2
- package/dist/dashboard/{flywheel-merge-order-CuDcqTRJ.js.map → flywheel-merge-order-B7BH8mZ3.js.map} +1 -1
- package/dist/dashboard/{flywheel-merge-order-B6YDSElh.js → flywheel-merge-order-CCwF60b-.js} +1 -1
- package/dist/dashboard/{harness-resolve-DKeSVsJL.js → harness-resolve-B3f9G1Kp.js} +2 -2
- package/dist/dashboard/{harness-resolve-DKeSVsJL.js.map → harness-resolve-B3f9G1Kp.js.map} +1 -1
- package/dist/dashboard/{inspect-agent-BKKc0XnB.js → inspect-agent-CKF5-SJr.js} +3 -3
- package/dist/dashboard/{inspect-agent-BKKc0XnB.js.map → inspect-agent-CKF5-SJr.js.map} +1 -1
- package/dist/dashboard/inspect-agent-CqpEWGWy.js +2 -0
- package/dist/dashboard/{issue-lifecycle-DnhQgddB.js → issue-lifecycle-5LbOcATP.js} +7 -7
- package/dist/dashboard/{issue-lifecycle-DnhQgddB.js.map → issue-lifecycle-5LbOcATP.js.map} +1 -1
- package/dist/dashboard/{issue-lifecycle-nY4esZn8.js → issue-lifecycle-CjYqQ669.js} +1 -1
- package/dist/dashboard/{issue-service-singleton-Bnqv1uaa.js → issue-service-singleton-B8iu_TKV.js} +1 -1
- package/dist/dashboard/{issue-service-singleton-_AquSBTl.js → issue-service-singleton-CDGt__oQ.js} +2 -2
- package/dist/dashboard/{issue-service-singleton-_AquSBTl.js.map → issue-service-singleton-CDGt__oQ.js.map} +1 -1
- package/dist/dashboard/{lifecycle-CGKm7doE.js → lifecycle-CEg4sHZH.js} +4 -4
- package/dist/dashboard/{lifecycle-CGKm7doE.js.map → lifecycle-CEg4sHZH.js.map} +1 -1
- package/dist/dashboard/{merge-agent-Dh8Y9PDO.js → merge-agent-7nBiCytp.js} +1 -1
- package/dist/dashboard/{merge-agent-BcgAYStl.js → merge-agent-C81xPIGd.js} +6 -6
- package/dist/dashboard/{merge-agent-BcgAYStl.js.map → merge-agent-C81xPIGd.js.map} +1 -1
- package/dist/dashboard/merge-ops-DE_6CnmZ.js +2 -0
- package/dist/dashboard/{merge-train-DmxlYbEo.js → merge-train-D3qzRccL.js} +2 -2
- package/dist/dashboard/{merge-train-DmxlYbEo.js.map → merge-train-D3qzRccL.js.map} +1 -1
- package/dist/dashboard/{merge-train-deps-DBHsOWt9.js → merge-train-deps-Be5ElC_P.js} +2 -2
- package/dist/dashboard/{merge-train-deps-DBHsOWt9.js.map → merge-train-deps-Be5ElC_P.js.map} +1 -1
- package/dist/dashboard/{orphan-proposed-reconciler-Db8tUhce.js → orphan-proposed-reconciler-Boq_XaRe.js} +3 -3
- package/dist/dashboard/{orphan-proposed-reconciler-Db8tUhce.js.map → orphan-proposed-reconciler-Boq_XaRe.js.map} +1 -1
- package/dist/dashboard/{orphan-proposed-reconciler-mXV--tcB.js → orphan-proposed-reconciler-C0sPnDq_.js} +1 -1
- package/dist/dashboard/{reconstruct-cache-_tDZ2D72.js → reconstruct-cache-C2pCltOq.js} +3 -3
- package/dist/dashboard/{reconstruct-cache-_tDZ2D72.js.map → reconstruct-cache-C2pCltOq.js.map} +1 -1
- package/dist/dashboard/{remote-completion-Bklh6loJ.js → remote-completion-BmxD5UMQ.js} +3 -3
- package/dist/dashboard/{remote-completion-Bklh6loJ.js.map → remote-completion-BmxD5UMQ.js.map} +1 -1
- package/dist/dashboard/resume-C-nxu9Y4.js +3 -0
- package/dist/dashboard/{review-agent-phzqNqIs.js → review-agent-D6P6d3pz.js} +26 -17
- package/dist/dashboard/review-agent-D6P6d3pz.js.map +1 -0
- package/dist/dashboard/review-agent-DTINEffB.js +3 -0
- package/dist/dashboard/{review-context-CCq56O_Y.js → review-context-Dyo0tsBa.js} +2 -2
- package/dist/dashboard/{review-context-CCq56O_Y.js.map → review-context-Dyo0tsBa.js.map} +1 -1
- package/dist/dashboard/{review-status-BQjqQXZG.js → review-status-B5ZASOo4.js} +18 -5
- package/dist/dashboard/review-status-B5ZASOo4.js.map +1 -0
- package/dist/dashboard/{review-status-bBkqUj5i.js → review-status-h7BXIA4z.js} +1 -1
- package/dist/dashboard/{review-verdict-feedback-wqnikhMK.js → review-verdict-feedback-B70VbfRL.js} +4 -4
- package/dist/dashboard/{review-verdict-feedback-wqnikhMK.js.map → review-verdict-feedback-B70VbfRL.js.map} +1 -1
- package/dist/dashboard/{review-verdict-feedback-cZh9Wi9G.js → review-verdict-feedback-CorgH49f.js} +1 -1
- package/dist/dashboard/{sequence-io-B2GmilSI.js → sequence-io-6YP8fVpH.js} +2 -2
- package/dist/dashboard/{sequence-io-B2GmilSI.js.map → sequence-io-6YP8fVpH.js.map} +1 -1
- package/dist/dashboard/{sequencer-agent-D8pW2aU_.js → sequencer-agent-ja-nkEc1.js} +5 -5
- package/dist/dashboard/{sequencer-agent-D8pW2aU_.js.map → sequencer-agent-ja-nkEc1.js.map} +1 -1
- package/dist/dashboard/server.js +66 -55
- package/dist/dashboard/server.js.map +1 -1
- package/dist/dashboard/{service-CILd-uOt.js → service-HKDrIy0h.js} +24 -24
- package/dist/dashboard/{service-CILd-uOt.js.map → service-HKDrIy0h.js.map} +1 -1
- package/dist/dashboard/{smart-compaction-Bgp_gwcA.js → smart-compaction-L0LSnF0_.js} +1 -1
- package/dist/dashboard/{smart-compaction-CrP90OFE.js → smart-compaction-uke1npUz.js} +2 -2
- package/dist/dashboard/{smart-compaction-CrP90OFE.js.map → smart-compaction-uke1npUz.js.map} +1 -1
- package/dist/dashboard/{spawn-planning-session-D15KbPOy.js → spawn-planning-session-CSMWco8B.js} +1 -1
- package/dist/dashboard/{spawn-planning-session-BmJWHSCu.js → spawn-planning-session-CXc0NkwV.js} +3 -3
- package/dist/dashboard/{spawn-planning-session-BmJWHSCu.js.map → spawn-planning-session-CXc0NkwV.js.map} +1 -1
- package/dist/dashboard/{specialist-context-CwKkcXL9.js → specialist-context-BGCJ24LH.js} +3 -3
- package/dist/dashboard/{specialist-context-CwKkcXL9.js.map → specialist-context-BGCJ24LH.js.map} +1 -1
- package/dist/dashboard/{specialist-logs-CvDxquV_.js → specialist-logs--Uz-r8ia.js} +2 -2
- package/dist/dashboard/{specialist-logs-CvDxquV_.js.map → specialist-logs--Uz-r8ia.js.map} +1 -1
- package/dist/dashboard/{specialists-BCjcG4uE.js → specialists-Ca9XSBCS.js} +1 -1
- package/dist/dashboard/{specialists-D07ybnam.js → specialists-DEfrAbWs.js} +36 -36
- package/dist/dashboard/{specialists-D07ybnam.js.map → specialists-DEfrAbWs.js.map} +1 -1
- package/dist/dashboard/{specialists-F2uMO4QS.js → specialists-DeZx9xom.js} +1 -1
- package/dist/dashboard/{specialists-BYi0k8CZ.js → specialists-nZ0mRwpZ.js} +12 -12
- package/dist/dashboard/{specialists-BYi0k8CZ.js.map → specialists-nZ0mRwpZ.js.map} +1 -1
- package/dist/dashboard/{summary-fork-DedqguZb.js → summary-fork-2a1L2DIU.js} +2 -2
- package/dist/dashboard/{summary-fork-EjvOkEPl.js → summary-fork-Xn0QUNmb.js} +3 -3
- package/dist/dashboard/{summary-fork-EjvOkEPl.js.map → summary-fork-Xn0QUNmb.js.map} +1 -1
- package/dist/dashboard/{teardown-workspace-5LCVbjfq.js → teardown-workspace-DhA6oAIK.js} +2 -2
- package/dist/dashboard/{teardown-workspace-5LCVbjfq.js.map → teardown-workspace-DhA6oAIK.js.map} +1 -1
- package/dist/dashboard/{test-agent-queue-qfsq6uaC.js → test-agent-queue-B_ukPyIK.js} +3 -3
- package/dist/dashboard/{test-agent-queue-qfsq6uaC.js.map → test-agent-queue-B_ukPyIK.js.map} +1 -1
- package/dist/dashboard/{uat-train-CtNGgXxj.js → uat-train-BLBAbJ8Y.js} +10 -10
- package/dist/dashboard/{uat-train-CtNGgXxj.js.map → uat-train-BLBAbJ8Y.js.map} +1 -1
- package/dist/dashboard/{uat-train-C3hWXtip.js → uat-train-DPfGR9_I.js} +1 -1
- package/dist/dashboard/{verification-runner-DuZRHjPU.js → verification-runner-KTGTNugM.js} +1 -1
- package/dist/dashboard/{verification-runner-BPAhPWR7.js → verification-runner-R2-4XgMO.js} +4 -4
- package/dist/dashboard/{verification-runner-BPAhPWR7.js.map → verification-runner-R2-4XgMO.js.map} +1 -1
- package/dist/dashboard/{workflows-H-COJ84X.js → workflows-CSKX5MhC.js} +7 -7
- package/dist/dashboard/{workflows-H-COJ84X.js.map → workflows-CSKX5MhC.js.map} +1 -1
- package/dist/dashboard/workflows-DVwXauef.js +2 -0
- package/dist/dashboard/{workspaces-CRU9_vRn.js → workspaces-DXLDgXo2.js} +32 -32
- package/dist/dashboard/{workspaces-CRU9_vRn.js.map → workspaces-DXLDgXo2.js.map} +1 -1
- package/dist/docs-index.sqlite +0 -0
- package/dist/{feedback-target-DTGAhFkM.js → feedback-target-BsKN4Tr_.js} +4 -4
- package/dist/{feedback-target-DTGAhFkM.js.map → feedback-target-BsKN4Tr_.js.map} +1 -1
- package/dist/{feedback-target-DutF088V.js → feedback-target-DM1WzOKy.js} +1 -1
- package/dist/{harness-resolve-Bz1prk6B.js → harness-resolve-B-YDNwNW.js} +2 -2
- package/dist/{harness-resolve-Bz1prk6B.js.map → harness-resolve-B-YDNwNW.js.map} +1 -1
- package/dist/{issue-lifecycle-fVqvCdKM.js → issue-lifecycle-Bc1l3U9f.js} +7 -7
- package/dist/{issue-lifecycle-fVqvCdKM.js.map → issue-lifecycle-Bc1l3U9f.js.map} +1 -1
- package/dist/{issue-service-singleton-CZm8p6Rj.js → issue-service-singleton-D-8Q6tdT.js} +1 -1
- package/dist/{issue-service-singleton-Cr73JAaR.js → issue-service-singleton-D1433I7n.js} +2 -2
- package/dist/{issue-service-singleton-Cr73JAaR.js.map → issue-service-singleton-D1433I7n.js.map} +1 -1
- package/dist/{lifecycle-CR6tZfl1.js → lifecycle-SmrqysDf.js} +7 -7
- package/dist/{lifecycle-CR6tZfl1.js.map → lifecycle-SmrqysDf.js.map} +1 -1
- package/dist/{lifecycle-D_EWiUjk.js → lifecycle-mRMyiIXs.js} +2 -2
- package/dist/{merge-agent-LM4avOtA.js → merge-agent-B9hIZ6Z0.js} +6 -6
- package/dist/{merge-agent-LM4avOtA.js.map → merge-agent-B9hIZ6Z0.js.map} +1 -1
- package/dist/{merge-agent-Bj046HE1.js → merge-agent-DUj22cXL.js} +1 -1
- package/dist/{merge-fulfillment-DrnC1Kmg.js → merge-fulfillment-__P4WE-T.js} +3 -3
- package/dist/{merge-fulfillment-DrnC1Kmg.js.map → merge-fulfillment-__P4WE-T.js.map} +1 -1
- package/dist/{reconstruct-cache-NPqoAUg-.js → reconstruct-cache-9SWp82SQ.js} +3 -3
- package/dist/{reconstruct-cache-NPqoAUg-.js.map → reconstruct-cache-9SWp82SQ.js.map} +1 -1
- package/dist/{records-BIkN1LQ4.js → records-CTmvuRzz.js} +14 -1
- package/dist/{records-BIkN1LQ4.js.map → records-CTmvuRzz.js.map} +1 -1
- package/dist/records-backfill-BQcmTmwF.js +2 -0
- package/dist/{records-backfill-HM0Pln6N.js → records-backfill-BrNsv_zT.js} +2 -2
- package/dist/{records-backfill-HM0Pln6N.js.map → records-backfill-BrNsv_zT.js.map} +1 -1
- package/dist/resume-Bn4kDk9x.js +3 -0
- package/dist/{review-agent-DFosQzCG.js → review-agent-PhqOhpx3.js} +24 -16
- package/dist/{review-agent-DFosQzCG.js.map → review-agent-PhqOhpx3.js.map} +1 -1
- package/dist/review-agent-hLbRRxZF.js +3 -0
- package/dist/{review-status-iJwfEoNX.js → review-status-B_XXomV0.js} +6 -6
- package/dist/{review-status-iJwfEoNX.js.map → review-status-B_XXomV0.js.map} +1 -1
- package/dist/{review-status-BbNVlXh1.js → review-status-Bo-EFVKh.js} +1 -1
- package/dist/{review-verdict-feedback-BGPw3z1X.js → review-verdict-feedback-CXHkoiKZ.js} +1 -1
- package/dist/{review-verdict-feedback-CCZ05atV.js → review-verdict-feedback-DGV13LDb.js} +4 -4
- package/dist/{review-verdict-feedback-CCZ05atV.js.map → review-verdict-feedback-DGV13LDb.js.map} +1 -1
- package/dist/{sequence-io-CcxZNHcD.js → sequence-io-Cg4NHAco.js} +1 -1
- package/dist/{sequence-io-Cx1usxG3.js → sequence-io-CyxvNHfA.js} +2 -2
- package/dist/{sequence-io-Cx1usxG3.js.map → sequence-io-CyxvNHfA.js.map} +1 -1
- package/dist/{smart-compaction-ByUEgQkF.js → smart-compaction-ByKXTQNy.js} +2 -2
- package/dist/{smart-compaction-ByUEgQkF.js.map → smart-compaction-ByKXTQNy.js.map} +1 -1
- package/dist/{smart-compaction-DfLe_CtH.js → smart-compaction-U6e_uB1E.js} +1 -1
- package/dist/{specialist-context-McuGkaeR.js → specialist-context-BUTadO-U.js} +3 -3
- package/dist/{specialist-context-McuGkaeR.js.map → specialist-context-BUTadO-U.js.map} +1 -1
- package/dist/{specialist-logs-CUUJ4eiB.js → specialist-logs-pEMCTtGZ.js} +2 -2
- package/dist/{specialist-logs-CUUJ4eiB.js.map → specialist-logs-pEMCTtGZ.js.map} +1 -1
- package/dist/{specialists-BSrylD1S.js → specialists-BGFnrQ8n.js} +1 -1
- package/dist/{specialists-B0elgInc.js → specialists-DeTkkp8b.js} +12 -12
- package/dist/{specialists-B0elgInc.js.map → specialists-DeTkkp8b.js.map} +1 -1
- package/dist/{summary-fork-DskMRnyb.js → summary-fork-CgzThE2-.js} +2 -2
- package/dist/{summary-fork-CPUTKcAT.js → summary-fork-Dx1RMuvU.js} +3 -3
- package/dist/{summary-fork-CPUTKcAT.js.map → summary-fork-Dx1RMuvU.js.map} +1 -1
- package/dist/{sync-BiNVQHBf.js → sync-Bsww9tuj.js} +2 -2
- package/dist/{sync-BiNVQHBf.js.map → sync-Bsww9tuj.js.map} +1 -1
- package/dist/sync-CylE_SjB.js +2 -0
- package/dist/{verdict-restore-DQiV7_fe.js → verdict-restore-DGpX0ZOJ.js} +5 -5
- package/dist/{verdict-restore-DQiV7_fe.js.map → verdict-restore-DGpX0ZOJ.js.map} +1 -1
- package/dist/{webhook-handlers-DHBSEDEm.js → webhook-handlers-BjsfIL7u.js} +3 -3
- package/dist/{webhook-handlers-DHBSEDEm.js.map → webhook-handlers-BjsfIL7u.js.map} +1 -1
- package/dist/{workspace-migrate-duUsWNpd.js → workspace-migrate-BBQ8nAnP.js} +2 -2
- package/dist/{workspace-migrate-duUsWNpd.js.map → workspace-migrate-BBQ8nAnP.js.map} +1 -1
- package/dist/{workspace-reap-DLCIoJmn.js → workspace-reap-12O9354k.js} +2 -2
- package/dist/{workspace-reap-DLCIoJmn.js.map → workspace-reap-12O9354k.js.map} +1 -1
- package/package.json +1 -1
- package/scripts/file-size-baseline.txt +1 -1
- package/dist/cli-DBWG12XK.js +0 -3
- package/dist/dashboard/cli-CJDWXE_Y.js +0 -3
- package/dist/dashboard/deacon-swarm-D1iAUX-P.js +0 -2
- package/dist/dashboard/inspect-agent-vm88mLYr.js +0 -2
- package/dist/dashboard/merge-ops-QdBiQ8XB.js +0 -2
- package/dist/dashboard/resume-DnIsmIgC.js +0 -3
- package/dist/dashboard/review-agent-DgySDb-G.js +0 -3
- package/dist/dashboard/review-agent-phzqNqIs.js.map +0 -1
- package/dist/dashboard/review-status-BQjqQXZG.js.map +0 -1
- package/dist/dashboard/workflows-Cz8OtiB4.js +0 -2
- package/dist/records-backfill-DEgtRyKL.js +0 -2
- package/dist/resume-DGymuXZM.js +0 -3
- package/dist/review-agent-DjVadURa.js +0 -3
- package/dist/sync-4jqukkxz.js +0 -2
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { c as init_review_status, f as markWorkspaceStuck, n as clearReviewStatus, p as mergeGateEligibility, s as getReviewStatusSync, u as loadReviewStatuses, y as setReviewStatusSync } from "./review-status-
|
|
1
|
+
import { c as init_review_status, f as markWorkspaceStuck, n as clearReviewStatus, p as mergeGateEligibility, s as getReviewStatusSync, u as loadReviewStatuses, y as setReviewStatusSync } from "./review-status-B5ZASOo4.js";
|
|
2
2
|
init_review_status();
|
|
3
3
|
export { clearReviewStatus, getReviewStatusSync, loadReviewStatuses, markWorkspaceStuck, mergeGateEligibility, setReviewStatusSync };
|
package/dist/dashboard/{review-verdict-feedback-wqnikhMK.js → review-verdict-feedback-B70VbfRL.js}
RENAMED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { n as __esmMin } from "./rolldown-runtime-DNCzzKnI.js";
|
|
2
2
|
import { Gn as resolveProjectFromIssueSync, Nn as init_projects } from "./config-yaml-DPAieL_G.js";
|
|
3
|
-
import { c as init_review_status, s as getReviewStatusSync } from "./review-status-
|
|
4
|
-
import { j as messageAgent, t as init_agents } from "./agents-
|
|
3
|
+
import { c as init_review_status, s as getReviewStatusSync } from "./review-status-B5ZASOo4.js";
|
|
4
|
+
import { j as messageAgent, t as init_agents } from "./agents-C7V4odQ6.js";
|
|
5
5
|
import { a as PAN_DIRNAME, p as init_types } from "./types-CE1m_daD.js";
|
|
6
6
|
import { a as writeFeedbackFile, i as init_feedback_writer } from "./feedback-writer-DMaO0XXa.js";
|
|
7
|
-
import { n as resolveIssueFeedbackTarget, r as surfaceIssueFeedbackNeedsYou, t as init_feedback_target } from "./feedback-target-
|
|
7
|
+
import { n as resolveIssueFeedbackTarget, r as surfaceIssueFeedbackNeedsYou, t as init_feedback_target } from "./feedback-target-dJjFfITP.js";
|
|
8
8
|
import { Effect } from "effect";
|
|
9
9
|
import { existsSync } from "node:fs";
|
|
10
10
|
import { join } from "node:path";
|
|
@@ -144,4 +144,4 @@ var init_review_verdict_feedback = __esmMin((() => {
|
|
|
144
144
|
//#endregion
|
|
145
145
|
export { init_review_verdict_feedback as n, postPrComment as r, deliverReviewVerdictFeedback as t };
|
|
146
146
|
|
|
147
|
-
//# sourceMappingURL=review-verdict-feedback-
|
|
147
|
+
//# sourceMappingURL=review-verdict-feedback-B70VbfRL.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review-verdict-feedback-wqnikhMK.js","names":["stat"],"sources":["../../src/lib/cloister/review-verdict-feedback.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { readdir, readFile, stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { Effect } from 'effect';\n\nimport { messageAgent } from '../agents.js';\nimport { resolveProjectFromIssueSync } from '../projects.js';\nimport { getReviewStatusSync } from '../review-status.js';\nimport { PAN_DIRNAME } from '../pan-dir/types.js';\nimport { writeFeedbackFile } from './feedback-writer.js';\nimport { resolveIssueFeedbackTarget, surfaceIssueFeedbackNeedsYou } from './feedback-target.js';\n\nconst execFileAsync = promisify(execFile);\n\ntype ReviewVerdict = 'blocked' | 'failed';\n\nexport interface DeliverReviewVerdictFeedbackOptions {\n issueId: string;\n verdict: ReviewVerdict;\n notes?: string;\n workspacePath?: string;\n prUrl?: string;\n slotItemId?: string;\n}\n\nexport interface DeliverReviewVerdictFeedbackResult {\n feedbackPath?: string;\n synthesisPath?: string;\n prCommentPosted: boolean;\n agentMessageSent: boolean;\n}\n\nasync function findLatestSynthesis(workspacePath: string): Promise<{ path: string; body: string } | null> {\n const reviewRoot = join(workspacePath, PAN_DIRNAME, 'review');\n if (!existsSync(reviewRoot)) return null;\n\n let latest: { path: string; mtimeMs: number } | null = null;\n const entries = await readdir(reviewRoot, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const synthesisPath = join(reviewRoot, entry.name, 'synthesis.md');\n if (!existsSync(synthesisPath)) continue;\n const fileStat = await stat(synthesisPath);\n if (!latest || fileStat.mtimeMs > latest.mtimeMs) {\n latest = { path: synthesisPath, mtimeMs: fileStat.mtimeMs };\n }\n }\n\n if (!latest) return null;\n return { path: latest.path, body: await readFile(latest.path, 'utf-8') };\n}\n\nfunction parseGitHubPrUrl(prUrl: string | undefined): { owner: string; repo: string; number: string } | null {\n const match = prUrl?.match(/github\\.com\\/([^/]+)\\/([^/]+)\\/pull\\/(\\d+)/);\n if (!match) return null;\n return { owner: match[1]!, repo: match[2]!, number: match[3]! };\n}\n\nfunction buildReviewFeedbackBody(opts: {\n issueId: string;\n verdict: ReviewVerdict;\n notes?: string;\n synthesisBody?: string;\n synthesisPath?: string;\n}): string {\n const verdictLabel = opts.verdict === 'blocked' ? 'CHANGES REQUESTED' : 'FAILED';\n const synthesis = opts.synthesisBody?.trim() || opts.notes?.trim() || 'Review did not provide a synthesis summary.';\n const sourceLine = opts.synthesisPath ? `\\n\\nSource: ${opts.synthesisPath}` : '';\n\n return `# Review ${verdictLabel} for ${opts.issueId}\\n\\n${synthesis}${sourceLine}\\n\\n## Required action\\n\\nFix every blocking review finding, commit the fixes, then re-request review with:\\n\\n\\`pan review request ${opts.issueId} -m \"Fixed review issues\"\\``;\n}\n\n// PAN-2518: the PR-comment POST is advisory — the review verdict is already\n// durable (setReviewStatusSync + writeFeedbackFile) before we get here. A `gh\n// api` call that STALLS (not rejects) on a network hiccup must never block the\n// caller: `pan admin specialists done` is shelled out from the review agent's\n// own session, so a hung POST leaves that agent waiting on a never-returning\n// command and the issue stalls in-review. A bounded timeout turns a stall into\n// a rejection the caller already swallows.\nconst PR_COMMENT_TIMEOUT_MS = 15_000;\n\nexport async function postPrComment(prUrl: string | undefined, body: string): Promise<boolean> {\n const parsed = parseGitHubPrUrl(prUrl);\n if (!parsed) return false;\n\n await execFileAsync(\n 'gh',\n ['api', `repos/${parsed.owner}/${parsed.repo}/issues/${parsed.number}/comments`, '--field', `body=${body}`],\n { encoding: 'utf-8', timeout: PR_COMMENT_TIMEOUT_MS, killSignal: 'SIGKILL' },\n );\n return true;\n}\n\nasync function deliverReviewVerdictFeedbackPromise(\n opts: DeliverReviewVerdictFeedbackOptions,\n): Promise<DeliverReviewVerdictFeedbackResult> {\n const issueId = opts.issueId.toUpperCase();\n const resolved = resolveProjectFromIssueSync(issueId);\n const workspacePath = opts.workspacePath\n ?? (resolved ? join(resolved.projectPath, 'workspaces', `feature-${issueId.toLowerCase()}`) : undefined);\n const existingStatus = getReviewStatusSync(issueId);\n const synthesis = workspacePath && existsSync(workspacePath)\n ? await findLatestSynthesis(workspacePath)\n : null;\n const markdownBody = buildReviewFeedbackBody({\n issueId,\n verdict: opts.verdict,\n notes: opts.notes,\n synthesisBody: synthesis?.body,\n synthesisPath: synthesis?.path,\n });\n\n let prCommentPosted = false;\n try {\n prCommentPosted = await postPrComment(opts.prUrl ?? existingStatus?.prUrl, markdownBody);\n } catch (err) {\n console.warn(`[review-verdict-feedback] Failed to post PR comment for ${issueId}: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n const fileResult = await Effect.runPromise(writeFeedbackFile({\n issueId,\n workspacePath,\n specialist: 'review-agent',\n outcome: opts.verdict === 'blocked' ? 'changes-requested' : 'failed',\n summary: `Review ${opts.verdict.toUpperCase()}: ${(opts.notes ?? synthesis?.body ?? '').slice(0, 80)}`,\n markdownBody,\n }));\n\n let agentMessageSent = false;\n if (fileResult.success && fileResult.filePath) {\n const message = `SPECIALIST FEEDBACK: review-agent reported ${opts.verdict.toUpperCase()} for ${issueId}.\\n\\nMUST READ: ${fileResult.filePath}\\n\\nUse your Read tool to open this file, read every line, then fix ALL review findings. Do NOT stop at the prompt.`;\n try {\n // PAN-2209/PAN-2461: resolveIssueFeedbackTarget's built-in resurrection ladder\n // (unpause pipeline pauses, clear troubled gates, resume stopped agents) handles\n // every non-live target; no local reviver override.\n const target = await resolveIssueFeedbackTarget(issueId, {\n itemId: opts.slotItemId,\n });\n if ('agentId' in target) {\n try {\n await messageAgent(target.agentId, message);\n agentMessageSent = true;\n } catch (err) {\n // PAN-2228: a resolved-but-unreachable target is a real delivery failure,\n // not a shrug. Surface it as needs-you so the stall is visible instead of\n // the issue silently parking with an unread feedback file.\n const reason = err instanceof Error ? err.message : String(err);\n console.warn(`[review-verdict-feedback] Could not message ${target.agentId}; feedback file remains available: ${reason}`);\n try {\n await surfaceIssueFeedbackNeedsYou(issueId, `Feedback delivery to ${target.agentId} failed: ${reason}`, {\n specialist: 'review-agent',\n feedbackPath: fileResult.filePath,\n slotItemId: opts.slotItemId,\n });\n } catch { /* best-effort — the warn above still records the failure */ }\n }\n } else {\n try {\n await surfaceIssueFeedbackNeedsYou(issueId, target.reason, {\n specialist: 'review-agent',\n feedbackPath: fileResult.filePath,\n slotItemId: opts.slotItemId,\n });\n } catch (err) {\n console.warn(`[review-verdict-feedback] Could not mark ${issueId} as needing human attention; feedback file remains available: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n } catch (err) {\n console.warn(`[review-verdict-feedback] Could not resolve a feedback target for ${issueId}; feedback file remains available: ${err instanceof Error ? err.message : String(err)}`);\n }\n } else if (!fileResult.success) {\n console.error(`[review-verdict-feedback] Failed to write feedback file for ${issueId}: ${fileResult.error}`);\n }\n\n return {\n feedbackPath: fileResult.filePath,\n synthesisPath: synthesis?.path,\n prCommentPosted,\n agentMessageSent,\n };\n}\n\n// ─── Effect variant (PAN-1249) ───────────────────────────────────────────────\n\n/**\n * Effect variant of {@link deliverReviewVerdictFeedback}. The Promise version\n * already swallows recoverable errors (PR comment failures, agent messaging,\n * synthesis lookup), so the Effect form mirrors that contract: callers see a\n * successful Effect carrying the same result shape and inspect the flags to\n * decide what surfaced. The single non-recoverable boundary — feedback file\n * write — keeps its existing error reporting through {@link writeFeedbackFile}.\n */\nexport const deliverReviewVerdictFeedback = (\n opts: DeliverReviewVerdictFeedbackOptions,\n): Effect.Effect<DeliverReviewVerdictFeedbackResult> =>\n Effect.promise(() => deliverReviewVerdictFeedbackPromise(opts));\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"review-verdict-feedback-B70VbfRL.js","names":["stat"],"sources":["../../src/lib/cloister/review-verdict-feedback.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { readdir, readFile, stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { Effect } from 'effect';\n\nimport { messageAgent } from '../agents.js';\nimport { resolveProjectFromIssueSync } from '../projects.js';\nimport { getReviewStatusSync } from '../review-status.js';\nimport { PAN_DIRNAME } from '../pan-dir/types.js';\nimport { writeFeedbackFile } from './feedback-writer.js';\nimport { resolveIssueFeedbackTarget, surfaceIssueFeedbackNeedsYou } from './feedback-target.js';\n\nconst execFileAsync = promisify(execFile);\n\ntype ReviewVerdict = 'blocked' | 'failed';\n\nexport interface DeliverReviewVerdictFeedbackOptions {\n issueId: string;\n verdict: ReviewVerdict;\n notes?: string;\n workspacePath?: string;\n prUrl?: string;\n slotItemId?: string;\n}\n\nexport interface DeliverReviewVerdictFeedbackResult {\n feedbackPath?: string;\n synthesisPath?: string;\n prCommentPosted: boolean;\n agentMessageSent: boolean;\n}\n\nasync function findLatestSynthesis(workspacePath: string): Promise<{ path: string; body: string } | null> {\n const reviewRoot = join(workspacePath, PAN_DIRNAME, 'review');\n if (!existsSync(reviewRoot)) return null;\n\n let latest: { path: string; mtimeMs: number } | null = null;\n const entries = await readdir(reviewRoot, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const synthesisPath = join(reviewRoot, entry.name, 'synthesis.md');\n if (!existsSync(synthesisPath)) continue;\n const fileStat = await stat(synthesisPath);\n if (!latest || fileStat.mtimeMs > latest.mtimeMs) {\n latest = { path: synthesisPath, mtimeMs: fileStat.mtimeMs };\n }\n }\n\n if (!latest) return null;\n return { path: latest.path, body: await readFile(latest.path, 'utf-8') };\n}\n\nfunction parseGitHubPrUrl(prUrl: string | undefined): { owner: string; repo: string; number: string } | null {\n const match = prUrl?.match(/github\\.com\\/([^/]+)\\/([^/]+)\\/pull\\/(\\d+)/);\n if (!match) return null;\n return { owner: match[1]!, repo: match[2]!, number: match[3]! };\n}\n\nfunction buildReviewFeedbackBody(opts: {\n issueId: string;\n verdict: ReviewVerdict;\n notes?: string;\n synthesisBody?: string;\n synthesisPath?: string;\n}): string {\n const verdictLabel = opts.verdict === 'blocked' ? 'CHANGES REQUESTED' : 'FAILED';\n const synthesis = opts.synthesisBody?.trim() || opts.notes?.trim() || 'Review did not provide a synthesis summary.';\n const sourceLine = opts.synthesisPath ? `\\n\\nSource: ${opts.synthesisPath}` : '';\n\n return `# Review ${verdictLabel} for ${opts.issueId}\\n\\n${synthesis}${sourceLine}\\n\\n## Required action\\n\\nFix every blocking review finding, commit the fixes, then re-request review with:\\n\\n\\`pan review request ${opts.issueId} -m \"Fixed review issues\"\\``;\n}\n\n// PAN-2518: the PR-comment POST is advisory — the review verdict is already\n// durable (setReviewStatusSync + writeFeedbackFile) before we get here. A `gh\n// api` call that STALLS (not rejects) on a network hiccup must never block the\n// caller: `pan admin specialists done` is shelled out from the review agent's\n// own session, so a hung POST leaves that agent waiting on a never-returning\n// command and the issue stalls in-review. A bounded timeout turns a stall into\n// a rejection the caller already swallows.\nconst PR_COMMENT_TIMEOUT_MS = 15_000;\n\nexport async function postPrComment(prUrl: string | undefined, body: string): Promise<boolean> {\n const parsed = parseGitHubPrUrl(prUrl);\n if (!parsed) return false;\n\n await execFileAsync(\n 'gh',\n ['api', `repos/${parsed.owner}/${parsed.repo}/issues/${parsed.number}/comments`, '--field', `body=${body}`],\n { encoding: 'utf-8', timeout: PR_COMMENT_TIMEOUT_MS, killSignal: 'SIGKILL' },\n );\n return true;\n}\n\nasync function deliverReviewVerdictFeedbackPromise(\n opts: DeliverReviewVerdictFeedbackOptions,\n): Promise<DeliverReviewVerdictFeedbackResult> {\n const issueId = opts.issueId.toUpperCase();\n const resolved = resolveProjectFromIssueSync(issueId);\n const workspacePath = opts.workspacePath\n ?? (resolved ? join(resolved.projectPath, 'workspaces', `feature-${issueId.toLowerCase()}`) : undefined);\n const existingStatus = getReviewStatusSync(issueId);\n const synthesis = workspacePath && existsSync(workspacePath)\n ? await findLatestSynthesis(workspacePath)\n : null;\n const markdownBody = buildReviewFeedbackBody({\n issueId,\n verdict: opts.verdict,\n notes: opts.notes,\n synthesisBody: synthesis?.body,\n synthesisPath: synthesis?.path,\n });\n\n let prCommentPosted = false;\n try {\n prCommentPosted = await postPrComment(opts.prUrl ?? existingStatus?.prUrl, markdownBody);\n } catch (err) {\n console.warn(`[review-verdict-feedback] Failed to post PR comment for ${issueId}: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n const fileResult = await Effect.runPromise(writeFeedbackFile({\n issueId,\n workspacePath,\n specialist: 'review-agent',\n outcome: opts.verdict === 'blocked' ? 'changes-requested' : 'failed',\n summary: `Review ${opts.verdict.toUpperCase()}: ${(opts.notes ?? synthesis?.body ?? '').slice(0, 80)}`,\n markdownBody,\n }));\n\n let agentMessageSent = false;\n if (fileResult.success && fileResult.filePath) {\n const message = `SPECIALIST FEEDBACK: review-agent reported ${opts.verdict.toUpperCase()} for ${issueId}.\\n\\nMUST READ: ${fileResult.filePath}\\n\\nUse your Read tool to open this file, read every line, then fix ALL review findings. Do NOT stop at the prompt.`;\n try {\n // PAN-2209/PAN-2461: resolveIssueFeedbackTarget's built-in resurrection ladder\n // (unpause pipeline pauses, clear troubled gates, resume stopped agents) handles\n // every non-live target; no local reviver override.\n const target = await resolveIssueFeedbackTarget(issueId, {\n itemId: opts.slotItemId,\n });\n if ('agentId' in target) {\n try {\n await messageAgent(target.agentId, message);\n agentMessageSent = true;\n } catch (err) {\n // PAN-2228: a resolved-but-unreachable target is a real delivery failure,\n // not a shrug. Surface it as needs-you so the stall is visible instead of\n // the issue silently parking with an unread feedback file.\n const reason = err instanceof Error ? err.message : String(err);\n console.warn(`[review-verdict-feedback] Could not message ${target.agentId}; feedback file remains available: ${reason}`);\n try {\n await surfaceIssueFeedbackNeedsYou(issueId, `Feedback delivery to ${target.agentId} failed: ${reason}`, {\n specialist: 'review-agent',\n feedbackPath: fileResult.filePath,\n slotItemId: opts.slotItemId,\n });\n } catch { /* best-effort — the warn above still records the failure */ }\n }\n } else {\n try {\n await surfaceIssueFeedbackNeedsYou(issueId, target.reason, {\n specialist: 'review-agent',\n feedbackPath: fileResult.filePath,\n slotItemId: opts.slotItemId,\n });\n } catch (err) {\n console.warn(`[review-verdict-feedback] Could not mark ${issueId} as needing human attention; feedback file remains available: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n } catch (err) {\n console.warn(`[review-verdict-feedback] Could not resolve a feedback target for ${issueId}; feedback file remains available: ${err instanceof Error ? err.message : String(err)}`);\n }\n } else if (!fileResult.success) {\n console.error(`[review-verdict-feedback] Failed to write feedback file for ${issueId}: ${fileResult.error}`);\n }\n\n return {\n feedbackPath: fileResult.filePath,\n synthesisPath: synthesis?.path,\n prCommentPosted,\n agentMessageSent,\n };\n}\n\n// ─── Effect variant (PAN-1249) ───────────────────────────────────────────────\n\n/**\n * Effect variant of {@link deliverReviewVerdictFeedback}. The Promise version\n * already swallows recoverable errors (PR comment failures, agent messaging,\n * synthesis lookup), so the Effect form mirrors that contract: callers see a\n * successful Effect carrying the same result shape and inspect the flags to\n * decide what surfaced. The single non-recoverable boundary — feedback file\n * write — keeps its existing error reporting through {@link writeFeedbackFile}.\n */\nexport const deliverReviewVerdictFeedback = (\n opts: DeliverReviewVerdictFeedbackOptions,\n): Effect.Effect<DeliverReviewVerdictFeedbackResult> =>\n Effect.promise(() => deliverReviewVerdictFeedbackPromise(opts));\n"],"mappings":"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"}
|
package/dist/dashboard/{review-verdict-feedback-cZh9Wi9G.js → review-verdict-feedback-CorgH49f.js}
RENAMED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as init_review_verdict_feedback, t as deliverReviewVerdictFeedback } from "./review-verdict-feedback-
|
|
1
|
+
import { n as init_review_verdict_feedback, t as deliverReviewVerdictFeedback } from "./review-verdict-feedback-B70VbfRL.js";
|
|
2
2
|
init_review_verdict_feedback();
|
|
3
3
|
export { deliverReviewVerdictFeedback };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __esmMin } from "./rolldown-runtime-DNCzzKnI.js";
|
|
2
2
|
import { in as queueAutoCommit, rn as init_auto_commit } from "./config-yaml-DPAieL_G.js";
|
|
3
|
-
import { c as init_review_status, s as getReviewStatusSync } from "./review-status-
|
|
3
|
+
import { c as init_review_status, s as getReviewStatusSync } from "./review-status-B5ZASOo4.js";
|
|
4
4
|
import { T as init_specs, w as getProjectPanPaths } from "./io-Wy8YpFeP.js";
|
|
5
5
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { dirname, join } from "node:path";
|
|
@@ -275,4 +275,4 @@ var init_sequence_io = __esmMin((() => {
|
|
|
275
275
|
//#endregion
|
|
276
276
|
export { parseSequenceMd as n, writeSequenceMd as r, init_sequence_io as t };
|
|
277
277
|
|
|
278
|
-
//# sourceMappingURL=sequence-io-
|
|
278
|
+
//# sourceMappingURL=sequence-io-6YP8fVpH.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequence-io-B2GmilSI.js","names":[],"sources":["../../src/lib/backlog/types.ts","../../src/lib/backlog/sequence-io.ts"],"sourcesContent":["export type NodeSize = 'XS' | 'S' | 'M' | 'L' | 'XL';\nexport type NodeImportance = 'critical' | 'high' | 'medium' | 'low';\nexport type NodeCondition = 'ok' | 'needs-refinement' | 'stale';\nexport type NodeGate = 'auto' | 'ready' | 'blocked';\nexport type NodePlanning = 'skip' | 'auto' | 'interactive';\nexport type EdgeType = 'unblocks' | 'informs' | 'contains';\nexport type EdgeSource = 'github-ref' | 'operator' | 'ai-inferred';\nexport type PassMode = 'creation' | 'incremental' | 'review';\n\nexport type SequenceNode = {\n issue: string;\n rank: number;\n size: NodeSize;\n importance: NodeImportance;\n score: number;\n condition: NodeCondition;\n dependsOn: string[];\n why: string;\n rationale?: string;\n gate: NodeGate;\n planning: NodePlanning;\n /**\n * True when this issue is an epic (a container of child issues), not directly\n * workable. Epics are excluded from the auto-pickable queue; their children\n * carry the work. Membership is expressed via `contains` edges (epic → child).\n */\n isEpic?: boolean;\n};\n\nexport type SequenceEdge = {\n from: string;\n to: string;\n type: EdgeType;\n source: EdgeSource;\n confidence: number;\n};\n\nexport type SequenceDoc = {\n version: number;\n project: string;\n generatedAt: string;\n model: string;\n pass: PassMode;\n lastReviewPass?: string;\n openCount: number;\n nodes: SequenceNode[];\n edges: SequenceEdge[];\n};\n\nexport type SequenceParseError = { ok: false; error: string };\nexport type SequenceParseResult = { ok: true; doc: SequenceDoc } | SequenceParseError;\n\nconst NODE_SIZES = new Set<string>(['XS', 'S', 'M', 'L', 'XL']);\nconst NODE_IMPORTANCES = new Set<string>(['critical', 'high', 'medium', 'low']);\nconst NODE_CONDITIONS = new Set<string>(['ok', 'needs-refinement', 'stale']);\nconst NODE_GATES = new Set<string>(['auto', 'ready', 'blocked']);\nconst NODE_PLANNINGS = new Set<string>(['skip', 'auto', 'interactive']);\nconst EDGE_TYPES = new Set<string>(['unblocks', 'informs', 'contains']);\nconst EDGE_SOURCES = new Set<string>(['github-ref', 'operator', 'ai-inferred']);\nconst PASS_MODES = new Set<string>(['creation', 'incremental', 'review']);\n\nfunction err(msg: string): SequenceParseError {\n return { ok: false, error: msg };\n}\n\nfunction validateNode(n: Record<string, unknown>, i: number): { ok: true; node: SequenceNode } | SequenceParseError {\n if (typeof n.issue !== 'string' || !n.issue) return err(`nodes[${i}].issue missing`);\n if (typeof n.rank !== 'number') return err(`nodes[${i}].rank missing`);\n if (typeof n.size !== 'string' || !NODE_SIZES.has(n.size)) return err(`nodes[${i}].size invalid: ${n.size}`);\n if (typeof n.importance !== 'string' || !NODE_IMPORTANCES.has(n.importance)) return err(`nodes[${i}].importance invalid: ${n.importance}`);\n if (typeof n.score !== 'number' || n.score < 0 || n.score > 100) return err(`nodes[${i}].score must be 0-100: ${n.score}`);\n if (typeof n.condition !== 'string' || !NODE_CONDITIONS.has(n.condition)) return err(`nodes[${i}].condition invalid: ${n.condition}`);\n if (!Array.isArray(n.dependsOn) || !n.dependsOn.every((d) => typeof d === 'string')) return err(`nodes[${i}].dependsOn must be string[]`);\n if (typeof n.why !== 'string') return err(`nodes[${i}].why missing`);\n if (n.why.length > 140) return err(`nodes[${i}].why exceeds 140 chars`);\n if (typeof n.gate !== 'string' || !NODE_GATES.has(n.gate)) return err(`nodes[${i}].gate invalid: ${n.gate}`);\n if (typeof n.planning !== 'string' || !NODE_PLANNINGS.has(n.planning)) return err(`nodes[${i}].planning invalid: ${n.planning}`);\n if (n.rationale !== undefined && typeof n.rationale !== 'string') return err(`nodes[${i}].rationale must be string`);\n if (n.isEpic !== undefined && typeof n.isEpic !== 'boolean') return err(`nodes[${i}].isEpic must be boolean`);\n return {\n ok: true,\n node: {\n issue: n.issue,\n rank: n.rank,\n size: n.size as NodeSize,\n importance: n.importance as NodeImportance,\n score: n.score,\n condition: n.condition as NodeCondition,\n dependsOn: n.dependsOn as string[],\n why: n.why,\n rationale: n.rationale as string | undefined,\n gate: n.gate as NodeGate,\n planning: n.planning as NodePlanning,\n isEpic: typeof n.isEpic === 'boolean' ? n.isEpic : undefined,\n },\n };\n}\n\nfunction validateEdge(e: Record<string, unknown>, i: number): { ok: true; edge: SequenceEdge } | SequenceParseError {\n if (typeof e.from !== 'string') return err(`edges[${i}].from missing`);\n if (typeof e.to !== 'string') return err(`edges[${i}].to missing`);\n if (typeof e.type !== 'string' || !EDGE_TYPES.has(e.type)) return err(`edges[${i}].type invalid: ${e.type}`);\n if (typeof e.source !== 'string' || !EDGE_SOURCES.has(e.source)) return err(`edges[${i}].source invalid: ${e.source}`);\n if (typeof e.confidence !== 'number' || e.confidence < 0 || e.confidence > 1) return err(`edges[${i}].confidence must be 0-1: ${e.confidence}`);\n return { ok: true, edge: { from: e.from, to: e.to, type: e.type as EdgeType, source: e.source as EdgeSource, confidence: e.confidence } };\n}\n\nexport function parseSequenceJson(value: unknown): SequenceParseResult {\n if (typeof value !== 'object' || value === null) return err('value must be an object');\n const v = value as Record<string, unknown>;\n\n if (typeof v.version !== 'number') return err('version missing');\n if (typeof v.project !== 'string') return err('project missing');\n if (typeof v.generatedAt !== 'string') return err('generatedAt missing');\n if (typeof v.model !== 'string') return err('model missing');\n if (typeof v.pass !== 'string' || !PASS_MODES.has(v.pass)) return err(`pass invalid: ${v.pass}`);\n if (typeof v.openCount !== 'number') return err('openCount missing');\n if (!Array.isArray(v.nodes)) return err('nodes must be an array');\n if (!Array.isArray(v.edges)) return err('edges must be an array');\n\n const nodes: SequenceNode[] = [];\n for (let i = 0; i < v.nodes.length; i++) {\n const result = validateNode(v.nodes[i] as Record<string, unknown>, i);\n if (!result.ok) return result;\n nodes.push(result.node);\n }\n\n const edges: SequenceEdge[] = [];\n for (let i = 0; i < v.edges.length; i++) {\n const result = validateEdge(v.edges[i] as Record<string, unknown>, i);\n if (!result.ok) return result;\n edges.push(result.edge);\n }\n\n return {\n ok: true,\n doc: {\n version: v.version,\n project: v.project,\n generatedAt: v.generatedAt,\n model: v.model,\n pass: v.pass as PassMode,\n lastReviewPass: typeof v.lastReviewPass === 'string' ? v.lastReviewPass : undefined,\n openCount: v.openCount,\n nodes,\n edges,\n },\n };\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { parseSequenceJson } from './types.js';\nimport type { SequenceDoc, SequenceEdge, SequenceNode, SequenceParseError } from './types.js';\nimport { queueAutoCommit } from '../pan-dir/auto-commit.js';\nimport { getReviewStatusSync } from '../review-status.js';\nimport { getProjectPanPaths } from '../pan-dir/specs.js';\n\nconst MACHINE_MARKER = '<!-- machine-readable; do not hand-edit below this line -->';\nconst TOP_TIER_SIZE = 80;\nfunction sequencePath(projectRoot: string): string {\n return join(getProjectPanPaths(projectRoot).panDir, 'backlog', 'sequence.md');\n}\n\nexport type ParseSequenceMdResult = { ok: true; doc: SequenceDoc } | SequenceParseError;\n\nexport function parseSequenceMd(markdown: string): ParseSequenceMdResult {\n const markerIdx = markdown.indexOf(MACHINE_MARKER);\n const searchText = markerIdx >= 0 ? markdown.slice(markerIdx) : markdown;\n\n const fenceMatch = searchText.match(/```json\\s*\\n([\\s\\S]*?)```/);\n if (!fenceMatch) {\n return { ok: false, error: 'No fenced JSON block found in sequence.md' };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(fenceMatch[1]);\n } catch (e) {\n return { ok: false, error: `JSON parse failed: ${e instanceof Error ? e.message : String(e)}` };\n }\n\n return parseSequenceJson(parsed);\n}\n\nfunction renderTable(nodes: SequenceNode[]): string {\n const header = '| rank | issue | size | importance | condition | epic | depends-on | why |';\n const sep = '|------|-------|------|------------|-----------|------|------------|-----|';\n const rows = nodes.map((n) =>\n `| ${n.rank} | ${n.issue} | ${n.size} | ${n.importance} | ${n.condition} | ${n.isEpic ? '✓' : ''} | ${n.dependsOn.join(', ')} | ${n.why} |`\n );\n return [header, sep, ...rows].join('\\n');\n}\n\nfunction renderRationaleSection(nodes: SequenceNode[]): string {\n const topTier = nodes.slice(0, TOP_TIER_SIZE).filter((n) => n.rationale);\n if (topTier.length === 0) return '';\n const lines = ['## Rationale detail', ''];\n for (const n of topTier) {\n lines.push(`### ${n.issue} (rank ${n.rank})`, '', n.rationale!, '');\n }\n return lines.join('\\n');\n}\n\nexport interface WriteSequenceMdOpts {\n /**\n * Set to true when the caller is an operator-facing route that has already\n * applied the intended field value to the doc. Skips the prior-file\n * preservation step so operators can reset gate/planning back to 'auto'.\n *\n * When false/absent (AI resequence path), prior non-'auto' operator fields\n * and in-pipeline ranks are carried forward from the on-disk file (FR-13,\n * FR-15, FR-16, FR-17).\n */\n operatorEdit?: boolean;\n}\n\n/**\n * Write sequence.md, merging operator-owned state from the prior file.\n *\n * Merge rules for AI resequence (operatorEdit absent/false):\n * - gate !== 'auto' in prior → carry forward (operator-set)\n * - planning !== 'auto' in prior → carry forward (operator-set)\n * - in-pipeline issues (live workspace or non-pending review) → carry forward rank/why/rationale\n * - edges with source === 'operator' in prior → always preserved verbatim\n *\n * For explicit operator edits (operatorEdit: true), the doc already contains\n * the correct operator-intended value; prior-preservation is skipped entirely.\n */\nexport function writeSequenceMd(projectRoot: string, doc: SequenceDoc, opts?: WriteSequenceMdOpts): void {\n const outPath = sequencePath(projectRoot);\n\n // Load prior sequence for merge-preservation (AI resequence path only)\n let priorNodeMap = new Map<string, SequenceNode>();\n let priorOperatorEdges: SequenceEdge[] = [];\n if (!opts?.operatorEdit && existsSync(outPath)) {\n const priorText = readFileSync(outPath, 'utf-8');\n const prior = parseSequenceMd(priorText);\n if (prior.ok) {\n priorNodeMap = new Map(prior.doc.nodes.map((n) => [n.issue, n]));\n priorOperatorEdges = prior.doc.edges.filter((e) => e.source === 'operator');\n }\n }\n\n // Detect in-pipeline (pinned) issues: live workspace dir OR non-pending review status\n const workspacesDir = join(projectRoot, 'workspaces');\n const isPinned = (issueId: string): boolean => {\n const rs = getReviewStatusSync(issueId.toUpperCase());\n if (rs && rs.reviewStatus !== 'pending') return true;\n return existsSync(join(workspacesDir, `feature-${issueId.toLowerCase()}`));\n };\n\n // Merge operator-owned fields into each node\n const mergedNodes: SequenceNode[] = doc.nodes.map((node) => {\n const prior = priorNodeMap.get(node.issue);\n if (!prior) return node;\n // Preserve operator-set gate and planning\n const gate = prior.gate !== 'auto' ? prior.gate : node.gate;\n const planning = prior.planning !== 'auto' ? prior.planning : node.planning;\n // Preserve rank/why/rationale for pinned (in-pipeline) issues\n if (isPinned(node.issue)) {\n return { ...node, gate, planning, rank: prior.rank, why: prior.why, rationale: prior.rationale };\n }\n return { ...node, gate, planning };\n });\n\n // Merge operator edges: union of prior operator edges and current doc's operator edges\n // (prior ones are kept even if the sequencer dropped them; new ones from doc are added).\n const currentOperatorEdges = doc.edges.filter((e) => e.source === 'operator');\n const currentNonOperatorEdges = doc.edges.filter((e) => e.source !== 'operator');\n const operatorEdgeKeys = new Set<string>();\n const mergedOperatorEdges: SequenceEdge[] = [];\n for (const edge of [...priorOperatorEdges, ...currentOperatorEdges]) {\n const key = `${edge.from}→${edge.to}→${edge.type}`;\n if (!operatorEdgeKeys.has(key)) {\n operatorEdgeKeys.add(key);\n mergedOperatorEdges.push(edge);\n }\n }\n const mergedEdges: SequenceEdge[] = [...mergedOperatorEdges, ...currentNonOperatorEdges];\n\n const mergedDoc: SequenceDoc = { ...doc, nodes: mergedNodes, edges: mergedEdges };\n const sortedNodes = [...mergedDoc.nodes].sort((a, b) => a.rank - b.rank);\n const ts = mergedDoc.generatedAt;\n const header = `# Backlog Sequence\\n\\n_Last sequenced: ${ts} · model: ${mergedDoc.model} · open: ${mergedDoc.openCount}_\\n`;\n const table = renderTable(sortedNodes);\n const rationale = renderRationaleSection(sortedNodes);\n const machineBlock = `${MACHINE_MARKER}\\n\\n\\`\\`\\`json\\n${JSON.stringify(mergedDoc, null, 2)}\\n\\`\\`\\`\\n`;\n\n const parts = [header, table];\n if (rationale) parts.push(rationale);\n parts.push(machineBlock);\n\n const content = parts.join('\\n\\n');\n mkdirSync(dirname(outPath), { recursive: true });\n writeFileSync(outPath, content, 'utf-8');\n\n queueAutoCommit({\n projectRoot,\n paths: [outPath],\n subject: `chore(state): update backlog sequence (${doc.project})`,\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sequence-io-6YP8fVpH.js","names":[],"sources":["../../src/lib/backlog/types.ts","../../src/lib/backlog/sequence-io.ts"],"sourcesContent":["export type NodeSize = 'XS' | 'S' | 'M' | 'L' | 'XL';\nexport type NodeImportance = 'critical' | 'high' | 'medium' | 'low';\nexport type NodeCondition = 'ok' | 'needs-refinement' | 'stale';\nexport type NodeGate = 'auto' | 'ready' | 'blocked';\nexport type NodePlanning = 'skip' | 'auto' | 'interactive';\nexport type EdgeType = 'unblocks' | 'informs' | 'contains';\nexport type EdgeSource = 'github-ref' | 'operator' | 'ai-inferred';\nexport type PassMode = 'creation' | 'incremental' | 'review';\n\nexport type SequenceNode = {\n issue: string;\n rank: number;\n size: NodeSize;\n importance: NodeImportance;\n score: number;\n condition: NodeCondition;\n dependsOn: string[];\n why: string;\n rationale?: string;\n gate: NodeGate;\n planning: NodePlanning;\n /**\n * True when this issue is an epic (a container of child issues), not directly\n * workable. Epics are excluded from the auto-pickable queue; their children\n * carry the work. Membership is expressed via `contains` edges (epic → child).\n */\n isEpic?: boolean;\n};\n\nexport type SequenceEdge = {\n from: string;\n to: string;\n type: EdgeType;\n source: EdgeSource;\n confidence: number;\n};\n\nexport type SequenceDoc = {\n version: number;\n project: string;\n generatedAt: string;\n model: string;\n pass: PassMode;\n lastReviewPass?: string;\n openCount: number;\n nodes: SequenceNode[];\n edges: SequenceEdge[];\n};\n\nexport type SequenceParseError = { ok: false; error: string };\nexport type SequenceParseResult = { ok: true; doc: SequenceDoc } | SequenceParseError;\n\nconst NODE_SIZES = new Set<string>(['XS', 'S', 'M', 'L', 'XL']);\nconst NODE_IMPORTANCES = new Set<string>(['critical', 'high', 'medium', 'low']);\nconst NODE_CONDITIONS = new Set<string>(['ok', 'needs-refinement', 'stale']);\nconst NODE_GATES = new Set<string>(['auto', 'ready', 'blocked']);\nconst NODE_PLANNINGS = new Set<string>(['skip', 'auto', 'interactive']);\nconst EDGE_TYPES = new Set<string>(['unblocks', 'informs', 'contains']);\nconst EDGE_SOURCES = new Set<string>(['github-ref', 'operator', 'ai-inferred']);\nconst PASS_MODES = new Set<string>(['creation', 'incremental', 'review']);\n\nfunction err(msg: string): SequenceParseError {\n return { ok: false, error: msg };\n}\n\nfunction validateNode(n: Record<string, unknown>, i: number): { ok: true; node: SequenceNode } | SequenceParseError {\n if (typeof n.issue !== 'string' || !n.issue) return err(`nodes[${i}].issue missing`);\n if (typeof n.rank !== 'number') return err(`nodes[${i}].rank missing`);\n if (typeof n.size !== 'string' || !NODE_SIZES.has(n.size)) return err(`nodes[${i}].size invalid: ${n.size}`);\n if (typeof n.importance !== 'string' || !NODE_IMPORTANCES.has(n.importance)) return err(`nodes[${i}].importance invalid: ${n.importance}`);\n if (typeof n.score !== 'number' || n.score < 0 || n.score > 100) return err(`nodes[${i}].score must be 0-100: ${n.score}`);\n if (typeof n.condition !== 'string' || !NODE_CONDITIONS.has(n.condition)) return err(`nodes[${i}].condition invalid: ${n.condition}`);\n if (!Array.isArray(n.dependsOn) || !n.dependsOn.every((d) => typeof d === 'string')) return err(`nodes[${i}].dependsOn must be string[]`);\n if (typeof n.why !== 'string') return err(`nodes[${i}].why missing`);\n if (n.why.length > 140) return err(`nodes[${i}].why exceeds 140 chars`);\n if (typeof n.gate !== 'string' || !NODE_GATES.has(n.gate)) return err(`nodes[${i}].gate invalid: ${n.gate}`);\n if (typeof n.planning !== 'string' || !NODE_PLANNINGS.has(n.planning)) return err(`nodes[${i}].planning invalid: ${n.planning}`);\n if (n.rationale !== undefined && typeof n.rationale !== 'string') return err(`nodes[${i}].rationale must be string`);\n if (n.isEpic !== undefined && typeof n.isEpic !== 'boolean') return err(`nodes[${i}].isEpic must be boolean`);\n return {\n ok: true,\n node: {\n issue: n.issue,\n rank: n.rank,\n size: n.size as NodeSize,\n importance: n.importance as NodeImportance,\n score: n.score,\n condition: n.condition as NodeCondition,\n dependsOn: n.dependsOn as string[],\n why: n.why,\n rationale: n.rationale as string | undefined,\n gate: n.gate as NodeGate,\n planning: n.planning as NodePlanning,\n isEpic: typeof n.isEpic === 'boolean' ? n.isEpic : undefined,\n },\n };\n}\n\nfunction validateEdge(e: Record<string, unknown>, i: number): { ok: true; edge: SequenceEdge } | SequenceParseError {\n if (typeof e.from !== 'string') return err(`edges[${i}].from missing`);\n if (typeof e.to !== 'string') return err(`edges[${i}].to missing`);\n if (typeof e.type !== 'string' || !EDGE_TYPES.has(e.type)) return err(`edges[${i}].type invalid: ${e.type}`);\n if (typeof e.source !== 'string' || !EDGE_SOURCES.has(e.source)) return err(`edges[${i}].source invalid: ${e.source}`);\n if (typeof e.confidence !== 'number' || e.confidence < 0 || e.confidence > 1) return err(`edges[${i}].confidence must be 0-1: ${e.confidence}`);\n return { ok: true, edge: { from: e.from, to: e.to, type: e.type as EdgeType, source: e.source as EdgeSource, confidence: e.confidence } };\n}\n\nexport function parseSequenceJson(value: unknown): SequenceParseResult {\n if (typeof value !== 'object' || value === null) return err('value must be an object');\n const v = value as Record<string, unknown>;\n\n if (typeof v.version !== 'number') return err('version missing');\n if (typeof v.project !== 'string') return err('project missing');\n if (typeof v.generatedAt !== 'string') return err('generatedAt missing');\n if (typeof v.model !== 'string') return err('model missing');\n if (typeof v.pass !== 'string' || !PASS_MODES.has(v.pass)) return err(`pass invalid: ${v.pass}`);\n if (typeof v.openCount !== 'number') return err('openCount missing');\n if (!Array.isArray(v.nodes)) return err('nodes must be an array');\n if (!Array.isArray(v.edges)) return err('edges must be an array');\n\n const nodes: SequenceNode[] = [];\n for (let i = 0; i < v.nodes.length; i++) {\n const result = validateNode(v.nodes[i] as Record<string, unknown>, i);\n if (!result.ok) return result;\n nodes.push(result.node);\n }\n\n const edges: SequenceEdge[] = [];\n for (let i = 0; i < v.edges.length; i++) {\n const result = validateEdge(v.edges[i] as Record<string, unknown>, i);\n if (!result.ok) return result;\n edges.push(result.edge);\n }\n\n return {\n ok: true,\n doc: {\n version: v.version,\n project: v.project,\n generatedAt: v.generatedAt,\n model: v.model,\n pass: v.pass as PassMode,\n lastReviewPass: typeof v.lastReviewPass === 'string' ? v.lastReviewPass : undefined,\n openCount: v.openCount,\n nodes,\n edges,\n },\n };\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { parseSequenceJson } from './types.js';\nimport type { SequenceDoc, SequenceEdge, SequenceNode, SequenceParseError } from './types.js';\nimport { queueAutoCommit } from '../pan-dir/auto-commit.js';\nimport { getReviewStatusSync } from '../review-status.js';\nimport { getProjectPanPaths } from '../pan-dir/specs.js';\n\nconst MACHINE_MARKER = '<!-- machine-readable; do not hand-edit below this line -->';\nconst TOP_TIER_SIZE = 80;\nfunction sequencePath(projectRoot: string): string {\n return join(getProjectPanPaths(projectRoot).panDir, 'backlog', 'sequence.md');\n}\n\nexport type ParseSequenceMdResult = { ok: true; doc: SequenceDoc } | SequenceParseError;\n\nexport function parseSequenceMd(markdown: string): ParseSequenceMdResult {\n const markerIdx = markdown.indexOf(MACHINE_MARKER);\n const searchText = markerIdx >= 0 ? markdown.slice(markerIdx) : markdown;\n\n const fenceMatch = searchText.match(/```json\\s*\\n([\\s\\S]*?)```/);\n if (!fenceMatch) {\n return { ok: false, error: 'No fenced JSON block found in sequence.md' };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(fenceMatch[1]);\n } catch (e) {\n return { ok: false, error: `JSON parse failed: ${e instanceof Error ? e.message : String(e)}` };\n }\n\n return parseSequenceJson(parsed);\n}\n\nfunction renderTable(nodes: SequenceNode[]): string {\n const header = '| rank | issue | size | importance | condition | epic | depends-on | why |';\n const sep = '|------|-------|------|------------|-----------|------|------------|-----|';\n const rows = nodes.map((n) =>\n `| ${n.rank} | ${n.issue} | ${n.size} | ${n.importance} | ${n.condition} | ${n.isEpic ? '✓' : ''} | ${n.dependsOn.join(', ')} | ${n.why} |`\n );\n return [header, sep, ...rows].join('\\n');\n}\n\nfunction renderRationaleSection(nodes: SequenceNode[]): string {\n const topTier = nodes.slice(0, TOP_TIER_SIZE).filter((n) => n.rationale);\n if (topTier.length === 0) return '';\n const lines = ['## Rationale detail', ''];\n for (const n of topTier) {\n lines.push(`### ${n.issue} (rank ${n.rank})`, '', n.rationale!, '');\n }\n return lines.join('\\n');\n}\n\nexport interface WriteSequenceMdOpts {\n /**\n * Set to true when the caller is an operator-facing route that has already\n * applied the intended field value to the doc. Skips the prior-file\n * preservation step so operators can reset gate/planning back to 'auto'.\n *\n * When false/absent (AI resequence path), prior non-'auto' operator fields\n * and in-pipeline ranks are carried forward from the on-disk file (FR-13,\n * FR-15, FR-16, FR-17).\n */\n operatorEdit?: boolean;\n}\n\n/**\n * Write sequence.md, merging operator-owned state from the prior file.\n *\n * Merge rules for AI resequence (operatorEdit absent/false):\n * - gate !== 'auto' in prior → carry forward (operator-set)\n * - planning !== 'auto' in prior → carry forward (operator-set)\n * - in-pipeline issues (live workspace or non-pending review) → carry forward rank/why/rationale\n * - edges with source === 'operator' in prior → always preserved verbatim\n *\n * For explicit operator edits (operatorEdit: true), the doc already contains\n * the correct operator-intended value; prior-preservation is skipped entirely.\n */\nexport function writeSequenceMd(projectRoot: string, doc: SequenceDoc, opts?: WriteSequenceMdOpts): void {\n const outPath = sequencePath(projectRoot);\n\n // Load prior sequence for merge-preservation (AI resequence path only)\n let priorNodeMap = new Map<string, SequenceNode>();\n let priorOperatorEdges: SequenceEdge[] = [];\n if (!opts?.operatorEdit && existsSync(outPath)) {\n const priorText = readFileSync(outPath, 'utf-8');\n const prior = parseSequenceMd(priorText);\n if (prior.ok) {\n priorNodeMap = new Map(prior.doc.nodes.map((n) => [n.issue, n]));\n priorOperatorEdges = prior.doc.edges.filter((e) => e.source === 'operator');\n }\n }\n\n // Detect in-pipeline (pinned) issues: live workspace dir OR non-pending review status\n const workspacesDir = join(projectRoot, 'workspaces');\n const isPinned = (issueId: string): boolean => {\n const rs = getReviewStatusSync(issueId.toUpperCase());\n if (rs && rs.reviewStatus !== 'pending') return true;\n return existsSync(join(workspacesDir, `feature-${issueId.toLowerCase()}`));\n };\n\n // Merge operator-owned fields into each node\n const mergedNodes: SequenceNode[] = doc.nodes.map((node) => {\n const prior = priorNodeMap.get(node.issue);\n if (!prior) return node;\n // Preserve operator-set gate and planning\n const gate = prior.gate !== 'auto' ? prior.gate : node.gate;\n const planning = prior.planning !== 'auto' ? prior.planning : node.planning;\n // Preserve rank/why/rationale for pinned (in-pipeline) issues\n if (isPinned(node.issue)) {\n return { ...node, gate, planning, rank: prior.rank, why: prior.why, rationale: prior.rationale };\n }\n return { ...node, gate, planning };\n });\n\n // Merge operator edges: union of prior operator edges and current doc's operator edges\n // (prior ones are kept even if the sequencer dropped them; new ones from doc are added).\n const currentOperatorEdges = doc.edges.filter((e) => e.source === 'operator');\n const currentNonOperatorEdges = doc.edges.filter((e) => e.source !== 'operator');\n const operatorEdgeKeys = new Set<string>();\n const mergedOperatorEdges: SequenceEdge[] = [];\n for (const edge of [...priorOperatorEdges, ...currentOperatorEdges]) {\n const key = `${edge.from}→${edge.to}→${edge.type}`;\n if (!operatorEdgeKeys.has(key)) {\n operatorEdgeKeys.add(key);\n mergedOperatorEdges.push(edge);\n }\n }\n const mergedEdges: SequenceEdge[] = [...mergedOperatorEdges, ...currentNonOperatorEdges];\n\n const mergedDoc: SequenceDoc = { ...doc, nodes: mergedNodes, edges: mergedEdges };\n const sortedNodes = [...mergedDoc.nodes].sort((a, b) => a.rank - b.rank);\n const ts = mergedDoc.generatedAt;\n const header = `# Backlog Sequence\\n\\n_Last sequenced: ${ts} · model: ${mergedDoc.model} · open: ${mergedDoc.openCount}_\\n`;\n const table = renderTable(sortedNodes);\n const rationale = renderRationaleSection(sortedNodes);\n const machineBlock = `${MACHINE_MARKER}\\n\\n\\`\\`\\`json\\n${JSON.stringify(mergedDoc, null, 2)}\\n\\`\\`\\`\\n`;\n\n const parts = [header, table];\n if (rationale) parts.push(rationale);\n parts.push(machineBlock);\n\n const content = parts.join('\\n\\n');\n mkdirSync(dirname(outPath), { recursive: true });\n writeFileSync(outPath, content, 'utf-8');\n\n queueAutoCommit({\n projectRoot,\n paths: [outPath],\n subject: `chore(state): update backlog sequence (${doc.project})`,\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { a as __toCommonJS, n as __esmMin } from "./rolldown-runtime-DNCzzKnI.js";
|
|
2
|
-
import { c as init_review_status, s as getReviewStatusSync } from "./review-status-
|
|
3
|
-
import { K as stopAgent, Pn as getAgentStateSync, Q as listRunningAgentsSync, W as spawnRun, cn as determineModel, mr as getAgentRuntimeStateSync, t as init_agents } from "./agents-
|
|
4
|
-
import { n as init_issue_service_singleton, r as issue_service_singleton_exports } from "./issue-service-singleton-
|
|
5
|
-
import { n as parseSequenceMd, t as init_sequence_io } from "./sequence-io-
|
|
2
|
+
import { c as init_review_status, s as getReviewStatusSync } from "./review-status-B5ZASOo4.js";
|
|
3
|
+
import { K as stopAgent, Pn as getAgentStateSync, Q as listRunningAgentsSync, W as spawnRun, cn as determineModel, mr as getAgentRuntimeStateSync, t as init_agents } from "./agents-C7V4odQ6.js";
|
|
4
|
+
import { n as init_issue_service_singleton, r as issue_service_singleton_exports } from "./issue-service-singleton-CDGt__oQ.js";
|
|
5
|
+
import { n as parseSequenceMd, t as init_sequence_io } from "./sequence-io-6YP8fVpH.js";
|
|
6
6
|
import { Effect } from "effect";
|
|
7
7
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
8
8
|
import { dirname, join } from "node:path";
|
|
@@ -331,4 +331,4 @@ var init_sequencer_agent = __esmMin((() => {
|
|
|
331
331
|
//#endregion
|
|
332
332
|
export { spawnSequencerAgent as a, init_sequencer_agent as i, clearFinishedSequencerRun as n, getSequencerRunStatus as r, SEQUENCER_AGENT_ID as t };
|
|
333
333
|
|
|
334
|
-
//# sourceMappingURL=sequencer-agent-
|
|
334
|
+
//# sourceMappingURL=sequencer-agent-ja-nkEc1.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequencer-agent-D8pW2aU_.js","names":[],"sources":["../../src/lib/backlog/backlog-input.ts","../../src/lib/backlog/sequencer-agent.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport type { Issue, IssueState, TrackerType } from '../tracker/interface.js';\nimport { getReviewStatusSync } from '../review-status.js';\nimport { parseSequenceMd } from './sequence-io.js';\nimport type { SequenceDoc } from './types.js';\n\nexport type BacklogManifestEntry = {\n id: string;\n title: string;\n labels: string[];\n priority: number | undefined;\n ageMs: number;\n inPipeline: boolean;\n hasPrd: boolean;\n ready: boolean;\n updatedAt: string;\n /** Epic container (`[EPIC]` title prefix or `epic` label) — not directly workable. */\n isEpic: boolean;\n /** Epic this issue declares membership in via \"Part of #N\" in its body, if any. */\n partOf?: string;\n};\n\nexport type BatchedBodyAccessor = {\n count: number;\n getBatch(batchIndex: number, batchSize: number): Array<{ id: string; body: string }>;\n};\n\nexport type CollectOpenBacklogResult = {\n manifest: BacklogManifestEntry[];\n bodies: BatchedBodyAccessor;\n priorSequence: SequenceDoc | null;\n};\n\nconst SEQUENCE_MD_PATH = '.pan/backlog/sequence.md';\nconst CLOSED_STATES = new Set(['closed', 'cancelled']);\n\n/**\n * Map a dashboard canonical status (or a raw tracker status) onto the\n * tracker-library {@link IssueState} union that {@link collectOpenBacklog}\n * expects. Dashboard read-model issues carry `canonicalStatus`/`state` values\n * like `done`/`canceled`/`verifying_on_main`; the backlog library only knows\n * `open`/`in_progress`/`in_review`/`closed`.\n */\nfunction canonicalToIssueState(raw: string): IssueState {\n const c = raw.toLowerCase();\n if (['done', 'closed', 'completed', 'canceled', 'cancelled', 'duplicate', 'wontfix'].includes(c)) return 'closed';\n if (['in_review', 'in review', 'review', 'qa', 'testing'].includes(c)) return 'in_review';\n if (['in_progress', 'in progress', 'started', 'active', 'verifying', 'verifying_on_main', 'verifying on main'].includes(c)) return 'in_progress';\n return 'open'; // backlog, todo, ready, triage, unknown, ''\n}\n\n/**\n * Adapt the dashboard read-model issue objects returned by\n * `getSharedIssueService().getIssues()` into tracker-library {@link Issue}\n * objects. The two shapes diverge: the dashboard keys the human ref as\n * `identifier` (e.g. \"PAN-302\") with no `ref` field, and its `state` is a\n * canonical dashboard status, not an {@link IssueState}. Feeding the raw\n * dashboard objects straight into {@link collectOpenBacklog} made\n * `getReviewStatusSync(issue.ref)` receive `undefined` and crash on\n * `undefined.toUpperCase()` — so every sequencer pass died before spawning.\n *\n * Issues without a usable human ref are dropped (they cannot be ranked).\n */\nexport function normalizeBacklogIssues(\n raw: ReadonlyArray<Record<string, unknown>>,\n): Issue[] {\n const out: Issue[] = [];\n for (const r of raw) {\n const ref = String(r['identifier'] ?? r['ref'] ?? '').trim();\n if (!ref) continue;\n const stateRaw = String(r['canonicalStatus'] ?? r['state'] ?? r['status'] ?? '');\n out.push({\n id: String(r['id'] ?? ref),\n ref,\n title: String(r['title'] ?? ''),\n description: String(r['description'] ?? ''),\n state: canonicalToIssueState(stateRaw),\n labels: Array.isArray(r['labels']) ? (r['labels'] as string[]) : [],\n url: String(r['url'] ?? ''),\n tracker: (typeof r['source'] === 'string' ? r['source'] : 'github') as TrackerType,\n priority: typeof r['priority'] === 'number' ? r['priority'] : undefined,\n createdAt: String(r['createdAt'] ?? ''),\n updatedAt: String(r['updatedAt'] ?? ''),\n });\n }\n return out;\n}\n\nconst EPIC_TITLE_RE = /^\\s*\\[EPIC\\]/i;\n\n/** An issue is an epic if its title is prefixed `[EPIC]` or it carries the `epic` label. */\nexport function detectIsEpic(title: string, labels: readonly string[]): boolean {\n return EPIC_TITLE_RE.test(title) || labels.some((l) => l.toLowerCase() === 'epic');\n}\n\n/**\n * Parse an explicit epic-membership declaration (\"Part of #N\") from an issue body.\n * Returns the epic's ref using the child's own prefix (PAN-2076 body \"Part of #2075\"\n * → \"PAN-2075\"), or undefined if none is declared or it points at the issue itself.\n */\nexport function detectPartOf(childRef: string, body: string): string | undefined {\n const m = /\\bpart of\\s+#(\\d+)\\b/i.exec(body);\n if (!m) return undefined;\n const prefix = childRef.split('-')[0];\n if (!prefix) return undefined;\n const epicRef = `${prefix}-${m[1]}`;\n return epicRef === childRef.toUpperCase() ? undefined : epicRef;\n}\n\nexport async function collectOpenBacklog(\n projectRoot: string,\n issues: Issue[],\n opts?: {\n hasPrdFn?: (issueId: string) => boolean;\n hasSpecFn?: (issueId: string) => boolean;\n },\n): Promise<CollectOpenBacklogResult> {\n const now = Date.now();\n\n const openIssues = issues.filter((issue) => !CLOSED_STATES.has(issue.state));\n\n // Build per-issue lookup sets once (filesystem scans are cheap when batched).\n const specsDir = join(projectRoot, '.pan', 'specs');\n const workspacesDir = join(projectRoot, 'workspaces');\n const issuesWithSpecs = new Set<string>();\n const issuesWithBeads = new Set<string>();\n if (!opts?.hasSpecFn) {\n if (existsSync(specsDir)) {\n for (const f of readdirSync(specsDir)) {\n const match = /^[\\d-]+-([A-Z]+-\\d+)-/i.exec(f);\n if (match) issuesWithSpecs.add(match[1]!.toUpperCase());\n }\n }\n if (existsSync(workspacesDir)) {\n for (const dir of readdirSync(workspacesDir)) {\n const match = /^feature-([a-z]+-\\d+)$/i.exec(dir);\n if (match) {\n if (existsSync(join(workspacesDir, dir, '.beads', 'issues.jsonl'))) {\n issuesWithBeads.add(match[1]!.toUpperCase());\n }\n }\n }\n }\n }\n\n const manifest: BacklogManifestEntry[] = openIssues.map((issue) => {\n const reviewStatus = getReviewStatusSync(issue.ref);\n const inPipeline =\n (reviewStatus !== null && reviewStatus.reviewStatus !== 'pending') ||\n existsSync(join(workspacesDir, `feature-${issue.ref.toLowerCase()}`));\n\n const hasPrd = opts?.hasPrdFn\n ? opts.hasPrdFn(issue.ref)\n : existsSync(join(projectRoot, '.pan', 'drafts', `${issue.ref.toUpperCase()}.md`));\n\n const ready = opts?.hasSpecFn\n ? opts.hasSpecFn(issue.ref)\n : (issuesWithSpecs.has(issue.ref.toUpperCase()) &&\n issuesWithBeads.has(issue.ref.toUpperCase()));\n\n const createdMs = issue.createdAt ? new Date(issue.createdAt).getTime() : now;\n\n return {\n id: issue.ref,\n title: issue.title,\n labels: issue.labels,\n priority: issue.priority,\n ageMs: now - createdMs,\n inPipeline,\n hasPrd,\n ready,\n updatedAt: issue.updatedAt,\n isEpic: detectIsEpic(issue.title, issue.labels),\n partOf: detectPartOf(issue.ref, issue.description),\n };\n });\n\n const bodies: BatchedBodyAccessor = {\n count: openIssues.length,\n getBatch(batchIndex: number, batchSize: number) {\n const start = batchIndex * batchSize;\n const batch = openIssues.slice(start, start + batchSize);\n return batch.map((issue) => ({ id: issue.ref, body: issue.description }));\n },\n };\n\n const sequencePath = join(projectRoot, SEQUENCE_MD_PATH);\n let priorSequence: SequenceDoc | null = null;\n if (existsSync(sequencePath)) {\n const md = readFileSync(sequencePath, 'utf-8');\n const result = parseSequenceMd(md);\n if (result.ok) {\n priorSequence = result.doc;\n }\n }\n\n return { manifest, bodies, priorSequence };\n}\n","import { existsSync, statSync } from 'node:fs';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\nimport type { AgentState } from '../agents.js';\nimport { Effect } from 'effect';\nimport {\n spawnRun,\n determineModel,\n listRunningAgentsSync,\n getAgentStateSync,\n getAgentRuntimeStateSync,\n stopAgent,\n} from '../agents.js';\nimport { collectOpenBacklog, normalizeBacklogIssues } from './backlog-input.js';\nimport type { PassMode } from './types.js';\nimport type { CollectOpenBacklogResult } from './backlog-input.js';\n\nexport const SEQUENCER_AGENT_ID = 'sequencer-runner';\n\nexport type SequencerRunStatus = {\n alive: boolean;\n running: boolean;\n done: boolean;\n startedAt: string | null;\n doneReason: 'fresh-sequence' | 'idle' | null;\n};\n\nexport type SpawnSequencerOptions = {\n projectRoot?: string;\n projectKey?: string;\n model?: string;\n workspace?: string;\n batchSize?: number;\n /**\n * Raw dashboard read-model issues (from `getSharedIssueService().getIssues()`).\n * Normalized to tracker `Issue` objects via {@link normalizeBacklogIssues}\n * before ranking — callers must NOT pre-cast to `Issue[]` (the shapes differ).\n */\n issues?: ReadonlyArray<Record<string, unknown>>;\n};\n\nexport function getSequencerRunStatus(projectRoot: string): SequencerRunStatus {\n const alive = listRunningAgentsSync().some((a) => a.id === SEQUENCER_AGENT_ID && a.tmuxActive);\n const startedAt = alive ? (getAgentStateSync(SEQUENCER_AGENT_ID)?.startedAt ?? null) : null;\n const seqPath = join(projectRoot, '.pan', 'backlog', 'sequence.md');\n\n let freshSequence = false;\n if (alive && startedAt && existsSync(seqPath)) {\n try {\n freshSequence = statSync(seqPath).mtimeMs >= new Date(startedAt).getTime();\n } catch {\n /* stat failed */\n }\n }\n\n const runtimeState = alive ? getAgentRuntimeStateSync(SEQUENCER_AGENT_ID)?.state ?? null : null;\n const idle = runtimeState === 'idle' || runtimeState === 'stopped' || runtimeState === 'suspended';\n const doneReason = freshSequence ? 'fresh-sequence' : idle ? 'idle' : null;\n const done = alive && doneReason !== null;\n\n return {\n alive,\n running: alive && !done,\n done,\n startedAt,\n doneReason,\n };\n}\n\nexport async function clearFinishedSequencerRun(\n projectRoot: string,\n stop: () => Promise<void> = () => Effect.runPromise(stopAgent(SEQUENCER_AGENT_ID)),\n): Promise<SequencerRunStatus> {\n const status = getSequencerRunStatus(projectRoot);\n if (status.done) {\n await stop();\n }\n return status;\n}\n\nexport async function spawnSequencerAgent(\n pass: PassMode | 'auto',\n opts: SpawnSequencerOptions = {},\n): Promise<AgentState> {\n const projectRoot = opts.projectRoot ?? process.cwd();\n const projectKey = opts.projectKey ?? 'overdeck';\n const batchSize = opts.batchSize ?? 20;\n\n const seqPath = join(projectRoot, '.pan', 'backlog', 'sequence.md');\n const resolvedPass: PassMode =\n pass !== 'auto' ? pass : existsSync(seqPath) ? 'incremental' : 'creation';\n\n let rawIssues = opts.issues;\n if (!rawIssues) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { getSharedIssueService } = require('../../dashboard/server/services/issue-service-singleton.js') as\n typeof import('../../dashboard/server/services/issue-service-singleton.js');\n rawIssues = getSharedIssueService().getIssues() as Array<Record<string, unknown>>;\n } catch {\n rawIssues = [];\n }\n }\n // Dashboard read-model issues key the human ref as `identifier` (not `ref`)\n // and carry canonical statuses; normalize to tracker `Issue` objects so the\n // backlog ranking pipeline can read `issue.ref`/`issue.state` (PAN-1866 fix).\n const allIssues = normalizeBacklogIssues(rawIssues);\n // Scope to Panopticon/overdeck issues only for now. The sequencer is a single\n // global runner; ranking every connected project's open issues (MIN/KRUX/TIN/…)\n // bloats the manifest and isn't meaningful for an overdeck-only sequence.\n // PAN-1999 generalizes this to one sequencer per project — drop the filter then.\n const issues = allIssues.filter((issue) => issue.ref.toUpperCase().startsWith('PAN-'));\n const input = await collectOpenBacklog(projectRoot, issues);\n\n // Write the manifest to a file and reference it from the prompt instead of\n // inlining hundreds of KB of JSON. Inlining produced a single multi-hundred-KB\n // chat message that froze the dashboard conversation panel and blew past\n // small-context models (PAN-1866). The agent reads the file with the Read tool.\n const manifestPath = join(projectRoot, '.pan', 'backlog', 'manifest.json');\n await mkdir(dirname(manifestPath), { recursive: true });\n await writeFile(manifestPath, JSON.stringify(input.manifest, null, 2), 'utf-8');\n\n const model = determineModel({ role: 'sequencer', model: opts.model, spawnKey: 'sequencer:global' });\n const prompt = buildSequencerPrompt(resolvedPass, { projectRoot, projectKey, input, batchSize });\n\n return spawnRun(SEQUENCER_AGENT_ID, 'sequencer', {\n agentId: SEQUENCER_AGENT_ID,\n workspace: opts.workspace ?? projectRoot,\n prompt,\n model,\n allowHost: true,\n registerConversation: true,\n });\n}\n\nexport type SequencerPromptInput = {\n projectRoot: string;\n projectKey: string;\n input: CollectOpenBacklogResult;\n batchSize?: number;\n};\n\nexport function buildSequencerPrompt(pass: PassMode, opts: SequencerPromptInput): string {\n const { projectRoot, projectKey, input, batchSize = 20 } = opts;\n const { manifest, bodies, priorSequence } = input;\n const hasPrior = priorSequence !== null;\n const priorSequencePath = `${projectRoot}/.pan/backlog/sequence.md`;\n\n const passInstructions = {\n creation: `\nThis is a CREATION pass — there is no prior sequence.md. You must rank the entire open backlog from scratch.\n\n1. Read all issue bodies in batches of ${batchSize}. NEVER request all bodies at once — do NOT inline the entire backlog in a single prompt or tool call. Read batch 0, update your running shortlist, then batch 1, and so on.\n2. Assign rank, size, importance, score, condition, gate, and planning to every issue.\n3. Derive the dependency DAG from GitHub cross-references and your analysis.\n4. Write the result via \\`pan backlog write-sequence\\` (see Output section below — do NOT write the file directly).\n`,\n incremental: `\nThis is an INCREMENTAL pass — a prior sequence.md exists at ${hasPrior ? priorSequencePath : '(not found)'}. Preserve existing ranks, scores, conditions, operator-owned fields, and operator-sourced edges VERBATIM unless a delta justifies a change.\n\nRules:\n- An issue changed since the prior run if its manifest \\`updatedAt\\` is LATER than the prior sequence \\`generatedAt\\` (${hasPrior ? priorSequence!.generatedAt : 'N/A'}). Read bodies ONLY for those issues. Batch these (${batchSize} at a time).\n- A delta justifies a rank change when: body changed materially, new cross-references appeared, a dependency was closed/merged, or condition changed.\n- For each changed issue: set a rationale field (one sentence) explaining why the rank changed.\n- Re-derive github-ref edges. Recompute ai-inferred edges as advisory. Preserve operator edges verbatim.\n- Preserve operator-owned gate and planning fields verbatim.\n`,\n review: `\nThis is a REVIEW pass — re-rank the full backlog on demand. A prior sequence.md is available at ${hasPrior ? priorSequencePath : '(not found)'} for reference.\n\n1. Re-read all issue bodies in batches of ${batchSize}. NEVER inline the entire backlog in one prompt. Do NOT concatenate all bodies — read them batch by batch against your running shortlist.\n2. Re-derive all ai-inferred and github-ref edges.\n3. Preserve operator edges verbatim.\n4. Never re-rank in-pipeline issues (inPipeline=true); pin them at rank 1 or their prior rank. Leave gate=auto — do NOT set gate=ready (the gate is operator-only; in-pipeline is detected automatically).\n`,\n };\n\n const commonRules = `\n## Ranking rules (all passes)\n\n- Rank by IMPACT toward shipping, not raw priority signal. GitHub priority and issue age are inputs, not determinants.\n- Substrate-hardening first: an issue labeled \\`substrate-improvement\\`, \\`architecture\\`, or \\`v1.0-required\\` is at least \\`high\\` importance (\\`critical\\` if it unblocks the pipeline or other substrate work) and ranks ahead of routine feature work of equal impact — a stable substrate is the prerequisite for everything else (vision.mdx). When a substrate epic ranks high, lift its CHILDREN's ranks together (the children are what get picked). Do not rank such an issue \\`low\\` just because it reads as cleanup.\n- NEVER re-rank in-pipeline issues (inPipeline: true in the manifest). Pin them at their rank; leave gate=auto (do NOT set gate=ready — gate is operator-only).\n- Assign condition to every issue: ok / needs-refinement / stale.\n- Every node's why field must be ≤ 140 characters (displayed in the ranked table).\n- Write full-paragraph rationale only for the active top tier (~top 80 nodes).\n- Preserve operator-owned gate and planning fields verbatim across all passes.\n- Keep operator-sourced edges verbatim. Re-derive github-ref edges. Recompute ai-inferred edges as advisory with a confidence value 0.0–1.0.\n- Stamp pass=\"${pass}\" and generatedAt=<current ISO timestamp> in the output JSON.\n\n## Epics & parent-child\n\n- An EPIC is a container of child issues, not directly workable. The manifest flags epics with \\`isEpic: true\\` (derived from an \\`[EPIC]\\` title prefix or an \\`epic\\` label). On an epic's node set \\`isEpic: true\\`, and rank/score it by the aggregate impact of its CHILDREN — never as standalone work. Never mark an epic ready/promoted; it must not be picked up.\n- Express membership with a \\`contains\\` edge from the epic to each child: \\`{ from: <epic>, to: <child>, type: \"contains\", source: \"github-ref\", confidence: 1 }\\`. Membership sources: a child's manifest \\`partOf\\` field (\"Part of #N\" in its body) AND the epic body's task-list of child issue numbers (read the epic body to confirm). Emit one \\`contains\\` edge per child.\n- \\`contains\\` edges are membership, NOT ordering. Keep the children's intended BUILD ORDER in their \\`dependsOn\\` (and \\`unblocks\\` edges) as usual — an epic body often states the order explicitly.\n\n## Reading issue bodies\n\nFetch issue bodies in batches of ${batchSize} using the GitHub CLI:\n gh issue view <NUMBER> --json number,title,body\n\nDerive NUMBER from the manifest id (e.g. PAN-42 → 42). Do NOT fetch all bodies at once; read one batch, update your running shortlist, then the next.\n\n## Output\n\nAfter completing your analysis, write the SequenceDoc JSON to a temp file and submit it via:\n\n pan backlog write-sequence /tmp/sequence-result.json\n\nThe \\`pan backlog write-sequence\\` command validates the JSON, writes the formatted\n\\`.pan/backlog/sequence.md\\`, and queues an auto-commit — so DO NOT write the file\ndirectly with the Write tool. Always go through this command.\n\nThe SequenceDoc JSON must conform to the schema:\n { version (number, e.g. 1), project, generatedAt (ISO), model, pass, openCount, nodes[], edges[] }\n\nwhere each node has: issue, rank, size (XS/S/M/L/XL), importance (critical/high/medium/low),\nscore (0-100), condition (ok/needs-refinement/stale), dependsOn (string[]), why (≤140 chars),\nrationale (optional), gate (auto/ready/blocked), planning (skip/auto/interactive),\nisEpic (optional boolean — true for epic containers).\n\nEach edge has: from, to, type (unblocks/informs/contains), source (github-ref/operator/ai-inferred),\nconfidence (0.0–1.0). Use type=\"contains\" only for epic→child membership.\n\nDo not ask for operator input. If an issue is ambiguous, assign condition=needs-refinement and move on.\n`;\n\n const priorContext = hasPrior\n ? `\\n## Prior sequence\\n\\nProject: ${priorSequence!.project}, pass: ${priorSequence!.pass}, ${priorSequence!.nodes.length} nodes, generated: ${priorSequence!.generatedAt}\\n`\n : '\\n## Prior sequence\\n\\nNo prior sequence.md found — this is the first run.\\n';\n\n return `# Sequencer run: ${pass.toUpperCase()} pass for ${projectKey}\n\nYou are the Overdeck Sequencer. Your job is to rank the open backlog for project \"${projectKey}\" and write .pan/backlog/sequence.md.\n\n## Pass\n${passInstructions[pass]}\n${priorContext}\n## Backlog manifest (${manifest.length} open issues, ${bodies.count} bodies available in ${Math.ceil(bodies.count / batchSize)} batches of ${batchSize})\n\nThe manifest is written to \\`.pan/backlog/manifest.json\\` (relative to the project root) — it is NOT inlined here. Read it FIRST (the Read tool, or \\`cat .pan/backlog/manifest.json\\`) to load every open issue's { id, title, labels, priority, ageMs, inPipeline, hasPrd, ready, updatedAt, isEpic, partOf }. Do NOT ask for it to be pasted into the prompt.\n${commonRules}`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sequencer-agent-ja-nkEc1.js","names":[],"sources":["../../src/lib/backlog/backlog-input.ts","../../src/lib/backlog/sequencer-agent.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport type { Issue, IssueState, TrackerType } from '../tracker/interface.js';\nimport { getReviewStatusSync } from '../review-status.js';\nimport { parseSequenceMd } from './sequence-io.js';\nimport type { SequenceDoc } from './types.js';\n\nexport type BacklogManifestEntry = {\n id: string;\n title: string;\n labels: string[];\n priority: number | undefined;\n ageMs: number;\n inPipeline: boolean;\n hasPrd: boolean;\n ready: boolean;\n updatedAt: string;\n /** Epic container (`[EPIC]` title prefix or `epic` label) — not directly workable. */\n isEpic: boolean;\n /** Epic this issue declares membership in via \"Part of #N\" in its body, if any. */\n partOf?: string;\n};\n\nexport type BatchedBodyAccessor = {\n count: number;\n getBatch(batchIndex: number, batchSize: number): Array<{ id: string; body: string }>;\n};\n\nexport type CollectOpenBacklogResult = {\n manifest: BacklogManifestEntry[];\n bodies: BatchedBodyAccessor;\n priorSequence: SequenceDoc | null;\n};\n\nconst SEQUENCE_MD_PATH = '.pan/backlog/sequence.md';\nconst CLOSED_STATES = new Set(['closed', 'cancelled']);\n\n/**\n * Map a dashboard canonical status (or a raw tracker status) onto the\n * tracker-library {@link IssueState} union that {@link collectOpenBacklog}\n * expects. Dashboard read-model issues carry `canonicalStatus`/`state` values\n * like `done`/`canceled`/`verifying_on_main`; the backlog library only knows\n * `open`/`in_progress`/`in_review`/`closed`.\n */\nfunction canonicalToIssueState(raw: string): IssueState {\n const c = raw.toLowerCase();\n if (['done', 'closed', 'completed', 'canceled', 'cancelled', 'duplicate', 'wontfix'].includes(c)) return 'closed';\n if (['in_review', 'in review', 'review', 'qa', 'testing'].includes(c)) return 'in_review';\n if (['in_progress', 'in progress', 'started', 'active', 'verifying', 'verifying_on_main', 'verifying on main'].includes(c)) return 'in_progress';\n return 'open'; // backlog, todo, ready, triage, unknown, ''\n}\n\n/**\n * Adapt the dashboard read-model issue objects returned by\n * `getSharedIssueService().getIssues()` into tracker-library {@link Issue}\n * objects. The two shapes diverge: the dashboard keys the human ref as\n * `identifier` (e.g. \"PAN-302\") with no `ref` field, and its `state` is a\n * canonical dashboard status, not an {@link IssueState}. Feeding the raw\n * dashboard objects straight into {@link collectOpenBacklog} made\n * `getReviewStatusSync(issue.ref)` receive `undefined` and crash on\n * `undefined.toUpperCase()` — so every sequencer pass died before spawning.\n *\n * Issues without a usable human ref are dropped (they cannot be ranked).\n */\nexport function normalizeBacklogIssues(\n raw: ReadonlyArray<Record<string, unknown>>,\n): Issue[] {\n const out: Issue[] = [];\n for (const r of raw) {\n const ref = String(r['identifier'] ?? r['ref'] ?? '').trim();\n if (!ref) continue;\n const stateRaw = String(r['canonicalStatus'] ?? r['state'] ?? r['status'] ?? '');\n out.push({\n id: String(r['id'] ?? ref),\n ref,\n title: String(r['title'] ?? ''),\n description: String(r['description'] ?? ''),\n state: canonicalToIssueState(stateRaw),\n labels: Array.isArray(r['labels']) ? (r['labels'] as string[]) : [],\n url: String(r['url'] ?? ''),\n tracker: (typeof r['source'] === 'string' ? r['source'] : 'github') as TrackerType,\n priority: typeof r['priority'] === 'number' ? r['priority'] : undefined,\n createdAt: String(r['createdAt'] ?? ''),\n updatedAt: String(r['updatedAt'] ?? ''),\n });\n }\n return out;\n}\n\nconst EPIC_TITLE_RE = /^\\s*\\[EPIC\\]/i;\n\n/** An issue is an epic if its title is prefixed `[EPIC]` or it carries the `epic` label. */\nexport function detectIsEpic(title: string, labels: readonly string[]): boolean {\n return EPIC_TITLE_RE.test(title) || labels.some((l) => l.toLowerCase() === 'epic');\n}\n\n/**\n * Parse an explicit epic-membership declaration (\"Part of #N\") from an issue body.\n * Returns the epic's ref using the child's own prefix (PAN-2076 body \"Part of #2075\"\n * → \"PAN-2075\"), or undefined if none is declared or it points at the issue itself.\n */\nexport function detectPartOf(childRef: string, body: string): string | undefined {\n const m = /\\bpart of\\s+#(\\d+)\\b/i.exec(body);\n if (!m) return undefined;\n const prefix = childRef.split('-')[0];\n if (!prefix) return undefined;\n const epicRef = `${prefix}-${m[1]}`;\n return epicRef === childRef.toUpperCase() ? undefined : epicRef;\n}\n\nexport async function collectOpenBacklog(\n projectRoot: string,\n issues: Issue[],\n opts?: {\n hasPrdFn?: (issueId: string) => boolean;\n hasSpecFn?: (issueId: string) => boolean;\n },\n): Promise<CollectOpenBacklogResult> {\n const now = Date.now();\n\n const openIssues = issues.filter((issue) => !CLOSED_STATES.has(issue.state));\n\n // Build per-issue lookup sets once (filesystem scans are cheap when batched).\n const specsDir = join(projectRoot, '.pan', 'specs');\n const workspacesDir = join(projectRoot, 'workspaces');\n const issuesWithSpecs = new Set<string>();\n const issuesWithBeads = new Set<string>();\n if (!opts?.hasSpecFn) {\n if (existsSync(specsDir)) {\n for (const f of readdirSync(specsDir)) {\n const match = /^[\\d-]+-([A-Z]+-\\d+)-/i.exec(f);\n if (match) issuesWithSpecs.add(match[1]!.toUpperCase());\n }\n }\n if (existsSync(workspacesDir)) {\n for (const dir of readdirSync(workspacesDir)) {\n const match = /^feature-([a-z]+-\\d+)$/i.exec(dir);\n if (match) {\n if (existsSync(join(workspacesDir, dir, '.beads', 'issues.jsonl'))) {\n issuesWithBeads.add(match[1]!.toUpperCase());\n }\n }\n }\n }\n }\n\n const manifest: BacklogManifestEntry[] = openIssues.map((issue) => {\n const reviewStatus = getReviewStatusSync(issue.ref);\n const inPipeline =\n (reviewStatus !== null && reviewStatus.reviewStatus !== 'pending') ||\n existsSync(join(workspacesDir, `feature-${issue.ref.toLowerCase()}`));\n\n const hasPrd = opts?.hasPrdFn\n ? opts.hasPrdFn(issue.ref)\n : existsSync(join(projectRoot, '.pan', 'drafts', `${issue.ref.toUpperCase()}.md`));\n\n const ready = opts?.hasSpecFn\n ? opts.hasSpecFn(issue.ref)\n : (issuesWithSpecs.has(issue.ref.toUpperCase()) &&\n issuesWithBeads.has(issue.ref.toUpperCase()));\n\n const createdMs = issue.createdAt ? new Date(issue.createdAt).getTime() : now;\n\n return {\n id: issue.ref,\n title: issue.title,\n labels: issue.labels,\n priority: issue.priority,\n ageMs: now - createdMs,\n inPipeline,\n hasPrd,\n ready,\n updatedAt: issue.updatedAt,\n isEpic: detectIsEpic(issue.title, issue.labels),\n partOf: detectPartOf(issue.ref, issue.description),\n };\n });\n\n const bodies: BatchedBodyAccessor = {\n count: openIssues.length,\n getBatch(batchIndex: number, batchSize: number) {\n const start = batchIndex * batchSize;\n const batch = openIssues.slice(start, start + batchSize);\n return batch.map((issue) => ({ id: issue.ref, body: issue.description }));\n },\n };\n\n const sequencePath = join(projectRoot, SEQUENCE_MD_PATH);\n let priorSequence: SequenceDoc | null = null;\n if (existsSync(sequencePath)) {\n const md = readFileSync(sequencePath, 'utf-8');\n const result = parseSequenceMd(md);\n if (result.ok) {\n priorSequence = result.doc;\n }\n }\n\n return { manifest, bodies, priorSequence };\n}\n","import { existsSync, statSync } from 'node:fs';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\nimport type { AgentState } from '../agents.js';\nimport { Effect } from 'effect';\nimport {\n spawnRun,\n determineModel,\n listRunningAgentsSync,\n getAgentStateSync,\n getAgentRuntimeStateSync,\n stopAgent,\n} from '../agents.js';\nimport { collectOpenBacklog, normalizeBacklogIssues } from './backlog-input.js';\nimport type { PassMode } from './types.js';\nimport type { CollectOpenBacklogResult } from './backlog-input.js';\n\nexport const SEQUENCER_AGENT_ID = 'sequencer-runner';\n\nexport type SequencerRunStatus = {\n alive: boolean;\n running: boolean;\n done: boolean;\n startedAt: string | null;\n doneReason: 'fresh-sequence' | 'idle' | null;\n};\n\nexport type SpawnSequencerOptions = {\n projectRoot?: string;\n projectKey?: string;\n model?: string;\n workspace?: string;\n batchSize?: number;\n /**\n * Raw dashboard read-model issues (from `getSharedIssueService().getIssues()`).\n * Normalized to tracker `Issue` objects via {@link normalizeBacklogIssues}\n * before ranking — callers must NOT pre-cast to `Issue[]` (the shapes differ).\n */\n issues?: ReadonlyArray<Record<string, unknown>>;\n};\n\nexport function getSequencerRunStatus(projectRoot: string): SequencerRunStatus {\n const alive = listRunningAgentsSync().some((a) => a.id === SEQUENCER_AGENT_ID && a.tmuxActive);\n const startedAt = alive ? (getAgentStateSync(SEQUENCER_AGENT_ID)?.startedAt ?? null) : null;\n const seqPath = join(projectRoot, '.pan', 'backlog', 'sequence.md');\n\n let freshSequence = false;\n if (alive && startedAt && existsSync(seqPath)) {\n try {\n freshSequence = statSync(seqPath).mtimeMs >= new Date(startedAt).getTime();\n } catch {\n /* stat failed */\n }\n }\n\n const runtimeState = alive ? getAgentRuntimeStateSync(SEQUENCER_AGENT_ID)?.state ?? null : null;\n const idle = runtimeState === 'idle' || runtimeState === 'stopped' || runtimeState === 'suspended';\n const doneReason = freshSequence ? 'fresh-sequence' : idle ? 'idle' : null;\n const done = alive && doneReason !== null;\n\n return {\n alive,\n running: alive && !done,\n done,\n startedAt,\n doneReason,\n };\n}\n\nexport async function clearFinishedSequencerRun(\n projectRoot: string,\n stop: () => Promise<void> = () => Effect.runPromise(stopAgent(SEQUENCER_AGENT_ID)),\n): Promise<SequencerRunStatus> {\n const status = getSequencerRunStatus(projectRoot);\n if (status.done) {\n await stop();\n }\n return status;\n}\n\nexport async function spawnSequencerAgent(\n pass: PassMode | 'auto',\n opts: SpawnSequencerOptions = {},\n): Promise<AgentState> {\n const projectRoot = opts.projectRoot ?? process.cwd();\n const projectKey = opts.projectKey ?? 'overdeck';\n const batchSize = opts.batchSize ?? 20;\n\n const seqPath = join(projectRoot, '.pan', 'backlog', 'sequence.md');\n const resolvedPass: PassMode =\n pass !== 'auto' ? pass : existsSync(seqPath) ? 'incremental' : 'creation';\n\n let rawIssues = opts.issues;\n if (!rawIssues) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { getSharedIssueService } = require('../../dashboard/server/services/issue-service-singleton.js') as\n typeof import('../../dashboard/server/services/issue-service-singleton.js');\n rawIssues = getSharedIssueService().getIssues() as Array<Record<string, unknown>>;\n } catch {\n rawIssues = [];\n }\n }\n // Dashboard read-model issues key the human ref as `identifier` (not `ref`)\n // and carry canonical statuses; normalize to tracker `Issue` objects so the\n // backlog ranking pipeline can read `issue.ref`/`issue.state` (PAN-1866 fix).\n const allIssues = normalizeBacklogIssues(rawIssues);\n // Scope to Panopticon/overdeck issues only for now. The sequencer is a single\n // global runner; ranking every connected project's open issues (MIN/KRUX/TIN/…)\n // bloats the manifest and isn't meaningful for an overdeck-only sequence.\n // PAN-1999 generalizes this to one sequencer per project — drop the filter then.\n const issues = allIssues.filter((issue) => issue.ref.toUpperCase().startsWith('PAN-'));\n const input = await collectOpenBacklog(projectRoot, issues);\n\n // Write the manifest to a file and reference it from the prompt instead of\n // inlining hundreds of KB of JSON. Inlining produced a single multi-hundred-KB\n // chat message that froze the dashboard conversation panel and blew past\n // small-context models (PAN-1866). The agent reads the file with the Read tool.\n const manifestPath = join(projectRoot, '.pan', 'backlog', 'manifest.json');\n await mkdir(dirname(manifestPath), { recursive: true });\n await writeFile(manifestPath, JSON.stringify(input.manifest, null, 2), 'utf-8');\n\n const model = determineModel({ role: 'sequencer', model: opts.model, spawnKey: 'sequencer:global' });\n const prompt = buildSequencerPrompt(resolvedPass, { projectRoot, projectKey, input, batchSize });\n\n return spawnRun(SEQUENCER_AGENT_ID, 'sequencer', {\n agentId: SEQUENCER_AGENT_ID,\n workspace: opts.workspace ?? projectRoot,\n prompt,\n model,\n allowHost: true,\n registerConversation: true,\n });\n}\n\nexport type SequencerPromptInput = {\n projectRoot: string;\n projectKey: string;\n input: CollectOpenBacklogResult;\n batchSize?: number;\n};\n\nexport function buildSequencerPrompt(pass: PassMode, opts: SequencerPromptInput): string {\n const { projectRoot, projectKey, input, batchSize = 20 } = opts;\n const { manifest, bodies, priorSequence } = input;\n const hasPrior = priorSequence !== null;\n const priorSequencePath = `${projectRoot}/.pan/backlog/sequence.md`;\n\n const passInstructions = {\n creation: `\nThis is a CREATION pass — there is no prior sequence.md. You must rank the entire open backlog from scratch.\n\n1. Read all issue bodies in batches of ${batchSize}. NEVER request all bodies at once — do NOT inline the entire backlog in a single prompt or tool call. Read batch 0, update your running shortlist, then batch 1, and so on.\n2. Assign rank, size, importance, score, condition, gate, and planning to every issue.\n3. Derive the dependency DAG from GitHub cross-references and your analysis.\n4. Write the result via \\`pan backlog write-sequence\\` (see Output section below — do NOT write the file directly).\n`,\n incremental: `\nThis is an INCREMENTAL pass — a prior sequence.md exists at ${hasPrior ? priorSequencePath : '(not found)'}. Preserve existing ranks, scores, conditions, operator-owned fields, and operator-sourced edges VERBATIM unless a delta justifies a change.\n\nRules:\n- An issue changed since the prior run if its manifest \\`updatedAt\\` is LATER than the prior sequence \\`generatedAt\\` (${hasPrior ? priorSequence!.generatedAt : 'N/A'}). Read bodies ONLY for those issues. Batch these (${batchSize} at a time).\n- A delta justifies a rank change when: body changed materially, new cross-references appeared, a dependency was closed/merged, or condition changed.\n- For each changed issue: set a rationale field (one sentence) explaining why the rank changed.\n- Re-derive github-ref edges. Recompute ai-inferred edges as advisory. Preserve operator edges verbatim.\n- Preserve operator-owned gate and planning fields verbatim.\n`,\n review: `\nThis is a REVIEW pass — re-rank the full backlog on demand. A prior sequence.md is available at ${hasPrior ? priorSequencePath : '(not found)'} for reference.\n\n1. Re-read all issue bodies in batches of ${batchSize}. NEVER inline the entire backlog in one prompt. Do NOT concatenate all bodies — read them batch by batch against your running shortlist.\n2. Re-derive all ai-inferred and github-ref edges.\n3. Preserve operator edges verbatim.\n4. Never re-rank in-pipeline issues (inPipeline=true); pin them at rank 1 or their prior rank. Leave gate=auto — do NOT set gate=ready (the gate is operator-only; in-pipeline is detected automatically).\n`,\n };\n\n const commonRules = `\n## Ranking rules (all passes)\n\n- Rank by IMPACT toward shipping, not raw priority signal. GitHub priority and issue age are inputs, not determinants.\n- Substrate-hardening first: an issue labeled \\`substrate-improvement\\`, \\`architecture\\`, or \\`v1.0-required\\` is at least \\`high\\` importance (\\`critical\\` if it unblocks the pipeline or other substrate work) and ranks ahead of routine feature work of equal impact — a stable substrate is the prerequisite for everything else (vision.mdx). When a substrate epic ranks high, lift its CHILDREN's ranks together (the children are what get picked). Do not rank such an issue \\`low\\` just because it reads as cleanup.\n- NEVER re-rank in-pipeline issues (inPipeline: true in the manifest). Pin them at their rank; leave gate=auto (do NOT set gate=ready — gate is operator-only).\n- Assign condition to every issue: ok / needs-refinement / stale.\n- Every node's why field must be ≤ 140 characters (displayed in the ranked table).\n- Write full-paragraph rationale only for the active top tier (~top 80 nodes).\n- Preserve operator-owned gate and planning fields verbatim across all passes.\n- Keep operator-sourced edges verbatim. Re-derive github-ref edges. Recompute ai-inferred edges as advisory with a confidence value 0.0–1.0.\n- Stamp pass=\"${pass}\" and generatedAt=<current ISO timestamp> in the output JSON.\n\n## Epics & parent-child\n\n- An EPIC is a container of child issues, not directly workable. The manifest flags epics with \\`isEpic: true\\` (derived from an \\`[EPIC]\\` title prefix or an \\`epic\\` label). On an epic's node set \\`isEpic: true\\`, and rank/score it by the aggregate impact of its CHILDREN — never as standalone work. Never mark an epic ready/promoted; it must not be picked up.\n- Express membership with a \\`contains\\` edge from the epic to each child: \\`{ from: <epic>, to: <child>, type: \"contains\", source: \"github-ref\", confidence: 1 }\\`. Membership sources: a child's manifest \\`partOf\\` field (\"Part of #N\" in its body) AND the epic body's task-list of child issue numbers (read the epic body to confirm). Emit one \\`contains\\` edge per child.\n- \\`contains\\` edges are membership, NOT ordering. Keep the children's intended BUILD ORDER in their \\`dependsOn\\` (and \\`unblocks\\` edges) as usual — an epic body often states the order explicitly.\n\n## Reading issue bodies\n\nFetch issue bodies in batches of ${batchSize} using the GitHub CLI:\n gh issue view <NUMBER> --json number,title,body\n\nDerive NUMBER from the manifest id (e.g. PAN-42 → 42). Do NOT fetch all bodies at once; read one batch, update your running shortlist, then the next.\n\n## Output\n\nAfter completing your analysis, write the SequenceDoc JSON to a temp file and submit it via:\n\n pan backlog write-sequence /tmp/sequence-result.json\n\nThe \\`pan backlog write-sequence\\` command validates the JSON, writes the formatted\n\\`.pan/backlog/sequence.md\\`, and queues an auto-commit — so DO NOT write the file\ndirectly with the Write tool. Always go through this command.\n\nThe SequenceDoc JSON must conform to the schema:\n { version (number, e.g. 1), project, generatedAt (ISO), model, pass, openCount, nodes[], edges[] }\n\nwhere each node has: issue, rank, size (XS/S/M/L/XL), importance (critical/high/medium/low),\nscore (0-100), condition (ok/needs-refinement/stale), dependsOn (string[]), why (≤140 chars),\nrationale (optional), gate (auto/ready/blocked), planning (skip/auto/interactive),\nisEpic (optional boolean — true for epic containers).\n\nEach edge has: from, to, type (unblocks/informs/contains), source (github-ref/operator/ai-inferred),\nconfidence (0.0–1.0). Use type=\"contains\" only for epic→child membership.\n\nDo not ask for operator input. If an issue is ambiguous, assign condition=needs-refinement and move on.\n`;\n\n const priorContext = hasPrior\n ? `\\n## Prior sequence\\n\\nProject: ${priorSequence!.project}, pass: ${priorSequence!.pass}, ${priorSequence!.nodes.length} nodes, generated: ${priorSequence!.generatedAt}\\n`\n : '\\n## Prior sequence\\n\\nNo prior sequence.md found — this is the first run.\\n';\n\n return `# Sequencer run: ${pass.toUpperCase()} pass for ${projectKey}\n\nYou are the Overdeck Sequencer. Your job is to rank the open backlog for project \"${projectKey}\" and write .pan/backlog/sequence.md.\n\n## Pass\n${passInstructions[pass]}\n${priorContext}\n## Backlog manifest (${manifest.length} open issues, ${bodies.count} bodies available in ${Math.ceil(bodies.count / batchSize)} batches of ${batchSize})\n\nThe manifest is written to \\`.pan/backlog/manifest.json\\` (relative to the project root) — it is NOT inlined here. Read it FIRST (the Read tool, or \\`cat .pan/backlog/manifest.json\\`) to load every open issue's { id, title, labels, priority, ageMs, inPipeline, hasPrd, ready, updatedAt, isEpic, partOf }. Do NOT ask for it to be pasted into the prompt.\n${commonRules}`;\n}\n"],"mappings":"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"}
|