@desplega.ai/agent-swarm 2.5.4 → 2.7.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 (354) hide show
  1. package/README.md +4 -2
  2. package/dist/{acp-adapter-ek38cwsv.js → acp-adapter-ma1js5n7.js} +9 -9
  3. package/dist/{actions-92mepq03.js → actions-1vhmtvg9.js} +21 -21
  4. package/dist/{amp-adapter-9gaxg015.js → amp-adapter-sxqqvmdk.js} +4 -4
  5. package/dist/{app-ctn8gsgx.js → app-mwx1d5a9.js} +3 -3
  6. package/dist/{assistant-zyr5kz47.js → assistant-yx1p6g82.js} +30 -26
  7. package/dist/{boot-reembed-w75maga2.js → boot-reembed-5h37a2c2.js} +1 -1
  8. package/dist/{boot-reembed-dwzfttdr.js → boot-reembed-7h78vmvv.js} +2 -1
  9. package/dist/{boot-scrub-sweep-e9kq43kf.js → boot-scrub-sweep-8mawd4gw.js} +4 -4
  10. package/dist/{boot-seeds-x28v3fhb.js → boot-seeds-ca84dhnn.js} +4 -4
  11. package/dist/{claude-adapter-f0afqnne.js → claude-adapter-wqt4hfkq.js} +9 -9
  12. package/dist/{claude-managed-adapter-x81a7r65.js → claude-managed-adapter-6fjqtr2z.js} +2 -2
  13. package/dist/{claude-managed-setup-bqzwjd9x.js → claude-managed-setup-rqv98sea.js} +10 -3
  14. package/dist/{claude-sdk-session-7b7whkaq.js → claude-sdk-session-f29f3b2x.js} +11 -11
  15. package/dist/{cli-sxgtf5fw.js → cli-07q03xm2.js} +1 -1
  16. package/dist/{cli-kxpfx2xr.js → cli-0z1xjzwa.js} +2 -2
  17. package/dist/{cli-g9vd9ece.js → cli-1hhbzkbb.js} +14 -16
  18. package/dist/{cli-qqzmjxkf.js → cli-1m9x8dr5.js} +11 -6
  19. package/dist/{cli-jbnn4vxb.js → cli-2pvzmas1.js} +3 -3
  20. package/dist/{cli-x77gen2p.js → cli-2y7v133v.js} +7 -7
  21. package/dist/{cli-dew6x255.js → cli-39aet655.js} +2 -2
  22. package/dist/{cli-g1cw7xtt.js → cli-39rrw8yp.js} +1 -1
  23. package/dist/{cli-jb30dzvk.js → cli-48gxjmcz.js} +530 -190
  24. package/dist/{cli-pzatvw94.js → cli-54sj64fc.js} +2 -2
  25. package/dist/{cli-bvpgr9ny.js → cli-60sty27p.js} +5 -5
  26. package/dist/{cli-asq5ydm4.js → cli-6a9qfa8b.js} +411 -69
  27. package/dist/{cli-277c31dw.js → cli-6mgdba42.js} +225 -3
  28. package/dist/{cli-19202kew.js → cli-6srv653c.js} +5 -5
  29. package/dist/{cli-n4c8e3s5.js → cli-708wdy32.js} +1 -1
  30. package/dist/{cli-pasyvjmm.js → cli-737pyqxr.js} +1 -1
  31. package/dist/{cli-6x9ma5w5.js → cli-803188pb.js} +1 -1
  32. package/dist/{cli-hh5we352.js → cli-86ehn4s5.js} +7 -7
  33. package/dist/{cli-9s05422w.js → cli-8mbc9za9.js} +1 -1
  34. package/dist/{cli-ff1tm9n9.js → cli-8wmj18cz.js} +1 -1
  35. package/dist/{cli-1r5ad7j5.js → cli-9gsm2rzp.js} +12 -12
  36. package/dist/{cli-mz9afxxf.js → cli-9pshx6rd.js} +17 -3
  37. package/dist/{cli-s682zgqz.js → cli-a6ds2epe.js} +1 -1
  38. package/dist/{cli-6a1xg1p7.js → cli-a89zdqz9.js} +2 -2
  39. package/dist/{cli-03vpq45j.js → cli-ay40dnj3.js} +2 -2
  40. package/dist/{cli-tsma7p8v.js → cli-aypd09nf.js} +2 -2
  41. package/dist/{cli-ethgy7ha.js → cli-b3yzyc57.js} +2 -2
  42. package/dist/{cli-bn0rewsy.js → cli-c081bj3b.js} +2 -2
  43. package/dist/{cli-mmhj8vd7.js → cli-c668vvcf.js} +11 -2
  44. package/dist/{cli-sbwsxvtd.js → cli-d20qvpr2.js} +2 -2
  45. package/dist/{cli-c952c7ac.js → cli-e1595bgx.js} +3 -3
  46. package/dist/{cli-621ce7kw.js → cli-f12mr20z.js} +3 -3
  47. package/dist/{cli-dqygeeh5.js → cli-f1e0ptjj.js} +10 -1
  48. package/dist/{cli-xzfq4at3.js → cli-f4dbh7a5.js} +16 -12
  49. package/dist/{cli-ha9rmwgq.js → cli-fb8m699c.js} +2 -2
  50. package/dist/{cli-5bnsc0e1.js → cli-gsfk58nw.js} +5 -5
  51. package/dist/cli-gt4h8cxw.js +895 -0
  52. package/dist/{cli-nwyw3zhg.js → cli-gxee0bqa.js} +1 -1
  53. package/dist/{cli-25n3mv5d.js → cli-h5jeg46p.js} +6 -6
  54. package/dist/{cli-gn5af0x5.js → cli-he9gbdx0.js} +62 -12
  55. package/dist/{cli-gbfxp48k.js → cli-j0ppywdr.js} +42 -35
  56. package/dist/{cli-k4tjsdx9.js → cli-j3y0x2n4.js} +277 -199
  57. package/dist/{cli-7p4jxgtt.js → cli-j9bpmykh.js} +75 -27
  58. package/dist/{cli-dabehxhp.js → cli-kt907da6.js} +1 -1
  59. package/dist/{cli-wx2nj19m.js → cli-kv7sbc2c.js} +6 -6
  60. package/dist/{cli-abs8ndtr.js → cli-m30k9777.js} +26 -26
  61. package/dist/{cli-cz5nmdxt.js → cli-m5e802r7.js} +2 -2
  62. package/dist/{cli-0shx9j93.js → cli-pfk92eqz.js} +2 -2
  63. package/dist/{cli-xtrz6bzs.js → cli-ptfq202x.js} +5 -3
  64. package/dist/{cli-6n8axjv1.js → cli-qj442fws.js} +2 -2
  65. package/dist/{cli-c61mbdds.js → cli-rd5m70gj.js} +4 -4
  66. package/dist/{cli-eftzyh9y.js → cli-s09j9vp5.js} +2 -2
  67. package/dist/{cli-m4ecdxvz.js → cli-s0mgx214.js} +7 -7
  68. package/dist/{cli-wghjkr0e.js → cli-sgqm2582.js} +10 -7
  69. package/dist/{cli-2655k16q.js → cli-sjctjr48.js} +2 -2
  70. package/dist/{cli-nzfnt2gs.js → cli-tf1n0r0b.js} +1 -1
  71. package/dist/{cli-x0f2v69c.js → cli-twctnkng.js} +12 -7
  72. package/dist/{cli-j6rktc91.js → cli-v6shg7na.js} +1 -1
  73. package/dist/{cli-gx4rm0qx.js → cli-vz78s5wm.js} +1 -1
  74. package/dist/{cli-gwhjmh8g.js → cli-wqr7cea4.js} +5 -5
  75. package/dist/{cli-e42vss7b.js → cli-x37r7qwf.js} +16 -8
  76. package/dist/{cli-4b2z6n0m.js → cli-yd2nreqw.js} +17 -8
  77. package/dist/{cli-64mh9mf3.js → cli-ymjpkxgn.js} +69 -17
  78. package/dist/{cli-5kqnemen.js → cli-yvy48785.js} +1 -1
  79. package/dist/{cli-9j129brq.js → cli-yxbsmx56.js} +6 -6
  80. package/dist/cli.js +22 -20
  81. package/dist/{codex-adapter-wch12q99.js → codex-adapter-zk59x2zh.js} +7 -7
  82. package/dist/{codex-hook-brpnycn5.js → codex-hook-xyjhvxwd.js} +1 -1
  83. package/dist/{codex-login-rn7c5gxt.js → codex-login-8cg0vhf2.js} +1 -1
  84. package/dist/{codex-session-runner-41pfcr95.js → codex-session-runner-kh6s4j3n.js} +8 -8
  85. package/dist/{commands-9849dkj6.js → commands-68et1qv2.js} +2 -2
  86. package/dist/{controller-ja0sd95p.js → controller-fyrbnzg4.js} +4 -4
  87. package/dist/{controllers-connect-xp05dj6x.js → controllers-connect-nep9h2xv.js} +23 -23
  88. package/dist/{cursor-adapter-623qxqew.js → cursor-adapter-yss3pg7t.js} +2 -2
  89. package/dist/{db-w759qmx0.js → db-28gjyvxj.js} +4 -2
  90. package/dist/{db-47vj40dy.js → db-8ftwvzba.js} +3 -3
  91. package/dist/{devin-adapter-4ycy4vrf.js → devin-adapter-byen2cxt.js} +1 -1
  92. package/dist/{dispatcher-7b8e4z2j.js → dispatcher-hayexmkr.js} +20 -20
  93. package/dist/{docker-s84hjs91.js → docker-fdzyewpz.js} +2 -2
  94. package/dist/{dsh-adapter-2ezw3xea.js → dsh-adapter-46wawff9.js} +2 -2
  95. package/dist/{e2b-9gkdhm3c.js → e2b-222hsajc.js} +2 -2
  96. package/dist/{e2b-cjtf8k1z.js → e2b-fn3zacvt.js} +2 -2
  97. package/dist/{easter-egg-3d-e4qv8dxj.js → easter-egg-3d-8d1e0h4m.js} +1 -1
  98. package/dist/{event-bus-3z78ep5n.js → event-bus-pghg8hqy.js} +1 -1
  99. package/dist/{execute-0xpz8950.js → execute-cjrfxfnm.js} +1 -1
  100. package/dist/{external-channel-e2s028da.js → external-channel-xbmxcg09.js} +2 -2
  101. package/dist/{grok-adapter-ys7gaqee.js → grok-adapter-ag4wks2a.js} +10 -10
  102. package/dist/handlers-tzmevqb5.js +41 -0
  103. package/dist/{heartbeat-w3mntghj.js → heartbeat-psfvcgwp.js} +23 -23
  104. package/dist/{hook-g7kvv6x9.js → hook-8pz04697.js} +6 -6
  105. package/dist/{hook-3jjywnpb.js → hook-cyq4mryn.js} +8 -8
  106. package/dist/{http-tkp7d4kb.js → http-haj1nd6k.js} +921 -169
  107. package/dist/{index-q7m26kvs.js → index-jwt2bj6f.js} +265 -97
  108. package/dist/{index-3n8m9ea2.js → index-q52f47pe.js} +1 -1
  109. package/dist/{index-31ceyf42.js → index-syvhnvtw.js} +1 -1
  110. package/dist/index-y1ajx04a.js +43 -0
  111. package/dist/{index-1ef1myq2.js → index-z5h22pes.js} +20 -20
  112. package/dist/{index-xdaahthb.js → index-zyq8ct52.js} +20 -20
  113. package/dist/{keepalive-v4ta8wgg.js → keepalive-xdvsamvj.js} +4 -4
  114. package/dist/lead-hqg57kdp.js +79 -0
  115. package/dist/{maintenance-84n1ex21.js → maintenance-4y2xzh3a.js} +1 -1
  116. package/dist/{oauth-refresh-sweep-vjnnandw.js → oauth-refresh-sweep-jd4r7zbs.js} +9 -4
  117. package/dist/{onboard-sfmpe4np.js → onboard-18447q9q.js} +6 -6
  118. package/dist/{opencode-adapter-jmpst4q4.js → opencode-adapter-26b2frdf.js} +7 -7
  119. package/dist/{otel-impl-v6cc0zve.js → otel-impl-f9tgr8yw.js} +2 -2
  120. package/dist/{pi-mono-adapter-fk8fkcf6.js → pi-mono-adapter-qn6qbga1.js} +38 -17
  121. package/dist/{pricing-refresh-fsk1e1zc.js → pricing-refresh-dw2tgb53.js} +3 -3
  122. package/dist/{rbac-roles-prmkdnkw.js → rbac-roles-aygm2760.js} +2 -2
  123. package/dist/{rbac-roles-zxmxqa39.js → rbac-roles-s4nwj2m3.js} +1 -1
  124. package/dist/render-v2-yfvdfr0x.js +16 -0
  125. package/dist/{resume-frdtgfa0.js → resume-1bmvjbf3.js} +9 -9
  126. package/dist/{runtime-bt5pkpm1.js → runtime-f7tpzedy.js} +1 -1
  127. package/dist/{session-access-fpez4y5q.js → session-access-r5garej6.js} +4 -4
  128. package/dist/session-source-backfill-424wzv0r.js +110 -0
  129. package/dist/{setup-mq6m3m8q.js → setup-8tygvxkq.js} +1 -1
  130. package/dist/{virtual-modules-mnfbh5mr.js → virtual-modules-xsw323b3.js} +2 -2
  131. package/dist/{work-objects-kfahhjsq.js → work-objects-ggnghpgf.js} +23 -23
  132. package/dist/worker-sqjd1nqf.js +79 -0
  133. package/dist/{x-pbpezr0s.js → x-wxrzvzx8.js} +2 -2
  134. package/openapi.json +1324 -14
  135. package/package.json +5 -3
  136. package/src/assets/source-key.ts +95 -0
  137. package/src/be/automation-preflight.ts +2 -0
  138. package/src/be/db/api-keys.ts +89 -0
  139. package/src/be/db/session-labels.ts +28 -0
  140. package/src/be/db/session-moves.ts +5 -6
  141. package/src/be/db/session-tree.ts +153 -14
  142. package/src/be/db/tasks/read.ts +11 -0
  143. package/src/be/db/tasks/write.ts +6 -1
  144. package/src/be/db/workflow-runs.ts +219 -6
  145. package/src/be/db-retention.ts +61 -6
  146. package/src/be/db.ts +135 -132
  147. package/src/be/memory/providers/openai-embedding.ts +5 -1
  148. package/src/be/memory/task-learning.ts +155 -0
  149. package/src/be/migrations/244_api_key_validation.sql +4 -0
  150. package/src/be/migrations/245_script_executor.sql +3 -0
  151. package/src/be/oauth-refresh-sweep.ts +2 -1
  152. package/src/be/onboarding.ts +4 -0
  153. package/src/be/scripts/boot-reembed.ts +2 -0
  154. package/src/be/scripts/db.ts +14 -4
  155. package/src/be/scripts/embeddings.ts +2 -0
  156. package/src/be/scripts/run-saved.ts +1 -0
  157. package/src/be/scripts/typecheck.ts +10 -4
  158. package/src/be/seed-skills/index.ts +7 -0
  159. package/src/be/session-source-backfill.ts +163 -0
  160. package/src/be/swarm-config-guard.ts +1 -0
  161. package/src/comb/review-batch.ts +28 -1
  162. package/src/comb/templates.ts +7 -2
  163. package/src/commands/claude-managed-setup.ts +7 -1
  164. package/src/commands/credential-refresh.ts +76 -1
  165. package/src/commands/credential-wait.ts +2 -2
  166. package/src/commands/onboard/compose-generator.ts +5 -3
  167. package/src/commands/provider-credentials.ts +212 -171
  168. package/src/commands/runner.ts +25 -4
  169. package/src/extensions/apply-task-create.ts +8 -1
  170. package/src/extensions/contract-types.generated.ts +1 -1
  171. package/src/extensions/contract.ts +5 -0
  172. package/src/heartbeat/heartbeat.ts +14 -1
  173. package/src/heartbeat/script-runner-probe.ts +47 -0
  174. package/src/http/all-routes.ts +2 -0
  175. package/src/http/api-keys.ts +77 -9
  176. package/src/http/assets.ts +15 -0
  177. package/src/http/codex-oauth-accounts.ts +191 -0
  178. package/src/http/comb.ts +15 -2
  179. package/src/http/config.ts +1 -1
  180. package/src/http/core.ts +6 -0
  181. package/src/http/fleet-benchmark.ts +5 -2
  182. package/src/http/idempotency-key.ts +1 -1
  183. package/src/http/index.ts +14 -3
  184. package/src/http/integrations.ts +5 -1
  185. package/src/http/kv.ts +8 -3
  186. package/src/http/onboarding.ts +6 -1
  187. package/src/http/pages-public.ts +38 -5
  188. package/src/http/pool-keys.ts +354 -0
  189. package/src/http/scripts.ts +27 -0
  190. package/src/http/sessions.ts +37 -12
  191. package/src/http/stats.ts +1 -0
  192. package/src/http/status.ts +26 -12
  193. package/src/http/tasks.ts +3 -0
  194. package/src/http/used-by.ts +7 -2
  195. package/src/http/workflows.ts +88 -9
  196. package/src/http/x.ts +5 -0
  197. package/src/integrations/chat-sdk/inbound.ts +27 -0
  198. package/src/kv-reserved-namespaces.ts +19 -0
  199. package/src/prompts/base-prompt.ts +21 -1
  200. package/src/prompts/session-templates.ts +17 -3
  201. package/src/providers/acp-targets.ts +1 -1
  202. package/src/providers/amp-adapter.ts +1 -1
  203. package/src/providers/claude-adapter.ts +5 -1
  204. package/src/providers/claude-managed-adapter.ts +16 -9
  205. package/src/providers/codex-adapter.ts +71 -11
  206. package/src/providers/dsh-adapter.ts +1 -1
  207. package/src/providers/pi-mono-adapter.ts +41 -11
  208. package/src/scheduler/scheduler.ts +5 -3
  209. package/src/scripts-runtime/eval-harness.ts +8 -1
  210. package/src/scripts-runtime/executors/native.ts +22 -16
  211. package/src/scripts-runtime/executors/quickjs-prelude.ts +103 -1
  212. package/src/scripts-runtime/executors/quickjs-runner.ts +2 -1
  213. package/src/scripts-runtime/executors/quickjs.ts +7 -0
  214. package/src/scripts-runtime/executors/registry.ts +32 -0
  215. package/src/scripts-runtime/executors/types.ts +7 -0
  216. package/src/scripts-runtime/host-validated-args.ts +133 -0
  217. package/src/scripts-runtime/loader.ts +30 -3
  218. package/src/scripts-runtime/swarm-sdk.ts +16 -3
  219. package/src/scripts-runtime/types/stdlib.d.ts +10 -2
  220. package/src/scripts-runtime/types/swarm-extension.d.ts +17 -8
  221. package/src/scripts-runtime/types/swarm-sdk.d.ts +10 -2
  222. package/src/slack/assistant.ts +7 -0
  223. package/src/slack/channel-labels.ts +74 -0
  224. package/src/slack/handlers.ts +8 -0
  225. package/src/slack/inbound-files.ts +5 -2
  226. package/src/slack/thread-buffer.ts +4 -0
  227. package/src/tasks/sibling-awareness.ts +12 -3
  228. package/src/telemetry-context.ts +5 -6
  229. package/src/telemetry-identity.ts +3 -3
  230. package/src/tests/api-key-status-by-suffix.test.ts +242 -0
  231. package/src/tests/api-keys-validation.test.ts +170 -0
  232. package/src/tests/base-prompt.test.ts +70 -2
  233. package/src/tests/claude-managed-adapter.test.ts +46 -0
  234. package/src/tests/claude-routes-e2e.test.ts +7 -2
  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/community-linear-delivery-loop.test.ts +2099 -0
  240. package/src/tests/config-pool-keys.test.ts +533 -0
  241. package/src/tests/credential-check.test.ts +294 -4
  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/docs-index.test.ts +135 -0
  248. package/src/tests/dsh-adapter.test.ts +1 -1
  249. package/src/tests/extensions-pre-task.test.ts +53 -1
  250. package/src/tests/fetch-resolved-env.test.ts +16 -2
  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/fleet-benchmark.test.ts +8 -0
  254. package/src/tests/get-workflow-run-tool.test.ts +98 -0
  255. package/src/tests/heartbeat-checklist.test.ts +89 -0
  256. package/src/tests/heartbeat-script-runner-probe.test.ts +83 -0
  257. package/src/tests/integrations-http.test.ts +32 -2
  258. package/src/tests/internal-ai/complete-structured.test.ts +37 -1
  259. package/src/tests/internal-ai/credentials.test.ts +23 -0
  260. package/src/tests/kv-http.test.ts +32 -0
  261. package/src/tests/kv-tool.test.ts +25 -0
  262. package/src/tests/multi-runtime-registration.test.ts +12 -12
  263. package/src/tests/oauth-refresh-sweep.test.ts +34 -1
  264. package/src/tests/onboard-compose.test.ts +20 -0
  265. package/src/tests/onboarding.test.ts +108 -1
  266. package/src/tests/openai-embedding-credentials.test.ts +35 -0
  267. package/src/tests/opencode-adapter.test.ts +2 -1
  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/pages-frame-ancestors.test.ts +162 -0
  271. package/src/tests/pi-codemode.test.ts +2 -1
  272. package/src/tests/pi-mono-adapter.test.ts +54 -0
  273. package/src/tests/pi-native-mcp.test.ts +13 -1
  274. package/src/tests/pi-tool-exposure.test.ts +8 -8
  275. package/src/tests/probe-tool-schema-tokens.test.ts +144 -0
  276. package/src/tests/prompt-template-session.test.ts +4 -3
  277. package/src/tests/provider-key-probes.test.ts +181 -0
  278. package/src/tests/rbac-e2e-helpers.test.ts +88 -1
  279. package/src/tests/rbac-e2e-helpers.ts +36 -11
  280. package/src/tests/request-composition-derive.test.ts +329 -0
  281. package/src/tests/script-connections.test.ts +4 -0
  282. package/src/tests/script-executor-conformance.test.ts +36 -1
  283. package/src/tests/script-executor-quickjs-pool.test.ts +50 -0
  284. package/src/tests/script-executor-quickjs.test.ts +140 -0
  285. package/src/tests/script-host-validated-args-native.test.ts +196 -0
  286. package/src/tests/script-per-script-executor.test.ts +415 -0
  287. package/src/tests/script-runs-retention.test.ts +212 -0
  288. package/src/tests/scripts-external-api.test.ts +45 -0
  289. package/src/tests/sdk-allowlist.test.ts +42 -2
  290. package/src/tests/self-improvement.test.ts +4 -4
  291. package/src/tests/session-source-backfill.test.ts +429 -0
  292. package/src/tests/session-source-keys.test.ts +236 -0
  293. package/src/tests/session-source-labels.test.ts +419 -0
  294. package/src/tests/sessions-detail-batch.test.ts +2 -0
  295. package/src/tests/sessions-move.test.ts +131 -0
  296. package/src/tests/sessions-tree.test.ts +299 -2
  297. package/src/tests/slack-inbound-files.test.ts +103 -23
  298. package/src/tests/status.test.ts +101 -18
  299. package/src/tests/store-progress-learning.test.ts +288 -0
  300. package/src/tests/tasks-workflow-run-filter.test.ts +146 -0
  301. package/src/tests/test-net.ts +31 -0
  302. package/src/tests/transcription.test.ts +8 -0
  303. package/src/tests/ui-logs-parser.test.ts +180 -0
  304. package/src/tests/used-by-route.test.ts +11 -0
  305. package/src/tests/workflow-cascade-cancel.test.ts +172 -0
  306. package/src/tests/workflow-engine-v2.test.ts +116 -1
  307. package/src/tests/workflow-http-v2.test.ts +131 -0
  308. package/src/tests/workflow-mcp-trigger-schema.test.ts +209 -0
  309. package/src/tests/workflow-run-finished-event.test.ts +263 -0
  310. package/src/tests/workflow-step-order.test.ts +92 -0
  311. package/src/tests/workflow-sub-workflow.test.ts +30 -0
  312. package/src/tests/workflow-swarm-script.test.ts +34 -0
  313. package/src/tools/get-tasks.ts +8 -0
  314. package/src/tools/kv/kv-read-auth.ts +4 -2
  315. package/src/tools/script-common.ts +1 -0
  316. package/src/tools/script-run.ts +7 -0
  317. package/src/tools/script-upsert.ts +7 -0
  318. package/src/tools/store-progress.ts +67 -1
  319. package/src/tools/task-action.ts +1 -1
  320. package/src/tools/workflows/get-workflow-run.ts +14 -4
  321. package/src/tools/workflows/trigger-workflow.ts +104 -10
  322. package/src/types.ts +36 -1
  323. package/src/utils/company-profile.ts +51 -1
  324. package/src/utils/credentials.ts +10 -4
  325. package/src/utils/internal-ai/complete-structured.ts +5 -0
  326. package/src/utils/internal-ai/credentials.ts +4 -3
  327. package/src/utils/provider-key-probes.ts +328 -0
  328. package/src/utils/transcription.ts +4 -1
  329. package/src/workflows/engine.ts +18 -16
  330. package/src/workflows/executors/sub-workflow.ts +8 -1
  331. package/src/workflows/executors/swarm-script.ts +5 -0
  332. package/src/workflows/foreach-driver.ts +5 -11
  333. package/src/workflows/node-timeout.ts +30 -0
  334. package/templates/ai-toolbox.manifest.json +2 -2
  335. package/templates/community/linear-delivery-loop/PLAYBOOK.md +323 -0
  336. package/templates/community/linear-delivery-loop/README.md +38 -0
  337. package/templates/community/linear-delivery-loop/config.example.json +31 -0
  338. package/templates/community/linear-delivery-loop/lead-prompt.md +34 -0
  339. package/templates/community/linear-delivery-loop/schedule.json +10 -0
  340. package/templates/community/linear-delivery-loop/scripts/linear-delivery-setup.ts +148 -0
  341. package/templates/community/linear-delivery-loop/scripts/linear-delivery-tick.ts +1781 -0
  342. package/templates/skills/researching/content.md +2 -0
  343. package/templates/skills/swarm-docs/config.json +14 -0
  344. package/templates/skills/swarm-docs/content.md +144 -0
  345. package/templates/skills/swarm-scripts/SKILL.md +1 -0
  346. package/templates/skills/swarm-scripts/content.md +1 -0
  347. package/dist/cli-7421jzsw.js +0 -84
  348. package/dist/cli-e45e4m6b.js +0 -413
  349. package/dist/cli-zw88zjba.js +0 -307
  350. package/dist/handlers-wy1dr6ja.js +0 -41
  351. package/dist/index-nmm79qgr.js +0 -43
  352. package/dist/lead-sawnyqxk.js +0 -79
  353. package/dist/render-v2-pjwxvnkw.js +0 -12
  354. package/dist/worker-v5e5rxj3.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,
