@desplega.ai/agent-swarm 2.6.0 → 2.7.1

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 (324) hide show
  1. package/README.md +2 -0
  2. package/dist/{acp-adapter-dgfakfpw.js → acp-adapter-8dn5tq56.js} +6 -6
  3. package/dist/{actions-fbqma8aa.js → actions-3r6gw7dy.js} +18 -18
  4. package/dist/{amp-adapter-en0jy6hs.js → amp-adapter-wjtq413p.js} +3 -3
  5. package/dist/{anthropic-messages-txs190dd.js → anthropic-messages-n4cby1rz.js} +4 -4
  6. package/dist/{app-k8a5cgpp.js → app-d53yhykk.js} +3 -3
  7. package/dist/{assistant-a16433gr.js → assistant-ksrawj3k.js} +20 -20
  8. package/dist/{boot-reembed-6c1sjfnr.js → boot-reembed-fxfw17m2.js} +11 -3
  9. package/dist/{boot-reembed-f4nn561n.js → boot-reembed-k5y5xbj0.js} +15 -8
  10. package/dist/{boot-scrub-sweep-d4w9gajf.js → boot-scrub-sweep-se41j9fd.js} +3 -3
  11. package/dist/{boot-seeds-9bmkspyw.js → boot-seeds-r3kwwv8b.js} +4 -4
  12. package/dist/{claude-adapter-nys1kjxa.js → claude-adapter-ahmyf231.js} +8 -8
  13. package/dist/{claude-managed-adapter-55207973.js → claude-managed-adapter-5knamegc.js} +3 -3
  14. package/dist/{claude-managed-setup-3cm35gey.js → claude-managed-setup-mdc7dy6b.js} +3 -3
  15. package/dist/{claude-sdk-session-nw5yd8cp.js → claude-sdk-session-n5wen9zk.js} +8729 -8600
  16. package/dist/{cli-683y0b3a.js → cli-0dqtv2jg.js} +2 -2
  17. package/dist/{cli-a34pr3w1.js → cli-0tww7dnz.js} +2 -2
  18. package/dist/{cli-w2656ka1.js → cli-0w4e4v58.js} +7 -7
  19. package/dist/{cli-5sckpqcx.js → cli-2sjm3t4r.js} +1 -1
  20. package/dist/{cli-gf2850q7.js → cli-3cywb44q.js} +18 -1
  21. package/dist/{cli-8wkb09q5.js → cli-3k9jej0c.js} +2 -2
  22. package/dist/{cli-3aqd4jaa.js → cli-3v2cyqb8.js} +3 -3
  23. package/dist/{cli-emhjcj2y.js → cli-5qt9vzmq.js} +89 -20
  24. package/dist/{cli-abkm71vr.js → cli-5rp1w4cr.js} +1 -1
  25. package/dist/{cli-gf95q3bm.js → cli-6vwjsetx.js} +4 -4
  26. package/dist/{cli-k21gx5ht.js → cli-6w2yrrc0.js} +10 -10
  27. package/dist/{cli-m70bajzr.js → cli-75tdydgv.js} +1 -1
  28. package/dist/{cli-5rj83bam.js → cli-8feswf2v.js} +47 -36
  29. package/dist/{cli-sxgtf5fw.js → cli-8wd3mbyj.js} +1 -1
  30. package/dist/{cli-ca6banwz.js → cli-9csfthbw.js} +10 -8
  31. package/dist/{cli-dqygeeh5.js → cli-b41p764a.js} +31 -3
  32. package/dist/{cli-m5a9m0ak.js → cli-c1t533hh.js} +3 -3
  33. package/dist/{cli-2sjhpsns.js → cli-c28jxpcv.js} +1 -1
  34. package/dist/{cli-bqztfyve.js → cli-cb50g9cd.js} +1 -1
  35. package/dist/{cli-ag2yrnt5.js → cli-d8gaphtr.js} +2 -2
  36. package/dist/{cli-9abdgn5t.js → cli-dgtfysne.js} +3 -3
  37. package/dist/{cli-nq677csy.js → cli-dscnhn18.js} +1 -1
  38. package/dist/{cli-3fwqy71j.js → cli-dv11pgpv.js} +39 -32
  39. package/dist/{cli-v49fkghp.js → cli-ekptgk2m.js} +6 -6
  40. package/dist/{cli-c2habvsf.js → cli-f3mzy662.js} +17 -17
  41. package/dist/{cli-zqne1qcj.js → cli-fk7k8s9x.js} +2 -2
  42. package/dist/{cli-1tem6ns9.js → cli-gt4h8cxw.js} +3 -2
  43. package/dist/{cli-vbhgkw9h.js → cli-h3e7bhvn.js} +3 -3
  44. package/dist/{cli-ffvsj2qw.js → cli-hkxqdmnb.js} +3 -3
  45. package/dist/{cli-a2rr0fmg.js → cli-hpkvgdad.js} +7 -4
  46. package/dist/{cli-art7c1zh.js → cli-hq2v4rr5.js} +37 -9
  47. package/dist/{cli-sqma6vw1.js → cli-k1zb7raw.js} +5 -5
  48. package/dist/{cli-4rvr7zfx.js → cli-k4awgvzm.js} +5 -0
  49. package/dist/{cli-3ndmpxxv.js → cli-k7d3hvya.js} +2 -2
  50. package/dist/{cli-3gfvmzht.js → cli-kbtdftbw.js} +74 -26
  51. package/dist/{cli-hfeb68z4.js → cli-kj69b9tw.js} +34 -6
  52. package/dist/{cli-az25fn5f.js → cli-kk9jy4nm.js} +2 -2
  53. package/dist/{cli-39aet655.js → cli-m52t4cta.js} +1 -1
  54. package/dist/{cli-cz37jqss.js → cli-mdadewqp.js} +5 -5
  55. package/dist/{cli-esakngh8.js → cli-nf6k60sn.js} +1 -1
  56. package/dist/{cli-j6rktc91.js → cli-nzdf09js.js} +1 -1
  57. package/dist/{cli-rr7zx19j.js → cli-prcyzecg.js} +12 -12
  58. package/dist/{cli-4hxrf0p4.js → cli-pzafyqtk.js} +393 -62
  59. package/dist/{cli-g8ka5j4j.js → cli-qvaa1gjp.js} +173 -52
  60. package/dist/{cli-d2dpf95n.js → cli-rg4b2g6j.js} +1 -1
  61. package/dist/{cli-kf4jree9.js → cli-rm66vqdz.js} +1 -1
  62. package/dist/{cli-4rf0f5vg.js → cli-s504c3w7.js} +5 -3
  63. package/dist/{cli-nn6vx2mq.js → cli-swkx9jm2.js} +7 -5
  64. package/dist/{cli-g20jjwt4.js → cli-thsaq4pd.js} +16 -16
  65. package/dist/{cli-aj8djyqt.js → cli-twjnyvs8.js} +2 -2
  66. package/dist/{cli-03gg9pd1.js → cli-typdpe8g.js} +4 -4
  67. package/dist/{cli-mtnj4fwa.js → cli-vg8pwmsd.js} +6 -6
  68. package/dist/{cli-gnsb1zxa.js → cli-vhpckzvp.js} +1 -1
  69. package/dist/{cli-7enjwya9.js → cli-vz78s5wm.js} +1 -1
  70. package/dist/{cli-dv97kdzv.js → cli-wdxgsdz5.js} +2 -2
  71. package/dist/{cli-7a6p4e65.js → cli-wtjg6je3.js} +1 -1
  72. package/dist/{cli-6y51ryva.js → cli-x3cngb1h.js} +44 -12
  73. package/dist/{cli-n7asmce6.js → cli-xbz6mcg4.js} +3 -3
  74. package/dist/{cli-24j1jeeb.js → cli-y4tdxsqb.js} +3 -3
  75. package/dist/{cli-mvjz5an3.js → cli-yqrsp3ny.js} +7 -7
  76. package/dist/cli.js +31 -21
  77. package/dist/{codex-adapter-d95q4qsn.js → codex-adapter-7wepzq15.js} +6 -6
  78. package/dist/{codex-hook-brpnycn5.js → codex-hook-pbdh4xhx.js} +2 -2
  79. package/dist/{codex-session-runner-gdwd8h0c.js → codex-session-runner-02sb49e4.js} +6 -6
  80. package/dist/{commands-jqmgk54b.js → commands-3rcspxct.js} +2 -2
  81. package/dist/{controller-z3jq589f.js → controller-8ar4avd6.js} +3 -3
  82. package/dist/{controllers-connect-r2za39ef.js → controllers-connect-ajvh9h0v.js} +19 -19
  83. package/dist/{cursor-adapter-4mr4jgkw.js → cursor-adapter-gd0sa7bh.js} +1 -1
  84. package/dist/{db-w36wwb5g.js → db-dv9j7ts5.js} +2 -2
  85. package/dist/{db-ppv2tze7.js → db-z26vgdvj.js} +3 -3
  86. package/dist/{dispatcher-pv5h77vf.js → dispatcher-8m0htjq8.js} +17 -17
  87. package/dist/{dsh-adapter-d4pdpb3r.js → dsh-adapter-y8gyk130.js} +1 -1
  88. package/dist/{e2b-fn3zacvt.js → e2b-74vg9b7e.js} +1 -1
  89. package/dist/{e2b-222hsajc.js → e2b-jyay8wzn.js} +1 -1
  90. package/dist/{easter-egg-3d-4sp4dvmc.js → easter-egg-3d-28f880xx.js} +1 -1
  91. package/dist/{execute-jev839y1.js → execute-9seb79vh.js} +1 -1
  92. package/dist/{external-channel-y6nkzhnn.js → external-channel-smz7jyth.js} +2 -2
  93. package/dist/{getMachineId-bsd-brn0xym3.js → getMachineId-bsd-whfre6gr.js} +3 -3
  94. package/dist/{getMachineId-darwin-t339sfxm.js → getMachineId-darwin-5zjynb19.js} +3 -3
  95. package/dist/{getMachineId-linux-5eq95d8b.js → getMachineId-linux-8mksrrsq.js} +3 -3
  96. package/dist/{getMachineId-unsupported-qavrtc7j.js → getMachineId-unsupported-fxtqsdt2.js} +3 -3
  97. package/dist/{getMachineId-win-q7fe1wx7.js → getMachineId-win-nzfmz857.js} +3 -3
  98. package/dist/{grok-adapter-t08b9ntm.js → grok-adapter-z0nnvtbn.js} +7 -7
  99. package/dist/handlers-pspryh6g.js +41 -0
  100. package/dist/{heartbeat-vn31xwdk.js → heartbeat-f928aqyp.js} +20 -20
  101. package/dist/{hook-cpjs8q51.js → hook-d7c605r4.js} +7 -7
  102. package/dist/{hook-6d0zbvvt.js → hook-q9hv5xf9.js} +5 -5
  103. package/dist/{http-9c6medda.js → http-q6j4k989.js} +1000 -251
  104. package/dist/{index-k0yt1tvq.js → index-5nb266jr.js} +17 -17
  105. package/dist/{index-ysd45kgc.js → index-8fxt5eah.js} +10 -10
  106. package/dist/{index-zgvqzjsw.js → index-cekzwhez.js} +5 -5
  107. package/dist/{index-38t35h0n.js → index-ch0c1xff.js} +17 -17
  108. package/dist/{index-pkma1yf8.js → index-ebnjhxh1.js} +1 -1
  109. package/dist/{index-yqgbfgaj.js → index-ed8dy8rn.js} +20 -20
  110. package/dist/{index-qhjf2htm.js → index-ejqdkkqx.js} +262 -96
  111. package/dist/{index-dr94zbnh.js → index-farm1zsn.js} +32661 -29443
  112. package/dist/{index-g6k9tctj.js → index-yn1yxg85.js} +1 -1
  113. package/dist/{keepalive-em0117bp.js → keepalive-zzc3hks1.js} +3 -3
  114. package/dist/lead-c0pjcaw4.js +79 -0
  115. package/dist/{maintenance-kbme3qy9.js → maintenance-kqsxzpzx.js} +1 -1
  116. package/dist/{oauth-refresh-sweep-xysj4yse.js → oauth-refresh-sweep-7qt0g55z.js} +8 -3
  117. package/dist/{onboard-p6q0vz97.js → onboard-k7x13fqg.js} +121 -8
  118. package/dist/{opencode-adapter-esv3k9yn.js → opencode-adapter-tqvrtter.js} +5 -5
  119. package/dist/{otel-impl-54qhqh1z.js → otel-impl-sqkf6k3b.js} +97 -97
  120. package/dist/{pi-mono-adapter-mymbwhj0.js → pi-mono-adapter-m2qnafxm.js} +89 -14
  121. package/dist/{pricing-refresh-yb75wv33.js → pricing-refresh-wkpwhgvs.js} +3 -3
  122. package/dist/{rbac-roles-dexhc9x8.js → rbac-roles-dpn0c0wj.js} +7 -4
  123. package/dist/{rbac-roles-1vp2mw4p.js → rbac-roles-wk7xd6a6.js} +2 -2
  124. package/dist/{render-v2-tjay5hhf.js → render-v2-ex2m4g2k.js} +3 -3
  125. package/dist/{resume-8ayf37g5.js → resume-725g9b0b.js} +7 -7
  126. package/dist/{runtime-hqe5cqcd.js → runtime-kajas15g.js} +1 -1
  127. package/dist/{session-access-fdhp987s.js → session-access-0j2ezjje.js} +8 -4
  128. package/dist/{session-source-backfill-qgtc86z1.js → session-source-backfill-62202awe.js} +2 -2
  129. package/dist/{setup-4rrmqcq3.js → setup-9sj11ax6.js} +1 -1
  130. package/dist/{virtual-modules-52km00d6.js → virtual-modules-c6fcq6zr.js} +2 -2
  131. package/dist/{work-objects-p28fgd70.js → work-objects-0y07495y.js} +20 -20
  132. package/dist/worker-d4q9sqbc.js +79 -0
  133. package/openapi.json +1536 -407
  134. package/package.json +7 -5
  135. package/src/be/automation-preflight.ts +2 -0
  136. package/src/be/connector-codes.ts +65 -22
  137. package/src/be/db/api-keys.ts +9 -0
  138. package/src/be/db/workflow-runs.ts +36 -5
  139. package/src/be/db.ts +80 -22
  140. package/src/be/memory/boot-reembed.ts +4 -1
  141. package/src/be/memory/constants.ts +6 -0
  142. package/src/be/memory/embedding-recovery.ts +48 -0
  143. package/src/be/memory/index-content.ts +5 -2
  144. package/src/be/memory/providers/openai-embedding.ts +65 -14
  145. package/src/be/memory/task-learning.ts +257 -0
  146. package/src/be/memory/types.ts +13 -2
  147. package/src/be/migrations/245_script_executor.sql +3 -0
  148. package/src/be/migrations/246_connector_code_kind.sql +11 -0
  149. package/src/be/oauth-refresh-sweep.ts +2 -1
  150. package/src/be/onboarding.ts +125 -15
  151. package/src/be/rbac-roles.ts +4 -1
  152. package/src/be/scripts/boot-reembed.ts +2 -0
  153. package/src/be/scripts/db.ts +14 -4
  154. package/src/be/scripts/embeddings.ts +4 -2
  155. package/src/be/scripts/run-saved.ts +1 -0
  156. package/src/be/scripts/typecheck.ts +9 -3
  157. package/src/be/seed/agent-fs-provision.ts +75 -14
  158. package/src/be/seed-skills/index.ts +7 -0
  159. package/src/be/swarm-config-guard.ts +3 -0
  160. package/src/cli.tsx +9 -0
  161. package/src/comb/config.ts +6 -1
  162. package/src/commands/onboard/agent-fs-version.ts +5 -0
  163. package/src/commands/onboard/compose-generator.ts +117 -4
  164. package/src/commands/onboard/env-generator.ts +9 -0
  165. package/src/commands/onboard/tei-image.ts +12 -0
  166. package/src/commands/onboard/types.ts +7 -0
  167. package/src/commands/onboard.tsx +11 -1
  168. package/src/commands/provider-credentials.ts +2 -1
  169. package/src/commands/runner.ts +14 -1
  170. package/src/heartbeat/heartbeat.ts +14 -1
  171. package/src/heartbeat/script-runner-probe.ts +47 -0
  172. package/src/http/agentfs-proxy.ts +369 -0
  173. package/src/http/all-routes.ts +1 -0
  174. package/src/http/api-keys.ts +24 -9
  175. package/src/http/codex-oauth-device.ts +8 -1
  176. package/src/http/fs.ts +64 -10
  177. package/src/http/idempotency-key.ts +1 -1
  178. package/src/http/inbox-state.ts +27 -1
  179. package/src/http/index.ts +7 -4
  180. package/src/http/memory.ts +7 -4
  181. package/src/http/onboarding.ts +139 -11
  182. package/src/http/pages-public.ts +38 -5
  183. package/src/http/scripts.ts +27 -0
  184. package/src/http/session-access.ts +24 -0
  185. package/src/http/sessions.ts +10 -6
  186. package/src/http/tasks.ts +85 -11
  187. package/src/http/telemetry-ui.ts +1 -1
  188. package/src/http/user-roles.ts +4 -1
  189. package/src/http/users.ts +272 -3
  190. package/src/http/utils.ts +22 -3
  191. package/src/http/workflows.ts +10 -0
  192. package/src/http/x.ts +5 -0
  193. package/src/prompts/base-prompt.ts +45 -10
  194. package/src/prompts/session-templates.ts +43 -5
  195. package/src/providers/amp-adapter.ts +1 -1
  196. package/src/providers/codex-adapter.ts +6 -1
  197. package/src/providers/cursor-adapter.ts +1 -1
  198. package/src/providers/dsh-adapter.ts +1 -1
  199. package/src/providers/pi-mono-adapter.ts +99 -14
  200. package/src/rbac/legacy-policy.ts +1 -0
  201. package/src/rbac/permissions.ts +4 -0
  202. package/src/scheduler/scheduler.ts +2 -1
  203. package/src/scripts-runtime/eval-harness.ts +8 -1
  204. package/src/scripts-runtime/executors/native.ts +22 -16
  205. package/src/scripts-runtime/executors/quickjs-prelude.ts +103 -1
  206. package/src/scripts-runtime/executors/quickjs-runner.ts +2 -1
  207. package/src/scripts-runtime/executors/quickjs.ts +7 -0
  208. package/src/scripts-runtime/executors/registry.ts +32 -0
  209. package/src/scripts-runtime/executors/types.ts +7 -0
  210. package/src/scripts-runtime/host-validated-args.ts +133 -0
  211. package/src/scripts-runtime/loader.ts +30 -3
  212. package/src/scripts-runtime/swarm-sdk.ts +9 -2
  213. package/src/scripts-runtime/types/stdlib.d.ts +9 -1
  214. package/src/scripts-runtime/types/swarm-sdk.d.ts +9 -1
  215. package/src/tests/agent-fs-provision-seeder.test.ts +261 -92
  216. package/src/tests/agentfs-proxy.test.ts +1106 -0
  217. package/src/tests/api-key-status-by-suffix.test.ts +242 -0
  218. package/src/tests/base-prompt.test.ts +139 -4
  219. package/src/tests/codex-adapter.test.ts +46 -8
  220. package/src/tests/codex-oauth-device.test.ts +12 -1
  221. package/src/tests/comb-config-guard.test.ts +20 -0
  222. package/src/tests/comb-links.test.ts +79 -1
  223. package/src/tests/comb-status.test.ts +44 -0
  224. package/src/tests/community-linear-delivery-loop.test.ts +2099 -0
  225. package/src/tests/credential-check.test.ts +4 -2
  226. package/src/tests/docs-index-footprint.test.js +3 -3
  227. package/src/tests/docs-index.test.ts +135 -0
  228. package/src/tests/dsh-adapter.test.ts +1 -1
  229. package/src/tests/fetch-resolved-env.test.ts +16 -2
  230. package/src/tests/fixtures/onboard/baseline-states.ts +68 -0
  231. package/src/tests/fixtures/onboard/content.compose.yml.txt +190 -0
  232. package/src/tests/fixtures/onboard/content.env.txt +29 -0
  233. package/src/tests/fixtures/onboard/dev.compose.yml.txt +155 -0
  234. package/src/tests/fixtures/onboard/dev.env.txt +28 -0
  235. package/src/tests/fixtures/onboard/full-all.compose.yml.txt +582 -0
  236. package/src/tests/fixtures/onboard/full-all.env.txt +59 -0
  237. package/src/tests/fixtures/onboard/full.compose.yml.txt +435 -0
  238. package/src/tests/fixtures/onboard/full.env.txt +36 -0
  239. package/src/tests/fixtures/onboard/research.compose.yml.txt +155 -0
  240. package/src/tests/fixtures/onboard/research.env.txt +28 -0
  241. package/src/tests/fixtures/onboard/solo.compose.yml.txt +85 -0
  242. package/src/tests/fixtures/onboard/solo.env.txt +26 -0
  243. package/src/tests/heartbeat-checklist.test.ts +89 -0
  244. package/src/tests/heartbeat-script-runner-probe.test.ts +83 -0
  245. package/src/tests/http-log-scrubbing.test.ts +34 -1
  246. package/src/tests/http-task-write-ownership.test.ts +5 -1
  247. package/src/tests/invites-http.test.ts +464 -0
  248. package/src/tests/memory-embedding-input-cap.test.ts +122 -1
  249. package/src/tests/memory-embedding-recovery.test.ts +137 -0
  250. package/src/tests/oauth-refresh-sweep.test.ts +34 -1
  251. package/src/tests/onboard-compose.test.ts +162 -0
  252. package/src/tests/onboard-env.test.ts +24 -0
  253. package/src/tests/onboard-non-interactive.test.ts +29 -0
  254. package/src/tests/onboard-tei-image.test.ts +36 -0
  255. package/src/tests/onboarding.test.ts +451 -4
  256. package/src/tests/openai-embedding-provider.test.ts +105 -2
  257. package/src/tests/opencode-adapter.test.ts +2 -1
  258. package/src/tests/pages-frame-ancestors.test.ts +162 -0
  259. package/src/tests/pi-codemode.test.ts +2 -1
  260. package/src/tests/pi-mono-adapter.test.ts +54 -0
  261. package/src/tests/pi-mono-session-cost-on-abort.test.ts +270 -0
  262. package/src/tests/pi-native-mcp.test.ts +13 -1
  263. package/src/tests/pi-tool-exposure.test.ts +8 -8
  264. package/src/tests/preload-env.test.ts +4 -0
  265. package/src/tests/preload.ts +4 -0
  266. package/src/tests/probe-tool-schema-tokens.test.ts +144 -0
  267. package/src/tests/prompt-template-session.test.ts +20 -3
  268. package/src/tests/rbac-admission-e2e.test.ts +22 -6
  269. package/src/tests/rbac-admission.test.ts +342 -4
  270. package/src/tests/rbac-engine.test.ts +1 -0
  271. package/src/tests/rbac-roles.test.ts +9 -1
  272. package/src/tests/request-composition-derive.test.ts +329 -0
  273. package/src/tests/script-connections.test.ts +2 -0
  274. package/src/tests/script-executor-conformance.test.ts +36 -1
  275. package/src/tests/script-executor-quickjs-pool.test.ts +50 -0
  276. package/src/tests/script-executor-quickjs.test.ts +140 -0
  277. package/src/tests/script-host-validated-args-native.test.ts +196 -0
  278. package/src/tests/script-per-script-executor.test.ts +415 -0
  279. package/src/tests/scripts-external-api.test.ts +45 -0
  280. package/src/tests/sdk-allowlist.test.ts +3 -2
  281. package/src/tests/self-improvement.test.ts +4 -4
  282. package/src/tests/send-task-requester-gate.test.ts +64 -3
  283. package/src/tests/sessions-move.test.ts +39 -1
  284. package/src/tests/store-progress-learning.test.ts +381 -0
  285. package/src/tests/ui-logs-parser.test.ts +180 -0
  286. package/src/tests/whoami-route.test.ts +41 -0
  287. package/src/tests/workflow-engine-v2.test.ts +116 -1
  288. package/src/tests/workflow-mcp-trigger-schema.test.ts +209 -0
  289. package/src/tests/workflow-run-finished-event.test.ts +263 -0
  290. package/src/tests/workflow-swarm-script.test.ts +34 -0
  291. package/src/tools/inject-learning.ts +1 -1
  292. package/src/tools/memory-edit.ts +1 -1
  293. package/src/tools/memory-search.ts +1 -1
  294. package/src/tools/script-common.ts +1 -0
  295. package/src/tools/script-run.ts +7 -0
  296. package/src/tools/script-upsert.ts +7 -0
  297. package/src/tools/store-progress.ts +71 -1
  298. package/src/tools/utils.ts +12 -1
  299. package/src/tools/workflows/trigger-workflow.ts +104 -10
  300. package/src/types.ts +12 -1
  301. package/src/utils/constants.ts +39 -0
  302. package/src/utils/credentials.ts +5 -2
  303. package/src/utils/task-attachment-links.ts +15 -3
  304. package/src/workflows/engine.ts +18 -16
  305. package/src/workflows/executors/swarm-script.ts +5 -0
  306. package/src/workflows/foreach-driver.ts +5 -11
  307. package/src/workflows/node-timeout.ts +30 -0
  308. package/templates/community/linear-delivery-loop/PLAYBOOK.md +323 -0
  309. package/templates/community/linear-delivery-loop/README.md +38 -0
  310. package/templates/community/linear-delivery-loop/config.example.json +31 -0
  311. package/templates/community/linear-delivery-loop/lead-prompt.md +34 -0
  312. package/templates/community/linear-delivery-loop/schedule.json +10 -0
  313. package/templates/community/linear-delivery-loop/scripts/linear-delivery-setup.ts +148 -0
  314. package/templates/community/linear-delivery-loop/scripts/linear-delivery-tick.ts +1781 -0
  315. package/templates/skills/swarm-docs/config.json +14 -0
  316. package/templates/skills/swarm-docs/content.md +144 -0
  317. package/dist/handlers-eqsnmv95.js +0 -41
  318. package/dist/lead-23e7z59t.js +0 -79
  319. package/dist/worker-e3w7vye1.js +0 -79
  320. package/dist/{azure-openai-responses-9kfwhmn7.js → azure-openai-responses-43asa23s.js} +0 -0
  321. package/dist/{node-vxx896fa.js → node-t28cc56b.js} +0 -0
  322. package/dist/{openai-codex-responses-79s8xnbh.js → openai-codex-responses-jhr3sjtm.js} +3 -3
  323. package/dist/{openai-completions-tdbyts0x.js → openai-completions-gs6yn37k.js} +3 -3
  324. /package/dist/{openai-responses-dm3t5vqp.js → openai-responses-jqm9vwwk.js} +0 -0
