@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.
- package/README.md +4 -2
- package/dist/{acp-adapter-2wdkktv6.js → acp-adapter-7g6bpwbk.js} +8 -6
- package/dist/{actions-c40ebcm4.js → actions-w8xd014k.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-nndcvftq.js} +3 -3
- package/dist/{assistant-sj1njh23.js → assistant-hjmqyscx.js} +24 -22
- package/dist/{azure-openai-responses-9dbmj346.js → azure-openai-responses-9kfwhmn7.js} +18 -13
- package/dist/{boot-reembed-b9c3az3c.js → boot-reembed-r8rhf9h8.js} +1 -1
- package/dist/{boot-reembed-qdkvxeem.js → boot-reembed-vwcj2y5d.js} +1 -1
- package/dist/{boot-scrub-sweep-m3wh8eks.js → boot-scrub-sweep-fr9q36ne.js} +4 -4
- package/dist/{boot-seeds-j2273s54.js → boot-seeds-9jqwnegq.js} +4 -4
- package/dist/{claude-adapter-m7q0a085.js → claude-adapter-2f8b85df.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-05kat8rv.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-1sp861s4.js → cli-0jy85zz4.js} +11 -11
- package/dist/{cli-j99azg3g.js → cli-1dp1zj04.js} +5 -5
- package/dist/{cli-3r8samv3.js → cli-1f0gp9vz.js} +3 -2
- package/dist/{cli-94gwyg7m.js → cli-22rmcjkg.js} +9 -9
- package/dist/{cli-ms85309d.js → cli-2jg61wab.js} +11 -11
- package/dist/{cli-0bqteszy.js → cli-2nf3b08t.js} +328 -25
- package/dist/{cli-9yqgm9nd.js → cli-2wba1ac9.js} +161 -63
- package/dist/{cli-cxxe61f6.js → cli-3ee5z0q0.js} +2 -2
- package/dist/{cli-k8g16gz3.js → cli-3qv8naq8.js} +115 -119
- package/dist/{cli-60cgh1rv.js → cli-459fk97x.js} +7 -7
- package/dist/{cli-h7gc0b4r.js → cli-5m84zd2k.js} +55 -18
- package/dist/{cli-dvkmp9bt.js → cli-6ctwrf1z.js} +20 -10
- package/dist/{cli-848hxdwj.js → cli-6rg2jn2y.js} +2 -1
- package/dist/{cli-dk44dxec.js → cli-9mm5ade4.js} +1 -1
- package/dist/{cli-7c9qs530.js → cli-ajqhxtnz.js} +5 -5
- package/dist/{cli-be2161h1.js → cli-cah5detr.js} +6 -6
- package/dist/{cli-v8fjakwf.js → cli-cwyafhw1.js} +1 -1
- 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-37j04k05.js → cli-e9btqw4y.js} +13 -13
- package/dist/{cli-1syn2xy1.js → cli-eym3jg7w.js} +32 -18
- package/dist/{cli-ftc1g5tj.js → cli-fes51ya2.js} +3 -3
- package/dist/{cli-s95dknxh.js → cli-g1cw7xtt.js} +1 -1
- package/dist/{cli-74c1wpm0.js → cli-gpv60278.js} +1 -1
- package/dist/{cli-1f3qzw6y.js → cli-gwcf52gz.js} +2 -2
- package/dist/{cli-pemywhfq.js → cli-ha9rmwgq.js} +2 -1
- package/dist/{cli-v0yrfmdh.js → cli-hadv0725.js} +3 -3
- package/dist/{cli-g35m2xwm.js → cli-j1eghqfm.js} +2 -2
- package/dist/{cli-qfxc84gh.js → cli-jpxsrxcb.js} +1 -1
- package/dist/{cli-n72rg53p.js → cli-kcsd1ez8.js} +848 -426
- package/dist/{cli-ejs3m1sx.js → cli-kxpfx2xr.js} +1 -1
- package/dist/{cli-pnp2j5zg.js → cli-mmhj8vd7.js} +2 -2
- package/dist/{cli-st8aw1m6.js → cli-mq7kg1b1.js} +4 -4
- package/dist/{cli-bnes4z6b.js → cli-mz2ygeyq.js} +3 -3
- package/dist/{cli-xf234ws8.js → cli-n4c8e3s5.js} +2 -0
- package/dist/{cli-f01h25yt.js → cli-n6kmqngw.js} +2 -2
- package/dist/cli-nj12tn2c.js +1193 -0
- 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-xpa64rek.js → cli-pyy4c9ch.js} +2362 -159
- package/dist/{cli-wt0jf9hm.js → cli-q9pzwxvk.js} +553 -193
- package/dist/{cli-z7d29rw9.js → cli-qfjm4gvt.js} +4 -4
- package/dist/{cli-p14m2cnp.js → cli-qfm6my86.js} +1 -1
- package/dist/{cli-8nyhf7za.js → cli-qqzmjxkf.js} +129 -105
- package/dist/{cli-4zfqgjc5.js → cli-r9fy0ddc.js} +2 -2
- package/dist/{cli-eww120g8.js → cli-rh5smt8t.js} +18 -4
- package/dist/{cli-a92r1127.js → cli-rngde2jv.js} +2 -2
- package/dist/{cli-qwkcwjdn.js → cli-rycdaj0a.js} +1 -1
- package/dist/{cli-fv5hepyy.js → cli-sn1vbtg2.js} +3 -3
- package/dist/{cli-36ckw0wx.js → cli-stxdrqs2.js} +2 -2
- package/dist/{cli-1m17dc9d.js → cli-ta8bd7th.js} +2 -2
- package/dist/{cli-43x64hv3.js → cli-v2g93k4v.js} +4 -4
- package/dist/{cli-d2mb5s8a.js → cli-x77gen2p.js} +680 -440
- package/dist/{cli-3a45zcgm.js → cli-xc65x52q.js} +2 -2
- package/dist/{cli-f0g3pgvf.js → cli-xd4eqtr2.js} +2 -2
- package/dist/{cli-018r4jq6.js → cli-y3zyaee5.js} +8 -8
- package/dist/{cli-kpw04va0.js → cli-z2dv25mf.js} +1 -1
- package/dist/{cli-qwhy2qma.js → cli-z63a269p.js} +2 -2
- package/dist/{cli-sm8rses9.js → cli-zfdp01hn.js} +8 -5
- package/dist/{cli-tw4p90jb.js → cli-znvq0k3t.js} +5 -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-p4ptwar5.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-964c7dnk.js} +7 -5
- package/dist/{commands-t7rz9146.js → commands-mbvhbrcy.js} +2 -2
- package/dist/{controller-m2jasma5.js → controller-gnq1k1mf.js} +4 -4
- package/dist/{controllers-connect-9ftpex99.js → controllers-connect-6dkm71tg.js} +25 -23
- package/dist/{cursor-adapter-mjv79e4z.js → cursor-adapter-yq5xgfcg.js} +1 -1
- package/dist/{db-6sfrn9g3.js → db-88wcymxt.js} +14 -2
- package/dist/{db-rn673r06.js → db-af9y8nkf.js} +3 -3
- package/dist/{devin-adapter-zgqadvnm.js → devin-adapter-4ycy4vrf.js} +1 -1
- package/dist/{dispatcher-c155xz0p.js → dispatcher-606ydx5v.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-y8q5z8z2.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-39aha52t.js} +9 -7
- package/dist/handlers-rk9dqech.js +41 -0
- package/dist/{heartbeat-dyg4npkp.js → heartbeat-jfe9zfjr.js} +25 -23
- package/dist/{hook-drspbwpe.js → hook-b1mez1m8.js} +9 -7
- package/dist/{hook-x26b31bg.js → hook-ffevzed1.js} +7 -5
- package/dist/{http-pk972xyw.js → http-d5b44f1r.js} +544 -76
- package/dist/{index-g6tbb6ve.js → index-31ceyf42.js} +1 -1
- package/dist/index-4q3vj1yr.js +46 -0
- package/dist/{index-arytgj5q.js → index-5en23s5z.js} +1 -1
- package/dist/index-d2qeem97.js +42 -0
- package/dist/index-mj46rk9k.js +43 -0
- package/dist/{index-jwxkkex2.js → index-nq8hhv28.js} +13 -11
- package/dist/{index-g216q6jr.js → index-zsyx51ap.js} +1 -4
- package/dist/{keepalive-7yrng7px.js → keepalive-wsby1btq.js} +4 -4
- package/dist/lead-paa141j6.js +79 -0
- package/dist/{llama-cpp-classify-vv43gswy.js → llama-cpp-classify-ee7vmd7q.js} +4 -1
- package/dist/{maintenance-e6cemdqt.js → maintenance-vnshcyv9.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-d6sqn5np.js} +3 -3
- package/dist/{onboard-0a9y5yrc.js → onboard-nr4xhpzy.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-ytn9wyv9.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-pva04zee.js} +3 -3
- package/dist/{rbac-roles-nxh5ahwk.js → rbac-roles-7rc1q3g4.js} +1 -1
- package/dist/{rbac-roles-hey3yv9d.js → rbac-roles-ff1ffmec.js} +2 -2
- package/dist/{render-v2-rr3p2atg.js → render-v2-pyfsg9zk.js} +3 -3
- package/dist/{resume-2efkf1s1.js → resume-phj8xhqr.js} +10 -8
- package/dist/{runtime-xe3aqy4x.js → runtime-bt5pkpm1.js} +1 -1
- package/dist/{session-access-s2mttxpw.js → session-access-jzx2z9h5.js} +6 -4
- package/dist/{setup-vypma5yt.js → setup-rfg0f0sg.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-44z2yjg8.js} +25 -23
- package/dist/worker-zsfqzxhm.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/auth.ts +8 -2
- package/src/gitlab/handlers.ts +63 -15
- package/src/gitlab/index.ts +1 -1
- 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-auth.test.ts +13 -5
- package/src/tests/gitlab-handlers.test.ts +273 -25
- 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
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
initDb,
|
|
14
14
|
} from "../be/db";
|
|
15
15
|
import { findUserByExternalId, linkIdentity } from "../be/users";
|
|
16
|
-
import {
|
|
16
|
+
import { getGitLabBotName } from "../gitlab/auth";
|
|
17
17
|
import { handleIssue, handleMergeRequest, handleNote, handlePipeline } from "../gitlab/handlers";
|
|
18
18
|
import type { IssueEvent, MergeRequestEvent, NoteEvent, PipelineEvent } from "../gitlab/types";
|
|
19
19
|
|
|
@@ -37,7 +37,7 @@ function makeMREvent(overrides: Partial<MergeRequestEvent> = {}): MergeRequestEv
|
|
|
37
37
|
id: 100,
|
|
38
38
|
iid: 1,
|
|
39
39
|
title: "Test MR",
|
|
40
|
-
description: `@${
|
|
40
|
+
description: `@${getGitLabBotName()} please review`,
|
|
41
41
|
state: "opened",
|
|
42
42
|
action: "open",
|
|
43
43
|
source_branch: "feature",
|
|
@@ -66,7 +66,7 @@ function makeIssueEvent(overrides: Partial<IssueEvent> = {}): IssueEvent {
|
|
|
66
66
|
id: 200,
|
|
67
67
|
iid: 10,
|
|
68
68
|
title: "Test Issue",
|
|
69
|
-
description: `@${
|
|
69
|
+
description: `@${getGitLabBotName()} fix this`,
|
|
70
70
|
state: "opened",
|
|
71
71
|
action: "open",
|
|
72
72
|
url: "https://gitlab.com/group/project/-/issues/10",
|
|
@@ -90,7 +90,7 @@ function makeNoteEvent(overrides: Partial<NoteEvent> = {}): NoteEvent {
|
|
|
90
90
|
},
|
|
91
91
|
object_attributes: {
|
|
92
92
|
id: 300,
|
|
93
|
-
note: `@${
|
|
93
|
+
note: `@${getGitLabBotName()} can you help?`,
|
|
94
94
|
noteable_type: "MergeRequest",
|
|
95
95
|
noteable_id: 100,
|
|
96
96
|
url: "https://gitlab.com/group/project/-/merge_requests/1#note_300",
|
|
@@ -181,7 +181,7 @@ describe("handleMergeRequest", () => {
|
|
|
181
181
|
id: 101,
|
|
182
182
|
iid: 50,
|
|
183
183
|
title: "MR with mention",
|
|
184
|
-
description: `@${
|
|
184
|
+
description: `@${getGitLabBotName()} review this please`,
|
|
185
185
|
state: "opened",
|
|
186
186
|
action: "open",
|
|
187
187
|
source_branch: "feat-a",
|
|
@@ -240,7 +240,7 @@ describe("handleMergeRequest", () => {
|
|
|
240
240
|
agentId: "lead-gl-001",
|
|
241
241
|
});
|
|
242
242
|
|
|
243
|
-
const existing = await findTaskByVcs("group/project", 60);
|
|
243
|
+
const existing = await findTaskByVcs("group/project", 60, "gitlab");
|
|
244
244
|
expect(existing).not.toBeNull();
|
|
245
245
|
|
|
246
246
|
const event = makeMREvent({
|
|
@@ -297,18 +297,212 @@ describe("handleMergeRequest", () => {
|
|
|
297
297
|
const result = await handleMergeRequest(event);
|
|
298
298
|
expect(result.created).toBe(false);
|
|
299
299
|
|
|
300
|
-
const existing = await findTaskByVcs("group/project", 61);
|
|
300
|
+
const existing = await findTaskByVcs("group/project", 61, "gitlab");
|
|
301
301
|
// Should no longer be active (findTaskByVcs filters out completed/failed)
|
|
302
302
|
expect(existing).toBeNull();
|
|
303
303
|
});
|
|
304
304
|
|
|
305
|
+
test("a merge cancels every active task for the MR, not only the newest", async () => {
|
|
306
|
+
const mrTask = await createTaskExtended("[GitLab MR #62] Test", {
|
|
307
|
+
source: "gitlab",
|
|
308
|
+
vcsProvider: "gitlab",
|
|
309
|
+
vcsRepo: "group/project",
|
|
310
|
+
vcsEventType: "merge_request",
|
|
311
|
+
vcsNumber: 62,
|
|
312
|
+
agentId: "lead-gl-001",
|
|
313
|
+
});
|
|
314
|
+
const noteTask = await createTaskExtended("[GitLab MR #62] Comment", {
|
|
315
|
+
source: "gitlab",
|
|
316
|
+
vcsProvider: "gitlab",
|
|
317
|
+
vcsRepo: "group/project",
|
|
318
|
+
vcsEventType: "note_on_mr",
|
|
319
|
+
vcsNumber: 62,
|
|
320
|
+
agentId: "lead-gl-001",
|
|
321
|
+
parentTaskId: mrTask.id,
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
const event = makeMREvent({
|
|
325
|
+
object_attributes: {
|
|
326
|
+
id: 105,
|
|
327
|
+
iid: 62,
|
|
328
|
+
title: "MR to merge",
|
|
329
|
+
description: null,
|
|
330
|
+
state: "merged",
|
|
331
|
+
action: "merge",
|
|
332
|
+
source_branch: "feat-e",
|
|
333
|
+
target_branch: "main",
|
|
334
|
+
url: "https://gitlab.com/group/project/-/merge_requests/62",
|
|
335
|
+
last_commit: null,
|
|
336
|
+
author_id: 1,
|
|
337
|
+
},
|
|
338
|
+
});
|
|
339
|
+
await handleMergeRequest(event);
|
|
340
|
+
|
|
341
|
+
for (const id of [mrTask.id, noteTask.id]) {
|
|
342
|
+
const task = await getTaskById(id);
|
|
343
|
+
expect(task?.status).toBe("failed");
|
|
344
|
+
expect(task?.failureReason).toBe("MR was merged");
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
test("closing MR !5 leaves issue #5 and its notes active", async () => {
|
|
349
|
+
// GitLab issue and MR iids are separate sequences: issue #5 and MR !5 coexist.
|
|
350
|
+
const issue = await handleIssue(
|
|
351
|
+
makeIssueEvent({
|
|
352
|
+
object_attributes: {
|
|
353
|
+
id: 205,
|
|
354
|
+
iid: 5,
|
|
355
|
+
title: "Issue five",
|
|
356
|
+
description: `@${getGitLabBotName()} fix this`,
|
|
357
|
+
state: "opened",
|
|
358
|
+
action: "open",
|
|
359
|
+
url: "https://gitlab.com/group/project/-/issues/5",
|
|
360
|
+
author_id: 1,
|
|
361
|
+
},
|
|
362
|
+
}),
|
|
363
|
+
);
|
|
364
|
+
const issueNote = await handleNote(
|
|
365
|
+
makeNoteEvent({
|
|
366
|
+
object_attributes: {
|
|
367
|
+
id: 395,
|
|
368
|
+
note: `@${getGitLabBotName()} any update?`,
|
|
369
|
+
noteable_type: "Issue",
|
|
370
|
+
noteable_id: 205,
|
|
371
|
+
url: "https://gitlab.com/group/project/-/issues/5#note_395",
|
|
372
|
+
author_id: 1,
|
|
373
|
+
type: null,
|
|
374
|
+
},
|
|
375
|
+
merge_request: undefined,
|
|
376
|
+
issue: {
|
|
377
|
+
id: 205,
|
|
378
|
+
iid: 5,
|
|
379
|
+
title: "Issue five",
|
|
380
|
+
description: null,
|
|
381
|
+
state: "opened",
|
|
382
|
+
action: "open",
|
|
383
|
+
url: "https://gitlab.com/group/project/-/issues/5",
|
|
384
|
+
author_id: 1,
|
|
385
|
+
},
|
|
386
|
+
}),
|
|
387
|
+
);
|
|
388
|
+
const mr = await handleMergeRequest(
|
|
389
|
+
makeMREvent({
|
|
390
|
+
object_attributes: {
|
|
391
|
+
id: 155,
|
|
392
|
+
iid: 5,
|
|
393
|
+
title: "MR five",
|
|
394
|
+
description: `@${getGitLabBotName()} please review`,
|
|
395
|
+
state: "opened",
|
|
396
|
+
action: "open",
|
|
397
|
+
source_branch: "feat-five",
|
|
398
|
+
target_branch: "main",
|
|
399
|
+
url: "https://gitlab.com/group/project/-/merge_requests/5",
|
|
400
|
+
last_commit: null,
|
|
401
|
+
author_id: 1,
|
|
402
|
+
},
|
|
403
|
+
}),
|
|
404
|
+
);
|
|
405
|
+
const mrNote = await handleNote(
|
|
406
|
+
makeNoteEvent({
|
|
407
|
+
object_attributes: {
|
|
408
|
+
id: 396,
|
|
409
|
+
note: `@${getGitLabBotName()} looks good?`,
|
|
410
|
+
noteable_type: "MergeRequest",
|
|
411
|
+
noteable_id: 155,
|
|
412
|
+
url: "https://gitlab.com/group/project/-/merge_requests/5#note_396",
|
|
413
|
+
author_id: 1,
|
|
414
|
+
type: null,
|
|
415
|
+
},
|
|
416
|
+
merge_request: {
|
|
417
|
+
id: 155,
|
|
418
|
+
iid: 5,
|
|
419
|
+
title: "MR five",
|
|
420
|
+
description: null,
|
|
421
|
+
state: "opened",
|
|
422
|
+
action: "open",
|
|
423
|
+
source_branch: "feat-five",
|
|
424
|
+
target_branch: "main",
|
|
425
|
+
url: "https://gitlab.com/group/project/-/merge_requests/5",
|
|
426
|
+
last_commit: null,
|
|
427
|
+
author_id: 1,
|
|
428
|
+
},
|
|
429
|
+
}),
|
|
430
|
+
);
|
|
431
|
+
// A pre-contextKey issue row must not be swept up either.
|
|
432
|
+
const legacyIssue = await createTaskExtended("[GitLab Issue #5] Legacy", {
|
|
433
|
+
source: "gitlab",
|
|
434
|
+
vcsProvider: "gitlab",
|
|
435
|
+
vcsRepo: "group/project",
|
|
436
|
+
vcsEventType: "issue",
|
|
437
|
+
vcsNumber: 5,
|
|
438
|
+
agentId: "lead-gl-001",
|
|
439
|
+
});
|
|
440
|
+
for (const r of [issue, issueNote, mr, mrNote]) expect(r.created).toBe(true);
|
|
441
|
+
|
|
442
|
+
await handleMergeRequest(
|
|
443
|
+
makeMREvent({
|
|
444
|
+
object_attributes: {
|
|
445
|
+
id: 155,
|
|
446
|
+
iid: 5,
|
|
447
|
+
title: "MR five",
|
|
448
|
+
description: null,
|
|
449
|
+
state: "closed",
|
|
450
|
+
action: "close",
|
|
451
|
+
source_branch: "feat-five",
|
|
452
|
+
target_branch: "main",
|
|
453
|
+
url: "https://gitlab.com/group/project/-/merge_requests/5",
|
|
454
|
+
last_commit: null,
|
|
455
|
+
author_id: 1,
|
|
456
|
+
},
|
|
457
|
+
}),
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
for (const id of [mr.taskId!, mrNote.taskId!]) {
|
|
461
|
+
const task = await getTaskById(id);
|
|
462
|
+
expect(task?.status).toBe("failed");
|
|
463
|
+
expect(task?.failureReason).toBe("MR was closed");
|
|
464
|
+
}
|
|
465
|
+
for (const id of [issue.taskId!, issueNote.taskId!, legacyIssue.id]) {
|
|
466
|
+
const task = await getTaskById(id);
|
|
467
|
+
expect(task?.status).not.toBe("failed");
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
test("reads GITLAB_BOT_NAME at match time, so a config reload applies", async () => {
|
|
472
|
+
const mrEvent = (iid: number, description: string) =>
|
|
473
|
+
makeMREvent({
|
|
474
|
+
object_attributes: {
|
|
475
|
+
id: 1000 + iid,
|
|
476
|
+
iid,
|
|
477
|
+
title: "MR for renamed bot",
|
|
478
|
+
description,
|
|
479
|
+
state: "opened",
|
|
480
|
+
action: "open",
|
|
481
|
+
source_branch: "feat-renamed",
|
|
482
|
+
target_branch: "main",
|
|
483
|
+
url: `https://gitlab.com/group/project/-/merge_requests/${iid}`,
|
|
484
|
+
last_commit: null,
|
|
485
|
+
author_id: 1,
|
|
486
|
+
},
|
|
487
|
+
});
|
|
488
|
+
process.env.GITLAB_BOT_NAME = "renamed-bot";
|
|
489
|
+
try {
|
|
490
|
+
expect((await handleMergeRequest(mrEvent(63, "@renamed-bot review"))).created).toBe(true);
|
|
491
|
+
expect((await handleMergeRequest(mrEvent(64, "@agent-swarm-bot review"))).created).toBe(
|
|
492
|
+
false,
|
|
493
|
+
);
|
|
494
|
+
} finally {
|
|
495
|
+
delete process.env.GITLAB_BOT_NAME;
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
|
|
305
499
|
test("ignores update action when no active task", async () => {
|
|
306
500
|
const event = makeMREvent({
|
|
307
501
|
object_attributes: {
|
|
308
502
|
id: 105,
|
|
309
503
|
iid: 62,
|
|
310
504
|
title: "Updated MR",
|
|
311
|
-
description: `@${
|
|
505
|
+
description: `@${getGitLabBotName()} review`,
|
|
312
506
|
state: "opened",
|
|
313
507
|
action: "update",
|
|
314
508
|
source_branch: "feat-e",
|
|
@@ -329,7 +523,7 @@ describe("handleMergeRequest", () => {
|
|
|
329
523
|
id: 106,
|
|
330
524
|
iid: 70,
|
|
331
525
|
title: "Dedup MR",
|
|
332
|
-
description: `@${
|
|
526
|
+
description: `@${getGitLabBotName()} review`,
|
|
333
527
|
state: "opened",
|
|
334
528
|
action: "open",
|
|
335
529
|
source_branch: "feat-dedup",
|
|
@@ -360,7 +554,7 @@ describe("handleIssue", () => {
|
|
|
360
554
|
id: 201,
|
|
361
555
|
iid: 20,
|
|
362
556
|
title: "Issue with mention",
|
|
363
|
-
description: `@${
|
|
557
|
+
description: `@${getGitLabBotName()} implement this feature`,
|
|
364
558
|
state: "opened",
|
|
365
559
|
action: "open",
|
|
366
560
|
url: "https://gitlab.com/group/project/-/issues/20",
|
|
@@ -391,7 +585,7 @@ describe("handleIssue", () => {
|
|
|
391
585
|
url: "https://gitlab.com/group/project/-/issues/21",
|
|
392
586
|
author_id: 1,
|
|
393
587
|
},
|
|
394
|
-
assignees: [{ id: 99, name: "Bot", username:
|
|
588
|
+
assignees: [{ id: 99, name: "Bot", username: getGitLabBotName(), avatar_url: "" }],
|
|
395
589
|
});
|
|
396
590
|
|
|
397
591
|
const result = await handleIssue(event);
|
|
@@ -444,9 +638,63 @@ describe("handleIssue", () => {
|
|
|
444
638
|
expect(result.created).toBe(false);
|
|
445
639
|
|
|
446
640
|
// Task should no longer be active
|
|
447
|
-
const task = await findTaskByVcs("group/project", 30);
|
|
641
|
+
const task = await findTaskByVcs("group/project", 30, "gitlab");
|
|
448
642
|
expect(task).toBeNull();
|
|
449
643
|
});
|
|
644
|
+
|
|
645
|
+
test("closing issue #6 fails the issue task, not the newer MR !6 task", async () => {
|
|
646
|
+
const issue = await handleIssue(
|
|
647
|
+
makeIssueEvent({
|
|
648
|
+
object_attributes: {
|
|
649
|
+
id: 206,
|
|
650
|
+
iid: 6,
|
|
651
|
+
title: "Issue six",
|
|
652
|
+
description: `@${getGitLabBotName()} fix this`,
|
|
653
|
+
state: "opened",
|
|
654
|
+
action: "open",
|
|
655
|
+
url: "https://gitlab.com/group/project/-/issues/6",
|
|
656
|
+
author_id: 1,
|
|
657
|
+
},
|
|
658
|
+
}),
|
|
659
|
+
);
|
|
660
|
+
// Created second, so it is the newest row for vcsNumber 6.
|
|
661
|
+
const mr = await handleMergeRequest(
|
|
662
|
+
makeMREvent({
|
|
663
|
+
object_attributes: {
|
|
664
|
+
id: 156,
|
|
665
|
+
iid: 6,
|
|
666
|
+
title: "MR six",
|
|
667
|
+
description: `@${getGitLabBotName()} please review`,
|
|
668
|
+
state: "opened",
|
|
669
|
+
action: "open",
|
|
670
|
+
source_branch: "feat-six",
|
|
671
|
+
target_branch: "main",
|
|
672
|
+
url: "https://gitlab.com/group/project/-/merge_requests/6",
|
|
673
|
+
last_commit: null,
|
|
674
|
+
author_id: 1,
|
|
675
|
+
},
|
|
676
|
+
}),
|
|
677
|
+
);
|
|
678
|
+
expect(issue.created && mr.created).toBe(true);
|
|
679
|
+
|
|
680
|
+
await handleIssue(
|
|
681
|
+
makeIssueEvent({
|
|
682
|
+
object_attributes: {
|
|
683
|
+
id: 206,
|
|
684
|
+
iid: 6,
|
|
685
|
+
title: "Issue six",
|
|
686
|
+
description: null,
|
|
687
|
+
state: "closed",
|
|
688
|
+
action: "close",
|
|
689
|
+
url: "https://gitlab.com/group/project/-/issues/6",
|
|
690
|
+
author_id: 1,
|
|
691
|
+
},
|
|
692
|
+
}),
|
|
693
|
+
);
|
|
694
|
+
|
|
695
|
+
expect((await getTaskById(issue.taskId!))?.failureReason).toBe("Issue was closed");
|
|
696
|
+
expect((await getTaskById(mr.taskId!))?.status).not.toBe("failed");
|
|
697
|
+
});
|
|
450
698
|
});
|
|
451
699
|
|
|
452
700
|
// ═══════════════════════════════════════════════════════
|
|
@@ -458,7 +706,7 @@ describe("handleNote", () => {
|
|
|
458
706
|
const event = makeNoteEvent({
|
|
459
707
|
object_attributes: {
|
|
460
708
|
id: 301,
|
|
461
|
-
note: `@${
|
|
709
|
+
note: `@${getGitLabBotName()} please check this code`,
|
|
462
710
|
noteable_type: "MergeRequest",
|
|
463
711
|
noteable_id: 100,
|
|
464
712
|
url: "https://gitlab.com/group/project/-/merge_requests/1#note_301",
|
|
@@ -493,7 +741,7 @@ describe("handleNote", () => {
|
|
|
493
741
|
const event = makeNoteEvent({
|
|
494
742
|
object_attributes: {
|
|
495
743
|
id: 302,
|
|
496
|
-
note: `@${
|
|
744
|
+
note: `@${getGitLabBotName()} what do you think?`,
|
|
497
745
|
noteable_type: "Issue",
|
|
498
746
|
noteable_id: 200,
|
|
499
747
|
url: "https://gitlab.com/group/project/-/issues/40#note_302",
|
|
@@ -542,7 +790,7 @@ describe("handleNote", () => {
|
|
|
542
790
|
const event = makeNoteEvent({
|
|
543
791
|
object_attributes: {
|
|
544
792
|
id: 304,
|
|
545
|
-
note: `@${
|
|
793
|
+
note: `@${getGitLabBotName()} review this commit`,
|
|
546
794
|
noteable_type: "Commit",
|
|
547
795
|
noteable_id: 999,
|
|
548
796
|
url: "https://gitlab.com/group/project/-/commit/abc#note_304",
|
|
@@ -572,7 +820,7 @@ describe("handleNote", () => {
|
|
|
572
820
|
const event = makeNoteEvent({
|
|
573
821
|
object_attributes: {
|
|
574
822
|
id: 305,
|
|
575
|
-
note: `@${
|
|
823
|
+
note: `@${getGitLabBotName()} also fix the linting`,
|
|
576
824
|
noteable_type: "MergeRequest",
|
|
577
825
|
noteable_id: 100,
|
|
578
826
|
url: "https://gitlab.com/group/project/-/merge_requests/85#note_305",
|
|
@@ -742,7 +990,7 @@ describe("identity resolution — MR handler", () => {
|
|
|
742
990
|
id: 901,
|
|
743
991
|
iid: 901,
|
|
744
992
|
title: "Known MR",
|
|
745
|
-
description: `@${
|
|
993
|
+
description: `@${getGitLabBotName()} review`,
|
|
746
994
|
state: "opened",
|
|
747
995
|
action: "open",
|
|
748
996
|
source_branch: "feat-known",
|
|
@@ -779,7 +1027,7 @@ describe("identity resolution — MR handler", () => {
|
|
|
779
1027
|
id: 902,
|
|
780
1028
|
iid: 902,
|
|
781
1029
|
title: "Inline-email MR",
|
|
782
|
-
description: `@${
|
|
1030
|
+
description: `@${getGitLabBotName()} please`,
|
|
783
1031
|
state: "opened",
|
|
784
1032
|
action: "open",
|
|
785
1033
|
source_branch: "feat-inline",
|
|
@@ -816,7 +1064,7 @@ describe("identity resolution — MR handler", () => {
|
|
|
816
1064
|
id: 903,
|
|
817
1065
|
iid: 903,
|
|
818
1066
|
title: "Ghost MR",
|
|
819
|
-
description: `@${
|
|
1067
|
+
description: `@${getGitLabBotName()} ping`,
|
|
820
1068
|
state: "opened",
|
|
821
1069
|
action: "open",
|
|
822
1070
|
source_branch: "feat-ghost",
|
|
@@ -850,7 +1098,7 @@ describe("identity resolution — MR handler", () => {
|
|
|
850
1098
|
id: 910 + i,
|
|
851
1099
|
iid: 910 + i,
|
|
852
1100
|
title: `Ghost MR ${i}`,
|
|
853
|
-
description: `@${
|
|
1101
|
+
description: `@${getGitLabBotName()} ping`,
|
|
854
1102
|
state: "opened",
|
|
855
1103
|
action: "open",
|
|
856
1104
|
source_branch: `feat-g-${i}`,
|
|
@@ -879,7 +1127,7 @@ describe("identity resolution — MR handler", () => {
|
|
|
879
1127
|
id: 920,
|
|
880
1128
|
iid: 920,
|
|
881
1129
|
title: "Empty email MR",
|
|
882
|
-
description: `@${
|
|
1130
|
+
description: `@${getGitLabBotName()} review`,
|
|
883
1131
|
state: "opened",
|
|
884
1132
|
action: "open",
|
|
885
1133
|
source_branch: "feat-empty",
|
|
@@ -914,7 +1162,7 @@ describe("identity resolution — Issue handler", () => {
|
|
|
914
1162
|
id: 950,
|
|
915
1163
|
iid: 950,
|
|
916
1164
|
title: "Ghost issue",
|
|
917
|
-
description: `@${
|
|
1165
|
+
description: `@${getGitLabBotName()} fix`,
|
|
918
1166
|
state: "opened",
|
|
919
1167
|
action: "open",
|
|
920
1168
|
url: "https://gitlab.com/group/project/-/issues/950",
|
|
@@ -942,7 +1190,7 @@ describe("identity resolution — Note handler", () => {
|
|
|
942
1190
|
});
|
|
943
1191
|
|
|
944
1192
|
test("unknown user WITHOUT email → unmapped entry tagged 'note'", async () => {
|
|
945
|
-
const noteBody = `@${
|
|
1193
|
+
const noteBody = `@${getGitLabBotName()} can you look at this comment that is somewhat longer than usual to verify the slice(0,100) truncation downstream`;
|
|
946
1194
|
const event = makeNoteEvent({
|
|
947
1195
|
user: { id: 31, name: "Note Ghost", username: "noteghost", avatar_url: "" },
|
|
948
1196
|
object_attributes: {
|
|
@@ -976,7 +1224,7 @@ describe("identity resolution — Note handler", () => {
|
|
|
976
1224
|
expect(meta).not.toBeNull();
|
|
977
1225
|
expect(meta?.sampleEventType).toBe("note");
|
|
978
1226
|
expect((meta?.sampleContext as string).length).toBeLessThanOrEqual(100);
|
|
979
|
-
expect((meta?.sampleContext as string).startsWith(`@${
|
|
1227
|
+
expect((meta?.sampleContext as string).startsWith(`@${getGitLabBotName()}`)).toBe(true);
|
|
980
1228
|
expect(await getUnmappedCount("noteghost")).toBe(1);
|
|
981
1229
|
|
|
982
1230
|
// The dead-coded `_requestedByUserId` is now wired: undefined for an
|
|
@@ -996,7 +1244,7 @@ describe("identity resolution — Note handler", () => {
|
|
|
996
1244
|
user: { id: 32, name: "Known Commenter", username: "knowncommenter", avatar_url: "" },
|
|
997
1245
|
object_attributes: {
|
|
998
1246
|
id: 961,
|
|
999
|
-
note: `@${
|
|
1247
|
+
note: `@${getGitLabBotName()} please take a look`,
|
|
1000
1248
|
noteable_type: "MergeRequest",
|
|
1001
1249
|
noteable_id: 101,
|
|
1002
1250
|
url: "https://gitlab.com/group/project/-/merge_requests/2#note_961",
|
|
@@ -100,7 +100,7 @@ describe("findTaskByVcs", () => {
|
|
|
100
100
|
agentId: "vcs-lead-001",
|
|
101
101
|
});
|
|
102
102
|
|
|
103
|
-
const found = await findTaskByVcs("findme/gh-repo", 100);
|
|
103
|
+
const found = await findTaskByVcs("findme/gh-repo", 100, "github");
|
|
104
104
|
expect(found).not.toBeNull();
|
|
105
105
|
expect(found?.vcsProvider).toBe("github");
|
|
106
106
|
});
|
|
@@ -114,7 +114,7 @@ describe("findTaskByVcs", () => {
|
|
|
114
114
|
agentId: "vcs-lead-001",
|
|
115
115
|
});
|
|
116
116
|
|
|
117
|
-
const found = await findTaskByVcs("findme/gl-project", 200);
|
|
117
|
+
const found = await findTaskByVcs("findme/gl-project", 200, "gitlab");
|
|
118
118
|
expect(found).not.toBeNull();
|
|
119
119
|
expect(found?.vcsProvider).toBe("gitlab");
|
|
120
120
|
});
|
|
@@ -133,12 +133,12 @@ describe("findTaskByVcs", () => {
|
|
|
133
133
|
await db.startTask(task.id);
|
|
134
134
|
await db.completeTask(task.id, "Done");
|
|
135
135
|
|
|
136
|
-
const found = await findTaskByVcs("findme/completed", 300);
|
|
136
|
+
const found = await findTaskByVcs("findme/completed", 300, "gitlab");
|
|
137
137
|
expect(found).toBeNull();
|
|
138
138
|
});
|
|
139
139
|
|
|
140
140
|
test("returns null for non-existent repo/number", async () => {
|
|
141
|
-
const found = await findTaskByVcs("nonexistent/repo", 9999);
|
|
141
|
+
const found = await findTaskByVcs("nonexistent/repo", 9999, "github");
|
|
142
142
|
expect(found).toBeNull();
|
|
143
143
|
});
|
|
144
144
|
});
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
14
14
|
import { initAgentMail, isAgentMailEnabled, resetAgentMail } from "../agentmail/app";
|
|
15
|
+
import { validateConfigValue } from "../be/swarm-config-guard";
|
|
16
|
+
import { isBitbucketEnabled, resetBitbucket } from "../bitbucket/auth";
|
|
15
17
|
import { initGitHub, isGitHubEnabled, resetGitHub } from "../github/app";
|
|
16
18
|
import { isJiraEnabled, resetJira } from "../jira/app";
|
|
17
19
|
import { isLinearEnabled, resetLinear } from "../linear/app";
|
|
@@ -28,6 +30,8 @@ const ENV_KEYS = [
|
|
|
28
30
|
"LINEAR_ENABLED",
|
|
29
31
|
"AGENTMAIL_DISABLE",
|
|
30
32
|
"AGENTMAIL_WEBHOOK_SECRET",
|
|
33
|
+
"BITBUCKET_DISABLE",
|
|
34
|
+
"BITBUCKET_WEBHOOK_SECRET",
|
|
31
35
|
] as const;
|
|
32
36
|
const originalEnv = new Map(ENV_KEYS.map((key) => [key, process.env[key]]));
|
|
33
37
|
|
|
@@ -45,6 +49,7 @@ afterEach(() => {
|
|
|
45
49
|
resetAgentMail();
|
|
46
50
|
resetJira();
|
|
47
51
|
resetLinear();
|
|
52
|
+
resetBitbucket();
|
|
48
53
|
for (const key of ENV_KEYS) {
|
|
49
54
|
const value = originalEnv.get(key);
|
|
50
55
|
if (value === undefined) delete process.env[key];
|
|
@@ -185,6 +190,37 @@ describe("AgentMail AGENTMAIL_DISABLE", () => {
|
|
|
185
190
|
});
|
|
186
191
|
});
|
|
187
192
|
|
|
193
|
+
describe("Bitbucket BITBUCKET_DISABLE", () => {
|
|
194
|
+
test("every truthy spelling disables the integration", () => {
|
|
195
|
+
process.env.BITBUCKET_WEBHOOK_SECRET = "secret";
|
|
196
|
+
for (const spelling of TRUTHY_SPELLINGS) {
|
|
197
|
+
process.env.BITBUCKET_DISABLE = spelling;
|
|
198
|
+
expect(isBitbucketEnabled()).toBe(false);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test("non-disabling values keep the integration enabled", () => {
|
|
203
|
+
process.env.BITBUCKET_WEBHOOK_SECRET = "secret";
|
|
204
|
+
for (const value of NON_DISABLING) {
|
|
205
|
+
if (value === undefined) delete process.env.BITBUCKET_DISABLE;
|
|
206
|
+
else process.env.BITBUCKET_DISABLE = value;
|
|
207
|
+
expect(isBitbucketEnabled()).toBe(true);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test("stays disabled without a webhook secret", () => {
|
|
212
|
+
expect(isBitbucketEnabled()).toBe(false);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
test("the config guard validates BITBUCKET_DISABLE as a boolean like GITLAB_DISABLE", () => {
|
|
216
|
+
for (const key of ["BITBUCKET_DISABLE", "GITLAB_DISABLE"]) {
|
|
217
|
+
expect(validateConfigValue(key, "true")).toBeNull();
|
|
218
|
+
expect(validateConfigValue(key, "false")).toBeNull();
|
|
219
|
+
expect(validateConfigValue(key, "maybe")).not.toBeNull();
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
188
224
|
describe("Slack SLACK_DISABLE", () => {
|
|
189
225
|
test("every truthy spelling reports disabled", () => {
|
|
190
226
|
for (const spelling of TRUTHY_SPELLINGS) {
|
|
@@ -52,7 +52,7 @@ describe("script MCP tools", () => {
|
|
|
52
52
|
"script-upsert":
|
|
53
53
|
'Typecheck and persist a TypeScript script to the swarm catalog under your agent scope (or global if you\'re a lead). Import `ScriptContext` from "swarm-sdk" for a real context type. Other agents and workflow nodes will be able to find and run it. For local-only scripts, use code-mode `save`.',
|
|
54
54
|
"script-delete":
|
|
55
|
-
"
|
|
55
|
+
"Permanently remove a swarm-shared script and all its versions from the catalog. This cannot be undone.",
|
|
56
56
|
"script-query-types":
|
|
57
57
|
// Updated for the frozen SwarmToolResult contract refactor: `name` is
|
|
58
58
|
// now optional — omit it to get the swarm-wide type surface instead
|
|
@@ -34,6 +34,7 @@ const ENV_KEYS = [
|
|
|
34
34
|
"EMBEDDING_MODEL",
|
|
35
35
|
"GITHUB_TOKEN",
|
|
36
36
|
"GITLAB_TOKEN",
|
|
37
|
+
"BITBUCKET_TOKEN",
|
|
37
38
|
"SLACK_BOT_TOKEN",
|
|
38
39
|
"SLACK_APP_TOKEN",
|
|
39
40
|
"SLACK_MODE",
|
|
@@ -380,6 +381,17 @@ describe("onboarding state", () => {
|
|
|
380
381
|
expect(body.state.steps.integrations).toMatchObject({ status: "done", method: "github" });
|
|
381
382
|
});
|
|
382
383
|
|
|
384
|
+
test("GET derives the Bitbucket integration from BITBUCKET_TOKEN", async () => {
|
|
385
|
+
process.env.BITBUCKET_TOKEN = "example-bitbucket-token";
|
|
386
|
+
const body = (await (await request("/api/onboarding")).json()) as {
|
|
387
|
+
state: OnboardingState;
|
|
388
|
+
signals: { integrations: Record<string, boolean> };
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
expect(body.signals.integrations.bitbucket).toBe(true);
|
|
392
|
+
expect(body.state.steps.integrations).toMatchObject({ status: "done", method: "bitbucket" });
|
|
393
|
+
});
|
|
394
|
+
|
|
383
395
|
test("the selected first task completes onboarding after that task completes", async () => {
|
|
384
396
|
// Onboarding starts before the first task exists (the task alone would mark an existing install).
|
|
385
397
|
await request("/api/onboarding");
|
|
@@ -340,8 +340,14 @@ describe("bounded codemode", () => {
|
|
|
340
340
|
undefined,
|
|
341
341
|
fakeCtx().ctx,
|
|
342
342
|
);
|
|
343
|
-
|
|
344
|
-
expect(
|
|
343
|
+
const elapsed = Date.now() - started;
|
|
344
|
+
expect(elapsed).toBeGreaterThanOrEqual(250);
|
|
345
|
+
expect(elapsed).toBeLessThan(5_000);
|
|
346
|
+
// pi 1.4 queues the script for a worker; our deadline ends the wait.
|
|
347
|
+
expect(textOf(result)).toContain(
|
|
348
|
+
"Script aborted: Codemode script exceeded its 300 ms deadline",
|
|
349
|
+
);
|
|
350
|
+
expect(textOf(result)).toContain("The script did not start.");
|
|
345
351
|
} finally {
|
|
346
352
|
holders.abort(new Error("test done"));
|
|
347
353
|
await Promise.all(holding);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { expect, test } from "bun:test";
|
|
2
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { CHILD_PROCESS_TEST_BUDGET_MS, expectChildOk, runChild } from "./test-proc";
|
|
6
|
+
|
|
7
|
+
test(
|
|
8
|
+
"preload clears inherited worker configuration before test files load",
|
|
9
|
+
async () => {
|
|
10
|
+
const directory = await mkdtemp(join(tmpdir(), "swarm-preload-env-"));
|
|
11
|
+
const fixture = join(directory, "worker-env.test.ts");
|
|
12
|
+
const keys = [
|
|
13
|
+
"SLACK_RENDER_V2",
|
|
14
|
+
"SLACK_STATUS_ICON_COMPLETED",
|
|
15
|
+
"SLACK_FUTURE_SETTING",
|
|
16
|
+
"COMB_ENABLED",
|
|
17
|
+
"APP_URL",
|
|
18
|
+
"AGENT_FS_API_URL",
|
|
19
|
+
"AGENT_FS_LIVE_URL",
|
|
20
|
+
"AGENT_FS_DEFAULT_ORG_ID",
|
|
21
|
+
"AGENT_FS_DEFAULT_DRIVE_ID",
|
|
22
|
+
"SWARM_ORG_NAME",
|
|
23
|
+
"SWARM_ORG_WEBSITE",
|
|
24
|
+
];
|
|
25
|
+
try {
|
|
26
|
+
await Bun.write(
|
|
27
|
+
fixture,
|
|
28
|
+
`import { expect, test } from "bun:test";
|
|
29
|
+
const inherited = ${JSON.stringify(keys)}.filter(key => process.env[key] !== undefined);
|
|
30
|
+
test("worker defaults are cleared before module evaluation", () => {
|
|
31
|
+
expect(inherited).toEqual([]);
|
|
32
|
+
expect(process.env.PRELOAD_ENV_CONTROL).toBe("preserved");
|
|
33
|
+
process.env.SLACK_STATUS_ICON_COMPLETED = "test-icon";
|
|
34
|
+
});
|
|
35
|
+
test("suite configuration survives between tests", () => {
|
|
36
|
+
expect(process.env.SLACK_STATUS_ICON_COMPLETED).toBe("test-icon");
|
|
37
|
+
});
|
|
38
|
+
`,
|
|
39
|
+
);
|
|
40
|
+
const result = expectChildOk(
|
|
41
|
+
await runChild([process.execPath, "test", fixture], {
|
|
42
|
+
cwd: join(import.meta.dir, "../.."),
|
|
43
|
+
env: {
|
|
44
|
+
...process.env,
|
|
45
|
+
...Object.fromEntries(keys.map((key) => [key, "inherited-worker-setting"])),
|
|
46
|
+
PRELOAD_ENV_CONTROL: "preserved",
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
49
|
+
"test runner with inherited worker env",
|
|
50
|
+
);
|
|
51
|
+
expect(result.stderr).toContain("2 pass");
|
|
52
|
+
} finally {
|
|
53
|
+
await rm(directory, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
CHILD_PROCESS_TEST_BUDGET_MS,
|
|
57
|
+
);
|