@@ -284,22 +288,31 @@ import {
284
288
  emitBudgetRefusalSideEffects,
285
289
  workflowModelErrors,
286
290
  patchWorkflowDefinition,
291
+ idempotencyKeyHeader,
292
+ readIdempotencyKey,
293
+ replayAcceptedOperation,
287
294
  resolveScriptsOnlyMode,
288
295
  ALL_CAPABILITIES,
289
296
  hasCapability,
290
297
  getEnabledCapabilities,
291
298
  createServer
292
- } from "./cli-asq5ydm4.js";
299
+ } from "./cli-6a9qfa8b.js";
293
300
  import {
294
301
  chatThreadOfContextKey,
295
302
  agentContextKey,
296
303
  pageContextKey,
297
304
  init_context_key,
305
+ sourceOfKey,
306
+ SOURCE_GROUPS_READ_ONLY,
307
+ sourceMoveError,
308
+ init_source_key,
298
309
  init_catalog,
299
310
  catalog_default,
300
311
  COMPANY_TEAM_SIZES,
301
312
  COMPANY_USE_CASES,
302
313
  USER_FUNCTIONS,
314
+ reportedUseCase,
315
+ reportedUserFunction,
303
316
  init_company_profile,
304
317
  TELEMETRY_PROXY_ORIGIN,
305
318
  normalizeOrgWebsite,
@@ -347,6 +360,7 @@ import {
347
360
  resolveTriggerSurface,
348
361
  emitTaskTelemetry,
349
362
  init_telemetry_trigger,
363
+ CODEX_AUTH_FAILURE_BENCH_THRESHOLD,
350
364
  CODEX_AUTH_WATCH_NAMESPACE,
351
365
  codexAuthBenchMarkerKey,
352
366
  init_codex_auth_failure,
@@ -410,6 +424,7 @@ import {
410
424
  listPrefixRoots,
411
425
  listSharedPrefixRoots,
412
426
  init_session_moves,
427
+ getSessionGroupKey,
413
428
  getSessionReadState,
414
429
  getSessionTree,
415
430
  triageSessionList,
@@ -442,10 +457,14 @@ import {
442
457
  updateTaskProgress2,
443
458
  IdempotencyKeyTakenError,
444
459
  workflowRequestFingerprint,
445
- findAcceptedWorkflowOperation,
446
460
  assertWorkflowIdempotencyKeyUnused,
447
461
  recordAcceptedWorkflowOperation,
448
462
  init_workflow_idempotency,
463
+ getWorkflowRunSummary,
464
+ getWorkflowRunStepsSlimByRunId,
465
+ WORKFLOW_RUN_TREE_MAX_DEPTH,
466
+ WorkflowRunTreeError,
467
+ getWorkflowRunTree,
449
468
  getWorkflowRunParent,
450
469
  init_workflow_runs,
451
470
  CHAT_SDK_ADAPTER_NAMES,
@@ -537,6 +556,9 @@ import {
537
556
  init_steering,
538
557
  refreshActiveSessionOnActivity2,
539
558
  recordKeySeatMismatch2,
559
+ recordKeyValidation2,
560
+ retirePoolKeyStatus,
561
+ init_api_keys,
540
562
  getScriptRunExecutionArgs2,
541
563
  updateTaskVcs2,
542
564
  upsertAssetKeyMapping2,
@@ -743,7 +765,7 @@ import {
743
765
  countScriptRunJournalSteps2,
744
766
  countScriptRunJournalAgentTaskSteps2,
745
767
  init_db3
746
- } from "./cli-jb30dzvk.js";
768
+ } from "./cli-48gxjmcz.js";
747
769
  import {
748
770
  PRIMARY_ROLE_NAMES2,
749
771
  getUserGrant2,
@@ -754,26 +776,26 @@ import {
754
776
  assertNotLastAdmin2,
755
777
  setUserRoles2,
756
778
  init_rbac_roles
757
- } from "./cli-ff1tm9n9.js";
758
- import"./cli-c61mbdds.js";
779
+ } from "./cli-8wmj18cz.js";
780
+ import"./cli-rd5m70gj.js";
759
781
  import {
760
782
  normalizeModelKey
761
- } from "./cli-sbwsxvtd.js";
783
+ } from "./cli-d20qvpr2.js";
762
784
  import {
763
785
  upsertModelCatalogOverlay,
764
786
  deleteModelCatalogOverlay,
765
787
  loadModelsCatalog,
766
788
  requestModelCatalogRefresh2
767
- } from "./cli-bvpgr9ny.js";
789
+ } from "./cli-60sty27p.js";
768
790
  import {
769
791
  AMP_ESTIMATE_MODELS,
770
792
  ampBillsCacheWrites,
771
793
  resolveAmpModel
772
- } from "./cli-9s05422w.js";
794
+ } from "./cli-8mbc9za9.js";
773
795
  import {
774
796
  workflowEventBus2,
775
797
  init_event_bus
776
- } from "./cli-dabehxhp.js";
798
+ } from "./cli-kt907da6.js";
777
799
  import {
778
800
  automationIntegrationFixUrl,
779
801
  preflightAutomation,
@@ -809,7 +831,7 @@ import {
809
831
  generateEdges,
810
832
  definitionNodeIds,
811
833
  validateDefinition
812
- } from "./cli-gbfxp48k.js";
834
+ } from "./cli-j0ppywdr.js";
813
835
  import {
814
836
  require_dist2,
815
837
  isInvalidClientError,
@@ -869,8 +891,10 @@ import {
869
891
  buildSandboxedCommand,
870
892
  sandboxSpawnEnv,
871
893
  readStreamCapped,
894
+ isExecutorAllowedByDeployment,
872
895
  MIN_SCRIPT_WALL_CLOCK_MS,
873
896
  MAX_SCRIPT_WALL_CLOCK_MS,
897
+ HOST_VALIDATED_ARGS,
874
898
  require_typescript2,
875
899
  checkImportAllowlist,
876
900
  runScriptWithRunCredential,
@@ -889,14 +913,14 @@ import {
889
913
  typecheckWithAmbient,
890
914
  typecheckScript,
891
915
  parseSkillContent
892
- } from "./cli-7p4jxgtt.js";
916
+ } from "./cli-j9bpmykh.js";
893
917
  import {
894
918
  buildAuthorizationUrl,
895
919
  exchangeAuthorizationCode,
896
920
  oauthAppRowToProviderConfig,
897
921
  forceRefreshAuthorizationOrThrow,
898
922
  forceRefreshTokenOrThrow
899
- } from "./cli-tsma7p8v.js";
923
+ } from "./cli-aypd09nf.js";
900
924
  import {
901
925
  signalProcessGroup,
902
926
  detachedProcessGroup,
@@ -924,27 +948,31 @@ import {
924
948
  getTaskCitationsForTasks,
925
949
  initialize,
926
950
  ensure,
951
+ callSlackWithRetry2,
952
+ slackErrorCode2,
927
953
  getSlackApp2,
928
954
  startSlackApp2,
929
955
  stopSlackApp2
930
- } from "./cli-abs8ndtr.js";
931
- import"./cli-eftzyh9y.js";
932
- import"./cli-qqzmjxkf.js";
956
+ } from "./cli-m30k9777.js";
957
+ import"./cli-s09j9vp5.js";
958
+ import"./cli-1m9x8dr5.js";
933
959
  import {
934
960
  _fetchHolder,
935
961
  CLIENT_ID,
962
+ decodeJwt,
936
963
  exchangeAuthorizationCode2,
937
964
  getAccountId,
965
+ extractChatgptPlanType,
938
966
  deriveCodexKeySuffix,
939
967
  MAX_CODEX_OAUTH_SLOT,
940
968
  codexOAuthKeyForSlot,
941
969
  loadAllCodexOAuthSlots,
942
970
  getValidCodexOAuth
943
- } from "./cli-kxpfx2xr.js";
971
+ } from "./cli-0z1xjzwa.js";
944
972
  import {
945
973
  retryFailedRun2,
946
974
  cancelWorkflowRun2
947
- } from "./cli-x0f2v69c.js";
975
+ } from "./cli-twctnkng.js";
948
976
  import {
949
977
  duplicateGuardedQueryKey,
950
978
  warnIfCorsAllowsAnyOrigin,
@@ -989,7 +1017,7 @@ import {
989
1017
  bodyListTask,
990
1018
  describeRequestRoute,
991
1019
  route
992
- } from "./cli-gwhjmh8g.js";
1020
+ } from "./cli-wqr7cea4.js";
993
1021
  import {
994
1022
  FilesError,
995
1023
  normalizeFilesError,
@@ -1017,13 +1045,13 @@ import {
1017
1045
  resolvePoolDelivery2,
1018
1046
  createPoolAgent2,
1019
1047
  init_db
1020
- } from "./cli-19202kew.js";
1048
+ } from "./cli-6srv653c.js";
1021
1049
  import {
1022
1050
  RATING_MODEL_MAX_LENGTH,
1023
1051
  REFERENCES_SOURCE_MAX_LENGTH,
1024
1052
  sanitizeReferencesSource
1025
1053
  } from "./cli-3h26v7yj.js";
