@desplega.ai/agent-swarm 1.173.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-ccm9xrep.js → acp-adapter-sj2g0m84.js} +17 -16
- package/dist/{actions-sgeyv08k.js → actions-fegk44gr.js} +39 -34
- package/dist/{amp-adapter-gpxp3kc9.js → amp-adapter-ad8ft89x.js} +8 -7
- package/dist/{app-km9qnv2f.js → app-kfvgbvzy.js} +18 -14
- package/dist/{assistant-5r8tcvvd.js → assistant-z7zdy9ja.js} +40 -35
- package/dist/{boot-reembed-swwzdgd7.js → boot-reembed-5c2z0mbe.js} +10 -9
- package/dist/{boot-reembed-16rv9843.js → boot-reembed-j8xa181e.js} +10 -9
- package/dist/{boot-scrub-sweep-zkr6vkqb.js → boot-scrub-sweep-hnkn3rgt.js} +11 -10
- package/dist/{boot-seeds-d8sp49t2.js → boot-seeds-kwjq4d2z.js} +14 -13
- package/dist/{claude-adapter-yzzzh8jp.js → claude-adapter-9vmvpvgd.js} +19 -18
- 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-4whxere4.js → claude-sdk-session-9jye6cxr.js} +11881 -11472
- package/dist/{cli-94b48jhk.js → cli-03gedhng.js} +16 -14
- package/dist/{cli-1w0vj3gw.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-x119kdba.js → cli-3dj8k4vy.js} +1 -1
- package/dist/{cli-srqq3gc5.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-42qhyvwx.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-0kxf81jj.js → cli-6jyj59nb.js} +2 -2
- package/dist/{cli-w1apjecb.js → cli-6razj6t4.js} +2 -2
- package/dist/{cli-anzdk0z4.js → cli-74ahz61x.js} +2 -2
- package/dist/{cli-m89t9jdf.js → cli-7x0g4sn1.js} +15416 -16024
- 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-na2pxe4f.js → cli-apx87jne.js} +2 -2
- package/dist/{cli-rfz2ve55.js → cli-bzszjf2p.js} +2855 -862
- 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-rfs4vddv.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-7a93cv8c.js → cli-ee9gtz70.js} +98 -23
- package/dist/{cli-3nxdmjrc.js → cli-eejsgvm4.js} +4 -4
- package/dist/{cli-fmhj1ehj.js → cli-ef1hg1wv.js} +470 -51
- 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-h7k0xtry.js → cli-hvqbtna4.js} +4 -1256
- package/dist/{cli-s8z6x4b4.js → cli-j0pfptdp.js} +218 -102
- package/dist/cli-jta2eyzc.js +619 -0
- package/dist/{cli-5er5gjbm.js → cli-k382tshb.js} +10 -11
- package/dist/{cli-v3zhnxsb.js → cli-k3dp5tpf.js} +2 -2
- package/dist/{cli-wd0hz6ah.js → cli-kbrt8gqa.js} +9 -91
- package/dist/cli-kceah1eh.js +92 -0
- package/dist/{cli-ne7smj1b.js → cli-ke896fcf.js} +10 -10
- package/dist/{cli-xc7p7s3g.js → cli-kt6zqg0e.js} +6 -6
- package/dist/{cli-wrh08zjd.js → cli-m50t4309.js} +5 -18
- package/dist/cli-n2wq4j7m.js +6985 -0
- package/dist/{cli-bv2etw2y.js → cli-n3hzg89b.js} +46 -15
- package/dist/{cli-tmhsxhb8.js → cli-n5vwg842.js} +23 -6
- package/dist/{cli-qm1448f9.js → cli-ne236afy.js} +8 -8
- package/dist/{cli-d161g69q.js → cli-p1x85d2t.js} +50 -2
- package/dist/{cli-7pz3b7x5.js → cli-przpmdgr.js} +25 -0
- package/dist/{cli-0a7mm3zp.js → cli-q0ke1yww.js} +25 -21
- package/dist/{cli-e3pmyt39.js → cli-q50942rs.js} +1 -1
- package/dist/{cli-r44t9wqc.js → cli-r106725k.js} +2 -2
- package/dist/{cli-phcqp1b9.js → cli-r2pnvj8g.js} +2 -2
- package/dist/{cli-jpc4r224.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-r4fqfpwf.js → cli-s2sp957d.js} +50 -27
- package/dist/{cli-1x7da0de.js → cli-s4setq91.js} +8 -8
- package/dist/{cli-6thk4jz3.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-nwrdx840.js → cli-tr4sxp68.js} +3 -3
- package/dist/{cli-r0byd61h.js → cli-tsde1hdr.js} +15 -15
- package/dist/{cli-b07hr3bt.js → cli-txqb9s38.js} +2 -2
- package/dist/{cli-6r2f7edk.js → cli-v1yb0rqb.js} +6 -6
- package/dist/{cli-saqyage0.js → cli-vatyhshy.js} +179 -27
- package/dist/{cli-5wpw4rab.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-c3rk1v0x.js → cli-wayw93nt.js} +3 -3
- package/dist/cli-wmgrkscj.js +23254 -0
- package/dist/{cli-9xf7fdtp.js → cli-z5jjpaxw.js} +29 -6
- package/dist/{cli-451ks6aw.js → cli-zkpks3r3.js} +1 -1
- package/dist/cli.js +29 -45
- package/dist/{codex-adapter-r3dn4fp5.js → codex-adapter-y81sssk0.js} +15 -14
- package/dist/{codex-login-841kv5fk.js → codex-login-f2rcfpp9.js} +3 -2
- package/dist/{codex-session-runner-fwt793h4.js → codex-session-runner-8vx4j6a9.js} +15 -14
- package/dist/{commands-z8fq9qna.js → commands-kcpvpcrr.js} +11 -10
- package/dist/{controller-hq5ggpcp.js → controller-ywrmt6yd.js} +5 -4
- package/dist/{controllers-connect-3mf2btyj.js → controllers-connect-kwpvj3rf.js} +42 -37
- package/dist/{cursor-adapter-q8pgv5qa.js → cursor-adapter-cehv1qns.js} +7 -6
- package/dist/{db-yyhqqrbf.js → db-k8ankj20.js} +12 -11
- package/dist/{db-qfpq4bt7.js → db-ww5d7jq3.js} +28 -9
- package/dist/{devin-adapter-xgtj680j.js → devin-adapter-x1022qb1.js} +3 -2
- package/dist/{dispatcher-x0x7qfcq.js → dispatcher-e8gq5m68.js} +38 -33
- package/dist/{docker-f503k9p0.js → docker-ff6y1190.js} +3 -2
- package/dist/{dsh-adapter-34etvb5m.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-h1fjecwe.js → external-channel-h3359cwn.js} +11 -10
- package/dist/{google-generative-ai-szdxbpqg.js → google-generative-ai-g8db7x0f.js} +4 -2
- package/dist/{google-vertex-qzw3p36d.js → google-vertex-r2692q0r.js} +4 -2
- package/dist/{grok-adapter-e7mr287e.js → grok-adapter-0d4x7gkx.js} +18 -17
- package/dist/{handlers-znb9n7d4.js → handlers-an1gzv21.js} +41 -36
- package/dist/{heartbeat-bm4qkn8d.js → heartbeat-6dakeb61.js} +43 -38
- package/dist/{hook-254r4mza.js → hook-6v6cv6d5.js} +11 -23
- package/dist/{hook-xaa3q80s.js → hook-sa5xye4y.js} +12 -11
- package/dist/{http-3dgrgp8y.js → http-r7f3eky0.js} +1499 -251
- package/dist/index-52j1aja4.js +3465 -0
- package/dist/{index-fx3jqq1e.js → index-7ep4gzdk.js} +38 -33
- 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-g2byveez.js → index-rmpw9a8q.js} +38 -33
- package/dist/{index-2ybk7khy.js → index-s2wxgzr0.js} +468 -683
- package/dist/{index-bdsqa799.js → index-v1v6n7hg.js} +43 -38
- package/dist/index-we27kd31.js +12810 -0
- package/dist/{index-jd7sejm2.js → index-zk96aq1k.js} +10 -9
- package/dist/{keepalive-6ywhpja1.js → keepalive-be9vwy5h.js} +12 -11
- package/dist/{lead-cw45n21s.js → lead-0861cwrf.js} +61 -56
- package/dist/{maintenance-ss1a1ge9.js → maintenance-mzzgc8bn.js} +10 -9
- package/dist/{node-fkajaq96.js → node-mn1zs7an.js} +2 -1
- package/dist/{oauth-refresh-sweep-3c6f8vyy.js → oauth-refresh-sweep-cpdnfwdj.js} +11 -10
- package/dist/{onboard-8hzdhc1k.js → onboard-fh8qs4r3.js} +11 -3
- package/dist/{opencode-adapter-qbchbcfz.js → opencode-adapter-nm42wwj8.js} +18 -13
- package/dist/{otel-impl-e6mnvc4v.js → otel-impl-x6c1c9g4.js} +242 -868
- package/dist/{pi-mono-adapter-3c9g9snh.js → pi-mono-adapter-9n2ya240.js} +244 -106
- package/dist/{pricing-refresh-gedkjdw0.js → pricing-refresh-qb0rv0ap.js} +12 -11
- package/dist/{rbac-roles-dt4vh1yy.js → rbac-roles-1gzdwbh1.js} +11 -10
- package/dist/{rbac-roles-eszdg6pm.js → rbac-roles-3mraey52.js} +12 -11
- package/dist/{render-v2-907cy6sa.js → render-v2-agpa45zz.js} +18 -14
- package/dist/{resume-42stcaz0.js → resume-x0ydy9s9.js} +25 -21
- package/dist/{runtime-qfry88v2.js → runtime-sa2vr16g.js} +2 -2
- package/dist/{setup-adbc1c10.js → setup-as9ga0d6.js} +2 -2
- package/dist/{virtual-modules-rtmt494q.js → virtual-modules-9gkxqrap.js} +6 -5
- package/dist/{work-objects-wpj8ck95.js → work-objects-y5g1y7ev.js} +41 -36
- package/dist/{worker-bzdra9rf.js → worker-860c3e38.js} +61 -56
- package/dist/{x-qfmygqqv.js → x-m477fr0h.js} +3 -2
- package/openapi.json +523 -344
- package/package.json +10 -11
- 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 +52 -7
- 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-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 +0 -18
- package/src/be/seed-skills/index.ts +104 -3
- package/src/be/swarm-config-guard.ts +52 -0
- package/src/cli.tsx +0 -16
- package/src/commands/onboard/non-interactive.ts +4 -2
- package/src/commands/provider-credentials.ts +52 -6
- package/src/commands/runner.ts +190 -54
- 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.ts +15 -5
- package/src/http/page-proxy.ts +2 -4
- package/src/http/pages-public.ts +3 -3
- package/src/http/pages.ts +3 -13
- package/src/http/poll.ts +28 -68
- package/src/http/requested-by.ts +54 -0
- package/src/http/scripts.ts +1 -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 +159 -1
- 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/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 +55 -2
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/claude-adapter.ts +1 -1
- package/src/providers/claude-flag-settings.ts +17 -5
- package/src/providers/claude-managed-adapter.ts +1 -1
- package/src/providers/claude-session-events.ts +6 -1
- package/src/providers/dsh-adapter.ts +1 -1
- package/src/providers/opencode-adapter.ts +243 -26
- package/src/providers/opencode-swarm-plugin.ts +31 -0
- package/src/providers/pi-mono-adapter.ts +398 -153
- package/src/providers/pricing-sources.md +33 -2
- package/src/providers/reasoning-effort.ts +27 -0
- package/src/providers/types.ts +6 -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/loader.ts +19 -7
- 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/event-dedup.ts +1 -1
- package/src/tasks/additive-buffer.ts +4 -2
- package/src/tasks/context-key.ts +60 -1
- package/src/tasks/model-pin.ts +67 -0
- package/src/tasks/worker-follow-up.ts +4 -31
- package/src/tests/acp-adapter.test.ts +42 -0
- package/src/tests/api-drain-worker-e2e.test.ts +1 -6
- package/src/tests/base-prompt.test.ts +58 -54
- package/src/tests/chat-sdk-commands.test.ts +191 -0
- package/src/tests/chat-sdk-config.test.ts +334 -0
- package/src/tests/chat-sdk-discord-api.test.ts +68 -0
- package/src/tests/chat-sdk-discord-gateway.test.ts +252 -0
- package/src/tests/chat-sdk-discord-webhook.test.ts +126 -0
- package/src/tests/chat-sdk-fields-sync.test.ts +50 -0
- package/src/tests/chat-sdk-harness.ts +146 -0
- package/src/tests/chat-sdk-inbound.test.ts +363 -0
- package/src/tests/chat-sdk-relay.test.ts +470 -0
- package/src/tests/chat-sdk-reload.test.ts +128 -0
- package/src/tests/chat-sdk-shutdown.test.ts +220 -0
- package/src/tests/chat-sdk-slack.test.ts +268 -0
- package/src/tests/chat-sdk-state.test.ts +163 -0
- package/src/tests/chat-sdk-status-route.test.ts +382 -0
- package/src/tests/chat-sdk-teams.test.ts +277 -0
- package/src/tests/chat-sdk-tools.test.ts +520 -0
- package/src/tests/chat-sdk-typing.test.ts +120 -0
- package/src/tests/chat-sdk-webhook-telegram.test.ts +200 -0
- package/src/tests/claude-adapter-binary.test.ts +9 -4
- package/src/tests/claude-flag-settings.test.ts +11 -3
- package/src/tests/claude-managed-adapter.test.ts +1 -1
- package/src/tests/claude-sdk-lifecycle.test.ts +9 -3
- package/src/tests/claude-thinking-tokens.test.ts +57 -0
- package/src/tests/claude-worker-parity.test.ts +2 -7
- package/src/tests/config-env-export-chat-sdk.test.ts +11 -0
- package/src/tests/config-refs.test.ts +66 -0
- package/src/tests/context-key.test.ts +19 -0
- package/src/tests/cors-allowlist.test.ts +25 -0
- package/src/tests/create-page-tool.test.ts +18 -0
- package/src/tests/credential-check.test.ts +139 -0
- package/src/tests/credentials.test.ts +21 -0
- package/src/tests/db-runtime.test.ts +61 -0
- package/src/tests/db-task-read-contract.test.ts +20 -0
- package/src/tests/db-task-write-contract.test.ts +10 -0
- 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/chat-sdk/telegram-private-text.json +10 -0
- package/src/tests/fixtures/extensions/route-chat-channel-to-agent/hooks.ts +27 -0
- package/src/tests/fixtures/extensions/route-chat-channel-to-agent/manifest.json +9 -0
- package/src/tests/fixtures/openai-compatible-registry-extension.child.ts +146 -0
- package/src/tests/fixtures/runner-legacy-resume-prompt.ts +122 -0
- package/src/tests/github-handlers.test.ts +35 -0
- package/src/tests/harness-provider-resolution.test.ts +12 -0
- package/src/tests/heartbeat-checklist.test.ts +3 -2
- package/src/tests/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/openai-compatible-providers.test.ts +134 -0
- package/src/tests/openai-compatible-registry-extension.test.ts +42 -0
- package/src/tests/opencode-adapter.test.ts +216 -2
- package/src/tests/opencode-helmcode-sdk.test.ts +201 -0
- package/src/tests/opencode-shell-env.test.ts +145 -0
- package/src/tests/openrouter-base-url.test.ts +101 -151
- package/src/tests/page-proxy.test.ts +1 -1
- package/src/tests/pages-browser-sdk.test.ts +76 -0
- package/src/tests/pages-feedback.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-legacy-resume-prompt.test.ts +64 -0
- package/src/tests/script-connections.test.ts +2 -0
- 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 +46 -0
- package/src/tests/skill-get-name-resolution.test.ts +137 -0
- package/src/tests/sonnet-5-5-registry.test.ts +9 -1
- package/src/tests/swarm-config-export-to-env.test.ts +267 -0
- package/src/tests/swarm-config-reserved-keys.test.ts +16 -0
- package/src/tests/swarm-diff.test.ts +1 -1
- package/src/tests/task-model-effort-rerun.test.ts +164 -0
- package/src/tests/task-session-prompts.test.ts +132 -0
- package/src/tests/task-tool-manifest.test.ts +14 -0
- package/src/tests/task-tools-ctx.test.ts +2 -0
- package/src/tests/tool-annotations.test.ts +6 -6
- package/src/tests/ui-logs-parser.test.ts +43 -0
- package/src/tests/used-by-route.test.ts +6 -0
- package/src/tests/vercel-ai-gateway.test.ts +149 -0
- package/src/tests/workflow-swarm-script.test.ts +38 -0
- package/src/tests/workflow-wait-filter.test.ts +5 -3
- package/src/tools/chat-access.ts +41 -0
- package/src/tools/chat-open-dm.ts +59 -0
- package/src/tools/chat-post.ts +74 -0
- package/src/tools/chat-read-thread.ts +100 -0
- package/src/tools/chat-reply.ts +75 -0
- package/src/tools/create-page.ts +3 -13
- package/src/tools/model-catalog/index.ts +2 -1
- package/src/tools/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/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/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 +8 -1
- package/templates/skills/apps/content.md +8 -1
- package/templates/skills/chat-sdk/config.json +14 -0
- package/templates/skills/chat-sdk/content.md +84 -0
- package/templates/skills/composio-gmail/content.md +7 -0
- package/templates/skills/composio-google-docs/content.md +1 -1
- package/templates/skills/email-domain-health/config.json +14 -0
- package/templates/skills/email-domain-health/content.md +131 -0
- package/templates/skills/kv-storage/content.md +2 -2
- package/templates/skills/pages/content.md +8 -10
- package/templates/skills/swarm-extensions/content.md +2 -0
- package/templates/skills/swarm-scripts/SKILL.md +4 -2
- package/templates/skills/swarm-scripts/config.json +1 -1
- package/templates/skills/swarm-scripts/content.md +4 -2
- package/templates/skills/workflow-iterate/content.md +38 -0
- package/dist/artifact-eczsknc3.js +0 -3843
- package/dist/cli-bd957dgb.js +0 -153
- package/dist/cli-q51yprfq.js +0 -1104
- package/dist/cli-t1ze64h3.js +0 -811
- package/dist/cli-tcc4wd5d.js +0 -56471
- package/dist/index-9ch1n761.js +0 -1102
- package/src/artifact-sdk/index.ts +0 -2
- package/src/artifact-sdk/localtunnel.d.ts +0 -20
- package/src/artifact-sdk/port.ts +0 -12
- package/src/artifact-sdk/server.ts +0 -183
- package/src/artifact-sdk/tunnel.ts +0 -19
- package/src/commands/artifact.ts +0 -249
- package/src/http/ecosystem.ts +0 -77
- package/src/tests/artifact-commands.test.ts +0 -92
- package/src/tests/artifact-sdk.test.ts +0 -793
- package/src/tests/register-service-security.test.ts +0 -194
- package/src/tools/list-services.ts +0 -107
- package/src/tools/register-service.ts +0 -177
- package/src/tools/unregister-service.ts +0 -73
- package/src/tools/update-service-status.ts +0 -96
- package/templates/skills/artifacts/config.json +0 -14
- package/templates/skills/artifacts/content.md +0 -344
- package/templates/skills/artifacts/files/examples/approval-flow.ts +0 -34
- package/templates/skills/artifacts/files/examples/hono-dashboard.ts +0 -31
- package/templates/skills/artifacts/files/examples/multi-artifact.ts +0 -20
- package/templates/skills/artifacts/files/examples/static-report.sh +0 -17
- /package/src/{artifact-sdk → pages}/browser-sdk.ts +0 -0
- /package/src/{artifact-sdk → pages}/feedback-overlay.ts +0 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { describe, expect, mock, test } from "bun:test";
|
|
2
|
+
import { OPENAI_COMPATIBLE_PROVIDERS } from "@desplega/model-catalog";
|
|
2
3
|
import {
|
|
3
4
|
buildCredStatusReport,
|
|
4
5
|
CREDENTIAL_PROVIDER_CHECKERS,
|
|
6
|
+
checkOpenAICompatibleProvider,
|
|
5
7
|
checkProviderCredentials,
|
|
6
8
|
isBedrockMode,
|
|
7
9
|
isCredCheckDisabled,
|
|
@@ -652,6 +654,37 @@ describe("checkOpencodeCredentials", () => {
|
|
|
652
654
|
).toBe(true);
|
|
653
655
|
});
|
|
654
656
|
|
|
657
|
+
test("strict: nan/* needs NAN_API_KEY or its HELMCODE_API_NAN alias", () => {
|
|
658
|
+
const env = { MODEL_OVERRIDE: "nan/glm5.3-flash", OPENROUTER_API_KEY: "x" };
|
|
659
|
+
const missing = checkOpencodeCredentials(env, { homeDir: HOME, fs: noFiles });
|
|
660
|
+
expect(missing.ready).toBe(false);
|
|
661
|
+
expect(missing.missing).toContain("NAN_API_KEY");
|
|
662
|
+
for (const name of ["NAN_API_KEY", "HELMCODE_API_NAN"]) {
|
|
663
|
+
expect(
|
|
664
|
+
checkOpencodeCredentials({ ...env, [name]: "x" }, { homeDir: HOME, fs: noFiles }).ready,
|
|
665
|
+
).toBe(true);
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
test("strict: helmcode/* needs HELMCODE_API_KEY, not the NaN alias", () => {
|
|
670
|
+
const env = { MODEL_OVERRIDE: "helmcode/glm5.3", HELMCODE_API_NAN: "x" };
|
|
671
|
+
const missing = checkOpencodeCredentials(env, { homeDir: HOME, fs: noFiles });
|
|
672
|
+
expect(missing.ready).toBe(false);
|
|
673
|
+
expect(missing.missing).toContain("HELMCODE_API_KEY");
|
|
674
|
+
expect(
|
|
675
|
+
checkOpencodeCredentials({ ...env, HELMCODE_API_KEY: "x" }, { homeDir: HOME, fs: noFiles })
|
|
676
|
+
.ready,
|
|
677
|
+
).toBe(true);
|
|
678
|
+
});
|
|
679
|
+
|
|
680
|
+
test("permissive: a NaN or Helmcode key alone is enough", () => {
|
|
681
|
+
for (const name of ["NAN_API_KEY", "HELMCODE_API_NAN", "HELMCODE_API_KEY"]) {
|
|
682
|
+
expect(checkOpencodeCredentials({ [name]: "x" }, { homeDir: HOME, fs: noFiles }).ready).toBe(
|
|
683
|
+
true,
|
|
684
|
+
);
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
|
|
655
688
|
test("not ready when nothing is set", () => {
|
|
656
689
|
const status = checkOpencodeCredentials({}, { homeDir: HOME, fs: noFiles });
|
|
657
690
|
expect(status.ready).toBe(false);
|
|
@@ -923,6 +956,112 @@ describe("REQUIRED_CRED_VARS_BY_PROVIDER", () => {
|
|
|
923
956
|
// acp is credential-free by design: the target process owns its own auth.
|
|
924
957
|
expect(REQUIRED_CRED_VARS_BY_PROVIDER.acp).toEqual([]);
|
|
925
958
|
});
|
|
959
|
+
|
|
960
|
+
test("pi and opencode list the NaN (both names) and Helmcode key vars", () => {
|
|
961
|
+
for (const p of ["pi", "opencode"] as const) {
|
|
962
|
+
expect(REQUIRED_CRED_VARS_BY_PROVIDER[p]).toEqual(
|
|
963
|
+
expect.arrayContaining(["NAN_API_KEY", "HELMCODE_API_NAN", "HELMCODE_API_KEY"]),
|
|
964
|
+
);
|
|
965
|
+
}
|
|
966
|
+
});
|
|
967
|
+
});
|
|
968
|
+
|
|
969
|
+
describe("NaN and Helmcode live probes", () => {
|
|
970
|
+
const envReady = { ready: true, missing: [], satisfiedBy: "env" as const };
|
|
971
|
+
|
|
972
|
+
function fakeProvider(status: number) {
|
|
973
|
+
const seen: Array<{ path: string; authorization: string | null }> = [];
|
|
974
|
+
const server = Bun.serve({
|
|
975
|
+
port: 0,
|
|
976
|
+
fetch(req) {
|
|
977
|
+
seen.push({
|
|
978
|
+
path: new URL(req.url).pathname,
|
|
979
|
+
authorization: req.headers.get("authorization"),
|
|
980
|
+
});
|
|
981
|
+
return new Response(status === 200 ? '{"data":[]}' : '{"error":"Invalid API key."}', {
|
|
982
|
+
status,
|
|
983
|
+
});
|
|
984
|
+
},
|
|
985
|
+
});
|
|
986
|
+
return { server, seen, baseUrl: `${server.url.toString().replace(/\/$/, "")}/v1` };
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
for (const [name, probe] of [
|
|
990
|
+
[
|
|
991
|
+
"nan",
|
|
992
|
+
(key: string, url: string) =>
|
|
993
|
+
checkOpenAICompatibleProvider(OPENAI_COMPATIBLE_PROVIDERS.nan, key, url),
|
|
994
|
+
],
|
|
995
|
+
[
|
|
996
|
+
"helmcode",
|
|
997
|
+
(key: string, url: string) =>
|
|
998
|
+
checkOpenAICompatibleProvider(OPENAI_COMPATIBLE_PROVIDERS.helmcode, key, url),
|
|
999
|
+
],
|
|
1000
|
+
] as const) {
|
|
1001
|
+
test(`${name} probe lists models with a Bearer key at the injected base URL`, async () => {
|
|
1002
|
+
const ok = fakeProvider(200);
|
|
1003
|
+
const bad = fakeProvider(401);
|
|
1004
|
+
try {
|
|
1005
|
+
expect(await probe("fixture-key", `${ok.baseUrl}/`)).toMatchObject({ ok: true });
|
|
1006
|
+
expect(ok.seen).toEqual([{ path: "/v1/models", authorization: "Bearer fixture-key" }]);
|
|
1007
|
+
const failure = await probe("fixture-key", bad.baseUrl);
|
|
1008
|
+
expect(failure.ok).toBe(false);
|
|
1009
|
+
expect(failure.error).toContain("HTTP 401");
|
|
1010
|
+
} finally {
|
|
1011
|
+
ok.server.stop(true);
|
|
1012
|
+
bad.server.stop(true);
|
|
1013
|
+
}
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
for (const provider of ["pi", "opencode"] as const) {
|
|
1018
|
+
for (const [env, url] of [
|
|
1019
|
+
[{ NAN_API_KEY: "fixture-nan" }, "https://api.nan.builders/v1/models"],
|
|
1020
|
+
[{ HELMCODE_API_NAN: "fixture-nan" }, "https://api.nan.builders/v1/models"],
|
|
1021
|
+
[{ HELMCODE_API_KEY: "fixture-helm" }, "https://api.helmcode.com/v1/models"],
|
|
1022
|
+
// `<ID>_BASE_URL` moves the probe with the provider.
|
|
1023
|
+
[
|
|
1024
|
+
{ NAN_API_KEY: "fixture-nan", NAN_BASE_URL: "https://nan-gw.example.test/v1/" },
|
|
1025
|
+
"https://nan-gw.example.test/v1/models",
|
|
1026
|
+
],
|
|
1027
|
+
] as const) {
|
|
1028
|
+
test(`${provider}: ${Object.keys(env).join("+")} is probed at ${url}`, async () => {
|
|
1029
|
+
const realFetch = globalThis.fetch;
|
|
1030
|
+
const fetchMock = mock(async (_url: string | URL | Request, _init?: RequestInit) => {
|
|
1031
|
+
return new Response("{}", { status: 200 });
|
|
1032
|
+
});
|
|
1033
|
+
globalThis.fetch = fetchMock as typeof fetch;
|
|
1034
|
+
try {
|
|
1035
|
+
const result = await validateProviderCredentials(provider, { ...env }, envReady);
|
|
1036
|
+
expect(result.ok).toBe(true);
|
|
1037
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
1038
|
+
expect(String(fetchMock.mock.calls[0]?.[0])).toBe(url);
|
|
1039
|
+
const headers = fetchMock.mock.calls[0]?.[1]?.headers as Record<string, string>;
|
|
1040
|
+
expect(headers.Authorization).toBe(`Bearer ${Object.values(env)[0]}`);
|
|
1041
|
+
} finally {
|
|
1042
|
+
globalThis.fetch = realFetch;
|
|
1043
|
+
}
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
test(`${provider}: an OpenRouter key keeps the probe ahead of a NaN key`, async () => {
|
|
1048
|
+
const realFetch = globalThis.fetch;
|
|
1049
|
+
const fetchMock = mock(async (_url: string | URL | Request, _init?: RequestInit) => {
|
|
1050
|
+
return new Response("{}", { status: 200 });
|
|
1051
|
+
});
|
|
1052
|
+
globalThis.fetch = fetchMock as typeof fetch;
|
|
1053
|
+
try {
|
|
1054
|
+
await validateProviderCredentials(
|
|
1055
|
+
provider,
|
|
1056
|
+
{ OPENROUTER_API_KEY: "fixture-or", NAN_API_KEY: "fixture-nan" },
|
|
1057
|
+
envReady,
|
|
1058
|
+
);
|
|
1059
|
+
expect(String(fetchMock.mock.calls[0]?.[0])).not.toContain("nan.builders");
|
|
1060
|
+
} finally {
|
|
1061
|
+
globalThis.fetch = realFetch;
|
|
1062
|
+
}
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
926
1065
|
});
|
|
927
1066
|
|
|
928
1067
|
// ─── Migration 055: report composition + opt-out ────────────────────────────
|
|
@@ -84,4 +84,25 @@ describe("validateOpencodeCredentials", () => {
|
|
|
84
84
|
validateOpencodeCredentials({ OPENROUTER_API_KEY: "sk-or", ANTHROPIC_API_KEY: "sk-ant" }),
|
|
85
85
|
).toBe("openrouter_api_key");
|
|
86
86
|
});
|
|
87
|
+
|
|
88
|
+
test("accepts a NaN key under either name", () => {
|
|
89
|
+
expect(validateOpencodeCredentials({ NAN_API_KEY: "example-nan" })).toBe("nan_api_key");
|
|
90
|
+
expect(validateOpencodeCredentials({ HELMCODE_API_NAN: "example-nan" })).toBe("nan_api_key");
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("accepts a Helmcode key", () => {
|
|
94
|
+
expect(validateOpencodeCredentials({ HELMCODE_API_KEY: "example-helm" })).toBe(
|
|
95
|
+
"helmcode_api_key",
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("keeps OpenRouter ahead of NaN and Helmcode", () => {
|
|
100
|
+
expect(
|
|
101
|
+
validateOpencodeCredentials({
|
|
102
|
+
OPENROUTER_API_KEY: "sk-or",
|
|
103
|
+
NAN_API_KEY: "example-nan",
|
|
104
|
+
HELMCODE_API_KEY: "example-helm",
|
|
105
|
+
}),
|
|
106
|
+
).toBe("openrouter_api_key");
|
|
107
|
+
});
|
|
87
108
|
});
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
1
2
|
import { afterEach, describe, expect, test } from "bun:test";
|
|
3
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
2
6
|
import * as facade from "../be/db";
|
|
3
7
|
import * as runtime from "../be/db/runtime";
|
|
8
|
+
import { CHILD_PROCESS_TEST_BUDGET_MS, expectChildOk, runChild } from "./test-proc";
|
|
4
9
|
|
|
5
10
|
const runtimeExports = [
|
|
6
11
|
"__resetSqliteVecExtensionPathCacheForTests",
|
|
@@ -67,4 +72,60 @@ describe("database runtime facade", () => {
|
|
|
67
72
|
globals.__testMigrationTemplate = template;
|
|
68
73
|
}
|
|
69
74
|
});
|
|
75
|
+
|
|
76
|
+
// rbac-admission-e2e restarted its server on an existing DB and the server
|
|
77
|
+
// died with "Encryption key not resolved yet": boot hit SQLITE_BUSY before
|
|
78
|
+
// resolving the key, and the db-client's BUSY retry reused the half-booted
|
|
79
|
+
// handle instead of booting again. Child processes boot cold (no test
|
|
80
|
+
// template) and leave no in-process connection blocking the lock below.
|
|
81
|
+
test(
|
|
82
|
+
"a cold boot that hits SQLITE_BUSY boots again before serving queries",
|
|
83
|
+
async () => {
|
|
84
|
+
const dir = mkdtempSync(join(tmpdir(), "db-runtime-busy-"));
|
|
85
|
+
const dbPath = join(dir, "boot.sqlite");
|
|
86
|
+
const child = (source: string) =>
|
|
87
|
+
runChild([process.execPath, "--eval", source], {
|
|
88
|
+
cwd: new URL("../../", import.meta.url).pathname,
|
|
89
|
+
env: { ...process.env, DATABASE_PATH: dbPath, AGENT_SWARM_TELEMETRY_DISABLED: "1" },
|
|
90
|
+
});
|
|
91
|
+
try {
|
|
92
|
+
expectChildOk(
|
|
93
|
+
await child(`
|
|
94
|
+
const db = await import("./src/be/db");
|
|
95
|
+
db.initDb(process.env.DATABASE_PATH);
|
|
96
|
+
await db.upsertSwarmConfig({ scope: "global", key: "BOOT_BUSY_SECRET", value: "boot-busy-value", isSecret: true });
|
|
97
|
+
db.closeDb();
|
|
98
|
+
`),
|
|
99
|
+
"seed",
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const holder = new Database(dbPath);
|
|
103
|
+
holder.run("PRAGMA locking_mode = EXCLUSIVE");
|
|
104
|
+
holder.run("BEGIN EXCLUSIVE");
|
|
105
|
+
let released = false;
|
|
106
|
+
const releaseLock = () => {
|
|
107
|
+
if (released) return;
|
|
108
|
+
released = true;
|
|
109
|
+
holder.run("COMMIT");
|
|
110
|
+
holder.close();
|
|
111
|
+
};
|
|
112
|
+
const release = setTimeout(releaseLock, 500);
|
|
113
|
+
try {
|
|
114
|
+
const read = await child(`
|
|
115
|
+
const db = await import("./src/be/db");
|
|
116
|
+
const configs = await db.getInjectableGlobalConfigs();
|
|
117
|
+
console.log("VALUE=" + configs.find((c) => c.key === "BOOT_BUSY_SECRET")?.value);
|
|
118
|
+
`);
|
|
119
|
+
expect(read.stderr).not.toContain("Encryption key not resolved yet");
|
|
120
|
+
expect(read.stdout).toContain("VALUE=boot-busy-value");
|
|
121
|
+
} finally {
|
|
122
|
+
clearTimeout(release);
|
|
123
|
+
releaseLock();
|
|
124
|
+
}
|
|
125
|
+
} finally {
|
|
126
|
+
rmSync(dir, { recursive: true, force: true });
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
CHILD_PROCESS_TEST_BUDGET_MS * 2,
|
|
130
|
+
);
|
|
70
131
|
});
|
|
@@ -72,6 +72,7 @@ type:McpServerFilters
|
|
|
72
72
|
type:McpServerInsert
|
|
73
73
|
type:MentionPreview
|
|
74
74
|
type:PageListOptions
|
|
75
|
+
type:PendingChatRelay
|
|
75
76
|
type:PlanSource
|
|
76
77
|
type:RecordBudgetRefusalNotificationInput
|
|
77
78
|
type:ScheduledTaskFilters
|
|
@@ -237,6 +238,7 @@ value:getAgentMcpServers
|
|
|
237
238
|
value:getAgentSkills
|
|
238
239
|
value:getAgentStatusCounts
|
|
239
240
|
value:getAgentWithTasks
|
|
241
|
+
value:getAgentWorkingOnContextKey
|
|
240
242
|
value:getAgentWorkingOnThread
|
|
241
243
|
value:getAllAgentMailInboxMappings
|
|
242
244
|
value:getAllAgents
|
|
@@ -298,8 +300,10 @@ value:getKv
|
|
|
298
300
|
value:getLastReadAt
|
|
299
301
|
value:getLastRunStart
|
|
300
302
|
value:getLastSuccessfulRun
|
|
303
|
+
value:getLatestActiveTaskByContextKey
|
|
301
304
|
value:getLatestActiveTaskInThread
|
|
302
305
|
value:getLatestContextVersion
|
|
306
|
+
value:getLatestLeadTaskByContextKey
|
|
303
307
|
value:getLatestLeadTaskInThread
|
|
304
308
|
value:getLatestPageBySlug
|
|
305
309
|
value:getLatestScriptRunStepTaskByContextKey
|
|
@@ -329,6 +333,7 @@ value:getPageVersion
|
|
|
329
333
|
value:getPageVersions
|
|
330
334
|
value:getPausedTasksForAgent
|
|
331
335
|
value:getPendingApprovalVoteState
|
|
336
|
+
value:getPendingChatRelayTasks
|
|
332
337
|
value:getPendingEventWaitNames
|
|
333
338
|
value:getPendingSlackRelayTasks
|
|
334
339
|
value:getPendingSteeringForAgent
|
|
@@ -426,6 +431,7 @@ value:getWorkflowRunStepsByRunId
|
|
|
426
431
|
value:getWorkflowVersion
|
|
427
432
|
value:getWorkflowVersions
|
|
428
433
|
value:getWorkflowsByScheduleId
|
|
434
|
+
value:giveUpStaleChatRelays
|
|
429
435
|
value:hasBudgetRefusalNotificationToday
|
|
430
436
|
value:hasCapacity
|
|
431
437
|
value:hasFirstCompletedTask
|
|
@@ -477,6 +483,9 @@ value:listUserFavorites
|
|
|
477
483
|
value:listWorkflowRuns
|
|
478
484
|
value:listWorkflowRunsPage
|
|
479
485
|
value:listWorkflows
|
|
486
|
+
value:markChatRelayAttempted
|
|
487
|
+
value:markChatRelayDelivered
|
|
488
|
+
value:markChatRelayGivenUp
|
|
480
489
|
value:markFinalizedSlackRelaysDelivered
|
|
481
490
|
value:markInboxMessageDelegated
|
|
482
491
|
value:markInboxMessageRead
|
|
@@ -505,6 +514,7 @@ value:promoteDraftTask
|
|
|
505
514
|
value:reassociateSessionLogs
|
|
506
515
|
value:recordApprovalVotes
|
|
507
516
|
value:recordBudgetRefusalNotification
|
|
517
|
+
value:recordChatRelayError
|
|
508
518
|
value:recordInlineScriptRun
|
|
509
519
|
value:recordKeyAuthFailure
|
|
510
520
|
value:recordKeyRateLimitWindows
|
|
@@ -598,6 +608,7 @@ value:upsertSwarmConfig
|
|
|
598
608
|
value:withFavoriteFlags`.split("\n");
|
|
599
609
|
const selected = `type:ExistingTrackerContextWork
|
|
600
610
|
type:ExistingTrackerContextWorkReason
|
|
611
|
+
type:PendingChatRelay
|
|
601
612
|
type:TaskFilters
|
|
602
613
|
value:findCompletedTaskInThread
|
|
603
614
|
value:findExistingLinearTrackerContextWork
|
|
@@ -605,17 +616,21 @@ value:findRecentCancelledTaskInThread
|
|
|
605
616
|
value:findTaskByGitHub
|
|
606
617
|
value:findTaskByVcs
|
|
607
618
|
value:getAgentCurrentTask
|
|
619
|
+
value:getAgentWorkingOnContextKey
|
|
608
620
|
value:getAgentWorkingOnThread
|
|
609
621
|
value:getAllTasks
|
|
610
622
|
value:getChildTasks
|
|
611
623
|
value:getCompletedSlackTasks
|
|
612
624
|
value:getInProgressSlackTasks
|
|
613
625
|
value:getInProgressTasksByContextKey
|
|
626
|
+
value:getLatestActiveTaskByContextKey
|
|
614
627
|
value:getLatestActiveTaskInThread
|
|
628
|
+
value:getLatestLeadTaskByContextKey
|
|
615
629
|
value:getLatestLeadTaskInThread
|
|
616
630
|
value:getLatestScriptRunStepTaskByContextKey
|
|
617
631
|
value:getLatestTaskByContextKey
|
|
618
632
|
value:getMostRecentTaskInThread
|
|
633
|
+
value:getPendingChatRelayTasks
|
|
619
634
|
value:getPendingSlackRelayTasks
|
|
620
635
|
value:getRecentlyFinishedWorkerTasks
|
|
621
636
|
value:getSlackTasksMissingTree
|
|
@@ -626,13 +641,18 @@ value:getTaskStats
|
|
|
626
641
|
value:getTasksByAgentId
|
|
627
642
|
value:getTasksByStatus
|
|
628
643
|
value:getTasksCount
|
|
644
|
+
value:giveUpStaleChatRelays
|
|
629
645
|
value:hasNonTerminalRerouteDecisionChild
|
|
630
646
|
value:hasNonTerminalResumeChild
|
|
631
647
|
value:isLinearTrackerContextKey
|
|
648
|
+
value:markChatRelayAttempted
|
|
649
|
+
value:markChatRelayDelivered
|
|
650
|
+
value:markChatRelayGivenUp
|
|
632
651
|
value:markFinalizedSlackRelaysDelivered
|
|
633
652
|
value:markSlackRelayAttempted
|
|
634
653
|
value:markSlackRelayDelivered
|
|
635
654
|
value:markTasksNotified
|
|
655
|
+
value:recordChatRelayError
|
|
636
656
|
value:resetTasksNotified`.split("\n");
|
|
637
657
|
const internal = [
|
|
638
658
|
"type:AgentTaskRow",
|
|
@@ -95,6 +95,7 @@ type:McpServerFilters
|
|
|
95
95
|
type:McpServerInsert
|
|
96
96
|
type:MentionPreview
|
|
97
97
|
type:PageListOptions
|
|
98
|
+
type:PendingChatRelay
|
|
98
99
|
type:PlanSource
|
|
99
100
|
type:RecordBudgetRefusalNotificationInput
|
|
100
101
|
type:ScheduledTaskFilters
|
|
@@ -260,6 +261,7 @@ value:getAgentMcpServers
|
|
|
260
261
|
value:getAgentSkills
|
|
261
262
|
value:getAgentStatusCounts
|
|
262
263
|
value:getAgentWithTasks
|
|
264
|
+
value:getAgentWorkingOnContextKey
|
|
263
265
|
value:getAgentWorkingOnThread
|
|
264
266
|
value:getAllAgentMailInboxMappings
|
|
265
267
|
value:getAllAgents
|
|
@@ -321,8 +323,10 @@ value:getKv
|
|
|
321
323
|
value:getLastReadAt
|
|
322
324
|
value:getLastRunStart
|
|
323
325
|
value:getLastSuccessfulRun
|
|
326
|
+
value:getLatestActiveTaskByContextKey
|
|
324
327
|
value:getLatestActiveTaskInThread
|
|
325
328
|
value:getLatestContextVersion
|
|
329
|
+
value:getLatestLeadTaskByContextKey
|
|
326
330
|
value:getLatestLeadTaskInThread
|
|
327
331
|
value:getLatestPageBySlug
|
|
328
332
|
value:getLatestScriptRunStepTaskByContextKey
|
|
@@ -352,6 +356,7 @@ value:getPageVersion
|
|
|
352
356
|
value:getPageVersions
|
|
353
357
|
value:getPausedTasksForAgent
|
|
354
358
|
value:getPendingApprovalVoteState
|
|
359
|
+
value:getPendingChatRelayTasks
|
|
355
360
|
value:getPendingEventWaitNames
|
|
356
361
|
value:getPendingSlackRelayTasks
|
|
357
362
|
value:getPendingSteeringForAgent
|
|
@@ -449,6 +454,7 @@ value:getWorkflowRunStepsByRunId
|
|
|
449
454
|
value:getWorkflowVersion
|
|
450
455
|
value:getWorkflowVersions
|
|
451
456
|
value:getWorkflowsByScheduleId
|
|
457
|
+
value:giveUpStaleChatRelays
|
|
452
458
|
value:hasBudgetRefusalNotificationToday
|
|
453
459
|
value:hasCapacity
|
|
454
460
|
value:hasFirstCompletedTask
|
|
@@ -500,6 +506,9 @@ value:listUserFavorites
|
|
|
500
506
|
value:listWorkflowRuns
|
|
501
507
|
value:listWorkflowRunsPage
|
|
502
508
|
value:listWorkflows
|
|
509
|
+
value:markChatRelayAttempted
|
|
510
|
+
value:markChatRelayDelivered
|
|
511
|
+
value:markChatRelayGivenUp
|
|
503
512
|
value:markFinalizedSlackRelaysDelivered
|
|
504
513
|
value:markInboxMessageDelegated
|
|
505
514
|
value:markInboxMessageRead
|
|
@@ -528,6 +537,7 @@ value:promoteDraftTask
|
|
|
528
537
|
value:reassociateSessionLogs
|
|
529
538
|
value:recordApprovalVotes
|
|
530
539
|
value:recordBudgetRefusalNotification
|
|
540
|
+
value:recordChatRelayError
|
|
531
541
|
value:recordInlineScriptRun
|
|
532
542
|
value:recordKeyAuthFailure
|
|
533
543
|
value:recordKeyRateLimitWindows
|
|
@@ -78,7 +78,7 @@ describe("docs API index footprint", () => {
|
|
|
78
78
|
expect(tasks).toContain('"path":"/api/task-templates","method":"get"');
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
-
test("OpenAPI and generated pages keep all
|
|
81
|
+
test("OpenAPI and generated pages keep all 425 operations", async () => {
|
|
82
82
|
const spec = await Bun.file(resolve(repoRoot, "openapi.json")).json();
|
|
83
83
|
const operationKeys = [];
|
|
84
84
|
const tags = new Set();
|
|
@@ -103,8 +103,8 @@ describe("docs API index footprint", () => {
|
|
|
103
103
|
expect(spec.paths["/api/agents/{id}/runtime"]?.get).toBeDefined();
|
|
104
104
|
|
|
105
105
|
const generatedKeys = await generatedOperationKeys();
|
|
106
|
-
expect(operationKeys).toHaveLength(
|
|
107
|
-
expect(generatedKeys).toHaveLength(
|
|
106
|
+
expect(operationKeys).toHaveLength(425);
|
|
107
|
+
expect(generatedKeys).toHaveLength(425);
|
|
108
108
|
expect(new Set(generatedKeys)).toEqual(new Set(operationKeys));
|
|
109
109
|
});
|
|
110
110
|
|
|
@@ -376,7 +376,7 @@ describe("dsh harness", () => {
|
|
|
376
376
|
await rename(join(config.cwd, "dsh"), join(config.cwd, "npx"));
|
|
377
377
|
config.env = { ...config.env, DSH_BINARY: "", PATH: config.cwd };
|
|
378
378
|
await expect(new DshAdapter().createSession(config)).rejects.toThrow(
|
|
379
|
-
"dsh CLI not found. Install @deepseek-ai/dsh@0.2.1-alpha.
|
|
379
|
+
"dsh CLI not found. Install @deepseek-ai/dsh@0.2.1-alpha.4",
|
|
380
380
|
);
|
|
381
381
|
expect(await Bun.file(join(config.cwd, "invocation.json")).exists()).toBe(false);
|
|
382
382
|
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { afterEach, expect, test } from "bun:test";
|
|
2
|
+
import { ALL_CAPABILITIES, getEnabledCapabilities, hasCapability } from "../server";
|
|
3
|
+
|
|
4
|
+
const originalCapabilities = process.env.CAPABILITIES;
|
|
5
|
+
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
if (originalCapabilities === undefined) delete process.env.CAPABILITIES;
|
|
8
|
+
else process.env.CAPABILITIES = originalCapabilities;
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
// `services` was a real capability until the PM2 service registry was removed.
|
|
12
|
+
// A deployment that still lists it must keep registering agents: the register
|
|
13
|
+
// response validates enabledCapabilities against ALL_CAPABILITIES.
|
|
14
|
+
test("enabledCapabilities drops retired and free-form names", () => {
|
|
15
|
+
process.env.CAPABILITIES = "core,services,artifacts,pages";
|
|
16
|
+
|
|
17
|
+
expect(ALL_CAPABILITIES as readonly string[]).not.toContain("services");
|
|
18
|
+
expect(getEnabledCapabilities()).toEqual(["core", "pages"]);
|
|
19
|
+
expect(hasCapability("pages")).toBe(true);
|
|
20
|
+
});
|
|
@@ -221,28 +221,34 @@ describe("wait_for_api_ready: immediate success", () => {
|
|
|
221
221
|
|
|
222
222
|
describe("wait_for_api_ready: transient failure then success", () => {
|
|
223
223
|
test("retries roughly once per second until the server recovers", async () => {
|
|
224
|
-
|
|
224
|
+
// A per-test path prefix: an ephemeral port can be reused from another test
|
|
225
|
+
// process whose poller still hits /health, and those stray requests used
|
|
226
|
+
// to count as retries (3 requests in 1033 ms on CI).
|
|
227
|
+
const prefix = `/${crypto.randomUUID()}`;
|
|
228
|
+
const requestTimes: number[] = [];
|
|
225
229
|
server = Bun.serve({
|
|
226
230
|
port: 0,
|
|
227
231
|
hostname: "127.0.0.1",
|
|
228
232
|
fetch(req) {
|
|
229
233
|
const url = new URL(req.url);
|
|
230
|
-
if (url.pathname !==
|
|
231
|
-
|
|
232
|
-
if (
|
|
234
|
+
if (url.pathname !== `${prefix}/health`) return new Response("not found", { status: 404 });
|
|
235
|
+
requestTimes.push(performance.now());
|
|
236
|
+
if (requestTimes.length < 3) return new Response("unavailable", { status: 503 });
|
|
233
237
|
return new Response("ok", { status: 200 });
|
|
234
238
|
},
|
|
235
239
|
});
|
|
236
240
|
|
|
237
|
-
const result = await runWaitForApiReady(server.url.
|
|
241
|
+
const result = await runWaitForApiReady(`${server.url.origin}${prefix}/`, {
|
|
238
242
|
WORKER_API_READY_TIMEOUT_SECONDS: "10",
|
|
239
243
|
});
|
|
240
244
|
|
|
241
245
|
expect(result.exitCode).toBe(0);
|
|
242
|
-
expect(
|
|
246
|
+
expect(requestTimes).toHaveLength(3);
|
|
243
247
|
expect(result.stdout).toContain("API ready at");
|
|
244
|
-
//
|
|
245
|
-
|
|
248
|
+
// Each retry waits out `sleep 1` after the previous response, so the
|
|
249
|
+
// server-side gap cannot shrink under load: paced, not a hot loop.
|
|
250
|
+
expect(requestTimes[1]! - requestTimes[0]!).toBeGreaterThanOrEqual(900);
|
|
251
|
+
expect(requestTimes[2]! - requestTimes[1]!).toBeGreaterThanOrEqual(900);
|
|
246
252
|
expect(result.durationMs).toBeLessThan(15000);
|
|
247
253
|
}, 20000);
|
|
248
254
|
});
|
|
@@ -93,7 +93,10 @@ function extractExportFilter(lineMarker: string): string {
|
|
|
93
93
|
const line = script.split("\n").find((l) => l.includes(lineMarker) && l.includes("jq -r '"));
|
|
94
94
|
if (!line) throw new Error(`Could not locate the jq line containing ${lineMarker}`);
|
|
95
95
|
const start = line.indexOf("jq -r '") + "jq -r '".length;
|
|
96
|
-
|
|
96
|
+
// Inline programs read /tmp/swarm_config.json; the swarm_config_env_lines
|
|
97
|
+
// function reads its "$1" argument.
|
|
98
|
+
const ends = ["' /tmp/swarm_config.json", '\' "$1"'].map((tail) => line.indexOf(tail, start));
|
|
99
|
+
const end = ends.find((index) => index !== -1) ?? -1;
|
|
97
100
|
if (end === -1) throw new Error(`Could not locate the end of the jq program for ${lineMarker}`);
|
|
98
101
|
return line.slice(start, end);
|
|
99
102
|
}
|
|
@@ -127,7 +130,7 @@ describe("entrypoint config env export: real jq filter", () => {
|
|
|
127
130
|
test(
|
|
128
131
|
"never exports codex_oauth or codex_oauth_<n>, nor the runner-resolved keys",
|
|
129
132
|
async () => {
|
|
130
|
-
const lines = await runJq(extractExportFilter("
|
|
133
|
+
const lines = await runJq(extractExportFilter("(.value | @sh)"), configs);
|
|
131
134
|
const keys = lines.map((l) => l.slice(0, l.indexOf("=")));
|
|
132
135
|
expect(keys).toEqual(["NORMAL", "codex_oauth_extra"]);
|
|
133
136
|
expect(lines.join("\n")).not.toContain("rt.secret");
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
2
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { CHILD_PROCESS_TEST_BUDGET_MS, expectChildOk, runChild } from "./test-proc";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Runs the real swarm_config_env block from docker-entrypoint.sh (extracted
|
|
9
|
+
* between its BEGIN/END markers) against a /api/config/resolved fixture, the
|
|
10
|
+
* same way the entrypoint sources it, and reads the resulting env.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const entrypoint = readFileSync("docker-entrypoint.sh", "utf8");
|
|
14
|
+
const block = entrypoint.slice(
|
|
15
|
+
entrypoint.indexOf("# BEGIN swarm_config_env"),
|
|
16
|
+
entrypoint.indexOf("# END swarm_config_env"),
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
let dir = "";
|
|
20
|
+
|
|
21
|
+
beforeAll(() => {
|
|
22
|
+
dir = mkdtempSync(join(tmpdir(), "entrypoint-export-"));
|
|
23
|
+
});
|
|
24
|
+
afterAll(() => {
|
|
25
|
+
rmSync(dir, { recursive: true, force: true });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
async function exportedEnv(configs: unknown[], containerEnv: Record<string, string> = {}) {
|
|
29
|
+
const fixture = join(dir, `${crypto.randomUUID()}.json`);
|
|
30
|
+
writeFileSync(fixture, JSON.stringify({ configs }));
|
|
31
|
+
const script = `${block}
|
|
32
|
+
swarm_config_env_lines "$1" > "$1.env"
|
|
33
|
+
set -a; . "$1.env"; set +a
|
|
34
|
+
for withheld_key in $(swarm_config_withheld_keys "$1"); do unset "$withheld_key"; done
|
|
35
|
+
env
|
|
36
|
+
`;
|
|
37
|
+
const result = await runChild(["bash", "-c", script, "bash", fixture], {
|
|
38
|
+
env: { PATH: process.env.PATH ?? "/usr/bin:/bin", ...containerEnv },
|
|
39
|
+
timeoutMs: CHILD_PROCESS_TEST_BUDGET_MS,
|
|
40
|
+
});
|
|
41
|
+
expectChildOk(result, "entrypoint export block");
|
|
42
|
+
return Object.fromEntries(
|
|
43
|
+
result.stdout
|
|
44
|
+
.split("\n")
|
|
45
|
+
.filter((line) => line.includes("="))
|
|
46
|
+
.map((line) => [line.slice(0, line.indexOf("=")), line.slice(line.indexOf("=") + 1)]),
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
describe("docker-entrypoint.sh swarm_config_env", () => {
|
|
51
|
+
test("markers are present", () => {
|
|
52
|
+
expect(block).toContain("swarm_config_env_lines()");
|
|
53
|
+
expect(block).toContain("swarm_config_withheld_keys()");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("exports exportToEnv rows and drops withheld ones, including container copies", async () => {
|
|
57
|
+
const env = await exportedEnv(
|
|
58
|
+
[
|
|
59
|
+
{ key: "GITHUB_TOKEN", value: "row-github", isSecret: true, exportToEnv: true },
|
|
60
|
+
{ key: "VERCEL_TOKEN", value: "row-vercel", isSecret: true, exportToEnv: false },
|
|
61
|
+
{ key: "QUOTED", value: "it's $HOME", isSecret: false, exportToEnv: true },
|
|
62
|
+
// A pre-215 API sends no flag: the row keeps exporting.
|
|
63
|
+
{ key: "LEGACY", value: "row-legacy", isSecret: true },
|
|
64
|
+
{ key: "CF-Access-Client-Id", value: "x", isSecret: true, exportToEnv: true },
|
|
65
|
+
{ key: "codex_oauth_1", value: "x", isSecret: true, exportToEnv: true },
|
|
66
|
+
{ key: "HARNESS_PROVIDER", value: "pi", isSecret: false, exportToEnv: true },
|
|
67
|
+
],
|
|
68
|
+
{ VERCEL_TOKEN: "container-vercel" },
|
|
69
|
+
);
|
|
70
|
+
expect(env.GITHUB_TOKEN).toBe("row-github");
|
|
71
|
+
expect(env.QUOTED).toBe("it's $HOME");
|
|
72
|
+
expect(env.LEGACY).toBe("row-legacy");
|
|
73
|
+
expect(env.VERCEL_TOKEN).toBeUndefined();
|
|
74
|
+
expect(env.codex_oauth_1).toBeUndefined();
|
|
75
|
+
expect(env.HARNESS_PROVIDER).toBeUndefined();
|
|
76
|
+
expect(Object.values(env)).not.toContain("row-vercel");
|
|
77
|
+
});
|
|
78
|
+
});
|