@desplega.ai/agent-swarm 1.173.0 → 2.1.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 (511) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-ccm9xrep.js → acp-adapter-kr4abrsk.js} +17 -16
  3. package/dist/{actions-sgeyv08k.js → actions-eh4g6w2r.js} +39 -34
  4. package/dist/{amp-adapter-gpxp3kc9.js → amp-adapter-7h7wdt8q.js} +8 -7
  5. package/dist/{app-km9qnv2f.js → app-7k8s9w5p.js} +18 -14
  6. package/dist/{assistant-5r8tcvvd.js → assistant-wswt2y7p.js} +40 -35
  7. package/dist/{boot-reembed-16rv9843.js → boot-reembed-9apm9qw6.js} +10 -9
  8. package/dist/{boot-reembed-swwzdgd7.js → boot-reembed-whzbdthj.js} +10 -9
  9. package/dist/{boot-scrub-sweep-zkr6vkqb.js → boot-scrub-sweep-ndzmvmgt.js} +11 -10
  10. package/dist/{boot-seeds-d8sp49t2.js → boot-seeds-e9sta0yt.js} +16 -13
  11. package/dist/{claude-adapter-yzzzh8jp.js → claude-adapter-4mqd3r6r.js} +19 -18
  12. package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-9wswb52m.js} +7 -5
  13. package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-tpe1effx.js} +6 -4
  14. package/dist/{claude-sdk-session-4whxere4.js → claude-sdk-session-q49ghmh9.js} +12402 -11850
  15. package/dist/{cli-ne7smj1b.js → cli-01xvj1rq.js} +10 -10
  16. package/dist/{cli-nwrdx840.js → cli-035vekcw.js} +3 -3
  17. package/dist/{cli-9xf7fdtp.js → cli-0pd8hzhc.js} +29 -6
  18. package/dist/{cli-tmhsxhb8.js → cli-0veb92a3.js} +28 -6
  19. package/dist/{cli-c3rk1v0x.js → cli-10jesr25.js} +3 -3
  20. package/dist/{cli-6thk4jz3.js → cli-1y7yywmj.js} +6 -6
  21. package/dist/{cli-6r2f7edk.js → cli-20krdhz5.js} +47 -19
  22. package/dist/{cli-rfs4vddv.js → cli-29rja109.js} +39 -20
  23. package/dist/cli-2m1ktfzz.js +17795 -0
  24. package/dist/{cli-na2pxe4f.js → cli-2pwa0q4d.js} +15 -4
  25. package/dist/{cli-7a93cv8c.js → cli-4mengw46.js} +441 -43
  26. package/dist/{cli-94b48jhk.js → cli-5twdke5x.js} +16 -14
  27. package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
  28. package/dist/cli-6cvfxs8r.js +47 -0
  29. package/dist/{cli-w1apjecb.js → cli-711vwbxn.js} +2 -2
  30. package/dist/{cli-r4fqfpwf.js → cli-78vv7446.js} +50 -27
  31. package/dist/{cli-srqq3gc5.js → cli-7n6s5man.js} +5 -5
  32. package/dist/{cli-m89t9jdf.js → cli-7x0g4sn1.js} +15416 -16024
  33. package/dist/{cli-2bw3w47j.js → cli-8wwxw8a3.js} +1 -1
  34. package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
  35. package/dist/{cli-ywm1azg9.js → cli-9jzdj90z.js} +8 -4
  36. package/dist/cli-9traj3dn.js +638 -0
  37. package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
  38. package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
  39. package/dist/cli-cvv9k0hh.js +10143 -0
  40. package/dist/{cli-anzdk0z4.js → cli-d9286m9h.js} +2 -2
  41. package/dist/cli-e3g5mbkz.js +776 -0
  42. package/dist/cli-f527ce74.js +781 -0
  43. package/dist/{cli-gmdajfw5.js → cli-gxzkg1de.js} +5020 -1729
  44. package/dist/{cli-451ks6aw.js → cli-h1arqn31.js} +1 -1
  45. package/dist/cli-hjwmhcg1.js +10622 -0
  46. package/dist/{cli-jpc4r224.js → cli-hqr88ew6.js} +19 -3
  47. package/dist/{cli-h7k0xtry.js → cli-hvqbtna4.js} +4 -1256
  48. package/dist/{cli-cd0hv9nh.js → cli-j67mh2vg.js} +2 -2
  49. package/dist/cli-jta2eyzc.js +619 -0
  50. package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
  51. package/dist/cli-kceah1eh.js +92 -0
  52. package/dist/{cli-d603qf86.js → cli-ksphgh48.js} +10 -8
  53. package/dist/{cli-3nxdmjrc.js → cli-mgz4nbgg.js} +4 -4
  54. package/dist/{cli-saqyage0.js → cli-mz5as5ha.js} +179 -27
  55. package/dist/cli-n2wq4j7m.js +6985 -0
  56. package/dist/{cli-ppy4nnnh.js → cli-n8ndw8j7.js} +2 -2
  57. package/dist/{cli-1w0vj3gw.js → cli-naqzr17j.js} +7 -7
  58. package/dist/{cli-0a7mm3zp.js → cli-nm1p8jfr.js} +25 -21
  59. package/dist/{cli-wrh08zjd.js → cli-p3zbc1rw.js} +5 -18
  60. package/dist/{cli-hsem16hb.js → cli-pe05f8yk.js} +29 -6
  61. package/dist/{cli-5wpw4rab.js → cli-qmzsbkvy.js} +5 -5
  62. package/dist/{cli-bv2etw2y.js → cli-qnm4e9e4.js} +99 -590
  63. package/dist/{cli-1x7da0de.js → cli-qqy4q48b.js} +8 -8
  64. package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
  65. package/dist/{cli-5er5gjbm.js → cli-r35rw5de.js} +15 -15
  66. package/dist/{cli-v3zhnxsb.js → cli-r610p9bs.js} +2 -2
  67. package/dist/{cli-7jykv7ef.js → cli-rc6pf5kv.js} +1 -1
  68. package/dist/{cli-x119kdba.js → cli-rdxm77k3.js} +1 -1
  69. package/dist/cli-rhs9pz33.js +294 -0
  70. package/dist/{cli-0p3enk35.js → cli-s69nfyeh.js} +9 -1
  71. package/dist/{cli-0kxf81jj.js → cli-sawv63e8.js} +2 -2
  72. package/dist/{cli-e3pmyt39.js → cli-sg19gbf0.js} +1 -1
  73. package/dist/{cli-d161g69q.js → cli-shk7r5cs.js} +57 -6
  74. package/dist/{cli-7pz3b7x5.js → cli-sksetb2q.js} +36 -1
  75. package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
  76. package/dist/{cli-db3m6zdt.js → cli-t02z59f2.js} +1 -1
  77. package/dist/{cli-b07hr3bt.js → cli-txqb9s38.js} +2 -2
  78. package/dist/{cli-s8z6x4b4.js → cli-v7g551te.js} +225 -113
  79. package/dist/{cli-rfz2ve55.js → cli-vgqzp4em.js} +3341 -955
  80. package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
  81. package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
  82. package/dist/cli-wfnemr1t.js +86 -0
  83. package/dist/cli-wmgrkscj.js +23254 -0
  84. package/dist/{cli-qm1448f9.js → cli-wms6x9db.js} +8 -8
  85. package/dist/{cli-tadfgd0t.js → cli-x1r545x8.js} +33 -4
  86. package/dist/{cli-xc7p7s3g.js → cli-xczsgshn.js} +6 -6
  87. package/dist/{cli-fmhj1ehj.js → cli-y3167wt1.js} +882 -271
  88. package/dist/{cli-r0byd61h.js → cli-yjmqpxt3.js} +17 -16
  89. package/dist/{cli-81r1wjyv.js → cli-z780ec7c.js} +1 -1
  90. package/dist/{cli-phcqp1b9.js → cli-zm9t2vde.js} +2 -2
  91. package/dist/cli.js +34 -49
  92. package/dist/{codex-adapter-r3dn4fp5.js → codex-adapter-4z16v9n0.js} +15 -14
  93. package/dist/{codex-login-841kv5fk.js → codex-login-pkepy2j1.js} +3 -2
  94. package/dist/{codex-session-runner-fwt793h4.js → codex-session-runner-rvms9y2x.js} +15 -14
  95. package/dist/{commands-z8fq9qna.js → commands-2a9rtyat.js} +11 -10
  96. package/dist/{controller-hq5ggpcp.js → controller-3k3madbn.js} +5 -4
  97. package/dist/{controllers-connect-3mf2btyj.js → controllers-connect-v9yn8zb9.js} +42 -37
  98. package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-98gbhyzn.js} +7 -6
  99. package/dist/{db-qfpq4bt7.js → db-eywwsnjw.js} +30 -9
  100. package/dist/{db-yyhqqrbf.js → db-ncypk9np.js} +12 -11
  101. package/dist/{devin-adapter-xgtj680j.js → devin-adapter-zeq8b9gz.js} +3 -2
  102. package/dist/{dispatcher-x0x7qfcq.js → dispatcher-w94kc575.js} +38 -33
  103. package/dist/{docker-f503k9p0.js → docker-b1e4cqab.js} +3 -2
  104. package/dist/{dsh-adapter-34etvb5m.js → dsh-adapter-47ztej36.js} +7 -6
  105. package/dist/{e2b-66xra4az.js → e2b-bbt8ey45.js} +4 -3
  106. package/dist/{e2b-xwhyj8cw.js → e2b-dp804sen.js} +4 -3
  107. package/dist/{event-bus-vjtv82gm.js → event-bus-j2jdg3qb.js} +3 -2
  108. package/dist/{external-channel-h1fjecwe.js → external-channel-zrkg8ar9.js} +11 -10
  109. package/dist/{google-generative-ai-szdxbpqg.js → google-generative-ai-g8db7x0f.js} +4 -2
  110. package/dist/{google-vertex-qzw3p36d.js → google-vertex-r2692q0r.js} +4 -2
  111. package/dist/{grok-adapter-e7mr287e.js → grok-adapter-s9ncp9vy.js} +18 -17
  112. package/dist/{handlers-znb9n7d4.js → handlers-kqftvjgw.js} +41 -36
  113. package/dist/{heartbeat-bm4qkn8d.js → heartbeat-9q96p8v9.js} +43 -38
  114. package/dist/{hook-254r4mza.js → hook-56qe10dp.js} +11 -23
  115. package/dist/{hook-xaa3q80s.js → hook-yy6rw42k.js} +12 -11
  116. package/dist/{http-3dgrgp8y.js → http-r2dnb8f8.js} +2411 -275
  117. package/dist/{index-fx3jqq1e.js → index-3gtmkhc6.js} +38 -33
  118. package/dist/{index-bdsqa799.js → index-3k5hkz7r.js} +43 -38
  119. package/dist/index-52j1aja4.js +3465 -0
  120. package/dist/{index-g2byveez.js → index-5e101240.js} +38 -33
  121. package/dist/{index-2ybk7khy.js → index-5wyfjc2c.js} +845 -683
  122. package/dist/index-9gw58n4k.js +193 -0
  123. package/dist/index-9j87mcm8.js +56305 -0
  124. package/dist/index-bsmcresk.js +79424 -0
  125. package/dist/index-mh85qhec.js +475 -0
  126. package/dist/{index-jd7sejm2.js → index-vxvhxxbn.js} +10 -9
  127. package/dist/index-we27kd31.js +12810 -0
  128. package/dist/{keepalive-6ywhpja1.js → keepalive-psj6j54c.js} +12 -11
  129. package/dist/{lead-cw45n21s.js → lead-hajz4688.js} +61 -56
  130. package/dist/{maintenance-ss1a1ge9.js → maintenance-ps02sb5m.js} +10 -9
  131. package/dist/{node-fkajaq96.js → node-mwb5r697.js} +2 -1
  132. package/dist/{oauth-refresh-sweep-3c6f8vyy.js → oauth-refresh-sweep-0284h93b.js} +11 -10
  133. package/dist/{onboard-8hzdhc1k.js → onboard-rbf6bg01.js} +11 -3
  134. package/dist/{opencode-adapter-qbchbcfz.js → opencode-adapter-13dcatgq.js} +18 -13
  135. package/dist/{otel-impl-e6mnvc4v.js → otel-impl-zvqcbhp7.js} +242 -868
  136. package/dist/{pi-mono-adapter-3c9g9snh.js → pi-mono-adapter-xxy47q4v.js} +244 -106
  137. package/dist/{pricing-refresh-gedkjdw0.js → pricing-refresh-kefx9v3t.js} +12 -11
  138. package/dist/{rbac-roles-dt4vh1yy.js → rbac-roles-3m36rxm2.js} +11 -10
  139. package/dist/{rbac-roles-eszdg6pm.js → rbac-roles-z76xv0hq.js} +12 -11
  140. package/dist/{render-v2-907cy6sa.js → render-v2-wz73bs25.js} +18 -14
  141. package/dist/{resume-42stcaz0.js → resume-k4wzge8w.js} +25 -21
  142. package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
  143. package/dist/{setup-adbc1c10.js → setup-2fp2pypp.js} +2 -2
  144. package/dist/{virtual-modules-rtmt494q.js → virtual-modules-9gkxqrap.js} +6 -5
  145. package/dist/{work-objects-wpj8ck95.js → work-objects-6k0ywz3m.js} +41 -36
  146. package/dist/{worker-bzdra9rf.js → worker-5v3rxsdh.js} +61 -56
  147. package/dist/{x-qfmygqqv.js → x-4mtdeym1.js} +3 -2
  148. package/openapi.json +1279 -329
  149. package/package.json +15 -15
  150. package/src/agentmail/handlers.ts +21 -11
  151. package/src/apps/definition.ts +16 -0
  152. package/src/azure-devops/api.ts +52 -2
  153. package/src/azure-devops/boards-sync.ts +50 -20
  154. package/src/azure-devops/index.ts +1 -0
  155. package/src/azure-devops/outbound.ts +95 -0
  156. package/src/be/boot-seeds.ts +11 -0
  157. package/src/be/config-refs.ts +60 -0
  158. package/src/be/db/model-profiles.ts +315 -0
  159. package/src/be/db/page-versions.ts +15 -0
  160. package/src/be/db/runtime.ts +35 -8
  161. package/src/be/db/skill-name-resolution.ts +36 -0
  162. package/src/be/db/tasks/read.ts +237 -0
  163. package/src/be/db/tasks/write.ts +7 -0
  164. package/src/be/db.ts +87 -36
  165. package/src/be/migrations/215_swarm_config_export_to_env.sql +34 -0
  166. package/src/be/migrations/216_task_resolved_effort.sql +5 -0
  167. package/src/be/migrations/217_chat_sdk_state.sql +104 -0
  168. package/src/be/migrations/219_relabel_pi_context_compactions.sql +22 -0
  169. package/src/be/migrations/220_model_profiles.sql +137 -0
  170. package/src/be/model-catalog-store.ts +5 -1
  171. package/src/be/model-tier-resolution.ts +155 -10
  172. package/src/be/model-validation.ts +12 -2
  173. package/src/be/models-catalog.ts +26 -1
  174. package/src/be/modelsdev-cache.json +198 -63
  175. package/src/be/modelsdev-cache.ts +9 -1
  176. package/src/be/script-credential-broker.ts +39 -2
  177. package/src/be/scripts/run-saved.ts +1 -0
  178. package/src/be/scripts/typecheck.ts +22 -8
  179. package/src/be/secret-registry.ts +6 -2
  180. package/src/be/seed/runner.ts +13 -1
  181. package/src/be/seed/state-db.ts +5 -0
  182. package/src/be/seed/types.ts +6 -0
  183. package/src/be/seed-model-profiles.ts +41 -0
  184. package/src/be/seed-pricing.ts +19 -2
  185. package/src/be/seed-scripts/catalog/heartbeat-jev-gate.ts +368 -0
  186. package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
  187. package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
  188. package/src/be/seed-scripts/index.ts +9 -0
  189. package/src/be/seed-skills/bundled-files.generated.json +0 -18
  190. package/src/be/seed-skills/index.ts +104 -3
  191. package/src/be/swarm-config-guard.ts +53 -0
  192. package/src/cli.tsx +0 -16
  193. package/src/commands/onboard/non-interactive.ts +4 -2
  194. package/src/commands/provider-credentials.ts +52 -6
  195. package/src/commands/runner.ts +193 -71
  196. package/src/e2b/env.ts +5 -0
  197. package/src/extensions/catalog.generated.json +17 -0
  198. package/src/extensions/contract-types.generated.ts +1 -1
  199. package/src/extensions/contract.ts +45 -0
  200. package/src/extensions/dispatcher.ts +7 -0
  201. package/src/extensions/loader.ts +10 -5
  202. package/src/extensions/post-bridge.ts +40 -0
  203. package/src/github/handlers.ts +11 -4
  204. package/src/heartbeat/heartbeat.ts +2 -1
  205. package/src/heartbeat/templates.ts +8 -5
  206. package/src/hooks/hook.ts +0 -26
  207. package/src/http/agents.ts +49 -2
  208. package/src/http/all-routes.ts +1 -1
  209. package/src/http/apps.ts +30 -3
  210. package/src/http/config.ts +62 -19
  211. package/src/http/core.ts +8 -0
  212. package/src/http/index.ts +25 -3
  213. package/src/http/integrations.ts +88 -1
  214. package/src/http/mcp.ts +15 -5
  215. package/src/http/model-profiles.ts +303 -0
  216. package/src/http/page-proxy.ts +2 -4
  217. package/src/http/pages-public.ts +13 -7
  218. package/src/http/pages.ts +3 -13
  219. package/src/http/poll.ts +42 -71
  220. package/src/http/requested-by.ts +54 -0
  221. package/src/http/script-runs.ts +1 -1
  222. package/src/http/scripts.ts +26 -2
  223. package/src/http/stats.ts +1 -30
  224. package/src/http/tasks.ts +79 -5
  225. package/src/http/utils.ts +14 -0
  226. package/src/http/webhooks.ts +160 -3
  227. package/src/http/x.ts +1 -0
  228. package/src/integrations/chat-sdk/adapters.ts +129 -0
  229. package/src/integrations/chat-sdk/attachments.ts +232 -0
  230. package/src/integrations/chat-sdk/background.ts +36 -0
  231. package/src/integrations/chat-sdk/commands.ts +194 -0
  232. package/src/integrations/chat-sdk/config.ts +198 -0
  233. package/src/integrations/chat-sdk/discord-api.ts +63 -0
  234. package/src/integrations/chat-sdk/discord-gateway.ts +185 -0
  235. package/src/integrations/chat-sdk/handlers.ts +28 -0
  236. package/src/integrations/chat-sdk/inbound.ts +426 -0
  237. package/src/integrations/chat-sdk/limits.ts +48 -0
  238. package/src/integrations/chat-sdk/logger.ts +81 -0
  239. package/src/integrations/chat-sdk/outbound.ts +123 -0
  240. package/src/integrations/chat-sdk/relay.ts +172 -0
  241. package/src/integrations/chat-sdk/router.ts +169 -0
  242. package/src/integrations/chat-sdk/runtime.ts +351 -0
  243. package/src/integrations/chat-sdk/schema.ts +245 -0
  244. package/src/integrations/chat-sdk/state.ts +243 -0
  245. package/src/integrations/chat-sdk/status.ts +244 -0
  246. package/src/integrations/chat-sdk/steering.ts +58 -0
  247. package/src/integrations/chat-sdk/teams-origin.ts +77 -0
  248. package/src/integrations/chat-sdk/telegram-api.ts +56 -0
  249. package/src/integrations/chat-sdk/templates.ts +16 -0
  250. package/src/integrations/chat-sdk/test-hooks.ts +37 -0
  251. package/src/integrations/chat-sdk/thread-buffer.ts +100 -0
  252. package/src/integrations/chat-sdk/typing.ts +65 -0
  253. package/src/{artifact-sdk → pages}/feedback-overlay.ts +65 -6
  254. package/src/pages/version.ts +4 -5
  255. package/src/prompts/base-prompt.ts +111 -45
  256. package/src/providers/acp-target-catalog.ts +6 -0
  257. package/src/providers/acp-targets.ts +56 -3
  258. package/src/providers/amp-adapter.ts +1 -1
  259. package/src/providers/claude-adapter.ts +1 -1
  260. package/src/providers/claude-flag-settings.ts +17 -5
  261. package/src/providers/claude-managed-adapter.ts +1 -1
  262. package/src/providers/claude-session-events.ts +6 -1
  263. package/src/providers/dsh-adapter.ts +1 -1
  264. package/src/providers/opencode-adapter.ts +243 -26
  265. package/src/providers/opencode-swarm-plugin.ts +31 -0
  266. package/src/providers/pi-mono-adapter.ts +398 -153
  267. package/src/providers/pi-mono-extension.ts +17 -3
  268. package/src/providers/pricing-sources.md +33 -2
  269. package/src/providers/reasoning-effort.ts +37 -0
  270. package/src/providers/types.ts +6 -2
  271. package/src/rbac/legacy-policy.ts +16 -2
  272. package/src/rbac/permissions.ts +26 -0
  273. package/src/scheduler/deferred-task-waits.ts +18 -5
  274. package/src/scheduler/scheduler.ts +11 -3
  275. package/src/scripts-runtime/executors/quickjs-prelude.ts +75 -6
  276. package/src/scripts-runtime/executors/quickjs-runner.ts +85 -8
  277. package/src/scripts-runtime/executors/quickjs-web-shims.ts +1041 -0
  278. package/src/scripts-runtime/extract-args-schema.ts +9 -8
  279. package/src/scripts-runtime/loader.ts +19 -7
  280. package/src/scripts-runtime/quickjs-compat.ts +464 -0
  281. package/src/scripts-runtime/sdk-allowlist.ts +12 -6
  282. package/src/scripts-runtime/swarm-sdk.ts +0 -11
  283. package/src/scripts-runtime/types/stdlib.d.ts +39 -15
  284. package/src/scripts-runtime/types/swarm-extension.d.ts +66 -1
  285. package/src/scripts-runtime/types/swarm-sdk.d.ts +39 -15
  286. package/src/server.ts +62 -19
  287. package/src/slack/blocks.ts +4 -2
  288. package/src/slack/event-dedup.ts +1 -1
  289. package/src/slack/reaction-shortcode.ts +14 -0
  290. package/src/slack/render-v2.ts +12 -7
  291. package/src/slack/responses.ts +5 -4
  292. package/src/slack/thread-buffer.ts +41 -22
  293. package/src/tasks/additive-buffer.ts +4 -2
  294. package/src/tasks/context-key.ts +60 -1
  295. package/src/tasks/model-pin.ts +67 -0
  296. package/src/tasks/worker-follow-up.ts +15 -33
  297. package/src/tests/acp-adapter.test.ts +42 -0
  298. package/src/tests/agentmail-filters.test.ts +47 -0
  299. package/src/tests/api-drain-worker-e2e.test.ts +1 -6
  300. package/src/tests/apps-spike2.test.ts +35 -0
  301. package/src/tests/azure-devops-outbound.test.ts +420 -0
  302. package/src/tests/base-prompt.test.ts +58 -54
  303. package/src/tests/chat-sdk-commands.test.ts +191 -0
  304. package/src/tests/chat-sdk-config.test.ts +334 -0
  305. package/src/tests/chat-sdk-discord-api.test.ts +68 -0
  306. package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
  307. package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
  308. package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
  309. package/src/tests/chat-sdk-harness.ts +146 -0
  310. package/src/tests/chat-sdk-inbound.test.ts +363 -0
  311. package/src/tests/chat-sdk-relay.test.ts +470 -0
  312. package/src/tests/chat-sdk-reload.test.ts +128 -0
  313. package/src/tests/chat-sdk-shutdown.test.ts +220 -0
  314. package/src/tests/chat-sdk-slack.test.ts +268 -0
  315. package/src/tests/chat-sdk-state.test.ts +163 -0
  316. package/src/tests/chat-sdk-status-route.test.ts +382 -0
  317. package/src/tests/chat-sdk-teams.test.ts +277 -0
  318. package/src/tests/chat-sdk-tools.test.ts +520 -0
  319. package/src/tests/chat-sdk-typing.test.ts +120 -0
  320. package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
  321. package/src/tests/claude-adapter-binary.test.ts +9 -4
  322. package/src/tests/claude-flag-settings.test.ts +11 -3
  323. package/src/tests/claude-managed-adapter.test.ts +1 -1
  324. package/src/tests/claude-sdk-lifecycle.test.ts +9 -3
  325. package/src/tests/claude-thinking-tokens.test.ts +57 -0
  326. package/src/tests/claude-worker-parity.test.ts +2 -7
  327. package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
  328. package/src/tests/config-refs.test.ts +66 -0
  329. package/src/tests/context-key.test.ts +19 -0
  330. package/src/tests/cors-allowlist.test.ts +25 -0
  331. package/src/tests/create-page-tool.test.ts +18 -0
  332. package/src/tests/credential-check.test.ts +139 -0
  333. package/src/tests/credentials.test.ts +21 -0
  334. package/src/tests/db-runtime.test.ts +61 -0
  335. package/src/tests/db-task-read-contract.test.ts +22 -0
  336. package/src/tests/db-task-write-contract.test.ts +11 -0
  337. package/src/tests/deferred-task-wake.test.ts +78 -1
  338. package/src/tests/docs-index-footprint.test.js +3 -3
  339. package/src/tests/dsh-adapter.test.ts +1 -1
  340. package/src/tests/enabled-capabilities.test.ts +20 -0
  341. package/src/tests/entrypoint-api-readiness.test.ts +14 -8
  342. package/src/tests/entrypoint-config-env-export.test.ts +5 -2
  343. package/src/tests/entrypoint-export-to-env.test.ts +78 -0
  344. package/src/tests/env-flag.test.ts +1 -0
  345. package/src/tests/explicit-model-validation.test.ts +105 -1
  346. package/src/tests/extensions-catalog.test.ts +1 -0
  347. package/src/tests/extensions-example-comms-adherence-gate.test.ts +413 -0
  348. package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
  349. package/src/tests/extensions-loader.test.ts +15 -0
  350. package/src/tests/extensions-post-bridge.test.ts +51 -0
  351. package/src/tests/fetch-resolved-env.test.ts +128 -0
  352. package/src/tests/fixtures/chat-sdk/telegram-private-text.json +10 -0
  353. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
  354. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
  355. package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
  356. package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
  357. package/src/tests/github-handlers.test.ts +35 -0
  358. package/src/tests/harness-provider-resolution.test.ts +12 -0
  359. package/src/tests/heartbeat-checklist.test.ts +3 -2
  360. package/src/tests/heartbeat-jev-gate-credentials.test.ts +168 -0
  361. package/src/tests/heartbeat-jev-gate.test.ts +385 -0
  362. package/src/tests/hook-runtime-close.test.ts +0 -2
  363. package/src/tests/http-api-integration.test.ts +0 -25
  364. package/src/tests/migration-046-budgets.test.ts +17 -16
  365. package/src/tests/migration-217-chat-sdk-state.test.ts +113 -0
  366. package/src/tests/model-profile-backcompat.test.ts +327 -0
  367. package/src/tests/model-profile-providers.test.ts +302 -0
  368. package/src/tests/model-profile-runtime-secrets.test.ts +223 -0
  369. package/src/tests/model-profiles-api.test.ts +614 -0
  370. package/src/tests/model-tier-resolution.test.ts +93 -0
  371. package/src/tests/models-catalog.test.ts +42 -1
  372. package/src/tests/openai-compatible-providers.test.ts +134 -0
  373. package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
  374. package/src/tests/opencode-adapter.test.ts +216 -2
  375. package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
  376. package/src/tests/opencode-shell-env.test.ts +145 -0
  377. package/src/tests/openrouter-base-url.test.ts +101 -151
  378. package/src/tests/page-proxy.test.ts +1 -1
  379. package/src/tests/pages-browser-sdk.test.ts +76 -0
  380. package/src/tests/pages-feedback-keys.test.ts +121 -0
  381. package/src/tests/pages-feedback.test.ts +4 -1
  382. package/src/tests/paused-tasks-requested-by.test.ts +102 -0
  383. package/src/tests/pi-context-compaction.test.ts +193 -0
  384. package/src/tests/pi-custom-provider-fake-server.test.ts +442 -0
  385. package/src/tests/pi-mono-adapter.test.ts +385 -5
  386. package/src/tests/pi-shell-env.test.ts +170 -0
  387. package/src/tests/profile-claim.test.ts +269 -0
  388. package/src/tests/prompt-template-remaining.test.ts +35 -0
  389. package/src/tests/quickjs-compat.test.ts +213 -0
  390. package/src/tests/rbac-engine.test.ts +32 -3
  391. package/src/tests/runner-exit-after-tasks.test.ts +0 -4
  392. package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
  393. package/src/tests/script-connections.test.ts +6 -0
  394. package/src/tests/script-executor-conformance.test.ts +252 -1
  395. package/src/tests/script-executor-quickjs.test.ts +96 -0
  396. package/src/tests/script-runs-http.test.ts +89 -0
  397. package/src/tests/scripts-http.test.ts +217 -1
  398. package/src/tests/scripts-only-gating.test.ts +2 -3
  399. package/src/tests/scripts-runtime.test.ts +58 -40
  400. package/src/tests/secret-scrubber.test.ts +96 -0
  401. package/src/tests/seed-model-profiles.test.ts +174 -0
  402. package/src/tests/seed-scripts.test.ts +2 -2
  403. package/src/tests/seed-skills-bundled-files.test.ts +45 -53
  404. package/src/tests/seed-skills-retire.test.ts +182 -0
  405. package/src/tests/send-task-requester-gate.test.ts +58 -0
  406. package/src/tests/session-cost-recompute-unit.test.ts +46 -0
  407. package/src/tests/skill-get-name-resolution.test.ts +137 -0
  408. package/src/tests/skill-invocations.test.ts +4 -2
  409. package/src/tests/slack-blocks.test.ts +36 -0
  410. package/src/tests/slack-inline-output.test.ts +14 -0
  411. package/src/tests/slack-reaction-config.test.ts +20 -0
  412. package/src/tests/slack-render-v2.test.ts +37 -0
  413. package/src/tests/slack-thread-buffer.test.ts +98 -1
  414. package/src/tests/sonnet-5-5-registry.test.ts +9 -1
  415. package/src/tests/swarm-config-export-to-env.test.ts +267 -0
  416. package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
  417. package/src/tests/swarm-diff.test.ts +1 -1
  418. package/src/tests/task-model-effort-rerun.test.ts +164 -0
  419. package/src/tests/task-session-prompts.test.ts +132 -0
  420. package/src/tests/task-tool-manifest.test.ts +14 -0
  421. package/src/tests/task-tools-ctx.test.ts +2 -0
  422. package/src/tests/tool-annotations.test.ts +6 -6
  423. package/src/tests/ui-logs-parser.test.ts +43 -0
  424. package/src/tests/used-by-route.test.ts +6 -0
  425. package/src/tests/vercel-ai-gateway.test.ts +149 -0
  426. package/src/tests/workflow-llm.test.ts +61 -0
  427. package/src/tests/workflow-swarm-script.test.ts +38 -0
  428. package/src/tests/workflow-wait-filter.test.ts +5 -3
  429. package/src/tools/chat-access.ts +41 -0
  430. package/src/tools/chat-open-dm.ts +59 -0
  431. package/src/tools/chat-post.ts +74 -0
  432. package/src/tools/chat-read-thread.ts +100 -0
  433. package/src/tools/chat-reply.ts +75 -0
  434. package/src/tools/create-page.ts +3 -13
  435. package/src/tools/model-catalog/index.ts +2 -1
  436. package/src/tools/model-profiles/list-model-profiles.ts +54 -0
  437. package/src/tools/register-chat-channel.ts +139 -0
  438. package/src/tools/request-human-input.ts +11 -3
  439. package/src/tools/script-apis.ts +5 -1
  440. package/src/tools/script-upsert.ts +4 -1
  441. package/src/tools/send-task.ts +48 -1
  442. package/src/tools/skills/skill-get.ts +17 -9
  443. package/src/tools/swarm-config/get-config.ts +2 -1
  444. package/src/tools/swarm-config/list-config.ts +2 -1
  445. package/src/tools/swarm-config/set-config.ts +16 -3
  446. package/src/tools/system-one-decide.ts +104 -0
  447. package/src/tools/task-action.ts +22 -1
  448. package/src/tools/tool-config.ts +14 -6
  449. package/src/types.ts +48 -3
  450. package/src/utils/config-env-export.ts +74 -0
  451. package/src/utils/credentials.test.ts +92 -0
  452. package/src/utils/credentials.ts +52 -4
  453. package/src/utils/harness-provider.ts +15 -6
  454. package/src/utils/runtime-model-catalog.ts +11 -1
  455. package/src/utils/secret-scrubber.ts +86 -10
  456. package/src/utils/task-tool-manifest.ts +19 -2
  457. package/src/utils/vcs-repo-match.ts +29 -0
  458. package/src/workflows/executors/raw-llm.ts +8 -3
  459. package/src/workflows/executors/swarm-script.ts +1 -0
  460. package/src/workflows/executors/system-one-decision.ts +21 -11
  461. package/src/workflows/executors/workflow-llm.ts +22 -0
  462. package/src/workflows/index.ts +21 -12
  463. package/templates/extensions/README.md +1 -0
  464. package/templates/extensions/comms-adherence-gate/README.md +88 -0
  465. package/templates/extensions/comms-adherence-gate/hooks.ts +489 -0
  466. package/templates/extensions/comms-adherence-gate/manifest.json +8 -0
  467. package/templates/skills/agent-browser/SKILL.md +1 -1
  468. package/templates/skills/agent-browser/content.md +1 -1
  469. package/templates/skills/apps/SKILL.md +8 -1
  470. package/templates/skills/apps/content.md +8 -1
  471. package/templates/skills/chat-sdk/config.json +14 -0
  472. package/templates/skills/chat-sdk/content.md +84 -0
  473. package/templates/skills/composio-gmail/content.md +7 -0
  474. package/templates/skills/composio-google-docs/content.md +1 -1
  475. package/templates/skills/email-domain-health/config.json +14 -0
  476. package/templates/skills/email-domain-health/content.md +131 -0
  477. package/templates/skills/kv-storage/content.md +2 -2
  478. package/templates/skills/pages/content.md +8 -10
  479. package/templates/skills/swarm-extensions/content.md +2 -0
  480. package/templates/skills/swarm-scripts/SKILL.md +4 -2
  481. package/templates/skills/swarm-scripts/config.json +1 -1
  482. package/templates/skills/swarm-scripts/content.md +4 -2
  483. package/templates/skills/workflow-iterate/content.md +38 -0
  484. package/dist/artifact-eczsknc3.js +0 -3843
  485. package/dist/cli-42qhyvwx.js +0 -33
  486. package/dist/cli-bd957dgb.js +0 -153
  487. package/dist/cli-q51yprfq.js +0 -1104
  488. package/dist/cli-t1ze64h3.js +0 -811
  489. package/dist/cli-tcc4wd5d.js +0 -56471
  490. package/dist/index-9ch1n761.js +0 -1102
  491. package/src/artifact-sdk/index.ts +0 -2
  492. package/src/artifact-sdk/localtunnel.d.ts +0 -20
  493. package/src/artifact-sdk/port.ts +0 -12
  494. package/src/artifact-sdk/server.ts +0 -183
  495. package/src/artifact-sdk/tunnel.ts +0 -19
  496. package/src/commands/artifact.ts +0 -249
  497. package/src/http/ecosystem.ts +0 -77
  498. package/src/tests/artifact-commands.test.ts +0 -92
  499. package/src/tests/artifact-sdk.test.ts +0 -793
  500. package/src/tests/register-service-security.test.ts +0 -194
  501. package/src/tools/list-services.ts +0 -107
  502. package/src/tools/register-service.ts +0 -177
  503. package/src/tools/unregister-service.ts +0 -73
  504. package/src/tools/update-service-status.ts +0 -96
  505. package/templates/skills/artifacts/config.json +0 -14
  506. package/templates/skills/artifacts/content.md +0 -344
  507. package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
  508. package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
  509. package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
  510. package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
  511. /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
