@desplega.ai/agent-swarm 1.165.0 → 1.167.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 (296) hide show
  1. package/dist/acp-adapter-zpvy6321.js +34 -0
  2. package/dist/{actions-jna0b3wm.js → actions-fq2zrwtf.js} +30 -34
  3. package/dist/{amp-adapter-0eve81pz.js → amp-adapter-5gbk7501.js} +7 -7
  4. package/dist/{anthropic-messages-hst62ws9.js → anthropic-messages-13yn502s.js} +4 -4
  5. package/dist/{app-75hm5cfa.js → app-nctetn1e.js} +11 -11
  6. package/dist/{assistant-yzd51j33.js → assistant-0aq8gjvj.js} +31 -35
  7. package/dist/{azure-openai-responses-mh8tvf78.js → azure-openai-responses-9st34pfz.js} +5 -5
  8. package/dist/{boot-reembed-z158xq32.js → boot-reembed-1ze5853n.js} +14 -16
  9. package/dist/{boot-reembed-2ex2mcsh.js → boot-reembed-fmp5ww69.js} +15 -16
  10. package/dist/boot-scrub-sweep-cbp8xd4e.js +212 -0
  11. package/dist/{boot-seeds-2bmnh18p.js → boot-seeds-22tx8a53.js} +13 -12
  12. package/dist/{claude-adapter-jbj1mycz.js → claude-adapter-0jhgeh1d.js} +25 -25
  13. package/dist/{claude-managed-adapter-17ggz09t.js → claude-managed-adapter-tzwxy803.js} +5 -5
  14. package/dist/{claude-managed-setup-ptm1nzm2.js → claude-managed-setup-nrhfx5b0.js} +5 -5
  15. package/dist/{claude-sdk-session-9re1g7r2.js → claude-sdk-session-wh77rh83.js} +2632 -2614
  16. package/dist/{cli-zsh093hk.js → cli-014vns2y.js} +63 -1
  17. package/dist/{cli-qvfk83fy.js → cli-13xwcqvj.js} +2 -2
  18. package/dist/{cli-8gpbwy09.js → cli-1yrcfa5s.js} +5 -5
  19. package/dist/{cli-xtgtyafv.js → cli-577bxkf6.js} +212 -451
  20. package/dist/{cli-ma3zvh39.js → cli-5qkcdv8c.js} +6118 -5874
  21. package/dist/{cli-cwxhbf43.js → cli-5t5my0h8.js} +85 -2
  22. package/dist/{cli-zvckv750.js → cli-69egj654.js} +2 -2
  23. package/dist/{cli-9xb89xca.js → cli-6bpvv8h4.js} +9 -9
  24. package/dist/{cli-90v942q1.js → cli-6qxmjpem.js} +8 -8
  25. package/dist/{cli-9866bd07.js → cli-6vfz44sr.js} +1 -1
  26. package/dist/{cli-32bca7nr.js → cli-7avy4v8w.js} +1 -1
  27. package/dist/{cli-xb3c6aat.js → cli-7mhy3ths.js} +21 -18
  28. package/dist/{cli-q38n4bq0.js → cli-95zs84qw.js} +3 -3
  29. package/dist/cli-a35hzdve.js +33 -0
  30. package/dist/{cli-x3x0qwky.js → cli-bxqez1p0.js} +51 -23
  31. package/dist/{cli-prt9emct.js → cli-c2tpw9ck.js} +3 -3
  32. package/dist/{cli-0n4fasz0.js → cli-c8r99akr.js} +16 -16
  33. package/dist/{cli-5anb0ev3.js → cli-cexctgn5.js} +89 -26
  34. package/dist/{cli-bns5c8k9.js → cli-cf2vgn9d.js} +105 -91
  35. package/dist/{cli-ng97fjq7.js → cli-cmxkbzzs.js} +33 -7
  36. package/dist/{cli-nexwh8zg.js → cli-g7k7zbcz.js} +12 -5
  37. package/dist/{cli-mmzwwptd.js → cli-hf5s9pgf.js} +1 -1
  38. package/dist/{cli-nvvfd8bq.js → cli-jbzbr36n.js} +4091 -3793
  39. package/dist/{cli-zn2v3t8v.js → cli-jvmtxqtc.js} +27 -15
  40. package/dist/{cli-pkke6geq.js → cli-km4x66j0.js} +83 -65
  41. package/dist/cli-kw0jcfje.js +516 -0
  42. package/dist/{cli-28smfvbn.js → cli-m7vmeepg.js} +32 -19
  43. package/dist/{cli-hpryr6em.js → cli-mb75wpxf.js} +1 -1
  44. package/dist/{cli-qdv8kgz7.js → cli-mkdsy1nq.js} +14018 -3333
  45. package/dist/{cli-b0f70z24.js → cli-mn8qkd8v.js} +1 -1
  46. package/dist/{cli-420bdgw0.js → cli-mv2520nm.js} +1 -1
  47. package/dist/{cli-n9ehc28t.js → cli-mxry91sa.js} +31 -10
  48. package/dist/{cli-wfajtmf7.js → cli-mxvnnv5q.js} +596 -13
  49. package/dist/cli-nkqjj42q.js +104 -0
  50. package/dist/{cli-e7t4snpa.js → cli-p8rt8spp.js} +5 -5
  51. package/dist/{cli-gh5yqzpe.js → cli-pkj1w46r.js} +12 -7
  52. package/dist/cli-q1vnz8wv.js +96 -0
  53. package/dist/{cli-fj86xr3c.js → cli-qd97v6z2.js} +2 -2
  54. package/dist/{cli-ba66wyhy.js → cli-qzmzwegq.js} +60 -20
  55. package/dist/{cli-5b2fjjzh.js → cli-r7eeddkq.js} +14 -9
  56. package/dist/{cli-8ssjez7e.js → cli-rhy7z1rp.js} +22 -11
  57. package/dist/{cli-4mevd1hf.js → cli-s9y81s7j.js} +5 -5
  58. package/dist/{cli-59jn5twa.js → cli-tc5zec7v.js} +7 -7
  59. package/dist/{cli-ttbsse3f.js → cli-tmhsxhb8.js} +1 -1
  60. package/dist/{cli-k6xx3pve.js → cli-tx2zvn23.js} +4 -4
  61. package/dist/{cli-pjxnr1jn.js → cli-ty4bzkqr.js} +5 -5
  62. package/dist/{cli-nfygw434.js → cli-v1pwxreq.js} +55 -52
  63. package/dist/{cli-ftry7975.js → cli-v1w7pbd8.js} +3 -2
  64. package/dist/{cli-10zmp1p7.js → cli-vr5avem2.js} +27 -32
  65. package/dist/{cli-bzr0ftht.js → cli-wnb9b2g3.js} +19 -0
  66. package/dist/cli-wt7ccy4r.js +2654 -0
  67. package/dist/{cli-50eg13rj.js → cli-wydz3feg.js} +549 -321
  68. package/dist/{cli-krqm5f11.js → cli-xezn9nkh.js} +16 -13
  69. package/dist/{cli-8kt0bmgx.js → cli-xf713zz0.js} +2 -2
  70. package/dist/{cli-x7afk5wm.js → cli-xvc3q9br.js} +1 -1
  71. package/dist/{cli-9s3h836g.js → cli-xvdgasgy.js} +1 -1
  72. package/dist/{cli-j0pdrmwg.js → cli-y0kjpfm9.js} +3 -3
  73. package/dist/{cli-6zcfw0x7.js → cli-y195hv1a.js} +1 -1
  74. package/dist/{cli-amwhs8h2.js → cli-ykt8f7va.js} +22 -9
  75. package/dist/{cli-1kzfvd1z.js → cli-ymmc1zxg.js} +15 -11
  76. package/dist/{cli-xnzrzets.js → cli-ypgba1a8.js} +2 -2
  77. package/dist/{cli-bdv39kgj.js → cli-z1dqhc9y.js} +31 -20
  78. package/dist/{cli-fw6vdcq5.js → cli-zp67qg5x.js} +34 -1
  79. package/dist/{cli-qbksc292.js → cli-zy39d433.js} +2 -0
  80. package/dist/cli.js +36 -32
  81. package/dist/{cloudflare-workers-ai-system-one-tt484t61.js → cloudflare-workers-ai-system-one-sta45jf9.js} +7 -5
  82. package/dist/{codex-adapter-3qnxshje.js → codex-adapter-cgesnjkr.js} +20 -20
  83. package/dist/{codex-login-brkxhhdg.js → codex-login-g1cyt5zm.js} +2 -2
  84. package/dist/{codex-session-runner-612wnapp.js → codex-session-runner-8kd7ddhr.js} +20 -20
  85. package/dist/{commands-2ybfcxkj.js → commands-h6zaaxym.js} +11 -10
  86. package/dist/{cursor-adapter-p3jgdehv.js → cursor-adapter-v8mm6bp5.js} +7 -7
  87. package/dist/{db-f4ans0jj.js → db-qg3myn53.js} +13 -10
  88. package/dist/{devin-adapter-dhzt01ff.js → devin-adapter-bffjj5n4.js} +2 -2
  89. package/dist/{dispatcher-pk182apd.js → dispatcher-7vnwj9qw.js} +28 -32
  90. package/dist/{dsh-adapter-7twaeps1.js → dsh-adapter-tz6hfp5r.js} +7 -7
  91. package/dist/{e2b-y8t3jzyz.js → e2b-nd50eccg.js} +1 -1
  92. package/dist/{easter-egg-3d-mtpnw06s.js → easter-egg-3d-66zxervv.js} +2 -2
  93. package/dist/{event-bus-w7ac4n3c.js → event-bus-vnfthafg.js} +2 -2
  94. package/dist/{execute-s4ccjq3n.js → execute-h4jgevyw.js} +61 -11
  95. package/dist/{google-generative-ai-d6nphg3q.js → google-generative-ai-b8zxrpax.js} +5 -5
  96. package/dist/{google-vertex-cpshkref.js → google-vertex-nrdd697t.js} +5 -5
  97. package/dist/grok-adapter-jdt2dz2s.js +39 -0
  98. package/dist/{handlers-g2wnr4t9.js → handlers-2qtkpncr.js} +31 -35
  99. package/dist/{hook-f7jt9vnm.js → hook-51yfcgsv.js} +48 -39
  100. package/dist/{hook-bbdpnkb4.js → hook-qnbdgwvd.js} +15 -17
  101. package/dist/{http-w40q4w94.js → http-jsmtag08.js} +536 -231
  102. package/dist/{index-056j5kzn.js → index-2t9kesn1.js} +13 -12
  103. package/dist/{index-cj1r9q83.js → index-bt8wkv1w.js} +29 -33
  104. package/dist/{index-7n70jwbb.js → index-cx1sb9bq.js} +42 -35
  105. package/dist/{index-9bfssf54.js → index-ekywyv2v.js} +28 -32
  106. package/dist/{index-fdk1t4d6.js → index-n0rxa4ca.js} +11962 -9900
  107. package/dist/{index-k8xc083e.js → index-t4g06w93.js} +28 -32
  108. package/dist/{keepalive-1tj10tf4.js → keepalive-4aezx4bj.js} +16 -12
  109. package/dist/{lead-st0bg7v4.js → lead-r44bkpm5.js} +52 -56
  110. package/dist/{llama-cpp-classify-tgj35k8d.js → llama-cpp-classify-6erb7wwv.js} +3 -1
  111. package/dist/{maintenance-nz71zats.js → maintenance-grz5jrzh.js} +12 -13
  112. package/dist/{mistral-conversations-8445ddjn.js → mistral-conversations-059y51zt.js} +4 -4
  113. package/dist/{node-f0ykebbv.js → node-qm9eb6z0.js} +25 -7
  114. package/dist/{oauth-refresh-sweep-aefzwvvq.js → oauth-refresh-sweep-wm4ctjfj.js} +15 -11
  115. package/dist/{onboard-kgpr9mbn.js → onboard-v60zgqf0.js} +2 -2
  116. package/dist/{openai-codex-responses-9ynm88zy.js → openai-codex-responses-jzxkta9b.js} +8 -7
  117. package/dist/{openai-completions-nhqwjmaw.js → openai-completions-663yncfq.js} +4 -4
  118. package/dist/openai-decisions-vj9nkpf8.js +162 -0
  119. package/dist/{openai-responses-xx1c4kgm.js → openai-responses-m3g43rrt.js} +5 -5
  120. package/dist/{opencode-adapter-0c8e70dk.js → opencode-adapter-yjyqynzf.js} +8 -8
  121. package/dist/{openrouter-images-8yx3487g.js → openrouter-images-kr60n6b9.js} +1 -1
  122. package/dist/{otel-impl-x8zp4y5a.js → otel-impl-ghh4dyf8.js} +2 -2
  123. package/dist/{pi-messages-vxdt8v7j.js → pi-messages-xszk613n.js} +1 -1
  124. package/dist/{pi-mono-adapter-t280ah5c.js → pi-mono-adapter-0eg8kw2c.js} +69 -52
  125. package/dist/{pricing-refresh-9e0q7cwk.js → pricing-refresh-mjrqvnvw.js} +12 -11
  126. package/dist/{rbac-roles-790j3ga8.js → rbac-roles-axv4d74x.js} +11 -10
  127. package/dist/{rbac-roles-kcp6zge2.js → rbac-roles-fd5tskj9.js} +11 -10
  128. package/dist/{render-v2-tch4nefj.js → render-v2-k50j33qd.js} +11 -11
  129. package/dist/{runtime-v2t1r79e.js → runtime-h9ha1mq6.js} +4 -4
  130. package/dist/{setup-rcm303ns.js → setup-4syh0pd2.js} +2 -2
  131. package/dist/{typesafe-system-one-datfr82p.js → typesafe-system-one-e988vty7.js} +7 -5
  132. package/dist/{virtual-modules-wm8mxdxx.js → virtual-modules-ftr9kwe8.js} +11 -11
  133. package/dist/{work-objects-ctg7t70w.js → work-objects-jcdbg8rr.js} +32 -36
  134. package/dist/{worker-5dp0xm55.js → worker-x8j8c9sx.js} +52 -56
  135. package/dist/{x-v3yw66zs.js → x-ma4gnfgy.js} +2 -2
  136. package/openapi.json +5 -2
  137. package/package.json +15 -11
  138. package/src/be/automation-preflight.ts +9 -4
  139. package/src/be/boot-scrub-sweep.ts +302 -0
  140. package/src/be/crypto/key-bootstrap.ts +1 -1
  141. package/src/be/db/approvals.ts +15 -1
  142. package/src/be/db/codex-oauth-device-flows.ts +40 -0
  143. package/src/be/db/config-secrets.ts +31 -0
  144. package/src/be/db/runtime.ts +4 -0
  145. package/src/be/db/script-runs.ts +15 -0
  146. package/src/be/db/tasks/write.ts +1 -1
  147. package/src/be/db-queries/mcp-oauth.ts +5 -0
  148. package/src/be/db-queries/oauth.ts +77 -0
  149. package/src/be/db.ts +162 -59
  150. package/src/be/events.ts +17 -1
  151. package/src/be/memory/index-content.ts +2 -2
  152. package/src/be/memory/providers/openai-embedding.ts +7 -2
  153. package/src/be/memory/providers/sqlite-store.ts +63 -11
  154. package/src/be/memory/raters/llm-summarizer.ts +7 -2
  155. package/src/be/memory/types.ts +14 -0
  156. package/src/be/migrations/201_workflow_replay_columns.sql +10 -0
  157. package/src/be/migrations/202_codex_oauth_device_flows.sql +24 -0
  158. package/src/be/modelsdev-cache.json +61 -0
  159. package/src/be/scripts/db.ts +28 -4
  160. package/src/be/scripts/source-secrets.ts +37 -0
  161. package/src/be/scrub-json.ts +32 -0
  162. package/src/be/sealed-json.ts +59 -0
  163. package/src/be/secret-registry.ts +131 -0
  164. package/src/be/seed-pricing.ts +84 -53
  165. package/src/be/swarm-config-guard.ts +13 -0
  166. package/src/be/workflow-replay.ts +77 -0
  167. package/src/commands/provider-credentials.ts +28 -5
  168. package/src/commands/runner.ts +7 -12
  169. package/src/heartbeat/heartbeat.ts +91 -19
  170. package/src/hooks/hook.ts +72 -27
  171. package/src/http/codex-oauth-device.ts +8 -10
  172. package/src/http/db-query-bounded.ts +3 -0
  173. package/src/http/db-query-shared.ts +107 -15
  174. package/src/http/db-query.ts +10 -2
  175. package/src/http/index.ts +23 -6
  176. package/src/http/mcp.ts +5 -0
  177. package/src/http/onboarding.ts +2 -0
  178. package/src/http/script-runs.ts +9 -1
  179. package/src/http/scripts.ts +15 -0
  180. package/src/http/workflows.ts +3 -2
  181. package/src/oauth/mcp-wrapper.ts +1 -1
  182. package/src/providers/acp-adapter.ts +25 -11
  183. package/src/providers/acp-target-catalog.ts +35 -1
  184. package/src/providers/acp-targets.ts +78 -7
  185. package/src/providers/amp-adapter.ts +1 -1
  186. package/src/providers/claude-adapter.ts +26 -0
  187. package/src/providers/codex-adapter.ts +30 -3
  188. package/src/providers/codex-oauth/auth-json.ts +21 -4
  189. package/src/providers/codex-oauth/types.ts +2 -0
  190. package/src/providers/cursor-adapter.ts +1 -1
  191. package/src/providers/dsh-adapter.ts +10 -1
  192. package/src/providers/grok-adapter.ts +18 -2
  193. package/src/providers/opencode-adapter.ts +21 -5
  194. package/src/providers/pi-mono-extension.ts +56 -25
  195. package/src/providers/pricing-sources.md +2 -0
  196. package/src/script-workflows/supervisor.ts +11 -2
  197. package/src/scripts-runtime/eval-harness.ts +2 -12
  198. package/src/scripts-runtime/executors/quickjs-bundle.ts +152 -0
  199. package/src/scripts-runtime/executors/quickjs-prelude.ts +285 -0
  200. package/src/scripts-runtime/executors/quickjs-runner.ts +580 -0
  201. package/src/scripts-runtime/executors/quickjs-worker.ts +81 -0
  202. package/src/scripts-runtime/executors/quickjs.ts +196 -0
  203. package/src/scripts-runtime/executors/registry.ts +2 -0
  204. package/src/scripts-runtime/executors/sourcemap.ts +79 -0
  205. package/src/scripts-runtime/script-error-hints.ts +14 -0
  206. package/src/server.ts +66 -4
  207. package/src/tests/acp-adapter.test.ts +277 -12
  208. package/src/tests/boot-scrub-sweep.test.ts +390 -0
  209. package/src/tests/check-text-columns.test.ts +145 -0
  210. package/src/tests/ci-unit-test-report.test.ts +73 -0
  211. package/src/tests/claude-default-route.test.ts +75 -0
  212. package/src/tests/claude-hook-output.test.ts +233 -0
  213. package/src/tests/claude-sdk-process.fixture.ts +13 -2
  214. package/src/tests/codex-adapter-pool-auth-revalidate.test.ts +4 -2
  215. package/src/tests/codex-adapter.test.ts +166 -26
  216. package/src/tests/codex-oauth-auth-timestamps.test.ts +76 -0
  217. package/src/tests/codex-oauth-device.test.ts +23 -37
  218. package/src/tests/codex-oauth.test.ts +4 -1
  219. package/src/tests/context-window.test.ts +2 -2
  220. package/src/tests/credential-check.test.ts +51 -1
  221. package/src/tests/db-query-denylist.test.ts +202 -0
  222. package/src/tests/db-task-read-contract.test.ts +1 -0
  223. package/src/tests/db-task-write-contract.test.ts +1 -0
  224. package/src/tests/dsh-adapter.test.ts +23 -1
  225. package/src/tests/enabled-tools.test.ts +269 -0
  226. package/src/tests/entrypoint-acp-target-binary.test.ts +31 -1
  227. package/src/tests/entrypoint-codex-oauth-seed.test.ts +12 -0
  228. package/src/tests/events-scrub.test.ts +88 -0
  229. package/src/tests/fixtures/secret-corpus.ts +320 -0
  230. package/src/tests/grok-adapter.test.ts +13 -0
  231. package/src/tests/haiku-5-5-pricing.test.ts +38 -0
  232. package/src/tests/heartbeat-checklist.test.ts +158 -1
  233. package/src/tests/onboarding.test.ts +44 -0
  234. package/src/tests/opencode-adapter.test.ts +66 -3
  235. package/src/tests/opencode-plugin.test.ts +37 -0
  236. package/src/tests/openrouter-attribution-call-sites.test.ts +204 -0
  237. package/src/tests/openrouter-base-url.test.ts +30 -39
  238. package/src/tests/pi-mono-extension.test.ts +161 -2
  239. package/src/tests/pricing-refresh.test.ts +70 -1
  240. package/src/tests/reasoning-effort.test.ts +3 -1
  241. package/src/tests/script-connections.test.ts +5 -0
  242. package/src/tests/script-executor-conformance.test.ts +3 -0
  243. package/src/tests/script-executor-quickjs.test.ts +442 -0
  244. package/src/tests/script-executor-registry.test.ts +6 -1
  245. package/src/tests/script-runs-http.test.ts +88 -1
  246. package/src/tests/script-runs-scrub.test.ts +275 -0
  247. package/src/tests/scripts-http.test.ts +82 -1
  248. package/src/tests/scrubbed-text-12e.test.ts +289 -0
  249. package/src/tests/sealed-key-guard.test.ts +166 -0
  250. package/src/tests/secret-canary-sweep.test.ts +958 -0
  251. package/src/tests/secret-registry.test.ts +355 -0
  252. package/src/tests/secret-rules.test.ts +230 -0
  253. package/src/tests/secret-scrubber.test.ts +3 -2
  254. package/src/tests/telemetry-trigger.test.ts +12 -1
  255. package/src/tests/workflow-llm.test.ts +14 -0
  256. package/src/tests/workflow-replay.test.ts +518 -0
  257. package/src/tests/workflow-scrub.test.ts +242 -0
  258. package/src/tests/workflow-system-one-decision-providers.test.ts +33 -0
  259. package/src/tools/db-query.ts +1 -1
  260. package/src/tools/inject-learning.ts +1 -1
  261. package/src/tools/request-human-input.ts +7 -2
  262. package/src/tools/workflows/get-workflow-run.ts +3 -2
  263. package/src/types.ts +1 -1
  264. package/src/utils/enabled-tools.ts +27 -0
  265. package/src/utils/internal-ai/complete-structured.ts +11 -3
  266. package/src/utils/openrouter-base-url.ts +23 -0
  267. package/src/utils/secret-rules.generated.ts +2055 -0
  268. package/src/utils/secret-scrubber.ts +363 -29
  269. package/src/workflows/engine.ts +39 -4
  270. package/src/workflows/executors/raw-llm.ts +1 -0
  271. package/src/workflows/executors/system-one-decision.ts +2 -0
  272. package/src/workflows/executors/validate.ts +1 -0
  273. package/src/workflows/executors/workflow-llm.ts +9 -2
  274. package/src/workflows/recovery.ts +10 -1
  275. package/src/workflows/resume.ts +62 -3
  276. package/src/workflows/retry-poller.ts +3 -0
  277. package/templates/skills/agent-browser/SKILL.md +2 -0
  278. package/templates/skills/agent-browser/content.md +2 -0
  279. package/templates/skills/code-quality/content.md +1 -0
  280. package/templates/skills/heartbeat-runbook/content.md +1 -1
  281. package/templates/skills/work-on-task/SKILL.md +4 -0
  282. package/templates/skills/work-on-task/content.md +4 -0
  283. package/templates/skills/workflow-iterate/content.md +9 -0
  284. package/dist/acp-adapter-w6zws6me.js +0 -23
  285. package/dist/boot-scrub-logs-246yn076.js +0 -99
  286. package/dist/cli-3a4m1aws.js +0 -572
  287. package/dist/cli-3dpj7atn.js +0 -11
  288. package/dist/cli-a87b04k8.js +0 -951
  289. package/dist/cli-cvk6yzw5.js +0 -40
  290. package/dist/cli-gvcgmx69.js +0 -183
  291. package/dist/cli-h1spv8v4.js +0 -427
  292. package/dist/cli-jqt9hrnz.js +0 -168
  293. package/dist/cli-yhmwmv0g.js +0 -9281
  294. package/dist/grok-adapter-yt9pab3k.js +0 -29
  295. package/src/be/boot-scrub-logs.ts +0 -132
  296. package/dist/{codex-hook-d2rkvf39.js → codex-hook-15dgc4cb.js} +1 -1
