@desplega.ai/agent-swarm 1.149.1 → 1.151.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 +18 -3
- package/dist/{acp-adapter-vhkzfpjg.js → acp-adapter-ex8hzjfc.js} +5 -5
- package/dist/{actions-9d2694yk.js → actions-2bgpyhww.js} +39 -11
- package/dist/{app-fq2ggynt.js → app-1706zhr1.js} +7 -7
- package/dist/{artifact-gj9arwrr.js → artifact-td4q4dch.js} +1 -1
- package/dist/{assistant-edb6n9nn.js → assistant-bavke5p7.js} +44 -20
- package/dist/{azure-openai-responses-cqar64rc.js → azure-openai-responses-f38x2avq.js} +13 -13
- package/dist/{boot-reembed-msweabbp.js → boot-reembed-3cmrrmpa.js} +9 -9
- package/dist/{boot-reembed-q5wd3tha.js → boot-reembed-nafcmmmc.js} +14 -16
- package/dist/{boot-scrub-logs-3g1az933.js → boot-scrub-logs-cd6a2sq0.js} +5 -5
- package/dist/{claude-adapter-v3rnzsdc.js → claude-adapter-wfp2gzvz.js} +15 -16
- package/dist/{claude-managed-adapter-qvsmh6mv.js → claude-managed-adapter-dsmkcrjy.js} +3 -3
- package/dist/{claude-sdk-session-qxrpsna1.js → claude-sdk-session-bht9jjak.js} +15 -16
- package/dist/{cli-5m0qmvdp.js → cli-0qb1z6s2.js} +1 -1
- package/dist/{cli-9d8ntetj.js → cli-2658f6at.js} +1 -1
- package/dist/{cli-7evafqvy.js → cli-2tbvf1z1.js} +85 -69
- package/dist/{cli-k351hv5k.js → cli-3v9xhjcn.js} +24 -12
- package/dist/{cli-1ebpar1q.js → cli-4wppfkcm.js} +350 -20
- package/dist/{cli-4260r1tg.js → cli-5jd2z7av.js} +97 -84
- package/dist/{cli-cv7s5zdq.js → cli-5tpgq60f.js} +9865 -715
- package/dist/{cli-6skz3rk8.js → cli-7tgcstn2.js} +9 -4
- package/dist/{cli-01g3x1ca.js → cli-9004vfdf.js} +108 -56
- package/dist/{cli-1c94wvcw.js → cli-a1z3h107.js} +124 -99
- package/dist/{cli-9br8ypfv.js → cli-czjtgfys.js} +2 -2
- package/dist/{cli-5my3bjsd.js → cli-d3p82erb.js} +7 -7
- package/dist/{cli-e29gmdmw.js → cli-dv6cdjs2.js} +2 -1
- package/dist/{cli-wby1xnnb.js → cli-f1wky6zp.js} +1 -1
- package/dist/{cli-zvz62chv.js → cli-fm4ytsdk.js} +4 -4
- package/dist/{cli-tg8qj8ee.js → cli-frcta2w4.js} +6 -6
- package/dist/{cli-7xx10h0a.js → cli-g69fdc9g.js} +2 -2
- package/dist/{cli-cmp8g3sw.js → cli-gbfwcd3k.js} +44 -9
- package/dist/{handlers-nsg0bcye.js → cli-gjyvhmmh.js} +97 -45
- package/dist/{cli-08b07b4r.js → cli-ht5rs63n.js} +1 -1
- package/dist/{cli-jecc01cb.js → cli-j4nv2wqy.js} +2 -4
- package/dist/{cli-cd60fv6j.js → cli-j9xczhaq.js} +1 -1
- package/dist/cli-pf9q3696.js +172 -0
- package/dist/{cli-xm87hzbw.js → cli-pgj4a5fb.js} +1 -1
- package/dist/{cli-jezx9b9c.js → cli-ppm4975n.js} +9 -3
- package/dist/{cli-3z634pqe.js → cli-q88st9aj.js} +2 -2
- package/dist/{cli-3sysyjve.js → cli-r2q6pevn.js} +142 -49
- package/dist/{cli-07jd68a1.js → cli-re8z5p8p.js} +1 -1
- package/dist/{cli-qgd4sqz5.js → cli-s14agm5s.js} +121 -14
- package/dist/{cli-svbrpf5q.js → cli-sjaae6ff.js} +9872 -424
- package/dist/{cli-73gq0zxn.js → cli-vwm416m6.js} +13 -13
- package/dist/{cli-4wtq5jjv.js → cli-wbyk465z.js} +1 -1
- package/dist/{cli-3apbzgyk.js → cli-z61ykvam.js} +19 -14
- package/dist/{cli-e06a8a7y.js → cli-zkxymas5.js} +4 -3
- package/dist/cli.js +26 -25
- package/dist/{codex-adapter-jyw7a91z.js → codex-adapter-jjjk8w4m.js} +8 -9
- package/dist/{codex-hook-hfrt9shr.js → codex-hook-8jexc34x.js} +3 -3
- package/dist/{codex-session-runner-bmngj0s5.js → codex-session-runner-nd6ayxkx.js} +8 -9
- package/dist/{commands-n755g391.js → commands-9v4psyq1.js} +5 -5
- package/dist/{db-s1cgh5gv.js → db-wnt58tpe.js} +5 -5
- package/dist/dispatcher-05jh1aqk.js +74 -0
- package/dist/{e2b-p04vmtx0.js → e2b-413b8t4v.js} +1 -1
- package/dist/{google-generative-ai-tsskx7te.js → google-generative-ai-ndjmj5fa.js} +7 -7
- package/dist/{google-vertex-ppw8ydpa.js → google-vertex-fr665tqs.js} +10 -10
- package/dist/handlers-tw90pkh5.js +65 -0
- package/dist/{hook-jf0xe8zh.js → hook-123e2scb.js} +11 -12
- package/dist/{hook-h9cqrm8q.js → hook-sxe3r349.js} +11 -12
- package/dist/{http-nc6pydw5.js → http-ecsar8ez.js} +1442 -581
- package/dist/{index-ezxkds2n.js → index-16js521z.js} +335 -107
- package/dist/{index-769nc012.js → index-hw26vj40.js} +25 -19
- package/dist/{index-0wdy6gwc.js → index-nnrbpcjp.js} +25 -17
- package/dist/index-ymn7em0p.js +25 -0
- package/dist/{index-x1zcj09z.js → index-zj518gf9.js} +26 -20
- package/dist/{keepalive-nesm3xb6.js → keepalive-asqtcm4y.js} +7 -7
- package/dist/{lead-bwy6t2za.js → lead-xbfr7fvt.js} +40 -48
- package/dist/{maintenance-8w393zf0.js → maintenance-qma55qvw.js} +9 -9
- package/dist/{oauth-refresh-sweep-sh8xjy08.js → oauth-refresh-sweep-3s04c6qw.js} +6 -6
- package/dist/{onboard-25ps29h1.js → onboard-drskd386.js} +13 -4
- package/dist/{openai-codex-responses-g7w48y30.js → openai-codex-responses-wy6a43wd.js} +13 -13
- package/dist/{openai-responses-nmeyptke.js → openai-responses-6xwf7bzg.js} +19 -19
- package/dist/{opencode-adapter-dce4wskd.js → opencode-adapter-28axqa09.js} +4 -4
- package/dist/{otel-impl-b93gxnz5.js → otel-impl-943c96er.js} +1 -1
- package/dist/{pi-mono-adapter-zvshk5cj.js → pi-mono-adapter-jcqt71cg.js} +17 -19
- package/dist/{pricing-refresh-5v56x7gb.js → pricing-refresh-mx51az05.js} +7 -7
- package/dist/{rbac-roles-x55cnezn.js → rbac-roles-78baecqd.js} +13 -9
- package/dist/{rbac-roles-0p0s6pbj.js → rbac-roles-wcmrg6sv.js} +7 -7
- package/dist/{render-v2-hyd45w8b.js → render-v2-8zjntgf5.js} +7 -7
- package/dist/{seed-pricing-49gbgn96.js → seed-pricing-jqjs6cws.js} +6 -6
- package/dist/{setup-qvq64vzq.js → setup-4pks0vfk.js} +2 -2
- package/dist/work-objects-wangt792.js +165 -0
- package/dist/{worker-scj60cxg.js → worker-p2mr422x.js} +40 -48
- package/openapi.json +1365 -268
- package/package.json +4 -3
- package/src/agentmail/handlers.ts +95 -66
- package/src/be/budget-refusal-notify.ts +1 -0
- package/src/be/db/tasks/read.ts +3 -0
- package/src/be/db/tasks/write.ts +13 -1
- package/src/be/db-client.ts +5 -0
- package/src/be/db.ts +15 -5
- package/src/be/extensions/db.ts +461 -0
- package/src/be/extensions/validate.ts +107 -0
- package/src/be/memory/boot-reembed.ts +17 -12
- package/src/be/memory/index.ts +12 -0
- package/src/be/memory/providers/openai-embedding.ts +4 -0
- package/src/be/memory/types.ts +2 -0
- package/src/be/migrations/153_deferred_task_wait_members.sql +25 -0
- package/src/be/migrations/154_routing_source.sql +3 -0
- package/src/be/migrations/155_extensions.sql +66 -0
- package/src/be/migrations/156_inbox_item_state_read_at.sql +7 -0
- package/src/be/rbac-roles.ts +3 -2
- package/src/be/scripts/typecheck.ts +59 -41
- package/src/be/seed/schedules-seeder.ts +25 -2
- package/src/be/seed/workflows-seeder.ts +17 -0
- package/src/be/seed-scripts/catalog/delegate.ts +3 -1
- package/src/be/seed-skills/bundled-files.generated.json +1 -1
- package/src/be/seed-skills/index.ts +7 -0
- package/src/be/steering.ts +1 -0
- package/src/be/swarm-config-guard.ts +3 -1
- package/src/commands/credential-refresh.ts +70 -0
- package/src/commands/onboard/compose-generator.ts +14 -2
- package/src/commands/onboard/env-generator.ts +7 -0
- package/src/commands/provider-credentials.ts +2 -25
- package/src/commands/runner.ts +24 -57
- package/src/extensions/apply-task-create.ts +135 -0
- package/src/extensions/bundle-path.ts +10 -0
- package/src/extensions/contract-runtime.ts +7 -0
- package/src/extensions/contract-types.generated.ts +4 -0
- package/src/extensions/contract.ts +270 -0
- package/src/extensions/ctx.ts +186 -0
- package/src/extensions/dispatcher.ts +479 -0
- package/src/extensions/identity.ts +44 -0
- package/src/extensions/lifecycle.ts +281 -0
- package/src/extensions/loader.ts +207 -0
- package/src/extensions/post-bridge.ts +161 -0
- package/src/github/handlers.ts +185 -140
- package/src/gitlab/handlers.ts +97 -77
- package/src/heartbeat/heartbeat.ts +155 -83
- package/src/http/agents.ts +1 -1
- package/src/http/all-routes.ts +1 -0
- package/src/http/approval-requests.ts +1 -0
- package/src/http/apps.ts +14 -9
- package/src/http/config.ts +4 -1
- package/src/http/core.ts +38 -2
- package/src/http/extensions.ts +547 -0
- package/src/http/inbox-state.ts +2 -0
- package/src/http/index.ts +41 -3
- package/src/http/mcp-bridge.ts +96 -62
- package/src/http/mcp.ts +1 -1
- package/src/http/script-runs.ts +5 -0
- package/src/http/status.ts +6 -4
- package/src/http/tasks.ts +51 -30
- package/src/integrations/kapso/inbound.ts +15 -10
- package/src/jira/sync.ts +26 -16
- package/src/linear/sync.ts +26 -16
- package/src/prompts/session-templates.ts +18 -13
- package/src/providers/claude-adapter.ts +21 -8
- package/src/rbac/admission.ts +1 -1
- package/src/rbac/elevated-agents.ts +24 -0
- package/src/rbac/legacy-policy.ts +35 -6
- package/src/rbac/permissions.ts +8 -0
- package/src/scheduler/deferred-task-waits.ts +138 -27
- package/src/scheduler/schedule-task.ts +54 -24
- package/src/scheduler/scheduler.ts +108 -125
- package/src/scripts-runtime/executors/native.ts +5 -1
- package/src/scripts-runtime/executors/types.ts +5 -0
- package/src/scripts-runtime/import-allowlist.ts +79 -19
- package/src/scripts-runtime/sdk-allowlist.ts +4 -0
- package/src/scripts-runtime/swarm-config.ts +8 -0
- package/src/scripts-runtime/swarm-sdk.ts +3 -0
- package/src/scripts-runtime/types/stdlib.d.ts +16 -3
- package/src/scripts-runtime/types/swarm-extension.d.ts +562 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +16 -3
- package/src/server.ts +6 -0
- package/src/slack/HEURISTICS.md +3 -1
- package/src/slack/actions.ts +21 -16
- package/src/slack/app.ts +2 -0
- package/src/slack/assistant.ts +4 -12
- package/src/slack/blocks.ts +1 -1
- package/src/slack/handlers.ts +107 -19
- package/src/slack/inbound-files.ts +9 -5
- package/src/slack/render-v2.ts +188 -38
- package/src/slack/router.ts +13 -3
- package/src/slack/steering.ts +3 -3
- package/src/slack/thread-buffer.ts +66 -23
- package/src/slack/work-objects.test.ts +252 -0
- package/src/slack/work-objects.ts +118 -0
- package/src/tasks/errors.ts +9 -0
- package/src/tasks/sibling-awareness.ts +35 -1
- package/src/tasks/worker-follow-up.ts +67 -11
- package/src/tests/acp-adapter.test.ts +10 -10
- package/src/tests/agent-fs-live-url.test.ts +40 -0
- package/src/tests/agent-fs-provision-seeder.test.ts +12 -12
- package/src/tests/api-key-tracking.test.ts +18 -18
- package/src/tests/api-key.test.ts +4 -2
- package/src/tests/apps-rbac.test.ts +1 -1
- package/src/tests/apps-spike5.test.ts +1 -1
- package/src/tests/apps-sync-engine.test.ts +8 -8
- package/src/tests/apps-user-config.test.ts +1 -1
- package/src/tests/artifact-sdk.test.ts +8 -8
- package/src/tests/asset-key-mcp.test.ts +2 -0
- package/src/tests/automation-preflight-alert.test.ts +1 -1
- package/src/tests/base-prompt.test.ts +7 -6
- package/src/tests/budget-user-scope.test.ts +1 -1
- package/src/tests/budgets-routes.test.ts +1 -1
- package/src/tests/claude-adapter-binary.test.ts +22 -40
- package/src/tests/claude-adapter-otel.test.ts +13 -7
- package/src/tests/claude-adapter.test.ts +8 -6
- package/src/tests/claude-hook-credentials.test.ts +3 -3
- package/src/tests/claude-managed-adapter.test.ts +4 -4
- package/src/tests/claude-managed-setup.test.ts +3 -3
- package/src/tests/claude-sdk-lifecycle.test.ts +1 -1
- package/src/tests/claude-sdk-transport.test.ts +6 -6
- package/src/tests/claude-stop-hook.test.ts +8 -8
- package/src/tests/claude-worker-parity.test.ts +3 -3
- package/src/tests/codex-adapter-pool-auth-revalidate.test.ts +5 -5
- package/src/tests/codex-adapter.test.ts +7 -5
- package/src/tests/codex-app-server.test.ts +2 -2
- package/src/tests/codex-login.test.ts +15 -15
- package/src/tests/codex-oauth-credential-info.test.ts +4 -4
- package/src/tests/codex-oauth-keep-warm.test.ts +4 -4
- package/src/tests/codex-oauth-refresh-lock.test.ts +1 -1
- package/src/tests/codex-oauth-storage.test.ts +7 -7
- package/src/tests/codex-pool.test.ts +1 -1
- package/src/tests/codex-steering-hook.test.ts +1 -1
- package/src/tests/codex-swarm-events.test.ts +1 -1
- package/src/tests/config-api-only-keys.test.ts +1 -1
- package/src/tests/config-session-auth.test.ts +2 -2
- package/src/tests/connection-embedded-auth.test.ts +20 -18
- package/src/tests/core-auth.test.ts +1 -1
- package/src/tests/create-page-tool.test.ts +3 -3
- package/src/tests/credential-refresh.test.ts +115 -0
- package/src/tests/credential-wait.test.ts +2 -2
- package/src/tests/credentials.test.ts +6 -4
- package/src/tests/db-queries-oauth.test.ts +40 -40
- package/src/tests/defer-task.test.ts +73 -8
- package/src/tests/deferred-task-wait-migration.test.ts +64 -0
- package/src/tests/deferred-task-wake.test.ts +349 -8
- package/src/tests/devin-adapter.test.ts +1 -1
- package/src/tests/devin-api.test.ts +1 -1
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/e2b-dispatch.test.ts +21 -19
- package/src/tests/e2e-claude-transport.test.ts +3 -3
- package/src/tests/e2e-redact.test.ts +6 -6
- package/src/tests/ensure-token.test.ts +68 -68
- package/src/tests/entrypoint-api-readiness.test.ts +1 -1
- package/src/tests/entrypoint-codex-oauth-seed.test.ts +13 -13
- package/src/tests/env-flag.test.ts +1 -0
- package/src/tests/events-http.test.ts +1 -1
- package/src/tests/extensions-db.test.ts +216 -0
- package/src/tests/extensions-dispatcher.test.ts +275 -0
- package/src/tests/extensions-example-heartbeat-remediate.test.ts +69 -0
- package/src/tests/extensions-example-mcp-install.test.ts +63 -0
- package/src/tests/extensions-example-no-exclamation-marks.test.ts +72 -0
- package/src/tests/extensions-example-rewrite-and-suppress.test.ts +70 -0
- package/src/tests/extensions-example-route-slack-channel.test.ts +217 -0
- package/src/tests/extensions-heartbeat.test.ts +291 -0
- package/src/tests/extensions-http.test.ts +431 -0
- package/src/tests/extensions-lead-equivalence.test.ts +49 -0
- package/src/tests/extensions-lifecycle.test.ts +209 -0
- package/src/tests/extensions-loader.test.ts +95 -0
- package/src/tests/extensions-mcp-tools.test.ts +245 -0
- package/src/tests/extensions-pre-task.test.ts +487 -0
- package/src/tests/extensions-run-context.test.ts +41 -0
- package/src/tests/extensions-tool-call.test.ts +288 -0
- package/src/tests/extensions-validate.test.ts +196 -0
- package/src/tests/fixtures/extensions/bad-import/hooks.ts +8 -0
- package/src/tests/fixtures/extensions/bad-import/manifest.json +9 -0
- package/src/tests/fixtures/extensions/bad-return-shape/hooks.ts +10 -0
- package/src/tests/fixtures/extensions/bad-return-shape/manifest.json +9 -0
- package/src/tests/fixtures/extensions/block-tasks-from-source/hooks.ts +22 -0
- package/src/tests/fixtures/extensions/block-tasks-from-source/manifest.json +9 -0
- package/src/tests/fixtures/extensions/ignore-channel/hooks.ts +22 -0
- package/src/tests/fixtures/extensions/ignore-channel/manifest.json +9 -0
- package/src/tests/fixtures/extensions/load.ts +10 -0
- package/src/tests/fixtures/extensions/minimal/hooks.ts +7 -0
- package/src/tests/fixtures/extensions/minimal/manifest.json +9 -0
- package/src/tests/fixtures/extensions/never-fail-long-tasks/hooks.ts +11 -0
- package/src/tests/fixtures/extensions/never-fail-long-tasks/manifest.json +9 -0
- package/src/tests/fixtures/extensions/no-exclamation-marks/hooks.ts +23 -0
- package/src/tests/fixtures/extensions/no-exclamation-marks/manifest.json +9 -0
- package/src/tests/fixtures/extensions/post-logger/hooks.ts +9 -0
- package/src/tests/fixtures/extensions/post-logger/manifest.json +9 -0
- package/src/tests/fixtures/extensions/priority-a/hooks.ts +7 -0
- package/src/tests/fixtures/extensions/priority-a/manifest.json +9 -0
- package/src/tests/fixtures/extensions/priority-b/hooks.ts +7 -0
- package/src/tests/fixtures/extensions/priority-b/manifest.json +9 -0
- package/src/tests/fixtures/extensions/record-only-on-tag/hooks.ts +16 -0
- package/src/tests/fixtures/extensions/record-only-on-tag/manifest.json +9 -0
- package/src/tests/fixtures/extensions/reserved-assets/hooks.ts +5 -0
- package/src/tests/fixtures/extensions/reserved-assets/manifest.json +10 -0
- package/src/tests/fixtures/extensions/rewrite-progress-prefix/hooks.ts +22 -0
- package/src/tests/fixtures/extensions/rewrite-progress-prefix/manifest.json +9 -0
- package/src/tests/fixtures/extensions/rewrite-task-priority/hooks.ts +7 -0
- package/src/tests/fixtures/extensions/rewrite-task-priority/manifest.json +9 -0
- package/src/tests/fixtures/extensions/route-channel-to-agent/hooks.ts +26 -0
- package/src/tests/fixtures/extensions/route-channel-to-agent/manifest.json +9 -0
- package/src/tests/fixtures/extensions/slow/hooks.ts +10 -0
- package/src/tests/fixtures/extensions/slow/manifest.json +9 -0
- package/src/tests/fixtures/extensions/suppress-lead-follow-up/hooks.ts +12 -0
- package/src/tests/fixtures/extensions/suppress-lead-follow-up/manifest.json +9 -0
- package/src/tests/fixtures/extensions/throws/hooks.ts +12 -0
- package/src/tests/fixtures/extensions/throws/manifest.json +9 -0
- package/src/tests/fixtures/extensions/worker-runtime/hooks.ts +5 -0
- package/src/tests/fixtures/extensions/worker-runtime/manifest.json +9 -0
- package/src/tests/fs-routes.test.ts +1 -1
- package/src/tests/gitlab-auth.test.ts +10 -10
- package/src/tests/harness-provider-resolution.test.ts +8 -5
- package/src/tests/heartbeat-reroute-decision.test.ts +1 -0
- package/src/tests/helper-credentials.test.ts +137 -0
- package/src/tests/http/context-routes.test.ts +2 -2
- package/src/tests/http-api-integration.test.ts +5 -2
- package/src/tests/http-users.test.ts +1 -1
- package/src/tests/identity-refresh.test.ts +2 -2
- package/src/tests/internal-ai/complete-structured.test.ts +2 -2
- package/src/tests/internal-ai/credentials.test.ts +19 -17
- package/src/tests/jira-metadata.test.ts +1 -1
- package/src/tests/jira-oauth.test.ts +5 -5
- package/src/tests/jira-sync.test.ts +1 -1
- package/src/tests/jira-webhook-lifecycle.test.ts +3 -3
- package/src/tests/jira-webhook.test.ts +2 -2
- package/src/tests/kapso-inbound.test.ts +2 -2
- package/src/tests/kv-http.test.ts +1 -1
- package/src/tests/kv-namespace-resolution.test.ts +1 -1
- package/src/tests/kv-page-proxy.test.ts +2 -2
- package/src/tests/launch-password-rejection.test.ts +2 -2
- package/src/tests/linear-webhook.test.ts +1 -1
- package/src/tests/mcp-oauth-dcr-reuse.test.ts +6 -6
- package/src/tests/mcp-oauth-ensure-token.test.ts +28 -22
- package/src/tests/mcp-oauth-manual-client.test.ts +16 -12
- package/src/tests/mcp-oauth-queries.test.ts +35 -32
- package/src/tests/mcp-oauth-resolve-secrets.test.ts +8 -8
- package/src/tests/mcp-oauth-wrapper.test.ts +20 -20
- package/src/tests/mcp-user-route.test.ts +1 -1
- package/src/tests/memory-edges.test.ts +1 -1
- package/src/tests/memory-edit-authorization.test.ts +32 -0
- package/src/tests/memory-rate-endpoint.test.ts +1 -1
- package/src/tests/memory-rate-tool.test.ts +2 -2
- package/src/tests/memory-rater-e2e.test.ts +1 -1
- package/src/tests/memory-rater-llm-summarizer.test.ts +3 -3
- package/src/tests/memory-rater-llm.test.ts +1 -1
- package/src/tests/model-control.test.ts +3 -0
- package/src/tests/multi-runtime-enabled-stats.test.ts +2 -2
- package/src/tests/multi-runtime-registration.test.ts +111 -17
- package/src/tests/oauth-access-token-tool.test.ts +18 -18
- package/src/tests/oauth-callback-flow.test.ts +8 -8
- package/src/tests/oauth-credential-bindings.test.ts +29 -27
- package/src/tests/oauth-keepalive.test.ts +10 -10
- package/src/tests/oauth-presets.test.ts +13 -5
- package/src/tests/oauth-refresh-failure.test.ts +9 -9
- package/src/tests/oauth-refresh-sweep.test.ts +20 -13
- package/src/tests/oauth-wrapper.test.ts +1 -1
- package/src/tests/onboard-compose.test.ts +47 -3
- package/src/tests/onboard-env.test.ts +26 -26
- package/src/tests/onboard-non-interactive.test.ts +4 -4
- package/src/tests/opencode-adapter.test.ts +1 -1
- package/src/tests/opencode-plugin.test.ts +2 -2
- package/src/tests/otel-session-cost-metrics.test.ts +1 -1
- package/src/tests/page-proxy-authed.test.ts +2 -2
- package/src/tests/page-proxy.test.ts +2 -2
- package/src/tests/page-session.test.ts +7 -7
- package/src/tests/page-viewer-auth.test.ts +2 -2
- package/src/tests/pages-authed-mode.test.ts +1 -1
- package/src/tests/pages-http.test.ts +1 -1
- package/src/tests/pages-password-mode.test.ts +1 -1
- package/src/tests/pages-public-authed-401.test.ts +1 -1
- package/src/tests/pages-public-html.test.ts +2 -2
- package/src/tests/pages-view-count.test.ts +1 -1
- package/src/tests/pi-mono-adapter.test.ts +10 -10
- package/src/tests/pi-mono-extension.test.ts +2 -2
- package/src/tests/preload.ts +5 -0
- package/src/tests/pricing-routes.test.ts +1 -1
- package/src/tests/profile-sync-warning.test.ts +8 -8
- package/src/tests/profile-sync.test.ts +8 -8
- package/src/tests/prompt-template-session.test.ts +36 -5
- package/src/tests/provider-process-group.test.ts +95 -4
- package/src/tests/providers/pi-cost.test.ts +1 -1
- package/src/tests/queue-stall-alarm.test.ts +1 -1
- package/src/tests/rbac-admission.test.ts +19 -4
- package/src/tests/rbac-charact-http.test.ts +1 -1
- package/src/tests/rbac-e2e-helpers.ts +1 -1
- package/src/tests/rbac-engine.test.ts +39 -0
- package/src/tests/realtime-room-auth.test.ts +1 -1
- package/src/tests/realtime-room-surfaces.test.ts +1 -1
- package/src/tests/reload-config.test.ts +45 -1
- package/src/tests/routing-affinity-inventory.test.ts +1 -1
- package/src/tests/routing-reason-contract.test.ts +76 -3
- package/src/tests/routing-reason-inventory.test.ts +11 -6
- package/src/tests/routing-source.test.ts +53 -0
- package/src/tests/runner-agent-fs-provision-retry.test.ts +1 -1
- package/src/tests/runner-context-preamble.test.ts +1 -1
- package/src/tests/runner-deployment-resume.test.ts +1 -1
- package/src/tests/runner-fallback-output.test.ts +1 -1
- package/src/tests/runner-identity-refresh.test.ts +1 -1
- package/src/tests/runner-skills-refresh.test.ts +1 -1
- package/src/tests/schedule-target-type.test.ts +3 -3
- package/src/tests/scheduled-tasks.test.ts +14 -5
- package/src/tests/scheduler-occurrence.test.ts +347 -0
- package/src/tests/script-apis-mcp.test.ts +1 -1
- package/src/tests/script-connections-http.test.ts +61 -58
- package/src/tests/script-connections-mcp.test.ts +1 -1
- package/src/tests/script-connections.test.ts +3 -1
- package/src/tests/script-runs-http.test.ts +15 -7
- package/src/tests/script-workflows-runtime-e2e.test.ts +1 -1
- package/src/tests/scripts-boot-reembed.test.ts +4 -0
- package/src/tests/scripts-embeddings.test.ts +4 -0
- package/src/tests/scripts-external-api.test.ts +1 -1
- package/src/tests/scripts-http.test.ts +1 -1
- package/src/tests/scripts-import-allowlist.test.ts +44 -1
- package/src/tests/scripts-mcp-e2e.test.ts +81 -1
- package/src/tests/scripts-only-gating.test.ts +4 -2
- package/src/tests/scripts-retention.test.ts +1 -1
- package/src/tests/scripts-runtime-identity.test.ts +2 -2
- package/src/tests/scripts-runtime-secret-egress.test.ts +1 -1
- package/src/tests/scripts-runtime.test.ts +6 -4
- package/src/tests/scripts-typecheck.test.ts +21 -0
- package/src/tests/sdk-allowlist.test.ts +1 -1
- package/src/tests/secret-scrubber.test.ts +38 -31
- package/src/tests/seed-registry.test.ts +46 -8
- package/src/tests/seed-schedules.test.ts +44 -9
- package/src/tests/seed-workflows.test.ts +21 -9
- package/src/tests/send-task-output-schema.test.ts +9 -1
- package/src/tests/send-task-requested-by.test.ts +1 -0
- package/src/tests/send-task-slack-routing-guard.test.ts +2 -0
- package/src/tests/session-costs-codex-recompute.test.ts +1 -1
- package/src/tests/session-costs-golden.test.ts +2 -2
- package/src/tests/session-costs-model-key-normalize.test.ts +2 -2
- package/src/tests/session-costs-recompute-all-providers.test.ts +1 -1
- package/src/tests/session-tokens.test.ts +1 -1
- package/src/tests/shutdown-error-scrubbing.test.ts +1 -1
- package/src/tests/slack-blocks.test.ts +12 -1
- package/src/tests/slack-file-tools-attachments.test.ts +1 -1
- package/src/tests/slack-inbound-files.test.ts +222 -86
- package/src/tests/slack-reaction-config.test.ts +5 -4
- package/src/tests/slack-read-boundaries.test.ts +1 -1
- package/src/tests/slack-render-v2.test.ts +196 -4
- package/src/tests/slack-router.test.ts +17 -2
- package/src/tests/slack-steering.test.ts +19 -0
- package/src/tests/status.test.ts +19 -7
- package/src/tests/steering-core.test.ts +1 -1
- package/src/tests/steering-enabled.test.ts +6 -8
- package/src/tests/steering-transport.test.ts +4 -4
- package/src/tests/store-progress-output-guidance.test.ts +34 -0
- package/src/tests/swarm-tool-result-gate.test.ts +11 -11
- package/src/tests/swarm-x-tool.test.ts +7 -5
- package/src/tests/sync-ai-toolbox-skills.test.ts +19 -0
- package/src/tests/task-supersede-resume.test.ts +1 -1
- package/src/tests/task-tool-preload-mcp.test.ts +4 -1
- package/src/tests/task-tools-ctx.test.ts +2 -0
- package/src/tests/tasks-requested-by-filter.test.ts +2 -2
- package/src/tests/telemetry-init.test.ts +11 -3
- package/src/tests/tool-annotations.test.ts +1 -1
- package/src/tests/tool-output-agent-id.test.ts +1 -0
- package/src/tests/tool-registrar-no-input.test.ts +42 -1
- package/src/tests/tracker-fold.test.ts +7 -7
- package/src/tests/tracker-tools.test.ts +3 -3
- package/src/tests/ui-followup-lead-delegation.test.ts +1 -0
- package/src/tests/unified-oauth-migration.test.ts +5 -5
- package/src/tests/user-token-rest-auth.test.ts +1 -1
- package/src/tests/user-token-routes.test.ts +1 -1
- package/src/tests/whoami-route.test.ts +1 -1
- package/src/tests/workflow-agent-task.test.ts +15 -13
- package/src/tests/workflow-ctx.test.ts +1 -1
- package/src/tests/workflow-e2e.test.ts +1 -1
- package/src/tests/workflow-engine-v2.test.ts +3 -1
- package/src/tests/workflow-executors.test.ts +2 -2
- package/src/tests/workflow-http-v2.test.ts +8 -6
- package/src/tests/workflow-input-redaction.test.ts +7 -5
- package/src/tests/workflow-integration-io.test.ts +2 -2
- package/src/tests/workflow-llm.test.ts +5 -5
- package/src/tests/workflow-registry.test.ts +1 -1
- package/src/tests/workflow-swarm-script.test.ts +1 -1
- package/src/tests/workflow-triggers-v2.test.ts +23 -21
- package/src/tests/x-composio.test.ts +9 -7
- package/src/tests/x402-client.test.ts +1 -1
- package/src/tests/x402-config.test.ts +28 -41
- package/src/tools/defer-task.ts +156 -24
- package/src/tools/extension-common.ts +84 -0
- package/src/tools/extension-install.ts +65 -0
- package/src/tools/extension-list.ts +66 -0
- package/src/tools/script-common.ts +43 -18
- package/src/tools/send-task.ts +87 -105
- package/src/tools/skills/skill-publish.ts +1 -0
- package/src/tools/store-progress.ts +1 -1
- package/src/tools/task-action.ts +43 -22
- package/src/tools/task-tool-ctx.ts +2 -0
- package/src/tools/templates.ts +2 -1
- package/src/tools/tool-config.ts +3 -1
- package/src/tools/utils.ts +140 -16
- package/src/types.ts +144 -0
- package/src/utils/constants.ts +7 -1
- package/src/utils/credentials.test.ts +16 -16
- package/src/utils/multi-runtime.ts +2 -2
- package/src/utils/steering-enabled.ts +4 -4
- package/src/workflows/executors/agent-task.ts +18 -3
- package/templates/ai-toolbox.manifest.json +7 -1
- package/templates/extensions/README.md +17 -0
- package/templates/extensions/notify-on-complete/README.md +11 -0
- package/templates/extensions/notify-on-complete/hooks.ts +61 -0
- package/templates/extensions/notify-on-complete/manifest.json +7 -0
- package/templates/extensions/require-ticket-ref/README.md +11 -0
- package/templates/extensions/require-ticket-ref/hooks.ts +30 -0
- package/templates/extensions/require-ticket-ref/manifest.json +7 -0
- package/templates/extensions/require-verification-note/README.md +11 -0
- package/templates/extensions/require-verification-note/hooks.ts +32 -0
- package/templates/extensions/require-verification-note/manifest.json +7 -0
- package/templates/schedules/daily-hn-briefing/config.json +1 -1
- package/templates/schedules/gtm-weekly-review/config.json +1 -1
- package/templates/schedules/weekly-code-health-reports/config.json +1 -1
- package/templates/schedules/weekly-dependabot-triage/config.json +1 -1
- package/templates/schedules/weekly-dora-metrics/config.json +1 -1
- package/templates/schedules/weekly-harness-upgrade-check/config.json +1 -1
- package/templates/skills/delegate-work/files/scripts/codex-exec.sh +1 -1
- package/templates/skills/scheduling/content.md +2 -0
- package/templates/skills/serply-search/SKILL.md +95 -0
- package/templates/skills/serply-search/config.json +13 -0
- package/templates/skills/serply-search/content.md +90 -0
- package/templates/skills/swarm-extensions/config.json +14 -0
- package/templates/skills/swarm-extensions/content.md +120 -0
- package/templates/skills/swarm-scripts/SKILL.md +2 -2
- package/templates/skills/swarm-scripts/content.md +2 -2
- package/templates/workflows/claude-code-changelog-watch/config.json +1 -1
- package/templates/workflows/gsc-topic-miner/config.json +1 -1
- package/templates/workflows/linear-drain-loop/config.json +1 -1
- package/templates/workflows/llm-safe-release-context/config.json +1 -1
- package/templates/workflows/ralph-loop/config.json +1 -1
- package/dist/cli-7fehefdf.js +0 -562
- package/dist/cli-ayvy5kde.js +0 -164
- package/dist/cli-ddfw1mc4.js +0 -4322
- package/dist/cli-hzqmgcm2.js +0 -3066
- package/dist/cli-j4d4f6hv.js +0 -338
- package/dist/cli-qgm2pfpq.js +0 -6377
- package/dist/cli-sdzq01t9.js +0 -823
- package/dist/cli-xvkmedgn.js +0 -332
- package/dist/cli-y3pq4v9g.js +0 -664
- package/dist/{anthropic-messages-vs2rabzp.js → anthropic-messages-2y8nktar.js} +19 -19
- package/dist/{claude-managed-setup-f5pmsyrp.js → claude-managed-setup-48dwg9bv.js} +3 -3
- package/dist/{cli-81r683bv.js → cli-ch38q5z4.js} +0 -0
- package/dist/{cli-6664w7y4.js → cli-kj76p1ez.js} +8 -8
- package/dist/{cli-c71mg51n.js → cli-r2fpe7cx.js} +5 -5
- package/dist/{cli-4xz3pmrq.js → cli-y6x0gqtg.js} +16 -16
- package/dist/{index-aa3sa6s8.js → index-2wsdsnmm.js} +1 -1
- package/dist/{mistral-conversations-4ryk7h83.js → mistral-conversations-qhr84ph3.js} +9 -9
- package/dist/{openai-completions-0bqmsajw.js → openai-completions-32rdwmze.js} +19 -19
- package/dist/{openrouter-images-qx18fyp8.js → openrouter-images-9f9ek4rw.js} +3 -3
- package/dist/{pi-messages-79jvzz1d.js → pi-messages-b1mbr6gp.js} +4 -4
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
getTaskById,
|
|
19
19
|
initDb,
|
|
20
20
|
startTask,
|
|
21
|
+
supersedeTask,
|
|
21
22
|
updateScheduledTask,
|
|
22
23
|
} from "../be/db";
|
|
23
24
|
import {
|
|
@@ -28,7 +29,9 @@ import {
|
|
|
28
29
|
type TaskWakeEvent,
|
|
29
30
|
} from "../scheduler/deferred-task-waits";
|
|
30
31
|
import { dispatchScheduleTarget, executeSchedule } from "../scheduler/scheduler";
|
|
32
|
+
import { createResumeFollowUp } from "../tasks/worker-follow-up";
|
|
31
33
|
import { registerDeferTaskTool } from "../tools/defer-task";
|
|
34
|
+
import type { AgentTask } from "../types";
|
|
32
35
|
|
|
33
36
|
type Result = { structuredContent: { success: boolean; message: string; scheduleId?: string } };
|
|
34
37
|
type Tool = {
|
|
@@ -133,10 +136,218 @@ async function waitState(scheduleId: string) {
|
|
|
133
136
|
childTaskId: string | null;
|
|
134
137
|
resolvedAt: string | null;
|
|
135
138
|
updated_at: string;
|
|
136
|
-
}>(
|
|
139
|
+
}>(
|
|
140
|
+
`SELECT w.*, m.taskId FROM deferred_task_waits w
|
|
141
|
+
JOIN deferred_task_wait_members m ON m.scheduleId = w.scheduleId
|
|
142
|
+
WHERE w.scheduleId = ?`,
|
|
143
|
+
[scheduleId],
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function resumeTask(parentId: string) {
|
|
148
|
+
const result = await createResumeFollowUp({ parentId, reason: "manual_supersede" });
|
|
149
|
+
if (result.kind !== "created") throw new Error(`Resume creation failed: ${result.kind}`);
|
|
150
|
+
return result.task;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function awaitWatchedTask(scheduleId: string, taskId: string) {
|
|
154
|
+
const deadline = Date.now() + 3000;
|
|
155
|
+
while (Date.now() < deadline) {
|
|
156
|
+
if ((await waitState(scheduleId))?.taskId === taskId) return;
|
|
157
|
+
await Bun.sleep(5);
|
|
158
|
+
}
|
|
159
|
+
throw new Error("Event bus did not transfer the watched task");
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async function multiFixture(mode?: "all" | "any", event: TaskWakeEvent = "settled") {
|
|
163
|
+
const parent = await activeTask();
|
|
164
|
+
const producers = [await activeTask(), await activeTask()];
|
|
165
|
+
const result = await defer(parent.id, producers[0]!.id, event, {
|
|
166
|
+
wakeOn: { taskIds: producers.map((producer) => producer.id), event, mode },
|
|
167
|
+
});
|
|
168
|
+
expect(result.structuredContent.success).toBe(true);
|
|
169
|
+
const schedule = (await getScheduledTaskById(result.structuredContent.scheduleId!))!;
|
|
170
|
+
return { parent, producers, schedule };
|
|
137
171
|
}
|
|
138
172
|
|
|
139
173
|
describe("defer-task wakeOn", () => {
|
|
174
|
+
test.each([
|
|
175
|
+
"completed",
|
|
176
|
+
"failed",
|
|
177
|
+
"cancelled",
|
|
178
|
+
])("all is the default and waits for the final member to be %s", async (status) => {
|
|
179
|
+
const { producers, schedule } = await multiFixture();
|
|
180
|
+
await completeTask(producers[0]!.id, "first result");
|
|
181
|
+
await reconcileDeferredTaskWaits(producers[0]!.id);
|
|
182
|
+
expect(await children(schedule.id)).toHaveLength(0);
|
|
183
|
+
// The dispatch entry point must also enforce the whole set.
|
|
184
|
+
expect(await dispatchDeferredTaskWait(schedule.id, "task.completed")).toEqual({});
|
|
185
|
+
if (status === "completed") await completeTask(producers[1]!.id, "second result");
|
|
186
|
+
else if (status === "failed") await failTask(producers[1]!.id, "second result failed");
|
|
187
|
+
else await cancelTask(producers[1]!.id, "second result cancelled");
|
|
188
|
+
await reconcileDeferredTaskWaits(producers[1]!.id);
|
|
189
|
+
const found = await children(schedule.id);
|
|
190
|
+
expect(found).toHaveLength(1);
|
|
191
|
+
expect(found[0]!.task).toContain("all tasks matched settled");
|
|
192
|
+
expect(found[0]!.task).toContain(`${producers[1]!.id} (${status})`);
|
|
193
|
+
expect((await getScheduledTaskById(schedule.id))?.enabled).toBe(false);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test.each([
|
|
197
|
+
"completed",
|
|
198
|
+
"failed",
|
|
199
|
+
"cancelled",
|
|
200
|
+
])("explicit any wakes on the first %s member", async (status) => {
|
|
201
|
+
const { producers, schedule } = await multiFixture("any");
|
|
202
|
+
if (status === "completed") await completeTask(producers[1]!.id, "ready");
|
|
203
|
+
else if (status === "failed") await failTask(producers[1]!.id, "failed");
|
|
204
|
+
else await cancelTask(producers[1]!.id, "cancelled");
|
|
205
|
+
await reconcileDeferredTaskWaits(producers[1]!.id);
|
|
206
|
+
expect(await children(schedule.id)).toHaveLength(1);
|
|
207
|
+
expect((await children(schedule.id))[0]!.task).toContain("any tasks matched settled");
|
|
208
|
+
expect((await getTaskById(producers[0]!.id))?.status).toBe("in_progress");
|
|
209
|
+
await completeTask(producers[0]!.id, "later");
|
|
210
|
+
await reconcileDeferredTaskWaits();
|
|
211
|
+
await executeSchedule(schedule);
|
|
212
|
+
expect(await children(schedule.id)).toHaveLength(1);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
test("all follows one member through repeated deferrals and restart without extending the ceiling", async () => {
|
|
216
|
+
const { producers, schedule } = await multiFixture("all");
|
|
217
|
+
await completeTask(producers[0]!.id, "ready");
|
|
218
|
+
let current = producers[1]!;
|
|
219
|
+
for (let step = 0; step < 2; step++) {
|
|
220
|
+
const deferred = await defer(current.id, current.id, "settled", { wakeOn: undefined });
|
|
221
|
+
expect(deferred.structuredContent.success).toBe(true);
|
|
222
|
+
await reconcileDeferredTaskWaits(current.id);
|
|
223
|
+
expect(await children(schedule.id)).toHaveLength(0);
|
|
224
|
+
expect(await dispatchDeferredTaskWait(schedule.id, "task.completed")).toEqual({});
|
|
225
|
+
const successor = (await getScheduledTaskById(deferred.structuredContent.scheduleId!))!;
|
|
226
|
+
await executeSchedule(successor);
|
|
227
|
+
current = (await children(successor.id))[0]!;
|
|
228
|
+
closeDb();
|
|
229
|
+
initDb(path);
|
|
230
|
+
await initDeferredTaskWaits();
|
|
231
|
+
expect(await children(schedule.id)).toHaveLength(0);
|
|
232
|
+
expect((await getScheduledTaskById(schedule.id))?.nextRunAt).toBe(schedule.nextRunAt);
|
|
233
|
+
}
|
|
234
|
+
await completeTask(current.id, "final result");
|
|
235
|
+
const child = await awaitChild(schedule.id);
|
|
236
|
+
expect(child.task).toContain(`${current.id} (completed)`);
|
|
237
|
+
expect(child.task).toContain(`${producers[0]!.id} (completed)`);
|
|
238
|
+
expect(await children(schedule.id)).toHaveLength(1);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test("any ignores a deferred completion until another member really settles", async () => {
|
|
242
|
+
const { producers, schedule } = await multiFixture("any");
|
|
243
|
+
await defer(producers[0]!.id, producers[0]!.id, "settled", { wakeOn: undefined });
|
|
244
|
+
await reconcileDeferredTaskWaits();
|
|
245
|
+
expect(await children(schedule.id)).toHaveLength(0);
|
|
246
|
+
await failTask(producers[1]!.id, "real failure");
|
|
247
|
+
await reconcileDeferredTaskWaits(producers[1]!.id);
|
|
248
|
+
expect(await children(schedule.id)).toHaveLength(1);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test("the set's ceiling fires before all settle and later events cannot duplicate it", async () => {
|
|
252
|
+
const { producers, schedule } = await multiFixture();
|
|
253
|
+
await completeTask(producers[0]!.id, "ready");
|
|
254
|
+
await reconcileDeferredTaskWaits();
|
|
255
|
+
expect(await children(schedule.id)).toHaveLength(0);
|
|
256
|
+
await executeSchedule(schedule);
|
|
257
|
+
expect((await children(schedule.id))[0]!.task).toContain("ceiling expired");
|
|
258
|
+
await completeTask(producers[1]!.id, "late");
|
|
259
|
+
await reconcileDeferredTaskWaits();
|
|
260
|
+
expect(await children(schedule.id)).toHaveLength(1);
|
|
261
|
+
expect((await waitState(schedule.id))?.firedBy).toBe("ceiling");
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
test.each([
|
|
265
|
+
"all",
|
|
266
|
+
"any",
|
|
267
|
+
] as const)("%s concurrent terminal events and the ceiling create exactly one child", async (mode) => {
|
|
268
|
+
const { producers, schedule } = await multiFixture(mode);
|
|
269
|
+
await initDeferredTaskWaits();
|
|
270
|
+
await Promise.all([
|
|
271
|
+
completeTask(producers[0]!.id, "ready"),
|
|
272
|
+
failTask(producers[1]!.id, "failed"),
|
|
273
|
+
executeSchedule(schedule),
|
|
274
|
+
]);
|
|
275
|
+
await reconcileDeferredTaskWaits();
|
|
276
|
+
const found = await children(schedule.id);
|
|
277
|
+
expect(found).toHaveLength(1);
|
|
278
|
+
expect((await waitState(schedule.id))?.childTaskId).toBe(found[0]!.id);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
test.each([
|
|
282
|
+
"all",
|
|
283
|
+
"any",
|
|
284
|
+
] as const)("%s respects event filters when a member fails", async (mode) => {
|
|
285
|
+
const { producers, schedule } = await multiFixture(mode, "task.completed");
|
|
286
|
+
await failTask(producers[0]!.id, "wrong event");
|
|
287
|
+
await reconcileDeferredTaskWaits();
|
|
288
|
+
expect(await children(schedule.id)).toHaveLength(0);
|
|
289
|
+
await completeTask(producers[1]!.id, "right event");
|
|
290
|
+
await reconcileDeferredTaskWaits();
|
|
291
|
+
expect(await children(schedule.id)).toHaveLength(mode === "all" ? 0 : 1);
|
|
292
|
+
await executeSchedule(schedule);
|
|
293
|
+
expect(await children(schedule.id)).toHaveLength(1);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
test("one invalid member rejects the entire set before any schedule or completion is committed", async () => {
|
|
297
|
+
const parent = await activeTask();
|
|
298
|
+
const valid = await activeTask();
|
|
299
|
+
const terminal = await activeTask();
|
|
300
|
+
await completeTask(terminal.id, "done");
|
|
301
|
+
for (const mode of ["all", "any"]) {
|
|
302
|
+
for (const [id, message] of [
|
|
303
|
+
[terminal.id, "already completed"],
|
|
304
|
+
[crypto.randomUUID(), "not found"],
|
|
305
|
+
[parent.id, "Cannot wake on"],
|
|
306
|
+
]) {
|
|
307
|
+
const result = await defer(parent.id, valid.id, "settled", {
|
|
308
|
+
wakeOn: { taskIds: [valid.id, id], event: "settled", mode },
|
|
309
|
+
});
|
|
310
|
+
expect(result.structuredContent.success).toBe(false);
|
|
311
|
+
expect(result.structuredContent.message).toContain(message!);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
expect((await getTaskById(parent.id))?.status).toBe("in_progress");
|
|
315
|
+
expect(
|
|
316
|
+
await getDbClient().query("SELECT id FROM scheduled_tasks WHERE parentTaskId = ?", [
|
|
317
|
+
parent.id,
|
|
318
|
+
]),
|
|
319
|
+
).toHaveLength(0);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
test("multi-ID schema rejects empty, duplicate, ambiguous, or missing IDs and invalid modes", async () => {
|
|
323
|
+
const parent = await activeTask();
|
|
324
|
+
const producer = await activeTask();
|
|
325
|
+
const base = { taskId: parent.id, summary: "done", note: "wait", delayMs: 60000 };
|
|
326
|
+
for (const fields of [
|
|
327
|
+
{},
|
|
328
|
+
{ taskIds: [] },
|
|
329
|
+
{ taskIds: [""] },
|
|
330
|
+
{ taskIds: [producer.id, producer.id] },
|
|
331
|
+
{ taskId: producer.id, taskIds: [producer.id] },
|
|
332
|
+
{ taskIds: [producer.id], mode: "some" },
|
|
333
|
+
]) {
|
|
334
|
+
expect(
|
|
335
|
+
tool.inputSchema.safeParse({ ...base, wakeOn: { event: "settled", ...fields } }).success,
|
|
336
|
+
).toBe(false);
|
|
337
|
+
}
|
|
338
|
+
const wakeOn = { taskIds: [producer.id], event: "settled" };
|
|
339
|
+
expect(tool.inputSchema.safeParse({ ...base, wakeOn }).success).toBe(true);
|
|
340
|
+
for (const extra of [
|
|
341
|
+
{ delayMs: undefined },
|
|
342
|
+
{ runAt: new Date(Date.now() + 60000).toISOString() },
|
|
343
|
+
]) {
|
|
344
|
+
expect(
|
|
345
|
+
(await defer(parent.id, producer.id, "settled", { wakeOn, ...extra })).structuredContent
|
|
346
|
+
.success,
|
|
347
|
+
).toBe(false);
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
|
|
140
351
|
test("ordinary schedules neither suppress a completion nor retarget its waiters", async () => {
|
|
141
352
|
const { producer, schedule } = await fixture();
|
|
142
353
|
const ordinary = await createScheduledTask({
|
|
@@ -392,7 +603,143 @@ describe("defer-task wakeOn", () => {
|
|
|
392
603
|
expect(await children(schedule.id)).toHaveLength(1);
|
|
393
604
|
});
|
|
394
605
|
|
|
395
|
-
test("
|
|
606
|
+
test("settled wakes on the cancellation bus and consumes the ceiling once", async () => {
|
|
607
|
+
await initDeferredTaskWaits();
|
|
608
|
+
const { producer, schedule } = await fixture();
|
|
609
|
+
await cancelTask(producer.id, "cancelled");
|
|
610
|
+
expect((await awaitChild(schedule.id)).task).toContain(
|
|
611
|
+
`Wake-up cause: task.cancelled for task ${producer.id}`,
|
|
612
|
+
);
|
|
613
|
+
expect(await waitState(schedule.id)).toMatchObject({ firedBy: "task.cancelled" });
|
|
614
|
+
await executeSchedule(schedule);
|
|
615
|
+
expect(await children(schedule.id)).toHaveLength(1);
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
test("restart reconciles cancellation missed while the listener was stopped", async () => {
|
|
619
|
+
const { producer, schedule } = await fixture();
|
|
620
|
+
await cancelTask(producer.id, "cancelled while stopped");
|
|
621
|
+
closeDb();
|
|
622
|
+
initDb(path);
|
|
623
|
+
await initDeferredTaskWaits();
|
|
624
|
+
expect(await waitState(schedule.id)).toMatchObject({
|
|
625
|
+
status: "fired",
|
|
626
|
+
firedBy: "task.cancelled",
|
|
627
|
+
});
|
|
628
|
+
expect(await children(schedule.id)).toHaveLength(1);
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
test.each([
|
|
632
|
+
"task.completed",
|
|
633
|
+
"task.failed",
|
|
634
|
+
] as const)("%s does not wake on cancellation and retains the ceiling", async (event) => {
|
|
635
|
+
await initDeferredTaskWaits();
|
|
636
|
+
const { producer, schedule } = await fixture(event);
|
|
637
|
+
await cancelTask(producer.id, "cancelled");
|
|
638
|
+
await reconcileDeferredTaskWaits(producer.id);
|
|
639
|
+
expect(await dispatchDeferredTaskWait(schedule.id, "task.cancelled")).toEqual({});
|
|
640
|
+
expect(await children(schedule.id)).toHaveLength(0);
|
|
641
|
+
expect(await waitState(schedule.id)).toMatchObject({ status: "pending" });
|
|
642
|
+
await executeSchedule(schedule);
|
|
643
|
+
expect(await waitState(schedule.id)).toMatchObject({ firedBy: "ceiling" });
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
test.each([
|
|
647
|
+
"resume first",
|
|
648
|
+
"supersede first",
|
|
649
|
+
])("superseded follows the resume without waking or extending the ceiling: %s", async (order) => {
|
|
650
|
+
await initDeferredTaskWaits();
|
|
651
|
+
for (const event of ["settled", "task.completed", "task.failed"] as const) {
|
|
652
|
+
const { producer, schedule } = await fixture(event);
|
|
653
|
+
let resume: AgentTask | undefined;
|
|
654
|
+
if (order === "resume first") {
|
|
655
|
+
resume = await resumeTask(producer.id);
|
|
656
|
+
await reconcileDeferredTaskWaits();
|
|
657
|
+
expect(await waitState(schedule.id)).toMatchObject({ taskId: producer.id });
|
|
658
|
+
}
|
|
659
|
+
await supersedeTask(producer.id, {
|
|
660
|
+
reason: "manual_supersede",
|
|
661
|
+
resumeTaskId: resume?.id ?? null,
|
|
662
|
+
});
|
|
663
|
+
if (!resume) {
|
|
664
|
+
await reconcileDeferredTaskWaits(producer.id);
|
|
665
|
+
expect(await waitState(schedule.id)).toMatchObject({
|
|
666
|
+
taskId: producer.id,
|
|
667
|
+
status: "pending",
|
|
668
|
+
});
|
|
669
|
+
resume = await resumeTask(producer.id);
|
|
670
|
+
}
|
|
671
|
+
await awaitWatchedTask(schedule.id, resume.id);
|
|
672
|
+
expect(await waitState(schedule.id)).toMatchObject({ status: "pending", firedBy: null });
|
|
673
|
+
expect(await children(schedule.id)).toHaveLength(0);
|
|
674
|
+
expect((await getScheduledTaskById(schedule.id))?.nextRunAt).toBe(schedule.nextRunAt);
|
|
675
|
+
if (event === "task.failed") await failTask(resume.id, "resume failed");
|
|
676
|
+
else await completeTask(resume.id, "resume completed");
|
|
677
|
+
expect((await awaitChild(schedule.id)).task).toContain(`for task ${resume.id}`);
|
|
678
|
+
await executeSchedule(schedule);
|
|
679
|
+
expect(await children(schedule.id)).toHaveLength(1);
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
test("superseded without a resume holds to its ceiling and a late resume cannot retarget a fired wait", async () => {
|
|
684
|
+
await initDeferredTaskWaits();
|
|
685
|
+
const { producer, schedule } = await fixture();
|
|
686
|
+
await supersedeTask(producer.id, { reason: "manual_supersede", resumeTaskId: null });
|
|
687
|
+
// An ordinary follow-up is not the replacement for superseded work.
|
|
688
|
+
await createTaskExtended("unrelated follow-up", {
|
|
689
|
+
parentTaskId: producer.id,
|
|
690
|
+
taskType: "follow-up",
|
|
691
|
+
});
|
|
692
|
+
await reconcileDeferredTaskWaits(producer.id);
|
|
693
|
+
expect(await waitState(schedule.id)).toMatchObject({ taskId: producer.id, status: "pending" });
|
|
694
|
+
expect(await children(schedule.id)).toHaveLength(0);
|
|
695
|
+
await executeSchedule(schedule);
|
|
696
|
+
const fired = await waitState(schedule.id);
|
|
697
|
+
expect(fired).toMatchObject({ firedBy: "ceiling" });
|
|
698
|
+
const resume = await resumeTask(producer.id);
|
|
699
|
+
await completeTask(resume.id, "too late");
|
|
700
|
+
await reconcileDeferredTaskWaits();
|
|
701
|
+
expect(await waitState(schedule.id)).toEqual(fired);
|
|
702
|
+
expect(await children(schedule.id)).toHaveLength(1);
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
test("restart follows a missed supersede chain to an already-terminal resume", async () => {
|
|
706
|
+
const { producer, schedule } = await fixture();
|
|
707
|
+
let current = producer;
|
|
708
|
+
for (let step = 0; step < 2; step++) {
|
|
709
|
+
await supersedeTask(current.id, { reason: "manual_supersede", resumeTaskId: null });
|
|
710
|
+
current = await resumeTask(current.id);
|
|
711
|
+
}
|
|
712
|
+
await completeTask(current.id, "final result");
|
|
713
|
+
closeDb();
|
|
714
|
+
initDb(path);
|
|
715
|
+
await initDeferredTaskWaits();
|
|
716
|
+
expect(await waitState(schedule.id)).toMatchObject({ taskId: current.id, status: "fired" });
|
|
717
|
+
expect((await awaitChild(schedule.id)).task).toContain(`for task ${current.id}`);
|
|
718
|
+
expect(await children(schedule.id)).toHaveLength(1);
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
test("a wait watching both the superseded parent and its resume collapses to one member", async () => {
|
|
722
|
+
const parent = await activeTask();
|
|
723
|
+
const producer = await activeTask();
|
|
724
|
+
const resume = await resumeTask(producer.id);
|
|
725
|
+
const deferred = await defer(parent.id, producer.id, "settled", {
|
|
726
|
+
wakeOn: { taskIds: [producer.id, resume.id], event: "settled" },
|
|
727
|
+
});
|
|
728
|
+
const scheduleId = deferred.structuredContent.scheduleId!;
|
|
729
|
+
await supersedeTask(producer.id, { reason: "manual_supersede", resumeTaskId: resume.id });
|
|
730
|
+
await reconcileDeferredTaskWaits();
|
|
731
|
+
expect(await waitState(scheduleId)).toMatchObject({ taskId: resume.id, status: "pending" });
|
|
732
|
+
expect(
|
|
733
|
+
await getDbClient().query("SELECT * FROM deferred_task_wait_members WHERE scheduleId = ?", [
|
|
734
|
+
scheduleId,
|
|
735
|
+
]),
|
|
736
|
+
).toHaveLength(1);
|
|
737
|
+
await completeTask(resume.id, "done");
|
|
738
|
+
await reconcileDeferredTaskWaits(resume.id);
|
|
739
|
+
expect(await children(scheduleId)).toHaveLength(1);
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
test("unmatched task or event does not wake", async () => {
|
|
396
743
|
await initDeferredTaskWaits();
|
|
397
744
|
const { producer, schedule } = await fixture("task.completed");
|
|
398
745
|
const other = await activeTask();
|
|
@@ -400,12 +747,6 @@ describe("defer-task wakeOn", () => {
|
|
|
400
747
|
await failTask(producer.id, "wrong event");
|
|
401
748
|
await reconcileDeferredTaskWaits();
|
|
402
749
|
expect(await children(schedule.id)).toHaveLength(0);
|
|
403
|
-
const cancelled = await fixture();
|
|
404
|
-
await cancelTask(cancelled.producer.id, "cancelled");
|
|
405
|
-
await reconcileDeferredTaskWaits();
|
|
406
|
-
expect(await children(cancelled.schedule.id)).toHaveLength(0);
|
|
407
|
-
await executeSchedule(cancelled.schedule);
|
|
408
|
-
expect(await children(cancelled.schedule.id)).toHaveLength(1);
|
|
409
750
|
await executeSchedule(schedule);
|
|
410
751
|
});
|
|
411
752
|
|
|
@@ -18,7 +18,7 @@ import { listenOnFreePort } from "./test-net";
|
|
|
18
18
|
|
|
19
19
|
let TEST_BASE_URL = "";
|
|
20
20
|
const ORG_ID = "org-adapter-test";
|
|
21
|
-
const API_KEY = "cog_adapter_key";
|
|
21
|
+
const API_KEY = "example-cog_adapter_key";
|
|
22
22
|
|
|
23
23
|
// ---------------------------------------------------------------------------
|
|
24
24
|
// Controllable mock state
|
|
@@ -13,7 +13,7 @@ import { listenOnFreePort } from "./test-net";
|
|
|
13
13
|
|
|
14
14
|
let TEST_BASE_URL = "";
|
|
15
15
|
const ORG_ID = "org-test-123";
|
|
16
|
-
const API_KEY = "cog_test_key";
|
|
16
|
+
const API_KEY = "example-cog_test_key";
|
|
17
17
|
|
|
18
18
|
// Canned responses -----------------------------------------------------------
|
|
19
19
|
const SESSION_RESPONSE = {
|
|
@@ -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 370 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(372);
|
|
107
|
+
expect(generatedKeys).toHaveLength(372);
|
|
108
108
|
expect(new Set(generatedKeys)).toEqual(new Set(operationKeys));
|
|
109
109
|
});
|
|
110
110
|
|
|
@@ -70,9 +70,9 @@ describe("E2B env helpers", () => {
|
|
|
70
70
|
delete process.env.API_KEY;
|
|
71
71
|
delete process.env.AGENT_SWARM_API_KEY;
|
|
72
72
|
try {
|
|
73
|
-
expect(
|
|
74
|
-
"preferred",
|
|
75
|
-
);
|
|
73
|
+
expect(
|
|
74
|
+
resolveSwarmApiKey({ API_KEY: "legacy", AGENT_SWARM_API_KEY: "example-preferred" }),
|
|
75
|
+
).toBe("example-preferred");
|
|
76
76
|
expect(resolveSwarmApiKey({ API_KEY: "legacy" }, "explicit")).toBe("explicit");
|
|
77
77
|
expect(() => resolveSwarmApiKey({})).toThrow("Missing swarm API key");
|
|
78
78
|
} finally {
|
|
@@ -92,14 +92,16 @@ describe("E2B env helpers", () => {
|
|
|
92
92
|
test("selectEnv and redactWithEnv keep secrets out of logs", () => {
|
|
93
93
|
const selected = selectEnv(
|
|
94
94
|
{
|
|
95
|
-
API_KEY: "super-secret-value",
|
|
96
|
-
E2B_API_KEY: "controller-secret",
|
|
95
|
+
API_KEY: "example-super-secret-value",
|
|
96
|
+
E2B_API_KEY: "example-controller-secret",
|
|
97
97
|
PATH: "/bin",
|
|
98
98
|
},
|
|
99
99
|
["API_KEY", "PATH"],
|
|
100
100
|
);
|
|
101
|
-
expect(selected).toEqual({ API_KEY: "super-secret-value", PATH: "/bin" });
|
|
102
|
-
expect(redactWithEnv("token=super-secret-value", selected)).toContain(
|
|
101
|
+
expect(selected).toEqual({ API_KEY: "example-super-secret-value", PATH: "/bin" });
|
|
102
|
+
expect(redactWithEnv("token=example-super-secret-value", selected)).toContain(
|
|
103
|
+
"[REDACTED:API_KEY]",
|
|
104
|
+
);
|
|
103
105
|
});
|
|
104
106
|
|
|
105
107
|
test("redactObjectWithEnv redacts token-like response fields", () => {
|
|
@@ -107,8 +109,8 @@ describe("E2B env helpers", () => {
|
|
|
107
109
|
redactObjectWithEnv(
|
|
108
110
|
{
|
|
109
111
|
sandboxID: "sbx123",
|
|
110
|
-
envdAccessToken: "controller-token-that-should-not-print",
|
|
111
|
-
nested: { trafficAccessToken: "traffic-token-that-should-not-print" },
|
|
112
|
+
envdAccessToken: "example-controller-token-that-should-not-print",
|
|
113
|
+
nested: { trafficAccessToken: "example-traffic-token-that-should-not-print" },
|
|
112
114
|
},
|
|
113
115
|
{},
|
|
114
116
|
),
|
|
@@ -232,7 +234,7 @@ describe("E2B dispatch helpers", () => {
|
|
|
232
234
|
test("E2B SDK connection options preserve loaded controller endpoints", () => {
|
|
233
235
|
expect(
|
|
234
236
|
e2bSdkConnectionOptions(
|
|
235
|
-
"controller-key",
|
|
237
|
+
"example-controller-key",
|
|
236
238
|
{
|
|
237
239
|
E2B_DOMAIN: "sandbox.example.com",
|
|
238
240
|
E2B_SANDBOX_URL: "https://sandbox.sandbox.example.com",
|
|
@@ -240,7 +242,7 @@ describe("E2B dispatch helpers", () => {
|
|
|
240
242
|
"https://api.sandbox.example.com",
|
|
241
243
|
),
|
|
242
244
|
).toEqual({
|
|
243
|
-
apiKey: "controller-key",
|
|
245
|
+
apiKey: "example-controller-key",
|
|
244
246
|
domain: "sandbox.example.com",
|
|
245
247
|
sandboxUrl: "https://sandbox.sandbox.example.com",
|
|
246
248
|
apiUrl: "https://api.sandbox.example.com",
|
|
@@ -360,7 +362,7 @@ describe("E2B dispatch helpers", () => {
|
|
|
360
362
|
name: "agent swarm/worker",
|
|
361
363
|
public: true,
|
|
362
364
|
e2bEnv: {
|
|
363
|
-
E2B_API_KEY: "controller-secret",
|
|
365
|
+
E2B_API_KEY: "example-controller-secret",
|
|
364
366
|
E2B_API_URL: "https://api.e2b.example",
|
|
365
367
|
},
|
|
366
368
|
});
|
|
@@ -370,7 +372,7 @@ describe("E2B dispatch helpers", () => {
|
|
|
370
372
|
expect(calls[0]?.init?.method).toBe("PATCH");
|
|
371
373
|
expect(calls[0]?.init?.headers).toMatchObject({
|
|
372
374
|
"Content-Type": "application/json",
|
|
373
|
-
"X-API-Key": "controller-secret",
|
|
375
|
+
"X-API-Key": "example-controller-secret",
|
|
374
376
|
});
|
|
375
377
|
expect(calls[0]?.init?.body).toBe(JSON.stringify({ public: true }));
|
|
376
378
|
expect(result.stdout).toBe(
|
|
@@ -826,7 +828,7 @@ describe("E2B swarm grouping + deep-link (Phase 4)", () => {
|
|
|
826
828
|
|
|
827
829
|
test("e2b dashboard deep-link uses camelCase params and hides the key by default", () => {
|
|
828
830
|
const masked = buildDashboardDeepLink(
|
|
829
|
-
{ apiUrl: "https://api.example.com", apiKey: "super-secret-key", name: "demo" },
|
|
831
|
+
{ apiUrl: "https://api.example.com", apiKey: "example-super-secret-key", name: "demo" },
|
|
830
832
|
false,
|
|
831
833
|
);
|
|
832
834
|
// camelCase params the SPA reads.
|
|
@@ -834,7 +836,7 @@ describe("E2B swarm grouping + deep-link (Phase 4)", () => {
|
|
|
834
836
|
expect(masked).toContain("name=demo");
|
|
835
837
|
// Key hidden — the real value MUST NOT appear.
|
|
836
838
|
expect(masked).toContain("apiKey=<hidden — pass --reveal-key>");
|
|
837
|
-
expect(masked).not.toContain("super-secret-key");
|
|
839
|
+
expect(masked).not.toContain("example-super-secret-key");
|
|
838
840
|
// Never snake_case.
|
|
839
841
|
expect(masked).not.toContain("api_url");
|
|
840
842
|
expect(masked).not.toContain("api_key");
|
|
@@ -842,10 +844,10 @@ describe("E2B swarm grouping + deep-link (Phase 4)", () => {
|
|
|
842
844
|
|
|
843
845
|
test("e2b dashboard deep-link embeds the real key only when revealed", () => {
|
|
844
846
|
const revealed = buildDashboardDeepLink(
|
|
845
|
-
{ apiUrl: "https://api.example.com", apiKey: "super-secret-key", name: "demo" },
|
|
847
|
+
{ apiUrl: "https://api.example.com", apiKey: "example-super-secret-key", name: "demo" },
|
|
846
848
|
true,
|
|
847
849
|
);
|
|
848
|
-
expect(revealed).toContain("apiKey=super-secret-key");
|
|
850
|
+
expect(revealed).toContain("apiKey=example-super-secret-key");
|
|
849
851
|
expect(revealed).not.toContain("<hidden");
|
|
850
852
|
expect(revealed).toContain("apiUrl=https%3A%2F%2Fapi.example.com");
|
|
851
853
|
});
|
|
@@ -876,10 +878,10 @@ describe("E2B swarm grouping + deep-link (Phase 4)", () => {
|
|
|
876
878
|
test("onboarding dashboard builder emits camelCase apiUrl/apiKey (not snake_case)", () => {
|
|
877
879
|
const url = buildOnboardDashboardUrl({
|
|
878
880
|
apiUrl: "http://localhost:3013",
|
|
879
|
-
apiKey: "onboard-key",
|
|
881
|
+
apiKey: "example-onboard-key",
|
|
880
882
|
});
|
|
881
883
|
expect(url).toContain("apiUrl=http%3A%2F%2Flocalhost%3A3013");
|
|
882
|
-
expect(url).toContain("apiKey=onboard-key");
|
|
884
|
+
expect(url).toContain("apiKey=example-onboard-key");
|
|
883
885
|
// The bug we fixed: snake_case is silently ignored by the SPA.
|
|
884
886
|
expect(url).not.toContain("api_url");
|
|
885
887
|
expect(url).not.toContain("api_key");
|
|
@@ -93,7 +93,7 @@ describe("Claude E2E transport harness", () => {
|
|
|
93
93
|
});
|
|
94
94
|
|
|
95
95
|
test("writes the agent override and validates transport metadata and Claude costs", async () => {
|
|
96
|
-
process.env.ANTHROPIC_API_KEY = "test-anthropic-key";
|
|
96
|
+
process.env.ANTHROPIC_API_KEY = "example-test-anthropic-key";
|
|
97
97
|
process.env.E2E_CLAUDE_BINARY = "/opt/claude-pinned";
|
|
98
98
|
process.env.E2E_WORKER_BINARY = "/opt/agent-swarm";
|
|
99
99
|
const spawnCalls: Parameters<typeof Bun.spawn>[] = [];
|
|
@@ -141,7 +141,7 @@ describe("Claude E2E transport harness", () => {
|
|
|
141
141
|
});
|
|
142
142
|
|
|
143
143
|
test("fails when Claude metadata or costs do not prove the selected transport", async () => {
|
|
144
|
-
process.env.ANTHROPIC_API_KEY = "test-anthropic-key";
|
|
144
|
+
process.env.ANTHROPIC_API_KEY = "example-test-anthropic-key";
|
|
145
145
|
process.env.E2E_CLAUDE_TRANSPORT = "sdk";
|
|
146
146
|
process.env.E2E_COST_TIMEOUT_MS = "1";
|
|
147
147
|
const spawnSpy = spyOn(Bun, "spawn").mockImplementation((() =>
|
|
@@ -184,7 +184,7 @@ describe("Claude E2E transport harness", () => {
|
|
|
184
184
|
|
|
185
185
|
test("does not validate the Claude flag for non-Claude legs", async () => {
|
|
186
186
|
process.env.E2E_CLAUDE_TRANSPORT = "invalid";
|
|
187
|
-
process.env.OPENROUTER_API_KEY = "test-openrouter-key";
|
|
187
|
+
process.env.OPENROUTER_API_KEY = "example-test-openrouter-key";
|
|
188
188
|
const spawnSpy = spyOn(Bun, "spawn").mockImplementation((() =>
|
|
189
189
|
fakeWorker()) as typeof Bun.spawn);
|
|
190
190
|
|
|
@@ -5,10 +5,10 @@ describe("e2e redaction", () => {
|
|
|
5
5
|
test("masks exact known values and common token shapes", () => {
|
|
6
6
|
const text = [
|
|
7
7
|
"Authorization: Bearer 0123456789abcdef0123456789abcdef",
|
|
8
|
-
"OPENAI_API_KEY=sk-proj-abcdefghijklmnopqrstuvwxyz0123",
|
|
9
|
-
"anthropic sk-ant-api03-abcdefghijklmnop",
|
|
10
|
-
"github ghp_abcdefghijklmnopqrstuvwxyz0123456789",
|
|
11
|
-
"slack xoxb-1234567890-abcdefghijk",
|
|
8
|
+
"OPENAI_API_KEY=example-sk-proj-abcdefghijklmnopqrstuvwxyz0123",
|
|
9
|
+
"anthropic example-sk-ant-api03-abcdefghijklmnop",
|
|
10
|
+
"github example-ghp_abcdefghijklmnopqrstuvwxyz0123456789",
|
|
11
|
+
"slack example-xoxb-1234567890-abcdefghijk",
|
|
12
12
|
'auth.json {"refresh_token":"rt-abcdefghijklmnop","id_token":"x.y.z"}',
|
|
13
13
|
"jwt eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
|
|
14
14
|
"my-secret-run-key-value appears here",
|
|
@@ -42,7 +42,7 @@ describe("e2e redaction", () => {
|
|
|
42
42
|
test("knownSecrets reads provider env values and the codex blob fields", () => {
|
|
43
43
|
const saved = { ...process.env };
|
|
44
44
|
try {
|
|
45
|
-
process.env.OPENROUTER_API_KEY = "sk-or-v1-known-value-1234";
|
|
45
|
+
process.env.OPENROUTER_API_KEY = "example-sk-or-v1-known-value-1234";
|
|
46
46
|
process.env.CODEX_OAUTH = JSON.stringify({
|
|
47
47
|
access: "access-token-value-1234",
|
|
48
48
|
refresh: "refresh-token-value-1234",
|
|
@@ -50,7 +50,7 @@ describe("e2e redaction", () => {
|
|
|
50
50
|
accountId: "acct",
|
|
51
51
|
});
|
|
52
52
|
const known = knownSecrets(["extra-secret-value"]);
|
|
53
|
-
expect(known).toContain("sk-or-v1-known-value-1234");
|
|
53
|
+
expect(known).toContain("example-sk-or-v1-known-value-1234");
|
|
54
54
|
expect(known).toContain("access-token-value-1234");
|
|
55
55
|
expect(known).toContain("refresh-token-value-1234");
|
|
56
56
|
expect(known).toContain("extra-secret-value");
|