1026
- import"./cli-pasyvjmm.js";
1054
+ import"./cli-737pyqxr.js";
1027
1055
  import {
1028
1056
  startPoolRouting,
1029
1057
  stopPoolRouting,
@@ -1033,8 +1061,8 @@ import {
1033
1061
  checkHeartbeatChecklist2,
1034
1062
  runHeartbeatSweep2,
1035
1063
  stopHeartbeat2
1036
- } from "./cli-gn5af0x5.js";
1037
- import"./cli-6n8axjv1.js";
1064
+ } from "./cli-he9gbdx0.js";
1065
+ import"./cli-qj442fws.js";
1038
1066
  import {
1039
1067
  import_websocket,
1040
1068
  import_websocket_server
@@ -1043,18 +1071,18 @@ import {
1043
1071
  runtimeSupervisorStatus,
1044
1072
  startRuntimeSupervisor,
1045
1073
  stopRuntimeSupervisor
1046
- } from "./cli-1r5ad7j5.js";
1074
+ } from "./cli-9gsm2rzp.js";
1047
1075
  import"./cli-ns59dc6r.js";
1048
1076
  import {
1049
1077
  ACP_TARGET_IDS
1050
- } from "./cli-5kqnemen.js";
1078
+ } from "./cli-yvy48785.js";
1051
1079
  import {
1052
1080
  reasoningCapability,
1053
1081
  supportedReasoningLevels
1054
- } from "./cli-bn0rewsy.js";
1082
+ } from "./cli-c081bj3b.js";
1055
1083
  import {
1056
1084
  MAX_RATE_LIMIT_RESET_MS
1057
- } from "./cli-gx4rm0qx.js";
1085
+ } from "./cli-vz78s5wm.js";
1058
1086
  import {
1059
1087
  isLeadChannelMonitoringEnabled,
1060
1088
  ORG_IDENTITY_KEYS,
@@ -1062,12 +1090,13 @@ import {
1062
1090
  SIMILARITY_THRESHOLD,
1063
1091
  memoryRelevance,
1064
1092
  isUnknownModelError,
1093
+ checkProviderPoolKey,
1065
1094
  writeSkillsToFilesystem
1066
- } from "./cli-277c31dw.js";
1095
+ } from "./cli-6mgdba42.js";
1067
1096
  import {
1068
1097
  inviteEmailToSharedOrg,
1069
1098
  ensureAgentFsCredentialsForAgent
1070
- } from "./cli-ethgy7ha.js";
1099
+ } from "./cli-b3yzyc57.js";
1071
1100
  import {
1072
1101
  Anthropic
1073
1102
  } from "./cli-rr7zx19j.js";
@@ -1107,7 +1136,7 @@ import {
1107
1136
  revokeAgentTokens,
1108
1137
  fingerprintApiKey,
1109
1138
  init_users
1110
- } from "./cli-6a1xg1p7.js";
1139
+ } from "./cli-a89zdqz9.js";
1111
1140
  import"./cli-v41kn3cd.js";
1112
1141
  import"./cli-wgtk7xxr.js";
1113
1142
  import"./cli-1f0gp9vz.js";
@@ -1235,10 +1264,12 @@ import {
1235
1264
  ScriptRunListItemSchema,
1236
1265
  ScriptRunJournalEntrySchema,
1237
1266
  WorkflowRunStepSchema,
1267
+ WorkflowRunStepSlimSchema,
1238
1268
  PromptTemplateSchema,
1239
1269
  PromptTemplateHistorySchema,
1240
1270
  ScriptScopeSchema,
1241
1271
  ScriptFsModeSchema,
1272
+ ScriptExecutorNameSchema,
1242
1273
  ScriptRecordSchema,
1243
1274
  ScriptVersionRecordSchema,
1244
1275
  ExtensionManifestSchema,
@@ -1271,31 +1302,35 @@ import {
1271
1302
  KvKeySchema,
1272
1303
  KvEntrySchema,
1273
1304
  init_types
1274
- } from "./cli-mz9afxxf.js";
1305
+ } from "./cli-9pshx6rd.js";
1275
1306
  import {
1276
1307
  IDENTITY_FIELD_BUDGETS,
1277
1308
  IdentityFieldBudgetError,
1278
1309
  init_identity_field_budget
1279
- } from "./cli-e42vss7b.js";
1280
- import {
1281
- getSlackConfiguration,
1282
- init_config
1283
- } from "./cli-qeaq3j6t.js";
1310
+ } from "./cli-x37r7qwf.js";
1284
1311
  import {
1285
1312
  isSteeringEnabled2,
1286
1313
  init_steering_enabled
1287
1314
  } from "./cli-4sydckyj.js";
1288
1315
  import {
1289
- MODEL_SCOPED_WINDOWS,
1290
- activeModelBlocks,
1291
- init_model_rate_limit_windows
1292
- } from "./cli-7421jzsw.js";
1316
+ getSlackConfiguration,
1317
+ init_config
1318
+ } from "./cli-qeaq3j6t.js";
1293
1319
  import {
1294
1320
  SUBSCRIPTION_PLANS_CHECKED_AT,
1295
1321
  SUBSCRIPTION_PLANS,
1296
1322
  isSubscriptionPlanId,
1297
1323
  init_subscription_plans
1298
1324
  } from "./cli-7akn6ze9.js";
1325
+ import {
1326
+ MODEL_SCOPED_WINDOWS,
1327
+ activeModelBlocks,
1328
+ init_model_rate_limit_windows,
1329
+ CREDENTIAL_POOL_VARS,
1330
+ splitCredentialPool,
1331
+ selectCredential,
1332
+ init_credentials
1333
+ } from "./cli-gt4h8cxw.js";
1299
1334
  import {
1300
1335
  getOpenRouterAttributionHeaders,
1301
1336
  init_openrouter_base_url
@@ -1309,7 +1344,7 @@ import {
1309
1344
  resolveTemplate,
1310
1345
  init_resolver,
1311
1346
  init_session_templates
1312
- } from "./cli-dqygeeh5.js";
1347
+ } from "./cli-f1e0ptjj.js";
1313
1348
  import {
1314
1349
  init_zod
1315
1350
  } from "./cli-4chz1hye.js";
@@ -1344,7 +1379,7 @@ import {
1344
1379
  import {
1345
1380
  init_package,
1346
1381
  package_default
1347
- } from "./cli-xtrz6bzs.js";
1382
+ } from "./cli-ptfq202x.js";
1348
1383
  import {
1349
1384
  realtimeBus,
1350
1385
  init_bus
@@ -1372,12 +1407,15 @@ import {
1372
1407
  findSecretsIn,
1373
1408
  scrubObject,
1374
1409
  registerVolatileSecret,
1410
+ registerEnvSecrets,
1375
1411
  init_secret_scrubber
1376
- } from "./cli-n4c8e3s5.js";
1412
+ } from "./cli-708wdy32.js";
1377
1413
  import {
1378
1414
  isAlias,
1415
+ baseUrlEnvVar,
1416
+ providerForKeyVar,
1379
1417
  init_src2
1380
- } from "./cli-nwyw3zhg.js";
1418
+ } from "./cli-gxee0bqa.js";
1381
1419
  import {
1382
1420
  __toESM
1383
1421
  } from "./cli-242037k3.js";
@@ -1435,6 +1473,7 @@ init_db3();
1435
1473
 
1436
1474
  // src/be/db-retention.ts
1437
1475
  import { AsyncLocalStorage } from "node:async_hooks";
1476
+ init_types();
1438
1477
  init_env_flag();
1439
1478
  init_secret_scrubber();
1440
1479
  init_db3();
@@ -1479,6 +1518,19 @@ var DB_RETENTION_TABLES = [
1479
1518
  metricsKey: "contextVersions",
1480
1519
  initialBatchSize: 50,
1481
1520
  maxBatchSize: 100
1521
+ },
1522
+ {
1523
+ table: "script_runs",
1524
+ policy: "age",
1525
+ timeColumn: "startedAt",
1526
+ cutoffFormat: "sqliteDatetime",
1527
+ statusColumn: "status",
1528
+ terminalStatuses: TERMINAL_SCRIPT_RUN_STATUSES,
1529
+ keepWhenSet: "idempotencyKey",
1530
+ envKey: "SCRIPT_RUNS_RETENTION_DAYS",
1531
+ metricsKey: "scriptRuns",
1532
+ initialBatchSize: 100,
1533
+ maxBatchSize: 500
1482
1534
  }
1483
1535
  ];
1484
1536
 
@@ -1612,13 +1664,26 @@ function sweepStatements(table, value, now) {
1612
1664
  params: [value]
1613
1665
  };
1614
1666
  }
1615
- const cutoff = new Date(now.getTime() - value * DAY_MS).toISOString();
1667
+ const iso = new Date(now.getTime() - value * DAY_MS).toISOString();
1668
+ const cutoff = "cutoffFormat" in table ? `${iso.slice(0, 10)} ${iso.slice(11, 19)}` : iso;
1669
+ const conditions = [];
1670
+ const params = [];
1671
+ if ("terminalStatuses" in table) {
1672
+ conditions.push(`${table.statusColumn} IN (${table.terminalStatuses.map(() => "?").join(", ")})`);
1673
+ params.push(...table.terminalStatuses);
1674
+ }
1675
+ conditions.push(`${table.timeColumn} < ?`);
1676
+ params.push(cutoff);
1677
+ if ("keepWhenSet" in table) {
1678
+ conditions.push(`rowid NOT IN (SELECT rowid FROM ${table.table} WHERE ${table.keepWhenSet} IS NOT NULL)`);
1679
+ }
1680
+ const where = conditions.join(" AND ");
1616
1681
  return {
1617
- backlogSql: `SELECT COUNT(*) AS n FROM ${table.table} WHERE ${table.timeColumn} < ?`,
1682
+ backlogSql: `SELECT COUNT(*) AS n FROM ${table.table} WHERE ${where}`,
1618
1683
  deleteSql: `DELETE FROM ${table.table} WHERE rowid IN (
1619
- SELECT rowid FROM ${table.table} WHERE ${table.timeColumn} < ? ORDER BY ${table.timeColumn} LIMIT ?
1684
+ SELECT rowid FROM ${table.table} WHERE ${where} ORDER BY ${table.timeColumn} LIMIT ?
1620
1685
  )`,
1621
- params: [cutoff]
1686
+ params
1622
1687
  };
1623
1688
  }
1624
1689
  function dryRunEnabled(env = process.env) {
@@ -5455,6 +5520,33 @@ var reportRateLimit = route({
5455
5520
  },
5456
5521
  auth: { apiKey: true }
5457
5522
  });
