@overdeck/desktop 0.45.23 → 0.45.24
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/drizzle/overdeck/0000_overdeck_init.sql +2 -0
- package/package.json +1 -1
- package/server/{acceptance-criteria-DOA0KgXx.js → acceptance-criteria-DDCnXF58.js} +2 -2
- package/server/{advancing-selfheal-BBu6DSNm.js → advancing-selfheal-BVwW4qRn.js} +6 -6
- package/server/{agent-gc-BV1q_2EV.js → agent-gc-CHcnvonI.js} +4 -4
- package/server/agent-state-Bc3tzUC8.js +3 -0
- package/server/{agent-state-service-HoK8U4jW.js → agent-state-service-BsgWxZuB.js} +5 -5
- package/server/{agent-state-service-CnzFKSAQ.js → agent-state-service-D5UGKIJL.js} +1 -1
- package/server/{agents-B4Bjbkfv.js → agents-EbI0zCJl.js} +4 -4
- package/server/agents-wi9NWzs2.js +3 -0
- package/server/{archive-planning-zkJb3BeM.js → archive-planning-BZDgzoEj.js} +1 -1
- package/server/{archive-planning-DYrYojxl.js → archive-planning-Du25Jtst.js} +4 -4
- package/server/{artifact-index-jobs-C-xy7Z5v.js → artifact-index-jobs-CbEDfCDu.js} +2 -2
- package/server/assemble-J2ZZ2C15.js +339 -0
- package/server/{backlog-auto-trigger-GtG71X8H.js → backlog-auto-trigger-2R2jog7n.js} +3 -3
- package/server/{behavior-B_-4EKF3.js → behavior-B3exJ42O.js} +2 -2
- package/server/{briefing-freshness-DWdW7vUm.js → briefing-freshness-D1wzUIWv.js} +2 -2
- package/server/{build-info-DgTqZkL5.js → build-info-CZk_TITh.js} +1 -1
- package/server/{build-info-BT096lEl.js → build-info-Ie_D0_BT.js} +3 -3
- package/server/{checkpoint-manager-DDqcGyu8.js → checkpoint-manager-BI1Wxoku.js} +2 -2
- package/server/{checkpoint-manager-B7Bt29J0.js → checkpoint-manager-DwbQoqrC.js} +1 -1
- package/server/checkpoint-worker.js +1 -1
- package/server/{checkpoints-CpgCjAlN.js → checkpoints-BJIs5QIA.js} +1 -1
- package/server/{checkpoints-C-AXLfYT.js → checkpoints-CQB1h765.js} +2 -2
- package/server/{claude-hooks-provision-C8wdRnN1.js → claude-hooks-provision-8Ngo8TpT.js} +1 -1
- package/server/{claude-hooks-provision-but-_qGY.js → claude-hooks-provision-D8GXF3_s.js} +2 -2
- package/server/{claude-permissions-H_5wHQZQ.js → claude-permissions-DNWEVV6z.js} +2 -2
- package/server/{claude-settings-overlay-CbSz0Dvb.js → claude-settings-overlay-CEdaqpWI.js} +2 -2
- package/server/{claude-settings-overlay-BTENVmYf.js → claude-settings-overlay-DWy-Bb4Y.js} +1 -1
- package/server/cli-B86rejVV.js +3 -0
- package/server/{cli-vBeXbPrq.js → cli-RoOx5DUf.js} +9 -9
- package/server/{cliproxy-Bgb2XCqi.js → cliproxy-C8a1vtTU.js} +2 -2
- package/server/{cliproxy-DW0V86F8.js → cliproxy-fHfIeiGd.js} +1 -1
- package/server/{close-issue-Dn_4c4G8.js → close-issue-DoOifFIK.js} +5 -5
- package/server/{closed-issue-reaper-hANY_ehE.js → closed-issue-reaper-Bk3SU4RC.js} +9 -9
- package/server/{closed-issue-reaper-CWpY2uBw.js → closed-issue-reaper-CktPXo8m.js} +1 -1
- package/server/{codex-TmSi-yTv.js → codex-BZXGhUVB.js} +7 -7
- package/server/{codex-Dg7Is5yb.js → codex-GcHuUF-k.js} +1 -1
- package/server/{codex-parser-C4gSH-IR.js → codex-parser-CFZ1_1Jl.js} +2 -2
- package/server/{config-CCvjQf27.js → config-BZ0sHTju.js} +2 -2
- package/server/{config-DjLOdbgT.js → config-CKxYiCmX.js} +2 -2
- package/server/{config-DUIhMN_T.js → config-DzV30TOm.js} +1 -1
- package/server/{config-yaml-DvyMuOle.js → config-yaml-DySPNmKN.js} +23 -9
- package/server/{conflict-gate-CmrYpa47.js → conflict-gate-BaCVrH-N.js} +3 -3
- package/server/{conflict-gate-BSJkNTdp.js → conflict-gate-BhAY7TUd.js} +1 -1
- package/server/context-layers-BrPmE__h.js +4 -0
- package/server/context-layers-igZ4FI4_.js +37 -0
- package/server/{control-settings-aP1ANIlI.js → control-settings-BQp7_4uD.js} +4 -4
- package/server/{conversation-compaction-CNbTLB86.js → conversation-compaction-CgrR8YYp.js} +8 -8
- package/server/{conversation-compaction-DiG5zWQq.js → conversation-compaction-eQB5CkOe.js} +1 -1
- package/server/{conversation-service-Up7FEzIC.js → conversation-service-BLd3MYsG.js} +1 -1
- package/server/{conversation-service-Du-MTNpJ.js → conversation-service-DPJ71F33.js} +329 -19
- package/server/{conversations-DbOs1e9Q.js → conversations-6AfUfbwc.js} +5 -5
- package/server/{conversations-6mPANqvL.js → conversations-CAsJF9kh.js} +1 -1
- package/server/{cost-Ca0YTWDw.js → cost-B2ddP6wq.js} +2 -2
- package/server/{cost-CW4WSe72.js → cost-R-m6Yi-W.js} +3 -3
- package/server/{cost-sync-C0VdGme1.js → cost-sync-BsN6ER0n.js} +3 -3
- package/server/{dag-CdOjJVDT.js → dag-B1ucnjDU.js} +2 -2
- package/server/{dangerous-git-ops-CT-IypG3.js → dangerous-git-ops-BXqeWVSf.js} +1 -1
- package/server/dashboard-db-worker.js +7 -7
- package/server/{deacon-pRnyD5w9.js → deacon-CU_cAYSR.js} +254 -144
- package/server/{deacon-DYSEJb48.js → deacon-kiQrb4ZT.js} +3 -3
- package/server/{deacon-nudge-log-Bjg8U4Y9.js → deacon-nudge-log-6wVqAaqz.js} +3 -3
- package/server/{deacon-swarm-DftYRDo8.js → deacon-swarm-BXZZ1Z2-.js} +13 -13
- package/server/deacon-swarm-C-GwfjJy.js +2 -0
- package/server/deacon.js +8 -8
- package/server/{deploy-patrol-Bjsho_ha.js → deploy-patrol-AiFoP8dw.js} +6 -6
- package/server/{deploy-window-DeP_OIRk.js → deploy-window-C3F-tihF.js} +6 -6
- package/server/{deploy-window-CM6W1-c6.js → deploy-window-DkZraDyj.js} +1 -1
- package/server/{dev-supervisor-BpMoHlkR.js → dev-supervisor-bcOWqdQE.js} +2 -2
- package/server/{devcontainer-renderer-CtUgrVKW.js → devcontainer-renderer-_d6XhyND.js} +3 -3
- package/server/dist-Bzy0y69j.js +3 -0
- package/server/{dist-DyRx4cI7.js → dist-Cb_0uvpS.js} +1 -1
- package/server/{docker-BK7HIcBj.js → docker-DcMTFTUC.js} +2 -2
- package/server/{dod-BrSfUHm0.js → dod-C6n9RV3G.js} +1 -1
- package/server/{ensure-devcontainer-DRqaAkBR.js → ensure-devcontainer-BZgOhRo7.js} +1 -1
- package/server/{ensure-devcontainer-DseivYEy.js → ensure-devcontainer-DNi-ono3.js} +4 -4
- package/server/{esm-shims-CbI3BVkl.js → esm-shims-OSHAYaS1.js} +1 -1
- package/server/{event-store-tdiY5eDZ.js → event-store-CQL6NeqB.js} +3 -3
- package/server/{event-store-Cr5PQwFC.js → event-store-EV2cMiXj.js} +1 -1
- package/server/{events-CvvGK6LT.js → events-BTdrdEq8.js} +1 -1
- package/server/{events-CC1dgUpx.js → events-DTfAe4My.js} +3 -3
- package/server/{factory-CynerjXO.js → factory-CFibJuaw.js} +4 -4
- package/server/{feature-registry-population-B0pmAz0a.js → feature-registry-population-DKZFMbFt.js} +4 -4
- package/server/{feature-registry-storage-_wUBRD3J.js → feature-registry-storage-BdPuLcBX.js} +2 -2
- package/server/{features-Dhxz-wLc.js → features-ez2271oH.js} +2 -2
- package/server/{feedback-target-CPS15Vte.js → feedback-target-7mqqwrX6.js} +7 -7
- package/server/{feedback-target-iygZwmMc.js → feedback-target-CoFDHiM8.js} +1 -1
- package/server/{feedback-writer-C9b6ccN1.js → feedback-writer-CY5L1lB7.js} +5 -5
- package/server/{feedback-writer-qmiMbqTZ.js → feedback-writer-D3a22RCd.js} +1 -1
- package/server/flywheel-DHrgCphM.js +1084 -0
- package/server/flywheel-DzGtWnJ1.js +477 -0
- package/server/flywheel-SVF02Jpq.js +2 -0
- package/server/{flywheel-merge-order-DxbQKE1d.js → flywheel-merge-order-UU0tiUld.js} +9 -8
- package/server/{flywheel-merge-order-C-6zRLvM.js → flywheel-merge-order-UUcsCDb6.js} +1 -1
- package/server/{forge-Ch9gCFod.js → forge-CNFnyqps.js} +2 -2
- package/server/forge-DXnS_YFH.js +2 -0
- package/server/{from-CJ_aH5jD.js → from-kNxT0bZC.js} +1 -1
- package/server/{fts-db-CKgg0VKg.js → fts-db-CE46vDkZ.js} +2 -2
- package/server/{fts-operations-BrL_VTRr.js → fts-operations-CqY6zl-i.js} +2 -2
- package/server/{git-utils-BVa07a4a.js → git-utils-CRw2zLPC.js} +68 -3
- package/server/git-utils-D0_yhCgF.js +3 -0
- package/server/{github-app-CMBdIFBQ.js → github-app-C3QrAUd0.js} +18 -7
- package/server/{github-app-CPfoFAdV.js → github-app-ClZ2lk8D.js} +1 -1
- package/server/{github-client--XVlDpwM.js → github-client-BnIsSrEN.js} +2 -2
- package/server/{github-client-B4QsdE-X.js → github-client-DfQYVUaw.js} +1 -1
- package/server/{github-pr-lookup-BRbDW-qk.js → github-pr-lookup-D16NGsSO.js} +2 -2
- package/server/{harness-binary-CVio2m-u.js → harness-binary-DPUi-Pv8.js} +32 -6
- package/server/{harness-resolve-qHJBhy3Z.js → harness-resolve-3lNZkyT4.js} +18 -9
- package/server/{health-events-C9B8y1Hm.js → health-events-BBcTYQKU.js} +2 -2
- package/server/{health-events-CpfvuVmm.js → health-events-BDOHby5Q.js} +1 -1
- package/server/{hooks-DUXw8A0-.js → hooks-CKZgXlJb.js} +2 -2
- package/server/{hooks-ltecuFqZ.js → hooks-DPVX1rwQ.js} +1 -1
- package/server/{hume-BEq0bUDg.js → hume-Cz8igP9E.js} +2 -2
- package/server/hume-ccTf4wTX.js +3 -0
- package/server/{idle-stack-reaper-D7w9t3fE.js → idle-stack-reaper-CuLF0j2H.js} +1 -1
- package/server/{idle-stack-reaper-w1ISSlhs.js → idle-stack-reaper-DDIRwxUY.js} +2 -2
- package/server/{in-flight-guard-aQ1IxeI3.js → in-flight-guard-CAAkqPLu.js} +2 -2
- package/server/{infra-CzaSOgul.js → infra-BEqFxlJc.js} +14 -4
- package/server/{injection-DZ0PfYa4.js → injection-C8aiVJrF.js} +191 -183
- package/server/{injection-oNZeoDhL.js → injection-CPUIqNhI.js} +1 -1
- package/server/{inspect-agent-DJKLWcVT.js → inspect-agent-BLuJ1AkT.js} +135 -79
- package/server/inspect-agent-Brtz0URj.js +2 -0
- package/server/{internal-token-DXdfprGr.js → internal-token-BrcU6qfe.js} +1 -1
- package/server/{internal-token-Bb4XeV2x.js → internal-token-s0-oKybJ.js} +2 -2
- package/server/{io-B3_AHDfr.js → io-C9kF1wtJ.js} +3 -3
- package/server/{issue-closed-zhdvQicO.js → issue-closed-CDJk4pIp.js} +7 -7
- package/server/{issue-lifecycle-Dy4vd0Oa.js → issue-lifecycle-B8sZHVHh.js} +1 -1
- package/server/{issue-lifecycle-CreaCkjW.js → issue-lifecycle-ojZAzDBP.js} +21 -21
- package/server/{issue-service-singleton-DabvBWUp.js → issue-service-singleton-BvJ09SaR.js} +1 -1
- package/server/{issue-service-singleton-B5ushCvE.js → issue-service-singleton-Yx5DdmVJ.js} +8 -8
- package/server/{issues-B6ToV6x1.js → issues-BMmP_77e.js} +2 -2
- package/server/{jsonl-parser-Dhflo1SH.js → jsonl-parser-BXSlHwEh.js} +3 -3
- package/server/{label-cleanup-BKPJm4Hv.js → label-cleanup-B0UJwnv5.js} +3 -3
- package/server/{label-reconciler-DdWbHEBu.js → label-reconciler-B4iOAjlC.js} +4 -4
- package/server/{launcher-generator-CHVm7bGT.js → launcher-generator-BBWG_SiS.js} +101 -7
- package/server/{lifecycle-io-D8iNBcux.js → lifecycle-io-BREGpnLk.js} +5 -5
- package/server/{lifecycle-io-Bsnr2K4F.js → lifecycle-io-DPo7x11I.js} +1 -1
- package/server/{lifecycle-sycO16hj.js → lifecycle-xmBfK2GJ.js} +6 -6
- package/server/{lifecycle-DfeyBDwA.js → lifecycle-yPd___5E.js} +2 -2
- package/server/{linear-client-D4zqMnX7.js → linear-client-BsuUvkdA.js} +2 -2
- package/server/{linear-client-DqhDQO9k.js → linear-client-CTskEeT_.js} +1 -1
- package/server/memory-fts-worker.js +1 -1
- package/server/{merge-DK23JEdS.js → merge-B1DiziGU.js} +1 -1
- package/server/{merge-C_ZEhbqI.js → merge-CefQNAnq.js} +3 -3
- package/server/{merge-agent-XrB80vfT.js → merge-agent-4WOWlSYA.js} +28 -28
- package/server/{merge-agent-BQM3a8z5.js → merge-agent-CKkgIBPB.js} +1 -1
- package/server/{merge-batch-Bwoyr8Je.js → merge-batch-ClFn2T-y.js} +1 -1
- package/server/merge-ops-CR44oU9-.js +2 -0
- package/server/{merge-rebase-C1KIVr0s.js → merge-rebase-BfaTyXsw.js} +2 -2
- package/server/merge-set-DJ8-UErs.js +83 -0
- package/server/{merge-set-DnSYdBEp.js → merge-set-bUqbm3yc.js} +1 -1
- package/server/{merge-sync-SSv3E-pl.js → merge-sync-BJYeOODr.js} +1 -1
- package/server/{merge-sync-DZ9dojJn.js → merge-sync-VPV28g0g.js} +2 -2
- package/server/{merge-train-DxDfBTjr.js → merge-train-CHopycP0.js} +3 -3
- package/server/{merge-train-deps-CyYQUksx.js → merge-train-deps-D1cOZzy2.js} +4 -4
- package/server/{merge-verification-CSizH3HY.js → merge-verification-BkaOqPsw.js} +4 -4
- package/server/{multipart-parser-Dt8YPN5S.js → multipart-parser-duPAfSBw.js} +2 -2
- package/server/{no-resume-mode-Cx3K0hHi.js → no-resume-mode-Nw29vaFb.js} +1 -1
- package/server/node_modules/.package-lock.json +8 -8
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/package.json +3 -3
- package/server/node_modules/undici/README.md +5 -0
- package/server/node_modules/undici/docs/docs/api/Client.md +4 -0
- package/server/node_modules/undici/docs/docs/api/Dispatcher.md +6 -0
- package/server/node_modules/undici/docs/docs/api/Interceptors.md +59 -0
- package/server/node_modules/undici/docs/docs/api/MockAgent.md +27 -0
- package/server/node_modules/undici/docs/docs/api/MockPool.md +28 -1
- package/server/node_modules/undici/docs/docs/index.md +5 -0
- package/server/node_modules/undici/lib/core/request.js +1 -1
- package/server/node_modules/undici/lib/core/util.js +6 -1
- package/server/node_modules/undici/lib/dispatcher/agent.js +3 -3
- package/server/node_modules/undici/lib/dispatcher/client-h1.js +31 -6
- package/server/node_modules/undici/lib/dispatcher/client-h2.js +34 -43
- package/server/node_modules/undici/lib/handler/cache-handler.js +93 -5
- package/server/node_modules/undici/lib/handler/cache-revalidation-handler.js +10 -0
- package/server/node_modules/undici/lib/handler/redirect-handler.js +5 -2
- package/server/node_modules/undici/lib/handler/retry-handler.js +6 -4
- package/server/node_modules/undici/lib/interceptor/cache.js +21 -4
- package/server/node_modules/undici/lib/interceptor/decompress.js +4 -0
- package/server/node_modules/undici/lib/mock/mock-interceptor.js +25 -7
- package/server/node_modules/undici/lib/mock/mock-utils.js +39 -10
- package/server/node_modules/undici/lib/util/cache.js +49 -7
- package/server/node_modules/undici/lib/web/fetch/body.js +2 -1
- package/server/node_modules/undici/lib/web/fetch/response.js +1 -3
- package/server/node_modules/undici/package.json +2 -2
- package/server/node_modules/undici/types/client.d.ts +2 -2
- package/server/node_modules/undici/types/dispatcher.d.ts +3 -3
- package/server/node_modules/undici/types/mock-interceptor.d.ts +5 -1
- package/server/{orphan-proposed-reconciler-neK8dHQk.js → orphan-proposed-reconciler-BvKkWMJQ.js} +12 -12
- package/server/{orphan-proposed-reconciler-BTkDrl4R.js → orphan-proposed-reconciler-CTSGcK8p.js} +1 -1
- package/server/package-lock.json +9 -9
- package/server/package.json +1 -1
- package/server/{pan-dir-DeVUgwA7.js → pan-dir-B0c3w0Ya.js} +3 -3
- package/server/{paths-_zEts6wc.js → paths-D-xWGHdh.js} +2 -2
- package/server/{pickup-Dd0Znxxy.js → pickup-DUCLWrJY.js} +17 -16
- package/server/{pipeline-membership-0HaEGDlH.js → pipeline-membership-mY3GprlK.js} +7 -7
- package/server/{pipeline-notifier-6iCJplFZ.js → pipeline-notifier-BJr8gQX6.js} +1 -1
- package/server/{pipeline-notifier-D0ykk59O.js → pipeline-notifier-BXkJzDC4.js} +2 -2
- package/server/{project-pipelines-2sK1apsO.js → project-pipelines-C0MWUeCU.js} +2 -2
- package/server/project-repos-B6GycDh9.js +94 -0
- package/server/project-repos-DXKQsc_m.js +3 -0
- package/server/{projects-9SkRpES9.js → projects-vjjcmiN8.js} +1 -1
- package/server/{prompts-Dp4Tpk39.js → prompts-DxzFXuLl.js} +2 -2
- package/server/{providers-DV7ec8l7.js → providers-qQAwGQDW.js} +7 -7
- package/server/{providers-DKkBXhxU.js → providers-u4Ga0jOr.js} +1 -1
- package/server/public/assets/{chunk-BO2N2NFS-CltymLRg.js → chunk-BO2N2NFS-BamJdinX.js} +4 -4
- package/server/public/assets/{diagram-OG6HWLK6-D2f6pjgA.js → diagram-OG6HWLK6-DfOB8-w4.js} +1 -1
- package/server/public/assets/{dist-DEmlBBNQ.js → dist-ByIuzMQW.js} +3 -3
- package/server/public/assets/{dist-BWR4qFiV.js → dist-D7zYSEA6.js} +1 -1
- package/server/public/assets/{ganttDiagram-6RSMTGT7-DnfiViPK.js → ganttDiagram-6RSMTGT7-EdmRyXL3.js} +1 -1
- package/server/public/assets/{highlighted-body-OFNGDK62-B8Wrmj9H.js → highlighted-body-OFNGDK62-MerOfTX8.js} +1 -1
- package/server/public/assets/{index-CsSuZQBI.js → index-CWeMerGO.js} +146 -144
- package/server/public/assets/{index-CUr1xv8w.css → index-CenuJ3Cw.css} +1 -1
- package/server/public/assets/{linear-C9zFQpkX.js → linear-BBbArIcK.js} +1 -1
- package/server/public/assets/mermaid-GHXKKRXX-CpPWAFwE.js +1 -0
- package/server/public/assets/{pieDiagram-4H26LBE5-lR8H7Yjd.js → pieDiagram-4H26LBE5-BKIddiJN.js} +1 -1
- package/server/public/assets/{prod-B1jCQihw.js → prod-B8vYiu52.js} +4 -4
- package/server/public/assets/{quadrantDiagram-W4KKPZXB-CVQ2guem.js → quadrantDiagram-W4KKPZXB-D6RtoULk.js} +1 -1
- package/server/public/assets/{sankeyDiagram-5OEKKPKP-eD1RB4gm.js → sankeyDiagram-5OEKKPKP-CLrCedZX.js} +1 -1
- package/server/public/assets/{xychartDiagram-2RQKCTM6-ChEC6dQn.js → xychartDiagram-2RQKCTM6-hznR8DYl.js} +1 -1
- package/server/public/index.html +2 -2
- package/server/{pull-requests--Ib2jTgy.js → pull-requests-7N8WKseP.js} +1 -1
- package/server/{pull-requests-CXIhdCYD.js → pull-requests-_lHueOHW.js} +3 -3
- package/server/{queries-6d7Cdtm7.js → queries-CjNIf-Ub.js} +576 -166
- package/server/{rally-B708-nZn.js → rally-CyWT_lNO.js} +3 -3
- package/server/{rally-api-nY0ZANw3.js → rally-api-C8e_1JRi.js} +2 -2
- package/server/{rally-api-yjQ0TfHd.js → rally-api-ClOSd-Tt.js} +1 -1
- package/server/{rally-client-B1EJhfV0.js → rally-client-lc-nokqr.js} +4 -4
- package/server/{rally-client-CULK2XAY.js → rally-client-sgtVqzNU.js} +1 -1
- package/server/rally-zhhtXuDP.js +3 -0
- package/server/{reap-terminal-sessions-MWnqdLCJ.js → reap-terminal-sessions-7KeHv1R1.js} +1 -1
- package/server/{reap-terminal-sessions-N3BTkmX_.js → reap-terminal-sessions-BtHPo6Xc.js} +1 -1
- package/server/rebuild-stack-CFvcBHsS.js +4 -0
- package/server/{rebuild-stack-Dp4eLkt4.js → rebuild-stack-lwtsW0GO.js} +26 -35
- package/server/{reconstruct-cache-uWbZfjms.js → reconstruct-cache-C3Ui7ojV.js} +6 -6
- package/server/{record-t6V-3Dcj.js → record-CN0pj4_5.js} +1 -1
- package/server/{record-update-DACtKh6_.js → record-update-bLJxAXH4.js} +1 -1
- package/server/{record-update-Dq0t2uBG.js → record-update-dE1Aw83j.js} +2 -2
- package/server/{recovery-trip-BJtIQuag.js → recovery-trip-BvRWfUXM.js} +2 -2
- package/server/{release-engine-DZpmGGzb.js → release-engine-Cx48W7z8.js} +5 -5
- package/server/{release-set-hnXd_kga.js → release-set-CQfuN9-v.js} +3 -3
- package/server/{remote-Br-ZWVIP.js → remote-C_2hasl7.js} +3 -3
- package/server/{remote-4tiENDaI.js → remote-ChgimyYa.js} +3 -3
- package/server/{remote-agents-nmty1mLu.js → remote-agents-By1ige5O.js} +6 -6
- package/server/{remote-agents-CRCg1L4H.js → remote-agents-CA3Ihlxj.js} +1 -1
- package/server/{remote-completion-BbWNd10K.js → remote-completion-fVe9e_3u.js} +12 -12
- package/server/resume-BFv1PGpA.js +3 -0
- package/server/{review-agent-sKkE1FEL.js → review-agent-CIGOQYBD.js} +29 -25
- package/server/{review-agent-DJRO8EG8.js → review-agent-DNboMyW4.js} +1 -1
- package/server/{review-artifacts-BLbSC4ke.js → review-artifacts-nRDPuMxd.js} +5 -5
- package/server/{review-context-BgX3lcCx.js → review-context-2uj-YQ8J.js} +69 -25
- package/server/{review-status-C6n6-9f_.js → review-status-btEYlaxA.js} +1 -1
- package/server/{review-status-enrichment-tbOn_A_u.js → review-status-enrichment-Dci-ZwEt.js} +3 -3
- package/server/{review-status-A7quS5KJ.js → review-status-kZj_KyCk.js} +42 -26
- package/server/{review-status-sync-BhSQ0d0l.js → review-status-sync-BTOpxtTC.js} +10 -5
- package/server/{review-status-sync-To3-iS-N.js → review-status-sync-DSDK3OMy.js} +1 -1
- package/server/{review-verdict-feedback-CTRNtzXO.js → review-verdict-feedback-CCjVA7Uk.js} +6 -6
- package/server/{review-verdict-feedback-C1Kg8n7t.js → review-verdict-feedback-CTd4QMBu.js} +1 -1
- package/server/{rollup-B53Y81xK.js → rollup-BKQC7jp4.js} +1 -1
- package/server/{rollup-WA0VD-Rr.js → rollup-FGsKki9R.js} +8 -8
- package/server/{scanner-D2743cp8.js → scanner-CnqEZeDy.js} +41 -14
- package/server/{sequence-io-Cg0zYj_E.js → sequence-io-D909zgeH.js} +4 -4
- package/server/{sequencer-agent-BGY8gjg-.js → sequencer-agent-CzkcK6P5.js} +5 -5
- package/server/server.js +2194 -341
- package/server/{service-DCpB_SGd.js → service-CLeAoU6G.js} +51 -50
- package/server/{session-fork-BQ8_6H32.js → session-fork-CHI1XvL9.js} +2 -2
- package/server/{session-history-CVZDpS3c.js → session-history-BT3IvqhC.js} +4 -4
- package/server/settings-66A6uvIA.js +2 -0
- package/server/{settings-BZ5m1UCl.js → settings-BTMvpNFU.js} +3 -3
- package/server/{settings-ylxwqwQG.js → settings-C0zgxOGf.js} +2 -2
- package/server/{shadow-engineering-BlxG6Xye.js → shadow-engineering-BJfgm-hX.js} +2 -2
- package/server/{shadow-state-Dh-HzF2J.js → shadow-state-7a-524T8.js} +2 -2
- package/server/{shadow-state-C2_epgx2.js → shadow-state-DnDyjujH.js} +1 -1
- package/server/{shadow-utils-4bvjn9b3.js → shadow-utils-Db3oroFG.js} +2 -2
- package/server/{ship-log-ClSMIzZX.js → ship-log-D9MlVzYU.js} +1 -1
- package/server/{smart-compaction-CHIxLr_d.js → smart-compaction-CV2ukKND.js} +1 -1
- package/server/{smart-compaction-r4pHQBIr.js → smart-compaction-KCYScAU1.js} +7 -7
- package/server/{spawn-planning-session-DWAorh2B.js → spawn-planning-session-DKpdFyOC.js} +30 -23
- package/server/{spawn-planning-session-KC_UduxD.js → spawn-planning-session-qUC2VWu3.js} +1 -1
- package/server/{specialist-completion-BXhav38U.js → specialist-completion-Ky9wCDpb.js} +1 -1
- package/server/{specialist-context-DtrYvGJ-.js → specialist-context-Bn3dCGS2.js} +5 -5
- package/server/{specialist-handoff-logger-C45ouoZ6.js → specialist-handoff-logger-CMEwYxa2.js} +2 -2
- package/server/{specialist-logs-DJ3RzKxW.js → specialist-logs-C5p8G7tx.js} +3 -3
- package/server/{specialists-JVO00bs7.js → specialists-CC4r-c2s.js} +776 -347
- package/server/{specialists-D5fRZXmN.js → specialists-CShuVGWT.js} +1 -1
- package/server/{specialists-DVj0hvaL.js → specialists-DM6bWjsi.js} +1 -1
- package/server/{specialists-DyFeedjn.js → specialists-jiuuyVkp.js} +21 -19
- package/server/specs-C8Wsn2XO.js +3 -0
- package/server/{src-CG9mCkP6.js → src-CXmtj0im.js} +6 -6
- package/server/{src-CMTQGyCK.js → src-CdmnTM2m.js} +5 -5
- package/server/{src-U7_kTPEE.js → src-DtcUOZCq.js} +111 -18
- package/server/stack-health-Bn3o8FBX.js +3 -0
- package/server/{stack-health-puygdaMd.js → stack-health-DxSdG9cW.js} +63 -9
- package/server/{stale-task-claims-BbFwCTb0.js → stale-task-claims-KJKxxiiQ.js} +4 -4
- package/server/{staleness-Cbl_w4Bw.js → staleness-CT34nwr9.js} +1 -1
- package/server/{staleness-Bpy41ngS.js → staleness-DPm7ClwA.js} +1 -1
- package/server/{state-home-CIGjwNfJ.js → state-home-Cn_Qu8IX.js} +2 -2
- package/server/{state-migrate-Dkzaxvny.js → state-migrate-BGg2ZaOt.js} +4 -4
- package/server/{stuck-remediation-CzEov_fq.js → stuck-remediation-DYuPRYYw.js} +300 -23
- package/server/{stuck-remediation-sY_MHHgQ.js → stuck-remediation-s9_2qfi6.js} +1 -1
- package/server/{substrate-bug-weights-service-BH66lhm7.js → substrate-bug-weights-service-B-FwCs5V.js} +3 -3
- package/server/{summary-fork-DHhJIsAL.js → summary-fork-D1RAk9rJ.js} +78 -12
- package/server/{summary-fork-D8bXjCr7.js → summary-fork-DpcxN9tf.js} +2 -2
- package/server/supervisor/{injection-budget-C1iPirFS.js → injection-budget-Csw5tqfJ.js} +2 -41
- package/server/supervisor/pty-supervisor.js +2 -1
- package/server/supervisor/pty-token-x-ea28Us.js +43 -0
- package/server/supervisor-FTJAIsAK.js +2 -0
- package/server/{supervisor-BO-Zk_h-.js → supervisor-wM4ooB5O.js} +3 -3
- package/server/{swarm-readiness-CQ_fwUWF.js → swarm-readiness-DlP_UjHq.js} +3 -3
- package/server/{system-prerequisites-Bza0ffAh.js → system-prerequisites-DUDj1YHf.js} +56 -29
- package/server/{teardown-workspace-CEgauF4U.js → teardown-workspace-DeTTImn-.js} +15 -15
- package/server/{test-agent-queue-DXDt0Xa-.js → test-agent-queue-MbxX5vqq.js} +6 -6
- package/server/{test-verdict-CmUBK5cT.js → test-verdict-bWYBtqBg.js} +1 -1
- package/server/{test-verdict-DFjjIHR5.js → test-verdict-gscuksPv.js} +1 -1
- package/server/{tldr-daemon-DL566HbH.js → tldr-daemon-BYFkts95.js} +1 -1
- package/server/{tldr-daemon-BDtLOIlO.js → tldr-daemon-C-69c3OI.js} +2 -2
- package/server/{tmux-DoThH6aj.js → tmux-B6z7h_vZ.js} +1 -1
- package/server/{tmux-ftABRAmc.js → tmux-R7N7y-Mh.js} +2 -2
- package/server/{token-CsOhvw42.js → token-BK6t8BIT.js} +2 -2
- package/server/token-util-DuPuNriz.js +3 -0
- package/server/{token-util-CTmczIfW.js → token-util-DxXu-vd1.js} +1 -1
- package/server/{tracker-config-B4itFzDo.js → tracker-config-G6latr8C.js} +2 -2
- package/server/{tracker-utils-BePq_oj-.js → tracker-utils-B4ylXZQK.js} +1 -1
- package/server/{tracker-utils-tnxxqROg.js → tracker-utils-DHv5pSDT.js} +2 -2
- package/server/{traefik-connect-m73vGebA.js → traefik-connect-Df2uXPsQ.js} +1 -1
- package/server/{tunnel-B2vxjx_b.js → tunnel-CDVKJpRv.js} +3 -3
- package/server/{tunnel-Cgj-IGIl.js → tunnel-DGdUkGoZ.js} +1 -1
- package/server/{types-BBNjPcqU.js → types-5M0lupud.js} +1 -1
- package/server/{uat-train-cKfM-_WW.js → uat-train-B05BWkp-.js} +1 -1
- package/server/{uat-train-CuEn0t9M.js → uat-train-DDSrSoV1.js} +25 -25
- package/server/validate-IfDGkaVR.js +177 -0
- package/server/{validation-CIi6pnI2.js → validation-CC9OPqJZ.js} +1 -1
- package/server/{validation-B5JxoPUS.js → validation-Dw1pzDzr.js} +4 -4
- package/server/{verification-artifact-C-lIHfUa.js → verification-artifact-B3itKTxu.js} +1 -1
- package/server/{verification-artifact-BcnIbigL.js → verification-artifact-TVFSz_q1.js} +1 -1
- package/server/{verification-runner-CDj4lD4t.js → verification-runner-BW4HOKAz.js} +1 -1
- package/server/{verification-runner-Br0S_Ous.js → verification-runner-CkgX6EtI.js} +91 -106
- package/server/{vtt-parser-DKpNNW5i.js → vtt-parser-DYPbKcIJ.js} +1 -1
- package/server/{work-agent-prompt-Yb2bd3Fq.js → work-agent-prompt-Du8Vh2aJ.js} +9 -9
- package/server/workflows-BQu4RFQ-.js +2 -0
- package/server/{workflows-C9WmILql.js → workflows-mbQzh6mQ.js} +18 -18
- package/server/{workspace-DuUdndHe.js → workspace--8tnhDI0.js} +1 -1
- package/server/{workspace-BVl4rihN.js → workspace-BPUws1-_.js} +3 -3
- package/server/{workspace-config-cEGcO6UT.js → workspace-config-CIVWZOQr.js} +1 -1
- package/server/{workspace-manager-hLUv3ADC.js → workspace-manager-CBhNdzE4.js} +66 -15
- package/server/workspace-manager-CWT55qeI.js +3 -0
- package/server/{workspace-metadata-DNpMixRq.js → workspace-metadata-BzHnwwX4.js} +1 -1
- package/server/{workspace-metadata-CskwzzhL.js → workspace-metadata-_WygnyoX.js} +2 -2
- package/server/{workspaces-hWvy9eKs.js → workspaces-Do_9J0LQ.js} +130 -111
- package/sync-sources/hooks/record-cost-event.js +6 -4
- package/sync-sources/skills/okf/README.md +11 -3
- package/sync-sources/skills/okf/SKILL.md +12 -1
- package/sync-sources/skills/okf/docs/USAGE.md +15 -0
- package/sync-sources/skills/okf/references/overdeck.md +28 -0
- package/sync-sources/skills/pan-flywheel/SKILL.md +18 -1
- package/sync-sources/skills/pan-knowledge/SKILL.md +10 -0
- package/sync-sources/skills/pan-orders/SKILL.md +33 -0
- package/sync-sources/skills/pan-start/SKILL.md +4 -0
- package/sync-sources/templates/traefik/dynamic/overdeck.yml.template +10 -0
- package/server/agent-state-Bg0lhqwj.js +0 -3
- package/server/agents-FlIgQ3ql.js +0 -3
- package/server/cli-BsVIHwzC.js +0 -3
- package/server/context-layers-B3Nt58jl.js +0 -4
- package/server/context-layers-ZYFcWiyc.js +0 -165
- package/server/deacon-swarm-9jRLS5Ke.js +0 -2
- package/server/dist-Bd3vn0Hw.js +0 -3
- package/server/flywheel-DMCUzDWg.js +0 -2
- package/server/flywheel-DSSpWmqF.js +0 -522
- package/server/flywheel-DcBkQvgE.js +0 -207
- package/server/forge-B-ZWyTRm.js +0 -2
- package/server/git-utils-Dry_Ka_D.js +0 -3
- package/server/hume-B_DbflNM.js +0 -3
- package/server/inspect-agent-ch-F-5Ci.js +0 -2
- package/server/layers-DzxSTGNA.js +0 -93
- package/server/merge-blockers-BsFjGrQ8.js +0 -41
- package/server/merge-ops-DlB1IM0Y.js +0 -2
- package/server/merge-set-DLz0MkGT.js +0 -139
- package/server/public/assets/mermaid-GHXKKRXX-BUAB8hqt.js +0 -1
- package/server/rally-njs_mJrt.js +0 -3
- package/server/rebuild-stack-kA7XngID.js +0 -3
- package/server/resume-CcKqnTvE.js +0 -3
- package/server/settings-D0OSwos5.js +0 -2
- package/server/specs-nN45DG2X.js +0 -3
- package/server/stack-health-Df0YEZKa.js +0 -3
- package/server/supervisor-BPy-o1A8.js +0 -2
- package/server/token-util-DrHg8abn.js +0 -3
- package/server/workflows-D90rMOya.js +0 -2
- package/server/workspace-manager-ZTdJAy9M.js +0 -3
|
@@ -1,44 +1,45 @@
|
|
|
1
1
|
import { a as __toCommonJS } from "./rolldown-runtime-DNCzzKnI.js";
|
|
2
|
-
import { A as canUseHarnessSync, Br as getOverdeckHome, D as resolveTieredExecutionEnabled, H as init_providers, I as UnknownModelError, Jn as extractPrefixSync, M as init_harness_policy, Nr as encodeClaudeProjectDir, O as resolveTieredExecutionEnabledForIssue, Qt as parsePorcelainStatusPaths, T as init_tier_table, Tn as init_projects, U as piProviderForModel, Ur as packageRoot, V as getProviderForModelSync, Vr as init_paths, Wr as resolveOhmypiExtensionPath, Yn as init_issue_id, Yt as init_state_plane, Zn as parseIssueIdSync, c as isClaudeCodeChannelsEnabled, f as loadConfigSync, in as shouldCommitLegacyWorkspaceArtifacts, ir as FsError, kn as listProjectsSync, mr as init_errors, nn as init_state_read_home, t as init_config_yaml, tt as resolveModel, yn as getProjectSync, zn as resolveProjectFromIssueSync } from "./config-yaml-
|
|
2
|
+
import { A as canUseHarnessSync, Br as getOverdeckHome, D as resolveTieredExecutionEnabled, H as init_providers, I as UnknownModelError, Jn as extractPrefixSync, M as init_harness_policy, Nr as encodeClaudeProjectDir, O as resolveTieredExecutionEnabledForIssue, Qt as parsePorcelainStatusPaths, T as init_tier_table, Tn as init_projects, U as piProviderForModel, Ur as packageRoot, V as getProviderForModelSync, Vr as init_paths, Wr as resolveOhmypiExtensionPath, Yn as init_issue_id, Yt as init_state_plane, Zn as parseIssueIdSync, c as isClaudeCodeChannelsEnabled, f as loadConfigSync, fn as findProjectByPathSync, in as shouldCommitLegacyWorkspaceArtifacts, ir as FsError, kn as listProjectsSync, mr as init_errors, nn as init_state_read_home, rn as resolveStateReadHomeSync, t as init_config_yaml, tt as resolveModel, yn as getProjectSync, zn as resolveProjectFromIssueSync } from "./config-yaml-DySPNmKN.js";
|
|
3
3
|
import { a as init_activity_logger, n as emitActivityEntrySync } from "./activity-logger-DDlOIAML.js";
|
|
4
|
-
import { d as getOverdeckDatabaseSync, f as init_infra } from "./infra-
|
|
5
|
-
import { $ as init_child_env, B as sendKeysAsync, D as killSession, H as sessionExists, M as listSessionNames, N as listSessions, Q as buildChildEnvWithoutTmuxSync, T as isHarnessProcessAlive, U as sessionExistsSync, V as sendRawKeystroke, W as setOption, X as BLANKED_PROVIDER_ENV, g as findManagedServerPidSync, i as capturePane, m as exactPaneTarget, s as createSession, w as init_tmux } from "./tmux-
|
|
6
|
-
import { a as init_event_store, n as getEventStore } from "./event-store-
|
|
7
|
-
import {
|
|
8
|
-
import { E as init_agent_state_sync, b as setReviewStatusSync, c as getReviewStatusSync, d as loadReviewStatuses, i as clearWorkspaceStuck, k as stateToOverdeckParamsForDb, l as init_review_status, w as AGENT_COLUMNS_FOR_DB } from "./review-status-
|
|
9
|
-
import { a as EventStoreService, c as ReadModelService, d as init_read_model, i as init_issue_lifecycle, s as init_domain_services, t as IssueLifecycle, u as getClosedIssueIdsForReadSource } from "./issue-lifecycle-
|
|
10
|
-
import { d as isTerminalIssueStage, o as init_agents, u as getIssueStageSync } from "./agents-
|
|
11
|
-
import { n as ensureSessionContextBriefingFile, r as init_briefing_freshness } from "./briefing-freshness-
|
|
12
|
-
import { o as getPricingSync, s as init_cost, t as calculateCostSync } from "./cost-
|
|
13
|
-
import {
|
|
14
|
-
import { a as performHandoff, i as checkAllTriggers, s as getAgentHealth, t as getCloisterService } from "./service-
|
|
15
|
-
import { o as init_persistent_logger, s as logAgentLifecycleSync } from "./session-history-
|
|
16
|
-
import { t as init_behavior } from "./behavior-
|
|
17
|
-
import { a as init_tracker_config, t as getGitHubConfig } from "./tracker-config-
|
|
18
|
-
import { n as init_issue_service_singleton, r as issue_service_singleton_exports } from "./issue-service-singleton-
|
|
19
|
-
import { o as getInternalTokenSync, s as init_internal_token } from "./internal-token-
|
|
4
|
+
import { d as getOverdeckDatabaseSync, f as init_infra } from "./infra-BEqFxlJc.js";
|
|
5
|
+
import { $ as init_child_env, B as sendKeysAsync, D as killSession, H as sessionExists, M as listSessionNames, N as listSessions, Q as buildChildEnvWithoutTmuxSync, T as isHarnessProcessAlive, U as sessionExistsSync, V as sendRawKeystroke, W as setOption, X as BLANKED_PROVIDER_ENV, g as findManagedServerPidSync, i as capturePane, m as exactPaneTarget, s as createSession, w as init_tmux } from "./tmux-R7N7y-Mh.js";
|
|
6
|
+
import { a as init_event_store, n as getEventStore } from "./event-store-CQL6NeqB.js";
|
|
7
|
+
import { M as normalizeChannelReplyPayload, o as getHarnessBehavior, t as init_src, w as DomainEvent } from "./src-DtcUOZCq.js";
|
|
8
|
+
import { E as init_agent_state_sync, b as setReviewStatusSync, c as getReviewStatusSync, d as loadReviewStatuses, i as clearWorkspaceStuck, k as stateToOverdeckParamsForDb, l as init_review_status, w as AGENT_COLUMNS_FOR_DB } from "./review-status-kZj_KyCk.js";
|
|
9
|
+
import { a as EventStoreService, c as ReadModelService, d as init_read_model, i as init_issue_lifecycle, s as init_domain_services, t as IssueLifecycle, u as getClosedIssueIdsForReadSource } from "./issue-lifecycle-ojZAzDBP.js";
|
|
10
|
+
import { d as isTerminalIssueStage, o as init_agents, u as getIssueStageSync } from "./agents-EbI0zCJl.js";
|
|
11
|
+
import { n as ensureSessionContextBriefingFile, r as init_briefing_freshness } from "./briefing-freshness-D1wzUIWv.js";
|
|
12
|
+
import { o as getPricingSync, s as init_cost, t as calculateCostSync } from "./cost-B2ddP6wq.js";
|
|
13
|
+
import { Ar as saveAgentRuntimeState, At as deliverAgentPermissionDecision, Bt as assertWorkspaceStackHealthyForSpawn, Cr as normalizeAgentId, Dn as validateProviderHealth, Dr as getAgentRuntimeState, En as init_provider_health, Er as waitForReadySignal, F as init_tier_escalation, Fn as writeChannelsBridgeMcpConfig, Fr as init_codex_auth, G as resumeAgent, Gn as getAgentDir, Gt as transitionIssueToInProgress, H as restartAgent, Lt as BRIDGE_TOKEN_HEADER, Nt as setAgentDeliveryMethod, Or as getAgentRuntimeStateSync, P as decideEscalation, Pn as dismissDevChannelsDialog, Pr as checkCodexAuthStatus, Q as operatorInterventionEvent, Rt as init_bridge_token, Sn as determineModel, Ut as init_spawn_prep, V as recoverAgent, Vn as clearAgentTroubled, X as messageAgent, Xt as resolveStaffing, Yn as getAgentStateSync, Z as init_operator_interventions, _r as init_pty_token, an as getProviderAuthMode, at as saveSessionId, b as init_agents$1, br as resolvePtySupervisorScriptPath, cr as saveAgentState, et as getActivity, fn as init_pi_fifo, ft as stopAgent, hn as ohmypiFifoPaths, i as listRunningAgents, kt as deliverAgentMessage, lr as saveAgentStateSync, mn as init_ohmypi_fifo, mr as writeAgentStateJsonSync, nn as getAgentRuntimeBaseCommand, nr as markAgentStoppedState, nt as getLatestSessionIdSync, pn as piFifoPaths, pr as wipeAgentStateDirs, qn as getAgentState, qt as init_staffing, r as listAgentStates, rt as getSessionId, sn as init_runtime_command, tn as getAcpLauncherFields, tt as getLatestSessionId, un as waitForAcpHostReady, ur as setAgentPaused, vr as writePtyToken, wn as getProviderExportsForModel, xr as clearReadySignal, yr as init_pty_supervisor_locate, zn as clearAgentPaused, zt as writeBridgeTokenSync } from "./queries-CjNIf-Ub.js";
|
|
14
|
+
import { a as performHandoff, i as checkAllTriggers, s as getAgentHealth, t as getCloisterService } from "./service-CLeAoU6G.js";
|
|
15
|
+
import { o as init_persistent_logger, s as logAgentLifecycleSync } from "./session-history-BT3IvqhC.js";
|
|
16
|
+
import { t as init_behavior } from "./behavior-B3exJ42O.js";
|
|
17
|
+
import { a as init_tracker_config, t as getGitHubConfig } from "./tracker-config-G6latr8C.js";
|
|
18
|
+
import { n as init_issue_service_singleton, r as issue_service_singleton_exports } from "./issue-service-singleton-Yx5DdmVJ.js";
|
|
19
|
+
import { o as getInternalTokenSync, s as init_internal_token } from "./internal-token-s0-oKybJ.js";
|
|
20
20
|
import { a as PAN_DIRNAME, i as PAN_CONTINUE_FILENAME, p as init_types } from "./types-hraoaQIp.js";
|
|
21
|
-
import { a as generateXBriefFilename, o as init_lifecycle } from "./lifecycle-
|
|
22
|
-
import { f as readTierOverrides, g as serializeXBriefDocument, h as recordTierPromotion, m as readWorkspacePlanSync, o as init_io, r as findPlan, u as readPlan } from "./io-
|
|
23
|
-
import { B as removeFavorite, E as hasOtherActiveConversationOnTmuxSession, F as markConversationEnded, G as setConversationHarness, K as setConversationModel, M as listConversations, P as markConversationActive, Q as updateConversationDeliveryMethod, S as getConversationByName, W as setConversationEffort, g as backfillConversationModel, h as archiveConversation, k as init_conversations, nt as updateLastAttached, rt as updateSpawnError, x as getConversationById, y as createConversation } from "./conversations-
|
|
24
|
-
import { n as recordFeatureRegistryLifecycle, t as init_feature_registry_population } from "./feature-registry-population-
|
|
25
|
-
import { a as
|
|
26
|
-
import { a as init_claude_permissions, o as resolvePermissionModeSync, r as getClaudePermissionFlagsStringSync, t as BYPASS_PERMISSION_MODE } from "./claude-permissions-
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import { a as
|
|
30
|
-
import { l as init_dag, o as getDispatchableItems } from "./dag-
|
|
31
|
-
import { n as resolveHarness, t as init_harness_resolve } from "./harness-resolve-
|
|
32
|
-
import { a as loadCloisterConfigSync, r as init_config } from "./config-
|
|
33
|
-
import { c as isStateMigrated, o as init_state_home } from "./state-home-
|
|
34
|
-
import { a as init_lifecycle_io, c as updatePlanStatus, s as transitionXBriefOnMain } from "./lifecycle-io-
|
|
35
|
-
import { _ as init_codex_conversation_parser, c as parseEntireConversation, d as init_pi_conversation_parser, g as parseOhmypiConversationMessages, m as init_ohmypi_conversation_parser, p as parsePiConversationMessages, t as init_conversation_service, v as parseCodexConversationMessages } from "./conversation-service-
|
|
36
|
-
import { _ as parseCodexApprovalPrompt, d as getAgentPendingQuestions$1, f as getAgentWorkspace$1, g as normalizeAwaitingInputPrompt, m as detectAwaitingInputForAgent, o as getRuntimeForAgent, p as scanPendingInputsPromise, s as computeAgentEnrichment, u as getAgentJsonlPath$1 } from "./stuck-remediation-
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
21
|
+
import { a as generateXBriefFilename, o as init_lifecycle } from "./lifecycle-yPd___5E.js";
|
|
22
|
+
import { f as readTierOverrides, g as serializeXBriefDocument, h as recordTierPromotion, m as readWorkspacePlanSync, o as init_io, r as findPlan, u as readPlan } from "./io-C9kF1wtJ.js";
|
|
23
|
+
import { B as removeFavorite, E as hasOtherActiveConversationOnTmuxSession, F as markConversationEnded, G as setConversationHarness, K as setConversationModel, M as listConversations, P as markConversationActive, Q as updateConversationDeliveryMethod, S as getConversationByName, W as setConversationEffort, g as backfillConversationModel, h as archiveConversation, k as init_conversations, nt as updateLastAttached, rt as updateSpawnError, x as getConversationById, y as createConversation } from "./conversations-6AfUfbwc.js";
|
|
24
|
+
import { n as recordFeatureRegistryLifecycle, t as init_feature_registry_population } from "./feature-registry-population-DKZFMbFt.js";
|
|
25
|
+
import { a as normalizeModelOverrideSync, i as init_model_validation, n as init_launcher_generator, o as requireModelOverrideSync, r as MODEL_ID_PATTERN, t as generateLauncherScriptSync } from "./launcher-generator-BBWG_SiS.js";
|
|
26
|
+
import { a as init_claude_permissions, o as resolvePermissionModeSync, r as getClaudePermissionFlagsStringSync, t as BYPASS_PERMISSION_MODE } from "./claude-permissions-DNWEVV6z.js";
|
|
27
|
+
import { E as init_layers, I as workspaceContextFile, k as piGlobalContextFile } from "./assemble-J2ZZ2C15.js";
|
|
28
|
+
import { i as prepareHarnessLaunch, r as init_harness_binary } from "./harness-binary-DPUi-Pv8.js";
|
|
29
|
+
import { a as getWorkspaceStackHealth, s as init_stack_health } from "./stack-health-DxSdG9cW.js";
|
|
30
|
+
import { l as init_dag, o as getDispatchableItems } from "./dag-B1ucnjDU.js";
|
|
31
|
+
import { n as resolveHarness, t as init_harness_resolve } from "./harness-resolve-3lNZkyT4.js";
|
|
32
|
+
import { a as loadCloisterConfigSync, r as init_config } from "./config-CKxYiCmX.js";
|
|
33
|
+
import { c as isStateMigrated, o as init_state_home } from "./state-home-Cn_Qu8IX.js";
|
|
34
|
+
import { a as init_lifecycle_io, c as updatePlanStatus, s as transitionXBriefOnMain } from "./lifecycle-io-BREGpnLk.js";
|
|
35
|
+
import { _ as init_codex_conversation_parser, b as parseAcpConversationMessages, c as parseEntireConversation, d as init_pi_conversation_parser, g as parseOhmypiConversationMessages, m as init_ohmypi_conversation_parser, p as parsePiConversationMessages, t as init_conversation_service, v as parseCodexConversationMessages, y as init_acp_conversation_parser } from "./conversation-service-DPJ71F33.js";
|
|
36
|
+
import { _ as parseCodexApprovalPrompt, d as getAgentPendingQuestions$1, f as getAgentWorkspace$1, g as normalizeAwaitingInputPrompt, m as detectAwaitingInputForAgent, o as getRuntimeForAgent, p as scanPendingInputsPromise, s as computeAgentEnrichment, u as getAgentJsonlPath$1 } from "./stuck-remediation-DYuPRYYw.js";
|
|
37
|
+
import { B as getBook, H as liveOrderIssueLookup, T as resolveLiveFlywheelRunId, w as readFlywheelLaunchMetadata, y as getFlywheelRunDir, z as computeBookProgress } from "./flywheel-DHrgCphM.js";
|
|
38
|
+
import { Dt as classifyMemoryPressure, It as getSystemHealthSnapshot, Pt as getResourceConfig } from "./deacon-CU_cAYSR.js";
|
|
39
|
+
import { o as stopWorkspaceDocker, r as init_workspace_manager } from "./workspace-manager-CBhNdzE4.js";
|
|
40
|
+
import { a as init_jsonl_parser, o as normalizeModelName } from "./jsonl-parser-BXSlHwEh.js";
|
|
41
|
+
import { r as init_in_flight_guard, t as createInFlightGuard } from "./in-flight-guard-CAAkqPLu.js";
|
|
42
|
+
import { a as loadWorkspaceMetadataSync } from "./workspace-metadata-_WygnyoX.js";
|
|
42
43
|
import { basename, delimiter, dirname, join, resolve } from "node:path";
|
|
43
44
|
import { Cause, Data, Effect, Layer, Option, Schema, Stream } from "effect";
|
|
44
45
|
import { join as join$1 } from "path";
|
|
@@ -200,10 +201,12 @@ init_layers();
|
|
|
200
201
|
init_harness_binary();
|
|
201
202
|
init_ohmypi_fifo();
|
|
202
203
|
init_pi_fifo();
|
|
204
|
+
init_runtime_command();
|
|
203
205
|
init_stack_health();
|
|
204
206
|
init_launcher_generator();
|
|
205
207
|
init_dag();
|
|
206
208
|
init_staffing();
|
|
209
|
+
init_spawn_prep();
|
|
207
210
|
init_harness_resolve();
|
|
208
211
|
init_bridge_token();
|
|
209
212
|
init_operator_interventions();
|
|
@@ -364,7 +367,215 @@ async function waitForSessionRespawn(sessionName, timeoutMs) {
|
|
|
364
367
|
return Effect.runPromise(sessionExists(sessionName));
|
|
365
368
|
}
|
|
366
369
|
//#endregion
|
|
370
|
+
//#region routes/dashboard-auth.ts
|
|
371
|
+
init_state_read_home();
|
|
372
|
+
init_state_plane();
|
|
373
|
+
init_types();
|
|
374
|
+
init_issue_lifecycle();
|
|
375
|
+
init_codex_auth();
|
|
376
|
+
init_config();
|
|
377
|
+
init_state_home();
|
|
378
|
+
init_internal_token();
|
|
379
|
+
const DASHBOARD_SESSION_COOKIE = "overdeck_session";
|
|
380
|
+
const DASHBOARD_CSRF_HEADER = "x-overdeck-csrf-token";
|
|
381
|
+
const DASHBOARD_SESSION_MAX_AGE_SECONDS = 3600 * 24 * 30;
|
|
382
|
+
let browserSessionToken;
|
|
383
|
+
let browserCsrfToken;
|
|
384
|
+
function getDashboardSessionToken() {
|
|
385
|
+
if (browserSessionToken) return browserSessionToken;
|
|
386
|
+
const override = process.env["OVERDECK_DASHBOARD_SESSION_TOKEN"];
|
|
387
|
+
if (override) {
|
|
388
|
+
browserSessionToken = override;
|
|
389
|
+
return browserSessionToken;
|
|
390
|
+
}
|
|
391
|
+
const internal = getInternalTokenSync();
|
|
392
|
+
browserSessionToken = internal ? createHmac("sha256", internal).update("overdeck-dashboard-session-v1").digest("base64url") : randomBytes(32).toString("base64url");
|
|
393
|
+
return browserSessionToken;
|
|
394
|
+
}
|
|
395
|
+
function dashboardCsrfToken() {
|
|
396
|
+
if (browserCsrfToken) return browserCsrfToken;
|
|
397
|
+
const override = process.env["OVERDECK_DASHBOARD_CSRF_TOKEN"];
|
|
398
|
+
if (override) {
|
|
399
|
+
browserCsrfToken = override;
|
|
400
|
+
return browserCsrfToken;
|
|
401
|
+
}
|
|
402
|
+
const internal = getInternalTokenSync();
|
|
403
|
+
browserCsrfToken = internal ? createHmac("sha256", internal).update("overdeck-dashboard-csrf-v1").digest("base64url") : randomBytes(32).toString("base64url");
|
|
404
|
+
return browserCsrfToken;
|
|
405
|
+
}
|
|
406
|
+
function constantTimeTokenEqual$1(provided, expected) {
|
|
407
|
+
if (!provided) return false;
|
|
408
|
+
return timingSafeEqual(createHash$1("sha256").update(provided).digest(), createHash$1("sha256").update(expected).digest());
|
|
409
|
+
}
|
|
410
|
+
function cookieValue(cookieHeader, name) {
|
|
411
|
+
if (!cookieHeader) return void 0;
|
|
412
|
+
for (const part of cookieHeader.split(";")) {
|
|
413
|
+
const [rawKey, ...rawValue] = part.trim().split("=");
|
|
414
|
+
if (rawKey !== name) continue;
|
|
415
|
+
try {
|
|
416
|
+
return decodeURIComponent(rawValue.join("="));
|
|
417
|
+
} catch {
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
function dashboardSessionCookieHeader(options = {}) {
|
|
423
|
+
const secure = options.secure ? "; Secure" : "";
|
|
424
|
+
return `${DASHBOARD_SESSION_COOKIE}=${encodeURIComponent(getDashboardSessionToken())}; Path=/; HttpOnly; SameSite=Strict; Max-Age=${DASHBOARD_SESSION_MAX_AGE_SECONDS}${secure}`;
|
|
425
|
+
}
|
|
426
|
+
function hasDashboardInternalTokenHeaders(headers) {
|
|
427
|
+
const expected = getInternalTokenSync();
|
|
428
|
+
if (!expected) return false;
|
|
429
|
+
if (constantTimeTokenEqual$1(getHeaderFromMap(headers, "x-overdeck-internal-token"), expected)) return true;
|
|
430
|
+
const authorization = getHeaderFromMap(headers, "authorization");
|
|
431
|
+
if (authorization) {
|
|
432
|
+
const [scheme, token] = authorization.split(/\s+/);
|
|
433
|
+
if (scheme?.toLowerCase() === "bearer" && constantTimeTokenEqual$1(token, expected)) return true;
|
|
434
|
+
}
|
|
435
|
+
return false;
|
|
436
|
+
}
|
|
437
|
+
function hasDashboardInternalToken(request) {
|
|
438
|
+
return hasDashboardInternalTokenHeaders(request.headers);
|
|
439
|
+
}
|
|
440
|
+
function hasDashboardAuthHeaders(headers) {
|
|
441
|
+
return hasDashboardInternalTokenHeaders(headers) || constantTimeTokenEqual$1(cookieValue(getHeaderFromMap(headers, "cookie"), "overdeck_session"), getDashboardSessionToken());
|
|
442
|
+
}
|
|
443
|
+
function hasDashboardAuth(request) {
|
|
444
|
+
return hasDashboardAuthHeaders(request.headers);
|
|
445
|
+
}
|
|
446
|
+
function isJsonContentType(headers) {
|
|
447
|
+
const contentType = getHeaderFromMap(headers, "content-type");
|
|
448
|
+
if (!contentType) return false;
|
|
449
|
+
const [mime] = contentType.toLowerCase().split(";");
|
|
450
|
+
return mime.trim() === "application/json";
|
|
451
|
+
}
|
|
452
|
+
function hasTrustedExactOrigin(headers) {
|
|
453
|
+
const origin = getHeaderFromMap(headers, "origin");
|
|
454
|
+
if (!origin) return false;
|
|
455
|
+
const normalized = normalizeOrigin(origin);
|
|
456
|
+
return !!normalized && getTrustedOrigins().includes(normalized);
|
|
457
|
+
}
|
|
458
|
+
function hasValidCsrfToken(headers) {
|
|
459
|
+
return constantTimeTokenEqual$1(getHeaderFromMap(headers, DASHBOARD_CSRF_HEADER), dashboardCsrfToken());
|
|
460
|
+
}
|
|
461
|
+
function rejectUnsafeDashboardMutationRequest(request) {
|
|
462
|
+
const authError = rejectUnauthorizedDashboardRequest(request);
|
|
463
|
+
if (authError) return authError;
|
|
464
|
+
const headers = request.headers;
|
|
465
|
+
if (!isJsonContentType(headers)) return jsonResponse({ error: "Content-Type must be application/json" }, { status: 400 });
|
|
466
|
+
if (hasDashboardInternalToken(request)) return null;
|
|
467
|
+
if (getHeaderFromMap(headers, "origin") && !hasTrustedExactOrigin(headers)) return jsonResponse({ error: "Invalid origin" }, { status: 403 });
|
|
468
|
+
if (!hasValidCsrfToken(headers)) return jsonResponse({ error: "Invalid CSRF token" }, { status: 403 });
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
function ipv4ToInt(value) {
|
|
472
|
+
const parts = value.split(".");
|
|
473
|
+
if (parts.length !== 4) return null;
|
|
474
|
+
let result = 0;
|
|
475
|
+
for (const part of parts) {
|
|
476
|
+
const octet = Number(part);
|
|
477
|
+
if (!Number.isInteger(octet) || octet < 0 || octet > 255) return null;
|
|
478
|
+
result = (result << 8 | octet) >>> 0;
|
|
479
|
+
}
|
|
480
|
+
return result;
|
|
481
|
+
}
|
|
482
|
+
/** RFC1918 private ranges — Docker bridges always fall inside one of these. */
|
|
483
|
+
function isRfc1918(ip) {
|
|
484
|
+
return (ip & 4278190080) >>> 0 === 167772160 || (ip & 4293918720) >>> 0 === 2886729728 || (ip & 4294901760) >>> 0 === 3232235520;
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* True when `addr` is the IP of a container on one of THIS host's Docker bridge
|
|
488
|
+
* interfaces (docker0 / br-*). Such a peer can only be a process running on this
|
|
489
|
+
* machine — our own host-local Traefik fronting overdeck.localhost, or another
|
|
490
|
+
* Overdeck container — never a LAN client (a direct LAN hit to the 0.0.0.0
|
|
491
|
+
* API port arrives with a LAN peer that is not inside any Docker bridge subnet).
|
|
492
|
+
*
|
|
493
|
+
* Pure for testability: the interface map is injected. We only ever trust
|
|
494
|
+
* RFC1918 bridge subnets, so a misconfigured public-range br-* cannot widen
|
|
495
|
+
* trust beyond the local Docker fabric.
|
|
496
|
+
*/
|
|
497
|
+
function peerIsHostLocalDockerBridge(addr, interfaces) {
|
|
498
|
+
const peer = ipv4ToInt(addr);
|
|
499
|
+
if (peer === null) return false;
|
|
500
|
+
for (const [name, addrs] of Object.entries(interfaces)) {
|
|
501
|
+
if (name !== "docker0" && !name.startsWith("br-")) continue;
|
|
502
|
+
for (const info of addrs ?? []) {
|
|
503
|
+
if (info.family !== "IPv4") continue;
|
|
504
|
+
const ifaceIp = ipv4ToInt(info.address);
|
|
505
|
+
const mask = ipv4ToInt(info.netmask);
|
|
506
|
+
if (ifaceIp === null || mask === null) continue;
|
|
507
|
+
const network = (ifaceIp & mask) >>> 0;
|
|
508
|
+
if (!isRfc1918(network)) continue;
|
|
509
|
+
if ((peer & mask) >>> 0 === network) return true;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return false;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* True when `addr` shares an RFC1918 subnet with one of THIS process's own
|
|
516
|
+
* network interfaces. This is the in-container counterpart of
|
|
517
|
+
* peerIsHostLocalDockerBridge: inside a container the Docker bridge is
|
|
518
|
+
* invisible — the container sees only its veth endpoints (eth0/eth1), so the
|
|
519
|
+
* docker0/br-* name filter never matches and the host-local Traefik fronting
|
|
520
|
+
* the stack 401'd every session mint (first hit live on the PAN-1737 UAT
|
|
521
|
+
* stack). A peer inside one of the container's attached Docker-network
|
|
522
|
+
* subnets can only be another container on those networks — the server
|
|
523
|
+
* publishes no host port (Traefik labels only), so no LAN client can ever
|
|
524
|
+
* present such an address. Only consulted when running inside a container.
|
|
525
|
+
*/
|
|
526
|
+
function peerIsLocalContainerNetwork(addr, interfaces) {
|
|
527
|
+
const peer = ipv4ToInt(addr);
|
|
528
|
+
if (peer === null) return false;
|
|
529
|
+
for (const addrs of Object.values(interfaces)) for (const info of addrs ?? []) {
|
|
530
|
+
if (info.family !== "IPv4" || info.internal) continue;
|
|
531
|
+
const ifaceIp = ipv4ToInt(info.address);
|
|
532
|
+
const mask = ipv4ToInt(info.netmask);
|
|
533
|
+
if (ifaceIp === null || mask === null) continue;
|
|
534
|
+
const network = (ifaceIp & mask) >>> 0;
|
|
535
|
+
if (!isRfc1918(network)) continue;
|
|
536
|
+
if ((peer & mask) >>> 0 === network) return true;
|
|
537
|
+
}
|
|
538
|
+
return false;
|
|
539
|
+
}
|
|
540
|
+
/** Docker creates /.dockerenv in every container — stable in-container signal. */
|
|
541
|
+
const runningInContainer = existsSync("/.dockerenv");
|
|
542
|
+
/**
|
|
543
|
+
* A request we trust to mint a session because it originated from this machine —
|
|
544
|
+
* the local browser hitting the dashboard directly (127.0.0.1), or the
|
|
545
|
+
* host-local Traefik that fronts overdeck.localhost. In Docker, that Traefik reaches
|
|
546
|
+
* the host server from a Docker-bridge IP (e.g. 172.18.0.2), NOT 127.0.0.1, so
|
|
547
|
+
* a literal-loopback check alone silently breaks the zero-step bootstrap for
|
|
548
|
+
* every overdeck.localhost user — their session mint 401s and no cookie is ever set.
|
|
549
|
+
*
|
|
550
|
+
* This is the auto-bootstrap that removes the manual one-time #overdeck_token
|
|
551
|
+
* step: any browser on overdeck.localhost gets a session with no user action. It is
|
|
552
|
+
* NOT a security downgrade for the LAN — the raw API ports bind 0.0.0.0, but a
|
|
553
|
+
* direct LAN hit has a non-loopback, non-Docker-bridge peer and is rejected. We
|
|
554
|
+
* read ONLY the real TCP peer (request.remoteAddress), never X-Forwarded-For,
|
|
555
|
+
* which a caller could spoof.
|
|
556
|
+
*/
|
|
557
|
+
function isLoopbackPeer(request) {
|
|
558
|
+
const remoteAddress = request.remoteAddress;
|
|
559
|
+
const raw = remoteAddress && typeof remoteAddress === "object" && "_tag" in remoteAddress ? Option.getOrElse(remoteAddress, () => "") : typeof remoteAddress === "string" ? remoteAddress : "";
|
|
560
|
+
if (!raw) return false;
|
|
561
|
+
const addr = raw.startsWith("::ffff:") ? raw.slice(7) : raw;
|
|
562
|
+
if (addr === "127.0.0.1" || addr === "::1") return true;
|
|
563
|
+
if (peerIsHostLocalDockerBridge(addr, networkInterfaces())) return true;
|
|
564
|
+
return runningInContainer && peerIsLocalContainerNetwork(addr, networkInterfaces());
|
|
565
|
+
}
|
|
566
|
+
function rejectUnauthorizedDashboardSessionMintRequest(request) {
|
|
567
|
+
if (!getInternalTokenSync()) return jsonResponse({ error: "dashboard session token not configured" }, { status: 503 });
|
|
568
|
+
if (!hasDashboardInternalToken(request) && !isLoopbackPeer(request)) return jsonResponse({ error: "unauthorized" }, { status: 401 });
|
|
569
|
+
return null;
|
|
570
|
+
}
|
|
571
|
+
function rejectUnauthorizedDashboardRequest(request) {
|
|
572
|
+
if (!getInternalTokenSync()) return jsonResponse({ error: "dashboard session token not configured" }, { status: 503 });
|
|
573
|
+
if (!hasDashboardAuth(request)) return jsonResponse({ error: "unauthorized" }, { status: 401 });
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
//#endregion
|
|
367
577
|
//#region routes/jsonl-resolver.ts
|
|
578
|
+
init_acp_conversation_parser();
|
|
368
579
|
init_codex_conversation_parser();
|
|
369
580
|
init_ohmypi_conversation_parser();
|
|
370
581
|
init_pi_conversation_parser();
|
|
@@ -390,6 +601,8 @@ init_conversation_service();
|
|
|
390
601
|
* order no longer reflects time-recency. We disambiguate
|
|
391
602
|
* across all listed IDs by JSONL mtime.
|
|
392
603
|
* 3. runtime state — in-process mirror, populated by hooks
|
|
604
|
+
* 4. agents registry — the DB row's session_id recorded at spawn; survives
|
|
605
|
+
* janitor removal of the agent directory
|
|
393
606
|
*
|
|
394
607
|
* Async-only (fs/promises) because this code path runs inside the dashboard
|
|
395
608
|
* server's event loop.
|
|
@@ -475,6 +688,10 @@ async function resolveClaudeSessionId(agentId, opts = {}) {
|
|
|
475
688
|
const runtimeState = await (opts.getRuntimeStateAsync ?? ((id) => Effect.runPromise(getAgentRuntimeState(id))))(agentId);
|
|
476
689
|
if (runtimeState?.claudeSessionId) return runtimeState.claudeSessionId;
|
|
477
690
|
} catch {}
|
|
691
|
+
if (!opts.agentsDirOverride) {
|
|
692
|
+
const registrySessionId = getAgentStateSync(agentId)?.sessionId?.trim();
|
|
693
|
+
if (registrySessionId) return registrySessionId;
|
|
694
|
+
}
|
|
478
695
|
return null;
|
|
479
696
|
}
|
|
480
697
|
/**
|
|
@@ -532,7 +749,7 @@ async function readRecordedState(agentId, opts) {
|
|
|
532
749
|
* Resolve the harness for transcript routing. Reads state.json, then
|
|
533
750
|
* self-corrects when the recorded value is stale.
|
|
534
751
|
*
|
|
535
|
-
* Trust an explicit non-default harness (codex / pi / ohmypi) — it was chosen
|
|
752
|
+
* Trust an explicit non-default harness (codex / pi / ohmypi / acp) — it was chosen
|
|
536
753
|
* by resolveHarness at spawn time and is not the generic fallback. The
|
|
537
754
|
* 'claude-code' default, however, goes stale in one observed case: a
|
|
538
755
|
* wipe-and-respawn that changed the provider-default harness left state.json
|
|
@@ -550,8 +767,9 @@ async function readRecordedState(agentId, opts) {
|
|
|
550
767
|
*/
|
|
551
768
|
async function resolveAgentHarness(agentId, opts = {}) {
|
|
552
769
|
const recorded = (await readRecordedState(agentId, opts)).harness;
|
|
553
|
-
if (recorded === "codex" || recorded === "pi" || recorded === "ohmypi") return recorded;
|
|
770
|
+
if (recorded === "codex" || recorded === "pi" || recorded === "ohmypi" || recorded === "acp") return recorded;
|
|
554
771
|
if (await agentHasClaudeTranscript(agentId, opts)) return recorded ?? "claude-code";
|
|
772
|
+
if (await resolveAcpTranscriptPath(agentId, opts)) return "acp";
|
|
555
773
|
if (await resolveCodexRolloutPath(agentId, opts)) return "codex";
|
|
556
774
|
if (await resolvePiSessionPath(agentId, opts)) return "ohmypi";
|
|
557
775
|
return recorded;
|
|
@@ -581,7 +799,7 @@ async function resolveCodexRolloutPath(agentId, opts = {}) {
|
|
|
581
799
|
const agentDir = join(opts.agentsDirOverride ?? join(getOverdeckHome(), "agents"), agentId);
|
|
582
800
|
const codexHome = join(agentDir, "codex-home");
|
|
583
801
|
if (!await pathExists$1(codexHome)) return null;
|
|
584
|
-
const { findRolloutPath, findLatestRollout } = await import("./codex-
|
|
802
|
+
const { findRolloutPath, findLatestRollout } = await import("./codex-GcHuUF-k.js");
|
|
585
803
|
const threadId = (await readOptional(join(agentDir, "codex-thread-id")))?.trim();
|
|
586
804
|
if (threadId) {
|
|
587
805
|
const rollout = findRolloutPath(codexHome, threadId);
|
|
@@ -589,6 +807,11 @@ async function resolveCodexRolloutPath(agentId, opts = {}) {
|
|
|
589
807
|
}
|
|
590
808
|
return findLatestRollout(codexHome);
|
|
591
809
|
}
|
|
810
|
+
/** Resolve the normalized transcript written by the persistent ACP host. */
|
|
811
|
+
async function resolveAcpTranscriptPath(agentId, opts = {}) {
|
|
812
|
+
const transcriptPath = join(opts.agentsDirOverride ?? join(getOverdeckHome(), "agents"), agentId, "acp-session.jsonl");
|
|
813
|
+
return await pathExists$1(transcriptPath) ? transcriptPath : null;
|
|
814
|
+
}
|
|
592
815
|
/**
|
|
593
816
|
* Resolve the pi/kimi session JSONL (PAN-1908). Pi writes its session transcript
|
|
594
817
|
* as `<iso-ts>_<session-id>.jsonl` either in the agent dir's `sessions/` subdir
|
|
@@ -599,6 +822,7 @@ async function resolveCodexRolloutPath(agentId, opts = {}) {
|
|
|
599
822
|
async function resolvePiSessionPath(agentId, opts = {}) {
|
|
600
823
|
const agentDir = join(opts.agentsDirOverride ?? join(getOverdeckHome(), "agents"), agentId);
|
|
601
824
|
const NON_TRANSCRIPT = new Set([
|
|
825
|
+
"acp-session.jsonl",
|
|
602
826
|
"cost-events.jsonl",
|
|
603
827
|
"activity.jsonl",
|
|
604
828
|
"pending-events.jsonl"
|
|
@@ -637,6 +861,7 @@ async function resolveJsonlPath(agentId, workspacePath, opts = {}) {
|
|
|
637
861
|
const behavior = behaviorForHarness(harness);
|
|
638
862
|
if (behavior.transcriptKind === "codex-rollout-jsonl") return resolveCodexRolloutPath(agentId, opts);
|
|
639
863
|
if (behavior.transcriptKind === "ohmypi-jsonl") return resolvePiSessionPath(agentId, opts);
|
|
864
|
+
if (behavior.transcriptKind === "acp-jsonl") return resolveAcpTranscriptPath(agentId, opts);
|
|
640
865
|
const claudeSessionId = await resolveClaudeSessionId(agentId, opts);
|
|
641
866
|
if (!claudeSessionId) {
|
|
642
867
|
logTranscriptResolution(agentId, `missing-session-id:${harness ?? "unknown"}`, `failed harness=${harness ?? "unknown"} reason=no-session-id checked=session.id,sessions.json,runtime-state`, opts);
|
|
@@ -808,7 +1033,7 @@ async function getWorkAgentLifecycleStateSnapshot(agentOrIssueId) {
|
|
|
808
1033
|
runtimeState: runtime,
|
|
809
1034
|
agentStatus,
|
|
810
1035
|
canStartFresh: (!hasLiveTmuxSession || hasLiveTmuxSession && isStopped) && (!requiresSessionResetBeforeFreshStart || isOrphaned),
|
|
811
|
-
canResumeSession: !isRunning && hasResumableBackingState && (isStopped || isCrashed),
|
|
1036
|
+
canResumeSession: !isRunning && hasSavedSession && hasResumableBackingState && (isStopped || isCrashed),
|
|
812
1037
|
canRestartWithContext: hasAgentState && hasWorkspace,
|
|
813
1038
|
canResetSession: hasSavedSession && hasResumableBackingState,
|
|
814
1039
|
requiresSessionResetBeforeFreshStart,
|
|
@@ -974,7 +1199,8 @@ function buildPanStartArgs(input) {
|
|
|
974
1199
|
"--model",
|
|
975
1200
|
input.model,
|
|
976
1201
|
...input.harness ? ["--harness", input.harness] : [],
|
|
977
|
-
...input.allowHost ? ["--host", "--yes"] : []
|
|
1202
|
+
...input.allowHost ? ["--host", "--yes"] : [],
|
|
1203
|
+
...input.offBook ? ["--off-book"] : []
|
|
978
1204
|
];
|
|
979
1205
|
}
|
|
980
1206
|
/**
|
|
@@ -1083,7 +1309,7 @@ function emitStartAgentPhase(issueId, phase, status, reason, details = {}) {
|
|
|
1083
1309
|
});
|
|
1084
1310
|
}
|
|
1085
1311
|
const INTERNAL_TOKEN_HEADER = "x-overdeck-internal-token";
|
|
1086
|
-
function constantTimeTokenEqual
|
|
1312
|
+
function constantTimeTokenEqual(provided, expected) {
|
|
1087
1313
|
if (!provided) return false;
|
|
1088
1314
|
const providedBuffer = Buffer.from(provided, "utf8");
|
|
1089
1315
|
const expectedBuffer = Buffer.from(expected, "utf8");
|
|
@@ -1109,7 +1335,7 @@ async function validateAgentRuntimeEventAuth(request) {
|
|
|
1109
1335
|
error: "internal token not configured"
|
|
1110
1336
|
}, { status: 503 })
|
|
1111
1337
|
};
|
|
1112
|
-
if (constantTimeTokenEqual
|
|
1338
|
+
if (constantTimeTokenEqual(getHeaderFromMap(request.headers, INTERNAL_TOKEN_HEADER), expected)) return { ok: true };
|
|
1113
1339
|
return {
|
|
1114
1340
|
ok: false,
|
|
1115
1341
|
response: jsonResponse({
|
|
@@ -1725,7 +1951,7 @@ const getAgentOutputRoute = HttpRouter.add("GET", "/api/agents/:id/output", http
|
|
|
1725
1951
|
} catch {}
|
|
1726
1952
|
let stdout;
|
|
1727
1953
|
if (isRemote && vmName) {
|
|
1728
|
-
const { getRemoteAgentOutput } = await import("./remote-agents-
|
|
1954
|
+
const { getRemoteAgentOutput } = await import("./remote-agents-CA3Ihlxj.js");
|
|
1729
1955
|
stdout = await getRemoteAgentOutput(id, vmName, parseInt(String(lines), 10) || 100);
|
|
1730
1956
|
} else stdout = await Effect.runPromise(capturePane(id, parseInt(String(lines), 10) || 100));
|
|
1731
1957
|
if (!stdout || stdout.trim() === "" || stdout.trim() === "Session not found") {
|
|
@@ -1790,6 +2016,20 @@ async function buildConversationResponse(id) {
|
|
|
1790
2016
|
streaming: false
|
|
1791
2017
|
};
|
|
1792
2018
|
}
|
|
2019
|
+
if (harness === "acp") {
|
|
2020
|
+
const sessionFile = await resolveAcpTranscriptPath(id);
|
|
2021
|
+
if (!sessionFile || !existsSync(sessionFile)) return EMPTY_CONVERSATION;
|
|
2022
|
+
const result = await parseAcpConversationMessages(sessionFile);
|
|
2023
|
+
return {
|
|
2024
|
+
...result,
|
|
2025
|
+
messages: result.messages.map((message) => message.role === "assistant" ? {
|
|
2026
|
+
...message,
|
|
2027
|
+
completedAt: message.completedAt ?? message.createdAt,
|
|
2028
|
+
streaming: false
|
|
2029
|
+
} : message),
|
|
2030
|
+
streaming: false
|
|
2031
|
+
};
|
|
2032
|
+
}
|
|
1793
2033
|
let jsonlPath = null;
|
|
1794
2034
|
const pinnedSessionId = await readLauncherPinnedSessionId(id);
|
|
1795
2035
|
if (pinnedSessionId) {
|
|
@@ -2146,7 +2386,7 @@ async function cleanupConversationAttachments(name) {
|
|
|
2146
2386
|
* sessions that the lifecycle poller missed. */
|
|
2147
2387
|
async function cleanupOrphanedConversationAttachments() {
|
|
2148
2388
|
try {
|
|
2149
|
-
const { listConversations } = await import("./conversations-
|
|
2389
|
+
const { listConversations } = await import("./conversations-CAsJF9kh.js");
|
|
2150
2390
|
const convNames = new Set(listConversations().map((c) => c.name));
|
|
2151
2391
|
const root = getConversationAttachmentsRoot();
|
|
2152
2392
|
await runInBatches((await readdir(root, { withFileTypes: true })).filter((entry) => entry.isDirectory() && !convNames.has(entry.name)).map((entry) => join(root, entry.name)), 10, (path) => rm(path, {
|
|
@@ -2424,7 +2664,7 @@ async function stopConversationRuntime(conv, name) {
|
|
|
2424
2664
|
function shellQuote(str) {
|
|
2425
2665
|
return "'" + str.replace(/'/g, "'\"'\"'") + "'";
|
|
2426
2666
|
}
|
|
2427
|
-
const SAFE_MODEL_PATTERN =
|
|
2667
|
+
const SAFE_MODEL_PATTERN = MODEL_ID_PATTERN;
|
|
2428
2668
|
const SAFE_EFFORT_PATTERN = /^(low|medium|high)$/;
|
|
2429
2669
|
const SAFE_ISSUE_ID_PATTERN = /^[A-Z0-9]+-[0-9]+$/;
|
|
2430
2670
|
const PI_CONVERSATION_SOURCE_CONTRACT = [
|
|
@@ -2436,7 +2676,7 @@ async function resolveAllowedHarness(requested, model) {
|
|
|
2436
2676
|
if (!model) return "claude-code";
|
|
2437
2677
|
return resolveHarness({
|
|
2438
2678
|
model,
|
|
2439
|
-
explicit: requested === "ohmypi" || requested === "claude-code" || requested === "codex" ? requested : void 0
|
|
2679
|
+
explicit: requested === "ohmypi" || requested === "claude-code" || requested === "codex" || requested === "acp" ? requested : void 0
|
|
2440
2680
|
});
|
|
2441
2681
|
}
|
|
2442
2682
|
async function isInsideGitWorkTree(dir) {
|
|
@@ -2518,6 +2758,10 @@ function shouldUseSupervisorForConversation(harness, options = {}) {
|
|
|
2518
2758
|
return getHarnessBehavior(harness).supportsPtySupervisor && process.env.OVERDECK_DOCKER_WORKSPACE !== "1" && process.env.PAN_DOCKER !== "1";
|
|
2519
2759
|
}
|
|
2520
2760
|
async function waitForConversationRuntimeReady(tmuxSession, harness, mode) {
|
|
2761
|
+
if (harness === "acp") {
|
|
2762
|
+
await waitForAcpHostReady(tmuxSession);
|
|
2763
|
+
return;
|
|
2764
|
+
}
|
|
2521
2765
|
const transcriptKind = getHarnessBehavior(harness).transcriptKind;
|
|
2522
2766
|
if (transcriptKind === "ohmypi-jsonl") {
|
|
2523
2767
|
if (!await waitForPiTuiReady(tmuxSession)) throw new Error(`Pi (ohmypi) did not become interactive in ${tmuxSession} within the startup window — MCP server connections are likely still in progress. Retry once MCP servers finish connecting, or check ~/.claude/mcp.json for a slow/hanging server.`);
|
|
@@ -2533,7 +2777,7 @@ async function handleConversationSwitchModel(name, body) {
|
|
|
2533
2777
|
const currentHarness = conv.harness ?? "claude-code";
|
|
2534
2778
|
const requestedHarness = body["harness"];
|
|
2535
2779
|
let harness = currentHarness;
|
|
2536
|
-
if (requestedHarness === "ohmypi" || requestedHarness === "pi" || requestedHarness === "claude-code" || requestedHarness === "codex") {
|
|
2780
|
+
if (requestedHarness === "ohmypi" || requestedHarness === "pi" || requestedHarness === "claude-code" || requestedHarness === "codex" || requestedHarness === "acp") {
|
|
2537
2781
|
const requestedRuntime = requestedHarness === "pi" ? "ohmypi" : requestedHarness;
|
|
2538
2782
|
if (requestedRuntime !== currentHarness) {
|
|
2539
2783
|
const policyModel = model ?? conv.model ?? "";
|
|
@@ -2686,14 +2930,25 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
2686
2930
|
let providerExportsStr = "";
|
|
2687
2931
|
let piFields;
|
|
2688
2932
|
let codexFields;
|
|
2933
|
+
let acpFields;
|
|
2689
2934
|
let codexTransport;
|
|
2690
|
-
if (
|
|
2935
|
+
if (behavior.launchCommandKind === "acp-host") {
|
|
2936
|
+
if (!model) throw new Error("ACP conversation requires a model");
|
|
2937
|
+
if (!SAFE_MODEL_PATTERN.test(model)) throw new Error("Invalid model name");
|
|
2938
|
+
const sessionIdPath = join(getOverdeckHome(), "agents", tmuxSession, "acp-session-id");
|
|
2939
|
+
const resumeSessionId = resume ? await readFile(sessionIdPath, "utf-8").then((value) => value.trim() || void 0).catch(() => void 0) : void 0;
|
|
2940
|
+
await rm(sessionIdPath, { force: true });
|
|
2941
|
+
acpFields = {
|
|
2942
|
+
...getAcpLauncherFields(tmuxSession, model, cwd, harnessLaunch.binaryPath, "work"),
|
|
2943
|
+
resumeSessionId
|
|
2944
|
+
};
|
|
2945
|
+
runtimeCommand = "acp-host";
|
|
2946
|
+
} else if (model) {
|
|
2691
2947
|
if (!SAFE_MODEL_PATTERN.test(model)) throw new Error("Invalid model name");
|
|
2692
2948
|
runtimeCommand = await getAgentRuntimeBaseCommand(model, void 0, void 0, harness);
|
|
2693
2949
|
const mode = resolvePermissionModeSync();
|
|
2694
2950
|
if (!runtimeCommand.includes("--permission-mode")) runtimeCommand = `${runtimeCommand} --permission-mode ${mode === "auto" ? "auto" : BYPASS_PERMISSION_MODE}`;
|
|
2695
2951
|
providerExportsStr = (await getProviderExportsForModel(model)).trim();
|
|
2696
|
-
await getProviderEnvForModel(model);
|
|
2697
2952
|
if (behavior.transcriptKind === "ohmypi-jsonl") {
|
|
2698
2953
|
if (getProviderForModelSync(model).name === "openai") {
|
|
2699
2954
|
const auth = await getOhmypiCodexAuthStatus({ refreshIfExpired: true });
|
|
@@ -2725,7 +2980,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
2725
2980
|
const codexApprovalPolicy = codexPermMode === "full-access" ? "never" : "on-request";
|
|
2726
2981
|
const codexSandboxMode = codexPermMode === "full-access" ? "danger-full-access" : codexPermMode === "read-only" ? "read-only" : "workspace-write";
|
|
2727
2982
|
const codexApprovalsReviewer = codexPermMode === "auto-review" ? "auto_review" : void 0;
|
|
2728
|
-
const { initCodexHome, extractThreadIdFromRollout } = await import("./codex-
|
|
2983
|
+
const { initCodexHome, extractThreadIdFromRollout } = await import("./codex-GcHuUF-k.js");
|
|
2729
2984
|
initCodexHome(codexHome, {
|
|
2730
2985
|
trustedDir: cwd,
|
|
2731
2986
|
approvalPolicy: codexApprovalPolicy,
|
|
@@ -2755,7 +3010,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
2755
3010
|
await writePtyToken(tmuxSession);
|
|
2756
3011
|
}
|
|
2757
3012
|
let channelsBridgeMcpConfig;
|
|
2758
|
-
if (!piFields && !codexFields && !plainFork && isClaudeCodeChannelsEnabled() && (!model || getProviderForModelSync(model).name === "anthropic") && process.env.CLAUDE_CODE_USE_BEDROCK !== "1" && process.env.CLAUDE_CODE_USE_VERTEX !== "1" && process.env.CLAUDE_CODE_USE_FOUNDRY !== "1" && process.env.OVERDECK_DOCKER_WORKSPACE !== "1" && process.env.PAN_DOCKER !== "1") {
|
|
3013
|
+
if (!piFields && !codexFields && !acpFields && !plainFork && isClaudeCodeChannelsEnabled() && (!model || getProviderForModelSync(model).name === "anthropic") && process.env.CLAUDE_CODE_USE_BEDROCK !== "1" && process.env.CLAUDE_CODE_USE_VERTEX !== "1" && process.env.CLAUDE_CODE_USE_FOUNDRY !== "1" && process.env.OVERDECK_DOCKER_WORKSPACE !== "1" && process.env.PAN_DOCKER !== "1") {
|
|
2759
3014
|
channelsBridgeMcpConfig = join(stateDir, "agent-mcp.json");
|
|
2760
3015
|
writeBridgeTokenSync(tmuxSession);
|
|
2761
3016
|
await writeChannelsBridgeMcpConfig(channelsBridgeMcpConfig, tmuxSession);
|
|
@@ -2769,19 +3024,19 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
2769
3024
|
unsetProviderEnv: true,
|
|
2770
3025
|
overdeckEnv: {
|
|
2771
3026
|
...issueId ? { issueId } : {},
|
|
2772
|
-
...piFields || codexFields || useSupervisor ? { agentId: tmuxSession } : {}
|
|
3027
|
+
...piFields || codexFields || acpFields || useSupervisor ? { agentId: tmuxSession } : {}
|
|
2773
3028
|
},
|
|
2774
3029
|
extraEnvExports: [harnessLaunch.pathExport, `export OVERDECK_DASHBOARD_URL="http://127.0.0.1:${process.env["API_PORT"] ?? process.env["PORT"] ?? "3011"}"`],
|
|
2775
3030
|
providerExports: providerExportsStr || void 0,
|
|
2776
3031
|
trapHup: true,
|
|
2777
3032
|
baseCommand: runtimeCommand,
|
|
2778
|
-
appendSystemPromptFiles: piFields ? await piConversationSystemPromptFiles(cwd) : codexFields ? [] : await claudeConversationSystemPromptFiles(cwd),
|
|
3033
|
+
appendSystemPromptFiles: piFields ? await piConversationSystemPromptFiles(cwd) : codexFields || acpFields ? [] : await claudeConversationSystemPromptFiles(cwd),
|
|
2779
3034
|
model: launcherModel,
|
|
2780
|
-
...piFields ?? codexFields ?? {
|
|
3035
|
+
...piFields ?? codexFields ?? acpFields ?? {
|
|
2781
3036
|
resumeSessionId: resume ? claudeSessionId : void 0,
|
|
2782
3037
|
sessionId: resume ? void 0 : claudeSessionId
|
|
2783
3038
|
},
|
|
2784
|
-
extraArgs: !piFields && effort ? `--effort "${effort}"` : void 0,
|
|
3039
|
+
extraArgs: !piFields && !acpFields && effort ? `--effort "${effort}"` : void 0,
|
|
2785
3040
|
keepAlive: true,
|
|
2786
3041
|
fileMode: 448,
|
|
2787
3042
|
channelsBridgeMcpConfig,
|
|
@@ -2794,7 +3049,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
2794
3049
|
} catch {}
|
|
2795
3050
|
console.log(`[claude-invoke] purpose=conversation-session | model=${model || "default"} | source=conversations.ts:spawnConversationSession | session=${tmuxSession} | resume=${resume} | command="${runtimeCommand}"`);
|
|
2796
3051
|
try {
|
|
2797
|
-
const { preTrustDirectory } = await import("./workspace-manager-
|
|
3052
|
+
const { preTrustDirectory } = await import("./workspace-manager-CWT55qeI.js");
|
|
2798
3053
|
preTrustDirectory(cwd);
|
|
2799
3054
|
} catch {}
|
|
2800
3055
|
try {
|
|
@@ -2811,7 +3066,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
2811
3066
|
const codexHomeDir = codexFields.codexHome;
|
|
2812
3067
|
(async () => {
|
|
2813
3068
|
try {
|
|
2814
|
-
const { waitForCodexRollout, extractThreadIdFromRollout, writeThreadId } = await import("./codex-
|
|
3069
|
+
const { waitForCodexRollout, extractThreadIdFromRollout, writeThreadId } = await import("./codex-GcHuUF-k.js");
|
|
2815
3070
|
const rollout = await waitForCodexRollout(codexHomeDir, 12e4);
|
|
2816
3071
|
if (rollout) {
|
|
2817
3072
|
const threadId = extractThreadIdFromRollout(rollout);
|
|
@@ -2887,10 +3142,14 @@ async function handleConversationCreate(body, deps) {
|
|
|
2887
3142
|
await spawnConversationSession(tmuxSession, cwd, claudeSessionId, model, effort, issueId, false, harness);
|
|
2888
3143
|
console.log(`[conversations] tmux session ${tmuxSession} spawned, sessionId: ${claudeSessionId}`);
|
|
2889
3144
|
await waitForConversationRuntimeReady(tmuxSession, harness, "spawn");
|
|
2890
|
-
if (message)
|
|
3145
|
+
if (message) {
|
|
3146
|
+
const delivery = await deliverAgentMessage(tmuxSession, message, "conversation-message", resolveConversationDeliveryMethod(conv));
|
|
3147
|
+
if (harness === "acp" && !delivery.ok) throw new Error(`ACP initial prompt did not land: ${delivery.failure ?? "unknown failure"}`);
|
|
3148
|
+
}
|
|
2891
3149
|
} catch (spawnErr) {
|
|
2892
3150
|
const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
|
|
2893
3151
|
console.error(`[conversations] background spawn failed for ${tmuxSession}: ${msg}`);
|
|
3152
|
+
if (harness === "acp") await stopConversationRuntime(conv, name);
|
|
2894
3153
|
updateSpawnError(name, msg);
|
|
2895
3154
|
getEventStore().emitOnly({
|
|
2896
3155
|
type: "conversation.created",
|
|
@@ -2976,6 +3235,9 @@ async function handleConversationResume(name, body, deps) {
|
|
|
2976
3235
|
reattached: false,
|
|
2977
3236
|
sessionAlive: true
|
|
2978
3237
|
});
|
|
3238
|
+
} catch (error) {
|
|
3239
|
+
if (harness === "acp") await stopConversationRuntime(conv, name);
|
|
3240
|
+
throw error;
|
|
2979
3241
|
} finally {
|
|
2980
3242
|
respawn.done();
|
|
2981
3243
|
}
|
|
@@ -3010,13 +3272,16 @@ async function handleConversationRestartAll(deps) {
|
|
|
3010
3272
|
const results = [];
|
|
3011
3273
|
for (const conv of convs) {
|
|
3012
3274
|
const respawn = markRespawnPending(conv.tmuxSession);
|
|
3275
|
+
let attemptedHarness = conv.harness ?? "claude-code";
|
|
3013
3276
|
try {
|
|
3014
3277
|
await Effect.runPromise(killSession(conv.tmuxSession).pipe(Effect.catch(() => Effect.succeed(void 0))));
|
|
3015
3278
|
const oldSessionId = conv.claudeSessionId;
|
|
3016
3279
|
const sessionFileForResume = await deps.resolveSessionFile(conv);
|
|
3017
3280
|
const canResume = !!oldSessionId && !!sessionFileForResume && existsSync(sessionFileForResume);
|
|
3018
3281
|
const harness = await resolveAllowedHarness(conv.harness, conv.model);
|
|
3282
|
+
attemptedHarness = harness;
|
|
3019
3283
|
await spawnConversationSession(conv.tmuxSession, conv.cwd, oldSessionId ?? randomUUID$1(), conv.model ?? void 0, conv.effort ?? void 0, conv.issueId ?? void 0, canResume, harness);
|
|
3284
|
+
if (harness === "acp") await waitForConversationRuntimeReady(conv.tmuxSession, harness, "respawn");
|
|
3020
3285
|
setConversationHarness(conv.name, harness);
|
|
3021
3286
|
markConversationActive(conv.name);
|
|
3022
3287
|
results.push({
|
|
@@ -3027,6 +3292,7 @@ async function handleConversationRestartAll(deps) {
|
|
|
3027
3292
|
} catch (err) {
|
|
3028
3293
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3029
3294
|
console.error(`[conversations] Failed to restart ${conv.name}:`, msg);
|
|
3295
|
+
if (attemptedHarness === "acp") await stopConversationRuntime(conv, conv.name);
|
|
3030
3296
|
results.push({
|
|
3031
3297
|
name: conv.name,
|
|
3032
3298
|
model: conv.model,
|
|
@@ -3230,6 +3496,7 @@ function pickDeliverAs(bodyDeliverAs) {
|
|
|
3230
3496
|
}
|
|
3231
3497
|
function resolveConversationDeliveryMethod(conv) {
|
|
3232
3498
|
const harness = conv.harness ?? "claude-code";
|
|
3499
|
+
if (harness === "acp") return "auto";
|
|
3233
3500
|
if (isPiControlChannelHarness(harness)) return "auto";
|
|
3234
3501
|
if (harness === "codex" && loadConfigSync().config.codex?.transport !== "tui") return "auto";
|
|
3235
3502
|
return conv.deliveryMethod ?? (getHarnessBehavior(harness).deliveryKind === "rpc-fifo" ? "tmux" : "auto");
|
|
@@ -3690,14 +3957,14 @@ const postInternalAgentPermissionRequestRoute = HttpRouter.add("POST", "/api/int
|
|
|
3690
3957
|
error: "missing agent id"
|
|
3691
3958
|
}, { status: 400 });
|
|
3692
3959
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
3693
|
-
const { INTERNAL_TOKEN_HEADER, getInternalTokenSync } = yield* Effect.promise(() => import("./internal-token-
|
|
3960
|
+
const { INTERNAL_TOKEN_HEADER, getInternalTokenSync } = yield* Effect.promise(() => import("./internal-token-BrcU6qfe.js"));
|
|
3694
3961
|
const expected = getInternalTokenSync();
|
|
3695
3962
|
if (!expected) return jsonResponse({
|
|
3696
3963
|
ok: false,
|
|
3697
3964
|
error: "internal token not configured"
|
|
3698
3965
|
}, { status: 503 });
|
|
3699
3966
|
const rawHeader = request.headers[INTERNAL_TOKEN_HEADER];
|
|
3700
|
-
if (!constantTimeTokenEqual
|
|
3967
|
+
if (!constantTimeTokenEqual(Array.isArray(rawHeader) ? rawHeader[0] : rawHeader, expected)) return jsonResponse({
|
|
3701
3968
|
ok: false,
|
|
3702
3969
|
error: "forbidden"
|
|
3703
3970
|
}, { status: 403 });
|
|
@@ -3957,7 +4224,7 @@ const getAgentHealthHistoryRoute = HttpRouter.add("GET", "/api/agents/:id/health
|
|
|
3957
4224
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
3958
4225
|
const urlOpt = HttpServerRequest.toURL(request);
|
|
3959
4226
|
const hours = Option.isSome(urlOpt) ? urlOpt.value.searchParams.get("hours") ?? "24" : "24";
|
|
3960
|
-
const { getHealthHistory } = yield* Effect.promise(() => import("./health-events-
|
|
4227
|
+
const { getHealthHistory } = yield* Effect.promise(() => import("./health-events-BDOHby5Q.js"));
|
|
3961
4228
|
const endTime = /* @__PURE__ */ new Date();
|
|
3962
4229
|
const startTime = /* @__PURE__ */ new Date(endTime.getTime() - parseInt(hours) * 60 * 60 * 1e3);
|
|
3963
4230
|
const events = getHealthHistory(id, startTime.toISOString(), endTime.toISOString());
|
|
@@ -3998,7 +4265,7 @@ function emitAgentRuntimeEvent(id, body, timestamp) {
|
|
|
3998
4265
|
detail: String(decoded.failure)
|
|
3999
4266
|
}, { status: 400 })
|
|
4000
4267
|
};
|
|
4001
|
-
const { AgentStateService } = yield* Effect.promise(() => import("./agent-state-service-
|
|
4268
|
+
const { AgentStateService } = yield* Effect.promise(() => import("./agent-state-service-D5UGKIJL.js"));
|
|
4002
4269
|
yield* (yield* AgentStateService).emit(decoded.success);
|
|
4003
4270
|
return {
|
|
4004
4271
|
ok: true,
|
|
@@ -4080,7 +4347,7 @@ const getAgentRuntimeRoute = HttpRouter.add("GET", "/api/agents/:id/runtime", ht
|
|
|
4080
4347
|
success: false,
|
|
4081
4348
|
error: "missing agent id"
|
|
4082
4349
|
}, { status: 400 });
|
|
4083
|
-
const { AgentStateService } = yield* Effect.promise(() => import("./agent-state-service-
|
|
4350
|
+
const { AgentStateService } = yield* Effect.promise(() => import("./agent-state-service-D5UGKIJL.js"));
|
|
4084
4351
|
const snapshot = yield* (yield* AgentStateService).get(id);
|
|
4085
4352
|
if (!snapshot) return jsonResponse({
|
|
4086
4353
|
success: false,
|
|
@@ -4265,8 +4532,8 @@ function createAgentStopHandler(lifecycleEvent) {
|
|
|
4265
4532
|
yield* stopAgent(id);
|
|
4266
4533
|
if (stateBeforeStop?.issueId) yield* Effect.promise(async () => {
|
|
4267
4534
|
try {
|
|
4268
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
4269
|
-
const { findWorkspacePath } = await import("./archive-planning-
|
|
4535
|
+
const { resolveProjectFromIssueSync } = await import("./projects-vjjcmiN8.js");
|
|
4536
|
+
const { findWorkspacePath } = await import("./archive-planning-BZDgzoEj.js");
|
|
4270
4537
|
const issueLower = stateBeforeStop.issueId.toLowerCase();
|
|
4271
4538
|
const workspacePath = findWorkspacePath(resolveProjectFromIssueSync(stateBeforeStop.issueId)?.projectPath ?? process.cwd(), issueLower);
|
|
4272
4539
|
if (workspacePath) {
|
|
@@ -4402,9 +4669,18 @@ const postAgentUnpauseRoute = HttpRouter.add("POST", "/api/agents/:id/unpause",
|
|
|
4402
4669
|
payload: buildAgentControlEventPayload(updatedState, toAgentStatusPayload(stateBeforeUnpause.status), hasLiveTmuxSession)
|
|
4403
4670
|
});
|
|
4404
4671
|
invalidateAgentsCache();
|
|
4672
|
+
let resumeTriggered = false;
|
|
4673
|
+
if ((yield* getWorkAgentLifecycleState(id)).canResumeSession && updatedState.troubled !== true) {
|
|
4674
|
+
resumeTriggered = true;
|
|
4675
|
+
yield* Effect.promise(() => appendAgentLifecycleLog(id, "agent.unpause_immediate_resume_triggered"));
|
|
4676
|
+
import("./resume-BFv1PGpA.js").then(({ resumeAgent }) => resumeAgent(id)).then((result) => {
|
|
4677
|
+
if (!result.success) console.warn(`[agents] immediate resume after unpause failed for ${id}: ${result.error}`);
|
|
4678
|
+
}).catch((err) => console.warn(`[agents] immediate resume after unpause errored for ${id}:`, err));
|
|
4679
|
+
}
|
|
4405
4680
|
return jsonResponse({
|
|
4406
4681
|
success: true,
|
|
4407
|
-
agent: updatedState
|
|
4682
|
+
agent: updatedState,
|
|
4683
|
+
resumeTriggered
|
|
4408
4684
|
});
|
|
4409
4685
|
})));
|
|
4410
4686
|
const postAgentUntroubledRoute = HttpRouter.add("POST", "/api/agents/:id/untroubled", httpHandler(Effect.gen(function* () {
|
|
@@ -4442,6 +4718,7 @@ const postAgentUntroubledRoute = HttpRouter.add("POST", "/api/agents/:id/untroub
|
|
|
4442
4718
|
init_config_yaml();
|
|
4443
4719
|
init_agents$1();
|
|
4444
4720
|
init_harness_policy();
|
|
4721
|
+
init_model_validation();
|
|
4445
4722
|
init_operator_interventions();
|
|
4446
4723
|
init_projects();
|
|
4447
4724
|
init_tmux();
|
|
@@ -5090,7 +5367,6 @@ const postAgentsRestartWithConfigRoute = HttpRouter.add("POST", "/api/agents/res
|
|
|
5090
5367
|
})));
|
|
5091
5368
|
//#endregion
|
|
5092
5369
|
//#region routes/agents/control.ts
|
|
5093
|
-
init_config();
|
|
5094
5370
|
init_jsonl_parser();
|
|
5095
5371
|
init_model_validation();
|
|
5096
5372
|
init_paths();
|
|
@@ -5244,35 +5520,351 @@ const postAgentSwitchModelRoute = HttpRouter.add("POST", "/api/agents/:id/switch
|
|
|
5244
5520
|
return jsonResponse({ error: `Agent ${(yield* HttpRouter.params)["id"] ?? ""} model is locked once the agent is spawned` }, { status: 409 });
|
|
5245
5521
|
})));
|
|
5246
5522
|
//#endregion
|
|
5247
|
-
//#region ../../lib/
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
}
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
const checklist = sectionLines.filter((line) => /^\s*[-*+]\s+\[[ xX]\]\s+/.test(line)).map(cleanMarkdownLine).filter(Boolean);
|
|
5267
|
-
if (checklist.length > 0) return checklist;
|
|
5268
|
-
const bullets = sectionLines.filter((line) => /^\s*[-*+]\s+/.test(line)).map(cleanMarkdownLine).filter(Boolean).slice(0, 8);
|
|
5269
|
-
if (bullets.length > 0) return bullets;
|
|
5523
|
+
//#region ../../lib/orders/eligibility.ts
|
|
5524
|
+
function evaluateOrderDispatchEligibility(input) {
|
|
5525
|
+
const issueId = input.issueId.toUpperCase();
|
|
5526
|
+
const item = input.book.items.find((candidate) => candidate.issue.toUpperCase() === issueId);
|
|
5527
|
+
if (!item) {
|
|
5528
|
+
const overrideUsed = input.offBook === true;
|
|
5529
|
+
return {
|
|
5530
|
+
eligible: overrideUsed,
|
|
5531
|
+
overrideUsed,
|
|
5532
|
+
...overrideUsed ? {} : {
|
|
5533
|
+
code: "off-book",
|
|
5534
|
+
message: `Issue ${issueId} is not in active order book ${input.book.id}; work-agent dispatch is blocked. Retry with --off-book only for an intentional exception.`
|
|
5535
|
+
},
|
|
5536
|
+
conditions: [{
|
|
5537
|
+
key: "book-membership",
|
|
5538
|
+
met: overrideUsed,
|
|
5539
|
+
detail: overrideUsed ? `Issue ${issueId} is outside the book and the operator supplied --off-book.` : `Issue ${issueId} is not a member of ${input.book.id}.`
|
|
5540
|
+
}]
|
|
5541
|
+
};
|
|
5270
5542
|
}
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
const
|
|
5275
|
-
const
|
|
5543
|
+
const terminalByIssue = new Map(input.progress.items.map((progress) => [progress.issue.toUpperCase(), progress.terminal]));
|
|
5544
|
+
for (const [issue, terminal] of input.prerequisiteTerminal ?? []) if (!terminalByIssue.has(issue.toUpperCase())) terminalByIssue.set(issue.toUpperCase(), terminal);
|
|
5545
|
+
const unmetPrereq = item.prereqs.find((prereq) => terminalByIssue.get(prereq.toUpperCase()) !== true);
|
|
5546
|
+
const prereqsMet = unmetPrereq === void 0;
|
|
5547
|
+
const otherInFlight = input.book.items.filter((candidate) => candidate.issue.toUpperCase() !== issueId && input.inFlightIssues.has(candidate.issue.toUpperCase()));
|
|
5548
|
+
const laneBBlocker = item.lane === "B" ? otherInFlight.find((candidate) => candidate.lane === "B") : void 0;
|
|
5549
|
+
const laneAInFlight = otherInFlight.filter((candidate) => candidate.lane === "A").length;
|
|
5550
|
+
const laneSlotFree = item.lane === "B" ? laneBBlocker === void 0 : laneAInFlight < input.book.settings.laneAConcurrency;
|
|
5551
|
+
const postureOpen = input.book.settings.posture === "open";
|
|
5552
|
+
const prdReverified = !item.reVerify;
|
|
5553
|
+
const conditions = [
|
|
5554
|
+
{
|
|
5555
|
+
key: "book-membership",
|
|
5556
|
+
met: true,
|
|
5557
|
+
detail: `${issueId} is a member of ${input.book.id}.`
|
|
5558
|
+
},
|
|
5559
|
+
{
|
|
5560
|
+
key: "pickup-posture",
|
|
5561
|
+
met: postureOpen,
|
|
5562
|
+
detail: postureOpen ? "Order-book pickup posture is OPEN." : "Order-book pickup posture is DRAIN."
|
|
5563
|
+
},
|
|
5564
|
+
{
|
|
5565
|
+
key: "lane-slot",
|
|
5566
|
+
met: laneSlotFree,
|
|
5567
|
+
detail: item.lane === "B" ? laneBBlocker ? `Lane B is occupied by ${laneBBlocker.issue}.` : "Lane B has no issue in flight." : `${laneAInFlight}/${input.book.settings.laneAConcurrency} Lane A slots are in flight.`
|
|
5568
|
+
},
|
|
5569
|
+
{
|
|
5570
|
+
key: "prerequisites",
|
|
5571
|
+
met: prereqsMet,
|
|
5572
|
+
detail: unmetPrereq ? `Prerequisite ${unmetPrereq.toUpperCase()} is not terminal.` : "Every prerequisite is landed or parked."
|
|
5573
|
+
},
|
|
5574
|
+
{
|
|
5575
|
+
key: "prd-reverified",
|
|
5576
|
+
met: prdReverified,
|
|
5577
|
+
detail: prdReverified ? "No PRD re-verification is pending." : `${issueId} requires PRD re-verification before dispatch.`
|
|
5578
|
+
}
|
|
5579
|
+
];
|
|
5580
|
+
if (!postureOpen) return {
|
|
5581
|
+
eligible: false,
|
|
5582
|
+
overrideUsed: false,
|
|
5583
|
+
code: "book-draining",
|
|
5584
|
+
message: `Issue ${issueId} cannot start because order book ${input.book.id} is in DRAIN posture; no new book items may dispatch.`,
|
|
5585
|
+
conditions
|
|
5586
|
+
};
|
|
5587
|
+
if (unmetPrereq) return {
|
|
5588
|
+
eligible: false,
|
|
5589
|
+
overrideUsed: false,
|
|
5590
|
+
code: "prerequisite-unmet",
|
|
5591
|
+
message: `Issue ${issueId} cannot start because prerequisite ${unmetPrereq.toUpperCase()} has not landed or been parked.`,
|
|
5592
|
+
conditions
|
|
5593
|
+
};
|
|
5594
|
+
if (!prdReverified) return {
|
|
5595
|
+
eligible: false,
|
|
5596
|
+
overrideUsed: false,
|
|
5597
|
+
code: "reverify-required",
|
|
5598
|
+
message: `Issue ${issueId} cannot start until its PRD has been re-verified against current main.`,
|
|
5599
|
+
conditions
|
|
5600
|
+
};
|
|
5601
|
+
if (laneBBlocker) return {
|
|
5602
|
+
eligible: false,
|
|
5603
|
+
overrideUsed: false,
|
|
5604
|
+
code: "lane-b-busy",
|
|
5605
|
+
message: `Issue ${issueId} cannot start in Lane B because ${laneBBlocker.issue} is still in flight; Lane B allows one active issue at a time.`,
|
|
5606
|
+
conditions
|
|
5607
|
+
};
|
|
5608
|
+
if (item.lane === "A" && !laneSlotFree) return {
|
|
5609
|
+
eligible: false,
|
|
5610
|
+
overrideUsed: false,
|
|
5611
|
+
code: "lane-a-full",
|
|
5612
|
+
message: `Issue ${issueId} cannot start in Lane A because ${laneAInFlight} issues are already in flight and laneAConcurrency is ${input.book.settings.laneAConcurrency}.`,
|
|
5613
|
+
conditions
|
|
5614
|
+
};
|
|
5615
|
+
return {
|
|
5616
|
+
eligible: true,
|
|
5617
|
+
overrideUsed: false,
|
|
5618
|
+
conditions
|
|
5619
|
+
};
|
|
5620
|
+
}
|
|
5621
|
+
//#endregion
|
|
5622
|
+
//#region ../../lib/orders/dispatch-gate.ts
|
|
5623
|
+
init_review_status();
|
|
5624
|
+
init_projects();
|
|
5625
|
+
function stateRootFor(projectRoot) {
|
|
5626
|
+
const project = findProjectByPathSync(projectRoot);
|
|
5627
|
+
if (!project) throw new Error(`No configured project contains ${projectRoot}`);
|
|
5628
|
+
return resolveStateReadHomeSync(project).root;
|
|
5629
|
+
}
|
|
5630
|
+
function defaultInFlightIssues(_bookId, issueIds) {
|
|
5631
|
+
const inFlight = /* @__PURE__ */ new Set();
|
|
5632
|
+
for (const issueId of issueIds) {
|
|
5633
|
+
const lifecycle = getWorkAgentLifecycleStateSync(issueId);
|
|
5634
|
+
const review = getReviewStatusSync(issueId);
|
|
5635
|
+
if (lifecycle.isRunning || review !== null && review.reviewStatus !== "pending") inFlight.add(issueId.toUpperCase());
|
|
5636
|
+
}
|
|
5637
|
+
return inFlight;
|
|
5638
|
+
}
|
|
5639
|
+
const booklessDecision = {
|
|
5640
|
+
eligible: true,
|
|
5641
|
+
overrideUsed: false,
|
|
5642
|
+
conditions: []
|
|
5643
|
+
};
|
|
5644
|
+
async function checkActiveOrderDispatch(projectRoot, issueId, options = {}, deps = {}) {
|
|
5645
|
+
const runId = await (deps.resolveRunId ?? resolveLiveFlywheelRunId)();
|
|
5646
|
+
if (!runId) return {
|
|
5647
|
+
ordersBound: false,
|
|
5648
|
+
decision: booklessDecision
|
|
5649
|
+
};
|
|
5650
|
+
const launch = await (deps.readLaunch ?? readFlywheelLaunchMetadata)(runId);
|
|
5651
|
+
const bookId = launch?.orders?.bookId;
|
|
5652
|
+
if (!bookId) return {
|
|
5653
|
+
ordersBound: false,
|
|
5654
|
+
runId,
|
|
5655
|
+
decision: booklessDecision
|
|
5656
|
+
};
|
|
5657
|
+
const stateRoot = (deps.stateRoot ?? stateRootFor)(launch?.workspace ?? projectRoot);
|
|
5658
|
+
const book = (deps.getOrderBook ?? getBook)(stateRoot, bookId);
|
|
5659
|
+
if (!book) throw new Error(`Active Flywheel run ${runId} references missing order book ${bookId}`);
|
|
5660
|
+
const progress = (deps.computeProgress ?? computeBookProgress)(book);
|
|
5661
|
+
const prerequisiteIds = [...new Set(book.items.flatMap((item) => item.prereqs.map((prereq) => prereq.toUpperCase())))];
|
|
5662
|
+
const prerequisiteState = (deps.issueLookup ?? liveOrderIssueLookup)(prerequisiteIds);
|
|
5663
|
+
const prerequisiteTerminal = new Map(prerequisiteIds.map((prereq) => {
|
|
5664
|
+
const state = prerequisiteState.get(prereq);
|
|
5665
|
+
return [prereq, state ? !state.open || state.parked : false];
|
|
5666
|
+
}));
|
|
5667
|
+
const inFlightIssues = new Set((deps.inFlightIssues ?? defaultInFlightIssues)(book.id, book.items.filter((item) => !progress.items.find((entry) => entry.issue === item.issue)?.terminal).map((item) => item.issue)));
|
|
5668
|
+
for (const reserved of deps.reservedIssues ?? []) inFlightIssues.add(reserved.toUpperCase());
|
|
5669
|
+
return {
|
|
5670
|
+
ordersBound: true,
|
|
5671
|
+
runId,
|
|
5672
|
+
bookId,
|
|
5673
|
+
decision: evaluateOrderDispatchEligibility({
|
|
5674
|
+
book,
|
|
5675
|
+
progress,
|
|
5676
|
+
issueId,
|
|
5677
|
+
inFlightIssues,
|
|
5678
|
+
prerequisiteTerminal,
|
|
5679
|
+
offBook: options.offBook
|
|
5680
|
+
})
|
|
5681
|
+
};
|
|
5682
|
+
}
|
|
5683
|
+
async function recordOffBookOverride(runId, bookId, issueId, actor = process.env["OVERDECK_AGENT_ID"] ?? "operator") {
|
|
5684
|
+
const runDir = getFlywheelRunDir(runId);
|
|
5685
|
+
const path = join(runDir, "orders-overrides.jsonl");
|
|
5686
|
+
await mkdir(runDir, { recursive: true });
|
|
5687
|
+
await appendFile(path, `${JSON.stringify({
|
|
5688
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5689
|
+
runId,
|
|
5690
|
+
bookId,
|
|
5691
|
+
issueId: issueId.toUpperCase(),
|
|
5692
|
+
actor,
|
|
5693
|
+
override: "off-book"
|
|
5694
|
+
})}\n`, "utf8");
|
|
5695
|
+
return path;
|
|
5696
|
+
}
|
|
5697
|
+
//#endregion
|
|
5698
|
+
//#region ../../lib/orders/dispatch-reservation.ts
|
|
5699
|
+
var OrderDispatchReservationError = class extends Error {
|
|
5700
|
+
constructor(check) {
|
|
5701
|
+
super(check.decision.message ?? "Order-book dispatch is blocked.");
|
|
5702
|
+
this.check = check;
|
|
5703
|
+
this.name = "OrderDispatchReservationError";
|
|
5704
|
+
}
|
|
5705
|
+
};
|
|
5706
|
+
const DEFAULT_STALE_MS = 900 * 1e3;
|
|
5707
|
+
const processLocks = /* @__PURE__ */ new Map();
|
|
5708
|
+
let reservationSequence = 0;
|
|
5709
|
+
async function withProcessLock(key, action) {
|
|
5710
|
+
const previous = processLocks.get(key) ?? Promise.resolve();
|
|
5711
|
+
let release;
|
|
5712
|
+
const current = new Promise((resolve) => {
|
|
5713
|
+
release = resolve;
|
|
5714
|
+
});
|
|
5715
|
+
const tail = previous.then(() => current);
|
|
5716
|
+
processLocks.set(key, tail);
|
|
5717
|
+
await previous;
|
|
5718
|
+
try {
|
|
5719
|
+
return await action();
|
|
5720
|
+
} finally {
|
|
5721
|
+
release();
|
|
5722
|
+
if (processLocks.get(key) === tail) processLocks.delete(key);
|
|
5723
|
+
}
|
|
5724
|
+
}
|
|
5725
|
+
function paths(root) {
|
|
5726
|
+
return {
|
|
5727
|
+
state: join(root, "orders-dispatch-reservations.json"),
|
|
5728
|
+
temp: join(root, `orders-dispatch-reservations.${process.pid}.tmp`),
|
|
5729
|
+
lock: join(root, "orders-dispatch-reservations.lock")
|
|
5730
|
+
};
|
|
5731
|
+
}
|
|
5732
|
+
async function acquireFileLock(path, staleMs, now) {
|
|
5733
|
+
try {
|
|
5734
|
+
await mkdir(path);
|
|
5735
|
+
return;
|
|
5736
|
+
} catch (error) {
|
|
5737
|
+
if ((typeof error === "object" && error !== null && "code" in error ? error.code : void 0) !== "EEXIST") throw error;
|
|
5738
|
+
}
|
|
5739
|
+
if (await stat$1(path).then((value) => now.getTime() - value.mtimeMs).catch(() => 0) <= staleMs) throw new Error("Another order-book dispatch admission is in progress; retry after it finishes.");
|
|
5740
|
+
await rm(path, {
|
|
5741
|
+
recursive: true,
|
|
5742
|
+
force: true
|
|
5743
|
+
});
|
|
5744
|
+
await mkdir(path);
|
|
5745
|
+
}
|
|
5746
|
+
async function readReservations(path) {
|
|
5747
|
+
try {
|
|
5748
|
+
const parsed = JSON.parse(await readFile(path, "utf8"));
|
|
5749
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
5750
|
+
} catch (error) {
|
|
5751
|
+
if ((typeof error === "object" && error !== null && "code" in error ? error.code : void 0) === "ENOENT") return [];
|
|
5752
|
+
throw error;
|
|
5753
|
+
}
|
|
5754
|
+
}
|
|
5755
|
+
async function writeReservations(path, tempPath, reservations) {
|
|
5756
|
+
await writeFile(tempPath, `${JSON.stringify(reservations, null, 2)}\n`, {
|
|
5757
|
+
encoding: "utf8",
|
|
5758
|
+
mode: 384
|
|
5759
|
+
});
|
|
5760
|
+
await rename(tempPath, path);
|
|
5761
|
+
}
|
|
5762
|
+
function freshReservations(reservations, now, staleMs) {
|
|
5763
|
+
return reservations.filter((reservation) => {
|
|
5764
|
+
const reservedAt = Date.parse(reservation.reservedAt);
|
|
5765
|
+
return Number.isFinite(reservedAt) && now.getTime() - reservedAt <= staleMs;
|
|
5766
|
+
});
|
|
5767
|
+
}
|
|
5768
|
+
async function reserveActiveOrderDispatch(projectRoot, issueId, options = {}, deps = {}) {
|
|
5769
|
+
const initial = await checkActiveOrderDispatch(projectRoot, issueId, options, deps);
|
|
5770
|
+
if (!initial.ordersBound || !initial.runId || !initial.bookId || !initial.decision.eligible) return {
|
|
5771
|
+
check: initial,
|
|
5772
|
+
release: async () => {}
|
|
5773
|
+
};
|
|
5774
|
+
const root = (deps.reservationRoot ?? getFlywheelRunDir)(initial.runId);
|
|
5775
|
+
await mkdir(root, { recursive: true });
|
|
5776
|
+
const reservationPaths = paths(root);
|
|
5777
|
+
const staleMs = deps.staleMs ?? DEFAULT_STALE_MS;
|
|
5778
|
+
const now = (deps.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
5779
|
+
const reservationId = `${process.pid}-${now.getTime()}-${reservationSequence++}`;
|
|
5780
|
+
let check = initial;
|
|
5781
|
+
await withProcessLock(reservationPaths.lock, async () => {
|
|
5782
|
+
await acquireFileLock(reservationPaths.lock, staleMs, now);
|
|
5783
|
+
try {
|
|
5784
|
+
const current = freshReservations(await readReservations(reservationPaths.state), now, staleMs);
|
|
5785
|
+
check = await checkActiveOrderDispatch(projectRoot, issueId, options, {
|
|
5786
|
+
...deps,
|
|
5787
|
+
reservedIssues: new Set(current.filter((reservation) => reservation.bookId === initial.bookId).map((reservation) => reservation.issueId))
|
|
5788
|
+
});
|
|
5789
|
+
if (!check.decision.eligible) return;
|
|
5790
|
+
current.push({
|
|
5791
|
+
id: reservationId,
|
|
5792
|
+
bookId: initial.bookId,
|
|
5793
|
+
issueId: issueId.toUpperCase(),
|
|
5794
|
+
reservedAt: now.toISOString()
|
|
5795
|
+
});
|
|
5796
|
+
await writeReservations(reservationPaths.state, reservationPaths.temp, current);
|
|
5797
|
+
} finally {
|
|
5798
|
+
await rm(reservationPaths.lock, {
|
|
5799
|
+
recursive: true,
|
|
5800
|
+
force: true
|
|
5801
|
+
});
|
|
5802
|
+
}
|
|
5803
|
+
});
|
|
5804
|
+
if (!check.decision.eligible) return {
|
|
5805
|
+
check,
|
|
5806
|
+
release: async () => {}
|
|
5807
|
+
};
|
|
5808
|
+
if (options.recordOverride && check.decision.overrideUsed) await (deps.recordOverride ?? recordOffBookOverride)(initial.runId, initial.bookId, issueId);
|
|
5809
|
+
let released = false;
|
|
5810
|
+
return {
|
|
5811
|
+
check,
|
|
5812
|
+
release: async () => {
|
|
5813
|
+
if (released) return;
|
|
5814
|
+
released = true;
|
|
5815
|
+
const releasedAt = (deps.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
5816
|
+
await withProcessLock(reservationPaths.lock, async () => {
|
|
5817
|
+
await acquireFileLock(reservationPaths.lock, staleMs, releasedAt);
|
|
5818
|
+
try {
|
|
5819
|
+
const current = freshReservations(await readReservations(reservationPaths.state), releasedAt, staleMs).filter((reservation) => reservation.id !== reservationId);
|
|
5820
|
+
await writeReservations(reservationPaths.state, reservationPaths.temp, current);
|
|
5821
|
+
} finally {
|
|
5822
|
+
await rm(reservationPaths.lock, {
|
|
5823
|
+
recursive: true,
|
|
5824
|
+
force: true
|
|
5825
|
+
});
|
|
5826
|
+
}
|
|
5827
|
+
});
|
|
5828
|
+
}
|
|
5829
|
+
};
|
|
5830
|
+
}
|
|
5831
|
+
async function withActiveOrderDispatchReservation(projectRoot, issueId, options, action, deps = {}) {
|
|
5832
|
+
const reservation = await reserveActiveOrderDispatch(projectRoot, issueId, options, deps);
|
|
5833
|
+
if (!reservation.check.decision.eligible) return { check: reservation.check };
|
|
5834
|
+
try {
|
|
5835
|
+
return {
|
|
5836
|
+
check: reservation.check,
|
|
5837
|
+
result: await action()
|
|
5838
|
+
};
|
|
5839
|
+
} finally {
|
|
5840
|
+
await reservation.release();
|
|
5841
|
+
}
|
|
5842
|
+
}
|
|
5843
|
+
//#endregion
|
|
5844
|
+
//#region ../../lib/xbrief/auto-synthesize.ts
|
|
5845
|
+
init_io();
|
|
5846
|
+
function cleanMarkdownLine(line) {
|
|
5847
|
+
return line.replace(/^[-*+]\s+\[[ xX]\]\s+/, "").replace(/^[-*+]\s+/, "").replace(/^#+\s+/, "").replace(/`([^`]+)`/g, "$1").trim();
|
|
5848
|
+
}
|
|
5849
|
+
function extractAcceptanceCriteriaFromIssue(title, body) {
|
|
5850
|
+
const text = body?.trim() ?? "";
|
|
5851
|
+
if (!text) return [`Implement ${title}`];
|
|
5852
|
+
const lines = text.split(/\r?\n/);
|
|
5853
|
+
const headingIndex = lines.findIndex((line) => /^#{1,6}\s+.*acceptance(\s+criteria)?\b/i.test(line) || /^\s*\*{0,2}acceptance criteria\*{0,2}:?\s*$/i.test(line));
|
|
5854
|
+
if (headingIndex >= 0) {
|
|
5855
|
+
const sectionEndIndex = lines.findIndex((line, idx) => idx > headingIndex && /^#+\s+/.test(line));
|
|
5856
|
+
const endIndex = sectionEndIndex >= 0 ? sectionEndIndex : lines.length;
|
|
5857
|
+
const sectionLines = lines.slice(headingIndex + 1, endIndex);
|
|
5858
|
+
const checklist = sectionLines.filter((line) => /^\s*[-*+]\s+\[[ xX]\]\s+/.test(line)).map(cleanMarkdownLine).filter(Boolean);
|
|
5859
|
+
if (checklist.length > 0) return checklist;
|
|
5860
|
+
const bullets = sectionLines.filter((line) => /^\s*[-*+]\s+/.test(line)).map(cleanMarkdownLine).filter(Boolean).slice(0, 8);
|
|
5861
|
+
if (bullets.length > 0) return bullets;
|
|
5862
|
+
}
|
|
5863
|
+
return [`Issue's stated fix implemented with tests`];
|
|
5864
|
+
}
|
|
5865
|
+
function synthesizeMinimalXBrief(issue) {
|
|
5866
|
+
const issueId = issue.issueId.toUpperCase();
|
|
5867
|
+
const issueLabel = issueId.toLowerCase();
|
|
5276
5868
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5277
5869
|
const items = extractAcceptanceCriteriaFromIssue(issue.title, issue.body).map((criterion, index) => ({
|
|
5278
5870
|
id: `auto-start.ac${index + 1}`,
|
|
@@ -5365,222 +5957,21 @@ const writeAutoStartXBrief = (projectRoot, workspacePath, issue) => Effect.tryPr
|
|
|
5365
5957
|
})
|
|
5366
5958
|
});
|
|
5367
5959
|
//#endregion
|
|
5368
|
-
//#region routes/dashboard-auth.ts
|
|
5369
|
-
init_issue_lifecycle();
|
|
5370
|
-
init_internal_token();
|
|
5371
|
-
const DASHBOARD_SESSION_COOKIE = "overdeck_session";
|
|
5372
|
-
const DASHBOARD_CSRF_HEADER = "x-overdeck-csrf-token";
|
|
5373
|
-
const DASHBOARD_SESSION_MAX_AGE_SECONDS = 3600 * 24 * 30;
|
|
5374
|
-
let browserSessionToken;
|
|
5375
|
-
let browserCsrfToken;
|
|
5376
|
-
function getDashboardSessionToken() {
|
|
5377
|
-
if (browserSessionToken) return browserSessionToken;
|
|
5378
|
-
const override = process.env["OVERDECK_DASHBOARD_SESSION_TOKEN"];
|
|
5379
|
-
if (override) {
|
|
5380
|
-
browserSessionToken = override;
|
|
5381
|
-
return browserSessionToken;
|
|
5382
|
-
}
|
|
5383
|
-
const internal = getInternalTokenSync();
|
|
5384
|
-
browserSessionToken = internal ? createHmac("sha256", internal).update("overdeck-dashboard-session-v1").digest("base64url") : randomBytes(32).toString("base64url");
|
|
5385
|
-
return browserSessionToken;
|
|
5386
|
-
}
|
|
5387
|
-
function dashboardCsrfToken() {
|
|
5388
|
-
if (browserCsrfToken) return browserCsrfToken;
|
|
5389
|
-
const override = process.env["OVERDECK_DASHBOARD_CSRF_TOKEN"];
|
|
5390
|
-
if (override) {
|
|
5391
|
-
browserCsrfToken = override;
|
|
5392
|
-
return browserCsrfToken;
|
|
5393
|
-
}
|
|
5394
|
-
const internal = getInternalTokenSync();
|
|
5395
|
-
browserCsrfToken = internal ? createHmac("sha256", internal).update("overdeck-dashboard-csrf-v1").digest("base64url") : randomBytes(32).toString("base64url");
|
|
5396
|
-
return browserCsrfToken;
|
|
5397
|
-
}
|
|
5398
|
-
function constantTimeTokenEqual(provided, expected) {
|
|
5399
|
-
if (!provided) return false;
|
|
5400
|
-
return timingSafeEqual(createHash$1("sha256").update(provided).digest(), createHash$1("sha256").update(expected).digest());
|
|
5401
|
-
}
|
|
5402
|
-
function cookieValue(cookieHeader, name) {
|
|
5403
|
-
if (!cookieHeader) return void 0;
|
|
5404
|
-
for (const part of cookieHeader.split(";")) {
|
|
5405
|
-
const [rawKey, ...rawValue] = part.trim().split("=");
|
|
5406
|
-
if (rawKey !== name) continue;
|
|
5407
|
-
try {
|
|
5408
|
-
return decodeURIComponent(rawValue.join("="));
|
|
5409
|
-
} catch {
|
|
5410
|
-
return;
|
|
5411
|
-
}
|
|
5412
|
-
}
|
|
5413
|
-
}
|
|
5414
|
-
function dashboardSessionCookieHeader(options = {}) {
|
|
5415
|
-
const secure = options.secure ? "; Secure" : "";
|
|
5416
|
-
return `${DASHBOARD_SESSION_COOKIE}=${encodeURIComponent(getDashboardSessionToken())}; Path=/; HttpOnly; SameSite=Strict; Max-Age=${DASHBOARD_SESSION_MAX_AGE_SECONDS}${secure}`;
|
|
5417
|
-
}
|
|
5418
|
-
function hasDashboardInternalTokenHeaders(headers) {
|
|
5419
|
-
const expected = getInternalTokenSync();
|
|
5420
|
-
if (!expected) return false;
|
|
5421
|
-
if (constantTimeTokenEqual(getHeaderFromMap(headers, "x-overdeck-internal-token"), expected)) return true;
|
|
5422
|
-
const authorization = getHeaderFromMap(headers, "authorization");
|
|
5423
|
-
if (authorization) {
|
|
5424
|
-
const [scheme, token] = authorization.split(/\s+/);
|
|
5425
|
-
if (scheme?.toLowerCase() === "bearer" && constantTimeTokenEqual(token, expected)) return true;
|
|
5426
|
-
}
|
|
5427
|
-
return false;
|
|
5428
|
-
}
|
|
5429
|
-
function hasDashboardInternalToken(request) {
|
|
5430
|
-
return hasDashboardInternalTokenHeaders(request.headers);
|
|
5431
|
-
}
|
|
5432
|
-
function hasDashboardAuthHeaders(headers) {
|
|
5433
|
-
return hasDashboardInternalTokenHeaders(headers) || constantTimeTokenEqual(cookieValue(getHeaderFromMap(headers, "cookie"), "overdeck_session"), getDashboardSessionToken());
|
|
5434
|
-
}
|
|
5435
|
-
function hasDashboardAuth(request) {
|
|
5436
|
-
return hasDashboardAuthHeaders(request.headers);
|
|
5437
|
-
}
|
|
5438
|
-
function isJsonContentType(headers) {
|
|
5439
|
-
const contentType = getHeaderFromMap(headers, "content-type");
|
|
5440
|
-
if (!contentType) return false;
|
|
5441
|
-
const [mime] = contentType.toLowerCase().split(";");
|
|
5442
|
-
return mime.trim() === "application/json";
|
|
5443
|
-
}
|
|
5444
|
-
function hasTrustedExactOrigin(headers) {
|
|
5445
|
-
const origin = getHeaderFromMap(headers, "origin");
|
|
5446
|
-
if (!origin) return false;
|
|
5447
|
-
const normalized = normalizeOrigin(origin);
|
|
5448
|
-
return !!normalized && getTrustedOrigins().includes(normalized);
|
|
5449
|
-
}
|
|
5450
|
-
function hasValidCsrfToken(headers) {
|
|
5451
|
-
return constantTimeTokenEqual(getHeaderFromMap(headers, DASHBOARD_CSRF_HEADER), dashboardCsrfToken());
|
|
5452
|
-
}
|
|
5453
|
-
function rejectUnsafeDashboardMutationRequest(request) {
|
|
5454
|
-
const authError = rejectUnauthorizedDashboardRequest(request);
|
|
5455
|
-
if (authError) return authError;
|
|
5456
|
-
const headers = request.headers;
|
|
5457
|
-
if (!isJsonContentType(headers)) return jsonResponse({ error: "Content-Type must be application/json" }, { status: 400 });
|
|
5458
|
-
if (hasDashboardInternalToken(request)) return null;
|
|
5459
|
-
if (getHeaderFromMap(headers, "origin") && !hasTrustedExactOrigin(headers)) return jsonResponse({ error: "Invalid origin" }, { status: 403 });
|
|
5460
|
-
if (!hasValidCsrfToken(headers)) return jsonResponse({ error: "Invalid CSRF token" }, { status: 403 });
|
|
5461
|
-
return null;
|
|
5462
|
-
}
|
|
5463
|
-
function ipv4ToInt(value) {
|
|
5464
|
-
const parts = value.split(".");
|
|
5465
|
-
if (parts.length !== 4) return null;
|
|
5466
|
-
let result = 0;
|
|
5467
|
-
for (const part of parts) {
|
|
5468
|
-
const octet = Number(part);
|
|
5469
|
-
if (!Number.isInteger(octet) || octet < 0 || octet > 255) return null;
|
|
5470
|
-
result = (result << 8 | octet) >>> 0;
|
|
5471
|
-
}
|
|
5472
|
-
return result;
|
|
5473
|
-
}
|
|
5474
|
-
/** RFC1918 private ranges — Docker bridges always fall inside one of these. */
|
|
5475
|
-
function isRfc1918(ip) {
|
|
5476
|
-
return (ip & 4278190080) >>> 0 === 167772160 || (ip & 4293918720) >>> 0 === 2886729728 || (ip & 4294901760) >>> 0 === 3232235520;
|
|
5477
|
-
}
|
|
5478
|
-
/**
|
|
5479
|
-
* True when `addr` is the IP of a container on one of THIS host's Docker bridge
|
|
5480
|
-
* interfaces (docker0 / br-*). Such a peer can only be a process running on this
|
|
5481
|
-
* machine — our own host-local Traefik fronting overdeck.localhost, or another
|
|
5482
|
-
* Overdeck container — never a LAN client (a direct LAN hit to the 0.0.0.0
|
|
5483
|
-
* API port arrives with a LAN peer that is not inside any Docker bridge subnet).
|
|
5484
|
-
*
|
|
5485
|
-
* Pure for testability: the interface map is injected. We only ever trust
|
|
5486
|
-
* RFC1918 bridge subnets, so a misconfigured public-range br-* cannot widen
|
|
5487
|
-
* trust beyond the local Docker fabric.
|
|
5488
|
-
*/
|
|
5489
|
-
function peerIsHostLocalDockerBridge(addr, interfaces) {
|
|
5490
|
-
const peer = ipv4ToInt(addr);
|
|
5491
|
-
if (peer === null) return false;
|
|
5492
|
-
for (const [name, addrs] of Object.entries(interfaces)) {
|
|
5493
|
-
if (name !== "docker0" && !name.startsWith("br-")) continue;
|
|
5494
|
-
for (const info of addrs ?? []) {
|
|
5495
|
-
if (info.family !== "IPv4") continue;
|
|
5496
|
-
const ifaceIp = ipv4ToInt(info.address);
|
|
5497
|
-
const mask = ipv4ToInt(info.netmask);
|
|
5498
|
-
if (ifaceIp === null || mask === null) continue;
|
|
5499
|
-
const network = (ifaceIp & mask) >>> 0;
|
|
5500
|
-
if (!isRfc1918(network)) continue;
|
|
5501
|
-
if ((peer & mask) >>> 0 === network) return true;
|
|
5502
|
-
}
|
|
5503
|
-
}
|
|
5504
|
-
return false;
|
|
5505
|
-
}
|
|
5506
|
-
/**
|
|
5507
|
-
* True when `addr` shares an RFC1918 subnet with one of THIS process's own
|
|
5508
|
-
* network interfaces. This is the in-container counterpart of
|
|
5509
|
-
* peerIsHostLocalDockerBridge: inside a container the Docker bridge is
|
|
5510
|
-
* invisible — the container sees only its veth endpoints (eth0/eth1), so the
|
|
5511
|
-
* docker0/br-* name filter never matches and the host-local Traefik fronting
|
|
5512
|
-
* the stack 401'd every session mint (first hit live on the PAN-1737 UAT
|
|
5513
|
-
* stack). A peer inside one of the container's attached Docker-network
|
|
5514
|
-
* subnets can only be another container on those networks — the server
|
|
5515
|
-
* publishes no host port (Traefik labels only), so no LAN client can ever
|
|
5516
|
-
* present such an address. Only consulted when running inside a container.
|
|
5517
|
-
*/
|
|
5518
|
-
function peerIsLocalContainerNetwork(addr, interfaces) {
|
|
5519
|
-
const peer = ipv4ToInt(addr);
|
|
5520
|
-
if (peer === null) return false;
|
|
5521
|
-
for (const addrs of Object.values(interfaces)) for (const info of addrs ?? []) {
|
|
5522
|
-
if (info.family !== "IPv4" || info.internal) continue;
|
|
5523
|
-
const ifaceIp = ipv4ToInt(info.address);
|
|
5524
|
-
const mask = ipv4ToInt(info.netmask);
|
|
5525
|
-
if (ifaceIp === null || mask === null) continue;
|
|
5526
|
-
const network = (ifaceIp & mask) >>> 0;
|
|
5527
|
-
if (!isRfc1918(network)) continue;
|
|
5528
|
-
if ((peer & mask) >>> 0 === network) return true;
|
|
5529
|
-
}
|
|
5530
|
-
return false;
|
|
5531
|
-
}
|
|
5532
|
-
/** Docker creates /.dockerenv in every container — stable in-container signal. */
|
|
5533
|
-
const runningInContainer = existsSync("/.dockerenv");
|
|
5534
|
-
/**
|
|
5535
|
-
* A request we trust to mint a session because it originated from this machine —
|
|
5536
|
-
* the local browser hitting the dashboard directly (127.0.0.1), or the
|
|
5537
|
-
* host-local Traefik that fronts overdeck.localhost. In Docker, that Traefik reaches
|
|
5538
|
-
* the host server from a Docker-bridge IP (e.g. 172.18.0.2), NOT 127.0.0.1, so
|
|
5539
|
-
* a literal-loopback check alone silently breaks the zero-step bootstrap for
|
|
5540
|
-
* every overdeck.localhost user — their session mint 401s and no cookie is ever set.
|
|
5541
|
-
*
|
|
5542
|
-
* This is the auto-bootstrap that removes the manual one-time #overdeck_token
|
|
5543
|
-
* step: any browser on overdeck.localhost gets a session with no user action. It is
|
|
5544
|
-
* NOT a security downgrade for the LAN — the raw API ports bind 0.0.0.0, but a
|
|
5545
|
-
* direct LAN hit has a non-loopback, non-Docker-bridge peer and is rejected. We
|
|
5546
|
-
* read ONLY the real TCP peer (request.remoteAddress), never X-Forwarded-For,
|
|
5547
|
-
* which a caller could spoof.
|
|
5548
|
-
*/
|
|
5549
|
-
function isLoopbackPeer(request) {
|
|
5550
|
-
const remoteAddress = request.remoteAddress;
|
|
5551
|
-
const raw = remoteAddress && typeof remoteAddress === "object" && "_tag" in remoteAddress ? Option.getOrElse(remoteAddress, () => "") : typeof remoteAddress === "string" ? remoteAddress : "";
|
|
5552
|
-
if (!raw) return false;
|
|
5553
|
-
const addr = raw.startsWith("::ffff:") ? raw.slice(7) : raw;
|
|
5554
|
-
if (addr === "127.0.0.1" || addr === "::1") return true;
|
|
5555
|
-
if (peerIsHostLocalDockerBridge(addr, networkInterfaces())) return true;
|
|
5556
|
-
return runningInContainer && peerIsLocalContainerNetwork(addr, networkInterfaces());
|
|
5557
|
-
}
|
|
5558
|
-
function rejectUnauthorizedDashboardSessionMintRequest(request) {
|
|
5559
|
-
if (!getInternalTokenSync()) return jsonResponse({ error: "dashboard session token not configured" }, { status: 503 });
|
|
5560
|
-
if (!hasDashboardInternalToken(request) && !isLoopbackPeer(request)) return jsonResponse({ error: "unauthorized" }, { status: 401 });
|
|
5561
|
-
return null;
|
|
5562
|
-
}
|
|
5563
|
-
function rejectUnauthorizedDashboardRequest(request) {
|
|
5564
|
-
if (!getInternalTokenSync()) return jsonResponse({ error: "dashboard session token not configured" }, { status: 503 });
|
|
5565
|
-
if (!hasDashboardAuth(request)) return jsonResponse({ error: "unauthorized" }, { status: 401 });
|
|
5566
|
-
return null;
|
|
5567
|
-
}
|
|
5568
|
-
//#endregion
|
|
5569
5960
|
//#region routes/agents/spawn-helpers.ts
|
|
5570
5961
|
init_child_env();
|
|
5571
5962
|
init_agents$1();
|
|
5572
5963
|
function handleRemoteAgentSpawn(input) {
|
|
5573
5964
|
return Effect.gen(function* () {
|
|
5574
5965
|
const { issueId, workspacePath, workspaceMetadata, spawnModel, projectPath, spawnGuardrails, lifecycle } = input;
|
|
5575
|
-
const { spawnRemoteAgent, checkRemoteSpendCap } = yield* Effect.promise(() => import("./remote-agents-
|
|
5576
|
-
const { createFlyProviderFromConfig } = yield* Effect.promise(() => import("./remote-
|
|
5577
|
-
const { loadConfigSync: loadPanConfig } = yield* Effect.promise(() => import("./config-
|
|
5966
|
+
const { spawnRemoteAgent, checkRemoteSpendCap } = yield* Effect.promise(() => import("./remote-agents-CA3Ihlxj.js"));
|
|
5967
|
+
const { createFlyProviderFromConfig } = yield* Effect.promise(() => import("./remote-ChgimyYa.js"));
|
|
5968
|
+
const { loadConfigSync: loadPanConfig } = yield* Effect.promise(() => import("./config-DzV30TOm.js"));
|
|
5578
5969
|
const panConfig = loadPanConfig();
|
|
5579
5970
|
const spendCap = checkRemoteSpendCap(panConfig);
|
|
5580
5971
|
if (!spendCap.allowed) return jsonResponse({ error: spendCap.message }, { status: 429 });
|
|
5581
5972
|
const fly = createFlyProviderFromConfig(panConfig.remote);
|
|
5582
5973
|
yield* Effect.promise(() => fly.syncAllCredentials(workspaceMetadata.vmName));
|
|
5583
|
-
const { buildWorkAgentPrompt, getTrackerContext } = yield* Effect.promise(() => import("./work-agent-prompt-
|
|
5974
|
+
const { buildWorkAgentPrompt, getTrackerContext } = yield* Effect.promise(() => import("./work-agent-prompt-Du8Vh2aJ.js"));
|
|
5584
5975
|
const trackerContext = yield* Effect.promise(() => getTrackerContext(issueId, workspacePath));
|
|
5585
5976
|
const agentPrompt = yield* Effect.promise(() => buildWorkAgentPrompt({
|
|
5586
5977
|
issueId,
|
|
@@ -5902,10 +6293,22 @@ init_harness_policy();
|
|
|
5902
6293
|
init_activity_logger();
|
|
5903
6294
|
init_projects();
|
|
5904
6295
|
init_review_status();
|
|
6296
|
+
init_state_read_home();
|
|
5905
6297
|
init_io();
|
|
5906
6298
|
init_read_model();
|
|
5907
6299
|
init_domain_services();
|
|
5908
6300
|
init_tmux();
|
|
6301
|
+
function orderDispatchConflict(decision) {
|
|
6302
|
+
if (decision.eligible) return null;
|
|
6303
|
+
return {
|
|
6304
|
+
status: 409,
|
|
6305
|
+
body: {
|
|
6306
|
+
error: decision.message ?? "Order-book dispatch is blocked.",
|
|
6307
|
+
code: decision.code ?? "order-dispatch-blocked",
|
|
6308
|
+
conditions: decision.conditions
|
|
6309
|
+
}
|
|
6310
|
+
};
|
|
6311
|
+
}
|
|
5909
6312
|
/**
|
|
5910
6313
|
* PAN-2386: emit a dashboard activity event when start-agent refuses to spawn
|
|
5911
6314
|
* because the workspace is dirty. Kept as a pure function so the refusal path
|
|
@@ -5974,6 +6377,7 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
|
|
|
5974
6377
|
const { issueId, projectId } = body;
|
|
5975
6378
|
const autoStart = body.auto === true;
|
|
5976
6379
|
const guardrailAcknowledged = body.guardrailAcknowledged === true;
|
|
6380
|
+
const offBook = body.offBook === true;
|
|
5977
6381
|
const requestedHostOverride = body.host === true || body.allowHost === true;
|
|
5978
6382
|
if (!issueId) return jsonResponse({ error: "issueId required" }, { status: 400 });
|
|
5979
6383
|
const legacyFields = [
|
|
@@ -6029,6 +6433,8 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
|
|
|
6029
6433
|
const resolvedProject = resolveProjectFromIssueSync(String(issueId));
|
|
6030
6434
|
const projectConfig = resolvedProject ? getProjectSync(resolvedProject.projectKey) : null;
|
|
6031
6435
|
const projectPath = projectConfig?.path ?? getProjectPath(projectId, issuePrefix);
|
|
6436
|
+
const orderConflict = orderDispatchConflict((yield* Effect.promise(() => checkActiveOrderDispatch(projectPath, issueId, { offBook }))).decision);
|
|
6437
|
+
if (orderConflict) return jsonResponse(orderConflict.body, { status: orderConflict.status });
|
|
6032
6438
|
const workspacePath = join(projectPath, "workspaces", `feature-${issueLower}`);
|
|
6033
6439
|
if (!existsSync(workspacePath)) try {
|
|
6034
6440
|
const nodeDir = dirname(process.execPath);
|
|
@@ -6173,10 +6579,18 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
|
|
|
6173
6579
|
}
|
|
6174
6580
|
if (!isRemote) {
|
|
6175
6581
|
emitStartAgentPhase(issueId, "stackHealthGate", "start", "checking workspace docker stack health", { workspacePath });
|
|
6176
|
-
|
|
6582
|
+
let stackHealth = yield* getWorkspaceStackHealth(issueId, {
|
|
6177
6583
|
projectConfig,
|
|
6178
6584
|
workspacePath
|
|
6179
6585
|
});
|
|
6586
|
+
if (!stackHealth.healthy && !allowHost) {
|
|
6587
|
+
emitStartAgentPhase(issueId, "stackHealthGate", "start", "stack unhealthy — attempting workspace stack rebuild", { workspacePath });
|
|
6588
|
+
yield* Effect.promise(() => assertWorkspaceStackHealthyForSpawn(issueId, "work", false, workspacePath).catch(() => void 0));
|
|
6589
|
+
stackHealth = yield* getWorkspaceStackHealth(issueId, {
|
|
6590
|
+
projectConfig,
|
|
6591
|
+
workspacePath
|
|
6592
|
+
});
|
|
6593
|
+
}
|
|
6180
6594
|
if (!stackHealth.healthy) {
|
|
6181
6595
|
yield* Effect.promise(() => appendAgentLifecycleLog(agentSessionName, "agent.start_blocked_stack_unhealthy", {
|
|
6182
6596
|
issueId,
|
|
@@ -6278,7 +6692,7 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
|
|
|
6278
6692
|
console.warn(`[start-agent] Failed to set plan.status=running (non-fatal): ${planStatusErr?.message ?? planStatusErr}`);
|
|
6279
6693
|
}
|
|
6280
6694
|
try {
|
|
6281
|
-
const { appendSessionEntry, getProjectConfigFromWorkspacePath, resolveProjectForIssue } = await import("./record-
|
|
6695
|
+
const { appendSessionEntry, getProjectConfigFromWorkspacePath, resolveProjectForIssue } = await import("./record-CN0pj4_5.js");
|
|
6282
6696
|
await appendSessionEntry(resolveProjectForIssue(issueId) ?? getProjectConfigFromWorkspacePath(workspacePath), issueId, {
|
|
6283
6697
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6284
6698
|
reason: "start",
|
|
@@ -6291,7 +6705,10 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
|
|
|
6291
6705
|
if (getReviewStatusSync(issueId)?.stuckReason === "planning_auto_handoff_failed") clearWorkspaceStuck(issueId);
|
|
6292
6706
|
};
|
|
6293
6707
|
if (isRemote && workspaceMetadata) {
|
|
6294
|
-
const
|
|
6708
|
+
const admitted = yield* Effect.promise(() => withActiveOrderDispatchReservation(projectPath, issueId, {
|
|
6709
|
+
offBook,
|
|
6710
|
+
recordOverride: true
|
|
6711
|
+
}, () => spawnAfterClearingStartGates({
|
|
6295
6712
|
agentSessionName,
|
|
6296
6713
|
gate: startGateBlock,
|
|
6297
6714
|
initialState: initialAgentState,
|
|
@@ -6305,7 +6722,10 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
|
|
|
6305
6722
|
lifecycle
|
|
6306
6723
|
})),
|
|
6307
6724
|
isSuccessful: (remoteResponse) => remoteResponse.status >= 200 && remoteResponse.status < 300
|
|
6308
|
-
}));
|
|
6725
|
+
})));
|
|
6726
|
+
const admittedConflict = orderDispatchConflict(admitted.check.decision);
|
|
6727
|
+
if (admittedConflict) return jsonResponse(admittedConflict.body, { status: admittedConflict.status });
|
|
6728
|
+
const response = admitted.result;
|
|
6309
6729
|
if (response.status < 200 || response.status >= 300) return response;
|
|
6310
6730
|
yield* Effect.promise(commitClearedGates);
|
|
6311
6731
|
yield* Effect.promise(markWorkStartAccepted);
|
|
@@ -6373,11 +6793,14 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
|
|
|
6373
6793
|
console.warn(`[start-agent] Failed to check workspace status for ${issueId}: ${message}`);
|
|
6374
6794
|
}
|
|
6375
6795
|
const bodyHarness = body.harness;
|
|
6376
|
-
const userPickedHarness = bodyHarness === "ohmypi" || bodyHarness === "claude-code" || bodyHarness === "codex" ? bodyHarness : null;
|
|
6796
|
+
const userPickedHarness = bodyHarness === "ohmypi" || bodyHarness === "claude-code" || bodyHarness === "codex" || bodyHarness === "acp" ? bodyHarness : null;
|
|
6377
6797
|
let effectiveHarness = null;
|
|
6378
6798
|
if (userPickedHarness !== null) effectiveHarness = (yield* Effect.promise(async () => canUseHarnessSync(userPickedHarness, spawnModel, await getProviderAuthMode(spawnModel)))).allowed ? userPickedHarness : "claude-code";
|
|
6379
6799
|
const spawnPanCommand = async (args, cwd) => {
|
|
6380
|
-
const
|
|
6800
|
+
const admitted = await withActiveOrderDispatchReservation(projectPath, issueId, {
|
|
6801
|
+
offBook,
|
|
6802
|
+
recordOverride: false
|
|
6803
|
+
}, () => spawnAfterClearingStartGates({
|
|
6381
6804
|
agentSessionName,
|
|
6382
6805
|
gate: gatesCommitted ? null : startGateBlock,
|
|
6383
6806
|
initialState: initialAgentState,
|
|
@@ -6389,9 +6812,10 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
|
|
|
6389
6812
|
args,
|
|
6390
6813
|
cwd
|
|
6391
6814
|
})
|
|
6392
|
-
});
|
|
6815
|
+
}));
|
|
6816
|
+
if (!admitted.check.decision.eligible || !admitted.result) throw new OrderDispatchReservationError(admitted.check);
|
|
6393
6817
|
await commitClearedGates();
|
|
6394
|
-
return
|
|
6818
|
+
return admitted.result;
|
|
6395
6819
|
};
|
|
6396
6820
|
const updateIssueStatus = async () => {
|
|
6397
6821
|
await Effect.runPromise(lifecycle.transitionTo(issueId, "in_progress").pipe(Effect.catch(() => Effect.void)));
|
|
@@ -6475,7 +6899,8 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
|
|
|
6475
6899
|
issueId,
|
|
6476
6900
|
model: spawnModel,
|
|
6477
6901
|
harness: effectiveHarness,
|
|
6478
|
-
allowHost
|
|
6902
|
+
allowHost,
|
|
6903
|
+
offBook
|
|
6479
6904
|
}), workspacePath));
|
|
6480
6905
|
yield* Effect.promise(markWorkStartAccepted);
|
|
6481
6906
|
emitStartAgentPhase(issueId, "spawn", "success", "local work agent spawn requested", {
|
|
@@ -6506,6 +6931,10 @@ const postAgentsRoute = HttpRouter.add("POST", "/api/agents", httpHandler(Effect
|
|
|
6506
6931
|
fallbackStatus: fallbackState.status
|
|
6507
6932
|
}));
|
|
6508
6933
|
invalidateAgentsCache();
|
|
6934
|
+
if (error instanceof OrderDispatchReservationError) {
|
|
6935
|
+
const conflict = orderDispatchConflict(error.check.decision);
|
|
6936
|
+
return jsonResponse(conflict.body, { status: conflict.status });
|
|
6937
|
+
}
|
|
6509
6938
|
const output = String(error?.output ?? error?.message ?? "");
|
|
6510
6939
|
if (output.includes(`Workspace docker stack for ${issueId}`) && output.includes("is not healthy")) {
|
|
6511
6940
|
const failedStackHealth = yield* getWorkspaceStackHealth(issueId, {
|
|
@@ -6715,10 +7144,10 @@ const _serverManagedMerges = /* @__PURE__ */ new Set();
|
|
|
6715
7144
|
function firePostMergeLifecycle(issueId, options) {
|
|
6716
7145
|
const started = postMergeGuard.run(issueId, async () => {
|
|
6717
7146
|
const projectPath = getProjectPathForIssue(extractPrefixSync(issueId) ?? issueId.split("-")[0]);
|
|
6718
|
-
const { postMergeLifecycle } = await import("./merge-agent-
|
|
7147
|
+
const { postMergeLifecycle } = await import("./merge-agent-CKkgIBPB.js");
|
|
6719
7148
|
await postMergeLifecycle(issueId, projectPath, options?.sourceBranch, options?.verifiedMergedRef ? { verifiedMergedRef: options.verifiedMergedRef } : void 0);
|
|
6720
7149
|
console.log(`[merge] post-merge lifecycle completed for ${issueId}`);
|
|
6721
|
-
const { runMergeTrainReconcile } = await import("./merge-train-
|
|
7150
|
+
const { runMergeTrainReconcile } = await import("./merge-train-CHopycP0.js");
|
|
6722
7151
|
const outcomes = await runMergeTrainReconcile(issueId);
|
|
6723
7152
|
if (outcomes.length > 0) console.log(`[merge-train] reconciled ${outcomes.length} sibling(s) after ${issueId}: ` + outcomes.map((o) => `${o.issueId}=${o.result}`).join(", "));
|
|
6724
7153
|
}, (err) => console.error(`[merge] post-merge lifecycle failed for ${issueId}:`, err));
|
|
@@ -6739,15 +7168,15 @@ init_io();
|
|
|
6739
7168
|
init_domain_services();
|
|
6740
7169
|
init_tmux();
|
|
6741
7170
|
const getSpecialistsRoute = HttpRouter.add("GET", "/api/specialists", httpHandler(Effect.gen(function* () {
|
|
6742
|
-
const { getAllSpecialistStatus, getAllProjectSpecialistStatuses } = yield* Effect.promise(() => import("./specialists-
|
|
7171
|
+
const { getAllSpecialistStatus, getAllProjectSpecialistStatuses } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
|
|
6743
7172
|
return jsonResponse({
|
|
6744
7173
|
specialists: yield* Effect.promise(() => getAllSpecialistStatus()),
|
|
6745
7174
|
projects: yield* Effect.promise(() => getAllProjectSpecialistStatuses())
|
|
6746
7175
|
});
|
|
6747
7176
|
})));
|
|
6748
7177
|
const postSpecialistsResetAllRoute = HttpRouter.add("POST", "/api/specialists/reset-all", httpHandler(Effect.gen(function* () {
|
|
6749
|
-
const { getAllSpecialists, isRunning, getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-
|
|
6750
|
-
const { clearHookSync } = yield* Effect.promise(() => import("./hooks-
|
|
7178
|
+
const { getAllSpecialists, isRunning, getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
|
|
7179
|
+
const { clearHookSync } = yield* Effect.promise(() => import("./hooks-DPVX1rwQ.js"));
|
|
6751
7180
|
const specialists = getAllSpecialists();
|
|
6752
7181
|
const results = [];
|
|
6753
7182
|
for (const specialist of specialists) {
|
|
@@ -6803,7 +7232,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
6803
7232
|
}
|
|
6804
7233
|
console.log(`[specialists/done] ${specialist} signaling ${status} for ${normalizedIssueId}`);
|
|
6805
7234
|
if (specialist === "merge") {
|
|
6806
|
-
const { reportSpecialistCompletion } = yield* Effect.promise(() => import("./specialist-completion-
|
|
7235
|
+
const { reportSpecialistCompletion } = yield* Effect.promise(() => import("./specialist-completion-Ky9wCDpb.js"));
|
|
6807
7236
|
if (yield* reportSpecialistCompletion(normalizedIssueId, {
|
|
6808
7237
|
status,
|
|
6809
7238
|
notes
|
|
@@ -6850,7 +7279,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
6850
7279
|
if (specialist === "inspect" && status === "failed") yield* Effect.promise(() => reportTieredInspectFailureEscalation(normalizedIssueId, notes));
|
|
6851
7280
|
yield* Effect.promise(async () => {
|
|
6852
7281
|
try {
|
|
6853
|
-
const { getTmuxSessionName, updateRunMetadata, makeSpecialistRegistryKey } = await import("./specialists-
|
|
7282
|
+
const { getTmuxSessionName, updateRunMetadata, makeSpecialistRegistryKey } = await import("./specialists-DM6bWjsi.js");
|
|
6854
7283
|
const projectKey = resolveProjectFromIssueSync(normalizedIssueId)?.projectKey;
|
|
6855
7284
|
const tmuxSession = projectKey ? getTmuxSessionName(`${specialist}-agent`, projectKey, normalizedIssueId) : getTmuxSessionName(`${specialist}-agent`);
|
|
6856
7285
|
saveAgentRuntimeState(tmuxSession, {
|
|
@@ -6869,7 +7298,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
6869
7298
|
});
|
|
6870
7299
|
console.log(`[specialists/done] Cleared registry lock for ${registryKey} (${projectKey})`);
|
|
6871
7300
|
}
|
|
6872
|
-
const { updateSpecialistHandoffStatus } = await import("./specialist-handoff-logger-
|
|
7301
|
+
const { updateSpecialistHandoffStatus } = await import("./specialist-handoff-logger-CMEwYxa2.js");
|
|
6873
7302
|
if (await Effect.runPromise(updateSpecialistHandoffStatus(normalizedIssueId, `${specialist}-agent`, status === "passed" ? "completed" : "failed", status === "passed" ? "success" : "failure"))) console.log(`[specialists/done] Updated handoff log: ${specialist}-agent ${normalizedIssueId} → ${status}`);
|
|
6874
7303
|
} catch (err) {
|
|
6875
7304
|
console.error(`[specialists/done] Error managing specialist state:`, err);
|
|
@@ -6881,7 +7310,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
6881
7310
|
if (project) {
|
|
6882
7311
|
const workspacePath = join(project.projectPath, "workspaces", `feature-${normalizedIssueId.toLowerCase()}`);
|
|
6883
7312
|
if (existsSync(workspacePath)) {
|
|
6884
|
-
const { getWorkspaceGitInfo } = await import("./git-utils-
|
|
7313
|
+
const { getWorkspaceGitInfo } = await import("./git-utils-D0_yhCgF.js");
|
|
6885
7314
|
const { HEAD } = await Effect.runPromise(getWorkspaceGitInfo(workspacePath));
|
|
6886
7315
|
setReviewStatusSync(normalizedIssueId, { reviewedAtCommit: HEAD });
|
|
6887
7316
|
console.log(`[specialists/done] Snapshotted reviewedAtCommit=${HEAD.substring(0, 8)} for ${normalizedIssueId}`);
|
|
@@ -6893,7 +7322,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
6893
7322
|
});
|
|
6894
7323
|
if (specialist === "inspect" && status === "passed") yield* Effect.promise(async () => {
|
|
6895
7324
|
try {
|
|
6896
|
-
const { onInspectComplete } = await import("./inspect-agent-
|
|
7325
|
+
const { onInspectComplete } = await import("./inspect-agent-Brtz0URj.js");
|
|
6897
7326
|
const project = resolveProjectFromIssueSync(normalizedIssueId);
|
|
6898
7327
|
if (project) {
|
|
6899
7328
|
const workspacePath = join(project.projectPath, "workspaces", `feature-${normalizedIssueId.toLowerCase()}`);
|
|
@@ -6909,7 +7338,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
6909
7338
|
if (project) {
|
|
6910
7339
|
if (existsSync(join(project.projectPath, "workspaces", `feature-${normalizedIssueId.toLowerCase()}`))) {
|
|
6911
7340
|
setReviewStatusSync(normalizedIssueId, { testStatus: "passed" });
|
|
6912
|
-
const { initEventStore } = await import("./event-store-
|
|
7341
|
+
const { initEventStore } = await import("./event-store-EV2cMiXj.js");
|
|
6913
7342
|
await (await initEventStore()).appendAsync({
|
|
6914
7343
|
type: "test.passed",
|
|
6915
7344
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -6962,8 +7391,8 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
6962
7391
|
if (notes?.toLowerCase().includes("conflict")) yield* Effect.promise(async () => {
|
|
6963
7392
|
try {
|
|
6964
7393
|
const workAgentId = `agent-${normalizedIssueId.toLowerCase()}`;
|
|
6965
|
-
const { sessionExists } = await import("./tmux-
|
|
6966
|
-
const { messageAgent, spawnAgent, getAgentStateSync } = await import("./agents-
|
|
7394
|
+
const { sessionExists } = await import("./tmux-B6z7h_vZ.js");
|
|
7395
|
+
const { messageAgent, spawnAgent, getAgentStateSync } = await import("./agents-wi9NWzs2.js");
|
|
6967
7396
|
if (await Effect.runPromise(sessionExists(workAgentId))) {
|
|
6968
7397
|
await messageAgent(workAgentId, `MERGE CONFLICT: The merge-agent could not rebase your branch onto main due to conflicts. Please fix this now:\n\n1. git fetch origin main\n2. git rebase origin/main\n3. Resolve any conflicts (git add <file> && git rebase --continue)\n4. git push --force-with-lease\n5. Resubmit: curl -s -X POST http://localhost:3011/api/review/${normalizedIssueId}/request -H "Content-Type: application/json" -d "{}"\n\nConflict details: ${notes}`);
|
|
6969
7398
|
console.log(`[specialists/done] Sent rebase instructions to ${workAgentId}`);
|
|
@@ -6977,7 +7406,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
6977
7406
|
try {
|
|
6978
7407
|
const project = resolveProjectFromIssueSync(normalizedIssueId);
|
|
6979
7408
|
const workspacePath = project ? join(project.projectPath, "workspaces", `feature-${normalizedIssueId.toLowerCase()}`) : void 0;
|
|
6980
|
-
const { deliverReviewVerdictFeedback } = await import("./review-verdict-feedback-
|
|
7409
|
+
const { deliverReviewVerdictFeedback } = await import("./review-verdict-feedback-CTd4QMBu.js");
|
|
6981
7410
|
const result = await Effect.runPromise(deliverReviewVerdictFeedback({
|
|
6982
7411
|
issueId: normalizedIssueId,
|
|
6983
7412
|
verdict: status === "failed" ? "failed" : "blocked",
|
|
@@ -7018,7 +7447,7 @@ const postSpecialistsDoneRoute = HttpRouter.add("POST", "/api/specialists/done",
|
|
|
7018
7447
|
});
|
|
7019
7448
|
})));
|
|
7020
7449
|
const postSpecialistsLogsCleanupAllRoute = HttpRouter.add("POST", "/api/specialists/logs/cleanup-all", httpHandler(Effect.gen(function* () {
|
|
7021
|
-
const { cleanupAllLogsSync } = yield* Effect.promise(() => import("./specialist-logs-
|
|
7450
|
+
const { cleanupAllLogsSync } = yield* Effect.promise(() => import("./specialist-logs-C5p8G7tx.js"));
|
|
7022
7451
|
const results = cleanupAllLogsSync();
|
|
7023
7452
|
return jsonResponse({
|
|
7024
7453
|
success: true,
|
|
@@ -7028,7 +7457,7 @@ const postSpecialistsLogsCleanupAllRoute = HttpRouter.add("POST", "/api/speciali
|
|
|
7028
7457
|
});
|
|
7029
7458
|
})));
|
|
7030
7459
|
const getSpecialistsProjectsRoute = HttpRouter.add("GET", "/api/specialists/projects", httpHandler(Effect.gen(function* () {
|
|
7031
|
-
const { getAllProjectSpecialistStatuses } = yield* Effect.promise(() => import("./specialists-
|
|
7460
|
+
const { getAllProjectSpecialistStatuses } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
|
|
7032
7461
|
return jsonResponse(yield* Effect.promise(() => getAllProjectSpecialistStatuses()));
|
|
7033
7462
|
})));
|
|
7034
7463
|
const postSpecialistWakeRoute = HttpRouter.add("POST", "/api/specialists/:name/wake", httpHandler(Effect.gen(function* () {
|
|
@@ -7072,7 +7501,7 @@ const postSpecialistReportStatusRoute = HttpRouter.add("POST", "/api/specialists
|
|
|
7072
7501
|
"blocked",
|
|
7073
7502
|
"failed"
|
|
7074
7503
|
].includes(status)) {
|
|
7075
|
-
const { getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-
|
|
7504
|
+
const { getTmuxSessionName } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
|
|
7076
7505
|
saveAgentRuntimeState(getTmuxSessionName(name), {
|
|
7077
7506
|
state: "idle",
|
|
7078
7507
|
lastActivity: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -7193,7 +7622,7 @@ const postProjectSpecialistKillRoute = HttpRouter.add("POST", "/api/specialists/
|
|
|
7193
7622
|
const issueId = params["issueId"];
|
|
7194
7623
|
const type = params["type"];
|
|
7195
7624
|
if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
|
|
7196
|
-
const { getTmuxSessionName, makeSpecialistRegistryKey, getRunMetadata } = yield* Effect.promise(() => import("./specialists-
|
|
7625
|
+
const { getTmuxSessionName, makeSpecialistRegistryKey, getRunMetadata } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
|
|
7197
7626
|
const tmuxSession = getRunMetadata(project, makeSpecialistRegistryKey(type, issueId)).tmuxSession ?? getTmuxSessionName(type, project, issueId);
|
|
7198
7627
|
yield* Effect.promise(() => Effect.runPromise(killSession(tmuxSession)).catch(() => {}));
|
|
7199
7628
|
saveAgentRuntimeState(tmuxSession, {
|
|
@@ -7220,7 +7649,7 @@ const getProjectSpecialistRunsRoute = HttpRouter.add("GET", "/api/specialists/:p
|
|
|
7220
7649
|
if (limitParam) limit = parseInt(limitParam, 10);
|
|
7221
7650
|
if (offsetParam) offset = parseInt(offsetParam, 10);
|
|
7222
7651
|
}
|
|
7223
|
-
const { listRunLogsSync } = yield* Effect.promise(() => import("./specialist-logs-
|
|
7652
|
+
const { listRunLogsSync } = yield* Effect.promise(() => import("./specialist-logs-C5p8G7tx.js"));
|
|
7224
7653
|
return jsonResponse(listRunLogsSync(project, type, {
|
|
7225
7654
|
limit,
|
|
7226
7655
|
offset
|
|
@@ -7231,7 +7660,7 @@ const getProjectSpecialistRunStreamRoute = HttpRouter.add("GET", "/api/specialis
|
|
|
7231
7660
|
const project = params["project"];
|
|
7232
7661
|
const type = params["type"];
|
|
7233
7662
|
const runId = params["runId"];
|
|
7234
|
-
const { getRunLogPath, isRunLogActive } = yield* Effect.promise(() => import("./specialist-logs-
|
|
7663
|
+
const { getRunLogPath, isRunLogActive } = yield* Effect.promise(() => import("./specialist-logs-C5p8G7tx.js"));
|
|
7235
7664
|
const logPath = getRunLogPath(project, type, runId);
|
|
7236
7665
|
if (!existsSync(logPath)) return jsonResponse({ error: "Run log not found" }, { status: 404 });
|
|
7237
7666
|
const encoder = new TextEncoder();
|
|
@@ -7290,7 +7719,7 @@ const getProjectSpecialistRunRoute = HttpRouter.add("GET", "/api/specialists/:pr
|
|
|
7290
7719
|
const project = params["project"];
|
|
7291
7720
|
const type = params["type"];
|
|
7292
7721
|
const runId = params["runId"];
|
|
7293
|
-
const { getRunLogSync, parseLogMetadata } = yield* Effect.promise(() => import("./specialist-logs-
|
|
7722
|
+
const { getRunLogSync, parseLogMetadata } = yield* Effect.promise(() => import("./specialist-logs-C5p8G7tx.js"));
|
|
7294
7723
|
const content = getRunLogSync(project, type, runId);
|
|
7295
7724
|
if (!content) return jsonResponse({ error: "Run log not found" }, { status: 404 });
|
|
7296
7725
|
return jsonResponse({
|
|
@@ -7304,7 +7733,7 @@ const postProjectSpecialistRunTerminateRoute = HttpRouter.add("POST", "/api/spec
|
|
|
7304
7733
|
const project = params["project"];
|
|
7305
7734
|
const type = params["type"];
|
|
7306
7735
|
if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
|
|
7307
|
-
const { terminateSpecialist } = yield* Effect.promise(() => import("./specialists-
|
|
7736
|
+
const { terminateSpecialist } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
|
|
7308
7737
|
yield* Effect.promise(() => terminateSpecialist(project, type));
|
|
7309
7738
|
return jsonResponse({
|
|
7310
7739
|
success: true,
|
|
@@ -7316,7 +7745,7 @@ const postProjectSpecialistGracePauseRoute = HttpRouter.add("POST", "/api/specia
|
|
|
7316
7745
|
const project = params["project"];
|
|
7317
7746
|
const type = params["type"];
|
|
7318
7747
|
if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
|
|
7319
|
-
const { pauseGracePeriod } = yield* Effect.promise(() => import("./specialists-
|
|
7748
|
+
const { pauseGracePeriod } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
|
|
7320
7749
|
if (pauseGracePeriod(project, type)) return jsonResponse({
|
|
7321
7750
|
success: true,
|
|
7322
7751
|
message: "Grace period paused"
|
|
@@ -7328,7 +7757,7 @@ const postProjectSpecialistGraceResumeRoute = HttpRouter.add("POST", "/api/speci
|
|
|
7328
7757
|
const project = params["project"];
|
|
7329
7758
|
const type = params["type"];
|
|
7330
7759
|
if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
|
|
7331
|
-
const { resumeGracePeriod } = yield* Effect.promise(() => import("./specialists-
|
|
7760
|
+
const { resumeGracePeriod } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
|
|
7332
7761
|
if (resumeGracePeriod(project, type)) return jsonResponse({
|
|
7333
7762
|
success: true,
|
|
7334
7763
|
message: "Grace period resumed"
|
|
@@ -7340,7 +7769,7 @@ const postProjectSpecialistGraceExitRoute = HttpRouter.add("POST", "/api/special
|
|
|
7340
7769
|
const project = params["project"];
|
|
7341
7770
|
const type = params["type"];
|
|
7342
7771
|
if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
|
|
7343
|
-
const { exitGracePeriod } = yield* Effect.promise(() => import("./specialists-
|
|
7772
|
+
const { exitGracePeriod } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
|
|
7344
7773
|
exitGracePeriod(project, type);
|
|
7345
7774
|
return jsonResponse({
|
|
7346
7775
|
success: true,
|
|
@@ -7352,7 +7781,7 @@ const getProjectSpecialistGraceRoute = HttpRouter.add("GET", "/api/specialists/:
|
|
|
7352
7781
|
const project = params["project"];
|
|
7353
7782
|
const type = params["type"];
|
|
7354
7783
|
if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
|
|
7355
|
-
const { getGracePeriodState } = yield* Effect.promise(() => import("./specialists-
|
|
7784
|
+
const { getGracePeriodState } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
|
|
7356
7785
|
const state = getGracePeriodState(project, type);
|
|
7357
7786
|
if (state) return jsonResponse(state);
|
|
7358
7787
|
else return jsonResponse({ error: "No active grace period" }, { status: 404 });
|
|
@@ -7361,7 +7790,7 @@ const getProjectSpecialistContextRoute = HttpRouter.add("GET", "/api/specialists
|
|
|
7361
7790
|
const params = yield* HttpRouter.params;
|
|
7362
7791
|
const project = params["project"];
|
|
7363
7792
|
const type = params["type"];
|
|
7364
|
-
const { loadContextDigest } = yield* Effect.promise(() => import("./specialist-context-
|
|
7793
|
+
const { loadContextDigest } = yield* Effect.promise(() => import("./specialist-context-Bn3dCGS2.js"));
|
|
7365
7794
|
const digest = loadContextDigest(project, type);
|
|
7366
7795
|
if (digest) return jsonResponse({ digest });
|
|
7367
7796
|
else return jsonResponse({ error: "No context digest found" }, { status: 404 });
|
|
@@ -7370,7 +7799,7 @@ const postProjectSpecialistContextRegenerateRoute = HttpRouter.add("POST", "/api
|
|
|
7370
7799
|
const params = yield* HttpRouter.params;
|
|
7371
7800
|
const project = params["project"];
|
|
7372
7801
|
const type = params["type"];
|
|
7373
|
-
const { regenerateContextDigest } = yield* Effect.promise(() => import("./specialist-context-
|
|
7802
|
+
const { regenerateContextDigest } = yield* Effect.promise(() => import("./specialist-context-Bn3dCGS2.js"));
|
|
7374
7803
|
const digest = yield* Effect.promise(() => regenerateContextDigest(project, type));
|
|
7375
7804
|
if (digest) return jsonResponse({
|
|
7376
7805
|
digest,
|
|
@@ -7389,7 +7818,7 @@ const postProjectSpecialistCompleteRoute = HttpRouter.add("POST", "/api/speciali
|
|
|
7389
7818
|
"blocked"
|
|
7390
7819
|
].includes(status)) return jsonResponse({ error: "Valid status (passed/failed/blocked) is required" }, { status: 400 });
|
|
7391
7820
|
if (!validateSpecialistAgentName(type)) return jsonResponse({ error: "Invalid specialist type. Must be review-agent, test-agent, or merge-agent" }, { status: 400 });
|
|
7392
|
-
const { signalSpecialistCompletion } = yield* Effect.promise(() => import("./specialists-
|
|
7821
|
+
const { signalSpecialistCompletion } = yield* Effect.promise(() => import("./specialists-DM6bWjsi.js"));
|
|
7393
7822
|
signalSpecialistCompletion(project, type, {
|
|
7394
7823
|
status,
|
|
7395
7824
|
notes
|
|
@@ -7423,8 +7852,8 @@ const postProjectSpecialistLogsCleanupRoute = HttpRouter.add("POST", "/api/speci
|
|
|
7423
7852
|
const params = yield* HttpRouter.params;
|
|
7424
7853
|
const project = params["project"];
|
|
7425
7854
|
const type = params["type"];
|
|
7426
|
-
const { cleanupOldLogsSync } = yield* Effect.promise(() => import("./specialist-logs-
|
|
7427
|
-
const { getSpecialistRetention } = yield* Effect.promise(() => import("./projects-
|
|
7855
|
+
const { cleanupOldLogsSync } = yield* Effect.promise(() => import("./specialist-logs-C5p8G7tx.js"));
|
|
7856
|
+
const { getSpecialistRetention } = yield* Effect.promise(() => import("./projects-vjjcmiN8.js"));
|
|
7428
7857
|
const retention = getSpecialistRetention(project);
|
|
7429
7858
|
const deleted = cleanupOldLogsSync(project, type, {
|
|
7430
7859
|
maxDays: retention.max_days,
|
|
@@ -7445,7 +7874,7 @@ const postProjectReviewRestartRoute = HttpRouter.add("POST", "/api/specialists/:
|
|
|
7445
7874
|
const project = params["project"];
|
|
7446
7875
|
const issueId = params["issueId"];
|
|
7447
7876
|
const { model, harness } = yield* readJsonBody;
|
|
7448
|
-
const { killAllReviewerSessions } = yield* Effect.promise(() => import("./review-agent-
|
|
7877
|
+
const { killAllReviewerSessions } = yield* Effect.promise(() => import("./review-agent-DNboMyW4.js"));
|
|
7449
7878
|
const killResult = yield* killAllReviewerSessions(project, issueId);
|
|
7450
7879
|
const projectConfig = resolveProjectFromIssueSync(issueId);
|
|
7451
7880
|
if (!projectConfig) return jsonResponse({ error: `Cannot resolve project for ${issueId}` }, { status: 404 });
|
|
@@ -7459,7 +7888,7 @@ const postProjectReviewRestartRoute = HttpRouter.add("POST", "/api/specialists/:
|
|
|
7459
7888
|
}));
|
|
7460
7889
|
branch = stdout.trim() || "unknown";
|
|
7461
7890
|
} catch {}
|
|
7462
|
-
const { spawnReviewRoleForIssue } = yield* Effect.promise(() => import("./review-agent-
|
|
7891
|
+
const { spawnReviewRoleForIssue } = yield* Effect.promise(() => import("./review-agent-DNboMyW4.js"));
|
|
7463
7892
|
const prUrl = getReviewStatusSync(issueId)?.prUrl;
|
|
7464
7893
|
const result = yield* spawnReviewRoleForIssue({
|
|
7465
7894
|
issueId,
|
|
@@ -7608,6 +8037,6 @@ const specialistsProjectRouteLayer = Layer.mergeAll(getProjectSpecialistStatusRo
|
|
|
7608
8037
|
*/
|
|
7609
8038
|
const specialistsRouteLayer = Layer.mergeAll(specialistsLegacyRouteLayer, specialistsProjectRouteLayer);
|
|
7610
8039
|
//#endregion
|
|
7611
|
-
export {
|
|
8040
|
+
export { panCliInvocation as $, resolveAllowedHarness as A, cleanupUnreferencedConversationAttachments as B, handleConversationCreate as C, jsonStringResponse as Ct, handleConversationStop as D, handleConversationResume as E, tmuxSessionExists as F, isManagedConversationAttachmentPath as G, extractConversationAttachmentPaths as H, waitForPiTuiReady as I, evaluateSpawnGuardrails as J, removeConversationAttachment as K, waitForTmuxSession as L, spawnConversationSession as M, startConversationModelBackfill as N, handleConversationSwitchModel as O, stopConversationRuntime as P, getWorkAgentLifecycleStateSync as Q, cleanupConversationAttachments as R, conversationSessionAliveFromState as S, jsonResponse as St, handleConversationRestartAll as T, getConversationAttachmentsRoot as U, ensureConversationAttachmentDir as V, hasConversationAttachment as W, resolveAgentGitInfo as X, invalidateAgentsCache as Y, resolveConversationGitInfo as Z, isPiControlChannelHarness as _, isTrustedOriginForHost as _t, agentsRouteLayer as a, resolveCodexRolloutPath as at, validateConversationControlAckOrigin as b, httpHandler as bt, codexConversationPendingInput as c, dashboardCsrfToken as ct, handleConversationCodexApproval as d, rejectUnauthorizedDashboardRequest as dt, spawnPanCli as et, handleConversationCompact as f, rejectUnauthorizedDashboardSessionMintRequest as ft, handleConversationThinkingLevel as g, getHeaderFromMap as gt, handleConversationPlanAction as h, waitForSessionRespawn as ht, validateSpecialistAutoCompleteMetadata as i, resolveClaudeSessionId as it, shouldReportUnresolvedLiveSession as j, isInsideGitWorkTree as k, deliverConversationViaControlChannel as l, dashboardSessionCookieHeader as lt, handleConversationDeliveryMethod as m, isRespawnPending as mt, _serverManagedMerges as n, resolveAcpTranscriptPath as nt, saveAgentStateAndEmitEvent as o, resolveJsonlPath as ot, handleConversationControlAck as p, rejectUnsafeDashboardMutationRequest as pt, runInBatches as q, firePostMergeLifecycle as r, resolveAgentHarness as rt, saveAgentStateAndEmitEventProgram as s, resolvePiSessionPath as st, specialistsRouteLayer as t, readLauncherPinnedSessionId as tt, handleConversationAbort as u, hasDashboardInternalToken as ut, pickDeliverAs as v, validateOrigin as vt, handleConversationDelete as w, conversationNeedsRunningRepair as x, getDefaultCwd as xt, resolveConversationDeliveryMethod as y, validateOriginHeaders as yt, cleanupOrphanedConversationAttachments as z };
|
|
7612
8041
|
|
|
7613
|
-
//# sourceMappingURL=specialists-
|
|
8042
|
+
//# sourceMappingURL=specialists-CC4r-c2s.js.map
|