@desplega.ai/agent-swarm 1.172.0 → 2.0.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 (525) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-fpecx1g1.js → acp-adapter-sj2g0m84.js} +18 -17
  3. package/dist/{actions-pw87a1a8.js → actions-fegk44gr.js} +65 -35
  4. package/dist/{amp-adapter-8jem2bc0.js → amp-adapter-ad8ft89x.js} +8 -7
  5. package/dist/{anthropic-messages-8ee2f22q.js → anthropic-messages-r6czkjv1.js} +7 -7
  6. package/dist/{app-wmf0m843.js → app-kfvgbvzy.js} +19 -13
  7. package/dist/{assistant-emp1e108.js → assistant-z7zdy9ja.js} +65 -38
  8. package/dist/{boot-reembed-1de4f4aj.js → boot-reembed-5c2z0mbe.js} +11 -9
  9. package/dist/{boot-reembed-4ymn9atn.js → boot-reembed-j8xa181e.js} +11 -9
  10. package/dist/{boot-scrub-sweep-adhk1s8c.js → boot-scrub-sweep-hnkn3rgt.js} +12 -10
  11. package/dist/{boot-seeds-8q637aew.js → boot-seeds-kwjq4d2z.js} +15 -13
  12. package/dist/{claude-adapter-t26cv8a4.js → claude-adapter-9vmvpvgd.js} +20 -19
  13. package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-k9qae05j.js} +7 -5
  14. package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-q54zx5q2.js} +6 -4
  15. package/dist/{claude-sdk-session-gsfsh662.js → claude-sdk-session-9jye6cxr.js} +12698 -11995
  16. package/dist/{cli-k46r9hmk.js → cli-03gedhng.js} +16 -14
  17. package/dist/{cli-kb4ehzx5.js → cli-1e4b6bzh.js} +7 -7
  18. package/dist/{cli-d603qf86.js → cli-29jc5q7w.js} +10 -8
  19. package/dist/cli-2m1ktfzz.js +17795 -0
  20. package/dist/{cli-8vs9trd4.js → cli-3dj8k4vy.js} +1 -1
  21. package/dist/{cli-zxm9p3x4.js → cli-3fbmmawm.js} +5 -5
  22. package/dist/{cli-gmdajfw5.js → cli-4jxm2qtz.js} +4987 -1708
  23. package/dist/{cli-tadfgd0t.js → cli-5hkm7whv.js} +33 -4
  24. package/dist/{cli-6jb2rf77.js → cli-5t4f29ez.js} +3 -3
  25. package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
  26. package/dist/cli-6cvfxs8r.js +47 -0
  27. package/dist/{cli-pj6x9qce.js → cli-6jyj59nb.js} +2 -2
  28. package/dist/{cli-388egyf6.js → cli-6razj6t4.js} +2 -2
  29. package/dist/{cli-qsztpfry.js → cli-74ahz61x.js} +2 -2
  30. package/dist/{cli-4nz8p1p5.js → cli-7x0g4sn1.js} +15474 -16082
  31. package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
  32. package/dist/{cli-81r1wjyv.js → cli-9nfx44eh.js} +1 -1
  33. package/dist/cli-9traj3dn.js +638 -0
  34. package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
  35. package/dist/{cli-bf7485pm.js → cli-apx87jne.js} +2 -2
  36. package/dist/{cli-ztrv9y21.js → cli-bzszjf2p.js} +3689 -1081
  37. package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
  38. package/dist/{cli-hsem16hb.js → cli-cgtksawx.js} +7 -4
  39. package/dist/{cli-db3m6zdt.js → cli-d2qr7aj4.js} +1 -1
  40. package/dist/{cli-1hgat6pa.js → cli-d5f9ed5c.js} +5 -5
  41. package/dist/cli-e3g5mbkz.js +776 -0
  42. package/dist/{cli-7jykv7ef.js → cli-e6mpjhed.js} +1 -1
  43. package/dist/{cli-j6kpj9az.js → cli-ee9gtz70.js} +1553 -68
  44. package/dist/{cli-e0a9sk00.js → cli-eejsgvm4.js} +4 -4
  45. package/dist/{cli-tgpfnm6r.js → cli-ef1hg1wv.js} +518 -59
  46. package/dist/cli-f527ce74.js +781 -0
  47. package/dist/{cli-ppy4nnnh.js → cli-f7kr7svz.js} +2 -2
  48. package/dist/cli-hjwmhcg1.js +10622 -0
  49. package/dist/{cli-2bw3w47j.js → cli-hnhtk6cj.js} +1 -1
  50. package/dist/{cli-ywm1azg9.js → cli-hnmhtzvh.js} +6 -4
  51. package/dist/{cli-4fnb6884.js → cli-hvqbtna4.js} +7 -1259
  52. package/dist/{cli-pstq9888.js → cli-j0pfptdp.js} +220 -103
  53. package/dist/cli-jta2eyzc.js +619 -0
  54. package/dist/{cli-esnpehf5.js → cli-k382tshb.js} +12 -13
  55. package/dist/cli-k3dp5tpf.js +263 -0
  56. package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
  57. package/dist/cli-kceah1eh.js +92 -0
  58. package/dist/{cli-prrt9fa0.js → cli-ke896fcf.js} +10 -10
  59. package/dist/{cli-nv4zd0b9.js → cli-kt6zqg0e.js} +6 -6
  60. package/dist/{cli-g6t9texm.js → cli-m50t4309.js} +5 -18
  61. package/dist/cli-n2wq4j7m.js +6985 -0
  62. package/dist/{cli-c2pq2rjb.js → cli-n3hzg89b.js} +46 -15
  63. package/dist/{cli-tmhsxhb8.js → cli-n5vwg842.js} +23 -6
  64. package/dist/{cli-5rv1j9ga.js → cli-ne236afy.js} +53 -7
  65. package/dist/cli-p0sg24zp.js +16 -0
  66. package/dist/{cli-d161g69q.js → cli-p1x85d2t.js} +50 -2
  67. package/dist/{cli-7pz3b7x5.js → cli-przpmdgr.js} +25 -0
  68. package/dist/{cli-g4f5pj26.js → cli-q0ke1yww.js} +111 -25
  69. package/dist/{cli-e3pmyt39.js → cli-q50942rs.js} +1 -1
  70. package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
  71. package/dist/{cli-gj81e47t.js → cli-r2pnvj8g.js} +2 -2
  72. package/dist/{cli-r8smj8b8.js → cli-r62a35ea.js} +19 -3
  73. package/dist/{cli-cd0hv9nh.js → cli-ra0xzggj.js} +2 -2
  74. package/dist/cli-rhs9pz33.js +294 -0
  75. package/dist/{cli-nyhb1r6x.js → cli-s2sp957d.js} +52 -29
  76. package/dist/{cli-1x7da0de.js → cli-s4setq91.js} +8 -8
  77. package/dist/{cli-xczpdp9e.js → cli-se8w6wny.js} +6 -6
  78. package/dist/cli-skxvvpap.js +10140 -0
  79. package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
  80. package/dist/{cli-0p3enk35.js → cli-tqaazemc.js} +9 -1
  81. package/dist/{cli-cf69s3ew.js → cli-tr4sxp68.js} +3 -3
  82. package/dist/{cli-8hzfb6xz.js → cli-tsde1hdr.js} +15 -15
  83. package/dist/{cli-cceskcvt.js → cli-txqb9s38.js} +8 -8
  84. package/dist/{cli-aspcaef3.js → cli-v1yb0rqb.js} +6 -6
  85. package/dist/{cli-j1pmc07z.js → cli-vatyhshy.js} +268 -40
  86. package/dist/{cli-04emfe2q.js → cli-vdach5a9.js} +5 -5
  87. package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
  88. package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
  89. package/dist/{cli-hwwvy36w.js → cli-wayw93nt.js} +3 -3
  90. package/dist/cli-wmgrkscj.js +23254 -0
  91. package/dist/{cli-gp1rtyvk.js → cli-z5jjpaxw.js} +29 -6
  92. package/dist/{cli-451ks6aw.js → cli-zkpks3r3.js} +1 -1
  93. package/dist/cli.js +32 -48
  94. package/dist/{codex-adapter-m4tgdysy.js → codex-adapter-y81sssk0.js} +16 -15
  95. package/dist/{codex-login-841kv5fk.js → codex-login-f2rcfpp9.js} +3 -2
  96. package/dist/{codex-session-runner-ymwzm6ea.js → codex-session-runner-8vx4j6a9.js} +16 -15
  97. package/dist/{commands-n0hshcvs.js → commands-kcpvpcrr.js} +21 -10
  98. package/dist/{controller-hq5ggpcp.js → controller-ywrmt6yd.js} +5 -4
  99. package/dist/{controllers-connect-y07cqcvy.js → controllers-connect-kwpvj3rf.js} +45 -38
  100. package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-cehv1qns.js} +7 -6
  101. package/dist/{db-hkqvrdcb.js → db-k8ankj20.js} +13 -11
  102. package/dist/{db-4w7tmt1g.js → db-ww5d7jq3.js} +29 -9
  103. package/dist/{devin-adapter-xgtj680j.js → devin-adapter-x1022qb1.js} +3 -2
  104. package/dist/{dispatcher-5sd69y14.js → dispatcher-e8gq5m68.js} +41 -34
  105. package/dist/{docker-f503k9p0.js → docker-ff6y1190.js} +3 -2
  106. package/dist/{dsh-adapter-2h8m4cab.js → dsh-adapter-3epjm3af.js} +7 -6
  107. package/dist/{e2b-66xra4az.js → e2b-8ygwhg0f.js} +4 -3
  108. package/dist/{e2b-xwhyj8cw.js → e2b-swhnpw3n.js} +4 -3
  109. package/dist/{event-bus-vjtv82gm.js → event-bus-6axnngdj.js} +3 -2
  110. package/dist/external-channel-h3359cwn.js +52 -0
  111. package/dist/{google-generative-ai-7pavrbv7.js → google-generative-ai-g8db7x0f.js} +5 -3
  112. package/dist/{google-vertex-3f1jk41f.js → google-vertex-r2692q0r.js} +5 -3
  113. package/dist/{grok-adapter-8m9yqzbq.js → grok-adapter-0d4x7gkx.js} +19 -18
  114. package/dist/{handlers-s20xr10r.js → handlers-an1gzv21.js} +44 -37
  115. package/dist/{heartbeat-3k31q4g2.js → heartbeat-6dakeb61.js} +46 -39
  116. package/dist/{hook-gdn6a2fn.js → hook-6v6cv6d5.js} +12 -24
  117. package/dist/{hook-ygwerrdh.js → hook-sa5xye4y.js} +13 -12
  118. package/dist/{http-jdteeg81.js → http-r7f3eky0.js} +1598 -279
  119. package/dist/index-52j1aja4.js +3465 -0
  120. package/dist/{index-e0snym4t.js → index-7ep4gzdk.js} +41 -34
  121. package/dist/index-9gw58n4k.js +193 -0
  122. package/dist/index-9j87mcm8.js +56305 -0
  123. package/dist/index-bsmcresk.js +79424 -0
  124. package/dist/index-mh85qhec.js +475 -0
  125. package/dist/{index-vm3bm9t7.js → index-rmpw9a8q.js} +41 -34
  126. package/dist/{index-6ksewd5y.js → index-s2wxgzr0.js} +1015 -732
  127. package/dist/{index-tsszt7g9.js → index-v1v6n7hg.js} +46 -39
  128. package/dist/index-we27kd31.js +12810 -0
  129. package/dist/{index-ffqzqgwb.js → index-zk96aq1k.js} +11 -9
  130. package/dist/{keepalive-jekc896t.js → keepalive-be9vwy5h.js} +13 -11
  131. package/dist/{lead-4k9s9szx.js → lead-0861cwrf.js} +64 -57
  132. package/dist/{maintenance-shazch4n.js → maintenance-mzzgc8bn.js} +11 -9
  133. package/dist/node-c9we95xf.js +1 -1
  134. package/dist/{node-fkajaq96.js → node-mn1zs7an.js} +2 -1
  135. package/dist/{oauth-refresh-sweep-5gb36kn8.js → oauth-refresh-sweep-cpdnfwdj.js} +12 -10
  136. package/dist/{onboard-ydrbnvww.js → onboard-fh8qs4r3.js} +11 -3
  137. package/dist/{opencode-adapter-5zh0he20.js → opencode-adapter-nm42wwj8.js} +19 -14
  138. package/dist/{otel-impl-6pf5cv86.js → otel-impl-x6c1c9g4.js} +248 -869
  139. package/dist/{pi-mono-adapter-ef9wwx9m.js → pi-mono-adapter-9n2ya240.js} +245 -107
  140. package/dist/{pricing-refresh-s52nsa5q.js → pricing-refresh-qb0rv0ap.js} +13 -11
  141. package/dist/{rbac-roles-aq3msh4e.js → rbac-roles-1gzdwbh1.js} +12 -10
  142. package/dist/{rbac-roles-q5gb5e8v.js → rbac-roles-3mraey52.js} +13 -11
  143. package/dist/{render-v2-pd1rg54q.js → render-v2-agpa45zz.js} +19 -13
  144. package/dist/{resume-gw4a2c6v.js → resume-x0ydy9s9.js} +27 -21
  145. package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
  146. package/dist/{setup-jda1ksdh.js → setup-as9ga0d6.js} +2 -2
  147. package/dist/{virtual-modules-b3ga2m65.js → virtual-modules-9gkxqrap.js} +7 -6
  148. package/dist/{work-objects-tb7ycye8.js → work-objects-y5g1y7ev.js} +49 -37
  149. package/dist/{worker-njjccz5d.js → worker-860c3e38.js} +64 -57
  150. package/dist/{x-qfmygqqv.js → x-m477fr0h.js} +3 -2
  151. package/openapi.json +951 -356
  152. package/package.json +12 -13
  153. package/src/apps/catalog.generated.json +1309 -53
  154. package/src/apps/page-validator.ts +93 -31
  155. package/src/azure-devops/api.ts +94 -18
  156. package/src/azure-devops/auth.ts +32 -0
  157. package/src/azure-devops/boards-sync.ts +708 -0
  158. package/src/azure-devops/handlers.ts +52 -8
  159. package/src/azure-devops/html.ts +26 -0
  160. package/src/azure-devops/index.ts +15 -0
  161. package/src/azure-devops/templates.ts +86 -0
  162. package/src/azure-devops/types.ts +65 -1
  163. package/src/be/config-refs.ts +60 -0
  164. package/src/be/db/page-versions.ts +15 -0
  165. package/src/be/db/runtime.ts +35 -8
  166. package/src/be/db/skill-name-resolution.ts +36 -0
  167. package/src/be/db/tasks/read.ts +230 -0
  168. package/src/be/db/tasks/write.ts +7 -0
  169. package/src/be/db.ts +74 -13
  170. package/src/be/migrations/213_script_connections_sql.sql +79 -0
  171. package/src/be/migrations/215_swarm_config_export_to_env.sql +34 -0
  172. package/src/be/migrations/216_task_resolved_effort.sql +5 -0
  173. package/src/be/migrations/217_chat_sdk_state.sql +104 -0
  174. package/src/be/model-catalog-store.ts +5 -1
  175. package/src/be/model-tier-resolution.ts +12 -1
  176. package/src/be/model-validation.ts +5 -2
  177. package/src/be/models-catalog.ts +26 -1
  178. package/src/be/modelsdev-cache.json +198 -63
  179. package/src/be/modelsdev-cache.ts +9 -1
  180. package/src/be/script-connections.ts +47 -8
  181. package/src/be/script-credential-broker.ts +39 -2
  182. package/src/be/scripts/run-saved.ts +1 -0
  183. package/src/be/scripts/typecheck.ts +10 -8
  184. package/src/be/seed/runner.ts +13 -1
  185. package/src/be/seed/state-db.ts +5 -0
  186. package/src/be/seed/types.ts +6 -0
  187. package/src/be/seed-pricing.ts +19 -2
  188. package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
  189. package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
  190. package/src/be/seed-skills/bundled-files.generated.json +10 -18
  191. package/src/be/seed-skills/index.ts +107 -3
  192. package/src/be/sql-connections.ts +118 -0
  193. package/src/be/swarm-config-guard.ts +53 -0
  194. package/src/cli.tsx +0 -16
  195. package/src/commands/onboard/non-interactive.ts +4 -2
  196. package/src/commands/profile-sync.ts +5 -3
  197. package/src/commands/provider-credentials.ts +52 -6
  198. package/src/commands/runner.ts +196 -56
  199. package/src/e2b/env.ts +5 -0
  200. package/src/extensions/contract-types.generated.ts +1 -1
  201. package/src/extensions/contract.ts +45 -0
  202. package/src/extensions/dispatcher.ts +7 -0
  203. package/src/extensions/post-bridge.ts +40 -0
  204. package/src/github/handlers.ts +11 -4
  205. package/src/heartbeat/templates.ts +8 -5
  206. package/src/hooks/hook.ts +0 -26
  207. package/src/http/all-routes.ts +0 -1
  208. package/src/http/config.ts +36 -17
  209. package/src/http/core.ts +4 -0
  210. package/src/http/index.ts +14 -2
  211. package/src/http/integrations.ts +88 -1
  212. package/src/http/mcp-oauth.ts +6 -13
  213. package/src/http/mcp.ts +15 -5
  214. package/src/http/page-proxy.ts +2 -4
  215. package/src/http/pages-public.ts +6 -5
  216. package/src/http/pages.ts +5 -14
  217. package/src/http/poll.ts +28 -68
  218. package/src/http/requested-by.ts +54 -0
  219. package/src/http/route-def.ts +7 -6
  220. package/src/http/script-connection-proxy.ts +51 -4
  221. package/src/http/script-connections.ts +5 -2
  222. package/src/http/scripts.ts +1 -0
  223. package/src/http/session-cost-recompute.ts +12 -2
  224. package/src/http/session-data.ts +4 -0
  225. package/src/http/stats.ts +1 -30
  226. package/src/http/tasks.ts +61 -5
  227. package/src/http/utils.ts +14 -0
  228. package/src/http/webhooks.ts +183 -2
  229. package/src/http/x.ts +1 -0
  230. package/src/integrations/chat-sdk/adapters.ts +129 -0
  231. package/src/integrations/chat-sdk/attachments.ts +232 -0
  232. package/src/integrations/chat-sdk/background.ts +36 -0
  233. package/src/integrations/chat-sdk/commands.ts +194 -0
  234. package/src/integrations/chat-sdk/config.ts +198 -0
  235. package/src/integrations/chat-sdk/discord-api.ts +63 -0
  236. package/src/integrations/chat-sdk/discord-gateway.ts +185 -0
  237. package/src/integrations/chat-sdk/handlers.ts +28 -0
  238. package/src/integrations/chat-sdk/inbound.ts +426 -0
  239. package/src/integrations/chat-sdk/limits.ts +48 -0
  240. package/src/integrations/chat-sdk/logger.ts +81 -0
  241. package/src/integrations/chat-sdk/outbound.ts +123 -0
  242. package/src/integrations/chat-sdk/relay.ts +172 -0
  243. package/src/integrations/chat-sdk/router.ts +169 -0
  244. package/src/integrations/chat-sdk/runtime.ts +351 -0
  245. package/src/integrations/chat-sdk/schema.ts +245 -0
  246. package/src/integrations/chat-sdk/state.ts +243 -0
  247. package/src/integrations/chat-sdk/status.ts +244 -0
  248. package/src/integrations/chat-sdk/steering.ts +58 -0
  249. package/src/integrations/chat-sdk/teams-origin.ts +77 -0
  250. package/src/integrations/chat-sdk/telegram-api.ts +56 -0
  251. package/src/integrations/chat-sdk/templates.ts +16 -0
  252. package/src/integrations/chat-sdk/test-hooks.ts +37 -0
  253. package/src/integrations/chat-sdk/thread-buffer.ts +100 -0
  254. package/src/integrations/chat-sdk/typing.ts +65 -0
  255. package/src/jira/adf.ts +3 -1
  256. package/src/kv-reserved-namespaces.ts +2 -0
  257. package/src/oauth/mcp-wrapper.ts +10 -6
  258. package/src/otel-impl.ts +2 -1
  259. package/src/pages/version.ts +4 -5
  260. package/src/prompts/base-prompt.ts +111 -45
  261. package/src/providers/acp-target-catalog.ts +6 -0
  262. package/src/providers/acp-targets.ts +56 -3
  263. package/src/providers/amp-adapter.ts +1 -1
  264. package/src/providers/claude-adapter.ts +27 -2
  265. package/src/providers/claude-flag-settings.ts +133 -0
  266. package/src/providers/claude-managed-adapter.ts +1 -1
  267. package/src/providers/claude-sdk-session.ts +7 -0
  268. package/src/providers/claude-session-events.ts +6 -1
  269. package/src/providers/dsh-adapter.ts +1 -1
  270. package/src/providers/opencode-adapter.ts +268 -37
  271. package/src/providers/opencode-billing.ts +86 -0
  272. package/src/providers/opencode-swarm-plugin.ts +51 -0
  273. package/src/providers/pi-mono-adapter.ts +398 -153
  274. package/src/providers/pricing-sources.md +37 -3
  275. package/src/providers/reasoning-effort.ts +27 -0
  276. package/src/providers/types.ts +11 -2
  277. package/src/rbac/legacy-policy.ts +8 -2
  278. package/src/rbac/permissions.ts +21 -0
  279. package/src/scheduler/scheduler.ts +4 -2
  280. package/src/scripts-runtime/api-client.ts +15 -1
  281. package/src/scripts-runtime/api-types.ts +9 -1
  282. package/src/scripts-runtime/ctx.ts +1 -1
  283. package/src/scripts-runtime/loader.ts +19 -7
  284. package/src/scripts-runtime/mcp-client.ts +30 -19
  285. package/src/scripts-runtime/sdk-allowlist.ts +8 -6
  286. package/src/scripts-runtime/swarm-sdk.ts +0 -11
  287. package/src/scripts-runtime/types/stdlib.d.ts +27 -15
  288. package/src/scripts-runtime/types/swarm-extension.d.ts +63 -1
  289. package/src/scripts-runtime/types/swarm-sdk.d.ts +27 -15
  290. package/src/server.ts +52 -18
  291. package/src/slack/actions.ts +29 -1
  292. package/src/slack/app.ts +14 -2
  293. package/src/slack/assistant.ts +36 -2
  294. package/src/slack/channel-join.ts +3 -16
  295. package/src/slack/commands.ts +9 -1
  296. package/src/slack/event-dedup.ts +1 -1
  297. package/src/slack/external-channel-egress.ts +113 -0
  298. package/src/slack/external-channel.ts +309 -0
  299. package/src/slack/handlers.ts +61 -0
  300. package/src/slack/render-v2.ts +40 -47
  301. package/src/slack/work-objects.ts +5 -0
  302. package/src/tasks/additive-buffer.ts +4 -2
  303. package/src/tasks/context-key.ts +94 -2
  304. package/src/tasks/model-pin.ts +67 -0
  305. package/src/tasks/worker-follow-up.ts +4 -31
  306. package/src/telemetry.ts +2 -1
  307. package/src/tests/acp-adapter.test.ts +42 -0
  308. package/src/tests/api-drain-worker-e2e.test.ts +1 -6
  309. package/src/tests/apps-catalog-feedback.test.ts +310 -0
  310. package/src/tests/apps-catalog-inputs.test.ts +70 -0
  311. package/src/tests/apps-catalog-table.test.ts +113 -0
  312. package/src/tests/azure-devops-boards-sync.test.ts +584 -0
  313. package/src/tests/azure-devops-html.test.ts +13 -0
  314. package/src/tests/azure-devops-webhook-malformed.test.ts +4 -0
  315. package/src/tests/base-prompt.test.ts +58 -54
  316. package/src/tests/chat-sdk-commands.test.ts +191 -0
  317. package/src/tests/chat-sdk-config.test.ts +334 -0
  318. package/src/tests/chat-sdk-discord-api.test.ts +68 -0
  319. package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
  320. package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
  321. package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
  322. package/src/tests/chat-sdk-harness.ts +146 -0
  323. package/src/tests/chat-sdk-inbound.test.ts +363 -0
  324. package/src/tests/chat-sdk-relay.test.ts +470 -0
  325. package/src/tests/chat-sdk-reload.test.ts +128 -0
  326. package/src/tests/chat-sdk-shutdown.test.ts +220 -0
  327. package/src/tests/chat-sdk-slack.test.ts +268 -0
  328. package/src/tests/chat-sdk-state.test.ts +163 -0
  329. package/src/tests/chat-sdk-status-route.test.ts +382 -0
  330. package/src/tests/chat-sdk-teams.test.ts +277 -0
  331. package/src/tests/chat-sdk-tools.test.ts +520 -0
  332. package/src/tests/chat-sdk-typing.test.ts +120 -0
  333. package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
  334. package/src/tests/claude-adapter-binary.test.ts +144 -0
  335. package/src/tests/claude-flag-settings.test.ts +114 -0
  336. package/src/tests/claude-managed-adapter.test.ts +1 -1
  337. package/src/tests/claude-sdk-lifecycle.test.ts +148 -1
  338. package/src/tests/claude-sdk-process.fixture.ts +7 -0
  339. package/src/tests/claude-thinking-tokens.test.ts +57 -0
  340. package/src/tests/claude-worker-parity.test.ts +2 -7
  341. package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
  342. package/src/tests/config-refs.test.ts +66 -0
  343. package/src/tests/context-key.test.ts +51 -0
  344. package/src/tests/cors-allowlist.test.ts +25 -0
  345. package/src/tests/create-page-tool.test.ts +18 -0
  346. package/src/tests/credential-check.test.ts +139 -0
  347. package/src/tests/credentials.test.ts +21 -0
  348. package/src/tests/db-runtime.test.ts +61 -0
  349. package/src/tests/db-task-read-contract.test.ts +20 -0
  350. package/src/tests/db-task-write-contract.test.ts +10 -0
  351. package/src/tests/deferred-task-wake.test.ts +52 -4
  352. package/src/tests/docs-index-footprint.test.js +3 -3
  353. package/src/tests/dsh-adapter.test.ts +1 -1
  354. package/src/tests/enabled-capabilities.test.ts +20 -0
  355. package/src/tests/entrypoint-api-readiness.test.ts +14 -8
  356. package/src/tests/entrypoint-config-env-export.test.ts +5 -2
  357. package/src/tests/entrypoint-export-to-env.test.ts +78 -0
  358. package/src/tests/explicit-model-validation.test.ts +105 -1
  359. package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
  360. package/src/tests/extensions-post-bridge.test.ts +51 -0
  361. package/src/tests/fetch-resolved-env.test.ts +128 -0
  362. package/src/tests/fixtures/azure-boards/workitem.commented.json +89 -0
  363. package/src/tests/fixtures/azure-boards/workitem.created.json +81 -0
  364. package/src/tests/fixtures/azure-boards/workitem.deleted.json +70 -0
  365. package/src/tests/fixtures/azure-boards/workitem.restored.json +82 -0
  366. package/src/tests/fixtures/azure-boards/workitem.updated.json +130 -0
  367. package/src/tests/fixtures/catalog-feedback-definition.json.txt +860 -0
  368. package/src/tests/fixtures/catalog-inputs-definition.json.txt +910 -0
  369. package/src/tests/fixtures/catalog-table-definition.json.txt +468 -0
  370. package/src/tests/fixtures/chat-sdk/telegram-private-text.json +10 -0
  371. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
  372. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
  373. package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
  374. package/src/tests/fixtures/runner-identity-refresh.ts +3 -0
  375. package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
  376. package/src/tests/github-handlers.test.ts +35 -0
  377. package/src/tests/harness-provider-resolution.test.ts +12 -0
  378. package/src/tests/heartbeat-checklist.test.ts +3 -2
  379. package/src/tests/hook-runtime-close.test.ts +0 -2
  380. package/src/tests/http-api-integration.test.ts +0 -25
  381. package/src/tests/migration-046-budgets.test.ts +17 -16
  382. package/src/tests/migration-217-chat-sdk-state.test.ts +113 -0
  383. package/src/tests/model-tier-resolution.test.ts +93 -0
  384. package/src/tests/models-catalog.test.ts +42 -1
  385. package/src/tests/node-env-runtime.test.ts +98 -0
  386. package/src/tests/openai-compatible-providers.test.ts +134 -0
  387. package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
  388. package/src/tests/opencode-adapter.test.ts +348 -3
  389. package/src/tests/opencode-billing.test.ts +28 -0
  390. package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
  391. package/src/tests/opencode-shell-env.test.ts +145 -0
  392. package/src/tests/openrouter-base-url.test.ts +101 -151
  393. package/src/tests/page-proxy.test.ts +1 -1
  394. package/src/tests/pages-browser-sdk.test.ts +76 -0
  395. package/src/tests/pages-feedback.test.ts +1 -1
  396. package/src/tests/paused-tasks-requested-by.test.ts +102 -0
  397. package/src/tests/pi-custom-provider-fake-server.test.ts +442 -0
  398. package/src/tests/pi-mono-adapter.test.ts +385 -5
  399. package/src/tests/pi-shell-env.test.ts +170 -0
  400. package/src/tests/prompt-template-remaining.test.ts +35 -0
  401. package/src/tests/rbac-engine.test.ts +11 -3
  402. package/src/tests/runner-exit-after-tasks.test.ts +0 -4
  403. package/src/tests/runner-identity-refresh.test.ts +3 -0
  404. package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
  405. package/src/tests/script-connections-sql.test.ts +675 -0
  406. package/src/tests/script-connections.test.ts +7 -1
  407. package/src/tests/scripts-http.test.ts +201 -1
  408. package/src/tests/scripts-only-gating.test.ts +2 -3
  409. package/src/tests/scripts-runtime.test.ts +58 -40
  410. package/src/tests/secret-scrubber.test.ts +86 -0
  411. package/src/tests/seed-skills-bundled-files.test.ts +45 -53
  412. package/src/tests/seed-skills-retire.test.ts +182 -0
  413. package/src/tests/send-task-requester-gate.test.ts +58 -0
  414. package/src/tests/session-cost-recompute-unit.test.ts +94 -0
  415. package/src/tests/skill-get-name-resolution.test.ts +137 -0
  416. package/src/tests/slack-channel-join.test.ts +4 -1
  417. package/src/tests/slack-external-channel-config.test.ts +65 -0
  418. package/src/tests/slack-external-channel-egress.test.ts +237 -0
  419. package/src/tests/slack-external-channel-guard.test.ts +280 -0
  420. package/src/tests/slack-external-channel-tools.test.ts +173 -0
  421. package/src/tests/slack-external-channel.test.ts +370 -0
  422. package/src/tests/slack-render-v2.test.ts +86 -10
  423. package/src/tests/sonnet-5-5-registry.test.ts +9 -1
  424. package/src/tests/spec-base-url.test.ts +16 -1
  425. package/src/tests/swarm-config-export-to-env.test.ts +267 -0
  426. package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
  427. package/src/tests/swarm-diff.test.ts +1 -1
  428. package/src/tests/task-model-effort-rerun.test.ts +164 -0
  429. package/src/tests/task-session-prompts.test.ts +132 -0
  430. package/src/tests/task-tool-manifest.test.ts +14 -0
  431. package/src/tests/task-tools-ctx.test.ts +2 -0
  432. package/src/tests/tool-annotations.test.ts +6 -6
  433. package/src/tests/ui-logs-parser.test.ts +43 -0
  434. package/src/tests/used-by-route.test.ts +6 -0
  435. package/src/tests/vendored-openapi.test.ts +16 -1
  436. package/src/tests/vercel-ai-gateway.test.ts +149 -0
  437. package/src/tests/workflow-swarm-script.test.ts +38 -0
  438. package/src/tests/workflow-wait-filter.test.ts +5 -3
  439. package/src/tools/chat-access.ts +41 -0
  440. package/src/tools/chat-open-dm.ts +59 -0
  441. package/src/tools/chat-post.ts +74 -0
  442. package/src/tools/chat-read-thread.ts +100 -0
  443. package/src/tools/chat-reply.ts +75 -0
  444. package/src/tools/create-page.ts +3 -13
  445. package/src/tools/defer-task.ts +17 -0
  446. package/src/tools/model-catalog/index.ts +2 -1
  447. package/src/tools/register-chat-channel.ts +139 -0
  448. package/src/tools/send-task.ts +24 -0
  449. package/src/tools/skills/skill-get.ts +17 -9
  450. package/src/tools/slack-post.ts +6 -0
  451. package/src/tools/slack-read.ts +8 -0
  452. package/src/tools/slack-reply.ts +6 -0
  453. package/src/tools/slack-start-thread.ts +6 -0
  454. package/src/tools/slack-update.ts +6 -0
  455. package/src/tools/slack-upload-file.ts +6 -0
  456. package/src/tools/swarm-config/get-config.ts +2 -1
  457. package/src/tools/swarm-config/list-config.ts +2 -1
  458. package/src/tools/swarm-config/set-config.ts +16 -3
  459. package/src/tools/tool-config.ts +8 -6
  460. package/src/types.ts +12 -2
  461. package/src/utils/config-env-export.ts +74 -0
  462. package/src/utils/credentials.test.ts +92 -0
  463. package/src/utils/credentials.ts +52 -4
  464. package/src/utils/harness-provider.ts +15 -6
  465. package/src/utils/node-env.ts +24 -0
  466. package/src/utils/runtime-model-catalog.ts +11 -1
  467. package/src/utils/secret-scrubber.ts +71 -2
  468. package/src/utils/task-tool-manifest.ts +19 -2
  469. package/src/workflows/executors/swarm-script.ts +1 -0
  470. package/templates/skills/agent-browser/SKILL.md +1 -1
  471. package/templates/skills/agent-browser/content.md +1 -1
  472. package/templates/skills/apps/SKILL.md +749 -0
  473. package/templates/skills/apps/content.md +60 -22
  474. package/templates/skills/chat-sdk/config.json +14 -0
  475. package/templates/skills/chat-sdk/content.md +84 -0
  476. package/templates/skills/composio-gmail/content.md +7 -0
  477. package/templates/skills/composio-google-docs/content.md +1 -1
  478. package/templates/skills/email-domain-health/config.json +14 -0
  479. package/templates/skills/email-domain-health/content.md +131 -0
  480. package/templates/skills/kv-storage/content.md +2 -2
  481. package/templates/skills/pages/content.md +8 -10
  482. package/templates/skills/qa-loom/config.json +14 -0
  483. package/templates/skills/qa-loom/content.md +187 -0
  484. package/templates/skills/qa-loom/files/build-loom.mjs +221 -0
  485. package/templates/skills/qa-loom/files/run-qa.sh +57 -0
  486. package/templates/skills/slack-interaction/content.md +4 -0
  487. package/templates/skills/swarm-extensions/content.md +2 -0
  488. package/templates/skills/swarm-scripts/SKILL.md +4 -2
  489. package/templates/skills/swarm-scripts/config.json +1 -1
  490. package/templates/skills/swarm-scripts/content.md +4 -2
  491. package/templates/skills/workflow-iterate/content.md +38 -0
  492. package/dist/artifact-eczsknc3.js +0 -3843
  493. package/dist/cli-9xsmdpdt.js +0 -56377
  494. package/dist/cli-bd957dgb.js +0 -153
  495. package/dist/cli-q51yprfq.js +0 -1104
  496. package/dist/cli-t1ze64h3.js +0 -811
  497. package/dist/index-9ch1n761.js +0 -1102
  498. package/src/artifact-sdk/index.ts +0 -2
  499. package/src/artifact-sdk/localtunnel.d.ts +0 -20
  500. package/src/artifact-sdk/port.ts +0 -12
  501. package/src/artifact-sdk/server.ts +0 -183
  502. package/src/artifact-sdk/tunnel.ts +0 -19
  503. package/src/commands/artifact.ts +0 -249
  504. package/src/http/ecosystem.ts +0 -77
  505. package/src/tests/artifact-commands.test.ts +0 -92
  506. package/src/tests/artifact-sdk.test.ts +0 -793
  507. package/src/tests/register-service-security.test.ts +0 -194
  508. package/src/tools/list-services.ts +0 -107
  509. package/src/tools/register-service.ts +0 -177
  510. package/src/tools/unregister-service.ts +0 -73
  511. package/src/tools/update-service-status.ts +0 -96
  512. package/templates/skills/artifacts/config.json +0 -14
  513. package/templates/skills/artifacts/content.md +0 -344
  514. package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
  515. package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
  516. package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
  517. package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
  518. package/dist/{azure-openai-responses-ap1gwxgr.js → azure-openai-responses-ygfreq4t.js} +5 -5
  519. package/dist/{cli-5rqrj7q0.js → cli-pw7ebjdt.js} +0 -0
  520. package/dist/{openai-codex-responses-33qhkkdy.js → openai-codex-responses-3bk0grnr.js} +4 -4
  521. package/dist/{openai-completions-s88xm3ns.js → openai-completions-5d4jpakc.js} +9 -9
  522. package/dist/{openai-responses-7xd2f2e2.js → openai-responses-krb51f59.js} +5 -5
  523. package/dist/{pi-messages-xszk613n.js → pi-messages-x9gzynm1.js} +3 -3
  524. /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
  525. /package/src/{artifact-sdk → pages}/feedback-overlay.ts +0 -0
