@desplega.ai/agent-swarm 1.172.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (525) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-fpecx1g1.js → acp-adapter-sj2g0m84.js} +18 -17
  3. package/dist/{actions-pw87a1a8.js → actions-fegk44gr.js} +65 -35
  4. package/dist/{amp-adapter-8jem2bc0.js → amp-adapter-ad8ft89x.js} +8 -7
  5. package/dist/{anthropic-messages-8ee2f22q.js → anthropic-messages-r6czkjv1.js} +7 -7
  6. package/dist/{app-wmf0m843.js → app-kfvgbvzy.js} +19 -13
  7. package/dist/{assistant-emp1e108.js → assistant-z7zdy9ja.js} +65 -38
  8. package/dist/{boot-reembed-1de4f4aj.js → boot-reembed-5c2z0mbe.js} +11 -9
  9. package/dist/{boot-reembed-4ymn9atn.js → boot-reembed-j8xa181e.js} +11 -9
  10. package/dist/{boot-scrub-sweep-adhk1s8c.js → boot-scrub-sweep-hnkn3rgt.js} +12 -10
  11. package/dist/{boot-seeds-8q637aew.js → boot-seeds-kwjq4d2z.js} +15 -13
  12. package/dist/{claude-adapter-t26cv8a4.js → claude-adapter-9vmvpvgd.js} +20 -19
  13. package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-k9qae05j.js} +7 -5
  14. package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-q54zx5q2.js} +6 -4
  15. package/dist/{claude-sdk-session-gsfsh662.js → claude-sdk-session-9jye6cxr.js} +12698 -11995
  16. package/dist/{cli-k46r9hmk.js → cli-03gedhng.js} +16 -14
  17. package/dist/{cli-kb4ehzx5.js → cli-1e4b6bzh.js} +7 -7
  18. package/dist/{cli-d603qf86.js → cli-29jc5q7w.js} +10 -8
  19. package/dist/cli-2m1ktfzz.js +17795 -0
  20. package/dist/{cli-8vs9trd4.js → cli-3dj8k4vy.js} +1 -1
  21. package/dist/{cli-zxm9p3x4.js → cli-3fbmmawm.js} +5 -5
  22. package/dist/{cli-gmdajfw5.js → cli-4jxm2qtz.js} +4987 -1708
  23. package/dist/{cli-tadfgd0t.js → cli-5hkm7whv.js} +33 -4
  24. package/dist/{cli-6jb2rf77.js → cli-5t4f29ez.js} +3 -3
  25. package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
  26. package/dist/cli-6cvfxs8r.js +47 -0
  27. package/dist/{cli-pj6x9qce.js → cli-6jyj59nb.js} +2 -2
  28. package/dist/{cli-388egyf6.js → cli-6razj6t4.js} +2 -2
  29. package/dist/{cli-qsztpfry.js → cli-74ahz61x.js} +2 -2
  30. package/dist/{cli-4nz8p1p5.js → cli-7x0g4sn1.js} +15474 -16082
  31. package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
  32. package/dist/{cli-81r1wjyv.js → cli-9nfx44eh.js} +1 -1
  33. package/dist/cli-9traj3dn.js +638 -0
  34. package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
  35. package/dist/{cli-bf7485pm.js → cli-apx87jne.js} +2 -2
  36. package/dist/{cli-ztrv9y21.js → cli-bzszjf2p.js} +3689 -1081
  37. package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
  38. package/dist/{cli-hsem16hb.js → cli-cgtksawx.js} +7 -4
  39. package/dist/{cli-db3m6zdt.js → cli-d2qr7aj4.js} +1 -1
  40. package/dist/{cli-1hgat6pa.js → cli-d5f9ed5c.js} +5 -5
  41. package/dist/cli-e3g5mbkz.js +776 -0
  42. package/dist/{cli-7jykv7ef.js → cli-e6mpjhed.js} +1 -1
  43. package/dist/{cli-j6kpj9az.js → cli-ee9gtz70.js} +1553 -68
  44. package/dist/{cli-e0a9sk00.js → cli-eejsgvm4.js} +4 -4
  45. package/dist/{cli-tgpfnm6r.js → cli-ef1hg1wv.js} +518 -59
  46. package/dist/cli-f527ce74.js +781 -0
  47. package/dist/{cli-ppy4nnnh.js → cli-f7kr7svz.js} +2 -2
  48. package/dist/cli-hjwmhcg1.js +10622 -0
  49. package/dist/{cli-2bw3w47j.js → cli-hnhtk6cj.js} +1 -1
  50. package/dist/{cli-ywm1azg9.js → cli-hnmhtzvh.js} +6 -4
  51. package/dist/{cli-4fnb6884.js → cli-hvqbtna4.js} +7 -1259
  52. package/dist/{cli-pstq9888.js → cli-j0pfptdp.js} +220 -103
  53. package/dist/cli-jta2eyzc.js +619 -0
  54. package/dist/{cli-esnpehf5.js → cli-k382tshb.js} +12 -13
  55. package/dist/cli-k3dp5tpf.js +263 -0
  56. package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
  57. package/dist/cli-kceah1eh.js +92 -0
  58. package/dist/{cli-prrt9fa0.js → cli-ke896fcf.js} +10 -10
  59. package/dist/{cli-nv4zd0b9.js → cli-kt6zqg0e.js} +6 -6
  60. package/dist/{cli-g6t9texm.js → cli-m50t4309.js} +5 -18
  61. package/dist/cli-n2wq4j7m.js +6985 -0
  62. package/dist/{cli-c2pq2rjb.js → cli-n3hzg89b.js} +46 -15
  63. package/dist/{cli-tmhsxhb8.js → cli-n5vwg842.js} +23 -6
  64. package/dist/{cli-5rv1j9ga.js → cli-ne236afy.js} +53 -7
  65. package/dist/cli-p0sg24zp.js +16 -0
  66. package/dist/{cli-d161g69q.js → cli-p1x85d2t.js} +50 -2
  67. package/dist/{cli-7pz3b7x5.js → cli-przpmdgr.js} +25 -0
  68. package/dist/{cli-g4f5pj26.js → cli-q0ke1yww.js} +111 -25
  69. package/dist/{cli-e3pmyt39.js → cli-q50942rs.js} +1 -1
  70. package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
  71. package/dist/{cli-gj81e47t.js → cli-r2pnvj8g.js} +2 -2
  72. package/dist/{cli-r8smj8b8.js → cli-r62a35ea.js} +19 -3
  73. package/dist/{cli-cd0hv9nh.js → cli-ra0xzggj.js} +2 -2
  74. package/dist/cli-rhs9pz33.js +294 -0
  75. package/dist/{cli-nyhb1r6x.js → cli-s2sp957d.js} +52 -29
  76. package/dist/{cli-1x7da0de.js → cli-s4setq91.js} +8 -8
  77. package/dist/{cli-xczpdp9e.js → cli-se8w6wny.js} +6 -6
  78. package/dist/cli-skxvvpap.js +10140 -0
  79. package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
  80. package/dist/{cli-0p3enk35.js → cli-tqaazemc.js} +9 -1
  81. package/dist/{cli-cf69s3ew.js → cli-tr4sxp68.js} +3 -3
  82. package/dist/{cli-8hzfb6xz.js → cli-tsde1hdr.js} +15 -15
  83. package/dist/{cli-cceskcvt.js → cli-txqb9s38.js} +8 -8
  84. package/dist/{cli-aspcaef3.js → cli-v1yb0rqb.js} +6 -6
  85. package/dist/{cli-j1pmc07z.js → cli-vatyhshy.js} +268 -40
  86. package/dist/{cli-04emfe2q.js → cli-vdach5a9.js} +5 -5
  87. package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
  88. package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
  89. package/dist/{cli-hwwvy36w.js → cli-wayw93nt.js} +3 -3
  90. package/dist/cli-wmgrkscj.js +23254 -0
  91. package/dist/{cli-gp1rtyvk.js → cli-z5jjpaxw.js} +29 -6
  92. package/dist/{cli-451ks6aw.js → cli-zkpks3r3.js} +1 -1
  93. package/dist/cli.js +32 -48
  94. package/dist/{codex-adapter-m4tgdysy.js → codex-adapter-y81sssk0.js} +16 -15
  95. package/dist/{codex-login-841kv5fk.js → codex-login-f2rcfpp9.js} +3 -2
  96. package/dist/{codex-session-runner-ymwzm6ea.js → codex-session-runner-8vx4j6a9.js} +16 -15
  97. package/dist/{commands-n0hshcvs.js → commands-kcpvpcrr.js} +21 -10
  98. package/dist/{controller-hq5ggpcp.js → controller-ywrmt6yd.js} +5 -4
  99. package/dist/{controllers-connect-y07cqcvy.js → controllers-connect-kwpvj3rf.js} +45 -38
  100. package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-cehv1qns.js} +7 -6
  101. package/dist/{db-hkqvrdcb.js → db-k8ankj20.js} +13 -11
  102. package/dist/{db-4w7tmt1g.js → db-ww5d7jq3.js} +29 -9
  103. package/dist/{devin-adapter-xgtj680j.js → devin-adapter-x1022qb1.js} +3 -2
  104. package/dist/{dispatcher-5sd69y14.js → dispatcher-e8gq5m68.js} +41 -34
  105. package/dist/{docker-f503k9p0.js → docker-ff6y1190.js} +3 -2
  106. package/dist/{dsh-adapter-2h8m4cab.js → dsh-adapter-3epjm3af.js} +7 -6
  107. package/dist/{e2b-66xra4az.js → e2b-8ygwhg0f.js} +4 -3
  108. package/dist/{e2b-xwhyj8cw.js → e2b-swhnpw3n.js} +4 -3
  109. package/dist/{event-bus-vjtv82gm.js → event-bus-6axnngdj.js} +3 -2
  110. package/dist/external-channel-h3359cwn.js +52 -0
  111. package/dist/{google-generative-ai-7pavrbv7.js → google-generative-ai-g8db7x0f.js} +5 -3
  112. package/dist/{google-vertex-3f1jk41f.js → google-vertex-r2692q0r.js} +5 -3
  113. package/dist/{grok-adapter-8m9yqzbq.js → grok-adapter-0d4x7gkx.js} +19 -18
  114. package/dist/{handlers-s20xr10r.js → handlers-an1gzv21.js} +44 -37
  115. package/dist/{heartbeat-3k31q4g2.js → heartbeat-6dakeb61.js} +46 -39
  116. package/dist/{hook-gdn6a2fn.js → hook-6v6cv6d5.js} +12 -24
  117. package/dist/{hook-ygwerrdh.js → hook-sa5xye4y.js} +13 -12
  118. package/dist/{http-jdteeg81.js → http-r7f3eky0.js} +1598 -279
  119. package/dist/index-52j1aja4.js +3465 -0
  120. package/dist/{index-e0snym4t.js → index-7ep4gzdk.js} +41 -34
  121. package/dist/index-9gw58n4k.js +193 -0
  122. package/dist/index-9j87mcm8.js +56305 -0
  123. package/dist/index-bsmcresk.js +79424 -0
  124. package/dist/index-mh85qhec.js +475 -0
  125. package/dist/{index-vm3bm9t7.js → index-rmpw9a8q.js} +41 -34
  126. package/dist/{index-6ksewd5y.js → index-s2wxgzr0.js} +1015 -732
  127. package/dist/{index-tsszt7g9.js → index-v1v6n7hg.js} +46 -39
  128. package/dist/index-we27kd31.js +12810 -0
  129. package/dist/{index-ffqzqgwb.js → index-zk96aq1k.js} +11 -9
  130. package/dist/{keepalive-jekc896t.js → keepalive-be9vwy5h.js} +13 -11
  131. package/dist/{lead-4k9s9szx.js → lead-0861cwrf.js} +64 -57
  132. package/dist/{maintenance-shazch4n.js → maintenance-mzzgc8bn.js} +11 -9
  133. package/dist/node-c9we95xf.js +1 -1
  134. package/dist/{node-fkajaq96.js → node-mn1zs7an.js} +2 -1
  135. package/dist/{oauth-refresh-sweep-5gb36kn8.js → oauth-refresh-sweep-cpdnfwdj.js} +12 -10
  136. package/dist/{onboard-ydrbnvww.js → onboard-fh8qs4r3.js} +11 -3
  137. package/dist/{opencode-adapter-5zh0he20.js → opencode-adapter-nm42wwj8.js} +19 -14
  138. package/dist/{otel-impl-6pf5cv86.js → otel-impl-x6c1c9g4.js} +248 -869
  139. package/dist/{pi-mono-adapter-ef9wwx9m.js → pi-mono-adapter-9n2ya240.js} +245 -107
  140. package/dist/{pricing-refresh-s52nsa5q.js → pricing-refresh-qb0rv0ap.js} +13 -11
  141. package/dist/{rbac-roles-aq3msh4e.js → rbac-roles-1gzdwbh1.js} +12 -10
  142. package/dist/{rbac-roles-q5gb5e8v.js → rbac-roles-3mraey52.js} +13 -11
  143. package/dist/{render-v2-pd1rg54q.js → render-v2-agpa45zz.js} +19 -13
  144. package/dist/{resume-gw4a2c6v.js → resume-x0ydy9s9.js} +27 -21
  145. package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
  146. package/dist/{setup-jda1ksdh.js → setup-as9ga0d6.js} +2 -2
  147. package/dist/{virtual-modules-b3ga2m65.js → virtual-modules-9gkxqrap.js} +7 -6
  148. package/dist/{work-objects-tb7ycye8.js → work-objects-y5g1y7ev.js} +49 -37
  149. package/dist/{worker-njjccz5d.js → worker-860c3e38.js} +64 -57
  150. package/dist/{x-qfmygqqv.js → x-m477fr0h.js} +3 -2
  151. package/openapi.json +951 -356
  152. package/package.json +12 -13
  153. package/src/apps/catalog.generated.json +1309 -53
  154. package/src/apps/page-validator.ts +93 -31
  155. package/src/azure-devops/api.ts +94 -18
  156. package/src/azure-devops/auth.ts +32 -0
  157. package/src/azure-devops/boards-sync.ts +708 -0
  158. package/src/azure-devops/handlers.ts +52 -8
  159. package/src/azure-devops/html.ts +26 -0
  160. package/src/azure-devops/index.ts +15 -0
  161. package/src/azure-devops/templates.ts +86 -0
  162. package/src/azure-devops/types.ts +65 -1
  163. package/src/be/config-refs.ts +60 -0
  164. package/src/be/db/page-versions.ts +15 -0
  165. package/src/be/db/runtime.ts +35 -8
  166. package/src/be/db/skill-name-resolution.ts +36 -0
  167. package/src/be/db/tasks/read.ts +230 -0
  168. package/src/be/db/tasks/write.ts +7 -0
  169. package/src/be/db.ts +74 -13
  170. package/src/be/migrations/213_script_connections_sql.sql +79 -0
  171. package/src/be/migrations/215_swarm_config_export_to_env.sql +34 -0
  172. package/src/be/migrations/216_task_resolved_effort.sql +5 -0
  173. package/src/be/migrations/217_chat_sdk_state.sql +104 -0
  174. package/src/be/model-catalog-store.ts +5 -1
  175. package/src/be/model-tier-resolution.ts +12 -1
  176. package/src/be/model-validation.ts +5 -2
  177. package/src/be/models-catalog.ts +26 -1
  178. package/src/be/modelsdev-cache.json +198 -63
  179. package/src/be/modelsdev-cache.ts +9 -1
  180. package/src/be/script-connections.ts +47 -8
  181. package/src/be/script-credential-broker.ts +39 -2
  182. package/src/be/scripts/run-saved.ts +1 -0
  183. package/src/be/scripts/typecheck.ts +10 -8
  184. package/src/be/seed/runner.ts +13 -1
  185. package/src/be/seed/state-db.ts +5 -0
  186. package/src/be/seed/types.ts +6 -0
  187. package/src/be/seed-pricing.ts +19 -2
  188. package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
  189. package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
  190. package/src/be/seed-skills/bundled-files.generated.json +10 -18
  191. package/src/be/seed-skills/index.ts +107 -3
  192. package/src/be/sql-connections.ts +118 -0
  193. package/src/be/swarm-config-guard.ts +53 -0
  194. package/src/cli.tsx +0 -16
  195. package/src/commands/onboard/non-interactive.ts +4 -2
  196. package/src/commands/profile-sync.ts +5 -3
  197. package/src/commands/provider-credentials.ts +52 -6
  198. package/src/commands/runner.ts +196 -56
  199. package/src/e2b/env.ts +5 -0
  200. package/src/extensions/contract-types.generated.ts +1 -1
  201. package/src/extensions/contract.ts +45 -0
  202. package/src/extensions/dispatcher.ts +7 -0
  203. package/src/extensions/post-bridge.ts +40 -0
  204. package/src/github/handlers.ts +11 -4
  205. package/src/heartbeat/templates.ts +8 -5
  206. package/src/hooks/hook.ts +0 -26
  207. package/src/http/all-routes.ts +0 -1
  208. package/src/http/config.ts +36 -17
  209. package/src/http/core.ts +4 -0
  210. package/src/http/index.ts +14 -2
  211. package/src/http/integrations.ts +88 -1
  212. package/src/http/mcp-oauth.ts +6 -13
  213. package/src/http/mcp.ts +15 -5
  214. package/src/http/page-proxy.ts +2 -4
  215. package/src/http/pages-public.ts +6 -5
  216. package/src/http/pages.ts +5 -14
  217. package/src/http/poll.ts +28 -68
  218. package/src/http/requested-by.ts +54 -0
  219. package/src/http/route-def.ts +7 -6
  220. package/src/http/script-connection-proxy.ts +51 -4
  221. package/src/http/script-connections.ts +5 -2
  222. package/src/http/scripts.ts +1 -0
  223. package/src/http/session-cost-recompute.ts +12 -2
  224. package/src/http/session-data.ts +4 -0
  225. package/src/http/stats.ts +1 -30
  226. package/src/http/tasks.ts +61 -5
  227. package/src/http/utils.ts +14 -0
  228. package/src/http/webhooks.ts +183 -2
  229. package/src/http/x.ts +1 -0
  230. package/src/integrations/chat-sdk/adapters.ts +129 -0
  231. package/src/integrations/chat-sdk/attachments.ts +232 -0
  232. package/src/integrations/chat-sdk/background.ts +36 -0
  233. package/src/integrations/chat-sdk/commands.ts +194 -0
  234. package/src/integrations/chat-sdk/config.ts +198 -0
  235. package/src/integrations/chat-sdk/discord-api.ts +63 -0
  236. package/src/integrations/chat-sdk/discord-gateway.ts +185 -0
  237. package/src/integrations/chat-sdk/handlers.ts +28 -0
  238. package/src/integrations/chat-sdk/inbound.ts +426 -0
  239. package/src/integrations/chat-sdk/limits.ts +48 -0
  240. package/src/integrations/chat-sdk/logger.ts +81 -0
  241. package/src/integrations/chat-sdk/outbound.ts +123 -0
  242. package/src/integrations/chat-sdk/relay.ts +172 -0
  243. package/src/integrations/chat-sdk/router.ts +169 -0
  244. package/src/integrations/chat-sdk/runtime.ts +351 -0
  245. package/src/integrations/chat-sdk/schema.ts +245 -0
  246. package/src/integrations/chat-sdk/state.ts +243 -0
  247. package/src/integrations/chat-sdk/status.ts +244 -0
  248. package/src/integrations/chat-sdk/steering.ts +58 -0
  249. package/src/integrations/chat-sdk/teams-origin.ts +77 -0
  250. package/src/integrations/chat-sdk/telegram-api.ts +56 -0
  251. package/src/integrations/chat-sdk/templates.ts +16 -0
  252. package/src/integrations/chat-sdk/test-hooks.ts +37 -0
  253. package/src/integrations/chat-sdk/thread-buffer.ts +100 -0
  254. package/src/integrations/chat-sdk/typing.ts +65 -0
  255. package/src/jira/adf.ts +3 -1
  256. package/src/kv-reserved-namespaces.ts +2 -0
  257. package/src/oauth/mcp-wrapper.ts +10 -6
  258. package/src/otel-impl.ts +2 -1
  259. package/src/pages/version.ts +4 -5
  260. package/src/prompts/base-prompt.ts +111 -45
  261. package/src/providers/acp-target-catalog.ts +6 -0
  262. package/src/providers/acp-targets.ts +56 -3
  263. package/src/providers/amp-adapter.ts +1 -1
  264. package/src/providers/claude-adapter.ts +27 -2
  265. package/src/providers/claude-flag-settings.ts +133 -0
  266. package/src/providers/claude-managed-adapter.ts +1 -1
  267. package/src/providers/claude-sdk-session.ts +7 -0
  268. package/src/providers/claude-session-events.ts +6 -1
  269. package/src/providers/dsh-adapter.ts +1 -1
  270. package/src/providers/opencode-adapter.ts +268 -37
  271. package/src/providers/opencode-billing.ts +86 -0
  272. package/src/providers/opencode-swarm-plugin.ts +51 -0
  273. package/src/providers/pi-mono-adapter.ts +398 -153
  274. package/src/providers/pricing-sources.md +37 -3
  275. package/src/providers/reasoning-effort.ts +27 -0
  276. package/src/providers/types.ts +11 -2
  277. package/src/rbac/legacy-policy.ts +8 -2
  278. package/src/rbac/permissions.ts +21 -0
  279. package/src/scheduler/scheduler.ts +4 -2
  280. package/src/scripts-runtime/api-client.ts +15 -1
  281. package/src/scripts-runtime/api-types.ts +9 -1
  282. package/src/scripts-runtime/ctx.ts +1 -1
  283. package/src/scripts-runtime/loader.ts +19 -7
  284. package/src/scripts-runtime/mcp-client.ts +30 -19
  285. package/src/scripts-runtime/sdk-allowlist.ts +8 -6
  286. package/src/scripts-runtime/swarm-sdk.ts +0 -11
  287. package/src/scripts-runtime/types/stdlib.d.ts +27 -15
  288. package/src/scripts-runtime/types/swarm-extension.d.ts +63 -1
  289. package/src/scripts-runtime/types/swarm-sdk.d.ts +27 -15
  290. package/src/server.ts +52 -18
  291. package/src/slack/actions.ts +29 -1
  292. package/src/slack/app.ts +14 -2
  293. package/src/slack/assistant.ts +36 -2
  294. package/src/slack/channel-join.ts +3 -16
  295. package/src/slack/commands.ts +9 -1
  296. package/src/slack/event-dedup.ts +1 -1
  297. package/src/slack/external-channel-egress.ts +113 -0
  298. package/src/slack/external-channel.ts +309 -0
  299. package/src/slack/handlers.ts +61 -0
  300. package/src/slack/render-v2.ts +40 -47
  301. package/src/slack/work-objects.ts +5 -0
  302. package/src/tasks/additive-buffer.ts +4 -2
  303. package/src/tasks/context-key.ts +94 -2
  304. package/src/tasks/model-pin.ts +67 -0
  305. package/src/tasks/worker-follow-up.ts +4 -31
  306. package/src/telemetry.ts +2 -1
  307. package/src/tests/acp-adapter.test.ts +42 -0
  308. package/src/tests/api-drain-worker-e2e.test.ts +1 -6
  309. package/src/tests/apps-catalog-feedback.test.ts +310 -0
  310. package/src/tests/apps-catalog-inputs.test.ts +70 -0
  311. package/src/tests/apps-catalog-table.test.ts +113 -0
  312. package/src/tests/azure-devops-boards-sync.test.ts +584 -0
  313. package/src/tests/azure-devops-html.test.ts +13 -0
  314. package/src/tests/azure-devops-webhook-malformed.test.ts +4 -0
  315. package/src/tests/base-prompt.test.ts +58 -54
  316. package/src/tests/chat-sdk-commands.test.ts +191 -0
  317. package/src/tests/chat-sdk-config.test.ts +334 -0
  318. package/src/tests/chat-sdk-discord-api.test.ts +68 -0
  319. package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
  320. package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
  321. package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
  322. package/src/tests/chat-sdk-harness.ts +146 -0
  323. package/src/tests/chat-sdk-inbound.test.ts +363 -0
  324. package/src/tests/chat-sdk-relay.test.ts +470 -0
  325. package/src/tests/chat-sdk-reload.test.ts +128 -0
  326. package/src/tests/chat-sdk-shutdown.test.ts +220 -0
  327. package/src/tests/chat-sdk-slack.test.ts +268 -0
  328. package/src/tests/chat-sdk-state.test.ts +163 -0
  329. package/src/tests/chat-sdk-status-route.test.ts +382 -0
  330. package/src/tests/chat-sdk-teams.test.ts +277 -0
  331. package/src/tests/chat-sdk-tools.test.ts +520 -0
  332. package/src/tests/chat-sdk-typing.test.ts +120 -0
  333. package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
  334. package/src/tests/claude-adapter-binary.test.ts +144 -0
  335. package/src/tests/claude-flag-settings.test.ts +114 -0
  336. package/src/tests/claude-managed-adapter.test.ts +1 -1
  337. package/src/tests/claude-sdk-lifecycle.test.ts +148 -1
  338. package/src/tests/claude-sdk-process.fixture.ts +7 -0
  339. package/src/tests/claude-thinking-tokens.test.ts +57 -0
  340. package/src/tests/claude-worker-parity.test.ts +2 -7
  341. package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
  342. package/src/tests/config-refs.test.ts +66 -0
  343. package/src/tests/context-key.test.ts +51 -0
  344. package/src/tests/cors-allowlist.test.ts +25 -0
  345. package/src/tests/create-page-tool.test.ts +18 -0
  346. package/src/tests/credential-check.test.ts +139 -0
  347. package/src/tests/credentials.test.ts +21 -0
  348. package/src/tests/db-runtime.test.ts +61 -0
  349. package/src/tests/db-task-read-contract.test.ts +20 -0
  350. package/src/tests/db-task-write-contract.test.ts +10 -0
  351. package/src/tests/deferred-task-wake.test.ts +52 -4
  352. package/src/tests/docs-index-footprint.test.js +3 -3
  353. package/src/tests/dsh-adapter.test.ts +1 -1
  354. package/src/tests/enabled-capabilities.test.ts +20 -0
  355. package/src/tests/entrypoint-api-readiness.test.ts +14 -8
  356. package/src/tests/entrypoint-config-env-export.test.ts +5 -2
  357. package/src/tests/entrypoint-export-to-env.test.ts +78 -0
  358. package/src/tests/explicit-model-validation.test.ts +105 -1
  359. package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
  360. package/src/tests/extensions-post-bridge.test.ts +51 -0
  361. package/src/tests/fetch-resolved-env.test.ts +128 -0
  362. package/src/tests/fixtures/azure-boards/workitem.commented.json +89 -0
  363. package/src/tests/fixtures/azure-boards/workitem.created.json +81 -0
  364. package/src/tests/fixtures/azure-boards/workitem.deleted.json +70 -0
  365. package/src/tests/fixtures/azure-boards/workitem.restored.json +82 -0
  366. package/src/tests/fixtures/azure-boards/workitem.updated.json +130 -0
  367. package/src/tests/fixtures/catalog-feedback-definition.json.txt +860 -0
  368. package/src/tests/fixtures/catalog-inputs-definition.json.txt +910 -0
  369. package/src/tests/fixtures/catalog-table-definition.json.txt +468 -0
  370. package/src/tests/fixtures/chat-sdk/telegram-private-text.json +10 -0
  371. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
  372. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
  373. package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
  374. package/src/tests/fixtures/runner-identity-refresh.ts +3 -0
  375. package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
  376. package/src/tests/github-handlers.test.ts +35 -0
  377. package/src/tests/harness-provider-resolution.test.ts +12 -0
  378. package/src/tests/heartbeat-checklist.test.ts +3 -2
  379. package/src/tests/hook-runtime-close.test.ts +0 -2
  380. package/src/tests/http-api-integration.test.ts +0 -25
  381. package/src/tests/migration-046-budgets.test.ts +17 -16
  382. package/src/tests/migration-217-chat-sdk-state.test.ts +113 -0
  383. package/src/tests/model-tier-resolution.test.ts +93 -0
  384. package/src/tests/models-catalog.test.ts +42 -1
  385. package/src/tests/node-env-runtime.test.ts +98 -0
  386. package/src/tests/openai-compatible-providers.test.ts +134 -0
  387. package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
  388. package/src/tests/opencode-adapter.test.ts +348 -3
  389. package/src/tests/opencode-billing.test.ts +28 -0
  390. package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
  391. package/src/tests/opencode-shell-env.test.ts +145 -0
  392. package/src/tests/openrouter-base-url.test.ts +101 -151
  393. package/src/tests/page-proxy.test.ts +1 -1
  394. package/src/tests/pages-browser-sdk.test.ts +76 -0
  395. package/src/tests/pages-feedback.test.ts +1 -1
  396. package/src/tests/paused-tasks-requested-by.test.ts +102 -0
  397. package/src/tests/pi-custom-provider-fake-server.test.ts +442 -0
  398. package/src/tests/pi-mono-adapter.test.ts +385 -5
  399. package/src/tests/pi-shell-env.test.ts +170 -0
  400. package/src/tests/prompt-template-remaining.test.ts +35 -0
  401. package/src/tests/rbac-engine.test.ts +11 -3
  402. package/src/tests/runner-exit-after-tasks.test.ts +0 -4
  403. package/src/tests/runner-identity-refresh.test.ts +3 -0
  404. package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
  405. package/src/tests/script-connections-sql.test.ts +675 -0
  406. package/src/tests/script-connections.test.ts +7 -1
  407. package/src/tests/scripts-http.test.ts +201 -1
  408. package/src/tests/scripts-only-gating.test.ts +2 -3
  409. package/src/tests/scripts-runtime.test.ts +58 -40
  410. package/src/tests/secret-scrubber.test.ts +86 -0
  411. package/src/tests/seed-skills-bundled-files.test.ts +45 -53
  412. package/src/tests/seed-skills-retire.test.ts +182 -0
  413. package/src/tests/send-task-requester-gate.test.ts +58 -0
  414. package/src/tests/session-cost-recompute-unit.test.ts +94 -0
  415. package/src/tests/skill-get-name-resolution.test.ts +137 -0
  416. package/src/tests/slack-channel-join.test.ts +4 -1
  417. package/src/tests/slack-external-channel-config.test.ts +65 -0
  418. package/src/tests/slack-external-channel-egress.test.ts +237 -0
  419. package/src/tests/slack-external-channel-guard.test.ts +280 -0
  420. package/src/tests/slack-external-channel-tools.test.ts +173 -0
  421. package/src/tests/slack-external-channel.test.ts +370 -0
  422. package/src/tests/slack-render-v2.test.ts +86 -10
  423. package/src/tests/sonnet-5-5-registry.test.ts +9 -1
  424. package/src/tests/spec-base-url.test.ts +16 -1
  425. package/src/tests/swarm-config-export-to-env.test.ts +267 -0
  426. package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
  427. package/src/tests/swarm-diff.test.ts +1 -1
  428. package/src/tests/task-model-effort-rerun.test.ts +164 -0
  429. package/src/tests/task-session-prompts.test.ts +132 -0
  430. package/src/tests/task-tool-manifest.test.ts +14 -0
  431. package/src/tests/task-tools-ctx.test.ts +2 -0
  432. package/src/tests/tool-annotations.test.ts +6 -6
  433. package/src/tests/ui-logs-parser.test.ts +43 -0
  434. package/src/tests/used-by-route.test.ts +6 -0
  435. package/src/tests/vendored-openapi.test.ts +16 -1
  436. package/src/tests/vercel-ai-gateway.test.ts +149 -0
  437. package/src/tests/workflow-swarm-script.test.ts +38 -0
  438. package/src/tests/workflow-wait-filter.test.ts +5 -3
  439. package/src/tools/chat-access.ts +41 -0
  440. package/src/tools/chat-open-dm.ts +59 -0
  441. package/src/tools/chat-post.ts +74 -0
  442. package/src/tools/chat-read-thread.ts +100 -0
  443. package/src/tools/chat-reply.ts +75 -0
  444. package/src/tools/create-page.ts +3 -13
  445. package/src/tools/defer-task.ts +17 -0
  446. package/src/tools/model-catalog/index.ts +2 -1
  447. package/src/tools/register-chat-channel.ts +139 -0
  448. package/src/tools/send-task.ts +24 -0
  449. package/src/tools/skills/skill-get.ts +17 -9
  450. package/src/tools/slack-post.ts +6 -0
  451. package/src/tools/slack-read.ts +8 -0
  452. package/src/tools/slack-reply.ts +6 -0
  453. package/src/tools/slack-start-thread.ts +6 -0
  454. package/src/tools/slack-update.ts +6 -0
  455. package/src/tools/slack-upload-file.ts +6 -0
  456. package/src/tools/swarm-config/get-config.ts +2 -1
  457. package/src/tools/swarm-config/list-config.ts +2 -1
  458. package/src/tools/swarm-config/set-config.ts +16 -3
  459. package/src/tools/tool-config.ts +8 -6
  460. package/src/types.ts +12 -2
  461. package/src/utils/config-env-export.ts +74 -0
  462. package/src/utils/credentials.test.ts +92 -0
  463. package/src/utils/credentials.ts +52 -4
  464. package/src/utils/harness-provider.ts +15 -6
  465. package/src/utils/node-env.ts +24 -0
  466. package/src/utils/runtime-model-catalog.ts +11 -1
  467. package/src/utils/secret-scrubber.ts +71 -2
  468. package/src/utils/task-tool-manifest.ts +19 -2
  469. package/src/workflows/executors/swarm-script.ts +1 -0
  470. package/templates/skills/agent-browser/SKILL.md +1 -1
  471. package/templates/skills/agent-browser/content.md +1 -1
  472. package/templates/skills/apps/SKILL.md +749 -0
  473. package/templates/skills/apps/content.md +60 -22
  474. package/templates/skills/chat-sdk/config.json +14 -0
  475. package/templates/skills/chat-sdk/content.md +84 -0
  476. package/templates/skills/composio-gmail/content.md +7 -0
  477. package/templates/skills/composio-google-docs/content.md +1 -1
  478. package/templates/skills/email-domain-health/config.json +14 -0
  479. package/templates/skills/email-domain-health/content.md +131 -0
  480. package/templates/skills/kv-storage/content.md +2 -2
  481. package/templates/skills/pages/content.md +8 -10
  482. package/templates/skills/qa-loom/config.json +14 -0
  483. package/templates/skills/qa-loom/content.md +187 -0
  484. package/templates/skills/qa-loom/files/build-loom.mjs +221 -0
  485. package/templates/skills/qa-loom/files/run-qa.sh +57 -0
  486. package/templates/skills/slack-interaction/content.md +4 -0
  487. package/templates/skills/swarm-extensions/content.md +2 -0
  488. package/templates/skills/swarm-scripts/SKILL.md +4 -2
  489. package/templates/skills/swarm-scripts/config.json +1 -1
  490. package/templates/skills/swarm-scripts/content.md +4 -2
  491. package/templates/skills/workflow-iterate/content.md +38 -0
  492. package/dist/artifact-eczsknc3.js +0 -3843
  493. package/dist/cli-9xsmdpdt.js +0 -56377
  494. package/dist/cli-bd957dgb.js +0 -153
  495. package/dist/cli-q51yprfq.js +0 -1104
  496. package/dist/cli-t1ze64h3.js +0 -811
  497. package/dist/index-9ch1n761.js +0 -1102
  498. package/src/artifact-sdk/index.ts +0 -2
  499. package/src/artifact-sdk/localtunnel.d.ts +0 -20
  500. package/src/artifact-sdk/port.ts +0 -12
  501. package/src/artifact-sdk/server.ts +0 -183
  502. package/src/artifact-sdk/tunnel.ts +0 -19
  503. package/src/commands/artifact.ts +0 -249
  504. package/src/http/ecosystem.ts +0 -77
  505. package/src/tests/artifact-commands.test.ts +0 -92
  506. package/src/tests/artifact-sdk.test.ts +0 -793
  507. package/src/tests/register-service-security.test.ts +0 -194
  508. package/src/tools/list-services.ts +0 -107
  509. package/src/tools/register-service.ts +0 -177
  510. package/src/tools/unregister-service.ts +0 -73
  511. package/src/tools/update-service-status.ts +0 -96
  512. package/templates/skills/artifacts/config.json +0 -14
  513. package/templates/skills/artifacts/content.md +0 -344
  514. package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
  515. package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
  516. package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
  517. package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
  518. package/dist/{azure-openai-responses-ap1gwxgr.js → azure-openai-responses-ygfreq4t.js} +5 -5
  519. package/dist/{cli-5rqrj7q0.js → cli-pw7ebjdt.js} +0 -0
  520. package/dist/{openai-codex-responses-33qhkkdy.js → openai-codex-responses-3bk0grnr.js} +4 -4
  521. package/dist/{openai-completions-s88xm3ns.js → openai-completions-5d4jpakc.js} +9 -9
  522. package/dist/{openai-responses-7xd2f2e2.js → openai-responses-krb51f59.js} +5 -5
  523. package/dist/{pi-messages-xszk613n.js → pi-messages-x9gzynm1.js} +3 -3
  524. /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
  525. /package/src/{artifact-sdk → pages}/feedback-overlay.ts +0 -0
