@desplega.ai/agent-swarm 1.172.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (525) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-fpecx1g1.js → acp-adapter-sj2g0m84.js} +18 -17
  3. package/dist/{actions-pw87a1a8.js → actions-fegk44gr.js} +65 -35
  4. package/dist/{amp-adapter-8jem2bc0.js → amp-adapter-ad8ft89x.js} +8 -7
  5. package/dist/{anthropic-messages-8ee2f22q.js → anthropic-messages-r6czkjv1.js} +7 -7
  6. package/dist/{app-wmf0m843.js → app-kfvgbvzy.js} +19 -13
  7. package/dist/{assistant-emp1e108.js → assistant-z7zdy9ja.js} +65 -38
  8. package/dist/{boot-reembed-1de4f4aj.js → boot-reembed-5c2z0mbe.js} +11 -9
  9. package/dist/{boot-reembed-4ymn9atn.js → boot-reembed-j8xa181e.js} +11 -9
  10. package/dist/{boot-scrub-sweep-adhk1s8c.js → boot-scrub-sweep-hnkn3rgt.js} +12 -10
  11. package/dist/{boot-seeds-8q637aew.js → boot-seeds-kwjq4d2z.js} +15 -13
  12. package/dist/{claude-adapter-t26cv8a4.js → claude-adapter-9vmvpvgd.js} +20 -19
  13. package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-k9qae05j.js} +7 -5
  14. package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-q54zx5q2.js} +6 -4
  15. package/dist/{claude-sdk-session-gsfsh662.js → claude-sdk-session-9jye6cxr.js} +12698 -11995
  16. package/dist/{cli-k46r9hmk.js → cli-03gedhng.js} +16 -14
  17. package/dist/{cli-kb4ehzx5.js → cli-1e4b6bzh.js} +7 -7
  18. package/dist/{cli-d603qf86.js → cli-29jc5q7w.js} +10 -8
  19. package/dist/cli-2m1ktfzz.js +17795 -0
  20. package/dist/{cli-8vs9trd4.js → cli-3dj8k4vy.js} +1 -1
  21. package/dist/{cli-zxm9p3x4.js → cli-3fbmmawm.js} +5 -5
  22. package/dist/{cli-gmdajfw5.js → cli-4jxm2qtz.js} +4987 -1708
  23. package/dist/{cli-tadfgd0t.js → cli-5hkm7whv.js} +33 -4
  24. package/dist/{cli-6jb2rf77.js → cli-5t4f29ez.js} +3 -3
  25. package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
  26. package/dist/cli-6cvfxs8r.js +47 -0
  27. package/dist/{cli-pj6x9qce.js → cli-6jyj59nb.js} +2 -2
  28. package/dist/{cli-388egyf6.js → cli-6razj6t4.js} +2 -2
  29. package/dist/{cli-qsztpfry.js → cli-74ahz61x.js} +2 -2
  30. package/dist/{cli-4nz8p1p5.js → cli-7x0g4sn1.js} +15474 -16082
  31. package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
  32. package/dist/{cli-81r1wjyv.js → cli-9nfx44eh.js} +1 -1
  33. package/dist/cli-9traj3dn.js +638 -0
  34. package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
  35. package/dist/{cli-bf7485pm.js → cli-apx87jne.js} +2 -2
  36. package/dist/{cli-ztrv9y21.js → cli-bzszjf2p.js} +3689 -1081
  37. package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
  38. package/dist/{cli-hsem16hb.js → cli-cgtksawx.js} +7 -4
  39. package/dist/{cli-db3m6zdt.js → cli-d2qr7aj4.js} +1 -1
  40. package/dist/{cli-1hgat6pa.js → cli-d5f9ed5c.js} +5 -5
  41. package/dist/cli-e3g5mbkz.js +776 -0
  42. package/dist/{cli-7jykv7ef.js → cli-e6mpjhed.js} +1 -1
  43. package/dist/{cli-j6kpj9az.js → cli-ee9gtz70.js} +1553 -68
  44. package/dist/{cli-e0a9sk00.js → cli-eejsgvm4.js} +4 -4
  45. package/dist/{cli-tgpfnm6r.js → cli-ef1hg1wv.js} +518 -59
  46. package/dist/cli-f527ce74.js +781 -0
  47. package/dist/{cli-ppy4nnnh.js → cli-f7kr7svz.js} +2 -2
  48. package/dist/cli-hjwmhcg1.js +10622 -0
  49. package/dist/{cli-2bw3w47j.js → cli-hnhtk6cj.js} +1 -1
  50. package/dist/{cli-ywm1azg9.js → cli-hnmhtzvh.js} +6 -4
  51. package/dist/{cli-4fnb6884.js → cli-hvqbtna4.js} +7 -1259
  52. package/dist/{cli-pstq9888.js → cli-j0pfptdp.js} +220 -103
  53. package/dist/cli-jta2eyzc.js +619 -0
  54. package/dist/{cli-esnpehf5.js → cli-k382tshb.js} +12 -13
  55. package/dist/cli-k3dp5tpf.js +263 -0
  56. package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
  57. package/dist/cli-kceah1eh.js +92 -0
  58. package/dist/{cli-prrt9fa0.js → cli-ke896fcf.js} +10 -10
  59. package/dist/{cli-nv4zd0b9.js → cli-kt6zqg0e.js} +6 -6
  60. package/dist/{cli-g6t9texm.js → cli-m50t4309.js} +5 -18
  61. package/dist/cli-n2wq4j7m.js +6985 -0
  62. package/dist/{cli-c2pq2rjb.js → cli-n3hzg89b.js} +46 -15
  63. package/dist/{cli-tmhsxhb8.js → cli-n5vwg842.js} +23 -6
  64. package/dist/{cli-5rv1j9ga.js → cli-ne236afy.js} +53 -7
  65. package/dist/cli-p0sg24zp.js +16 -0
  66. package/dist/{cli-d161g69q.js → cli-p1x85d2t.js} +50 -2
  67. package/dist/{cli-7pz3b7x5.js → cli-przpmdgr.js} +25 -0
  68. package/dist/{cli-g4f5pj26.js → cli-q0ke1yww.js} +111 -25
  69. package/dist/{cli-e3pmyt39.js → cli-q50942rs.js} +1 -1
  70. package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
  71. package/dist/{cli-gj81e47t.js → cli-r2pnvj8g.js} +2 -2
  72. package/dist/{cli-r8smj8b8.js → cli-r62a35ea.js} +19 -3
  73. package/dist/{cli-cd0hv9nh.js → cli-ra0xzggj.js} +2 -2
  74. package/dist/cli-rhs9pz33.js +294 -0
  75. package/dist/{cli-nyhb1r6x.js → cli-s2sp957d.js} +52 -29
  76. package/dist/{cli-1x7da0de.js → cli-s4setq91.js} +8 -8
  77. package/dist/{cli-xczpdp9e.js → cli-se8w6wny.js} +6 -6
  78. package/dist/cli-skxvvpap.js +10140 -0
  79. package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
  80. package/dist/{cli-0p3enk35.js → cli-tqaazemc.js} +9 -1
  81. package/dist/{cli-cf69s3ew.js → cli-tr4sxp68.js} +3 -3
  82. package/dist/{cli-8hzfb6xz.js → cli-tsde1hdr.js} +15 -15
  83. package/dist/{cli-cceskcvt.js → cli-txqb9s38.js} +8 -8
  84. package/dist/{cli-aspcaef3.js → cli-v1yb0rqb.js} +6 -6
  85. package/dist/{cli-j1pmc07z.js → cli-vatyhshy.js} +268 -40
  86. package/dist/{cli-04emfe2q.js → cli-vdach5a9.js} +5 -5
  87. package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
  88. package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
  89. package/dist/{cli-hwwvy36w.js → cli-wayw93nt.js} +3 -3
  90. package/dist/cli-wmgrkscj.js +23254 -0
  91. package/dist/{cli-gp1rtyvk.js → cli-z5jjpaxw.js} +29 -6
  92. package/dist/{cli-451ks6aw.js → cli-zkpks3r3.js} +1 -1
  93. package/dist/cli.js +32 -48
  94. package/dist/{codex-adapter-m4tgdysy.js → codex-adapter-y81sssk0.js} +16 -15
  95. package/dist/{codex-login-841kv5fk.js → codex-login-f2rcfpp9.js} +3 -2
  96. package/dist/{codex-session-runner-ymwzm6ea.js → codex-session-runner-8vx4j6a9.js} +16 -15
  97. package/dist/{commands-n0hshcvs.js → commands-kcpvpcrr.js} +21 -10
  98. package/dist/{controller-hq5ggpcp.js → controller-ywrmt6yd.js} +5 -4
  99. package/dist/{controllers-connect-y07cqcvy.js → controllers-connect-kwpvj3rf.js} +45 -38
  100. package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-cehv1qns.js} +7 -6
  101. package/dist/{db-hkqvrdcb.js → db-k8ankj20.js} +13 -11
  102. package/dist/{db-4w7tmt1g.js → db-ww5d7jq3.js} +29 -9
  103. package/dist/{devin-adapter-xgtj680j.js → devin-adapter-x1022qb1.js} +3 -2
  104. package/dist/{dispatcher-5sd69y14.js → dispatcher-e8gq5m68.js} +41 -34
  105. package/dist/{docker-f503k9p0.js → docker-ff6y1190.js} +3 -2
  106. package/dist/{dsh-adapter-2h8m4cab.js → dsh-adapter-3epjm3af.js} +7 -6
  107. package/dist/{e2b-66xra4az.js → e2b-8ygwhg0f.js} +4 -3
  108. package/dist/{e2b-xwhyj8cw.js → e2b-swhnpw3n.js} +4 -3
  109. package/dist/{event-bus-vjtv82gm.js → event-bus-6axnngdj.js} +3 -2
  110. package/dist/external-channel-h3359cwn.js +52 -0
  111. package/dist/{google-generative-ai-7pavrbv7.js → google-generative-ai-g8db7x0f.js} +5 -3
  112. package/dist/{google-vertex-3f1jk41f.js → google-vertex-r2692q0r.js} +5 -3
  113. package/dist/{grok-adapter-8m9yqzbq.js → grok-adapter-0d4x7gkx.js} +19 -18
  114. package/dist/{handlers-s20xr10r.js → handlers-an1gzv21.js} +44 -37
  115. package/dist/{heartbeat-3k31q4g2.js → heartbeat-6dakeb61.js} +46 -39
  116. package/dist/{hook-gdn6a2fn.js → hook-6v6cv6d5.js} +12 -24
  117. package/dist/{hook-ygwerrdh.js → hook-sa5xye4y.js} +13 -12
  118. package/dist/{http-jdteeg81.js → http-r7f3eky0.js} +1598 -279
  119. package/dist/index-52j1aja4.js +3465 -0
  120. package/dist/{index-e0snym4t.js → index-7ep4gzdk.js} +41 -34
  121. package/dist/index-9gw58n4k.js +193 -0
  122. package/dist/index-9j87mcm8.js +56305 -0
  123. package/dist/index-bsmcresk.js +79424 -0
  124. package/dist/index-mh85qhec.js +475 -0
  125. package/dist/{index-vm3bm9t7.js → index-rmpw9a8q.js} +41 -34
  126. package/dist/{index-6ksewd5y.js → index-s2wxgzr0.js} +1015 -732
  127. package/dist/{index-tsszt7g9.js → index-v1v6n7hg.js} +46 -39
  128. package/dist/index-we27kd31.js +12810 -0
  129. package/dist/{index-ffqzqgwb.js → index-zk96aq1k.js} +11 -9
  130. package/dist/{keepalive-jekc896t.js → keepalive-be9vwy5h.js} +13 -11
  131. package/dist/{lead-4k9s9szx.js → lead-0861cwrf.js} +64 -57
  132. package/dist/{maintenance-shazch4n.js → maintenance-mzzgc8bn.js} +11 -9
  133. package/dist/node-c9we95xf.js +1 -1
  134. package/dist/{node-fkajaq96.js → node-mn1zs7an.js} +2 -1
  135. package/dist/{oauth-refresh-sweep-5gb36kn8.js → oauth-refresh-sweep-cpdnfwdj.js} +12 -10
  136. package/dist/{onboard-ydrbnvww.js → onboard-fh8qs4r3.js} +11 -3
  137. package/dist/{opencode-adapter-5zh0he20.js → opencode-adapter-nm42wwj8.js} +19 -14
  138. package/dist/{otel-impl-6pf5cv86.js → otel-impl-x6c1c9g4.js} +248 -869
  139. package/dist/{pi-mono-adapter-ef9wwx9m.js → pi-mono-adapter-9n2ya240.js} +245 -107
  140. package/dist/{pricing-refresh-s52nsa5q.js → pricing-refresh-qb0rv0ap.js} +13 -11
  141. package/dist/{rbac-roles-aq3msh4e.js → rbac-roles-1gzdwbh1.js} +12 -10
  142. package/dist/{rbac-roles-q5gb5e8v.js → rbac-roles-3mraey52.js} +13 -11
  143. package/dist/{render-v2-pd1rg54q.js → render-v2-agpa45zz.js} +19 -13
  144. package/dist/{resume-gw4a2c6v.js → resume-x0ydy9s9.js} +27 -21
  145. package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
  146. package/dist/{setup-jda1ksdh.js → setup-as9ga0d6.js} +2 -2
  147. package/dist/{virtual-modules-b3ga2m65.js → virtual-modules-9gkxqrap.js} +7 -6
  148. package/dist/{work-objects-tb7ycye8.js → work-objects-y5g1y7ev.js} +49 -37
  149. package/dist/{worker-njjccz5d.js → worker-860c3e38.js} +64 -57
  150. package/dist/{x-qfmygqqv.js → x-m477fr0h.js} +3 -2
  151. package/openapi.json +951 -356
  152. package/package.json +12 -13
  153. package/src/apps/catalog.generated.json +1309 -53
  154. package/src/apps/page-validator.ts +93 -31
  155. package/src/azure-devops/api.ts +94 -18
  156. package/src/azure-devops/auth.ts +32 -0
  157. package/src/azure-devops/boards-sync.ts +708 -0
  158. package/src/azure-devops/handlers.ts +52 -8
  159. package/src/azure-devops/html.ts +26 -0
  160. package/src/azure-devops/index.ts +15 -0
  161. package/src/azure-devops/templates.ts +86 -0
  162. package/src/azure-devops/types.ts +65 -1
  163. package/src/be/config-refs.ts +60 -0
  164. package/src/be/db/page-versions.ts +15 -0
  165. package/src/be/db/runtime.ts +35 -8
  166. package/src/be/db/skill-name-resolution.ts +36 -0
  167. package/src/be/db/tasks/read.ts +230 -0
  168. package/src/be/db/tasks/write.ts +7 -0
  169. package/src/be/db.ts +74 -13
  170. package/src/be/migrations/213_script_connections_sql.sql +79 -0
  171. package/src/be/migrations/215_swarm_config_export_to_env.sql +34 -0
  172. package/src/be/migrations/216_task_resolved_effort.sql +5 -0
  173. package/src/be/migrations/217_chat_sdk_state.sql +104 -0
  174. package/src/be/model-catalog-store.ts +5 -1
  175. package/src/be/model-tier-resolution.ts +12 -1
  176. package/src/be/model-validation.ts +5 -2
  177. package/src/be/models-catalog.ts +26 -1
  178. package/src/be/modelsdev-cache.json +198 -63
  179. package/src/be/modelsdev-cache.ts +9 -1
  180. package/src/be/script-connections.ts +47 -8
  181. package/src/be/script-credential-broker.ts +39 -2
  182. package/src/be/scripts/run-saved.ts +1 -0
  183. package/src/be/scripts/typecheck.ts +10 -8
  184. package/src/be/seed/runner.ts +13 -1
  185. package/src/be/seed/state-db.ts +5 -0
  186. package/src/be/seed/types.ts +6 -0
  187. package/src/be/seed-pricing.ts +19 -2
  188. package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
  189. package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
  190. package/src/be/seed-skills/bundled-files.generated.json +10 -18
  191. package/src/be/seed-skills/index.ts +107 -3
  192. package/src/be/sql-connections.ts +118 -0
  193. package/src/be/swarm-config-guard.ts +53 -0
  194. package/src/cli.tsx +0 -16
  195. package/src/commands/onboard/non-interactive.ts +4 -2
  196. package/src/commands/profile-sync.ts +5 -3
  197. package/src/commands/provider-credentials.ts +52 -6
  198. package/src/commands/runner.ts +196 -56
  199. package/src/e2b/env.ts +5 -0
  200. package/src/extensions/contract-types.generated.ts +1 -1
  201. package/src/extensions/contract.ts +45 -0
  202. package/src/extensions/dispatcher.ts +7 -0
  203. package/src/extensions/post-bridge.ts +40 -0
  204. package/src/github/handlers.ts +11 -4
  205. package/src/heartbeat/templates.ts +8 -5
  206. package/src/hooks/hook.ts +0 -26
  207. package/src/http/all-routes.ts +0 -1
  208. package/src/http/config.ts +36 -17
  209. package/src/http/core.ts +4 -0
  210. package/src/http/index.ts +14 -2
  211. package/src/http/integrations.ts +88 -1
  212. package/src/http/mcp-oauth.ts +6 -13
  213. package/src/http/mcp.ts +15 -5
  214. package/src/http/page-proxy.ts +2 -4
  215. package/src/http/pages-public.ts +6 -5
  216. package/src/http/pages.ts +5 -14
  217. package/src/http/poll.ts +28 -68
  218. package/src/http/requested-by.ts +54 -0
  219. package/src/http/route-def.ts +7 -6
  220. package/src/http/script-connection-proxy.ts +51 -4
  221. package/src/http/script-connections.ts +5 -2
  222. package/src/http/scripts.ts +1 -0
  223. package/src/http/session-cost-recompute.ts +12 -2
  224. package/src/http/session-data.ts +4 -0
  225. package/src/http/stats.ts +1 -30
  226. package/src/http/tasks.ts +61 -5
  227. package/src/http/utils.ts +14 -0
  228. package/src/http/webhooks.ts +183 -2
  229. package/src/http/x.ts +1 -0
  230. package/src/integrations/chat-sdk/adapters.ts +129 -0
  231. package/src/integrations/chat-sdk/attachments.ts +232 -0
  232. package/src/integrations/chat-sdk/background.ts +36 -0
  233. package/src/integrations/chat-sdk/commands.ts +194 -0
  234. package/src/integrations/chat-sdk/config.ts +198 -0
  235. package/src/integrations/chat-sdk/discord-api.ts +63 -0
  236. package/src/integrations/chat-sdk/discord-gateway.ts +185 -0
  237. package/src/integrations/chat-sdk/handlers.ts +28 -0
  238. package/src/integrations/chat-sdk/inbound.ts +426 -0
  239. package/src/integrations/chat-sdk/limits.ts +48 -0
  240. package/src/integrations/chat-sdk/logger.ts +81 -0
  241. package/src/integrations/chat-sdk/outbound.ts +123 -0
  242. package/src/integrations/chat-sdk/relay.ts +172 -0
  243. package/src/integrations/chat-sdk/router.ts +169 -0
  244. package/src/integrations/chat-sdk/runtime.ts +351 -0
  245. package/src/integrations/chat-sdk/schema.ts +245 -0
  246. package/src/integrations/chat-sdk/state.ts +243 -0
  247. package/src/integrations/chat-sdk/status.ts +244 -0
  248. package/src/integrations/chat-sdk/steering.ts +58 -0
  249. package/src/integrations/chat-sdk/teams-origin.ts +77 -0
  250. package/src/integrations/chat-sdk/telegram-api.ts +56 -0
  251. package/src/integrations/chat-sdk/templates.ts +16 -0
  252. package/src/integrations/chat-sdk/test-hooks.ts +37 -0
  253. package/src/integrations/chat-sdk/thread-buffer.ts +100 -0
  254. package/src/integrations/chat-sdk/typing.ts +65 -0
  255. package/src/jira/adf.ts +3 -1
  256. package/src/kv-reserved-namespaces.ts +2 -0
  257. package/src/oauth/mcp-wrapper.ts +10 -6
  258. package/src/otel-impl.ts +2 -1
  259. package/src/pages/version.ts +4 -5
  260. package/src/prompts/base-prompt.ts +111 -45
  261. package/src/providers/acp-target-catalog.ts +6 -0
  262. package/src/providers/acp-targets.ts +56 -3
  263. package/src/providers/amp-adapter.ts +1 -1
  264. package/src/providers/claude-adapter.ts +27 -2
  265. package/src/providers/claude-flag-settings.ts +133 -0
  266. package/src/providers/claude-managed-adapter.ts +1 -1
  267. package/src/providers/claude-sdk-session.ts +7 -0
  268. package/src/providers/claude-session-events.ts +6 -1
  269. package/src/providers/dsh-adapter.ts +1 -1
  270. package/src/providers/opencode-adapter.ts +268 -37
  271. package/src/providers/opencode-billing.ts +86 -0
  272. package/src/providers/opencode-swarm-plugin.ts +51 -0
  273. package/src/providers/pi-mono-adapter.ts +398 -153
  274. package/src/providers/pricing-sources.md +37 -3
  275. package/src/providers/reasoning-effort.ts +27 -0
  276. package/src/providers/types.ts +11 -2
  277. package/src/rbac/legacy-policy.ts +8 -2
  278. package/src/rbac/permissions.ts +21 -0
  279. package/src/scheduler/scheduler.ts +4 -2
  280. package/src/scripts-runtime/api-client.ts +15 -1
  281. package/src/scripts-runtime/api-types.ts +9 -1
  282. package/src/scripts-runtime/ctx.ts +1 -1
  283. package/src/scripts-runtime/loader.ts +19 -7
  284. package/src/scripts-runtime/mcp-client.ts +30 -19
  285. package/src/scripts-runtime/sdk-allowlist.ts +8 -6
  286. package/src/scripts-runtime/swarm-sdk.ts +0 -11
  287. package/src/scripts-runtime/types/stdlib.d.ts +27 -15
  288. package/src/scripts-runtime/types/swarm-extension.d.ts +63 -1
  289. package/src/scripts-runtime/types/swarm-sdk.d.ts +27 -15
  290. package/src/server.ts +52 -18
  291. package/src/slack/actions.ts +29 -1
  292. package/src/slack/app.ts +14 -2
  293. package/src/slack/assistant.ts +36 -2
  294. package/src/slack/channel-join.ts +3 -16
  295. package/src/slack/commands.ts +9 -1
  296. package/src/slack/event-dedup.ts +1 -1
  297. package/src/slack/external-channel-egress.ts +113 -0
  298. package/src/slack/external-channel.ts +309 -0
  299. package/src/slack/handlers.ts +61 -0
  300. package/src/slack/render-v2.ts +40 -47
  301. package/src/slack/work-objects.ts +5 -0
  302. package/src/tasks/additive-buffer.ts +4 -2
  303. package/src/tasks/context-key.ts +94 -2
  304. package/src/tasks/model-pin.ts +67 -0
  305. package/src/tasks/worker-follow-up.ts +4 -31
  306. package/src/telemetry.ts +2 -1
  307. package/src/tests/acp-adapter.test.ts +42 -0
  308. package/src/tests/api-drain-worker-e2e.test.ts +1 -6
  309. package/src/tests/apps-catalog-feedback.test.ts +310 -0
  310. package/src/tests/apps-catalog-inputs.test.ts +70 -0
  311. package/src/tests/apps-catalog-table.test.ts +113 -0
  312. package/src/tests/azure-devops-boards-sync.test.ts +584 -0
  313. package/src/tests/azure-devops-html.test.ts +13 -0
  314. package/src/tests/azure-devops-webhook-malformed.test.ts +4 -0
  315. package/src/tests/base-prompt.test.ts +58 -54
  316. package/src/tests/chat-sdk-commands.test.ts +191 -0
  317. package/src/tests/chat-sdk-config.test.ts +334 -0
  318. package/src/tests/chat-sdk-discord-api.test.ts +68 -0
  319. package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
  320. package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
  321. package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
  322. package/src/tests/chat-sdk-harness.ts +146 -0
  323. package/src/tests/chat-sdk-inbound.test.ts +363 -0
  324. package/src/tests/chat-sdk-relay.test.ts +470 -0
  325. package/src/tests/chat-sdk-reload.test.ts +128 -0
  326. package/src/tests/chat-sdk-shutdown.test.ts +220 -0
  327. package/src/tests/chat-sdk-slack.test.ts +268 -0
  328. package/src/tests/chat-sdk-state.test.ts +163 -0
  329. package/src/tests/chat-sdk-status-route.test.ts +382 -0
  330. package/src/tests/chat-sdk-teams.test.ts +277 -0
  331. package/src/tests/chat-sdk-tools.test.ts +520 -0
  332. package/src/tests/chat-sdk-typing.test.ts +120 -0
  333. package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
  334. package/src/tests/claude-adapter-binary.test.ts +144 -0
  335. package/src/tests/claude-flag-settings.test.ts +114 -0
  336. package/src/tests/claude-managed-adapter.test.ts +1 -1
  337. package/src/tests/claude-sdk-lifecycle.test.ts +148 -1
  338. package/src/tests/claude-sdk-process.fixture.ts +7 -0
  339. package/src/tests/claude-thinking-tokens.test.ts +57 -0
  340. package/src/tests/claude-worker-parity.test.ts +2 -7
  341. package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
  342. package/src/tests/config-refs.test.ts +66 -0
  343. package/src/tests/context-key.test.ts +51 -0
  344. package/src/tests/cors-allowlist.test.ts +25 -0
  345. package/src/tests/create-page-tool.test.ts +18 -0
  346. package/src/tests/credential-check.test.ts +139 -0
  347. package/src/tests/credentials.test.ts +21 -0
  348. package/src/tests/db-runtime.test.ts +61 -0
  349. package/src/tests/db-task-read-contract.test.ts +20 -0
  350. package/src/tests/db-task-write-contract.test.ts +10 -0
  351. package/src/tests/deferred-task-wake.test.ts +52 -4
  352. package/src/tests/docs-index-footprint.test.js +3 -3
  353. package/src/tests/dsh-adapter.test.ts +1 -1
  354. package/src/tests/enabled-capabilities.test.ts +20 -0
  355. package/src/tests/entrypoint-api-readiness.test.ts +14 -8
  356. package/src/tests/entrypoint-config-env-export.test.ts +5 -2
  357. package/src/tests/entrypoint-export-to-env.test.ts +78 -0
  358. package/src/tests/explicit-model-validation.test.ts +105 -1
  359. package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
  360. package/src/tests/extensions-post-bridge.test.ts +51 -0
  361. package/src/tests/fetch-resolved-env.test.ts +128 -0
  362. package/src/tests/fixtures/azure-boards/workitem.commented.json +89 -0
  363. package/src/tests/fixtures/azure-boards/workitem.created.json +81 -0
  364. package/src/tests/fixtures/azure-boards/workitem.deleted.json +70 -0
  365. package/src/tests/fixtures/azure-boards/workitem.restored.json +82 -0
  366. package/src/tests/fixtures/azure-boards/workitem.updated.json +130 -0
  367. package/src/tests/fixtures/catalog-feedback-definition.json.txt +860 -0
  368. package/src/tests/fixtures/catalog-inputs-definition.json.txt +910 -0
  369. package/src/tests/fixtures/catalog-table-definition.json.txt +468 -0
  370. package/src/tests/fixtures/chat-sdk/telegram-private-text.json +10 -0
  371. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
  372. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
  373. package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
  374. package/src/tests/fixtures/runner-identity-refresh.ts +3 -0
  375. package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
  376. package/src/tests/github-handlers.test.ts +35 -0
  377. package/src/tests/harness-provider-resolution.test.ts +12 -0
  378. package/src/tests/heartbeat-checklist.test.ts +3 -2
  379. package/src/tests/hook-runtime-close.test.ts +0 -2
  380. package/src/tests/http-api-integration.test.ts +0 -25
  381. package/src/tests/migration-046-budgets.test.ts +17 -16
  382. package/src/tests/migration-217-chat-sdk-state.test.ts +113 -0
  383. package/src/tests/model-tier-resolution.test.ts +93 -0
  384. package/src/tests/models-catalog.test.ts +42 -1
  385. package/src/tests/node-env-runtime.test.ts +98 -0
  386. package/src/tests/openai-compatible-providers.test.ts +134 -0
  387. package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
  388. package/src/tests/opencode-adapter.test.ts +348 -3
  389. package/src/tests/opencode-billing.test.ts +28 -0
  390. package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
  391. package/src/tests/opencode-shell-env.test.ts +145 -0
  392. package/src/tests/openrouter-base-url.test.ts +101 -151
  393. package/src/tests/page-proxy.test.ts +1 -1
  394. package/src/tests/pages-browser-sdk.test.ts +76 -0
  395. package/src/tests/pages-feedback.test.ts +1 -1
  396. package/src/tests/paused-tasks-requested-by.test.ts +102 -0
  397. package/src/tests/pi-custom-provider-fake-server.test.ts +442 -0
  398. package/src/tests/pi-mono-adapter.test.ts +385 -5
  399. package/src/tests/pi-shell-env.test.ts +170 -0
  400. package/src/tests/prompt-template-remaining.test.ts +35 -0
  401. package/src/tests/rbac-engine.test.ts +11 -3
  402. package/src/tests/runner-exit-after-tasks.test.ts +0 -4
  403. package/src/tests/runner-identity-refresh.test.ts +3 -0
  404. package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
  405. package/src/tests/script-connections-sql.test.ts +675 -0
  406. package/src/tests/script-connections.test.ts +7 -1
  407. package/src/tests/scripts-http.test.ts +201 -1
  408. package/src/tests/scripts-only-gating.test.ts +2 -3
  409. package/src/tests/scripts-runtime.test.ts +58 -40
  410. package/src/tests/secret-scrubber.test.ts +86 -0
  411. package/src/tests/seed-skills-bundled-files.test.ts +45 -53
  412. package/src/tests/seed-skills-retire.test.ts +182 -0
  413. package/src/tests/send-task-requester-gate.test.ts +58 -0
  414. package/src/tests/session-cost-recompute-unit.test.ts +94 -0
  415. package/src/tests/skill-get-name-resolution.test.ts +137 -0
  416. package/src/tests/slack-channel-join.test.ts +4 -1
  417. package/src/tests/slack-external-channel-config.test.ts +65 -0
  418. package/src/tests/slack-external-channel-egress.test.ts +237 -0
  419. package/src/tests/slack-external-channel-guard.test.ts +280 -0
  420. package/src/tests/slack-external-channel-tools.test.ts +173 -0
  421. package/src/tests/slack-external-channel.test.ts +370 -0
  422. package/src/tests/slack-render-v2.test.ts +86 -10
  423. package/src/tests/sonnet-5-5-registry.test.ts +9 -1
  424. package/src/tests/spec-base-url.test.ts +16 -1
  425. package/src/tests/swarm-config-export-to-env.test.ts +267 -0
  426. package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
  427. package/src/tests/swarm-diff.test.ts +1 -1
  428. package/src/tests/task-model-effort-rerun.test.ts +164 -0
  429. package/src/tests/task-session-prompts.test.ts +132 -0
  430. package/src/tests/task-tool-manifest.test.ts +14 -0
  431. package/src/tests/task-tools-ctx.test.ts +2 -0
  432. package/src/tests/tool-annotations.test.ts +6 -6
  433. package/src/tests/ui-logs-parser.test.ts +43 -0
  434. package/src/tests/used-by-route.test.ts +6 -0
  435. package/src/tests/vendored-openapi.test.ts +16 -1
  436. package/src/tests/vercel-ai-gateway.test.ts +149 -0
  437. package/src/tests/workflow-swarm-script.test.ts +38 -0
  438. package/src/tests/workflow-wait-filter.test.ts +5 -3
  439. package/src/tools/chat-access.ts +41 -0
  440. package/src/tools/chat-open-dm.ts +59 -0
  441. package/src/tools/chat-post.ts +74 -0
  442. package/src/tools/chat-read-thread.ts +100 -0
  443. package/src/tools/chat-reply.ts +75 -0
  444. package/src/tools/create-page.ts +3 -13
  445. package/src/tools/defer-task.ts +17 -0
  446. package/src/tools/model-catalog/index.ts +2 -1
  447. package/src/tools/register-chat-channel.ts +139 -0
  448. package/src/tools/send-task.ts +24 -0
  449. package/src/tools/skills/skill-get.ts +17 -9
  450. package/src/tools/slack-post.ts +6 -0
  451. package/src/tools/slack-read.ts +8 -0
  452. package/src/tools/slack-reply.ts +6 -0
  453. package/src/tools/slack-start-thread.ts +6 -0
  454. package/src/tools/slack-update.ts +6 -0
  455. package/src/tools/slack-upload-file.ts +6 -0
  456. package/src/tools/swarm-config/get-config.ts +2 -1
  457. package/src/tools/swarm-config/list-config.ts +2 -1
  458. package/src/tools/swarm-config/set-config.ts +16 -3
  459. package/src/tools/tool-config.ts +8 -6
  460. package/src/types.ts +12 -2
  461. package/src/utils/config-env-export.ts +74 -0
  462. package/src/utils/credentials.test.ts +92 -0
  463. package/src/utils/credentials.ts +52 -4
  464. package/src/utils/harness-provider.ts +15 -6
  465. package/src/utils/node-env.ts +24 -0
  466. package/src/utils/runtime-model-catalog.ts +11 -1
  467. package/src/utils/secret-scrubber.ts +71 -2
  468. package/src/utils/task-tool-manifest.ts +19 -2
  469. package/src/workflows/executors/swarm-script.ts +1 -0
  470. package/templates/skills/agent-browser/SKILL.md +1 -1
  471. package/templates/skills/agent-browser/content.md +1 -1
  472. package/templates/skills/apps/SKILL.md +749 -0
  473. package/templates/skills/apps/content.md +60 -22
  474. package/templates/skills/chat-sdk/config.json +14 -0
  475. package/templates/skills/chat-sdk/content.md +84 -0
  476. package/templates/skills/composio-gmail/content.md +7 -0
  477. package/templates/skills/composio-google-docs/content.md +1 -1
  478. package/templates/skills/email-domain-health/config.json +14 -0
  479. package/templates/skills/email-domain-health/content.md +131 -0
  480. package/templates/skills/kv-storage/content.md +2 -2
  481. package/templates/skills/pages/content.md +8 -10
  482. package/templates/skills/qa-loom/config.json +14 -0
  483. package/templates/skills/qa-loom/content.md +187 -0
  484. package/templates/skills/qa-loom/files/build-loom.mjs +221 -0
  485. package/templates/skills/qa-loom/files/run-qa.sh +57 -0
  486. package/templates/skills/slack-interaction/content.md +4 -0
  487. package/templates/skills/swarm-extensions/content.md +2 -0
  488. package/templates/skills/swarm-scripts/SKILL.md +4 -2
  489. package/templates/skills/swarm-scripts/config.json +1 -1
  490. package/templates/skills/swarm-scripts/content.md +4 -2
  491. package/templates/skills/workflow-iterate/content.md +38 -0
  492. package/dist/artifact-eczsknc3.js +0 -3843
  493. package/dist/cli-9xsmdpdt.js +0 -56377
  494. package/dist/cli-bd957dgb.js +0 -153
  495. package/dist/cli-q51yprfq.js +0 -1104
  496. package/dist/cli-t1ze64h3.js +0 -811
  497. package/dist/index-9ch1n761.js +0 -1102
  498. package/src/artifact-sdk/index.ts +0 -2
  499. package/src/artifact-sdk/localtunnel.d.ts +0 -20
  500. package/src/artifact-sdk/port.ts +0 -12
  501. package/src/artifact-sdk/server.ts +0 -183
  502. package/src/artifact-sdk/tunnel.ts +0 -19
  503. package/src/commands/artifact.ts +0 -249
  504. package/src/http/ecosystem.ts +0 -77
  505. package/src/tests/artifact-commands.test.ts +0 -92
  506. package/src/tests/artifact-sdk.test.ts +0 -793
  507. package/src/tests/register-service-security.test.ts +0 -194
  508. package/src/tools/list-services.ts +0 -107
  509. package/src/tools/register-service.ts +0 -177
  510. package/src/tools/unregister-service.ts +0 -73
  511. package/src/tools/update-service-status.ts +0 -96
  512. package/templates/skills/artifacts/config.json +0 -14
  513. package/templates/skills/artifacts/content.md +0 -344
  514. package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
  515. package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
  516. package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
  517. package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
  518. package/dist/{azure-openai-responses-ap1gwxgr.js → azure-openai-responses-ygfreq4t.js} +5 -5
  519. package/dist/{cli-5rqrj7q0.js → cli-pw7ebjdt.js} +0 -0
  520. package/dist/{openai-codex-responses-33qhkkdy.js → openai-codex-responses-3bk0grnr.js} +4 -4
  521. package/dist/{openai-completions-s88xm3ns.js → openai-completions-5d4jpakc.js} +9 -9
  522. package/dist/{openai-responses-7xd2f2e2.js → openai-responses-krb51f59.js} +5 -5
  523. package/dist/{pi-messages-xszk613n.js → pi-messages-x9gzynm1.js} +3 -3
  524. /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
  525. /package/src/{artifact-sdk → pages}/feedback-overlay.ts +0 -0
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Runs the real runner boot in a child process up to the legacy paused-task
3
+ * resume, and records the prompts the provider receives for that session.
4
+ */
5
+ import { mock } from "bun:test";
6
+ import { writeFileSync } from "node:fs";
7
+ import { join } from "node:path";
8
+ import type { ProviderSessionConfig } from "../../providers/types";
9
+
10
+ const directory = process.argv[2]!;
11
+ const pausedTaskId = "44444444-4444-4444-8444-444444444444";
12
+ const REQUESTER_SENTINEL = "RESUME_REQUESTER_SENTINEL_7f3a";
13
+ const MISSING_DIR = "/nonexistent/legacy-resume-dir-7f3a";
14
+
15
+ const resolver = await import("../../prompts/resolver");
16
+ mock.module("../../prompts/resolver", () => ({
17
+ ...resolver,
18
+ configureHttpResolver() {},
19
+ }));
20
+ const profileSync = await import("../../commands/profile-sync");
21
+ mock.module("../../commands/profile-sync", () => ({
22
+ ...profileSync,
23
+ SOUL_MD_PATH: join(directory, "SOUL.md"),
24
+ IDENTITY_MD_PATH: join(directory, "IDENTITY.md"),
25
+ TOOLS_MD_PATH: join(directory, "TOOLS.md"),
26
+ HEARTBEAT_MD_PATH: join(directory, "HEARTBEAT.md"),
27
+ CLAUDE_MD_PATH: join(directory, "CLAUDE.md"),
28
+ WORKSPACE_CLAUDE_MD_PATH: join(directory, "CLAUDE.md"),
29
+ SETUP_SCRIPT_PATH: join(directory, "start-up.sh"),
30
+ IDENTITY_BASELINES_PATH: join(directory, "baselines.json"),
31
+ async readIdentityBaselines() {
32
+ return {};
33
+ },
34
+ async writeProfileFileFromDb() {
35
+ return null;
36
+ },
37
+ async writeIdentityBaselines() {},
38
+ async syncProfileFilesToServer() {},
39
+ async prependProfileSyncRejectionBanner(prompt: string) {
40
+ return { prompt, injected: false };
41
+ },
42
+ }));
43
+ mock.module("../../utils/skills-refresh", () => ({
44
+ async refreshSkillsIfChanged() {
45
+ return { changed: false };
46
+ },
47
+ }));
48
+ const credentials = await import("../../utils/credentials");
49
+ mock.module("../../utils/credentials", () => ({
50
+ ...credentials,
51
+ async resolveCredentialPools() {
52
+ return [];
53
+ },
54
+ }));
55
+
56
+ mock.module("../../providers/index", () => ({
57
+ async createProviderAdapter() {
58
+ return {
59
+ name: "pi",
60
+ traits: { hasMcp: true, hasLocalEnvironment: true, nativeSkillDiscovery: false },
61
+ formatCommand(name: string, args: string) {
62
+ return `/${name} ${args}`;
63
+ },
64
+ async createSession(config: ProviderSessionConfig) {
65
+ writeFileSync(
66
+ join(directory, "result.json"),
67
+ JSON.stringify({
68
+ taskId: config.taskId,
69
+ prompt: config.prompt,
70
+ systemPrompt: config.systemPrompt,
71
+ }),
72
+ );
73
+ // runAgent runs forever; the first spawn is the resumed task.
74
+ process.exit(0);
75
+ },
76
+ };
77
+ },
78
+ }));
79
+
80
+ // All requests terminate here. The paused-tasks endpoint carries the
81
+ // requester projection the API attaches, as on a task_assigned trigger.
82
+ globalThis.fetch = (async (input: string | URL | Request) => {
83
+ const url = new URL(input instanceof Request ? input.url : input.toString());
84
+ if (url.pathname === "/me") {
85
+ return Response.json({ name: "Fixture agent", soulMd: "Fixture soul" });
86
+ }
87
+ if (url.pathname === "/api/paused-tasks") {
88
+ return Response.json({
89
+ tasks: [
90
+ {
91
+ id: pausedTaskId,
92
+ task: "Resume the paused fixture task",
93
+ status: "paused",
94
+ dir: MISSING_DIR,
95
+ attachments: [],
96
+ requestedBy: {
97
+ id: "user-1",
98
+ name: "Fixture Requester",
99
+ email: "requester@example.com",
100
+ role: "CTO",
101
+ notes: REQUESTER_SENTINEL,
102
+ },
103
+ },
104
+ ],
105
+ });
106
+ }
107
+ if (url.pathname === "/api/poll") return new Promise(() => {});
108
+ if (url.pathname === "/api/config/resolved") return Response.json({ configs: [] });
109
+ if (url.pathname === "/api/agents") return Response.json({ enabledCapabilities: [] });
110
+ if (url.pathname === "/cancelled-tasks") return Response.json({ cancelled: [] });
111
+ if (url.pathname.startsWith("/api/tasks/")) {
112
+ return Response.json({ success: true, task: { id: pausedTaskId, status: "in_progress" } });
113
+ }
114
+ return Response.json({ enabled: false, recovered: 0, memories: [], configs: [] });
115
+ }) as typeof fetch;
116
+
117
+ process.env.MAX_CONCURRENT_TASKS = "1";
118
+ const { runAgent } = await import("../../commands/runner");
119
+ await runAgent(
120
+ { role: "worker", defaultPrompt: "Fixture", metadataType: "worker_metadata" },
121
+ { logsDir: join(directory, "logs"), systemPrompt: "Additional fixture instructions" },
122
+ );
@@ -421,3 +421,38 @@ describe("no github email enrichment", () => {
421
421
  expect(await getKv(UNMAPPED_NAMESPACE, "triage-target:count")).toBeNull();
422
422
  });
