@desplega.ai/agent-swarm 1.172.0 → 2.0.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-fpecx1g1.js → acp-adapter-sj2g0m84.js} +18 -17
- package/dist/{actions-pw87a1a8.js → actions-fegk44gr.js} +65 -35
- package/dist/{amp-adapter-8jem2bc0.js → amp-adapter-ad8ft89x.js} +8 -7
- package/dist/{anthropic-messages-8ee2f22q.js → anthropic-messages-r6czkjv1.js} +7 -7
- package/dist/{app-wmf0m843.js → app-kfvgbvzy.js} +19 -13
- package/dist/{assistant-emp1e108.js → assistant-z7zdy9ja.js} +65 -38
- package/dist/{boot-reembed-1de4f4aj.js → boot-reembed-5c2z0mbe.js} +11 -9
- package/dist/{boot-reembed-4ymn9atn.js → boot-reembed-j8xa181e.js} +11 -9
- package/dist/{boot-scrub-sweep-adhk1s8c.js → boot-scrub-sweep-hnkn3rgt.js} +12 -10
- package/dist/{boot-seeds-8q637aew.js → boot-seeds-kwjq4d2z.js} +15 -13
- package/dist/{claude-adapter-t26cv8a4.js → claude-adapter-9vmvpvgd.js} +20 -19
- package/dist/{claude-managed-adapter-xgxhqrt2.js → claude-managed-adapter-k9qae05j.js} +7 -5
- package/dist/{claude-managed-setup-bnmjarjc.js → claude-managed-setup-q54zx5q2.js} +6 -4
- package/dist/{claude-sdk-session-gsfsh662.js → claude-sdk-session-9jye6cxr.js} +12698 -11995
- package/dist/{cli-k46r9hmk.js → cli-03gedhng.js} +16 -14
- package/dist/{cli-kb4ehzx5.js → cli-1e4b6bzh.js} +7 -7
- package/dist/{cli-d603qf86.js → cli-29jc5q7w.js} +10 -8
- package/dist/cli-2m1ktfzz.js +17795 -0
- package/dist/{cli-8vs9trd4.js → cli-3dj8k4vy.js} +1 -1
- package/dist/{cli-zxm9p3x4.js → cli-3fbmmawm.js} +5 -5
- package/dist/{cli-gmdajfw5.js → cli-4jxm2qtz.js} +4987 -1708
- package/dist/{cli-tadfgd0t.js → cli-5hkm7whv.js} +33 -4
- package/dist/{cli-6jb2rf77.js → cli-5t4f29ez.js} +3 -3
- package/dist/{cli-7a0sde2x.js → cli-6cagzc96.js} +9 -0
- package/dist/cli-6cvfxs8r.js +47 -0
- package/dist/{cli-pj6x9qce.js → cli-6jyj59nb.js} +2 -2
- package/dist/{cli-388egyf6.js → cli-6razj6t4.js} +2 -2
- package/dist/{cli-qsztpfry.js → cli-74ahz61x.js} +2 -2
- package/dist/{cli-4nz8p1p5.js → cli-7x0g4sn1.js} +15474 -16082
- package/dist/{cli-yatxqynm.js → cli-9ha6hs2d.js} +1 -290
- package/dist/{cli-81r1wjyv.js → cli-9nfx44eh.js} +1 -1
- package/dist/cli-9traj3dn.js +638 -0
- package/dist/{cli-smcrrmhy.js → cli-agzebbd5.js} +9 -9
- package/dist/{cli-bf7485pm.js → cli-apx87jne.js} +2 -2
- package/dist/{cli-ztrv9y21.js → cli-bzszjf2p.js} +3689 -1081
- package/dist/{cli-c5km5znr.js → cli-c8r3kzzb.js} +1 -1
- package/dist/{cli-hsem16hb.js → cli-cgtksawx.js} +7 -4
- package/dist/{cli-db3m6zdt.js → cli-d2qr7aj4.js} +1 -1
- package/dist/{cli-1hgat6pa.js → cli-d5f9ed5c.js} +5 -5
- package/dist/cli-e3g5mbkz.js +776 -0
- package/dist/{cli-7jykv7ef.js → cli-e6mpjhed.js} +1 -1
- package/dist/{cli-j6kpj9az.js → cli-ee9gtz70.js} +1553 -68
- package/dist/{cli-e0a9sk00.js → cli-eejsgvm4.js} +4 -4
- package/dist/{cli-tgpfnm6r.js → cli-ef1hg1wv.js} +518 -59
- package/dist/cli-f527ce74.js +781 -0
- package/dist/{cli-ppy4nnnh.js → cli-f7kr7svz.js} +2 -2
- package/dist/cli-hjwmhcg1.js +10622 -0
- package/dist/{cli-2bw3w47j.js → cli-hnhtk6cj.js} +1 -1
- package/dist/{cli-ywm1azg9.js → cli-hnmhtzvh.js} +6 -4
- package/dist/{cli-4fnb6884.js → cli-hvqbtna4.js} +7 -1259
- package/dist/{cli-pstq9888.js → cli-j0pfptdp.js} +220 -103
- package/dist/cli-jta2eyzc.js +619 -0
- package/dist/{cli-esnpehf5.js → cli-k382tshb.js} +12 -13
- package/dist/cli-k3dp5tpf.js +263 -0
- package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
- package/dist/cli-kceah1eh.js +92 -0
- package/dist/{cli-prrt9fa0.js → cli-ke896fcf.js} +10 -10
- package/dist/{cli-nv4zd0b9.js → cli-kt6zqg0e.js} +6 -6
- package/dist/{cli-g6t9texm.js → cli-m50t4309.js} +5 -18
- package/dist/cli-n2wq4j7m.js +6985 -0
- package/dist/{cli-c2pq2rjb.js → cli-n3hzg89b.js} +46 -15
- package/dist/{cli-tmhsxhb8.js → cli-n5vwg842.js} +23 -6
- package/dist/{cli-5rv1j9ga.js → cli-ne236afy.js} +53 -7
- package/dist/cli-p0sg24zp.js +16 -0
- package/dist/{cli-d161g69q.js → cli-p1x85d2t.js} +50 -2
- package/dist/{cli-7pz3b7x5.js → cli-przpmdgr.js} +25 -0
- package/dist/{cli-g4f5pj26.js → cli-q0ke1yww.js} +111 -25
- package/dist/{cli-e3pmyt39.js → cli-q50942rs.js} +1 -1
- package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
- package/dist/{cli-gj81e47t.js → cli-r2pnvj8g.js} +2 -2
- package/dist/{cli-r8smj8b8.js → cli-r62a35ea.js} +19 -3
- package/dist/{cli-cd0hv9nh.js → cli-ra0xzggj.js} +2 -2
- package/dist/cli-rhs9pz33.js +294 -0
- package/dist/{cli-nyhb1r6x.js → cli-s2sp957d.js} +52 -29
- package/dist/{cli-1x7da0de.js → cli-s4setq91.js} +8 -8
- package/dist/{cli-xczpdp9e.js → cli-se8w6wny.js} +6 -6
- package/dist/cli-skxvvpap.js +10140 -0
- package/dist/{cli-014vns2y.js → cli-stfs0k5s.js} +208 -525
- package/dist/{cli-0p3enk35.js → cli-tqaazemc.js} +9 -1
- package/dist/{cli-cf69s3ew.js → cli-tr4sxp68.js} +3 -3
- package/dist/{cli-8hzfb6xz.js → cli-tsde1hdr.js} +15 -15
- package/dist/{cli-cceskcvt.js → cli-txqb9s38.js} +8 -8
- package/dist/{cli-aspcaef3.js → cli-v1yb0rqb.js} +6 -6
- package/dist/{cli-j1pmc07z.js → cli-vatyhshy.js} +268 -40
- package/dist/{cli-04emfe2q.js → cli-vdach5a9.js} +5 -5
- package/dist/{cli-7avy4v8w.js → cli-w1q7h2r2.js} +5 -3
- package/dist/{cli-rcp5aqdw.js → cli-w7m81tb7.js} +1 -1
- package/dist/{cli-hwwvy36w.js → cli-wayw93nt.js} +3 -3
- package/dist/cli-wmgrkscj.js +23254 -0
- package/dist/{cli-gp1rtyvk.js → cli-z5jjpaxw.js} +29 -6
- package/dist/{cli-451ks6aw.js → cli-zkpks3r3.js} +1 -1
- package/dist/cli.js +32 -48
- package/dist/{codex-adapter-m4tgdysy.js → codex-adapter-y81sssk0.js} +16 -15
- package/dist/{codex-login-841kv5fk.js → codex-login-f2rcfpp9.js} +3 -2
- package/dist/{codex-session-runner-ymwzm6ea.js → codex-session-runner-8vx4j6a9.js} +16 -15
- package/dist/{commands-n0hshcvs.js → commands-kcpvpcrr.js} +21 -10
- package/dist/{controller-hq5ggpcp.js → controller-ywrmt6yd.js} +5 -4
- package/dist/{controllers-connect-y07cqcvy.js → controllers-connect-kwpvj3rf.js} +45 -38
- package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-cehv1qns.js} +7 -6
- package/dist/{db-hkqvrdcb.js → db-k8ankj20.js} +13 -11
- package/dist/{db-4w7tmt1g.js → db-ww5d7jq3.js} +29 -9
- package/dist/{devin-adapter-xgtj680j.js → devin-adapter-x1022qb1.js} +3 -2
- package/dist/{dispatcher-5sd69y14.js → dispatcher-e8gq5m68.js} +41 -34
- package/dist/{docker-f503k9p0.js → docker-ff6y1190.js} +3 -2
- package/dist/{dsh-adapter-2h8m4cab.js → dsh-adapter-3epjm3af.js} +7 -6
- package/dist/{e2b-66xra4az.js → e2b-8ygwhg0f.js} +4 -3
- package/dist/{e2b-xwhyj8cw.js → e2b-swhnpw3n.js} +4 -3
- package/dist/{event-bus-vjtv82gm.js → event-bus-6axnngdj.js} +3 -2
- package/dist/external-channel-h3359cwn.js +52 -0
- package/dist/{google-generative-ai-7pavrbv7.js → google-generative-ai-g8db7x0f.js} +5 -3
- package/dist/{google-vertex-3f1jk41f.js → google-vertex-r2692q0r.js} +5 -3
- package/dist/{grok-adapter-8m9yqzbq.js → grok-adapter-0d4x7gkx.js} +19 -18
- package/dist/{handlers-s20xr10r.js → handlers-an1gzv21.js} +44 -37
- package/dist/{heartbeat-3k31q4g2.js → heartbeat-6dakeb61.js} +46 -39
- package/dist/{hook-gdn6a2fn.js → hook-6v6cv6d5.js} +12 -24
- package/dist/{hook-ygwerrdh.js → hook-sa5xye4y.js} +13 -12
- package/dist/{http-jdteeg81.js → http-r7f3eky0.js} +1598 -279
- package/dist/index-52j1aja4.js +3465 -0
- package/dist/{index-e0snym4t.js → index-7ep4gzdk.js} +41 -34
- 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-vm3bm9t7.js → index-rmpw9a8q.js} +41 -34
- package/dist/{index-6ksewd5y.js → index-s2wxgzr0.js} +1015 -732
- package/dist/{index-tsszt7g9.js → index-v1v6n7hg.js} +46 -39
- package/dist/index-we27kd31.js +12810 -0
- package/dist/{index-ffqzqgwb.js → index-zk96aq1k.js} +11 -9
- package/dist/{keepalive-jekc896t.js → keepalive-be9vwy5h.js} +13 -11
- package/dist/{lead-4k9s9szx.js → lead-0861cwrf.js} +64 -57
- package/dist/{maintenance-shazch4n.js → maintenance-mzzgc8bn.js} +11 -9
- package/dist/node-c9we95xf.js +1 -1
- package/dist/{node-fkajaq96.js → node-mn1zs7an.js} +2 -1
- package/dist/{oauth-refresh-sweep-5gb36kn8.js → oauth-refresh-sweep-cpdnfwdj.js} +12 -10
- package/dist/{onboard-ydrbnvww.js → onboard-fh8qs4r3.js} +11 -3
- package/dist/{opencode-adapter-5zh0he20.js → opencode-adapter-nm42wwj8.js} +19 -14
- package/dist/{otel-impl-6pf5cv86.js → otel-impl-x6c1c9g4.js} +248 -869
- package/dist/{pi-mono-adapter-ef9wwx9m.js → pi-mono-adapter-9n2ya240.js} +245 -107
- package/dist/{pricing-refresh-s52nsa5q.js → pricing-refresh-qb0rv0ap.js} +13 -11
- package/dist/{rbac-roles-aq3msh4e.js → rbac-roles-1gzdwbh1.js} +12 -10
- package/dist/{rbac-roles-q5gb5e8v.js → rbac-roles-3mraey52.js} +13 -11
- package/dist/{render-v2-pd1rg54q.js → render-v2-agpa45zz.js} +19 -13
- package/dist/{resume-gw4a2c6v.js → resume-x0ydy9s9.js} +27 -21
- package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
- package/dist/{setup-jda1ksdh.js → setup-as9ga0d6.js} +2 -2
- package/dist/{virtual-modules-b3ga2m65.js → virtual-modules-9gkxqrap.js} +7 -6
- package/dist/{work-objects-tb7ycye8.js → work-objects-y5g1y7ev.js} +49 -37
- package/dist/{worker-njjccz5d.js → worker-860c3e38.js} +64 -57
- package/dist/{x-qfmygqqv.js → x-m477fr0h.js} +3 -2
- package/openapi.json +951 -356
- package/package.json +12 -13
- package/src/apps/catalog.generated.json +1309 -53
- package/src/apps/page-validator.ts +93 -31
- package/src/azure-devops/api.ts +94 -18
- package/src/azure-devops/auth.ts +32 -0
- package/src/azure-devops/boards-sync.ts +708 -0
- package/src/azure-devops/handlers.ts +52 -8
- package/src/azure-devops/html.ts +26 -0
- package/src/azure-devops/index.ts +15 -0
- package/src/azure-devops/templates.ts +86 -0
- package/src/azure-devops/types.ts +65 -1
- package/src/be/config-refs.ts +60 -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 +230 -0
- package/src/be/db/tasks/write.ts +7 -0
- package/src/be/db.ts +74 -13
- package/src/be/migrations/213_script_connections_sql.sql +79 -0
- 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/model-catalog-store.ts +5 -1
- package/src/be/model-tier-resolution.ts +12 -1
- package/src/be/model-validation.ts +5 -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-connections.ts +47 -8
- package/src/be/script-credential-broker.ts +39 -2
- package/src/be/scripts/run-saved.ts +1 -0
- package/src/be/scripts/typecheck.ts +10 -8
- 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-pricing.ts +19 -2
- 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-skills/bundled-files.generated.json +10 -18
- package/src/be/seed-skills/index.ts +107 -3
- package/src/be/sql-connections.ts +118 -0
- 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/profile-sync.ts +5 -3
- package/src/commands/provider-credentials.ts +52 -6
- package/src/commands/runner.ts +196 -56
- package/src/e2b/env.ts +5 -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/post-bridge.ts +40 -0
- package/src/github/handlers.ts +11 -4
- package/src/heartbeat/templates.ts +8 -5
- package/src/hooks/hook.ts +0 -26
- package/src/http/all-routes.ts +0 -1
- package/src/http/config.ts +36 -17
- package/src/http/core.ts +4 -0
- package/src/http/index.ts +14 -2
- package/src/http/integrations.ts +88 -1
- package/src/http/mcp-oauth.ts +6 -13
- package/src/http/mcp.ts +15 -5
- package/src/http/page-proxy.ts +2 -4
- package/src/http/pages-public.ts +6 -5
- package/src/http/pages.ts +5 -14
- package/src/http/poll.ts +28 -68
- package/src/http/requested-by.ts +54 -0
- package/src/http/route-def.ts +7 -6
- package/src/http/script-connection-proxy.ts +51 -4
- package/src/http/script-connections.ts +5 -2
- package/src/http/scripts.ts +1 -0
- package/src/http/session-cost-recompute.ts +12 -2
- package/src/http/session-data.ts +4 -0
- package/src/http/stats.ts +1 -30
- package/src/http/tasks.ts +61 -5
- package/src/http/utils.ts +14 -0
- package/src/http/webhooks.ts +183 -2
- 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/jira/adf.ts +3 -1
- package/src/kv-reserved-namespaces.ts +2 -0
- package/src/oauth/mcp-wrapper.ts +10 -6
- package/src/otel-impl.ts +2 -1
- 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 +27 -2
- package/src/providers/claude-flag-settings.ts +133 -0
- package/src/providers/claude-managed-adapter.ts +1 -1
- package/src/providers/claude-sdk-session.ts +7 -0
- package/src/providers/claude-session-events.ts +6 -1
- package/src/providers/dsh-adapter.ts +1 -1
- package/src/providers/opencode-adapter.ts +268 -37
- package/src/providers/opencode-billing.ts +86 -0
- package/src/providers/opencode-swarm-plugin.ts +51 -0
- package/src/providers/pi-mono-adapter.ts +398 -153
- package/src/providers/pricing-sources.md +37 -3
- package/src/providers/reasoning-effort.ts +27 -0
- package/src/providers/types.ts +11 -2
- package/src/rbac/legacy-policy.ts +8 -2
- package/src/rbac/permissions.ts +21 -0
- package/src/scheduler/scheduler.ts +4 -2
- package/src/scripts-runtime/api-client.ts +15 -1
- package/src/scripts-runtime/api-types.ts +9 -1
- package/src/scripts-runtime/ctx.ts +1 -1
- package/src/scripts-runtime/loader.ts +19 -7
- package/src/scripts-runtime/mcp-client.ts +30 -19
- package/src/scripts-runtime/sdk-allowlist.ts +8 -6
- package/src/scripts-runtime/swarm-sdk.ts +0 -11
- package/src/scripts-runtime/types/stdlib.d.ts +27 -15
- package/src/scripts-runtime/types/swarm-extension.d.ts +63 -1
- package/src/scripts-runtime/types/swarm-sdk.d.ts +27 -15
- package/src/server.ts +52 -18
- package/src/slack/actions.ts +29 -1
- package/src/slack/app.ts +14 -2
- package/src/slack/assistant.ts +36 -2
- package/src/slack/channel-join.ts +3 -16
- package/src/slack/commands.ts +9 -1
- package/src/slack/event-dedup.ts +1 -1
- package/src/slack/external-channel-egress.ts +113 -0
- package/src/slack/external-channel.ts +309 -0
- package/src/slack/handlers.ts +61 -0
- package/src/slack/render-v2.ts +40 -47
- package/src/slack/work-objects.ts +5 -0
- package/src/tasks/additive-buffer.ts +4 -2
- package/src/tasks/context-key.ts +94 -2
- package/src/tasks/model-pin.ts +67 -0
- package/src/tasks/worker-follow-up.ts +4 -31
- package/src/telemetry.ts +2 -1
- package/src/tests/acp-adapter.test.ts +42 -0
- package/src/tests/api-drain-worker-e2e.test.ts +1 -6
- package/src/tests/apps-catalog-feedback.test.ts +310 -0
- package/src/tests/apps-catalog-inputs.test.ts +70 -0
- package/src/tests/apps-catalog-table.test.ts +113 -0
- package/src/tests/azure-devops-boards-sync.test.ts +584 -0
- package/src/tests/azure-devops-html.test.ts +13 -0
- package/src/tests/azure-devops-webhook-malformed.test.ts +4 -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 +144 -0
- package/src/tests/claude-flag-settings.test.ts +114 -0
- package/src/tests/claude-managed-adapter.test.ts +1 -1
- package/src/tests/claude-sdk-lifecycle.test.ts +148 -1
- package/src/tests/claude-sdk-process.fixture.ts +7 -0
- 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 +51 -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 +20 -0
- package/src/tests/db-task-write-contract.test.ts +10 -0
- package/src/tests/deferred-task-wake.test.ts +52 -4
- 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/explicit-model-validation.test.ts +105 -1
- package/src/tests/extensions-example-route-chat-channel.test.ts +154 -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/azure-boards/workitem.commented.json +89 -0
- package/src/tests/fixtures/azure-boards/workitem.created.json +81 -0
- package/src/tests/fixtures/azure-boards/workitem.deleted.json +70 -0
- package/src/tests/fixtures/azure-boards/workitem.restored.json +82 -0
- package/src/tests/fixtures/azure-boards/workitem.updated.json +130 -0
- package/src/tests/fixtures/catalog-feedback-definition.json.txt +860 -0
- package/src/tests/fixtures/catalog-inputs-definition.json.txt +910 -0
- package/src/tests/fixtures/catalog-table-definition.json.txt +468 -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-identity-refresh.ts +3 -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/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-tier-resolution.test.ts +93 -0
- package/src/tests/models-catalog.test.ts +42 -1
- package/src/tests/node-env-runtime.test.ts +98 -0
- 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 +348 -3
- package/src/tests/opencode-billing.test.ts +28 -0
- 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.test.ts +1 -1
- package/src/tests/paused-tasks-requested-by.test.ts +102 -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/prompt-template-remaining.test.ts +35 -0
- package/src/tests/rbac-engine.test.ts +11 -3
- package/src/tests/runner-exit-after-tasks.test.ts +0 -4
- package/src/tests/runner-identity-refresh.test.ts +3 -0
- package/src/tests/runner-legacy-resume-prompt.test.ts +64 -0
- package/src/tests/script-connections-sql.test.ts +675 -0
- package/src/tests/script-connections.test.ts +7 -1
- package/src/tests/scripts-http.test.ts +201 -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 +86 -0
- 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 +94 -0
- package/src/tests/skill-get-name-resolution.test.ts +137 -0
- package/src/tests/slack-channel-join.test.ts +4 -1
- package/src/tests/slack-external-channel-config.test.ts +65 -0
- package/src/tests/slack-external-channel-egress.test.ts +237 -0
- package/src/tests/slack-external-channel-guard.test.ts +280 -0
- package/src/tests/slack-external-channel-tools.test.ts +173 -0
- package/src/tests/slack-external-channel.test.ts +370 -0
- package/src/tests/slack-render-v2.test.ts +86 -10
- package/src/tests/sonnet-5-5-registry.test.ts +9 -1
- package/src/tests/spec-base-url.test.ts +16 -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/vendored-openapi.test.ts +16 -1
- package/src/tests/vercel-ai-gateway.test.ts +149 -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/defer-task.ts +17 -0
- package/src/tools/model-catalog/index.ts +2 -1
- package/src/tools/register-chat-channel.ts +139 -0
- package/src/tools/send-task.ts +24 -0
- package/src/tools/skills/skill-get.ts +17 -9
- package/src/tools/slack-post.ts +6 -0
- package/src/tools/slack-read.ts +8 -0
- package/src/tools/slack-reply.ts +6 -0
- package/src/tools/slack-start-thread.ts +6 -0
- package/src/tools/slack-update.ts +6 -0
- package/src/tools/slack-upload-file.ts +6 -0
- 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/tool-config.ts +8 -6
- package/src/types.ts +12 -2
- 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/node-env.ts +24 -0
- package/src/utils/runtime-model-catalog.ts +11 -1
- package/src/utils/secret-scrubber.ts +71 -2
- package/src/utils/task-tool-manifest.ts +19 -2
- package/src/workflows/executors/swarm-script.ts +1 -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 +749 -0
- package/templates/skills/apps/content.md +60 -22
- 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/qa-loom/config.json +14 -0
- package/templates/skills/qa-loom/content.md +187 -0
- package/templates/skills/qa-loom/files/build-loom.mjs +221 -0
- package/templates/skills/qa-loom/files/run-qa.sh +57 -0
- package/templates/skills/slack-interaction/content.md +4 -0
- 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-9xsmdpdt.js +0 -56377
- package/dist/cli-bd957dgb.js +0 -153
- package/dist/cli-q51yprfq.js +0 -1104
- package/dist/cli-t1ze64h3.js +0 -811
- 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/dist/{azure-openai-responses-ap1gwxgr.js → azure-openai-responses-ygfreq4t.js} +5 -5
- package/dist/{cli-5rqrj7q0.js → cli-pw7ebjdt.js} +0 -0
- package/dist/{openai-codex-responses-33qhkkdy.js → openai-codex-responses-3bk0grnr.js} +4 -4
- package/dist/{openai-completions-s88xm3ns.js → openai-completions-5d4jpakc.js} +9 -9
- package/dist/{openai-responses-7xd2f2e2.js → openai-responses-krb51f59.js} +5 -5
- package/dist/{pi-messages-xszk613n.js → pi-messages-x9gzynm1.js} +3 -3
- /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
- /package/src/{artifact-sdk → pages}/feedback-overlay.ts +0 -0
|
@@ -42,19 +42,50 @@ export const ELEMENT_KEYS = new Set([
|
|
|
42
42
|
"repeat",
|
|
43
43
|
"watch",
|
|
44
44
|
]);
|
|
45
|
-
const UI_STATE_COMPONENTS = new Set(["SearchInput", "Select", "Tabs"]);
|
|
45
|
+
const UI_STATE_COMPONENTS = new Set(["SearchInput", "Select", "Tabs", "Chips"]);
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* Props that hold a plain action chain (an array of `{ action, params }`),
|
|
49
|
-
* keyed by component type.
|
|
50
|
-
*
|
|
49
|
+
* keyed by component type. Chains nested one level deeper (an array prop
|
|
50
|
+
* whose items each carry a chain) are listed in `ITEM_ACTION_CHAINS`.
|
|
51
51
|
*/
|
|
52
52
|
const PROP_ACTION_CHAINS: Record<string, readonly string[]> = {
|
|
53
|
+
Table: ["onRowClick"],
|
|
53
54
|
Form: ["onSubmit"],
|
|
54
55
|
Kanban: ["onMove", "onCardClick"],
|
|
55
56
|
Calendar: ["onSelect"],
|
|
56
57
|
};
|
|
57
58
|
|
|
59
|
+
/**
|
|
60
|
+
* `[arrayProp, chainKey]` pairs: every item of `props[arrayProp]` carries an
|
|
61
|
+
* action chain under `chainKey` (Table `rowActions[].actions`, Table
|
|
62
|
+
* `columns[].onChange`, Drawer footer `actions[].actions`).
|
|
63
|
+
*/
|
|
64
|
+
const ITEM_ACTION_CHAINS: Record<string, readonly (readonly [string, string])[]> = {
|
|
65
|
+
Table: [
|
|
66
|
+
["rowActions", "actions"],
|
|
67
|
+
["columns", "onChange"],
|
|
68
|
+
],
|
|
69
|
+
Drawer: [["actions", "actions"]],
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/** Every `[path, chain]` nested in an element's item-chain props. */
|
|
73
|
+
function itemActionChains(type: unknown, props: Record<string, unknown>, propsPath: string) {
|
|
74
|
+
const chains: { path: string; chain: unknown }[] = [];
|
|
75
|
+
for (const [arrayProp, chainKey] of ITEM_ACTION_CHAINS[String(type)] ?? []) {
|
|
76
|
+
const items = props[arrayProp];
|
|
77
|
+
if (!Array.isArray(items)) continue;
|
|
78
|
+
for (const [index, item] of items.entries()) {
|
|
79
|
+
if (!isPlainObject(item) || !Object.hasOwn(item, chainKey)) continue;
|
|
80
|
+
chains.push({
|
|
81
|
+
path: `${propsPath}.${arrayProp}.${index}.${chainKey}`,
|
|
82
|
+
chain: item[chainKey],
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return chains;
|
|
87
|
+
}
|
|
88
|
+
|
|
58
89
|
/** Props naming a row field of the bound `data` query's model, per type. */
|
|
59
90
|
const DATA_FIELD_PROPS: Record<string, readonly string[]> = {
|
|
60
91
|
Kanban: ["columnField", "titleField", "idField"],
|
|
@@ -373,14 +404,17 @@ function actionParams(
|
|
|
373
404
|
}
|
|
374
405
|
if (op === "update" || op === "delete") {
|
|
375
406
|
const rowId = params.rowId;
|
|
407
|
+
// A `$state` binding is the Drawer-footer shape: the open record's id
|
|
408
|
+
// lives at `/route/params/<param>` (both chain runners resolve it).
|
|
376
409
|
const validRowId =
|
|
377
410
|
typeof rowId === "string" ||
|
|
411
|
+
isStateBinding(rowId) ||
|
|
378
412
|
(isPlainObject(rowId) && typeof rowId.$row === "string" && Object.keys(rowId).length === 1);
|
|
379
413
|
if (!validRowId) {
|
|
380
414
|
result.issues.push(
|
|
381
415
|
issue(
|
|
382
416
|
appendPath(paramsPath, "rowId"),
|
|
383
|
-
"is required for update and delete and must be a string or $
|
|
417
|
+
"is required for update and delete and must be a string, $row, or $state binding",
|
|
384
418
|
),
|
|
385
419
|
);
|
|
386
420
|
}
|
|
@@ -416,6 +450,20 @@ function actionParams(
|
|
|
416
450
|
issue(appendPath(paramsPath, "name"), `unknown app action "${String(params.name)}"`),
|
|
417
451
|
);
|
|
418
452
|
}
|
|
453
|
+
} else if (step.action === "ui.toast") {
|
|
454
|
+
// The Undo chain runs through the same handlers as any other chain, so
|
|
455
|
+
// its steps get the same per-action checks (models, queries, actions).
|
|
456
|
+
const undo = toastUndoChain(step);
|
|
457
|
+
if (Array.isArray(undo)) {
|
|
458
|
+
const undoResult = validateActionChain(
|
|
459
|
+
undo,
|
|
460
|
+
appendPath(appendPath(paramsPath, "undo"), "actions"),
|
|
461
|
+
definition,
|
|
462
|
+
catalog,
|
|
463
|
+
);
|
|
464
|
+
result.issues.push(...undoResult.issues);
|
|
465
|
+
result.stateRefs.push(...undoResult.stateRefs);
|
|
466
|
+
}
|
|
419
467
|
}
|
|
420
468
|
|
|
421
469
|
return result;
|
|
@@ -689,10 +737,22 @@ function visitActionChain(
|
|
|
689
737
|
const normalized = allowSingle && isPlainObject(chain) ? [chain] : chain;
|
|
690
738
|
if (!Array.isArray(normalized)) return;
|
|
691
739
|
for (const [index, step] of normalized.entries()) {
|
|
692
|
-
if (isPlainObject(step))
|
|
740
|
+
if (!isPlainObject(step)) continue;
|
|
741
|
+
const stepPath = appendPath(path, index);
|
|
742
|
+
visit(step, stepPath);
|
|
743
|
+
// `ui.toast` nests a whole chain (the Undo button) inside its params.
|
|
744
|
+
const undo = toastUndoChain(step);
|
|
745
|
+
if (undo !== undefined) visitActionChain(undo, `${stepPath}.params.undo.actions`, visit, false);
|
|
693
746
|
}
|
|
694
747
|
}
|
|
695
748
|
|
|
749
|
+
/** The `undo.actions` chain of a `ui.toast` step, when it has one. */
|
|
750
|
+
function toastUndoChain(step: Record<string, unknown>): unknown {
|
|
751
|
+
if (step.action !== "ui.toast" || !isPlainObject(step.params)) return undefined;
|
|
752
|
+
const undo = step.params.undo;
|
|
753
|
+
return isPlainObject(undo) && Object.hasOwn(undo, "actions") ? undo.actions : undefined;
|
|
754
|
+
}
|
|
755
|
+
|
|
696
756
|
function visitPageActionSteps(
|
|
697
757
|
page: ElementTree,
|
|
698
758
|
pagePath: string,
|
|
@@ -712,16 +772,12 @@ function visitPageActionSteps(
|
|
|
712
772
|
}
|
|
713
773
|
|
|
714
774
|
if (!isPlainObject(rawElement.props)) continue;
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
visit,
|
|
722
|
-
false,
|
|
723
|
-
);
|
|
724
|
-
}
|
|
775
|
+
for (const { path, chain } of itemActionChains(
|
|
776
|
+
rawElement.type,
|
|
777
|
+
rawElement.props,
|
|
778
|
+
`${elementPath}.props`,
|
|
779
|
+
)) {
|
|
780
|
+
visitActionChain(chain, path, visit, false);
|
|
725
781
|
}
|
|
726
782
|
for (const prop of PROP_ACTION_CHAINS[String(rawElement.type)] ?? []) {
|
|
727
783
|
visitActionChain(rawElement.props[prop], `${elementPath}.props.${prop}`, visit, false);
|
|
@@ -1251,9 +1307,14 @@ export function validatePage(
|
|
|
1251
1307
|
|
|
1252
1308
|
if (component) {
|
|
1253
1309
|
const propsPath = appendPath(elementPath, "props");
|
|
1310
|
+
const itemChainPaths = new Set(
|
|
1311
|
+
isPlainObject(rawElement.props)
|
|
1312
|
+
? itemActionChains(type, rawElement.props, propsPath).map(({ path }) => path)
|
|
1313
|
+
: [],
|
|
1314
|
+
);
|
|
1254
1315
|
const actionChainPath = (path: string): boolean =>
|
|
1255
1316
|
(PROP_ACTION_CHAINS[String(type)] ?? []).some((prop) => path === `${propsPath}.${prop}`) ||
|
|
1256
|
-
(
|
|
1317
|
+
itemChainPaths.has(path);
|
|
1257
1318
|
const propsResult = validateSchema(
|
|
1258
1319
|
Object.hasOwn(rawElement, "props") ? rawElement.props : {},
|
|
1259
1320
|
component.props,
|
|
@@ -1334,6 +1395,15 @@ export function validatePage(
|
|
|
1334
1395
|
queryModel.model,
|
|
1335
1396
|
issues,
|
|
1336
1397
|
);
|
|
1398
|
+
for (const prop of ["onRowClick", "columns"] as const) {
|
|
1399
|
+
collectRowFieldIssues(
|
|
1400
|
+
rawElement.props[prop],
|
|
1401
|
+
`${elementPath}.props.${prop}`,
|
|
1402
|
+
queryModel.modelName,
|
|
1403
|
+
queryModel.model,
|
|
1404
|
+
issues,
|
|
1405
|
+
);
|
|
1406
|
+
}
|
|
1337
1407
|
}
|
|
1338
1408
|
} else if (type === "DetailList") {
|
|
1339
1409
|
const queryModel = queryModelFromDataBinding(definition, rawElement.props.data);
|
|
@@ -1479,24 +1549,16 @@ export function validatePage(
|
|
|
1479
1549
|
}
|
|
1480
1550
|
}
|
|
1481
1551
|
|
|
1482
|
-
if (
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
const chainResult = validateActionChain(
|
|
1490
|
-
rowAction.actions,
|
|
1491
|
-
`${elementPath}.props.rowActions.${rowActionIndex}.actions`,
|
|
1492
|
-
definition,
|
|
1493
|
-
catalog,
|
|
1494
|
-
);
|
|
1552
|
+
if (isPlainObject(rawElement.props)) {
|
|
1553
|
+
for (const { path, chain } of itemActionChains(
|
|
1554
|
+
type,
|
|
1555
|
+
rawElement.props,
|
|
1556
|
+
`${elementPath}.props`,
|
|
1557
|
+
)) {
|
|
1558
|
+
const chainResult = validateActionChain(chain, path, definition, catalog);
|
|
1495
1559
|
issues.push(...chainResult.issues);
|
|
1496
1560
|
stateRefs.push(...chainResult.stateRefs);
|
|
1497
1561
|
}
|
|
1498
|
-
}
|
|
1499
|
-
if (isPlainObject(rawElement.props)) {
|
|
1500
1562
|
for (const prop of PROP_ACTION_CHAINS[String(type)] ?? []) {
|
|
1501
1563
|
if (!Object.hasOwn(rawElement.props, prop)) continue;
|
|
1502
1564
|
const chainResult = validateActionChain(
|
package/src/azure-devops/api.ts
CHANGED
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
* and resolving the bot identity behind the PAT. Uses raw fetch, no SDK.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
getAzureDevOpsOrgUrl,
|
|
8
|
+
getAzureDevOpsToken,
|
|
9
|
+
isTrustedOrgUrl,
|
|
10
|
+
normalizeOrgUrl,
|
|
11
|
+
} from "./auth";
|
|
7
12
|
|
|
8
13
|
const API_VERSION = "7.1";
|
|
9
14
|
|
|
@@ -32,7 +37,55 @@ function pullRequestBase(ref: AzureDevOpsPullRequestRef): string {
|
|
|
32
37
|
);
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
|
|
40
|
+
interface BotIdentity {
|
|
41
|
+
id: string | null;
|
|
42
|
+
uniqueName: string | null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** A transient failure resolving the bot identity; the caller should let the delivery be retried. */
|
|
46
|
+
export class AzureDevOpsLookupError extends Error {}
|
|
47
|
+
|
|
48
|
+
let cachedBotIdentity: { orgUrl: string; identity: BotIdentity } | null = null;
|
|
49
|
+
|
|
50
|
+
/** Org URL to query, or null when there is none or it is not safe to send the PAT to. */
|
|
51
|
+
function credentialedOrgUrl(orgBaseUrl: string | null | undefined): string | null {
|
|
52
|
+
const orgUrl = normalizeOrgUrl(orgBaseUrl) ?? getAzureDevOpsOrgUrl();
|
|
53
|
+
if (!orgUrl || !getAzureDevOpsToken()) return null;
|
|
54
|
+
if (!isTrustedOrgUrl(orgUrl)) {
|
|
55
|
+
console.error("[AzureDevOps] Refusing to send credentials to an untrusted organization URL");
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return orgUrl;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* `_apis/connectionData` of the identity that owns the PAT, cached per org.
|
|
63
|
+
* Throws AzureDevOpsLookupError on a failed request. Redirects are refused so
|
|
64
|
+
* the PAT never follows a response to another host.
|
|
65
|
+
*/
|
|
66
|
+
async function loadBotIdentity(orgUrl: string): Promise<BotIdentity> {
|
|
67
|
+
if (cachedBotIdentity?.orgUrl === orgUrl) return cachedBotIdentity.identity;
|
|
68
|
+
let data: {
|
|
69
|
+
authenticatedUser?: { id?: string; properties?: { Account?: { $value?: string } } };
|
|
70
|
+
};
|
|
71
|
+
try {
|
|
72
|
+
const resp = await fetch(`${orgUrl}/_apis/connectionData`, {
|
|
73
|
+
headers: headers(),
|
|
74
|
+
redirect: "error",
|
|
75
|
+
});
|
|
76
|
+
if (!resp.ok) throw new AzureDevOpsLookupError(`connectionData returned ${resp.status}`);
|
|
77
|
+
data = (await resp.json()) as typeof data;
|
|
78
|
+
} catch (err) {
|
|
79
|
+
if (err instanceof AzureDevOpsLookupError) throw err;
|
|
80
|
+
throw new AzureDevOpsLookupError(`connectionData request failed: ${String(err)}`);
|
|
81
|
+
}
|
|
82
|
+
const identity = {
|
|
83
|
+
id: data.authenticatedUser?.id ?? null,
|
|
84
|
+
uniqueName: data.authenticatedUser?.properties?.Account?.$value?.trim() || null,
|
|
85
|
+
};
|
|
86
|
+
if (identity.id || identity.uniqueName) cachedBotIdentity = { orgUrl, identity };
|
|
87
|
+
return identity;
|
|
88
|
+
}
|
|
36
89
|
|
|
37
90
|
/**
|
|
38
91
|
* Identity GUID of the bot. A picker @mention is stored as `@<GUID>` in the
|
|
@@ -46,31 +99,54 @@ export async function resolveAzureDevOpsBotId(
|
|
|
46
99
|
): Promise<string | null> {
|
|
47
100
|
const fromEnv = process.env.AZURE_DEVOPS_BOT_ID?.trim();
|
|
48
101
|
if (fromEnv) return fromEnv;
|
|
102
|
+
const orgUrl = credentialedOrgUrl(orgBaseUrl);
|
|
103
|
+
if (!orgUrl) return null;
|
|
104
|
+
try {
|
|
105
|
+
return (await loadBotIdentity(orgUrl)).id;
|
|
106
|
+
} catch (err) {
|
|
107
|
+
console.error(`[AzureDevOps] Failed to resolve bot identity:`, err);
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
49
111
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
112
|
+
/**
|
|
113
|
+
* Sign-in name (usually the email) of the identity that owns the PAT, from
|
|
114
|
+
* `_apis/connectionData` (`authenticatedUser.properties.Account.$value`),
|
|
115
|
+
* cached per org. Work-item payloads carry people as the string
|
|
116
|
+
* `"Display Name <unique@name>"` with no GUID, so this is what identifies the
|
|
117
|
+
* bot in `System.AssignedTo`. Returns null when it cannot be resolved.
|
|
118
|
+
*/
|
|
119
|
+
export async function resolveAzureDevOpsBotUniqueName(
|
|
120
|
+
orgBaseUrl: string | null | undefined,
|
|
121
|
+
): Promise<string | null> {
|
|
122
|
+
const orgUrl = credentialedOrgUrl(orgBaseUrl);
|
|
123
|
+
if (!orgUrl) return null;
|
|
54
124
|
try {
|
|
55
|
-
|
|
56
|
-
if (!resp.ok) {
|
|
57
|
-
console.error(`[AzureDevOps] Failed to resolve bot identity: ${resp.status}`);
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
const data = (await resp.json()) as { authenticatedUser?: { id?: string } };
|
|
61
|
-
const id = data.authenticatedUser?.id;
|
|
62
|
-
if (!id) return null;
|
|
63
|
-
cachedBotId = { orgUrl, id };
|
|
64
|
-
return id;
|
|
125
|
+
return (await loadBotIdentity(orgUrl)).uniqueName;
|
|
65
126
|
} catch (err) {
|
|
66
|
-
console.error(`[AzureDevOps]
|
|
127
|
+
console.error(`[AzureDevOps] Failed to resolve bot sign-in name:`, err);
|
|
67
128
|
return null;
|
|
68
129
|
}
|
|
69
130
|
}
|
|
70
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Both bot identifiers in one lookup, for work-item handlers. Unlike the
|
|
134
|
+
* helpers above, a failed request throws AzureDevOpsLookupError instead of
|
|
135
|
+
* degrading to null, so a transient outage makes the delivery retryable.
|
|
136
|
+
*/
|
|
137
|
+
export async function resolveAzureDevOpsBotIdentity(
|
|
138
|
+
orgBaseUrl: string | null | undefined,
|
|
139
|
+
): Promise<BotIdentity> {
|
|
140
|
+
const fromEnv = process.env.AZURE_DEVOPS_BOT_ID?.trim() || null;
|
|
141
|
+
const orgUrl = credentialedOrgUrl(orgBaseUrl);
|
|
142
|
+
if (!orgUrl) return { id: fromEnv, uniqueName: null };
|
|
143
|
+
const identity = await loadBotIdentity(orgUrl);
|
|
144
|
+
return { id: fromEnv ?? identity.id, uniqueName: identity.uniqueName };
|
|
145
|
+
}
|
|
146
|
+
|
|
71
147
|
/** Reset the cached bot identity (tests, config reloads). */
|
|
72
148
|
export function resetAzureDevOpsBotIdCache(): void {
|
|
73
|
-
|
|
149
|
+
cachedBotIdentity = null;
|
|
74
150
|
}
|
|
75
151
|
|
|
76
152
|
/**
|
package/src/azure-devops/auth.ts
CHANGED
|
@@ -66,6 +66,38 @@ export function normalizeOrgUrl(url: string | null | undefined): string | null {
|
|
|
66
66
|
return trimmed ? trimmed : null;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Organization identity of an Azure DevOps URL: `dev.azure.com/{org}` or the
|
|
71
|
+
* `{org}.visualstudio.com` host, lowercased. Null for anything that is not a
|
|
72
|
+
* plain HTTPS URL, so credentials are never attached to it.
|
|
73
|
+
*/
|
|
74
|
+
export function orgKeyOf(url: string | null | undefined): string | null {
|
|
75
|
+
if (!url) return null;
|
|
76
|
+
let parsed: URL;
|
|
77
|
+
try {
|
|
78
|
+
parsed = new URL(url);
|
|
79
|
+
} catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
if (parsed.protocol !== "https:" || parsed.username || parsed.password) return null;
|
|
83
|
+
const host = parsed.host.toLowerCase();
|
|
84
|
+
if (host !== "dev.azure.com") return host;
|
|
85
|
+
const org = parsed.pathname.split("/").find(Boolean);
|
|
86
|
+
return org ? `${host}/${org.toLowerCase()}` : null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Whether the PAT may be sent to `url`. With a configured organization only
|
|
91
|
+
* that organization qualifies; without one, only the public Azure DevOps hosts.
|
|
92
|
+
*/
|
|
93
|
+
export function isTrustedOrgUrl(url: string | null | undefined): boolean {
|
|
94
|
+
const key = orgKeyOf(url);
|
|
95
|
+
if (!key) return false;
|
|
96
|
+
const configured = orgKeyOf(orgUrl);
|
|
97
|
+
if (orgUrl) return key === configured;
|
|
98
|
+
return key.startsWith("dev.azure.com/") || key.endsWith(".visualstudio.com");
|
|
99
|
+
}
|
|
100
|
+
|
|
69
101
|
/** Bot name for plain-text `@name` mentions. */
|
|
70
102
|
export const AZURE_DEVOPS_BOT_NAME = process.env.AZURE_DEVOPS_BOT_NAME ?? "agent-swarm-bot";
|
|
71
103
|
|