@desplega.ai/agent-swarm 1.173.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (511) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-ccm9xrep.js → acp-adapter-kr4abrsk.js} +17 -16
  3. package/dist/{actions-sgeyv08k.js → actions-eh4g6w2r.js} +39 -34
  4. package/dist/{amp-adapter-gpxp3kc9.js → amp-adapter-7h7wdt8q.js} +8 -7
  5. package/dist/{app-km9qnv2f.js → app-7k8s9w5p.js} +18 -14
  6. package/dist/{assistant-5r8tcvvd.js → assistant-wswt2y7p.js} +40 -35
  7. package/dist/{boot-reembed-16rv9843.js → boot-reembed-9apm9qw6.js} +10 -9
  8. package/dist/{boot-reembed-swwzdgd7.js → boot-reembed-whzbdthj.js} +10 -9
  9. package/dist/{boot-scrub-sweep-zkr6vkqb.js → boot-scrub-sweep-ndzmvmgt.js} +11 -10
  10. package/dist/{boot-seeds-d8sp49t2.js → boot-seeds-e9sta0yt.js} +16 -13
  11. package/dist/{claude-adapter-yzzzh8jp.js → claude-adapter-4mqd3r6r.js} +19 -18
  12. package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-9wswb52m.js} +7 -5
  13. package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-tpe1effx.js} +6 -4
  14. package/dist/{claude-sdk-session-4whxere4.js → claude-sdk-session-q49ghmh9.js} +12402 -11850
  15. package/dist/{cli-ne7smj1b.js → cli-01xvj1rq.js} +10 -10
  16. package/dist/{cli-nwrdx840.js → cli-035vekcw.js} +3 -3
  17. package/dist/{cli-9xf7fdtp.js → cli-0pd8hzhc.js} +29 -6
  18. package/dist/{cli-tmhsxhb8.js → cli-0veb92a3.js} +28 -6
  19. package/dist/{cli-c3rk1v0x.js → cli-10jesr25.js} +3 -3
  20. package/dist/{cli-6thk4jz3.js → cli-1y7yywmj.js} +6 -6
  21. package/dist/{cli-6r2f7edk.js → cli-20krdhz5.js} +47 -19
  22. package/dist/{cli-rfs4vddv.js → cli-29rja109.js} +39 -20
  23. package/dist/cli-2m1ktfzz.js +17795 -0
  24. package/dist/{cli-na2pxe4f.js → cli-2pwa0q4d.js} +15 -4
  25. package/dist/{cli-7a93cv8c.js → cli-4mengw46.js} +441 -43
  26. package/dist/{cli-94b48jhk.js → cli-5twdke5x.js} +16 -14
  27. package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
  28. package/dist/cli-6cvfxs8r.js +47 -0
  29. package/dist/{cli-w1apjecb.js → cli-711vwbxn.js} +2 -2
  30. package/dist/{cli-r4fqfpwf.js → cli-78vv7446.js} +50 -27
  31. package/dist/{cli-srqq3gc5.js → cli-7n6s5man.js} +5 -5
  32. package/dist/{cli-m89t9jdf.js → cli-7x0g4sn1.js} +15416 -16024
  33. package/dist/{cli-2bw3w47j.js → cli-8wwxw8a3.js} +1 -1
  34. package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
  35. package/dist/{cli-ywm1azg9.js → cli-9jzdj90z.js} +8 -4
  36. package/dist/cli-9traj3dn.js +638 -0
  37. package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
  38. package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
  39. package/dist/cli-cvv9k0hh.js +10143 -0
  40. package/dist/{cli-anzdk0z4.js → cli-d9286m9h.js} +2 -2
  41. package/dist/cli-e3g5mbkz.js +776 -0
  42. package/dist/cli-f527ce74.js +781 -0
  43. package/dist/{cli-gmdajfw5.js → cli-gxzkg1de.js} +5020 -1729
  44. package/dist/{cli-451ks6aw.js → cli-h1arqn31.js} +1 -1
  45. package/dist/cli-hjwmhcg1.js +10622 -0
  46. package/dist/{cli-jpc4r224.js → cli-hqr88ew6.js} +19 -3
  47. package/dist/{cli-h7k0xtry.js → cli-hvqbtna4.js} +4 -1256
  48. package/dist/{cli-cd0hv9nh.js → cli-j67mh2vg.js} +2 -2
  49. package/dist/cli-jta2eyzc.js +619 -0
  50. package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
  51. package/dist/cli-kceah1eh.js +92 -0
  52. package/dist/{cli-d603qf86.js → cli-ksphgh48.js} +10 -8
  53. package/dist/{cli-3nxdmjrc.js → cli-mgz4nbgg.js} +4 -4
  54. package/dist/{cli-saqyage0.js → cli-mz5as5ha.js} +179 -27
  55. package/dist/cli-n2wq4j7m.js +6985 -0
  56. package/dist/{cli-ppy4nnnh.js → cli-n8ndw8j7.js} +2 -2
  57. package/dist/{cli-1w0vj3gw.js → cli-naqzr17j.js} +7 -7
  58. package/dist/{cli-0a7mm3zp.js → cli-nm1p8jfr.js} +25 -21
  59. package/dist/{cli-wrh08zjd.js → cli-p3zbc1rw.js} +5 -18
  60. package/dist/{cli-hsem16hb.js → cli-pe05f8yk.js} +29 -6
  61. package/dist/{cli-5wpw4rab.js → cli-qmzsbkvy.js} +5 -5
  62. package/dist/{cli-bv2etw2y.js → cli-qnm4e9e4.js} +99 -590
  63. package/dist/{cli-1x7da0de.js → cli-qqy4q48b.js} +8 -8
  64. package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
  65. package/dist/{cli-5er5gjbm.js → cli-r35rw5de.js} +15 -15
  66. package/dist/{cli-v3zhnxsb.js → cli-r610p9bs.js} +2 -2
  67. package/dist/{cli-7jykv7ef.js → cli-rc6pf5kv.js} +1 -1
  68. package/dist/{cli-x119kdba.js → cli-rdxm77k3.js} +1 -1
  69. package/dist/cli-rhs9pz33.js +294 -0
  70. package/dist/{cli-0p3enk35.js → cli-s69nfyeh.js} +9 -1
  71. package/dist/{cli-0kxf81jj.js → cli-sawv63e8.js} +2 -2
  72. package/dist/{cli-e3pmyt39.js → cli-sg19gbf0.js} +1 -1
  73. package/dist/{cli-d161g69q.js → cli-shk7r5cs.js} +57 -6
  74. package/dist/{cli-7pz3b7x5.js → cli-sksetb2q.js} +36 -1
  75. package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
  76. package/dist/{cli-db3m6zdt.js → cli-t02z59f2.js} +1 -1
  77. package/dist/{cli-b07hr3bt.js → cli-txqb9s38.js} +2 -2
  78. package/dist/{cli-s8z6x4b4.js → cli-v7g551te.js} +225 -113
  79. package/dist/{cli-rfz2ve55.js → cli-vgqzp4em.js} +3341 -955
  80. package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
  81. package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
  82. package/dist/cli-wfnemr1t.js +86 -0
  83. package/dist/cli-wmgrkscj.js +23254 -0
  84. package/dist/{cli-qm1448f9.js → cli-wms6x9db.js} +8 -8
  85. package/dist/{cli-tadfgd0t.js → cli-x1r545x8.js} +33 -4
  86. package/dist/{cli-xc7p7s3g.js → cli-xczsgshn.js} +6 -6
  87. package/dist/{cli-fmhj1ehj.js → cli-y3167wt1.js} +882 -271
  88. package/dist/{cli-r0byd61h.js → cli-yjmqpxt3.js} +17 -16
  89. package/dist/{cli-81r1wjyv.js → cli-z780ec7c.js} +1 -1
  90. package/dist/{cli-phcqp1b9.js → cli-zm9t2vde.js} +2 -2
  91. package/dist/cli.js +34 -49
  92. package/dist/{codex-adapter-r3dn4fp5.js → codex-adapter-4z16v9n0.js} +15 -14
  93. package/dist/{codex-login-841kv5fk.js → codex-login-pkepy2j1.js} +3 -2
  94. package/dist/{codex-session-runner-fwt793h4.js → codex-session-runner-rvms9y2x.js} +15 -14
  95. package/dist/{commands-z8fq9qna.js → commands-2a9rtyat.js} +11 -10
  96. package/dist/{controller-hq5ggpcp.js → controller-3k3madbn.js} +5 -4
  97. package/dist/{controllers-connect-3mf2btyj.js → controllers-connect-v9yn8zb9.js} +42 -37
  98. package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-98gbhyzn.js} +7 -6
  99. package/dist/{db-qfpq4bt7.js → db-eywwsnjw.js} +30 -9
  100. package/dist/{db-yyhqqrbf.js → db-ncypk9np.js} +12 -11
  101. package/dist/{devin-adapter-xgtj680j.js → devin-adapter-zeq8b9gz.js} +3 -2
  102. package/dist/{dispatcher-x0x7qfcq.js → dispatcher-w94kc575.js} +38 -33
  103. package/dist/{docker-f503k9p0.js → docker-b1e4cqab.js} +3 -2
  104. package/dist/{dsh-adapter-34etvb5m.js → dsh-adapter-47ztej36.js} +7 -6
  105. package/dist/{e2b-66xra4az.js → e2b-bbt8ey45.js} +4 -3
  106. package/dist/{e2b-xwhyj8cw.js → e2b-dp804sen.js} +4 -3
  107. package/dist/{event-bus-vjtv82gm.js → event-bus-j2jdg3qb.js} +3 -2
  108. package/dist/{external-channel-h1fjecwe.js → external-channel-zrkg8ar9.js} +11 -10
  109. package/dist/{google-generative-ai-szdxbpqg.js → google-generative-ai-g8db7x0f.js} +4 -2
  110. package/dist/{google-vertex-qzw3p36d.js → google-vertex-r2692q0r.js} +4 -2
  111. package/dist/{grok-adapter-e7mr287e.js → grok-adapter-s9ncp9vy.js} +18 -17
  112. package/dist/{handlers-znb9n7d4.js → handlers-kqftvjgw.js} +41 -36
  113. package/dist/{heartbeat-bm4qkn8d.js → heartbeat-9q96p8v9.js} +43 -38
  114. package/dist/{hook-254r4mza.js → hook-56qe10dp.js} +11 -23
  115. package/dist/{hook-xaa3q80s.js → hook-yy6rw42k.js} +12 -11
  116. package/dist/{http-3dgrgp8y.js → http-r2dnb8f8.js} +2411 -275
  117. package/dist/{index-fx3jqq1e.js → index-3gtmkhc6.js} +38 -33
  118. package/dist/{index-bdsqa799.js → index-3k5hkz7r.js} +43 -38
  119. package/dist/index-52j1aja4.js +3465 -0
  120. package/dist/{index-g2byveez.js → index-5e101240.js} +38 -33
  121. package/dist/{index-2ybk7khy.js → index-5wyfjc2c.js} +845 -683
  122. package/dist/index-9gw58n4k.js +193 -0
  123. package/dist/index-9j87mcm8.js +56305 -0
  124. package/dist/index-bsmcresk.js +79424 -0
  125. package/dist/index-mh85qhec.js +475 -0
  126. package/dist/{index-jd7sejm2.js → index-vxvhxxbn.js} +10 -9
  127. package/dist/index-we27kd31.js +12810 -0
  128. package/dist/{keepalive-6ywhpja1.js → keepalive-psj6j54c.js} +12 -11
  129. package/dist/{lead-cw45n21s.js → lead-hajz4688.js} +61 -56
  130. package/dist/{maintenance-ss1a1ge9.js → maintenance-ps02sb5m.js} +10 -9
  131. package/dist/{node-fkajaq96.js → node-mwb5r697.js} +2 -1
  132. package/dist/{oauth-refresh-sweep-3c6f8vyy.js → oauth-refresh-sweep-0284h93b.js} +11 -10
  133. package/dist/{onboard-8hzdhc1k.js → onboard-rbf6bg01.js} +11 -3
  134. package/dist/{opencode-adapter-qbchbcfz.js → opencode-adapter-13dcatgq.js} +18 -13
  135. package/dist/{otel-impl-e6mnvc4v.js → otel-impl-zvqcbhp7.js} +242 -868
  136. package/dist/{pi-mono-adapter-3c9g9snh.js → pi-mono-adapter-xxy47q4v.js} +244 -106
  137. package/dist/{pricing-refresh-gedkjdw0.js → pricing-refresh-kefx9v3t.js} +12 -11
  138. package/dist/{rbac-roles-dt4vh1yy.js → rbac-roles-3m36rxm2.js} +11 -10
  139. package/dist/{rbac-roles-eszdg6pm.js → rbac-roles-z76xv0hq.js} +12 -11
  140. package/dist/{render-v2-907cy6sa.js → render-v2-wz73bs25.js} +18 -14
  141. package/dist/{resume-42stcaz0.js → resume-k4wzge8w.js} +25 -21
  142. package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
  143. package/dist/{setup-adbc1c10.js → setup-2fp2pypp.js} +2 -2
  144. package/dist/{virtual-modules-rtmt494q.js → virtual-modules-9gkxqrap.js} +6 -5
  145. package/dist/{work-objects-wpj8ck95.js → work-objects-6k0ywz3m.js} +41 -36
  146. package/dist/{worker-bzdra9rf.js → worker-5v3rxsdh.js} +61 -56
  147. package/dist/{x-qfmygqqv.js → x-4mtdeym1.js} +3 -2
  148. package/openapi.json +1279 -329
  149. package/package.json +15 -15
  150. package/src/agentmail/handlers.ts +21 -11
  151. package/src/apps/definition.ts +16 -0
  152. package/src/azure-devops/api.ts +52 -2
  153. package/src/azure-devops/boards-sync.ts +50 -20
  154. package/src/azure-devops/index.ts +1 -0
  155. package/src/azure-devops/outbound.ts +95 -0
  156. package/src/be/boot-seeds.ts +11 -0
  157. package/src/be/config-refs.ts +60 -0
  158. package/src/be/db/model-profiles.ts +315 -0
  159. package/src/be/db/page-versions.ts +15 -0
  160. package/src/be/db/runtime.ts +35 -8
  161. package/src/be/db/skill-name-resolution.ts +36 -0
  162. package/src/be/db/tasks/read.ts +237 -0
  163. package/src/be/db/tasks/write.ts +7 -0
  164. package/src/be/db.ts +87 -36
  165. package/src/be/migrations/215_swarm_config_export_to_env.sql +34 -0
  166. package/src/be/migrations/216_task_resolved_effort.sql +5 -0
  167. package/src/be/migrations/217_chat_sdk_state.sql +104 -0
  168. package/src/be/migrations/219_relabel_pi_context_compactions.sql +22 -0
  169. package/src/be/migrations/220_model_profiles.sql +137 -0
  170. package/src/be/model-catalog-store.ts +5 -1
  171. package/src/be/model-tier-resolution.ts +155 -10
  172. package/src/be/model-validation.ts +12 -2
  173. package/src/be/models-catalog.ts +26 -1
  174. package/src/be/modelsdev-cache.json +198 -63
  175. package/src/be/modelsdev-cache.ts +9 -1
  176. package/src/be/script-credential-broker.ts +39 -2
  177. package/src/be/scripts/run-saved.ts +1 -0
  178. package/src/be/scripts/typecheck.ts +22 -8
  179. package/src/be/secret-registry.ts +6 -2
  180. package/src/be/seed/runner.ts +13 -1
  181. package/src/be/seed/state-db.ts +5 -0
  182. package/src/be/seed/types.ts +6 -0
  183. package/src/be/seed-model-profiles.ts +41 -0
  184. package/src/be/seed-pricing.ts +19 -2
  185. package/src/be/seed-scripts/catalog/heartbeat-jev-gate.ts +368 -0
  186. package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
  187. package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
  188. package/src/be/seed-scripts/index.ts +9 -0
  189. package/src/be/seed-skills/bundled-files.generated.json +0 -18
  190. package/src/be/seed-skills/index.ts +104 -3
  191. package/src/be/swarm-config-guard.ts +53 -0
  192. package/src/cli.tsx +0 -16
  193. package/src/commands/onboard/non-interactive.ts +4 -2
  194. package/src/commands/provider-credentials.ts +52 -6
  195. package/src/commands/runner.ts +193 -71
  196. package/src/e2b/env.ts +5 -0
  197. package/src/extensions/catalog.generated.json +17 -0
  198. package/src/extensions/contract-types.generated.ts +1 -1
  199. package/src/extensions/contract.ts +45 -0
  200. package/src/extensions/dispatcher.ts +7 -0
  201. package/src/extensions/loader.ts +10 -5
  202. package/src/extensions/post-bridge.ts +40 -0
  203. package/src/github/handlers.ts +11 -4
  204. package/src/heartbeat/heartbeat.ts +2 -1
  205. package/src/heartbeat/templates.ts +8 -5
  206. package/src/hooks/hook.ts +0 -26
  207. package/src/http/agents.ts +49 -2
  208. package/src/http/all-routes.ts +1 -1
  209. package/src/http/apps.ts +30 -3
  210. package/src/http/config.ts +62 -19
  211. package/src/http/core.ts +8 -0
  212. package/src/http/index.ts +25 -3
  213. package/src/http/integrations.ts +88 -1
  214. package/src/http/mcp.ts +15 -5
  215. package/src/http/model-profiles.ts +303 -0
  216. package/src/http/page-proxy.ts +2 -4
  217. package/src/http/pages-public.ts +13 -7
  218. package/src/http/pages.ts +3 -13
  219. package/src/http/poll.ts +42 -71
  220. package/src/http/requested-by.ts +54 -0
  221. package/src/http/script-runs.ts +1 -1
  222. package/src/http/scripts.ts +26 -2
  223. package/src/http/stats.ts +1 -30
  224. package/src/http/tasks.ts +79 -5
  225. package/src/http/utils.ts +14 -0
  226. package/src/http/webhooks.ts +160 -3
  227. package/src/http/x.ts +1 -0
  228. package/src/integrations/chat-sdk/adapters.ts +129 -0
  229. package/src/integrations/chat-sdk/attachments.ts +232 -0
  230. package/src/integrations/chat-sdk/background.ts +36 -0
  231. package/src/integrations/chat-sdk/commands.ts +194 -0
  232. package/src/integrations/chat-sdk/config.ts +198 -0
  233. package/src/integrations/chat-sdk/discord-api.ts +63 -0
  234. package/src/integrations/chat-sdk/discord-gateway.ts +185 -0
  235. package/src/integrations/chat-sdk/handlers.ts +28 -0
  236. package/src/integrations/chat-sdk/inbound.ts +426 -0
  237. package/src/integrations/chat-sdk/limits.ts +48 -0
  238. package/src/integrations/chat-sdk/logger.ts +81 -0
  239. package/src/integrations/chat-sdk/outbound.ts +123 -0
  240. package/src/integrations/chat-sdk/relay.ts +172 -0
  241. package/src/integrations/chat-sdk/router.ts +169 -0
  242. package/src/integrations/chat-sdk/runtime.ts +351 -0
  243. package/src/integrations/chat-sdk/schema.ts +245 -0
  244. package/src/integrations/chat-sdk/state.ts +243 -0
  245. package/src/integrations/chat-sdk/status.ts +244 -0
  246. package/src/integrations/chat-sdk/steering.ts +58 -0
  247. package/src/integrations/chat-sdk/teams-origin.ts +77 -0
  248. package/src/integrations/chat-sdk/telegram-api.ts +56 -0
  249. package/src/integrations/chat-sdk/templates.ts +16 -0
  250. package/src/integrations/chat-sdk/test-hooks.ts +37 -0
  251. package/src/integrations/chat-sdk/thread-buffer.ts +100 -0
  252. package/src/integrations/chat-sdk/typing.ts +65 -0
  253. package/src/{artifact-sdk → pages}/feedback-overlay.ts +65 -6
  254. package/src/pages/version.ts +4 -5
  255. package/src/prompts/base-prompt.ts +111 -45
  256. package/src/providers/acp-target-catalog.ts +6 -0
  257. package/src/providers/acp-targets.ts +56 -3
  258. package/src/providers/amp-adapter.ts +1 -1
  259. package/src/providers/claude-adapter.ts +1 -1
  260. package/src/providers/claude-flag-settings.ts +17 -5
  261. package/src/providers/claude-managed-adapter.ts +1 -1
  262. package/src/providers/claude-session-events.ts +6 -1
  263. package/src/providers/dsh-adapter.ts +1 -1
  264. package/src/providers/opencode-adapter.ts +243 -26
  265. package/src/providers/opencode-swarm-plugin.ts +31 -0
  266. package/src/providers/pi-mono-adapter.ts +398 -153
  267. package/src/providers/pi-mono-extension.ts +17 -3
  268. package/src/providers/pricing-sources.md +33 -2
  269. package/src/providers/reasoning-effort.ts +37 -0
  270. package/src/providers/types.ts +6 -2
  271. package/src/rbac/legacy-policy.ts +16 -2
  272. package/src/rbac/permissions.ts +26 -0
  273. package/src/scheduler/deferred-task-waits.ts +18 -5
  274. package/src/scheduler/scheduler.ts +11 -3
  275. package/src/scripts-runtime/executors/quickjs-prelude.ts +75 -6
  276. package/src/scripts-runtime/executors/quickjs-runner.ts +85 -8
  277. package/src/scripts-runtime/executors/quickjs-web-shims.ts +1041 -0
  278. package/src/scripts-runtime/extract-args-schema.ts +9 -8
  279. package/src/scripts-runtime/loader.ts +19 -7
  280. package/src/scripts-runtime/quickjs-compat.ts +464 -0
  281. package/src/scripts-runtime/sdk-allowlist.ts +12 -6
  282. package/src/scripts-runtime/swarm-sdk.ts +0 -11
  283. package/src/scripts-runtime/types/stdlib.d.ts +39 -15
  284. package/src/scripts-runtime/types/swarm-extension.d.ts +66 -1
  285. package/src/scripts-runtime/types/swarm-sdk.d.ts +39 -15
  286. package/src/server.ts +62 -19
  287. package/src/slack/blocks.ts +4 -2
  288. package/src/slack/event-dedup.ts +1 -1
  289. package/src/slack/reaction-shortcode.ts +14 -0
  290. package/src/slack/render-v2.ts +12 -7
  291. package/src/slack/responses.ts +5 -4
  292. package/src/slack/thread-buffer.ts +41 -22
  293. package/src/tasks/additive-buffer.ts +4 -2
  294. package/src/tasks/context-key.ts +60 -1
  295. package/src/tasks/model-pin.ts +67 -0
  296. package/src/tasks/worker-follow-up.ts +15 -33
  297. package/src/tests/acp-adapter.test.ts +42 -0
  298. package/src/tests/agentmail-filters.test.ts +47 -0
  299. package/src/tests/api-drain-worker-e2e.test.ts +1 -6
  300. package/src/tests/apps-spike2.test.ts +35 -0
  301. package/src/tests/azure-devops-outbound.test.ts +420 -0
  302. package/src/tests/base-prompt.test.ts +58 -54
  303. package/src/tests/chat-sdk-commands.test.ts +191 -0
  304. package/src/tests/chat-sdk-config.test.ts +334 -0
  305. package/src/tests/chat-sdk-discord-api.test.ts +68 -0
  306. package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
  307. package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
  308. package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
  309. package/src/tests/chat-sdk-harness.ts +146 -0
  310. package/src/tests/chat-sdk-inbound.test.ts +363 -0
  311. package/src/tests/chat-sdk-relay.test.ts +470 -0
  312. package/src/tests/chat-sdk-reload.test.ts +128 -0
  313. package/src/tests/chat-sdk-shutdown.test.ts +220 -0
  314. package/src/tests/chat-sdk-slack.test.ts +268 -0
  315. package/src/tests/chat-sdk-state.test.ts +163 -0
  316. package/src/tests/chat-sdk-status-route.test.ts +382 -0
  317. package/src/tests/chat-sdk-teams.test.ts +277 -0
  318. package/src/tests/chat-sdk-tools.test.ts +520 -0
  319. package/src/tests/chat-sdk-typing.test.ts +120 -0
  320. package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
  321. package/src/tests/claude-adapter-binary.test.ts +9 -4
  322. package/src/tests/claude-flag-settings.test.ts +11 -3
  323. package/src/tests/claude-managed-adapter.test.ts +1 -1
  324. package/src/tests/claude-sdk-lifecycle.test.ts +9 -3
  325. package/src/tests/claude-thinking-tokens.test.ts +57 -0
  326. package/src/tests/claude-worker-parity.test.ts +2 -7
  327. package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
  328. package/src/tests/config-refs.test.ts +66 -0
  329. package/src/tests/context-key.test.ts +19 -0
  330. package/src/tests/cors-allowlist.test.ts +25 -0
  331. package/src/tests/create-page-tool.test.ts +18 -0
  332. package/src/tests/credential-check.test.ts +139 -0
  333. package/src/tests/credentials.test.ts +21 -0
  334. package/src/tests/db-runtime.test.ts +61 -0
  335. package/src/tests/db-task-read-contract.test.ts +22 -0
  336. package/src/tests/db-task-write-contract.test.ts +11 -0
  337. package/src/tests/deferred-task-wake.test.ts +78 -1
  338. package/src/tests/docs-index-footprint.test.js +3 -3
  339. package/src/tests/dsh-adapter.test.ts +1 -1
  340. package/src/tests/enabled-capabilities.test.ts +20 -0
  341. package/src/tests/entrypoint-api-readiness.test.ts +14 -8
  342. package/src/tests/entrypoint-config-env-export.test.ts +5 -2
  343. package/src/tests/entrypoint-export-to-env.test.ts +78 -0
  344. package/src/tests/env-flag.test.ts +1 -0
  345. package/src/tests/explicit-model-validation.test.ts +105 -1
  346. package/src/tests/extensions-catalog.test.ts +1 -0
  347. package/src/tests/extensions-example-comms-adherence-gate.test.ts +413 -0
  348. package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
  349. package/src/tests/extensions-loader.test.ts +15 -0
  350. package/src/tests/extensions-post-bridge.test.ts +51 -0
  351. package/src/tests/fetch-resolved-env.test.ts +128 -0
  352. package/src/tests/fixtures/chat-sdk/telegram-private-text.json +10 -0
  353. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
  354. package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
  355. package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
  356. package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
  357. package/src/tests/github-handlers.test.ts +35 -0
  358. package/src/tests/harness-provider-resolution.test.ts +12 -0
  359. package/src/tests/heartbeat-checklist.test.ts +3 -2
  360. package/src/tests/heartbeat-jev-gate-credentials.test.ts +168 -0
  361. package/src/tests/heartbeat-jev-gate.test.ts +385 -0
  362. package/src/tests/hook-runtime-close.test.ts +0 -2
  363. package/src/tests/http-api-integration.test.ts +0 -25
  364. package/src/tests/migration-046-budgets.test.ts +17 -16
  365. package/src/tests/migration-217-chat-sdk-state.test.ts +113 -0
  366. package/src/tests/model-profile-backcompat.test.ts +327 -0
  367. package/src/tests/model-profile-providers.test.ts +302 -0
  368. package/src/tests/model-profile-runtime-secrets.test.ts +223 -0
  369. package/src/tests/model-profiles-api.test.ts +614 -0
  370. package/src/tests/model-tier-resolution.test.ts +93 -0
  371. package/src/tests/models-catalog.test.ts +42 -1
  372. package/src/tests/openai-compatible-providers.test.ts +134 -0
  373. package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
  374. package/src/tests/opencode-adapter.test.ts +216 -2
  375. package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
  376. package/src/tests/opencode-shell-env.test.ts +145 -0
  377. package/src/tests/openrouter-base-url.test.ts +101 -151
  378. package/src/tests/page-proxy.test.ts +1 -1
  379. package/src/tests/pages-browser-sdk.test.ts +76 -0
  380. package/src/tests/pages-feedback-keys.test.ts +121 -0
  381. package/src/tests/pages-feedback.test.ts +4 -1
  382. package/src/tests/paused-tasks-requested-by.test.ts +102 -0
  383. package/src/tests/pi-context-compaction.test.ts +193 -0
  384. package/src/tests/pi-custom-provider-fake-server.test.ts +442 -0
  385. package/src/tests/pi-mono-adapter.test.ts +385 -5
  386. package/src/tests/pi-shell-env.test.ts +170 -0
  387. package/src/tests/profile-claim.test.ts +269 -0
  388. package/src/tests/prompt-template-remaining.test.ts +35 -0
  389. package/src/tests/quickjs-compat.test.ts +213 -0
  390. package/src/tests/rbac-engine.test.ts +32 -3
  391. package/src/tests/runner-exit-after-tasks.test.ts +0 -4
  392. package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
  393. package/src/tests/script-connections.test.ts +6 -0
  394. package/src/tests/script-executor-conformance.test.ts +252 -1
  395. package/src/tests/script-executor-quickjs.test.ts +96 -0
  396. package/src/tests/script-runs-http.test.ts +89 -0
  397. package/src/tests/scripts-http.test.ts +217 -1
  398. package/src/tests/scripts-only-gating.test.ts +2 -3
  399. package/src/tests/scripts-runtime.test.ts +58 -40
  400. package/src/tests/secret-scrubber.test.ts +96 -0
  401. package/src/tests/seed-model-profiles.test.ts +174 -0
  402. package/src/tests/seed-scripts.test.ts +2 -2
  403. package/src/tests/seed-skills-bundled-files.test.ts +45 -53
  404. package/src/tests/seed-skills-retire.test.ts +182 -0
  405. package/src/tests/send-task-requester-gate.test.ts +58 -0
  406. package/src/tests/session-cost-recompute-unit.test.ts +46 -0
  407. package/src/tests/skill-get-name-resolution.test.ts +137 -0
  408. package/src/tests/skill-invocations.test.ts +4 -2
  409. package/src/tests/slack-blocks.test.ts +36 -0
  410. package/src/tests/slack-inline-output.test.ts +14 -0
  411. package/src/tests/slack-reaction-config.test.ts +20 -0
  412. package/src/tests/slack-render-v2.test.ts +37 -0
  413. package/src/tests/slack-thread-buffer.test.ts +98 -1
  414. package/src/tests/sonnet-5-5-registry.test.ts +9 -1
  415. package/src/tests/swarm-config-export-to-env.test.ts +267 -0
  416. package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
  417. package/src/tests/swarm-diff.test.ts +1 -1
  418. package/src/tests/task-model-effort-rerun.test.ts +164 -0
  419. package/src/tests/task-session-prompts.test.ts +132 -0
  420. package/src/tests/task-tool-manifest.test.ts +14 -0
  421. package/src/tests/task-tools-ctx.test.ts +2 -0
  422. package/src/tests/tool-annotations.test.ts +6 -6
  423. package/src/tests/ui-logs-parser.test.ts +43 -0
  424. package/src/tests/used-by-route.test.ts +6 -0
  425. package/src/tests/vercel-ai-gateway.test.ts +149 -0
  426. package/src/tests/workflow-llm.test.ts +61 -0
  427. package/src/tests/workflow-swarm-script.test.ts +38 -0
  428. package/src/tests/workflow-wait-filter.test.ts +5 -3
  429. package/src/tools/chat-access.ts +41 -0
  430. package/src/tools/chat-open-dm.ts +59 -0
  431. package/src/tools/chat-post.ts +74 -0
  432. package/src/tools/chat-read-thread.ts +100 -0
  433. package/src/tools/chat-reply.ts +75 -0
  434. package/src/tools/create-page.ts +3 -13
  435. package/src/tools/model-catalog/index.ts +2 -1
  436. package/src/tools/model-profiles/list-model-profiles.ts +54 -0
  437. package/src/tools/register-chat-channel.ts +139 -0
  438. package/src/tools/request-human-input.ts +11 -3
  439. package/src/tools/script-apis.ts +5 -1
  440. package/src/tools/script-upsert.ts +4 -1
  441. package/src/tools/send-task.ts +48 -1
  442. package/src/tools/skills/skill-get.ts +17 -9
  443. package/src/tools/swarm-config/get-config.ts +2 -1
  444. package/src/tools/swarm-config/list-config.ts +2 -1
  445. package/src/tools/swarm-config/set-config.ts +16 -3
  446. package/src/tools/system-one-decide.ts +104 -0
  447. package/src/tools/task-action.ts +22 -1
  448. package/src/tools/tool-config.ts +14 -6
  449. package/src/types.ts +48 -3
  450. package/src/utils/config-env-export.ts +74 -0
  451. package/src/utils/credentials.test.ts +92 -0
  452. package/src/utils/credentials.ts +52 -4
  453. package/src/utils/harness-provider.ts +15 -6
  454. package/src/utils/runtime-model-catalog.ts +11 -1
  455. package/src/utils/secret-scrubber.ts +86 -10
  456. package/src/utils/task-tool-manifest.ts +19 -2
  457. package/src/utils/vcs-repo-match.ts +29 -0
  458. package/src/workflows/executors/raw-llm.ts +8 -3
  459. package/src/workflows/executors/swarm-script.ts +1 -0
  460. package/src/workflows/executors/system-one-decision.ts +21 -11
  461. package/src/workflows/executors/workflow-llm.ts +22 -0
  462. package/src/workflows/index.ts +21 -12
  463. package/templates/extensions/README.md +1 -0
  464. package/templates/extensions/comms-adherence-gate/README.md +88 -0
  465. package/templates/extensions/comms-adherence-gate/hooks.ts +489 -0
  466. package/templates/extensions/comms-adherence-gate/manifest.json +8 -0
  467. package/templates/skills/agent-browser/SKILL.md +1 -1
  468. package/templates/skills/agent-browser/content.md +1 -1
  469. package/templates/skills/apps/SKILL.md +8 -1
  470. package/templates/skills/apps/content.md +8 -1
  471. package/templates/skills/chat-sdk/config.json +14 -0
  472. package/templates/skills/chat-sdk/content.md +84 -0
  473. package/templates/skills/composio-gmail/content.md +7 -0
  474. package/templates/skills/composio-google-docs/content.md +1 -1
  475. package/templates/skills/email-domain-health/config.json +14 -0
  476. package/templates/skills/email-domain-health/content.md +131 -0
  477. package/templates/skills/kv-storage/content.md +2 -2
  478. package/templates/skills/pages/content.md +8 -10
  479. package/templates/skills/swarm-extensions/content.md +2 -0
  480. package/templates/skills/swarm-scripts/SKILL.md +4 -2
  481. package/templates/skills/swarm-scripts/config.json +1 -1
  482. package/templates/skills/swarm-scripts/content.md +4 -2
  483. package/templates/skills/workflow-iterate/content.md +38 -0
  484. package/dist/artifact-eczsknc3.js +0 -3843
  485. package/dist/cli-42qhyvwx.js +0 -33
  486. package/dist/cli-bd957dgb.js +0 -153
  487. package/dist/cli-q51yprfq.js +0 -1104
  488. package/dist/cli-t1ze64h3.js +0 -811
  489. package/dist/cli-tcc4wd5d.js +0 -56471
  490. package/dist/index-9ch1n761.js +0 -1102
  491. package/src/artifact-sdk/index.ts +0 -2
  492. package/src/artifact-sdk/localtunnel.d.ts +0 -20
  493. package/src/artifact-sdk/port.ts +0 -12
  494. package/src/artifact-sdk/server.ts +0 -183
  495. package/src/artifact-sdk/tunnel.ts +0 -19
  496. package/src/commands/artifact.ts +0 -249
  497. package/src/http/ecosystem.ts +0 -77
  498. package/src/tests/artifact-commands.test.ts +0 -92
  499. package/src/tests/artifact-sdk.test.ts +0 -793
  500. package/src/tests/register-service-security.test.ts +0 -194
  501. package/src/tools/list-services.ts +0 -107
  502. package/src/tools/register-service.ts +0 -177
  503. package/src/tools/unregister-service.ts +0 -73
  504. package/src/tools/update-service-status.ts +0 -96
  505. package/templates/skills/artifacts/config.json +0 -14
  506. package/templates/skills/artifacts/content.md +0 -344
  507. package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
  508. package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
  509. package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
  510. package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
  511. /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
