@desplega.ai/agent-swarm 1.149.1 → 1.151.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 (538) hide show
  1. package/README.md +18 -3
  2. package/dist/{acp-adapter-vhkzfpjg.js → acp-adapter-ex8hzjfc.js} +5 -5
  3. package/dist/{actions-9d2694yk.js → actions-2bgpyhww.js} +39 -11
  4. package/dist/{app-fq2ggynt.js → app-1706zhr1.js} +7 -7
  5. package/dist/{artifact-gj9arwrr.js → artifact-td4q4dch.js} +1 -1
  6. package/dist/{assistant-edb6n9nn.js → assistant-bavke5p7.js} +44 -20
  7. package/dist/{azure-openai-responses-cqar64rc.js → azure-openai-responses-f38x2avq.js} +13 -13
  8. package/dist/{boot-reembed-msweabbp.js → boot-reembed-3cmrrmpa.js} +9 -9
  9. package/dist/{boot-reembed-q5wd3tha.js → boot-reembed-nafcmmmc.js} +14 -16
  10. package/dist/{boot-scrub-logs-3g1az933.js → boot-scrub-logs-cd6a2sq0.js} +5 -5
  11. package/dist/{claude-adapter-v3rnzsdc.js → claude-adapter-wfp2gzvz.js} +15 -16
  12. package/dist/{claude-managed-adapter-qvsmh6mv.js → claude-managed-adapter-dsmkcrjy.js} +3 -3
  13. package/dist/{claude-sdk-session-qxrpsna1.js → claude-sdk-session-bht9jjak.js} +15 -16
  14. package/dist/{cli-5m0qmvdp.js → cli-0qb1z6s2.js} +1 -1
  15. package/dist/{cli-9d8ntetj.js → cli-2658f6at.js} +1 -1
  16. package/dist/{cli-7evafqvy.js → cli-2tbvf1z1.js} +85 -69
  17. package/dist/{cli-k351hv5k.js → cli-3v9xhjcn.js} +24 -12
  18. package/dist/{cli-1ebpar1q.js → cli-4wppfkcm.js} +350 -20
  19. package/dist/{cli-4260r1tg.js → cli-5jd2z7av.js} +97 -84
  20. package/dist/{cli-cv7s5zdq.js → cli-5tpgq60f.js} +9865 -715
  21. package/dist/{cli-6skz3rk8.js → cli-7tgcstn2.js} +9 -4
  22. package/dist/{cli-01g3x1ca.js → cli-9004vfdf.js} +108 -56
  23. package/dist/{cli-1c94wvcw.js → cli-a1z3h107.js} +124 -99
  24. package/dist/{cli-9br8ypfv.js → cli-czjtgfys.js} +2 -2
  25. package/dist/{cli-5my3bjsd.js → cli-d3p82erb.js} +7 -7
  26. package/dist/{cli-e29gmdmw.js → cli-dv6cdjs2.js} +2 -1
  27. package/dist/{cli-wby1xnnb.js → cli-f1wky6zp.js} +1 -1
  28. package/dist/{cli-zvz62chv.js → cli-fm4ytsdk.js} +4 -4
  29. package/dist/{cli-tg8qj8ee.js → cli-frcta2w4.js} +6 -6
  30. package/dist/{cli-7xx10h0a.js → cli-g69fdc9g.js} +2 -2
  31. package/dist/{cli-cmp8g3sw.js → cli-gbfwcd3k.js} +44 -9
  32. package/dist/{handlers-nsg0bcye.js → cli-gjyvhmmh.js} +97 -45
  33. package/dist/{cli-08b07b4r.js → cli-ht5rs63n.js} +1 -1
  34. package/dist/{cli-jecc01cb.js → cli-j4nv2wqy.js} +2 -4
  35. package/dist/{cli-cd60fv6j.js → cli-j9xczhaq.js} +1 -1
  36. package/dist/cli-pf9q3696.js +172 -0
  37. package/dist/{cli-xm87hzbw.js → cli-pgj4a5fb.js} +1 -1
  38. package/dist/{cli-jezx9b9c.js → cli-ppm4975n.js} +9 -3
  39. package/dist/{cli-3z634pqe.js → cli-q88st9aj.js} +2 -2
  40. package/dist/{cli-3sysyjve.js → cli-r2q6pevn.js} +142 -49
  41. package/dist/{cli-07jd68a1.js → cli-re8z5p8p.js} +1 -1
  42. package/dist/{cli-qgd4sqz5.js → cli-s14agm5s.js} +121 -14
  43. package/dist/{cli-svbrpf5q.js → cli-sjaae6ff.js} +9872 -424
  44. package/dist/{cli-73gq0zxn.js → cli-vwm416m6.js} +13 -13
  45. package/dist/{cli-4wtq5jjv.js → cli-wbyk465z.js} +1 -1
  46. package/dist/{cli-3apbzgyk.js → cli-z61ykvam.js} +19 -14
  47. package/dist/{cli-e06a8a7y.js → cli-zkxymas5.js} +4 -3
  48. package/dist/cli.js +26 -25
  49. package/dist/{codex-adapter-jyw7a91z.js → codex-adapter-jjjk8w4m.js} +8 -9
  50. package/dist/{codex-hook-hfrt9shr.js → codex-hook-8jexc34x.js} +3 -3
  51. package/dist/{codex-session-runner-bmngj0s5.js → codex-session-runner-nd6ayxkx.js} +8 -9
  52. package/dist/{commands-n755g391.js → commands-9v4psyq1.js} +5 -5
  53. package/dist/{db-s1cgh5gv.js → db-wnt58tpe.js} +5 -5
  54. package/dist/dispatcher-05jh1aqk.js +74 -0
  55. package/dist/{e2b-p04vmtx0.js → e2b-413b8t4v.js} +1 -1
  56. package/dist/{google-generative-ai-tsskx7te.js → google-generative-ai-ndjmj5fa.js} +7 -7
  57. package/dist/{google-vertex-ppw8ydpa.js → google-vertex-fr665tqs.js} +10 -10
  58. package/dist/handlers-tw90pkh5.js +65 -0
  59. package/dist/{hook-jf0xe8zh.js → hook-123e2scb.js} +11 -12
  60. package/dist/{hook-h9cqrm8q.js → hook-sxe3r349.js} +11 -12
  61. package/dist/{http-nc6pydw5.js → http-ecsar8ez.js} +1442 -581
  62. package/dist/{index-ezxkds2n.js → index-16js521z.js} +335 -107
  63. package/dist/{index-769nc012.js → index-hw26vj40.js} +25 -19
  64. package/dist/{index-0wdy6gwc.js → index-nnrbpcjp.js} +25 -17
  65. package/dist/index-ymn7em0p.js +25 -0
  66. package/dist/{index-x1zcj09z.js → index-zj518gf9.js} +26 -20
  67. package/dist/{keepalive-nesm3xb6.js → keepalive-asqtcm4y.js} +7 -7
  68. package/dist/{lead-bwy6t2za.js → lead-xbfr7fvt.js} +40 -48
  69. package/dist/{maintenance-8w393zf0.js → maintenance-qma55qvw.js} +9 -9
  70. package/dist/{oauth-refresh-sweep-sh8xjy08.js → oauth-refresh-sweep-3s04c6qw.js} +6 -6
  71. package/dist/{onboard-25ps29h1.js → onboard-drskd386.js} +13 -4
  72. package/dist/{openai-codex-responses-g7w48y30.js → openai-codex-responses-wy6a43wd.js} +13 -13
  73. package/dist/{openai-responses-nmeyptke.js → openai-responses-6xwf7bzg.js} +19 -19
  74. package/dist/{opencode-adapter-dce4wskd.js → opencode-adapter-28axqa09.js} +4 -4
  75. package/dist/{otel-impl-b93gxnz5.js → otel-impl-943c96er.js} +1 -1
  76. package/dist/{pi-mono-adapter-zvshk5cj.js → pi-mono-adapter-jcqt71cg.js} +17 -19
  77. package/dist/{pricing-refresh-5v56x7gb.js → pricing-refresh-mx51az05.js} +7 -7
  78. package/dist/{rbac-roles-x55cnezn.js → rbac-roles-78baecqd.js} +13 -9
  79. package/dist/{rbac-roles-0p0s6pbj.js → rbac-roles-wcmrg6sv.js} +7 -7
  80. package/dist/{render-v2-hyd45w8b.js → render-v2-8zjntgf5.js} +7 -7
  81. package/dist/{seed-pricing-49gbgn96.js → seed-pricing-jqjs6cws.js} +6 -6
  82. package/dist/{setup-qvq64vzq.js → setup-4pks0vfk.js} +2 -2
  83. package/dist/work-objects-wangt792.js +165 -0
  84. package/dist/{worker-scj60cxg.js → worker-p2mr422x.js} +40 -48
  85. package/openapi.json +1365 -268
  86. package/package.json +4 -3
  87. package/src/agentmail/handlers.ts +95 -66
  88. package/src/be/budget-refusal-notify.ts +1 -0
  89. package/src/be/db/tasks/read.ts +3 -0
  90. package/src/be/db/tasks/write.ts +13 -1
  91. package/src/be/db-client.ts +5 -0
  92. package/src/be/db.ts +15 -5
  93. package/src/be/extensions/db.ts +461 -0
  94. package/src/be/extensions/validate.ts +107 -0
  95. package/src/be/memory/boot-reembed.ts +17 -12
  96. package/src/be/memory/index.ts +12 -0
  97. package/src/be/memory/providers/openai-embedding.ts +4 -0
  98. package/src/be/memory/types.ts +2 -0
  99. package/src/be/migrations/153_deferred_task_wait_members.sql +25 -0
  100. package/src/be/migrations/154_routing_source.sql +3 -0
  101. package/src/be/migrations/155_extensions.sql +66 -0
  102. package/src/be/migrations/156_inbox_item_state_read_at.sql +7 -0
  103. package/src/be/rbac-roles.ts +3 -2
  104. package/src/be/scripts/typecheck.ts +59 -41
  105. package/src/be/seed/schedules-seeder.ts +25 -2
  106. package/src/be/seed/workflows-seeder.ts +17 -0
  107. package/src/be/seed-scripts/catalog/delegate.ts +3 -1
  108. package/src/be/seed-skills/bundled-files.generated.json +1 -1
  109. package/src/be/seed-skills/index.ts +7 -0
  110. package/src/be/steering.ts +1 -0
  111. package/src/be/swarm-config-guard.ts +3 -1
  112. package/src/commands/credential-refresh.ts +70 -0
  113. package/src/commands/onboard/compose-generator.ts +14 -2
  114. package/src/commands/onboard/env-generator.ts +7 -0
  115. package/src/commands/provider-credentials.ts +2 -25
  116. package/src/commands/runner.ts +24 -57
  117. package/src/extensions/apply-task-create.ts +135 -0
  118. package/src/extensions/bundle-path.ts +10 -0
  119. package/src/extensions/contract-runtime.ts +7 -0
  120. package/src/extensions/contract-types.generated.ts +4 -0
  121. package/src/extensions/contract.ts +270 -0
  122. package/src/extensions/ctx.ts +186 -0
  123. package/src/extensions/dispatcher.ts +479 -0
  124. package/src/extensions/identity.ts +44 -0
  125. package/src/extensions/lifecycle.ts +281 -0
  126. package/src/extensions/loader.ts +207 -0
  127. package/src/extensions/post-bridge.ts +161 -0
  128. package/src/github/handlers.ts +185 -140
  129. package/src/gitlab/handlers.ts +97 -77
  130. package/src/heartbeat/heartbeat.ts +155 -83
  131. package/src/http/agents.ts +1 -1
  132. package/src/http/all-routes.ts +1 -0
  133. package/src/http/approval-requests.ts +1 -0
  134. package/src/http/apps.ts +14 -9
  135. package/src/http/config.ts +4 -1
  136. package/src/http/core.ts +38 -2
  137. package/src/http/extensions.ts +547 -0
  138. package/src/http/inbox-state.ts +2 -0
  139. package/src/http/index.ts +41 -3
  140. package/src/http/mcp-bridge.ts +96 -62
  141. package/src/http/mcp.ts +1 -1
  142. package/src/http/script-runs.ts +5 -0
  143. package/src/http/status.ts +6 -4
  144. package/src/http/tasks.ts +51 -30
  145. package/src/integrations/kapso/inbound.ts +15 -10
  146. package/src/jira/sync.ts +26 -16
  147. package/src/linear/sync.ts +26 -16
  148. package/src/prompts/session-templates.ts +18 -13
  149. package/src/providers/claude-adapter.ts +21 -8
  150. package/src/rbac/admission.ts +1 -1
  151. package/src/rbac/elevated-agents.ts +24 -0
  152. package/src/rbac/legacy-policy.ts +35 -6
  153. package/src/rbac/permissions.ts +8 -0
  154. package/src/scheduler/deferred-task-waits.ts +138 -27
  155. package/src/scheduler/schedule-task.ts +54 -24
  156. package/src/scheduler/scheduler.ts +108 -125
  157. package/src/scripts-runtime/executors/native.ts +5 -1
  158. package/src/scripts-runtime/executors/types.ts +5 -0
  159. package/src/scripts-runtime/import-allowlist.ts +79 -19
  160. package/src/scripts-runtime/sdk-allowlist.ts +4 -0
  161. package/src/scripts-runtime/swarm-config.ts +8 -0
  162. package/src/scripts-runtime/swarm-sdk.ts +3 -0
  163. package/src/scripts-runtime/types/stdlib.d.ts +16 -3
  164. package/src/scripts-runtime/types/swarm-extension.d.ts +562 -0
  165. package/src/scripts-runtime/types/swarm-sdk.d.ts +16 -3
  166. package/src/server.ts +6 -0
  167. package/src/slack/HEURISTICS.md +3 -1
  168. package/src/slack/actions.ts +21 -16
  169. package/src/slack/app.ts +2 -0
  170. package/src/slack/assistant.ts +4 -12
  171. package/src/slack/blocks.ts +1 -1
  172. package/src/slack/handlers.ts +107 -19
  173. package/src/slack/inbound-files.ts +9 -5
  174. package/src/slack/render-v2.ts +188 -38
  175. package/src/slack/router.ts +13 -3
  176. package/src/slack/steering.ts +3 -3
  177. package/src/slack/thread-buffer.ts +66 -23
  178. package/src/slack/work-objects.test.ts +252 -0
  179. package/src/slack/work-objects.ts +118 -0
  180. package/src/tasks/errors.ts +9 -0
  181. package/src/tasks/sibling-awareness.ts +35 -1
  182. package/src/tasks/worker-follow-up.ts +67 -11
  183. package/src/tests/acp-adapter.test.ts +10 -10
  184. package/src/tests/agent-fs-live-url.test.ts +40 -0
  185. package/src/tests/agent-fs-provision-seeder.test.ts +12 -12
  186. package/src/tests/api-key-tracking.test.ts +18 -18
  187. package/src/tests/api-key.test.ts +4 -2
  188. package/src/tests/apps-rbac.test.ts +1 -1
  189. package/src/tests/apps-spike5.test.ts +1 -1
  190. package/src/tests/apps-sync-engine.test.ts +8 -8
  191. package/src/tests/apps-user-config.test.ts +1 -1
  192. package/src/tests/artifact-sdk.test.ts +8 -8
  193. package/src/tests/asset-key-mcp.test.ts +2 -0
  194. package/src/tests/automation-preflight-alert.test.ts +1 -1
  195. package/src/tests/base-prompt.test.ts +7 -6
  196. package/src/tests/budget-user-scope.test.ts +1 -1
  197. package/src/tests/budgets-routes.test.ts +1 -1
  198. package/src/tests/claude-adapter-binary.test.ts +22 -40
  199. package/src/tests/claude-adapter-otel.test.ts +13 -7
  200. package/src/tests/claude-adapter.test.ts +8 -6
  201. package/src/tests/claude-hook-credentials.test.ts +3 -3
  202. package/src/tests/claude-managed-adapter.test.ts +4 -4
  203. package/src/tests/claude-managed-setup.test.ts +3 -3
  204. package/src/tests/claude-sdk-lifecycle.test.ts +1 -1
  205. package/src/tests/claude-sdk-transport.test.ts +6 -6
  206. package/src/tests/claude-stop-hook.test.ts +8 -8
  207. package/src/tests/claude-worker-parity.test.ts +3 -3
  208. package/src/tests/codex-adapter-pool-auth-revalidate.test.ts +5 -5
  209. package/src/tests/codex-adapter.test.ts +7 -5
  210. package/src/tests/codex-app-server.test.ts +2 -2
  211. package/src/tests/codex-login.test.ts +15 -15
  212. package/src/tests/codex-oauth-credential-info.test.ts +4 -4
  213. package/src/tests/codex-oauth-keep-warm.test.ts +4 -4
  214. package/src/tests/codex-oauth-refresh-lock.test.ts +1 -1
  215. package/src/tests/codex-oauth-storage.test.ts +7 -7
  216. package/src/tests/codex-pool.test.ts +1 -1
  217. package/src/tests/codex-steering-hook.test.ts +1 -1
  218. package/src/tests/codex-swarm-events.test.ts +1 -1
  219. package/src/tests/config-api-only-keys.test.ts +1 -1
  220. package/src/tests/config-session-auth.test.ts +2 -2
  221. package/src/tests/connection-embedded-auth.test.ts +20 -18
  222. package/src/tests/core-auth.test.ts +1 -1
  223. package/src/tests/create-page-tool.test.ts +3 -3
  224. package/src/tests/credential-refresh.test.ts +115 -0
  225. package/src/tests/credential-wait.test.ts +2 -2
  226. package/src/tests/credentials.test.ts +6 -4
  227. package/src/tests/db-queries-oauth.test.ts +40 -40
  228. package/src/tests/defer-task.test.ts +73 -8
  229. package/src/tests/deferred-task-wait-migration.test.ts +64 -0
  230. package/src/tests/deferred-task-wake.test.ts +349 -8
  231. package/src/tests/devin-adapter.test.ts +1 -1
  232. package/src/tests/devin-api.test.ts +1 -1
  233. package/src/tests/docs-index-footprint.test.js +3 -3
  234. package/src/tests/e2b-dispatch.test.ts +21 -19
  235. package/src/tests/e2e-claude-transport.test.ts +3 -3
  236. package/src/tests/e2e-redact.test.ts +6 -6
  237. package/src/tests/ensure-token.test.ts +68 -68
  238. package/src/tests/entrypoint-api-readiness.test.ts +1 -1
  239. package/src/tests/entrypoint-codex-oauth-seed.test.ts +13 -13
  240. package/src/tests/env-flag.test.ts +1 -0
  241. package/src/tests/events-http.test.ts +1 -1
  242. package/src/tests/extensions-db.test.ts +216 -0
  243. package/src/tests/extensions-dispatcher.test.ts +275 -0
  244. package/src/tests/extensions-example-heartbeat-remediate.test.ts +69 -0
  245. package/src/tests/extensions-example-mcp-install.test.ts +63 -0
  246. package/src/tests/extensions-example-no-exclamation-marks.test.ts +72 -0
  247. package/src/tests/extensions-example-rewrite-and-suppress.test.ts +70 -0
  248. package/src/tests/extensions-example-route-slack-channel.test.ts +217 -0
  249. package/src/tests/extensions-heartbeat.test.ts +291 -0
  250. package/src/tests/extensions-http.test.ts +431 -0
  251. package/src/tests/extensions-lead-equivalence.test.ts +49 -0
  252. package/src/tests/extensions-lifecycle.test.ts +209 -0
  253. package/src/tests/extensions-loader.test.ts +95 -0
  254. package/src/tests/extensions-mcp-tools.test.ts +245 -0
  255. package/src/tests/extensions-pre-task.test.ts +487 -0
  256. package/src/tests/extensions-run-context.test.ts +41 -0
  257. package/src/tests/extensions-tool-call.test.ts +288 -0
  258. package/src/tests/extensions-validate.test.ts +196 -0
  259. package/src/tests/fixtures/extensions/bad-import/hooks.ts +8 -0
  260. package/src/tests/fixtures/extensions/bad-import/manifest.json +9 -0
  261. package/src/tests/fixtures/extensions/bad-return-shape/hooks.ts +10 -0
  262. package/src/tests/fixtures/extensions/bad-return-shape/manifest.json +9 -0
  263. package/src/tests/fixtures/extensions/block-tasks-from-source/hooks.ts +22 -0
  264. package/src/tests/fixtures/extensions/block-tasks-from-source/manifest.json +9 -0
  265. package/src/tests/fixtures/extensions/ignore-channel/hooks.ts +22 -0
  266. package/src/tests/fixtures/extensions/ignore-channel/manifest.json +9 -0
  267. package/src/tests/fixtures/extensions/load.ts +10 -0
  268. package/src/tests/fixtures/extensions/minimal/hooks.ts +7 -0
  269. package/src/tests/fixtures/extensions/minimal/manifest.json +9 -0
  270. package/src/tests/fixtures/extensions/never-fail-long-tasks/hooks.ts +11 -0
  271. package/src/tests/fixtures/extensions/never-fail-long-tasks/manifest.json +9 -0
  272. package/src/tests/fixtures/extensions/no-exclamation-marks/hooks.ts +23 -0
  273. package/src/tests/fixtures/extensions/no-exclamation-marks/manifest.json +9 -0
  274. package/src/tests/fixtures/extensions/post-logger/hooks.ts +9 -0
  275. package/src/tests/fixtures/extensions/post-logger/manifest.json +9 -0
  276. package/src/tests/fixtures/extensions/priority-a/hooks.ts +7 -0
  277. package/src/tests/fixtures/extensions/priority-a/manifest.json +9 -0
  278. package/src/tests/fixtures/extensions/priority-b/hooks.ts +7 -0
  279. package/src/tests/fixtures/extensions/priority-b/manifest.json +9 -0
  280. package/src/tests/fixtures/extensions/record-only-on-tag/hooks.ts +16 -0
  281. package/src/tests/fixtures/extensions/record-only-on-tag/manifest.json +9 -0
  282. package/src/tests/fixtures/extensions/reserved-assets/hooks.ts +5 -0
  283. package/src/tests/fixtures/extensions/reserved-assets/manifest.json +10 -0
  284. package/src/tests/fixtures/extensions/rewrite-progress-prefix/hooks.ts +22 -0
  285. package/src/tests/fixtures/extensions/rewrite-progress-prefix/manifest.json +9 -0
  286. package/src/tests/fixtures/extensions/rewrite-task-priority/hooks.ts +7 -0
  287. package/src/tests/fixtures/extensions/rewrite-task-priority/manifest.json +9 -0
  288. package/src/tests/fixtures/extensions/route-channel-to-agent/hooks.ts +26 -0
  289. package/src/tests/fixtures/extensions/route-channel-to-agent/manifest.json +9 -0
  290. package/src/tests/fixtures/extensions/slow/hooks.ts +10 -0
  291. package/src/tests/fixtures/extensions/slow/manifest.json +9 -0
  292. package/src/tests/fixtures/extensions/suppress-lead-follow-up/hooks.ts +12 -0
  293. package/src/tests/fixtures/extensions/suppress-lead-follow-up/manifest.json +9 -0
  294. package/src/tests/fixtures/extensions/throws/hooks.ts +12 -0
  295. package/src/tests/fixtures/extensions/throws/manifest.json +9 -0
  296. package/src/tests/fixtures/extensions/worker-runtime/hooks.ts +5 -0
  297. package/src/tests/fixtures/extensions/worker-runtime/manifest.json +9 -0
  298. package/src/tests/fs-routes.test.ts +1 -1
  299. package/src/tests/gitlab-auth.test.ts +10 -10
  300. package/src/tests/harness-provider-resolution.test.ts +8 -5
  301. package/src/tests/heartbeat-reroute-decision.test.ts +1 -0
  302. package/src/tests/helper-credentials.test.ts +137 -0
  303. package/src/tests/http/context-routes.test.ts +2 -2
  304. package/src/tests/http-api-integration.test.ts +5 -2
  305. package/src/tests/http-users.test.ts +1 -1
  306. package/src/tests/identity-refresh.test.ts +2 -2
  307. package/src/tests/internal-ai/complete-structured.test.ts +2 -2
  308. package/src/tests/internal-ai/credentials.test.ts +19 -17
  309. package/src/tests/jira-metadata.test.ts +1 -1
  310. package/src/tests/jira-oauth.test.ts +5 -5
  311. package/src/tests/jira-sync.test.ts +1 -1
  312. package/src/tests/jira-webhook-lifecycle.test.ts +3 -3
  313. package/src/tests/jira-webhook.test.ts +2 -2
  314. package/src/tests/kapso-inbound.test.ts +2 -2
  315. package/src/tests/kv-http.test.ts +1 -1
  316. package/src/tests/kv-namespace-resolution.test.ts +1 -1
  317. package/src/tests/kv-page-proxy.test.ts +2 -2
  318. package/src/tests/launch-password-rejection.test.ts +2 -2
  319. package/src/tests/linear-webhook.test.ts +1 -1
  320. package/src/tests/mcp-oauth-dcr-reuse.test.ts +6 -6
  321. package/src/tests/mcp-oauth-ensure-token.test.ts +28 -22
  322. package/src/tests/mcp-oauth-manual-client.test.ts +16 -12
  323. package/src/tests/mcp-oauth-queries.test.ts +35 -32
  324. package/src/tests/mcp-oauth-resolve-secrets.test.ts +8 -8
  325. package/src/tests/mcp-oauth-wrapper.test.ts +20 -20
  326. package/src/tests/mcp-user-route.test.ts +1 -1
  327. package/src/tests/memory-edges.test.ts +1 -1
  328. package/src/tests/memory-edit-authorization.test.ts +32 -0
  329. package/src/tests/memory-rate-endpoint.test.ts +1 -1
  330. package/src/tests/memory-rate-tool.test.ts +2 -2
  331. package/src/tests/memory-rater-e2e.test.ts +1 -1
  332. package/src/tests/memory-rater-llm-summarizer.test.ts +3 -3
  333. package/src/tests/memory-rater-llm.test.ts +1 -1
  334. package/src/tests/model-control.test.ts +3 -0
  335. package/src/tests/multi-runtime-enabled-stats.test.ts +2 -2
  336. package/src/tests/multi-runtime-registration.test.ts +111 -17
  337. package/src/tests/oauth-access-token-tool.test.ts +18 -18
  338. package/src/tests/oauth-callback-flow.test.ts +8 -8
  339. package/src/tests/oauth-credential-bindings.test.ts +29 -27
  340. package/src/tests/oauth-keepalive.test.ts +10 -10
  341. package/src/tests/oauth-presets.test.ts +13 -5
  342. package/src/tests/oauth-refresh-failure.test.ts +9 -9
  343. package/src/tests/oauth-refresh-sweep.test.ts +20 -13
  344. package/src/tests/oauth-wrapper.test.ts +1 -1
  345. package/src/tests/onboard-compose.test.ts +47 -3
  346. package/src/tests/onboard-env.test.ts +26 -26
  347. package/src/tests/onboard-non-interactive.test.ts +4 -4
  348. package/src/tests/opencode-adapter.test.ts +1 -1
  349. package/src/tests/opencode-plugin.test.ts +2 -2
  350. package/src/tests/otel-session-cost-metrics.test.ts +1 -1
  351. package/src/tests/page-proxy-authed.test.ts +2 -2
  352. package/src/tests/page-proxy.test.ts +2 -2
  353. package/src/tests/page-session.test.ts +7 -7
  354. package/src/tests/page-viewer-auth.test.ts +2 -2
  355. package/src/tests/pages-authed-mode.test.ts +1 -1
  356. package/src/tests/pages-http.test.ts +1 -1
  357. package/src/tests/pages-password-mode.test.ts +1 -1
  358. package/src/tests/pages-public-authed-401.test.ts +1 -1
  359. package/src/tests/pages-public-html.test.ts +2 -2
  360. package/src/tests/pages-view-count.test.ts +1 -1
  361. package/src/tests/pi-mono-adapter.test.ts +10 -10
  362. package/src/tests/pi-mono-extension.test.ts +2 -2
  363. package/src/tests/preload.ts +5 -0
  364. package/src/tests/pricing-routes.test.ts +1 -1
  365. package/src/tests/profile-sync-warning.test.ts +8 -8
  366. package/src/tests/profile-sync.test.ts +8 -8
  367. package/src/tests/prompt-template-session.test.ts +36 -5
  368. package/src/tests/provider-process-group.test.ts +95 -4
  369. package/src/tests/providers/pi-cost.test.ts +1 -1
  370. package/src/tests/queue-stall-alarm.test.ts +1 -1
  371. package/src/tests/rbac-admission.test.ts +19 -4
  372. package/src/tests/rbac-charact-http.test.ts +1 -1
  373. package/src/tests/rbac-e2e-helpers.ts +1 -1
  374. package/src/tests/rbac-engine.test.ts +39 -0
  375. package/src/tests/realtime-room-auth.test.ts +1 -1
  376. package/src/tests/realtime-room-surfaces.test.ts +1 -1
  377. package/src/tests/reload-config.test.ts +45 -1
  378. package/src/tests/routing-affinity-inventory.test.ts +1 -1
  379. package/src/tests/routing-reason-contract.test.ts +76 -3
  380. package/src/tests/routing-reason-inventory.test.ts +11 -6
  381. package/src/tests/routing-source.test.ts +53 -0
  382. package/src/tests/runner-agent-fs-provision-retry.test.ts +1 -1
  383. package/src/tests/runner-context-preamble.test.ts +1 -1
  384. package/src/tests/runner-deployment-resume.test.ts +1 -1
  385. package/src/tests/runner-fallback-output.test.ts +1 -1
  386. package/src/tests/runner-identity-refresh.test.ts +1 -1
  387. package/src/tests/runner-skills-refresh.test.ts +1 -1
  388. package/src/tests/schedule-target-type.test.ts +3 -3
  389. package/src/tests/scheduled-tasks.test.ts +14 -5
  390. package/src/tests/scheduler-occurrence.test.ts +347 -0
  391. package/src/tests/script-apis-mcp.test.ts +1 -1
  392. package/src/tests/script-connections-http.test.ts +61 -58
  393. package/src/tests/script-connections-mcp.test.ts +1 -1
  394. package/src/tests/script-connections.test.ts +3 -1
  395. package/src/tests/script-runs-http.test.ts +15 -7
  396. package/src/tests/script-workflows-runtime-e2e.test.ts +1 -1
  397. package/src/tests/scripts-boot-reembed.test.ts +4 -0
  398. package/src/tests/scripts-embeddings.test.ts +4 -0
  399. package/src/tests/scripts-external-api.test.ts +1 -1
  400. package/src/tests/scripts-http.test.ts +1 -1
  401. package/src/tests/scripts-import-allowlist.test.ts +44 -1
  402. package/src/tests/scripts-mcp-e2e.test.ts +81 -1
  403. package/src/tests/scripts-only-gating.test.ts +4 -2
  404. package/src/tests/scripts-retention.test.ts +1 -1
  405. package/src/tests/scripts-runtime-identity.test.ts +2 -2
  406. package/src/tests/scripts-runtime-secret-egress.test.ts +1 -1
  407. package/src/tests/scripts-runtime.test.ts +6 -4
  408. package/src/tests/scripts-typecheck.test.ts +21 -0
  409. package/src/tests/sdk-allowlist.test.ts +1 -1
  410. package/src/tests/secret-scrubber.test.ts +38 -31
  411. package/src/tests/seed-registry.test.ts +46 -8
  412. package/src/tests/seed-schedules.test.ts +44 -9
  413. package/src/tests/seed-workflows.test.ts +21 -9
  414. package/src/tests/send-task-output-schema.test.ts +9 -1
  415. package/src/tests/send-task-requested-by.test.ts +1 -0
  416. package/src/tests/send-task-slack-routing-guard.test.ts +2 -0
  417. package/src/tests/session-costs-codex-recompute.test.ts +1 -1
  418. package/src/tests/session-costs-golden.test.ts +2 -2
  419. package/src/tests/session-costs-model-key-normalize.test.ts +2 -2
  420. package/src/tests/session-costs-recompute-all-providers.test.ts +1 -1
  421. package/src/tests/session-tokens.test.ts +1 -1
  422. package/src/tests/shutdown-error-scrubbing.test.ts +1 -1
  423. package/src/tests/slack-blocks.test.ts +12 -1
  424. package/src/tests/slack-file-tools-attachments.test.ts +1 -1
  425. package/src/tests/slack-inbound-files.test.ts +222 -86
  426. package/src/tests/slack-reaction-config.test.ts +5 -4
  427. package/src/tests/slack-read-boundaries.test.ts +1 -1
  428. package/src/tests/slack-render-v2.test.ts +196 -4
  429. package/src/tests/slack-router.test.ts +17 -2
  430. package/src/tests/slack-steering.test.ts +19 -0
  431. package/src/tests/status.test.ts +19 -7
  432. package/src/tests/steering-core.test.ts +1 -1
  433. package/src/tests/steering-enabled.test.ts +6 -8
  434. package/src/tests/steering-transport.test.ts +4 -4
  435. package/src/tests/store-progress-output-guidance.test.ts +34 -0
  436. package/src/tests/swarm-tool-result-gate.test.ts +11 -11
  437. package/src/tests/swarm-x-tool.test.ts +7 -5
  438. package/src/tests/sync-ai-toolbox-skills.test.ts +19 -0
  439. package/src/tests/task-supersede-resume.test.ts +1 -1
  440. package/src/tests/task-tool-preload-mcp.test.ts +4 -1
  441. package/src/tests/task-tools-ctx.test.ts +2 -0
  442. package/src/tests/tasks-requested-by-filter.test.ts +2 -2
  443. package/src/tests/telemetry-init.test.ts +11 -3
  444. package/src/tests/tool-annotations.test.ts +1 -1
  445. package/src/tests/tool-output-agent-id.test.ts +1 -0
  446. package/src/tests/tool-registrar-no-input.test.ts +42 -1
  447. package/src/tests/tracker-fold.test.ts +7 -7
  448. package/src/tests/tracker-tools.test.ts +3 -3
  449. package/src/tests/ui-followup-lead-delegation.test.ts +1 -0
  450. package/src/tests/unified-oauth-migration.test.ts +5 -5
  451. package/src/tests/user-token-rest-auth.test.ts +1 -1
  452. package/src/tests/user-token-routes.test.ts +1 -1
  453. package/src/tests/whoami-route.test.ts +1 -1
  454. package/src/tests/workflow-agent-task.test.ts +15 -13
  455. package/src/tests/workflow-ctx.test.ts +1 -1
  456. package/src/tests/workflow-e2e.test.ts +1 -1
  457. package/src/tests/workflow-engine-v2.test.ts +3 -1
  458. package/src/tests/workflow-executors.test.ts +2 -2
  459. package/src/tests/workflow-http-v2.test.ts +8 -6
  460. package/src/tests/workflow-input-redaction.test.ts +7 -5
  461. package/src/tests/workflow-integration-io.test.ts +2 -2
  462. package/src/tests/workflow-llm.test.ts +5 -5
  463. package/src/tests/workflow-registry.test.ts +1 -1
  464. package/src/tests/workflow-swarm-script.test.ts +1 -1
  465. package/src/tests/workflow-triggers-v2.test.ts +23 -21
  466. package/src/tests/x-composio.test.ts +9 -7
  467. package/src/tests/x402-client.test.ts +1 -1
  468. package/src/tests/x402-config.test.ts +28 -41
  469. package/src/tools/defer-task.ts +156 -24
  470. package/src/tools/extension-common.ts +84 -0
  471. package/src/tools/extension-install.ts +65 -0
  472. package/src/tools/extension-list.ts +66 -0
  473. package/src/tools/script-common.ts +43 -18
  474. package/src/tools/send-task.ts +87 -105
  475. package/src/tools/skills/skill-publish.ts +1 -0
  476. package/src/tools/store-progress.ts +1 -1
  477. package/src/tools/task-action.ts +43 -22
  478. package/src/tools/task-tool-ctx.ts +2 -0
  479. package/src/tools/templates.ts +2 -1
  480. package/src/tools/tool-config.ts +3 -1
  481. package/src/tools/utils.ts +140 -16
  482. package/src/types.ts +144 -0
  483. package/src/utils/constants.ts +7 -1
  484. package/src/utils/credentials.test.ts +16 -16
  485. package/src/utils/multi-runtime.ts +2 -2
  486. package/src/utils/steering-enabled.ts +4 -4
  487. package/src/workflows/executors/agent-task.ts +18 -3
  488. package/templates/ai-toolbox.manifest.json +7 -1
  489. package/templates/extensions/README.md +17 -0
  490. package/templates/extensions/notify-on-complete/README.md +11 -0
  491. package/templates/extensions/notify-on-complete/hooks.ts +61 -0
  492. package/templates/extensions/notify-on-complete/manifest.json +7 -0
  493. package/templates/extensions/require-ticket-ref/README.md +11 -0
  494. package/templates/extensions/require-ticket-ref/hooks.ts +30 -0
  495. package/templates/extensions/require-ticket-ref/manifest.json +7 -0
  496. package/templates/extensions/require-verification-note/README.md +11 -0
  497. package/templates/extensions/require-verification-note/hooks.ts +32 -0
  498. package/templates/extensions/require-verification-note/manifest.json +7 -0
  499. package/templates/schedules/daily-hn-briefing/config.json +1 -1
  500. package/templates/schedules/gtm-weekly-review/config.json +1 -1
  501. package/templates/schedules/weekly-code-health-reports/config.json +1 -1
  502. package/templates/schedules/weekly-dependabot-triage/config.json +1 -1
  503. package/templates/schedules/weekly-dora-metrics/config.json +1 -1
  504. package/templates/schedules/weekly-harness-upgrade-check/config.json +1 -1
  505. package/templates/skills/delegate-work/files/scripts/codex-exec.sh +1 -1
  506. package/templates/skills/scheduling/content.md +2 -0
  507. package/templates/skills/serply-search/SKILL.md +95 -0
  508. package/templates/skills/serply-search/config.json +13 -0
  509. package/templates/skills/serply-search/content.md +90 -0
  510. package/templates/skills/swarm-extensions/config.json +14 -0
  511. package/templates/skills/swarm-extensions/content.md +120 -0
  512. package/templates/skills/swarm-scripts/SKILL.md +2 -2
  513. package/templates/skills/swarm-scripts/content.md +2 -2
  514. package/templates/workflows/claude-code-changelog-watch/config.json +1 -1
  515. package/templates/workflows/gsc-topic-miner/config.json +1 -1
  516. package/templates/workflows/linear-drain-loop/config.json +1 -1
  517. package/templates/workflows/llm-safe-release-context/config.json +1 -1
  518. package/templates/workflows/ralph-loop/config.json +1 -1
  519. package/dist/cli-7fehefdf.js +0 -562
  520. package/dist/cli-ayvy5kde.js +0 -164
  521. package/dist/cli-ddfw1mc4.js +0 -4322
  522. package/dist/cli-hzqmgcm2.js +0 -3066
  523. package/dist/cli-j4d4f6hv.js +0 -338
  524. package/dist/cli-qgm2pfpq.js +0 -6377
  525. package/dist/cli-sdzq01t9.js +0 -823
  526. package/dist/cli-xvkmedgn.js +0 -332
  527. package/dist/cli-y3pq4v9g.js +0 -664
  528. package/dist/{anthropic-messages-vs2rabzp.js → anthropic-messages-2y8nktar.js} +19 -19
  529. package/dist/{claude-managed-setup-f5pmsyrp.js → claude-managed-setup-48dwg9bv.js} +3 -3
  530. package/dist/{cli-81r683bv.js → cli-ch38q5z4.js} +0 -0
  531. package/dist/{cli-6664w7y4.js → cli-kj76p1ez.js} +8 -8
  532. package/dist/{cli-c71mg51n.js → cli-r2fpe7cx.js} +5 -5
  533. package/dist/{cli-4xz3pmrq.js → cli-y6x0gqtg.js} +16 -16
  534. package/dist/{index-aa3sa6s8.js → index-2wsdsnmm.js} +1 -1
  535. package/dist/{mistral-conversations-4ryk7h83.js → mistral-conversations-qhr84ph3.js} +9 -9
  536. package/dist/{openai-completions-0bqmsajw.js → openai-completions-32rdwmze.js} +19 -19
  537. package/dist/{openrouter-images-qx18fyp8.js → openrouter-images-9f9ek4rw.js} +3 -3
  538. package/dist/{pi-messages-79jvzz1d.js → pi-messages-b1mbr6gp.js} +4 -4