@@ -0,0 +1,196 @@
1
+ import type { QuickJSWorkerMessage, QuickJSWorkerRequest } from "./quickjs-worker";
2
+ import type { ExecutorInput, ExecutorOutput, ScriptExecutor, ScriptExecutorError } from "./types";
3
+
4
+ /**
5
+ * Opt-in executor (`SCRIPT_EXECUTOR=quickjs`) that evaluates scripts in
6
+ * QuickJS compiled to WASM, inside a small pool of worker threads. There is
7
+ * no process spawn per run, so a short script costs about a millisecond
8
+ * instead of the native floor (~10 ms on Linux, ~35 ms on macOS).
9
+ *
10
+ * The sandbox has no filesystem, no process APIs, and no network except the
11
+ * host calls that the quickjs runner exposes (ctx.swarm, ctx.api, ctx.mcp,
12
+ * fetch). Every value crosses as JSON. See quickjs-runner.ts for the limits.
13
+ */
14
+
15
+ // Each worker keeps one QuickJS WASM module (~25 ms to load) and runs one job
16
+ // at a time. Jobs beyond the pool size wait in a queue.
17
+ const POOL_SIZE = 4;
18
+ // The worker enforces the wall clock itself. This margin only catches a
19
+ // worker that stopped answering, for example a host call that never settles.
20
+ const UNRESPONSIVE_GRACE_MS = 5_000;
21
+ // A worker's WASM memory keeps the peak of its largest job (up to memoryMb).
22
+ // Recycle a worker that grew past this, so idle workers stay small.
23
+ const RECYCLE_WASM_HEAP_BYTES = 64 * 1024 * 1024;
24
+
25
+ type Slot = { worker: Worker; ready: Promise<void>; busy: boolean };
26
+
27
+ /**
28
+ * In the compiled API binary every module's `import.meta.url` is the binary
29
+ * itself, and the extra worker entrypoint lives at its path relative to the
30
+ * entrypoints' common root (`src/`). See the Dockerfile compile step.
31
+ */
32
+ function workerSpecifier(): string {
33
+ if (import.meta.url.includes("/$bunfs/")) return "./scripts-runtime/executors/quickjs-worker.ts";
34
+ return new URL("./quickjs-worker.ts", import.meta.url).href;
35
+ }
36
+
37
+ function emptyOutput(error: ScriptExecutorError, stderr = ""): ExecutorOutput {
38
+ return {
39
+ result: undefined,
40
+ stdout: "",
41
+ stderr,
42
+ truncated: { stdout: false, stderr: false },
43
+ durationMs: 0,
44
+ exitCode: 1,
45
+ error,
46
+ };
47
+ }
48
+
49
+ class QuickJSWorkerPool {
50
+ private readonly slots: Slot[] = [];
51
+ private readonly waiters: Array<(slot: Slot) => void> = [];
52
+
53
+ constructor(private readonly size: number) {}
54
+
55
+ private spawn(): Slot {
56
+ const worker = new Worker(workerSpecifier());
57
+ // Idle workers must not keep the API process (or a test run) alive.
58
+ (worker as Worker & { unref?: () => void }).unref?.();
59
+ const ready = new Promise<void>((resolve, reject) => {
60
+ const onMessage = (event: MessageEvent<QuickJSWorkerMessage>) => {
61
+ if (event.data.type === "ready") resolve();
62
+ else if (event.data.type === "fatal" && event.data.id === undefined) {
63
+ reject(new Error(event.data.message));
64
+ } else return;
65
+ worker.removeEventListener("message", onMessage);
66
+ };
67
+ worker.addEventListener("message", onMessage);
68
+ worker.addEventListener("error", (event) => reject(new Error(event.message)), { once: true });
69
+ });
70
+ // A failed boot is reported to the job that waits on `ready`.
71
+ ready.catch(() => {});
72
+ const slot: Slot = { worker, ready, busy: true };
73
+ this.slots.push(slot);
74
+ return slot;
75
+ }
76
+
77
+ acquire(): Promise<Slot> {
78
+ const idle = this.slots.find((slot) => !slot.busy);
79
+ if (idle) {
80
+ idle.busy = true;
81
+ return Promise.resolve(idle);
82
+ }
83
+ if (this.slots.length < this.size) return Promise.resolve(this.spawn());
84
+ return new Promise((resolve) => this.waiters.push(resolve));
85
+ }
86
+
87
+ release(slot: Slot): void {
88
+ const waiter = this.waiters.shift();
89
+ if (waiter) waiter(slot);
90
+ else slot.busy = false;
91
+ }
92
+
93
+ /** Terminate a worker that is in an unknown state and hand its place to a waiter. */
94
+ get workerCount(): number {
95
+ return this.slots.length;
96
+ }
97
+
98
+ discard(slot: Slot): void {
99
+ slot.worker.terminate();
100
+ const index = this.slots.indexOf(slot);
101
+ if (index !== -1) this.slots.splice(index, 1);
102
+ const waiter = this.waiters.shift();
103
+ if (waiter) waiter(this.spawn());
104
+ }
105
+ }
106
+
107
+ let sharedPool: QuickJSWorkerPool | undefined;
108
+
109
+ /** Number of live workers in the shared pool. For tests and diagnostics. */
110
+ export function quickJSWorkerCount(): number {
111
+ return sharedPool?.workerCount ?? 0;
112
+ }
113
+ let requestSeq = 0;
114
+
115
+ export class QuickJSScriptExecutor implements ScriptExecutor {
116
+ readonly name = "quickjs";
117
+
118
+ async run(input: ExecutorInput): Promise<ExecutorOutput> {
119
+ if (input.fsMode === "workspace-rw") {
120
+ return emptyOutput("executor_error", "workspace-rw not supported by quickjs executor");
121
+ }
122
+ if (input.signal?.aborted) return emptyOutput("killed");
123
+
124
+ sharedPool ??= new QuickJSWorkerPool(POOL_SIZE);
125
+ const pool = sharedPool;
126
+ const slot = await pool.acquire();
127
+ if (input.signal?.aborted) {
128
+ pool.release(slot);
129
+ return emptyOutput("killed");
130
+ }
131
+ try {
132
+ await slot.ready;
133
+ } catch (error) {
134
+ pool.discard(slot);
135
+ return emptyOutput(
136
+ "executor_error",
137
+ `quickjs worker failed to start: ${error instanceof Error ? error.message : String(error)}`,
138
+ );
139
+ }
140
+
141
+ const id = ++requestSeq;
142
+ const start = performance.now();
143
+ return await new Promise<ExecutorOutput>((resolve) => {
144
+ let settled = false;
145
+ const settle = (output: ExecutorOutput, healthy: boolean) => {
146
+ if (settled) return;
147
+ settled = true;
148
+ clearTimeout(watchdog);
149
+ slot.worker.removeEventListener("message", onMessage);
150
+ slot.worker.removeEventListener("error", onError);
151
+ input.signal?.removeEventListener("abort", onAbort);
152
+ if (healthy) pool.release(slot);
153
+ else pool.discard(slot);
154
+ resolve(output);
155
+ };
156
+ const elapsed = () => Math.round(performance.now() - start);
157
+ const onMessage = (event: MessageEvent<QuickJSWorkerMessage>) => {
158
+ const message = event.data;
159
+ if (message.type === "result" && message.id === id) {
160
+ // Reuse the worker only if every host call settled and its memory stayed small.
161
+ const reusable =
162
+ message.leakedHostCalls === 0 &&
163
+ (message.wasmHeapBytes ?? 0) <= RECYCLE_WASM_HEAP_BYTES;
164
+ settle(message.output, reusable);
165
+ } else if (message.type === "fatal" && message.id === id) {
166
+ settle(
167
+ { ...emptyOutput("executor_error", message.message), durationMs: elapsed() },
168
+ false,
169
+ );
170
+ }
171
+ };
172
+ const onError = (event: ErrorEvent) => {
173
+ settle({ ...emptyOutput("executor_error", event.message), durationMs: elapsed() }, false);
174
+ };
175
+ // Terminating the worker is the hard kill: it also stops a busy loop.
176
+ const onAbort = () => settle({ ...emptyOutput("killed"), durationMs: elapsed() }, false);
177
+ const watchdog = setTimeout(
178
+ () => settle({ ...emptyOutput("timeout"), exitCode: 124, durationMs: elapsed() }, false),
179
+ input.resources.wallClockMs + UNRESPONSIVE_GRACE_MS,
180
+ );
181
+
182
+ slot.worker.addEventListener("message", onMessage);
183
+ slot.worker.addEventListener("error", onError);
184
+ input.signal?.addEventListener("abort", onAbort, { once: true });
185
+ slot.worker.postMessage({
186
+ id,
187
+ job: {
188
+ source: input.source,
189
+ args: input.args,
190
+ configPayload: input.configPayload,
191
+ resources: input.resources,
192
+ },
193
+ } satisfies QuickJSWorkerRequest);
194
+ });
195
+ }
196
+ }
@@ -1,8 +1,10 @@
1
1
  import { NativeScriptExecutor } from "./native";