@@ -0,0 +1,245 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * `CHAT_SDK_ADAPTERS` schema. Kept free of DB imports because
5
+ * `src/be/swarm-config-guard.ts` (imported by `src/be/db.ts`) validates writes
6
+ * with it; `config.ts` adds the DB-backed resolution on top.
7
+ */
8
+
9
+ export const CHAT_SDK_ADAPTER_NAMES = ["telegram", "slack", "discord", "teams"] as const;
10
+ export type ChatSdkAdapterName = (typeof CHAT_SDK_ADAPTER_NAMES)[number];
11
+
12
+ export const ConfigRefSchema = z.strictObject({ $config: z.string().min(1) });
13
+
14
+ /** A literal string or a `{ "$config": "KEY" }` reference to a swarm_config key. */
15
+ const Str = z.union([z.string().trim().min(1), ConfigRefSchema]);
16
+
17
+ /**
18
+ * Keys an operator must never set. A base URL plus a `$config` ref would send
19
+ * the referenced secret to an arbitrary host. A verifier or an "unverified"
20
+ * switch bypasses the platform signature check on the public webhook.
21
+ * Mock base URLs come only from the env-only `CHAT_SDK_API_URL_OVERRIDES`.
22
+ */
23
+ const FORBIDDEN_ADAPTER_KEYS = [
24
+ "apiUrl",
25
+ "apiBaseUrl",
26
+ "webhookVerifier",
27
+ "allowUnverifiedWebhooks",
28
+ ] as const;
29
+
30
+ type AdapterShape = z.ZodRawShape;
31
+
32
+ function forbiddenKeyIssues(value: Record<string, unknown>, ctx: z.RefinementCtx): void {
33
+ for (const key of FORBIDDEN_ADAPTER_KEYS) {
34
+ if (key in value) {
35
+ ctx.addIssue({
36
+ code: "custom",
37
+ path: [key],
38
+ message: `${key} is not allowed in CHAT_SDK_ADAPTERS`,
39
+ });
40
+ }
41
+ }
42
+ }
43
+
44
+ /** Fields every adapter has next to its own shape. `enabled: false` keeps the entry but does not start it. */
45
+ const COMMON_SHAPE = {
46
+ userName: z.string().min(1).optional(),
47
+ enabled: z.boolean().optional(),
48
+ };
49
+
50
+ function adapterSchema<S extends AdapterShape>(shape: S) {
51
+ return z.looseObject({ ...shape, ...COMMON_SHAPE }).superRefine(forbiddenKeyIssues);
52
+ }
53
+
54
+ /**
55
+ * The same adapter, with every field optional: the shape a dashboard save may
56
+ * store before the operator has every value (`.partial()` refuses schemas with
57
+ * refinements, so the optional shape is built by hand). Forbidden keys and
58
+ * value formats still apply.
59
+ */
60
+ function draftShape<S extends AdapterShape>(shape: S): AdapterShape {
61
+ return Object.fromEntries(
62
+ Object.entries(shape).map(([key, field]) => [key, (field as z.ZodType).optional()]),
63
+ );
64
+ }
65
+
66
+ const TELEGRAM_SHAPE = {
67
+ botToken: Str,
68
+ secretToken: Str.optional(),
69
+ // Never the SDK's "auto": auto starts long polling against the real Bot API
70
+ // when no webhook is registered.
71
+ mode: z.enum(["webhook", "polling"]).default("webhook"),
72
+ allowedUserIds: z.array(z.union([z.string(), z.number()])).optional(),
73
+ };
74
+
75
+ const SLACK_SHAPE = {
76
+ botToken: Str,
77
+ signingSecret: Str.optional(),
78
+ appToken: Str.optional(),
79
+ mode: z.enum(["webhook", "socket"]).default("webhook"),
80
+ };
81
+
82
+ export const TelegramAdapterSchema = adapterSchema(TELEGRAM_SHAPE);
83
+
84
+ export const SlackAdapterSchema = adapterSchema(SLACK_SHAPE).superRefine((value, ctx) => {
85
+ // Required here, not left to the adapter: the adapter falls back to
86
+ // SLACK_SIGNING_SECRET / SLACK_APP_TOKEN, which belong to the built-in Slack app.
87
+ if (value.mode === "webhook" && value.signingSecret === undefined) {
88
+ ctx.addIssue({
89
+ code: "custom",
90
+ path: ["signingSecret"],
91
+ message: "signingSecret is required in webhook mode",
92
+ });
93
+ }
94
+ if (value.mode === "socket" && value.appToken === undefined) {
95
+ ctx.addIssue({
96
+ code: "custom",
97
+ path: ["appToken"],
98
+ message: "appToken is required in socket mode",
99
+ });
100
+ }
101
+ });
102
+
103
+ const DISCORD_PUBLIC_KEY_PATTERN = /^[0-9a-fA-F]{64}$/;
104
+
105
+ const DISCORD_SHAPE = {
106
+ botToken: Str,
107
+ publicKey: Str,
108
+ applicationId: Str,
109
+ respondToChannelIds: z.array(z.string()).optional(),
110
+ respondToGlobalMentions: z.boolean().optional(),
111
+ mentionRoleIds: z.array(z.string()).optional(),
112
+ };
113
+
114
+ // A literal key must be the hex Ed25519 public key from the Developer Portal.
115
+ // A `$config` value resolves at startup, where the adapter logs a bad format.
116
+ function discordPublicKeyIssue(value: Record<string, unknown>, ctx: z.RefinementCtx): void {
117
+ if (typeof value.publicKey === "string" && !DISCORD_PUBLIC_KEY_PATTERN.test(value.publicKey)) {
118
+ ctx.addIssue({
119
+ code: "custom",
120
+ path: ["publicKey"],
121
+ message: "publicKey must be 64 hex characters (the application's Ed25519 public key)",
122
+ });
123
+ }
124
+ }
125
+
126
+ export const DiscordAdapterSchema = adapterSchema(DISCORD_SHAPE).superRefine(discordPublicKeyIssue);
127
+
128
+ const TEAMS_SHAPE = {
129
+ appId: Str,
130
+ appPassword: Str,
131
+ appTenantId: Str.optional(),
132
+ appType: z.enum(["MultiTenant", "SingleTenant"]).default("MultiTenant"),
133
+ };
134
+
135
+ export const TeamsAdapterSchema = adapterSchema(TEAMS_SHAPE).superRefine((value, ctx) => {
136
+ // The adapter falls back to TEAMS_APP_TENANT_ID when a single-tenant app has no tenant.
137
+ if (value.appType === "SingleTenant" && value.appTenantId === undefined) {
138
+ ctx.addIssue({
139
+ code: "custom",
140
+ path: ["appTenantId"],
141
+ message: "appTenantId is required for a SingleTenant app",
142
+ });
143
+ }
144
+ });
145
+
146
+ // Strict: a typo'd adapter name must fail loudly, not silently disable it.
147
+ export const ChatSdkAdaptersSchema = z
148
+ .strictObject({
149
+ telegram: TelegramAdapterSchema,
150
+ slack: SlackAdapterSchema,
151
+ discord: DiscordAdapterSchema,
152
+ teams: TeamsAdapterSchema,
153
+ })
154
+ .partial();
155
+
156
+ export type ChatSdkAdapters = z.infer<typeof ChatSdkAdaptersSchema>;
157
+
158
+ /** The full schema of one adapter entry. An entry that fails it is "incomplete". */
159
+ export const CHAT_SDK_ADAPTER_SCHEMAS: Record<ChatSdkAdapterName, z.ZodType> = {
160
+ telegram: TelegramAdapterSchema,
161
+ slack: SlackAdapterSchema,
162
+ discord: DiscordAdapterSchema,
163
+ teams: TeamsAdapterSchema,
164
+ };
165
+
166
+ /**
167
+ * What a `CHAT_SDK_ADAPTERS` write must satisfy: known adapter names, object
168
+ * entries, no forbidden keys, well-formed values. Required fields may be
169
+ * missing (a partial dashboard save); such an adapter does not start and the
170
+ * status reports it as incomplete, while the complete adapters run.
171
+ */
172
+ export const ChatSdkAdaptersDraftSchema = z
173
+ .strictObject({
174
+ telegram: adapterSchema(draftShape(TELEGRAM_SHAPE)),
175
+ slack: adapterSchema(draftShape(SLACK_SHAPE)),
176
+ discord: adapterSchema(draftShape(DISCORD_SHAPE)).superRefine(discordPublicKeyIssue),
177
+ teams: adapterSchema(draftShape(TEAMS_SHAPE)),
178
+ })
179
+ .partial();
180
+
181
+ function valueAt(input: unknown, path: PropertyKey[]): unknown {
182
+ let current: unknown = input;
183
+ for (const key of path) {
184
+ if (current === null || typeof current !== "object") return undefined;
185
+ current = (current as Record<PropertyKey, unknown>)[key];
186
+ }
187
+ return current;
188
+ }
189
+
190
+ /**
191
+ * `<prefix>.<path>: <message>` for the first issue of a failed parse. With
192
+ * `input`, a missing value reads "required" instead of zod's union text
193
+ * ("Invalid input"), which is what a partial dashboard save produces.
194
+ */
195
+ export function firstIssueText(
196
+ error: z.ZodError,
197
+ prefix = "CHAT_SDK_ADAPTERS",
198
+ input?: unknown,
199
+ ): string {
200
+ const issue = error.issues[0];
201
+ if (!issue) return `${prefix} is invalid`;
202
+ const path = issue.path.length > 0 ? issue.path.join(".") : "(root)";
203
+ const missing =
204
+ input !== undefined && issue.path.length > 0 && valueAt(input, issue.path) === undefined;
205
+ return `${prefix}.${path}: ${missing ? "required" : issue.message}`;
206
+ }
207
+
208
+ /**
209
+ * Field names per adapter, derived from the schemas. The dashboard keeps its
210
+ * own field list (`apps/ui/src/lib/chat-sdk-fields.ts`, it cannot import zod
211
+ * schemas from the API); `src/tests/chat-sdk-fields-sync.test.ts` keeps the two equal.
212
+ */
213
+ export const CHAT_SDK_ADAPTER_FIELDS: Record<ChatSdkAdapterName, readonly string[]> = {
214
+ telegram: formFields(TelegramAdapterSchema.shape),
215
+ slack: formFields(SlackAdapterSchema.shape),
216
+ discord: formFields(DiscordAdapterSchema.shape),
217
+ teams: formFields(TeamsAdapterSchema.shape),
218
+ };
219
+
220
+ /** `enabled` is the panel switch on the card, not a form field. */
221
+ function formFields(shape: AdapterShape): string[] {
222
+ return Object.keys(shape).filter((key) => key !== "enabled");
223
+ }
224
+
225
+ /** True unless the entry carries `enabled: false`. */
226
+ export function isAdapterEntryEnabled(entry: Record<string, unknown> | undefined): boolean {
227
+ return entry !== undefined && entry.enabled !== false;
228
+ }
229
+
230
+ /**
231
+ * `VALIDATED_KEYS` validator for `CHAT_SDK_ADAPTERS`: the draft shape only
232
+ * (missing required fields are allowed, see `ChatSdkAdaptersDraftSchema`), no
233
+ * reference resolution. Returns the first issue as a string, or null.
234
+ */
235
+ export function validateChatSdkAdaptersValue(value: unknown): string | null {
236
+ if (typeof value !== "string") return "CHAT_SDK_ADAPTERS must be a JSON string";
237
+ let parsed: unknown;
238
+ try {
239
+ parsed = JSON.parse(value);
240
+ } catch (error) {
241
+ return `CHAT_SDK_ADAPTERS is not valid JSON: ${error instanceof Error ? error.message : String(error)}`;
242
+ }
243
+ const result = ChatSdkAdaptersDraftSchema.safeParse(parsed);
244
+ return result.success ? null : firstIssueText(result.error);
245
+ }
@@ -0,0 +1,243 @@
1
+ import type { Lock, Message, QueueEntry, SerializedMessage, StateAdapter } from "chat";
2
+ import { getDbClient } from "@/be/db";
3
+
4
+ /**
5
+ * Chat SDK `StateAdapter` backed by the dedicated `chat_*` tables (migration
6
+ * 213). Every method is one statement or one short transaction through the
7
+ * async DB seam, so each operation is atomic by construction.
8
+ *
9
+ * Expiry columns hold epoch milliseconds. A `ttlMs` of 0 or undefined means no
10
+ * expiry. Queue entries are not filtered by `expiresAt` here: the Chat core
11
+ * drops expired entries itself on dequeue.
12
+ */
13
+
14
+ function encode(value: unknown): string {
15
+ return JSON.stringify(value ?? null);
16
+ }
17
+
18
+ function decode<T>(value: string): T {
19
+ return JSON.parse(value) as T;
20
+ }
21
+
22
+ function expiresAtFor(ttlMs: number | undefined, now: number): number | null {
23
+ return ttlMs ? now + ttlMs : null;
24
+ }
25
+
26
+ export class SqliteChatState implements StateAdapter {
27
+ async connect(): Promise<void> {}
28
+
29
+ /**
30
+ * No-op on purpose. The memory adapter clears subscriptions on disconnect
31
+ * because it is memory. A durable store keeps "we own this thread" across
32
+ * restarts, and locks expire by TTL.
33
+ */
34
+ async disconnect(): Promise<void> {}
35
+
36
+ async subscribe(threadId: string): Promise<void> {
37
+ await getDbClient().run("INSERT OR IGNORE INTO chat_subscriptions (thread_id) VALUES (?)", [
38
+ threadId,
39
+ ]);
40
+ }
41
+
42
+ async unsubscribe(threadId: string): Promise<void> {
43
+ await getDbClient().run("DELETE FROM chat_subscriptions WHERE thread_id = ?", [threadId]);
44
+ }
45
+
46
+ async isSubscribed(threadId: string): Promise<boolean> {
47
+ const row = await getDbClient().get<{ one: number }>(
48
+ "SELECT 1 AS one FROM chat_subscriptions WHERE thread_id = ?",
49
+ [threadId],
50
+ );
51
+ return row !== null;
52
+ }
53
+
54
+ async acquireLock(threadId: string, ttlMs: number): Promise<Lock | null> {
55
+ const now = Date.now();
56
+ const lock: Lock = { threadId, token: crypto.randomUUID(), expiresAt: now + ttlMs };
57
+ const result = await getDbClient().run(
58
+ `INSERT INTO chat_locks (thread_id, token, expires_at) VALUES (?, ?, ?)
59
+ ON CONFLICT(thread_id) DO UPDATE SET
60
+ token = excluded.token,
61
+ expires_at = excluded.expires_at
62
+ WHERE chat_locks.expires_at <= ?`,
63
+ [threadId, lock.token, lock.expiresAt, now],
64
+ );
65
+ return result.changes > 0 ? lock : null;
66
+ }
67
+
68
+ async extendLock(lock: Lock, ttlMs: number): Promise<boolean> {
69
+ const now = Date.now();
70
+ const result = await getDbClient().run(
71
+ "UPDATE chat_locks SET expires_at = ? WHERE thread_id = ? AND token = ? AND expires_at > ?",
72
+ [now + ttlMs, lock.threadId, lock.token, now],
73
+ );
74
+ return result.changes > 0;
75
+ }
76
+
77
+ async releaseLock(lock: Lock): Promise<void> {
78
+ await getDbClient().run("DELETE FROM chat_locks WHERE thread_id = ? AND token = ?", [
79
+ lock.threadId,
80
+ lock.token,
81
+ ]);
82
+ }
83
+
84
+ async forceReleaseLock(threadId: string): Promise<void> {
85
+ await getDbClient().run("DELETE FROM chat_locks WHERE thread_id = ?", [threadId]);
86
+ }
87
+
88
+ async get<T = unknown>(key: string): Promise<T | null> {
89
+ const now = Date.now();
90
+ const row = await getDbClient().get<{ value: string; expires_at: number | null }>(
91
+ "SELECT value, expires_at FROM chat_state_kv WHERE key = ?",
92
+ [key],
93
+ );
94
+ if (!row) return null;
95
+ if (row.expires_at !== null && row.expires_at <= now) {
96
+ await getDbClient().run("DELETE FROM chat_state_kv WHERE key = ? AND expires_at <= ?", [
97
+ key,
98
+ now,
99
+ ]);
100
+ return null;
101
+ }
102
+ return decode<T>(row.value);
103
+ }
104
+
105
+ async set<T = unknown>(key: string, value: T, ttlMs?: number): Promise<void> {
106
+ await getDbClient().run(
107
+ `INSERT INTO chat_state_kv (key, value, expires_at) VALUES (?, ?, ?)
108
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value, expires_at = excluded.expires_at`,
109
+ [key, encode(value), expiresAtFor(ttlMs, Date.now())],
110
+ );
111
+ }
112
+
113
+ async setIfNotExists(key: string, value: unknown, ttlMs?: number): Promise<boolean> {
114
+ const now = Date.now();
115
+ const result = await getDbClient().run(
116
+ `INSERT INTO chat_state_kv (key, value, expires_at) VALUES (?, ?, ?)
117
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value, expires_at = excluded.expires_at
118
+ WHERE chat_state_kv.expires_at IS NOT NULL AND chat_state_kv.expires_at <= ?`,
119
+ [key, encode(value), expiresAtFor(ttlMs, now), now],
120
+ );
121
+ return result.changes > 0;
122
+ }
123
+
124
+ async delete(key: string): Promise<void> {
125
+ await getDbClient().run("DELETE FROM chat_state_kv WHERE key = ?", [key]);
126
+ }
127
+
128
+ async appendToList(
129
+ key: string,
130
+ value: unknown,
131
+ options?: { maxLength?: number; ttlMs?: number },
132
+ ): Promise<void> {
133
+ const now = Date.now();
134
+ const expiresAt = expiresAtFor(options?.ttlMs, now);
135
+ await getDbClient().transaction(async (tx) => {
136
+ // An expired list starts over, like the memory adapter.
137
+ await tx.run(
138
+ "DELETE FROM chat_lists WHERE key = ? AND expires_at IS NOT NULL AND expires_at <= ?",
139
+ [key, now],
140
+ );
141
+ await tx.run(
142
+ `INSERT INTO chat_lists (key, seq, value, expires_at)
143
+ VALUES (?, (SELECT COALESCE(MAX(seq), 0) + 1 FROM chat_lists WHERE key = ?), ?, ?)`,
144
+ [key, key, encode(value), expiresAt],
145
+ );
146
+ if (options?.maxLength && options.maxLength > 0) {
147
+ await tx.run(
148
+ `DELETE FROM chat_lists WHERE key = ? AND seq NOT IN (
149
+ SELECT seq FROM chat_lists WHERE key = ? ORDER BY seq DESC LIMIT ?
150
+ )`,
151
+ [key, key, options.maxLength],
152
+ );
153
+ }
154
+ await tx.run("UPDATE chat_lists SET expires_at = ? WHERE key = ?", [expiresAt, key]);
155
+ });
156
+ }
157
+
158
+ async getList<T = unknown>(key: string): Promise<T[]> {
159
+ const rows = await getDbClient().query<{ value: string }>(
160
+ `SELECT value FROM chat_lists
161
+ WHERE key = ? AND (expires_at IS NULL OR expires_at > ?)
162
+ ORDER BY seq ASC`,
163
+ [key, Date.now()],
164
+ );
165
+ return rows.map((row) => decode<T>(row.value));
166
+ }
167
+
168
+ async enqueue(threadId: string, entry: QueueEntry, maxSize: number): Promise<number> {
169
+ return await getDbClient().transaction(async (tx) => {
170
+ await tx.run("INSERT INTO chat_queue (thread_id, entry) VALUES (?, ?)", [
171
+ threadId,
172
+ encode(entry),
173
+ ]);
174
+ await tx.run(
175
+ `DELETE FROM chat_queue WHERE thread_id = ? AND id NOT IN (
176
+ SELECT id FROM chat_queue WHERE thread_id = ? ORDER BY id DESC LIMIT ?
177
+ )`,
178
+ [threadId, threadId, Math.max(maxSize, 0)],
179
+ );
180
+ const row = await tx.get<{ depth: number }>(
181
+ "SELECT COUNT(*) AS depth FROM chat_queue WHERE thread_id = ?",
182
+ [threadId],
183
+ );
184
+ return row?.depth ?? 0;
185
+ });
186
+ }
187
+
188
+ async dequeue(threadId: string): Promise<QueueEntry | null> {
189
+ return await getDbClient().transaction(async (tx) => {
190
+ const row = await tx.get<{ id: number; entry: string }>(
191
+ "SELECT id, entry FROM chat_queue WHERE thread_id = ? ORDER BY id ASC LIMIT 1",
192
+ [threadId],
193
+ );
194
+ if (!row) return null;
195
+ await tx.run("DELETE FROM chat_queue WHERE id = ?", [row.id]);
196
+ return decode<QueueEntry>(row.entry);
197
+ });
198
+ }
199
+
200
+ async queueDepth(threadId: string): Promise<number> {
201
+ const row = await getDbClient().get<{ depth: number }>(
202
+ "SELECT COUNT(*) AS depth FROM chat_queue WHERE thread_id = ?",
203
+ [threadId],
204
+ );
205
+ return row?.depth ?? 0;
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Delete expired state rows. Called from the Phase 3 watcher tick; exported
211
+ * now for tests.
212
+ */
213
+ export async function sweepExpired(now: number = Date.now()): Promise<void> {
214
+ await getDbClient().transaction(async (tx) => {
215
+ await tx.run("DELETE FROM chat_state_kv WHERE expires_at IS NOT NULL AND expires_at <= ?", [
216
+ now,
217
+ ]);
218
+ await tx.run("DELETE FROM chat_lists WHERE expires_at IS NOT NULL AND expires_at <= ?", [now]);
219
+ await tx.run("DELETE FROM chat_locks WHERE expires_at <= ?", [now]);
220
+ });
221
+ }
222
+
223
+ /**
224
+ * Key prefix of the SDK `ThreadHistoryCache` (chat 4.41): the per-thread
225
+ * message list for adapters with `persistThreadHistory` (Telegram, WhatsApp).
226
+ * Pinned by `chat-sdk-commands.test.ts` against the real SDK.
227
+ */
228
+ export const SDK_THREAD_HISTORY_PREFIX = "msg-history:";
229
+
230
+ /**
231
+ * The thread history the SDK persisted here, oldest first. The adapters that
232
+ * persist it answer `fetchMessages` from process memory, and the SDK reads this
233
+ * store only when that memory is empty. After a restart the memory holds just
234
+ * the newest message, so callers merge both sources themselves.
235
+ */
236
+ export async function readPersistedThreadHistory(threadId: string): Promise<Message[]> {
237
+ const rows = await new SqliteChatState().getList<SerializedMessage>(
238
+ `${SDK_THREAD_HISTORY_PREFIX}${threadId}`,
239
+ );
240
+ if (rows.length === 0) return [];
241
+ const { Message: MessageClass } = await import("chat");
242
+ return rows.map((row) => MessageClass.fromJSON(row));
243
+ }