@@ -1,823 +0,0 @@
1
- import {
2
- getFileStorageProvider,
3
- providerPath
4
- } from "./cli-jsp14b6c.js";
5
- import {
6
- createTaskWithSiblingAwareness
7
- } from "./cli-ayvy5kde.js";
8
- import {
9
- init_task_attachment_links,
10
- taskAttachmentFetchCommand
11
- } from "./cli-9d8ntetj.js";
12
- import {
13
- getAgentById,
14
- getAgentWorkingOnThread,
15
- getAllAgents,
16
- getTaskAttachments,
17
- getTaskById,
18
- init_db,
19
- insertTaskAttachment,
20
- promoteDraftTask,
21
- refreshDraftTaskLease
22
- } from "./cli-qgd4sqz5.js";
23
- import {
24
- init_registry,
25
- init_resolver,
26
- registerTemplate,
27
- resolveTemplate
28
- } from "./cli-3apbzgyk.js";
29
- import {
30
- init_env_flag,
31
- isEnvFlagEnabled
32
- } from "./cli-ej6gbxfb.js";
33
- import {
34
- init_secret_scrubber,
35
- scrubSecrets
36
- } from "./cli-r2ap2czm.js";
37
- import {
38
- __callDispose,
39
- __using
40
- } from "./cli-bc05qbss.js";
41
-
42
- // src/slack/templates.ts
43
- init_registry();
44
- registerTemplate({
45
- eventType: "slack.assistant.greeting",
46
- header: "",
47
- defaultBody: "Hi! I'm your Agent Swarm assistant. How can I help?",
48
- variables: [],
49
- category: "system"
50
- });
51
- registerTemplate({
52
- eventType: "slack.assistant.suggested_prompts",
53
- header: "",
54
- defaultBody: `Try these:
55
- - Check status: What's the current status of all agents?
56
- - Assign a task: Can you help me with...
57
- - List recent tasks: Show me the most recent tasks`,
58
- variables: [],
59
- category: "system"
60
- });
61
- registerTemplate({
62
- eventType: "slack.assistant.offline",
63
- header: "",
64
- defaultBody: "No agents are available right now. Your request has been queued and will be processed when agents come back online.",
65
- variables: [],
66
- category: "system"
67
- });
68
- registerTemplate({
69
- eventType: "slack.message.attachment_failed",
70
- header: "",
71
- defaultBody: ":warning: Couldn't attach {{failed_files}} to the task. The agent sees the file name, not its contents.",
72
- variables: [
73
- {
74
- name: "failed_files",
75
- description: "Comma-separated `name` (reason) list of the files that were not attached"
76
- }
77
- ],
78
- category: "system"
79
- });
80
- registerTemplate({
81
- eventType: "slack.message.thread_context",
82
- header: "",
83
- defaultBody: `<thread_context>
84
- {{thread_messages}}
85
- </thread_context>`,
86
- variables: [
87
- {
88
- name: "thread_messages",
89
- description: "Formatted thread messages (user: text pairs)"
90
- }
91
- ],
92
- category: "system"
93
- });
94
-
95
- // src/slack/inbound-files.ts
96
- init_db();
97
- import { mkdtemp, rm } from "node:fs/promises";
98
- import { tmpdir } from "node:os";
99
- import { join } from "node:path";
100
-
101
- // src/be/task-attachment-store.ts
102
- init_secret_scrubber();
103
- init_db();
104
- var MAX_TASK_ATTACHMENT_BYTES = 50 * 1024 * 1024;
105
- async function recordTaskAttachmentUpload(input) {
106
- const { provider, scope, uploaded, contentType } = input;
107
- try {
108
- return await insertTaskAttachment({
109
- taskId: scope.taskId,
110
- agentId: input.agentId,
111
- name: scope.name,
112
- kind: provider.id === "agent-fs" ? "agent-fs" : "shared-fs",
113
- path: uploaded.key,
114
- providerId: provider.id,
115
- providerKey: uploaded.key,
116
- capabilities: {
117
- ...provider.capabilities,
118
- version: uploaded.version,
119
- etag: uploaded.etag
120
- },
121
- mimeType: uploaded.contentType ?? contentType,
122
- sizeBytes: uploaded.sizeBytes ?? input.sizeBytes,
123
- sha256: uploaded.sha256 ?? input.sha256,
124
- intent: input.intent,
125
- description: input.description,
126
- isPrimary: input.isPrimary ?? false,
127
- createdBy: input.createdBy
128
- });
129
- } catch (error) {
130
- try {
131
- await provider.delete(scope);
132
- } catch (cleanupError) {
133
- console.warn(scrubSecrets(`[fs] upload metadata insert failed and blob cleanup failed: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`));
134
- }
135
- throw error;
136
- }
137
- }
138
-
139
- // src/slack/inbound-files.ts
140
- init_resolver();
141
- init_secret_scrubber();
142
- init_task_attachment_links();
143
-
144
- // src/slack/files.ts
145
- import { createWriteStream } from "node:fs";
146
- import { mkdir } from "node:fs/promises";
147
- import { dirname } from "node:path";
148
- var MAX_FILE_SIZE = 1073741824;
149
- var DEFAULT_DOWNLOAD_DIR = `/workspace/shared/downloads/${process.env.AGENT_ID || "default"}/slack`;
150
- async function uploadFile(client, options) {
151
- const { file, filename, channelId, threadTs, initialComment, title } = options;
152
- try {
153
- if (Buffer.isBuffer(file) && file.length > MAX_FILE_SIZE) {
154
- return {
155
- success: false,
156
- error: `File size ${file.length} bytes exceeds maximum of ${MAX_FILE_SIZE} bytes (1 GB)`
157
- };
158
- }
159
- if (typeof file === "string") {
160
- const bunFile = Bun.file(file);
161
- const size = bunFile.size;
162
- if (size > MAX_FILE_SIZE) {
163
- return {
164
- success: false,
165
- error: `File size ${size} bytes exceeds maximum of ${MAX_FILE_SIZE} bytes (1 GB)`
166
- };
167
- }
168
- }
169
- const uploadArgs = {
170
- file,
171
- filename,
172
- title: title || filename
173
- };
174
- if (channelId) {
175
- uploadArgs.channel_id = channelId;
176
- if (threadTs) {
177
- uploadArgs.thread_ts = threadTs;
178
- }
179
- if (initialComment) {
180
- uploadArgs.initial_comment = initialComment;
181
- }
182
- }
183
- const result = await client.filesUploadV2(uploadArgs);
184
- const uploadedFile = result.files?.[0];
185
- const fileId = uploadedFile?.files?.[0]?.id;
186
- if (!fileId) {
187
- return {
188
- success: false,
189
- error: "Upload succeeded but no file ID returned"
190
- };
191
- }
192
- return {
193
- success: true,
194
- fileId
195
- };
196
- } catch (error) {
197
- const errorMsg = error instanceof Error ? error.message : String(error);
198
- return {
199
- success: false,
200
- error: errorMsg
201
- };
202
- }
203
- }
204
- async function downloadFile(options) {
205
- const { file, savePath, token } = options;
206
- try {
207
- const downloadUrl = typeof file === "string" ? file : file.url_private_download;
208
- if (!downloadUrl) {
209
- return {
210
- success: false,
211
- error: "No download URL available for this file"
212
- };
213
- }
214
- let finalPath = savePath;
215
- if (typeof file !== "string" && (savePath.endsWith("/") || !savePath.includes("."))) {
216
- finalPath = savePath.endsWith("/") ? `${savePath}${file.name}` : `${savePath}/${file.name}`;
217
- }
218
- await mkdir(dirname(finalPath), { recursive: true });
219
- const response = await fetch(downloadUrl, {
220
- headers: {
221
- Authorization: `Bearer ${token}`
222
- }
223
- });
224
- if (!response.ok) {
225
- return {
226
- success: false,
227
- error: `HTTP error ${response.status}: ${response.statusText}`
228
- };
229
- }
230
- const body = response.body;
231
- if (!body) {
232
- return {
233
- success: false,
234
- error: "No response body"
235
- };
236
- }
237
- const writer = createWriteStream(finalPath);
238
- const reader = body.getReader();
239
- try {
240
- while (true) {
241
- const { done, value } = await reader.read();
242
- if (done)
243
- break;
244
- writer.write(value);
245
- }
246
- writer.end();
247
- } finally {
248
- reader.releaseLock();
249
- }
250
- await new Promise((resolve, reject) => {
251
- writer.on("finish", resolve);
252
- writer.on("error", reject);
253
- });
254
- return {
255
- success: true,
256
- savedPath: finalPath
257
- };
258
- } catch (error) {
259
- const errorMsg = error instanceof Error ? error.message : String(error);
260
- return {
261
- success: false,
262
- error: errorMsg
263
- };
264
- }
265
- }
266
- async function getFileInfo(client, fileId) {
267
- try {
268
- const result = await client.files.info({ file: fileId });
269
- if (!result.file) {
270
- return null;
271
- }
272
- const f = result.file;
273
- return {
274
- id: f.id,
275
- name: f.name,
276
- title: f.title,
277
- mimetype: f.mimetype,
278
- filetype: f.filetype,
279
- size: f.size,
280
- url_private: f.url_private,
281
- url_private_download: f.url_private_download,
282
- thumb_64: f.thumb_64,
283
- thumb_80: f.thumb_80,
284
- thumb_160: f.thumb_160,
285
- thumb_360: f.thumb_360,
286
- thumb_480: f.thumb_480,
287
- user: f.user,
288
- created: f.created
289
- };
290
- } catch {
291
- return null;
292
- }
293
- }
294
-
295
- // src/slack/inbound-files.ts
296
- var DOWNLOAD_TIMEOUT_MS = 30000;
297
- var SIGNED_OUT_REASON = "Slack returned its sign-in page instead of the file (is the files:read scope granted?)";
298
- var SIGN_IN_MARKERS = [
299
- /<title>[^<]*sign in to slack/i,
300
- /id="signin[_-]form"/i,
301
- /slack\.com\/(workspace-)?signin/i
302
- ];
303
- var SIGN_IN_SNIFF_BYTES = 4096;
304
- var draftLeaseRefreshMs = 60000;
305
- var SHARED_FILE_INTENT = "user-upload";
306
- var FETCHED_FILE_INTENT = "slack-file";
307
- var BUFFERED_REASON = "follow-ups queued by ADDITIVE_SLACK carry the file name only";
308
- function errorText(error) {
309
- return scrubSecrets(error instanceof Error ? error.message : String(error));
310
- }
311
- function formatFileSize(bytes) {
312
- if (bytes < 1024)
313
- return `${bytes} B`;
314
- if (bytes < 1024 * 1024)
315
- return `${(bytes / 1024).toFixed(1)} KB`;
316
- if (bytes < 1024 * 1024 * 1024)
317
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
318
- return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
319
- }
320
- function buildAttachmentText(files, failed = []) {
321
- const reasons = new Map(failed.map((f) => [f.file.id, f.reason]));
322
- return files.map((f) => {
323
- const size = typeof f.size === "number" ? formatFileSize(f.size) : "unknown size";
324
- const line = `[File: ${f.name ?? f.id} (${f.mimetype ?? "unknown type"}, ${size}) id=${f.id}]`;
325
- const reason = reasons.get(f.id);
326
- return reason ? `${line} (not attached: ${reason})` : line;
327
- }).join(`
328
- `);
329
- }
330
- function buildEffectiveText(text, files, failed) {
331
- const hasText = !!text?.trim();
332
- const hasFiles = files && files.length > 0;
333
- if (hasText && hasFiles) {
334
- return `${text}
335
-
336
- ${buildAttachmentText(files, failed)}`;
337
- }
338
- if (hasFiles) {
339
- return buildAttachmentText(files, failed);
340
- }
341
- return text || "";
342
- }
343
- function bufferedFileFailures(files) {
344
- return (files ?? []).map((file) => ({ file, reason: BUFFERED_REASON }));
345
- }
346
- async function fetchSlackFiles(client, files) {
347
- let dir;
348
- const result = {
349
- files: [],
350
- fetched: [],
351
- failed: [],
352
- async[Symbol.asyncDispose]() {
353
- if (dir)
354
- await rm(dir, { recursive: true, force: true });
355
- }
356
- };
357
- if (!files || files.length === 0)
358
- return result;
359
- dir = await mkdtemp(join(tmpdir(), "slack-files-"));
360
- const token = client.token ?? process.env.SLACK_BOT_TOKEN;
361
- for (const [index, eventFile] of files.entries()) {
362
- const file = eventFile.url_private_download ? eventFile : await getFileInfo(client, eventFile.id) ?? eventFile;
363
- result.files.push(file);
364
- const outcome = await downloadSlackFile(file, token, join(dir, String(index)));
365
- if (typeof outcome === "string") {
366
- console.warn(`[Slack] could not fetch file ${file.id}: ${outcome}`);
367
- result.failed.push({ file, reason: outcome });
368
- } else {
369
- result.fetched.push({ file, ...outcome });
370
- }
371
- }
372
- return result;
373
- }
374
- function looksLikeSignIn(head) {
375
- const joined = new Uint8Array(head.reduce((total, part) => total + part.byteLength, 0));
376
- let offset = 0;
377
- for (const part of head) {
378
- joined.set(part, offset);
379
- offset += part.byteLength;
380
- }
381
- const text = new TextDecoder().decode(joined);
382
- return SIGN_IN_MARKERS.some((marker) => marker.test(text));
383
- }
384
- async function downloadSlackFile(file, token, path) {
385
- const limit = `larger than the ${MAX_TASK_ATTACHMENT_BYTES / (1024 * 1024)} MB limit`;
386
- if (file.size > MAX_TASK_ATTACHMENT_BYTES)
387
- return limit;
388
- if (!file.url_private_download)
389
- return "Slack gave no download URL";
390
- if (!token)
391
- return "no Slack bot token configured";
392
- const abort = new AbortController;
393
- try {
394
- const response = await fetch(file.url_private_download, {
395
- headers: { Authorization: `Bearer ${token}` },
396
- signal: AbortSignal.any([abort.signal, AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS)])
397
- });
398
- if (!response.ok)
399
- return `download failed (HTTP ${response.status})`;
400
- const isHtml = (response.headers.get("content-type") ?? "").startsWith("text/html");
401
- const redirectedToHtml = isHtml && response.redirected && !new URL(response.url).pathname.includes("/files-pri/");
402
- if (redirectedToHtml || isHtml && !file.mimetype?.startsWith("text/html")) {
403
- abort.abort();
404
- return SIGNED_OUT_REASON;
405
- }
406
- if (Number(response.headers.get("content-length") ?? 0) > MAX_TASK_ATTACHMENT_BYTES) {
407
- abort.abort();
408
- return limit;
409
- }
410
- const hasher = new Bun.CryptoHasher("sha256");
411
- const sink = Bun.file(path).writer({ highWaterMark: 1024 * 1024 });
412
- let sizeBytes = 0;
413
- let overCap = false;
414
- const head = [];
415
- let headBytes = 0;
416
- try {
417
- for await (const chunk of response.body ?? []) {
418
- sizeBytes += chunk.byteLength;
419
- if (sizeBytes > MAX_TASK_ATTACHMENT_BYTES) {
420
- overCap = true;
421
- break;
422
- }
423
- if (isHtml && headBytes < SIGN_IN_SNIFF_BYTES) {
424
- const wanted = chunk.subarray(0, SIGN_IN_SNIFF_BYTES - headBytes);
425
- head.push(wanted);
426
- headBytes += wanted.byteLength;
427
- }
428
- hasher.update(chunk);
429
- sink.write(chunk);
430
- }
431
- } finally {
432
- await sink.end();
433
- }
434
- if (overCap) {
435
- abort.abort();
436
- return limit;
437
- }
438
- if (isHtml && looksLikeSignIn(head))
439
- return SIGNED_OUT_REASON;
440
- if (isHtml && file.size > 0 && sizeBytes !== file.size) {
441
- return `Slack sent ${sizeBytes} bytes of HTML for a ${file.size}-byte file, likely its sign-in page (is the files:read scope granted?)`;
442
- }
443
- return { path, sizeBytes, sha256: hasher.digest("hex") };
444
- } catch (error) {
445
- return `download failed (${errorText(error)})`;
446
- }
447
- }
448
- async function createSlackTaskWithFiles(description, options, inbound) {
449
- if (inbound.fetched.length === 0) {
450
- const task2 = await createTaskWithSiblingAwareness(description, options);
451
- return { task: task2, unattached: inbound.failed };
452
- }
453
- const task = await createTaskWithSiblingAwareness(description, { ...options, status: "draft" });
454
- const unattached = [...inbound.failed];
455
- const lease = setInterval(() => {
456
- refreshDraftTaskLease(task.id).catch((error) => console.warn(`[Slack] could not renew the draft lease of task ${task.id}: ${errorText(error)}`));
457
- }, draftLeaseRefreshMs);
458
- try {
459
- unattached.push(...(await attachSlackFilesToTask(task.id, inbound.fetched, null)).unattached);
460
- } finally {
461
- clearInterval(lease);
462
- await promoteDraftTask(task.id);
463
- }
464
- return { task, unattached };
465
- }
466
- async function attachSlackFilesToTask(taskId, fetched, agentId) {
467
- const existing = await getTaskAttachments(taskId);
468
- const bySha = new Map(existing.flatMap((a) => a.sha256 ? [[a.sha256, a]] : []));
469
- const usedNames = new Set(existing.map((a) => a.name));
470
- const provider = getFileStorageProvider();
471
- const attached = [];
472
- const unattached = [];
473
- for (const { file, path, sizeBytes, sha256 } of fetched) {
474
- const known = bySha.get(sha256);
475
- if (known) {
476
- attached.push({ file, attachment: known });
477
- continue;
478
- }
479
- const name = usedNames.has(file.name) ? `${file.id}-${file.name}` : file.name;
480
- usedNames.add(name);
481
- const key = providerPath({ taskId, name: `slack-${file.id}-${file.name}` });
482
- const scope = { taskId, name, key };
483
- try {
484
- const uploaded = await provider.upload(scope, Bun.file(path), {
485
- contentType: file.mimetype,
486
- sizeBytes,
487
- message: `Upload ${name} from Slack for task ${taskId}`
488
- });
489
- const attachment = await recordTaskAttachmentUpload({
490
- provider,
491
- scope,
492
- uploaded,
493
- sizeBytes,
494
- sha256,
495
- contentType: file.mimetype,
496
- agentId,
497
- intent: agentId ? FETCHED_FILE_INTENT : SHARED_FILE_INTENT,
498
- description: agentId ? `Fetched from Slack (file ${file.id})` : `Shared on Slack (file ${file.id})`
499
- });
500
- bySha.set(sha256, attachment);
501
- attached.push({ file, attachment });
502
- } catch (error) {
503
- const reason = `could not be stored (${errorText(error)})`;
504
- console.warn(`[Slack] file ${file.id} for task ${taskId} ${reason}`);
505
- unattached.push({ file, reason });
506
- }
507
- }
508
- return { attached, unattached };
509
- }
510
- async function attachSlackFilesForAgent(client, task, files, agentId) {
511
- const outcomes = new Map;
512
- for (const file of files) {
513
- let __stack = [];
514
- try {
515
- if (outcomes.has(file.id))
516
- continue;
517
- const inbound = __using(__stack, await fetchSlackFiles(client, [file]), 1);
518
- const { attached, unattached } = await attachSlackFilesToTask(task.id, inbound.fetched, agentId);
519
- for (const { file: failed, reason } of [...inbound.failed, ...unattached]) {
520
- outcomes.set(failed.id, { reason });
521
- }
522
- for (const { file: stored, attachment } of attached) {
523
- outcomes.set(stored.id, {
524
- attachment,
525
- fetchCommand: taskAttachmentFetchCommand(task.id, attachment.id, attachment.name)
526
- });
527
- }
528
- } catch (_catch) {
529
- var _err = _catch, _hasErr = 1;
530
- } finally {
531
- var _promise = __callDispose(__stack, _err, _hasErr);
532
- _promise && await _promise;
533
- }
534
- }
535
- return outcomes;
536
- }
537
- async function attachableTask(agentId, taskId) {
538
- if (!taskId)
539
- return null;
540
- const task = await getTaskById(taskId);
541
- if (!task)
542
- return null;
543
- return task.agentId === agentId || task.creatorAgentId === agentId ? task : null;
544
- }
545
- async function notifySlackFileFailures(client, channel, threadTs, failures) {
546
- if (failures.length === 0)
547
- return;
548
- const byFile = new Map(failures.map((f) => [f.file.id, f]));
549
- const failedFiles = [...byFile.values()].map((f) => `\`${f.file.name}\` (${f.reason})`).join(", ");
550
- const { text } = resolveTemplate("slack.message.attachment_failed", {
551
- failed_files: failedFiles
552
- });
553
- try {
554
- await client.chat.postMessage({
555
- channel,
556
- thread_ts: threadTs,
557
- text,
558
- unfurl_links: false,
559
- unfurl_media: false
560
- });
561
- } catch (error) {
562
- console.warn(`[Slack] could not post the attachment-failure notice in ${channel}/${threadTs}: ${errorText(error)}`);
563
- }
564
- }
565
-
566
- // src/slack/router.ts
567
- init_db();
568
- init_env_flag();
569
- function hasOtherUserMention(text, botUserId) {
570
- const mentions = text.match(/<@([A-Z0-9]+)>/g) ?? [];
571
- return mentions.some((m) => m !== `<@${botUserId}>`);
572
- }
573
- async function routeMessage(text, botUserId, botMentioned, threadContext) {
574
- const matches = [];
575
- const requireMentionForThreadFollowup = isEnvFlagEnabled("SLACK_THREAD_FOLLOWUP_REQUIRE_MENTION", false);
576
- const agents = (await getAllAgents()).filter((a) => a.status !== "offline");
577
- const idMatches = text.matchAll(/swarm#([a-f0-9-]{36})/gi);
578
- for (const match of idMatches) {
579
- const agentId = match[1];
580
- if (!agentId)
581
- continue;
582
- const agent = await getAgentById(agentId);
583
- if (agent && agent.status !== "offline") {
584
- matches.push({ agent, matchedText: match[0] });
585
- }
586
- }
587
- if (/swarm#all/i.test(text)) {
588
- const nonLeadAgents = agents.filter((a) => !a.isLead);
589
- for (const agent of nonLeadAgents) {
590
- if (!matches.some((m) => m.agent.id === agent.id)) {
591
- matches.push({ agent, matchedText: "swarm#all" });
592
- }
593
- }
594
- }
595
- if (matches.length === 0 && threadContext && (!requireMentionForThreadFollowup || botMentioned)) {
596
- if (!botMentioned && hasOtherUserMention(text, botUserId)) {
597
- console.log(`[Slack] Skipping thread follow-up in ${threadContext.channelId}/${threadContext.threadTs}: message mentions another user`);
598
- return matches;
599
- }
600
- const workingAgent = await getAgentWorkingOnThread(threadContext.channelId, threadContext.threadTs);
601
- if (workingAgent && workingAgent.status !== "offline") {
602
- console.log(`[Slack] Thread follow-up: routing to agent ${workingAgent.name} (${workingAgent.id}) in thread ${threadContext.threadTs}`);
603
- matches.push({ agent: workingAgent, matchedText: "thread follow-up" });
604
- } else if (workingAgent) {
605
- console.log(`[Slack] Thread follow-up: agent ${workingAgent.name} is offline, routing to lead`);
606
- const allAgents = await getAllAgents();
607
- const lead = allAgents.find((a) => a.isLead && a.status !== "offline");
608
- if (lead) {
609
- matches.push({ agent: lead, matchedText: "thread follow-up (lead fallback)" });
610
- }
611
- }
612
- }
613
- if (matches.length === 0 && botMentioned) {
614
- const lead = agents.find((a) => a.isLead);
615
- if (lead) {
616
- matches.push({ agent: lead, matchedText: "@bot" });
617
- }
618
- }
619
- return matches;
620
- }
621
- function extractTaskFromMessage(text, botUserId) {
622
- return text.replace(new RegExp(`<@${botUserId}>`, "g"), "").replace(/swarm#[a-f0-9-]{36}/gi, "").replace(/swarm#all/gi, "").trim();
623
- }
624
-
625
- // src/slack/message-text.ts
626
- function collectRichTextParts(node, parts) {
627
- if (node == null || typeof node !== "object")
628
- return;
629
- const n = node;
630
- if (n.type === "text" && n.text) {
631
- parts.push(n.text);
632
- }
633
- if (Array.isArray(n.elements)) {
634
- for (const child of n.elements) {
635
- collectRichTextParts(child, parts);
636
- }
637
- }
638
- }
639
- function extractSlackMessageText(msg) {
640
- const topText = msg.text?.trim() ?? "";
641
- const attachmentParts = [];
642
- if (Array.isArray(msg.attachments) && msg.attachments.length > 0) {
643
- for (const raw of msg.attachments) {
644
- if (raw == null || typeof raw !== "object")
645
- continue;
646
- const a = raw;
647
- const attParts = [];
648
- const titleText = a.title_link && a.title ? `<${a.title_link}|${a.title}>` : a.title;
649
- const seenPrimary = new Set;
650
- for (const part of [a.pretext, titleText, a.text, a.fallback]) {
651
- const s = part?.trim();
652
- if (s && !seenPrimary.has(s)) {
653
- seenPrimary.add(s);
654
- attParts.push(s);
655
- }
656
- }
657
- if (Array.isArray(a.fields)) {
658
- for (const field of a.fields) {
659
- if (field == null || typeof field !== "object")
660
- continue;
661
- const f = field;
662
- if (f.title && f.value)
663
- attParts.push(`${f.title}: ${f.value}`);
664
- else if (f.title)
665
- attParts.push(f.title);
666
- else if (f.value)
667
- attParts.push(f.value);
668
- }
669
- }
670
- if (Array.isArray(a.actions)) {
671
- for (const action of a.actions) {
672
- if (action == null || typeof action !== "object")
673
- continue;
674
- const act = action;
675
- if (act.url) {
676
- attParts.push(act.text ? `<${act.url}|${act.text}>` : act.url);
677
- }
678
- }
679
- }
680
- if (attParts.length > 0)
681
- attachmentParts.push(attParts.join(`
682
- `));
683
- }
684
- }
685
- const blockParts = [];
686
- if (Array.isArray(msg.blocks) && msg.blocks.length > 0) {
687
- for (const rawBlock of msg.blocks) {
688
- if (rawBlock == null || typeof rawBlock !== "object")
689
- continue;
690
- const block = rawBlock;
691
- if (block.type === "section") {
692
- if (block.text?.text)
693
- blockParts.push(block.text.text);
694
- if (Array.isArray(block.fields)) {
695
- for (const field of block.fields) {
696
- if (field != null && typeof field === "object" && field.text) {
697
- blockParts.push(field.text);
698
- }
699
- }
700
- }
701
- } else if (block.type === "rich_text" && Array.isArray(block.elements)) {
702
- for (const el of block.elements) {
703
- collectRichTextParts(el, blockParts);
704
- }
705
- } else if (block.type === "header") {
706
- if (block.text?.text)
707
- blockParts.push(block.text.text);
708
- } else if (block.type === "context" && Array.isArray(block.elements)) {
709
- for (const el of block.elements) {
710
- if (el == null || typeof el !== "object")
711
- continue;
712
- const e = el;
713
- if (e.text)
714
- blockParts.push(e.text);
715
- }
716
- } else if (block.type === "actions" && Array.isArray(block.elements)) {
717
- for (const el of block.elements) {
718
- if (el == null || typeof el !== "object")
719
- continue;
720
- const e = el;
721
- const label = e.text?.text;
722
- const url = e.url;
723
- if (label && url)
724
- blockParts.push(`<${url}|${label}>`);
725
- else if (label)
726
- blockParts.push(label);
727
- else if (url)
728
- blockParts.push(url);
729
- }
730
- }
731
- }
732
- }
733
- const bodyText = [...attachmentParts, ...blockParts].filter(Boolean).join(`
734
- `);
735
- const bodyLines = new Set(bodyText.split(`
736
- `).map((l) => l.trim()).filter(Boolean));
737
- if (topText && !bodyLines.has(topText)) {
738
- return bodyText ? `${topText}
739
- ${bodyText}` : topText;
740
- }
741
- return bodyText || topText;
742
- }
743
- function parseSlackTs(input) {
744
- const trimmed = input.trim();
745
- if (/^\d{6,}\.\d{1,}$/.test(trimmed))
746
- return trimmed;
747
- const m = trimmed.match(/p?(\d{10})(\d{6})(?:\D|$)/);
748
- if (m)
749
- return `${m[1]}.${m[2]}`;
750
- return trimmed;
751
- }
752
-
753
- // src/tasks/additive-buffer.ts
754
- function createAdditiveBuffer(options) {
755
- const { timeoutMs, onFlush, label } = options;
756
- if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
757
- throw new Error(`additive-buffer: timeoutMs must be a positive number, got ${timeoutMs}`);
758
- }
759
- const buffers = new Map;
760
- const prefix = label ? `[buffer:${label}]` : "[buffer]";
761
- function scheduleFlush(key) {
762
- return setTimeout(() => {
763
- doFlush(key, "timer");
764
- }, timeoutMs);
765
- }
766
- async function doFlush(key, reason) {
767
- const entry = buffers.get(key);
768
- if (!entry || entry.items.length === 0) {
769
- buffers.delete(key);
770
- return;
771
- }
772
- clearTimeout(entry.timer);
773
- buffers.delete(key);
774
- try {
775
- await onFlush(entry.items, key, reason);
776
- } catch (error) {
777
- console.error(`${prefix} onFlush threw for key=${key}:`, error);
778
- }
779
- }
780
- return {
781
- enqueue(contextKey, item) {
782
- if (!contextKey) {
783
- throw new Error("additive-buffer: contextKey is required");
784
- }
785
- const existing = buffers.get(contextKey);
786
- if (existing) {
787
- clearTimeout(existing.timer);
788
- existing.items.push(item);
789
- existing.timer = scheduleFlush(contextKey);
790
- console.log(`${prefix} append: ${contextKey} (${existing.items.length} items, timer reset to ${timeoutMs}ms)`);
791
- } else {
792
- const entry = {
793
- items: [item],
794
- timer: scheduleFlush(contextKey)
795
- };
796
- buffers.set(contextKey, entry);
797
- console.log(`${prefix} created: ${contextKey} (timer set to ${timeoutMs}ms)`);
798
- }
799
- },
800
- isBuffered(contextKey) {
801
- return buffers.has(contextKey);
802
- },
803
- count(contextKey) {
804
- return buffers.get(contextKey)?.items.length ?? 0;
805
- },
806
- instantFlush(contextKey) {
807
- return doFlush(contextKey, "manual");
808
- },
809
- cancel(contextKey) {
810
- const entry = buffers.get(contextKey);
811
- if (!entry)
812
- return false;
813
- clearTimeout(entry.timer);
814
- buffers.delete(contextKey);
815
- return true;
816
- },
817
- keys() {
818
- return Array.from(buffers.keys());
819
- }
820
- };
821
- }
822
-
823
- export { createAdditiveBuffer, MAX_TASK_ATTACHMENT_BYTES, recordTaskAttachmentUpload, MAX_FILE_SIZE, DEFAULT_DOWNLOAD_DIR, uploadFile, downloadFile, getFileInfo, buildEffectiveText, bufferedFileFailures, fetchSlackFiles, createSlackTaskWithFiles, attachSlackFilesForAgent, attachableTask, notifySlackFileFailures, hasOtherUserMention, routeMessage, extractTaskFromMessage, extractSlackMessageText, parseSlackTs };