@desplega.ai/agent-swarm 2.4.5 → 2.5.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 (275) hide show
  1. package/README.md +4 -2
  2. package/dist/{acp-adapter-2wdkktv6.js → acp-adapter-7g6bpwbk.js} +8 -6
  3. package/dist/{actions-c40ebcm4.js → actions-w8xd014k.js} +23 -21
  4. package/dist/{amp-adapter-wb67m95z.js → amp-adapter-z4qvhacj.js} +2 -2
  5. package/dist/{anthropic-messages-g6pqmqk4.js → anthropic-messages-txs190dd.js} +17 -20
  6. package/dist/{app-353vre8g.js → app-nndcvftq.js} +3 -3
  7. package/dist/{assistant-sj1njh23.js → assistant-hjmqyscx.js} +24 -22
  8. package/dist/{azure-openai-responses-9dbmj346.js → azure-openai-responses-9kfwhmn7.js} +18 -13
  9. package/dist/{boot-reembed-b9c3az3c.js → boot-reembed-r8rhf9h8.js} +1 -1
  10. package/dist/{boot-reembed-qdkvxeem.js → boot-reembed-vwcj2y5d.js} +1 -1
  11. package/dist/{boot-scrub-sweep-m3wh8eks.js → boot-scrub-sweep-fr9q36ne.js} +4 -4
  12. package/dist/{boot-seeds-j2273s54.js → boot-seeds-9jqwnegq.js} +4 -4
  13. package/dist/{claude-adapter-m7q0a085.js → claude-adapter-2f8b85df.js} +8 -6
  14. package/dist/{claude-managed-adapter-5ptb6tzs.js → claude-managed-adapter-gt6pa35d.js} +2 -2
  15. package/dist/{claude-managed-setup-smrqk5j5.js → claude-managed-setup-c3hp36ph.js} +4 -4
  16. package/dist/{claude-sdk-session-38xnz21e.js → claude-sdk-session-05kat8rv.js} +9012 -8928
  17. package/dist/{cli-b9fcxxev.js → cli-007cnhm1.js} +50 -4
  18. package/dist/{cli-j4rqdf2n.js → cli-03vpq45j.js} +2 -2
  19. package/dist/{cli-1sp861s4.js → cli-0jy85zz4.js} +11 -11
  20. package/dist/{cli-j99azg3g.js → cli-1dp1zj04.js} +5 -5
  21. package/dist/{cli-3r8samv3.js → cli-1f0gp9vz.js} +3 -2
  22. package/dist/{cli-94gwyg7m.js → cli-22rmcjkg.js} +9 -9
  23. package/dist/{cli-ms85309d.js → cli-2jg61wab.js} +11 -11
  24. package/dist/{cli-0bqteszy.js → cli-2nf3b08t.js} +328 -25
  25. package/dist/{cli-9yqgm9nd.js → cli-2wba1ac9.js} +161 -63
  26. package/dist/{cli-cxxe61f6.js → cli-3ee5z0q0.js} +2 -2
  27. package/dist/{cli-k8g16gz3.js → cli-3qv8naq8.js} +115 -119
  28. package/dist/{cli-60cgh1rv.js → cli-459fk97x.js} +7 -7
  29. package/dist/{cli-h7gc0b4r.js → cli-5m84zd2k.js} +55 -18
  30. package/dist/{cli-dvkmp9bt.js → cli-6ctwrf1z.js} +20 -10
  31. package/dist/{cli-848hxdwj.js → cli-6rg2jn2y.js} +2 -1
  32. package/dist/{cli-dk44dxec.js → cli-9mm5ade4.js} +1 -1
  33. package/dist/{cli-7c9qs530.js → cli-ajqhxtnz.js} +5 -5
  34. package/dist/{cli-be2161h1.js → cli-cah5detr.js} +6 -6
  35. package/dist/{cli-v8fjakwf.js → cli-cwyafhw1.js} +1 -1
  36. package/dist/{cli-wxbn3yfx.js → cli-cz5nmdxt.js} +2 -2
  37. package/dist/{cli-wt645v7q.js → cli-dabehxhp.js} +1 -1
  38. package/dist/{cli-vfha21c9.js → cli-e5bxnjps.js} +2 -2
  39. package/dist/{cli-37j04k05.js → cli-e9btqw4y.js} +13 -13
  40. package/dist/{cli-1syn2xy1.js → cli-eym3jg7w.js} +32 -18
  41. package/dist/{cli-ftc1g5tj.js → cli-fes51ya2.js} +3 -3
  42. package/dist/{cli-s95dknxh.js → cli-g1cw7xtt.js} +1 -1
  43. package/dist/{cli-74c1wpm0.js → cli-gpv60278.js} +1 -1
  44. package/dist/{cli-1f3qzw6y.js → cli-gwcf52gz.js} +2 -2
  45. package/dist/{cli-pemywhfq.js → cli-ha9rmwgq.js} +2 -1
  46. package/dist/{cli-v0yrfmdh.js → cli-hadv0725.js} +3 -3
  47. package/dist/{cli-g35m2xwm.js → cli-j1eghqfm.js} +2 -2
  48. package/dist/{cli-qfxc84gh.js → cli-jpxsrxcb.js} +1 -1
  49. package/dist/{cli-n72rg53p.js → cli-kcsd1ez8.js} +848 -426
  50. package/dist/{cli-ejs3m1sx.js → cli-kxpfx2xr.js} +1 -1
  51. package/dist/{cli-pnp2j5zg.js → cli-mmhj8vd7.js} +2 -2
  52. package/dist/{cli-st8aw1m6.js → cli-mq7kg1b1.js} +4 -4
  53. package/dist/{cli-bnes4z6b.js → cli-mz2ygeyq.js} +3 -3
  54. package/dist/{cli-xf234ws8.js → cli-n4c8e3s5.js} +2 -0
  55. package/dist/{cli-f01h25yt.js → cli-n6kmqngw.js} +2 -2
  56. package/dist/cli-nj12tn2c.js +1193 -0
  57. package/dist/{cli-1dmcq2eh.js → cli-nzfnt2gs.js} +1 -1
  58. package/dist/{cli-625tb7aq.js → cli-p859hcc8.js} +2 -2
  59. package/dist/{cli-smvcw9z5.js → cli-pasyvjmm.js} +1 -1
  60. package/dist/cli-pkaqk57w.js +128 -0
  61. package/dist/{cli-xpa64rek.js → cli-pyy4c9ch.js} +2362 -159
  62. package/dist/{cli-wt0jf9hm.js → cli-q9pzwxvk.js} +553 -193
  63. package/dist/{cli-z7d29rw9.js → cli-qfjm4gvt.js} +4 -4
  64. package/dist/{cli-p14m2cnp.js → cli-qfm6my86.js} +1 -1
  65. package/dist/{cli-8nyhf7za.js → cli-qqzmjxkf.js} +129 -105
  66. package/dist/{cli-4zfqgjc5.js → cli-r9fy0ddc.js} +2 -2
  67. package/dist/{cli-eww120g8.js → cli-rh5smt8t.js} +18 -4
  68. package/dist/{cli-a92r1127.js → cli-rngde2jv.js} +2 -2
  69. package/dist/{cli-qwkcwjdn.js → cli-rycdaj0a.js} +1 -1
  70. package/dist/{cli-fv5hepyy.js → cli-sn1vbtg2.js} +3 -3
  71. package/dist/{cli-36ckw0wx.js → cli-stxdrqs2.js} +2 -2
  72. package/dist/{cli-1m17dc9d.js → cli-ta8bd7th.js} +2 -2
  73. package/dist/{cli-43x64hv3.js → cli-v2g93k4v.js} +4 -4
  74. package/dist/{cli-d2mb5s8a.js → cli-x77gen2p.js} +680 -440
  75. package/dist/{cli-3a45zcgm.js → cli-xc65x52q.js} +2 -2
  76. package/dist/{cli-f0g3pgvf.js → cli-xd4eqtr2.js} +2 -2
  77. package/dist/{cli-018r4jq6.js → cli-y3zyaee5.js} +8 -8
  78. package/dist/{cli-kpw04va0.js → cli-z2dv25mf.js} +1 -1
  79. package/dist/{cli-qwhy2qma.js → cli-z63a269p.js} +2 -2
  80. package/dist/{cli-sm8rses9.js → cli-zfdp01hn.js} +8 -5
  81. package/dist/{cli-tw4p90jb.js → cli-znvq0k3t.js} +5 -5
  82. package/dist/cli.js +29 -27
  83. package/dist/{cloudflare-workers-ai-system-one-ch2wxfcp.js → cloudflare-workers-ai-system-one-43v9qkjk.js} +7 -2
  84. package/dist/{codex-adapter-tn6k5mkg.js → codex-adapter-p4ptwar5.js} +6 -4
  85. package/dist/{codex-login-m819c41r.js → codex-login-rn7c5gxt.js} +1 -1
  86. package/dist/{codex-session-runner-7vjt7jbw.js → codex-session-runner-964c7dnk.js} +7 -5
  87. package/dist/{commands-t7rz9146.js → commands-mbvhbrcy.js} +2 -2
  88. package/dist/{controller-m2jasma5.js → controller-gnq1k1mf.js} +4 -4
  89. package/dist/{controllers-connect-9ftpex99.js → controllers-connect-6dkm71tg.js} +25 -23
  90. package/dist/{cursor-adapter-mjv79e4z.js → cursor-adapter-yq5xgfcg.js} +1 -1
  91. package/dist/{db-6sfrn9g3.js → db-88wcymxt.js} +14 -2
  92. package/dist/{db-rn673r06.js → db-af9y8nkf.js} +3 -3
  93. package/dist/{devin-adapter-zgqadvnm.js → devin-adapter-4ycy4vrf.js} +1 -1
  94. package/dist/{dispatcher-c155xz0p.js → dispatcher-606ydx5v.js} +22 -20
  95. package/dist/{docker-fkgtr75t.js → docker-nfy2gc8t.js} +2 -2
  96. package/dist/{dsh-adapter-3mmszc1x.js → dsh-adapter-tvhc4k2d.js} +1 -1
  97. package/dist/{e2b-16d6ch39.js → e2b-9gkdhm3c.js} +2 -2
  98. package/dist/{e2b-zn0b4w5w.js → e2b-cjtf8k1z.js} +2 -2
  99. package/dist/{easter-egg-3d-5cgynaja.js → easter-egg-3d-e4qv8dxj.js} +1 -1
  100. package/dist/{event-bus-9vpk8gmq.js → event-bus-3z78ep5n.js} +1 -1
  101. package/dist/{execute-t4e6m3rw.js → execute-0xpz8950.js} +85 -23
  102. package/dist/{external-channel-35k6tkv8.js → external-channel-y8q5z8z2.js} +2 -2
  103. package/dist/{google-generative-ai-bmq8gkf3.js → google-generative-ai-mk9vcpe1.js} +15 -15
  104. package/dist/{google-vertex-b1rvp52s.js → google-vertex-q580kz8k.js} +20 -20
  105. package/dist/{grok-adapter-tfrq7tg1.js → grok-adapter-39aha52t.js} +9 -7
  106. package/dist/handlers-rk9dqech.js +41 -0
  107. package/dist/{heartbeat-dyg4npkp.js → heartbeat-jfe9zfjr.js} +25 -23
  108. package/dist/{hook-drspbwpe.js → hook-b1mez1m8.js} +9 -7
  109. package/dist/{hook-x26b31bg.js → hook-ffevzed1.js} +7 -5
  110. package/dist/{http-pk972xyw.js → http-d5b44f1r.js} +544 -76
  111. package/dist/{index-g6tbb6ve.js → index-31ceyf42.js} +1 -1
  112. package/dist/index-4q3vj1yr.js +46 -0
  113. package/dist/{index-arytgj5q.js → index-5en23s5z.js} +1 -1
  114. package/dist/index-d2qeem97.js +42 -0
  115. package/dist/index-mj46rk9k.js +43 -0
  116. package/dist/{index-jwxkkex2.js → index-nq8hhv28.js} +13 -11
  117. package/dist/{index-g216q6jr.js → index-zsyx51ap.js} +1 -4
  118. package/dist/{keepalive-7yrng7px.js → keepalive-wsby1btq.js} +4 -4
  119. package/dist/lead-paa141j6.js +79 -0
  120. package/dist/{llama-cpp-classify-vv43gswy.js → llama-cpp-classify-ee7vmd7q.js} +4 -1
  121. package/dist/{maintenance-e6cemdqt.js → maintenance-vnshcyv9.js} +1 -1
  122. package/dist/{mistral-conversations-1medfwv7.js → mistral-conversations-sd0xf1tn.js} +13 -13
  123. package/dist/{node-de6akczr.js → node-jzjj7r9x.js} +1 -1
  124. package/dist/{oauth-refresh-sweep-yw3xdbcj.js → oauth-refresh-sweep-d6sqn5np.js} +3 -3
  125. package/dist/{onboard-0a9y5yrc.js → onboard-nr4xhpzy.js} +2 -2
  126. package/dist/{openai-codex-responses-de9pvs4d.js → openai-codex-responses-79s8xnbh.js} +29 -23
  127. package/dist/{openai-completions-mtqge3nf.js → openai-completions-tdbyts0x.js} +21 -20
  128. package/dist/{openai-decisions-ygk4kkxd.js → openai-decisions-bqhnjyfz.js} +2 -1
  129. package/dist/{openai-responses-dkyng71g.js → openai-responses-dm3t5vqp.js} +26 -17
  130. package/dist/{opencode-adapter-x4tqzhkh.js → opencode-adapter-e56086m1.js} +7 -5
  131. package/dist/{openrouter-images-wvv7camj.js → openrouter-images-ssttr1y4.js} +6 -3
  132. package/dist/{otel-impl-trjpkfb7.js → otel-impl-ytn9wyv9.js} +2 -2
  133. package/dist/{pi-messages-nhh1pkz2.js → pi-messages-3nf8bq1a.js} +6 -4
  134. package/dist/{pi-mono-adapter-mcfkn9vf.js → pi-mono-adapter-tzps8f38.js} +9 -37
  135. package/dist/{pricing-refresh-d2b5my0y.js → pricing-refresh-pva04zee.js} +3 -3
  136. package/dist/{rbac-roles-nxh5ahwk.js → rbac-roles-7rc1q3g4.js} +1 -1
  137. package/dist/{rbac-roles-hey3yv9d.js → rbac-roles-ff1ffmec.js} +2 -2
  138. package/dist/{render-v2-rr3p2atg.js → render-v2-pyfsg9zk.js} +3 -3
  139. package/dist/{resume-2efkf1s1.js → resume-phj8xhqr.js} +10 -8
  140. package/dist/{runtime-xe3aqy4x.js → runtime-bt5pkpm1.js} +1 -1
  141. package/dist/{session-access-s2mttxpw.js → session-access-jzx2z9h5.js} +6 -4
  142. package/dist/{setup-vypma5yt.js → setup-rfg0f0sg.js} +1 -1
  143. package/dist/{typesafe-system-one-2hgpayzy.js → typesafe-system-one-bre38hvs.js} +4 -2
  144. package/dist/{virtual-modules-4r3zkc20.js → virtual-modules-mnfbh5mr.js} +8 -2
  145. package/dist/{work-objects-rvhckdkp.js → work-objects-44z2yjg8.js} +25 -23
  146. package/dist/worker-zsfqzxhm.js +79 -0
  147. package/dist/{x-y45mthwn.js → x-pbpezr0s.js} +2 -2
  148. package/openapi.json +785 -5
  149. package/package.json +9 -9
  150. package/src/assets/key.ts +17 -0
  151. package/src/azure-devops/handlers.ts +1 -1
  152. package/src/be/db/approvals.ts +18 -0
  153. package/src/be/db/session-moves.ts +164 -0
  154. package/src/be/db/session-tree.ts +384 -0
  155. package/src/be/db/tasks/read.ts +40 -4
  156. package/src/be/db/workflow-runs.ts +96 -0
  157. package/src/be/db.ts +80 -236
  158. package/src/be/onboarding.ts +3 -0
  159. package/src/be/skill-sync.ts +43 -2
  160. package/src/be/swarm-config-guard.ts +1 -0
  161. package/src/bitbucket/api.ts +81 -0
  162. package/src/bitbucket/auth.ts +64 -0
  163. package/src/bitbucket/handlers.ts +434 -0
  164. package/src/bitbucket/index.ts +28 -0
  165. package/src/bitbucket/templates.ts +134 -0
  166. package/src/bitbucket/types.ts +65 -0
  167. package/src/commands/runner.ts +55 -3
  168. package/src/e2b/env.ts +1 -0
  169. package/src/extensions/contract-types.generated.ts +1 -1
  170. package/src/extensions/contract.ts +2 -2
  171. package/src/extensions/post-bridge.ts +1 -0
  172. package/src/github/handlers.ts +6 -6
  173. package/src/gitlab/auth.ts +8 -2
  174. package/src/gitlab/handlers.ts +63 -15
  175. package/src/gitlab/index.ts +1 -1
  176. package/src/http/assets.ts +14 -2
  177. package/src/http/core.ts +12 -0
  178. package/src/http/index.ts +4 -0
  179. package/src/http/onboarding.ts +1 -0
  180. package/src/http/sessions.ts +366 -12
  181. package/src/http/skills.ts +48 -1
  182. package/src/http/tasks.ts +1 -1
  183. package/src/http/users.ts +1 -0
  184. package/src/http/webhooks.ts +141 -0
  185. package/src/integrations/chat-sdk/adapters.ts +19 -3
  186. package/src/integrations/chat-sdk/facts.ts +30 -12
  187. package/src/integrations/chat-sdk/outbound.ts +38 -1
  188. package/src/providers/acp-targets.ts +1 -1
  189. package/src/providers/amp-adapter.ts +1 -1
  190. package/src/providers/pi-mono-adapter.ts +5 -53
  191. package/src/scripts-runtime/types/swarm-extension.d.ts +6 -4
  192. package/src/slack/handlers.test.ts +158 -0
  193. package/src/slack/handlers.ts +19 -28
  194. package/src/tasks/context-key.ts +61 -1
  195. package/src/tests/bitbucket-auth.test.ts +156 -0
  196. package/src/tests/bitbucket-handlers.test.ts +425 -0
  197. package/src/tests/bitbucket-webhook.test.ts +220 -0
  198. package/src/tests/chat-sdk-inbound.test.ts +39 -0
  199. package/src/tests/chat-sdk-telegram-markdown.test.ts +92 -0
  200. package/src/tests/context-key.test.ts +50 -0
  201. package/src/tests/core-auth.test.ts +5 -0
  202. package/src/tests/db-task-read-contract.test.ts +7 -0
  203. package/src/tests/db-task-write-contract.test.ts +6 -0
  204. package/src/tests/docs-index-footprint.test.js +3 -3
  205. package/src/tests/fixtures/bitbucket/pullrequest-comment-created-inline.json +174 -0
  206. package/src/tests/fixtures/bitbucket/pullrequest-comment-created.json +170 -0
  207. package/src/tests/fixtures/bitbucket/pullrequest-created-mention.json +132 -0
  208. package/src/tests/fixtures/bitbucket/pullrequest-created-reviewer.json +140 -0
  209. package/src/tests/fixtures/bitbucket/pullrequest-fulfilled.json +134 -0
  210. package/src/tests/fixtures/bitbucket/pullrequest-rejected.json +133 -0
  211. package/src/tests/generate-mcp-docs.test.ts +101 -0
  212. package/src/tests/gitlab-auth.test.ts +13 -5
  213. package/src/tests/gitlab-handlers.test.ts +273 -25
  214. package/src/tests/gitlab-vcs-db.test.ts +4 -4
  215. package/src/tests/integration-disable-flags.test.ts +36 -0
  216. package/src/tests/mcp-tools.test.ts +1 -1
  217. package/src/tests/onboarding.test.ts +12 -0
  218. package/src/tests/pi-codemode.test.ts +8 -2
  219. package/src/tests/preload-env.test.ts +57 -0
  220. package/src/tests/preload.ts +21 -0
  221. package/src/tests/prompt-template-remaining.test.ts +38 -0
  222. package/src/tests/run-root-coverage.test.ts +39 -0
  223. package/src/tests/runner-bitbucket-vcs.test.ts +191 -0
  224. package/src/tests/runner-skills-refresh.test.ts +58 -0
  225. package/src/tests/secret-scrubber.test.ts +15 -0
  226. package/src/tests/sessions-move.test.ts +576 -0
  227. package/src/tests/sessions-tree.test.ts +493 -0
  228. package/src/tests/skill-files-http.test.ts +50 -0
  229. package/src/tests/skills-bundle.test.ts +99 -0
  230. package/src/tests/swarm-config-export-to-env.test.ts +2 -1
  231. package/src/tests/vcs-bitbucket.test.ts +91 -0
  232. package/src/tests/vcs-provider-isolation.test.ts +123 -0
  233. package/src/tests/vcs-provider.test.ts +16 -1
  234. package/src/tests/vcs-tracking.test.ts +3 -3
  235. package/src/tests/workflow-foreach-bodies.test.ts +637 -0
  236. package/src/tests/workflow-foreach-concurrency.test.ts +342 -0
  237. package/src/tests/workflow-foreach-retry.test.ts +537 -0
  238. package/src/tests/workflow-foreach.test.ts +44 -23
  239. package/src/tests/workflow-step-claims.test.ts +6 -6
  240. package/src/tests/workflow-tla-races.test.ts +2 -2
  241. package/src/tools/script-delete.ts +1 -1
  242. package/src/tools/workflows/create-workflow.ts +5 -3
  243. package/src/types.ts +3 -2
  244. package/src/utils/config-env-export.ts +1 -0
  245. package/src/utils/secret-scrubber.ts +4 -0
  246. package/src/utils/skills-refresh.ts +83 -43
  247. package/src/vcs/bitbucket.ts +58 -0
  248. package/src/vcs/index.ts +2 -0
  249. package/src/vcs/types.ts +2 -2
  250. package/src/workflows/approval-resolution.ts +4 -1
  251. package/src/workflows/checkpoint.ts +9 -1
  252. package/src/workflows/constants.ts +3 -0
  253. package/src/workflows/definition.ts +48 -17
  254. package/src/workflows/engine.ts +25 -15
  255. package/src/workflows/executors/foreach.ts +45 -99
  256. package/src/workflows/foreach-body.ts +146 -0
  257. package/src/workflows/foreach-driver.ts +552 -0
  258. package/src/workflows/foreach-join.ts +206 -7
  259. package/src/workflows/node-timeout.ts +21 -0
  260. package/src/workflows/recovery.ts +68 -3
  261. package/src/workflows/resume.ts +221 -43
  262. package/src/workflows/retry-poller.ts +39 -24
  263. package/src/workflows/step-input.ts +59 -0
  264. package/src/workflows/task-step-routing.ts +114 -56
  265. package/templates/skills/slack-interaction/content.md +5 -0
  266. package/templates/skills/work-on-task/SKILL.md +1 -1
  267. package/templates/skills/work-on-task/content.md +1 -1
  268. package/dist/cli-9hstj09h.js +0 -2657
  269. package/dist/cli-yw91rnmw.js +0 -13
  270. package/dist/handlers-7gw64dxw.js +0 -39
  271. package/dist/index-bgdyvcnv.js +0 -40
  272. package/dist/index-gabbcdn2.js +0 -43
  273. package/dist/index-tfb26zhy.js +0 -41
  274. package/dist/lead-7e02z839.js +0 -77
  275. package/dist/worker-5snytpbd.js +0 -77
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Bitbucket Cloud event prompt template definitions.
3
+ *
4
+ * Each template is registered at module load time via registerTemplate().
5
+ * Handlers import this module for the side-effect of registration.
6
+ *
7
+ * Template text uses {{variable}} syntax. The resolver interpolates variables
8
+ * and expands {{@template[id]}} references before returning the final text.
9
+ */
10
+
11
+ import { registerTemplate } from "../prompts/registry";
12
+
13
+ // ============================================================================
14
+ // Common building blocks (Bitbucket-specific)
15
+ // ============================================================================
16
+
17
+ registerTemplate({
18
+ eventType: "common.delegation_instruction.bitbucket",
19
+ header: "",
20
+ defaultBody:
21
+ "\n\n**Delegation instruction:** As the lead agent, analyze this and decide whether to handle it yourself or delegate to a worker agent. Use `send-task` to delegate with clear instructions.",
22
+ variables: [],
23
+ category: "common",
24
+ });
25
+
26
+ // There is no Bitbucket CLI in the worker image, so the recipes are curl calls
27
+ // against the REST API with the worker's BITBUCKET_TOKEN.
28
+ registerTemplate({
29
+ eventType: "common.command_suggestions.bitbucket_pr",
30
+ header: "",
31
+ defaultBody:
32
+ 'Workers have `git` authenticated for bitbucket.org and `BITBUCKET_TOKEN` in env; there is no Bitbucket CLI, so use curl against `https://api.bitbucket.org/2.0/repositories/{{repo}}` with `-H "Authorization: Bearer $BITBUCKET_TOKEN"`. Inspect the PR with `GET .../pullrequests/{{pr_id}}` and its diff with `GET .../pullrequests/{{pr_id}}/diff`. Reply with `POST .../pullrequests/{{pr_id}}/comments` and JSON body `{"content":{"raw":"<reply>"}}`. Find a PR by branch with `GET .../pullrequests?q=source.branch.name="<branch>"`. Open a PR with `POST .../pullrequests` and JSON body `{"title":"<title>","source":{"branch":{"name":"<branch>"}},"destination":{"branch":{"name":"<base>"}}}`.',
33
+ variables: [
34
+ { name: "repo", description: "Repository full name (<workspace>/<repo_slug>)" },
35
+ { name: "pr_id", description: "Pull request ID" },
36
+ ],
37
+ category: "common",
38
+ });
39
+
40
+ const SHARED_VARIABLES = [
41
+ { name: "pr_id", description: "Pull request ID" },
42
+ { name: "pr_title", description: "Pull request title" },
43
+ { name: "repo", description: "Repository full name (<workspace>/<repo_slug>)" },
44
+ { name: "pr_url", description: "Pull request web URL" },
45
+ ];
46
+
47
+ const PR_BRANCH_VARIABLES = [
48
+ { name: "source_branch", description: "Source branch name" },
49
+ { name: "target_branch", description: "Target branch name" },
50
+ { name: "context_section", description: "Context section with description or empty string" },
51
+ ];
52
+
53
+ // ============================================================================
54
+ // Pull request events
55
+ // ============================================================================
56
+
57
+ registerTemplate({
58
+ eventType: "bitbucket.pull_request.opened",
59
+ header: "[Bitbucket PR #{{pr_id}}] {{pr_title}}",
60
+ defaultBody: `Repo: {{repo}}
61
+ Author: {{username}}
62
+ Branch: {{source_branch}} → {{target_branch}}
63
+ URL: {{pr_url}}
64
+
65
+ {{context_section}}{{@template[common.command_suggestions.bitbucket_pr]}}{{@template[common.delegation_instruction.bitbucket]}}`,
66
+ variables: [
67
+ ...SHARED_VARIABLES,
68
+ {
69
+ name: "username",
70
+ description:
71
+ "Author identity — resolved canonical name (e.g. 'Luis (bitbucket:557058:…)') or the UNKNOWN sentinel",
72
+ },
73
+ ...PR_BRANCH_VARIABLES,
74
+ ],
75
+ category: "event",
76
+ });
77
+
78
+ registerTemplate({
79
+ eventType: "bitbucket.pull_request.review_requested",
80
+ header: "[Bitbucket PR #{{pr_id}}] Review requested: {{pr_title}}",
81
+ defaultBody: `Repo: {{repo}}
82
+ Author: {{username}}
83
+ Branch: {{source_branch}} → {{target_branch}}
84
+ URL: {{pr_url}}
85
+
86
+ You were added as a reviewer on this pull request.
87
+
88
+ {{context_section}}{{@template[common.command_suggestions.bitbucket_pr]}}{{@template[common.delegation_instruction.bitbucket]}}`,
89
+ variables: [
90
+ ...SHARED_VARIABLES,
91
+ {
92
+ name: "username",
93
+ description:
94
+ "Author identity — resolved canonical name (e.g. 'Luis (bitbucket:557058:…)') or the UNKNOWN sentinel",
95
+ },
96
+ ...PR_BRANCH_VARIABLES,
97
+ ],
98
+ category: "event",
99
+ });
100
+
101
+ // ============================================================================
102
+ // Pull request comment events
103
+ // ============================================================================
104
+
105
+ registerTemplate({
106
+ eventType: "bitbucket.comment.mentioned",
107
+ header: "[Bitbucket Comment on PR #{{pr_id}}] {{username}} mentioned bot",
108
+ defaultBody: `Repo: {{repo}}
109
+ PR: {{pr_title}}
110
+ URL: {{pr_url}}
111
+ {{location_section}}
112
+ Comment:
113
+ {{context}}{{existing_task_note}}
114
+
115
+ {{@template[common.command_suggestions.bitbucket_pr]}}{{@template[common.delegation_instruction.bitbucket]}}`,
116
+ variables: [
117
+ ...SHARED_VARIABLES,
118
+ {
119
+ name: "username",
120
+ description:
121
+ "Comment author identity — resolved canonical name (e.g. 'Luis (bitbucket:557058:…)') or the UNKNOWN sentinel",
122
+ },
123
+ {
124
+ name: "location_section",
125
+ description: "`File: <path>:<line>` line for inline comments, or empty string",
126
+ },
127
+ { name: "context", description: "Extracted mention context from comment" },
128
+ {
129
+ name: "existing_task_note",
130
+ description: "Note about existing active task, or empty string",
131
+ },
132
+ ],
133
+ category: "event",
134
+ });
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Bitbucket Cloud webhook payload types (subsets of the documented event
3
+ * payloads; only the fields the handlers read).
4
+ * https://support.atlassian.com/bitbucket-cloud/docs/event-payloads/
5
+ */
6
+
7
+ export interface BitbucketAccount {
8
+ type?: string;
9
+ /** Atlassian account id, e.g. `557058:<uuid>`. Absent for some app/team actors. */
10
+ account_id?: string;
11
+ /** Bitbucket user UUID, wrapped in braces: `{…}`. */
12
+ uuid?: string;
13
+ display_name?: string;
14
+ nickname?: string;
15
+ }
16
+
17
+ export interface BitbucketRepository {
18
+ /** Repository UUID, wrapped in braces: `{…}`. Stable across renames. */
19
+ uuid: string;
20
+ /** `<workspace>/<repo_slug>` */
21
+ full_name: string;
22
+ name?: string;
23
+ links?: { html?: { href: string } };
24
+ }
25
+
26
+ export interface BitbucketBranchRef {
27
+ branch?: { name: string };
28
+ commit?: { hash: string };
29
+ repository?: BitbucketRepository;
30
+ }
31
+
32
+ export interface BitbucketPullRequest {
33
+ id: number;
34
+ title: string;
35
+ description?: string | null;
36
+ state?: "OPEN" | "MERGED" | "DECLINED" | "SUPERSEDED";
37
+ author?: BitbucketAccount;
38
+ source?: BitbucketBranchRef;
39
+ destination?: BitbucketBranchRef;
40
+ reviewers?: BitbucketAccount[];
41
+ links?: { html?: { href: string } };
42
+ }
43
+
44
+ export interface BitbucketComment {
45
+ id: number;
46
+ content: { raw: string; markup?: string; html?: string };
47
+ user?: BitbucketAccount;
48
+ inline?: { path: string; from?: number | null; to?: number | null } | null;
49
+ parent?: { id: number } | null;
50
+ links?: { html?: { href: string } };
51
+ }
52
+
53
+ /** `pullrequest:created`, `pullrequest:fulfilled`, `pullrequest:rejected` */
54
+ export interface PullRequestEvent {
55
+ actor: BitbucketAccount;
56
+ pullrequest: BitbucketPullRequest;
57
+ repository: BitbucketRepository;
58
+ }
59
+
60
+ /** `pullrequest:comment_created` */
61
+ export interface PullRequestCommentEvent extends PullRequestEvent {
62
+ comment: BitbucketComment;
63
+ }
64
+
65
+ export type BitbucketWebhookEvent = PullRequestEvent | PullRequestCommentEvent;
@@ -108,6 +108,7 @@ import {
108
108
  isAzureDevOpsUrl,
109
109
  parseAzureDevOpsRepoUrl,
110
110
  } from "../vcs/azure-devops.ts";
