@desplega.ai/agent-swarm 2.5.3 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (349) hide show
  1. package/README.md +2 -2
  2. package/dist/{acp-adapter-gr2fcyyj.js → acp-adapter-dgfakfpw.js} +9 -9
  3. package/dist/{actions-wv766ghf.js → actions-fbqma8aa.js} +21 -21
  4. package/dist/{amp-adapter-speb906t.js → amp-adapter-en0jy6hs.js} +4 -4
  5. package/dist/{app-ag29n14f.js → app-k8a5cgpp.js} +3 -3
  6. package/dist/{assistant-3x8bz3eg.js → assistant-a16433gr.js} +30 -26
  7. package/dist/{boot-reembed-jsmfrpzf.js → boot-reembed-6c1sjfnr.js} +1 -1
  8. package/dist/{boot-reembed-5b3d2eea.js → boot-reembed-f4nn561n.js} +1 -1
  9. package/dist/{boot-scrub-sweep-s73gerxy.js → boot-scrub-sweep-d4w9gajf.js} +4 -4
  10. package/dist/{boot-seeds-5zmax2wr.js → boot-seeds-9bmkspyw.js} +4 -4
  11. package/dist/{claude-adapter-hswdnm3t.js → claude-adapter-nys1kjxa.js} +9 -9
  12. package/dist/{claude-managed-adapter-cvbzj1h6.js → claude-managed-adapter-55207973.js} +3 -3
  13. package/dist/{claude-managed-setup-3k8m3hhc.js → claude-managed-setup-3cm35gey.js} +11 -4
  14. package/dist/{claude-sdk-session-fkbyk66x.js → claude-sdk-session-nw5yd8cp.js} +9313 -9260
  15. package/dist/{cli-210xd1f4.js → cli-03gg9pd1.js} +4 -4
  16. package/dist/{cli-kxpfx2xr.js → cli-0z1xjzwa.js} +2 -2
  17. package/dist/cli-1tem6ns9.js +894 -0
  18. package/dist/{cli-25j01dpj.js → cli-24j1jeeb.js} +3 -3
  19. package/dist/{cli-ta8bd7th.js → cli-2sjhpsns.js} +2 -2
  20. package/dist/{cli-p859hcc8.js → cli-39aet655.js} +2 -2
  21. package/dist/{cli-g1cw7xtt.js → cli-39rrw8yp.js} +1 -1
  22. package/dist/{cli-e2ar4bp1.js → cli-3aqd4jaa.js} +121 -47
  23. package/dist/{cli-jjznk3f7.js → cli-3fwqy71j.js} +69 -35
  24. package/dist/{cli-p9rafdrb.js → cli-3gfvmzht.js} +7 -7
  25. package/dist/{cli-03vpq45j.js → cli-3ndmpxxv.js} +2 -2
  26. package/dist/{cli-aecdcr77.js → cli-4hxrf0p4.js} +228 -74
  27. package/dist/{cli-mz9afxxf.js → cli-4rf0f5vg.js} +15 -3
  28. package/dist/{cli-qzme5949.js → cli-5rj83bam.js} +284 -202
  29. package/dist/{cli-fsdprwrg.js → cli-5sckpqcx.js} +2 -2
  30. package/dist/{cli-cz5nmdxt.js → cli-683y0b3a.js} +2 -2
  31. package/dist/{cli-3ngdk5te.js → cli-6y51ryva.js} +2 -2
  32. package/dist/{cli-n4c8e3s5.js → cli-708wdy32.js} +1 -1
  33. package/dist/{cli-pasyvjmm.js → cli-737pyqxr.js} +1 -1
  34. package/dist/{cli-gx4rm0qx.js → cli-7enjwya9.js} +1 -1
  35. package/dist/{cli-6x9ma5w5.js → cli-803188pb.js} +1 -1
  36. package/dist/{cli-avdvgcay.js → cli-9abdgn5t.js} +28 -9
  37. package/dist/{cli-99xgw26r.js → cli-a2rr0fmg.js} +1 -1
  38. package/dist/{cli-e5bxnjps.js → cli-a34pr3w1.js} +7 -7
  39. package/dist/{cli-502eqv93.js → cli-abkm71vr.js} +1 -1
  40. package/dist/{cli-mmhj8vd7.js → cli-ag2yrnt5.js} +11 -2
  41. package/dist/{cli-n45mr7zh.js → cli-aj8djyqt.js} +5 -5
  42. package/dist/{cli-1fc85mvt.js → cli-art7c1zh.js} +5 -5
  43. package/dist/{cli-40jsnrjm.js → cli-az25fn5f.js} +10 -8
  44. package/dist/{cli-9s05422w.js → cli-bqztfyve.js} +1 -1
  45. package/dist/{cli-bn0rewsy.js → cli-c081bj3b.js} +2 -2
  46. package/dist/{cli-svrj71pg.js → cli-c2habvsf.js} +12 -12
  47. package/dist/{cli-s49hpn37.js → cli-ca6banwz.js} +85 -19
  48. package/dist/{cli-hhxjnjzs.js → cli-cz37jqss.js} +12 -10
  49. package/dist/{cli-6n8axjv1.js → cli-d2dpf95n.js} +2 -2
  50. package/dist/{cli-tx00c0h6.js → cli-dqygeeh5.js} +17 -1
  51. package/dist/{cli-z21whrrg.js → cli-emhjcj2y.js} +17 -17
  52. package/dist/{cli-e8jyq7d8.js → cli-esakngh8.js} +7 -3
  53. package/dist/{cli-ha9rmwgq.js → cli-fb8m699c.js} +2 -2
  54. package/dist/{cli-35gtk1p6.js → cli-ffvsj2qw.js} +44 -13
  55. package/dist/{cli-ce0ak9ms.js → cli-g20jjwt4.js} +26 -26
  56. package/dist/{cli-kxawjrxg.js → cli-g8ka5j4j.js} +772 -194
  57. package/dist/{cli-vwn81jbs.js → cli-gf95q3bm.js} +5 -5
  58. package/dist/{cli-s53vp709.js → cli-gnsb1zxa.js} +2 -2
  59. package/dist/{cli-nwyw3zhg.js → cli-gxee0bqa.js} +1 -1
  60. package/dist/{cli-gpv60278.js → cli-hfeb68z4.js} +7 -7
  61. package/dist/{cli-0ebey9hg.js → cli-j6rktc91.js} +1 -1
  62. package/dist/{cli-ewm3pwbq.js → cli-k21gx5ht.js} +46 -23
  63. package/dist/{cli-egjggehm.js → cli-kf4jree9.js} +2 -2
  64. package/dist/{cli-dabehxhp.js → cli-kt907da6.js} +1 -1
  65. package/dist/{cli-p0rzjkya.js → cli-m5a9m0ak.js} +32 -13
  66. package/dist/{cli-fzcn3d87.js → cli-m70bajzr.js} +3 -3
  67. package/dist/{cli-w1zwctj2.js → cli-mtnj4fwa.js} +11 -5
  68. package/dist/{cli-gpsz7g88.js → cli-mvjz5an3.js} +16 -12
  69. package/dist/{cli-hcpj2xqz.js → cli-n7asmce6.js} +225 -3
  70. package/dist/{cli-y561h5a9.js → cli-nn6vx2mq.js} +5 -5
  71. package/dist/cli-nq677csy.js +140 -0
  72. package/dist/{cli-a5ebc95n.js → cli-pfk92eqz.js} +18 -15
  73. package/dist/{cli-p6zs9h4y.js → cli-rr7zx19j.js} +767 -249
  74. package/dist/{cli-qgf8emrn.js → cli-sqma6vw1.js} +10 -7
  75. package/dist/{cli-0xk505e8.js → cli-sxgtf5fw.js} +1 -1
  76. package/dist/{cli-nzfnt2gs.js → cli-tf1n0r0b.js} +1 -1
  77. package/dist/{cli-qqzmjxkf.js → cli-v49fkghp.js} +11 -6
  78. package/dist/{cli-x77gen2p.js → cli-w2656ka1.js} +7 -7
  79. package/dist/{cli-5kqnemen.js → cli-yvy48785.js} +1 -1
  80. package/dist/{cli-8s5wx3nz.js → cli-zqne1qcj.js} +44 -17
  81. package/dist/cli.js +22 -22
  82. package/dist/{codex-adapter-n8ka66vf.js → codex-adapter-d95q4qsn.js} +7 -7
  83. package/dist/{codex-hook-e2he7aca.js → codex-hook-brpnycn5.js} +1 -1
  84. package/dist/{codex-login-rn7c5gxt.js → codex-login-8cg0vhf2.js} +1 -1
  85. package/dist/{codex-session-runner-fsebts37.js → codex-session-runner-gdwd8h0c.js} +8 -8
  86. package/dist/{commands-t04rt2pc.js → commands-jqmgk54b.js} +2 -2
  87. package/dist/{controller-rgna04r2.js → controller-z3jq589f.js} +30 -4
  88. package/dist/{controllers-connect-bqm1rtft.js → controllers-connect-r2za39ef.js} +23 -23
  89. package/dist/{cursor-adapter-swr2k95y.js → cursor-adapter-4mr4jgkw.js} +2 -3
  90. package/dist/{db-a4m7haw0.js → db-ppv2tze7.js} +3 -3
  91. package/dist/{db-24ck09xy.js → db-w36wwb5g.js} +4 -2
  92. package/dist/{devin-adapter-4ycy4vrf.js → devin-adapter-byen2cxt.js} +1 -1
  93. package/dist/{dispatcher-nwf9ss0q.js → dispatcher-pv5h77vf.js} +20 -20
  94. package/dist/{docker-nfy2gc8t.js → docker-fdzyewpz.js} +4 -4
  95. package/dist/{dsh-adapter-kpdnhjst.js → dsh-adapter-d4pdpb3r.js} +2 -3
  96. package/dist/{e2b-9gkdhm3c.js → e2b-222hsajc.js} +2 -2
  97. package/dist/{e2b-cjtf8k1z.js → e2b-fn3zacvt.js} +2 -2
  98. package/dist/{easter-egg-3d-e4qv8dxj.js → easter-egg-3d-4sp4dvmc.js} +1 -1
  99. package/dist/{event-bus-3z78ep5n.js → event-bus-pghg8hqy.js} +1 -1
  100. package/dist/{execute-0xpz8950.js → execute-jev839y1.js} +1 -1
  101. package/dist/{external-channel-j1e2p34p.js → external-channel-y6nkzhnn.js} +2 -2
  102. package/dist/{grok-adapter-qtjz0whk.js → grok-adapter-t08b9ntm.js} +10 -10
  103. package/dist/handlers-eqsnmv95.js +41 -0
  104. package/dist/{heartbeat-vtesda5d.js → heartbeat-vn31xwdk.js} +23 -23
  105. package/dist/{hook-b2hhj6rd.js → hook-6d0zbvvt.js} +6 -5
  106. package/dist/{hook-8wqaszda.js → hook-cpjs8q51.js} +13 -7
  107. package/dist/{http-mxcqhhcs.js → http-9c6medda.js} +1085 -136
  108. package/dist/{index-spwxjgay.js → index-38t35h0n.js} +20 -20
  109. package/dist/{index-1r8wfpzs.js → index-g6k9tctj.js} +1 -1
  110. package/dist/{index-srg522m6.js → index-k0yt1tvq.js} +20 -20
  111. package/dist/{index-31ceyf42.js → index-pkma1yf8.js} +1 -1
  112. package/dist/{index-n1vbvta9.js → index-qhjf2htm.js} +29 -24
  113. package/dist/index-yqgbfgaj.js +43 -0
  114. package/dist/{keepalive-dsd8rtgx.js → keepalive-em0117bp.js} +4 -4
  115. package/dist/lead-23e7z59t.js +79 -0
  116. package/dist/{maintenance-jqmqwnet.js → maintenance-kbme3qy9.js} +1 -1
  117. package/dist/{oauth-refresh-sweep-q2c3bnvm.js → oauth-refresh-sweep-xysj4yse.js} +3 -3
  118. package/dist/{onboard-w4yd7s8t.js → onboard-p6q0vz97.js} +3 -3
  119. package/dist/{opencode-adapter-9tppvxar.js → opencode-adapter-esv3k9yn.js} +7 -7
  120. package/dist/{otel-impl-f36byzbd.js → otel-impl-54qhqh1z.js} +2 -2
  121. package/dist/{pi-mono-adapter-tqsge1ay.js → pi-mono-adapter-mymbwhj0.js} +41 -14
  122. package/dist/{pricing-refresh-xvak5p4v.js → pricing-refresh-yb75wv33.js} +3 -3
  123. package/dist/{rbac-roles-gfn30fb8.js → rbac-roles-1vp2mw4p.js} +2 -2
  124. package/dist/{rbac-roles-682k2mt5.js → rbac-roles-dexhc9x8.js} +1 -1
  125. package/dist/render-v2-tjay5hhf.js +16 -0
  126. package/dist/{resume-2dvq348g.js → resume-8ayf37g5.js} +11 -9
  127. package/dist/{runtime-bt5pkpm1.js → runtime-hqe5cqcd.js} +1 -1
  128. package/dist/{session-access-7f21ekq9.js → session-access-fdhp987s.js} +4 -4
  129. package/dist/session-source-backfill-qgtc86z1.js +110 -0
  130. package/dist/{setup-epffxtbk.js → setup-4rrmqcq3.js} +1 -1
  131. package/dist/{virtual-modules-mnfbh5mr.js → virtual-modules-52km00d6.js} +2 -2
  132. package/dist/{work-objects-xz1a5rqk.js → work-objects-p28fgd70.js} +23 -23
  133. package/dist/worker-e3w7vye1.js +79 -0
  134. package/dist/{x-pbpezr0s.js → x-wxrzvzx8.js} +2 -2
  135. package/openapi.json +1323 -16
  136. package/package.json +5 -5
  137. package/plugin/commands/create-pr.md +2 -2
  138. package/plugin/pi-skills/create-pr/SKILL.md +2 -2
  139. package/src/assets/source-key.ts +95 -0
  140. package/src/be/db/api-keys.ts +80 -0
  141. package/src/be/db/approvals.ts +48 -0
  142. package/src/be/db/session-labels.ts +28 -0
  143. package/src/be/db/session-moves.ts +5 -6
  144. package/src/be/db/session-tree.ts +153 -14
  145. package/src/be/db/tasks/read.ts +11 -0
  146. package/src/be/db/tasks/write.ts +21 -6
  147. package/src/be/db/workflow-idempotency.ts +183 -0
  148. package/src/be/db/workflow-runs.ts +500 -7
  149. package/src/be/db-retention.ts +61 -6
  150. package/src/be/db.ts +126 -131
  151. package/src/be/memory/providers/openai-embedding.ts +5 -1
  152. package/src/be/migrations/242_workflow_idempotency_keys.sql +40 -0
  153. package/src/be/migrations/244_api_key_validation.sql +4 -0
  154. package/src/be/onboarding.ts +4 -0
  155. package/src/be/scripts/typecheck.ts +1 -1
  156. package/src/be/sealed-json.ts +1 -0
  157. package/src/be/seed-scripts/catalog/compound-insights.inline.ts +2 -2
  158. package/src/be/seed-scripts/catalog/compound-insights.ts +2 -2
  159. package/src/be/seed-skills/bundled-files.generated.json +1 -1
  160. package/src/be/session-source-backfill.ts +163 -0
  161. package/src/be/sql-connections.ts +7 -1
  162. package/src/be/swarm-config-guard.ts +3 -0
  163. package/src/be/users.ts +9 -0
  164. package/src/comb/review-batch.ts +28 -1
  165. package/src/comb/templates.ts +7 -2
  166. package/src/commands/claude-managed-setup.ts +7 -1
  167. package/src/commands/controller.ts +33 -0
  168. package/src/commands/credential-refresh.ts +76 -1
  169. package/src/commands/credential-wait.ts +2 -2
  170. package/src/commands/provider-credentials.ts +210 -170
  171. package/src/commands/runner.ts +31 -6
  172. package/src/extensions/apply-task-create.ts +64 -11
  173. package/src/extensions/contract-types.generated.ts +1 -1
  174. package/src/extensions/contract.ts +30 -0
  175. package/src/extensions/dispatcher.ts +4 -0
  176. package/src/extensions/post-bridge.ts +8 -0
  177. package/src/hooks/context-bound-note.ts +196 -0
  178. package/src/hooks/hook.ts +12 -0
  179. package/src/http/all-routes.ts +2 -0
  180. package/src/http/api-keys.ts +53 -0
  181. package/src/http/assets.ts +15 -0
  182. package/src/http/codex-oauth-accounts.ts +191 -0
  183. package/src/http/comb.ts +15 -2
  184. package/src/http/config.ts +49 -17
  185. package/src/http/core.ts +6 -0
  186. package/src/http/fleet-benchmark.ts +5 -2
  187. package/src/http/idempotency-key.ts +117 -0
  188. package/src/http/index.ts +11 -0
  189. package/src/http/integrations.ts +5 -1
  190. package/src/http/kv.ts +8 -3
  191. package/src/http/onboarding.ts +6 -1
  192. package/src/http/pool-keys.ts +354 -0
  193. package/src/http/sessions.ts +37 -12
  194. package/src/http/stats.ts +1 -0
  195. package/src/http/status.ts +26 -12
  196. package/src/http/tasks.ts +3 -0
  197. package/src/http/used-by.ts +7 -2
  198. package/src/http/workflows.ts +207 -33
  199. package/src/integrations/chat-sdk/inbound.ts +27 -0
  200. package/src/kv-reserved-namespaces.ts +19 -0
  201. package/src/prompts/context-bound-note.ts +48 -0
  202. package/src/prompts/session-templates.ts +25 -1
  203. package/src/providers/acp-targets.ts +1 -1
  204. package/src/providers/amp-adapter.ts +30 -8
  205. package/src/providers/claude-adapter.ts +34 -5
  206. package/src/providers/claude-managed-adapter.ts +42 -9
  207. package/src/providers/claude-sdk-session.ts +10 -0
  208. package/src/providers/claude-session-events.ts +13 -0
  209. package/src/providers/codex-adapter.ts +83 -11
  210. package/src/providers/opencode-adapter.ts +18 -0
  211. package/src/providers/pi-mono-adapter.ts +35 -0
  212. package/src/runtime-providers/docker.ts +6 -2
  213. package/src/scheduler/scheduler.ts +3 -2
  214. package/src/scripts-runtime/swarm-sdk.ts +7 -1
  215. package/src/scripts-runtime/types/stdlib.d.ts +1 -1
  216. package/src/scripts-runtime/types/swarm-extension.d.ts +52 -8
  217. package/src/scripts-runtime/types/swarm-sdk.d.ts +1 -1
  218. package/src/slack/assistant.ts +7 -0
  219. package/src/slack/channel-labels.ts +74 -0
  220. package/src/slack/handlers.ts +8 -0
  221. package/src/slack/inbound-files.ts +5 -2
  222. package/src/slack/thread-buffer.ts +4 -0
  223. package/src/tasks/sibling-awareness.ts +12 -3
  224. package/src/telemetry-context.ts +5 -6
  225. package/src/telemetry-identity.ts +3 -3
  226. package/src/tests/amp-adapter.test.ts +97 -0
  227. package/src/tests/api-keys-validation.test.ts +170 -0
  228. package/src/tests/approval-requests.test.ts +10 -7
  229. package/src/tests/approval-sweeps.test.ts +12 -6
  230. package/src/tests/base-prompt.test.ts +1 -1
  231. package/src/tests/claude-hook-output.test.ts +79 -1
  232. package/src/tests/claude-managed-adapter.test.ts +321 -0
  233. package/src/tests/claude-routes-e2e.test.ts +7 -2
  234. package/src/tests/codex-adapter.test.ts +163 -0
  235. package/src/tests/codex-credential-pools.test.ts +120 -0
  236. package/src/tests/codex-gateway-route.test.ts +165 -0
  237. package/src/tests/codex-oauth-accounts.test.ts +357 -0
  238. package/src/tests/comb-review-batch.test.ts +63 -2
  239. package/src/tests/config-pool-keys.test.ts +533 -0
  240. package/src/tests/context-bound-note.test.ts +269 -0
  241. package/src/tests/credential-check.test.ts +290 -2
  242. package/src/tests/credential-refresh.test.ts +172 -1
  243. package/src/tests/db-retention.test.ts +9 -3
  244. package/src/tests/db-task-read-contract.test.ts +1 -0
  245. package/src/tests/db-task-write-contract.test.ts +1 -3
  246. package/src/tests/docs-index-footprint.test.js +3 -3
  247. package/src/tests/extensions-pre-task.test.ts +325 -0
  248. package/src/tests/fetch-resolved-env.test.ts +17 -0
  249. package/src/tests/fixtures/extensions/record-blocks/hooks.ts +10 -0
  250. package/src/tests/fixtures/extensions/record-blocks/manifest.json +7 -0
  251. package/src/tests/fixtures/extensions/record-task-create/hooks.ts +9 -0
  252. package/src/tests/fixtures/extensions/record-task-create/manifest.json +7 -0
  253. package/src/tests/fixtures/fake-amp.ts +22 -8
  254. package/src/tests/fixtures/held-template-render.ts +42 -0
  255. package/src/tests/fixtures/workflow-idempotency-trigger.child.ts +73 -0
  256. package/src/tests/fleet-benchmark.test.ts +8 -0
  257. package/src/tests/get-workflow-run-tool.test.ts +98 -0
  258. package/src/tests/integrations-http.test.ts +32 -2
  259. package/src/tests/internal-ai/complete-structured.test.ts +37 -1
  260. package/src/tests/internal-ai/credentials.test.ts +23 -0
  261. package/src/tests/kv-http.test.ts +32 -0
  262. package/src/tests/kv-tool.test.ts +25 -0
  263. package/src/tests/multi-runtime-registration.test.ts +12 -12
  264. package/src/tests/onboarding.test.ts +108 -1
  265. package/src/tests/openai-embedding-credentials.test.ts +35 -0
  266. package/src/tests/openapi-route-headers.test.ts +2 -0
  267. package/src/tests/opencode-adapter.test.ts +134 -0
  268. package/src/tests/openrouter-attribution-call-sites.test.ts +2 -2
  269. package/src/tests/org-website.test.ts +36 -0
  270. package/src/tests/pi-mono-adapter.test.ts +105 -0
  271. package/src/tests/prompt-template-session.test.ts +4 -3
  272. package/src/tests/provider-key-probes.test.ts +181 -0
  273. package/src/tests/rbac-e2e-helpers.test.ts +88 -1
  274. package/src/tests/rbac-e2e-helpers.ts +36 -11
  275. package/src/tests/runner-push-delivery.test.ts +25 -0
  276. package/src/tests/runtime-controller-liveness.test.ts +133 -0
  277. package/src/tests/runtime-providers-docker.test.ts +2 -0
  278. package/src/tests/script-connections.test.ts +5 -0
  279. package/src/tests/script-run-config-scope.test.ts +91 -3
  280. package/src/tests/script-runs-retention.test.ts +212 -0
  281. package/src/tests/sdk-allowlist.test.ts +39 -0
  282. package/src/tests/session-logs.test.ts +70 -0
  283. package/src/tests/session-source-backfill.test.ts +429 -0
  284. package/src/tests/session-source-keys.test.ts +236 -0
  285. package/src/tests/session-source-labels.test.ts +419 -0
  286. package/src/tests/sessions-detail-batch.test.ts +2 -0
  287. package/src/tests/sessions-move.test.ts +131 -0
  288. package/src/tests/sessions-tree.test.ts +336 -2
  289. package/src/tests/slack-inbound-files.test.ts +103 -23
  290. package/src/tests/status.test.ts +101 -18
  291. package/src/tests/tasks-workflow-run-filter.test.ts +146 -0
  292. package/src/tests/test-net.ts +31 -0
  293. package/src/tests/transcription.test.ts +8 -0
  294. package/src/tests/used-by-route.test.ts +11 -0
  295. package/src/tests/workflow-cascade-cancel.test.ts +1341 -0
  296. package/src/tests/workflow-foreach-supersede-retry.test.ts +488 -0
  297. package/src/tests/workflow-http-v2.test.ts +131 -0
  298. package/src/tests/workflow-idempotency.test.ts +915 -0
  299. package/src/tests/workflow-step-order.test.ts +92 -0
  300. package/src/tests/workflow-sub-workflow.test.ts +30 -0
  301. package/src/tools/get-tasks.ts +8 -0
  302. package/src/tools/kv/kv-read-auth.ts +4 -2
  303. package/src/tools/task-action.ts +1 -1
  304. package/src/tools/workflows/cancel-workflow-run.ts +1 -1
  305. package/src/tools/workflows/get-workflow-run.ts +14 -4
  306. package/src/types.ts +24 -0
  307. package/src/utils/company-profile.ts +51 -1
  308. package/src/utils/context-window.ts +8 -6
  309. package/src/utils/credentials.ts +5 -2
  310. package/src/utils/internal-ai/complete-structured.ts +5 -0
  311. package/src/utils/internal-ai/credentials.ts +4 -3
  312. package/src/utils/provider-key-probes.ts +328 -0
  313. package/src/utils/transcription.ts +4 -1
  314. package/src/workflows/approval-cancel.ts +15 -13
  315. package/src/workflows/approval-notifications.ts +5 -1
  316. package/src/workflows/checkpoint.ts +6 -3
  317. package/src/workflows/engine.ts +30 -8
  318. package/src/workflows/executors/foreach.ts +2 -2
  319. package/src/workflows/executors/sub-workflow.ts +8 -1
  320. package/src/workflows/foreach-driver.ts +10 -3
  321. package/src/workflows/foreach-join.ts +29 -6
  322. package/src/workflows/recovery.ts +6 -1
  323. package/src/workflows/resume.ts +168 -56
  324. package/src/workflows/retry-poller.ts +49 -3
  325. package/src/workflows/task-step-routing.ts +29 -7
  326. package/templates/ai-toolbox.manifest.json +8 -8
  327. package/templates/community/open-prompt-showreel/PLAYBOOK.md +5 -6
  328. package/templates/community/open-prompt-showreel/lead-prompt.md +1 -1
  329. package/templates/community/open-prompt-showreel/skills/open-prompt-showreel/SKILL.md +4 -4
  330. package/templates/skills/agent-browser/SKILL.md +4 -4
  331. package/templates/skills/agent-browser/content.md +4 -4
  332. package/templates/skills/code-quality/config.json +1 -1
  333. package/templates/skills/code-quality/content.md +2 -2
  334. package/templates/skills/delegate-work/content.md +29 -25
  335. package/templates/skills/delegate-work/files/scripts/codex-exec.sh +5 -5
  336. package/templates/skills/qa/content.md +2 -2
  337. package/templates/skills/researching/content.md +4 -0
  338. package/templates/skills/swarm-scripts/SKILL.md +1 -0
  339. package/templates/skills/swarm-scripts/content.md +1 -0
  340. package/templates/skills/work-on-task/SKILL.md +1 -1
  341. package/templates/skills/work-on-task/content.md +1 -1
  342. package/dist/cli-7421jzsw.js +0 -84
  343. package/dist/cli-e45e4m6b.js +0 -413
  344. package/dist/cli-zw88zjba.js +0 -307
  345. package/dist/handlers-19xr6dnz.js +0 -41
  346. package/dist/index-kw2mmat7.js +0 -43
  347. package/dist/lead-zyerk1x2.js +0 -79
  348. package/dist/render-v2-hgytz8nn.js +0 -12
  349. package/dist/worker-42t8emjt.js +0 -79