423
423
  });
424
+
425
+ // ── Every no-task comment path logs why ──
426
+
427
+ describe("comment skip reasons", () => {
428
+ async function skippedReasons(events: CommentEvent[]): Promise<string[]> {
429
+ const logSpy = spyOn(console, "log").mockImplementation(() => {});
430
+ try {
431
+ for (const event of events) {
432
+ expect((await handleComment(event, "issue_comment")).created).toBe(false);
433
+ }
434
+ return logSpy.mock.calls
435
+ .map((args) => String(args[0]))
436
+ .filter((line) => line.startsWith("[GitHub] Skipped issue_comment."));
437
+ } finally {
438
+ logSpy.mockRestore();
439
+ }
440
+ }
441
+
442
+ test("edited, unmentioned and duplicate comments each log a reason", async () => {
443
+ const mention = `@${GITHUB_BOT_NAME} please review`;
444
+ const edited = { ...makeCommentEvent("skip-edit", mention), action: "edited" };
445
+ edited.comment = { ...edited.comment, id: 7001 };
446
+ const noMention = makeCommentEvent("skip-plain", "no ping here");
447
+ noMention.comment = { ...noMention.comment, id: 7002 };
448
+ const first = makeCommentEvent("skip-dup", mention);
449
+ first.comment = { ...first.comment, id: 7003 };
450
+
451
+ expect((await handleComment(first, "issue_comment")).created).toBe(true);
452
+ expect(await skippedReasons([edited, noMention, first])).toEqual([
453
+ "[GitHub] Skipped issue_comment.edited by skip-edit on test/repo comment 7001: action is not created",
454
+ "[GitHub] Skipped issue_comment.created by skip-plain on test/repo comment 7002: no bot mention",
455
+ "[GitHub] Skipped issue_comment.created by skip-dup on test/repo comment 7003: duplicate delivery",
456
+ ]);
457
+ });
458
+ });
@@ -158,6 +158,18 @@ describe("resolveHarnessProvider", () => {
158
158
  test("keeps 'claude' when no credentials are present at all", () => {
159
159
  expect(resolveHarnessProvider({}, {})).toBe("claude");
160
160
  });
161
+
162
+ test("prefers 'pi' when a NaN or Helmcode key is the only LLM credential", () => {
163
+ expect(resolveHarnessProvider({ NAN_API_KEY: "example-nan" }, {})).toBe("pi");
164
+ expect(resolveHarnessProvider({}, { HELMCODE_API_NAN: "example-nan" })).toBe("pi");
165
+ expect(resolveHarnessProvider({ HELMCODE_API_KEY: "example-helm" }, {})).toBe("pi");
166
+ });
167
+
168
+ test("keeps 'claude' when a NaN key sits next to an Anthropic credential", () => {
169
+ expect(
170
+ resolveHarnessProvider({ NAN_API_KEY: "example-nan", ANTHROPIC_API_KEY: "example-ant" }, {}),
171
+ ).toBe("claude");
172
+ });
161
173
  });
