@desplega.ai/agent-swarm 1.173.0 → 2.1.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 +1 -1
- package/dist/{acp-adapter-ccm9xrep.js → acp-adapter-kr4abrsk.js} +17 -16
- package/dist/{actions-sgeyv08k.js → actions-eh4g6w2r.js} +39 -34
- package/dist/{amp-adapter-gpxp3kc9.js → amp-adapter-7h7wdt8q.js} +8 -7
- package/dist/{app-km9qnv2f.js → app-7k8s9w5p.js} +18 -14
- package/dist/{assistant-5r8tcvvd.js → assistant-wswt2y7p.js} +40 -35
- package/dist/{boot-reembed-16rv9843.js → boot-reembed-9apm9qw6.js} +10 -9
- package/dist/{boot-reembed-swwzdgd7.js → boot-reembed-whzbdthj.js} +10 -9
- package/dist/{boot-scrub-sweep-zkr6vkqb.js → boot-scrub-sweep-ndzmvmgt.js} +11 -10
- package/dist/{boot-seeds-d8sp49t2.js → boot-seeds-e9sta0yt.js} +16 -13
- package/dist/{claude-adapter-yzzzh8jp.js → claude-adapter-4mqd3r6r.js} +19 -18
- package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-9wswb52m.js} +7 -5
- package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-tpe1effx.js} +6 -4
- package/dist/{claude-sdk-session-4whxere4.js → claude-sdk-session-q49ghmh9.js} +12402 -11850
- package/dist/{cli-ne7smj1b.js → cli-01xvj1rq.js} +10 -10
- package/dist/{cli-nwrdx840.js → cli-035vekcw.js} +3 -3
- package/dist/{cli-9xf7fdtp.js → cli-0pd8hzhc.js} +29 -6
- package/dist/{cli-tmhsxhb8.js → cli-0veb92a3.js} +28 -6
- package/dist/{cli-c3rk1v0x.js → cli-10jesr25.js} +3 -3
- package/dist/{cli-6thk4jz3.js → cli-1y7yywmj.js} +6 -6
- package/dist/{cli-6r2f7edk.js → cli-20krdhz5.js} +47 -19
- package/dist/{cli-rfs4vddv.js → cli-29rja109.js} +39 -20
- package/dist/cli-2m1ktfzz.js +17795 -0
- package/dist/{cli-na2pxe4f.js → cli-2pwa0q4d.js} +15 -4
- package/dist/{cli-7a93cv8c.js → cli-4mengw46.js} +441 -43
- package/dist/{cli-94b48jhk.js → cli-5twdke5x.js} +16 -14
- package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
- package/dist/cli-6cvfxs8r.js +47 -0
- package/dist/{cli-w1apjecb.js → cli-711vwbxn.js} +2 -2
- package/dist/{cli-r4fqfpwf.js → cli-78vv7446.js} +50 -27
- package/dist/{cli-srqq3gc5.js → cli-7n6s5man.js} +5 -5
- package/dist/{cli-m89t9jdf.js → cli-7x0g4sn1.js} +15416 -16024
- package/dist/{cli-2bw3w47j.js → cli-8wwxw8a3.js} +1 -1
- package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
- package/dist/{cli-ywm1azg9.js → cli-9jzdj90z.js} +8 -4
- package/dist/cli-9traj3dn.js +638 -0
- package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
- package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
- package/dist/cli-cvv9k0hh.js +10143 -0
- package/dist/{cli-anzdk0z4.js → cli-d9286m9h.js} +2 -2
- package/dist/cli-e3g5mbkz.js +776 -0
- package/dist/cli-f527ce74.js +781 -0
- package/dist/{cli-gmdajfw5.js → cli-gxzkg1de.js} +5020 -1729
- package/dist/{cli-451ks6aw.js → cli-h1arqn31.js} +1 -1
- package/dist/cli-hjwmhcg1.js +10622 -0
- package/dist/{cli-jpc4r224.js → cli-hqr88ew6.js} +19 -3
- package/dist/{cli-h7k0xtry.js → cli-hvqbtna4.js} +4 -1256
- package/dist/{cli-cd0hv9nh.js → cli-j67mh2vg.js} +2 -2
- package/dist/cli-jta2eyzc.js +619 -0
- package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
- package/dist/cli-kceah1eh.js +92 -0
- package/dist/{cli-d603qf86.js → cli-ksphgh48.js} +10 -8
- package/dist/{cli-3nxdmjrc.js → cli-mgz4nbgg.js} +4 -4
- package/dist/{cli-saqyage0.js → cli-mz5as5ha.js} +179 -27
- package/dist/cli-n2wq4j7m.js +6985 -0
- package/dist/{cli-ppy4nnnh.js → cli-n8ndw8j7.js} +2 -2
- package/dist/{cli-1w0vj3gw.js → cli-naqzr17j.js} +7 -7
- package/dist/{cli-0a7mm3zp.js → cli-nm1p8jfr.js} +25 -21
- package/dist/{cli-wrh08zjd.js → cli-p3zbc1rw.js} +5 -18
- package/dist/{cli-hsem16hb.js → cli-pe05f8yk.js} +29 -6
- package/dist/{cli-5wpw4rab.js → cli-qmzsbkvy.js} +5 -5
- package/dist/{cli-bv2etw2y.js → cli-qnm4e9e4.js} +99 -590
- package/dist/{cli-1x7da0de.js → cli-qqy4q48b.js} +8 -8
- package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
- package/dist/{cli-5er5gjbm.js → cli-r35rw5de.js} +15 -15
- package/dist/{cli-v3zhnxsb.js → cli-r610p9bs.js} +2 -2
- package/dist/{cli-7jykv7ef.js → cli-rc6pf5kv.js} +1 -1
- package/dist/{cli-x119kdba.js → cli-rdxm77k3.js} +1 -1
- package/dist/cli-rhs9pz33.js +294 -0
- package/dist/{cli-0p3enk35.js → cli-s69nfyeh.js} +9 -1
- package/dist/{cli-0kxf81jj.js → cli-sawv63e8.js} +2 -2
- package/dist/{cli-e3pmyt39.js → cli-sg19gbf0.js} +1 -1
- package/dist/{cli-d161g69q.js → cli-shk7r5cs.js} +57 -6
- package/dist/{cli-7pz3b7x5.js → cli-sksetb2q.js} +36 -1
- package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
- package/dist/{cli-db3m6zdt.js → cli-t02z59f2.js} +1 -1
- package/dist/{cli-b07hr3bt.js → cli-txqb9s38.js} +2 -2
- package/dist/{cli-s8z6x4b4.js → cli-v7g551te.js} +225 -113
- package/dist/{cli-rfz2ve55.js → cli-vgqzp4em.js} +3341 -955
- package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
- package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
- package/dist/cli-wfnemr1t.js +86 -0
- package/dist/cli-wmgrkscj.js +23254 -0
- package/dist/{cli-qm1448f9.js → cli-wms6x9db.js} +8 -8
- package/dist/{cli-tadfgd0t.js → cli-x1r545x8.js} +33 -4
- package/dist/{cli-xc7p7s3g.js → cli-xczsgshn.js} +6 -6
- package/dist/{cli-fmhj1ehj.js → cli-y3167wt1.js} +882 -271
- package/dist/{cli-r0byd61h.js → cli-yjmqpxt3.js} +17 -16
- package/dist/{cli-81r1wjyv.js → cli-z780ec7c.js} +1 -1
- package/dist/{cli-phcqp1b9.js → cli-zm9t2vde.js} +2 -2
- package/dist/cli.js +34 -49
- package/dist/{codex-adapter-r3dn4fp5.js → codex-adapter-4z16v9n0.js} +15 -14
- package/dist/{codex-login-841kv5fk.js → codex-login-pkepy2j1.js} +3 -2
- package/dist/{codex-session-runner-fwt793h4.js → codex-session-runner-rvms9y2x.js} +15 -14
- package/dist/{commands-z8fq9qna.js → commands-2a9rtyat.js} +11 -10
- package/dist/{controller-hq5ggpcp.js → controller-3k3madbn.js} +5 -4
- package/dist/{controllers-connect-3mf2btyj.js → controllers-connect-v9yn8zb9.js} +42 -37
- package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-98gbhyzn.js} +7 -6
- package/dist/{db-qfpq4bt7.js → db-eywwsnjw.js} +30 -9
- package/dist/{db-yyhqqrbf.js → db-ncypk9np.js} +12 -11
- package/dist/{devin-adapter-xgtj680j.js → devin-adapter-zeq8b9gz.js} +3 -2
- package/dist/{dispatcher-x0x7qfcq.js → dispatcher-w94kc575.js} +38 -33
- package/dist/{docker-f503k9p0.js → docker-b1e4cqab.js} +3 -2
- package/dist/{dsh-adapter-34etvb5m.js → dsh-adapter-47ztej36.js} +7 -6
- package/dist/{e2b-66xra4az.js → e2b-bbt8ey45.js} +4 -3
- package/dist/{e2b-xwhyj8cw.js → e2b-dp804sen.js} +4 -3
- package/dist/{event-bus-vjtv82gm.js → event-bus-j2jdg3qb.js} +3 -2
- package/dist/{external-channel-h1fjecwe.js → external-channel-zrkg8ar9.js} +11 -10
- package/dist/{google-generative-ai-szdxbpqg.js → google-generative-ai-g8db7x0f.js} +4 -2
- package/dist/{google-vertex-qzw3p36d.js → google-vertex-r2692q0r.js} +4 -2
- package/dist/{grok-adapter-e7mr287e.js → grok-adapter-s9ncp9vy.js} +18 -17
- package/dist/{handlers-znb9n7d4.js → handlers-kqftvjgw.js} +41 -36
- package/dist/{heartbeat-bm4qkn8d.js → heartbeat-9q96p8v9.js} +43 -38
- package/dist/{hook-254r4mza.js → hook-56qe10dp.js} +11 -23
- package/dist/{hook-xaa3q80s.js → hook-yy6rw42k.js} +12 -11
- package/dist/{http-3dgrgp8y.js → http-r2dnb8f8.js} +2411 -275
- package/dist/{index-fx3jqq1e.js → index-3gtmkhc6.js} +38 -33
- package/dist/{index-bdsqa799.js → index-3k5hkz7r.js} +43 -38
- package/dist/index-52j1aja4.js +3465 -0
- package/dist/{index-g2byveez.js → index-5e101240.js} +38 -33
- package/dist/{index-2ybk7khy.js → index-5wyfjc2c.js} +845 -683
- package/dist/index-9gw58n4k.js +193 -0
- package/dist/index-9j87mcm8.js +56305 -0
- package/dist/index-bsmcresk.js +79424 -0
- package/dist/index-mh85qhec.js +475 -0
- package/dist/{index-jd7sejm2.js → index-vxvhxxbn.js} +10 -9
- package/dist/index-we27kd31.js +12810 -0
- package/dist/{keepalive-6ywhpja1.js → keepalive-psj6j54c.js} +12 -11
- package/dist/{lead-cw45n21s.js → lead-hajz4688.js} +61 -56
- package/dist/{maintenance-ss1a1ge9.js → maintenance-ps02sb5m.js} +10 -9
- package/dist/{node-fkajaq96.js → node-mwb5r697.js} +2 -1
- package/dist/{oauth-refresh-sweep-3c6f8vyy.js → oauth-refresh-sweep-0284h93b.js} +11 -10
- package/dist/{onboard-8hzdhc1k.js → onboard-rbf6bg01.js} +11 -3
- package/dist/{opencode-adapter-qbchbcfz.js → opencode-adapter-13dcatgq.js} +18 -13
- package/dist/{otel-impl-e6mnvc4v.js → otel-impl-zvqcbhp7.js} +242 -868
- package/dist/{pi-mono-adapter-3c9g9snh.js → pi-mono-adapter-xxy47q4v.js} +244 -106
- package/dist/{pricing-refresh-gedkjdw0.js → pricing-refresh-kefx9v3t.js} +12 -11
- package/dist/{rbac-roles-dt4vh1yy.js → rbac-roles-3m36rxm2.js} +11 -10
- package/dist/{rbac-roles-eszdg6pm.js → rbac-roles-z76xv0hq.js} +12 -11
- package/dist/{render-v2-907cy6sa.js → render-v2-wz73bs25.js} +18 -14
- package/dist/{resume-42stcaz0.js → resume-k4wzge8w.js} +25 -21
- package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
- package/dist/{setup-adbc1c10.js → setup-2fp2pypp.js} +2 -2
- package/dist/{virtual-modules-rtmt494q.js → virtual-modules-9gkxqrap.js} +6 -5
- package/dist/{work-objects-wpj8ck95.js → work-objects-6k0ywz3m.js} +41 -36
- package/dist/{worker-bzdra9rf.js → worker-5v3rxsdh.js} +61 -56
- package/dist/{x-qfmygqqv.js → x-4mtdeym1.js} +3 -2
- package/openapi.json +1279 -329
- package/package.json +15 -15
- package/src/agentmail/handlers.ts +21 -11
- package/src/apps/definition.ts +16 -0
- package/src/azure-devops/api.ts +52 -2
- package/src/azure-devops/boards-sync.ts +50 -20
- package/src/azure-devops/index.ts +1 -0
- package/src/azure-devops/outbound.ts +95 -0
- package/src/be/boot-seeds.ts +11 -0
- package/src/be/config-refs.ts +60 -0
- package/src/be/db/model-profiles.ts +315 -0
- package/src/be/db/page-versions.ts +15 -0
- package/src/be/db/runtime.ts +35 -8
- package/src/be/db/skill-name-resolution.ts +36 -0
- package/src/be/db/tasks/read.ts +237 -0
- package/src/be/db/tasks/write.ts +7 -0
- package/src/be/db.ts +87 -36
- package/src/be/migrations/215_swarm_config_export_to_env.sql +34 -0
- package/src/be/migrations/216_task_resolved_effort.sql +5 -0
- package/src/be/migrations/217_chat_sdk_state.sql +104 -0
- package/src/be/migrations/219_relabel_pi_context_compactions.sql +22 -0
- package/src/be/migrations/220_model_profiles.sql +137 -0
- package/src/be/model-catalog-store.ts +5 -1
- package/src/be/model-tier-resolution.ts +155 -10
- package/src/be/model-validation.ts +12 -2
- package/src/be/models-catalog.ts +26 -1
- package/src/be/modelsdev-cache.json +198 -63
- package/src/be/modelsdev-cache.ts +9 -1
- package/src/be/script-credential-broker.ts +39 -2
- package/src/be/scripts/run-saved.ts +1 -0
- package/src/be/scripts/typecheck.ts +22 -8
- package/src/be/secret-registry.ts +6 -2
- package/src/be/seed/runner.ts +13 -1
- package/src/be/seed/state-db.ts +5 -0
- package/src/be/seed/types.ts +6 -0
- package/src/be/seed-model-profiles.ts +41 -0
- package/src/be/seed-pricing.ts +19 -2
- package/src/be/seed-scripts/catalog/heartbeat-jev-gate.ts +368 -0
- package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
- package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
- package/src/be/seed-scripts/index.ts +9 -0
- package/src/be/seed-skills/bundled-files.generated.json +0 -18
- package/src/be/seed-skills/index.ts +104 -3
- package/src/be/swarm-config-guard.ts +53 -0
- package/src/cli.tsx +0 -16
- package/src/commands/onboard/non-interactive.ts +4 -2
- package/src/commands/provider-credentials.ts +52 -6
- package/src/commands/runner.ts +193 -71
- package/src/e2b/env.ts +5 -0
- package/src/extensions/catalog.generated.json +17 -0
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/extensions/contract.ts +45 -0
- package/src/extensions/dispatcher.ts +7 -0
- package/src/extensions/loader.ts +10 -5
- package/src/extensions/post-bridge.ts +40 -0
- package/src/github/handlers.ts +11 -4
- package/src/heartbeat/heartbeat.ts +2 -1
- package/src/heartbeat/templates.ts +8 -5
- package/src/hooks/hook.ts +0 -26
- package/src/http/agents.ts +49 -2
- package/src/http/all-routes.ts +1 -1
- package/src/http/apps.ts +30 -3
- package/src/http/config.ts +62 -19
- package/src/http/core.ts +8 -0
- package/src/http/index.ts +25 -3
- package/src/http/integrations.ts +88 -1
- package/src/http/mcp.ts +15 -5
- package/src/http/model-profiles.ts +303 -0
- package/src/http/page-proxy.ts +2 -4
- package/src/http/pages-public.ts +13 -7
- package/src/http/pages.ts +3 -13
- package/src/http/poll.ts +42 -71
- package/src/http/requested-by.ts +54 -0
- package/src/http/script-runs.ts +1 -1
- package/src/http/scripts.ts +26 -2
- package/src/http/stats.ts +1 -30
- package/src/http/tasks.ts +79 -5
- package/src/http/utils.ts +14 -0
- package/src/http/webhooks.ts +160 -3
- package/src/http/x.ts +1 -0
- package/src/integrations/chat-sdk/adapters.ts +129 -0
- package/src/integrations/chat-sdk/attachments.ts +232 -0
- package/src/integrations/chat-sdk/background.ts +36 -0
- package/src/integrations/chat-sdk/commands.ts +194 -0
- package/src/integrations/chat-sdk/config.ts +198 -0
- package/src/integrations/chat-sdk/discord-api.ts +63 -0
- package/src/integrations/chat-sdk/discord-gateway.ts +185 -0
- package/src/integrations/chat-sdk/handlers.ts +28 -0
- package/src/integrations/chat-sdk/inbound.ts +426 -0
- package/src/integrations/chat-sdk/limits.ts +48 -0
- package/src/integrations/chat-sdk/logger.ts +81 -0
- package/src/integrations/chat-sdk/outbound.ts +123 -0
- package/src/integrations/chat-sdk/relay.ts +172 -0
- package/src/integrations/chat-sdk/router.ts +169 -0
- package/src/integrations/chat-sdk/runtime.ts +351 -0
- package/src/integrations/chat-sdk/schema.ts +245 -0
- package/src/integrations/chat-sdk/state.ts +243 -0
- package/src/integrations/chat-sdk/status.ts +244 -0
- package/src/integrations/chat-sdk/steering.ts +58 -0
- package/src/integrations/chat-sdk/teams-origin.ts +77 -0
- package/src/integrations/chat-sdk/telegram-api.ts +56 -0
- package/src/integrations/chat-sdk/templates.ts +16 -0
- package/src/integrations/chat-sdk/test-hooks.ts +37 -0
- package/src/integrations/chat-sdk/thread-buffer.ts +100 -0
- package/src/integrations/chat-sdk/typing.ts +65 -0
- package/src/{artifact-sdk → pages}/feedback-overlay.ts +65 -6
- package/src/pages/version.ts +4 -5
- package/src/prompts/base-prompt.ts +111 -45
- package/src/providers/acp-target-catalog.ts +6 -0
- package/src/providers/acp-targets.ts +56 -3
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/claude-adapter.ts +1 -1
- package/src/providers/claude-flag-settings.ts +17 -5
- package/src/providers/claude-managed-adapter.ts +1 -1
- package/src/providers/claude-session-events.ts +6 -1
- package/src/providers/dsh-adapter.ts +1 -1
- package/src/providers/opencode-adapter.ts +243 -26
- package/src/providers/opencode-swarm-plugin.ts +31 -0
- package/src/providers/pi-mono-adapter.ts +398 -153
- package/src/providers/pi-mono-extension.ts +17 -3
- package/src/providers/pricing-sources.md +33 -2
- package/src/providers/reasoning-effort.ts +37 -0
- package/src/providers/types.ts +6 -2
- package/src/rbac/legacy-policy.ts +16 -2
- package/src/rbac/permissions.ts +26 -0
- package/src/scheduler/deferred-task-waits.ts +18 -5
- package/src/scheduler/scheduler.ts +11 -3
- package/src/scripts-runtime/executors/quickjs-prelude.ts +75 -6
- package/src/scripts-runtime/executors/quickjs-runner.ts +85 -8
- package/src/scripts-runtime/executors/quickjs-web-shims.ts +1041 -0
- package/src/scripts-runtime/extract-args-schema.ts +9 -8
- package/src/scripts-runtime/loader.ts +19 -7
- package/src/scripts-runtime/quickjs-compat.ts +464 -0
- package/src/scripts-runtime/sdk-allowlist.ts +12 -6
- package/src/scripts-runtime/swarm-sdk.ts +0 -11
- package/src/scripts-runtime/types/stdlib.d.ts +39 -15
- package/src/scripts-runtime/types/swarm-extension.d.ts +66 -1
- package/src/scripts-runtime/types/swarm-sdk.d.ts +39 -15
- package/src/server.ts +62 -19
- package/src/slack/blocks.ts +4 -2
- package/src/slack/event-dedup.ts +1 -1
- package/src/slack/reaction-shortcode.ts +14 -0
- package/src/slack/render-v2.ts +12 -7
- package/src/slack/responses.ts +5 -4
- package/src/slack/thread-buffer.ts +41 -22
- package/src/tasks/additive-buffer.ts +4 -2
- package/src/tasks/context-key.ts +60 -1
- package/src/tasks/model-pin.ts +67 -0
- package/src/tasks/worker-follow-up.ts +15 -33
- package/src/tests/acp-adapter.test.ts +42 -0
- package/src/tests/agentmail-filters.test.ts +47 -0
- package/src/tests/api-drain-worker-e2e.test.ts +1 -6
- package/src/tests/apps-spike2.test.ts +35 -0
- package/src/tests/azure-devops-outbound.test.ts +420 -0
- package/src/tests/base-prompt.test.ts +58 -54
- package/src/tests/chat-sdk-commands.test.ts +191 -0
- package/src/tests/chat-sdk-config.test.ts +334 -0
- package/src/tests/chat-sdk-discord-api.test.ts +68 -0
- package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
- package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
- package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
- package/src/tests/chat-sdk-harness.ts +146 -0
- package/src/tests/chat-sdk-inbound.test.ts +363 -0
- package/src/tests/chat-sdk-relay.test.ts +470 -0
- package/src/tests/chat-sdk-reload.test.ts +128 -0
- package/src/tests/chat-sdk-shutdown.test.ts +220 -0
- package/src/tests/chat-sdk-slack.test.ts +268 -0
- package/src/tests/chat-sdk-state.test.ts +163 -0
- package/src/tests/chat-sdk-status-route.test.ts +382 -0
- package/src/tests/chat-sdk-teams.test.ts +277 -0
- package/src/tests/chat-sdk-tools.test.ts +520 -0
- package/src/tests/chat-sdk-typing.test.ts +120 -0
- package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
- package/src/tests/claude-adapter-binary.test.ts +9 -4
- package/src/tests/claude-flag-settings.test.ts +11 -3
- package/src/tests/claude-managed-adapter.test.ts +1 -1
- package/src/tests/claude-sdk-lifecycle.test.ts +9 -3
- package/src/tests/claude-thinking-tokens.test.ts +57 -0
- package/src/tests/claude-worker-parity.test.ts +2 -7
- package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
- package/src/tests/config-refs.test.ts +66 -0
- package/src/tests/context-key.test.ts +19 -0
- package/src/tests/cors-allowlist.test.ts +25 -0
- package/src/tests/create-page-tool.test.ts +18 -0
- package/src/tests/credential-check.test.ts +139 -0
- package/src/tests/credentials.test.ts +21 -0
- package/src/tests/db-runtime.test.ts +61 -0
- package/src/tests/db-task-read-contract.test.ts +22 -0
- package/src/tests/db-task-write-contract.test.ts +11 -0
- package/src/tests/deferred-task-wake.test.ts +78 -1
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/dsh-adapter.test.ts +1 -1
- package/src/tests/enabled-capabilities.test.ts +20 -0
- package/src/tests/entrypoint-api-readiness.test.ts +14 -8
- package/src/tests/entrypoint-config-env-export.test.ts +5 -2
- package/src/tests/entrypoint-export-to-env.test.ts +78 -0
- package/src/tests/env-flag.test.ts +1 -0
- package/src/tests/explicit-model-validation.test.ts +105 -1
- package/src/tests/extensions-catalog.test.ts +1 -0
- package/src/tests/extensions-example-comms-adherence-gate.test.ts +413 -0
- package/src/tests/extensions-example-route-chat-channel.test.ts +154 -0
- package/src/tests/extensions-loader.test.ts +15 -0
- package/src/tests/extensions-post-bridge.test.ts +51 -0
- package/src/tests/fetch-resolved-env.test.ts +128 -0
- package/src/tests/fixtures/chat-sdk/telegram-private-text.json +10 -0
- package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
- package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
- package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
- package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
- package/src/tests/github-handlers.test.ts +35 -0
- package/src/tests/harness-provider-resolution.test.ts +12 -0
- package/src/tests/heartbeat-checklist.test.ts +3 -2
- package/src/tests/heartbeat-jev-gate-credentials.test.ts +168 -0
- package/src/tests/heartbeat-jev-gate.test.ts +385 -0
- package/src/tests/hook-runtime-close.test.ts +0 -2
- package/src/tests/http-api-integration.test.ts +0 -25
- package/src/tests/migration-046-budgets.test.ts +17 -16
- package/src/tests/migration-217-chat-sdk-state.test.ts +113 -0
- package/src/tests/model-profile-backcompat.test.ts +327 -0
- package/src/tests/model-profile-providers.test.ts +302 -0
- package/src/tests/model-profile-runtime-secrets.test.ts +223 -0
- package/src/tests/model-profiles-api.test.ts +614 -0
- package/src/tests/model-tier-resolution.test.ts +93 -0
- package/src/tests/models-catalog.test.ts +42 -1
- package/src/tests/openai-compatible-providers.test.ts +134 -0
- package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
- package/src/tests/opencode-adapter.test.ts +216 -2
- package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
- package/src/tests/opencode-shell-env.test.ts +145 -0
- package/src/tests/openrouter-base-url.test.ts +101 -151
- package/src/tests/page-proxy.test.ts +1 -1
- package/src/tests/pages-browser-sdk.test.ts +76 -0
- package/src/tests/pages-feedback-keys.test.ts +121 -0
- package/src/tests/pages-feedback.test.ts +4 -1
- package/src/tests/paused-tasks-requested-by.test.ts +102 -0
- package/src/tests/pi-context-compaction.test.ts +193 -0
- package/src/tests/pi-custom-provider-fake-server.test.ts +442 -0
- package/src/tests/pi-mono-adapter.test.ts +385 -5
- package/src/tests/pi-shell-env.test.ts +170 -0
- package/src/tests/profile-claim.test.ts +269 -0
- package/src/tests/prompt-template-remaining.test.ts +35 -0
- package/src/tests/quickjs-compat.test.ts +213 -0
- package/src/tests/rbac-engine.test.ts +32 -3
- package/src/tests/runner-exit-after-tasks.test.ts +0 -4
- package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
- package/src/tests/script-connections.test.ts +6 -0
- package/src/tests/script-executor-conformance.test.ts +252 -1
- package/src/tests/script-executor-quickjs.test.ts +96 -0
- package/src/tests/script-runs-http.test.ts +89 -0
- package/src/tests/scripts-http.test.ts +217 -1
- package/src/tests/scripts-only-gating.test.ts +2 -3
- package/src/tests/scripts-runtime.test.ts +58 -40
- package/src/tests/secret-scrubber.test.ts +96 -0
- package/src/tests/seed-model-profiles.test.ts +174 -0
- package/src/tests/seed-scripts.test.ts +2 -2
- package/src/tests/seed-skills-bundled-files.test.ts +45 -53
- package/src/tests/seed-skills-retire.test.ts +182 -0
- package/src/tests/send-task-requester-gate.test.ts +58 -0
- package/src/tests/session-cost-recompute-unit.test.ts +46 -0
- package/src/tests/skill-get-name-resolution.test.ts +137 -0
- package/src/tests/skill-invocations.test.ts +4 -2
- package/src/tests/slack-blocks.test.ts +36 -0
- package/src/tests/slack-inline-output.test.ts +14 -0
- package/src/tests/slack-reaction-config.test.ts +20 -0
- package/src/tests/slack-render-v2.test.ts +37 -0
- package/src/tests/slack-thread-buffer.test.ts +98 -1
- package/src/tests/sonnet-5-5-registry.test.ts +9 -1
- package/src/tests/swarm-config-export-to-env.test.ts +267 -0
- package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
- package/src/tests/swarm-diff.test.ts +1 -1
- package/src/tests/task-model-effort-rerun.test.ts +164 -0
- package/src/tests/task-session-prompts.test.ts +132 -0
- package/src/tests/task-tool-manifest.test.ts +14 -0
- package/src/tests/task-tools-ctx.test.ts +2 -0
- package/src/tests/tool-annotations.test.ts +6 -6
- package/src/tests/ui-logs-parser.test.ts +43 -0
- package/src/tests/used-by-route.test.ts +6 -0
- package/src/tests/vercel-ai-gateway.test.ts +149 -0
- package/src/tests/workflow-llm.test.ts +61 -0
- package/src/tests/workflow-swarm-script.test.ts +38 -0
- package/src/tests/workflow-wait-filter.test.ts +5 -3
- package/src/tools/chat-access.ts +41 -0
- package/src/tools/chat-open-dm.ts +59 -0
- package/src/tools/chat-post.ts +74 -0
- package/src/tools/chat-read-thread.ts +100 -0
- package/src/tools/chat-reply.ts +75 -0
- package/src/tools/create-page.ts +3 -13
- package/src/tools/model-catalog/index.ts +2 -1
- package/src/tools/model-profiles/list-model-profiles.ts +54 -0
- package/src/tools/register-chat-channel.ts +139 -0
- package/src/tools/request-human-input.ts +11 -3
- package/src/tools/script-apis.ts +5 -1
- package/src/tools/script-upsert.ts +4 -1
- package/src/tools/send-task.ts +48 -1
- package/src/tools/skills/skill-get.ts +17 -9
- package/src/tools/swarm-config/get-config.ts +2 -1
- package/src/tools/swarm-config/list-config.ts +2 -1
- package/src/tools/swarm-config/set-config.ts +16 -3
- package/src/tools/system-one-decide.ts +104 -0
- package/src/tools/task-action.ts +22 -1
- package/src/tools/tool-config.ts +14 -6
- package/src/types.ts +48 -3
- package/src/utils/config-env-export.ts +74 -0
- package/src/utils/credentials.test.ts +92 -0
- package/src/utils/credentials.ts +52 -4
- package/src/utils/harness-provider.ts +15 -6
- package/src/utils/runtime-model-catalog.ts +11 -1
- package/src/utils/secret-scrubber.ts +86 -10
- package/src/utils/task-tool-manifest.ts +19 -2
- package/src/utils/vcs-repo-match.ts +29 -0
- package/src/workflows/executors/raw-llm.ts +8 -3
- package/src/workflows/executors/swarm-script.ts +1 -0
- package/src/workflows/executors/system-one-decision.ts +21 -11
- package/src/workflows/executors/workflow-llm.ts +22 -0
- package/src/workflows/index.ts +21 -12
- package/templates/extensions/README.md +1 -0
- package/templates/extensions/comms-adherence-gate/README.md +88 -0
- package/templates/extensions/comms-adherence-gate/hooks.ts +489 -0
- package/templates/extensions/comms-adherence-gate/manifest.json +8 -0
- package/templates/skills/agent-browser/SKILL.md +1 -1
- package/templates/skills/agent-browser/content.md +1 -1
- package/templates/skills/apps/SKILL.md +8 -1
- package/templates/skills/apps/content.md +8 -1
- package/templates/skills/chat-sdk/config.json +14 -0
- package/templates/skills/chat-sdk/content.md +84 -0
- package/templates/skills/composio-gmail/content.md +7 -0
- package/templates/skills/composio-google-docs/content.md +1 -1
- package/templates/skills/email-domain-health/config.json +14 -0
- package/templates/skills/email-domain-health/content.md +131 -0
- package/templates/skills/kv-storage/content.md +2 -2
- package/templates/skills/pages/content.md +8 -10
- package/templates/skills/swarm-extensions/content.md +2 -0
- package/templates/skills/swarm-scripts/SKILL.md +4 -2
- package/templates/skills/swarm-scripts/config.json +1 -1
- package/templates/skills/swarm-scripts/content.md +4 -2
- package/templates/skills/workflow-iterate/content.md +38 -0
- package/dist/artifact-eczsknc3.js +0 -3843
- package/dist/cli-42qhyvwx.js +0 -33
- package/dist/cli-bd957dgb.js +0 -153
- package/dist/cli-q51yprfq.js +0 -1104
- package/dist/cli-t1ze64h3.js +0 -811
- package/dist/cli-tcc4wd5d.js +0 -56471
- package/dist/index-9ch1n761.js +0 -1102
- package/src/artifact-sdk/index.ts +0 -2
- package/src/artifact-sdk/localtunnel.d.ts +0 -20
- package/src/artifact-sdk/port.ts +0 -12
- package/src/artifact-sdk/server.ts +0 -183
- package/src/artifact-sdk/tunnel.ts +0 -19
- package/src/commands/artifact.ts +0 -249
- package/src/http/ecosystem.ts +0 -77
- package/src/tests/artifact-commands.test.ts +0 -92
- package/src/tests/artifact-sdk.test.ts +0 -793
- package/src/tests/register-service-security.test.ts +0 -194
- package/src/tools/list-services.ts +0 -107
- package/src/tools/register-service.ts +0 -177
- package/src/tools/unregister-service.ts +0 -73
- package/src/tools/update-service-status.ts +0 -96
- package/templates/skills/artifacts/config.json +0 -14
- package/templates/skills/artifacts/content.md +0 -344
- package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
- package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
- package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
- package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
- /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@desplega.ai/agent-swarm",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "agent-swarm.dev — an open-source operating system for AI work: a lead agent breaks goals into tasks, routes them to specialized workers such as Claude Code or Codex, runs each worker in an isolated container, and preserves shared memory, tools, schedules, and review gates so delegated work compounds across sessions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-swarm.dev",
|
|
@@ -168,11 +168,6 @@
|
|
|
168
168
|
"docs:mcp": "bun scripts/generate-mcp-docs.ts",
|
|
169
169
|
"docs:openapi": "bun scripts/generate-openapi.ts",
|
|
170
170
|
"docs:business-use": "bun scripts/generate-business-use-docs.ts",
|
|
171
|
-
"pm2-start": "pm2 start ecosystem.config.cjs",
|
|
172
|
-
"pm2-stop": "pm2 stop ecosystem.config.cjs",
|
|
173
|
-
"pm2-restart": "pm2 restart ecosystem.config.cjs",
|
|
174
|
-
"pm2-logs": "pm2 logs swarm-api swarm-ui swarm-lead swarm-worker",
|
|
175
|
-
"pm2-status": "pm2 status swarm-api swarm-ui swarm-lead swarm-worker",
|
|
176
171
|
"seed": "bun scripts/seed.ts",
|
|
177
172
|
"seed:clean": "bun scripts/seed.ts --clean",
|
|
178
173
|
"seed:people": "bun scripts/seed-people.ts",
|
|
@@ -180,16 +175,17 @@
|
|
|
180
175
|
},
|
|
181
176
|
"devDependencies": {
|
|
182
177
|
"@biomejs/biome": "^2.3.10",
|
|
183
|
-
"@desplega.ai/slack-mock": "^0.4.
|
|
178
|
+
"@desplega.ai/slack-mock": "^0.4.1",
|
|
184
179
|
"@desplega/model-catalog": "workspace:*",
|
|
185
180
|
"@desplega/model-routing": "workspace:*",
|
|
186
181
|
"@faker-js/faker": "^10.4.0",
|
|
187
|
-
"@opencode/plugin": "2.0.
|
|
188
|
-
"@opencode/sdk": "2.0.
|
|
182
|
+
"@opencode/plugin": "2.0.31",
|
|
183
|
+
"@opencode/sdk": "2.0.31",
|
|
189
184
|
"@oxlint/plugins": "1.78.0",
|
|
190
185
|
"@types/bun": "latest",
|
|
191
186
|
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
192
187
|
"dependency-cruiser": "^18.0.0",
|
|
188
|
+
"happy-dom": "^20.14.5",
|
|
193
189
|
"konsistent": "1.0.0-beta.1",
|
|
194
190
|
"openapi-typescript": "^7",
|
|
195
191
|
"oxlint": "1.78.0",
|
|
@@ -203,15 +199,18 @@
|
|
|
203
199
|
"bun": ">=1.3.12"
|
|
204
200
|
},
|
|
205
201
|
"dependencies": {
|
|
206
|
-
"@agentclientprotocol/sdk": "1.
|
|
202
|
+
"@agentclientprotocol/sdk": "1.9.0",
|
|
207
203
|
"@ai-sdk/openai": "^3.0.41",
|
|
208
|
-
"@anthropic-ai/claude-agent-sdk": "0.3.
|
|
209
|
-
"@anthropic-ai/sdk": "^0.
|
|
204
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.301",
|
|
205
|
+
"@anthropic-ai/sdk": "^0.135.0",
|
|
210
206
|
"@asteasolutions/zod-to-openapi": "^8.0.0",
|
|
211
207
|
"@aws-sdk/client-bedrock": "3.1048.0",
|
|
208
|
+
"@chat-adapter/discord": "4.41.1",
|
|
209
|
+
"@chat-adapter/slack": "4.41.1",
|
|
210
|
+
"@chat-adapter/teams": "4.41.1",
|
|
211
|
+
"@chat-adapter/telegram": "4.41.1",
|
|
212
212
|
"@cursor/sdk": "1.0.37",
|
|
213
213
|
"@desplega.ai/business-use": "^0.4.2",
|
|
214
|
-
"@desplega.ai/localtunnel": "^2.2.0",
|
|
215
214
|
"@earendil-works/pi-agent-core": "^1.2.0",
|
|
216
215
|
"@earendil-works/pi-ai": "^1.2.0",
|
|
217
216
|
"@earendil-works/pi-coding-agent": "^1.2.0",
|
|
@@ -219,7 +218,7 @@
|
|
|
219
218
|
"@jitl/quickjs-singlefile-mjs-release-sync": "0.32.0",
|
|
220
219
|
"@linear/sdk": "^77.0.0",
|
|
221
220
|
"@modelcontextprotocol/sdk": "1.31.0",
|
|
222
|
-
"@openai/codex": "0.
|
|
221
|
+
"@openai/codex": "0.163.0",
|
|
223
222
|
"@openfort/openfort-node": "^0.9.1",
|
|
224
223
|
"@opentelemetry/api": "^1.9.1",
|
|
225
224
|
"@opentelemetry/api-logs": "^0.218.0",
|
|
@@ -230,15 +229,16 @@
|
|
|
230
229
|
"@opentelemetry/sdk-node": "^0.218.0",
|
|
231
230
|
"@opentelemetry/semantic-conventions": "^1.41.1",
|
|
232
231
|
"@slack/bolt": "^4.6.0",
|
|
232
|
+
"@slack/web-api": "7.13.0",
|
|
233
233
|
"@types/react": "^19.2.7",
|
|
234
234
|
"@x402/core": "^2.5.0",
|
|
235
235
|
"@x402/evm": "^2.5.0",
|
|
236
236
|
"@x402/fetch": "^2.5.0",
|
|
237
237
|
"ai": "^6.0.116",
|
|
238
|
+
"chat": "4.41.1",
|
|
238
239
|
"cron-parser": "^5.4.0",
|
|
239
240
|
"date-fns": "^4.1.0",
|
|
240
241
|
"e2b": "2.26.0",
|
|
241
|
-
"hono": "^4.12.3",
|
|
242
242
|
"ink": "^6.5.1",
|
|
243
243
|
"oauth4webapi": "^3.8.5",
|
|
244
244
|
"openai": "^6.22.0",
|
|
@@ -91,32 +91,42 @@ function extractNameFromField(from: string): string | undefined {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
|
-
* Check
|
|
95
|
-
*
|
|
94
|
+
* Check an email address against comma-separated filter entries.
|
|
95
|
+
* An entry containing "@" matches that exact address; a bare entry matches any
|
|
96
|
+
* address on that domain. Comparison is case-insensitive.
|
|
97
|
+
*/
|
|
98
|
+
function matchesAddressFilter(email: string, filter: string): boolean {
|
|
99
|
+
const address = email.trim().toLowerCase();
|
|
100
|
+
const domain = address.split("@")[1];
|
|
101
|
+
if (!domain) return false;
|
|
102
|
+
return filter
|
|
103
|
+
.split(",")
|
|
104
|
+
.map((entry) => entry.trim().toLowerCase())
|
|
105
|
+
.some((entry) => (entry.includes("@") ? entry === address : entry === domain));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Check if an inbox address is allowed by the filter (full addresses or domains).
|
|
110
|
+
* Returns true if no filter is set or the inbox matches an entry.
|
|
96
111
|
*/
|
|
97
112
|
export function isInboxAllowed(inboxId: string, filter: string | undefined): boolean {
|
|
98
113
|
if (!filter) return true;
|
|
99
|
-
|
|
100
|
-
const inboxDomain = inboxId.split("@")[1]?.toLowerCase();
|
|
101
|
-
return !!inboxDomain && allowedDomains.includes(inboxDomain);
|
|
114
|
+
return matchesAddressFilter(inboxId, filter);
|
|
102
115
|
}
|
|
103
116
|
|
|
104
117
|
/**
|
|
105
|
-
* Check if a sender
|
|
106
|
-
* Returns true if no filter is set or at least one sender
|
|
118
|
+
* Check if a sender address is allowed by the filter (full addresses or domains).
|
|
119
|
+
* Returns true if no filter is set or at least one sender matches an entry.
|
|
107
120
|
*/
|
|
108
121
|
export function isSenderAllowed(
|
|
109
122
|
from: AgentMailMessage["from_"],
|
|
110
123
|
filter: string | undefined,
|
|
111
124
|
): boolean {
|
|
112
125
|
if (!filter) return true;
|
|
113
|
-
const allowedDomains = filter.split(",").map((d) => d.trim().toLowerCase());
|
|
114
126
|
const fromAddresses = Array.isArray(from) ? from : [from || ""];
|
|
115
127
|
return fromAddresses.some((addr) => {
|
|
116
128
|
const emailMatch = addr.match(/<([^>]+)>/);
|
|
117
|
-
|
|
118
|
-
const domain = email.split("@")[1]?.toLowerCase();
|
|
119
|
-
return !!domain && allowedDomains.includes(domain);
|
|
129
|
+
return matchesAddressFilter(emailMatch?.[1] ?? addr, filter);
|
|
120
130
|
});
|
|
121
131
|
}
|
|
122
132
|
|
package/src/apps/definition.ts
CHANGED
|
@@ -2,6 +2,7 @@ import * as z from "zod";
|
|
|
2
2
|
import { listScriptConnections } from "../be/script-connections";
|
|
3
3
|
import { getScriptById } from "../be/scripts/db";
|
|
4
4
|
import { getSavedScriptOwnerAgentId } from "../be/scripts/run-saved";
|
|
5
|
+
import { checkQuickJSCompat, quickJSCompatWarnings } from "../scripts-runtime/quickjs-compat";
|
|
5
6
|
import catalog from "./catalog.generated.json";
|
|
6
7
|
import {
|
|
7
8
|
crossPageDefinitionIssues,
|
|
@@ -592,6 +593,21 @@ export function collectScriptReferences(definition: unknown): Map<string, string
|
|
|
592
593
|
return references;
|
|
593
594
|
}
|
|
594
595
|
|
|
596
|
+
/**
|
|
597
|
+
* Advisory quickjs compatibility warnings for every script that the
|
|
598
|
+
* definition's actions and sync sources run. Never a validation issue.
|
|
599
|
+
*/
|
|
600
|
+
export async function scriptCompatWarnings(definition: unknown): Promise<string[]> {
|
|
601
|
+
const warnings: string[] = [];
|
|
602
|
+
for (const [scriptId, paths] of collectScriptReferences(definition)) {
|
|
603
|
+
const script = await getScriptById(scriptId);
|
|
604
|
+
if (!script) continue;
|
|
605
|
+
const report = checkQuickJSCompat(script.source, { fsMode: script.fsMode });
|
|
606
|
+
warnings.push(...quickJSCompatWarnings(report, paths.join(", ")));
|
|
607
|
+
}
|
|
608
|
+
return warnings;
|
|
609
|
+
}
|
|
610
|
+
|
|
595
611
|
/**
|
|
596
612
|
* Is this agent-scoped script foreign to the writing principal? Operators
|
|
597
613
|
* (no writer identity at all) may wire anything; an agent may wire its own;
|
package/src/azure-devops/api.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* and resolving the bot identity behind the PAT. Uses raw fetch, no SDK.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { scrubSecrets } from "../utils/secret-scrubber";
|
|
6
7
|
import {
|
|
7
8
|
getAzureDevOpsOrgUrl,
|
|
8
9
|
getAzureDevOpsToken,
|
|
@@ -163,7 +164,9 @@ export async function likeAzureDevOpsComment(
|
|
|
163
164
|
try {
|
|
164
165
|
const resp = await fetch(url, { method: "POST", headers: headers() });
|
|
165
166
|
if (!resp.ok) {
|
|
166
|
-
console.error(
|
|
167
|
+
console.error(
|
|
168
|
+
`[AzureDevOps] Failed to like comment: ${resp.status} ${scrubSecrets(await resp.text())}`,
|
|
169
|
+
);
|
|
167
170
|
}
|
|
168
171
|
} catch (err) {
|
|
169
172
|
console.error(`[AzureDevOps] Error liking comment:`, err);
|
|
@@ -189,9 +192,56 @@ export async function postAzureDevOpsPullRequestComment(
|
|
|
189
192
|
}),
|
|
190
193
|
});
|
|
191
194
|
if (!resp.ok) {
|
|
192
|
-
console.error(
|
|
195
|
+
console.error(
|
|
196
|
+
`[AzureDevOps] Failed to post comment: ${resp.status} ${scrubSecrets(await resp.text())}`,
|
|
197
|
+
);
|
|
193
198
|
}
|
|
194
199
|
} catch (err) {
|
|
195
200
|
console.error(`[AzureDevOps] Error posting comment:`, err);
|
|
196
201
|
}
|
|
197
202
|
}
|
|
203
|
+
|
|
204
|
+
/** One JSON Patch operation on a work item. */
|
|
205
|
+
export interface WorkItemFieldOp {
|
|
206
|
+
op: "add" | "replace";
|
|
207
|
+
path: string; // e.g. "/fields/System.State"
|
|
208
|
+
value: unknown;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Update work-item fields with one JSON Patch call. Returns whether it
|
|
213
|
+
* succeeded; failures are logged, never thrown, since callers are
|
|
214
|
+
* fire-and-forget lifecycle mirrors. The project segment is optional here.
|
|
215
|
+
* @see https://learn.microsoft.com/rest/api/azure/devops/wit/work-items/update
|
|
216
|
+
*/
|
|
217
|
+
export async function updateWorkItemFields(
|
|
218
|
+
orgBaseUrl: string,
|
|
219
|
+
workItemId: number,
|
|
220
|
+
ops: WorkItemFieldOp[],
|
|
221
|
+
): Promise<boolean> {
|
|
222
|
+
const orgUrl = credentialedOrgUrl(orgBaseUrl);
|
|
223
|
+
if (!orgUrl) return false;
|
|
224
|
+
try {
|
|
225
|
+
const resp = await fetch(
|
|
226
|
+
`${orgUrl}/_apis/wit/workitems/${workItemId}?api-version=${API_VERSION}`,
|
|
227
|
+
{
|
|
228
|
+
method: "PATCH",
|
|
229
|
+
headers: { ...headers(), "Content-Type": "application/json-patch+json" },
|
|
230
|
+
body: JSON.stringify(ops),
|
|
231
|
+
redirect: "error",
|
|
232
|
+
},
|
|
233
|
+
);
|
|
234
|
+
if (!resp.ok) {
|
|
235
|
+
console.error(
|
|
236
|
+
`[AzureDevOps] Failed to update work item #${workItemId}: ${resp.status} ${scrubSecrets(await resp.text())}`,
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
return resp.ok;
|
|
240
|
+
} catch (err) {
|
|
241
|
+
console.error(
|
|
242
|
+
`[AzureDevOps] Error updating work item #${workItemId}:`,
|
|
243
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
244
|
+
);
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
@@ -37,6 +37,7 @@ import { azureDevOpsWorkItemContextKey } from "../tasks/context-key";
|
|
|
37
37
|
import { createTaskWithSiblingAwareness } from "../tasks/sibling-awareness";
|
|
38
38
|
import type { TrackerSync } from "../tracker/types";
|
|
39
39
|
import { isTerminalTaskStatus } from "../types";
|
|
40
|
+
import { workflowEventBus } from "../workflows/event-bus";
|
|
40
41
|
import { resolveAzureDevOpsBotIdentity } from "./api";
|
|
41
42
|
import {
|
|
42
43
|
AZURE_DEVOPS_BOT_NAME,
|
|
@@ -561,7 +562,7 @@ export async function handleWorkItemUpdated(event: WorkItemUpdatedEvent): Promis
|
|
|
561
562
|
const org = orgFor(event);
|
|
562
563
|
if (!org) return dropUntrustedOrg(event.eventType);
|
|
563
564
|
|
|
564
|
-
|
|
565
|
+
const routeAssignment = async (): Promise<HandlerResult> => {
|
|
565
566
|
const bot = await resolveBot(org.url);
|
|
566
567
|
if (!isBotString(change.newValue, bot) || isBotString(change.oldValue, bot)) {
|
|
567
568
|
return { created: false };
|
|
@@ -579,6 +580,21 @@ export async function handleWorkItemUpdated(event: WorkItemUpdatedEvent): Promis
|
|
|
579
580
|
},
|
|
580
581
|
"assigned",
|
|
581
582
|
);
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
return await handleDelivery(org, event.id, update.workItemId, async () => {
|
|
586
|
+
const result = await routeAssignment();
|
|
587
|
+
// Published inside the receipt and lock so a retried delivery cannot repeat it.
|
|
588
|
+
workflowEventBus.emit("azure-devops.work_item.assigned", {
|
|
589
|
+
work_item_id: update.workItemId,
|
|
590
|
+
title: update.revision.fields["System.Title"],
|
|
591
|
+
project: update.revision.fields["System.TeamProject"],
|
|
592
|
+
action: "assigned",
|
|
593
|
+
assigned_to: change.newValue,
|
|
594
|
+
previous_assignee: change.oldValue,
|
|
595
|
+
user_login: update.revisedBy?.uniqueName ?? update.revisedBy?.id,
|
|
596
|
+
});
|
|
597
|
+
return result;
|
|
582
598
|
});
|
|
583
599
|
}
|
|
584
600
|
|
|
@@ -598,31 +614,45 @@ export async function handleWorkItemCommented(
|
|
|
598
614
|
const org = orgFor(event);
|
|
599
615
|
if (!org) return dropUntrustedOrg(event.eventType);
|
|
600
616
|
|
|
617
|
+
const routeComment = async (): Promise<HandlerResult> => {
|
|
618
|
+
const bot = await resolveBot(org.url);
|
|
619
|
+
const actor = parseIdentityString(item.fields["System.ChangedBy"]);
|
|
620
|
+
if (isBotIdentity(actor, bot)) return { created: false };
|
|
621
|
+
|
|
622
|
+
const { mentioned, text } = inspectMention(item.fields["System.History"], bot);
|
|
623
|
+
if (!mentioned) return { created: false };
|
|
624
|
+
|
|
625
|
+
return await routeToTask(
|
|
626
|
+
{
|
|
627
|
+
eventId: event.id,
|
|
628
|
+
eventType: event.eventType,
|
|
629
|
+
workItemId: item.id,
|
|
630
|
+
fields: item.fields,
|
|
631
|
+
org,
|
|
632
|
+
actor,
|
|
633
|
+
},
|
|
634
|
+
"mentioned_comment",
|
|
635
|
+
text,
|
|
636
|
+
);
|
|
637
|
+
};
|
|
638
|
+
|
|
601
639
|
const commentKey = ref ? `comment:${trackerKey(org, item.id)}:${ref.commentId}` : undefined;
|
|
602
640
|
return await handleDelivery(
|
|
603
641
|
org,
|
|
604
642
|
event.id,
|
|
605
643
|
item.id,
|
|
606
644
|
async () => {
|
|
607
|
-
const
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
workItemId: item.id,
|
|
619
|
-
fields: item.fields,
|
|
620
|
-
org,
|
|
621
|
-
actor,
|
|
622
|
-
},
|
|
623
|
-
"mentioned_comment",
|
|
624
|
-
text,
|
|
625
|
-
);
|
|
645
|
+
const result = await routeComment();
|
|
646
|
+
// Published inside the receipt and lock so a retried delivery cannot repeat it.
|
|
647
|
+
workflowEventBus.emit("azure-devops.work_item.commented", {
|
|
648
|
+
work_item_id: item.id,
|
|
649
|
+
title: item.fields["System.Title"],
|
|
650
|
+
project: item.fields["System.TeamProject"],
|
|
651
|
+
action: "commented",
|
|
652
|
+
comment: item.fields["System.History"],
|
|
653
|
+
user_login: item.fields["System.ChangedBy"],
|
|
654
|
+
});
|
|
655
|
+
return result;
|
|
626
656
|
},
|
|
627
657
|
commentKey,
|
|
628
658
|
);
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { getDbClient } from "../be/db";
|
|
2
|
+
import { getTrackerSync } from "../be/db-queries/tracker";
|
|
3
|
+
import { onTaskStarted } from "../be/task-lifecycle-events";
|
|
4
|
+
import type { AgentTask } from "../types";
|
|
5
|
+
import { scrubSecrets } from "../utils/secret-scrubber";
|
|
6
|
+
import { workflowEventBus } from "../workflows/event-bus";
|
|
7
|
+
import { updateWorkItemFields } from "./api";
|
|
8
|
+
|
|
9
|
+
const PROVIDER = "azure-devops";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Target state names are process-specific (Agile Active/Closed, Scrum
|
|
13
|
+
* Committed/Done, Basic Doing/Done), so they are operator-set. Unset or blank
|
|
14
|
+
* means the swarm never changes the work item state.
|
|
15
|
+
*/
|
|
16
|
+
export function getWorkItemState(which: "STARTED" | "DONE"): string | null {
|
|
17
|
+
return process.env[`AZURE_DEVOPS_WORKITEM_STATE_${which}`]?.trim() || null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Move the work item linked to `taskId` to `state`. Tasks without a link are ignored. */
|
|
21
|
+
async function transitionLinkedWorkItem(taskId: string, state: string): Promise<void> {
|
|
22
|
+
const sync = await getTrackerSync(PROVIDER, "task", taskId);
|
|
23
|
+
if (!sync) return;
|
|
24
|
+
// externalId is `{orgKey}#{workItemId}`, orgKey `dev.azure.com/{org}` or `{org}.visualstudio.com`.
|
|
25
|
+
const [orgKey, id] = sync.externalId.split("#");
|
|
26
|
+
const workItemId = Number(id);
|
|
27
|
+
if (!orgKey || !Number.isInteger(workItemId)) return;
|
|
28
|
+
const ok = await updateWorkItemFields(`https://${orgKey}`, workItemId, [
|
|
29
|
+
{ op: "add", path: "/fields/System.State", value: state },
|
|
30
|
+
]);
|
|
31
|
+
if (ok) {
|
|
32
|
+
console.log(
|
|
33
|
+
scrubSecrets(`[AzureDevOps] Work item #${workItemId} -> ${state} (task ${taskId})`),
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const transitionChains = new Map<string, Promise<void>>();
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Run transitions for one task in the order they were requested, so a slow
|
|
42
|
+
* "Doing" PATCH cannot land after "Done". Callers never wait on the chain.
|
|
43
|
+
*/
|
|
44
|
+
function enqueueTransition(taskId: string, state: string, eventName: string): void {
|
|
45
|
+
const run = (transitionChains.get(taskId) ?? Promise.resolve())
|
|
46
|
+
.then(() => transitionLinkedWorkItem(taskId, state))
|
|
47
|
+
.catch((error) => report(eventName, error));
|
|
48
|
+
transitionChains.set(taskId, run);
|
|
49
|
+
void run.then(() => {
|
|
50
|
+
if (transitionChains.get(taskId) === run) transitionChains.delete(taskId);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function report(eventName: string, error: unknown): void {
|
|
55
|
+
console.error(
|
|
56
|
+
`[AzureDevOps Outbound] ${eventName} handler failed:`,
|
|
57
|
+
scrubSecrets(error instanceof Error ? error.message : String(error)),
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function handleTaskStarted(task: AgentTask): void {
|
|
62
|
+
const state = getWorkItemState("STARTED");
|
|
63
|
+
if (state) enqueueTransition(task.id, state, "task.started");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const onTaskCompleted = (data: unknown): void => {
|
|
67
|
+
const { taskId } = (data ?? {}) as { taskId?: string };
|
|
68
|
+
const state = getWorkItemState("DONE");
|
|
69
|
+
if (taskId && state) enqueueTransition(taskId, state, "task.completed");
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
let subscribed = false;
|
|
73
|
+
let startedHookRegistered = false;
|
|
74
|
+
|
|
75
|
+
/** Subscribe work-item state transitions to task lifecycle events. Idempotent, API-server only. */
|
|
76
|
+
export function initAzureDevOpsOutbound(): void {
|
|
77
|
+
if (subscribed) return;
|
|
78
|
+
subscribed = true;
|
|
79
|
+
// onTaskStarted has no unregister, so register once and gate on `subscribed`.
|
|
80
|
+
if (!startedHookRegistered) {
|
|
81
|
+
startedHookRegistered = true;
|
|
82
|
+
onTaskStarted((task) => {
|
|
83
|
+
// startTask/claimTask can emit inside a transaction; a rollback must not reach Azure.
|
|
84
|
+
if (subscribed) getDbClient().afterCommit(() => handleTaskStarted(task));
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
workflowEventBus.on("task.completed", onTaskCompleted);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Unsubscribe from lifecycle events (tests, config reloads). */
|
|
91
|
+
export function teardownAzureDevOpsOutbound(): void {
|
|
92
|
+
if (!subscribed) return;
|
|
93
|
+
subscribed = false;
|
|
94
|
+
workflowEventBus.off("task.completed", onTaskCompleted);
|
|
95
|
+
}
|
package/src/be/boot-seeds.ts
CHANGED
|
@@ -18,10 +18,12 @@
|
|
|
18
18
|
import type { Database } from "bun:sqlite";
|
|
19
19
|
import { getDb } from "./db";
|
|
20
20
|
import { ensureRbacSeedsSynced } from "./rbac-roles";
|
|
21
|
+
import { seedModelProfiles } from "./seed-model-profiles";
|
|
21
22
|
import { seedPricingFromModelsDev } from "./seed-pricing";
|
|
22
23
|
|
|
23
24
|
const pricingSeededDbs = new WeakSet<Database>();
|
|
24
25
|
const rbacSyncedDbs = new WeakSet<Database>();
|
|
26
|
+
const modelProfilesSeededDbs = new WeakSet<Database>();
|
|
25
27
|
|
|
26
28
|
/** Seed the pricing table from the vendored models.dev snapshot. */
|
|
27
29
|
export function ensurePricingSeeded(): void {
|
|
@@ -38,3 +40,12 @@ export function ensureRbacSeeded(): void {
|
|
|
38
40
|
ensureRbacSeedsSynced();
|
|
39
41
|
rbacSyncedDbs.add(db);
|
|
40
42
|
}
|
|
43
|
+
|
|
44
|
+
/** Seed the shipped `<harness>-<tier>` model profiles (src/be/seed-model-profiles.ts). */
|
|
45
|
+
export async function ensureModelProfilesSeeded(): Promise<void> {
|
|
46
|
+
const db = getDb();
|
|
47
|
+
if (modelProfilesSeededDbs.has(db)) return;
|
|
48
|
+
const inserted = await seedModelProfiles();
|
|
49
|
+
if (inserted > 0) console.log(`[startup] Seeded ${inserted} model profiles`);
|
|
50
|
+
modelProfilesSeededDbs.add(db);
|
|
51
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config references: `{ "$config": "KEY" }` leaves inside a JSON config value
|
|
3
|
+
* that point at another config key (usually a secret). Pure, no DB access: the
|
|
4
|
+
* caller supplies the lookup and decides which keys are allowed.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface ConfigRef {
|
|
8
|
+
$config: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** True when `value` is exactly `{ "$config": "<non-empty string>" }`. */
|
|
12
|
+
export function isConfigRef(value: unknown): value is ConfigRef {
|
|
13
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
14
|
+
const keys = Object.keys(value);
|
|
15
|
+
const ref = (value as { $config?: unknown }).$config;
|
|
16
|
+
return keys.length === 1 && keys[0] === "$config" && typeof ref === "string" && ref.length > 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class ConfigRefError extends Error {
|
|
20
|
+
constructor(
|
|
21
|
+
message: string,
|
|
22
|
+
readonly missingKeys: string[],
|
|
23
|
+
) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = "ConfigRefError";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Replace every `{ "$config": "KEY" }` leaf in `value` with `lookup(KEY)`.
|
|
31
|
+
* Walks arrays and plain objects. Missing keys (lookup returns undefined) are
|
|
32
|
+
* collected and reported in one error. A lookup that throws (for example on a
|
|
33
|
+
* forbidden key) propagates as-is.
|
|
34
|
+
*/
|
|
35
|
+
export function resolveConfigRefs<T>(
|
|
36
|
+
value: unknown,
|
|
37
|
+
lookup: (key: string) => string | undefined,
|
|
38
|
+
): T {
|
|
39
|
+
const missing = new Set<string>();
|
|
40
|
+
|
|
41
|
+
const walk = (node: unknown): unknown => {
|
|
42
|
+
if (isConfigRef(node)) {
|
|
43
|
+
const resolved = lookup(node.$config);
|
|
44
|
+
if (resolved === undefined) missing.add(node.$config);
|
|
45
|
+
return resolved;
|
|
46
|
+
}
|
|
47
|
+
if (Array.isArray(node)) return node.map(walk);
|
|
48
|
+
if (node !== null && typeof node === "object") {
|
|
49
|
+
return Object.fromEntries(Object.entries(node).map(([k, v]) => [k, walk(v)]));
|
|
50
|
+
}
|
|
51
|
+
return node;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const result = walk(value);
|
|
55
|
+
if (missing.size > 0) {
|
|
56
|
+
const keys = [...missing].sort();
|
|
57
|
+
throw new ConfigRefError(`Unresolved config reference(s): ${keys.join(", ")}`, keys);
|
|
58
|
+
}
|
|
59
|
+
return result as T;
|
|
60
|
+
}
|