@desplega.ai/agent-swarm 2.5.3 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (349) hide show
  1. package/README.md +2 -2
  2. package/dist/{acp-adapter-gr2fcyyj.js → acp-adapter-dgfakfpw.js} +9 -9
  3. package/dist/{actions-wv766ghf.js → actions-fbqma8aa.js} +21 -21
  4. package/dist/{amp-adapter-speb906t.js → amp-adapter-en0jy6hs.js} +4 -4
  5. package/dist/{app-ag29n14f.js → app-k8a5cgpp.js} +3 -3
  6. package/dist/{assistant-3x8bz3eg.js → assistant-a16433gr.js} +30 -26
  7. package/dist/{boot-reembed-jsmfrpzf.js → boot-reembed-6c1sjfnr.js} +1 -1
  8. package/dist/{boot-reembed-5b3d2eea.js → boot-reembed-f4nn561n.js} +1 -1
  9. package/dist/{boot-scrub-sweep-s73gerxy.js → boot-scrub-sweep-d4w9gajf.js} +4 -4
  10. package/dist/{boot-seeds-5zmax2wr.js → boot-seeds-9bmkspyw.js} +4 -4
  11. package/dist/{claude-adapter-hswdnm3t.js → claude-adapter-nys1kjxa.js} +9 -9
  12. package/dist/{claude-managed-adapter-cvbzj1h6.js → claude-managed-adapter-55207973.js} +3 -3
  13. package/dist/{claude-managed-setup-3k8m3hhc.js → claude-managed-setup-3cm35gey.js} +11 -4
  14. package/dist/{claude-sdk-session-fkbyk66x.js → claude-sdk-session-nw5yd8cp.js} +9313 -9260
  15. package/dist/{cli-210xd1f4.js → cli-03gg9pd1.js} +4 -4
  16. package/dist/{cli-kxpfx2xr.js → cli-0z1xjzwa.js} +2 -2
  17. package/dist/cli-1tem6ns9.js +894 -0
  18. package/dist/{cli-25j01dpj.js → cli-24j1jeeb.js} +3 -3
  19. package/dist/{cli-ta8bd7th.js → cli-2sjhpsns.js} +2 -2
  20. package/dist/{cli-p859hcc8.js → cli-39aet655.js} +2 -2
  21. package/dist/{cli-g1cw7xtt.js → cli-39rrw8yp.js} +1 -1
  22. package/dist/{cli-e2ar4bp1.js → cli-3aqd4jaa.js} +121 -47
  23. package/dist/{cli-jjznk3f7.js → cli-3fwqy71j.js} +69 -35
  24. package/dist/{cli-p9rafdrb.js → cli-3gfvmzht.js} +7 -7
  25. package/dist/{cli-03vpq45j.js → cli-3ndmpxxv.js} +2 -2
  26. package/dist/{cli-aecdcr77.js → cli-4hxrf0p4.js} +228 -74
  27. package/dist/{cli-mz9afxxf.js → cli-4rf0f5vg.js} +15 -3
  28. package/dist/{cli-qzme5949.js → cli-5rj83bam.js} +284 -202
  29. package/dist/{cli-fsdprwrg.js → cli-5sckpqcx.js} +2 -2
  30. package/dist/{cli-cz5nmdxt.js → cli-683y0b3a.js} +2 -2
  31. package/dist/{cli-3ngdk5te.js → cli-6y51ryva.js} +2 -2
  32. package/dist/{cli-n4c8e3s5.js → cli-708wdy32.js} +1 -1
  33. package/dist/{cli-pasyvjmm.js → cli-737pyqxr.js} +1 -1
  34. package/dist/{cli-gx4rm0qx.js → cli-7enjwya9.js} +1 -1
  35. package/dist/{cli-6x9ma5w5.js → cli-803188pb.js} +1 -1
  36. package/dist/{cli-avdvgcay.js → cli-9abdgn5t.js} +28 -9
  37. package/dist/{cli-99xgw26r.js → cli-a2rr0fmg.js} +1 -1
  38. package/dist/{cli-e5bxnjps.js → cli-a34pr3w1.js} +7 -7
  39. package/dist/{cli-502eqv93.js → cli-abkm71vr.js} +1 -1
  40. package/dist/{cli-mmhj8vd7.js → cli-ag2yrnt5.js} +11 -2
  41. package/dist/{cli-n45mr7zh.js → cli-aj8djyqt.js} +5 -5
  42. package/dist/{cli-1fc85mvt.js → cli-art7c1zh.js} +5 -5
  43. package/dist/{cli-40jsnrjm.js → cli-az25fn5f.js} +10 -8
  44. package/dist/{cli-9s05422w.js → cli-bqztfyve.js} +1 -1
  45. package/dist/{cli-bn0rewsy.js → cli-c081bj3b.js} +2 -2
  46. package/dist/{cli-svrj71pg.js → cli-c2habvsf.js} +12 -12
  47. package/dist/{cli-s49hpn37.js → cli-ca6banwz.js} +85 -19
  48. package/dist/{cli-hhxjnjzs.js → cli-cz37jqss.js} +12 -10
  49. package/dist/{cli-6n8axjv1.js → cli-d2dpf95n.js} +2 -2
  50. package/dist/{cli-tx00c0h6.js → cli-dqygeeh5.js} +17 -1
  51. package/dist/{cli-z21whrrg.js → cli-emhjcj2y.js} +17 -17
  52. package/dist/{cli-e8jyq7d8.js → cli-esakngh8.js} +7 -3
  53. package/dist/{cli-ha9rmwgq.js → cli-fb8m699c.js} +2 -2
  54. package/dist/{cli-35gtk1p6.js → cli-ffvsj2qw.js} +44 -13
  55. package/dist/{cli-ce0ak9ms.js → cli-g20jjwt4.js} +26 -26
  56. package/dist/{cli-kxawjrxg.js → cli-g8ka5j4j.js} +772 -194
  57. package/dist/{cli-vwn81jbs.js → cli-gf95q3bm.js} +5 -5
  58. package/dist/{cli-s53vp709.js → cli-gnsb1zxa.js} +2 -2
  59. package/dist/{cli-nwyw3zhg.js → cli-gxee0bqa.js} +1 -1
  60. package/dist/{cli-gpv60278.js → cli-hfeb68z4.js} +7 -7
  61. package/dist/{cli-0ebey9hg.js → cli-j6rktc91.js} +1 -1
  62. package/dist/{cli-ewm3pwbq.js → cli-k21gx5ht.js} +46 -23
  63. package/dist/{cli-egjggehm.js → cli-kf4jree9.js} +2 -2
  64. package/dist/{cli-dabehxhp.js → cli-kt907da6.js} +1 -1
  65. package/dist/{cli-p0rzjkya.js → cli-m5a9m0ak.js} +32 -13
  66. package/dist/{cli-fzcn3d87.js → cli-m70bajzr.js} +3 -3
  67. package/dist/{cli-w1zwctj2.js → cli-mtnj4fwa.js} +11 -5
  68. package/dist/{cli-gpsz7g88.js → cli-mvjz5an3.js} +16 -12
  69. package/dist/{cli-hcpj2xqz.js → cli-n7asmce6.js} +225 -3
  70. package/dist/{cli-y561h5a9.js → cli-nn6vx2mq.js} +5 -5
  71. package/dist/cli-nq677csy.js +140 -0
  72. package/dist/{cli-a5ebc95n.js → cli-pfk92eqz.js} +18 -15
  73. package/dist/{cli-p6zs9h4y.js → cli-rr7zx19j.js} +767 -249
  74. package/dist/{cli-qgf8emrn.js → cli-sqma6vw1.js} +10 -7
  75. package/dist/{cli-0xk505e8.js → cli-sxgtf5fw.js} +1 -1
  76. package/dist/{cli-nzfnt2gs.js → cli-tf1n0r0b.js} +1 -1
  77. package/dist/{cli-qqzmjxkf.js → cli-v49fkghp.js} +11 -6
  78. package/dist/{cli-x77gen2p.js → cli-w2656ka1.js} +7 -7
  79. package/dist/{cli-5kqnemen.js → cli-yvy48785.js} +1 -1
  80. package/dist/{cli-8s5wx3nz.js → cli-zqne1qcj.js} +44 -17
  81. package/dist/cli.js +22 -22
  82. package/dist/{codex-adapter-n8ka66vf.js → codex-adapter-d95q4qsn.js} +7 -7
  83. package/dist/{codex-hook-e2he7aca.js → codex-hook-brpnycn5.js} +1 -1
  84. package/dist/{codex-login-rn7c5gxt.js → codex-login-8cg0vhf2.js} +1 -1
  85. package/dist/{codex-session-runner-fsebts37.js → codex-session-runner-gdwd8h0c.js} +8 -8
  86. package/dist/{commands-t04rt2pc.js → commands-jqmgk54b.js} +2 -2
  87. package/dist/{controller-rgna04r2.js → controller-z3jq589f.js} +30 -4
  88. package/dist/{controllers-connect-bqm1rtft.js → controllers-connect-r2za39ef.js} +23 -23
  89. package/dist/{cursor-adapter-swr2k95y.js → cursor-adapter-4mr4jgkw.js} +2 -3
  90. package/dist/{db-a4m7haw0.js → db-ppv2tze7.js} +3 -3
  91. package/dist/{db-24ck09xy.js → db-w36wwb5g.js} +4 -2
  92. package/dist/{devin-adapter-4ycy4vrf.js → devin-adapter-byen2cxt.js} +1 -1
  93. package/dist/{dispatcher-nwf9ss0q.js → dispatcher-pv5h77vf.js} +20 -20
  94. package/dist/{docker-nfy2gc8t.js → docker-fdzyewpz.js} +4 -4
  95. package/dist/{dsh-adapter-kpdnhjst.js → dsh-adapter-d4pdpb3r.js} +2 -3
  96. package/dist/{e2b-9gkdhm3c.js → e2b-222hsajc.js} +2 -2
  97. package/dist/{e2b-cjtf8k1z.js → e2b-fn3zacvt.js} +2 -2
  98. package/dist/{easter-egg-3d-e4qv8dxj.js → easter-egg-3d-4sp4dvmc.js} +1 -1
  99. package/dist/{event-bus-3z78ep5n.js → event-bus-pghg8hqy.js} +1 -1
  100. package/dist/{execute-0xpz8950.js → execute-jev839y1.js} +1 -1
  101. package/dist/{external-channel-j1e2p34p.js → external-channel-y6nkzhnn.js} +2 -2
  102. package/dist/{grok-adapter-qtjz0whk.js → grok-adapter-t08b9ntm.js} +10 -10
  103. package/dist/handlers-eqsnmv95.js +41 -0
  104. package/dist/{heartbeat-vtesda5d.js → heartbeat-vn31xwdk.js} +23 -23
  105. package/dist/{hook-b2hhj6rd.js → hook-6d0zbvvt.js} +6 -5
  106. package/dist/{hook-8wqaszda.js → hook-cpjs8q51.js} +13 -7
  107. package/dist/{http-mxcqhhcs.js → http-9c6medda.js} +1085 -136
  108. package/dist/{index-spwxjgay.js → index-38t35h0n.js} +20 -20
  109. package/dist/{index-1r8wfpzs.js → index-g6k9tctj.js} +1 -1
  110. package/dist/{index-srg522m6.js → index-k0yt1tvq.js} +20 -20
  111. package/dist/{index-31ceyf42.js → index-pkma1yf8.js} +1 -1
  112. package/dist/{index-n1vbvta9.js → index-qhjf2htm.js} +29 -24
  113. package/dist/index-yqgbfgaj.js +43 -0
  114. package/dist/{keepalive-dsd8rtgx.js → keepalive-em0117bp.js} +4 -4
  115. package/dist/lead-23e7z59t.js +79 -0
  116. package/dist/{maintenance-jqmqwnet.js → maintenance-kbme3qy9.js} +1 -1
  117. package/dist/{oauth-refresh-sweep-q2c3bnvm.js → oauth-refresh-sweep-xysj4yse.js} +3 -3
  118. package/dist/{onboard-w4yd7s8t.js → onboard-p6q0vz97.js} +3 -3
  119. package/dist/{opencode-adapter-9tppvxar.js → opencode-adapter-esv3k9yn.js} +7 -7
  120. package/dist/{otel-impl-f36byzbd.js → otel-impl-54qhqh1z.js} +2 -2
  121. package/dist/{pi-mono-adapter-tqsge1ay.js → pi-mono-adapter-mymbwhj0.js} +41 -14
  122. package/dist/{pricing-refresh-xvak5p4v.js → pricing-refresh-yb75wv33.js} +3 -3
  123. package/dist/{rbac-roles-gfn30fb8.js → rbac-roles-1vp2mw4p.js} +2 -2
  124. package/dist/{rbac-roles-682k2mt5.js → rbac-roles-dexhc9x8.js} +1 -1
  125. package/dist/render-v2-tjay5hhf.js +16 -0
  126. package/dist/{resume-2dvq348g.js → resume-8ayf37g5.js} +11 -9
  127. package/dist/{runtime-bt5pkpm1.js → runtime-hqe5cqcd.js} +1 -1
  128. package/dist/{session-access-7f21ekq9.js → session-access-fdhp987s.js} +4 -4
  129. package/dist/session-source-backfill-qgtc86z1.js +110 -0
  130. package/dist/{setup-epffxtbk.js → setup-4rrmqcq3.js} +1 -1
  131. package/dist/{virtual-modules-mnfbh5mr.js → virtual-modules-52km00d6.js} +2 -2
  132. package/dist/{work-objects-xz1a5rqk.js → work-objects-p28fgd70.js} +23 -23
  133. package/dist/worker-e3w7vye1.js +79 -0
  134. package/dist/{x-pbpezr0s.js → x-wxrzvzx8.js} +2 -2
  135. package/openapi.json +1323 -16
  136. package/package.json +5 -5
  137. package/plugin/commands/create-pr.md +2 -2
  138. package/plugin/pi-skills/create-pr/SKILL.md +2 -2
  139. package/src/assets/source-key.ts +95 -0
  140. package/src/be/db/api-keys.ts +80 -0
  141. package/src/be/db/approvals.ts +48 -0
  142. package/src/be/db/session-labels.ts +28 -0
  143. package/src/be/db/session-moves.ts +5 -6
  144. package/src/be/db/session-tree.ts +153 -14
  145. package/src/be/db/tasks/read.ts +11 -0
  146. package/src/be/db/tasks/write.ts +21 -6
  147. package/src/be/db/workflow-idempotency.ts +183 -0
  148. package/src/be/db/workflow-runs.ts +500 -7
  149. package/src/be/db-retention.ts +61 -6
  150. package/src/be/db.ts +126 -131
  151. package/src/be/memory/providers/openai-embedding.ts +5 -1
  152. package/src/be/migrations/242_workflow_idempotency_keys.sql +40 -0
  153. package/src/be/migrations/244_api_key_validation.sql +4 -0
  154. package/src/be/onboarding.ts +4 -0
  155. package/src/be/scripts/typecheck.ts +1 -1
  156. package/src/be/sealed-json.ts +1 -0
  157. package/src/be/seed-scripts/catalog/compound-insights.inline.ts +2 -2
  158. package/src/be/seed-scripts/catalog/compound-insights.ts +2 -2
  159. package/src/be/seed-skills/bundled-files.generated.json +1 -1
  160. package/src/be/session-source-backfill.ts +163 -0
  161. package/src/be/sql-connections.ts +7 -1
  162. package/src/be/swarm-config-guard.ts +3 -0
  163. package/src/be/users.ts +9 -0
  164. package/src/comb/review-batch.ts +28 -1
  165. package/src/comb/templates.ts +7 -2
  166. package/src/commands/claude-managed-setup.ts +7 -1
  167. package/src/commands/controller.ts +33 -0
  168. package/src/commands/credential-refresh.ts +76 -1
  169. package/src/commands/credential-wait.ts +2 -2
  170. package/src/commands/provider-credentials.ts +210 -170
  171. package/src/commands/runner.ts +31 -6
  172. package/src/extensions/apply-task-create.ts +64 -11
  173. package/src/extensions/contract-types.generated.ts +1 -1
  174. package/src/extensions/contract.ts +30 -0
  175. package/src/extensions/dispatcher.ts +4 -0
  176. package/src/extensions/post-bridge.ts +8 -0
  177. package/src/hooks/context-bound-note.ts +196 -0
  178. package/src/hooks/hook.ts +12 -0
  179. package/src/http/all-routes.ts +2 -0
  180. package/src/http/api-keys.ts +53 -0
  181. package/src/http/assets.ts +15 -0
  182. package/src/http/codex-oauth-accounts.ts +191 -0
  183. package/src/http/comb.ts +15 -2
  184. package/src/http/config.ts +49 -17
  185. package/src/http/core.ts +6 -0
  186. package/src/http/fleet-benchmark.ts +5 -2
  187. package/src/http/idempotency-key.ts +117 -0
  188. package/src/http/index.ts +11 -0
  189. package/src/http/integrations.ts +5 -1
  190. package/src/http/kv.ts +8 -3
  191. package/src/http/onboarding.ts +6 -1
  192. package/src/http/pool-keys.ts +354 -0
  193. package/src/http/sessions.ts +37 -12
  194. package/src/http/stats.ts +1 -0
  195. package/src/http/status.ts +26 -12
  196. package/src/http/tasks.ts +3 -0
  197. package/src/http/used-by.ts +7 -2
  198. package/src/http/workflows.ts +207 -33
  199. package/src/integrations/chat-sdk/inbound.ts +27 -0
  200. package/src/kv-reserved-namespaces.ts +19 -0
  201. package/src/prompts/context-bound-note.ts +48 -0
  202. package/src/prompts/session-templates.ts +25 -1
  203. package/src/providers/acp-targets.ts +1 -1
  204. package/src/providers/amp-adapter.ts +30 -8
  205. package/src/providers/claude-adapter.ts +34 -5
  206. package/src/providers/claude-managed-adapter.ts +42 -9
  207. package/src/providers/claude-sdk-session.ts +10 -0
  208. package/src/providers/claude-session-events.ts +13 -0
  209. package/src/providers/codex-adapter.ts +83 -11
  210. package/src/providers/opencode-adapter.ts +18 -0
  211. package/src/providers/pi-mono-adapter.ts +35 -0
  212. package/src/runtime-providers/docker.ts +6 -2
  213. package/src/scheduler/scheduler.ts +3 -2
  214. package/src/scripts-runtime/swarm-sdk.ts +7 -1
  215. package/src/scripts-runtime/types/stdlib.d.ts +1 -1
  216. package/src/scripts-runtime/types/swarm-extension.d.ts +52 -8
  217. package/src/scripts-runtime/types/swarm-sdk.d.ts +1 -1
  218. package/src/slack/assistant.ts +7 -0
  219. package/src/slack/channel-labels.ts +74 -0
  220. package/src/slack/handlers.ts +8 -0
  221. package/src/slack/inbound-files.ts +5 -2
  222. package/src/slack/thread-buffer.ts +4 -0
  223. package/src/tasks/sibling-awareness.ts +12 -3
  224. package/src/telemetry-context.ts +5 -6
  225. package/src/telemetry-identity.ts +3 -3
  226. package/src/tests/amp-adapter.test.ts +97 -0
  227. package/src/tests/api-keys-validation.test.ts +170 -0
  228. package/src/tests/approval-requests.test.ts +10 -7
  229. package/src/tests/approval-sweeps.test.ts +12 -6
  230. package/src/tests/base-prompt.test.ts +1 -1
  231. package/src/tests/claude-hook-output.test.ts +79 -1
  232. package/src/tests/claude-managed-adapter.test.ts +321 -0
  233. package/src/tests/claude-routes-e2e.test.ts +7 -2
  234. package/src/tests/codex-adapter.test.ts +163 -0
  235. package/src/tests/codex-credential-pools.test.ts +120 -0
  236. package/src/tests/codex-gateway-route.test.ts +165 -0
  237. package/src/tests/codex-oauth-accounts.test.ts +357 -0
  238. package/src/tests/comb-review-batch.test.ts +63 -2
  239. package/src/tests/config-pool-keys.test.ts +533 -0
  240. package/src/tests/context-bound-note.test.ts +269 -0
  241. package/src/tests/credential-check.test.ts +290 -2
  242. package/src/tests/credential-refresh.test.ts +172 -1
  243. package/src/tests/db-retention.test.ts +9 -3
  244. package/src/tests/db-task-read-contract.test.ts +1 -0
  245. package/src/tests/db-task-write-contract.test.ts +1 -3
  246. package/src/tests/docs-index-footprint.test.js +3 -3
  247. package/src/tests/extensions-pre-task.test.ts +325 -0
  248. package/src/tests/fetch-resolved-env.test.ts +17 -0
  249. package/src/tests/fixtures/extensions/record-blocks/hooks.ts +10 -0
  250. package/src/tests/fixtures/extensions/record-blocks/manifest.json +7 -0
  251. package/src/tests/fixtures/extensions/record-task-create/hooks.ts +9 -0
  252. package/src/tests/fixtures/extensions/record-task-create/manifest.json +7 -0
  253. package/src/tests/fixtures/fake-amp.ts +22 -8
  254. package/src/tests/fixtures/held-template-render.ts +42 -0
  255. package/src/tests/fixtures/workflow-idempotency-trigger.child.ts +73 -0
  256. package/src/tests/fleet-benchmark.test.ts +8 -0
  257. package/src/tests/get-workflow-run-tool.test.ts +98 -0
  258. package/src/tests/integrations-http.test.ts +32 -2
  259. package/src/tests/internal-ai/complete-structured.test.ts +37 -1
  260. package/src/tests/internal-ai/credentials.test.ts +23 -0
  261. package/src/tests/kv-http.test.ts +32 -0
  262. package/src/tests/kv-tool.test.ts +25 -0
  263. package/src/tests/multi-runtime-registration.test.ts +12 -12
  264. package/src/tests/onboarding.test.ts +108 -1
  265. package/src/tests/openai-embedding-credentials.test.ts +35 -0
  266. package/src/tests/openapi-route-headers.test.ts +2 -0
  267. package/src/tests/opencode-adapter.test.ts +134 -0
  268. package/src/tests/openrouter-attribution-call-sites.test.ts +2 -2
  269. package/src/tests/org-website.test.ts +36 -0
  270. package/src/tests/pi-mono-adapter.test.ts +105 -0
  271. package/src/tests/prompt-template-session.test.ts +4 -3
  272. package/src/tests/provider-key-probes.test.ts +181 -0
  273. package/src/tests/rbac-e2e-helpers.test.ts +88 -1
  274. package/src/tests/rbac-e2e-helpers.ts +36 -11
  275. package/src/tests/runner-push-delivery.test.ts +25 -0
  276. package/src/tests/runtime-controller-liveness.test.ts +133 -0
  277. package/src/tests/runtime-providers-docker.test.ts +2 -0
  278. package/src/tests/script-connections.test.ts +5 -0
  279. package/src/tests/script-run-config-scope.test.ts +91 -3
  280. package/src/tests/script-runs-retention.test.ts +212 -0
  281. package/src/tests/sdk-allowlist.test.ts +39 -0
  282. package/src/tests/session-logs.test.ts +70 -0
  283. package/src/tests/session-source-backfill.test.ts +429 -0
  284. package/src/tests/session-source-keys.test.ts +236 -0
  285. package/src/tests/session-source-labels.test.ts +419 -0
  286. package/src/tests/sessions-detail-batch.test.ts +2 -0
  287. package/src/tests/sessions-move.test.ts +131 -0
  288. package/src/tests/sessions-tree.test.ts +336 -2
  289. package/src/tests/slack-inbound-files.test.ts +103 -23
  290. package/src/tests/status.test.ts +101 -18
  291. package/src/tests/tasks-workflow-run-filter.test.ts +146 -0
  292. package/src/tests/test-net.ts +31 -0
  293. package/src/tests/transcription.test.ts +8 -0
  294. package/src/tests/used-by-route.test.ts +11 -0
  295. package/src/tests/workflow-cascade-cancel.test.ts +1341 -0
  296. package/src/tests/workflow-foreach-supersede-retry.test.ts +488 -0
  297. package/src/tests/workflow-http-v2.test.ts +131 -0
  298. package/src/tests/workflow-idempotency.test.ts +915 -0
  299. package/src/tests/workflow-step-order.test.ts +92 -0
  300. package/src/tests/workflow-sub-workflow.test.ts +30 -0
  301. package/src/tools/get-tasks.ts +8 -0
  302. package/src/tools/kv/kv-read-auth.ts +4 -2
  303. package/src/tools/task-action.ts +1 -1
  304. package/src/tools/workflows/cancel-workflow-run.ts +1 -1
  305. package/src/tools/workflows/get-workflow-run.ts +14 -4
  306. package/src/types.ts +24 -0
  307. package/src/utils/company-profile.ts +51 -1
  308. package/src/utils/context-window.ts +8 -6
  309. package/src/utils/credentials.ts +5 -2
  310. package/src/utils/internal-ai/complete-structured.ts +5 -0
  311. package/src/utils/internal-ai/credentials.ts +4 -3
  312. package/src/utils/provider-key-probes.ts +328 -0
  313. package/src/utils/transcription.ts +4 -1
  314. package/src/workflows/approval-cancel.ts +15 -13
  315. package/src/workflows/approval-notifications.ts +5 -1
  316. package/src/workflows/checkpoint.ts +6 -3
  317. package/src/workflows/engine.ts +30 -8
  318. package/src/workflows/executors/foreach.ts +2 -2
  319. package/src/workflows/executors/sub-workflow.ts +8 -1
  320. package/src/workflows/foreach-driver.ts +10 -3
  321. package/src/workflows/foreach-join.ts +29 -6
  322. package/src/workflows/recovery.ts +6 -1
  323. package/src/workflows/resume.ts +168 -56
  324. package/src/workflows/retry-poller.ts +49 -3
  325. package/src/workflows/task-step-routing.ts +29 -7
  326. package/templates/ai-toolbox.manifest.json +8 -8
  327. package/templates/community/open-prompt-showreel/PLAYBOOK.md +5 -6
  328. package/templates/community/open-prompt-showreel/lead-prompt.md +1 -1
  329. package/templates/community/open-prompt-showreel/skills/open-prompt-showreel/SKILL.md +4 -4
  330. package/templates/skills/agent-browser/SKILL.md +4 -4
  331. package/templates/skills/agent-browser/content.md +4 -4
  332. package/templates/skills/code-quality/config.json +1 -1
  333. package/templates/skills/code-quality/content.md +2 -2
  334. package/templates/skills/delegate-work/content.md +29 -25
  335. package/templates/skills/delegate-work/files/scripts/codex-exec.sh +5 -5
  336. package/templates/skills/qa/content.md +2 -2
  337. package/templates/skills/researching/content.md +4 -0
  338. package/templates/skills/swarm-scripts/SKILL.md +1 -0
  339. package/templates/skills/swarm-scripts/content.md +1 -0
  340. package/templates/skills/work-on-task/SKILL.md +1 -1
  341. package/templates/skills/work-on-task/content.md +1 -1
  342. package/dist/cli-7421jzsw.js +0 -84
  343. package/dist/cli-e45e4m6b.js +0 -413
  344. package/dist/cli-zw88zjba.js +0 -307
  345. package/dist/handlers-19xr6dnz.js +0 -41
  346. package/dist/index-kw2mmat7.js +0 -43
  347. package/dist/lead-zyerk1x2.js +0 -79
  348. package/dist/render-v2-hgytz8nn.js +0 -12
  349. package/dist/worker-42t8emjt.js +0 -79