162
174
 
163
175
  // ─── validateConfigValue ─────────────────────────────────────────────────────
@@ -524,7 +524,8 @@ describe("Heartbeat Checklist", () => {
524
524
  buildCredentials: () => {
525
525
  setupStarted.resolve();
526
526
  return new Promise((resolve) => {
527
- releaseSetup = () => resolve({ egressSecrets: [], failedBindings: [] });
527
+ releaseSetup = () =>
528
+ resolve({ egressSecrets: [], failedBindings: [], userConfig: {} });
528
529
  });
529
530
  },
530
531
  });
@@ -561,7 +562,7 @@ describe("Heartbeat Checklist", () => {
561
562
  {
562
563
  buildCredentials: async () => {
563
564
  controller.abort();
564
- return { egressSecrets: [], failedBindings: [] };
565
+ return { egressSecrets: [], failedBindings: [], userConfig: {} };
565
566
  },
566
567
  },
567
568
  );
@@ -24,8 +24,6 @@ test(
24
24
  });
25
25
  await Bun.$`mkdir -p ${tempDir}`.quiet();
26
26
  try {
27
- await Bun.write(`${tempDir}/pm2`, '#!/bin/sh\nif [ "$1" = jlist ]; then printf "[]"; fi\n');
28
- await Bun.$`chmod +x ${tempDir}/pm2`.quiet();
29
27
  await Bun.write(
30
28
  `${tempDir}/.mcp.json`,
31
29
  JSON.stringify({
@@ -1174,13 +1174,6 @@ describe("Stats & Metadata", () => {
1174
1174
  expect(Array.isArray(body.logs)).toBe(true);
1175
1175
  });
1176
1176
 
1177
- test("GET /api/services — returns services list", async () => {
1178
- const { status, body } = await get("/api/services");
1179
- expect(status).toBe(200);
1180
- expect(body.services).toBeDefined();
1181
- expect(Array.isArray(body.services)).toBe(true);
1182
- });
1183
-
1184
1177
  test("GET /api/scheduled-tasks — returns scheduled tasks", async () => {
1185
1178
  const { status, body } = await get("/api/scheduled-tasks");
1186
1179
  expect(status).toBe(200);
@@ -1817,24 +1810,6 @@ describe("Memory", () => {
1817
1810
  });
1818
1811
  });
1819
1812
 
1820
- // ===========================================================================
1821
- // 16. Ecosystem
1822
- // ===========================================================================
1823
-
1824
- describe("Ecosystem", () => {
1825
- test("GET /ecosystem — missing agent ID header returns 400", async () => {
1826
- const { status } = await get("/ecosystem");
1827
- expect(status).toBe(400);
1828
- });
1829
-
1830
- test("GET /ecosystem — returns ecosystem config for agent", async () => {
1831
- const { status, body } = await get("/ecosystem", { agentId: ids.workerAgent });
1832
- expect(status).toBe(200);
1833
- expect(body.apps).toBeDefined();
1834
- expect(Array.isArray(body.apps)).toBe(true);
1835
- });
1836
- });
1837
-
1838
1813
  // ===========================================================================
1839
1814
  // 17. Close Agent (run near end as it changes agent state)
1840
1815
  // ===========================================================================
@@ -224,25 +224,26 @@ describe("migration 046 — budgets and pricing", () => {
224
224
  // Derive expected rates from the vendored snapshot instead of literals —
225
225
  // Anthropic reprices (sonnet-5 intro rate through 2026-08-31), and this
226
226
  // test pins faithful PROJECTION of the snapshot, not a rate freeze.
227
- const cost = loadModelsDevCache()?.anthropic?.models?.["claude-sonnet-5"]?.cost;
228
- expect(cost?.input).toBeGreaterThan(0);
229
- const expectedPrices = {
230
- input: cost?.input,
231
- cached_input: cost?.cache_read,
232
- cache_write: cost?.cache_write,
233
- // Phase 3: Anthropic-billed rows derive the 1h class at 2x base input.
234
- cache_write_1h: (cost?.input ?? 0) * 2,
235
- output: cost?.output,
236
- } as const;
227
+ // The `sonnet` shortname follows the current default, Sonnet 5.5.
237
228
  const seededKeys = [
238
- ["claude", "claude-sonnet-5"],
239
- ["claude-managed", "claude-sonnet-5"],
240
- ["claude", "sonnet"],
241
- ["claude-managed", "sonnet"],
242
- ["pi", "sonnet"],
229
+ ["claude", "claude-sonnet-5", "claude-sonnet-5"],
230
+ ["claude-managed", "claude-sonnet-5", "claude-sonnet-5"],
231
+ ["claude", "sonnet", "claude-sonnet-5-5"],
232
+ ["claude-managed", "sonnet", "claude-sonnet-5-5"],
233
+ ["pi", "sonnet", "claude-sonnet-5-5"],
243
234
  ] as const;
244
235
 
245
- for (const [provider, model] of seededKeys) {
236
+ for (const [provider, model, sourceId] of seededKeys) {
237
+ const cost = loadModelsDevCache()?.anthropic?.models?.[sourceId]?.cost;
238
+ expect(cost?.input).toBeGreaterThan(0);
239
+ const expectedPrices = {
240
+ input: cost?.input,
241
+ cached_input: cost?.cache_read,
242
+ cache_write: cost?.cache_write,
243
+ // Phase 3: Anthropic-billed rows derive the 1h class at 2x base input.
244
+ cache_write_1h: (cost?.input ?? 0) * 2,
245
+ output: cost?.output,
246
+ } as const;
246
247
  for (const [tokenClass, price] of Object.entries(expectedPrices)) {
247
248
  const row = await client.get<PricingRow>(
248
249
  `SELECT * FROM pricing
@@ -0,0 +1,113 @@
1
+ import { Database } from "bun:sqlite";
2
+ import { expect, test } from "bun:test";
3
+
4
+ function setup(): Database {
5
+ const db = new Database(":memory:");
6
+ db.exec(
7
+ `CREATE TABLE agents (
8
+ id TEXT PRIMARY KEY,
9
+ isLead INTEGER NOT NULL DEFAULT 0
10
+ )`,
11
+ );
12
+ db.exec("INSERT INTO agents (id, isLead) VALUES ('lead', 1), ('worker', 0)");
13
+ db.exec(
14
+ `CREATE TABLE agent_tasks (
15
+ id TEXT PRIMARY KEY,
16
+ status TEXT NOT NULL,
17
+ source TEXT NOT NULL,
18
+ taskType TEXT,
19
+ contextKey TEXT,
20
+ agentId TEXT
21
+ )`,
22
+ );
23
+ return db;
24
+ }
25
+
26
+ function obligations(db: Database): string[] {
27
+ return db
28
+ .query<{ task_id: string }, []>("SELECT task_id FROM chat_relay_obligations ORDER BY task_id")
29
+ .all()
30
+ .map((row) => row.task_id);
31
+ }
32
+
33
+ test("migration 217 creates the chat state tables and the pending index", async () => {
34
+ const db = setup();
35
+ try {
36
+ db.exec(await Bun.file("src/be/migrations/217_chat_sdk_state.sql").text());
37
+ const tables = db
38
+ .query<{ name: string }, []>("SELECT name FROM sqlite_master WHERE type = 'table'")
39
+ .all()
40
+ .map((row) => row.name);
41
+ for (const table of [
42
+ "chat_state_kv",
43
+ "chat_subscriptions",
44
+ "chat_locks",
45
+ "chat_lists",
46
+ "chat_queue",
47
+ "chat_relay_obligations",
48
+ ]) {
49
+ expect(tables).toContain(table);
50
+ }
51
+ const pendingIndex = db
52
+ .query<{ sql: string }, []>(
53
+ "SELECT sql FROM sqlite_master WHERE name = 'idx_chat_relay_obligations_pending'",
54
+ )
55
+ .get();
56
+ expect(pendingIndex?.sql).toContain("WHERE delivered_at IS NULL AND given_up_at IS NULL");
57
+ expect(
58
+ db
59
+ .query<{ name: string }, []>("PRAGMA index_list(chat_queue)")
60
+ .all()
61
+ .map((index) => index.name),
62
+ ).toContain("idx_chat_queue_thread");
63
+ expect(db.query("PRAGMA integrity_check").get()).toEqual({ integrity_check: "ok" });
64
+ } finally {
65
+ db.close();
66
+ }
67
+ });
68
+
69
+ test("migration 217 triggers enqueue a relay obligation only for chat-rooted terminal tasks", async () => {
70
+ const db = setup();
71
+ try {
72
+ db.exec(await Bun.file("src/be/migrations/217_chat_sdk_state.sql").text());
73
+ const insert = db.prepare(
74
+ "INSERT INTO agent_tasks (id, status, source, taskType, contextKey, agentId) VALUES (?, ?, ?, ?, ?, ?)",
75
+ );
76
+ const key = "task:chat-sdk:telegram:555";
77
+ insert.run("chat", "in_progress", "chat", "chat-inbound", key, "lead");
78
+ insert.run("slack", "in_progress", "slack", null, "task:slack:C1:1.2", "lead");
79
+ insert.run("followup", "in_progress", "system", "follow-up", key, "lead");
80
+ insert.run("resume-lead", "in_progress", "system", "resume", key, "lead");
81
+ insert.run("resume-worker", "in_progress", "system", "resume", key, "worker");
82
+ insert.run("resume-unassigned", "in_progress", "system", "resume", key, null);
83
+ insert.run("delegated", "in_progress", "system", "delegated", key, "worker");
84
+ insert.run("upper", "in_progress", "chat", null, "TASK:CHAT-SDK:telegram:555", "lead");
85
+ insert.run("done-at-insert", "completed", "chat", null, "task:chat-sdk:telegram:777", "lead");
86
+ insert.run("resume-at-insert", "completed", "system", "resume", key, "lead");
87
+
88
+ for (const id of [
89
+ "chat",
90
+ "slack",
91
+ "followup",
92
+ "resume-lead",
93
+ "resume-worker",
94
+ "resume-unassigned",
95
+ "delegated",
96
+ "upper",
97
+ ]) {
98
+ db.run("UPDATE agent_tasks SET status = 'completed' WHERE id = ?", [id]);
99
+ }
100
+ // A second terminal transition must not add a second row.
101
+ db.run("UPDATE agent_tasks SET status = 'failed' WHERE id = 'chat'");
102
+
103
+ expect(obligations(db)).toEqual([
104
+ "chat",
105
+ "done-at-insert",
106
+ "followup",
107
+ "resume-at-insert",
108
+ "resume-lead",
109
+ ]);
110
+ } finally {
111
+ db.close();
112
+ }
113
+ });
@@ -267,6 +267,99 @@ describe("claim-time resolution via /api/poll", () => {
267
267
  });
268
268
  });
269
269
 
270
+ // A row that already ran carries that run's model: the session report wrote it
271
+ // into `model`, and the claim wrote `resolvedModel`/`modelSource`. Re-claiming
272
+ // it must resolve from the config in force NOW, not replay the previous run.
273
+ describe("re-claim after a previous run", () => {
274
+ async function markRan(
275
+ taskId: string,
276
+ fields: { model: string; resolvedModel?: string; modelSource?: string },
277
+ ): Promise<void> {
278
+ await getDbClient().run(
279
+ `UPDATE agent_tasks SET model = ?, resolvedModel = ?, modelSource = ?,
280
+ claudeSessionId = 'previous-session', status = 'pending' WHERE id = ?`,
281
+ [fields.model, fields.resolvedModel ?? null, fields.modelSource ?? null, taskId],
282
+ );
283
+ }
284
+
285
+ test("an unpinned task drops the previous run's model, so the agent's current config applies", async () => {
286
+ const worker = await createAgent({
287
+ name: "rerun-unpinned",
288
+ isLead: false,
289
+ status: "idle",
290
+ maxTasks: 1,
291
+ harnessProvider: "claude",
292
+ });
293
+ const task = await createTaskExtended("plain work", { agentId: worker.id });
294
+ // First run: no pin, MODEL_OVERRIDE was opus, the session reported it.
295
+ await markRan(task.id, { model: "claude-opus-5-5" });
296
+
297
+ const trigger = await callPoll(worker.id);
298
+
299
+ expect(trigger?.type).toBe("task_assigned");
300
+ // No `model` in the trigger: the worker falls through to MODEL_OVERRIDE.
301
+ expect(trigger?.task.model).toBeUndefined();
302
+ expect(trigger?.task.resolvedModel).toBeUndefined();
303
+ expect(await taskRow(task.id)).toEqual({
304
+ resolvedModel: null,
305
+ modelSource: null,
306
+ modelAlias: null,
307
+ });
308
+ });
309
+
310
+ test("a tier task re-resolves the tier after the tier config changed", async () => {
311
+ const worker = await createAgent({
312
+ name: "rerun-tier",
313
+ isLead: false,
314
+ status: "idle",
315
+ maxTasks: 1,
316
+ harnessProvider: "claude",
317
+ });
318
+ const task = await createTaskExtended("smart work", { agentId: worker.id, modelTier: "smart" });
319
+ await markRan(task.id, {
320
+ model: "claude-opus-5-5",
321
+ resolvedModel: "claude-opus-5-5",
322
+ modelSource: "tier-config",
323
+ });
324
+ process.env.MODEL_TIER_CLAUDE_SMART = "claude-sonnet-5-5";
325
+
326
+ const trigger = await callPoll(worker.id, header({}));
327
+
328
+ expect(trigger?.task.model).toBeUndefined();
329
+ expect(trigger?.task.resolvedModel).toBe("claude-sonnet-5-5");
330
+ expect(await taskRow(task.id)).toEqual({
331
+ resolvedModel: "claude-sonnet-5-5",
332
+ modelSource: "tier-config",
333
+ modelAlias: null,
334
+ });
335
+ });
336
+
337
+ test("a task-pinned model stays pinned on re-claim", async () => {
338
+ const worker = await createAgent({
339
+ name: "rerun-pinned",
340
+ isLead: false,
341
+ status: "idle",
342
+ maxTasks: 1,
343
+ harnessProvider: "claude",
344
+ });
345
+ const task = await createTaskExtended("pinned work", {
346
+ agentId: worker.id,
347
+ model: "claude-sonnet-5-5",
348
+ });
349
+ await markRan(task.id, {
350
+ model: "claude-sonnet-5-5",
351
+ resolvedModel: "claude-sonnet-5-5",
352
+ modelSource: "model",
353
+ });
354
+
355
+ const trigger = await callPoll(worker.id);
356
+
357
+ expect(trigger?.task.model).toBe("claude-sonnet-5-5");
358
+ expect(trigger?.task.resolvedModel).toBe("claude-sonnet-5-5");
359
+ expect((await taskRow(task.id))?.modelSource).toBe("model");
360
+ });
361
+ });
362
+
270
363
  describe("claim-time harness guard", () => {
271
364
  test("a directed task pinning an Anthropic model on a Codex worker fails fast with a tagged reason", async () => {
272
365
  const worker = await createAgent({
@@ -11,14 +11,17 @@
11
11
  */
12
12
 
13
13
  import { afterEach, describe, expect, test } from "bun:test";
14
+ import { reasoningLevelsForModel } from "@desplega/model-catalog";
14
15
  import {
15
16
  buildModelsCatalog,
17
+ type CatalogProviderId,
16
18
  getModelsCatalog,
17
19
  PINNED_MODELSDEV_ENTRIES,
18
20
  resetModelsCatalogForTests,
19
21
  updateLiveModelsCatalog,
20
22
  } from "../be/models-catalog";
21
23
  import type { ModelsDevCache } from "../be/modelsdev-cache";
24
+ import { getContextWindowSize } from "../utils/context-window";
22
25
 
23
26
  afterEach(() => {
24
27
  resetModelsCatalogForTests();
@@ -82,6 +85,14 @@ describe("getModelsCatalog", () => {
82
85
  expect(Object.keys(result.providers.openrouter?.models ?? {}).length).toBeGreaterThan(0);
83
86
  expect(Object.keys(result.providers.anthropic?.models ?? {}).length).toBeGreaterThan(0);
84
87
  expect(Object.keys(result.providers.opencode?.models ?? {}).length).toBeGreaterThan(0);
88
+ expect(result.providers.nan?.models["glm5.3-flash"]).toBeDefined();
89
+ expect(Object.keys(result.providers.helmcode?.models ?? {}).sort()).toEqual([
90
+ "deepseek-v4-flash",
91
+ "gemma4",
92
+ "glm5.3",
93
+ "glm5.3-flash",
94
+ "qwen3.6",
95
+ ]);
85
96
  });
86
97
 
87
98
  test("prefers live data after an update", () => {
@@ -99,7 +110,7 @@ describe("getModelsCatalog", () => {
99
110
  const result = getModelsCatalog();
100
111
  for (const entryPath of PINNED_MODELSDEV_ENTRIES) {
101
112
  const slashIndex = entryPath.indexOf("/");
102
- const providerId = entryPath.slice(0, slashIndex) as "anthropic" | "amazon-bedrock";
113
+ const providerId = entryPath.slice(0, slashIndex) as CatalogProviderId;
103
114
  const modelId = entryPath.slice(slashIndex + 1);
104
115
  expect(result.providers[providerId]?.models[modelId]).toBeDefined();
105
116
  }
@@ -118,3 +129,33 @@ describe("getModelsCatalog", () => {
118
129
  expect(result.providers.anthropic?.models["claude-mythos-5"]?.name).toBe("Live Mythos");
119
130
  });
120
131
  });
132
+
133
+ describe("nan and helmcode sections", () => {
134
+ test("the registry-synthesized helmcode section survives a live payload that lacks it", () => {
135
+ // LIVE_CACHE has no helmcode provider: the registry section is refilled.
136
+ updateLiveModelsCatalog(LIVE_CACHE);
137
+ const helmcode = getModelsCatalog().providers.helmcode;
138
+ expect(helmcode?.id).toBe("helmcode");
139
+ expect(helmcode?.name).toBe("Helmcode");
140
+ expect(helmcode?.models["glm5.3"]?.limit?.context).toBe(1_048_576);
141
+ expect(helmcode?.models["qwen3.6"]?.limit?.context).toBe(262_144);
142
+ });
143
+
144
+ test("reasoning levels resolve for helmcode and nan ids on pi and opencode", () => {
145
+ const catalog = getModelsCatalog().providers;
146
+ for (const harness of ["pi", "opencode"]) {
147
+ expect(
148
+ reasoningLevelsForModel(harness, "helmcode/glm5.3-flash", catalog).length,
149
+ ).toBeGreaterThan(0);
150
+ expect(reasoningLevelsForModel(harness, "nan/glm5.3-flash", catalog).length).toBeGreaterThan(
151
+ 0,
152
+ );
153
+ }
154
+ });
155
+
156
+ test("context windows come from the catalog sections", () => {
157
+ expect(getContextWindowSize("helmcode/glm5.3")).toBe(1_048_576);
158
+ expect(getContextWindowSize("helmcode/gemma4")).toBe(262_144);
159
+ expect(getContextWindowSize("nan/qwen3.6")).toBe(262_144);
160
+ });
161
+ });