@desplega.ai/agent-swarm 1.173.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 (432) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-ccm9xrep.js → acp-adapter-sj2g0m84.js} +17 -16
  3. package/dist/{actions-sgeyv08k.js → actions-fegk44gr.js} +39 -34
  4. package/dist/{amp-adapter-gpxp3kc9.js → amp-adapter-ad8ft89x.js} +8 -7
  5. package/dist/{app-km9qnv2f.js → app-kfvgbvzy.js} +18 -14
  6. package/dist/{assistant-5r8tcvvd.js → assistant-z7zdy9ja.js} +40 -35
  7. package/dist/{boot-reembed-swwzdgd7.js → boot-reembed-5c2z0mbe.js} +10 -9
  8. package/dist/{boot-reembed-16rv9843.js → boot-reembed-j8xa181e.js} +10 -9
  9. package/dist/{boot-scrub-sweep-zkr6vkqb.js → boot-scrub-sweep-hnkn3rgt.js} +11 -10
  10. package/dist/{boot-seeds-d8sp49t2.js → boot-seeds-kwjq4d2z.js} +14 -13
  11. package/dist/{claude-adapter-yzzzh8jp.js → claude-adapter-9vmvpvgd.js} +19 -18
  12. package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-k9qae05j.js} +7 -5
  13. package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-q54zx5q2.js} +6 -4
  14. package/dist/{claude-sdk-session-4whxere4.js → claude-sdk-session-9jye6cxr.js} +11881 -11472
  15. package/dist/{cli-94b48jhk.js → cli-03gedhng.js} +16 -14
  16. package/dist/{cli-1w0vj3gw.js → cli-1e4b6bzh.js} +7 -7
  17. package/dist/{cli-d603qf86.js → cli-29jc5q7w.js} +10 -8
  18. package/dist/cli-2m1ktfzz.js +17795 -0
  19. package/dist/{cli-x119kdba.js → cli-3dj8k4vy.js} +1 -1
  20. package/dist/{cli-srqq3gc5.js → cli-3fbmmawm.js} +5 -5
  21. package/dist/{cli-gmdajfw5.js → cli-4jxm2qtz.js} +4987 -1708
  22. package/dist/{cli-tadfgd0t.js → cli-5hkm7whv.js} +33 -4
  23. package/dist/{cli-42qhyvwx.js → cli-5t4f29ez.js} +3 -3
  24. package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
  25. package/dist/cli-6cvfxs8r.js +47 -0
  26. package/dist/{cli-0kxf81jj.js → cli-6jyj59nb.js} +2 -2
  27. package/dist/{cli-w1apjecb.js → cli-6razj6t4.js} +2 -2
  28. package/dist/{cli-anzdk0z4.js → cli-74ahz61x.js} +2 -2
  29. package/dist/{cli-m89t9jdf.js → cli-7x0g4sn1.js} +15416 -16024
  30. package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
  31. package/dist/{cli-81r1wjyv.js → cli-9nfx44eh.js} +1 -1
  32. package/dist/cli-9traj3dn.js +638 -0
  33. package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
  34. package/dist/{cli-na2pxe4f.js → cli-apx87jne.js} +2 -2
  35. package/dist/{cli-rfz2ve55.js → cli-bzszjf2p.js} +2855 -862
  36. package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
  37. package/dist/{cli-hsem16hb.js → cli-cgtksawx.js} +7 -4
  38. package/dist/{cli-db3m6zdt.js → cli-d2qr7aj4.js} +1 -1
  39. package/dist/{cli-rfs4vddv.js → cli-d5f9ed5c.js} +5 -5
  40. package/dist/cli-e3g5mbkz.js +776 -0
  41. package/dist/{cli-7jykv7ef.js → cli-e6mpjhed.js} +1 -1
  42. package/dist/{cli-7a93cv8c.js → cli-ee9gtz70.js} +98 -23
  43. package/dist/{cli-3nxdmjrc.js → cli-eejsgvm4.js} +4 -4
  44. package/dist/{cli-fmhj1ehj.js → cli-ef1hg1wv.js} +470 -51
  45. package/dist/cli-f527ce74.js +781 -0
  46. package/dist/{cli-ppy4nnnh.js → cli-f7kr7svz.js} +2 -2
  47. package/dist/cli-hjwmhcg1.js +10622 -0
  48. package/dist/{cli-2bw3w47j.js → cli-hnhtk6cj.js} +1 -1
  49. package/dist/{cli-ywm1azg9.js → cli-hnmhtzvh.js} +6 -4
  50. package/dist/{cli-h7k0xtry.js → cli-hvqbtna4.js} +4 -1256
  51. package/dist/{cli-s8z6x4b4.js → cli-j0pfptdp.js} +218 -102
  52. package/dist/cli-jta2eyzc.js +619 -0
  53. package/dist/{cli-5er5gjbm.js → cli-k382tshb.js} +10 -11
  54. package/dist/{cli-v3zhnxsb.js → cli-k3dp5tpf.js} +2 -2
  55. package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
  56. package/dist/cli-kceah1eh.js +92 -0
  57. package/dist/{cli-ne7smj1b.js → cli-ke896fcf.js} +10 -10
  58. package/dist/{cli-xc7p7s3g.js → cli-kt6zqg0e.js} +6 -6
  59. package/dist/{cli-wrh08zjd.js → cli-m50t4309.js} +5 -18
  60. package/dist/cli-n2wq4j7m.js +6985 -0
  61. package/dist/{cli-bv2etw2y.js → cli-n3hzg89b.js} +46 -15
  62. package/dist/{cli-tmhsxhb8.js → cli-n5vwg842.js} +23 -6
  63. package/dist/{cli-qm1448f9.js → cli-ne236afy.js} +8 -8
  64. package/dist/{cli-d161g69q.js → cli-p1x85d2t.js} +50 -2
  65. package/dist/{cli-7pz3b7x5.js → cli-przpmdgr.js} +25 -0
  66. package/dist/{cli-0a7mm3zp.js → cli-q0ke1yww.js} +25 -21
  67. package/dist/{cli-e3pmyt39.js → cli-q50942rs.js} +1 -1
  68. package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
  69. package/dist/{cli-phcqp1b9.js → cli-r2pnvj8g.js} +2 -2
  70. package/dist/{cli-jpc4r224.js → cli-r62a35ea.js} +19 -3
  71. package/dist/{cli-cd0hv9nh.js → cli-ra0xzggj.js} +2 -2
  72. package/dist/cli-rhs9pz33.js +294 -0
  73. package/dist/{cli-r4fqfpwf.js → cli-s2sp957d.js} +50 -27
  74. package/dist/{cli-1x7da0de.js → cli-s4setq91.js} +8 -8
  75. package/dist/{cli-6thk4jz3.js → cli-se8w6wny.js} +6 -6
  76. package/dist/cli-skxvvpap.js +10140 -0
  77. package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
  78. package/dist/{cli-0p3enk35.js → cli-tqaazemc.js} +9 -1
  79. package/dist/{cli-nwrdx840.js → cli-tr4sxp68.js} +3 -3
  80. package/dist/{cli-r0byd61h.js → cli-tsde1hdr.js} +15 -15
  81. package/dist/{cli-b07hr3bt.js → cli-txqb9s38.js} +2 -2
  82. package/dist/{cli-6r2f7edk.js → cli-v1yb0rqb.js} +6 -6
  83. package/dist/{cli-saqyage0.js → cli-vatyhshy.js} +179 -27
  84. package/dist/{cli-5wpw4rab.js → cli-vdach5a9.js} +5 -5
  85. package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
  86. package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
  87. package/dist/{cli-c3rk1v0x.js → cli-wayw93nt.js} +3 -3
  88. package/dist/cli-wmgrkscj.js +23254 -0
  89. package/dist/{cli-9xf7fdtp.js → cli-z5jjpaxw.js} +29 -6
  90. package/dist/{cli-451ks6aw.js → cli-zkpks3r3.js} +1 -1
  91. package/dist/cli.js +29 -45
  92. package/dist/{codex-adapter-r3dn4fp5.js → codex-adapter-y81sssk0.js} +15 -14
  93. package/dist/{codex-login-841kv5fk.js → codex-login-f2rcfpp9.js} +3 -2
  94. package/dist/{codex-session-runner-fwt793h4.js → codex-session-runner-8vx4j6a9.js} +15 -14
  95. package/dist/{commands-z8fq9qna.js → commands-kcpvpcrr.js} +11 -10
  96. package/dist/{controller-hq5ggpcp.js → controller-ywrmt6yd.js} +5 -4
  97. package/dist/{controllers-connect-3mf2btyj.js → controllers-connect-kwpvj3rf.js} +42 -37
  98. package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-cehv1qns.js} +7 -6
  99. package/dist/{db-yyhqqrbf.js → db-k8ankj20.js} +12 -11
  100. package/dist/{db-qfpq4bt7.js → db-ww5d7jq3.js} +28 -9
  101. package/dist/{devin-adapter-xgtj680j.js → devin-adapter-x1022qb1.js} +3 -2
  102. package/dist/{dispatcher-x0x7qfcq.js → dispatcher-e8gq5m68.js} +38 -33
  103. package/dist/{docker-f503k9p0.js → docker-ff6y1190.js} +3 -2
  104. package/dist/{dsh-adapter-34etvb5m.js → dsh-adapter-3epjm3af.js} +7 -6
  105. package/dist/{e2b-66xra4az.js → e2b-8ygwhg0f.js} +4 -3
  106. package/dist/{e2b-xwhyj8cw.js → e2b-swhnpw3n.js} +4 -3
  107. package/dist/{event-bus-vjtv82gm.js → event-bus-6axnngdj.js} +3 -2
  108. package/dist/{external-channel-h1fjecwe.js → external-channel-h3359cwn.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-0d4x7gkx.js} +18 -17
  112. package/dist/{handlers-znb9n7d4.js → handlers-an1gzv21.js} +41 -36
  113. package/dist/{heartbeat-bm4qkn8d.js → heartbeat-6dakeb61.js} +43 -38
  114. package/dist/{hook-254r4mza.js → hook-6v6cv6d5.js} +11 -23
  115. package/dist/{hook-xaa3q80s.js → hook-sa5xye4y.js} +12 -11
  116. package/dist/{http-3dgrgp8y.js → http-r7f3eky0.js} +1499 -251
  117. package/dist/index-52j1aja4.js +3465 -0
  118. package/dist/{index-fx3jqq1e.js → index-7ep4gzdk.js} +38 -33
  119. package/dist/index-9gw58n4k.js +193 -0
  120. package/dist/index-9j87mcm8.js +56305 -0
  121. package/dist/index-bsmcresk.js +79424 -0
  122. package/dist/index-mh85qhec.js +475 -0
  123. package/dist/{index-g2byveez.js → index-rmpw9a8q.js} +38 -33
  124. package/dist/{index-2ybk7khy.js → index-s2wxgzr0.js} +468 -683
  125. package/dist/{index-bdsqa799.js → index-v1v6n7hg.js} +43 -38
  126. package/dist/index-we27kd31.js +12810 -0
  127. package/dist/{index-jd7sejm2.js → index-zk96aq1k.js} +10 -9
  128. package/dist/{keepalive-6ywhpja1.js → keepalive-be9vwy5h.js} +12 -11
  129. package/dist/{lead-cw45n21s.js → lead-0861cwrf.js} +61 -56
  130. package/dist/{maintenance-ss1a1ge9.js → maintenance-mzzgc8bn.js} +10 -9
  131. package/dist/{node-fkajaq96.js → node-mn1zs7an.js} +2 -1
  132. package/dist/{oauth-refresh-sweep-3c6f8vyy.js → oauth-refresh-sweep-cpdnfwdj.js} +11 -10
  133. package/dist/{onboard-8hzdhc1k.js → onboard-fh8qs4r3.js} +11 -3
  134. package/dist/{opencode-adapter-qbchbcfz.js → opencode-adapter-nm42wwj8.js} +18 -13
  135. package/dist/{otel-impl-e6mnvc4v.js → otel-impl-x6c1c9g4.js} +242 -868
  136. package/dist/{pi-mono-adapter-3c9g9snh.js → pi-mono-adapter-9n2ya240.js} +244 -106
  137. package/dist/{pricing-refresh-gedkjdw0.js → pricing-refresh-qb0rv0ap.js} +12 -11
  138. package/dist/{rbac-roles-dt4vh1yy.js → rbac-roles-1gzdwbh1.js} +11 -10
  139. package/dist/{rbac-roles-eszdg6pm.js → rbac-roles-3mraey52.js} +12 -11
  140. package/dist/{render-v2-907cy6sa.js → render-v2-agpa45zz.js} +18 -14
  141. package/dist/{resume-42stcaz0.js → resume-x0ydy9s9.js} +25 -21
  142. package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
  143. package/dist/{setup-adbc1c10.js → setup-as9ga0d6.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-y5g1y7ev.js} +41 -36
  146. package/dist/{worker-bzdra9rf.js → worker-860c3e38.js} +61 -56
  147. package/dist/{x-qfmygqqv.js → x-m477fr0h.js} +3 -2
  148. package/openapi.json +523 -344
  149. package/package.json +10 -11
  150. package/src/be/config-refs.ts +60 -0
  151. package/src/be/db/page-versions.ts +15 -0
  152. package/src/be/db/runtime.ts +35 -8
  153. package/src/be/db/skill-name-resolution.ts +36 -0
  154. package/src/be/db/tasks/read.ts +230 -0
  155. package/src/be/db/tasks/write.ts +7 -0
  156. package/src/be/db.ts +52 -7
  157. package/src/be/migrations/215_swarm_config_export_to_env.sql +34 -0
  158. package/src/be/migrations/216_task_resolved_effort.sql +5 -0
  159. package/src/be/migrations/217_chat_sdk_state.sql +104 -0
  160. package/src/be/model-catalog-store.ts +5 -1
  161. package/src/be/model-tier-resolution.ts +12 -1
  162. package/src/be/model-validation.ts +5 -2
  163. package/src/be/models-catalog.ts +26 -1
  164. package/src/be/modelsdev-cache.json +198 -63
  165. package/src/be/modelsdev-cache.ts +9 -1
  166. package/src/be/script-credential-broker.ts +39 -2
  167. package/src/be/scripts/run-saved.ts +1 -0
  168. package/src/be/scripts/typecheck.ts +10 -8
  169. package/src/be/seed/runner.ts +13 -1
  170. package/src/be/seed/state-db.ts +5 -0
  171. package/src/be/seed/types.ts +6 -0
  172. package/src/be/seed-pricing.ts +19 -2
  173. package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
  174. package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
  175. package/src/be/seed-skills/bundled-files.generated.json +0 -18
  176. package/src/be/seed-skills/index.ts +104 -3
  177. package/src/be/swarm-config-guard.ts +52 -0
  178. package/src/cli.tsx +0 -16
  179. package/src/commands/onboard/non-interactive.ts +4 -2
  180. package/src/commands/provider-credentials.ts +52 -6
  181. package/src/commands/runner.ts +190 -54
  182. package/src/e2b/env.ts +5 -0
  183. package/src/extensions/contract-types.generated.ts +1 -1
  184. package/src/extensions/contract.ts +45 -0
  185. package/src/extensions/dispatcher.ts +7 -0
  186. package/src/extensions/post-bridge.ts +40 -0
  187. package/src/github/handlers.ts +11 -4
  188. package/src/heartbeat/templates.ts +8 -5
  189. package/src/hooks/hook.ts +0 -26
  190. package/src/http/all-routes.ts +0 -1
  191. package/src/http/config.ts +36 -17
  192. package/src/http/core.ts +4 -0
  193. package/src/http/index.ts +14 -2
  194. package/src/http/integrations.ts +88 -1
  195. package/src/http/mcp.ts +15 -5
  196. package/src/http/page-proxy.ts +2 -4
  197. package/src/http/pages-public.ts +3 -3
  198. package/src/http/pages.ts +3 -13
  199. package/src/http/poll.ts +28 -68
  200. package/src/http/requested-by.ts +54 -0
  201. package/src/http/scripts.ts +1 -0
  202. package/src/http/stats.ts +1 -30
  203. package/src/http/tasks.ts +61 -5
  204. package/src/http/utils.ts +14 -0
  205. package/src/http/webhooks.ts +159 -1
  206. package/src/http/x.ts +1 -0
  207. package/src/integrations/chat-sdk/adapters.ts +129 -0
  208. package/src/integrations/chat-sdk/attachments.ts +232 -0
  209. package/src/integrations/chat-sdk/background.ts +36 -0
  210. package/src/integrations/chat-sdk/commands.ts +194 -0
  211. package/src/integrations/chat-sdk/config.ts +198 -0
  212. package/src/integrations/chat-sdk/discord-api.ts +63 -0
  213. package/src/integrations/chat-sdk/discord-gateway.ts +185 -0
  214. package/src/integrations/chat-sdk/handlers.ts +28 -0
  215. package/src/integrations/chat-sdk/inbound.ts +426 -0
  216. package/src/integrations/chat-sdk/limits.ts +48 -0
  217. package/src/integrations/chat-sdk/logger.ts +81 -0
  218. package/src/integrations/chat-sdk/outbound.ts +123 -0
  219. package/src/integrations/chat-sdk/relay.ts +172 -0
  220. package/src/integrations/chat-sdk/router.ts +169 -0
  221. package/src/integrations/chat-sdk/runtime.ts +351 -0
  222. package/src/integrations/chat-sdk/schema.ts +245 -0
  223. package/src/integrations/chat-sdk/state.ts +243 -0
  224. package/src/integrations/chat-sdk/status.ts +244 -0
  225. package/src/integrations/chat-sdk/steering.ts +58 -0
  226. package/src/integrations/chat-sdk/teams-origin.ts +77 -0
  227. package/src/integrations/chat-sdk/telegram-api.ts +56 -0
  228. package/src/integrations/chat-sdk/templates.ts +16 -0
  229. package/src/integrations/chat-sdk/test-hooks.ts +37 -0
  230. package/src/integrations/chat-sdk/thread-buffer.ts +100 -0
  231. package/src/integrations/chat-sdk/typing.ts +65 -0
  232. package/src/pages/version.ts +4 -5
  233. package/src/prompts/base-prompt.ts +111 -45
  234. package/src/providers/acp-target-catalog.ts +6 -0
  235. package/src/providers/acp-targets.ts +55 -2
  236. package/src/providers/amp-adapter.ts +1 -1
  237. package/src/providers/claude-adapter.ts +1 -1
  238. package/src/providers/claude-flag-settings.ts +17 -5
  239. package/src/providers/claude-managed-adapter.ts +1 -1
  240. package/src/providers/claude-session-events.ts +6 -1
  241. package/src/providers/dsh-adapter.ts +1 -1
  242. package/src/providers/opencode-adapter.ts +243 -26
  243. package/src/providers/opencode-swarm-plugin.ts +31 -0
  244. package/src/providers/pi-mono-adapter.ts +398 -153
  245. package/src/providers/pricing-sources.md +33 -2
  246. package/src/providers/reasoning-effort.ts +27 -0
  247. package/src/providers/types.ts +6 -2
  248. package/src/rbac/legacy-policy.ts +8 -2
  249. package/src/rbac/permissions.ts +21 -0
  250. package/src/scheduler/scheduler.ts +4 -2
  251. package/src/scripts-runtime/loader.ts +19 -7
  252. package/src/scripts-runtime/sdk-allowlist.ts +8 -6
  253. package/src/scripts-runtime/swarm-sdk.ts +0 -11
  254. package/src/scripts-runtime/types/stdlib.d.ts +27 -15
  255. package/src/scripts-runtime/types/swarm-extension.d.ts +63 -1
  256. package/src/scripts-runtime/types/swarm-sdk.d.ts +27 -15
  257. package/src/server.ts +52 -18
  258. package/src/slack/event-dedup.ts +1 -1
  259. package/src/tasks/additive-buffer.ts +4 -2
  260. package/src/tasks/context-key.ts +60 -1
  261. package/src/tasks/model-pin.ts +67 -0
  262. package/src/tasks/worker-follow-up.ts +4 -31
  263. package/src/tests/acp-adapter.test.ts +42 -0
  264. package/src/tests/api-drain-worker-e2e.test.ts +1 -6
  265. package/src/tests/base-prompt.test.ts +58 -54
  266. package/src/tests/chat-sdk-commands.test.ts +191 -0
  267. package/src/tests/chat-sdk-config.test.ts +334 -0
  268. package/src/tests/chat-sdk-discord-api.test.ts +68 -0
  269. package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
  270. package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
  271. package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
  272. package/src/tests/chat-sdk-harness.ts +146 -0
  273. package/src/tests/chat-sdk-inbound.test.ts +363 -0
  274. package/src/tests/chat-sdk-relay.test.ts +470 -0
  275. package/src/tests/chat-sdk-reload.test.ts +128 -0
  276. package/src/tests/chat-sdk-shutdown.test.ts +220 -0
  277. package/src/tests/chat-sdk-slack.test.ts +268 -0
  278. package/src/tests/chat-sdk-state.test.ts +163 -0
  279. package/src/tests/chat-sdk-status-route.test.ts +382 -0
  280. package/src/tests/chat-sdk-teams.test.ts +277 -0
  281. package/src/tests/chat-sdk-tools.test.ts +520 -0
  282. package/src/tests/chat-sdk-typing.test.ts +120 -0
  283. package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
  284. package/src/tests/claude-adapter-binary.test.ts +9 -4
  285. package/src/tests/claude-flag-settings.test.ts +11 -3
  286. package/src/tests/claude-managed-adapter.test.ts +1 -1
  287. package/src/tests/claude-sdk-lifecycle.test.ts +9 -3
  288. package/src/tests/claude-thinking-tokens.test.ts +57 -0
  289. package/src/tests/claude-worker-parity.test.ts +2 -7
  290. package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
  291. package/src/tests/config-refs.test.ts +66 -0
  292. package/src/tests/context-key.test.ts +19 -0
  293. package/src/tests/cors-allowlist.test.ts +25 -0
  294. package/src/tests/create-page-tool.test.ts +18 -0
  295. package/src/tests/credential-check.test.ts +139 -0
  296. package/src/tests/credentials.test.ts +21 -0
  297. package/src/tests/db-runtime.test.ts +61 -0
  298. package/src/tests/db-task-read-contract.test.ts +20 -0
  299. package/src/tests/db-task-write-contract.test.ts +10 -0
  300. package/src/tests/docs-index-footprint.test.js +3 -3
  301. package/src/tests/dsh-adapter.test.ts +1 -1
  302. package/src/tests/enabled-capabilities.test.ts +20 -0
  303. package/src/tests/entrypoint-api-readiness.test.ts +14 -8
  304. package/src/tests/entrypoint-config-env-export.test.ts +5 -2
  305. package/src/tests/entrypoint-export-to-env.test.ts +78 -0
  306. package/src/tests/explicit-model-validation.test.ts +105 -1
  307. package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
  308. package/src/tests/extensions-post-bridge.test.ts +51 -0
  309. package/src/tests/fetch-resolved-env.test.ts +128 -0
  310. package/src/tests/fixtures/chat-sdk/telegram-private-text.json +10 -0
  311. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
  312. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
  313. package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
  314. package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
  315. package/src/tests/github-handlers.test.ts +35 -0
  316. package/src/tests/harness-provider-resolution.test.ts +12 -0
  317. package/src/tests/heartbeat-checklist.test.ts +3 -2
  318. package/src/tests/hook-runtime-close.test.ts +0 -2
  319. package/src/tests/http-api-integration.test.ts +0 -25
  320. package/src/tests/migration-046-budgets.test.ts +17 -16
  321. package/src/tests/migration-217-chat-sdk-state.test.ts +113 -0
  322. package/src/tests/model-tier-resolution.test.ts +93 -0
  323. package/src/tests/models-catalog.test.ts +42 -1
  324. package/src/tests/openai-compatible-providers.test.ts +134 -0
  325. package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
  326. package/src/tests/opencode-adapter.test.ts +216 -2
  327. package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
  328. package/src/tests/opencode-shell-env.test.ts +145 -0
  329. package/src/tests/openrouter-base-url.test.ts +101 -151
  330. package/src/tests/page-proxy.test.ts +1 -1
  331. package/src/tests/pages-browser-sdk.test.ts +76 -0
  332. package/src/tests/pages-feedback.test.ts +1 -1
  333. package/src/tests/paused-tasks-requested-by.test.ts +102 -0
  334. package/src/tests/pi-custom-provider-fake-server.test.ts +442 -0
  335. package/src/tests/pi-mono-adapter.test.ts +385 -5
  336. package/src/tests/pi-shell-env.test.ts +170 -0
  337. package/src/tests/prompt-template-remaining.test.ts +35 -0
  338. package/src/tests/rbac-engine.test.ts +11 -3
  339. package/src/tests/runner-exit-after-tasks.test.ts +0 -4
  340. package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
  341. package/src/tests/script-connections.test.ts +2 -0
  342. package/src/tests/scripts-http.test.ts +201 -1
  343. package/src/tests/scripts-only-gating.test.ts +2 -3
  344. package/src/tests/scripts-runtime.test.ts +58 -40
  345. package/src/tests/secret-scrubber.test.ts +86 -0
  346. package/src/tests/seed-skills-bundled-files.test.ts +45 -53
  347. package/src/tests/seed-skills-retire.test.ts +182 -0
  348. package/src/tests/send-task-requester-gate.test.ts +58 -0
  349. package/src/tests/session-cost-recompute-unit.test.ts +46 -0
  350. package/src/tests/skill-get-name-resolution.test.ts +137 -0
  351. package/src/tests/sonnet-5-5-registry.test.ts +9 -1
  352. package/src/tests/swarm-config-export-to-env.test.ts +267 -0
  353. package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
  354. package/src/tests/swarm-diff.test.ts +1 -1
  355. package/src/tests/task-model-effort-rerun.test.ts +164 -0
  356. package/src/tests/task-session-prompts.test.ts +132 -0
  357. package/src/tests/task-tool-manifest.test.ts +14 -0
  358. package/src/tests/task-tools-ctx.test.ts +2 -0
  359. package/src/tests/tool-annotations.test.ts +6 -6
  360. package/src/tests/ui-logs-parser.test.ts +43 -0
  361. package/src/tests/used-by-route.test.ts +6 -0
  362. package/src/tests/vercel-ai-gateway.test.ts +149 -0
  363. package/src/tests/workflow-swarm-script.test.ts +38 -0
  364. package/src/tests/workflow-wait-filter.test.ts +5 -3
  365. package/src/tools/chat-access.ts +41 -0
  366. package/src/tools/chat-open-dm.ts +59 -0
  367. package/src/tools/chat-post.ts +74 -0
  368. package/src/tools/chat-read-thread.ts +100 -0
  369. package/src/tools/chat-reply.ts +75 -0
  370. package/src/tools/create-page.ts +3 -13
  371. package/src/tools/model-catalog/index.ts +2 -1
  372. package/src/tools/register-chat-channel.ts +139 -0
  373. package/src/tools/send-task.ts +24 -0
  374. package/src/tools/skills/skill-get.ts +17 -9
  375. package/src/tools/swarm-config/get-config.ts +2 -1
  376. package/src/tools/swarm-config/list-config.ts +2 -1
  377. package/src/tools/swarm-config/set-config.ts +16 -3
  378. package/src/tools/tool-config.ts +8 -6
  379. package/src/types.ts +12 -2
  380. package/src/utils/config-env-export.ts +74 -0
  381. package/src/utils/credentials.test.ts +92 -0
  382. package/src/utils/credentials.ts +52 -4
  383. package/src/utils/harness-provider.ts +15 -6
  384. package/src/utils/runtime-model-catalog.ts +11 -1
  385. package/src/utils/secret-scrubber.ts +71 -2
  386. package/src/utils/task-tool-manifest.ts +19 -2
  387. package/src/workflows/executors/swarm-script.ts +1 -0
  388. package/templates/skills/agent-browser/SKILL.md +1 -1
  389. package/templates/skills/agent-browser/content.md +1 -1
  390. package/templates/skills/apps/SKILL.md +8 -1
  391. package/templates/skills/apps/content.md +8 -1
  392. package/templates/skills/chat-sdk/config.json +14 -0
  393. package/templates/skills/chat-sdk/content.md +84 -0
  394. package/templates/skills/composio-gmail/content.md +7 -0
  395. package/templates/skills/composio-google-docs/content.md +1 -1
  396. package/templates/skills/email-domain-health/config.json +14 -0
  397. package/templates/skills/email-domain-health/content.md +131 -0
  398. package/templates/skills/kv-storage/content.md +2 -2
  399. package/templates/skills/pages/content.md +8 -10
  400. package/templates/skills/swarm-extensions/content.md +2 -0
  401. package/templates/skills/swarm-scripts/SKILL.md +4 -2
  402. package/templates/skills/swarm-scripts/config.json +1 -1
  403. package/templates/skills/swarm-scripts/content.md +4 -2
  404. package/templates/skills/workflow-iterate/content.md +38 -0
  405. package/dist/artifact-eczsknc3.js +0 -3843
  406. package/dist/cli-bd957dgb.js +0 -153
  407. package/dist/cli-q51yprfq.js +0 -1104
  408. package/dist/cli-t1ze64h3.js +0 -811
  409. package/dist/cli-tcc4wd5d.js +0 -56471
  410. package/dist/index-9ch1n761.js +0 -1102
  411. package/src/artifact-sdk/index.ts +0 -2
  412. package/src/artifact-sdk/localtunnel.d.ts +0 -20
  413. package/src/artifact-sdk/port.ts +0 -12
  414. package/src/artifact-sdk/server.ts +0 -183
  415. package/src/artifact-sdk/tunnel.ts +0 -19
  416. package/src/commands/artifact.ts +0 -249
  417. package/src/http/ecosystem.ts +0 -77
  418. package/src/tests/artifact-commands.test.ts +0 -92
  419. package/src/tests/artifact-sdk.test.ts +0 -793
  420. package/src/tests/register-service-security.test.ts +0 -194
  421. package/src/tools/list-services.ts +0 -107
  422. package/src/tools/register-service.ts +0 -177
  423. package/src/tools/unregister-service.ts +0 -73
  424. package/src/tools/update-service-status.ts +0 -96
  425. package/templates/skills/artifacts/config.json +0 -14
  426. package/templates/skills/artifacts/content.md +0 -344
  427. package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
  428. package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
  429. package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
  430. package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
  431. /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
  432. /package/src/{artifact-sdk → pages}/feedback-overlay.ts +0 -0
