@overdeck/desktop 0.45.15 → 0.45.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-electron/main.js +149 -158
- package/dist-electron/main.js.map +1 -1
- package/dist-electron/preload.js +17 -2
- package/dist-electron/preload.js.map +1 -1
- package/package.json +5 -4
- package/server/acceptance-criteria-aQFKQf-J.js +62 -0
- package/server/{advancing-selfheal-CSuZ31bB.js → advancing-selfheal-DgwQgm4D.js} +6 -5
- package/server/{agent-gc-D_DxfBHR.js → agent-gc-kpzxqT7P.js} +3 -3
- package/server/agent-state-C_6TG-Ad.js +3 -0
- package/server/{agent-state-service-C_2ZAQRP.js → agent-state-service-BUfovFfB.js} +1 -1
- package/server/{agent-state-service-BZkvgQf4.js → agent-state-service-nUD3qfob.js} +9 -52
- package/server/agents-BA15AQqo.js +3 -0
- package/server/{briefing-freshness-Kh5V8RTh.js → agents-BHBxr8c9.js} +5 -131
- package/server/{archive-planning-DkivCk1A.js → archive-planning-CzCW9Ifl.js} +5 -10
- package/server/{archive-planning-CTILQRnV.js → archive-planning-D-QsBufn.js} +1 -1
- package/server/{artifact-index-jobs-CmsvQ1ey.js → artifact-index-jobs-qqa51B2Z.js} +2 -2
- package/server/{backlog-auto-trigger-ueRaT8Dy.js → backlog-auto-trigger-B7Bi0bvY.js} +3 -3
- package/server/behavior-CWqNMqE5.js +10 -0
- package/server/briefing-freshness-DuxIE1yr.js +131 -0
- package/server/{checkpoint-manager-fu9oVsR-.js → checkpoint-manager-DF6hb9Jw.js} +3 -3
- package/server/{checkpoint-manager-CAFos8e1.js → checkpoint-manager-DixkLus7.js} +1 -1
- package/server/checkpoint-worker.js +1 -1
- package/server/{checkpoints-DvhGi8P_.js → checkpoints-B1Z42tJE.js} +1 -1
- package/server/{checkpoints-1BqOlS4q.js → checkpoints-BiviJqei.js} +2 -2
- package/server/claude-hooks-provision-BeMGi4ty.js +3 -0
- package/server/{claude-hooks-provision-s_wdpeVj.js → claude-hooks-provision-Du_PkMsp.js} +132 -114
- package/server/{claude-permissions-CaWqysff.js → claude-permissions-BB6agcOZ.js} +2 -2
- package/server/{claude-settings-overlay-CcTf0xzG.js → claude-settings-overlay-CAq2oFSK.js} +2 -2
- package/server/{claude-settings-overlay-BbA4FbVI.js → claude-settings-overlay-DUWWLd6M.js} +1 -1
- package/server/cli-BFgrSWKV.js +3 -0
- package/server/{cli-BwCvCUBK.js → cli-C33xPZNm.js} +9 -9
- package/server/{cliproxy-C2xC-3vH.js → cliproxy-BQX1TL6N.js} +1 -1
- package/server/{cliproxy-BsoNNDAj.js → cliproxy-CGBA1GzA.js} +2 -2
- package/server/{close-issue-BleIwP3f.js → close-issue-DNv8npc1.js} +5 -5
- package/server/{closed-issue-reaper-BwUUvjEW.js → closed-issue-reaper-DrqgBJlr.js} +1 -1
- package/server/{closed-issue-reaper-mC5pujeb.js → closed-issue-reaper-LoMnnjtJ.js} +9 -9
- package/server/codex-DxLivxri.js +3 -0
- package/server/{behavior-Cpj03N4v.js → codex-parser-DboQnEXN.js} +3 -9
- package/server/{codex-DW60_5j2.js → codex-sgWVCGUd.js} +43 -17
- package/server/{config-BRNQJXhA.js → config-6MCHOZ2N.js} +1 -1
- package/server/{config-ZNnMpIlh.js → config-DfaUXr6r.js} +2 -2
- package/server/{config-yaml-Dcz-8uit.js → config-yaml-CqaAyn8y.js} +149 -80
- package/server/{conflict-gate-DTje2Ll7.js → conflict-gate-BF_zhcmb.js} +3 -3
- package/server/{conflict-gate-DGT8jCLp.js → conflict-gate-BubJprtD.js} +1 -1
- package/server/{context-layers-BdUCQ-cl.js → context-layers-BFrxfl0l.js} +17 -3
- package/server/{context-layers-ByOWUjUg.js → context-layers-DWL_8HhY.js} +2 -2
- package/server/{control-settings-DwkAeooY.js → control-settings-BguNQ1F_.js} +4 -4
- package/server/{conversation-compaction-WYQZUVDm.js → conversation-compaction-CRKAf2qP.js} +1 -1
- package/server/{conversation-compaction-OTYgd6eg.js → conversation-compaction-DxSXl0pT.js} +8 -8
- package/server/{conversation-service-C_kNZPLx.js → conversation-service-DzuY9qoH.js} +1 -1
- package/server/{conversation-service-BR1OgvxO.js → conversation-service-mFVFdDQK.js} +6 -5
- package/server/{conversations-DG2M8WnT.js → conversations-BX5aD-6F.js} +4 -4
- package/server/{conversations-izHvSoAR.js → conversations-BajHQ60c.js} +1 -1
- package/server/{cost-DQ2ajr_m.js → cost-BoqD1Pxz.js} +2 -2
- package/server/{cost-B2mj17iG.js → cost-DuZ5vlv-.js} +3 -3
- package/server/{cost-sync-gTayEuWP.js → cost-sync-BYnmnMkY.js} +3 -3
- package/server/{dag-CqTehWpY.js → dag-C6kYyF17.js} +7 -243
- package/server/{dangerous-git-ops-DDWQlPC3.js → dangerous-git-ops-q5OPtXMd.js} +1 -1
- package/server/dashboard-db-worker.js +6 -6
- package/server/{deacon-BqW9HMew.js → deacon-CwCiNuEZ.js} +3 -3
- package/server/{deacon-DrKDBeJL.js → deacon-Dru5onpk.js} +258 -167
- package/server/{deacon-nudge-log-D1wEK6zF.js → deacon-nudge-log-ilDfxrhK.js} +1 -1
- package/server/{deacon-swarm-CO_A7xyd.js → deacon-swarm-BPmBmSoU.js} +298 -72
- package/server/deacon-swarm-CKyGJng1.js +2 -0
- package/server/deacon.js +14 -7
- package/server/{devcontainer-renderer-BQolp_qZ.js → devcontainer-renderer-BqGNCzvN.js} +3 -3
- package/server/{dist-Bc32rWJB.js → dist-BwlEiLCU.js} +1 -1
- package/server/dist-Bx4KkgYL.js +3 -0
- package/server/{dist-src-Byxt1ifL.js → dist-src-BE0Denfs.js} +1 -1
- package/server/{docker-s-esqZ__.js → docker-CNjXS72x.js} +2 -2
- package/server/{ensure-devcontainer-DA4-jF6R.js → ensure-devcontainer-5e9xOve4.js} +4 -4
- package/server/{ensure-devcontainer-pUVaT0h3.js → ensure-devcontainer-C6gyUQdE.js} +1 -1
- package/server/{esm-shims-CJHy8CZY.js → esm-shims-Cso7IGBC.js} +1 -1
- package/server/{event-store-CcJAhKCl.js → event-store-D9UhQyMS.js} +1 -1
- package/server/{event-store-DRte2Rwt.js → event-store-KZnWUKWh.js} +3 -3
- package/server/{events-Bej1w_k8.js → events-2eFUPdqz.js} +3 -3
- package/server/{events-CtsLScn8.js → events-BYbvqZky.js} +1 -1
- package/server/{factory-FN727tWr.js → factory-BtaRsHFC.js} +20 -17
- package/server/{feature-registry-population-ie-yBcQC.js → feature-registry-population-Ca2UaV0U.js} +4 -4
- package/server/{feature-registry-storage-CkZTFSsn.js → feature-registry-storage-DaP-bQxO.js} +2 -2
- package/server/{features-Dtm9ABuz.js → features-DqvaoQoa.js} +2 -2
- package/server/{feedback-target-BYtpyt1i.js → feedback-target-BXWdOiYI.js} +9 -7
- package/server/{feedback-target-DVJQDiE4.js → feedback-target-BblmMe9P.js} +1 -1
- package/server/{feedback-writer-DOUhyIW2.js → feedback-writer-CULeOOY4.js} +1 -1
- package/server/{feedback-writer-fdE1BzeL.js → feedback-writer-Dn8o9ZyE.js} +4 -4
- package/server/{flywheel-Bi82iiNl.js → flywheel-BUWdcfhq.js} +1 -1
- package/server/{flywheel-Bv3wv2S6.js → flywheel-CqkO3cDj.js} +15 -28
- package/server/{flywheel-CUErLAyN.js → flywheel-D9r1mw2U.js} +13 -13
- package/server/{flywheel-merge-order-DXjeBnJ1.js → flywheel-merge-order-LDzQDwSg.js} +1 -1
- package/server/{flywheel-merge-order-BaEN3iyN.js → flywheel-merge-order-VtjUweEb.js} +7 -7
- package/server/forge-DJy3Zx4s.js +2 -0
- package/server/{forge-ButEdJ31.js → forge-wEollMCi.js} +22 -12
- package/server/{from-CbtTxftl.js → from-B2tOYhYV.js} +1 -1
- package/server/{fts-db-CBgBLZcL.js → fts-db-Bgzn2RO7.js} +2 -2
- package/server/{fts-operations-CI9Xuo_1.js → fts-operations-Bj8yutnR.js} +2 -2
- package/server/{git-utils-ClfpP47N.js → git-utils-GxlL0tmt.js} +2 -2
- package/server/{git-utils-BCLRWQ-y.js → git-utils-q8jNoBts.js} +1 -1
- package/server/{github-app-DRD2woO0.js → github-app-BrYwK_Gb.js} +1 -1
- package/server/{github-app-DscZ0_B6.js → github-app-tUbb8Ldr.js} +8 -3
- package/server/{github-client-DpiZnxGH.js → github-client-BwBU41jK.js} +3 -3
- package/server/{github-client-iFRw8f7e.js → github-client-D6CNsftm.js} +1 -1
- package/server/{github-pr-lookup-D-EBexxC.js → github-pr-lookup-BS5PqkJb.js} +2 -2
- package/server/{harness-resolve-iMjyNUJ2.js → harness-resolve-Dx8hUsvC.js} +3 -3
- package/server/{health-events-CRdxDFN2.js → health-events-2DLp-5Xp.js} +2 -2
- package/server/{health-events-B_WsQyYm.js → health-events-B0mj6Iae.js} +1 -1
- package/server/{hooks-C1ScyVxP.js → hooks-BDcQJDUe.js} +1 -1
- package/server/{hooks-C9b7Vqpw.js → hooks-BS_JrvYP.js} +3 -3
- package/server/hume-B4seN95Y.js +3 -0
- package/server/{hume-TQ5pvOZ_.js → hume-BRhNKyXQ.js} +2 -2
- package/server/{idle-stack-reaper-B1kG7B_X.js → idle-stack-reaper-BCITXNW5.js} +2 -2
- package/server/{idle-stack-reaper-iFVOAoJy.js → idle-stack-reaper-C1ymihno.js} +1 -1
- package/server/{infra-bpq1MHKU.js → infra-_Kx1m9pm.js} +9 -4
- package/server/{injection-BLWfwTVZ.js → injection-Bvhyg_MV.js} +1 -1
- package/server/{injection-DJqWld1v.js → injection-CCaYkofq.js} +7 -7
- package/server/{inspect-agent-DytCsltn.js → inspect-agent-BqyZ4pCo.js} +35 -67
- package/server/inspect-agent-DCJQm9Wu.js +2 -0
- package/server/{internal-token-CjlhdufS.js → internal-token-Cl-1IxaE.js} +2 -2
- package/server/{internal-token-CCaWaTwE.js → internal-token-D-t28de5.js} +1 -1
- package/server/{io-BiQ2Cs3k.js → io-DkC4sFSy.js} +42 -56
- package/server/{issue-closed-FApNiOOs.js → issue-closed-Cpl4VDUM.js} +41 -6
- package/server/{issue-lifecycle-C-K53ASY.js → issue-lifecycle-CFR8TJ22.js} +22 -37
- package/server/{issue-lifecycle-BkFWNjlD.js → issue-lifecycle-YNTy3OT3.js} +1 -1
- package/server/{issue-service-singleton-bG1WdSdQ.js → issue-service-singleton-D81mCts_.js} +1 -1
- package/server/{issue-service-singleton-CuHGpJJP.js → issue-service-singleton-ldvUUXi3.js} +29 -29
- package/server/{issues-CwQMphDH.js → issues-DIEHt9sq.js} +2 -2
- package/server/{jsonl-parser-dNIjHgym.js → jsonl-parser-Cd5jIqh7.js} +3 -3
- package/server/{label-cleanup-DYvAZknd.js → label-cleanup-Btny6Gyo.js} +3 -3
- package/server/{state-home-CRowbXqU.js → launcher-generator-BXLM9f4b.js} +7 -127
- package/server/{layers-CD6FysRU.js → layers-gCJlK62m.js} +2 -2
- package/server/lifecycle-D7aQUnTO.js +12 -0
- package/server/{lifecycle-io-C_Wu0_i-.js → lifecycle-io-DQBF-GHO.js} +1 -1
- package/server/{lifecycle-io-CeYxP3cE.js → lifecycle-io-FfPUtz-y.js} +36 -47
- package/server/{linear-client-EtVyblVz.js → linear-client-CDH2D6Qy.js} +3 -3
- package/server/{linear-client-4qoKnuQu.js → linear-client-WrYrUIAH.js} +1 -1
- package/server/memory-fts-worker.js +1 -1
- package/server/{merge-7rqkTUm2.js → merge-BsDgUxFz.js} +3 -3
- package/server/{merge-brm721Es.js → merge-Dervs4BF.js} +1 -1
- package/server/{merge-agent-4Zhlgvqp.js → merge-agent-D6DNhe9j.js} +64 -51
- package/server/{merge-agent-36wfYm2u.js → merge-agent-DMQTJMP0.js} +1 -1
- package/server/{merge-batch-itfnwdsT.js → merge-batch-Bv6Z5K2H.js} +1 -1
- package/server/{merge-blockers-Bto_Oe_o.js → merge-blockers-WWWi6Ur2.js} +2 -2
- package/server/merge-ops-h9OCnIVz.js +2 -0
- package/server/{merge-rebase-Czfqfe4q.js → merge-rebase-Czth9ggm.js} +2 -2
- package/server/{merge-set-BIkGQL9j.js → merge-set-DNc4zBqd.js} +3 -3
- package/server/{merge-set-G1RHcu3D.js → merge-set-vuE3MEVt.js} +1 -1
- package/server/{merge-sync-B43Dybea.js → merge-sync-B2KSk54U.js} +2 -2
- package/server/{merge-sync-DIrmlZUr.js → merge-sync-B9nHdUGx.js} +1 -1
- package/server/{merge-train-DGqVuNZV.js → merge-train-DJgr81tF.js} +3 -3
- package/server/{merge-train-deps-q15XLnAS.js → merge-train-deps-B2OWS0k9.js} +4 -4
- package/server/{merge-verification-Cqfxx6bE.js → merge-verification-BBIXUEqa.js} +4 -4
- package/server/{multipart-parser-CiPxxfUH.js → multipart-parser-9DhuAkPd.js} +2 -2
- package/server/{no-resume-mode-yrPEQ_pC.js → no-resume-mode-Gh5R_YLF.js} +1 -1
- package/server/node_modules/.package-lock.json +11 -11
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/package.json +3 -3
- package/server/node_modules/toml/README.md +54 -0
- package/server/node_modules/toml/index.d.ts +42 -1
- package/server/node_modules/toml/index.js +3 -3
- package/server/node_modules/toml/lib/compiler.js +35 -3
- package/server/node_modules/toml/lib/parser.js +224 -143
- package/server/node_modules/toml/package.json +3 -1
- package/server/node_modules/ws/lib/receiver.js +15 -32
- package/server/node_modules/ws/lib/websocket-server.js +4 -4
- package/server/node_modules/ws/lib/websocket.js +4 -4
- package/server/node_modules/ws/package.json +5 -1
- package/server/{orphan-proposed-reconciler-BWWHn4Lr.js → orphan-proposed-reconciler-B8H41C4a.js} +14 -24
- package/server/{orphan-proposed-reconciler-DAD9FJtQ.js → orphan-proposed-reconciler-DbTmT7qy.js} +1 -1
- package/server/package-lock.json +12 -12
- package/server/package.json +1 -1
- package/server/{pan-dir-Bj7Hy8iu.js → pan-dir-BTw4MdSe.js} +4 -4
- package/server/{paths-C9DkhIOT.js → paths-Btkc8mzp.js} +2 -2
- package/server/{pickup-CKRuGDsB.js → pickup-BtvRBbvI.js} +1 -1
- package/server/{pipeline-notifier-BkKbQ8ji.js → pipeline-notifier-3frIvSi3.js} +1 -1
- package/server/{pipeline-notifier-CAurUste.js → pipeline-notifier-DTd19f18.js} +2 -2
- package/server/{project-pipelines-BRWaGmI4.js → project-pipelines-B95fcAek.js} +2 -2
- package/server/projects-Dc9aoVoG.js +3 -0
- package/server/{prompts-DfI5qbTW.js → prompts-CIVmjHxn.js} +2 -2
- package/server/{providers-D-5txBRc.js → providers-BLLk5IIb.js} +1 -1
- package/server/{providers-CWDXoaMA.js → providers-C-yWibCk.js} +7 -7
- package/server/public/assets/chunk-BO2N2NFS-DzKZyoKY.js +103 -0
- package/server/public/assets/{diagram-OG6HWLK6-Avtvq2qI.js → diagram-OG6HWLK6-Cx8mWUb8.js} +1 -1
- package/server/public/assets/{dist-BEHQuasD.js → dist-BqccLhaw.js} +3 -3
- package/server/public/assets/{dist-BvmY-qb1.js → dist-rC3nAs_O.js} +1 -1
- package/server/public/assets/{ganttDiagram-6RSMTGT7-7KhCd0fH.js → ganttDiagram-6RSMTGT7-DLYPLf5T.js} +1 -1
- package/server/public/assets/{highlighted-body-OFNGDK62-iQoBMTf0.js → highlighted-body-OFNGDK62-D4DqixbV.js} +1 -1
- package/server/public/assets/index-CPcysUHk.js +796 -0
- package/server/public/assets/index-H5M0yhM4.css +1 -0
- package/server/public/assets/{linear-CiJHW9g5.js → linear-yqcXkDfj.js} +1 -1
- package/server/public/assets/mermaid-GHXKKRXX-CWdZ_heB.js +1 -0
- package/server/public/assets/{pieDiagram-4H26LBE5-BOhmvUhW.js → pieDiagram-4H26LBE5-DhraIOaV.js} +1 -1
- package/server/public/assets/{prod-DmLBBqat.js → prod-DKUunUdN.js} +4 -4
- package/server/public/assets/{quadrantDiagram-W4KKPZXB-Cjku660G.js → quadrantDiagram-W4KKPZXB-DPiRcToa.js} +1 -1
- package/server/public/assets/{sankeyDiagram-5OEKKPKP-D52w5oPh.js → sankeyDiagram-5OEKKPKP-3An5HNkZ.js} +1 -1
- package/server/public/assets/{xychartDiagram-2RQKCTM6-BTO07_Iv.js → xychartDiagram-2RQKCTM6-lbEOjfqQ.js} +1 -1
- package/server/public/index.html +2 -2
- package/server/{pull-requests-CKZPWhjD.js → pull-requests-D7AL5woD.js} +1 -1
- package/server/{pull-requests-Bmre-Xlz.js → pull-requests-NDDNtqNq.js} +3 -3
- package/server/{agents-CsOzAmRg.js → queries-C0LCGG21.js} +743 -399
- package/server/{rally-BBd9tQ__.js → rally-4oKvnxLG.js} +3 -3
- package/server/rally-DF5a3ioP.js +3 -0
- package/server/{rally-api-DxZFObI_.js → rally-api-41tT6ikZ.js} +2 -2
- package/server/{rally-api-DDc85HIz.js → rally-api-BsaQ8Vnz.js} +1 -1
- package/server/{rally-client-DvvLiAQP.js → rally-client-Bo4hNcCZ.js} +5 -5
- package/server/{rally-client-BADHn0m_.js → rally-client-b5PT1x5L.js} +1 -1
- package/server/{reap-terminal-sessions-D_xvy-Mk.js → reap-terminal-sessions-BR39qflC.js} +1 -1
- package/server/{reap-terminal-sessions-D6JDJsqF.js → reap-terminal-sessions-CFkuquQj.js} +1 -1
- package/server/{rebuild-stack-GOsWqXi3.js → rebuild-stack-C7JPUom6.js} +1 -1
- package/server/{rebuild-stack-D19i080j.js → rebuild-stack-Ddv6W017.js} +6 -6
- package/server/{reconstruct-cache-lQrG4xGg.js → reconstruct-cache-Gqhm---K.js} +6 -6
- package/server/record-DLOqfbkI.js +3 -0
- package/server/record-update-BltEmPge.js +168 -0
- package/server/record-update-CDp7aTaT.js +3 -0
- package/server/recovery-trip-Cn7KJVkS.js +44 -0
- package/server/{release-engine-DxcMWRuK.js → release-engine-BYzmIBf9.js} +5 -5
- package/server/{release-set-BYsgX7o6.js → release-set-7pnxFOWR.js} +3 -3
- package/server/{remote-DmeL21dF.js → remote-Cvu4CSDk.js} +3 -3
- package/server/{remote-agents-BfQBE6MN.js → remote-agents-C2C6z9tj.js} +6 -33
- package/server/{remote-agents-DlvbzO7m.js → remote-agents-DYY5fFpd.js} +1 -1
- package/server/{remote-completion-BgkiSQmx.js → remote-completion-2Kb4IDg_.js} +13 -13
- package/server/{remote-8W2Yhygw.js → remote-rN0ecjHE.js} +3 -3
- package/server/resume-BFLl-yLn.js +3 -0
- package/server/{review-agent-D025Wt7w.js → review-agent-BZvk0N5G.js} +31 -23
- package/server/{review-agent-Rub0OpZc.js → review-agent-CpSHLzed.js} +1 -1
- package/server/{review-artifacts-CX951jTU.js → review-artifacts-PCo53YMn.js} +5 -19
- package/server/{review-context-DGGGR_w5.js → review-context-M7QtJlJq.js} +8 -8
- package/server/{review-monitor-0_qqMcnS.js → review-monitor-BLC5mTTg.js} +2 -2
- package/server/{review-status-Br6lAFGO.js → review-status-77N3PoZr.js} +1 -1
- package/server/{review-status-4qqLkRMu.js → review-status-DANr0t-v.js} +33 -59
- package/server/{review-status-enrichment-Cr8m3uVL.js → review-status-enrichment-DwOg4UfL.js} +3 -3
- package/server/{review-status-sync-D3KUhsdA.js → review-status-sync-Bd08OOFA.js} +1 -1
- package/server/{review-status-sync-OC-l1lNt.js → review-status-sync-BjTUJ5fx.js} +2 -2
- package/server/{review-verdict-feedback-YOzmsq9G.js → review-verdict-feedback-BsFLjN_6.js} +1 -1
- package/server/{review-verdict-feedback-DrWMuRaj.js → review-verdict-feedback-CBf-J_wS.js} +8 -8
- package/server/{rollup-CnxbwaLH.js → rollup-Bu0f2EyN.js} +8 -8
- package/server/{rollup-DmazRY0j.js → rollup-DTCCdEy4.js} +1 -1
- package/server/{scanner-DE1MqAaF.js → scanner-BlZ2vB7j.js} +7 -7
- package/server/{sequence-io-C0uoqfGx.js → sequence-io-ylyDtz2J.js} +4 -4
- package/server/{sequencer-agent-i-b2u4SJ.js → sequencer-agent-DsWQ-87H.js} +6 -17
- package/server/server.js +5670 -6392
- package/server/{service-D0_gh2tl.js → service-CLVBC_1Y.js} +116 -90
- package/server/{session-fork-DZ12vipL.js → session-fork-DlEIAhRy.js} +2 -2
- package/server/session-history-bnOFKMwf.js +168 -0
- package/server/settings-CP3GGon2.js +2 -0
- package/server/{settings-ByqjPtFO.js → settings-Cqa-8nyj.js} +2 -2
- package/server/{settings-DCC4BAqj.js → settings-gJrdLZy2.js} +3 -3
- package/server/{shadow-engineering-BhnmtW5m.js → shadow-engineering-fq1YEKV3.js} +3 -3
- package/server/{shadow-state-ByXZehsy.js → shadow-state-BqeFAygK.js} +1 -1
- package/server/{shadow-state-CKm8xWX9.js → shadow-state-RptE9Cau.js} +2 -2
- package/server/shadow-utils-BMWr5tRT.js +39 -0
- package/server/{ship-log-DE_0Cv_i.js → ship-log-BRQQi2lU.js} +1 -1
- package/server/{smart-compaction-D5Zen3AA.js → smart-compaction-CmoXpjeU.js} +7 -7
- package/server/{smart-compaction-h4_ca6Uk.js → smart-compaction-DldUel4B.js} +1 -1
- package/server/{spawn-planning-session-Dueit4WX.js → spawn-planning-session-CoS6LTc6.js} +16 -16
- package/server/{spawn-planning-session-Bgi7Ub02.js → spawn-planning-session-DT2tSMxo.js} +1 -1
- package/server/{specialist-completion-BZ8M-WZ0.js → specialist-completion-pJtESo7m.js} +1 -1
- package/server/{specialist-context-BMq83C58.js → specialist-context-CspI4Eog.js} +5 -5
- package/server/{specialist-handoff-logger-BxX1YefH.js → specialist-handoff-logger-Duz9RGvk.js} +2 -2
- package/server/{specialist-logs-BWZYcJ6P.js → specialist-logs-DtSkPJZK.js} +3 -3
- package/server/{specialists-ZkW4Mb7U.js → specialists-CywEMwxk.js} +1 -1
- package/server/{specialists-8ZAguXef.js → specialists-D9-dMUtI.js} +1 -1
- package/server/{specialists-BudKrjOu.js → specialists-Dax7tqXC.js} +1817 -560
- package/server/{specialists-DrPrC9Y9.js → specialists-GF42OOqd.js} +18 -18
- package/server/specs-VwcFtEDi.js +3 -0
- package/server/{src-DHn4Rd2F.js → src-By3D85Ry.js} +77 -1
- package/server/{src-Dv6L03vW.js → src-CqyFg52C.js} +5 -5
- package/server/{src-DNUUqkec.js → src-DhxM-eCb.js} +6 -6
- package/server/{stack-health-Dclm7_tu.js → stack-health-BsEVrJZ6.js} +1 -1
- package/server/{stack-health-DxsTx7II.js → stack-health-C-SnpRHh.js} +2 -2
- package/server/stale-task-claims-vTxmRzLi.js +69 -0
- package/server/state-home-Bur1y4oH.js +213 -0
- package/server/{state-mapping-BvAgFK8n.js → state-mapping-Ci0pkac4.js} +1 -1
- package/server/state-migrate-D3VveYfO.js +362 -0
- package/server/{stuck-remediation-CFWUP8_I.js → stuck-remediation-B699-p8v.js} +63 -46
- package/server/{stuck-remediation-CLHd-lrF.js → stuck-remediation-CaFYYTQW.js} +1 -1
- package/server/{summary-fork-CKc01Our.js → summary-fork-BxnF8Xh0.js} +2 -2
- package/server/{summary-fork-CtCwBJ2Z.js → summary-fork-COqYpVa3.js} +8 -8
- package/server/supervisor/{paths-3R6b989k.js → paths-Bk6hJRH9.js} +4 -3
- package/server/supervisor/pty-supervisor.js +2 -2
- package/server/supervisor/{pty-token-CScQ32Rj.js → pty-token-BZS5GYdG.js} +2 -2
- package/server/supervisor-eWAAmXKu.js +2 -0
- package/server/{supervisor-BA5D72Qa.js → supervisor-liMgIPDF.js} +2 -2
- package/server/{swarm-readiness-CL5sM9B1.js → swarm-readiness-sXB1vhzo.js} +3 -3
- package/server/{system-prerequisites-DmFSXIE5.js → system-prerequisites-Bz6KdkFJ.js} +1 -13
- package/server/{teardown-workspace-DWmFJzTw.js → teardown-workspace-DvzqnmUF.js} +14 -71
- package/server/{test-agent-queue-DjsQoV5X.js → test-agent-queue-hAU1Ah08.js} +6 -6
- package/server/{test-verdict-BSqsQp3G.js → test-verdict-CRsPpByy.js} +1 -1
- package/server/{test-verdict-D1AmZ2c0.js → test-verdict-CXMLATGc.js} +1 -1
- package/server/{tldr-daemon-C-MGomL8.js → tldr-daemon-Bam7Xhoo.js} +2 -2
- package/server/{tldr-daemon-DD9rI5gA.js → tldr-daemon-DhGwd88s.js} +1 -1
- package/server/tmux-C-rgxRDA.js +3 -0
- package/server/{tmux-C_d-lSIq.js → tmux-U55cNGFG.js} +92 -4
- package/server/{token-DfBf1bsd.js → token-Dsa-i36o.js} +2 -2
- package/server/{token-util-CROoF5ic.js → token-util-BWNpH96m.js} +1 -1
- package/server/token-util-DRt0j2nQ.js +3 -0
- package/server/{tracker-config-CNODpd11.js → tracker-config-OkdbaUCm.js} +2 -2
- package/server/{tracker-utils-Ch2_5GGf.js → tracker-utils-CghXMF3q.js} +2 -2
- package/server/{tracker-utils-B9ZoVA9b.js → tracker-utils-DdzUiPNU.js} +1 -1
- package/server/{traefik-connect-BF4x_LUQ.js → traefik-connect-CZYB3dlm.js} +1 -1
- package/server/{tunnel-r_5nHAI6.js → tunnel-D1YxesBL.js} +3 -3
- package/server/{tunnel-YD80_IHr.js → tunnel-DjlzgTl3.js} +1 -1
- package/server/typed-errors-CH4roFIj.js +3 -0
- package/server/{typed-errors-BEJhbjJg.js → typed-errors-n_Tnb4Fh.js} +3 -4
- package/server/{types-CE1m_daD.js → types-DOjWNv3Z.js} +1 -1
- package/server/{types-33JEP4LZ.js → types-DXBMm4mX.js} +1 -1
- package/server/{uat-train-DDI00aqD.js → uat-train-CaaWs9Rp.js} +1 -1
- package/server/{uat-train-DjkFWXge.js → uat-train-CqN34zFx.js} +24 -25
- package/server/{validation-DUTiJnyz.js → validation-4-z2Cw4z.js} +70 -23
- package/server/validation-DpTNakM6.js +3 -0
- package/server/verification-artifact-DK1xb1zG.js +56 -0
- package/server/verification-artifact-JD_edpZ9.js +2 -0
- package/server/{verification-runner-inLgeQux.js → verification-runner-BjHN80pJ.js} +338 -58
- package/server/verification-runner-ShYu5Ph3.js +2 -0
- package/server/{work-agent-prompt-fZljjA1_.js → work-agent-prompt-BiJ43Der.js} +12 -88
- package/server/workflows-B4C3lY9E.js +2 -0
- package/server/{workflows-oBnJ7Tm0.js → workflows-DkTotz_m.js} +17 -24
- package/server/{workspace-CNuW2j41.js → workspace-CuN0ev4Z.js} +3 -3
- package/server/{workspace-B2WOW9Hw.js → workspace-DQ4vVivd.js} +1 -1
- package/server/{workspace-config-CBgMGhWs.js → workspace-config-C77NKnsV.js} +1 -1
- package/server/{workspace-manager-DjUAJCSs.js → workspace-manager-B1mYn0lN.js} +1 -1
- package/server/{workspace-manager-CB-R07R3.js → workspace-manager-Beeo2aKF.js} +23 -48
- package/server/{workspace-metadata-9Nn5kgRl.js → workspace-metadata-BZC5BmoP.js} +2 -2
- package/server/{workspace-metadata-Fd58uUQG.js → workspace-metadata-Cy7_ZACL.js} +1 -1
- package/server/{workspaces-BjWXntty.js → workspaces-CGuzW1Ia.js} +191 -153
- package/sync-sources/hooks/ask-user-question-hook +7 -1
- package/sync-sources/hooks/codex-notify-hook +64 -8
- package/sync-sources/hooks/record-cost-event.js +1109 -36
- package/sync-sources/hooks/record-cost-event.js.map +1 -1
- package/sync-sources/hooks/statusline.sh +2 -2
- package/sync-sources/hooks/work-agent-stop-hook +1 -2
- package/server/acceptance-criteria-DHZk2ceV.js +0 -33
- package/server/agent-runtime-mirror-DrWxopNA.js +0 -37
- package/server/agent-state-EP2QFV9n.js +0 -3
- package/server/agents-DCvyTXNU.js +0 -3
- package/server/auto-commit-QAfsu3Sb.js +0 -3
- package/server/bd-process-lock-D3S4T4o-.js +0 -390
- package/server/beads-BGGxrkZ5.js +0 -649
- package/server/beads-CYsLiyIM.js +0 -2
- package/server/beads-query-B1DlJVp9.js +0 -95
- package/server/beads-restore-CyygSmmn.js +0 -23
- package/server/cli-ClIQwgMI.js +0 -3
- package/server/codex-B7DTpwEw.js +0 -3
- package/server/compact-beads-CK_hHEnB.js +0 -3
- package/server/compact-beads-DKL54y6j.js +0 -94
- package/server/deacon-swarm-BY5hKNaU.js +0 -2
- package/server/dist-DGTwcZhI.js +0 -3
- package/server/export-Dx_qJ3h8.js +0 -87
- package/server/forge-XlDgPQWs.js +0 -2
- package/server/hume-K1pi8jC4.js +0 -3
- package/server/inspect-agent-477VxQim.js +0 -2
- package/server/lifecycle-C_73gi-C.js +0 -14
- package/server/merge-ops-PzqsW69V.js +0 -2
- package/server/projects-KJ94e50I.js +0 -3
- package/server/public/assets/chunk-BO2N2NFS-ClukPsZQ.js +0 -103
- package/server/public/assets/index-DUFDmvmH.css +0 -1
- package/server/public/assets/index-DnTZ2QeN.js +0 -796
- package/server/public/assets/mermaid-GHXKKRXX-DZJOwgBG.js +0 -1
- package/server/rally-Dc2Wnxw2.js +0 -3
- package/server/record-pyB6VA32.js +0 -3
- package/server/recovery-trip-Dfh1tNHn.js +0 -98
- package/server/resolver-dTpSSzaH.js +0 -158
- package/server/resume-DhcIqsTm.js +0 -3
- package/server/settings-yydgaqhv.js +0 -2
- package/server/specs-DwoAEGrW.js +0 -3
- package/server/supervisor-DHjumXlL.js +0 -2
- package/server/tmux-x291Gjjb.js +0 -3
- package/server/token-util-xNaV-00f.js +0 -3
- package/server/tracker-config-DItsdelv.js +0 -3
- package/server/typed-errors-DSPn_xWP.js +0 -3
- package/server/validation-ict8hnXk.js +0 -3
- package/server/verification-runner-ATaLbpr5.js +0 -2
- package/server/workflows-tU7KKxQi.js +0 -2
- package/server/writer-CQMGzEkw.js +0 -3
- package/server/writer-fe1-8iGc.js +0 -251
|
@@ -1,40 +1,41 @@
|
|
|
1
1
|
import { n as __esmMin, o as __toESM } from "./rolldown-runtime-DNCzzKnI.js";
|
|
2
|
-
import {
|
|
2
|
+
import { $r as sessionFilePath, C as init_tier_table, Cr as AGENTS_DIR, En as getIssuePrefix, F as getBuiltInDefaultHarness, Fn as init_projects, H as setupCredentialFileAuthSync, It as resolveProjectForIssue, Jr as getOverdeckHome, L as getProviderEnvSync, Mr as OVERDECK_HOME, Nt as readIssueRecordForWorkspaceSync, On as getProjectSwarmHotspots, P as clearCredentialFileAuthSync, Pt as readIssueRecordSync, Qr as resolveOhmypiExtensionPath, R as getProviderForModelSync, Rt as writeAgentHarnessModelSync, Sn as findProjectByPathSync, Sr as init_errors, T as resolveTieredExecutionEnabledForIssue, U as ensureOpenAICompatibleProxyRunning, Vr as encodeClaudeProjectDir, W as init_openai_compatible_proxy, X as init_roles, Yr as init_paths, Z as resolveModel, Zr as packageRoot, at as resolveModelIdSync, b as DEFAULT_TIERED_EXECUTION_CONFIG, cr as require_dist, ct as init_percent, dr as ConfigError, et as getModelCapabilitySync, f as loadConfigSync, fr as FsError, hn as shouldCommitLegacyWorkspaceArtifacts, kn as getProjectSync, kt as init_record, l as isClaudeCodeChannelsMcpEnabled, nt as hasModelCapabilitySync, or as resolveBareNumericIdSync, ot as fmix32, pn as init_state_read_home, qn as resolveProjectFromIssueSync, rr as init_issue_id, rt as init_model_capabilities, st as fnv1a32, t as init_config_yaml, u as isTldrEnabledSync, ur as ClaudeCredentialParseError, w as resolveTieredExecutionEnabled, x as TIERED_EXECUTION_DIFFICULTIES, z as init_providers } from "./config-yaml-CqaAyn8y.js";
|
|
3
3
|
import { t as require_toml } from "./toml-CeLDATih.js";
|
|
4
4
|
import { a as init_activity_logger, n as emitActivityEntrySync, r as emitActivityTtsSync } from "./activity-logger-pcbf-e30.js";
|
|
5
|
-
import { d as getOverdeckDatabaseSync, f as init_infra } from "./infra-
|
|
6
|
-
import { A as
|
|
7
|
-
import { a as init_event_store, i as initEventStore } from "./event-store-
|
|
8
|
-
import { a as getHarnessBehavior, i as OHMYPI_BEHAVIOR } from "./src-
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { _ as init_tier_metrics, g as estimateFeedDeliveryTokens, v as recordTierFeedDelivery } from "./cost-sync-
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import { L as normalizeHarness, R as reactivateConversationForSpawn, S as getConversationByName, k as init_conversations, y as createConversation } from "./conversations-
|
|
20
|
-
import { n as recordFeatureRegistryLifecycle, t as init_feature_registry_population } from "./feature-registry-population-
|
|
21
|
-
import { a as readCavemanVariant, n as init_workspace } from "./workspace-
|
|
22
|
-
import { a as
|
|
23
|
-
import { a as init_claude_permissions, r as getClaudePermissionFlagsStringSync } from "./claude-permissions-
|
|
24
|
-
import { h as workspaceContextFile, o as init_layers } from "./layers-
|
|
25
|
-
import { a as extractThreadIdFromRollout, c as initCodexHome, l as init_codex, o as findLatestRollout } from "./codex-
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import { a as
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
5
|
+
import { d as getOverdeckDatabaseSync, f as init_infra } from "./infra-_Kx1m9pm.js";
|
|
6
|
+
import { A as listSessions, B as setOption, D as listPaneValues, E as killSessionSync, F as sendKeys, G as BLANKED_PROVIDER_ENV, J as init_child_env, L as sendRawKeystroke, P as sendEscapeKeyAsync, R as sessionExists, S as init_tmux, T as killSession, a as capturePaneSync, f as exactPaneTarget, i as capturePane, j as listSessionsSync, o as createSession, s as createSessionSync, w as isPaneDead, z as sessionExistsSync } from "./tmux-U55cNGFG.js";
|
|
7
|
+
import { a as init_event_store, i as initEventStore } from "./event-store-KZnWUKWh.js";
|
|
8
|
+
import { a as getHarnessBehavior, i as OHMYPI_BEHAVIOR } from "./src-By3D85Ry.js";
|
|
9
|
+
import { C as init_review_status_source, D as init_agent_state_sync, E as getOverdeckAgentStateSync, O as listOverdeckAgentStatesSync, c as init_review_status, k as saveOverdeckAgentStateSync, m as resetPipelineVerdictsForWorkStartSync, w as readReviewStatusMap } from "./review-status-DANr0t-v.js";
|
|
10
|
+
import { i as countAgentsByStatus, o as init_agents$1 } from "./agents-BHBxr8c9.js";
|
|
11
|
+
import { n as ensureSessionContextBriefingFile, r as init_briefing_freshness } from "./briefing-freshness-DuxIE1yr.js";
|
|
12
|
+
import { o as getPricingSync, s as init_cost } from "./cost-BoqD1Pxz.js";
|
|
13
|
+
import { _ as init_tier_metrics, g as estimateFeedDeliveryTokens, v as recordTierFeedDelivery } from "./cost-sync-BYnmnMkY.js";
|
|
14
|
+
import { a as persistCurrentSessionId, d as isAgentStateServiceInProcess, i as logLauncherSessionPinned, l as getRuntimeSnapshot, n as createFreshSessionIdentity, o as init_persistent_logger, r as init_session_history, s as logAgentLifecycleSync, u as init_agent_runtime_mirror } from "./session-history-bnOFKMwf.js";
|
|
15
|
+
import { t as init_behavior } from "./behavior-CWqNMqE5.js";
|
|
16
|
+
import { i as ensureInternalTokenSync, s as init_internal_token, t as INTERNAL_TOKEN_HEADER } from "./internal-token-Cl-1IxaE.js";
|
|
17
|
+
import { m as readWorkspacePlanSync, o as init_io } from "./io-DkC4sFSy.js";
|
|
18
|
+
import { c as bridgeGeminiAuthToCliproxy, d as getCliproxyAuthDir, g as getCliproxyLogPath, l as decodeJwtPayload$1, p as getCliproxyClientEnv, s as bridgeCodexAuthToCliproxySync, v as init_cliproxy } from "./cliproxy-CGBA1GzA.js";
|
|
19
|
+
import { L as normalizeHarness, R as reactivateConversationForSpawn, S as getConversationByName, k as init_conversations, y as createConversation } from "./conversations-BX5aD-6F.js";
|
|
20
|
+
import { n as recordFeatureRegistryLifecycle, t as init_feature_registry_population } from "./feature-registry-population-Ca2UaV0U.js";
|
|
21
|
+
import { a as readCavemanVariant, n as init_workspace } from "./workspace-CuN0ev4Z.js";
|
|
22
|
+
import { a as requireModelOverrideSync, i as normalizeModelOverrideSync, n as init_launcher_generator, o as shellQuoteModelIdSync, r as init_model_validation, t as generateLauncherScriptSync } from "./launcher-generator-BXLM9f4b.js";
|
|
23
|
+
import { a as init_claude_permissions, r as getClaudePermissionFlagsStringSync } from "./claude-permissions-BB6agcOZ.js";
|
|
24
|
+
import { h as workspaceContextFile, o as init_layers } from "./layers-gCJlK62m.js";
|
|
25
|
+
import { a as extractThreadIdFromRollout, c as initCodexHome, l as init_codex, o as findLatestRollout } from "./codex-sgWVCGUd.js";
|
|
26
|
+
import { f as init_config$1, m as loadConfigSync$1 } from "./config-DfaUXr6r.js";
|
|
27
|
+
import { a as getFlywheelActiveRunIdSync, s as init_control_settings } from "./control-settings-BguNQ1F_.js";
|
|
28
|
+
import { n as createTrackerFromConfig, r as init_factory, t as createTracker } from "./factory-BtaRsHFC.js";
|
|
29
|
+
import { a as init_stack_health, i as getWorkspaceStackHealth } from "./stack-health-C-SnpRHh.js";
|
|
30
|
+
import { i as createActiveSlice, l as init_dag, o as getDispatchableItems, s as groupItemsByWave } from "./dag-C6kYyF17.js";
|
|
31
|
+
import { c as generateFixedPointPromptSync, f as initHookSync, n as checkHookSync, p as init_hooks } from "./hooks-BS_JrvYP.js";
|
|
32
|
+
import { n as resolveHarness, t as init_harness_resolve } from "./harness-resolve-Dx8hUsvC.js";
|
|
33
|
+
import { r as isRoleTerminal, t as init_reap_terminal_sessions } from "./reap-terminal-sessions-CFkuquQj.js";
|
|
34
|
+
import { c as isStateMigrated, o as init_state_home } from "./state-home-Bur1y4oH.js";
|
|
35
|
+
import { n as provisionClaudeHooks, t as init_claude_hooks_provision } from "./claude-hooks-provision-Du_PkMsp.js";
|
|
36
|
+
import { a as init_lifecycle_io, t as appendContinueSessionEntryForIssue } from "./lifecycle-io-FfPUtz-y.js";
|
|
37
|
+
import { r as init_swarm_readiness, t as analyzeSwarmReadiness } from "./swarm-readiness-sXB1vhzo.js";
|
|
38
|
+
import { dirname, join, relative } from "node:path";
|
|
38
39
|
import { Data, Duration, Effect, FileSystem } from "effect";
|
|
39
40
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, statSync, statfsSync, unlinkSync, writeFileSync } from "fs";
|
|
40
41
|
import { basename as basename$1, dirname as dirname$1, join as join$1, resolve as resolve$1 } from "path";
|
|
@@ -44,11 +45,11 @@ import { chmodSync as chmodSync$1, closeSync as closeSync$1, constants, cpSync,
|
|
|
44
45
|
import { chmod, mkdir, readFile, stat as stat$1, writeFile } from "node:fs/promises";
|
|
45
46
|
import { randomUUID } from "crypto";
|
|
46
47
|
import { ChildProcess } from "effect/unstable/process";
|
|
47
|
-
import { mkdir as mkdir$1, readFile as readFile$1, readdir as readdir$1, rename as rename$1, rm as rm$1, stat as stat$2, writeFile as writeFile$1 } from "fs/promises";
|
|
48
|
+
import { mkdir as mkdir$1, open as open$1, readFile as readFile$1, readdir as readdir$1, rename as rename$1, rm as rm$1, stat as stat$2, writeFile as writeFile$1 } from "fs/promises";
|
|
48
49
|
import { platform as platform$2 } from "process";
|
|
49
50
|
import { exec, execFile } from "node:child_process";
|
|
50
51
|
import { promisify } from "node:util";
|
|
51
|
-
import { exec as exec$1, execSync
|
|
52
|
+
import { exec as exec$1, execSync } from "child_process";
|
|
52
53
|
import { promisify as promisify$1 } from "util";
|
|
53
54
|
import { createHash as createHash$1, randomBytes, randomUUID as randomUUID$1 } from "node:crypto";
|
|
54
55
|
import { fileURLToPath } from "node:url";
|
|
@@ -356,6 +357,402 @@ var init_ohmypi_parser = __esmMin((() => {
|
|
|
356
357
|
]);
|
|
357
358
|
}));
|
|
358
359
|
//#endregion
|
|
360
|
+
//#region ../../lib/codex-auth.ts
|
|
361
|
+
/** Absolute path to the codex CLI's own global credential file. */
|
|
362
|
+
function getNativeCodexAuthPath() {
|
|
363
|
+
return join$1(homedir(), ".codex", "auth.json");
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Pure classifier for the native store's raw JSON (PAN-2285). Decodes the
|
|
367
|
+
* access_token JWT `exp` to decide valid/expired; reports missing when the file
|
|
368
|
+
* is absent (raw === null) and unknown when it is malformed. API-key mode
|
|
369
|
+
* (OPENAI_API_KEY set, no OAuth tokens) is a valid auth state. Exported for
|
|
370
|
+
* testing with fabricated JWTs.
|
|
371
|
+
*/
|
|
372
|
+
function classifyNativeCodexAuth(raw, now = Date.now()) {
|
|
373
|
+
if (raw === null) return { status: "missing" };
|
|
374
|
+
let parsed;
|
|
375
|
+
try {
|
|
376
|
+
parsed = JSON.parse(raw);
|
|
377
|
+
} catch {
|
|
378
|
+
return { status: "unknown" };
|
|
379
|
+
}
|
|
380
|
+
const lastRefresh = typeof parsed.last_refresh === "string" ? parsed.last_refresh : void 0;
|
|
381
|
+
const accessToken = typeof parsed.tokens?.access_token === "string" ? parsed.tokens.access_token : null;
|
|
382
|
+
if (!accessToken) {
|
|
383
|
+
if (typeof parsed.OPENAI_API_KEY === "string" && parsed.OPENAI_API_KEY) return {
|
|
384
|
+
status: "valid",
|
|
385
|
+
lastRefresh
|
|
386
|
+
};
|
|
387
|
+
return {
|
|
388
|
+
status: "unknown",
|
|
389
|
+
lastRefresh
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
const idToken = typeof parsed.tokens?.id_token === "string" ? parsed.tokens.id_token : null;
|
|
393
|
+
const idClaims = idToken ? decodeJwtPayload$1(idToken) : null;
|
|
394
|
+
const email = idClaims && typeof idClaims.email === "string" ? idClaims.email : void 0;
|
|
395
|
+
const accessClaims = decodeJwtPayload$1(accessToken);
|
|
396
|
+
const expSec = accessClaims && typeof accessClaims.exp === "number" ? accessClaims.exp : null;
|
|
397
|
+
if (expSec === null) return {
|
|
398
|
+
status: "unknown",
|
|
399
|
+
email,
|
|
400
|
+
lastRefresh
|
|
401
|
+
};
|
|
402
|
+
const expiresAt = (/* @__PURE__ */ new Date(expSec * 1e3)).toISOString();
|
|
403
|
+
if (expSec * 1e3 <= now) return {
|
|
404
|
+
status: "expired",
|
|
405
|
+
email,
|
|
406
|
+
expiresAt,
|
|
407
|
+
lastRefresh
|
|
408
|
+
};
|
|
409
|
+
return {
|
|
410
|
+
status: "valid",
|
|
411
|
+
email,
|
|
412
|
+
expiresAt,
|
|
413
|
+
lastRefresh
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
/** Async native-store probe used by the dashboard status endpoint. */
|
|
417
|
+
async function probeNativeCodexAuth(now = Date.now()) {
|
|
418
|
+
const path = getNativeCodexAuthPath();
|
|
419
|
+
let raw;
|
|
420
|
+
let mtimeMs = 0;
|
|
421
|
+
try {
|
|
422
|
+
raw = await readFile$1(path, "utf8");
|
|
423
|
+
mtimeMs = (await stat$2(path)).mtimeMs;
|
|
424
|
+
} catch {
|
|
425
|
+
raw = null;
|
|
426
|
+
}
|
|
427
|
+
return {
|
|
428
|
+
...classifyNativeCodexAuth(raw, now),
|
|
429
|
+
mtimeMs
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
/** Sync native-store probe used by the spawn gate. */
|
|
433
|
+
function probeNativeCodexAuthSync(now = Date.now()) {
|
|
434
|
+
let raw;
|
|
435
|
+
try {
|
|
436
|
+
raw = readFileSync(getNativeCodexAuthPath(), "utf8");
|
|
437
|
+
} catch {
|
|
438
|
+
raw = null;
|
|
439
|
+
}
|
|
440
|
+
return classifyNativeCodexAuth(raw, now);
|
|
441
|
+
}
|
|
442
|
+
function nativeCodexAuthMtimeSync() {
|
|
443
|
+
try {
|
|
444
|
+
return statSync(getNativeCodexAuthPath()).mtimeMs;
|
|
445
|
+
} catch {
|
|
446
|
+
return 0;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Pure classifier over a codex agent's pane tail (PAN-2285). True when the pane
|
|
451
|
+
* shows the revoked/invalidated refresh-token error. Exported so it is testable
|
|
452
|
+
* without tmux.
|
|
453
|
+
*/
|
|
454
|
+
function paneShowsCodexAuthBurn(paneText) {
|
|
455
|
+
return CODEX_AUTH_BURN_MARKERS.some((marker) => paneText.includes(marker));
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Mark an agent state as codex-auth-burned (PAN-2285). Pure mutation — the
|
|
459
|
+
* caller persists via the agent-state write door (saveAgentStateSync), which
|
|
460
|
+
* mirrors into the shared agents table so the flag crosses the deacon/server
|
|
461
|
+
* process boundary. Returns true only when the state was newly flagged
|
|
462
|
+
* (idempotent: an already-flagged state is left untouched), so callers can emit
|
|
463
|
+
* a single operator notice instead of one per patrol tick. The flag time is
|
|
464
|
+
* embedded in the reason (`codex-auth-burned[<ISO>]`) because the agents table
|
|
465
|
+
* has no dedicated column for it and `troubledAt` may predate the burn when the
|
|
466
|
+
* agent was already troubled for another reason.
|
|
467
|
+
*/
|
|
468
|
+
function applyCodexAuthBurnFlag(state, nowMs = Date.now()) {
|
|
469
|
+
if (state.troubled && state.lastFailureReason?.startsWith("codex-auth-burned")) return false;
|
|
470
|
+
const nowIso = new Date(nowMs).toISOString();
|
|
471
|
+
state.troubled = true;
|
|
472
|
+
if (!state.troubledAt) state.troubledAt = nowIso;
|
|
473
|
+
state.lastFailureReason = `${CODEX_AUTH_BURNED_REASON_PREFIX}[${nowIso}]: Codex refresh token was revoked — re-authenticate (dashboard Codex-auth banner has a Re-authenticate button, or run \`codex login\`)`;
|
|
474
|
+
state.lastFailureAt = nowIso;
|
|
475
|
+
return true;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* When (epoch ms) a state was flagged codex-auth-burned, or null if it is not
|
|
479
|
+
* currently flagged. Requires the troubled gate to still be set — `pan
|
|
480
|
+
* untroubled` / resume clears troubled and the failure fields, which retires the
|
|
481
|
+
* flag. Parses the ISO stamp embedded in the reason; falls back to `troubledAt`
|
|
482
|
+
* for flags written by builds that predate the embedded stamp.
|
|
483
|
+
*/
|
|
484
|
+
function codexAuthBurnFlaggedAtMs(state) {
|
|
485
|
+
if (!state.troubled) return null;
|
|
486
|
+
const reason = state.lastFailureReason;
|
|
487
|
+
if (!reason?.startsWith("codex-auth-burned")) return null;
|
|
488
|
+
const embedded = reason.match(/^codex-auth-burned\[([^\]]+)\]/)?.[1];
|
|
489
|
+
const fromReason = embedded ? Date.parse(embedded) : NaN;
|
|
490
|
+
if (Number.isFinite(fromReason)) return fromReason;
|
|
491
|
+
const fromTroubledAt = state.troubledAt ? Date.parse(state.troubledAt) : NaN;
|
|
492
|
+
return Number.isFinite(fromTroubledAt) ? fromTroubledAt : 0;
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Pure filter: which of these agent states are burned AND still current? Flags
|
|
496
|
+
* recorded strictly before the native store's last write are stale: a global
|
|
497
|
+
* `codex login` rewrites ~/.codex/auth.json (bumping its mtime) and heals every
|
|
498
|
+
* agent through the shared symlink, so those burns no longer apply (the flag
|
|
499
|
+
* itself is retired when the agent is untroubled/resumed).
|
|
500
|
+
*/
|
|
501
|
+
function filterCodexAuthBurnedAgentIds(states, nativeMtimeMs) {
|
|
502
|
+
const active = [];
|
|
503
|
+
for (const state of states) {
|
|
504
|
+
const flaggedAt = codexAuthBurnFlaggedAtMs(state);
|
|
505
|
+
if (flaggedAt !== null && flaggedAt >= nativeMtimeMs) active.push(state.id);
|
|
506
|
+
}
|
|
507
|
+
return active;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Agents currently flagged codex-auth-burned. Callers supply states read through
|
|
511
|
+
* the agent resolver so this pure auth module does not create a spawn-time cycle.
|
|
512
|
+
*/
|
|
513
|
+
function listCodexAuthBurnedAgentsSync(nativeMtimeMs, states) {
|
|
514
|
+
return filterCodexAuthBurnedAgentIds(states, nativeMtimeMs);
|
|
515
|
+
}
|
|
516
|
+
/** Sync convenience for the spawn gate: are any agents still burned right now? */
|
|
517
|
+
function hasActiveBurnedCodexAgentsSync(states) {
|
|
518
|
+
return listCodexAuthBurnedAgentsSync(nativeCodexAuthMtimeSync(), states).length > 0;
|
|
519
|
+
}
|
|
520
|
+
function nativeToStatus(native) {
|
|
521
|
+
switch (native.status) {
|
|
522
|
+
case "valid": return {
|
|
523
|
+
status: "valid",
|
|
524
|
+
email: native.email ?? "",
|
|
525
|
+
expiresAt: native.expiresAt ?? "",
|
|
526
|
+
source: "native"
|
|
527
|
+
};
|
|
528
|
+
case "expired": return {
|
|
529
|
+
status: "expired",
|
|
530
|
+
email: native.email ?? "",
|
|
531
|
+
expiresAt: native.expiresAt ?? "",
|
|
532
|
+
source: "native"
|
|
533
|
+
};
|
|
534
|
+
case "missing": return {
|
|
535
|
+
status: "missing",
|
|
536
|
+
source: "native"
|
|
537
|
+
};
|
|
538
|
+
case "unknown": return {
|
|
539
|
+
status: "unknown",
|
|
540
|
+
source: "native"
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
function withSource(status, source) {
|
|
545
|
+
return {
|
|
546
|
+
...status,
|
|
547
|
+
source
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Merge the native and cliproxy statuses into the single worst state the banner
|
|
552
|
+
* should react to (burned > expired > valid > missing > unknown). Both stores
|
|
553
|
+
* are healed by the same `codex login`, so surfacing the more severe one is
|
|
554
|
+
* correct and its remedy is identical. Exported for testing.
|
|
555
|
+
*/
|
|
556
|
+
function combineCodexAuthStatuses(native, cliproxy) {
|
|
557
|
+
const nativeSev = CODEX_AUTH_SEVERITY[native.status];
|
|
558
|
+
return CODEX_AUTH_SEVERITY[cliproxy.status] > nativeSev ? withSource(cliproxy, "cliproxy") : native;
|
|
559
|
+
}
|
|
560
|
+
async function checkCodexAuthStatusPromise(options = {}) {
|
|
561
|
+
const native = await probeNativeCodexAuth(Date.now());
|
|
562
|
+
const cliproxy = await checkCliproxyCodexAuthStatusPromise(options);
|
|
563
|
+
const activeBurned = listCodexAuthBurnedAgentsSync(native.mtimeMs, options.agentStates ?? []);
|
|
564
|
+
if (activeBurned.length > 0) return {
|
|
565
|
+
status: "burned",
|
|
566
|
+
email: native.email ?? "",
|
|
567
|
+
expiresAt: native.expiresAt ?? "",
|
|
568
|
+
source: "native",
|
|
569
|
+
affectedAgents: activeBurned
|
|
570
|
+
};
|
|
571
|
+
return combineCodexAuthStatuses(nativeToStatus(native), cliproxy);
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Spawn gate (PAN-2285): refuse to launch a NEW codex-harness agent while the
|
|
575
|
+
* native codex auth is unusable — missing/expired file or any agent currently
|
|
576
|
+
* burned (revoked refresh token shared across the family). Resumes are exempt:
|
|
577
|
+
* the symlink migration in initCodexHome heals a stale home on relaunch. Throws
|
|
578
|
+
* a clear, remedy-naming error, mirroring the harness-policy ToS gate.
|
|
579
|
+
*/
|
|
580
|
+
function assertCodexNativeAuthForSpawn(harness, agentStates) {
|
|
581
|
+
if (harness !== "codex") return;
|
|
582
|
+
const native = probeNativeCodexAuthSync();
|
|
583
|
+
const reason = native.status === "missing" ? "not signed in (~/.codex/auth.json is missing)" : native.status === "expired" ? "expired (~/.codex/auth.json access token has lapsed)" : hasActiveBurnedCodexAgentsSync(agentStates) ? "revoked (a running codex agent hit a revoked refresh token — the shared token family is dead)" : null;
|
|
584
|
+
if (reason === null) return;
|
|
585
|
+
throw new Error(`Cannot spawn a Codex agent: native Codex authentication is ${reason}. Run \`codex login\` on the host (or click Re-authenticate in the dashboard Codex-auth banner), then retry.`);
|
|
586
|
+
}
|
|
587
|
+
async function checkCliproxyCodexAuthStatusPromise(options = {}) {
|
|
588
|
+
const credPath = join$1(getCliproxyAuthDir(), "codex-primary.json");
|
|
589
|
+
let raw;
|
|
590
|
+
let credMtimeMs = null;
|
|
591
|
+
try {
|
|
592
|
+
raw = await readFile$1(credPath, "utf8");
|
|
593
|
+
credMtimeMs = (await stat$2(credPath)).mtimeMs;
|
|
594
|
+
} catch {
|
|
595
|
+
return { status: "missing" };
|
|
596
|
+
}
|
|
597
|
+
let creds;
|
|
598
|
+
try {
|
|
599
|
+
creds = JSON.parse(raw);
|
|
600
|
+
} catch {
|
|
601
|
+
return {
|
|
602
|
+
status: "unknown",
|
|
603
|
+
message: "Malformed credential file"
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
const accessToken = typeof creds.access_token === "string" ? creds.access_token : null;
|
|
607
|
+
if (!accessToken) return {
|
|
608
|
+
status: "unknown",
|
|
609
|
+
message: "Missing access_token in credential file"
|
|
610
|
+
};
|
|
611
|
+
const claims = decodeJwtPayload$1(accessToken);
|
|
612
|
+
if (!claims) return {
|
|
613
|
+
status: "unknown",
|
|
614
|
+
message: "Unable to decode access_token"
|
|
615
|
+
};
|
|
616
|
+
const expSec = typeof claims.exp === "number" ? claims.exp : null;
|
|
617
|
+
if (expSec === null) return {
|
|
618
|
+
status: "unknown",
|
|
619
|
+
message: "Missing exp claim in access_token"
|
|
620
|
+
};
|
|
621
|
+
const email = typeof creds.email === "string" ? creds.email : "";
|
|
622
|
+
const expiresAt = (/* @__PURE__ */ new Date(expSec * 1e3)).toISOString();
|
|
623
|
+
if (expSec * 1e3 <= Date.now()) return {
|
|
624
|
+
status: "expired",
|
|
625
|
+
email,
|
|
626
|
+
expiresAt
|
|
627
|
+
};
|
|
628
|
+
return await applyBurnedTokenOverride({
|
|
629
|
+
status: "valid",
|
|
630
|
+
email,
|
|
631
|
+
expiresAt
|
|
632
|
+
}, email, expiresAt, { ignoreBurnBefore: options.ignoreBurnBefore ?? credMtimeMs ?? void 0 });
|
|
633
|
+
}
|
|
634
|
+
/** Read the trailing window of the cliproxy log for burn/failure analysis. */
|
|
635
|
+
async function readLogTail(path) {
|
|
636
|
+
const TAIL_BYTES = 128 * 1024;
|
|
637
|
+
const file = await open$1(path, "r");
|
|
638
|
+
try {
|
|
639
|
+
const stat = await file.stat();
|
|
640
|
+
const length = Math.min(stat.size, TAIL_BYTES);
|
|
641
|
+
const buffer = Buffer.alloc(length);
|
|
642
|
+
await file.read(buffer, 0, length, stat.size - length);
|
|
643
|
+
return buffer.toString("utf8");
|
|
644
|
+
} finally {
|
|
645
|
+
await file.close();
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
async function applyBurnedTokenOverride(baseStatus, email, expiresAt, options) {
|
|
649
|
+
let logRaw;
|
|
650
|
+
try {
|
|
651
|
+
logRaw = await readLogTail(getCliproxyLogPath());
|
|
652
|
+
} catch {
|
|
653
|
+
return baseStatus;
|
|
654
|
+
}
|
|
655
|
+
return evaluateBurnedFromLog(logRaw, baseStatus, email, expiresAt, options);
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* Pure decision: given the cliproxy log tail, decide whether a JWT-valid token
|
|
659
|
+
* is actually burned. Exported for regression testing (PAN-1584).
|
|
660
|
+
*
|
|
661
|
+
* "Auth failure" evidence = either a refresh-token burn line
|
|
662
|
+
* (`refresh token has already been used`) OR a `503` on `/v1/messages` /
|
|
663
|
+
* `/v1/chat/completions` (the live symptom the agent hits once cliproxy disables
|
|
664
|
+
* the provider — and which keeps appearing after the burn line stops, since a
|
|
665
|
+
* disabled provider no longer attempts refreshes). "Success" = a `200` on those
|
|
666
|
+
* same paths (proves the auth path works right now).
|
|
667
|
+
*
|
|
668
|
+
* Decision:
|
|
669
|
+
* - No failure evidence → trust base status.
|
|
670
|
+
* - Success AFTER the last failure → trust base status (recovered).
|
|
671
|
+
* - Failure AFTER the credential's last write (ignoreBurnBefore) → BURNED,
|
|
672
|
+
* regardless of age. The credential write time is when you last logged in;
|
|
673
|
+
* a failure after it means the current token is dead. This is authoritative
|
|
674
|
+
* and is the fix for the bug where a >1h-stale burn line was dismissed as
|
|
675
|
+
* "valid" during a quiet period even though the token was dead (PAN-1584).
|
|
676
|
+
* - Failure BEFORE that cutoff → trust base status (re-authed since).
|
|
677
|
+
* - No cutoff available → fall back to the staleness backstop:
|
|
678
|
+
* burned only if the last failure is within BURN_STALENESS_MS.
|
|
679
|
+
*
|
|
680
|
+
* We intentionally don't probe cliproxy with HTTP — `GET /v1/models` always
|
|
681
|
+
* 401s (it needs real OAuth, not the local key) and would generate spurious log
|
|
682
|
+
* lines on every dashboard load.
|
|
683
|
+
*/
|
|
684
|
+
function evaluateBurnedFromLog(logRaw, baseStatus, email, expiresAt, options = {}) {
|
|
685
|
+
const now = options.now ?? Date.now();
|
|
686
|
+
const lines = logRaw.split("\n").slice(-500);
|
|
687
|
+
const isBurnLine = (l) => l.includes("refresh token has already been used") || l.includes("refresh_token_reused");
|
|
688
|
+
const isAuthFailure503 = (l) => /\b503 \|/.test(l) && /POST\s+"\/v1\/(messages|chat\/completions)/.test(l);
|
|
689
|
+
const isSuccess = (l) => /\b200 \|/.test(l) && /POST\s+"\/v1\/(messages|chat\/completions)/.test(l);
|
|
690
|
+
const timestampAt = (idx) => {
|
|
691
|
+
for (let j = idx; j >= Math.max(0, idx - 10); j--) {
|
|
692
|
+
const m = lines[j]?.match(/^\[(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2})\]/);
|
|
693
|
+
if (m) {
|
|
694
|
+
const t = Date.parse(`${m[1]}T${m[2]}Z`);
|
|
695
|
+
if (Number.isFinite(t)) return t;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
return null;
|
|
699
|
+
};
|
|
700
|
+
let lastFailureIdx = -1;
|
|
701
|
+
let lastFailureTimestamp = null;
|
|
702
|
+
let lastSuccessIdx = -1;
|
|
703
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
704
|
+
const line = lines[i] ?? "";
|
|
705
|
+
if (lastFailureIdx < 0 && (isBurnLine(line) || isAuthFailure503(line))) {
|
|
706
|
+
lastFailureIdx = i;
|
|
707
|
+
lastFailureTimestamp = timestampAt(i);
|
|
708
|
+
}
|
|
709
|
+
if (lastSuccessIdx < 0 && isSuccess(line)) lastSuccessIdx = i;
|
|
710
|
+
if (lastFailureIdx >= 0 && lastSuccessIdx >= 0) break;
|
|
711
|
+
}
|
|
712
|
+
if (lastFailureIdx < 0) return baseStatus;
|
|
713
|
+
if (lastSuccessIdx > lastFailureIdx) return baseStatus;
|
|
714
|
+
if (options.ignoreBurnBefore !== void 0) {
|
|
715
|
+
if (lastFailureTimestamp !== null && lastFailureTimestamp + 1e3 <= options.ignoreBurnBefore) return baseStatus;
|
|
716
|
+
return {
|
|
717
|
+
status: "burned",
|
|
718
|
+
email,
|
|
719
|
+
expiresAt
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
if (lastFailureTimestamp !== null && now - lastFailureTimestamp > BURN_STALENESS_MS) return baseStatus;
|
|
723
|
+
return {
|
|
724
|
+
status: "burned",
|
|
725
|
+
email,
|
|
726
|
+
expiresAt
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
var CodexAuthCheckError, CODEX_AUTH_BURN_MARKERS, CODEX_AUTH_BURNED_REASON_PREFIX, CODEX_AUTH_SEVERITY, BURN_STALENESS_MS, checkCodexAuthStatus;
|
|
730
|
+
var init_codex_auth = __esmMin((() => {
|
|
731
|
+
init_cliproxy();
|
|
732
|
+
CodexAuthCheckError = class extends Data.TaggedError("CodexAuthCheckError") {};
|
|
733
|
+
CODEX_AUTH_BURN_MARKERS = [
|
|
734
|
+
"could not be refreshed because your refresh token was revoked",
|
|
735
|
+
"token_invalidated",
|
|
736
|
+
"token_revoked"
|
|
737
|
+
];
|
|
738
|
+
CODEX_AUTH_BURNED_REASON_PREFIX = "codex-auth-burned";
|
|
739
|
+
CODEX_AUTH_SEVERITY = {
|
|
740
|
+
burned: 4,
|
|
741
|
+
expired: 3,
|
|
742
|
+
valid: 2,
|
|
743
|
+
missing: 1,
|
|
744
|
+
unknown: 0
|
|
745
|
+
};
|
|
746
|
+
BURN_STALENESS_MS = 3600 * 1e3;
|
|
747
|
+
checkCodexAuthStatus = (options = {}) => Effect.tryPromise({
|
|
748
|
+
try: () => checkCodexAuthStatusPromise(options),
|
|
749
|
+
catch: (cause) => new CodexAuthCheckError({
|
|
750
|
+
message: cause instanceof Error ? cause.message : String(cause),
|
|
751
|
+
cause
|
|
752
|
+
})
|
|
753
|
+
});
|
|
754
|
+
}));
|
|
755
|
+
//#endregion
|
|
359
756
|
//#region ../../lib/overdeck/agent-rollback-state.ts
|
|
360
757
|
function getRollbackAgentStatePath(agentId) {
|
|
361
758
|
return join(getOverdeckHome(), "agents", agentId, AGENT_STATE_ROLLBACK_FILE);
|
|
@@ -889,54 +1286,6 @@ var init_agent_record_sync = __esmMin((() => {
|
|
|
889
1286
|
init_record();
|
|
890
1287
|
}));
|
|
891
1288
|
//#endregion
|
|
892
|
-
//#region ../../lib/persistent-logger.ts
|
|
893
|
-
/**
|
|
894
|
-
* Append-only persistent logger for forensic audit trails.
|
|
895
|
-
*
|
|
896
|
-
* Complements the SQLite event store (activity-logger.ts) with flat-file logs
|
|
897
|
-
* that survive event-store resets and are greppable from the shell.
|
|
898
|
-
*
|
|
899
|
-
* Files:
|
|
900
|
-
* ~/.overdeck/logs/deacon.log — deacon startup recovery actions
|
|
901
|
-
* ~/.overdeck/agents/<id>/lifecycle.log — per-agent state transitions
|
|
902
|
-
*/
|
|
903
|
-
function logsDir() {
|
|
904
|
-
return join$1(getOverdeckHome(), "logs");
|
|
905
|
-
}
|
|
906
|
-
function agentDir(agentId) {
|
|
907
|
-
return join$1(getOverdeckHome(), "agents", agentId);
|
|
908
|
-
}
|
|
909
|
-
function ensureLogsDir() {
|
|
910
|
-
try {
|
|
911
|
-
mkdirSync(logsDir(), { recursive: true });
|
|
912
|
-
} catch {}
|
|
913
|
-
}
|
|
914
|
-
function ensureAgentDir(agentId) {
|
|
915
|
-
try {
|
|
916
|
-
mkdirSync(agentDir(agentId), { recursive: true });
|
|
917
|
-
} catch {}
|
|
918
|
-
}
|
|
919
|
-
function timestamp() {
|
|
920
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
921
|
-
}
|
|
922
|
-
/** Append a line to ~/.overdeck/logs/deacon.log */
|
|
923
|
-
function logDeaconEventSync(message) {
|
|
924
|
-
ensureLogsDir();
|
|
925
|
-
try {
|
|
926
|
-
appendFileSync(join$1(logsDir(), "deacon.log"), `[${timestamp()}] ${message}\n`);
|
|
927
|
-
} catch {}
|
|
928
|
-
}
|
|
929
|
-
/** Append a line to ~/.overdeck/agents/<agentId>/lifecycle.log */
|
|
930
|
-
function logAgentLifecycleSync(agentId, message) {
|
|
931
|
-
ensureAgentDir(agentId);
|
|
932
|
-
try {
|
|
933
|
-
appendFileSync(join$1(agentDir(agentId), "lifecycle.log"), `[${timestamp()}] ${message}\n`);
|
|
934
|
-
} catch {}
|
|
935
|
-
}
|
|
936
|
-
var init_persistent_logger = __esmMin((() => {
|
|
937
|
-
init_paths();
|
|
938
|
-
}));
|
|
939
|
-
//#endregion
|
|
940
1289
|
//#region ../../lib/agents/agent-state.ts
|
|
941
1290
|
function getAgentDir(agentId) {
|
|
942
1291
|
return join$1(getOverdeckHome(), "agents", agentId);
|
|
@@ -1308,10 +1657,16 @@ function getAgentResumeGateBlockReason(state) {
|
|
|
1308
1657
|
/** Intent-aware policy over a classified gate. This function never mutates agent state. */
|
|
1309
1658
|
function decideResumeGate(block, intent, context = {}) {
|
|
1310
1659
|
if (!block) return { decision: "proceed" };
|
|
1311
|
-
if (intent === "message-delivery")
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1660
|
+
if (intent === "message-delivery") {
|
|
1661
|
+
if (block.gate === "stopped-by-user" && context.hasCompletedHandoff === true && context.owesRework === true) return {
|
|
1662
|
+
decision: "proceed",
|
|
1663
|
+
clearStoppedByUser: true
|
|
1664
|
+
};
|
|
1665
|
+
return {
|
|
1666
|
+
decision: "queue-message",
|
|
1667
|
+
reason: block.reason
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1315
1670
|
if (intent === "operator-start") {
|
|
1316
1671
|
if (block.gate === "paused") return {
|
|
1317
1672
|
decision: "block",
|
|
@@ -2324,7 +2679,7 @@ async function createOhmypiFifoPromise(agentId, home) {
|
|
|
2324
2679
|
mode: 448
|
|
2325
2680
|
});
|
|
2326
2681
|
if (existsSync$1(paths.fifoPath)) unlinkSync$1(paths.fifoPath);
|
|
2327
|
-
await execAsync$
|
|
2682
|
+
await execAsync$6(`mkfifo -m 600 ${shellQuote$1(paths.fifoPath)}`);
|
|
2328
2683
|
return paths.fifoPath;
|
|
2329
2684
|
}
|
|
2330
2685
|
/**
|
|
@@ -2362,14 +2717,14 @@ function writeOhmypiCommandSync(agentId, command, home) {
|
|
|
2362
2717
|
closeSync$1(fd);
|
|
2363
2718
|
}
|
|
2364
2719
|
}
|
|
2365
|
-
function shellQuote$
|
|
2720
|
+
function shellQuote$1(s) {
|
|
2366
2721
|
if (/^[A-Za-z0-9._/-]+$/.test(s)) return s;
|
|
2367
2722
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
2368
2723
|
}
|
|
2369
|
-
var execAsync$
|
|
2724
|
+
var execAsync$6, OhmypiNotReady, OhmypiFifoError, createOhmypiFifo;
|
|
2370
2725
|
var init_ohmypi_fifo = __esmMin((() => {
|
|
2371
2726
|
init_paths();
|
|
2372
|
-
execAsync$
|
|
2727
|
+
execAsync$6 = promisify(exec);
|
|
2373
2728
|
OhmypiNotReady = class extends Error {
|
|
2374
2729
|
code = "OHMYPI_NOT_READY";
|
|
2375
2730
|
constructor(message) {
|
|
@@ -2429,12 +2784,12 @@ async function claudeSystemPromptFiles(workspace, harness) {
|
|
|
2429
2784
|
files.push(await ensureSessionContextBriefingFile());
|
|
2430
2785
|
const behavior = getHarnessBehavior(harness);
|
|
2431
2786
|
if (behavior.contextLayerKind === "pi") {
|
|
2432
|
-
const { piGlobalContextFile } = await import("./context-layers-
|
|
2787
|
+
const { piGlobalContextFile } = await import("./context-layers-DWL_8HhY.js");
|
|
2433
2788
|
const globalFile = piGlobalContextFile();
|
|
2434
2789
|
if (existsSync(globalFile)) files.unshift(globalFile);
|
|
2435
2790
|
}
|
|
2436
2791
|
if (behavior.contextLayerKind === "codex") {
|
|
2437
|
-
const { codexGlobalContextFile } = await import("./context-layers-
|
|
2792
|
+
const { codexGlobalContextFile } = await import("./context-layers-DWL_8HhY.js");
|
|
2438
2793
|
const globalFile = codexGlobalContextFile();
|
|
2439
2794
|
if (existsSync(globalFile)) files.unshift(globalFile);
|
|
2440
2795
|
}
|
|
@@ -2461,14 +2816,14 @@ async function hasAgentRuntimeInSubtree(rootPid, harness = "claude-code") {
|
|
|
2461
2816
|
if (seen.has(pid) || !/^\d+$/.test(pid)) continue;
|
|
2462
2817
|
seen.add(pid);
|
|
2463
2818
|
try {
|
|
2464
|
-
const { stdout: comm } = await execAsync$
|
|
2819
|
+
const { stdout: comm } = await execAsync$4(`ps -p ${pid} -o comm=`);
|
|
2465
2820
|
const name = comm.trim();
|
|
2466
2821
|
if (expectedProcessNames.has(name)) return true;
|
|
2467
2822
|
} catch {
|
|
2468
2823
|
continue;
|
|
2469
2824
|
}
|
|
2470
2825
|
try {
|
|
2471
|
-
const { stdout: kids } = await execAsync$
|
|
2826
|
+
const { stdout: kids } = await execAsync$4(`pgrep -P ${pid}`);
|
|
2472
2827
|
for (const kid of kids.trim().split("\n").filter(Boolean)) queue.push(kid);
|
|
2473
2828
|
} catch {}
|
|
2474
2829
|
}
|
|
@@ -2587,7 +2942,7 @@ async function injectPiPromptTimeMemory(agentId, prompt) {
|
|
|
2587
2942
|
agentRole: agentState.role ?? "work",
|
|
2588
2943
|
agentHarness: agentState.harness ?? "claude-code"
|
|
2589
2944
|
};
|
|
2590
|
-
const { injectPromptTimeMemory } = await import("./injection-
|
|
2945
|
+
const { injectPromptTimeMemory } = await import("./injection-Bvhyg_MV.js");
|
|
2591
2946
|
const result = await injectPromptTimeMemory({
|
|
2592
2947
|
prompt,
|
|
2593
2948
|
identity,
|
|
@@ -2621,7 +2976,7 @@ async function injectPiConversationMemory(opts, prompt) {
|
|
|
2621
2976
|
agentRole: "work",
|
|
2622
2977
|
agentHarness: "ohmypi"
|
|
2623
2978
|
};
|
|
2624
|
-
const { injectPromptTimeMemory } = await import("./injection-
|
|
2979
|
+
const { injectPromptTimeMemory } = await import("./injection-Bvhyg_MV.js");
|
|
2625
2980
|
const result = await injectPromptTimeMemory({
|
|
2626
2981
|
prompt,
|
|
2627
2982
|
identity,
|
|
@@ -2797,7 +3152,7 @@ async function getRoleRuntimeBaseCommand(model, agentName, role, harness = "clau
|
|
|
2797
3152
|
if (provider.name === "openai" && await getProviderAuthMode(validatedModel) === "subscription") return `claude${printFlag}${roleInject}${permissionFlags} --model ${shellQuoteModelIdSync(CLI_PROXY_MODEL_ALIASES[validatedModel] ?? validatedModel)}${effortFlag}${nameFlag}`;
|
|
2798
3153
|
return `claude${printFlag}${roleInject}${permissionFlags} --model ${quotedModel}${effortFlag}${nameFlag}`;
|
|
2799
3154
|
}
|
|
2800
|
-
var import_dist, execAsync$
|
|
3155
|
+
var import_dist, execAsync$4, missingRoleDefinitionWarnings, OHMYPI_AGENT_READY_TIMEOUT_SECONDS;
|
|
2801
3156
|
var init_runtime_command = __esmMin((() => {
|
|
2802
3157
|
import_dist = /* @__PURE__ */ __toESM(require_dist(), 1);
|
|
2803
3158
|
init_claude_permissions();
|
|
@@ -2817,7 +3172,7 @@ var init_runtime_command = __esmMin((() => {
|
|
|
2817
3172
|
init_agent_state();
|
|
2818
3173
|
init_identity();
|
|
2819
3174
|
init_provider_env();
|
|
2820
|
-
execAsync$
|
|
3175
|
+
execAsync$4 = promisify$1(exec$1);
|
|
2821
3176
|
missingRoleDefinitionWarnings = /* @__PURE__ */ new Set();
|
|
2822
3177
|
OHMYPI_AGENT_READY_TIMEOUT_SECONDS = 120;
|
|
2823
3178
|
}));
|
|
@@ -2876,6 +3231,14 @@ var init_resolve_tier = __esmMin((() => {
|
|
|
2876
3231
|
}));
|
|
2877
3232
|
//#endregion
|
|
2878
3233
|
//#region ../../lib/agents/staffing.ts
|
|
3234
|
+
/** Per-issue work-model override from the issue record, or undefined. */
|
|
3235
|
+
function resolveIssueWorkModel(issueId) {
|
|
3236
|
+
const resolved = resolveProjectFromIssueSync(issueId);
|
|
3237
|
+
if (!resolved) return void 0;
|
|
3238
|
+
const project = getProjectSync(resolved.projectKey);
|
|
3239
|
+
if (!project) return void 0;
|
|
3240
|
+
return readIssueRecordSync(project, issueId)?.workModel || void 0;
|
|
3241
|
+
}
|
|
2879
3242
|
/** Provider-default harness for a model (PAN-1984: harness is derived from the
|
|
2880
3243
|
* model's provider — per-provider setting else built-in default). */
|
|
2881
3244
|
function providerDefaultHarnessSync(model, config) {
|
|
@@ -2900,6 +3263,16 @@ function resolveImplicitStaffing(config, spawnKey) {
|
|
|
2900
3263
|
*/
|
|
2901
3264
|
function resolveStaffing(item, options = {}) {
|
|
2902
3265
|
const config = options.config ?? loadConfigSync().config;
|
|
3266
|
+
const issueModel = options.issueId ? resolveIssueWorkModel(options.issueId) : void 0;
|
|
3267
|
+
if (issueModel) {
|
|
3268
|
+
const model = requireModelOverrideSync(issueModel);
|
|
3269
|
+
return {
|
|
3270
|
+
tierName: "issue-override",
|
|
3271
|
+
model,
|
|
3272
|
+
harness: providerDefaultHarnessSync(model, config),
|
|
3273
|
+
implicit: false
|
|
3274
|
+
};
|
|
3275
|
+
}
|
|
2903
3276
|
const tiered = config.tieredExecution;
|
|
2904
3277
|
if (tiered && resolveTieredExecutionEnabled(tiered, options.planMetadata)) try {
|
|
2905
3278
|
const tier = resolveTier(item, tiered);
|
|
@@ -2939,7 +3312,9 @@ var init_staffing = __esmMin((() => {
|
|
|
2939
3312
|
init_config_yaml();
|
|
2940
3313
|
init_roles();
|
|
2941
3314
|
init_model_validation();
|
|
3315
|
+
init_record();
|
|
2942
3316
|
init_providers();
|
|
3317
|
+
init_projects();
|
|
2943
3318
|
init_percent();
|
|
2944
3319
|
init_resolve_tier();
|
|
2945
3320
|
init_tier_table();
|
|
@@ -3011,7 +3386,8 @@ function resolveSlotTierSpawnParams(baseWorkspace, slotItemId, explicitModel, sp
|
|
|
3011
3386
|
const staffing = resolveStaffing(item, {
|
|
3012
3387
|
planMetadata,
|
|
3013
3388
|
spawnKey,
|
|
3014
|
-
config
|
|
3389
|
+
config,
|
|
3390
|
+
issueId: issueId ?? void 0
|
|
3015
3391
|
});
|
|
3016
3392
|
return {
|
|
3017
3393
|
model: staffing.model,
|
|
@@ -3043,6 +3419,7 @@ function resolveSingleWorkTierSpawnParams(workspace, explicitModel, spawnKey) {
|
|
|
3043
3419
|
const staffing = resolveStaffing(item, {
|
|
3044
3420
|
planMetadata,
|
|
3045
3421
|
spawnKey,
|
|
3422
|
+
issueId: issueId ?? void 0,
|
|
3046
3423
|
config: {
|
|
3047
3424
|
...config,
|
|
3048
3425
|
tieredExecution: {
|
|
@@ -3125,7 +3502,7 @@ async function transitionIssueToInReview(issueId, workspacePath) {
|
|
|
3125
3502
|
async function buildAgentLaunchConfig(opts) {
|
|
3126
3503
|
const model = requireModelOverrideSync(opts.model);
|
|
3127
3504
|
try {
|
|
3128
|
-
const { injectOverdeckInfraDeny } = await import("./claude-settings-overlay-
|
|
3505
|
+
const { injectOverdeckInfraDeny } = await import("./claude-settings-overlay-DUWWLd6M.js");
|
|
3129
3506
|
await Effect.runPromise(injectOverdeckInfraDeny(opts.workspace));
|
|
3130
3507
|
} catch (err) {
|
|
3131
3508
|
console.warn(`[agents] injectOverdeckInfraDeny failed for ${opts.agentId} (non-fatal): ${err instanceof Error ? err.message : err}`);
|
|
@@ -3206,7 +3583,7 @@ async function retrieveSpawnTimeMemoryContext(input) {
|
|
|
3206
3583
|
agentRole: input.role,
|
|
3207
3584
|
agentHarness: input.harness
|
|
3208
3585
|
};
|
|
3209
|
-
const { injectPromptTimeMemory } = await import("./injection-
|
|
3586
|
+
const { injectPromptTimeMemory } = await import("./injection-Bvhyg_MV.js");
|
|
3210
3587
|
return (await injectPromptTimeMemory({
|
|
3211
3588
|
prompt: input.prompt,
|
|
3212
3589
|
identity,
|
|
@@ -3297,7 +3674,7 @@ async function assertWorkspaceStackHealthyForSpawn(issueId, role, allowHost = fa
|
|
|
3297
3674
|
record.attempts += 1;
|
|
3298
3675
|
spawnStackRebuildState.set(normalizedIssue, record);
|
|
3299
3676
|
console.log(`[agents] Workspace stack for ${normalizedIssue} unhealthy (${details}) — rebuilding before spawn (attempt ${record.attempts}/${SPAWN_STACK_REBUILD_MAX_ATTEMPTS})`);
|
|
3300
|
-
const { rebuildWorkspaceStack } = await import("./rebuild-stack-
|
|
3677
|
+
const { rebuildWorkspaceStack } = await import("./rebuild-stack-C7JPUom6.js");
|
|
3301
3678
|
const result = await Effect.runPromise(rebuildWorkspaceStack(issueId, { onProgress: (m) => console.log(`[agents] ${normalizedIssue} stack rebuild: ${m}`) })).catch((err) => ({
|
|
3302
3679
|
success: false,
|
|
3303
3680
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -4196,12 +4573,6 @@ var init_config = __esmMin((() => {
|
|
|
4196
4573
|
120
|
|
4197
4574
|
]
|
|
4198
4575
|
},
|
|
4199
|
-
cost_limits: {
|
|
4200
|
-
per_agent_usd: 10,
|
|
4201
|
-
per_issue_usd: 25,
|
|
4202
|
-
daily_total_usd: 100,
|
|
4203
|
-
alert_threshold: .8
|
|
4204
|
-
},
|
|
4205
4576
|
retention: {
|
|
4206
4577
|
agent_state_days: 7,
|
|
4207
4578
|
reviewer_state_days: 1,
|
|
@@ -4523,151 +4894,6 @@ var init_concurrency = __esmMin((() => {
|
|
|
4523
4894
|
swarmReservedThisPatrol = 0;
|
|
4524
4895
|
}));
|
|
4525
4896
|
//#endregion
|
|
4526
|
-
//#region ../../lib/agents/queries.ts
|
|
4527
|
-
function listRunningAgentsSync() {
|
|
4528
|
-
const tmuxSessions = listSessionsSync();
|
|
4529
|
-
const tmuxNames = new Set(tmuxSessions.map((s) => s.name));
|
|
4530
|
-
return listOverdeckAgentStatesSync().map((state) => {
|
|
4531
|
-
const normalizedId = normalizeAgentId(state.id);
|
|
4532
|
-
return {
|
|
4533
|
-
...state,
|
|
4534
|
-
id: normalizedId,
|
|
4535
|
-
tmuxActive: tmuxNames.has(normalizedId)
|
|
4536
|
-
};
|
|
4537
|
-
});
|
|
4538
|
-
}
|
|
4539
|
-
/**
|
|
4540
|
-
* PAN-1908: list all agents in the SQLite registry with optional filtering.
|
|
4541
|
-
* This is the replacement for enumerating ~/.overdeck/agents/ directories.
|
|
4542
|
-
*/
|
|
4543
|
-
function listAgentStates(options) {
|
|
4544
|
-
return listOverdeckAgentStatesSync().filter((state) => {
|
|
4545
|
-
if (options?.status && state.status !== options.status) return false;
|
|
4546
|
-
if (options?.role && state.role !== options.role) return false;
|
|
4547
|
-
return true;
|
|
4548
|
-
});
|
|
4549
|
-
}
|
|
4550
|
-
/**
|
|
4551
|
-
* PAN-1048 P2: async startup migration.
|
|
4552
|
-
*
|
|
4553
|
-
* The previous synchronous version used readdirSync, readFileSync,
|
|
4554
|
-
* killSession (sync tmux subprocess), and rmSync — all on the Node
|
|
4555
|
-
* event loop. Called from warnOnBareNumericIssueIds() during dashboard
|
|
4556
|
-
* read-model bootstrap, this blocked all HTTP/WebSocket/PTY traffic on
|
|
4557
|
-
* server startup while it scanned every agent dir, killed stale tmux
|
|
4558
|
-
* sessions, and recursively deleted directories.
|
|
4559
|
-
*
|
|
4560
|
-
* This async variant does the same work using fs/promises and the
|
|
4561
|
-
* already-async killSessionAsync() so the bootstrap path no longer
|
|
4562
|
-
* stalls the event loop.
|
|
4563
|
-
*/
|
|
4564
|
-
async function dropLegacyAgentStatesMissingRoleAsync() {
|
|
4565
|
-
if (!existsSync(AGENTS_DIR)) return 0;
|
|
4566
|
-
const fsp = await import("fs/promises");
|
|
4567
|
-
let entries;
|
|
4568
|
-
try {
|
|
4569
|
-
entries = await fsp.readdir(AGENTS_DIR);
|
|
4570
|
-
} catch {
|
|
4571
|
-
return 0;
|
|
4572
|
-
}
|
|
4573
|
-
let dropped = 0;
|
|
4574
|
-
await Promise.all(entries.map(async (entry) => {
|
|
4575
|
-
const dirPath = join$1(AGENTS_DIR, entry);
|
|
4576
|
-
let stat;
|
|
4577
|
-
try {
|
|
4578
|
-
stat = await fsp.stat(dirPath);
|
|
4579
|
-
} catch {
|
|
4580
|
-
return;
|
|
4581
|
-
}
|
|
4582
|
-
if (!stat.isDirectory()) return;
|
|
4583
|
-
const agentId = normalizeAgentId(entry);
|
|
4584
|
-
const stateFile = getRollbackAgentStatePath(agentId);
|
|
4585
|
-
let raw;
|
|
4586
|
-
try {
|
|
4587
|
-
const contents = await fsp.readFile(stateFile, "utf8");
|
|
4588
|
-
raw = JSON.parse(contents);
|
|
4589
|
-
} catch {
|
|
4590
|
-
return;
|
|
4591
|
-
}
|
|
4592
|
-
if (isRole(raw.role)) return;
|
|
4593
|
-
try {
|
|
4594
|
-
await Effect.runPromise(killSession(agentId));
|
|
4595
|
-
} catch {}
|
|
4596
|
-
try {
|
|
4597
|
-
await fsp.rm(dirPath, {
|
|
4598
|
-
recursive: true,
|
|
4599
|
-
force: true
|
|
4600
|
-
});
|
|
4601
|
-
dropped++;
|
|
4602
|
-
} catch (err) {
|
|
4603
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
4604
|
-
console.warn(`[agents] Failed to drop legacy agent state ${agentId}: ${msg}`);
|
|
4605
|
-
}
|
|
4606
|
-
}));
|
|
4607
|
-
return dropped;
|
|
4608
|
-
}
|
|
4609
|
-
/**
|
|
4610
|
-
* Scan ~/.overdeck/agents/ for state files with bare numeric issueIds
|
|
4611
|
-
* (e.g. "484" instead of "PAN-484") and log warnings to stderr.
|
|
4612
|
-
*
|
|
4613
|
-
* These workspaces were created before the pan- prefix convention and may
|
|
4614
|
-
* cause cross-tracker pollution if their in_review transition is triggered.
|
|
4615
|
-
* Called once at server startup to surface legacy state files.
|
|
4616
|
-
*/
|
|
4617
|
-
/**
|
|
4618
|
-
* PAN-1048 P2: bootstrap-path migration is async.
|
|
4619
|
-
*
|
|
4620
|
-
* Sweeps legacy state files missing a `role` field and warns on bare
|
|
4621
|
-
* numeric issueIds. Both passes used to be synchronous (readdirSync,
|
|
4622
|
-
* readFileSync, killSession, rmSync), which blocked the dashboard
|
|
4623
|
-
* server's event loop on startup. The async version scans the same
|
|
4624
|
-
* directory once per concern and uses fs/promises throughout.
|
|
4625
|
-
*/
|
|
4626
|
-
async function warnOnBareNumericIssueIds() {
|
|
4627
|
-
const droppedLegacyAgents = await dropLegacyAgentStatesMissingRoleAsync();
|
|
4628
|
-
if (droppedLegacyAgents > 0) console.warn(`[agents] Dropped ${droppedLegacyAgents} legacy agent state file(s) missing role`);
|
|
4629
|
-
if (!existsSync(AGENTS_DIR)) return;
|
|
4630
|
-
const fsp = await import("fs/promises");
|
|
4631
|
-
let entries;
|
|
4632
|
-
try {
|
|
4633
|
-
entries = await fsp.readdir(AGENTS_DIR);
|
|
4634
|
-
} catch {
|
|
4635
|
-
return;
|
|
4636
|
-
}
|
|
4637
|
-
const legacy = [];
|
|
4638
|
-
await Promise.all(entries.map(async (entry) => {
|
|
4639
|
-
const dirPath = join$1(AGENTS_DIR, entry);
|
|
4640
|
-
try {
|
|
4641
|
-
if (!(await fsp.stat(dirPath)).isDirectory()) return;
|
|
4642
|
-
} catch {
|
|
4643
|
-
return;
|
|
4644
|
-
}
|
|
4645
|
-
const state = await Effect.runPromise(getAgentState(entry));
|
|
4646
|
-
if (state?.issueId && /^\d+$/.test(state.issueId)) legacy.push(`${entry} (issueId: "${state.issueId}")`);
|
|
4647
|
-
}));
|
|
4648
|
-
if (legacy.length > 0) console.warn(`[agents] WARNING: ${legacy.length} agent state file(s) have bare numeric issueIds (created before the pan- prefix convention). These agents will not be able to transition tracker state. Consider removing or updating them:\n` + legacy.map((l) => ` ~/.overdeck/agents/${l}`).join("\n"));
|
|
4649
|
-
}
|
|
4650
|
-
var listRunningAgents;
|
|
4651
|
-
var init_queries = __esmMin((() => {
|
|
4652
|
-
init_agents();
|
|
4653
|
-
init_tmux();
|
|
4654
|
-
init_paths();
|
|
4655
|
-
init_agent_rollback_state();
|
|
4656
|
-
init_agent_state_sync();
|
|
4657
|
-
listRunningAgents = () => Effect.gen(function* () {
|
|
4658
|
-
const tmuxSessions = yield* listSessions();
|
|
4659
|
-
const tmuxNames = new Set(tmuxSessions.map((s) => s.name));
|
|
4660
|
-
return listOverdeckAgentStatesSync().map((state) => {
|
|
4661
|
-
const normalizedId = normalizeAgentId(state.id);
|
|
4662
|
-
return {
|
|
4663
|
-
...state,
|
|
4664
|
-
id: normalizedId,
|
|
4665
|
-
tmuxActive: tmuxNames.has(normalizedId)
|
|
4666
|
-
};
|
|
4667
|
-
});
|
|
4668
|
-
});
|
|
4669
|
-
}));
|
|
4670
|
-
//#endregion
|
|
4671
4897
|
//#region ../../lib/agents/termination.ts
|
|
4672
4898
|
/**
|
|
4673
4899
|
* True when the PID is a tmux process (client or server). Used to keep the
|
|
@@ -4701,7 +4927,7 @@ function killLauncherProcessSync(agentId) {
|
|
|
4701
4927
|
const launcherPath = join$1(AGENTS_DIR, agentId, "launcher.sh");
|
|
4702
4928
|
let pidsOut;
|
|
4703
4929
|
try {
|
|
4704
|
-
pidsOut = execSync
|
|
4930
|
+
pidsOut = execSync(`pgrep -f ${JSON.stringify(launcherPath)}`, {
|
|
4705
4931
|
encoding: "utf-8",
|
|
4706
4932
|
stdio: [
|
|
4707
4933
|
"ignore",
|
|
@@ -4718,7 +4944,7 @@ function killLauncherProcessSync(agentId) {
|
|
|
4718
4944
|
process.kill(pid, "SIGTERM");
|
|
4719
4945
|
} catch {}
|
|
4720
4946
|
try {
|
|
4721
|
-
execSync
|
|
4947
|
+
execSync("sleep 0.5", { stdio: "ignore" });
|
|
4722
4948
|
} catch {}
|
|
4723
4949
|
const survivors = [];
|
|
4724
4950
|
for (const pid of pids) try {
|
|
@@ -4733,7 +4959,7 @@ async function killLauncherProcessAsync(agentId) {
|
|
|
4733
4959
|
const launcherPath = join$1(AGENTS_DIR, agentId, "launcher.sh");
|
|
4734
4960
|
let pidsOut;
|
|
4735
4961
|
try {
|
|
4736
|
-
const { stdout } = await execAsync$
|
|
4962
|
+
const { stdout } = await execAsync$3(`pgrep -f ${JSON.stringify(launcherPath)}`);
|
|
4737
4963
|
pidsOut = stdout.trim();
|
|
4738
4964
|
} catch {
|
|
4739
4965
|
return;
|
|
@@ -4777,14 +5003,14 @@ function stopAgentSync(agentId) {
|
|
|
4777
5003
|
lastActivity: (/* @__PURE__ */ new Date()).toISOString()
|
|
4778
5004
|
});
|
|
4779
5005
|
}
|
|
4780
|
-
var execAsync$
|
|
5006
|
+
var execAsync$3, stopAgent;
|
|
4781
5007
|
var init_termination = __esmMin((() => {
|
|
4782
5008
|
init_agents();
|
|
4783
5009
|
init_agent_runtime();
|
|
4784
5010
|
init_paths();
|
|
4785
5011
|
init_tmux();
|
|
4786
5012
|
init_errors();
|
|
4787
|
-
execAsync$
|
|
5013
|
+
execAsync$3 = promisify$1(exec$1);
|
|
4788
5014
|
stopAgent = (agentId) => {
|
|
4789
5015
|
const normalizedId = normalizeAgentId(agentId);
|
|
4790
5016
|
return Effect.gen(function* () {
|
|
@@ -4835,44 +5061,25 @@ var init_termination = __esmMin((() => {
|
|
|
4835
5061
|
};
|
|
4836
5062
|
}));
|
|
4837
5063
|
//#endregion
|
|
4838
|
-
//#region ../../lib/
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
`, { mode: 493 });
|
|
4858
|
-
chmodSync$1(path, 493);
|
|
4859
|
-
return {
|
|
4860
|
-
binDir,
|
|
4861
|
-
pathPrefix: `${binDir}${delimiter}${process.env.PATH ?? ""}`
|
|
4862
|
-
};
|
|
4863
|
-
}
|
|
4864
|
-
async function resolveBdAgentShimPath(agentDir) {
|
|
4865
|
-
try {
|
|
4866
|
-
const { stdout } = await execAsync$3("command -v bd", { encoding: "utf8" });
|
|
4867
|
-
const realBd = stdout.trim();
|
|
4868
|
-
return realBd ? installBdAgentShim(agentDir, realBd).pathPrefix : void 0;
|
|
4869
|
-
} catch {
|
|
4870
|
-
return;
|
|
4871
|
-
}
|
|
4872
|
-
}
|
|
4873
|
-
var execAsync$3;
|
|
4874
|
-
var init_bd_shim = __esmMin((() => {
|
|
4875
|
-
execAsync$3 = promisify(exec);
|
|
5064
|
+
//#region ../../lib/agents/hook-readiness.ts
|
|
5065
|
+
/**
|
|
5066
|
+
* Ensure Claude's global lifecycle hooks are registered before the process can
|
|
5067
|
+
* emit SessionStart. This must be awaited: provisioning after launch races the
|
|
5068
|
+
* one event that writes ready.json and acknowledges kickoff delivery.
|
|
5069
|
+
*/
|
|
5070
|
+
async function ensureLifecycleHooksBeforeLaunch(agentId, harness) {
|
|
5071
|
+
if (harness !== "claude-code") return;
|
|
5072
|
+
const result = await provisionClaudeHooks();
|
|
5073
|
+
if (!result.ok) {
|
|
5074
|
+
const reason = result.reason ?? "unknown provisioning failure";
|
|
5075
|
+
logAgentLifecycleSync(agentId, `hook provisioning: failed harness=${harness} reason=${reason}`);
|
|
5076
|
+
throw new Error(`Claude Code lifecycle hooks are unavailable: ${reason}. Run \`pan up\` to install host prerequisites, then \`pan sync\` and retry.`);
|
|
5077
|
+
}
|
|
5078
|
+
logAgentLifecycleSync(agentId, `hook provisioning: ready harness=${harness} changed=${result.changed} binariesSynced=${result.binariesSynced} registered=${result.registered.length} pruned=${result.pruned.length}`);
|
|
5079
|
+
}
|
|
5080
|
+
var init_hook_readiness = __esmMin((() => {
|
|
5081
|
+
init_claude_hooks_provision();
|
|
5082
|
+
init_persistent_logger();
|
|
4876
5083
|
}));
|
|
4877
5084
|
//#endregion
|
|
4878
5085
|
//#region ../../lib/agents/spawn.ts
|
|
@@ -4923,18 +5130,18 @@ async function spawnRun(issueId, role, options = {}) {
|
|
|
4923
5130
|
let reapWarmIdle = false;
|
|
4924
5131
|
const advancing = role === "review" || role === "test" || role === "ship";
|
|
4925
5132
|
try {
|
|
4926
|
-
const { isPaneDead } = await import("./tmux-
|
|
5133
|
+
const { isPaneDead } = await import("./tmux-C-rgxRDA.js");
|
|
4927
5134
|
if (await Effect.runPromise(isPaneDead(agentId))) reapWarmIdle = true;
|
|
4928
5135
|
else if (advancing) {
|
|
4929
|
-
const { getReviewStatusSync } = await import("./review-status-
|
|
4930
|
-
const { isRoleTerminal } = await import("./reap-terminal-sessions-
|
|
5136
|
+
const { getReviewStatusSync } = await import("./review-status-77N3PoZr.js");
|
|
5137
|
+
const { isRoleTerminal } = await import("./reap-terminal-sessions-BR39qflC.js");
|
|
4931
5138
|
const status = getReviewStatusSync(issueId);
|
|
4932
5139
|
reapWarmIdle = !!status && isRoleTerminal(role, status);
|
|
4933
5140
|
}
|
|
4934
5141
|
} catch {}
|
|
4935
5142
|
if (!reapWarmIdle) throw new Error(`Role run ${agentId} already running. Use 'pan tell' to message it.`);
|
|
4936
5143
|
console.log(`[spawn] ${agentId} is warm-idle from the previous cycle — reaping it for the new ${role} dispatch (PAN-2579)`);
|
|
4937
|
-
const { killSession } = await import("./tmux-
|
|
5144
|
+
const { killSession } = await import("./tmux-C-rgxRDA.js");
|
|
4938
5145
|
await Effect.runPromise(killSession(agentId)).catch(() => {});
|
|
4939
5146
|
}
|
|
4940
5147
|
await assertWorkspaceStackHealthyForSpawn(issueId, role, options.allowHost, workspace);
|
|
@@ -4944,8 +5151,10 @@ async function spawnRun(issueId, role, options = {}) {
|
|
|
4944
5151
|
role,
|
|
4945
5152
|
model: selectedModel
|
|
4946
5153
|
});
|
|
5154
|
+
assertCodexNativeAuthForSpawn(resolvedHarness, listAgentStates());
|
|
5155
|
+
await ensureLifecycleHooksBeforeLaunch(agentId, resolvedHarness);
|
|
4947
5156
|
if (getProviderForModelSync(selectedModel).name === "openai" && await getProviderAuthMode(selectedModel) === "subscription") {
|
|
4948
|
-
const { isCliproxyRunning } = await import("./cliproxy-
|
|
5157
|
+
const { isCliproxyRunning } = await import("./cliproxy-BQX1TL6N.js");
|
|
4949
5158
|
if (!await Effect.runPromise(isCliproxyRunning())) throw new Error("CLIProxyAPI sidecar is not running. GPT subscription role runs route through a local cliproxy process managed by `pan up`. Run `pan up` (or restart the dashboard) before spawning a GPT role run.");
|
|
4950
5159
|
}
|
|
4951
5160
|
const state = {
|
|
@@ -4986,7 +5195,6 @@ async function spawnRun(issueId, role, options = {}) {
|
|
|
4986
5195
|
await Effect.runPromise(saveAgentState(state));
|
|
4987
5196
|
}
|
|
4988
5197
|
}
|
|
4989
|
-
checkAndSetupHooks();
|
|
4990
5198
|
const provider = getProviderForModelSync(selectedModel);
|
|
4991
5199
|
if (provider.authType === "credential-file") setupCredentialFileAuthSync(provider, workspace);
|
|
4992
5200
|
else clearCredentialFileAuthSync(workspace);
|
|
@@ -5054,7 +5262,7 @@ async function spawnRun(issueId, role, options = {}) {
|
|
|
5054
5262
|
const claudeCmd = `bash ${launcherScript}`;
|
|
5055
5263
|
console.log(`[claude-invoke] purpose=role-run | role=${role} | model=${state.model} | source=agents.ts:spawnRun | session=${agentId} | command="${claudeCmd}"`);
|
|
5056
5264
|
try {
|
|
5057
|
-
const { preTrustDirectory } = await import("./workspace-manager-
|
|
5265
|
+
const { preTrustDirectory } = await import("./workspace-manager-B1mYn0lN.js");
|
|
5058
5266
|
preTrustDirectory(workspace);
|
|
5059
5267
|
} catch {}
|
|
5060
5268
|
clearReadySignal(agentId);
|
|
@@ -5124,15 +5332,7 @@ async function spawnAgent(options) {
|
|
|
5124
5332
|
if (await Effect.runPromise(sessionExists(agentId))) throw new Error(`Agent ${agentId} already running. Use 'pan tell' to message it.`);
|
|
5125
5333
|
await assertWorkspaceStackHealthyForSpawn(options.issueId, role, options.allowHost, options.workspace);
|
|
5126
5334
|
initHookSync(agentId);
|
|
5127
|
-
if (role !== "strike" && role !== "knowledge" && options.slotItemId === void 0)
|
|
5128
|
-
await Effect.runPromise(assertIssueHasBeads(options.workspace, options.issueId, { acquisitionTimeoutMs: 500 }));
|
|
5129
|
-
} catch (error) {
|
|
5130
|
-
if (error instanceof BeadsMissingError && error.transientFailure !== void 0) {
|
|
5131
|
-
const attempts = error.transientFailure instanceof BdTransientFailure ? ` after ${error.transientFailure.attempts} attempts` : "";
|
|
5132
|
-
throw new Error(`Beads database was temporarily locked while checking ${options.issueId}${attempts}; re-run shortly.`);
|
|
5133
|
-
}
|
|
5134
|
-
throw error;
|
|
5135
|
-
}
|
|
5335
|
+
if (role !== "strike" && role !== "knowledge" && options.slotItemId === void 0 && !readWorkspacePlanSync(options.workspace)) throw new Error(`The required vBRIEF checklist for ${options.issueId} is missing or unreadable. Run planning before spawning a work agent.`);
|
|
5136
5336
|
const modelSpawnKey = `${role}:${options.issueId}`;
|
|
5137
5337
|
const singleTierParams = role === "work" && options.slotItemId === void 0 && options.slotIndex === void 0 ? resolveSingleWorkTierSpawnParams(options.workspace, options.model, modelSpawnKey) : {};
|
|
5138
5338
|
const selectedModel = determineModel({
|
|
@@ -5142,7 +5342,7 @@ async function spawnAgent(options) {
|
|
|
5142
5342
|
});
|
|
5143
5343
|
console.log(`[DEBUG] Selected model: ${selectedModel}`);
|
|
5144
5344
|
if (getProviderForModelSync(selectedModel).name === "openai" && await getProviderAuthMode(selectedModel) === "subscription") {
|
|
5145
|
-
const { isCliproxyRunning } = await import("./cliproxy-
|
|
5345
|
+
const { isCliproxyRunning } = await import("./cliproxy-BQX1TL6N.js");
|
|
5146
5346
|
if (!await Effect.runPromise(isCliproxyRunning())) throw new Error("CLIProxyAPI sidecar is not running. GPT subscription agents route through a local cliproxy process managed by `pan up`. Run `pan up` (or restart the dashboard) before spawning a GPT agent.");
|
|
5147
5347
|
}
|
|
5148
5348
|
const resolvedHarness = await resolveHarness({
|
|
@@ -5150,6 +5350,8 @@ async function spawnAgent(options) {
|
|
|
5150
5350
|
role,
|
|
5151
5351
|
model: selectedModel
|
|
5152
5352
|
});
|
|
5353
|
+
assertCodexNativeAuthForSpawn(resolvedHarness, listAgentStates());
|
|
5354
|
+
await ensureLifecycleHooksBeforeLaunch(agentId, resolvedHarness);
|
|
5153
5355
|
const state = {
|
|
5154
5356
|
id: agentId,
|
|
5155
5357
|
issueId: options.issueId,
|
|
@@ -5161,14 +5363,15 @@ async function spawnAgent(options) {
|
|
|
5161
5363
|
status: "starting",
|
|
5162
5364
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5163
5365
|
costSoFar: 0,
|
|
5164
|
-
hostOverride: options.allowHost || void 0
|
|
5366
|
+
hostOverride: options.allowHost || void 0,
|
|
5367
|
+
sessionId: createFreshSessionIdentity(agentId, resolvedHarness)
|
|
5165
5368
|
};
|
|
5166
5369
|
const supervisorLaunch = await prepareSupervisorForFreshLaunch(agentId, options, state);
|
|
5167
5370
|
saveAgentStateSync(state);
|
|
5168
5371
|
if (role === "work") {
|
|
5169
5372
|
try {
|
|
5170
5373
|
if (resetPipelineVerdictsForWorkStartSync(options.issueId)) {
|
|
5171
|
-
const { resetPostMergeState } = await import("./merge-agent-
|
|
5374
|
+
const { resetPostMergeState } = await import("./merge-agent-DMQTJMP0.js");
|
|
5172
5375
|
resetPostMergeState(options.issueId);
|
|
5173
5376
|
}
|
|
5174
5377
|
} catch (err) {
|
|
@@ -5179,7 +5382,7 @@ async function spawnAgent(options) {
|
|
|
5179
5382
|
});
|
|
5180
5383
|
}
|
|
5181
5384
|
if (role === "work") try {
|
|
5182
|
-
const { writeStoryFeatureContext } = await import("./work-agent-prompt-
|
|
5385
|
+
const { writeStoryFeatureContext } = await import("./work-agent-prompt-BiJ43Der.js");
|
|
5183
5386
|
await writeStoryFeatureContext(options.workspace, options.issueId);
|
|
5184
5387
|
} catch (ctxErr) {
|
|
5185
5388
|
console.warn(`[agents] Could not write story feature context for ${options.issueId}: ${ctxErr.message}`);
|
|
@@ -5225,11 +5428,10 @@ async function spawnAgent(options) {
|
|
|
5225
5428
|
saveAgentStateSync(state);
|
|
5226
5429
|
}
|
|
5227
5430
|
}
|
|
5228
|
-
checkAndSetupHooks();
|
|
5229
5431
|
try {
|
|
5230
5432
|
const venvPath = join$1(options.workspace, ".venv");
|
|
5231
5433
|
if (isTldrEnabledSync() && existsSync(venvPath)) {
|
|
5232
|
-
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-
|
|
5434
|
+
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-DhGwd88s.js");
|
|
5233
5435
|
const tldrService = getTldrDaemonServiceSync(options.workspace, venvPath);
|
|
5234
5436
|
if (!(await tldrService.getStatus()).running) {
|
|
5235
5437
|
await tldrService.start(true);
|
|
@@ -5259,21 +5461,23 @@ async function spawnAgent(options) {
|
|
|
5259
5461
|
useSupervisor: supervisorLaunch.useSupervisor,
|
|
5260
5462
|
supervisorScriptPath: supervisorLaunch.supervisorScriptPath,
|
|
5261
5463
|
harness: state.harness ?? "claude-code",
|
|
5464
|
+
sessionId: state.sessionId,
|
|
5262
5465
|
extraEnvExports: flywheelEnvExports(flywheelEnv),
|
|
5263
5466
|
effort: options.effort
|
|
5264
5467
|
});
|
|
5265
5468
|
const launcherScript = join$1(getAgentDir(agentId), "launcher.sh");
|
|
5266
5469
|
await writeLauncherScriptAtomic(launcherScript, launcherContent);
|
|
5470
|
+
if (state.sessionId) logLauncherSessionPinned(agentId, state.sessionId, launcherScript);
|
|
5267
5471
|
const claudeCmd = `bash ${launcherScript}`;
|
|
5268
5472
|
console.log(`[claude-invoke] purpose=work-agent | model=${state.model} | source=agents.ts:spawnAgent | session=${agentId} | command="${claudeCmd}"`);
|
|
5269
5473
|
try {
|
|
5270
|
-
const { preTrustDirectory } = await import("./workspace-manager-
|
|
5474
|
+
const { preTrustDirectory } = await import("./workspace-manager-B1mYn0lN.js");
|
|
5271
5475
|
preTrustDirectory(options.workspace);
|
|
5272
5476
|
} catch {}
|
|
5273
5477
|
try {
|
|
5274
|
-
const { isGitHubAppConfigured, generateInstallationToken, configureWorkspaceForBot } = await import("./github-app-
|
|
5478
|
+
const { isGitHubAppConfigured, generateInstallationToken, configureWorkspaceForBot } = await import("./github-app-BrYwK_Gb.js");
|
|
5275
5479
|
if (isGitHubAppConfigured()) {
|
|
5276
|
-
const { findProjectByPathSync } = await import("./projects-
|
|
5480
|
+
const { findProjectByPathSync } = await import("./projects-Dc9aoVoG.js");
|
|
5277
5481
|
const ghRepo = findProjectByPathSync(resolve$1(options.workspace, "..", ".."))?.github_repo;
|
|
5278
5482
|
if (ghRepo) {
|
|
5279
5483
|
const [owner, repo] = ghRepo.split("/");
|
|
@@ -5286,7 +5490,6 @@ async function spawnAgent(options) {
|
|
|
5286
5490
|
console.warn(`[${agentId}] GitHub App config failed (falling back to SSH): ${err.message}`);
|
|
5287
5491
|
}
|
|
5288
5492
|
clearReadySignal(agentId);
|
|
5289
|
-
const bdShimPath = role === "work" ? await resolveBdAgentShimPath(getAgentDir(agentId)) : void 0;
|
|
5290
5493
|
await Effect.runPromise(createSession(agentId, options.workspace, claudeCmd, { env: {
|
|
5291
5494
|
...BLANKED_PROVIDER_ENV,
|
|
5292
5495
|
TERM: "xterm-256color",
|
|
@@ -5295,11 +5498,11 @@ async function spawnAgent(options) {
|
|
|
5295
5498
|
OVERDECK_SESSION_TYPE: role,
|
|
5296
5499
|
CLAUDE_CODE_ENABLE_PROMPT_SUGGESTION: "false",
|
|
5297
5500
|
GIT_SEQUENCE_EDITOR: "false",
|
|
5298
|
-
...bdShimPath ? { PATH: bdShimPath } : {},
|
|
5299
5501
|
...flywheelEnv,
|
|
5300
5502
|
...providerEnv
|
|
5301
5503
|
} }));
|
|
5302
5504
|
await saveAgentRuntimeState(agentId, {
|
|
5505
|
+
claudeSessionId: state.sessionId,
|
|
5303
5506
|
sessionModel: selectedModel,
|
|
5304
5507
|
sessionHarness: resolvedHarness
|
|
5305
5508
|
});
|
|
@@ -5343,7 +5546,7 @@ async function spawnAgent(options) {
|
|
|
5343
5546
|
const codexHomeForAgent = join$1(homedir(), ".overdeck", "agents", agentId, "codex-home");
|
|
5344
5547
|
(async () => {
|
|
5345
5548
|
try {
|
|
5346
|
-
const { waitForCodexRollout, extractThreadIdFromRollout, writeThreadId } = await import("./codex-
|
|
5549
|
+
const { waitForCodexRollout, extractThreadIdFromRollout, writeThreadId } = await import("./codex-DxLivxri.js");
|
|
5347
5550
|
const rollout = await waitForCodexRollout(codexHomeForAgent, 12e4);
|
|
5348
5551
|
if (rollout) {
|
|
5349
5552
|
const threadId = extractThreadIdFromRollout(rollout);
|
|
@@ -5423,26 +5626,6 @@ function escapeRegExp$1(value) {
|
|
|
5423
5626
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5424
5627
|
}
|
|
5425
5628
|
/**
|
|
5426
|
-
* Check if Overdeck hooks are configured, and auto-setup if not
|
|
5427
|
-
*/
|
|
5428
|
-
function checkAndSetupHooks() {
|
|
5429
|
-
const settingsPath = join$1(homedir(), ".claude", "settings.json");
|
|
5430
|
-
const hookPath = join$1(homedir(), ".overdeck", "bin", "heartbeat-hook");
|
|
5431
|
-
if (existsSync(settingsPath)) try {
|
|
5432
|
-
const settingsContent = readFileSync(settingsPath, "utf-8");
|
|
5433
|
-
if ((JSON.parse(settingsContent)?.hooks?.PostToolUse || []).some((hookConfig) => hookConfig.hooks?.some((hook) => hook.command === hookPath || hook.command?.includes("overdeck") || hook.command?.includes("heartbeat-hook")))) return;
|
|
5434
|
-
} catch {}
|
|
5435
|
-
try {
|
|
5436
|
-
console.log("Configuring Overdeck heartbeat hooks...");
|
|
5437
|
-
exec$1("pan admin hooks install", (error) => {
|
|
5438
|
-
if (error) console.warn("⚠ Failed to auto-configure hooks. Run `pan admin hooks install` manually.");
|
|
5439
|
-
else console.log("✓ Heartbeat hooks configured");
|
|
5440
|
-
});
|
|
5441
|
-
} catch (error) {
|
|
5442
|
-
console.warn("⚠ Failed to auto-configure hooks. Run `pan admin hooks install` manually.");
|
|
5443
|
-
}
|
|
5444
|
-
}
|
|
5445
|
-
/**
|
|
5446
5629
|
* Write task cache for heartbeat hook to use
|
|
5447
5630
|
*/
|
|
5448
5631
|
function writeTaskCache(agentId, issueId) {
|
|
@@ -5457,8 +5640,6 @@ function writeTaskCache(agentId, issueId) {
|
|
|
5457
5640
|
var execAsync$2;
|
|
5458
5641
|
var init_spawn = __esmMin((() => {
|
|
5459
5642
|
init_activity_logger();
|
|
5460
|
-
init_beads_query();
|
|
5461
|
-
init_bd_process_lock();
|
|
5462
5643
|
init_child_env();
|
|
5463
5644
|
init_config_yaml();
|
|
5464
5645
|
init_conversations();
|
|
@@ -5468,6 +5649,7 @@ var init_spawn = __esmMin((() => {
|
|
|
5468
5649
|
init_providers();
|
|
5469
5650
|
init_review_status();
|
|
5470
5651
|
init_harness_resolve();
|
|
5652
|
+
init_codex_auth();
|
|
5471
5653
|
init_bridge_token();
|
|
5472
5654
|
init_tmux();
|
|
5473
5655
|
init_dag();
|
|
@@ -5486,7 +5668,8 @@ var init_spawn = __esmMin((() => {
|
|
|
5486
5668
|
init_state_read_home();
|
|
5487
5669
|
init_supervisor_channels();
|
|
5488
5670
|
init_termination();
|
|
5489
|
-
|
|
5671
|
+
init_session_history();
|
|
5672
|
+
init_hook_readiness();
|
|
5490
5673
|
execAsync$2 = promisify$1(exec$1);
|
|
5491
5674
|
}));
|
|
5492
5675
|
//#endregion
|
|
@@ -5917,9 +6100,7 @@ function getActivity(agentId, limit = 100) {
|
|
|
5917
6100
|
* Save Claude session ID for later resume
|
|
5918
6101
|
*/
|
|
5919
6102
|
function saveSessionId(agentId, sessionId) {
|
|
5920
|
-
|
|
5921
|
-
mkdirSync(dir, { recursive: true });
|
|
5922
|
-
writeFileSync(join$1(dir, "session.id"), sessionId);
|
|
6103
|
+
persistCurrentSessionId(agentId, sessionId);
|
|
5923
6104
|
}
|
|
5924
6105
|
/**
|
|
5925
6106
|
* Get saved Claude session ID
|
|
@@ -6024,6 +6205,7 @@ var init_activity = __esmMin((() => {
|
|
|
6024
6205
|
init_ohmypi();
|
|
6025
6206
|
init_behavior();
|
|
6026
6207
|
init_errors();
|
|
6208
|
+
init_session_history();
|
|
6027
6209
|
getLatestSessionId = (agentId) => {
|
|
6028
6210
|
const agentDir = getAgentDir(agentId);
|
|
6029
6211
|
const sessionFile = join$1(agentDir, "session.id");
|
|
@@ -6102,9 +6284,24 @@ async function appendTellInterventionForUserSource(normalizedId, caller) {
|
|
|
6102
6284
|
source: caller
|
|
6103
6285
|
});
|
|
6104
6286
|
}
|
|
6105
|
-
async function messageAgent(agentId, message, caller = "internal") {
|
|
6287
|
+
async function messageAgent(agentId, message, caller = "internal", opts = {}) {
|
|
6106
6288
|
const normalizedId = normalizeAgentId(agentId);
|
|
6107
6289
|
const agentState = getAgentStateSync(normalizedId);
|
|
6290
|
+
const decideMessageGate = () => {
|
|
6291
|
+
const block = agentState ? getAgentResumeGateBlockReason(agentState) : void 0;
|
|
6292
|
+
const agentDir = getAgentDir(normalizedId);
|
|
6293
|
+
const decision = decideResumeGate(block, "message-delivery", {
|
|
6294
|
+
hasCompletedHandoff: existsSync(join$1(agentDir, "completed")) || existsSync(join$1(agentDir, "completed.processed")),
|
|
6295
|
+
owesRework: opts.owesRework === true
|
|
6296
|
+
});
|
|
6297
|
+
if (decision.decision === "proceed" && decision.clearStoppedByUser && agentState) {
|
|
6298
|
+
console.log(`[agents] ${normalizedId} was operator-stopped but owes rework after a completed handoff — clearing stop gate to deliver feedback (PAN-2668)`);
|
|
6299
|
+
logAgentLifecycleSync(normalizedId, "stoppedByUser cleared: completed handoff owes rework; delivering pipeline feedback (PAN-2668)");
|
|
6300
|
+
delete agentState.stoppedByUser;
|
|
6301
|
+
saveAgentStateSync(agentState);
|
|
6302
|
+
}
|
|
6303
|
+
return decision;
|
|
6304
|
+
};
|
|
6108
6305
|
if (agentState?.paused === true) {
|
|
6109
6306
|
const gateBlockReason = getAgentResumeGateBlockReason(agentState)?.reason ?? "agent is paused";
|
|
6110
6307
|
queueAgentMail(normalizedId, message);
|
|
@@ -6113,15 +6310,16 @@ async function messageAgent(agentId, message, caller = "internal") {
|
|
|
6113
6310
|
return;
|
|
6114
6311
|
}
|
|
6115
6312
|
if (getAgentRuntimeStateSync(normalizedId)?.state === "suspended") {
|
|
6116
|
-
const
|
|
6117
|
-
if (
|
|
6313
|
+
const suspendedGate = decideMessageGate();
|
|
6314
|
+
if (suspendedGate.decision !== "proceed") {
|
|
6315
|
+
const gateBlockReason = suspendedGate.reason ?? "agent is gated";
|
|
6118
6316
|
queueAgentMail(normalizedId, message);
|
|
6119
6317
|
logAgentLifecycleSync(normalizedId, `messageAgent queued mail without resume: ${gateBlockReason}`);
|
|
6120
6318
|
console.log(`[agents] Queued message for ${normalizedId}; ${gateBlockReason}`);
|
|
6121
6319
|
return;
|
|
6122
6320
|
}
|
|
6123
6321
|
console.log(`[agents] Auto-resuming suspended agent ${normalizedId} to deliver message`);
|
|
6124
|
-
const { resumeAgent } = await import("./agents-
|
|
6322
|
+
const { resumeAgent } = await import("./agents-BA15AQqo.js");
|
|
6125
6323
|
const result = await resumeAgent(normalizedId, message);
|
|
6126
6324
|
if (!result.success) throw new Error(`Failed to auto-resume agent: ${result.error}`);
|
|
6127
6325
|
if (result.messageDelivered === false) throw new Error(`Agent resumed but ready signal did not fire — message not delivered. Feedback is in the mail queue.`);
|
|
@@ -6129,15 +6327,16 @@ async function messageAgent(agentId, message, caller = "internal") {
|
|
|
6129
6327
|
return;
|
|
6130
6328
|
}
|
|
6131
6329
|
if (agentState && agentState.status === "stopped") {
|
|
6132
|
-
const
|
|
6133
|
-
if (
|
|
6330
|
+
const stoppedGate = decideMessageGate();
|
|
6331
|
+
if (stoppedGate.decision !== "proceed") {
|
|
6332
|
+
const gateBlockReason = stoppedGate.reason ?? "agent is gated";
|
|
6134
6333
|
queueAgentMail(normalizedId, message);
|
|
6135
6334
|
logAgentLifecycleSync(normalizedId, `messageAgent queued mail without resume: ${gateBlockReason}`);
|
|
6136
6335
|
console.log(`[agents] Queued message for ${normalizedId}; ${gateBlockReason}`);
|
|
6137
6336
|
return;
|
|
6138
6337
|
}
|
|
6139
6338
|
console.log(`[agents] Auto-resuming stopped agent ${normalizedId} to deliver feedback (session exists: ${await Effect.runPromise(sessionExists(normalizedId))})`);
|
|
6140
|
-
const { resumeAgent } = await import("./agents-
|
|
6339
|
+
const { resumeAgent } = await import("./agents-BA15AQqo.js");
|
|
6141
6340
|
const resumeResult = await resumeAgent(normalizedId, message);
|
|
6142
6341
|
queueAgentMail(normalizedId, message);
|
|
6143
6342
|
if (resumeResult.success && resumeResult.messageDelivered !== false) {
|
|
@@ -6173,7 +6372,7 @@ async function messageAgent(agentId, message, caller = "internal") {
|
|
|
6173
6372
|
const resumeRole = agentState.role ?? "work";
|
|
6174
6373
|
const resumeModel = agentState.model || "claude-sonnet-4-6";
|
|
6175
6374
|
const fallbackHarness = agentState.harness ?? "claude-code";
|
|
6176
|
-
const { assertWorkspaceStackHealthyForSpawn } = await import("./agents-
|
|
6375
|
+
const { assertWorkspaceStackHealthyForSpawn } = await import("./agents-BA15AQqo.js");
|
|
6177
6376
|
await assertWorkspaceStackHealthyForSpawn(agentState.issueId || normalizedId.replace(/^agent-/, "").toUpperCase(), resumeRole, agentState.hostOverride === true, agentState.workspace);
|
|
6178
6377
|
const fallbackPiFields = fallbackHarness === "ohmypi" ? await getOhmypiLauncherFields(normalizedId, resumeModel) : {};
|
|
6179
6378
|
const fallbackCodexFields = fallbackHarness === "codex" ? getCodexLauncherFields(normalizedId, resumeModel, agentState.workspace) : {};
|
|
@@ -6236,7 +6435,7 @@ async function messageAgent(agentId, message, caller = "internal") {
|
|
|
6236
6435
|
} else console.warn(`[agents] Fallback-restarted ${normalizedId} but ready signal not detected — feedback in mail queue`);
|
|
6237
6436
|
return;
|
|
6238
6437
|
}
|
|
6239
|
-
const { loadRemoteAgentState, sendToRemoteAgent } = await import("./remote-agents-
|
|
6438
|
+
const { loadRemoteAgentState, sendToRemoteAgent } = await import("./remote-agents-DYY5fFpd.js");
|
|
6240
6439
|
const remoteState = loadRemoteAgentState(normalizedId);
|
|
6241
6440
|
if (remoteState && remoteState.vmName) {
|
|
6242
6441
|
console.log(`[agents] Sending message to remote agent ${normalizedId} on ${remoteState.vmName}`);
|
|
@@ -6250,7 +6449,7 @@ async function messageAgent(agentId, message, caller = "internal") {
|
|
|
6250
6449
|
const expectedHarness = agentState?.harness ?? "claude-code";
|
|
6251
6450
|
if (panePids.length > 0 && !await hasAgentRuntimeInSubtree(panePids[0], expectedHarness)) {
|
|
6252
6451
|
console.warn(`[agents] ${normalizedId} tmux session is a zombie (no ${expectedHarness} runtime) — attempting resume`);
|
|
6253
|
-
const { resumeAgent } = await import("./agents-
|
|
6452
|
+
const { resumeAgent } = await import("./agents-BA15AQqo.js");
|
|
6254
6453
|
const resumeResult = await resumeAgent(normalizedId, message);
|
|
6255
6454
|
if (resumeResult.success) {
|
|
6256
6455
|
if (resumeResult.messageDelivered !== false) await appendTellInterventionForUserSource(normalizedId, caller);
|
|
@@ -6318,7 +6517,7 @@ function buildCompactRecoverySeedMessage(issueId, summary) {
|
|
|
6318
6517
|
const lines = [`Your previous session for ${issueId} hit the model's context-window limit, so you are starting a fresh session. This freed tokens; it did not reset your filesystem work.`, "Do NOT start over and do NOT expect the prior conversation to be available."];
|
|
6319
6518
|
if (summary) lines.push("", "Summary of the archived session:", "", summary, "");
|
|
6320
6519
|
else lines.push("");
|
|
6321
|
-
lines.push("Reconstruct your exact work-in-progress from durable artifacts:", "1. Read .pan/continue.json for resumePoint, decisions, hazards, feedback, and sessionHistory.", "2. Run `
|
|
6520
|
+
lines.push("Reconstruct your exact work-in-progress from durable artifacts:", "1. Read .pan/continue.json for resumePoint, decisions, hazards, feedback, and sessionHistory.", "2. Run `pan task next` for the next open item and `pan task show <issue> <item>` for its current state.", "3. Inspect `git status` and `git diff` for uncommitted work already on disk.", "Then continue from that reconstructed state and complete the next required bead — do not wait for further instructions.");
|
|
6322
6521
|
return lines.join("\n");
|
|
6323
6522
|
}
|
|
6324
6523
|
var CONTEXT_OVERFLOW_PATTERNS;
|
|
@@ -6362,7 +6561,7 @@ async function buildCompactRecoverySeed(agentId) {
|
|
|
6362
6561
|
if (agentState?.workspace && sessionId) {
|
|
6363
6562
|
const sessionFile = sessionFilePath(agentState.workspace, sessionId);
|
|
6364
6563
|
try {
|
|
6365
|
-
const [{ getConversationCompactionSettings }, { generateSmartSummary }] = await Promise.all([import("./conversation-compaction-
|
|
6564
|
+
const [{ getConversationCompactionSettings }, { generateSmartSummary }] = await Promise.all([import("./conversation-compaction-CRKAf2qP.js"), import("./smart-compaction-DldUel4B.js")]);
|
|
6366
6565
|
const settings = getConversationCompactionSettings();
|
|
6367
6566
|
summary = (await Effect.runPromise(generateSmartSummary({
|
|
6368
6567
|
jsonlPath: sessionFile,
|
|
@@ -6373,7 +6572,7 @@ async function buildCompactRecoverySeed(agentId) {
|
|
|
6373
6572
|
} catch (err) {
|
|
6374
6573
|
logAgentLifecycleSync(normalizedId, `compact-recovery smart summary failed (${err instanceof Error ? err.message : String(err)}); trying heuristic fallback`);
|
|
6375
6574
|
try {
|
|
6376
|
-
const { generateFallbackSummary } = await import("./summary-fork-
|
|
6575
|
+
const { generateFallbackSummary } = await import("./summary-fork-BxnF8Xh0.js");
|
|
6377
6576
|
summary = await Effect.runPromise(generateFallbackSummary(sessionFile));
|
|
6378
6577
|
} catch (fallbackErr) {
|
|
6379
6578
|
logAgentLifecycleSync(normalizedId, `compact-recovery fallback summary failed (${fallbackErr instanceof Error ? fallbackErr.message : String(fallbackErr)}); seeding with reseed instructions only`);
|
|
@@ -6990,7 +7189,7 @@ function generateRecoveryPrompt(state) {
|
|
|
6990
7189
|
`- Started: ${state.startedAt}`,
|
|
6991
7190
|
"",
|
|
6992
7191
|
"## Recovery Steps",
|
|
6993
|
-
"1. Check
|
|
7192
|
+
"1. Check the vBRIEF task state: `pan task show " + state.issueId + " <item-id>`",
|
|
6994
7193
|
"2. Review recent git commits: `git log --oneline -10`",
|
|
6995
7194
|
"3. Check hook for pending work: `pan admin fpp check`",
|
|
6996
7195
|
"4. Resume from last known state",
|
|
@@ -7192,10 +7391,10 @@ function computeTierRunSchedule(doc, config) {
|
|
|
7192
7391
|
if (!item) continue;
|
|
7193
7392
|
const tier = resolveTier(item, config);
|
|
7194
7393
|
const currentRun = runs[runs.length - 1];
|
|
7195
|
-
if (currentRun && currentRun.tierName === tier.tierName) currentRun.
|
|
7394
|
+
if (currentRun && currentRun.tierName === tier.tierName) currentRun.itemIds.push(item.id);
|
|
7196
7395
|
else runs.push({
|
|
7197
7396
|
tierName: tier.tierName,
|
|
7198
|
-
|
|
7397
|
+
itemIds: [item.id]
|
|
7199
7398
|
});
|
|
7200
7399
|
}
|
|
7201
7400
|
return runs;
|
|
@@ -7229,20 +7428,20 @@ function applyEffectiveDifficulty(item, overrides) {
|
|
|
7229
7428
|
* retry event persistence, tier promotion writes, dispatch, and notifications.
|
|
7230
7429
|
*/
|
|
7231
7430
|
function decideEscalation(trigger, bead, config, overrides) {
|
|
7232
|
-
const
|
|
7431
|
+
const itemId = trigger.itemId || bead.id;
|
|
7233
7432
|
const override = overrides[bead.id];
|
|
7234
7433
|
const currentDifficulty = override?.effectiveDifficulty ?? bead.metadata?.difficulty;
|
|
7235
7434
|
if (!currentDifficulty) return {
|
|
7236
7435
|
action: "block",
|
|
7237
|
-
reason: `
|
|
7436
|
+
reason: `task ${itemId} has no effective difficulty`
|
|
7238
7437
|
};
|
|
7239
7438
|
if ((override?.promotions ?? 0) >= config.max_promotions) return {
|
|
7240
7439
|
action: "block",
|
|
7241
|
-
reason: `max promotions reached for ${
|
|
7440
|
+
reason: `max promotions reached for ${itemId} at ${currentDifficulty}`
|
|
7242
7441
|
};
|
|
7243
7442
|
if (currentDifficulty === "expert") return {
|
|
7244
7443
|
action: "block",
|
|
7245
|
-
reason: `expert
|
|
7444
|
+
reason: `expert task ${itemId} cannot promote beyond expert`
|
|
7246
7445
|
};
|
|
7247
7446
|
const attemptsAtCurrentTier = trigger.attemptsAtCurrentTier ?? 0;
|
|
7248
7447
|
if (attemptsAtCurrentTier < config.retries_at_tier) return {
|
|
@@ -7252,7 +7451,7 @@ function decideEscalation(trigger, bead, config, overrides) {
|
|
|
7252
7451
|
const to = TIERED_EXECUTION_DIFFICULTIES[TIERED_EXECUTION_DIFFICULTIES.indexOf(currentDifficulty) + 1];
|
|
7253
7452
|
if (!to) return {
|
|
7254
7453
|
action: "block",
|
|
7255
|
-
reason: `
|
|
7454
|
+
reason: `task ${itemId} cannot promote beyond ${currentDifficulty}`
|
|
7256
7455
|
};
|
|
7257
7456
|
return {
|
|
7258
7457
|
action: "promote",
|
|
@@ -7324,20 +7523,20 @@ function resolveFeedApiUrl(env = process.env) {
|
|
|
7324
7523
|
}
|
|
7325
7524
|
/**
|
|
7326
7525
|
* Compose the ingestion-only feed message for one commit. Deterministic over
|
|
7327
|
-
* (sha,
|
|
7526
|
+
* (sha, itemTitle, diff) so replay reconstructs byte-identical messages.
|
|
7328
7527
|
*/
|
|
7329
|
-
function composeCommitFeedMessage(sha,
|
|
7528
|
+
function composeCommitFeedMessage(sha, itemTitle, diff, callout) {
|
|
7330
7529
|
const lines = [
|
|
7331
7530
|
`# Commit feed (ingestion-only): ${sha}`,
|
|
7332
7531
|
"",
|
|
7333
|
-
`Bead: ${
|
|
7532
|
+
`Bead: ${itemTitle}`,
|
|
7334
7533
|
""
|
|
7335
7534
|
];
|
|
7336
7535
|
if (callout) {
|
|
7337
7536
|
const body = JSON.stringify({
|
|
7338
7537
|
issueId: callout.issueId,
|
|
7339
7538
|
sha,
|
|
7340
|
-
|
|
7539
|
+
itemId: callout.itemId,
|
|
7341
7540
|
tierName: callout.tierName,
|
|
7342
7541
|
agentId: callout.agentId,
|
|
7343
7542
|
claim: "<one sentence: what is wrong and where>"
|
|
@@ -7354,22 +7553,22 @@ function composeCommitFeedMessage(sha, beadTitle, diff, callout) {
|
|
|
7354
7553
|
*/
|
|
7355
7554
|
async function broadcastCommit(options) {
|
|
7356
7555
|
const feedConfig = options.feedConfig ?? DEFAULT_FEED_CONFIG;
|
|
7357
|
-
if (shouldSkipFeedSubject(options.commitSubject ?? options.
|
|
7556
|
+
if (shouldSkipFeedSubject(options.commitSubject ?? options.itemTitle, feedConfig)) return [];
|
|
7358
7557
|
const renderDiff = options.renderDiff ?? (options.gitShow ? (workspace, sha) => options.gitShow(workspace, sha) : renderCommitFeedDiff);
|
|
7359
7558
|
const deliver = options.deliver ?? deliverAgentMessage;
|
|
7360
7559
|
const recordDelivery = options.recordDelivery ?? recordTierFeedDelivery;
|
|
7361
7560
|
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
7362
7561
|
const diff = await renderDiff(options.workspace, options.sha, feedConfig);
|
|
7363
|
-
const baseMessage = composeCommitFeedMessage(options.sha, options.
|
|
7562
|
+
const baseMessage = composeCommitFeedMessage(options.sha, options.itemTitle, diff);
|
|
7364
7563
|
const baseTokenCount = estimateFeedDeliveryTokens(baseMessage);
|
|
7365
|
-
const includeCallout = feedConfig.callouts !== "off" && options.issueId !== void 0 && options.
|
|
7564
|
+
const includeCallout = feedConfig.callouts !== "off" && options.issueId !== void 0 && options.itemId !== void 0;
|
|
7366
7565
|
const apiUrl = options.apiUrl ?? resolveFeedApiUrl();
|
|
7367
7566
|
const deliveries = [];
|
|
7368
7567
|
for (const tier of options.tiers) {
|
|
7369
|
-
const message = includeCallout ? composeCommitFeedMessage(options.sha, options.
|
|
7568
|
+
const message = includeCallout ? composeCommitFeedMessage(options.sha, options.itemTitle, diff, {
|
|
7370
7569
|
apiUrl,
|
|
7371
7570
|
issueId: options.issueId,
|
|
7372
|
-
|
|
7571
|
+
itemId: options.itemId,
|
|
7373
7572
|
tierName: tier.tierName,
|
|
7374
7573
|
agentId: tier.agentId
|
|
7375
7574
|
}) : baseMessage;
|
|
@@ -7388,7 +7587,7 @@ async function broadcastCommit(options) {
|
|
|
7388
7587
|
ts: now().toISOString(),
|
|
7389
7588
|
issueId: options.issueId,
|
|
7390
7589
|
sha: options.sha,
|
|
7391
|
-
|
|
7590
|
+
itemTitle: options.itemTitle,
|
|
7392
7591
|
tierName: tier.tierName,
|
|
7393
7592
|
agentId: tier.agentId,
|
|
7394
7593
|
tokenCount,
|
|
@@ -7467,10 +7666,10 @@ function shouldSupervise(bead, policy, options = {}) {
|
|
|
7467
7666
|
* is stable across the live commit feed, replay re-delivery (tier-replay),
|
|
7468
7667
|
* and tests.
|
|
7469
7668
|
*/
|
|
7470
|
-
function sampleFraction(
|
|
7669
|
+
function sampleFraction(itemId) {
|
|
7471
7670
|
let hash = 2166136261;
|
|
7472
|
-
for (let i = 0; i <
|
|
7473
|
-
hash ^=
|
|
7671
|
+
for (let i = 0; i < itemId.length; i++) {
|
|
7672
|
+
hash ^= itemId.charCodeAt(i);
|
|
7474
7673
|
hash = Math.imul(hash, 16777619);
|
|
7475
7674
|
}
|
|
7476
7675
|
return (hash >>> 0) / 4294967296;
|
|
@@ -7587,7 +7786,7 @@ You are the standing supervisor for ${event.issueId}. Review this commit against
|
|
|
7587
7786
|
## Bead under review
|
|
7588
7787
|
|
|
7589
7788
|
- Issue: ${event.issueId}
|
|
7590
|
-
- Bead: ${event.
|
|
7789
|
+
- Bead: ${event.itemId} — ${event.itemTitle}
|
|
7591
7790
|
- Commit: ${event.sha}
|
|
7592
7791
|
|
|
7593
7792
|
## Acceptance criteria
|
|
@@ -7602,14 +7801,14 @@ ${event.diff}
|
|
|
7602
7801
|
|
|
7603
7802
|
## Verdict (REQUIRED — post exactly one)
|
|
7604
7803
|
|
|
7605
|
-
Land your verdict on the existing inspect-status surface. Your notes MUST begin with "
|
|
7804
|
+
Land your verdict on the existing inspect-status surface. Your notes MUST begin with "Item ${event.itemId}" — the server extracts the bead id from that prefix.
|
|
7606
7805
|
|
|
7607
7806
|
If the diff satisfies the acceptance criteria, post an ack (this persists inspectStatus and saves the bead checkpoint):
|
|
7608
7807
|
|
|
7609
7808
|
\`\`\`bash
|
|
7610
7809
|
curl -X POST ${event.apiUrl}/api/specialists/done \\
|
|
7611
7810
|
-H "Content-Type: application/json" \\
|
|
7612
|
-
-d '{"specialist":"inspect","issueId":"${event.issueId}","status":"passed","notes":"
|
|
7811
|
+
-d '{"specialist":"inspect","issueId":"${event.issueId}","status":"passed","notes":"Item ${event.itemId} ack: <one-line summary>"}'
|
|
7613
7812
|
\`\`\`
|
|
7614
7813
|
|
|
7615
7814
|
If any acceptance criterion is not met, post a blocking finding with specific, actionable violations ([file:line] + what is wrong):
|
|
@@ -7617,7 +7816,7 @@ If any acceptance criterion is not met, post a blocking finding with specific, a
|
|
|
7617
7816
|
\`\`\`bash
|
|
7618
7817
|
curl -X POST ${event.apiUrl}/api/specialists/done \\
|
|
7619
7818
|
-H "Content-Type: application/json" \\
|
|
7620
|
-
-d '{"specialist":"inspect","issueId":"${event.issueId}","status":"failed","notes":"
|
|
7819
|
+
-d '{"specialist":"inspect","issueId":"${event.issueId}","status":"failed","notes":"Item ${event.itemId} BLOCKED: <specific violations and required fixes>"}'
|
|
7621
7820
|
\`\`\`
|
|
7622
7821
|
|
|
7623
7822
|
Rules:
|
|
@@ -7646,8 +7845,8 @@ async function deliverCommitForReview(options) {
|
|
|
7646
7845
|
const frText = options.prdMarkdown && traces.length > 0 ? extractTracedFrText(options.prdMarkdown, traces) : void 0;
|
|
7647
7846
|
const message = buildSupervisorReviewMessage({
|
|
7648
7847
|
issueId: options.issueId,
|
|
7649
|
-
|
|
7650
|
-
|
|
7848
|
+
itemId: options.itemId ?? options.item.id,
|
|
7849
|
+
itemTitle: options.item.title,
|
|
7651
7850
|
sha: options.sha,
|
|
7652
7851
|
diff,
|
|
7653
7852
|
acceptanceCriteria: extractAcceptanceCriteria(options.item),
|
|
@@ -7784,11 +7983,11 @@ async function replayTierFeed(agentId, target, commits, deps) {
|
|
|
7784
7983
|
const includeCallout = (target.feedConfig ?? DEFAULT_TIERED_EXECUTION_CONFIG.feed).callouts !== "off";
|
|
7785
7984
|
const apiUrl = target.apiUrl ?? resolveFeedApiUrl();
|
|
7786
7985
|
for (const commit of commits) {
|
|
7787
|
-
const
|
|
7788
|
-
const message = composeCommitFeedMessage(commit.sha, commit.subject, commit.diff, includeCallout &&
|
|
7986
|
+
const itemId = commit.itemId;
|
|
7987
|
+
const message = composeCommitFeedMessage(commit.sha, commit.subject, commit.diff, includeCallout && itemId ? {
|
|
7789
7988
|
apiUrl,
|
|
7790
7989
|
issueId: target.issueId,
|
|
7791
|
-
|
|
7990
|
+
itemId,
|
|
7792
7991
|
tierName: target.tierName,
|
|
7793
7992
|
agentId
|
|
7794
7993
|
} : void 0);
|
|
@@ -7808,8 +8007,8 @@ async function replaySupervisorFeed(agentId, target, commits, deps) {
|
|
|
7808
8007
|
const frText = target.prdMarkdown && traces.length > 0 ? extractTracedFrText(target.prdMarkdown, traces) : void 0;
|
|
7809
8008
|
const message = buildSupervisorReviewMessage({
|
|
7810
8009
|
issueId: target.issueId,
|
|
7811
|
-
|
|
7812
|
-
|
|
8010
|
+
itemId: item.id,
|
|
8011
|
+
itemTitle: item.title,
|
|
7813
8012
|
sha: commit.sha,
|
|
7814
8013
|
diff: commit.diff,
|
|
7815
8014
|
acceptanceCriteria: extractAcceptanceCriteria(item),
|
|
@@ -7915,6 +8114,151 @@ var init_agents = __esmMin((() => {
|
|
|
7915
8114
|
init_tier_replay();
|
|
7916
8115
|
}));
|
|
7917
8116
|
//#endregion
|
|
7918
|
-
|
|
8117
|
+
//#region ../../lib/agents/queries.ts
|
|
8118
|
+
function listRunningAgentsSync() {
|
|
8119
|
+
const tmuxSessions = listSessionsSync();
|
|
8120
|
+
const tmuxNames = new Set(tmuxSessions.map((s) => s.name));
|
|
8121
|
+
return listOverdeckAgentStatesSync().map((state) => {
|
|
8122
|
+
const normalizedId = normalizeAgentId(state.id);
|
|
8123
|
+
return {
|
|
8124
|
+
...state,
|
|
8125
|
+
id: normalizedId,
|
|
8126
|
+
tmuxActive: tmuxNames.has(normalizedId)
|
|
8127
|
+
};
|
|
8128
|
+
});
|
|
8129
|
+
}
|
|
8130
|
+
/**
|
|
8131
|
+
* PAN-1908: list all agents in the SQLite registry with optional filtering.
|
|
8132
|
+
* This is the replacement for enumerating ~/.overdeck/agents/ directories.
|
|
8133
|
+
*/
|
|
8134
|
+
function listAgentStates(options) {
|
|
8135
|
+
return listOverdeckAgentStatesSync().filter((state) => {
|
|
8136
|
+
if (options?.status && state.status !== options.status) return false;
|
|
8137
|
+
if (options?.role && state.role !== options.role) return false;
|
|
8138
|
+
return true;
|
|
8139
|
+
});
|
|
8140
|
+
}
|
|
8141
|
+
/**
|
|
8142
|
+
* PAN-1048 P2: async startup migration.
|
|
8143
|
+
*
|
|
8144
|
+
* The previous synchronous version used readdirSync, readFileSync,
|
|
8145
|
+
* killSession (sync tmux subprocess), and rmSync — all on the Node
|
|
8146
|
+
* event loop. Called from warnOnBareNumericIssueIds() during dashboard
|
|
8147
|
+
* read-model bootstrap, this blocked all HTTP/WebSocket/PTY traffic on
|
|
8148
|
+
* server startup while it scanned every agent dir, killed stale tmux
|
|
8149
|
+
* sessions, and recursively deleted directories.
|
|
8150
|
+
*
|
|
8151
|
+
* This async variant does the same work using fs/promises and the
|
|
8152
|
+
* already-async killSessionAsync() so the bootstrap path no longer
|
|
8153
|
+
* stalls the event loop.
|
|
8154
|
+
*/
|
|
8155
|
+
async function dropLegacyAgentStatesMissingRoleAsync() {
|
|
8156
|
+
if (!existsSync(AGENTS_DIR)) return 0;
|
|
8157
|
+
const fsp = await import("fs/promises");
|
|
8158
|
+
let entries;
|
|
8159
|
+
try {
|
|
8160
|
+
entries = await fsp.readdir(AGENTS_DIR);
|
|
8161
|
+
} catch {
|
|
8162
|
+
return 0;
|
|
8163
|
+
}
|
|
8164
|
+
let dropped = 0;
|
|
8165
|
+
await Promise.all(entries.map(async (entry) => {
|
|
8166
|
+
const dirPath = join$1(AGENTS_DIR, entry);
|
|
8167
|
+
let stat;
|
|
8168
|
+
try {
|
|
8169
|
+
stat = await fsp.stat(dirPath);
|
|
8170
|
+
} catch {
|
|
8171
|
+
return;
|
|
8172
|
+
}
|
|
8173
|
+
if (!stat.isDirectory()) return;
|
|
8174
|
+
const agentId = normalizeAgentId(entry);
|
|
8175
|
+
const stateFile = getRollbackAgentStatePath(agentId);
|
|
8176
|
+
let raw;
|
|
8177
|
+
try {
|
|
8178
|
+
const contents = await fsp.readFile(stateFile, "utf8");
|
|
8179
|
+
raw = JSON.parse(contents);
|
|
8180
|
+
} catch {
|
|
8181
|
+
return;
|
|
8182
|
+
}
|
|
8183
|
+
if (isRole(raw.role)) return;
|
|
8184
|
+
try {
|
|
8185
|
+
await Effect.runPromise(killSession(agentId));
|
|
8186
|
+
} catch {}
|
|
8187
|
+
try {
|
|
8188
|
+
await fsp.rm(dirPath, {
|
|
8189
|
+
recursive: true,
|
|
8190
|
+
force: true
|
|
8191
|
+
});
|
|
8192
|
+
dropped++;
|
|
8193
|
+
} catch (err) {
|
|
8194
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
8195
|
+
console.warn(`[agents] Failed to drop legacy agent state ${agentId}: ${msg}`);
|
|
8196
|
+
}
|
|
8197
|
+
}));
|
|
8198
|
+
return dropped;
|
|
8199
|
+
}
|
|
8200
|
+
/**
|
|
8201
|
+
* Scan ~/.overdeck/agents/ for state files with bare numeric issueIds
|
|
8202
|
+
* (e.g. "484" instead of "PAN-484") and log warnings to stderr.
|
|
8203
|
+
*
|
|
8204
|
+
* These workspaces were created before the pan- prefix convention and may
|
|
8205
|
+
* cause cross-tracker pollution if their in_review transition is triggered.
|
|
8206
|
+
* Called once at server startup to surface legacy state files.
|
|
8207
|
+
*/
|
|
8208
|
+
/**
|
|
8209
|
+
* PAN-1048 P2: bootstrap-path migration is async.
|
|
8210
|
+
*
|
|
8211
|
+
* Sweeps legacy state files missing a `role` field and warns on bare
|
|
8212
|
+
* numeric issueIds. Both passes used to be synchronous (readdirSync,
|
|
8213
|
+
* readFileSync, killSession, rmSync), which blocked the dashboard
|
|
8214
|
+
* server's event loop on startup. The async version scans the same
|
|
8215
|
+
* directory once per concern and uses fs/promises throughout.
|
|
8216
|
+
*/
|
|
8217
|
+
async function warnOnBareNumericIssueIds() {
|
|
8218
|
+
const droppedLegacyAgents = await dropLegacyAgentStatesMissingRoleAsync();
|
|
8219
|
+
if (droppedLegacyAgents > 0) console.warn(`[agents] Dropped ${droppedLegacyAgents} legacy agent state file(s) missing role`);
|
|
8220
|
+
if (!existsSync(AGENTS_DIR)) return;
|
|
8221
|
+
const fsp = await import("fs/promises");
|
|
8222
|
+
let entries;
|
|
8223
|
+
try {
|
|
8224
|
+
entries = await fsp.readdir(AGENTS_DIR);
|
|
8225
|
+
} catch {
|
|
8226
|
+
return;
|
|
8227
|
+
}
|
|
8228
|
+
const legacy = [];
|
|
8229
|
+
await Promise.all(entries.map(async (entry) => {
|
|
8230
|
+
const dirPath = join$1(AGENTS_DIR, entry);
|
|
8231
|
+
try {
|
|
8232
|
+
if (!(await fsp.stat(dirPath)).isDirectory()) return;
|
|
8233
|
+
} catch {
|
|
8234
|
+
return;
|
|
8235
|
+
}
|
|
8236
|
+
const state = await Effect.runPromise(getAgentState(entry));
|
|
8237
|
+
if (state?.issueId && /^\d+$/.test(state.issueId)) legacy.push(`${entry} (issueId: "${state.issueId}")`);
|
|
8238
|
+
}));
|
|
8239
|
+
if (legacy.length > 0) console.warn(`[agents] WARNING: ${legacy.length} agent state file(s) have bare numeric issueIds (created before the pan- prefix convention). These agents will not be able to transition tracker state. Consider removing or updating them:\n` + legacy.map((l) => ` ~/.overdeck/agents/${l}`).join("\n"));
|
|
8240
|
+
}
|
|
8241
|
+
var listRunningAgents;
|
|
8242
|
+
var init_queries = __esmMin((() => {
|
|
8243
|
+
init_agents();
|
|
8244
|
+
init_tmux();
|
|
8245
|
+
init_paths();
|
|
8246
|
+
init_agent_rollback_state();
|
|
8247
|
+
init_agent_state_sync();
|
|
8248
|
+
listRunningAgents = () => Effect.gen(function* () {
|
|
8249
|
+
const tmuxSessions = yield* listSessions();
|
|
8250
|
+
const tmuxNames = new Set(tmuxSessions.map((s) => s.name));
|
|
8251
|
+
return listOverdeckAgentStatesSync().map((state) => {
|
|
8252
|
+
const normalizedId = normalizeAgentId(state.id);
|
|
8253
|
+
return {
|
|
8254
|
+
...state,
|
|
8255
|
+
id: normalizedId,
|
|
8256
|
+
tmuxActive: tmuxNames.has(normalizedId)
|
|
8257
|
+
};
|
|
8258
|
+
});
|
|
8259
|
+
});
|
|
8260
|
+
}));
|
|
8261
|
+
//#endregion
|
|
8262
|
+
export { stopAgentSync as $, wipeAgentStateDirs as $n, roleAgentDefinitionPath as $t, buildCompactRecoverySeed as A, decideResumeGate as An, init_bridge_token as At, appendActivity as B, markAgentRunning as Bn, resolveImplicitStaffing as Bt, init_slot_reconcile as C, SESSION_EXITED_BEFORE_KICKOFF as Cn, init_ohmypi_parser as Cr, deliverAgentPermissionDecision as Ct, detectCrashedAgents as D, clearAgentTroubled as Dn, captureTranscriptUserRecordSnapshot as Dt, autoRecoverAgents as E, clearAgentPausedSync as En, setAgentDeliveryMethod as Et, isContextOverflowTail as F, getAgentStateSync as Fn, init_spawn_prep as Ft, saveSessionId as G, recordAgentFailureSync as Gn, describeOhmypiSpawnFailure as Gt, getLatestSessionId as H, markAgentStoppedState as Hn, init_resolve_tier as Ht, init_messaging as I, init_agent_state as In, retrieveSpawnTimeMemoryContext as It, init_spawn as J, saveAgentState as Jn, getOhmypiLauncherFields as Jt, createOhmypiRuntimeSync as K, recordStartupSessionExit as Kn, getAgentRuntimeBaseCommand as Kt, messageAgent as L, isAgentPaused as Ln, transitionIssueToInProgress as Lt, resumeAgent as M, getAgentResumeGateBlockReason as Mn, assertWorkspaceStackHealthyForSpawn as Mt, init_context_overflow as N, getAgentState as Nn, buildAgentLaunchConfig as Nt, recoverAgent as O, clearAgentTroubledSync as On, init_transcript_landing as Ot, isContextOverflowError as P, getAgentStateFilePath as Pn, defaultRunWorkspace as Pt, stopAgent as Q, setAgentYieldedSync as Qn, injectPiConversationMemory as Qt, init_operator_interventions as R, isAgentTroubled as Rn, transitionIssueToInReview as Rt, init_tier_escalation as S, GOVERNOR_SLOT_PAUSE_REASON_PREFIX as Sn, paneShowsCodexAuthBurn as Sr, deliverAgentMessage as St, reconcileSlotState as T, clearAgentPaused as Tn, deliverResumeMessageWithTranscriptConfirmation as Tt, getLatestSessionIdSync as U, markAgentTroubled as Un, resolveTier as Ut, getActivity as V, markAgentRunningState as Vn, resolveStaffing as Vt, getSessionId as W, recordAgentFailure as Wn, OHMYPI_AGENT_READY_TIMEOUT_SECONDS as Wt, spawnRun as X, setAgentPaused as Xn, getRoleRuntimeBaseCommand as Xt, spawnAgent as Y, saveAgentStateSync as Yn, getProviderAuthMode as Yt, init_termination as Z, setAgentPausedSync as Zn, init_runtime_command as Zt, spawnTierSupervisor as _, buildDefaultResumeContinueMessage as _n, getAgentRuntimeSnapshot as _r, init_config as _t, listRunningAgentsSync as a, getClaudeAuthStatus as an, init_pty_supervisor_locate as ar, init_concurrency as at, init_tier_feed as b, dismissDevChannelsDialog as bn, checkCodexAuthStatus as br, saveCloisterConfigSync as bt, compactAtTierRunBoundary as c, buildSpawnEnvForModel as cn, isQualifiedAgentId as cr, resetPatrolDispatchBudget as ct, replayStandingAgent as d, getProviderExportsForModel as dn, waitForAgentIdle as dr, workResumeSlotsAvailable as dt, waitForPromptReady as en, writeAgentStateJsonSync as er, countRunningAgents as et, shouldReplayCompactAtTierRunBoundary as f, getProviderTmuxFlags as fn, waitForReadySignal as fr, getCachedMemoryVerdict as ft, shouldSupervise as g, init_openai_auth as gn, saveAgentRuntimeState as gr, getHealthThresholdsMs as gt, loadPrdDraft as h, getOpenAIAuthStatus as hn, init_runtime_state as hr, DEFAULT_CLOISTER_CONFIG as ht, listRunningAgents as i, ohmypiFifoPaths as in, writePtyToken as ir, getConcurrencyLimits as it, init_resume as j, getAgentDir as jn, writeBridgeTokenSync as jt, restartAgent as k, clearYieldForResumeSync as kn, probeTranscriptSince as kt, contextWindowForModel as l, determineModel as ln, normalizeAgentId as lr, tryReserveAdvancingSlot as lt, init_tier_supervisor as m, validateProviderHealth as mn, getAgentRuntimeStateSync as mr, setCachedMemoryVerdict as mt, init_queries as n, piFifoPaths as nn, readAgentHarnessModelRecordSync as nr, describeRunningAgents as nt, warnOnBareNumericIssueIds as o, init_claude_auth as on, resolvePtySupervisorScriptPath as or, releaseAdvancingSlot as ot, deliverCommitForReview as p, init_provider_health as pn, getAgentRuntimeState as pr, init_memory_verdict_cache as pt, init_ohmypi as q, resetAgentFailureCount as qn, getCodexLauncherFields as qt, listAgentStates as r, init_ohmypi_fifo as rn, init_pty_token as rr, emergencyBrake as rt, init_agents as s, buildCavemanExports as sn, clearReadySignal as sr, releaseSwarmSlot as st, dropLegacyAgentStatesMissingRoleAsync as t, init_pi_fifo as tn, init_agent_record_sync as tr, countRunningSwarmSlotsForIssue as tt, replayCrashedStandingAgent as u, getProviderEnvForModel as un, resolveAgentTargetSync as ur, tryReserveSwarmSlot as ut, supervisorAgentId as v, decideChannelsForWorkAgent as vn, init_agent_runtime as vr, loadCloisterConfig as vt, listSlotAssignments as w, __testInternals as wn, parseOhmypiSessionCostResultSync as wr, deliverInitialPromptWithRetry as wt, decideEscalation as x, writeChannelsBridgeMcpConfig as xn, init_codex_auth as xr, shouldAutoStart as xt, broadcastCommit as y, decideSupervisorForWorkAgent as yn, applyCodexAuthBurnFlag as yr, loadCloisterConfigSync as yt, operatorInterventionEvent as z, isRole as zn, init_staffing as zt };
|
|
7919
8263
|
|
|
7920
|
-
//# sourceMappingURL=
|
|
8264
|
+
//# sourceMappingURL=queries-C0LCGG21.js.map
|