111
+ import { bitbucketFullName, isBitbucketUrl, parseBitbucketRepoUrl } from "../vcs/bitbucket.ts";
111
112
  import { detectVcsProvider, type VcsProvider } from "../vcs/index.ts";
112
113
  import { validateJsonSchema } from "../workflows/json-schema-validator.ts";
113
114
  import { buildAttachmentsSection } from "./attachments-section.ts";
@@ -311,6 +312,7 @@ const CONTINUATION_TASK_TYPES = new Set([
311
312
  "gitlab-comment",
312
313
  "gitlab-ci",
313
314
  "azure-devops-comment",
315
+ "bitbucket-comment",
314
316
  ]);
315
317
 
316
318
  /**
@@ -2946,11 +2948,51 @@ const vcsDetectedTasks = new Set<string>();
2946
2948
  const vcsCheckTimestamps = new Map<string, number>();
2947
2949
  const VCS_CHECK_INTERVAL = 60_000; // 60 seconds
2948
2950
 
2951
+ /**
2952
+ * Find the open Bitbucket Cloud pull request whose source branch is `branch`.
2953
+ * There is no Bitbucket CLI in the worker image, so this calls the REST API
2954
+ * with `BITBUCKET_TOKEN` as a Bearer token. Returns null when the token is
2955
+ * unset, the remote is not a Bitbucket Cloud repo, the API answers non-2xx,
2956
+ * no PR matches, or the request fails. Never throws.
2957
+ */
2958
+ export async function findBitbucketOpenPullRequest(
2959
+ remoteUrl: string,
2960
+ branch: string,
2961
+ opts: { token?: string; fetchImpl?: typeof fetch } = {},
2962
+ ): Promise<{ number: number; url: string } | null> {
2963
+ const token = opts.token ?? process.env.BITBUCKET_TOKEN;
2964
+ if (!token) return null;
2965
+ const repo = parseBitbucketRepoUrl(remoteUrl);
2966
+ if (!repo) return null;
2967
+ const query = `source.branch.name="${branch.replace(/["\\]/g, "\\$&")}" AND state="OPEN"`;
2968
+ const url =
2969
+ `https://api.bitbucket.org/2.0/repositories/${encodeURIComponent(repo.workspace)}` +
2970
+ `/${encodeURIComponent(repo.repoSlug)}/pullrequests?q=${encodeURIComponent(query)}&pagelen=1`;
2971
+ try {
2972
+ const res = await (opts.fetchImpl ?? fetch)(url, {
2973
+ headers: { Authorization: `Bearer ${token}`, Accept: "application/json" },
2974
+ signal: AbortSignal.timeout(15_000),
2975
+ });
2976
+ if (!res.ok) return null;
2977
+ const body = (await res.json()) as {
2978
+ values?: Array<{ id?: unknown; links?: { html?: { href?: unknown } } }>;
2979
+ };
2980
+ const pr = body.values?.[0];
2981
+ const href = pr?.links?.html?.href;
2982
+ if (typeof pr?.id !== "number" || pr.id <= 0 || typeof href !== "string" || !href) {
2983
+ return null;
2984
+ }
2985
+ return { number: pr.id, url: href };
2986
+ } catch {
2987
+ return null;
2988
+ }
2989
+ }
2990
+
2949
2991
  /**
2950
2992
  * Detect if the task's working directory has an open PR for the current branch.
2951
2993
  * If found, report VCS info to the API so webhook events can link back to this task.
2952
2994
  */
