@overdeck/desktop 0.49.1 → 0.50.0
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 +1 -0
- package/package.json +1 -1
- package/server/{acceptance-criteria-Crw-xSJ3.js → acceptance-criteria-B_maCGZv.js} +2 -2
- package/server/{active-dashboard-bundle-CLwfD-Om.js → active-dashboard-bundle-CCqpFWiz.js} +2 -2
- package/server/activity-logger-B0X2JJwM.js +3 -0
- package/server/{activity-logger-BAVLrkR7.js → activity-logger-SlTXYCVf.js} +22 -4
- package/server/{advancing-selfheal-BQiJ7mIH.js → advancing-selfheal-BJAfiY-C.js} +12 -7
- package/server/{agent-gc-5E0lgxI1.js → agent-gc-bhikjoJ_.js} +11 -11
- package/server/agent-idle-D-UQ7gDv.js +745 -0
- package/server/agent-state-BrUPf_7Z.js +3 -0
- package/server/{agent-state-Bb3UUxQm.js → agent-state-FABw8neJ.js} +682 -454
- package/server/{agent-state-service-keg-x1bT.js → agent-state-service-BAQApt97.js} +1 -1
- package/server/{agent-state-service-BFbttwRA.js → agent-state-service-rDenYSlD.js} +5 -5
- package/server/agents-DixZjXWm.js +3 -0
- package/server/{agents-CqQJW75N.js → agents-DzpQidT8.js} +8 -8
- package/server/{archive-planning-BwEhu9Oq.js → archive-planning-BL1ABtW0.js} +20 -135
- package/server/archive-planning-D3gw32U9.js +2 -0
- package/server/{artifact-index-jobs-C6Lg2rKm.js → artifact-index-jobs-Cjdme0jS.js} +3 -3
- package/server/{assemble-DyTp2gSB.js → assemble-B_JgnCbG.js} +28 -9
- package/server/{auto-spawn-consent-BDfe4qz0.js → auto-spawn-consent-BesWchEi.js} +8 -7
- package/server/{backlog-auto-trigger-DuOGpdDW.js → backlog-auto-trigger-COLq639j.js} +3 -3
- package/server/{behavior-Bitko0mD.js → behavior-DCg8CIWC.js} +3 -3
- package/server/{bridge-pool-patrol-DiHEd13O.js → bridge-pool-patrol-BDohuMRt.js} +2 -2
- package/server/{briefing-freshness-CDJcmHHZ.js → briefing-freshness-ENa_hW_V.js} +2 -2
- package/server/build-info-Dx2qrVhb.js +2 -0
- package/server/{build-info-DTX8JwVP.js → build-info-WuZT6xyi.js} +3 -3
- package/server/{checkpoint-manager-BlOOdzLF.js → checkpoint-manager-CSZ7aVQF.js} +26 -9
- package/server/{checkpoint-manager-CKg1tn34.js → checkpoint-manager-DXhGRvg4.js} +1 -1
- package/server/checkpoint-worker.js +1 -1
- package/server/{checkpoints-BGfl0cHM.js → checkpoints-DUkUsPVS.js} +2 -2
- package/server/{checkpoints-DRALkfDS.js → checkpoints-tm_w6Y4V.js} +1 -1
- package/server/{claude-hooks-provision-B_tv3wzE.js → claude-hooks-provision-CTh9zxEi.js} +1 -1
- package/server/{claude-hooks-provision-BlGv6twJ.js → claude-hooks-provision-fRofvhTN.js} +2 -2
- package/server/{claude-permissions-aHgDcZi5.js → claude-permissions-DLrb9ovz.js} +18 -3
- package/server/{claude-settings-overlay-T2LWLteV.js → claude-settings-overlay-BYnXaTVc.js} +2 -2
- package/server/{claude-settings-overlay-CYOvFE3A.js → claude-settings-overlay-CMS5Jab5.js} +1 -1
- package/server/cli-BflmtEFM.js +2 -0
- package/server/{cli-Do8UpLoI.js → cli-CoQou1t_.js} +11 -11
- package/server/{cliproxy-CX6jHRDP.js → cliproxy-DXDQcR3I.js} +52 -17
- package/server/cliproxy-DdhFpcXU.js +3 -0
- package/server/{close-issue-J0_eWYT1.js → close-issue-CpQ0BWg-.js} +5 -5
- package/server/{closed-issue-reaper-bFppuk6F.js → closed-issue-reaper-CdcJRvUx.js} +13 -12
- package/server/{closed-issue-reaper-Cl2h9AfT.js → closed-issue-reaper-TymtZM37.js} +1 -1
- package/server/{codex-icapA4om.js → codex-BValsmtK.js} +1 -1
- package/server/{codex-OOea7lXs.js → codex-DYyZL8JD.js} +16 -10
- package/server/{compaction-continuation-D5voR1ME.js → compaction-continuation-CVjbdGKt.js} +3 -3
- package/server/{config-Cjleh3_U.js → config-CvKH7r7W.js} +1 -1
- package/server/{config-tucKBCCc.js → config-NxI9Yl2f.js} +2 -2
- package/server/{config-DC75T4Mr.js → config-_qaa1UXH.js} +2 -2
- package/server/{config-yaml-BwOEANMr.js → config-yaml-D60AnTIu.js} +55 -15
- package/server/{conflict-gate-DlpWCMd7.js → conflict-gate-0dD1kxjN.js} +1 -1
- package/server/{conflict-gate-D2L1kZeL.js → conflict-gate-hAUCL-un.js} +5 -5
- package/server/{context-layers-CSPGc2Hb.js → context-layers-CdpabJj0.js} +3 -3
- package/server/context-layers-Ds1MnEFI.js +4 -0
- package/server/{continue-U3Af0jUq.js → continue-CnvrUfxw.js} +3 -3
- package/server/{control-settings-5k6ixdFW.js → control-settings-Db0uXgVM.js} +310 -7
- package/server/{conversation-compaction-CSpVpxN6.js → conversation-compaction-B-1KETG9.js} +8 -8
- package/server/{conversation-compaction-Ciit9O6k.js → conversation-compaction-DzMXGRiJ.js} +1 -1
- package/server/{conversation-service-BxrB5lUT.js → conversation-service-BL-asWPX.js} +1 -1
- package/server/{conversation-service-BteE4ELK.js → conversation-service-BxIOd5ay.js} +21 -7
- package/server/conversations-CEMfwMt-.js +3 -0
- package/server/{conversations-DhwxsOru.js → conversations-nS6QgYpD.js} +12 -7
- package/server/cost-3FyqKK56.js +838 -0
- package/server/{cost-Bnf9NUC5.js → cost-Cctc-Q9M.js} +3 -3
- package/server/{cost-CQKI6OCu.js → cost-DTuIRE4y.js} +2 -2
- package/server/{cost-sync-B-ADeXKY.js → cost-sync-DfmvLT9L.js} +3 -3
- package/server/{dag-DI9LaK_q.js → dag-o-dUpw1L.js} +6 -19
- package/server/{dangerous-git-ops-akhA3iyF.js → dangerous-git-ops-BOtXCFkT.js} +1 -1
- package/server/dashboard-db-worker.js +61 -11
- package/server/{deacon-TPYssFYt.js → deacon-CsisLmPt.js} +1735 -172
- package/server/{deacon-canonical-state-DFYymrDw.js → deacon-canonical-state-DkdkQS5p.js} +3 -3
- package/server/deacon-e6py3jkM.js +4 -0
- package/server/{deacon-event-client-Te5v10-b.js → deacon-event-client-BCjHiGAY.js} +1 -1
- package/server/{deacon-event-client-BKOL4AcL.js → deacon-event-client-CMQswEHX.js} +2 -2
- package/server/{deacon-nudge-log-BtlTWgWu.js → deacon-nudge-log-pcliw8Dr.js} +1 -1
- package/server/{deacon-pending-lifecycle-DVHjOLje.js → deacon-pending-lifecycle-BzaE76Xo.js} +3 -3
- package/server/deacon.js +11 -11
- package/server/{dead-end-trip-P0IF1O0E.js → dead-end-trip-Bs3hxIn6.js} +3 -3
- package/server/dead-end-trip-DUbiRMtT.js +2 -0
- package/server/delivery-DhZGRShH.js +3 -0
- package/server/{deploy-patrol-BXjlvoV3.js → deploy-patrol-B8sKkA8h.js} +8 -8
- package/server/deploy-queue--smqHLhe.js +2 -0
- package/server/{deploy-queue-o7shYg1j.js → deploy-queue-CCGWXFkp.js} +2 -2
- package/server/{deploy-window-CNT6fOff.js → deploy-window-YuJewzmC.js} +4 -4
- package/server/{deploy-window-BMk5_oX6.js → deploy-window-hgsvZ3UZ.js} +1 -1
- package/server/{dev-supervisor-SR1CLOAK.js → dev-supervisor-4SBloJHV.js} +2 -2
- package/server/{devcontainer-renderer-enMmNDFa.js → devcontainer-renderer-BiJhwFNi.js} +3 -3
- package/server/{dist-CPTO_zMR.js → dist-CoR2sivG.js} +1 -1
- package/server/dist-FHv1s5ez.js +3 -0
- package/server/{docker-B7qUZptz.js → docker-CWO7dcIP.js} +3 -3
- package/server/{docker-KR3zSFKY.js → docker-DQzyMXkd.js} +1 -1
- package/server/{dod-gK835UMf.js → dod-BAk5arLF.js} +1 -1
- package/server/{done-preflight-CksRvh49.js → done-preflight-CGFA0M1b.js} +1 -1
- package/server/{done-preflight-Bk8aExAL.js → done-preflight-Cx9JGznT.js} +5 -5
- package/server/{driver-CmsY2RLl.js → driver-BtcFz-qu.js} +14 -3
- package/server/durable-review-pipeline-BOEZ0chh.js +3 -0
- package/server/{durable-review-pipeline-DgYHucN2.js → durable-review-pipeline-Djx_lvFd.js} +11 -2
- package/server/{ensure-devcontainer-BQ4YizSH.js → ensure-devcontainer-Dk6ZMOUC.js} +1 -1
- package/server/{ensure-devcontainer-ojerEqQg.js → ensure-devcontainer-DzYBBwnM.js} +4 -4
- package/server/{esm-shims-1htPASWs.js → esm-shims-deFq5Hhl.js} +1 -1
- package/server/{event-store-BgEjNsvk.js → event-store-C50Qt-f1.js} +1 -1
- package/server/{event-store-D7qcJXuZ.js → event-store-DTns2XZP.js} +5 -5
- package/server/{event-store-provider-BKvk2rDj.js → event-store-provider-Bu1Qrg6v.js} +1 -1
- package/server/{events-BIKGJZOT.js → events-B6xW8Cpm.js} +3 -3
- package/server/{dist-src-BM9eudEd.js → factory-CWVKwKFE.js} +714 -2
- package/server/{feature-registry-storage-ewNSIVsQ.js → feature-registry-storage-vaxRN3WO.js} +3 -3
- package/server/{features-CGopJXdU.js → features-DXWwktJB.js} +2 -2
- package/server/{feedback-stuck-retirement-B8-fX7NA.js → feedback-stuck-retirement-CXAYe2rU.js} +2 -2
- package/server/{feedback-target-CkyLYohm.js → feedback-target-DSVpi0gT.js} +1 -1
- package/server/{feedback-target-Ci6N5p4G.js → feedback-target-yPD_wclF.js} +10 -10
- package/server/{feedback-writer-DfuVjvH0.js → feedback-writer-BzN4qvaP.js} +1 -1
- package/server/{feedback-writer-D4ULO4qG.js → feedback-writer-Ds1Wjsz4.js} +5 -5
- package/server/{flywheel-DXI_WITn.js → flywheel-BCZS-FlW.js} +1 -1
- package/server/{flywheel-BwYPDlhK.js → flywheel-CC4gE_rx.js} +15 -15
- package/server/{flywheel-C7yek87O.js → flywheel-DWKd7bMc.js} +79 -29
- package/server/{flywheel-merge-order-C5m5bYBc.js → flywheel-merge-order-DDT3i57u.js} +1 -1
- package/server/{flywheel-merge-order-CXfU4M6l.js → flywheel-merge-order-DJwH2KpL.js} +17 -15
- package/server/forge-4VVCRcF7.js +2 -0
- package/server/{forge-DYX9sKzG.js → forge-CHADjOFs.js} +2 -2
- package/server/{from-DAdMxC29.js → from-C3dzmjSO.js} +1 -1
- package/server/{fs-lock-cw25uO_E.js → fs-lock-DQ_gUxfq.js} +2 -2
- package/server/{fts-operations-D_rzLxX5.js → fts-operations-asZo2fh1.js} +3 -3
- package/server/git-info-DMOSfJ9I.js +148 -0
- package/server/{git-utils-Y0zG25ez.js → git-utils-BAMwn9Nf.js} +1 -1
- package/server/{git-utils-DV4B9TRl.js → git-utils-BdHk8y7g.js} +4 -4
- package/server/{github-app-C33lDk9Z.js → github-app-BWziYCf3.js} +1 -1
- package/server/{github-app-4UX8VIr8.js → github-app-BlMSzSTw.js} +2 -2
- package/server/{github-client-nPj5ckZO.js → github-client-OK24qpol.js} +1 -1
- package/server/{github-client-DkJVR908.js → github-client-w6j5nVlz.js} +3 -3
- package/server/{github-pr-lookup-C9Vokb0W.js → github-pr-lookup-bGcsEvLE.js} +2 -2
- package/server/{harness-binary-BgXYDo2Z.js → harness-binary-DChiynaB.js} +2 -2
- package/server/{harness-resolve-1NZcVx7n.js → harness-resolve-BplBEbwn.js} +4 -4
- package/server/{health-events-jMfxrElt.js → health-events-BTqsmunw.js} +1 -1
- package/server/{health-events-DlX_FVAB.js → health-events-Bk3LjaJ9.js} +2 -2
- package/server/{hooks-NQ19vvlB.js → hooks-DJR1yR9w.js} +2 -2
- package/server/{hooks-W3REcb3h.js → hooks-EndRNrx9.js} +1 -1
- package/server/{hume-BFkid2PO.js → hume-1FJmNDTq.js} +2 -2
- package/server/hume-gXLmRhmN.js +3 -0
- package/server/{identity-Bwh6VGeL.js → identity-C3s8lyp0.js} +3 -3
- package/server/{idle-stack-reaper-CHtCNpvd.js → idle-stack-reaper-CBelVOE3.js} +1 -1
- package/server/{idle-stack-reaper-BeU_KxWx.js → idle-stack-reaper-DtoI4al6.js} +4 -4
- package/server/{in-flight-guard-pcwXKLGz.js → in-flight-guard-B7khcBdQ.js} +1 -1
- package/server/{infra-KTp9KV9u.js → infra-CJRi_5Wu.js} +36 -7
- package/server/{injection-67YyU6SC.js → injection-ADWQ3D0s.js} +8 -8
- package/server/{injection-BxbZKPDh.js → injection-BWsgHvrL.js} +1 -1
- package/server/{inspect-agent-VHSihlb7.js → inspect-agent-CCfNJjKr.js} +12 -12
- package/server/inspect-agent-Dhp3hCGp.js +2 -0
- package/server/{internal-token-B-z-sGBH.js → internal-token-BCTEqUCX.js} +1 -1
- package/server/{internal-token-zY75jrRJ.js → internal-token-BeIWG_kT.js} +2 -2
- package/server/{io-DfvO2xyh.js → io-BCtZoXHo.js} +5 -5
- package/server/{issue-closed-dvEWKO7Q.js → issue-closed-CiYAa6bX.js} +7 -7
- package/server/{issue-lifecycle-3N8XF7lP.js → issue-lifecycle-BETNVVLq.js} +206 -29
- package/server/{issue-lifecycle-BI6jAfp8.js → issue-lifecycle-DaKN57sx.js} +1 -1
- package/server/{issue-service-singleton-CL6hESX2.js → issue-service-singleton-1Q0ER8Yc.js} +1 -1
- package/server/{issue-service-singleton-BN_2MXp4.js → issue-service-singleton-C_sZ0HjP.js} +124 -11
- package/server/issue-title-fallback-B91iD66g.js +120 -0
- package/server/{issues-CkvUoAnq.js → issues-RGHQUKhB.js} +2 -2
- package/server/{jsonl-parser-CrEb2PWr.js → jsonl-parser-Dfs1dlYE.js} +3 -3
- package/server/jsonl-resolver-bFtftCDd.js +324 -0
- package/server/{kimi-code-DoMoGqIu.js → kimi-code-BxkDgaj4.js} +1 -1
- package/server/{kimi-code-C26gmGxM.js → kimi-code-CNYRA8Dd.js} +14 -12
- package/server/{kimi-parser-Dmhy3UlR.js → kimi-parser-OcWwmOqF.js} +2 -2
- package/server/{label-cleanup-X2lWfghH.js → label-cleanup-CefxK9tL.js} +3 -3
- package/server/{lifecycle-B0rL38D3.js → lifecycle-DDZ7w-BY.js} +6 -6
- package/server/{lifecycle-Bg44O-9x.js → lifecycle-DVXyUil2.js} +2 -2
- package/server/{lifecycle-io-DQDU0apV.js → lifecycle-io-D1oBiMce.js} +1 -1
- package/server/{lifecycle-io-CCBpRv5m.js → lifecycle-io-D7N0vQNj.js} +5 -5
- package/server/{linear-client-B0cIkTs4.js → linear-client-DUN7zCeb.js} +3 -3
- package/server/{linear-client-6V2E-DSa.js → linear-client-TL32snOy.js} +1 -1
- package/server/{linear-mcp-auth-LCo9AWUd.js → linear-mcp-auth-CtRKSHy5.js} +1 -1
- package/server/{linear-mcp-auth-Dsu9Io9r.js → linear-mcp-auth-bB0CPyjh.js} +5 -5
- package/server/memory-fts-worker.js +1 -1
- package/server/{memory-governor-A4O6vI9d.js → memory-governor-Cvv_9K0M.js} +88 -22
- package/server/{memory-pressure-patrol-BWlWywmA.js → memory-pressure-patrol-C6DJJQRA.js} +38 -14
- package/server/{merge-BGWcBxku.js → merge-DOCR6pHi.js} +1 -1
- package/server/{merge-vz80RvSE.js → merge-FTk4LsnM.js} +3 -3
- package/server/{merge-agent-GWhmnxFk.js → merge-agent-C-dsN9se.js} +37 -33
- package/server/{merge-agent-BRSz26Oh.js → merge-agent-D-4_iQgy.js} +2 -2
- package/server/{merge-batch-CFMEtTxv.js → merge-batch-BJjzUUL7.js} +1 -1
- package/server/{merge-completeness-CP347umA.js → merge-completeness-BOtBUwTU.js} +4 -4
- package/server/{merge-completeness-7ajHAIR-.js → merge-completeness-CoLJxfUY.js} +1 -1
- package/server/merge-eligibility-C4rTS97F.js +3 -0
- package/server/merge-eligibility-D7wRnJbj.js +51 -0
- package/server/merge-ops-Cf02szJ5.js +2 -0
- package/server/merge-rebase-Bj7eJAG4.js +2 -0
- package/server/{merge-rebase-C5htyEEH.js → merge-rebase-KBw4rdh3.js} +2 -2
- package/server/{merge-set-DsGW8fmc.js → merge-set-CVfEM57p.js} +1 -1
- package/server/{merge-set-eiE2nC6C.js → merge-set-CyW-xSn4.js} +4 -4
- package/server/{merge-sync-CM2-myXu.js → merge-sync-CYGsJy0u.js} +1 -1
- package/server/{merge-sync-Ct0-cxMX.js → merge-sync-YLvOPAry.js} +2 -2
- package/server/{merge-train-BOu3fN7O.js → merge-train-VxLn8Ms4.js} +4 -4
- package/server/{merge-train-deps-LXHGK61n.js → merge-train-deps-D0y4hBB9.js} +4 -4
- package/server/{merge-verification-BRp08IzI.js → merge-verification-BfJRNMiD.js} +6 -6
- package/server/{merged-docker-cleanup-worker-CwldDjHV.js → merged-docker-cleanup-worker-Bh5fKG_b.js} +4 -4
- package/server/{merged-docker-cleanup-worker-C8eGn78a.js → merged-docker-cleanup-worker-Ci9oeFAe.js} +1 -1
- package/server/messaging-Dfbhgjd6.js +3 -0
- package/server/{multipart-parser-OAuW7824.js → multipart-parser-BYwfKOVU.js} +2 -2
- package/server/{no-resume-mode-MWI6pnrK.js → no-resume-mode-DjMQRkId.js} +1 -1
- package/server/node_modules/.package-lock.json +24 -24
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/AGENTS.md +14 -0
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/CLAUDE.md +14 -0
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/README.md +10 -3
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/ai-docs/package.json +2 -2
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/ai-docs/src/40_sql/10_basics.ts +175 -0
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/ai-docs/src/40_sql/index.md +6 -0
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/ai-docs/src/51_http-server/10_basics.ts +3 -1
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/ai-docs/src/51_http-server/20_testing.ts +100 -0
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/ai-docs/src/51_http-server/fixtures/api/Users.ts +30 -14
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/ai-docs/src/51_http-server/fixtures/domain/User.ts +15 -6
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/ai-docs/src/51_http-server/fixtures/server/Authorization.ts +11 -10
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/ai-docs/src/51_http-server/fixtures/server/Users/http.ts +41 -32
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/ai-docs/src/51_http-server/fixtures/server/Users.ts +141 -20
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/ai-docs/src/70_cli/10_basics.ts +31 -5
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeChildProcessSpawner.d.ts.map +1 -1
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeChildProcessSpawner.js +10 -9
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeChildProcessSpawner.js.map +1 -1
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeClusterSocket.d.ts.map +1 -1
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeClusterSocket.js +12 -9
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeClusterSocket.js.map +1 -1
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeSocket.js +1 -1
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeSocket.js.map +1 -1
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeSocketServer.js +4 -4
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeSocketServer.js.map +1 -1
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeStream.d.ts.map +1 -1
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeStream.js +10 -4
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeStream.js.map +1 -1
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/internal/nodeChildProcessSpawner.d.ts +4 -0
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/internal/nodeChildProcessSpawner.d.ts.map +1 -0
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/internal/nodeChildProcessSpawner.js +10 -0
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/internal/nodeChildProcessSpawner.js.map +1 -0
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/package.json +7 -7
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/src/NodeChildProcessSpawner.ts +16 -11
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/src/NodeClusterSocket.ts +15 -12
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/src/NodeSocket.ts +1 -1
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/src/NodeSocketServer.ts +4 -4
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/src/NodeStream.ts +10 -4
- package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/src/internal/nodeChildProcessSpawner.ts +16 -0
- package/server/node_modules/@types/node/README.md +1 -1
- package/server/node_modules/@types/node/buffer.buffer.d.ts +5 -5
- package/server/node_modules/@types/node/crypto.d.ts +2 -2
- package/server/node_modules/@types/node/http.d.ts +16 -0
- package/server/node_modules/@types/node/http2.d.ts +10 -2
- package/server/node_modules/@types/node/package.json +2 -2
- package/server/node_modules/@types/node/process.d.ts +52 -0
- package/server/node_modules/@types/node/quic.d.ts +210 -28
- package/server/node_modules/@types/node/sqlite.d.ts +6 -2
- package/server/node_modules/@types/node/test.d.ts +36 -0
- package/server/node_modules/ansi-regex/index.js +3 -2
- package/server/node_modules/ansi-regex/package.json +1 -1
- package/server/node_modules/effect/node_modules/uuid/README.md +19 -19
- package/server/node_modules/effect/node_modules/uuid/dist/v1.js +7 -3
- package/server/node_modules/effect/node_modules/uuid/dist/v7.js +5 -2
- package/server/node_modules/effect/node_modules/uuid/dist-node/v1.js +7 -3
- package/server/node_modules/effect/node_modules/uuid/dist-node/v7.js +5 -2
- package/server/node_modules/effect/node_modules/uuid/package.json +4 -3
- package/server/node_modules/gaxios/build/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/server/node_modules/gaxios/build/esm/tsconfig.tsbuildinfo +1 -1
- package/server/node_modules/gaxios/package.json +3 -3
- package/server/node_modules/msgpackr/dist/index-no-eval.cjs +11 -5
- package/server/node_modules/msgpackr/dist/index-no-eval.cjs.map +1 -1
- package/server/node_modules/msgpackr/dist/index-no-eval.min.js +1 -1
- package/server/node_modules/msgpackr/dist/index-no-eval.min.js.map +1 -1
- package/server/node_modules/msgpackr/dist/index.js +11 -5
- package/server/node_modules/msgpackr/dist/index.js.map +1 -1
- package/server/node_modules/msgpackr/dist/index.min.js +1 -1
- package/server/node_modules/msgpackr/dist/index.min.js.map +1 -1
- package/server/node_modules/msgpackr/dist/node.cjs +11 -5
- package/server/node_modules/msgpackr/dist/node.cjs.map +1 -1
- package/server/node_modules/msgpackr/dist/test.js +11 -5
- package/server/node_modules/msgpackr/dist/test.js.map +1 -1
- package/server/node_modules/msgpackr/dist/unpack-no-eval.cjs +11 -5
- package/server/node_modules/msgpackr/dist/unpack-no-eval.cjs.map +1 -1
- package/server/node_modules/msgpackr/package.json +1 -1
- package/server/node_modules/msgpackr/unpack.js +11 -5
- package/server/node_modules/picomatch/lib/parse.js +10 -1
- package/server/node_modules/picomatch/lib/scan.js +30 -18
- package/server/node_modules/picomatch/package.json +1 -1
- package/server/{orphan-proposed-reconciler-BAE5AZ_e.js → orphan-proposed-reconciler-CnP0K2v3.js} +2 -2
- package/server/{orphan-proposed-reconciler-cV3URUqk.js → orphan-proposed-reconciler-nFUlquZt.js} +24 -23
- package/server/package-lock.json +25 -25
- package/server/package.json +1 -1
- package/server/{pan-dir-DDd91kMb.js → pan-dir-B4NfzOf3.js} +5 -5
- package/server/{deacon-merge-BOGFEV8_.js → parked-residue-8WbU0y1z.js} +188 -69
- package/server/{paths-CRLnDgcI.js → paths-rETQhTF2.js} +2 -2
- package/server/{pending-lifecycle-claim-CYgMiDAP.js → pending-lifecycle-claim-yAwDuGS4.js} +2 -2
- package/server/{pickup-BjJsSX12.js → pickup-Dle6k9Xt.js} +1 -1
- package/server/{pipeline-agent-reader-BLc43dVJ.js → pipeline-agent-reader-CeWhQzXC.js} +5 -5
- package/server/{pipeline-membership-BHZp_ShY.js → pipeline-membership-BV4hdkHm.js} +1 -1
- package/server/{pipeline-membership-5qlRz5Qg.js → pipeline-membership-C9ykcjsn.js} +1 -1
- package/server/{pipeline-membership-gather-CGFY1v-y.js → pipeline-membership-gather-Ba0wJNCR.js} +17 -12
- package/server/{pipeline-membership-gather-WhRc1yke.js → pipeline-membership-gather-C9E22B2W.js} +1 -1
- package/server/{pipeline-notifier-C4fZ2ito.js → pipeline-notifier-B5DPXvnr.js} +1 -1
- package/server/{pipeline-notifier-BmsLWM_2.js → pipeline-notifier-p190L97e.js} +2 -2
- package/server/{post-merge-lifecycle-worker-KK1RTKRE.js → post-merge-lifecycle-worker-OQoK8Ckg.js} +3 -3
- package/server/{post-merge-state-_Lj3LDLh.js → post-merge-state-DFaf7OI1.js} +4 -4
- package/server/prd-locations-F2oLSAhy.js +124 -0
- package/server/{project-pipelines-CCkebHOu.js → project-pipelines-CUsa6U59.js} +2 -2
- package/server/project-repos-BVdi9-ch.js +3 -0
- package/server/{project-repos-B4MK48j4.js → project-repos-CsfvLtmr.js} +29 -3
- package/server/project-resource-refresh-queue-BehrH4Ai.js +865 -0
- package/server/project-resource-refresh-queue-D2110Guc.js +2 -0
- package/server/{projects-DvPEAP18.js → projects-BMuEf14J.js} +1 -1
- package/server/{prompts-BiS5I2tZ.js → prompts-CKpDt8Jn.js} +2 -2
- package/server/providers-Buv2wmFU.js +3 -0
- package/server/{providers-DrfK0Ip8.js → providers-CxPKmyif.js} +7 -7
- package/server/public/assets/{chunk-BO2N2NFS-GtVe_o56.js → chunk-BO2N2NFS-DZOQVqV1.js} +4 -4
- package/server/public/assets/{diagram-OG6HWLK6-BvhcYYHc.js → diagram-OG6HWLK6-oKeXcbO1.js} +1 -1
- package/server/public/assets/{dist-CSmUXazd.js → dist-2qPmeRzT.js} +3 -3
- package/server/public/assets/{dist-D0ryefak.js → dist-ClBlE-Nm.js} +1 -1
- package/server/public/assets/{ganttDiagram-6RSMTGT7-BXA51DzM.js → ganttDiagram-6RSMTGT7-BwdG9fQv.js} +1 -1
- package/server/public/assets/{highlighted-body-OFNGDK62-mlV4EpWt.js → highlighted-body-OFNGDK62-BzGNdskQ.js} +1 -1
- package/server/public/assets/index-CdPveU3M.css +1 -0
- package/server/public/assets/index-Cg6tdZoY.js +860 -0
- package/server/public/assets/{linear-BPE7oswm.js → linear-DpEt1TJb.js} +1 -1
- package/server/public/assets/mermaid-GHXKKRXX-6KBD_3T_.js +1 -0
- package/server/public/assets/{pieDiagram-4H26LBE5-BguGGV3S.js → pieDiagram-4H26LBE5-9BpM4oRJ.js} +1 -1
- package/server/public/assets/{prod-aKDYUrXQ.js → prod-CzJiNNEG.js} +4 -4
- package/server/public/assets/{quadrantDiagram-W4KKPZXB-Bx3i4B6H.js → quadrantDiagram-W4KKPZXB-BXWVAoZx.js} +1 -1
- package/server/public/assets/{sankeyDiagram-5OEKKPKP-B5vuLjA4.js → sankeyDiagram-5OEKKPKP-5oxodGEw.js} +1 -1
- package/server/public/assets/{xychartDiagram-2RQKCTM6-HPlpkqsN.js → xychartDiagram-2RQKCTM6-BChDrHxZ.js} +1 -1
- package/server/public/index.html +2 -2
- package/server/pull-requests-CmlandI7.js +2 -0
- package/server/{pull-requests-BcHIsFJv.js → pull-requests-T0OV0Vn4.js} +3 -3
- package/server/{rally-B1OMtzch.js → rally-CUqj2oIN.js} +3 -3
- package/server/rally-DYIn9R2U.js +3 -0
- package/server/{rally-api-ShZ4kvn0.js → rally-api-BFPb2oSq.js} +2 -2
- package/server/{rally-api-u_vkr5c_.js → rally-api-BoucQG1u.js} +1 -1
- package/server/{rally-client-D6Feq1Ka.js → rally-client-16iObny7.js} +5 -5
- package/server/{rally-client-DgZvUZqX.js → rally-client-CsqLjLLa.js} +1 -1
- package/server/{reap-terminal-sessions-CRfiXLY0.js → reap-terminal-sessions-BaDSNR-k.js} +2 -2
- package/server/{reap-terminal-sessions-D7f3zSE9.js → reap-terminal-sessions-DgEIKMhH.js} +2 -2
- package/server/{rebuild-stack-CCwKHZb6.js → rebuild-stack-BcBVFJp3.js} +2 -2
- package/server/{rebuild-stack-DKxOnkpE.js → rebuild-stack-CyXMrj6K.js} +7 -7
- package/server/reconciler-caYiRnPy.js +657 -0
- package/server/{reconstruct-cache-BP8UIKt7.js → reconstruct-cache-3JzPOune.js} +7 -7
- package/server/{record-By-wp6pg.js → record-DYOg97Iv.js} +1 -1
- package/server/{record-update-D23jPU6b.js → record-update-BPqpBu3O.js} +9 -7
- package/server/{record-update-ByGtIlUK.js → record-update-CDPEX7BH.js} +1 -1
- package/server/{recovery-trip-C4dTl8DO.js → recovery-trip-CpfW6LCJ.js} +43 -10
- package/server/{recovery-trip-qloOYOFz.js → recovery-trip-xqKC07Gy.js} +1 -1
- package/server/{release-engine-Crc0Tjx-.js → release-engine-C_OOhCaK.js} +5 -5
- package/server/{release-set-DDXwbIK7.js → release-set-DOIDz2vw.js} +3 -3
- package/server/{remote-oEMfXlwT.js → remote-BTh-sjpX.js} +3 -3
- package/server/{remote-agents-Bgtc2nOO.js → remote-agents-DbbN7vSm.js} +6 -6
- package/server/{remote-agents-DQVGZVQ9.js → remote-agents-MuXx2gWm.js} +1 -1
- package/server/{remote-completion-DxUJ5HKR.js → remote-completion-LcWCpAm2.js} +13 -13
- package/server/{remote-CBpLi4Yy.js → remote-xY0B43Ho.js} +3 -3
- package/server/{resolver-CuAULbLs.js → resolver-C2QKOf09.js} +2 -2
- package/server/{resolver-C8rooxoz.js → resolver-D4nsxfGo.js} +31 -8
- package/server/resume-ByUrJUNX.js +3 -0
- package/server/{review-agent-7C2w5CzU.js → review-agent-BRBTm1qE.js} +43 -55
- package/server/review-agent-Caodi0PX.js +3 -0
- package/server/{review-artifacts-BJeEfm2r.js → review-artifacts-DgaDlbO4.js} +6 -6
- package/server/{review-convoy-liveness-DfF9eXjI.js → review-convoy-liveness-BBvyuRLC.js} +20 -11
- package/server/{review-run-recovery-ZjuDTNhZ.js → review-run-recovery-DCzWMMvE.js} +1 -1
- package/server/{review-run-recovery-7BKt2Es0.js → review-run-recovery-THHMKlXJ.js} +3 -3
- package/server/{review-status-CUnjjOUu.js → review-status-Bge_3XTR.js} +1 -1
- package/server/{review-status-DBnR5t4z.js → review-status-DpniqzPT.js} +113 -44
- package/server/{review-status-emit-Cg4tOb8U.js → review-status-emit-D7sM720S.js} +3 -3
- package/server/{review-status-enrichment-D-rQshu6.js → review-status-enrichment-PDI4-faj.js} +3 -3
- package/server/{review-status-source-DSn0glLa.js → review-status-source-D2PCWS6E.js} +1 -1
- package/server/{review-status-source-Ct912fv_.js → review-status-source-Jq0BXmn3.js} +1 -1
- package/server/{review-status-sync-B7V_Gg51.js → review-status-sync-C6ZKTI8f.js} +11 -8
- package/server/{review-status-sync-YthpOH_q.js → review-status-sync-CvpHWyvR.js} +1 -1
- package/server/{review-verdict-feedback-C-dBon_-.js → review-verdict-feedback-B2ojHFH5.js} +8 -8
- package/server/{review-verdict-feedback-DqXTuJk8.js → review-verdict-feedback-tyMoLT2L.js} +1 -1
- package/server/{review-verdict-writer-CKaJWp75.js → review-verdict-writer-Cy_1pnIj.js} +7 -7
- package/server/{review-verdict-writer-jldSh3Bm.js → review-verdict-writer-DjrJ64eS.js} +1 -1
- package/server/{rollup-DZwH4CLs.js → rollup-Cp0KEoOu.js} +1 -1
- package/server/{rollup-QCwYcBdP.js → rollup-DU3xBQu2.js} +8 -8
- package/server/{scanner-2aHeLC3W.js → scanner-BFKG3Gxv.js} +8 -8
- package/server/{search-DwHYaj66.js → search-DhtKwbBC.js} +2 -2
- package/server/{secret-redaction-B5G1xZ3k.js → secret-redaction-DLZ-VqHq.js} +1 -1
- package/server/{sequence-io-POKWdusG.js → sequence-io-C-Q19Jez.js} +4 -4
- package/server/{sequencer-agent-DS00KHVm.js → sequencer-agent-eN2P2lDz.js} +6 -6
- package/server/server.js +1499 -1350
- package/server/{service-BLb_CyPL.js → service-CThO0Sar.js} +80 -774
- package/server/{session-fork-DcTzVwex.js → session-fork-ZYTHtpBh.js} +2 -2
- package/server/settings-ByDRfuuE.js +2 -0
- package/server/{settings-Clw8UVNs.js → settings-CTywpFw5.js} +2 -2
- package/server/{settings-B9-H2K_E.js → settings-nAT-eK56.js} +3 -3
- package/server/{shadow-engineering-C6oO_PiR.js → shadow-engineering-BHZKPJhq.js} +3 -3
- package/server/{shadow-state-CEGrrECe.js → shadow-state-BTLi4Axs.js} +2 -2
- package/server/{shadow-state-e7250VUx.js → shadow-state-CZ_LnPsi.js} +1 -1
- package/server/{shadow-utils-xFk2Wusb.js → shadow-utils-CPLlPHdn.js} +2 -2
- package/server/{ship-log-7BnQHuKU.js → ship-log-D-CphNZx.js} +1 -1
- package/server/{ship-record-CwUX6Afo.js → ship-record-BaBla0l_.js} +7 -7
- package/server/{ship-record-BgUPnpT0.js → ship-record-BlvX8-xv.js} +1 -1
- package/server/{ship-status-Ce3_3edi.js → ship-status-rQbPQBsF.js} +2 -2
- package/server/{smart-compaction-BmfIi3oL.js → smart-compaction-CUXn8mfX.js} +1 -1
- package/server/{smart-compaction-Dy0gw1VH.js → smart-compaction-D1CNGdZx.js} +7 -7
- package/server/{spawn-planning-session-nH3b4Drz.js → spawn-planning-session-DCmO6COk.js} +19 -19
- package/server/{spawn-planning-session-CfhxRJoY.js → spawn-planning-session-DfEWyrVV.js} +2 -2
- package/server/{specialist-completion-CC1XJbTx.js → specialist-completion-BMv3K54P.js} +1 -1
- package/server/{specialist-context-cHwpcXSh.js → specialist-context-C1-CfYQb.js} +5 -5
- package/server/{specialist-handoff-logger-GqnGSYoJ.js → specialist-handoff-logger-BDKoz5Z9.js} +2 -2
- package/server/{specialist-logs-5OTnrV91.js → specialist-logs-BJQFkpdG.js} +3 -3
- package/server/specialists-CYt1U3Zm.js +4 -0
- package/server/{specialists-8LcQi9Np.js → specialists-D6MUU31Q.js} +21 -272
- package/server/{specialists-DocAK-7A.js → specialists-DhS79T9v.js} +369 -691
- package/server/{specialists-xXcJHAyg.js → specialists-Dx0zRTxX.js} +1 -1
- package/server/specialists-registry-BRLCi61y.js +3 -0
- package/server/specialists-registry-Bng0OFGH.js +277 -0
- package/server/specs-oRGyfz6C.js +3 -0
- package/server/{src-C2TAxwki.js → src-C7gGe4KU.js} +6 -6
- package/server/{src-DudQNYVw.js → src-CdwN6WY6.js} +344 -7
- package/server/{src-DUVvEA8Q.js → src-DMosbuSJ.js} +3 -3
- package/server/{stack-health-DKT4ySnA.js → stack-health-BKfNaqMm.js} +3 -3
- package/server/{stack-health-CbyiYS9H.js → stack-health-Bz711z1Y.js} +1 -1
- package/server/{stale-task-claims-PzFee70R.js → stale-task-claims-DMRLb5R2.js} +5 -5
- package/server/{staleness-D8UTEXV5.js → staleness-CxZaIhrn.js} +1 -1
- package/server/{staleness-BjOAq9-d.js → staleness-r_dkMyMG.js} +1 -1
- package/server/{stall-sweeper-DOyIfeLR.js → stall-sweeper-CBWqSWV2.js} +8 -8
- package/server/{state-home-DhAZlk5k.js → state-home-DhsMqg8W.js} +2 -2
- package/server/{state-mapping-BVSs84bO.js → state-mapping-D2yC81Vy.js} +1 -1
- package/server/{state-migrate-CJKEwpB0.js → state-migrate-C2Ouyd6e.js} +6 -6
- package/server/{state-mirror-Do7pag7W.js → state-mirror-BPXciz84.js} +3 -3
- package/server/stuck-remediation-DALieAkx.js +2 -0
- package/server/stuck-remediation-kta3KN7c.js +774 -0
- package/server/{substrate-bug-weights-service-BTNjHBnl.js → substrate-bug-weights-service-D_ICP7TI.js} +3 -3
- package/server/{summary-fork-CvB7Oyq9.js → summary-fork-CojrFKb6.js} +2 -2
- package/server/{summary-fork-CZ88rhVx.js → summary-fork-DhhaFhxZ.js} +113 -30
- package/server/supervisor/{pane-composer-BaLLspSj.js → pane-composer-CoiVkGIt.js} +8 -1
- package/server/supervisor/{paths-D6XUcR_g.js → paths-DTGbtcaP.js} +8 -4
- package/server/supervisor/pty-supervisor.js +3 -3
- package/server/supervisor/{pty-token-DjjHxoCq.js → pty-token-GVqnvU3U.js} +2 -2
- package/server/supervisor-DSSWo4M2.js +2 -0
- package/server/{supervisor-D4v0WfiQ.js → supervisor-DqH-laVL.js} +4 -4
- package/server/{swarm-readiness-D8R-LWX5.js → swarm-readiness-LF8ZF_hc.js} +3 -3
- package/server/{synthesis-verdict-N5Z11pg7.js → synthesis-verdict-CGFF8uQI.js} +2 -2
- package/server/{synthesis-verdict-B6wvLGcA.js → synthesis-verdict-DSoOFUIV.js} +1 -1
- package/server/{system-prerequisites-BbGZ_WHF.js → system-prerequisites-Lsx0jUUV.js} +2 -2
- package/server/{teardown-workspace-CYend-KY.js → teardown-workspace-DMwomEG1.js} +16 -16
- package/server/{test-agent-queue-BUtWhNcc.js → test-agent-queue-Cu0D6BYe.js} +6 -6
- package/server/{test-verdict-BWm3hgDj.js → test-verdict-9mvl7pQn.js} +1 -1
- package/server/{test-verdict-BWtRmdiR.js → test-verdict-oNSv1rVr.js} +2 -2
- package/server/{tldr-daemon-CneJ24eL.js → tldr-daemon-CRSAkhBx.js} +1 -1
- package/server/{tldr-daemon-CMVBT4kT.js → tldr-daemon-McqCk2X7.js} +2 -2
- package/server/tmux-CYucGrTl.js +4 -0
- package/server/{tmux-BqXzRuaH.js → tmux-wnT_hg-s.js} +91 -19
- package/server/{token-CO3INKbh.js → token-BdfZLRg1.js} +2 -2
- package/server/{token-util-DyJJyX_B.js → token-util-Crcay9j_.js} +1 -1
- package/server/token-util-DfUS3Lpp.js +3 -0
- package/server/{tracker-config-DVzhaUxO.js → tracker-config-tfAOWgng.js} +2 -2
- package/server/{tracker-utils-xnVJVrrO.js → tracker-utils-Dbg_pVZg.js} +2 -2
- package/server/{traefik-connect-A5k54mCv.js → traefik-connect-DoQvQ6oJ.js} +1 -1
- package/server/{tunnel-DauSR-rs.js → tunnel-B1MNIgkL.js} +1 -1
- package/server/{tunnel-CwOnS-PB.js → tunnel-skW68j9B.js} +3 -3
- package/server/{typed-errors-B-gfU2RB.js → typed-errors-CZ3GFBvo.js} +1 -1
- package/server/{typed-errors-DzC4zXbI.js → typed-errors-DXqf3RnP.js} +1 -1
- package/server/{types-DjpLVpsj.js → types-PW4zkxCM.js} +1 -1
- package/server/{types-DbxY2QB6.js → types-pLpbsNto.js} +1 -1
- package/server/{uat-failure-feedback-BVqsWlrr.js → uat-failure-feedback-ly8ZwtfC.js} +5 -5
- package/server/{uat-promote-verification-DmG097QS.js → uat-promote-verification-BBaMwfdc.js} +5 -5
- package/server/{uat-train-DVUNW03P.js → uat-train-BBEiYSep.js} +0 -0
- package/server/{uat-train-COSy-vEX.js → uat-train-D7Ran2FB.js} +1 -1
- package/server/{validate-Dvv83iBx.js → validate-BYcBcBwg.js} +3 -3
- package/server/{validation-DlHafKzu.js → validation-BfG2jW5C.js} +9 -6
- package/server/{validation-BdCjzWLN.js → validation-nSrYiYvA.js} +1 -1
- package/server/{verification-artifact-CaSbxUVg.js → verification-artifact-Cmhgq4b_.js} +1 -1
- package/server/{verification-artifact-0Zku8N-W.js → verification-artifact-DglwaHke.js} +1 -1
- package/server/{verification-runner-DwP2fUEF.js → verification-runner-BEq5ZF-h.js} +53 -27
- package/server/{verification-runner-C6wdZda2.js → verification-runner-CFjAuv9u.js} +1 -1
- package/server/{vtt-parser-luerJpYT.js → vtt-parser-Va--tv27.js} +1 -1
- package/server/work-agent-prompt-BnhKNAg7.js +3 -0
- package/server/{work-agent-prompt--9AWNYwZ.js → work-agent-prompt-CaD2ue8m.js} +14 -14
- package/server/{work-agent-start-BNQO65W7.js → work-agent-start-0nJ-6UeA.js} +2 -2
- package/server/{work-agent-start-DkzseQFl.js → work-agent-start-D8NEN5KD.js} +1 -1
- package/server/workflows-BtHRlFIm.js +2 -0
- package/server/{workflows-BYwR2aIN.js → workflows-C7mxM1qc.js} +114 -41
- package/server/{workspace-iTnTycOB.js → workspace-BAhMgMaO.js} +3 -3
- package/server/{workspace-B-QJa3Ps.js → workspace-Dbqv9ehn.js} +1 -1
- package/server/{workspace-anchor-drift-CHiGg8iu.js → workspace-anchor-drift-B_3kyyxJ.js} +4 -4
- package/server/{workspace-anchor-drift-DTt6h2Em.js → workspace-anchor-drift-Bpa3xoni.js} +1 -1
- package/server/{workspace-config-D0CavVtz.js → workspace-config-D-bNq2CF.js} +1 -1
- package/server/{workspace-manager-5BKPV6SY.js → workspace-manager-BrbX90Rm.js} +1 -1
- package/server/{workspace-manager-W1OnbvU5.js → workspace-manager-CM8RCrSc.js} +17 -17
- package/server/{workspace-metadata-tbbevEmP.js → workspace-metadata-BEOwJSdK.js} +1 -1
- package/server/{workspace-metadata-dJhXvZGQ.js → workspace-metadata-Cu6yfxBS.js} +2 -2
- package/server/{workspaces-BlpbOPZ7.js → workspaces-C7LAuZfe.js} +140 -709
- package/sync-sources/dev-skills/pan-style-guide/SKILL.md +90 -15
- package/sync-sources/hooks/linear-mcp-auth-hook +6 -1
- package/sync-sources/rules/agent-message-delivery.md +21 -14
- package/sync-sources/rules/handoff-isolate-cwd.md +4 -4
- package/sync-sources/rules/pan-handoff-focus-limit.md +14 -5
- package/sync-sources/rules/ste-writing.md +17 -0
- package/sync-sources/rules/work-agents-via-pan.md +2 -1
- package/sync-sources/rules/writing-style.md +3 -2
- package/sync-sources/skills/{skill-creator → claude-skill-creator}/SKILL.md +1 -1
- package/sync-sources/skills/{skill-creator → claude-skill-creator}/scripts/init_skill.py +1 -1
- package/sync-sources/skills/{skill-creator → claude-skill-creator}/scripts/package_skill.py +1 -1
- package/sync-sources/skills/pan-gauntlet-loop/SKILL.md +230 -0
- package/sync-sources/skills/pan-gauntlet-loop/assets/PROMPT.template.md +92 -0
- package/sync-sources/skills/pan-gauntlet-loop/assets/REFERENCE-BAR.template.md +53 -0
- package/sync-sources/skills/pan-gauntlet-loop/assets/STYLE.template.md +41 -0
- package/sync-sources/skills/pan-gauntlet-loop/assets/gauntlet-index.html +237 -0
- package/sync-sources/skills/pan-gauntlet-loop/references/domains.md +106 -0
- package/sync-sources/skills/pan-handoff/SKILL.md +24 -6
- package/sync-sources/skills/pan-help/SKILL.md +1 -1
- package/sync-sources/skills/pan-peer-review/SKILL.md +3 -3
- package/sync-sources/skills/pan-restart/SKILL.md +6 -3
- package/sync-sources/skills/pan-start/SKILL.md +3 -0
- package/sync-sources/skills/pan-swarm/SKILL.md +32 -44
- package/sync-sources/skills/pan-sync/SKILL.md +1 -1
- package/server/activity-logger-BejO16Am.js +0 -3
- package/server/agent-state-DH_-Jkua.js +0 -3
- package/server/agents-megfmQHM.js +0 -3
- package/server/archive-planning-C-H9cM_J.js +0 -2
- package/server/build-info-PQlh_Rhb.js +0 -2
- package/server/cli-TaZspPHS.js +0 -2
- package/server/cliproxy-36ncAXlu.js +0 -3
- package/server/context-layers-CF6zHws4.js +0 -4
- package/server/conversations-AnGJ5rtX.js +0 -3
- package/server/deacon-BEH-IY0v.js +0 -5
- package/server/deacon-swarm-BHX-kR1b.js +0 -2
- package/server/deacon-swarm-BiLfNm_v.js +0 -1522
- package/server/dead-end-trip-BWpDg1Qd.js +0 -2
- package/server/delivery-cJM6zRjJ.js +0 -3
- package/server/deploy-queue-CmVBZEja.js +0 -2
- package/server/dist-VKBfkdi7.js +0 -3
- package/server/durable-review-pipeline-DgcVCYDL.js +0 -3
- package/server/factory-D4V2wd_V.js +0 -717
- package/server/forge-CrP1L3i6.js +0 -2
- package/server/hume-1ubD_6O7.js +0 -3
- package/server/inspect-agent-CfxERkNt.js +0 -2
- package/server/merge-ops-DtHx17Vd.js +0 -2
- package/server/merge-rebase-BvB4UuNS.js +0 -2
- package/server/project-repos-BJiShUsN.js +0 -3
- package/server/providers-CStNGwze.js +0 -3
- package/server/public/assets/index-BFEwfmqX.js +0 -860
- package/server/public/assets/index-_USwyTAT.css +0 -1
- package/server/public/assets/mermaid-GHXKKRXX-Dsln95SK.js +0 -1
- package/server/pull-requests-C1Cqp2yo.js +0 -2
- package/server/rally-CjayjUIl.js +0 -3
- package/server/resume-D7JuMCRQ.js +0 -3
- package/server/review-agent-BUNTVJK2.js +0 -2
- package/server/settings-DBWB1gsG.js +0 -2
- package/server/specialists-D8gsOCwh.js +0 -3
- package/server/specs-BqkrRnU9.js +0 -3
- package/server/stuck-remediation-Di5JYkoo.js +0 -1164
- package/server/stuck-remediation-TNM1VhZb.js +0 -2
- package/server/supervisor-DX8VsPnb.js +0 -2
- package/server/tmux-CqNapnrr.js +0 -4
- package/server/token-util-Bu8bPF9f.js +0 -3
- package/server/workflows-Cf4LAnhg.js +0 -2
|
@@ -1,1522 +0,0 @@
|
|
|
1
|
-
import { E as init_tier_table, It as isStatePlaneOnlyStatus, J as getProjectConfigFromWorkspacePath, K as getIssueRecordPathForWorkspace, Mt as init_state_plane, O as resolveTieredExecutionEnabled, On as resolveProjectFromIssueSync, Y as init_record, et as readIssueRecordForWorkspaceSync, fn as init_projects, on as getProjectSync, p as loadConfigSync, rt as resolveProjectForIssue, t as init_config_yaml, tt as readIssueRecordSync, vn as listProjectsSync } from "./config-yaml-BwOEANMr.js";
|
|
2
|
-
import { a as updateIssueRecord, i as init_record_update, o as updateIssueRecordForWorkspace } from "./record-update-D23jPU6b.js";
|
|
3
|
-
import { A as listSessionNames, B as sessionExists, O as listPaneValues, S as init_tmux, r as capturePane, w as isPaneDead } from "./tmux-BqXzRuaH.js";
|
|
4
|
-
import { $ as loadPrdDraft, Dr as resolveTier, Er as init_resolve_tier, Fn as getConcurrencyLimits, Gn as getCachedMemoryVerdict, In as init_concurrency, Kn as init_memory_verdict_cache, Lt as init_messaging, Mn as countRunningSwarmSlotsForIssue, Q as init_tier_supervisor, Qt as init_spawn, Rn as releaseSwarmSlot, Rt as messageAgent, Si as init_agent_runtime, Vn as tryReserveSwarmSlot, Z as deliverCommitForReview, _r as defaultRunWorkspace, ct as listSlotAssignments, d as getAgentResumeGateBlockReason, en as spawnRun, et as shouldSupervise, h as init_agent_state, ht as init_pending_decision_gate, in as stopAgent, it as init_tier_feed, l as decideResumeGate, lt as reconcileSlotState, m as getAgentStateSync, mt as detectPendingOperatorDecision, nt as supervisorAgentId, rn as init_termination, rt as broadcastCommit, st as init_slot_reconcile, tt as spawnTierSupervisor, u as getAgentDir, vr as init_spawn_prep, xi as getAgentRuntimeSnapshot } from "./agent-state-Bb3UUxQm.js";
|
|
5
|
-
import { c as init_control_settings, d as isDeaconGloballyPausedSync } from "./control-settings-5k6ixdFW.js";
|
|
6
|
-
import { C as init_specs, S as findSpecByIssue, b as subItemsOf, f as readPlanSync, i as findPlanSync, n as applyStatusOverrides, s as init_io, y as init_types } from "./io-DfvO2xyh.js";
|
|
7
|
-
import { i as createActiveSlice, l as init_dag, n as blockingParentCount, o as getDispatchableItems } from "./dag-DI9LaK_q.js";
|
|
8
|
-
import { a as loadCloisterConfigSync, r as init_config } from "./config-DC75T4Mr.js";
|
|
9
|
-
import { r as init_swarm_readiness, t as analyzeSwarmReadiness } from "./swarm-readiness-D8R-LWX5.js";
|
|
10
|
-
import { d as getReviewStatusSync, p as init_review_status, w as setReviewStatusSync } from "./review-status-DBnR5t4z.js";
|
|
11
|
-
import { i as recordRecoveryFailure, r as init_recovery_trip, t as acknowledgeRecoveryTrip } from "./recovery-trip-C4dTl8DO.js";
|
|
12
|
-
import { basename, join } from "node:path";
|
|
13
|
-
import { Effect } from "effect";
|
|
14
|
-
import { existsSync, readdirSync } from "fs";
|
|
15
|
-
import { join as join$1 } from "path";
|
|
16
|
-
import { hostname } from "node:os";
|
|
17
|
-
import { existsSync as existsSync$1 } from "node:fs";
|
|
18
|
-
import { exec } from "node:child_process";
|
|
19
|
-
import { promisify } from "node:util";
|
|
20
|
-
//#region ../../lib/agents/slot-merge.ts
|
|
21
|
-
init_projects();
|
|
22
|
-
init_record();
|
|
23
|
-
init_tier_table();
|
|
24
|
-
init_config_yaml();
|
|
25
|
-
init_tmux();
|
|
26
|
-
init_agent_runtime();
|
|
27
|
-
init_control_settings();
|
|
28
|
-
init_specs();
|
|
29
|
-
init_types();
|
|
30
|
-
init_io();
|
|
31
|
-
init_dag();
|
|
32
|
-
init_config();
|
|
33
|
-
init_memory_verdict_cache();
|
|
34
|
-
init_concurrency();
|
|
35
|
-
init_termination();
|
|
36
|
-
init_spawn();
|
|
37
|
-
init_agent_state();
|
|
38
|
-
init_spawn_prep();
|
|
39
|
-
const execAsync$3 = promisify(exec);
|
|
40
|
-
async function verifyAndMergeSlot(issue, slotIndex, item, options = {}) {
|
|
41
|
-
const issueId = typeof issue === "string" ? issue : issue.issueId;
|
|
42
|
-
const featureWorkspace = typeof issue === "string" ? defaultRunWorkspace(issue) : issue.featureWorkspace ?? defaultRunWorkspace(issue.issueId);
|
|
43
|
-
const slotWorkspace = `${featureWorkspace}-slot-${slotIndex}`;
|
|
44
|
-
const slotBranch = `feature/${issueId.toLowerCase()}-slot-${slotIndex}`;
|
|
45
|
-
const deps = {
|
|
46
|
-
run: async (command, cwd) => execAsync$3(command, { cwd }),
|
|
47
|
-
...options.deps
|
|
48
|
-
};
|
|
49
|
-
const verifyCommands = item.metadata?.verify_commands ?? [];
|
|
50
|
-
const expectedOutputs = item.metadata?.expected_outputs ?? [];
|
|
51
|
-
const evidence = {
|
|
52
|
-
verifyCommands,
|
|
53
|
-
expectedOutputs,
|
|
54
|
-
commandOutputs: []
|
|
55
|
-
};
|
|
56
|
-
if (!Number.isInteger(slotIndex) || slotIndex < 1) return {
|
|
57
|
-
verified: false,
|
|
58
|
-
merged: false,
|
|
59
|
-
conflicts: false,
|
|
60
|
-
evidence,
|
|
61
|
-
failure: `Invalid slot index: ${slotIndex}`
|
|
62
|
-
};
|
|
63
|
-
if (verifyCommands.length === 0) return {
|
|
64
|
-
verified: false,
|
|
65
|
-
merged: false,
|
|
66
|
-
conflicts: false,
|
|
67
|
-
evidence,
|
|
68
|
-
failure: `Item ${item.id} has no verify_commands`
|
|
69
|
-
};
|
|
70
|
-
if (expectedOutputs.length === 0) return {
|
|
71
|
-
verified: false,
|
|
72
|
-
merged: false,
|
|
73
|
-
conflicts: false,
|
|
74
|
-
evidence,
|
|
75
|
-
failure: `Item ${item.id} has no expected_outputs`
|
|
76
|
-
};
|
|
77
|
-
for (const command of verifyCommands) try {
|
|
78
|
-
const output = await deps.run(command, slotWorkspace);
|
|
79
|
-
evidence.commandOutputs.push({
|
|
80
|
-
command,
|
|
81
|
-
stdout: output.stdout,
|
|
82
|
-
stderr: output.stderr
|
|
83
|
-
});
|
|
84
|
-
} catch (error) {
|
|
85
|
-
const failed = commandFailure(error);
|
|
86
|
-
evidence.commandOutputs.push({
|
|
87
|
-
command,
|
|
88
|
-
stdout: failed.stdout,
|
|
89
|
-
stderr: failed.stderr
|
|
90
|
-
});
|
|
91
|
-
return {
|
|
92
|
-
verified: false,
|
|
93
|
-
merged: false,
|
|
94
|
-
conflicts: false,
|
|
95
|
-
evidence,
|
|
96
|
-
failure: `Verify command failed for ${item.id}: ${command}`
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
try {
|
|
100
|
-
evidence.mergeOutput = await deps.run(`git merge --no-ff ${JSON.stringify(slotBranch)}`, featureWorkspace);
|
|
101
|
-
return {
|
|
102
|
-
verified: true,
|
|
103
|
-
merged: true,
|
|
104
|
-
conflicts: false,
|
|
105
|
-
evidence
|
|
106
|
-
};
|
|
107
|
-
} catch (error) {
|
|
108
|
-
const failed = commandFailure(error);
|
|
109
|
-
evidence.mergeOutput = {
|
|
110
|
-
stdout: failed.stdout,
|
|
111
|
-
stderr: failed.stderr
|
|
112
|
-
};
|
|
113
|
-
await deps.run("git merge --abort", featureWorkspace).catch(() => {});
|
|
114
|
-
return {
|
|
115
|
-
verified: true,
|
|
116
|
-
merged: false,
|
|
117
|
-
conflicts: true,
|
|
118
|
-
evidence,
|
|
119
|
-
failure: `Slot branch ${slotBranch} did not merge cleanly`
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
function commandFailure(error) {
|
|
124
|
-
const partial = error;
|
|
125
|
-
return {
|
|
126
|
-
stdout: typeof partial.stdout === "string" ? partial.stdout : "",
|
|
127
|
-
stderr: typeof partial.stderr === "string" ? partial.stderr : typeof partial.message === "string" ? partial.message : String(error)
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
//#endregion
|
|
131
|
-
//#region ../../lib/pan-dir/task-door.ts
|
|
132
|
-
init_state_plane();
|
|
133
|
-
init_swarm_readiness();
|
|
134
|
-
init_slot_reconcile();
|
|
135
|
-
/** Single task-mutation write door over the immutable xBRIEF specification. */
|
|
136
|
-
init_record_update();
|
|
137
|
-
var TaskStatusChangeError = class extends Error {
|
|
138
|
-
constructor(message, details) {
|
|
139
|
-
super(message);
|
|
140
|
-
this.details = details;
|
|
141
|
-
this.name = "TaskStatusChangeError";
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
const TERMINAL = new Set(["completed", "cancelled"]);
|
|
145
|
-
function statusFor(type) {
|
|
146
|
-
if (type === "claim") return "running";
|
|
147
|
-
if (type === "done") return "completed";
|
|
148
|
-
if (type === "block") return "blocked";
|
|
149
|
-
if (type === "unblock") return "pending";
|
|
150
|
-
return "cancelled";
|
|
151
|
-
}
|
|
152
|
-
function subItemOverrideKey(itemId, subItemId) {
|
|
153
|
-
return subItemId.includes(".") ? subItemId : `${itemId}.${subItemId}`;
|
|
154
|
-
}
|
|
155
|
-
function allowedFrom(type, status) {
|
|
156
|
-
if (type === "claim") return status === "pending";
|
|
157
|
-
if (type === "done") return status === "running";
|
|
158
|
-
if (type === "block") return status === "pending" || status === "running";
|
|
159
|
-
if (type === "unblock") return status === "blocked";
|
|
160
|
-
return status === "pending" || status === "running" || status === "blocked";
|
|
161
|
-
}
|
|
162
|
-
function taskError(issueId, itemId, operation, currentStatus, owner, extra) {
|
|
163
|
-
const ownerText = owner ? ` The current claim owner is ${owner}.` : "";
|
|
164
|
-
const recovery = `Run \`pan task show ${issueId} ${itemId}\` to inspect the current task state before retrying.`;
|
|
165
|
-
return new TaskStatusChangeError(`Task ${itemId} on ${issueId} is ${currentStatus}, so ${operation} is not allowed.${ownerText}${extra ? ` ${extra}` : ""} ${recovery}`, {
|
|
166
|
-
issueId,
|
|
167
|
-
itemId,
|
|
168
|
-
operation,
|
|
169
|
-
currentStatus,
|
|
170
|
-
owner
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
function archiveClaim(record, itemId, outcome, reason, forced, now) {
|
|
174
|
-
const claim = record.tasks?.claims[itemId];
|
|
175
|
-
if (!claim || !record.tasks) return;
|
|
176
|
-
const entry = {
|
|
177
|
-
...claim,
|
|
178
|
-
itemId,
|
|
179
|
-
outcome,
|
|
180
|
-
reason,
|
|
181
|
-
forced: forced || void 0,
|
|
182
|
-
releasedAt: now
|
|
183
|
-
};
|
|
184
|
-
record.tasks.claimHistory = [...record.tasks.claimHistory ?? [], entry].slice(-50);
|
|
185
|
-
delete record.tasks.claims[itemId];
|
|
186
|
-
}
|
|
187
|
-
async function applyTaskStatusChange(project, issueId, operation) {
|
|
188
|
-
const normalizedIssueId = issueId.toUpperCase();
|
|
189
|
-
const writerId = operation.writerId ?? process.env.OVERDECK_AGENT_ID ?? `cli-${process.pid}@${hostname()}`;
|
|
190
|
-
let result;
|
|
191
|
-
await updateIssueRecord(project, normalizedIssueId, (record) => {
|
|
192
|
-
const planPath = findPlanSync(join(project.path, "workspaces", `feature-${normalizedIssueId.toLowerCase()}`));
|
|
193
|
-
if (!planPath) throw new Error(`The xBRIEF for ${normalizedIssueId} is missing or unreadable. Return the issue to planning before changing task state.`);
|
|
194
|
-
const item = applyStatusOverrides(readPlanSync(planPath), record.statusOverrides ?? {}).plan.items.find(({ id }) => id === operation.itemId);
|
|
195
|
-
if (!item) throw new Error(`Task ${operation.itemId} does not exist in the immutable xBRIEF for ${normalizedIssueId}. Return the issue to planning to change scope.`);
|
|
196
|
-
const currentStatus = item.status;
|
|
197
|
-
const currentSequence = record.tasks?.sequence ?? 0;
|
|
198
|
-
const existingClaim = record.tasks?.claims[operation.itemId];
|
|
199
|
-
const nextStatus = statusFor(operation.type);
|
|
200
|
-
const subItems = subItemsOf(item);
|
|
201
|
-
const subIds = operation.subItemIds?.length ? new Set(operation.subItemIds) : new Set(operation.type === "done" || operation.type === "cancel" ? subItems.map(({ id }) => id) : []);
|
|
202
|
-
const repeatedCancellation = operation.type === "cancel" && currentStatus === "cancelled";
|
|
203
|
-
if (operation.expectedSequence !== void 0 && operation.expectedSequence !== currentSequence) throw new TaskStatusChangeError(`Task sequence conflict for ${normalizedIssueId}: expected ${operation.expectedSequence}, but the current sequence is ${currentSequence}. Run \`pan task next ${normalizedIssueId}\` and retry with the new sequence.`, {
|
|
204
|
-
issueId: normalizedIssueId,
|
|
205
|
-
itemId: operation.itemId,
|
|
206
|
-
operation: operation.type,
|
|
207
|
-
currentStatus,
|
|
208
|
-
currentSequence
|
|
209
|
-
});
|
|
210
|
-
if (TERMINAL.has(currentStatus) && !repeatedCancellation) throw taskError(normalizedIssueId, operation.itemId, operation.type, currentStatus, existingClaim?.writerId);
|
|
211
|
-
if (operation.force && !operation.reason) throw taskError(normalizedIssueId, operation.itemId, operation.type, currentStatus, existingClaim?.writerId, "A forced transition requires --reason.");
|
|
212
|
-
if ((operation.type === "block" || operation.type === "cancel") && !operation.reason) throw taskError(normalizedIssueId, operation.itemId, operation.type, currentStatus, existingClaim?.writerId, "This transition requires --reason.");
|
|
213
|
-
if (repeatedCancellation && subItems.every((subItem) => subItem.status === "cancelled")) {
|
|
214
|
-
result = {
|
|
215
|
-
issueId: normalizedIssueId,
|
|
216
|
-
itemId: operation.itemId,
|
|
217
|
-
status: "cancelled",
|
|
218
|
-
sequence: currentSequence,
|
|
219
|
-
idempotent: true
|
|
220
|
-
};
|
|
221
|
-
return record;
|
|
222
|
-
}
|
|
223
|
-
if (operation.type === "claim" && currentStatus === "running" && existingClaim?.writerId === writerId) {
|
|
224
|
-
result = {
|
|
225
|
-
issueId: normalizedIssueId,
|
|
226
|
-
itemId: operation.itemId,
|
|
227
|
-
status: "running",
|
|
228
|
-
sequence: currentSequence,
|
|
229
|
-
claim: existingClaim,
|
|
230
|
-
idempotent: true
|
|
231
|
-
};
|
|
232
|
-
return record;
|
|
233
|
-
}
|
|
234
|
-
const ownerRestricted = (operation.type === "done" || operation.type === "block" || operation.type === "cancel") && currentStatus === "running";
|
|
235
|
-
if (!operation.force && ownerRestricted && existingClaim?.writerId !== writerId) throw taskError(normalizedIssueId, operation.itemId, operation.type, currentStatus, existingClaim?.writerId ?? "missing claim owner");
|
|
236
|
-
if (!operation.force && !repeatedCancellation && !allowedFrom(operation.type, currentStatus)) throw taskError(normalizedIssueId, operation.itemId, operation.type, currentStatus, existingClaim?.writerId);
|
|
237
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
238
|
-
record.tasks ??= {
|
|
239
|
-
sequence: 0,
|
|
240
|
-
claims: {}
|
|
241
|
-
};
|
|
242
|
-
record.statusOverrides = {
|
|
243
|
-
...record.statusOverrides ?? {},
|
|
244
|
-
[operation.itemId]: nextStatus
|
|
245
|
-
};
|
|
246
|
-
for (const subId of subIds) record.statusOverrides[subItemOverrideKey(operation.itemId, subId)] = nextStatus;
|
|
247
|
-
if (operation.type === "claim") record.tasks.claims[operation.itemId] = {
|
|
248
|
-
writerId,
|
|
249
|
-
agentId: process.env.OVERDECK_AGENT_ID ?? null,
|
|
250
|
-
pid: process.pid,
|
|
251
|
-
host: hostname(),
|
|
252
|
-
claimedAt: now
|
|
253
|
-
};
|
|
254
|
-
else if (existingClaim) archiveClaim(record, operation.itemId, nextStatus === "completed" ? "completed" : nextStatus === "blocked" ? "blocked" : "cancelled", operation.reason, operation.force ?? false, now);
|
|
255
|
-
if (operation.reason) record.tasks.statusReasons = {
|
|
256
|
-
...record.tasks.statusReasons ?? {},
|
|
257
|
-
[operation.itemId]: {
|
|
258
|
-
reason: operation.reason,
|
|
259
|
-
updatedAt: now,
|
|
260
|
-
forced: operation.force || void 0
|
|
261
|
-
}
|
|
262
|
-
};
|
|
263
|
-
record.tasks.sequence = currentSequence + 1;
|
|
264
|
-
result = {
|
|
265
|
-
issueId: normalizedIssueId,
|
|
266
|
-
itemId: operation.itemId,
|
|
267
|
-
status: nextStatus,
|
|
268
|
-
sequence: record.tasks.sequence,
|
|
269
|
-
claim: record.tasks.claims[operation.itemId]
|
|
270
|
-
};
|
|
271
|
-
return record;
|
|
272
|
-
}, { writerId });
|
|
273
|
-
if (!result) throw new Error(`Task mutation for ${normalizedIssueId}/${operation.itemId} produced no result.`);
|
|
274
|
-
return result;
|
|
275
|
-
}
|
|
276
|
-
//#endregion
|
|
277
|
-
//#region ../../lib/swarm-policy.ts
|
|
278
|
-
init_review_status();
|
|
279
|
-
function resolveSwarmPolicyLayers(global = {}, project = {}, issue = {}, cli = {}) {
|
|
280
|
-
const resolve = (key, fallback) => {
|
|
281
|
-
for (const [source, layer] of [
|
|
282
|
-
["cli", cli],
|
|
283
|
-
["issue", issue],
|
|
284
|
-
["project", project],
|
|
285
|
-
["global", global]
|
|
286
|
-
]) if (layer[key] !== void 0) return {
|
|
287
|
-
value: layer[key],
|
|
288
|
-
source
|
|
289
|
-
};
|
|
290
|
-
return {
|
|
291
|
-
value: fallback,
|
|
292
|
-
source: "default"
|
|
293
|
-
};
|
|
294
|
-
};
|
|
295
|
-
const mode = resolve("mode", "off");
|
|
296
|
-
const maxSlots = resolve("maxSlots", 3);
|
|
297
|
-
const autoAdvance = resolve("autoAdvance", true);
|
|
298
|
-
return {
|
|
299
|
-
mode: mode.value,
|
|
300
|
-
maxSlots: maxSlots.value,
|
|
301
|
-
autoAdvance: autoAdvance.value,
|
|
302
|
-
source: {
|
|
303
|
-
mode: mode.source,
|
|
304
|
-
maxSlots: maxSlots.source,
|
|
305
|
-
autoAdvance: autoAdvance.source
|
|
306
|
-
}
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
function resolveSwarmPolicy(issueId, cli = {}) {
|
|
310
|
-
const global = loadConfigSync().config.swarm;
|
|
311
|
-
if (!issueId) return resolveSwarmPolicyLayers(global, {}, {}, cli);
|
|
312
|
-
const resolved = resolveProjectFromIssueSync(issueId);
|
|
313
|
-
const project = resolved ? getProjectSync(resolved.projectKey) : void 0;
|
|
314
|
-
const issue = project ? readIssueRecordSync(project, issueId)?.swarm?.policy : void 0;
|
|
315
|
-
return resolveSwarmPolicyLayers(global, project?.swarm, issue, cli);
|
|
316
|
-
}
|
|
317
|
-
function resolveAutomaticSwarmPolicy(issueId, manual = false, inProgress = false) {
|
|
318
|
-
const policy = resolveSwarmPolicy(issueId);
|
|
319
|
-
return {
|
|
320
|
-
policy,
|
|
321
|
-
enabled: manual || policy.mode !== "off" && (policy.autoAdvance || !inProgress)
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
function resolveSwarmMaxSlots(issueId, configured) {
|
|
325
|
-
return Math.min(Math.max(1, Math.floor(configured)), Math.max(1, Math.floor(resolveSwarmPolicy(issueId).maxSlots)));
|
|
326
|
-
}
|
|
327
|
-
//#endregion
|
|
328
|
-
//#region ../../lib/cloister/deacon-workspaces.ts
|
|
329
|
-
init_projects();
|
|
330
|
-
function listFeatureWorkspaces(options = {}) {
|
|
331
|
-
const includeSlotWorkspaces = options.includeSlotWorkspaces ?? true;
|
|
332
|
-
const projects = listProjectsSync();
|
|
333
|
-
const workspaces = [];
|
|
334
|
-
for (const { config: projectConfig } of projects) {
|
|
335
|
-
const workspacesRoot = join$1(projectConfig.path, "workspaces");
|
|
336
|
-
if (!existsSync(workspacesRoot)) continue;
|
|
337
|
-
let entries;
|
|
338
|
-
try {
|
|
339
|
-
entries = readdirSync(workspacesRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name.startsWith("feature-")).filter((e) => includeSlotWorkspaces || !/-slot-\d+$/.test(e.name)).map((e) => e.name);
|
|
340
|
-
} catch {
|
|
341
|
-
continue;
|
|
342
|
-
}
|
|
343
|
-
for (const entry of entries) workspaces.push({
|
|
344
|
-
issueId: entry.replace(/^feature-/, "").toUpperCase(),
|
|
345
|
-
workspacePath: join$1(workspacesRoot, entry),
|
|
346
|
-
projectPath: projectConfig.path
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
return workspaces;
|
|
350
|
-
}
|
|
351
|
-
//#endregion
|
|
352
|
-
//#region ../../lib/cloister/deacon-swarm-orphan-gc.ts
|
|
353
|
-
/**
|
|
354
|
-
* Reconcile GC for truly-orphaned slots (PAN-2214, completes PAN-2213(c)).
|
|
355
|
-
*
|
|
356
|
-
* An orphan is a slot index with an on-disk worktree or a local slot branch but
|
|
357
|
-
* no slotAssignments entry and no live agent tmux session. Zero-commit-ahead
|
|
358
|
-
* orphans are removed; orphans with unmerged commits are only reported so the
|
|
359
|
-
* operator can push them via `pan swarm reset` — never deleted.
|
|
360
|
-
*/
|
|
361
|
-
async function gcOrphanedSlots(issueId, workspacePath, reconciled, deps) {
|
|
362
|
-
const actions = [];
|
|
363
|
-
const issueLower = issueId.toLowerCase();
|
|
364
|
-
const worktreeSlotIndexes = await listSlotWorktreeIndexes(workspacePath, deps.runGitCommand);
|
|
365
|
-
const branchesBySlot = new Map(reconciled.branches.map((branch) => [branch.slotIndex, branch.branch]));
|
|
366
|
-
const candidateSlotIndexes = [...new Set([...worktreeSlotIndexes, ...branchesBySlot.keys()])].sort((a, b) => a - b);
|
|
367
|
-
if (candidateSlotIndexes.length === 0) return actions;
|
|
368
|
-
const ownedSlotIndexes = new Set([
|
|
369
|
-
...(deps.listSlotAssignments ?? listSlotAssignments)(issueId, workspacePath).map((assignment) => assignment.slotIndex),
|
|
370
|
-
...reconciled.merged.map((slot) => slot.slotIndex),
|
|
371
|
-
...reconciled.inFlight.map((slot) => slot.slotIndex)
|
|
372
|
-
]);
|
|
373
|
-
const sessionNames = new Set(await deps.listSessionNames());
|
|
374
|
-
for (const slotIndex of candidateSlotIndexes) {
|
|
375
|
-
if (ownedSlotIndexes.has(slotIndex)) continue;
|
|
376
|
-
if (sessionNames.has(`agent-${issueLower}-slot-${slotIndex}`)) continue;
|
|
377
|
-
const branch = branchesBySlot.get(slotIndex);
|
|
378
|
-
const aheadCount = branch ? await countCommitsAhead(workspacePath, branch, deps.runGitCommand) : 0;
|
|
379
|
-
if (aheadCount === null || aheadCount > 0) {
|
|
380
|
-
actions.push(`[swarm] orphan slot ${slotIndex} for ${issueId} preserved: ${branch} has ${aheadCount ?? "an unknown number of"} unmerged commit(s) — run \`pan swarm reset ${issueId}\` to push it to origin before cleanup`);
|
|
381
|
-
continue;
|
|
382
|
-
}
|
|
383
|
-
if (worktreeSlotIndexes.has(slotIndex)) await deps.runGitCommand(`git worktree remove --force ${JSON.stringify(`${workspacePath}-slot-${slotIndex}`)}`, workspacePath);
|
|
384
|
-
if (branch) await deps.runGitCommand(`git branch -D ${JSON.stringify(branch)}`, workspacePath);
|
|
385
|
-
actions.push(`[swarm] gc-orphan slot ${slotIndex} for ${issueId}`);
|
|
386
|
-
}
|
|
387
|
-
return actions;
|
|
388
|
-
}
|
|
389
|
-
async function listSlotWorktreeIndexes(workspacePath, runGitCommand) {
|
|
390
|
-
const indexes = /* @__PURE__ */ new Set();
|
|
391
|
-
try {
|
|
392
|
-
const result = await runGitCommand("git worktree list --porcelain", workspacePath);
|
|
393
|
-
const pattern = new RegExp(`^worktree ${escapeRegExp(workspacePath)}-slot-(\\d+)$`);
|
|
394
|
-
for (const line of String(result?.stdout ?? "").split("\n")) {
|
|
395
|
-
const match = pattern.exec(line.trim());
|
|
396
|
-
if (match) indexes.add(Number(match[1]));
|
|
397
|
-
}
|
|
398
|
-
} catch {}
|
|
399
|
-
return indexes;
|
|
400
|
-
}
|
|
401
|
-
async function countCommitsAhead(workspacePath, branch, runGitCommand) {
|
|
402
|
-
try {
|
|
403
|
-
const result = await runGitCommand(`git rev-list --count HEAD..${JSON.stringify(branch)}`, workspacePath);
|
|
404
|
-
const count = Number(String(result?.stdout ?? "").trim());
|
|
405
|
-
return Number.isFinite(count) ? count : null;
|
|
406
|
-
} catch {
|
|
407
|
-
return null;
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
function escapeRegExp(value) {
|
|
411
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
412
|
-
}
|
|
413
|
-
//#endregion
|
|
414
|
-
//#region ../../lib/cloister/deacon-swarm-completion.ts
|
|
415
|
-
init_messaging();
|
|
416
|
-
const execAsync$2 = promisify(exec);
|
|
417
|
-
const slotCompletionObservations = /* @__PURE__ */ new Map();
|
|
418
|
-
async function classifyDoneWithoutSignal(slot, deps, options, observation) {
|
|
419
|
-
const mode = options.inferCompletion ?? "off";
|
|
420
|
-
if (mode === "off" || !slot.agentId || !slot.branch || !options.workspacePath || !options.issueId) {
|
|
421
|
-
slotCompletionObservations.delete(observation.progressKey);
|
|
422
|
-
return null;
|
|
423
|
-
}
|
|
424
|
-
const aheadCount = await (deps.getSlotBranchAheadCount ?? defaultGetSlotBranchAheadCount)(options.workspacePath, options.issueId, slot.branch).catch(() => 0);
|
|
425
|
-
const clean = await (deps.isSlotWorktreeClean ?? defaultIsSlotWorktreeClean)(`${options.workspacePath}-slot-${slot.slotIndex}`).catch(() => false);
|
|
426
|
-
if (aheadCount < 1 || !clean) {
|
|
427
|
-
slotCompletionObservations.delete(observation.progressKey);
|
|
428
|
-
return null;
|
|
429
|
-
}
|
|
430
|
-
const signature = `${observation.commitTime ?? "none"}:${observation.outputDigest}:${aheadCount}:clean`;
|
|
431
|
-
const previous = slotCompletionObservations.get(observation.progressKey);
|
|
432
|
-
const current = {
|
|
433
|
-
signature,
|
|
434
|
-
nudged: previous?.signature === signature ? previous.nudged : false,
|
|
435
|
-
consecutiveDoneCount: previous?.signature === signature ? previous.consecutiveDoneCount + 1 : 1
|
|
436
|
-
};
|
|
437
|
-
const actions = [];
|
|
438
|
-
const normalizedIssueId = options.issueId.toUpperCase();
|
|
439
|
-
if (!current.nudged) {
|
|
440
|
-
await (deps.sendCompletionNudge ?? defaultSendCompletionNudge)(slot.agentId, normalizedIssueId);
|
|
441
|
-
current.nudged = true;
|
|
442
|
-
actions.push(`[swarm] nudged slot ${slot.slotIndex} (item ${slot.itemId}) for ${normalizedIssueId}: run pan done ${normalizedIssueId}`);
|
|
443
|
-
}
|
|
444
|
-
slotCompletionObservations.set(observation.progressKey, current);
|
|
445
|
-
if (mode === "auto" && current.consecutiveDoneCount >= 2) return {
|
|
446
|
-
...slot,
|
|
447
|
-
lifecycle: "ready-to-merge",
|
|
448
|
-
exitStatus: 0,
|
|
449
|
-
signal: "inferred",
|
|
450
|
-
actions
|
|
451
|
-
};
|
|
452
|
-
return {
|
|
453
|
-
...slot,
|
|
454
|
-
lifecycle: "awaiting-completion-signal",
|
|
455
|
-
reason: "no-progress-timeout",
|
|
456
|
-
stalledForMs: observation.stalledForMs,
|
|
457
|
-
signal: "completion-nudge",
|
|
458
|
-
actions
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
async function classifyDurableReadySlot(slot, deps, options) {
|
|
462
|
-
if (!slot.branch || !options.workspacePath || !options.issueId) return null;
|
|
463
|
-
if (await (deps.getSlotBranchAheadCount ?? defaultGetSlotBranchAheadCount)(options.workspacePath, options.issueId, slot.branch).catch(() => 0) < 1) return null;
|
|
464
|
-
if (!await (deps.isSlotWorktreeClean ?? defaultIsSlotWorktreeClean)(`${options.workspacePath}-slot-${slot.slotIndex}`).catch(() => false)) return null;
|
|
465
|
-
return {
|
|
466
|
-
...slot,
|
|
467
|
-
lifecycle: "ready-to-merge",
|
|
468
|
-
exitStatus: 0,
|
|
469
|
-
signal: "inferred"
|
|
470
|
-
};
|
|
471
|
-
}
|
|
472
|
-
function clearSwarmCompletionObservation(progressKey) {
|
|
473
|
-
slotCompletionObservations.delete(progressKey);
|
|
474
|
-
}
|
|
475
|
-
function swarmInferCompletionMode() {
|
|
476
|
-
const raw = process.env.PAN_SWARM_INFER_COMPLETION ?? loadCloisterConfigSync().swarm?.infer_completion;
|
|
477
|
-
return raw === "off" || raw === "nudge" || raw === "auto" ? raw : "auto";
|
|
478
|
-
}
|
|
479
|
-
async function defaultGetSlotBranchAheadCount(workspacePath, issueId, branch) {
|
|
480
|
-
const baseBranch = `feature/${issueId.toLowerCase()}`;
|
|
481
|
-
const { stdout } = await execAsync$2(`git rev-list --count ${JSON.stringify(baseBranch)}..${JSON.stringify(branch)}`, { cwd: workspacePath });
|
|
482
|
-
const count = Number(stdout.trim());
|
|
483
|
-
return Number.isFinite(count) && count > 0 ? count : 0;
|
|
484
|
-
}
|
|
485
|
-
async function defaultIsSlotWorktreeClean(slotWorkspacePath) {
|
|
486
|
-
const { stdout } = await execAsync$2("git status --porcelain", { cwd: slotWorkspacePath });
|
|
487
|
-
return isStatePlaneOnlyStatus(stdout);
|
|
488
|
-
}
|
|
489
|
-
async function defaultSendCompletionNudge(agentId, issueId) {
|
|
490
|
-
await messageAgent(agentId, `You appear to have committed clean slot work but have not signaled completion. If the slot is complete, run exactly:\n\npan done ${issueId}`, "deacon:swarm-completion-inference");
|
|
491
|
-
}
|
|
492
|
-
//#endregion
|
|
493
|
-
//#region ../../lib/cloister/deacon-swarm-finalization.ts
|
|
494
|
-
init_io();
|
|
495
|
-
async function defaultRequestIssueReview(issueId, workspacePath) {
|
|
496
|
-
setReviewStatusSync(issueId, {
|
|
497
|
-
reviewStatus: "pending",
|
|
498
|
-
testStatus: "pending",
|
|
499
|
-
mergeStatus: "pending",
|
|
500
|
-
readyForMerge: false,
|
|
501
|
-
verificationStatus: "pending",
|
|
502
|
-
verificationCycleCount: 0,
|
|
503
|
-
autoRequeueCount: 0,
|
|
504
|
-
reviewRequestedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
505
|
-
});
|
|
506
|
-
const { spawnReviewRoleForIssue } = await import("./review-agent-BUNTVJK2.js");
|
|
507
|
-
return Effect.runPromise(spawnReviewRoleForIssue({
|
|
508
|
-
issueId,
|
|
509
|
-
workspace: workspacePath,
|
|
510
|
-
branch: `feature/${issueId.toLowerCase()}`
|
|
511
|
-
}));
|
|
512
|
-
}
|
|
513
|
-
async function finalizeSwarmIssueIfComplete(issueId, workspacePath, baseDoc, deps) {
|
|
514
|
-
const overrides = deps.readStatusOverrides?.(workspacePath, issueId);
|
|
515
|
-
if (!(overrides && Object.keys(overrides).length > 0 ? applyStatusOverrides(baseDoc, overrides) : baseDoc).plan.items.every((item) => item.status === "completed")) return [];
|
|
516
|
-
if (deps.getFinalizedAt?.(issueId, workspacePath)) return [];
|
|
517
|
-
const currentStatus = getReviewStatusSync(issueId);
|
|
518
|
-
if (currentStatus?.mergeStatus === "merged") return [];
|
|
519
|
-
if (currentStatus?.reviewRequestedAt || currentStatus?.reviewStatus === "reviewing" || currentStatus?.reviewStatus === "passed") return [];
|
|
520
|
-
const result = await deps.requestIssueReview(issueId, workspacePath);
|
|
521
|
-
if (result.success) {
|
|
522
|
-
deps.setFinalizedAt?.(issueId, workspacePath, (/* @__PURE__ */ new Date()).toISOString());
|
|
523
|
-
return [`[swarm] finalized ${issueId}: issue-level review requested`];
|
|
524
|
-
}
|
|
525
|
-
return [`[swarm] finalization deferred ${issueId}: ${result.error || result.message}`];
|
|
526
|
-
}
|
|
527
|
-
//#endregion
|
|
528
|
-
//#region ../../lib/cloister/deacon-swarm-gc.ts
|
|
529
|
-
const MERGED_LIVE_SLOT_IDLE_MS = 1800 * 1e3;
|
|
530
|
-
async function reapMergedSlotAgent(issueId, slot, stopSlotAgent = (id) => Effect.runPromise(stopAgent(id))) {
|
|
531
|
-
const agentId = slot.agentId ?? `agent-${issueId.toLowerCase()}-slot-${slot.slotIndex}`;
|
|
532
|
-
try {
|
|
533
|
-
await stopSlotAgent(agentId);
|
|
534
|
-
return `[swarm] reaped merged agent ${agentId}`;
|
|
535
|
-
} catch (err) {
|
|
536
|
-
return `[swarm] could not reap merged agent ${agentId}: ${err instanceof Error ? err.message : String(err)}`;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
async function gcMergedSlots(issueId, workspacePath, slots, deps) {
|
|
540
|
-
const actions = [];
|
|
541
|
-
const sessionNames = new Set(await deps.listSessionNames());
|
|
542
|
-
const worktreeExists = deps.slotWorktreeExists ?? existsSync$1;
|
|
543
|
-
for (const slot of slots) {
|
|
544
|
-
if (slot.status !== "merged") continue;
|
|
545
|
-
const agentId = slot.agentId ?? `agent-${issueId.toLowerCase()}-slot-${slot.slotIndex}`;
|
|
546
|
-
if (sessionNames.has(agentId)) {
|
|
547
|
-
const completionProven = slot.mergedVia === "completed-status";
|
|
548
|
-
const lastActivity = (deps.getAgentLastActivity ?? ((id) => getAgentStateSync(id)?.lastActivity))(agentId);
|
|
549
|
-
const idleFor = lastActivity ? Date.now() - Date.parse(lastActivity) : 0;
|
|
550
|
-
if (!completionProven && (!Number.isFinite(idleFor) || idleFor < MERGED_LIVE_SLOT_IDLE_MS)) {
|
|
551
|
-
actions.push(`[swarm] gc skipped slot ${slot.slotIndex} (item ${slot.itemId}) for ${issueId}: agent session alive`);
|
|
552
|
-
continue;
|
|
553
|
-
}
|
|
554
|
-
await (deps.stopSlotAgent ?? ((id) => Effect.runPromise(stopAgent(id))))(agentId);
|
|
555
|
-
actions.push(completionProven ? `[swarm] gc reaped merged agent ${agentId}` : `[swarm] gc reaped idle merged agent ${agentId}`);
|
|
556
|
-
}
|
|
557
|
-
const slotWorkspace = `${workspacePath}-slot-${slot.slotIndex}`;
|
|
558
|
-
const slotBranch = slot.branch ?? `feature/${issueId.toLowerCase()}-slot-${slot.slotIndex}`;
|
|
559
|
-
if (worktreeExists(slotWorkspace)) try {
|
|
560
|
-
await deps.runGitCommand(`git worktree remove --force ${JSON.stringify(slotWorkspace)}`, workspacePath);
|
|
561
|
-
} catch (error) {
|
|
562
|
-
actions.push(`[swarm] gc deferred slot ${slot.slotIndex} (item ${slot.itemId}) for ${issueId}: worktree remove failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
563
|
-
continue;
|
|
564
|
-
}
|
|
565
|
-
try {
|
|
566
|
-
await deps.runGitCommand(`git branch -D ${JSON.stringify(slotBranch)}`, workspacePath);
|
|
567
|
-
} catch (error) {
|
|
568
|
-
actions.push(`[swarm] gc deferred slot ${slot.slotIndex} (item ${slot.itemId}) for ${issueId}: branch delete failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
569
|
-
continue;
|
|
570
|
-
}
|
|
571
|
-
deps.clearSlotAssignment(workspacePath, issueId, slot.slotIndex, slot.itemId);
|
|
572
|
-
actions.push(`[swarm] gc slot ${slot.slotIndex} (item ${slot.itemId}) for ${issueId}`);
|
|
573
|
-
}
|
|
574
|
-
return actions;
|
|
575
|
-
}
|
|
576
|
-
//#endregion
|
|
577
|
-
//#region ../../lib/cloister/deacon-swarm-record.ts
|
|
578
|
-
init_record();
|
|
579
|
-
init_record_update();
|
|
580
|
-
async function writeSwarmFinalizedAt(workspacePath, issueId, finalizedAt) {
|
|
581
|
-
await updateIssueRecordForWorkspace(workspacePath, issueId.toUpperCase(), (record) => ({
|
|
582
|
-
...record,
|
|
583
|
-
swarm: {
|
|
584
|
-
...record.swarm ?? {},
|
|
585
|
-
finalizedAt
|
|
586
|
-
}
|
|
587
|
-
}));
|
|
588
|
-
}
|
|
589
|
-
/**
|
|
590
|
-
* PAN-2372 WI-3 / FR-6: clear a slot's completion marker once the coordinator
|
|
591
|
-
* (WI-4) has consumed it (merge/requeue). No-op when no marker exists for the
|
|
592
|
-
* slot, so callers can clear unconditionally on the terminal transition.
|
|
593
|
-
*/
|
|
594
|
-
async function clearSwarmSlotCompletion(workspacePath, issueId, slotIndex) {
|
|
595
|
-
const normalizedIssueId = issueId.toUpperCase();
|
|
596
|
-
const current = readIssueRecordForWorkspaceSync(workspacePath, normalizedIssueId);
|
|
597
|
-
if (!current?.swarm?.slotCompletions || !(String(slotIndex) in current.swarm.slotCompletions)) return;
|
|
598
|
-
await updateIssueRecordForWorkspace(workspacePath, normalizedIssueId, (record) => {
|
|
599
|
-
const existing = record.swarm?.slotCompletions;
|
|
600
|
-
if (!existing || !(String(slotIndex) in existing)) return record;
|
|
601
|
-
const next = { ...existing };
|
|
602
|
-
delete next[String(slotIndex)];
|
|
603
|
-
return {
|
|
604
|
-
...record,
|
|
605
|
-
swarm: {
|
|
606
|
-
...record.swarm,
|
|
607
|
-
slotCompletions: next
|
|
608
|
-
}
|
|
609
|
-
};
|
|
610
|
-
});
|
|
611
|
-
}
|
|
612
|
-
//#endregion
|
|
613
|
-
//#region ../../lib/cloister/swarm-tiered-hooks.ts
|
|
614
|
-
/**
|
|
615
|
-
* PAN-2385 — tiered-execution commit hooks for the swarm dispatch path.
|
|
616
|
-
*
|
|
617
|
-
* The tier-feed and tier-supervisor libraries shipped with PAN-1791/2222 but
|
|
618
|
-
* had no production caller: commits landed and neither the standing crew nor
|
|
619
|
-
* the subscribe-policy supervisor ever heard about them (found live during
|
|
620
|
-
* the first Standing Crew run, PAN-2383). This module is the ignition.
|
|
621
|
-
*
|
|
622
|
-
* Fired from mergeReadySlots after a slot's bead commits merge into the
|
|
623
|
-
* feature workspace:
|
|
624
|
-
* 1. broadcastCommit — every live slot agent hears the rendered diff
|
|
625
|
-
* (ingestion-only; everyone-hears-everything per docs/TIERED-EXECUTION.md).
|
|
626
|
-
* 2. shouldSupervise(item, subscribe) → deliverCommitForReview — the
|
|
627
|
-
* standing supervisor reviews per its subscribe policy. This is
|
|
628
|
-
* independent of supervisor.owns_inspection, which only routes
|
|
629
|
-
* `pan inspect`.
|
|
630
|
-
*
|
|
631
|
-
* Both hooks are best-effort: the commit has already landed, so a delivery
|
|
632
|
-
* failure logs loudly and never blocks the merge loop.
|
|
633
|
-
*/
|
|
634
|
-
init_config_yaml();
|
|
635
|
-
init_resolve_tier();
|
|
636
|
-
init_tier_feed();
|
|
637
|
-
init_tier_supervisor();
|
|
638
|
-
init_slot_reconcile();
|
|
639
|
-
const execAsync$1 = promisify(exec);
|
|
640
|
-
const defaultDeps$1 = {
|
|
641
|
-
loadConfig: loadConfigSync,
|
|
642
|
-
getHeadSha: async (workspacePath) => (await execAsync$1("git rev-parse HEAD", { cwd: workspacePath })).stdout.trim(),
|
|
643
|
-
listAssignments: listSlotAssignments,
|
|
644
|
-
isSessionAlive: (sessionName) => Effect.runPromise(sessionExists(sessionName)),
|
|
645
|
-
broadcast: broadcastCommit,
|
|
646
|
-
ensureSupervisor: spawnTierSupervisor,
|
|
647
|
-
deliverReview: deliverCommitForReview,
|
|
648
|
-
loadPrd: loadPrdDraft
|
|
649
|
-
};
|
|
650
|
-
/** Resolve the tier name a bead belongs to, for the feed header. Falls back to
|
|
651
|
-
* the slot label when the tier table cannot resolve the item (fail-open here is
|
|
652
|
-
* correct: the feed is informational and the commit has already landed). */
|
|
653
|
-
function tierNameForItem(item, tiered, slotIndex) {
|
|
654
|
-
if (item) try {
|
|
655
|
-
return resolveTier(item, tiered).tierName;
|
|
656
|
-
} catch {}
|
|
657
|
-
return `slot-${slotIndex}`;
|
|
658
|
-
}
|
|
659
|
-
/**
|
|
660
|
-
* Fire the commit feed + supervisor review for a bead whose commits just
|
|
661
|
-
* merged into the feature workspace. Returns deacon action-log lines.
|
|
662
|
-
*/
|
|
663
|
-
async function fireTieredCommitHooks(options, deps = defaultDeps$1) {
|
|
664
|
-
const actions = [];
|
|
665
|
-
const { issueId, workspacePath, item, doc } = options;
|
|
666
|
-
let tiered;
|
|
667
|
-
try {
|
|
668
|
-
tiered = deps.loadConfig().config.tieredExecution;
|
|
669
|
-
} catch (err) {
|
|
670
|
-
actions.push(`[tiered] skipped commit hooks for ${issueId}: config load failed (${err instanceof Error ? err.message : String(err)})`);
|
|
671
|
-
return actions;
|
|
672
|
-
}
|
|
673
|
-
if (!tiered || !resolveTieredExecutionEnabled(tiered, doc.plan.metadata)) return actions;
|
|
674
|
-
let sha;
|
|
675
|
-
try {
|
|
676
|
-
sha = await deps.getHeadSha(workspacePath);
|
|
677
|
-
} catch (err) {
|
|
678
|
-
actions.push(`[tiered] commit hooks for ${issueId} item ${item.id} could not resolve HEAD: ${err instanceof Error ? err.message : String(err)}`);
|
|
679
|
-
return actions;
|
|
680
|
-
}
|
|
681
|
-
try {
|
|
682
|
-
const itemsById = new Map(doc.plan.items.map((planItem) => [planItem.id, planItem]));
|
|
683
|
-
const assignments = deps.listAssignments(issueId, workspacePath);
|
|
684
|
-
const listeners = [];
|
|
685
|
-
for (const assignment of assignments) {
|
|
686
|
-
if (!assignment.agentId) continue;
|
|
687
|
-
if (!await deps.isSessionAlive(assignment.agentId)) continue;
|
|
688
|
-
listeners.push({
|
|
689
|
-
tierName: tierNameForItem(itemsById.get(assignment.itemId), tiered, assignment.slotIndex),
|
|
690
|
-
agentId: assignment.agentId
|
|
691
|
-
});
|
|
692
|
-
}
|
|
693
|
-
if (listeners.length > 0) {
|
|
694
|
-
const delivered = (await deps.broadcast({
|
|
695
|
-
workspace: workspacePath,
|
|
696
|
-
issueId,
|
|
697
|
-
sha,
|
|
698
|
-
itemTitle: item.title,
|
|
699
|
-
itemId: item.id,
|
|
700
|
-
tiers: listeners,
|
|
701
|
-
feedConfig: tiered.feed
|
|
702
|
-
})).filter((delivery) => delivery.result.ok).length;
|
|
703
|
-
actions.push(`[tiered] broadcast commit ${sha.slice(0, 10)} (item ${item.id}) for ${issueId} to ${delivered}/${listeners.length} standing agents`);
|
|
704
|
-
}
|
|
705
|
-
} catch (err) {
|
|
706
|
-
actions.push(`[tiered] feed broadcast FAILED for ${issueId} item ${item.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
707
|
-
}
|
|
708
|
-
try {
|
|
709
|
-
const supervisor = tiered.supervisor;
|
|
710
|
-
if (supervisor && shouldSupervise(item, supervisor.subscribe)) {
|
|
711
|
-
const agentId = supervisorAgentId(issueId);
|
|
712
|
-
if (!await deps.isSessionAlive(agentId)) {
|
|
713
|
-
await deps.ensureSupervisor(issueId, supervisor, { workspace: workspacePath });
|
|
714
|
-
actions.push(`[tiered] spawned standing supervisor ${agentId} for ${issueId}`);
|
|
715
|
-
}
|
|
716
|
-
const prdMarkdown = await deps.loadPrd(workspacePath, issueId).catch(() => void 0);
|
|
717
|
-
await deps.deliverReview({
|
|
718
|
-
supervisorAgentId: agentId,
|
|
719
|
-
workspacePath,
|
|
720
|
-
issueId,
|
|
721
|
-
item,
|
|
722
|
-
sha,
|
|
723
|
-
itemId: item.id,
|
|
724
|
-
prdMarkdown
|
|
725
|
-
});
|
|
726
|
-
actions.push(`[tiered] supervisor review dispatched for ${issueId} item ${item.id} (subscribe=${supervisor.subscribe})`);
|
|
727
|
-
}
|
|
728
|
-
} catch (err) {
|
|
729
|
-
actions.push(`[tiered] supervisor review FAILED for ${issueId} item ${item.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
730
|
-
}
|
|
731
|
-
return actions;
|
|
732
|
-
}
|
|
733
|
-
//#endregion
|
|
734
|
-
//#region ../../lib/cloister/redrive-gate.ts
|
|
735
|
-
init_recovery_trip();
|
|
736
|
-
/**
|
|
737
|
-
* PAN-2543 shared autonomous re-drive gate.
|
|
738
|
-
*
|
|
739
|
-
* Recovery entry points classify agent gates, apply the intent policy, and
|
|
740
|
-
* consult the cached memory verdict through this one function before acting.
|
|
741
|
-
* Callers still reserve their role-specific concurrency slot after admission.
|
|
742
|
-
*/
|
|
743
|
-
init_agent_state();
|
|
744
|
-
init_pending_decision_gate();
|
|
745
|
-
function decideAutonomousRedrive(state, context = {}) {
|
|
746
|
-
const gateDecision = decideResumeGate(getAgentResumeGateBlockReason(state), "autonomous", context);
|
|
747
|
-
if (gateDecision.decision !== "proceed") return {
|
|
748
|
-
decision: "defer",
|
|
749
|
-
reason: gateDecision.reason,
|
|
750
|
-
...gateDecision.decision === "block" && gateDecision.needsYou ? { needsYou: true } : {}
|
|
751
|
-
};
|
|
752
|
-
const memoryVerdict = getCachedMemoryVerdict();
|
|
753
|
-
if (memoryVerdict && memoryVerdict.band !== "ok") return {
|
|
754
|
-
decision: "defer",
|
|
755
|
-
reason: `memory pressure is ${memoryVerdict.band}`
|
|
756
|
-
};
|
|
757
|
-
return {
|
|
758
|
-
decision: "proceed",
|
|
759
|
-
gateDecision
|
|
760
|
-
};
|
|
761
|
-
}
|
|
762
|
-
async function decideAgentAutonomousRedrive(state, agentDir, owesRework, deps = {}) {
|
|
763
|
-
const admission = decideAutonomousRedrive(state, {
|
|
764
|
-
hasCompletedHandoff: existsSync$1(join(agentDir, "completed")) || existsSync$1(join(agentDir, "completed.processed")),
|
|
765
|
-
owesRework
|
|
766
|
-
});
|
|
767
|
-
if (admission.decision === "defer") return admission;
|
|
768
|
-
const agentId = basename(agentDir);
|
|
769
|
-
const pendingDecision = await (deps.detectPendingOperatorDecision ?? detectPendingOperatorDecision)(agentId);
|
|
770
|
-
if (pendingDecision) return {
|
|
771
|
-
decision: "defer",
|
|
772
|
-
reason: `agent is waiting on an operator decision (${pendingDecision.reason})`,
|
|
773
|
-
needsYou: true
|
|
774
|
-
};
|
|
775
|
-
return admission;
|
|
776
|
-
}
|
|
777
|
-
//#endregion
|
|
778
|
-
//#region ../../lib/cloister/swarm-failed-slot.ts
|
|
779
|
-
init_record_update();
|
|
780
|
-
init_agent_state();
|
|
781
|
-
async function archiveFailedSwarmSlot(issueId, workspacePath, slot, deps, now = /* @__PURE__ */ new Date()) {
|
|
782
|
-
const normalized = issueId.toUpperCase();
|
|
783
|
-
const suffix = now.toISOString().replace(/[-:.TZ]/g, "");
|
|
784
|
-
const archivedStem = `slot-${slot.slotIndex}-failed-${suffix}`;
|
|
785
|
-
const oldWorktree = `${workspacePath}-slot-${slot.slotIndex}`;
|
|
786
|
-
const archivedWorktree = `${workspacePath}-${archivedStem}`;
|
|
787
|
-
const oldBranch = slot.branch ?? `feature/${issueId.toLowerCase()}-slot-${slot.slotIndex}`;
|
|
788
|
-
const archivedBranch = `feature/${issueId.toLowerCase()}-${archivedStem}`;
|
|
789
|
-
if (existsSync$1(oldWorktree)) await deps.runGitCommand(`git worktree move ${JSON.stringify(oldWorktree)} ${JSON.stringify(archivedWorktree)}`, workspacePath);
|
|
790
|
-
await deps.runGitCommand(`git branch -m ${JSON.stringify(oldBranch)} ${JSON.stringify(archivedBranch)}`, workspacePath);
|
|
791
|
-
const attempt = {
|
|
792
|
-
slotIndex: slot.slotIndex,
|
|
793
|
-
itemId: slot.itemId,
|
|
794
|
-
agentId: slot.agentId,
|
|
795
|
-
branch: oldBranch,
|
|
796
|
-
archivedBranch,
|
|
797
|
-
...existsSync$1(archivedWorktree) ? { archivedWorktree } : {},
|
|
798
|
-
reason: slot.reason ?? "failed swarm slot",
|
|
799
|
-
supersededAt: now.toISOString()
|
|
800
|
-
};
|
|
801
|
-
await updateIssueRecordForWorkspace(workspacePath, normalized, (existing) => ({
|
|
802
|
-
...existing,
|
|
803
|
-
swarm: {
|
|
804
|
-
...existing.swarm ?? {},
|
|
805
|
-
supersededAttempts: [...existing.swarm?.supersededAttempts ?? [], attempt]
|
|
806
|
-
}
|
|
807
|
-
}));
|
|
808
|
-
await clearSwarmSlotCompletion(workspacePath, normalized, slot.slotIndex);
|
|
809
|
-
await deps.clearSlotAssignment(workspacePath, normalized, slot.slotIndex, slot.itemId);
|
|
810
|
-
return attempt;
|
|
811
|
-
}
|
|
812
|
-
async function requeueFailedSwarmSlots(issueId, workspacePath, classified, doc, reconciled, deps, blockedSlotIndexes = /* @__PURE__ */ new Set()) {
|
|
813
|
-
let nextDoc = doc;
|
|
814
|
-
const actions = [];
|
|
815
|
-
const decideAgentRedrive = deps.decideAgentAutonomousRedrive ?? decideAgentAutonomousRedrive;
|
|
816
|
-
const decideUnownedRedrive = deps.decideAutonomousRedrive ?? decideAutonomousRedrive;
|
|
817
|
-
const recordFailure = deps.recordRecoveryFailure ?? recordRecoveryFailure;
|
|
818
|
-
const acknowledgeTrip = deps.acknowledgeRecoveryTrip ?? acknowledgeRecoveryTrip;
|
|
819
|
-
for (const slot of classified.filter((candidate) => candidate.lifecycle === "failed")) {
|
|
820
|
-
if (blockedSlotIndexes.has(slot.slotIndex)) {
|
|
821
|
-
actions.push(`[swarm] skipped requeue slot ${slot.slotIndex} (item ${slot.itemId}) for ${issueId}: failed-merge block — awaiting operator recovery`);
|
|
822
|
-
continue;
|
|
823
|
-
}
|
|
824
|
-
const pendingDecisionRecoveryPath = "swarm-slot-pending-operator-decision";
|
|
825
|
-
const pendingDecisionGeneration = `${slot.itemId}:${slot.agentId ?? `slot-${slot.slotIndex}`}`;
|
|
826
|
-
const admission = slot.agentId ? await decideAgentRedrive(getAgentStateSync(slot.agentId) ?? {}, getAgentDir(slot.agentId), true) : decideUnownedRedrive({}, { owesRework: true });
|
|
827
|
-
if (admission.decision === "defer") {
|
|
828
|
-
if (admission.needsYou) {
|
|
829
|
-
if ((await recordFailure(workspacePath, issueId, pendingDecisionRecoveryPath, pendingDecisionGeneration, 1)).emitNeedsYou) actions.push(`[swarm] needs-you ${issueId}: failed slot ${slot.slotIndex} ${admission.reason}`);
|
|
830
|
-
}
|
|
831
|
-
actions.push(`[swarm] deferred failed slot ${slot.slotIndex}: ${admission.reason}`);
|
|
832
|
-
continue;
|
|
833
|
-
}
|
|
834
|
-
await acknowledgeTrip(workspacePath, issueId, pendingDecisionRecoveryPath, pendingDecisionGeneration);
|
|
835
|
-
const attempt = await archiveFailedSwarmSlot(issueId, workspacePath, slot, deps);
|
|
836
|
-
await deps.applyTaskOperationToPlanFile(issueId, {
|
|
837
|
-
type: "unblock",
|
|
838
|
-
itemId: slot.itemId,
|
|
839
|
-
writerId: "deacon-swarm",
|
|
840
|
-
reason: `Redispatch after ${slot.reason ?? "slot failure"}`
|
|
841
|
-
}, workspacePath);
|
|
842
|
-
reconciled.inFlight = reconciled.inFlight.filter((candidate) => candidate.itemId !== slot.itemId);
|
|
843
|
-
reconciled.superseded = [...reconciled.superseded ?? [], attempt];
|
|
844
|
-
nextDoc = {
|
|
845
|
-
...nextDoc,
|
|
846
|
-
plan: {
|
|
847
|
-
...nextDoc.plan,
|
|
848
|
-
items: nextDoc.plan.items.map((item) => item.id === slot.itemId ? {
|
|
849
|
-
...item,
|
|
850
|
-
status: "pending"
|
|
851
|
-
} : item)
|
|
852
|
-
}
|
|
853
|
-
};
|
|
854
|
-
actions.push(`[swarm] archived failed slot ${slot.slotIndex} (item ${slot.itemId}) for ${issueId}`);
|
|
855
|
-
const failure = await recordFailure(workspacePath, issueId, "swarm-slot-requeue", slot.itemId);
|
|
856
|
-
if (failure.emitNeedsYou) actions.push(`[swarm] needs-you ${issueId}: slot item ${slot.itemId} failed ${failure.trip.tripCount} times`);
|
|
857
|
-
}
|
|
858
|
-
return {
|
|
859
|
-
doc: nextDoc,
|
|
860
|
-
actions
|
|
861
|
-
};
|
|
862
|
-
}
|
|
863
|
-
function applySupersededSlotHighWater(occupied, reconciled, configuredMax) {
|
|
864
|
-
const highWater = Math.max(0, ...(reconciled.superseded ?? []).map((attempt) => attempt.slotIndex));
|
|
865
|
-
if (highWater > 0) for (let index = 1; index <= highWater; index++) occupied.add(index);
|
|
866
|
-
return Math.max(configuredMax, highWater + 1);
|
|
867
|
-
}
|
|
868
|
-
//#endregion
|
|
869
|
-
//#region ../../lib/cloister/deacon-swarm.ts
|
|
870
|
-
init_slot_reconcile();
|
|
871
|
-
init_record();
|
|
872
|
-
init_record_update();
|
|
873
|
-
init_tmux();
|
|
874
|
-
init_io();
|
|
875
|
-
init_review_status();
|
|
876
|
-
const execAsync = promisify(exec);
|
|
877
|
-
const SLOT_MERGE_REFIRE_COOLDOWN_MS = 5e3;
|
|
878
|
-
const SWARM_ADVANCE_FAILURE_THRESHOLD = 3;
|
|
879
|
-
const SWARM_ADVANCE_FAILURE_COOLDOWN_MS = 6e4;
|
|
880
|
-
const DEFAULT_SWARM_STALL_THRESHOLD_MS = 1800 * 1e3;
|
|
881
|
-
const recentSlotMergeFires = /* @__PURE__ */ new Map();
|
|
882
|
-
const issueAdvanceFailures = /* @__PURE__ */ new Map();
|
|
883
|
-
const failedMergeBlocks = /* @__PURE__ */ new Map();
|
|
884
|
-
const slotProgressObservations = /* @__PURE__ */ new Map();
|
|
885
|
-
const defaultDeps = {
|
|
886
|
-
listFeatureWorkspaces: () => listFeatureWorkspaces({ includeSlotWorkspaces: false }),
|
|
887
|
-
reconcileSlotState,
|
|
888
|
-
listSessionNames: () => Effect.runPromise(listSessionNames()),
|
|
889
|
-
isPaneDead: (sessionName) => Effect.runPromise(isPaneDead(sessionName)),
|
|
890
|
-
getPaneExitStatus: async (sessionName) => {
|
|
891
|
-
const raw = (await Effect.runPromise(listPaneValues(sessionName, "#{pane_dead_status}")))[0]?.trim();
|
|
892
|
-
if (!raw) return null;
|
|
893
|
-
const status = Number(raw);
|
|
894
|
-
return Number.isFinite(status) ? status : null;
|
|
895
|
-
},
|
|
896
|
-
getAgentRuntimeState: (agentId) => Effect.runPromise(getAgentRuntimeSnapshot(agentId)),
|
|
897
|
-
getPaneOutputDigest: async (sessionName) => Effect.runPromise(capturePane(sessionName, 200)),
|
|
898
|
-
getBranchTipCommitTime: async (workspacePath, branch) => {
|
|
899
|
-
try {
|
|
900
|
-
const { stdout } = await execAsync(`git log -1 --format=%ct ${JSON.stringify(branch)}`, { cwd: workspacePath });
|
|
901
|
-
const seconds = Number(stdout.trim());
|
|
902
|
-
return Number.isFinite(seconds) ? seconds * 1e3 : null;
|
|
903
|
-
} catch {
|
|
904
|
-
return null;
|
|
905
|
-
}
|
|
906
|
-
},
|
|
907
|
-
getSlotBranchAheadCount: defaultGetSlotBranchAheadCount,
|
|
908
|
-
isSlotWorktreeClean: defaultIsSlotWorktreeClean,
|
|
909
|
-
sendCompletionNudge: defaultSendCompletionNudge,
|
|
910
|
-
slotWorktreeExists: existsSync$1,
|
|
911
|
-
verifyAndMergeSlot,
|
|
912
|
-
applyTaskOperationToPlanFile: (issueId, operation, workspacePath = "") => {
|
|
913
|
-
return applyTaskStatusChange(resolveProjectForIssue(issueId) ?? getProjectConfigFromWorkspacePath(workspacePath), issueId, operation);
|
|
914
|
-
},
|
|
915
|
-
fireTieredCommitHooks,
|
|
916
|
-
recordSlotAssignment,
|
|
917
|
-
clearSlotAssignment,
|
|
918
|
-
runGitCommand: (command, cwd) => execAsync(command, { cwd }),
|
|
919
|
-
registeredSlotCapacityAvailable: (issueId, selectedCount) => registeredSlotCapacityAvailable(issueId, selectedCount),
|
|
920
|
-
tryReserveSwarmSlot,
|
|
921
|
-
releaseSwarmSlot,
|
|
922
|
-
spawnRun,
|
|
923
|
-
getIssueHold: defaultGetIssueHold,
|
|
924
|
-
shouldDispatch: defaultShouldDispatch,
|
|
925
|
-
getMaxSlotIndex: defaultGetMaxSlotIndex,
|
|
926
|
-
listSlotAssignments,
|
|
927
|
-
readStatusOverrides: defaultReadStatusOverrides,
|
|
928
|
-
readSlotCompletion: defaultReadSlotCompletion,
|
|
929
|
-
getFinalizedAt: getSwarmFinalizedAt,
|
|
930
|
-
setFinalizedAt: recordSwarmFinalizedAt,
|
|
931
|
-
requestIssueReview: defaultRequestIssueReview
|
|
932
|
-
};
|
|
933
|
-
function defaultGetMaxSlotIndex() {
|
|
934
|
-
return Math.max(1, getConcurrencyLimits().reservedSwarmSlots);
|
|
935
|
-
}
|
|
936
|
-
function defaultGetIssueHold(issueId) {
|
|
937
|
-
try {
|
|
938
|
-
return getReviewStatusSync(issueId);
|
|
939
|
-
} catch {
|
|
940
|
-
return null;
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
function defaultReadStatusOverrides(workspacePath, issueId) {
|
|
944
|
-
const normalized = issueId.toUpperCase();
|
|
945
|
-
const record = readIssueRecordForWorkspaceSync(workspacePath, normalized);
|
|
946
|
-
if (record === null && existsSync$1(getIssueRecordPathForWorkspace(workspacePath, normalized))) {
|
|
947
|
-
console.warn(`[swarm] record unreadable for ${normalized} — treating as no overrides; see .corrupt sidecar`);
|
|
948
|
-
return;
|
|
949
|
-
}
|
|
950
|
-
return record?.statusOverrides;
|
|
951
|
-
}
|
|
952
|
-
/**
|
|
953
|
-
* PAN-2372 WI-4 / FR-6: read a slot's durable completion marker from the record
|
|
954
|
-
* door. Returns undefined when no record or no marker exists. Used by
|
|
955
|
-
* classifyInFlightSlots to recognize a slot whose `pan done` durably recorded
|
|
956
|
-
* completion even when the runtime plane (agent state, tmux session) is gone.
|
|
957
|
-
*/
|
|
958
|
-
function defaultReadSlotCompletion(workspacePath, issueId, slotIndex) {
|
|
959
|
-
try {
|
|
960
|
-
return readIssueRecordForWorkspaceSync(workspacePath, issueId.toUpperCase())?.swarm?.slotCompletions?.[String(slotIndex)];
|
|
961
|
-
} catch {
|
|
962
|
-
return;
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
function defaultShouldDispatch(issueId) {
|
|
966
|
-
if (isDeaconGloballyPausedSync()) return false;
|
|
967
|
-
const hold = defaultGetIssueHold(issueId);
|
|
968
|
-
return !(hold?.stuck || hold?.deaconIgnored);
|
|
969
|
-
}
|
|
970
|
-
async function coordinateSwarmSlots(opts = {}, deps = defaultDeps) {
|
|
971
|
-
const actions = [];
|
|
972
|
-
const filterIssueId = opts.issueId?.toUpperCase();
|
|
973
|
-
for (const workspace of deps.listFeatureWorkspaces()) {
|
|
974
|
-
const issueId = workspace.issueId.toUpperCase();
|
|
975
|
-
if (filterIssueId && issueId !== filterIssueId) continue;
|
|
976
|
-
const hold = (deps.getIssueHold ?? defaultGetIssueHold)(issueId);
|
|
977
|
-
if (hold?.deaconIgnored) {
|
|
978
|
-
actions.push(`[swarm] skipped ${issueId}: deacon-ignored — operator hold`);
|
|
979
|
-
continue;
|
|
980
|
-
}
|
|
981
|
-
if (hold?.stuck) actions.push(`[swarm] ${issueId} is system-stuck (${hold.stuckReason ?? "unknown"}) — coordinating anyway (stuck no longer halts assembly, PAN-2469)`);
|
|
982
|
-
if (isSwarmAdvanceCoolingDown(issueId)) {
|
|
983
|
-
actions.push(`[swarm] deferred ${issueId}: advance backoff active`);
|
|
984
|
-
continue;
|
|
985
|
-
}
|
|
986
|
-
const failedMergeBlocks = getFailedMergeBlocks(issueId, workspace.workspacePath);
|
|
987
|
-
const blockedSlotIndexes = new Set(failedMergeBlocks.map((block) => block.slotIndex));
|
|
988
|
-
const blockedItemIds = new Set(failedMergeBlocks.map((block) => block.itemId));
|
|
989
|
-
if (failedMergeBlocks.length > 0) {
|
|
990
|
-
const slots = failedMergeBlocks.map((block) => `slot ${block.slotIndex} (item ${block.itemId})`).join(", ");
|
|
991
|
-
actions.push(`[swarm] blocked slots for ${issueId}: ${slots} — other slots continue; run \`pan swarm recover ${issueId} <slot>\``);
|
|
992
|
-
}
|
|
993
|
-
try {
|
|
994
|
-
const spec = await Effect.runPromise(findSpecByIssue(workspace.projectPath, issueId));
|
|
995
|
-
if (!spec) continue;
|
|
996
|
-
const planStatus = spec.document.plan.status;
|
|
997
|
-
if (planStatus === "completed" || planStatus === "cancelled") continue;
|
|
998
|
-
const overrides = (deps.readStatusOverrides ?? defaultReadStatusOverrides)(workspace.workspacePath, issueId);
|
|
999
|
-
const doc = overrides && Object.keys(overrides).length > 0 ? applyStatusOverrides(spec.document, overrides) : spec.document;
|
|
1000
|
-
const readiness = analyzeSwarmReadiness(doc);
|
|
1001
|
-
const slotEligibleCount = readiness.items.filter((item) => item.slotEligible).length;
|
|
1002
|
-
const swarmInProgress = Object.entries(overrides ?? {}).some(([key, value]) => !key.includes(".") && value === "completed");
|
|
1003
|
-
const { policy, enabled } = resolveAutomaticSwarmPolicy(issueId, opts.manual, swarmInProgress);
|
|
1004
|
-
if (!enabled) {
|
|
1005
|
-
actions.push(`[swarm] ${issueId}: swarming off (${policy.source.mode}) — no automatic dispatch, recovery, merge, or cleanup; use an explicit swarm command or stop the legacy sessions`);
|
|
1006
|
-
continue;
|
|
1007
|
-
}
|
|
1008
|
-
const dispatchEligible = enabled && readiness.swarmEligible && (slotEligibleCount >= 2 || swarmInProgress);
|
|
1009
|
-
if (dispatchEligible) actions.push(`[swarm] considered ${issueId}: swarm eligible`);
|
|
1010
|
-
const reconciled = await deps.reconcileSlotState(issueId, workspace.workspacePath, doc);
|
|
1011
|
-
if (!dispatchEligible) {
|
|
1012
|
-
if (!(reconciled.merged.length > 0 || reconciled.inFlight.length > 0 || reconciled.branches.length > 0 || reconciled.agents.length > 0)) {
|
|
1013
|
-
actions.push(...await finalizeSwarmIssueIfComplete(issueId, workspace.workspacePath, doc, deps));
|
|
1014
|
-
continue;
|
|
1015
|
-
}
|
|
1016
|
-
actions.push(`[swarm] considered ${issueId}: endgame (merge/cleanup only)`);
|
|
1017
|
-
}
|
|
1018
|
-
const classified = await classifyInFlightSlots(reconciled.inFlight, deps, {
|
|
1019
|
-
workspacePath: workspace.workspacePath,
|
|
1020
|
-
issueId,
|
|
1021
|
-
inferCompletion: swarmInferCompletionMode()
|
|
1022
|
-
});
|
|
1023
|
-
for (const slot of classified) {
|
|
1024
|
-
actions.push(`[swarm] ${issueId} slot ${slot.slotIndex} ${slot.lifecycle}${slot.signal ? ` signal: ${slot.signal}` : ""}`);
|
|
1025
|
-
if (slot.actions) actions.push(...slot.actions);
|
|
1026
|
-
}
|
|
1027
|
-
const requeue = await requeueFailedSwarmSlots(issueId, workspace.workspacePath, classified, doc, reconciled, deps, blockedSlotIndexes);
|
|
1028
|
-
actions.push(...requeue.actions);
|
|
1029
|
-
actions.push(...await recordStalledSlotRecovery(issueId, classified, workspace.workspacePath));
|
|
1030
|
-
actions.push(...await mergeReadySlots(issueId, workspace.workspacePath, doc, classified, deps, blockedSlotIndexes));
|
|
1031
|
-
actions.push(...await gcMergedSlots(issueId, workspace.workspacePath, reconciled.merged, deps));
|
|
1032
|
-
actions.push(...await gcOrphanedSlots(issueId, workspace.workspacePath, reconciled, deps));
|
|
1033
|
-
actions.push(...await finalizeSwarmIssueIfComplete(issueId, workspace.workspacePath, spec.document, deps));
|
|
1034
|
-
if (dispatchEligible) actions.push(...await dispatchNextWave(issueId, workspace.workspacePath, requeue.doc, reconciled, analyzeSwarmReadiness(requeue.doc), deps, blockedSlotIndexes, blockedItemIds));
|
|
1035
|
-
recordSwarmAdvanceSuccess(issueId);
|
|
1036
|
-
} catch (err) {
|
|
1037
|
-
recordSwarmAdvanceFailure(issueId);
|
|
1038
|
-
console.warn(`[deacon] Error coordinating swarm ${issueId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
|
-
return actions;
|
|
1042
|
-
}
|
|
1043
|
-
async function classifyInFlightSlots(slots, deps = defaultDeps, options = {}) {
|
|
1044
|
-
const sessionNames = new Set(await deps.listSessionNames());
|
|
1045
|
-
const classified = [];
|
|
1046
|
-
const now = options.now ?? Date.now();
|
|
1047
|
-
const stallThresholdMs = options.stallThresholdMs ?? swarmStallThresholdMs();
|
|
1048
|
-
for (const slot of slots) {
|
|
1049
|
-
if (options.workspacePath && options.issueId) {
|
|
1050
|
-
const completion = await (deps.readSlotCompletion ?? defaultReadSlotCompletion)(options.workspacePath, options.issueId, slot.slotIndex);
|
|
1051
|
-
if (completion && (!completion.itemId || completion.itemId === slot.itemId)) {
|
|
1052
|
-
classified.push({
|
|
1053
|
-
...slot,
|
|
1054
|
-
lifecycle: "ready-to-merge",
|
|
1055
|
-
exitStatus: 0,
|
|
1056
|
-
signal: "durable-completion"
|
|
1057
|
-
});
|
|
1058
|
-
continue;
|
|
1059
|
-
}
|
|
1060
|
-
}
|
|
1061
|
-
const durableReady = await classifyDurableReadySlot(slot, deps, options);
|
|
1062
|
-
if (!slot.agentId) {
|
|
1063
|
-
if (durableReady) {
|
|
1064
|
-
classified.push(durableReady);
|
|
1065
|
-
continue;
|
|
1066
|
-
}
|
|
1067
|
-
classified.push({
|
|
1068
|
-
...slot,
|
|
1069
|
-
lifecycle: "failed",
|
|
1070
|
-
reason: "missing-agent"
|
|
1071
|
-
});
|
|
1072
|
-
continue;
|
|
1073
|
-
}
|
|
1074
|
-
const runtimeState = deps.getAgentRuntimeState ? await deps.getAgentRuntimeState(slot.agentId) : null;
|
|
1075
|
-
if (runtimeState?.resolution === "done" || runtimeState?.resolution === "completed") {
|
|
1076
|
-
classified.push({
|
|
1077
|
-
...slot,
|
|
1078
|
-
lifecycle: "ready-to-merge",
|
|
1079
|
-
exitStatus: 0
|
|
1080
|
-
});
|
|
1081
|
-
continue;
|
|
1082
|
-
}
|
|
1083
|
-
if (!sessionNames.has(slot.agentId)) {
|
|
1084
|
-
if (durableReady) {
|
|
1085
|
-
classified.push(durableReady);
|
|
1086
|
-
continue;
|
|
1087
|
-
}
|
|
1088
|
-
classified.push({
|
|
1089
|
-
...slot,
|
|
1090
|
-
lifecycle: "failed",
|
|
1091
|
-
reason: "vanished-session"
|
|
1092
|
-
});
|
|
1093
|
-
continue;
|
|
1094
|
-
}
|
|
1095
|
-
if (!await deps.isPaneDead(slot.agentId)) {
|
|
1096
|
-
const outputDigest = deps.getPaneOutputDigest ? await deps.getPaneOutputDigest(slot.agentId).catch(() => "") : "";
|
|
1097
|
-
const commitTime = slot.branch && options.workspacePath && deps.getBranchTipCommitTime ? await deps.getBranchTipCommitTime(options.workspacePath, slot.branch).catch(() => null) : null;
|
|
1098
|
-
const progressKey = slotProgressKey(slot);
|
|
1099
|
-
const previous = slotProgressObservations.get(progressKey);
|
|
1100
|
-
if (!previous || previous.commitTime !== commitTime || previous.outputDigest !== outputDigest) {
|
|
1101
|
-
slotProgressObservations.set(progressKey, {
|
|
1102
|
-
commitTime,
|
|
1103
|
-
outputDigest,
|
|
1104
|
-
lastProgressAt: now
|
|
1105
|
-
});
|
|
1106
|
-
clearSwarmCompletionObservation(progressKey);
|
|
1107
|
-
classified.push({
|
|
1108
|
-
...slot,
|
|
1109
|
-
lifecycle: "running"
|
|
1110
|
-
});
|
|
1111
|
-
continue;
|
|
1112
|
-
}
|
|
1113
|
-
const stalledForMs = now - previous.lastProgressAt;
|
|
1114
|
-
if (stalledForMs > stallThresholdMs) {
|
|
1115
|
-
const inferred = await classifyDoneWithoutSignal(slot, deps, options, {
|
|
1116
|
-
commitTime,
|
|
1117
|
-
outputDigest,
|
|
1118
|
-
progressKey,
|
|
1119
|
-
stalledForMs
|
|
1120
|
-
});
|
|
1121
|
-
if (inferred) {
|
|
1122
|
-
classified.push(inferred);
|
|
1123
|
-
continue;
|
|
1124
|
-
}
|
|
1125
|
-
classified.push({
|
|
1126
|
-
...slot,
|
|
1127
|
-
lifecycle: "stalled",
|
|
1128
|
-
reason: "no-progress-timeout",
|
|
1129
|
-
stalledForMs
|
|
1130
|
-
});
|
|
1131
|
-
continue;
|
|
1132
|
-
}
|
|
1133
|
-
classified.push({
|
|
1134
|
-
...slot,
|
|
1135
|
-
lifecycle: "running"
|
|
1136
|
-
});
|
|
1137
|
-
continue;
|
|
1138
|
-
}
|
|
1139
|
-
const exitStatus = await deps.getPaneExitStatus(slot.agentId);
|
|
1140
|
-
if (exitStatus === 0) {
|
|
1141
|
-
classified.push({
|
|
1142
|
-
...slot,
|
|
1143
|
-
lifecycle: "ready-to-merge",
|
|
1144
|
-
exitStatus
|
|
1145
|
-
});
|
|
1146
|
-
continue;
|
|
1147
|
-
}
|
|
1148
|
-
classified.push({
|
|
1149
|
-
...slot,
|
|
1150
|
-
lifecycle: "failed",
|
|
1151
|
-
exitStatus,
|
|
1152
|
-
reason: exitStatus === null ? "pane-exit-unknown" : "pane-exit-nonzero"
|
|
1153
|
-
});
|
|
1154
|
-
}
|
|
1155
|
-
return classified;
|
|
1156
|
-
}
|
|
1157
|
-
function slotProgressKey(slot) {
|
|
1158
|
-
return slot.agentId ?? slot.branch ?? `${slot.itemId}:${slot.slotIndex}`;
|
|
1159
|
-
}
|
|
1160
|
-
function swarmStallThresholdMs() {
|
|
1161
|
-
const raw = process.env.PAN_SWARM_STALL_THRESHOLD_MS;
|
|
1162
|
-
if (!raw) return DEFAULT_SWARM_STALL_THRESHOLD_MS;
|
|
1163
|
-
const parsed = Number(raw);
|
|
1164
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_SWARM_STALL_THRESHOLD_MS;
|
|
1165
|
-
}
|
|
1166
|
-
async function mergeReadySlots(issueId, workspacePath, doc, slots, deps = defaultDeps, blockedSlotIndexes = /* @__PURE__ */ new Set()) {
|
|
1167
|
-
const actions = [];
|
|
1168
|
-
const itemsById = new Map(doc.plan.items.map((item) => [item.id, item]));
|
|
1169
|
-
join$1(workspacePath, ".pan", "spec.vbrief.json");
|
|
1170
|
-
for (const slot of slots) {
|
|
1171
|
-
if (slot.lifecycle !== "ready-to-merge") continue;
|
|
1172
|
-
if (blockedSlotIndexes.has(slot.slotIndex)) {
|
|
1173
|
-
actions.push(`[swarm] skipped merge slot ${slot.slotIndex} (item ${slot.itemId}) for ${issueId}: failed-merge block — awaiting \`pan swarm recover\``);
|
|
1174
|
-
continue;
|
|
1175
|
-
}
|
|
1176
|
-
const item = itemsById.get(slot.itemId);
|
|
1177
|
-
if (!item) {
|
|
1178
|
-
actions.push(`[swarm] cannot merge slot ${slot.slotIndex} for ${issueId}: itemId "${slot.itemId}" not in the current plan (spec drift?) — needs operator attention`);
|
|
1179
|
-
continue;
|
|
1180
|
-
}
|
|
1181
|
-
const branchKey = slot.branch ?? `feature/${issueId.toLowerCase()}-slot-${slot.slotIndex}`;
|
|
1182
|
-
if (isSlotMergeCoolingDown(branchKey)) {
|
|
1183
|
-
actions.push(`[swarm] skipped merge slot ${slot.slotIndex} (item ${item.id}) for ${issueId}: refire cooldown`);
|
|
1184
|
-
continue;
|
|
1185
|
-
}
|
|
1186
|
-
recordSlotMergeFire(branchKey);
|
|
1187
|
-
const result = await deps.verifyAndMergeSlot({
|
|
1188
|
-
issueId,
|
|
1189
|
-
featureWorkspace: workspacePath
|
|
1190
|
-
}, slot.slotIndex, item);
|
|
1191
|
-
if (result.merged) {
|
|
1192
|
-
await deps.applyTaskOperationToPlanFile(issueId, {
|
|
1193
|
-
type: "done",
|
|
1194
|
-
itemId: item.id,
|
|
1195
|
-
writerId: "deacon-swarm"
|
|
1196
|
-
}, workspacePath);
|
|
1197
|
-
await clearSwarmSlotCompletion(workspacePath, issueId, slot.slotIndex);
|
|
1198
|
-
actions.push(await reapMergedSlotAgent(issueId, slot, deps.stopSlotAgent), `[swarm] merged slot ${slot.slotIndex} (item ${item.id}) for ${issueId}`);
|
|
1199
|
-
try {
|
|
1200
|
-
actions.push(...await deps.fireTieredCommitHooks({
|
|
1201
|
-
issueId,
|
|
1202
|
-
workspacePath,
|
|
1203
|
-
item,
|
|
1204
|
-
doc
|
|
1205
|
-
}));
|
|
1206
|
-
} catch (err) {
|
|
1207
|
-
actions.push(`[tiered] commit hooks threw for ${issueId} item ${item.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
1208
|
-
}
|
|
1209
|
-
continue;
|
|
1210
|
-
}
|
|
1211
|
-
if (result.conflicts) {
|
|
1212
|
-
await recordFailedMergeBlock({
|
|
1213
|
-
issueId,
|
|
1214
|
-
itemId: item.id,
|
|
1215
|
-
slotIndex: slot.slotIndex,
|
|
1216
|
-
branch: slot.branch,
|
|
1217
|
-
note: `Slot branch ${slot.branch ?? slot.slotIndex} did not merge cleanly`
|
|
1218
|
-
}, workspacePath);
|
|
1219
|
-
actions.push(`[swarm] failed-merge slot ${slot.slotIndex} (item ${item.id}) for ${issueId}`);
|
|
1220
|
-
continue;
|
|
1221
|
-
}
|
|
1222
|
-
actions.push(`[swarm] verify-failed slot ${slot.slotIndex} (item ${item.id}) for ${issueId}: ${result.failure ?? "verification failed"}`);
|
|
1223
|
-
}
|
|
1224
|
-
return actions;
|
|
1225
|
-
}
|
|
1226
|
-
function recordSwarmAdvanceFailure(issueId, now = Date.now()) {
|
|
1227
|
-
const normalized = issueId.toUpperCase();
|
|
1228
|
-
const previous = issueAdvanceFailures.get(normalized);
|
|
1229
|
-
const count = (previous?.count ?? 0) + 1;
|
|
1230
|
-
issueAdvanceFailures.set(normalized, {
|
|
1231
|
-
count,
|
|
1232
|
-
cooldownUntil: count >= SWARM_ADVANCE_FAILURE_THRESHOLD ? now + SWARM_ADVANCE_FAILURE_COOLDOWN_MS : previous?.cooldownUntil ?? 0
|
|
1233
|
-
});
|
|
1234
|
-
}
|
|
1235
|
-
function recordSwarmAdvanceSuccess(issueId) {
|
|
1236
|
-
issueAdvanceFailures.delete(issueId.toUpperCase());
|
|
1237
|
-
}
|
|
1238
|
-
function isSwarmAdvanceCoolingDown(issueId, now = Date.now()) {
|
|
1239
|
-
const record = issueAdvanceFailures.get(issueId.toUpperCase());
|
|
1240
|
-
return record !== void 0 && record.cooldownUntil > now;
|
|
1241
|
-
}
|
|
1242
|
-
function getFailedMergeBlock(issueId, slotIndex, workspacePath) {
|
|
1243
|
-
const normalized = issueId.toUpperCase();
|
|
1244
|
-
if (workspacePath) {
|
|
1245
|
-
const swarm = readIssueRecordForWorkspaceSync(workspacePath, normalized)?.swarm;
|
|
1246
|
-
const keyed = swarm?.failedMergeBlocks?.[String(slotIndex)];
|
|
1247
|
-
if (keyed) return {
|
|
1248
|
-
...keyed,
|
|
1249
|
-
issueId: keyed.issueId.toUpperCase()
|
|
1250
|
-
};
|
|
1251
|
-
const legacy = swarm?.failedMergeBlock;
|
|
1252
|
-
if (legacy && legacy.slotIndex === slotIndex) return {
|
|
1253
|
-
...legacy,
|
|
1254
|
-
issueId: legacy.issueId.toUpperCase()
|
|
1255
|
-
};
|
|
1256
|
-
}
|
|
1257
|
-
return failedMergeBlocks.get(`${normalized}:${slotIndex}`);
|
|
1258
|
-
}
|
|
1259
|
-
function getFailedMergeBlocks(issueId, workspacePath) {
|
|
1260
|
-
const normalized = issueId.toUpperCase();
|
|
1261
|
-
const bySlot = /* @__PURE__ */ new Map();
|
|
1262
|
-
if (workspacePath) {
|
|
1263
|
-
const swarm = readIssueRecordForWorkspaceSync(workspacePath, normalized)?.swarm;
|
|
1264
|
-
if (swarm?.failedMergeBlock) {
|
|
1265
|
-
const legacy = swarm.failedMergeBlock;
|
|
1266
|
-
bySlot.set(legacy.slotIndex, {
|
|
1267
|
-
...legacy,
|
|
1268
|
-
issueId: legacy.issueId.toUpperCase()
|
|
1269
|
-
});
|
|
1270
|
-
}
|
|
1271
|
-
if (swarm?.failedMergeBlocks) for (const [key, block] of Object.entries(swarm.failedMergeBlocks)) bySlot.set(Number(key), {
|
|
1272
|
-
...block,
|
|
1273
|
-
issueId: block.issueId.toUpperCase()
|
|
1274
|
-
});
|
|
1275
|
-
}
|
|
1276
|
-
for (const [key, block] of failedMergeBlocks.entries()) if (key.startsWith(`${normalized}:`) && !bySlot.has(block.slotIndex)) bySlot.set(block.slotIndex, { ...block });
|
|
1277
|
-
return [...bySlot.values()].sort((a, b) => a.slotIndex - b.slotIndex);
|
|
1278
|
-
}
|
|
1279
|
-
function getSwarmFinalizedAt(issueId, workspacePath) {
|
|
1280
|
-
return workspacePath ? readIssueRecordForWorkspaceSync(workspacePath, issueId.toUpperCase())?.swarm?.finalizedAt : void 0;
|
|
1281
|
-
}
|
|
1282
|
-
async function recordSwarmFinalizedAt(issueId, workspacePath, finalizedAt) {
|
|
1283
|
-
await writeSwarmFinalizedAt(workspacePath, issueId.toUpperCase(), finalizedAt);
|
|
1284
|
-
}
|
|
1285
|
-
async function recordFailedMergeBlock(block, workspacePath) {
|
|
1286
|
-
const normalizedBlock = {
|
|
1287
|
-
...block,
|
|
1288
|
-
issueId: block.issueId.toUpperCase()
|
|
1289
|
-
};
|
|
1290
|
-
failedMergeBlocks.set(`${normalizedBlock.issueId}:${normalizedBlock.slotIndex}`, normalizedBlock);
|
|
1291
|
-
if (workspacePath) await writeSwarmFailedMergeBlock(workspacePath, normalizedBlock.issueId, normalizedBlock.slotIndex, normalizedBlock);
|
|
1292
|
-
}
|
|
1293
|
-
async function recordStalledSlotRecovery(issueId, slots, workspacePath) {
|
|
1294
|
-
const actions = [];
|
|
1295
|
-
const normalizedIssueId = issueId.toUpperCase();
|
|
1296
|
-
for (const slot of slots.filter((s) => s.lifecycle === "stalled")) {
|
|
1297
|
-
if (getFailedMergeBlock(normalizedIssueId, slot.slotIndex, workspacePath)) continue;
|
|
1298
|
-
await recordFailedMergeBlock({
|
|
1299
|
-
issueId: normalizedIssueId,
|
|
1300
|
-
itemId: slot.itemId,
|
|
1301
|
-
slotIndex: slot.slotIndex,
|
|
1302
|
-
branch: slot.branch,
|
|
1303
|
-
note: `Slot ${slot.slotIndex} stalled with no branch commit or pane output progress`
|
|
1304
|
-
}, workspacePath);
|
|
1305
|
-
actions.push(`[swarm] stalled slot ${slot.slotIndex} (item ${slot.itemId}) for ${normalizedIssueId}: recovery required`);
|
|
1306
|
-
}
|
|
1307
|
-
return actions;
|
|
1308
|
-
}
|
|
1309
|
-
function writeSwarmFailedMergeBlock(workspacePath, issueId, slotIndex, block) {
|
|
1310
|
-
return updateIssueRecordForWorkspace(workspacePath, issueId.toUpperCase(), (record) => {
|
|
1311
|
-
const existingSwarm = record.swarm ?? {};
|
|
1312
|
-
const foldedBlocks = { ...existingSwarm.failedMergeBlocks ?? {} };
|
|
1313
|
-
if (existingSwarm.failedMergeBlock) foldedBlocks[String(existingSwarm.failedMergeBlock.slotIndex)] = existingSwarm.failedMergeBlock;
|
|
1314
|
-
if (block) foldedBlocks[String(slotIndex)] = block;
|
|
1315
|
-
else delete foldedBlocks[String(slotIndex)];
|
|
1316
|
-
return {
|
|
1317
|
-
...record,
|
|
1318
|
-
swarm: {
|
|
1319
|
-
...existingSwarm,
|
|
1320
|
-
failedMergeBlocks: foldedBlocks,
|
|
1321
|
-
failedMergeBlock: void 0
|
|
1322
|
-
}
|
|
1323
|
-
};
|
|
1324
|
-
}).then(() => void 0);
|
|
1325
|
-
}
|
|
1326
|
-
function recordSlotMergeFire(branchKey, now = Date.now()) {
|
|
1327
|
-
recentSlotMergeFires.set(branchKey, now + SLOT_MERGE_REFIRE_COOLDOWN_MS);
|
|
1328
|
-
}
|
|
1329
|
-
function isSlotMergeCoolingDown(branchKey, now = Date.now()) {
|
|
1330
|
-
const until = recentSlotMergeFires.get(branchKey);
|
|
1331
|
-
if (until === void 0) return false;
|
|
1332
|
-
if (until > now) return true;
|
|
1333
|
-
recentSlotMergeFires.delete(branchKey);
|
|
1334
|
-
return false;
|
|
1335
|
-
}
|
|
1336
|
-
async function dispatchNextWave(issueId, workspacePath, doc, reconciled, readiness, deps = defaultDeps, blockedSlotIndexes = /* @__PURE__ */ new Set(), blockedItemIds = /* @__PURE__ */ new Set()) {
|
|
1337
|
-
const actions = [];
|
|
1338
|
-
const mergedItemIds = new Set(reconciled.merged.map((slot) => slot.itemId));
|
|
1339
|
-
const slotEligibleIds = new Set(readiness.items.filter((item) => item.slotEligible).map((item) => item.id));
|
|
1340
|
-
const configuredMaxSlotIndex = resolveSwarmMaxSlots(issueId, (deps.getMaxSlotIndex ?? defaultGetMaxSlotIndex)());
|
|
1341
|
-
const occupiedSlotIndexes = new Set([
|
|
1342
|
-
...blockedSlotIndexes,
|
|
1343
|
-
...reconciled.inFlight.map((slot) => slot.slotIndex),
|
|
1344
|
-
...reconciled.branches.map((branch) => branch.slotIndex),
|
|
1345
|
-
...reconciled.agents.map((agent) => agent.slotIndex),
|
|
1346
|
-
...(deps.listSlotAssignments ?? listSlotAssignments)(issueId, workspacePath).map((assignment) => assignment.slotIndex),
|
|
1347
|
-
...(reconciled.superseded ?? []).map((attempt) => attempt.slotIndex)
|
|
1348
|
-
]);
|
|
1349
|
-
const maxSlotIndex = applySupersededSlotHighWater(occupiedSlotIndexes, reconciled, configuredMaxSlotIndex);
|
|
1350
|
-
if (deps.slotWorktreeExists) {
|
|
1351
|
-
for (let index = 1; index <= maxSlotIndex; index++) if (!occupiedSlotIndexes.has(index) && deps.slotWorktreeExists(`${workspacePath}-slot-${index}`)) occupiedSlotIndexes.add(index);
|
|
1352
|
-
}
|
|
1353
|
-
const sessionNames = deps.listSessionNames ? await deps.listSessionNames() : [];
|
|
1354
|
-
const inFlightItemIds = new Set(reconciled.inFlight.map((slot) => slot.itemId));
|
|
1355
|
-
const selectedItemIds = [];
|
|
1356
|
-
for (const item of getDispatchableItems(doc, mergedItemIds)) {
|
|
1357
|
-
if (blockedItemIds.has(item.id)) continue;
|
|
1358
|
-
if (!slotEligibleIds.has(item.id)) continue;
|
|
1359
|
-
if (inFlightItemIds.has(item.id)) continue;
|
|
1360
|
-
const overlapItemId = firstOverlappingItemId(item.id, [...inFlightItemIds, ...selectedItemIds], readiness);
|
|
1361
|
-
if (overlapItemId) {
|
|
1362
|
-
actions.push(`[swarm] deferred ${item.id} for ${issueId}: files_scope overlaps ${overlapItemId}`);
|
|
1363
|
-
continue;
|
|
1364
|
-
}
|
|
1365
|
-
if (!deps.registeredSlotCapacityAvailable(issueId, selectedItemIds.length)) {
|
|
1366
|
-
actions.push(`[swarm] deferred ${item.id} for ${issueId}: registered slot cap reached`);
|
|
1367
|
-
continue;
|
|
1368
|
-
}
|
|
1369
|
-
let slotIndex = null;
|
|
1370
|
-
for (;;) {
|
|
1371
|
-
const candidate = allocateSlotIndex(occupiedSlotIndexes, maxSlotIndex);
|
|
1372
|
-
if (candidate === null) break;
|
|
1373
|
-
const conflict = slotIndexConflictReason(issueId, workspacePath, candidate, sessionNames, reconciled, deps);
|
|
1374
|
-
if (!conflict) {
|
|
1375
|
-
slotIndex = candidate;
|
|
1376
|
-
break;
|
|
1377
|
-
}
|
|
1378
|
-
occupiedSlotIndexes.add(candidate);
|
|
1379
|
-
actions.push(`[swarm] slot ${candidate} occupied for ${issueId}: ${conflict} — advancing`);
|
|
1380
|
-
}
|
|
1381
|
-
if (slotIndex === null) {
|
|
1382
|
-
const occupying = [...occupiedSlotIndexes].filter((index) => index >= 1 && index <= maxSlotIndex).sort((a, b) => a - b);
|
|
1383
|
-
actions.push(`[swarm] deferred ${item.id} for ${issueId}: all slot indexes 1..${maxSlotIndex} are occupied (slots ${occupying.join(", ")}) — run \`pan swarm reset ${issueId}\` if these slots are orphans`);
|
|
1384
|
-
break;
|
|
1385
|
-
}
|
|
1386
|
-
if (!deps.tryReserveSwarmSlot()) {
|
|
1387
|
-
actions.push(`[swarm] deferred ${item.id} for ${issueId}: swarm dispatch budget exhausted`);
|
|
1388
|
-
continue;
|
|
1389
|
-
}
|
|
1390
|
-
try {
|
|
1391
|
-
await deps.applyTaskOperationToPlanFile(issueId, {
|
|
1392
|
-
type: "claim",
|
|
1393
|
-
itemId: item.id,
|
|
1394
|
-
writerId: "deacon-swarm"
|
|
1395
|
-
}, workspacePath);
|
|
1396
|
-
await deps.recordSlotAssignment(workspacePath, issueId, {
|
|
1397
|
-
slotIndex,
|
|
1398
|
-
itemId: item.id,
|
|
1399
|
-
agentId: `agent-${issueId.toLowerCase()}-slot-${slotIndex}`,
|
|
1400
|
-
branch: `feature/${issueId.toLowerCase()}-slot-${slotIndex}`
|
|
1401
|
-
});
|
|
1402
|
-
if (!(deps.shouldDispatch ?? defaultShouldDispatch)(issueId)) {
|
|
1403
|
-
await deps.applyTaskOperationToPlanFile(issueId, {
|
|
1404
|
-
type: "unblock",
|
|
1405
|
-
itemId: item.id,
|
|
1406
|
-
writerId: "deacon-swarm",
|
|
1407
|
-
reason: "dispatch halted: freeze/hold active"
|
|
1408
|
-
}, workspacePath).catch(() => void 0);
|
|
1409
|
-
await deps.clearSlotAssignment(workspacePath, issueId, slotIndex, item.id);
|
|
1410
|
-
deps.releaseSwarmSlot();
|
|
1411
|
-
actions.push(`[swarm] dispatch-halted ${item.id}: freeze/hold active`);
|
|
1412
|
-
continue;
|
|
1413
|
-
}
|
|
1414
|
-
await deps.spawnRun(issueId, "work", {
|
|
1415
|
-
workspace: workspacePath,
|
|
1416
|
-
slotIndex,
|
|
1417
|
-
slotItemId: item.id,
|
|
1418
|
-
prompt: promptForDispatchItem(issueId, doc, item),
|
|
1419
|
-
startedBy: "deacon:swarm-slot"
|
|
1420
|
-
});
|
|
1421
|
-
occupiedSlotIndexes.add(slotIndex);
|
|
1422
|
-
selectedItemIds.push(item.id);
|
|
1423
|
-
actions.push(`[swarm] dispatched ${dispatchPhaseForItem(doc, item)} slot ${slotIndex} (item ${item.id}) for ${issueId}`);
|
|
1424
|
-
} catch (error) {
|
|
1425
|
-
await deps.applyTaskOperationToPlanFile(issueId, {
|
|
1426
|
-
type: "unblock",
|
|
1427
|
-
itemId: item.id,
|
|
1428
|
-
writerId: "deacon-swarm",
|
|
1429
|
-
reason: `slot dispatch failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1430
|
-
}, workspacePath).catch(() => void 0);
|
|
1431
|
-
await deps.clearSlotAssignment(workspacePath, issueId, slotIndex, item.id);
|
|
1432
|
-
deps.releaseSwarmSlot();
|
|
1433
|
-
actions.push(`[swarm] failed-dispatch ${item.id} for ${issueId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1434
|
-
}
|
|
1435
|
-
}
|
|
1436
|
-
return actions;
|
|
1437
|
-
}
|
|
1438
|
-
function recordSlotAssignment(workspacePath, issueId, assignment) {
|
|
1439
|
-
return writeSwarmSlotAssignments(workspacePath, issueId, (existing) => [...existing.filter((slot) => slot.slotIndex !== assignment.slotIndex && slot.itemId !== assignment.itemId), {
|
|
1440
|
-
...assignment,
|
|
1441
|
-
assignedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1442
|
-
}]);
|
|
1443
|
-
}
|
|
1444
|
-
function clearSlotAssignment(workspacePath, issueId, slotIndex, itemId) {
|
|
1445
|
-
return writeSwarmSlotAssignments(workspacePath, issueId, (existing) => existing.filter((slot) => slot.slotIndex !== slotIndex && (itemId === void 0 || slot.itemId !== itemId)));
|
|
1446
|
-
}
|
|
1447
|
-
function writeSwarmSlotAssignments(workspacePath, issueId, update) {
|
|
1448
|
-
return updateIssueRecordForWorkspace(workspacePath, issueId.toUpperCase(), (record) => {
|
|
1449
|
-
const slotAssignments = update(record.swarm?.slotAssignments ?? []).filter((assignment) => Number.isInteger(assignment.slotIndex) && assignment.slotIndex > 0 && assignment.itemId.trim().length > 0).sort((a, b) => a.slotIndex - b.slotIndex);
|
|
1450
|
-
return {
|
|
1451
|
-
...record,
|
|
1452
|
-
swarm: {
|
|
1453
|
-
...record.swarm ?? {},
|
|
1454
|
-
slotAssignments
|
|
1455
|
-
}
|
|
1456
|
-
};
|
|
1457
|
-
}).then(() => void 0);
|
|
1458
|
-
}
|
|
1459
|
-
function slotIndexConflictReason(issueId, workspacePath, slotIndex, sessionNames, reconciled, deps) {
|
|
1460
|
-
const issueLower = issueId.toLowerCase();
|
|
1461
|
-
const agentId = `agent-${issueLower}-slot-${slotIndex}`;
|
|
1462
|
-
const branch = `feature/${issueLower}-slot-${slotIndex}`;
|
|
1463
|
-
if (sessionNames.includes(agentId)) return `live ${agentId} session already exists`;
|
|
1464
|
-
if (reconciled.branches.find((slotBranch) => slotBranch.slotIndex === slotIndex && slotBranch.branch === branch && !slotBranch.merged)) return `unmerged ${branch} branch already exists`;
|
|
1465
|
-
const slotWorkspacePath = `${workspacePath}-slot-${slotIndex}`;
|
|
1466
|
-
if (deps.slotWorktreeExists?.(slotWorkspacePath)) return `slot worktree already exists at ${slotWorkspacePath}`;
|
|
1467
|
-
}
|
|
1468
|
-
function dispatchPhaseForItem(doc, item) {
|
|
1469
|
-
return itemRequiresSynthesis(doc, item) && !synthesisContextForItem(item) ? "synthesis" : "implementation";
|
|
1470
|
-
}
|
|
1471
|
-
function promptForDispatchItem(issueId, doc, item) {
|
|
1472
|
-
if (!itemRequiresSynthesis(doc, item)) return void 0;
|
|
1473
|
-
const synthesisContext = synthesisContextForItem(item);
|
|
1474
|
-
if (synthesisContext) return createActiveSlice(doc, {
|
|
1475
|
-
issueId,
|
|
1476
|
-
itemId: item.id,
|
|
1477
|
-
currentItemIds: [item.id],
|
|
1478
|
-
synthesisOutputs: { [item.id]: { contextUpdate: synthesisContext } }
|
|
1479
|
-
}).prompt;
|
|
1480
|
-
const parentIds = doc.plan.edges.filter((edge) => edge.type === "blocks" && edge.to === item.id).map((edge) => edge.from);
|
|
1481
|
-
return [
|
|
1482
|
-
`SYNTHESIS PHASE for ${item.id}`,
|
|
1483
|
-
"",
|
|
1484
|
-
"Do not implement this item yet. Summarize the blocking parent outputs into a concise context update for the implementation slot.",
|
|
1485
|
-
`Blocking parents: ${parentIds.join(", ") || "(none)"}`,
|
|
1486
|
-
"",
|
|
1487
|
-
"Persist the synthesis context on the xBRIEF item metadata as synthesisContext, commit it, then stop."
|
|
1488
|
-
].join("\n");
|
|
1489
|
-
}
|
|
1490
|
-
function itemRequiresSynthesis(doc, item) {
|
|
1491
|
-
return item.metadata?.requiresSynthesis === true || blockingParentCount(doc, item.id) > 1;
|
|
1492
|
-
}
|
|
1493
|
-
function synthesisContextForItem(item) {
|
|
1494
|
-
const raw = item.metadata?.synthesisContext;
|
|
1495
|
-
return typeof raw === "string" && raw.trim().length > 0 ? raw : void 0;
|
|
1496
|
-
}
|
|
1497
|
-
/**
|
|
1498
|
-
* Lowest free slot index within the bound, derived purely from the occupied
|
|
1499
|
-
* set. Returns null — never an index above the bound — when indexes 1..bound
|
|
1500
|
-
* are all occupied (PAN-2214: unbounded allocation climbed slot-5..slot-20).
|
|
1501
|
-
*/
|
|
1502
|
-
function allocateSlotIndex(occupiedSlotIndexes, bound) {
|
|
1503
|
-
const maxIndex = Math.max(1, Math.floor(bound));
|
|
1504
|
-
for (let slotIndex = 1; slotIndex <= maxIndex; slotIndex++) if (!occupiedSlotIndexes.has(slotIndex)) return slotIndex;
|
|
1505
|
-
return null;
|
|
1506
|
-
}
|
|
1507
|
-
function firstOverlappingItemId(itemId, activeItemIds, readiness) {
|
|
1508
|
-
for (const activeItemId of activeItemIds) if ((readiness.overlapMatrix[itemId]?.[activeItemId]?.length ?? 0) > 0) return activeItemId;
|
|
1509
|
-
}
|
|
1510
|
-
/**
|
|
1511
|
-
* Whether the issue may register another slot. Counts only tmux-ALIVE slot
|
|
1512
|
-
* sessions (stale agents-table rows blocked all dispatch at zero live slots
|
|
1513
|
-
* after a reset), capped by the same swarm reserve tryReserveSwarmSlot
|
|
1514
|
-
* enforces — never maxWorkAgents (PAN-2214).
|
|
1515
|
-
*/
|
|
1516
|
-
function registeredSlotCapacityAvailable(issueId, selectedCount, liveSlotCount = countRunningSwarmSlotsForIssue(issueId), limits = getConcurrencyLimits()) {
|
|
1517
|
-
return liveSlotCount + selectedCount < limits.reservedSwarmSlots;
|
|
1518
|
-
}
|
|
1519
|
-
//#endregion
|
|
1520
|
-
export { gcMergedSlots as _, getFailedMergeBlock as a, resolveSwarmPolicy as b, isSwarmAdvanceCoolingDown as c, recordStalledSlotRecovery as d, recordSwarmAdvanceFailure as f, decideAgentAutonomousRedrive as g, registeredSlotCapacityAvailable as h, dispatchNextWave as i, mergeReadySlots as l, recordSwarmFinalizedAt as m, classifyInFlightSlots as n, getFailedMergeBlocks as o, recordSwarmAdvanceSuccess as p, coordinateSwarmSlots as r, getSwarmFinalizedAt as s, allocateSlotIndex as t, recordFailedMergeBlock as u, gcOrphanedSlots as v, listFeatureWorkspaces as y };
|
|
1521
|
-
|
|
1522
|
-
//# sourceMappingURL=deacon-swarm-BiLfNm_v.js.map
|