5523
+ var reportValidation = route({
5524
+ method: "post",
5525
+ path: "/api/keys/report-validation",
5526
+ pattern: ["api", "keys", "report-validation"],
5527
+ summary: "Record live validation results for a credential pool",
5528
+ tags: ["API Keys"],
5529
+ body: object2({
5530
+ keyType: string2(),
5531
+ keys: array2(object2({
5532
+ keyIndex: number2().int().min(0),
5533
+ keySuffix: string2().min(1).max(10),
5534
+ ok: boolean(),
5535
+ httpStatus: number2().int().optional()
5536
+ })).min(1).max(100),
5537
+ scope: string2().optional(),
5538
+ scopeId: string2().optional()
5539
+ }),
5540
+ responses: {
5541
+ 200: { description: "Validation recorded", schema: successMessageSchema },
5542
+ 400: { description: "Validation error" },
5543
+ 401: { description: "Unauthorized" }
5544
+ },
5545
+ auth: { apiKey: true },
5546
+ rbac: {
5547
+ ungated: "worker credential telemetry, same posture as POST /api/keys/report-rate-limit"
5548
+ }
5549
+ });
5458
5550
  var reportAuthFailure = route({
5459
5551
  method: "post",
5460
5552
  path: "/api/keys/report-auth-failure",
@@ -5564,7 +5656,11 @@ var getAvailable = route({
5564
5656
  totalKeys: exports_coerce.number().int().min(1),
5565
5657
  scope: string2().optional(),
5566
5658
  scopeId: string2().optional(),
5567
- model: _enum2(["fable", "opus", "sonnet", "haiku"]).optional()
5659
+ model: _enum2(["fable", "opus", "sonnet", "haiku"]).optional(),
5660
+ keySuffixes: string2().transform((value) => value.split(",")).optional()
5661
+ }).refine((query) => !query.keySuffixes || query.keySuffixes.length === query.totalKeys, {
5662
+ message: "keySuffixes must list exactly totalKeys suffixes",
5663
+ path: ["keySuffixes"]
5568
5664
  }),
5569
5665
  responses: {
5570
5666
  200: {
@@ -5572,6 +5668,7 @@ var getAvailable = route({
5572
5668
  schema: object2({
5573
5669
  success: literal2(true),
5574
5670
  availableIndices: array2(number2().int()),
5671
+ rejectedIndices: array2(number2().int()).optional(),
5575
5672
  totalKeys: number2().int(),
5576
5673
  modelBlockedIndices: array2(number2().int()).optional(),
5577
5674
  earliestModelResetAt: string2().nullable().optional(),
@@ -5606,6 +5703,8 @@ var ApiKeyStatusSchema = object2({
5606
5703
  lastSeatMismatchModel: string2().nullable(),
5607
5704
  consecutiveAuthFailures: number2().int(),
5608
5705
  lastAuthFailureAt: string2().nullable(),
5706
+ lastValidationError: string2().nullable(),
5707
+ lastValidationFailedAt: string2().nullable(),
5609
5708
  modelLimits: array2(object2({
5610
5709
  model: string2(),
5611
5710
  window: string2(),
@@ -5828,6 +5927,19 @@ async function handleApiKeys(req, res, pathSegments, queryParams) {
5828
5927
  }
5829
5928
  return true;
5830
5929
  }
5930
+ if (reportValidation.match(req.method, pathSegments)) {
5931
+ const parsed = await reportValidation.parse(req, res, pathSegments, queryParams);
5932
+ if (!parsed)
5933
+ return true;
5934
+ const { keyType, keys, scope, scopeId } = parsed.body;
5935
+ try {
5936
+ await recordKeyValidation2(keyType, keys, scope, scopeId ?? null);
5937
+ reportValidation.respond(res, 200, { success: true, message: "Key validation recorded" });
5938
+ } catch (err) {
5939
+ jsonError(res, err instanceof Error ? err.message : "Failed to record key validation", 500);
5940
+ }
5941
+ return true;
5942
+ }
5831
5943
  if (reportAuthFailure.match(req.method, pathSegments)) {
5832
5944
  const parsed = await reportAuthFailure.parse(req, res, pathSegments, queryParams);
5833
5945
  if (!parsed)
@@ -5883,12 +5995,13 @@ async function handleApiKeys(req, res, pathSegments, queryParams) {
5883
5995
  const parsed = await getAvailable.parse(req, res, pathSegments, queryParams);
5884
5996
  if (!parsed)
5885
5997
  return true;
5886
- const { keyType, totalKeys, scope, scopeId, model } = parsed.query;
5998
+ const { keyType, totalKeys, scope, scopeId, model, keySuffixes } = parsed.query;
5887
5999
  try {
5888
- const result = await getAvailableKeyIndices2(keyType, totalKeys, scope, scopeId ?? null, model);
6000
+ const result = await getAvailableKeyIndices2(keyType, totalKeys, scope, scopeId ?? null, model, keySuffixes);
5889
6001
  getAvailable.respond(res, 200, {
5890
6002
  success: true,
5891
6003
  availableIndices: result.availableIndices,
6004
+ rejectedIndices: result.rejectedIndices,
5892
6005
  totalKeys,
5893
6006
  authFailureFence: result.authFailureFence,
5894
6007
  ...model !== undefined ? {
@@ -6160,7 +6273,11 @@ async function handleUsedBy(req, res, pathSegments, queryParams, myAgentId) {
6160
6273
  org_website: orgWebsite,
6161
6274
  ...orgDomain ? { org_domain: orgDomain } : {},
6162
6275
  granted,
6163
- ...granted ? { contact_email: contactEmail, contact_function: contactFunction, quote } : {},
6276
+ ...granted ? {
6277
+ contact_email: contactEmail,
6278
+ contact_function: reportedUserFunction(contactFunction),
6279
+ quote
6280
+ } : {},
6164
6281
  changed_at: changedAt
6165
6282
  }),
6166
6283
  signal: AbortSignal.timeout(TIMEOUT_MS)
@@ -7568,6 +7685,8 @@ async function approvalQuorumMet(approvers, votes) {
7568
7685
 
7569
7686
  // src/http/assets.ts
7570
7687
  init_zod();
7688
+ init_key();
7689
+ init_source_key();
7571
7690
  init_asset_key_audit();
7572
7691
  init_db3();
7573
7692
  init_db2();
@@ -7827,6 +7946,16 @@ async function handleAssets(req, res, pathSegments, queryParams, myAgentId) {
7827
7946
  jsonError(res, await canReadSession2(req, myAgentId, task.id) ? "You can view this session but not move it." : SESSION_READ_DENIED2, 403);
7828
7947
  return true;
7829
7948
  }
7949
+ const destination = normalizeAssetKey(parsed.body.key);
7950
+ if (sourceOfKey(destination)) {
7951
+ const rootId = task.parentTaskId ? (await getSessionRoot(task.id))?.id : task.id;
7952
+ const root = rootId === task.id ? task : rootId ? await getTaskById2(rootId) : null;
7953
+ const sourceError = sourceMoveError(destination, root ?? { id: task.id });
7954
+ if (sourceError) {
7955
+ jsonError(res, sourceError, 400);
7956
+ return true;
7957
+ }
7958
+ }
7830
7959
  const tasks = parsed.body.cascade ? await getRootTaskChain2(task.id) : [task];
7831
7960
  for (const target of tasks) {
7832
7961
  if (!await canMutateTaskNamespace(target, myAgentId, req)) {
@@ -8052,6 +8181,165 @@ async function handleBudgets(req, res, pathSegments, queryParams, _myAgentId) {
8052
8181
  return false;
8053
8182
  }
8054
8183
 
8184
+ // src/http/codex-oauth-accounts.ts
8185
+ init_zod();
8186
+ init_crypto();
8187
+ init_db3();
8188
+ init_api_keys();
8189
+ init_codex_auth_failure();
8190
+ var CodexAccountSchema = object2({
8191
+ slot: number2().int().min(0),
8192
+ configKey: string2(),
8193
+ legacy: boolean(),
8194
+ suffix: string2().nullable(),
8195
+ plan: string2().nullable(),
8196
+ email: string2().nullable(),
8197
+ status: _enum2(["ok", "needs_login", "unchecked"])
8198
+ });
8199
+ var CodexAccountsResponseSchema = object2({ accounts: array2(CodexAccountSchema) });
8200
+ var listAccounts = route({
8201
+ method: "get",
8202
+ path: "/api/codex-oauth/accounts",
8203
+ pattern: ["api", "codex-oauth", "accounts"],
8204
+ summary: "List stored Codex ChatGPT accounts",
8205
+ tags: ["Codex OAuth"],
8206
+ responses: {
8207
+ 200: { description: "Stored account metadata", schema: CodexAccountsResponseSchema },
8208
+ 403: { description: "Caller cannot read all secrets" }
8209
+ }
8210
+ });
8211
+ var deleteAccount = route({
8212
+ method: "delete",
8213
+ path: "/api/codex-oauth/accounts/{slot}",
8214
+ pattern: ["api", "codex-oauth", "accounts", null],
8215
+ summary: "Remove a stored Codex ChatGPT account",
8216
+ tags: ["Codex OAuth"],
8217
+ rbac: { permission: "config.delete.any" },
8218
+ params: object2({ slot: exports_coerce.number().int().min(0).max(MAX_CODEX_OAUTH_SLOT) }),
8219
+ responses: {
8220
+ 200: { description: "Remaining accounts", schema: CodexAccountsResponseSchema },
8221
+ 403: { description: "Config administration and permission to read all secrets required" },
8222
+ 404: { description: "Account slot does not exist" }
8223
+ }
8224
+ });
8225
+ async function accountRows() {
8226
+ 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]*')");
8227
+ const hasSlotZero = rows.some((row) => row.key === "codex_oauth_0");
8228
+ return rows.flatMap((row) => {
8229
+ if (row.key === "codex_oauth") {
8230
+ return hasSlotZero ? [] : [{ ...row, slot: 0, legacy: true }];
8231
+ }
8232
+ const match = /^codex_oauth_(0|[1-9]\d*)$/.exec(row.key);
8233
+ if (!match)
8234
+ return [];
8235
+ const slot = Number(match[1]);
8236
+ return slot <= MAX_CODEX_OAUTH_SLOT ? [{ ...row, slot, legacy: false }] : [];
8237
+ }).sort((a, b) => a.slot - b.slot);
8238
+ }
8239
+ var AccountCredentialsSchema = object2({
8240
+ access: string2().min(1),
8241
+ refresh: string2().min(1),
8242
+ expires: number2().finite(),
8243
+ accountId: string2().min(1)
8244
+ });
8245
+ function readCredentials(row) {
8246
+ try {
8247
+ const value = row.encrypted ? decryptSecret(row.value, getEncryptionKey()) : row.value;
8248
+ return AccountCredentialsSchema.parse(JSON.parse(value));
8249
+ } catch {
8250
+ return null;
8251
+ }
8252
+ }
8253
+ function accountSuffix(row) {
8254
+ const credentials = readCredentials(row);
8255
+ return credentials ? deriveCodexKeySuffix(credentials.access, credentials.accountId) : null;
8256
+ }
8257
+ async function accountsResponse() {
8258
+ const rows = await accountRows();
8259
+ const statuses = await getKeyStatuses2("CODEX_OAUTH", "global", null);
8260
+ const accounts = [];
8261
+ for (const row of rows) {
8262
+ const account = {
8263
+ slot: row.slot,
8264
+ configKey: row.key,
8265
+ legacy: row.legacy,
8266
+ suffix: null,
8267
+ plan: null,
8268
+ email: null,
8269
+ status: "needs_login"
8270
+ };
8271
+ const credentials = readCredentials(row);
8272
+ if (!credentials) {
8273
+ accounts.push(account);
8274
+ continue;
8275
+ }
8276
+ account.suffix = deriveCodexKeySuffix(credentials.access, credentials.accountId);
8277
+ account.plan = extractChatgptPlanType(credentials.access);
8278
+ const profile = decodeJwt(credentials.access)?.["https://api.openai.com/profile"];
8279
+ if (profile && typeof profile === "object" && "email" in profile) {
8280
+ account.email = typeof profile.email === "string" && profile.email ? profile.email : null;
8281
+ }
8282
+ const status = statuses.find((entry) => entry.keySuffix === account.suffix);
8283
+ const marker = await getKv2(CODEX_AUTH_WATCH_NAMESPACE, codexAuthBenchMarkerKey(account.suffix));
8284
+ const statusBenched = status && status.consecutiveAuthFailures >= CODEX_AUTH_FAILURE_BENCH_THRESHOLD && status.status === "rate_limited";
8285
+ account.status = marker || statusBenched ? "needs_login" : status ? "ok" : "unchecked";
8286
+ accounts.push(account);
8287
+ }
8288
+ return { accounts };
8289
+ }
8290
+ async function ensureSecretRead(req, res) {
8291
+ if (await requestSecretReadScope(req) === "all")
8292
+ return true;
8293
+ jsonError(res, "Reading Codex accounts requires access to all secrets", 403);
8294
+ return false;
8295
+ }
8296
+ async function handleCodexOAuthAccounts(req, res, pathSegments, queryParams) {
8297
+ if (listAccounts.match(req.method, pathSegments)) {
8298
+ const parsed = await listAccounts.parse(req, res, pathSegments, queryParams);
8299
+ if (!parsed)
8300
+ return true;
8301
+ if (!await ensureSecretRead(req, res))
8302
+ return true;
8303
+ listAccounts.respond(res, 200, await accountsResponse());
8304
+ return true;
8305
+ }
8306
+ if (deleteAccount.match(req.method, pathSegments)) {
8307
+ const parsed = await deleteAccount.parse(req, res, pathSegments, queryParams);
8308
+ if (!parsed)
8309
+ return true;
8310
+ if (!await ensureConfigAdmin(req, res, "config.delete.any"))
8311
+ return true;
8312
+ if (!await ensureSecretRead(req, res))
8313
+ return true;
8314
+ const deletedKey = await getDbClient2().transaction(async () => {
8315
+ const rows = await accountRows();
8316
+ const account = rows.find((row) => row.slot === parsed.params.slot);
8317
+ if (!account || !await deleteSwarmConfigByKey2("global", null, account.key))
8318
+ return null;
8319
+ const suffix = accountSuffix(account);
8320
+ if (suffix) {
8321
+ const remaining = rows.flatMap((row) => {
8322
+ const keySuffix = row === account ? null : accountSuffix(row);
8323
+ return keySuffix ? [{ keySuffix, keyIndex: row.slot }] : [];
8324
+ });
8325
+ await retirePoolKeyStatus("CODEX_OAUTH", suffix, remaining);
8326
+ if (!remaining.some((row) => row.keySuffix === suffix)) {
8327
+ await deleteKv2(CODEX_AUTH_WATCH_NAMESPACE, codexAuthBenchMarkerKey(suffix));
8328
+ }
8329
+ }
8330
+ return account.key;
8331
+ });
8332
+ if (deletedKey === null) {
8333
+ jsonError(res, "Codex account slot does not exist", 404);
8334
+ return true;
8335
+ }
8336
+ await runConfigWriteSideEffects("global", deletedKey, "");
8337
+ deleteAccount.respond(res, 200, await accountsResponse());
8338
+ return true;
8339
+ }
8340
+ return false;
8341
+ }
8342
+
8055
8343
  // src/http/codex-oauth-device.ts
8056
8344
  init_zod();
8057
8345
  init_crypto();
@@ -8192,7 +8480,9 @@ var OnboardingSignalsSchema = object2({
8192
8480
  provider: ProviderNameSchema,
8193
8481
  state: _enum2(["unverified", "configured", "verified"]),
8194
8482
  workers: number2().int().nonnegative(),
8195
- verifiedWorkers: number2().int().nonnegative()
8483
+ verifiedWorkers: number2().int().nonnegative(),
8484
+ error: string2().nullable(),
8485
+ warning: string2().nullable()
8196
8486
  })),
8197
8487
  embeddings: object2({
8198
8488
  configured: boolean(),
@@ -9117,6 +9407,7 @@ function sentTaskId(thread, replies, serviceUserId) {
9117
9407
  // src/comb/review-batch.ts
9118
9408
  init_templates();
9119
9409
  var REVIEW_BATCH_MAX = 50;
9410
+ var REVIEW_NOTE_MAX = 4000;
9120
9411
  var REVIEW_BATCH_READ_CONCURRENCY = 5;
9121
9412
  var SENT_KV_NAMESPACE = "comb:sent";
9122
9413
  var PENDING_CLAIM_MS = 5 * 60000;
@@ -9147,6 +9438,9 @@ async function sendReviewBatch(input, deps = {}) {
9147
9438
  if (ids.length === 0 || ids.length > REVIEW_BATCH_MAX) {
9148
9439
  throw new ReviewBatchError(400, `Send between 1 and ${REVIEW_BATCH_MAX} comments`);
9149
9440
  }
9441
+ if ((input.note?.length ?? 0) > REVIEW_NOTE_MAX) {
9442
+ throw new ReviewBatchError(400, `The note is longer than ${REVIEW_NOTE_MAX} characters`);
9443
+ }
9150
9444
  const agentFs = combAgentFs();
9151
9445
  if (!agentFs)
9152
9446
  throw new ReviewBatchError(503, "agent-fs is not set up for this swarm");
@@ -9180,6 +9474,7 @@ async function sendReviewBatch(input, deps = {}) {
9180
9474
  }
9181
9475
  const wonIds = won.map((read) => read.id);
9182
9476
  let taskId = null;
9477
+ let leadState = "none";
9183
9478
  if (won.length > 0) {
9184
9479
  try {
9185
9480
  const text = await renderTaskText(input, won);
@@ -9190,6 +9485,7 @@ async function sendReviewBatch(input, deps = {}) {
9190
9485
  ]);
9191
9486
  }
9192
9487
  const lead = await getLeadAgent2();
9488
+ leadState = !lead ? "none" : lead.status === "offline" ? "offline" : "online";
9193
9489
  const task = await createTask(text, {
9194
9490
  agentId: lead?.id ?? "",
9195
9491
  routingReason: lead ? "skill" : undefined,
@@ -9226,7 +9522,7 @@ async function sendReviewBatch(input, deps = {}) {
9226
9522
  if (taskId === null && repaired.length === 0) {
9227
9523
  throw new ReviewBatchError(409, "Nothing to send", skipped);
9228
9524
  }
9229
- return { taskId, sent: wonIds, skipped, repaired };
9525
+ return taskId === null ? { taskId, sent: wonIds, skipped, repaired } : { taskId, sent: wonIds, skipped, repaired, lead: leadState };
9230
9526
  }
9231
9527
  async function mapLimited(items, limit, fn) {
9232
9528
  const results = new Array(items.length);
@@ -9371,6 +9667,7 @@ async function renderTaskText(input, reads) {
9371
9667
  requested_by: await requesterLabel(input.requestedByUserId),
9372
9668
  org_id: input.orgId,
9373
9669
  drive_id: input.driveId,
9670
+ note_block: noteBlock(input.note),
9374
9671
  comments_block: blocks.join(`
9375
9672
  `)
9376
9673
  });
@@ -9385,6 +9682,13 @@ function lineRange(comment) {
9385
9682
  const end = comment.lineEnd ?? comment.lineStart;
9386
9683
  return end === comment.lineStart ? `line ${comment.lineStart}` : `lines ${comment.lineStart}-${end}`;
9387
9684
  }
9685
+ function noteBlock(note) {
9686
+ const text = note?.trim();
9687
+ return text ? `
9688
+ Note from the sender, about all the comments:
9689
+ ${fenced(text)}
9690
+ ` : "";
9691
+ }
9388
9692
  function fenced(text) {
9389
9693
  const longest = (text.match(/`+/g) ?? []).reduce((max, run) => Math.max(max, run.length), 0);
9390
9694
  const fence = "`".repeat(Math.max(3, longest + 1));
@@ -9425,7 +9729,8 @@ var resultSchema = object2({
9425
9729
  taskId: string2().nullable(),
9426
9730
  sent: array2(string2()),
9427
9731
  skipped: array2(skippedSchema),
9428
- repaired: array2(object2({ id: string2(), taskId: string2() }))
9732
+ repaired: array2(object2({ id: string2(), taskId: string2() })),
9733
+ lead: _enum2(["online", "offline", "none"]).optional()
9429
9734
  });
9430
9735
  var batchErrorSchema = object2({ error: string2(), skipped: array2(skippedSchema) });
9431
9736
  function isDrivePath(path) {
@@ -9436,13 +9741,14 @@ var reviewBatchRoute = route({
9436
9741
  path: "/api/comb/review-batches",
9437
9742
  pattern: ["api", "comb", "review-batches"],
9438
9743
  summary: "Send agent-fs comments to the swarm as one lead task",
9439
- 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.",
9744
+ 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.",
9440
9745
  tags: ["Comb"],
9441
9746
  body: object2({
9442
9747
  orgId: string2().min(1),
9443
9748
  driveId: string2().min(1),
9444
9749
  commentIds: array2(uuid()).min(1).max(REVIEW_BATCH_MAX),
9445
- scopePath: string2().min(1).max(1024).refine(isDrivePath, "scopePath must start with '/' and have no '.' or '..' segment")
9750
+ scopePath: string2().min(1).max(1024).refine(isDrivePath, "scopePath must start with '/' and have no '.' or '..' segment"),
9751
+ note: string2().max(REVIEW_NOTE_MAX).optional()
9446
9752
  }),
9447
9753
  responses: {
9448
9754
  200: {
@@ -9832,16 +10138,16 @@ declare module "swarm-extension" {
9832
10138
  | "schedule"
9833
10139
  | "slack"
9834
10140
  | "agentmail"
9835
- | "mcp"
9836
- | "api"
9837
- | "ui"
9838
10141
  | "github"
9839
10142
  | "gitlab"
9840
10143
  | "azure-devops"
9841
10144
  | "bitbucket"
9842
- | "system"
9843
10145
  | "linear"
9844
10146
  | "jira"
10147
+ | "mcp"
10148
+ | "api"
10149
+ | "ui"
10150
+ | "system"
9845
10151
  | "comb"
9846
10152
  | "chat"
9847
10153
  | undefined;
@@ -9950,16 +10256,16 @@ declare module "swarm-extension" {
9950
10256
  | "schedule"
9951
10257
  | "slack"
9952
10258
  | "agentmail"
9953
- | "mcp"
9954
- | "api"
9955
- | "ui"
9956
10259
  | "github"
9957
10260
  | "gitlab"
9958
10261
  | "azure-devops"
9959
10262
  | "bitbucket"
9960
- | "system"
9961
10263
  | "linear"
9962
10264
  | "jira"
10265
+ | "mcp"
10266
+ | "api"
10267
+ | "ui"
10268
+ | "system"
9963
10269
  | "comb"
9964
10270
  | "chat";
9965
10271
  tags: string[];
@@ -10224,6 +10530,15 @@ declare module "swarm-extension" {
10224
10530
  description: string;
10225
10531
  origin: TaskCreateOrigin;
10226
10532
  requestInfo?: RequestInfo;
10533
+ /** Slack ingress metadata; not persisted or writable through modify. */
10534
+ slack?: {
10535
+ trigger: "mention" | "thread-buffer";
10536
+ messages: {
10537
+ ts: string;
10538
+ userId: string;
10539
+ text: string;
10540
+ }[];
10541
+ };
10227
10542
  }
10228
10543
  /** A pre.task.create hook blocked a task before it was created. */
10229
10544
  export interface TaskBlockedEvent {
@@ -13653,6 +13968,7 @@ async function buildFleetBenchmarkResponse(now = new Date) {
13653
13968
  const team = _enum2(COMPANY_TEAM_SIZES).safeParse(teamSize);
13654
13969
  const use = _enum2(COMPANY_USE_CASES).safeParse(useCase);
13655
13970
  const peerGroup = normalizeOrgWebsite(website) && team.success && use.success ? { teamSize: team.data, useCase: use.data } : null;
13971
+ const proxyPeerGroup = peerGroup && reportedUseCase(peerGroup.useCase) ? peerGroup : null;
13656
13972
  const empty = {
13657
13973
  level: peerGroup ? "full" : "basic",
13658
13974
  peerGroup: null,
@@ -13679,7 +13995,7 @@ async function buildFleetBenchmarkResponse(now = new Date) {
13679
13995
  return { ...empty, state: "telemetry_off", local };
13680
13996
  if (finishedTasks < FLEET_MIN_FINISHED_TASKS)
13681
13997
  return { ...empty, state: "not_enough_tasks", local };
13682
- const fleet = await fleetBenchmarks(now.getTime(), peerGroup);
13998
+ const fleet = await fleetBenchmarks(now.getTime(), proxyPeerGroup);
13683
13999
  const responsePeerGroup = peerGroup && fleet?.peer_group ? {
13684
14000
  teamSize: fleet.peer_group.team_size,
13685
14001
  useCase: fleet.peer_group.use_case,
@@ -14736,6 +15052,9 @@ function buildSlackManifest(name) {
14736
15052
  return manifest;
14737
15053
  }
14738
15054
 
15055
+ // src/http/integrations.ts
15056
+ init_credentials();
15057
+
14739
15058
  // src/http/config-values.ts
14740
15059
  init_db3();
14741
15060
  async function resolveConfigValue(key) {
@@ -14910,7 +15229,7 @@ function createIntegrationsHandler(deps = {}) {
14910
15229
  return true;
14911
15230
  }
14912
15231
  try {
14913
- const client = buildClient(apiKey);
15232
+ const client = buildClient(selectCredential(apiKey, undefined, "ANTHROPIC_API_KEY").selected);
14914
15233
  const agent = await client.beta.agents.retrieve(agentId);
14915
15234
  const modelId = typeof agent.model === "string" ? agent.model : agent.model?.id ?? null;
14916
15235
  claudeManagedTestRoute.respond(res, 200, {
@@ -15187,8 +15506,8 @@ function authorizeWrite(namespace, ctx) {
15187
15506
  return null;
15188
15507
  }
15189
15508
  function authorizeRead(namespace, ctx) {
15190
- const overflowAuthErr = mcpOverflowAuthError(namespace, ctx.callerAgentId);
15191
- return overflowAuthErr ? { status: 403, message: overflowAuthErr } : null;
15509
+ const readErr = privateNamespaceError(namespace) ?? mcpOverflowAuthError(namespace, ctx.callerAgentId);
15510
+ return readErr ? { status: 403, message: readErr } : null;
15192
15511
  }
15193
15512
  function encodeValueOrError(res, value, valueType) {
15194
15513
  try {
@@ -21590,6 +21909,7 @@ init_db3();
21590
21909
  init_memory();
21591
21910
  init_constants();
21592
21911
  init_types();
21912
+ init_credentials();
21593
21913
  init_openrouter_base_url();
21594
21914
 
21595
21915
  // src/http/status.ts
@@ -21658,6 +21978,7 @@ var StatusIdentitySchema = object2({
21658
21978
  var StatusActivitySchema = object2({
21659
21979
  agents_online: number2().int().nonnegative(),
21660
21980
  leads_online: number2().int().nonnegative(),
21981
+ leads_ready: number2().int().nonnegative(),
21661
21982
  recent_tasks_count: number2().int().nonnegative()
21662
21983
  });
21663
21984
  var StatusCombSchema = object2({
@@ -22038,7 +22359,7 @@ async function buildSetup(automationSetup) {
22038
22359
  await firstTaskMilestone()
22039
22360
  ];
22040
22361
  }
22041
- function computeHealth(setup) {
22362
+ function computeHealth(setup, readyLeads) {
22042
22363
  const byId = new Map(setup.map((m) => [m.id, m]));
22043
22364
  const harness = byId.get("harness");
22044
22365
  const workers = byId.get("workers");
@@ -22046,6 +22367,8 @@ function computeHealth(setup) {
22046
22367
  return "broken";
22047
22368
  if (!workers || workers.state === "unverified")
22048
22369
  return "broken";
22370
+ if (readyLeads === 0)
22371
+ return "degraded";
22049
22372
  if (harness.state === "configured")
22050
22373
  return "degraded";
22051
22374
  for (const id of ["slack", "github", "linear", "jira"]) {
@@ -22063,12 +22386,13 @@ async function buildStatusPayload() {
22063
22386
  const toStatus = ({ failureReason: _, ...status }) => status;
22064
22387
  const automations = automationInputs.map((automation) => toStatus(preflightAutomation(automation, automationSetup))).sort((a, b) => a.name.localeCompare(b.name) || a.kind.localeCompare(b.kind));
22065
22388
  const activity = await getInstanceActivity2();
22389
+ const readyLeads = (await getReadyAgentCounts2()).leads;
22066
22390
  const instance = await getInstanceFeedbackSignals();
22067
22391
  return {
22068
22392
  runtime_pools: { enabled: isRuntimePoolsEnabled(), supervisor: runtimeSupervisorStatus() },
22069
22393
  identity: buildIdentity(),
22070
22394
  setup,
22071
- activity,
22395
+ activity: { ...activity, leads_ready: readyLeads },
22072
22396
  agent_fs: {
22073
22397
  configured: !!process.env.AGENT_FS_API_URL,
22074
22398
  base_url: process.env.AGENT_FS_API_URL ?? null,
@@ -22076,7 +22400,7 @@ async function buildStatusPayload() {
22076
22400
  comb: getCombStatus(await combServiceUserId)
22077
22401
  },
22078
22402
  automations,
22079
- health: computeHealth(setup),
22403
+ health: computeHealth(setup, readyLeads),
22080
22404
  telemetry: { enabled: isTelemetryEnabled() },
22081
22405
  instance
22082
22406
  };
@@ -22111,7 +22435,7 @@ var getStatus = route({
22111
22435
  path: "/status",
22112
22436
  pattern: ["status"],
22113
22437
  summary: "Identity + setup readiness + live activity for the swarm dashboard",
22114
- 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.",
22438
+ 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.",
22115
22439
  tags: ["Status"],
22116
22440
  responses: {
22117
22441
  200: { description: "Status payload", schema: StatusResponseSchema },
@@ -22184,11 +22508,14 @@ async function buildSignals(state) {
22184
22508
  if (!provider.success)
22185
22509
  continue;
22186
22510
  const rollup = await rollupCredStatusForProvider(provider.data);
22511
+ const live = rollup.latestLiveTest;
22187
22512
  providers.push({
22188
22513
  provider: provider.data,
22189
22514
  state: rollup.state,
22190
22515
  workers: rollup.workers,
22191
- verifiedWorkers: rollup.verifiedWorkers
22516
+ verifiedWorkers: rollup.verifiedWorkers,
22517
+ error: live && !live.ok ? live.error ?? null : null,
22518
+ warning: live?.ok ? live.warning ?? null : null
22192
22519
  });
22193
22520
  }
22194
22521
  const integrations = await getAutomationSetupStates();
@@ -22334,7 +22661,7 @@ async function handleMemoryProbe(body) {
22334
22661
  const canReuseKey = reuseHost === undefined || endpoint.hostname === reuseHost;
22335
22662
  const reusedKey = !explicitKey && body.reuseKey && canReuseKey ? process.env[body.reuseKey] : undefined;
22336
22663
  const implicitKey = body.preset === "existing" ? process.env.EMBEDDING_API_KEY ?? process.env.OPENAI_API_KEY : undefined;
22337
- const apiKey = explicitKey ?? reusedKey ?? implicitKey;
22664
+ const apiKey = splitCredentialPool(explicitKey ?? reusedKey ?? implicitKey ?? "")[0];
22338
22665
  if (!apiKey) {
22339
22666
  return {
22340
22667
  ok: false,
@@ -22794,6 +23121,7 @@ var listTasks = route({
22794
23121
  status: string2().optional(),
22795
23122
  agentId: string2().optional(),
22796
23123
  scheduleId: string2().optional(),
23124
+ workflowRunId: string2().uuid().optional(),
22797
23125
  key: AssetKeySchema.optional(),
22798
23126
  keyPrefix: AssetKeySchema.optional(),
22799
23127
  search: string2().optional(),
@@ -23396,6 +23724,7 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
23396
23724
  status,
23397
23725
  agentId: parsed.query.agentId || undefined,
23398
23726
  scheduleId: parsed.query.scheduleId || undefined,
23727
+ workflowRunId: parsed.query.workflowRunId,
23399
23728
  key: parsed.query.key,
23400
23729
  keyPrefix: parsed.query.keyPrefix,
23401
23730
  search: parsed.query.search || undefined,
@@ -26520,7 +26849,26 @@ var LOCAL_PAGE_APP_URL = "http://localhost:5274";
26520
26849
  function getAppBaseUrl2() {
26521
26850
  return getAppUrl(LOCAL_PAGE_APP_URL);
26522
26851
  }
26523
- function buildCsp() {
26852
+ var FRAME_ANCESTOR_SOURCE_RE = /^(?:https?:\/\/)?(?:\*\.)?[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)*(?::(?:\d{1,5}|\*))?$/i;
26853
+ var cachedFrameAncestors = null;
26854
+ function getPageFrameAncestors() {
26855
+ const raw = process.env.PAGES_FRAME_ANCESTORS ?? "";
26856
+ if (cachedFrameAncestors?.raw === raw)
26857
+ return cachedFrameAncestors.origins;
26858
+ const origins = [];
26859
+ for (const entry of raw.split(/[\s,]+/)) {
26860
+ const value = entry.replace(/\/+$/, "");
26861
+ if (!value)
26862
+ continue;
26863
+ if (FRAME_ANCESTOR_SOURCE_RE.test(value))
26864
+ origins.push(value);
26865
+ else
26866
+ console.warn(`[pages] ignoring invalid PAGES_FRAME_ANCESTORS entry: ${entry}`);
26867
+ }
26868
+ cachedFrameAncestors = { raw, origins };
26869
+ return origins;
26870
+ }
26871
+ function buildCsp(page) {
26524
26872
  const configured = getConfiguredAppUrls();
26525
26873
  const devFallbacks = getNodeEnv() === "production" ? [] : [
26526
26874
  "http://localhost:5274",
@@ -26530,7 +26878,8 @@ function buildCsp() {
26530
26878
  "https://*.localhost",
26531
26879
  "http://*.localhost"
26532
26880
  ];
26533
- const ancestors = Array.from(new Set([...configured, ...devFallbacks]));
26881
+ const embedders = page.authMode === "public" ? getPageFrameAncestors() : [];
26882
+ const ancestors = Array.from(new Set([...configured, ...devFallbacks, ...embedders]));
26534
26883
  return [
26535
26884
  "default-src 'self'",
26536
26885
  "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.tailwindcss.com https://cdn.jsdelivr.net https://unpkg.com",
@@ -26696,7 +27045,7 @@ async function handlePagesPublic(req, res, pathSegments, queryParams) {
26696
27045
  const headers = {
26697
27046
  "Content-Type": "text/html; charset=utf-8",
26698
27047
  "Cache-Control": "no-store",
26699
- "Content-Security-Policy": buildCsp(),
27048
+ "Content-Security-Policy": buildCsp(page),
26700
27049
  "X-Content-Type-Options": "nosniff"
26701
27050
  };
26702
27051
  if (inlineSetCookie.length > 0)
@@ -26720,7 +27069,7 @@ async function handlePagesPublic(req, res, pathSegments, queryParams) {
26720
27069
  const headers = {
26721
27070
  "Content-Type": "text/html; charset=utf-8",
26722
27071
  "Cache-Control": "no-store",
26723
- "Content-Security-Policy": buildCsp(),
27072
+ "Content-Security-Policy": buildCsp(page),
26724
27073
  "X-Content-Type-Options": "nosniff"
26725
27074
  };
26726
27075
  if (inlineSetCookie.length > 0)
@@ -27302,6 +27651,298 @@ async function handlePoll(req, res, pathSegments, queryParams, myAgentId) {
27302
27651
  return false;
27303
27652
  }
27304
27653
 
27654
+ // src/http/pool-keys.ts
27655
+ init_src2();
27656
+ init_zod();
27657
+ init_db3();
27658
+ init_api_keys();
27659
+ init_swarm_config_guard();
27660
+ init_credentials();
27661
+ init_secret_scrubber();
27662
+ var PoolKeyStatusSchema = _enum2(["ok", "rejected", "rate_limited", "unchecked"]);
27663
+ var PoolKeySchema = object2({
27664
+ index: number2().int().min(0),
27665
+ suffix: string2(),
27666
+ status: PoolKeyStatusSchema,
27667
+ error: string2().nullable(),
27668
+ checkedAt: string2().nullable(),
27669
+ rateLimitedUntil: string2().nullable()
27670
+ });
27671
+ var PoolKeysResponseSchema = object2({
27672
+ key: string2(),
27673
+ source: _enum2(["stored", "env", "none"]),
27674
+ readOnly: boolean(),
27675
+ keys: array2(PoolKeySchema)
27676
+ });
27677
+ var PoolKeyCheckResultSchema = _enum2(["verified", "rejected", "not_tested"]);
27678
+ var PoolKeyCheckSchema = object2({
27679
+ suffix: string2(),
27680
+ result: PoolKeyCheckResultSchema,
27681
+ httpStatus: number2().nullable(),
27682
+ error: string2().nullable()
27683
+ });
27684
+ var poolVar = string2().refine((key) => key !== "CODEX_OAUTH" && CREDENTIAL_POOL_VARS.includes(key), "Choose a credential pool variable.");
27685
+ var getPoolKeys = route({
27686
+ method: "get",
27687
+ path: "/api/config/pool-keys",
27688
+ pattern: ["api", "config", "pool-keys"],
27689
+ summary: "List credential pool suffixes and status",
27690
+ tags: ["Config"],
27691
+ query: object2({ key: poolVar }),
27692
+ responses: {
27693
+ 200: { description: "Credential pool", schema: PoolKeysResponseSchema },
27694
+ 400: { description: "Invalid pool variable" },
27695
+ 403: { description: "Secret read permission required" }
27696
+ }
27697
+ });
27698
+ var addPoolKeys = route({
27699
+ method: "post",
27700
+ path: "/api/config/pool-keys",
27701
+ pattern: ["api", "config", "pool-keys"],
27702
+ summary: "Test and append keys to a credential pool",
27703
+ tags: ["Config"],
27704
+ rbac: { permission: "config.write.any" },
27705
+ body: object2({
27706
+ key: poolVar,
27707
+ value: string2(),
27708
+ baseUrl: string2().nullable().optional().describe("Base URL for the check only. Null tests the provider default. Omit to use the stored URL.")
27709
+ }),
27710
+ responses: {
27711
+ 200: {
27712
+ description: "Updated credential pool and checks",
27713
+ schema: PoolKeysResponseSchema.extend({ checks: array2(PoolKeyCheckSchema) })
27714
+ },
27715
+ 400: { description: "Invalid key" },
27716
+ 403: { description: "Config administration and permission to read all secrets required" },
27717
+ 409: { description: "Duplicate key or deployment env pool" },
27718
+ 422: {
27719
+ description: "Provider rejected a key. Nothing was saved.",
27720
+ schema: object2({ error: string2(), checks: array2(PoolKeyCheckSchema) })
27721
+ }
27722
+ }
27723
+ });
27724
+ var deletePoolKey = route({
27725
+ method: "delete",
27726
+ path: "/api/config/pool-keys",
27727
+ pattern: ["api", "config", "pool-keys"],
27728
+ summary: "Remove one credential pool member",
27729
+ tags: ["Config"],
27730
+ rbac: { permission: "config.delete.any" },
27731
+ query: object2({
27732
+ key: poolVar,
27733
+ index: exports_coerce.number().int().min(0),
27734
+ suffix: string2().min(1).max(5)
27735
+ }),
27736
+ responses: {
27737
+ 200: { description: "Updated credential pool", schema: PoolKeysResponseSchema },
27738
+ 400: { description: "Invalid pool member" },
27739
+ 403: { description: "Config administration and permission to read all secrets required" },
27740
+ 409: { description: "The pool changed or comes from the deployment env" }
27741
+ }
27742
+ });
27743
+ var ENV_POOL_ERROR = "These keys come from the deployment env. Change them there.";
27744
+ async function readPool(key) {
27745
+ const [row] = await getSwarmConfigs2({ scope: "global", key });
27746
+ const envValue = getDeploymentEnvValue(key);
27747
+ const source = row ? "stored" : envValue ? "env" : "none";
27748
+ const value = row?.value ?? envValue ?? "";
27749
+ registerEnvSecrets({ [key]: value });
27750
+ return { row, source, members: splitCredentialPool(value) };
27751
+ }
27752
+ async function poolResponse(key) {
27753
+ const pool = await readPool(key);
27754
+ const statuses = await getKeyStatuses2(key, "global", null);
27755
+ return {
27756
+ key,
27757
+ source: pool.source,
27758
+ readOnly: pool.source === "env",
27759
+ keys: pool.members.map((member, index) => {
27760
+ const suffix = member.slice(-5);
27761
+ const row = statuses.find((status) => status.keySuffix === suffix);
27762
+ const rejected = !!row?.lastValidationFailedAt;
27763
+ const limited = row?.status === "rate_limited" && !!row.rateLimitedUntil && Date.parse(row.rateLimitedUntil) > Date.now();
27764
+ return {
27765
+ index,
27766
+ suffix,
27767
+ status: rejected ? "rejected" : limited ? "rate_limited" : row ? "ok" : "unchecked",
27768
+ error: rejected ? scrubSecrets(row?.lastValidationError) || null : null,
27769
+ checkedAt: rejected ? row.lastValidationFailedAt : row?.updatedAt ?? null,
27770
+ rateLimitedUntil: row?.rateLimitedUntil ?? null
27771
+ };
27772
+ })
27773
+ };
27774
+ }
27775
+ function duplicateError(members, additions) {
27776
+ const seen = new Set(members);
27777
+ for (const member of additions) {
27778
+ if (seen.has(member))
27779
+ return `The key ending ${member.slice(-5)} is already in the pool.`;
27780
+ seen.add(member);
27781
+ }
27782
+ return null;
27783
+ }
27784
+ async function savePool(key, members, row) {
27785
+ const value = members.join(",");
27786
+ const validationError = validateConfigEntry({
27787
+ scope: "global",
27788
+ key,
27789
+ value,
27790
+ exportToEnv: row?.exportToEnv
27791
+ });
27792
+ if (validationError)
27793
+ return validationError;
27794
+ await upsertSwarmConfigWithPolicyMirror({
27795
+ scope: "global",
27796
+ key,
27797
+ value,
27798
+ isSecret: true,
27799
+ description: row?.description ?? null,
27800
+ envPath: row?.envPath ?? null,
27801
+ exportToEnv: row?.exportToEnv
27802
+ });
27803
+ return null;
27804
+ }
27805
+ async function ensureSecretRead2(req, res) {
27806
+ if (await requestSecretReadScope(req) === "all")
27807
+ return true;
27808
+ jsonError(res, "Reading credential pools requires permission to read all secrets.", 403);
27809
+ return false;
27810
+ }
27811
+ async function handlePoolKeys(req, res, pathSegments, queryParams) {
27812
+ if (getPoolKeys.match(req.method, pathSegments)) {
27813
+ const parsed = await getPoolKeys.parse(req, res, pathSegments, queryParams);
27814
+ if (!parsed)
27815
+ return true;
27816
+ if (!await ensureSecretRead2(req, res))
27817
+ return true;
27818
+ getPoolKeys.respond(res, 200, await poolResponse(parsed.query.key));
27819
+ return true;
27820
+ }
27821
+ if (addPoolKeys.match(req.method, pathSegments)) {
27822
+ const parsed = await addPoolKeys.parse(req, res, pathSegments, queryParams);
27823
+ if (!parsed)
27824
+ return true;
27825
+ if (!await ensureConfigAdmin(req, res, "config.write.any"))
27826
+ return true;
27827
+ if (!await ensureSecretRead2(req, res))
27828
+ return true;
27829
+ const { key, value, baseUrl } = parsed.body;
27830
+ const additions = value.split(",").map((part) => part.trim()).filter(Boolean);
27831
+ if (!additions.length) {
27832
+ jsonError(res, "Enter a key.", 400);
27833
+ return true;
27834
+ }
27835
+ if (additions.some((part) => /\s/.test(part))) {
27836
+ jsonError(res, "A key cannot contain spaces or line breaks.", 400);
27837
+ return true;
27838
+ }
27839
+ registerEnvSecrets({ [key]: additions.join(",") });
27840
+ const initial = await readPool(key);
27841
+ if (initial.source === "env") {
27842
+ jsonError(res, ENV_POOL_ERROR, 409);
27843
+ return true;
27844
+ }
27845
+ const duplicate = duplicateError(initial.members, additions);
27846
+ if (duplicate) {
27847
+ jsonError(res, scrubSecrets(duplicate), 409);
27848
+ return true;
27849
+ }
27850
+ const env = { ...process.env };
27851
+ const provider = providerForKeyVar(key);
27852
+ const baseUrlKey = key === "OPENROUTER_API_KEY" ? "OPENROUTER_BASE_URL" : provider ? baseUrlEnvVar(provider) : undefined;
27853
+ if (baseUrlKey && baseUrl !== undefined) {
27854
+ env[baseUrlKey] = baseUrl ?? "";
27855
+ } else if (baseUrlKey) {
27856
+ const [row] = await getSwarmConfigs2({ scope: "global", key: baseUrlKey });
27857
+ if (row)
27858
+ env[baseUrlKey] = row.value;
27859
+ }
27860
+ const checks = await Promise.all(additions.map(async (member) => {
27861
+ try {
27862
+ const probe = await checkProviderPoolKey(key, member, env);
27863
+ return {
27864
+ suffix: member.slice(-5),
27865
+ result: probe.skipped ? "not_tested" : probe.ok ? "verified" : probe.httpStatus === 401 ? "rejected" : "not_tested",
27866
+ httpStatus: probe.httpStatus ?? null,
27867
+ error: scrubSecrets(probe.error?.replaceAll(member, "[REDACTED]")) || null
27868
+ };
27869
+ } catch {
27870
+ return {
27871
+ suffix: member.slice(-5),
27872
+ result: "not_tested",
27873
+ httpStatus: null,
27874
+ error: "The provider check did not complete."
27875
+ };
27876
+ }
27877
+ }));
27878
+ const rejected = checks.find((check) => check.result === "rejected");
27879
+ if (rejected) {
27880
+ addPoolKeys.respond(res, 422, {
27881
+ error: scrubSecrets(`The key ending ${rejected.suffix} was rejected (HTTP 401). Nothing was saved.`),
27882
+ checks
27883
+ });
27884
+ return true;
27885
+ }
27886
+ const result = await getDbClient2().transaction(async () => {
27887
+ const current = await readPool(key);
27888
+ if (current.source === "env")
27889
+ return { error: ENV_POOL_ERROR, status: 409 };
27890
+ const duplicate = duplicateError(current.members, additions);
27891
+ if (duplicate)
27892
+ return { error: duplicate, status: 409 };
27893
+ const members = [...current.members, ...additions];
27894
+ const error = await savePool(key, members, current.row);
27895
+ if (error)
27896
+ return { error, status: 400 };
27897
+ await recordKeyValidation2(key, checks.flatMap((check, index) => check.result === "verified" ? [{ keyIndex: current.members.length + index, keySuffix: check.suffix, ok: true }] : []), "global", null, { retireAbsent: false });
27898
+ return { value: members.join(",") };
27899
+ });
27900
+ if ("error" in result) {
27901
+ jsonError(res, scrubSecrets(result.error), result.status);
27902
+ return true;
27903
+ }
27904
+ await runConfigWriteSideEffects("global", key, result.value);
27905
+ addPoolKeys.respond(res, 200, { ...await poolResponse(key), checks });
27906
+ return true;
27907
+ }
27908
+ if (deletePoolKey.match(req.method, pathSegments)) {
27909
+ const parsed = await deletePoolKey.parse(req, res, pathSegments, queryParams);
27910
+ if (!parsed)
27911
+ return true;
27912
+ if (!await ensureConfigAdmin(req, res, "config.delete.any"))
27913
+ return true;
27914
+ if (!await ensureSecretRead2(req, res))
27915
+ return true;
27916
+ const { key, index, suffix } = parsed.query;
27917
+ const result = await getDbClient2().transaction(async () => {
27918
+ const current = await readPool(key);
27919
+ if (current.source === "env")
27920
+ return { error: ENV_POOL_ERROR, status: 409 };
27921
+ if (!current.members[index] || current.members[index].slice(-5) !== suffix) {
27922
+ return { error: "The key list changed. Reload it and try again.", status: 409 };
27923
+ }
27924
+ const members = current.members.filter((_, position) => position !== index);
27925
+ if (members.length) {
27926
+ const error = await savePool(key, members, current.row);
27927
+ if (error)
27928
+ return { error, status: 400 };
27929
+ } else {
27930
+ await deleteSwarmConfigByKey2("global", null, key);
27931
+ }
27932
+ await retirePoolKeyStatus(key, suffix, members.map((member, keyIndex) => ({ keySuffix: member.slice(-5), keyIndex })));
27933
+ return { value: members.join(",") };
27934
+ });
27935
+ if ("error" in result) {
27936
+ jsonError(res, scrubSecrets(result.error), result.status);
27937
+ return true;
27938
+ }
27939
+ await runConfigWriteSideEffects("global", key, result.value);
27940
+ deletePoolKey.respond(res, 200, await poolResponse(key));
27941
+ return true;
27942
+ }
27943
+ return false;
27944
+ }
27945
+
27305
27946
  // src/http/pricing.ts
27306
27947
  init_zod();
27307
27948
  init_db3();
@@ -32240,7 +32881,8 @@ var upsertBodySchema = object2({
32240
32881
  description: string2().default(""),
32241
32882
  intent: string2().default(""),
32242
32883
  scope: ScriptScopeSchema.default("agent"),
32243
- fsMode: ScriptFsModeSchema.default("none")
32884
+ fsMode: ScriptFsModeSchema.default("none"),
32885
+ executor: ScriptExecutorNameSchema.nullable().optional()
32244
32886
  });
32245
32887
  var runBodySchema = object2({
32246
32888
  name: scriptNameSchema.optional(),
@@ -32249,6 +32891,7 @@ var runBodySchema = object2({
32249
32891
  intent: string2().default(""),
32250
32892
  scope: ScriptScopeSchema.optional(),
32251
32893
  fsMode: ScriptFsModeSchema.default("none"),
32894
+ executor: ScriptExecutorNameSchema.nullable().optional(),
32252
32895
  idempotencyKey: string2().max(200).optional()
32253
32896
  }).refine((body) => Boolean(body.name) !== Boolean(body.source), {
32254
32897
  message: "Provide exactly one of name or source"
@@ -32697,6 +33340,10 @@ async function handleScripts(req, res, pathSegments, queryParams, agentId) {
32697
33340
  return true;
32698
33341
  }
32699
33342
  }
33343
+ if (parsed.body.executor && !isExecutorAllowedByDeployment(parsed.body.executor)) {
33344
+ jsonError(res, 'Executor "native" is not permitted when deployment SCRIPT_EXECUTOR="quickjs"', 400);
33345
+ return true;
33346
+ }
32700
33347
  const secretRefusal = refuseSourceWithSecrets(parsed.body.source);
32701
33348
  if (secretRefusal) {
32702
33349
  json(res, secretRefusal, 400);
@@ -32724,6 +33371,7 @@ async function handleScripts(req, res, pathSegments, queryParams, agentId) {
32724
33371
  signatureJson: signatureJsonFor(parsed.body.source),
32725
33372
  argsJsonSchema,
32726
33373
  fsMode: parsed.body.fsMode,
33374
+ executor: parsed.body.executor,
32727
33375
  agentId: agent.id,
32728
33376
  isScratch: false,
32729
33377
  typeChecked: true,
@@ -32761,6 +33409,7 @@ async function handleScripts(req, res, pathSegments, queryParams, agentId) {
32761
33409
  }
32762
33410
  let source = parsed.body.source;
32763
33411
  let fsMode = parsed.body.fsMode;
33412
+ let executor = parsed.body.executor ?? null;
32764
33413
  let namedScript = null;
32765
33414
  if (parsed.body.name) {
32766
33415
  const script = await resolveScript(parsed.body.name, agent.id, parsed.body.scope);
@@ -32771,11 +33420,16 @@ async function handleScripts(req, res, pathSegments, queryParams, agentId) {
32771
33420
  namedScript = script;
32772
33421
  source = script.source;
32773
33422
  fsMode = script.fsMode;
33423
+ executor = parsed.body.executor !== undefined ? parsed.body.executor : script.executor;
32774
33424
  }
32775
33425
  if (fsMode === "workspace-rw") {
32776
33426
  jsonError(res, "workspace-rw scripts are not supported by /api/scripts/run in v1", 501);
32777
33427
  return true;
32778
33428
  }
33429
+ if (executor && !isExecutorAllowedByDeployment(executor)) {
33430
+ jsonError(res, 'Executor "native" is not permitted when deployment SCRIPT_EXECUTOR="quickjs"', 400);
33431
+ return true;
33432
+ }
32779
33433
  const startedAt = new Date().toISOString();
32780
33434
  const runStartTouch = namedScript?.isScratch ? await touchScratchScriptLastUsed(namedScript.id) : null;
32781
33435
  const credentials = await buildScriptCredentialBindingsWithFailures({ agentId: agent.id });
@@ -32783,6 +33437,7 @@ async function handleScripts(req, res, pathSegments, queryParams, agentId) {
32783
33437
  source,
32784
33438
  args: parsed.body.args,
32785
33439
  fsMode,
33440
+ executor,
32786
33441
  agentId: agent.id,
32787
33442
  runtimeInstanceId,
32788
33443
  egressSecrets: credentials.egressSecrets,
@@ -32911,6 +33566,7 @@ async function handleScripts(req, res, pathSegments, queryParams, agentId) {
32911
33566
  isScratch: script.isScratch,
32912
33567
  typeChecked: script.typeChecked,
32913
33568
  fsMode: script.fsMode,
33569
+ executor: script.executor,
32914
33570
  createdByAgentId: script.createdByAgentId,
32915
33571
  createdAt: script.createdAt,
32916
33572
  updatedAt: script.updatedAt
@@ -33672,6 +34328,7 @@ async function handleSessionData(req, res, pathSegments, queryParams, myAgentId)
33672
34328
  // src/http/sessions.ts
33673
34329
  init_zod();
33674
34330
  init_key();
34331
+ init_source_key();
33675
34332
  init_db3();
33676
34333
  init_session_moves();
33677
34334
  init_session_tree();
@@ -33680,6 +34337,74 @@ init_steering();
33680
34337
  init_users();
33681
34338
  init_rbac();
33682
34339
  init_bus();
34340
+
34341
+ // src/slack/channel-labels.ts
34342
+ var LABEL_TTL_MS = 24 * 60 * 60 * 1000;
34343
+ var FAILURE_TTL_MS = 10 * 60 * 1000;
34344
+ var FAILURE_CACHE_MAX = 500;
34345
+ var LOOKUP_QUEUE_MAX = 50;
34346
+ var inFlight2 = new Set;
34347
+ var failedUntil = new Map;
34348
+ var pending = Promise.resolve();
34349
+ async function channelLabel(client, id) {
34350
+ const result = await callSlackWithRetry2(client, "conversations.info", {
34351
+ channel: id.toUpperCase()
34352
+ });
34353
+ const channel = result.channel;
34354
+ if (result.ok === false || !channel)
34355
+ throw new Error("Channel lookup failed");
34356
+ if (channel.is_mpim)
34357
+ return "Group DM";
34358
+ if (channel.is_im && channel.user) {
34359
+ const result = await callSlackWithRetry2(client, "users.info", { user: channel.user });
34360
+ const user = result.user;
34361
+ const name = user?.profile?.display_name || user?.real_name || user?.profile?.real_name;
34362
+ if (result.ok !== false && name)
34363
+ return `DM · ${name}`;
34364
+ } else if (channel.name) {
34365
+ return `#${channel.name}`;
34366
+ }
34367
+ throw new Error("Channel label unavailable");
34368
+ }
34369
+ var CHANNEL_GROUP_KEY = /^shared\/slack\/([^/]+)\/$/;
34370
+ function warmSlackChannelLabels(groupKeys) {
34371
+ const client = getSlackApp2()?.client;
34372
+ if (!client)
34373
+ return;
34374
+ for (const groupKey of groupKeys) {
34375
+ const id = CHANNEL_GROUP_KEY.exec(groupKey)?.[1];
34376
+ if (!id)
34377
+ continue;
34378
+ if (inFlight2.has(id) || (failedUntil.get(id) ?? 0) > Date.now())
34379
+ continue;
34380
+ failedUntil.delete(id);
34381
+ if (inFlight2.size >= LOOKUP_QUEUE_MAX)
34382
+ continue;
34383
+ if (failedUntil.size + inFlight2.size >= FAILURE_CACHE_MAX) {
34384
+ const now = Date.now();
34385
+ for (const [failedId, until] of failedUntil) {
34386
+ if (until <= now)
34387
+ failedUntil.delete(failedId);
34388
+ }
34389
+ if (failedUntil.size + inFlight2.size >= FAILURE_CACHE_MAX)
34390
+ continue;
34391
+ }
34392
+ inFlight2.add(id);
34393
+ pending = pending.then(async () => {
34394
+ try {
34395
+ const label = await channelLabel(client, id);
34396
+ await rememberSessionLabel(groupKey, label, LABEL_TTL_MS);
34397
+ } catch (error) {
34398
+ failedUntil.set(id, Date.now() + FAILURE_TTL_MS);
34399
+ console.warn(`[Slack] Could not cache a session channel label: ${slackErrorCode2(error) ?? "unknown error"}`);
34400
+ } finally {
34401
+ inFlight2.delete(id);
34402
+ }
34403
+ });
34404
+ }
34405
+ }
34406
+
34407
+ // src/http/sessions.ts
33683
34408
  init_types();
33684
34409
  init_request_auth_context();
33685
34410
  init_runtime_pools_flag();
@@ -33742,6 +34467,7 @@ var SessionTreeGroupSchema = SessionSectionCountsSchema.extend({
33742
34467
  lastActivityAt: string2()
33743
34468
  });
33744
34469
  var SessionTreeResponseSchema = object2({
34470
+ labels: record2(string2(), string2()).optional(),
33745
34471
  groups: array2(SessionTreeGroupSchema),
33746
34472
  inbox: SessionSectionCountsSchema,
33747
34473
  later: SessionSectionCountsSchema,
@@ -34179,6 +34905,9 @@ async function checkSessionMove(rootTaskId, actor, req, myAgentId, options = {})
34179
34905
  }
34180
34906
  if (root.parentTaskId)
34181
34907
  return { reason: "Task is not a session root" };
34908
+ const sourceError = sourceMoveError(options.destination ?? null, root);
34909
+ if (sourceError)
34910
+ return { reason: sourceError };
34182
34911
  const tasks = await getRootTaskChain2(root.id);
34183
34912
  for (const task of tasks) {
34184
34913
  if (!await canMutateTaskNamespace(task, myAgentId, req)) {
@@ -34203,6 +34932,7 @@ var getSession = route({
34203
34932
  chain: array2(TaskWithSteeringSchema),
34204
34933
  access: SessionAccessSchema,
34205
34934
  owner: SessionOwnerSchema.nullable(),
34935
+ groupKey: string2(),
34206
34936
  approvals: array2(SessionApprovalSchema).optional(),
34207
34937
  readState: _enum2(["unread", "read", "later", "done"]).optional(),
34208
34938
  lastActivityAt: string2().optional()
@@ -34389,11 +35119,15 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
34389
35119
  if (!parsed)
34390
35120
  return true;
34391
35121
  const actor = await resolveSessionActor2(req, myAgentId);
34392
- sessionTree.respond(res, 200, await getSessionTree(actor, undefined, {
35122
+ const tree = await getSessionTree(actor, undefined, {
34393
35123
  mine: parsed.query.show !== "all",
34394
35124
  hideSource: parsed.query.hideSource,
34395
35125
  showSource: parsed.query.showSource
34396
- }));
35126
+ });
35127
+ const { sourceGroups, slackChannels, threadLabels, ...counts } = tree;
35128
+ const labels = { ...threadLabels, ...await getSessionLabels(sourceGroups) };
35129
+ warmSlackChannelLabels(slackChannels.map((id) => `shared/slack/${id}/`).filter((key) => labels[key] === undefined));
35130
+ sessionTree.respond(res, 200, { ...counts, labels });
34397
35131
  return true;
34398
35132
  }
34399
35133
  if (triageSessionListRoute.match(req.method, pathSegments)) {
@@ -34418,7 +35152,9 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
34418
35152
  const skipped = [];
34419
35153
  const moves = [];
34420
35154
  for (const rootId of new Set(parsed.body.rootTaskIds)) {
34421
- const checked = await checkSessionMove(rootId, actor, req, myAgentId);
35155
+ const checked = await checkSessionMove(rootId, actor, req, myAgentId, {
35156
+ destination: key
35157
+ });
34422
35158
  if ("reason" in checked) {
34423
35159
  skipped.push({ rootTaskId: rootId, reason: checked.reason });
34424
35160
  } else {
@@ -34439,6 +35175,10 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
34439
35175
  if (!parsed)
34440
35176
  return true;
34441
35177
  const from = normalizeAssetKey(parsed.body.from);
35178
+ if (sourceOfKey(from) || parsed.body.to && sourceOfKey(normalizeAssetKey(parsed.body.to))) {
35179
+ jsonError(res, SOURCE_GROUPS_READ_ONLY, 400);
35180
+ return true;
35181
+ }
34442
35182
  if (parseAssetKey(from).relativeSegments.length === 0) {
34443
35183
  jsonError(res, "Cannot move a namespace root", 400);
34444
35184
  return true;
@@ -34478,7 +35218,8 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
34478
35218
  continue;
34479
35219
  }
34480
35220
  const checked = await checkSessionMove(root.id, actor, req, myAgentId, {
34481
- ownerOnly: true
35221
+ ownerOnly: true,
35222
+ destination: nextKey
34482
35223
  });
34483
35224
  if ("reason" in checked) {
34484
35225
  skipped.push({ rootTaskId: root.id, reason: checked.reason });
@@ -34522,11 +35263,12 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
34522
35263
  } : null;
34523
35264
  const chain = await getRootTaskChain2(parsed.params.rootTaskId);
34524
35265
  const tasks = [root, ...chain];
34525
- const [steering, citations, approvals, read] = await Promise.all([
35266
+ const [steering, citations, approvals, read, groupKey] = await Promise.all([
34526
35267
  getTaskSteeringFieldsForTasks(tasks),
34527
35268
  getTaskCitationsForTasks(tasks.map((task) => task.id)),
34528
35269
  getPendingApprovalsForTasks2(tasks.map((task) => task.id)),
34529
- actor.kind === "user" && actor.userId ? getSessionReadState(sessionRoot.id, actor.userId) : Promise.resolve(null)
35270
+ actor.kind === "user" && actor.userId ? getSessionReadState(sessionRoot.id, actor.userId) : Promise.resolve(null),
35271
+ getSessionGroupKey(root)
34530
35272
  ]);
34531
35273
  const decorate = (task) => ({
34532
35274
  ...task,
@@ -34538,6 +35280,7 @@ async function handleSessions(req, res, pathSegments, queryParams, myAgentId) {
34538
35280
  chain: chain.map(decorate),
34539
35281
  access,
34540
35282
  owner,
35283
+ groupKey,
34541
35284
  ...approvals.length ? { approvals } : {},
34542
35285
  ...read ?? {}
34543
35286
  });
@@ -35926,7 +36669,8 @@ var SwarmMetricsSchema = object2({
35926
36669
  sessionLogs: RetentionTableStatsSchema.optional(),
35927
36670
  agentLog: RetentionTableStatsSchema.optional(),
35928
36671
  events: RetentionTableStatsSchema.optional(),
35929
- contextVersions: RetentionTableStatsSchema.optional()
36672
+ contextVersions: RetentionTableStatsSchema.optional(),
36673
+ scriptRuns: RetentionTableStatsSchema.optional()
35930
36674
  })
35931
36675
  });
35932
36676
  var ConcurrentContextSchema = object2({
@@ -39306,63 +40050,6 @@ init_db3();
39306
40050
  init_workflow_idempotency();
39307
40051
  init_workflow_runs();
39308
40052
  init_types();
39309
-
39310
- // src/http/idempotency-key.ts
39311
- init_zod();
39312
- init_workflow_idempotency();
39313
- init_request_auth_context();
39314
- var IDEMPOTENCY_KEY_PATTERN = /^[\x21-\x7E]{1,255}$/;
39315
- var IDEMPOTENT_REPLAYED_HEADER = "Idempotent-Replayed";
39316
- var idempotencyKeyHeader = (accepted) => object2({
39317
- "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.")
39318
- });
39319
- function idempotencyPrincipal(req, myAgentId) {
39320
- const auth = getRequestAuth(req);
39321
- switch (auth?.kind) {
39322
- case "user":
39323
- return `user:${auth.userId}`;
39324
- case "agent":
39325
- return `agent:${auth.agentId}`;
39326
- case "controller":
39327
- return `controller:${auth.controllerId}`;
39328
- case "guest":
39329
- return null;
39330
- default:
39331
- return myAgentId ? `agent:${myAgentId}` : "operator";
39332
- }
39333
- }
39334
- function readIdempotencyKey(req, res, myAgentId) {
39335
- const raw = req.headers["idempotency-key"];
39336
- if (raw === undefined)
39337
- return;
39338
- const key = Array.isArray(raw) ? raw.join(", ") : raw;
39339
- if (!IDEMPOTENCY_KEY_PATTERN.test(key)) {
39340
- jsonError(res, "Idempotency-Key must be 1-255 visible ASCII characters", 400);
39341
- return null;
39342
- }
39343
- const principal = idempotencyPrincipal(req, myAgentId);
39344
- if (!principal) {
39345
- jsonError(res, "Idempotency-Key needs an identified caller", 400);
39346
- return null;
39347
- }
39348
- return { principal, key };
39349
- }
39350
- async function replayAcceptedOperation(res, claim, send) {
39351
- const accepted = await findAcceptedWorkflowOperation(claim);
39352
- if (!accepted)
39353
- return false;
39354
- if (accepted.fingerprint !== claim.fingerprint) {
39355
- jsonError(res, "Idempotency-Key was already used for a different request", 409);
39356
- } else if (accepted.resourceDeletedAt !== null) {
39357
- jsonError(res, "The workflow this Idempotency-Key created or triggered was deleted; send a new key to start over", 410);
39358
- } else {
39359
- res.setHeader(IDEMPOTENT_REPLAYED_HEADER, "true");
39360
- send(accepted.body);
39361
- }
39362
- return true;
39363
- }
39364
-
39365
- // src/http/workflows.ts
39366
40053
  var WorkflowWithFavoriteSchema = WorkflowSchema.extend({ favorite: boolean() });
39367
40054
  var WorkflowSaveResponseSchema = WorkflowSchema.extend({
39368
40055
  warnings: array2(string2()).optional()
@@ -39391,6 +40078,11 @@ var WorkflowRunPageSchema = object2({
39391
40078
  nextOffset: number2().int().optional()
39392
40079
  })
39393
40080
  });
40081
+ var WorkflowRunTreeSchema = object2({
40082
+ rootRunId: string2(),
40083
+ runs: array2(WorkflowRunSummarySchema),
40084
+ hasOpenWork: boolean()
40085
+ });
39394
40086
  var SuccessResponseSchema = object2({ success: literal2(true) });
39395
40087
  async function withSaveWarnings(workflow) {
39396
40088
  const warnings = await workflowSaveWarnings(workflow.definition, getExecutorRegistry2());
@@ -39551,6 +40243,9 @@ var triggerWorkflowRoute = route({
39551
40243
  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.",
39552
40244
  tags: ["Workflows"],
39553
40245
  params: object2({ id: string2() }),
40246
+ query: object2({
40247
+ wait: _enum2(["true", "false"]).optional().describe("Default true: respond after the run's instant steps ran, when it finishes or parks at its first async step. " + "false: respond as soon as the run is committed and walk it in the background.")
40248
+ }),
39554
40249
  headers: idempotencyKeyHeader("starts one run"),
39555
40250
  responses: {
39556
40251
  201: {
@@ -39605,20 +40300,45 @@ var getWorkflowRunRoute = route({
39605
40300
  path: "/api/workflow-runs/{id}",
39606
40301
  pattern: ["api", "workflow-runs", null],
39607
40302
  summary: "Get a workflow run with steps (includes retry columns)",
40303
+ 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.",
39608
40304
  tags: ["Workflows"],
39609
40305
  params: object2({ id: string2() }),
40306
+ query: object2({
40307
+ fields: _enum2(["full", "slim"]).optional()
40308
+ }),
39610
40309
  responses: {
39611
40310
  200: {
39612
40311
  description: "Workflow run details with steps including retry info",
39613
- schema: object2({
39614
- run: WorkflowRunSchema,
39615
- steps: array2(WorkflowRunStepSchema),
39616
- parent: WorkflowRunParentSchema.optional()
39617
- })
40312
+ schema: union2([
40313
+ object2({
40314
+ run: WorkflowRunSchema,
40315
+ steps: array2(WorkflowRunStepSchema),
40316
+ parent: WorkflowRunParentSchema.optional()
40317
+ }),
40318
+ object2({
40319
+ run: WorkflowRunSummarySchema,
40320
+ steps: array2(WorkflowRunStepSlimSchema),
40321
+ parent: WorkflowRunParentSchema.optional()
40322
+ })
40323
+ ])
39618
40324
  },
39619
40325
  404: { description: "Run not found" }
39620
40326
  }
39621
40327
  });
40328
+ var getWorkflowRunTreeRoute = route({
40329
+ method: "get",
40330
+ path: "/api/workflow-runs/{id}/tree",
40331
+ pattern: ["api", "workflow-runs", null, "tree"],
40332
+ summary: "Get a workflow run and every sub-workflow run below it",
40333
+ 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.`,
40334
+ tags: ["Workflows"],
40335
+ params: object2({ id: string2() }),
40336
+ responses: {
40337
+ 200: { description: "The run tree", schema: WorkflowRunTreeSchema },
40338
+ 404: { description: "Run not found" },
40339
+ 409: { description: "Stored parent links form a cycle or nest past the depth bound" }
40340
+ }
40341
+ });
39622
40342
  var retryWorkflowRunRoute = route({
39623
40343
  method: "post",
39624
40344
  path: "/api/workflow-runs/{id}/retry",
@@ -40124,6 +40844,7 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
40124
40844
  runId = await startWorkflowExecution2(workflow, body, getExecutorRegistry2(), {
40125
40845
  triggerType: "api",
40126
40846
  requestedByUserId: await resolveHttpAuditUserId(req, myAgentId) ?? undefined,
40847
+ detach: parsed.query.wait === "false",
40127
40848
  accept: claim ? async (run) => {
40128
40849
  const response = { runId: run.runId, skipped: run.skipped };
40129
40850
  await recordAcceptedWorkflowOperation(claim, {
@@ -40171,17 +40892,39 @@ async function handleWorkflows(req, res, pathSegments, queryParams, myAgentId) {
40171
40892
  const parsed = await getWorkflowRunRoute.parse(req, res, pathSegments, queryParams);
40172
40893
  if (!parsed)
40173
40894
  return true;
40174
- const run = await getWorkflowRun2(parsed.params.id, "display");
40895
+ const slim = parsed.query.fields === "slim";
40896
+ const run = slim ? await getWorkflowRunSummary(parsed.params.id) : await getWorkflowRun2(parsed.params.id, "display");
40175
40897
  if (!run) {
40176
40898
  res.writeHead(404);
40177
40899
  res.end();
40178
40900
  return true;
40179
40901
  }
40180
- const steps = await getWorkflowRunStepsByRunId2(parsed.params.id, "display");
40902
+ const steps = slim ? await getWorkflowRunStepsSlimByRunId(parsed.params.id) : await getWorkflowRunStepsByRunId2(parsed.params.id, "display");
40181
40903
  const parent = run.parentStepId ? await getWorkflowRunParent(run.parentStepId) : null;
40182
40904
  getWorkflowRunRoute.respond(res, 200, { run, steps, ...parent ? { parent } : {} });
40183
40905
  return true;
40184
40906
  }
40907
+ if (getWorkflowRunTreeRoute.match(req.method, pathSegments)) {
40908
+ const parsed = await getWorkflowRunTreeRoute.parse(req, res, pathSegments, queryParams);
40909
+ if (!parsed)
40910
+ return true;
40911
+ let tree;
40912
+ try {
40913
+ tree = await getWorkflowRunTree(parsed.params.id);
40914
+ } catch (err) {
40915
+ if (!(err instanceof WorkflowRunTreeError))
40916
+ throw err;
40917
+ jsonError(res, err.message, 409);
40918
+ return true;
40919
+ }
40920
+ if (!tree) {
40921
+ res.writeHead(404);
40922
+ res.end();
40923
+ return true;
40924
+ }
40925
+ getWorkflowRunTreeRoute.respond(res, 200, tree);
40926
+ return true;
40927
+ }
40185
40928
  if (retryWorkflowRunRoute.match(req.method, pathSegments)) {
40186
40929
  const parsed = await retryWorkflowRunRoute.parse(req, res, pathSegments, queryParams);
40187
40930
  if (!parsed)
@@ -40346,6 +41089,7 @@ async function handleX(req, res, pathSegments) {
40346
41089
  jsonError(res, "workspace-rw scripts are not supported", 501);
40347
41090
  return true;
40348
41091
  }
41092
+ let hostValidatedArgs = false;
40349
41093
  if (script.argsJsonSchema) {
40350
41094
  try {
40351
41095
  const schema = JSON.parse(script.argsJsonSchema);
@@ -40359,6 +41103,7 @@ async function handleX(req, res, pathSegments) {
40359
41103
  });
40360
41104
  return true;
40361
41105
  }
41106
+ hostValidatedArgs = true;
40362
41107
  } catch {}
40363
41108
  }
40364
41109
  const timeoutMs = resolveTimeoutMs(req);
@@ -40370,7 +41115,9 @@ async function handleX(req, res, pathSegments) {
40370
41115
  const output = await runScriptWithRunCredential({
40371
41116
  source: script.source,
40372
41117
  args: args ?? null,
41118
+ [HOST_VALIDATED_ARGS]: hostValidatedArgs,
40373
41119
  fsMode: "none",
41120
+ executor: script.executor,
40374
41121
  agentId: endpoint.agentId,
40375
41122
  timeoutMs,
40376
41123
  egressSecrets: credentials.egressSecrets,
@@ -40536,6 +41283,7 @@ var httpServer = createHttpServer(async (req, res) => {
40536
41283
  () => handleStatus(req, res, pathSegments, queryParams),
40537
41284
  () => handleOnboarding(req, res, pathSegments, queryParams),
40538
41285
  () => handleCodexOAuthDevice(req, res, pathSegments, queryParams),
41286
+ () => handleCodexOAuthAccounts(req, res, pathSegments, queryParams),
40539
41287
  () => handleActiveSessions(req, res, pathSegments, queryParams, myAgentId),
40540
41288
  () => handlePricing(req, res, pathSegments, queryParams, myAgentId),
40541
41289
  () => handleSchedules(req, res, pathSegments, queryParams, myAgentId),
@@ -40543,6 +41291,7 @@ var httpServer = createHttpServer(async (req, res) => {
40543
41291
  () => handleWorkflowEvents(req, res, pathSegments, queryParams),
40544
41292
  () => handleApprovalRequests(req, res, pathSegments, queryParams),
40545
41293
  () => handleApps(req, res, pathSegments, queryParams, myAgentId),
41294
+ () => handlePoolKeys(req, res, pathSegments, queryParams),
40546
41295
  () => handleConfig(req, res, pathSegments, queryParams),
40547
41296
  () => handleFs(req, res, pathSegments, queryParams, myAgentId),
40548
41297
  () => handleComb(req, res, pathSegments, queryParams, myAgentId),
@@ -40619,7 +41368,7 @@ var httpServer = createHttpServer(async (req, res) => {
40619
41368
  });
40620
41369
  });
40621
41370
  var detachRealtime = attachRealtimeTransport(httpServer);
40622
- var { attachControllerTransport } = await import("./controllers-connect-xp05dj6x.js");
41371
+ var { attachControllerTransport } = await import("./controllers-connect-nep9h2xv.js");
40623
41372
  var detachControllers = attachControllerTransport(httpServer);
40624
41373
  var stopWorkerNudges = startWorkerNudgeListener();
40625
41374
  var stopRoomDeletion = realtimeBus.subscribe("room:namespace-deleted", (namespace) => {
@@ -40648,7 +41397,7 @@ async function shutdown() {
40648
41397
  sessionsProcessed: getServerSessionsProcessed()
40649
41398
  });
40650
41399
  if (hasCapability("scheduling")) {
40651
- const { stopScheduler } = await import("./index-xdaahthb.js");
41400
+ const { stopScheduler } = await import("./index-zyq8ct52.js");
40652
41401
  stopScheduler();
40653
41402
  }
40654
41403
  stopHeartbeat2();
@@ -40659,8 +41408,8 @@ async function shutdown() {
40659
41408
  await stopScriptRunSupervisor();
40660
41409
  await stopSlackApp2();
40661
41410
  await stopChatSdk();
40662
- if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
40663
- const { stopOAuthKeepalive } = await import("./keepalive-v4ta8wgg.js");
41411
+ if (!isEnvFlagEnabled("OAUTH_KEEPALIVE_DISABLE", false)) {
41412
+ const { stopOAuthKeepalive } = await import("./keepalive-xdvsamvj.js");
40664
41413
  await stopOAuthKeepalive();
40665
41414
  }
40666
41415
  stopOAuthPendingGc();
@@ -40740,21 +41489,21 @@ try {
40740
41489
  console.warn("[startup] CAPABILITIES upgrade seed failed (non-fatal):", err);
40741
41490
  }
40742
41491
  try {
40743
- const { ensurePricingSeeded } = await import("./boot-seeds-x28v3fhb.js");
41492
+ const { ensurePricingSeeded } = await import("./boot-seeds-ca84dhnn.js");
40744
41493
  ensurePricingSeeded();
40745
- const { startPricingRefreshLoop } = await import("./pricing-refresh-fsk1e1zc.js");
41494
+ const { startPricingRefreshLoop } = await import("./pricing-refresh-dw2tgb53.js");
40746
41495
  startPricingRefreshLoop();
40747
41496
  } catch (err) {
40748
41497
  console.error("[startup] Failed to seed pricing rows:", err);
40749
41498
  }
40750
41499
  try {
40751
- const { ensureModelProfilesSeeded } = await import("./boot-seeds-x28v3fhb.js");
41500
+ const { ensureModelProfilesSeeded } = await import("./boot-seeds-ca84dhnn.js");
40752
41501
  await ensureModelProfilesSeeded();
40753
41502
  } catch (err) {
40754
41503
  console.error("[startup] Failed to seed model profiles:", err);
40755
41504
  }
40756
41505
  try {
40757
- const { ensureRbacSeeded } = await import("./boot-seeds-x28v3fhb.js");
41506
+ const { ensureRbacSeeded } = await import("./boot-seeds-ca84dhnn.js");
40758
41507
  ensureRbacSeeded();
40759
41508
  } catch (err) {
40760
41509
  console.error("[startup] Failed to sync RBAC seed rows:", err);
@@ -40762,7 +41511,7 @@ try {
40762
41511
  throw err;
40763
41512
  }
40764
41513
  try {
40765
- const { runAllSeeders } = await import("./index-q7m26kvs.js");
41514
+ const { runAllSeeders } = await import("./index-jwt2bj6f.js");
40766
41515
  await runAllSeeders({ scriptEmbeddingMode: "skip" });
40767
41516
  } catch (err) {
40768
41517
  console.error("[startup] Failed to seed built-in entities:", err);
@@ -40825,41 +41574,44 @@ httpServer.listen(port, async () => {
40825
41574
  await initWorkflows2();
40826
41575
  await startScriptRunSupervisor(getMcpBaseUrl());
40827
41576
  if (hasCapability("scheduling")) {
40828
- const { startScheduler } = await import("./index-xdaahthb.js");
40829
- const { getExecutorRegistry } = await import("./index-1ef1myq2.js");
41577
+ const { startScheduler } = await import("./index-zyq8ct52.js");
41578
+ const { getExecutorRegistry } = await import("./index-z5h22pes.js");
40830
41579
  const intervalMs = Number(process.env.SCHEDULER_INTERVAL_MS) || 1e4;
40831
41580
  startScheduler(getExecutorRegistry(), intervalMs, {
40832
41581
  runId: globalState.__runId
40833
41582
  });
40834
41583
  }
40835
41584
  if (!isEnvFlagEnabled("HEARTBEAT_DISABLE", false)) {
40836
- const { startHeartbeat } = await import("./index-nmm79qgr.js");
41585
+ const { startHeartbeat } = await import("./index-y1ajx04a.js");
40837
41586
  const heartbeatMs = Number(process.env.HEARTBEAT_INTERVAL_MS) || 90000;
40838
41587
  startHeartbeat(heartbeatMs);
40839
41588
  }
40840
41589
  startPoolRouting();
40841
41590
  startRuntimeSupervisor();
40842
- if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
40843
- const { startOAuthKeepalive } = await import("./keepalive-v4ta8wgg.js");
41591
+ if (!isEnvFlagEnabled("OAUTH_KEEPALIVE_DISABLE", false)) {
41592
+ const { startOAuthKeepalive } = await import("./keepalive-xdvsamvj.js");
40844
41593
  startOAuthKeepalive();
40845
41594
  }
40846
- if (process.env.OAUTH_REFRESH_SWEEP_DISABLE !== "true") {
40847
- const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-vjnnandw.js");
41595
+ if (!isEnvFlagEnabled("OAUTH_REFRESH_SWEEP_DISABLE", false)) {
41596
+ const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-jd4r7zbs.js");
40848
41597
  startOAuthRefreshSweep();
40849
41598
  }
40850
41599
  startOAuthPendingGc();
40851
41600
  await startMemoryGc();
40852
41601
  await startDbRetention();
40853
41602
  startHumanFreeDrain();
40854
- import("./boot-reembed-w75maga2.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
41603
+ import("./boot-reembed-5h37a2c2.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
40855
41604
  console.error("[boot-reembed] startup backfill failed (non-fatal):", err);
40856
41605
  });
40857
- import("./boot-reembed-dwzfttdr.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
41606
+ import("./boot-reembed-7h78vmvv.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
40858
41607
  console.error("[boot-reembed-scripts] startup backfill failed (non-fatal):", err);
40859
41608
  });
40860
- import("./boot-scrub-sweep-e9kq43kf.js").then(({ runBootScrubSweep }) => runBootScrubSweep()).catch((err) => {
41609
+ import("./boot-scrub-sweep-8mawd4gw.js").then(({ runBootScrubSweep }) => runBootScrubSweep()).catch((err) => {
40861
41610
  console.error("[boot-scrub-sweep] startup scrub failed (non-fatal):", err);
40862
41611
  });
41612
+ import("./session-source-backfill-424wzv0r.js").then(({ runSessionSourceBackfill }) => runSessionSourceBackfill()).catch((err) => {
41613
+ console.error("[session-source-backfill] startup run failed (non-fatal):", err);
41614
+ });
40863
41615
  }).on("error", (err) => {
40864
41616
  console.error("HTTP Server Error:", err);
40865
41617
  });