@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
@@ -324,6 +324,8 @@ declare module "swarm-sdk" {
324
324
  types?: Array<"public" | "private" | "dm" | "mpim">;
325
325
  limit?: number;
326
326
  }): Promise<unknown>;
327
+ // --- chat sdk ---
328
+ chat_readThread(args: { threadId: string; limit?: number }): Promise<unknown>;
327
329
  // --- messaging ---
328
330
  message_read(args?: {
329
331
  channel?: string;
@@ -333,13 +335,6 @@ declare module "swarm-sdk" {
333
335
  mentionsOnly?: boolean;
334
336
  markAsRead?: boolean;
335
337
  }): Promise<unknown>;
336
- // --- services ---
337
- service_list(args?: {
338
- agentId?: string;
339
- name?: string;
340
- status?: "starting" | "healthy" | "unhealthy" | "stopped";
341
- includeOwn?: boolean;
342
- }): Promise<unknown>;
343
338
  // --- context / profiles ---
344
339
  context_history(args?: {
345
340
  agentId?: string;
@@ -434,6 +429,7 @@ declare module "swarm-sdk" {
434
429
  scope?: "global" | "agent" | "repo";
435
430
  scopeId?: string;
436
431
  isSecret?: boolean;
432
+ exportToEnv?: boolean;
437
433
  }): Promise<unknown>;
438
434
  config_delete(args: { id: string }): Promise<unknown>;
439
435
 
@@ -474,20 +470,36 @@ declare module "swarm-sdk" {
474
470
  slack_delete(args: { channelId: string; messageTs: string }): Promise<unknown>;
475
471
  slack_update(args: { channelId: string; messageTs: string; message: string }): Promise<unknown>;
476
472
 
473
+ // --- write: chat sdk ---
474
+ chat_reply(args: { text: string }): Promise<unknown>;
475
+ chat_post(args: {
476
+ adapter: "telegram" | "slack" | "discord" | "teams";
477
+ threadId?: string;
478
+ channelId?: string;
479
+ text: string;
480
+ }): Promise<unknown>;
481
+ chat_openDm(args: {
482
+ adapter: "telegram" | "slack" | "discord" | "teams";
483
+ userId: string;
484
+ }): Promise<unknown>;
485
+ chat_registerChannel(args: {
486
+ adapter: "telegram" | "slack" | "discord" | "teams";
487
+ channelId: string;
488
+ agentId?: string;
489
+ workflowId?: string;
490
+ name?: string;
491
+ }): Promise<unknown>;
492
+ chat_unregisterChannel(args: {
493
+ adapter: "telegram" | "slack" | "discord" | "teams";
494
+ channelId: string;
495
+ }): Promise<unknown>;
496
+
477
497
  // --- write: messaging (internal) ---
478
498
  message_post(args: { channel?: string; content: string; to?: string }): Promise<unknown>;
479
499
 
480
500
  // --- write: profiles ---
481
501
  profile_update(args: Record<string, unknown>): Promise<unknown>;
482
502
 
483
- // --- write: services ---
484
- service_register(args: Record<string, unknown>): Promise<unknown>;
485
- service_unregister(args: { name: string }): Promise<unknown>;
486
- service_updateStatus(args: {
487
- name: string;
488
- status: "starting" | "healthy" | "unhealthy" | "stopped";
489
- }): Promise<unknown>;
490
-
491
503
  // --- write: schedules ---
492
504
  schedule_create(args: Record<string, unknown>): Promise<unknown>;
493
505
  schedule_update(args: Record<string, unknown>): Promise<unknown>;
package/src/server.ts CHANGED
@@ -6,6 +6,7 @@ import { startPricingRefreshLoop } from "./be/pricing-refresh";
6
6
  import { isSteeringEnabled } from "./be/steering";
7
7
  import { registerGithubTaskReactions } from "./github/task-reactions";
8
8
  import { loadGlobalConfigsIntoEnv } from "./http/core";
9
+ import { isChatSdkEnabled } from "./integrations/chat-sdk/config";
9
10
  import { resolveTemplate } from "./prompts/resolver";
10
11
  import { isRbacEnabled } from "./rbac";
11
12
  import { getSlackConfiguration } from "./slack/config";
@@ -21,6 +22,10 @@ import { registerAppSyncTool } from "./tools/app-sync";
21
22
  import { registerAppUpsertTool } from "./tools/app-upsert";
22
23
  import { registerCancelApprovalRequestTool } from "./tools/cancel-approval-request";
23
24
  import { registerCancelTaskTool } from "./tools/cancel-task";
25
+ import { registerChatOpenDmTool } from "./tools/chat-open-dm";
26
+ import { registerChatPostTool } from "./tools/chat-post";
27
+ import { registerChatReadThreadTool } from "./tools/chat-read-thread";
28
+ import { registerChatReplyTool } from "./tools/chat-reply";
24
29
  import { registerContextDiffTool } from "./tools/context-diff";
25
30
  import { registerContextHistoryTool } from "./tools/context-history";
26
31
  import { registerCreateChannelTool } from "./tools/create-channel";
@@ -54,7 +59,6 @@ import {
54
59
  } from "./tools/kv";
55
60
  // Messaging capability
56
61
  import { registerListChannelsTool } from "./tools/list-channels";
57
- import { registerListServicesTool } from "./tools/list-services";
58
62
  import { registerManageUserTool } from "./tools/manage-user";
59
63
  // MCP Servers capability
60
64
  import {
@@ -91,12 +95,15 @@ import {
91
95
  } from "./tools/prompt-templates";
92
96
  import { registerReadMessagesTool } from "./tools/read-messages";
93
97
  import { registerRegisterAgentmailInboxTool } from "./tools/register-agentmail-inbox";
98
+ import {
99
+ registerRegisterChatChannelTool,
100
+ registerUnregisterChatChannelTool,
101
+ } from "./tools/register-chat-channel";
94
102
  import {
95
103
  registerRegisterKapsoNumberTool,
96
104
  registerUnregisterKapsoNumberTool,
97
105
  } from "./tools/register-kapso-number";
98
106
  // Services capability
99
- import { registerRegisterServiceTool } from "./tools/register-service";
100
107
  // Repo management tools
101
108
  import { registerGetReposTool, registerUpdateRepoTool } from "./tools/repos";
102
109
  import { registerRequestHumanInputTool } from "./tools/request-human-input";
@@ -178,10 +185,8 @@ import {
178
185
  registerTrackerSyncStatusTool,
179
186
  registerTrackerUnlinkTool,
180
187
  } from "./tools/tracker";
181
- import { registerUnregisterServiceTool } from "./tools/unregister-service";
182
188
  // Profiles capability
183
189
  import { registerUpdateProfileTool } from "./tools/update-profile";
184
- import { registerUpdateServiceStatusTool } from "./tools/update-service-status";
185
190
  import { setPreloadedTools } from "./tools/utils";
186
191
  import {
187
192
  registerReplyWhatsappMessageTool,
@@ -216,7 +221,6 @@ export const ALL_CAPABILITIES = [
216
221
  "prompt-templates",
217
222
  "mcp",
218
223
  "profiles",
219
- "services",
220
224
  "scheduling",
221
225
  "memory",
222
226
  "workflows",
@@ -230,6 +234,7 @@ export const ALL_CAPABILITIES = [
230
234
  "repo",
231
235
  "agentmail",
232
236
  "kapso",
237
+ "chat-sdk",
233
238
  "swarm-x",
234
239
  ] as const;
235
240
 
@@ -256,12 +261,12 @@ const DEFAULT_CAPABILITIES: string = [
256
261
  //
257
262
  // Disabled by default
258
263
  //
259
- // "services",
260
264
  // "prompt-templates",
261
265
  // "messaging",
262
266
  // "swarm-x",
263
267
  // "agentmail",
264
268
  // "kapso",
269
+ // "chat-sdk", (added by getEnabledCapabilities when CHAT_SDK_ENABLED is true)
265
270
  ].join(",");
266
271
 
267
272
  // Note: unknown names are kept (they never match hasCapability); workers
@@ -280,11 +285,22 @@ export function hasCapability(cap: CAPABILITIES_T): boolean {
280
285
  return getCapabilities().has(cap);
281
286
  }
282
287
 
288
+ const KNOWN_CAPABILITIES: ReadonlySet<string> = new Set(ALL_CAPABILITIES);
289
+
283
290
  export function getEnabledCapabilities(): CAPABILITIES_T[] {
284
- const capabilities = Array.from(getCapabilities());
291
+ // Only known flags: the register response validates against ALL_CAPABILITIES,
292
+ // so a retired name still listed in CAPABILITIES (e.g. `services`) would
293
+ // otherwise turn every agent registration into a 500.
294
+ const capabilities: CAPABILITIES_T[] = Array.from(getCapabilities()).filter(
295
+ (capability) => KNOWN_CAPABILITIES.has(capability) && capability !== "chat-sdk",
296
+ );
297
+ // The Chat SDK channel follows CHAT_SDK_ENABLED, not the CAPABILITIES list.
298
+ if (isChatSdkEnabled()) capabilities.push("chat-sdk");
285
299
  // Phase 1 has no HTTP receiver. Do not advertise usable Slack tools to
286
- // workers when HTTP (or an invalid transport) was selected.
287
- return getSlackConfiguration().mode === "socket"
300
+ // workers when HTTP (or an invalid transport) was selected, or when the
301
+ // built-in Slack app is off (SLACK_DISABLE, required by the Chat SDK Slack adapter).
302
+ const slack = getSlackConfiguration();
303
+ return slack.mode === "socket" && !slack.disabled
288
304
  ? capabilities
289
305
  : capabilities.filter((capability) => capability !== "slack");
290
306
  }
@@ -344,6 +360,13 @@ function applyToolAllowlist(server: McpServer, allowlist: readonly string[]): vo
344
360
  }
345
361
  }
346
362
 
363
+ function removeTools(server: McpServer, names: readonly string[]): void {
364
+ // oxlint-disable-next-line anti-slop/no-chained-type-assertions -- the MCP SDK keeps its tool registry private.
365
+ const tools = (server as unknown as { _registeredTools: Record<string, { remove(): void }> })
366
+ ._registeredTools;
367
+ for (const name of names) tools[name]?.remove();
368
+ }
369
+
347
370
  export async function createServer(
348
371
  opts: {
349
372
  scriptsOnly?: boolean;
@@ -351,6 +374,8 @@ export async function createServer(
351
374
  preloadedTools?: readonly string[];
352
375
  /** Raw SWARM_ENABLED_TOOLS value for this session; defaults to the env. */
353
376
  enabledTools?: string;
377
+ /** Tool names removed from this session after registration (task-context filters). */
378
+ excludedTools?: readonly string[];
354
379
  } = {},
355
380
  ) {
356
381
  // Reload env
@@ -368,8 +393,12 @@ export async function createServer(
368
393
  // fullSurface to register every tool group regardless of CAPABILITIES.
369
394
  // An allowlist also registers every group, then prunes to the listed names.
370
395
  // This shadows the module-level hasCapability for the registrations below.
396
+ // `chat-sdk` follows CHAT_SDK_ENABLED (as in getEnabledCapabilities), not
397
+ // the CAPABILITIES list.
371
398
  const hasCapability = (cap: CAPABILITIES_T): boolean =>
372
- opts.fullSurface === true || toolAllowlist !== undefined || getCapabilities().has(cap);
399
+ opts.fullSurface === true ||
400
+ toolAllowlist !== undefined ||
401
+ (cap === "chat-sdk" ? isChatSdkEnabled() : getCapabilities().has(cap));
373
402
 
374
403
  // Initialize database with WAL mode
375
404
  // Uses DATABASE_PATH env var for Docker volume compatibility (WAL needs .sqlite, .sqlite-wal, .sqlite-shm on same filesystem)
@@ -677,6 +706,16 @@ export async function createServer(
677
706
  registerReplyWhatsappMessageTool(server);
678
707
  }
679
708
 
709
+ // Chat SDK capability - Telegram/Slack/Discord/Teams through the Chat SDK channel (reply, post, DM, read, channel routes)
710
+ if (hasCapability("chat-sdk")) {
711
+ registerChatReplyTool(server);
712
+ registerChatPostTool(server);
713
+ registerChatOpenDmTool(server);
714
+ registerChatReadThreadTool(server);
715
+ registerRegisterChatChannelTool(server);
716
+ registerUnregisterChatChannelTool(server);
717
+ }
718
+
680
719
  // Swarm-x capability - external command routes mirroring the `agent-swarm x ...` CLI surface
681
720
  if (hasCapability("swarm-x")) {
682
721
  registerSwarmXTool(server);
@@ -693,15 +732,10 @@ export async function createServer(
693
732
  registerDeleteChannelTool(server);
694
733
  }
695
734
 
696
- // Services capability - PM2/background service registry
697
- if (hasCapability("services")) {
698
- registerRegisterServiceTool(server);
699
- registerUnregisterServiceTool(server);
700
- registerListServicesTool(server);
701
- registerUpdateServiceStatusTool(server);
702
- }
703
-
704
735
  if (toolAllowlist) applyToolAllowlist(server, toolAllowlist);
736
+ if (opts.fullSurface !== true && opts.excludedTools?.length) {
737
+ removeTools(server, opts.excludedTools);
738
+ }
705
739
 
706
740
  return server;
707
741
  }
@@ -1,10 +1,11 @@
1
1
  import type { App } from "@slack/bolt";
2
- import type { ChatUpdateArguments } from "@slack/web-api";
2
+ import type { ChatUpdateArguments, WebClient } from "@slack/web-api";
3
3
  import { cancelTask, getAgentById, getLeadAgent, getTaskById } from "../be/db";
4
4
  import { slackContextKey } from "../tasks/context-key";
5
5
  import { createTaskWithSiblingAwareness } from "../tasks/sibling-awareness";
6
6
  import { buildCancelledBlocks, getTaskLink } from "./blocks";
7
7
  import { resolveSlackUserId } from "./enrich";
8
+ import { EXTERNAL_CHANNEL_BLOCKED_REPLY, shouldBlockChannel } from "./external-channel";
8
9
  import { ignoreSlackInbound, noteSlackInboundSideEffect } from "./inbound-dispatch";
9
10
  import { ensureSlackThreadTree, isSlackRenderV2Enabled } from "./render-v2";
10
11
  import { getAgentDisplayName, getAgentEmoji } from "./responses";
@@ -14,6 +15,22 @@ type ChatUpdatePayload = ChatUpdateArguments & {
14
15
  unfurl_media: false;
15
16
  };
16
17
 
18
+ async function postExternalChannelNotice(
19
+ client: WebClient,
20
+ channelId: string,
21
+ userId: string,
22
+ ): Promise<void> {
23
+ try {
24
+ await client.chat.postEphemeral({
25
+ channel: channelId,
26
+ user: userId,
27
+ text: EXTERNAL_CHANNEL_BLOCKED_REPLY,
28
+ });
29
+ } catch (error) {
30
+ console.error("[Slack] Failed to post external channel notice:", error);
31
+ }
32
+ }
33
+
17
34
  export function registerActionHandlers(app: App): void {
18
35
  // "View Full Logs" — URL button, just ack (Slack opens the link automatically)
19
36
  app.action("view_task_logs", async ({ ack }) => {
@@ -31,6 +48,12 @@ export function registerActionHandlers(app: App): void {
31
48
  const triggerId = "trigger_id" in body ? body.trigger_id : undefined;
32
49
  if (!triggerId) return;
33
50
 
51
+ const channelId = "channel" in body ? body.channel?.id : undefined;
52
+ if (channelId && (await shouldBlockChannel(client, channelId))) {
53
+ await postExternalChannelNotice(client, channelId, body.user.id);
54
+ return ignoreSlackInbound("external_channel");
55
+ }
56
+
34
57
  try {
35
58
  await client.views.open({
36
59
  trigger_id: triggerId,
@@ -78,6 +101,11 @@ export function registerActionHandlers(app: App): void {
78
101
  return ignoreSlackInbound("follow_up_target_missing");
79
102
  }
80
103
 
104
+ if (await shouldBlockChannel(client, originalTask.slackChannelId)) {
105
+ await postExternalChannelNotice(client, originalTask.slackChannelId, body.user.id);
106
+ return ignoreSlackInbound("external_channel");
107
+ }
108
+
81
109
  const lead = await getLeadAgent();
82
110
  // Resolve via the shared cascade. Sample context = the modal callback ID
83
111
  // so operators can see *which* modal-submit triggered an unmapped entry.
package/src/slack/app.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import { App, LogLevel, SocketModeReceiver } from "@slack/bolt";
2
2
  import { emitBuiltInIntegrationConnectedOnce, ensureSlackRenderV2Activation } from "../be/db";
3
+ import { getNodeEnv } from "../utils/node-env";
3
4
  import { getSlackConfiguration } from "./config";
4
5
  import { type SlackConnectionState, setSlackConnectionState } from "./connection-state";
5
6
  import { installSlackEgressScrub } from "./egress-scrub";
7
+ import { installSlackExternalChannelGuard } from "./external-channel-egress";
6
8
  import { slackInboundOutcomeMiddleware } from "./inbound-dispatch";
7
9
  import { getSlackSocketModeBlockReason, SLACK_DEV_SOCKET_MODE_OPT_IN } from "./socket-mode-guard";
8
10
  import { startTaskWatcher, stopTaskWatcher } from "./watcher";
@@ -78,13 +80,15 @@ export async function initSlackApp(): Promise<App | null> {
78
80
  return null;
79
81
  }
80
82
 
81
- // Every client Bolt builds from here on scrubs outbound text.
83
+ // Every client Bolt builds from here on scrubs outbound text and refuses
84
+ // writes to external channels when SLACK_BLOCK_EXTERNAL_CHANNELS is on.
82
85
  installSlackEgressScrub();
86
+ installSlackExternalChannelGuard();
83
87
 
84
88
  // SLACK_API_URL points Bolt (Web API and apps.connections.open) at a mock Slack server for e2e tests.
85
89
  const slackApiUrl = process.env.SLACK_API_URL;
86
90
  const clientOptions = slackApiUrl ? { slackApiUrl } : undefined;
87
- const logLevel = process.env.NODE_ENV === "development" ? LogLevel.DEBUG : LogLevel.INFO;
91
+ const logLevel = getNodeEnv() === "development" ? LogLevel.DEBUG : LogLevel.INFO;
88
92
  // Build the receiver ourselves so its SocketModeClient lifecycle events can
89
93
  // feed /status. Bolt would otherwise forward clientOptions via installerOptions.
90
94
  receiver = new SocketModeReceiver({
@@ -123,6 +127,14 @@ export async function initSlackApp(): Promise<App | null> {
123
127
  const { createAssistant } = await import("./assistant");
124
128
  app.assistant(createAssistant());
125
129
 
130
+ // Report-only scan for external (Slack Connect) channels the bot is already in.
131
+ const { isBlockExternalEnabled, scanExternalChannelsOnBoot } = await import("./external-channel");
132
+ if (isBlockExternalEnabled()) {
133
+ scanExternalChannelsOnBoot(app.client).catch((error) => {
134
+ console.error("[Slack] External channel boot scan failed:", error);
135
+ });
136
+ }
137
+
126
138
  return app;
127
139
  }
128
140
 
@@ -1,10 +1,12 @@
1
1
  import { Assistant } from "@slack/bolt";
2
+ import type { WebClient } from "@slack/web-api";
2
3
  import { getAgentWorkingOnThread, getLeadAgent, getMostRecentTaskInThread } from "../be/db";
3
4
  import { resolveTemplate } from "../prompts/resolver";
4
5
  import { slackContextKey } from "../tasks/context-key";
5
6
  import { ackSlackMessage, reactionName } from "./ack";
6
7
  import { resolveSlackUserId, rewriteSlackMentions } from "./enrich";
7
8
  import { wasEventSeen } from "./event-dedup";
9
+ import { shouldBlockChannel } from "./external-channel";
8
10
  import type { SlackFile } from "./files";
9
11
  import {
10
12
  ignoreSlackInbound,
@@ -32,9 +34,24 @@ const isAdditiveSlack = () => isEnvFlagEnabled("ADDITIVE_SLACK", false);
32
34
  // a different agent (e.g. Devin) rather than our bot.
33
35
  let cachedBotUserId: string | null = null;
34
36
 
37
+ /** Startup and context callbacks write to the thread, so they get the inbound guard too. */
38
+ async function isExternalAssistantThread(
39
+ client: WebClient,
40
+ channelId: string,
41
+ body: unknown,
42
+ ): Promise<boolean> {
43
+ const envelope = (body as { is_ext_shared_channel?: boolean }).is_ext_shared_channel;
44
+ if (!(await shouldBlockChannel(client, channelId, envelope))) return false;
45
+ console.log(`[Slack] Ignoring assistant thread event in external channel ${channelId}`);
46
+ return true;
47
+ }
48
+
35
49
  export function createAssistant(): Assistant {
36
50
  return new Assistant({
37
- threadStarted: async ({ say, setSuggestedPrompts, saveThreadContext }) => {
51
+ threadStarted: async ({ event, body, client, say, setSuggestedPrompts, saveThreadContext }) => {
52
+ if (await isExternalAssistantThread(client, event.assistant_thread.channel_id, body)) {
53
+ return ignoreSlackInbound("external_channel");
54
+ }
38
55
  try {
39
56
  await saveThreadContext();
40
57
 
@@ -57,7 +74,10 @@ export function createAssistant(): Assistant {
57
74
  }
58
75
  },
59
76
 
60
- threadContextChanged: async ({ saveThreadContext }) => {
77
+ threadContextChanged: async ({ event, body, client, saveThreadContext }) => {
78
+ if (await isExternalAssistantThread(client, event.assistant_thread.channel_id, body)) {
79
+ return ignoreSlackInbound("external_channel");
80
+ }
61
81
  await saveThreadContext();
62
82
  },
63
83
 
@@ -71,6 +91,20 @@ export function createAssistant(): Assistant {
71
91
  return ignoreSlackInbound("duplicate_event");
72
92
  }
73
93
 
94
+ // Block external (Slack Connect) channels when SLACK_BLOCK_EXTERNAL_CHANNELS is on.
95
+ const externalCheckChannel = (message as { channel?: string }).channel;
96
+ if (
97
+ externalCheckChannel &&
98
+ (await shouldBlockChannel(
99
+ client,
100
+ externalCheckChannel,
101
+ (body as { is_ext_shared_channel?: boolean }).is_ext_shared_channel,
102
+ ))
103
+ ) {
104
+ console.log(`[Slack] Ignoring message in external channel ${externalCheckChannel}`);
105
+ return ignoreSlackInbound("external_channel");
106
+ }
107
+
74
108
  // Wrap setStatus/setTitle to swallow all errors gracefully.
75
109
  // These calls can fail for various reasons (no_permission when the thread
76
110
  // wasn't started by the assistant, network errors, etc.), so we log and continue.
@@ -1,6 +1,5 @@
1
1
  import type { WebClient } from "@slack/web-api";
2
-
3
- const logger = console;
2
+ import { getChannelExternality } from "./external-channel";
4
3
 
5
4
  type SlackErrorData = {
6
5
  error?: unknown;
@@ -36,20 +35,8 @@ export function slackMissingScopeMessage(error: unknown): string | undefined {
36
35
  * are the authoritative org-boundary signal per Slack's API docs.
37
36
  */
38
37
  async function isKnownExternalChannel(client: WebClient, channelId: string): Promise<boolean> {
39
- try {
40
- const resp = await client.conversations.info({ channel: channelId });
41
- const ch = (resp.channel ?? {}) as {
42
- is_ext_shared?: boolean;
43
- is_pending_ext_shared?: boolean;
44
- };
45
- return ch.is_ext_shared === true || ch.is_pending_ext_shared === true;
46
- } catch (error) {
47
- logger.warn(
48
- `[Slack] conversations.info failed for ${channelId}; attempting join fallback:`,
49
- error,
50
- );
51
- return false;
52
- }
38
+ // "unknown" (conversations.info failed) falls through to the join attempt.
39
+ return (await getChannelExternality(client, channelId)) === "external";
53
40
  }
54
41
 
55
42
  /**
@@ -1,11 +1,19 @@
1
1
  import type { App } from "@slack/bolt";
2
2
  import { getAllAgents, getAllTasks } from "../be/db";
3
3
  import { isEnvFlagEnabled } from "../utils/env-flag";
4
+ import { EXTERNAL_CHANNEL_BLOCKED_REPLY, shouldBlockChannel } from "./external-channel";
4
5
 
5
6
  export function registerCommandHandler(app: App): void {
6
- app.command("/agent-swarm-status", async ({ ack, respond }) => {
7
+ app.command("/agent-swarm-status", async ({ ack, respond, command, client }) => {
7
8
  await ack();
8
9
 
10
+ // The status reply lists task summaries; never show them in an external channel.
11
+ if (await shouldBlockChannel(client, command.channel_id)) {
12
+ console.log(`[Slack] Refusing /agent-swarm-status in external channel ${command.channel_id}`);
13
+ await respond({ response_type: "ephemeral", text: EXTERNAL_CHANNEL_BLOCKED_REPLY });
14
+ return;
15
+ }
16
+
9
17
  const agents = await getAllAgents();
10
18
  const tasks = await getAllTasks({ status: "in_progress" });
11
19
 
@@ -18,7 +18,7 @@
18
18
  * safe-but-tight bound.
19
19
  *
20
20
  * Single-pod-only. The API server (which owns the Slack socket) runs as a
21
- * single PM2 process; if that ever changes, swap this for a DB-backed table.
21
+ * single API process; if that ever changes, swap this for a DB-backed table.
22
22
  */
23
23
 
24
24
  const DEFAULT_TTL_MS = 300_000; // 5 minutes
@@ -0,0 +1,113 @@
1
+ import { webApi } from "@slack/bolt";
2
+ import type { WebClient } from "@slack/web-api";
3
+ import { type ChannelBlockReason, getChannelBlockReason } from "./external-channel";
4
+
5
+ /**
6
+ * Client-level external-channel guard for every outbound Slack write.
7
+ *
8
+ * Tools, the watcher, render-v2 streaming, outcome cards, progress edits and
9
+ * alerts all call `client.chat.*` / `filesUploadV2` directly, so the guard sits
10
+ * on `WebClient` itself, like `egress-scrub.ts`. The prototype is patched
11
+ * before any client is built, which covers Bolt's `app.client` and the
12
+ * per-request clients it hands to listeners. A no-op unless
13
+ * SLACK_BLOCK_EXTERNAL_CHANNELS is on.
14
+ */
15
+
16
+ /** Methods that publish content into a channel, and the argument naming it. */
17
+ const GUARDED_METHODS: Record<string, readonly string[]> = {
18
+ "chat.postMessage": ["channel"],
19
+ "chat.postEphemeral": ["channel"],
20
+ "chat.update": ["channel"],
21
+ "chat.scheduleMessage": ["channel"],
22
+ "chat.meMessage": ["channel"],
23
+ "chat.startStream": ["channel"],
24
+ "chat.appendStream": ["channel"],
25
+ "chat.stopStream": ["channel"],
26
+ "assistant.threads.setStatus": ["channel_id"],
27
+ "assistant.threads.setSuggestedPrompts": ["channel_id"],
28
+ "assistant.threads.setTitle": ["channel_id"],
29
+ "files.completeUploadExternal": ["channel_id", "channels"],
30
+ };
31
+
32
+ /** Slack-shaped error codes, so delivery code classifies them like platform errors. */
33
+ export const EXTERNAL_CHANNEL_BLOCKED_CODE = "external_channel_blocked";
34
+ export const EXTERNAL_CHANNEL_UNVERIFIED_CODE = "external_channel_unverified";
35
+
36
+ type Args = Record<string, unknown>;
37
+
38
+ /** Channel IDs named by a write's arguments (`channels` may be comma-separated). */
39
+ function targetChannels(fields: readonly string[], args: Args | undefined): string[] {
40
+ if (!args) return [];
41
+ const out: string[] = [];
42
+ for (const field of fields) {
43
+ const value = args[field];
44
+ if (typeof value !== "string") continue;
45
+ for (const id of value.split(",")) {
46
+ const trimmed = id.trim();
47
+ if (trimmed) out.push(trimmed);
48
+ }
49
+ }
50
+ return out;
51
+ }
52
+
53
+ function blockedError(method: string, channelId: string, reason: ChannelBlockReason): Error {
54
+ const code =
55
+ reason === "external" ? EXTERNAL_CHANNEL_BLOCKED_CODE : EXTERNAL_CHANNEL_UNVERIFIED_CODE;
56
+ const error = new Error(
57
+ `An API error occurred: ${code} (${method} to ${channelId} refused by SLACK_BLOCK_EXTERNAL_CHANNELS)`,
58
+ );
59
+ return Object.assign(error, {
60
+ code: webApi.ErrorCode.PlatformError,
61
+ data: { ok: false, error: code },
62
+ });
63
+ }
64
+
65
+ async function assertChannelsAllowed(
66
+ client: WebClient,
67
+ method: string,
68
+ channels: string[],
69
+ ): Promise<void> {
70
+ for (const channelId of channels) {
71
+ const reason = await getChannelBlockReason(client, channelId);
72
+ if (reason) {
73
+ console.warn(`[Slack] Refused ${method} to ${channelId} (${reason})`);
74
+ throw blockedError(method, channelId, reason);
75
+ }
76
+ }
77
+ }
78
+
79
+ const INSTALLED = Symbol.for("agent-swarm.slack-external-channel-guard");
80
+
81
+ type PatchableProto = {
82
+ apiCall: (method: string, options?: Args) => Promise<unknown>;
83
+ filesUploadV2: (options: Args) => Promise<unknown>;
84
+ [INSTALLED]?: true;
85
+ };
86
+
87
+ /**
88
+ * Route every `WebClient` built after this call through the guard. Idempotent.
89
+ * Call it before the Bolt `App` (and its receiver) are constructed.
90
+ */
91
+ export function installSlackExternalChannelGuard(): void {
92
+ // oxlint-disable-next-line anti-slop/no-chained-type-assertions -- we patch private WebClient prototype methods.
93
+ const proto = webApi.WebClient.prototype as unknown as PatchableProto;
94
+ if (proto[INSTALLED]) return;
95
+ const originalApiCall = proto.apiCall;
96
+ const originalUpload = proto.filesUploadV2;
97
+ proto.apiCall = async function (this: WebClient, method: string, options?: Args) {
98
+ const fields = GUARDED_METHODS[method];
99
+ if (fields) await assertChannelsAllowed(this, method, targetChannels(fields, options));
100
+ return originalApiCall.call(this, method, options);
101
+ };
102
+ // Check before the bytes leave: completeUploadExternal is guarded too, but by
103
+ // then the file already sits in Slack storage.
104
+ proto.filesUploadV2 = async function (this: WebClient, options: Args) {
105
+ await assertChannelsAllowed(
106
+ this,
107
+ "files.uploadV2",
108
+ targetChannels(["channel_id", "channels"], options),
109
+ );
110
+ return originalUpload.call(this, options);
111
+ };
112
+ proto[INSTALLED] = true;
113
+ }