@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,315 @@
1
+ /**
2
+ * Model profiles: a named (harness, model, effort) picked per task (`profile`)
3
+ * or applied as an agent's default (agent-scoped `MODEL_PROFILE` config row).
4
+ * Claim resolves them (`src/be/model-tier-resolution.ts`). See
5
+ * runbooks/model-tiers.md § Model profiles.
6
+ */
7
+ import {
8
+ type ModelProfile,
9
+ type ProviderName,
10
+ ProviderNameSchema,
11
+ type ReasoningEffort,
12
+ ReasoningEffortSchema,
13
+ } from "../../types";
14
+ import { vcsRepoName, vcsRepoUrlMatches } from "../../utils/vcs-repo-match";
15
+ import { getDbClient } from "./runtime";
16
+ import { SUPERSEDED_RESUME_REPAIR_WINDOW_MS } from "./tasks/read";
17
+
18
+ /** Agent-scoped swarm_config key holding the agent's default profile name. */
19
+ export const MODEL_PROFILE_CONFIG_KEY = "MODEL_PROFILE";
20
+
21
+ type ModelProfileRow = {
22
+ id: string;
23
+ name: string;
24
+ harness: string;
25
+ model: string;
26
+ effort: string | null;
27
+ allowCustomModel: number;
28
+ description: string | null;
29
+ seededFrom: string | null;
30
+ createdAt: string;
31
+ lastUpdatedAt: string;
32
+ };
33
+
34
+ function rowToModelProfile(row: ModelProfileRow): ModelProfile {
35
+ return {
36
+ id: row.id,
37
+ name: row.name,
38
+ harness: ProviderNameSchema.parse(row.harness),
39
+ model: row.model,
40
+ effort: ReasoningEffortSchema.safeParse(row.effort).success
41
+ ? (row.effort as ReasoningEffort)
42
+ : null,
43
+ allowCustomModel: row.allowCustomModel === 1,
44
+ description: row.description,
45
+ seededFrom: row.seededFrom,
46
+ createdAt: row.createdAt,
47
+ lastUpdatedAt: row.lastUpdatedAt,
48
+ };
49
+ }
50
+
51
+ export async function listModelProfiles(
52
+ filter: { harness?: ProviderName } = {},
53
+ ): Promise<ModelProfile[]> {
54
+ const rows = filter.harness
55
+ ? await getDbClient().query<ModelProfileRow>(
56
+ "SELECT * FROM model_profiles WHERE harness = ? ORDER BY harness, name",
57
+ [filter.harness],
58
+ )
59
+ : await getDbClient().query<ModelProfileRow>(
60
+ "SELECT * FROM model_profiles ORDER BY harness, name",
61
+ );
62
+ return rows.map(rowToModelProfile);
63
+ }
64
+
65
+ export async function getModelProfileByName(name: string): Promise<ModelProfile | null> {
66
+ const row = await getDbClient().get<ModelProfileRow>(
67
+ "SELECT * FROM model_profiles WHERE name = ?",
68
+ [name.trim()],
69
+ );
70
+ return row ? rowToModelProfile(row) : null;
71
+ }
72
+
73
+ export interface ModelProfileInput {
74
+ name: string;
75
+ harness: ProviderName;
76
+ model: string;
77
+ effort?: ReasoningEffort | null;
78
+ allowCustomModel?: boolean;
79
+ description?: string | null;
80
+ seededFrom?: string | null;
81
+ }
82
+
83
+ /** Insert a profile. Returns null when the name is taken. */
84
+ export async function createModelProfile(
85
+ input: ModelProfileInput,
86
+ audit: { userId?: string | null } = {},
87
+ ): Promise<ModelProfile | null> {
88
+ const now = new Date().toISOString();
89
+ const row = await getDbClient().get<ModelProfileRow>(
90
+ `INSERT INTO model_profiles
91
+ (id, name, harness, model, effort, allowCustomModel, description, seededFrom, createdAt, lastUpdatedAt, created_by, updated_by)
92
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
93
+ ON CONFLICT(name) DO NOTHING
94
+ RETURNING *`,
95
+ [
96
+ crypto.randomUUID(),
97
+ input.name,
98
+ input.harness,
99
+ input.model,
100
+ input.effort ?? null,
101
+ input.allowCustomModel ? 1 : 0,
102
+ input.description ?? null,
103
+ input.seededFrom ?? null,
104
+ now,
105
+ now,
106
+ audit.userId ?? null,
107
+ audit.userId ?? null,
108
+ ],
109
+ );
110
+ return row ? rowToModelProfile(row) : null;
111
+ }
112
+
113
+ export type ModelProfilePatch = Partial<
114
+ Pick<ModelProfileInput, "model" | "effort" | "allowCustomModel" | "description">
115
+ >;
116
+
117
+ /** Update a profile's model, effort or description. The name and harness are fixed. */
118
+ export async function updateModelProfile(
119
+ name: string,
120
+ patch: ModelProfilePatch,
121
+ audit: { userId?: string | null } = {},
122
+ ): Promise<ModelProfile | null> {
123
+ const sets: string[] = [];
124
+ const params: (string | number | null)[] = [];
125
+ if (patch.model !== undefined) {
126
+ sets.push("model = ?");
127
+ params.push(patch.model);
128
+ }
129
+ if (patch.effort !== undefined) {
130
+ sets.push("effort = ?");
131
+ params.push(patch.effort);
132
+ }
133
+ if (patch.allowCustomModel !== undefined) {
134
+ sets.push("allowCustomModel = ?");
135
+ params.push(patch.allowCustomModel ? 1 : 0);
136
+ }
137
+ if (patch.description !== undefined) {
138
+ sets.push("description = ?");
139
+ params.push(patch.description);
140
+ }
141
+ sets.push("lastUpdatedAt = ?", "updated_by = ?");
142
+ params.push(new Date().toISOString(), audit.userId ?? null);
143
+ const row = await getDbClient().get<ModelProfileRow>(
144
+ `UPDATE model_profiles SET ${sets.join(", ")} WHERE name = ? RETURNING *`,
145
+ [...params, name],
146
+ );
147
+ return row ? rowToModelProfile(row) : null;
148
+ }
149
+
150
+ /**
151
+ * Tasks (alias `t`) that still hold their profile: unfinished ones, and
152
+ * superseded ones still owed a resume. The resume copies the profile in a
153
+ * later write than the supersede (HTTP supersede, heartbeat remediation), and
154
+ * after a restart the heartbeat's orphan repair makes it, inside the same
155
+ * window (`SUPERSEDED_RESUME_REPAIR_WINDOW_MS`). Binds one parameter: the
156
+ * oldest `finishedAt` the repair still covers.
157
+ */
158
+ const TASK_HOLDS_PROFILE_SQL = `(
159
+ t.status NOT IN ('completed', 'failed', 'cancelled', 'superseded')
160
+ OR (t.status = 'superseded'
161
+ AND t.workflowRunStepId IS NULL
162
+ AND (t.finishedAt IS NULL OR t.finishedAt > ?)
163
+ AND NOT EXISTS (
164
+ SELECT 1 FROM agent_tasks c WHERE c.parentTaskId = t.id AND c.taskType = 'resume')))`;
165
+
166
+ function repairWindowStart(): string {
167
+ return new Date(Date.now() - SUPERSEDED_RESUME_REPAIR_WINDOW_MS).toISOString();
168
+ }
169
+
170
+ /** Who still points at a profile: agents with it as default, and tasks that still hold it. */
171
+ export async function modelProfileReferences(
172
+ name: string,
173
+ ): Promise<{ agentIds: string[]; openTaskCount: number }> {
174
+ const agents = await getDbClient().query<{ scopeId: string }>(
175
+ "SELECT scopeId FROM swarm_config WHERE scope = 'agent' AND key = ? AND value = ?",
176
+ [MODEL_PROFILE_CONFIG_KEY, name],
177
+ );
178
+ const tasks = await getDbClient().get<{ n: number }>(
179
+ `SELECT COUNT(*) AS n FROM agent_tasks t WHERE t.profile = ? AND ${TASK_HOLDS_PROFILE_SQL}`,
180
+ [name, repairWindowStart()],
181
+ );
182
+ return { agentIds: agents.map((a) => a.scopeId), openTaskCount: tasks?.n ?? 0 };
183
+ }
184
+
185
+ /**
186
+ * Which migration-220 reference trigger refused a write: `missing` when a task
187
+ * or an agent default names a profile that does not exist.
188
+ */
189
+ export function modelProfileRefError(error: unknown): "missing" | null {
190
+ const message = error instanceof Error ? error.message : "";
191
+ return message.includes("model-profile-missing:") ? "missing" : null;
192
+ }
193
+
194
+ /**
195
+ * Delete a profile unless a task still holds it (`TASK_HOLDS_PROFILE_SQL`) or
196
+ * an agent default names it. The check is part of the DELETE statement, so a
197
+ * reference written after the caller's own count still makes it `in-use`; the
198
+ * triggers in migration 220 refuse the opposite order (a reference written
199
+ * after this delete).
200
+ */
201
+ export async function deleteModelProfile(name: string): Promise<"deleted" | "missing" | "in-use"> {
202
+ const row = await getDbClient().get<{ id: string }>(
203
+ `DELETE FROM model_profiles
204
+ WHERE name = ?
205
+ AND NOT EXISTS (
206
+ SELECT 1 FROM agent_tasks t
207
+ WHERE t.profile = model_profiles.name AND ${TASK_HOLDS_PROFILE_SQL})
208
+ AND NOT EXISTS (
209
+ SELECT 1 FROM swarm_config
210
+ WHERE scope = 'agent' AND key = ? AND trim(value) = model_profiles.name)
211
+ RETURNING id`,
212
+ [name, repairWindowStart(), MODEL_PROFILE_CONFIG_KEY],
213
+ );
214
+ if (row) return "deleted";
215
+ return (await getModelProfileByName(name)) ? "in-use" : "missing";
216
+ }
217
+
218
+ /** The agent's default profile name (agent-scoped MODEL_PROFILE), or null. */
219
+ export async function getAgentDefaultProfileName(agentId: string): Promise<string | null> {
220
+ const row = await getDbClient().get<{ value: string }>(
221
+ "SELECT value FROM swarm_config WHERE scope = 'agent' AND scopeId = ? AND key = ?",
222
+ [agentId, MODEL_PROFILE_CONFIG_KEY],
223
+ );
224
+ return row?.value.trim() || null;
225
+ }
226
+
227
+ /**
228
+ * Which of MODEL_OVERRIDE / REASONING_EFFORT_OVERRIDE the task's repo sets at
229
+ * repo scope, exported or not. The worker env takes a repo row over the
230
+ * agent's own (repo > agent), and a withheld one removes the key, so the
231
+ * agent's default profile must not supply that axis. Finds the repo the way
232
+ * the worker does (`fetchRepoConfig`). `includeSecrets: false` leaves out
233
+ * secret rows, as `/api/config/resolved` does for a worker that cannot read
234
+ * them (`readsRepoSecrets`): that worker's env never gets them.
235
+ */
236
+ export async function repoModelOverrideKeys(
237
+ vcsRepo: string | null | undefined,
238
+ { includeSecrets = true }: { includeSecrets?: boolean } = {},
239
+ ): Promise<Set<string>> {
240
+ if (!vcsRepo?.trim()) return new Set();
241
+ const repos = await getDbClient().query<{ id: string; url: string }>(
242
+ "SELECT id, url FROM swarm_repos WHERE name = ? ORDER BY name ASC",
243
+ [vcsRepoName(vcsRepo)],
244
+ );
245
+ const repo = repos.find((r) => vcsRepoUrlMatches(r.url, vcsRepo));
246
+ if (!repo) return new Set();
247
+ const rows = await getDbClient().query<{ key: string }>(
248
+ `SELECT key FROM swarm_config
249
+ WHERE scope = 'repo' AND scopeId = ? AND key IN ('MODEL_OVERRIDE', 'REASONING_EFFORT_OVERRIDE')
250
+ ${includeSecrets ? "" : "AND isSecret = 0"}`,
251
+ [repo.id],
252
+ );
253
+ return new Set(rows.map((row) => row.key));
254
+ }
255
+
256
+ /**
257
+ * Why a task cannot ask for `profile`, or null when it can. PR 1 validity is
258
+ * the harness only: the profile must exist and, when the target agent is known
259
+ * and has a harness, run on that harness. `profile` is exclusive with `model`
260
+ * and `modelTier`, which pick the model another way.
261
+ */
262
+ export async function taskProfileError(check: {
263
+ profile?: string | null;
264
+ model?: string | null;
265
+ modelTier?: string | null;
266
+ agentId?: string | null;
267
+ }): Promise<string | null> {
268
+ const name = check.profile?.trim();
269
+ if (!name) return null;
270
+ if (check.model?.trim() || check.modelTier?.trim()) {
271
+ return "Pass `profile`, or `model`/`modelTier`, not both.";
272
+ }
273
+ const profile = await getModelProfileByName(name);
274
+ if (!profile) {
275
+ return `Unknown model profile "${name}". List profiles with list-model-profiles.`;
276
+ }
277
+ if (!check.agentId) return null;
278
+ const agent = await getDbClient().get<{ harness: string | null }>(
279
+ "SELECT COALESCE(harness_provider, provider) AS harness FROM agents WHERE id = ?",
280
+ [check.agentId],
281
+ );
282
+ if (agent?.harness && agent.harness !== profile.harness) {
283
+ return `Model profile "${name}" runs on the ${profile.harness} harness; the target agent runs ${agent.harness}.`;
284
+ }
285
+ return null;
286
+ }
287
+
288
+ type OverrideRowState = { value: string; exportToEnv?: number } | null;
289
+
290
+ /** What a config row does to the worker env: its value, withheld (exportToEnv off), or absent. */
291
+ function effectiveOverride(row: OverrideRowState): string | null {
292
+ if (!row) return null;
293
+ return row.exportToEnv === 0 ? "\u0000withheld" : row.value;
294
+ }
295
+
296
+ /**
297
+ * An agent's default model profile (MODEL_PROFILE) beats its MODEL_OVERRIDE and
298
+ * REASONING_EFFORT_OVERRIDE at claim. An effective change to either override, by
299
+ * any path, drops the profile default, so a stale default never beats a fresh
300
+ * override. Effective means what the worker env sees: the value, and whether
301
+ * the row is exported (`exportToEnv`).
302
+ */
303
+ export async function clearAgentModelProfileOnOverrideChange(
304
+ agentId: string,
305
+ key: string,
306
+ before: OverrideRowState,
307
+ after: OverrideRowState,
308
+ ): Promise<void> {
309
+ if (key !== "MODEL_OVERRIDE" && key !== "REASONING_EFFORT_OVERRIDE") return;
310
+ if (effectiveOverride(before) === effectiveOverride(after)) return;
311
+ await getDbClient().run(
312
+ "DELETE FROM swarm_config WHERE scope = 'agent' AND scopeId = ? AND key = ?",
313
+ [agentId, MODEL_PROFILE_CONFIG_KEY],
314
+ );
315
+ }
@@ -0,0 +1,15 @@
1
+ import { getDbClient } from "./runtime";
2
+
3
+ /**
4
+ * The page's edit counter, `MAX(page_versions.version) + 1`, or 1 before the
5
+ * first snapshot. Reads one indexed aggregate instead of every snapshot body:
6
+ * loading all versions of a large, often-edited page blocked the event loop
7
+ * for seconds per call.
8
+ */
9
+ export async function getPageEditCounter(pageId: string): Promise<number> {
10
+ const row = await getDbClient().get<{ latest: number | null }>(
11
+ "SELECT MAX(version) AS latest FROM page_versions WHERE pageId = ?",
12
+ [pageId],
13
+ );
14
+ return (row?.latest ?? 0) + 1;
15
+ }
@@ -104,7 +104,34 @@ export function initDb(dbPath = "./agent-swarm-db.sqlite"): Database {
104
104
  db = new Database(dbPath, { create: true });
105
105
  console.log(`Database initialized at ${dbPath}`);
106
106
 
107
- const database = db;
107
+ // Boot must finish before getDb() hands this handle out. A step below can
108
+ // throw SQLITE_BUSY while another connection holds the file, and the
109
+ // db-client retries BUSY by calling getDb() again. With `db` still assigned,
110
+ // that retry got a connection whose encryption key was never resolved, and
111
+ // the server died on "Encryption key not resolved yet". Drop the handle so
112
+ // the retry runs boot again.
113
+ const opened = db;
114
+ try {
115
+ return bootOpenedDb(opened, dbPath, resolvePromptTemplate, autoEncryptLegacyPlaintextSecrets);
116
+ } catch (error) {
117
+ if (db === opened) {
118
+ db = null;
119
+ try {
120
+ opened.close();
121
+ } catch {
122
+ // Already closed by the step that failed.
123
+ }
124
+ }
125
+ throw error;
126
+ }
127
+ }
128
+
129
+ function bootOpenedDb(
130
+ database: Database,
131
+ dbPath: string,
132
+ resolvePromptTemplate: typeof import("../db").resolvePromptTemplate,
133
+ autoEncryptLegacyPlaintextSecrets: typeof import("../db").autoEncryptLegacyPlaintextSecrets,
134
+ ): Database {
108
135
  database.run("PRAGMA journal_mode = WAL;");
109
136
  database.run("PRAGMA busy_timeout = 5000;");
110
137
  database.run("PRAGMA foreign_keys = ON;");
@@ -140,7 +167,7 @@ export function initDb(dbPath = "./agent-swarm-db.sqlite"): Database {
140
167
  // Old databases have CHECK(status IN ('pending','in_progress','completed','failed'))
141
168
  // which blocks 'cancelled', 'paused', 'offered', 'unassigned' statuses
142
169
  try {
143
- const taskSchemaInfo = db
170
+ const taskSchemaInfo = database
144
171
  .prepare<{ sql: string | null }, []>(
145
172
  "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'agent_tasks'",
146
173
  )
@@ -153,7 +180,7 @@ export function initDb(dbPath = "./agent-swarm-db.sqlite"): Database {
153
180
 
154
181
  if (needsStatusMigration) {
155
182
  console.log("[Migration] Removing restrictive CHECK constraint on agent_tasks.status");
156
- db.run("PRAGMA foreign_keys=off");
183
+ database.run("PRAGMA foreign_keys=off");
157
184
 
158
185
  // Migrations run before this compatibility guard, so a legacy table now
159
186
  // carries every current column. Rebuilding from an old hard-coded column
@@ -169,12 +196,12 @@ export function initDb(dbPath = "./agent-swarm-db.sqlite"): Database {
169
196
  if (rebuiltSchemaSql === schemaSql || !/agent_tasks_new/i.test(rebuiltSchemaSql)) {
170
197
  throw new Error("Could not derive agent_tasks schema without legacy status CHECK");
171
198
  }
172
- const columns = db
199
+ const columns = database
173
200
  .prepare<{ name: string }, []>('PRAGMA table_info("agent_tasks")')
174
201
  .all()
175
202
  .map((column) => `"${column.name.replaceAll('"', '""')}"`)
176
203
  .join(", ");
177
- const schemaObjects = db
204
+ const schemaObjects = database
178
205
  .prepare<{ sql: string }, []>(
179
206
  `SELECT sql FROM sqlite_master
180
207
  WHERE tbl_name = 'agent_tasks'
@@ -194,13 +221,13 @@ export function initDb(dbPath = "./agent-swarm-db.sqlite"): Database {
194
221
  for (const sql of schemaObjects) database.run(sql);
195
222
  })();
196
223
 
197
- db.run("PRAGMA foreign_keys=on");
224
+ database.run("PRAGMA foreign_keys=on");
198
225
  console.log("[Migration] Successfully removed CHECK constraint on agent_tasks.status");
199
226
  }
200
227
  } catch (e) {
201
228
  console.error("[Migration] Failed to update agent_tasks CHECK constraint:", e);
202
229
  try {
203
- db.run("PRAGMA foreign_keys=on");
230
+ database.run("PRAGMA foreign_keys=on");
204
231
  } catch (cleanupError) {
205
232
  console.error("[Migration] Failed to re-enable SQLite foreign_keys pragma:", cleanupError);
206
233
  }
@@ -291,7 +318,7 @@ export function initDb(dbPath = "./agent-swarm-db.sqlite"): Database {
291
318
  throw err;
292
319
  }
293
320
 
294
- return db;
321
+ return database;
295
322
  }
296
323
 
297
324
  export function getDb(path?: string): Database {
@@ -0,0 +1,36 @@
1
+ import { getDbClient } from "./runtime";
2
+
3
+ export type SwarmSkillNameResolution =
4
+ | { kind: "found"; skillId: string }
5
+ | { kind: "ambiguous"; skillIds: string[] }
6
+ | { kind: "none" };
7
+
8
+ /**
9
+ * Resolve a swarm-scope skill name for `skill-get`.
10
+ *
11
+ * Migration 019 makes a name unique only per scope + owner, so a swarm name can
12
+ * match one ownerless row plus any number of agent-owned rows. Precedence:
13
+ * the ownerless row, then the caller's own row, then a single owned row.
14
+ * Several foreign-owned rows are ambiguous; the caller must pass a skillId.
15
+ *
16
+ * `getSkillByName(name, "swarm")` stays ownerless-only: the seeder relies on it.
17
+ */
18
+ export async function resolveSwarmSkillByName(
19
+ name: string,
20
+ callerAgentId?: string,
21
+ ): Promise<SwarmSkillNameResolution> {
22
+ const rows = await getDbClient().query<{ id: string; ownerAgentId: string | null }>(
23
+ "SELECT id, ownerAgentId FROM skills WHERE name = ? AND scope = 'swarm' ORDER BY createdAt, id",
24
+ [name],
25
+ );
26
+
27
+ const ownerless = rows.find((row) => !row.ownerAgentId);
28
+ if (ownerless) return { kind: "found", skillId: ownerless.id };
29
+
30
+ const own = callerAgentId ? rows.find((row) => row.ownerAgentId === callerAgentId) : undefined;
31
+ if (own) return { kind: "found", skillId: own.id };
32
+
33
+ if (rows.length === 1) return { kind: "found", skillId: rows[0]!.id };
34
+ if (rows.length > 1) return { kind: "ambiguous", skillIds: rows.map((row) => row.id) };
35
+ return { kind: "none" };
36
+ }