@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
@@ -1,5 +1,10 @@
1
1
  import { afterAll, beforeEach, describe, expect, test } from "bun:test";
2
- import { type BasePromptArgs, getBasePrompt, truncateRepoClaudeMd } from "../prompts/base-prompt";
2
+ import {
3
+ type BasePromptArgs,
4
+ getBasePrompt,
5
+ getTaskContextPrompt,
6
+ truncateRepoClaudeMd,
7
+ } from "../prompts/base-prompt";
3
8
  import { generateDefaultClaudeMd, generateDefaultIdentityMd } from "../prompts/defaults";
4
9
  import type { ProviderTraits } from "../providers/types";
5
10
 
@@ -377,7 +382,7 @@ describe("getBasePrompt: persona injection", () => {
377
382
  });
378
383
 
379
384
  // ---------------------------------------------------------------------------
380
- // 4. Agent notes (CLAUDE.md): codex, opencode, pi only, only when edited
385
+ // 4. Agent notes (CLAUDE.md): local providers, only when edited
381
386
  // ---------------------------------------------------------------------------
382
387
 
383
388
  describe("getBasePrompt: agent notes section", () => {
@@ -385,18 +390,9 @@ describe("getBasePrompt: agent notes section", () => {
385
390
  const EDITED = "# Agent: Ada\n\nAlways run `bun run tsc:check` before you push.";
386
391
  const notesAgent = { name: "Ada", role: "worker" };
387
392
 
388
- test("claude never gets the section, even when the notes are edited", async () => {
389
- const result = await getBasePrompt({
390
- ...minimalArgs,
391
- name: "Ada",
392
- provider: "claude",
393
- claudeMd: EDITED,
394
- });
395
- expect(result).not.toContain(NOTES_HEADER);
396
- expect(result).not.toContain("Always run `bun run tsc:check` before you push.");
397
- });
398
-
399
- for (const provider of ["codex", "opencode", "pi"] as const) {
393
+ // Claude excludes ~/.claude/CLAUDE.md from its memory load
394
+ // (claude-flag-settings.ts), so the system prompt is its only copy.
395
+ for (const provider of ["claude", "codex", "opencode", "pi"] as const) {
400
396
  test(`${provider} gets the section when the notes are edited`, async () => {
401
397
  const result = await getBasePrompt({
402
398
  ...minimalArgs,
@@ -409,6 +405,17 @@ describe("getBasePrompt: agent notes section", () => {
409
405
  });
410
406
  }
411
407
 
408
+ test("claude truncates notes over 20k characters and points at its own file", async () => {
409
+ const result = await getBasePrompt({
410
+ ...minimalArgs,
411
+ name: "Ada",
412
+ provider: "claude",
413
+ claudeMd: "x".repeat(25_000),
414
+ });
415
+ expect(result).toContain("[...truncated, see ~/.claude/CLAUDE.md for full content]");
416
+ expect(result).not.toContain("x".repeat(20_000));
417
+ });
418
+
412
419
  test("codex skips notes that equal the generated default", async () => {
413
420
  const result = await getBasePrompt({
414
421
  ...minimalArgs,
@@ -598,11 +605,15 @@ describe("getBasePrompt: slack section", () => {
598
605
 
599
606
  test("a scripts-only worker with a Slack task gets the scripts-only variant only", async () => {
600
607
  enableSlack();
601
- const result = await getBasePrompt({
608
+ const system = await getBasePrompt({ ...minimalArgs, scriptsOnly: true });
609
+ const result = await getTaskContextPrompt({
602
610
  ...minimalArgs,
603
611
  scriptsOnly: true,
604
612
  slackContext: { channelId: "C0SAMPLE", threadTs: "123.456" },
605
613
  });
614
+ // The channel id is per task, so the note rides in the task prompt.
615
+ expect(system).not.toContain(SCRIPTS_ONLY_SLACK_HEADER);
616
+ expect(system).not.toContain(SLACK_HEADER);
606
617
  expect(result).toContain(SCRIPTS_ONLY_SLACK_HEADER);
607
618
  expect(result).toContain("C0SAMPLE");
608
619
  expect(result).not.toContain(SLACK_HEADER);
@@ -610,7 +621,7 @@ describe("getBasePrompt: slack section", () => {
610
621
 
611
622
  test("a scripts-only lead with a Slack task gets neither variant", async () => {
612
623
  enableSlack();
613
- const result = await getBasePrompt({
624
+ const result = await getTaskContextPrompt({
614
625
  ...minimalArgs,
615
626
  role: "lead",
616
627
  scriptsOnly: true,
@@ -786,14 +797,14 @@ describe("getBasePrompt: tools and skills section", () => {
786
797
  // 10. Repository
787
798
  // ---------------------------------------------------------------------------
788
799
 
789
- describe("getBasePrompt: repository section", () => {
800
+ describe("getTaskContextPrompt: repository section", () => {
790
801
  const CLONE_PATH = "/workspace/repos/my-repo";
791
802
  const CLONE_SENTENCE = "This task's repository is cloned locally. `get-repos` returns the path.";
792
803
  const CODE_QUALITY_LINE =
793
804
  "You MUST use the `code-quality` skill before you push, open a PR, or review one.";
794
805
 
795
806
  test("a local claude worker gets the clone sentence and no clone path literal", async () => {
796
- const result = await getBasePrompt({
807
+ const result = await getTaskContextPrompt({
797
808
  ...minimalArgs,
798
809
  traits: localTraits,
799
810
  repoContext: { claudeMd: "Repo rules here.", clonePath: CLONE_PATH },
@@ -804,7 +815,7 @@ describe("getBasePrompt: repository section", () => {
804
815
  });
805
816
 
806
817
  test("claude does not get the repo CLAUDE.md inlined", async () => {
807
- const result = await getBasePrompt({
818
+ const result = await getTaskContextPrompt({
808
819
  ...minimalArgs,
809
820
  provider: "claude",
810
821
  traits: localTraits,
@@ -814,7 +825,7 @@ describe("getBasePrompt: repository section", () => {
814
825
  });
815
826
 
816
827
  test("opencode inlines the repo CLAUDE.md with the clone path", async () => {
817
- const result = await getBasePrompt({
828
+ const result = await getTaskContextPrompt({
818
829
  ...minimalArgs,
819
830
  provider: "opencode",
820
831
  traits: localTraits,
@@ -826,7 +837,7 @@ describe("getBasePrompt: repository section", () => {
826
837
 
827
838
  test("opencode truncates a repo CLAUDE.md over 12k with an on-disk pointer", async () => {
828
839
  const huge = "x".repeat(30_000);
829
- const result = await getBasePrompt({
840
+ const result = await getTaskContextPrompt({
830
841
  ...minimalArgs,
831
842
  provider: "opencode",
832
843
  traits: localTraits,
@@ -838,7 +849,7 @@ describe("getBasePrompt: repository section", () => {
838
849
 
839
850
  test("opencode keeps a repo CLAUDE.md under the cap verbatim", async () => {
840
851
  const small = "y".repeat(5_000);
841
- const result = await getBasePrompt({
852
+ const result = await getTaskContextPrompt({
842
853
  ...minimalArgs,
843
854
  provider: "opencode",
844
855
  traits: localTraits,
@@ -849,7 +860,7 @@ describe("getBasePrompt: repository section", () => {
849
860
  });
850
861
 
851
862
  test("shows the repo warning when one is set", async () => {
852
- const result = await getBasePrompt({
863
+ const result = await getTaskContextPrompt({
853
864
  ...minimalArgs,
854
865
  repoContext: { clonePath: CLONE_PATH, warning: "Repo is stale" },
855
866
  });
@@ -857,7 +868,7 @@ describe("getBasePrompt: repository section", () => {
857
868
  });
858
869
 
859
870
  test("surfaces auto-stashed work when entries exist", async () => {
860
- const result = await getBasePrompt({
871
+ const result = await getTaskContextPrompt({
861
872
  ...minimalArgs,
862
873
  traits: localTraits,
863
874
  repoContext: {
@@ -871,7 +882,7 @@ describe("getBasePrompt: repository section", () => {
871
882
  });
872
883
 
873
884
  test("says nothing about stashes when the list is empty", async () => {
874
- const result = await getBasePrompt({
885
+ const result = await getTaskContextPrompt({
875
886
  ...minimalArgs,
876
887
  traits: localTraits,
877
888
  repoContext: { clonePath: CLONE_PATH, autoStashes: [] },
@@ -880,7 +891,7 @@ describe("getBasePrompt: repository section", () => {
880
891
  });
881
892
 
882
893
  test("null guidelines tell the agent to ask the lead", async () => {
883
- const result = await getBasePrompt({
894
+ const result = await getTaskContextPrompt({
884
895
  ...minimalArgs,
885
896
  repoContext: { clonePath: CLONE_PATH, guidelines: null },
886
897
  });
@@ -889,7 +900,7 @@ describe("getBasePrompt: repository section", () => {
889
900
  });
890
901
 
891
902
  test("full guidelines render PR checks, merge policy, and review guidance", async () => {
892
- const result = await getBasePrompt({
903
+ const result = await getTaskContextPrompt({
893
904
  ...minimalArgs,
894
905
  repoContext: {
895
906
  clonePath: CLONE_PATH,
@@ -911,7 +922,7 @@ describe("getBasePrompt: repository section", () => {
911
922
  });
912
923
 
913
924
  test("all-empty guidelines render no guidelines block", async () => {
914
- const result = await getBasePrompt({
925
+ const result = await getTaskContextPrompt({
915
926
  ...minimalArgs,
916
927
  repoContext: {
917
928
  clonePath: CLONE_PATH,
@@ -923,7 +934,7 @@ describe("getBasePrompt: repository section", () => {
923
934
  });
924
935
 
925
936
  test("allowMerge true renders the merge policy even with empty arrays", async () => {
926
- const result = await getBasePrompt({
937
+ const result = await getTaskContextPrompt({
927
938
  ...minimalArgs,
928
939
  repoContext: {
929
940
  clonePath: CLONE_PATH,
@@ -935,7 +946,7 @@ describe("getBasePrompt: repository section", () => {
935
946
  });
936
947
 
937
948
  test("a remote worker keeps the guidelines but loses the clone sentence", async () => {
938
- const result = await getBasePrompt({
949
+ const result = await getTaskContextPrompt({
939
950
  ...minimalArgs,
940
951
  provider: "devin",
941
952
  traits: remoteTraits,
@@ -957,7 +968,7 @@ describe("getBasePrompt: repository section", () => {
957
968
  });
958
969
 
959
970
  test("the code-quality pointer is present with MCP", async () => {
960
- const result = await getBasePrompt({
971
+ const result = await getTaskContextPrompt({
961
972
  ...minimalArgs,
962
973
  traits: localTraits,
963
974
  repoContext: { clonePath: CLONE_PATH },
@@ -966,7 +977,7 @@ describe("getBasePrompt: repository section", () => {
966
977
  });
967
978
 
968
979
  test("the code-quality pointer is absent for a remote worker", async () => {
969
- const result = await getBasePrompt({
980
+ const result = await getTaskContextPrompt({
970
981
  ...minimalArgs,
971
982
  traits: remoteTraits,
972
983
  repoContext: { clonePath: CLONE_PATH },
@@ -1033,18 +1044,6 @@ describe("getBasePrompt: size budget", () => {
1033
1044
  claudeMd: big(40_000),
1034
1045
  skillsSummary: [{ name: "commit", description: "Create a commit" }],
1035
1046
  mcpServers: ["linear"],
1036
- slackContext: { channelId: "C0SAMPLE" },
1037
- repoContext: {
1038
- claudeMd: big(60_000),
1039
- clonePath: "/workspace/repos/big-repo",
1040
- warning: "Repo is stale",
1041
- guidelines: {
1042
- prChecks: ["bun run lint"],
1043
- mergeChecks: ["CI green"],
1044
- allowMerge: true,
1045
- review: ["Read the runbook"],
1046
- },
1047
- },
1048
1047
  });
1049
1048
  expect(result.length).toBeLessThan(120_000);
1050
1049
  });
@@ -1070,7 +1069,7 @@ describe("getBasePrompt: output hygiene", () => {
1070
1069
  args: { ...minimalArgs, name: "Ada", traits: remoteTraits, provider: "devin" },
1071
1070
  },
1072
1071
  {
1073
- label: "codex worker with skills and a repo",
1072
+ label: "codex worker with skills",
1074
1073
  args: {
1075
1074
  ...minimalArgs,
1076
1075
  name: "Ada",
@@ -1078,20 +1077,25 @@ describe("getBasePrompt: output hygiene", () => {
1078
1077
  traits: { ...localTraits, nativeSkillDiscovery: false, steerModes: ["queue"] },
1079
1078
  skillsSummary: [{ name: "commit", description: "Create a commit" }],
1080
1079
  mcpServers: ["linear"],
1081
- repoContext: {
1082
- clonePath: "/workspace/repos/my-repo",
1083
- guidelines: {
1084
- prChecks: ["bun run lint"],
1085
- mergeChecks: [],
1086
- allowMerge: false,
1087
- review: [],
1088
- },
1089
- },
1090
1080
  },
1091
1081
  },
1092
1082
  { label: "scripts-only worker", args: { ...minimalArgs, name: "Ada", scriptsOnly: true } },
1093
1083
  ];
1094
1084
 
1085
+ test("the task context renders no em dash and no triple newline", async () => {
1086
+ const result = await getTaskContextPrompt({
1087
+ ...minimalArgs,
1088
+ provider: "codex",
1089
+ traits: localTraits,
1090
+ repoContext: {
1091
+ clonePath: "/workspace/repos/my-repo",
1092
+ guidelines: { prChecks: ["bun run lint"], mergeChecks: [], allowMerge: false, review: [] },
1093
+ },
1094
+ });
1095
+ expect(result).not.toContain(EM_DASH);
1096
+ expect(result).not.toMatch(/\n{3,}/);
1097
+ });
1098
+
1095
1099
  for (const variant of hygieneVariants) {
1096
1100
  test(`${variant.label} renders no em dash`, async () => {
1097
1101
  const result = await getBasePrompt(variant.args);
@@ -0,0 +1,191 @@
1
+ import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
+ import { unlink } from "node:fs/promises";
3
+ import { closeDb, createAgent, getDbClient, getTaskById, initDb } from "../be/db";
4
+ import { CHAT_COMMANDS } from "../integrations/chat-sdk/commands";
5
+ import { startChatSdk, stopChatSdk } from "../integrations/chat-sdk/runtime";
6
+ import { readPersistedThreadHistory } from "../integrations/chat-sdk/state";
7
+ import { chatSdkContextKey } from "../tasks/context-key";
8
+ import {
9
+ flushChatBuffers,
10
+ postTelegramUpdate,
11
+ startTelegramHarness,
12
+ type TelegramChat,
13
+ type TelegramHarness,
14
+ telegramUpdate,
15
+ } from "./chat-sdk-harness";
16
+
17
+ const TEST_DB_PATH = "./test-chat-sdk-commands.sqlite";
18
+
19
+ let harness: TelegramHarness;
20
+
21
+ type TaskRow = { id: string; task: string; status: string; parentTaskId: string | null };
22
+
23
+ async function chatTasks(chatId: number): Promise<TaskRow[]> {
24
+ return getDbClient().query<TaskRow>(
25
+ `SELECT id, task, status, parentTaskId FROM agent_tasks
26
+ WHERE source = 'chat' AND contextKey = ? ORDER BY createdAt, rowid`,
27
+ [chatSdkContextKey(`telegram:${chatId}`)],
28
+ );
29
+ }
30
+
31
+ async function removeDbFiles(): Promise<void> {
32
+ for (const suffix of ["", "-wal", "-shm"]) {
33
+ await unlink(`${TEST_DB_PATH}${suffix}`).catch(() => {});
34
+ }
35
+ }
36
+
37
+ const dm = (id: number): TelegramChat => ({ id, type: "private" });
38
+
39
+ /** A `/command` update: Telegram marks the command with a `bot_command` entity at offset 0. */
40
+ function commandUpdate(chat: TelegramChat, command: string): Record<string, unknown> {
41
+ return telegramUpdate(chat, command, {
42
+ entities: [{ type: "bot_command", offset: 0, length: command.length }],
43
+ });
44
+ }
45
+
46
+ /** Text of every message the bot sent to `chatId`, in order. */
47
+ function sentTexts(chatId: number): string[] {
48
+ return harness.mock.calls
49
+ .filter((call) => /^send(Rich)?Message$/.test(call.method))
50
+ .filter((call) => String(call.body.chat_id) === String(chatId))
51
+ .map((call) => {
52
+ const rich = call.body.rich_message as { markdown?: string } | undefined;
53
+ return String(call.body.text ?? rich?.markdown ?? "");
54
+ });
55
+ }
56
+
57
+ beforeAll(async () => {
58
+ await removeDbFiles();
59
+ initDb(TEST_DB_PATH);
60
+ await createAgent({ id: crypto.randomUUID(), name: "CmdLead", isLead: true, status: "idle" });
61
+ harness = await startTelegramHarness();
62
+ });
63
+
64
+ afterAll(async () => {
65
+ await harness.stop();
66
+ closeDb();
67
+ await removeDbFiles();
68
+ });
69
+
70
+ describe("Chat SDK slash commands", () => {
71
+ test("the command list is published to Telegram at adapter start", () => {
72
+ const call = harness.mock.calls.find((c) => c.method === "setMyCommands");
73
+ expect(call).toBeDefined();
74
+ const names = (call!.body.commands as { command: string }[]).map((c) => c.command);
75
+ expect(names).toEqual(CHAT_COMMANDS.map((c) => c.command));
76
+ });
77
+
78
+ test("/help answers with the list and creates no task", async () => {
79
+ await postTelegramUpdate(commandUpdate(dm(3001), "/help"));
80
+ const texts = sentTexts(3001);
81
+ expect(texts).toHaveLength(1);
82
+ for (const spec of CHAT_COMMANDS) expect(texts[0]).toContain(`/${spec.command}`);
83
+ await flushChatBuffers();
84
+ expect(await chatTasks(3001)).toHaveLength(0);
85
+ });
86
+
87
+ test("an unknown command gets the list instead of silence", async () => {
88
+ await postTelegramUpdate(commandUpdate(dm(3002), "/deploy"));
89
+ const texts = sentTexts(3002);
90
+ expect(texts).toHaveLength(1);
91
+ expect(texts[0]).toContain("Unknown command /deploy");
92
+ expect(texts[0]).toContain("/help");
93
+ await flushChatBuffers();
94
+ expect(await chatTasks(3002)).toHaveLength(0);
95
+ });
96
+
97
+ test("/status reports the latest task and /cancel cancels the active one", async () => {
98
+ await postTelegramUpdate(commandUpdate(dm(3003), "/status"));
99
+ expect(sentTexts(3003).at(-1)).toContain("No task yet");
100
+
101
+ await postTelegramUpdate(telegramUpdate(dm(3003), "please look into the build"));
102
+ await flushChatBuffers();
103
+ const [task] = await chatTasks(3003);
104
+ expect(task).toBeDefined();
105
+ expect(task!.status).toBe("pending");
106
+
107
+ await postTelegramUpdate(commandUpdate(dm(3003), "/status"));
108
+ const status = sentTexts(3003).at(-1)!;
109
+ expect(status).toContain(task!.id.slice(0, 8));
110
+ expect(status).toContain("pending");
111
+ expect(status).toContain("/cancel");
112
+
113
+ await postTelegramUpdate(commandUpdate(dm(3003), "/cancel"));
114
+ expect(sentTexts(3003).at(-1)).toContain(`Cancelled task ${task!.id.slice(0, 8)}`);
115
+ const cancelled = await getTaskById(task!.id);
116
+ expect(cancelled?.status).toBe("cancelled");
117
+ expect(cancelled?.failureReason).toContain("Cancelled from chat by tester");
118
+
119
+ await postTelegramUpdate(commandUpdate(dm(3003), "/cancel"));
120
+ expect(sentTexts(3003).at(-1)).toContain("No running task");
121
+ });
122
+
123
+ test("/reset starts a new conversation: no parent task and no older context", async () => {
124
+ await postTelegramUpdate(telegramUpdate(dm(3004), "the first request"));
125
+ await flushChatBuffers();
126
+ await postTelegramUpdate(telegramUpdate(dm(3004), "a follow-up"));
127
+ await flushChatBuffers();
128
+ let tasks = await chatTasks(3004);
129
+ expect(tasks).toHaveLength(2);
130
+ expect(tasks[1]!.parentTaskId).toBe(tasks[0]!.id);
131
+ expect(tasks[1]!.task).toContain("<thread_context>");
132
+ expect(tasks[1]!.task).toContain("the first request");
133
+
134
+ // Reset while a task still runs: the mark is set, and the reply says so.
135
+ await postTelegramUpdate(commandUpdate(dm(3004), "/reset"));
136
+ expect(sentTexts(3004).at(-1)).toContain("Context reset");
137
+ expect(sentTexts(3004).at(-1)).toContain("still running");
138
+
139
+ // The usual case: the thread's tasks are done when the user resets.
140
+ await getDbClient().run("UPDATE agent_tasks SET status = 'completed' WHERE contextKey = ?", [
141
+ chatSdkContextKey("telegram:3004"),
142
+ ]);
143
+ await postTelegramUpdate(commandUpdate(dm(3004), "/reset"));
144
+ expect(sentTexts(3004).at(-1)).not.toContain("still running");
145
+ // The reset mark is compared to message timestamps with second precision.
146
+ await Bun.sleep(1_100);
147
+
148
+ await postTelegramUpdate(telegramUpdate(dm(3004), "a brand new topic"));
149
+ await flushChatBuffers();
150
+ tasks = await chatTasks(3004);
151
+ expect(tasks).toHaveLength(3);
152
+ expect(tasks[2]!.parentTaskId).toBeNull();
153
+ expect(tasks[2]!.task).not.toContain("<thread_context>");
154
+ expect(tasks[2]!.task).not.toContain("the first request");
155
+
156
+ await postTelegramUpdate(telegramUpdate(dm(3004), "more on the new topic"));
157
+ await flushChatBuffers();
158
+ tasks = await chatTasks(3004);
159
+ expect(tasks).toHaveLength(4);
160
+ expect(tasks[3]!.parentTaskId).toBe(tasks[2]!.id);
161
+ expect(tasks[3]!.task).toContain("a brand new topic");
162
+ expect(tasks[3]!.task).not.toContain("the first request");
163
+ expect(tasks[3]!.task).not.toContain("a follow-up");
164
+ });
165
+ });
166
+
167
+ describe("Chat SDK thread context across an adapter restart", () => {
168
+ test("the SDK persists Telegram history under the pinned key prefix", async () => {
169
+ await postTelegramUpdate(telegramUpdate(dm(3005), "remember this one"));
170
+ await flushChatBuffers();
171
+ const history = await readPersistedThreadHistory("telegram:3005");
172
+ expect(history.map((m) => m.text)).toContain("remember this one");
173
+ });
174
+
175
+ test("a message after a restart still carries the earlier thread messages", async () => {
176
+ await postTelegramUpdate(telegramUpdate(dm(3006), "before the restart"));
177
+ await flushChatBuffers();
178
+
179
+ // Same as a config reload or an API restart: the adapter's memory is gone.
180
+ await stopChatSdk();
181
+ await startChatSdk();
182
+
183
+ await postTelegramUpdate(telegramUpdate(dm(3006), "after the restart"));
184
+ await flushChatBuffers();
185
+ const tasks = await chatTasks(3006);
186
+ expect(tasks).toHaveLength(2);
187
+ expect(tasks[1]!.parentTaskId).toBe(tasks[0]!.id);
188
+ expect(tasks[1]!.task).toContain("<thread_context>");
189
+ expect(tasks[1]!.task).toContain("before the restart");
190
+ });
191
+ });