@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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"specialist-logs-CUUJ4eiB.js","names":[],"sources":["../src/lib/cloister/specialist-logs.ts"],"sourcesContent":["/**\n * Specialist Log Management\n *\n * Manages persistent log files for specialist agent runs.\n * Each run produces a structured log file with metadata, context, and full transcript.\n *\n * Directory structure:\n * ~/.overdeck/specialists/{projectKey}/{specialistType}/runs/{timestamp}-{issueId}.log\n */\n\nimport { existsSync, mkdirSync, writeFileSync, appendFileSync, readFileSync, readdirSync, statSync, unlinkSync } from 'fs';\nimport { join, basename } from 'path';\nimport { Data, Effect } from 'effect';\nimport { getOverdeckHome } from '../paths.js';\n\n/** Get specialists directory (lazy to support test env overrides) */\nfunction getSpecialistsDir(): string {\n return join(getOverdeckHome(), 'specialists');\n}\n\n/**\n * Log file metadata\n */\nexport interface RunLogMetadata {\n runId: string;\n project: string;\n specialistType: string;\n issueId: string;\n startedAt: string;\n finishedAt?: string;\n status?: 'passed' | 'failed' | 'blocked' | 'incomplete';\n duration?: number; // in milliseconds\n notes?: string;\n}\n\n/**\n * Run log entry for listing\n */\nexport interface RunLogEntry {\n runId: string;\n filePath: string;\n metadata: RunLogMetadata;\n fileSize: number;\n createdAt: Date;\n}\n\n/**\n * Get the runs directory for a project's specialist\n */\nexport function getRunsDirectory(projectKey: string, specialistType: string): string {\n return join(getSpecialistsDir(), projectKey, specialistType, 'runs');\n}\n\n/**\n * Generate a run ID from timestamp and issue ID\n */\nexport function generateRunId(issueId: string): string {\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-').substring(0, 19);\n return `${timestamp}-${issueId}`;\n}\n\n/**\n * Get the log file path for a run\n */\nexport function getRunLogPath(projectKey: string, specialistType: string, runId: string): string {\n const runsDir = getRunsDirectory(projectKey, specialistType);\n return join(runsDir, `${runId}.log`);\n}\n\n/**\n * Ensure runs directory exists for a project's specialist\n */\nfunction ensureRunsDirectory(projectKey: string, specialistType: string): void {\n const runsDir = getRunsDirectory(projectKey, specialistType);\n if (!existsSync(runsDir)) {\n mkdirSync(runsDir, { recursive: true });\n }\n}\n\n/**\n * Create a new run log file\n *\n * Initializes a log file with metadata header.\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type (review-agent, test-agent, merge-agent)\n * @param issueId - Issue ID being worked on\n * @param contextSeed - Optional context digest that was provided to the specialist\n * @returns Run ID and file path\n */\nexport function createRunLogSync(\n projectKey: string,\n specialistType: string,\n issueId: string,\n contextSeed?: string\n): { runId: string; filePath: string } {\n ensureRunsDirectory(projectKey, specialistType);\n\n const runId = generateRunId(issueId);\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n const startedAt = new Date().toISOString();\n\n // Create log header\n const header = `# ${specialistType} Run - ${issueId}\nProject: ${projectKey}\nStarted: ${startedAt}\nIssue: ${issueId}\nRun ID: ${runId}\n\n## Context Seed\n${contextSeed ? contextSeed : '[No context digest available]'}\n\n## Session Transcript\n`;\n\n writeFileSync(filePath, header, 'utf-8');\n\n return { runId, filePath };\n}\n\n/**\n * Append content to a run log\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @param content - Content to append\n */\nexport function appendToRunLogSync(\n projectKey: string,\n specialistType: string,\n runId: string,\n content: string\n): void {\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n\n if (!existsSync(filePath)) {\n throw new Error(`Run log not found: ${filePath}`);\n }\n\n appendFileSync(filePath, content, 'utf-8');\n}\n\n/**\n * Finalize a run log with result metadata\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @param result - Run result\n */\nexport function finalizeRunLogSync(\n projectKey: string,\n specialistType: string,\n runId: string,\n result: {\n status: 'passed' | 'failed' | 'blocked' | 'incomplete';\n notes?: string;\n }\n): void {\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n\n if (!existsSync(filePath)) {\n throw new Error(`Run log not found: ${filePath}`);\n }\n\n // Read the log to extract start time\n const content = readFileSync(filePath, 'utf-8');\n const startMatch = content.match(/^Started: (.+)$/m);\n const startedAt = startMatch ? new Date(startMatch[1]) : new Date();\n const finishedAt = new Date();\n const duration = finishedAt.getTime() - startedAt.getTime();\n\n // Format duration\n const durationSeconds = Math.floor(duration / 1000);\n const minutes = Math.floor(durationSeconds / 60);\n const seconds = durationSeconds % 60;\n const durationStr = `${minutes}m ${seconds}s`;\n\n // Append result section\n const resultSection = `\n\n## Result\nStatus: ${result.status}\n${result.notes ? `Notes: ${result.notes}` : ''}\nDuration: ${durationStr}\nFinished: ${finishedAt.toISOString()}\n`;\n\n appendFileSync(filePath, resultSection, 'utf-8');\n}\n\n/**\n * Read a run log file\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @returns Log content or null if not found\n */\nexport function getRunLogSync(\n projectKey: string,\n specialistType: string,\n runId: string\n): string | null {\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n\n if (!existsSync(filePath)) {\n return null;\n }\n\n try {\n return readFileSync(filePath, 'utf-8');\n } catch (error) {\n console.error(`Failed to read run log ${runId}:`, error);\n return null;\n }\n}\n\n/**\n * Parse metadata from a log file\n *\n * @param logContent - Log file content\n * @returns Parsed metadata\n */\nexport function parseLogMetadata(logContent: string): Partial<RunLogMetadata> {\n const metadata: Partial<RunLogMetadata> = {};\n\n // Extract metadata from header\n const projectMatch = logContent.match(/^Project: (.+)$/m);\n const startedMatch = logContent.match(/^Started: (.+)$/m);\n const issueMatch = logContent.match(/^Issue: (.+)$/m);\n const runIdMatch = logContent.match(/^Run ID: (.+)$/m);\n const statusMatch = logContent.match(/^Status: (.+)$/m);\n const notesMatch = logContent.match(/^Notes: (.+)$/m);\n const finishedMatch = logContent.match(/^Finished: (.+)$/m);\n const durationMatch = logContent.match(/^Duration: (.+)$/m);\n\n if (projectMatch) metadata.project = projectMatch[1].trim();\n if (startedMatch) metadata.startedAt = startedMatch[1].trim();\n if (issueMatch) metadata.issueId = issueMatch[1].trim();\n if (runIdMatch) metadata.runId = runIdMatch[1].trim();\n if (statusMatch) metadata.status = statusMatch[1].trim() as RunLogMetadata['status'];\n if (notesMatch) metadata.notes = notesMatch[1].trim();\n if (finishedMatch) metadata.finishedAt = finishedMatch[1].trim();\n\n // Parse duration if available\n if (durationMatch) {\n const durationStr = durationMatch[1].trim();\n const minutesMatch = durationStr.match(/(\\d+)m/);\n const secondsMatch = durationStr.match(/(\\d+)s/);\n const minutes = minutesMatch ? parseInt(minutesMatch[1], 10) : 0;\n const seconds = secondsMatch ? parseInt(secondsMatch[1], 10) : 0;\n metadata.duration = (minutes * 60 + seconds) * 1000;\n }\n\n return metadata;\n}\n\n/**\n * List all run logs for a project's specialist\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param options - Listing options\n * @returns Array of run log entries, sorted by most recent first\n */\nexport function listRunLogsSync(\n projectKey: string,\n specialistType: string,\n options: {\n limit?: number;\n offset?: number;\n } = {}\n): RunLogEntry[] {\n const runsDir = getRunsDirectory(projectKey, specialistType);\n\n if (!existsSync(runsDir)) {\n return [];\n }\n\n try {\n const files = readdirSync(runsDir)\n .filter(f => f.endsWith('.log'))\n .map(f => {\n const filePath = join(runsDir, f);\n const stats = statSync(filePath);\n const runId = basename(f, '.log');\n\n // Read file to extract metadata\n const content = readFileSync(filePath, 'utf-8');\n const metadata = parseLogMetadata(content);\n\n return {\n runId,\n filePath,\n metadata: {\n runId,\n project: projectKey,\n specialistType,\n issueId: metadata.issueId || 'unknown',\n startedAt: metadata.startedAt || stats.birthtime.toISOString(),\n finishedAt: metadata.finishedAt,\n status: metadata.status,\n duration: metadata.duration,\n notes: metadata.notes,\n },\n fileSize: stats.size,\n createdAt: stats.birthtime,\n };\n });\n\n // Sort by most recent first, with runId as tiebreaker for stable ordering\n files.sort((a, b) => {\n const timeDiff = b.createdAt.getTime() - a.createdAt.getTime();\n if (timeDiff !== 0) return timeDiff;\n return b.runId.localeCompare(a.runId);\n });\n\n // Apply pagination\n const { limit, offset = 0 } = options;\n if (limit !== undefined) {\n return files.slice(offset, offset + limit);\n }\n\n return files.slice(offset);\n } catch (error) {\n console.error(`Failed to list run logs for ${projectKey}/${specialistType}:`, error);\n return [];\n }\n}\n\n/**\n * Get the most recent N run logs\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param count - Number of recent runs to retrieve\n * @returns Array of recent run log entries\n */\nexport function getRecentRunLogs(\n projectKey: string,\n specialistType: string,\n count: number\n): RunLogEntry[] {\n return listRunLogsSync(projectKey, specialistType, { limit: count });\n}\n\n/**\n * Clean up old run logs based on retention policy\n *\n * Keeps logs that match either criteria (whichever is more permissive):\n * - Within maxDays\n * - Within the last maxRuns count\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param retention - Retention policy\n * @returns Number of logs deleted\n */\nexport function cleanupOldLogsSync(\n projectKey: string,\n specialistType: string,\n retention: { maxDays: number; maxRuns: number }\n): number {\n const { maxDays, maxRuns } = retention;\n\n // Compute cutoff BEFORE reading file stats. This ensures all files that existed\n // when cleanup was invoked have birthtimes <= cutoffDate when maxDays=0, avoiding\n // a race where a file created in the same millisecond as cutoffDate would be\n // incorrectly retained by a >= comparison.\n const now = new Date();\n const cutoffDate = new Date(now.getTime() - maxDays * 24 * 60 * 60 * 1000);\n\n const allLogs = listRunLogsSync(projectKey, specialistType);\n\n if (allLogs.length === 0) {\n return 0;\n }\n\n let deletedCount = 0;\n\n allLogs.forEach((log, index) => {\n // Keep if within maxRuns (most recent N runs)\n if (index < maxRuns) {\n return;\n }\n\n // Keep if within maxDays. Skip the age check entirely when maxDays=0, because\n // \"within 0 days\" means no age-based protection — only maxRuns applies.\n // This avoids a timing/rounding issue: Node.js converts nanosecond birthtime\n // to milliseconds using standard rounding, so a file created at 431.6ms gets\n // birthtime 432ms. If cutoff is 431ms (same wall-clock millisecond), the file\n // incorrectly appears newer than the cutoff and gets retained.\n if (maxDays > 0 && log.createdAt >= cutoffDate) {\n return;\n }\n\n // Delete this log\n try {\n unlinkSync(log.filePath);\n deletedCount++;\n console.log(`[specialist-logs] Deleted old log: ${log.runId}`);\n } catch (error) {\n console.error(`[specialist-logs] Failed to delete ${log.runId}:`, error);\n }\n });\n\n return deletedCount;\n}\n\n/**\n * Check if a run log is still active (not finalized)\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @returns True if log exists but has no result section yet\n */\nexport function isRunLogActive(\n projectKey: string,\n specialistType: string,\n runId: string\n): boolean {\n const content = getRunLogSync(projectKey, specialistType, runId);\n\n if (!content) {\n return false;\n }\n\n // Check if Result section exists\n return !content.includes('## Result');\n}\n\n/**\n * Get file size of a run log (useful for truncation check)\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @returns File size in bytes or null if not found\n */\nexport function getRunLogSize(\n projectKey: string,\n specialistType: string,\n runId: string\n): number | null {\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n\n if (!existsSync(filePath)) {\n return null;\n }\n\n try {\n const stats = statSync(filePath);\n return stats.size;\n } catch (error) {\n return null;\n }\n}\n\n/**\n * Maximum log file size (10MB) before truncation warning\n */\nexport const MAX_LOG_SIZE = 10 * 1024 * 1024;\n\n/**\n * Check if a log file is approaching or exceeding size limits\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @returns Warning info or null if size is OK\n */\nexport function checkLogSizeLimit(\n projectKey: string,\n specialistType: string,\n runId: string\n): { exceeded: boolean; size: number; limit: number } | null {\n const size = getRunLogSize(projectKey, specialistType, runId);\n\n if (size === null) {\n return null;\n }\n\n if (size >= MAX_LOG_SIZE) {\n return {\n exceeded: true,\n size,\n limit: MAX_LOG_SIZE,\n };\n }\n\n return null;\n}\n\n/**\n * Clean up old logs for all projects and specialists\n *\n * Runs cleanup based on retention policies configured in projects.yaml.\n * This should be called periodically (e.g., daily cron job).\n *\n * @returns Summary of cleanup results\n */\nexport function cleanupAllLogsSync(): {\n totalDeleted: number;\n byProject: Record<string, Record<string, number>>;\n} {\n const { listProjectsWithSpecialists } = require('./specialists.js');\n const { getSpecialistRetention } = require('../projects.js');\n\n const results = {\n totalDeleted: 0,\n byProject: {} as Record<string, Record<string, number>>,\n };\n\n const projects = listProjectsWithSpecialists();\n\n for (const projectKey of projects) {\n results.byProject[projectKey] = {};\n\n // Get retention policy for this project\n const retention = getSpecialistRetention(projectKey);\n\n // Clean up each specialist type\n const specialistTypes = ['review-agent', 'test-agent', 'merge-agent'];\n\n for (const specialistType of specialistTypes) {\n const deleted = cleanupOldLogsSync(projectKey, specialistType, retention);\n\n if (deleted > 0) {\n results.byProject[projectKey][specialistType] = deleted;\n results.totalDeleted += deleted;\n }\n }\n }\n\n console.log(`[specialist-logs] Cleanup complete: deleted ${results.totalDeleted} old logs`);\n\n return results;\n}\n\n// ─── Effect variants (PAN-1249) ───────────────────────────────────────────────\n//\n// Additive Effect wrappers around the existing sync APIs. The underlying file\n// I/O is sync (CLI-callable); these variants lift thrown exceptions into a\n// typed error channel so callers can compose specialist-log operations with\n// other Effect-native code. Migrate callers individually.\n\n/** Tagged error for specialist-log Effect variants. */\nexport class SpecialistLogError extends Data.TaggedError('SpecialistLogError')<{\n readonly projectKey: string;\n readonly specialistType: string;\n readonly operation: string;\n readonly message: string;\n readonly cause?: unknown;\n}> {}\n\nconst liftLogError = (\n projectKey: string,\n specialistType: string,\n operation: string,\n cause: unknown,\n): SpecialistLogError =>\n new SpecialistLogError({\n projectKey,\n specialistType,\n operation,\n message: cause instanceof Error ? cause.message : String(cause),\n cause,\n });\n\n/** Effect variant of `createRunLog`. */\nexport const createRunLog = (\n projectKey: string,\n specialistType: string,\n issueId: string,\n contextSeed?: string,\n): Effect.Effect<{ runId: string; filePath: string }, SpecialistLogError> =>\n Effect.try({\n try: () => createRunLogSync(projectKey, specialistType, issueId, contextSeed),\n catch: (cause) => liftLogError(projectKey, specialistType, 'createRunLog', cause),\n });\n\n/** Effect variant of `appendToRunLog`. */\nexport const appendToRunLog = (\n projectKey: string,\n specialistType: string,\n runId: string,\n content: string,\n): Effect.Effect<void, SpecialistLogError> =>\n Effect.try({\n try: () => appendToRunLogSync(projectKey, specialistType, runId, content),\n catch: (cause) => liftLogError(projectKey, specialistType, 'appendToRunLog', cause),\n });\n\n/** Effect variant of `finalizeRunLog`. */\nexport const finalizeRunLog = (\n projectKey: string,\n specialistType: string,\n runId: string,\n result: { status: 'passed' | 'failed' | 'blocked' | 'incomplete'; notes?: string },\n): Effect.Effect<void, SpecialistLogError> =>\n Effect.try({\n try: () => finalizeRunLogSync(projectKey, specialistType, runId, result),\n catch: (cause) => liftLogError(projectKey, specialistType, 'finalizeRunLog', cause),\n });\n\n/** Effect variant of `getRunLog`. */\nexport const getRunLog = (\n projectKey: string,\n specialistType: string,\n runId: string,\n): Effect.Effect<string | null, SpecialistLogError> =>\n Effect.try({\n try: () => getRunLogSync(projectKey, specialistType, runId),\n catch: (cause) => liftLogError(projectKey, specialistType, 'getRunLog', cause),\n });\n\n/** Effect variant of `listRunLogs`. */\nexport const listRunLogs = (\n projectKey: string,\n specialistType: string,\n options: { limit?: number; offset?: number } = {},\n): Effect.Effect<RunLogEntry[], SpecialistLogError> =>\n Effect.try({\n try: () => listRunLogsSync(projectKey, specialistType, options),\n catch: (cause) => liftLogError(projectKey, specialistType, 'listRunLogs', cause),\n });\n\n/** Effect variant of `cleanupOldLogs`. */\nexport const cleanupOldLogs = (\n projectKey: string,\n specialistType: string,\n retention: { maxDays: number; maxRuns: number },\n): Effect.Effect<number, SpecialistLogError> =>\n Effect.try({\n try: () => cleanupOldLogsSync(projectKey, specialistType, retention),\n catch: (cause) => liftLogError(projectKey, specialistType, 'cleanupOldLogs', cause),\n });\n\n/** Effect variant of `cleanupAllLogs`. */\nexport const cleanupAllLogs = (): Effect.Effect<\n { totalDeleted: number; byProject: Record<string, Record<string, number>> },\n SpecialistLogError\n> =>\n Effect.try({\n try: () => cleanupAllLogsSync(),\n catch: (cause) => liftLogError('*', '*', 'cleanupAllLogs', cause),\n });\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"specialist-logs-pEMCTtGZ.js","names":[],"sources":["../src/lib/cloister/specialist-logs.ts"],"sourcesContent":["/**\n * Specialist Log Management\n *\n * Manages persistent log files for specialist agent runs.\n * Each run produces a structured log file with metadata, context, and full transcript.\n *\n * Directory structure:\n * ~/.overdeck/specialists/{projectKey}/{specialistType}/runs/{timestamp}-{issueId}.log\n */\n\nimport { existsSync, mkdirSync, writeFileSync, appendFileSync, readFileSync, readdirSync, statSync, unlinkSync } from 'fs';\nimport { join, basename } from 'path';\nimport { Data, Effect } from 'effect';\nimport { getOverdeckHome } from '../paths.js';\n\n/** Get specialists directory (lazy to support test env overrides) */\nfunction getSpecialistsDir(): string {\n return join(getOverdeckHome(), 'specialists');\n}\n\n/**\n * Log file metadata\n */\nexport interface RunLogMetadata {\n runId: string;\n project: string;\n specialistType: string;\n issueId: string;\n startedAt: string;\n finishedAt?: string;\n status?: 'passed' | 'failed' | 'blocked' | 'incomplete';\n duration?: number; // in milliseconds\n notes?: string;\n}\n\n/**\n * Run log entry for listing\n */\nexport interface RunLogEntry {\n runId: string;\n filePath: string;\n metadata: RunLogMetadata;\n fileSize: number;\n createdAt: Date;\n}\n\n/**\n * Get the runs directory for a project's specialist\n */\nexport function getRunsDirectory(projectKey: string, specialistType: string): string {\n return join(getSpecialistsDir(), projectKey, specialistType, 'runs');\n}\n\n/**\n * Generate a run ID from timestamp and issue ID\n */\nexport function generateRunId(issueId: string): string {\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-').substring(0, 19);\n return `${timestamp}-${issueId}`;\n}\n\n/**\n * Get the log file path for a run\n */\nexport function getRunLogPath(projectKey: string, specialistType: string, runId: string): string {\n const runsDir = getRunsDirectory(projectKey, specialistType);\n return join(runsDir, `${runId}.log`);\n}\n\n/**\n * Ensure runs directory exists for a project's specialist\n */\nfunction ensureRunsDirectory(projectKey: string, specialistType: string): void {\n const runsDir = getRunsDirectory(projectKey, specialistType);\n if (!existsSync(runsDir)) {\n mkdirSync(runsDir, { recursive: true });\n }\n}\n\n/**\n * Create a new run log file\n *\n * Initializes a log file with metadata header.\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type (review-agent, test-agent, merge-agent)\n * @param issueId - Issue ID being worked on\n * @param contextSeed - Optional context digest that was provided to the specialist\n * @returns Run ID and file path\n */\nexport function createRunLogSync(\n projectKey: string,\n specialistType: string,\n issueId: string,\n contextSeed?: string\n): { runId: string; filePath: string } {\n ensureRunsDirectory(projectKey, specialistType);\n\n const runId = generateRunId(issueId);\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n const startedAt = new Date().toISOString();\n\n // Create log header\n const header = `# ${specialistType} Run - ${issueId}\nProject: ${projectKey}\nStarted: ${startedAt}\nIssue: ${issueId}\nRun ID: ${runId}\n\n## Context Seed\n${contextSeed ? contextSeed : '[No context digest available]'}\n\n## Session Transcript\n`;\n\n writeFileSync(filePath, header, 'utf-8');\n\n return { runId, filePath };\n}\n\n/**\n * Append content to a run log\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @param content - Content to append\n */\nexport function appendToRunLogSync(\n projectKey: string,\n specialistType: string,\n runId: string,\n content: string\n): void {\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n\n if (!existsSync(filePath)) {\n throw new Error(`Run log not found: ${filePath}`);\n }\n\n appendFileSync(filePath, content, 'utf-8');\n}\n\n/**\n * Finalize a run log with result metadata\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @param result - Run result\n */\nexport function finalizeRunLogSync(\n projectKey: string,\n specialistType: string,\n runId: string,\n result: {\n status: 'passed' | 'failed' | 'blocked' | 'incomplete';\n notes?: string;\n }\n): void {\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n\n if (!existsSync(filePath)) {\n throw new Error(`Run log not found: ${filePath}`);\n }\n\n // Read the log to extract start time\n const content = readFileSync(filePath, 'utf-8');\n const startMatch = content.match(/^Started: (.+)$/m);\n const startedAt = startMatch ? new Date(startMatch[1]) : new Date();\n const finishedAt = new Date();\n const duration = finishedAt.getTime() - startedAt.getTime();\n\n // Format duration\n const durationSeconds = Math.floor(duration / 1000);\n const minutes = Math.floor(durationSeconds / 60);\n const seconds = durationSeconds % 60;\n const durationStr = `${minutes}m ${seconds}s`;\n\n // Append result section\n const resultSection = `\n\n## Result\nStatus: ${result.status}\n${result.notes ? `Notes: ${result.notes}` : ''}\nDuration: ${durationStr}\nFinished: ${finishedAt.toISOString()}\n`;\n\n appendFileSync(filePath, resultSection, 'utf-8');\n}\n\n/**\n * Read a run log file\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @returns Log content or null if not found\n */\nexport function getRunLogSync(\n projectKey: string,\n specialistType: string,\n runId: string\n): string | null {\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n\n if (!existsSync(filePath)) {\n return null;\n }\n\n try {\n return readFileSync(filePath, 'utf-8');\n } catch (error) {\n console.error(`Failed to read run log ${runId}:`, error);\n return null;\n }\n}\n\n/**\n * Parse metadata from a log file\n *\n * @param logContent - Log file content\n * @returns Parsed metadata\n */\nexport function parseLogMetadata(logContent: string): Partial<RunLogMetadata> {\n const metadata: Partial<RunLogMetadata> = {};\n\n // Extract metadata from header\n const projectMatch = logContent.match(/^Project: (.+)$/m);\n const startedMatch = logContent.match(/^Started: (.+)$/m);\n const issueMatch = logContent.match(/^Issue: (.+)$/m);\n const runIdMatch = logContent.match(/^Run ID: (.+)$/m);\n const statusMatch = logContent.match(/^Status: (.+)$/m);\n const notesMatch = logContent.match(/^Notes: (.+)$/m);\n const finishedMatch = logContent.match(/^Finished: (.+)$/m);\n const durationMatch = logContent.match(/^Duration: (.+)$/m);\n\n if (projectMatch) metadata.project = projectMatch[1].trim();\n if (startedMatch) metadata.startedAt = startedMatch[1].trim();\n if (issueMatch) metadata.issueId = issueMatch[1].trim();\n if (runIdMatch) metadata.runId = runIdMatch[1].trim();\n if (statusMatch) metadata.status = statusMatch[1].trim() as RunLogMetadata['status'];\n if (notesMatch) metadata.notes = notesMatch[1].trim();\n if (finishedMatch) metadata.finishedAt = finishedMatch[1].trim();\n\n // Parse duration if available\n if (durationMatch) {\n const durationStr = durationMatch[1].trim();\n const minutesMatch = durationStr.match(/(\\d+)m/);\n const secondsMatch = durationStr.match(/(\\d+)s/);\n const minutes = minutesMatch ? parseInt(minutesMatch[1], 10) : 0;\n const seconds = secondsMatch ? parseInt(secondsMatch[1], 10) : 0;\n metadata.duration = (minutes * 60 + seconds) * 1000;\n }\n\n return metadata;\n}\n\n/**\n * List all run logs for a project's specialist\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param options - Listing options\n * @returns Array of run log entries, sorted by most recent first\n */\nexport function listRunLogsSync(\n projectKey: string,\n specialistType: string,\n options: {\n limit?: number;\n offset?: number;\n } = {}\n): RunLogEntry[] {\n const runsDir = getRunsDirectory(projectKey, specialistType);\n\n if (!existsSync(runsDir)) {\n return [];\n }\n\n try {\n const files = readdirSync(runsDir)\n .filter(f => f.endsWith('.log'))\n .map(f => {\n const filePath = join(runsDir, f);\n const stats = statSync(filePath);\n const runId = basename(f, '.log');\n\n // Read file to extract metadata\n const content = readFileSync(filePath, 'utf-8');\n const metadata = parseLogMetadata(content);\n\n return {\n runId,\n filePath,\n metadata: {\n runId,\n project: projectKey,\n specialistType,\n issueId: metadata.issueId || 'unknown',\n startedAt: metadata.startedAt || stats.birthtime.toISOString(),\n finishedAt: metadata.finishedAt,\n status: metadata.status,\n duration: metadata.duration,\n notes: metadata.notes,\n },\n fileSize: stats.size,\n createdAt: stats.birthtime,\n };\n });\n\n // Sort by most recent first, with runId as tiebreaker for stable ordering\n files.sort((a, b) => {\n const timeDiff = b.createdAt.getTime() - a.createdAt.getTime();\n if (timeDiff !== 0) return timeDiff;\n return b.runId.localeCompare(a.runId);\n });\n\n // Apply pagination\n const { limit, offset = 0 } = options;\n if (limit !== undefined) {\n return files.slice(offset, offset + limit);\n }\n\n return files.slice(offset);\n } catch (error) {\n console.error(`Failed to list run logs for ${projectKey}/${specialistType}:`, error);\n return [];\n }\n}\n\n/**\n * Get the most recent N run logs\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param count - Number of recent runs to retrieve\n * @returns Array of recent run log entries\n */\nexport function getRecentRunLogs(\n projectKey: string,\n specialistType: string,\n count: number\n): RunLogEntry[] {\n return listRunLogsSync(projectKey, specialistType, { limit: count });\n}\n\n/**\n * Clean up old run logs based on retention policy\n *\n * Keeps logs that match either criteria (whichever is more permissive):\n * - Within maxDays\n * - Within the last maxRuns count\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param retention - Retention policy\n * @returns Number of logs deleted\n */\nexport function cleanupOldLogsSync(\n projectKey: string,\n specialistType: string,\n retention: { maxDays: number; maxRuns: number }\n): number {\n const { maxDays, maxRuns } = retention;\n\n // Compute cutoff BEFORE reading file stats. This ensures all files that existed\n // when cleanup was invoked have birthtimes <= cutoffDate when maxDays=0, avoiding\n // a race where a file created in the same millisecond as cutoffDate would be\n // incorrectly retained by a >= comparison.\n const now = new Date();\n const cutoffDate = new Date(now.getTime() - maxDays * 24 * 60 * 60 * 1000);\n\n const allLogs = listRunLogsSync(projectKey, specialistType);\n\n if (allLogs.length === 0) {\n return 0;\n }\n\n let deletedCount = 0;\n\n allLogs.forEach((log, index) => {\n // Keep if within maxRuns (most recent N runs)\n if (index < maxRuns) {\n return;\n }\n\n // Keep if within maxDays. Skip the age check entirely when maxDays=0, because\n // \"within 0 days\" means no age-based protection — only maxRuns applies.\n // This avoids a timing/rounding issue: Node.js converts nanosecond birthtime\n // to milliseconds using standard rounding, so a file created at 431.6ms gets\n // birthtime 432ms. If cutoff is 431ms (same wall-clock millisecond), the file\n // incorrectly appears newer than the cutoff and gets retained.\n if (maxDays > 0 && log.createdAt >= cutoffDate) {\n return;\n }\n\n // Delete this log\n try {\n unlinkSync(log.filePath);\n deletedCount++;\n console.log(`[specialist-logs] Deleted old log: ${log.runId}`);\n } catch (error) {\n console.error(`[specialist-logs] Failed to delete ${log.runId}:`, error);\n }\n });\n\n return deletedCount;\n}\n\n/**\n * Check if a run log is still active (not finalized)\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @returns True if log exists but has no result section yet\n */\nexport function isRunLogActive(\n projectKey: string,\n specialistType: string,\n runId: string\n): boolean {\n const content = getRunLogSync(projectKey, specialistType, runId);\n\n if (!content) {\n return false;\n }\n\n // Check if Result section exists\n return !content.includes('## Result');\n}\n\n/**\n * Get file size of a run log (useful for truncation check)\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @returns File size in bytes or null if not found\n */\nexport function getRunLogSize(\n projectKey: string,\n specialistType: string,\n runId: string\n): number | null {\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n\n if (!existsSync(filePath)) {\n return null;\n }\n\n try {\n const stats = statSync(filePath);\n return stats.size;\n } catch (error) {\n return null;\n }\n}\n\n/**\n * Maximum log file size (10MB) before truncation warning\n */\nexport const MAX_LOG_SIZE = 10 * 1024 * 1024;\n\n/**\n * Check if a log file is approaching or exceeding size limits\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @returns Warning info or null if size is OK\n */\nexport function checkLogSizeLimit(\n projectKey: string,\n specialistType: string,\n runId: string\n): { exceeded: boolean; size: number; limit: number } | null {\n const size = getRunLogSize(projectKey, specialistType, runId);\n\n if (size === null) {\n return null;\n }\n\n if (size >= MAX_LOG_SIZE) {\n return {\n exceeded: true,\n size,\n limit: MAX_LOG_SIZE,\n };\n }\n\n return null;\n}\n\n/**\n * Clean up old logs for all projects and specialists\n *\n * Runs cleanup based on retention policies configured in projects.yaml.\n * This should be called periodically (e.g., daily cron job).\n *\n * @returns Summary of cleanup results\n */\nexport function cleanupAllLogsSync(): {\n totalDeleted: number;\n byProject: Record<string, Record<string, number>>;\n} {\n const { listProjectsWithSpecialists } = require('./specialists.js');\n const { getSpecialistRetention } = require('../projects.js');\n\n const results = {\n totalDeleted: 0,\n byProject: {} as Record<string, Record<string, number>>,\n };\n\n const projects = listProjectsWithSpecialists();\n\n for (const projectKey of projects) {\n results.byProject[projectKey] = {};\n\n // Get retention policy for this project\n const retention = getSpecialistRetention(projectKey);\n\n // Clean up each specialist type\n const specialistTypes = ['review-agent', 'test-agent', 'merge-agent'];\n\n for (const specialistType of specialistTypes) {\n const deleted = cleanupOldLogsSync(projectKey, specialistType, retention);\n\n if (deleted > 0) {\n results.byProject[projectKey][specialistType] = deleted;\n results.totalDeleted += deleted;\n }\n }\n }\n\n console.log(`[specialist-logs] Cleanup complete: deleted ${results.totalDeleted} old logs`);\n\n return results;\n}\n\n// ─── Effect variants (PAN-1249) ───────────────────────────────────────────────\n//\n// Additive Effect wrappers around the existing sync APIs. The underlying file\n// I/O is sync (CLI-callable); these variants lift thrown exceptions into a\n// typed error channel so callers can compose specialist-log operations with\n// other Effect-native code. Migrate callers individually.\n\n/** Tagged error for specialist-log Effect variants. */\nexport class SpecialistLogError extends Data.TaggedError('SpecialistLogError')<{\n readonly projectKey: string;\n readonly specialistType: string;\n readonly operation: string;\n readonly message: string;\n readonly cause?: unknown;\n}> {}\n\nconst liftLogError = (\n projectKey: string,\n specialistType: string,\n operation: string,\n cause: unknown,\n): SpecialistLogError =>\n new SpecialistLogError({\n projectKey,\n specialistType,\n operation,\n message: cause instanceof Error ? cause.message : String(cause),\n cause,\n });\n\n/** Effect variant of `createRunLog`. */\nexport const createRunLog = (\n projectKey: string,\n specialistType: string,\n issueId: string,\n contextSeed?: string,\n): Effect.Effect<{ runId: string; filePath: string }, SpecialistLogError> =>\n Effect.try({\n try: () => createRunLogSync(projectKey, specialistType, issueId, contextSeed),\n catch: (cause) => liftLogError(projectKey, specialistType, 'createRunLog', cause),\n });\n\n/** Effect variant of `appendToRunLog`. */\nexport const appendToRunLog = (\n projectKey: string,\n specialistType: string,\n runId: string,\n content: string,\n): Effect.Effect<void, SpecialistLogError> =>\n Effect.try({\n try: () => appendToRunLogSync(projectKey, specialistType, runId, content),\n catch: (cause) => liftLogError(projectKey, specialistType, 'appendToRunLog', cause),\n });\n\n/** Effect variant of `finalizeRunLog`. */\nexport const finalizeRunLog = (\n projectKey: string,\n specialistType: string,\n runId: string,\n result: { status: 'passed' | 'failed' | 'blocked' | 'incomplete'; notes?: string },\n): Effect.Effect<void, SpecialistLogError> =>\n Effect.try({\n try: () => finalizeRunLogSync(projectKey, specialistType, runId, result),\n catch: (cause) => liftLogError(projectKey, specialistType, 'finalizeRunLog', cause),\n });\n\n/** Effect variant of `getRunLog`. */\nexport const getRunLog = (\n projectKey: string,\n specialistType: string,\n runId: string,\n): Effect.Effect<string | null, SpecialistLogError> =>\n Effect.try({\n try: () => getRunLogSync(projectKey, specialistType, runId),\n catch: (cause) => liftLogError(projectKey, specialistType, 'getRunLog', cause),\n });\n\n/** Effect variant of `listRunLogs`. */\nexport const listRunLogs = (\n projectKey: string,\n specialistType: string,\n options: { limit?: number; offset?: number } = {},\n): Effect.Effect<RunLogEntry[], SpecialistLogError> =>\n Effect.try({\n try: () => listRunLogsSync(projectKey, specialistType, options),\n catch: (cause) => liftLogError(projectKey, specialistType, 'listRunLogs', cause),\n });\n\n/** Effect variant of `cleanupOldLogs`. */\nexport const cleanupOldLogs = (\n projectKey: string,\n specialistType: string,\n retention: { maxDays: number; maxRuns: number },\n): Effect.Effect<number, SpecialistLogError> =>\n Effect.try({\n try: () => cleanupOldLogsSync(projectKey, specialistType, retention),\n catch: (cause) => liftLogError(projectKey, specialistType, 'cleanupOldLogs', cause),\n });\n\n/** Effect variant of `cleanupAllLogs`. */\nexport const cleanupAllLogs = (): Effect.Effect<\n { totalDeleted: number; byProject: Record<string, Record<string, number>> },\n SpecialistLogError\n> =>\n Effect.try({\n try: () => cleanupAllLogsSync(),\n catch: (cause) => liftLogError('*', '*', 'cleanupAllLogs', cause),\n });\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { O as init_specialists, V as pruneSpecialistRegistryEntriesForIssue, y as getProjectSpecialistMetadata } from "./specialists-
|
|
1
|
+
import { O as init_specialists, V as pruneSpecialistRegistryEntriesForIssue, y as getProjectSpecialistMetadata } from "./specialists-DeTkkp8b.js";
|
|
2
2
|
init_specialists();
|
|
3
3
|
export { getProjectSpecialistMetadata, pruneSpecialistRegistryEntriesForIssue };
|
|
@@ -4,7 +4,7 @@ import { m as init_errors } from "./errors-DyEDJ7xB.js";
|
|
|
4
4
|
import { A as sessionExists, C as listPaneValues, x as killSession, y as init_tmux } from "./tmux-Ceg1ulra.js";
|
|
5
5
|
import { f as init_cost, t as calculateCostSync, u as getPricingSync } from "./cost-6uWF3Bnw.js";
|
|
6
6
|
import { a as readCavemanVariant, n as init_workspace } from "./workspace-P0whzIO3.js";
|
|
7
|
-
import { n as resolveHarness, t as init_harness_resolve } from "./harness-resolve-
|
|
7
|
+
import { n as resolveHarness, t as init_harness_resolve } from "./harness-resolve-B-YDNwNW.js";
|
|
8
8
|
import { Effect } from "effect";
|
|
9
9
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
|
|
10
10
|
import { basename, join } from "path";
|
|
@@ -295,7 +295,7 @@ function roleForSpecialistModel(specialistType) {
|
|
|
295
295
|
return { role: "work" };
|
|
296
296
|
}
|
|
297
297
|
async function buildSpecialistBaseCommand(specialistType, model, sessionName) {
|
|
298
|
-
const { getAgentRuntimeBaseCommand } = await import("./agents-
|
|
298
|
+
const { getAgentRuntimeBaseCommand } = await import("./agents-By3u_fQ8.js");
|
|
299
299
|
const role = roleForSpecialistModel(specialistType).role;
|
|
300
300
|
const harness = await resolveHarness({
|
|
301
301
|
model,
|
|
@@ -694,7 +694,7 @@ async function signalSpecialistCompletion(projectKey, specialistType, result, is
|
|
|
694
694
|
const resolvedTmuxSession = metadata.tmuxSession ?? getTmuxSessionName(specialistType, projectKey, issueId);
|
|
695
695
|
updateRunStatus(projectKey, registryKey, result.status);
|
|
696
696
|
if (metadata.currentRun) try {
|
|
697
|
-
const { finalizeRunLogSync } = await import("./specialist-logs-
|
|
697
|
+
const { finalizeRunLogSync } = await import("./specialist-logs-pEMCTtGZ.js");
|
|
698
698
|
finalizeRunLogSync(projectKey, specialistType, metadata.currentRun, {
|
|
699
699
|
status: result.status,
|
|
700
700
|
notes: result.notes
|
|
@@ -704,7 +704,7 @@ async function signalSpecialistCompletion(projectKey, specialistType, result, is
|
|
|
704
704
|
}
|
|
705
705
|
setCurrentRun(projectKey, registryKey, null);
|
|
706
706
|
updateRunMetadata(projectKey, registryKey, { currentActivity: null });
|
|
707
|
-
import("./agents-
|
|
707
|
+
import("./agents-By3u_fQ8.js").then(({ saveAgentRuntimeState }) => {
|
|
708
708
|
saveAgentRuntimeState(resolvedTmuxSession, {
|
|
709
709
|
state: "idle",
|
|
710
710
|
lastActivity: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -735,7 +735,7 @@ async function terminateSpecialist(projectKey, specialistType, issueId) {
|
|
|
735
735
|
console.error(`[specialist] Failed to kill tmux session ${tmuxSession}:`, error);
|
|
736
736
|
}
|
|
737
737
|
if (metadata.currentRun) {
|
|
738
|
-
const { finalizeRunLogSync } = await import("./specialist-logs-
|
|
738
|
+
const { finalizeRunLogSync } = await import("./specialist-logs-pEMCTtGZ.js");
|
|
739
739
|
try {
|
|
740
740
|
finalizeRunLogSync(projectKey, specialistType, metadata.currentRun, {
|
|
741
741
|
status: metadata.lastRunStatus || "incomplete",
|
|
@@ -749,12 +749,12 @@ async function terminateSpecialist(projectKey, specialistType, issueId) {
|
|
|
749
749
|
updateRunMetadata(projectKey, registryKey, { currentActivity: null });
|
|
750
750
|
const key = `${projectKey}-${specialistType}`;
|
|
751
751
|
gracePeriodStates.delete(key);
|
|
752
|
-
const { saveAgentRuntimeState } = await import("./agents-
|
|
752
|
+
const { saveAgentRuntimeState } = await import("./agents-By3u_fQ8.js");
|
|
753
753
|
saveAgentRuntimeState(tmuxSession, {
|
|
754
754
|
state: "suspended",
|
|
755
755
|
lastActivity: (/* @__PURE__ */ new Date()).toISOString()
|
|
756
756
|
});
|
|
757
|
-
const { scheduleDigestGeneration } = await import("./specialist-context-
|
|
757
|
+
const { scheduleDigestGeneration } = await import("./specialist-context-BUTadO-U.js");
|
|
758
758
|
scheduleDigestGeneration(projectKey, specialistType);
|
|
759
759
|
scheduleLogCleanup(projectKey, specialistType);
|
|
760
760
|
}
|
|
@@ -767,7 +767,7 @@ async function terminateSpecialist(projectKey, specialistType, issueId) {
|
|
|
767
767
|
function scheduleLogCleanup(projectKey, specialistType) {
|
|
768
768
|
Promise.resolve().then(async () => {
|
|
769
769
|
try {
|
|
770
|
-
const { cleanupOldLogsSync } = await import("./specialist-logs-
|
|
770
|
+
const { cleanupOldLogsSync } = await import("./specialist-logs-pEMCTtGZ.js");
|
|
771
771
|
const { getSpecialistRetention } = await import("./projects-DbssjAtz.js");
|
|
772
772
|
const retention = getSpecialistRetention(projectKey);
|
|
773
773
|
const deleted = cleanupOldLogsSync(projectKey, specialistType, {
|
|
@@ -922,7 +922,7 @@ function listSpecialistsForProject(projectKey) {
|
|
|
922
922
|
*/
|
|
923
923
|
async function getAllProjectSpecialistStatuses() {
|
|
924
924
|
const registry = loadRegistry();
|
|
925
|
-
const { getAgentRuntimeStateSync } = await import("./agents-
|
|
925
|
+
const { getAgentRuntimeStateSync } = await import("./agents-By3u_fQ8.js");
|
|
926
926
|
const results = [];
|
|
927
927
|
for (const [projectKey, specialists] of Object.entries(registry.projects)) for (const [registryKey, metadata] of Object.entries(specialists)) {
|
|
928
928
|
const { specialistType, issueId, role } = parseSpecialistRegistryKey(registryKey);
|
|
@@ -1059,7 +1059,7 @@ async function getSpecialistStatus(name, projectKey) {
|
|
|
1059
1059
|
const sessionId = readRecordedClaudeSessionId(getTmuxSessionName(name, projectKey));
|
|
1060
1060
|
const running = await isRunning(name, projectKey);
|
|
1061
1061
|
const contextTokens = countContextTokens(name);
|
|
1062
|
-
const { getAgentRuntimeStateSync } = await import("./agents-
|
|
1062
|
+
const { getAgentRuntimeStateSync } = await import("./agents-By3u_fQ8.js");
|
|
1063
1063
|
const runtimeState = getAgentRuntimeStateSync(getTmuxSessionName(name, projectKey));
|
|
1064
1064
|
let state;
|
|
1065
1065
|
if (runtimeState) switch (runtimeState.state) {
|
|
@@ -1158,7 +1158,7 @@ async function sendFeedbackToAgent(feedback) {
|
|
|
1158
1158
|
return false;
|
|
1159
1159
|
}
|
|
1160
1160
|
try {
|
|
1161
|
-
const { messageAgent } = await import("./agents-
|
|
1161
|
+
const { messageAgent } = await import("./agents-By3u_fQ8.js");
|
|
1162
1162
|
await messageAgent(agentSession, `SPECIALIST FEEDBACK: ${fromSpecialist} reported ${feedback.feedbackType.toUpperCase()} for ${toIssueId}.\n\nMUST READ: ${fileResult.filePath}\n\nUse your Read tool to open this file, read every line, then address the feedback and continue working. Do NOT stop at the prompt.`);
|
|
1163
1163
|
console.log(`[specialist] Sent feedback from ${fromSpecialist} to ${agentSession} (file: ${fileResult.filePath})`);
|
|
1164
1164
|
return true;
|
|
@@ -1277,4 +1277,4 @@ var init_specialists = __esmMin((() => {
|
|
|
1277
1277
|
//#endregion
|
|
1278
1278
|
export { updateRunMetadata as $, isEnabled as A, pauseGracePeriod as B, getSpecialistState as C, initSpecialistsDirectory as D, incrementProjectRunCount as E, listSpecialistsForProject as F, sendFeedbackToAgent as G, recordWake as H, loadRegistry as I, specialists_exports as J, setCurrentRun as K, makeSpecialistRegistryKey as L, isProjectSpecialistActivelyRunning as M, isRunning as N, init_specialists as O, listProjectsWithSpecialists as P, updateProjectSpecialistMetadata as Q, parseReviewerSessionName as R, getSpecialistMetadata as S, getTmuxSessionName as T, resumeGracePeriod as U, pruneSpecialistRegistryEntriesForIssue as V, saveRegistry as W, terminateSpecialist as X, startGracePeriod as Y, updateContextTokens as Z, getPendingFeedback as _, disableSpecialist as a, getReviewerSessionName as b, exitGracePeriod as c, getAllProjectSpecialistStatuses as d, updateRunStatus as et, getAllSpecialistStatus as f, getGracePeriodState as g, getFeedbackStats as h, countContextTokens as i, isInitialized as j, initializeEnabledSpecialists as k, findActiveRegistryKey as l, getEnabledSpecialists as m, buildSpecialistBaseCommand as n, enableSpecialist as o, getAllSpecialists as p, signalSpecialistCompletion as q, buildSpecialistCavemanExports as r, ensureProjectSpecialistDir as s, REVIEWER_ROLES as t, updateSpecialistMetadata as tt, findSessionFile as u, getProjectSpecialistDir as v, getSpecialistStatus as w, getRunMetadata as x, getProjectSpecialistMetadata as y, parseSpecialistRegistryKey as z };
|
|
1279
1279
|
|
|
1280
|
-
//# sourceMappingURL=specialists-
|
|
1280
|
+
//# sourceMappingURL=specialists-DeTkkp8b.js.map
|