@@ -0,0 +1,196 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import os from "node:os";
3
+ import { z } from "zod";
4
+ import * as zm from "zod/mini";
5
+ import { NativeScriptExecutor } from "../scripts-runtime/executors/native";
6
+ import { DEFAULT_SCRIPT_RESOURCES, type ExecutorInput } from "../scripts-runtime/executors/types";
7
+ import {
8
+ HOST_VALIDATED_ARGS,
9
+ isHostValidationEquivalent,
10
+ } from "../scripts-runtime/host-validated-args";
11
+
12
+ process.env.TMPDIR ??= os.tmpdir().replaceAll("\\", "/");
13
+
14
+ function makeInput(
15
+ source: string,
16
+ args: unknown,
17
+ opts: { hostValidatedArgs?: boolean } = {},
18
+ ): ExecutorInput {
19
+ return {
20
+ source,
21
+ args,
22
+ ...(opts.hostValidatedArgs !== undefined ? { hostValidatedArgs: opts.hostValidatedArgs } : {}),
23
+ fsMode: "none",
24
+ network: "open",
25
+ resources: DEFAULT_SCRIPT_RESOURCES,
26
+ configPayload: {
27
+ system: {
28
+ apiKey: { value: "test-key", isSecret: true },
29
+ agentId: { value: "00000000-0000-0000-0000-000000000001", isSecret: false },
30
+ mcpBaseUrl: { value: "http://127.0.0.1:19999", isSecret: false },
31
+ },
32
+ user: {},
33
+ },
34
+ };
35
+ }
36
+
37
+ describe("isHostValidationEquivalent", () => {
38
+ test("accepts pure structural zod and zod/mini schemas with matching values", () => {
39
+ const schema = z.object({
40
+ name: z.string(),
41
+ count: z.number(),
42
+ active: z.boolean(),
43
+ tags: z.array(z.string()),
44
+ mode: z.enum(["fast", "slow"]),
45
+ version: z.literal(1),
46
+ note: z.string().optional(),
47
+ parent: z.string().nullable(),
48
+ });
49
+
50
+ expect(
51
+ isHostValidationEquivalent(schema, {
52
+ name: "demo",
53
+ count: 3,
54
+ active: true,
55
+ tags: ["a", "b"],
56
+ mode: "fast",
57
+ version: 1,
58
+ parent: null,
59
+ }),
60
+ ).toBe(true);
61
+
62
+ const miniSchema = zm.object({
63
+ id: zm.string(),
64
+ limit: zm.optional(zm.number()),
65
+ });
66
+ expect(isHostValidationEquivalent(miniSchema, { id: "abc" })).toBe(true);
67
+ expect(isHostValidationEquivalent(miniSchema, { id: "abc", limit: 10 })).toBe(true);
68
+ });
69
+
70
+ test("rejects schemas with defaults, transforms, refinements, coercions, checks, or unknown keys", () => {
71
+ expect(isHostValidationEquivalent(z.object({ x: z.string().default("hi") }), {})).toBe(false);
72
+ expect(
73
+ isHostValidationEquivalent(z.object({ x: z.string().default("hi").optional() }), {}),
74
+ ).toBe(false);
75
+ expect(
76
+ isHostValidationEquivalent(z.object({ x: z.string().transform((s) => s.trim()) }), {
77
+ x: " hi ",
78
+ }),
79
+ ).toBe(false);
80
+ expect(
81
+ isHostValidationEquivalent(z.object({ x: z.string().refine((s) => s.length > 0) }), {
82
+ x: "hi",
83
+ }),
84
+ ).toBe(false);
85
+ expect(isHostValidationEquivalent(z.object({ x: z.coerce.number() }), { x: 42 })).toBe(false);
86
+ expect(isHostValidationEquivalent(z.object({ x: z.string().min(1) }), { x: "hi" })).toBe(false);
87
+ expect(isHostValidationEquivalent(z.object({ x: z.string().email() }), { x: "a@b.co" })).toBe(
88
+ false,
89
+ );
90
+ expect(isHostValidationEquivalent(z.object({ x: z.number().int() }), { x: 5 })).toBe(false);
91
+ // Extra unknown keys require .parse() so z.object strips them (or z.strictObject rejects them)
92
+ expect(isHostValidationEquivalent(z.object({ x: z.string() }), { x: "hi", extra: 1 })).toBe(
93
+ false,
94
+ );
95
+ // Reverse numeric enum keys (e.g. { 0: "Read", Read: 0 }) must not pass as valid values
96
+ const numericEnumSchema = z.enum({ 0: "Read", Read: 0 }).nullable();
97
+ expect(isHostValidationEquivalent(numericEnumSchema, 0)).toBe(true);
98
+ expect(isHostValidationEquivalent(numericEnumSchema, null)).toBe(true);
99
+ expect(isHostValidationEquivalent(numericEnumSchema, "Read")).toBe(false);
100
+ // Inherited Object.prototype properties (constructor, toString) on `{}` must fall back to .parse()
101
+ expect(
102
+ isHostValidationEquivalent(z.object({ constructor: z.string().nullable().optional() }), {}),
103
+ ).toBe(false);
104
+ expect(
105
+ isHostValidationEquivalent(z.object({ toString: z.string().nullable().optional() }), {}),
106
+ ).toBe(false);
107
+ });
108
+ });
109
+
110
+ describe("NativeScriptExecutor hostValidatedArgs (#2010)", () => {
111
+ const executor = new NativeScriptExecutor();
112
+
113
+ const countedStructuralScript = `
114
+ import { z } from "zod";
115
+ export const argsSchema = z.object({
116
+ value: z.number(),
117
+ label: z.string().optional(),
118
+ });
119
+ let parseCalls = 0;
120
+ const origParse = argsSchema.parse.bind(argsSchema);
121
+ argsSchema.parse = ((v: unknown) => {
122
+ parseCalls++;
123
+ return origParse(v);
124
+ }) as typeof argsSchema.parse;
125
+
126
+ export default async function (args: z.infer<typeof argsSchema>) {
127
+ return { doubled: args.value * 2, label: args.label ?? null, parseCalls };
128
+ }
129
+ `;
130
+
131
+ test("skips duplicate argsSchema.parse when hostValidatedArgs is true and schema is structural", async () => {
132
+ const out = await executor.run(
133
+ makeInput(countedStructuralScript, { value: 21, label: "ok" }, { hostValidatedArgs: true }),
134
+ );
135
+ expect(out.exitCode).toBe(0);
136
+ expect(out.error).toBeUndefined();
137
+ expect(out.result).toEqual({ doubled: 42, label: "ok", parseCalls: 0 });
138
+ });
139
+
140
+ test("still runs argsSchema.parse when hostValidatedArgs is omitted or false", async () => {
141
+ const out = await executor.run(makeInput(countedStructuralScript, { value: 21 }));
142
+ expect(out.exitCode).toBe(0);
143
+ expect(out.result).toEqual({ doubled: 42, label: null, parseCalls: 1 });
144
+ });
145
+
146
+ test("still runs argsSchema.parse when args contain extra keys that Zod strips", async () => {
147
+ const out = await executor.run(
148
+ makeInput(
149
+ countedStructuralScript,
150
+ { value: 21, extra: "stripped-by-zod" },
151
+ { hostValidatedArgs: true },
152
+ ),
153
+ );
154
+ expect(out.exitCode).toBe(0);
155
+ expect(out.result).toEqual({ doubled: 42, label: null, parseCalls: 1 });
156
+ });
157
+
158
+ test("still runs argsSchema.parse when schema uses defaults, transforms, or refinements", async () => {
159
+ const scriptWithDefaultsAndTransforms = `
160
+ import { z } from "zod";
161
+ export const argsSchema = z.object({
162
+ value: z.number().default(10),
163
+ tag: z.string().transform((s) => s.toUpperCase()),
164
+ });
165
+ let parseCalls = 0;
166
+ const origParse = argsSchema.parse.bind(argsSchema);
167
+ argsSchema.parse = ((v: unknown) => {
168
+ parseCalls++;
169
+ return origParse(v);
170
+ }) as typeof argsSchema.parse;
171
+
172
+ export default async function (args: z.infer<typeof argsSchema>) {
173
+ return { value: args.value, tag: args.tag, parseCalls };
174
+ }
175
+ `;
176
+ const out = await executor.run(
177
+ makeInput(scriptWithDefaultsAndTransforms, { tag: "hello" }, { hostValidatedArgs: true }),
178
+ );
179
+ expect(out.exitCode).toBe(0);
180
+ expect(out.result).toEqual({ value: 10, tag: "HELLO", parseCalls: 1 });
181
+ });
182
+
183
+ test("caller-supplied args payload cannot spoof the trusted host validation marker", async () => {
184
+ expect(Symbol.keyFor(HOST_VALIDATED_ARGS)).toBeUndefined();
185
+ expect(Symbol.for("swarm.hostValidatedArgs")).not.toBe(HOST_VALIDATED_ARGS);
186
+ const out = await executor.run(
187
+ makeInput(countedStructuralScript, {
188
+ value: 7,
189
+ hostValidatedArgs: true,
190
+ SWARM_SCRIPT_HOST_VALIDATED_ARGS: "1",
191
+ }),
192
+ );
193
+ expect(out.exitCode).toBe(0);
194
+ expect(out.result).toEqual({ doubled: 14, label: null, parseCalls: 1 });
195
+ });
196
+ });
@@ -0,0 +1,415 @@
1
+ import { afterEach, beforeAll, describe, expect, test } from "bun:test";
2
+ import type { IncomingMessage, ServerResponse } from "node:http";
3
+ import os from "node:os";
4
+ import { Readable } from "node:stream";
5
+ import { createAgent, getScriptRun, initDb, listScriptRuns } from "../be/db";
6
+ import { getScriptById, insertScript, upsertScriptByName } from "../be/scripts/db";
7
+ import { setScriptEmbeddingProviderForTests } from "../be/scripts/embeddings";
8
+ import { runSavedScriptAsAgent } from "../be/scripts/run-saved";
9
+ import { typecheckScript } from "../be/scripts/typecheck";
10
+ import { handleScripts } from "../http/scripts";
11
+ import {
12
+ isExecutorAllowedByDeployment,
13
+ resolveScriptExecutor,
14
+ } from "../scripts-runtime/executors/registry";
15
+ import { runScript } from "../scripts-runtime/loader";
16
+ import { type ScheduledTask, ScriptExecutorNameSchema, ScriptRecordSchema } from "../types";
17
+ import { SwarmScriptExecutor } from "../workflows/executors/swarm-script";
18
+
19
+ process.env.TMPDIR ??= os.tmpdir().replaceAll("\\", "/");
20
+ process.env.API_KEY ??= "test-per-script-executor-api-key";
21
+ process.env.MCP_BASE_URL ??= "http://127.0.0.1:19999";
22
+
23
+ const RUNTIME_PROBE_SOURCE =
24
+ 'export default async () => ({ hasProcess: typeof (globalThis as { process?: unknown }).process !== "undefined" });';
25
+
26
+ const savedScriptExecutorEnv = process.env.SCRIPT_EXECUTOR;
27
+
28
+ afterEach(() => {
29
+ if (savedScriptExecutorEnv === undefined) {
30
+ delete process.env.SCRIPT_EXECUTOR;
31
+ } else {
32
+ process.env.SCRIPT_EXECUTOR = savedScriptExecutorEnv;
33
+ }
34
+ });
35
+
36
+ describe("per-script executor schema (#2013)", () => {
37
+ test("ScriptExecutorNameSchema accepts native and quickjs and rejects invalid names", () => {
38
+ expect(ScriptExecutorNameSchema.safeParse("native").success).toBe(true);
39
+ expect(ScriptExecutorNameSchema.safeParse("quickjs").success).toBe(true);
40
+ expect(ScriptExecutorNameSchema.safeParse("e2b").success).toBe(false);
41
+ expect(ScriptExecutorNameSchema.safeParse("").success).toBe(false);
42
+ });
43
+
44
+ test("ScriptRecordSchema defaults executor to null and accepts explicit executor", () => {
45
+ const base = {
46
+ id: "00000000-0000-0000-0000-000000000001",
47
+ name: "demo",
48
+ scope: "agent" as const,
49
+ scopeId: "00000000-0000-0000-0000-000000000002",
50
+ source: RUNTIME_PROBE_SOURCE,
51
+ description: "",
52
+ intent: "",
53
+ signatureJson: "{}",
54
+ argsJsonSchema: null,
55
+ contentHash: "abc",
56
+ version: 1,
57
+ isScratch: false,
58
+ typeChecked: true,
59
+ fsMode: "none" as const,
60
+ createdByAgentId: null,
61
+ createdAt: "2026-10-26T00:00:00.000Z",
62
+ updatedAt: "2026-10-26T00:00:00.000Z",
63
+ };
64
+
65
+ expect(ScriptRecordSchema.parse(base).executor).toBeNull();
66
+ expect(ScriptRecordSchema.parse({ ...base, executor: "quickjs" }).executor).toBe("quickjs");
67
+ expect(ScriptRecordSchema.parse({ ...base, executor: "native" }).executor).toBe("native");
68
+ });
69
+ });
70
+
71
+ describe("runScript per-script executor precedence (#2013)", () => {
72
+ test("explicit executor: 'quickjs' overrides SCRIPT_EXECUTOR=native", async () => {
73
+ process.env.SCRIPT_EXECUTOR = "native";
74
+ const out = await runScript({
75
+ source: RUNTIME_PROBE_SOURCE,
76
+ agentId: "00000000-0000-0000-0000-000000000001",
77
+ executor: "quickjs",
78
+ egressSecrets: [],
79
+ });
80
+ expect(out.exitCode).toBe(0);
81
+ expect(out.error).toBeUndefined();
82
+ expect(out.result).toEqual({ hasProcess: false });
83
+ });
84
+
85
+ test("explicit executor: 'native' is denied when deployment SCRIPT_EXECUTOR=quickjs", async () => {
86
+ process.env.SCRIPT_EXECUTOR = "quickjs";
87
+ expect(isExecutorAllowedByDeployment("native")).toBe(false);
88
+ expect(isExecutorAllowedByDeployment("quickjs")).toBe(true);
89
+ expect(isExecutorAllowedByDeployment(null)).toBe(true);
90
+ expect(() => resolveScriptExecutor("native")).toThrow(
91
+ 'Executor "native" is not permitted when deployment SCRIPT_EXECUTOR="quickjs"',
92
+ );
93
+
94
+ let canaryHits = 0;
95
+ const server = Bun.serve({
96
+ hostname: "127.0.0.1",
97
+ port: 0,
98
+ fetch() {
99
+ canaryHits += 1;
100
+ return new Response("reached");
101
+ },
102
+ });
103
+ try {
104
+ const out = await runScript({
105
+ source: `export default async () => { await fetch("http://127.0.0.1:${server.port}/canary"); return { ok: true }; };`,
106
+ agentId: "00000000-0000-0000-0000-000000000001",
107
+ executor: "native",
108
+ egressSecrets: [],
109
+ });
110
+ expect(out.exitCode).toBe(1);
111
+ expect(out.error).toBe("executor_error");
112
+ expect(out.stderr).toContain(
113
+ 'Executor "native" is not permitted when deployment SCRIPT_EXECUTOR="quickjs"',
114
+ );
115
+ expect(canaryHits).toBe(0);
116
+ } finally {
117
+ server.stop(true);
118
+ }
119
+ });
120
+
121
+ test("null or omitted executor falls back to SCRIPT_EXECUTOR", async () => {
122
+ process.env.SCRIPT_EXECUTOR = "quickjs";
123
+ const quickjsDefault = await runScript({
124
+ source: RUNTIME_PROBE_SOURCE,
125
+ agentId: "00000000-0000-0000-0000-000000000001",
126
+ executor: null,
127
+ egressSecrets: [],
128
+ });
129
+ expect(quickjsDefault.exitCode).toBe(0);
130
+ expect(quickjsDefault.result).toEqual({ hasProcess: false });
131
+ });
132
+
133
+ test("null or omitted executor falls back to native when SCRIPT_EXECUTOR is unset", async () => {
134
+ delete process.env.SCRIPT_EXECUTOR;
135
+ const nativeDefault = await runScript({
136
+ source: RUNTIME_PROBE_SOURCE,
137
+ agentId: "00000000-0000-0000-0000-000000000001",
138
+ executor: null,
139
+ egressSecrets: [],
140
+ });
141
+ expect(nativeDefault.exitCode).toBe(0);
142
+ expect(nativeDefault.result).toEqual({ hasProcess: true });
143
+ }, 15_000);
144
+ });
145
+
146
+ describe("scripts DB & runSavedScriptAsAgent executor persistence (#2013)", () => {
147
+ let agentId: string;
148
+
149
+ beforeAll(async () => {
150
+ initDb(":memory:");
151
+ setScriptEmbeddingProviderForTests({
152
+ name: "test/noop",
153
+ dimensions: 1,
154
+ async embed() {
155
+ return null;
156
+ },
157
+ async embedBatch(texts) {
158
+ return texts.map(() => null);
159
+ },
160
+ });
161
+ const agent = await createAgent({ name: "exec-select-worker", isLead: false, status: "idle" });
162
+ agentId = agent.id;
163
+ });
164
+
165
+ test("insertScript and upsertScriptByName persist executor and runSavedScriptAsAgent uses it", async () => {
166
+ const inserted = await insertScript({
167
+ name: `exec-probe-${crypto.randomUUID().slice(0, 8)}`,
168
+ scope: "agent",
169
+ scopeId: agentId,
170
+ source: RUNTIME_PROBE_SOURCE,
171
+ description: "probe",
172
+ intent: "test",
173
+ signatureJson: "{}",
174
+ executor: "quickjs",
175
+ agentId,
176
+ typeChecked: true,
177
+ });
178
+ expect(inserted.executor).toBe("quickjs");
179
+ expect((await getScriptById(inserted.id))?.executor).toBe("quickjs");
180
+
181
+ process.env.SCRIPT_EXECUTOR = "native";
182
+ const quickjsOut = await runSavedScriptAsAgent(
183
+ { script: inserted, input: null, agentId },
184
+ {
185
+ buildCredentials: async () => ({
186
+ egressSecrets: [],
187
+ failedBindings: [],
188
+ userConfig: {},
189
+ }),
190
+ },
191
+ );
192
+ expect(quickjsOut.exitCode).toBe(0);
193
+ expect(quickjsOut.result).toEqual({ hasProcess: false });
194
+
195
+ // Metadata-only upsert changing executor from "quickjs" to "native"
196
+ const updated = await upsertScriptByName({
197
+ name: inserted.name,
198
+ scope: "agent",
199
+ scopeId: agentId,
200
+ source: RUNTIME_PROBE_SOURCE,
201
+ description: "probe",
202
+ intent: "test",
203
+ signatureJson: "{}",
204
+ executor: "native",
205
+ agentId,
206
+ typeChecked: true,
207
+ });
208
+ expect(updated.contentDeduped).toBe(true);
209
+ expect(updated.script.executor).toBe("native");
210
+
211
+ process.env.SCRIPT_EXECUTOR = "native";
212
+ const nativeOut = await runSavedScriptAsAgent(
213
+ { script: updated.script, input: null, agentId },
214
+ {
215
+ buildCredentials: async () => ({
216
+ egressSecrets: [],
217
+ failedBindings: [],
218
+ userConfig: {},
219
+ }),
220
+ },
221
+ );
222
+ expect(nativeOut.exitCode).toBe(0);
223
+ expect(nativeOut.result).toEqual({ hasProcess: true });
224
+
225
+ // Under operator ceiling SCRIPT_EXECUTOR=quickjs, saved native script is denied
226
+ process.env.SCRIPT_EXECUTOR = "quickjs";
227
+ const deniedOut = await runSavedScriptAsAgent(
228
+ { script: updated.script, input: null, agentId },
229
+ {
230
+ buildCredentials: async () => ({
231
+ egressSecrets: [],
232
+ failedBindings: [],
233
+ userConfig: {},
234
+ }),
235
+ },
236
+ );
237
+ expect(deniedOut.exitCode).toBe(1);
238
+ expect(deniedOut.error).toBe("executor_error");
239
+ expect(deniedOut.stderr).toContain(
240
+ 'Executor "native" is not permitted when deployment SCRIPT_EXECUTOR="quickjs"',
241
+ );
242
+ });
243
+
244
+ test("HTTP /api/scripts/upsert, /api/scripts/run, and GET /api/scripts enforce ceiling and expose executor", async () => {
245
+ async function invokeScriptsHttp(opts: {
246
+ method: string;
247
+ pathSegments: string[];
248
+ queryParams?: URLSearchParams;
249
+ body?: unknown;
250
+ agentId?: string;
251
+ }): Promise<{ status: number; body: unknown }> {
252
+ const payload = opts.body !== undefined ? JSON.stringify(opts.body) : "";
253
+ const req = Object.assign(Readable.from(payload ? [Buffer.from(payload)] : []), {
254
+ method: opts.method,
255
+ url: `/${opts.pathSegments.join("/")}`,
256
+ headers: {
257
+ "content-type": "application/json",
258
+ ...(opts.agentId ? { "x-agent-id": opts.agentId } : {}),
259
+ },
260
+ }) as unknown as IncomingMessage;
261
+
262
+ let status = 200;
263
+ const chunks: Buffer[] = [];
264
+ const res = {
265
+ writeHead(code: number) {
266
+ status = code;
267
+ return this;
268
+ },
269
+ setHeader() {
270
+ return this;
271
+ },
272
+ end(chunk?: string | Buffer) {
273
+ if (chunk) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
274
+ return this;
275
+ },
276
+ } as unknown as ServerResponse;
277
+
278
+ await handleScripts(
279
+ req,
280
+ res,
281
+ opts.pathSegments,
282
+ opts.queryParams ?? new URLSearchParams(),
283
+ opts.agentId,
284
+ );
285
+ const text = Buffer.concat(chunks).toString("utf8");
286
+ return { status, body: text ? JSON.parse(text) : null };
287
+ }
288
+
289
+ process.env.SCRIPT_EXECUTOR = "quickjs";
290
+
291
+ const upsertDenied = await invokeScriptsHttp({
292
+ method: "POST",
293
+ pathSegments: ["api", "scripts", "upsert"],
294
+ agentId,
295
+ body: {
296
+ name: "escape-attempt",
297
+ scope: "agent",
298
+ source: RUNTIME_PROBE_SOURCE,
299
+ executor: "native",
300
+ },
301
+ });
302
+ expect(upsertDenied.status).toBe(400);
303
+ expect((upsertDenied.body as { error?: string }).error).toContain(
304
+ 'Executor "native" is not permitted when deployment SCRIPT_EXECUTOR="quickjs"',
305
+ );
306
+
307
+ const runDenied = await invokeScriptsHttp({
308
+ method: "POST",
309
+ pathSegments: ["api", "scripts", "run"],
310
+ agentId,
311
+ body: {
312
+ source: RUNTIME_PROBE_SOURCE,
313
+ executor: "native",
314
+ },
315
+ });
316
+ expect(runDenied.status).toBe(400);
317
+ expect((runDenied.body as { error?: string }).error).toContain(
318
+ 'Executor "native" is not permitted when deployment SCRIPT_EXECUTOR="quickjs"',
319
+ );
320
+
321
+ const listRes = await invokeScriptsHttp({
322
+ method: "GET",
323
+ pathSegments: ["api", "scripts"],
324
+ queryParams: new URLSearchParams("scope=agent"),
325
+ });
326
+ expect(listRes.status).toBe(200);
327
+ const listed = (listRes.body as { scripts: Array<{ executor: string | null }> }).scripts;
328
+ expect(listed.length).toBeGreaterThan(0);
329
+ expect(listed.some((s) => s.executor === "native" || s.executor === "quickjs")).toBe(true);
330
+ });
331
+
332
+ test("workflow SwarmScriptExecutor and scheduler dispatchScheduleTarget forward script.executor", async () => {
333
+ process.env.SCRIPT_EXECUTOR = "native";
334
+ const globalQuickjs = await insertScript({
335
+ name: `global-qjs-${crypto.randomUUID().slice(0, 8)}`,
336
+ scope: "global",
337
+ scopeId: null,
338
+ source: RUNTIME_PROBE_SOURCE,
339
+ description: "global quickjs script",
340
+ intent: "test",
341
+ signatureJson: "{}",
342
+ executor: "quickjs",
343
+ agentId,
344
+ typeChecked: true,
345
+ });
346
+
347
+ const wfExecutor = new SwarmScriptExecutor({
348
+ db: {
349
+ getWorkflow: async () => null,
350
+ } as never,
351
+ eventBus: { emit: () => {} } as never,
352
+ });
353
+ const wfResult = await wfExecutor.run({
354
+ config: { scriptName: globalQuickjs.name, scope: "global", fsMode: "none" },
355
+ context: { agentId },
356
+ meta: {
357
+ runId: crypto.randomUUID(),
358
+ stepId: crypto.randomUUID(),
359
+ nodeId: "n1",
360
+ workflowId: crypto.randomUUID(),
361
+ },
362
+ });
363
+ expect(wfResult.status).toBe("success");
364
+ if (wfResult.status === "success") {
365
+ expect(wfResult.output.result).toEqual({ hasProcess: false });
366
+ }
367
+
368
+ const { executeScheduleScript } = await import("../scheduler/scheduler");
369
+ const schedule: ScheduledTask = {
370
+ id: crypto.randomUUID(),
371
+ name: `sched-${globalQuickjs.name}`,
372
+ taskTemplate: "",
373
+ targetType: "script",
374
+ scriptName: globalQuickjs.name,
375
+ scriptArgs: {},
376
+ tags: [],
377
+ priority: 50,
378
+ enabled: true,
379
+ scheduleType: "recurring",
380
+ consecutiveErrors: 0,
381
+ createdByAgentId: agentId,
382
+ createdAt: new Date().toISOString(),
383
+ lastUpdatedAt: new Date().toISOString(),
384
+ };
385
+ await executeScheduleScript(schedule);
386
+ const runs = await listScriptRuns({ limit: 10 });
387
+ const matchedRun = runs.find((r) => r.scriptName === globalQuickjs.name);
388
+ expect(matchedRun?.status).toBe("completed");
389
+ const fullRun = matchedRun ? await getScriptRun(matchedRun.id) : null;
390
+ expect(fullRun?.output).toEqual({ hasProcess: false });
391
+ });
392
+
393
+ test("typecheckScript accepts executor on ctx.swarm.script_upsert and ctx.swarm.script_run", async () => {
394
+ const valid = await typecheckScript(
395
+ `import type { ScriptContext } from "swarm-sdk";
396
+ export default async (_args: unknown, ctx: ScriptContext) => {
397
+ await ctx.swarm.script_upsert({ name: "demo", source: "export default async () => 1;", executor: "quickjs" });
398
+ await ctx.swarm.script_run({ name: "demo", executor: "quickjs" });
399
+ return { ok: true };
400
+ };`,
401
+ { agentId },
402
+ );
403
+ expect(valid.ok).toBe(true);
404
+
405
+ const invalid = await typecheckScript(
406
+ `import type { ScriptContext } from "swarm-sdk";
407
+ export default async (_args: unknown, ctx: ScriptContext) => {
408
+ await ctx.swarm.script_run({ name: "demo", executor: "e2b" });
409
+ return { ok: true };
410
+ };`,
411
+ { agentId },
412
+ );
413
+ expect(invalid.ok).toBe(false);
414
+ });
415
+ });
@@ -421,6 +421,51 @@ describe("public execution route", () => {
421
421
  expect(body.error.type).toBe("args_validation");
422
422
  });
