@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
|
@@ -1,793 +0,0 @@
|
|
|
1
|
-
import { afterAll, beforeAll, describe, expect, mock, test } from "bun:test";
|
|
2
|
-
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { BROWSER_SDK_JS } from "../artifact-sdk/browser-sdk";
|
|
4
|
-
import { getAvailablePort } from "../artifact-sdk/port";
|
|
5
|
-
import {
|
|
6
|
-
createArtifactServer,
|
|
7
|
-
createBunHonoFetchHandler,
|
|
8
|
-
createBunResponse,
|
|
9
|
-
} from "../artifact-sdk/server";
|
|
10
|
-
import { getBasePrompt } from "../prompts/base-prompt";
|
|
11
|
-
|
|
12
|
-
function restoreEnvValue(key: string, value: string | undefined): void {
|
|
13
|
-
if (value === undefined) delete process.env[key];
|
|
14
|
-
else process.env[key] = value;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// ─── Port allocation tests ──────────────────────────────────────────────
|
|
18
|
-
|
|
19
|
-
describe("getAvailablePort", () => {
|
|
20
|
-
test("returns a valid port number", async () => {
|
|
21
|
-
const port = await getAvailablePort();
|
|
22
|
-
expect(port).toBeGreaterThan(0);
|
|
23
|
-
expect(port).toBeLessThan(65536);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test("returns different ports on consecutive calls", async () => {
|
|
27
|
-
const port1 = await getAvailablePort();
|
|
28
|
-
const port2 = await getAvailablePort();
|
|
29
|
-
expect(port1).not.toBe(port2);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test("returns a port that is actually available", async () => {
|
|
33
|
-
const port = await getAvailablePort();
|
|
34
|
-
// Try to start a Bun server on the port — should succeed
|
|
35
|
-
const server = Bun.serve({
|
|
36
|
-
port,
|
|
37
|
-
fetch: () => createBunResponse("ok"),
|
|
38
|
-
});
|
|
39
|
-
expect(server.port).toBe(port);
|
|
40
|
-
server.stop();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test("returns ports in ephemeral range", async () => {
|
|
44
|
-
const ports: number[] = [];
|
|
45
|
-
for (let i = 0; i < 5; i++) {
|
|
46
|
-
ports.push(await getAvailablePort());
|
|
47
|
-
}
|
|
48
|
-
// All ports should be in the ephemeral range (typically > 1024)
|
|
49
|
-
for (const p of ports) {
|
|
50
|
-
expect(p).toBeGreaterThan(1024);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test("all returned ports are unique", async () => {
|
|
55
|
-
const ports = new Set<number>();
|
|
56
|
-
for (let i = 0; i < 10; i++) {
|
|
57
|
-
ports.add(await getAvailablePort());
|
|
58
|
-
}
|
|
59
|
-
// Allow minor collisions — OS can recycle ports between bind/release cycles
|
|
60
|
-
expect(ports.size).toBeGreaterThanOrEqual(8);
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
// ─── Browser SDK tests ─────────────────────────────────────────────────
|
|
65
|
-
|
|
66
|
-
describe("BROWSER_SDK_JS", () => {
|
|
67
|
-
test("is a non-empty string", () => {
|
|
68
|
-
expect(typeof BROWSER_SDK_JS).toBe("string");
|
|
69
|
-
expect(BROWSER_SDK_JS.length).toBeGreaterThan(100);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test("contains SwarmSDK class", () => {
|
|
73
|
-
expect(BROWSER_SDK_JS).toContain("class SwarmSDK");
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test("is syntactically valid JavaScript", () => {
|
|
77
|
-
expect(() => new Function(BROWSER_SDK_JS)).not.toThrow();
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
test("exposes the eight canonical domains", () => {
|
|
81
|
-
const expectedDomains = [
|
|
82
|
-
"this.tasks",
|
|
83
|
-
"this.agents",
|
|
84
|
-
"this.events",
|
|
85
|
-
"this.memory",
|
|
86
|
-
"this.repos",
|
|
87
|
-
"this.schedules",
|
|
88
|
-
"this.approvalRequests",
|
|
89
|
-
"this.assets",
|
|
90
|
-
];
|
|
91
|
-
for (const domain of expectedDomains) {
|
|
92
|
-
expect(BROWSER_SDK_JS).toContain(domain);
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test("removed domains are NOT exposed (messages, services, slack)", () => {
|
|
97
|
-
const removed = ["this.messages", "this.services", "this.slack", "postMessage", "readMessages"];
|
|
98
|
-
for (const r of removed) {
|
|
99
|
-
expect(BROWSER_SDK_JS).not.toContain(r);
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
test("assigns SwarmSDK class + swarmSdk singleton to window", () => {
|
|
104
|
-
expect(BROWSER_SDK_JS).toContain("window.SwarmSDK = SwarmSDK");
|
|
105
|
-
expect(BROWSER_SDK_JS).toContain("window.swarmSdk = new SwarmSDK()");
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
test("routes calls through the /@swarm/api/* proxy", () => {
|
|
109
|
-
expect(BROWSER_SDK_JS).toContain("const base = '/@swarm/api'");
|
|
110
|
-
// Sentinel endpoints — one per domain.
|
|
111
|
-
expect(BROWSER_SDK_JS).toContain("'/tasks'");
|
|
112
|
-
expect(BROWSER_SDK_JS).toContain("'/agents'");
|
|
113
|
-
expect(BROWSER_SDK_JS).toContain("'/events'");
|
|
114
|
-
expect(BROWSER_SDK_JS).toContain("'/memory/search'");
|
|
115
|
-
expect(BROWSER_SDK_JS).toContain("'/repos'");
|
|
116
|
-
expect(BROWSER_SDK_JS).toContain("'/schedules'");
|
|
117
|
-
expect(BROWSER_SDK_JS).toContain("'/approval-requests'");
|
|
118
|
-
expect(BROWSER_SDK_JS).toContain("'/assets'");
|
|
119
|
-
expect(BROWSER_SDK_JS).toContain("'/assets/key-audit'");
|
|
120
|
-
expect(BROWSER_SDK_JS).toContain("'/assets/mappings'");
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
test("does not fetch on SDK load or construction", () => {
|
|
124
|
-
const fetchMock = mock(() => Promise.resolve(Response.json({})));
|
|
125
|
-
const window = {};
|
|
126
|
-
const loadSdk = new Function("window", "fetch", `${BROWSER_SDK_JS}\nreturn window.SwarmSDK;`);
|
|
127
|
-
|
|
128
|
-
const SwarmSDK = loadSdk(window, fetchMock);
|
|
129
|
-
expect(window).toHaveProperty("swarmSdk");
|
|
130
|
-
expect(fetchMock).not.toHaveBeenCalled();
|
|
131
|
-
|
|
132
|
-
new SwarmSDK();
|
|
133
|
-
new SwarmSDK();
|
|
134
|
-
expect(fetchMock).not.toHaveBeenCalled();
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
// ─── createArtifactServer factory tests ──────────────────────────────────
|
|
139
|
-
|
|
140
|
-
describe("createArtifactServer", () => {
|
|
141
|
-
const originalEnv = { ...process.env };
|
|
142
|
-
|
|
143
|
-
beforeAll(() => {
|
|
144
|
-
process.env.AGENT_ID = "test-agent-id";
|
|
145
|
-
process.env.API_KEY = "example-test-api-key";
|
|
146
|
-
process.env.MCP_BASE_URL = "http://localhost:19999"; // Intentionally unreachable
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
afterAll(() => {
|
|
150
|
-
restoreEnvValue("AGENT_ID", originalEnv.AGENT_ID);
|
|
151
|
-
restoreEnvValue("API_KEY", originalEnv.API_KEY);
|
|
152
|
-
restoreEnvValue("MCP_BASE_URL", originalEnv.MCP_BASE_URL);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
describe("factory return shape", () => {
|
|
156
|
-
test("returns object with expected properties", () => {
|
|
157
|
-
const server = createArtifactServer({ name: "test" });
|
|
158
|
-
expect(server).toHaveProperty("start");
|
|
159
|
-
expect(server).toHaveProperty("stop");
|
|
160
|
-
expect(server).toHaveProperty("url");
|
|
161
|
-
expect(server).toHaveProperty("port");
|
|
162
|
-
expect(server).toHaveProperty("tunnel");
|
|
163
|
-
expect(typeof server.start).toBe("function");
|
|
164
|
-
expect(typeof server.stop).toBe("function");
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
test("initial url is empty string", () => {
|
|
168
|
-
const server = createArtifactServer({ name: "test" });
|
|
169
|
-
expect(server.url).toBe("");
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
test("initial port is 0", () => {
|
|
173
|
-
const server = createArtifactServer({ name: "test" });
|
|
174
|
-
expect(server.port).toBe(0);
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
test("initial tunnel is null", () => {
|
|
178
|
-
const server = createArtifactServer({ name: "test" });
|
|
179
|
-
expect(server.tunnel).toBeNull();
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
describe("Hono app routes", () => {
|
|
184
|
-
test("server serves static content via Hono", async () => {
|
|
185
|
-
const { Hono } = await import("hono");
|
|
186
|
-
const port = await getAvailablePort();
|
|
187
|
-
|
|
188
|
-
const app = new Hono();
|
|
189
|
-
app.get("/", (c) => c.text("Hello from test artifact"));
|
|
190
|
-
|
|
191
|
-
// Create a minimal Hono server without tunnel
|
|
192
|
-
const honoApp = new Hono();
|
|
193
|
-
honoApp.get("/@swarm/sdk.js", (c) => {
|
|
194
|
-
c.header("Content-Type", "application/javascript");
|
|
195
|
-
return c.body(BROWSER_SDK_JS);
|
|
196
|
-
});
|
|
197
|
-
honoApp.get("/@swarm/config", (c) => {
|
|
198
|
-
return c.json({ agentId: "test-agent-id", artifactName: "test" });
|
|
199
|
-
});
|
|
200
|
-
honoApp.route("/", app);
|
|
201
|
-
|
|
202
|
-
const server = Bun.serve({ port, fetch: createBunHonoFetchHandler(honoApp) });
|
|
203
|
-
|
|
204
|
-
try {
|
|
205
|
-
// Test content serving
|
|
206
|
-
const res = await fetch(`http://localhost:${port}/`);
|
|
207
|
-
expect(res.status).toBe(200);
|
|
208
|
-
expect(await res.text()).toBe("Hello from test artifact");
|
|
209
|
-
|
|
210
|
-
// Test SDK endpoint
|
|
211
|
-
const sdkRes = await fetch(`http://localhost:${port}/@swarm/sdk.js`);
|
|
212
|
-
expect(sdkRes.status).toBe(200);
|
|
213
|
-
expect(sdkRes.headers.get("content-type")).toContain("javascript");
|
|
214
|
-
const sdkBody = await sdkRes.text();
|
|
215
|
-
expect(sdkBody).toContain("class SwarmSDK");
|
|
216
|
-
|
|
217
|
-
// Test config endpoint
|
|
218
|
-
const configRes = await fetch(`http://localhost:${port}/@swarm/config`);
|
|
219
|
-
expect(configRes.status).toBe(200);
|
|
220
|
-
const config = await configRes.json();
|
|
221
|
-
expect(config).toEqual({ agentId: "test-agent-id", artifactName: "test" });
|
|
222
|
-
} finally {
|
|
223
|
-
server.stop();
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
test("server serves static files from directory", async () => {
|
|
228
|
-
const { Hono } = await import("hono");
|
|
229
|
-
const { serveStatic } = await import("hono/bun");
|
|
230
|
-
const port = await getAvailablePort();
|
|
231
|
-
const testDir = "/tmp/test-artifact-static";
|
|
232
|
-
|
|
233
|
-
// Create test directory with content
|
|
234
|
-
mkdirSync(testDir, { recursive: true });
|
|
235
|
-
writeFileSync(`${testDir}/index.html`, "<h1>Test Static</h1>");
|
|
236
|
-
writeFileSync(`${testDir}/data.json`, '{"test": true}');
|
|
237
|
-
|
|
238
|
-
const app = new Hono();
|
|
239
|
-
app.use("/*", serveStatic({ root: testDir }));
|
|
240
|
-
|
|
241
|
-
const server = Bun.serve({ port, fetch: createBunHonoFetchHandler(app) });
|
|
242
|
-
|
|
243
|
-
try {
|
|
244
|
-
const res = await fetch(`http://localhost:${port}/index.html`);
|
|
245
|
-
expect(res.status).toBe(200);
|
|
246
|
-
expect(await res.text()).toBe("<h1>Test Static</h1>");
|
|
247
|
-
|
|
248
|
-
const jsonRes = await fetch(`http://localhost:${port}/data.json`);
|
|
249
|
-
expect(jsonRes.status).toBe(200);
|
|
250
|
-
const data = await jsonRes.json();
|
|
251
|
-
expect(data).toEqual({ test: true });
|
|
252
|
-
} finally {
|
|
253
|
-
server.stop();
|
|
254
|
-
rmSync(testDir, { recursive: true, force: true });
|
|
255
|
-
}
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
test("API proxy returns 502 when MCP server is unreachable", async () => {
|
|
259
|
-
const { Hono } = await import("hono");
|
|
260
|
-
const port = await getAvailablePort();
|
|
261
|
-
|
|
262
|
-
const app = new Hono();
|
|
263
|
-
app.all("/@swarm/api/*", async (c) => {
|
|
264
|
-
const path = c.req.path.replace("/@swarm/api", "/api");
|
|
265
|
-
const targetUrl = `http://localhost:19999${path}`; // Unreachable
|
|
266
|
-
try {
|
|
267
|
-
const res = await fetch(targetUrl, { method: c.req.method });
|
|
268
|
-
return new Response(res.body, { status: res.status });
|
|
269
|
-
} catch (e) {
|
|
270
|
-
return c.json({ error: "Proxy error", message: String(e) }, 502);
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
const server = Bun.serve({ port, fetch: createBunHonoFetchHandler(app) });
|
|
275
|
-
|
|
276
|
-
try {
|
|
277
|
-
const res = await fetch(`http://localhost:${port}/@swarm/api/agents`);
|
|
278
|
-
expect(res.status).toBe(502);
|
|
279
|
-
const body = await res.json();
|
|
280
|
-
expect(body.error).toBe("Proxy error");
|
|
281
|
-
} finally {
|
|
282
|
-
server.stop();
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
test("CORS preflight returns 204 with correct headers", async () => {
|
|
287
|
-
const { Hono } = await import("hono");
|
|
288
|
-
const port = await getAvailablePort();
|
|
289
|
-
|
|
290
|
-
const app = new Hono();
|
|
291
|
-
app.options("/@swarm/api/*", (_c) => {
|
|
292
|
-
return new Response(null, {
|
|
293
|
-
status: 204,
|
|
294
|
-
headers: {
|
|
295
|
-
"Access-Control-Allow-Origin": "*",
|
|
296
|
-
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
|
|
297
|
-
"Access-Control-Allow-Headers": "Content-Type",
|
|
298
|
-
},
|
|
299
|
-
});
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
const server = Bun.serve({ port, fetch: createBunHonoFetchHandler(app) });
|
|
303
|
-
|
|
304
|
-
try {
|
|
305
|
-
const res = await fetch(`http://localhost:${port}/@swarm/api/tasks`, {
|
|
306
|
-
method: "OPTIONS",
|
|
307
|
-
});
|
|
308
|
-
expect(res.status).toBe(204);
|
|
309
|
-
expect(res.headers.get("access-control-allow-origin")).toBe("*");
|
|
310
|
-
expect(res.headers.get("access-control-allow-methods")).toContain("GET");
|
|
311
|
-
expect(res.headers.get("access-control-allow-methods")).toContain("POST");
|
|
312
|
-
expect(res.headers.get("access-control-allow-methods")).toContain("DELETE");
|
|
313
|
-
expect(res.headers.get("access-control-allow-headers")).toContain("Content-Type");
|
|
314
|
-
} finally {
|
|
315
|
-
server.stop();
|
|
316
|
-
}
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
test("API proxy forwards auth headers to MCP server", async () => {
|
|
320
|
-
const { Hono } = await import("hono");
|
|
321
|
-
const proxyPort = await getAvailablePort();
|
|
322
|
-
const mockMcpPort = await getAvailablePort();
|
|
323
|
-
|
|
324
|
-
// Mock MCP server that captures headers
|
|
325
|
-
let capturedHeaders: Record<string, string> = {};
|
|
326
|
-
const mockMcp = Bun.serve({
|
|
327
|
-
port: mockMcpPort,
|
|
328
|
-
fetch: (req) => {
|
|
329
|
-
capturedHeaders = {};
|
|
330
|
-
for (const [key, value] of req.headers.entries()) {
|
|
331
|
-
capturedHeaders[key.toLowerCase()] = value;
|
|
332
|
-
}
|
|
333
|
-
return createBunResponse(JSON.stringify({ success: true }), {
|
|
334
|
-
headers: { "Content-Type": "application/json" },
|
|
335
|
-
});
|
|
336
|
-
},
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
// Build proxy app matching server.ts pattern
|
|
340
|
-
const app = new Hono();
|
|
341
|
-
app.all("/@swarm/api/*", async (c) => {
|
|
342
|
-
const path = c.req.path.replace("/@swarm/api", "/api");
|
|
343
|
-
const targetUrl = `http://localhost:${mockMcpPort}${path}`;
|
|
344
|
-
const headers: Record<string, string> = {
|
|
345
|
-
Authorization: "Bearer example-test-api-key",
|
|
346
|
-
"X-Agent-ID": "test-agent-id",
|
|
347
|
-
};
|
|
348
|
-
if (c.req.method !== "GET") {
|
|
349
|
-
headers["Content-Type"] = "application/json";
|
|
350
|
-
}
|
|
351
|
-
try {
|
|
352
|
-
const res = await fetch(targetUrl, { method: c.req.method, headers });
|
|
353
|
-
return new Response(res.body, {
|
|
354
|
-
status: res.status,
|
|
355
|
-
headers: {
|
|
356
|
-
"Access-Control-Allow-Origin": "*",
|
|
357
|
-
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
|
|
358
|
-
"Access-Control-Allow-Headers": "Content-Type",
|
|
359
|
-
},
|
|
360
|
-
});
|
|
361
|
-
} catch (e) {
|
|
362
|
-
return c.json({ error: "Proxy error", message: String(e) }, 502);
|
|
363
|
-
}
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
const proxy = Bun.serve({ port: proxyPort, fetch: createBunHonoFetchHandler(app) });
|
|
367
|
-
|
|
368
|
-
try {
|
|
369
|
-
// Test GET request headers
|
|
370
|
-
await fetch(`http://localhost:${proxyPort}/@swarm/api/agents`);
|
|
371
|
-
expect(capturedHeaders.authorization).toBe("Bearer example-test-api-key");
|
|
372
|
-
expect(capturedHeaders["x-agent-id"]).toBe("test-agent-id");
|
|
373
|
-
|
|
374
|
-
// GET should NOT have Content-Type
|
|
375
|
-
expect(capturedHeaders["content-type"]).toBeUndefined();
|
|
376
|
-
|
|
377
|
-
// Test POST request headers
|
|
378
|
-
await fetch(`http://localhost:${proxyPort}/@swarm/api/tasks`, {
|
|
379
|
-
method: "POST",
|
|
380
|
-
body: JSON.stringify({ task: "test" }),
|
|
381
|
-
});
|
|
382
|
-
expect(capturedHeaders.authorization).toBe("Bearer example-test-api-key");
|
|
383
|
-
expect(capturedHeaders["x-agent-id"]).toBe("test-agent-id");
|
|
384
|
-
expect(capturedHeaders["content-type"]).toBe("application/json");
|
|
385
|
-
} finally {
|
|
386
|
-
proxy.stop();
|
|
387
|
-
mockMcp.stop();
|
|
388
|
-
}
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
test("API proxy response includes CORS headers", async () => {
|
|
392
|
-
const { Hono } = await import("hono");
|
|
393
|
-
const proxyPort = await getAvailablePort();
|
|
394
|
-
const mockMcpPort = await getAvailablePort();
|
|
395
|
-
|
|
396
|
-
const mockMcp = Bun.serve({
|
|
397
|
-
port: mockMcpPort,
|
|
398
|
-
fetch: () =>
|
|
399
|
-
createBunResponse(JSON.stringify({ ok: true }), {
|
|
400
|
-
headers: { "Content-Type": "application/json" },
|
|
401
|
-
}),
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
const app = new Hono();
|
|
405
|
-
app.all("/@swarm/api/*", async (c) => {
|
|
406
|
-
const path = c.req.path.replace("/@swarm/api", "/api");
|
|
407
|
-
const targetUrl = `http://localhost:${mockMcpPort}${path}`;
|
|
408
|
-
try {
|
|
409
|
-
const res = await fetch(targetUrl, { method: c.req.method });
|
|
410
|
-
return new Response(res.body, {
|
|
411
|
-
status: res.status,
|
|
412
|
-
headers: {
|
|
413
|
-
"Access-Control-Allow-Origin": "*",
|
|
414
|
-
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
|
|
415
|
-
"Access-Control-Allow-Headers": "Content-Type",
|
|
416
|
-
},
|
|
417
|
-
});
|
|
418
|
-
} catch (_e) {
|
|
419
|
-
return c.json({ error: "Proxy error" }, 502);
|
|
420
|
-
}
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
const proxy = Bun.serve({ port: proxyPort, fetch: createBunHonoFetchHandler(app) });
|
|
424
|
-
|
|
425
|
-
try {
|
|
426
|
-
const res = await fetch(`http://localhost:${proxyPort}/@swarm/api/agents`);
|
|
427
|
-
expect(res.status).toBe(200);
|
|
428
|
-
expect(res.headers.get("access-control-allow-origin")).toBe("*");
|
|
429
|
-
} finally {
|
|
430
|
-
proxy.stop();
|
|
431
|
-
mockMcp.stop();
|
|
432
|
-
}
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
test("API proxy correctly rewrites path from /@swarm/api to /api", async () => {
|
|
436
|
-
const { Hono } = await import("hono");
|
|
437
|
-
const proxyPort = await getAvailablePort();
|
|
438
|
-
const mockMcpPort = await getAvailablePort();
|
|
439
|
-
|
|
440
|
-
let capturedPath = "";
|
|
441
|
-
const mockMcp = Bun.serve({
|
|
442
|
-
port: mockMcpPort,
|
|
443
|
-
fetch: (req) => {
|
|
444
|
-
capturedPath = new URL(req.url).pathname;
|
|
445
|
-
return createBunResponse(JSON.stringify({ ok: true }));
|
|
446
|
-
},
|
|
447
|
-
});
|
|
448
|
-
|
|
449
|
-
const app = new Hono();
|
|
450
|
-
app.all("/@swarm/api/*", async (c) => {
|
|
451
|
-
const path = c.req.path.replace("/@swarm/api", "/api");
|
|
452
|
-
const targetUrl = `http://localhost:${mockMcpPort}${path}`;
|
|
453
|
-
try {
|
|
454
|
-
const res = await fetch(targetUrl, { method: c.req.method });
|
|
455
|
-
return new Response(res.body, { status: res.status });
|
|
456
|
-
} catch (_e) {
|
|
457
|
-
return c.json({ error: "Proxy error" }, 502);
|
|
458
|
-
}
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
const proxy = Bun.serve({ port: proxyPort, fetch: createBunHonoFetchHandler(app) });
|
|
462
|
-
|
|
463
|
-
try {
|
|
464
|
-
await fetch(`http://localhost:${proxyPort}/@swarm/api/tasks/123/progress`);
|
|
465
|
-
expect(capturedPath).toBe("/api/tasks/123/progress");
|
|
466
|
-
|
|
467
|
-
await fetch(`http://localhost:${proxyPort}/@swarm/api/agents`);
|
|
468
|
-
expect(capturedPath).toBe("/api/agents");
|
|
469
|
-
|
|
470
|
-
await fetch(`http://localhost:${proxyPort}/@swarm/api/services`);
|
|
471
|
-
expect(capturedPath).toBe("/api/services");
|
|
472
|
-
} finally {
|
|
473
|
-
proxy.stop();
|
|
474
|
-
mockMcp.stop();
|
|
475
|
-
}
|
|
476
|
-
});
|
|
477
|
-
});
|
|
478
|
-
|
|
479
|
-
describe("stop()", () => {
|
|
480
|
-
test("stop() is safe to call when server was never started", async () => {
|
|
481
|
-
const server = createArtifactServer({ name: "never-started" });
|
|
482
|
-
// Should not throw
|
|
483
|
-
await server.stop();
|
|
484
|
-
expect(server.port).toBe(0);
|
|
485
|
-
expect(server.tunnel).toBeNull();
|
|
486
|
-
});
|
|
487
|
-
});
|
|
488
|
-
});
|
|
489
|
-
|
|
490
|
-
// ─── tunnel.ts tests ──────────────────────────────────────────────────────
|
|
491
|
-
|
|
492
|
-
describe("createTunnel", () => {
|
|
493
|
-
test("module exports createTunnel function", async () => {
|
|
494
|
-
const tunnelMod = await import("../artifact-sdk/tunnel");
|
|
495
|
-
expect(typeof tunnelMod.createTunnel).toBe("function");
|
|
496
|
-
});
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
// ─── index.ts re-export tests ──────────────────────────────────────────
|
|
500
|
-
|
|
501
|
-
describe("artifact-sdk index exports", () => {
|
|
502
|
-
test("exports createArtifactServer", async () => {
|
|
503
|
-
const sdk = await import("../artifact-sdk/index");
|
|
504
|
-
expect(typeof sdk.createArtifactServer).toBe("function");
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
test("createArtifactServer from index is same as from server", async () => {
|
|
508
|
-
const sdk = await import("../artifact-sdk/index");
|
|
509
|
-
const { createArtifactServer: direct } = await import("../artifact-sdk/server");
|
|
510
|
-
expect(sdk.createArtifactServer).toBe(direct);
|
|
511
|
-
});
|
|
512
|
-
});
|
|
513
|
-
|
|
514
|
-
// ─── CLI command tests ─────────────────────────────────────────────────
|
|
515
|
-
|
|
516
|
-
describe("artifact CLI command", () => {
|
|
517
|
-
test("runArtifact module exports correctly", async () => {
|
|
518
|
-
const mod = await import("../commands/artifact");
|
|
519
|
-
expect(typeof mod.runArtifact).toBe("function");
|
|
520
|
-
});
|
|
521
|
-
|
|
522
|
-
test("runArtifact with unknown subcommand calls printHelp (no crash)", async () => {
|
|
523
|
-
const { runArtifact } = await import("../commands/artifact");
|
|
524
|
-
// "help" and unknown subcommands should just print help and return
|
|
525
|
-
const consoleSpy = mock(() => {});
|
|
526
|
-
const origLog = console.log;
|
|
527
|
-
console.log = consoleSpy;
|
|
528
|
-
try {
|
|
529
|
-
await runArtifact("help", { additionalArgs: [] });
|
|
530
|
-
expect(consoleSpy).toHaveBeenCalled();
|
|
531
|
-
const output = consoleSpy.mock.calls.map((c) => c[0]).join("\n");
|
|
532
|
-
expect(output).toContain("Usage: agent-swarm artifact");
|
|
533
|
-
expect(output).toContain("serve");
|
|
534
|
-
expect(output).toContain("list");
|
|
535
|
-
expect(output).toContain("stop");
|
|
536
|
-
} finally {
|
|
537
|
-
console.log = origLog;
|
|
538
|
-
}
|
|
539
|
-
});
|
|
540
|
-
|
|
541
|
-
test("runArtifact with no subcommand defaults to help", async () => {
|
|
542
|
-
const { runArtifact } = await import("../commands/artifact");
|
|
543
|
-
const consoleSpy = mock(() => {});
|
|
544
|
-
const origLog = console.log;
|
|
545
|
-
console.log = consoleSpy;
|
|
546
|
-
try {
|
|
547
|
-
// Default case when subcommand is not recognized
|
|
548
|
-
await runArtifact("unknown-command", { additionalArgs: [] });
|
|
549
|
-
expect(consoleSpy).toHaveBeenCalled();
|
|
550
|
-
const output = consoleSpy.mock.calls.map((c) => c[0]).join("\n");
|
|
551
|
-
expect(output).toContain("Usage: agent-swarm artifact");
|
|
552
|
-
} finally {
|
|
553
|
-
console.log = origLog;
|
|
554
|
-
}
|
|
555
|
-
});
|
|
556
|
-
|
|
557
|
-
describe("artifact list", () => {
|
|
558
|
-
test("lists artifacts from mock MCP server", async () => {
|
|
559
|
-
const mockPort = await getAvailablePort();
|
|
560
|
-
const mockServer = Bun.serve({
|
|
561
|
-
port: mockPort,
|
|
562
|
-
fetch: (req) => {
|
|
563
|
-
const url = new URL(req.url);
|
|
564
|
-
if (url.pathname === "/api/services") {
|
|
565
|
-
return createBunResponse(
|
|
566
|
-
JSON.stringify({
|
|
567
|
-
services: [
|
|
568
|
-
{
|
|
569
|
-
id: "svc-1",
|
|
570
|
-
name: "artifact-dashboard",
|
|
571
|
-
agentId: "agent-123",
|
|
572
|
-
status: "healthy",
|
|
573
|
-
metadata: {
|
|
574
|
-
type: "artifact",
|
|
575
|
-
artifactName: "dashboard",
|
|
576
|
-
port: 3001,
|
|
577
|
-
publicUrl: "https://test.lt.example.com",
|
|
578
|
-
},
|
|
579
|
-
},
|
|
580
|
-
{
|
|
581
|
-
id: "svc-2",
|
|
582
|
-
name: "some-other-service",
|
|
583
|
-
agentId: "agent-456",
|
|
584
|
-
status: "healthy",
|
|
585
|
-
metadata: { type: "web" },
|
|
586
|
-
},
|
|
587
|
-
],
|
|
588
|
-
}),
|
|
589
|
-
);
|
|
590
|
-
}
|
|
591
|
-
return createBunResponse("Not found", { status: 404 });
|
|
592
|
-
},
|
|
593
|
-
});
|
|
594
|
-
|
|
595
|
-
const origEnv = { ...process.env };
|
|
596
|
-
process.env.MCP_BASE_URL = `http://localhost:${mockPort}`;
|
|
597
|
-
process.env.API_KEY = "example-test-key";
|
|
598
|
-
process.env.AGENT_ID = "test-agent";
|
|
599
|
-
|
|
600
|
-
const consoleSpy = mock(() => {});
|
|
601
|
-
const origLog = console.log;
|
|
602
|
-
console.log = consoleSpy;
|
|
603
|
-
|
|
604
|
-
try {
|
|
605
|
-
const { runArtifact } = await import("../commands/artifact");
|
|
606
|
-
await runArtifact("list", { additionalArgs: [] });
|
|
607
|
-
|
|
608
|
-
const output = consoleSpy.mock.calls.map((c) => c[0]).join("\n");
|
|
609
|
-
// Should show the artifact but not the non-artifact service
|
|
610
|
-
expect(output).toContain("dashboard");
|
|
611
|
-
expect(output).toContain("https://test.lt.example.com");
|
|
612
|
-
} finally {
|
|
613
|
-
console.log = origLog;
|
|
614
|
-
restoreEnvValue("MCP_BASE_URL", origEnv.MCP_BASE_URL);
|
|
615
|
-
restoreEnvValue("API_KEY", origEnv.API_KEY);
|
|
616
|
-
restoreEnvValue("AGENT_ID", origEnv.AGENT_ID);
|
|
617
|
-
mockServer.stop();
|
|
618
|
-
}
|
|
619
|
-
});
|
|
620
|
-
|
|
621
|
-
test("shows 'No active artifacts' when none exist", async () => {
|
|
622
|
-
const mockPort = await getAvailablePort();
|
|
623
|
-
const mockServer = Bun.serve({
|
|
624
|
-
port: mockPort,
|
|
625
|
-
fetch: () => createBunResponse(JSON.stringify({ services: [] })),
|
|
626
|
-
});
|
|
627
|
-
|
|
628
|
-
const origEnv = { ...process.env };
|
|
629
|
-
process.env.MCP_BASE_URL = `http://localhost:${mockPort}`;
|
|
630
|
-
process.env.API_KEY = "example-test-key";
|
|
631
|
-
process.env.AGENT_ID = "test-agent";
|
|
632
|
-
|
|
633
|
-
const consoleSpy = mock(() => {});
|
|
634
|
-
const origLog = console.log;
|
|
635
|
-
console.log = consoleSpy;
|
|
636
|
-
|
|
637
|
-
try {
|
|
638
|
-
const { runArtifact } = await import("../commands/artifact");
|
|
639
|
-
await runArtifact("list", { additionalArgs: [] });
|
|
640
|
-
|
|
641
|
-
const output = consoleSpy.mock.calls.map((c) => c[0]).join("\n");
|
|
642
|
-
expect(output).toContain("No active artifacts");
|
|
643
|
-
} finally {
|
|
644
|
-
console.log = origLog;
|
|
645
|
-
restoreEnvValue("MCP_BASE_URL", origEnv.MCP_BASE_URL);
|
|
646
|
-
restoreEnvValue("API_KEY", origEnv.API_KEY);
|
|
647
|
-
restoreEnvValue("AGENT_ID", origEnv.AGENT_ID);
|
|
648
|
-
mockServer.stop();
|
|
649
|
-
}
|
|
650
|
-
});
|
|
651
|
-
|
|
652
|
-
test("filters only artifact-type services from list", async () => {
|
|
653
|
-
const mockPort = await getAvailablePort();
|
|
654
|
-
const mockServer = Bun.serve({
|
|
655
|
-
port: mockPort,
|
|
656
|
-
fetch: () =>
|
|
657
|
-
createBunResponse(
|
|
658
|
-
JSON.stringify({
|
|
659
|
-
services: [
|
|
660
|
-
{
|
|
661
|
-
id: "s1",
|
|
662
|
-
name: "web-server",
|
|
663
|
-
agentId: "a1",
|
|
664
|
-
status: "healthy",
|
|
665
|
-
metadata: { type: "web" },
|
|
666
|
-
},
|
|
667
|
-
{
|
|
668
|
-
id: "s2",
|
|
669
|
-
name: "api-server",
|
|
670
|
-
agentId: "a2",
|
|
671
|
-
status: "healthy",
|
|
672
|
-
metadata: {},
|
|
673
|
-
},
|
|
674
|
-
],
|
|
675
|
-
}),
|
|
676
|
-
),
|
|
677
|
-
});
|
|
678
|
-
|
|
679
|
-
const origEnv = { ...process.env };
|
|
680
|
-
process.env.MCP_BASE_URL = `http://localhost:${mockPort}`;
|
|
681
|
-
process.env.API_KEY = "example-test-key";
|
|
682
|
-
process.env.AGENT_ID = "test-agent";
|
|
683
|
-
|
|
684
|
-
const consoleSpy = mock(() => {});
|
|
685
|
-
const origLog = console.log;
|
|
686
|
-
console.log = consoleSpy;
|
|
687
|
-
|
|
688
|
-
try {
|
|
689
|
-
const { runArtifact } = await import("../commands/artifact");
|
|
690
|
-
await runArtifact("list", { additionalArgs: [] });
|
|
691
|
-
|
|
692
|
-
const output = consoleSpy.mock.calls.map((c) => c[0]).join("\n");
|
|
693
|
-
// None have type "artifact" so should say no artifacts
|
|
694
|
-
expect(output).toContain("No active artifacts");
|
|
695
|
-
} finally {
|
|
696
|
-
console.log = origLog;
|
|
697
|
-
restoreEnvValue("MCP_BASE_URL", origEnv.MCP_BASE_URL);
|
|
698
|
-
restoreEnvValue("API_KEY", origEnv.API_KEY);
|
|
699
|
-
restoreEnvValue("AGENT_ID", origEnv.AGENT_ID);
|
|
700
|
-
mockServer.stop();
|
|
701
|
-
}
|
|
702
|
-
});
|
|
703
|
-
});
|
|
704
|
-
|
|
705
|
-
describe("artifact stop", () => {
|
|
706
|
-
test("stop sends delete request to service registry", async () => {
|
|
707
|
-
const mockPort = await getAvailablePort();
|
|
708
|
-
let deletedServiceId = "";
|
|
709
|
-
|
|
710
|
-
const mockServer = Bun.serve({
|
|
711
|
-
port: mockPort,
|
|
712
|
-
fetch: (req) => {
|
|
713
|
-
const url = new URL(req.url);
|
|
714
|
-
if (req.method === "GET" && url.pathname === "/api/services") {
|
|
715
|
-
return createBunResponse(
|
|
716
|
-
JSON.stringify({
|
|
717
|
-
services: [
|
|
718
|
-
{
|
|
719
|
-
id: "svc-to-delete",
|
|
720
|
-
name: "artifact-my-report",
|
|
721
|
-
metadata: { type: "artifact", artifactName: "my-report" },
|
|
722
|
-
},
|
|
723
|
-
],
|
|
724
|
-
}),
|
|
725
|
-
);
|
|
726
|
-
}
|
|
727
|
-
if (req.method === "DELETE" && url.pathname.startsWith("/api/services/")) {
|
|
728
|
-
deletedServiceId = url.pathname.split("/").pop() || "";
|
|
729
|
-
return createBunResponse(JSON.stringify({ success: true }));
|
|
730
|
-
}
|
|
731
|
-
return createBunResponse("Not found", { status: 404 });
|
|
732
|
-
},
|
|
733
|
-
});
|
|
734
|
-
|
|
735
|
-
const origEnv = { ...process.env };
|
|
736
|
-
process.env.MCP_BASE_URL = `http://localhost:${mockPort}`;
|
|
737
|
-
process.env.API_KEY = "example-test-key";
|
|
738
|
-
process.env.AGENT_ID = "test-agent";
|
|
739
|
-
|
|
740
|
-
const consoleSpy = mock(() => {});
|
|
741
|
-
const origLog = console.log;
|
|
742
|
-
console.log = consoleSpy;
|
|
743
|
-
|
|
744
|
-
try {
|
|
745
|
-
const { runArtifact } = await import("../commands/artifact");
|
|
746
|
-
await runArtifact("stop", { additionalArgs: ["my-report"] });
|
|
747
|
-
|
|
748
|
-
expect(deletedServiceId).toBe("svc-to-delete");
|
|
749
|
-
const output = consoleSpy.mock.calls.map((c) => c[0]).join("\n");
|
|
750
|
-
expect(output).toContain("my-report");
|
|
751
|
-
expect(output).toContain("stopped");
|
|
752
|
-
} finally {
|
|
753
|
-
console.log = origLog;
|
|
754
|
-
restoreEnvValue("MCP_BASE_URL", origEnv.MCP_BASE_URL);
|
|
755
|
-
restoreEnvValue("API_KEY", origEnv.API_KEY);
|
|
756
|
-
restoreEnvValue("AGENT_ID", origEnv.AGENT_ID);
|
|
757
|
-
mockServer.stop();
|
|
758
|
-
}
|
|
759
|
-
});
|
|
760
|
-
});
|
|
761
|
-
});
|
|
762
|
-
|
|
763
|
-
// ─── Base prompt tests ──────────────────────────────────────────────────
|
|
764
|
-
|
|
765
|
-
// Prompt v2: the artifacts block left the system prompt. Outputs go through
|
|
766
|
-
// pages, apps, and agent-fs; the `artifacts` skill is opt-in (systemDefault
|
|
767
|
-
// false). The prompt must not point at artifacts any more.
|
|
768
|
-
describe("base prompt artifacts mention", () => {
|
|
769
|
-
test("does not mention the artifacts path, localtunnel, or the SDK", async () => {
|
|
770
|
-
const prompt = await getBasePrompt({
|
|
771
|
-
role: "worker",
|
|
772
|
-
agentId: "test-agent-id",
|
|
773
|
-
capabilities: ["core", "artifacts", "services"],
|
|
774
|
-
});
|
|
775
|
-
|
|
776
|
-
expect(prompt).not.toContain("/workspace/personal/artifacts/");
|
|
777
|
-
expect(prompt).not.toContain("localtunnel");
|
|
778
|
-
expect(prompt).not.toContain("createArtifactServer");
|
|
779
|
-
expect(prompt).not.toContain("SwarmSDK");
|
|
780
|
-
});
|
|
781
|
-
|
|
782
|
-
test("points at pages and apps for human-facing outputs instead", async () => {
|
|
783
|
-
const prompt = await getBasePrompt({
|
|
784
|
-
role: "worker",
|
|
785
|
-
agentId: "test-agent-id",
|
|
786
|
-
capabilities: ["core", "artifacts"],
|
|
787
|
-
});
|
|
788
|
-
|
|
789
|
-
expect(prompt).toContain("## Outputs");
|
|
790
|
-
expect(prompt).toContain("`pages` skill");
|
|
791
|
-
expect(prompt).toContain("`apps` skill");
|
|
792
|
-
});
|
|
793
|
-
});
|