@@ -38,7 +38,7 @@ const CONTRADICTORY_RE =
38
38
  /\b(do not|don't|never)\b[\s\S]{0,240}\b(always|must|required)\b|\b(always|must|required)\b[\s\S]{0,240}\b(do not|don't|never)\b/i;
39
39
 
40
40
  const CODE_REGISTRY_EVENTS =
41
- "agentmail.email.followup agentmail.email.mapped_lead agentmail.email.mapped_worker agentmail.email.no_agent agentmail.email.unmapped common.command_suggestions.github_comment_issue common.command_suggestions.github_comment_pr common.command_suggestions.github_issue common.command_suggestions.github_pr common.command_suggestions.gitlab_issue common.command_suggestions.gitlab_mr common.delegation_instruction common.delegation_instruction.gitlab github.check_run.failed github.check_suite.failed github.comment.mentioned github.issue.assigned github.issue.labeled github.issue.mentioned github.pull_request.assigned github.pull_request.closed github.pull_request.labeled github.pull_request.mentioned github.pull_request.review_requested github.pull_request.review_submitted github.pull_request.synchronize github.workflow_run.failed gitlab.comment.mentioned gitlab.issue.assigned gitlab.merge_request.opened gitlab.pipeline.failed heartbeat.boot-triage heartbeat.checklist jira.issue.assigned jira.issue.commented jira.issue.followup kapso.message.received linear.issue.assigned linear.issue.followup linear.issue.reassigned slack.assistant.greeting slack.assistant.offline slack.assistant.suggested_prompts slack.message.attachment_failed slack.message.thread_context system.agent.communication system.agent.lead system.agent.memory system.agent.memory.remote system.agent.outputs system.agent.outputs.no_agent_fs system.agent.repository system.agent.role system.agent.secrets system.agent.slack system.agent.tools_skills system.agent.worker system.agent.worker.remote system.agent.workspace system.agent.workspace.remote system.session.lead system.session.lead.managed system.session.worker system.session.worker.managed system.session.worker.remote task.budget.refused task.requester.profile task.worker.completed task.worker.failed".split(
41
+ "agentmail.email.followup agentmail.email.mapped_lead agentmail.email.mapped_worker agentmail.email.no_agent agentmail.email.unmapped chat.message.thread_context common.command_suggestions.github_comment_issue common.command_suggestions.github_comment_pr common.command_suggestions.github_issue common.command_suggestions.github_pr common.command_suggestions.gitlab_issue common.command_suggestions.gitlab_mr common.delegation_instruction common.delegation_instruction.gitlab github.check_run.failed github.check_suite.failed github.comment.mentioned github.issue.assigned github.issue.labeled github.issue.mentioned github.pull_request.assigned github.pull_request.closed github.pull_request.labeled github.pull_request.mentioned github.pull_request.review_requested github.pull_request.review_submitted github.pull_request.synchronize github.workflow_run.failed gitlab.comment.mentioned gitlab.issue.assigned gitlab.merge_request.opened gitlab.pipeline.failed heartbeat.boot-triage heartbeat.checklist jira.issue.assigned jira.issue.commented jira.issue.followup kapso.message.received linear.issue.assigned linear.issue.followup linear.issue.reassigned slack.assistant.greeting slack.assistant.offline slack.assistant.suggested_prompts slack.message.attachment_failed slack.message.thread_context system.agent.communication system.agent.lead system.agent.memory system.agent.memory.remote system.agent.outputs system.agent.outputs.no_agent_fs system.agent.repository system.agent.role system.agent.secrets system.agent.slack system.agent.tools_skills system.agent.worker system.agent.worker.remote system.agent.workspace system.agent.workspace.remote system.session.lead system.session.lead.managed system.session.worker system.session.worker.managed system.session.worker.remote task.budget.refused task.requester.profile task.worker.completed task.worker.failed".split(
42
42
  " ",
43
43
  );
44
44
 
@@ -1,22 +1,4 @@
1
1
  {
2
- "artifacts": [
3
- {
4
- "path": "examples/approval-flow.ts",
5
- "content": "import { createArtifactServer } from \"../../src/artifact-sdk\";\nimport { Hono } from \"hono\";\n\nconst app = new Hono();\napp.get(\"/\", (c) =>\n c.html(`\n<!DOCTYPE html>\n<html>\n<head><title>Approval Required</title></head>\n<body>\n <h1>PR #42 — Review Required</h1>\n <p>Agent wants to merge this PR. Please review.</p>\n <button id=\"approve\">Approve</button>\n <button id=\"reject\">Reject</button>\n <script src=\"/@swarm/sdk.js\"></script>\n <script>\n const swarm = new SwarmSDK();\n document.getElementById('approve').onclick = async () => {\n await swarm.createTask({ task: 'Merge PR #42 — human approved' });\n document.body.innerHTML = '<h1>Approved! Task created.</h1>';\n };\n document.getElementById('reject').onclick = async () => {\n await swarm.createTask({ task: 'PR #42 rejected by human — needs changes' });\n document.body.innerHTML = '<h1>Rejected. Agent notified.</h1>';\n };\n </script>\n</body>\n</html>\n`),\n);\n\nconst server = createArtifactServer({ name: \"approval-pr-42\", app });\nawait server.start();\nconsole.log(`Approval artifact at: ${server.url}`);\n"
6
- },
7
- {
8
- "path": "examples/hono-dashboard.ts",
9
- "content": "import { createArtifactServer } from \"../../src/artifact-sdk\";\nimport { Hono } from \"hono\";\n\nconst app = new Hono();\n\napp.get(\"/\", (c) =>\n c.html(`\n<!DOCTYPE html>\n<html>\n<head><title>Dashboard</title></head>\n<body>\n <h1>Agent Dashboard</h1>\n <div id=\"agents\"></div>\n <script src=\"/@swarm/sdk.js\"></script>\n <script>\n const swarm = new SwarmSDK();\n swarm.getSwarm().then(agents => {\n document.getElementById('agents').innerHTML =\n '<ul>' + agents.map(a => '<li>' + a.name + ' (' + a.status + ')</li>').join('') + '</ul>';\n });\n </script>\n</body>\n</html>\n`),\n);\n\napp.get(\"/api/status\", (c) => c.json({ status: \"ok\", timestamp: Date.now() }));\n\nconst server = createArtifactServer({ name: \"dashboard\", app });\nawait server.start();\nconsole.log(`Dashboard live at: ${server.url}`);\n"
10
- },
11
- {
12
- "path": "examples/multi-artifact.ts",
13
- "content": "import { createArtifactServer } from \"../../src/artifact-sdk\";\nimport { Hono } from \"hono\";\n\n// Artifact 1: Status page\nconst statusApp = new Hono();\nstatusApp.get(\"/\", (c) => c.html(\"<h1>Status: All systems operational</h1>\"));\n\n// Artifact 2: Data viewer\nconst dataApp = new Hono();\ndataApp.get(\"/\", (c) => c.json({ items: [1, 2, 3], generated: new Date().toISOString() }));\n\nconst status = createArtifactServer({ name: \"status\", app: statusApp });\nconst data = createArtifactServer({ name: \"data\", app: dataApp });\n\nawait status.start();\nawait data.start();\n\nconsole.log(`Status page: ${status.url}`);\nconsole.log(`Data viewer: ${data.url}`);\nconsole.log(`Both artifacts running on different ports (${status.port}, ${data.port})`);\n"
14
- },
15
- {
16
- "path": "examples/static-report.sh",
17
- "content": "#!/bin/bash\n# Serve a static HTML report as an artifact\nARTIFACT_DIR=\"/workspace/personal/artifacts/my-report\"\nmkdir -p \"$ARTIFACT_DIR\"\n\ncat > \"$ARTIFACT_DIR/index.html\" << 'HTML'\n<!DOCTYPE html>\n<html>\n<head><title>Agent Report</title></head>\n<body>\n <h1>Analysis Report</h1>\n <p>Generated by agent</p>\n</body>\n</html>\nHTML\n\nagent-swarm artifact serve \"$ARTIFACT_DIR\" --name \"my-report\"\n"
18
- }
19
- ],
20
2
  "brainstorming": [
21
3
  {
22
4
  "path": "template.md",
@@ -16,8 +16,6 @@ import agentBrowserContent from "../../../templates/skills/agent-browser/content
16
16
  };
17
17
  import appsConfig from "../../../templates/skills/apps/config.json" with { type: "text" };
18
18
  import appsContent from "../../../templates/skills/apps/content.md" with { type: "text" };
19
- import artifactsConfig from "../../../templates/skills/artifacts/config.json" with { type: "text" };
20
- import artifactsContent from "../../../templates/skills/artifacts/content.md" with { type: "text" };
21
19
  import askUserConfig from "../../../templates/skills/ask-user/config.json" with { type: "text" };
22
20
  import askUserContent from "../../../templates/skills/ask-user/content.md" with { type: "text" };
23
21
  import assetNamespacesConfig from "../../../templates/skills/asset-namespaces/config.json" with {
@@ -38,6 +36,8 @@ import brainstormingConfig from "../../../templates/skills/brainstorming/config.
38
36
  import brainstormingContent from "../../../templates/skills/brainstorming/content.md" with {
39
37
  type: "text",
40
38
  };
39
+ import chatSdkConfig from "../../../templates/skills/chat-sdk/config.json" with { type: "text" };
40
+ import chatSdkContent from "../../../templates/skills/chat-sdk/content.md" with { type: "text" };
41
41
  import codeQualityConfig from "../../../templates/skills/code-quality/config.json" with {
42
42
  type: "text",
43
43
  };
@@ -96,6 +96,12 @@ import downloadTaskAttachmentConfig from "../../../templates/skills/download-tas
96
96
  import downloadTaskAttachmentContent from "../../../templates/skills/download-task-attachment/content.md" with {
97
97
  type: "text",
98
98
  };
99
+ import emailDomainHealthConfig from "../../../templates/skills/email-domain-health/config.json" with {
100
+ type: "text",
101
+ };
102
+ import emailDomainHealthContent from "../../../templates/skills/email-domain-health/content.md" with {
103
+ type: "text",
104
+ };
99
105
  import engineeringStandardsConfig from "../../../templates/skills/engineering-standards/config.json" with {
100
106
  type: "text",
101
107
  };
@@ -270,9 +276,11 @@ import wtsExpertConfig from "../../../templates/skills/wts-expert/config.json" w
270
276
  import wtsExpertContent from "../../../templates/skills/wts-expert/content.md" with {
271
277
  type: "text",
272
278
  };
279
+ import type { Skill } from "../../types";
273
280
  import {
274
281
  computeContentHash,
275
282
  createSkill,
283
+ deleteSkill,
276
284
  deleteSkillFile,
277
285
  getDbClient,
278
286
  getSkillByName,
@@ -280,7 +288,9 @@ import {
280
288
  updateSkill,
281
289
  upsertSkillFiles,
282
290
  } from "../db";
291
+ import { deleteSeedState, getSeedState } from "../seed/state-db";
283
292
  import type { Seeder, SeedItem } from "../seed/types";
293
+ import { parseSkillContent } from "../skill-parser";
284
294
  import bundledFilesManifest from "./bundled-files.generated.json";
285
295
  import { buildSkillContent, type SkillTemplateConfig } from "./render";
286
296
 
@@ -321,11 +331,11 @@ const BUILT_IN_SKILL_FILES = bundledFilesManifest as Record<string, SeedSkillFil
321
331
  const BUILT_IN_SKILL_SOURCES = [
322
332
  { config: agentBrowserConfig, body: agentBrowserContent },
323
333
  { config: appsConfig, body: appsContent },
324
- { config: artifactsConfig, body: artifactsContent },
325
334
  { config: askUserConfig, body: askUserContent },
326
335
  { config: assetNamespacesConfig, body: assetNamespacesContent },
327
336
  { config: attioInteractionConfig, body: attioInteractionContent },
328
337
  { config: brainstormingConfig, body: brainstormingContent },
338
+ { config: chatSdkConfig, body: chatSdkContent },
329
339
  { config: codeQualityConfig, body: codeQualityContent },
330
340
  { config: codeReviewingConfig, body: codeReviewingContent },
331
341
  { config: commsConfig, body: commsContent },
@@ -337,6 +347,7 @@ const BUILT_IN_SKILL_SOURCES = [
337
347
  { config: delegateWorkConfig, body: delegateWorkContent },
338
348
  { config: designDocsConfig, body: designDocsContent },
339
349
  { config: downloadTaskAttachmentConfig, body: downloadTaskAttachmentContent },
350
+ { config: emailDomainHealthConfig, body: emailDomainHealthContent },
340
351
  { config: engineeringStandardsConfig, body: engineeringStandardsContent },
341
352
  { config: heartbeatRunbookConfig, body: heartbeatRunbookContent },
342
353
  { config: implementingConfig, body: implementingContent },
@@ -527,6 +538,94 @@ async function syncSeededSkillFiles(skillId: string, files: SeedSkillFile[]): Pr
527
538
  if (files.length > 0) await upsertSkillFiles(skillId, files);
528
539
  }
529
540
 
541
+ /**
542
+ * Skills this catalog used to seed and no longer ships. Dropping a template
543
+ * alone leaves its last seeded row live on every existing install, so agents
544
+ * keep reading instructions for a removed feature. `artifacts` documented the
545
+ * PM2 + localtunnel serving path, removed together with PM2.
546
+ */
547
+ export const RETIRED_SEED_SKILLS: readonly string[] = ["artifacts"];
548
+
549
+ /**
550
+ * True when every user-editable column outside the seed hash still holds what
551
+ * `skillsSeeder.apply` writes. The seed hash covers only content,
552
+ * systemDefault, userInvocable and bundled files, so an edit to any other
553
+ * column (description, model, allowedTools, source fields, ...) is invisible
554
+ * to it. The seeder writes the description from the same config as the
555
+ * content's frontmatter, so a pristine row's description equals the
556
+ * frontmatter one; every other column keeps its insert default.
557
+ */
558
+ function metadataAsSeeded(skill: Skill, fileCount: number): boolean {
559
+ let seededDescription: string;
560
+ try {
561
+ seededDescription = parseSkillContent(skill.content).description;
562
+ } catch {
563
+ return false;
564
+ }
565
+
566
+ return (
567
+ skill.description === seededDescription &&
568
+ skill.type === "personal" &&
569
+ skill.isComplex === fileCount > 0 &&
570
+ skill.isEnabled &&
571
+ !skill.disableModelInvocation &&
572
+ skill.allowedTools === null &&
573
+ skill.model === null &&
574
+ skill.effort === null &&
575
+ skill.context === null &&
576
+ skill.agent === null &&
577
+ skill.sourceUrl === null &&
578
+ skill.sourceRepo === null &&
579
+ skill.sourcePath === null &&
580
+ skill.sourceBranch === "main" &&
581
+ skill.sourceHash === null &&
582
+ skill.lastFetchedAt === null
583
+ );
584
+ }
585
+
586
+ /**
587
+ * Delete each retired skill the seeder still owns: a `seed_state` row exists,
588
+ * the live copy hashes to what was last seeded, and its metadata is as seeded.
589
+ * A skill the seeder never recorded, or one a user edited since (content,
590
+ * files or metadata), is left in place.
591
+ */
592
+ export async function retireSeedSkills(
593
+ names: readonly string[] = RETIRED_SEED_SKILLS,
594
+ ): Promise<string[]> {
595
+ const retired: string[] = [];
596
+
597
+ for (const name of names) {
598
+ const existing = await getSkillByName(name, "swarm");
599
+ if (!existing) continue;
600
+
601
+ const state = await getSeedState("skill", name);
602
+ if (!state) continue;
603
+
604
+ const liveFiles = (await getSkillFiles(existing.id)).map((file) => ({
605
+ path: file.path,
606
+ content: file.content,
607
+ }));
608
+ const liveHash = skillSeedHash(
609
+ existing.content,
610
+ existing.systemDefault,
611
+ liveFiles,
612
+ existing.userInvocable,
613
+ );
614
+ if (liveHash !== state.seededHash || !metadataAsSeeded(existing, liveFiles.length)) {
615
+ console.warn(`[seed:skill] kept retired skill "${name}": edited since it was seeded`);
616
+ continue;
617
+ }
618
+
619
+ await getDbClient().transaction(async () => {
620
+ await deleteSkill(existing.id);
621
+ await deleteSeedState("skill", name);
622
+ });
623
+ retired.push(name);
624
+ }
625
+
626
+ return retired;
627
+ }
628
+
530
629
  type SkillSeedItem = SeedItem & { skill: SeedSkill };
531
630
 
532
631
  export const skillsSeeder: Seeder<SkillSeedItem> = {
@@ -614,4 +713,6 @@ export const skillsSeeder: Seeder<SkillSeedItem> = {
614
713
  await syncSeededSkillFiles(created.id, skill.files);
615
714
  });
616
715
  },
716
+
717
+ retire: () => retireSeedSkills(),
617
718
  };
@@ -1,7 +1,9 @@
1
+ import { validateChatSdkAdaptersValue } from "../integrations/chat-sdk/schema";
1
2
  import { validateQuickJSPoolSize } from "../scripts-runtime/executors/quickjs-pool-config";
2
3
  import { normalizeSlackReactionShortcode } from "../slack/reaction-shortcode";
3
4
  import { ProviderNameSchema } from "../types";
4
5
  import { API_DRAIN_MAX_MS_LIMIT } from "../utils/api-drain";
6
+ import { envExportRestrictedError, isEnvExportRestrictedKey } from "../utils/config-env-export";
5
7
  import { parseEnabledTools } from "../utils/enabled-tools";
6
8
  import { normalizeOrgWebsite } from "../utils/org-website";
7
9
  import { parseTaskToolManifest } from "../utils/task-tool-manifest";
@@ -24,13 +26,47 @@ import { isTierConfigKey, validateTierConfigValue } from "./model-tier-keys";
24
26
  * rejected at every write path (DB helpers, HTTP routes, MCP tools).
25
27
  */
26
28
  // Lead activation is also deployment-only: leads can write ordinary global config.
29
+ // CHAT_SDK_API_URL_OVERRIDES points Chat SDK adapters (and the secrets they carry)
30
+ // at another host, so it must never come from a config row.
31
+ /**
32
+ * Teams SDK env fallbacks; a config row must not redirect the bot token.
33
+ * `@microsoft/teams.apps` reads these from `process.env`. Operators may still
34
+ * store them (they are not reserved), they just never reach env through
35
+ * `getInjectableGlobalConfigs`.
36
+ */
37
+ export const TEAMS_SDK_ENV_KEYS = [
38
+ "SERVICE_URL",
39
+ "TENANT_ID",
40
+ "CLIENT_ID",
41
+ "CLIENT_SECRET",
42
+ "MANAGED_IDENTITY_CLIENT_ID",
43
+ "CLOUD",
44
+ ] as const;
45
+
46
+ /** SQL literal list for the `NOT IN (...)` injection denylist in db.ts. */
47
+ export function teamsSdkEnvKeysSql(): string {
48
+ return TEAMS_SDK_ENV_KEYS.map((key) => `'${key}'`).join(", ");
49
+ }
50
+
27
51
  const RESERVED_KEYS = new Set([
28
52
  "API_KEY",
29
53
  "SECRETS_ENCRYPTION_KEY",
30
54
  "CORS_ALLOW_ANY_ORIGIN",
31
55
  "EXTENSION_ALLOW_LEAD_ACTIVATION",
56
+ "CHAT_SDK_API_URL_OVERRIDES",
32
57
  ]);
33
58
 
59
+ // Config keys the API server owns for its own use and must NEVER hand out over
60
+ // HTTP or to a script — workers/entrypoints read config to build their env, and
61
+ // the agent-fs bootstrap admin key would let a compromised worker administer the
62
+ // shared org. The API materializes these into its own process.env at boot via
63
+ // getInjectableGlobalConfigs, so no HTTP consumer legitimately needs them.
64
+ const API_ONLY_CONFIG_KEYS = new Set(["API_AGENT_FS_API_KEY", "SLACK_SIGNING_SECRET"]);
65
+
66
+ export function isApiOnlyConfigKey(key: string): boolean {
67
+ return API_ONLY_CONFIG_KEYS.has(key);
68
+ }
69
+
34
70
  /** Config rows owned by dedicated API surfaces, not the generic config API. */
35
71
  export const INTERNAL_CONFIG_KEYS = new Set(["onboarding_state", "runtime_owner_id"]);
36
72
 
@@ -254,6 +290,7 @@ const VALIDATED_KEYS: Record<string, ConfigValidator> = {
254
290
  ["RUNTIME_WAKE_GRACE_SEC", "RUNTIME_WAKE_REROUTE_SEC", "RUNTIME_ROUTING_INTERVAL_MS"],
255
291
  0,
256
292
  ),
293
+ CHAT_SDK_ADAPTERS: validateChatSdkAdaptersValue,
257
294
  TASK_TOOL_MANIFESTS: (value) => {
258
295
  try {
259
296
  if (typeof value !== "string") throw new Error("Expected JSON string");
@@ -380,6 +417,7 @@ const VALIDATED_KEYS: Record<string, ConfigValidator> = {
380
417
  "OPENROUTER_APP_ATTRIBUTION",
381
418
  "CURSOR_NATIVE_SYSTEM_PROMPT",
382
419
  "SLACK_DISABLE",
420
+ "CHAT_SDK_ENABLED",
383
421
  "SLACK_RENDER_V2",
384
422
  "SLACK_RENDER_V2_DELEGATION",
385
423
  "SLACK_BLOCK_EXTERNAL_CHANNELS",
@@ -474,6 +512,10 @@ const VALIDATED_KEYS: Record<string, ConfigValidator> = {
474
512
  ...integerValidators(["APPROVAL_REQUEST_AUTO_CANCELLATION_DAYS"], 0),
475
513
  // 0 turns the shutdown drain off; the shutdown path clamps to the same limit.
476
514
  ...boundedIntegerValidators(["API_DRAIN_MAX_MS"], 0, API_DRAIN_MAX_MS_LIMIT),
515
+ // Chat SDK thread buffer window. 0 or an invalid value falls back to the 10 s
516
+ // default in thread-buffer.ts; above 10 minutes a
517
+ // reply waits longer than any operator expects.
518
+ ...boundedIntegerValidators(["CHAT_SDK_BUFFER_MS"], 1, 600_000),
477
519
  // Below ~100 tokens the preamble can't fit a useful summary; above 20000
478
520
  // (~80k chars) it risks the SIGTERM-143 context-saturation failure mode
479
521
  // the cap exists to prevent (see context-preamble.ts).
@@ -495,3 +537,13 @@ export function validateConfigValue(key: string, value: unknown): string | null
495
537
  const validator = VALIDATED_KEYS[key.toUpperCase()];
496
538
  return validator ? validator(value) : null;
497
539
  }
540
+
541
+ /**
542
+ * Rejects `exportToEnv: true` for keys only the API server reads. Omitting the
543
+ * flag is fine: the write path stores false for those keys.
544
+ */
545
+ export function validateExportToEnv(key: string, exportToEnv: boolean | undefined): string | null {
546
+ return exportToEnv === true && isEnvExportRestrictedKey(key)
547
+ ? envExportRestrictedError(key)
548
+ : null;
549
+ }
package/src/cli.tsx CHANGED
@@ -303,12 +303,6 @@ const COMMAND_HELP: Record<
303
303
  options: " Internal command; no user-facing options",
304
304
  examples: ` ${binName} session-summary-stdin`,
305
305
  },
306
- artifact: {
307
- usage: `${binName} artifact <subcommand> [options]`,
308
- description: "Manage agent artifacts (serve, list, etc.).",
309
- options: " -h, --help Show this help",
310
- examples: [` ${binName} artifact serve`, ` ${binName} artifact help`].join("\n"),
311
- },
312
306
  x: {
313
307
  usage: `${binName} x <target> [args]`,
314
308
  description:
@@ -445,7 +439,6 @@ function printHelp(command?: string) {
445
439
  ["hook", "Handle Claude Code hook events (stdin)"],
446
440
  ["codex-hook", "Handle Codex CLI hook events (stdin, steering delivery)"],
447
441
  ["session-summary-stdin", "Generate a Claude session summary (internal, stdin)"],
448
- ["artifact", "Manage agent artifacts"],
449
442
  ["x", "Execute external command routes"],
450
443
  ["scripts", "Reusable scripts maintenance"],
451
444
  ["rbac", "RBAC role management (bootstrap)"],
@@ -774,15 +767,6 @@ if (args.showHelp || args.command === "help" || args.command === undefined) {
774
767
  const { runSessionSummaryFromStdin } = await import("./hooks/hook.ts");
775
768
  await runSessionSummaryFromStdin();
776
769
  process.exit(process.exitCode ?? 0);
777
- } else if (args.command === "artifact") {
778
- // Pass all args after "artifact" directly
779
- const artifactArgs = process.argv.slice(process.argv.indexOf("artifact") + 1);
780
- const { runArtifact } = await import("./commands/artifact");
781
- await runArtifact(artifactArgs[0] || "help", {
782
- additionalArgs: artifactArgs.slice(1),
783
- port: args.port,
784
- key: args.key,
785
- });
786
770
  } else if (args.command === "x") {
787
771
  const xArgs = process.argv.slice(process.argv.indexOf("x") + 1);
788
772
  const { runXCommand } = await import("./commands/x");
@@ -1,3 +1,4 @@
1
+ import { openAICompatibleProviders, providerKeyVars } from "@desplega/model-catalog";
1
2
  import {
2
3
  type HarnessProvider,
3
4
  type InstallProvider,
@@ -42,8 +43,9 @@ type ProviderStateKey =
42
43
  | "awsSessionToken"
43
44
  | "awsProfile";
44
45
 
45
- const ACCEPTED_CREDENTIALS =
46
- "Set one of: CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_API_KEY (Claude Code); OPENAI_API_KEY (OpenAI); OPENROUTER_API_KEY (OpenRouter); or AWS_REGION plus AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY or AWS_PROFILE and a Bedrock MODEL_OVERRIDE.";
46
+ const ACCEPTED_CREDENTIALS = `Set one of: CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_API_KEY (Claude Code); OPENAI_API_KEY (OpenAI); OPENROUTER_API_KEY (OpenRouter); or AWS_REGION plus AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY or AWS_PROFILE and a Bedrock MODEL_OVERRIDE. ${openAICompatibleProviders()
47
+ .map((p) => `${p.displayName} (${providerKeyVars(p).join(" or ")})`)
48
+ .join(" and ")} keys for pi/opencode are added from the dashboard.`;
47
49
 
48
50
  const DEFERRED_CREDENTIAL_LABEL = "no credential yet";
49
51
 
@@ -18,6 +18,13 @@
18
18
  * runs the predicate itself — it just reads the agent row.
19
19
  */
20
20
 
21
+ import {
22
+ type OpenAICompatibleProvider,
23
+ openAICompatibleKeyVars,
24
+ openAICompatibleProviders,
25
+ providerBaseUrl,
26
+ providerKeyFromEnv,
27
+ } from "@desplega/model-catalog";
21
28
  import { deriveDefaultRoute, validateRoute } from "@desplega/model-routing";
22
29
  import { ACP_TARGET_IDS, isAcpTarget } from "../providers/acp-target-catalog";
23
30
  import { checkAmpCredentials, liveTestAmpCredentials } from "../providers/amp-adapter";
@@ -116,8 +123,13 @@ export const REQUIRED_CRED_VARS_BY_PROVIDER: Record<SupportedProvider, readonly
116
123
  ],
117
124
  codex: ["OPENAI_API_KEY", "CODEX_OAUTH"],
118
125
  devin: ["DEVIN_API_KEY", "DEVIN_ORG_ID"],
119
- opencode: ["OPENROUTER_API_KEY", "ANTHROPIC_API_KEY", "OPENAI_API_KEY"],
120
- pi: ["ANTHROPIC_API_KEY", "OPENROUTER_API_KEY", "OPENAI_API_KEY"],
126
+ opencode: [
127
+ "OPENROUTER_API_KEY",
128
+ "ANTHROPIC_API_KEY",
129
+ "OPENAI_API_KEY",
130
+ ...openAICompatibleKeyVars(),
131
+ ],
132
+ pi: ["ANTHROPIC_API_KEY", "OPENROUTER_API_KEY", "OPENAI_API_KEY", ...openAICompatibleKeyVars()],
121
133
  // The ACP target owns its auth; custom targets still need a command.
122
134
  acp: [],
123
135
  dsh: ["DEEPSEEK_API_KEY", "OPENROUTER_API_KEY"],
@@ -323,6 +335,29 @@ async function checkOpenRouter(apiKey: string): Promise<LiveValidationResult> {
323
335
  };
324
336
  }
325
337
 
338
+ /**
339
+ * `GET <baseUrl>/models` with a Bearer key against an OpenAI-compatible
340
+ * registry provider (NaN, Helmcode). Lists models, runs no inference.
341
+ * `baseUrl` defaults to the registry entry; the probe passes the
342
+ * `<ID>_BASE_URL` override, and tests inject a fake server.
343
+ */
344
+ export async function checkOpenAICompatibleProvider(
345
+ provider: OpenAICompatibleProvider,
346
+ apiKey: string,
347
+ baseUrl: string = provider.baseUrl,
348
+ ): Promise<LiveValidationResult> {
349
+ const r = await timedFetch(`${baseUrl.replace(/\/+$/, "")}/models`, {
350
+ method: "GET",
351
+ headers: { Authorization: `Bearer ${apiKey}` },
352
+ });
353
+ if (r.ok) return { ok: true, latency_ms: r.latency_ms };
354
+ return {
355
+ ok: false,
356
+ error: scrubSecrets(`HTTP ${r.status}: ${r.bodyText.slice(0, 200)}`),
357
+ latency_ms: r.latency_ms,
358
+ };
359
+ }
360
+
326
361
  /**
327
362
  * Mirror of the disk check in `checkCodexCredentials` — true when the worker
328
363
  * has a materialised `~/.codex/auth.json`, which is the canonical "logged in"
@@ -365,7 +400,7 @@ function parseCodexOAuthAccess(blob: string | undefined): string | null {
365
400
  * | `claude` | default route: Foundry / Bedrock / Vertex → gateway (`ANTHROPIC_BASE_URL` + `ANTHROPIC_AUTH_TOKEN` or `ANTHROPIC_API_KEY`) → `CLAUDE_CODE_OAUTH_TOKEN` → `ANTHROPIC_API_KEY` | the route's own `/v1/models`; OAuth presence-only; cloud routes skipped |
366
401
  * | `claude-managed` | `ANTHROPIC_API_KEY` (managed agents always use API key + managed envs) | Anthropic `/v1/models` |
367
402
  * | `codex` | `~/.codex/auth.json` (file) → `CODEX_OAUTH` (env OAuth) → `OPENAI_API_KEY` | OpenAI `/v1/models` (api-key path only) |
368
- * | `opencode` | auth.json (file) → `OPENROUTER_API_KEY` → `ANTHROPIC_API_KEY` → `OPENAI_API_KEY` | file presence-only, otherwise provider's `/v1/models` |
403
+ * | `opencode` | auth.json (file) → `OPENROUTER_API_KEY` → `ANTHROPIC_API_KEY` → `OPENAI_API_KEY` → each registry provider key (`NAN_API_KEY` or `HELMCODE_API_NAN`, `HELMCODE_API_KEY`) | file presence-only, otherwise provider's `/v1/models` |
369
404
  * | `pi` | auth.json (file) → provider API keys, including model-specific keys | file/model-specific key presence-only, otherwise provider's `/v1/models` |
370
405
  * | `acp` | target-specific (the ACP target process owns its own auth) | presence-only (validated by the target process) |
371
406
  * | `pi` (bedrock) | `MODEL_OVERRIDE=amazon-bedrock/*` → AWS SDK default credential chain | presence-only (real check is the worker-side Bedrock enumeration) |
@@ -459,17 +494,28 @@ export async function validateProviderCredentials(
459
494
  // decision, including any injected filesystem probe used by reports.
460
495
  if (status.ready && status.satisfiedBy === "file") return presenceCheckOk();
461
496
  // Preserve the live-probe order for supported env keys:
462
- // OPENROUTER → ANTHROPIC → OPENAI.
497
+ // OPENROUTER → ANTHROPIC → OPENAI, then the OpenAI-compatible
498
+ // registry providers in declaration order (NaN, canonical key or
499
+ // alias → Helmcode) at their `<ID>_BASE_URL`, so existing env
500
+ // combinations keep their probe.
463
501
  if (env.OPENROUTER_API_KEY) return checkOpenRouter(env.OPENROUTER_API_KEY);
464
502
  if (env.ANTHROPIC_API_KEY) return checkAnthropicApiKey(env.ANTHROPIC_API_KEY);
465
503
  if (env.OPENAI_API_KEY) return checkOpenAiApiKey(env.OPENAI_API_KEY);
504
+ for (const direct of openAICompatibleProviders()) {
505
+ const key = providerKeyFromEnv(direct, env);
506
+ if (key) {
507
+ return checkOpenAICompatibleProvider(direct, key, providerBaseUrl(direct, env));
508
+ }
509
+ }
466
510
  // Model-specific keys (e.g. GEMINI_API_KEY) can satisfy readiness
467
511
  // without a probeable endpoint. The harness validates them at inference.
468
512
  if (status.ready) return presenceCheckOk();
469
513
  return {
470
514
  ok: false,
471
- error:
472
- "No usable credential found (OPENROUTER_API_KEY, ANTHROPIC_API_KEY, or OPENAI_API_KEY).",
515
+ error: `No usable credential found (OPENROUTER_API_KEY, ANTHROPIC_API_KEY, OPENAI_API_KEY, ${openAICompatibleProviders()
516
+ .map((p) => p.envVar)
517
+ .join(", ")
518
+ .replace(/, (?=[^,]*$)/, ", or ")}).`,
473
519
  latency_ms: Date.now() - startedAt,
474
520
  };
475
521
  }