423
423
 
424
+ test("POST {} against z.object with inherited Object.prototype keys (constructor, toString) retains Zod rejection under quickjs", async () => {
425
+ const prevExecutor = process.env.SCRIPT_EXECUTOR;
426
+ process.env.SCRIPT_EXECUTOR = "quickjs";
427
+ try {
428
+ for (const propName of ["constructor", "toString"] as const) {
429
+ const script = await insertScript({
430
+ name: `proto-${propName}-${crypto.randomUUID().slice(0, 8)}`,
431
+ scope: "agent",
432
+ scopeId: workerId,
433
+ source: `import { z } from "zod";\nexport const argsSchema = z.object({ ${propName}: z.string().nullable().optional() });\nexport default async function (args: z.infer<typeof argsSchema>) { return { ok: true, val: args.${propName} ?? null }; }`,
434
+ description: "Prototype key test",
435
+ intent: "test fixture",
436
+ signatureJson: "{}",
437
+ argsJsonSchema: JSON.stringify({
438
+ type: "object",
439
+ properties: { [propName]: { type: ["string", "null"] } },
440
+ }),
441
+ agentId: workerId,
442
+ typeChecked: true,
443
+ });
444
+ const endpoint = await createScriptApi({
445
+ scriptId: script.id,
446
+ agentId: workerId,
447
+ authMode: "none",
448
+ });
449
+
450
+ const res = await dispatch(`/api/x/script/${endpoint.id}`, {
451
+ method: "POST",
452
+ body: JSON.stringify({}),
453
+ auth: null,
454
+ });
455
+ expect(res.status).toBe(200);
456
+ const body = (await res.json()) as {
457
+ ok: boolean;
458
+ error: { type: string; message: string } | null;
459
+ };
460
+ expect(body.ok).toBe(false);
461
+ expect(body.error?.type).toBe("runtime_error");
462
+ }
463
+ } finally {
464
+ if (prevExecutor === undefined) delete process.env.SCRIPT_EXECUTOR;
465
+ else process.env.SCRIPT_EXECUTOR = prevExecutor;
466
+ }
467
+ });
468
+
424
469
  test("disabled endpoint → 404", async () => {
425
470
  const script = await insertDoubler();
426
471
  const endpoint = await createScriptApi({
@@ -291,8 +291,9 @@ describe("script SDK allowlist", () => {
291
291
 
292
292
  test("bundled swarm-sdk.d.ts uses triggerData (not input) for workflow_trigger", async () => {
293
293
  const types = await Bun.file("src/scripts-runtime/types/swarm-sdk.d.ts").text();
294
- expect(types).toContain("workflow_trigger(args: { id: string; triggerData?");
295
- expect(types).not.toContain("workflow_trigger(args: { id: string; input?");
294
+ expect(types).toMatch(/workflow_trigger\(args: \{\s*id: string;\s*triggerData\?/);
295
+ expect(types).toMatch(/workflow_trigger\(args: \{[^}]*\bwait\?: boolean;/);
296
+ expect(types).not.toMatch(/workflow_trigger\(args: \{\s*id: string;\s*input\?/);
296
297
  });
297
298
  });
298
299