@desplega.ai/agent-swarm 1.173.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (511) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-ccm9xrep.js → acp-adapter-kr4abrsk.js} +17 -16
  3. package/dist/{actions-sgeyv08k.js → actions-eh4g6w2r.js} +39 -34
  4. package/dist/{amp-adapter-gpxp3kc9.js → amp-adapter-7h7wdt8q.js} +8 -7
  5. package/dist/{app-km9qnv2f.js → app-7k8s9w5p.js} +18 -14
  6. package/dist/{assistant-5r8tcvvd.js → assistant-wswt2y7p.js} +40 -35
  7. package/dist/{boot-reembed-16rv9843.js → boot-reembed-9apm9qw6.js} +10 -9
  8. package/dist/{boot-reembed-swwzdgd7.js → boot-reembed-whzbdthj.js} +10 -9
  9. package/dist/{boot-scrub-sweep-zkr6vkqb.js → boot-scrub-sweep-ndzmvmgt.js} +11 -10
  10. package/dist/{boot-seeds-d8sp49t2.js → boot-seeds-e9sta0yt.js} +16 -13
  11. package/dist/{claude-adapter-yzzzh8jp.js → claude-adapter-4mqd3r6r.js} +19 -18
  12. package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-9wswb52m.js} +7 -5
  13. package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-tpe1effx.js} +6 -4
  14. package/dist/{claude-sdk-session-4whxere4.js → claude-sdk-session-q49ghmh9.js} +12402 -11850
  15. package/dist/{cli-ne7smj1b.js → cli-01xvj1rq.js} +10 -10
  16. package/dist/{cli-nwrdx840.js → cli-035vekcw.js} +3 -3
  17. package/dist/{cli-9xf7fdtp.js → cli-0pd8hzhc.js} +29 -6
  18. package/dist/{cli-tmhsxhb8.js → cli-0veb92a3.js} +28 -6
  19. package/dist/{cli-c3rk1v0x.js → cli-10jesr25.js} +3 -3
  20. package/dist/{cli-6thk4jz3.js → cli-1y7yywmj.js} +6 -6
  21. package/dist/{cli-6r2f7edk.js → cli-20krdhz5.js} +47 -19
  22. package/dist/{cli-rfs4vddv.js → cli-29rja109.js} +39 -20
  23. package/dist/cli-2m1ktfzz.js +17795 -0
  24. package/dist/{cli-na2pxe4f.js → cli-2pwa0q4d.js} +15 -4
  25. package/dist/{cli-7a93cv8c.js → cli-4mengw46.js} +441 -43
  26. package/dist/{cli-94b48jhk.js → cli-5twdke5x.js} +16 -14
  27. package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
  28. package/dist/cli-6cvfxs8r.js +47 -0
  29. package/dist/{cli-w1apjecb.js → cli-711vwbxn.js} +2 -2
  30. package/dist/{cli-r4fqfpwf.js → cli-78vv7446.js} +50 -27
  31. package/dist/{cli-srqq3gc5.js → cli-7n6s5man.js} +5 -5
  32. package/dist/{cli-m89t9jdf.js → cli-7x0g4sn1.js} +15416 -16024
  33. package/dist/{cli-2bw3w47j.js → cli-8wwxw8a3.js} +1 -1
  34. package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
  35. package/dist/{cli-ywm1azg9.js → cli-9jzdj90z.js} +8 -4
  36. package/dist/cli-9traj3dn.js +638 -0
  37. package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
  38. package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
  39. package/dist/cli-cvv9k0hh.js +10143 -0
  40. package/dist/{cli-anzdk0z4.js → cli-d9286m9h.js} +2 -2
  41. package/dist/cli-e3g5mbkz.js +776 -0
  42. package/dist/cli-f527ce74.js +781 -0
  43. package/dist/{cli-gmdajfw5.js → cli-gxzkg1de.js} +5020 -1729
  44. package/dist/{cli-451ks6aw.js → cli-h1arqn31.js} +1 -1
  45. package/dist/cli-hjwmhcg1.js +10622 -0
  46. package/dist/{cli-jpc4r224.js → cli-hqr88ew6.js} +19 -3
  47. package/dist/{cli-h7k0xtry.js → cli-hvqbtna4.js} +4 -1256
  48. package/dist/{cli-cd0hv9nh.js → cli-j67mh2vg.js} +2 -2
  49. package/dist/cli-jta2eyzc.js +619 -0
  50. package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
  51. package/dist/cli-kceah1eh.js +92 -0
  52. package/dist/{cli-d603qf86.js → cli-ksphgh48.js} +10 -8
  53. package/dist/{cli-3nxdmjrc.js → cli-mgz4nbgg.js} +4 -4
  54. package/dist/{cli-saqyage0.js → cli-mz5as5ha.js} +179 -27
  55. package/dist/cli-n2wq4j7m.js +6985 -0
  56. package/dist/{cli-ppy4nnnh.js → cli-n8ndw8j7.js} +2 -2
  57. package/dist/{cli-1w0vj3gw.js → cli-naqzr17j.js} +7 -7
  58. package/dist/{cli-0a7mm3zp.js → cli-nm1p8jfr.js} +25 -21
  59. package/dist/{cli-wrh08zjd.js → cli-p3zbc1rw.js} +5 -18
  60. package/dist/{cli-hsem16hb.js → cli-pe05f8yk.js} +29 -6
  61. package/dist/{cli-5wpw4rab.js → cli-qmzsbkvy.js} +5 -5
  62. package/dist/{cli-bv2etw2y.js → cli-qnm4e9e4.js} +99 -590
  63. package/dist/{cli-1x7da0de.js → cli-qqy4q48b.js} +8 -8
  64. package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
  65. package/dist/{cli-5er5gjbm.js → cli-r35rw5de.js} +15 -15
  66. package/dist/{cli-v3zhnxsb.js → cli-r610p9bs.js} +2 -2
  67. package/dist/{cli-7jykv7ef.js → cli-rc6pf5kv.js} +1 -1
  68. package/dist/{cli-x119kdba.js → cli-rdxm77k3.js} +1 -1
  69. package/dist/cli-rhs9pz33.js +294 -0
  70. package/dist/{cli-0p3enk35.js → cli-s69nfyeh.js} +9 -1
  71. package/dist/{cli-0kxf81jj.js → cli-sawv63e8.js} +2 -2
  72. package/dist/{cli-e3pmyt39.js → cli-sg19gbf0.js} +1 -1
  73. package/dist/{cli-d161g69q.js → cli-shk7r5cs.js} +57 -6
  74. package/dist/{cli-7pz3b7x5.js → cli-sksetb2q.js} +36 -1
  75. package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
  76. package/dist/{cli-db3m6zdt.js → cli-t02z59f2.js} +1 -1
  77. package/dist/{cli-b07hr3bt.js → cli-txqb9s38.js} +2 -2
  78. package/dist/{cli-s8z6x4b4.js → cli-v7g551te.js} +225 -113
  79. package/dist/{cli-rfz2ve55.js → cli-vgqzp4em.js} +3341 -955
  80. package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
  81. package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
  82. package/dist/cli-wfnemr1t.js +86 -0
  83. package/dist/cli-wmgrkscj.js +23254 -0
  84. package/dist/{cli-qm1448f9.js → cli-wms6x9db.js} +8 -8
  85. package/dist/{cli-tadfgd0t.js → cli-x1r545x8.js} +33 -4
  86. package/dist/{cli-xc7p7s3g.js → cli-xczsgshn.js} +6 -6
  87. package/dist/{cli-fmhj1ehj.js → cli-y3167wt1.js} +882 -271
  88. package/dist/{cli-r0byd61h.js → cli-yjmqpxt3.js} +17 -16
  89. package/dist/{cli-81r1wjyv.js → cli-z780ec7c.js} +1 -1
  90. package/dist/{cli-phcqp1b9.js → cli-zm9t2vde.js} +2 -2
  91. package/dist/cli.js +34 -49
  92. package/dist/{codex-adapter-r3dn4fp5.js → codex-adapter-4z16v9n0.js} +15 -14
  93. package/dist/{codex-login-841kv5fk.js → codex-login-pkepy2j1.js} +3 -2
  94. package/dist/{codex-session-runner-fwt793h4.js → codex-session-runner-rvms9y2x.js} +15 -14
  95. package/dist/{commands-z8fq9qna.js → commands-2a9rtyat.js} +11 -10
  96. package/dist/{controller-hq5ggpcp.js → controller-3k3madbn.js} +5 -4
  97. package/dist/{controllers-connect-3mf2btyj.js → controllers-connect-v9yn8zb9.js} +42 -37
  98. package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-98gbhyzn.js} +7 -6
  99. package/dist/{db-qfpq4bt7.js → db-eywwsnjw.js} +30 -9
  100. package/dist/{db-yyhqqrbf.js → db-ncypk9np.js} +12 -11
  101. package/dist/{devin-adapter-xgtj680j.js → devin-adapter-zeq8b9gz.js} +3 -2
  102. package/dist/{dispatcher-x0x7qfcq.js → dispatcher-w94kc575.js} +38 -33
  103. package/dist/{docker-f503k9p0.js → docker-b1e4cqab.js} +3 -2
  104. package/dist/{dsh-adapter-34etvb5m.js → dsh-adapter-47ztej36.js} +7 -6
  105. package/dist/{e2b-66xra4az.js → e2b-bbt8ey45.js} +4 -3
  106. package/dist/{e2b-xwhyj8cw.js → e2b-dp804sen.js} +4 -3
  107. package/dist/{event-bus-vjtv82gm.js → event-bus-j2jdg3qb.js} +3 -2
  108. package/dist/{external-channel-h1fjecwe.js → external-channel-zrkg8ar9.js} +11 -10
  109. package/dist/{google-generative-ai-szdxbpqg.js → google-generative-ai-g8db7x0f.js} +4 -2
  110. package/dist/{google-vertex-qzw3p36d.js → google-vertex-r2692q0r.js} +4 -2
  111. package/dist/{grok-adapter-e7mr287e.js → grok-adapter-s9ncp9vy.js} +18 -17
  112. package/dist/{handlers-znb9n7d4.js → handlers-kqftvjgw.js} +41 -36
  113. package/dist/{heartbeat-bm4qkn8d.js → heartbeat-9q96p8v9.js} +43 -38
  114. package/dist/{hook-254r4mza.js → hook-56qe10dp.js} +11 -23
  115. package/dist/{hook-xaa3q80s.js → hook-yy6rw42k.js} +12 -11
  116. package/dist/{http-3dgrgp8y.js → http-r2dnb8f8.js} +2411 -275
  117. package/dist/{index-fx3jqq1e.js → index-3gtmkhc6.js} +38 -33
  118. package/dist/{index-bdsqa799.js → index-3k5hkz7r.js} +43 -38
  119. package/dist/index-52j1aja4.js +3465 -0
  120. package/dist/{index-g2byveez.js → index-5e101240.js} +38 -33
  121. package/dist/{index-2ybk7khy.js → index-5wyfjc2c.js} +845 -683
  122. package/dist/index-9gw58n4k.js +193 -0
  123. package/dist/index-9j87mcm8.js +56305 -0
  124. package/dist/index-bsmcresk.js +79424 -0
  125. package/dist/index-mh85qhec.js +475 -0
  126. package/dist/{index-jd7sejm2.js → index-vxvhxxbn.js} +10 -9
  127. package/dist/index-we27kd31.js +12810 -0
  128. package/dist/{keepalive-6ywhpja1.js → keepalive-psj6j54c.js} +12 -11
  129. package/dist/{lead-cw45n21s.js → lead-hajz4688.js} +61 -56
  130. package/dist/{maintenance-ss1a1ge9.js → maintenance-ps02sb5m.js} +10 -9
  131. package/dist/{node-fkajaq96.js → node-mwb5r697.js} +2 -1
  132. package/dist/{oauth-refresh-sweep-3c6f8vyy.js → oauth-refresh-sweep-0284h93b.js} +11 -10
  133. package/dist/{onboard-8hzdhc1k.js → onboard-rbf6bg01.js} +11 -3
  134. package/dist/{opencode-adapter-qbchbcfz.js → opencode-adapter-13dcatgq.js} +18 -13
  135. package/dist/{otel-impl-e6mnvc4v.js → otel-impl-zvqcbhp7.js} +242 -868
  136. package/dist/{pi-mono-adapter-3c9g9snh.js → pi-mono-adapter-xxy47q4v.js} +244 -106
  137. package/dist/{pricing-refresh-gedkjdw0.js → pricing-refresh-kefx9v3t.js} +12 -11
  138. package/dist/{rbac-roles-dt4vh1yy.js → rbac-roles-3m36rxm2.js} +11 -10
  139. package/dist/{rbac-roles-eszdg6pm.js → rbac-roles-z76xv0hq.js} +12 -11
  140. package/dist/{render-v2-907cy6sa.js → render-v2-wz73bs25.js} +18 -14
  141. package/dist/{resume-42stcaz0.js → resume-k4wzge8w.js} +25 -21
  142. package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
  143. package/dist/{setup-adbc1c10.js → setup-2fp2pypp.js} +2 -2
  144. package/dist/{virtual-modules-rtmt494q.js → virtual-modules-9gkxqrap.js} +6 -5
  145. package/dist/{work-objects-wpj8ck95.js → work-objects-6k0ywz3m.js} +41 -36
  146. package/dist/{worker-bzdra9rf.js → worker-5v3rxsdh.js} +61 -56
  147. package/dist/{x-qfmygqqv.js → x-4mtdeym1.js} +3 -2
  148. package/openapi.json +1279 -329
  149. package/package.json +15 -15
  150. package/src/agentmail/handlers.ts +21 -11
  151. package/src/apps/definition.ts +16 -0
  152. package/src/azure-devops/api.ts +52 -2
  153. package/src/azure-devops/boards-sync.ts +50 -20
  154. package/src/azure-devops/index.ts +1 -0
  155. package/src/azure-devops/outbound.ts +95 -0
  156. package/src/be/boot-seeds.ts +11 -0
  157. package/src/be/config-refs.ts +60 -0
  158. package/src/be/db/model-profiles.ts +315 -0
  159. package/src/be/db/page-versions.ts +15 -0
  160. package/src/be/db/runtime.ts +35 -8
  161. package/src/be/db/skill-name-resolution.ts +36 -0
  162. package/src/be/db/tasks/read.ts +237 -0
  163. package/src/be/db/tasks/write.ts +7 -0
  164. package/src/be/db.ts +87 -36
  165. package/src/be/migrations/215_swarm_config_export_to_env.sql +34 -0
  166. package/src/be/migrations/216_task_resolved_effort.sql +5 -0
  167. package/src/be/migrations/217_chat_sdk_state.sql +104 -0
  168. package/src/be/migrations/219_relabel_pi_context_compactions.sql +22 -0
  169. package/src/be/migrations/220_model_profiles.sql +137 -0
  170. package/src/be/model-catalog-store.ts +5 -1
  171. package/src/be/model-tier-resolution.ts +155 -10
  172. package/src/be/model-validation.ts +12 -2
  173. package/src/be/models-catalog.ts +26 -1
  174. package/src/be/modelsdev-cache.json +198 -63
  175. package/src/be/modelsdev-cache.ts +9 -1
  176. package/src/be/script-credential-broker.ts +39 -2
  177. package/src/be/scripts/run-saved.ts +1 -0
  178. package/src/be/scripts/typecheck.ts +22 -8
  179. package/src/be/secret-registry.ts +6 -2
  180. package/src/be/seed/runner.ts +13 -1
  181. package/src/be/seed/state-db.ts +5 -0
  182. package/src/be/seed/types.ts +6 -0
  183. package/src/be/seed-model-profiles.ts +41 -0
  184. package/src/be/seed-pricing.ts +19 -2
  185. package/src/be/seed-scripts/catalog/heartbeat-jev-gate.ts +368 -0
  186. package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
  187. package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
  188. package/src/be/seed-scripts/index.ts +9 -0
  189. package/src/be/seed-skills/bundled-files.generated.json +0 -18
  190. package/src/be/seed-skills/index.ts +104 -3
  191. package/src/be/swarm-config-guard.ts +53 -0
  192. package/src/cli.tsx +0 -16
  193. package/src/commands/onboard/non-interactive.ts +4 -2
  194. package/src/commands/provider-credentials.ts +52 -6
  195. package/src/commands/runner.ts +193 -71
  196. package/src/e2b/env.ts +5 -0
  197. package/src/extensions/catalog.generated.json +17 -0
  198. package/src/extensions/contract-types.generated.ts +1 -1
  199. package/src/extensions/contract.ts +45 -0
  200. package/src/extensions/dispatcher.ts +7 -0
  201. package/src/extensions/loader.ts +10 -5
  202. package/src/extensions/post-bridge.ts +40 -0
  203. package/src/github/handlers.ts +11 -4
  204. package/src/heartbeat/heartbeat.ts +2 -1
  205. package/src/heartbeat/templates.ts +8 -5
  206. package/src/hooks/hook.ts +0 -26
  207. package/src/http/agents.ts +49 -2
  208. package/src/http/all-routes.ts +1 -1
  209. package/src/http/apps.ts +30 -3
  210. package/src/http/config.ts +62 -19
  211. package/src/http/core.ts +8 -0
  212. package/src/http/index.ts +25 -3
  213. package/src/http/integrations.ts +88 -1
  214. package/src/http/mcp.ts +15 -5
  215. package/src/http/model-profiles.ts +303 -0
  216. package/src/http/page-proxy.ts +2 -4
  217. package/src/http/pages-public.ts +13 -7
  218. package/src/http/pages.ts +3 -13
  219. package/src/http/poll.ts +42 -71
  220. package/src/http/requested-by.ts +54 -0
  221. package/src/http/script-runs.ts +1 -1
  222. package/src/http/scripts.ts +26 -2
  223. package/src/http/stats.ts +1 -30
  224. package/src/http/tasks.ts +79 -5
  225. package/src/http/utils.ts +14 -0
  226. package/src/http/webhooks.ts +160 -3
  227. package/src/http/x.ts +1 -0
  228. package/src/integrations/chat-sdk/adapters.ts +129 -0
  229. package/src/integrations/chat-sdk/attachments.ts +232 -0
  230. package/src/integrations/chat-sdk/background.ts +36 -0
  231. package/src/integrations/chat-sdk/commands.ts +194 -0
  232. package/src/integrations/chat-sdk/config.ts +198 -0
  233. package/src/integrations/chat-sdk/discord-api.ts +63 -0
  234. package/src/integrations/chat-sdk/discord-gateway.ts +185 -0
  235. package/src/integrations/chat-sdk/handlers.ts +28 -0
  236. package/src/integrations/chat-sdk/inbound.ts +426 -0
  237. package/src/integrations/chat-sdk/limits.ts +48 -0
  238. package/src/integrations/chat-sdk/logger.ts +81 -0
  239. package/src/integrations/chat-sdk/outbound.ts +123 -0
  240. package/src/integrations/chat-sdk/relay.ts +172 -0
  241. package/src/integrations/chat-sdk/router.ts +169 -0
  242. package/src/integrations/chat-sdk/runtime.ts +351 -0
  243. package/src/integrations/chat-sdk/schema.ts +245 -0
  244. package/src/integrations/chat-sdk/state.ts +243 -0
  245. package/src/integrations/chat-sdk/status.ts +244 -0
  246. package/src/integrations/chat-sdk/steering.ts +58 -0
  247. package/src/integrations/chat-sdk/teams-origin.ts +77 -0
  248. package/src/integrations/chat-sdk/telegram-api.ts +56 -0
  249. package/src/integrations/chat-sdk/templates.ts +16 -0
  250. package/src/integrations/chat-sdk/test-hooks.ts +37 -0
  251. package/src/integrations/chat-sdk/thread-buffer.ts +100 -0
  252. package/src/integrations/chat-sdk/typing.ts +65 -0
  253. package/src/{artifact-sdk → pages}/feedback-overlay.ts +65 -6
  254. package/src/pages/version.ts +4 -5
  255. package/src/prompts/base-prompt.ts +111 -45
  256. package/src/providers/acp-target-catalog.ts +6 -0
  257. package/src/providers/acp-targets.ts +56 -3
  258. package/src/providers/amp-adapter.ts +1 -1
  259. package/src/providers/claude-adapter.ts +1 -1
  260. package/src/providers/claude-flag-settings.ts +17 -5
  261. package/src/providers/claude-managed-adapter.ts +1 -1
  262. package/src/providers/claude-session-events.ts +6 -1
  263. package/src/providers/dsh-adapter.ts +1 -1
  264. package/src/providers/opencode-adapter.ts +243 -26
  265. package/src/providers/opencode-swarm-plugin.ts +31 -0
  266. package/src/providers/pi-mono-adapter.ts +398 -153
  267. package/src/providers/pi-mono-extension.ts +17 -3
  268. package/src/providers/pricing-sources.md +33 -2
  269. package/src/providers/reasoning-effort.ts +37 -0
  270. package/src/providers/types.ts +6 -2
  271. package/src/rbac/legacy-policy.ts +16 -2
  272. package/src/rbac/permissions.ts +26 -0
  273. package/src/scheduler/deferred-task-waits.ts +18 -5
  274. package/src/scheduler/scheduler.ts +11 -3
  275. package/src/scripts-runtime/executors/quickjs-prelude.ts +75 -6
  276. package/src/scripts-runtime/executors/quickjs-runner.ts +85 -8
  277. package/src/scripts-runtime/executors/quickjs-web-shims.ts +1041 -0
  278. package/src/scripts-runtime/extract-args-schema.ts +9 -8
  279. package/src/scripts-runtime/loader.ts +19 -7
  280. package/src/scripts-runtime/quickjs-compat.ts +464 -0
  281. package/src/scripts-runtime/sdk-allowlist.ts +12 -6
  282. package/src/scripts-runtime/swarm-sdk.ts +0 -11
  283. package/src/scripts-runtime/types/stdlib.d.ts +39 -15
  284. package/src/scripts-runtime/types/swarm-extension.d.ts +66 -1
  285. package/src/scripts-runtime/types/swarm-sdk.d.ts +39 -15
  286. package/src/server.ts +62 -19
  287. package/src/slack/blocks.ts +4 -2
  288. package/src/slack/event-dedup.ts +1 -1
  289. package/src/slack/reaction-shortcode.ts +14 -0
  290. package/src/slack/render-v2.ts +12 -7
  291. package/src/slack/responses.ts +5 -4
  292. package/src/slack/thread-buffer.ts +41 -22
  293. package/src/tasks/additive-buffer.ts +4 -2
  294. package/src/tasks/context-key.ts +60 -1
  295. package/src/tasks/model-pin.ts +67 -0
  296. package/src/tasks/worker-follow-up.ts +15 -33
  297. package/src/tests/acp-adapter.test.ts +42 -0
  298. package/src/tests/agentmail-filters.test.ts +47 -0
  299. package/src/tests/api-drain-worker-e2e.test.ts +1 -6
  300. package/src/tests/apps-spike2.test.ts +35 -0
  301. package/src/tests/azure-devops-outbound.test.ts +420 -0
  302. package/src/tests/base-prompt.test.ts +58 -54
  303. package/src/tests/chat-sdk-commands.test.ts +191 -0
  304. package/src/tests/chat-sdk-config.test.ts +334 -0
  305. package/src/tests/chat-sdk-discord-api.test.ts +68 -0
  306. package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
  307. package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
  308. package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
  309. package/src/tests/chat-sdk-harness.ts +146 -0
  310. package/src/tests/chat-sdk-inbound.test.ts +363 -0
  311. package/src/tests/chat-sdk-relay.test.ts +470 -0
  312. package/src/tests/chat-sdk-reload.test.ts +128 -0
  313. package/src/tests/chat-sdk-shutdown.test.ts +220 -0
  314. package/src/tests/chat-sdk-slack.test.ts +268 -0
  315. package/src/tests/chat-sdk-state.test.ts +163 -0
  316. package/src/tests/chat-sdk-status-route.test.ts +382 -0
  317. package/src/tests/chat-sdk-teams.test.ts +277 -0
  318. package/src/tests/chat-sdk-tools.test.ts +520 -0
  319. package/src/tests/chat-sdk-typing.test.ts +120 -0
  320. package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
  321. package/src/tests/claude-adapter-binary.test.ts +9 -4
  322. package/src/tests/claude-flag-settings.test.ts +11 -3
  323. package/src/tests/claude-managed-adapter.test.ts +1 -1
  324. package/src/tests/claude-sdk-lifecycle.test.ts +9 -3
  325. package/src/tests/claude-thinking-tokens.test.ts +57 -0
  326. package/src/tests/claude-worker-parity.test.ts +2 -7
  327. package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
  328. package/src/tests/config-refs.test.ts +66 -0
  329. package/src/tests/context-key.test.ts +19 -0
  330. package/src/tests/cors-allowlist.test.ts +25 -0
  331. package/src/tests/create-page-tool.test.ts +18 -0
  332. package/src/tests/credential-check.test.ts +139 -0
  333. package/src/tests/credentials.test.ts +21 -0
  334. package/src/tests/db-runtime.test.ts +61 -0
  335. package/src/tests/db-task-read-contract.test.ts +22 -0
  336. package/src/tests/db-task-write-contract.test.ts +11 -0
  337. package/src/tests/deferred-task-wake.test.ts +78 -1
  338. package/src/tests/docs-index-footprint.test.js +3 -3
  339. package/src/tests/dsh-adapter.test.ts +1 -1
  340. package/src/tests/enabled-capabilities.test.ts +20 -0
  341. package/src/tests/entrypoint-api-readiness.test.ts +14 -8
  342. package/src/tests/entrypoint-config-env-export.test.ts +5 -2
  343. package/src/tests/entrypoint-export-to-env.test.ts +78 -0
  344. package/src/tests/env-flag.test.ts +1 -0
  345. package/src/tests/explicit-model-validation.test.ts +105 -1
  346. package/src/tests/extensions-catalog.test.ts +1 -0
  347. package/src/tests/extensions-example-comms-adherence-gate.test.ts +413 -0
  348. package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
  349. package/src/tests/extensions-loader.test.ts +15 -0
  350. package/src/tests/extensions-post-bridge.test.ts +51 -0
  351. package/src/tests/fetch-resolved-env.test.ts +128 -0
  352. package/src/tests/fixtures/chat-sdk/telegram-private-text.json +10 -0
  353. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
  354. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
  355. package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
  356. package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
  357. package/src/tests/github-handlers.test.ts +35 -0
  358. package/src/tests/harness-provider-resolution.test.ts +12 -0
  359. package/src/tests/heartbeat-checklist.test.ts +3 -2
  360. package/src/tests/heartbeat-jev-gate-credentials.test.ts +168 -0
  361. package/src/tests/heartbeat-jev-gate.test.ts +385 -0
  362. package/src/tests/hook-runtime-close.test.ts +0 -2
  363. package/src/tests/http-api-integration.test.ts +0 -25
  364. package/src/tests/migration-046-budgets.test.ts +17 -16
  365. package/src/tests/migration-217-chat-sdk-state.test.ts +113 -0
  366. package/src/tests/model-profile-backcompat.test.ts +327 -0
  367. package/src/tests/model-profile-providers.test.ts +302 -0
  368. package/src/tests/model-profile-runtime-secrets.test.ts +223 -0
  369. package/src/tests/model-profiles-api.test.ts +614 -0
  370. package/src/tests/model-tier-resolution.test.ts +93 -0
  371. package/src/tests/models-catalog.test.ts +42 -1
  372. package/src/tests/openai-compatible-providers.test.ts +134 -0
  373. package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
  374. package/src/tests/opencode-adapter.test.ts +216 -2
  375. package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
  376. package/src/tests/opencode-shell-env.test.ts +145 -0
  377. package/src/tests/openrouter-base-url.test.ts +101 -151
  378. package/src/tests/page-proxy.test.ts +1 -1
  379. package/src/tests/pages-browser-sdk.test.ts +76 -0
  380. package/src/tests/pages-feedback-keys.test.ts +121 -0
  381. package/src/tests/pages-feedback.test.ts +4 -1
  382. package/src/tests/paused-tasks-requested-by.test.ts +102 -0
  383. package/src/tests/pi-context-compaction.test.ts +193 -0
  384. package/src/tests/pi-custom-provider-fake-server.test.ts +442 -0
  385. package/src/tests/pi-mono-adapter.test.ts +385 -5
  386. package/src/tests/pi-shell-env.test.ts +170 -0
  387. package/src/tests/profile-claim.test.ts +269 -0
  388. package/src/tests/prompt-template-remaining.test.ts +35 -0
  389. package/src/tests/quickjs-compat.test.ts +213 -0
  390. package/src/tests/rbac-engine.test.ts +32 -3
  391. package/src/tests/runner-exit-after-tasks.test.ts +0 -4
  392. package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
  393. package/src/tests/script-connections.test.ts +6 -0
  394. package/src/tests/script-executor-conformance.test.ts +252 -1
  395. package/src/tests/script-executor-quickjs.test.ts +96 -0
  396. package/src/tests/script-runs-http.test.ts +89 -0
  397. package/src/tests/scripts-http.test.ts +217 -1
  398. package/src/tests/scripts-only-gating.test.ts +2 -3
  399. package/src/tests/scripts-runtime.test.ts +58 -40
  400. package/src/tests/secret-scrubber.test.ts +96 -0
  401. package/src/tests/seed-model-profiles.test.ts +174 -0
  402. package/src/tests/seed-scripts.test.ts +2 -2
  403. package/src/tests/seed-skills-bundled-files.test.ts +45 -53
  404. package/src/tests/seed-skills-retire.test.ts +182 -0
  405. package/src/tests/send-task-requester-gate.test.ts +58 -0
  406. package/src/tests/session-cost-recompute-unit.test.ts +46 -0
  407. package/src/tests/skill-get-name-resolution.test.ts +137 -0
  408. package/src/tests/skill-invocations.test.ts +4 -2
  409. package/src/tests/slack-blocks.test.ts +36 -0
  410. package/src/tests/slack-inline-output.test.ts +14 -0
  411. package/src/tests/slack-reaction-config.test.ts +20 -0
  412. package/src/tests/slack-render-v2.test.ts +37 -0
  413. package/src/tests/slack-thread-buffer.test.ts +98 -1
  414. package/src/tests/sonnet-5-5-registry.test.ts +9 -1
  415. package/src/tests/swarm-config-export-to-env.test.ts +267 -0
  416. package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
  417. package/src/tests/swarm-diff.test.ts +1 -1
  418. package/src/tests/task-model-effort-rerun.test.ts +164 -0
  419. package/src/tests/task-session-prompts.test.ts +132 -0
  420. package/src/tests/task-tool-manifest.test.ts +14 -0
  421. package/src/tests/task-tools-ctx.test.ts +2 -0
  422. package/src/tests/tool-annotations.test.ts +6 -6
  423. package/src/tests/ui-logs-parser.test.ts +43 -0
  424. package/src/tests/used-by-route.test.ts +6 -0
  425. package/src/tests/vercel-ai-gateway.test.ts +149 -0
  426. package/src/tests/workflow-llm.test.ts +61 -0
  427. package/src/tests/workflow-swarm-script.test.ts +38 -0
  428. package/src/tests/workflow-wait-filter.test.ts +5 -3
  429. package/src/tools/chat-access.ts +41 -0
  430. package/src/tools/chat-open-dm.ts +59 -0
  431. package/src/tools/chat-post.ts +74 -0
  432. package/src/tools/chat-read-thread.ts +100 -0
  433. package/src/tools/chat-reply.ts +75 -0
  434. package/src/tools/create-page.ts +3 -13
  435. package/src/tools/model-catalog/index.ts +2 -1
  436. package/src/tools/model-profiles/list-model-profiles.ts +54 -0
  437. package/src/tools/register-chat-channel.ts +139 -0
  438. package/src/tools/request-human-input.ts +11 -3
  439. package/src/tools/script-apis.ts +5 -1
  440. package/src/tools/script-upsert.ts +4 -1
  441. package/src/tools/send-task.ts +48 -1
  442. package/src/tools/skills/skill-get.ts +17 -9
  443. package/src/tools/swarm-config/get-config.ts +2 -1
  444. package/src/tools/swarm-config/list-config.ts +2 -1
  445. package/src/tools/swarm-config/set-config.ts +16 -3
  446. package/src/tools/system-one-decide.ts +104 -0
  447. package/src/tools/task-action.ts +22 -1
  448. package/src/tools/tool-config.ts +14 -6
  449. package/src/types.ts +48 -3
  450. package/src/utils/config-env-export.ts +74 -0
  451. package/src/utils/credentials.test.ts +92 -0
  452. package/src/utils/credentials.ts +52 -4
  453. package/src/utils/harness-provider.ts +15 -6
  454. package/src/utils/runtime-model-catalog.ts +11 -1
  455. package/src/utils/secret-scrubber.ts +86 -10
  456. package/src/utils/task-tool-manifest.ts +19 -2
  457. package/src/utils/vcs-repo-match.ts +29 -0
  458. package/src/workflows/executors/raw-llm.ts +8 -3
  459. package/src/workflows/executors/swarm-script.ts +1 -0
  460. package/src/workflows/executors/system-one-decision.ts +21 -11
  461. package/src/workflows/executors/workflow-llm.ts +22 -0
  462. package/src/workflows/index.ts +21 -12
  463. package/templates/extensions/README.md +1 -0
  464. package/templates/extensions/comms-adherence-gate/README.md +88 -0
  465. package/templates/extensions/comms-adherence-gate/hooks.ts +489 -0
  466. package/templates/extensions/comms-adherence-gate/manifest.json +8 -0
  467. package/templates/skills/agent-browser/SKILL.md +1 -1
  468. package/templates/skills/agent-browser/content.md +1 -1
  469. package/templates/skills/apps/SKILL.md +8 -1
  470. package/templates/skills/apps/content.md +8 -1
  471. package/templates/skills/chat-sdk/config.json +14 -0
  472. package/templates/skills/chat-sdk/content.md +84 -0
  473. package/templates/skills/composio-gmail/content.md +7 -0
  474. package/templates/skills/composio-google-docs/content.md +1 -1
  475. package/templates/skills/email-domain-health/config.json +14 -0
  476. package/templates/skills/email-domain-health/content.md +131 -0
  477. package/templates/skills/kv-storage/content.md +2 -2
  478. package/templates/skills/pages/content.md +8 -10
  479. package/templates/skills/swarm-extensions/content.md +2 -0
  480. package/templates/skills/swarm-scripts/SKILL.md +4 -2
  481. package/templates/skills/swarm-scripts/config.json +1 -1
  482. package/templates/skills/swarm-scripts/content.md +4 -2
  483. package/templates/skills/workflow-iterate/content.md +38 -0
  484. package/dist/artifact-eczsknc3.js +0 -3843
  485. package/dist/cli-42qhyvwx.js +0 -33
  486. package/dist/cli-bd957dgb.js +0 -153
  487. package/dist/cli-q51yprfq.js +0 -1104
  488. package/dist/cli-t1ze64h3.js +0 -811
  489. package/dist/cli-tcc4wd5d.js +0 -56471
  490. package/dist/index-9ch1n761.js +0 -1102
  491. package/src/artifact-sdk/index.ts +0 -2
  492. package/src/artifact-sdk/localtunnel.d.ts +0 -20
  493. package/src/artifact-sdk/port.ts +0 -12
  494. package/src/artifact-sdk/server.ts +0 -183
  495. package/src/artifact-sdk/tunnel.ts +0 -19
  496. package/src/commands/artifact.ts +0 -249
  497. package/src/http/ecosystem.ts +0 -77
  498. package/src/tests/artifact-commands.test.ts +0 -92
  499. package/src/tests/artifact-sdk.test.ts +0 -793
  500. package/src/tests/register-service-security.test.ts +0 -194
  501. package/src/tools/list-services.ts +0 -107
  502. package/src/tools/register-service.ts +0 -177
  503. package/src/tools/unregister-service.ts +0 -73
  504. package/src/tools/update-service-status.ts +0 -96
  505. package/templates/skills/artifacts/config.json +0 -14
  506. package/templates/skills/artifacts/content.md +0 -344
  507. package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
  508. package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
  509. package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
  510. package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
  511. /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