@@ -0,0 +1,267 @@
1
+ import { Database } from "bun:sqlite";
2
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
3
+ import { readFileSync } from "node:fs";
4
+ import { unlink } from "node:fs/promises";
5
+ import { createServer as createHttpServer, type Server } from "node:http";
6
+ import { closeDb, createAgent, getSwarmConfigs, initDb, upsertSwarmConfig } from "../be/db";
7
+ import { handleConfig } from "../http/config";
8
+ import { getPathSegments, parseQueryParams } from "../http/utils";
9
+ import { registerSetConfigTool } from "../tools/swarm-config/set-config";
10
+ import { ENV_EXPORT_RESTRICTED_KEYS, envExportRestrictedError } from "../utils/config-env-export";
11
+ import { setRequestAuth } from "../utils/request-auth-context";
12
+ import { clearVolatileSecretsForTesting } from "../utils/secret-scrubber";
13
+ import { listenOnFreePort } from "./test-net";
14
+
15
+ const TEST_DB_PATH = "./test-swarm-config-export-to-env.sqlite";
16
+ const LEAD_ID = "21111111-1111-1111-1111-111111111111";
17
+ const MIGRATION = "src/be/migrations/215_swarm_config_export_to_env.sql";
18
+
19
+ type ToolHandler = (args: unknown, meta: unknown) => Promise<unknown> | unknown;
20
+
21
+ class MockMcpServer {
22
+ handlers = new Map<string, ToolHandler>();
23
+ registerTool(name: string, _config: unknown, handler: ToolHandler) {
24
+ this.handlers.set(name, handler);
25
+ return { name };
26
+ }
27
+ }
28
+
29
+ const requestInfo = {
30
+ sessionId: "test-session",
31
+ requestInfo: { headers: { "x-agent-id": LEAD_ID } },
32
+ };
33
+
34
+ describe("swarm_config exportToEnv", () => {
35
+ let server: Server;
36
+ let baseUrl = "";
37
+ const mcpServer = new MockMcpServer();
38
+
39
+ beforeAll(async () => {
40
+ initDb(TEST_DB_PATH);
41
+ await createAgent({
42
+ id: LEAD_ID,
43
+ name: "export-to-env-test-lead",
44
+ isLead: true,
45
+ status: "idle",
46
+ capabilities: [],
47
+ });
48
+ registerSetConfigTool(mcpServer as unknown as Parameters<typeof registerSetConfigTool>[0]);
49
+ server = createHttpServer(async (req, res) => {
50
+ setRequestAuth(req, { kind: "operator", fingerprint: "test" });
51
+ const handled = await handleConfig(
52
+ req,
53
+ res,
54
+ getPathSegments(req.url || ""),
55
+ parseQueryParams(req.url || ""),
56
+ );
57
+ if (!handled) {
58
+ res.writeHead(404);
59
+ res.end();
60
+ }
61
+ });
62
+ baseUrl = `http://localhost:${await listenOnFreePort(server)}`;
63
+ });
64
+
65
+ afterAll(async () => {
66
+ clearVolatileSecretsForTesting();
67
+ server.close();
68
+ closeDb();
69
+ for (const suffix of ["", "-wal", "-shm"]) {
70
+ await unlink(`${TEST_DB_PATH}${suffix}`).catch(() => {});
71
+ }
72
+ });
73
+
74
+ test("new rows export by default; an update without the flag keeps it", async () => {
75
+ const created = await upsertSwarmConfig({ scope: "global", key: "EXPORT_A", value: "1" });
76
+ expect(created.exportToEnv).toBe(true);
77
+
78
+ const off = await upsertSwarmConfig({
79
+ scope: "global",
80
+ key: "EXPORT_A",
81
+ value: "2",
82
+ isSecret: true,
83
+ exportToEnv: false,
84
+ });
85
+ expect(off.exportToEnv).toBe(false);
86
+
87
+ const kept = await upsertSwarmConfig({
88
+ scope: "global",
89
+ key: "EXPORT_A",
90
+ value: "3",
91
+ isSecret: true,
92
+ });
93
+ expect(kept.exportToEnv).toBe(false);
94
+
95
+ const on = await upsertSwarmConfig({
96
+ scope: "global",
97
+ key: "EXPORT_A",
98
+ value: "4",
99
+ exportToEnv: true,
100
+ });
101
+ expect(on.exportToEnv).toBe(true);
102
+ });
103
+
104
+ test("default-off keys start off on create but accept an explicit true", async () => {
105
+ const created = await upsertSwarmConfig({
106
+ scope: "global",
107
+ key: "KAPSO_WEBHOOK_HMAC_SECRET",
108
+ value: "k",
109
+ isSecret: true,
110
+ });
111
+ expect(created.exportToEnv).toBe(false);
112
+
113
+ const optedIn = await upsertSwarmConfig({
114
+ scope: "global",
115
+ key: "X_CLIENT_SECRET",
116
+ value: "x",
117
+ isSecret: true,
118
+ exportToEnv: true,
119
+ });
120
+ expect(optedIn.exportToEnv).toBe(true);
121
+ });
122
+
123
+ test("restricted keys store false and reject true through DB, HTTP, and MCP", async () => {
124
+ const key = "SLACK_SIGNING_SECRET";
125
+ const stored = await upsertSwarmConfig({ scope: "global", key, value: "s", isSecret: true });
126
+ expect(stored.exportToEnv).toBe(false);
127
+ const connection = await upsertSwarmConfig({
128
+ scope: "global",
129
+ key: "connection.example.secret",
130
+ value: "s",
131
+ isSecret: true,
132
+ });
133
+ expect(connection.exportToEnv).toBe(false);
134
+
135
+ const body = { scope: "global" as const, key, value: "s", isSecret: true, exportToEnv: true };
136
+ await expect(upsertSwarmConfig(body)).rejects.toThrow(envExportRestrictedError(key));
137
+
138
+ const res = await fetch(`${baseUrl}/api/config`, {
139
+ method: "PUT",
140
+ headers: { "Content-Type": "application/json" },
141
+ body: JSON.stringify(body),
142
+ });
143
+ expect(res.status).toBe(400);
144
+ expect(await res.json()).toMatchObject({ error: envExportRestrictedError(key) });
145
+
146
+ const result = (await mcpServer.handlers.get("set-config")!(body, requestInfo)) as {
147
+ structuredContent: { success: boolean; message: string };
148
+ };
149
+ expect(result.structuredContent.success).toBe(false);
150
+ expect(result.structuredContent.message).toBe(envExportRestrictedError(key));
151
+
152
+ const [row] = await getSwarmConfigs({ key });
153
+ expect(row?.exportToEnv).toBe(false);
154
+ });
155
+
156
+ test("the config API and /api/config/resolved carry the flag", async () => {
157
+ const put = await fetch(`${baseUrl}/api/config`, {
158
+ method: "PUT",
159
+ headers: { "Content-Type": "application/json" },
160
+ body: JSON.stringify({
161
+ scope: "global",
162
+ key: "EXPORT_B",
163
+ value: "b",
164
+ isSecret: true,
165
+ exportToEnv: false,
166
+ }),
167
+ });
168
+ expect(put.status).toBe(200);
169
+ expect(await put.json()).toMatchObject({ key: "EXPORT_B", exportToEnv: false });
170
+
171
+ const resolved = await fetch(`${baseUrl}/api/config/resolved?key=EXPORT_B`);
172
+ const { configs } = (await resolved.json()) as {
173
+ configs: Array<{ key: string; exportToEnv: boolean }>;
174
+ };
175
+ expect(configs).toEqual([expect.objectContaining({ key: "EXPORT_B", exportToEnv: false })]);
176
+ });
177
+
178
+ test("set-config accepts the flag and keeps it on a later write", async () => {
179
+ const handler = mcpServer.handlers.get("set-config")!;
180
+ await handler(
181
+ { scope: "global", key: "EXPORT_C", value: "c", isSecret: true, exportToEnv: false },
182
+ requestInfo,
183
+ );
184
+ await handler({ scope: "global", key: "EXPORT_C", value: "c2", isSecret: true }, requestInfo);
185
+ const [row] = await getSwarmConfigs({ key: "EXPORT_C" });
186
+ expect(row?.exportToEnv).toBe(false);
187
+ });
188
+ });
189
+
190
+ describe("migration 215", () => {
191
+ // Keys agents read from their own env today (PR #2156 review audit, plus
192
+ // harness, git and agent-fs credentials). None may land on the deny list.
193
+ const MUST_STAY_EXPORTED = [
194
+ "AGENTMAIL_API_KEY",
195
+ "ATTIO_API_KEY",
196
+ "DOKPLOY_API_KEY",
197
+ "ELEVENLABS_API_KEY",
198
+ "EXA_API_KEY",
199
+ "GSC_SERVICE_ACCOUNT_BASE64",
200
+ "HETZNER_API_KEY",
201
+ "IMGFLIP_PASSWORD",
202
+ "IMGFLIP_USERNAME",
203
+ "KAPSO_API_KEY",
204
+ "PLAUSIBLE_API_KEY",
205
+ "SPRITES_API_KEY",
206
+ "SUPERAGENT_API_KEY",
207
+ "TURSO_API_TOKEN",
208
+ "TURSO_DB_TOKEN",
209
+ "TURSO_X_POSTS_DB_TOKEN",
210
+ "WORKDIR_API_KEY",
211
+ "X_ACCESS_TOKEN",
212
+ "X_ACCESS_TOKEN_SECRET",
213
+ "X_API_KEY",
214
+ "X_API_SECRET",
215
+ "X_BEARER_TOKEN",
216
+ "CLAUDE_CODE_OAUTH_TOKEN",
217
+ "OPENROUTER_API_KEY",
218
+ "GITHUB_TOKEN",
219
+ "AGENT_FS_API_KEY",
220
+ "SLACK_BOT_TOKEN",
221
+ "SELF_DRIVING_WEBHOOK_SECRET",
222
+ "DESPLEGA_PROD_DATABASE_URL",
223
+ "GWS_CREDS_BASE64",
224
+ "codex_oauth_1",
225
+ ];
226
+ const DENY_ONLY = [
227
+ "KAPSO_WEBHOOK_HMAC_SECRET",
228
+ "SENTRY_TEST_APP_WEBHOOK_SECRET",
229
+ "TELEMETRY_CH_AUTH",
230
+ "HACK_AGENT_FS_ADMIN_KEY",
231
+ "X_CLIENT_SECRET",
232
+ "connection.example.secret",
233
+ ];
234
+
235
+ test("backfills true and turns off only the deny list", () => {
236
+ const db = new Database(":memory:");
237
+ try {
238
+ db.exec(`CREATE TABLE swarm_config (
239
+ id TEXT PRIMARY KEY, scope TEXT NOT NULL, scopeId TEXT, key TEXT NOT NULL,
240
+ value TEXT NOT NULL, isSecret INTEGER NOT NULL DEFAULT 0, envPath TEXT,
241
+ description TEXT, createdAt TEXT NOT NULL, lastUpdatedAt TEXT NOT NULL,
242
+ encrypted INTEGER NOT NULL DEFAULT 0)`);
243
+ const insert = db.prepare(
244
+ "INSERT INTO swarm_config (id, scope, key, value, isSecret, createdAt, lastUpdatedAt) VALUES (?, 'global', ?, 'v', 1, 'now', 'now')",
245
+ );
246
+ const keys = [...MUST_STAY_EXPORTED, ...DENY_ONLY, ...ENV_EXPORT_RESTRICTED_KEYS];
247
+ for (const key of keys) insert.run(crypto.randomUUID(), key);
248
+
249
+ db.exec(readFileSync(MIGRATION, "utf8"));
250
+
251
+ const flags = Object.fromEntries(
252
+ db
253
+ .query<{ key: string; exportToEnv: number }, []>(
254
+ "SELECT key, exportToEnv FROM swarm_config",
255
+ )
256
+ .all()
257
+ .map((row) => [row.key, row.exportToEnv]),
258
+ );
259
+ for (const key of MUST_STAY_EXPORTED) expect([key, flags[key]]).toEqual([key, 1]);
260
+ for (const key of [...DENY_ONLY, ...ENV_EXPORT_RESTRICTED_KEYS]) {
261
+ expect([key, flags[key]]).toEqual([key, 0]);
262
+ }
263
+ } finally {
264
+ db.close();
265
+ }
266
+ });
267
+ });
@@ -6,6 +6,7 @@ import {
6
6
  createAgent,
7
7
  deleteSwarmConfig,
8
8
  getDbClient,
9
+ getInjectableGlobalConfigs,
9
10
  getSwarmConfigById,
10
11
  getSwarmConfigs,
11
12
  initDb,
@@ -94,6 +95,20 @@ function createTestServer(): Server {
94
95
  });
