@overdeck/desktop 0.45.13 → 0.45.15
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-DHZk2ceV.js} +2 -2
- package/server/{advancing-selfheal-Bn5QiLtn.js → advancing-selfheal-CSuZ31bB.js} +5 -5
- package/server/{agent-gc-Cl9Nm0Zu.js → agent-gc-D_DxfBHR.js} +3 -3
- package/server/{agent-state-C6Rm6FPR.js → agent-state-EP2QFV9n.js} +1 -1
- package/server/{agent-state-service-JhFzYCP_.js → agent-state-service-BZkvgQf4.js} +5 -5
- package/server/{agent-state-service-U8feBf8t.js → agent-state-service-C_2ZAQRP.js} +1 -1
- package/server/{agents-DqQa4Dq_.js → agents-CsOzAmRg.js} +117 -74
- package/server/{agents-CxbuBjID.js → agents-DCvyTXNU.js} +1 -1
- package/server/{archive-planning-DmpT1_14.js → archive-planning-CTILQRnV.js} +1 -1
- package/server/{archive-planning-CPitEZo4.js → archive-planning-DkivCk1A.js} +4 -4
- package/server/{artifact-index-jobs-sMnNtPhy.js → artifact-index-jobs-CmsvQ1ey.js} +2 -2
- package/server/auto-commit-QAfsu3Sb.js +3 -0
- package/server/{backlog-auto-trigger-Cf9C8fwD.js → backlog-auto-trigger-ueRaT8Dy.js} +2 -2
- package/server/{bd-process-lock-D1aJxeYv.js → bd-process-lock-D3S4T4o-.js} +32 -11
- package/server/{beads-DRoj6-e1.js → beads-BGGxrkZ5.js} +96 -196
- package/server/{beads-CivpXztb.js → beads-CYsLiyIM.js} +1 -1
- package/server/{beads-query-tOsAYP5h.js → beads-query-B1DlJVp9.js} +24 -99
- package/server/beads-restore-CyygSmmn.js +23 -0
- package/server/{behavior-D3d2mVyD.js → behavior-Cpj03N4v.js} +3 -3
- package/server/{briefing-freshness-BL3Q6p7R.js → briefing-freshness-Kh5V8RTh.js} +4 -4
- package/server/{checkpoint-manager-j5URlFY7.js → checkpoint-manager-CAFos8e1.js} +1 -1
- package/server/{checkpoint-manager-DCxjQvP_.js → checkpoint-manager-fu9oVsR-.js} +2 -2
- package/server/checkpoint-worker.js +1 -1
- package/server/{checkpoints-BoX1H2Hf.js → checkpoints-1BqOlS4q.js} +2 -2
- package/server/{checkpoints-Bu_M_Q9W.js → checkpoints-DvhGi8P_.js} +1 -1
- package/server/{claude-hooks-provision-D-jGXmu1.js → claude-hooks-provision-s_wdpeVj.js} +2 -2
- package/server/{claude-permissions-DxIjkOVl.js → claude-permissions-CaWqysff.js} +2 -2
- package/server/{claude-settings-overlay-5b9X2S0C.js → claude-settings-overlay-BbA4FbVI.js} +1 -1
- package/server/{claude-settings-overlay-BPDS6GfE.js → claude-settings-overlay-CcTf0xzG.js} +2 -2
- package/server/{cli-s7bPWy-E.js → cli-BwCvCUBK.js} +9 -9
- package/server/cli-ClIQwgMI.js +3 -0
- package/server/{cliproxy-BituqWtR.js → cliproxy-BsoNNDAj.js} +2 -2
- package/server/{cliproxy-D3sHB0sI.js → cliproxy-C2xC-3vH.js} +1 -1
- package/server/{close-issue-CrBE7voz.js → close-issue-BleIwP3f.js} +5 -5
- package/server/{closed-issue-reaper-BRQBc7Xa.js → closed-issue-reaper-BwUUvjEW.js} +1 -1
- package/server/{closed-issue-reaper-DX9mYUji.js → closed-issue-reaper-mC5pujeb.js} +102 -30
- package/server/{codex-Bi1ITSOo.js → codex-B7DTpwEw.js} +1 -1
- package/server/{codex-CO0HrK3j.js → codex-DW60_5j2.js} +5 -5
- package/server/{compact-beads-CrA8-k10.js → compact-beads-CK_hHEnB.js} +1 -1
- package/server/{compact-beads-DUkCUFxA.js → compact-beads-DKL54y6j.js} +15 -8
- package/server/{config-B4_d7z7z.js → config-BRNQJXhA.js} +1 -1
- package/server/{config-DsCxzjXK.js → config-ZNnMpIlh.js} +2 -2
- package/server/{config-yaml-C_djSurJ.js → config-yaml-Dcz-8uit.js} +29 -3
- package/server/{conflict-gate-CpOn9KC-.js → conflict-gate-DGT8jCLp.js} +1 -1
- package/server/{conflict-gate-D47Kl78u.js → conflict-gate-DTje2Ll7.js} +3 -3
- package/server/{context-layers-BNhUBTkf.js → context-layers-BdUCQ-cl.js} +3 -3
- package/server/{context-layers-CHl3Nroz.js → context-layers-ByOWUjUg.js} +2 -2
- package/server/{control-settings-KyYNXZLv.js → control-settings-DwkAeooY.js} +4 -4
- package/server/{conversation-compaction-D3aS5PnS.js → conversation-compaction-OTYgd6eg.js} +8 -8
- package/server/{conversation-compaction-D4Wed1BJ.js → conversation-compaction-WYQZUVDm.js} +1 -1
- package/server/{conversation-service-CFZIjs-M.js → conversation-service-BR1OgvxO.js} +5 -5
- package/server/{conversation-service-DcDB5usR.js → conversation-service-C_kNZPLx.js} +1 -1
- package/server/{conversations-BSOU5qnu.js → conversations-DG2M8WnT.js} +4 -4
- package/server/{conversations-BbDPrz89.js → conversations-izHvSoAR.js} +1 -1
- package/server/{cost-BE_ulOrw.js → cost-B2mj17iG.js} +3 -3
- package/server/{cost-CaiG63FG.js → cost-DQ2ajr_m.js} +2 -2
- package/server/{cost-sync-D6AX8jv-.js → cost-sync-gTayEuWP.js} +3 -3
- package/server/{dag-BQFtXOuJ.js → dag-CqTehWpY.js} +3 -3
- package/server/{dangerous-git-ops-04Ba-Qu3.js → dangerous-git-ops-DDWQlPC3.js} +1 -1
- package/server/dashboard-db-worker.js +6 -6
- package/server/{deacon-Bz-6Wjmn.js → deacon-BqW9HMew.js} +3 -3
- package/server/{deacon-2EvA9Ci3.js → deacon-DrKDBeJL.js} +161 -1594
- package/server/{deacon-nudge-log-B-naf89q.js → deacon-nudge-log-D1wEK6zF.js} +1 -1
- package/server/deacon-swarm-BY5hKNaU.js +2 -0
- package/server/{deacon-swarm-DYYOzHRH.js → deacon-swarm-CO_A7xyd.js} +12 -105
- package/server/deacon.js +7 -7
- package/server/{devcontainer-renderer-Dx0C7VWJ.js → devcontainer-renderer-BQolp_qZ.js} +3 -3
- package/server/{dist-ya66D9ze.js → dist-Bc32rWJB.js} +1 -1
- package/server/dist-DGTwcZhI.js +3 -0
- package/server/{docker-D2TbXDO6.js → docker-s-esqZ__.js} +67 -28
- package/server/{ensure-devcontainer-BTiMfFp5.js → ensure-devcontainer-DA4-jF6R.js} +4 -4
- package/server/{ensure-devcontainer-BIShzs3M.js → ensure-devcontainer-pUVaT0h3.js} +1 -1
- package/server/{esm-shims-DiV9jHa_.js → esm-shims-CJHy8CZY.js} +1 -1
- package/server/{event-store-C02Gprug.js → event-store-CcJAhKCl.js} +1 -1
- package/server/{event-store-C71x6h0i.js → event-store-DRte2Rwt.js} +3 -3
- package/server/{events-BFDuPV6n.js → events-Bej1w_k8.js} +3 -3
- package/server/{events-D2gP2-Yv.js → events-CtsLScn8.js} +1 -1
- package/server/export-Dx_qJ3h8.js +87 -0
- package/server/{factory-ByfbrCab.js → factory-FN727tWr.js} +4 -4
- package/server/{feature-registry-population-CSH66UO8.js → feature-registry-population-ie-yBcQC.js} +4 -4
- package/server/{feature-registry-storage-DW7dUefc.js → feature-registry-storage-CkZTFSsn.js} +2 -2
- package/server/{features-x_aLR7U9.js → features-Dtm9ABuz.js} +2 -2
- package/server/{feedback-target-BFo9fScH.js → feedback-target-BYtpyt1i.js} +6 -6
- package/server/{feedback-target-C4VMPTZu.js → feedback-target-DVJQDiE4.js} +1 -1
- package/server/{feedback-writer-DCyd75yJ.js → feedback-writer-DOUhyIW2.js} +1 -1
- package/server/{feedback-writer-B9ZqnnX3.js → feedback-writer-fdE1BzeL.js} +4 -4
- package/server/{flywheel-DB48X7Nn.js → flywheel-Bi82iiNl.js} +1 -1
- package/server/{flywheel-D9NKvWqb.js → flywheel-Bv3wv2S6.js} +23 -15
- package/server/{flywheel-DwQCoZQG.js → flywheel-CUErLAyN.js} +13 -13
- package/server/{flywheel-merge-order-DrjmFXg4.js → flywheel-merge-order-BaEN3iyN.js} +7 -7
- package/server/{flywheel-merge-order-f1bi5XIf.js → flywheel-merge-order-DXjeBnJ1.js} +1 -1
- package/server/{forge-C-SoKy8U.js → forge-ButEdJ31.js} +2 -2
- package/server/forge-XlDgPQWs.js +2 -0
- package/server/{from-fu7ZumnY.js → from-CbtTxftl.js} +1 -1
- package/server/{fts-db-CL-YzSRG.js → fts-db-CBgBLZcL.js} +2 -2
- package/server/{fts-operations-Bylu5NjM.js → fts-operations-CI9Xuo_1.js} +2 -2
- package/server/{git-utils-Ym380hJZ.js → git-utils-BCLRWQ-y.js} +1 -1
- package/server/{git-utils-C8koBs8j.js → git-utils-ClfpP47N.js} +2 -2
- package/server/{github-app-DIr70YLg.js → github-app-DRD2woO0.js} +1 -1
- package/server/{github-app-DhycHVLF.js → github-app-DscZ0_B6.js} +2 -2
- package/server/{github-client-7gkcXcBS.js → github-client-DpiZnxGH.js} +2 -2
- package/server/{github-client-Ji9lUTNF.js → github-client-iFRw8f7e.js} +1 -1
- package/server/{github-pr-lookup-rt7T9FwA.js → github-pr-lookup-D-EBexxC.js} +2 -2
- package/server/{harness-resolve-CvGXUnAF.js → harness-resolve-iMjyNUJ2.js} +3 -3
- package/server/{health-events-DDfkoO5a.js → health-events-B_WsQyYm.js} +1 -1
- package/server/{health-events-D4E1DLN-.js → health-events-CRdxDFN2.js} +2 -2
- package/server/{hooks-DvdnCVv6.js → hooks-C1ScyVxP.js} +1 -1
- package/server/{hooks-D_6pAbuJ.js → hooks-C9b7Vqpw.js} +2 -2
- package/server/hume-K1pi8jC4.js +3 -0
- package/server/{hume-DkVOs1Qi.js → hume-TQ5pvOZ_.js} +2 -2
- package/server/{idle-stack-reaper-cDRXDpgE.js → idle-stack-reaper-B1kG7B_X.js} +2 -2
- package/server/{idle-stack-reaper-DNbV9-fj.js → idle-stack-reaper-iFVOAoJy.js} +1 -1
- package/server/{infra-Clew3DpF.js → infra-bpq1MHKU.js} +3 -3
- package/server/{injection-QCIHOpk6.js → injection-BLWfwTVZ.js} +1 -1
- package/server/{injection-ql0Nddcn.js → injection-DJqWld1v.js} +7 -7
- package/server/inspect-agent-477VxQim.js +2 -0
- package/server/{inspect-agent-DY18KEx4.js → inspect-agent-DytCsltn.js} +9 -9
- package/server/{internal-token-C90jBp-y.js → internal-token-CCaWaTwE.js} +1 -1
- package/server/{internal-token-BeXjPLKy.js → internal-token-CjlhdufS.js} +2 -2
- package/server/{io-CbAFXQge.js → io-BiQ2Cs3k.js} +2 -2
- package/server/{issue-closed-BYC2TCk-.js → issue-closed-FApNiOOs.js} +4 -4
- package/server/{issue-lifecycle-CLHbj8RS.js → issue-lifecycle-BkFWNjlD.js} +1 -1
- package/server/{issue-lifecycle-BoJa6qIt.js → issue-lifecycle-C-K53ASY.js} +21 -21
- package/server/{issue-service-singleton-BS9NENuR.js → issue-service-singleton-CuHGpJJP.js} +8 -8
- package/server/{issue-service-singleton-3g_CCY-1.js → issue-service-singleton-bG1WdSdQ.js} +1 -1
- package/server/{issues-BPcqPqfV.js → issues-CwQMphDH.js} +2 -2
- package/server/jsonl-parser-dNIjHgym.js +245 -0
- package/server/{label-cleanup-CwiCSZrb.js → label-cleanup-DYvAZknd.js} +3 -3
- package/server/{layers-OHHLphl0.js → layers-CD6FysRU.js} +2 -2
- package/server/{lifecycle-B8IdvUbt.js → lifecycle-C_73gi-C.js} +7 -7
- package/server/{lifecycle-io-BMCH1Bxg.js → lifecycle-io-C_Wu0_i-.js} +1 -1
- package/server/{lifecycle-io-C73m5e6R.js → lifecycle-io-CeYxP3cE.js} +4 -4
- package/server/{linear-client-BMxgycoy.js → linear-client-4qoKnuQu.js} +1 -1
- package/server/{linear-client-CgQlM4aT.js → linear-client-EtVyblVz.js} +2 -2
- package/server/memory-fts-worker.js +1 -1
- package/server/{merge-B7Oi-g6k.js → merge-7rqkTUm2.js} +3 -3
- package/server/{merge-agent-Bwm34MZ5.js → merge-agent-36wfYm2u.js} +1 -1
- package/server/{merge-agent-DNFFsiEm.js → merge-agent-4Zhlgvqp.js} +28 -28
- package/server/{merge-batch-BpYXUaqJ.js → merge-batch-itfnwdsT.js} +1 -1
- package/server/{merge-blockers-DIOZmqdK.js → merge-blockers-Bto_Oe_o.js} +2 -2
- package/server/{merge-BRkVaIx-.js → merge-brm721Es.js} +1 -1
- package/server/merge-ops-PzqsW69V.js +2 -0
- package/server/{merge-rebase-C8WH39MB.js → merge-rebase-Czfqfe4q.js} +2 -2
- package/server/{merge-set-CsEE2CyQ.js → merge-set-BIkGQL9j.js} +3 -3
- package/server/{merge-set-DOsBTBQc.js → merge-set-G1RHcu3D.js} +1 -1
- package/server/{merge-sync-C2B322Ot.js → merge-sync-B43Dybea.js} +2 -2
- package/server/{merge-sync-CcLM2vwW.js → merge-sync-DIrmlZUr.js} +1 -1
- package/server/{merge-train-BIm7-7cy.js → merge-train-DGqVuNZV.js} +3 -3
- package/server/{merge-train-deps-DG1oQ2DT.js → merge-train-deps-q15XLnAS.js} +4 -4
- package/server/{merge-verification-BAbjxEd5.js → merge-verification-Cqfxx6bE.js} +4 -4
- package/server/{multipart-parser-jKtKAXtl.js → multipart-parser-CiPxxfUH.js} +2 -2
- package/server/node_modules/.package-lock.json +1 -1
- package/server/{orphan-proposed-reconciler-zHrwJ3xr.js → orphan-proposed-reconciler-BWWHn4Lr.js} +15 -39
- package/server/{orphan-proposed-reconciler-BqVGaOIj.js → orphan-proposed-reconciler-DAD9FJtQ.js} +1 -1
- package/server/package-lock.json +2 -2
- package/server/package.json +1 -1
- package/server/{pan-dir-BlNrLzW7.js → pan-dir-Bj7Hy8iu.js} +3 -3
- package/server/{paths-CiVeo4N_.js → paths-C9DkhIOT.js} +2 -2
- package/server/{pickup-KLRUhThD.js → pickup-CKRuGDsB.js} +1 -1
- package/server/{pipeline-notifier-nkWCe042.js → pipeline-notifier-BkKbQ8ji.js} +1 -1
- package/server/{pipeline-notifier-DBF6dHxH.js → pipeline-notifier-CAurUste.js} +2 -2
- package/server/project-pipelines-BRWaGmI4.js +162 -0
- package/server/projects-KJ94e50I.js +3 -0
- package/server/{prompts-CXbQvevY.js → prompts-DfI5qbTW.js} +2 -2
- package/server/{providers-CUdAb5Qu.js → providers-CWDXoaMA.js} +7 -7
- package/server/providers-D-5txBRc.js +3 -0
- package/server/public/assets/{chunk-BO2N2NFS-C-6y8VFI.js → chunk-BO2N2NFS-ClukPsZQ.js} +4 -4
- package/server/public/assets/{diagram-OG6HWLK6-NACO1xW5.js → diagram-OG6HWLK6-Avtvq2qI.js} +1 -1
- package/server/public/assets/{dist-DQD-ZjQY.js → dist-BEHQuasD.js} +3 -3
- package/server/public/assets/{dist-D1FjqGgm.js → dist-BvmY-qb1.js} +1 -1
- package/server/public/assets/{ganttDiagram-6RSMTGT7-CEMAKgmE.js → ganttDiagram-6RSMTGT7-7KhCd0fH.js} +1 -1
- package/server/public/assets/{highlighted-body-OFNGDK62-D5lC7FW8.js → highlighted-body-OFNGDK62-iQoBMTf0.js} +1 -1
- package/server/public/assets/index-DUFDmvmH.css +1 -0
- package/server/public/assets/{index-BDqWyuZQ.js → index-DnTZ2QeN.js} +132 -132
- package/server/public/assets/{linear-DDHAMRPB.js → linear-CiJHW9g5.js} +1 -1
- package/server/public/assets/mermaid-GHXKKRXX-DZJOwgBG.js +1 -0
- package/server/public/assets/{pieDiagram-4H26LBE5-DwBdeKBb.js → pieDiagram-4H26LBE5-BOhmvUhW.js} +1 -1
- package/server/public/assets/{prod-DAZt0c4G.js → prod-DmLBBqat.js} +4 -4
- package/server/public/assets/{quadrantDiagram-W4KKPZXB-CNDLp-_m.js → quadrantDiagram-W4KKPZXB-Cjku660G.js} +1 -1
- package/server/public/assets/{sankeyDiagram-5OEKKPKP-oIUL_uO1.js → sankeyDiagram-5OEKKPKP-D52w5oPh.js} +1 -1
- package/server/public/assets/{xychartDiagram-2RQKCTM6-B-IM6Cck.js → xychartDiagram-2RQKCTM6-BTO07_Iv.js} +1 -1
- package/server/public/index.html +2 -2
- package/server/{pull-requests-kTRl7cWC.js → pull-requests-Bmre-Xlz.js} +3 -3
- package/server/{pull-requests-DZ-V7_LB.js → pull-requests-CKZPWhjD.js} +1 -1
- package/server/{rally-xCTZ-UcI.js → rally-BBd9tQ__.js} +3 -3
- package/server/rally-Dc2Wnxw2.js +3 -0
- package/server/{rally-api-jOk4vit_.js → rally-api-DDc85HIz.js} +1 -1
- package/server/{rally-api-DpZo3WwF.js → rally-api-DxZFObI_.js} +2 -2
- package/server/{rally-client-BQjm3aaq.js → rally-client-BADHn0m_.js} +1 -1
- package/server/{rally-client-CoWZeVEj.js → rally-client-DvvLiAQP.js} +4 -4
- package/server/{reap-terminal-sessions-CAmURC2h.js → reap-terminal-sessions-D6JDJsqF.js} +1 -1
- package/server/{reap-terminal-sessions-BwJb2DLJ.js → reap-terminal-sessions-D_xvy-Mk.js} +1 -1
- package/server/{rebuild-stack-BZ7j27xY.js → rebuild-stack-D19i080j.js} +6 -6
- package/server/{rebuild-stack-r-cxcr26.js → rebuild-stack-GOsWqXi3.js} +1 -1
- package/server/{reconstruct-cache-13EkMg_i.js → reconstruct-cache-lQrG4xGg.js} +6 -6
- package/server/record-pyB6VA32.js +3 -0
- package/server/recovery-trip-Dfh1tNHn.js +98 -0
- package/server/{release-engine-YLTnEO_K.js → release-engine-DxcMWRuK.js} +5 -5
- package/server/{release-set-DwvT_Opu.js → release-set-BYsgX7o6.js} +3 -3
- package/server/{remote-9u9WL0NJ.js → remote-8W2Yhygw.js} +3 -3
- package/server/{remote-B062S1Kc.js → remote-DmeL21dF.js} +3 -3
- package/server/{remote-agents-BBTg-vLT.js → remote-agents-BfQBE6MN.js} +5 -5
- package/server/{remote-agents-B4eWgwNd.js → remote-agents-DlvbzO7m.js} +1 -1
- package/server/{remote-completion-B0rmBnbL.js → remote-completion-BgkiSQmx.js} +12 -12
- package/server/resolver-dTpSSzaH.js +158 -0
- package/server/resume-DhcIqsTm.js +3 -0
- package/server/{review-agent-tfR5RDzG.js → review-agent-D025Wt7w.js} +22 -22
- package/server/{review-agent-Bf9XjLnl.js → review-agent-Rub0OpZc.js} +1 -1
- package/server/{review-artifacts-D0_IE6DQ.js → review-artifacts-CX951jTU.js} +6 -6
- package/server/{review-context-CXO5ml5D.js → review-context-DGGGR_w5.js} +7 -7
- package/server/{review-monitor-DfFUSx0J.js → review-monitor-0_qqMcnS.js} +2 -2
- package/server/{review-status-BcfwcAcO.js → review-status-4qqLkRMu.js} +17 -17
- package/server/{review-status-B0Axo-Ma.js → review-status-Br6lAFGO.js} +1 -1
- package/server/{review-status-enrichment-Cp5kFTGl.js → review-status-enrichment-Cr8m3uVL.js} +3 -3
- package/server/{review-status-sync-Bc0c_u12.js → review-status-sync-D3KUhsdA.js} +1 -1
- package/server/{review-status-sync-CEFty1pW.js → review-status-sync-OC-l1lNt.js} +2 -2
- package/server/{review-verdict-feedback-BOKRLLDf.js → review-verdict-feedback-DrWMuRaj.js} +6 -6
- package/server/{review-verdict-feedback-BnGtT0vN.js → review-verdict-feedback-YOzmsq9G.js} +1 -1
- package/server/{rollup-C22QDVxh.js → rollup-CnxbwaLH.js} +8 -8
- package/server/{rollup-BVqFuiS9.js → rollup-DmazRY0j.js} +1 -1
- package/server/{scanner-BLCnuXqY.js → scanner-DE1MqAaF.js} +7 -7
- package/server/{sequence-io-BozlUb6f.js → sequence-io-C0uoqfGx.js} +4 -4
- package/server/{sequencer-agent-BEDEHfd2.js → sequencer-agent-i-b2u4SJ.js} +10 -6
- package/server/server.js +1020 -293
- package/server/{service-C8jKYZ0w.js → service-D0_gh2tl.js} +1668 -1408
- package/server/{session-fork-BDGksK4e.js → session-fork-DZ12vipL.js} +2 -2
- package/server/{settings-CSLhh6qR.js → settings-ByqjPtFO.js} +2 -2
- package/server/{settings-DrRQCren.js → settings-DCC4BAqj.js} +3 -3
- package/server/settings-yydgaqhv.js +2 -0
- package/server/{shadow-engineering-BMcBN-Of.js → shadow-engineering-BhnmtW5m.js} +2 -2
- package/server/{shadow-state-CHqWHD3T.js → shadow-state-ByXZehsy.js} +1 -1
- package/server/{shadow-state-B4ayC7nx.js → shadow-state-CKm8xWX9.js} +2 -2
- package/server/{ship-log-CDVmOlZP.js → ship-log-DE_0Cv_i.js} +1 -1
- package/server/{smart-compaction-C-F5sP9P.js → smart-compaction-D5Zen3AA.js} +7 -7
- package/server/{smart-compaction-V9DBrGcr.js → smart-compaction-h4_ca6Uk.js} +1 -1
- package/server/{spawn-planning-session-Bz4_JES2.js → spawn-planning-session-Bgi7Ub02.js} +1 -1
- package/server/{spawn-planning-session-dSpOU0lP.js → spawn-planning-session-Dueit4WX.js} +15 -15
- package/server/{specialist-completion-Coz3eTSr.js → specialist-completion-BZ8M-WZ0.js} +1 -1
- package/server/{specialist-context-fmb03vXQ.js → specialist-context-BMq83C58.js} +5 -5
- package/server/{specialist-handoff-logger-B9HK_lRu.js → specialist-handoff-logger-BxX1YefH.js} +2 -2
- package/server/{specialist-logs-B24R2B9Y.js → specialist-logs-BWZYcJ6P.js} +3 -3
- package/server/{specialists-Chvvwf5z.js → specialists-8ZAguXef.js} +1 -1
- package/server/{specialists-CL7E8yUg.js → specialists-BudKrjOu.js} +76 -76
- package/server/{specialists-BGNZ0_ZW.js → specialists-DrPrC9Y9.js} +20 -256
- package/server/{specialists-B6f5-5nG.js → specialists-ZkW4Mb7U.js} +1 -1
- package/server/specs-DwoAEGrW.js +3 -0
- package/server/{src-DGAEtABV.js → src-DHn4Rd2F.js} +13 -2
- package/server/{src-D-VXCC9C.js → src-DNUUqkec.js} +6 -6
- package/server/{src-BVxZuHMg.js → src-Dv6L03vW.js} +3 -3
- package/server/{stack-health-BKbTTOT2.js → stack-health-Dclm7_tu.js} +1 -1
- package/server/{stack-health-C-le5erA.js → stack-health-DxsTx7II.js} +2 -2
- package/server/{state-home-CoyWsECg.js → state-home-CRowbXqU.js} +6 -6
- package/server/stuck-remediation-CFWUP8_I.js +1491 -0
- package/server/stuck-remediation-CLHd-lrF.js +2 -0
- package/server/{summary-fork-BF_0vxrq.js → summary-fork-CKc01Our.js} +2 -2
- package/server/{summary-fork-BlE30Q-I.js → summary-fork-CtCwBJ2Z.js} +8 -8
- package/server/{supervisor-BSeML_p0.js → supervisor-BA5D72Qa.js} +2 -2
- package/server/supervisor-DHjumXlL.js +2 -0
- package/server/{swarm-readiness-CQ4sjrXc.js → swarm-readiness-CL5sM9B1.js} +3 -3
- package/server/{system-prerequisites-DnmLYOnU.js → system-prerequisites-DmFSXIE5.js} +1 -1
- package/server/{teardown-workspace-CpcjDrZ4.js → teardown-workspace-DWmFJzTw.js} +37 -68
- package/server/{test-agent-queue-Bq298zZl.js → test-agent-queue-DjsQoV5X.js} +6 -6
- package/server/{test-verdict-CCDd25uN.js → test-verdict-BSqsQp3G.js} +1 -1
- package/server/{test-verdict-Bm4uv_AA.js → test-verdict-D1AmZ2c0.js} +1 -1
- package/server/{tldr-daemon-CaSUXd9r.js → tldr-daemon-C-MGomL8.js} +2 -2
- package/server/{tldr-daemon-Rn1Zue0P.js → tldr-daemon-DD9rI5gA.js} +1 -1
- package/server/{tmux-BVc-NeKM.js → tmux-C_d-lSIq.js} +2 -2
- package/server/{tmux-CbcrkUx5.js → tmux-x291Gjjb.js} +1 -1
- package/server/{token-D2OC_9ms.js → token-DfBf1bsd.js} +1 -1
- package/server/{tracker-config-C1Y_2CIo.js → tracker-config-CNODpd11.js} +2 -2
- package/server/{tracker-config-EsBoOWEy.js → tracker-config-DItsdelv.js} +1 -1
- package/server/{tracker-utils-DSb9cfrF.js → tracker-utils-B9ZoVA9b.js} +1 -1
- package/server/{tracker-utils-lph9C3Pw.js → tracker-utils-Ch2_5GGf.js} +2 -2
- package/server/{traefik-connect-5EP1WS_Z.js → traefik-connect-BF4x_LUQ.js} +1 -1
- package/server/{tunnel-DDe-ATFF.js → tunnel-YD80_IHr.js} +1 -1
- package/server/{tunnel-BFBCeo97.js → tunnel-r_5nHAI6.js} +3 -3
- package/server/{types-B5u3NxMl.js → types-33JEP4LZ.js} +1 -1
- package/server/{uat-train-8T24rPzc.js → uat-train-DDI00aqD.js} +1 -1
- package/server/{uat-train-DtKHHy1U.js → uat-train-DjkFWXge.js} +25 -25
- package/server/{validation-lyudzPvD.js → validation-DUTiJnyz.js} +4 -4
- package/server/{validation-COOXwNXU.js → validation-ict8hnXk.js} +1 -1
- package/server/{verification-runner-Dd1FX8Qk.js → verification-runner-ATaLbpr5.js} +1 -1
- package/server/{verification-runner-DO0nYTJx.js → verification-runner-inLgeQux.js} +12 -12
- package/server/{vtt-parser-C57tEF7-.js → vtt-parser-QnRfcjiU.js} +1 -1
- package/server/{work-agent-prompt-B2F3ZwKm.js → work-agent-prompt-fZljjA1_.js} +12 -12
- package/server/{workflows-Clz_AFwR.js → workflows-oBnJ7Tm0.js} +14 -14
- package/server/workflows-tU7KKxQi.js +2 -0
- package/server/{workspace-D0rCFemz.js → workspace-B2WOW9Hw.js} +1 -1
- package/server/{workspace-CY_2-Ddv.js → workspace-CNuW2j41.js} +3 -3
- package/server/{workspace-config-DA8U97k9.js → workspace-config-CBgMGhWs.js} +1 -1
- package/server/{workspace-manager-D6NgGkiF.js → workspace-manager-CB-R07R3.js} +12 -12
- package/server/{workspace-manager-BIfpzqdU.js → workspace-manager-DjUAJCSs.js} +1 -1
- package/server/{workspace-metadata-C8yn8kAH.js → workspace-metadata-9Nn5kgRl.js} +2 -2
- package/server/{workspace-metadata-DfgR40YU.js → workspace-metadata-Fd58uUQG.js} +1 -1
- package/server/{workspaces-DOeHyKmA.js → workspaces-BjWXntty.js} +94 -120
- package/server/writer-CQMGzEkw.js +3 -0
- package/server/writer-fe1-8iGc.js +251 -0
- package/sync-sources/hooks/record-cost-event.js +2 -1
- package/sync-sources/hooks/record-cost-event.js.map +1 -1
- 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/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/workflows-B4fIN8VP.js +0 -2
|
@@ -1,695 +1,53 @@
|
|
|
1
1
|
import { i as __require, t as __commonJSMin } from "./rolldown-runtime-DNCzzKnI.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Ar as OVERDECK_HOME, Bt as writeIssueRecordSync, Ct as ensureIssueRecordSync, Kn as resolveProjectFromIssueSync, Nt as readIssueRecordForWorkspaceSync, On as getProjectSync, Pn as init_projects, Pt as readIssueRecordSync, Rn as listProjectsSync, Tn as getIssuePrefix, Zr as sessionFilePath, br as init_errors, cn as STATE_PLANE_PATHS, f as loadConfigSync, fn as isStatePlanePath, in as init_auto_commit, kt as init_record, ln as getMainDivergence, on as queueBeadsAutoCommit, qr as init_paths, s as init_load, un as init_state_plane, xr as AGENTS_DIR } from "./config-yaml-Dcz-8uit.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 { t as init_behavior } from "./behavior-D3d2mVyD.js";
|
|
11
|
-
import { a as init_tracker_config, t as getGitHubConfig } from "./tracker-config-C1Y_2CIo.js";
|
|
12
|
-
import { i as resolveGitHubIssueSync, n as init_tracker_utils } from "./tracker-utils-lph9C3Pw.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-C_d-lSIq.js";
|
|
5
|
+
import { a as init_event_store, i as initEventStore } from "./event-store-DRte2Rwt.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-4qqLkRMu.js";
|
|
7
|
+
import { d as init_agents, g as isTerminalIssueStage, h as getIssueStageSync, p as listAllAgentsSync } from "./briefing-freshness-Kh5V8RTh.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, _r as init_runtime_state, _t as init_config, at as init_concurrency, ct as resetPatrolDispatchBudget, dt as workResumeSlotsAvailable, er as init_persistent_logger, et as countRunningAgents, gn as buildDefaultResumeContinueMessage, gr as getAgentRuntimeStateSync, hr as getAgentRuntimeState, it as getConcurrencyLimits, k as isContextOverflowTail, lt as tryReserveAdvancingSlot, mt as setCachedMemoryVerdict, nr as logDeaconEventSync, nt as describeRunningAgents, ot as releaseAdvancingSlot, pt as init_memory_verdict_cache, qn as saveAgentState, t as init_agents$1, tr as logAgentLifecycleSync, vr as saveAgentRuntimeState, vt as loadCloisterConfig, wt as deliverInitialPromptWithRetry, yt as loadCloisterConfigSync } from "./agents-CsOzAmRg.js";
|
|
9
|
+
import { i as resolveGitHubIssueSync, n as init_tracker_utils } from "./tracker-utils-Ch2_5GGf.js";
|
|
13
10
|
import { n as mapGitHubStateToCanonical, t as init_state_mapping } from "./state-mapping-BvAgFK8n.js";
|
|
14
|
-
import { c as init_review_status_sync, l as markWorkspaceStuck } from "./review-status-sync-
|
|
15
|
-
import { f as init_config$1, m as loadConfigSync$1, p as loadConfig$1 } from "./config-
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import { a as
|
|
21
|
-
import { n as __filename, r as init_esm_shims } from "./esm-shims-
|
|
22
|
-
import {
|
|
23
|
-
import { t as
|
|
24
|
-
import {
|
|
25
|
-
import { a as inferBranchFromWorkspace, i as findWorkspacePath, o as init_archive_planning } from "./archive-planning-
|
|
26
|
-
import { n as init_issue_closed, r as isIssueClosed } from "./issue-closed-
|
|
27
|
-
import { n as shouldSkipDispatchAsMerged, t as init_merge_verification } from "./merge-verification-
|
|
28
|
-
import { n as init_review_verdict_feedback, t as deliverReviewVerdictFeedback } from "./review-verdict-feedback-
|
|
29
|
-
import { n as reconcileTraefikNetworks, t as init_traefik_connect } from "./traefik-connect-
|
|
30
|
-
import {
|
|
11
|
+
import { c as init_review_status_sync, l as markWorkspaceStuck } from "./review-status-sync-OC-l1lNt.js";
|
|
12
|
+
import { f as init_config$1, m as loadConfigSync$1, p as loadConfig$1 } from "./config-ZNnMpIlh.js";
|
|
13
|
+
import { n as init_state_home, t as findRecreatedLegacyStatePaths } from "./state-home-CRowbXqU.js";
|
|
14
|
+
import { T as stampBootReconciliation, h as setBootReconciliationDecision, l as isDeaconGloballyPaused, r as getBootReconciliationState, s as init_control_settings } from "./control-settings-DwkAeooY.js";
|
|
15
|
+
import { c as init_docker_stats, s as DockerStatsCollector } from "./stack-health-DxsTx7II.js";
|
|
16
|
+
import { a as queryBeadsForIssue, o as queryReadyBeadsByIssueLabels, r as init_beads_query, s as resolveBeadsQueryRoot } from "./beads-query-B1DlJVp9.js";
|
|
17
|
+
import { a as isAgentIdleForNudge, t as checkStuckAgentRemediation } from "./stuck-remediation-CFWUP8_I.js";
|
|
18
|
+
import { n as __filename, r as init_esm_shims } from "./esm-shims-CJHy8CZY.js";
|
|
19
|
+
import { t as recordDeaconNudge } from "./deacon-nudge-log-D1wEK6zF.js";
|
|
20
|
+
import { n as init_review_monitor, t as REVIEW_SUB_ROLES } from "./review-monitor-0_qqMcnS.js";
|
|
21
|
+
import { O as init_specialists, R as parseReviewerSessionName, T as getTmuxSessionName, d as getAllProjectSpecialistStatuses } from "./specialists-DrPrC9Y9.js";
|
|
22
|
+
import { a as inferBranchFromWorkspace, i as findWorkspacePath, o as init_archive_planning } from "./archive-planning-DkivCk1A.js";
|
|
23
|
+
import { n as init_issue_closed, r as isIssueClosed } from "./issue-closed-FApNiOOs.js";
|
|
24
|
+
import { n as shouldSkipDispatchAsMerged, t as init_merge_verification } from "./merge-verification-Cqfxx6bE.js";
|
|
25
|
+
import { n as init_review_verdict_feedback, t as deliverReviewVerdictFeedback } from "./review-verdict-feedback-DrWMuRaj.js";
|
|
26
|
+
import { n as reconcileTraefikNetworks, t as init_traefik_connect } from "./traefik-connect-BF4x_LUQ.js";
|
|
27
|
+
import { g as decideAgentAutonomousRedrive, r as coordinateSwarmSlots, y as listFeatureWorkspaces } from "./deacon-swarm-CO_A7xyd.js";
|
|
28
|
+
import { t as recordRecoveryFailure } from "./recovery-trip-Dfh1tNHn.js";
|
|
31
29
|
import { n as isExplicitNoResumeRequest, t as init_no_resume_mode } from "./no-resume-mode-yrPEQ_pC.js";
|
|
32
|
-
import { n as reconcileClosedIssueAgents } from "./closed-issue-reaper-
|
|
33
|
-
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-
|
|
34
|
-
import { n as pruneTerminalStoppedAgents } from "./agent-gc-
|
|
35
|
-
import { a as spawnWorkAgentThroughAgentsEndpoint, i as reconcileOrphanProposedSpecs, o as triggerRebuildAndStart } from "./orphan-proposed-reconciler-
|
|
36
|
-
import { n as reconcileIdleWorkspaceStacks } from "./idle-stack-reaper-
|
|
37
|
-
import { i as readTestVerdictArtifact, n as decideUnsignaledTestAction, r as init_test_verdict } from "./test-verdict-
|
|
30
|
+
import { n as reconcileClosedIssueAgents } from "./closed-issue-reaper-mC5pujeb.js";
|
|
31
|
+
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-CKRuGDsB.js";
|
|
32
|
+
import { n as pruneTerminalStoppedAgents } from "./agent-gc-D_DxfBHR.js";
|
|
33
|
+
import { a as spawnWorkAgentThroughAgentsEndpoint, i as reconcileOrphanProposedSpecs, o as triggerRebuildAndStart } from "./orphan-proposed-reconciler-BWWHn4Lr.js";
|
|
34
|
+
import { n as reconcileIdleWorkspaceStacks } from "./idle-stack-reaper-B1kG7B_X.js";
|
|
35
|
+
import { i as readTestVerdictArtifact, n as decideUnsignaledTestAction, r as init_test_verdict } from "./test-verdict-D1AmZ2c0.js";
|
|
38
36
|
import { createRequire } from "node:module";
|
|
39
37
|
import { join } from "node:path";
|
|
40
38
|
import { Effect } from "effect";
|
|
41
|
-
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync,
|
|
39
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "fs";
|
|
42
40
|
import { dirname as dirname$1, join as join$1 } from "path";
|
|
43
|
-
import { cpus,
|
|
41
|
+
import { cpus, loadavg } from "os";
|
|
44
42
|
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
43
|
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
44
|
import { access, readFile } from "node:fs/promises";
|
|
47
|
-
import { readFile as readFile$1, readdir as readdir$1,
|
|
45
|
+
import { readFile as readFile$1, readdir as readdir$1, writeFile as writeFile$1 } from "fs/promises";
|
|
48
46
|
import { exec, execFile, spawn } from "node:child_process";
|
|
49
47
|
import { promisify } from "node:util";
|
|
50
48
|
import { exec as exec$1, execFile as execFile$1, spawn as spawn$1 } from "child_process";
|
|
51
49
|
import { promisify as promisify$1 } from "util";
|
|
52
|
-
import "node:crypto";
|
|
53
50
|
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
51
|
//#region ../../../node_modules/.bun/undici@7.25.0/node_modules/undici/lib/core/symbols.js
|
|
694
52
|
var require_symbols = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
695
53
|
module.exports = {
|
|
@@ -22101,7 +21459,9 @@ var require_eventsource = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
22101
21459
|
defaultReconnectionTime
|
|
22102
21460
|
};
|
|
22103
21461
|
}));
|
|
22104
|
-
|
|
21462
|
+
//#endregion
|
|
21463
|
+
//#region ../../../node_modules/.bun/undici@7.25.0/node_modules/undici/index.js
|
|
21464
|
+
var require_undici = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
22105
21465
|
init_esm_shims();
|
|
22106
21466
|
const Client = require_client();
|
|
22107
21467
|
const Dispatcher = require_dispatcher();
|
|
@@ -22267,7 +21627,30 @@ new ((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
22267
21627
|
globalThis.EventSource = module.exports.EventSource;
|
|
22268
21628
|
}
|
|
22269
21629
|
module.exports.install = install;
|
|
22270
|
-
}))
|
|
21630
|
+
}));
|
|
21631
|
+
//#endregion
|
|
21632
|
+
//#region ../../../node_modules/.bun/smee-client@5.0.0/node_modules/smee-client/index.js
|
|
21633
|
+
init_paths();
|
|
21634
|
+
init_errors();
|
|
21635
|
+
init_activity_logger();
|
|
21636
|
+
init_projects();
|
|
21637
|
+
init_tmux();
|
|
21638
|
+
init_agents();
|
|
21639
|
+
init_review_status_sync();
|
|
21640
|
+
init_review_dispatch_decision();
|
|
21641
|
+
init_review_status();
|
|
21642
|
+
init_runtime_state();
|
|
21643
|
+
init_persistent_logger();
|
|
21644
|
+
init_agent_state();
|
|
21645
|
+
init_transcript_landing();
|
|
21646
|
+
init_config();
|
|
21647
|
+
init_memory_verdict_cache();
|
|
21648
|
+
init_concurrency();
|
|
21649
|
+
init_queries();
|
|
21650
|
+
init_termination();
|
|
21651
|
+
init_context_overflow();
|
|
21652
|
+
init_agents$1();
|
|
21653
|
+
new (require_undici()).EnvHttpProxyAgent();
|
|
22271
21654
|
//#endregion
|
|
22272
21655
|
//#region ../../lib/smee.ts
|
|
22273
21656
|
/**
|
|
@@ -22286,7 +21669,7 @@ new ((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
22286
21669
|
* stopSmeeProcess();
|
|
22287
21670
|
* isSmeeProcessRunning();
|
|
22288
21671
|
*/
|
|
22289
|
-
|
|
21672
|
+
init_config$1();
|
|
22290
21673
|
const SMEE_URL_PATH = join(homedir$1(), ".overdeck", "github-app", "smee-url");
|
|
22291
21674
|
const SMEE_PID_PATH = join(homedir$1(), ".overdeck", "github-app", "smee.pid");
|
|
22292
21675
|
const SMEE_LOG_PATH = join(homedir$1(), ".overdeck", "logs", "smee.log");
|
|
@@ -22451,10 +21834,9 @@ function startSmeeProcessSync() {
|
|
|
22451
21834
|
}
|
|
22452
21835
|
//#endregion
|
|
22453
21836
|
//#region services/system-health-service.ts
|
|
22454
|
-
|
|
22455
|
-
|
|
22456
|
-
|
|
22457
|
-
const execAsync$7 = promisify(exec);
|
|
21837
|
+
init_docker_stats();
|
|
21838
|
+
init_event_store();
|
|
21839
|
+
const execAsync$6 = promisify(exec);
|
|
22458
21840
|
const DEFAULT_HEALTH_POLL_SECONDS = 15;
|
|
22459
21841
|
const DEFAULT_RESOURCE_CONFIG = {
|
|
22460
21842
|
memoryWarnGb: 4,
|
|
@@ -22586,7 +21968,7 @@ async function readProcMemoryDarwin() {
|
|
|
22586
21968
|
let memAvailable = freemem$1();
|
|
22587
21969
|
let memFree = freemem$1();
|
|
22588
21970
|
try {
|
|
22589
|
-
const { stdout } = await execAsync$
|
|
21971
|
+
const { stdout } = await execAsync$6("vm_stat", {
|
|
22590
21972
|
encoding: "utf-8",
|
|
22591
21973
|
timeout: 5e3
|
|
22592
21974
|
});
|
|
@@ -22606,7 +21988,7 @@ async function readProcMemoryDarwin() {
|
|
|
22606
21988
|
let swapTotal = 0;
|
|
22607
21989
|
let swapFree = 0;
|
|
22608
21990
|
try {
|
|
22609
|
-
const { stdout } = await execAsync$
|
|
21991
|
+
const { stdout } = await execAsync$6("sysctl -n vm.swapusage", {
|
|
22610
21992
|
encoding: "utf-8",
|
|
22611
21993
|
timeout: 5e3
|
|
22612
21994
|
});
|
|
@@ -22666,7 +22048,7 @@ async function readCpuPercent() {
|
|
|
22666
22048
|
return Math.round((totalDelta - idleDelta) / totalDelta * 1e3) / 10;
|
|
22667
22049
|
}
|
|
22668
22050
|
async function readProcessTable() {
|
|
22669
|
-
const { stdout } = await execAsync$
|
|
22051
|
+
const { stdout } = await execAsync$6("ps -eo pid=,ppid=,rss=,args=", {
|
|
22670
22052
|
encoding: "utf-8",
|
|
22671
22053
|
timeout: 1e4
|
|
22672
22054
|
});
|
|
@@ -22943,6 +22325,7 @@ async function getSystemHealthSnapshot(snapshot) {
|
|
|
22943
22325
|
}
|
|
22944
22326
|
//#endregion
|
|
22945
22327
|
//#region routes/resources/shared.ts
|
|
22328
|
+
init_load();
|
|
22946
22329
|
init_docker_stats();
|
|
22947
22330
|
function getCurrentDockerStats() {
|
|
22948
22331
|
return [];
|
|
@@ -23111,378 +22494,6 @@ async function assessMemoryPressure() {
|
|
|
23111
22494
|
return verdict;
|
|
23112
22495
|
}
|
|
23113
22496
|
//#endregion
|
|
23114
|
-
//#region ../../lib/runtimes/claude-code.ts
|
|
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();
|
|
23124
|
-
init_tmux();
|
|
23125
|
-
init_jsonl_parser();
|
|
23126
|
-
init_errors();
|
|
23127
|
-
const CLAUDE_PROJECTS_DIR = join$1(homedir(), ".claude", "projects");
|
|
23128
|
-
/**
|
|
23129
|
-
* Claude Code Runtime implementation
|
|
23130
|
-
*/
|
|
23131
|
-
var ClaudeCodeRuntimeSync = class {
|
|
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
22497
|
//#region ../../lib/cloister/deacon-inspect.ts
|
|
23487
22498
|
init_review_status();
|
|
23488
22499
|
init_tmux();
|
|
@@ -23526,7 +22537,7 @@ async function checkInspectAgentTimeouts(now = /* @__PURE__ */ new Date()) {
|
|
|
23526
22537
|
console.warn(`[deacon] Failed to kill inspect session ${sessionName}: ${msg}`);
|
|
23527
22538
|
});
|
|
23528
22539
|
try {
|
|
23529
|
-
const { messageAgent } = await import("./agents-
|
|
22540
|
+
const { messageAgent } = await import("./agents-DCvyTXNU.js");
|
|
23530
22541
|
await messageAgent(`agent-${issueId.toLowerCase()}`, verdict, "deacon:inspect-watchdog");
|
|
23531
22542
|
} catch (err) {
|
|
23532
22543
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -23539,43 +22550,6 @@ async function checkInspectAgentTimeouts(now = /* @__PURE__ */ new Date()) {
|
|
|
23539
22550
|
return actions;
|
|
23540
22551
|
}
|
|
23541
22552
|
//#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
22553
|
//#region ../../lib/cloister/modal-detector.ts
|
|
23580
22554
|
init_tmux();
|
|
23581
22555
|
const KNOWN_AGENT_MODALS = [{
|
|
@@ -23584,9 +22558,15 @@ const KNOWN_AGENT_MODALS = [{
|
|
|
23584
22558
|
keys: ["Down", "Enter"]
|
|
23585
22559
|
}];
|
|
23586
22560
|
/** Rollout JSONL is launch/turn attribution only until a captured switch proves otherwise. */
|
|
22561
|
+
const MODEL_SHAPED_TOKEN = /^(?:gpt|o\d|claude|kimi|glm|gemini|deepseek|qwen|minimax|grok)[\w.-]*$/i;
|
|
23587
22562
|
function paneShowsModelSwitch(pane, launchModel) {
|
|
23588
|
-
const
|
|
23589
|
-
|
|
22563
|
+
const modelPhrase = pane.match(/model\s+(?:switched|switching)\s+to\s+([\w.-]+)|(?:switched|switching)\s+model\s+to\s+([\w.-]+)/i);
|
|
22564
|
+
let target = modelPhrase?.[1] ?? modelPhrase?.[2];
|
|
22565
|
+
if (!target) {
|
|
22566
|
+
const generic = pane.match(/(?:switched|switching)\s+to\s+([\w.-]+)/i)?.[1];
|
|
22567
|
+
if (generic && MODEL_SHAPED_TOKEN.test(generic)) target = generic;
|
|
22568
|
+
}
|
|
22569
|
+
return Boolean(target && target.toLowerCase() !== launchModel.toLowerCase());
|
|
23590
22570
|
}
|
|
23591
22571
|
const defaultDeps = {
|
|
23592
22572
|
capturePane: (agentId) => Effect.runPromise(capturePane(agentId, 100)),
|
|
@@ -23604,7 +22584,6 @@ async function handleKnownAgentModal(agentId, deps = defaultDeps, initialPane) {
|
|
|
23604
22584
|
//#endregion
|
|
23605
22585
|
//#region ../../lib/cloister/deacon-api-recovery.ts
|
|
23606
22586
|
init_agents$1();
|
|
23607
|
-
init_paths();
|
|
23608
22587
|
init_review_status();
|
|
23609
22588
|
init_tmux();
|
|
23610
22589
|
/**
|
|
@@ -23701,7 +22680,7 @@ async function maybeProactivelyCompactContext(sessionName, now) {
|
|
|
23701
22680
|
if (!agentState?.workspace || !sessionId || !agentState.model) return null;
|
|
23702
22681
|
let usage = null;
|
|
23703
22682
|
try {
|
|
23704
|
-
const { computeContextUsage } = await import("./conversation-service-
|
|
22683
|
+
const { computeContextUsage } = await import("./conversation-service-C_kNZPLx.js");
|
|
23705
22684
|
usage = await computeContextUsage(sessionFilePath(agentState.workspace, sessionId), agentState.model);
|
|
23706
22685
|
} catch {
|
|
23707
22686
|
return null;
|
|
@@ -23798,13 +22777,13 @@ async function checkApiErrorAgents() {
|
|
|
23798
22777
|
const st = getAgentStateSync(sessionName);
|
|
23799
22778
|
const sid = st?.sessionId ?? runtimeState?.claudeSessionId;
|
|
23800
22779
|
if (st?.workspace && sid && st.model) {
|
|
23801
|
-
const { computeContextUsage } = await import("./conversation-service-
|
|
22780
|
+
const { computeContextUsage } = await import("./conversation-service-C_kNZPLx.js");
|
|
23802
22781
|
const usage = await computeContextUsage(sessionFilePath(st.workspace, sid), st.model);
|
|
23803
22782
|
if (usage && usage.percentUsed < 85) recoveredPct = usage.percentUsed;
|
|
23804
22783
|
}
|
|
23805
22784
|
} catch {}
|
|
23806
22785
|
if (recoveredPct !== null) {
|
|
23807
|
-
const { clearWorkspaceStuck } = await import("./review-status-sync-
|
|
22786
|
+
const { clearWorkspaceStuck } = await import("./review-status-sync-D3KUhsdA.js");
|
|
23808
22787
|
clearWorkspaceStuck(issueId);
|
|
23809
22788
|
stuckOverflowNativeRecoveryState.delete(sessionName);
|
|
23810
22789
|
actions.push(`Context overflow recovery: cleared stuck flag for ${sessionName} (context back to ${Math.round(recoveredPct)}%)`);
|
|
@@ -23820,7 +22799,7 @@ async function checkApiErrorAgents() {
|
|
|
23820
22799
|
rec.attempts += 1;
|
|
23821
22800
|
rec.lastAttempt = now;
|
|
23822
22801
|
stuckOverflowNativeRecoveryState.set(sessionName, rec);
|
|
23823
|
-
const { resumeAgent } = await import("./agents-
|
|
22802
|
+
const { resumeAgent } = await import("./agents-DCvyTXNU.js");
|
|
23824
22803
|
const recovered = await resumeAgent(sessionName, void 0, { compact: true });
|
|
23825
22804
|
if (recovered.success) {
|
|
23826
22805
|
stuckOverflowNativeRecoveryState.delete(sessionName);
|
|
@@ -23868,7 +22847,7 @@ async function checkApiErrorAgents() {
|
|
|
23868
22847
|
}
|
|
23869
22848
|
const compactAttempts = (ov?.compactAttempts ?? 0) + 1;
|
|
23870
22849
|
if (issueId !== null) {
|
|
23871
|
-
const { resumeAgent } = await import("./agents-
|
|
22850
|
+
const { resumeAgent } = await import("./agents-DCvyTXNU.js");
|
|
23872
22851
|
const resumeResult = await resumeAgent(sessionName, void 0, { compact: true });
|
|
23873
22852
|
contextOverflowRecoveryState.set(sessionName, {
|
|
23874
22853
|
lastAttempt: now,
|
|
@@ -23943,8 +22922,8 @@ async function checkApiErrorAgents() {
|
|
|
23943
22922
|
}
|
|
23944
22923
|
//#endregion
|
|
23945
22924
|
//#region ../../lib/cloister/preemption.ts
|
|
23946
|
-
init_specialists();
|
|
23947
22925
|
init_review_monitor();
|
|
22926
|
+
init_specialists();
|
|
23948
22927
|
/**
|
|
23949
22928
|
* PAN-2507: preemptive pipeline scheduler.
|
|
23950
22929
|
*
|
|
@@ -24115,6 +23094,8 @@ async function resumeYieldedVictim(agentId) {
|
|
|
24115
23094
|
init_archive_planning();
|
|
24116
23095
|
init_issue_closed();
|
|
24117
23096
|
init_merge_verification();
|
|
23097
|
+
init_state_mapping();
|
|
23098
|
+
init_tracker_utils();
|
|
24118
23099
|
const execFileAsync$5 = promisify$1(execFile$1);
|
|
24119
23100
|
const autoCloseOutCache = /* @__PURE__ */ new Map();
|
|
24120
23101
|
const AUTO_CLOSE_OUT_CACHE_TTL_MS = 600 * 1e3;
|
|
@@ -24233,7 +23214,7 @@ function reviewConvoyLiveness(issueId) {
|
|
|
24233
23214
|
*/
|
|
24234
23215
|
async function recoverUnhealthyTestStack(issueId, workspacePath) {
|
|
24235
23216
|
const key = issueId.toUpperCase();
|
|
24236
|
-
const { getWorkspaceStackHealth } = await import("./stack-health-
|
|
23217
|
+
const { getWorkspaceStackHealth } = await import("./stack-health-Dclm7_tu.js");
|
|
24237
23218
|
const health = await Effect.runPromise(getWorkspaceStackHealth(issueId, { workspacePath }));
|
|
24238
23219
|
if (health.healthy) {
|
|
24239
23220
|
testStackRebuildState.delete(key);
|
|
@@ -24265,7 +23246,7 @@ async function recoverUnhealthyTestStack(issueId, workspacePath) {
|
|
|
24265
23246
|
record.attempts += 1;
|
|
24266
23247
|
testStackRebuildState.set(key, record);
|
|
24267
23248
|
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-
|
|
23249
|
+
const { rebuildWorkspaceStack } = await import("./rebuild-stack-GOsWqXi3.js");
|
|
24269
23250
|
const result = await Effect.runPromise(rebuildWorkspaceStack(issueId, { onProgress: (m) => console.log(`[deacon] ${key} stack rebuild: ${m}`) }));
|
|
24270
23251
|
if (!result.success) {
|
|
24271
23252
|
console.warn(`[deacon] Test stack rebuild failed for ${key}: ${result.error}`);
|
|
@@ -24393,7 +23374,7 @@ async function handleReviewCoordinatorDied(issueId, _sessionName, _reason) {
|
|
|
24393
23374
|
return actions;
|
|
24394
23375
|
}
|
|
24395
23376
|
try {
|
|
24396
|
-
const { spawnReviewRoleForIssue } = await import("./review-agent-
|
|
23377
|
+
const { spawnReviewRoleForIssue } = await import("./review-agent-Rub0OpZc.js");
|
|
24397
23378
|
const dispatchResult = await Effect.runPromise(spawnReviewRoleForIssue({
|
|
24398
23379
|
issueId,
|
|
24399
23380
|
workspace,
|
|
@@ -24523,7 +23504,7 @@ async function reconcileReviewStatusOrphan(issueId, rawStatus) {
|
|
|
24523
23504
|
const workspace = agentState?.workspace || (resolved ? findWorkspacePath(resolved.projectPath, issueLower) : null);
|
|
24524
23505
|
if (workspace && resolved && !tryReserveAdvancingSlot() && !await tryYieldForAdvancingDispatch("review", issueId)) actions.push(`Deferred review re-dispatch for ${issueId} — advancing-role concurrency ceiling reached`);
|
|
24525
23506
|
else if (workspace && resolved) try {
|
|
24526
|
-
const { spawnReviewRoleForIssue } = await import("./review-agent-
|
|
23507
|
+
const { spawnReviewRoleForIssue } = await import("./review-agent-Rub0OpZc.js");
|
|
24527
23508
|
const dispatchResult = await Effect.runPromise(spawnReviewRoleForIssue({
|
|
24528
23509
|
issueId,
|
|
24529
23510
|
workspace,
|
|
@@ -24548,8 +23529,8 @@ async function reconcileReviewStatusOrphan(issueId, rawStatus) {
|
|
|
24548
23529
|
const workspace = agentState?.workspace || (resolved ? findWorkspacePath(resolved.projectPath, issueLower) : null);
|
|
24549
23530
|
if (workspace && resolved) {
|
|
24550
23531
|
const branch = `feature/${issueLower}`;
|
|
24551
|
-
const { spawnRun } = await import("./agents-
|
|
24552
|
-
const { buildTestRolePrompt } = await import("./test-agent-queue-
|
|
23532
|
+
const { spawnRun } = await import("./agents-DCvyTXNU.js");
|
|
23533
|
+
const { buildTestRolePrompt } = await import("./test-agent-queue-DjsQoV5X.js");
|
|
24553
23534
|
const stackRecovery = await recoverUnhealthyTestStack(issueId, workspace);
|
|
24554
23535
|
if (stackRecovery === "cooldown" || stackRecovery === "exhausted") {
|
|
24555
23536
|
setReviewStatusSync(issueId, { testStatus: "dispatch_failed" });
|
|
@@ -24687,7 +23668,7 @@ async function recoverStalledReviewConvoys(getCanonicalState = getAutoCloseOutCa
|
|
|
24687
23668
|
record.lastAttempt = now;
|
|
24688
23669
|
record.attempts += 1;
|
|
24689
23670
|
stalledReviewConvoyRecoveryState.set(key, record);
|
|
24690
|
-
const { spawnReviewRoleForIssue } = await import("./review-agent-
|
|
23671
|
+
const { spawnReviewRoleForIssue } = await import("./review-agent-Rub0OpZc.js");
|
|
24691
23672
|
try {
|
|
24692
23673
|
const result = await Effect.runPromise(spawnReviewRoleForIssue({
|
|
24693
23674
|
issueId,
|
|
@@ -24758,7 +23739,7 @@ async function checkMissingReviewStatuses() {
|
|
|
24758
23739
|
continue;
|
|
24759
23740
|
}
|
|
24760
23741
|
try {
|
|
24761
|
-
const { spawnReviewRoleForIssue } = await import("./review-agent-
|
|
23742
|
+
const { spawnReviewRoleForIssue } = await import("./review-agent-Rub0OpZc.js");
|
|
24762
23743
|
await Effect.runPromise(spawnReviewRoleForIssue({
|
|
24763
23744
|
issueId,
|
|
24764
23745
|
workspace,
|
|
@@ -24809,7 +23790,7 @@ async function checkStuckReviewing() {
|
|
|
24809
23790
|
const actions = [];
|
|
24810
23791
|
const REVIEW_STUCK_THRESHOLD_MS = 1800 * 1e3;
|
|
24811
23792
|
try {
|
|
24812
|
-
const { loadReviewStatuses, setReviewStatusSync } = await import("./review-status-
|
|
23793
|
+
const { loadReviewStatuses, setReviewStatusSync } = await import("./review-status-Br6lAFGO.js");
|
|
24813
23794
|
const statuses = loadReviewStatuses();
|
|
24814
23795
|
const now = Date.now();
|
|
24815
23796
|
const activeReviewIssues = /* @__PURE__ */ new Set();
|
|
@@ -24825,7 +23806,7 @@ async function checkStuckReviewing() {
|
|
|
24825
23806
|
if (rState?.state === "active" && rState.currentIssue) activeReviewIssues.add(rState.currentIssue.toUpperCase());
|
|
24826
23807
|
}
|
|
24827
23808
|
try {
|
|
24828
|
-
const { listRunningAgents } = await import("./agents-
|
|
23809
|
+
const { listRunningAgents } = await import("./agents-DCvyTXNU.js");
|
|
24829
23810
|
const agents = await Effect.runPromise(listRunningAgents());
|
|
24830
23811
|
for (const agent of agents) {
|
|
24831
23812
|
if (agent.status === "stopped" || agent.status === "error") continue;
|
|
@@ -24958,7 +23939,7 @@ async function checkCompletedButUnsignaledReviews() {
|
|
|
24958
23939
|
}
|
|
24959
23940
|
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
23941
|
try {
|
|
24961
|
-
const { messageAgent } = await import("./agents-
|
|
23942
|
+
const { messageAgent } = await import("./agents-DCvyTXNU.js");
|
|
24962
23943
|
await messageAgent(reviewSession, nudge);
|
|
24963
23944
|
unsignaledReviewNudges.set(latestDir, now);
|
|
24964
23945
|
actions.push(`Nudged ${reviewSession} to signal ${verdict} (synthesis written ${Math.round((now - latestMtime) / 6e4)}min ago)`);
|
|
@@ -25079,7 +24060,7 @@ async function respawnIdleReviewer(state, agentId) {
|
|
|
25079
24060
|
return false;
|
|
25080
24061
|
}
|
|
25081
24062
|
try {
|
|
25082
|
-
const { spawnReviewSubRoleForIssue } = await import("./review-agent-
|
|
24063
|
+
const { spawnReviewSubRoleForIssue } = await import("./review-agent-Rub0OpZc.js");
|
|
25083
24064
|
const contextManifestPath = join$1(dirname$1(outputPath), "context.json");
|
|
25084
24065
|
const result = await Effect.runPromise(spawnReviewSubRoleForIssue({
|
|
25085
24066
|
issueId: state.issueId,
|
|
@@ -25117,7 +24098,7 @@ async function nudgeSynthesisForCompleteReviewerReports(states) {
|
|
|
25117
24098
|
const status = getReviewStatusSync(state.issueId);
|
|
25118
24099
|
if (!status || status.reviewStatus !== "reviewing") continue;
|
|
25119
24100
|
const reviewDir = join$1(state.workspace, ".pan", "review", state.reviewRunId);
|
|
25120
|
-
|
|
24101
|
+
const synthesisAlreadyWritten = existsSync(join$1(reviewDir, "synthesis.md"));
|
|
25121
24102
|
const startedMs = Date.parse(state.startedAt);
|
|
25122
24103
|
const readyLines = [];
|
|
25123
24104
|
const reports = [];
|
|
@@ -25156,7 +24137,7 @@ async function nudgeSynthesisForCompleteReviewerReports(states) {
|
|
|
25156
24137
|
if (lastNudge && now - lastNudge < REVIEW_REPORTS_PRESENT_NUDGE_COOLDOWN_MS) continue;
|
|
25157
24138
|
const sessionAlive = await Effect.runPromise(sessionExists(state.id)).catch(() => false);
|
|
25158
24139
|
const paneDead = sessionAlive ? await Effect.runPromise(isPaneDead(state.id)).catch(() => true) : true;
|
|
25159
|
-
if (lastNudge || !sessionAlive || paneDead) {
|
|
24140
|
+
if (synthesisAlreadyWritten || lastNudge || !sessionAlive || paneDead) {
|
|
25160
24141
|
const synthesis = synthesizeReviewFromReports({
|
|
25161
24142
|
issueId: state.issueId,
|
|
25162
24143
|
reviewDir,
|
|
@@ -25208,7 +24189,7 @@ async function nudgeSynthesisForCompleteReviewerReports(states) {
|
|
|
25208
24189
|
"Read the four reports, write synthesis.md, then signal review status exactly as roles/review.md instructs."
|
|
25209
24190
|
].join("\n");
|
|
25210
24191
|
try {
|
|
25211
|
-
const { messageAgent } = await import("./agents-
|
|
24192
|
+
const { messageAgent } = await import("./agents-DCvyTXNU.js");
|
|
25212
24193
|
await messageAgent(state.id, message);
|
|
25213
24194
|
reviewReportsPresentNudges.set(nudgeKey, now);
|
|
25214
24195
|
const action = `Nudged ${state.id} to synthesize from ${REVIEW_SUB_ROLES.length} reviewer reports`;
|
|
@@ -25287,7 +24268,7 @@ async function monitorReviewConvoySignals() {
|
|
|
25287
24268
|
if (!signal) continue;
|
|
25288
24269
|
const message = signal === "ready" ? `REVIEWER_READY ${state.reviewSubRole} ${outputPath}` : signal === "timeout" ? `REVIEWER_TIMEOUT ${state.reviewSubRole} ${reason}` : `REVIEWER_FAILED ${state.reviewSubRole} ${reason}`;
|
|
25289
24270
|
try {
|
|
25290
|
-
const { messageAgent } = await import("./agents-
|
|
24271
|
+
const { messageAgent } = await import("./agents-DCvyTXNU.js");
|
|
25291
24272
|
await messageAgent(state.reviewSynthesisAgentId, message);
|
|
25292
24273
|
state.reviewMonitorSignaled = signal;
|
|
25293
24274
|
saveAgentStateSync(state);
|
|
@@ -25295,7 +24276,7 @@ async function monitorReviewConvoySignals() {
|
|
|
25295
24276
|
actions.push(action);
|
|
25296
24277
|
logDeaconEventSync(`monitorReviewConvoySignals: ${action}`);
|
|
25297
24278
|
if (signal === "ready") try {
|
|
25298
|
-
const { notifyPipelineSync } = await import("./pipeline-notifier-
|
|
24279
|
+
const { notifyPipelineSync } = await import("./pipeline-notifier-BkKbQ8ji.js");
|
|
25299
24280
|
notifyPipelineSync({
|
|
25300
24281
|
type: "reviewer_completed",
|
|
25301
24282
|
issueId: state.issueId,
|
|
@@ -25303,7 +24284,7 @@ async function monitorReviewConvoySignals() {
|
|
|
25303
24284
|
});
|
|
25304
24285
|
} catch {}
|
|
25305
24286
|
else if (signal === "timeout") try {
|
|
25306
|
-
const { notifyPipelineSync } = await import("./pipeline-notifier-
|
|
24287
|
+
const { notifyPipelineSync } = await import("./pipeline-notifier-BkKbQ8ji.js");
|
|
25307
24288
|
notifyPipelineSync({
|
|
25308
24289
|
type: "reviewer_timed_out",
|
|
25309
24290
|
issueId: state.issueId,
|
|
@@ -25403,7 +24384,7 @@ const FORK_CACHE_CHECK_DELAY_MS = 180 * 1e3;
|
|
|
25403
24384
|
async function checkStalledReviewDiscovery() {
|
|
25404
24385
|
const actions = [];
|
|
25405
24386
|
try {
|
|
25406
|
-
const { listAgentStates } = await import("./agents-
|
|
24387
|
+
const { listAgentStates } = await import("./agents-DCvyTXNU.js");
|
|
25407
24388
|
const states = listAgentStates();
|
|
25408
24389
|
const now = Date.now();
|
|
25409
24390
|
for (const state of states) {
|
|
@@ -25412,7 +24393,7 @@ async function checkStalledReviewDiscovery() {
|
|
|
25412
24393
|
const aged = Number.isFinite(startedMs) && now - startedMs > 48e4;
|
|
25413
24394
|
const dead = !await Effect.runPromise(sessionExists(state.id)).catch(() => false) || await Effect.runPromise(isPaneDead(state.id)).catch(() => true);
|
|
25414
24395
|
if (!aged && !dead) continue;
|
|
25415
|
-
const { handleReviewDiscoveryReady } = await import("./review-agent-
|
|
24396
|
+
const { handleReviewDiscoveryReady } = await import("./review-agent-Rub0OpZc.js");
|
|
25416
24397
|
const result = await handleReviewDiscoveryReady(state.issueId, { source: dead ? "deacon-backstop (parent dead)" : "deacon-backstop (discovery timeout)" });
|
|
25417
24398
|
actions.push(result.message);
|
|
25418
24399
|
logDeaconEventSync(`checkStalledReviewDiscovery: ${result.message}`);
|
|
@@ -25435,8 +24416,8 @@ async function checkStalledReviewDiscovery() {
|
|
|
25435
24416
|
async function checkStalledReviewParents() {
|
|
25436
24417
|
const actions = [];
|
|
25437
24418
|
try {
|
|
25438
|
-
const { listAgentStates, markAgentStoppedState } = await import("./agents-
|
|
25439
|
-
const { PARENT_REVIEW_TIMEOUT_MS } = await import("./review-agent-
|
|
24419
|
+
const { listAgentStates, markAgentStoppedState } = await import("./agents-DCvyTXNU.js");
|
|
24420
|
+
const { PARENT_REVIEW_TIMEOUT_MS } = await import("./review-agent-Rub0OpZc.js");
|
|
25440
24421
|
const states = listAgentStates();
|
|
25441
24422
|
const now = Date.now();
|
|
25442
24423
|
for (const state of states) {
|
|
@@ -25485,8 +24466,8 @@ async function checkStalledReviewParents() {
|
|
|
25485
24466
|
async function checkReviewForkCacheMisses() {
|
|
25486
24467
|
const actions = [];
|
|
25487
24468
|
try {
|
|
25488
|
-
const { listAgentStates, saveAgentState } = await import("./agents-
|
|
25489
|
-
const { readEventsSync } = await import("./events-
|
|
24469
|
+
const { listAgentStates, saveAgentState } = await import("./agents-DCvyTXNU.js");
|
|
24470
|
+
const { readEventsSync } = await import("./events-CtsLScn8.js");
|
|
25490
24471
|
const { emitActivityEntrySync } = await import("./activity-logger-DvYvFhwZ.js");
|
|
25491
24472
|
const states = listAgentStates();
|
|
25492
24473
|
const now = Date.now();
|
|
@@ -25633,7 +24614,7 @@ async function reconcileStaleMergeStatus() {
|
|
|
25633
24614
|
if (!project) continue;
|
|
25634
24615
|
let specStatus;
|
|
25635
24616
|
try {
|
|
25636
|
-
const { findSpecByIssue } = await import("./specs-
|
|
24617
|
+
const { findSpecByIssue } = await import("./specs-DwoAEGrW.js");
|
|
25637
24618
|
const spec = await Effect.runPromise(findSpecByIssue(project.projectPath, issueId));
|
|
25638
24619
|
specStatus = spec?.status;
|
|
25639
24620
|
if (spec && (spec.status === "completed" || spec.status === "cancelled")) {
|
|
@@ -25648,7 +24629,7 @@ async function reconcileStaleMergeStatus() {
|
|
|
25648
24629
|
if (branchTip.stdout.trim() === mainTip.stdout.trim()) console.log(`[deacon] ${issueId}: branch ${branch} points at main; not treating zero-commit branch as merged`);
|
|
25649
24630
|
} catch {}
|
|
25650
24631
|
if (!isMerged) {
|
|
25651
|
-
const { resolveGitHubIssueSync: _resolveGitHubIssue } = await import("./tracker-utils-
|
|
24632
|
+
const { resolveGitHubIssueSync: _resolveGitHubIssue } = await import("./tracker-utils-B9ZoVA9b.js");
|
|
25652
24633
|
const ghResolved = _resolveGitHubIssue(issueId);
|
|
25653
24634
|
if (ghResolved.isGitHub) try {
|
|
25654
24635
|
const { stdout } = await execFileAsync$4("gh", [
|
|
@@ -25685,7 +24666,7 @@ async function reconcileStaleMergeStatus() {
|
|
|
25685
24666
|
actions.push(msg);
|
|
25686
24667
|
console.log(`[deacon] ${msg}`);
|
|
25687
24668
|
try {
|
|
25688
|
-
const { postMergeLifecycle } = await import("./merge-agent-
|
|
24669
|
+
const { postMergeLifecycle } = await import("./merge-agent-36wfYm2u.js");
|
|
25689
24670
|
postMergeLifecycle(issueId, project.projectPath, branch, { skipDeploy: true }).catch((err) => console.warn(`[deacon] postMergeLifecycle (reconcile) failed for ${issueId}: ${err}`));
|
|
25690
24671
|
} catch (err) {
|
|
25691
24672
|
console.warn(`[deacon] Could not import postMergeLifecycle: ${err}`);
|
|
@@ -25710,7 +24691,7 @@ const falseMergedReset = /* @__PURE__ */ new Set();
|
|
|
25710
24691
|
async function reconcileFalseMerged() {
|
|
25711
24692
|
const actions = [];
|
|
25712
24693
|
try {
|
|
25713
|
-
const { getPullRequestState, isGitHubAppConfigured } = await import("./github-app-
|
|
24694
|
+
const { getPullRequestState, isGitHubAppConfigured } = await import("./github-app-DRD2woO0.js");
|
|
25714
24695
|
if (!isGitHubAppConfigured()) return actions;
|
|
25715
24696
|
const statuses = loadReviewStatuses();
|
|
25716
24697
|
for (const [issueId, status] of Object.entries(statuses)) {
|
|
@@ -25755,7 +24736,7 @@ const CLOSED_PR_RECONCILE_COOLDOWN_MS = 600 * 1e3;
|
|
|
25755
24736
|
async function reconcileClosedPrReadyForMerge() {
|
|
25756
24737
|
const actions = [];
|
|
25757
24738
|
try {
|
|
25758
|
-
const { getPullRequestState, isGitHubAppConfigured } = await import("./github-app-
|
|
24739
|
+
const { getPullRequestState, isGitHubAppConfigured } = await import("./github-app-DRD2woO0.js");
|
|
25759
24740
|
if (!isGitHubAppConfigured()) return actions;
|
|
25760
24741
|
const statuses = loadReviewStatuses();
|
|
25761
24742
|
const now = Date.now();
|
|
@@ -25827,7 +24808,7 @@ const STALE_MERGE_BLOCKER_COOLDOWN_MS = 120 * 1e3;
|
|
|
25827
24808
|
async function reconcileStaleMergeBlockers() {
|
|
25828
24809
|
const actions = [];
|
|
25829
24810
|
try {
|
|
25830
|
-
const { resolveConflictGate, buildRealConflictGateDeps } = await import("./conflict-gate-
|
|
24811
|
+
const { resolveConflictGate, buildRealConflictGateDeps } = await import("./conflict-gate-DGT8jCLp.js");
|
|
25831
24812
|
const statuses = loadReviewStatuses();
|
|
25832
24813
|
const now = Date.now();
|
|
25833
24814
|
const deps = buildRealConflictGateDeps();
|
|
@@ -25970,7 +24951,7 @@ async function checkFailedMergeRetry() {
|
|
|
25970
24951
|
if (ciEntry.count === 5) {
|
|
25971
24952
|
console.log(`[deacon] CI check failure for ${issueId} — retries exhausted, notifying work agent`);
|
|
25972
24953
|
const ciNotes = status.mergeNotes || "CI checks are failing on the PR";
|
|
25973
|
-
const { writeFeedbackFile } = await import("./feedback-writer-
|
|
24954
|
+
const { writeFeedbackFile } = await import("./feedback-writer-DOUhyIW2.js");
|
|
25974
24955
|
const ciFileResult = await Effect.runPromise(writeFeedbackFile({
|
|
25975
24956
|
issueId,
|
|
25976
24957
|
specialist: "merge-agent",
|
|
@@ -26002,7 +24983,7 @@ async function checkFailedMergeRetry() {
|
|
|
26002
24983
|
ciRetryMap.set(issueId, ciEntry);
|
|
26003
24984
|
console.log(`[deacon] CI check failure for ${issueId} — notifying agent to re-submit (attempt ${ciEntry.count}/5)`);
|
|
26004
24985
|
const ciNotes = status.mergeNotes || "CI checks are failing on the PR";
|
|
26005
|
-
const { writeFeedbackFile } = await import("./feedback-writer-
|
|
24986
|
+
const { writeFeedbackFile } = await import("./feedback-writer-DOUhyIW2.js");
|
|
26006
24987
|
const ciFileResult2 = await Effect.runPromise(writeFeedbackFile({
|
|
26007
24988
|
issueId,
|
|
26008
24989
|
specialist: "merge-agent",
|
|
@@ -26030,7 +25011,7 @@ async function checkFailedMergeRetry() {
|
|
|
26030
25011
|
const lastNudge = timeoutNudgeCooldowns.get(issueIdForFb);
|
|
26031
25012
|
if (!lastNudge || now - lastNudge >= TIMEOUT_NUDGE_COOLDOWN_MS) {
|
|
26032
25013
|
const timeoutNotes = status.mergeNotes;
|
|
26033
|
-
const { writeFeedbackFile } = await import("./feedback-writer-
|
|
25014
|
+
const { writeFeedbackFile } = await import("./feedback-writer-DOUhyIW2.js");
|
|
26034
25015
|
await Effect.runPromise(writeFeedbackFile({
|
|
26035
25016
|
issueId: issueIdForFb,
|
|
26036
25017
|
specialist: "merge-agent",
|
|
@@ -26135,7 +25116,7 @@ async function autoCloseOut(now = /* @__PURE__ */ new Date()) {
|
|
|
26135
25116
|
} } : {}
|
|
26136
25117
|
};
|
|
26137
25118
|
try {
|
|
26138
|
-
const { closeOut } = await import("./workflows-
|
|
25119
|
+
const { closeOut } = await import("./workflows-tU7KKxQi.js");
|
|
26139
25120
|
const result = await Effect.runPromise(closeOut(ctx));
|
|
26140
25121
|
if (!result.success) {
|
|
26141
25122
|
const failed = result.steps.find((step) => !step.success && !step.skipped);
|
|
@@ -26285,6 +25266,7 @@ function skippedBootReconciliationOutcomes(agents, reason) {
|
|
|
26285
25266
|
}
|
|
26286
25267
|
//#endregion
|
|
26287
25268
|
//#region ../../lib/cloister/boot-reconciliation-predicates.ts
|
|
25269
|
+
init_control_settings();
|
|
26288
25270
|
init_no_resume_mode();
|
|
26289
25271
|
init_agent_state();
|
|
26290
25272
|
init_review_status();
|
|
@@ -26438,6 +25420,7 @@ init_review_status();
|
|
|
26438
25420
|
init_control_settings();
|
|
26439
25421
|
init_agents$1();
|
|
26440
25422
|
init_tmux();
|
|
25423
|
+
init_beads_query();
|
|
26441
25424
|
const orphanFailureRecordedForAutoResume = /* @__PURE__ */ new Set();
|
|
26442
25425
|
const appliedBootReconciliationDecisions = /* @__PURE__ */ new Set();
|
|
26443
25426
|
const emptyBootReconciliationApplyResult = () => ({
|
|
@@ -26697,7 +25680,7 @@ async function nudgeStalledResumeWorkAgents() {
|
|
|
26697
25680
|
const message = buildStalledResumePrompt(state);
|
|
26698
25681
|
if (!message) continue;
|
|
26699
25682
|
try {
|
|
26700
|
-
const { messageAgent } = await import("./agents-
|
|
25683
|
+
const { messageAgent } = await import("./agents-DCvyTXNU.js");
|
|
26701
25684
|
await messageAgent(agentId, message);
|
|
26702
25685
|
recordCooldown(agentId, ".last-stalled-resume-nudge");
|
|
26703
25686
|
const action = `Re-sent stalled resume prompt to ${agentId} (${state.issueId})`;
|
|
@@ -26812,10 +25795,10 @@ async function nudgeIdleWorkAgentsWithOpenBeads() {
|
|
|
26812
25795
|
``,
|
|
26813
25796
|
`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
25797
|
``,
|
|
26815
|
-
"Continue the per-bead workflow without asking — claim it (`
|
|
25798
|
+
"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
25799
|
].join("\n");
|
|
26817
25800
|
try {
|
|
26818
|
-
const { messageAgent } = await import("./agents-
|
|
25801
|
+
const { messageAgent } = await import("./agents-DCvyTXNU.js");
|
|
26819
25802
|
await messageAgent(agentId, message);
|
|
26820
25803
|
writeFileSync(join$1(getAgentDir(agentId), ".last-bead-nudge"), String(Date.now()), "utf-8");
|
|
26821
25804
|
const action = `Nudged idle ${agentId} (${state.issueId}) — ${openBeads.length} open bead(s)`;
|
|
@@ -27137,6 +26120,7 @@ function createInFlightGuard() {
|
|
|
27137
26120
|
}
|
|
27138
26121
|
//#endregion
|
|
27139
26122
|
//#region ../../lib/pipeline-state-paths.ts
|
|
26123
|
+
init_state_plane();
|
|
27140
26124
|
const execFileAsync$3 = promisify$1(execFile$1);
|
|
27141
26125
|
const STATE_PLANE_DIFF_EXCLUDES = STATE_PLANE_PATHS.map((path) => `:(exclude)${path.replace(/\/$/, "")}`);
|
|
27142
26126
|
function isPipelineStatePath(relativePath) {
|
|
@@ -27246,6 +26230,9 @@ async function gitStdout(workspacePath, args) {
|
|
|
27246
26230
|
}
|
|
27247
26231
|
//#endregion
|
|
27248
26232
|
//#region ../../lib/cloister/state-recreation-patrol.ts
|
|
26233
|
+
init_auto_commit();
|
|
26234
|
+
init_record();
|
|
26235
|
+
init_state_home();
|
|
27249
26236
|
async function recreatedStateWarnings(projects) {
|
|
27250
26237
|
const warnings = [];
|
|
27251
26238
|
for (const { config } of projects) {
|
|
@@ -27257,6 +26244,7 @@ async function recreatedStateWarnings(projects) {
|
|
|
27257
26244
|
}
|
|
27258
26245
|
//#endregion
|
|
27259
26246
|
//#region ../../lib/cloister/deacon-main-divergence.ts
|
|
26247
|
+
init_record_lock();
|
|
27260
26248
|
init_projects();
|
|
27261
26249
|
init_state_plane();
|
|
27262
26250
|
async function recordMainDivergenceHealth(state, projects = listProjectsSync(), measure = getMainDivergence) {
|
|
@@ -27289,427 +26277,6 @@ async function recordMainDivergenceHealth(state, projects = listProjectsSync(),
|
|
|
27289
26277
|
return warnings;
|
|
27290
26278
|
}
|
|
27291
26279
|
//#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
26280
|
//#region ../../lib/backlog/label-ops.ts
|
|
27714
26281
|
init_tracker_utils();
|
|
27715
26282
|
const execAsync$3 = promisify(exec);
|
|
@@ -28608,8 +27175,8 @@ async function cleanupStaleAgentState() {
|
|
|
28608
27175
|
*/
|
|
28609
27176
|
async function cleanupAbandonedFeedback() {
|
|
28610
27177
|
const actions = [];
|
|
28611
|
-
const { getReviewStatusSync } = await import("./review-status-
|
|
28612
|
-
const { clearFeedbackFiles } = await import("./feedback-writer-
|
|
27178
|
+
const { getReviewStatusSync } = await import("./review-status-Br6lAFGO.js");
|
|
27179
|
+
const { clearFeedbackFiles } = await import("./feedback-writer-DOUhyIW2.js");
|
|
28613
27180
|
for (const { issueId, workspacePath } of listFeatureWorkspaces()) {
|
|
28614
27181
|
const panFeedbackDir = join$1(workspacePath, ".pan", "feedback");
|
|
28615
27182
|
if (!existsSync(panFeedbackDir)) continue;
|
|
@@ -28680,7 +27247,7 @@ async function handleOrphanReviewerSession(sessionName, sessions, creationTimes,
|
|
|
28680
27247
|
if (!issueId) return null;
|
|
28681
27248
|
const agentSession = `agent-${issueId.toLowerCase()}`;
|
|
28682
27249
|
if (sessions.includes(agentSession)) return null;
|
|
28683
|
-
const { getReviewStatusSync } = await import("./review-status-
|
|
27250
|
+
const { getReviewStatusSync } = await import("./review-status-Br6lAFGO.js");
|
|
28684
27251
|
try {
|
|
28685
27252
|
if (getReviewStatusSync(issueId)?.reviewStatus === "reviewing") return null;
|
|
28686
27253
|
} catch {}
|
|
@@ -28800,7 +27367,7 @@ async function checkOrphanedCompletions() {
|
|
|
28800
27367
|
async function checkPendingTestDispatch() {
|
|
28801
27368
|
const actions = [];
|
|
28802
27369
|
try {
|
|
28803
|
-
const { loadReviewStatuses, setReviewStatusSync } = await import("./review-status-
|
|
27370
|
+
const { loadReviewStatuses, setReviewStatusSync } = await import("./review-status-Br6lAFGO.js");
|
|
28804
27371
|
const statuses = loadReviewStatuses();
|
|
28805
27372
|
const now = Date.now();
|
|
28806
27373
|
for (const [issueId, status] of Object.entries(statuses)) {
|
|
@@ -28833,7 +27400,7 @@ async function checkPendingTestDispatch() {
|
|
|
28833
27400
|
console.log(`[deacon] ${issueId}: skipping test re-dispatch — issue is closed`);
|
|
28834
27401
|
continue;
|
|
28835
27402
|
}
|
|
28836
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
27403
|
+
const { resolveProjectFromIssueSync } = await import("./projects-KJ94e50I.js");
|
|
28837
27404
|
const resolved = resolveProjectFromIssueSync(issueId);
|
|
28838
27405
|
if (!resolved) continue;
|
|
28839
27406
|
const issueLower = issueId.toLowerCase();
|
|
@@ -28848,8 +27415,8 @@ async function checkPendingTestDispatch() {
|
|
|
28848
27415
|
logDeaconEventSync(`checkPendingTestDispatch: deferred test for ${issueId} — advancing ceiling reached (PAN-1665) — ${describeRunningAgents()}`);
|
|
28849
27416
|
continue;
|
|
28850
27417
|
}
|
|
28851
|
-
const { spawnRun } = await import("./agents-
|
|
28852
|
-
const { buildTestRolePrompt } = await import("./test-agent-queue-
|
|
27418
|
+
const { spawnRun } = await import("./agents-DCvyTXNU.js");
|
|
27419
|
+
const { buildTestRolePrompt } = await import("./test-agent-queue-DjsQoV5X.js");
|
|
28853
27420
|
try {
|
|
28854
27421
|
const run = await spawnRun(issueId, "test", {
|
|
28855
27422
|
workspace,
|
|
@@ -28972,7 +27539,7 @@ async function checkCompletedButUnsignaledTests() {
|
|
|
28972
27539
|
const cmd = `pan admin specialists done test ${issueId} --status ${decision.status}${noteArg}`;
|
|
28973
27540
|
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
27541
|
try {
|
|
28975
|
-
const { messageAgent } = await import("./agents-
|
|
27542
|
+
const { messageAgent } = await import("./agents-DCvyTXNU.js");
|
|
28976
27543
|
await messageAgent(testSession, nudge);
|
|
28977
27544
|
unsignaledTestNudges.set(testSession, now);
|
|
28978
27545
|
const msg = `Nudged ${testSession} to signal ${decision.status} (verdict artifact present)`;
|
|
@@ -28986,7 +27553,7 @@ async function checkCompletedButUnsignaledTests() {
|
|
|
28986
27553
|
case "nudge-write": {
|
|
28987
27554
|
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
27555
|
try {
|
|
28989
|
-
const { messageAgent } = await import("./agents-
|
|
27556
|
+
const { messageAgent } = await import("./agents-DCvyTXNU.js");
|
|
28990
27557
|
await messageAgent(testSession, nudge);
|
|
28991
27558
|
unsignaledTestNudges.set(testSession, now);
|
|
28992
27559
|
const msg = `Nudged ${testSession} to write+signal a test verdict (no artifact yet)`;
|
|
@@ -29009,8 +27576,8 @@ async function checkCompletedButUnsignaledTests() {
|
|
|
29009
27576
|
async function checkVerificationReviewContradiction() {
|
|
29010
27577
|
const actions = [];
|
|
29011
27578
|
try {
|
|
29012
|
-
const { loadReviewStatuses, setReviewStatusSync } = await import("./review-status-
|
|
29013
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
27579
|
+
const { loadReviewStatuses, setReviewStatusSync } = await import("./review-status-Br6lAFGO.js");
|
|
27580
|
+
const { resolveProjectFromIssueSync } = await import("./projects-KJ94e50I.js");
|
|
29014
27581
|
const statuses = loadReviewStatuses();
|
|
29015
27582
|
for (const [issueId, status] of Object.entries(statuses)) if (status.verificationStatus === "passed" && status.reviewStatus === "reviewing" && status.stuckReason === "review_infrastructure_failure") {
|
|
29016
27583
|
let reviewedAtCommit;
|
|
@@ -29059,7 +27626,7 @@ async function checkPostReviewCommits() {
|
|
|
29059
27626
|
const actions = [];
|
|
29060
27627
|
try {
|
|
29061
27628
|
const statuses = loadReviewStatuses();
|
|
29062
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
27629
|
+
const { resolveProjectFromIssueSync } = await import("./projects-KJ94e50I.js");
|
|
29063
27630
|
for (const [issueId, status] of Object.entries(statuses)) {
|
|
29064
27631
|
if (status.mergeStatus === "merged") continue;
|
|
29065
27632
|
if (!status.reviewedAtCommit) continue;
|
|
@@ -29114,7 +27681,7 @@ async function checkPostReviewCommits() {
|
|
|
29114
27681
|
actions.push(`Deferred post-review re-dispatch for ${issueId} — advancing-role concurrency ceiling reached`);
|
|
29115
27682
|
logDeaconEventSync(`checkPostReviewCommits: deferred review for ${issueId} — advancing ceiling reached (PAN-1665) — ${describeRunningAgents()}`);
|
|
29116
27683
|
} else if (freshStatus?.reviewStatus === "pending") {
|
|
29117
|
-
const { spawnReviewRoleForIssue } = await import("./review-agent-
|
|
27684
|
+
const { spawnReviewRoleForIssue } = await import("./review-agent-Rub0OpZc.js");
|
|
29118
27685
|
const branch = `feature/${issueId.toLowerCase()}`;
|
|
29119
27686
|
const dispatchResult = await Effect.runPromise(spawnReviewRoleForIssue({
|
|
29120
27687
|
issueId,
|
|
@@ -29214,7 +27781,7 @@ async function checkReadyForMergeStuck() {
|
|
|
29214
27781
|
const testStatusGreenCiReconcileCooldowns = /* @__PURE__ */ new Map();
|
|
29215
27782
|
const TEST_STATUS_GREEN_CI_RECONCILE_COOLDOWN_MS = 300 * 1e3;
|
|
29216
27783
|
async function reconcileTestStatusFromGreenCi() {
|
|
29217
|
-
const { getCiCheckRunsState, getPullRequestHeadState, isGitHubAppConfigured } = await import("./github-app-
|
|
27784
|
+
const { getCiCheckRunsState, getPullRequestHeadState, isGitHubAppConfigured } = await import("./github-app-DRD2woO0.js");
|
|
29218
27785
|
return reconcileTestStatusFromGreenCiWithDeps({
|
|
29219
27786
|
isGitHubAppConfigured,
|
|
29220
27787
|
loadReviewStatuses,
|
|
@@ -29235,7 +27802,7 @@ async function reconcileTestStatusFromGreenCi() {
|
|
|
29235
27802
|
*/
|
|
29236
27803
|
async function clearStaleCiFeedback(issueId) {
|
|
29237
27804
|
const { readdir, rm } = await import("fs/promises");
|
|
29238
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
27805
|
+
const { resolveProjectFromIssueSync } = await import("./projects-KJ94e50I.js");
|
|
29239
27806
|
const projectConfig = resolveProjectFromIssueSync(issueId);
|
|
29240
27807
|
if (!projectConfig) return;
|
|
29241
27808
|
const repoDir = projectConfig.projectPath;
|
|
@@ -29535,7 +28102,7 @@ async function checkWorkspaceContainerHealth(sharedState) {
|
|
|
29535
28102
|
}
|
|
29536
28103
|
}
|
|
29537
28104
|
try {
|
|
29538
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
28105
|
+
const { resolveProjectFromIssueSync } = await import("./projects-KJ94e50I.js");
|
|
29539
28106
|
const resolved = resolveProjectFromIssueSync(issueLower.toUpperCase());
|
|
29540
28107
|
if (resolved) await killOrphanedWorkspaceProcesses(`${resolved.projectPath}/workspaces/feature-${issueLower}`);
|
|
29541
28108
|
} catch {}
|
|
@@ -29584,8 +28151,8 @@ async function checkWorkspaceContainerHealth(sharedState) {
|
|
|
29584
28151
|
async function checkMergedWorkSessions() {
|
|
29585
28152
|
const actions = [];
|
|
29586
28153
|
try {
|
|
29587
|
-
const { selectMergedWorkSessions } = await import("./reap-terminal-sessions-
|
|
29588
|
-
const { setAgentPaused } = await import("./agents-
|
|
28154
|
+
const { selectMergedWorkSessions } = await import("./reap-terminal-sessions-D_xvy-Mk.js");
|
|
28155
|
+
const { setAgentPaused } = await import("./agents-DCvyTXNU.js");
|
|
29589
28156
|
const toKill = selectMergedWorkSessions(loadReviewStatuses(), [...await Effect.runPromise(listSessionNames())]);
|
|
29590
28157
|
for (const session of toKill) try {
|
|
29591
28158
|
await Effect.runPromise(setAgentPaused(session, "merged — awaiting close-out (verify on main)", true));
|
|
@@ -29625,7 +28192,7 @@ const AWAITING_TEST_IDLE_REAP_MS = 600 * 1e3;
|
|
|
29625
28192
|
async function checkAwaitingTestWorkSessions() {
|
|
29626
28193
|
const actions = [];
|
|
29627
28194
|
try {
|
|
29628
|
-
const { selectAwaitingTestWorkSessions } = await import("./reap-terminal-sessions-
|
|
28195
|
+
const { selectAwaitingTestWorkSessions } = await import("./reap-terminal-sessions-D_xvy-Mk.js");
|
|
29629
28196
|
const candidates = selectAwaitingTestWorkSessions(loadReviewStatuses(), [...await Effect.runPromise(listSessionNames())]);
|
|
29630
28197
|
const now = Date.now();
|
|
29631
28198
|
for (const session of candidates) {
|
|
@@ -29681,7 +28248,7 @@ async function runPatrol() {
|
|
|
29681
28248
|
const stuckRemediationActions = await checkStuckAgentRemediation();
|
|
29682
28249
|
actions.push(...stuckRemediationActions);
|
|
29683
28250
|
for (const a of stuckRemediationActions) addLog("action", a, state.patrolCycle);
|
|
29684
|
-
const { reconcileInFlightJournals } = await import("./advancing-selfheal-
|
|
28251
|
+
const { reconcileInFlightJournals } = await import("./advancing-selfheal-CSuZ31bB.js");
|
|
29685
28252
|
const reconciledJournalActions = await reconcileInFlightJournals();
|
|
29686
28253
|
actions.push(...reconciledJournalActions);
|
|
29687
28254
|
for (const a of reconciledJournalActions) addLog("action", a, state.patrolCycle);
|
|
@@ -29693,7 +28260,7 @@ async function runPatrol() {
|
|
|
29693
28260
|
const age = Date.now() - (pending.timestamp ?? 0);
|
|
29694
28261
|
if (age < 3600 * 1e3) {
|
|
29695
28262
|
console.log(`[deacon] Processing pending post-merge lifecycle for ${pending.issueId} (age: ${Math.round(age / 1e3)}s)`);
|
|
29696
|
-
const { postMergeLifecycle } = await import("./merge-agent-
|
|
28263
|
+
const { postMergeLifecycle } = await import("./merge-agent-36wfYm2u.js");
|
|
29697
28264
|
const { unlinkSync } = await import("fs");
|
|
29698
28265
|
unlinkSync(pendingFile);
|
|
29699
28266
|
await postMergeLifecycle(pending.issueId, pending.projectPath, pending.sourceBranch, { skipDeploy: true });
|
|
@@ -29738,7 +28305,7 @@ async function runPatrol() {
|
|
|
29738
28305
|
actions.push(...suspendActions);
|
|
29739
28306
|
for (const a of suspendActions) addLog("action", a, state.patrolCycle);
|
|
29740
28307
|
try {
|
|
29741
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
28308
|
+
const { resolveProjectFromIssueSync } = await import("./projects-KJ94e50I.js");
|
|
29742
28309
|
const allStatuses = loadReviewStatuses();
|
|
29743
28310
|
for (const [issueId, status] of Object.entries(allStatuses)) {
|
|
29744
28311
|
if (!status.readyForMerge || status.mergeStatus === "merged") continue;
|
|
@@ -29758,7 +28325,7 @@ async function runPatrol() {
|
|
|
29758
28325
|
} catch (err) {
|
|
29759
28326
|
console.warn(`[deacon] Failed to check workspace existence: ${err.message}`);
|
|
29760
28327
|
}
|
|
29761
|
-
const { checkMergedAdvancingSessions } = await import("./advancing-selfheal-
|
|
28328
|
+
const { checkMergedAdvancingSessions } = await import("./advancing-selfheal-CSuZ31bB.js");
|
|
29762
28329
|
const reapedWorkActions = await checkMergedWorkSessions();
|
|
29763
28330
|
actions.push(...reapedWorkActions);
|
|
29764
28331
|
for (const a of reapedWorkActions) addLog("action", a, state.patrolCycle);
|
|
@@ -29766,7 +28333,7 @@ async function runPatrol() {
|
|
|
29766
28333
|
actions.push(...reapedMergedAdvancingActions);
|
|
29767
28334
|
for (const a of reapedMergedAdvancingActions) addLog("action", a, state.patrolCycle);
|
|
29768
28335
|
try {
|
|
29769
|
-
const { refreshClaudeCredentialsForActiveRemoteAgents } = await import("./remote-completion-
|
|
28336
|
+
const { refreshClaudeCredentialsForActiveRemoteAgents } = await import("./remote-completion-BgkiSQmx.js");
|
|
29770
28337
|
const remoteCredentialActions = await refreshClaudeCredentialsForActiveRemoteAgents();
|
|
29771
28338
|
actions.push(...remoteCredentialActions);
|
|
29772
28339
|
for (const a of remoteCredentialActions) addLog(a.includes("failed") ? "warn" : "action", a, state.patrolCycle);
|
|
@@ -29774,7 +28341,7 @@ async function runPatrol() {
|
|
|
29774
28341
|
addLog("warn", `Remote credential refresh patrol failed: ${err.message}`, state.patrolCycle);
|
|
29775
28342
|
}
|
|
29776
28343
|
try {
|
|
29777
|
-
const { refreshHostHeartbeatForEphemeralVms } = await import("./remote-agents-
|
|
28344
|
+
const { refreshHostHeartbeatForEphemeralVms } = await import("./remote-agents-DlvbzO7m.js");
|
|
29778
28345
|
const heartbeatActions = await refreshHostHeartbeatForEphemeralVms();
|
|
29779
28346
|
actions.push(...heartbeatActions);
|
|
29780
28347
|
for (const a of heartbeatActions) addLog(a.includes("failed") ? "warn" : "action", a, state.patrolCycle);
|
|
@@ -29782,7 +28349,7 @@ async function runPatrol() {
|
|
|
29782
28349
|
addLog("warn", `Remote heartbeat refresh patrol failed: ${err.message}`, state.patrolCycle);
|
|
29783
28350
|
}
|
|
29784
28351
|
try {
|
|
29785
|
-
const { reapCompletedRemoteAgents } = await import("./remote-completion-
|
|
28352
|
+
const { reapCompletedRemoteAgents } = await import("./remote-completion-BgkiSQmx.js");
|
|
29786
28353
|
const remoteReap = await reapCompletedRemoteAgents();
|
|
29787
28354
|
for (const r of remoteReap) if (r.status === "handed-off" || r.status === "error") {
|
|
29788
28355
|
const msg = `Remote reap ${r.issueId}: ${r.status} (${r.details.join("; ")})`;
|
|
@@ -29960,7 +28527,7 @@ async function runPatrol() {
|
|
|
29960
28527
|
const issueId = runtimeState.currentIssue;
|
|
29961
28528
|
try {
|
|
29962
28529
|
if (getReviewStatusSync(issueId)?.mergeStatus === "merging") {
|
|
29963
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
28530
|
+
const { resolveProjectFromIssueSync } = await import("./projects-KJ94e50I.js");
|
|
29964
28531
|
const resolved = resolveProjectFromIssueSync(issueId);
|
|
29965
28532
|
if (resolved) {
|
|
29966
28533
|
const branch = `feature/${issueId.toLowerCase()}`;
|
|
@@ -29974,7 +28541,7 @@ async function runPatrol() {
|
|
|
29974
28541
|
mergeStatus: "merged",
|
|
29975
28542
|
readyForMerge: false
|
|
29976
28543
|
});
|
|
29977
|
-
const { postMergeLifecycle } = await import("./merge-agent-
|
|
28544
|
+
const { postMergeLifecycle } = await import("./merge-agent-36wfYm2u.js");
|
|
29978
28545
|
postMergeLifecycle(issueId, resolved.projectPath).catch((err) => console.warn(`[deacon] postMergeLifecycle failed for ${issueId}: ${err}`));
|
|
29979
28546
|
actions.push(`Auto-completed stale merge for ${issueId}`);
|
|
29980
28547
|
} else {
|
|
@@ -30154,7 +28721,7 @@ function startDeacon() {
|
|
|
30154
28721
|
logDeaconEventSync(`startDeacon: health monitor starting (patrol every ${config.patrolIntervalMs / 1e3}s)`);
|
|
30155
28722
|
(async () => {
|
|
30156
28723
|
await reconcileAgentLiveness();
|
|
30157
|
-
const { runBootAdvancingSelfHeal } = await import("./advancing-selfheal-
|
|
28724
|
+
const { runBootAdvancingSelfHeal } = await import("./advancing-selfheal-CSuZ31bB.js");
|
|
30158
28725
|
await runBootAdvancingSelfHeal();
|
|
30159
28726
|
runScheduledPatrol("startup");
|
|
30160
28727
|
})().catch((err) => {
|
|
@@ -30224,6 +28791,6 @@ function assessDeaconPatrolFreshness(params) {
|
|
|
30224
28791
|
};
|
|
30225
28792
|
}
|
|
30226
28793
|
//#endregion
|
|
30227
|
-
export { isPreKickoffLaunchDeath as $,
|
|
28794
|
+
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
28795
|
|
|
30229
|
-
//# sourceMappingURL=deacon-
|
|
28796
|
+
//# sourceMappingURL=deacon-DrKDBeJL.js.map
|