@@ -0,0 +1,75 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import * as z from "zod";
3
+ import { getAgentCurrentTask, getTaskById } from "@/be/db";
4
+ import { errorMessage } from "@/integrations/chat-sdk/logger";
5
+ import { ChatAdapterUnavailableError, postChatMessage } from "@/integrations/chat-sdk/outbound";
6
+ import { chatThreadOfContextKey } from "@/tasks/context-key";
7
+ import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
8
+
9
+ export const registerChatReplyTool = (server: McpServer) => {
10
+ createToolRegistrar(server)(
11
+ "chat-reply",
12
+ {
13
+ title: "Reply in the chat thread of this task",
14
+ description:
15
+ "Post a message to the Telegram, Slack, Discord or Teams thread your current task came from. Works only on a task whose contextKey starts with task:chat-sdk:. The task's final output is posted to the thread automatically when the task ends, so use this only for a question to the user or a short progress note on long work. Markdown is supported; long text is split into several messages.",
16
+ annotations: { openWorldHint: true },
17
+ inputSchema: z.object({
18
+ text: z.string().min(1).max(20_000).describe("Markdown text to post to the thread."),
19
+ }),
20
+ outputSchema: swarmToolOutputSchema({
21
+ yourAgentId: z.string().optional(),
22
+ messageId: z.string().optional(),
23
+ adapter: z.string().optional(),
24
+ threadId: z.string().optional(),
25
+ }),
26
+ },
27
+ async ({ text }, requestInfo) => {
28
+ if (!requestInfo.agentId) return toolErr("Agent ID not found.");
29
+ const data = { yourAgentId: requestInfo.agentId };
30
+
31
+ // The header names the task this session works on; without it, the
32
+ // agent's current in-progress task.
33
+ const task = requestInfo.sourceTaskId
34
+ ? await getTaskById(requestInfo.sourceTaskId)
35
+ : await getAgentCurrentTask(requestInfo.agentId);
36
+ if (!task) return toolErr("No current task found for chat-reply.", { data });
37
+ // Creator is safe: a non-lead agent can only create a chat-bound task under a parent it owns or created.
38
+ if (task.agentId !== requestInfo.agentId && task.creatorAgentId !== requestInfo.agentId) {
39
+ return toolErr("You don't have context for this task.", { data });
40
+ }
41
+ const thread = chatThreadOfContextKey(task.contextKey);
42
+ if (!thread) {
43
+ return toolErr(
44
+ `Task ${task.id} did not come from a chat thread (no task:chat-sdk contextKey). Use the tool of the channel the task came from.`,
45
+ { data },
46
+ );
47
+ }
48
+
49
+ try {
50
+ const sent = await postChatMessage({
51
+ adapter: thread.adapter,
52
+ threadId: thread.threadId,
53
+ text,
54
+ taskId: task.id,
55
+ });
56
+ return toolOk(`Posted to ${thread.adapter} thread ${sent.threadId}.`, {
57
+ data: {
58
+ ...data,
59
+ messageId: sent.messageIds.at(-1),
60
+ adapter: sent.adapter,
61
+ threadId: sent.threadId,
62
+ },
63
+ });
64
+ } catch (error) {
65
+ const message = errorMessage(error);
66
+ return toolErr(
67
+ error instanceof ChatAdapterUnavailableError
68
+ ? `${message}. The final task output is still posted when the adapter is back.`
69
+ : `Could not post to the chat thread: ${message}`,
70
+ { data },
71
+ );
72
+ }
73
+ },
74
+ );
75
+ };
@@ -21,7 +21,8 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
21
21
  import * as z from "zod";