@@ -150,6 +150,8 @@ import {
150
150
  TelegramBotApiError,
151
151
  callTelegramBotApi,
152
152
  isTrustedTeamsServiceUrl,
153
+ getSessionLabels,
154
+ rememberSessionLabel,
153
155
  isChatSdkStopping,
154
156
  startChatSdk,
155
157
  getChatInstance,
@@ -176,6 +178,7 @@ import {
176
178
  extractAndVerifyCookie,
177
179
  pageSessionSetCookies,
178
180
  resolveHttpRequestAuth,
181
+ getDeploymentEnvValue,
179
182
  loadGlobalConfigsIntoEnv,
180
183
  reloadGlobalConfigsAndIntegrations,
181
184
  scheduleIntegrationsReload,
@@ -227,6 +230,7 @@ import {
227
230
  getTasksOutputSchema,
228
231
  getTasksHandler,
229
232
  reservedNamespaceError,
233
+ privateNamespaceError,
230
234
  reservedRoomKeyError,
231
235
  updateMcpServerChecked,
232
236
  updateTouchesStdioExecution,
@@ -289,17 +293,23 @@ import {
289
293
  hasCapability,
290
294
  getEnabledCapabilities,
291
295
  createServer
292
- } from "./cli-aecdcr77.js";
296
+ } from "./cli-4hxrf0p4.js";
293
297
  import {
294
298
  chatThreadOfContextKey,
295
299
  agentContextKey,
296
300
  pageContextKey,
297
301
  init_context_key,
302
+ sourceOfKey,
303
+ SOURCE_GROUPS_READ_ONLY,
304
+ sourceMoveError,
305
+ init_source_key,
298
306
  init_catalog,
299
307
  catalog_default,
300
308
  COMPANY_TEAM_SIZES,
301
309
  COMPANY_USE_CASES,
302
310
  USER_FUNCTIONS,
311
+ reportedUseCase,
312
+ reportedUserFunction,
303
313
  init_company_profile,
304
314
  TELEMETRY_PROXY_ORIGIN,
305
315
  normalizeOrgWebsite,
@@ -347,6 +357,7 @@ import {
347
357
  resolveTriggerSurface,
348
358
  emitTaskTelemetry,
349
359
  init_telemetry_trigger,
360
+ CODEX_AUTH_FAILURE_BENCH_THRESHOLD,
350
361
  CODEX_AUTH_WATCH_NAMESPACE,
351
362
  codexAuthBenchMarkerKey,
352
363
  init_codex_auth_failure,
@@ -410,6 +421,7 @@ import {
410
421
  listPrefixRoots,
411
422
  listSharedPrefixRoots,
412
423
  init_session_moves,
424
+ getSessionGroupKey,
413
425
  getSessionReadState,
414
426
  getSessionTree,
415
427
  triageSessionList,
@@ -440,6 +452,17 @@ import {
440
452
  getPausedTasksForAgent2,
441
453
  resetOrphanedInProgressTasksForAgent2,
442
454
  updateTaskProgress2,
455
+ IdempotencyKeyTakenError,
456
+ workflowRequestFingerprint,
457
+ findAcceptedWorkflowOperation,
458
+ assertWorkflowIdempotencyKeyUnused,
459
+ recordAcceptedWorkflowOperation,
460
+ init_workflow_idempotency,
461
+ getWorkflowRunSummary,
462
+ getWorkflowRunStepsSlimByRunId,
463
+ WORKFLOW_RUN_TREE_MAX_DEPTH,
464
+ WorkflowRunTreeError,
465
+ getWorkflowRunTree,
443
466
  getWorkflowRunParent,
444
467
  init_workflow_runs,
445
468
  CHAT_SDK_ADAPTER_NAMES,
@@ -531,6 +554,9 @@ import {
531
554
  init_steering,
532
555
  refreshActiveSessionOnActivity2,
533
556
  recordKeySeatMismatch2,
557
+ recordKeyValidation2,
558
+ retirePoolKeyStatus,
559
+ init_api_keys,
534
560
  getScriptRunExecutionArgs2,
535
561
  updateTaskVcs2,
536
562
  upsertAssetKeyMapping2,
@@ -737,7 +763,7 @@ import {
737
763
  countScriptRunJournalSteps2,
738
764
  countScriptRunJournalAgentTaskSteps2,
739
765
  init_db3
740
- } from "./cli-kxawjrxg.js";
766
+ } from "./cli-g8ka5j4j.js";
741
767
  import {
742
768
  PRIMARY_ROLE_NAMES2,
743
769
  getUserGrant2,
@@ -748,22 +774,26 @@ import {
748
774
  assertNotLastAdmin2,
749
775
  setUserRoles2,
750
776
  init_rbac_roles
751
- } from "./cli-99xgw26r.js";
752
- import"./cli-210xd1f4.js";
777
+ } from "./cli-a2rr0fmg.js";
778
+ import"./cli-03gg9pd1.js";
753
779
  import {
754
780
  normalizeModelKey
755
- } from "./cli-fsdprwrg.js";
781
+ } from "./cli-5sckpqcx.js";
756
782
  import {
757
783
  upsertModelCatalogOverlay,
758
784
  deleteModelCatalogOverlay,
759
785
  loadModelsCatalog,
760
786
  requestModelCatalogRefresh2
761
- } from "./cli-n45mr7zh.js";
787
+ } from "./cli-aj8djyqt.js";
762
788
  import {
763
789
  AMP_ESTIMATE_MODELS,
764
790
  ampBillsCacheWrites,
765
791
  resolveAmpModel
766
- } from "./cli-9s05422w.js";
792
+ } from "./cli-bqztfyve.js";
793
+ import {
794
+ workflowEventBus2,
795
+ init_event_bus
796
+ } from "./cli-kt907da6.js";
767
797
  import {
768
798
  automationIntegrationFixUrl,
769
799
  preflightAutomation,
@@ -799,7 +829,7 @@ import {
799
829
  generateEdges,
800
830
  definitionNodeIds,
801
831
  validateDefinition
802
- } from "./cli-jjznk3f7.js";
832
+ } from "./cli-3fwqy71j.js";
803
833
  import {
804
834
  require_dist2,
805
835
  isInvalidClientError,
@@ -879,14 +909,14 @@ import {
879
909
  typecheckWithAmbient,
880
910
  typecheckScript,
881
911
  parseSkillContent
882
- } from "./cli-p9rafdrb.js";
912
+ } from "./cli-3gfvmzht.js";
883
913
  import {
884
914
  buildAuthorizationUrl,
885
915
  exchangeAuthorizationCode,
886
916
  oauthAppRowToProviderConfig,
887
917
  forceRefreshAuthorizationOrThrow,
888
918
  forceRefreshTokenOrThrow
889
- } from "./cli-egjggehm.js";
919
+ } from "./cli-kf4jree9.js";
890
920
  import {
891
921
  signalProcessGroup,
892
922
  detachedProcessGroup,
@@ -914,31 +944,31 @@ import {
914
944
  getTaskCitationsForTasks,
915
945
  initialize,
916
946
  ensure,
947
+ callSlackWithRetry2,
948
+ slackErrorCode2,
917
949
  getSlackApp2,
918
950
  startSlackApp2,
919
951
  stopSlackApp2
920
- } from "./cli-ce0ak9ms.js";
921
- import"./cli-s53vp709.js";
922
- import"./cli-qqzmjxkf.js";
952
+ } from "./cli-g20jjwt4.js";
953
+ import"./cli-gnsb1zxa.js";
954
+ import"./cli-v49fkghp.js";
923
955
  import {
924
956
  _fetchHolder,
925
957
  CLIENT_ID,
958
+ decodeJwt,
926
959
  exchangeAuthorizationCode2,
927
960
  getAccountId,
961
+ extractChatgptPlanType,
928
962
  deriveCodexKeySuffix,
929
963
  MAX_CODEX_OAUTH_SLOT,
930
964
  codexOAuthKeyForSlot,
931
965
  loadAllCodexOAuthSlots,
932
966
  getValidCodexOAuth
933
- } from "./cli-kxpfx2xr.js";
934
- import {
935
- workflowEventBus2,
936
- init_event_bus
937
- } from "./cli-dabehxhp.js";
967
+ } from "./cli-0z1xjzwa.js";
938
968
  import {
939
969
  retryFailedRun2,
940
970
  cancelWorkflowRun2
941
- } from "./cli-e2ar4bp1.js";
971
+ } from "./cli-3aqd4jaa.js";
942
972
  import {
943
973
  duplicateGuardedQueryKey,
944
974
  warnIfCorsAllowsAnyOrigin,
@@ -983,7 +1013,7 @@ import {
983
1013
  bodyListTask,
984
1014
  describeRequestRoute,
985
1015
  route
986
- } from "./cli-1fc85mvt.js";
1016
+ } from "./cli-art7c1zh.js";
987
1017
  import {
988
1018
  FilesError,
989
1019
  normalizeFilesError,
@@ -1011,13 +1041,13 @@ import {
1011
1041
  resolvePoolDelivery2,
1012
1042
  createPoolAgent2,
1013
1043
  init_db
1014
- } from "./cli-vwn81jbs.js";
1044
+ } from "./cli-gf95q3bm.js";
1015
1045
  import {
1016
1046
  RATING_MODEL_MAX_LENGTH,
1017
1047
  REFERENCES_SOURCE_MAX_LENGTH,
1018
1048
  sanitizeReferencesSource
1019
1049
  } from "./cli-3h26v7yj.js";