@@ -1,793 +0,0 @@
1
- import { afterAll, beforeAll, describe, expect, mock, test } from "bun:test";
2
- import { mkdirSync, rmSync, writeFileSync } from "node:fs";
3
- import { BROWSER_SDK_JS } from "../artifact-sdk/browser-sdk";
4
- import { getAvailablePort } from "../artifact-sdk/port";
5
- import {
6
- createArtifactServer,
7
- createBunHonoFetchHandler,
8
- createBunResponse,
9
- } from "../artifact-sdk/server";
10
- import { getBasePrompt } from "../prompts/base-prompt";
11
-
12
- function restoreEnvValue(key: string, value: string | undefined): void {
13
- if (value === undefined) delete process.env[key];
14
- else process.env[key] = value;
15
- }
16
-
17
- // ─── Port allocation tests ──────────────────────────────────────────────
18
-
19
- describe("getAvailablePort", () => {
20
- test("returns a valid port number", async () => {
21
- const port = await getAvailablePort();
22
- expect(port).toBeGreaterThan(0);
23
- expect(port).toBeLessThan(65536);
24
- });
25
-
26
- test("returns different ports on consecutive calls", async () => {
27
- const port1 = await getAvailablePort();
28
- const port2 = await getAvailablePort();
29
- expect(port1).not.toBe(port2);
30
- });
31
-
32
- test("returns a port that is actually available", async () => {
33
- const port = await getAvailablePort();
34
- // Try to start a Bun server on the port — should succeed
35
- const server = Bun.serve({
36
- port,
37
- fetch: () => createBunResponse("ok"),
38
- });
39
- expect(server.port).toBe(port);
40
- server.stop();
41
- });
42
-
43
- test("returns ports in ephemeral range", async () => {
44
- const ports: number[] = [];
45
- for (let i = 0; i < 5; i++) {
46
- ports.push(await getAvailablePort());
47
- }
48
- // All ports should be in the ephemeral range (typically > 1024)
49
- for (const p of ports) {
50
- expect(p).toBeGreaterThan(1024);
51
- }
52
- });
53
-
54
- test("all returned ports are unique", async () => {
55
- const ports = new Set<number>();
56
- for (let i = 0; i < 10; i++) {
57
- ports.add(await getAvailablePort());
58
- }
59
- // Allow minor collisions — OS can recycle ports between bind/release cycles
60
- expect(ports.size).toBeGreaterThanOrEqual(8);
61
- });
62
- });
63
-
64
- // ─── Browser SDK tests ─────────────────────────────────────────────────
65
-
66
- describe("BROWSER_SDK_JS", () => {
67
- test("is a non-empty string", () => {
68
- expect(typeof BROWSER_SDK_JS).toBe("string");
69
- expect(BROWSER_SDK_JS.length).toBeGreaterThan(100);
70
- });
71
-
72
- test("contains SwarmSDK class", () => {
73
- expect(BROWSER_SDK_JS).toContain("class SwarmSDK");
74
- });
75
-
76
- test("is syntactically valid JavaScript", () => {
77
- expect(() => new Function(BROWSER_SDK_JS)).not.toThrow();
78
- });
79
-
80
- test("exposes the eight canonical domains", () => {
81
- const expectedDomains = [
82
- "this.tasks",
83
- "this.agents",
84
- "this.events",
85
- "this.memory",
86
- "this.repos",
87
- "this.schedules",
88
- "this.approvalRequests",
89
- "this.assets",
90
- ];
91
- for (const domain of expectedDomains) {
92
- expect(BROWSER_SDK_JS).toContain(domain);
93
- }
94
- });
95
-
96
- test("removed domains are NOT exposed (messages, services, slack)", () => {
97
- const removed = ["this.messages", "this.services", "this.slack", "postMessage", "readMessages"];
98
- for (const r of removed) {
99
- expect(BROWSER_SDK_JS).not.toContain(r);
100
- }
101
- });
102
-
103
- test("assigns SwarmSDK class + swarmSdk singleton to window", () => {
104
- expect(BROWSER_SDK_JS).toContain("window.SwarmSDK = SwarmSDK");
105
- expect(BROWSER_SDK_JS).toContain("window.swarmSdk = new SwarmSDK()");
106
- });
107
-
108
- test("routes calls through the /@swarm/api/* proxy", () => {
109
- expect(BROWSER_SDK_JS).toContain("const base = '/@swarm/api'");
110
- // Sentinel endpoints — one per domain.
111
- expect(BROWSER_SDK_JS).toContain("'/tasks'");
112
- expect(BROWSER_SDK_JS).toContain("'/agents'");
113
- expect(BROWSER_SDK_JS).toContain("'/events'");
114
- expect(BROWSER_SDK_JS).toContain("'/memory/search'");
115
- expect(BROWSER_SDK_JS).toContain("'/repos'");
116
- expect(BROWSER_SDK_JS).toContain("'/schedules'");
117
- expect(BROWSER_SDK_JS).toContain("'/approval-requests'");
118
- expect(BROWSER_SDK_JS).toContain("'/assets'");
119
- expect(BROWSER_SDK_JS).toContain("'/assets/key-audit'");
120
- expect(BROWSER_SDK_JS).toContain("'/assets/mappings'");
121
- });
122
-
123
- test("does not fetch on SDK load or construction", () => {
124
- const fetchMock = mock(() => Promise.resolve(Response.json({})));
125
- const window = {};
126
- const loadSdk = new Function("window", "fetch", `${BROWSER_SDK_JS}\nreturn window.SwarmSDK;`);
127
-
128
- const SwarmSDK = loadSdk(window, fetchMock);
129
- expect(window).toHaveProperty("swarmSdk");
130
- expect(fetchMock).not.toHaveBeenCalled();
131
-
132
- new SwarmSDK();
133
- new SwarmSDK();
134
- expect(fetchMock).not.toHaveBeenCalled();
135
- });
136
- });
137
-
138
- // ─── createArtifactServer factory tests ──────────────────────────────────
139
-
140
- describe("createArtifactServer", () => {
141
- const originalEnv = { ...process.env };
142
-
143
- beforeAll(() => {
144
- process.env.AGENT_ID = "test-agent-id";
145
- process.env.API_KEY = "example-test-api-key";
146
- process.env.MCP_BASE_URL = "http://localhost:19999"; // Intentionally unreachable
147
- });
148
-
149
- afterAll(() => {
150
- restoreEnvValue("AGENT_ID", originalEnv.AGENT_ID);
151
- restoreEnvValue("API_KEY", originalEnv.API_KEY);
152
- restoreEnvValue("MCP_BASE_URL", originalEnv.MCP_BASE_URL);
153
- });
154
-
155
- describe("factory return shape", () => {
156
- test("returns object with expected properties", () => {
157
- const server = createArtifactServer({ name: "test" });
158
- expect(server).toHaveProperty("start");
159
- expect(server).toHaveProperty("stop");
160
- expect(server).toHaveProperty("url");
161
- expect(server).toHaveProperty("port");
162
- expect(server).toHaveProperty("tunnel");
163
- expect(typeof server.start).toBe("function");
164
- expect(typeof server.stop).toBe("function");
165
- });
166
-
167
- test("initial url is empty string", () => {
168
- const server = createArtifactServer({ name: "test" });
169
- expect(server.url).toBe("");
170
- });
171
-
172
- test("initial port is 0", () => {
173
- const server = createArtifactServer({ name: "test" });
174
- expect(server.port).toBe(0);
175
- });
176
-
177
- test("initial tunnel is null", () => {
178
- const server = createArtifactServer({ name: "test" });
179
- expect(server.tunnel).toBeNull();
180
- });
181
- });
182
-
183
- describe("Hono app routes", () => {
184
- test("server serves static content via Hono", async () => {
185
- const { Hono } = await import("hono");
186
- const port = await getAvailablePort();
187
-
188
- const app = new Hono();
189
- app.get("/", (c) => c.text("Hello from test artifact"));
190
-
191
- // Create a minimal Hono server without tunnel
192
- const honoApp = new Hono();
193
- honoApp.get("/@swarm/sdk.js", (c) => {
194
- c.header("Content-Type", "application/javascript");
195
- return c.body(BROWSER_SDK_JS);
196
- });
197
- honoApp.get("/@swarm/config", (c) => {
198
- return c.json({ agentId: "test-agent-id", artifactName: "test" });
199
- });
200
- honoApp.route("/", app);
201
-
202
- const server = Bun.serve({ port, fetch: createBunHonoFetchHandler(honoApp) });
203
-
204
- try {
205
- // Test content serving
206
- const res = await fetch(`http://localhost:${port}/`);
207
- expect(res.status).toBe(200);
208
- expect(await res.text()).toBe("Hello from test artifact");
209
-
210
- // Test SDK endpoint
211
- const sdkRes = await fetch(`http://localhost:${port}/@swarm/sdk.js`);
212
- expect(sdkRes.status).toBe(200);
213
- expect(sdkRes.headers.get("content-type")).toContain("javascript");
214
- const sdkBody = await sdkRes.text();
215
- expect(sdkBody).toContain("class SwarmSDK");
216
-
217
- // Test config endpoint
218
- const configRes = await fetch(`http://localhost:${port}/@swarm/config`);
219
- expect(configRes.status).toBe(200);
220
- const config = await configRes.json();
221
- expect(config).toEqual({ agentId: "test-agent-id", artifactName: "test" });
222
- } finally {
223
- server.stop();
224
- }
225
- });
226
-
227
- test("server serves static files from directory", async () => {
228
- const { Hono } = await import("hono");
229
- const { serveStatic } = await import("hono/bun");
230
- const port = await getAvailablePort();
231
- const testDir = "/tmp/test-artifact-static";
232
-
233
- // Create test directory with content
234
- mkdirSync(testDir, { recursive: true });
235
- writeFileSync(`${testDir}/index.html`, "<h1>Test Static</h1>");
236
- writeFileSync(`${testDir}/data.json`, '{"test": true}');
237
-
238
- const app = new Hono();
239
- app.use("/*", serveStatic({ root: testDir }));
240
-
241
- const server = Bun.serve({ port, fetch: createBunHonoFetchHandler(app) });
242
-
243
- try {
244
- const res = await fetch(`http://localhost:${port}/index.html`);
245
- expect(res.status).toBe(200);
246
- expect(await res.text()).toBe("<h1>Test Static</h1>");
247
-
248
- const jsonRes = await fetch(`http://localhost:${port}/data.json`);
249
- expect(jsonRes.status).toBe(200);
250
- const data = await jsonRes.json();
251
- expect(data).toEqual({ test: true });
252
- } finally {
253
- server.stop();
254
- rmSync(testDir, { recursive: true, force: true });
255
- }
256
- });
257
-
258
- test("API proxy returns 502 when MCP server is unreachable", async () => {
259
- const { Hono } = await import("hono");
260
- const port = await getAvailablePort();
261
-
262
- const app = new Hono();
263
- app.all("/@swarm/api/*", async (c) => {
264
- const path = c.req.path.replace("/@swarm/api", "/api");
265
- const targetUrl = `http://localhost:19999${path}`; // Unreachable
266
- try {
267
- const res = await fetch(targetUrl, { method: c.req.method });
268
- return new Response(res.body, { status: res.status });
269
- } catch (e) {
270
- return c.json({ error: "Proxy error", message: String(e) }, 502);
271
- }
272
- });
273
-
274
- const server = Bun.serve({ port, fetch: createBunHonoFetchHandler(app) });
275
-
276
- try {
277
- const res = await fetch(`http://localhost:${port}/@swarm/api/agents`);
278
- expect(res.status).toBe(502);
279
- const body = await res.json();
280
- expect(body.error).toBe("Proxy error");
281
- } finally {
282
- server.stop();
283
- }
284
- });
285
-
286
- test("CORS preflight returns 204 with correct headers", async () => {
287
- const { Hono } = await import("hono");
288
- const port = await getAvailablePort();
289
-
290
- const app = new Hono();
291
- app.options("/@swarm/api/*", (_c) => {
292
- return new Response(null, {
293
- status: 204,
294
- headers: {
295
- "Access-Control-Allow-Origin": "*",
296
- "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
297
- "Access-Control-Allow-Headers": "Content-Type",
298
- },
299
- });
300
- });
301
-
302
- const server = Bun.serve({ port, fetch: createBunHonoFetchHandler(app) });
303
-
304
- try {
305
- const res = await fetch(`http://localhost:${port}/@swarm/api/tasks`, {
306
- method: "OPTIONS",
307
- });
308
- expect(res.status).toBe(204);
309
- expect(res.headers.get("access-control-allow-origin")).toBe("*");
310
- expect(res.headers.get("access-control-allow-methods")).toContain("GET");
311
- expect(res.headers.get("access-control-allow-methods")).toContain("POST");
312
- expect(res.headers.get("access-control-allow-methods")).toContain("DELETE");
313
- expect(res.headers.get("access-control-allow-headers")).toContain("Content-Type");
314
- } finally {
315
- server.stop();
316
- }
317
- });
318
-
319
- test("API proxy forwards auth headers to MCP server", async () => {
320
- const { Hono } = await import("hono");
321
- const proxyPort = await getAvailablePort();
322
- const mockMcpPort = await getAvailablePort();
323
-
324
- // Mock MCP server that captures headers
325
- let capturedHeaders: Record<string, string> = {};
326
- const mockMcp = Bun.serve({
327
- port: mockMcpPort,
328
- fetch: (req) => {
329
- capturedHeaders = {};
330
- for (const [key, value] of req.headers.entries()) {
331
- capturedHeaders[key.toLowerCase()] = value;
332
- }
333
- return createBunResponse(JSON.stringify({ success: true }), {
334
- headers: { "Content-Type": "application/json" },
335
- });
336
- },
337
- });
338
-
339
- // Build proxy app matching server.ts pattern
340
- const app = new Hono();
341
- app.all("/@swarm/api/*", async (c) => {
342
- const path = c.req.path.replace("/@swarm/api", "/api");
343
- const targetUrl = `http://localhost:${mockMcpPort}${path}`;
344
- const headers: Record<string, string> = {
345
- Authorization: "Bearer example-test-api-key",
346
- "X-Agent-ID": "test-agent-id",
347
- };
348
- if (c.req.method !== "GET") {
349
- headers["Content-Type"] = "application/json";
350
- }
351
- try {
352
- const res = await fetch(targetUrl, { method: c.req.method, headers });
353
- return new Response(res.body, {
354
- status: res.status,
355
- headers: {
356
- "Access-Control-Allow-Origin": "*",
357
- "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
358
- "Access-Control-Allow-Headers": "Content-Type",
359
- },
360
- });
361
- } catch (e) {
362
- return c.json({ error: "Proxy error", message: String(e) }, 502);
363
- }
364
- });
365
-
366
- const proxy = Bun.serve({ port: proxyPort, fetch: createBunHonoFetchHandler(app) });
367
-
368
- try {
369
- // Test GET request headers
370
- await fetch(`http://localhost:${proxyPort}/@swarm/api/agents`);
371
- expect(capturedHeaders.authorization).toBe("Bearer example-test-api-key");
372
- expect(capturedHeaders["x-agent-id"]).toBe("test-agent-id");
373
-
374
- // GET should NOT have Content-Type
375
- expect(capturedHeaders["content-type"]).toBeUndefined();
376
-
377
- // Test POST request headers
378
- await fetch(`http://localhost:${proxyPort}/@swarm/api/tasks`, {
379
- method: "POST",
380
- body: JSON.stringify({ task: "test" }),
381
- });
382
- expect(capturedHeaders.authorization).toBe("Bearer example-test-api-key");
383
- expect(capturedHeaders["x-agent-id"]).toBe("test-agent-id");
384
- expect(capturedHeaders["content-type"]).toBe("application/json");
385
- } finally {
386
- proxy.stop();
387
- mockMcp.stop();
388
- }
389
- });
390
-
391
- test("API proxy response includes CORS headers", async () => {
392
- const { Hono } = await import("hono");
393
- const proxyPort = await getAvailablePort();
394
- const mockMcpPort = await getAvailablePort();
395
-
396
- const mockMcp = Bun.serve({
397
- port: mockMcpPort,
398
- fetch: () =>
399
- createBunResponse(JSON.stringify({ ok: true }), {
400
- headers: { "Content-Type": "application/json" },
401
- }),
402
- });
403
-
404
- const app = new Hono();
405
- app.all("/@swarm/api/*", async (c) => {
406
- const path = c.req.path.replace("/@swarm/api", "/api");
407
- const targetUrl = `http://localhost:${mockMcpPort}${path}`;
408
- try {
409
- const res = await fetch(targetUrl, { method: c.req.method });
410
- return new Response(res.body, {
411
- status: res.status,
412
- headers: {
413
- "Access-Control-Allow-Origin": "*",
414
- "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
415
- "Access-Control-Allow-Headers": "Content-Type",
416
- },
417
- });
418
- } catch (_e) {
419
- return c.json({ error: "Proxy error" }, 502);
420
- }
421
- });
422
-
423
- const proxy = Bun.serve({ port: proxyPort, fetch: createBunHonoFetchHandler(app) });
424
-
425
- try {
426
- const res = await fetch(`http://localhost:${proxyPort}/@swarm/api/agents`);
427
- expect(res.status).toBe(200);
428
- expect(res.headers.get("access-control-allow-origin")).toBe("*");
429
- } finally {
430
- proxy.stop();
431
- mockMcp.stop();
432
- }
433
- });
434
-
435
- test("API proxy correctly rewrites path from /@swarm/api to /api", async () => {
436
- const { Hono } = await import("hono");
437
- const proxyPort = await getAvailablePort();
438
- const mockMcpPort = await getAvailablePort();
439
-
440
- let capturedPath = "";
441
- const mockMcp = Bun.serve({
442
- port: mockMcpPort,
443
- fetch: (req) => {
444
- capturedPath = new URL(req.url).pathname;
445
- return createBunResponse(JSON.stringify({ ok: true }));
446
- },
447
- });
448
-
449
- const app = new Hono();
450
- app.all("/@swarm/api/*", async (c) => {
451
- const path = c.req.path.replace("/@swarm/api", "/api");
452
- const targetUrl = `http://localhost:${mockMcpPort}${path}`;
453
- try {
454
- const res = await fetch(targetUrl, { method: c.req.method });
455
- return new Response(res.body, { status: res.status });
456
- } catch (_e) {
457
- return c.json({ error: "Proxy error" }, 502);
458
- }
459
- });
460
-
461
- const proxy = Bun.serve({ port: proxyPort, fetch: createBunHonoFetchHandler(app) });
462
-
463
- try {
464
- await fetch(`http://localhost:${proxyPort}/@swarm/api/tasks/123/progress`);
465
- expect(capturedPath).toBe("/api/tasks/123/progress");
466
-
467
- await fetch(`http://localhost:${proxyPort}/@swarm/api/agents`);
468
- expect(capturedPath).toBe("/api/agents");
469
-
470
- await fetch(`http://localhost:${proxyPort}/@swarm/api/services`);
471
- expect(capturedPath).toBe("/api/services");
472
- } finally {
473
- proxy.stop();
474
- mockMcp.stop();
475
- }
476
- });
477
- });
478
-
479
- describe("stop()", () => {
480
- test("stop() is safe to call when server was never started", async () => {
481
- const server = createArtifactServer({ name: "never-started" });
482
- // Should not throw
483
- await server.stop();
484
- expect(server.port).toBe(0);
485
- expect(server.tunnel).toBeNull();
486
- });
487
- });
488
- });
489
-
490
- // ─── tunnel.ts tests ──────────────────────────────────────────────────────
491
-
492
- describe("createTunnel", () => {
493
- test("module exports createTunnel function", async () => {
494
- const tunnelMod = await import("../artifact-sdk/tunnel");
495
- expect(typeof tunnelMod.createTunnel).toBe("function");
496
- });
497
- });
498
-
499
- // ─── index.ts re-export tests ──────────────────────────────────────────
500
-
501
- describe("artifact-sdk index exports", () => {
502
- test("exports createArtifactServer", async () => {
503
- const sdk = await import("../artifact-sdk/index");
504
- expect(typeof sdk.createArtifactServer).toBe("function");
505
- });
506
-
507
- test("createArtifactServer from index is same as from server", async () => {
508
- const sdk = await import("../artifact-sdk/index");
509
- const { createArtifactServer: direct } = await import("../artifact-sdk/server");
510
- expect(sdk.createArtifactServer).toBe(direct);
511
- });
512
- });
513
-
514
- // ─── CLI command tests ─────────────────────────────────────────────────
515
-
516
- describe("artifact CLI command", () => {
517
- test("runArtifact module exports correctly", async () => {
518
- const mod = await import("../commands/artifact");
519
- expect(typeof mod.runArtifact).toBe("function");
520
- });
521
-
522
- test("runArtifact with unknown subcommand calls printHelp (no crash)", async () => {
523
- const { runArtifact } = await import("../commands/artifact");
524
- // "help" and unknown subcommands should just print help and return
525
- const consoleSpy = mock(() => {});
526
- const origLog = console.log;
527
- console.log = consoleSpy;
528
- try {
529
- await runArtifact("help", { additionalArgs: [] });
530
- expect(consoleSpy).toHaveBeenCalled();
531
- const output = consoleSpy.mock.calls.map((c) => c[0]).join("\n");
532
- expect(output).toContain("Usage: agent-swarm artifact");
533
- expect(output).toContain("serve");
534
- expect(output).toContain("list");
535
- expect(output).toContain("stop");
536
- } finally {
537
- console.log = origLog;
538
- }
539
- });
540
-
541
- test("runArtifact with no subcommand defaults to help", async () => {
542
- const { runArtifact } = await import("../commands/artifact");
543
- const consoleSpy = mock(() => {});
544
- const origLog = console.log;
545
- console.log = consoleSpy;
546
- try {
547
- // Default case when subcommand is not recognized
548
- await runArtifact("unknown-command", { additionalArgs: [] });
549
- expect(consoleSpy).toHaveBeenCalled();
550
- const output = consoleSpy.mock.calls.map((c) => c[0]).join("\n");
551
- expect(output).toContain("Usage: agent-swarm artifact");
552
- } finally {
553
- console.log = origLog;
554
- }
555
- });
556
-
557
- describe("artifact list", () => {
558
- test("lists artifacts from mock MCP server", async () => {
559
- const mockPort = await getAvailablePort();
560
- const mockServer = Bun.serve({
561
- port: mockPort,
562
- fetch: (req) => {
563
- const url = new URL(req.url);
564
- if (url.pathname === "/api/services") {
565
- return createBunResponse(
566
- JSON.stringify({
567
- services: [
568
- {
569
- id: "svc-1",
570
- name: "artifact-dashboard",
571
- agentId: "agent-123",
572
- status: "healthy",
573
- metadata: {
574
- type: "artifact",
575
- artifactName: "dashboard",
576
- port: 3001,
577
- publicUrl: "https://test.lt.example.com",
578
- },
579
- },
580
- {
581
- id: "svc-2",
582
- name: "some-other-service",
583
- agentId: "agent-456",
584
- status: "healthy",
585
- metadata: { type: "web" },
586
- },
587
- ],
588
- }),
589
- );
590
- }
591
- return createBunResponse("Not found", { status: 404 });
592
- },
593
- });
594
-
595
- const origEnv = { ...process.env };
596
- process.env.MCP_BASE_URL = `http://localhost:${mockPort}`;
597
- process.env.API_KEY = "example-test-key";
598
- process.env.AGENT_ID = "test-agent";
599
-
600
- const consoleSpy = mock(() => {});
601
- const origLog = console.log;
602
- console.log = consoleSpy;
603
-
604
- try {
605
- const { runArtifact } = await import("../commands/artifact");
606
- await runArtifact("list", { additionalArgs: [] });
607
-
608
- const output = consoleSpy.mock.calls.map((c) => c[0]).join("\n");
609
- // Should show the artifact but not the non-artifact service
610
- expect(output).toContain("dashboard");
611
- expect(output).toContain("https://test.lt.example.com");
612
- } finally {
613
- console.log = origLog;
614
- restoreEnvValue("MCP_BASE_URL", origEnv.MCP_BASE_URL);
615
- restoreEnvValue("API_KEY", origEnv.API_KEY);
616
- restoreEnvValue("AGENT_ID", origEnv.AGENT_ID);
617
- mockServer.stop();
618
- }
619
- });
620
-
621
- test("shows 'No active artifacts' when none exist", async () => {
622
- const mockPort = await getAvailablePort();
623
- const mockServer = Bun.serve({
624
- port: mockPort,
625
- fetch: () => createBunResponse(JSON.stringify({ services: [] })),
626
- });
627
-
628
- const origEnv = { ...process.env };
629
- process.env.MCP_BASE_URL = `http://localhost:${mockPort}`;
630
- process.env.API_KEY = "example-test-key";
631
- process.env.AGENT_ID = "test-agent";
632
-
633
- const consoleSpy = mock(() => {});
634
- const origLog = console.log;
635
- console.log = consoleSpy;
636
-
637
- try {
638
- const { runArtifact } = await import("../commands/artifact");
639
- await runArtifact("list", { additionalArgs: [] });
640
-
641
- const output = consoleSpy.mock.calls.map((c) => c[0]).join("\n");
642
- expect(output).toContain("No active artifacts");
643
- } finally {
644
- console.log = origLog;
645
- restoreEnvValue("MCP_BASE_URL", origEnv.MCP_BASE_URL);
646
- restoreEnvValue("API_KEY", origEnv.API_KEY);
647
- restoreEnvValue("AGENT_ID", origEnv.AGENT_ID);
648
- mockServer.stop();
649
- }
650
- });
651
-
652
- test("filters only artifact-type services from list", async () => {
653
- const mockPort = await getAvailablePort();
654
- const mockServer = Bun.serve({
655
- port: mockPort,
656
- fetch: () =>
657
- createBunResponse(
658
- JSON.stringify({
659
- services: [
660
- {
661
- id: "s1",
662
- name: "web-server",
663
- agentId: "a1",
664
- status: "healthy",
665
- metadata: { type: "web" },
666
- },
667
- {
668
- id: "s2",
669
- name: "api-server",
670
- agentId: "a2",
671
- status: "healthy",
672
- metadata: {},
673
- },
674
- ],
675
- }),
676
- ),
677
- });
678
-
679
- const origEnv = { ...process.env };
680
- process.env.MCP_BASE_URL = `http://localhost:${mockPort}`;
681
- process.env.API_KEY = "example-test-key";
682
- process.env.AGENT_ID = "test-agent";
683
-
684
- const consoleSpy = mock(() => {});
685
- const origLog = console.log;
686
- console.log = consoleSpy;
687
-
688
- try {
689
- const { runArtifact } = await import("../commands/artifact");
690
- await runArtifact("list", { additionalArgs: [] });
691
-
692
- const output = consoleSpy.mock.calls.map((c) => c[0]).join("\n");
693
- // None have type "artifact" so should say no artifacts
694
- expect(output).toContain("No active artifacts");
695
- } finally {
696
- console.log = origLog;
697
- restoreEnvValue("MCP_BASE_URL", origEnv.MCP_BASE_URL);
698
- restoreEnvValue("API_KEY", origEnv.API_KEY);
699
- restoreEnvValue("AGENT_ID", origEnv.AGENT_ID);
700
- mockServer.stop();
701
- }
702
- });
703
- });
704
-
705
- describe("artifact stop", () => {
706
- test("stop sends delete request to service registry", async () => {
707
- const mockPort = await getAvailablePort();
708
- let deletedServiceId = "";
709
-
710
- const mockServer = Bun.serve({
711
- port: mockPort,
712
- fetch: (req) => {
713
- const url = new URL(req.url);
714
- if (req.method === "GET" && url.pathname === "/api/services") {
715
- return createBunResponse(
716
- JSON.stringify({
717
- services: [
718
- {
719
- id: "svc-to-delete",
720
- name: "artifact-my-report",
721
- metadata: { type: "artifact", artifactName: "my-report" },
722
- },
723
- ],
724
- }),
725
- );
726
- }
727
- if (req.method === "DELETE" && url.pathname.startsWith("/api/services/")) {
728
- deletedServiceId = url.pathname.split("/").pop() || "";
729
- return createBunResponse(JSON.stringify({ success: true }));
730
- }
731
- return createBunResponse("Not found", { status: 404 });
732
- },
733
- });
734
-
735
- const origEnv = { ...process.env };
736
- process.env.MCP_BASE_URL = `http://localhost:${mockPort}`;
737
- process.env.API_KEY = "example-test-key";
738
- process.env.AGENT_ID = "test-agent";
739
-
740
- const consoleSpy = mock(() => {});
741
- const origLog = console.log;
742
- console.log = consoleSpy;
743
-
744
- try {
745
- const { runArtifact } = await import("../commands/artifact");
746
- await runArtifact("stop", { additionalArgs: ["my-report"] });
747
-
748
- expect(deletedServiceId).toBe("svc-to-delete");
749
- const output = consoleSpy.mock.calls.map((c) => c[0]).join("\n");
750
- expect(output).toContain("my-report");
751
- expect(output).toContain("stopped");
752
- } finally {
753
- console.log = origLog;
754
- restoreEnvValue("MCP_BASE_URL", origEnv.MCP_BASE_URL);
755
- restoreEnvValue("API_KEY", origEnv.API_KEY);
756
- restoreEnvValue("AGENT_ID", origEnv.AGENT_ID);
757
- mockServer.stop();
758
- }
759
- });
760
- });
761
- });
762
-
763
- // ─── Base prompt tests ──────────────────────────────────────────────────
764
-
765
- // Prompt v2: the artifacts block left the system prompt. Outputs go through
766
- // pages, apps, and agent-fs; the `artifacts` skill is opt-in (systemDefault
767
- // false). The prompt must not point at artifacts any more.
768
- describe("base prompt artifacts mention", () => {
769
- test("does not mention the artifacts path, localtunnel, or the SDK", async () => {
770
- const prompt = await getBasePrompt({
771
- role: "worker",
772
- agentId: "test-agent-id",
773
- capabilities: ["core", "artifacts", "services"],
774
- });
775
-
776
- expect(prompt).not.toContain("/workspace/personal/artifacts/");
777
- expect(prompt).not.toContain("localtunnel");
778
- expect(prompt).not.toContain("createArtifactServer");
779
- expect(prompt).not.toContain("SwarmSDK");
780
- });
781
-
782
- test("points at pages and apps for human-facing outputs instead", async () => {
783
- const prompt = await getBasePrompt({
784
- role: "worker",
785
- agentId: "test-agent-id",
786
- capabilities: ["core", "artifacts"],
787
- });
788
-
789
- expect(prompt).toContain("## Outputs");
790
- expect(prompt).toContain("`pages` skill");
791
- expect(prompt).toContain("`apps` skill");
792
- });
793
- });