2953
- async function detectVcsForTask(
2995
+ export async function detectVcsForTask(
2954
2996
  apiUrl: string,
2955
2997
  apiKey: string,
2956
2998
  taskId: string,
@@ -2974,6 +3016,7 @@ async function detectVcsForTask(
2974
3016
  let vcsProvider: VcsProvider;
2975
3017
  let prJson: string;
2976
3018
  let azureRepo: string | null = null;
3019
+ let bitbucketRepo: string | null = null;
2977
3020
 
2978
3021
  if (isAzureDevOpsUrl(remoteUrl)) {
2979
3022
  const parsed = parseAzureDevOpsRepoUrl(remoteUrl);
@@ -2991,6 +3034,14 @@ async function detectVcsForTask(
2991
3034
  url: `${azureRepo}/pullrequest/${pr.pullRequestId}`,
2992
3035
  })),
2993
3036
  );
3037
+ } else if (isBitbucketUrl(remoteUrl)) {
3038
+ // Checked before the loose "github" substring match below, so a
3039
+ // Bitbucket repo with "github" in its slug is not sent to `gh`.
3040
+ bitbucketRepo = bitbucketFullName(remoteUrl);
3041
+ if (!bitbucketRepo) return;
3042
+ vcsProvider = "bitbucket";
3043
+ const pr = await findBitbucketOpenPullRequest(remoteUrl, branch);
3044
+ prJson = JSON.stringify(pr ? [pr] : []);
2994
3045
  } else if (remoteUrl.includes("github.com") || remoteUrl.includes("github")) {
2995
3046
  vcsProvider = "github";
2996
3047
  prJson = (
@@ -3017,9 +3068,10 @@ async function detectVcsForTask(
3017
3068
  if (!vcsNumber || !vcsUrl) return;
3018
3069
 
3019
3070
  // 6. Extract repo from remote URL (Azure Repos keep the canonical clone URL,
3020
- // matching the vcsRepo their webhook tasks carry)
3071
+ // matching the vcsRepo their webhook tasks carry; Bitbucket uses the
3072
+ // `workspace/repo_slug` full name its webhook tasks carry)
3021
3073
  const repoMatch = remoteUrl.match(/[:/]([^/]+\/[^/.]+?)(?:\.git)?$/);
3022
- const vcsRepo = azureRepo ?? repoMatch?.[1];
3074
+ const vcsRepo = azureRepo ?? bitbucketRepo ?? repoMatch?.[1];
3023
3075
  if (!vcsRepo) return;
3024
3076
 
3025
3077
  // 7. Report to API
package/src/e2b/env.ts CHANGED
@@ -29,6 +29,7 @@ export const DEFAULT_E2B_FORWARD_KEYS = [
29
29
  "GITLAB_TOKEN",
30
30
  "AZURE_DEVOPS_TOKEN",
31
31
  "AZURE_DEVOPS_ORG_URL",
32
+ "BITBUCKET_TOKEN",
32
33
  "LINEAR_API_KEY",
33
34
  "SLACK_BOT_TOKEN",
34
35
  "SLACK_SIGNING_SECRET",
@@ -1,4 +1,4 @@
1
1
  // Generated by scripts/bundle-extension-types.ts. Do not edit.
2
2
  // biome-ignore-all lint/suspicious/noTemplateCurlyInString: Type declarations contain literal template placeholders.
3
3
  export const EXTENSION_TYPE_DEFINITIONS =
4
- '// biome-ignore-all lint/suspicious/noConfusingVoidType: Extension handlers may explicitly return no result.\ndeclare module "swarm-extension" {\n export type CreateTaskOptions = {\n key?: string | undefined;\n agentId?: string | null | undefined;\n creatorAgentId?: string | undefined;\n source?:\n | "workflow"\n | "schedule"\n | "slack"\n | "agentmail"\n | "mcp"\n | "api"\n | "ui"\n | "github"\n | "gitlab"\n | "azure-devops"\n | "system"\n | "linear"\n | "jira"\n | "comb"\n | "chat"\n | undefined;\n routingReason?:\n | "skill"\n | "continuity"\n | "overflow"\n | "human_pinned"\n | "reroute_fault"\n | undefined;\n routingSource?: "declared" | "engine_default" | undefined;\n routingNote?: string | undefined;\n taskType?: string | undefined;\n tags?: string[] | undefined;\n priority?: number | undefined;\n dependsOn?: string[] | undefined;\n offeredTo?: string | undefined;\n status?: "draft" | "backlog" | "unassigned" | undefined;\n slackChannelId?: string | undefined;\n slackThreadTs?: string | undefined;\n slackTriggerMessageTs?: string | undefined;\n slackUserId?: string | undefined;\n overrideSlackContext?: boolean | undefined;\n vcsProvider?: "github" | "gitlab" | "azure-devops" | undefined;\n vcsRepo?: string | undefined;\n vcsEventType?: string | undefined;\n vcsNumber?: number | undefined;\n vcsCommentId?: number | undefined;\n vcsAuthor?: string | undefined;\n vcsUrl?: string | undefined;\n vcsInstallationId?: number | undefined;\n vcsNodeId?: string | undefined;\n agentmailInboxId?: string | undefined;\n agentmailMessageId?: string | undefined;\n agentmailThreadId?: string | undefined;\n mentionMessageId?: string | undefined;\n mentionChannelId?: string | undefined;\n dir?: string | undefined;\n parentTaskId?: string | undefined;\n model?: string | undefined;\n modelTier?: "smol" | "regular" | "smart" | "ultra" | undefined;\n effort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;\n profile?: string | undefined;\n scheduleId?: string | undefined;\n workflowRunId?: string | undefined;\n workflowRunStepId?: string | undefined;\n sourceTaskId?: string | undefined;\n outputSchema?: Record<string, unknown> | undefined;\n inheritParentOutputSchema?: boolean | undefined;\n inheritParentRequester?: boolean | undefined;\n inheritParentRoutingAffinity?: boolean | undefined;\n inheritParentFollowUpConfig?: boolean | undefined;\n followUpConfig?:\n | {\n disabled?: boolean | undefined;\n onCompleted?: string | undefined;\n onFailed?: string | undefined;\n }\n | undefined;\n requestedByUserId?: string | undefined;\n contextKey?: string | undefined;\n bypassTrackerContextDedup?: boolean | undefined;\n routingAffinity?:\n | {\n capabilities: string[];\n sourceAgentId?: string | undefined;\n role?: string | undefined;\n harnessProvider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | "grok"\n | undefined;\n leadOnly?: boolean | undefined;\n }\n | undefined;\n };\n\n export type AgentTask = {\n id: string;\n key: string;\n agentId: string | null;\n task: string;\n status:\n | "draft"\n | "backlog"\n | "unassigned"\n | "offered"\n | "reviewing"\n | "pending"\n | "in_progress"\n | "paused"\n | "completed"\n | "failed"\n | "cancelled"\n | "superseded";\n source:\n | "workflow"\n | "schedule"\n | "slack"\n | "agentmail"\n | "mcp"\n | "api"\n | "ui"\n | "github"\n | "gitlab"\n | "azure-devops"\n | "system"\n | "linear"\n | "jira"\n | "comb"\n | "chat";\n tags: string[];\n priority: number;\n dependsOn: string[];\n createdAt: string;\n lastUpdatedAt: string;\n slackReplySent: boolean;\n wasPaused: boolean;\n creatorAgentId?: string | undefined;\n title?: string | undefined;\n routingReason?:\n | "skill"\n | "continuity"\n | "overflow"\n | "human_pinned"\n | "reroute_fault"\n | undefined;\n routingSource?: "declared" | "engine_default" | undefined;\n routingNote?: string | undefined;\n poolWakeAt?: string | undefined;\n taskType?: string | undefined;\n offeredTo?: string | undefined;\n offeredAt?: string | undefined;\n acceptedAt?: string | undefined;\n rejectionReason?: string | undefined;\n finishedAt?: string | undefined;\n notifiedAt?: string | undefined;\n failureReason?: string | undefined;\n output?: string | undefined;\n progress?: string | undefined;\n slackChannelId?: string | undefined;\n slackThreadTs?: string | undefined;\n slackTriggerMessageTs?: string | undefined;\n slackUserId?: string | undefined;\n slackProgressMessageTs?: string | undefined;\n slackTreeRootMessageTs?: string | undefined;\n vcsProvider?: "github" | "gitlab" | "azure-devops" | undefined;\n vcsRepo?: string | undefined;\n vcsEventType?: string | undefined;\n vcsNumber?: number | undefined;\n vcsCommentId?: number | undefined;\n vcsAuthor?: string | undefined;\n vcsUrl?: string | undefined;\n vcsInstallationId?: number | undefined;\n vcsNodeId?: string | undefined;\n agentmailInboxId?: string | undefined;\n agentmailMessageId?: string | undefined;\n agentmailThreadId?: string | undefined;\n mentionMessageId?: string | undefined;\n mentionChannelId?: string | undefined;\n dir?: string | undefined;\n parentTaskId?: string | undefined;\n claudeSessionId?: string | undefined;\n model?: string | undefined;\n modelTier?: "smol" | "regular" | "smart" | "ultra" | undefined;\n effort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;\n resolvedModel?: string | undefined;\n modelSource?: string | undefined;\n modelAlias?: string | undefined;\n resolvedEffort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;\n profile?: string | undefined;\n resolvedProfile?: string | undefined;\n scheduleId?: string | undefined;\n workflowRunId?: string | null | undefined;\n workflowRunStepId?: string | null | undefined;\n contextKey?: string | undefined;\n outputSchema?: Record<string, unknown> | undefined;\n followUpConfig?:\n | {\n disabled?: boolean | undefined;\n onCompleted?: string | undefined;\n onFailed?: string | undefined;\n }\n | undefined;\n deferredAt?: string | undefined;\n compactionCount?: number | undefined;\n peakContextPercent?: number | undefined;\n peakContextTokens?: number | undefined;\n contextWindowSize?: number | undefined;\n credentialKeySuffix?: string | undefined;\n credentialKeyType?: string | undefined;\n requestedByUserId?: string | undefined;\n swarmVersion?: string | undefined;\n provider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | "grok"\n | undefined;\n providerMeta?: Record<string, unknown> | undefined;\n harnessVariant?: string | undefined;\n harnessVariantMeta?: Record<string, unknown> | undefined;\n totalCostUsd?: number | undefined;\n routingAffinity?:\n | {\n capabilities: string[];\n sourceAgentId?: string | undefined;\n role?: string | undefined;\n harnessProvider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | "grok"\n | undefined;\n leadOnly?: boolean | undefined;\n }\n | undefined;\n routingAffinityInvalid?: boolean | undefined;\n };\n\n export type ActiveSession = {\n id: string;\n agentId: string;\n taskId: string | null;\n triggerType: string;\n inboxMessageId: string | null;\n taskDescription: string | null;\n runnerSessionId: string | null;\n providerSessionId: string | null;\n startedAt: string;\n lastHeartbeatAt: string;\n runtimeInstanceId?: string | null | undefined;\n };\n\n export type RequestInfo = {\n sessionId: string | undefined;\n agentId: string | undefined;\n runtimeInstanceId: string | undefined;\n sourceTaskId: string | undefined;\n contextKey: string | undefined;\n callOrigin: "mcp" | "extension" | "script-sdk";\n };\n\n import type { SwarmSdk } from "swarm-sdk";\n import type { z } from "zod";\n export type Runtime = "api" | "worker";\n export interface ExtensionScriptAsset {\n name: string;\n file: string;\n description: string;\n intent?: string;\n }\n export interface ExtensionScheduleAsset {\n name: string;\n description?: string;\n script: string;\n cronExpression?: string;\n intervalMs?: number;\n timezone?: string;\n args?: Record<string, unknown>;\n }\n export interface ExtensionWorkflowAsset {\n file: string;\n }\n export interface ExtensionSkillAsset {\n dir: string;\n }\n export interface ExtensionManifest {\n $schema?: string;\n name: string;\n description: string;\n version: string;\n runtime: Runtime;\n assets: {\n hooks: string;\n scripts?: readonly ExtensionScriptAsset[];\n schedules?: readonly ExtensionScheduleAsset[];\n workflows?: readonly ExtensionWorkflowAsset[];\n skills?: readonly ExtensionSkillAsset[];\n };\n homepage?: string;\n author?: string;\n }\n export interface HooksModule {\n default: SwarmExtension;\n config?: z.ZodTypeAny;\n }\n export interface ExtensionState {\n get<T = unknown>(key: string): Promise<T | null>;\n set<T>(key: string, value: T): Promise<void>;\n incr(key: string, by?: number): Promise<number>;\n del(key: string): Promise<void>;\n }\n export interface ExtensionLogger {\n debug(message: string, data?: unknown): void;\n info(message: string, data?: unknown): void;\n warn(message: string, data?: unknown): void;\n error(message: string, data?: unknown): void;\n }\n type ConfigFor<M extends ExtensionManifest> = M extends {\n config: infer C extends z.ZodTypeAny;\n }\n ? z.infer<C>\n : Record<string, unknown>;\n export interface ApiCtx<Config = Record<string, unknown>> {\n swarm: SwarmSdk;\n state: ExtensionState;\n config: Config;\n log: ExtensionLogger;\n signal: AbortSignal;\n event: {\n name: keyof SwarmEventMap;\n at: string;\n extension: {\n id: string;\n version: number;\n };\n };\n }\n export interface WorkerCtx<Config = Record<string, unknown>>\n extends Omit<ApiCtx<Config>, "swarm"> {\n swarm: SwarmSdk;\n worker: {\n agentId: string;\n taskId: string;\n harness: string;\n };\n }\n export type CtxFor<M extends ExtensionManifest> = M["runtime"] extends "api"\n ? ApiCtx<ConfigFor<M>>\n : WorkerCtx<ConfigFor<M>>;\n export type PreResult<Modify> =\n | void\n | {\n action: "continue";\n }\n | {\n action: "modify";\n data: Modify;\n }\n | {\n action: "block";\n reason: string;\n };\n export type TaskCreateOrigin =\n | "rest"\n | "app"\n | "mcp"\n | "slack"\n | "schedule"\n | "workflow"\n | "webhook"\n | "followUp"\n | `extension:${string}`;\n export interface TaskCreateEvent {\n options: CreateTaskOptions;\n description: string;\n origin: TaskCreateOrigin;\n requestInfo?: RequestInfo;\n }\n export type TaskCreateModify = Partial<\n Pick<\n CreateTaskOptions,\n | "agentId"\n | "creatorAgentId"\n | "source"\n | "taskType"\n | "tags"\n | "priority"\n | "dependsOn"\n | "offeredTo"\n | "vcsProvider"\n | "vcsRepo"\n | "vcsEventType"\n | "vcsNumber"\n | "vcsCommentId"\n | "vcsAuthor"\n | "vcsUrl"\n | "vcsInstallationId"\n | "vcsNodeId"\n | "agentmailInboxId"\n | "agentmailMessageId"\n | "agentmailThreadId"\n | "mentionMessageId"\n | "mentionChannelId"\n | "dir"\n | "model"\n | "modelTier"\n | "effort"\n | "outputSchema"\n | "followUpConfig"\n | "bypassTrackerContextDedup"\n >\n > & {\n description?: string;\n };\n export interface TaskFollowUpEvent {\n completedTask: AgentTask;\n status: "completed" | "failed";\n output?: string;\n failureReason?: string;\n workerAgentId: string;\n leadAgentId: string;\n summary: string;\n }\n export type TaskFollowUpModify = Partial<\n Pick<CreateTaskOptions, "agentId" | "priority" | "followUpConfig">\n > & {\n description?: string;\n };\n export interface SlackRouteEvent {\n channelId: string;\n userId: string;\n text: string;\n threadTs?: string;\n botMentioned: boolean;\n threadContext?: {\n channelId: string;\n threadTs: string;\n };\n }\n export interface SlackRouteModify {\n target:\n | {\n kind: "agent";\n agentId: string;\n }\n | {\n kind: "lead";\n }\n | {\n kind: "broadcast";\n };\n }\n /** A Chat SDK message after its thread buffer flushed, before routing. */\n export interface ChatRouteEvent {\n /** Adapter name, such as `telegram` or `slack`. */\n adapter: string;\n channelId: string;\n /** The Chat SDK thread id, prefixed with the adapter name. */\n threadId: string;\n /** The first buffered sender. */\n userId: string;\n userName?: string;\n /** The buffered messages, joined. */\n text: string;\n /** True for an @mention and for a reply to one of the bot\'s messages. */\n botMentioned: boolean;\n isDirectMessage: boolean;\n /** Platform chat type, such as Telegram `private`, `group`, `supergroup` or `channel`. */\n chatType?: string;\n /** Set for a Telegram supergroup with topics. */\n isForum?: boolean;\n /** A buffered message replies to one of the bot\'s own messages. */\n replyToBot: boolean;\n /** Set when earlier swarm tasks exist in this thread. */\n threadContext?: {\n adapter: string;\n threadId: string;\n };\n }\n export interface ChatRouteModify {\n target:\n | {\n kind: "agent";\n agentId: string;\n }\n | {\n kind: "lead";\n }\n | {\n kind: "broadcast";\n }\n | {\n kind: "workflow";\n workflowId: string;\n };\n }\n export type HeartbeatClassification = "no-session" | "stale-session" | "fresh-stalled";\n export type HeartbeatAction = "supersede-resume" | "fail" | "record";\n export interface HeartbeatRemediateEvent {\n task: AgentTask;\n session?: ActiveSession;\n classification: HeartbeatClassification;\n proposedAction: HeartbeatAction;\n reason: string;\n taskAgeMs: number;\n sessionHeartbeatAgeMs?: number;\n }\n export interface HeartbeatRemediateModify {\n proposedAction: HeartbeatAction;\n }\n export interface ToolCallEvent {\n tool: string;\n args: unknown;\n requestInfo: RequestInfo;\n }\n export interface ToolCallModify {\n args: unknown;\n }\n export interface TaskEvent {\n task: AgentTask;\n }\n export interface TaskCompletedEvent extends TaskEvent {\n output: string;\n }\n export interface TaskFailedEvent extends TaskEvent {\n failureReason: string;\n }\n export interface TaskSupersededEvent extends TaskEvent {\n supersededBy: string;\n }\n export interface TaskProgressEvent extends TaskEvent {\n progress: string;\n }\n export interface SlackMessageEvent {\n channelId: string;\n userId: string;\n text: string;\n threadTs?: string;\n taskId?: string;\n }\n /** A Chat SDK message the swarm received or sent. */\n export interface ChatMessageEvent {\n adapter: string;\n channelId: string;\n threadId: string;\n /** The sender, for an inbound message. */\n userId?: string;\n text: string;\n direction: "inbound" | "outbound";\n taskId?: string;\n messageId?: string;\n }\n /**\n * A person answered an approval request. Fires for workflow and standalone\n * requests. Timeouts and cancellations do not emit it today.\n */\n export interface ApprovalResolvedEvent {\n requestId: string;\n status: "approved" | "rejected" | "timeout" | "cancelled";\n responses: Record<string, unknown> | null;\n /** Set when a workflow human-in-the-loop step asked. Absent for a standalone request. */\n workflowRunId?: string;\n workflowRunStepId?: string;\n /** The task whose agent asked, for a standalone request. */\n sourceTaskId?: string;\n }\n /** A task was refused because a daily spend budget is used up. */\n export interface TaskBudgetRefusedEvent extends TaskEvent {\n /** The agent the task was refused for. */\n agentId: string;\n /** Which budget refused it. The matching spend and budget fields are set. */\n cause: "agent" | "global" | "user";\n agentSpendUsd?: number;\n agentBudgetUsd?: number;\n globalSpendUsd?: number;\n globalBudgetUsd?: number;\n userSpendUsd?: number;\n userBudgetUsd?: number;\n /** ISO 8601 time the daily budget resets. */\n resetAt: string;\n }\n /** An inbound AgentMail message. */\n export interface EmailReceivedEvent {\n inboxId: string;\n /** The From header as sent. */\n from: string;\n subject: string;\n /** The text body, or the HTML when there is no text, cut to 500 characters with `...` appended. */\n body: string;\n threadId: string;\n messageId: string;\n }\n /** An inbound Kapso (WhatsApp) message. */\n export interface KapsoMessageEvent {\n phoneNumberId: string;\n conversationId?: string;\n messageId: string;\n from?: string;\n /** Kapso message type, such as `text` or `image`. */\n type?: string;\n /** The text, or a placeholder naming the type for a non-text message. */\n text: string;\n }\n export type VcsProvider = "github" | "gitlab" | "azure-devops";\n /**\n * The provider object the event is about, as the provider names it. GitLab\n * calls a pull request a merge request, and a comment a `note`.\n */\n export type VcsEventKind =\n | "pull_request"\n | "merge_request"\n | "issue"\n | "issue_comment"\n | "note"\n | "pull_request_review"\n | "pipeline";\n /**\n * A webhook event from a connected code host. `action` is the provider\'s own\n * value: `opened`, `closed`, `synchronize`, `merge`, `created`, `commented`, or,\n * for a pipeline, its status such as `success` or `failed`. Fields a kind does\n * not carry are absent.\n */\n export interface VcsEvent {\n provider: VcsProvider;\n kind: VcsEventKind;\n action: string;\n /** `owner/name` on GitHub and GitLab, the repository URL on Azure DevOps. */\n repo: string;\n /** The PR, merge request, or issue number. Absent for a pipeline outside a merge request. */\n number?: number;\n title?: string;\n body?: string | null;\n /** Login of the user behind the event. Set for pull requests, merge requests, and Azure DevOps comments. */\n author?: string;\n url?: string;\n merged?: boolean;\n changedFiles?: number;\n /** The review verdict, on a pull request review. */\n reviewState?: string;\n }\n export interface ToolCallCompletedEvent extends ToolCallEvent {\n result: unknown;\n durationMs: number;\n }\n export interface SwarmEventMap {\n "pre.task.create": {\n event: TaskCreateEvent;\n modify: TaskCreateModify;\n result: PreResult<TaskCreateModify>;\n };\n "pre.task.followUp": {\n event: TaskFollowUpEvent;\n modify: TaskFollowUpModify;\n result: PreResult<TaskFollowUpModify>;\n };\n "pre.slack.route": {\n event: SlackRouteEvent;\n modify: SlackRouteModify;\n result: PreResult<SlackRouteModify>;\n };\n "pre.chat.route": {\n event: ChatRouteEvent;\n modify: ChatRouteModify;\n result: PreResult<ChatRouteModify>;\n };\n "pre.heartbeat.remediate": {\n event: HeartbeatRemediateEvent;\n modify: HeartbeatRemediateModify;\n result: PreResult<HeartbeatRemediateModify>;\n };\n "pre.tool.call": {\n event: ToolCallEvent;\n modify: ToolCallModify;\n result: PreResult<ToolCallModify>;\n };\n "post.task.created": {\n event: TaskEvent;\n modify: never;\n result: void;\n };\n "post.task.completed": {\n event: TaskCompletedEvent;\n modify: never;\n result: void;\n };\n "post.task.failed": {\n event: TaskFailedEvent;\n modify: never;\n result: void;\n };\n "post.task.cancelled": {\n event: TaskEvent;\n modify: never;\n result: void;\n };\n "post.task.superseded": {\n event: TaskSupersededEvent;\n modify: never;\n result: void;\n };\n "post.task.progress": {\n event: TaskProgressEvent;\n modify: never;\n result: void;\n };\n "post.slack.message": {\n event: SlackMessageEvent;\n modify: never;\n result: void;\n };\n "post.chat.message": {\n event: ChatMessageEvent;\n modify: never;\n result: void;\n };\n "post.approval.resolved": {\n event: ApprovalResolvedEvent;\n modify: never;\n result: void;\n };\n "post.task.budgetRefused": {\n event: TaskBudgetRefusedEvent;\n modify: never;\n result: void;\n };\n "post.email.received": {\n event: EmailReceivedEvent;\n modify: never;\n result: void;\n };\n "post.kapso.message": {\n event: KapsoMessageEvent;\n modify: never;\n result: void;\n };\n "post.vcs.event": {\n event: VcsEvent;\n modify: never;\n result: void;\n };\n "post.tool.call": {\n event: ToolCallCompletedEvent;\n modify: never;\n result: void;\n };\n }\n export interface ExtensionApi<\n M extends ExtensionManifest = ExtensionManifest & {\n runtime: "api";\n },\n > {\n on<E extends keyof SwarmEventMap>(\n event: E,\n handler: (\n event: SwarmEventMap[E]["event"],\n ctx: CtxFor<M>,\n ) => Promise<SwarmEventMap[E]["result"]> | SwarmEventMap[E]["result"],\n opts?: {\n priority?: number;\n },\n ): void;\n }\n export type SwarmExtension<\n M extends ExtensionManifest = ExtensionManifest & {\n runtime: "api";\n },\n > = (api: ExtensionApi<M>) => void;\n export { block, modify } from "./contract-runtime";\n}\n';
4
+ '// biome-ignore-all lint/suspicious/noConfusingVoidType: Extension handlers may explicitly return no result.\ndeclare module "swarm-extension" {\n export type CreateTaskOptions = {\n key?: string | undefined;\n agentId?: string | null | undefined;\n creatorAgentId?: string | undefined;\n source?:\n | "workflow"\n | "schedule"\n | "slack"\n | "agentmail"\n | "mcp"\n | "api"\n | "ui"\n | "github"\n | "gitlab"\n | "azure-devops"\n | "bitbucket"\n | "system"\n | "linear"\n | "jira"\n | "comb"\n | "chat"\n | undefined;\n routingReason?:\n | "skill"\n | "continuity"\n | "overflow"\n | "human_pinned"\n | "reroute_fault"\n | undefined;\n routingSource?: "declared" | "engine_default" | undefined;\n routingNote?: string | undefined;\n taskType?: string | undefined;\n tags?: string[] | undefined;\n priority?: number | undefined;\n dependsOn?: string[] | undefined;\n offeredTo?: string | undefined;\n status?: "draft" | "backlog" | "unassigned" | undefined;\n slackChannelId?: string | undefined;\n slackThreadTs?: string | undefined;\n slackTriggerMessageTs?: string | undefined;\n slackUserId?: string | undefined;\n overrideSlackContext?: boolean | undefined;\n vcsProvider?: "github" | "gitlab" | "azure-devops" | "bitbucket" | undefined;\n vcsRepo?: string | undefined;\n vcsEventType?: string | undefined;\n vcsNumber?: number | undefined;\n vcsCommentId?: number | undefined;\n vcsAuthor?: string | undefined;\n vcsUrl?: string | undefined;\n vcsInstallationId?: number | undefined;\n vcsNodeId?: string | undefined;\n agentmailInboxId?: string | undefined;\n agentmailMessageId?: string | undefined;\n agentmailThreadId?: string | undefined;\n mentionMessageId?: string | undefined;\n mentionChannelId?: string | undefined;\n dir?: string | undefined;\n parentTaskId?: string | undefined;\n model?: string | undefined;\n modelTier?: "smol" | "regular" | "smart" | "ultra" | undefined;\n effort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;\n profile?: string | undefined;\n scheduleId?: string | undefined;\n workflowRunId?: string | undefined;\n workflowRunStepId?: string | undefined;\n sourceTaskId?: string | undefined;\n outputSchema?: Record<string, unknown> | undefined;\n inheritParentOutputSchema?: boolean | undefined;\n inheritParentRequester?: boolean | undefined;\n inheritParentRoutingAffinity?: boolean | undefined;\n inheritParentFollowUpConfig?: boolean | undefined;\n followUpConfig?:\n | {\n disabled?: boolean | undefined;\n onCompleted?: string | undefined;\n onFailed?: string | undefined;\n }\n | undefined;\n requestedByUserId?: string | undefined;\n contextKey?: string | undefined;\n bypassTrackerContextDedup?: boolean | undefined;\n routingAffinity?:\n | {\n capabilities: string[];\n sourceAgentId?: string | undefined;\n role?: string | undefined;\n harnessProvider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | "grok"\n | undefined;\n leadOnly?: boolean | undefined;\n }\n | undefined;\n };\n\n export type AgentTask = {\n id: string;\n key: string;\n agentId: string | null;\n task: string;\n status:\n | "draft"\n | "backlog"\n | "unassigned"\n | "offered"\n | "reviewing"\n | "pending"\n | "in_progress"\n | "paused"\n | "completed"\n | "failed"\n | "cancelled"\n | "superseded";\n source:\n | "workflow"\n | "schedule"\n | "slack"\n | "agentmail"\n | "mcp"\n | "api"\n | "ui"\n | "github"\n | "gitlab"\n | "azure-devops"\n | "bitbucket"\n | "system"\n | "linear"\n | "jira"\n | "comb"\n | "chat";\n tags: string[];\n priority: number;\n dependsOn: string[];\n createdAt: string;\n lastUpdatedAt: string;\n slackReplySent: boolean;\n wasPaused: boolean;\n creatorAgentId?: string | undefined;\n title?: string | undefined;\n routingReason?:\n | "skill"\n | "continuity"\n | "overflow"\n | "human_pinned"\n | "reroute_fault"\n | undefined;\n routingSource?: "declared" | "engine_default" | undefined;\n routingNote?: string | undefined;\n poolWakeAt?: string | undefined;\n taskType?: string | undefined;\n offeredTo?: string | undefined;\n offeredAt?: string | undefined;\n acceptedAt?: string | undefined;\n rejectionReason?: string | undefined;\n finishedAt?: string | undefined;\n notifiedAt?: string | undefined;\n failureReason?: string | undefined;\n output?: string | undefined;\n progress?: string | undefined;\n slackChannelId?: string | undefined;\n slackThreadTs?: string | undefined;\n slackTriggerMessageTs?: string | undefined;\n slackUserId?: string | undefined;\n slackProgressMessageTs?: string | undefined;\n slackTreeRootMessageTs?: string | undefined;\n vcsProvider?: "github" | "gitlab" | "azure-devops" | "bitbucket" | undefined;\n vcsRepo?: string | undefined;\n vcsEventType?: string | undefined;\n vcsNumber?: number | undefined;\n vcsCommentId?: number | undefined;\n vcsAuthor?: string | undefined;\n vcsUrl?: string | undefined;\n vcsInstallationId?: number | undefined;\n vcsNodeId?: string | undefined;\n agentmailInboxId?: string | undefined;\n agentmailMessageId?: string | undefined;\n agentmailThreadId?: string | undefined;\n mentionMessageId?: string | undefined;\n mentionChannelId?: string | undefined;\n dir?: string | undefined;\n parentTaskId?: string | undefined;\n claudeSessionId?: string | undefined;\n model?: string | undefined;\n modelTier?: "smol" | "regular" | "smart" | "ultra" | undefined;\n effort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;\n resolvedModel?: string | undefined;\n modelSource?: string | undefined;\n modelAlias?: string | undefined;\n resolvedEffort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;\n profile?: string | undefined;\n resolvedProfile?: string | undefined;\n scheduleId?: string | undefined;\n workflowRunId?: string | null | undefined;\n workflowRunStepId?: string | null | undefined;\n contextKey?: string | undefined;\n outputSchema?: Record<string, unknown> | undefined;\n followUpConfig?:\n | {\n disabled?: boolean | undefined;\n onCompleted?: string | undefined;\n onFailed?: string | undefined;\n }\n | undefined;\n deferredAt?: string | undefined;\n compactionCount?: number | undefined;\n peakContextPercent?: number | undefined;\n peakContextTokens?: number | undefined;\n contextWindowSize?: number | undefined;\n credentialKeySuffix?: string | undefined;\n credentialKeyType?: string | undefined;\n requestedByUserId?: string | undefined;\n swarmVersion?: string | undefined;\n provider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | "grok"\n | undefined;\n providerMeta?: Record<string, unknown> | undefined;\n harnessVariant?: string | undefined;\n harnessVariantMeta?: Record<string, unknown> | undefined;\n totalCostUsd?: number | undefined;\n routingAffinity?:\n | {\n capabilities: string[];\n sourceAgentId?: string | undefined;\n role?: string | undefined;\n harnessProvider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | "grok"\n | undefined;\n leadOnly?: boolean | undefined;\n }\n | undefined;\n routingAffinityInvalid?: boolean | undefined;\n };\n\n export type ActiveSession = {\n id: string;\n agentId: string;\n taskId: string | null;\n triggerType: string;\n inboxMessageId: string | null;\n taskDescription: string | null;\n runnerSessionId: string | null;\n providerSessionId: string | null;\n startedAt: string;\n lastHeartbeatAt: string;\n runtimeInstanceId?: string | null | undefined;\n };\n\n export type RequestInfo = {\n sessionId: string | undefined;\n agentId: string | undefined;\n runtimeInstanceId: string | undefined;\n sourceTaskId: string | undefined;\n contextKey: string | undefined;\n callOrigin: "mcp" | "extension" | "script-sdk";\n };\n\n import type { SwarmSdk } from "swarm-sdk";\n import type { z } from "zod";\n export type Runtime = "api" | "worker";\n export interface ExtensionScriptAsset {\n name: string;\n file: string;\n description: string;\n intent?: string;\n }\n export interface ExtensionScheduleAsset {\n name: string;\n description?: string;\n script: string;\n cronExpression?: string;\n intervalMs?: number;\n timezone?: string;\n args?: Record<string, unknown>;\n }\n export interface ExtensionWorkflowAsset {\n file: string;\n }\n export interface ExtensionSkillAsset {\n dir: string;\n }\n export interface ExtensionManifest {\n $schema?: string;\n name: string;\n description: string;\n version: string;\n runtime: Runtime;\n assets: {\n hooks: string;\n scripts?: readonly ExtensionScriptAsset[];\n schedules?: readonly ExtensionScheduleAsset[];\n workflows?: readonly ExtensionWorkflowAsset[];\n skills?: readonly ExtensionSkillAsset[];\n };\n homepage?: string;\n author?: string;\n }\n export interface HooksModule {\n default: SwarmExtension;\n config?: z.ZodTypeAny;\n }\n export interface ExtensionState {\n get<T = unknown>(key: string): Promise<T | null>;\n set<T>(key: string, value: T): Promise<void>;\n incr(key: string, by?: number): Promise<number>;\n del(key: string): Promise<void>;\n }\n export interface ExtensionLogger {\n debug(message: string, data?: unknown): void;\n info(message: string, data?: unknown): void;\n warn(message: string, data?: unknown): void;\n error(message: string, data?: unknown): void;\n }\n type ConfigFor<M extends ExtensionManifest> = M extends {\n config: infer C extends z.ZodTypeAny;\n }\n ? z.infer<C>\n : Record<string, unknown>;\n export interface ApiCtx<Config = Record<string, unknown>> {\n swarm: SwarmSdk;\n state: ExtensionState;\n config: Config;\n log: ExtensionLogger;\n signal: AbortSignal;\n event: {\n name: keyof SwarmEventMap;\n at: string;\n extension: {\n id: string;\n version: number;\n };\n };\n }\n export interface WorkerCtx<Config = Record<string, unknown>>\n extends Omit<ApiCtx<Config>, "swarm"> {\n swarm: SwarmSdk;\n worker: {\n agentId: string;\n taskId: string;\n harness: string;\n };\n }\n export type CtxFor<M extends ExtensionManifest> = M["runtime"] extends "api"\n ? ApiCtx<ConfigFor<M>>\n : WorkerCtx<ConfigFor<M>>;\n export type PreResult<Modify> =\n | void\n | {\n action: "continue";\n }\n | {\n action: "modify";\n data: Modify;\n }\n | {\n action: "block";\n reason: string;\n };\n export type TaskCreateOrigin =\n | "rest"\n | "app"\n | "mcp"\n | "slack"\n | "schedule"\n | "workflow"\n | "webhook"\n | "followUp"\n | `extension:${string}`;\n export interface TaskCreateEvent {\n options: CreateTaskOptions;\n description: string;\n origin: TaskCreateOrigin;\n requestInfo?: RequestInfo;\n }\n export type TaskCreateModify = Partial<\n Pick<\n CreateTaskOptions,\n | "agentId"\n | "creatorAgentId"\n | "source"\n | "taskType"\n | "tags"\n | "priority"\n | "dependsOn"\n | "offeredTo"\n | "vcsProvider"\n | "vcsRepo"\n | "vcsEventType"\n | "vcsNumber"\n | "vcsCommentId"\n | "vcsAuthor"\n | "vcsUrl"\n | "vcsInstallationId"\n | "vcsNodeId"\n | "agentmailInboxId"\n | "agentmailMessageId"\n | "agentmailThreadId"\n | "mentionMessageId"\n | "mentionChannelId"\n | "dir"\n | "model"\n | "modelTier"\n | "effort"\n | "outputSchema"\n | "followUpConfig"\n | "bypassTrackerContextDedup"\n >\n > & {\n description?: string;\n };\n export interface TaskFollowUpEvent {\n completedTask: AgentTask;\n status: "completed" | "failed";\n output?: string;\n failureReason?: string;\n workerAgentId: string;\n leadAgentId: string;\n summary: string;\n }\n export type TaskFollowUpModify = Partial<\n Pick<CreateTaskOptions, "agentId" | "priority" | "followUpConfig">\n > & {\n description?: string;\n };\n export interface SlackRouteEvent {\n channelId: string;\n userId: string;\n text: string;\n threadTs?: string;\n botMentioned: boolean;\n threadContext?: {\n channelId: string;\n threadTs: string;\n };\n }\n export interface SlackRouteModify {\n target:\n | {\n kind: "agent";\n agentId: string;\n }\n | {\n kind: "lead";\n }\n | {\n kind: "broadcast";\n };\n }\n /** A Chat SDK message after its thread buffer flushed, before routing. */\n export interface ChatRouteEvent {\n /** Adapter name, such as `telegram` or `slack`. */\n adapter: string;\n channelId: string;\n /** The Chat SDK thread id, prefixed with the adapter name. */\n threadId: string;\n /** The first buffered sender. */\n userId: string;\n userName?: string;\n /** The buffered messages, joined. */\n text: string;\n /** True for an @mention and for a reply to one of the bot\'s messages. */\n botMentioned: boolean;\n isDirectMessage: boolean;\n /** Platform chat type, such as Telegram `private`, `group`, `supergroup` or `channel`. */\n chatType?: string;\n /** Set for a Telegram supergroup with topics. */\n isForum?: boolean;\n /** A buffered message replies to one of the bot\'s own messages. */\n replyToBot: boolean;\n /** Set when earlier swarm tasks exist in this thread. */\n threadContext?: {\n adapter: string;\n threadId: string;\n };\n }\n export interface ChatRouteModify {\n target:\n | {\n kind: "agent";\n agentId: string;\n }\n | {\n kind: "lead";\n }\n | {\n kind: "broadcast";\n }\n | {\n kind: "workflow";\n workflowId: string;\n };\n }\n export type HeartbeatClassification = "no-session" | "stale-session" | "fresh-stalled";\n export type HeartbeatAction = "supersede-resume" | "fail" | "record";\n export interface HeartbeatRemediateEvent {\n task: AgentTask;\n session?: ActiveSession;\n classification: HeartbeatClassification;\n proposedAction: HeartbeatAction;\n reason: string;\n taskAgeMs: number;\n sessionHeartbeatAgeMs?: number;\n }\n export interface HeartbeatRemediateModify {\n proposedAction: HeartbeatAction;\n }\n export interface ToolCallEvent {\n tool: string;\n args: unknown;\n requestInfo: RequestInfo;\n }\n export interface ToolCallModify {\n args: unknown;\n }\n export interface TaskEvent {\n task: AgentTask;\n }\n export interface TaskCompletedEvent extends TaskEvent {\n output: string;\n }\n export interface TaskFailedEvent extends TaskEvent {\n failureReason: string;\n }\n export interface TaskSupersededEvent extends TaskEvent {\n supersededBy: string;\n }\n export interface TaskProgressEvent extends TaskEvent {\n progress: string;\n }\n export interface SlackMessageEvent {\n channelId: string;\n userId: string;\n text: string;\n threadTs?: string;\n taskId?: string;\n }\n /** A Chat SDK message the swarm received or sent. */\n export interface ChatMessageEvent {\n adapter: string;\n channelId: string;\n threadId: string;\n /** The sender, for an inbound message. */\n userId?: string;\n text: string;\n direction: "inbound" | "outbound";\n taskId?: string;\n messageId?: string;\n }\n /**\n * A person answered an approval request. Fires for workflow and standalone\n * requests. Timeouts and cancellations do not emit it today.\n */\n export interface ApprovalResolvedEvent {\n requestId: string;\n status: "approved" | "rejected" | "timeout" | "cancelled";\n responses: Record<string, unknown> | null;\n /** Set when a workflow human-in-the-loop step asked. Absent for a standalone request. */\n workflowRunId?: string;\n workflowRunStepId?: string;\n /** The task whose agent asked, for a standalone request. */\n sourceTaskId?: string;\n }\n /** A task was refused because a daily spend budget is used up. */\n export interface TaskBudgetRefusedEvent extends TaskEvent {\n /** The agent the task was refused for. */\n agentId: string;\n /** Which budget refused it. The matching spend and budget fields are set. */\n cause: "agent" | "global" | "user";\n agentSpendUsd?: number;\n agentBudgetUsd?: number;\n globalSpendUsd?: number;\n globalBudgetUsd?: number;\n userSpendUsd?: number;\n userBudgetUsd?: number;\n /** ISO 8601 time the daily budget resets. */\n resetAt: string;\n }\n /** An inbound AgentMail message. */\n export interface EmailReceivedEvent {\n inboxId: string;\n /** The From header as sent. */\n from: string;\n subject: string;\n /** The text body, or the HTML when there is no text, cut to 500 characters with `...` appended. */\n body: string;\n threadId: string;\n messageId: string;\n }\n /** An inbound Kapso (WhatsApp) message. */\n export interface KapsoMessageEvent {\n phoneNumberId: string;\n conversationId?: string;\n messageId: string;\n from?: string;\n /** Kapso message type, such as `text` or `image`. */\n type?: string;\n /** The text, or a placeholder naming the type for a non-text message. */\n text: string;\n }\n export type VcsProvider = "github" | "gitlab" | "azure-devops" | "bitbucket";\n /**\n * The provider object the event is about, as the provider names it. GitLab\n * calls a pull request a merge request, and a comment a `note`.\n */\n export type VcsEventKind =\n | "pull_request"\n | "merge_request"\n | "issue"\n | "issue_comment"\n | "note"\n | "pull_request_review"\n | "pipeline";\n /**\n * A webhook event from a connected code host. `action` is the provider\'s own\n * value: `opened`, `closed`, `synchronize`, `merge`, `created`, `commented`, or,\n * for a pipeline, its status such as `success` or `failed`. Fields a kind does\n * not carry are absent.\n */\n export interface VcsEvent {\n provider: VcsProvider;\n kind: VcsEventKind;\n action: string;\n /** `owner/name` on GitHub and GitLab, `workspace/repo_slug` on Bitbucket, the repository URL on Azure DevOps. */\n repo: string;\n /** The PR, merge request, or issue number. Absent for a pipeline outside a merge request. */\n number?: number;\n title?: string;\n body?: string | null;\n /** Login of the user behind the event. Set for pull requests, merge requests, and Azure DevOps comments. */\n author?: string;\n url?: string;\n merged?: boolean;\n changedFiles?: number;\n /** The review verdict, on a pull request review. */\n reviewState?: string;\n }\n export interface ToolCallCompletedEvent extends ToolCallEvent {\n result: unknown;\n durationMs: number;\n }\n export interface SwarmEventMap {\n "pre.task.create": {\n event: TaskCreateEvent;\n modify: TaskCreateModify;\n result: PreResult<TaskCreateModify>;\n };\n "pre.task.followUp": {\n event: TaskFollowUpEvent;\n modify: TaskFollowUpModify;\n result: PreResult<TaskFollowUpModify>;\n };\n "pre.slack.route": {\n event: SlackRouteEvent;\n modify: SlackRouteModify;\n result: PreResult<SlackRouteModify>;\n };\n "pre.chat.route": {\n event: ChatRouteEvent;\n modify: ChatRouteModify;\n result: PreResult<ChatRouteModify>;\n };\n "pre.heartbeat.remediate": {\n event: HeartbeatRemediateEvent;\n modify: HeartbeatRemediateModify;\n result: PreResult<HeartbeatRemediateModify>;\n };\n "pre.tool.call": {\n event: ToolCallEvent;\n modify: ToolCallModify;\n result: PreResult<ToolCallModify>;\n };\n "post.task.created": {\n event: TaskEvent;\n modify: never;\n result: void;\n };\n "post.task.completed": {\n event: TaskCompletedEvent;\n modify: never;\n result: void;\n };\n "post.task.failed": {\n event: TaskFailedEvent;\n modify: never;\n result: void;\n };\n "post.task.cancelled": {\n event: TaskEvent;\n modify: never;\n result: void;\n };\n "post.task.superseded": {\n event: TaskSupersededEvent;\n modify: never;\n result: void;\n };\n "post.task.progress": {\n event: TaskProgressEvent;\n modify: never;\n result: void;\n };\n "post.slack.message": {\n event: SlackMessageEvent;\n modify: never;\n result: void;\n };\n "post.chat.message": {\n event: ChatMessageEvent;\n modify: never;\n result: void;\n };\n "post.approval.resolved": {\n event: ApprovalResolvedEvent;\n modify: never;\n result: void;\n };\n "post.task.budgetRefused": {\n event: TaskBudgetRefusedEvent;\n modify: never;\n result: void;\n };\n "post.email.received": {\n event: EmailReceivedEvent;\n modify: never;\n result: void;\n };\n "post.kapso.message": {\n event: KapsoMessageEvent;\n modify: never;\n result: void;\n };\n "post.vcs.event": {\n event: VcsEvent;\n modify: never;\n result: void;\n };\n "post.tool.call": {\n event: ToolCallCompletedEvent;\n modify: never;\n result: void;\n };\n }\n export interface ExtensionApi<\n M extends ExtensionManifest = ExtensionManifest & {\n runtime: "api";\n },\n > {\n on<E extends keyof SwarmEventMap>(\n event: E,\n handler: (\n event: SwarmEventMap[E]["event"],\n ctx: CtxFor<M>,\n ) => Promise<SwarmEventMap[E]["result"]> | SwarmEventMap[E]["result"],\n opts?: {\n priority?: number;\n },\n ): void;\n }\n export type SwarmExtension<\n M extends ExtensionManifest = ExtensionManifest & {\n runtime: "api";\n },\n > = (api: ExtensionApi<M>) => void;\n export { block, modify } from "./contract-runtime";\n}\n';
@@ -337,7 +337,7 @@ export interface KapsoMessageEvent {
337
337
  text: string;
338
338
  }
339
339
 
340
- export type VcsProvider = "github" | "gitlab" | "azure-devops";
340
+ export type VcsProvider = "github" | "gitlab" | "azure-devops" | "bitbucket";
341
341
 
342
342
  /**
343
343
  * The provider object the event is about, as the provider names it. GitLab
@@ -362,7 +362,7 @@ export interface VcsEvent {
362
362
  provider: VcsProvider;
363
363
  kind: VcsEventKind;
364
364
  action: string;
365
- /** `owner/name` on GitHub and GitLab, the repository URL on Azure DevOps. */
365
+ /** `owner/name` on GitHub and GitLab, `workspace/repo_slug` on Bitbucket, the repository URL on Azure DevOps. */
366
366
  repo: string;
367
367
  /** The PR, merge request, or issue number. Absent for a pipeline outside a merge request. */
368
368
  number?: number;
@@ -301,6 +301,7 @@ const VCS_PROVIDERS: ReadonlySet<string> = new Set<VcsProvider>([
301
301
  "github",
302
302
  "gitlab",
303
303
  "azure-devops",
304
+ "bitbucket",
304
305
  ]);
305
306
  const VCS_KINDS: ReadonlySet<string> = new Set<VcsEventKind>([
306
307
  "pull_request",
@@ -307,7 +307,7 @@ export async function handlePullRequest(
307
307
  }
308
308
 
309
309
  // Find the related task
310
- const task = await findTaskByVcs(repository.full_name, pr.number);
310
+ const task = await findTaskByVcs(repository.full_name, pr.number, "github");
311
311
  if (!task) {
312
312
  console.log(`[GitHub] No active task found for PR #${pr.number} to cancel`);
313
313
  return { created: false };
@@ -337,7 +337,7 @@ export async function handlePullRequest(
337
337
  }
338
338
 
339
339
  // Check if there's an existing active task for this PR — skip duplicate review tasks
340
- const existingTask = await findTaskByVcs(repository.full_name, pr.number);
340
+ const existingTask = await findTaskByVcs(repository.full_name, pr.number, "github");
341
341
  if (existingTask) {
342
342
  console.log(
343
343
  `[GitHub] Skipping review task for PR #${pr.number} — active task ${existingTask.id} already exists`,
@@ -419,7 +419,7 @@ export async function handlePullRequest(
419
419
  }
420
420
 
421
421
  // Find the related task
422
- const task = await findTaskByVcs(repository.full_name, pr.number);
422
+ const task = await findTaskByVcs(repository.full_name, pr.number, "github");
423
423
  if (!task) {
424
424
  console.log(`[GitHub] No active task found for PR #${pr.number} to cancel`);
425
425
  return { created: false };
@@ -703,7 +703,7 @@ export async function handleIssue(
703
703
  }
704
704
 
705
705
  // Find the related task
706
- const task = await findTaskByVcs(repository.full_name, issue.number);
706
+ const task = await findTaskByVcs(repository.full_name, issue.number, "github");
707
707
  if (!task) {
708
708
  console.log(`[GitHub] No active task found for issue #${issue.number} to cancel`);
709
709
  return { created: false };
@@ -913,7 +913,7 @@ export async function handleComment(
913
913
 
914
914
  // Check if there's an existing task for this PR/Issue
915
915
  const existingTask = targetNumber
916
- ? await findTaskByVcs(repository.full_name, targetNumber)
916
+ ? await findTaskByVcs(repository.full_name, targetNumber, "github")
917
917
  : null;
918
918
 
919
919
  // Build task description
@@ -1365,7 +1365,7 @@ export async function handlePullRequestReview(
1365
1365
  }
1366
1366
 
1367
1367
  // Find any existing task for this PR
1368
- const existingTask = await findTaskByVcs(repository.full_name, pr.number);
1368
+ const existingTask = await findTaskByVcs(repository.full_name, pr.number, "github");
1369
1369
 
1370
1370
  // Only notify for PRs where bot is creator or already has a task
1371
1371
  const isBotCreator = isBotAssignee(pr.user.login);
@@ -53,8 +53,14 @@ export function getGitLabUrl(): string {
53
53
  return gitlabUrl;
54
54
  }
55
55
 
56
- /** Bot name for mention detection. */
57
- export const GITLAB_BOT_NAME = process.env.GITLAB_BOT_NAME ?? "agent-swarm-bot";
56
+ /**
57
+ * Bot name for mention detection. Read on every call: a stored swarm_config
58
+ * value reaches process.env after this module loads, and again on each config
59
+ * reload.
60
+ */
61
+ export function getGitLabBotName(): string {
62
+ return process.env.GITLAB_BOT_NAME || "agent-swarm-bot";
63
+ }
58
64
 
59
65
  /** Reset state for testing. */
60
66
  export function resetGitLab(): void {