1020
- import"./cli-pasyvjmm.js";
1050
+ import"./cli-737pyqxr.js";
1021
1051
  import {
1022
1052
  startPoolRouting,
1023
1053
  stopPoolRouting,
@@ -1027,8 +1057,8 @@ import {
1027
1057
  checkHeartbeatChecklist2,
1028
1058
  runHeartbeatSweep2,
1029
1059
  stopHeartbeat2
1030
- } from "./cli-z21whrrg.js";
1031
- import"./cli-6n8axjv1.js";
1060
+ } from "./cli-emhjcj2y.js";
1061
+ import"./cli-d2dpf95n.js";
1032
1062
  import {
1033
1063
  import_websocket,
1034
1064
  import_websocket_server
@@ -1037,18 +1067,18 @@ import {
1037
1067
  runtimeSupervisorStatus,
1038
1068
  startRuntimeSupervisor,
1039
1069
  stopRuntimeSupervisor
1040
- } from "./cli-svrj71pg.js";
1070
+ } from "./cli-c2habvsf.js";
1041
1071
  import"./cli-ns59dc6r.js";
1042
1072
  import {
1043
1073
  ACP_TARGET_IDS
1044
- } from "./cli-5kqnemen.js";
1074
+ } from "./cli-yvy48785.js";
1045
1075
  import {
1046
1076
  reasoningCapability,
1047
1077
  supportedReasoningLevels
1048
- } from "./cli-bn0rewsy.js";
1078
+ } from "./cli-c081bj3b.js";
1049
1079
  import {
1050
1080
  MAX_RATE_LIMIT_RESET_MS
1051
- } from "./cli-gx4rm0qx.js";
1081
+ } from "./cli-7enjwya9.js";
1052
1082
  import {
1053
1083
  isLeadChannelMonitoringEnabled,
1054
1084
  ORG_IDENTITY_KEYS,
@@ -1056,15 +1086,16 @@ import {
1056
1086
  SIMILARITY_THRESHOLD,
1057
1087
  memoryRelevance,
1058
1088
  isUnknownModelError,
1089
+ checkProviderPoolKey,
1059
1090
  writeSkillsToFilesystem
1060
- } from "./cli-hcpj2xqz.js";
1091
+ } from "./cli-n7asmce6.js";
1061
1092
  import {
1062
1093
  inviteEmailToSharedOrg,
1063
1094
  ensureAgentFsCredentialsForAgent
1064
- } from "./cli-3ngdk5te.js";
1095
+ } from "./cli-6y51ryva.js";
1065
1096
  import {
1066
1097
  Anthropic
1067
- } from "./cli-p6zs9h4y.js";
1098
+ } from "./cli-rr7zx19j.js";
1068
1099
  import {
1069
1100
  isCodexOAuthConfigKey
1070
1101
  } from "./cli-j4bwnpkm.js";
@@ -1093,6 +1124,7 @@ import {
1093
1124
  InvalidRuntimeTokenError,
1094
1125
  mintSessionToken,
1095
1126
  mintRuntimeToken,
1127
+ isScriptRunToken,
1096
1128
  revokeSessionToken,
1097
1129
  AgentTokenExistsError,
1098
1130
  mintAgentToken,
@@ -1100,7 +1132,7 @@ import {
1100
1132
  revokeAgentTokens,
1101
1133
  fingerprintApiKey,
1102
1134
  init_users
1103
- } from "./cli-e8jyq7d8.js";
1135
+ } from "./cli-esakngh8.js";
1104
1136
  import"./cli-v41kn3cd.js";
1105
1137
  import"./cli-wgtk7xxr.js";
1106
1138
  import"./cli-1f0gp9vz.js";
@@ -1228,6 +1260,7 @@ import {
1228
1260
  ScriptRunListItemSchema,
1229
1261
  ScriptRunJournalEntrySchema,
1230
1262
  WorkflowRunStepSchema,
1263
+ WorkflowRunStepSlimSchema,
1231
1264
  PromptTemplateSchema,
1232
1265
  PromptTemplateHistorySchema,
1233
1266
  ScriptScopeSchema,
@@ -1264,45 +1297,49 @@ import {
1264
1297
  KvKeySchema,
1265
1298
  KvEntrySchema,
1266
1299
  init_types
1267
- } from "./cli-mz9afxxf.js";
1300
+ } from "./cli-4rf0f5vg.js";
1268
1301
  import {
1269
1302
  IDENTITY_FIELD_BUDGETS,
1270
1303
  IdentityFieldBudgetError,
1271
1304
  init_identity_field_budget
1272
- } from "./cli-gpv60278.js";
1273
- import {
1274
- getSlackConfiguration,
1275
- init_config
1276
- } from "./cli-qeaq3j6t.js";
1305
+ } from "./cli-hfeb68z4.js";
1277
1306
  import {
1278
1307
  isSteeringEnabled2,
1279
1308
  init_steering_enabled
1280
1309
  } from "./cli-4sydckyj.js";
1281
1310
  import {
1282
- interpolate,
1283
- init_template,
1284
- getTemplateDefinition,
1285
- getAllTemplateDefinitions,
1286
- init_registry,
1287
- resolveTemplate,
1288
- init_resolver,
1289
- init_session_templates
1290
- } from "./cli-tx00c0h6.js";
1291
- import {
1292
- MODEL_SCOPED_WINDOWS,
1293
- activeModelBlocks,
1294
- init_model_rate_limit_windows
1295
- } from "./cli-7421jzsw.js";
1311
+ getSlackConfiguration,
1312
+ init_config
1313
+ } from "./cli-qeaq3j6t.js";
1296
1314
  import {
1297
1315
  SUBSCRIPTION_PLANS_CHECKED_AT,
1298
1316
  SUBSCRIPTION_PLANS,
1299
1317
  isSubscriptionPlanId,
1300
1318
  init_subscription_plans
1301
1319
  } from "./cli-7akn6ze9.js";
1320
+ import {
1321
+ MODEL_SCOPED_WINDOWS,
1322
+ activeModelBlocks,
1323
+ init_model_rate_limit_windows,
1324
+ CREDENTIAL_POOL_VARS,
1325
+ splitCredentialPool,
1326
+ selectCredential,
1327
+ init_credentials
1328
+ } from "./cli-1tem6ns9.js";
1302
1329
  import {
1303
1330
  getOpenRouterAttributionHeaders,
1304
1331
  init_openrouter_base_url
1305
1332
  } from "./cli-dfyv0jdy.js";
1333
+ import {
1334
+ interpolate,
1335
+ init_template,
1336
+ getTemplateDefinition,
1337
+ getAllTemplateDefinitions,
1338
+ init_registry,
1339
+ resolveTemplate,
1340
+ init_resolver,
1341
+ init_session_templates
1342
+ } from "./cli-dqygeeh5.js";
1306
1343
  import {
1307
1344
  init_zod
1308
1345
  } from "./cli-4chz1hye.js";
@@ -1337,7 +1374,7 @@ import {
1337
1374
  import {
1338
1375
  init_package,
1339
1376
  package_default
1340
- } from "./cli-y561h5a9.js";
1377
+ } from "./cli-nn6vx2mq.js";
1341
1378
  import {
1342
1379
  realtimeBus,
1343
1380
  init_bus
@@ -1365,12 +1402,15 @@ import {
1365
1402
  findSecretsIn,
1366
1403
  scrubObject,
1367
1404
  registerVolatileSecret,
1405
+ registerEnvSecrets,
1368
1406
  init_secret_scrubber
1369
- } from "./cli-n4c8e3s5.js";
1407
+ } from "./cli-708wdy32.js";
1370
1408
  import {
1371
1409
  isAlias,
1410
+ baseUrlEnvVar,
1411
+ providerForKeyVar,
1372
1412
  init_src2
1373
- } from "./cli-nwyw3zhg.js";
1413
+ } from "./cli-gxee0bqa.js";
1374
1414
  import {
1375
1415
  __toESM
1376
1416
  } from "./cli-242037k3.js";
@@ -1428,6 +1468,7 @@ init_db3();
1428
1468
 
1429
1469
  // src/be/db-retention.ts
1430
1470
  import { AsyncLocalStorage } from "node:async_hooks";
1471
+ init_types();
1431
1472
  init_env_flag();
1432
1473
  init_secret_scrubber();
1433
1474
  init_db3();
@@ -1472,6 +1513,19 @@ var DB_RETENTION_TABLES = [
1472
1513
  metricsKey: "contextVersions",
1473
1514
  initialBatchSize: 50,
1474
1515
  maxBatchSize: 100
1516
+ },
1517
+ {
1518
+ table: "script_runs",
1519
+ policy: "age",
1520
+ timeColumn: "startedAt",
1521
+ cutoffFormat: "sqliteDatetime",
1522
+ statusColumn: "status",
1523
+ terminalStatuses: TERMINAL_SCRIPT_RUN_STATUSES,
1524
+ keepWhenSet: "idempotencyKey",
1525
+ envKey: "SCRIPT_RUNS_RETENTION_DAYS",
1526
+ metricsKey: "scriptRuns",
1527
+ initialBatchSize: 100,
1528
+ maxBatchSize: 500
1475
1529
  }
1476
1530
  ];
1477
1531
 
@@ -1605,13 +1659,26 @@ function sweepStatements(table, value, now) {
1605
1659
  params: [value]
1606
1660
  };
1607
1661
  }
1608
- const cutoff = new Date(now.getTime() - value * DAY_MS).toISOString();
1662
+ const iso = new Date(now.getTime() - value * DAY_MS).toISOString();
1663
+ const cutoff = "cutoffFormat" in table ? `${iso.slice(0, 10)} ${iso.slice(11, 19)}` : iso;
1664
+ const conditions = [];
1665
+ const params = [];
1666
+ if ("terminalStatuses" in table) {
1667
+ conditions.push(`${table.statusColumn} IN (${table.terminalStatuses.map(() => "?").join(", ")})`);
1668
+ params.push(...table.terminalStatuses);
1669
+ }
1670
+ conditions.push(`${table.timeColumn} < ?`);
1671
+ params.push(cutoff);
1672
+ if ("keepWhenSet" in table) {
1673
+ conditions.push(`rowid NOT IN (SELECT rowid FROM ${table.table} WHERE ${table.keepWhenSet} IS NOT NULL)`);
1674
+ }
1675
+ const where = conditions.join(" AND ");
1609
1676
  return {
1610
- backlogSql: `SELECT COUNT(*) AS n FROM ${table.table} WHERE ${table.timeColumn} < ?`,
1677
+ backlogSql: `SELECT COUNT(*) AS n FROM ${table.table} WHERE ${where}`,
1611
1678
  deleteSql: `DELETE FROM ${table.table} WHERE rowid IN (
1612
- SELECT rowid FROM ${table.table} WHERE ${table.timeColumn} < ? ORDER BY ${table.timeColumn} LIMIT ?
1679
+ SELECT rowid FROM ${table.table} WHERE ${where} ORDER BY ${table.timeColumn} LIMIT ?
1613
1680
  )`,
1614
- params: [cutoff]
1681
+ params
1615
1682
  };
1616
1683
  }
1617
1684
  function dryRunEnabled(env = process.env) {
@@ -5448,6 +5515,33 @@ var reportRateLimit = route({
5448
5515
  },
5449
5516
  auth: { apiKey: true }
5450
5517
  });