@@ -78,6 +78,7 @@ afterAll(async () => {
78
78
  });
79
79
 
80
80
  describe("migration 196 skill invocations", () => {
81
+ // The full migration chain on a fresh DB can be slow under CI shard load.
81
82
  test("fresh DB has the counter columns and the invocations table", () => {
82
83
  const db = new Database(MIGRATION_DB_PATH, { create: true });
83
84
  try {
@@ -109,8 +110,9 @@ describe("migration 196 skill invocations", () => {
109
110
  } finally {
110
111
  db.close();
111
112
  }
112
- });
113
+ }, 30_000);
113
114
 
115
+ // The full migration chain on a fresh DB can be slow under CI shard load.
114
116
  test("existing DB keeps its skills and starts them at zero", async () => {
115
117
  await removeDb(MIGRATION_DB_PATH);
116
118
  const db = new Database(MIGRATION_DB_PATH, { create: true });
@@ -143,7 +145,7 @@ describe("migration 196 skill invocations", () => {
143
145
  } finally {
144
146
  db.close();
145
147
  }
146
- });
148
+ }, 30_000);
147
149
  });
148
150
 
149
151
  describe("skill.invoke ingestion", () => {
@@ -192,6 +192,42 @@ describe("buildCompletedBlocks", () => {
192
192
  });
193
193
  });
