@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
package/src/http/stats.ts CHANGED
@@ -3,7 +3,6 @@ import { z } from "zod";
3
3
  import {
4
4
  getAgentStatusCounts,
5
5
  getAllLogs,
6
- getAllServices,
7
6
  getConcurrentContext,
8
7
  getLogsByAgentId,
9
8
  getScheduledTasks,
@@ -14,7 +13,7 @@ import {
14
13
  import { getDbRetentionStats } from "../be/db-retention";
15
14
  import { isSteeringEnabled } from "../be/steering";
16
15
  import type { AgentLog } from "../types";
17
- import { AgentLogSchema, ScheduledTaskSchema, ServiceSchema } from "../types";
16
+ import { AgentLogSchema, ScheduledTaskSchema } from "../types";
18
17
  import { isEnvFlagEnabled } from "../utils/env-flag";
19
18
  import { isMultiRuntimeEnabled } from "../utils/multi-runtime";
20
19
  import { resolveHttpFavoriteOwner } from "./favorite-owner";
@@ -166,22 +165,6 @@ const getMetrics = route({
166
165
  },
167
166
  });
168
167
 
169
- const listServices = route({
170
- method: "get",
171
- path: "/api/services",
172
- pattern: ["api", "services"],
173
- summary: "List all registered services",
174
- tags: ["Stats"],
175
- query: z.object({
176
- status: z.string().optional(),
177
- agentId: z.string().optional(),
178
- name: z.string().optional(),
179
- }),
180
- responses: {
181
- 200: { description: "Service list", schema: z.object({ services: z.array(ServiceSchema) }) },
182
- },
183
- });
184
-
185
168
  const listScheduledTasks = route({
186
169
  method: "get",
187
170
  path: "/api/scheduled-tasks",
@@ -295,18 +278,6 @@ export async function handleStats(
295
278
  return true;
296
279
  }
297
280
 
298
- if (listServices.match(req.method, pathSegments)) {
299
- const parsed = await listServices.parse(req, res, pathSegments, queryParams);
300
- if (!parsed) return true;
301
- const services = await getAllServices({
302
- status: (parsed.query.status as import("../types").ServiceStatus) || undefined,
303
- agentId: parsed.query.agentId || undefined,
304
- name: parsed.query.name || undefined,
305
- });
306
- listServices.respond(res, 200, { services });
307
- return true;
308
- }
309
-
310
281
  if (listScheduledTasks.match(req.method, pathSegments)) {
311
282
  const parsed = await listScheduledTasks.parse(req, res, pathSegments, queryParams);
312
283
  if (!parsed) return true;
package/src/http/tasks.ts CHANGED
@@ -45,6 +45,7 @@ import {
45
45
  import { getTaskCitations, TaskCitationSchema } from "../be/task-citations";
46
46
  import { findUserById } from "../be/users";
47
47
  import { can, type RbacPrincipal, type RbacResource } from "../rbac";
48
+ import { chatThreadOfContextKey } from "../tasks/context-key";
48
49
  import { TaskCreationBlockedError } from "../tasks/errors";
49
50
  import { createTaskWithSiblingAwareness } from "../tasks/sibling-awareness";
50
51
  import { guardTerminalTaskResultWrite } from "../tasks/terminal-result-guard";
@@ -76,6 +77,7 @@ import { ensure } from "../utils/business-use";
76
77
  import { getRequestAuth } from "../utils/request-auth-context";
77
78
  import { scrubSecrets } from "../utils/secret-scrubber";
78
79
  import { rejectGuest } from "./request-principal";
80
+ import { buildTaskRequestedBy, TaskRequestedBySchema } from "./requested-by";
79
81
  import { route } from "./route-def";
80
82
  import { jsonError, parseBody } from "./utils";
81
83
 
@@ -110,6 +112,7 @@ const AgentTaskSummarySchema = AgentTaskSchema.pick({
110
112
  modelSource: true,
111
113
  modelAlias: true,
112
114
  effort: true,
115
+ resolvedEffort: true,
113
116
  provider: true,
114
117
  requestedByUserId: true,
115
118
  progress: true,
@@ -308,6 +311,10 @@ const createTask = route({
308
311
  description:
309
312
  "Validation error, an unknown `model` (set `allowCustomModel` to store a custom id), or agentId/offeredTo targets an extension identity",
310
313
  },
314
+ 403: {
315
+ description:
316
+ "An agent caller names a parentTaskId it neither owns nor created, or a non-lead agent binds the task to a chat thread",
317
+ },
311
318
  422: {
312
319
  description: "Task creation blocked by an extension",
313
320
  schema: z.object({
@@ -357,6 +364,8 @@ const updateSession = route({
357
364
  claudeSessionId: z.string().min(1),
358
365
  provider: ProviderNameSchema.exclude(["devin"]).optional(),
359
366
  model: z.string().optional(),
367
+ // Effort the session runs at; null when the harness default applies.
368
+ effort: ReasoningEffortSchema.nullable().optional(),
360
369
  providerMeta: z.object({ transport: z.enum(["cli", "sdk"]).optional() }).optional(),
361
370
  harnessVariant: z.string().optional(),
362
371
  harnessVariantMeta: z.record(z.string(), z.unknown()).optional(),
@@ -592,7 +601,14 @@ const listPausedTasks = route({
592
601
  200: {
593
602
  description: "Paused task list",
594
603
  schema: z.object({
595
- tasks: z.array(AgentTaskSchema.extend({ attachments: z.array(TaskAttachmentSchema) })),
604
+ tasks: z.array(
605
+ AgentTaskSchema.extend({
606
+ attachments: z.array(TaskAttachmentSchema),
607
+ // Same requester projection a fresh task_assigned trigger carries,
608
+ // so a resumed session gets the same requester-profile prompt.
609
+ requestedBy: TaskRequestedBySchema.optional(),
610
+ }),
611
+ ),
596
612
  }),
597
613
  },
598
614
  },
@@ -954,6 +970,41 @@ export async function handleTasks(
954
970
  const parentTask = parsed.body.parentTaskId
955
971
  ? await getTaskById(parsed.body.parentTaskId)
956
972
  : null;
973
+ // The child inherits the parent's thread context, so an agent caller must own or
974
+ // have created the parent. Operator and user callers keep their access.
975
+ const principal = await resolveTaskWritePrincipal(req, myAgentId);
976
+ if (
977
+ parentTask &&
978
+ !can({
979
+ principal,
980
+ verb: "task.parent.attach",
981
+ resource: {
982
+ kind: "task",
983
+ taskId: parentTask.id,
984
+ requestedByUserId: parentTask.requestedByUserId,
985
+ creatorAgentId: parentTask.creatorAgentId,
986
+ agentId: parentTask.agentId,
987
+ },
988
+ source: "http",
989
+ }).allow
990
+ ) {
991
+ jsonError(res, `You don't have context for parent task ${parentTask.id}.`, 403);
992
+ return true;
993
+ }
994
+ // A chat-sdk contextKey binds the task to a chat thread that its assignee and creator
995
+ // may then read and post to. An agent may only name a thread other than the parent's
996
+ // with the lead's chat post permission.
997
+ if (
998
+ principal.kind === "agent" &&
999
+ parsed.body.contextKey &&
1000
+ parsed.body.contextKey !== parentTask?.contextKey &&
1001
+ chatThreadOfContextKey(parsed.body.contextKey) &&
1002
+ !can({ principal, verb: "integration.chat.post", resource: { kind: "none" }, source: "http" })
1003
+ .allow
1004
+ ) {
1005
+ jsonError(res, "Permission denied: only a lead can bind a task to a chat thread.", 403);
1006
+ return true;
1007
+ }
957
1008
  let assetKey: string | undefined;
958
1009
  try {
959
1010
  const inheritedKey = parentTask?.key;
@@ -1083,6 +1134,7 @@ export async function handleTasks(
1083
1134
  parsed.body.model,
1084
1135
  "harnessVariant" in parsed.body ? parsed.body.harnessVariant : undefined,
1085
1136
  "harnessVariantMeta" in parsed.body ? parsed.body.harnessVariantMeta : undefined,
1137
+ "effort" in parsed.body ? parsed.body.effort : undefined,
1086
1138
  );
1087
1139
  if (!task) {
1088
1140
  jsonError(res, "Task not found", 404);
@@ -1667,10 +1719,14 @@ export async function handleTasks(
1667
1719
  }
1668
1720
  const pausedTasks = await getPausedTasksForAgent(myAgentId);
1669
1721
  const tasks = await Promise.all(
1670
- pausedTasks.map(async (task) => ({
1671
- ...task,
1672
- attachments: await getTaskAttachments(task.id),
1673
- })),
1722
+ pausedTasks.map(async (task) => {
1723
+ const requestedBy = await buildTaskRequestedBy(task);
1724
+ return {
1725
+ ...task,
1726
+ attachments: await getTaskAttachments(task.id),
1727
+ ...(requestedBy && { requestedBy }),
1728
+ };
1729
+ }),
1674
1730
  );
1675
1731
  listPausedTasks.respond(res, 200, { tasks });
1676
1732
  return true;
package/src/http/utils.ts CHANGED
@@ -2,6 +2,7 @@ import type { IncomingMessage, ServerResponse } from "node:http";
2
2
  import { getActiveTaskCount } from "../be/db";
3
3
  import type { SwarmSpan } from "../otel";
4
4
  import { isEnvFlagEnabled } from "../utils/env-flag";
5
+ import { getNodeEnv } from "../utils/node-env";
5
6
  import { scrubSecrets } from "../utils/secret-scrubber";
6
7
 
7
8
  export function duplicateGuardedQueryKey(query: URLSearchParams): string | undefined {
@@ -41,6 +42,18 @@ function getAllowedOrigins(): string[] {
41
42
  .filter(Boolean);
42
43
  }
43
44
 
45
+ /**
46
+ * Loopback origins on any port are trusted in local development
47
+ * (`NODE_ENV=development`, set by `start:http` and `dev:http`). The dashboard
48
+ * dev server, Playwright, or a second worktree pick arbitrary ports, and every
49
+ * loopback page already runs on the developer's machine. The production binary
50
+ * and the Docker image run without NODE_ENV, so this never applies there.
51
+ */
52
+ function isDevLoopbackOrigin(origin: string): boolean {
53
+ if (getNodeEnv() !== "development") return false;
54
+ return /^https?:\/\/(localhost|127\.0\.0\.1|\[::1\])(:\d{1,5})?$/.test(origin);
55
+ }
56
+
44
57
  /**
45
58
  * Decide whether `origin` may receive credentialed CORS headers.
46
59
  * Unset or blank uses the built-in hosted/dev allowlist. Exact entries retain
@@ -50,6 +63,7 @@ function getAllowedOrigins(): string[] {
50
63
  * Bare `*`, `https://*`, other wildcard positions, and non-origin URLs are ignored.
51
64
  */
52
65
  function originAllowedForCredentials(origin: string): boolean {
66
+ if (isDevLoopbackOrigin(origin)) return true;
53
67
  return getAllowedOrigins().some((entry) => {
54
68
  if (!entry.includes("*")) return entry === origin;
55
69
 
@@ -9,12 +9,25 @@ import {
9
9
  verifyAgentMailWebhook,
10
10
  } from "../agentmail";
11
11
  import { archiveInboundMessage } from "../agentmail/inbound-archive";
12
- import type { PullRequestCommentedEvent, PullRequestCreatedEvent } from "../azure-devops";
12
+ import type {
13
+ PullRequestCommentedEvent,
14
+ PullRequestCreatedEvent,
15
+ WorkItemCommentedEvent,
16
+ WorkItemCreatedEvent,
17
+ WorkItemDeletedEvent,
18
+ WorkItemRestoredEvent,
19
+ WorkItemUpdatedEvent,
20
+ } from "../azure-devops";
13
21
  import {
14
22
  commentedPayloadOf,
15
23
  createdPullRequestOf,
16
24
  handlePullRequestCommented,
17
25
  handlePullRequestCreated,
26
+ handleWorkItemCommented,
27
+ handleWorkItemCreated,
28
+ handleWorkItemDeleted,
29
+ handleWorkItemRestored,
30
+ handleWorkItemUpdated,
18
31
  isAzureDevOpsEnabled,
19
32
  verifyAzureDevOpsWebhook,
20
33
  } from "../azure-devops";
@@ -53,6 +66,14 @@ import {
53
66
  verifyGitLabWebhook,
54
67
  } from "../gitlab";
55
68
  import { gitlabWorkflowActionName } from "../gitlab/workflow-action-name";
69
+ import { trackBackground } from "../integrations/chat-sdk/background";
70
+ import { isChatSdkEnabled } from "../integrations/chat-sdk/config";
71
+ import {
72
+ getChatInstance,
73
+ isChatAdapterConfigured,
74
+ isChatSdkStopping,
75
+ } from "../integrations/chat-sdk/runtime";
76
+ import { isTrustedTeamsServiceUrl } from "../integrations/chat-sdk/teams-origin";
56
77
  import {
57
78
  type KapsoMessageActionResult,
58
79
  markKapsoMessageRead,
@@ -63,11 +84,14 @@ import { getKapsoConfig } from "../integrations/kapso/config";
63
84
  import type { KapsoWebhookPayload } from "../integrations/kapso/inbound";
64
85
  import { resolveKapsoRequestedByUserId, routeKapsoInbound } from "../integrations/kapso/inbound";
65
86
  import { TaskCreationBlockedError } from "../tasks/errors";
87
+ import { getPublicMcpBaseUrl } from "../utils/constants";
88
+ import { scrubSecrets } from "../utils/secret-scrubber";
66
89
  import { canonicalAzureDevOpsRepoUrl } from "../vcs/azure-devops";
67
90
  import { getExecutorRegistry } from "../workflows";
68
91
  import { workflowEventBus } from "../workflows/event-bus";
69
92
  import { handleWebhookTrigger, verifyHmacSignature, WebhookError } from "../workflows/triggers";
70
93
  import { route } from "./route-def";
94
+ import { BODY_TOO_LARGE, enforceContentLengthCap, jsonError } from "./utils";
71
95
 
72
96
  // ─── Route Definitions (documentation only — webhooks handle their own body parsing) ─
73
97
 
@@ -190,8 +214,75 @@ const kapsoWebhook = route({
190
214
  },
191
215
  });
192
216
 
217
+ const chatSdkWebhook = route({
218
+ method: "post",
219
+ path: "/api/integrations/chat/{adapter}/webhook",
220
+ pattern: ["api", "integrations", "chat", null, "webhook"],
221
+ summary: "Handle Chat SDK platform webhooks (Telegram, Slack, Discord, Teams)",
222
+ tags: ["Webhooks"],
223
+ params: z.object({ adapter: z.string().describe("Chat SDK adapter name, e.g. telegram") }),
224
+ auth: { apiKey: false },
225
+ rbac: {
226
+ ungated:
227
+ "provider webhook: the Chat SDK adapter verifies the platform signature (Telegram secret token, Slack signing secret, Discord Ed25519, Teams JWT)",
228
+ },
229
+ responses: {
230
+ 200: { description: "Adapter response", unstructured: "adapter response proxied as-is" },
231
+ 401: { description: "Invalid platform signature or secret token" },
232
+ 403: { description: "Teams activity whose serviceUrl is not a Bot Framework host" },
233
+ 404: { description: "Chat SDK disabled or adapter not configured" },
234
+ 413: { description: "Body exceeds 1 MiB" },
235
+ 503: { description: "Adapter configured but failed to start" },
236
+ },
237
+ });
238
+
239
+ /**
240
+ * Upper bound for a Chat SDK webhook body. Platform payloads are a few KB and
241
+ * files travel by URL, so anything larger is not a platform delivery.
242
+ */
243
+ const CHAT_SDK_WEBHOOK_MAX_BODY_BYTES = 1024 * 1024;
244
+
193
245
  // ─── Handler ─────────────────────────────────────────────────────────────────
194
246
 
247
+ /** False when a Teams activity body carries a `serviceUrl` that is not a Bot Framework host. */
248
+ function hasTrustedTeamsServiceUrl(body: Buffer): boolean {
249
+ let serviceUrl: unknown;
250
+ try {
251
+ serviceUrl = (JSON.parse(body.toString("utf-8")) as { serviceUrl?: unknown } | null)
252
+ ?.serviceUrl;
253
+ } catch {
254
+ // Not JSON: the adapter rejects it.
255
+ return true;
256
+ }
257
+ if (serviceUrl === undefined || serviceUrl === null || serviceUrl === "") return true;
258
+ return typeof serviceUrl === "string" && isTrustedTeamsServiceUrl(serviceUrl);
259
+ }
260
+
261
+ /**
262
+ * Rebuild a Fetch `Request` from the raw Node request. Headers come from
263
+ * `rawHeaders` pairs: building `Headers` from `IncomingMessage.headers`
264
+ * comma-joins repeated values, which breaks signature checks.
265
+ */
266
+ function toFetchRequest(req: IncomingMessage, rawBody: Buffer, fallbackPath: string): Request {
267
+ const headers = new Headers();
268
+ if (Array.isArray(req.rawHeaders) && req.rawHeaders.length > 0) {
269
+ for (let i = 0; i + 1 < req.rawHeaders.length; i += 2) {
270
+ headers.append(req.rawHeaders[i] as string, req.rawHeaders[i + 1] as string);
271
+ }
272
+ } else {
273
+ for (const [name, value] of Object.entries(req.headers)) {
274
+ for (const item of Array.isArray(value) ? value : value === undefined ? [] : [value]) {
275
+ headers.append(name, item);
276
+ }
277
+ }
278
+ }
279
+ return new Request(`${getPublicMcpBaseUrl()}${req.url ?? fallbackPath}`, {
280
+ method: req.method ?? "POST",
281
+ headers,
282
+ body: rawBody.length > 0 ? new Uint8Array(rawBody) : undefined,
283
+ });
284
+ }
285
+
195
286
  function logKapsoAckResult(action: string, result: KapsoMessageActionResult): void {
196
287
  if (result.ok) return;
197
288
  console.warn(
@@ -303,7 +394,8 @@ export async function handleWebhooks(
303
394
  return true;
304
395
  }
305
396
 
306
- console.log(`[GitHub] Received ${eventType} event`);
397
+ const deliveryId = req.headers["x-github-delivery"] as string | undefined;
398
+ console.log(`[GitHub] Received ${eventType} event (delivery ${deliveryId ?? "unknown"})`);
307
399
 
308
400
  let result: WebhookDispatchResult = { created: false };
309
401
 
@@ -560,6 +652,16 @@ export async function handleWebhooks(
560
652
  return await handlePullRequestCreated(body as PullRequestCreatedEvent);
561
653
  case "ms.vss-code.git-pullrequest-comment-event":
562
654
  return await handlePullRequestCommented(body as PullRequestCommentedEvent);
655
+ case "workitem.created":
656
+ return await handleWorkItemCreated(body as WorkItemCreatedEvent);
657
+ case "workitem.updated":
658
+ return await handleWorkItemUpdated(body as WorkItemUpdatedEvent);
659
+ case "workitem.commented":
660
+ return await handleWorkItemCommented(body as WorkItemCommentedEvent);
661
+ case "workitem.deleted":
662
+ return await handleWorkItemDeleted(body as WorkItemDeletedEvent);
663
+ case "workitem.restored":
664
+ return await handleWorkItemRestored(body as WorkItemRestoredEvent);
563
665
  default:
564
666
  console.log(`[AzureDevOps] Ignoring unsupported event type: ${eventType}`);
565
667
  return { created: false };
@@ -795,5 +897,84 @@ export async function handleWebhooks(
795
897
  return true;
796
898
  }
797
899
 
900
+ // Chat SDK webhook: the adapter verifies the platform signature over the raw
901
+ // body, so the request is proxied as-is and the adapter's response returned.
902
+ if (chatSdkWebhook.match(req.method, pathSegments)) {
903
+ const adapterName = pathSegments[3] ?? "";
904
+ if (!isChatSdkEnabled() || !isChatAdapterConfigured(adapterName)) {
905
+ res.writeHead(404, { "Content-Type": "application/json" });
906
+ res.end(JSON.stringify({ error: "Chat SDK adapter not configured" }));
907
+ return true;
908
+ }
909
+ if (isChatSdkStopping()) {
910
+ res.writeHead(503, { "Content-Type": "application/json" });
911
+ res.end(JSON.stringify({ error: "Chat SDK is shutting down" }));
912
+ return true;
913
+ }
914
+ const chat = getChatInstance(adapterName);
915
+ const handler = chat?.webhooks[adapterName];
916
+ if (!handler) {
917
+ res.writeHead(503, { "Content-Type": "application/json" });
918
+ res.end(JSON.stringify({ error: "Chat SDK adapter failed to start" }));
919
+ return true;
920
+ }
921
+
922
+ // The route is unauthenticated and the adapter verifies the signature over
923
+ // the buffered body, so the body is bounded before it is buffered. An
924
+ // oversized stream is answered at once and drained without buffering, the
925
+ // same way `parseBody` keeps the connection usable.
926
+ if (enforceContentLengthCap(req, res, CHAT_SDK_WEBHOOK_MAX_BODY_BYTES) === BODY_TOO_LARGE) {
927
+ return true;
928
+ }
929
+ const chunks: Buffer[] = [];
930
+ let receivedBytes = 0;
931
+ let tooLarge = false;
932
+ for await (const chunk of req) {
933
+ if (tooLarge) continue;
934
+ receivedBytes += (chunk as Buffer).byteLength;
935
+ if (receivedBytes > CHAT_SDK_WEBHOOK_MAX_BODY_BYTES) {
936
+ tooLarge = true;
937
+ chunks.length = 0;
938
+ jsonError(res, `Payload too large (max ${CHAT_SDK_WEBHOOK_MAX_BODY_BYTES} bytes)`, 413);
939
+ continue;
940
+ }
941
+ chunks.push(chunk as Buffer);
942
+ }
943
+ if (tooLarge) return true;
944
+ const rawBody = Buffer.concat(chunks);
945
+ // The Teams adapter replies, reads history and downloads files with the
946
+ // bot token at the activity's serviceUrl, and caches it for DMs. Refuse an
947
+ // untrusted one before the adapter sees the activity.
948
+ if (adapterName === "teams" && !hasTrustedTeamsServiceUrl(rawBody)) {
949
+ console.warn("[chat-sdk] teams webhook refused: serviceUrl is not a Bot Framework host");
950
+ res.writeHead(403, { "Content-Type": "application/json" });
951
+ res.end(JSON.stringify({ error: "Untrusted Teams serviceUrl" }));
952
+ return true;
953
+ }
954
+ const request = toFetchRequest(req, rawBody, `/api/integrations/chat/${adapterName}/webhook`);
955
+
956
+ try {
957
+ const response = await handler(request, {
958
+ // Handler errors are logged by `trackBackground` in `handlers.ts`.
959
+ waitUntil: trackBackground,
960
+ });
961
+ const responseHeaders: Record<string, string> = {};
962
+ response.headers.forEach((value, name) => {
963
+ responseHeaders[name] = value;
964
+ });
965
+ const body = Buffer.from(await response.arrayBuffer());
966
+ res.writeHead(response.status, responseHeaders);
967
+ res.end(body);
968
+ } catch (err) {
969
+ const message = err instanceof Error ? err.message : String(err);
970
+ console.error(`[chat-sdk] ${adapterName} webhook failed: ${scrubSecrets(message)}`);
971
+ if (!res.headersSent) {
972
+ res.writeHead(500, { "Content-Type": "application/json" });
973
+ }
974
+ res.end(JSON.stringify({ error: "Chat SDK webhook failed" }));
975
+ }
976
+ return true;
977
+ }
978
+
798
979
  return false;
799
980
  }
package/src/http/x.ts CHANGED
@@ -255,6 +255,7 @@ export async function handleX(
255
255
  timeoutMs,
256
256
  egressSecrets: credentials.egressSecrets,
257
257
  failedBindings: credentials.failedBindings,
258
+ userConfig: credentials.userConfig,
258
259
  apiConnections: getScriptApiConnectionDescriptors({ agentId: endpoint.agentId }),
259
260
  mcpConnections: getScriptMcpConnectionDescriptors({ agentId: endpoint.agentId }),
260
261
  });
@@ -0,0 +1,129 @@
1
+ import type { Adapter, Logger } from "chat";
2
+ import { type ChatSdkAdapterName, type ResolvedAdapterConfig, readApiUrlOverrides } from "./config";
3
+ import { withInfoFilter } from "./logger";
4
+ import { getChatSdkTestHooks } from "./test-hooks";
5
+
6
+ /**
7
+ * Platform API bases passed explicitly so the adapters never fall back to
8
+ * `TELEGRAM_API_BASE_URL` / `SLACK_API_URL` / `DISCORD_API_URL` /
9
+ * `TEAMS_API_URL` from `process.env`. Global swarm_config rows are injected
10
+ * into `process.env`, so an env fallback would let a config row redirect bot
11
+ * tokens to another host. Teams gets "" which blocks only `TEAMS_API_URL`.
12
+ * The other Teams SDK env fallbacks (`SERVICE_URL`, `TENANT_ID`, `CLIENT_ID`,
13
+ * `CLIENT_SECRET`, `MANAGED_IDENTITY_CLIENT_ID`, `CLOUD`) are closed by the
14
+ * injection denylist in `getInjectableGlobalConfigs` (`src/be/db.ts`).
15
+ * Deployment env can still set them on purpose.
16
+ */
17
+ const DEFAULT_API_URLS: Record<ChatSdkAdapterName, string> = {
18
+ telegram: "https://api.telegram.org",
19
+ slack: "https://slack.com/api/",
20
+ discord: "https://discord.com/api/v10",
21
+ teams: "",
22
+ };
23
+
24
+ /**
25
+ * Discord adapter info lines dropped from the logs. They fire per event and
26
+ * carry guild message content (first 100 chars), or the public key and
27
+ * signature prefix of every interaction. Warn and error lines are kept.
28
+ */
29
+ const DISCORD_NOISY_INFO_PREFIXES = [
30
+ "Discord Gateway message received",
31
+ "Discord webhook received",
32
+ "Discord signature verification",
33
+ "Discord interaction parsed",
34
+ "Discord PING received",
35
+ ];
36
+
37
+ export function keepDiscordInfoLine(message: string): boolean {
38
+ return !DISCORD_NOISY_INFO_PREFIXES.some((prefix) => message.startsWith(prefix));
39
+ }
40
+
41
+ /**
42
+ * Platform API base for one adapter: the env-only `CHAT_SDK_API_URL_OVERRIDES`
43
+ * entry, else the platform default. The adapters and the Telegram
44
+ * register-webhook route use the same base.
45
+ */
46
+ export function resolveAdapterApiUrl(name: ChatSdkAdapterName): string {
47
+ return readApiUrlOverrides()[name] ?? DEFAULT_API_URLS[name];
48
+ }
49
+
50
+ /**
51
+ * Construct one adapter. Each branch is a literal-path dynamic import so
52
+ * `bun build --compile` bundles it (a computed specifier is not bundled).
53
+ * `apiUrl` comes only from the env-only `CHAT_SDK_API_URL_OVERRIDES`.
54
+ */
55
+ export async function loadAdapter(
56
+ name: ChatSdkAdapterName,
57
+ config: ResolvedAdapterConfig,
58
+ logger: Logger,
59
+ ): Promise<Adapter> {
60
+ const apiUrl = resolveAdapterApiUrl(name);
61
+ const base = { ...config, apiUrl, logger };
62
+ switch (name) {
63
+ case "telegram": {
64
+ const { createTelegramAdapter } = await import("@chat-adapter/telegram");
65
+ // Explicit `false` blocks the TELEGRAM_ALLOW_UNVERIFIED_WEBHOOKS env fallback.
66
+ return createTelegramAdapter({ ...base, allowUnverifiedWebhooks: false } as Parameters<
67
+ typeof createTelegramAdapter
68
+ >[0]);
69
+ }
70
+ case "slack": {
71
+ const { createSlackAdapter } = await import("@chat-adapter/slack");
72
+ // "" (not undefined) blocks each `?? process.env.SLACK_*` fallback, which
73
+ // would pick up the built-in Slack app's secrets. Socket forwarding and
74
+ // the installation encryption key are multi-workspace features we do not
75
+ // use; "" turns both off.
76
+ return createSlackAdapter({
77
+ ...base,
78
+ signingSecret: config.signingSecret ?? "",
79
+ appToken: config.appToken ?? "",
80
+ socketForwardingSecret: "",
81
+ encryptionKey: "",
82
+ } as Parameters<typeof createSlackAdapter>[0]);
83
+ }
84
+ case "discord": {
85
+ const { createDiscordAdapter } = await import("@chat-adapter/discord");
86
+ // `[]` (not undefined) blocks the DISCORD_RESPOND_TO_CHANNEL_IDS and
87
+ // DISCORD_MENTION_ROLE_IDS env fallbacks.
88
+ return createDiscordAdapter({
89
+ ...base,
90
+ logger: withInfoFilter(logger, keepDiscordInfoLine),
91
+ respondToChannelIds: config.respondToChannelIds ?? [],
92
+ mentionRoleIds: config.mentionRoleIds ?? [],
93
+ } as Parameters<typeof createDiscordAdapter>[0]);
94
+ }
95
+ case "teams": {
96
+ const { createTeamsAdapter } = await import("@chat-adapter/teams");
97
+ // `webhookVerifier` replaces the Bot Framework JWT check and `token` the
98
+ // bot token call. Only tests set them (test-hooks.ts); the operator
99
+ // schema rejects `webhookVerifier`, and `token` is a function.
100
+ const { teamsWebhookVerifier, teamsToken } = getChatSdkTestHooks();
101
+ return createTeamsAdapter({
102
+ ...base,
103
+ ...(teamsWebhookVerifier ? { webhookVerifier: teamsWebhookVerifier } : {}),
104
+ ...(teamsToken ? { token: teamsToken } : {}),
105
+ } as Parameters<typeof createTeamsAdapter>[0]);
106
+ }
107
+ }
108
+ }
109
+
110
+ type SocketClientLike = { on(event: string, listener: () => void): unknown };
111
+
112
+ /**
113
+ * Slack socket mode reconnects on its own and logs through its own logger,
114
+ * not ours. Surface hard failures through the scrubbing logger so adapter
115
+ * health (`lastWarning`) shows them. A failed first connect rejects
116
+ * `initialize()` for auth errors. Network failures go through the WebClient
117
+ * retry policy and can take long before they surface here.
118
+ * `reconnecting` also fires on Slack's routine connection refresh, so it is
119
+ * logged at info only and never reaches health.
120
+ */
121
+ export function watchSocketConnection(adapter: Adapter, logger: Logger): void {
122
+ const client = (adapter as { socketClient?: SocketClientLike }).socketClient;
123
+ if (!client) return;
124
+ client.on("reconnecting", () => logger.info("Slack socket mode reconnecting"));
125
+ client.on("unable_to_socket_mode_start", () =>
126
+ logger.warn("Slack socket mode unable to start, retrying"),
127
+ );
128
+ client.on("error", () => logger.warn("Slack socket mode error"));
129
+ }