5518
+ var reportValidation = route({
5519
+ method: "post",
5520
+ path: "/api/keys/report-validation",
5521
+ pattern: ["api", "keys", "report-validation"],
5522
+ summary: "Record live validation results for a credential pool",
5523
+ tags: ["API Keys"],
5524
+ body: object2({
5525
+ keyType: string2(),
5526
+ keys: array2(object2({
5527
+ keyIndex: number2().int().min(0),
5528
+ keySuffix: string2().min(1).max(10),
5529
+ ok: boolean(),
5530
+ httpStatus: number2().int().optional()
5531
+ })).min(1).max(100),
5532
+ scope: string2().optional(),
5533
+ scopeId: string2().optional()
5534
+ }),
5535
+ responses: {
5536
+ 200: { description: "Validation recorded", schema: successMessageSchema },
5537
+ 400: { description: "Validation error" },
5538
+ 401: { description: "Unauthorized" }
5539
+ },
5540
+ auth: { apiKey: true },
5541
+ rbac: {
5542
+ ungated: "worker credential telemetry, same posture as POST /api/keys/report-rate-limit"
5543
+ }
5544
+ });
5451
5545
  var reportAuthFailure = route({
5452
5546
  method: "post",
5453
5547
  path: "/api/keys/report-auth-failure",
@@ -5565,6 +5659,7 @@ var getAvailable = route({
5565
5659
  schema: object2({
5566
5660
  success: literal2(true),
5567
5661
  availableIndices: array2(number2().int()),
5662
+ rejectedIndices: array2(number2().int()).optional(),
5568
5663
  totalKeys: number2().int(),
5569
5664
  modelBlockedIndices: array2(number2().int()).optional(),
5570
5665
  earliestModelResetAt: string2().nullable().optional(),
@@ -5599,6 +5694,8 @@ var ApiKeyStatusSchema = object2({
5599
5694
  lastSeatMismatchModel: string2().nullable(),
5600
5695
  consecutiveAuthFailures: number2().int(),
5601
5696
  lastAuthFailureAt: string2().nullable(),
5697
+ lastValidationError: string2().nullable(),
5698
+ lastValidationFailedAt: string2().nullable(),
5602
5699
  modelLimits: array2(object2({
5603
5700
  model: string2(),
5604
5701
  window: string2(),
@@ -5821,6 +5918,19 @@ async function handleApiKeys(req, res, pathSegments, queryParams) {
5821
5918
  }
5822
5919
  return true;
5823
5920
  }
5921
+ if (reportValidation.match(req.method, pathSegments)) {
5922
+ const parsed = await reportValidation.parse(req, res, pathSegments, queryParams);
5923
+ if (!parsed)
5924
+ return true;
5925
+ const { keyType, keys, scope, scopeId } = parsed.body;
5926
+ try {
5927
+ await recordKeyValidation2(keyType, keys, scope, scopeId ?? null);
5928
+ reportValidation.respond(res, 200, { success: true, message: "Key validation recorded" });
5929
+ } catch (err) {
5930
+ jsonError(res, err instanceof Error ? err.message : "Failed to record key validation", 500);
5931
+ }
5932
+ return true;
5933
+ }
5824
5934
  if (reportAuthFailure.match(req.method, pathSegments)) {
5825
5935
  const parsed = await reportAuthFailure.parse(req, res, pathSegments, queryParams);
5826
5936
  if (!parsed)
@@ -5882,6 +5992,7 @@ async function handleApiKeys(req, res, pathSegments, queryParams) {
5882
5992
  getAvailable.respond(res, 200, {
5883
5993
  success: true,
5884
5994
  availableIndices: result.availableIndices,
5995
+ rejectedIndices: result.rejectedIndices,
5885
5996
  totalKeys,
5886
5997
  authFailureFence: result.authFailureFence,
5887
5998
  ...model !== undefined ? {
@@ -6044,6 +6155,7 @@ async function fillOrgLogoFromWebsite(website) {
6044
6155
  // src/http/config.ts
6045
6156
  init_rbac_roles();
6046
6157
  init_swarm_config_guard();
6158
+ init_users();
6047
6159
  init_rbac();
6048
6160
  init_types();
6049
6161
  init_request_auth_context();
@@ -6152,7 +6264,11 @@ async function handleUsedBy(req, res, pathSegments, queryParams, myAgentId) {
6152
6264
  org_website: orgWebsite,
6153
6265
  ...orgDomain ? { org_domain: orgDomain } : {},
6154
6266
  granted,
6155
- ...granted ? { contact_email: contactEmail, contact_function: contactFunction, quote } : {},
6267
+ ...granted ? {
6268
+ contact_email: contactEmail,
6269
+ contact_function: reportedUserFunction(contactFunction),
6270
+ quote
6271
+ } : {},
6156
6272
  changed_at: changedAt
6157
6273
  }),
6158
6274
  signal: AbortSignal.timeout(TIMEOUT_MS)
@@ -6513,6 +6629,28 @@ async function resolveSecretsRead(req, includeSecrets, resolvedScope) {
6513
6629
  secretsNote: includeSecrets && scope === "none" ? SECRETS_FORCE_MASK_NOTE : ""
6514
6630
  };
6515
6631
  }
6632
+ async function scriptRunHeldConfigIds(req) {
6633
+ const auth = getRequestAuth(req);
6634
+ if (auth?.kind !== "agent" || auth.tokenKind !== "agent")
6635
+ return;
6636
+ if (!await isScriptRunToken(auth.tokenId))
6637
+ return;
6638
+ const held = stripApiOnlyKeys(await getResolvedConfig2(auth.agentId, undefined, { includeRepoSecrets: false }));
6639
+ return new Set(held.map((config) => config.id));
6640
+ }
6641
+ async function maskConfigRead(req, configs, includeSecrets) {
6642
+ const { effectiveIncludeSecrets, secretsNote } = await resolveSecretsRead(req, includeSecrets);
6643
+ const held = includeSecrets && !effectiveIncludeSecrets ? await scriptRunHeldConfigIds(req) : undefined;
6644
+ const reveal = (config) => effectiveIncludeSecrets || !!held?.has(config.id);
6645
+ const result = configs.map((config) => config.isSecret && !reveal(config) ? maskSecrets2([config])[0] : config);
6646
+ for (const config of result) {
6647
+ if (config.isSecret && config.value && reveal(config)) {
6648
+ registerVolatileSecret(config.value, `config:${config.key}`);
6649
+ }
6650
+ }
6651
+ const anyMasked = result.some((config) => config.isSecret && !reveal(config));
6652
+ return { result, secretsNote: held && !anyMasked ? "" : secretsNote };
6653
+ }
6516
6654
  async function ensureConfigAdmin(req, res, verb) {
6517
6655
  return ensureHttpPermission(req, res, verb, verb === "config.write.any" ? "Writing swarm config requires the lead agent" : "Deleting swarm config requires the lead agent");
6518
6656
  }
@@ -6757,13 +6895,9 @@ async function handleConfig(req, res, pathSegments, queryParams) {
6757
6895
  jsonError(res, "Config not found", 404);
6758
6896
  return true;
6759
6897
  }
6760
- const { effectiveIncludeSecrets, secretsNote } = await resolveSecretsRead(req, includeSecrets);
6761
- const singleResult = effectiveIncludeSecrets ? config : maskSecrets2([config])[0];
6762
- if (effectiveIncludeSecrets && singleResult.isSecret && singleResult.value) {
6763
- registerVolatileSecret(singleResult.value, `config:${singleResult.key}`);
6764
- }
6898
+ const { result, secretsNote } = await maskConfigRead(req, [config], includeSecrets);
6765
6899
  getConfigById.respond(res, 200, {
6766
- ...singleResult,
6900
+ ...result[0],
6767
6901
  ...secretsNote ? { message: `Found 1 config(s).${secretsNote}` } : {}
6768
6902
  });
6769
6903
  return true;
@@ -6773,20 +6907,12 @@ async function handleConfig(req, res, pathSegments, queryParams) {
6773
6907
  if (!parsed)
6774
6908
  return true;
6775
6909
  const includeSecrets = parsed.query.includeSecrets === "true";
6776
- const { effectiveIncludeSecrets, secretsNote } = await resolveSecretsRead(req, includeSecrets);
6777
6910
  const configs = stripApiOnlyKeys(await getSwarmConfigs2({
6778
6911
  scope: parsed.query.scope || undefined,
6779
6912
  scopeId: parsed.query.scopeId || undefined,
6780
6913
  key: parsed.query.key
6781
6914
  }));
6782
- const listResult = effectiveIncludeSecrets ? configs : maskSecrets2(configs);
6783
- if (effectiveIncludeSecrets) {
6784
- for (const c of listResult) {
6785
- if (c.isSecret && c.value) {
6786
- registerVolatileSecret(c.value, `config:${c.key}`);
6787
- }
6788
- }
6789
- }
6915
+ const { result: listResult, secretsNote } = await maskConfigRead(req, configs, includeSecrets);
6790
6916
  listConfig.respond(res, 200, {
6791
6917
  configs: listResult,
6792
6918
  ...secretsNote ? { message: `Found ${listResult.length} config(s).${secretsNote}` } : {}
@@ -7550,6 +7676,8 @@ async function approvalQuorumMet(approvers, votes) {
7550
7676
 
7551
7677
  // src/http/assets.ts
7552
7678
  init_zod();
7679
+ init_key();
7680
+ init_source_key();
7553
7681
  init_asset_key_audit();
7554
7682
  init_db3();
7555
7683
  init_db2();
@@ -7809,6 +7937,16 @@ async function handleAssets(req, res, pathSegments, queryParams, myAgentId) {
7809
7937
  jsonError(res, await canReadSession2(req, myAgentId, task.id) ? "You can view this session but not move it." : SESSION_READ_DENIED2, 403);
7810
7938
  return true;
7811
7939
  }
7940
+ const destination = normalizeAssetKey(parsed.body.key);
7941
+ if (sourceOfKey(destination)) {
7942
+ const rootId = task.parentTaskId ? (await getSessionRoot(task.id))?.id : task.id;
7943
+ const root = rootId === task.id ? task : rootId ? await getTaskById2(rootId) : null;
7944
+ const sourceError = sourceMoveError(destination, root ?? { id: task.id });
7945
+ if (sourceError) {
7946
+ jsonError(res, sourceError, 400);
7947
+ return true;
7948
+ }
7949
+ }
7812
7950
  const tasks = parsed.body.cascade ? await getRootTaskChain2(task.id) : [task];
7813
7951
  for (const target of tasks) {
7814
7952
  if (!await canMutateTaskNamespace(target, myAgentId, req)) {
@@ -8034,6 +8172,165 @@ async function handleBudgets(req, res, pathSegments, queryParams, _myAgentId) {
8034
8172
  return false;
8035
8173
  }
8036
8174
 
8175
+ // src/http/codex-oauth-accounts.ts
8176
+ init_zod();
8177
+ init_crypto();
8178
+ init_db3();
8179
+ init_api_keys();
8180
+ init_codex_auth_failure();
8181
+ var CodexAccountSchema = object2({
8182
+ slot: number2().int().min(0),
8183
+ configKey: string2(),
8184
+ legacy: boolean(),
8185
+ suffix: string2().nullable(),
8186
+ plan: string2().nullable(),
8187
+ email: string2().nullable(),
8188
+ status: _enum2(["ok", "needs_login", "unchecked"])
8189
+ });
8190
+ var CodexAccountsResponseSchema = object2({ accounts: array2(CodexAccountSchema) });
8191
+ var listAccounts = route({
8192
+ method: "get",
8193
+ path: "/api/codex-oauth/accounts",
8194
+ pattern: ["api", "codex-oauth", "accounts"],
8195
+ summary: "List stored Codex ChatGPT accounts",
8196
+ tags: ["Codex OAuth"],
8197
+ responses: {
8198
+ 200: { description: "Stored account metadata", schema: CodexAccountsResponseSchema },
8199
+ 403: { description: "Caller cannot read all secrets" }
8200
+ }
8201
+ });
8202
+ var deleteAccount = route({
8203
+ method: "delete",
8204
+ path: "/api/codex-oauth/accounts/{slot}",
8205
+ pattern: ["api", "codex-oauth", "accounts", null],
8206
+ summary: "Remove a stored Codex ChatGPT account",
8207
+ tags: ["Codex OAuth"],
8208
+ rbac: { permission: "config.delete.any" },
8209
+ params: object2({ slot: exports_coerce.number().int().min(0).max(MAX_CODEX_OAUTH_SLOT) }),
8210
+ responses: {
8211
+ 200: { description: "Remaining accounts", schema: CodexAccountsResponseSchema },
8212
+ 403: { description: "Config administration and permission to read all secrets required" },
8213
+ 404: { description: "Account slot does not exist" }
8214
+ }
8215
+ });
8216
+ async function accountRows() {
8217
+ const rows = await getDbClient2().query("SELECT key, value, encrypted FROM swarm_config WHERE scope = 'global' AND (key = 'codex_oauth' OR key GLOB 'codex_oauth_[0-9]*')");
8218
+ const hasSlotZero = rows.some((row) => row.key === "codex_oauth_0");
8219
+ return rows.flatMap((row) => {
8220
+ if (row.key === "codex_oauth") {
8221
+ return hasSlotZero ? [] : [{ ...row, slot: 0, legacy: true }];
8222
+ }
8223
+ const match = /^codex_oauth_(0|[1-9]\d*)$/.exec(row.key);
8224
+ if (!match)
8225
+ return [];
8226
+ const slot = Number(match[1]);
8227
+ return slot <= MAX_CODEX_OAUTH_SLOT ? [{ ...row, slot, legacy: false }] : [];
8228
+ }).sort((a, b) => a.slot - b.slot);
8229
+ }
8230
+ var AccountCredentialsSchema = object2({
8231
+ access: string2().min(1),
8232
+ refresh: string2().min(1),
8233
+ expires: number2().finite(),
8234
+ accountId: string2().min(1)
8235
+ });
8236
+ function readCredentials(row) {
8237
+ try {
8238
+ const value = row.encrypted ? decryptSecret(row.value, getEncryptionKey()) : row.value;
8239
+ return AccountCredentialsSchema.parse(JSON.parse(value));
8240
+ } catch {
8241
+ return null;
8242
+ }
8243
+ }
8244
+ function accountSuffix(row) {
8245
+ const credentials = readCredentials(row);
8246
+ return credentials ? deriveCodexKeySuffix(credentials.access, credentials.accountId) : null;
8247
+ }
8248
+ async function accountsResponse() {
8249
+ const rows = await accountRows();
8250
+ const statuses = await getKeyStatuses2("CODEX_OAUTH", "global", null);
8251
+ const accounts = [];
8252
+ for (const row of rows) {
8253
+ const account = {
8254
+ slot: row.slot,
8255
+ configKey: row.key,
8256
+ legacy: row.legacy,
8257
+ suffix: null,
8258
+ plan: null,
8259
+ email: null,
8260
+ status: "needs_login"
8261
+ };
8262
+ const credentials = readCredentials(row);
8263
+ if (!credentials) {
8264
+ accounts.push(account);
8265
+ continue;
8266
+ }
8267
+ account.suffix = deriveCodexKeySuffix(credentials.access, credentials.accountId);
8268
+ account.plan = extractChatgptPlanType(credentials.access);
8269
+ const profile = decodeJwt(credentials.access)?.["https://api.openai.com/profile"];
8270
+ if (profile && typeof profile === "object" && "email" in profile) {
8271
+ account.email = typeof profile.email === "string" && profile.email ? profile.email : null;
8272
+ }
8273
+ const status = statuses.find((entry) => entry.keySuffix === account.suffix);
8274
+ const marker = await getKv2(CODEX_AUTH_WATCH_NAMESPACE, codexAuthBenchMarkerKey(account.suffix));
8275
+ const statusBenched = status && status.consecutiveAuthFailures >= CODEX_AUTH_FAILURE_BENCH_THRESHOLD && status.status === "rate_limited";
8276
+ account.status = marker || statusBenched ? "needs_login" : status ? "ok" : "unchecked";
8277
+ accounts.push(account);
8278
+ }
8279
+ return { accounts };
8280
+ }
8281
+ async function ensureSecretRead(req, res) {
8282
+ if (await requestSecretReadScope(req) === "all")
8283
+ return true;
8284
+ jsonError(res, "Reading Codex accounts requires access to all secrets", 403);
8285
+ return false;
8286
+ }
8287
+ async function handleCodexOAuthAccounts(req, res, pathSegments, queryParams) {
8288
+ if (listAccounts.match(req.method, pathSegments)) {
8289
+ const parsed = await listAccounts.parse(req, res, pathSegments, queryParams);
8290
+ if (!parsed)
8291
+ return true;
8292
+ if (!await ensureSecretRead(req, res))
8293
+ return true;
8294
+ listAccounts.respond(res, 200, await accountsResponse());
8295
+ return true;
8296
+ }
8297
+ if (deleteAccount.match(req.method, pathSegments)) {
8298
+ const parsed = await deleteAccount.parse(req, res, pathSegments, queryParams);
8299
+ if (!parsed)
8300
+ return true;
8301
+ if (!await ensureConfigAdmin(req, res, "config.delete.any"))
8302
+ return true;
8303
+ if (!await ensureSecretRead(req, res))
8304
+ return true;
8305
+ const deletedKey = await getDbClient2().transaction(async () => {
8306
+ const rows = await accountRows();
8307
+ const account = rows.find((row) => row.slot === parsed.params.slot);
8308
+ if (!account || !await deleteSwarmConfigByKey2("global", null, account.key))
8309
+ return null;
8310
+ const suffix = accountSuffix(account);
8311
+ if (suffix) {
8312
+ const remaining = rows.flatMap((row) => {
8313
+ const keySuffix = row === account ? null : accountSuffix(row);
8314
+ return keySuffix ? [{ keySuffix, keyIndex: row.slot }] : [];
8315
+ });
8316
+ await retirePoolKeyStatus("CODEX_OAUTH", suffix, remaining);
8317
+ if (!remaining.some((row) => row.keySuffix === suffix)) {
8318
+ await deleteKv2(CODEX_AUTH_WATCH_NAMESPACE, codexAuthBenchMarkerKey(suffix));
8319
+ }
8320
+ }
8321
+ return account.key;
8322
+ });
8323
+ if (deletedKey === null) {
8324
+ jsonError(res, "Codex account slot does not exist", 404);
8325
+ return true;
8326
+ }
8327
+ await runConfigWriteSideEffects("global", deletedKey, "");
8328
+ deleteAccount.respond(res, 200, await accountsResponse());
8329
+ return true;
8330
+ }
8331
+ return false;
8332
+ }
8333
+
8037
8334
  // src/http/codex-oauth-device.ts
8038
8335
  init_zod();
8039
8336
  init_crypto();
@@ -8174,7 +8471,9 @@ var OnboardingSignalsSchema = object2({
8174
8471
  provider: ProviderNameSchema,
8175
8472
  state: _enum2(["unverified", "configured", "verified"]),
8176
8473
  workers: number2().int().nonnegative(),
8177
- verifiedWorkers: number2().int().nonnegative()
8474
+ verifiedWorkers: number2().int().nonnegative(),
8475
+ error: string2().nullable(),
8476
+ warning: string2().nullable()
8178
8477
  })),
8179
8478
  embeddings: object2({
8180
8479
  configured: boolean(),
@@ -9099,6 +9398,7 @@ function sentTaskId(thread, replies, serviceUserId) {
9099
9398
  // src/comb/review-batch.ts
9100
9399
  init_templates();
9101
9400
  var REVIEW_BATCH_MAX = 50;
9401
+ var REVIEW_NOTE_MAX = 4000;
9102
9402
  var REVIEW_BATCH_READ_CONCURRENCY = 5;
9103
9403
  var SENT_KV_NAMESPACE = "comb:sent";
9104
9404
  var PENDING_CLAIM_MS = 5 * 60000;
@@ -9129,6 +9429,9 @@ async function sendReviewBatch(input, deps = {}) {
9129
9429
  if (ids.length === 0 || ids.length > REVIEW_BATCH_MAX) {
9130
9430
  throw new ReviewBatchError(400, `Send between 1 and ${REVIEW_BATCH_MAX} comments`);
9131
9431
  }
9432
+ if ((input.note?.length ?? 0) > REVIEW_NOTE_MAX) {
9433
+ throw new ReviewBatchError(400, `The note is longer than ${REVIEW_NOTE_MAX} characters`);
9434
+ }
9132
9435
  const agentFs = combAgentFs();
9133
9436
  if (!agentFs)
9134
9437
  throw new ReviewBatchError(503, "agent-fs is not set up for this swarm");
@@ -9162,6 +9465,7 @@ async function sendReviewBatch(input, deps = {}) {
9162
9465
  }
9163
9466
  const wonIds = won.map((read) => read.id);
9164
9467
  let taskId = null;
9468
+ let leadState = "none";
9165
9469
  if (won.length > 0) {
9166
9470
  try {
9167
9471
  const text = await renderTaskText(input, won);
@@ -9172,6 +9476,7 @@ async function sendReviewBatch(input, deps = {}) {
9172
9476
  ]);
9173
9477
  }
9174
9478
  const lead = await getLeadAgent2();
9479
+ leadState = !lead ? "none" : lead.status === "offline" ? "offline" : "online";
9175
9480
  const task = await createTask(text, {
9176
9481
  agentId: lead?.id ?? "",
9177
9482
  routingReason: lead ? "skill" : undefined,
@@ -9208,7 +9513,7 @@ async function sendReviewBatch(input, deps = {}) {
9208
9513
  if (taskId === null && repaired.length === 0) {
9209
9514
  throw new ReviewBatchError(409, "Nothing to send", skipped);
9210
9515
  }
9211
- return { taskId, sent: wonIds, skipped, repaired };
9516
+ return taskId === null ? { taskId, sent: wonIds, skipped, repaired } : { taskId, sent: wonIds, skipped, repaired, lead: leadState };
9212
9517
  }
9213
9518
  async function mapLimited(items, limit, fn) {
9214
9519
  const results = new Array(items.length);
@@ -9353,6 +9658,7 @@ async function renderTaskText(input, reads) {
9353
9658
  requested_by: await requesterLabel(input.requestedByUserId),
9354
9659
  org_id: input.orgId,
9355
9660
  drive_id: input.driveId,
9661
+ note_block: noteBlock(input.note),
9356
9662
  comments_block: blocks.join(`
9357
9663
  `)
9358
9664
  });
@@ -9367,6 +9673,13 @@ function lineRange(comment) {
9367
9673
  const end = comment.lineEnd ?? comment.lineStart;
9368
9674
  return end === comment.lineStart ? `line ${comment.lineStart}` : `lines ${comment.lineStart}-${end}`;
9369
9675
  }
9676
+ function noteBlock(note) {
9677
+ const text = note?.trim();
9678
+ return text ? `
9679
+ Note from the sender, about all the comments:
9680
+ ${fenced(text)}
9681
+ ` : "";
9682
+ }
9370
9683
  function fenced(text) {
9371
9684
  const longest = (text.match(/`+/g) ?? []).reduce((max, run) => Math.max(max, run.length), 0);
9372
9685
  const fence = "`".repeat(Math.max(3, longest + 1));
@@ -9407,7 +9720,8 @@ var resultSchema = object2({
9407
9720
  taskId: string2().nullable(),
9408
9721
  sent: array2(string2()),
9409
9722
  skipped: array2(skippedSchema),
9410
- repaired: array2(object2({ id: string2(), taskId: string2() }))
9723
+ repaired: array2(object2({ id: string2(), taskId: string2() })),
9724
+ lead: _enum2(["online", "offline", "none"]).optional()
9411
9725
  });
9412
9726
  var batchErrorSchema = object2({ error: string2(), skipped: array2(skippedSchema) });
9413
9727
  function isDrivePath(path) {
@@ -9418,13 +9732,14 @@ var reviewBatchRoute = route({
9418
9732
  path: "/api/comb/review-batches",
9419
9733
  pattern: ["api", "comb", "review-batches"],
9420
9734
  summary: "Send agent-fs comments to the swarm as one lead task",
9421
- description: "Comb's 'Send to swarm'. The server reads each comment again from agent-fs with its bootstrap key, skips replies, resolved comments, and comments already sent, and creates ONE task for the lead. Each sent comment gets a `[comb:sent task=<id>]` reply from the swarm service account. A comment is sent at most once. When an earlier send lost its reply, the batch posts that reply again (`repaired`). Answers 404 while COMB_ENABLED is off.",
9735
+ description: "Comb's 'Send to swarm'. The server reads each comment again from agent-fs with its bootstrap key, skips replies, resolved comments, and comments already sent, and creates ONE task for the lead. Each sent comment gets a `[comb:sent task=<id>]` reply from the swarm service account. A comment is sent at most once. An optional `note` from the sender goes into the task text. When an earlier send lost its reply, the batch posts that reply again (`repaired`). Answers 404 while COMB_ENABLED is off.",
9422
9736
  tags: ["Comb"],
9423
9737
  body: object2({
9424
9738
  orgId: string2().min(1),
9425
9739
  driveId: string2().min(1),
9426
9740
  commentIds: array2(uuid()).min(1).max(REVIEW_BATCH_MAX),
9427
- scopePath: string2().min(1).max(1024).refine(isDrivePath, "scopePath must start with '/' and have no '.' or '..' segment")
9741
+ scopePath: string2().min(1).max(1024).refine(isDrivePath, "scopePath must start with '/' and have no '.' or '..' segment"),
9742
+ note: string2().max(REVIEW_NOTE_MAX).optional()
9428
9743
  }),
9429
9744
  responses: {
9430
9745
  200: {
@@ -9814,16 +10129,16 @@ declare module "swarm-extension" {
9814
10129
  | "schedule"
9815
10130
  | "slack"
9816
10131
  | "agentmail"
9817
- | "mcp"
9818
- | "api"
9819
- | "ui"
9820
10132
  | "github"
9821
10133
  | "gitlab"
9822
10134
  | "azure-devops"
9823
10135
  | "bitbucket"
9824
- | "system"
9825
10136
  | "linear"
9826
10137
  | "jira"
10138
+ | "mcp"
10139
+ | "api"
10140
+ | "ui"
10141
+ | "system"
9827
10142
  | "comb"
9828
10143
  | "chat"
9829
10144
  | undefined;
@@ -9932,16 +10247,16 @@ declare module "swarm-extension" {
9932
10247
  | "schedule"
9933
10248
  | "slack"
9934
10249
  | "agentmail"
9935
- | "mcp"
9936
- | "api"
9937
- | "ui"
9938
10250
  | "github"
9939
10251
  | "gitlab"
9940
10252
  | "azure-devops"
9941
10253
  | "bitbucket"
9942
- | "system"
9943
10254
  | "linear"
9944
10255
  | "jira"
10256
+ | "mcp"
10257
+ | "api"
10258
+ | "ui"
10259
+ | "system"
9945
10260
  | "comb"
9946
10261
  | "chat";
9947
10262
  tags: string[];
@@ -10206,6 +10521,45 @@ declare module "swarm-extension" {
10206
10521
  description: string;
10207
10522
  origin: TaskCreateOrigin;
10208
10523
  requestInfo?: RequestInfo;
10524
+ /** Slack ingress metadata; not persisted or writable through modify. */
10525
+ slack?: {
10526
+ trigger: "mention" | "thread-buffer";
10527
+ messages: {
10528
+ ts: string;
10529
+ userId: string;
10530
+ text: string;
10531
+ }[];
10532
+ };
10533
+ }
10534
+ /** A pre.task.create hook blocked a task before it was created. */
10535
+ export interface TaskBlockedEvent {
10536
+ /** The extension that blocked, or whose model/agent rewrite was rejected. */
10537
+ extension: {
10538
+ id: string;
10539
+ name: string;
10540
+ };
10541
+ /** The scrubbed block reason. */
10542
+ reason: string;
10543
+ origin: TaskCreateOrigin;
10544
+ source?: AgentTask["source"];
10545
+ requester: {
10546
+ userId?: string;
10547
+ agentId?: string;
10548
+ slackUserId?: string;
10549
+ };
10550
+ context?: {
10551
+ contextKey?: string;
10552
+ scheduleId?: string;
10553
+ workflowRunId?: string;
10554
+ workflowRunStepId?: string;
10555
+ parentTaskId?: string;
10556
+ vcsRepo?: string;
10557
+ vcsNumber?: number;
10558
+ slackChannelId?: string;
10559
+ slackThreadTs?: string;
10560
+ };
10561
+ /** The original task description, scrubbed and cut to 500 characters. */
10562
+ description: string;
10209
10563
  }
10210
10564
  export type TaskCreateModify = Partial<
10211
10565
  Pick<
@@ -10509,6 +10863,11 @@ declare module "swarm-extension" {
10509
10863
  modify: never;
10510
10864
  result: void;
10511
10865
  };
10866
+ "post.task.blocked": {
10867
+ event: TaskBlockedEvent;
10868
+ modify: never;
10869
+ result: void;
10870
+ };
10512
10871
  "post.task.completed": {
10513
10872
  event: TaskCompletedEvent;
10514
10873
  modify: never;
@@ -13600,6 +13959,7 @@ async function buildFleetBenchmarkResponse(now = new Date) {
13600
13959
  const team = _enum2(COMPANY_TEAM_SIZES).safeParse(teamSize);
13601
13960
  const use = _enum2(COMPANY_USE_CASES).safeParse(useCase);
13602
13961
  const peerGroup = normalizeOrgWebsite(website) && team.success && use.success ? { teamSize: team.data, useCase: use.data } : null;
13962
+ const proxyPeerGroup = peerGroup && reportedUseCase(peerGroup.useCase) ? peerGroup : null;
13603
13963
  const empty = {
13604
13964
  level: peerGroup ? "full" : "basic",
13605
13965
  peerGroup: null,
@@ -13626,7 +13986,7 @@ async function buildFleetBenchmarkResponse(now = new Date) {
13626
13986
  return { ...empty, state: "telemetry_off", local };
13627
13987
  if (finishedTasks < FLEET_MIN_FINISHED_TASKS)
13628
13988
  return { ...empty, state: "not_enough_tasks", local };
13629
- const fleet = await fleetBenchmarks(now.getTime(), peerGroup);
13989
+ const fleet = await fleetBenchmarks(now.getTime(), proxyPeerGroup);
13630
13990
  const responsePeerGroup = peerGroup && fleet?.peer_group ? {
13631
13991
  teamSize: fleet.peer_group.team_size,
13632
13992
  useCase: fleet.peer_group.use_case,
@@ -14683,6 +15043,9 @@ function buildSlackManifest(name) {
14683
15043
  return manifest;
14684
15044
  }
14685
15045
 
15046
+ // src/http/integrations.ts
15047
+ init_credentials();
15048
+
14686
15049
  // src/http/config-values.ts
14687
15050
  init_db3();
14688
15051
  async function resolveConfigValue(key) {
@@ -14857,7 +15220,7 @@ function createIntegrationsHandler(deps = {}) {
14857
15220
  return true;
14858
15221
  }
14859
15222
  try {
14860
- const client = buildClient(apiKey);
15223
+ const client = buildClient(selectCredential(apiKey, undefined, "ANTHROPIC_API_KEY").selected);
14861
15224
  const agent = await client.beta.agents.retrieve(agentId);
14862
15225
  const modelId = typeof agent.model === "string" ? agent.model : agent.model?.id ?? null;
14863
15226
  claudeManagedTestRoute.respond(res, 200, {
@@ -15134,8 +15497,8 @@ function authorizeWrite(namespace, ctx) {
15134
15497
  return null;
15135
15498
  }
15136
15499
  function authorizeRead(namespace, ctx) {
15137
- const overflowAuthErr = mcpOverflowAuthError(namespace, ctx.callerAgentId);
15138
- return overflowAuthErr ? { status: 403, message: overflowAuthErr } : null;
15500
+ const readErr = privateNamespaceError(namespace) ?? mcpOverflowAuthError(namespace, ctx.callerAgentId);
15501
+ return readErr ? { status: 403, message: readErr } : null;
15139
15502
  }
15140
15503
  function encodeValueOrError(res, value, valueType) {
15141
15504
  try {
@@ -21537,6 +21900,7 @@ init_db3();
21537
21900
  init_memory();
21538
21901
  init_constants();
21539
21902
  init_types();
21903
+ init_credentials();
21540
21904
  init_openrouter_base_url();
21541
21905
 
21542
21906
  // src/http/status.ts
@@ -21605,6 +21969,7 @@ var StatusIdentitySchema = object2({
21605
21969
  var StatusActivitySchema = object2({
21606
21970
  agents_online: number2().int().nonnegative(),
21607
21971
  leads_online: number2().int().nonnegative(),
21972
+ leads_ready: number2().int().nonnegative(),
21608
21973
  recent_tasks_count: number2().int().nonnegative()
21609
21974
  });
21610
21975
  var StatusCombSchema = object2({
@@ -21985,7 +22350,7 @@ async function buildSetup(automationSetup) {
21985
22350
  await firstTaskMilestone()
21986
22351
  ];
21987
22352
  }
21988
- function computeHealth(setup) {
22353
+ function computeHealth(setup, readyLeads) {
21989
22354
  const byId = new Map(setup.map((m) => [m.id, m]));
21990
22355
  const harness = byId.get("harness");
21991
22356
  const workers = byId.get("workers");
@@ -21993,6 +22358,8 @@ function computeHealth(setup) {
21993
22358
  return "broken";
21994
22359
  if (!workers || workers.state === "unverified")
21995
22360
  return "broken";
22361
+ if (readyLeads === 0)
22362
+ return "degraded";
21996
22363
  if (harness.state === "configured")
21997
22364
  return "degraded";
21998
22365
  for (const id of ["slack", "github", "linear", "jira"]) {
@@ -22010,12 +22377,13 @@ async function buildStatusPayload() {
22010
22377
  const toStatus = ({ failureReason: _, ...status }) => status;
22011
22378
  const automations = automationInputs.map((automation) => toStatus(preflightAutomation(automation, automationSetup))).sort((a, b) => a.name.localeCompare(b.name) || a.kind.localeCompare(b.kind));
22012
22379
  const activity = await getInstanceActivity2();
22380
+ const readyLeads = (await getReadyAgentCounts2()).leads;
22013
22381
  const instance = await getInstanceFeedbackSignals();
22014
22382
  return {
22015
22383
  runtime_pools: { enabled: isRuntimePoolsEnabled(), supervisor: runtimeSupervisorStatus() },
22016
22384
  identity: buildIdentity(),
22017
22385
  setup,
22018
- activity,
22386
+ activity: { ...activity, leads_ready: readyLeads },
22019
22387
  agent_fs: {
22020
22388
  configured: !!process.env.AGENT_FS_API_URL,
22021
22389
  base_url: process.env.AGENT_FS_API_URL ?? null,
@@ -22023,7 +22391,7 @@ async function buildStatusPayload() {
22023
22391
  comb: getCombStatus(await combServiceUserId)
22024
22392
  },
22025
22393
  automations,
22026
- health: computeHealth(setup),
22394
+ health: computeHealth(setup, readyLeads),
22027
22395
  telemetry: { enabled: isTelemetryEnabled() },
22028
22396
  instance
22029
22397
  };
@@ -22058,7 +22426,7 @@ var getStatus = route({
22058
22426
  path: "/status",
22059
22427
  pattern: ["status"],
22060
22428
  summary: "Identity + setup readiness + live activity for the swarm dashboard",
22061
- description: "Single source of truth consumed by the UI home page. Identity comes from SWARM_* envs; setup milestones each emit `unverified | configured | verified`; automations report `running | needs_setup` from the same runtime preflight used at dispatch; activity counts agents alive in the last 5 min and tasks created in the last 24h; agent_fs reports whether AGENT_FS_API_URL is set, plus the Comb settings (COMB_ENABLED, the browser-facing agent-fs URL, the shared org and drive ids, and the agent-fs user id of the swarm service account); telemetry reports the effective ANONYMIZED_TELEMETRY opt-out state.",
22429
+ description: "Single source of truth consumed by the UI home page. Identity comes from SWARM_* envs; setup milestones each emit `unverified | configured | verified`; automations report `running | needs_setup` from the same runtime preflight used at dispatch; activity counts agents alive in the last 5 min, leads that can take work (status idle or busy), and tasks created in the last 24h; agent_fs reports whether AGENT_FS_API_URL is set, plus the Comb settings (COMB_ENABLED, the browser-facing agent-fs URL, the shared org and drive ids, and the agent-fs user id of the swarm service account); telemetry reports the effective ANONYMIZED_TELEMETRY opt-out state.",
22062
22430
  tags: ["Status"],
22063
22431
  responses: {
22064
22432
  200: { description: "Status payload", schema: StatusResponseSchema },
@@ -22131,11 +22499,14 @@ async function buildSignals(state) {
22131
22499
  if (!provider.success)
22132
22500
  continue;
22133
22501
  const rollup = await rollupCredStatusForProvider(provider.data);
22502
+ const live = rollup.latestLiveTest;
22134
22503
  providers.push({
22135
22504
  provider: provider.data,
22136
22505
  state: rollup.state,
22137
22506
  workers: rollup.workers,
22138
- verifiedWorkers: rollup.verifiedWorkers
22507
+ verifiedWorkers: rollup.verifiedWorkers,
22508
+ error: live && !live.ok ? live.error ?? null : null,
22509
+ warning: live?.ok ? live.warning ?? null : null
22139
22510
  });
22140
22511
  }
22141
22512
  const integrations = await getAutomationSetupStates();
@@ -22281,7 +22652,7 @@ async function handleMemoryProbe(body) {
22281
22652
  const canReuseKey = reuseHost === undefined || endpoint.hostname === reuseHost;
22282
22653
  const reusedKey = !explicitKey && body.reuseKey && canReuseKey ? process.env[body.reuseKey] : undefined;
22283
22654
  const implicitKey = body.preset === "existing" ? process.env.EMBEDDING_API_KEY ?? process.env.OPENAI_API_KEY : undefined;
22284
- const apiKey = explicitKey ?? reusedKey ?? implicitKey;
22655
+ const apiKey = splitCredentialPool(explicitKey ?? reusedKey ?? implicitKey ?? "")[0];
22285
22656
  if (!apiKey) {
22286
22657
  return {
22287
22658
  ok: false,
@@ -22741,6 +23112,7 @@ var listTasks = route({
22741
23112
  status: string2().optional(),
22742
23113
  agentId: string2().optional(),
22743
23114
  scheduleId: string2().optional(),
23115
+ workflowRunId: string2().uuid().optional(),
22744
23116
  key: AssetKeySchema.optional(),
22745
23117
  keyPrefix: AssetKeySchema.optional(),
22746
23118
  search: string2().optional(),
@@ -23343,6 +23715,7 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
23343
23715
  status,
23344
23716
  agentId: parsed.query.agentId || undefined,
23345
23717
  scheduleId: parsed.query.scheduleId || undefined,
23718
+ workflowRunId: parsed.query.workflowRunId,
23346
23719
  key: parsed.query.key,
23347
23720
  keyPrefix: parsed.query.keyPrefix,
23348
23721
  search: parsed.query.search || undefined,
@@ -27249,6 +27622,298 @@ async function handlePoll(req, res, pathSegments, queryParams, myAgentId) {
27249
27622
  return false;
27250
27623
  }
27251
27624
 
27625
+ // src/http/pool-keys.ts
27626
+ init_src2();
27627
+ init_zod();
27628
+ init_db3();
27629
+ init_api_keys();
27630
+ init_swarm_config_guard();
27631
+ init_credentials();
27632
+ init_secret_scrubber();
27633
+ var PoolKeyStatusSchema = _enum2(["ok", "rejected", "rate_limited", "unchecked"]);
27634
+ var PoolKeySchema = object2({
27635
+ index: number2().int().min(0),
27636
+ suffix: string2(),
27637
+ status: PoolKeyStatusSchema,
27638
+ error: string2().nullable(),
27639
+ checkedAt: string2().nullable(),
27640
+ rateLimitedUntil: string2().nullable()
27641
+ });
27642
+ var PoolKeysResponseSchema = object2({
27643
+ key: string2(),
27644
+ source: _enum2(["stored", "env", "none"]),
27645
+ readOnly: boolean(),
27646
+ keys: array2(PoolKeySchema)
27647
+ });
27648
+ var PoolKeyCheckResultSchema = _enum2(["verified", "rejected", "not_tested"]);
27649
+ var PoolKeyCheckSchema = object2({
27650
+ suffix: string2(),
27651
+ result: PoolKeyCheckResultSchema,
27652
+ httpStatus: number2().nullable(),
27653
+ error: string2().nullable()
27654
+ });
27655
+ var poolVar = string2().refine((key) => key !== "CODEX_OAUTH" && CREDENTIAL_POOL_VARS.includes(key), "Choose a credential pool variable.");
27656
+ var getPoolKeys = route({
27657
+ method: "get",
27658
+ path: "/api/config/pool-keys",
27659
+ pattern: ["api", "config", "pool-keys"],
27660
+ summary: "List credential pool suffixes and status",
27661
+ tags: ["Config"],
27662
+ query: object2({ key: poolVar }),
27663
+ responses: {
27664
+ 200: { description: "Credential pool", schema: PoolKeysResponseSchema },
27665
+ 400: { description: "Invalid pool variable" },
27666
+ 403: { description: "Secret read permission required" }
27667
+ }
27668
+ });
27669
+ var addPoolKeys = route({
27670
+ method: "post",
27671
+ path: "/api/config/pool-keys",
27672
+ pattern: ["api", "config", "pool-keys"],
27673
+ summary: "Test and append keys to a credential pool",
27674
+ tags: ["Config"],
27675
+ rbac: { permission: "config.write.any" },
27676
+ body: object2({
27677
+ key: poolVar,
27678
+ value: string2(),
27679
+ baseUrl: string2().nullable().optional().describe("Base URL for the check only. Null tests the provider default. Omit to use the stored URL.")
27680
+ }),
27681
+ responses: {
27682
+ 200: {
27683
+ description: "Updated credential pool and checks",
27684
+ schema: PoolKeysResponseSchema.extend({ checks: array2(PoolKeyCheckSchema) })
27685
+ },
27686
+ 400: { description: "Invalid key" },
27687
+ 403: { description: "Config administration and permission to read all secrets required" },
27688
+ 409: { description: "Duplicate key or deployment env pool" },
27689
+ 422: {
27690
+ description: "Provider rejected a key. Nothing was saved.",
27691
+ schema: object2({ error: string2(), checks: array2(PoolKeyCheckSchema) })
27692
+ }
27693
+ }
27694
+ });
27695
+ var deletePoolKey = route({
27696
+ method: "delete",
27697
+ path: "/api/config/pool-keys",
27698
+ pattern: ["api", "config", "pool-keys"],
27699
+ summary: "Remove one credential pool member",
27700
+ tags: ["Config"],
27701
+ rbac: { permission: "config.delete.any" },
27702
+ query: object2({
27703
+ key: poolVar,
27704
+ index: exports_coerce.number().int().min(0),
27705
+ suffix: string2().min(1).max(5)
27706
+ }),
27707
+ responses: {
27708
+ 200: { description: "Updated credential pool", schema: PoolKeysResponseSchema },
27709
+ 400: { description: "Invalid pool member" },
27710
+ 403: { description: "Config administration and permission to read all secrets required" },
27711
+ 409: { description: "The pool changed or comes from the deployment env" }
27712
+ }
27713
+ });
27714
+ var ENV_POOL_ERROR = "These keys come from the deployment env. Change them there.";
27715
+ async function readPool(key) {
27716
+ const [row] = await getSwarmConfigs2({ scope: "global", key });
27717
+ const envValue = getDeploymentEnvValue(key);
27718
+ const source = row ? "stored" : envValue ? "env" : "none";
27719
+ const value = row?.value ?? envValue ?? "";
27720
+ registerEnvSecrets({ [key]: value });
27721
+ return { row, source, members: splitCredentialPool(value) };
27722
+ }
27723
+ async function poolResponse(key) {
27724
+ const pool = await readPool(key);
27725
+ const statuses = await getKeyStatuses2(key, "global", null);
27726
+ return {
27727
+ key,
27728
+ source: pool.source,
27729
+ readOnly: pool.source === "env",
27730
+ keys: pool.members.map((member, index) => {
27731
+ const suffix = member.slice(-5);
27732
+ const row = statuses.find((status) => status.keySuffix === suffix);
27733
+ const rejected = !!row?.lastValidationFailedAt;
27734
+ const limited = row?.status === "rate_limited" && !!row.rateLimitedUntil && Date.parse(row.rateLimitedUntil) > Date.now();
27735
+ return {
27736
+ index,
27737
+ suffix,
27738
+ status: rejected ? "rejected" : limited ? "rate_limited" : row ? "ok" : "unchecked",
27739
+ error: rejected ? scrubSecrets(row?.lastValidationError) || null : null,
27740
+ checkedAt: rejected ? row.lastValidationFailedAt : row?.updatedAt ?? null,
27741
+ rateLimitedUntil: row?.rateLimitedUntil ?? null
27742
+ };
27743
+ })
27744
+ };
27745
+ }
27746
+ function duplicateError(members, additions) {
27747
+ const seen = new Set(members);
27748
+ for (const member of additions) {
27749
+ if (seen.has(member))
27750
+ return `The key ending ${member.slice(-5)} is already in the pool.`;
27751
+ seen.add(member);
27752
+ }
27753
+ return null;
27754
+ }
27755
+ async function savePool(key, members, row) {
27756
+ const value = members.join(",");
27757
+ const validationError = validateConfigEntry({
27758
+ scope: "global",
27759
+ key,
27760
+ value,
27761
+ exportToEnv: row?.exportToEnv
27762
+ });
27763
+ if (validationError)
27764
+ return validationError;
27765
+ await upsertSwarmConfigWithPolicyMirror({
27766
+ scope: "global",
27767
+ key,
27768
+ value,
27769
+ isSecret: true,
27770
+ description: row?.description ?? null,
27771
+ envPath: row?.envPath ?? null,
27772
+ exportToEnv: row?.exportToEnv
27773
+ });
27774
+ return null;
27775
+ }
27776
+ async function ensureSecretRead2(req, res) {
27777
+ if (await requestSecretReadScope(req) === "all")
27778
+ return true;
27779
+ jsonError(res, "Reading credential pools requires permission to read all secrets.", 403);
27780
+ return false;
27781
+ }
27782
+ async function handlePoolKeys(req, res, pathSegments, queryParams) {
27783
+ if (getPoolKeys.match(req.method, pathSegments)) {
27784
+ const parsed = await getPoolKeys.parse(req, res, pathSegments, queryParams);
27785
+ if (!parsed)
27786
+ return true;
27787
+ if (!await ensureSecretRead2(req, res))
27788
+ return true;
27789
+ getPoolKeys.respond(res, 200, await poolResponse(parsed.query.key));
27790
+ return true;
27791
+ }
27792
+ if (addPoolKeys.match(req.method, pathSegments)) {
27793
+ const parsed = await addPoolKeys.parse(req, res, pathSegments, queryParams);
27794
+ if (!parsed)
27795
+ return true;
27796
+ if (!await ensureConfigAdmin(req, res, "config.write.any"))
27797
+ return true;
27798
+ if (!await ensureSecretRead2(req, res))
27799
+ return true;
27800
+ const { key, value, baseUrl } = parsed.body;
27801
+ const additions = value.split(",").map((part) => part.trim()).filter(Boolean);
27802
+ if (!additions.length) {
27803
+ jsonError(res, "Enter a key.", 400);
27804
+ return true;
27805
+ }
27806
+ if (additions.some((part) => /\s/.test(part))) {
27807
+ jsonError(res, "A key cannot contain spaces or line breaks.", 400);
27808
+ return true;
27809
+ }
27810
+ registerEnvSecrets({ [key]: additions.join(",") });
27811
+ const initial = await readPool(key);
27812
+ if (initial.source === "env") {
27813
+ jsonError(res, ENV_POOL_ERROR, 409);
27814
+ return true;
27815
+ }
27816
+ const duplicate = duplicateError(initial.members, additions);
27817
+ if (duplicate) {
27818
+ jsonError(res, scrubSecrets(duplicate), 409);
27819
+ return true;
27820
+ }
27821
+ const env = { ...process.env };
27822
+ const provider = providerForKeyVar(key);
27823
+ const baseUrlKey = key === "OPENROUTER_API_KEY" ? "OPENROUTER_BASE_URL" : provider ? baseUrlEnvVar(provider) : undefined;
27824
+ if (baseUrlKey && baseUrl !== undefined) {
27825
+ env[baseUrlKey] = baseUrl ?? "";
27826
+ } else if (baseUrlKey) {
27827
+ const [row] = await getSwarmConfigs2({ scope: "global", key: baseUrlKey });
27828
+ if (row)
27829
+ env[baseUrlKey] = row.value;
27830
+ }
27831
+ const checks = await Promise.all(additions.map(async (member) => {
27832
+ try {
27833
+ const probe = await checkProviderPoolKey(key, member, env);
27834
+ return {
27835
+ suffix: member.slice(-5),
27836
+ result: probe.skipped ? "not_tested" : probe.ok ? "verified" : probe.httpStatus === 401 ? "rejected" : "not_tested",
27837
+ httpStatus: probe.httpStatus ?? null,
27838
+ error: scrubSecrets(probe.error?.replaceAll(member, "[REDACTED]")) || null
27839
+ };
27840
+ } catch {
27841
+ return {
27842
+ suffix: member.slice(-5),
27843
+ result: "not_tested",
27844
+ httpStatus: null,
27845
+ error: "The provider check did not complete."
27846
+ };
27847
+ }
27848
+ }));
27849
+ const rejected = checks.find((check) => check.result === "rejected");
27850
+ if (rejected) {
27851
+ addPoolKeys.respond(res, 422, {
27852
+ error: scrubSecrets(`The key ending ${rejected.suffix} was rejected (HTTP 401). Nothing was saved.`),
27853
+ checks
27854
+ });
27855
+ return true;
27856
+ }
27857
+ const result = await getDbClient2().transaction(async () => {
27858
+ const current = await readPool(key);
27859
+ if (current.source === "env")
27860
+ return { error: ENV_POOL_ERROR, status: 409 };
27861
+ const duplicate = duplicateError(current.members, additions);
27862
+ if (duplicate)
27863
+ return { error: duplicate, status: 409 };
27864
+ const members = [...current.members, ...additions];
27865
+ const error = await savePool(key, members, current.row);
27866
+ if (error)
27867
+ return { error, status: 400 };
27868
+ await recordKeyValidation2(key, checks.flatMap((check, index) => check.result === "verified" ? [{ keyIndex: current.members.length + index, keySuffix: check.suffix, ok: true }] : []), "global", null, { retireAbsent: false });
27869
+ return { value: members.join(",") };
27870
+ });
27871
+ if ("error" in result) {
27872
+ jsonError(res, scrubSecrets(result.error), result.status);
27873
+ return true;
27874
+ }
27875
+ await runConfigWriteSideEffects("global", key, result.value);
27876
+ addPoolKeys.respond(res, 200, { ...await poolResponse(key), checks });
27877
+ return true;
27878
+ }
27879
+ if (deletePoolKey.match(req.method, pathSegments)) {
27880
+ const parsed = await deletePoolKey.parse(req, res, pathSegments, queryParams);
27881
+ if (!parsed)
27882
+ return true;
27883
+ if (!await ensureConfigAdmin(req, res, "config.delete.any"))
27884
+ return true;
27885
+ if (!await ensureSecretRead2(req, res))
27886
+ return true;
27887
+ const { key, index, suffix } = parsed.query;
27888
+ const result = await getDbClient2().transaction(async () => {
27889
+ const current = await readPool(key);
27890
+ if (current.source === "env")
27891
+ return { error: ENV_POOL_ERROR, status: 409 };
27892
+ if (!current.members[index] || current.members[index].slice(-5) !== suffix) {
27893
+ return { error: "The key list changed. Reload it and try again.", status: 409 };
27894
+ }
27895
+ const members = current.members.filter((_, position) => position !== index);
27896
+ if (members.length) {
27897
+ const error = await savePool(key, members, current.row);
27898
+ if (error)
27899
+ return { error, status: 400 };
27900
+ } else {
27901
+ await deleteSwarmConfigByKey2("global", null, key);
27902
+ }
27903
+ await retirePoolKeyStatus(key, suffix, members.map((member, keyIndex) => ({ keySuffix: member.slice(-5), keyIndex })));
27904
+ return { value: members.join(",") };
27905
+ });
27906
+ if ("error" in result) {
27907
+ jsonError(res, scrubSecrets(result.error), result.status);
27908
+ return true;
27909
+ }
27910
+ await runConfigWriteSideEffects("global", key, result.value);
27911
+ deletePoolKey.respond(res, 200, await poolResponse(key));
27912
+ return true;
27913
+ }
27914
+ return false;
27915
+ }
27916
+
27252
27917
  // src/http/pricing.ts
27253
27918
  init_zod();
27254
27919
  init_db3();
@@ -33619,6 +34284,7 @@ async function handleSessionData(req, res, pathSegments, queryParams, myAgentId)
33619
34284
  // src/http/sessions.ts
33620
34285
  init_zod();
33621
34286
  init_key();
34287
+ init_source_key();
33622
34288
  init_db3();
33623
34289
  init_session_moves();
33624
34290
  init_session_tree();
@@ -33627,6 +34293,74 @@ init_steering();
33627
34293
  init_users();
33628
34294
  init_rbac();
33629
34295
  init_bus();
34296
+
34297
+ // src/slack/channel-labels.ts
34298
+ var LABEL_TTL_MS = 24 * 60 * 60 * 1000;
34299
+ var FAILURE_TTL_MS = 10 * 60 * 1000;
34300
+ var FAILURE_CACHE_MAX = 500;
34301
+ var LOOKUP_QUEUE_MAX = 50;
34302
+ var inFlight2 = new Set;
34303
+ var failedUntil = new Map;
34304
+ var pending = Promise.resolve();
34305
+ async function channelLabel(client, id) {
34306
+ const result = await callSlackWithRetry2(client, "conversations.info", {
34307
+ channel: id.toUpperCase()
34308
+ });
34309
+ const channel = result.channel;
34310
+ if (result.ok === false || !channel)
34311
+ throw new Error("Channel lookup failed");
34312
+ if (channel.is_mpim)
34313
+ return "Group DM";
34314
+ if (channel.is_im && channel.user) {
34315
+ const result = await callSlackWithRetry2(client, "users.info", { user: channel.user });
34316
+ const user = result.user;
34317
+ const name = user?.profile?.display_name || user?.real_name || user?.profile?.real_name;
34318
+ if (result.ok !== false && name)
34319
+ return `DM · ${name}`;
34320
+ } else if (channel.name) {
34321
+ return `#${channel.name}`;
34322
+ }
34323
+ throw new Error("Channel label unavailable");
34324
+ }
34325
+ var CHANNEL_GROUP_KEY = /^shared\/slack\/([^/]+)\/$/;
34326
+ function warmSlackChannelLabels(groupKeys) {
34327
+ const client = getSlackApp2()?.client;
34328
+ if (!client)
34329
+ return;
34330
+ for (const groupKey of groupKeys) {
34331
+ const id = CHANNEL_GROUP_KEY.exec(groupKey)?.[1];
34332
+ if (!id)
34333
+ continue;
34334
+ if (inFlight2.has(id) || (failedUntil.get(id) ?? 0) > Date.now())
34335
+ continue;
34336
+ failedUntil.delete(id);
34337
+ if (inFlight2.size >= LOOKUP_QUEUE_MAX)
34338
+ continue;
34339
+ if (failedUntil.size + inFlight2.size >= FAILURE_CACHE_MAX) {
34340
+ const now = Date.now();
34341
+ for (const [failedId, until] of failedUntil) {
34342
+ if (until <= now)
34343
+ failedUntil.delete(failedId);
34344
+ }
34345
+ if (failedUntil.size + inFlight2.size >= FAILURE_CACHE_MAX)
34346
+ continue;
34347
+ }
34348
+ inFlight2.add(id);
34349
+ pending = pending.then(async () => {
34350
+ try {
34351
+ const label = await channelLabel(client, id);
34352
+ await rememberSessionLabel(groupKey, label, LABEL_TTL_MS);
34353
+ } catch (error) {
34354
+ failedUntil.set(id, Date.now() + FAILURE_TTL_MS);
34355
+ console.warn(`[Slack] Could not cache a session channel label: ${slackErrorCode2(error) ?? "unknown error"}`);
34356
+ } finally {
34357
+ inFlight2.delete(id);
34358
+ }
34359
+ });
34360
+ }
34361
+ }
34362
+
34363
+ // src/http/sessions.ts
33630
34364
  init_types();
33631
34365
  init_request_auth_context();
33632
34366
  init_runtime_pools_flag();
@@ -33689,6 +34423,7 @@ var SessionTreeGroupSchema = SessionSectionCountsSchema.extend({
33689
34423
  lastActivityAt: string2()
33690
34424
  });
33691
34425
  var SessionTreeResponseSchema = object2({
34426
+ labels: record2(string2(), string2()).optional(),
33692
34427
  groups: array2(SessionTreeGroupSchema),
33693
34428
  inbox: SessionSectionCountsSchema,
33694
34429
  later: SessionSectionCountsSchema,
@@ -34126,6 +34861,9 @@ async function checkSessionMove(rootTaskId, actor, req, myAgentId, options = {})
34126
34861
  }
34127
34862
  if (root.parentTaskId)
34128
34863
  return { reason: "Task is not a session root" };
34864
+ const sourceError = sourceMoveError(options.destination ?? null, root);
34865
+ if (sourceError)
34866
+ return { reason: sourceError };
34129
34867
  const tasks = await getRootTaskChain2(root.id);
34130
34868
  for (const task of tasks) {
34131
34869
  if (!await canMutateTaskNamespace(task, myAgentId, req)) {
@@ -34150,6 +34888,7 @@ var getSession = route({
34150
34888
  chain: array2(TaskWithSteeringSchema),
34151
34889
  access: SessionAccessSchema,
34152
34890
  owner: SessionOwnerSchema.nullable(),
34891
+ groupKey: string2(),
34153
34892
  approvals: array2(SessionApprovalSchema).optional(),
34154
34893
  readState: _enum2(["unread", "read", "later", "done"]).optional(),
34155
34894
  lastActivityAt: string2().optional()
@@ -34336,11 +35075,15 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
34336
35075
  if (!parsed)
34337
35076
  return true;
34338
35077
  const actor = await resolveSessionActor2(req, myAgentId);
34339
- sessionTree.respond(res, 200, await getSessionTree(actor, undefined, {
35078
+ const tree = await getSessionTree(actor, undefined, {
34340
35079
  mine: parsed.query.show !== "all",
34341
35080
  hideSource: parsed.query.hideSource,
34342
35081
  showSource: parsed.query.showSource
34343
- }));
35082
+ });
35083
+ const { sourceGroups, slackChannels, threadLabels, ...counts } = tree;
35084
+ const labels = { ...threadLabels, ...await getSessionLabels(sourceGroups) };
35085
+ warmSlackChannelLabels(slackChannels.map((id) => `shared/slack/${id}/`).filter((key) => labels[key] === undefined));
35086
+ sessionTree.respond(res, 200, { ...counts, labels });
34344
35087
  return true;
34345
35088
  }
34346
35089
  if (triageSessionListRoute.match(req.method, pathSegments)) {
@@ -34365,7 +35108,9 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
34365
35108
  const skipped = [];
34366
35109
  const moves = [];
34367
35110
  for (const rootId of new Set(parsed.body.rootTaskIds)) {
34368
- const checked = await checkSessionMove(rootId, actor, req, myAgentId);
35111
+ const checked = await checkSessionMove(rootId, actor, req, myAgentId, {
35112
+ destination: key
35113
+ });
34369
35114
  if ("reason" in checked) {
34370
35115
  skipped.push({ rootTaskId: rootId, reason: checked.reason });
34371
35116
  } else {
@@ -34386,6 +35131,10 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
34386
35131
  if (!parsed)
34387
35132
  return true;
34388
35133
  const from = normalizeAssetKey(parsed.body.from);
35134
+ if (sourceOfKey(from) || parsed.body.to && sourceOfKey(normalizeAssetKey(parsed.body.to))) {
35135
+ jsonError(res, SOURCE_GROUPS_READ_ONLY, 400);
35136
+ return true;
35137
+ }
34389
35138
  if (parseAssetKey(from).relativeSegments.length === 0) {
34390
35139
  jsonError(res, "Cannot move a namespace root", 400);
34391
35140
  return true;
@@ -34425,7 +35174,8 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
34425
35174
  continue;
34426
35175
  }
34427
35176
  const checked = await checkSessionMove(root.id, actor, req, myAgentId, {
34428
- ownerOnly: true
35177
+ ownerOnly: true,
35178
+ destination: nextKey
34429
35179
  });
34430
35180
  if ("reason" in checked) {
34431
35181
  skipped.push({ rootTaskId: root.id, reason: checked.reason });
@@ -34469,11 +35219,12 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
34469
35219
  } : null;
34470
35220
  const chain = await getRootTaskChain2(parsed.params.rootTaskId);
34471
35221
  const tasks = [root, ...chain];
34472
- const [steering, citations, approvals, read] = await Promise.all([
35222
+ const [steering, citations, approvals, read, groupKey] = await Promise.all([
34473
35223
  getTaskSteeringFieldsForTasks(tasks),
34474
35224
  getTaskCitationsForTasks(tasks.map((task) => task.id)),
34475
35225
  getPendingApprovalsForTasks2(tasks.map((task) => task.id)),
34476
- actor.kind === "user" && actor.userId ? getSessionReadState(sessionRoot.id, actor.userId) : Promise.resolve(null)
35226
+ actor.kind === "user" && actor.userId ? getSessionReadState(sessionRoot.id, actor.userId) : Promise.resolve(null),
35227
+ getSessionGroupKey(root)
34477
35228
  ]);
34478
35229
  const decorate = (task) => ({
34479
35230
  ...task,
@@ -34485,6 +35236,7 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
34485
35236
  chain: chain.map(decorate),
34486
35237
  access,
34487
35238
  owner,
35239
+ groupKey,
34488
35240
  ...approvals.length ? { approvals } : {},
34489
35241
  ...read ?? {}
34490
35242
  });
@@ -35873,7 +36625,8 @@ var SwarmMetricsSchema = object2({
35873
36625
  sessionLogs: RetentionTableStatsSchema.optional(),
35874
36626
  agentLog: RetentionTableStatsSchema.optional(),
35875
36627
  events: RetentionTableStatsSchema.optional(),
35876
- contextVersions: RetentionTableStatsSchema.optional()
36628
+ contextVersions: RetentionTableStatsSchema.optional(),
36629
+ scriptRuns: RetentionTableStatsSchema.optional()
35877
36630
  })
35878
36631
  });
35879
36632
  var ConcurrentContextSchema = object2({
@@ -39250,8 +40003,66 @@ async function handleWorkflowEvents(req, res, pathSegments, queryParams) {
39250
40003
  // src/http/workflows.ts
39251
40004
  init_zod();
39252
40005
  init_db3();
40006
+ init_workflow_idempotency();
39253
40007
  init_workflow_runs();
39254
40008
  init_types();
40009
+
40010
+ // src/http/idempotency-key.ts
40011
+ init_zod();
40012
+ init_workflow_idempotency();
40013
+ init_request_auth_context();
40014
+ var IDEMPOTENCY_KEY_PATTERN = /^[\x21-\x7E]{1,255}$/;
40015
+ var IDEMPOTENT_REPLAYED_HEADER = "Idempotent-Replayed";
40016
+ var idempotencyKeyHeader = (accepted) => object2({
40017
+ "Idempotency-Key": string2().regex(IDEMPOTENCY_KEY_PATTERN).optional().describe("Optional client-generated key, 1-255 visible ASCII characters (a UUID works). " + `The first request the server accepts under a key ${accepted}; a retry with the same key ` + "and an equivalent body gets that request's status and body back (with " + `\`${IDEMPOTENT_REPLAYED_HEADER}: true\`) and changes nothing. The key is scoped to the ` + "caller's identity and this operation; it is not a credential. The same key with a " + "different body is a 409. A request rejected before it is accepted (validation, auth, " + "not found, disabled) does not use up the key. Accepted keys do not expire.")
40018
+ });
40019
+ function idempotencyPrincipal(req, myAgentId) {
40020
+ const auth = getRequestAuth(req);
40021
+ switch (auth?.kind) {
40022
+ case "user":
40023
+ return `user:${auth.userId}`;
40024
+ case "agent":
40025
+ return `agent:${auth.agentId}`;
40026
+ case "controller":
40027
+ return `controller:${auth.controllerId}`;
40028
+ case "guest":
40029
+ return null;
40030
+ default:
40031
+ return myAgentId ? `agent:${myAgentId}` : "operator";
40032
+ }
40033
+ }
40034
+ function readIdempotencyKey(req, res, myAgentId) {
40035
+ const raw = req.headers["idempotency-key"];
40036
+ if (raw === undefined)
40037
+ return;
40038
+ const key = Array.isArray(raw) ? raw.join(", ") : raw;
40039
+ if (!IDEMPOTENCY_KEY_PATTERN.test(key)) {
40040
+ jsonError(res, "Idempotency-Key must be 1-255 visible ASCII characters", 400);
40041
+ return null;
40042
+ }
40043
+ const principal = idempotencyPrincipal(req, myAgentId);
40044
+ if (!principal) {
40045
+ jsonError(res, "Idempotency-Key needs an identified caller", 400);
40046
+ return null;
40047
+ }
40048
+ return { principal, key };
40049
+ }
40050
+ async function replayAcceptedOperation(res, claim, send) {
40051
+ const accepted = await findAcceptedWorkflowOperation(claim);
40052
+ if (!accepted)
40053
+ return false;
40054
+ if (accepted.fingerprint !== claim.fingerprint) {
40055
+ jsonError(res, "Idempotency-Key was already used for a different request", 409);
40056
+ } else if (accepted.resourceDeletedAt !== null) {
40057
+ jsonError(res, "The workflow this Idempotency-Key created or triggered was deleted; send a new key to start over", 410);
40058
+ } else {
40059
+ res.setHeader(IDEMPOTENT_REPLAYED_HEADER, "true");
40060
+ send(accepted.body);
40061
+ }
40062
+ return true;
40063
+ }
40064
+
40065
+ // src/http/workflows.ts
39255
40066
  var WorkflowWithFavoriteSchema = WorkflowSchema.extend({ favorite: boolean() });
39256
40067
  var WorkflowSaveResponseSchema = WorkflowSchema.extend({
39257
40068
  warnings: array2(string2()).optional()
@@ -39280,6 +40091,11 @@ var WorkflowRunPageSchema = object2({
39280
40091
  nextOffset: number2().int().optional()
39281
40092
  })
39282
40093
  });
40094
+ var WorkflowRunTreeSchema = object2({
40095
+ rootRunId: string2(),
40096
+ runs: array2(WorkflowRunSummarySchema),
40097
+ hasOpenWork: boolean()
40098
+ });
39283
40099
  var SuccessResponseSchema = object2({ success: literal2(true) });
39284
40100
  async function withSaveWarnings(workflow) {
39285
40101
  const warnings = await workflowSaveWarnings(workflow.definition, getExecutorRegistry2());
@@ -39313,6 +40129,7 @@ var createWorkflowRoute = route({
39313
40129
  pattern: ["api", "workflows"],
39314
40130
  summary: "Create a new workflow",
39315
40131
  tags: ["Workflows"],
40132
+ headers: idempotencyKeyHeader("creates one workflow"),
39316
40133
  body: object2({
39317
40134
  name: string2().min(1),
39318
40135
  key: AssetKeySchema.optional(),
@@ -39330,7 +40147,9 @@ var createWorkflowRoute = route({
39330
40147
  }),
39331
40148
  responses: {
39332
40149
  201: { description: "Workflow created", schema: WorkflowSaveResponseSchema },
39333
- 400: { description: "Invalid definition" }
40150
+ 400: { description: "Invalid definition, or a malformed Idempotency-Key" },
40151
+ 409: { description: "Idempotency-Key was already used for a different request" },
40152
+ 410: { description: "The workflow created under this Idempotency-Key was deleted" }
39334
40153
  }
39335
40154
  });
39336
40155
  var getWorkflowRoute = route({
@@ -39434,16 +40253,20 @@ var triggerWorkflowRoute = route({
39434
40253
  path: "/api/workflows/{id}/trigger",
39435
40254
  pattern: ["api", "workflows", null, "trigger"],
39436
40255
  summary: "Trigger a workflow execution",
40256
+ description: "With an `Idempotency-Key`, a retry returns the accepted run's `runId` and `skipped` without starting, resuming or waiting for anything, even after the workflow was disabled or edited and whatever state the run is in now.",
39437
40257
  tags: ["Workflows"],
39438
40258
  params: object2({ id: string2() }),
40259
+ headers: idempotencyKeyHeader("starts one run"),
39439
40260
  responses: {
39440
40261
  201: {
39441
40262
  description: "Workflow run started (or skipped if cooldown active)",
39442
40263
  schema: object2({ runId: string2(), skipped: boolean() })
39443
40264
  },
39444
- 400: { description: "Workflow is disabled" },
40265
+ 400: { description: "Workflow is disabled, or a malformed Idempotency-Key" },
39445
40266
  401: { description: "Unauthorized" },
39446
- 404: { description: "Workflow not found" }
40267
+ 404: { description: "Workflow not found" },
40268
+ 409: { description: "Idempotency-Key was already used for a different request" },
40269
+ 410: { description: "The workflow triggered under this Idempotency-Key was deleted" }
39447
40270
  }
39448
40271
  });
39449
40272
  var validateTriggerRoute = route({
@@ -39487,20 +40310,45 @@ var getWorkflowRunRoute = route({
39487
40310
  path: "/api/workflow-runs/{id}",
39488
40311
  pattern: ["api", "workflow-runs", null],
39489
40312
  summary: "Get a workflow run with steps (includes retry columns)",
40313
+ description: "Returns the run with its `context` and every step with its `input` by default. A step's `input` is a snapshot of the context when the step started, so in runs with loops (polling, `wait`, iterations) the response grows with steps × context size. Pass `fields=slim` to drop `run.context` and `steps[].input`; outputs, errors, diagnostics, retry fields and `parent` stay.",
39490
40314
  tags: ["Workflows"],
39491
40315
  params: object2({ id: string2() }),
40316
+ query: object2({
40317
+ fields: _enum2(["full", "slim"]).optional()
40318
+ }),
39492
40319
  responses: {
39493
40320
  200: {
39494
40321
  description: "Workflow run details with steps including retry info",
39495
- schema: object2({
39496
- run: WorkflowRunSchema,
39497
- steps: array2(WorkflowRunStepSchema),
39498
- parent: WorkflowRunParentSchema.optional()
39499
- })
40322
+ schema: union2([
40323
+ object2({
40324
+ run: WorkflowRunSchema,
40325
+ steps: array2(WorkflowRunStepSchema),
40326
+ parent: WorkflowRunParentSchema.optional()
40327
+ }),
40328
+ object2({
40329
+ run: WorkflowRunSummarySchema,
40330
+ steps: array2(WorkflowRunStepSlimSchema),
40331
+ parent: WorkflowRunParentSchema.optional()
40332
+ })
40333
+ ])
39500
40334
  },
39501
40335
  404: { description: "Run not found" }
39502
40336
  }
39503
40337
  });
40338
+ var getWorkflowRunTreeRoute = route({
40339
+ method: "get",
40340
+ path: "/api/workflow-runs/{id}/tree",
40341
+ pattern: ["api", "workflow-runs", null, "tree"],
40342
+ summary: "Get a workflow run and every sub-workflow run below it",
40343
+ description: `Follows stored parent links (\`parentStepId\` → step → run) through every attempt of every step, terminal runs included. \`runs\` holds list rows without \`context\`, root first. \`hasOpenWork\` is true while any run in the tree is live, has a pending, running or waiting step, a queued retry, an open task or a pending approval; after a cancel it turns false once the tree has settled. Both come from one read snapshot. The tree is not paginated. Links that form a cycle or nest deeper than ${WORKFLOW_RUN_TREE_MAX_DEPTH} levels return 409.`,
40344
+ tags: ["Workflows"],
40345
+ params: object2({ id: string2() }),
40346
+ responses: {
40347
+ 200: { description: "The run tree", schema: WorkflowRunTreeSchema },
40348
+ 404: { description: "Run not found" },
40349
+ 409: { description: "Stored parent links form a cycle or nest past the depth bound" }
40350
+ }
40351
+ });
39504
40352
  var retryWorkflowRunRoute = route({
39505
40353
  method: "post",
39506
40354
  path: "/api/workflow-runs/{id}/retry",
@@ -39688,9 +40536,21 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
39688
40536
  return true;
39689
40537
  }
39690
40538
  if (createWorkflowRoute.match(req.method, pathSegments)) {
40539
+ const idempotency = readIdempotencyKey(req, res, myAgentId);
40540
+ if (idempotency === null)
40541
+ return true;
39691
40542
  const parsed = await createWorkflowRoute.parse(req, res, pathSegments, queryParams);
39692
40543
  if (!parsed)
39693
40544
  return true;
40545
+ const claim = idempotency && {
40546
+ ...idempotency,
40547
+ operation: "workflow.create",
40548
+ targetId: "",
40549
+ fingerprint: workflowRequestFingerprint("workflow.create", parsed.body)
40550
+ };
40551
+ const replayCreate = (body) => createWorkflowRoute.respond(res, 201, body);
40552
+ if (claim && await replayAcceptedOperation(res, claim, replayCreate))
40553
+ return true;
39694
40554
  const validation = validateDefinition(parsed.body.definition, getExecutorRegistry2());
39695
40555
  if (!validation.valid) {
39696
40556
  jsonError(res, `Invalid definition: ${validation.errors.join("; ")}`, 400);
@@ -39712,7 +40572,7 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
39712
40572
  }
39713
40573
  throw error;
39714
40574
  }
39715
- const workflow = await createWorkflow2({
40575
+ const data = {
39716
40576
  key,
39717
40577
  name: parsed.body.name,
39718
40578
  description: parsed.body.description,
@@ -39728,8 +40588,34 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
39728
40588
  vcsRepo: parsed.body.vcsRepo,
39729
40589
  createdByAgentId: myAgentId ?? undefined,
39730
40590
  createdBy: await resolveHttpAuditUserId(req, myAgentId) ?? undefined
39731
- }, "api");
39732
- createWorkflowRoute.respond(res, 201, await withSaveWarnings(workflow));
40591
+ };
40592
+ if (!claim) {
40593
+ const workflow = await createWorkflow2(data, "api");
40594
+ createWorkflowRoute.respond(res, 201, await withSaveWarnings(workflow));
40595
+ return true;
40596
+ }
40597
+ const warnings = await workflowSaveWarnings(parsed.body.definition, getExecutorRegistry2());
40598
+ let saved;
40599
+ try {
40600
+ saved = await getDbClient2().transaction(async () => {
40601
+ await assertWorkflowIdempotencyKeyUnused(claim);
40602
+ const workflow = await createWorkflow2(data, "api");
40603
+ const body = warnings.length > 0 ? { ...workflow, warnings } : workflow;
40604
+ await recordAcceptedWorkflowOperation(claim, {
40605
+ workflowId: workflow.id,
40606
+ status: 201,
40607
+ body
40608
+ });
40609
+ return body;
40610
+ });
40611
+ } catch (err) {
40612
+ if (err instanceof IdempotencyKeyTakenError) {
40613
+ if (await replayAcceptedOperation(res, claim, replayCreate))
40614
+ return true;
40615
+ }
40616
+ throw err;
40617
+ }
40618
+ createWorkflowRoute.respond(res, 201, saved);
39733
40619
  return true;
39734
40620
  }
39735
40621
  if (getWorkflowRoute.match(req.method, pathSegments)) {
@@ -39931,9 +40817,26 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
39931
40817
  return true;
39932
40818
  }
39933
40819
  if (triggerWorkflowRoute.match(req.method, pathSegments)) {
40820
+ const idempotency = readIdempotencyKey(req, res, myAgentId);
40821
+ if (idempotency === null)
40822
+ return true;
39934
40823
  const parsed = await triggerWorkflowRoute.parse(req, res, pathSegments, queryParams);
39935
40824
  if (!parsed)
39936
40825
  return true;
40826
+ let claim;
40827
+ let keyedBody;
40828
+ const replayTrigger = (body) => triggerWorkflowRoute.respond(res, 201, body);
40829
+ if (idempotency) {
40830
+ keyedBody = await parseBody(req);
40831
+ claim = {
40832
+ ...idempotency,
40833
+ operation: "workflow.trigger",
40834
+ targetId: parsed.params.id,
40835
+ fingerprint: workflowRequestFingerprint("workflow.trigger", keyedBody)
40836
+ };
40837
+ if (await replayAcceptedOperation(res, claim, replayTrigger))
40838
+ return true;
40839
+ }
39937
40840
  const workflow = await getWorkflow2(parsed.params.id);
39938
40841
  if (!workflow) {
39939
40842
  res.writeHead(404);
@@ -39944,20 +40847,39 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
39944
40847
  jsonError(res, "Workflow is disabled", 400);
39945
40848
  return true;
39946
40849
  }
39947
- const body = await parseBody(req);
40850
+ const body = idempotency ? keyedBody : await parseBody(req);
39948
40851
  let runId;
40852
+ let accepted;
39949
40853
  try {
39950
40854
  runId = await startWorkflowExecution2(workflow, body, getExecutorRegistry2(), {
39951
40855
  triggerType: "api",
39952
- requestedByUserId: await resolveHttpAuditUserId(req, myAgentId) ?? undefined
40856
+ requestedByUserId: await resolveHttpAuditUserId(req, myAgentId) ?? undefined,
40857
+ accept: claim ? async (run) => {
40858
+ const response = { runId: run.runId, skipped: run.skipped };
40859
+ await recordAcceptedWorkflowOperation(claim, {
40860
+ workflowId: workflow.id,
40861
+ runId: run.runId,
40862
+ status: 201,
40863
+ body: response
40864
+ });
40865
+ accepted = response;
40866
+ } : undefined
39953
40867
  });
39954
40868
  } catch (err) {
39955
40869
  if (err instanceof TriggerSchemaError) {
39956
40870
  triggerSchemaErrorResponse(res, err.message, err.validationErrors);
39957
40871
  return true;
39958
40872
  }
40873
+ if (claim && err instanceof IdempotencyKeyTakenError) {
40874
+ if (await replayAcceptedOperation(res, claim, replayTrigger))
40875
+ return true;
40876
+ }
39959
40877
  throw err;
39960
40878
  }
40879
+ if (accepted) {
40880
+ triggerWorkflowRoute.respond(res, 201, accepted);
40881
+ return true;
40882
+ }
39961
40883
  const run = await getWorkflowRun2(runId);
39962
40884
  const skipped = run?.status === "skipped";
39963
40885
  triggerWorkflowRoute.respond(res, 201, { runId, skipped });
@@ -39979,17 +40901,39 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
39979
40901
  const parsed = await getWorkflowRunRoute.parse(req, res, pathSegments, queryParams);
39980
40902
  if (!parsed)
39981
40903
  return true;
39982
- const run = await getWorkflowRun2(parsed.params.id, "display");
40904
+ const slim = parsed.query.fields === "slim";
40905
+ const run = slim ? await getWorkflowRunSummary(parsed.params.id) : await getWorkflowRun2(parsed.params.id, "display");
39983
40906
  if (!run) {
39984
40907
  res.writeHead(404);
39985
40908
  res.end();
39986
40909
  return true;
39987
40910
  }
39988
- const steps = await getWorkflowRunStepsByRunId2(parsed.params.id, "display");
40911
+ const steps = slim ? await getWorkflowRunStepsSlimByRunId(parsed.params.id) : await getWorkflowRunStepsByRunId2(parsed.params.id, "display");
39989
40912
  const parent = run.parentStepId ? await getWorkflowRunParent(run.parentStepId) : null;
39990
40913
  getWorkflowRunRoute.respond(res, 200, { run, steps, ...parent ? { parent } : {} });
39991
40914
  return true;
39992
40915
  }
40916
+ if (getWorkflowRunTreeRoute.match(req.method, pathSegments)) {
40917
+ const parsed = await getWorkflowRunTreeRoute.parse(req, res, pathSegments, queryParams);
40918
+ if (!parsed)
40919
+ return true;
40920
+ let tree;
40921
+ try {
40922
+ tree = await getWorkflowRunTree(parsed.params.id);
40923
+ } catch (err) {
40924
+ if (!(err instanceof WorkflowRunTreeError))
40925
+ throw err;
40926
+ jsonError(res, err.message, 409);
40927
+ return true;
40928
+ }
40929
+ if (!tree) {
40930
+ res.writeHead(404);
40931
+ res.end();
40932
+ return true;
40933
+ }
40934
+ getWorkflowRunTreeRoute.respond(res, 200, tree);
40935
+ return true;
40936
+ }
39993
40937
  if (retryWorkflowRunRoute.match(req.method, pathSegments)) {
39994
40938
  const parsed = await retryWorkflowRunRoute.parse(req, res, pathSegments, queryParams);
39995
40939
  if (!parsed)
@@ -40344,6 +41288,7 @@ var httpServer = createHttpServer(async (req, res) => {
40344
41288
  () => handleStatus(req, res, pathSegments, queryParams),
40345
41289
  () => handleOnboarding(req, res, pathSegments, queryParams),
40346
41290
  () => handleCodexOAuthDevice(req, res, pathSegments, queryParams),
41291
+ () => handleCodexOAuthAccounts(req, res, pathSegments, queryParams),
40347
41292
  () => handleActiveSessions(req, res, pathSegments, queryParams, myAgentId),
40348
41293
  () => handlePricing(req, res, pathSegments, queryParams, myAgentId),
40349
41294
  () => handleSchedules(req, res, pathSegments, queryParams, myAgentId),
@@ -40351,6 +41296,7 @@ var httpServer = createHttpServer(async (req, res) => {
40351
41296
  () => handleWorkflowEvents(req, res, pathSegments, queryParams),
40352
41297
  () => handleApprovalRequests(req, res, pathSegments, queryParams),
40353
41298
  () => handleApps(req, res, pathSegments, queryParams, myAgentId),
41299
+ () => handlePoolKeys(req, res, pathSegments, queryParams),
40354
41300
  () => handleConfig(req, res, pathSegments, queryParams),
40355
41301
  () => handleFs(req, res, pathSegments, queryParams, myAgentId),
40356
41302
  () => handleComb(req, res, pathSegments, queryParams, myAgentId),
@@ -40427,7 +41373,7 @@ var httpServer = createHttpServer(async (req, res) => {
40427
41373
  });
40428
41374
  });
40429
41375
  var detachRealtime = attachRealtimeTransport(httpServer);
40430
- var { attachControllerTransport } = await import("./controllers-connect-bqm1rtft.js");
41376
+ var { attachControllerTransport } = await import("./controllers-connect-r2za39ef.js");
40431
41377
  var detachControllers = attachControllerTransport(httpServer);
40432
41378
  var stopWorkerNudges = startWorkerNudgeListener();
40433
41379
  var stopRoomDeletion = realtimeBus.subscribe("room:namespace-deleted", (namespace) => {
@@ -40456,7 +41402,7 @@ async function shutdown() {
40456
41402
  sessionsProcessed: getServerSessionsProcessed()
40457
41403
  });
40458
41404
  if (hasCapability("scheduling")) {
40459
- const { stopScheduler } = await import("./index-spwxjgay.js");
41405
+ const { stopScheduler } = await import("./index-38t35h0n.js");
40460
41406
  stopScheduler();
40461
41407
  }
40462
41408
  stopHeartbeat2();
@@ -40468,7 +41414,7 @@ async function shutdown() {
40468
41414
  await stopSlackApp2();
40469
41415
  await stopChatSdk();
40470
41416
  if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
40471
- const { stopOAuthKeepalive } = await import("./keepalive-dsd8rtgx.js");
41417
+ const { stopOAuthKeepalive } = await import("./keepalive-em0117bp.js");
40472
41418
  await stopOAuthKeepalive();
40473
41419
  }
40474
41420
  stopOAuthPendingGc();
@@ -40548,21 +41494,21 @@ try {
40548
41494
  console.warn("[startup] CAPABILITIES upgrade seed failed (non-fatal):", err);
40549
41495
  }
40550
41496
  try {
40551
- const { ensurePricingSeeded } = await import("./boot-seeds-5zmax2wr.js");
41497
+ const { ensurePricingSeeded } = await import("./boot-seeds-9bmkspyw.js");
40552
41498
  ensurePricingSeeded();
40553
- const { startPricingRefreshLoop } = await import("./pricing-refresh-xvak5p4v.js");
41499
+ const { startPricingRefreshLoop } = await import("./pricing-refresh-yb75wv33.js");
40554
41500
  startPricingRefreshLoop();
40555
41501
  } catch (err) {
40556
41502
  console.error("[startup] Failed to seed pricing rows:", err);
40557
41503
  }
40558
41504
  try {
40559
- const { ensureModelProfilesSeeded } = await import("./boot-seeds-5zmax2wr.js");
41505
+ const { ensureModelProfilesSeeded } = await import("./boot-seeds-9bmkspyw.js");
40560
41506
  await ensureModelProfilesSeeded();
40561
41507
  } catch (err) {
40562
41508
  console.error("[startup] Failed to seed model profiles:", err);
40563
41509
  }
40564
41510
  try {
40565
- const { ensureRbacSeeded } = await import("./boot-seeds-5zmax2wr.js");
41511
+ const { ensureRbacSeeded } = await import("./boot-seeds-9bmkspyw.js");
40566
41512
  ensureRbacSeeded();
40567
41513
  } catch (err) {
40568
41514
  console.error("[startup] Failed to sync RBAC seed rows:", err);
@@ -40570,7 +41516,7 @@ try {
40570
41516
  throw err;
40571
41517
  }
40572
41518
  try {
40573
- const { runAllSeeders } = await import("./index-n1vbvta9.js");
41519
+ const { runAllSeeders } = await import("./index-qhjf2htm.js");
40574
41520
  await runAllSeeders({ scriptEmbeddingMode: "skip" });
40575
41521
  } catch (err) {
40576
41522
  console.error("[startup] Failed to seed built-in entities:", err);
@@ -40633,41 +41579,44 @@ httpServer.listen(port, async () => {
40633
41579
  await initWorkflows2();
40634
41580
  await startScriptRunSupervisor(getMcpBaseUrl());
40635
41581
  if (hasCapability("scheduling")) {
40636
- const { startScheduler } = await import("./index-spwxjgay.js");
40637
- const { getExecutorRegistry } = await import("./index-srg522m6.js");
41582
+ const { startScheduler } = await import("./index-38t35h0n.js");
41583
+ const { getExecutorRegistry } = await import("./index-k0yt1tvq.js");
40638
41584
  const intervalMs = Number(process.env.SCHEDULER_INTERVAL_MS) || 1e4;
40639
41585
  startScheduler(getExecutorRegistry(), intervalMs, {
40640
41586
  runId: globalState.__runId
40641
41587
  });
40642
41588
  }
40643
41589
  if (!isEnvFlagEnabled("HEARTBEAT_DISABLE", false)) {
40644
- const { startHeartbeat } = await import("./index-kw2mmat7.js");
41590
+ const { startHeartbeat } = await import("./index-yqgbfgaj.js");
40645
41591
  const heartbeatMs = Number(process.env.HEARTBEAT_INTERVAL_MS) || 90000;
40646
41592
  startHeartbeat(heartbeatMs);
40647
41593
  }
40648
41594
  startPoolRouting();
40649
41595
  startRuntimeSupervisor();
40650
41596
  if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
40651
- const { startOAuthKeepalive } = await import("./keepalive-dsd8rtgx.js");
41597
+ const { startOAuthKeepalive } = await import("./keepalive-em0117bp.js");
40652
41598
  startOAuthKeepalive();
40653
41599
  }
40654
41600
  if (process.env.OAUTH_REFRESH_SWEEP_DISABLE !== "true") {
40655
- const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-q2c3bnvm.js");
41601
+ const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-xysj4yse.js");
40656
41602
  startOAuthRefreshSweep();
40657
41603
  }
40658
41604
  startOAuthPendingGc();
40659
41605
  await startMemoryGc();
40660
41606
  await startDbRetention();
40661
41607
  startHumanFreeDrain();
40662
- import("./boot-reembed-5b3d2eea.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
41608
+ import("./boot-reembed-f4nn561n.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
40663
41609
  console.error("[boot-reembed] startup backfill failed (non-fatal):", err);
40664
41610
  });
40665
- import("./boot-reembed-jsmfrpzf.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
41611
+ import("./boot-reembed-6c1sjfnr.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
40666
41612
  console.error("[boot-reembed-scripts] startup backfill failed (non-fatal):", err);
40667
41613
  });
40668
- import("./boot-scrub-sweep-s73gerxy.js").then(({ runBootScrubSweep }) => runBootScrubSweep()).catch((err) => {
41614
+ import("./boot-scrub-sweep-d4w9gajf.js").then(({ runBootScrubSweep }) => runBootScrubSweep()).catch((err) => {
40669
41615
  console.error("[boot-scrub-sweep] startup scrub failed (non-fatal):", err);
40670
41616
  });
41617
+ import("./session-source-backfill-qgtc86z1.js").then(({ runSessionSourceBackfill }) => runSessionSourceBackfill()).catch((err) => {
41618
+ console.error("[session-source-backfill] startup run failed (non-fatal):", err);
41619
+ });
40671
41620
  }).on("error", (err) => {
40672
41621
  console.error("HTTP Server Error:", err);
40673
41622
  });