@desplega.ai/agent-swarm 1.150.0 → 1.152.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 (311) hide show
  1. package/README.md +11 -0
  2. package/dist/{acp-adapter-d5mzggyk.js → acp-adapter-d05sg0q4.js} +5 -5
  3. package/dist/{actions-wn6ew0p7.js → actions-4sc0v342.js} +38 -11
  4. package/dist/{anthropic-messages-ec35ktvx.js → anthropic-messages-2y8nktar.js} +16 -16
  5. package/dist/{app-dty7p9hg.js → app-2d0v6kt6.js} +7 -7
  6. package/dist/{assistant-q4vhgjtx.js → assistant-zs6wdnrf.js} +41 -16
  7. package/dist/{azure-openai-responses-g85jv7m8.js → azure-openai-responses-f38x2avq.js} +13 -13
  8. package/dist/{boot-reembed-n15q6s9x.js → boot-reembed-3dwdnnsr.js} +13 -15
  9. package/dist/{boot-reembed-92292pgf.js → boot-reembed-vhh33520.js} +8 -8
  10. package/dist/{boot-scrub-logs-44pc955m.js → boot-scrub-logs-e1fnabcg.js} +5 -5
  11. package/dist/{claude-adapter-cjegjbje.js → claude-adapter-h58xqzzd.js} +12 -13
  12. package/dist/{claude-managed-adapter-p3ts5m9m.js → claude-managed-adapter-dsmkcrjy.js} +3 -3
  13. package/dist/{claude-sdk-session-7ywbn12v.js → claude-sdk-session-pbaczbgt.js} +12 -13
  14. package/dist/{cli-9gqddmxs.js → cli-4fqn2vpg.js} +8 -8
  15. package/dist/{cli-mzb0n642.js → cli-4wppfkcm.js} +350 -20
  16. package/dist/{cli-h505yhex.js → cli-5bqt4gwa.js} +2 -2
  17. package/dist/{cli-hbagregr.js → cli-5p007m2q.js} +88 -13
  18. package/dist/{cli-3ckzxdt1.js → cli-6k2athpf.js} +94 -81
  19. package/dist/{cli-3mh119qv.js → cli-72vksk1n.js} +9855 -693
  20. package/dist/{cli-taym3dmg.js → cli-87hdfyde.js} +13 -13
  21. package/dist/{cli-zthatyrx.js → cli-8fy9dmpv.js} +5 -5
  22. package/dist/{cli-asvrh7kj.js → cli-9xvdm3bx.js} +1 -1
  23. package/dist/{cli-72xdszyx.js → cli-awb59f08.js} +2 -2
  24. package/dist/{cli-vr6qj104.js → cli-cs9z1hw3.js} +1 -1
  25. package/dist/{cli-kt7wevqh.js → cli-cwvey7n1.js} +164 -56
  26. package/dist/{cli-5my3bjsd.js → cli-d3p82erb.js} +7 -7
  27. package/dist/{cli-7kwmt3r5.js → cli-evgy5w3y.js} +9 -3
  28. package/dist/{cli-111ey3ra.js → cli-f1f9n77e.js} +5 -5
  29. package/dist/{cli-ttje5a4z.js → cli-fhdssm2v.js} +105 -56
  30. package/dist/{cli-a45d5v9b.js → cli-fm4ytsdk.js} +2 -2
  31. package/dist/{cli-qp69dd5d.js → cli-gacq5hg8.js} +116 -14
  32. package/dist/{cli-hmyynq9b.js → cli-ht5rs63n.js} +1 -1
  33. package/dist/{cli-dyx0237s.js → cli-j4nv2wqy.js} +2 -4
  34. package/dist/{cli-gm0fhz13.js → cli-jh9txj4n.js} +2 -1
  35. package/dist/{cli-8chp8xab.js → cli-nd5s3m4y.js} +2 -2
  36. package/dist/{cli-zd21jrrc.js → cli-p2hx1pxm.js} +9872 -424
  37. package/dist/cli-pf9q3696.js +172 -0
  38. package/dist/{cli-7fesa1ky.js → cli-pgj4a5fb.js} +1 -1
  39. package/dist/{cli-07jd68a1.js → cli-re8z5p8p.js} +1 -1
  40. package/dist/{cli-ryz8q8p1.js → cli-t1mykkng.js} +40 -40
  41. package/dist/{cli-ck1vqzdj.js → cli-t6axtdcg.js} +9 -4
  42. package/dist/{cli-1mx65de9.js → cli-wbyk465z.js} +1 -1
  43. package/dist/{cli-kyysm7m3.js → cli-wp7cejrg.js} +1 -1
  44. package/dist/{cli-n75jt793.js → cli-z61ykvam.js} +6 -5
  45. package/dist/{cli-ceb5y160.js → cli-zdcdh02m.js} +1 -1
  46. package/dist/{cli-cmp8g3sw.js → cli-zfzznn7c.js} +45 -9
  47. package/dist/cli.js +22 -21
  48. package/dist/{codex-adapter-rn3aq7jm.js → codex-adapter-v3cz462q.js} +8 -9
  49. package/dist/{codex-hook-gthcmm0g.js → codex-hook-8jexc34x.js} +2 -2
  50. package/dist/{codex-session-runner-bge0cbsw.js → codex-session-runner-de1a5g5z.js} +8 -9
  51. package/dist/{commands-26phw0pc.js → commands-wfqqpn95.js} +5 -5
  52. package/dist/{db-jxjx6s1b.js → db-9zzv5y05.js} +5 -5
  53. package/dist/dispatcher-hfm1jbgx.js +74 -0
  54. package/dist/{google-generative-ai-tsskx7te.js → google-generative-ai-ndjmj5fa.js} +7 -7
  55. package/dist/{google-vertex-pkhpkbq9.js → google-vertex-fr665tqs.js} +10 -10
  56. package/dist/handlers-wrrhsack.js +65 -0
  57. package/dist/{hook-jw0ztn96.js → hook-9skye8zd.js} +9 -10
  58. package/dist/{hook-t6fqsggw.js → hook-fgjv62k5.js} +9 -10
  59. package/dist/{http-hyc7s57s.js → http-7grttjfq.js} +1434 -579
  60. package/dist/{index-bcyx5djw.js → index-29gxx9ar.js} +25 -17
  61. package/dist/{index-wtwpthe1.js → index-30pz2h9w.js} +25 -19
  62. package/dist/{index-1d9r6a74.js → index-4ek1df87.js} +26 -20
  63. package/dist/{index-sfhaq59d.js → index-myfwqqyq.js} +120 -102
  64. package/dist/index-pfhzrh1d.js +25 -0
  65. package/dist/{keepalive-fbsak4ya.js → keepalive-j75m2m7k.js} +7 -7
  66. package/dist/{lead-rdzdm627.js → lead-a1hpjt0a.js} +41 -49
  67. package/dist/{maintenance-25z1c1vf.js → maintenance-tngjzqdq.js} +8 -8
  68. package/dist/{node-209sxmg3.js → node-x1g4v0pq.js} +9 -9
  69. package/dist/{oauth-refresh-sweep-j3d7gtse.js → oauth-refresh-sweep-em1fn044.js} +6 -6
  70. package/dist/{onboard-dkcwrc75.js → onboard-fv7ezvwx.js} +13 -4
  71. package/dist/{openai-codex-responses-pm5gnyfa.js → openai-codex-responses-wy6a43wd.js} +11 -11
  72. package/dist/{openai-responses-vwvk1taj.js → openai-responses-6xwf7bzg.js} +13 -13
  73. package/dist/{opencode-adapter-dce4wskd.js → opencode-adapter-28axqa09.js} +4 -4
  74. package/dist/{otel-impl-8rgyy3j8.js → otel-impl-6vbb568y.js} +1 -1
  75. package/dist/{pi-mono-adapter-4s2bbkgq.js → pi-mono-adapter-jcqt71cg.js} +14 -16
  76. package/dist/{pricing-refresh-9cek71nq.js → pricing-refresh-nmm949an.js} +7 -7
  77. package/dist/{rbac-roles-vk8mqp9v.js → rbac-roles-0fz5qryx.js} +7 -7
  78. package/dist/{rbac-roles-z98s2ypy.js → rbac-roles-xtp05syf.js} +13 -9
  79. package/dist/{render-v2-3j26g0qh.js → render-v2-fpb8whme.js} +7 -7
  80. package/dist/{seed-pricing-7rxhcnzm.js → seed-pricing-zwa8bs3t.js} +6 -6
  81. package/dist/{setup-e2t7vz0c.js → setup-3ybwbdpd.js} +2 -2
  82. package/dist/{work-objects-8d3nd3x2.js → work-objects-rmayxcx7.js} +41 -16
  83. package/dist/{worker-0x9fn7nq.js → worker-rng4jhnh.js} +41 -49
  84. package/openapi.json +1351 -265
  85. package/package.json +2 -1
  86. package/src/agentmail/handlers.ts +95 -71
  87. package/src/be/db-client.ts +5 -0
  88. package/src/be/db.ts +12 -4
  89. package/src/be/extensions/db.ts +461 -0
  90. package/src/be/extensions/validate.ts +107 -0
  91. package/src/be/memory/boot-reembed.ts +17 -12
  92. package/src/be/memory/index.ts +12 -0
  93. package/src/be/memory/providers/openai-embedding.ts +4 -0
  94. package/src/be/memory/types.ts +2 -0
  95. package/src/be/migrations/155_extensions.sql +66 -0
  96. package/src/be/migrations/156_inbox_item_state_read_at.sql +7 -0
  97. package/src/be/rbac-roles.ts +3 -2
  98. package/src/be/scripts/typecheck.ts +56 -38
  99. package/src/be/seed-skills/index.ts +7 -0
  100. package/src/be/swarm-config-guard.ts +10 -2
  101. package/src/commands/onboard/compose-generator.ts +14 -2
  102. package/src/commands/onboard/env-generator.ts +7 -0
  103. package/src/commands/runner.ts +1 -1
  104. package/src/extensions/apply-task-create.ts +135 -0
  105. package/src/extensions/bundle-path.ts +10 -0
  106. package/src/extensions/contract-runtime.ts +7 -0
  107. package/src/extensions/contract-types.generated.ts +4 -0
  108. package/src/extensions/contract.ts +270 -0
  109. package/src/extensions/ctx.ts +186 -0
  110. package/src/extensions/dispatcher.ts +479 -0
  111. package/src/extensions/identity.ts +44 -0
  112. package/src/extensions/lifecycle.ts +303 -0
  113. package/src/extensions/loader.ts +207 -0
  114. package/src/extensions/post-bridge.ts +161 -0
  115. package/src/github/handlers.ts +185 -149
  116. package/src/gitlab/handlers.ts +97 -81
  117. package/src/heartbeat/heartbeat.ts +152 -83
  118. package/src/http/agents.ts +1 -1
  119. package/src/http/all-routes.ts +1 -0
  120. package/src/http/apps.ts +14 -10
  121. package/src/http/core.ts +34 -0
  122. package/src/http/extensions.ts +552 -0
  123. package/src/http/inbox-state.ts +2 -0
  124. package/src/http/index.ts +25 -0
  125. package/src/http/mcp-bridge.ts +96 -62
  126. package/src/http/mcp.ts +1 -1
  127. package/src/http/status.ts +6 -4
  128. package/src/http/tasks.ts +51 -35
  129. package/src/integrations/kapso/inbound.ts +15 -11
  130. package/src/jira/sync.ts +26 -18
  131. package/src/linear/sync.ts +26 -18
  132. package/src/prompts/session-templates.ts +5 -4
  133. package/src/rbac/admission.ts +1 -1
  134. package/src/rbac/elevated-agents.ts +24 -0
  135. package/src/rbac/legacy-policy.ts +47 -6
  136. package/src/rbac/permissions.ts +8 -0
  137. package/src/scheduler/deferred-task-waits.ts +133 -51
  138. package/src/scheduler/schedule-task.ts +50 -24
  139. package/src/scheduler/scheduler.ts +4 -2
  140. package/src/scripts-runtime/executors/native.ts +5 -1
  141. package/src/scripts-runtime/executors/types.ts +5 -0
  142. package/src/scripts-runtime/import-allowlist.ts +79 -19
  143. package/src/scripts-runtime/sdk-allowlist.ts +8 -0
  144. package/src/scripts-runtime/swarm-config.ts +8 -0
  145. package/src/scripts-runtime/swarm-sdk.ts +3 -0
  146. package/src/scripts-runtime/types/stdlib.d.ts +13 -0
  147. package/src/scripts-runtime/types/swarm-extension.d.ts +562 -0
  148. package/src/scripts-runtime/types/swarm-sdk.d.ts +13 -0
  149. package/src/server.ts +18 -0
  150. package/src/slack/HEURISTICS.md +1 -1
  151. package/src/slack/actions.ts +21 -17
  152. package/src/slack/blocks.ts +1 -1
  153. package/src/slack/handlers.ts +98 -5
  154. package/src/slack/inbound-files.ts +6 -2
  155. package/src/slack/render-v2.ts +181 -39
  156. package/src/slack/responses.ts +7 -4
  157. package/src/slack/router.ts +13 -3
  158. package/src/slack/steering.ts +3 -3
  159. package/src/slack/task-output.ts +21 -0
  160. package/src/slack/watcher.ts +3 -2
  161. package/src/slack/work-objects.ts +2 -1
  162. package/src/tasks/errors.ts +9 -0
  163. package/src/tasks/sibling-awareness.ts +35 -1
  164. package/src/tasks/worker-follow-up.ts +64 -12
  165. package/src/tests/base-prompt.test.ts +1 -0
  166. package/src/tests/deferred-task-wake.test.ts +161 -9
  167. package/src/tests/docs-index-footprint.test.js +3 -3
  168. package/src/tests/env-flag.test.ts +1 -0
  169. package/src/tests/extensions-db.test.ts +216 -0
  170. package/src/tests/extensions-dispatcher.test.ts +275 -0
  171. package/src/tests/extensions-example-heartbeat-remediate.test.ts +69 -0
  172. package/src/tests/extensions-example-mcp-install.test.ts +63 -0
  173. package/src/tests/extensions-example-no-exclamation-marks.test.ts +72 -0
  174. package/src/tests/extensions-example-rewrite-and-suppress.test.ts +70 -0
  175. package/src/tests/extensions-example-route-slack-channel.test.ts +217 -0
  176. package/src/tests/extensions-heartbeat.test.ts +291 -0
  177. package/src/tests/extensions-http.test.ts +512 -0
  178. package/src/tests/extensions-lead-equivalence.test.ts +70 -0
  179. package/src/tests/extensions-lifecycle.test.ts +209 -0
  180. package/src/tests/extensions-loader.test.ts +95 -0
  181. package/src/tests/extensions-mcp-tools.test.ts +353 -0
  182. package/src/tests/extensions-pre-task.test.ts +487 -0
  183. package/src/tests/extensions-run-context.test.ts +41 -0
  184. package/src/tests/extensions-tool-call.test.ts +288 -0
  185. package/src/tests/extensions-validate.test.ts +196 -0
  186. package/src/tests/fixtures/extensions/bad-import/hooks.ts +8 -0
  187. package/src/tests/fixtures/extensions/bad-import/manifest.json +9 -0
  188. package/src/tests/fixtures/extensions/bad-return-shape/hooks.ts +10 -0
  189. package/src/tests/fixtures/extensions/bad-return-shape/manifest.json +9 -0
  190. package/src/tests/fixtures/extensions/block-tasks-from-source/hooks.ts +22 -0
  191. package/src/tests/fixtures/extensions/block-tasks-from-source/manifest.json +9 -0
  192. package/src/tests/fixtures/extensions/ignore-channel/hooks.ts +22 -0
  193. package/src/tests/fixtures/extensions/ignore-channel/manifest.json +9 -0
  194. package/src/tests/fixtures/extensions/load.ts +10 -0
  195. package/src/tests/fixtures/extensions/minimal/hooks.ts +7 -0
  196. package/src/tests/fixtures/extensions/minimal/manifest.json +9 -0
  197. package/src/tests/fixtures/extensions/never-fail-long-tasks/hooks.ts +11 -0
  198. package/src/tests/fixtures/extensions/never-fail-long-tasks/manifest.json +9 -0
  199. package/src/tests/fixtures/extensions/no-exclamation-marks/hooks.ts +23 -0
  200. package/src/tests/fixtures/extensions/no-exclamation-marks/manifest.json +9 -0
  201. package/src/tests/fixtures/extensions/post-logger/hooks.ts +9 -0
  202. package/src/tests/fixtures/extensions/post-logger/manifest.json +9 -0
  203. package/src/tests/fixtures/extensions/priority-a/hooks.ts +7 -0
  204. package/src/tests/fixtures/extensions/priority-a/manifest.json +9 -0
  205. package/src/tests/fixtures/extensions/priority-b/hooks.ts +7 -0
  206. package/src/tests/fixtures/extensions/priority-b/manifest.json +9 -0
  207. package/src/tests/fixtures/extensions/record-only-on-tag/hooks.ts +16 -0
  208. package/src/tests/fixtures/extensions/record-only-on-tag/manifest.json +9 -0
  209. package/src/tests/fixtures/extensions/reserved-assets/hooks.ts +5 -0
  210. package/src/tests/fixtures/extensions/reserved-assets/manifest.json +10 -0
  211. package/src/tests/fixtures/extensions/rewrite-progress-prefix/hooks.ts +22 -0
  212. package/src/tests/fixtures/extensions/rewrite-progress-prefix/manifest.json +9 -0
  213. package/src/tests/fixtures/extensions/rewrite-task-priority/hooks.ts +7 -0
  214. package/src/tests/fixtures/extensions/rewrite-task-priority/manifest.json +9 -0
  215. package/src/tests/fixtures/extensions/route-channel-to-agent/hooks.ts +26 -0
  216. package/src/tests/fixtures/extensions/route-channel-to-agent/manifest.json +9 -0
  217. package/src/tests/fixtures/extensions/slow/hooks.ts +10 -0
  218. package/src/tests/fixtures/extensions/slow/manifest.json +9 -0
  219. package/src/tests/fixtures/extensions/suppress-lead-follow-up/hooks.ts +12 -0
  220. package/src/tests/fixtures/extensions/suppress-lead-follow-up/manifest.json +9 -0
  221. package/src/tests/fixtures/extensions/throws/hooks.ts +12 -0
  222. package/src/tests/fixtures/extensions/throws/manifest.json +9 -0
  223. package/src/tests/fixtures/extensions/worker-runtime/hooks.ts +5 -0
  224. package/src/tests/fixtures/extensions/worker-runtime/manifest.json +9 -0
  225. package/src/tests/fixtures/store-progress-malformed-output.json +4 -0
  226. package/src/tests/memory-edit-authorization.test.ts +32 -0
  227. package/src/tests/multi-runtime-enabled-stats.test.ts +2 -2
  228. package/src/tests/multi-runtime-registration.test.ts +14 -14
  229. package/src/tests/onboard-compose.test.ts +44 -0
  230. package/src/tests/preload.ts +5 -0
  231. package/src/tests/rbac-admission-e2e.test.ts +35 -4
  232. package/src/tests/rbac-admission.test.ts +18 -3
  233. package/src/tests/rbac-e2e-helpers.ts +18 -0
  234. package/src/tests/rbac-engine.test.ts +39 -0
  235. package/src/tests/rbac-mcp-admission-e2e.test.ts +22 -4
  236. package/src/tests/realtime-room-auth.test.ts +1 -1
  237. package/src/tests/reload-config.test.ts +61 -0
  238. package/src/tests/routing-affinity-inventory.test.ts +1 -1
  239. package/src/tests/script-connections.test.ts +2 -0
  240. package/src/tests/scripts-boot-reembed.test.ts +4 -0
  241. package/src/tests/scripts-embeddings.test.ts +4 -0
  242. package/src/tests/scripts-import-allowlist.test.ts +44 -1
  243. package/src/tests/scripts-mcp-e2e.test.ts +80 -0
  244. package/src/tests/scripts-only-gating.test.ts +6 -0
  245. package/src/tests/scripts-runtime-identity.test.ts +1 -1
  246. package/src/tests/slack-blocks.test.ts +12 -1
  247. package/src/tests/slack-render-v2.test.ts +100 -5
  248. package/src/tests/slack-router.test.ts +17 -2
  249. package/src/tests/slack-steering.test.ts +19 -0
  250. package/src/tests/slack-task-output.test.ts +36 -0
  251. package/src/tests/status.test.ts +12 -0
  252. package/src/tests/steering-enabled.test.ts +6 -8
  253. package/src/tests/store-progress-attachments-handler.test.ts +100 -1
  254. package/src/tests/swarm-config-reserved-keys.test.ts +6 -1
  255. package/src/tests/task-tool-preload-mcp.test.ts +4 -1
  256. package/src/tests/tool-annotations.test.ts +1 -1
  257. package/src/tests/tool-registrar-no-input.test.ts +42 -1
  258. package/src/tools/defer-task.ts +1 -1
  259. package/src/tools/extension-activate-version.ts +38 -0
  260. package/src/tools/extension-common.ts +85 -0
  261. package/src/tools/extension-delete.ts +29 -0
  262. package/src/tools/extension-disable.ts +36 -0
  263. package/src/tools/extension-enable.ts +36 -0
  264. package/src/tools/extension-install.ts +65 -0
  265. package/src/tools/extension-list.ts +66 -0
  266. package/src/tools/script-common.ts +43 -18
  267. package/src/tools/send-task.ts +69 -107
  268. package/src/tools/store-progress.ts +30 -0
  269. package/src/tools/task-action.ts +43 -22
  270. package/src/tools/task-tool-ctx.ts +2 -0
  271. package/src/tools/tool-config.ts +7 -1
  272. package/src/tools/utils.ts +140 -16
  273. package/src/types.ts +133 -0
  274. package/src/utils/multi-runtime.ts +2 -2
  275. package/src/utils/steering-enabled.ts +4 -4
  276. package/src/workflows/executors/agent-task.ts +13 -3
  277. package/templates/extensions/README.md +17 -0
  278. package/templates/extensions/notify-on-complete/README.md +11 -0
  279. package/templates/extensions/notify-on-complete/hooks.ts +61 -0
  280. package/templates/extensions/notify-on-complete/manifest.json +7 -0
  281. package/templates/extensions/require-ticket-ref/README.md +11 -0
  282. package/templates/extensions/require-ticket-ref/hooks.ts +30 -0
  283. package/templates/extensions/require-ticket-ref/manifest.json +7 -0
  284. package/templates/extensions/require-verification-note/README.md +11 -0
  285. package/templates/extensions/require-verification-note/hooks.ts +32 -0
  286. package/templates/extensions/require-verification-note/manifest.json +7 -0
  287. package/templates/skills/agent-browser/SKILL.md +84 -0
  288. package/templates/skills/agent-browser/content.md +21 -0
  289. package/templates/skills/scheduling/content.md +2 -0
  290. package/templates/skills/swarm-extensions/config.json +14 -0
  291. package/templates/skills/swarm-extensions/content.md +120 -0
  292. package/dist/cli-b8x19vbh.js +0 -823
  293. package/dist/cli-n1yj5fd5.js +0 -164
  294. package/dist/cli-q04q68be.js +0 -3066
  295. package/dist/cli-qgm2pfpq.js +0 -6377
  296. package/dist/cli-rnsr8asm.js +0 -4323
  297. package/dist/cli-rwp3ksm7.js +0 -545
  298. package/dist/cli-xjb9wghj.js +0 -668
  299. package/dist/cli-xvkmedgn.js +0 -332
  300. package/dist/cli-ydk0wjj8.js +0 -338
  301. package/dist/handlers-vr1djg4n.js +0 -41
  302. package/dist/{claude-managed-setup-f5pmsyrp.js → claude-managed-setup-48dwg9bv.js} +3 -3
  303. package/dist/{cli-81r683bv.js → cli-ch38q5z4.js} +0 -0
  304. package/dist/{cli-wk0gjrn3.js → cli-kj76p1ez.js} +6 -6
  305. package/dist/{cli-c71mg51n.js → cli-r2fpe7cx.js} +5 -5
  306. package/dist/{cli-8qx7jnrk.js → cli-y6x0gqtg.js} +16 -16
  307. package/dist/{index-aa3sa6s8.js → index-2wsdsnmm.js} +1 -1
  308. package/dist/{mistral-conversations-4ryk7h83.js → mistral-conversations-qhr84ph3.js} +9 -9
  309. package/dist/{openai-completions-qdcmkfnr.js → openai-completions-32rdwmze.js} +17 -17
  310. package/dist/{openrouter-images-qx18fyp8.js → openrouter-images-9f9ek4rw.js} +3 -3
  311. package/dist/{pi-messages-79jvzz1d.js → pi-messages-b1mbr6gp.js} +4 -4
