@desplega.ai/agent-swarm 2.4.5 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/{acp-adapter-2wdkktv6.js → acp-adapter-11gp67nr.js} +8 -6
- package/dist/{actions-c40ebcm4.js → actions-8p2kze8j.js} +23 -21
- package/dist/{amp-adapter-wb67m95z.js → amp-adapter-z4qvhacj.js} +2 -2
- package/dist/{anthropic-messages-g6pqmqk4.js → anthropic-messages-txs190dd.js} +17 -20
- package/dist/{app-353vre8g.js → app-0qp0a2gk.js} +3 -3
- package/dist/{assistant-sj1njh23.js → assistant-jedd3ktm.js} +24 -22
- package/dist/{azure-openai-responses-9dbmj346.js → azure-openai-responses-9kfwhmn7.js} +18 -13
- package/dist/{boot-reembed-qdkvxeem.js → boot-reembed-4xwq5tg0.js} +1 -1
- package/dist/{boot-reembed-b9c3az3c.js → boot-reembed-n4wq5dd2.js} +1 -1
- package/dist/{boot-scrub-sweep-m3wh8eks.js → boot-scrub-sweep-69h90xcq.js} +4 -4
- package/dist/{boot-seeds-j2273s54.js → boot-seeds-3vn0m9sg.js} +4 -4
- package/dist/{claude-adapter-m7q0a085.js → claude-adapter-221mvad5.js} +8 -6
- package/dist/{claude-managed-adapter-5ptb6tzs.js → claude-managed-adapter-gt6pa35d.js} +2 -2
- package/dist/{claude-managed-setup-smrqk5j5.js → claude-managed-setup-c3hp36ph.js} +4 -4
- package/dist/{claude-sdk-session-38xnz21e.js → claude-sdk-session-8thjsk5e.js} +9012 -8928
- package/dist/{cli-b9fcxxev.js → cli-007cnhm1.js} +50 -4
- package/dist/{cli-j4rqdf2n.js → cli-03vpq45j.js} +2 -2
- package/dist/{cli-dk44dxec.js → cli-0y6f0ckq.js} +1 -1
- package/dist/{cli-kpw04va0.js → cli-0z3vjrpm.js} +1 -1
- package/dist/{cli-94gwyg7m.js → cli-179xcyky.js} +9 -9
- package/dist/{cli-3r8samv3.js → cli-1f0gp9vz.js} +3 -2
- package/dist/{cli-4zfqgjc5.js → cli-1pr672hz.js} +2 -2
- package/dist/{cli-0bqteszy.js → cli-2nf3b08t.js} +328 -25
- package/dist/{cli-43x64hv3.js → cli-36j4jnk3.js} +4 -4
- package/dist/{cli-k8g16gz3.js → cli-3qv8naq8.js} +115 -119
- package/dist/cli-3zwye9sn.js +1193 -0
- package/dist/{cli-60cgh1rv.js → cli-459fk97x.js} +7 -7
- package/dist/{cli-v8fjakwf.js → cli-4w24f7z3.js} +1 -1
- package/dist/{cli-n72rg53p.js → cli-5kzk3472.js} +812 -418
- package/dist/{cli-h7gc0b4r.js → cli-5m84zd2k.js} +55 -18
- package/dist/{cli-j99azg3g.js → cli-5rvg1ddk.js} +5 -5
- package/dist/{cli-dvkmp9bt.js → cli-6ctwrf1z.js} +20 -10
- package/dist/{cli-848hxdwj.js → cli-6rg2jn2y.js} +2 -1
- package/dist/{cli-fv5hepyy.js → cli-7bwtc6yx.js} +3 -3
- package/dist/{cli-ms85309d.js → cli-7g40g8hq.js} +11 -11
- package/dist/{cli-xpa64rek.js → cli-92mqenkc.js} +2362 -159
- package/dist/{cli-018r4jq6.js → cli-9ce2xw98.js} +8 -8
- package/dist/{cli-1syn2xy1.js → cli-bgdtv62r.js} +32 -18
- package/dist/{cli-wxbn3yfx.js → cli-cz5nmdxt.js} +2 -2
- package/dist/{cli-wt645v7q.js → cli-dabehxhp.js} +1 -1
- package/dist/{cli-vfha21c9.js → cli-e5bxnjps.js} +2 -2
- package/dist/{cli-wt0jf9hm.js → cli-fcc5qe3f.js} +553 -193
- package/dist/{cli-ftc1g5tj.js → cli-fes51ya2.js} +3 -3
- package/dist/{cli-3a45zcgm.js → cli-ftmq4nvk.js} +2 -2
- package/dist/{cli-37j04k05.js → cli-fy1jyyym.js} +13 -13
- package/dist/{cli-s95dknxh.js → cli-g1cw7xtt.js} +1 -1
- package/dist/{cli-74c1wpm0.js → cli-gpv60278.js} +1 -1
- package/dist/{cli-pemywhfq.js → cli-ha9rmwgq.js} +2 -1
- package/dist/{cli-g35m2xwm.js → cli-j1eghqfm.js} +2 -2
- package/dist/{cli-qfxc84gh.js → cli-jpxsrxcb.js} +1 -1
- package/dist/{cli-ejs3m1sx.js → cli-kxpfx2xr.js} +1 -1
- package/dist/{cli-p14m2cnp.js → cli-mbfj11fq.js} +1 -1
- package/dist/{cli-pnp2j5zg.js → cli-mmhj8vd7.js} +2 -2
- package/dist/{cli-xf234ws8.js → cli-n4c8e3s5.js} +2 -0
- package/dist/{cli-f01h25yt.js → cli-n6kmqngw.js} +2 -2
- package/dist/{cli-v0yrfmdh.js → cli-nnvjb17s.js} +3 -3
- package/dist/{cli-1dmcq2eh.js → cli-nzfnt2gs.js} +1 -1
- package/dist/{cli-625tb7aq.js → cli-p859hcc8.js} +2 -2
- package/dist/{cli-smvcw9z5.js → cli-pasyvjmm.js} +1 -1
- package/dist/cli-pkaqk57w.js +128 -0
- package/dist/{cli-8nyhf7za.js → cli-qqzmjxkf.js} +129 -105
- package/dist/{cli-9yqgm9nd.js → cli-r25qpaxt.js} +161 -63
- package/dist/{cli-eww120g8.js → cli-rh5smt8t.js} +18 -4
- package/dist/{cli-qwkcwjdn.js → cli-rycdaj0a.js} +1 -1
- package/dist/{cli-a92r1127.js → cli-s4sntwt4.js} +2 -2
- package/dist/{cli-be2161h1.js → cli-segs7hx9.js} +6 -6
- package/dist/{cli-36ckw0wx.js → cli-stxdrqs2.js} +2 -2
- package/dist/{cli-z7d29rw9.js → cli-sy8f9705.js} +4 -4
- package/dist/{cli-1m17dc9d.js → cli-ta8bd7th.js} +2 -2
- package/dist/{cli-st8aw1m6.js → cli-we0ra057.js} +4 -4
- package/dist/{cli-7c9qs530.js → cli-x21dqn18.js} +5 -5
- package/dist/{cli-1sp861s4.js → cli-x6vf4sad.js} +11 -11
- package/dist/{cli-d2mb5s8a.js → cli-x77gen2p.js} +680 -440
- package/dist/{cli-tw4p90jb.js → cli-xawhpgc9.js} +5 -5
- package/dist/{cli-f0g3pgvf.js → cli-xd4eqtr2.js} +2 -2
- package/dist/{cli-1f3qzw6y.js → cli-xt768r5m.js} +2 -2
- package/dist/{cli-cxxe61f6.js → cli-y4x8ww6s.js} +2 -2
- package/dist/{cli-bnes4z6b.js → cli-y9jvxfhk.js} +3 -3
- package/dist/{cli-qwhy2qma.js → cli-z63a269p.js} +2 -2
- package/dist/{cli-sm8rses9.js → cli-zfdp01hn.js} +8 -5
- package/dist/cli.js +29 -27
- package/dist/{cloudflare-workers-ai-system-one-ch2wxfcp.js → cloudflare-workers-ai-system-one-43v9qkjk.js} +7 -2
- package/dist/{codex-adapter-tn6k5mkg.js → codex-adapter-tcg1q3jk.js} +6 -4
- package/dist/{codex-login-m819c41r.js → codex-login-rn7c5gxt.js} +1 -1
- package/dist/{codex-session-runner-7vjt7jbw.js → codex-session-runner-xfx4wd9x.js} +7 -5
- package/dist/{commands-t7rz9146.js → commands-ew83nj70.js} +2 -2
- package/dist/{controller-m2jasma5.js → controller-gnq1k1mf.js} +4 -4
- package/dist/{controllers-connect-9ftpex99.js → controllers-connect-tw1dan9r.js} +25 -23
- package/dist/{cursor-adapter-mjv79e4z.js → cursor-adapter-yq5xgfcg.js} +1 -1
- package/dist/{db-6sfrn9g3.js → db-7gbc53fd.js} +14 -2
- package/dist/{db-rn673r06.js → db-t86xrnes.js} +3 -3
- package/dist/{devin-adapter-zgqadvnm.js → devin-adapter-4ycy4vrf.js} +1 -1
- package/dist/{dispatcher-c155xz0p.js → dispatcher-64bdyhps.js} +22 -20
- package/dist/{docker-fkgtr75t.js → docker-nfy2gc8t.js} +2 -2
- package/dist/{dsh-adapter-3mmszc1x.js → dsh-adapter-tvhc4k2d.js} +1 -1
- package/dist/{e2b-16d6ch39.js → e2b-9gkdhm3c.js} +2 -2
- package/dist/{e2b-zn0b4w5w.js → e2b-cjtf8k1z.js} +2 -2
- package/dist/{easter-egg-3d-5cgynaja.js → easter-egg-3d-e4qv8dxj.js} +1 -1
- package/dist/{event-bus-9vpk8gmq.js → event-bus-3z78ep5n.js} +1 -1
- package/dist/{execute-t4e6m3rw.js → execute-0xpz8950.js} +85 -23
- package/dist/{external-channel-35k6tkv8.js → external-channel-e9nw24zv.js} +2 -2
- package/dist/{google-generative-ai-bmq8gkf3.js → google-generative-ai-mk9vcpe1.js} +15 -15
- package/dist/{google-vertex-b1rvp52s.js → google-vertex-q580kz8k.js} +20 -20
- package/dist/{grok-adapter-tfrq7tg1.js → grok-adapter-v82srhrx.js} +9 -7
- package/dist/handlers-c9ajzhbn.js +41 -0
- package/dist/{heartbeat-dyg4npkp.js → heartbeat-2vqs1319.js} +25 -23
- package/dist/{hook-x26b31bg.js → hook-01nk13wx.js} +7 -5
- package/dist/{hook-drspbwpe.js → hook-jzpheegg.js} +9 -7
- package/dist/{http-pk972xyw.js → http-fc1k6ec8.js} +544 -76
- package/dist/index-07ef7nkm.js +42 -0
- package/dist/{index-g6tbb6ve.js → index-31ceyf42.js} +1 -1
- package/dist/index-7yts8n9s.js +43 -0
- package/dist/index-q3t40ryv.js +46 -0
- package/dist/{index-arytgj5q.js → index-sepja052.js} +1 -1
- package/dist/{index-jwxkkex2.js → index-zdycv3ja.js} +13 -11
- package/dist/{index-g216q6jr.js → index-zsyx51ap.js} +1 -4
- package/dist/{keepalive-7yrng7px.js → keepalive-5nh2rhmr.js} +4 -4
- package/dist/lead-aayq64jn.js +79 -0
- package/dist/{llama-cpp-classify-vv43gswy.js → llama-cpp-classify-ee7vmd7q.js} +4 -1
- package/dist/{maintenance-e6cemdqt.js → maintenance-hjhzdt3k.js} +1 -1
- package/dist/{mistral-conversations-1medfwv7.js → mistral-conversations-sd0xf1tn.js} +13 -13
- package/dist/{node-de6akczr.js → node-jzjj7r9x.js} +1 -1
- package/dist/{oauth-refresh-sweep-yw3xdbcj.js → oauth-refresh-sweep-y3n1knmd.js} +3 -3
- package/dist/{onboard-0a9y5yrc.js → onboard-1zq3m7db.js} +2 -2
- package/dist/{openai-codex-responses-de9pvs4d.js → openai-codex-responses-79s8xnbh.js} +29 -23
- package/dist/{openai-completions-mtqge3nf.js → openai-completions-tdbyts0x.js} +21 -20
- package/dist/{openai-decisions-ygk4kkxd.js → openai-decisions-bqhnjyfz.js} +2 -1
- package/dist/{openai-responses-dkyng71g.js → openai-responses-dm3t5vqp.js} +26 -17
- package/dist/{opencode-adapter-x4tqzhkh.js → opencode-adapter-e56086m1.js} +7 -5
- package/dist/{openrouter-images-wvv7camj.js → openrouter-images-ssttr1y4.js} +6 -3
- package/dist/{otel-impl-trjpkfb7.js → otel-impl-h9yyza47.js} +2 -2
- package/dist/{pi-messages-nhh1pkz2.js → pi-messages-3nf8bq1a.js} +6 -4
- package/dist/{pi-mono-adapter-mcfkn9vf.js → pi-mono-adapter-tzps8f38.js} +9 -37
- package/dist/{pricing-refresh-d2b5my0y.js → pricing-refresh-nevhat8h.js} +3 -3
- package/dist/{rbac-roles-nxh5ahwk.js → rbac-roles-4y6ngvzq.js} +1 -1
- package/dist/{rbac-roles-hey3yv9d.js → rbac-roles-exbg8xb6.js} +2 -2
- package/dist/{render-v2-rr3p2atg.js → render-v2-cfsh13z3.js} +3 -3
- package/dist/{resume-2efkf1s1.js → resume-5s2t0dbs.js} +10 -8
- package/dist/{runtime-xe3aqy4x.js → runtime-bt5pkpm1.js} +1 -1
- package/dist/{session-access-s2mttxpw.js → session-access-dnbyp3cn.js} +6 -4
- package/dist/{setup-vypma5yt.js → setup-1wj1y77j.js} +1 -1
- package/dist/{typesafe-system-one-2hgpayzy.js → typesafe-system-one-bre38hvs.js} +4 -2
- package/dist/{virtual-modules-4r3zkc20.js → virtual-modules-mnfbh5mr.js} +8 -2
- package/dist/{work-objects-rvhckdkp.js → work-objects-7mg6216g.js} +25 -23
- package/dist/worker-nwb789mg.js +79 -0
- package/dist/{x-y45mthwn.js → x-pbpezr0s.js} +2 -2
- package/openapi.json +785 -5
- package/package.json +9 -9
- package/src/assets/key.ts +17 -0
- package/src/azure-devops/handlers.ts +1 -1
- package/src/be/db/approvals.ts +18 -0
- package/src/be/db/session-moves.ts +164 -0
- package/src/be/db/session-tree.ts +384 -0
- package/src/be/db/tasks/read.ts +40 -4
- package/src/be/db/workflow-runs.ts +96 -0
- package/src/be/db.ts +80 -236
- package/src/be/onboarding.ts +3 -0
- package/src/be/skill-sync.ts +43 -2
- package/src/be/swarm-config-guard.ts +1 -0
- package/src/bitbucket/api.ts +81 -0
- package/src/bitbucket/auth.ts +64 -0
- package/src/bitbucket/handlers.ts +434 -0
- package/src/bitbucket/index.ts +28 -0
- package/src/bitbucket/templates.ts +134 -0
- package/src/bitbucket/types.ts +65 -0
- package/src/commands/runner.ts +55 -3
- package/src/e2b/env.ts +1 -0
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/extensions/contract.ts +2 -2
- package/src/extensions/post-bridge.ts +1 -0
- package/src/github/handlers.ts +6 -6
- package/src/gitlab/handlers.ts +5 -5
- package/src/http/assets.ts +14 -2
- package/src/http/core.ts +12 -0
- package/src/http/index.ts +4 -0
- package/src/http/onboarding.ts +1 -0
- package/src/http/sessions.ts +366 -12
- package/src/http/skills.ts +48 -1
- package/src/http/tasks.ts +1 -1
- package/src/http/users.ts +1 -0
- package/src/http/webhooks.ts +141 -0
- package/src/integrations/chat-sdk/adapters.ts +19 -3
- package/src/integrations/chat-sdk/facts.ts +30 -12
- package/src/integrations/chat-sdk/outbound.ts +38 -1
- package/src/providers/acp-targets.ts +1 -1
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/pi-mono-adapter.ts +5 -53
- package/src/scripts-runtime/types/swarm-extension.d.ts +6 -4
- package/src/slack/handlers.test.ts +158 -0
- package/src/slack/handlers.ts +19 -28
- package/src/tasks/context-key.ts +61 -1
- package/src/tests/bitbucket-auth.test.ts +156 -0
- package/src/tests/bitbucket-handlers.test.ts +425 -0
- package/src/tests/bitbucket-webhook.test.ts +220 -0
- package/src/tests/chat-sdk-inbound.test.ts +39 -0
- package/src/tests/chat-sdk-telegram-markdown.test.ts +92 -0
- package/src/tests/context-key.test.ts +50 -0
- package/src/tests/core-auth.test.ts +5 -0
- package/src/tests/db-task-read-contract.test.ts +7 -0
- package/src/tests/db-task-write-contract.test.ts +6 -0
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/fixtures/bitbucket/pullrequest-comment-created-inline.json +174 -0
- package/src/tests/fixtures/bitbucket/pullrequest-comment-created.json +170 -0
- package/src/tests/fixtures/bitbucket/pullrequest-created-mention.json +132 -0
- package/src/tests/fixtures/bitbucket/pullrequest-created-reviewer.json +140 -0
- package/src/tests/fixtures/bitbucket/pullrequest-fulfilled.json +134 -0
- package/src/tests/fixtures/bitbucket/pullrequest-rejected.json +133 -0
- package/src/tests/generate-mcp-docs.test.ts +101 -0
- package/src/tests/gitlab-handlers.test.ts +3 -3
- package/src/tests/gitlab-vcs-db.test.ts +4 -4
- package/src/tests/integration-disable-flags.test.ts +36 -0
- package/src/tests/mcp-tools.test.ts +1 -1
- package/src/tests/onboarding.test.ts +12 -0
- package/src/tests/pi-codemode.test.ts +8 -2
- package/src/tests/preload-env.test.ts +57 -0
- package/src/tests/preload.ts +21 -0
- package/src/tests/prompt-template-remaining.test.ts +38 -0
- package/src/tests/run-root-coverage.test.ts +39 -0
- package/src/tests/runner-bitbucket-vcs.test.ts +191 -0
- package/src/tests/runner-skills-refresh.test.ts +58 -0
- package/src/tests/secret-scrubber.test.ts +15 -0
- package/src/tests/sessions-move.test.ts +576 -0
- package/src/tests/sessions-tree.test.ts +493 -0
- package/src/tests/skill-files-http.test.ts +50 -0
- package/src/tests/skills-bundle.test.ts +99 -0
- package/src/tests/swarm-config-export-to-env.test.ts +2 -1
- package/src/tests/vcs-bitbucket.test.ts +91 -0
- package/src/tests/vcs-provider-isolation.test.ts +123 -0
- package/src/tests/vcs-provider.test.ts +16 -1
- package/src/tests/vcs-tracking.test.ts +3 -3
- package/src/tests/workflow-foreach-bodies.test.ts +637 -0
- package/src/tests/workflow-foreach-concurrency.test.ts +342 -0
- package/src/tests/workflow-foreach-retry.test.ts +537 -0
- package/src/tests/workflow-foreach.test.ts +44 -23
- package/src/tests/workflow-step-claims.test.ts +6 -6
- package/src/tests/workflow-tla-races.test.ts +2 -2
- package/src/tools/script-delete.ts +1 -1
- package/src/tools/workflows/create-workflow.ts +5 -3
- package/src/types.ts +3 -2
- package/src/utils/config-env-export.ts +1 -0
- package/src/utils/secret-scrubber.ts +4 -0
- package/src/utils/skills-refresh.ts +83 -43
- package/src/vcs/bitbucket.ts +58 -0
- package/src/vcs/index.ts +2 -0
- package/src/vcs/types.ts +2 -2
- package/src/workflows/approval-resolution.ts +4 -1
- package/src/workflows/checkpoint.ts +9 -1
- package/src/workflows/constants.ts +3 -0
- package/src/workflows/definition.ts +48 -17
- package/src/workflows/engine.ts +25 -15
- package/src/workflows/executors/foreach.ts +45 -99
- package/src/workflows/foreach-body.ts +146 -0
- package/src/workflows/foreach-driver.ts +552 -0
- package/src/workflows/foreach-join.ts +206 -7
- package/src/workflows/node-timeout.ts +21 -0
- package/src/workflows/recovery.ts +68 -3
- package/src/workflows/resume.ts +221 -43
- package/src/workflows/retry-poller.ts +39 -24
- package/src/workflows/step-input.ts +59 -0
- package/src/workflows/task-step-routing.ts +114 -56
- package/templates/skills/slack-interaction/content.md +5 -0
- package/templates/skills/work-on-task/SKILL.md +1 -1
- package/templates/skills/work-on-task/content.md +1 -1
- package/dist/cli-9hstj09h.js +0 -2657
- package/dist/cli-yw91rnmw.js +0 -13
- package/dist/handlers-7gw64dxw.js +0 -39
- package/dist/index-bgdyvcnv.js +0 -40
- package/dist/index-gabbcdn2.js +0 -43
- package/dist/index-tfb26zhy.js +0 -41
- package/dist/lead-7e02z839.js +0 -77
- 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;
|
package/src/commands/runner.ts
CHANGED
|
@@ -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
|
@@ -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;
|
package/src/github/handlers.ts
CHANGED
|
@@ -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);
|
package/src/gitlab/handlers.ts
CHANGED
|
@@ -207,7 +207,7 @@ export async function handleMergeRequest(
|
|
|
207
207
|
case "close":
|
|
208
208
|
case "merge": {
|
|
209
209
|
// Cancel existing tasks for this MR
|
|
210
|
-
const existingTask = await findTaskByVcs(repo, mr.iid);
|
|
210
|
+
const existingTask = await findTaskByVcs(repo, mr.iid, "gitlab");
|
|
211
211
|
if (existingTask) {
|
|
212
212
|
const reason = action === "merge" ? "MR was merged" : "MR was closed";
|
|
213
213
|
console.log(`[GitLab] Cancelling task ${existingTask.id} — ${reason}`);
|
|
@@ -218,7 +218,7 @@ export async function handleMergeRequest(
|
|
|
218
218
|
|
|
219
219
|
case "update": {
|
|
220
220
|
// Check if there's an active task for this MR — if so, notify about the update
|
|
221
|
-
const task = await findTaskByVcs(repo, mr.iid);
|
|
221
|
+
const task = await findTaskByVcs(repo, mr.iid, "gitlab");
|
|
222
222
|
if (task) {
|
|
223
223
|
console.log(`[GitLab] MR #${mr.iid} updated, active task exists: ${task.id}`);
|
|
224
224
|
// Don't create a new task — the worker will see the changes
|
|
@@ -318,7 +318,7 @@ export async function handleIssue(
|
|
|
318
318
|
}
|
|
319
319
|
|
|
320
320
|
case "close": {
|
|
321
|
-
const existingTask = await findTaskByVcs(repo, issue.iid);
|
|
321
|
+
const existingTask = await findTaskByVcs(repo, issue.iid, "gitlab");
|
|
322
322
|
if (existingTask) {
|
|
323
323
|
console.log(`[GitLab] Cancelling task ${existingTask.id} — issue closed`);
|
|
324
324
|
await failTask(existingTask.id, "Issue was closed");
|
|
@@ -375,7 +375,7 @@ export async function handleNote(event: NoteEvent): Promise<{ created: boolean;
|
|
|
375
375
|
}
|
|
376
376
|
|
|
377
377
|
// Check if there's already an active task for this entity
|
|
378
|
-
const existingTask = targetNumber ? await findTaskByVcs(repo, targetNumber) : null;
|
|
378
|
+
const existingTask = targetNumber ? await findTaskByVcs(repo, targetNumber, "gitlab") : null;
|
|
379
379
|
|
|
380
380
|
const existingTaskNote = existingTask
|
|
381
381
|
? `\n\n_Note: There's an active task (${existingTask.id}) for this ${entityLabel}._`
|
|
@@ -462,7 +462,7 @@ export async function handlePipeline(
|
|
|
462
462
|
}
|
|
463
463
|
|
|
464
464
|
// Only create task if there's already an active task for this MR
|
|
465
|
-
const existingTask = await findTaskByVcs(repo, mrIid);
|
|
465
|
+
const existingTask = await findTaskByVcs(repo, mrIid, "gitlab");
|
|
466
466
|
if (!existingTask) {
|
|
467
467
|
return { created: false };
|
|
468
468
|
}
|
package/src/http/assets.ts
CHANGED
|
@@ -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,
|
|
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
|
|