22
22
  import { authorizeAssetKeyWrite } from "@/be/asset-key-auth";
23
23
  import { resolveTaskAuditUserId } from "@/be/audit-user";
24
- import { createPage, getPage, getPageBySlug, getPageVersions, updatePage } from "@/be/db";
24
+ import { createPage, getPage, getPageBySlug, updatePage } from "@/be/db";
25
+ import { getPageEditCounter } from "@/be/db/page-versions";
25
26
  import { snapshotPage } from "@/pages/version";
26
27
  import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
27
28
  import { AssetKeySchema, PageAuthModeSchema, PageContentTypeSchema } from "@/types";
@@ -45,17 +46,6 @@ function getAppBaseUrl(): string {
45
46
  return getAppUrl();
46
47
  }
47
48
 
48
- /**
49
- * Edit counter for a page — `MAX(page_versions.version) + 1`. Returned to
50
- * the agent as `version` so they have a monotonic "this page has been
51
- * edited N times" signal. Mirrors the value returned by
52
- * `PUT /api/pages/:id` (see src/http/pages.ts:pageEditCounter).
53
- */
54
- async function pageEditCounter(pageId: string): Promise<number> {
55
- const versions = await getPageVersions(pageId);
56
- return versions.length > 0 ? versions[0]!.version + 1 : 1;
57
- }
58
-
59
49
  export const registerCreatePageTool = (server: McpServer) => {
60
50
  createToolRegistrar(server)(
61
51
  "create_page",
@@ -217,7 +207,7 @@ export const registerCreatePageTool = (server: McpServer) => {
217
207
 
218
208
  const apiUrl = `${getApiBaseUrl()}/p/${id}`;
219
209
  const appUrl = `${getAppBaseUrl()}/pages/${id}`;
220
- const version = await pageEditCounter(id);
210
+ const version = await getPageEditCounter(id);
221
211
 
222
212
  return toolOk(`Page "${input.title}" saved (slug=${finalSlug}, version=${version}).`, {
223
213
  details: `API: ${apiUrl}\n App: ${appUrl}`,
@@ -306,6 +306,23 @@ export const registerDeferTaskTool = (server: McpServer) => {
306
306
 
307
307
  try {
308
308
  const committed = await getDbClient().transaction(async () => {
309
+ // The transaction's write lock makes admission atomic with the INSERT.
310
+ if (watchedTaskIds.length) {
311
+ const existing = await getDbClient().get<{ scheduleId: string; parentTaskId: string }>(
312
+ `SELECT w.scheduleId, s.parentTaskId FROM deferred_task_waits w
313
+ JOIN scheduled_tasks s ON s.id = w.scheduleId
314
+ JOIN deferred_task_wait_members m ON m.scheduleId = w.scheduleId
315
+ WHERE w.status = 'pending' AND s.enabled = 1 AND s.targetAgentId = ?
316
+ AND m.taskId IN (${watchedTaskIds.map(() => "?").join(", ")})
317
+ LIMIT 1`,
318
+ [agent.id, ...watchedTaskIds],
319
+ );
320
+ if (existing) {
321
+ throw new DeferAbortedError(
322
+ `Pending watcher ${existing.scheduleId} (task ${existing.parentTaskId}) already watches these tasks for this agent.`,
323
+ );
324
+ }
325
+ }
309
326
  const watchedAgentNames: string[] = [];
310
327
  for (const watchedId of watchedTaskIds) {
311
328
  if (watchedId === taskId)
@@ -1,3 +1,4 @@
1
+ import { openAICompatibleProviderIds } from "@desplega/model-catalog";
1
2
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
3
  import * as z from "zod";
3
4
  import { getAgentById } from "@/be/db";
@@ -86,7 +87,7 @@ export const registerModelCatalogOverlayUpsertTool = (server: McpServer) => {
86
87
  .string()
87
88
  .min(1)
88
89
  .describe(
89
- "models.dev provider id: anthropic, openai, openrouter, amazon-bedrock, opencode.",
90
+ `models.dev provider id: anthropic, openai, openrouter, amazon-bedrock, opencode, ${openAICompatibleProviderIds().join(", ")}.`,
90
91
  ),
91
92
  modelId: z
92
93
  .string()
@@ -0,0 +1,139 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import * as z from "zod";
3
+ import { getAgentById, getWorkflow } from "@/be/db";
4
+ import { CHAT_SDK_ADAPTER_NAMES } from "@/integrations/chat-sdk/config";
5
+ import { errorMessage } from "@/integrations/chat-sdk/logger";
6
+ import {
7
+ type ChatChannelMapping,
8
+ chatChannelKey,
9
+ deleteChatChannelMapping,
10
+ putChatChannelMapping,
11
+ } from "@/integrations/chat-sdk/router";
12
+ import { can } from "@/rbac";
13
+ import {
14
+ createToolRegistrar,
15
+ type RequestInfo,
16
+ swarmToolOutputSchema,
17
+ toolErr,
18
+ toolOk,
19
+ } from "@/tools/utils";
20
+
21
+ async function canManageChatChannels(requestInfo: RequestInfo): Promise<boolean> {
22
+ const caller = requestInfo.agentId ? await getAgentById(requestInfo.agentId) : null;
23
+ return can({
24
+ principal: {
25
+ kind: "agent",
26
+ agentId: requestInfo.agentId ?? "",
27
+ isLead: caller?.isLead ?? false,
28
+ },
29
+ verb: "integration.chat.manage",
30
+ resource: { kind: "none" },
31
+ source: "mcp",
32
+ }).allow;
33
+ }
34
+
35
+ export const registerRegisterChatChannelTool = (server: McpServer) => {
36
+ createToolRegistrar(server)(
37
+ "register-chat-channel",
38
+ {
39
+ title: "Route a chat channel to an agent or workflow",
40
+ annotations: { idempotentHint: true },
41
+ description:
42
+ "Lead-only. Route every swarm-addressed message from one Chat SDK channel (a Telegram group, Slack channel, Discord channel or Teams chat) to a fixed agent or workflow instead of the lead. Give exactly one of agentId or workflowId. A swarm#<agentId> token in a message still wins over the mapping. Remove it with unregister-chat-channel.",
43
+ inputSchema: z.object({
44
+ adapter: z.enum(CHAT_SDK_ADAPTER_NAMES).describe("Chat SDK adapter name."),
45
+ channelId: z
46
+ .string()
47
+ .min(1)
48
+ .describe("SDK channel id, such as telegram:-100123 or slack:C123 (prefix optional)."),
49
+ agentId: z.string().optional().describe("Agent that receives the channel's tasks."),
50
+ workflowId: z
51
+ .string()
52
+ .optional()
53
+ .describe("Workflow whose webhook trigger receives the channel's messages."),
54
+ name: z.string().max(200).optional().describe("Display name for the mapping."),
55
+ }),
56
+ outputSchema: swarmToolOutputSchema({
57
+ yourAgentId: z.string().optional(),
58
+ key: z.string().optional(),
59
+ mapping: z
60
+ .looseObject({
61
+ agentId: z.string().optional(),
62
+ workflowId: z.string().optional(),
63
+ name: z.string().optional(),
64
+ createdAt: z.string().optional(),
65
+ })
66
+ .optional(),
67
+ }),
68
+ },
69
+ async ({ adapter, channelId, agentId, workflowId, name }, requestInfo) => {
70
+ const data = { yourAgentId: requestInfo.agentId };
71
+ try {
72
+ if (!(await canManageChatChannels(requestInfo))) {
73
+ return toolErr("Permission denied. Only the lead can register a chat channel.", {
74
+ data,
75
+ });
76
+ }
77
+ if (Boolean(agentId) === Boolean(workflowId)) {
78
+ return toolErr("Give exactly one of agentId or workflowId.", { data });
79
+ }
80
+ if (agentId && !(await getAgentById(agentId))) {
81
+ return toolErr(`Agent ${agentId} not found.`, { data });
82
+ }
83
+ if (workflowId && !(await getWorkflow(workflowId))) {
84
+ return toolErr(`Workflow ${workflowId} not found.`, { data });
85
+ }
86
+ const mapping: ChatChannelMapping = {
87
+ ...(agentId ? { agentId } : {}),
88
+ ...(workflowId ? { workflowId } : {}),
89
+ ...(name ? { name } : {}),
90
+ createdAt: new Date().toISOString(),
91
+ };
92
+ const key = await putChatChannelMapping(adapter, channelId, mapping);
93
+ return toolOk(
94
+ `Registered chat channel ${key} -> ${workflowId ? `workflow ${workflowId}` : `agent ${agentId}`}.`,
95
+ { data: { ...data, key, mapping } },
96
+ );
97
+ } catch (error) {
98
+ return toolErr(errorMessage(error), { data });
99
+ }
100
+ },
101
+ );
102
+ };
103
+
104
+ export const registerUnregisterChatChannelTool = (server: McpServer) => {
105
+ createToolRegistrar(server)(
106
+ "unregister-chat-channel",
107
+ {
108
+ title: "Remove a chat channel route",
109
+ annotations: { idempotentHint: true },
110
+ description:
111
+ "Lead-only. Remove the channel-to-agent or channel-to-workflow route that register-chat-channel stored. Messages from the channel go back to the default route (thread owner, then the lead).",
112
+ inputSchema: z.object({
113
+ adapter: z.enum(CHAT_SDK_ADAPTER_NAMES).describe("Chat SDK adapter name."),
114
+ channelId: z.string().min(1).describe("SDK channel id (prefix optional)."),
115
+ }),
116
+ outputSchema: swarmToolOutputSchema({
117
+ yourAgentId: z.string().optional(),
118
+ key: z.string().optional(),
119
+ }),
120
+ },
121
+ async ({ adapter, channelId }, requestInfo) => {
122
+ const data = { yourAgentId: requestInfo.agentId };
123
+ try {
124
+ if (!(await canManageChatChannels(requestInfo))) {
125
+ return toolErr("Permission denied. Only the lead can unregister a chat channel.", {
126
+ data,
127
+ });
128
+ }
129
+ const key = chatChannelKey(adapter, channelId);
130
+ const deleted = await deleteChatChannelMapping(adapter, channelId);
131
+ return deleted
132
+ ? toolOk(`Unregistered chat channel ${key}.`, { data: { ...data, key } })
133
+ : toolErr(`No mapping found for chat channel ${key}.`, { data: { ...data, key } });
134
+ } catch (error) {
135
+ return toolErr(errorMessage(error), { data });
136
+ }
137
+ },
138
+ );
139
+ };
@@ -378,6 +378,30 @@ export async function sendTaskHandler(
378
378
  const effectiveParentTask = effectiveParentTaskId
379
379
  ? await getTaskById(effectiveParentTaskId)
380
380
  : null;
381
+ // The child inherits the parent's contextKey (its Slack or chat thread) and requester, and
382
+ // thread-scoped tools trust that binding. An agent can only build on a parent it owns or
383
+ // created; otherwise a worker could mint access to a foreign thread.
384
+ if (ctx.kind === "owner" && creatorAgentId && effectiveParentTask) {
385
+ const caller = await getAgentById(creatorAgentId);
386
+ const decision = can({
387
+ principal: { kind: "agent", agentId: creatorAgentId, isLead: caller?.isLead ?? false },
388
+ verb: "task.parent.attach",
389
+ resource: {
390
+ kind: "task",
391
+ taskId: effectiveParentTask.id,
392
+ requestedByUserId: effectiveParentTask.requestedByUserId,
393
+ creatorAgentId: effectiveParentTask.creatorAgentId,
394
+ agentId: effectiveParentTask.agentId,
395
+ },
396
+ source: "mcp",
397
+ });
398
+ if (!decision.allow) {
399
+ return toolErr(
400
+ `You don't have context for parent task ${effectiveParentTask.id}. Only its assignee, its creator, or a lead can create a child task under it.`,
401
+ { data: { yourAgentId: creatorAgentId } },
402
+ );
403
+ }
404
+ }
381
405
  if (effectiveParentTask?.routingAffinityInvalid) {
382
406
  return toolErr("Cannot continue a task with an invalid routing affinity.", {
383
407
  data: { yourAgentId: creatorAgentId },
@@ -1,6 +1,7 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import * as z from "zod";
3
3
  import { getSkillById, getSkillByName } from "@/be/db";
4
+ import { resolveSwarmSkillByName } from "@/be/db/skill-name-resolution";
4
5
  import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
5
6
 
6
7
  export const registerSkillGetTool = (server: McpServer) => {
@@ -10,7 +11,7 @@ export const registerSkillGetTool = (server: McpServer) => {
10
11
  title: "Get Skill",
11
12
  annotations: { destructiveHint: false },
12
13
  description:
13
- "Get full skill content by ID or name. Name resolution checks agent scope first, then swarm, then global.",
14
+ "Get full skill content by ID or name. Name resolution checks agent scope first, then swarm, then global. In swarm scope the ownerless skill wins, then your own, then the only agent-owned one; when several other agents own that name, it errors with their IDs: pass skillId instead.",
14
15
  inputSchema: z.object({
15
16
  skillId: z.string().optional().describe("Skill ID"),
16
17
  name: z.string().optional().describe("Skill name (resolved with precedence)"),
@@ -29,15 +30,22 @@ export const registerSkillGetTool = (server: McpServer) => {
29
30
 
30
31
  if (args.skillId) {
31
32
  skill = await getSkillById(args.skillId);
32
- } else if (args.name && requestInfo.agentId) {
33
- // Precedence: agent (personal) → swarm → global
34
- skill =
35
- (await getSkillByName(args.name, "agent", requestInfo.agentId)) ||
36
- (await getSkillByName(args.name, "swarm")) ||
37
- (await getSkillByName(args.name, "global"));
38
33
  } else if (args.name) {
39
- skill =
40
- (await getSkillByName(args.name, "swarm")) || (await getSkillByName(args.name, "global"));
34
+ // Precedence: agent (personal) → swarm → global
35
+ if (requestInfo.agentId) {
36
+ skill = await getSkillByName(args.name, "agent", requestInfo.agentId);
37
+ }
38
+ if (!skill) {
39
+ const swarm = await resolveSwarmSkillByName(args.name, requestInfo.agentId);
40
+ if (swarm.kind === "ambiguous") {
41
+ return toolErr(
42
+ `Skill name "${args.name}" matches ${swarm.skillIds.length} swarm skills owned by other agents: ${swarm.skillIds.join(", ")}. Call skill-get with skillId instead.`,
43
+ { data: { yourAgentId: requestInfo.agentId } },
44
+ );
45
+ }
46
+ if (swarm.kind === "found") skill = await getSkillById(swarm.skillId);
47
+ }
48
+ if (!skill) skill = await getSkillByName(args.name, "global");
41
49
  }
42
50
 
43
51
  if (!skill) {
@@ -10,6 +10,7 @@ import { can } from "@/rbac";
10
10
  import { getSlackApp } from "@/slack/app";
11
11
  import { getTaskLink } from "@/slack/blocks";
12
12
  import { withAutoJoin } from "@/slack/channel-join";
13
+ import { externalChannelToolError, getChannelBlockReason } from "@/slack/external-channel";
13
14
  import { getAgentDisplayName, getAgentEmoji, markdownToSlack } from "@/slack/responses";
14
15
  import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
15
16
 
@@ -67,6 +68,11 @@ export const registerSlackPostTool = (server: McpServer) => {
67
68
  return toolErr("Slack not configured.");
68
69
  }
69
70
 
71
+ const blockReason = await getChannelBlockReason(app.client, channelId);
72
+ if (blockReason) {
73
+ return toolErr(externalChannelToolError(channelId, blockReason));
74
+ }
75
+
70
76
  try {
71
77
  const slackMessage = markdownToSlack(message);
72
78
 
@@ -4,6 +4,7 @@ import { getAgentById, getInboxMessageById, getTaskById } from "@/be/db";
4
4
  import { can } from "@/rbac";
5
5
  import { getSlackApp } from "@/slack/app";
6
6
  import { withAutoJoin } from "@/slack/channel-join";
7
+ import { externalChannelToolError, getChannelBlockReason } from "@/slack/external-channel";
7
8
  import { downloadFile, type SlackFile } from "@/slack/files";
8
9
  import { attachableTask, attachSlackFilesForAgent } from "@/slack/inbound-files";
9
10
  import { extractSlackMessageText } from "@/slack/message-text";
@@ -154,6 +155,13 @@ export const registerSlackReadTool = (server: McpServer) => {
154
155
  return toolErr("Slack not configured.", { data: { messages: [] } });
155
156
  }
156
157
 
158
+ const blockReason = await getChannelBlockReason(app.client, slackChannelId);
159
+ if (blockReason) {
160
+ return toolErr(externalChannelToolError(slackChannelId, blockReason), {
161
+ data: { messages: [] },
162
+ });
163
+ }
164
+
157
165
  try {
158
166
  const client = app.client;
159
167
 
@@ -13,6 +13,7 @@ import { getTaskCitations } from "@/be/task-citations";
13
13
  import { getSlackApp } from "@/slack/app";
14
14
  import { buildCaptionBlock, getTaskLink, getTaskUrl } from "@/slack/blocks";
15
15
  import { withAutoJoin } from "@/slack/channel-join";
16
+ import { externalChannelToolError, getChannelBlockReason } from "@/slack/external-channel";
16
17
  import { getAgentDisplayName, getAgentEmoji, markdownToSlack } from "@/slack/responses";
17
18
  import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
18
19
  import {
@@ -110,6 +111,11 @@ export const registerSlackReplyTool = (server: McpServer) => {
110
111
  return toolErr("Slack not configured.");
111
112
  }
112
113
 
114
+ const blockReason = await getChannelBlockReason(app.client, slackChannelId);
115
+ if (blockReason) {
116
+ return toolErr(externalChannelToolError(slackChannelId, blockReason));
117
+ }
118
+
113
119
  try {
114
120
  const citations = taskId ? await getTaskCitations(taskId) : [];
115
121
  // Sources go in a caption under the reply, never in the body or the
@@ -4,6 +4,7 @@ import { getAgentById, getTaskById, recordSlackMessage } from "@/be/db";
4
4
  import { can } from "@/rbac";
5
5
  import { getSlackApp } from "@/slack/app";
6
6
  import { withAutoJoin } from "@/slack/channel-join";
7
+ import { externalChannelToolError, getChannelBlockReason } from "@/slack/external-channel";
7
8
  import { getAgentDisplayName, getAgentEmoji, markdownToSlack } from "@/slack/responses";
8
9
  import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
9
10
 
@@ -56,6 +57,11 @@ export const registerSlackStartThreadTool = (server: McpServer) => {
56
57
  return toolErr("Slack not configured.");
57
58
  }
58
59
 
60
+ const blockReason = await getChannelBlockReason(app.client, channelId);
61
+ if (blockReason) {
62
+ return toolErr(externalChannelToolError(channelId, blockReason));
63
+ }
64
+
59
65
  try {
60
66
  const slackMessage = markdownToSlack(message);
61
67
  const messageBlocks = blocks ?? [
@@ -4,6 +4,7 @@ import * as z from "zod";
4
4
  import { getAgentById } from "@/be/db";
5
5
  import { can } from "@/rbac";
6
6
  import { getSlackApp } from "@/slack/app";
7
+ import { externalChannelToolError, getChannelBlockReason } from "@/slack/external-channel";
7
8
  import { parseSlackTs } from "@/slack/message-text";
8
9
  import { markdownToSlack } from "@/slack/responses";
9
10
  import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
@@ -61,6 +62,11 @@ export const registerSlackUpdateTool = (server: McpServer) => {
61
62
  return toolErr("Slack not configured.");
62
63
  }
63
64
 
65
+ const blockReason = await getChannelBlockReason(app.client, channelId);
66
+ if (blockReason) {
67
+ return toolErr(externalChannelToolError(channelId, blockReason));
68
+ }
69
+
64
70
  try {
65
71
  const ts = parseSlackTs(messageTs);
66
72
  const slackMessage = markdownToSlack(message);
@@ -3,6 +3,7 @@ import * as z from "zod";
3
3
  import { getAgentById, getInboxMessageById, getTaskById } from "@/be/db";
4
4
  import { can } from "@/rbac";
5
5
  import { getSlackApp } from "@/slack/app";
6
+ import { externalChannelToolError, getChannelBlockReason } from "@/slack/external-channel";
6
7
  import { MAX_FILE_SIZE, uploadFile } from "@/slack/files";
7
8
  import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
8
9
 
@@ -223,6 +224,11 @@ export const registerSlackUploadFileTool = (server: McpServer) => {
223
224
  return toolErr("Slack not configured.");
224
225
  }
225
226
 
227
+ const blockReason = await getChannelBlockReason(app.client, slackChannelId);
228
+ if (blockReason) {
229
+ return toolErr(externalChannelToolError(slackChannelId, blockReason));
230
+ }
231
+
226
232
  // Validate: must provide either filePath OR content (not both, not neither)
227
233
  if (!filePath && !content) {
228
234
  return toolErr("Must provide either filePath or content (base64).");
@@ -19,6 +19,7 @@ const configEntryShape = z.looseObject({
19
19
  createdAt: z.string().optional(),
20
20
  lastUpdatedAt: z.string().optional(),
21
21
  encrypted: z.boolean().optional(),
22
+ exportToEnv: z.boolean().optional(),
22
23
  });
23
24
 
24
25
  export const registerGetConfigTool = (server: McpServer) => {
@@ -110,7 +111,7 @@ export const registerGetConfigTool = (server: McpServer) => {
110
111
  : result
111
112
  .map(
112
113
  (c) =>
113
- `- ${c.key}=${c.isSecret && !effectiveIncludeSecrets ? "********" : c.value} (scope: ${c.scope}${c.scopeId ? `, scopeId: ${c.scopeId}` : ""})`,
114
+ `- ${c.key}=${c.isSecret && !effectiveIncludeSecrets ? "********" : c.value} (scope: ${c.scope}${c.scopeId ? `, scopeId: ${c.scopeId}` : ""}${c.exportToEnv ? "" : ", not in agent env"})`,
114
115
  )
115
116
  .join("\n");
116
117
 
@@ -19,6 +19,7 @@ const configEntryShape = z.looseObject({
19
19
  createdAt: z.string().optional(),
20
20
  lastUpdatedAt: z.string().optional(),
21
21
  encrypted: z.boolean().optional(),
22
+ exportToEnv: z.boolean().optional(),
22
23
  });
23
24
 
24
25
  export const registerListConfigTool = (server: McpServer) => {
@@ -102,7 +103,7 @@ export const registerListConfigTool = (server: McpServer) => {
102
103
  : result
103
104
  .map(
104
105
  (c) =>
105
- `- [${c.scope}${c.scopeId ? `:${c.scopeId}` : ""}] ${c.key}=${c.isSecret && !effectiveIncludeSecrets ? "********" : c.value}${c.description ? ` — ${c.description}` : ""}`,
106
+ `- [${c.scope}${c.scopeId ? `:${c.scopeId}` : ""}] ${c.key}=${c.isSecret && !effectiveIncludeSecrets ? "********" : c.value}${c.exportToEnv ? "" : " [not in agent env]"}${c.description ? ` — ${c.description}` : ""}`,
106
107
  )
107
108
  .join("\n");
108
109
 
@@ -8,6 +8,7 @@ import {
8
8
  isReservedConfigKey,
9
9
  reservedKeyError,
10
10
  validateConfigValue,
11
+ validateExportToEnv,
11
12
  } from "@/be/swarm-config-guard";
12
13
  import { scheduleIntegrationsReload } from "@/http/core";
13
14
  import { can } from "@/rbac";
@@ -26,6 +27,7 @@ const configEntryShape = z.looseObject({
26
27
  createdAt: z.string().optional(),
27
28
  lastUpdatedAt: z.string().optional(),
28
29
  encrypted: z.boolean().optional(),
30
+ exportToEnv: z.boolean().optional(),
29
31
  });
30
32
 
31
33
  export const registerSetConfigTool = (server: McpServer) => {
@@ -34,7 +36,7 @@ export const registerSetConfigTool = (server: McpServer) => {
34
36
  {
35
37
  title: "Set Config",
36
38
  description:
37
- "Set or update a swarm configuration value. Upserts by (scope, scopeId, key). Use scope='global' for server-wide settings, 'agent' for agent-specific, or 'repo' for repo-specific. Set isSecret=true to mask the value in API responses.",
39
+ "Set or update a swarm configuration value. Upserts by (scope, scopeId, key). Use scope='global' for server-wide settings, 'agent' for agent-specific, or 'repo' for repo-specific. Set isSecret=true to mask the value in API responses. Set exportToEnv=false to keep the row out of agent process env (agents then reach it through a connection or script credential binding).",
38
40
  annotations: { idempotentHint: true },
39
41
 
40
42
  inputSchema: z.object({
@@ -63,13 +65,22 @@ export const registerSetConfigTool = (server: McpServer) => {
63
65
  .string()
64
66
  .optional()
65
67
  .describe("Optional human-readable description of this config entry."),
68
+ exportToEnv: z
69
+ .boolean()
70
+ .optional()
71
+ .describe(
72
+ "Export this row into agent process env (default true on create, false for a few server-side secrets; omitted on update keeps the stored flag). Rejected as true for keys only the API server reads.",
73
+ ),
66
74
  }),
67
75
  outputSchema: swarmToolOutputSchema({
68
76
  yourAgentId: z.string().optional(),
69
77
  config: configEntryShape.optional(),
70
78
  }),
71
79
  },
72
- async ({ scope, scopeId, key, value, isSecret, envPath, description }, requestInfo) => {
80
+ async (
81
+ { scope, scopeId, key, value, isSecret, envPath, description, exportToEnv },
82
+ requestInfo,
83
+ ) => {
73
84
  if (!requestInfo.agentId) {
74
85
  return toolErr('Agent ID not found. Set the "X-Agent-ID" header.');
75
86
  }
@@ -114,7 +125,8 @@ export const registerSetConfigTool = (server: McpServer) => {
114
125
  });
115
126
  }
116
127
 
117
- const validationError = validateConfigValue(key, value);
128
+ const validationError =
129
+ validateConfigValue(key, value) ?? validateExportToEnv(key, exportToEnv);
118
130
  if (validationError) {
119
131
  return toolErr(validationError, { data: { yourAgentId: requestInfo.agentId } });
120
132
  }
@@ -127,6 +139,7 @@ export const registerSetConfigTool = (server: McpServer) => {
127
139
  isSecret,
128
140
  envPath,
129
141
  description,
142
+ exportToEnv,
130
143
  });
131
144
 
132
145
  if (scope === "global") {
@@ -72,12 +72,6 @@ export const DEFERRED_TOOLS = new Set([
72
72
  "retry-workflow-run",
73
73
  "cancel-workflow-run",
74
74
 
75
- // Services (4)
76
- "register-service",
77
- "unregister-service",
78
- "list-services",
79
- "update-service-status",
80
-
81
75
  // Config (7)
82
76
  "set-config",
83
77
  "list-config",
@@ -127,6 +121,14 @@ export const DEFERRED_TOOLS = new Set([
127
121
  "send-whatsapp-message",
128
122
  "reply-whatsapp-message",
129
123
 
124
+ // Chat SDK (6)
125
+ "chat-reply",
126
+ "chat-post",
127
+ "chat-open-dm",
128
+ "chat-read-thread",
129
+ "register-chat-channel",
130
+ "unregister-chat-channel",
131
+
130
132
  // Tracker (7)
131
133
  "tracker-status",
132
134
  "get-oauth-access-token",