@@ -1,9 +1,14 @@
1
1
  import ts from "typescript";
2
2
 
3
- const ALLOWED_BARE_IMPORTS = new Set(["swarm-sdk", "stdlib", "zod"]);
3
+ const SCRIPT_ALLOWED_BARE_IMPORTS = ["swarm-sdk", "stdlib", "zod"] as const;
4
4
  const FORBIDDEN_HINTS = new Set(["node:", "bun:", "fs", "child_process", "crypto", "bun:sqlite"]);
5
- const ALLOWLIST_REMEDY =
6
- 'Allowed imports are "swarm-sdk", "stdlib", "zod", and relative paths ("./" or "../").';
5
+
6
+ export type ImportAllowlistOptions = {
7
+ allowedBare: readonly string[];
8
+ allowRelative: boolean;
9
+ // Extensions need strict dynamic imports because they run in-process without a sandbox.
10
+ strictDynamic?: boolean;
11
+ };
7
12
 
8
13
  export type ImportAllowlistResult =
9
14
  | { ok: true }
@@ -13,11 +18,18 @@ function isRelative(specifier: string): boolean {
13
18
  return specifier.startsWith("./") || specifier.startsWith("../");
14
19
  }
15
20
 
16
- function isAllowed(specifier: string): boolean {
17
- return isRelative(specifier) || ALLOWED_BARE_IMPORTS.has(specifier);
21
+ function isAllowed(specifier: string, options: ImportAllowlistOptions): boolean {
22
+ return (
23
+ (options.allowRelative && isRelative(specifier)) || options.allowedBare.includes(specifier)
24
+ );
18
25
  }
19
26
 
20
- function collectImportSpecifiers(source: string): string[] {
27
+ type CollectedImports = {
28
+ imports: string[];
29
+ unsupportedSyntax: "import()" | "require()" | "import-equals" | null;
30
+ };
31
+
32
+ function collectImportSpecifiers(source: string, strictDynamic = false): CollectedImports {
21
33
  const sourceFile = ts.createSourceFile(
22
34
  "user-script.ts",
23
35
  source,
@@ -26,6 +38,7 @@ function collectImportSpecifiers(source: string): string[] {
26
38
  ts.ScriptKind.TS,
27
39
  );
28
40
  const imports: string[] = [];
41
+ let unsupportedSyntax: CollectedImports["unsupportedSyntax"] = null;
29
42
 
30
43
  const visit = (node: ts.Node) => {
31
44
  if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) {
@@ -34,19 +47,42 @@ function collectImportSpecifiers(source: string): string[] {
34
47
  imports.push(moduleSpecifier.text);
35
48
  }
36
49
 
50
+ if (
51
+ strictDynamic &&
52
+ ts.isImportEqualsDeclaration(node) &&
53
+ ts.isExternalModuleReference(node.moduleReference)
54
+ ) {
55
+ const specifier = node.moduleReference.expression;
56
+ if (specifier && ts.isStringLiteralLike(specifier)) imports.push(specifier.text);
57
+ else unsupportedSyntax ??= "import-equals";
58
+ }
59
+
37
60
  if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
38
61
  const [arg] = node.arguments;
39
- if (arg && ts.isStringLiteral(arg)) imports.push(arg.text);
62
+ if (arg && (ts.isStringLiteral(arg) || (strictDynamic && ts.isStringLiteralLike(arg))))
63
+ imports.push(arg.text);
64
+ else if (strictDynamic) unsupportedSyntax ??= "import()";
65
+ }
66
+
67
+ if (
68
+ strictDynamic &&
69
+ ts.isCallExpression(node) &&
70
+ ts.isIdentifier(node.expression) &&
71
+ node.expression.text === "require"
72
+ ) {
73
+ const [arg] = node.arguments;
74
+ if (arg && ts.isStringLiteralLike(arg)) imports.push(arg.text);
75
+ else unsupportedSyntax ??= "require()";
40
76
  }
41
77
 
42
78
  ts.forEachChild(node, visit);
43
79
  };
44
80
 
45
81
  visit(sourceFile);
46
- return imports;
82
+ return { imports, unsupportedSyntax };
47
83
  }
48
84
 
49
- function findForbiddenDynamicCode(source: string): string | null {
85
+ function findForbiddenDynamicCode(source: string, subject: string): string | null {
50
86
  const sourceFile = ts.createSourceFile(
51
87
  "user-script.ts",
52
88
  source,
@@ -64,7 +100,7 @@ function findForbiddenDynamicCode(source: string): string | null {
64
100
  node.expression.kind === ts.SyntaxKind.Identifier &&
65
101
  node.expression.getText(sourceFile) === "eval"
66
102
  ) {
67
- diagnostic = "eval is not allowed in swarm scripts";
103
+ diagnostic = `eval is not allowed in ${subject}`;
68
104
  return;
69
105
  }
70
106
 
@@ -73,7 +109,7 @@ function findForbiddenDynamicCode(source: string): string | null {
73
109
  node.expression.kind === ts.SyntaxKind.Identifier &&
74
110
  node.expression.getText(sourceFile) === "Function"
75
111
  ) {
76
- diagnostic = "Function constructor is not allowed in swarm scripts";
112
+ diagnostic = `Function constructor is not allowed in ${subject}`;
77
113
  return;
78
114
  }
79
115
 
@@ -82,7 +118,7 @@ function findForbiddenDynamicCode(source: string): string | null {
82
118
  node.expression.kind === ts.SyntaxKind.Identifier &&
83
119
  node.expression.getText(sourceFile) === "Function"
84
120
  ) {
85
- diagnostic = "Function constructor is not allowed in swarm scripts";
121
+ diagnostic = `Function constructor is not allowed in ${subject}`;
86
122
  return;
87
123
  }
88
124
 
@@ -93,23 +129,47 @@ function findForbiddenDynamicCode(source: string): string | null {
93
129
  return diagnostic;
94
130
  }
95
131
 
96
- export function validateScriptImports(source: string): ImportAllowlistResult {
97
- const dynamicDiagnostic = findForbiddenDynamicCode(source);
132
+ export function checkImportAllowlist(
133
+ source: string,
134
+ options: ImportAllowlistOptions,
135
+ ): ImportAllowlistResult {
136
+ const isExtension = options.allowedBare.includes("swarm-extension");
137
+ const subject = isExtension ? "swarm extensions" : "swarm scripts";
138
+ const dynamicDiagnostic = findForbiddenDynamicCode(source, subject);
98
139
  if (dynamicDiagnostic) return { ok: false, diagnostic: dynamicDiagnostic, imports: [] };
99
140
 
100
- const imports = collectImportSpecifiers(source);
101
- const rejected = imports.filter((specifier) => !isAllowed(specifier));
141
+ const collected = collectImportSpecifiers(source, options.strictDynamic);
142
+ if (collected.unsupportedSyntax) {
143
+ return {
144
+ ok: false,
145
+ diagnostic: `Computed ${collected.unsupportedSyntax} is not allowed in ${subject}. Use a string literal from the import allowlist.`,
146
+ imports: collected.imports,
147
+ };
148
+ }
149
+ const imports = collected.imports;
150
+ const rejected = imports.filter((specifier) => !isAllowed(specifier, options));
102
151
  if (rejected.length === 0) return { ok: true };
103
152
 
104
153
  const hint = rejected.find(
105
154
  (specifier) => FORBIDDEN_HINTS.has(specifier) || specifier.startsWith("node:"),
106
155
  );
107
156
  const reason = hint
108
- ? `Import '${hint}' is not allowed in swarm scripts`
109
- : `Import '${rejected[0]}' is not on the swarm script allowlist`;
157
+ ? `Import '${hint}' is not allowed in ${subject}`
158
+ : `Import '${rejected[0]}' is not on the ${subject} allowlist`;
159
+ const listed = options.allowedBare.map((specifier) => `"${specifier}"`).join(", ");
160
+ const allowlistRemedy = options.allowRelative
161
+ ? `Allowed imports are ${listed}, and relative paths ("./" or "../").`
162
+ : `Allowed imports are ${listed}. Relative imports are not allowed.`;
110
163
  const remedy =
111
164
  hint === "crypto" || hint === "node:crypto"
112
165
  ? "The global crypto object already provides randomUUID, getRandomValues, and subtle.digest; delete the import and use crypto directly."
113
- : ALLOWLIST_REMEDY;
166
+ : allowlistRemedy;
114
167
  return { ok: false, diagnostic: `${reason}. ${remedy}`, imports: rejected };
115
168
  }
169
+
170
+ export function validateScriptImports(source: string): ImportAllowlistResult {
171
+ return checkImportAllowlist(source, {
172
+ allowedBare: SCRIPT_ALLOWED_BARE_IMPORTS,
173
+ allowRelative: true,
174
+ });
175
+ }
@@ -56,6 +56,14 @@ export const SDK_TOOL_NAME_MAP = {
56
56
  script_getRun: "get-script-run",
57
57
  script_listRuns: "list-script-runs",
58
58
 
59
+ // ── extensions ──
60
+ extension_delete: "extension-delete",
61
+ extension_enable: "extension-enable",
62
+ extension_disable: "extension-disable",
63
+ extension_activate_version: "extension-activate-version",
64
+ extension_install: "extension-install",
65
+ extension_list: "extension-list",
66
+
59
67
  // ── swarm / agent ──
60
68
  swarm_get: "get-swarm",
61
69
  agent_info: "my-agent-info",
@@ -7,6 +7,8 @@ export class SwarmConfig {
7
7
  readonly mcpBaseUrl: RedactedValue<string>;
8
8
  /** Per-boot runtime identity of the invoking worker; system context, never script input. */
9
9
  readonly runtimeInstanceId: RedactedValue<string> | undefined;
10
+ /** Per-process extension bridge secret; present only for in-process extension SDKs. */
11
+ readonly extensionToken: RedactedValue<string> | undefined;
10
12
 
11
13
  private readonly userValues: Map<string, RedactedValue<string>>;
12
14
 
@@ -29,6 +31,12 @@ export class SwarmConfig {
29
31
  isSecret: payload.system.runtimeInstanceId.isSecret,
30
32
  })
31
33
  : undefined;
34
+ this.extensionToken = payload.system.extensionToken
35
+ ? Redacted.make(payload.system.extensionToken.value, {
36
+ type: "system",
37
+ isSecret: payload.system.extensionToken.isSecret,
38
+ })
39
+ : undefined;
32
40
  this.userValues = new Map(
33
41
  Object.entries(payload.user ?? {}).map(([key, value]) => [
34
42
  key,
@@ -20,6 +20,9 @@ function headers(config: SwarmConfig): Record<string, string> {
20
20
  ...(config.runtimeInstanceId
21
21
  ? { "X-Runtime-Instance-ID": Redacted.value(config.runtimeInstanceId) }
22
22
  : {}),
23
+ ...(config.extensionToken
24
+ ? { "X-Extension-Token": Redacted.value(config.extensionToken) }
25
+ : {}),
23
26
  "Content-Type": "application/json",
24
27
  };
25
28
  }
@@ -517,6 +517,19 @@ declare module "swarm-sdk" {
517
517
  offset?: number;
518
518
  }): Promise<unknown>;
519
519
 
520
+ // --- write: extensions ---
521
+ extension_install(args: {
522
+ manifest: Record<string, unknown>;
523
+ files: Record<string, string>;
524
+ priority?: number;
525
+ config?: Record<string, unknown>;
526
+ }): Promise<unknown>;
527
+ extension_list(args?: { enabledOnly?: boolean }): Promise<unknown>;
528
+ extension_delete(args: { id: string }): Promise<unknown>;
529
+ extension_enable(args: { id: string }): Promise<unknown>;
530
+ extension_disable(args: { id: string }): Promise<unknown>;
531
+ extension_activate_version(args: { id: string; version: number }): Promise<unknown>;
532
+
520
533
  // --- write: repos ---
521
534
  repo_update(args: Record<string, unknown>): Promise<unknown>;
522
535