2
+ import { QuickJSScriptExecutor } from "./quickjs";
2
3
  import type { ScriptExecutor } from "./types";
3
4
 
4
5
  const EXECUTORS: Record<string, () => ScriptExecutor> = {
5
6
  native: () => new NativeScriptExecutor(),
7
+ quickjs: () => new QuickJSScriptExecutor(),
6
8
  };
7
9
 
8
10
  export function getScriptExecutor(name = process.env.SCRIPT_EXECUTOR ?? "native"): ScriptExecutor {
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Minimal source map v3 reader for the quickjs executor. It maps a
3
+ * generated (line, column) back to the original source position so runtime
4
+ * errors point at the user's TypeScript, not at the bundled JavaScript.
5
+ *
6
+ * Lines and columns are 1-based on input and output, to match stack frames.
7
+ */
8
+
9
+ type Segment = { genColumn: number; source: number; line: number; column: number };
10
+
11
+ export type OriginalPosition = { source: string; line: number; column: number };
12
+
13
+ const BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
14
+ const BASE64_INDEX = new Map([...BASE64].map((char, index) => [char, index]));
15
+
16
+ function decodeVlq(segment: string): number[] {
17
+ const values: number[] = [];
18
+ let value = 0;
19
+ let shift = 0;
20
+ for (const char of segment) {
21
+ const digit = BASE64_INDEX.get(char);
22
+ if (digit === undefined) throw new Error(`invalid source map VLQ character: ${char}`);
23
+ value += (digit & 31) << shift;
24
+ if (digit & 32) {
25
+ shift += 5;
26
+ continue;
27
+ }
28
+ const negative = value & 1;
29
+ value >>>= 1;
30
+ values.push(negative ? -value : value);
31
+ value = 0;
32
+ shift = 0;
33
+ }
34
+ return values;
35
+ }
36
+
37
+ export class SourceMapReader {
38
+ private readonly sources: string[];
39
+ private readonly lines: Segment[][];
40
+
41
+ constructor(map: { sources: string[]; mappings: string }) {
42
+ this.sources = map.sources;
43
+ this.lines = [];
44
+ let source = 0;
45
+ let line = 0;
46
+ let column = 0;
47
+ for (const generatedLine of map.mappings.split(";")) {
48
+ const segments: Segment[] = [];
49
+ let genColumn = 0;
50
+ for (const raw of generatedLine.split(",")) {
51
+ if (!raw) continue;
52
+ const fields = decodeVlq(raw);
53
+ genColumn += fields[0] ?? 0;
54
+ if (fields.length < 4) continue;
55
+ source += fields[1] ?? 0;
56
+ line += fields[2] ?? 0;
57
+ column += fields[3] ?? 0;
58
+ segments.push({ genColumn, source, line, column });
59
+ }
60
+ this.lines.push(segments);
61
+ }
62
+ }
63
+
64
+ /** Look up the closest mapping at or before (line, column) on that line. */
65
+ originalPositionFor(line: number, column: number): OriginalPosition | undefined {
66
+ const segments = this.lines[line - 1];
67
+ if (!segments || segments.length === 0) return undefined;
68
+ let match: Segment | undefined;
69
+ for (const segment of segments) {
70
+ if (segment.genColumn > column - 1) break;
71
+ match = segment;
72
+ }
73
+ match ??= segments[0];
74
+ if (!match) return undefined;
75
+ const source = this.sources[match.source];
76
+ if (source === undefined) return undefined;
77
+ return { source, line: match.line + 1, column: match.column + 1 };
78
+ }
79
+ }
@@ -0,0 +1,14 @@
1
+ // Matches runtime errors that look like a swapped/misused (args, ctx) signature,
2
+ // e.g. destructuring `ctx.api`/`ctx.kv`/`ctx.fetchJson`/`ctx.log` off `undefined`/`null`
3
+ // because the script read them off `args` instead.
4
+ const CTX_UNDEFINED_ACCESS_RE = /cannot read propert(?:y|ies)(?: .*)? of (?:undefined|null)/i;
5
+ const CTX_MEMBER_RE = /\b(api|kv|fetchJson|log)\b/i;
6
+ const CTX_SIGNATURE_HINT =
7
+ "Hint: swarm scripts export default async function (args, ctx) — args comes first, ctx second.";
8
+
9
+ /** Shared by every script executor so structured errors carry the same hint. */
10
+ export function ctxSignatureHintFor(message: string): string | undefined {
11
+ return CTX_UNDEFINED_ACCESS_RE.test(message) && CTX_MEMBER_RE.test(message)
12
+ ? CTX_SIGNATURE_HINT
13
+ : undefined;
14
+ }
package/src/server.ts CHANGED
@@ -196,6 +196,7 @@ import {
196
196
  registerTriggerWorkflowTool,
197
197
  registerUpdateWorkflowTool,
198
198
  } from "./tools/workflows";
199
+ import { parseEnabledTools } from "./utils/enabled-tools";
199
200
  import { resolveScriptsOnlyMode } from "./utils/scripts-only-mode";
200
201
 
201
202
  // Every known capability, including the ones disabled by default. Exported for
@@ -293,18 +294,75 @@ export function isScriptsOnlyMcp(): boolean {
293
294
  return resolveScriptsOnlyMode({ env: process.env.SCRIPTS_ONLY_MCP });
294
295
  }
295
296
 
297
+ const loggedToolAllowlistWarnings = new Set<string>();
298
+
299
+ function warnToolAllowlistOnce(message: string): void {
300
+ if (loggedToolAllowlistWarnings.has(message)) return;
301
+ loggedToolAllowlistWarnings.add(message);
302
+ console.warn(message);
303
+ }
304
+
305
+ /**
306
+ * SWARM_ENABLED_TOOLS: an optional explicit allowlist for the externally
307
+ * exposed MCP surface. Returns undefined (capability-driven surface) when the
308
+ * value is unset, blank, or invalid. Never logs the raw value.
309
+ */
310
+ function resolveToolAllowlist(value: string | undefined): string[] | undefined {
311
+ if (value === undefined) return undefined;
312
+ try {
313
+ const tools = parseEnabledTools(value);
314
+ if (!tools) {
315
+ warnToolAllowlistOnce("[MCP] SWARM_ENABLED_TOOLS is set but lists no tools; ignoring it");
316
+ }
317
+ return tools;
318
+ } catch {
319
+ warnToolAllowlistOnce("[MCP] Invalid SWARM_ENABLED_TOOLS; ignoring it");
320
+ return undefined;
321
+ }
322
+ }
323
+
324
+ /** Drop every registered tool the allowlist does not name; warn on unknown names. */
325
+ function applyToolAllowlist(server: McpServer, allowlist: readonly string[]): void {
326
+ const tools = (server as unknown as { _registeredTools: Record<string, { remove(): void }> })
327
+ ._registeredTools;
328
+ const allowed = new Set(allowlist);
329
+ for (const [name, tool] of Object.entries(tools)) {
330
+ if (!allowed.has(name)) tool.remove();
331
+ }
332
+ const unknown = allowlist.filter((name) => !Object.hasOwn(tools, name));
333
+ if (unknown.length > 0) {
334
+ warnToolAllowlistOnce(
335
+ `[MCP] SWARM_ENABLED_TOOLS names unknown tools, ignoring them: ${unknown.join(", ")}`,
336
+ );
337
+ }
338
+ }
339
+
296
340
  export async function createServer(
297
- opts: { scriptsOnly?: boolean; fullSurface?: boolean; preloadedTools?: readonly string[] } = {},
341
+ opts: {
342
+ scriptsOnly?: boolean;
343
+ fullSurface?: boolean;
344
+ preloadedTools?: readonly string[];
345
+ /** Raw SWARM_ENABLED_TOOLS value for this session; defaults to the env. */
346
+ enabledTools?: string;
347
+ } = {},
298
348
  ) {
299
349
  // Reload env
300
350
  await loadGlobalConfigsIntoEnv(true);
301
351
 
352
+ // The tool allowlist replaces CAPABILITIES and SCRIPTS_ONLY_MCP when set.
353
+ // Full-surface consumers (the scripts SDK bridge) ignore it.
354
+ const toolAllowlist =
355
+ opts.fullSurface === true
356
+ ? undefined
357
+ : resolveToolAllowlist(opts.enabledTools ?? process.env.SWARM_ENABLED_TOOLS);
358
+
302
359
  // Capability flags shape the externally exposed MCP tool list only. Internal
303
360
  // full-surface consumers (the scripts SDK bridge, drift-check tests) pass
304
361
  // fullSurface to register every tool group regardless of CAPABILITIES.
362
+ // An allowlist also registers every group, then prunes to the listed names.
305
363
  // This shadows the module-level hasCapability for the registrations below.
306
364
  const hasCapability = (cap: CAPABILITIES_T): boolean =>
307
- opts.fullSurface === true || getCapabilities().has(cap);
365
+ opts.fullSurface === true || toolAllowlist !== undefined || getCapabilities().has(cap);
308
366
 
309
367
  // Initialize database with WAL mode
310
368
  // Uses DATABASE_PATH env var for Docker volume compatibility (WAL needs .sqlite, .sqlite-wal, .sqlite-shm on same filesystem)
@@ -355,7 +413,7 @@ export async function createServer(
355
413
  // Scripts-only surface (experimental code-mode): register just the script
356
414
  // catalog tools and stop. script-connections / script-apis stay out — they
357
415
  // are lead-only security admin and excluded from the scripts SDK too.
358
- if (opts.scriptsOnly ?? isScriptsOnlyMcp()) {
416
+ if (toolAllowlist === undefined && (opts.scriptsOnly ?? isScriptsOnlyMcp())) {
359
417
  registerScriptSearchTool(server);
360
418
  registerScriptRunTool(server);
361
419
  registerScriptUpsertTool(server);
@@ -392,7 +450,9 @@ export async function createServer(
392
450
  registerResolveUserTool(server);
393
451
  registerManageUserTool(server); // self-guards with lead check
394
452
 
395
- // Debug tools (self-guard with lead check)
453
+ // Debug tools. Neither has a lead check: both are open to every
454
+ // authenticated agent. db-query refuses credential tables and its results
455
+ // are scrubbed; get-oauth-access-token returns tokens by design.
396
456
  registerDbQueryTool(server);
397
457
  registerGetOauthAccessTokenTool(server);
398
458
 
@@ -628,5 +688,7 @@ export async function createServer(
628
688
  registerUpdateServiceStatusTool(server);
629
689
  }
630
690
 
691
+ if (toolAllowlist) applyToolAllowlist(server, toolAllowlist);
692
+
631
693
  return server;
632
694
  }