@overdeck/desktop 0.45.13 → 0.45.16
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/package.json +1 -1
- package/server/{acceptance-criteria-CfujPRrz.js → acceptance-criteria-BZ_nQS1f.js} +2 -2
- package/server/{advancing-selfheal-Bn5QiLtn.js → advancing-selfheal-DJYAvGv-.js} +6 -5
- package/server/{agent-gc-Cl9Nm0Zu.js → agent-gc-D0wDIeV1.js} +3 -3
- package/server/{agent-state-C6Rm6FPR.js → agent-state-lGvgPP4m.js} +1 -1
- package/server/{agent-state-service-U8feBf8t.js → agent-state-service-CZrayD_G.js} +1 -1
- package/server/{agent-state-service-JhFzYCP_.js → agent-state-service-DFslS5go.js} +9 -52
- package/server/{agents-DqQa4Dq_.js → agents-B9GwfCyp.js} +155 -153
- package/server/{agents-CxbuBjID.js → agents-CEcaxSkR.js} +1 -1
- package/server/{archive-planning-CPitEZo4.js → archive-planning-CbghE9-o.js} +5 -5
- package/server/{archive-planning-DmpT1_14.js → archive-planning-CoyIbgGK.js} +1 -1
- package/server/{artifact-index-jobs-sMnNtPhy.js → artifact-index-jobs-CcSrUoSE.js} +2 -2
- package/server/auto-commit-IW-eik_b.js +3 -0
- package/server/{backlog-auto-trigger-Cf9C8fwD.js → backlog-auto-trigger-BfgDsII0.js} +3 -3
- package/server/{bd-process-lock-D1aJxeYv.js → bd-process-lock-XAXAet9O.js} +32 -11
- package/server/{beads-CivpXztb.js → beads-B1u04n3o.js} +1 -1
- package/server/{beads-DRoj6-e1.js → beads-BeSMEjGT.js} +96 -196
- package/server/{beads-query-tOsAYP5h.js → beads-query-Dl4FhT8J.js} +24 -99
- package/server/beads-restore-BUItPOjI.js +23 -0
- package/server/behavior-BTpYbAv4.js +10 -0
- package/server/{briefing-freshness-BL3Q6p7R.js → briefing-freshness-DESTCWo-.js} +4 -4
- package/server/{checkpoint-manager-DCxjQvP_.js → checkpoint-manager-BwFdegJF.js} +2 -2
- package/server/{checkpoint-manager-j5URlFY7.js → checkpoint-manager-DWSXooZV.js} +1 -1
- package/server/checkpoint-worker.js +1 -1
- package/server/{checkpoints-BoX1H2Hf.js → checkpoints-BtUonbs3.js} +2 -2
- package/server/{checkpoints-Bu_M_Q9W.js → checkpoints-fjadfOKF.js} +1 -1
- package/server/{claude-hooks-provision-D-jGXmu1.js → claude-hooks-provision-DAtxutOs.js} +132 -114
- package/server/claude-hooks-provision-DiK62u0k.js +3 -0
- package/server/{claude-permissions-DxIjkOVl.js → claude-permissions-CThLgf8d.js} +2 -2
- package/server/{claude-settings-overlay-BPDS6GfE.js → claude-settings-overlay-BF9MPIwx.js} +2 -2
- package/server/{claude-settings-overlay-5b9X2S0C.js → claude-settings-overlay-Dx_Uqcmv.js} +1 -1
- package/server/{cli-s7bPWy-E.js → cli-ByKIIMfT.js} +9 -9
- package/server/cli-D9cUTbBr.js +3 -0
- package/server/{cliproxy-BituqWtR.js → cliproxy-B4c1BUvs.js} +2 -2
- package/server/{cliproxy-D3sHB0sI.js → cliproxy-C_GuT5DU.js} +1 -1
- package/server/{close-issue-CrBE7voz.js → close-issue-BOuLKr6e.js} +5 -5
- package/server/{closed-issue-reaper-BRQBc7Xa.js → closed-issue-reaper-CksfuiFD.js} +1 -1
- package/server/{closed-issue-reaper-DX9mYUji.js → closed-issue-reaper-DCAYzNXW.js} +102 -30
- package/server/{codex-Bi1ITSOo.js → codex-BYPz6ZdF.js} +1 -1
- package/server/{codex-CO0HrK3j.js → codex-BbqIRZjd.js} +6 -5
- package/server/{behavior-D3d2mVyD.js → codex-parser-mFYZh8vR.js} +3 -9
- package/server/{compact-beads-DUkCUFxA.js → compact-beads-CyJtoXJi.js} +15 -8
- package/server/{compact-beads-CrA8-k10.js → compact-beads-N00E4EVa.js} +1 -1
- package/server/{config-DsCxzjXK.js → config-DVLdmnMJ.js} +2 -2
- package/server/{config-B4_d7z7z.js → config-Dj6N8EP9.js} +1 -1
- package/server/{config-yaml-C_djSurJ.js → config-yaml-cNOZcEww.js} +118 -23
- package/server/{conflict-gate-D47Kl78u.js → conflict-gate-BMKm_5DV.js} +3 -3
- package/server/{conflict-gate-CpOn9KC-.js → conflict-gate-CuXUv-bP.js} +1 -1
- package/server/{context-layers-CHl3Nroz.js → context-layers-CeAwSYNt.js} +2 -2
- package/server/{context-layers-BNhUBTkf.js → context-layers-c0JqYHcS.js} +3 -3
- package/server/{control-settings-KyYNXZLv.js → control-settings-D4EFsRBd.js} +4 -4
- package/server/{conversation-compaction-D3aS5PnS.js → conversation-compaction-BCggyih4.js} +8 -8
- package/server/{conversation-compaction-D4Wed1BJ.js → conversation-compaction-kHVfVRg3.js} +1 -1
- package/server/{conversation-service-CFZIjs-M.js → conversation-service-B8LFQQm1.js} +6 -5
- package/server/{conversation-service-DcDB5usR.js → conversation-service-BTzObqGi.js} +1 -1
- package/server/{conversations-BSOU5qnu.js → conversations-B-lcHv-5.js} +4 -4
- package/server/{conversations-BbDPrz89.js → conversations-BM7zlXjr.js} +1 -1
- package/server/{cost-BE_ulOrw.js → cost-BcpRQ-7o.js} +3 -3
- package/server/{cost-CaiG63FG.js → cost-D9kPIY_5.js} +2 -2
- package/server/{cost-sync-D6AX8jv-.js → cost-sync-DF6odxK9.js} +3 -3
- package/server/{dag-BQFtXOuJ.js → dag-DKI3sOmX.js} +3 -3
- package/server/{dangerous-git-ops-04Ba-Qu3.js → dangerous-git-ops-Bn18PEcN.js} +1 -1
- package/server/dashboard-db-worker.js +6 -6
- package/server/{deacon-Bz-6Wjmn.js → deacon-DONuopff.js} +3 -3
- package/server/{deacon-2EvA9Ci3.js → deacon-DdARMjZq.js} +188 -1601
- package/server/{deacon-swarm-DYYOzHRH.js → deacon-swarm-BNGkmYR_.js} +12 -105
- package/server/deacon-swarm-CvdFekIO.js +2 -0
- package/server/deacon.js +7 -7
- package/server/{devcontainer-renderer-Dx0C7VWJ.js → devcontainer-renderer-C-34Sxyz.js} +3 -3
- package/server/{dist-ya66D9ze.js → dist-BMXvKiZP.js} +1 -1
- package/server/dist-BNwrgsUO.js +3 -0
- package/server/{dist-src-Byxt1ifL.js → dist-src-BgGUblXg.js} +1 -1
- package/server/{docker-D2TbXDO6.js → docker-apZ9pBYw.js} +67 -28
- package/server/{ensure-devcontainer-BTiMfFp5.js → ensure-devcontainer-Bqi1EF1P.js} +4 -4
- package/server/{ensure-devcontainer-BIShzs3M.js → ensure-devcontainer-Dq3KoOIl.js} +1 -1
- package/server/{esm-shims-DiV9jHa_.js → esm-shims-BEjvINX3.js} +1 -1
- package/server/{event-store-C02Gprug.js → event-store-CqDgfbAs.js} +1 -1
- package/server/{event-store-C71x6h0i.js → event-store-D89fMfXS.js} +3 -3
- package/server/{events-BFDuPV6n.js → events-S_C0pvl6.js} +3 -3
- package/server/{events-D2gP2-Yv.js → events-rIGncmP1.js} +1 -1
- package/server/export-BJHSVwKP.js +87 -0
- package/server/{factory-ByfbrCab.js → factory-DV18m0rc.js} +5 -5
- package/server/{feature-registry-population-CSH66UO8.js → feature-registry-population-CqZSnqQi.js} +4 -4
- package/server/{feature-registry-storage-DW7dUefc.js → feature-registry-storage-BeXmNBwK.js} +2 -2
- package/server/{features-x_aLR7U9.js → features-u5XeMaOK.js} +2 -2
- package/server/{feedback-target-BFo9fScH.js → feedback-target-CwyWf0Dg.js} +6 -6
- package/server/{feedback-target-C4VMPTZu.js → feedback-target-DDG1PWl3.js} +1 -1
- package/server/{feedback-writer-DCyd75yJ.js → feedback-writer-BsJiw5aT.js} +1 -1
- package/server/{feedback-writer-B9ZqnnX3.js → feedback-writer-D20HSXre.js} +4 -4
- package/server/{flywheel-DwQCoZQG.js → flywheel-9Y1X7IM-.js} +13 -13
- package/server/{flywheel-D9NKvWqb.js → flywheel-Dczmgchd.js} +23 -15
- package/server/{flywheel-DB48X7Nn.js → flywheel-RCnHAgc4.js} +1 -1
- package/server/{flywheel-merge-order-DrjmFXg4.js → flywheel-merge-order-CtCYsFJP.js} +7 -7
- package/server/{flywheel-merge-order-f1bi5XIf.js → flywheel-merge-order-DEtEd3aK.js} +1 -1
- package/server/forge-8y6aEPTB.js +2 -0
- package/server/{forge-C-SoKy8U.js → forge-DFDThFil.js} +2 -2
- package/server/{from-fu7ZumnY.js → from-NSJypkI8.js} +1 -1
- package/server/{fts-db-CL-YzSRG.js → fts-db-C5A_TTOM.js} +2 -2
- package/server/{fts-operations-Bylu5NjM.js → fts-operations-DvCSimfU.js} +2 -2
- package/server/{git-utils-Ym380hJZ.js → git-utils-C0neHvQx.js} +1 -1
- package/server/{git-utils-C8koBs8j.js → git-utils-Dr0L7mFk.js} +2 -2
- package/server/{github-app-DIr70YLg.js → github-app-Bwt9lK4A.js} +1 -1
- package/server/{github-app-DhycHVLF.js → github-app-u9-SX7Gc.js} +2 -2
- package/server/{github-client-7gkcXcBS.js → github-client-Btyy3uan.js} +3 -3
- package/server/{github-client-Ji9lUTNF.js → github-client-Do3k-N1W.js} +1 -1
- package/server/{github-pr-lookup-rt7T9FwA.js → github-pr-lookup-DOF1U2WW.js} +2 -2
- package/server/{harness-resolve-CvGXUnAF.js → harness-resolve-C6g2R0Cd.js} +3 -3
- package/server/{health-events-D4E1DLN-.js → health-events-B4u-2a9m.js} +2 -2
- package/server/{health-events-DDfkoO5a.js → health-events-Bos3sk5g.js} +1 -1
- package/server/{hooks-D_6pAbuJ.js → hooks-BCoOjL_R.js} +2 -2
- package/server/{hooks-DvdnCVv6.js → hooks-uEr8WTx_.js} +1 -1
- package/server/{hume-DkVOs1Qi.js → hume-BqxYKbUf.js} +2 -2
- package/server/hume-CerGi2RH.js +3 -0
- package/server/{idle-stack-reaper-cDRXDpgE.js → idle-stack-reaper-DbZ8ukMd.js} +2 -2
- package/server/{idle-stack-reaper-DNbV9-fj.js → idle-stack-reaper-H0W6XtHh.js} +1 -1
- package/server/{infra-Clew3DpF.js → infra-Ba9mS6e6.js} +3 -3
- package/server/{injection-QCIHOpk6.js → injection-C1DKXeIZ.js} +1 -1
- package/server/{injection-ql0Nddcn.js → injection-yrMBxzVq.js} +7 -7
- package/server/{inspect-agent-DY18KEx4.js → inspect-agent-B-mnb4uh.js} +9 -9
- package/server/inspect-agent-CWkeAB7J.js +2 -0
- package/server/{internal-token-C90jBp-y.js → internal-token-BPYEaXFh.js} +1 -1
- package/server/{internal-token-BeXjPLKy.js → internal-token-BtqSbKTx.js} +2 -2
- package/server/{io-CbAFXQge.js → io-VEGSAqsd.js} +15 -22
- package/server/{issue-closed-BYC2TCk-.js → issue-closed-BxcePXL-.js} +4 -4
- package/server/{issue-lifecycle-BoJa6qIt.js → issue-lifecycle--8MRxrG1.js} +22 -22
- package/server/{issue-lifecycle-CLHbj8RS.js → issue-lifecycle-CdMUauyb.js} +1 -1
- package/server/{issue-service-singleton-BS9NENuR.js → issue-service-singleton-CkTUI-eu.js} +10 -10
- package/server/{issue-service-singleton-3g_CCY-1.js → issue-service-singleton-MZsDhAob.js} +1 -1
- package/server/{issues-BPcqPqfV.js → issues-CBAsuoAO.js} +2 -2
- package/server/jsonl-parser-BUW5_sSK.js +245 -0
- package/server/{label-cleanup-CwiCSZrb.js → label-cleanup-htK6fBRU.js} +3 -3
- package/server/{layers-OHHLphl0.js → layers-jjL16At6.js} +2 -2
- package/server/{lifecycle-B8IdvUbt.js → lifecycle-Ck2UR27D.js} +7 -7
- package/server/{lifecycle-io-BMCH1Bxg.js → lifecycle-io-DXv8Utct.js} +1 -1
- package/server/{lifecycle-io-C73m5e6R.js → lifecycle-io-IehcRt2v.js} +36 -47
- package/server/{linear-client-BMxgycoy.js → linear-client-By7hjwuN.js} +1 -1
- package/server/{linear-client-CgQlM4aT.js → linear-client-D9cSQfvD.js} +3 -3
- package/server/memory-fts-worker.js +1 -1
- package/server/{merge-BRkVaIx-.js → merge-BLcEZNXz.js} +1 -1
- package/server/{merge-B7Oi-g6k.js → merge-BN8FGJ2q.js} +3 -3
- package/server/{merge-agent-DNFFsiEm.js → merge-agent-B3u2szOL.js} +29 -29
- package/server/{merge-agent-Bwm34MZ5.js → merge-agent-ejC7Wos8.js} +1 -1
- package/server/{merge-batch-BpYXUaqJ.js → merge-batch-DyqlgYGp.js} +1 -1
- package/server/{merge-blockers-DIOZmqdK.js → merge-blockers-cq-aS2KG.js} +2 -2
- package/server/merge-ops-CFkQtXEj.js +2 -0
- package/server/{merge-rebase-C8WH39MB.js → merge-rebase-Dl7yIxtV.js} +2 -2
- package/server/{merge-set-CsEE2CyQ.js → merge-set-CZ9Nbay0.js} +3 -3
- package/server/{merge-set-DOsBTBQc.js → merge-set-Dy0D0r3i.js} +1 -1
- package/server/{merge-sync-CcLM2vwW.js → merge-sync-CG9kDCdT.js} +1 -1
- package/server/{merge-sync-C2B322Ot.js → merge-sync-D7jWLgCC.js} +2 -2
- package/server/{merge-train-BIm7-7cy.js → merge-train-CH33XJOH.js} +3 -3
- package/server/{merge-train-deps-DG1oQ2DT.js → merge-train-deps-JoVdGnOg.js} +4 -4
- package/server/{merge-verification-BAbjxEd5.js → merge-verification-D4wTChdX.js} +4 -4
- package/server/{multipart-parser-jKtKAXtl.js → multipart-parser-Csn8U-K9.js} +2 -2
- package/server/{no-resume-mode-yrPEQ_pC.js → no-resume-mode-Gh5R_YLF.js} +1 -1
- package/server/node_modules/.package-lock.json +1 -1
- package/server/{orphan-proposed-reconciler-BqVGaOIj.js → orphan-proposed-reconciler-BIcNu4tl.js} +1 -1
- package/server/{orphan-proposed-reconciler-zHrwJ3xr.js → orphan-proposed-reconciler-DI_IS1p_.js} +15 -39
- package/server/package-lock.json +2 -2
- package/server/package.json +1 -1
- package/server/{pan-dir-BlNrLzW7.js → pan-dir-CQIfKG8c.js} +4 -4
- package/server/{paths-CiVeo4N_.js → paths-Blj6A9AJ.js} +2 -2
- package/server/{pickup-KLRUhThD.js → pickup-BtvRBbvI.js} +1 -1
- package/server/{pipeline-notifier-nkWCe042.js → pipeline-notifier-BH4PAi-w.js} +1 -1
- package/server/{pipeline-notifier-DBF6dHxH.js → pipeline-notifier-D_WYtEwl.js} +2 -2
- package/server/project-pipelines-jMTitpeO.js +162 -0
- package/server/projects-CrBE6IhN.js +3 -0
- package/server/{prompts-CXbQvevY.js → prompts-B3njaImU.js} +2 -2
- package/server/{providers-CUdAb5Qu.js → providers-BbEyFhPX.js} +7 -7
- package/server/providers-DnPxkHoG.js +3 -0
- package/server/public/assets/chunk-BO2N2NFS-3qh9TUJi.js +103 -0
- package/server/public/assets/{diagram-OG6HWLK6-NACO1xW5.js → diagram-OG6HWLK6-D8UVTPj7.js} +1 -1
- package/server/public/assets/{dist-DQD-ZjQY.js → dist-BvLLn1YC.js} +3 -3
- package/server/public/assets/{dist-D1FjqGgm.js → dist-CyubL7Wj.js} +1 -1
- package/server/public/assets/{ganttDiagram-6RSMTGT7-CEMAKgmE.js → ganttDiagram-6RSMTGT7-BI4E1LbQ.js} +1 -1
- package/server/public/assets/{highlighted-body-OFNGDK62-D5lC7FW8.js → highlighted-body-OFNGDK62-D_bapWkF.js} +1 -1
- package/server/public/assets/index-BAZxZ-8I.js +796 -0
- package/server/public/assets/index-FBG3JBfq.css +1 -0
- package/server/public/assets/{linear-DDHAMRPB.js → linear-CEdobObr.js} +1 -1
- package/server/public/assets/mermaid-GHXKKRXX-BYP8MI37.js +1 -0
- package/server/public/assets/{pieDiagram-4H26LBE5-DwBdeKBb.js → pieDiagram-4H26LBE5-DT79L01f.js} +1 -1
- package/server/public/assets/{prod-DAZt0c4G.js → prod-CR_K2DFV.js} +4 -4
- package/server/public/assets/{quadrantDiagram-W4KKPZXB-CNDLp-_m.js → quadrantDiagram-W4KKPZXB-BEkKXXrL.js} +1 -1
- package/server/public/assets/{sankeyDiagram-5OEKKPKP-oIUL_uO1.js → sankeyDiagram-5OEKKPKP-BxSCqn-j.js} +1 -1
- package/server/public/assets/{xychartDiagram-2RQKCTM6-B-IM6Cck.js → xychartDiagram-2RQKCTM6-DicwJGG_.js} +1 -1
- package/server/public/index.html +2 -2
- package/server/{pull-requests-DZ-V7_LB.js → pull-requests-43LPDfM8.js} +1 -1
- package/server/{pull-requests-kTRl7cWC.js → pull-requests-DyUkQl4W.js} +3 -3
- package/server/{rally-xCTZ-UcI.js → rally-BtWjybOa.js} +3 -3
- package/server/{rally-api-jOk4vit_.js → rally-api-B-YA_oXx.js} +1 -1
- package/server/{rally-api-DpZo3WwF.js → rally-api-B-osULNL.js} +2 -2
- package/server/{rally-client-BQjm3aaq.js → rally-client-CzFymP7P.js} +1 -1
- package/server/{rally-client-CoWZeVEj.js → rally-client-sErNQBO0.js} +5 -5
- package/server/rally-oggyp4cs.js +3 -0
- package/server/{reap-terminal-sessions-CAmURC2h.js → reap-terminal-sessions-2s-fvilz.js} +1 -1
- package/server/{reap-terminal-sessions-BwJb2DLJ.js → reap-terminal-sessions-DnDQ7pf9.js} +1 -1
- package/server/{rebuild-stack-BZ7j27xY.js → rebuild-stack-CoU-HqZj.js} +6 -6
- package/server/{rebuild-stack-r-cxcr26.js → rebuild-stack-nGD_nPZo.js} +1 -1
- package/server/{reconstruct-cache-13EkMg_i.js → reconstruct-cache-Wj8GrYB0.js} +6 -6
- package/server/record-lEYK__LD.js +3 -0
- package/server/recovery-trip-BT7nb9OV.js +98 -0
- package/server/{release-engine-YLTnEO_K.js → release-engine-CBLQXDlH.js} +5 -5
- package/server/{release-set-DwvT_Opu.js → release-set-BNiqi7hy.js} +3 -3
- package/server/{remote-B062S1Kc.js → remote-DW_TWQnr.js} +3 -3
- package/server/{remote-9u9WL0NJ.js → remote-DcO9An_f.js} +3 -3
- package/server/{remote-agents-BBTg-vLT.js → remote-agents-C4cyxHQS.js} +6 -6
- package/server/{remote-agents-B4eWgwNd.js → remote-agents-Cv-U-_V8.js} +1 -1
- package/server/{remote-completion-B0rmBnbL.js → remote-completion-PhXGGFQy.js} +13 -13
- package/server/resolver-C7dLn8OK.js +158 -0
- package/server/resume-BYZBIab-.js +3 -0
- package/server/{review-agent-tfR5RDzG.js → review-agent-Dn-yn7Zj.js} +23 -23
- package/server/{review-agent-Bf9XjLnl.js → review-agent-u5q3ip7H.js} +1 -1
- package/server/{review-artifacts-D0_IE6DQ.js → review-artifacts-D4T04aYI.js} +6 -6
- package/server/{review-context-CXO5ml5D.js → review-context-Rc0VDLG_.js} +8 -8
- package/server/{review-monitor-DfFUSx0J.js → review-monitor-BC--miCO.js} +2 -2
- package/server/{review-status-B0Axo-Ma.js → review-status-CG0iDuWa.js} +1 -1
- package/server/{review-status-BcfwcAcO.js → review-status-Dc1l4dVz.js} +18 -18
- package/server/{review-status-enrichment-Cp5kFTGl.js → review-status-enrichment-C1a1OG_1.js} +3 -3
- package/server/{review-status-sync-CEFty1pW.js → review-status-sync-CAr-hfnJ.js} +2 -2
- package/server/{review-status-sync-Bc0c_u12.js → review-status-sync-CfSixhhX.js} +1 -1
- package/server/{review-verdict-feedback-BOKRLLDf.js → review-verdict-feedback-CVDbIDBe.js} +7 -7
- package/server/{review-verdict-feedback-BnGtT0vN.js → review-verdict-feedback-D2Q960wX.js} +1 -1
- package/server/{rollup-BVqFuiS9.js → rollup-CakjztPl.js} +1 -1
- package/server/{rollup-C22QDVxh.js → rollup-DctoIu-A.js} +8 -8
- package/server/{scanner-BLCnuXqY.js → scanner-BTM1jc_u.js} +7 -7
- package/server/{sequence-io-BozlUb6f.js → sequence-io-pnoIDGv4.js} +4 -4
- package/server/{sequencer-agent-BEDEHfd2.js → sequencer-agent-9Soi-WL-.js} +10 -6
- package/server/server.js +1239 -1836
- package/server/{service-C8jKYZ0w.js → service-DfTVoqJg.js} +1668 -1408
- package/server/{session-fork-BDGksK4e.js → session-fork-C4jAFHj8.js} +2 -2
- package/server/session-history-DanhhiCw.js +168 -0
- package/server/{settings-CSLhh6qR.js → settings-Cuc12oP_.js} +2 -2
- package/server/settings-Cy7SCFO9.js +2 -0
- package/server/{settings-DrRQCren.js → settings-DfT3f86D.js} +3 -3
- package/server/{shadow-engineering-BMcBN-Of.js → shadow-engineering-bKuKTCn-.js} +3 -3
- package/server/{shadow-state-CHqWHD3T.js → shadow-state-CVHpRWlb.js} +1 -1
- package/server/{shadow-state-B4ayC7nx.js → shadow-state-DJz6_pb_.js} +2 -2
- package/server/{ship-log-CDVmOlZP.js → ship-log-CwqPFfqx.js} +1 -1
- package/server/{smart-compaction-V9DBrGcr.js → smart-compaction-B4KlpZGN.js} +1 -1
- package/server/{smart-compaction-C-F5sP9P.js → smart-compaction-CiWfGfRZ.js} +7 -7
- package/server/{spawn-planning-session-dSpOU0lP.js → spawn-planning-session-CU-DwyDl.js} +15 -15
- package/server/{spawn-planning-session-Bz4_JES2.js → spawn-planning-session-D5N3RuLG.js} +1 -1
- package/server/{specialist-completion-Coz3eTSr.js → specialist-completion-CJcv-NXH.js} +1 -1
- package/server/{specialist-context-fmb03vXQ.js → specialist-context-B2HlbNxS.js} +5 -5
- package/server/{specialist-handoff-logger-B9HK_lRu.js → specialist-handoff-logger-CQyF1ygu.js} +2 -2
- package/server/{specialist-logs-B24R2B9Y.js → specialist-logs-CdcUpfjj.js} +3 -3
- package/server/{specialists-CL7E8yUg.js → specialists-CFgw_0Q6.js} +1657 -113
- package/server/{specialists-BGNZ0_ZW.js → specialists-CwzFdapR.js} +20 -256
- package/server/{specialists-B6f5-5nG.js → specialists-D7AcFi1u.js} +1 -1
- package/server/{specialists-Chvvwf5z.js → specialists-k22_Btaq.js} +1 -1
- package/server/specs-RzcDgozr.js +3 -0
- package/server/{src-DGAEtABV.js → src-B4TTzNSr.js} +84 -2
- package/server/{src-BVxZuHMg.js → src-BvpMg4EB.js} +3 -3
- package/server/{src-D-VXCC9C.js → src-D4YUZrwR.js} +6 -6
- package/server/{stack-health-C-le5erA.js → stack-health-CSgcYcr8.js} +2 -2
- package/server/{stack-health-BKbTTOT2.js → stack-health-DVN7zRnL.js} +1 -1
- package/server/{state-home-CoyWsECg.js → state-home-CEvD_v5F.js} +6 -6
- package/server/{state-mapping-BvAgFK8n.js → state-mapping-C13UaCL7.js} +1 -1
- package/server/stuck-remediation-CxsyxwFO.js +1513 -0
- package/server/stuck-remediation-nTIvhGOR.js +2 -0
- package/server/{summary-fork-BF_0vxrq.js → summary-fork-CnRMPCYd.js} +2 -2
- package/server/{summary-fork-BlE30Q-I.js → summary-fork-gKSoFAnK.js} +8 -8
- package/server/{supervisor-BSeML_p0.js → supervisor-CZMs8s0M.js} +2 -2
- package/server/supervisor-CfX192ma.js +2 -0
- package/server/{swarm-readiness-CQ4sjrXc.js → swarm-readiness-h6-pwY8w.js} +3 -3
- package/server/{system-prerequisites-DnmLYOnU.js → system-prerequisites-DZZTi2G6.js} +1 -1
- package/server/{teardown-workspace-CpcjDrZ4.js → teardown-workspace-B4D-oCVg.js} +37 -68
- package/server/{test-agent-queue-Bq298zZl.js → test-agent-queue-CnuYku4B.js} +6 -6
- package/server/{test-verdict-CCDd25uN.js → test-verdict-CRsPpByy.js} +1 -1
- package/server/{test-verdict-Bm4uv_AA.js → test-verdict-CXMLATGc.js} +1 -1
- package/server/{tldr-daemon-Rn1Zue0P.js → tldr-daemon-CgZQ3jmZ.js} +1 -1
- package/server/{tldr-daemon-CaSUXd9r.js → tldr-daemon-CuA8hz21.js} +2 -2
- package/server/{tmux-CbcrkUx5.js → tmux-By8E_Yv_.js} +1 -1
- package/server/{tmux-BVc-NeKM.js → tmux-C3g9VFcg.js} +2 -2
- package/server/{token-D2OC_9ms.js → token-g_sJ19g3.js} +2 -2
- package/server/token-util-C9u4An3K.js +3 -0
- package/server/{token-util-CROoF5ic.js → token-util-DiwnnbJo.js} +1 -1
- package/server/{tracker-config-EsBoOWEy.js → tracker-config-BzfVj41Z.js} +1 -1
- package/server/{tracker-config-C1Y_2CIo.js → tracker-config-dQxC15vH.js} +2 -2
- package/server/{tracker-utils-lph9C3Pw.js → tracker-utils--z8FLSWn.js} +2 -2
- package/server/{tracker-utils-DSb9cfrF.js → tracker-utils-DkKyRT0H.js} +1 -1
- package/server/{traefik-connect-5EP1WS_Z.js → traefik-connect-CZYB3dlm.js} +1 -1
- package/server/{tunnel-BFBCeo97.js → tunnel-BpWZs0Jy.js} +3 -3
- package/server/{tunnel-DDe-ATFF.js → tunnel-CN2px87h.js} +1 -1
- package/server/{typed-errors-DSPn_xWP.js → typed-errors-CrN1AByg.js} +1 -1
- package/server/{typed-errors-BEJhbjJg.js → typed-errors-sLpGfegz.js} +1 -1
- package/server/{types-CE1m_daD.js → types-BLS_Zbmd.js} +1 -1
- package/server/{types-B5u3NxMl.js → types-tlXf80x3.js} +1 -1
- package/server/{uat-train-DtKHHy1U.js → uat-train-BRo6DM7p.js} +24 -24
- package/server/{uat-train-8T24rPzc.js → uat-train-utGVmqdm.js} +1 -1
- package/server/{validation-lyudzPvD.js → validation-CsPVsoA0.js} +4 -4
- package/server/{validation-COOXwNXU.js → validation-Dq_wwcw3.js} +1 -1
- package/server/{verification-runner-DO0nYTJx.js → verification-runner-CMT5WRMS.js} +12 -12
- package/server/{verification-runner-Dd1FX8Qk.js → verification-runner-D0Uh-9jc.js} +1 -1
- package/server/{vtt-parser-C57tEF7-.js → vtt-parser-C_XPlifj.js} +1 -1
- package/server/{work-agent-prompt-B2F3ZwKm.js → work-agent-prompt-ZTAb2Hyf.js} +12 -12
- package/server/workflows-BLwxUMP7.js +2 -0
- package/server/{workflows-Clz_AFwR.js → workflows-CXRwhw_o.js} +14 -14
- package/server/{workspace-D0rCFemz.js → workspace-9UEsKuiP.js} +1 -1
- package/server/{workspace-CY_2-Ddv.js → workspace-CNfuj1-5.js} +3 -3
- package/server/{workspace-config-DA8U97k9.js → workspace-config-ChWOECy0.js} +1 -1
- package/server/{workspace-manager-BIfpzqdU.js → workspace-manager-BO-6k3sP.js} +1 -1
- package/server/{workspace-manager-D6NgGkiF.js → workspace-manager-D8AByFIT.js} +13 -13
- package/server/{workspace-metadata-C8yn8kAH.js → workspace-metadata-CvC268MN.js} +2 -2
- package/server/{workspace-metadata-DfgR40YU.js → workspace-metadata-DZiJtnuF.js} +1 -1
- package/server/{workspaces-DOeHyKmA.js → workspaces-D-uIoqbg.js} +104 -122
- package/server/writer-BUweuRPx.js +3 -0
- package/server/writer-CrP2xuBn.js +251 -0
- package/sync-sources/hooks/ask-user-question-hook +7 -1
- package/sync-sources/hooks/record-cost-event.js +4 -3
- package/sync-sources/hooks/record-cost-event.js.map +1 -1
- package/server/agent-runtime-mirror-DrWxopNA.js +0 -37
- package/server/auto-commit-wZ9X7Isd.js +0 -3
- package/server/bd-mutex-BItGvLQ8.js +0 -35
- package/server/beads-restore-CMbDSB5R.js +0 -60
- package/server/cli-CqgiSAU8.js +0 -3
- package/server/deacon-swarm-B8pgK2a7.js +0 -2
- package/server/dist-BYSj075e.js +0 -3
- package/server/forge-CUCYK7h_.js +0 -2
- package/server/hume-x9voULey.js +0 -3
- package/server/inspect-agent-D8UBDgfR.js +0 -2
- package/server/merge-ops-B7m-hBEZ.js +0 -2
- package/server/projects-BqRMlDOv.js +0 -3
- package/server/providers-gZ0cUgQM.js +0 -3
- package/server/public/assets/chunk-BO2N2NFS-C-6y8VFI.js +0 -103
- package/server/public/assets/index-BDqWyuZQ.js +0 -796
- package/server/public/assets/index-CZiADHcL.css +0 -1
- package/server/public/assets/mermaid-GHXKKRXX-DRM2ANcR.js +0 -1
- package/server/rally-CRteqXe0.js +0 -3
- package/server/record-CJsjvRO4.js +0 -3
- package/server/resume-R7xkSmLW.js +0 -3
- package/server/settings-CSaXtkoA.js +0 -2
- package/server/specs-oaaYaA5c.js +0 -3
- package/server/supervisor-03Tj_Wra.js +0 -2
- package/server/token-util-xNaV-00f.js +0 -3
- package/server/workflows-B4fIN8VP.js +0 -2
|
@@ -1,695 +1,54 @@
|
|
|
1
1
|
import { i as __require, t as __commonJSMin } from "./rolldown-runtime-DNCzzKnI.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Bt as writeIssueRecordSync, Ct as ensureIssueRecordSync, En as getIssuePrefix, Fn as init_projects, Jr as init_paths, Nt as readIssueRecordForWorkspaceSync, Pt as readIssueRecordSync, Qr as sessionFilePath, Sr as AGENTS_DIR, dn as init_state_plane, f as loadConfigSync, in as init_auto_commit, jr as OVERDECK_HOME, kn as getProjectSync, kt as init_record, ln as STATE_PLANE_PATHS, on as queueBeadsAutoCommit, pn as isStatePlanePath, qn as resolveProjectFromIssueSync, s as init_load, sn as reconcileStatePlaneDrift, un as getMainDivergence, xr as init_errors, zn as listProjectsSync } from "./config-yaml-cNOZcEww.js";
|
|
3
3
|
import { a as init_activity_logger, n as emitActivityEntrySync, r as emitActivityTtsSync } from "./activity-logger-pcbf-e30.js";
|
|
4
|
-
import { C as isPaneDead,
|
|
5
|
-
import { a as init_event_store, i as initEventStore } from "./event-store-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import { a as queryBeadsForIssue, o as queryReadyBeadsByIssueLabels, r as init_beads_query, s as resolveBeadsQueryRoot } from "./beads-query-tOsAYP5h.js";
|
|
21
|
-
import { n as __filename, r as init_esm_shims } from "./esm-shims-DiV9jHa_.js";
|
|
22
|
-
import { O as init_specialists, R as parseReviewerSessionName, T as getTmuxSessionName, at as init_jsonl_parser, d as getAllProjectSpecialistStatuses, it as getSessionFilesSync, rt as getProjectDirsSync, st as parseClaudeSessionSync } from "./specialists-BGNZ0_ZW.js";
|
|
4
|
+
import { C as isPaneDead, E as listPaneValues, F as sendKeysAsync, L as sessionExists, O as listSessionNames, P as sendKeys, R as sessionExistsSync, i as capturePane, k as listSessions, w as killSession, x as init_tmux } from "./tmux-C3g9VFcg.js";
|
|
5
|
+
import { a as init_event_store, i as initEventStore } from "./event-store-D89fMfXS.js";
|
|
6
|
+
import { C as init_record_lock, S as needsReviewDispatch, c as init_review_status, h as reviewGatesPassedSync, s as getReviewStatusSync, u as loadReviewStatuses, w as withIssueRecordLock, x as init_review_dispatch_decision, y as setReviewStatusSync } from "./review-status-Dc1l4dVz.js";
|
|
7
|
+
import { d as init_agents, g as isTerminalIssueStage, h as getIssueStageSync, p as listAllAgentsSync } from "./briefing-freshness-DESTCWo-.js";
|
|
8
|
+
import { An as getAgentDir, Bn as markAgentRunningState, D as init_context_overflow, Dn as clearAgentTroubledSync, Dt as captureTranscriptUserRecordSnapshot, E as resumeAgent, Fn as init_agent_state, G as init_termination, Jn as saveAgentStateSync, K as stopAgent, Kn as resetAgentFailureCount, Mn as getAgentState, On as clearYieldForResumeSync, Ot as init_transcript_landing, Pn as getAgentStateSync, Q as listRunningAgentsSync, Un as recordAgentFailure, X as listAgentStates, Xn as setAgentPausedSync, Y as init_queries, Z as listRunningAgents, Zn as setAgentYieldedSync, _t as init_config, at as init_concurrency, ct as resetPatrolDispatchBudget, dt as workResumeSlotsAvailable, et as countRunningAgents, fr as getAgentRuntimeState, gn as buildDefaultResumeContinueMessage, hr as saveAgentRuntimeState, it as getConcurrencyLimits, k as isContextOverflowTail, lt as tryReserveAdvancingSlot, mr as init_runtime_state, mt as setCachedMemoryVerdict, nt as describeRunningAgents, ot as releaseAdvancingSlot, pr as getAgentRuntimeStateSync, pt as init_memory_verdict_cache, qn as saveAgentState, t as init_agents$1, vt as loadCloisterConfig, wt as deliverInitialPromptWithRetry, yt as loadCloisterConfigSync } from "./agents-B9GwfCyp.js";
|
|
9
|
+
import { c as logDeaconEventSync, o as init_persistent_logger, s as logAgentLifecycleSync } from "./session-history-DanhhiCw.js";
|
|
10
|
+
import { i as resolveGitHubIssueSync, n as init_tracker_utils } from "./tracker-utils--z8FLSWn.js";
|
|
11
|
+
import { n as mapGitHubStateToCanonical, t as init_state_mapping } from "./state-mapping-C13UaCL7.js";
|
|
12
|
+
import { c as init_review_status_sync, l as markWorkspaceStuck } from "./review-status-sync-CAr-hfnJ.js";
|
|
13
|
+
import { f as init_config$1, m as loadConfigSync$1, p as loadConfig$1 } from "./config-DVLdmnMJ.js";
|
|
14
|
+
import { n as init_state_home, t as findRecreatedLegacyStatePaths } from "./state-home-CEvD_v5F.js";
|
|
15
|
+
import { T as stampBootReconciliation, h as setBootReconciliationDecision, l as isDeaconGloballyPaused, r as getBootReconciliationState, s as init_control_settings } from "./control-settings-D4EFsRBd.js";
|
|
16
|
+
import { c as init_docker_stats, s as DockerStatsCollector } from "./stack-health-CSgcYcr8.js";
|
|
17
|
+
import { a as queryBeadsForIssue, o as queryReadyBeadsByIssueLabels, r as init_beads_query, s as resolveBeadsQueryRoot } from "./beads-query-Dl4FhT8J.js";
|
|
18
|
+
import { a as isAgentIdleForNudge, t as checkStuckAgentRemediation } from "./stuck-remediation-CxsyxwFO.js";
|
|
19
|
+
import { n as __filename, r as init_esm_shims } from "./esm-shims-BEjvINX3.js";
|
|
23
20
|
import { t as recordDeaconNudge } from "./deacon-nudge-log-B-naf89q.js";
|
|
24
|
-
import { n as init_review_monitor, t as REVIEW_SUB_ROLES } from "./review-monitor-
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import { n as
|
|
28
|
-
import { n as
|
|
29
|
-
import { n as
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import { n as
|
|
35
|
-
import { a as
|
|
36
|
-
import { n as
|
|
37
|
-
import {
|
|
21
|
+
import { n as init_review_monitor, t as REVIEW_SUB_ROLES } from "./review-monitor-BC--miCO.js";
|
|
22
|
+
import { O as init_specialists, R as parseReviewerSessionName, T as getTmuxSessionName, d as getAllProjectSpecialistStatuses } from "./specialists-CwzFdapR.js";
|
|
23
|
+
import { a as inferBranchFromWorkspace, i as findWorkspacePath, o as init_archive_planning } from "./archive-planning-CbghE9-o.js";
|
|
24
|
+
import { n as init_issue_closed, r as isIssueClosed } from "./issue-closed-BxcePXL-.js";
|
|
25
|
+
import { n as shouldSkipDispatchAsMerged, t as init_merge_verification } from "./merge-verification-D4wTChdX.js";
|
|
26
|
+
import { n as init_review_verdict_feedback, t as deliverReviewVerdictFeedback } from "./review-verdict-feedback-CVDbIDBe.js";
|
|
27
|
+
import { n as reconcileTraefikNetworks, t as init_traefik_connect } from "./traefik-connect-CZYB3dlm.js";
|
|
28
|
+
import { g as decideAgentAutonomousRedrive, r as coordinateSwarmSlots, y as listFeatureWorkspaces } from "./deacon-swarm-BNGkmYR_.js";
|
|
29
|
+
import { t as recordRecoveryFailure } from "./recovery-trip-BT7nb9OV.js";
|
|
30
|
+
import { n as isExplicitNoResumeRequest, t as init_no_resume_mode } from "./no-resume-mode-Gh5R_YLF.js";
|
|
31
|
+
import { n as reconcileClosedIssueAgents } from "./closed-issue-reaper-DCAYzNXW.js";
|
|
32
|
+
import { a as RELEASED_LABEL, i as READY_LABEL, n as OBJECTION_LABEL, o as VETOED_LABEL, r as PARKED_LABEL, t as BLOCKS_MAIN_LABEL } from "./pickup-BtvRBbvI.js";
|
|
33
|
+
import { n as pruneTerminalStoppedAgents } from "./agent-gc-D0wDIeV1.js";
|
|
34
|
+
import { a as spawnWorkAgentThroughAgentsEndpoint, i as reconcileOrphanProposedSpecs, o as triggerRebuildAndStart } from "./orphan-proposed-reconciler-DI_IS1p_.js";
|
|
35
|
+
import { n as reconcileIdleWorkspaceStacks } from "./idle-stack-reaper-DbZ8ukMd.js";
|
|
36
|
+
import { i as readTestVerdictArtifact, n as decideUnsignaledTestAction, r as init_test_verdict } from "./test-verdict-CXMLATGc.js";
|
|
38
37
|
import { createRequire } from "node:module";
|
|
39
38
|
import { join } from "node:path";
|
|
40
39
|
import { Effect } from "effect";
|
|
41
|
-
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync,
|
|
40
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "fs";
|
|
42
41
|
import { dirname as dirname$1, join as join$1 } from "path";
|
|
43
|
-
import { cpus,
|
|
42
|
+
import { cpus, loadavg } from "os";
|
|
44
43
|
import { cpus as cpus$1, freemem as freemem$1, homedir as homedir$1, loadavg as loadavg$1, platform as platform$1, totalmem as totalmem$1 } from "node:os";
|
|
45
44
|
import { closeSync as closeSync$1, existsSync as existsSync$1, openSync as openSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, unlinkSync as unlinkSync$1, writeFileSync as writeFileSync$1 } from "node:fs";
|
|
46
45
|
import { access, readFile } from "node:fs/promises";
|
|
47
|
-
import { readFile as readFile$1, readdir as readdir$1,
|
|
46
|
+
import { readFile as readFile$1, readdir as readdir$1, writeFile as writeFile$1 } from "fs/promises";
|
|
48
47
|
import { exec, execFile, spawn } from "node:child_process";
|
|
49
48
|
import { promisify } from "node:util";
|
|
50
49
|
import { exec as exec$1, execFile as execFile$1, spawn as spawn$1 } from "child_process";
|
|
51
50
|
import { promisify as promisify$1 } from "util";
|
|
52
|
-
import "node:crypto";
|
|
53
51
|
import { layer } from "@effect/platform-node/NodeServices";
|
|
54
|
-
//#region ../../lib/agent-input-detection.ts
|
|
55
|
-
init_paths();
|
|
56
|
-
init_activity_logger();
|
|
57
|
-
init_issue_id();
|
|
58
|
-
init_projects();
|
|
59
|
-
init_state_plane();
|
|
60
|
-
init_auto_commit();
|
|
61
|
-
init_record();
|
|
62
|
-
init_load();
|
|
63
|
-
init_event_store();
|
|
64
|
-
init_agents();
|
|
65
|
-
init_tracker_utils();
|
|
66
|
-
init_state_mapping();
|
|
67
|
-
init_review_status_sync();
|
|
68
|
-
init_record_lock();
|
|
69
|
-
init_review_dispatch_decision();
|
|
70
|
-
init_review_status();
|
|
71
|
-
init_config$1();
|
|
72
|
-
init_behavior();
|
|
73
|
-
init_runtime_state();
|
|
74
|
-
init_persistent_logger();
|
|
75
|
-
init_agent_state();
|
|
76
|
-
init_codex();
|
|
77
|
-
init_pi_fifo();
|
|
78
|
-
init_control_settings();
|
|
79
|
-
init_docker_stats();
|
|
80
|
-
init_launcher_generator();
|
|
81
|
-
init_beads_query();
|
|
82
|
-
init_transcript_landing();
|
|
83
|
-
init_config();
|
|
84
|
-
init_memory_verdict_cache();
|
|
85
|
-
init_concurrency();
|
|
86
|
-
init_queries();
|
|
87
|
-
init_state_home();
|
|
88
|
-
init_termination();
|
|
89
|
-
init_ohmypi();
|
|
90
|
-
init_context_overflow();
|
|
91
|
-
init_agents$1();
|
|
92
|
-
init_tmux();
|
|
93
|
-
init_errors();
|
|
94
|
-
const ANSI_PATTERN = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
|
|
95
|
-
const MAX_PROMPT_CHARS = 2e3;
|
|
96
|
-
const PANE_DETECTION_CACHE_TTL_MS = 1e4;
|
|
97
|
-
const MAX_PANE_DETECTION_CACHE_ENTRIES = 256;
|
|
98
|
-
const MAX_CONCURRENT_PANE_DETECTIONS = 4;
|
|
99
|
-
const paneDetectionCache = /* @__PURE__ */ new Map();
|
|
100
|
-
const paneDetectionInFlight = /* @__PURE__ */ new Map();
|
|
101
|
-
const paneDetectionWaiters = [];
|
|
102
|
-
let activePaneDetections = 0;
|
|
103
|
-
function getPaneDetectionCacheKey(agentId, options) {
|
|
104
|
-
return `${agentId}:${options.isPlanning === true ? "planning" : "agent"}:${options.lines ?? 90}`;
|
|
105
|
-
}
|
|
106
|
-
function sweepPaneDetectionCache(now = Date.now()) {
|
|
107
|
-
for (const [key, entry] of paneDetectionCache) if (entry.expiresAt <= now) paneDetectionCache.delete(key);
|
|
108
|
-
while (paneDetectionCache.size > MAX_PANE_DETECTION_CACHE_ENTRIES) {
|
|
109
|
-
const oldestKey = paneDetectionCache.keys().next().value;
|
|
110
|
-
if (!oldestKey) break;
|
|
111
|
-
paneDetectionCache.delete(oldestKey);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
async function withPaneDetectionSlot(fn) {
|
|
115
|
-
if (activePaneDetections >= MAX_CONCURRENT_PANE_DETECTIONS) await new Promise((resolve) => paneDetectionWaiters.push(resolve));
|
|
116
|
-
activePaneDetections += 1;
|
|
117
|
-
try {
|
|
118
|
-
return await fn();
|
|
119
|
-
} finally {
|
|
120
|
-
activePaneDetections = Math.max(0, activePaneDetections - 1);
|
|
121
|
-
paneDetectionWaiters.shift()?.();
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
function cleanPaneLine(line) {
|
|
125
|
-
return line.replace(ANSI_PATTERN, "").replace(/[\x00-\x1f\x7f]/g, "").replace(/\s+$/g, "");
|
|
126
|
-
}
|
|
127
|
-
function compactPrompt(prompt) {
|
|
128
|
-
const compact = prompt.split("\n").map((line) => line.trim()).filter(Boolean).join("\n").trim();
|
|
129
|
-
if (compact.length <= MAX_PROMPT_CHARS) return compact;
|
|
130
|
-
return `${compact.slice(0, MAX_PROMPT_CHARS - 1)}…`;
|
|
131
|
-
}
|
|
132
|
-
function normalizeAwaitingInputPrompt(prompt) {
|
|
133
|
-
return compactPrompt(prompt);
|
|
134
|
-
}
|
|
135
|
-
function snippetAround(lines, index, before = 8, after = 4) {
|
|
136
|
-
const start = Math.max(0, index - before);
|
|
137
|
-
const end = Math.min(lines.length, index + after + 1);
|
|
138
|
-
return compactPrompt(lines.slice(start, end).join("\n"));
|
|
139
|
-
}
|
|
140
|
-
function lastIndexMatching(lines, predicate) {
|
|
141
|
-
for (let i = lines.length - 1; i >= 0; i -= 1) if (predicate(lines[i], i)) return i;
|
|
142
|
-
return -1;
|
|
143
|
-
}
|
|
144
|
-
function isRecentPromptIndex(lines, index) {
|
|
145
|
-
if (index < 0) return false;
|
|
146
|
-
return lines.length - index <= 25;
|
|
147
|
-
}
|
|
148
|
-
function isCurrentPromptIndex(lines, index, maxTrailingLines = 0) {
|
|
149
|
-
if (index < 0) return false;
|
|
150
|
-
return lines.length - index <= maxTrailingLines + 1;
|
|
151
|
-
}
|
|
152
|
-
function findPermissionMenuEndIndex(lines, menuStartIndex) {
|
|
153
|
-
if (menuStartIndex < 0) return -1;
|
|
154
|
-
const end = Math.min(lines.length, menuStartIndex + 8);
|
|
155
|
-
for (let i = menuStartIndex; i < end; i += 1) if (/\s*3\.\s*No\b/i.test(lines[i])) return i;
|
|
156
|
-
return menuStartIndex;
|
|
157
|
-
}
|
|
158
|
-
function looksLikeClaudePermissionMenu(text) {
|
|
159
|
-
return /(?:^|\n)\s*❯?\s*1\.\s*Yes\b/i.test(text) && /(?:^|\n)\s*2\.\s*Yes,?\s*(?:and\s*)?(?:allow|don't ask|always)/i.test(text) && /(?:^|\n)\s*3\.\s*No\b/i.test(text);
|
|
160
|
-
}
|
|
161
|
-
function looksLikePermissionText(text) {
|
|
162
|
-
return /permission|allow(?:\s+this)?|tool use|bash command|mcp tool|do you want to proceed|do you want to continue/i.test(text);
|
|
163
|
-
}
|
|
164
|
-
function looksLikeGenericConfirmation(line) {
|
|
165
|
-
return /(?:\?|:)\s*(?:\[[Yy]\/[Nn]\]|\[[Nn]\/[Yy]\]|\([Yy]\/[Nn]\)|\([Nn]\/[Yy]\)|\[y\/N\]|\[Y\/n\])\s*$/i.test(line) || /\b(?:continue|proceed|confirm|approve|allow|run|execute|overwrite|delete|remove)\b.*(?:\[[Yy]\/[Nn]\]|\([Yy]\/[Nn]\)|\[y\/N\]|\[Y\/n\])/i.test(line);
|
|
166
|
-
}
|
|
167
|
-
function looksLikePiPermission(text) {
|
|
168
|
-
return /(?:permission|approval|approve|allow).{0,80}(?:required|request|prompt|action|command)/i.test(text) || /(?:allow|approve|run|execute)\s+(?:this\s+)?(?:command|tool|action)/i.test(text);
|
|
169
|
-
}
|
|
170
|
-
function looksLikePlanningDone(text) {
|
|
171
|
-
return /planning finalized\s*[—-]\s*click done/i.test(text) || /click Done in the dashboard/i.test(text) || /planning (?:is )?complete.{0,120}(?:click|press|select) Done/i.test(text);
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* PAN-1520 (covers #1197) — Claude Code session-resume dialog. Fires when an
|
|
175
|
-
* agent is resumed via `claude --resume <session>` and a prior session is
|
|
176
|
-
* still considered active or interrupted. The dialog blocks tool execution
|
|
177
|
-
* until acknowledged. Conservative patterns — we want false-negatives over
|
|
178
|
-
* false-positives, so we only match strings that clearly indicate a resume
|
|
179
|
-
* choice point.
|
|
180
|
-
*/
|
|
181
|
-
function looksLikeSessionResumeDialog(text) {
|
|
182
|
-
return /this session (?:is|was)\s+(?:still\s+)?(?:active|interrupted|running)/i.test(text) || /resume (?:the\s+)?previous session/i.test(text) || /(?:continue|resume) (?:this\s+)?session\??.{0,40}(?:\[[Yy]\/[Nn]\]|\([Yy]\/[Nn]\)|press\s+enter)/i.test(text) || /press enter to (?:continue|resume)/i.test(text);
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* PAN-1834 — Codex/gpt-5.5 rate-limit / model-switch modal. The harness shows a
|
|
186
|
-
* choice between keeping the current model and switching to an alternative.
|
|
187
|
-
* To avoid matching prose that merely mentions rate limits, require BOTH option
|
|
188
|
-
* lines to be present near the bottom of the pane.
|
|
189
|
-
*/
|
|
190
|
-
function looksLikeRateLimitModelSwitchModal(text) {
|
|
191
|
-
return /keep current model/i.test(text) && /switch to\s+\S+/i.test(text);
|
|
192
|
-
}
|
|
193
|
-
/**
|
|
194
|
-
* PAN-1690 — Codex TUI approval prompt header. Codex asks for approval with a
|
|
195
|
-
* distinctive "Would you like to …?" prompt box (command run, edits, network/
|
|
196
|
-
* host grants) followed by a numbered Yes/…/No menu. Unlike Claude's menu,
|
|
197
|
-
* Codex renders option descriptions and a footer hint *below* "3. No", so the
|
|
198
|
-
* trailing-line heuristics the Claude path relies on never fire — we key on the
|
|
199
|
-
* header instead. Verb list pulled from the codex binary; see PAN-1690.
|
|
200
|
-
*/
|
|
201
|
-
function looksLikeCodexApprovalHeader(line) {
|
|
202
|
-
return /Would you like to (?:run the following command|grant these permissions?|make the following edits|allow|apply)\b/i.test(line);
|
|
203
|
-
}
|
|
204
|
-
function detectAwaitingInputFromPaneSync(pane, options = {}) {
|
|
205
|
-
const lines = pane.split("\n").map(cleanPaneLine).filter((line) => line.trim().length > 0);
|
|
206
|
-
if (lines.length === 0) return null;
|
|
207
|
-
const recentText = lines.slice(-45).join("\n");
|
|
208
|
-
if (looksLikeClaudePermissionMenu(recentText) && looksLikePermissionText(recentText)) {
|
|
209
|
-
const menuIndex = lastIndexMatching(lines, (line) => /❯?\s*1\.\s*Yes\b/i.test(line));
|
|
210
|
-
const menuEndIndex = findPermissionMenuEndIndex(lines, menuIndex);
|
|
211
|
-
if (isRecentPromptIndex(lines, menuIndex) && isCurrentPromptIndex(lines, menuEndIndex)) return {
|
|
212
|
-
reason: "tool_permission",
|
|
213
|
-
prompt: snippetAround(lines, menuIndex, 10, 3)
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
const codexHeaderIndex = lastIndexMatching(lines, looksLikeCodexApprovalHeader);
|
|
217
|
-
if (codexHeaderIndex >= 0 && isRecentPromptIndex(lines, codexHeaderIndex)) {
|
|
218
|
-
const optionIndex = lastIndexMatching(lines, (line) => /^[^\w]*1\.\s*Yes\b/i.test(line));
|
|
219
|
-
if (optionIndex > codexHeaderIndex && lines.length - optionIndex <= 12) return {
|
|
220
|
-
reason: "tool_permission",
|
|
221
|
-
prompt: snippetAround(lines, codexHeaderIndex, 1, 14)
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
const piIndex = lastIndexMatching(lines, (line) => looksLikePiPermission(line) || looksLikeGenericConfirmation(line));
|
|
225
|
-
if (isRecentPromptIndex(lines, piIndex) && isCurrentPromptIndex(lines, piIndex)) {
|
|
226
|
-
const snippet = snippetAround(lines, piIndex, 6, 2);
|
|
227
|
-
return {
|
|
228
|
-
reason: looksLikeGenericConfirmation(lines[piIndex]) ? "confirmation" : "tool_permission",
|
|
229
|
-
prompt: snippet
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
if (options.isPlanning && looksLikePlanningDone(recentText)) {
|
|
233
|
-
const doneIndex = lastIndexMatching(lines, (line) => /done|planning/i.test(line));
|
|
234
|
-
return {
|
|
235
|
-
reason: "planning_done",
|
|
236
|
-
prompt: snippetAround(lines, doneIndex >= 0 ? doneIndex : lines.length - 1, 8, 2)
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
if (looksLikeSessionResumeDialog(recentText)) {
|
|
240
|
-
const resumeIndex = lastIndexMatching(lines, (line) => looksLikeSessionResumeDialog(line));
|
|
241
|
-
return {
|
|
242
|
-
reason: "session_resume",
|
|
243
|
-
prompt: snippetAround(lines, resumeIndex >= 0 ? resumeIndex : lines.length - 1, 8, 2)
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
if (looksLikeRateLimitModelSwitchModal(recentText)) {
|
|
247
|
-
const rateLimitIndex = lastIndexMatching(lines, (line) => /keep current model|switch to\s+\S+/i.test(line));
|
|
248
|
-
if (isRecentPromptIndex(lines, rateLimitIndex)) return {
|
|
249
|
-
reason: "rate_limit",
|
|
250
|
-
prompt: snippetAround(lines, rateLimitIndex >= 0 ? rateLimitIndex : lines.length - 1, 8, 2)
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
return null;
|
|
254
|
-
}
|
|
255
|
-
async function detectAwaitingInputForAgentPromise(agentId, options = {}) {
|
|
256
|
-
const cacheEnabled = options.cache !== false;
|
|
257
|
-
const cacheKey = getPaneDetectionCacheKey(agentId, options);
|
|
258
|
-
const now = Date.now();
|
|
259
|
-
if (cacheEnabled) {
|
|
260
|
-
sweepPaneDetectionCache(now);
|
|
261
|
-
const cached = paneDetectionCache.get(cacheKey);
|
|
262
|
-
if (cached && cached.expiresAt > now) {
|
|
263
|
-
paneDetectionCache.delete(cacheKey);
|
|
264
|
-
paneDetectionCache.set(cacheKey, cached);
|
|
265
|
-
return cached.detection;
|
|
266
|
-
}
|
|
267
|
-
const inFlight = paneDetectionInFlight.get(cacheKey);
|
|
268
|
-
if (inFlight) return inFlight;
|
|
269
|
-
}
|
|
270
|
-
const detectionPromise = withPaneDetectionSlot(async () => {
|
|
271
|
-
const detection = detectAwaitingInputFromPaneSync(await Effect.runPromise(capturePane(agentId, options.lines ?? 90)), options);
|
|
272
|
-
if (cacheEnabled) {
|
|
273
|
-
paneDetectionCache.set(cacheKey, {
|
|
274
|
-
expiresAt: Date.now() + PANE_DETECTION_CACHE_TTL_MS,
|
|
275
|
-
detection
|
|
276
|
-
});
|
|
277
|
-
sweepPaneDetectionCache();
|
|
278
|
-
}
|
|
279
|
-
return detection;
|
|
280
|
-
});
|
|
281
|
-
if (!cacheEnabled) return detectionPromise;
|
|
282
|
-
paneDetectionInFlight.set(cacheKey, detectionPromise);
|
|
283
|
-
try {
|
|
284
|
-
return await detectionPromise;
|
|
285
|
-
} finally {
|
|
286
|
-
paneDetectionInFlight.delete(cacheKey);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
/**
|
|
290
|
-
* Effect-native variant of detectAwaitingInputForAgent. Fails with TmuxError if
|
|
291
|
-
* the pane capture fails outside the in-cache fast path.
|
|
292
|
-
*/
|
|
293
|
-
const detectAwaitingInputForAgent = (agentId, options = {}) => Effect.tryPromise({
|
|
294
|
-
try: () => detectAwaitingInputForAgentPromise(agentId, options),
|
|
295
|
-
catch: (cause) => new TmuxError({
|
|
296
|
-
command: "capture-pane",
|
|
297
|
-
message: `failed to detect awaiting input for ${agentId}`,
|
|
298
|
-
cause
|
|
299
|
-
})
|
|
300
|
-
});
|
|
301
|
-
/**
|
|
302
|
-
* PAN-1690 — parse a Codex approval prompt (as captured by the codex-aware
|
|
303
|
-
* branch of detectAwaitingInputFromPaneSync) into its header, detail, and
|
|
304
|
-
* numbered options, so the dashboard can render the menu and answer it without
|
|
305
|
-
* the terminal. Returns null when the text doesn't contain a usable menu
|
|
306
|
-
* (fewer than two numbered options). Option lines tolerate a leading selection
|
|
307
|
-
* cursor (❯ › > etc.); the footer hint and other non-numbered lines are
|
|
308
|
-
* naturally excluded.
|
|
309
|
-
*/
|
|
310
|
-
function parseCodexApprovalPrompt(text) {
|
|
311
|
-
const lines = text.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
|
|
312
|
-
if (lines.length === 0) return null;
|
|
313
|
-
const headerIndex = lines.findIndex((l) => looksLikeCodexApprovalHeader(l));
|
|
314
|
-
if (headerIndex < 0) return null;
|
|
315
|
-
const optionRe = /^[^\w]*(\d+)\.\s*(.+?)\s*$/;
|
|
316
|
-
const options = [];
|
|
317
|
-
const detailLines = [];
|
|
318
|
-
let firstOptionSeen = false;
|
|
319
|
-
for (let i = headerIndex + 1; i < lines.length; i += 1) {
|
|
320
|
-
const m = optionRe.exec(lines[i]);
|
|
321
|
-
if (m) {
|
|
322
|
-
firstOptionSeen = true;
|
|
323
|
-
options.push({
|
|
324
|
-
number: Number(m[1]),
|
|
325
|
-
label: m[2].trim()
|
|
326
|
-
});
|
|
327
|
-
} else if (!firstOptionSeen) detailLines.push(lines[i]);
|
|
328
|
-
}
|
|
329
|
-
if (options.length < 2) return null;
|
|
330
|
-
return {
|
|
331
|
-
header: lines[headerIndex],
|
|
332
|
-
detail: detailLines.join("\n"),
|
|
333
|
-
options
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
//#endregion
|
|
337
|
-
//#region ../../lib/agent-enrichment.ts
|
|
338
|
-
/**
|
|
339
|
-
* Agent enrichment utilities (PAN-440 / PAN-1048)
|
|
340
|
-
*
|
|
341
|
-
* Shared functions for computing enrichment fields:
|
|
342
|
-
* role, hasPendingQuestion, pendingQuestionCount, resolution, resolutionCount
|
|
343
|
-
*
|
|
344
|
-
* Used by both the legacy REST /api/agents endpoint and the new
|
|
345
|
-
* AgentEnrichmentService background poller.
|
|
346
|
-
*
|
|
347
|
-
* PAN-1048: replaced the legacy `agentPhase` string with the role primitive —
|
|
348
|
-
* the dashboard derives label/status from `role` + lifecycle state.
|
|
349
|
-
*/
|
|
350
|
-
init_errors();
|
|
351
|
-
init_tracker_config();
|
|
352
|
-
const execAsync$8 = promisify$1(exec$1);
|
|
353
|
-
function appendPaneDetectionKind(detection, kinds) {
|
|
354
|
-
if (detection?.reason === "session_resume" && !kinds.includes("sessionResume")) kinds.push("sessionResume");
|
|
355
|
-
if (detection?.reason === "rate_limit" && !kinds.includes("rateLimit")) kinds.push("rateLimit");
|
|
356
|
-
}
|
|
357
|
-
function isOwnActiveSpecialist(role) {
|
|
358
|
-
return role === "review" || role === "test" || role === "ship";
|
|
359
|
-
}
|
|
360
|
-
function getClaudeProjectDir(workspacePath) {
|
|
361
|
-
return join$1(homedir(), ".claude", "projects", encodeClaudeProjectDir(workspacePath));
|
|
362
|
-
}
|
|
363
|
-
async function getActiveSessionPath(projectDir) {
|
|
364
|
-
if (!existsSync(projectDir)) return null;
|
|
365
|
-
try {
|
|
366
|
-
const jsonlFiles = (await readdir$1(projectDir)).filter((f) => f.endsWith(".jsonl"));
|
|
367
|
-
if (jsonlFiles.length === 0) return null;
|
|
368
|
-
const withMtime = (await Promise.all(jsonlFiles.map(async (f) => {
|
|
369
|
-
try {
|
|
370
|
-
return {
|
|
371
|
-
name: f,
|
|
372
|
-
path: join$1(projectDir, f),
|
|
373
|
-
mtime: (await stat$2(join$1(projectDir, f))).mtime.getTime()
|
|
374
|
-
};
|
|
375
|
-
} catch {
|
|
376
|
-
return null;
|
|
377
|
-
}
|
|
378
|
-
}))).filter((x) => x !== null);
|
|
379
|
-
if (withMtime.length === 0) return null;
|
|
380
|
-
withMtime.sort((a, b) => b.mtime - a.mtime);
|
|
381
|
-
return withMtime[0].path;
|
|
382
|
-
} catch {
|
|
383
|
-
return null;
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
function getProjectPathByPrefix(issuePrefix) {
|
|
387
|
-
const resolved = resolveProjectFromIssueSync(`${issuePrefix}-1`);
|
|
388
|
-
if (resolved) return resolved.projectPath;
|
|
389
|
-
const config = getGitHubConfig();
|
|
390
|
-
if (config) {
|
|
391
|
-
for (const { owner, repo, prefix } of config.repos) if ((prefix || repo.toUpperCase().replace(/-CLI$/, "").replace(/-/g, "")).toUpperCase() === issuePrefix.toUpperCase()) {
|
|
392
|
-
const possiblePaths = [
|
|
393
|
-
join$1(homedir(), "Projects", repo),
|
|
394
|
-
join$1(homedir(), "Projects", repo.replace(/-cli$/, "")),
|
|
395
|
-
join$1(homedir(), "Projects", owner, repo)
|
|
396
|
-
];
|
|
397
|
-
for (const path of possiblePaths) if (existsSync(path)) return path;
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
return join$1(homedir(), "Projects");
|
|
401
|
-
}
|
|
402
|
-
async function getAgentWorkspacePromise(agentId) {
|
|
403
|
-
const workspace = getAgentStateSync(agentId)?.workspace;
|
|
404
|
-
if (workspace) return workspace;
|
|
405
|
-
try {
|
|
406
|
-
const { stdout: paneCwd } = await execAsync$8(`tmux display-message -t ${agentId} -p '#{pane_current_path}' 2>/dev/null`, { encoding: "utf-8" });
|
|
407
|
-
const trimmed = paneCwd.trim();
|
|
408
|
-
if (trimmed && existsSync(trimmed)) return trimmed;
|
|
409
|
-
} catch {}
|
|
410
|
-
const issueId = agentId.replace(/^(agent-|planning-)/, "").toUpperCase();
|
|
411
|
-
const prefix = extractPrefixSync(issueId);
|
|
412
|
-
if (!prefix) return null;
|
|
413
|
-
try {
|
|
414
|
-
const projectPath = getProjectPathByPrefix(prefix);
|
|
415
|
-
const workspacePath = join$1(projectPath, "workspaces", `feature-${issueId.toLowerCase()}`);
|
|
416
|
-
if (existsSync(workspacePath)) return workspacePath;
|
|
417
|
-
return projectPath;
|
|
418
|
-
} catch {
|
|
419
|
-
return null;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
async function getAgentJsonlPathPromise(agentId) {
|
|
423
|
-
const workspace = await Effect.runPromise(getAgentWorkspace(agentId));
|
|
424
|
-
if (!workspace) return null;
|
|
425
|
-
return await getActiveSessionPath(getClaudeProjectDir(workspace));
|
|
426
|
-
}
|
|
427
|
-
/**
|
|
428
|
-
* Count outstanding AskUserQuestions across ALL of an agent's workspace JSONL
|
|
429
|
-
* session files — not just the newest one. Claude Code rotates session files,
|
|
430
|
-
* so an open AskUserQuestion can sit in a file that is not the most-recently-
|
|
431
|
-
* modified. The complete-planning guard MUST be robust to that: scanning only
|
|
432
|
-
* the active file let TIN-1 complete planning while the operator's question was
|
|
433
|
-
* still open. Returns 0 only when no file has an unanswered AUQ.
|
|
434
|
-
*/
|
|
435
|
-
async function countPendingAskUserQuestionsForAgentPromise(agentId) {
|
|
436
|
-
const workspace = await Effect.runPromise(getAgentWorkspace(agentId));
|
|
437
|
-
if (!workspace) return 0;
|
|
438
|
-
const projectDir = getClaudeProjectDir(workspace);
|
|
439
|
-
if (!existsSync(projectDir)) return 0;
|
|
440
|
-
let files;
|
|
441
|
-
try {
|
|
442
|
-
files = (await readdir$1(projectDir)).filter((f) => f.endsWith(".jsonl"));
|
|
443
|
-
} catch {
|
|
444
|
-
return 0;
|
|
445
|
-
}
|
|
446
|
-
let total = 0;
|
|
447
|
-
for (const f of files) try {
|
|
448
|
-
const scan = await scanPendingInputsPromise(join$1(projectDir, f));
|
|
449
|
-
total += scan.askUserQuestions.length;
|
|
450
|
-
} catch {}
|
|
451
|
-
return total;
|
|
452
|
-
}
|
|
453
|
-
/** Effect-native: count pending AskUserQuestions across all of an agent's JSONL files. */
|
|
454
|
-
const countPendingAskUserQuestionsForAgent = (agentId) => Effect.promise(() => countPendingAskUserQuestionsForAgentPromise(agentId));
|
|
455
|
-
/**
|
|
456
|
-
* Read the last `maxBytes` from a file. Efficient for large JSONL files where
|
|
457
|
-
* only recent entries (at the end) are relevant.
|
|
458
|
-
*/
|
|
459
|
-
async function readFileTail(filePath, maxBytes) {
|
|
460
|
-
try {
|
|
461
|
-
const fileStat = await stat$2(filePath);
|
|
462
|
-
const start = Math.max(0, fileStat.size - maxBytes);
|
|
463
|
-
if (start === 0) return readFile$1(filePath, "utf-8");
|
|
464
|
-
const { createReadStream } = await import("node:fs");
|
|
465
|
-
return new Promise((resolve, reject) => {
|
|
466
|
-
const stream = createReadStream(filePath, {
|
|
467
|
-
start,
|
|
468
|
-
encoding: "utf-8"
|
|
469
|
-
});
|
|
470
|
-
let data = "";
|
|
471
|
-
stream.on("data", (chunk) => {
|
|
472
|
-
data += chunk;
|
|
473
|
-
});
|
|
474
|
-
stream.on("end", () => resolve(data));
|
|
475
|
-
stream.on("error", reject);
|
|
476
|
-
});
|
|
477
|
-
} catch {
|
|
478
|
-
return "";
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
const ASK_USER_QUESTION_HOOK_DENY_MARKER = "PAN-1520";
|
|
482
|
-
function isAskUserQuestionHookDenyToolResult(item) {
|
|
483
|
-
if (item.is_error !== true) return false;
|
|
484
|
-
const content = item.content;
|
|
485
|
-
if (typeof content === "string") return content.includes(ASK_USER_QUESTION_HOOK_DENY_MARKER);
|
|
486
|
-
if (Array.isArray(content)) return content.some((part) => {
|
|
487
|
-
if (typeof part === "string") return part.includes(ASK_USER_QUESTION_HOOK_DENY_MARKER);
|
|
488
|
-
if (part && typeof part === "object" && "text" in part) {
|
|
489
|
-
const text = part.text;
|
|
490
|
-
return typeof text === "string" && text.includes(ASK_USER_QUESTION_HOOK_DENY_MARKER);
|
|
491
|
-
}
|
|
492
|
-
return false;
|
|
493
|
-
});
|
|
494
|
-
return false;
|
|
495
|
-
}
|
|
496
|
-
async function getPendingQuestionsPromise(jsonlPath) {
|
|
497
|
-
return (await scanPendingInputsPromise(jsonlPath)).askUserQuestions;
|
|
498
|
-
}
|
|
499
|
-
/**
|
|
500
|
-
* PAN-1520 — does this user-message entry carry operator text (i.e. an answer)
|
|
501
|
-
* rather than just being a wrapper for a tool_result? When the hook denies an
|
|
502
|
-
* AskUserQuestion the agent restates the question as plain text; the operator's
|
|
503
|
-
* next user message — whether typed in the terminal, sent from the conversation
|
|
504
|
-
* composer, or delivered by the answer-question route — is the actual answer.
|
|
505
|
-
* The presence of that user-text turn after the deny is what resolves the AUQ.
|
|
506
|
-
*/
|
|
507
|
-
function isUserTextEntry(entry) {
|
|
508
|
-
if (!entry || typeof entry !== "object") return false;
|
|
509
|
-
const e = entry;
|
|
510
|
-
if (e.type !== "user") return false;
|
|
511
|
-
const content = e.message?.content;
|
|
512
|
-
if (typeof content === "string") return content.trim().length > 0;
|
|
513
|
-
if (Array.isArray(content)) return content.some((item) => {
|
|
514
|
-
if (!item || typeof item !== "object") return false;
|
|
515
|
-
return item.type !== "tool_result";
|
|
516
|
-
});
|
|
517
|
-
return false;
|
|
518
|
-
}
|
|
519
|
-
async function scanPendingInputsPromise(jsonlPath) {
|
|
520
|
-
if (!existsSync(jsonlPath)) return {
|
|
521
|
-
askUserQuestions: [],
|
|
522
|
-
enterPlanModeOpen: false,
|
|
523
|
-
exitPlanModePending: false
|
|
524
|
-
};
|
|
525
|
-
try {
|
|
526
|
-
const lines = (await readFileTail(jsonlPath, 512e3)).split("\n").filter((line) => line.trim());
|
|
527
|
-
const askToolCalls = /* @__PURE__ */ new Map();
|
|
528
|
-
const askAnswered = /* @__PURE__ */ new Set();
|
|
529
|
-
const askDeniedAwaitingUser = /* @__PURE__ */ new Set();
|
|
530
|
-
const exitPlanModeIds = /* @__PURE__ */ new Set();
|
|
531
|
-
const exitPlanModeAnswered = /* @__PURE__ */ new Set();
|
|
532
|
-
const enterPlanModeIds = /* @__PURE__ */ new Set();
|
|
533
|
-
const exitPlanModeFiredAfterEnter = /* @__PURE__ */ new Set();
|
|
534
|
-
for (const line of lines) try {
|
|
535
|
-
const entry = JSON.parse(line);
|
|
536
|
-
if (isUserTextEntry(entry)) {
|
|
537
|
-
for (const id of askDeniedAwaitingUser) askAnswered.add(id);
|
|
538
|
-
askDeniedAwaitingUser.clear();
|
|
539
|
-
}
|
|
540
|
-
const messageContent = entry.message?.content;
|
|
541
|
-
if (!Array.isArray(messageContent)) continue;
|
|
542
|
-
for (const item of messageContent) {
|
|
543
|
-
if (item.type === "tool_use") {
|
|
544
|
-
if (item.name === "AskUserQuestion" && typeof item.id === "string") askToolCalls.set(item.id, {
|
|
545
|
-
toolId: item.id,
|
|
546
|
-
timestamp: entry.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
547
|
-
questions: item.input?.questions || []
|
|
548
|
-
});
|
|
549
|
-
else if (item.name === "ExitPlanMode" && typeof item.id === "string") {
|
|
550
|
-
exitPlanModeIds.add(item.id);
|
|
551
|
-
exitPlanModeFiredAfterEnter.add(item.id);
|
|
552
|
-
} else if (item.name === "EnterPlanMode" && typeof item.id === "string") enterPlanModeIds.add(item.id);
|
|
553
|
-
}
|
|
554
|
-
if (item.type === "tool_result" && typeof item.tool_use_id === "string") {
|
|
555
|
-
if (askToolCalls.has(item.tool_use_id)) if (isAskUserQuestionHookDenyToolResult(item)) askDeniedAwaitingUser.add(item.tool_use_id);
|
|
556
|
-
else {
|
|
557
|
-
askAnswered.add(item.tool_use_id);
|
|
558
|
-
askDeniedAwaitingUser.delete(item.tool_use_id);
|
|
559
|
-
}
|
|
560
|
-
if (exitPlanModeIds.has(item.tool_use_id)) exitPlanModeAnswered.add(item.tool_use_id);
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
} catch {}
|
|
564
|
-
const askUserQuestions = Array.from(askToolCalls.entries()).filter(([id]) => !askAnswered.has(id)).map(([, question]) => question);
|
|
565
|
-
const exitPlanModePending = Array.from(exitPlanModeIds).some((id) => !exitPlanModeAnswered.has(id));
|
|
566
|
-
return {
|
|
567
|
-
askUserQuestions,
|
|
568
|
-
enterPlanModeOpen: enterPlanModeIds.size > 0 && exitPlanModeFiredAfterEnter.size === 0,
|
|
569
|
-
exitPlanModePending
|
|
570
|
-
};
|
|
571
|
-
} catch {
|
|
572
|
-
return {
|
|
573
|
-
askUserQuestions: [],
|
|
574
|
-
enterPlanModeOpen: false,
|
|
575
|
-
exitPlanModePending: false
|
|
576
|
-
};
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
async function getAgentPendingQuestionsPromise(agentId) {
|
|
580
|
-
const jsonlPath = await Effect.runPromise(getAgentJsonlPath(agentId));
|
|
581
|
-
if (!jsonlPath) return [];
|
|
582
|
-
return [...await Effect.runPromise(getPendingQuestions(jsonlPath))];
|
|
583
|
-
}
|
|
584
|
-
async function getAgentJsonlMtimePromise(agentId) {
|
|
585
|
-
const jsonlPath = await Effect.runPromise(getAgentJsonlPath(agentId));
|
|
586
|
-
if (!jsonlPath || !existsSync(jsonlPath)) return null;
|
|
587
|
-
try {
|
|
588
|
-
return (await stat$2(jsonlPath)).mtime.getTime();
|
|
589
|
-
} catch {
|
|
590
|
-
return null;
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
async function computeAgentEnrichmentPromise(agentId, startedAt, hasActiveSpecialist, skipJsonlScan) {
|
|
594
|
-
const isPlanning = agentId.startsWith("planning-");
|
|
595
|
-
const stateRole = getAgentStateSync(agentId)?.role;
|
|
596
|
-
const role = stateRole === "plan" || stateRole === "work" || stateRole === "review" || stateRole === "test" || stateRole === "ship" || stateRole === "flywheel" ? stateRole : isPlanning ? "plan" : void 0;
|
|
597
|
-
const runtimeState = await Effect.runPromise(getAgentRuntimeState(agentId));
|
|
598
|
-
let pendingQuestions = [];
|
|
599
|
-
let enterPlanModeOpen = false;
|
|
600
|
-
let exitPlanModePending = false;
|
|
601
|
-
if (!skipJsonlScan) {
|
|
602
|
-
const jsonlPath = await Effect.runPromise(getAgentJsonlPath(agentId));
|
|
603
|
-
if (jsonlPath) {
|
|
604
|
-
const scan = await scanPendingInputsPromise(jsonlPath);
|
|
605
|
-
pendingQuestions = [...scan.askUserQuestions];
|
|
606
|
-
enterPlanModeOpen = scan.enterPlanModeOpen;
|
|
607
|
-
exitPlanModePending = scan.exitPlanModePending;
|
|
608
|
-
}
|
|
609
|
-
if (pendingQuestions.length > 0 && startedAt) {
|
|
610
|
-
const agentStartTime = new Date(startedAt).getTime();
|
|
611
|
-
pendingQuestions = pendingQuestions.filter((q) => {
|
|
612
|
-
const qTime = new Date(q.timestamp).getTime();
|
|
613
|
-
return !isNaN(qTime) && qTime >= agentStartTime;
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
const questionDetection = pendingQuestions.length > 0 ? {
|
|
618
|
-
reason: "user_question",
|
|
619
|
-
prompt: normalizeAwaitingInputPrompt(pendingQuestions[0]?.questions.map((q) => q.question).filter(Boolean).join("\n") || "Agent is waiting for a user answer")
|
|
620
|
-
} : null;
|
|
621
|
-
const runtimeDetection = runtimeState?.state === "waiting-on-human" ? {
|
|
622
|
-
reason: runtimeState.waitingReason || "other",
|
|
623
|
-
prompt: normalizeAwaitingInputPrompt(runtimeState.waitingNotification || "Agent is waiting for human input")
|
|
624
|
-
} : null;
|
|
625
|
-
const paneDetection = !questionDetection && !runtimeDetection ? await Effect.runPromise(detectAwaitingInputForAgent(agentId, { isPlanning })) : null;
|
|
626
|
-
const fallbackDetection = runtimeState?.resolution === "needs_input" ? {
|
|
627
|
-
reason: "other",
|
|
628
|
-
prompt: normalizeAwaitingInputPrompt("Agent stopped because it needs human input or hit a blocker")
|
|
629
|
-
} : null;
|
|
630
|
-
const detection = questionDetection ?? runtimeDetection ?? paneDetection ?? fallbackDetection;
|
|
631
|
-
const shouldSuppressPendingInput = hasActiveSpecialist === true && !isOwnActiveSpecialist(role);
|
|
632
|
-
const hasPendingQuestion = !shouldSuppressPendingInput && detection !== null;
|
|
633
|
-
const pendingInputKinds = [];
|
|
634
|
-
let pendingAskUserQuestion;
|
|
635
|
-
if (!shouldSuppressPendingInput) {
|
|
636
|
-
if (pendingQuestions.length > 0) {
|
|
637
|
-
pendingInputKinds.push("askUserQuestion");
|
|
638
|
-
const first = pendingQuestions[0];
|
|
639
|
-
pendingAskUserQuestion = {
|
|
640
|
-
toolUseId: first.toolId,
|
|
641
|
-
askedAt: first.timestamp,
|
|
642
|
-
questions: first.questions.map((q) => ({
|
|
643
|
-
question: q.question,
|
|
644
|
-
header: q.header,
|
|
645
|
-
multiSelect: q.multiSelect,
|
|
646
|
-
options: q.options.map((o) => ({
|
|
647
|
-
label: o.label,
|
|
648
|
-
description: o.description
|
|
649
|
-
}))
|
|
650
|
-
}))
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
if (exitPlanModePending) pendingInputKinds.push("exitPlanMode");
|
|
654
|
-
if (enterPlanModeOpen && !exitPlanModePending) pendingInputKinds.push("enterPlanMode");
|
|
655
|
-
appendPaneDetectionKind(detection, pendingInputKinds);
|
|
656
|
-
}
|
|
657
|
-
return {
|
|
658
|
-
role,
|
|
659
|
-
hasPendingQuestion,
|
|
660
|
-
pendingQuestionCount: pendingQuestions.length,
|
|
661
|
-
pendingQuestionPrompt: detection?.prompt,
|
|
662
|
-
pendingQuestionReason: detection?.reason,
|
|
663
|
-
pendingInputCount: pendingInputKinds.length,
|
|
664
|
-
pendingInputKinds,
|
|
665
|
-
pendingAskUserQuestion,
|
|
666
|
-
resolution: runtimeState?.resolution || "working",
|
|
667
|
-
resolutionCount: runtimeState?.resolutionCount || 0
|
|
668
|
-
};
|
|
669
|
-
}
|
|
670
|
-
/**
|
|
671
|
-
* Effect-native variant of computeAgentEnrichment. Fails with FsError if any
|
|
672
|
-
* underlying filesystem read fails outside the swallowed branches.
|
|
673
|
-
*/
|
|
674
|
-
const computeAgentEnrichment = (agentId, startedAt, hasActiveSpecialist, skipJsonlScan) => Effect.tryPromise({
|
|
675
|
-
try: () => computeAgentEnrichmentPromise(agentId, startedAt, hasActiveSpecialist, skipJsonlScan),
|
|
676
|
-
catch: (cause) => new FsError({
|
|
677
|
-
path: getAgentDir(agentId),
|
|
678
|
-
operation: "computeAgentEnrichment",
|
|
679
|
-
cause
|
|
680
|
-
})
|
|
681
|
-
});
|
|
682
|
-
/** Effect-native: resolve the workspace path for an agent (null on failure). */
|
|
683
|
-
const getAgentWorkspace = (agentId) => Effect.promise(() => getAgentWorkspacePromise(agentId));
|
|
684
|
-
/** Effect-native: resolve the active JSONL session path for an agent (null on failure). */
|
|
685
|
-
const getAgentJsonlPath = (agentId) => Effect.promise(() => getAgentJsonlPathPromise(agentId));
|
|
686
|
-
/** Effect-native: get the mtime of the agent's active JSONL session file. */
|
|
687
|
-
const getAgentJsonlMtime = (agentId) => Effect.promise(() => getAgentJsonlMtimePromise(agentId));
|
|
688
|
-
/** Effect-native: parse pending questions from a JSONL file. */
|
|
689
|
-
const getPendingQuestions = (jsonlPath) => Effect.promise(() => getPendingQuestionsPromise(jsonlPath));
|
|
690
|
-
/** Effect-native: get pending questions for an agent by id. */
|
|
691
|
-
const getAgentPendingQuestions = (agentId) => Effect.promise(() => getAgentPendingQuestionsPromise(agentId));
|
|
692
|
-
//#endregion
|
|
693
52
|
//#region ../../../node_modules/.bun/undici@7.25.0/node_modules/undici/lib/core/symbols.js
|
|
694
53
|
var require_symbols = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
695
54
|
module.exports = {
|
|
@@ -22101,7 +21460,9 @@ var require_eventsource = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
22101
21460
|
defaultReconnectionTime
|
|
22102
21461
|
};
|
|
22103
21462
|
}));
|
|
22104
|
-
|
|
21463
|
+
//#endregion
|
|
21464
|
+
//#region ../../../node_modules/.bun/undici@7.25.0/node_modules/undici/index.js
|
|
21465
|
+
var require_undici = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
22105
21466
|
init_esm_shims();
|
|
22106
21467
|
const Client = require_client();
|
|
22107
21468
|
const Dispatcher = require_dispatcher();
|
|
@@ -22267,7 +21628,30 @@ new ((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
22267
21628
|
globalThis.EventSource = module.exports.EventSource;
|
|
22268
21629
|
}
|
|
22269
21630
|
module.exports.install = install;
|
|
22270
|
-
}))
|
|
21631
|
+
}));
|
|
21632
|
+
//#endregion
|
|
21633
|
+
//#region ../../../node_modules/.bun/smee-client@5.0.0/node_modules/smee-client/index.js
|
|
21634
|
+
init_paths();
|
|
21635
|
+
init_errors();
|
|
21636
|
+
init_activity_logger();
|
|
21637
|
+
init_projects();
|
|
21638
|
+
init_tmux();
|
|
21639
|
+
init_agents();
|
|
21640
|
+
init_persistent_logger();
|
|
21641
|
+
init_review_status_sync();
|
|
21642
|
+
init_review_dispatch_decision();
|
|
21643
|
+
init_review_status();
|
|
21644
|
+
init_runtime_state();
|
|
21645
|
+
init_agent_state();
|
|
21646
|
+
init_transcript_landing();
|
|
21647
|
+
init_config();
|
|
21648
|
+
init_memory_verdict_cache();
|
|
21649
|
+
init_concurrency();
|
|
21650
|
+
init_queries();
|
|
21651
|
+
init_termination();
|
|
21652
|
+
init_context_overflow();
|
|
21653
|
+
init_agents$1();
|
|
21654
|
+
new (require_undici()).EnvHttpProxyAgent();
|
|
22271
21655
|
//#endregion
|
|
22272
21656
|
//#region ../../lib/smee.ts
|
|
22273
21657
|
/**
|
|
@@ -22286,7 +21670,7 @@ new ((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
22286
21670
|
* stopSmeeProcess();
|
|
22287
21671
|
* isSmeeProcessRunning();
|
|
22288
21672
|
*/
|
|
22289
|
-
|
|
21673
|
+
init_config$1();
|
|
22290
21674
|
const SMEE_URL_PATH = join(homedir$1(), ".overdeck", "github-app", "smee-url");
|
|
22291
21675
|
const SMEE_PID_PATH = join(homedir$1(), ".overdeck", "github-app", "smee.pid");
|
|
22292
21676
|
const SMEE_LOG_PATH = join(homedir$1(), ".overdeck", "logs", "smee.log");
|
|
@@ -22451,10 +21835,9 @@ function startSmeeProcessSync() {
|
|
|
22451
21835
|
}
|
|
22452
21836
|
//#endregion
|
|
22453
21837
|
//#region services/system-health-service.ts
|
|
22454
|
-
|
|
22455
|
-
|
|
22456
|
-
|
|
22457
|
-
const execAsync$7 = promisify(exec);
|
|
21838
|
+
init_docker_stats();
|
|
21839
|
+
init_event_store();
|
|
21840
|
+
const execAsync$6 = promisify(exec);
|
|
22458
21841
|
const DEFAULT_HEALTH_POLL_SECONDS = 15;
|
|
22459
21842
|
const DEFAULT_RESOURCE_CONFIG = {
|
|
22460
21843
|
memoryWarnGb: 4,
|
|
@@ -22586,7 +21969,7 @@ async function readProcMemoryDarwin() {
|
|
|
22586
21969
|
let memAvailable = freemem$1();
|
|
22587
21970
|
let memFree = freemem$1();
|
|
22588
21971
|
try {
|
|
22589
|
-
const { stdout } = await execAsync$
|
|
21972
|
+
const { stdout } = await execAsync$6("vm_stat", {
|
|
22590
21973
|
encoding: "utf-8",
|
|
22591
21974
|
timeout: 5e3
|
|
22592
21975
|
});
|
|
@@ -22606,7 +21989,7 @@ async function readProcMemoryDarwin() {
|
|
|
22606
21989
|
let swapTotal = 0;
|
|
22607
21990
|
let swapFree = 0;
|
|
22608
21991
|
try {
|
|
22609
|
-
const { stdout } = await execAsync$
|
|
21992
|
+
const { stdout } = await execAsync$6("sysctl -n vm.swapusage", {
|
|
22610
21993
|
encoding: "utf-8",
|
|
22611
21994
|
timeout: 5e3
|
|
22612
21995
|
});
|
|
@@ -22666,7 +22049,7 @@ async function readCpuPercent() {
|
|
|
22666
22049
|
return Math.round((totalDelta - idleDelta) / totalDelta * 1e3) / 10;
|
|
22667
22050
|
}
|
|
22668
22051
|
async function readProcessTable() {
|
|
22669
|
-
const { stdout } = await execAsync$
|
|
22052
|
+
const { stdout } = await execAsync$6("ps -eo pid=,ppid=,rss=,args=", {
|
|
22670
22053
|
encoding: "utf-8",
|
|
22671
22054
|
timeout: 1e4
|
|
22672
22055
|
});
|
|
@@ -22943,6 +22326,7 @@ async function getSystemHealthSnapshot(snapshot) {
|
|
|
22943
22326
|
}
|
|
22944
22327
|
//#endregion
|
|
22945
22328
|
//#region routes/resources/shared.ts
|
|
22329
|
+
init_load();
|
|
22946
22330
|
init_docker_stats();
|
|
22947
22331
|
function getCurrentDockerStats() {
|
|
22948
22332
|
return [];
|
|
@@ -23111,385 +22495,13 @@ async function assessMemoryPressure() {
|
|
|
23111
22495
|
return verdict;
|
|
23112
22496
|
}
|
|
23113
22497
|
//#endregion
|
|
23114
|
-
//#region ../../lib/
|
|
23115
|
-
|
|
23116
|
-
* Claude Code Runtime Implementation
|
|
23117
|
-
*
|
|
23118
|
-
* Implements AgentRuntime for Claude Code CLI.
|
|
23119
|
-
*
|
|
23120
|
-
* Session storage: ~/.claude/projects/<workspace-hash>/<session-id>.jsonl
|
|
23121
|
-
* Session index: ~/.claude/projects/<workspace-hash>/sessions-index.json
|
|
23122
|
-
*/
|
|
23123
|
-
init_agents$1();
|
|
22498
|
+
//#region ../../lib/cloister/deacon-inspect.ts
|
|
22499
|
+
init_review_status();
|
|
23124
22500
|
init_tmux();
|
|
23125
|
-
init_jsonl_parser();
|
|
23126
|
-
init_errors();
|
|
23127
|
-
const CLAUDE_PROJECTS_DIR = join$1(homedir(), ".claude", "projects");
|
|
23128
22501
|
/**
|
|
23129
|
-
*
|
|
23130
|
-
|
|
23131
|
-
|
|
23132
|
-
name = "claude-code";
|
|
23133
|
-
getHarnessBehavior() {
|
|
23134
|
-
return CLAUDE_CODE_BEHAVIOR;
|
|
23135
|
-
}
|
|
23136
|
-
/**
|
|
23137
|
-
* Get the project directory for a workspace
|
|
23138
|
-
*
|
|
23139
|
-
* Claude Code hashes the workspace path to create project directories.
|
|
23140
|
-
* We need to find the project directory that contains sessions for this workspace.
|
|
23141
|
-
*/
|
|
23142
|
-
getProjectDirForWorkspace(workspace) {
|
|
23143
|
-
if (!existsSync(CLAUDE_PROJECTS_DIR)) return null;
|
|
23144
|
-
const projectDirs = getProjectDirsSync();
|
|
23145
|
-
for (const projectDir of projectDirs) {
|
|
23146
|
-
const indexPath = join$1(projectDir, "sessions-index.json");
|
|
23147
|
-
if (existsSync(indexPath)) try {
|
|
23148
|
-
if (readFileSync(indexPath, "utf-8").includes(workspace)) return projectDir;
|
|
23149
|
-
} catch {}
|
|
23150
|
-
}
|
|
23151
|
-
return null;
|
|
23152
|
-
}
|
|
23153
|
-
/**
|
|
23154
|
-
* Get the active session ID for an agent from the sessions index
|
|
23155
|
-
*/
|
|
23156
|
-
getActiveSessionId(projectDir) {
|
|
23157
|
-
const indexPath = join$1(projectDir, "sessions-index.json");
|
|
23158
|
-
if (!existsSync(indexPath)) return null;
|
|
23159
|
-
try {
|
|
23160
|
-
const indexContent = readFileSync(indexPath, "utf-8");
|
|
23161
|
-
const index = JSON.parse(indexContent);
|
|
23162
|
-
if (index.sessions && Array.isArray(index.sessions)) {
|
|
23163
|
-
const sessions = index.sessions;
|
|
23164
|
-
if (sessions.length === 0) return null;
|
|
23165
|
-
return sessions.sort((a, b) => {
|
|
23166
|
-
return new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime();
|
|
23167
|
-
})[0].sessionId;
|
|
23168
|
-
}
|
|
23169
|
-
} catch {}
|
|
23170
|
-
return null;
|
|
23171
|
-
}
|
|
23172
|
-
/**
|
|
23173
|
-
* Get the most recent JSONL file for a project
|
|
23174
|
-
*/
|
|
23175
|
-
getMostRecentJSONL(projectDir) {
|
|
23176
|
-
const files = getSessionFilesSync(projectDir);
|
|
23177
|
-
return files.length > 0 ? files[0] : null;
|
|
23178
|
-
}
|
|
23179
|
-
/**
|
|
23180
|
-
* Get the session path for an agent
|
|
23181
|
-
*/
|
|
23182
|
-
getSessionPath(agentId) {
|
|
23183
|
-
const state = getAgentStateSync(agentId);
|
|
23184
|
-
if (!state) return null;
|
|
23185
|
-
const projectDir = this.getProjectDirForWorkspace(state.workspace);
|
|
23186
|
-
if (!projectDir) return null;
|
|
23187
|
-
const sessionId = this.getActiveSessionId(projectDir);
|
|
23188
|
-
if (sessionId) {
|
|
23189
|
-
const sessionPath = join$1(projectDir, `${sessionId}.jsonl`);
|
|
23190
|
-
if (existsSync(sessionPath)) return sessionPath;
|
|
23191
|
-
}
|
|
23192
|
-
return this.getMostRecentJSONL(projectDir);
|
|
23193
|
-
}
|
|
23194
|
-
/**
|
|
23195
|
-
* Get last activity timestamp for an agent
|
|
23196
|
-
*
|
|
23197
|
-
* Uses passive detection via JSONL file modification time.
|
|
23198
|
-
*/
|
|
23199
|
-
getLastActivity(agentId) {
|
|
23200
|
-
const sessionPath = this.getSessionPath(agentId);
|
|
23201
|
-
if (!sessionPath || !existsSync(sessionPath)) return null;
|
|
23202
|
-
try {
|
|
23203
|
-
return statSync(sessionPath).mtime;
|
|
23204
|
-
} catch {
|
|
23205
|
-
return null;
|
|
23206
|
-
}
|
|
23207
|
-
}
|
|
23208
|
-
/**
|
|
23209
|
-
* Read active heartbeat file if it exists
|
|
23210
|
-
*/
|
|
23211
|
-
getActiveHeartbeat(agentId) {
|
|
23212
|
-
const heartbeatPath = join$1(homedir(), ".overdeck", "heartbeats", `${agentId}.json`);
|
|
23213
|
-
if (!existsSync(heartbeatPath)) return null;
|
|
23214
|
-
try {
|
|
23215
|
-
const content = readFileSync(heartbeatPath, "utf-8");
|
|
23216
|
-
const data = JSON.parse(content);
|
|
23217
|
-
const timestamp = new Date(data.timestamp);
|
|
23218
|
-
if ((/* @__PURE__ */ new Date()).getTime() - timestamp.getTime() > 300 * 1e3) return null;
|
|
23219
|
-
return {
|
|
23220
|
-
timestamp,
|
|
23221
|
-
agentId: data.agent_id || agentId,
|
|
23222
|
-
source: "active-heartbeat",
|
|
23223
|
-
confidence: "high",
|
|
23224
|
-
toolName: data.tool_name,
|
|
23225
|
-
lastAction: data.last_action,
|
|
23226
|
-
currentTask: data.current_task,
|
|
23227
|
-
gitBranch: data.git_branch,
|
|
23228
|
-
workspace: data.workspace,
|
|
23229
|
-
pid: data.pid,
|
|
23230
|
-
sessionId: data.session_id
|
|
23231
|
-
};
|
|
23232
|
-
} catch {
|
|
23233
|
-
return null;
|
|
23234
|
-
}
|
|
23235
|
-
}
|
|
23236
|
-
/**
|
|
23237
|
-
* Get passive heartbeat from file timestamps
|
|
23238
|
-
*/
|
|
23239
|
-
getPassiveHeartbeat(agentId) {
|
|
23240
|
-
const lastActivity = this.getLastActivity(agentId);
|
|
23241
|
-
if (!lastActivity) return null;
|
|
23242
|
-
return {
|
|
23243
|
-
timestamp: lastActivity,
|
|
23244
|
-
agentId,
|
|
23245
|
-
source: "jsonl",
|
|
23246
|
-
confidence: "medium"
|
|
23247
|
-
};
|
|
23248
|
-
}
|
|
23249
|
-
/**
|
|
23250
|
-
* Get heartbeat for an agent
|
|
23251
|
-
*
|
|
23252
|
-
* Tries active heartbeat first (if hooks configured), falls back to passive.
|
|
23253
|
-
*/
|
|
23254
|
-
getHeartbeat(agentId) {
|
|
23255
|
-
const activeHeartbeat = this.getActiveHeartbeat(agentId);
|
|
23256
|
-
if (activeHeartbeat) return activeHeartbeat;
|
|
23257
|
-
return this.getPassiveHeartbeat(agentId);
|
|
23258
|
-
}
|
|
23259
|
-
/**
|
|
23260
|
-
* Get token usage for an agent's current session
|
|
23261
|
-
*/
|
|
23262
|
-
getTokenUsage(agentId) {
|
|
23263
|
-
const sessionPath = this.getSessionPath(agentId);
|
|
23264
|
-
if (!sessionPath) return null;
|
|
23265
|
-
const sessionUsage = parseClaudeSessionSync(sessionPath);
|
|
23266
|
-
if (!sessionUsage) return null;
|
|
23267
|
-
return sessionUsage.usage;
|
|
23268
|
-
}
|
|
23269
|
-
/**
|
|
23270
|
-
* Get cost breakdown for an agent's current session
|
|
23271
|
-
*/
|
|
23272
|
-
getSessionCost(agentId) {
|
|
23273
|
-
const sessionPath = this.getSessionPath(agentId);
|
|
23274
|
-
if (!sessionPath) return null;
|
|
23275
|
-
const sessionUsage = parseClaudeSessionSync(sessionPath);
|
|
23276
|
-
if (!sessionUsage) return null;
|
|
23277
|
-
const inputPrice = 3 / 1e6;
|
|
23278
|
-
const outputPrice = 15 / 1e6;
|
|
23279
|
-
const cacheReadPrice = .3 / 1e6;
|
|
23280
|
-
const cacheWritePrice = 3.75 / 1e6;
|
|
23281
|
-
const usage = sessionUsage.usage;
|
|
23282
|
-
const inputCost = usage.inputTokens * inputPrice;
|
|
23283
|
-
const outputCost = usage.outputTokens * outputPrice;
|
|
23284
|
-
const cacheReadCost = (usage.cacheReadTokens || 0) * cacheReadPrice;
|
|
23285
|
-
const cacheWriteCost = (usage.cacheWriteTokens || 0) * cacheWritePrice;
|
|
23286
|
-
return {
|
|
23287
|
-
inputCost,
|
|
23288
|
-
outputCost,
|
|
23289
|
-
cacheReadCost,
|
|
23290
|
-
cacheWriteCost,
|
|
23291
|
-
totalCost: inputCost + outputCost + cacheReadCost + cacheWriteCost,
|
|
23292
|
-
currency: "USD"
|
|
23293
|
-
};
|
|
23294
|
-
}
|
|
23295
|
-
/**
|
|
23296
|
-
* Send a message to a running agent
|
|
23297
|
-
*/
|
|
23298
|
-
async sendMessage(agentId, message) {
|
|
23299
|
-
if (!sessionExistsSync(agentId)) throw new Error(`Agent ${agentId} is not running`);
|
|
23300
|
-
await Effect.runPromise(sendKeys(agentId, message));
|
|
23301
|
-
const mailDir = join$1(getAgentDir(agentId), "mail");
|
|
23302
|
-
mkdirSync(mailDir, { recursive: true });
|
|
23303
|
-
writeFileSync(join$1(mailDir, `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.md`), `# Message\n\n${message}\n`);
|
|
23304
|
-
}
|
|
23305
|
-
/**
|
|
23306
|
-
* Kill an agent
|
|
23307
|
-
*/
|
|
23308
|
-
killAgent(agentId) {
|
|
23309
|
-
if (!sessionExistsSync(agentId)) throw new Error(`Agent ${agentId} is not running`);
|
|
23310
|
-
killSessionSync(agentId);
|
|
23311
|
-
saveAgentRuntimeState(agentId, {
|
|
23312
|
-
state: "idle",
|
|
23313
|
-
lastActivity: (/* @__PURE__ */ new Date()).toISOString()
|
|
23314
|
-
});
|
|
23315
|
-
const state = getAgentStateSync(agentId);
|
|
23316
|
-
if (state) {
|
|
23317
|
-
state.status = "stopped";
|
|
23318
|
-
saveAgentStateSync(state);
|
|
23319
|
-
}
|
|
23320
|
-
}
|
|
23321
|
-
/**
|
|
23322
|
-
* Spawn a new agent
|
|
23323
|
-
*/
|
|
23324
|
-
async spawnAgent(config) {
|
|
23325
|
-
const state = await spawnAgent({
|
|
23326
|
-
issueId: config.agentId.replace(/^agent-/, ""),
|
|
23327
|
-
workspace: config.workspace,
|
|
23328
|
-
harness: "claude-code",
|
|
23329
|
-
model: determineModel({
|
|
23330
|
-
model: config.model,
|
|
23331
|
-
role: "work",
|
|
23332
|
-
spawnKey: `work:${config.agentId.replace(/^agent-/, "")}`
|
|
23333
|
-
}),
|
|
23334
|
-
role: "work",
|
|
23335
|
-
prompt: config.prompt
|
|
23336
|
-
});
|
|
23337
|
-
const projectDir = this.getProjectDirForWorkspace(config.workspace);
|
|
23338
|
-
const sessionId = projectDir ? this.getActiveSessionId(projectDir) : void 0;
|
|
23339
|
-
return {
|
|
23340
|
-
id: state.id,
|
|
23341
|
-
sessionId: sessionId || "unknown",
|
|
23342
|
-
runtime: "claude-code",
|
|
23343
|
-
model: state.model,
|
|
23344
|
-
workspace: state.workspace,
|
|
23345
|
-
startedAt: new Date(state.startedAt)
|
|
23346
|
-
};
|
|
23347
|
-
}
|
|
23348
|
-
/**
|
|
23349
|
-
* List all sessions for this runtime
|
|
23350
|
-
*/
|
|
23351
|
-
listSessions(workspace) {
|
|
23352
|
-
const sessions = [];
|
|
23353
|
-
if (workspace) {
|
|
23354
|
-
const projectDir = this.getProjectDirForWorkspace(workspace);
|
|
23355
|
-
if (projectDir) {
|
|
23356
|
-
const files = getSessionFilesSync(projectDir);
|
|
23357
|
-
for (const file of files) {
|
|
23358
|
-
const session = this.parseSessionFile(file, workspace);
|
|
23359
|
-
if (session) sessions.push(session);
|
|
23360
|
-
}
|
|
23361
|
-
}
|
|
23362
|
-
} else {
|
|
23363
|
-
const projectDirs = getProjectDirsSync();
|
|
23364
|
-
for (const projectDir of projectDirs) {
|
|
23365
|
-
const files = getSessionFilesSync(projectDir);
|
|
23366
|
-
for (const file of files) {
|
|
23367
|
-
const session = this.parseSessionFile(file);
|
|
23368
|
-
if (session) sessions.push(session);
|
|
23369
|
-
}
|
|
23370
|
-
}
|
|
23371
|
-
}
|
|
23372
|
-
return sessions;
|
|
23373
|
-
}
|
|
23374
|
-
/**
|
|
23375
|
-
* Parse a session file into a Session object
|
|
23376
|
-
*/
|
|
23377
|
-
parseSessionFile(file, workspace) {
|
|
23378
|
-
const sessionUsage = parseClaudeSessionSync(file);
|
|
23379
|
-
if (!sessionUsage) return null;
|
|
23380
|
-
const stat = statSync(file);
|
|
23381
|
-
return {
|
|
23382
|
-
id: sessionUsage.sessionId,
|
|
23383
|
-
agentId: "unknown",
|
|
23384
|
-
workspace: workspace || "unknown",
|
|
23385
|
-
model: sessionUsage.model,
|
|
23386
|
-
startedAt: new Date(sessionUsage.startTime),
|
|
23387
|
-
lastActivity: stat.mtime,
|
|
23388
|
-
tokenUsage: sessionUsage.usage
|
|
23389
|
-
};
|
|
23390
|
-
}
|
|
23391
|
-
/**
|
|
23392
|
-
* Check if an agent is running
|
|
23393
|
-
*/
|
|
23394
|
-
isRunning(agentId) {
|
|
23395
|
-
return sessionExistsSync(agentId);
|
|
23396
|
-
}
|
|
23397
|
-
};
|
|
23398
|
-
/**
|
|
23399
|
-
* Create a Claude Code runtime instance
|
|
23400
|
-
*/
|
|
23401
|
-
function createClaudeCodeRuntimeSync() {
|
|
23402
|
-
return new ClaudeCodeRuntimeSync();
|
|
23403
|
-
}
|
|
23404
|
-
//#endregion
|
|
23405
|
-
//#region ../../lib/cost-parsers/pi-parser.ts
|
|
23406
|
-
init_errors();
|
|
23407
|
-
//#endregion
|
|
23408
|
-
//#region ../../lib/runtimes/pi.ts
|
|
23409
|
-
init_behavior();
|
|
23410
|
-
init_tmux();
|
|
23411
|
-
init_errors();
|
|
23412
|
-
init_paths();
|
|
23413
|
-
promisify(exec);
|
|
23414
|
-
//#endregion
|
|
23415
|
-
//#region ../../lib/runtimes/index.ts
|
|
23416
|
-
init_behavior();
|
|
23417
|
-
init_agents$1();
|
|
23418
|
-
/**
|
|
23419
|
-
* Runtime registry implementation
|
|
23420
|
-
*
|
|
23421
|
-
* Manages multiple runtime adapters and provides lookup by agent ID.
|
|
23422
|
-
*/
|
|
23423
|
-
var RuntimeRegistry = class {
|
|
23424
|
-
runtimes = /* @__PURE__ */ new Map();
|
|
23425
|
-
/**
|
|
23426
|
-
* Register a runtime adapter
|
|
23427
|
-
*/
|
|
23428
|
-
register(runtime) {
|
|
23429
|
-
this.runtimes.set(runtime.name, runtime);
|
|
23430
|
-
}
|
|
23431
|
-
/**
|
|
23432
|
-
* Get a runtime by name
|
|
23433
|
-
*/
|
|
23434
|
-
get(name) {
|
|
23435
|
-
return this.runtimes.get(name);
|
|
23436
|
-
}
|
|
23437
|
-
/**
|
|
23438
|
-
* Get all registered runtimes
|
|
23439
|
-
*/
|
|
23440
|
-
getAll() {
|
|
23441
|
-
return Array.from(this.runtimes.values());
|
|
23442
|
-
}
|
|
23443
|
-
/**
|
|
23444
|
-
* Get the runtime for a specific agent.
|
|
23445
|
-
*
|
|
23446
|
-
* Reads the agent's state file and dispatches by `state.harness`. When
|
|
23447
|
-
* the harness field is missing or carries a legacy value (e.g. 'claude'
|
|
23448
|
-
* from pre-PAN-636 wire format), we fall back to the claude-code runtime
|
|
23449
|
-
* to preserve back-compat (PAN-636 ac2).
|
|
23450
|
-
*/
|
|
23451
|
-
getRuntimeForAgent(agentId) {
|
|
23452
|
-
const state = getAgentStateSync(agentId);
|
|
23453
|
-
if (!state) return null;
|
|
23454
|
-
const harness = state.harness;
|
|
23455
|
-
if (harness === "ohmypi" || harness === "pi") return this.get("ohmypi") ?? null;
|
|
23456
|
-
if (harness === "codex") return this.get("codex") ?? null;
|
|
23457
|
-
return this.get("claude-code") ?? null;
|
|
23458
|
-
}
|
|
23459
|
-
};
|
|
23460
|
-
/**
|
|
23461
|
-
* Global runtime registry instance
|
|
23462
|
-
*/
|
|
23463
|
-
let globalRegistry = null;
|
|
23464
|
-
/**
|
|
23465
|
-
* Get the global runtime registry
|
|
23466
|
-
*
|
|
23467
|
-
* Creates a new registry if one doesn't exist.
|
|
23468
|
-
* Registers Claude Code runtime by default.
|
|
23469
|
-
*/
|
|
23470
|
-
function getGlobalRegistry() {
|
|
23471
|
-
if (!globalRegistry) {
|
|
23472
|
-
globalRegistry = new RuntimeRegistry();
|
|
23473
|
-
globalRegistry.register(createClaudeCodeRuntimeSync());
|
|
23474
|
-
globalRegistry.register(createOhmypiRuntimeSync());
|
|
23475
|
-
globalRegistry.register(createCodexRuntimeSync());
|
|
23476
|
-
}
|
|
23477
|
-
return globalRegistry;
|
|
23478
|
-
}
|
|
23479
|
-
/**
|
|
23480
|
-
* Helper to get the runtime for an agent from the global registry
|
|
23481
|
-
*/
|
|
23482
|
-
function getRuntimeForAgent(agentId) {
|
|
23483
|
-
return getGlobalRegistry().getRuntimeForAgent(agentId);
|
|
23484
|
-
}
|
|
23485
|
-
//#endregion
|
|
23486
|
-
//#region ../../lib/cloister/deacon-inspect.ts
|
|
23487
|
-
init_review_status();
|
|
23488
|
-
init_tmux();
|
|
23489
|
-
/**
|
|
23490
|
-
* Inspect prompts state a 10-minute budget. Deacon gives the agent a small
|
|
23491
|
-
* grace window beyond that, then fails loud so the parent work agent never waits
|
|
23492
|
-
* forever for a verdict that will not arrive.
|
|
22502
|
+
* Inspect prompts state a 10-minute budget. Deacon gives the agent a small
|
|
22503
|
+
* grace window beyond that, then fails loud so the parent work agent never waits
|
|
22504
|
+
* forever for a verdict that will not arrive.
|
|
23493
22505
|
*/
|
|
23494
22506
|
const INSPECT_TIMEOUT_MS = 12 * 6e4;
|
|
23495
22507
|
function inspectSessionName(issueId, beadId) {
|
|
@@ -23526,7 +22538,7 @@ async function checkInspectAgentTimeouts(now = /* @__PURE__ */ new Date()) {
|
|
|
23526
22538
|
console.warn(`[deacon] Failed to kill inspect session ${sessionName}: ${msg}`);
|
|
23527
22539
|
});
|
|
23528
22540
|
try {
|
|
23529
|
-
const { messageAgent } = await import("./agents-
|
|
22541
|
+
const { messageAgent } = await import("./agents-CEcaxSkR.js");
|
|
23530
22542
|
await messageAgent(`agent-${issueId.toLowerCase()}`, verdict, "deacon:inspect-watchdog");
|
|
23531
22543
|
} catch (err) {
|
|
23532
22544
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -23539,43 +22551,6 @@ async function checkInspectAgentTimeouts(now = /* @__PURE__ */ new Date()) {
|
|
|
23539
22551
|
return actions;
|
|
23540
22552
|
}
|
|
23541
22553
|
//#endregion
|
|
23542
|
-
//#region ../../lib/cloister/agent-idle.ts
|
|
23543
|
-
init_agents$1();
|
|
23544
|
-
init_tmux();
|
|
23545
|
-
function getAgentEffectiveLastActivityMs(agentId) {
|
|
23546
|
-
const candidates = [];
|
|
23547
|
-
const runtimeState = getAgentRuntimeStateSync(agentId);
|
|
23548
|
-
const runtimeMs = runtimeState?.lastActivity ? new Date(runtimeState.lastActivity).getTime() : NaN;
|
|
23549
|
-
if (Number.isFinite(runtimeMs)) candidates.push(runtimeMs);
|
|
23550
|
-
try {
|
|
23551
|
-
const tmuxActivity = listPaneValuesSync(agentId, "#{window_activity}").map((value) => Number.parseInt(value.trim(), 10) * 1e3).filter(Number.isFinite);
|
|
23552
|
-
candidates.push(...tmuxActivity);
|
|
23553
|
-
} catch {}
|
|
23554
|
-
try {
|
|
23555
|
-
const heartbeat = getRuntimeForAgent(agentId)?.getHeartbeat(agentId);
|
|
23556
|
-
if (heartbeat?.timestamp) {
|
|
23557
|
-
const heartbeatMs = heartbeat.timestamp.getTime();
|
|
23558
|
-
if (Number.isFinite(heartbeatMs)) candidates.push(heartbeatMs);
|
|
23559
|
-
}
|
|
23560
|
-
} catch {}
|
|
23561
|
-
return candidates.length > 0 ? Math.max(...candidates) : null;
|
|
23562
|
-
}
|
|
23563
|
-
function isAgentIdleForNudge(agentId, staleActiveThresholdMs = 300 * 1e3, now = Date.now()) {
|
|
23564
|
-
const runtimeState = getAgentRuntimeStateSync(agentId);
|
|
23565
|
-
const effectiveLastActivityMs = getAgentEffectiveLastActivityMs(agentId);
|
|
23566
|
-
if (!runtimeState) {
|
|
23567
|
-
if (effectiveLastActivityMs === null) {
|
|
23568
|
-
console.log(`[deacon] ${agentId}: no runtime.json — skipping (hook not yet fired)`);
|
|
23569
|
-
return false;
|
|
23570
|
-
}
|
|
23571
|
-
return now - effectiveLastActivityMs > staleActiveThresholdMs;
|
|
23572
|
-
}
|
|
23573
|
-
if (runtimeState.state === "suspended" || runtimeState.state === "stopped") return false;
|
|
23574
|
-
if (runtimeState.state === "waiting-on-human") return false;
|
|
23575
|
-
if (runtimeState.state === "idle") return true;
|
|
23576
|
-
return now - (effectiveLastActivityMs ?? new Date(runtimeState.lastActivity).getTime()) > staleActiveThresholdMs;
|
|
23577
|
-
}
|
|
23578
|
-
//#endregion
|
|
23579
22554
|
//#region ../../lib/cloister/modal-detector.ts
|
|
23580
22555
|
init_tmux();
|
|
23581
22556
|
const KNOWN_AGENT_MODALS = [{
|
|
@@ -23584,9 +22559,15 @@ const KNOWN_AGENT_MODALS = [{
|
|
|
23584
22559
|
keys: ["Down", "Enter"]
|
|
23585
22560
|
}];
|
|
23586
22561
|
/** Rollout JSONL is launch/turn attribution only until a captured switch proves otherwise. */
|
|
22562
|
+
const MODEL_SHAPED_TOKEN = /^(?:gpt|o\d|claude|kimi|glm|gemini|deepseek|qwen|minimax|grok)[\w.-]*$/i;
|
|
23587
22563
|
function paneShowsModelSwitch(pane, launchModel) {
|
|
23588
|
-
const
|
|
23589
|
-
|
|
22564
|
+
const modelPhrase = pane.match(/model\s+(?:switched|switching)\s+to\s+([\w.-]+)|(?:switched|switching)\s+model\s+to\s+([\w.-]+)/i);
|
|
22565
|
+
let target = modelPhrase?.[1] ?? modelPhrase?.[2];
|
|
22566
|
+
if (!target) {
|
|
22567
|
+
const generic = pane.match(/(?:switched|switching)\s+to\s+([\w.-]+)/i)?.[1];
|
|
22568
|
+
if (generic && MODEL_SHAPED_TOKEN.test(generic)) target = generic;
|
|
22569
|
+
}
|
|
22570
|
+
return Boolean(target && target.toLowerCase() !== launchModel.toLowerCase());
|
|
23590
22571
|
}
|
|
23591
22572
|
const defaultDeps = {
|
|
23592
22573
|
capturePane: (agentId) => Effect.runPromise(capturePane(agentId, 100)),
|
|
@@ -23604,7 +22585,6 @@ async function handleKnownAgentModal(agentId, deps = defaultDeps, initialPane) {
|
|
|
23604
22585
|
//#endregion
|
|
23605
22586
|
//#region ../../lib/cloister/deacon-api-recovery.ts
|
|
23606
22587
|
init_agents$1();
|
|
23607
|
-
init_paths();
|
|
23608
22588
|
init_review_status();
|
|
23609
22589
|
init_tmux();
|
|
23610
22590
|
/**
|
|
@@ -23701,7 +22681,7 @@ async function maybeProactivelyCompactContext(sessionName, now) {
|
|
|
23701
22681
|
if (!agentState?.workspace || !sessionId || !agentState.model) return null;
|
|
23702
22682
|
let usage = null;
|
|
23703
22683
|
try {
|
|
23704
|
-
const { computeContextUsage } = await import("./conversation-service-
|
|
22684
|
+
const { computeContextUsage } = await import("./conversation-service-BTzObqGi.js");
|
|
23705
22685
|
usage = await computeContextUsage(sessionFilePath(agentState.workspace, sessionId), agentState.model);
|
|
23706
22686
|
} catch {
|
|
23707
22687
|
return null;
|
|
@@ -23798,13 +22778,13 @@ async function checkApiErrorAgents() {
|
|
|
23798
22778
|
const st = getAgentStateSync(sessionName);
|
|
23799
22779
|
const sid = st?.sessionId ?? runtimeState?.claudeSessionId;
|
|
23800
22780
|
if (st?.workspace && sid && st.model) {
|
|
23801
|
-
const { computeContextUsage } = await import("./conversation-service-
|
|
22781
|
+
const { computeContextUsage } = await import("./conversation-service-BTzObqGi.js");
|
|
23802
22782
|
const usage = await computeContextUsage(sessionFilePath(st.workspace, sid), st.model);
|
|
23803
22783
|
if (usage && usage.percentUsed < 85) recoveredPct = usage.percentUsed;
|
|
23804
22784
|
}
|
|
23805
22785
|
} catch {}
|
|
23806
22786
|
if (recoveredPct !== null) {
|
|
23807
|
-
const { clearWorkspaceStuck } = await import("./review-status-sync-
|
|
22787
|
+
const { clearWorkspaceStuck } = await import("./review-status-sync-CfSixhhX.js");
|
|
23808
22788
|
clearWorkspaceStuck(issueId);
|
|
23809
22789
|
stuckOverflowNativeRecoveryState.delete(sessionName);
|
|
23810
22790
|
actions.push(`Context overflow recovery: cleared stuck flag for ${sessionName} (context back to ${Math.round(recoveredPct)}%)`);
|
|
@@ -23820,7 +22800,7 @@ async function checkApiErrorAgents() {
|
|
|
23820
22800
|
rec.attempts += 1;
|
|
23821
22801
|
rec.lastAttempt = now;
|
|
23822
22802
|
stuckOverflowNativeRecoveryState.set(sessionName, rec);
|
|
23823
|
-
const { resumeAgent } = await import("./agents-
|
|
22803
|
+
const { resumeAgent } = await import("./agents-CEcaxSkR.js");
|
|
23824
22804
|
const recovered = await resumeAgent(sessionName, void 0, { compact: true });
|
|
23825
22805
|
if (recovered.success) {
|
|
23826
22806
|
stuckOverflowNativeRecoveryState.delete(sessionName);
|
|
@@ -23868,7 +22848,7 @@ async function checkApiErrorAgents() {
|
|
|
23868
22848
|
}
|
|
23869
22849
|
const compactAttempts = (ov?.compactAttempts ?? 0) + 1;
|
|
23870
22850
|
if (issueId !== null) {
|
|
23871
|
-
const { resumeAgent } = await import("./agents-
|
|
22851
|
+
const { resumeAgent } = await import("./agents-CEcaxSkR.js");
|
|
23872
22852
|
const resumeResult = await resumeAgent(sessionName, void 0, { compact: true });
|
|
23873
22853
|
contextOverflowRecoveryState.set(sessionName, {
|
|
23874
22854
|
lastAttempt: now,
|
|
@@ -23943,8 +22923,8 @@ async function checkApiErrorAgents() {
|
|
|
23943
22923
|
}
|
|
23944
22924
|
//#endregion
|
|
23945
22925
|
//#region ../../lib/cloister/preemption.ts
|
|
23946
|
-
init_specialists();
|
|
23947
22926
|
init_review_monitor();
|
|
22927
|
+
init_specialists();
|
|
23948
22928
|
/**
|
|
23949
22929
|
* PAN-2507: preemptive pipeline scheduler.
|
|
23950
22930
|
*
|
|
@@ -24115,6 +23095,8 @@ async function resumeYieldedVictim(agentId) {
|
|
|
24115
23095
|
init_archive_planning();
|
|
24116
23096
|
init_issue_closed();
|
|
24117
23097
|
init_merge_verification();
|
|
23098
|
+
init_state_mapping();
|
|
23099
|
+
init_tracker_utils();
|
|
24118
23100
|
const execFileAsync$5 = promisify$1(execFile$1);
|
|
24119
23101
|
const autoCloseOutCache = /* @__PURE__ */ new Map();
|
|
24120
23102
|
const AUTO_CLOSE_OUT_CACHE_TTL_MS = 600 * 1e3;
|
|
@@ -24233,7 +23215,7 @@ function reviewConvoyLiveness(issueId) {
|
|
|
24233
23215
|
*/
|
|
24234
23216
|
async function recoverUnhealthyTestStack(issueId, workspacePath) {
|
|
24235
23217
|
const key = issueId.toUpperCase();
|
|
24236
|
-
const { getWorkspaceStackHealth } = await import("./stack-health-
|
|
23218
|
+
const { getWorkspaceStackHealth } = await import("./stack-health-DVN7zRnL.js");
|
|
24237
23219
|
const health = await Effect.runPromise(getWorkspaceStackHealth(issueId, { workspacePath }));
|
|
24238
23220
|
if (health.healthy) {
|
|
24239
23221
|
testStackRebuildState.delete(key);
|
|
@@ -24265,7 +23247,7 @@ async function recoverUnhealthyTestStack(issueId, workspacePath) {
|
|
|
24265
23247
|
record.attempts += 1;
|
|
24266
23248
|
testStackRebuildState.set(key, record);
|
|
24267
23249
|
console.log(`[deacon] Test stack for ${key} unhealthy (${health.reasons.join("; ")}) — rebuilding (attempt ${record.attempts}/${TEST_STACK_REBUILD_MAX_ATTEMPTS})`);
|
|
24268
|
-
const { rebuildWorkspaceStack } = await import("./rebuild-stack-
|
|
23250
|
+
const { rebuildWorkspaceStack } = await import("./rebuild-stack-nGD_nPZo.js");
|
|
24269
23251
|
const result = await Effect.runPromise(rebuildWorkspaceStack(issueId, { onProgress: (m) => console.log(`[deacon] ${key} stack rebuild: ${m}`) }));
|
|
24270
23252
|
if (!result.success) {
|
|
24271
23253
|
console.warn(`[deacon] Test stack rebuild failed for ${key}: ${result.error}`);
|
|
@@ -24393,7 +23375,7 @@ async function handleReviewCoordinatorDied(issueId, _sessionName, _reason) {
|
|
|
24393
23375
|
return actions;
|
|
24394
23376
|
}
|
|
24395
23377
|
try {
|
|
24396
|
-
const { spawnReviewRoleForIssue } = await import("./review-agent-
|
|
23378
|
+
const { spawnReviewRoleForIssue } = await import("./review-agent-u5q3ip7H.js");
|
|
24397
23379
|
const dispatchResult = await Effect.runPromise(spawnReviewRoleForIssue({
|
|
24398
23380
|
issueId,
|
|
24399
23381
|
workspace,
|
|
@@ -24523,7 +23505,7 @@ async function reconcileReviewStatusOrphan(issueId, rawStatus) {
|
|
|
24523
23505
|
const workspace = agentState?.workspace || (resolved ? findWorkspacePath(resolved.projectPath, issueLower) : null);
|
|
24524
23506
|
if (workspace && resolved && !tryReserveAdvancingSlot() && !await tryYieldForAdvancingDispatch("review", issueId)) actions.push(`Deferred review re-dispatch for ${issueId} — advancing-role concurrency ceiling reached`);
|
|
24525
23507
|
else if (workspace && resolved) try {
|
|
24526
|
-
const { spawnReviewRoleForIssue } = await import("./review-agent-
|
|
23508
|
+
const { spawnReviewRoleForIssue } = await import("./review-agent-u5q3ip7H.js");
|
|
24527
23509
|
const dispatchResult = await Effect.runPromise(spawnReviewRoleForIssue({
|
|
24528
23510
|
issueId,
|
|
24529
23511
|
workspace,
|
|
@@ -24548,8 +23530,8 @@ async function reconcileReviewStatusOrphan(issueId, rawStatus) {
|
|
|
24548
23530
|
const workspace = agentState?.workspace || (resolved ? findWorkspacePath(resolved.projectPath, issueLower) : null);
|
|
24549
23531
|
if (workspace && resolved) {
|
|
24550
23532
|
const branch = `feature/${issueLower}`;
|
|
24551
|
-
const { spawnRun } = await import("./agents-
|
|
24552
|
-
const { buildTestRolePrompt } = await import("./test-agent-queue-
|
|
23533
|
+
const { spawnRun } = await import("./agents-CEcaxSkR.js");
|
|
23534
|
+
const { buildTestRolePrompt } = await import("./test-agent-queue-CnuYku4B.js");
|
|
24553
23535
|
const stackRecovery = await recoverUnhealthyTestStack(issueId, workspace);
|
|
24554
23536
|
if (stackRecovery === "cooldown" || stackRecovery === "exhausted") {
|
|
24555
23537
|
setReviewStatusSync(issueId, { testStatus: "dispatch_failed" });
|
|
@@ -24687,7 +23669,7 @@ async function recoverStalledReviewConvoys(getCanonicalState = getAutoCloseOutCa
|
|
|
24687
23669
|
record.lastAttempt = now;
|
|
24688
23670
|
record.attempts += 1;
|
|
24689
23671
|
stalledReviewConvoyRecoveryState.set(key, record);
|
|
24690
|
-
const { spawnReviewRoleForIssue } = await import("./review-agent-
|
|
23672
|
+
const { spawnReviewRoleForIssue } = await import("./review-agent-u5q3ip7H.js");
|
|
24691
23673
|
try {
|
|
24692
23674
|
const result = await Effect.runPromise(spawnReviewRoleForIssue({
|
|
24693
23675
|
issueId,
|
|
@@ -24758,7 +23740,7 @@ async function checkMissingReviewStatuses() {
|
|
|
24758
23740
|
continue;
|
|
24759
23741
|
}
|
|
24760
23742
|
try {
|
|
24761
|
-
const { spawnReviewRoleForIssue } = await import("./review-agent-
|
|
23743
|
+
const { spawnReviewRoleForIssue } = await import("./review-agent-u5q3ip7H.js");
|
|
24762
23744
|
await Effect.runPromise(spawnReviewRoleForIssue({
|
|
24763
23745
|
issueId,
|
|
24764
23746
|
workspace,
|
|
@@ -24809,7 +23791,7 @@ async function checkStuckReviewing() {
|
|
|
24809
23791
|
const actions = [];
|
|
24810
23792
|
const REVIEW_STUCK_THRESHOLD_MS = 1800 * 1e3;
|
|
24811
23793
|
try {
|
|
24812
|
-
const { loadReviewStatuses, setReviewStatusSync } = await import("./review-status-
|
|
23794
|
+
const { loadReviewStatuses, setReviewStatusSync } = await import("./review-status-CG0iDuWa.js");
|
|
24813
23795
|
const statuses = loadReviewStatuses();
|
|
24814
23796
|
const now = Date.now();
|
|
24815
23797
|
const activeReviewIssues = /* @__PURE__ */ new Set();
|
|
@@ -24825,7 +23807,7 @@ async function checkStuckReviewing() {
|
|
|
24825
23807
|
if (rState?.state === "active" && rState.currentIssue) activeReviewIssues.add(rState.currentIssue.toUpperCase());
|
|
24826
23808
|
}
|
|
24827
23809
|
try {
|
|
24828
|
-
const { listRunningAgents } = await import("./agents-
|
|
23810
|
+
const { listRunningAgents } = await import("./agents-CEcaxSkR.js");
|
|
24829
23811
|
const agents = await Effect.runPromise(listRunningAgents());
|
|
24830
23812
|
for (const agent of agents) {
|
|
24831
23813
|
if (agent.status === "stopped" || agent.status === "error") continue;
|
|
@@ -24958,7 +23940,7 @@ async function checkCompletedButUnsignaledReviews() {
|
|
|
24958
23940
|
}
|
|
24959
23941
|
const nudge = `Your review synthesis is already written and saved. Your ONLY remaining task is to execute this Bash command immediately — do not analyze, do not summarize, do not ask questions, just run it:\n\n${`pan admin specialists done review ${issueId} --status ${verdict}${verdict === "blocked" || verdict === "failed" ? ` --notes "${topBlocker || "See synthesis.md"}"` : ""}`}\n\nRun this command NOW. Do not write any other response before executing it.`;
|
|
24960
23942
|
try {
|
|
24961
|
-
const { messageAgent } = await import("./agents-
|
|
23943
|
+
const { messageAgent } = await import("./agents-CEcaxSkR.js");
|
|
24962
23944
|
await messageAgent(reviewSession, nudge);
|
|
24963
23945
|
unsignaledReviewNudges.set(latestDir, now);
|
|
24964
23946
|
actions.push(`Nudged ${reviewSession} to signal ${verdict} (synthesis written ${Math.round((now - latestMtime) / 6e4)}min ago)`);
|
|
@@ -25079,7 +24061,7 @@ async function respawnIdleReviewer(state, agentId) {
|
|
|
25079
24061
|
return false;
|
|
25080
24062
|
}
|
|
25081
24063
|
try {
|
|
25082
|
-
const { spawnReviewSubRoleForIssue } = await import("./review-agent-
|
|
24064
|
+
const { spawnReviewSubRoleForIssue } = await import("./review-agent-u5q3ip7H.js");
|
|
25083
24065
|
const contextManifestPath = join$1(dirname$1(outputPath), "context.json");
|
|
25084
24066
|
const result = await Effect.runPromise(spawnReviewSubRoleForIssue({
|
|
25085
24067
|
issueId: state.issueId,
|
|
@@ -25117,7 +24099,7 @@ async function nudgeSynthesisForCompleteReviewerReports(states) {
|
|
|
25117
24099
|
const status = getReviewStatusSync(state.issueId);
|
|
25118
24100
|
if (!status || status.reviewStatus !== "reviewing") continue;
|
|
25119
24101
|
const reviewDir = join$1(state.workspace, ".pan", "review", state.reviewRunId);
|
|
25120
|
-
|
|
24102
|
+
const synthesisAlreadyWritten = existsSync(join$1(reviewDir, "synthesis.md"));
|
|
25121
24103
|
const startedMs = Date.parse(state.startedAt);
|
|
25122
24104
|
const readyLines = [];
|
|
25123
24105
|
const reports = [];
|
|
@@ -25156,7 +24138,7 @@ async function nudgeSynthesisForCompleteReviewerReports(states) {
|
|
|
25156
24138
|
if (lastNudge && now - lastNudge < REVIEW_REPORTS_PRESENT_NUDGE_COOLDOWN_MS) continue;
|
|
25157
24139
|
const sessionAlive = await Effect.runPromise(sessionExists(state.id)).catch(() => false);
|
|
25158
24140
|
const paneDead = sessionAlive ? await Effect.runPromise(isPaneDead(state.id)).catch(() => true) : true;
|
|
25159
|
-
if (lastNudge || !sessionAlive || paneDead) {
|
|
24141
|
+
if (synthesisAlreadyWritten || lastNudge || !sessionAlive || paneDead) {
|
|
25160
24142
|
const synthesis = synthesizeReviewFromReports({
|
|
25161
24143
|
issueId: state.issueId,
|
|
25162
24144
|
reviewDir,
|
|
@@ -25208,7 +24190,7 @@ async function nudgeSynthesisForCompleteReviewerReports(states) {
|
|
|
25208
24190
|
"Read the four reports, write synthesis.md, then signal review status exactly as roles/review.md instructs."
|
|
25209
24191
|
].join("\n");
|
|
25210
24192
|
try {
|
|
25211
|
-
const { messageAgent } = await import("./agents-
|
|
24193
|
+
const { messageAgent } = await import("./agents-CEcaxSkR.js");
|
|
25212
24194
|
await messageAgent(state.id, message);
|
|
25213
24195
|
reviewReportsPresentNudges.set(nudgeKey, now);
|
|
25214
24196
|
const action = `Nudged ${state.id} to synthesize from ${REVIEW_SUB_ROLES.length} reviewer reports`;
|
|
@@ -25287,7 +24269,7 @@ async function monitorReviewConvoySignals() {
|
|
|
25287
24269
|
if (!signal) continue;
|
|
25288
24270
|
const message = signal === "ready" ? `REVIEWER_READY ${state.reviewSubRole} ${outputPath}` : signal === "timeout" ? `REVIEWER_TIMEOUT ${state.reviewSubRole} ${reason}` : `REVIEWER_FAILED ${state.reviewSubRole} ${reason}`;
|
|
25289
24271
|
try {
|
|
25290
|
-
const { messageAgent } = await import("./agents-
|
|
24272
|
+
const { messageAgent } = await import("./agents-CEcaxSkR.js");
|
|
25291
24273
|
await messageAgent(state.reviewSynthesisAgentId, message);
|
|
25292
24274
|
state.reviewMonitorSignaled = signal;
|
|
25293
24275
|
saveAgentStateSync(state);
|
|
@@ -25295,7 +24277,7 @@ async function monitorReviewConvoySignals() {
|
|
|
25295
24277
|
actions.push(action);
|
|
25296
24278
|
logDeaconEventSync(`monitorReviewConvoySignals: ${action}`);
|
|
25297
24279
|
if (signal === "ready") try {
|
|
25298
|
-
const { notifyPipelineSync } = await import("./pipeline-notifier-
|
|
24280
|
+
const { notifyPipelineSync } = await import("./pipeline-notifier-BH4PAi-w.js");
|
|
25299
24281
|
notifyPipelineSync({
|
|
25300
24282
|
type: "reviewer_completed",
|
|
25301
24283
|
issueId: state.issueId,
|
|
@@ -25303,7 +24285,7 @@ async function monitorReviewConvoySignals() {
|
|
|
25303
24285
|
});
|
|
25304
24286
|
} catch {}
|
|
25305
24287
|
else if (signal === "timeout") try {
|
|
25306
|
-
const { notifyPipelineSync } = await import("./pipeline-notifier-
|
|
24288
|
+
const { notifyPipelineSync } = await import("./pipeline-notifier-BH4PAi-w.js");
|
|
25307
24289
|
notifyPipelineSync({
|
|
25308
24290
|
type: "reviewer_timed_out",
|
|
25309
24291
|
issueId: state.issueId,
|
|
@@ -25403,7 +24385,7 @@ const FORK_CACHE_CHECK_DELAY_MS = 180 * 1e3;
|
|
|
25403
24385
|
async function checkStalledReviewDiscovery() {
|
|
25404
24386
|
const actions = [];
|
|
25405
24387
|
try {
|
|
25406
|
-
const { listAgentStates } = await import("./agents-
|
|
24388
|
+
const { listAgentStates } = await import("./agents-CEcaxSkR.js");
|
|
25407
24389
|
const states = listAgentStates();
|
|
25408
24390
|
const now = Date.now();
|
|
25409
24391
|
for (const state of states) {
|
|
@@ -25412,7 +24394,7 @@ async function checkStalledReviewDiscovery() {
|
|
|
25412
24394
|
const aged = Number.isFinite(startedMs) && now - startedMs > 48e4;
|
|
25413
24395
|
const dead = !await Effect.runPromise(sessionExists(state.id)).catch(() => false) || await Effect.runPromise(isPaneDead(state.id)).catch(() => true);
|
|
25414
24396
|
if (!aged && !dead) continue;
|
|
25415
|
-
const { handleReviewDiscoveryReady } = await import("./review-agent-
|
|
24397
|
+
const { handleReviewDiscoveryReady } = await import("./review-agent-u5q3ip7H.js");
|
|
25416
24398
|
const result = await handleReviewDiscoveryReady(state.issueId, { source: dead ? "deacon-backstop (parent dead)" : "deacon-backstop (discovery timeout)" });
|
|
25417
24399
|
actions.push(result.message);
|
|
25418
24400
|
logDeaconEventSync(`checkStalledReviewDiscovery: ${result.message}`);
|
|
@@ -25435,8 +24417,8 @@ async function checkStalledReviewDiscovery() {
|
|
|
25435
24417
|
async function checkStalledReviewParents() {
|
|
25436
24418
|
const actions = [];
|
|
25437
24419
|
try {
|
|
25438
|
-
const { listAgentStates, markAgentStoppedState } = await import("./agents-
|
|
25439
|
-
const { PARENT_REVIEW_TIMEOUT_MS } = await import("./review-agent-
|
|
24420
|
+
const { listAgentStates, markAgentStoppedState } = await import("./agents-CEcaxSkR.js");
|
|
24421
|
+
const { PARENT_REVIEW_TIMEOUT_MS } = await import("./review-agent-u5q3ip7H.js");
|
|
25440
24422
|
const states = listAgentStates();
|
|
25441
24423
|
const now = Date.now();
|
|
25442
24424
|
for (const state of states) {
|
|
@@ -25485,8 +24467,8 @@ async function checkStalledReviewParents() {
|
|
|
25485
24467
|
async function checkReviewForkCacheMisses() {
|
|
25486
24468
|
const actions = [];
|
|
25487
24469
|
try {
|
|
25488
|
-
const { listAgentStates, saveAgentState } = await import("./agents-
|
|
25489
|
-
const { readEventsSync } = await import("./events-
|
|
24470
|
+
const { listAgentStates, saveAgentState } = await import("./agents-CEcaxSkR.js");
|
|
24471
|
+
const { readEventsSync } = await import("./events-rIGncmP1.js");
|
|
25490
24472
|
const { emitActivityEntrySync } = await import("./activity-logger-DvYvFhwZ.js");
|
|
25491
24473
|
const states = listAgentStates();
|
|
25492
24474
|
const now = Date.now();
|
|
@@ -25633,7 +24615,7 @@ async function reconcileStaleMergeStatus() {
|
|
|
25633
24615
|
if (!project) continue;
|
|
25634
24616
|
let specStatus;
|
|
25635
24617
|
try {
|
|
25636
|
-
const { findSpecByIssue } = await import("./specs-
|
|
24618
|
+
const { findSpecByIssue } = await import("./specs-RzcDgozr.js");
|
|
25637
24619
|
const spec = await Effect.runPromise(findSpecByIssue(project.projectPath, issueId));
|
|
25638
24620
|
specStatus = spec?.status;
|
|
25639
24621
|
if (spec && (spec.status === "completed" || spec.status === "cancelled")) {
|
|
@@ -25648,7 +24630,7 @@ async function reconcileStaleMergeStatus() {
|
|
|
25648
24630
|
if (branchTip.stdout.trim() === mainTip.stdout.trim()) console.log(`[deacon] ${issueId}: branch ${branch} points at main; not treating zero-commit branch as merged`);
|
|
25649
24631
|
} catch {}
|
|
25650
24632
|
if (!isMerged) {
|
|
25651
|
-
const { resolveGitHubIssueSync: _resolveGitHubIssue } = await import("./tracker-utils-
|
|
24633
|
+
const { resolveGitHubIssueSync: _resolveGitHubIssue } = await import("./tracker-utils-DkKyRT0H.js");
|
|
25652
24634
|
const ghResolved = _resolveGitHubIssue(issueId);
|
|
25653
24635
|
if (ghResolved.isGitHub) try {
|
|
25654
24636
|
const { stdout } = await execFileAsync$4("gh", [
|
|
@@ -25685,7 +24667,7 @@ async function reconcileStaleMergeStatus() {
|
|
|
25685
24667
|
actions.push(msg);
|
|
25686
24668
|
console.log(`[deacon] ${msg}`);
|
|
25687
24669
|
try {
|
|
25688
|
-
const { postMergeLifecycle } = await import("./merge-agent-
|
|
24670
|
+
const { postMergeLifecycle } = await import("./merge-agent-ejC7Wos8.js");
|
|
25689
24671
|
postMergeLifecycle(issueId, project.projectPath, branch, { skipDeploy: true }).catch((err) => console.warn(`[deacon] postMergeLifecycle (reconcile) failed for ${issueId}: ${err}`));
|
|
25690
24672
|
} catch (err) {
|
|
25691
24673
|
console.warn(`[deacon] Could not import postMergeLifecycle: ${err}`);
|
|
@@ -25710,7 +24692,7 @@ const falseMergedReset = /* @__PURE__ */ new Set();
|
|
|
25710
24692
|
async function reconcileFalseMerged() {
|
|
25711
24693
|
const actions = [];
|
|
25712
24694
|
try {
|
|
25713
|
-
const { getPullRequestState, isGitHubAppConfigured } = await import("./github-app-
|
|
24695
|
+
const { getPullRequestState, isGitHubAppConfigured } = await import("./github-app-Bwt9lK4A.js");
|
|
25714
24696
|
if (!isGitHubAppConfigured()) return actions;
|
|
25715
24697
|
const statuses = loadReviewStatuses();
|
|
25716
24698
|
for (const [issueId, status] of Object.entries(statuses)) {
|
|
@@ -25755,7 +24737,7 @@ const CLOSED_PR_RECONCILE_COOLDOWN_MS = 600 * 1e3;
|
|
|
25755
24737
|
async function reconcileClosedPrReadyForMerge() {
|
|
25756
24738
|
const actions = [];
|
|
25757
24739
|
try {
|
|
25758
|
-
const { getPullRequestState, isGitHubAppConfigured } = await import("./github-app-
|
|
24740
|
+
const { getPullRequestState, isGitHubAppConfigured } = await import("./github-app-Bwt9lK4A.js");
|
|
25759
24741
|
if (!isGitHubAppConfigured()) return actions;
|
|
25760
24742
|
const statuses = loadReviewStatuses();
|
|
25761
24743
|
const now = Date.now();
|
|
@@ -25827,7 +24809,7 @@ const STALE_MERGE_BLOCKER_COOLDOWN_MS = 120 * 1e3;
|
|
|
25827
24809
|
async function reconcileStaleMergeBlockers() {
|
|
25828
24810
|
const actions = [];
|
|
25829
24811
|
try {
|
|
25830
|
-
const { resolveConflictGate, buildRealConflictGateDeps } = await import("./conflict-gate-
|
|
24812
|
+
const { resolveConflictGate, buildRealConflictGateDeps } = await import("./conflict-gate-CuXUv-bP.js");
|
|
25831
24813
|
const statuses = loadReviewStatuses();
|
|
25832
24814
|
const now = Date.now();
|
|
25833
24815
|
const deps = buildRealConflictGateDeps();
|
|
@@ -25970,7 +24952,7 @@ async function checkFailedMergeRetry() {
|
|
|
25970
24952
|
if (ciEntry.count === 5) {
|
|
25971
24953
|
console.log(`[deacon] CI check failure for ${issueId} — retries exhausted, notifying work agent`);
|
|
25972
24954
|
const ciNotes = status.mergeNotes || "CI checks are failing on the PR";
|
|
25973
|
-
const { writeFeedbackFile } = await import("./feedback-writer-
|
|
24955
|
+
const { writeFeedbackFile } = await import("./feedback-writer-BsJiw5aT.js");
|
|
25974
24956
|
const ciFileResult = await Effect.runPromise(writeFeedbackFile({
|
|
25975
24957
|
issueId,
|
|
25976
24958
|
specialist: "merge-agent",
|
|
@@ -26002,7 +24984,7 @@ async function checkFailedMergeRetry() {
|
|
|
26002
24984
|
ciRetryMap.set(issueId, ciEntry);
|
|
26003
24985
|
console.log(`[deacon] CI check failure for ${issueId} — notifying agent to re-submit (attempt ${ciEntry.count}/5)`);
|
|
26004
24986
|
const ciNotes = status.mergeNotes || "CI checks are failing on the PR";
|
|
26005
|
-
const { writeFeedbackFile } = await import("./feedback-writer-
|
|
24987
|
+
const { writeFeedbackFile } = await import("./feedback-writer-BsJiw5aT.js");
|
|
26006
24988
|
const ciFileResult2 = await Effect.runPromise(writeFeedbackFile({
|
|
26007
24989
|
issueId,
|
|
26008
24990
|
specialist: "merge-agent",
|
|
@@ -26030,7 +25012,7 @@ async function checkFailedMergeRetry() {
|
|
|
26030
25012
|
const lastNudge = timeoutNudgeCooldowns.get(issueIdForFb);
|
|
26031
25013
|
if (!lastNudge || now - lastNudge >= TIMEOUT_NUDGE_COOLDOWN_MS) {
|
|
26032
25014
|
const timeoutNotes = status.mergeNotes;
|
|
26033
|
-
const { writeFeedbackFile } = await import("./feedback-writer-
|
|
25015
|
+
const { writeFeedbackFile } = await import("./feedback-writer-BsJiw5aT.js");
|
|
26034
25016
|
await Effect.runPromise(writeFeedbackFile({
|
|
26035
25017
|
issueId: issueIdForFb,
|
|
26036
25018
|
specialist: "merge-agent",
|
|
@@ -26135,7 +25117,7 @@ async function autoCloseOut(now = /* @__PURE__ */ new Date()) {
|
|
|
26135
25117
|
} } : {}
|
|
26136
25118
|
};
|
|
26137
25119
|
try {
|
|
26138
|
-
const { closeOut } = await import("./workflows-
|
|
25120
|
+
const { closeOut } = await import("./workflows-BLwxUMP7.js");
|
|
26139
25121
|
const result = await Effect.runPromise(closeOut(ctx));
|
|
26140
25122
|
if (!result.success) {
|
|
26141
25123
|
const failed = result.steps.find((step) => !step.success && !step.skipped);
|
|
@@ -26285,6 +25267,7 @@ function skippedBootReconciliationOutcomes(agents, reason) {
|
|
|
26285
25267
|
}
|
|
26286
25268
|
//#endregion
|
|
26287
25269
|
//#region ../../lib/cloister/boot-reconciliation-predicates.ts
|
|
25270
|
+
init_control_settings();
|
|
26288
25271
|
init_no_resume_mode();
|
|
26289
25272
|
init_agent_state();
|
|
26290
25273
|
init_review_status();
|
|
@@ -26438,6 +25421,7 @@ init_review_status();
|
|
|
26438
25421
|
init_control_settings();
|
|
26439
25422
|
init_agents$1();
|
|
26440
25423
|
init_tmux();
|
|
25424
|
+
init_beads_query();
|
|
26441
25425
|
const orphanFailureRecordedForAutoResume = /* @__PURE__ */ new Set();
|
|
26442
25426
|
const appliedBootReconciliationDecisions = /* @__PURE__ */ new Set();
|
|
26443
25427
|
const emptyBootReconciliationApplyResult = () => ({
|
|
@@ -26697,7 +25681,7 @@ async function nudgeStalledResumeWorkAgents() {
|
|
|
26697
25681
|
const message = buildStalledResumePrompt(state);
|
|
26698
25682
|
if (!message) continue;
|
|
26699
25683
|
try {
|
|
26700
|
-
const { messageAgent } = await import("./agents-
|
|
25684
|
+
const { messageAgent } = await import("./agents-CEcaxSkR.js");
|
|
26701
25685
|
await messageAgent(agentId, message);
|
|
26702
25686
|
recordCooldown(agentId, ".last-stalled-resume-nudge");
|
|
26703
25687
|
const action = `Re-sent stalled resume prompt to ${agentId} (${state.issueId})`;
|
|
@@ -26812,10 +25796,10 @@ async function nudgeIdleWorkAgentsWithOpenBeads() {
|
|
|
26812
25796
|
``,
|
|
26813
25797
|
`If you don't already have your full brief for ${state.issueId} in context (work-agent role instructions, the vBRIEF plan, recorded decisions & hazards), re-read it now — it is on disk at ${briefPath}, plus .pan/continue.json and .pan/spec.vbrief.json in your workspace. Startup kickoff delivery can silently fail on large briefs, so do not assume you received it.`,
|
|
26814
25798
|
``,
|
|
26815
|
-
"Continue the per-bead workflow without asking — claim it (`
|
|
25799
|
+
"Continue the per-bead workflow without asking — claim it (`pan beads claim <bead-id>`), implement, commit, close through `pan beads close`. Inspection is conditional on metadata.requiresInspection (default false; check the plan item before deciding to call `pan inspect`). Do NOT end your turn with a multi-paragraph summary; just advance to the next bead."
|
|
26816
25800
|
].join("\n");
|
|
26817
25801
|
try {
|
|
26818
|
-
const { messageAgent } = await import("./agents-
|
|
25802
|
+
const { messageAgent } = await import("./agents-CEcaxSkR.js");
|
|
26819
25803
|
await messageAgent(agentId, message);
|
|
26820
25804
|
writeFileSync(join$1(getAgentDir(agentId), ".last-bead-nudge"), String(Date.now()), "utf-8");
|
|
26821
25805
|
const action = `Nudged idle ${agentId} (${state.issueId}) — ${openBeads.length} open bead(s)`;
|
|
@@ -27137,6 +26121,7 @@ function createInFlightGuard() {
|
|
|
27137
26121
|
}
|
|
27138
26122
|
//#endregion
|
|
27139
26123
|
//#region ../../lib/pipeline-state-paths.ts
|
|
26124
|
+
init_state_plane();
|
|
27140
26125
|
const execFileAsync$3 = promisify$1(execFile$1);
|
|
27141
26126
|
const STATE_PLANE_DIFF_EXCLUDES = STATE_PLANE_PATHS.map((path) => `:(exclude)${path.replace(/\/$/, "")}`);
|
|
27142
26127
|
function isPipelineStatePath(relativePath) {
|
|
@@ -27245,6 +26230,25 @@ async function gitStdout(workspacePath, args) {
|
|
|
27245
26230
|
return String(result.stdout ?? "");
|
|
27246
26231
|
}
|
|
27247
26232
|
//#endregion
|
|
26233
|
+
//#region ../../lib/cloister/state-plane-patrol.ts
|
|
26234
|
+
init_record();
|
|
26235
|
+
init_state_home();
|
|
26236
|
+
init_auto_commit();
|
|
26237
|
+
async function reconcileProjectStatePlanes(projects) {
|
|
26238
|
+
const actions = [];
|
|
26239
|
+
for (const { config } of projects) {
|
|
26240
|
+
if (!config.path) continue;
|
|
26241
|
+
queueBeadsAutoCommit(config.path);
|
|
26242
|
+
const write = await Effect.runPromise(reconcileStatePlaneDrift(config.path));
|
|
26243
|
+
if (!write.committed) continue;
|
|
26244
|
+
actions.push({
|
|
26245
|
+
message: `Reconciled pending spec/record state for ${config.name ?? config.path}`,
|
|
26246
|
+
level: write.pushed === false ? "warn" : "action"
|
|
26247
|
+
});
|
|
26248
|
+
}
|
|
26249
|
+
return actions;
|
|
26250
|
+
}
|
|
26251
|
+
//#endregion
|
|
27248
26252
|
//#region ../../lib/cloister/state-recreation-patrol.ts
|
|
27249
26253
|
async function recreatedStateWarnings(projects) {
|
|
27250
26254
|
const warnings = [];
|
|
@@ -27257,6 +26261,7 @@ async function recreatedStateWarnings(projects) {
|
|
|
27257
26261
|
}
|
|
27258
26262
|
//#endregion
|
|
27259
26263
|
//#region ../../lib/cloister/deacon-main-divergence.ts
|
|
26264
|
+
init_record_lock();
|
|
27260
26265
|
init_projects();
|
|
27261
26266
|
init_state_plane();
|
|
27262
26267
|
async function recordMainDivergenceHealth(state, projects = listProjectsSync(), measure = getMainDivergence) {
|
|
@@ -27289,427 +26294,6 @@ async function recordMainDivergenceHealth(state, projects = listProjectsSync(),
|
|
|
27289
26294
|
return warnings;
|
|
27290
26295
|
}
|
|
27291
26296
|
//#endregion
|
|
27292
|
-
//#region ../../lib/cloister/agent-death.ts
|
|
27293
|
-
/**
|
|
27294
|
-
* Agent death diagnostics (PAN-2108).
|
|
27295
|
-
*
|
|
27296
|
-
* When an ohmypi/pi agent process dies, the launcher records its exit code +
|
|
27297
|
-
* timestamp to `<agentDir>/exit-status` (see buildOhmypiCommand in
|
|
27298
|
-
* launcher-generator.ts), and omp's stdout/stderr is captured to
|
|
27299
|
-
* `<agentDir>/output.log`. This module turns those into a one-line death reason
|
|
27300
|
-
* the deacon can log, replacing the opaque "session is dead" with an actual
|
|
27301
|
-
* cause — the gap that made the flywheel orchestrator's silent death
|
|
27302
|
-
* undiagnosable in RUN-30.
|
|
27303
|
-
*/
|
|
27304
|
-
init_paths();
|
|
27305
|
-
init_tmux();
|
|
27306
|
-
function agentDir(agentId) {
|
|
27307
|
-
return join$1(getOverdeckHome(), "agents", agentId);
|
|
27308
|
-
}
|
|
27309
|
-
/** Read the launcher-recorded exit code + UTC timestamp, or null if absent. */
|
|
27310
|
-
function readAgentExitStatus(agentId) {
|
|
27311
|
-
try {
|
|
27312
|
-
const p = join$1(agentDir(agentId), "exit-status");
|
|
27313
|
-
if (!existsSync(p)) return null;
|
|
27314
|
-
const raw = readFileSync(p, "utf-8").trim();
|
|
27315
|
-
if (!raw) return null;
|
|
27316
|
-
const [code, at = ""] = raw.split(/\s+/);
|
|
27317
|
-
return {
|
|
27318
|
-
code: code ?? "?",
|
|
27319
|
-
at
|
|
27320
|
-
};
|
|
27321
|
-
} catch {
|
|
27322
|
-
return null;
|
|
27323
|
-
}
|
|
27324
|
-
}
|
|
27325
|
-
/**
|
|
27326
|
-
* Best-effort one-line description of why an agent process died: the
|
|
27327
|
-
* launcher-recorded exit status (preferred), the tmux pane exit status (fallback
|
|
27328
|
-
* when the dead pane corpse still exists), and the tail of output.log.
|
|
27329
|
-
*/
|
|
27330
|
-
function describeAgentDeath(agentId) {
|
|
27331
|
-
const parts = [];
|
|
27332
|
-
const exit = readAgentExitStatus(agentId);
|
|
27333
|
-
if (exit) parts.push(`exit=${exit.code}${exit.at ? ` at ${exit.at}` : ""}`);
|
|
27334
|
-
else if (sessionExistsSync(agentId)) {
|
|
27335
|
-
const paneExit = listPaneValuesSync(agentId, "#{pane_exit_status}").find((v) => v !== "");
|
|
27336
|
-
if (paneExit) parts.push(`pane_exit=${paneExit}`);
|
|
27337
|
-
}
|
|
27338
|
-
try {
|
|
27339
|
-
const logPath = join$1(agentDir(agentId), "output.log");
|
|
27340
|
-
if (existsSync(logPath)) {
|
|
27341
|
-
const tail = readFileSync(logPath, "utf-8").slice(-1500).trim().split("\n").slice(-6).join(" | ").trim();
|
|
27342
|
-
if (tail) parts.push(`output.log tail: ${tail}`);
|
|
27343
|
-
}
|
|
27344
|
-
} catch {}
|
|
27345
|
-
return parts.length ? parts.join("; ") : "no exit trace (exit-status + output.log empty)";
|
|
27346
|
-
}
|
|
27347
|
-
//#endregion
|
|
27348
|
-
//#region ../../lib/cloister/stuck-remediation-state.ts
|
|
27349
|
-
init_paths();
|
|
27350
|
-
function agentStateDir(agentId) {
|
|
27351
|
-
return join$1(getOverdeckHome(), "agents", agentId);
|
|
27352
|
-
}
|
|
27353
|
-
function statePath(agentId) {
|
|
27354
|
-
return join$1(agentStateDir(agentId), "stuck-remediation.json");
|
|
27355
|
-
}
|
|
27356
|
-
function readStuckRemediationState(agentId) {
|
|
27357
|
-
const filePath = statePath(agentId);
|
|
27358
|
-
if (!existsSync(filePath)) return null;
|
|
27359
|
-
try {
|
|
27360
|
-
return JSON.parse(readFileSync(filePath, "utf-8"));
|
|
27361
|
-
} catch (error) {
|
|
27362
|
-
console.warn(`Failed to read stuck-remediation state for ${agentId}:`, error);
|
|
27363
|
-
return null;
|
|
27364
|
-
}
|
|
27365
|
-
}
|
|
27366
|
-
function writeStuckRemediationState(agentId, state) {
|
|
27367
|
-
mkdirSync(agentStateDir(agentId), { recursive: true });
|
|
27368
|
-
writeFileSync(statePath(agentId), `${JSON.stringify(state, null, 2)}\n`, "utf-8");
|
|
27369
|
-
}
|
|
27370
|
-
function clearStuckRemediationState(agentId) {
|
|
27371
|
-
const filePath = statePath(agentId);
|
|
27372
|
-
if (!existsSync(filePath)) return;
|
|
27373
|
-
unlinkSync(filePath);
|
|
27374
|
-
}
|
|
27375
|
-
//#endregion
|
|
27376
|
-
//#region ../../lib/cloister/stuck-remediation.ts
|
|
27377
|
-
init_agents$1();
|
|
27378
|
-
init_persistent_logger();
|
|
27379
|
-
init_review_status();
|
|
27380
|
-
init_tmux();
|
|
27381
|
-
init_config();
|
|
27382
|
-
init_control_settings();
|
|
27383
|
-
init_beads_query();
|
|
27384
|
-
function issueIdForAgent(agent) {
|
|
27385
|
-
return agent.issueId || agent.id.replace(/^agent-/, "").toUpperCase();
|
|
27386
|
-
}
|
|
27387
|
-
function shouldSkipReviewStatus(status) {
|
|
27388
|
-
if (!status) return false;
|
|
27389
|
-
if (status.stuck || status.deaconIgnored || status.mergeStatus === "merged" || status.readyForMerge) return true;
|
|
27390
|
-
if (status.reviewStatus === "blocked" || status.reviewStatus === "failed") return true;
|
|
27391
|
-
if (status.verificationStatus === "failed" || status.testStatus === "failed") return true;
|
|
27392
|
-
if (status.reviewStatus === "reviewing" || status.reviewStatus === "passed") return true;
|
|
27393
|
-
return status.reviewStatus === "pending" && !!status.reviewRequestedAt;
|
|
27394
|
-
}
|
|
27395
|
-
function hasPendingRework(status) {
|
|
27396
|
-
if (!status) return false;
|
|
27397
|
-
if (status.stuck || status.deaconIgnored || status.mergeStatus === "merged" || status.readyForMerge) return false;
|
|
27398
|
-
return status.reviewStatus === "blocked" || status.reviewStatus === "failed" || status.verificationStatus === "failed" || status.testStatus === "failed";
|
|
27399
|
-
}
|
|
27400
|
-
const STUCK_KILL_REQUEUE_CEILING = 25;
|
|
27401
|
-
async function evaluateWedgedReworkAgent(agent, config, now, actions) {
|
|
27402
|
-
const agentId = agent.id;
|
|
27403
|
-
if (agent.role !== "work" || !agent.workspace) return false;
|
|
27404
|
-
const issueId = issueIdForAgent(agent);
|
|
27405
|
-
const status = getReviewStatusSync(issueId);
|
|
27406
|
-
if (!hasPendingRework(status)) return false;
|
|
27407
|
-
const lastActivityMs = getAgentEffectiveLastActivityMs(agentId);
|
|
27408
|
-
if (lastActivityMs === null || !Number.isFinite(lastActivityMs)) return false;
|
|
27409
|
-
const stuckState = readStuckRemediationState(agentId);
|
|
27410
|
-
if (stuckState) {
|
|
27411
|
-
const firstStuckMs = new Date(stuckState.firstStuckAt).getTime();
|
|
27412
|
-
if (Number.isFinite(firstStuckMs) && lastActivityMs > firstStuckMs) {
|
|
27413
|
-
clearStuckRemediationState(agentId);
|
|
27414
|
-
return false;
|
|
27415
|
-
}
|
|
27416
|
-
}
|
|
27417
|
-
const idleMinutes = Math.floor((now - lastActivityMs) / 6e4);
|
|
27418
|
-
const lastStage = stuckState?.lastStage ?? 0;
|
|
27419
|
-
if (idleMinutes < config.stage3_minutes || lastStage >= 3) return false;
|
|
27420
|
-
const firstStuck = firstStuckAt(new Date(lastActivityMs).toISOString(), stuckState);
|
|
27421
|
-
if ((status?.autoRequeueCount ?? 0) >= STUCK_KILL_REQUEUE_CEILING) {
|
|
27422
|
-
markAgentTroubled(agentId);
|
|
27423
|
-
writeStuckRemediationState(agentId, stageState(3, now, firstStuck));
|
|
27424
|
-
logAction(actions, transitionAction(3, issueId, idleMinutes, "rework-wedge-troubled"));
|
|
27425
|
-
surfaceStuckNeedsYou(agent, issueId, firstStuck, actions);
|
|
27426
|
-
return true;
|
|
27427
|
-
}
|
|
27428
|
-
killSessionSync(agentId);
|
|
27429
|
-
writeStuckRemediationState(agentId, stageState(3, now, firstStuck));
|
|
27430
|
-
logAction(actions, transitionAction(3, issueId, idleMinutes, "killed-for-respawn"));
|
|
27431
|
-
return true;
|
|
27432
|
-
}
|
|
27433
|
-
function hasReadyBeads(readyByQueryRoot, agent, issueLabel) {
|
|
27434
|
-
return (readyByQueryRoot.get(resolveBeadsQueryRoot(agent.workspace))?.[issueLabel] ?? []).length > 0;
|
|
27435
|
-
}
|
|
27436
|
-
function shouldCheckReadyBeadsForAgent(agent, now) {
|
|
27437
|
-
const agentId = agent.id;
|
|
27438
|
-
if (!agentId) return false;
|
|
27439
|
-
if (agent.status !== "running") return false;
|
|
27440
|
-
if (agent.role !== "work") return false;
|
|
27441
|
-
if (!agent.workspace) return false;
|
|
27442
|
-
const completedAt = agent.completedAt;
|
|
27443
|
-
if (agent.paused || agent.troubled || completedAt) return false;
|
|
27444
|
-
if (!sessionExistsSync(agentId)) return false;
|
|
27445
|
-
if (shouldSkipReviewStatus(getReviewStatusSync(issueIdForAgent(agent)))) return false;
|
|
27446
|
-
return isAgentIdleForNudge(agentId, 300 * 1e3, now);
|
|
27447
|
-
}
|
|
27448
|
-
function firstStuckAt(runtimeLastActivity, stuckState) {
|
|
27449
|
-
return stuckState?.firstStuckAt ?? runtimeLastActivity;
|
|
27450
|
-
}
|
|
27451
|
-
function stageState(stage, now, firstStuck, prev) {
|
|
27452
|
-
return {
|
|
27453
|
-
lastStage: stage,
|
|
27454
|
-
lastStageAt: new Date(now).toISOString(),
|
|
27455
|
-
firstStuckAt: firstStuck,
|
|
27456
|
-
...prev?.respawnCount !== void 0 ? { respawnCount: prev.respawnCount } : {},
|
|
27457
|
-
...prev?.lastRespawnAt !== void 0 ? { lastRespawnAt: prev.lastRespawnAt } : {}
|
|
27458
|
-
};
|
|
27459
|
-
}
|
|
27460
|
-
function transitionAction(stage, issueId, idleMinutes, action) {
|
|
27461
|
-
return `[deacon] stuck-remediation stage=${stage} issue=${issueId} idleMin=${idleMinutes} action=${action}`;
|
|
27462
|
-
}
|
|
27463
|
-
function logAction(actions, action) {
|
|
27464
|
-
actions.push(action);
|
|
27465
|
-
console.log(action);
|
|
27466
|
-
logDeaconEventSync(action);
|
|
27467
|
-
}
|
|
27468
|
-
function surfaceStuckNeedsYou(agent, issueId, generation, actions) {
|
|
27469
|
-
if (!agent.workspace) return;
|
|
27470
|
-
if (recordRecoveryFailure(agent.workspace, issueId, "stuck-remediation", generation, 1).emitNeedsYou) logAction(actions, `[deacon] needs-you ${issueId}: stuck remediation exhausted`);
|
|
27471
|
-
}
|
|
27472
|
-
async function evaluateAgent(agent, config, now, actions, readyByQueryRoot) {
|
|
27473
|
-
const agentId = agent.id;
|
|
27474
|
-
if (!agentId) return;
|
|
27475
|
-
if (agent.status !== "running") return;
|
|
27476
|
-
const completedAt = agent.completedAt;
|
|
27477
|
-
if (agent.paused || agent.troubled || completedAt) return;
|
|
27478
|
-
if (agent.role === "flywheel") {
|
|
27479
|
-
await evaluateFlywheelOrchestrator(agent, config, now, actions);
|
|
27480
|
-
return;
|
|
27481
|
-
}
|
|
27482
|
-
if (!sessionExistsSync(agentId)) return;
|
|
27483
|
-
if (agent.role === "plan" && agent.auto === true) {
|
|
27484
|
-
await evaluateAutoPlanningAgent(agent, config, now, actions);
|
|
27485
|
-
return;
|
|
27486
|
-
}
|
|
27487
|
-
if (await evaluateWedgedReworkAgent(agent, config, now, actions)) return;
|
|
27488
|
-
if (!shouldCheckReadyBeadsForAgent(agent, now)) return;
|
|
27489
|
-
if (!agent.workspace) return;
|
|
27490
|
-
const issueId = issueIdForAgent(agent);
|
|
27491
|
-
if (hasReadyBeads(readyByQueryRoot, agent, issueId.toLowerCase())) return;
|
|
27492
|
-
const lastActivityMs = getAgentEffectiveLastActivityMs(agentId);
|
|
27493
|
-
if (lastActivityMs === null) return;
|
|
27494
|
-
if (!Number.isFinite(lastActivityMs)) return;
|
|
27495
|
-
const lastActivity = new Date(lastActivityMs).toISOString();
|
|
27496
|
-
const stuckState = readStuckRemediationState(agentId);
|
|
27497
|
-
if (stuckState) {
|
|
27498
|
-
const firstStuckMs = new Date(stuckState.firstStuckAt).getTime();
|
|
27499
|
-
if (Number.isFinite(firstStuckMs) && lastActivityMs > firstStuckMs) {
|
|
27500
|
-
clearStuckRemediationState(agentId);
|
|
27501
|
-
return;
|
|
27502
|
-
}
|
|
27503
|
-
}
|
|
27504
|
-
const idleMinutes = Math.floor((now - lastActivityMs) / 6e4);
|
|
27505
|
-
const lastStage = stuckState?.lastStage ?? 0;
|
|
27506
|
-
const firstStuck = firstStuckAt(lastActivity, stuckState);
|
|
27507
|
-
if (idleMinutes >= config.stage3_minutes && lastStage < 3) {
|
|
27508
|
-
markAgentTroubled(agentId);
|
|
27509
|
-
writeStuckRemediationState(agentId, stageState(3, now, firstStuck));
|
|
27510
|
-
logAction(actions, transitionAction(3, issueId, idleMinutes, "marked-troubled"));
|
|
27511
|
-
surfaceStuckNeedsYou(agent, issueId, firstStuck, actions);
|
|
27512
|
-
return;
|
|
27513
|
-
}
|
|
27514
|
-
if (idleMinutes >= config.stage2_minutes && lastStage < 2) {
|
|
27515
|
-
if ((await resumeAgent(agentId, `Resuming after auto-detected stall (${idleMinutes} min idle). Review your last work and decide whether to continue or signal done with \`pan done ${issueId}\`.`)).success) {
|
|
27516
|
-
writeStuckRemediationState(agentId, stageState(2, now, firstStuck));
|
|
27517
|
-
logAction(actions, transitionAction(2, issueId, idleMinutes, "resumed"));
|
|
27518
|
-
} else {
|
|
27519
|
-
const action = `${transitionAction(2, issueId, idleMinutes, "resume-failed")} — death: ${describeAgentDeath(agentId)}`;
|
|
27520
|
-
console.warn(action);
|
|
27521
|
-
logDeaconEventSync(action);
|
|
27522
|
-
}
|
|
27523
|
-
return;
|
|
27524
|
-
}
|
|
27525
|
-
if (idleMinutes >= config.stage1_minutes && lastStage < 1) {
|
|
27526
|
-
await messageAgent(agentId, `You appear stuck — no tool calls for ${idleMinutes} min. If your implementation is complete, run \`pan done ${issueId}\`. Otherwise reply with a one-line summary of what you're waiting on, then continue.`);
|
|
27527
|
-
writeStuckRemediationState(agentId, stageState(1, now, firstStuck));
|
|
27528
|
-
logAction(actions, transitionAction(1, issueId, idleMinutes, "poked"));
|
|
27529
|
-
}
|
|
27530
|
-
}
|
|
27531
|
-
async function evaluateAutoPlanningAgent(agent, config, now, actions) {
|
|
27532
|
-
const agentId = agent.id;
|
|
27533
|
-
if (!isAgentIdleForNudge(agentId, 300 * 1e3, now)) return;
|
|
27534
|
-
if (await Effect.runPromise(countPendingAskUserQuestionsForAgent(agentId)) === 0) return;
|
|
27535
|
-
const lastActivityMs = getAgentEffectiveLastActivityMs(agentId);
|
|
27536
|
-
if (lastActivityMs === null || !Number.isFinite(lastActivityMs)) return;
|
|
27537
|
-
const lastActivity = new Date(lastActivityMs).toISOString();
|
|
27538
|
-
const stuckState = readStuckRemediationState(agentId);
|
|
27539
|
-
if (stuckState) {
|
|
27540
|
-
const firstStuckMs = new Date(stuckState.firstStuckAt).getTime();
|
|
27541
|
-
if (Number.isFinite(firstStuckMs) && lastActivityMs > firstStuckMs) {
|
|
27542
|
-
clearStuckRemediationState(agentId);
|
|
27543
|
-
return;
|
|
27544
|
-
}
|
|
27545
|
-
}
|
|
27546
|
-
const idleMinutes = Math.floor((now - lastActivityMs) / 6e4);
|
|
27547
|
-
const lastStage = stuckState?.lastStage ?? 0;
|
|
27548
|
-
if (idleMinutes < config.stage1_minutes || lastStage >= 1) return;
|
|
27549
|
-
const issueId = issueIdForAgent(agent);
|
|
27550
|
-
await messageAgent(agentId, `This planning session was launched with \`pan plan ${issueId} --auto\`, so do not wait for operator input. Proceed with the most defensible default from the issue/PRD/comments, record the choice in \`plan.autoDecisions[]\` with rationale, and continue to \`pan plan finalize\`. Only halt for a genuine contradiction between authoritative inputs.`);
|
|
27551
|
-
writeStuckRemediationState(agentId, stageState(1, now, firstStuckAt(lastActivity, stuckState)));
|
|
27552
|
-
logAction(actions, transitionAction(1, issueId, idleMinutes, "auto-planning-default"));
|
|
27553
|
-
}
|
|
27554
|
-
const FLYWHEEL_RESPAWN_WINDOW_MS = 1800 * 1e3;
|
|
27555
|
-
const FLYWHEEL_MAX_RESPAWNS = 3;
|
|
27556
|
-
const FLYWHEEL_ORCHESTRATOR_AGENT_ID = "flywheel-orchestrator";
|
|
27557
|
-
/**
|
|
27558
|
-
* Pure decision for recovering a dead or wedged flywheel orchestrator (no I/O —
|
|
27559
|
-
* side effects live in remediateFlywheelOrchestrator). The respawn cap
|
|
27560
|
-
* (FLYWHEEL_MAX_RESPAWNS within FLYWHEEL_RESPAWN_WINDOW_MS) stops an infinite
|
|
27561
|
-
* relaunch loop: past the cap, escalate to paused+troubled. `hasActiveRun` false
|
|
27562
|
-
* ⇒ the operator stopped the flywheel deliberately ⇒ do not resurrect.
|
|
27563
|
-
*/
|
|
27564
|
-
function decideFlywheelRemediation(opts) {
|
|
27565
|
-
if (!opts.hasActiveRun) return { kind: "noop" };
|
|
27566
|
-
const lastRespawnMs = opts.prev?.lastRespawnAt ? new Date(opts.prev.lastRespawnAt).getTime() : 0;
|
|
27567
|
-
const respawnCount = Number.isFinite(lastRespawnMs) && opts.now - lastRespawnMs < FLYWHEEL_RESPAWN_WINDOW_MS ? opts.prev?.respawnCount ?? 0 : 0;
|
|
27568
|
-
if (respawnCount >= FLYWHEEL_MAX_RESPAWNS) return {
|
|
27569
|
-
kind: "escalate",
|
|
27570
|
-
respawnCount
|
|
27571
|
-
};
|
|
27572
|
-
return {
|
|
27573
|
-
kind: "relaunch",
|
|
27574
|
-
respawnCount: respawnCount + 1
|
|
27575
|
-
};
|
|
27576
|
-
}
|
|
27577
|
-
/** True when the orchestrator's process is actually gone (session missing or dead pane). */
|
|
27578
|
-
function isFlywheelOrchestratorDead(agentId) {
|
|
27579
|
-
if (!sessionExistsSync(agentId)) return true;
|
|
27580
|
-
return listPaneValuesSync(agentId, "#{pane_dead}").some((v) => v === "1");
|
|
27581
|
-
}
|
|
27582
|
-
/**
|
|
27583
|
-
* Recover a dead or wedged flywheel orchestrator: relaunch (capped) or, past the
|
|
27584
|
-
* cap, pause+trouble. `reason` describes why recovery fired (death vs wedge) for
|
|
27585
|
-
* the deacon log. NO_RESUME is intentionally NOT consulted (see header comment) —
|
|
27586
|
-
* the operator gate is the active run (`pan flywheel stop`) / patrol freeze.
|
|
27587
|
-
*/
|
|
27588
|
-
async function remediateFlywheelOrchestrator(agentId, now, actions, reason) {
|
|
27589
|
-
const decision = decideFlywheelRemediation({
|
|
27590
|
-
hasActiveRun: Boolean(getFlywheelActiveRunId()),
|
|
27591
|
-
prev: readStuckRemediationState(agentId),
|
|
27592
|
-
now
|
|
27593
|
-
});
|
|
27594
|
-
if (decision.kind === "noop") return;
|
|
27595
|
-
const { resumeFlywheel, pauseFlywheel } = await import("./flywheel-DB48X7Nn.js");
|
|
27596
|
-
const prev = readStuckRemediationState(agentId);
|
|
27597
|
-
const nowIso = new Date(now).toISOString();
|
|
27598
|
-
if (decision.kind === "escalate") {
|
|
27599
|
-
await pauseFlywheel();
|
|
27600
|
-
markAgentTroubled(agentId);
|
|
27601
|
-
writeStuckRemediationState(agentId, {
|
|
27602
|
-
lastStage: 3,
|
|
27603
|
-
lastStageAt: nowIso,
|
|
27604
|
-
firstStuckAt: prev?.firstStuckAt ?? nowIso,
|
|
27605
|
-
respawnCount: decision.respawnCount,
|
|
27606
|
-
lastRespawnAt: prev?.lastRespawnAt
|
|
27607
|
-
});
|
|
27608
|
-
logAction(actions, `[deacon] FLYWHEEL orchestrator ${reason} and exceeded ${FLYWHEEL_MAX_RESPAWNS} relaunches in ${FLYWHEEL_RESPAWN_WINDOW_MS / 6e4}min — paused + troubled; operator needed`);
|
|
27609
|
-
return;
|
|
27610
|
-
}
|
|
27611
|
-
try {
|
|
27612
|
-
killSessionSync(agentId);
|
|
27613
|
-
} catch {}
|
|
27614
|
-
try {
|
|
27615
|
-
await resumeFlywheel();
|
|
27616
|
-
writeStuckRemediationState(agentId, {
|
|
27617
|
-
lastStage: 0,
|
|
27618
|
-
lastStageAt: nowIso,
|
|
27619
|
-
firstStuckAt: nowIso,
|
|
27620
|
-
respawnCount: decision.respawnCount,
|
|
27621
|
-
lastRespawnAt: nowIso
|
|
27622
|
-
});
|
|
27623
|
-
logAction(actions, `[deacon] FLYWHEEL orchestrator ${reason} — fresh-launched (relaunch ${decision.respawnCount}/${FLYWHEEL_MAX_RESPAWNS})`);
|
|
27624
|
-
} catch (error) {
|
|
27625
|
-
logAction(actions, `[deacon] FLYWHEEL orchestrator ${reason} — relaunch FAILED: ${error instanceof Error ? error.message : String(error)}`);
|
|
27626
|
-
}
|
|
27627
|
-
}
|
|
27628
|
-
async function evaluateFlywheelOrchestrator(agent, config, now, actions) {
|
|
27629
|
-
const agentId = agent.id;
|
|
27630
|
-
if (isFlywheelOrchestratorDead(agentId)) {
|
|
27631
|
-
await remediateFlywheelOrchestrator(agentId, now, actions, `DIED (${describeAgentDeath(agentId)})`);
|
|
27632
|
-
return;
|
|
27633
|
-
}
|
|
27634
|
-
if (!isAgentIdleForNudge(agentId, 300 * 1e3, now)) return;
|
|
27635
|
-
const runtime = getAgentRuntimeStateSync(agentId);
|
|
27636
|
-
if (!runtime?.lastActivity) return;
|
|
27637
|
-
const lastActivityMs = new Date(runtime.lastActivity).getTime();
|
|
27638
|
-
if (!Number.isFinite(lastActivityMs)) return;
|
|
27639
|
-
const stuckState = readStuckRemediationState(agentId);
|
|
27640
|
-
if (stuckState) {
|
|
27641
|
-
const firstStuckMs = new Date(stuckState.firstStuckAt).getTime();
|
|
27642
|
-
if (Number.isFinite(firstStuckMs) && lastActivityMs > firstStuckMs) {
|
|
27643
|
-
clearStuckRemediationState(agentId);
|
|
27644
|
-
return;
|
|
27645
|
-
}
|
|
27646
|
-
}
|
|
27647
|
-
const idleMinutes = Math.floor((now - lastActivityMs) / 6e4);
|
|
27648
|
-
const lastStage = stuckState?.lastStage ?? 0;
|
|
27649
|
-
const firstStuck = firstStuckAt(runtime.lastActivity, stuckState);
|
|
27650
|
-
if (idleMinutes >= config.flywheel_stage3_minutes && lastStage < 3) {
|
|
27651
|
-
await remediateFlywheelOrchestrator(agentId, now, actions, `wedged (idle ${idleMinutes}min)`);
|
|
27652
|
-
return;
|
|
27653
|
-
}
|
|
27654
|
-
if (idleMinutes >= config.flywheel_stage2_minutes && lastStage < 2) {
|
|
27655
|
-
await messageAgent(agentId, `Stage 2: idle ${idleMinutes} min — run a FULL flywheel tick NOW: inventory -> diagnose -> suggest -> launch ready work -> \`pan flywheel emit-status\`. Then call ScheduleWakeup(delaySeconds:1000) to arm the next tick. Do NOT ask the operator a question, do NOT wait, and do NOT just emit a stale status or pause.`);
|
|
27656
|
-
writeStuckRemediationState(agentId, stageState(2, now, firstStuck, stuckState));
|
|
27657
|
-
logAction(actions, transitionAction(2, "FLYWHEEL", idleMinutes, "escalated-nudge"));
|
|
27658
|
-
return;
|
|
27659
|
-
}
|
|
27660
|
-
if (idleMinutes >= config.flywheel_stage1_minutes && lastStage < 1) {
|
|
27661
|
-
await messageAgent(agentId, `You appear stuck — ${idleMinutes} min since your last tick. Run a FULL flywheel tick NOW: inventory -> diagnose -> suggest -> launch ready work -> \`pan flywheel emit-status\`. Then call ScheduleWakeup(delaySeconds:1000) to arm the next tick. Do NOT ask the operator a question, do NOT wait, and do NOT just emit a stale status or pause.`);
|
|
27662
|
-
writeStuckRemediationState(agentId, stageState(1, now, firstStuck, stuckState));
|
|
27663
|
-
logAction(actions, transitionAction(1, "FLYWHEEL", idleMinutes, "poked"));
|
|
27664
|
-
}
|
|
27665
|
-
}
|
|
27666
|
-
async function reconcileActiveFlywheelWithoutRunningAgent(now, actions) {
|
|
27667
|
-
if (!getFlywheelActiveRunId()) return;
|
|
27668
|
-
if (isFlywheelGloballyPaused()) return;
|
|
27669
|
-
if (sessionExistsSync(FLYWHEEL_ORCHESTRATOR_AGENT_ID)) return;
|
|
27670
|
-
await remediateFlywheelOrchestrator(FLYWHEEL_ORCHESTRATOR_AGENT_ID, now, actions, `DIED (${describeAgentDeath(FLYWHEEL_ORCHESTRATOR_AGENT_ID)})`);
|
|
27671
|
-
}
|
|
27672
|
-
async function checkStuckAgentRemediation(opts = {}) {
|
|
27673
|
-
const config = loadCloisterConfigSync().stuck_remediation ?? DEFAULT_CLOISTER_CONFIG.stuck_remediation;
|
|
27674
|
-
if (!config.enabled) return [];
|
|
27675
|
-
const actions = [];
|
|
27676
|
-
const now = opts.now ?? Date.now();
|
|
27677
|
-
const runningAgents = listRunningAgentsSync();
|
|
27678
|
-
const readyByQueryRoot = /* @__PURE__ */ new Map();
|
|
27679
|
-
const workAgentsByQueryRoot = /* @__PURE__ */ new Map();
|
|
27680
|
-
let sawFlywheelOrchestrator = false;
|
|
27681
|
-
for (const agent of runningAgents) {
|
|
27682
|
-
if (!shouldCheckReadyBeadsForAgent(agent, now)) continue;
|
|
27683
|
-
const queryRoot = resolveBeadsQueryRoot(agent.workspace);
|
|
27684
|
-
const workspaceAgents = workAgentsByQueryRoot.get(queryRoot) ?? [];
|
|
27685
|
-
workspaceAgents.push(agent);
|
|
27686
|
-
workAgentsByQueryRoot.set(queryRoot, workspaceAgents);
|
|
27687
|
-
}
|
|
27688
|
-
for (const [queryRoot, workspaceAgents] of workAgentsByQueryRoot) {
|
|
27689
|
-
const issueIds = workspaceAgents.map(issueIdForAgent);
|
|
27690
|
-
const ready = await Effect.runPromise(queryReadyBeadsByIssueLabels(queryRoot, issueIds, { acquisitionTimeoutMs: 500 }));
|
|
27691
|
-
readyByQueryRoot.set(queryRoot, ready.byIssue);
|
|
27692
|
-
}
|
|
27693
|
-
for (const agent of runningAgents) {
|
|
27694
|
-
if (agent.id === FLYWHEEL_ORCHESTRATOR_AGENT_ID || agent.role === "flywheel") sawFlywheelOrchestrator = true;
|
|
27695
|
-
try {
|
|
27696
|
-
await evaluateAgent(agent, config, now, actions, readyByQueryRoot);
|
|
27697
|
-
} catch (error) {
|
|
27698
|
-
const message = `[deacon] stuck-remediation agent=${agent.id || "(unknown)"} error=${error instanceof Error ? error.message : String(error)}`;
|
|
27699
|
-
console.error(message, error);
|
|
27700
|
-
logDeaconEventSync(message);
|
|
27701
|
-
}
|
|
27702
|
-
}
|
|
27703
|
-
if (!sawFlywheelOrchestrator) try {
|
|
27704
|
-
await reconcileActiveFlywheelWithoutRunningAgent(now, actions);
|
|
27705
|
-
} catch (error) {
|
|
27706
|
-
const message = `[deacon] stuck-remediation agent=${FLYWHEEL_ORCHESTRATOR_AGENT_ID} error=${error instanceof Error ? error.message : String(error)}`;
|
|
27707
|
-
console.error(message, error);
|
|
27708
|
-
logDeaconEventSync(message);
|
|
27709
|
-
}
|
|
27710
|
-
return actions;
|
|
27711
|
-
}
|
|
27712
|
-
//#endregion
|
|
27713
26297
|
//#region ../../lib/backlog/label-ops.ts
|
|
27714
26298
|
init_tracker_utils();
|
|
27715
26299
|
const execAsync$3 = promisify(exec);
|
|
@@ -28608,8 +27192,8 @@ async function cleanupStaleAgentState() {
|
|
|
28608
27192
|
*/
|
|
28609
27193
|
async function cleanupAbandonedFeedback() {
|
|
28610
27194
|
const actions = [];
|
|
28611
|
-
const { getReviewStatusSync } = await import("./review-status-
|
|
28612
|
-
const { clearFeedbackFiles } = await import("./feedback-writer-
|
|
27195
|
+
const { getReviewStatusSync } = await import("./review-status-CG0iDuWa.js");
|
|
27196
|
+
const { clearFeedbackFiles } = await import("./feedback-writer-BsJiw5aT.js");
|
|
28613
27197
|
for (const { issueId, workspacePath } of listFeatureWorkspaces()) {
|
|
28614
27198
|
const panFeedbackDir = join$1(workspacePath, ".pan", "feedback");
|
|
28615
27199
|
if (!existsSync(panFeedbackDir)) continue;
|
|
@@ -28680,7 +27264,7 @@ async function handleOrphanReviewerSession(sessionName, sessions, creationTimes,
|
|
|
28680
27264
|
if (!issueId) return null;
|
|
28681
27265
|
const agentSession = `agent-${issueId.toLowerCase()}`;
|
|
28682
27266
|
if (sessions.includes(agentSession)) return null;
|
|
28683
|
-
const { getReviewStatusSync } = await import("./review-status-
|
|
27267
|
+
const { getReviewStatusSync } = await import("./review-status-CG0iDuWa.js");
|
|
28684
27268
|
try {
|
|
28685
27269
|
if (getReviewStatusSync(issueId)?.reviewStatus === "reviewing") return null;
|
|
28686
27270
|
} catch {}
|
|
@@ -28800,7 +27384,7 @@ async function checkOrphanedCompletions() {
|
|
|
28800
27384
|
async function checkPendingTestDispatch() {
|
|
28801
27385
|
const actions = [];
|
|
28802
27386
|
try {
|
|
28803
|
-
const { loadReviewStatuses, setReviewStatusSync } = await import("./review-status-
|
|
27387
|
+
const { loadReviewStatuses, setReviewStatusSync } = await import("./review-status-CG0iDuWa.js");
|
|
28804
27388
|
const statuses = loadReviewStatuses();
|
|
28805
27389
|
const now = Date.now();
|
|
28806
27390
|
for (const [issueId, status] of Object.entries(statuses)) {
|
|
@@ -28833,7 +27417,7 @@ async function checkPendingTestDispatch() {
|
|
|
28833
27417
|
console.log(`[deacon] ${issueId}: skipping test re-dispatch — issue is closed`);
|
|
28834
27418
|
continue;
|
|
28835
27419
|
}
|
|
28836
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
27420
|
+
const { resolveProjectFromIssueSync } = await import("./projects-CrBE6IhN.js");
|
|
28837
27421
|
const resolved = resolveProjectFromIssueSync(issueId);
|
|
28838
27422
|
if (!resolved) continue;
|
|
28839
27423
|
const issueLower = issueId.toLowerCase();
|
|
@@ -28848,8 +27432,8 @@ async function checkPendingTestDispatch() {
|
|
|
28848
27432
|
logDeaconEventSync(`checkPendingTestDispatch: deferred test for ${issueId} — advancing ceiling reached (PAN-1665) — ${describeRunningAgents()}`);
|
|
28849
27433
|
continue;
|
|
28850
27434
|
}
|
|
28851
|
-
const { spawnRun } = await import("./agents-
|
|
28852
|
-
const { buildTestRolePrompt } = await import("./test-agent-queue-
|
|
27435
|
+
const { spawnRun } = await import("./agents-CEcaxSkR.js");
|
|
27436
|
+
const { buildTestRolePrompt } = await import("./test-agent-queue-CnuYku4B.js");
|
|
28853
27437
|
try {
|
|
28854
27438
|
const run = await spawnRun(issueId, "test", {
|
|
28855
27439
|
workspace,
|
|
@@ -28972,7 +27556,7 @@ async function checkCompletedButUnsignaledTests() {
|
|
|
28972
27556
|
const cmd = `pan admin specialists done test ${issueId} --status ${decision.status}${noteArg}`;
|
|
28973
27557
|
const nudge = `Your test verdict (${decision.status}) is already written to .pan/test/result.json. Your ONLY remaining task is to execute this Bash command immediately — do not analyze, do not summarize, do not ask questions, just run it:\n\n${cmd}\n\nRun this command NOW. Do not write any other response before executing it.`;
|
|
28974
27558
|
try {
|
|
28975
|
-
const { messageAgent } = await import("./agents-
|
|
27559
|
+
const { messageAgent } = await import("./agents-CEcaxSkR.js");
|
|
28976
27560
|
await messageAgent(testSession, nudge);
|
|
28977
27561
|
unsignaledTestNudges.set(testSession, now);
|
|
28978
27562
|
const msg = `Nudged ${testSession} to signal ${decision.status} (verdict artifact present)`;
|
|
@@ -28986,7 +27570,7 @@ async function checkCompletedButUnsignaledTests() {
|
|
|
28986
27570
|
case "nudge-write": {
|
|
28987
27571
|
const nudge = `Your test run for ${issueId} looks finished but no verdict was recorded. Decide the verdict from the gates/UAT you ran, then do BOTH of these now: (1) write the workspace file .pan/test/result.json as {"status":"passed"|"failed","notes":"<evidence>"}, and (2) run: pan admin specialists done test ${issueId} --status passed|failed. Do this immediately — do not summarize or ask questions, just write the file and run the command.`;
|
|
28988
27572
|
try {
|
|
28989
|
-
const { messageAgent } = await import("./agents-
|
|
27573
|
+
const { messageAgent } = await import("./agents-CEcaxSkR.js");
|
|
28990
27574
|
await messageAgent(testSession, nudge);
|
|
28991
27575
|
unsignaledTestNudges.set(testSession, now);
|
|
28992
27576
|
const msg = `Nudged ${testSession} to write+signal a test verdict (no artifact yet)`;
|
|
@@ -29009,8 +27593,8 @@ async function checkCompletedButUnsignaledTests() {
|
|
|
29009
27593
|
async function checkVerificationReviewContradiction() {
|
|
29010
27594
|
const actions = [];
|
|
29011
27595
|
try {
|
|
29012
|
-
const { loadReviewStatuses, setReviewStatusSync } = await import("./review-status-
|
|
29013
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
27596
|
+
const { loadReviewStatuses, setReviewStatusSync } = await import("./review-status-CG0iDuWa.js");
|
|
27597
|
+
const { resolveProjectFromIssueSync } = await import("./projects-CrBE6IhN.js");
|
|
29014
27598
|
const statuses = loadReviewStatuses();
|
|
29015
27599
|
for (const [issueId, status] of Object.entries(statuses)) if (status.verificationStatus === "passed" && status.reviewStatus === "reviewing" && status.stuckReason === "review_infrastructure_failure") {
|
|
29016
27600
|
let reviewedAtCommit;
|
|
@@ -29059,7 +27643,7 @@ async function checkPostReviewCommits() {
|
|
|
29059
27643
|
const actions = [];
|
|
29060
27644
|
try {
|
|
29061
27645
|
const statuses = loadReviewStatuses();
|
|
29062
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
27646
|
+
const { resolveProjectFromIssueSync } = await import("./projects-CrBE6IhN.js");
|
|
29063
27647
|
for (const [issueId, status] of Object.entries(statuses)) {
|
|
29064
27648
|
if (status.mergeStatus === "merged") continue;
|
|
29065
27649
|
if (!status.reviewedAtCommit) continue;
|
|
@@ -29114,7 +27698,7 @@ async function checkPostReviewCommits() {
|
|
|
29114
27698
|
actions.push(`Deferred post-review re-dispatch for ${issueId} — advancing-role concurrency ceiling reached`);
|
|
29115
27699
|
logDeaconEventSync(`checkPostReviewCommits: deferred review for ${issueId} — advancing ceiling reached (PAN-1665) — ${describeRunningAgents()}`);
|
|
29116
27700
|
} else if (freshStatus?.reviewStatus === "pending") {
|
|
29117
|
-
const { spawnReviewRoleForIssue } = await import("./review-agent-
|
|
27701
|
+
const { spawnReviewRoleForIssue } = await import("./review-agent-u5q3ip7H.js");
|
|
29118
27702
|
const branch = `feature/${issueId.toLowerCase()}`;
|
|
29119
27703
|
const dispatchResult = await Effect.runPromise(spawnReviewRoleForIssue({
|
|
29120
27704
|
issueId,
|
|
@@ -29214,7 +27798,7 @@ async function checkReadyForMergeStuck() {
|
|
|
29214
27798
|
const testStatusGreenCiReconcileCooldowns = /* @__PURE__ */ new Map();
|
|
29215
27799
|
const TEST_STATUS_GREEN_CI_RECONCILE_COOLDOWN_MS = 300 * 1e3;
|
|
29216
27800
|
async function reconcileTestStatusFromGreenCi() {
|
|
29217
|
-
const { getCiCheckRunsState, getPullRequestHeadState, isGitHubAppConfigured } = await import("./github-app-
|
|
27801
|
+
const { getCiCheckRunsState, getPullRequestHeadState, isGitHubAppConfigured } = await import("./github-app-Bwt9lK4A.js");
|
|
29218
27802
|
return reconcileTestStatusFromGreenCiWithDeps({
|
|
29219
27803
|
isGitHubAppConfigured,
|
|
29220
27804
|
loadReviewStatuses,
|
|
@@ -29235,7 +27819,7 @@ async function reconcileTestStatusFromGreenCi() {
|
|
|
29235
27819
|
*/
|
|
29236
27820
|
async function clearStaleCiFeedback(issueId) {
|
|
29237
27821
|
const { readdir, rm } = await import("fs/promises");
|
|
29238
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
27822
|
+
const { resolveProjectFromIssueSync } = await import("./projects-CrBE6IhN.js");
|
|
29239
27823
|
const projectConfig = resolveProjectFromIssueSync(issueId);
|
|
29240
27824
|
if (!projectConfig) return;
|
|
29241
27825
|
const repoDir = projectConfig.projectPath;
|
|
@@ -29535,7 +28119,7 @@ async function checkWorkspaceContainerHealth(sharedState) {
|
|
|
29535
28119
|
}
|
|
29536
28120
|
}
|
|
29537
28121
|
try {
|
|
29538
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
28122
|
+
const { resolveProjectFromIssueSync } = await import("./projects-CrBE6IhN.js");
|
|
29539
28123
|
const resolved = resolveProjectFromIssueSync(issueLower.toUpperCase());
|
|
29540
28124
|
if (resolved) await killOrphanedWorkspaceProcesses(`${resolved.projectPath}/workspaces/feature-${issueLower}`);
|
|
29541
28125
|
} catch {}
|
|
@@ -29584,8 +28168,8 @@ async function checkWorkspaceContainerHealth(sharedState) {
|
|
|
29584
28168
|
async function checkMergedWorkSessions() {
|
|
29585
28169
|
const actions = [];
|
|
29586
28170
|
try {
|
|
29587
|
-
const { selectMergedWorkSessions } = await import("./reap-terminal-sessions-
|
|
29588
|
-
const { setAgentPaused } = await import("./agents-
|
|
28171
|
+
const { selectMergedWorkSessions } = await import("./reap-terminal-sessions-DnDQ7pf9.js");
|
|
28172
|
+
const { setAgentPaused } = await import("./agents-CEcaxSkR.js");
|
|
29589
28173
|
const toKill = selectMergedWorkSessions(loadReviewStatuses(), [...await Effect.runPromise(listSessionNames())]);
|
|
29590
28174
|
for (const session of toKill) try {
|
|
29591
28175
|
await Effect.runPromise(setAgentPaused(session, "merged — awaiting close-out (verify on main)", true));
|
|
@@ -29625,7 +28209,7 @@ const AWAITING_TEST_IDLE_REAP_MS = 600 * 1e3;
|
|
|
29625
28209
|
async function checkAwaitingTestWorkSessions() {
|
|
29626
28210
|
const actions = [];
|
|
29627
28211
|
try {
|
|
29628
|
-
const { selectAwaitingTestWorkSessions } = await import("./reap-terminal-sessions-
|
|
28212
|
+
const { selectAwaitingTestWorkSessions } = await import("./reap-terminal-sessions-DnDQ7pf9.js");
|
|
29629
28213
|
const candidates = selectAwaitingTestWorkSessions(loadReviewStatuses(), [...await Effect.runPromise(listSessionNames())]);
|
|
29630
28214
|
const now = Date.now();
|
|
29631
28215
|
for (const session of candidates) {
|
|
@@ -29681,7 +28265,7 @@ async function runPatrol() {
|
|
|
29681
28265
|
const stuckRemediationActions = await checkStuckAgentRemediation();
|
|
29682
28266
|
actions.push(...stuckRemediationActions);
|
|
29683
28267
|
for (const a of stuckRemediationActions) addLog("action", a, state.patrolCycle);
|
|
29684
|
-
const { reconcileInFlightJournals } = await import("./advancing-selfheal-
|
|
28268
|
+
const { reconcileInFlightJournals } = await import("./advancing-selfheal-DJYAvGv-.js");
|
|
29685
28269
|
const reconciledJournalActions = await reconcileInFlightJournals();
|
|
29686
28270
|
actions.push(...reconciledJournalActions);
|
|
29687
28271
|
for (const a of reconciledJournalActions) addLog("action", a, state.patrolCycle);
|
|
@@ -29693,7 +28277,7 @@ async function runPatrol() {
|
|
|
29693
28277
|
const age = Date.now() - (pending.timestamp ?? 0);
|
|
29694
28278
|
if (age < 3600 * 1e3) {
|
|
29695
28279
|
console.log(`[deacon] Processing pending post-merge lifecycle for ${pending.issueId} (age: ${Math.round(age / 1e3)}s)`);
|
|
29696
|
-
const { postMergeLifecycle } = await import("./merge-agent-
|
|
28280
|
+
const { postMergeLifecycle } = await import("./merge-agent-ejC7Wos8.js");
|
|
29697
28281
|
const { unlinkSync } = await import("fs");
|
|
29698
28282
|
unlinkSync(pendingFile);
|
|
29699
28283
|
await postMergeLifecycle(pending.issueId, pending.projectPath, pending.sourceBranch, { skipDeploy: true });
|
|
@@ -29738,7 +28322,7 @@ async function runPatrol() {
|
|
|
29738
28322
|
actions.push(...suspendActions);
|
|
29739
28323
|
for (const a of suspendActions) addLog("action", a, state.patrolCycle);
|
|
29740
28324
|
try {
|
|
29741
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
28325
|
+
const { resolveProjectFromIssueSync } = await import("./projects-CrBE6IhN.js");
|
|
29742
28326
|
const allStatuses = loadReviewStatuses();
|
|
29743
28327
|
for (const [issueId, status] of Object.entries(allStatuses)) {
|
|
29744
28328
|
if (!status.readyForMerge || status.mergeStatus === "merged") continue;
|
|
@@ -29758,7 +28342,7 @@ async function runPatrol() {
|
|
|
29758
28342
|
} catch (err) {
|
|
29759
28343
|
console.warn(`[deacon] Failed to check workspace existence: ${err.message}`);
|
|
29760
28344
|
}
|
|
29761
|
-
const { checkMergedAdvancingSessions } = await import("./advancing-selfheal-
|
|
28345
|
+
const { checkMergedAdvancingSessions } = await import("./advancing-selfheal-DJYAvGv-.js");
|
|
29762
28346
|
const reapedWorkActions = await checkMergedWorkSessions();
|
|
29763
28347
|
actions.push(...reapedWorkActions);
|
|
29764
28348
|
for (const a of reapedWorkActions) addLog("action", a, state.patrolCycle);
|
|
@@ -29766,7 +28350,7 @@ async function runPatrol() {
|
|
|
29766
28350
|
actions.push(...reapedMergedAdvancingActions);
|
|
29767
28351
|
for (const a of reapedMergedAdvancingActions) addLog("action", a, state.patrolCycle);
|
|
29768
28352
|
try {
|
|
29769
|
-
const { refreshClaudeCredentialsForActiveRemoteAgents } = await import("./remote-completion-
|
|
28353
|
+
const { refreshClaudeCredentialsForActiveRemoteAgents } = await import("./remote-completion-PhXGGFQy.js");
|
|
29770
28354
|
const remoteCredentialActions = await refreshClaudeCredentialsForActiveRemoteAgents();
|
|
29771
28355
|
actions.push(...remoteCredentialActions);
|
|
29772
28356
|
for (const a of remoteCredentialActions) addLog(a.includes("failed") ? "warn" : "action", a, state.patrolCycle);
|
|
@@ -29774,7 +28358,7 @@ async function runPatrol() {
|
|
|
29774
28358
|
addLog("warn", `Remote credential refresh patrol failed: ${err.message}`, state.patrolCycle);
|
|
29775
28359
|
}
|
|
29776
28360
|
try {
|
|
29777
|
-
const { refreshHostHeartbeatForEphemeralVms } = await import("./remote-agents-
|
|
28361
|
+
const { refreshHostHeartbeatForEphemeralVms } = await import("./remote-agents-Cv-U-_V8.js");
|
|
29778
28362
|
const heartbeatActions = await refreshHostHeartbeatForEphemeralVms();
|
|
29779
28363
|
actions.push(...heartbeatActions);
|
|
29780
28364
|
for (const a of heartbeatActions) addLog(a.includes("failed") ? "warn" : "action", a, state.patrolCycle);
|
|
@@ -29782,7 +28366,7 @@ async function runPatrol() {
|
|
|
29782
28366
|
addLog("warn", `Remote heartbeat refresh patrol failed: ${err.message}`, state.patrolCycle);
|
|
29783
28367
|
}
|
|
29784
28368
|
try {
|
|
29785
|
-
const { reapCompletedRemoteAgents } = await import("./remote-completion-
|
|
28369
|
+
const { reapCompletedRemoteAgents } = await import("./remote-completion-PhXGGFQy.js");
|
|
29786
28370
|
const remoteReap = await reapCompletedRemoteAgents();
|
|
29787
28371
|
for (const r of remoteReap) if (r.status === "handed-off" || r.status === "error") {
|
|
29788
28372
|
const msg = `Remote reap ${r.issueId}: ${r.status} (${r.details.join("; ")})`;
|
|
@@ -29917,7 +28501,10 @@ async function runPatrol() {
|
|
|
29917
28501
|
for (const a of playwrightActions) addLog("action", a, state.patrolCycle);
|
|
29918
28502
|
}
|
|
29919
28503
|
const projectConfigs = listProjectsSync();
|
|
29920
|
-
for (const
|
|
28504
|
+
for (const result of await reconcileProjectStatePlanes(projectConfigs)) {
|
|
28505
|
+
actions.push(result.message);
|
|
28506
|
+
addLog(result.level, result.message, state.patrolCycle);
|
|
28507
|
+
}
|
|
29921
28508
|
for (const warning of await recreatedStateWarnings(projectConfigs)) addLog("error", warning, state.patrolCycle);
|
|
29922
28509
|
const divergenceWarnings = await recordMainDivergenceHealth(state, projectConfigs);
|
|
29923
28510
|
for (const warning of divergenceWarnings) addLog("warn", warning, state.patrolCycle);
|
|
@@ -29960,7 +28547,7 @@ async function runPatrol() {
|
|
|
29960
28547
|
const issueId = runtimeState.currentIssue;
|
|
29961
28548
|
try {
|
|
29962
28549
|
if (getReviewStatusSync(issueId)?.mergeStatus === "merging") {
|
|
29963
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
28550
|
+
const { resolveProjectFromIssueSync } = await import("./projects-CrBE6IhN.js");
|
|
29964
28551
|
const resolved = resolveProjectFromIssueSync(issueId);
|
|
29965
28552
|
if (resolved) {
|
|
29966
28553
|
const branch = `feature/${issueId.toLowerCase()}`;
|
|
@@ -29974,7 +28561,7 @@ async function runPatrol() {
|
|
|
29974
28561
|
mergeStatus: "merged",
|
|
29975
28562
|
readyForMerge: false
|
|
29976
28563
|
});
|
|
29977
|
-
const { postMergeLifecycle } = await import("./merge-agent-
|
|
28564
|
+
const { postMergeLifecycle } = await import("./merge-agent-ejC7Wos8.js");
|
|
29978
28565
|
postMergeLifecycle(issueId, resolved.projectPath).catch((err) => console.warn(`[deacon] postMergeLifecycle failed for ${issueId}: ${err}`));
|
|
29979
28566
|
actions.push(`Auto-completed stale merge for ${issueId}`);
|
|
29980
28567
|
} else {
|
|
@@ -30154,7 +28741,7 @@ function startDeacon() {
|
|
|
30154
28741
|
logDeaconEventSync(`startDeacon: health monitor starting (patrol every ${config.patrolIntervalMs / 1e3}s)`);
|
|
30155
28742
|
(async () => {
|
|
30156
28743
|
await reconcileAgentLiveness();
|
|
30157
|
-
const { runBootAdvancingSelfHeal } = await import("./advancing-selfheal-
|
|
28744
|
+
const { runBootAdvancingSelfHeal } = await import("./advancing-selfheal-DJYAvGv-.js");
|
|
30158
28745
|
await runBootAdvancingSelfHeal();
|
|
30159
28746
|
runScheduledPatrol("startup");
|
|
30160
28747
|
})().catch((err) => {
|
|
@@ -30224,6 +28811,6 @@ function assessDeaconPatrolFreshness(params) {
|
|
|
30224
28811
|
};
|
|
30225
28812
|
}
|
|
30226
28813
|
//#endregion
|
|
30227
|
-
export { isPreKickoffLaunchDeath as $,
|
|
28814
|
+
export { isPreKickoffLaunchDeath as $, reconcileAgentLiveness as A, stalledReviewConvoyRecoveryState as At, applyIssueBlocksMainLabel as B, getContainerHistory as Bt, getLastPatrolResult as C, isSynthesisForActiveReviewRun as Ct, isDeaconRunning as D, handleWorkCompleted as Dt, handleAgentStoppedForOrphanReviewerSessions as E, handleReviewCoordinatorDied as Et, setAgentStatusChangedNotifier as F, INSPECT_TIMEOUT_MS as Ft, applyIssueVetoedLabel as G, startSmeeProcessSync as Gt, applyIssueParkedLabel as H, getResourceConfig as Ht, setAgentStoppedNotifier as I, checkInspectAgentTimeouts as It, removeIssueParkedLabel as J, removeIssueBlocksMainLabel as K, setMergeReadyNotifier as L, classifyMemoryPressure as Lt, resetPatrolHeartbeatForStartup as M, contextOverflowRecoveryState as Mt, runPatrol as N, contextProactiveCompactState as Nt, loadConfig as O, recoverStalledReviewConvoys as Ot, saveState as P, stuckOverflowNativeRecoveryState as Pt, createInFlightGuard as Q, startDeacon as R, getResourceStacks as Rt, getDeaconStatus as S, checkStuckReviewing as St, handleAgentStoppedEvent as T, checkOrphanedReviewStatuses as Tt, applyIssueReadyLabel as U, getSystemHealthSnapshot as Ut, applyIssueObjectionLabel as V, getCurrentDockerStats as Vt, applyIssueReleasedLabel as W, isSmeeConfiguredSync as Wt, removeIssueReleasedLabel as X, removeIssueReadyLabel as Y, removeIssueVetoedLabel as Z, cleanupOrphanReviewerSessions as _, withConcurrencyLimit as _t, checkCompletedButUnsignaledTests as a, listBootReconciliationCandidates as at, containerRestartBackoffMs as b, synthesizeReviewFromReports as bt, checkMergedWorkSessions as c, checkFailedMergeRetry as ct, checkPostReviewCommits as d, reconcileClosedPrReadyForMerge as dt, isRapidPostResumeDeath as et, checkReadyForMergeStuck as f, reconcileFalseMerged as ft, cleanupAbandonedFeedback as g, reconcileStuckReadyForMerge as gt, checkWorkspaceContainerHealth as h, reconcileStaleMergeStatus as ht, checkAwaitingTestWorkSessions as i, isBootReconciliationCandidate as it, reconcileTestStatusFromGreenCi as j, checkApiErrorAgents as jt, loadState as k, reviewConvoyLiveness as kt, checkOrphanedCompletions as l, checkFirstCompletionAgents as lt, checkVerificationReviewContradiction as m, reconcileStaleMergeBlockers as mt, assessDeaconPatrolFreshness as n, nudgeStalledResumeWorkAgents as nt, checkDeadEndAgents as o, startBootReconciliation as ot, checkStuckWorkAgents as p, reconcileMergedButReviewing as pt, removeIssueObjectionLabel as q, checkAndSuspendIdleAgents as r, redeliverUndeliveredKickoffs as rt, checkMassDeath as s, autoCloseOut as st, applyBootReconciliationDecision as t, nudgeIdleWorkAgentsWithOpenBeads as tt, checkPendingTestDispatch as u, ciRetryMap as ut, cleanupOrphanedPlanningSessions as v, cleanupOrphanedReviewSessions as vt, handleAgentHeartbeatDeadEvent as w, checkMissingReviewStatuses as wt, getDeaconLogs as x, checkCompletedButUnsignaledReviews as xt, cleanupStaleAgentState as y, monitorReviewConvoySignals as yt, stopDeacon as z, formatUptime as zt };
|
|
30228
28815
|
|
|
30229
|
-
//# sourceMappingURL=deacon-
|
|
28816
|
+
//# sourceMappingURL=deacon-DdARMjZq.js.map
|