@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
@@ -8,13 +8,21 @@
8
8
  * - Detects bot mentions
9
9
  */
10
10
 
11
- import { failTask, findTaskByVcs, getAllAgents, incrKv, upsertKv } from "../be/db";
11
+ import {
12
+ failTask,
13
+ findActiveTasksByVcs,
14
+ findTaskByVcs,
15
+ getAllAgents,
16
+ incrKv,
17
+ upsertKv,
18
+ } from "../be/db";
12
19
  import { renderIdentity, resolveIdentity } from "../be/identity";
13
20
  import { findOrCreateUserByEmail, findUserByExternalId, linkIdentity } from "../be/users";
14
21
  import { resolveTemplate } from "../prompts/resolver";
15
22
  import { gitlabContextKey } from "../tasks/context-key";
16
23
  import { createTaskWithSiblingAwareness } from "../tasks/sibling-awareness";
17
- import { GITLAB_BOT_NAME } from "./auth";
24
+ import type { AgentTask } from "../types";
25
+ import { getGitLabBotName } from "./auth";
18
26
  import { addGitLabNoteReaction, addGitLabReaction } from "./reactions";
19
27
  import type { GitLabUser } from "./types";
20
28
  // Side-effect import: registers all GitLab event templates in the in-memory registry
@@ -40,11 +48,37 @@ function isDuplicate(key: string): boolean {
40
48
 
41
49
  function detectMention(text: string | null | undefined): boolean {
42
50
  if (!text) return false;
43
- return new RegExp(`@${GITLAB_BOT_NAME}\\b`, "i").test(text);
51
+ return new RegExp(`@${getGitLabBotName()}\\b`, "i").test(text);
44
52
  }
45
53
 
46
54
  function extractMentionContext(text: string): string {
47
- return text.replace(new RegExp(`@${GITLAB_BOT_NAME}\\b`, "gi"), "").trim();
55
+ return text.replace(new RegExp(`@${getGitLabBotName()}\\b`, "gi"), "").trim();
56
+ }
57
+
58
+ // Legacy rows written before contextKey existed: scoped only on positive evidence.
59
+ const LEGACY_SCOPE = {
60
+ mr: {
61
+ taskTypes: new Set(["gitlab-mr", "gitlab-ci"]),
62
+ eventTypes: new Set(["merge_request", "note_on_mr", "pipeline"]),
63
+ },
64
+ issue: {
65
+ taskTypes: new Set(["gitlab-issue"]),
66
+ eventTypes: new Set(["issue", "note_on_issue"]),
67
+ },
68
+ };
69
+
70
+ /**
71
+ * GitLab issue and MR iids are separate per-project sequences, so a vcsNumber
72
+ * match alone hits both issue #N and MR !N. Match on the contextKey instead; a
73
+ * row without one counts only when its taskType or vcsEventType names the kind.
74
+ */
75
+ function isScopedTask(task: AgentTask, kind: "mr" | "issue", contextKey: string): boolean {
76
+ if (task.contextKey) return task.contextKey === contextKey;
77
+ const legacy = LEGACY_SCOPE[kind];
78
+ return (
79
+ (task.taskType !== undefined && legacy.taskTypes.has(task.taskType)) ||
80
+ (task.vcsEventType !== undefined && legacy.eventTypes.has(task.vcsEventType))
81
+ );
48
82
  }
49
83
 
50
84
  async function findLeadAgent() {
@@ -206,19 +240,25 @@ export async function handleMergeRequest(
206
240
 
207
241
  case "close":
208
242
  case "merge": {
209
- // Cancel existing tasks for this MR
210
- const existingTask = await findTaskByVcs(repo, mr.iid);
211
- if (existingTask) {
212
- const reason = action === "merge" ? "MR was merged" : "MR was closed";
213
- console.log(`[GitLab] Cancelling task ${existingTask.id} — ${reason}`);
214
- await failTask(existingTask.id, reason);
243
+ // Every active task, not only the newest: a note task is a child of the
244
+ // MR task, and failTask does not cascade up to the parent.
245
+ const reason = action === "merge" ? "MR was merged" : "MR was closed";
246
+ const mrContextKey = gitlabContextKey({
247
+ projectId: String(project.id),
248
+ kind: "mr",
249
+ iid: mr.iid,
250
+ });
251
+ const tasks = await findActiveTasksByVcs(repo, mr.iid, "gitlab");
252
+ for (const task of tasks.filter((t) => isScopedTask(t, "mr", mrContextKey))) {
253
+ console.log(`[GitLab] Cancelling task ${task.id} — ${reason}`);
254
+ await failTask(task.id, reason);
215
255
  }
216
256
  return { created: false };
217
257
  }
218
258
 
219
259
  case "update": {
220
260
  // Check if there's an active task for this MR — if so, notify about the update
221
- const task = await findTaskByVcs(repo, mr.iid);
261
+ const task = await findTaskByVcs(repo, mr.iid, "gitlab");
222
262
  if (task) {
223
263
  console.log(`[GitLab] MR #${mr.iid} updated, active task exists: ${task.id}`);
224
264
  // Don't create a new task — the worker will see the changes
@@ -262,7 +302,7 @@ export async function handleIssue(
262
302
  if (!hasMention) {
263
303
  // Check if bot is in assignees
264
304
  const isBotAssigned = event.assignees?.some(
265
- (a) => a.username.toLowerCase() === GITLAB_BOT_NAME.toLowerCase(),
305
+ (a) => a.username.toLowerCase() === getGitLabBotName().toLowerCase(),
266
306
  );
267
307
  if (!isBotAssigned) {
268
308
  console.log(`[GitLab] Issue opened without bot mention/assignment, skipping`);
@@ -318,7 +358,15 @@ export async function handleIssue(
318
358
  }
319
359
 
320
360
  case "close": {
321
- const existingTask = await findTaskByVcs(repo, issue.iid);
361
+ const issueContextKey = gitlabContextKey({
362
+ projectId: String(project.id),
363
+ kind: "issue",
364
+ iid: issue.iid,
365
+ });
366
+ // Newest issue-scoped task only; MR !N shares the iid but not the issue.
367
+ const existingTask = (await findActiveTasksByVcs(repo, issue.iid, "gitlab")).find((t) =>
368
+ isScopedTask(t, "issue", issueContextKey),
369
+ );
322
370
  if (existingTask) {
323
371
  console.log(`[GitLab] Cancelling task ${existingTask.id} — issue closed`);
324
372
  await failTask(existingTask.id, "Issue was closed");
@@ -375,7 +423,7 @@ export async function handleNote(event: NoteEvent): Promise<{ created: boolean;
375
423
  }
376
424
 
377
425
  // Check if there's already an active task for this entity
378
- const existingTask = targetNumber ? await findTaskByVcs(repo, targetNumber) : null;
426
+ const existingTask = targetNumber ? await findTaskByVcs(repo, targetNumber, "gitlab") : null;
379
427
 
380
428
  const existingTaskNote = existingTask
381
429
  ? `\n\n_Note: There's an active task (${existingTask.id}) for this ${entityLabel}._`
@@ -462,7 +510,7 @@ export async function handlePipeline(
462
510
  }
463
511
 
464
512
  // Only create task if there's already an active task for this MR
465
- const existingTask = await findTaskByVcs(repo, mrIid);
513
+ const existingTask = await findTaskByVcs(repo, mrIid, "gitlab");
466
514
  if (!existingTask) {
467
515
  return { created: false };
468
516
  }
@@ -1,6 +1,6 @@
1
1
  // GitLab Integration
2
2
  export {
3
- GITLAB_BOT_NAME,
3
+ getGitLabBotName,
4
4
  getGitLabToken,
5
5
  getGitLabUrl,
6
6
  initGitLab,
@@ -5,6 +5,7 @@ import { auditAssetKeys } from "../be/asset-key-audit";
5
5
  import { AssetKeyAuthorizationError, authorizeAssetKeyWrite } from "../be/asset-key-auth";
6
6
  import { resolveHttpAuditUserId } from "../be/audit-user";
7
7
  import {
8
+ AssetKeyMovesBlockedError,
8
9
  getDb,
9
10
  getDbClient,
10
11
  getRootTaskChain,
@@ -25,6 +26,7 @@ import {
25
26
  import { getRequestAuth } from "../utils/request-auth-context";
26
27
  import { requestPrincipal } from "./request-principal";
27
28
  import { route } from "./route-def";
29
+ import { canReadSession, hasSessionWrite, SESSION_READ_DENIED } from "./session-access";
28
30
  import { jsonError } from "./utils";
29
31
 
30
32
  const AssetKeyAuditIssueSchema = z.object({
@@ -184,7 +186,7 @@ const moveAssetRoute = route({
184
186
  },
185
187
  });
186
188
 
187
- async function canMutateTaskNamespace(
189
+ export async function canMutateTaskNamespace(
188
190
  task: { id: string; agentId: string | null; creatorAgentId?: string },
189
191
  myAgentId: string | undefined,
190
192
  req: IncomingMessage,
@@ -322,6 +324,16 @@ export async function handleAssets(
322
324
  jsonError(res, "Asset not found", 404);
323
325
  return true;
324
326
  }
327
+ if (!(await hasSessionWrite(req, myAgentId, task.id))) {
328
+ jsonError(
329
+ res,
330
+ (await canReadSession(req, myAgentId, task.id))
331
+ ? "You can view this session but not move it."
332
+ : SESSION_READ_DENIED,
333
+ 403,
334
+ );
335
+ return true;
336
+ }
325
337
  // Only the tasks checked here move: a subtask created after this read stays put.
326
338
  const tasks = parsed.body.cascade ? await getRootTaskChain(task.id) : [task];
327
339
  for (const target of tasks) {
@@ -382,7 +394,7 @@ export async function handleAssets(
382
394
  return true;
383
395
  }
384
396
  const message = error instanceof Error ? error.message : String(error);
385
- jsonError(res, message, message.includes("blocked until") ? 409 : 400);
397
+ jsonError(res, message, error instanceof AssetKeyMovesBlockedError ? 409 : 400);
386
398
  }
387
399
  return true;
388
400
  }
package/src/http/core.ts CHANGED
@@ -29,6 +29,12 @@ import {
29
29
  import { enqueueAdmissionRow } from "../be/rbac-audit";
30
30
  import { getUserGrant } from "../be/rbac-roles";
31
31
  import { syncTelemetryEnabled } from "../be/telemetry-enable";
32
+ import {
33
+ initBitbucket,
34
+ isBitbucketEnabled,
35
+ resetBitbucket,
36
+ resetBitbucketBotCache,
37
+ } from "../bitbucket";
32
38
  import { initGitHub, resetGitHub } from "../github";
33
39
  import { initGitLab, isGitLabEnabled, resetGitLab } from "../gitlab";
34
40
  import { restartChatSdkIfConfigChanged } from "../integrations/chat-sdk/runtime";
@@ -248,6 +254,12 @@ async function reloadGlobalConfigsAndIntegrationsInner(): Promise<ReloadConfigRe
248
254
  teardownAzureDevOpsOutbound();
249
255
  if (isAzureDevOpsEnabled()) initAzureDevOpsOutbound();
250
256
 
257
+ // Same reset-then-init: the webhook secret and bot account id are cached.
258
+ resetBitbucket();
259
+ resetBitbucketBotCache();
260
+ initBitbucket();
261
+ if (isBitbucketEnabled()) integrations.push("bitbucket");
262
+
251
263
  resetLinear();
252
264
  if (await initLinear()) integrations.push("linear");
253
265
 
package/src/http/index.ts CHANGED
@@ -33,6 +33,7 @@ import { loadSecretRegistry } from "../be/secret-registry";
33
33
  import { seedLegacyCapabilitiesConfig } from "../be/seed-capabilities";
34
34
  import { initApiTelemetry } from "../be/telemetry-enable";
35
35
  import { startWorkerNudgeListener } from "../be/worker-nudge-listener";
36
+ import { initBitbucket } from "../bitbucket";
36
37
  import {
37
38
  loadEnabledExtensions,
38
39
  setExtensionLoopbackBaseUrl,
@@ -798,6 +799,9 @@ httpServer
798
799
  initAzureDevOps();
799
800
  initAzureDevOpsOutbound();
800
801
 
802
+ // Initialize Bitbucket Cloud webhook handler (if configured)
803
+ initBitbucket();
804
+
801
805
  // Initialize AgentMail webhook handler (if configured)
802
806
  initAgentMail();
803
807
 
@@ -58,6 +58,7 @@ async function buildSignals(state: OnboardingState): Promise<OnboardingSignals>
58
58
  slack: integrations.slack === "configured",
59
59
  github: Boolean(process.env.GITHUB_TOKEN?.trim()) || integrations.github === "verified",
60
60
  gitlab: Boolean(process.env.GITLAB_TOKEN?.trim()),
61
+ bitbucket: Boolean(process.env.BITBUCKET_TOKEN?.trim()),
61
62
  linear: integrations.linear === "verified",
62
63
  jira: integrations.jira === "verified",
63
64
  },