@overdeck/desktop 0.49.1 → 0.49.2

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.
Files changed (497) hide show
  1. package/package.json +1 -1
  2. package/server/{acceptance-criteria-Crw-xSJ3.js → acceptance-criteria-CHtDkHEL.js} +2 -2
  3. package/server/{active-dashboard-bundle-CLwfD-Om.js → active-dashboard-bundle-Byh6sP-q.js} +2 -2
  4. package/server/{activity-logger-BAVLrkR7.js → activity-logger-BWZhVphb.js} +22 -4
  5. package/server/activity-logger-Ck8qoluj.js +3 -0
  6. package/server/{advancing-selfheal-BQiJ7mIH.js → advancing-selfheal-65W4yUQi.js} +6 -6
  7. package/server/{agent-gc-5E0lgxI1.js → agent-gc-BNUudFnt.js} +10 -10
  8. package/server/agent-idle-ONBssBN_.js +745 -0
  9. package/server/{agent-state-Bb3UUxQm.js → agent-state-BJhGIJZe.js} +421 -135
  10. package/server/agent-state-CM8iVw5B.js +3 -0
  11. package/server/{agent-state-service-BFbttwRA.js → agent-state-service-CiIuwzIs.js} +5 -5
  12. package/server/{agent-state-service-keg-x1bT.js → agent-state-service-CzHfoqKQ.js} +1 -1
  13. package/server/agents-DpCuoF65.js +3 -0
  14. package/server/{agents-CqQJW75N.js → agents-jXgqpHca.js} +8 -8
  15. package/server/archive-planning-BW4MKNI7.js +2 -0
  16. package/server/{archive-planning-BwEhu9Oq.js → archive-planning-CGkU6UeL.js} +20 -135
  17. package/server/{artifact-index-jobs-C6Lg2rKm.js → artifact-index-jobs-Ck4NRRkY.js} +3 -3
  18. package/server/{assemble-DyTp2gSB.js → assemble-CyvEBmmq.js} +28 -9
  19. package/server/{auto-spawn-consent-BDfe4qz0.js → auto-spawn-consent-Dc4mtM-B.js} +8 -7
  20. package/server/{backlog-auto-trigger-DuOGpdDW.js → backlog-auto-trigger-CCEpr4YT.js} +3 -3
  21. package/server/{behavior-Bitko0mD.js → behavior-BiCQzqyT.js} +3 -3
  22. package/server/{bridge-pool-patrol-DiHEd13O.js → bridge-pool-patrol-Ce8rNPym.js} +2 -2
  23. package/server/{briefing-freshness-CDJcmHHZ.js → briefing-freshness-e_OEYZEe.js} +2 -2
  24. package/server/{build-info-DTX8JwVP.js → build-info-BRw4QlYO.js} +3 -3
  25. package/server/build-info-Bj2vQEMh.js +2 -0
  26. package/server/{checkpoint-manager-CKg1tn34.js → checkpoint-manager-CKr42Usw.js} +1 -1
  27. package/server/{checkpoint-manager-BlOOdzLF.js → checkpoint-manager-DOwRGFff.js} +26 -9
  28. package/server/checkpoint-worker.js +1 -1
  29. package/server/{checkpoints-DRALkfDS.js → checkpoints-Cb6CWT4S.js} +1 -1
  30. package/server/{checkpoints-BGfl0cHM.js → checkpoints-Cszp_0Np.js} +2 -2
  31. package/server/{claude-hooks-provision-B_tv3wzE.js → claude-hooks-provision-C5JHpxTS.js} +1 -1
  32. package/server/{claude-hooks-provision-BlGv6twJ.js → claude-hooks-provision-Cer2eFfj.js} +2 -2
  33. package/server/{claude-permissions-aHgDcZi5.js → claude-permissions-Bc5kjX1q.js} +2 -2
  34. package/server/{claude-settings-overlay-CYOvFE3A.js → claude-settings-overlay-C7rWsnya.js} +1 -1
  35. package/server/{claude-settings-overlay-T2LWLteV.js → claude-settings-overlay-m-VVZej1.js} +2 -2
  36. package/server/cli-BRuzUT_I.js +2 -0
  37. package/server/{cli-Do8UpLoI.js → cli-BmczsfD6.js} +11 -11
  38. package/server/{cliproxy-CX6jHRDP.js → cliproxy-BpYpkogS.js} +52 -17
  39. package/server/cliproxy-_yUU0HRY.js +3 -0
  40. package/server/{close-issue-J0_eWYT1.js → close-issue-CxvRD0UI.js} +5 -5
  41. package/server/{closed-issue-reaper-bFppuk6F.js → closed-issue-reaper-nMLRi5de.js} +13 -12
  42. package/server/{closed-issue-reaper-Cl2h9AfT.js → closed-issue-reaper-omOcUDBl.js} +1 -1
  43. package/server/{codex-icapA4om.js → codex-DZhFfcWu.js} +1 -1
  44. package/server/{codex-OOea7lXs.js → codex-KaSKE-R3.js} +16 -10
  45. package/server/{compaction-continuation-D5voR1ME.js → compaction-continuation-Bjfi70G-.js} +3 -3
  46. package/server/{config-Cjleh3_U.js → config-CH1AqqIQ.js} +1 -1
  47. package/server/{config-DC75T4Mr.js → config-Doq_tF-f.js} +2 -2
  48. package/server/{config-tucKBCCc.js → config-ZGjvuR6J.js} +2 -2
  49. package/server/{config-yaml-BwOEANMr.js → config-yaml-D9nfpEx1.js} +33 -8
  50. package/server/{conflict-gate-DlpWCMd7.js → conflict-gate-D4XCtrm2.js} +1 -1
  51. package/server/{conflict-gate-D2L1kZeL.js → conflict-gate-DcUTY4Gb.js} +4 -4
  52. package/server/{context-layers-CSPGc2Hb.js → context-layers-BBTKP-Y4.js} +3 -3
  53. package/server/context-layers-BGj2Y9l3.js +4 -0
  54. package/server/{continue-U3Af0jUq.js → continue-i7Revg8D.js} +3 -3
  55. package/server/{control-settings-5k6ixdFW.js → control-settings-BMoDHY1G.js} +6 -6
  56. package/server/{conversation-compaction-CSpVpxN6.js → conversation-compaction-D4VOmF7p.js} +8 -8
  57. package/server/{conversation-compaction-Ciit9O6k.js → conversation-compaction-DzIjYMfg.js} +1 -1
  58. package/server/{conversation-service-BxrB5lUT.js → conversation-service-CzZUJFEx.js} +1 -1
  59. package/server/{conversation-service-BteE4ELK.js → conversation-service-tQCIbBVZ.js} +6 -6
  60. package/server/{conversations-DhwxsOru.js → conversations-C75EFFjf.js} +12 -7
  61. package/server/conversations-bFDaD5YN.js +3 -0
  62. package/server/{cost-Bnf9NUC5.js → cost-BCWEkvro.js} +3 -3
  63. package/server/{cost-CQKI6OCu.js → cost-CiIwxH1D.js} +2 -2
  64. package/server/{cost-sync-B-ADeXKY.js → cost-sync-DOkdE_yB.js} +3 -3
  65. package/server/{dag-DI9LaK_q.js → dag-BPc74hwj.js} +6 -19
  66. package/server/{dangerous-git-ops-akhA3iyF.js → dangerous-git-ops-By9iguTP.js} +1 -1
  67. package/server/dashboard-db-worker.js +7 -7
  68. package/server/{deacon-TPYssFYt.js → deacon-B24dNzr8.js} +1774 -171
  69. package/server/deacon-CzSZMtb-.js +4 -0
  70. package/server/{deacon-canonical-state-DFYymrDw.js → deacon-canonical-state-CkvxRPck.js} +3 -3
  71. package/server/{deacon-event-client-Te5v10-b.js → deacon-event-client-BYIQBu0T.js} +1 -1
  72. package/server/{deacon-event-client-BKOL4AcL.js → deacon-event-client-Do6Z2gKl.js} +2 -2
  73. package/server/{deacon-nudge-log-BtlTWgWu.js → deacon-nudge-log-CzM9JA9t.js} +1 -1
  74. package/server/{deacon-pending-lifecycle-DVHjOLje.js → deacon-pending-lifecycle-BObEdT-L.js} +3 -3
  75. package/server/deacon.js +11 -11
  76. package/server/dead-end-trip-6V_CwveT.js +2 -0
  77. package/server/{dead-end-trip-P0IF1O0E.js → dead-end-trip-CnVmjnya.js} +3 -3
  78. package/server/delivery-gyce0vQ7.js +3 -0
  79. package/server/{deploy-patrol-BXjlvoV3.js → deploy-patrol-CEwwEYDM.js} +8 -8
  80. package/server/deploy-queue-CjLErpgw.js +2 -0
  81. package/server/{deploy-queue-o7shYg1j.js → deploy-queue-r96ojDI3.js} +2 -2
  82. package/server/{deploy-window-CNT6fOff.js → deploy-window-D_3hhfxt.js} +4 -4
  83. package/server/{deploy-window-BMk5_oX6.js → deploy-window-DeJK8mTK.js} +1 -1
  84. package/server/{dev-supervisor-SR1CLOAK.js → dev-supervisor-DZWwpENk.js} +2 -2
  85. package/server/{devcontainer-renderer-enMmNDFa.js → devcontainer-renderer-d-9dCV_2.js} +3 -3
  86. package/server/{dist-CPTO_zMR.js → dist-DsLAsFSh.js} +1 -1
  87. package/server/dist-fCA6y2bH.js +3 -0
  88. package/server/{docker-B7qUZptz.js → docker-B2mUBzGk.js} +3 -3
  89. package/server/{docker-KR3zSFKY.js → docker-CRPHBylA.js} +1 -1
  90. package/server/{dod-gK835UMf.js → dod-DWtilRLx.js} +1 -1
  91. package/server/{done-preflight-CksRvh49.js → done-preflight-BDVdWed5.js} +1 -1
  92. package/server/{done-preflight-Bk8aExAL.js → done-preflight-D4ukUf-S.js} +5 -5
  93. package/server/{driver-CmsY2RLl.js → driver-BtcFz-qu.js} +14 -3
  94. package/server/{durable-review-pipeline-DgYHucN2.js → durable-review-pipeline-B3OS2_He.js} +11 -2
  95. package/server/durable-review-pipeline-CaCbEJSt.js +3 -0
  96. package/server/{ensure-devcontainer-ojerEqQg.js → ensure-devcontainer-BUeBRjmm.js} +4 -4
  97. package/server/{ensure-devcontainer-BQ4YizSH.js → ensure-devcontainer-rGSh0JHK.js} +1 -1
  98. package/server/{esm-shims-1htPASWs.js → esm-shims-oAaKIa-a.js} +1 -1
  99. package/server/{event-store-D7qcJXuZ.js → event-store-BCSgMubf.js} +5 -5
  100. package/server/{event-store-BgEjNsvk.js → event-store-Db4w4YIY.js} +1 -1
  101. package/server/{event-store-provider-BKvk2rDj.js → event-store-provider-DlSQND3V.js} +1 -1
  102. package/server/{events-BIKGJZOT.js → events-B6zioJA_.js} +3 -3
  103. package/server/{dist-src-BM9eudEd.js → factory-BrdqXBeK.js} +714 -2
  104. package/server/{feature-registry-storage-ewNSIVsQ.js → feature-registry-storage-zh3ZXW6f.js} +3 -3
  105. package/server/{features-CGopJXdU.js → features-BGntOWdy.js} +2 -2
  106. package/server/{feedback-stuck-retirement-B8-fX7NA.js → feedback-stuck-retirement-DpA5u1kt.js} +2 -2
  107. package/server/{feedback-target-Ci6N5p4G.js → feedback-target-D7GxdUYG.js} +10 -10
  108. package/server/{feedback-target-CkyLYohm.js → feedback-target-Ddqk93NF.js} +1 -1
  109. package/server/{feedback-writer-D4ULO4qG.js → feedback-writer-C1gCLFmp.js} +5 -5
  110. package/server/{feedback-writer-DfuVjvH0.js → feedback-writer-CH2846DP.js} +1 -1
  111. package/server/{flywheel-C7yek87O.js → flywheel-CjW2L7BS.js} +79 -29
  112. package/server/{flywheel-DXI_WITn.js → flywheel-HJt7QdWP.js} +1 -1
  113. package/server/{flywheel-merge-order-C5m5bYBc.js → flywheel-merge-order-4fNRN2F2.js} +1 -1
  114. package/server/{flywheel-merge-order-CXfU4M6l.js → flywheel-merge-order-D_yyAlND.js} +7 -7
  115. package/server/{flywheel-BwYPDlhK.js → flywheel-v1cCOBx-.js} +14 -14
  116. package/server/{forge-DYX9sKzG.js → forge-RVTCK_5X.js} +2 -2
  117. package/server/forge-bvak6vXJ.js +2 -0
  118. package/server/{from-DAdMxC29.js → from-BnLgKYvw.js} +1 -1
  119. package/server/{fs-lock-cw25uO_E.js → fs-lock-C7J-ugIf.js} +2 -2
  120. package/server/{fts-operations-D_rzLxX5.js → fts-operations-CU0B5WUx.js} +3 -3
  121. package/server/git-info-BSrI9owC.js +148 -0
  122. package/server/{git-utils-Y0zG25ez.js → git-utils-CsKV0Dis.js} +1 -1
  123. package/server/{git-utils-DV4B9TRl.js → git-utils-DW8-jIUJ.js} +4 -4
  124. package/server/{github-app-4UX8VIr8.js → github-app-7ywLhuZO.js} +2 -2
  125. package/server/{github-app-C33lDk9Z.js → github-app-Oi5hdn1n.js} +1 -1
  126. package/server/{github-client-nPj5ckZO.js → github-client-Cy0fSj1a.js} +1 -1
  127. package/server/{github-client-DkJVR908.js → github-client-DAbuXLuk.js} +3 -3
  128. package/server/{github-pr-lookup-C9Vokb0W.js → github-pr-lookup-Dhh3ec1V.js} +2 -2
  129. package/server/{harness-binary-BgXYDo2Z.js → harness-binary-tMmgJfC1.js} +2 -2
  130. package/server/{harness-resolve-1NZcVx7n.js → harness-resolve-DusNpVEe.js} +4 -4
  131. package/server/{health-events-jMfxrElt.js → health-events-BYDZ9n2i.js} +1 -1
  132. package/server/{health-events-DlX_FVAB.js → health-events-DNw9Mzw9.js} +2 -2
  133. package/server/{hooks-W3REcb3h.js → hooks-B4wj32l2.js} +1 -1
  134. package/server/{hooks-NQ19vvlB.js → hooks-BjBjxqNh.js} +2 -2
  135. package/server/{hume-BFkid2PO.js → hume-BP9YbxaE.js} +2 -2
  136. package/server/hume-TYTb6fDU.js +3 -0
  137. package/server/{identity-Bwh6VGeL.js → identity-C23uY8dZ.js} +3 -3
  138. package/server/{idle-stack-reaper-BeU_KxWx.js → idle-stack-reaper-BSxb1bln.js} +4 -4
  139. package/server/{idle-stack-reaper-CHtCNpvd.js → idle-stack-reaper-Bw0rU9GC.js} +1 -1
  140. package/server/{in-flight-guard-pcwXKLGz.js → in-flight-guard-DuxabAHT.js} +1 -1
  141. package/server/{infra-KTp9KV9u.js → infra-CHIvOb9q.js} +30 -7
  142. package/server/{injection-67YyU6SC.js → injection-BYUt8ml1.js} +8 -8
  143. package/server/{injection-BxbZKPDh.js → injection-BviePcm3.js} +1 -1
  144. package/server/inspect-agent-JFEaYTRa.js +2 -0
  145. package/server/{inspect-agent-VHSihlb7.js → inspect-agent-sV_19NxZ.js} +12 -12
  146. package/server/{internal-token-B-z-sGBH.js → internal-token-BOtIRJU7.js} +1 -1
  147. package/server/{internal-token-zY75jrRJ.js → internal-token-DoVzb4b7.js} +2 -2
  148. package/server/{io-DfvO2xyh.js → io-DKrWd3gX.js} +5 -5
  149. package/server/{issue-closed-dvEWKO7Q.js → issue-closed-6RQsAjDX.js} +7 -7
  150. package/server/{issue-lifecycle-3N8XF7lP.js → issue-lifecycle-D9nLErvS.js} +206 -29
  151. package/server/{issue-lifecycle-BI6jAfp8.js → issue-lifecycle-DOPVv7xz.js} +1 -1
  152. package/server/{issue-service-singleton-BN_2MXp4.js → issue-service-singleton-B2xy-IS9.js} +124 -11
  153. package/server/{issue-service-singleton-CL6hESX2.js → issue-service-singleton-CvgNAWqK.js} +1 -1
  154. package/server/issue-title-fallback-DTSCQVu0.js +120 -0
  155. package/server/{issues-CkvUoAnq.js → issues-e_Ck1Ln2.js} +2 -2
  156. package/server/{jsonl-parser-CrEb2PWr.js → jsonl-parser-DqxVCZ1k.js} +3 -3
  157. package/server/jsonl-resolver-07OS3qOr.js +324 -0
  158. package/server/{kimi-code-C26gmGxM.js → kimi-code-BjtAHIz1.js} +14 -12
  159. package/server/{kimi-code-DoMoGqIu.js → kimi-code-vtXl2DR5.js} +1 -1
  160. package/server/{kimi-parser-Dmhy3UlR.js → kimi-parser-B1lgy2Vt.js} +2 -2
  161. package/server/{label-cleanup-X2lWfghH.js → label-cleanup-D2zUMasf.js} +3 -3
  162. package/server/{lifecycle-Bg44O-9x.js → lifecycle-0NOEzomy.js} +2 -2
  163. package/server/{lifecycle-B0rL38D3.js → lifecycle-DaCovZwn.js} +6 -6
  164. package/server/{lifecycle-io-CCBpRv5m.js → lifecycle-io-6WL46dsB.js} +5 -5
  165. package/server/{lifecycle-io-DQDU0apV.js → lifecycle-io-BBMTaP7S.js} +1 -1
  166. package/server/{linear-client-B0cIkTs4.js → linear-client-7fQThJTc.js} +3 -3
  167. package/server/{linear-client-6V2E-DSa.js → linear-client-BTGApNLo.js} +1 -1
  168. package/server/{linear-mcp-auth-LCo9AWUd.js → linear-mcp-auth-B8pYRsiU.js} +1 -1
  169. package/server/{linear-mcp-auth-Dsu9Io9r.js → linear-mcp-auth-Nk5s3L9M.js} +5 -5
  170. package/server/memory-fts-worker.js +1 -1
  171. package/server/{memory-governor-A4O6vI9d.js → memory-governor-Cqvbusr4.js} +14 -14
  172. package/server/{memory-pressure-patrol-BWlWywmA.js → memory-pressure-patrol-DPb8foam.js} +5 -5
  173. package/server/{merge-BGWcBxku.js → merge-BB_bjJ9a.js} +1 -1
  174. package/server/{merge-vz80RvSE.js → merge-FZ78_cEz.js} +3 -3
  175. package/server/{merge-agent-GWhmnxFk.js → merge-agent-B3jRrlS1.js} +37 -33
  176. package/server/{merge-agent-BRSz26Oh.js → merge-agent-BuoC_PRZ.js} +2 -2
  177. package/server/{merge-batch-CFMEtTxv.js → merge-batch-B8bVjFWS.js} +1 -1
  178. package/server/{merge-completeness-CP347umA.js → merge-completeness-DQt7Qa7i.js} +4 -4
  179. package/server/{merge-completeness-7ajHAIR-.js → merge-completeness-DkdabVch.js} +1 -1
  180. package/server/merge-ops-DabXHp2i.js +2 -0
  181. package/server/merge-rebase-CXq0qsgR.js +2 -0
  182. package/server/{merge-rebase-C5htyEEH.js → merge-rebase-qq40s91P.js} +2 -2
  183. package/server/{merge-set-DsGW8fmc.js → merge-set-BTNYvxM3.js} +1 -1
  184. package/server/{merge-set-eiE2nC6C.js → merge-set-BmRRflt0.js} +4 -4
  185. package/server/{merge-sync-CM2-myXu.js → merge-sync-0m2Q087q.js} +1 -1
  186. package/server/{merge-sync-Ct0-cxMX.js → merge-sync-CJpOa0cZ.js} +2 -2
  187. package/server/{merge-train-deps-LXHGK61n.js → merge-train-deps-CH5Mr3vN.js} +4 -4
  188. package/server/{merge-train-BOu3fN7O.js → merge-train-iwKqjtCF.js} +4 -4
  189. package/server/{merge-verification-BRp08IzI.js → merge-verification-JJc5GC2t.js} +6 -6
  190. package/server/{merged-docker-cleanup-worker-CwldDjHV.js → merged-docker-cleanup-worker-BOqWA373.js} +4 -4
  191. package/server/{merged-docker-cleanup-worker-C8eGn78a.js → merged-docker-cleanup-worker-CrhTdxZV.js} +1 -1
  192. package/server/messaging-nuwStbdQ.js +3 -0
  193. package/server/{multipart-parser-OAuW7824.js → multipart-parser-DxuW_rZV.js} +2 -2
  194. package/server/{no-resume-mode-MWI6pnrK.js → no-resume-mode-xuYLFhLw.js} +1 -1
  195. package/server/node_modules/.package-lock.json +11 -11
  196. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/AGENTS.md +14 -0
  197. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/CLAUDE.md +14 -0
  198. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/README.md +10 -3
  199. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/ai-docs/src/40_sql/10_basics.ts +175 -0
  200. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/ai-docs/src/40_sql/index.md +6 -0
  201. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/ai-docs/src/51_http-server/10_basics.ts +3 -1
  202. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/ai-docs/src/51_http-server/20_testing.ts +100 -0
  203. 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
  204. 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
  205. 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
  206. 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
  207. 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
  208. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/ai-docs/src/70_cli/10_basics.ts +27 -3
  209. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeChildProcessSpawner.d.ts.map +1 -1
  210. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeChildProcessSpawner.js +10 -9
  211. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeChildProcessSpawner.js.map +1 -1
  212. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeSocketServer.js +4 -4
  213. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeSocketServer.js.map +1 -1
  214. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeStream.d.ts.map +1 -1
  215. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeStream.js +10 -4
  216. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/NodeStream.js.map +1 -1
  217. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/internal/nodeChildProcessSpawner.d.ts +4 -0
  218. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/internal/nodeChildProcessSpawner.d.ts.map +1 -0
  219. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/internal/nodeChildProcessSpawner.js +10 -0
  220. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/dist/internal/nodeChildProcessSpawner.js.map +1 -0
  221. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/package.json +4 -4
  222. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/src/NodeChildProcessSpawner.ts +16 -11
  223. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/src/NodeSocketServer.ts +4 -4
  224. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/src/NodeStream.ts +10 -4
  225. package/server/node_modules/@effect/platform-node/node_modules/@effect/platform-node-shared/src/internal/nodeChildProcessSpawner.ts +16 -0
  226. package/server/node_modules/ansi-regex/index.js +3 -2
  227. package/server/node_modules/ansi-regex/package.json +1 -1
  228. package/server/node_modules/gaxios/build/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  229. package/server/node_modules/gaxios/build/esm/tsconfig.tsbuildinfo +1 -1
  230. package/server/node_modules/gaxios/package.json +3 -3
  231. package/server/{orphan-proposed-reconciler-cV3URUqk.js → orphan-proposed-reconciler-Dmk0kO_p.js} +24 -23
  232. package/server/{orphan-proposed-reconciler-BAE5AZ_e.js → orphan-proposed-reconciler-gf4TxfZb.js} +2 -2
  233. package/server/package-lock.json +12 -12
  234. package/server/package.json +1 -1
  235. package/server/{pan-dir-DDd91kMb.js → pan-dir-BMda7tQj.js} +5 -5
  236. package/server/{deacon-merge-BOGFEV8_.js → parked-residue-BiHb8cD7.js} +150 -35
  237. package/server/{paths-CRLnDgcI.js → paths-DEe9j-kw.js} +2 -2
  238. package/server/{pending-lifecycle-claim-CYgMiDAP.js → pending-lifecycle-claim-J5uIIJPu.js} +2 -2
  239. package/server/{pickup-BjJsSX12.js → pickup-D1UbSDPd.js} +1 -1
  240. package/server/{pipeline-agent-reader-BLc43dVJ.js → pipeline-agent-reader-D-6okryb.js} +5 -5
  241. package/server/{pipeline-membership-5qlRz5Qg.js → pipeline-membership-CCbgBzNC.js} +1 -1
  242. package/server/{pipeline-membership-BHZp_ShY.js → pipeline-membership-PGX3Pe8V.js} +1 -1
  243. package/server/{pipeline-membership-gather-CGFY1v-y.js → pipeline-membership-gather-BK4dzh0X.js} +17 -12
  244. package/server/{pipeline-membership-gather-WhRc1yke.js → pipeline-membership-gather-BRhU7XPx.js} +1 -1
  245. package/server/{pipeline-notifier-BmsLWM_2.js → pipeline-notifier-BNAV9kpa.js} +2 -2
  246. package/server/{pipeline-notifier-C4fZ2ito.js → pipeline-notifier-DvHLaXKb.js} +1 -1
  247. package/server/{post-merge-lifecycle-worker-KK1RTKRE.js → post-merge-lifecycle-worker-DAWgzXQA.js} +3 -3
  248. package/server/{post-merge-state-_Lj3LDLh.js → post-merge-state-DC2_0t12.js} +4 -4
  249. package/server/prd-locations-BbAvqQmT.js +124 -0
  250. package/server/{project-pipelines-CCkebHOu.js → project-pipelines-By_5WcT4.js} +2 -2
  251. package/server/{project-repos-B4MK48j4.js → project-repos--QeCg7yQ.js} +29 -3
  252. package/server/project-repos-3bI6t4fO.js +3 -0
  253. package/server/project-resource-refresh-queue-BaZC79S3.js +2 -0
  254. package/server/project-resource-refresh-queue-x-K9mvpP.js +865 -0
  255. package/server/{projects-DvPEAP18.js → projects-LftaVK99.js} +1 -1
  256. package/server/{prompts-BiS5I2tZ.js → prompts-BotGu-6W.js} +2 -2
  257. package/server/{providers-DrfK0Ip8.js → providers-BL1I66sM.js} +7 -7
  258. package/server/providers-Dqgz3MY5.js +3 -0
  259. package/server/public/assets/{chunk-BO2N2NFS-GtVe_o56.js → chunk-BO2N2NFS-D5Fz5jND.js} +4 -4
  260. package/server/public/assets/{diagram-OG6HWLK6-BvhcYYHc.js → diagram-OG6HWLK6-Eux0gWFq.js} +1 -1
  261. package/server/public/assets/{dist-D0ryefak.js → dist-C3zShwhA.js} +1 -1
  262. package/server/public/assets/{dist-CSmUXazd.js → dist-D-JX_u7m.js} +3 -3
  263. package/server/public/assets/{ganttDiagram-6RSMTGT7-BXA51DzM.js → ganttDiagram-6RSMTGT7-UH3aweia.js} +1 -1
  264. package/server/public/assets/{highlighted-body-OFNGDK62-mlV4EpWt.js → highlighted-body-OFNGDK62-ccIQ-WXS.js} +1 -1
  265. package/server/public/assets/index-2wV4ipy_.css +1 -0
  266. package/server/public/assets/index-BTVcdPve.js +860 -0
  267. package/server/public/assets/{linear-BPE7oswm.js → linear-Cnnu4YQy.js} +1 -1
  268. package/server/public/assets/mermaid-GHXKKRXX-Bjto8iJh.js +1 -0
  269. package/server/public/assets/{pieDiagram-4H26LBE5-BguGGV3S.js → pieDiagram-4H26LBE5-BD8-Tye6.js} +1 -1
  270. package/server/public/assets/{prod-aKDYUrXQ.js → prod-Ca6aKMts.js} +4 -4
  271. package/server/public/assets/{quadrantDiagram-W4KKPZXB-Bx3i4B6H.js → quadrantDiagram-W4KKPZXB-BmSrVyFD.js} +1 -1
  272. package/server/public/assets/{sankeyDiagram-5OEKKPKP-B5vuLjA4.js → sankeyDiagram-5OEKKPKP-CEGy8Das.js} +1 -1
  273. package/server/public/assets/{xychartDiagram-2RQKCTM6-HPlpkqsN.js → xychartDiagram-2RQKCTM6-VnQ8iY8s.js} +1 -1
  274. package/server/public/index.html +2 -2
  275. package/server/{pull-requests-BcHIsFJv.js → pull-requests-Cp_FDT8-.js} +3 -3
  276. package/server/pull-requests-jVGcVq5G.js +2 -0
  277. package/server/rally-CxhVgIQ6.js +3 -0
  278. package/server/{rally-api-ShZ4kvn0.js → rally-api-CqAIJ8RX.js} +2 -2
  279. package/server/{rally-api-u_vkr5c_.js → rally-api-Ij1Zt0NI.js} +1 -1
  280. package/server/{rally-B1OMtzch.js → rally-bQpBzUNf.js} +3 -3
  281. package/server/{rally-client-DgZvUZqX.js → rally-client-CN5vh4Ac.js} +1 -1
  282. package/server/{rally-client-D6Feq1Ka.js → rally-client-qKbCNRVW.js} +5 -5
  283. package/server/{reap-terminal-sessions-CRfiXLY0.js → reap-terminal-sessions-BaDSNR-k.js} +2 -2
  284. package/server/{reap-terminal-sessions-D7f3zSE9.js → reap-terminal-sessions-DgEIKMhH.js} +2 -2
  285. package/server/{rebuild-stack-DKxOnkpE.js → rebuild-stack-BNOMVh7C.js} +7 -7
  286. package/server/{rebuild-stack-CCwKHZb6.js → rebuild-stack-DrMyA_mA.js} +2 -2
  287. package/server/{reconstruct-cache-BP8UIKt7.js → reconstruct-cache-mxIYCnqs.js} +7 -7
  288. package/server/{record-By-wp6pg.js → record-Ug18Cp4V.js} +1 -1
  289. package/server/{record-update-ByGtIlUK.js → record-update-WyhsREoH.js} +1 -1
  290. package/server/{record-update-D23jPU6b.js → record-update-dBGxL9OC.js} +8 -6
  291. package/server/{recovery-trip-C4dTl8DO.js → recovery-trip-BKLrL6NX.js} +43 -10
  292. package/server/{recovery-trip-qloOYOFz.js → recovery-trip-wFAixKsg.js} +1 -1
  293. package/server/{release-engine-Crc0Tjx-.js → release-engine-D9gaCBn9.js} +5 -5
  294. package/server/{release-set-DDXwbIK7.js → release-set-DPHHzEGx.js} +3 -3
  295. package/server/{remote-CBpLi4Yy.js → remote-BU6ONLpv.js} +3 -3
  296. package/server/{remote-oEMfXlwT.js → remote-BUEeUic6.js} +3 -3
  297. package/server/{remote-agents-DQVGZVQ9.js → remote-agents-BVtASiOF.js} +1 -1
  298. package/server/{remote-agents-Bgtc2nOO.js → remote-agents-CSaTLi3u.js} +6 -6
  299. package/server/{remote-completion-DxUJ5HKR.js → remote-completion-CBV3b9TI.js} +13 -13
  300. package/server/{resolver-C8rooxoz.js → resolver-DvSMXty7.js} +31 -8
  301. package/server/{resolver-CuAULbLs.js → resolver-gxv97jsQ.js} +2 -2
  302. package/server/resume-DvHuF-bm.js +3 -0
  303. package/server/review-agent-DgkUPRx0.js +3 -0
  304. package/server/{review-agent-7C2w5CzU.js → review-agent-esZ0QXdY.js} +43 -55
  305. package/server/{review-artifacts-BJeEfm2r.js → review-artifacts-DGGEobLp.js} +6 -6
  306. package/server/{review-convoy-liveness-DfF9eXjI.js → review-convoy-liveness-DmO8dIBH.js} +20 -11
  307. package/server/{review-run-recovery-7BKt2Es0.js → review-run-recovery-Ct0q7FkE.js} +3 -3
  308. package/server/{review-run-recovery-ZjuDTNhZ.js → review-run-recovery-DHiiw7d8.js} +1 -1
  309. package/server/{review-status-CUnjjOUu.js → review-status-C_kQeeX0.js} +1 -1
  310. package/server/{review-status-emit-Cg4tOb8U.js → review-status-emit-BZz1Y_22.js} +3 -3
  311. package/server/{review-status-enrichment-D-rQshu6.js → review-status-enrichment-BWH0XW_m.js} +3 -3
  312. package/server/{review-status-source-DSn0glLa.js → review-status-source-D2PCWS6E.js} +1 -1
  313. package/server/{review-status-source-Ct912fv_.js → review-status-source-Jq0BXmn3.js} +1 -1
  314. package/server/{review-status-sync-B7V_Gg51.js → review-status-sync-2C9lk85r.js} +2 -2
  315. package/server/{review-status-sync-YthpOH_q.js → review-status-sync-Bq00Loey.js} +1 -1
  316. package/server/{review-status-DBnR5t4z.js → review-status-yOGD2MuK.js} +86 -27
  317. package/server/{review-verdict-feedback-DqXTuJk8.js → review-verdict-feedback-Brjaxoda.js} +1 -1
  318. package/server/{review-verdict-feedback-C-dBon_-.js → review-verdict-feedback-CE_tr2iQ.js} +8 -8
  319. package/server/{review-verdict-writer-jldSh3Bm.js → review-verdict-writer-CD-4kDVx.js} +1 -1
  320. package/server/{review-verdict-writer-CKaJWp75.js → review-verdict-writer-Ca2V7QSY.js} +7 -7
  321. package/server/{rollup-DZwH4CLs.js → rollup--g9ik1XQ.js} +1 -1
  322. package/server/{rollup-QCwYcBdP.js → rollup-B6g9Nr6L.js} +8 -8
  323. package/server/{scanner-2aHeLC3W.js → scanner-YxIv-fG1.js} +8 -8
  324. package/server/{search-DwHYaj66.js → search-DqMN4__-.js} +2 -2
  325. package/server/{secret-redaction-B5G1xZ3k.js → secret-redaction-DLZ-VqHq.js} +1 -1
  326. package/server/{sequence-io-POKWdusG.js → sequence-io--b3_PsWq.js} +4 -4
  327. package/server/{sequencer-agent-DS00KHVm.js → sequencer-agent-CqouKVZG.js} +6 -6
  328. package/server/server.js +1115 -1269
  329. package/server/{service-BLb_CyPL.js → service-CEp-3iow.js} +64 -63
  330. package/server/{session-fork-DcTzVwex.js → session-fork-GtoeCh2H.js} +2 -2
  331. package/server/{settings-Clw8UVNs.js → settings-CLQcdkoD.js} +2 -2
  332. package/server/{settings-B9-H2K_E.js → settings-Ch2pCVtt.js} +3 -3
  333. package/server/settings-DhtPDmmI.js +2 -0
  334. package/server/{shadow-engineering-C6oO_PiR.js → shadow-engineering-BxiFrIKv.js} +3 -3
  335. package/server/{shadow-state-CEGrrECe.js → shadow-state-CSA1vtxr.js} +2 -2
  336. package/server/{shadow-state-e7250VUx.js → shadow-state-nGhCNXT2.js} +1 -1
  337. package/server/{shadow-utils-xFk2Wusb.js → shadow-utils-7q5QDmMj.js} +2 -2
  338. package/server/{ship-log-7BnQHuKU.js → ship-log-ie0A_SqV.js} +1 -1
  339. package/server/{ship-record-CwUX6Afo.js → ship-record-BM3oVvnL.js} +7 -7
  340. package/server/{ship-record-BgUPnpT0.js → ship-record-DHWH1hLz.js} +1 -1
  341. package/server/{ship-status-Ce3_3edi.js → ship-status-BEkddXMT.js} +2 -2
  342. package/server/{smart-compaction-BmfIi3oL.js → smart-compaction-BkzjVpWL.js} +1 -1
  343. package/server/{smart-compaction-Dy0gw1VH.js → smart-compaction-D0TE1lBD.js} +7 -7
  344. package/server/{spawn-planning-session-nH3b4Drz.js → spawn-planning-session-CkGweSCC.js} +19 -19
  345. package/server/{spawn-planning-session-CfhxRJoY.js → spawn-planning-session-s406rw1N.js} +2 -2
  346. package/server/{specialist-completion-CC1XJbTx.js → specialist-completion-CTAjwH5j.js} +1 -1
  347. package/server/{specialist-context-cHwpcXSh.js → specialist-context-CKasRfYu.js} +5 -5
  348. package/server/{specialist-handoff-logger-GqnGSYoJ.js → specialist-handoff-logger-DrjrOmmn.js} +2 -2
  349. package/server/{specialist-logs-5OTnrV91.js → specialist-logs-Du6quZ0_.js} +3 -3
  350. package/server/{specialists-xXcJHAyg.js → specialists-B-4zyE4Y.js} +1 -1
  351. package/server/{specialists-8LcQi9Np.js → specialists-CuDWiNdB.js} +21 -272
  352. package/server/{specialists-DocAK-7A.js → specialists-b0dMMjWq.js} +148 -685
  353. package/server/specialists-registry-1y6Rt_F1.js +3 -0
  354. package/server/specialists-registry-BYjs04iK.js +277 -0
  355. package/server/specialists-x-kPMhrL.js +4 -0
  356. package/server/specs-IYsFlM-L.js +3 -0
  357. package/server/{src-DudQNYVw.js → src-CY2Wl8IX.js} +337 -6
  358. package/server/{src-C2TAxwki.js → src-CZsPs61V.js} +6 -6
  359. package/server/{src-DUVvEA8Q.js → src-DeQwpuh6.js} +3 -3
  360. package/server/{stack-health-DKT4ySnA.js → stack-health-BQFSJc0l.js} +3 -3
  361. package/server/{stack-health-CbyiYS9H.js → stack-health-ypIKtkbE.js} +1 -1
  362. package/server/{stale-task-claims-PzFee70R.js → stale-task-claims-C2e1zdMT.js} +5 -5
  363. package/server/{staleness-BjOAq9-d.js → staleness-CRDK6LFG.js} +1 -1
  364. package/server/{staleness-D8UTEXV5.js → staleness-Fzx_3_Hr.js} +1 -1
  365. package/server/{stall-sweeper-DOyIfeLR.js → stall-sweeper-QNk4h9m6.js} +8 -8
  366. package/server/{state-home-DhAZlk5k.js → state-home-DdG8erBI.js} +2 -2
  367. package/server/{state-mapping-BVSs84bO.js → state-mapping-D2yC81Vy.js} +1 -1
  368. package/server/{state-migrate-CJKEwpB0.js → state-migrate-C6H3jfHE.js} +6 -6
  369. package/server/{state-mirror-Do7pag7W.js → state-mirror-DF4Lfxm0.js} +3 -3
  370. package/server/stuck-remediation-BDa_tXgB.js +774 -0
  371. package/server/stuck-remediation-BVNd9txd.js +2 -0
  372. package/server/{substrate-bug-weights-service-BTNjHBnl.js → substrate-bug-weights-service-BbbCZEtJ.js} +3 -3
  373. package/server/{summary-fork-CZ88rhVx.js → summary-fork-BvcW6bq0.js} +113 -30
  374. package/server/{summary-fork-CvB7Oyq9.js → summary-fork-DIQmtOuV.js} +2 -2
  375. package/server/supervisor/{pane-composer-BaLLspSj.js → pane-composer-CoiVkGIt.js} +8 -1
  376. package/server/supervisor/{paths-D6XUcR_g.js → paths-DTGbtcaP.js} +8 -4
  377. package/server/supervisor/pty-supervisor.js +3 -3
  378. package/server/supervisor/{pty-token-DjjHxoCq.js → pty-token-GVqnvU3U.js} +2 -2
  379. package/server/{supervisor-D4v0WfiQ.js → supervisor-D3jC2c7A.js} +4 -4
  380. package/server/supervisor-v0cYN2Vp.js +2 -0
  381. package/server/{swarm-readiness-D8R-LWX5.js → swarm-readiness-CMWAQuWM.js} +3 -3
  382. package/server/{synthesis-verdict-B6wvLGcA.js → synthesis-verdict-C-pJOPsn.js} +1 -1
  383. package/server/{synthesis-verdict-N5Z11pg7.js → synthesis-verdict-DVlrLF9A.js} +2 -2
  384. package/server/{system-prerequisites-BbGZ_WHF.js → system-prerequisites-QKtIYXI2.js} +2 -2
  385. package/server/{teardown-workspace-CYend-KY.js → teardown-workspace-cJea1OLo.js} +16 -16
  386. package/server/{test-agent-queue-BUtWhNcc.js → test-agent-queue-C5DI_gWX.js} +6 -6
  387. package/server/{test-verdict-BWm3hgDj.js → test-verdict-C7kmd2_Y.js} +1 -1
  388. package/server/{test-verdict-BWtRmdiR.js → test-verdict-DUbDHqeD.js} +2 -2
  389. package/server/{tldr-daemon-CneJ24eL.js → tldr-daemon-BNQHwblU.js} +1 -1
  390. package/server/{tldr-daemon-CMVBT4kT.js → tldr-daemon-CO08YlfQ.js} +2 -2
  391. package/server/tmux-B8zsqD_6.js +4 -0
  392. package/server/{tmux-BqXzRuaH.js → tmux-DWEc4Ld9.js} +91 -19
  393. package/server/{token-CO3INKbh.js → token-Bez-qCB2.js} +2 -2
  394. package/server/{token-util-DyJJyX_B.js → token-util-Crcay9j_.js} +1 -1
  395. package/server/token-util-DfUS3Lpp.js +3 -0
  396. package/server/{tracker-config-DVzhaUxO.js → tracker-config-CJzPhSHv.js} +2 -2
  397. package/server/{tracker-utils-xnVJVrrO.js → tracker-utils-DJAOAuMN.js} +2 -2
  398. package/server/{traefik-connect-A5k54mCv.js → traefik-connect-D3H5I6b9.js} +1 -1
  399. package/server/{tunnel-DauSR-rs.js → tunnel-BSdKnW0U.js} +1 -1
  400. package/server/{tunnel-CwOnS-PB.js → tunnel-Cr3ctqxp.js} +3 -3
  401. package/server/{typed-errors-B-gfU2RB.js → typed-errors-CZ3GFBvo.js} +1 -1
  402. package/server/{typed-errors-DzC4zXbI.js → typed-errors-DXqf3RnP.js} +1 -1
  403. package/server/{types-DjpLVpsj.js → types-fzBp9cYi.js} +1 -1
  404. package/server/{types-DbxY2QB6.js → types-pLpbsNto.js} +1 -1
  405. package/server/{uat-failure-feedback-BVqsWlrr.js → uat-failure-feedback-IZQ-J8jt.js} +5 -5
  406. package/server/{uat-promote-verification-DmG097QS.js → uat-promote-verification-DXApKcc2.js} +5 -5
  407. package/server/{uat-train-COSy-vEX.js → uat-train-CycEzpbE.js} +1 -1
  408. package/server/{uat-train-DVUNW03P.js → uat-train-IIZlz7r3.js} +0 -0
  409. package/server/{validate-Dvv83iBx.js → validate-Ur4xH5bN.js} +3 -3
  410. package/server/{validation-BdCjzWLN.js → validation-CHovCoTT.js} +1 -1
  411. package/server/{validation-DlHafKzu.js → validation-Dr6V4PXx.js} +9 -6
  412. package/server/{verification-artifact-CaSbxUVg.js → verification-artifact-D3viYe_t.js} +1 -1
  413. package/server/{verification-artifact-0Zku8N-W.js → verification-artifact-k5Ftpg0c.js} +1 -1
  414. package/server/{verification-runner-C6wdZda2.js → verification-runner-BuqGwm2t.js} +1 -1
  415. package/server/{verification-runner-DwP2fUEF.js → verification-runner-Dl13mmsI.js} +53 -27
  416. package/server/{vtt-parser-luerJpYT.js → vtt-parser-BSnAB-Og.js} +1 -1
  417. package/server/work-agent-prompt-CJJ4tXci.js +3 -0
  418. package/server/{work-agent-prompt--9AWNYwZ.js → work-agent-prompt-CioeOuM4.js} +14 -14
  419. package/server/{work-agent-start-BNQO65W7.js → work-agent-start-B65Gqn9N.js} +2 -2
  420. package/server/{work-agent-start-DkzseQFl.js → work-agent-start-Ct1HVh6z.js} +1 -1
  421. package/server/{workflows-BYwR2aIN.js → workflows-AgFul1xc.js} +114 -41
  422. package/server/workflows-CfHm8lVd.js +2 -0
  423. package/server/{workspace-B-QJa3Ps.js → workspace-Cu3XlMXt.js} +1 -1
  424. package/server/{workspace-iTnTycOB.js → workspace-Cy4sDd3q.js} +3 -3
  425. package/server/{workspace-anchor-drift-DTt6h2Em.js → workspace-anchor-drift-BI0Hz6zI.js} +1 -1
  426. package/server/{workspace-anchor-drift-CHiGg8iu.js → workspace-anchor-drift-CMaqvizr.js} +4 -4
  427. package/server/{workspace-config-D0CavVtz.js → workspace-config-DRYDO7Zr.js} +1 -1
  428. package/server/{workspace-manager-W1OnbvU5.js → workspace-manager-CgovxDrO.js} +17 -17
  429. package/server/{workspace-manager-5BKPV6SY.js → workspace-manager-jfkKAEuO.js} +1 -1
  430. package/server/{workspace-metadata-tbbevEmP.js → workspace-metadata-BDqXzGGK.js} +1 -1
  431. package/server/{workspace-metadata-dJhXvZGQ.js → workspace-metadata-BNzODIv6.js} +2 -2
  432. package/server/{workspaces-BlpbOPZ7.js → workspaces-BJdPqx_J.js} +131 -127
  433. package/sync-sources/dev-skills/pan-style-guide/SKILL.md +90 -15
  434. package/sync-sources/hooks/linear-mcp-auth-hook +6 -1
  435. package/sync-sources/rules/handoff-isolate-cwd.md +4 -4
  436. package/sync-sources/rules/pan-handoff-focus-limit.md +12 -5
  437. package/sync-sources/rules/ste-writing.md +17 -0
  438. package/sync-sources/rules/work-agents-via-pan.md +2 -1
  439. package/sync-sources/rules/writing-style.md +3 -2
  440. package/sync-sources/skills/{skill-creator → claude-skill-creator}/SKILL.md +1 -1
  441. package/sync-sources/skills/{skill-creator → claude-skill-creator}/scripts/init_skill.py +1 -1
  442. package/sync-sources/skills/{skill-creator → claude-skill-creator}/scripts/package_skill.py +1 -1
  443. package/sync-sources/skills/pan-gauntlet-loop/SKILL.md +182 -0
  444. package/sync-sources/skills/pan-gauntlet-loop/assets/PROMPT.template.md +92 -0
  445. package/sync-sources/skills/pan-gauntlet-loop/assets/REFERENCE-BAR.template.md +53 -0
  446. package/sync-sources/skills/pan-gauntlet-loop/assets/STYLE.template.md +41 -0
  447. package/sync-sources/skills/pan-gauntlet-loop/assets/gauntlet-index.html +237 -0
  448. package/sync-sources/skills/pan-gauntlet-loop/references/domains.md +106 -0
  449. package/sync-sources/skills/pan-gauntlet-loop/references/lessons.md +60 -0
  450. package/sync-sources/skills/pan-handoff/SKILL.md +13 -6
  451. package/sync-sources/skills/pan-help/SKILL.md +1 -1
  452. package/sync-sources/skills/pan-peer-review/SKILL.md +3 -3
  453. package/sync-sources/skills/pan-restart/SKILL.md +6 -3
  454. package/sync-sources/skills/pan-start/SKILL.md +3 -0
  455. package/sync-sources/skills/pan-swarm/SKILL.md +32 -44
  456. package/sync-sources/skills/pan-sync/SKILL.md +1 -1
  457. package/server/activity-logger-BejO16Am.js +0 -3
  458. package/server/agent-state-DH_-Jkua.js +0 -3
  459. package/server/agents-megfmQHM.js +0 -3
  460. package/server/archive-planning-C-H9cM_J.js +0 -2
  461. package/server/build-info-PQlh_Rhb.js +0 -2
  462. package/server/cli-TaZspPHS.js +0 -2
  463. package/server/cliproxy-36ncAXlu.js +0 -3
  464. package/server/context-layers-CF6zHws4.js +0 -4
  465. package/server/conversations-AnGJ5rtX.js +0 -3
  466. package/server/deacon-BEH-IY0v.js +0 -5
  467. package/server/deacon-swarm-BHX-kR1b.js +0 -2
  468. package/server/deacon-swarm-BiLfNm_v.js +0 -1522
  469. package/server/dead-end-trip-BWpDg1Qd.js +0 -2
  470. package/server/delivery-cJM6zRjJ.js +0 -3
  471. package/server/deploy-queue-CmVBZEja.js +0 -2
  472. package/server/dist-VKBfkdi7.js +0 -3
  473. package/server/durable-review-pipeline-DgcVCYDL.js +0 -3
  474. package/server/factory-D4V2wd_V.js +0 -717
  475. package/server/forge-CrP1L3i6.js +0 -2
  476. package/server/hume-1ubD_6O7.js +0 -3
  477. package/server/inspect-agent-CfxERkNt.js +0 -2
  478. package/server/merge-ops-DtHx17Vd.js +0 -2
  479. package/server/merge-rebase-BvB4UuNS.js +0 -2
  480. package/server/project-repos-BJiShUsN.js +0 -3
  481. package/server/providers-CStNGwze.js +0 -3
  482. package/server/public/assets/index-BFEwfmqX.js +0 -860
  483. package/server/public/assets/index-_USwyTAT.css +0 -1
  484. package/server/public/assets/mermaid-GHXKKRXX-Dsln95SK.js +0 -1
  485. package/server/pull-requests-C1Cqp2yo.js +0 -2
  486. package/server/rally-CjayjUIl.js +0 -3
  487. package/server/resume-D7JuMCRQ.js +0 -3
  488. package/server/review-agent-BUNTVJK2.js +0 -2
  489. package/server/settings-DBWB1gsG.js +0 -2
  490. package/server/specialists-D8gsOCwh.js +0 -3
  491. package/server/specs-BqkrRnU9.js +0 -3
  492. package/server/stuck-remediation-Di5JYkoo.js +0 -1164
  493. package/server/stuck-remediation-TNM1VhZb.js +0 -2
  494. package/server/supervisor-DX8VsPnb.js +0 -2
  495. package/server/tmux-CqNapnrr.js +0 -4
  496. package/server/token-util-Bu8bPF9f.js +0 -3
  497. 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