@@ -864,30 +864,30 @@ describe("validateProviderCredentials — error scrubbing", () => {
864
864
  expect(result.error).toContain("ANTHROPIC_API_KEY");
865
865
  });
866
866
 
867
- test("claude with CLAUDE_CODE_OAUTH_TOKEN passes via presence check (no upstream call)", async () => {
867
+ test("claude with CLAUDE_CODE_OAUTH_TOKEN checks the token against the OAuth profile", async () => {
868
868
  delete process.env.ANTHROPIC_API_KEY;
869
869
  process.env.CLAUDE_CODE_OAUTH_TOKEN = "sk-ant-oat01-fake-oauth-token";
870
- let fetchCalled = false;
871
- globalThis.fetch = (async () => {
872
- fetchCalled = true;
870
+ const urls: string[] = [];
871
+ globalThis.fetch = (async (url: string | URL | Request) => {
872
+ urls.push(String(url));
873
873
  return new Response("{}", { status: 200 });
874
874
  }) as typeof fetch;
875
875
  const result = await validateProviderCredentials("claude");
876
876
  expect(result.ok).toBe(true);
877
- expect(fetchCalled).toBe(false);
877
+ expect(urls).toEqual(["https://api.anthropic.com/api/oauth/profile"]);
878
878
  });
879
879
 
880
- test("claude prefers OAuth presence check over API-key live call when both are set", async () => {
880
+ test("claude prefers the OAuth check over the API-key check when both are set", async () => {
881
881
  process.env.ANTHROPIC_API_KEY = "sk-ant-api-fake-1234";
882
882
  process.env.CLAUDE_CODE_OAUTH_TOKEN = "sk-ant-oat01-fake-oauth";
883
- let fetchCalled = false;
884
- globalThis.fetch = (async () => {
885
- fetchCalled = true;
883
+ const urls: string[] = [];
884
+ globalThis.fetch = (async (url: string | URL | Request) => {
885
+ urls.push(String(url));
886
886
  return new Response("{}", { status: 200 });
887
887
  }) as typeof fetch;
888
888
  const result = await validateProviderCredentials("claude");
889
889
  expect(result.ok).toBe(true);
890
- expect(fetchCalled).toBe(false);
890
+ expect(urls).toEqual(["https://api.anthropic.com/api/oauth/profile"]);
891
891
  });
892
892
 
893
893
  test("codex with valid CODEX_OAUTH JSON passes via presence check (no upstream call)", async () => {
@@ -1212,10 +1212,10 @@ describe("computeHealth (Phase 2)", () => {
1212
1212
  expect((harness.providers ?? []).map((p) => p.provider)).toEqual(["claude"]);
1213
1213
  });
1214
1214
 
1215
- test("`ok` when workers are `configured` (heartbeat drift is a runtime concern, not setup health)", async () => {
1215
+ test("`ok` when workers are `configured` and the seeded lead is `idle`", async () => {
1216
1216
  // Workers in `configured` state means agents exist but haven't posted a
1217
- // heartbeat in the last 5 minutes. This is surfaced on /agents and the
1218
- // dashboard canvas — it should NOT degrade the header health dot.
1217
+ // heartbeat in the last 5 minutes. Health reads the lead's status, not
1218
+ // its heartbeat: this lead is `idle`, so it can take work.
1219
1219
  const lead = await createAgent({
1220
1220
  name: "lead-d",
1221
1221
  isLead: true,
@@ -1229,9 +1229,92 @@ describe("computeHealth (Phase 2)", () => {
1229
1229
  });
1230
1230
  const payload = await buildStatusPayload();
1231
1231
  expect(getMilestone(payload, "workers").state).toBe("configured");
1232
+ expect(payload.activity.leads_ready).toBe(1);
1233
+ expect(payload.health).toBe("ok");
1234
+ });
1235
+
1236
+ test("`ok` for an idle lead with a stale heartbeat and no worker heartbeat", async () => {
1237
+ const lead = await createAgent({
1238
+ name: "lead-idle",
1239
+ isLead: true,
1240
+ status: "idle",
1241
+ capabilities: [],
1242
+ });
1243
+ const worker = await createAgent({
1244
+ name: "worker-quiet",
1245
+ isLead: false,
1246
+ status: "idle",
1247
+ capabilities: [],
1248
+ });
1249
+ // The lead last ran a session an hour ago. The worker never heartbeated.
1250
+ const hourAgo = new Date(Date.now() - 3_600_000).toISOString();
1251
+ await getDbClient().run(`UPDATE agents SET lastActivityAt = ? WHERE id = ?`, [
1252
+ hourAgo,
1253
+ lead.id,
1254
+ ]);
1255
+ const pass = { ok: true, error: null, latency_ms: 12, testedAt: Date.now() };
1256
+ await seedCredStatus(lead.id, "claude", { ready: true, satisfiedBy: "env", liveTest: pass });
1257
+ await seedCredStatus(worker.id, "claude", { ready: true, satisfiedBy: "env", liveTest: pass });
1258
+
1259
+ const payload = await buildStatusPayload();
1260
+ expect(payload.activity.leads_online).toBe(0);
1261
+ expect(payload.activity.leads_ready).toBe(1);
1232
1262
  expect(payload.health).toBe("ok");
1233
1263
  });
1234
1264
 
1265
+ test("`degraded` when no lead row exists", async () => {
1266
+ const worker = await createAgent({
1267
+ name: "worker-alone",
1268
+ isLead: false,
1269
+ status: "idle",
1270
+ capabilities: [],
1271
+ });
1272
+ await updateAgentActivity(worker.id);
1273
+ await seedCredStatus(worker.id, "claude", {
1274
+ ready: true,
1275
+ satisfiedBy: "env",
1276
+ liveTest: { ok: true, error: null, latency_ms: 12, testedAt: Date.now() },
1277
+ });
1278
+
1279
+ const payload = await buildStatusPayload();
1280
+ expect(getMilestone(payload, "harness").state).toBe("verified");
1281
+ expect(payload.activity.leads_ready).toBe(0);
1282
+ expect(payload.health).toBe("degraded");
1283
+ });
1284
+
1285
+ test("`degraded` when the only lead is offline", async () => {
1286
+ const lead = await createAgent({
1287
+ name: "lead-gone",
1288
+ isLead: true,
1289
+ status: "offline",
1290
+ capabilities: [],
1291
+ });
1292
+ const worker = await createAgent({
1293
+ name: "worker-left",
1294
+ isLead: false,
1295
+ status: "idle",
1296
+ capabilities: [],
1297
+ });
1298
+ await updateAgentActivity(worker.id);
1299
+ const pass = { ok: true, error: null, latency_ms: 12, testedAt: Date.now() };
1300
+ await seedCredStatus(lead.id, "claude", { ready: true, satisfiedBy: "env", liveTest: pass });
1301
+ await seedCredStatus(worker.id, "claude", { ready: true, satisfiedBy: "env", liveTest: pass });
1302
+
1303
+ const payload = await buildStatusPayload();
1304
+ expect(getMilestone(payload, "harness").state).toBe("verified");
1305
+ expect(payload.activity.leads_ready).toBe(0);
1306
+ expect(payload.health).toBe("degraded");
1307
+ });
1308
+
1309
+ test("no ready lead degrades an otherwise `ok` rollup", () => {
1310
+ const synthetic: SetupMilestone[] = [
1311
+ { id: "harness", label: "Harness", state: "verified" },
1312
+ { id: "workers", label: "Workers", state: "verified" },
1313
+ ];
1314
+ expect(computeHealth(synthetic, 1)).toBe("ok");
1315
+ expect(computeHealth(synthetic, 0)).toBe("degraded");
1316
+ });
1317
+
1235
1318
  test("`ok` when harness verified and workers verified (no other integration is `configured`)", () => {
1236
1319
  // We can't reach the in-memory cache from here, so simulate by directly
1237
1320
  // checking the helper: build a synthetic milestone array.
@@ -1245,7 +1328,7 @@ describe("computeHealth (Phase 2)", () => {
1245
1328
  { id: "workers", label: "Workers", state: "verified" },
1246
1329
  { id: "first_task", label: "First task", state: "verified" },
1247
1330
  ];
1248
- expect(computeHealth(synthetic)).toBe("ok");
1331
+ expect(computeHealth(synthetic, 1)).toBe("ok");
1249
1332
  });
1250
1333
 
1251
1334
  test("`degraded` when an integration is `configured`", () => {
@@ -1258,7 +1341,7 @@ describe("computeHealth (Phase 2)", () => {
1258
1341
  { id: "workers", label: "Workers", state: "verified" },
1259
1342
  { id: "first_task", label: "First task", state: "verified" },
1260
1343
  ];
1261
- expect(computeHealth(synthetic)).toBe("degraded");
1344
+ expect(computeHealth(synthetic, 1)).toBe("degraded");
1262
1345
  });
1263
1346
 
1264
1347
  test("`ok` when a connected Slack reports `verified` next to other connected integrations", () => {
@@ -1271,7 +1354,7 @@ describe("computeHealth (Phase 2)", () => {
1271
1354
  { id: "workers", label: "Workers", state: "verified" },
1272
1355
  { id: "first_task", label: "First task", state: "verified" },
1273
1356
  ];
1274
- expect(computeHealth(synthetic)).toBe("ok");
1357
+ expect(computeHealth(synthetic, 1)).toBe("ok");
1275
1358
  });
1276
1359
 
1277
1360
  test("integrations in `unverified` alone do NOT degrade health", () => {
@@ -1286,7 +1369,7 @@ describe("computeHealth (Phase 2)", () => {
1286
1369
  { id: "workers", label: "Workers", state: "verified" },
1287
1370
  { id: "first_task", label: "First task", state: "unverified" },
1288
1371
  ];
1289
- expect(computeHealth(synthetic)).toBe("ok");
1372
+ expect(computeHealth(synthetic, 1)).toBe("ok");
1290
1373
  });
1291
1374
 
1292
1375
  test("an unverified embedding key never blocks boot or degrades health", () => {
@@ -1295,7 +1378,7 @@ describe("computeHealth (Phase 2)", () => {
1295
1378
  { id: "embeddings", label: "Memory search", state: "unverified" },
1296
1379
  { id: "workers", label: "Workers", state: "verified" },
1297
1380
  ];
1298
- expect(computeHealth(synthetic)).toBe("ok");
1381
+ expect(computeHealth(synthetic, 1)).toBe("ok");
1299
1382
  });
1300
1383
  });
1301
1384
 
@@ -0,0 +1,146 @@
1
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
+ import { unlink } from "node:fs/promises";
3
+ import {
4
+ createServer as createHttpServer,
5
+ type IncomingMessage,
6
+ type Server,
7
+ type ServerResponse,
8
+ } from "node:http";
9
+ import {
10
+ closeDb,
11
+ createAgent,
12
+ createTaskExtended,
13
+ createWorkflow,
14
+ createWorkflowRun,
15
+ getAllTasks,
16
+ getTasksCount,
17
+ initDb,
18
+ } from "../be/db";
19
+ import { handleCore } from "../http/core";
20
+ import { handleTasks } from "../http/tasks";
21
+ import { getPathSegments, parseQueryParams } from "../http/utils";
22
+ import { listenOnFreePort } from "./test-net";
23
+
24
+ const TEST_DB_PATH = "./test-tasks-workflow-run-filter.sqlite";
25
+ const API_KEY = "test-tasks-workflow-run-filter";
26
+
27
+ async function removeDbFiles(path: string): Promise<void> {
28
+ for (const suffix of ["", "-wal", "-shm"]) {
29
+ try {
30
+ await unlink(path + suffix);
31
+ } catch (error) {
32
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
33
+ }
34
+ }
35
+ }
36
+
37
+ function createTestServer(apiKey: string): Server {
38
+ return createHttpServer(async (req: IncomingMessage, res: ServerResponse) => {
39
+ const myAgentId = req.headers["x-agent-id"] as string | undefined;
40
+ const handled = await handleCore(req, res, myAgentId, apiKey);
41
+ if (handled) return;
42
+ const pathSegments = getPathSegments(req.url || "");
43
+ const queryParams = parseQueryParams(req.url || "");
44
+ const ok = await handleTasks(req, res, pathSegments, queryParams, myAgentId);
45
+ if (!ok) {
46
+ res.writeHead(404);
47
+ res.end("Not Found");
48
+ }
49
+ });
50
+ }
51
+
52
+ describe("workflowRunId task filter", () => {
53
+ let server: Server;
54
+ let port: number;
55
+ let agentId: string;
56
+ let runAId: string;
57
+ let runATaskIds: string[];
58
+ let runBTaskId: string;
59
+ let noRunTaskId: string;
60
+
61
+ beforeAll(async () => {
62
+ await removeDbFiles(TEST_DB_PATH);
63
+ initDb(TEST_DB_PATH);
64
+ agentId = (
65
+ await createAgent({ name: "workflow-run-filter-agent", isLead: false, status: "idle" })
66
+ ).id;
67
+ const workflow = await createWorkflow({
68
+ name: `workflow-run-filter-${crypto.randomUUID()}`,
69
+ definition: { nodes: [] },
70
+ });
71
+ const runA = await createWorkflowRun({ id: crypto.randomUUID(), workflowId: workflow.id });
72
+ const runB = await createWorkflowRun({ id: crypto.randomUUID(), workflowId: workflow.id });
73
+ runAId = runA.id;
74
+ runATaskIds = [
75
+ (
76
+ await createTaskExtended("run A — step 1", {
77
+ agentId,
78
+ source: "workflow",
79
+ workflowRunId: runA.id,
80
+ })
81
+ ).id,
82
+ (
83
+ await createTaskExtended("run A — step 2", {
84
+ agentId,
85
+ source: "workflow",
86
+ workflowRunId: runA.id,
87
+ })
88
+ ).id,
89
+ ];
90
+ runBTaskId = (
91
+ await createTaskExtended("run B — step 1", {
92
+ agentId,
93
+ source: "workflow",
94
+ workflowRunId: runB.id,
95
+ })
96
+ ).id;
97
+ noRunTaskId = (await createTaskExtended("task outside any run", { agentId })).id;
98
+
99
+ server = createTestServer(API_KEY);
100
+ port = await listenOnFreePort(server);
101
+ });
102
+
103
+ afterAll(async () => {
104
+ await new Promise<void>((resolve) => server.close(() => resolve()));
105
+ closeDb();
106
+ await removeDbFiles(TEST_DB_PATH);
107
+ });
108
+
109
+ function listTasks(query: string): Promise<Response> {
110
+ return fetch(`http://localhost:${port}/api/tasks?${query}`, {
111
+ headers: { Authorization: `Bearer ${API_KEY}`, "X-Agent-ID": agentId },
112
+ });
113
+ }
114
+
115
+ test("getAllTasks and getTasksCount return only the run's tasks", async () => {
116
+ const tasks = await getAllTasks({ workflowRunId: runAId });
117
+ expect(tasks.map((t) => t.id).sort()).toEqual([...runATaskIds].sort());
118
+ expect(await getTasksCount({ workflowRunId: runAId })).toBe(2);
119
+ });
120
+
121
+ for (const fields of ["slim", "full", "timeline"] as const) {
122
+ test(`GET /api/tasks?workflowRunId with fields=${fields} returns only the run's tasks`, async () => {
123
+ const res = await listTasks(`workflowRunId=${runAId}&fields=${fields}&includeTotal=true`);
124
+ expect(res.status).toBe(200);
125
+ const body = (await res.json()) as { tasks: { id: string }[]; total: number };
126
+ const ids = body.tasks.map((t) => t.id);
127
+ expect(ids.sort()).toEqual([...runATaskIds].sort());
128
+ expect(ids).not.toContain(runBTaskId);
129
+ expect(ids).not.toContain(noRunTaskId);
130
+ expect(body.total).toBe(2);
131
+ });
132
+ }
133
+
134
+ test("an unknown run returns an empty list and zero total", async () => {
135
+ const res = await listTasks(`workflowRunId=${crypto.randomUUID()}&includeTotal=true`);
136
+ expect(res.status).toBe(200);
137
+ const body = (await res.json()) as { tasks: unknown[]; total: number };
138
+ expect(body.tasks).toEqual([]);
139
+ expect(body.total).toBe(0);
140
+ });
141
+
142
+ test("a non-UUID workflowRunId is rejected", async () => {
143
+ const res = await listTasks("workflowRunId=not-a-uuid");
144
+ expect(res.status).toBe(400);
145
+ });
146
+ });
@@ -6,6 +6,8 @@
6
6
  * Always bind an OS-assigned port: `listenOnFreePort(server)` for an
7
7
  * in-process `node:http` server, `getFreePort()` for a port that must be known
8
8
  * before the server exists (spawned `src/http.ts` children take it via `PORT`).
9
+ * A spawned child can lose that port before it binds; `startOnFreePort` retries
10
+ * it on a new one.
9
11
  */
10
12
  import { createServer, type Server } from "node:net";
11
13
 
@@ -27,6 +29,35 @@ export function getFreePort(): Promise<number> {
27
29
  });
28
30
  }
29
31
 
32
+ /** Matches the boot error a server prints when its port is already bound. */
33
+ export const PORT_IN_USE_LOG = /EADDRINUSE|Is port \d+ in use\?/;
34
+
35
+ /** Thrown by a `startOnFreePort` callback when the server lost its port to another process. */
36
+ export class PortInUseError extends Error {}
37
+
38
+ /**
39
+ * Start a server on a getFreePort() port, and on a new port when `start`
40
+ * throws PortInUseError. getFreePort() releases the port before the spawned
41
+ * server binds it, and under `bun test --parallel` another process can take
42
+ * it during the server's boot. Any other error, or the last attempt's
43
+ * PortInUseError, propagates unchanged.
44
+ */
45
+ export async function startOnFreePort<T>(
46
+ start: (port: number) => Promise<T>,
47
+ opts: { attempts?: number; getPort?: () => Promise<number> } = {},
48
+ ): Promise<T> {
49
+ const attempts = opts.attempts ?? 3;
50
+ const getPort = opts.getPort ?? getFreePort;
51
+ for (let attempt = 1; ; attempt++) {
52
+ const port = await getPort();
53
+ try {
54
+ return await start(port);
55
+ } catch (error) {
56
+ if (!(error instanceof PortInUseError) || attempt >= attempts) throw error;
57
+ }
58
+ }
59
+ }
60
+
30
61
  /**
31
62
  * Bind `server` to port 0 and return the assigned port. Binds all interfaces
32
63
  * unless `host` is given, matching a bare `server.listen(0)`, so
@@ -207,6 +207,14 @@ describe("provider key fallback", () => {
207
207
  });
208
208
  });
209
209
 
210
+ test("a pooled OPENAI_API_KEY sends one member", async () => {
211
+ process.env.OPENAI_API_KEY = `${OPENAI_FAKE}-a,${OPENAI_FAKE}-b`;
212
+ const apiKey = resolveTranscriptionConfig()?.apiKey;
213
+ expect([`${OPENAI_FAKE}-a`, `${OPENAI_FAKE}-b`]).toContain(apiKey);
214
+ await transcribeAudio(audio);
215
+ expect(captured[0]?.authorization).toMatch(new RegExp(`^Bearer ${OPENAI_FAKE}-[ab]$`));
216
+ });
217
+
210
218
  test("GROQ_API_KEY alone uses Groq's OpenAI-compatible endpoint and whisper model", async () => {
211
219
  process.env.GROQ_API_KEY = GROQ_FAKE;
212
220
  expect(resolveTranscriptionConfig()).toMatchObject({
@@ -183,6 +183,17 @@ describe("POST /api/used-by", () => {
183
183
  expect(proxied[1]?.body).not.toHaveProperty("quote");
184
184
  });
185
185
 
186
+ test("a job function the catalog does not list yet is stored but not sent", async () => {
187
+ const grant = await post(
188
+ { granted: true, contactEmail: "admin@acme.com", contactFunction: "marketing" },
189
+ OPERATOR,
190
+ );
191
+ expect(grant.statusCode).toBe(200);
192
+ expect(proxied[0]?.body).toMatchObject({ granted: true, contact_email: "admin@acme.com" });
193
+ expect(proxied[0]?.body).not.toHaveProperty("contact_function");
194
+ expect(await configValue("SWARM_USED_BY_CONTACT_FUNCTION")).toBe("marketing");
195
+ });
196
+
186
197
  test("a grant requires valid contact details and a quote of at most 280 characters", async () => {
187
198
  for (const details of [
188
199
  {},