@desplega.ai/agent-swarm 1.149.0 → 1.150.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 +7 -3
- package/dist/{acp-adapter-4jncb126.js → acp-adapter-d5mzggyk.js} +1 -1
- package/dist/{actions-31vp3ae7.js → actions-wn6ew0p7.js} +11 -10
- package/dist/{anthropic-messages-vs2rabzp.js → anthropic-messages-ec35ktvx.js} +4 -4
- package/dist/{app-1hh67x8w.js → app-dty7p9hg.js} +7 -7
- package/dist/{artifact-gj9arwrr.js → artifact-td4q4dch.js} +1 -1
- package/dist/{assistant-z66dmz6p.js → assistant-q4vhgjtx.js} +16 -17
- package/dist/{boot-reembed-wxa8ya0s.js → boot-reembed-92292pgf.js} +9 -9
- package/dist/{boot-reembed-fqzxxzjh.js → boot-reembed-n15q6s9x.js} +8 -8
- package/dist/{boot-scrub-logs-jnyndh79.js → boot-scrub-logs-44pc955m.js} +5 -5
- package/dist/{claude-adapter-3qpa9w0j.js → claude-adapter-cjegjbje.js} +14 -14
- package/dist/{claude-managed-adapter-qvsmh6mv.js → claude-managed-adapter-p3ts5m9m.js} +2 -2
- package/dist/{claude-sdk-session-2yxgjs5d.js → claude-sdk-session-7ywbn12v.js} +14 -14
- package/dist/{cli-cr12paw2.js → cli-111ey3ra.js} +5 -5
- package/dist/{cli-4wtq5jjv.js → cli-1mx65de9.js} +1 -1
- package/dist/{cli-9d8ntetj.js → cli-2658f6at.js} +1 -1
- package/dist/{cli-n3dz2942.js → cli-3ckzxdt1.js} +10 -6
- package/dist/{cli-yb9qhqam.js → cli-3mh119qv.js} +184 -67
- package/dist/{cli-ykxrnd1q.js → cli-72xdszyx.js} +2 -2
- package/dist/{cli-xm87hzbw.js → cli-7fesa1ky.js} +1 -1
- package/dist/{cli-3q5ejx9p.js → cli-7kwmt3r5.js} +2 -2
- package/dist/{cli-2qts1hys.js → cli-8chp8xab.js} +2 -2
- package/dist/{cli-qaacms9y.js → cli-9gqddmxs.js} +122 -97
- package/dist/{cli-zvz62chv.js → cli-a45d5v9b.js} +4 -4
- package/dist/{cli-9xvdm3bx.js → cli-asvrh7kj.js} +1 -1
- package/dist/{cli-kgz4np97.js → cli-b8x19vbh.js} +4 -4
- package/dist/{cli-9fy6nk6g.js → cli-ceb5y160.js} +1 -1
- package/dist/{cli-k0cr4kat.js → cli-ck1vqzdj.js} +1 -1
- package/dist/{cli-e29gmdmw.js → cli-dv6cdjs2.js} +2 -1
- package/dist/{cli-jecc01cb.js → cli-dyx0237s.js} +1 -1
- package/dist/{cli-kjwt6hdf.js → cli-gm0fhz13.js} +3 -3
- package/dist/{cli-sd5pv3b1.js → cli-h505yhex.js} +2 -2
- package/dist/{handlers-nbzdzn9k.js → cli-hbagregr.js} +15 -38
- package/dist/{cli-08b07b4r.js → cli-hmyynq9b.js} +1 -1
- package/dist/{cli-d8ftsp62.js → cli-kt7wevqh.js} +20 -13
- package/dist/{cli-gjhjfeeg.js → cli-kyysm7m3.js} +1 -1
- package/dist/{cli-1ebpar1q.js → cli-mzb0n642.js} +6 -6
- package/dist/{cli-q50ef8g0.js → cli-n1yj5fd5.js} +1 -1
- package/dist/{cli-3apbzgyk.js → cli-n75jt793.js} +13 -9
- package/dist/{cli-19f354qr.js → cli-q04q68be.js} +2 -2
- package/dist/{cli-yab68w40.js → cli-qp69dd5d.js} +29 -14
- package/dist/{cli-6pqcb4q0.js → cli-rnsr8asm.js} +12 -11
- package/dist/{cli-ygweqcn4.js → cli-rwp3ksm7.js} +91 -108
- package/dist/{cli-phsxnkp6.js → cli-ryz8q8p1.js} +74 -58
- package/dist/{cli-e95cx1eb.js → cli-taym3dmg.js} +10 -10
- package/dist/{cli-nye12xk5.js → cli-ttje5a4z.js} +7 -4
- package/dist/{cli-9hspd3dp.js → cli-vr6qj104.js} +1 -1
- package/dist/{cli-mnmsfd1w.js → cli-xjb9wghj.js} +7 -3
- package/dist/{cli-gv88e1vf.js → cli-ydk0wjj8.js} +1 -1
- package/dist/{cli-aae6hz6a.js → cli-zd21jrrc.js} +3 -3
- package/dist/{cli-7smrsr25.js → cli-zthatyrx.js} +23 -11
- package/dist/cli.js +19 -19
- package/dist/{codex-adapter-8meawydj.js → codex-adapter-rn3aq7jm.js} +7 -7
- package/dist/{codex-hook-hfrt9shr.js → codex-hook-gthcmm0g.js} +3 -3
- package/dist/{codex-session-runner-gjgxyp5j.js → codex-session-runner-bge0cbsw.js} +7 -7
- package/dist/{commands-hz3nb95f.js → commands-26phw0pc.js} +5 -5
- package/dist/{db-ggz97zbm.js → db-jxjx6s1b.js} +6 -6
- package/dist/{e2b-p04vmtx0.js → e2b-413b8t4v.js} +1 -1
- package/dist/handlers-vr1djg4n.js +41 -0
- package/dist/{hook-bks2q1f6.js → hook-jw0ztn96.js} +9 -9
- package/dist/{hook-kq9wp0ep.js → hook-t6fqsggw.js} +10 -10
- package/dist/{http-hrf77v87.js → http-hyc7s57s.js} +80 -71
- package/dist/{index-n28pw1zt.js → index-1d9r6a74.js} +18 -18
- package/dist/{index-cqtebbhb.js → index-bcyx5djw.js} +17 -17
- package/dist/{index-6nsbg88z.js → index-sfhaq59d.js} +408 -74
- package/dist/{index-8hmeg8j1.js → index-wtwpthe1.js} +17 -17
- package/dist/{keepalive-dxc12gvg.js → keepalive-fbsak4ya.js} +7 -7
- package/dist/{lead-yckfn18d.js → lead-rdzdm627.js} +39 -39
- package/dist/{maintenance-6kfb2m5e.js → maintenance-25z1c1vf.js} +9 -9
- package/dist/{node-x1g4v0pq.js → node-209sxmg3.js} +9 -9
- package/dist/{oauth-refresh-sweep-1x1ac722.js → oauth-refresh-sweep-j3d7gtse.js} +6 -6
- package/dist/{onboard-dcyt1609.js → onboard-dkcwrc75.js} +2 -2
- package/dist/{otel-impl-tbk3e5dr.js → otel-impl-8rgyy3j8.js} +1 -1
- package/dist/{pi-mono-adapter-zvshk5cj.js → pi-mono-adapter-4s2bbkgq.js} +8 -8
- package/dist/{pricing-refresh-kaqg567e.js → pricing-refresh-9cek71nq.js} +7 -7
- package/dist/{rbac-roles-cf97v1vd.js → rbac-roles-vk8mqp9v.js} +6 -6
- package/dist/{rbac-roles-ammq6rd2.js → rbac-roles-z98s2ypy.js} +5 -5
- package/dist/{render-v2-80w603vy.js → render-v2-3j26g0qh.js} +7 -7
- package/dist/{seed-pricing-zbrn83xv.js → seed-pricing-7rxhcnzm.js} +6 -6
- package/dist/{setup-fe66kczs.js → setup-e2t7vz0c.js} +2 -2
- package/dist/work-objects-8d3nd3x2.js +141 -0
- package/dist/{worker-qmb2d1e2.js → worker-0x9fn7nq.js} +39 -39
- package/openapi.json +15 -4
- package/package.json +3 -3
- package/src/agentmail/handlers.ts +5 -0
- 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.ts +4 -2
- 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/scripts/typecheck.ts +7 -3
- package/src/be/seed/automation-toggle.ts +69 -0
- package/src/be/seed/schedules-seeder.ts +53 -8
- package/src/be/seed/workflows-seeder.ts +35 -6
- package/src/be/seed-scripts/catalog/delegate.ts +3 -1
- package/src/be/seed-skills/bundled-files.generated.json +1 -1
- package/src/be/steering.ts +1 -0
- package/src/be/swarm-config-guard.ts +1 -0
- package/src/commands/credential-refresh.ts +70 -0
- package/src/commands/provider-credentials.ts +2 -25
- package/src/commands/runner.ts +23 -56
- package/src/github/handlers.ts +9 -0
- package/src/gitlab/handlers.ts +4 -0
- package/src/heartbeat/heartbeat.ts +3 -0
- package/src/http/approval-requests.ts +1 -0
- package/src/http/apps.ts +1 -0
- package/src/http/config.ts +4 -1
- package/src/http/core.ts +4 -2
- package/src/http/index.ts +16 -3
- package/src/http/script-runs.ts +5 -0
- package/src/http/tasks.ts +5 -0
- package/src/integrations/kapso/inbound.ts +1 -0
- package/src/jira/sync.ts +2 -0
- package/src/linear/sync.ts +2 -0
- package/src/prompts/session-templates.ts +13 -9
- package/src/providers/claude-adapter.ts +21 -8
- package/src/scheduler/deferred-task-waits.ts +34 -5
- package/src/scheduler/schedule-task.ts +5 -1
- package/src/scheduler/scheduler.ts +104 -123
- package/src/scripts-runtime/types/stdlib.d.ts +7 -3
- package/src/scripts-runtime/types/swarm-sdk.d.ts +7 -3
- package/src/slack/HEURISTICS.md +2 -0
- package/src/slack/actions.ts +1 -0
- package/src/slack/app.ts +2 -0
- package/src/slack/assistant.ts +4 -12
- package/src/slack/handlers.ts +9 -14
- package/src/slack/inbound-files.ts +3 -3
- package/src/slack/render-v2.ts +17 -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/worker-follow-up.ts +4 -0
- 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 +6 -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 +190 -1
- package/src/tests/devin-adapter.test.ts +1 -1
- package/src/tests/devin-api.test.ts +1 -1
- 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/events-http.test.ts +1 -1
- 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-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-registration.test.ts +97 -3
- 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 +3 -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/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 +1 -1
- package/src/tests/rbac-charact-http.test.ts +1 -1
- package/src/tests/rbac-e2e-helpers.ts +1 -1
- package/src/tests/realtime-room-surfaces.test.ts +1 -1
- package/src/tests/reload-config.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 +1 -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-external-api.test.ts +1 -1
- package/src/tests/scripts-http.test.ts +1 -1
- package/src/tests/scripts-mcp-e2e.test.ts +1 -1
- package/src/tests/scripts-only-gating.test.ts +2 -2
- package/src/tests/scripts-retention.test.ts +1 -1
- package/src/tests/scripts-runtime-identity.test.ts +1 -1
- 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 +139 -8
- package/src/tests/seed-workflows.test.ts +93 -7
- 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-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 +120 -1
- package/src/tests/status.test.ts +7 -7
- package/src/tests/steering-core.test.ts +1 -1
- 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-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-output-agent-id.test.ts +1 -0
- 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/send-task.ts +21 -1
- package/src/tools/skills/skill-publish.ts +1 -0
- package/src/tools/store-progress.ts +1 -1
- package/src/tools/templates.ts +2 -1
- package/src/types.ts +11 -0
- package/src/utils/constants.ts +7 -1
- package/src/utils/credentials.test.ts +16 -16
- package/src/workflows/executors/agent-task.ts +5 -0
- package/templates/ai-toolbox.manifest.json +7 -1
- package/templates/schedules/daily-blocker-digest/config.json +6 -1
- package/templates/schedules/daily-compounding-reflection/config.json +1 -0
- package/templates/schedules/daily-hn-briefing/config.json +1 -1
- package/templates/schedules/daily-status-report/config.json +6 -1
- package/templates/schedules/daily-swarm-update-check/config.json +19 -0
- package/templates/schedules/daily-swarm-update-check/content.md +49 -0
- package/templates/schedules/daily-workflow-health-audit/config.json +6 -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/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-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/{azure-openai-responses-cqar64rc.js → azure-openai-responses-g85jv7m8.js} +8 -8
- package/dist/{cli-4xz3pmrq.js → cli-8qx7jnrk.js} +5 -5
- package/dist/{cli-6664w7y4.js → cli-wk0gjrn3.js} +3 -3
- package/dist/{google-vertex-ppw8ydpa.js → google-vertex-pkhpkbq9.js} +3 -3
- package/dist/{openai-codex-responses-g7w48y30.js → openai-codex-responses-pm5gnyfa.js} +4 -4
- package/dist/{openai-completions-0bqmsajw.js → openai-completions-qdcmkfnr.js} +12 -12
- package/dist/{openai-responses-nmeyptke.js → openai-responses-vwvk1taj.js} +13 -13
|
@@ -41,6 +41,8 @@ import { listenOnFreePort } from "./test-net";
|
|
|
41
41
|
|
|
42
42
|
const TEST_DB_PATH = "./test-workflow-http-v2.sqlite";
|
|
43
43
|
|
|
44
|
+
const secretRef = (name: string): string => `secret.${name}`;
|
|
45
|
+
|
|
44
46
|
// ─── Test Server ─────────────────────────────────────────────
|
|
45
47
|
|
|
46
48
|
function createTestServer(): Server {
|
|
@@ -201,10 +203,10 @@ describe("Workflow HTTP API v2", () => {
|
|
|
201
203
|
name: "full-schema-workflow",
|
|
202
204
|
description: "test",
|
|
203
205
|
definition: simpleDefinition(),
|
|
204
|
-
triggers: [{ type: "webhook", hmacSecret: "secret-123" }],
|
|
206
|
+
triggers: [{ type: "webhook", hmacSecret: "example-secret-123" }],
|
|
205
207
|
cooldown: { minutes: 30 },
|
|
206
208
|
// biome-ignore lint/suspicious/noTemplateCurlyInString: intentional — this is the input resolution syntax
|
|
207
|
-
input: { apiKey: "${API_KEY}", secret: "
|
|
209
|
+
input: { apiKey: "${API_KEY}", secret: secretRef("MY_SECRET"), literal: "hello" },
|
|
208
210
|
}),
|
|
209
211
|
});
|
|
210
212
|
|
|
@@ -480,7 +482,7 @@ describe("Workflow HTTP API v2", () => {
|
|
|
480
482
|
method: "PUT",
|
|
481
483
|
headers,
|
|
482
484
|
body: JSON.stringify({
|
|
483
|
-
triggers: [{ type: "webhook", hmacSecret: "new-secret" }],
|
|
485
|
+
triggers: [{ type: "webhook", hmacSecret: "example-new-secret" }],
|
|
484
486
|
cooldown: { seconds: 30 },
|
|
485
487
|
input: { key: "value" },
|
|
486
488
|
params: { REPO_URL: "acme/widgets" },
|
|
@@ -921,11 +923,11 @@ describe("Workflow HTTP API v2", () => {
|
|
|
921
923
|
describe("POST /api/webhooks/:workflowId", () => {
|
|
922
924
|
test("valid HMAC returns 201", async () => {
|
|
923
925
|
const workflow = await createTestWorkflow({
|
|
924
|
-
triggers: [{ type: "webhook", hmacSecret: "test-secret" }],
|
|
926
|
+
triggers: [{ type: "webhook", hmacSecret: "example-test-secret" }],
|
|
925
927
|
});
|
|
926
928
|
|
|
927
929
|
const body = '{"event":"test"}';
|
|
928
|
-
const hmac = crypto.createHmac("sha256", "test-secret");
|
|
930
|
+
const hmac = crypto.createHmac("sha256", "example-test-secret");
|
|
929
931
|
hmac.update(body);
|
|
930
932
|
const sig = `sha256=${hmac.digest("hex")}`;
|
|
931
933
|
|
|
@@ -944,7 +946,7 @@ describe("Workflow HTTP API v2", () => {
|
|
|
944
946
|
|
|
945
947
|
test("invalid HMAC returns 401", async () => {
|
|
946
948
|
const workflow = await createTestWorkflow({
|
|
947
|
-
triggers: [{ type: "webhook", hmacSecret: "test-secret" }],
|
|
949
|
+
triggers: [{ type: "webhook", hmacSecret: "example-test-secret" }],
|
|
948
950
|
});
|
|
949
951
|
|
|
950
952
|
const res = await fetch(`${baseUrl}/api/webhooks/${workflow.id}`, {
|
|
@@ -26,6 +26,8 @@ import {
|
|
|
26
26
|
|
|
27
27
|
const TEST_DB_PATH = "./test-workflow-input-redaction.sqlite";
|
|
28
28
|
|
|
29
|
+
const secretRef = (name: string): string => `secret.${name}`;
|
|
30
|
+
|
|
29
31
|
// Captures the input it was invoked with so we can assert what the executor
|
|
30
32
|
// actually receives (real value, not redacted).
|
|
31
33
|
class CaptureExecutor extends BaseExecutor<
|
|
@@ -52,7 +54,7 @@ class CaptureExecutor extends BaseExecutor<
|
|
|
52
54
|
|
|
53
55
|
describe("getSecretInputKeys", () => {
|
|
54
56
|
test("flags secret.* references", () => {
|
|
55
|
-
const keys = getSecretInputKeys({ GITHUB_TOKEN: "
|
|
57
|
+
const keys = getSecretInputKeys({ GITHUB_TOKEN: secretRef("GITHUB_TOKEN") });
|
|
56
58
|
expect(keys.has("GITHUB_TOKEN")).toBe(true);
|
|
57
59
|
expect(keys.size).toBe(1);
|
|
58
60
|
});
|
|
@@ -104,7 +106,7 @@ describe("redactSecretsForStorage", () => {
|
|
|
104
106
|
test("redacts only declared secret keys in ctx.input", () => {
|
|
105
107
|
const ctx = {
|
|
106
108
|
trigger: { topic: "tuxedo" },
|
|
107
|
-
input: { GITHUB_TOKEN: "ghp_real_value_xxx", branch: "main" },
|
|
109
|
+
input: { GITHUB_TOKEN: "example-ghp_real_value_xxx", branch: "main" },
|
|
108
110
|
};
|
|
109
111
|
const out = redactSecretsForStorage(ctx, new Set(["GITHUB_TOKEN"]));
|
|
110
112
|
expect((out.input as Record<string, unknown>).GITHUB_TOKEN).toBe(REDACTED_SECRET_VALUE);
|
|
@@ -114,9 +116,9 @@ describe("redactSecretsForStorage", () => {
|
|
|
114
116
|
});
|
|
115
117
|
|
|
116
118
|
test("does not mutate the original ctx (executor still sees real value)", () => {
|
|
117
|
-
const ctx = { input: { GITHUB_TOKEN: "ghp_real" } };
|
|
119
|
+
const ctx = { input: { GITHUB_TOKEN: "example-ghp_real" } };
|
|
118
120
|
redactSecretsForStorage(ctx, new Set(["GITHUB_TOKEN"]));
|
|
119
|
-
expect((ctx.input as Record<string, unknown>).GITHUB_TOKEN).toBe("ghp_real");
|
|
121
|
+
expect((ctx.input as Record<string, unknown>).GITHUB_TOKEN).toBe("example-ghp_real");
|
|
120
122
|
});
|
|
121
123
|
|
|
122
124
|
test("no-ops when ctx has no input block", () => {
|
|
@@ -187,7 +189,7 @@ describe("end-to-end — workflow step persistence redacts secrets", () => {
|
|
|
187
189
|
definition: def,
|
|
188
190
|
triggers: [],
|
|
189
191
|
input: {
|
|
190
|
-
GITHUB_TOKEN: "
|
|
192
|
+
GITHUB_TOKEN: secretRef("TEST_REDACTION_GITHUB_TOKEN"),
|
|
191
193
|
plain: "not-a-secret",
|
|
192
194
|
},
|
|
193
195
|
});
|
|
@@ -588,7 +588,7 @@ describe("Workflow Integration — I/O Schemas, Convergence, TriggerSchema (Phas
|
|
|
588
588
|
};
|
|
589
589
|
|
|
590
590
|
// Set env var for input resolution
|
|
591
|
-
process.env.TEST_INTEG_API_KEY = "secret123";
|
|
591
|
+
process.env.TEST_INTEG_API_KEY = "example-secret123";
|
|
592
592
|
const workflow = await makeWorkflow(def, {
|
|
593
593
|
// biome-ignore lint/suspicious/noTemplateCurlyInString: testing env var syntax
|
|
594
594
|
input: { API_KEY: "${TEST_INTEG_API_KEY}" },
|
|
@@ -600,7 +600,7 @@ describe("Workflow Integration — I/O Schemas, Convergence, TriggerSchema (Phas
|
|
|
600
600
|
expect(run!.status).toBe("completed");
|
|
601
601
|
|
|
602
602
|
const ctx = run!.context as Record<string, unknown>;
|
|
603
|
-
expect(ctx.step1).toEqual({ echo: "env=secret123" });
|
|
603
|
+
expect(ctx.step1).toEqual({ echo: "env=example-secret123" });
|
|
604
604
|
});
|
|
605
605
|
});
|
|
606
606
|
|
|
@@ -17,11 +17,11 @@ describe("resolveWorkflowLlmConfig", () => {
|
|
|
17
17
|
|
|
18
18
|
test("routes OpenAI credentials to the SDK default endpoint", async () => {
|
|
19
19
|
const config = await resolveWorkflowLlmConfig(undefined, {
|
|
20
|
-
OPENAI_API_KEY: "sk-openai-test",
|
|
20
|
+
OPENAI_API_KEY: "example-sk-openai-test",
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
expect(config).toEqual({
|
|
24
|
-
apiKey: "sk-openai-test",
|
|
24
|
+
apiKey: "example-sk-openai-test",
|
|
25
25
|
baseURL: undefined,
|
|
26
26
|
model: "gpt-5.4-mini",
|
|
27
27
|
});
|
|
@@ -32,7 +32,7 @@ describe("resolveWorkflowLlmConfig", () => {
|
|
|
32
32
|
process.env.MEMORY_RATER_MODEL = "openrouter/anthropic/claude-sonnet-4-5";
|
|
33
33
|
try {
|
|
34
34
|
const config = await resolveWorkflowLlmConfig(undefined, {
|
|
35
|
-
OPENAI_API_KEY: "sk-openai-test",
|
|
35
|
+
OPENAI_API_KEY: "example-sk-openai-test",
|
|
36
36
|
});
|
|
37
37
|
expect(config.model).toBe("gpt-5.4-mini");
|
|
38
38
|
} finally {
|
|
@@ -43,7 +43,7 @@ describe("resolveWorkflowLlmConfig", () => {
|
|
|
43
43
|
|
|
44
44
|
test("preserves an explicit provider-compatible model", async () => {
|
|
45
45
|
const config = await resolveWorkflowLlmConfig("openai/gpt-5.4", {
|
|
46
|
-
OPENAI_API_KEY: "sk-openai-test",
|
|
46
|
+
OPENAI_API_KEY: "example-sk-openai-test",
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
expect(config.model).toBe("gpt-5.4");
|
|
@@ -51,7 +51,7 @@ describe("resolveWorkflowLlmConfig", () => {
|
|
|
51
51
|
|
|
52
52
|
test("rejects credential kinds without an OpenAI-compatible endpoint", async () => {
|
|
53
53
|
await expect(
|
|
54
|
-
resolveWorkflowLlmConfig(undefined, { ANTHROPIC_API_KEY: "sk-ant-test" }),
|
|
54
|
+
resolveWorkflowLlmConfig(undefined, { ANTHROPIC_API_KEY: "example-sk-ant-test" }),
|
|
55
55
|
).rejects.toThrow("do not support the resolved anthropic credential yet");
|
|
56
56
|
});
|
|
57
57
|
});
|
|
@@ -500,7 +500,7 @@ describe("Workflow Registry & Definition (Phase 1)", () => {
|
|
|
500
500
|
{ id: "b", type: "notify", config: { channel: "swarm", template: "done" } },
|
|
501
501
|
],
|
|
502
502
|
},
|
|
503
|
-
triggers: [{ type: "webhook", hmacSecret: "test-secret" }],
|
|
503
|
+
triggers: [{ type: "webhook", hmacSecret: "example-test-secret" }],
|
|
504
504
|
cooldown: { hours: 1 },
|
|
505
505
|
input: { apiKey: envVarRef },
|
|
506
506
|
});
|
|
@@ -35,7 +35,7 @@ import { SKIP_SANDBOX_SPAWN_TESTS } from "./sandbox-spawn-test-helpers";
|
|
|
35
35
|
const skip = test.skipIf(SKIP_SANDBOX_SPAWN_TESTS);
|
|
36
36
|
|
|
37
37
|
const TEST_DB_PATH = "./test-workflow-swarm-script.sqlite";
|
|
38
|
-
const API_KEY = "test-workflow-swarm-script-key-1234567890";
|
|
38
|
+
const API_KEY = "example-test-workflow-swarm-script-key-1234567890";
|
|
39
39
|
|
|
40
40
|
const noOpEmbeddingProvider = {
|
|
41
41
|
name: "test/noop-workflow-script-embedding",
|
|
@@ -27,6 +27,8 @@ import {
|
|
|
27
27
|
|
|
28
28
|
const TEST_DB_PATH = "./test-workflow-triggers-v2.sqlite";
|
|
29
29
|
|
|
30
|
+
const secretRef = (name: string): string => `secret.${name}`;
|
|
31
|
+
|
|
30
32
|
// ─── Test Executor ──────────────────────────────────────────
|
|
31
33
|
|
|
32
34
|
class NoopExecutor extends BaseExecutor<typeof NoopExecutor.schema, typeof NoopExecutor.outSchema> {
|
|
@@ -86,7 +88,7 @@ async function makeWorkflow(
|
|
|
86
88
|
// ─── HMAC Verification ──────────────────────────────────────
|
|
87
89
|
|
|
88
90
|
describe("verifyHmacSignature", () => {
|
|
89
|
-
const secret = "test-secret-123";
|
|
91
|
+
const secret = "example-test-secret-123";
|
|
90
92
|
const body = '{"event":"test"}';
|
|
91
93
|
|
|
92
94
|
test("valid sha256=<hex> signature passes", () => {
|
|
@@ -123,7 +125,7 @@ describe("verifyHmacSignature", () => {
|
|
|
123
125
|
});
|
|
124
126
|
|
|
125
127
|
describe("verifyTimestampedHmacSignature", () => {
|
|
126
|
-
const secret = "timestamped-secret";
|
|
128
|
+
const secret = "example-timestamped-secret";
|
|
127
129
|
const body = '{"event":"finding.triage_completed"}';
|
|
128
130
|
const timestamp = 1_700_000_000;
|
|
129
131
|
const nowMs = timestamp * 1000;
|
|
@@ -213,7 +215,7 @@ describe("verifyTokenEquality", () => {
|
|
|
213
215
|
|
|
214
216
|
describe("handleWebhookTrigger", () => {
|
|
215
217
|
test("valid HMAC starts workflow", async () => {
|
|
216
|
-
const secret = "my-webhook-secret";
|
|
218
|
+
const secret = "example-my-webhook-secret";
|
|
217
219
|
const workflow = await makeWorkflow({
|
|
218
220
|
triggers: [{ type: "webhook", hmacSecret: secret }],
|
|
219
221
|
});
|
|
@@ -241,7 +243,7 @@ describe("handleWebhookTrigger", () => {
|
|
|
241
243
|
|
|
242
244
|
test("invalid HMAC rejects with 401", async () => {
|
|
243
245
|
const workflow = await makeWorkflow({
|
|
244
|
-
triggers: [{ type: "webhook", hmacSecret: "secret-123" }],
|
|
246
|
+
triggers: [{ type: "webhook", hmacSecret: "example-secret-123" }],
|
|
245
247
|
});
|
|
246
248
|
|
|
247
249
|
try {
|
|
@@ -260,7 +262,7 @@ describe("handleWebhookTrigger", () => {
|
|
|
260
262
|
|
|
261
263
|
test("missing signature rejects with 401 when hmacSecret is set", async () => {
|
|
262
264
|
const workflow = await makeWorkflow({
|
|
263
|
-
triggers: [{ type: "webhook", hmacSecret: "secret-xyz" }],
|
|
265
|
+
triggers: [{ type: "webhook", hmacSecret: "example-secret-xyz" }],
|
|
264
266
|
});
|
|
265
267
|
|
|
266
268
|
try {
|
|
@@ -374,7 +376,7 @@ describe("handleWebhookTrigger — custom hmacHeader", () => {
|
|
|
374
376
|
}
|
|
375
377
|
|
|
376
378
|
test("custom hmacHeader (X-Webhook-Signature) is picked up and verified", async () => {
|
|
377
|
-
const secret = "kapso-secret";
|
|
379
|
+
const secret = "example-kapso-secret";
|
|
378
380
|
const workflow = await makeWorkflow({
|
|
379
381
|
triggers: [{ type: "webhook", hmacSecret: secret, hmacHeader: "X-Webhook-Signature" }],
|
|
380
382
|
});
|
|
@@ -393,7 +395,7 @@ describe("handleWebhookTrigger — custom hmacHeader", () => {
|
|
|
393
395
|
});
|
|
394
396
|
|
|
395
397
|
test("custom hmacHeader lookup is case-insensitive", async () => {
|
|
396
|
-
const secret = "kapso-secret-ci";
|
|
398
|
+
const secret = "example-kapso-secret-ci";
|
|
397
399
|
const workflow = await makeWorkflow({
|
|
398
400
|
triggers: [{ type: "webhook", hmacSecret: secret, hmacHeader: "X-Webhook-Signature" }],
|
|
399
401
|
});
|
|
@@ -410,7 +412,7 @@ describe("handleWebhookTrigger — custom hmacHeader", () => {
|
|
|
410
412
|
});
|
|
411
413
|
|
|
412
414
|
test("signature on a non-configured header is rejected as missing", async () => {
|
|
413
|
-
const secret = "kapso-secret-2";
|
|
415
|
+
const secret = "example-kapso-secret-2";
|
|
414
416
|
const workflow = await makeWorkflow({
|
|
415
417
|
triggers: [{ type: "webhook", hmacSecret: secret, hmacHeader: "X-Webhook-Signature" }],
|
|
416
418
|
});
|
|
@@ -432,7 +434,7 @@ describe("handleWebhookTrigger — custom hmacHeader", () => {
|
|
|
432
434
|
});
|
|
433
435
|
|
|
434
436
|
test("fallback header (x-signature) still works without explicit hmacHeader", async () => {
|
|
435
|
-
const secret = "fallback-secret";
|
|
437
|
+
const secret = "example-fallback-secret";
|
|
436
438
|
const workflow = await makeWorkflow({
|
|
437
439
|
triggers: [{ type: "webhook", hmacSecret: secret }],
|
|
438
440
|
});
|
|
@@ -449,7 +451,7 @@ describe("handleWebhookTrigger — custom hmacHeader", () => {
|
|
|
449
451
|
});
|
|
450
452
|
|
|
451
453
|
test("default X-Hub-Signature-256 path still works (no regression)", async () => {
|
|
452
|
-
const secret = "default-header-secret";
|
|
454
|
+
const secret = "example-default-header-secret";
|
|
453
455
|
const workflow = await makeWorkflow({
|
|
454
456
|
triggers: [{ type: "webhook", hmacSecret: secret }],
|
|
455
457
|
});
|
|
@@ -467,7 +469,7 @@ describe("handleWebhookTrigger — custom hmacHeader", () => {
|
|
|
467
469
|
});
|
|
468
470
|
|
|
469
471
|
test("explicit hmac-sha256 verification does not use fallback headers", async () => {
|
|
470
|
-
const secret = "explicit-hmac-secret";
|
|
472
|
+
const secret = "example-explicit-hmac-secret";
|
|
471
473
|
const workflow = await makeWorkflow({
|
|
472
474
|
triggers: [
|
|
473
475
|
{
|
|
@@ -500,7 +502,7 @@ describe("handleWebhookTrigger — verification formats", () => {
|
|
|
500
502
|
}
|
|
501
503
|
|
|
502
504
|
test("timestamped-hmac-sha256 starts workflow for Superagent-shaped request", async () => {
|
|
503
|
-
const secret = "superagent-secret";
|
|
505
|
+
const secret = "example-superagent-secret";
|
|
504
506
|
const timestamp = Math.floor(Date.now() / 1000);
|
|
505
507
|
const workflow = await makeWorkflow({
|
|
506
508
|
triggers: [
|
|
@@ -536,7 +538,7 @@ describe("handleWebhookTrigger — verification formats", () => {
|
|
|
536
538
|
});
|
|
537
539
|
|
|
538
540
|
test("timestamped-hmac-sha256 rejects signatures on fallback headers", async () => {
|
|
539
|
-
const secret = "timestamped-no-fallback-secret";
|
|
541
|
+
const secret = "example-timestamped-no-fallback-secret";
|
|
540
542
|
const timestamp = Math.floor(Date.now() / 1000);
|
|
541
543
|
const workflow = await makeWorkflow({
|
|
542
544
|
triggers: [
|
|
@@ -571,7 +573,7 @@ describe("handleWebhookTrigger — verification formats", () => {
|
|
|
571
573
|
triggers: [
|
|
572
574
|
{
|
|
573
575
|
type: "webhook",
|
|
574
|
-
hmacSecret: "gitlab-token",
|
|
576
|
+
hmacSecret: "example-gitlab-token",
|
|
575
577
|
verification: { format: "token-equality", header: "X-Gitlab-Token" },
|
|
576
578
|
},
|
|
577
579
|
],
|
|
@@ -580,7 +582,7 @@ describe("handleWebhookTrigger — verification formats", () => {
|
|
|
580
582
|
const result = await handleWebhookTrigger(
|
|
581
583
|
workflow.id,
|
|
582
584
|
'{"event":"push"}',
|
|
583
|
-
{ "x-gitlab-token": "gitlab-token" },
|
|
585
|
+
{ "x-gitlab-token": "example-gitlab-token" },
|
|
584
586
|
registry,
|
|
585
587
|
);
|
|
586
588
|
|
|
@@ -592,7 +594,7 @@ describe("handleWebhookTrigger — verification formats", () => {
|
|
|
592
594
|
triggers: [
|
|
593
595
|
{
|
|
594
596
|
type: "webhook",
|
|
595
|
-
hmacSecret: "gitlab-token",
|
|
597
|
+
hmacSecret: "example-gitlab-token",
|
|
596
598
|
verification: { format: "token-equality", header: "X-Gitlab-Token" },
|
|
597
599
|
},
|
|
598
600
|
],
|
|
@@ -658,7 +660,7 @@ describe("handleWebhookTrigger — hmacSecret references", () => {
|
|
|
658
660
|
triggers: [
|
|
659
661
|
{
|
|
660
662
|
type: "webhook",
|
|
661
|
-
hmacSecret: "
|
|
663
|
+
hmacSecret: secretRef("TEST_KAPSO_WEBHOOK_HMAC_SECRET"),
|
|
662
664
|
hmacHeader: "X-Webhook-Signature",
|
|
663
665
|
},
|
|
664
666
|
],
|
|
@@ -678,7 +680,7 @@ describe("handleWebhookTrigger — hmacSecret references", () => {
|
|
|
678
680
|
|
|
679
681
|
test("unresolvable secret.NAME ref fails cleanly with a WebhookError", async () => {
|
|
680
682
|
const workflow = await makeWorkflow({
|
|
681
|
-
triggers: [{ type: "webhook", hmacSecret: "
|
|
683
|
+
triggers: [{ type: "webhook", hmacSecret: secretRef("NONEXISTENT_HMAC_SECRET_12345") }],
|
|
682
684
|
});
|
|
683
685
|
|
|
684
686
|
const body = '{"event":"missing-secret"}';
|
|
@@ -697,7 +699,7 @@ describe("handleWebhookTrigger — hmacSecret references", () => {
|
|
|
697
699
|
});
|
|
698
700
|
|
|
699
701
|
test("a literal hmacSecret is not treated as a reference", async () => {
|
|
700
|
-
const secret = "
|
|
702
|
+
const secret = `plain.${"literal-not-a-ref"}`;
|
|
701
703
|
const workflow = await makeWorkflow({
|
|
702
704
|
triggers: [{ type: "webhook", hmacSecret: secret }],
|
|
703
705
|
});
|
|
@@ -739,7 +741,7 @@ describe("handleWebhookTrigger — triggerData JSON parsing", () => {
|
|
|
739
741
|
});
|
|
740
742
|
|
|
741
743
|
test("signed JSON body: HMAC verified against raw bytes, triggerData parsed to object", async () => {
|
|
742
|
-
const secret = "kapso-deep-secret";
|
|
744
|
+
const secret = "example-kapso-deep-secret";
|
|
743
745
|
const workflow = await makeWorkflow({
|
|
744
746
|
triggers: [{ type: "webhook", hmacSecret: secret, hmacHeader: "X-Webhook-Signature" }],
|
|
745
747
|
});
|
|
@@ -858,7 +860,7 @@ describe("TriggerConfigSchema", () => {
|
|
|
858
860
|
test("accepts verification configured with hmacSecret", () => {
|
|
859
861
|
const result = TriggerConfigSchema.safeParse({
|
|
860
862
|
type: "webhook",
|
|
861
|
-
hmacSecret: "gitlab-token",
|
|
863
|
+
hmacSecret: "example-gitlab-token",
|
|
862
864
|
verification: { format: "token-equality", header: "X-Gitlab-Token" },
|
|
863
865
|
});
|
|
864
866
|
|
|
@@ -45,12 +45,12 @@ describe("runComposioCommand", () => {
|
|
|
45
45
|
const fetchMock = mock(async (url: string | URL | Request, init?: RequestInit) => {
|
|
46
46
|
expect(String(url)).toBe("https://backend.composio.dev/api/v3.1/tools?limit=10");
|
|
47
47
|
expect(init?.method).toBe("GET");
|
|
48
|
-
expect((init?.headers as Record<string, string>)["x-api-key"]).toBe("ck_test_secret");
|
|
49
|
-
return jsonResponse({ ok: true, token: "ck_test_secret" });
|
|
48
|
+
expect((init?.headers as Record<string, string>)["x-api-key"]).toBe("example-ck_test_secret");
|
|
49
|
+
return jsonResponse({ ok: true, token: "example-ck_test_secret" });
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
await runComposioCommand(["GET", "/tools", "--query", "limit=10"], {
|
|
53
|
-
env: { COMPOSIO_API_KEY: "ck_test_secret" },
|
|
53
|
+
env: { COMPOSIO_API_KEY: "example-ck_test_secret" },
|
|
54
54
|
fetch: fetchMock,
|
|
55
55
|
log: (message) => out.push(message),
|
|
56
56
|
error: (message) => out.push(message),
|
|
@@ -62,18 +62,20 @@ describe("runComposioCommand", () => {
|
|
|
62
62
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
63
63
|
expect(out.join("\n")).toContain('"ok": true');
|
|
64
64
|
expect(out.join("\n")).toContain("[REDACTED:COMPOSIO_API_KEY]");
|
|
65
|
-
expect(out.join("\n")).not.toContain("ck_test_secret");
|
|
65
|
+
expect(out.join("\n")).not.toContain("example-ck_test_secret");
|
|
66
66
|
});
|
|
67
67
|
|
|
68
68
|
test("uses org key header when --org is passed", async () => {
|
|
69
69
|
const fetchMock = mock(async (_url: string | URL | Request, init?: RequestInit) => {
|
|
70
|
-
expect((init?.headers as Record<string, string>)["x-org-api-key"]).toBe(
|
|
70
|
+
expect((init?.headers as Record<string, string>)["x-org-api-key"]).toBe(
|
|
71
|
+
"example-org_secret_value",
|
|
72
|
+
);
|
|
71
73
|
expect((init?.headers as Record<string, string>)["x-api-key"]).toBeUndefined();
|
|
72
74
|
return jsonResponse({ ok: true });
|
|
73
75
|
});
|
|
74
76
|
|
|
75
77
|
await runComposioCommand(["GET", "/org/projects", "--org"], {
|
|
76
|
-
env: { COMPOSIO_ORG_API_KEY: "org_secret_value" },
|
|
78
|
+
env: { COMPOSIO_ORG_API_KEY: "example-org_secret_value" },
|
|
77
79
|
fetch: fetchMock,
|
|
78
80
|
log: () => {},
|
|
79
81
|
error: () => {},
|
|
@@ -108,7 +110,7 @@ describe("runXCommand", () => {
|
|
|
108
110
|
test("dispatches to composio target", async () => {
|
|
109
111
|
const fetchMock = mock(async () => jsonResponse({ ok: true }));
|
|
110
112
|
await runXCommand(["composio", "GET", "/tools"], {
|
|
111
|
-
env: { COMPOSIO_API_KEY: "ck_test_secret" },
|
|
113
|
+
env: { COMPOSIO_API_KEY: "example-ck_test_secret" },
|
|
112
114
|
fetch: fetchMock,
|
|
113
115
|
log: () => {},
|
|
114
116
|
error: () => {},
|
|
@@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
|
2
2
|
import { createX402Client } from "../x402/client.ts";
|
|
3
3
|
|
|
4
4
|
// A valid test private key (DO NOT use in production — this is a well-known throwaway key)
|
|
5
|
-
const TEST_PRIVATE_KEY = "
|
|
5
|
+
const TEST_PRIVATE_KEY = `0x${"11".repeat(32)}`;
|
|
6
6
|
|
|
7
7
|
describe("createX402Client", () => {
|
|
8
8
|
const originalEnv = { ...process.env };
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
2
|
import { loadX402Config } from "../x402/config.ts";
|
|
3
3
|
|
|
4
|
+
const TEST_PRIVATE_KEY = `0x${"11".repeat(32)}`;
|
|
5
|
+
const TEST_PRIVATE_KEY_WITHOUT_PREFIX = TEST_PRIVATE_KEY.slice(2);
|
|
6
|
+
|
|
4
7
|
describe("loadX402Config", () => {
|
|
5
8
|
const originalEnv = { ...process.env };
|
|
6
9
|
|
|
@@ -28,25 +31,20 @@ describe("loadX402Config", () => {
|
|
|
28
31
|
// --- Viem signer tests ---
|
|
29
32
|
|
|
30
33
|
test("auto-detects viem signer when EVM_PRIVATE_KEY is set", () => {
|
|
31
|
-
process.env.EVM_PRIVATE_KEY =
|
|
32
|
-
"0xdeadbeef1234567890abcdef1234567890abcdef1234567890abcdef12345678";
|
|
34
|
+
process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
|
|
33
35
|
|
|
34
36
|
const config = loadX402Config();
|
|
35
37
|
expect(config.signerType).toBe("viem");
|
|
36
|
-
expect(config.evmPrivateKey).toBe(
|
|
37
|
-
"0xdeadbeef1234567890abcdef1234567890abcdef1234567890abcdef12345678",
|
|
38
|
-
);
|
|
38
|
+
expect(config.evmPrivateKey).toBe(TEST_PRIVATE_KEY);
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
test("throws when EVM_PRIVATE_KEY does not start with 0x", () => {
|
|
42
|
-
process.env.EVM_PRIVATE_KEY =
|
|
43
|
-
"deadbeef1234567890abcdef1234567890abcdef1234567890abcdef12345678";
|
|
42
|
+
process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY_WITHOUT_PREFIX;
|
|
44
43
|
expect(() => loadX402Config()).toThrow("EVM_PRIVATE_KEY must start with '0x'");
|
|
45
44
|
});
|
|
46
45
|
|
|
47
46
|
test("returns config with defaults when only EVM_PRIVATE_KEY is set", () => {
|
|
48
|
-
process.env.EVM_PRIVATE_KEY =
|
|
49
|
-
"0xdeadbeef1234567890abcdef1234567890abcdef1234567890abcdef12345678";
|
|
47
|
+
process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
|
|
50
48
|
|
|
51
49
|
const config = loadX402Config();
|
|
52
50
|
|
|
@@ -59,33 +57,32 @@ describe("loadX402Config", () => {
|
|
|
59
57
|
// --- Openfort signer tests ---
|
|
60
58
|
|
|
61
59
|
test("auto-detects openfort signer when OPENFORT_API_KEY is set", () => {
|
|
62
|
-
process.env.OPENFORT_API_KEY = "sk_test_abc123";
|
|
63
|
-
process.env.OPENFORT_WALLET_SECRET = "base64secret";
|
|
60
|
+
process.env.OPENFORT_API_KEY = "example-sk_test_abc123";
|
|
61
|
+
process.env.OPENFORT_WALLET_SECRET = "example-base64secret";
|
|
64
62
|
|
|
65
63
|
const config = loadX402Config();
|
|
66
64
|
expect(config.signerType).toBe("openfort");
|
|
67
|
-
expect(config.openfortApiKey).toBe("sk_test_abc123");
|
|
68
|
-
expect(config.openfortWalletSecret).toBe("base64secret");
|
|
65
|
+
expect(config.openfortApiKey).toBe("example-sk_test_abc123");
|
|
66
|
+
expect(config.openfortWalletSecret).toBe("example-base64secret");
|
|
69
67
|
});
|
|
70
68
|
|
|
71
69
|
test("openfort takes priority over viem when both are set", () => {
|
|
72
|
-
process.env.OPENFORT_API_KEY = "sk_test_abc123";
|
|
73
|
-
process.env.OPENFORT_WALLET_SECRET = "base64secret";
|
|
74
|
-
process.env.EVM_PRIVATE_KEY =
|
|
75
|
-
"0xdeadbeef1234567890abcdef1234567890abcdef1234567890abcdef12345678";
|
|
70
|
+
process.env.OPENFORT_API_KEY = "example-sk_test_abc123";
|
|
71
|
+
process.env.OPENFORT_WALLET_SECRET = "example-base64secret";
|
|
72
|
+
process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
|
|
76
73
|
|
|
77
74
|
const config = loadX402Config();
|
|
78
75
|
expect(config.signerType).toBe("openfort");
|
|
79
76
|
});
|
|
80
77
|
|
|
81
78
|
test("throws when openfort signer is selected but OPENFORT_WALLET_SECRET is missing", () => {
|
|
82
|
-
process.env.OPENFORT_API_KEY = "sk_test_abc123";
|
|
79
|
+
process.env.OPENFORT_API_KEY = "example-sk_test_abc123";
|
|
83
80
|
expect(() => loadX402Config()).toThrow("OPENFORT_WALLET_SECRET is required");
|
|
84
81
|
});
|
|
85
82
|
|
|
86
83
|
test("includes OPENFORT_WALLET_ADDRESS when set", () => {
|
|
87
|
-
process.env.OPENFORT_API_KEY = "sk_test_abc123";
|
|
88
|
-
process.env.OPENFORT_WALLET_SECRET = "base64secret";
|
|
84
|
+
process.env.OPENFORT_API_KEY = "example-sk_test_abc123";
|
|
85
|
+
process.env.OPENFORT_WALLET_SECRET = "example-base64secret";
|
|
89
86
|
process.env.OPENFORT_WALLET_ADDRESS = "0x1234567890abcdef1234567890abcdef12345678";
|
|
90
87
|
|
|
91
88
|
const config = loadX402Config();
|
|
@@ -96,9 +93,8 @@ describe("loadX402Config", () => {
|
|
|
96
93
|
|
|
97
94
|
test("respects explicit X402_SIGNER_TYPE=viem", () => {
|
|
98
95
|
process.env.X402_SIGNER_TYPE = "viem";
|
|
99
|
-
process.env.EVM_PRIVATE_KEY =
|
|
100
|
-
|
|
101
|
-
process.env.OPENFORT_API_KEY = "sk_test_abc123";
|
|
96
|
+
process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
|
|
97
|
+
process.env.OPENFORT_API_KEY = "example-sk_test_abc123";
|
|
102
98
|
|
|
103
99
|
const config = loadX402Config();
|
|
104
100
|
expect(config.signerType).toBe("viem");
|
|
@@ -106,16 +102,14 @@ describe("loadX402Config", () => {
|
|
|
106
102
|
|
|
107
103
|
test("throws on invalid X402_SIGNER_TYPE", () => {
|
|
108
104
|
process.env.X402_SIGNER_TYPE = "invalid";
|
|
109
|
-
process.env.EVM_PRIVATE_KEY =
|
|
110
|
-
"0xdeadbeef1234567890abcdef1234567890abcdef1234567890abcdef12345678";
|
|
105
|
+
process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
|
|
111
106
|
expect(() => loadX402Config()).toThrow('X402_SIGNER_TYPE must be "openfort" or "viem"');
|
|
112
107
|
});
|
|
113
108
|
|
|
114
109
|
// --- Spending limit tests ---
|
|
115
110
|
|
|
116
111
|
test("parses custom X402_MAX_AUTO_APPROVE", () => {
|
|
117
|
-
process.env.EVM_PRIVATE_KEY =
|
|
118
|
-
"0xdeadbeef1234567890abcdef1234567890abcdef1234567890abcdef12345678";
|
|
112
|
+
process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
|
|
119
113
|
process.env.X402_MAX_AUTO_APPROVE = "5.50";
|
|
120
114
|
|
|
121
115
|
const config = loadX402Config();
|
|
@@ -123,8 +117,7 @@ describe("loadX402Config", () => {
|
|
|
123
117
|
});
|
|
124
118
|
|
|
125
119
|
test("parses custom X402_DAILY_LIMIT", () => {
|
|
126
|
-
process.env.EVM_PRIVATE_KEY =
|
|
127
|
-
"0xdeadbeef1234567890abcdef1234567890abcdef1234567890abcdef12345678";
|
|
120
|
+
process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
|
|
128
121
|
process.env.X402_DAILY_LIMIT = "25.00";
|
|
129
122
|
|
|
130
123
|
const config = loadX402Config();
|
|
@@ -132,8 +125,7 @@ describe("loadX402Config", () => {
|
|
|
132
125
|
});
|
|
133
126
|
|
|
134
127
|
test("uses custom X402_NETWORK", () => {
|
|
135
|
-
process.env.EVM_PRIVATE_KEY =
|
|
136
|
-
"0xdeadbeef1234567890abcdef1234567890abcdef1234567890abcdef12345678";
|
|
128
|
+
process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
|
|
137
129
|
process.env.X402_NETWORK = "eip155:8453";
|
|
138
130
|
|
|
139
131
|
const config = loadX402Config();
|
|
@@ -141,40 +133,35 @@ describe("loadX402Config", () => {
|
|
|
141
133
|
});
|
|
142
134
|
|
|
143
135
|
test("throws when X402_MAX_AUTO_APPROVE is not a valid number", () => {
|
|
144
|
-
process.env.EVM_PRIVATE_KEY =
|
|
145
|
-
"0xdeadbeef1234567890abcdef1234567890abcdef1234567890abcdef12345678";
|
|
136
|
+
process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
|
|
146
137
|
process.env.X402_MAX_AUTO_APPROVE = "abc";
|
|
147
138
|
|
|
148
139
|
expect(() => loadX402Config()).toThrow("X402_MAX_AUTO_APPROVE must be a positive number");
|
|
149
140
|
});
|
|
150
141
|
|
|
151
142
|
test("throws when X402_MAX_AUTO_APPROVE is zero", () => {
|
|
152
|
-
process.env.EVM_PRIVATE_KEY =
|
|
153
|
-
"0xdeadbeef1234567890abcdef1234567890abcdef1234567890abcdef12345678";
|
|
143
|
+
process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
|
|
154
144
|
process.env.X402_MAX_AUTO_APPROVE = "0";
|
|
155
145
|
|
|
156
146
|
expect(() => loadX402Config()).toThrow("X402_MAX_AUTO_APPROVE must be a positive number");
|
|
157
147
|
});
|
|
158
148
|
|
|
159
149
|
test("throws when X402_MAX_AUTO_APPROVE is negative", () => {
|
|
160
|
-
process.env.EVM_PRIVATE_KEY =
|
|
161
|
-
"0xdeadbeef1234567890abcdef1234567890abcdef1234567890abcdef12345678";
|
|
150
|
+
process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
|
|
162
151
|
process.env.X402_MAX_AUTO_APPROVE = "-1";
|
|
163
152
|
|
|
164
153
|
expect(() => loadX402Config()).toThrow("X402_MAX_AUTO_APPROVE must be a positive number");
|
|
165
154
|
});
|
|
166
155
|
|
|
167
156
|
test("throws when X402_DAILY_LIMIT is not a valid number", () => {
|
|
168
|
-
process.env.EVM_PRIVATE_KEY =
|
|
169
|
-
"0xdeadbeef1234567890abcdef1234567890abcdef1234567890abcdef12345678";
|
|
157
|
+
process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
|
|
170
158
|
process.env.X402_DAILY_LIMIT = "not-a-number";
|
|
171
159
|
|
|
172
160
|
expect(() => loadX402Config()).toThrow("X402_DAILY_LIMIT must be a positive number");
|
|
173
161
|
});
|
|
174
162
|
|
|
175
163
|
test("throws when X402_DAILY_LIMIT is zero", () => {
|
|
176
|
-
process.env.EVM_PRIVATE_KEY =
|
|
177
|
-
"0xdeadbeef1234567890abcdef1234567890abcdef1234567890abcdef12345678";
|
|
164
|
+
process.env.EVM_PRIVATE_KEY = TEST_PRIVATE_KEY;
|
|
178
165
|
process.env.X402_DAILY_LIMIT = "0";
|
|
179
166
|
|
|
180
167
|
expect(() => loadX402Config()).toThrow("X402_DAILY_LIMIT must be a positive number");
|