95
96
  }
96
97
 
98
+ describe("Teams SDK env fallbacks", () => {
99
+ test("a global SERVICE_URL row is storable but never injected into env", async () => {
100
+ await upsertSwarmConfig({ scope: "global", key: "SERVICE_URL", value: "https://evil.example" });
101
+ try {
102
+ expect((await getSwarmConfigs({ scope: "global", key: "SERVICE_URL" })).length).toBe(1);
103
+ const injectable = await getInjectableGlobalConfigs();
104
+ expect(injectable.some((config) => config.key === "SERVICE_URL")).toBe(false);
105
+ } finally {
106
+ const rows = await getSwarmConfigs({ scope: "global", key: "SERVICE_URL" });
107
+ for (const row of rows) await deleteSwarmConfig(row.id);
108
+ }
109
+ });
110
+ });
111
+
97
112
  describe("swarm-config reserved keys guard", () => {
98
113
  let server: Server;
99
114
  let baseUrl = "";
@@ -139,6 +154,7 @@ describe("swarm-config reserved keys guard", () => {
139
154
  "cors_allow_any_origin",
140
155
  "EXTENSION_ALLOW_LEAD_ACTIVATION",
141
156
  "extension_allow_lead_activation",
157
+ "CHAT_SDK_API_URL_OVERRIDES",
142
158
  ]) {
143
159
  test(`rejects deployment-only ${key} through DB, HTTP, and MCP`, async () => {
144
160
  const config = { scope: "global" as const, key, value: "true" };
@@ -8,7 +8,7 @@
8
8
  * anchor ids, severity badges) without dragging in a real DOM lib.
9
9
  */
10
10
  import { describe, expect, test } from "bun:test";
11
- import { SWARM_UI_JS } from "../artifact-sdk/browser-sdk";
11
+ import { SWARM_UI_JS } from "../pages/browser-sdk";
12
12
 
13
13
  const EXAMPLE_HUNK = {
14
14
  hunks: [
@@ -0,0 +1,164 @@
1
+ // What a task records about the model and effort it ran on, and what a re-run
2
+ // of the same row carries over. Regression for: an agent's model/effort changed
3
+ // in the dashboard, and the next run of a task kept the previous values.
4
+
5
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
6
+ import { unlink } from "node:fs/promises";
7
+ import {
8
+ closeDb,
9
+ createAgent,
10
+ createTaskExtended,
11
+ getTaskById,
12
+ initDb,
13
+ updateTaskClaudeSessionId,
14
+ } from "../be/db";
15
+ import { effectiveReasoningEffort } from "../providers/reasoning-effort";
16
+ import { resumedTaskModelSelection, taskModelPin } from "../tasks/model-pin";
17
+
18
+ const TEST_DB_PATH = "./test-task-model-effort-rerun.sqlite";
19
+
20
+ async function removeDbFiles(path: string): Promise<void> {
21
+ for (const suffix of ["", "-wal", "-shm"]) {
22
+ try {
23
+ await unlink(path + suffix);
24
+ } catch (error) {
25
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
26
+ }
27
+ }
28
+ }
29
+
30
+ beforeAll(async () => {
31
+ await removeDbFiles(TEST_DB_PATH);
32
+ initDb(TEST_DB_PATH);
33
+ });
34
+
35
+ afterAll(async () => {
36
+ closeDb();
37
+ await removeDbFiles(TEST_DB_PATH);
38
+ });
39
+
40
+ describe("taskModelPin", () => {
41
+ test("a model reported by a previous session is not a pin", () => {
42
+ expect(taskModelPin({ model: "claude-opus-5-5", claudeSessionId: "s1" })).toBeUndefined();
43
+ });
44
+
45
+ test("a model a tier layer chose is not a pin", () => {
46
+ expect(
47
+ taskModelPin({
48
+ model: "claude-opus-5-5",
49
+ modelTier: "smart",
50
+ resolvedModel: "claude-opus-5-5",
51
+ modelSource: "tier-default",
52
+ }),
53
+ ).toBeUndefined();
54
+ });
55
+
56
+ test("the creator's model on an unclaimed row is the pin", () => {
57
+ expect(taskModelPin({ model: "claude-sonnet-5-5" })).toBe("claude-sonnet-5-5");
58
+ });
59
+
60
+ test("a claimed pin keeps its alias", () => {
61
+ expect(
62
+ taskModelPin({
63
+ model: "claude-opus-5-5",
64
+ modelSource: "model",
65
+ modelAlias: "latest:anthropic/opus",
66
+ claudeSessionId: "s1",
67
+ }),
68
+ ).toBe("latest:anthropic/opus");
69
+ });
70
+ });
71
+
72
+ describe("resumedTaskModelSelection", () => {
73
+ test("a paused unpinned task resumes without the previous run's model or claim record", () => {
74
+ expect(
75
+ resumedTaskModelSelection({
76
+ model: "claude-opus-5-5",
77
+ resolvedModel: "claude-opus-5-5",
78
+ modelSource: "tier-config",
79
+ modelTier: "smart",
80
+ claudeSessionId: "s1",
81
+ }),
82
+ ).toEqual({ model: undefined, resolvedModel: undefined, modelSource: undefined });
83
+ });
84
+
85
+ test("a paused pinned task resumes on its pin", () => {
86
+ expect(
87
+ resumedTaskModelSelection({
88
+ model: "claude-sonnet-5-5",
89
+ resolvedModel: "claude-sonnet-5-5",
90
+ modelSource: "model",
91
+ claudeSessionId: "s1",
92
+ }),
93
+ ).toEqual({
94
+ model: "claude-sonnet-5-5",
95
+ resolvedModel: "claude-sonnet-5-5",
96
+ modelSource: "model",
97
+ });
98
+ });
99
+ });
100
+
101
+ describe("effectiveReasoningEffort", () => {
102
+ test("unset effort records nothing", () => {
103
+ expect(effectiveReasoningEffort("claude", "claude-opus-5-5", undefined)).toBeNull();
104
+ });
105
+
106
+ test("harnesses without effort support record nothing", () => {
107
+ expect(effectiveReasoningEffort("devin", "", "high")).toBeNull();
108
+ });
109
+
110
+ test("a level the model cannot take is dropped, the same as the adapter does", () => {
111
+ expect(effectiveReasoningEffort("claude", "not-a-reasoning-model", "high")).toBeNull();
112
+ });
113
+ });
114
+
115
+ describe("session report records the effort", () => {
116
+ test("the effort the session ran at lands on resolvedEffort, and a re-run replaces it", async () => {
117
+ const agent = await createAgent({ name: "effort-rerun", isLead: false, status: "idle" });
118
+ const task = await createTaskExtended("work", { agentId: agent.id });
119
+
120
+ // First run: the agent's REASONING_EFFORT_OVERRIDE was high.
121
+ await updateTaskClaudeSessionId(
122
+ task.id,
123
+ "run-1",
124
+ "claude",
125
+ undefined,
126
+ "claude-opus-5-5",
127
+ undefined,
128
+ undefined,
129
+ "high",
130
+ );
131
+ let row = await getTaskById(task.id);
132
+ expect(row?.resolvedEffort).toBe("high");
133
+ // The requested-effort column stays the creator's value, not a pin.
134
+ expect(row?.effort).toBeUndefined();
135
+
136
+ // Effort changed to low in the dashboard; the next run records low.
137
+ await updateTaskClaudeSessionId(
138
+ task.id,
139
+ "run-2",
140
+ "claude",
141
+ undefined,
142
+ "claude-opus-5-5",
143
+ undefined,
144
+ undefined,
145
+ "low",
146
+ );
147
+ row = await getTaskById(task.id);
148
+ expect(row?.resolvedEffort).toBe("low");
149
+
150
+ // Effort set back to Auto: the harness default applied, nothing to show.
151
+ await updateTaskClaudeSessionId(
152
+ task.id,
153
+ "run-3",
154
+ "claude",
155
+ undefined,
156
+ "claude-opus-5-5",
157
+ undefined,
158
+ undefined,
159
+ null,
160
+ );
161
+ row = await getTaskById(task.id);
162
+ expect(row?.resolvedEffort).toBeUndefined();
163
+ });
164
+ });
@@ -0,0 +1,132 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import {
3
+ buildRequesterProfilePrompt,
4
+ buildTaskSessionPrompts,
5
+ type TaskSessionContext,
6
+ } from "../commands/runner";
7
+ import { type BasePromptArgs, getTaskContextPrompt } from "../prompts/base-prompt";
8
+ import type { ProviderName } from "../types";
9
+
10
+ // The provider caches the system prompt as a prefix, so any per-task byte in it
11
+ // re-bills the whole prompt on the first call of every session. These tests pin
12
+ // the split: one agent, different tasks, requesters and repos, same system
13
+ // prompt; the per-task context still reaches the model, in the task prompt.
14
+
15
+ const agentArgs = (
16
+ provider: ProviderName,
17
+ extra: Partial<BasePromptArgs> = {},
18
+ ): BasePromptArgs => ({
19
+ role: "worker",
20
+ agentId: "11111111-2222-3333-4444-555555555555",
21
+ name: "Ada",
22
+ provider,
23
+ traits: { hasMcp: true, hasLocalEnvironment: true, nativeSkillDiscovery: provider !== "codex" },
24
+ soulMd: "You are Ada.",
25
+ claudeMd: "# Agent: Ada\n\nAlways run the tests before you push.",
26
+ skillsSummary: [{ name: "commit", description: "Create a commit" }],
27
+ mcpServers: ["linear"],
28
+ ...extra,
29
+ });
30
+
31
+ const sessionA: TaskSessionContext = {
32
+ repoContext: {
33
+ clonePath: "/workspace/personal/repos/alpha",
34
+ claudeMd: "Alpha repo rules.",
35
+ warning: "Alpha is behind origin",
36
+ autoStashes: [{ ref: "stash@{0}", message: "WIP alpha" }],
37
+ guidelines: {
38
+ prChecks: ["bun run lint"],
39
+ mergeChecks: ["CI green"],
40
+ allowMerge: false,
41
+ review: ["Check the db boundary"],
42
+ },
43
+ },
44
+ slackContext: { channelId: "C0ALPHA", threadTs: "111.222" },
45
+ requestedBy: {
46
+ name: "Taras",
47
+ role: "CTO",
48
+ notes: "Lead with the answer.",
49
+ comms: { verbosity: "terse" },
50
+ },
51
+ cwdWarning: 'Note: The task requested working directory "/nope" but it does not exist.',
52
+ };
53
+
54
+ const sessionB: TaskSessionContext = {
55
+ repoContext: { clonePath: "/workspace/personal/repos/beta", guidelines: null },
56
+ requestedBy: { name: "Eze", role: "CEO", comms: { language: "Spanish" } },
57
+ };
58
+
59
+ // A heartbeat: no repository, no requester, no working directory.
60
+ const sessionC: TaskSessionContext = {};
61
+
62
+ async function build(args: BasePromptArgs, context: TaskSessionContext, taskPrompt: string) {
63
+ return buildTaskSessionPrompts({
64
+ basePromptArgs: args,
65
+ additionalSystemPrompt: "Operator note: be careful.",
66
+ taskPrompt,
67
+ context,
68
+ });
69
+ }
70
+
71
+ describe("buildTaskSessionPrompts", () => {
72
+ for (const provider of ["claude", "codex", "opencode", "pi"] as const) {
73
+ test(`${provider}: the system prompt is byte-identical across tasks, requesters and repos`, async () => {
74
+ const a = await build(agentArgs(provider), sessionA, "/work-on-task aaa\n\nTask: alpha");
75
+ const b = await build(agentArgs(provider), sessionB, "/work-on-task bbb\n\nTask: beta");
76
+ const c = await build(agentArgs(provider), sessionC, "/work-on-task ccc\n\nTask: heartbeat");
77
+
78
+ expect(a.systemPrompt).toBe(b.systemPrompt);
79
+ expect(a.systemPrompt).toBe(c.systemPrompt);
80
+ expect(a.systemPrompt).toEndWith("\n\nOperator note: be careful.");
81
+ for (const perTask of ["## Repository", "## Requester Profile", "Taras", "Eze", "/nope"]) {
82
+ expect(a.systemPrompt).not.toContain(perTask);
83
+ }
84
+ });
85
+ }
86
+
87
+ test("a scripts-only worker keeps the system prompt stable across Slack and non-Slack tasks", async () => {
88
+ const keys = ["SLACK_DISABLE", "SLACK_BOT_TOKEN", "SLACK_APP_TOKEN"] as const;
89
+ const saved = keys.map((key) => [key, process.env[key]] as const);
90
+ delete process.env.SLACK_DISABLE;
91
+ process.env.SLACK_BOT_TOKEN = "xoxb-test-token";
92
+ process.env.SLACK_APP_TOKEN = "xapp-test-token";
93
+ try {
94
+ const args = agentArgs("claude", { scriptsOnly: true });
95
+ const a = await build(args, sessionA, "task a");
96
+ const c = await build(args, sessionC, "task c");
97
+ expect(a.systemPrompt).toBe(c.systemPrompt);
98
+ expect(a.systemPrompt).not.toContain("C0ALPHA");
99
+ expect(a.prompt).toContain("## Slack (scripts-only)");
100
+ expect(a.prompt).toContain("C0ALPHA");
101
+ } finally {
102
+ for (const [key, value] of saved) {
103
+ if (value === undefined) delete process.env[key];
104
+ else process.env[key] = value;
105
+ }
106
+ }
107
+ });
108
+
109
+ test("the per-task context reaches the task prompt with the same text, after the task", async () => {
110
+ const args = agentArgs("opencode");
111
+ const taskPrompt = "/work-on-task aaa\n\nTask: alpha";
112
+ const { prompt } = await build(args, sessionA, taskPrompt);
113
+
114
+ const repoBlock = await getTaskContextPrompt({ ...args, repoContext: sessionA.repoContext });
115
+ const profile = await buildRequesterProfilePrompt(sessionA.requestedBy);
116
+ expect(repoBlock).toContain("## Repository");
117
+ expect(repoBlock).toContain("Alpha repo rules.");
118
+ expect(profile).toContain("This task was requested by Taras (CTO).");
119
+
120
+ expect(prompt).toStartWith(`${taskPrompt}\n\n`);
121
+ expect(prompt).toContain(repoBlock);
122
+ expect(prompt).toContain(profile);
123
+ expect(prompt).toEndWith(sessionA.cwdWarning ?? "");
124
+ expect(prompt.indexOf(repoBlock)).toBeLessThan(prompt.indexOf(profile));
125
+ expect(prompt).not.toMatch(/\n{3,}/);
126
+ });
127
+
128
+ test("a task with no per-task context keeps its prompt unchanged", async () => {
129
+ const { prompt } = await build(agentArgs("claude"), sessionC, "/work-on-task ccc");
130
+ expect(prompt).toBe("/work-on-task ccc");
131
+ });
132
+ });
@@ -27,6 +27,20 @@ describe("task tool manifests", () => {
27
27
  ]);
28
28
  });
29
29
 
30
+ test("chat-reply only preloads for a task carrying a chat-sdk contextKey", () => {
31
+ const manifest = parseTaskToolManifest('{"taskTypes":{"review":["chat-reply","script-run"]}}');
32
+ expect(selectTaskTools(manifest, { taskType: "review" })).toEqual(["script-run"]);
33
+ expect(
34
+ selectTaskTools(manifest, { taskType: "review", contextKey: "task:slack:C123:1700.1" }),
35
+ ).toEqual(["script-run"]);
36
+ expect(
37
+ selectTaskTools(manifest, {
38
+ taskType: "review",
39
+ contextKey: "task:chat-sdk:telegram:555001",
40
+ }),
41
+ ).toEqual(["chat-reply", "script-run"]);
42
+ });
43
+
30
44
  test("config writes reject unknown tools, invalid shapes, and oversized selections", () => {
31
45
  for (const value of [
32
46
  "not json",
@@ -137,8 +137,10 @@ describe("task tool ctx", () => {
137
137
  });
138
138
  await updateAgentProfile(lead.id, { capabilities: ["merge"] });
139
139
  await updateAgentProfile(underprivilegedLead.id, { capabilities: ["typescript"] });
140
+ // The sender created the parent, so it may continue it (task.parent.attach).
140
141
  const parent = await createTaskExtended("privileged parent", {
141
142
  agentId: lead.id,
143
+ creatorAgentId: sender.id,
142
144
  routingAffinity: { capabilities: ["merge"], leadOnly: true },
143
145
  });
144
146
 
@@ -116,7 +116,6 @@ describe("Tool Annotations & Classification", () => {
116
116
  "delete-config",
117
117
  "delete-workflow",
118
118
  "delete-page",
119
- "unregister-service",
120
119
  "slack-delete",
121
120
  "slack-archive-channel",
122
121
  ];
@@ -135,7 +134,6 @@ describe("Tool Annotations & Classification", () => {
135
134
  "get-tasks",
136
135
  "get-config",
137
136
  "list-channels",
138
- "list-services",
139
137
  "list-schedules",
140
138
  "list-config",
141
139
  "memory-get",
@@ -350,7 +348,7 @@ describe("Tool Annotations & Classification", () => {
350
348
  expect(missing).toEqual([]);
351
349
  });
352
350
 
353
- test("service tools are all deferred", () => {
351
+ test("the removed PM2 service registry tools stay gone", () => {
354
352
  const serviceTools = [
355
353
  "register-service",
356
354
  "unregister-service",
@@ -358,7 +356,8 @@ describe("Tool Annotations & Classification", () => {
358
356
  "update-service-status",
359
357
  ];
360
358
  for (const tool of serviceTools) {
361
- expect(DEFERRED_TOOLS.has(tool)).toBe(true);
359
+ expect(DEFERRED_TOOLS.has(tool)).toBe(false);
360
+ expect(tools[tool]).toBeUndefined();
362
361
  }
363
362
  });
364
363
 
@@ -376,9 +375,10 @@ describe("Tool Annotations & Classification", () => {
376
375
  // We expect all tools to be registered when all capabilities are enabled
377
376
  // (this suite forces ALL_CAPABILITIES, including default-disabled ones).
378
377
  // Includes 11 skill tools, 7 MCP server tools, reusable script tools, and the
379
- // native Kapso/WhatsApp tools (register/unregister number + send/reply message).
378
+ // native Kapso/WhatsApp tools (register/unregister number + send/reply message),
379
+ // and the six Chat SDK tools (chat-* + register/unregister-chat-channel).
380
380
  expect(count).toBeGreaterThanOrEqual(45);
381
- expect(count).toBeLessThanOrEqual(157);
381
+ expect(count).toBeLessThanOrEqual(163);
382
382
  });
383
383
 
384
384
  test("core tools are fewer than deferred tools", () => {