194
194
 
195
+ describe("completed status icon override", () => {
196
+ test("buildCompletedBlocks and tree lines use SLACK_STATUS_ICON_COMPLETED", () => {
197
+ process.env.SLACK_STATUS_ICON_COMPLETED = "bee-lgtm";
198
+ try {
199
+ const card = buildCompletedBlocks({
200
+ agentName: "Alpha",
201
+ taskId: "abcdef12-3456-7890-abcd-ef1234567890",
202
+ body: "Task output here",
203
+ });
204
+ expect(card[0].text.text.startsWith(":bee-lgtm: *Alpha*")).toBe(true);
205
+
206
+ const tree = buildTreeBlocks([
207
+ {
208
+ taskId: makeTaskId("icon0001"),
209
+ agentName: "Lead",
210
+ status: "completed",
211
+ children: [
212
+ {
213
+ taskId: makeTaskId("icon0002"),
214
+ agentName: "Worker",
215
+ status: "failed",
216
+ children: [],
217
+ },
218
+ ],
219
+ },
220
+ ]);
221
+ const text = tree[0].text.text;
222
+ expect(text).toContain(":bee-lgtm: *Lead*");
223
+ expect(text).toContain("❌ *Worker*");
224
+ expect(text).not.toContain("✅");
225
+ } finally {
226
+ delete process.env.SLACK_STATUS_ICON_COMPLETED;
227
+ }
228
+ });
229
+ });
230
+
195
231
  describe("buildFailedBlocks", () => {
196
232
  test("returns single-line header + error section", () => {
197
233
  const blocks = buildFailedBlocks({
@@ -71,4 +71,18 @@ describe("Slack inline completion output", () => {
71
71
  expect(text).toContain("|`abcdef12`>");
72
72
  expect(text).toContain(finalMarker);
73
73
  });
74
+
75
+ test("the inline output header uses SLACK_STATUS_ICON_COMPLETED", () => {
76
+ process.env.SLACK_STATUS_ICON_COMPLETED = ":bee-lgtm:";
77
+ try {
78
+ const [first] = formatInlineCompletionOutputChunks({
79
+ agentName: "Analyst",
80
+ taskId: TASK_ID,
81
+ output: "Done.",
82
+ });
83
+ expect(first?.startsWith(":bee-lgtm: *Analyst* completed with output")).toBe(true);
84
+ } finally {
85
+ delete process.env.SLACK_STATUS_ICON_COMPLETED;
86
+ }
87
+ });
74
88
  });
@@ -2,6 +2,7 @@ import { afterAll, beforeEach, describe, expect, spyOn, test } from "bun:test";
2
2
  import * as otelModule from "../otel";
3
3
  import { ackSlackMessage, finalizeSlackMessageReaction } from "../slack/ack";
4
4
  import {
5
+ completedStatusIcon,
5
6
  normalizeSlackReactionShortcode,
6
7
  reactionName,
7
8
  SLACK_REACTION_CONFIG_KEYS,
@@ -114,6 +115,25 @@ describe("reaction-shortcode.ts", () => {
114
115
  expect(normalizeSlackReactionShortcode("thumbsup::skin-tone-6::skin-tone-6")).toBeNull();
115
116
  });
116
117
 
118
+ test("completedStatusIcon defaults to ✅ and renders a configured name as :name:", () => {
119
+ const previous = process.env.SLACK_STATUS_ICON_COMPLETED;
120
+ try {
121
+ delete process.env.SLACK_STATUS_ICON_COMPLETED;
122
+ expect(completedStatusIcon()).toBe("✅");
123
+ for (const value of ["bee-lgtm", ":bee-lgtm:", " :Bee-LGTM: "]) {
124
+ process.env.SLACK_STATUS_ICON_COMPLETED = value;
125
+ expect(completedStatusIcon()).toBe(":bee-lgtm:");
126
+ }
127
+ for (const bad of ["", "::", "bee lgtm", "✅", "bee:lgtm"]) {
128
+ process.env.SLACK_STATUS_ICON_COMPLETED = bad;
129
+ expect(completedStatusIcon()).toBe("✅");
130
+ }
131
+ } finally {
132
+ if (previous === undefined) delete process.env.SLACK_STATUS_ICON_COMPLETED;
133
+ else process.env.SLACK_STATUS_ICON_COMPLETED = previous;
134
+ }
135
+ });
136
+
117
137
  test("no Slack source file outside ack.ts names a reaction shortcode or calls reactions.add", async () => {
118
138
  const glob = new Bun.Glob("*.ts");
119
139
  const dir = new URL("../slack/", import.meta.url);
@@ -1116,6 +1116,43 @@ describe("Slack renderer v2", () => {
1116
1116
  expect(doneText.startsWith("🧵 ✅ done")).toBe(true);
1117
1117
  });
1118
1118
 
1119
+ test("the completed glyph follows SLACK_STATUS_ICON_COMPLETED in tree, header and cards", async () => {
1120
+ const lead = await createAgent({ name: "Icon Lead", isLead: true, status: "idle" });
1121
+ const ask = await createTaskExtended("icon ask", { agentId: lead.id, source: "slack" });
1122
+ const now = new Date();
1123
+ const done = {
1124
+ ...ask,
1125
+ status: "completed" as const,
1126
+ output: "Shipped.",
1127
+ lastUpdatedAt: now.toISOString(),
1128
+ finishedAt: now.toISOString(),
1129
+ };
1130
+
1131
+ const defaultTree = await renderThreadTree([done], new Map(), now);
1132
+ expect(defaultTree.startsWith("🧵 ✅ done")).toBe(true);
1133
+ expect(defaultTree).toContain("↳ ✅ ");
1134
+ expect(await childOutcomeContent(done, false)).toBe("↳ ✅ Icon Lead — result: Shipped.");
1135
+
1136
+ process.env.SLACK_STATUS_ICON_COMPLETED = ":bee-lgtm:";
1137
+ try {
1138
+ const tree = await renderThreadTree([done], new Map(), now);
1139
+ expect(tree.startsWith("🧵 :bee-lgtm: done")).toBe(true);
1140
+ expect(tree).toContain("↳ :bee-lgtm: ");
1141
+ expect(tree).not.toContain("✅");
1142
+ expect(await childOutcomeContent(done, false)).toBe(
1143
+ "↳ :bee-lgtm: Icon Lead — result: Shipped.",
1144
+ );
1145
+ expect(await childOutcomeContent(done, true)).toBe("↳ :bee-lgtm: Icon Lead completed");
1146
+
1147
+ // Only the completed glyph moves; failure keeps its own icon.
1148
+ expect(
1149
+ await childOutcomeContent({ ...done, status: "failed", failureReason: "boom" }, false),
1150
+ ).toBe("↳ ❌ Icon Lead — failed: boom");
1151
+ } finally {
1152
+ delete process.env.SLACK_STATUS_ICON_COMPLETED;
1153
+ }
1154
+ });
1155
+
1119
1156
  test("a parked deferral reads waiting, and done once its wake-up settles", async () => {
1120
1157
  const lead = await createAgent({ name: "Parked Header Lead", isLead: true, status: "idle" });
1121
1158
  const ask = await createTaskExtended("parked header ask", {
@@ -1,16 +1,21 @@
1
- import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
1
+ import { afterAll, beforeAll, beforeEach, describe, expect, spyOn, test } from "bun:test";
2
2
  import { unlinkSync } from "node:fs";
3
3
  import {
4
4
  closeDb,
5
5
  createAgent,
6
6
  createTaskExtended,
7
7
  createUser,
8
+ getDbClient,
8
9
  getLatestActiveTaskInThread,
9
10
  getMostRecentTaskInThread,
10
11
  getSlackTasksInThread,
11
12
  initDb,
12
13
  } from "../be/db";
14
+ import { installExtension, setExtensionState } from "../be/extensions/db";
13
15
  import { type IdentityActor, linkIdentity } from "../be/users";
16
+ import { registerLoaded, unregister } from "../extensions/dispatcher";
17
+ import { ensureExtensionAgent } from "../extensions/identity";
18
+ import { cleanExtensionTmpRoot, loadExtension } from "../extensions/loader";
14
19
  import { registerMessageHandler } from "../slack/handlers";
15
20
  import {
16
21
  bufferThreadMessage,
@@ -18,6 +23,7 @@ import {
18
23
  instantFlush,
19
24
  isThreadBuffered,
20
25
  } from "../slack/thread-buffer";
26
+ import { loadBundleFixture } from "./fixtures/extensions/load";
21
27
 
22
28
  process.env.SLACK_RENDER_V2 = "false";
23
29
 
@@ -73,6 +79,27 @@ afterAll(() => {
73
79
  }
74
80
  });
75
81
 
82
+ async function loadBlockingExtension(reason: string) {
83
+ const bundle = await loadBundleFixture("minimal");
84
+ const name = "slack-buffer-block-test";
85
+ bundle.manifest = { ...bundle.manifest, name };
86
+ bundle.files[bundle.manifest.assets.hooks] = `
87
+ import { block, type SwarmExtension } from "swarm-extension";
88
+ const extension: SwarmExtension = (api) => {
89
+ api.on("pre.task.create", () => block(${JSON.stringify(reason)}));
90
+ };
91
+ export default extension;
92
+ `;
93
+ const installed = await installExtension(bundle);
94
+ const record = await setExtensionState(installed.extension.id, {
95
+ agentId: await ensureExtensionAgent(name),
96
+ });
97
+ if (!record) throw new Error("Failed to load the blocking Slack test extension");
98
+ const loaded = await loadExtension({ record, ...bundle });
99
+ registerLoaded(loaded);
100
+ return loaded;
101
+ }
102
+
76
103
  describe("Slack thread buffer", () => {
77
104
  describe("ADDITIVE_SLACK thread ingress", () => {
78
105
  const originalAdditiveSlack = process.env.ADDITIVE_SLACK;
@@ -612,4 +639,74 @@ describe("Slack thread buffer", () => {
612
639
  expect(task!.task).toContain("solo message");
613
640
  });
614
641
  });
642
+
643
+ test(
644
+ "logs a blocked pre-task.create once at info level with its reason scrubbed",
645
+ async () => {
646
+ const secret = `ghp_${"Z".repeat(36)}`;
647
+ const extensionName = "slack-buffer-block-test";
648
+ const loaded = await loadBlockingExtension(`Ticket required: ${secret}`);
649
+ const info = spyOn(console, "info").mockImplementation(() => {});
650
+ const error = spyOn(console, "error").mockImplementation(() => {});
651
+ const channelId = "C_BLOCKED_FLUSH";
652
+ const threadTs = "14000.0001";
653
+
654
+ try {
655
+ bufferThreadMessage(channelId, threadTs, "follow-up", "U1", "14000.0002");
656
+ await instantFlush(`${channelId}:${threadTs}`);
657
+
658
+ expect(info).toHaveBeenCalledTimes(1);
659
+ expect(info.mock.calls[0]?.[0]).toBe("[Slack] pre.task.create blocked:");
660
+ expect(info.mock.calls[0]?.[1]).toBe(extensionName);
661
+ expect(String(info.mock.calls[0]?.[2])).toContain("[REDACTED:");
662
+ expect(String(info.mock.calls[0]?.[2])).not.toContain(secret);
663
+ expect(error).not.toHaveBeenCalled();
664
+ expect(await getMostRecentTaskInThread(channelId, threadTs)).toBeNull();
665
+ } finally {
666
+ unregister(loaded.record.id);
667
+ await loaded.dispose();
668
+ info.mockRestore();
669
+ error.mockRestore();
670
+ await cleanExtensionTmpRoot();
671
+ }
672
+ },
673
+ { timeout: 15_000 },
674
+ );
675
+
676
+ test(
677
+ "does not treat unexpected task creation errors as blocked",
678
+ async () => {
679
+ const triggerName = "fail_slack_buffer_task_creation";
680
+ const failure = "simulated Slack task creation failure";
681
+ const channelId = "C_UNEXPECTED_FLUSH";
682
+ const threadTs = "14000.0003";
683
+ const info = spyOn(console, "info").mockImplementation(() => {});
684
+ const error = spyOn(console, "error").mockImplementation(() => {});
685
+
686
+ try {
687
+ await getDbClient().run(`DROP TRIGGER IF EXISTS ${triggerName}`);
688
+ await getDbClient().run(`
689
+ CREATE TRIGGER ${triggerName}
690
+ BEFORE INSERT ON agent_tasks
691
+ WHEN NEW.slackChannelId = '${channelId}'
692
+ BEGIN
693
+ SELECT RAISE(ABORT, '${failure}');
694
+ END
695
+ `);
696
+
697
+ bufferThreadMessage(channelId, threadTs, "follow-up", "U1", "14000.0004");
698
+ await instantFlush(`${channelId}:${threadTs}`);
699
+
700
+ expect(info).not.toHaveBeenCalled();
701
+ expect(error).toHaveBeenCalledTimes(1);
702
+ expect(String(error.mock.calls[0]?.[1])).toContain(failure);
703
+ expect(await getMostRecentTaskInThread(channelId, threadTs)).toBeNull();
704
+ } finally {
705
+ await getDbClient().run(`DROP TRIGGER IF EXISTS ${triggerName}`);
706
+ info.mockRestore();
707
+ error.mockRestore();
708
+ }
709
+ },
710
+ { timeout: 15_000 },
711
+ );
615
712
  });
@@ -23,10 +23,11 @@ describe("Sonnet 5.5 registry", () => {
23
23
  .filter((row) => row.provider === provider && row.model === model)
24
24
  .map((row) => [row.tokenClass, row.pricePerMillionUsd]),
25
25
  );
26
+ // Sonnet 5.5 cache hits cost 0.05x input, not the usual 0.1x.
26
27
  expect(rates).toEqual({
27
28
  input: 2,
28
29
  output: 10,
29
- cached_input: 0.2,
30
+ cached_input: 0.1,
30
31
  cache_write: 2.5,
31
32
  cache_write_1h: 4,
32
33
  });
@@ -41,4 +42,11 @@ describe("Sonnet 5.5 registry", () => {
41
42
  ).toBe(2);
42
43
  }
43
44
  });
45
+
46
+ test("the shortname fallback seeds the same cache-read rate when the snapshot lacks the model", () => {
47
+ const row = buildModelsDevSeedRows({ anthropic: { models: {} } }).find(
48
+ (r) => r.provider === "claude" && r.model === "sonnet" && r.tokenClass === "cached_input",
49
+ );
50
+ expect(row?.pricePerMillionUsd).toBe(0.1);
51
+ });
44
52
  });
@@ -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: [