@adcp/sdk 5.23.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/.claude-plugin/marketplace.json +17 -0
- package/.claude-plugin/plugin.json +25 -0
- package/ADCP_VERSION +1 -0
- package/AGENTS.md +282 -0
- package/LICENSE +191 -0
- package/README.md +816 -0
- package/bin/adcp-async-handler.js +275 -0
- package/bin/adcp-config.js +240 -0
- package/bin/adcp-fuzz.js +391 -0
- package/bin/adcp-grade.js +505 -0
- package/bin/adcp-json-stdout.js +36 -0
- package/bin/adcp-registry.js +745 -0
- package/bin/adcp-signing.js +233 -0
- package/bin/adcp-step-hints.js +246 -0
- package/bin/adcp-version-check.js +150 -0
- package/bin/adcp.js +4821 -0
- package/compliance/cache/3.0.0/domains/brand/index.yaml +167 -0
- package/compliance/cache/3.0.0/domains/creative/index.yaml +412 -0
- package/compliance/cache/3.0.0/domains/governance/index.yaml +683 -0
- package/compliance/cache/3.0.0/domains/media-buy/creative-reception.yaml +247 -0
- package/compliance/cache/3.0.0/domains/media-buy/index.yaml +742 -0
- package/compliance/cache/3.0.0/domains/media-buy/scenarios/creative_fate_after_cancellation.yaml +414 -0
- package/compliance/cache/3.0.0/domains/media-buy/scenarios/delivery_reporting.yaml +180 -0
- package/compliance/cache/3.0.0/domains/media-buy/scenarios/governance_approved.yaml +186 -0
- package/compliance/cache/3.0.0/domains/media-buy/scenarios/governance_conditions.yaml +195 -0
- package/compliance/cache/3.0.0/domains/media-buy/scenarios/governance_denied.yaml +189 -0
- package/compliance/cache/3.0.0/domains/media-buy/scenarios/governance_denied_recovery.yaml +243 -0
- package/compliance/cache/3.0.0/domains/media-buy/scenarios/invalid_transitions.yaml +279 -0
- package/compliance/cache/3.0.0/domains/media-buy/scenarios/inventory_list_no_match.yaml +143 -0
- package/compliance/cache/3.0.0/domains/media-buy/scenarios/inventory_list_targeting.yaml +266 -0
- package/compliance/cache/3.0.0/domains/media-buy/scenarios/measurement_terms_rejected.yaml +194 -0
- package/compliance/cache/3.0.0/domains/media-buy/scenarios/pending_creatives_to_start.yaml +250 -0
- package/compliance/cache/3.0.0/domains/media-buy/scenarios/proposal_finalize.yaml +242 -0
- package/compliance/cache/3.0.0/domains/media-buy/scenarios/refine_products.yaml +148 -0
- package/compliance/cache/3.0.0/domains/media-buy/state-machine.yaml +437 -0
- package/compliance/cache/3.0.0/domains/signals/index.yaml +266 -0
- package/compliance/cache/3.0.0/domains/sponsored-intelligence/index.yaml +256 -0
- package/compliance/cache/3.0.0/index.json +324 -0
- package/compliance/cache/3.0.0/protocols/brand/index.yaml +167 -0
- package/compliance/cache/3.0.0/protocols/creative/index.yaml +412 -0
- package/compliance/cache/3.0.0/protocols/governance/index.yaml +683 -0
- package/compliance/cache/3.0.0/protocols/media-buy/creative-reception.yaml +247 -0
- package/compliance/cache/3.0.0/protocols/media-buy/index.yaml +742 -0
- package/compliance/cache/3.0.0/protocols/media-buy/scenarios/creative_fate_after_cancellation.yaml +414 -0
- package/compliance/cache/3.0.0/protocols/media-buy/scenarios/delivery_reporting.yaml +180 -0
- package/compliance/cache/3.0.0/protocols/media-buy/scenarios/governance_approved.yaml +186 -0
- package/compliance/cache/3.0.0/protocols/media-buy/scenarios/governance_conditions.yaml +195 -0
- package/compliance/cache/3.0.0/protocols/media-buy/scenarios/governance_denied.yaml +189 -0
- package/compliance/cache/3.0.0/protocols/media-buy/scenarios/governance_denied_recovery.yaml +243 -0
- package/compliance/cache/3.0.0/protocols/media-buy/scenarios/invalid_transitions.yaml +279 -0
- package/compliance/cache/3.0.0/protocols/media-buy/scenarios/inventory_list_no_match.yaml +143 -0
- package/compliance/cache/3.0.0/protocols/media-buy/scenarios/inventory_list_targeting.yaml +266 -0
- package/compliance/cache/3.0.0/protocols/media-buy/scenarios/measurement_terms_rejected.yaml +194 -0
- package/compliance/cache/3.0.0/protocols/media-buy/scenarios/pending_creatives_to_start.yaml +250 -0
- package/compliance/cache/3.0.0/protocols/media-buy/scenarios/proposal_finalize.yaml +242 -0
- package/compliance/cache/3.0.0/protocols/media-buy/scenarios/refine_products.yaml +148 -0
- package/compliance/cache/3.0.0/protocols/media-buy/state-machine.yaml +437 -0
- package/compliance/cache/3.0.0/protocols/signals/index.yaml +266 -0
- package/compliance/cache/3.0.0/protocols/sponsored-intelligence/index.yaml +256 -0
- package/compliance/cache/3.0.0/specialisms/audience-sync/index.yaml +280 -0
- package/compliance/cache/3.0.0/specialisms/brand-rights/index.yaml +346 -0
- package/compliance/cache/3.0.0/specialisms/brand-rights/scenarios/governance_denied.yaml +203 -0
- package/compliance/cache/3.0.0/specialisms/collection-lists/index.yaml +359 -0
- package/compliance/cache/3.0.0/specialisms/content-standards/index.yaml +572 -0
- package/compliance/cache/3.0.0/specialisms/creative-ad-server/index.yaml +383 -0
- package/compliance/cache/3.0.0/specialisms/creative-generative/generative-seller.yaml +733 -0
- package/compliance/cache/3.0.0/specialisms/creative-generative/index.yaml +746 -0
- package/compliance/cache/3.0.0/specialisms/creative-template/index.yaml +413 -0
- package/compliance/cache/3.0.0/specialisms/governance-aware-seller/index.yaml +99 -0
- package/compliance/cache/3.0.0/specialisms/governance-delivery-monitor/index.yaml +419 -0
- package/compliance/cache/3.0.0/specialisms/governance-spend-authority/denied.yaml +221 -0
- package/compliance/cache/3.0.0/specialisms/governance-spend-authority/index.yaml +330 -0
- package/compliance/cache/3.0.0/specialisms/property-lists/index.yaml +482 -0
- package/compliance/cache/3.0.0/specialisms/sales-broadcast-tv/index.yaml +664 -0
- package/compliance/cache/3.0.0/specialisms/sales-catalog-driven/index.yaml +779 -0
- package/compliance/cache/3.0.0/specialisms/sales-guaranteed/index.yaml +479 -0
- package/compliance/cache/3.0.0/specialisms/sales-non-guaranteed/index.yaml +428 -0
- package/compliance/cache/3.0.0/specialisms/sales-proposal-mode/index.yaml +520 -0
- package/compliance/cache/3.0.0/specialisms/sales-social/index.yaml +521 -0
- package/compliance/cache/3.0.0/specialisms/signal-marketplace/index.yaml +415 -0
- package/compliance/cache/3.0.0/specialisms/signal-marketplace/scenarios/governance_denied.yaml +195 -0
- package/compliance/cache/3.0.0/specialisms/signal-owned/index.yaml +316 -0
- package/compliance/cache/3.0.0/specialisms/signed-requests/index.yaml +192 -0
- package/compliance/cache/3.0.0/test-kits/acme-outdoor.yaml +210 -0
- package/compliance/cache/3.0.0/test-kits/bistro-oranje.yaml +126 -0
- package/compliance/cache/3.0.0/test-kits/nova-motors.yaml +262 -0
- package/compliance/cache/3.0.0/test-kits/osei-natural.yaml +126 -0
- package/compliance/cache/3.0.0/test-kits/signed-requests-runner.yaml +153 -0
- package/compliance/cache/3.0.0/test-kits/substitution-observer-runner.yaml +690 -0
- package/compliance/cache/3.0.0/test-kits/summit-foods.yaml +125 -0
- package/compliance/cache/3.0.0/test-kits/webhook-receiver-runner.yaml +265 -0
- package/compliance/cache/3.0.0/test-vectors/plan-hash/001-minimal-plan.json +43 -0
- package/compliance/cache/3.0.0/test-vectors/plan-hash/002-full-plan.json +217 -0
- package/compliance/cache/3.0.0/test-vectors/plan-hash/003-bookkeeping-stripped.json +60 -0
- package/compliance/cache/3.0.0/test-vectors/plan-hash/004a-human-review-omitted.json +43 -0
- package/compliance/cache/3.0.0/test-vectors/plan-hash/004b-human-review-explicit-null.json +49 -0
- package/compliance/cache/3.0.0/test-vectors/plan-hash/005a-policy-categories-order-1.json +53 -0
- package/compliance/cache/3.0.0/test-vectors/plan-hash/005b-policy-categories-order-2.json +57 -0
- package/compliance/cache/3.0.0/test-vectors/plan-hash/006a-ext-trace-v1.json +49 -0
- package/compliance/cache/3.0.0/test-vectors/plan-hash/006b-ext-trace-v2.json +53 -0
- package/compliance/cache/3.0.0/test-vectors/plan-hash/007-unicode-objectives.json +43 -0
- package/compliance/cache/3.0.0/test-vectors/plan-hash/008-numeric-canonicalization.json +65 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/README.md +219 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/canonicalization.json +241 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/keys.json +60 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/001-no-signature-header.json +24 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/002-wrong-tag.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/003-expired-signature.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/004-window-too-long.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/005-alg-not-allowed.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/006-missing-covered-component.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/007-missing-content-digest.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/008-unknown-keyid.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/009-key-ops-missing-verify.json +27 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/010-content-digest-mismatch.json +33 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/011-malformed-header.json +27 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/012-missing-expires-param.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/013-expires-le-created.json +27 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/014-missing-nonce-param.json +27 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/015-signature-invalid.json +28 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/016-replayed-nonce.json +35 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/017-key-revoked.json +38 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/018-digest-covered-when-forbidden.json +28 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/019-signature-without-signature-input.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/020-rate-abuse.json +34 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/021-duplicate-signature-input-label.json +31 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/022-multi-valued-content-type.json +31 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/023-multi-valued-content-digest.json +32 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/024-unquoted-string-param.json +31 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/025-jwk-alg-crv-mismatch.json +43 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/026-non-ascii-host.json +31 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/negative/027-webhook-registration-authentication-unsigned.json +25 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/positive/001-basic-post.json +30 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/positive/002-post-with-content-digest.json +31 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/positive/003-es256-post.json +30 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/positive/004-multiple-signature-labels.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/positive/005-default-port-stripped.json +30 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/positive/006-dot-segment-path.json +30 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/positive/007-query-byte-preserved.json +30 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/positive/008-percent-encoded-path.json +30 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/positive/009-percent-encoded-unreserved-decoded.json +30 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/positive/010-percent-encoded-slash-preserved.json +30 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/positive/011-ipv6-authority.json +30 -0
- package/compliance/cache/3.0.0/test-vectors/request-signing/positive/012-ipv6-authority-default-port-stripped.json +30 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/README.md +211 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/keys.json +61 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/001-wrong-tag.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/002-expired-signature.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/003-window-too-long.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/004-alg-not-allowed.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/005-missing-authority-component.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/006-missing-content-digest.json +25 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/007-unknown-keyid.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/008-wrong-adcp-use.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/009-content-digest-mismatch.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/010-malformed-signature-input.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/011-signature-without-input.json +25 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/012-missing-expires-param.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/013-expires-le-created.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/014-missing-nonce-param.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/015-signature-invalid.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/016-replayed-nonce.json +37 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/017-key-revoked.json +32 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/018-rate-abuse.json +33 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/019-revocation-stale.json +32 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/020-key-ops-missing-verify.json +41 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/negative/021-base64-alphabet-mixing.json +26 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/positive/001-basic-post.json +24 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/positive/002-es256-post.json +24 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/positive/003-multiple-signature-labels.json +24 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/positive/004-default-port-stripped.json +24 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/positive/005-percent-encoded-path.json +24 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/positive/006-query-byte-preserved.json +24 -0
- package/compliance/cache/3.0.0/test-vectors/webhook-signing/positive/007-body-without-idempotency-key.json +25 -0
- package/compliance/cache/3.0.0/universal/capability-discovery.yaml +125 -0
- package/compliance/cache/3.0.0/universal/deterministic-testing.yaml +1318 -0
- package/compliance/cache/3.0.0/universal/error-compliance.yaml +468 -0
- package/compliance/cache/3.0.0/universal/fictional-entities.yaml +307 -0
- package/compliance/cache/3.0.0/universal/idempotency.yaml +577 -0
- package/compliance/cache/3.0.0/universal/runner-output-contract.yaml +335 -0
- package/compliance/cache/3.0.0/universal/schema-validation.yaml +514 -0
- package/compliance/cache/3.0.0/universal/security.yaml +428 -0
- package/compliance/cache/3.0.0/universal/storyboard-schema.yaml +1010 -0
- package/compliance/cache/3.0.0/universal/webhook-emission.yaml +337 -0
- package/compliance/cache/3.0.0.previous/domains/brand/index.yaml +167 -0
- package/compliance/cache/3.0.0.previous/domains/creative/index.yaml +412 -0
- package/compliance/cache/3.0.0.previous/domains/governance/index.yaml +683 -0
- package/compliance/cache/3.0.0.previous/domains/media-buy/creative-reception.yaml +247 -0
- package/compliance/cache/3.0.0.previous/domains/media-buy/index.yaml +742 -0
- package/compliance/cache/3.0.0.previous/domains/media-buy/scenarios/creative_fate_after_cancellation.yaml +414 -0
- package/compliance/cache/3.0.0.previous/domains/media-buy/scenarios/delivery_reporting.yaml +180 -0
- package/compliance/cache/3.0.0.previous/domains/media-buy/scenarios/governance_approved.yaml +186 -0
- package/compliance/cache/3.0.0.previous/domains/media-buy/scenarios/governance_conditions.yaml +195 -0
- package/compliance/cache/3.0.0.previous/domains/media-buy/scenarios/governance_denied.yaml +189 -0
- package/compliance/cache/3.0.0.previous/domains/media-buy/scenarios/governance_denied_recovery.yaml +243 -0
- package/compliance/cache/3.0.0.previous/domains/media-buy/scenarios/invalid_transitions.yaml +279 -0
- package/compliance/cache/3.0.0.previous/domains/media-buy/scenarios/inventory_list_no_match.yaml +143 -0
- package/compliance/cache/3.0.0.previous/domains/media-buy/scenarios/inventory_list_targeting.yaml +266 -0
- package/compliance/cache/3.0.0.previous/domains/media-buy/scenarios/measurement_terms_rejected.yaml +194 -0
- package/compliance/cache/3.0.0.previous/domains/media-buy/scenarios/pending_creatives_to_start.yaml +250 -0
- package/compliance/cache/3.0.0.previous/domains/media-buy/scenarios/proposal_finalize.yaml +242 -0
- package/compliance/cache/3.0.0.previous/domains/media-buy/scenarios/refine_products.yaml +148 -0
- package/compliance/cache/3.0.0.previous/domains/media-buy/state-machine.yaml +437 -0
- package/compliance/cache/3.0.0.previous/domains/signals/index.yaml +266 -0
- package/compliance/cache/3.0.0.previous/domains/sponsored-intelligence/index.yaml +256 -0
- package/compliance/cache/3.0.0.previous/index.json +324 -0
- package/compliance/cache/3.0.0.previous/protocols/brand/index.yaml +167 -0
- package/compliance/cache/3.0.0.previous/protocols/creative/index.yaml +412 -0
- package/compliance/cache/3.0.0.previous/protocols/governance/index.yaml +683 -0
- package/compliance/cache/3.0.0.previous/protocols/media-buy/creative-reception.yaml +247 -0
- package/compliance/cache/3.0.0.previous/protocols/media-buy/index.yaml +742 -0
- package/compliance/cache/3.0.0.previous/protocols/media-buy/scenarios/creative_fate_after_cancellation.yaml +414 -0
- package/compliance/cache/3.0.0.previous/protocols/media-buy/scenarios/delivery_reporting.yaml +180 -0
- package/compliance/cache/3.0.0.previous/protocols/media-buy/scenarios/governance_approved.yaml +186 -0
- package/compliance/cache/3.0.0.previous/protocols/media-buy/scenarios/governance_conditions.yaml +195 -0
- package/compliance/cache/3.0.0.previous/protocols/media-buy/scenarios/governance_denied.yaml +189 -0
- package/compliance/cache/3.0.0.previous/protocols/media-buy/scenarios/governance_denied_recovery.yaml +243 -0
- package/compliance/cache/3.0.0.previous/protocols/media-buy/scenarios/invalid_transitions.yaml +279 -0
- package/compliance/cache/3.0.0.previous/protocols/media-buy/scenarios/inventory_list_no_match.yaml +143 -0
- package/compliance/cache/3.0.0.previous/protocols/media-buy/scenarios/inventory_list_targeting.yaml +266 -0
- package/compliance/cache/3.0.0.previous/protocols/media-buy/scenarios/measurement_terms_rejected.yaml +194 -0
- package/compliance/cache/3.0.0.previous/protocols/media-buy/scenarios/pending_creatives_to_start.yaml +250 -0
- package/compliance/cache/3.0.0.previous/protocols/media-buy/scenarios/proposal_finalize.yaml +242 -0
- package/compliance/cache/3.0.0.previous/protocols/media-buy/scenarios/refine_products.yaml +148 -0
- package/compliance/cache/3.0.0.previous/protocols/media-buy/state-machine.yaml +437 -0
- package/compliance/cache/3.0.0.previous/protocols/signals/index.yaml +266 -0
- package/compliance/cache/3.0.0.previous/protocols/sponsored-intelligence/index.yaml +256 -0
- package/compliance/cache/3.0.0.previous/specialisms/audience-sync/index.yaml +280 -0
- package/compliance/cache/3.0.0.previous/specialisms/brand-rights/index.yaml +346 -0
- package/compliance/cache/3.0.0.previous/specialisms/brand-rights/scenarios/governance_denied.yaml +203 -0
- package/compliance/cache/3.0.0.previous/specialisms/collection-lists/index.yaml +359 -0
- package/compliance/cache/3.0.0.previous/specialisms/content-standards/index.yaml +572 -0
- package/compliance/cache/3.0.0.previous/specialisms/creative-ad-server/index.yaml +383 -0
- package/compliance/cache/3.0.0.previous/specialisms/creative-generative/generative-seller.yaml +733 -0
- package/compliance/cache/3.0.0.previous/specialisms/creative-generative/index.yaml +746 -0
- package/compliance/cache/3.0.0.previous/specialisms/creative-template/index.yaml +413 -0
- package/compliance/cache/3.0.0.previous/specialisms/governance-aware-seller/index.yaml +99 -0
- package/compliance/cache/3.0.0.previous/specialisms/governance-delivery-monitor/index.yaml +419 -0
- package/compliance/cache/3.0.0.previous/specialisms/governance-spend-authority/denied.yaml +221 -0
- package/compliance/cache/3.0.0.previous/specialisms/governance-spend-authority/index.yaml +330 -0
- package/compliance/cache/3.0.0.previous/specialisms/property-lists/index.yaml +482 -0
- package/compliance/cache/3.0.0.previous/specialisms/sales-broadcast-tv/index.yaml +664 -0
- package/compliance/cache/3.0.0.previous/specialisms/sales-catalog-driven/index.yaml +779 -0
- package/compliance/cache/3.0.0.previous/specialisms/sales-guaranteed/index.yaml +479 -0
- package/compliance/cache/3.0.0.previous/specialisms/sales-non-guaranteed/index.yaml +428 -0
- package/compliance/cache/3.0.0.previous/specialisms/sales-proposal-mode/index.yaml +520 -0
- package/compliance/cache/3.0.0.previous/specialisms/sales-social/index.yaml +521 -0
- package/compliance/cache/3.0.0.previous/specialisms/signal-marketplace/index.yaml +415 -0
- package/compliance/cache/3.0.0.previous/specialisms/signal-marketplace/scenarios/governance_denied.yaml +195 -0
- package/compliance/cache/3.0.0.previous/specialisms/signal-owned/index.yaml +316 -0
- package/compliance/cache/3.0.0.previous/specialisms/signed-requests/index.yaml +192 -0
- package/compliance/cache/3.0.0.previous/test-kits/acme-outdoor.yaml +210 -0
- package/compliance/cache/3.0.0.previous/test-kits/bistro-oranje.yaml +126 -0
- package/compliance/cache/3.0.0.previous/test-kits/nova-motors.yaml +262 -0
- package/compliance/cache/3.0.0.previous/test-kits/osei-natural.yaml +126 -0
- package/compliance/cache/3.0.0.previous/test-kits/signed-requests-runner.yaml +153 -0
- package/compliance/cache/3.0.0.previous/test-kits/substitution-observer-runner.yaml +690 -0
- package/compliance/cache/3.0.0.previous/test-kits/summit-foods.yaml +125 -0
- package/compliance/cache/3.0.0.previous/test-kits/webhook-receiver-runner.yaml +265 -0
- package/compliance/cache/3.0.0.previous/test-vectors/plan-hash/001-minimal-plan.json +43 -0
- package/compliance/cache/3.0.0.previous/test-vectors/plan-hash/002-full-plan.json +217 -0
- package/compliance/cache/3.0.0.previous/test-vectors/plan-hash/003-bookkeeping-stripped.json +60 -0
- package/compliance/cache/3.0.0.previous/test-vectors/plan-hash/004a-human-review-omitted.json +43 -0
- package/compliance/cache/3.0.0.previous/test-vectors/plan-hash/004b-human-review-explicit-null.json +49 -0
- package/compliance/cache/3.0.0.previous/test-vectors/plan-hash/005a-policy-categories-order-1.json +53 -0
- package/compliance/cache/3.0.0.previous/test-vectors/plan-hash/005b-policy-categories-order-2.json +57 -0
- package/compliance/cache/3.0.0.previous/test-vectors/plan-hash/006a-ext-trace-v1.json +49 -0
- package/compliance/cache/3.0.0.previous/test-vectors/plan-hash/006b-ext-trace-v2.json +53 -0
- package/compliance/cache/3.0.0.previous/test-vectors/plan-hash/007-unicode-objectives.json +43 -0
- package/compliance/cache/3.0.0.previous/test-vectors/plan-hash/008-numeric-canonicalization.json +65 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/README.md +219 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/canonicalization.json +241 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/keys.json +60 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/001-no-signature-header.json +24 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/002-wrong-tag.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/003-expired-signature.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/004-window-too-long.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/005-alg-not-allowed.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/006-missing-covered-component.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/007-missing-content-digest.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/008-unknown-keyid.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/009-key-ops-missing-verify.json +27 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/010-content-digest-mismatch.json +33 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/011-malformed-header.json +27 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/012-missing-expires-param.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/013-expires-le-created.json +27 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/014-missing-nonce-param.json +27 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/015-signature-invalid.json +28 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/016-replayed-nonce.json +35 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/017-key-revoked.json +38 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/018-digest-covered-when-forbidden.json +28 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/019-signature-without-signature-input.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/020-rate-abuse.json +34 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/021-duplicate-signature-input-label.json +31 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/022-multi-valued-content-type.json +31 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/023-multi-valued-content-digest.json +32 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/024-unquoted-string-param.json +31 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/025-jwk-alg-crv-mismatch.json +43 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/026-non-ascii-host.json +31 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/negative/027-webhook-registration-authentication-unsigned.json +25 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/positive/001-basic-post.json +30 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/positive/002-post-with-content-digest.json +31 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/positive/003-es256-post.json +30 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/positive/004-multiple-signature-labels.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/positive/005-default-port-stripped.json +30 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/positive/006-dot-segment-path.json +30 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/positive/007-query-byte-preserved.json +30 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/positive/008-percent-encoded-path.json +30 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/positive/009-percent-encoded-unreserved-decoded.json +30 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/positive/010-percent-encoded-slash-preserved.json +30 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/positive/011-ipv6-authority.json +30 -0
- package/compliance/cache/3.0.0.previous/test-vectors/request-signing/positive/012-ipv6-authority-default-port-stripped.json +30 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/README.md +211 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/keys.json +61 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/001-wrong-tag.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/002-expired-signature.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/003-window-too-long.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/004-alg-not-allowed.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/005-missing-authority-component.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/006-missing-content-digest.json +25 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/007-unknown-keyid.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/008-wrong-adcp-use.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/009-content-digest-mismatch.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/010-malformed-signature-input.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/011-signature-without-input.json +25 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/012-missing-expires-param.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/013-expires-le-created.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/014-missing-nonce-param.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/015-signature-invalid.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/016-replayed-nonce.json +37 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/017-key-revoked.json +32 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/018-rate-abuse.json +33 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/019-revocation-stale.json +32 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/020-key-ops-missing-verify.json +41 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/negative/021-base64-alphabet-mixing.json +26 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/positive/001-basic-post.json +24 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/positive/002-es256-post.json +24 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/positive/003-multiple-signature-labels.json +24 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/positive/004-default-port-stripped.json +24 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/positive/005-percent-encoded-path.json +24 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/positive/006-query-byte-preserved.json +24 -0
- package/compliance/cache/3.0.0.previous/test-vectors/webhook-signing/positive/007-body-without-idempotency-key.json +25 -0
- package/compliance/cache/3.0.0.previous/universal/capability-discovery.yaml +125 -0
- package/compliance/cache/3.0.0.previous/universal/deterministic-testing.yaml +1318 -0
- package/compliance/cache/3.0.0.previous/universal/error-compliance.yaml +468 -0
- package/compliance/cache/3.0.0.previous/universal/fictional-entities.yaml +307 -0
- package/compliance/cache/3.0.0.previous/universal/idempotency.yaml +577 -0
- package/compliance/cache/3.0.0.previous/universal/runner-output-contract.yaml +335 -0
- package/compliance/cache/3.0.0.previous/universal/schema-validation.yaml +514 -0
- package/compliance/cache/3.0.0.previous/universal/security.yaml +428 -0
- package/compliance/cache/3.0.0.previous/universal/storyboard-schema.yaml +1010 -0
- package/compliance/cache/3.0.0.previous/universal/webhook-emission.yaml +337 -0
- package/compliance/cache/3.0.1/domains/brand/index.yaml +163 -0
- package/compliance/cache/3.0.1/domains/creative/index.yaml +412 -0
- package/compliance/cache/3.0.1/domains/governance/index.yaml +683 -0
- package/compliance/cache/3.0.1/domains/media-buy/creative-reception.yaml +247 -0
- package/compliance/cache/3.0.1/domains/media-buy/index.yaml +769 -0
- package/compliance/cache/3.0.1/domains/media-buy/scenarios/create_media_buy_async.yaml +232 -0
- package/compliance/cache/3.0.1/domains/media-buy/scenarios/creative_fate_after_cancellation.yaml +414 -0
- package/compliance/cache/3.0.1/domains/media-buy/scenarios/delivery_reporting.yaml +205 -0
- package/compliance/cache/3.0.1/domains/media-buy/scenarios/governance_approved.yaml +211 -0
- package/compliance/cache/3.0.1/domains/media-buy/scenarios/governance_conditions.yaml +196 -0
- package/compliance/cache/3.0.1/domains/media-buy/scenarios/governance_denied.yaml +192 -0
- package/compliance/cache/3.0.1/domains/media-buy/scenarios/governance_denied_recovery.yaml +244 -0
- package/compliance/cache/3.0.1/domains/media-buy/scenarios/invalid_transitions.yaml +284 -0
- package/compliance/cache/3.0.1/domains/media-buy/scenarios/inventory_list_no_match.yaml +143 -0
- package/compliance/cache/3.0.1/domains/media-buy/scenarios/inventory_list_targeting.yaml +266 -0
- package/compliance/cache/3.0.1/domains/media-buy/scenarios/measurement_terms_rejected.yaml +195 -0
- package/compliance/cache/3.0.1/domains/media-buy/scenarios/pending_creatives_to_start.yaml +250 -0
- package/compliance/cache/3.0.1/domains/media-buy/scenarios/proposal_finalize.yaml +243 -0
- package/compliance/cache/3.0.1/domains/media-buy/scenarios/refine_products.yaml +148 -0
- package/compliance/cache/3.0.1/domains/media-buy/state-machine.yaml +442 -0
- package/compliance/cache/3.0.1/domains/signals/index.yaml +266 -0
- package/compliance/cache/3.0.1/domains/sponsored-intelligence/index.yaml +256 -0
- package/compliance/cache/3.0.1/index.json +324 -0
- package/compliance/cache/3.0.1/protocols/brand/index.yaml +163 -0
- package/compliance/cache/3.0.1/protocols/creative/index.yaml +412 -0
- package/compliance/cache/3.0.1/protocols/governance/index.yaml +683 -0
- package/compliance/cache/3.0.1/protocols/media-buy/creative-reception.yaml +247 -0
- package/compliance/cache/3.0.1/protocols/media-buy/index.yaml +769 -0
- package/compliance/cache/3.0.1/protocols/media-buy/scenarios/create_media_buy_async.yaml +232 -0
- package/compliance/cache/3.0.1/protocols/media-buy/scenarios/creative_fate_after_cancellation.yaml +414 -0
- package/compliance/cache/3.0.1/protocols/media-buy/scenarios/delivery_reporting.yaml +205 -0
- package/compliance/cache/3.0.1/protocols/media-buy/scenarios/governance_approved.yaml +211 -0
- package/compliance/cache/3.0.1/protocols/media-buy/scenarios/governance_conditions.yaml +196 -0
- package/compliance/cache/3.0.1/protocols/media-buy/scenarios/governance_denied.yaml +192 -0
- package/compliance/cache/3.0.1/protocols/media-buy/scenarios/governance_denied_recovery.yaml +244 -0
- package/compliance/cache/3.0.1/protocols/media-buy/scenarios/invalid_transitions.yaml +284 -0
- package/compliance/cache/3.0.1/protocols/media-buy/scenarios/inventory_list_no_match.yaml +143 -0
- package/compliance/cache/3.0.1/protocols/media-buy/scenarios/inventory_list_targeting.yaml +266 -0
- package/compliance/cache/3.0.1/protocols/media-buy/scenarios/measurement_terms_rejected.yaml +195 -0
- package/compliance/cache/3.0.1/protocols/media-buy/scenarios/pending_creatives_to_start.yaml +250 -0
- package/compliance/cache/3.0.1/protocols/media-buy/scenarios/proposal_finalize.yaml +243 -0
- package/compliance/cache/3.0.1/protocols/media-buy/scenarios/refine_products.yaml +148 -0
- package/compliance/cache/3.0.1/protocols/media-buy/state-machine.yaml +442 -0
- package/compliance/cache/3.0.1/protocols/signals/index.yaml +266 -0
- package/compliance/cache/3.0.1/protocols/sponsored-intelligence/index.yaml +256 -0
- package/compliance/cache/3.0.1/specialisms/audience-sync/index.yaml +280 -0
- package/compliance/cache/3.0.1/specialisms/brand-rights/index.yaml +350 -0
- package/compliance/cache/3.0.1/specialisms/brand-rights/scenarios/governance_denied.yaml +204 -0
- package/compliance/cache/3.0.1/specialisms/collection-lists/index.yaml +359 -0
- package/compliance/cache/3.0.1/specialisms/content-standards/index.yaml +572 -0
- package/compliance/cache/3.0.1/specialisms/creative-ad-server/index.yaml +383 -0
- package/compliance/cache/3.0.1/specialisms/creative-generative/generative-seller.yaml +758 -0
- package/compliance/cache/3.0.1/specialisms/creative-generative/index.yaml +746 -0
- package/compliance/cache/3.0.1/specialisms/creative-template/index.yaml +413 -0
- package/compliance/cache/3.0.1/specialisms/governance-aware-seller/index.yaml +136 -0
- package/compliance/cache/3.0.1/specialisms/governance-delivery-monitor/index.yaml +441 -0
- package/compliance/cache/3.0.1/specialisms/governance-spend-authority/denied.yaml +221 -0
- package/compliance/cache/3.0.1/specialisms/governance-spend-authority/index.yaml +330 -0
- package/compliance/cache/3.0.1/specialisms/property-lists/index.yaml +482 -0
- package/compliance/cache/3.0.1/specialisms/sales-broadcast-tv/index.yaml +689 -0
- package/compliance/cache/3.0.1/specialisms/sales-catalog-driven/index.yaml +779 -0
- package/compliance/cache/3.0.1/specialisms/sales-guaranteed/index.yaml +504 -0
- package/compliance/cache/3.0.1/specialisms/sales-non-guaranteed/index.yaml +428 -0
- package/compliance/cache/3.0.1/specialisms/sales-proposal-mode/index.yaml +520 -0
- package/compliance/cache/3.0.1/specialisms/sales-social/index.yaml +577 -0
- package/compliance/cache/3.0.1/specialisms/signal-marketplace/index.yaml +415 -0
- package/compliance/cache/3.0.1/specialisms/signal-marketplace/scenarios/governance_denied.yaml +207 -0
- package/compliance/cache/3.0.1/specialisms/signal-owned/index.yaml +316 -0
- package/compliance/cache/3.0.1/test-kits/acme-outdoor.yaml +210 -0
- package/compliance/cache/3.0.1/test-kits/bistro-oranje.yaml +126 -0
- package/compliance/cache/3.0.1/test-kits/nova-motors.yaml +262 -0
- package/compliance/cache/3.0.1/test-kits/osei-natural.yaml +126 -0
- package/compliance/cache/3.0.1/test-kits/signed-requests-runner.yaml +155 -0
- package/compliance/cache/3.0.1/test-kits/substitution-observer-runner.yaml +690 -0
- package/compliance/cache/3.0.1/test-kits/summit-foods.yaml +125 -0
- package/compliance/cache/3.0.1/test-kits/webhook-receiver-runner.yaml +265 -0
- package/compliance/cache/3.0.1/test-vectors/plan-hash/001-minimal-plan.json +43 -0
- package/compliance/cache/3.0.1/test-vectors/plan-hash/002-full-plan.json +217 -0
- package/compliance/cache/3.0.1/test-vectors/plan-hash/003-bookkeeping-stripped.json +60 -0
- package/compliance/cache/3.0.1/test-vectors/plan-hash/004a-human-review-omitted.json +43 -0
- package/compliance/cache/3.0.1/test-vectors/plan-hash/004b-human-review-explicit-null.json +49 -0
- package/compliance/cache/3.0.1/test-vectors/plan-hash/005a-policy-categories-order-1.json +53 -0
- package/compliance/cache/3.0.1/test-vectors/plan-hash/005b-policy-categories-order-2.json +57 -0
- package/compliance/cache/3.0.1/test-vectors/plan-hash/006a-ext-trace-v1.json +49 -0
- package/compliance/cache/3.0.1/test-vectors/plan-hash/006b-ext-trace-v2.json +53 -0
- package/compliance/cache/3.0.1/test-vectors/plan-hash/007-unicode-objectives.json +43 -0
- package/compliance/cache/3.0.1/test-vectors/plan-hash/008-numeric-canonicalization.json +65 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/README.md +219 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/canonicalization.json +241 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/keys.json +60 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/001-no-signature-header.json +24 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/002-wrong-tag.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/003-expired-signature.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/004-window-too-long.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/005-alg-not-allowed.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/006-missing-covered-component.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/007-missing-content-digest.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/008-unknown-keyid.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/009-key-ops-missing-verify.json +27 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/010-content-digest-mismatch.json +33 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/011-malformed-header.json +27 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/012-missing-expires-param.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/013-expires-le-created.json +27 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/014-missing-nonce-param.json +27 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/015-signature-invalid.json +28 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/016-replayed-nonce.json +35 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/017-key-revoked.json +38 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/018-digest-covered-when-forbidden.json +28 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/019-signature-without-signature-input.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/020-rate-abuse.json +34 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/021-duplicate-signature-input-label.json +31 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/022-multi-valued-content-type.json +31 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/023-multi-valued-content-digest.json +32 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/024-unquoted-string-param.json +31 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/025-jwk-alg-crv-mismatch.json +43 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/026-non-ascii-host.json +31 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/negative/027-webhook-registration-authentication-unsigned.json +25 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/positive/001-basic-post.json +30 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/positive/002-post-with-content-digest.json +31 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/positive/003-es256-post.json +30 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/positive/004-multiple-signature-labels.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/positive/005-default-port-stripped.json +30 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/positive/006-dot-segment-path.json +30 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/positive/007-query-byte-preserved.json +30 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/positive/008-percent-encoded-path.json +30 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/positive/009-percent-encoded-unreserved-decoded.json +30 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/positive/010-percent-encoded-slash-preserved.json +30 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/positive/011-ipv6-authority.json +30 -0
- package/compliance/cache/3.0.1/test-vectors/request-signing/positive/012-ipv6-authority-default-port-stripped.json +30 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/README.md +211 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/keys.json +61 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/001-wrong-tag.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/002-expired-signature.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/003-window-too-long.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/004-alg-not-allowed.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/005-missing-authority-component.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/006-missing-content-digest.json +25 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/007-unknown-keyid.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/008-wrong-adcp-use.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/009-content-digest-mismatch.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/010-malformed-signature-input.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/011-signature-without-input.json +25 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/012-missing-expires-param.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/013-expires-le-created.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/014-missing-nonce-param.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/015-signature-invalid.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/016-replayed-nonce.json +37 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/017-key-revoked.json +32 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/018-rate-abuse.json +33 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/019-revocation-stale.json +32 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/020-key-ops-missing-verify.json +41 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/negative/021-base64-alphabet-mixing.json +26 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/positive/001-basic-post.json +24 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/positive/002-es256-post.json +24 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/positive/003-multiple-signature-labels.json +24 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/positive/004-default-port-stripped.json +24 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/positive/005-percent-encoded-path.json +24 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/positive/006-query-byte-preserved.json +24 -0
- package/compliance/cache/3.0.1/test-vectors/webhook-signing/positive/007-body-without-idempotency-key.json +25 -0
- package/compliance/cache/3.0.1/universal/capability-discovery.yaml +125 -0
- package/compliance/cache/3.0.1/universal/collection-lists-pagination-integrity.yaml +306 -0
- package/compliance/cache/3.0.1/universal/content-standards-pagination-integrity.yaml +326 -0
- package/compliance/cache/3.0.1/universal/deterministic-testing.yaml +1343 -0
- package/compliance/cache/3.0.1/universal/error-compliance.yaml +474 -0
- package/compliance/cache/3.0.1/universal/fictional-entities.yaml +307 -0
- package/compliance/cache/3.0.1/universal/get-media-buys-pagination-integrity.yaml +160 -0
- package/compliance/cache/3.0.1/universal/get-signals-pagination-integrity.yaml +211 -0
- package/compliance/cache/3.0.1/universal/idempotency.yaml +593 -0
- package/compliance/cache/3.0.1/universal/pagination-integrity-creative-formats.yaml +258 -0
- package/compliance/cache/3.0.1/universal/pagination-integrity-list-accounts.yaml +262 -0
- package/compliance/cache/3.0.1/universal/pagination-integrity.yaml +263 -0
- package/compliance/cache/3.0.1/universal/property-lists-pagination-integrity.yaml +307 -0
- package/compliance/cache/3.0.1/universal/runner-output-contract.yaml +339 -0
- package/compliance/cache/3.0.1/universal/schema-validation.yaml +526 -0
- package/compliance/cache/3.0.1/universal/security.yaml +431 -0
- package/compliance/cache/3.0.1/universal/signed-requests.yaml +205 -0
- package/compliance/cache/3.0.1/universal/storyboard-schema.yaml +1056 -0
- package/compliance/cache/3.0.1/universal/v3-envelope-integrity.yaml +104 -0
- package/compliance/cache/3.0.1/universal/webhook-emission.yaml +337 -0
- package/compliance/cache/3.0.1.previous/domains/brand/index.yaml +163 -0
- package/compliance/cache/3.0.1.previous/domains/creative/index.yaml +412 -0
- package/compliance/cache/3.0.1.previous/domains/governance/index.yaml +683 -0
- package/compliance/cache/3.0.1.previous/domains/media-buy/creative-reception.yaml +247 -0
- package/compliance/cache/3.0.1.previous/domains/media-buy/index.yaml +769 -0
- package/compliance/cache/3.0.1.previous/domains/media-buy/scenarios/create_media_buy_async.yaml +232 -0
- package/compliance/cache/3.0.1.previous/domains/media-buy/scenarios/creative_fate_after_cancellation.yaml +414 -0
- package/compliance/cache/3.0.1.previous/domains/media-buy/scenarios/delivery_reporting.yaml +205 -0
- package/compliance/cache/3.0.1.previous/domains/media-buy/scenarios/governance_approved.yaml +211 -0
- package/compliance/cache/3.0.1.previous/domains/media-buy/scenarios/governance_conditions.yaml +196 -0
- package/compliance/cache/3.0.1.previous/domains/media-buy/scenarios/governance_denied.yaml +192 -0
- package/compliance/cache/3.0.1.previous/domains/media-buy/scenarios/governance_denied_recovery.yaml +244 -0
- package/compliance/cache/3.0.1.previous/domains/media-buy/scenarios/invalid_transitions.yaml +284 -0
- package/compliance/cache/3.0.1.previous/domains/media-buy/scenarios/inventory_list_no_match.yaml +143 -0
- package/compliance/cache/3.0.1.previous/domains/media-buy/scenarios/inventory_list_targeting.yaml +266 -0
- package/compliance/cache/3.0.1.previous/domains/media-buy/scenarios/measurement_terms_rejected.yaml +195 -0
- package/compliance/cache/3.0.1.previous/domains/media-buy/scenarios/pending_creatives_to_start.yaml +250 -0
- package/compliance/cache/3.0.1.previous/domains/media-buy/scenarios/proposal_finalize.yaml +243 -0
- package/compliance/cache/3.0.1.previous/domains/media-buy/scenarios/refine_products.yaml +148 -0
- package/compliance/cache/3.0.1.previous/domains/media-buy/state-machine.yaml +442 -0
- package/compliance/cache/3.0.1.previous/domains/signals/index.yaml +266 -0
- package/compliance/cache/3.0.1.previous/domains/sponsored-intelligence/index.yaml +256 -0
- package/compliance/cache/3.0.1.previous/index.json +324 -0
- package/compliance/cache/3.0.1.previous/protocols/brand/index.yaml +163 -0
- package/compliance/cache/3.0.1.previous/protocols/creative/index.yaml +412 -0
- package/compliance/cache/3.0.1.previous/protocols/governance/index.yaml +683 -0
- package/compliance/cache/3.0.1.previous/protocols/media-buy/creative-reception.yaml +247 -0
- package/compliance/cache/3.0.1.previous/protocols/media-buy/index.yaml +769 -0
- package/compliance/cache/3.0.1.previous/protocols/media-buy/scenarios/create_media_buy_async.yaml +232 -0
- package/compliance/cache/3.0.1.previous/protocols/media-buy/scenarios/creative_fate_after_cancellation.yaml +414 -0
- package/compliance/cache/3.0.1.previous/protocols/media-buy/scenarios/delivery_reporting.yaml +205 -0
- package/compliance/cache/3.0.1.previous/protocols/media-buy/scenarios/governance_approved.yaml +211 -0
- package/compliance/cache/3.0.1.previous/protocols/media-buy/scenarios/governance_conditions.yaml +196 -0
- package/compliance/cache/3.0.1.previous/protocols/media-buy/scenarios/governance_denied.yaml +192 -0
- package/compliance/cache/3.0.1.previous/protocols/media-buy/scenarios/governance_denied_recovery.yaml +244 -0
- package/compliance/cache/3.0.1.previous/protocols/media-buy/scenarios/invalid_transitions.yaml +284 -0
- package/compliance/cache/3.0.1.previous/protocols/media-buy/scenarios/inventory_list_no_match.yaml +143 -0
- package/compliance/cache/3.0.1.previous/protocols/media-buy/scenarios/inventory_list_targeting.yaml +266 -0
- package/compliance/cache/3.0.1.previous/protocols/media-buy/scenarios/measurement_terms_rejected.yaml +195 -0
- package/compliance/cache/3.0.1.previous/protocols/media-buy/scenarios/pending_creatives_to_start.yaml +250 -0
- package/compliance/cache/3.0.1.previous/protocols/media-buy/scenarios/proposal_finalize.yaml +243 -0
- package/compliance/cache/3.0.1.previous/protocols/media-buy/scenarios/refine_products.yaml +148 -0
- package/compliance/cache/3.0.1.previous/protocols/media-buy/state-machine.yaml +442 -0
- package/compliance/cache/3.0.1.previous/protocols/signals/index.yaml +266 -0
- package/compliance/cache/3.0.1.previous/protocols/sponsored-intelligence/index.yaml +256 -0
- package/compliance/cache/3.0.1.previous/specialisms/audience-sync/index.yaml +280 -0
- package/compliance/cache/3.0.1.previous/specialisms/brand-rights/index.yaml +350 -0
- package/compliance/cache/3.0.1.previous/specialisms/brand-rights/scenarios/governance_denied.yaml +204 -0
- package/compliance/cache/3.0.1.previous/specialisms/collection-lists/index.yaml +359 -0
- package/compliance/cache/3.0.1.previous/specialisms/content-standards/index.yaml +572 -0
- package/compliance/cache/3.0.1.previous/specialisms/creative-ad-server/index.yaml +383 -0
- package/compliance/cache/3.0.1.previous/specialisms/creative-generative/generative-seller.yaml +758 -0
- package/compliance/cache/3.0.1.previous/specialisms/creative-generative/index.yaml +746 -0
- package/compliance/cache/3.0.1.previous/specialisms/creative-template/index.yaml +413 -0
- package/compliance/cache/3.0.1.previous/specialisms/governance-aware-seller/index.yaml +136 -0
- package/compliance/cache/3.0.1.previous/specialisms/governance-delivery-monitor/index.yaml +441 -0
- package/compliance/cache/3.0.1.previous/specialisms/governance-spend-authority/denied.yaml +221 -0
- package/compliance/cache/3.0.1.previous/specialisms/governance-spend-authority/index.yaml +330 -0
- package/compliance/cache/3.0.1.previous/specialisms/property-lists/index.yaml +482 -0
- package/compliance/cache/3.0.1.previous/specialisms/sales-broadcast-tv/index.yaml +689 -0
- package/compliance/cache/3.0.1.previous/specialisms/sales-catalog-driven/index.yaml +779 -0
- package/compliance/cache/3.0.1.previous/specialisms/sales-guaranteed/index.yaml +504 -0
- package/compliance/cache/3.0.1.previous/specialisms/sales-non-guaranteed/index.yaml +428 -0
- package/compliance/cache/3.0.1.previous/specialisms/sales-proposal-mode/index.yaml +520 -0
- package/compliance/cache/3.0.1.previous/specialisms/sales-social/index.yaml +577 -0
- package/compliance/cache/3.0.1.previous/specialisms/signal-marketplace/index.yaml +415 -0
- package/compliance/cache/3.0.1.previous/specialisms/signal-marketplace/scenarios/governance_denied.yaml +207 -0
- package/compliance/cache/3.0.1.previous/specialisms/signal-owned/index.yaml +316 -0
- package/compliance/cache/3.0.1.previous/test-kits/acme-outdoor.yaml +210 -0
- package/compliance/cache/3.0.1.previous/test-kits/bistro-oranje.yaml +126 -0
- package/compliance/cache/3.0.1.previous/test-kits/nova-motors.yaml +262 -0
- package/compliance/cache/3.0.1.previous/test-kits/osei-natural.yaml +126 -0
- package/compliance/cache/3.0.1.previous/test-kits/signed-requests-runner.yaml +155 -0
- package/compliance/cache/3.0.1.previous/test-kits/substitution-observer-runner.yaml +690 -0
- package/compliance/cache/3.0.1.previous/test-kits/summit-foods.yaml +125 -0
- package/compliance/cache/3.0.1.previous/test-kits/webhook-receiver-runner.yaml +265 -0
- package/compliance/cache/3.0.1.previous/test-vectors/plan-hash/001-minimal-plan.json +43 -0
- package/compliance/cache/3.0.1.previous/test-vectors/plan-hash/002-full-plan.json +217 -0
- package/compliance/cache/3.0.1.previous/test-vectors/plan-hash/003-bookkeeping-stripped.json +60 -0
- package/compliance/cache/3.0.1.previous/test-vectors/plan-hash/004a-human-review-omitted.json +43 -0
- package/compliance/cache/3.0.1.previous/test-vectors/plan-hash/004b-human-review-explicit-null.json +49 -0
- package/compliance/cache/3.0.1.previous/test-vectors/plan-hash/005a-policy-categories-order-1.json +53 -0
- package/compliance/cache/3.0.1.previous/test-vectors/plan-hash/005b-policy-categories-order-2.json +57 -0
- package/compliance/cache/3.0.1.previous/test-vectors/plan-hash/006a-ext-trace-v1.json +49 -0
- package/compliance/cache/3.0.1.previous/test-vectors/plan-hash/006b-ext-trace-v2.json +53 -0
- package/compliance/cache/3.0.1.previous/test-vectors/plan-hash/007-unicode-objectives.json +43 -0
- package/compliance/cache/3.0.1.previous/test-vectors/plan-hash/008-numeric-canonicalization.json +65 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/README.md +219 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/canonicalization.json +241 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/keys.json +60 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/001-no-signature-header.json +24 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/002-wrong-tag.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/003-expired-signature.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/004-window-too-long.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/005-alg-not-allowed.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/006-missing-covered-component.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/007-missing-content-digest.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/008-unknown-keyid.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/009-key-ops-missing-verify.json +27 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/010-content-digest-mismatch.json +33 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/011-malformed-header.json +27 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/012-missing-expires-param.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/013-expires-le-created.json +27 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/014-missing-nonce-param.json +27 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/015-signature-invalid.json +28 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/016-replayed-nonce.json +35 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/017-key-revoked.json +38 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/018-digest-covered-when-forbidden.json +28 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/019-signature-without-signature-input.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/020-rate-abuse.json +34 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/021-duplicate-signature-input-label.json +31 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/022-multi-valued-content-type.json +31 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/023-multi-valued-content-digest.json +32 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/024-unquoted-string-param.json +31 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/025-jwk-alg-crv-mismatch.json +43 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/026-non-ascii-host.json +31 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/negative/027-webhook-registration-authentication-unsigned.json +25 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/positive/001-basic-post.json +30 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/positive/002-post-with-content-digest.json +31 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/positive/003-es256-post.json +30 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/positive/004-multiple-signature-labels.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/positive/005-default-port-stripped.json +30 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/positive/006-dot-segment-path.json +30 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/positive/007-query-byte-preserved.json +30 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/positive/008-percent-encoded-path.json +30 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/positive/009-percent-encoded-unreserved-decoded.json +30 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/positive/010-percent-encoded-slash-preserved.json +30 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/positive/011-ipv6-authority.json +30 -0
- package/compliance/cache/3.0.1.previous/test-vectors/request-signing/positive/012-ipv6-authority-default-port-stripped.json +30 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/README.md +211 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/keys.json +61 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/001-wrong-tag.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/002-expired-signature.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/003-window-too-long.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/004-alg-not-allowed.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/005-missing-authority-component.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/006-missing-content-digest.json +25 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/007-unknown-keyid.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/008-wrong-adcp-use.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/009-content-digest-mismatch.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/010-malformed-signature-input.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/011-signature-without-input.json +25 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/012-missing-expires-param.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/013-expires-le-created.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/014-missing-nonce-param.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/015-signature-invalid.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/016-replayed-nonce.json +37 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/017-key-revoked.json +32 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/018-rate-abuse.json +33 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/019-revocation-stale.json +32 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/020-key-ops-missing-verify.json +41 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/negative/021-base64-alphabet-mixing.json +26 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/positive/001-basic-post.json +24 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/positive/002-es256-post.json +24 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/positive/003-multiple-signature-labels.json +24 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/positive/004-default-port-stripped.json +24 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/positive/005-percent-encoded-path.json +24 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/positive/006-query-byte-preserved.json +24 -0
- package/compliance/cache/3.0.1.previous/test-vectors/webhook-signing/positive/007-body-without-idempotency-key.json +25 -0
- package/compliance/cache/3.0.1.previous/universal/capability-discovery.yaml +125 -0
- package/compliance/cache/3.0.1.previous/universal/collection-lists-pagination-integrity.yaml +306 -0
- package/compliance/cache/3.0.1.previous/universal/content-standards-pagination-integrity.yaml +326 -0
- package/compliance/cache/3.0.1.previous/universal/deterministic-testing.yaml +1343 -0
- package/compliance/cache/3.0.1.previous/universal/error-compliance.yaml +474 -0
- package/compliance/cache/3.0.1.previous/universal/fictional-entities.yaml +307 -0
- package/compliance/cache/3.0.1.previous/universal/get-media-buys-pagination-integrity.yaml +160 -0
- package/compliance/cache/3.0.1.previous/universal/get-signals-pagination-integrity.yaml +211 -0
- package/compliance/cache/3.0.1.previous/universal/idempotency.yaml +593 -0
- package/compliance/cache/3.0.1.previous/universal/pagination-integrity-creative-formats.yaml +258 -0
- package/compliance/cache/3.0.1.previous/universal/pagination-integrity-list-accounts.yaml +262 -0
- package/compliance/cache/3.0.1.previous/universal/pagination-integrity.yaml +263 -0
- package/compliance/cache/3.0.1.previous/universal/property-lists-pagination-integrity.yaml +307 -0
- package/compliance/cache/3.0.1.previous/universal/runner-output-contract.yaml +339 -0
- package/compliance/cache/3.0.1.previous/universal/schema-validation.yaml +526 -0
- package/compliance/cache/3.0.1.previous/universal/security.yaml +431 -0
- package/compliance/cache/3.0.1.previous/universal/signed-requests.yaml +205 -0
- package/compliance/cache/3.0.1.previous/universal/storyboard-schema.yaml +1056 -0
- package/compliance/cache/3.0.1.previous/universal/v3-envelope-integrity.yaml +104 -0
- package/compliance/cache/3.0.1.previous/universal/webhook-emission.yaml +337 -0
- package/dist/lib/adapters/content-standards-adapter.d.ts +106 -0
- package/dist/lib/adapters/content-standards-adapter.d.ts.map +1 -0
- package/dist/lib/adapters/content-standards-adapter.js +201 -0
- package/dist/lib/adapters/content-standards-adapter.js.map +1 -0
- package/dist/lib/adapters/governance-adapter.d.ts +88 -0
- package/dist/lib/adapters/governance-adapter.d.ts.map +1 -0
- package/dist/lib/adapters/governance-adapter.js +93 -0
- package/dist/lib/adapters/governance-adapter.js.map +1 -0
- package/dist/lib/adapters/index.d.ts +19 -0
- package/dist/lib/adapters/index.d.ts.map +1 -0
- package/dist/lib/adapters/index.js +47 -0
- package/dist/lib/adapters/index.js.map +1 -0
- package/dist/lib/adapters/property-list-adapter.d.ts +123 -0
- package/dist/lib/adapters/property-list-adapter.d.ts.map +1 -0
- package/dist/lib/adapters/property-list-adapter.js +231 -0
- package/dist/lib/adapters/property-list-adapter.js.map +1 -0
- package/dist/lib/adapters/proposal-manager.d.ts +142 -0
- package/dist/lib/adapters/proposal-manager.d.ts.map +1 -0
- package/dist/lib/adapters/proposal-manager.js +184 -0
- package/dist/lib/adapters/proposal-manager.js.map +1 -0
- package/dist/lib/adapters/si-session-manager.d.ts +164 -0
- package/dist/lib/adapters/si-session-manager.d.ts.map +1 -0
- package/dist/lib/adapters/si-session-manager.js +330 -0
- package/dist/lib/adapters/si-session-manager.js.map +1 -0
- package/dist/lib/advanced.d.ts +41 -0
- package/dist/lib/advanced.d.ts.map +1 -0
- package/dist/lib/advanced.js +49 -0
- package/dist/lib/advanced.js.map +1 -0
- package/dist/lib/agents/index.generated.d.ts +397 -0
- package/dist/lib/agents/index.generated.d.ts.map +1 -0
- package/dist/lib/agents/index.generated.js +624 -0
- package/dist/lib/agents/index.generated.js.map +1 -0
- package/dist/lib/auth/index.d.ts +39 -0
- package/dist/lib/auth/index.d.ts.map +1 -0
- package/dist/lib/auth/index.js +100 -0
- package/dist/lib/auth/index.js.map +1 -0
- package/dist/lib/auth/oauth/CLIFlowHandler.d.ts +61 -0
- package/dist/lib/auth/oauth/CLIFlowHandler.d.ts.map +1 -0
- package/dist/lib/auth/oauth/CLIFlowHandler.js +287 -0
- package/dist/lib/auth/oauth/CLIFlowHandler.js.map +1 -0
- package/dist/lib/auth/oauth/ClientCredentialsFlow.d.ts +134 -0
- package/dist/lib/auth/oauth/ClientCredentialsFlow.d.ts.map +1 -0
- package/dist/lib/auth/oauth/ClientCredentialsFlow.js +325 -0
- package/dist/lib/auth/oauth/ClientCredentialsFlow.js.map +1 -0
- package/dist/lib/auth/oauth/MCPOAuthProvider.d.ts +136 -0
- package/dist/lib/auth/oauth/MCPOAuthProvider.d.ts.map +1 -0
- package/dist/lib/auth/oauth/MCPOAuthProvider.js +255 -0
- package/dist/lib/auth/oauth/MCPOAuthProvider.js.map +1 -0
- package/dist/lib/auth/oauth/NonInteractiveFlowHandler.d.ts +37 -0
- package/dist/lib/auth/oauth/NonInteractiveFlowHandler.d.ts.map +1 -0
- package/dist/lib/auth/oauth/NonInteractiveFlowHandler.js +30 -0
- package/dist/lib/auth/oauth/NonInteractiveFlowHandler.js.map +1 -0
- package/dist/lib/auth/oauth/authorization-required.d.ts +112 -0
- package/dist/lib/auth/oauth/authorization-required.d.ts.map +1 -0
- package/dist/lib/auth/oauth/authorization-required.js +363 -0
- package/dist/lib/auth/oauth/authorization-required.js.map +1 -0
- package/dist/lib/auth/oauth/diagnose.d.ts +101 -0
- package/dist/lib/auth/oauth/diagnose.d.ts.map +1 -0
- package/dist/lib/auth/oauth/diagnose.js +630 -0
- package/dist/lib/auth/oauth/diagnose.js.map +1 -0
- package/dist/lib/auth/oauth/diagnostics.d.ts +129 -0
- package/dist/lib/auth/oauth/diagnostics.d.ts.map +1 -0
- package/dist/lib/auth/oauth/diagnostics.js +207 -0
- package/dist/lib/auth/oauth/diagnostics.js.map +1 -0
- package/dist/lib/auth/oauth/discovery.d.ts +96 -0
- package/dist/lib/auth/oauth/discovery.d.ts.map +1 -0
- package/dist/lib/auth/oauth/discovery.js +119 -0
- package/dist/lib/auth/oauth/discovery.js.map +1 -0
- package/dist/lib/auth/oauth/file-storage.d.ts +40 -0
- package/dist/lib/auth/oauth/file-storage.d.ts.map +1 -0
- package/dist/lib/auth/oauth/file-storage.js +112 -0
- package/dist/lib/auth/oauth/file-storage.js.map +1 -0
- package/dist/lib/auth/oauth/index.d.ts +133 -0
- package/dist/lib/auth/oauth/index.d.ts.map +1 -0
- package/dist/lib/auth/oauth/index.js +246 -0
- package/dist/lib/auth/oauth/index.js.map +1 -0
- package/dist/lib/auth/oauth/secret-resolver.d.ts +54 -0
- package/dist/lib/auth/oauth/secret-resolver.d.ts.map +1 -0
- package/dist/lib/auth/oauth/secret-resolver.js +96 -0
- package/dist/lib/auth/oauth/secret-resolver.js.map +1 -0
- package/dist/lib/auth/oauth/storage-registry.d.ts +44 -0
- package/dist/lib/auth/oauth/storage-registry.d.ts.map +1 -0
- package/dist/lib/auth/oauth/storage-registry.js +33 -0
- package/dist/lib/auth/oauth/storage-registry.js.map +1 -0
- package/dist/lib/auth/oauth/types.d.ts +114 -0
- package/dist/lib/auth/oauth/types.d.ts.map +1 -0
- package/dist/lib/auth/oauth/types.js +104 -0
- package/dist/lib/auth/oauth/types.js.map +1 -0
- package/dist/lib/client/index.d.ts +2 -0
- package/dist/lib/client/index.d.ts.map +1 -0
- package/dist/lib/client/index.js +26 -0
- package/dist/lib/client/index.js.map +1 -0
- package/dist/lib/compliance/index.d.ts +5 -0
- package/dist/lib/compliance/index.d.ts.map +1 -0
- package/dist/lib/compliance/index.js +52 -0
- package/dist/lib/compliance/index.js.map +1 -0
- package/dist/lib/compliance-fixtures/index.d.ts +167 -0
- package/dist/lib/compliance-fixtures/index.d.ts.map +1 -0
- package/dist/lib/compliance-fixtures/index.js +218 -0
- package/dist/lib/compliance-fixtures/index.js.map +1 -0
- package/dist/lib/compliance-fixtures/test-authorization-server.d.ts +88 -0
- package/dist/lib/compliance-fixtures/test-authorization-server.d.ts.map +1 -0
- package/dist/lib/compliance-fixtures/test-authorization-server.js +252 -0
- package/dist/lib/compliance-fixtures/test-authorization-server.js.map +1 -0
- package/dist/lib/conformance/index.d.ts +26 -0
- package/dist/lib/conformance/index.d.ts.map +1 -0
- package/dist/lib/conformance/index.js +34 -0
- package/dist/lib/conformance/index.js.map +1 -0
- package/dist/lib/conformance/invariants/uniformError.d.ts +45 -0
- package/dist/lib/conformance/invariants/uniformError.d.ts.map +1 -0
- package/dist/lib/conformance/invariants/uniformError.js +179 -0
- package/dist/lib/conformance/invariants/uniformError.js.map +1 -0
- package/dist/lib/conformance/invariants/uniformErrorComparator.d.ts +8 -0
- package/dist/lib/conformance/invariants/uniformErrorComparator.d.ts.map +1 -0
- package/dist/lib/conformance/invariants/uniformErrorComparator.js +488 -0
- package/dist/lib/conformance/invariants/uniformErrorComparator.js.map +1 -0
- package/dist/lib/conformance/oracle.d.ts +36 -0
- package/dist/lib/conformance/oracle.d.ts.map +1 -0
- package/dist/lib/conformance/oracle.js +267 -0
- package/dist/lib/conformance/oracle.js.map +1 -0
- package/dist/lib/conformance/runConformance.d.ts +17 -0
- package/dist/lib/conformance/runConformance.d.ts.map +1 -0
- package/dist/lib/conformance/runConformance.js +174 -0
- package/dist/lib/conformance/runConformance.js.map +1 -0
- package/dist/lib/conformance/runners.d.ts +27 -0
- package/dist/lib/conformance/runners.d.ts.map +1 -0
- package/dist/lib/conformance/runners.js +159 -0
- package/dist/lib/conformance/runners.js.map +1 -0
- package/dist/lib/conformance/schemaArbitrary.d.ts +39 -0
- package/dist/lib/conformance/schemaArbitrary.d.ts.map +1 -0
- package/dist/lib/conformance/schemaArbitrary.js +382 -0
- package/dist/lib/conformance/schemaArbitrary.js.map +1 -0
- package/dist/lib/conformance/schemaLoader.d.ts +12 -0
- package/dist/lib/conformance/schemaLoader.d.ts.map +1 -0
- package/dist/lib/conformance/schemaLoader.js +122 -0
- package/dist/lib/conformance/schemaLoader.js.map +1 -0
- package/dist/lib/conformance/seeder.d.ts +51 -0
- package/dist/lib/conformance/seeder.d.ts.map +1 -0
- package/dist/lib/conformance/seeder.js +341 -0
- package/dist/lib/conformance/seeder.js.map +1 -0
- package/dist/lib/conformance/types.d.ts +201 -0
- package/dist/lib/conformance/types.d.ts.map +1 -0
- package/dist/lib/conformance/types.js +56 -0
- package/dist/lib/conformance/types.js.map +1 -0
- package/dist/lib/core/ADCPMultiAgentClient.d.ts +624 -0
- package/dist/lib/core/ADCPMultiAgentClient.d.ts.map +1 -0
- package/dist/lib/core/ADCPMultiAgentClient.js +908 -0
- package/dist/lib/core/ADCPMultiAgentClient.js.map +1 -0
- package/dist/lib/core/AgentClient.d.ts +517 -0
- package/dist/lib/core/AgentClient.d.ts.map +1 -0
- package/dist/lib/core/AgentClient.js +784 -0
- package/dist/lib/core/AgentClient.js.map +1 -0
- package/dist/lib/core/AsyncHandler.d.ts +210 -0
- package/dist/lib/core/AsyncHandler.d.ts.map +1 -0
- package/dist/lib/core/AsyncHandler.js +182 -0
- package/dist/lib/core/AsyncHandler.js.map +1 -0
- package/dist/lib/core/ConfigurationManager.d.ts +79 -0
- package/dist/lib/core/ConfigurationManager.d.ts.map +1 -0
- package/dist/lib/core/ConfigurationManager.js +249 -0
- package/dist/lib/core/ConfigurationManager.js.map +1 -0
- package/dist/lib/core/ConversationTypes.d.ts +422 -0
- package/dist/lib/core/ConversationTypes.d.ts.map +1 -0
- package/dist/lib/core/ConversationTypes.js +5 -0
- package/dist/lib/core/ConversationTypes.js.map +1 -0
- package/dist/lib/core/CreativeAgentClient.d.ts +144 -0
- package/dist/lib/core/CreativeAgentClient.d.ts.map +1 -0
- package/dist/lib/core/CreativeAgentClient.js +169 -0
- package/dist/lib/core/CreativeAgentClient.js.map +1 -0
- package/dist/lib/core/GovernanceMiddleware.d.ts +93 -0
- package/dist/lib/core/GovernanceMiddleware.d.ts.map +1 -0
- package/dist/lib/core/GovernanceMiddleware.js +306 -0
- package/dist/lib/core/GovernanceMiddleware.js.map +1 -0
- package/dist/lib/core/GovernanceTypes.d.ts +116 -0
- package/dist/lib/core/GovernanceTypes.d.ts.map +1 -0
- package/dist/lib/core/GovernanceTypes.js +60 -0
- package/dist/lib/core/GovernanceTypes.js.map +1 -0
- package/dist/lib/core/ProtocolResponseParser.d.ts +80 -0
- package/dist/lib/core/ProtocolResponseParser.d.ts.map +1 -0
- package/dist/lib/core/ProtocolResponseParser.js +367 -0
- package/dist/lib/core/ProtocolResponseParser.js.map +1 -0
- package/dist/lib/core/ResponseValidator.d.ts +68 -0
- package/dist/lib/core/ResponseValidator.d.ts.map +1 -0
- package/dist/lib/core/ResponseValidator.js +283 -0
- package/dist/lib/core/ResponseValidator.js.map +1 -0
- package/dist/lib/core/SingleAgentClient.d.ts +1065 -0
- package/dist/lib/core/SingleAgentClient.d.ts.map +1 -0
- package/dist/lib/core/SingleAgentClient.js +2134 -0
- package/dist/lib/core/SingleAgentClient.js.map +1 -0
- package/dist/lib/core/TaskEventTypes.d.ts +220 -0
- package/dist/lib/core/TaskEventTypes.d.ts.map +1 -0
- package/dist/lib/core/TaskEventTypes.js +80 -0
- package/dist/lib/core/TaskEventTypes.js.map +1 -0
- package/dist/lib/core/TaskExecutor.d.ts +245 -0
- package/dist/lib/core/TaskExecutor.d.ts.map +1 -0
- package/dist/lib/core/TaskExecutor.js +1452 -0
- package/dist/lib/core/TaskExecutor.js.map +1 -0
- package/dist/lib/core/match.d.ts +84 -0
- package/dist/lib/core/match.d.ts.map +1 -0
- package/dist/lib/core/match.js +47 -0
- package/dist/lib/core/match.js.map +1 -0
- package/dist/lib/discovery/network-consistency-checker.d.ts +111 -0
- package/dist/lib/discovery/network-consistency-checker.d.ts.map +1 -0
- package/dist/lib/discovery/network-consistency-checker.js +541 -0
- package/dist/lib/discovery/network-consistency-checker.js.map +1 -0
- package/dist/lib/discovery/property-crawler.d.ts +91 -0
- package/dist/lib/discovery/property-crawler.d.ts.map +1 -0
- package/dist/lib/discovery/property-crawler.js +290 -0
- package/dist/lib/discovery/property-crawler.js.map +1 -0
- package/dist/lib/discovery/property-index.d.ts +68 -0
- package/dist/lib/discovery/property-index.d.ts.map +1 -0
- package/dist/lib/discovery/property-index.js +163 -0
- package/dist/lib/discovery/property-index.js.map +1 -0
- package/dist/lib/discovery/types.d.ts +42 -0
- package/dist/lib/discovery/types.d.ts.map +1 -0
- package/dist/lib/discovery/types.js +7 -0
- package/dist/lib/discovery/types.js.map +1 -0
- package/dist/lib/errors/index.d.ts +284 -0
- package/dist/lib/errors/index.d.ts.map +1 -0
- package/dist/lib/errors/index.js +446 -0
- package/dist/lib/errors/index.js.map +1 -0
- package/dist/lib/express-mcp/index.d.ts +62 -0
- package/dist/lib/express-mcp/index.d.ts.map +1 -0
- package/dist/lib/express-mcp/index.js +118 -0
- package/dist/lib/express-mcp/index.js.map +1 -0
- package/dist/lib/governance/index.d.ts +149 -0
- package/dist/lib/governance/index.d.ts.map +1 -0
- package/dist/lib/governance/index.js +171 -0
- package/dist/lib/governance/index.js.map +1 -0
- package/dist/lib/handlers/types.d.ts +119 -0
- package/dist/lib/handlers/types.d.ts.map +1 -0
- package/dist/lib/handlers/types.js +239 -0
- package/dist/lib/handlers/types.js.map +1 -0
- package/dist/lib/index.d.ts +118 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +689 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/net/address-guards.d.ts +34 -0
- package/dist/lib/net/address-guards.d.ts.map +1 -0
- package/dist/lib/net/address-guards.js +132 -0
- package/dist/lib/net/address-guards.js.map +1 -0
- package/dist/lib/net/index.d.ts +8 -0
- package/dist/lib/net/index.d.ts.map +1 -0
- package/dist/lib/net/index.js +17 -0
- package/dist/lib/net/index.js.map +1 -0
- package/dist/lib/net/ssrf-fetch.d.ts +56 -0
- package/dist/lib/net/ssrf-fetch.d.ts.map +1 -0
- package/dist/lib/net/ssrf-fetch.js +199 -0
- package/dist/lib/net/ssrf-fetch.js.map +1 -0
- package/dist/lib/observability/index.d.ts +8 -0
- package/dist/lib/observability/index.d.ts.map +1 -0
- package/dist/lib/observability/index.js +17 -0
- package/dist/lib/observability/index.js.map +1 -0
- package/dist/lib/observability/tracing.d.ts +42 -0
- package/dist/lib/observability/tracing.d.ts.map +1 -0
- package/dist/lib/observability/tracing.js +126 -0
- package/dist/lib/observability/tracing.js.map +1 -0
- package/dist/lib/protocols/a2a.d.ts +23 -0
- package/dist/lib/protocols/a2a.d.ts.map +1 -0
- package/dist/lib/protocols/a2a.js +268 -0
- package/dist/lib/protocols/a2a.js.map +1 -0
- package/dist/lib/protocols/index.d.ts +43 -0
- package/dist/lib/protocols/index.d.ts.map +1 -0
- package/dist/lib/protocols/index.js +264 -0
- package/dist/lib/protocols/index.js.map +1 -0
- package/dist/lib/protocols/mcp-tasks.d.ts +79 -0
- package/dist/lib/protocols/mcp-tasks.d.ts.map +1 -0
- package/dist/lib/protocols/mcp-tasks.js +407 -0
- package/dist/lib/protocols/mcp-tasks.js.map +1 -0
- package/dist/lib/protocols/mcp.d.ts +124 -0
- package/dist/lib/protocols/mcp.d.ts.map +1 -0
- package/dist/lib/protocols/mcp.js +564 -0
- package/dist/lib/protocols/mcp.js.map +1 -0
- package/dist/lib/protocols/rawResponseCapture.d.ts +44 -0
- package/dist/lib/protocols/rawResponseCapture.d.ts.map +1 -0
- package/dist/lib/protocols/rawResponseCapture.js +147 -0
- package/dist/lib/protocols/rawResponseCapture.js.map +1 -0
- package/dist/lib/registry/cursor-store.d.ts +19 -0
- package/dist/lib/registry/cursor-store.d.ts.map +1 -0
- package/dist/lib/registry/cursor-store.js +44 -0
- package/dist/lib/registry/cursor-store.js.map +1 -0
- package/dist/lib/registry/index.d.ts +278 -0
- package/dist/lib/registry/index.d.ts.map +1 -0
- package/dist/lib/registry/index.js +652 -0
- package/dist/lib/registry/index.js.map +1 -0
- package/dist/lib/registry/property-registry.d.ts +57 -0
- package/dist/lib/registry/property-registry.d.ts.map +1 -0
- package/dist/lib/registry/property-registry.js +92 -0
- package/dist/lib/registry/property-registry.js.map +1 -0
- package/dist/lib/registry/sync.d.ts +139 -0
- package/dist/lib/registry/sync.d.ts.map +1 -0
- package/dist/lib/registry/sync.js +390 -0
- package/dist/lib/registry/sync.js.map +1 -0
- package/dist/lib/registry/types.d.ts +112 -0
- package/dist/lib/registry/types.d.ts.map +1 -0
- package/dist/lib/registry/types.generated.d.ts +5680 -0
- package/dist/lib/registry/types.generated.d.ts.map +1 -0
- package/dist/lib/registry/types.generated.js +8 -0
- package/dist/lib/registry/types.generated.js.map +1 -0
- package/dist/lib/registry/types.js +9 -0
- package/dist/lib/registry/types.js.map +1 -0
- package/dist/lib/schemas/index.d.ts +76 -0
- package/dist/lib/schemas/index.d.ts.map +1 -0
- package/dist/lib/schemas/index.js +133 -0
- package/dist/lib/schemas/index.js.map +1 -0
- package/dist/lib/schemas-data/3.0.1/a2ui/bound-value.json +81 -0
- package/dist/lib/schemas-data/3.0.1/a2ui/component.json +32 -0
- package/dist/lib/schemas-data/3.0.1/a2ui/si-catalog.json +427 -0
- package/dist/lib/schemas-data/3.0.1/a2ui/surface.json +39 -0
- package/dist/lib/schemas-data/3.0.1/a2ui/user-action.json +47 -0
- package/dist/lib/schemas-data/3.0.1/account/get-account-financials-request.json +70 -0
- package/dist/lib/schemas-data/3.0.1/account/get-account-financials-response.json +320 -0
- package/dist/lib/schemas-data/3.0.1/account/list-accounts-request.json +42 -0
- package/dist/lib/schemas-data/3.0.1/account/list-accounts-response.json +108 -0
- package/dist/lib/schemas-data/3.0.1/account/report-usage-request.json +168 -0
- package/dist/lib/schemas-data/3.0.1/account/report-usage-response.json +56 -0
- package/dist/lib/schemas-data/3.0.1/account/sync-accounts-request.json +201 -0
- package/dist/lib/schemas-data/3.0.1/account/sync-accounts-response.json +346 -0
- package/dist/lib/schemas-data/3.0.1/account/sync-governance-request.json +170 -0
- package/dist/lib/schemas-data/3.0.1/account/sync-governance-response.json +193 -0
- package/dist/lib/schemas-data/3.0.1/adagents.json +1225 -0
- package/dist/lib/schemas-data/3.0.1/brand/acquire-rights-request.json +114 -0
- package/dist/lib/schemas-data/3.0.1/brand/acquire-rights-response.json +220 -0
- package/dist/lib/schemas-data/3.0.1/brand/creative-approval-request.json +63 -0
- package/dist/lib/schemas-data/3.0.1/brand/creative-approval-response.json +189 -0
- package/dist/lib/schemas-data/3.0.1/brand/get-brand-identity-request.json +56 -0
- package/dist/lib/schemas-data/3.0.1/brand/get-brand-identity-response.json +585 -0
- package/dist/lib/schemas-data/3.0.1/brand/get-rights-request.json +70 -0
- package/dist/lib/schemas-data/3.0.1/brand/get-rights-response.json +220 -0
- package/dist/lib/schemas-data/3.0.1/brand/revocation-notification.json +57 -0
- package/dist/lib/schemas-data/3.0.1/brand/rights-pricing-option.json +65 -0
- package/dist/lib/schemas-data/3.0.1/brand/rights-terms.json +70 -0
- package/dist/lib/schemas-data/3.0.1/brand/update-rights-request.json +63 -0
- package/dist/lib/schemas-data/3.0.1/brand/update-rights-response.json +99 -0
- package/dist/lib/schemas-data/3.0.1/brand.json +2582 -0
- package/dist/lib/schemas-data/3.0.1/bundled/content-standards/calibrate-content-request.json +1712 -0
- package/dist/lib/schemas-data/3.0.1/bundled/content-standards/calibrate-content-response.json +180 -0
- package/dist/lib/schemas-data/3.0.1/bundled/content-standards/create-content-standards-request.json +3622 -0
- package/dist/lib/schemas-data/3.0.1/bundled/content-standards/create-content-standards-response.json +116 -0
- package/dist/lib/schemas-data/3.0.1/bundled/content-standards/get-content-standards-request.json +38 -0
- package/dist/lib/schemas-data/3.0.1/bundled/content-standards/get-content-standards-response.json +3851 -0
- package/dist/lib/schemas-data/3.0.1/bundled/content-standards/get-media-buy-artifacts-request.json +234 -0
- package/dist/lib/schemas-data/3.0.1/bundled/content-standards/get-media-buy-artifacts-response.json +1880 -0
- package/dist/lib/schemas-data/3.0.1/bundled/content-standards/list-content-standards-request.json +121 -0
- package/dist/lib/schemas-data/3.0.1/bundled/content-standards/list-content-standards-response.json +3880 -0
- package/dist/lib/schemas-data/3.0.1/bundled/content-standards/update-content-standards-request.json +3611 -0
- package/dist/lib/schemas-data/3.0.1/bundled/content-standards/update-content-standards-response.json +131 -0
- package/dist/lib/schemas-data/3.0.1/bundled/content-standards/validate-content-delivery-request.json +1766 -0
- package/dist/lib/schemas-data/3.0.1/bundled/content-standards/validate-content-delivery-response.json +208 -0
- package/dist/lib/schemas-data/3.0.1/bundled/core/tasks-get-request.json +60 -0
- package/dist/lib/schemas-data/3.0.1/bundled/core/tasks-get-response.json +264 -0
- package/dist/lib/schemas-data/3.0.1/bundled/core/tasks-list-request.json +318 -0
- package/dist/lib/schemas-data/3.0.1/bundled/core/tasks-list-response.json +258 -0
- package/dist/lib/schemas-data/3.0.1/bundled/creative/get-creative-delivery-request.json +245 -0
- package/dist/lib/schemas-data/3.0.1/bundled/creative/get-creative-delivery-response.json +5967 -0
- package/dist/lib/schemas-data/3.0.1/bundled/creative/get-creative-features-request.json +5091 -0
- package/dist/lib/schemas-data/3.0.1/bundled/creative/get-creative-features-response.json +230 -0
- package/dist/lib/schemas-data/3.0.1/bundled/creative/list-creative-formats-request.json +485 -0
- package/dist/lib/schemas-data/3.0.1/bundled/creative/list-creative-formats-response.json +4076 -0
- package/dist/lib/schemas-data/3.0.1/bundled/creative/list-creatives-request.json +687 -0
- package/dist/lib/schemas-data/3.0.1/bundled/creative/list-creatives-response.json +5977 -0
- package/dist/lib/schemas-data/3.0.1/bundled/creative/preview-creative-request.json +9624 -0
- package/dist/lib/schemas-data/3.0.1/bundled/creative/preview-creative-response.json +5931 -0
- package/dist/lib/schemas-data/3.0.1/bundled/creative/sync-creatives-request.json +5268 -0
- package/dist/lib/schemas-data/3.0.1/bundled/creative/sync-creatives-response.json +1146 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/build-creative-request.json +5369 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/build-creative-response.json +10286 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/create-media-buy-request.json +7893 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/create-media-buy-response.json +4170 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/get-media-buy-delivery-request.json +494 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/get-media-buy-delivery-response.json +4256 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/get-media-buys-request.json +261 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/get-media-buys-response.json +2357 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/get-products-request.json +2046 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/get-products-response.json +6809 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/list-creative-formats-request.json +311 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/list-creative-formats-response.json +4080 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/log-event-request.json +394 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/log-event-response.json +193 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/package-request.json +6923 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/provide-performance-feedback-request.json +119 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/provide-performance-feedback-response.json +142 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/sync-audiences-request.json +454 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/sync-audiences-response.json +335 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/sync-catalogs-request.json +836 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/sync-catalogs-response.json +344 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/sync-event-sources-request.json +299 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/sync-event-sources-response.json +461 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/update-media-buy-request.json +13548 -0
- package/dist/lib/schemas-data/3.0.1/bundled/media-buy/update-media-buy-response.json +2799 -0
- package/dist/lib/schemas-data/3.0.1/bundled/property/create-property-list-request.json +661 -0
- package/dist/lib/schemas-data/3.0.1/bundled/property/create-property-list-response.json +928 -0
- package/dist/lib/schemas-data/3.0.1/bundled/property/delete-property-list-request.json +198 -0
- package/dist/lib/schemas-data/3.0.1/bundled/property/delete-property-list-response.json +44 -0
- package/dist/lib/schemas-data/3.0.1/bundled/property/get-property-list-request.json +212 -0
- package/dist/lib/schemas-data/3.0.1/bundled/property/get-property-list-response.json +1001 -0
- package/dist/lib/schemas-data/3.0.1/bundled/property/list-property-lists-request.json +204 -0
- package/dist/lib/schemas-data/3.0.1/bundled/property/list-property-lists-response.json +946 -0
- package/dist/lib/schemas-data/3.0.1/bundled/property/update-property-list-request.json +670 -0
- package/dist/lib/schemas-data/3.0.1/bundled/property/update-property-list-response.json +923 -0
- package/dist/lib/schemas-data/3.0.1/bundled/property/validate-property-delivery-request.json +308 -0
- package/dist/lib/schemas-data/3.0.1/bundled/property/validate-property-delivery-response.json +418 -0
- package/dist/lib/schemas-data/3.0.1/bundled/protocol/get-adcp-capabilities-request.json +47 -0
- package/dist/lib/schemas-data/3.0.1/bundled/protocol/get-adcp-capabilities-response.json +1729 -0
- package/dist/lib/schemas-data/3.0.1/bundled/signals/activate-signal-request.json +269 -0
- package/dist/lib/schemas-data/3.0.1/bundled/signals/activate-signal-response.json +320 -0
- package/dist/lib/schemas-data/3.0.1/bundled/signals/get-signals-request.json +409 -0
- package/dist/lib/schemas-data/3.0.1/bundled/signals/get-signals-response.json +689 -0
- package/dist/lib/schemas-data/3.0.1/bundled/sponsored-intelligence/si-get-offering-request.json +57 -0
- package/dist/lib/schemas-data/3.0.1/bundled/sponsored-intelligence/si-get-offering-response.json +207 -0
- package/dist/lib/schemas-data/3.0.1/bundled/sponsored-intelligence/si-initiate-session-request.json +322 -0
- package/dist/lib/schemas-data/3.0.1/bundled/sponsored-intelligence/si-initiate-session-response.json +618 -0
- package/dist/lib/schemas-data/3.0.1/bundled/sponsored-intelligence/si-send-message-request.json +81 -0
- package/dist/lib/schemas-data/3.0.1/bundled/sponsored-intelligence/si-send-message-response.json +589 -0
- package/dist/lib/schemas-data/3.0.1/bundled/sponsored-intelligence/si-terminate-session-request.json +87 -0
- package/dist/lib/schemas-data/3.0.1/bundled/sponsored-intelligence/si-terminate-session-response.json +156 -0
- package/dist/lib/schemas-data/3.0.1/collection/base-collection-source.json +118 -0
- package/dist/lib/schemas-data/3.0.1/collection/collection-list-changed-webhook.json +74 -0
- package/dist/lib/schemas-data/3.0.1/collection/collection-list-filters.json +85 -0
- package/dist/lib/schemas-data/3.0.1/collection/collection-list.json +71 -0
- package/dist/lib/schemas-data/3.0.1/collection/create-collection-list-request.json +62 -0
- package/dist/lib/schemas-data/3.0.1/collection/create-collection-list-response.json +33 -0
- package/dist/lib/schemas-data/3.0.1/collection/delete-collection-list-request.json +43 -0
- package/dist/lib/schemas-data/3.0.1/collection/delete-collection-list-response.json +34 -0
- package/dist/lib/schemas-data/3.0.1/collection/get-collection-list-request.json +57 -0
- package/dist/lib/schemas-data/3.0.1/collection/get-collection-list-response.json +122 -0
- package/dist/lib/schemas-data/3.0.1/collection/list-collection-lists-request.json +33 -0
- package/dist/lib/schemas-data/3.0.1/collection/list-collection-lists-response.json +29 -0
- package/dist/lib/schemas-data/3.0.1/collection/update-collection-list-request.json +71 -0
- package/dist/lib/schemas-data/3.0.1/collection/update-collection-list-response.json +28 -0
- package/dist/lib/schemas-data/3.0.1/content-standards/artifact-webhook-payload.json +88 -0
- package/dist/lib/schemas-data/3.0.1/content-standards/artifact.json +407 -0
- package/dist/lib/schemas-data/3.0.1/content-standards/calibrate-content-request.json +42 -0
- package/dist/lib/schemas-data/3.0.1/content-standards/calibrate-content-response.json +93 -0
- package/dist/lib/schemas-data/3.0.1/content-standards/content-standards.json +83 -0
- package/dist/lib/schemas-data/3.0.1/content-standards/create-content-standards-request.json +177 -0
- package/dist/lib/schemas-data/3.0.1/content-standards/create-content-standards-response.json +53 -0
- package/dist/lib/schemas-data/3.0.1/content-standards/get-content-standards-request.json +28 -0
- package/dist/lib/schemas-data/3.0.1/content-standards/get-content-standards-response.json +47 -0
- package/dist/lib/schemas-data/3.0.1/content-standards/get-media-buy-artifacts-request.json +79 -0
- package/dist/lib/schemas-data/3.0.1/content-standards/get-media-buy-artifacts-response.json +136 -0
- package/dist/lib/schemas-data/3.0.1/content-standards/list-content-standards-request.json +49 -0
- package/dist/lib/schemas-data/3.0.1/content-standards/list-content-standards-response.json +55 -0
- package/dist/lib/schemas-data/3.0.1/content-standards/update-content-standards-request.json +166 -0
- package/dist/lib/schemas-data/3.0.1/content-standards/update-content-standards-response.json +68 -0
- package/dist/lib/schemas-data/3.0.1/content-standards/validate-content-delivery-request.json +96 -0
- package/dist/lib/schemas-data/3.0.1/content-standards/validate-content-delivery-response.json +121 -0
- package/dist/lib/schemas-data/3.0.1/core/account-ref.json +71 -0
- package/dist/lib/schemas-data/3.0.1/core/account.json +344 -0
- package/dist/lib/schemas-data/3.0.1/core/activation-key.json +50 -0
- package/dist/lib/schemas-data/3.0.1/core/ad-inventory-config.json +39 -0
- package/dist/lib/schemas-data/3.0.1/core/agent-encryption-key.json +41 -0
- package/dist/lib/schemas-data/3.0.1/core/agent-signing-key.json +55 -0
- package/dist/lib/schemas-data/3.0.1/core/app-item.json +170 -0
- package/dist/lib/schemas-data/3.0.1/core/assets/audio-asset.json +82 -0
- package/dist/lib/schemas-data/3.0.1/core/assets/brief-asset.json +22 -0
- package/dist/lib/schemas-data/3.0.1/core/assets/catalog-asset.json +22 -0
- package/dist/lib/schemas-data/3.0.1/core/assets/css-asset.json +31 -0
- package/dist/lib/schemas-data/3.0.1/core/assets/daast-asset.json +88 -0
- package/dist/lib/schemas-data/3.0.1/core/assets/html-asset.json +54 -0
- package/dist/lib/schemas-data/3.0.1/core/assets/image-asset.json +49 -0
- package/dist/lib/schemas-data/3.0.1/core/assets/javascript-asset.json +54 -0
- package/dist/lib/schemas-data/3.0.1/core/assets/markdown-asset.json +37 -0
- package/dist/lib/schemas-data/3.0.1/core/assets/text-asset.json +31 -0
- package/dist/lib/schemas-data/3.0.1/core/assets/url-asset.json +36 -0
- package/dist/lib/schemas-data/3.0.1/core/assets/vast-asset.json +94 -0
- package/dist/lib/schemas-data/3.0.1/core/assets/video-asset.json +179 -0
- package/dist/lib/schemas-data/3.0.1/core/assets/webhook-asset.json +97 -0
- package/dist/lib/schemas-data/3.0.1/core/async-response-data.json +128 -0
- package/dist/lib/schemas-data/3.0.1/core/attribution-window.json +33 -0
- package/dist/lib/schemas-data/3.0.1/core/audience-member.json +70 -0
- package/dist/lib/schemas-data/3.0.1/core/audience-selector.json +134 -0
- package/dist/lib/schemas-data/3.0.1/core/brand-id.json +16 -0
- package/dist/lib/schemas-data/3.0.1/core/brand-ref.json +76 -0
- package/dist/lib/schemas-data/3.0.1/core/business-entity.json +207 -0
- package/dist/lib/schemas-data/3.0.1/core/cancellation-policy.json +49 -0
- package/dist/lib/schemas-data/3.0.1/core/catalog-field-mapping.json +144 -0
- package/dist/lib/schemas-data/3.0.1/core/catalog.json +222 -0
- package/dist/lib/schemas-data/3.0.1/core/catchment.json +221 -0
- package/dist/lib/schemas-data/3.0.1/core/collection-distribution.json +41 -0
- package/dist/lib/schemas-data/3.0.1/core/collection-list-ref.json +29 -0
- package/dist/lib/schemas-data/3.0.1/core/collection-selector.json +27 -0
- package/dist/lib/schemas-data/3.0.1/core/collection.json +116 -0
- package/dist/lib/schemas-data/3.0.1/core/content-rating.json +22 -0
- package/dist/lib/schemas-data/3.0.1/core/context.json +8 -0
- package/dist/lib/schemas-data/3.0.1/core/creative-asset.json +150 -0
- package/dist/lib/schemas-data/3.0.1/core/creative-assignment.json +32 -0
- package/dist/lib/schemas-data/3.0.1/core/creative-brief.json +136 -0
- package/dist/lib/schemas-data/3.0.1/core/creative-consumption.json +30 -0
- package/dist/lib/schemas-data/3.0.1/core/creative-filters.json +119 -0
- package/dist/lib/schemas-data/3.0.1/core/creative-item.json +79 -0
- package/dist/lib/schemas-data/3.0.1/core/creative-manifest.json +96 -0
- package/dist/lib/schemas-data/3.0.1/core/creative-policy.json +31 -0
- package/dist/lib/schemas-data/3.0.1/core/creative-variable.json +47 -0
- package/dist/lib/schemas-data/3.0.1/core/creative-variant.json +60 -0
- package/dist/lib/schemas-data/3.0.1/core/data-provider-signal-selector.json +94 -0
- package/dist/lib/schemas-data/3.0.1/core/date-range.json +24 -0
- package/dist/lib/schemas-data/3.0.1/core/datetime-range.json +24 -0
- package/dist/lib/schemas-data/3.0.1/core/daypart-target.json +39 -0
- package/dist/lib/schemas-data/3.0.1/core/deadline-policy.json +58 -0
- package/dist/lib/schemas-data/3.0.1/core/delivery-forecast.json +86 -0
- package/dist/lib/schemas-data/3.0.1/core/delivery-metrics.json +327 -0
- package/dist/lib/schemas-data/3.0.1/core/deployment.json +93 -0
- package/dist/lib/schemas-data/3.0.1/core/destination-item.json +168 -0
- package/dist/lib/schemas-data/3.0.1/core/destination.json +53 -0
- package/dist/lib/schemas-data/3.0.1/core/diagnostic-issue.json +27 -0
- package/dist/lib/schemas-data/3.0.1/core/duration.json +30 -0
- package/dist/lib/schemas-data/3.0.1/core/education-item.json +168 -0
- package/dist/lib/schemas-data/3.0.1/core/error.json +52 -0
- package/dist/lib/schemas-data/3.0.1/core/event-custom-data.json +86 -0
- package/dist/lib/schemas-data/3.0.1/core/event-source-health.json +70 -0
- package/dist/lib/schemas-data/3.0.1/core/event.json +54 -0
- package/dist/lib/schemas-data/3.0.1/core/ext.json +8 -0
- package/dist/lib/schemas-data/3.0.1/core/feature-requirement.json +45 -0
- package/dist/lib/schemas-data/3.0.1/core/flight-item.json +159 -0
- package/dist/lib/schemas-data/3.0.1/core/forecast-point.json +85 -0
- package/dist/lib/schemas-data/3.0.1/core/forecast-range.json +38 -0
- package/dist/lib/schemas-data/3.0.1/core/format-id.json +48 -0
- package/dist/lib/schemas-data/3.0.1/core/format.json +904 -0
- package/dist/lib/schemas-data/3.0.1/core/frequency-cap.json +73 -0
- package/dist/lib/schemas-data/3.0.1/core/generation-credential.json +44 -0
- package/dist/lib/schemas-data/3.0.1/core/geo-breakdown-support.json +38 -0
- package/dist/lib/schemas-data/3.0.1/core/hotel-item.json +214 -0
- package/dist/lib/schemas-data/3.0.1/core/identifier.json +22 -0
- package/dist/lib/schemas-data/3.0.1/core/industry-identifier.json +22 -0
- package/dist/lib/schemas-data/3.0.1/core/insertion-order.json +91 -0
- package/dist/lib/schemas-data/3.0.1/core/installment-deadlines.json +29 -0
- package/dist/lib/schemas-data/3.0.1/core/installment.json +108 -0
- package/dist/lib/schemas-data/3.0.1/core/job-item.json +199 -0
- package/dist/lib/schemas-data/3.0.1/core/limited-series.json +28 -0
- package/dist/lib/schemas-data/3.0.1/core/material-deadline.json +31 -0
- package/dist/lib/schemas-data/3.0.1/core/mcp-webhook-payload.json +163 -0
- package/dist/lib/schemas-data/3.0.1/core/measurement-readiness.json +43 -0
- package/dist/lib/schemas-data/3.0.1/core/measurement-terms.json +63 -0
- package/dist/lib/schemas-data/3.0.1/core/measurement-window.json +54 -0
- package/dist/lib/schemas-data/3.0.1/core/media-buy-features.json +24 -0
- package/dist/lib/schemas-data/3.0.1/core/media-buy.json +101 -0
- package/dist/lib/schemas-data/3.0.1/core/offering-asset-group.json +118 -0
- package/dist/lib/schemas-data/3.0.1/core/offering.json +267 -0
- package/dist/lib/schemas-data/3.0.1/core/optimization-goal.json +285 -0
- package/dist/lib/schemas-data/3.0.1/core/outcome-measurement.json +48 -0
- package/dist/lib/schemas-data/3.0.1/core/overlay.json +89 -0
- package/dist/lib/schemas-data/3.0.1/core/package.json +170 -0
- package/dist/lib/schemas-data/3.0.1/core/pagination-request.json +21 -0
- package/dist/lib/schemas-data/3.0.1/core/pagination-response.json +26 -0
- package/dist/lib/schemas-data/3.0.1/core/performance-feedback.json +90 -0
- package/dist/lib/schemas-data/3.0.1/core/performance-standard.json +33 -0
- package/dist/lib/schemas-data/3.0.1/core/placement-definition.json +81 -0
- package/dist/lib/schemas-data/3.0.1/core/placement.json +42 -0
- package/dist/lib/schemas-data/3.0.1/core/planned-delivery.json +84 -0
- package/dist/lib/schemas-data/3.0.1/core/price.json +59 -0
- package/dist/lib/schemas-data/3.0.1/core/pricing-option.json +35 -0
- package/dist/lib/schemas-data/3.0.1/core/product-allocation.json +69 -0
- package/dist/lib/schemas-data/3.0.1/core/product-filters.json +435 -0
- package/dist/lib/schemas-data/3.0.1/core/product.json +493 -0
- package/dist/lib/schemas-data/3.0.1/core/property-id.json +15 -0
- package/dist/lib/schemas-data/3.0.1/core/property-list-ref.json +29 -0
- package/dist/lib/schemas-data/3.0.1/core/property-tag.json +16 -0
- package/dist/lib/schemas-data/3.0.1/core/property.json +70 -0
- package/dist/lib/schemas-data/3.0.1/core/proposal.json +89 -0
- package/dist/lib/schemas-data/3.0.1/core/protocol-envelope.json +186 -0
- package/dist/lib/schemas-data/3.0.1/core/provenance.json +234 -0
- package/dist/lib/schemas-data/3.0.1/core/publisher-property-selector.json +92 -0
- package/dist/lib/schemas-data/3.0.1/core/push-notification-config.json +47 -0
- package/dist/lib/schemas-data/3.0.1/core/real-estate-item.json +241 -0
- package/dist/lib/schemas-data/3.0.1/core/reference-asset.json +36 -0
- package/dist/lib/schemas-data/3.0.1/core/reporting-capabilities.json +118 -0
- package/dist/lib/schemas-data/3.0.1/core/reporting-webhook.json +67 -0
- package/dist/lib/schemas-data/3.0.1/core/requirements/asset-requirements.json +44 -0
- package/dist/lib/schemas-data/3.0.1/core/requirements/audio-asset-requirements.json +68 -0
- package/dist/lib/schemas-data/3.0.1/core/requirements/catalog-field-binding.json +172 -0
- package/dist/lib/schemas-data/3.0.1/core/requirements/catalog-requirements.json +68 -0
- package/dist/lib/schemas-data/3.0.1/core/requirements/css-asset-requirements.json +15 -0
- package/dist/lib/schemas-data/3.0.1/core/requirements/daast-asset-requirements.json +17 -0
- package/dist/lib/schemas-data/3.0.1/core/requirements/html-asset-requirements.json +38 -0
- package/dist/lib/schemas-data/3.0.1/core/requirements/image-asset-requirements.json +151 -0
- package/dist/lib/schemas-data/3.0.1/core/requirements/javascript-asset-requirements.json +40 -0
- package/dist/lib/schemas-data/3.0.1/core/requirements/markdown-asset-requirements.json +15 -0
- package/dist/lib/schemas-data/3.0.1/core/requirements/offering-asset-constraint.json +66 -0
- package/dist/lib/schemas-data/3.0.1/core/requirements/text-asset-requirements.json +41 -0
- package/dist/lib/schemas-data/3.0.1/core/requirements/url-asset-requirements.json +50 -0
- package/dist/lib/schemas-data/3.0.1/core/requirements/vast-asset-requirements.json +21 -0
- package/dist/lib/schemas-data/3.0.1/core/requirements/video-asset-requirements.json +172 -0
- package/dist/lib/schemas-data/3.0.1/core/requirements/webhook-asset-requirements.json +21 -0
- package/dist/lib/schemas-data/3.0.1/core/response.json +24 -0
- package/dist/lib/schemas-data/3.0.1/core/rights-constraint.json +98 -0
- package/dist/lib/schemas-data/3.0.1/core/seller-agent-ref.json +30 -0
- package/dist/lib/schemas-data/3.0.1/core/signal-definition.json +89 -0
- package/dist/lib/schemas-data/3.0.1/core/signal-filters.json +43 -0
- package/dist/lib/schemas-data/3.0.1/core/signal-id.json +66 -0
- package/dist/lib/schemas-data/3.0.1/core/signal-pricing-option.json +7 -0
- package/dist/lib/schemas-data/3.0.1/core/signal-pricing.json +194 -0
- package/dist/lib/schemas-data/3.0.1/core/signal-targeting.json +93 -0
- package/dist/lib/schemas-data/3.0.1/core/special.json +31 -0
- package/dist/lib/schemas-data/3.0.1/core/start-timing.json +18 -0
- package/dist/lib/schemas-data/3.0.1/core/store-item.json +259 -0
- package/dist/lib/schemas-data/3.0.1/core/talent.json +27 -0
- package/dist/lib/schemas-data/3.0.1/core/targeting.json +510 -0
- package/dist/lib/schemas-data/3.0.1/core/tasks-get-request.json +50 -0
- package/dist/lib/schemas-data/3.0.1/core/tasks-get-response.json +159 -0
- package/dist/lib/schemas-data/3.0.1/core/tasks-list-request.json +185 -0
- package/dist/lib/schemas-data/3.0.1/core/tasks-list-response.json +153 -0
- package/dist/lib/schemas-data/3.0.1/core/user-match.json +90 -0
- package/dist/lib/schemas-data/3.0.1/core/vehicle-item.json +231 -0
- package/dist/lib/schemas-data/3.0.1/core/vendor-pricing-option.json +24 -0
- package/dist/lib/schemas-data/3.0.1/core/x-entity-types.json +69 -0
- package/dist/lib/schemas-data/3.0.1/creative/asset-types/index.json +118 -0
- package/dist/lib/schemas-data/3.0.1/creative/creative-feature-result.json +69 -0
- package/dist/lib/schemas-data/3.0.1/creative/get-creative-delivery-request.json +75 -0
- package/dist/lib/schemas-data/3.0.1/creative/get-creative-delivery-response.json +143 -0
- package/dist/lib/schemas-data/3.0.1/creative/get-creative-features-request.json +41 -0
- package/dist/lib/schemas-data/3.0.1/creative/get-creative-features-response.json +76 -0
- package/dist/lib/schemas-data/3.0.1/creative/list-creative-formats-request.json +150 -0
- package/dist/lib/schemas-data/3.0.1/creative/list-creative-formats-response.json +64 -0
- package/dist/lib/schemas-data/3.0.1/creative/list-creatives-request.json +184 -0
- package/dist/lib/schemas-data/3.0.1/creative/list-creatives-response.json +445 -0
- package/dist/lib/schemas-data/3.0.1/creative/preview-creative-request.json +212 -0
- package/dist/lib/schemas-data/3.0.1/creative/preview-creative-response.json +307 -0
- package/dist/lib/schemas-data/3.0.1/creative/preview-render.json +225 -0
- package/dist/lib/schemas-data/3.0.1/creative/sync-creatives-async-response-input-required.json +25 -0
- package/dist/lib/schemas-data/3.0.1/creative/sync-creatives-async-response-submitted.json +16 -0
- package/dist/lib/schemas-data/3.0.1/creative/sync-creatives-async-response-working.json +46 -0
- package/dist/lib/schemas-data/3.0.1/creative/sync-creatives-request.json +242 -0
- package/dist/lib/schemas-data/3.0.1/creative/sync-creatives-response.json +270 -0
- package/dist/lib/schemas-data/3.0.1/enums/account-scope.json +19 -0
- package/dist/lib/schemas-data/3.0.1/enums/account-status.json +23 -0
- package/dist/lib/schemas-data/3.0.1/enums/action-source.json +29 -0
- package/dist/lib/schemas-data/3.0.1/enums/adcp-protocol.json +23 -0
- package/dist/lib/schemas-data/3.0.1/enums/adjustment-kind.json +19 -0
- package/dist/lib/schemas-data/3.0.1/enums/advertiser-industry.json +175 -0
- package/dist/lib/schemas-data/3.0.1/enums/age-verification-method.json +14 -0
- package/dist/lib/schemas-data/3.0.1/enums/assessment-status.json +19 -0
- package/dist/lib/schemas-data/3.0.1/enums/asset-content-type.json +23 -0
- package/dist/lib/schemas-data/3.0.1/enums/attribution-model.json +14 -0
- package/dist/lib/schemas-data/3.0.1/enums/audience-source.json +15 -0
- package/dist/lib/schemas-data/3.0.1/enums/audience-status.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/audio-channel-layout.json +13 -0
- package/dist/lib/schemas-data/3.0.1/enums/auth-scheme.json +11 -0
- package/dist/lib/schemas-data/3.0.1/enums/available-metric.json +31 -0
- package/dist/lib/schemas-data/3.0.1/enums/billing-party.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/binary-verdict.json +15 -0
- package/dist/lib/schemas-data/3.0.1/enums/brand-agent-type.json +27 -0
- package/dist/lib/schemas-data/3.0.1/enums/canceled-by.json +15 -0
- package/dist/lib/schemas-data/3.0.1/enums/catalog-action.json +14 -0
- package/dist/lib/schemas-data/3.0.1/enums/catalog-item-status.json +19 -0
- package/dist/lib/schemas-data/3.0.1/enums/catalog-type.json +22 -0
- package/dist/lib/schemas-data/3.0.1/enums/channels.json +51 -0
- package/dist/lib/schemas-data/3.0.1/enums/cloud-storage-protocol.json +12 -0
- package/dist/lib/schemas-data/3.0.1/enums/co-branding-requirement.json +12 -0
- package/dist/lib/schemas-data/3.0.1/enums/collection-cadence.json +23 -0
- package/dist/lib/schemas-data/3.0.1/enums/collection-kind.json +19 -0
- package/dist/lib/schemas-data/3.0.1/enums/collection-relationship.json +21 -0
- package/dist/lib/schemas-data/3.0.1/enums/collection-status.json +19 -0
- package/dist/lib/schemas-data/3.0.1/enums/consent-basis.json +13 -0
- package/dist/lib/schemas-data/3.0.1/enums/content-id-type.json +21 -0
- package/dist/lib/schemas-data/3.0.1/enums/content-rating-system.json +33 -0
- package/dist/lib/schemas-data/3.0.1/enums/creative-action.json +14 -0
- package/dist/lib/schemas-data/3.0.1/enums/creative-agent-capability.json +14 -0
- package/dist/lib/schemas-data/3.0.1/enums/creative-approval-status.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/creative-identifier-type.json +22 -0
- package/dist/lib/schemas-data/3.0.1/enums/creative-quality.json +15 -0
- package/dist/lib/schemas-data/3.0.1/enums/creative-sort-field.json +14 -0
- package/dist/lib/schemas-data/3.0.1/enums/creative-status.json +21 -0
- package/dist/lib/schemas-data/3.0.1/enums/daast-tracking-event.json +32 -0
- package/dist/lib/schemas-data/3.0.1/enums/daast-version.json +11 -0
- package/dist/lib/schemas-data/3.0.1/enums/day-of-week.json +16 -0
- package/dist/lib/schemas-data/3.0.1/enums/delegation-authority.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/delivery-type.json +15 -0
- package/dist/lib/schemas-data/3.0.1/enums/demographic-system.json +23 -0
- package/dist/lib/schemas-data/3.0.1/enums/derivative-type.json +21 -0
- package/dist/lib/schemas-data/3.0.1/enums/device-platform.json +21 -0
- package/dist/lib/schemas-data/3.0.1/enums/device-type.json +15 -0
- package/dist/lib/schemas-data/3.0.1/enums/digital-source-type.json +29 -0
- package/dist/lib/schemas-data/3.0.1/enums/dimension-unit.json +15 -0
- package/dist/lib/schemas-data/3.0.1/enums/disclosure-persistence.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/disclosure-position.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/distance-unit.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/distribution-identifier-type.json +53 -0
- package/dist/lib/schemas-data/3.0.1/enums/error-code.json +101 -0
- package/dist/lib/schemas-data/3.0.1/enums/escalation-severity.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/event-type.json +67 -0
- package/dist/lib/schemas-data/3.0.1/enums/exclusivity.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/feature-check-status.json +19 -0
- package/dist/lib/schemas-data/3.0.1/enums/feed-format.json +14 -0
- package/dist/lib/schemas-data/3.0.1/enums/feedback-source.json +13 -0
- package/dist/lib/schemas-data/3.0.1/enums/forecast-method.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/forecast-range-unit.json +27 -0
- package/dist/lib/schemas-data/3.0.1/enums/forecastable-metric.json +43 -0
- package/dist/lib/schemas-data/3.0.1/enums/format-id-parameter.json +11 -0
- package/dist/lib/schemas-data/3.0.1/enums/frame-rate-type.json +15 -0
- package/dist/lib/schemas-data/3.0.1/enums/frequency-cap-scope.json +13 -0
- package/dist/lib/schemas-data/3.0.1/enums/genre-taxonomy.json +29 -0
- package/dist/lib/schemas-data/3.0.1/enums/geo-level.json +13 -0
- package/dist/lib/schemas-data/3.0.1/enums/gop-type.json +15 -0
- package/dist/lib/schemas-data/3.0.1/enums/governance-decision.json +18 -0
- package/dist/lib/schemas-data/3.0.1/enums/governance-domain.json +13 -0
- package/dist/lib/schemas-data/3.0.1/enums/governance-mode.json +18 -0
- package/dist/lib/schemas-data/3.0.1/enums/governance-phase.json +12 -0
- package/dist/lib/schemas-data/3.0.1/enums/history-entry-type.json +11 -0
- package/dist/lib/schemas-data/3.0.1/enums/http-method.json +11 -0
- package/dist/lib/schemas-data/3.0.1/enums/identifier-types.json +61 -0
- package/dist/lib/schemas-data/3.0.1/enums/installment-status.json +25 -0
- package/dist/lib/schemas-data/3.0.1/enums/javascript-module-type.json +12 -0
- package/dist/lib/schemas-data/3.0.1/enums/landing-page-requirement.json +12 -0
- package/dist/lib/schemas-data/3.0.1/enums/makegood-remedy.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/markdown-flavor.json +11 -0
- package/dist/lib/schemas-data/3.0.1/enums/match-id-type.json +29 -0
- package/dist/lib/schemas-data/3.0.1/enums/match-type.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/media-buy-status.json +25 -0
- package/dist/lib/schemas-data/3.0.1/enums/media-buy-valid-action.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/metric-type.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/metro-system.json +14 -0
- package/dist/lib/schemas-data/3.0.1/enums/moov-atom-position.json +15 -0
- package/dist/lib/schemas-data/3.0.1/enums/notification-type.json +13 -0
- package/dist/lib/schemas-data/3.0.1/enums/outcome-type.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/pacing.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/payment-terms.json +23 -0
- package/dist/lib/schemas-data/3.0.1/enums/performance-standard-metric.json +21 -0
- package/dist/lib/schemas-data/3.0.1/enums/policy-category.json +15 -0
- package/dist/lib/schemas-data/3.0.1/enums/policy-enforcement.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/postal-system.json +20 -0
- package/dist/lib/schemas-data/3.0.1/enums/preview-output-format.json +11 -0
- package/dist/lib/schemas-data/3.0.1/enums/pricing-model.json +29 -0
- package/dist/lib/schemas-data/3.0.1/enums/production-quality.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/property-type.json +31 -0
- package/dist/lib/schemas-data/3.0.1/enums/proposal-status.json +15 -0
- package/dist/lib/schemas-data/3.0.1/enums/publisher-identifier-types.json +19 -0
- package/dist/lib/schemas-data/3.0.1/enums/purchase-type.json +13 -0
- package/dist/lib/schemas-data/3.0.1/enums/reach-unit.json +23 -0
- package/dist/lib/schemas-data/3.0.1/enums/reporting-frequency.json +12 -0
- package/dist/lib/schemas-data/3.0.1/enums/response-type.json +19 -0
- package/dist/lib/schemas-data/3.0.1/enums/restricted-attribute.json +31 -0
- package/dist/lib/schemas-data/3.0.1/enums/right-type.json +22 -0
- package/dist/lib/schemas-data/3.0.1/enums/right-use.json +36 -0
- package/dist/lib/schemas-data/3.0.1/enums/rights-billing-period.json +15 -0
- package/dist/lib/schemas-data/3.0.1/enums/scan-type.json +15 -0
- package/dist/lib/schemas-data/3.0.1/enums/si-session-status.json +19 -0
- package/dist/lib/schemas-data/3.0.1/enums/signal-catalog-type.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/signal-source.json +15 -0
- package/dist/lib/schemas-data/3.0.1/enums/signal-value-type.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/snapshot-unavailable-reason.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/sort-direction.json +11 -0
- package/dist/lib/schemas-data/3.0.1/enums/sort-metric.json +31 -0
- package/dist/lib/schemas-data/3.0.1/enums/special-category.json +35 -0
- package/dist/lib/schemas-data/3.0.1/enums/specialism.json +55 -0
- package/dist/lib/schemas-data/3.0.1/enums/talent-role.json +29 -0
- package/dist/lib/schemas-data/3.0.1/enums/task-status.json +29 -0
- package/dist/lib/schemas-data/3.0.1/enums/task-type.json +57 -0
- package/dist/lib/schemas-data/3.0.1/enums/transport-mode.json +19 -0
- package/dist/lib/schemas-data/3.0.1/enums/travel-time-unit.json +15 -0
- package/dist/lib/schemas-data/3.0.1/enums/uid-type.json +31 -0
- package/dist/lib/schemas-data/3.0.1/enums/universal-macro.json +149 -0
- package/dist/lib/schemas-data/3.0.1/enums/update-frequency.json +13 -0
- package/dist/lib/schemas-data/3.0.1/enums/url-asset-type.json +12 -0
- package/dist/lib/schemas-data/3.0.1/enums/validation-mode.json +11 -0
- package/dist/lib/schemas-data/3.0.1/enums/vast-tracking-event.json +41 -0
- package/dist/lib/schemas-data/3.0.1/enums/vast-version.json +14 -0
- package/dist/lib/schemas-data/3.0.1/enums/viewability-standard.json +15 -0
- package/dist/lib/schemas-data/3.0.1/enums/wcag-level.json +17 -0
- package/dist/lib/schemas-data/3.0.1/enums/webhook-response-type.json +13 -0
- package/dist/lib/schemas-data/3.0.1/enums/webhook-security-method.json +12 -0
- package/dist/lib/schemas-data/3.0.1/error-details/account-setup-required.json +22 -0
- package/dist/lib/schemas-data/3.0.1/error-details/audience-too-small.json +18 -0
- package/dist/lib/schemas-data/3.0.1/error-details/budget-too-low.json +18 -0
- package/dist/lib/schemas-data/3.0.1/error-details/conflict.json +28 -0
- package/dist/lib/schemas-data/3.0.1/error-details/creative-rejected.json +27 -0
- package/dist/lib/schemas-data/3.0.1/error-details/policy-violation.json +27 -0
- package/dist/lib/schemas-data/3.0.1/error-details/rate-limited.json +31 -0
- package/dist/lib/schemas-data/3.0.1/error-details/vendor-error-codes.json +55 -0
- package/dist/lib/schemas-data/3.0.1/extensions/extension-meta.json +69 -0
- package/dist/lib/schemas-data/3.0.1/extensions/index.json +9 -0
- package/dist/lib/schemas-data/3.0.1/governance/attribute-definition.json +82 -0
- package/dist/lib/schemas-data/3.0.1/governance/audience-constraints.json +27 -0
- package/dist/lib/schemas-data/3.0.1/governance/check-governance-request.json +198 -0
- package/dist/lib/schemas-data/3.0.1/governance/check-governance-response.json +217 -0
- package/dist/lib/schemas-data/3.0.1/governance/get-plan-audit-logs-request.json +79 -0
- package/dist/lib/schemas-data/3.0.1/governance/get-plan-audit-logs-response.json +423 -0
- package/dist/lib/schemas-data/3.0.1/governance/policy-category-definition.json +95 -0
- package/dist/lib/schemas-data/3.0.1/governance/policy-entry.json +165 -0
- package/dist/lib/schemas-data/3.0.1/governance/policy-ref.json +27 -0
- package/dist/lib/schemas-data/3.0.1/governance/report-plan-outcome-request.json +165 -0
- package/dist/lib/schemas-data/3.0.1/governance/report-plan-outcome-response.json +89 -0
- package/dist/lib/schemas-data/3.0.1/governance/sync-plans-request.json +449 -0
- package/dist/lib/schemas-data/3.0.1/governance/sync-plans-response.json +119 -0
- package/dist/lib/schemas-data/3.0.1/index.json +1678 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/build-creative-async-response-input-required.json +32 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/build-creative-async-response-submitted.json +16 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/build-creative-async-response-working.json +36 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/build-creative-request.json +138 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/build-creative-response.json +293 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/create-media-buy-async-response-input-required.json +31 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/create-media-buy-async-response-submitted.json +16 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/create-media-buy-async-response-working.json +36 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/create-media-buy-request.json +221 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/create-media-buy-response.json +194 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/get-media-buy-delivery-request.json +205 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/get-media-buy-delivery-response.json +704 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/get-media-buys-request.json +66 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/get-media-buys-response.json +394 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/get-products-async-response-input-required.json +38 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/get-products-async-response-submitted.json +21 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/get-products-async-response-working.json +34 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/get-products-request.json +229 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/get-products-response.json +195 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/list-creative-formats-request.json +103 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/list-creative-formats-response.json +68 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/log-event-request.json +53 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/log-event-response.json +130 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/package-request.json +133 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/package-update.json +202 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/provide-performance-feedback-request.json +73 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/provide-performance-feedback-response.json +79 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/sync-audiences-request.json +127 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/sync-audiences-response.json +191 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/sync-catalogs-async-response-input-required.json +26 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/sync-catalogs-async-response-submitted.json +16 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/sync-catalogs-async-response-working.json +56 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/sync-catalogs-request.json +162 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/sync-catalogs-response.json +213 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/sync-event-sources-request.json +82 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/sync-event-sources-response.json +167 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/update-media-buy-async-response-input-required.json +24 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/update-media-buy-async-response-submitted.json +16 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/update-media-buy-async-response-working.json +36 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/update-media-buy-request.json +99 -0
- package/dist/lib/schemas-data/3.0.1/media-buy/update-media-buy-response.json +119 -0
- package/dist/lib/schemas-data/3.0.1/pricing-options/cpa-option.json +75 -0
- package/dist/lib/schemas-data/3.0.1/pricing-options/cpc-option.json +71 -0
- package/dist/lib/schemas-data/3.0.1/pricing-options/cpcv-option.json +71 -0
- package/dist/lib/schemas-data/3.0.1/pricing-options/cpm-option.json +71 -0
- package/dist/lib/schemas-data/3.0.1/pricing-options/cpp-option.json +90 -0
- package/dist/lib/schemas-data/3.0.1/pricing-options/cpv-option.json +107 -0
- package/dist/lib/schemas-data/3.0.1/pricing-options/flat-rate-option.json +116 -0
- package/dist/lib/schemas-data/3.0.1/pricing-options/price-breakdown.json +88 -0
- package/dist/lib/schemas-data/3.0.1/pricing-options/price-guidance.json +30 -0
- package/dist/lib/schemas-data/3.0.1/pricing-options/time-option.json +97 -0
- package/dist/lib/schemas-data/3.0.1/pricing-options/vcpm-option.json +71 -0
- package/dist/lib/schemas-data/3.0.1/property/authorization-result.json +50 -0
- package/dist/lib/schemas-data/3.0.1/property/base-property-source.json +98 -0
- package/dist/lib/schemas-data/3.0.1/property/create-property-list-request.json +62 -0
- package/dist/lib/schemas-data/3.0.1/property/create-property-list-response.json +33 -0
- package/dist/lib/schemas-data/3.0.1/property/delete-property-list-request.json +43 -0
- package/dist/lib/schemas-data/3.0.1/property/delete-property-list-response.json +34 -0
- package/dist/lib/schemas-data/3.0.1/property/delivery-record.json +35 -0
- package/dist/lib/schemas-data/3.0.1/property/get-property-list-request.json +57 -0
- package/dist/lib/schemas-data/3.0.1/property/get-property-list-response.json +53 -0
- package/dist/lib/schemas-data/3.0.1/property/list-property-lists-request.json +33 -0
- package/dist/lib/schemas-data/3.0.1/property/list-property-lists-response.json +29 -0
- package/dist/lib/schemas-data/3.0.1/property/property-error.json +34 -0
- package/dist/lib/schemas-data/3.0.1/property/property-feature-definition.json +96 -0
- package/dist/lib/schemas-data/3.0.1/property/property-feature-result.json +50 -0
- package/dist/lib/schemas-data/3.0.1/property/property-feature-value.json +59 -0
- package/dist/lib/schemas-data/3.0.1/property/property-feature.json +26 -0
- package/dist/lib/schemas-data/3.0.1/property/property-list-changed-webhook.json +74 -0
- package/dist/lib/schemas-data/3.0.1/property/property-list-filters.json +51 -0
- package/dist/lib/schemas-data/3.0.1/property/property-list.json +79 -0
- package/dist/lib/schemas-data/3.0.1/property/update-property-list-request.json +71 -0
- package/dist/lib/schemas-data/3.0.1/property/update-property-list-response.json +28 -0
- package/dist/lib/schemas-data/3.0.1/property/validate-property-delivery-request.json +49 -0
- package/dist/lib/schemas-data/3.0.1/property/validate-property-delivery-response.json +180 -0
- package/dist/lib/schemas-data/3.0.1/property/validation-result.json +101 -0
- package/dist/lib/schemas-data/3.0.1/protocol/get-adcp-capabilities-request.json +37 -0
- package/dist/lib/schemas-data/3.0.1/protocol/get-adcp-capabilities-response.json +1108 -0
- package/dist/lib/schemas-data/3.0.1/signals/activate-signal-request.json +66 -0
- package/dist/lib/schemas-data/3.0.1/signals/activate-signal-response.json +81 -0
- package/dist/lib/schemas-data/3.0.1/signals/get-signals-request.json +80 -0
- package/dist/lib/schemas-data/3.0.1/signals/get-signals-response.json +130 -0
- package/dist/lib/schemas-data/3.0.1/sponsored-intelligence/si-capabilities.json +154 -0
- package/dist/lib/schemas-data/3.0.1/sponsored-intelligence/si-get-offering-request.json +47 -0
- package/dist/lib/schemas-data/3.0.1/sponsored-intelligence/si-get-offering-response.json +150 -0
- package/dist/lib/schemas-data/3.0.1/sponsored-intelligence/si-identity.json +104 -0
- package/dist/lib/schemas-data/3.0.1/sponsored-intelligence/si-initiate-session-request.json +65 -0
- package/dist/lib/schemas-data/3.0.1/sponsored-intelligence/si-initiate-session-response.json +64 -0
- package/dist/lib/schemas-data/3.0.1/sponsored-intelligence/si-send-message-request.json +71 -0
- package/dist/lib/schemas-data/3.0.1/sponsored-intelligence/si-send-message-response.json +123 -0
- package/dist/lib/schemas-data/3.0.1/sponsored-intelligence/si-terminate-session-request.json +77 -0
- package/dist/lib/schemas-data/3.0.1/sponsored-intelligence/si-terminate-session-response.json +86 -0
- package/dist/lib/schemas-data/3.0.1/sponsored-intelligence/si-ui-element.json +341 -0
- package/dist/lib/server/a2a-adapter.d.ts +234 -0
- package/dist/lib/server/a2a-adapter.d.ts.map +1 -0
- package/dist/lib/server/a2a-adapter.js +503 -0
- package/dist/lib/server/a2a-adapter.js.map +1 -0
- package/dist/lib/server/adcp-server.d.ts +265 -0
- package/dist/lib/server/adcp-server.d.ts.map +1 -0
- package/dist/lib/server/adcp-server.js +187 -0
- package/dist/lib/server/adcp-server.js.map +1 -0
- package/dist/lib/server/auth-introspection.d.ts +83 -0
- package/dist/lib/server/auth-introspection.d.ts.map +1 -0
- package/dist/lib/server/auth-introspection.js +297 -0
- package/dist/lib/server/auth-introspection.js.map +1 -0
- package/dist/lib/server/auth-signature.d.ts +322 -0
- package/dist/lib/server/auth-signature.d.ts.map +1 -0
- package/dist/lib/server/auth-signature.js +310 -0
- package/dist/lib/server/auth-signature.js.map +1 -0
- package/dist/lib/server/auth.d.ts +303 -0
- package/dist/lib/server/auth.d.ts.map +1 -0
- package/dist/lib/server/auth.js +387 -0
- package/dist/lib/server/auth.js.map +1 -0
- package/dist/lib/server/create-adcp-server.d.ts +968 -0
- package/dist/lib/server/create-adcp-server.d.ts.map +1 -0
- package/dist/lib/server/create-adcp-server.js +1831 -0
- package/dist/lib/server/create-adcp-server.js.map +1 -0
- package/dist/lib/server/envelope-allowlist.d.ts +109 -0
- package/dist/lib/server/envelope-allowlist.d.ts.map +1 -0
- package/dist/lib/server/envelope-allowlist.js +155 -0
- package/dist/lib/server/envelope-allowlist.js.map +1 -0
- package/dist/lib/server/errors.d.ts +129 -0
- package/dist/lib/server/errors.d.ts.map +1 -0
- package/dist/lib/server/errors.js +85 -0
- package/dist/lib/server/errors.js.map +1 -0
- package/dist/lib/server/express-adapter.d.ts +169 -0
- package/dist/lib/server/express-adapter.d.ts.map +1 -0
- package/dist/lib/server/express-adapter.js +271 -0
- package/dist/lib/server/express-adapter.js.map +1 -0
- package/dist/lib/server/governance.d.ts +122 -0
- package/dist/lib/server/governance.d.ts.map +1 -0
- package/dist/lib/server/governance.js +189 -0
- package/dist/lib/server/governance.js.map +1 -0
- package/dist/lib/server/idempotency/backends/memory.d.ts +22 -0
- package/dist/lib/server/idempotency/backends/memory.d.ts.map +1 -0
- package/dist/lib/server/idempotency/backends/memory.js +78 -0
- package/dist/lib/server/idempotency/backends/memory.js.map +1 -0
- package/dist/lib/server/idempotency/backends/pg.d.ts +76 -0
- package/dist/lib/server/idempotency/backends/pg.d.ts.map +1 -0
- package/dist/lib/server/idempotency/backends/pg.js +163 -0
- package/dist/lib/server/idempotency/backends/pg.js.map +1 -0
- package/dist/lib/server/idempotency/index.d.ts +7 -0
- package/dist/lib/server/idempotency/index.d.ts.map +1 -0
- package/dist/lib/server/idempotency/index.js +15 -0
- package/dist/lib/server/idempotency/index.js.map +1 -0
- package/dist/lib/server/idempotency/store.d.ts +302 -0
- package/dist/lib/server/idempotency/store.d.ts.map +1 -0
- package/dist/lib/server/idempotency/store.js +272 -0
- package/dist/lib/server/idempotency/store.js.map +1 -0
- package/dist/lib/server/index.d.ts +50 -0
- package/dist/lib/server/index.d.ts.map +1 -0
- package/dist/lib/server/index.js +164 -0
- package/dist/lib/server/index.js.map +1 -0
- package/dist/lib/server/media-buy-helpers.d.ts +47 -0
- package/dist/lib/server/media-buy-helpers.d.ts.map +1 -0
- package/dist/lib/server/media-buy-helpers.js +43 -0
- package/dist/lib/server/media-buy-helpers.js.map +1 -0
- package/dist/lib/server/pin-and-bind-fetch.d.ts +115 -0
- package/dist/lib/server/pin-and-bind-fetch.d.ts.map +1 -0
- package/dist/lib/server/pin-and-bind-fetch.js +244 -0
- package/dist/lib/server/pin-and-bind-fetch.js.map +1 -0
- package/dist/lib/server/postgres-state-store.d.ts +76 -0
- package/dist/lib/server/postgres-state-store.d.ts.map +1 -0
- package/dist/lib/server/postgres-state-store.js +218 -0
- package/dist/lib/server/postgres-state-store.js.map +1 -0
- package/dist/lib/server/postgres-task-store.d.ts +121 -0
- package/dist/lib/server/postgres-task-store.d.ts.map +1 -0
- package/dist/lib/server/postgres-task-store.js +298 -0
- package/dist/lib/server/postgres-task-store.js.map +1 -0
- package/dist/lib/server/product-defaults.d.ts +16 -0
- package/dist/lib/server/product-defaults.d.ts.map +1 -0
- package/dist/lib/server/product-defaults.js +25 -0
- package/dist/lib/server/product-defaults.js.map +1 -0
- package/dist/lib/server/responses.d.ts +257 -0
- package/dist/lib/server/responses.d.ts.map +1 -0
- package/dist/lib/server/responses.js +542 -0
- package/dist/lib/server/responses.js.map +1 -0
- package/dist/lib/server/serve.d.ts +308 -0
- package/dist/lib/server/serve.d.ts.map +1 -0
- package/dist/lib/server/serve.js +663 -0
- package/dist/lib/server/serve.js.map +1 -0
- package/dist/lib/server/state-store.d.ts +296 -0
- package/dist/lib/server/state-store.d.ts.map +1 -0
- package/dist/lib/server/state-store.js +459 -0
- package/dist/lib/server/state-store.js.map +1 -0
- package/dist/lib/server/structured-serialize.d.ts +30 -0
- package/dist/lib/server/structured-serialize.d.ts.map +1 -0
- package/dist/lib/server/structured-serialize.js +109 -0
- package/dist/lib/server/structured-serialize.js.map +1 -0
- package/dist/lib/server/targeting-helpers.d.ts +90 -0
- package/dist/lib/server/targeting-helpers.d.ts.map +1 -0
- package/dist/lib/server/targeting-helpers.js +144 -0
- package/dist/lib/server/targeting-helpers.js.map +1 -0
- package/dist/lib/server/tasks.d.ts +91 -0
- package/dist/lib/server/tasks.d.ts.map +1 -0
- package/dist/lib/server/tasks.js +116 -0
- package/dist/lib/server/tasks.js.map +1 -0
- package/dist/lib/server/test-controller-bridge.d.ts +192 -0
- package/dist/lib/server/test-controller-bridge.d.ts.map +1 -0
- package/dist/lib/server/test-controller-bridge.js +207 -0
- package/dist/lib/server/test-controller-bridge.js.map +1 -0
- package/dist/lib/server/test-controller.d.ts +388 -0
- package/dist/lib/server/test-controller.d.ts.map +1 -0
- package/dist/lib/server/test-controller.js +735 -0
- package/dist/lib/server/test-controller.js.map +1 -0
- package/dist/lib/server/webhook-emitter.d.ts +192 -0
- package/dist/lib/server/webhook-emitter.d.ts.map +1 -0
- package/dist/lib/server/webhook-emitter.js +316 -0
- package/dist/lib/server/webhook-emitter.js.map +1 -0
- package/dist/lib/server/wrap-envelope.d.ts +162 -0
- package/dist/lib/server/wrap-envelope.d.ts.map +1 -0
- package/dist/lib/server/wrap-envelope.js +145 -0
- package/dist/lib/server/wrap-envelope.js.map +1 -0
- package/dist/lib/signing/agent-context.d.ts +73 -0
- package/dist/lib/signing/agent-context.d.ts.map +1 -0
- package/dist/lib/signing/agent-context.js +104 -0
- package/dist/lib/signing/agent-context.js.map +1 -0
- package/dist/lib/signing/agent-fetch.d.ts +177 -0
- package/dist/lib/signing/agent-fetch.d.ts.map +1 -0
- package/dist/lib/signing/agent-fetch.js +271 -0
- package/dist/lib/signing/agent-fetch.js.map +1 -0
- package/dist/lib/signing/brand-jwks.d.ts +102 -0
- package/dist/lib/signing/brand-jwks.d.ts.map +1 -0
- package/dist/lib/signing/brand-jwks.js +433 -0
- package/dist/lib/signing/brand-jwks.js.map +1 -0
- package/dist/lib/signing/canonicalize.d.ts +39 -0
- package/dist/lib/signing/canonicalize.d.ts.map +1 -0
- package/dist/lib/signing/canonicalize.js +149 -0
- package/dist/lib/signing/canonicalize.js.map +1 -0
- package/dist/lib/signing/capability-cache.d.ts +70 -0
- package/dist/lib/signing/capability-cache.d.ts.map +1 -0
- package/dist/lib/signing/capability-cache.js +90 -0
- package/dist/lib/signing/capability-cache.js.map +1 -0
- package/dist/lib/signing/capability-priming.d.ts +30 -0
- package/dist/lib/signing/capability-priming.d.ts.map +1 -0
- package/dist/lib/signing/capability-priming.js +145 -0
- package/dist/lib/signing/capability-priming.js.map +1 -0
- package/dist/lib/signing/client.d.ts +25 -0
- package/dist/lib/signing/client.d.ts.map +1 -0
- package/dist/lib/signing/client.js +70 -0
- package/dist/lib/signing/client.js.map +1 -0
- package/dist/lib/signing/content-digest.d.ts +9 -0
- package/dist/lib/signing/content-digest.d.ts.map +1 -0
- package/dist/lib/signing/content-digest.js +48 -0
- package/dist/lib/signing/content-digest.js.map +1 -0
- package/dist/lib/signing/crypto.d.ts +5 -0
- package/dist/lib/signing/crypto.d.ts.map +1 -0
- package/dist/lib/signing/crypto.js +35 -0
- package/dist/lib/signing/crypto.js.map +1 -0
- package/dist/lib/signing/ecdsa-encoding.d.ts +20 -0
- package/dist/lib/signing/ecdsa-encoding.d.ts.map +1 -0
- package/dist/lib/signing/ecdsa-encoding.js +91 -0
- package/dist/lib/signing/ecdsa-encoding.js.map +1 -0
- package/dist/lib/signing/errors.d.ts +49 -0
- package/dist/lib/signing/errors.d.ts.map +1 -0
- package/dist/lib/signing/errors.js +48 -0
- package/dist/lib/signing/errors.js.map +1 -0
- package/dist/lib/signing/fetch-async.d.ts +23 -0
- package/dist/lib/signing/fetch-async.d.ts.map +1 -0
- package/dist/lib/signing/fetch-async.js +96 -0
- package/dist/lib/signing/fetch-async.js.map +1 -0
- package/dist/lib/signing/fetch.d.ts +17 -0
- package/dist/lib/signing/fetch.d.ts.map +1 -0
- package/dist/lib/signing/fetch.js +89 -0
- package/dist/lib/signing/fetch.js.map +1 -0
- package/dist/lib/signing/index.d.ts +16 -0
- package/dist/lib/signing/index.d.ts.map +1 -0
- package/dist/lib/signing/index.js +32 -0
- package/dist/lib/signing/index.js.map +1 -0
- package/dist/lib/signing/jwks-helpers.d.ts +48 -0
- package/dist/lib/signing/jwks-helpers.d.ts.map +1 -0
- package/dist/lib/signing/jwks-helpers.js +87 -0
- package/dist/lib/signing/jwks-helpers.js.map +1 -0
- package/dist/lib/signing/jwks-https.d.ts +61 -0
- package/dist/lib/signing/jwks-https.d.ts.map +1 -0
- package/dist/lib/signing/jwks-https.js +165 -0
- package/dist/lib/signing/jwks-https.js.map +1 -0
- package/dist/lib/signing/jwks.d.ts +10 -0
- package/dist/lib/signing/jwks.d.ts.map +1 -0
- package/dist/lib/signing/jwks.js +15 -0
- package/dist/lib/signing/jwks.js.map +1 -0
- package/dist/lib/signing/middleware.d.ts +77 -0
- package/dist/lib/signing/middleware.d.ts.map +1 -0
- package/dist/lib/signing/middleware.js +77 -0
- package/dist/lib/signing/middleware.js.map +1 -0
- package/dist/lib/signing/parser.d.ts +35 -0
- package/dist/lib/signing/parser.d.ts.map +1 -0
- package/dist/lib/signing/parser.js +244 -0
- package/dist/lib/signing/parser.js.map +1 -0
- package/dist/lib/signing/postgres-replay-store.d.ts +138 -0
- package/dist/lib/signing/postgres-replay-store.d.ts.map +1 -0
- package/dist/lib/signing/postgres-replay-store.js +236 -0
- package/dist/lib/signing/postgres-replay-store.js.map +1 -0
- package/dist/lib/signing/provider.d.ts +81 -0
- package/dist/lib/signing/provider.d.ts.map +1 -0
- package/dist/lib/signing/provider.js +3 -0
- package/dist/lib/signing/provider.js.map +1 -0
- package/dist/lib/signing/replay.d.ts +62 -0
- package/dist/lib/signing/replay.d.ts.map +1 -0
- package/dist/lib/signing/replay.js +106 -0
- package/dist/lib/signing/replay.js.map +1 -0
- package/dist/lib/signing/revocation-https.d.ts +79 -0
- package/dist/lib/signing/revocation-https.d.ts.map +1 -0
- package/dist/lib/signing/revocation-https.js +144 -0
- package/dist/lib/signing/revocation-https.js.map +1 -0
- package/dist/lib/signing/revocation.d.ts +11 -0
- package/dist/lib/signing/revocation.d.ts.map +1 -0
- package/dist/lib/signing/revocation.js +18 -0
- package/dist/lib/signing/revocation.js.map +1 -0
- package/dist/lib/signing/server.d.ts +27 -0
- package/dist/lib/signing/server.d.ts.map +1 -0
- package/dist/lib/signing/server.js +67 -0
- package/dist/lib/signing/server.js.map +1 -0
- package/dist/lib/signing/signer-async.d.ts +24 -0
- package/dist/lib/signing/signer-async.d.ts.map +1 -0
- package/dist/lib/signing/signer-async.js +34 -0
- package/dist/lib/signing/signer-async.js.map +1 -0
- package/dist/lib/signing/signer.d.ts +94 -0
- package/dist/lib/signing/signer.d.ts.map +1 -0
- package/dist/lib/signing/signer.js +131 -0
- package/dist/lib/signing/signer.js.map +1 -0
- package/dist/lib/signing/testing.d.ts +45 -0
- package/dist/lib/signing/testing.d.ts.map +1 -0
- package/dist/lib/signing/testing.js +81 -0
- package/dist/lib/signing/testing.js.map +1 -0
- package/dist/lib/signing/types.d.ts +90 -0
- package/dist/lib/signing/types.d.ts.map +1 -0
- package/dist/lib/signing/types.js +9 -0
- package/dist/lib/signing/types.js.map +1 -0
- package/dist/lib/signing/verifier.d.ts +23 -0
- package/dist/lib/signing/verifier.d.ts.map +1 -0
- package/dist/lib/signing/verifier.js +386 -0
- package/dist/lib/signing/verifier.js.map +1 -0
- package/dist/lib/signing/webhook-verifier.d.ts +119 -0
- package/dist/lib/signing/webhook-verifier.d.ts.map +1 -0
- package/dist/lib/signing/webhook-verifier.js +292 -0
- package/dist/lib/signing/webhook-verifier.js.map +1 -0
- package/dist/lib/storage/MemoryStorage.d.ts +93 -0
- package/dist/lib/storage/MemoryStorage.d.ts.map +1 -0
- package/dist/lib/storage/MemoryStorage.js +219 -0
- package/dist/lib/storage/MemoryStorage.js.map +1 -0
- package/dist/lib/storage/interfaces.d.ts +195 -0
- package/dist/lib/storage/interfaces.d.ts.map +1 -0
- package/dist/lib/storage/interfaces.js +5 -0
- package/dist/lib/storage/interfaces.js.map +1 -0
- package/dist/lib/substitution/encoder/SubstitutionEncoder.d.ts +45 -0
- package/dist/lib/substitution/encoder/SubstitutionEncoder.d.ts.map +1 -0
- package/dist/lib/substitution/encoder/SubstitutionEncoder.js +73 -0
- package/dist/lib/substitution/encoder/SubstitutionEncoder.js.map +1 -0
- package/dist/lib/substitution/encoder/index.d.ts +2 -0
- package/dist/lib/substitution/encoder/index.d.ts.map +1 -0
- package/dist/lib/substitution/encoder/index.js +7 -0
- package/dist/lib/substitution/encoder/index.js.map +1 -0
- package/dist/lib/substitution/index.d.ts +36 -0
- package/dist/lib/substitution/index.d.ts.map +1 -0
- package/dist/lib/substitution/index.js +56 -0
- package/dist/lib/substitution/index.js.map +1 -0
- package/dist/lib/substitution/observer/SubstitutionObserver.d.ts +91 -0
- package/dist/lib/substitution/observer/SubstitutionObserver.d.ts.map +1 -0
- package/dist/lib/substitution/observer/SubstitutionObserver.js +248 -0
- package/dist/lib/substitution/observer/SubstitutionObserver.js.map +1 -0
- package/dist/lib/substitution/observer/alignment.d.ts +24 -0
- package/dist/lib/substitution/observer/alignment.d.ts.map +1 -0
- package/dist/lib/substitution/observer/alignment.js +279 -0
- package/dist/lib/substitution/observer/alignment.js.map +1 -0
- package/dist/lib/substitution/observer/assertions.d.ts +48 -0
- package/dist/lib/substitution/observer/assertions.d.ts.map +1 -0
- package/dist/lib/substitution/observer/assertions.js +145 -0
- package/dist/lib/substitution/observer/assertions.js.map +1 -0
- package/dist/lib/substitution/observer/html-parser.d.ts +29 -0
- package/dist/lib/substitution/observer/html-parser.d.ts.map +1 -0
- package/dist/lib/substitution/observer/html-parser.js +308 -0
- package/dist/lib/substitution/observer/html-parser.js.map +1 -0
- package/dist/lib/substitution/observer/index.d.ts +7 -0
- package/dist/lib/substitution/observer/index.d.ts.map +1 -0
- package/dist/lib/substitution/observer/index.js +21 -0
- package/dist/lib/substitution/observer/index.js.map +1 -0
- package/dist/lib/substitution/observer/ssrf.d.ts +29 -0
- package/dist/lib/substitution/observer/ssrf.d.ts.map +1 -0
- package/dist/lib/substitution/observer/ssrf.js +226 -0
- package/dist/lib/substitution/observer/ssrf.js.map +1 -0
- package/dist/lib/substitution/rfc3986.d.ts +51 -0
- package/dist/lib/substitution/rfc3986.d.ts.map +1 -0
- package/dist/lib/substitution/rfc3986.js +139 -0
- package/dist/lib/substitution/rfc3986.js.map +1 -0
- package/dist/lib/substitution/types.d.ts +147 -0
- package/dist/lib/substitution/types.d.ts.map +1 -0
- package/dist/lib/substitution/types.js +8 -0
- package/dist/lib/substitution/types.js.map +1 -0
- package/dist/lib/substitution/vectors.d.ts +18 -0
- package/dist/lib/substitution/vectors.d.ts.map +1 -0
- package/dist/lib/substitution/vectors.js +79 -0
- package/dist/lib/substitution/vectors.js.map +1 -0
- package/dist/lib/testing/agent-tester.d.ts +34 -0
- package/dist/lib/testing/agent-tester.d.ts.map +1 -0
- package/dist/lib/testing/agent-tester.js +421 -0
- package/dist/lib/testing/agent-tester.js.map +1 -0
- package/dist/lib/testing/client.d.ts +104 -0
- package/dist/lib/testing/client.d.ts.map +1 -0
- package/dist/lib/testing/client.js +487 -0
- package/dist/lib/testing/client.js.map +1 -0
- package/dist/lib/testing/compliance/briefs.d.ts +11 -0
- package/dist/lib/testing/compliance/briefs.d.ts.map +1 -0
- package/dist/lib/testing/compliance/briefs.js +156 -0
- package/dist/lib/testing/compliance/briefs.js.map +1 -0
- package/dist/lib/testing/compliance/comply.d.ts +83 -0
- package/dist/lib/testing/compliance/comply.d.ts.map +1 -0
- package/dist/lib/testing/compliance/comply.js +1275 -0
- package/dist/lib/testing/compliance/comply.js.map +1 -0
- package/dist/lib/testing/compliance/index.d.ts +10 -0
- package/dist/lib/testing/compliance/index.d.ts.map +1 -0
- package/dist/lib/testing/compliance/index.js +18 -0
- package/dist/lib/testing/compliance/index.js.map +1 -0
- package/dist/lib/testing/compliance/storyboard-tracks.d.ts +17 -0
- package/dist/lib/testing/compliance/storyboard-tracks.d.ts.map +1 -0
- package/dist/lib/testing/compliance/storyboard-tracks.js +147 -0
- package/dist/lib/testing/compliance/storyboard-tracks.js.map +1 -0
- package/dist/lib/testing/compliance/types.d.ts +145 -0
- package/dist/lib/testing/compliance/types.d.ts.map +1 -0
- package/dist/lib/testing/compliance/types.js +6 -0
- package/dist/lib/testing/compliance/types.js.map +1 -0
- package/dist/lib/testing/comply-controller.d.ts +193 -0
- package/dist/lib/testing/comply-controller.d.ts.map +1 -0
- package/dist/lib/testing/comply-controller.js +199 -0
- package/dist/lib/testing/comply-controller.js.map +1 -0
- package/dist/lib/testing/controller-assertions.d.ts +67 -0
- package/dist/lib/testing/controller-assertions.d.ts.map +1 -0
- package/dist/lib/testing/controller-assertions.js +60 -0
- package/dist/lib/testing/controller-assertions.js.map +1 -0
- package/dist/lib/testing/formatter.d.ts +17 -0
- package/dist/lib/testing/formatter.d.ts.map +1 -0
- package/dist/lib/testing/formatter.js +92 -0
- package/dist/lib/testing/formatter.js.map +1 -0
- package/dist/lib/testing/index.d.ts +19 -0
- package/dist/lib/testing/index.d.ts.map +1 -0
- package/dist/lib/testing/index.js +185 -0
- package/dist/lib/testing/index.js.map +1 -0
- package/dist/lib/testing/local-agent-runner.d.ts +189 -0
- package/dist/lib/testing/local-agent-runner.d.ts.map +1 -0
- package/dist/lib/testing/local-agent-runner.js +290 -0
- package/dist/lib/testing/local-agent-runner.js.map +1 -0
- package/dist/lib/testing/orchestrator.d.ts +70 -0
- package/dist/lib/testing/orchestrator.d.ts.map +1 -0
- package/dist/lib/testing/orchestrator.js +278 -0
- package/dist/lib/testing/orchestrator.js.map +1 -0
- package/dist/lib/testing/scenarios/brand-rights.d.ts +41 -0
- package/dist/lib/testing/scenarios/brand-rights.d.ts.map +1 -0
- package/dist/lib/testing/scenarios/brand-rights.js +278 -0
- package/dist/lib/testing/scenarios/brand-rights.js.map +1 -0
- package/dist/lib/testing/scenarios/capabilities.d.ts +27 -0
- package/dist/lib/testing/scenarios/capabilities.d.ts.map +1 -0
- package/dist/lib/testing/scenarios/capabilities.js +332 -0
- package/dist/lib/testing/scenarios/capabilities.js.map +1 -0
- package/dist/lib/testing/scenarios/creative.d.ts +38 -0
- package/dist/lib/testing/scenarios/creative.d.ts.map +1 -0
- package/dist/lib/testing/scenarios/creative.js +429 -0
- package/dist/lib/testing/scenarios/creative.js.map +1 -0
- package/dist/lib/testing/scenarios/deterministic.d.ts +37 -0
- package/dist/lib/testing/scenarios/deterministic.d.ts.map +1 -0
- package/dist/lib/testing/scenarios/deterministic.js +705 -0
- package/dist/lib/testing/scenarios/deterministic.js.map +1 -0
- package/dist/lib/testing/scenarios/discovery.d.ts +15 -0
- package/dist/lib/testing/scenarios/discovery.d.ts.map +1 -0
- package/dist/lib/testing/scenarios/discovery.js +68 -0
- package/dist/lib/testing/scenarios/discovery.js.map +1 -0
- package/dist/lib/testing/scenarios/edge-cases.d.ts +64 -0
- package/dist/lib/testing/scenarios/edge-cases.d.ts.map +1 -0
- package/dist/lib/testing/scenarios/edge-cases.js +569 -0
- package/dist/lib/testing/scenarios/edge-cases.js.map +1 -0
- package/dist/lib/testing/scenarios/error-compliance.d.ts +30 -0
- package/dist/lib/testing/scenarios/error-compliance.d.ts.map +1 -0
- package/dist/lib/testing/scenarios/error-compliance.js +372 -0
- package/dist/lib/testing/scenarios/error-compliance.js.map +1 -0
- package/dist/lib/testing/scenarios/governance.d.ts +114 -0
- package/dist/lib/testing/scenarios/governance.d.ts.map +1 -0
- package/dist/lib/testing/scenarios/governance.js +1619 -0
- package/dist/lib/testing/scenarios/governance.js.map +1 -0
- package/dist/lib/testing/scenarios/health.d.ts +12 -0
- package/dist/lib/testing/scenarios/health.d.ts.map +1 -0
- package/dist/lib/testing/scenarios/health.js +21 -0
- package/dist/lib/testing/scenarios/health.js.map +1 -0
- package/dist/lib/testing/scenarios/index.d.ts +20 -0
- package/dist/lib/testing/scenarios/index.d.ts.map +1 -0
- package/dist/lib/testing/scenarios/index.js +96 -0
- package/dist/lib/testing/scenarios/index.js.map +1 -0
- package/dist/lib/testing/scenarios/media-buy.d.ts +128 -0
- package/dist/lib/testing/scenarios/media-buy.d.ts.map +1 -0
- package/dist/lib/testing/scenarios/media-buy.js +1655 -0
- package/dist/lib/testing/scenarios/media-buy.js.map +1 -0
- package/dist/lib/testing/scenarios/schema-compliance.d.ts +17 -0
- package/dist/lib/testing/scenarios/schema-compliance.d.ts.map +1 -0
- package/dist/lib/testing/scenarios/schema-compliance.js +194 -0
- package/dist/lib/testing/scenarios/schema-compliance.js.map +1 -0
- package/dist/lib/testing/scenarios/signals.d.ts +22 -0
- package/dist/lib/testing/scenarios/signals.d.ts.map +1 -0
- package/dist/lib/testing/scenarios/signals.js +221 -0
- package/dist/lib/testing/scenarios/signals.js.map +1 -0
- package/dist/lib/testing/scenarios/sponsored-intelligence.d.ts +45 -0
- package/dist/lib/testing/scenarios/sponsored-intelligence.d.ts.map +1 -0
- package/dist/lib/testing/scenarios/sponsored-intelligence.js +554 -0
- package/dist/lib/testing/scenarios/sponsored-intelligence.js.map +1 -0
- package/dist/lib/testing/scenarios/trusted-match.d.ts +22 -0
- package/dist/lib/testing/scenarios/trusted-match.d.ts.map +1 -0
- package/dist/lib/testing/scenarios/trusted-match.js +128 -0
- package/dist/lib/testing/scenarios/trusted-match.js.map +1 -0
- package/dist/lib/testing/seed-merge.d.ts +150 -0
- package/dist/lib/testing/seed-merge.d.ts.map +1 -0
- package/dist/lib/testing/seed-merge.js +315 -0
- package/dist/lib/testing/seed-merge.js.map +1 -0
- package/dist/lib/testing/storyboard/assertions.d.ts +148 -0
- package/dist/lib/testing/storyboard/assertions.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/assertions.js +270 -0
- package/dist/lib/testing/storyboard/assertions.js.map +1 -0
- package/dist/lib/testing/storyboard/compliance.d.ts +166 -0
- package/dist/lib/testing/storyboard/compliance.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/compliance.js +434 -0
- package/dist/lib/testing/storyboard/compliance.js.map +1 -0
- package/dist/lib/testing/storyboard/context.d.ts +124 -0
- package/dist/lib/testing/storyboard/context.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/context.js +560 -0
- package/dist/lib/testing/storyboard/context.js.map +1 -0
- package/dist/lib/testing/storyboard/default-invariants.d.ts +36 -0
- package/dist/lib/testing/storyboard/default-invariants.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/default-invariants.js +882 -0
- package/dist/lib/testing/storyboard/default-invariants.js.map +1 -0
- package/dist/lib/testing/storyboard/index.d.ts +34 -0
- package/dist/lib/testing/storyboard/index.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/index.js +110 -0
- package/dist/lib/testing/storyboard/index.js.map +1 -0
- package/dist/lib/testing/storyboard/junit.d.ts +2 -0
- package/dist/lib/testing/storyboard/junit.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/junit.js +104 -0
- package/dist/lib/testing/storyboard/junit.js.map +1 -0
- package/dist/lib/testing/storyboard/loader.d.ts +28 -0
- package/dist/lib/testing/storyboard/loader.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/loader.js +194 -0
- package/dist/lib/testing/storyboard/loader.js.map +1 -0
- package/dist/lib/testing/storyboard/path.d.ts +76 -0
- package/dist/lib/testing/storyboard/path.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/path.js +258 -0
- package/dist/lib/testing/storyboard/path.js.map +1 -0
- package/dist/lib/testing/storyboard/probes.d.ts +148 -0
- package/dist/lib/testing/storyboard/probes.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/probes.js +402 -0
- package/dist/lib/testing/storyboard/probes.js.map +1 -0
- package/dist/lib/testing/storyboard/rejection-hints.d.ts +41 -0
- package/dist/lib/testing/storyboard/rejection-hints.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/rejection-hints.js +344 -0
- package/dist/lib/testing/storyboard/rejection-hints.js.map +1 -0
- package/dist/lib/testing/storyboard/request-builder.d.ts +35 -0
- package/dist/lib/testing/storyboard/request-builder.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/request-builder.js +845 -0
- package/dist/lib/testing/storyboard/request-builder.js.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/builder.d.ts +60 -0
- package/dist/lib/testing/storyboard/request-signing/builder.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/builder.js +462 -0
- package/dist/lib/testing/storyboard/request-signing/builder.js.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/grader.d.ts +166 -0
- package/dist/lib/testing/storyboard/request-signing/grader.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/grader.js +517 -0
- package/dist/lib/testing/storyboard/request-signing/grader.js.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/index.d.ts +38 -0
- package/dist/lib/testing/storyboard/request-signing/index.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/index.js +62 -0
- package/dist/lib/testing/storyboard/request-signing/index.js.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.d.ts +10 -0
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.js +81 -0
- package/dist/lib/testing/storyboard/request-signing/probe-dispatch.js.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/probe.d.ts +41 -0
- package/dist/lib/testing/storyboard/request-signing/probe.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/probe.js +220 -0
- package/dist/lib/testing/storyboard/request-signing/probe.js.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/synthesize.d.ts +28 -0
- package/dist/lib/testing/storyboard/request-signing/synthesize.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/synthesize.js +79 -0
- package/dist/lib/testing/storyboard/request-signing/synthesize.js.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/test-kit.d.ts +42 -0
- package/dist/lib/testing/storyboard/request-signing/test-kit.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/test-kit.js +101 -0
- package/dist/lib/testing/storyboard/request-signing/test-kit.js.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/types.d.ts +72 -0
- package/dist/lib/testing/storyboard/request-signing/types.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/types.js +6 -0
- package/dist/lib/testing/storyboard/request-signing/types.js.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/vector-loader.d.ts +16 -0
- package/dist/lib/testing/storyboard/request-signing/vector-loader.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/request-signing/vector-loader.js +242 -0
- package/dist/lib/testing/storyboard/request-signing/vector-loader.js.map +1 -0
- package/dist/lib/testing/storyboard/runner.d.ts +141 -0
- package/dist/lib/testing/storyboard/runner.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/runner.js +2349 -0
- package/dist/lib/testing/storyboard/runner.js.map +1 -0
- package/dist/lib/testing/storyboard/sandbox-entities.d.ts +56 -0
- package/dist/lib/testing/storyboard/sandbox-entities.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/sandbox-entities.js +222 -0
- package/dist/lib/testing/storyboard/sandbox-entities.js.map +1 -0
- package/dist/lib/testing/storyboard/seeding.d.ts +72 -0
- package/dist/lib/testing/storyboard/seeding.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/seeding.js +282 -0
- package/dist/lib/testing/storyboard/seeding.js.map +1 -0
- package/dist/lib/testing/storyboard/shape-drift-hints.d.ts +54 -0
- package/dist/lib/testing/storyboard/shape-drift-hints.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/shape-drift-hints.js +200 -0
- package/dist/lib/testing/storyboard/shape-drift-hints.js.map +1 -0
- package/dist/lib/testing/storyboard/signer-grader/grader.d.ts +56 -0
- package/dist/lib/testing/storyboard/signer-grader/grader.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/signer-grader/grader.js +270 -0
- package/dist/lib/testing/storyboard/signer-grader/grader.js.map +1 -0
- package/dist/lib/testing/storyboard/signer-grader/index.d.ts +3 -0
- package/dist/lib/testing/storyboard/signer-grader/index.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/signer-grader/index.js +6 -0
- package/dist/lib/testing/storyboard/signer-grader/index.js.map +1 -0
- package/dist/lib/testing/storyboard/signer-grader/types.d.ts +62 -0
- package/dist/lib/testing/storyboard/signer-grader/types.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/signer-grader/types.js +3 -0
- package/dist/lib/testing/storyboard/signer-grader/types.js.map +1 -0
- package/dist/lib/testing/storyboard/strict-validation-hints.d.ts +28 -0
- package/dist/lib/testing/storyboard/strict-validation-hints.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/strict-validation-hints.js +128 -0
- package/dist/lib/testing/storyboard/strict-validation-hints.js.map +1 -0
- package/dist/lib/testing/storyboard/task-map.d.ts +25 -0
- package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/task-map.js +130 -0
- package/dist/lib/testing/storyboard/task-map.js.map +1 -0
- package/dist/lib/testing/storyboard/test-kit.d.ts +52 -0
- package/dist/lib/testing/storyboard/test-kit.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/test-kit.js +93 -0
- package/dist/lib/testing/storyboard/test-kit.js.map +1 -0
- package/dist/lib/testing/storyboard/types.d.ts +1404 -0
- package/dist/lib/testing/storyboard/types.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/types.js +35 -0
- package/dist/lib/testing/storyboard/types.js.map +1 -0
- package/dist/lib/testing/storyboard/validations.d.ts +103 -0
- package/dist/lib/testing/storyboard/validations.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/validations.js +1729 -0
- package/dist/lib/testing/storyboard/validations.js.map +1 -0
- package/dist/lib/testing/storyboard/webhook-assertions.d.ts +62 -0
- package/dist/lib/testing/storyboard/webhook-assertions.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/webhook-assertions.js +538 -0
- package/dist/lib/testing/storyboard/webhook-assertions.js.map +1 -0
- package/dist/lib/testing/storyboard/webhook-receiver.d.ts +104 -0
- package/dist/lib/testing/storyboard/webhook-receiver.d.ts.map +1 -0
- package/dist/lib/testing/storyboard/webhook-receiver.js +402 -0
- package/dist/lib/testing/storyboard/webhook-receiver.js.map +1 -0
- package/dist/lib/testing/stubs/governance-agent-stub.d.ts +72 -0
- package/dist/lib/testing/stubs/governance-agent-stub.d.ts.map +1 -0
- package/dist/lib/testing/stubs/governance-agent-stub.js +297 -0
- package/dist/lib/testing/stubs/governance-agent-stub.js.map +1 -0
- package/dist/lib/testing/stubs/index.d.ts +3 -0
- package/dist/lib/testing/stubs/index.d.ts.map +1 -0
- package/dist/lib/testing/stubs/index.js +6 -0
- package/dist/lib/testing/stubs/index.js.map +1 -0
- package/dist/lib/testing/test-controller.d.ts +46 -0
- package/dist/lib/testing/test-controller.d.ts.map +1 -0
- package/dist/lib/testing/test-controller.js +143 -0
- package/dist/lib/testing/test-controller.js.map +1 -0
- package/dist/lib/testing/test-helpers.d.ts +213 -0
- package/dist/lib/testing/test-helpers.d.ts.map +1 -0
- package/dist/lib/testing/test-helpers.js +250 -0
- package/dist/lib/testing/test-helpers.js.map +1 -0
- package/dist/lib/testing/types.d.ts +222 -0
- package/dist/lib/testing/types.d.ts.map +1 -0
- package/dist/lib/testing/types.js +6 -0
- package/dist/lib/testing/types.js.map +1 -0
- package/dist/lib/types/adcp.d.ts +625 -0
- package/dist/lib/types/adcp.d.ts.map +1 -0
- package/dist/lib/types/adcp.js +20 -0
- package/dist/lib/types/adcp.js.map +1 -0
- package/dist/lib/types/asset-instances.d.ts +32 -0
- package/dist/lib/types/asset-instances.d.ts.map +1 -0
- package/dist/lib/types/asset-instances.js +24 -0
- package/dist/lib/types/asset-instances.js.map +1 -0
- package/dist/lib/types/compat.d.ts +105 -0
- package/dist/lib/types/compat.d.ts.map +1 -0
- package/dist/lib/types/compat.js +52 -0
- package/dist/lib/types/compat.js.map +1 -0
- package/dist/lib/types/core.generated.d.ts +15973 -0
- package/dist/lib/types/core.generated.d.ts.map +1 -0
- package/dist/lib/types/core.generated.js +5 -0
- package/dist/lib/types/core.generated.js.map +1 -0
- package/dist/lib/types/enums.generated.d.ts +139 -0
- package/dist/lib/types/enums.generated.d.ts.map +1 -0
- package/dist/lib/types/enums.generated.js +158 -0
- package/dist/lib/types/enums.generated.js.map +1 -0
- package/dist/lib/types/error-codes.d.ts +32 -0
- package/dist/lib/types/error-codes.d.ts.map +1 -0
- package/dist/lib/types/error-codes.js +146 -0
- package/dist/lib/types/error-codes.js.map +1 -0
- package/dist/lib/types/format-asset-slots.d.ts +117 -0
- package/dist/lib/types/format-asset-slots.d.ts.map +1 -0
- package/dist/lib/types/format-asset-slots.js +20 -0
- package/dist/lib/types/format-asset-slots.js.map +1 -0
- package/dist/lib/types/index.d.ts +20 -0
- package/dist/lib/types/index.d.ts.map +1 -0
- package/dist/lib/types/index.js +48 -0
- package/dist/lib/types/index.js.map +1 -0
- package/dist/lib/types/inline-enums.aliases.d.ts +53 -0
- package/dist/lib/types/inline-enums.aliases.d.ts.map +1 -0
- package/dist/lib/types/inline-enums.aliases.js +73 -0
- package/dist/lib/types/inline-enums.aliases.js.map +1 -0
- package/dist/lib/types/inline-enums.generated.d.ts +157 -0
- package/dist/lib/types/inline-enums.generated.d.ts.map +1 -0
- package/dist/lib/types/inline-enums.generated.js +239 -0
- package/dist/lib/types/inline-enums.generated.js.map +1 -0
- package/dist/lib/types/schemas.generated.d.ts +46531 -0
- package/dist/lib/types/schemas.generated.d.ts.map +1 -0
- package/dist/lib/types/schemas.generated.js +5867 -0
- package/dist/lib/types/schemas.generated.js.map +1 -0
- package/dist/lib/types/sync-rows.d.ts +37 -0
- package/dist/lib/types/sync-rows.d.ts.map +1 -0
- package/dist/lib/types/sync-rows.js +21 -0
- package/dist/lib/types/sync-rows.js.map +1 -0
- package/dist/lib/types/tools.generated.d.ts +13423 -0
- package/dist/lib/types/tools.generated.d.ts.map +1 -0
- package/dist/lib/types/tools.generated.js +5 -0
- package/dist/lib/types/tools.generated.js.map +1 -0
- package/dist/lib/types/wellknown-schemas.generated.d.ts +1363 -0
- package/dist/lib/types/wellknown-schemas.generated.d.ts.map +1 -0
- package/dist/lib/types/wellknown-schemas.generated.js +14 -0
- package/dist/lib/types/wellknown-schemas.generated.js.map +1 -0
- package/dist/lib/utils/a2a-discovery.d.ts +42 -0
- package/dist/lib/utils/a2a-discovery.d.ts.map +1 -0
- package/dist/lib/utils/a2a-discovery.js +68 -0
- package/dist/lib/utils/a2a-discovery.js.map +1 -0
- package/dist/lib/utils/adcp-version-config.d.ts +11 -0
- package/dist/lib/utils/adcp-version-config.d.ts.map +1 -0
- package/dist/lib/utils/adcp-version-config.js +44 -0
- package/dist/lib/utils/adcp-version-config.js.map +1 -0
- package/dist/lib/utils/asset-builders.d.ts +44 -0
- package/dist/lib/utils/asset-builders.d.ts.map +1 -0
- package/dist/lib/utils/asset-builders.js +84 -0
- package/dist/lib/utils/asset-builders.js.map +1 -0
- package/dist/lib/utils/capabilities.d.ts +259 -0
- package/dist/lib/utils/capabilities.d.ts.map +1 -0
- package/dist/lib/utils/capabilities.js +463 -0
- package/dist/lib/utils/capabilities.js.map +1 -0
- package/dist/lib/utils/creative-adapter.d.ts +91 -0
- package/dist/lib/utils/creative-adapter.d.ts.map +1 -0
- package/dist/lib/utils/creative-adapter.js +156 -0
- package/dist/lib/utils/creative-adapter.js.map +1 -0
- package/dist/lib/utils/deprecation.d.ts +11 -0
- package/dist/lib/utils/deprecation.d.ts.map +1 -0
- package/dist/lib/utils/deprecation.js +23 -0
- package/dist/lib/utils/deprecation.js.map +1 -0
- package/dist/lib/utils/error-extraction.d.ts +43 -0
- package/dist/lib/utils/error-extraction.d.ts.map +1 -0
- package/dist/lib/utils/error-extraction.js +225 -0
- package/dist/lib/utils/error-extraction.js.map +1 -0
- package/dist/lib/utils/extract-result.d.ts +45 -0
- package/dist/lib/utils/extract-result.d.ts.map +1 -0
- package/dist/lib/utils/extract-result.js +27 -0
- package/dist/lib/utils/extract-result.js.map +1 -0
- package/dist/lib/utils/format-asset-slot-builders.d.ts +76 -0
- package/dist/lib/utils/format-asset-slot-builders.d.ts.map +1 -0
- package/dist/lib/utils/format-asset-slot-builders.js +174 -0
- package/dist/lib/utils/format-asset-slot-builders.js.map +1 -0
- package/dist/lib/utils/format-assets.d.ts +100 -0
- package/dist/lib/utils/format-assets.d.ts.map +1 -0
- package/dist/lib/utils/format-assets.js +147 -0
- package/dist/lib/utils/format-assets.js.map +1 -0
- package/dist/lib/utils/format-render-builders.d.ts +76 -0
- package/dist/lib/utils/format-render-builders.d.ts.map +1 -0
- package/dist/lib/utils/format-render-builders.js +76 -0
- package/dist/lib/utils/format-render-builders.js.map +1 -0
- package/dist/lib/utils/format-renders.d.ts +96 -0
- package/dist/lib/utils/format-renders.d.ts.map +1 -0
- package/dist/lib/utils/format-renders.js +141 -0
- package/dist/lib/utils/format-renders.js.map +1 -0
- package/dist/lib/utils/idempotency.d.ts +96 -0
- package/dist/lib/utils/idempotency.d.ts.map +1 -0
- package/dist/lib/utils/idempotency.js +156 -0
- package/dist/lib/utils/idempotency.js.map +1 -0
- package/dist/lib/utils/index.d.ts +39 -0
- package/dist/lib/utils/index.d.ts.map +1 -0
- package/dist/lib/utils/index.js +196 -0
- package/dist/lib/utils/index.js.map +1 -0
- package/dist/lib/utils/jcs.d.ts +30 -0
- package/dist/lib/utils/jcs.d.ts.map +1 -0
- package/dist/lib/utils/jcs.js +167 -0
- package/dist/lib/utils/jcs.js.map +1 -0
- package/dist/lib/utils/logger.d.ts +55 -0
- package/dist/lib/utils/logger.d.ts.map +1 -0
- package/dist/lib/utils/logger.js +100 -0
- package/dist/lib/utils/logger.js.map +1 -0
- package/dist/lib/utils/pagination.d.ts +31 -0
- package/dist/lib/utils/pagination.d.ts.map +1 -0
- package/dist/lib/utils/pagination.js +51 -0
- package/dist/lib/utils/pagination.js.map +1 -0
- package/dist/lib/utils/preview-normalizer.d.ts +109 -0
- package/dist/lib/utils/preview-normalizer.d.ts.map +1 -0
- package/dist/lib/utils/preview-normalizer.js +122 -0
- package/dist/lib/utils/preview-normalizer.js.map +1 -0
- package/dist/lib/utils/preview-utils.d.ts +87 -0
- package/dist/lib/utils/preview-utils.d.ts.map +1 -0
- package/dist/lib/utils/preview-utils.js +340 -0
- package/dist/lib/utils/preview-utils.js.map +1 -0
- package/dist/lib/utils/pricing-adapter.d.ts +144 -0
- package/dist/lib/utils/pricing-adapter.d.ts.map +1 -0
- package/dist/lib/utils/pricing-adapter.js +322 -0
- package/dist/lib/utils/pricing-adapter.js.map +1 -0
- package/dist/lib/utils/protocol-detection.d.ts +26 -0
- package/dist/lib/utils/protocol-detection.d.ts.map +1 -0
- package/dist/lib/utils/protocol-detection.js +62 -0
- package/dist/lib/utils/protocol-detection.js.map +1 -0
- package/dist/lib/utils/render-builders.d.ts +41 -0
- package/dist/lib/utils/render-builders.d.ts.map +1 -0
- package/dist/lib/utils/render-builders.js +52 -0
- package/dist/lib/utils/render-builders.js.map +1 -0
- package/dist/lib/utils/request-normalizer.d.ts +26 -0
- package/dist/lib/utils/request-normalizer.d.ts.map +1 -0
- package/dist/lib/utils/request-normalizer.js +175 -0
- package/dist/lib/utils/request-normalizer.js.map +1 -0
- package/dist/lib/utils/response-schemas.d.ts +9 -0
- package/dist/lib/utils/response-schemas.d.ts.map +1 -0
- package/dist/lib/utils/response-schemas.js +129 -0
- package/dist/lib/utils/response-schemas.js.map +1 -0
- package/dist/lib/utils/response-unwrapper.d.ts +54 -0
- package/dist/lib/utils/response-unwrapper.d.ts.map +1 -0
- package/dist/lib/utils/response-unwrapper.js +406 -0
- package/dist/lib/utils/response-unwrapper.js.map +1 -0
- package/dist/lib/utils/retry.d.ts +15 -0
- package/dist/lib/utils/retry.d.ts.map +1 -0
- package/dist/lib/utils/retry.js +22 -0
- package/dist/lib/utils/retry.js.map +1 -0
- package/dist/lib/utils/sync-creatives-adapter.d.ts +18 -0
- package/dist/lib/utils/sync-creatives-adapter.d.ts.map +1 -0
- package/dist/lib/utils/sync-creatives-adapter.js +46 -0
- package/dist/lib/utils/sync-creatives-adapter.js.map +1 -0
- package/dist/lib/utils/tool-request-schemas.d.ts +15 -0
- package/dist/lib/utils/tool-request-schemas.d.ts.map +1 -0
- package/dist/lib/utils/tool-request-schemas.js +129 -0
- package/dist/lib/utils/tool-request-schemas.js.map +1 -0
- package/dist/lib/utils/typeGuards.d.ts +147 -0
- package/dist/lib/utils/typeGuards.d.ts.map +1 -0
- package/dist/lib/utils/typeGuards.js +240 -0
- package/dist/lib/utils/typeGuards.js.map +1 -0
- package/dist/lib/utils/union-errors.d.ts +20 -0
- package/dist/lib/utils/union-errors.d.ts.map +1 -0
- package/dist/lib/utils/union-errors.js +38 -0
- package/dist/lib/utils/union-errors.js.map +1 -0
- package/dist/lib/utils/validate-user-agent.d.ts +8 -0
- package/dist/lib/utils/validate-user-agent.d.ts.map +1 -0
- package/dist/lib/utils/validate-user-agent.js +15 -0
- package/dist/lib/utils/validate-user-agent.js.map +1 -0
- package/dist/lib/validation/client-hooks.d.ts +49 -0
- package/dist/lib/validation/client-hooks.d.ts.map +1 -0
- package/dist/lib/validation/client-hooks.js +82 -0
- package/dist/lib/validation/client-hooks.js.map +1 -0
- package/dist/lib/validation/index.d.ts +37 -0
- package/dist/lib/validation/index.d.ts.map +1 -0
- package/dist/lib/validation/index.js +202 -0
- package/dist/lib/validation/index.js.map +1 -0
- package/dist/lib/validation/schema-errors.d.ts +67 -0
- package/dist/lib/validation/schema-errors.d.ts.map +1 -0
- package/dist/lib/validation/schema-errors.js +75 -0
- package/dist/lib/validation/schema-errors.js.map +1 -0
- package/dist/lib/validation/schema-loader.d.ts +24 -0
- package/dist/lib/validation/schema-loader.d.ts.map +1 -0
- package/dist/lib/validation/schema-loader.js +315 -0
- package/dist/lib/validation/schema-loader.js.map +1 -0
- package/dist/lib/validation/schema-validator.d.ts +83 -0
- package/dist/lib/validation/schema-validator.d.ts.map +1 -0
- package/dist/lib/validation/schema-validator.js +142 -0
- package/dist/lib/validation/schema-validator.js.map +1 -0
- package/dist/lib/validation/sync-creatives.d.ts +327 -0
- package/dist/lib/validation/sync-creatives.d.ts.map +1 -0
- package/dist/lib/validation/sync-creatives.js +72 -0
- package/dist/lib/validation/sync-creatives.js.map +1 -0
- package/dist/lib/version.d.ts +63 -0
- package/dist/lib/version.d.ts.map +1 -0
- package/dist/lib/version.js +85 -0
- package/dist/lib/version.js.map +1 -0
- package/docs/README.md +42 -0
- package/docs/guides/BUILD-AN-AGENT.md +632 -0
- package/docs/llms.txt +1197 -0
- package/examples/README.md +117 -0
- package/examples/adcp.config.json +30 -0
- package/examples/basic-a2a.ts +76 -0
- package/examples/basic-mcp.ts +50 -0
- package/examples/batch-preview-test.ts +266 -0
- package/examples/comply-controller-seller.ts +146 -0
- package/examples/conversation-client.ts +291 -0
- package/examples/debug-preview-response.ts +73 -0
- package/examples/debug-preview-with-logging.ts +50 -0
- package/examples/easy-config-demo.ts +242 -0
- package/examples/env-config.ts +51 -0
- package/examples/error-compliant-server.ts +241 -0
- package/examples/gcp-kms-signing-provider.ts +281 -0
- package/examples/generative-creative-demo.ts +196 -0
- package/examples/inspect-card-formats.ts +161 -0
- package/examples/logger-usage.ts +165 -0
- package/examples/oauth-cli-example.ts +154 -0
- package/examples/pr78-async-patterns-demo.ts +247 -0
- package/examples/seller-test-controller.ts +320 -0
- package/examples/signals-agent.ts +201 -0
- package/examples/simple-getting-started.ts +225 -0
- package/examples/simple-protocol-demo.ts +75 -0
- package/examples/test-helpers-demo.ts +239 -0
- package/examples/zod-validation-example.ts +126 -0
- package/package.json +313 -0
- package/skills/adcp/SKILL.md +326 -0
- package/skills/adcp-brand/SKILL.md +202 -0
- package/skills/adcp-brand.previous/SKILL.md +202 -0
- package/skills/adcp-creative/SKILL.md +301 -0
- package/skills/adcp-creative.previous/SKILL.md +301 -0
- package/skills/adcp-governance/SKILL.md +566 -0
- package/skills/adcp-governance.previous/SKILL.md +566 -0
- package/skills/adcp-media-buy/SKILL.md +446 -0
- package/skills/adcp-media-buy.previous/SKILL.md +446 -0
- package/skills/adcp-si/SKILL.md +206 -0
- package/skills/adcp-si.previous/SKILL.md +206 -0
- package/skills/adcp-signals/SKILL.md +204 -0
- package/skills/adcp-signals.previous/SKILL.md +204 -0
- package/skills/build-brand-rights-agent/SKILL.md +528 -0
- package/skills/build-creative-agent/SKILL.md +824 -0
- package/skills/build-generative-seller-agent/SKILL.md +579 -0
- package/skills/build-governance-agent/SKILL.md +966 -0
- package/skills/build-retail-media-agent/SKILL.md +488 -0
- package/skills/build-seller-agent/SKILL.md +1407 -0
- package/skills/build-seller-agent/deployment.md +407 -0
- package/skills/build-seller-agent/specialisms/audience-sync.md +63 -0
- package/skills/build-seller-agent/specialisms/sales-broadcast-tv.md +71 -0
- package/skills/build-seller-agent/specialisms/sales-guaranteed.md +67 -0
- package/skills/build-seller-agent/specialisms/sales-non-guaranteed.md +39 -0
- package/skills/build-seller-agent/specialisms/sales-proposal-mode.md +51 -0
- package/skills/build-seller-agent/specialisms/sales-social.md +30 -0
- package/skills/build-seller-agent/specialisms/signed-requests.md +89 -0
- package/skills/build-si-agent/SKILL.md +347 -0
- package/skills/build-signals-agent/SKILL.md +527 -0
- package/skills/call-adcp-agent/SKILL.md +255 -0
- package/skills/call-adcp-agent.previous/SKILL.md +255 -0
package/bin/adcp.js
ADDED
|
@@ -0,0 +1,4821 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AdCP CLI Tool
|
|
5
|
+
*
|
|
6
|
+
* Simple command-line utility to call AdCP agents directly
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* adcp <protocol> <agent-url> <tool-name> [payload-json] [--auth token]
|
|
10
|
+
*
|
|
11
|
+
* Examples:
|
|
12
|
+
* adcp mcp https://agent.example.com/mcp get_products '{"brief":"coffee brands"}'
|
|
13
|
+
* adcp a2a https://agent.example.com list_creative_formats '{}' --auth your_token_here
|
|
14
|
+
* adcp mcp https://agent.example.com/mcp create_media_buy @payload.json --auth $AGENT_TOKEN
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const { AdCPClient, detectProtocol, usesDeprecatedAssetsField } = require('../dist/lib/index.js');
|
|
18
|
+
const { readFileSync, statSync } = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
const { pathToFileURL } = require('url');
|
|
21
|
+
const net = require('net');
|
|
22
|
+
const { spawn } = require('child_process');
|
|
23
|
+
const { AsyncWebhookHandler } = require('./adcp-async-handler.js');
|
|
24
|
+
const {
|
|
25
|
+
getAgent,
|
|
26
|
+
listAgents,
|
|
27
|
+
isAlias,
|
|
28
|
+
interactiveSetup,
|
|
29
|
+
removeAgent,
|
|
30
|
+
getConfigPath,
|
|
31
|
+
saveAgent,
|
|
32
|
+
} = require('./adcp-config.js');
|
|
33
|
+
const { handleRegistryCommand } = require('./adcp-registry.js');
|
|
34
|
+
const { captureStdoutLogs, writeJsonOutput } = require('./adcp-json-stdout.js');
|
|
35
|
+
const { printStepHints, countHintsInResult } = require('./adcp-step-hints.js');
|
|
36
|
+
const { scheduleVersionCheck } = require('./adcp-version-check.js');
|
|
37
|
+
const { formatStoryboardResultsAsJUnit } = require('../dist/lib/testing/storyboard/junit.js');
|
|
38
|
+
const { LIBRARY_VERSION } = require('../dist/lib/version.js');
|
|
39
|
+
const {
|
|
40
|
+
createCLIOAuthProvider,
|
|
41
|
+
hasValidOAuthTokens,
|
|
42
|
+
clearOAuthTokens,
|
|
43
|
+
getEffectiveAuthToken,
|
|
44
|
+
createFileOAuthStorage,
|
|
45
|
+
bindAgentStorage,
|
|
46
|
+
NeedsAuthorizationError,
|
|
47
|
+
exchangeClientCredentials,
|
|
48
|
+
ensureClientCredentialsTokens,
|
|
49
|
+
ClientCredentialsExchangeError,
|
|
50
|
+
MissingEnvSecretError,
|
|
51
|
+
toEnvSecretReference,
|
|
52
|
+
discoverAuthorizationRequirements,
|
|
53
|
+
} = require('../dist/lib/auth/oauth/index.js');
|
|
54
|
+
|
|
55
|
+
// Test scenarios available
|
|
56
|
+
const TEST_SCENARIOS = [
|
|
57
|
+
'health_check',
|
|
58
|
+
'discovery',
|
|
59
|
+
'create_media_buy',
|
|
60
|
+
'full_sales_flow',
|
|
61
|
+
'creative_sync',
|
|
62
|
+
'creative_inline',
|
|
63
|
+
'creative_flow',
|
|
64
|
+
'signals_flow',
|
|
65
|
+
'error_handling',
|
|
66
|
+
'validation',
|
|
67
|
+
'pricing_edge_cases',
|
|
68
|
+
'temporal_validation',
|
|
69
|
+
'behavior_analysis',
|
|
70
|
+
'response_consistency',
|
|
71
|
+
// v3 protocol scenarios
|
|
72
|
+
'capability_discovery',
|
|
73
|
+
'governance_property_lists',
|
|
74
|
+
'governance_content_standards',
|
|
75
|
+
'si_session_lifecycle',
|
|
76
|
+
'si_availability',
|
|
77
|
+
'campaign_governance',
|
|
78
|
+
'campaign_governance_denied',
|
|
79
|
+
'campaign_governance_conditions',
|
|
80
|
+
'campaign_governance_delivery',
|
|
81
|
+
'seller_governance_context',
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
// Built-in test agent aliases (shared between main CLI and test command)
|
|
85
|
+
// Note: These tokens are intentionally public for the AdCP test infrastructure.
|
|
86
|
+
// They provide rate-limited access to test agents for SDK development and examples.
|
|
87
|
+
const BUILT_IN_AGENTS = {
|
|
88
|
+
'test-mcp': {
|
|
89
|
+
url: 'https://test-agent.adcontextprotocol.org/mcp/',
|
|
90
|
+
protocol: 'mcp',
|
|
91
|
+
auth_token: '1v8tAhASaUYYp4odoQ1PnMpdqNaMiTrCRqYo9OJp6IQ',
|
|
92
|
+
description: 'AdCP public test agent (MCP, with auth)',
|
|
93
|
+
},
|
|
94
|
+
'test-a2a': {
|
|
95
|
+
url: 'https://test-agent.adcontextprotocol.org',
|
|
96
|
+
protocol: 'a2a',
|
|
97
|
+
auth_token: '1v8tAhASaUYYp4odoQ1PnMpdqNaMiTrCRqYo9OJp6IQ',
|
|
98
|
+
description: 'AdCP public test agent (A2A, with auth)',
|
|
99
|
+
},
|
|
100
|
+
'test-no-auth': {
|
|
101
|
+
url: 'https://test-agent.adcontextprotocol.org/mcp/',
|
|
102
|
+
protocol: 'mcp',
|
|
103
|
+
description: 'AdCP public test agent (MCP, no auth - demonstrates errors)',
|
|
104
|
+
},
|
|
105
|
+
'test-a2a-no-auth': {
|
|
106
|
+
url: 'https://test-agent.adcontextprotocol.org',
|
|
107
|
+
protocol: 'a2a',
|
|
108
|
+
description: 'AdCP public test agent (A2A, no auth - demonstrates errors)',
|
|
109
|
+
},
|
|
110
|
+
creative: {
|
|
111
|
+
url: 'https://creative.adcontextprotocol.org/mcp',
|
|
112
|
+
protocol: 'mcp',
|
|
113
|
+
description: 'Official AdCP creative agent (MCP only)',
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Check formats for deprecated assets_required usage
|
|
119
|
+
* Returns array of format IDs using the deprecated field
|
|
120
|
+
*/
|
|
121
|
+
function checkDeprecatedFormats(formats) {
|
|
122
|
+
if (!formats || !Array.isArray(formats)) return [];
|
|
123
|
+
|
|
124
|
+
return formats
|
|
125
|
+
.filter(format => usesDeprecatedAssetsField(format))
|
|
126
|
+
.map(format => format.format_id?.id || format.format_id || format.id || format.name || 'unknown');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Extract human-readable protocol message from conversation
|
|
131
|
+
*/
|
|
132
|
+
function extractProtocolMessage(conversation, protocol) {
|
|
133
|
+
if (!conversation || conversation.length === 0) return null;
|
|
134
|
+
|
|
135
|
+
// Find the last agent response (don't mutate original array)
|
|
136
|
+
const agentResponse = [...conversation].reverse().find(msg => msg.role === 'agent');
|
|
137
|
+
if (!agentResponse || !agentResponse.content) return null;
|
|
138
|
+
|
|
139
|
+
if (protocol === 'mcp') {
|
|
140
|
+
// MCP: The content[].text contains the tool response (JSON stringified)
|
|
141
|
+
// This IS the protocol message in MCP
|
|
142
|
+
if (agentResponse.content.content && Array.isArray(agentResponse.content.content)) {
|
|
143
|
+
const textContent = agentResponse.content.content.find(c => c.type === 'text');
|
|
144
|
+
return textContent?.text || null;
|
|
145
|
+
}
|
|
146
|
+
if (agentResponse.content.text) {
|
|
147
|
+
return agentResponse.content.text;
|
|
148
|
+
}
|
|
149
|
+
} else if (protocol === 'a2a') {
|
|
150
|
+
// A2A: Extract human-readable message from task result
|
|
151
|
+
// The message is nested in result.artifacts[0].parts[0].data.message
|
|
152
|
+
const result = agentResponse.content.result;
|
|
153
|
+
if (result && result.artifacts && result.artifacts.length > 0) {
|
|
154
|
+
const artifact = result.artifacts[0];
|
|
155
|
+
if (artifact.parts && artifact.parts.length > 0) {
|
|
156
|
+
const data = artifact.parts[0].data;
|
|
157
|
+
if (data && data.message) {
|
|
158
|
+
return data.message;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Fallback: check top-level status message
|
|
163
|
+
if (result && result.status && result.status.message) {
|
|
164
|
+
return result.status.message;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Display agent info - includes capabilities detection for v3.0
|
|
173
|
+
*/
|
|
174
|
+
async function displayAgentInfo(agentConfig, jsonOutput) {
|
|
175
|
+
const client = new AdCPClient([agentConfig]);
|
|
176
|
+
const agentClient = client.agent(agentConfig.id);
|
|
177
|
+
const info = await agentClient.getAgentInfo();
|
|
178
|
+
|
|
179
|
+
// Try to get capabilities (v3.0 feature detection)
|
|
180
|
+
let capabilities = null;
|
|
181
|
+
try {
|
|
182
|
+
if (typeof agentClient.getCapabilities === 'function') {
|
|
183
|
+
capabilities = await agentClient.getCapabilities();
|
|
184
|
+
}
|
|
185
|
+
} catch (e) {
|
|
186
|
+
// Capabilities detection failed - continue without
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (jsonOutput) {
|
|
190
|
+
// Include capabilities in JSON output
|
|
191
|
+
const output = {
|
|
192
|
+
...info,
|
|
193
|
+
...(capabilities && { capabilities }),
|
|
194
|
+
};
|
|
195
|
+
console.log(JSON.stringify(output, null, 2));
|
|
196
|
+
} else {
|
|
197
|
+
console.log(`\nš Agent Information\n`);
|
|
198
|
+
console.log(`Name: ${info.name}`);
|
|
199
|
+
if (info.description) {
|
|
200
|
+
console.log(`Description: ${info.description}`);
|
|
201
|
+
}
|
|
202
|
+
console.log(`Protocol: ${info.protocol.toUpperCase()}`);
|
|
203
|
+
console.log(`URL: ${info.url}`);
|
|
204
|
+
|
|
205
|
+
// Display capabilities if available
|
|
206
|
+
if (capabilities) {
|
|
207
|
+
console.log(`\nš§ Capabilities:\n`);
|
|
208
|
+
console.log(` AdCP Version: ${capabilities.version}${capabilities._synthetic ? ' (detected)' : ''}`);
|
|
209
|
+
if (capabilities.protocols && capabilities.protocols.length > 0) {
|
|
210
|
+
console.log(` Supported Protocols: ${capabilities.protocols.join(', ')}`);
|
|
211
|
+
}
|
|
212
|
+
if (capabilities.features) {
|
|
213
|
+
const features = [];
|
|
214
|
+
if (capabilities.features.supportsCreativeAssignments) features.push('creative_assignments');
|
|
215
|
+
if (capabilities.features.supportsRenders) features.push('renders');
|
|
216
|
+
if (capabilities.features.supportsPropertyListFiltering) features.push('property_list_filtering');
|
|
217
|
+
if (capabilities.features.supportsContentStandards) features.push('content_standards');
|
|
218
|
+
if (features.length > 0) {
|
|
219
|
+
console.log(` v3.0 Features: ${features.join(', ')}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (capabilities.extensions && capabilities.extensions.length > 0) {
|
|
223
|
+
console.log(` Extensions: ${capabilities.extensions.join(', ')}`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
console.log(`\nAvailable Tools (${info.tools.length}):\n`);
|
|
228
|
+
|
|
229
|
+
if (info.tools.length === 0) {
|
|
230
|
+
console.log('No tools found.');
|
|
231
|
+
} else {
|
|
232
|
+
info.tools.forEach((tool, i) => {
|
|
233
|
+
console.log(`${i + 1}. ${tool.name}`);
|
|
234
|
+
if (tool.description) {
|
|
235
|
+
console.log(` ${tool.description}`);
|
|
236
|
+
}
|
|
237
|
+
if (tool.parameters && tool.parameters.length > 0) {
|
|
238
|
+
console.log(` Parameters: ${tool.parameters.join(', ')}`);
|
|
239
|
+
}
|
|
240
|
+
console.log('');
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Handle the 'test' subcommand for running agent test scenarios
|
|
248
|
+
*/
|
|
249
|
+
async function handleTestCommand(args) {
|
|
250
|
+
// Handle --list-scenarios and --help
|
|
251
|
+
if (args.includes('--list-scenarios') || args.includes('--help') || args.includes('-h') || args.length === 0) {
|
|
252
|
+
console.log('\nš Available Test Scenarios:\n');
|
|
253
|
+
const descriptions = {
|
|
254
|
+
health_check: 'Basic connectivity check - verify agent responds',
|
|
255
|
+
discovery: 'Test get_products, list_creative_formats, list_authorized_properties',
|
|
256
|
+
create_media_buy: 'Discovery + create a test media buy (sandbox)',
|
|
257
|
+
full_sales_flow: 'Full lifecycle: discovery ā create ā update ā delivery',
|
|
258
|
+
creative_sync: 'Test sync_creatives flow',
|
|
259
|
+
creative_inline: 'Test inline creatives in create_media_buy',
|
|
260
|
+
creative_flow: 'Creative agent: list_formats ā build ā preview',
|
|
261
|
+
signals_flow: 'Signals agent: get_signals ā activate',
|
|
262
|
+
error_handling: 'Verify agent returns proper error responses',
|
|
263
|
+
validation: 'Test schema validation (invalid inputs should be rejected)',
|
|
264
|
+
pricing_edge_cases: 'Test auction vs fixed pricing, min spend, bid_price',
|
|
265
|
+
temporal_validation: 'Test date/time ordering and format validation',
|
|
266
|
+
behavior_analysis: 'Analyze agent behavior: auth, brief relevance, filtering',
|
|
267
|
+
response_consistency: 'Check for schema errors, pagination bugs, data mismatches',
|
|
268
|
+
// v3 protocol scenarios
|
|
269
|
+
capability_discovery: 'Test get_adcp_capabilities and verify v3 protocol support',
|
|
270
|
+
governance_property_lists: 'Test property list CRUD (create, get, update, delete)',
|
|
271
|
+
governance_content_standards: 'Test content standards listing and calibration',
|
|
272
|
+
si_session_lifecycle: 'Test full SI session: initiate ā messages ā terminate',
|
|
273
|
+
si_availability: 'Quick check for SI offering availability',
|
|
274
|
+
campaign_governance: 'Full governance lifecycle: sync_plans ā check ā execute ā report',
|
|
275
|
+
campaign_governance_denied: 'Denied flow: over-budget, unauthorized market',
|
|
276
|
+
campaign_governance_conditions: 'Conditions flow: apply conditions ā re-check',
|
|
277
|
+
campaign_governance_delivery: 'Delivery monitoring with drift detection',
|
|
278
|
+
seller_governance_context: 'Verify seller persists governance_context from media buy lifecycle',
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
for (const scenario of TEST_SCENARIOS) {
|
|
282
|
+
console.log(` ${scenario}`);
|
|
283
|
+
if (descriptions[scenario]) {
|
|
284
|
+
console.log(` ${descriptions[scenario]}`);
|
|
285
|
+
}
|
|
286
|
+
console.log('');
|
|
287
|
+
}
|
|
288
|
+
console.log('Usage: adcp test <agent> [scenario] [options]\n');
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Parse options with bounds checking
|
|
293
|
+
const authIndex = args.indexOf('--auth');
|
|
294
|
+
let authToken = process.env.ADCP_AUTH_TOKEN;
|
|
295
|
+
if (authIndex !== -1) {
|
|
296
|
+
if (authIndex + 1 >= args.length || args[authIndex + 1].startsWith('--')) {
|
|
297
|
+
console.error('ERROR: --auth requires a token value\n');
|
|
298
|
+
process.exit(2);
|
|
299
|
+
}
|
|
300
|
+
authToken = args[authIndex + 1];
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const protocolIndex = args.indexOf('--protocol');
|
|
304
|
+
let protocolFlag = null;
|
|
305
|
+
if (protocolIndex !== -1) {
|
|
306
|
+
if (protocolIndex + 1 >= args.length || args[protocolIndex + 1].startsWith('--')) {
|
|
307
|
+
console.error('ERROR: --protocol requires a value (mcp or a2a)\n');
|
|
308
|
+
process.exit(2);
|
|
309
|
+
}
|
|
310
|
+
protocolFlag = args[protocolIndex + 1];
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const briefIndex = args.indexOf('--brief');
|
|
314
|
+
let brief;
|
|
315
|
+
if (briefIndex !== -1) {
|
|
316
|
+
if (briefIndex + 1 >= args.length || args[briefIndex + 1].startsWith('--')) {
|
|
317
|
+
console.error('ERROR: --brief requires a value\n');
|
|
318
|
+
process.exit(2);
|
|
319
|
+
}
|
|
320
|
+
brief = args[briefIndex + 1];
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const jsonOutput = args.includes('--json');
|
|
324
|
+
const debug = args.includes('--debug') || process.env.ADCP_DEBUG === 'true';
|
|
325
|
+
const dryRun = args.includes('--dry-run');
|
|
326
|
+
const useOAuth = args.includes('--oauth');
|
|
327
|
+
|
|
328
|
+
// Filter out flag arguments to find positional arguments
|
|
329
|
+
const positionalArgs = args.filter(
|
|
330
|
+
arg => !arg.startsWith('--') && arg !== authToken && arg !== protocolFlag && arg !== brief
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
if (positionalArgs.length === 0) {
|
|
334
|
+
console.error('ERROR: test command requires an agent alias or URL\n');
|
|
335
|
+
console.error('Usage: adcp test <agent> [scenario] [options]');
|
|
336
|
+
console.error(' adcp test --list-scenarios\n');
|
|
337
|
+
process.exit(2);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const agentArg = positionalArgs[0];
|
|
341
|
+
const scenario = positionalArgs[1] || 'discovery';
|
|
342
|
+
|
|
343
|
+
// Validate scenario
|
|
344
|
+
if (!TEST_SCENARIOS.includes(scenario)) {
|
|
345
|
+
console.error(`ERROR: Unknown scenario '${scenario}'\n`);
|
|
346
|
+
console.error('Available scenarios:');
|
|
347
|
+
TEST_SCENARIOS.forEach(s => console.error(` - ${s}`));
|
|
348
|
+
console.error('\nUse: adcp test --list-scenarios for descriptions\n');
|
|
349
|
+
process.exit(2);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Validate protocol flag if provided
|
|
353
|
+
if (protocolFlag && protocolFlag !== 'mcp' && protocolFlag !== 'a2a') {
|
|
354
|
+
console.error(`ERROR: Invalid protocol '${protocolFlag}'. Must be 'mcp' or 'a2a'\n`);
|
|
355
|
+
process.exit(2);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
let agentUrl;
|
|
359
|
+
let protocol = protocolFlag;
|
|
360
|
+
let finalAuthToken = authToken;
|
|
361
|
+
let oauthTokens = null;
|
|
362
|
+
|
|
363
|
+
// Resolve agent
|
|
364
|
+
if (BUILT_IN_AGENTS[agentArg]) {
|
|
365
|
+
const builtIn = BUILT_IN_AGENTS[agentArg];
|
|
366
|
+
agentUrl = builtIn.url;
|
|
367
|
+
protocol = protocol || builtIn.protocol;
|
|
368
|
+
finalAuthToken = finalAuthToken || builtIn.auth_token;
|
|
369
|
+
} else if (isAlias(agentArg)) {
|
|
370
|
+
const savedAgent = getAgent(agentArg);
|
|
371
|
+
agentUrl = savedAgent.url;
|
|
372
|
+
protocol = protocol || savedAgent.protocol;
|
|
373
|
+
finalAuthToken = finalAuthToken || getEffectiveAuthToken(savedAgent);
|
|
374
|
+
if (savedAgent.oauth_client_credentials) {
|
|
375
|
+
// Client credentials: tokens are refreshed inside `ProtocolClient.callTool`
|
|
376
|
+
// via `ensureClientCredentialsTokens`. Surface cached tokens so the call
|
|
377
|
+
// path has a warm start; the library persists any refresh via the
|
|
378
|
+
// `bindAgentStorage` wiring below.
|
|
379
|
+
oauthTokens = savedAgent.oauth_tokens;
|
|
380
|
+
} else if (savedAgent.oauth_tokens) {
|
|
381
|
+
if (hasValidOAuthTokens(savedAgent)) {
|
|
382
|
+
oauthTokens = savedAgent.oauth_tokens;
|
|
383
|
+
} else {
|
|
384
|
+
if (debug) {
|
|
385
|
+
console.error(
|
|
386
|
+
`DEBUG: OAuth tokens expired for '${agentArg}', using ${finalAuthToken ? 'static token' : 'no auth'}`
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
if (useOAuth) {
|
|
390
|
+
// Only error on expired tokens if --oauth flag was explicitly passed
|
|
391
|
+
if (jsonOutput) {
|
|
392
|
+
console.log(
|
|
393
|
+
JSON.stringify({
|
|
394
|
+
success: false,
|
|
395
|
+
error: 'OAuth tokens expired',
|
|
396
|
+
message: `Run: adcp ${agentArg} --oauth to refresh`,
|
|
397
|
+
})
|
|
398
|
+
);
|
|
399
|
+
} else {
|
|
400
|
+
console.error(`ā ļø OAuth tokens for '${agentArg}' are expired.`);
|
|
401
|
+
console.error(`Run: adcp ${agentArg} --oauth to refresh.\n`);
|
|
402
|
+
}
|
|
403
|
+
process.exit(2);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
} else if (agentArg.startsWith('http://') || agentArg.startsWith('https://')) {
|
|
408
|
+
agentUrl = agentArg;
|
|
409
|
+
if (useOAuth && !jsonOutput) {
|
|
410
|
+
console.error('ā ļø --oauth flag only works with saved agent aliases, not URLs.');
|
|
411
|
+
console.error(' Save the agent first: adcp --save-auth <alias> <url> --oauth\n');
|
|
412
|
+
}
|
|
413
|
+
} else {
|
|
414
|
+
console.error(`ERROR: '${agentArg}' is not a valid agent alias or URL\n`);
|
|
415
|
+
console.error('Built-in aliases: test-mcp, test-a2a, creative');
|
|
416
|
+
console.error(`Saved aliases: ${Object.keys(listAgents()).join(', ') || 'none'}\n`);
|
|
417
|
+
process.exit(2);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Auto-detect protocol if not specified
|
|
421
|
+
if (!protocol) {
|
|
422
|
+
if (!jsonOutput) {
|
|
423
|
+
console.error('š Auto-detecting protocol...');
|
|
424
|
+
}
|
|
425
|
+
try {
|
|
426
|
+
protocol = await detectProtocol(agentUrl);
|
|
427
|
+
if (!jsonOutput) {
|
|
428
|
+
console.error(`ā Detected protocol: ${protocol.toUpperCase()}\n`);
|
|
429
|
+
}
|
|
430
|
+
} catch (error) {
|
|
431
|
+
console.error(`ERROR: Failed to detect protocol: ${error.message}\n`);
|
|
432
|
+
console.error('Please specify protocol: --protocol mcp or --protocol a2a\n');
|
|
433
|
+
process.exit(2);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Build test options
|
|
438
|
+
const testOptions = {
|
|
439
|
+
protocol,
|
|
440
|
+
brief,
|
|
441
|
+
...(finalAuthToken && { auth: { type: 'bearer', token: finalAuthToken } }),
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
if (!jsonOutput) {
|
|
445
|
+
console.log(`\nš§Ŗ Running '${scenario}' tests against ${agentUrl}`);
|
|
446
|
+
console.log(` Protocol: ${protocol.toUpperCase()}`);
|
|
447
|
+
console.log(` Auth: ${oauthTokens ? 'oauth' : finalAuthToken ? 'configured' : 'none'}\n`);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Import and run tests
|
|
451
|
+
try {
|
|
452
|
+
const {
|
|
453
|
+
testAgent: runAgentTests,
|
|
454
|
+
formatTestResults,
|
|
455
|
+
formatTestResultsJSON,
|
|
456
|
+
} = await import('../dist/lib/testing/agent-tester.js');
|
|
457
|
+
|
|
458
|
+
// Silence default logger for cleaner output
|
|
459
|
+
const { setAgentTesterLogger } = await import('../dist/lib/testing/client.js');
|
|
460
|
+
if (!debug) {
|
|
461
|
+
setAgentTesterLogger({
|
|
462
|
+
info: () => {},
|
|
463
|
+
error: () => {},
|
|
464
|
+
warn: () => {},
|
|
465
|
+
debug: () => {},
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const result = await runAgentTests(agentUrl, scenario, testOptions);
|
|
470
|
+
|
|
471
|
+
if (jsonOutput) {
|
|
472
|
+
console.log(formatTestResultsJSON(result));
|
|
473
|
+
} else {
|
|
474
|
+
console.log(formatTestResults(result));
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// Clean up cached connections before exit
|
|
478
|
+
const { closeMCPConnections } = await import('../dist/lib/protocols/mcp.js');
|
|
479
|
+
await closeMCPConnections();
|
|
480
|
+
|
|
481
|
+
// Exit with appropriate code
|
|
482
|
+
process.exit(result.overall_passed ? 0 : 3);
|
|
483
|
+
} catch (error) {
|
|
484
|
+
// Clean up cached connections before exit
|
|
485
|
+
try {
|
|
486
|
+
const { closeMCPConnections } = await import('../dist/lib/protocols/mcp.js');
|
|
487
|
+
await closeMCPConnections();
|
|
488
|
+
} catch {
|
|
489
|
+
/* ignore */
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
console.error(`\nā Test execution failed: ${error.message}`);
|
|
493
|
+
if (debug) {
|
|
494
|
+
console.error('\nStack trace:');
|
|
495
|
+
console.error(error.stack);
|
|
496
|
+
}
|
|
497
|
+
process.exit(1);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Parse a JSON flag value ā supports inline JSON or @file.json (read from file).
|
|
503
|
+
*/
|
|
504
|
+
function parseJsonFlag(flagName, value) {
|
|
505
|
+
if (value.startsWith('@')) {
|
|
506
|
+
const filePath = value.substring(1);
|
|
507
|
+
if (!filePath) {
|
|
508
|
+
console.error(`${flagName} requires a filename after @, e.g. ${flagName} @context.json`);
|
|
509
|
+
process.exit(2);
|
|
510
|
+
}
|
|
511
|
+
let fileContent;
|
|
512
|
+
try {
|
|
513
|
+
fileContent = readFileSync(filePath, 'utf-8');
|
|
514
|
+
} catch (e) {
|
|
515
|
+
console.error(`Cannot read file for ${flagName}: ${e.message}`);
|
|
516
|
+
process.exit(2);
|
|
517
|
+
}
|
|
518
|
+
try {
|
|
519
|
+
return JSON.parse(fileContent);
|
|
520
|
+
} catch (e) {
|
|
521
|
+
console.error(`Invalid JSON in ${filePath} for ${flagName}: ${e.message}`);
|
|
522
|
+
process.exit(2);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
try {
|
|
526
|
+
return JSON.parse(value);
|
|
527
|
+
} catch (e) {
|
|
528
|
+
console.error(`Invalid JSON for ${flagName}: ${e.message}`);
|
|
529
|
+
process.exit(2);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
function closestFlag(input, known) {
|
|
534
|
+
let best = null;
|
|
535
|
+
let bestDist = Infinity;
|
|
536
|
+
for (const flag of known) {
|
|
537
|
+
const d = levenshtein(input, flag);
|
|
538
|
+
if (d < bestDist) {
|
|
539
|
+
bestDist = d;
|
|
540
|
+
best = flag;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
// Only suggest if the edit distance is reasonable (at most ~30% of the flag length)
|
|
544
|
+
return bestDist <= Math.max(2, Math.ceil(input.length * 0.3)) ? best : null;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function levenshtein(a, b) {
|
|
548
|
+
const m = a.length,
|
|
549
|
+
n = b.length;
|
|
550
|
+
const dp = Array.from({ length: m + 1 }, () => new Array(n + 1));
|
|
551
|
+
for (let i = 0; i <= m; i++) dp[i][0] = i;
|
|
552
|
+
for (let j = 0; j <= n; j++) dp[0][j] = j;
|
|
553
|
+
for (let i = 1; i <= m; i++) {
|
|
554
|
+
for (let j = 1; j <= n; j++) {
|
|
555
|
+
dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return dp[m][n];
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function parseAgentOptions(args) {
|
|
562
|
+
const authIndex = args.indexOf('--auth');
|
|
563
|
+
let authToken = process.env.ADCP_AUTH_TOKEN;
|
|
564
|
+
if (authIndex !== -1 && authIndex + 1 < args.length && !args[authIndex + 1].startsWith('--')) {
|
|
565
|
+
authToken = args[authIndex + 1];
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
const protocolIndex = args.indexOf('--protocol');
|
|
569
|
+
let protocolFlag = null;
|
|
570
|
+
if (protocolIndex !== -1 && protocolIndex + 1 < args.length && !args[protocolIndex + 1].startsWith('--')) {
|
|
571
|
+
protocolFlag = args[protocolIndex + 1];
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
const briefIndex = args.indexOf('--brief');
|
|
575
|
+
let brief;
|
|
576
|
+
if (briefIndex !== -1 && briefIndex + 1 < args.length && !args[briefIndex + 1].startsWith('--')) {
|
|
577
|
+
brief = args[briefIndex + 1];
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Storyboard-specific flags (--context, --request) with JSON values
|
|
581
|
+
const contextIndex = args.indexOf('--context');
|
|
582
|
+
let contextValue = null;
|
|
583
|
+
if (contextIndex !== -1 && contextIndex + 1 < args.length && !args[contextIndex + 1].startsWith('--')) {
|
|
584
|
+
contextValue = args[contextIndex + 1];
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
const requestIndex = args.indexOf('--request');
|
|
588
|
+
let requestValue = null;
|
|
589
|
+
if (requestIndex !== -1 && requestIndex + 1 < args.length && !args[requestIndex + 1].startsWith('--')) {
|
|
590
|
+
requestValue = args[requestIndex + 1];
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// Assessment flags (--tracks, --storyboards, --platform-type, --timeout)
|
|
594
|
+
const tracksIndex = args.indexOf('--tracks');
|
|
595
|
+
let tracksValue = null;
|
|
596
|
+
if (tracksIndex !== -1 && tracksIndex + 1 < args.length && !args[tracksIndex + 1].startsWith('--')) {
|
|
597
|
+
tracksValue = args[tracksIndex + 1];
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
const storyboardsIndex = args.indexOf('--storyboards');
|
|
601
|
+
let storyboardsValue = null;
|
|
602
|
+
if (storyboardsIndex !== -1 && storyboardsIndex + 1 < args.length && !args[storyboardsIndex + 1].startsWith('--')) {
|
|
603
|
+
storyboardsValue = args[storyboardsIndex + 1];
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
const platformTypeIndex = args.indexOf('--platform-type');
|
|
607
|
+
let platformTypeValue = null;
|
|
608
|
+
if (
|
|
609
|
+
platformTypeIndex !== -1 &&
|
|
610
|
+
platformTypeIndex + 1 < args.length &&
|
|
611
|
+
!args[platformTypeIndex + 1].startsWith('--')
|
|
612
|
+
) {
|
|
613
|
+
platformTypeValue = args[platformTypeIndex + 1];
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
const timeoutIndex = args.indexOf('--timeout');
|
|
617
|
+
let timeoutValue = null;
|
|
618
|
+
if (timeoutIndex !== -1 && timeoutIndex + 1 < args.length && !args[timeoutIndex + 1].startsWith('--')) {
|
|
619
|
+
timeoutValue = args[timeoutIndex + 1];
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// --multi-instance-strategy's value is captured here solely so it's excluded
|
|
623
|
+
// from `positionalArgs`. The authoritative parse lives in
|
|
624
|
+
// `extractMultiInstanceStrategy(args)` which validates the value and emits
|
|
625
|
+
// error messages; keeping both in sync requires adding the string here when
|
|
626
|
+
// the enum grows.
|
|
627
|
+
const multiInstanceStrategyIndex = args.indexOf('--multi-instance-strategy');
|
|
628
|
+
const multiInstanceStrategyValue =
|
|
629
|
+
multiInstanceStrategyIndex !== -1 &&
|
|
630
|
+
multiInstanceStrategyIndex + 1 < args.length &&
|
|
631
|
+
!args[multiInstanceStrategyIndex + 1].startsWith('--')
|
|
632
|
+
? args[multiInstanceStrategyIndex + 1]
|
|
633
|
+
: null;
|
|
634
|
+
|
|
635
|
+
// --file PATH | --file=PATH: ad-hoc storyboard YAML (spec evolution workflow)
|
|
636
|
+
const fileIndex = args.indexOf('--file');
|
|
637
|
+
let file = null;
|
|
638
|
+
if (fileIndex !== -1 && fileIndex + 1 < args.length && !args[fileIndex + 1].startsWith('--')) {
|
|
639
|
+
file = args[fileIndex + 1];
|
|
640
|
+
} else {
|
|
641
|
+
const eqArg = args.find(a => a.startsWith('--file='));
|
|
642
|
+
if (eqArg) file = eqArg.slice('--file='.length);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
const jsonOutput = args.includes('--json');
|
|
646
|
+
const debug = args.includes('--debug') || process.env.ADCP_DEBUG === 'true';
|
|
647
|
+
const dryRun = args.includes('--dry-run');
|
|
648
|
+
const allowHttp = args.includes('--allow-http');
|
|
649
|
+
// `--no-sandbox` forces `account.sandbox: false` (production) on every
|
|
650
|
+
// request the runner builds. The default behavior leaves the field unset
|
|
651
|
+
// (spec-equivalent to false), but agents that key sandbox routing on
|
|
652
|
+
// field PRESENCE rather than VALUE behave differently. Setting the flag
|
|
653
|
+
// makes the production intent explicit on the wire.
|
|
654
|
+
const noSandbox = args.includes('--no-sandbox');
|
|
655
|
+
|
|
656
|
+
// Webhook-receiver flags are captured here solely so their values are excluded
|
|
657
|
+
// from `positionalArgs`. The authoritative parse lives in
|
|
658
|
+
// `extractWebhookReceiverOptions(args)` which validates and exits on error.
|
|
659
|
+
const webhookReceiverIdx = args.indexOf('--webhook-receiver');
|
|
660
|
+
const webhookReceiverModeValue =
|
|
661
|
+
webhookReceiverIdx !== -1 && webhookReceiverIdx + 1 < args.length && !args[webhookReceiverIdx + 1].startsWith('--')
|
|
662
|
+
? args[webhookReceiverIdx + 1]
|
|
663
|
+
: null;
|
|
664
|
+
const webhookReceiverPortIdx = args.indexOf('--webhook-receiver-port');
|
|
665
|
+
const webhookReceiverPortValue =
|
|
666
|
+
webhookReceiverPortIdx !== -1 &&
|
|
667
|
+
webhookReceiverPortIdx + 1 < args.length &&
|
|
668
|
+
!args[webhookReceiverPortIdx + 1].startsWith('--')
|
|
669
|
+
? args[webhookReceiverPortIdx + 1]
|
|
670
|
+
: null;
|
|
671
|
+
const webhookReceiverPublicUrlIdx = args.indexOf('--webhook-receiver-public-url');
|
|
672
|
+
const webhookReceiverPublicUrlValue =
|
|
673
|
+
webhookReceiverPublicUrlIdx !== -1 &&
|
|
674
|
+
webhookReceiverPublicUrlIdx + 1 < args.length &&
|
|
675
|
+
!args[webhookReceiverPublicUrlIdx + 1].startsWith('--')
|
|
676
|
+
? args[webhookReceiverPublicUrlIdx + 1]
|
|
677
|
+
: null;
|
|
678
|
+
|
|
679
|
+
const invariantsIdx = args.indexOf('--invariants');
|
|
680
|
+
const invariantsValue =
|
|
681
|
+
invariantsIdx !== -1 && invariantsIdx + 1 < args.length && !args[invariantsIdx + 1].startsWith('--')
|
|
682
|
+
? args[invariantsIdx + 1]
|
|
683
|
+
: null;
|
|
684
|
+
|
|
685
|
+
const localAgentIdx = args.indexOf('--local-agent');
|
|
686
|
+
const localAgentValue =
|
|
687
|
+
localAgentIdx !== -1 && localAgentIdx + 1 < args.length && !args[localAgentIdx + 1].startsWith('--')
|
|
688
|
+
? args[localAgentIdx + 1]
|
|
689
|
+
: null;
|
|
690
|
+
|
|
691
|
+
const formatIdx = args.indexOf('--format');
|
|
692
|
+
const formatValue =
|
|
693
|
+
formatIdx !== -1 && formatIdx + 1 < args.length && !args[formatIdx + 1].startsWith('--')
|
|
694
|
+
? args[formatIdx + 1]
|
|
695
|
+
: null;
|
|
696
|
+
|
|
697
|
+
// Filter out flags and their values to find positional args. The `--file=PATH`
|
|
698
|
+
// form is already removed by the `startsWith('--')` check; only the
|
|
699
|
+
// space-separated value needs explicit exclusion. Use explicit nullish check
|
|
700
|
+
// so falsy-but-valid values (e.g. port "0") aren't dropped from the filter.
|
|
701
|
+
const flagValues = [
|
|
702
|
+
authToken,
|
|
703
|
+
protocolFlag,
|
|
704
|
+
brief,
|
|
705
|
+
contextValue,
|
|
706
|
+
requestValue,
|
|
707
|
+
tracksValue,
|
|
708
|
+
storyboardsValue,
|
|
709
|
+
platformTypeValue,
|
|
710
|
+
timeoutValue,
|
|
711
|
+
multiInstanceStrategyValue,
|
|
712
|
+
webhookReceiverModeValue,
|
|
713
|
+
webhookReceiverPortValue,
|
|
714
|
+
webhookReceiverPublicUrlValue,
|
|
715
|
+
invariantsValue,
|
|
716
|
+
localAgentValue,
|
|
717
|
+
formatValue,
|
|
718
|
+
fileIndex !== -1 ? file : null,
|
|
719
|
+
].filter(v => v !== null && v !== undefined);
|
|
720
|
+
const positionalArgs = args.filter(arg => !arg.startsWith('--') && !flagValues.includes(arg));
|
|
721
|
+
|
|
722
|
+
return {
|
|
723
|
+
authToken,
|
|
724
|
+
protocolFlag,
|
|
725
|
+
brief,
|
|
726
|
+
file,
|
|
727
|
+
jsonOutput,
|
|
728
|
+
debug,
|
|
729
|
+
dryRun,
|
|
730
|
+
allowHttp,
|
|
731
|
+
noSandbox,
|
|
732
|
+
positionalArgs,
|
|
733
|
+
localAgent: localAgentValue,
|
|
734
|
+
format: formatValue,
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* If `--oauth` appears in `args` and `agentArg` is a saved alias, ensure
|
|
740
|
+
* the alias has valid OAuth tokens by running the browser flow when
|
|
741
|
+
* needed. No-op when `--oauth` is absent.
|
|
742
|
+
*
|
|
743
|
+
* Mirrors the top-level CLI constraint: `--oauth` requires a saved alias.
|
|
744
|
+
* Raw URLs get a friendly pointer to `--save-auth` instead of a silent pass.
|
|
745
|
+
*/
|
|
746
|
+
async function maybeRunInlineOAuth(agentArg, args, { jsonOutput } = {}) {
|
|
747
|
+
if (!args.includes('--oauth')) return;
|
|
748
|
+
if (!agentArg) return;
|
|
749
|
+
|
|
750
|
+
if (isAlias(agentArg)) {
|
|
751
|
+
const saved = getAgent(agentArg);
|
|
752
|
+
if (!saved) return;
|
|
753
|
+
try {
|
|
754
|
+
await ensureOAuthTokensForAlias(agentArg, saved.url, { quiet: jsonOutput });
|
|
755
|
+
} catch (err) {
|
|
756
|
+
const hint = `Run: adcp --save-auth ${agentArg} ${saved.url} --oauth to re-register`;
|
|
757
|
+
if (jsonOutput) {
|
|
758
|
+
console.log(
|
|
759
|
+
JSON.stringify({
|
|
760
|
+
success: false,
|
|
761
|
+
error: 'oauth_flow_failed',
|
|
762
|
+
alias: agentArg,
|
|
763
|
+
message: err.message,
|
|
764
|
+
hint,
|
|
765
|
+
})
|
|
766
|
+
);
|
|
767
|
+
} else {
|
|
768
|
+
console.error(`\nā OAuth failed for '${agentArg}': ${err.message}`);
|
|
769
|
+
console.error(` ${hint}\n`);
|
|
770
|
+
}
|
|
771
|
+
process.exit(1);
|
|
772
|
+
}
|
|
773
|
+
if (!jsonOutput) console.log('');
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
if (agentArg.startsWith('http://') || agentArg.startsWith('https://')) {
|
|
778
|
+
// Raw URL + `--oauth` never fires the browser flow (no alias to persist
|
|
779
|
+
// tokens under). Treat as a hard error under `--json` so CI jobs exit
|
|
780
|
+
// non-zero instead of silently running and failing N minutes later on
|
|
781
|
+
// a 401 from the storyboard runner.
|
|
782
|
+
if (jsonOutput) {
|
|
783
|
+
console.log(
|
|
784
|
+
JSON.stringify({
|
|
785
|
+
success: false,
|
|
786
|
+
error: 'oauth_requires_alias',
|
|
787
|
+
message: `--oauth requires a saved alias, not a raw URL. Save first: adcp --save-auth <alias> ${agentArg} --oauth`,
|
|
788
|
+
})
|
|
789
|
+
);
|
|
790
|
+
process.exit(2);
|
|
791
|
+
}
|
|
792
|
+
console.error('ā ļø --oauth requires a saved agent alias, not a raw URL.');
|
|
793
|
+
console.error(` Save first: adcp --save-auth <alias> ${agentArg} --oauth\n`);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* Run the interactive browser OAuth flow against `url` and persist the
|
|
799
|
+
* resulting tokens under `alias`. Idempotent ā returns early if the alias
|
|
800
|
+
* already has valid tokens.
|
|
801
|
+
*
|
|
802
|
+
* Callers:
|
|
803
|
+
* - `adcp --save-auth <alias> <url> --oauth` (first-time setup)
|
|
804
|
+
* - `adcp storyboard run <alias> --oauth` (inline auth before a run)
|
|
805
|
+
* - any other subcommand that wants the same contract
|
|
806
|
+
*
|
|
807
|
+
* Only supports MCP ā authorization-code OAuth is an MCP concept in AdCP.
|
|
808
|
+
* A2A agents use static bearer tokens or client credentials.
|
|
809
|
+
*
|
|
810
|
+
* @returns The updated saved agent record (with oauth_tokens and oauth_client).
|
|
811
|
+
*/
|
|
812
|
+
async function ensureOAuthTokensForAlias(alias, url, { quiet = false } = {}) {
|
|
813
|
+
const existing = getAgent(alias);
|
|
814
|
+
if (existing && hasValidOAuthTokens(existing)) {
|
|
815
|
+
if (!quiet) console.log(`Using saved OAuth tokens for '${alias}'.`);
|
|
816
|
+
return existing;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
// Spread the in-flight PKCE verifier too: if a prior attempt crashed mid-
|
|
820
|
+
// flow the verifier lives on the saved record, and without it the MCP SDK
|
|
821
|
+
// throws "No PKCE code verifier found" when the AS redirects back.
|
|
822
|
+
const tempAgent = {
|
|
823
|
+
id: alias,
|
|
824
|
+
name: alias,
|
|
825
|
+
agent_uri: url,
|
|
826
|
+
protocol: 'mcp',
|
|
827
|
+
...(existing?.oauth_client && { oauth_client: existing.oauth_client }),
|
|
828
|
+
...(existing?.oauth_tokens && { oauth_tokens: existing.oauth_tokens }),
|
|
829
|
+
...(existing?.oauth_code_verifier && { oauth_code_verifier: existing.oauth_code_verifier }),
|
|
830
|
+
};
|
|
831
|
+
|
|
832
|
+
const { Client: MCPClient } = require('@modelcontextprotocol/sdk/client/index.js');
|
|
833
|
+
const { StreamableHTTPClientTransport } = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
|
|
834
|
+
const { UnauthorizedError } = require('@modelcontextprotocol/sdk/client/auth.js');
|
|
835
|
+
|
|
836
|
+
const oauthProvider = createCLIOAuthProvider(tempAgent, { quiet });
|
|
837
|
+
const mcpClient = new MCPClient({ name: 'adcp-cli', version: '1.0.0' });
|
|
838
|
+
const transport = new StreamableHTTPClientTransport(new URL(url), { authProvider: oauthProvider });
|
|
839
|
+
|
|
840
|
+
// Persist back to disk if the MCP SDK silently refreshed tokens during
|
|
841
|
+
// connect/finishAuth ā otherwise the refreshed access_token dies with
|
|
842
|
+
// tempAgent and the next call burns a second refresh. Saves only when
|
|
843
|
+
// something changed to avoid a needless write on the happy idempotent path.
|
|
844
|
+
const persistIfChanged = () => {
|
|
845
|
+
if (!tempAgent.oauth_tokens) return null;
|
|
846
|
+
const same =
|
|
847
|
+
existing?.oauth_tokens?.access_token === tempAgent.oauth_tokens.access_token &&
|
|
848
|
+
existing?.oauth_tokens?.refresh_token === tempAgent.oauth_tokens.refresh_token;
|
|
849
|
+
if (same) return existing;
|
|
850
|
+
const merged = {
|
|
851
|
+
...(existing ?? {}),
|
|
852
|
+
url,
|
|
853
|
+
protocol: 'mcp',
|
|
854
|
+
oauth_tokens: tempAgent.oauth_tokens,
|
|
855
|
+
oauth_client: tempAgent.oauth_client ?? existing?.oauth_client,
|
|
856
|
+
};
|
|
857
|
+
saveAgent(alias, merged);
|
|
858
|
+
return merged;
|
|
859
|
+
};
|
|
860
|
+
|
|
861
|
+
try {
|
|
862
|
+
if (!quiet) console.log(`Authorizing '${alias}' via browserā¦`);
|
|
863
|
+
try {
|
|
864
|
+
await mcpClient.connect(transport);
|
|
865
|
+
// Connected without needing OAuth ā agent isn't gated. Persist in
|
|
866
|
+
// case the SDK silently refreshed tokens during connect.
|
|
867
|
+
const refreshed = persistIfChanged();
|
|
868
|
+
if (!quiet) {
|
|
869
|
+
console.log(
|
|
870
|
+
refreshed && refreshed !== existing
|
|
871
|
+
? 'Server accepted refreshed OAuth tokens.'
|
|
872
|
+
: 'Server did not require OAuth ā no tokens saved.'
|
|
873
|
+
);
|
|
874
|
+
}
|
|
875
|
+
return refreshed ?? existing ?? null;
|
|
876
|
+
} catch (error) {
|
|
877
|
+
if (!(error instanceof UnauthorizedError) && error.name !== 'UnauthorizedError') {
|
|
878
|
+
throw error;
|
|
879
|
+
}
|
|
880
|
+
const code = await oauthProvider.waitForCallback();
|
|
881
|
+
await transport.finishAuth(code);
|
|
882
|
+
const merged = persistIfChanged();
|
|
883
|
+
if (!quiet) console.log(`OAuth tokens saved to '${alias}'.`);
|
|
884
|
+
return merged ?? existing ?? null;
|
|
885
|
+
}
|
|
886
|
+
} finally {
|
|
887
|
+
await oauthProvider.cleanup().catch(() => {});
|
|
888
|
+
await mcpClient.close().catch(() => {});
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
/**
|
|
893
|
+
* Build the `auth` option for the testing library from a resolved agent.
|
|
894
|
+
* Single source of truth for CLI ā lib auth handoff so every runner
|
|
895
|
+
* (storyboard, step, fuzz, grade) uses the same precedence:
|
|
896
|
+
* client credentials > authorization-code OAuth > static bearer.
|
|
897
|
+
*/
|
|
898
|
+
function buildResolvedAuthOption({
|
|
899
|
+
resolvedAuth,
|
|
900
|
+
resolvedOauthTokens,
|
|
901
|
+
resolvedOauthClient,
|
|
902
|
+
resolvedOauthClientCredentials,
|
|
903
|
+
}) {
|
|
904
|
+
if (resolvedOauthClientCredentials) {
|
|
905
|
+
return {
|
|
906
|
+
auth: {
|
|
907
|
+
type: 'oauth_client_credentials',
|
|
908
|
+
credentials: resolvedOauthClientCredentials,
|
|
909
|
+
...(resolvedOauthTokens && { tokens: resolvedOauthTokens }),
|
|
910
|
+
},
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
if (resolvedOauthTokens) {
|
|
914
|
+
return {
|
|
915
|
+
auth: {
|
|
916
|
+
type: 'oauth',
|
|
917
|
+
tokens: resolvedOauthTokens,
|
|
918
|
+
...(resolvedOauthClient && { client: resolvedOauthClient }),
|
|
919
|
+
},
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
if (resolvedAuth) {
|
|
923
|
+
return { auth: { type: 'bearer', token: resolvedAuth } };
|
|
924
|
+
}
|
|
925
|
+
return {};
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* Resolve an agent argument (alias or URL) to
|
|
930
|
+
* `{ agentUrl, protocol, authToken, oauthTokens, oauthClient, oauthClientCredentials, aliasId }`.
|
|
931
|
+
*
|
|
932
|
+
* Auth resolution order:
|
|
933
|
+
* 1. Explicit --auth token from CLI (bearer)
|
|
934
|
+
* 2. ADCP_AUTH_TOKEN env var
|
|
935
|
+
* 3. Saved OAuth client credentials (if alias has them ā library refreshes per call)
|
|
936
|
+
* 4. Saved OAuth tokens (if alias has them ā returned as-is; library refreshes on 401)
|
|
937
|
+
* 5. Static auth_token from alias or built-in
|
|
938
|
+
* 6. None
|
|
939
|
+
*
|
|
940
|
+
* Client-credentials refresh happens inside `ProtocolClient.callTool`, so this
|
|
941
|
+
* function deliberately does NOT exchange ā it just surfaces the saved
|
|
942
|
+
* credentials so the caller can hand them to the testing/protocol layer.
|
|
943
|
+
*/
|
|
944
|
+
async function resolveAgent(agentArg, authToken, protocolFlag, jsonOutput) {
|
|
945
|
+
let agentUrl;
|
|
946
|
+
let protocol = protocolFlag;
|
|
947
|
+
let finalAuthToken = authToken;
|
|
948
|
+
let oauthTokens;
|
|
949
|
+
let oauthClient;
|
|
950
|
+
let oauthClientCredentials;
|
|
951
|
+
let aliasId;
|
|
952
|
+
|
|
953
|
+
if (BUILT_IN_AGENTS[agentArg]) {
|
|
954
|
+
const builtIn = BUILT_IN_AGENTS[agentArg];
|
|
955
|
+
agentUrl = builtIn.url;
|
|
956
|
+
protocol = protocol || builtIn.protocol;
|
|
957
|
+
finalAuthToken = finalAuthToken || builtIn.auth_token;
|
|
958
|
+
} else if (isAlias(agentArg)) {
|
|
959
|
+
const savedAgent = getAgent(agentArg);
|
|
960
|
+
agentUrl = savedAgent.url;
|
|
961
|
+
protocol = protocol || savedAgent.protocol;
|
|
962
|
+
aliasId = agentArg;
|
|
963
|
+
if (savedAgent.oauth_client_credentials) {
|
|
964
|
+
oauthClientCredentials = savedAgent.oauth_client_credentials;
|
|
965
|
+
oauthTokens = savedAgent.oauth_tokens;
|
|
966
|
+
} else if (savedAgent.oauth_tokens) {
|
|
967
|
+
oauthTokens = savedAgent.oauth_tokens;
|
|
968
|
+
oauthClient = savedAgent.oauth_client;
|
|
969
|
+
}
|
|
970
|
+
finalAuthToken = finalAuthToken || getEffectiveAuthToken(savedAgent);
|
|
971
|
+
} else if (agentArg.startsWith('http://') || agentArg.startsWith('https://')) {
|
|
972
|
+
agentUrl = agentArg;
|
|
973
|
+
} else {
|
|
974
|
+
console.error(`ERROR: '${agentArg}' is not a valid agent alias or URL\n`);
|
|
975
|
+
console.error('Built-in aliases: test-mcp, test-a2a, creative');
|
|
976
|
+
console.error(`Saved aliases: ${Object.keys(listAgents()).join(', ') || 'none'}\n`);
|
|
977
|
+
process.exit(2);
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
// Auto-detect protocol if not specified
|
|
981
|
+
if (!protocol) {
|
|
982
|
+
if (!jsonOutput) console.error('Auto-detecting protocol...');
|
|
983
|
+
try {
|
|
984
|
+
protocol = await detectProtocol(agentUrl);
|
|
985
|
+
if (!jsonOutput) console.error(`Detected protocol: ${protocol.toUpperCase()}\n`);
|
|
986
|
+
} catch (error) {
|
|
987
|
+
console.error(`ERROR: Failed to detect protocol: ${error.message}\n`);
|
|
988
|
+
process.exit(2);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
return {
|
|
993
|
+
agentUrl,
|
|
994
|
+
protocol,
|
|
995
|
+
authToken: finalAuthToken,
|
|
996
|
+
oauthTokens,
|
|
997
|
+
oauthClient,
|
|
998
|
+
oauthClientCredentials,
|
|
999
|
+
aliasId,
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
async function handleComplyCommand(args) {
|
|
1004
|
+
// 'adcp comply' is an alias for 'adcp storyboard run'
|
|
1005
|
+
if (!args.includes('--json') && !args.includes('--help') && !args.includes('-h')) {
|
|
1006
|
+
console.error('DEPRECATED: "adcp comply" will be removed. Use "adcp storyboard run" instead.\n');
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
if (args.includes('--help') || args.length === 0) {
|
|
1010
|
+
console.log(`
|
|
1011
|
+
DEPRECATED: "adcp comply" will be removed in v5.
|
|
1012
|
+
Use "adcp storyboard run" instead. Run "adcp storyboard run --help" for full usage.
|
|
1013
|
+
`);
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
// Delegate to storyboard run (full assessment mode)
|
|
1018
|
+
await handleStoryboardRun(args);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
function printUsage() {
|
|
1022
|
+
console.log(`
|
|
1023
|
+
AdCP CLI Tool
|
|
1024
|
+
|
|
1025
|
+
USAGE:
|
|
1026
|
+
adcp <agent> [tool] [payload] [options]
|
|
1027
|
+
adcp <command> [args]
|
|
1028
|
+
|
|
1029
|
+
COMMANDS:
|
|
1030
|
+
storyboard <subcommand> Test agent flows (run, list, show, step)
|
|
1031
|
+
grade <subject> <url> Conformance graders (e.g. request-signing)
|
|
1032
|
+
fuzz <url> Property-based conformance fuzzing against schemas
|
|
1033
|
+
signing <subcommand> RFC 9421 signing key tools (generate, verify)
|
|
1034
|
+
check-network Validate managed publisher network deployment
|
|
1035
|
+
diagnose-auth <alias|url> Diagnose OAuth handshake with ranked hypotheses
|
|
1036
|
+
(alias: "adcp diagnose oauth <alias|url>")
|
|
1037
|
+
comply <agent> [options] DEPRECATED ā use "storyboard run" instead
|
|
1038
|
+
test <agent> [scenario] Run individual test scenarios (legacy)
|
|
1039
|
+
registry <command> Brand/property registry lookups
|
|
1040
|
+
|
|
1041
|
+
Run 'adcp <command> --help' for details on each command.
|
|
1042
|
+
|
|
1043
|
+
QUICK START:
|
|
1044
|
+
adcp test-mcp List tools on the test agent
|
|
1045
|
+
adcp test-mcp get_products '{"brief":"coffee"}' Call a tool
|
|
1046
|
+
adcp storyboard run test-mcp Run capability-driven assessment
|
|
1047
|
+
adcp storyboard run test-mcp media_buy_seller Run a single storyboard or bundle
|
|
1048
|
+
adcp test test-mcp full_sales_flow Run test scenario
|
|
1049
|
+
|
|
1050
|
+
AGENT MANAGEMENT:
|
|
1051
|
+
--save-auth <alias> [url] Save agent with alias
|
|
1052
|
+
Static bearer: --auth <token> | --no-auth
|
|
1053
|
+
OAuth (browser): --oauth
|
|
1054
|
+
OAuth (M2M): --client-id <id> | --client-id-env <VAR>
|
|
1055
|
+
--client-secret <s> | --client-secret-env <VAR>
|
|
1056
|
+
[--scope <scope>] [--oauth-auth-method basic|body]
|
|
1057
|
+
[--oauth-token-url <url>] (optional; auto-discovered)
|
|
1058
|
+
--list-agents List saved agents
|
|
1059
|
+
--remove-agent <alias> Remove saved agent
|
|
1060
|
+
--show-config Show config location
|
|
1061
|
+
|
|
1062
|
+
OPTIONS:
|
|
1063
|
+
--protocol PROTO Force protocol: mcp or a2a (default: auto-detect)
|
|
1064
|
+
--auth TOKEN Authentication token
|
|
1065
|
+
--oauth OAuth authentication (MCP only, opens browser)
|
|
1066
|
+
--clear-oauth Clear saved OAuth tokens
|
|
1067
|
+
--wait Wait for async/webhook responses
|
|
1068
|
+
--json Raw JSON output
|
|
1069
|
+
--debug Debug output
|
|
1070
|
+
--allow-v2 Suppress the v2-sunset warning (unsupported since 2026-04-20)
|
|
1071
|
+
--help, -h Show help
|
|
1072
|
+
|
|
1073
|
+
BUILT-IN AGENTS:
|
|
1074
|
+
test-mcp AdCP public test agent (MCP)
|
|
1075
|
+
test-a2a AdCP public test agent (A2A)
|
|
1076
|
+
test-no-auth Test agent without auth (MCP)
|
|
1077
|
+
test-a2a-no-auth Test agent without auth (A2A)
|
|
1078
|
+
creative AdCP creative agent (MCP)
|
|
1079
|
+
|
|
1080
|
+
Full documentation: https://github.com/adcontextprotocol/adcp-client/blob/main/docs/CLI.md
|
|
1081
|
+
`);
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
1085
|
+
// Storyboard command
|
|
1086
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
1087
|
+
|
|
1088
|
+
async function handleStoryboardCommand(args) {
|
|
1089
|
+
if (args.includes('--help') || args.includes('-h') || args.length === 0) {
|
|
1090
|
+
console.log(`
|
|
1091
|
+
Storyboard-driven testing
|
|
1092
|
+
|
|
1093
|
+
USAGE:
|
|
1094
|
+
adcp storyboard list [--json]
|
|
1095
|
+
adcp storyboard show <id> [--json]
|
|
1096
|
+
adcp storyboard run <agent> [id|bundle] [options]
|
|
1097
|
+
adcp storyboard run <agent> --file <path.yaml> [options]
|
|
1098
|
+
adcp storyboard run --local-agent <module> [id|bundle] [options]
|
|
1099
|
+
adcp storyboard step <agent> <storyboard_id> <step_id> [options]
|
|
1100
|
+
|
|
1101
|
+
SUBCOMMANDS:
|
|
1102
|
+
list Enumerate storyboards in the compliance cache
|
|
1103
|
+
show <id> Show storyboard structure (phases, steps)
|
|
1104
|
+
run <agent> [id] Run storyboards. With id, run one bundle/storyboard; otherwise
|
|
1105
|
+
the agent's get_adcp_capabilities drives selection.
|
|
1106
|
+
step <agent> <id> <step_id> Run a single step (stateless, LLM-friendly)
|
|
1107
|
+
|
|
1108
|
+
RUN OPTIONS (full assessment):
|
|
1109
|
+
--tracks TRACKS Comma-separated tracks to include in the report
|
|
1110
|
+
--storyboards IDS Comma-separated storyboard/bundle IDs to run
|
|
1111
|
+
--file PATH Run an ad-hoc storyboard YAML (spec evolution)
|
|
1112
|
+
--timeout SECONDS Timeout in seconds (default: 120)
|
|
1113
|
+
--brief TEXT Custom brief for product discovery
|
|
1114
|
+
--no-sandbox Force account.sandbox=false on every request. The
|
|
1115
|
+
default leaves sandbox unset (spec-equivalent to false),
|
|
1116
|
+
but agents that branch on field PRESENCE behave
|
|
1117
|
+
differently from agents that branch on VALUE.
|
|
1118
|
+
|
|
1119
|
+
WEBHOOK OPTIONS:
|
|
1120
|
+
--webhook-receiver [MODE] Host an ephemeral receiver so expect_webhook*
|
|
1121
|
+
steps can grade outbound webhooks. MODE is
|
|
1122
|
+
"loopback" (default, 127.0.0.1) or "proxy"
|
|
1123
|
+
(operator-supplied public URL). Required for
|
|
1124
|
+
the webhook-emission and idempotency bundles
|
|
1125
|
+
to produce grades instead of skips.
|
|
1126
|
+
--webhook-receiver-port PORT Force a bind port (default: auto-assign).
|
|
1127
|
+
--webhook-receiver-public-url URL
|
|
1128
|
+
Public HTTPS base URL for proxy mode. Implies
|
|
1129
|
+
--webhook-receiver proxy when used alone.
|
|
1130
|
+
Incompatible with --multi-instance-strategy
|
|
1131
|
+
multi-pass (receiver URL is per-pass).
|
|
1132
|
+
--webhook-receiver-auto-tunnel Autodetect a tunnel binary on PATH (ngrok or
|
|
1133
|
+
cloudflared; override with $ADCP_WEBHOOK_TUNNEL),
|
|
1134
|
+
spawn it against the receiver, and plug its
|
|
1135
|
+
public URL into proxy mode. Cleans up on exit.
|
|
1136
|
+
Custom override: $ADCP_WEBHOOK_TUNNEL="<cmd>
|
|
1137
|
+
{port}"; the command must emit a line
|
|
1138
|
+
containing \`ADCP_TUNNEL_URL=<https-url>\`
|
|
1139
|
+
on stdout or stderr (first match wins) and
|
|
1140
|
+
should exec the tunnel directly (no
|
|
1141
|
+
\`sh -c\` wrapper ā cleanup signals the
|
|
1142
|
+
direct child only).
|
|
1143
|
+
HTTP-on-the-wire ā spec-compliant.
|
|
1144
|
+
|
|
1145
|
+
OPTIONS:
|
|
1146
|
+
--context JSON Pass context from previous step (step only)
|
|
1147
|
+
--request JSON Override sample_request for the step (step only)
|
|
1148
|
+
--json JSON output (recommended for LLM consumption)
|
|
1149
|
+
--auth TOKEN Authentication token
|
|
1150
|
+
--oauth Run the browser OAuth flow inline if the saved alias
|
|
1151
|
+
has no valid tokens yet. Requires a saved alias
|
|
1152
|
+
(use --save-auth first for raw URLs). MCP only.
|
|
1153
|
+
--protocol PROTO Force protocol: mcp or a2a
|
|
1154
|
+
--dry-run Preview steps without executing
|
|
1155
|
+
--debug Debug output
|
|
1156
|
+
--invariants SPECS Comma-separated module specifiers to dynamic-import
|
|
1157
|
+
before running. Each module must call registerAssertion(...)
|
|
1158
|
+
at import time so the storyboard's invariants field can
|
|
1159
|
+
resolve. Relative paths (./my-invariants.js) resolve
|
|
1160
|
+
against the current directory; bare specifiers
|
|
1161
|
+
(@org/invariants) resolve as npm packages. Modules run
|
|
1162
|
+
with full CLI privileges ā only load code you trust.
|
|
1163
|
+
--local-agent PATH Spin up the agent in-process. PATH imports a module
|
|
1164
|
+
whose default export (or \`createAgent\` named export)
|
|
1165
|
+
matches \`serve()\`'s factory signature:
|
|
1166
|
+
\`(ctx) => createAdcpServer({...})\`. The CLI binds
|
|
1167
|
+
an ephemeral HTTP port, seeds compliance fixtures,
|
|
1168
|
+
runs storyboards, and tears down ā no url/auth flags
|
|
1169
|
+
required. See docs/guides/VALIDATE-LOCALLY.md for
|
|
1170
|
+
the full pattern.
|
|
1171
|
+
--format FORMAT Output format for single-storyboard and --local-agent
|
|
1172
|
+
runs. One of: table (default), json, junit. junit
|
|
1173
|
+
emits a JUnit XML report to stdout ā each storyboard
|
|
1174
|
+
becomes a testsuite, each step a testcase.
|
|
1175
|
+
|
|
1176
|
+
OUTPUT:
|
|
1177
|
+
If you see a \`š” Hint: ā¦\` line in a failing step, the runner has
|
|
1178
|
+
traced the rejection to seller-side catalog drift between two of the
|
|
1179
|
+
agent's own tools ā not an SDK bug. Fix the agent's catalog, not the
|
|
1180
|
+
client. Hints fire only when the rejected value can be tied back to
|
|
1181
|
+
a prior-step \`\$context.*\` write; otherwise they stay silent. They
|
|
1182
|
+
also land in JUnit XML \`<failure>\` bodies and on
|
|
1183
|
+
\`StoryboardStepResult.hints[]\` in JSON output, and the run summary
|
|
1184
|
+
appends \`Ā· N hints\` when any fired. Full reader's guide:
|
|
1185
|
+
docs/guides/VALIDATE-YOUR-AGENT.md § Reading hint lines.
|
|
1186
|
+
|
|
1187
|
+
NOTE: Storyboards are pulled from the compliance cache populated by
|
|
1188
|
+
\`npm run sync-schemas\` (fetches /protocol/{version}.tgz).
|
|
1189
|
+
|
|
1190
|
+
EXAMPLES:
|
|
1191
|
+
adcp storyboard run test-mcp # capability-driven assessment
|
|
1192
|
+
adcp storyboard run test-mcp --tracks core,products # filter report by track
|
|
1193
|
+
adcp storyboard run test-mcp sales-guaranteed # run one specialism bundle
|
|
1194
|
+
adcp storyboard run test-mcp --file ./my-wip.yaml # test a local YAML
|
|
1195
|
+
adcp storyboard run test-mcp webhook-emission --webhook-receiver
|
|
1196
|
+
# grade outbound webhooks via loopback receiver
|
|
1197
|
+
adcp storyboard run my-remote idempotency \\
|
|
1198
|
+
--webhook-receiver proxy --webhook-receiver-public-url https://run.example.com
|
|
1199
|
+
# remote agent via tunnel (ngrok/cloudflared/ingress)
|
|
1200
|
+
adcp storyboard run my-remote webhook-emission --webhook-receiver-auto-tunnel
|
|
1201
|
+
# remote agent, tunnel autodetected + managed
|
|
1202
|
+
adcp storyboard run test-mcp sales-non-guaranteed \\
|
|
1203
|
+
--invariants ./my-invariants.js,@adcp/invariants # register cross-step invariants
|
|
1204
|
+
adcp storyboard list
|
|
1205
|
+
adcp storyboard show media_buy_seller
|
|
1206
|
+
adcp storyboard step test-mcp media_buy_seller sync_accounts --json
|
|
1207
|
+
`);
|
|
1208
|
+
process.exit(0);
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
const subcommand = args[0];
|
|
1212
|
+
const subArgs = args.slice(1);
|
|
1213
|
+
|
|
1214
|
+
switch (subcommand) {
|
|
1215
|
+
case 'list':
|
|
1216
|
+
await handleStoryboardList(subArgs);
|
|
1217
|
+
break;
|
|
1218
|
+
case 'show':
|
|
1219
|
+
await handleStoryboardShow(subArgs);
|
|
1220
|
+
break;
|
|
1221
|
+
case 'run':
|
|
1222
|
+
await handleStoryboardRun(subArgs);
|
|
1223
|
+
break;
|
|
1224
|
+
case 'step':
|
|
1225
|
+
await handleStoryboardStepCmd(subArgs);
|
|
1226
|
+
break;
|
|
1227
|
+
default:
|
|
1228
|
+
console.error(`Unknown storyboard subcommand: ${subcommand}`);
|
|
1229
|
+
console.error('Available: list, show, run, step');
|
|
1230
|
+
process.exit(2);
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
async function handleStoryboardList(args) {
|
|
1235
|
+
const { listBundles, loadBundleStoryboards } = await import('../dist/lib/testing/storyboard/index.js');
|
|
1236
|
+
const jsonOutput = args.includes('--json');
|
|
1237
|
+
// --stateful: keep only storyboards that contain at least one step marked
|
|
1238
|
+
// `stateful: true`. That's the same predicate the multi-instance runner
|
|
1239
|
+
// uses to identify storyboards whose writeāread chains surface in-process
|
|
1240
|
+
// state bugs, so this filter returns the "worth round-robining" set.
|
|
1241
|
+
const statefulOnly = args.includes('--stateful');
|
|
1242
|
+
|
|
1243
|
+
let bundles;
|
|
1244
|
+
try {
|
|
1245
|
+
bundles = listBundles();
|
|
1246
|
+
} catch (err) {
|
|
1247
|
+
console.error(`ERROR: ${err.message}`);
|
|
1248
|
+
process.exit(1);
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
const grouped = { universal: [], protocol: [], specialism: [] };
|
|
1252
|
+
const flat = [];
|
|
1253
|
+
for (const ref of bundles) {
|
|
1254
|
+
const storyboards = loadBundleStoryboards(ref);
|
|
1255
|
+
if (storyboards.length === 0) continue; // skip schema/fixture YAMLs that aren't runnable
|
|
1256
|
+
const summaryStoryboards = storyboards
|
|
1257
|
+
.map(s => {
|
|
1258
|
+
const allSteps = s.phases.flatMap(p => p.steps);
|
|
1259
|
+
const statefulStepCount = allSteps.filter(step => step.stateful === true).length;
|
|
1260
|
+
return {
|
|
1261
|
+
id: s.id,
|
|
1262
|
+
title: s.title,
|
|
1263
|
+
category: s.category,
|
|
1264
|
+
summary: s.summary,
|
|
1265
|
+
track: s.track,
|
|
1266
|
+
step_count: allSteps.length,
|
|
1267
|
+
stateful_step_count: statefulStepCount,
|
|
1268
|
+
};
|
|
1269
|
+
})
|
|
1270
|
+
.filter(s => !statefulOnly || s.stateful_step_count > 0);
|
|
1271
|
+
if (summaryStoryboards.length === 0) continue;
|
|
1272
|
+
const summary = { bundle_kind: ref.kind, bundle_id: ref.id, storyboards: summaryStoryboards };
|
|
1273
|
+
grouped[ref.kind].push(summary);
|
|
1274
|
+
for (const sb of summaryStoryboards) {
|
|
1275
|
+
flat.push({ ...sb, bundle_kind: ref.kind, bundle_id: ref.id });
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
if (jsonOutput) {
|
|
1280
|
+
await writeJsonOutput({ bundles: grouped, storyboards: flat, filter: statefulOnly ? 'stateful' : null });
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
const heading = statefulOnly
|
|
1285
|
+
? 'Stateful compliance storyboards (1+ step marked stateful: true)'
|
|
1286
|
+
: 'Compliance storyboards (from local cache)';
|
|
1287
|
+
console.log(`\n${heading}\n`);
|
|
1288
|
+
for (const kind of ['universal', 'protocol', 'specialism']) {
|
|
1289
|
+
if (grouped[kind].length === 0) continue;
|
|
1290
|
+
const header =
|
|
1291
|
+
kind === 'universal' ? 'Universal (required for all agents)' : kind === 'protocol' ? 'Protocols' : 'Specialisms';
|
|
1292
|
+
console.log(`${header}:`);
|
|
1293
|
+
for (const bundle of grouped[kind]) {
|
|
1294
|
+
console.log(` [${bundle.bundle_id}]`);
|
|
1295
|
+
for (const sb of bundle.storyboards) {
|
|
1296
|
+
const statefulSuffix = statefulOnly || sb.stateful_step_count > 0 ? `, ${sb.stateful_step_count} stateful` : '';
|
|
1297
|
+
console.log(` ${sb.id} ā ${sb.title} (${sb.step_count} steps${statefulSuffix})`);
|
|
1298
|
+
if (sb.track) console.log(` Track: ${sb.track}`);
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
console.log();
|
|
1302
|
+
}
|
|
1303
|
+
const suffix = statefulOnly ? ' with at least one stateful step' : '';
|
|
1304
|
+
console.log(
|
|
1305
|
+
`${flat.length} storyboard(s)${suffix} across ${grouped.universal.length + grouped.protocol.length + grouped.specialism.length} bundle(s).`
|
|
1306
|
+
);
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
async function handleStoryboardShow(args) {
|
|
1310
|
+
const { resolveBundleOrStoryboard, findBundleById, listAllComplianceStoryboards } =
|
|
1311
|
+
await import('../dist/lib/testing/storyboard/index.js');
|
|
1312
|
+
const jsonOutput = args.includes('--json');
|
|
1313
|
+
const positionalArgs = args.filter(a => !a.startsWith('--'));
|
|
1314
|
+
const storyboardId = positionalArgs[0];
|
|
1315
|
+
|
|
1316
|
+
if (!storyboardId) {
|
|
1317
|
+
console.error('Usage: adcp storyboard show <id>');
|
|
1318
|
+
process.exit(2);
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
const matches = resolveBundleOrStoryboard(storyboardId);
|
|
1322
|
+
if (matches.length === 0) {
|
|
1323
|
+
console.error(`Storyboard or bundle not found: ${storyboardId}`);
|
|
1324
|
+
console.error(
|
|
1325
|
+
`Available: ${listAllComplianceStoryboards()
|
|
1326
|
+
.map(s => s.id)
|
|
1327
|
+
.join(', ')}`
|
|
1328
|
+
);
|
|
1329
|
+
process.exit(2);
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
const storyboard = matches[0];
|
|
1333
|
+
const bundle = findBundleById(storyboardId);
|
|
1334
|
+
if (bundle && matches.length > 1 && !jsonOutput) {
|
|
1335
|
+
console.log(
|
|
1336
|
+
`\n[${bundle.kind} bundle "${bundle.id}"] contains ${matches.length} storyboards: ${matches
|
|
1337
|
+
.map(s => s.id)
|
|
1338
|
+
.join(', ')}`
|
|
1339
|
+
);
|
|
1340
|
+
console.log(`Showing first (${storyboard.id}). Run 'storyboard show <id>' for another.`);
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
if (jsonOutput) {
|
|
1344
|
+
await writeJsonOutput(storyboard);
|
|
1345
|
+
} else {
|
|
1346
|
+
console.log(`\n${storyboard.title}`);
|
|
1347
|
+
console.log(`${'ā'.repeat(storyboard.title.length)}`);
|
|
1348
|
+
console.log(`ID: ${storyboard.id} | Category: ${storyboard.category} | Version: ${storyboard.version}`);
|
|
1349
|
+
if (storyboard.track) console.log(`Track: ${storyboard.track}`);
|
|
1350
|
+
console.log(`\n${storyboard.summary}`);
|
|
1351
|
+
if (storyboard.narrative) {
|
|
1352
|
+
console.log(`\n${storyboard.narrative.trim()}`);
|
|
1353
|
+
}
|
|
1354
|
+
console.log();
|
|
1355
|
+
|
|
1356
|
+
for (const phase of storyboard.phases) {
|
|
1357
|
+
const stepCount = phase.steps.length;
|
|
1358
|
+
console.log(`Phase: ${phase.title} (${stepCount} step${stepCount !== 1 ? 's' : ''})`);
|
|
1359
|
+
if (phase.narrative) {
|
|
1360
|
+
// Indent phase narrative
|
|
1361
|
+
const lines = phase.narrative.trim().split('\n');
|
|
1362
|
+
for (const line of lines) {
|
|
1363
|
+
console.log(` ${line}`);
|
|
1364
|
+
}
|
|
1365
|
+
console.log();
|
|
1366
|
+
}
|
|
1367
|
+
for (const step of phase.steps) {
|
|
1368
|
+
const validationCount = step.validations?.length || 0;
|
|
1369
|
+
const statefulTag = step.stateful ? ' [stateful]' : '';
|
|
1370
|
+
console.log(` ā ${step.id}: ${step.title}${statefulTag}`);
|
|
1371
|
+
console.log(` Task: ${step.task} | Validations: ${validationCount}`);
|
|
1372
|
+
if (step.expected) {
|
|
1373
|
+
// Show expected on one line, trimmed
|
|
1374
|
+
const expected = step.expected.trim().split('\n')[0];
|
|
1375
|
+
console.log(` Expected: ${expected}`);
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
console.log();
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
// Flags that used to be accepted but have been removed from the SDK/CLI.
|
|
1384
|
+
// Silent-ignore hides real divergence between author intent and runtime behavior
|
|
1385
|
+
// (observed in third-party CI scripts that still pass `--platform-type`).
|
|
1386
|
+
// Each entry: { since: version-string, hint: what-to-do-instead }.
|
|
1387
|
+
//
|
|
1388
|
+
// NOTE: `parseAgentOptions` still captures `--platform-type`'s value (line ~602)
|
|
1389
|
+
// solely so the value doesn't leak into `positionalArgs`. That capture + this
|
|
1390
|
+
// warning are both necessary ā removing the capture would make a bare
|
|
1391
|
+
// `--platform-type X` turn `X` into an agent alias lookup.
|
|
1392
|
+
const REMOVED_FLAGS = {
|
|
1393
|
+
'--platform-type': {
|
|
1394
|
+
since: '5.1.0',
|
|
1395
|
+
hint: 'Agent selection is now driven by get_adcp_capabilities (supported_protocols + specialisms). Pass --storyboards <bundle-or-id> to target a specific bundle.',
|
|
1396
|
+
},
|
|
1397
|
+
};
|
|
1398
|
+
|
|
1399
|
+
// Scan `args` for removed flags and emit a stderr warning for each one found.
|
|
1400
|
+
// Writes to stderr unconditionally ā stderr does not corrupt `--json` stdout,
|
|
1401
|
+
// and the CI logs where these warnings need to land capture both streams.
|
|
1402
|
+
// Returns the names of the removed flags actually present so callers can
|
|
1403
|
+
// decide to hard-fail (see `enforceStrictFlags`). Non-breaking unless
|
|
1404
|
+
// `--strict-flags` is set.
|
|
1405
|
+
function warnRemovedFlags(args) {
|
|
1406
|
+
const found = [];
|
|
1407
|
+
for (const [flag, meta] of Object.entries(REMOVED_FLAGS)) {
|
|
1408
|
+
if (args.includes(flag) || args.some(a => a.startsWith(`${flag}=`))) {
|
|
1409
|
+
found.push(flag);
|
|
1410
|
+
console.error(`DEPRECATED: ${flag} was removed in ${meta.since} and is being ignored. ${meta.hint}`);
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
return found;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
// If `--strict-flags` is present and any removed flag was passed, exit 2
|
|
1417
|
+
// after emitting a pointed error that names every offender. Advisory-by-
|
|
1418
|
+
// default means CI pipelines opt-in; a team that wants stale scripts to
|
|
1419
|
+
// break the build sets the flag. Factored out of `handleStoryboardRun`
|
|
1420
|
+
// so `storyboard step` and future runner commands can share it.
|
|
1421
|
+
function enforceStrictFlags(args, removedFound) {
|
|
1422
|
+
if (removedFound.length > 0 && args.includes('--strict-flags')) {
|
|
1423
|
+
console.error(
|
|
1424
|
+
`ERROR: --strict-flags was set and ${removedFound.length} removed flag(s) were passed: ${removedFound.join(', ')}. ` +
|
|
1425
|
+
`Remove them or drop --strict-flags to continue with advisory warnings only.`
|
|
1426
|
+
);
|
|
1427
|
+
process.exit(2);
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
async function handleStoryboardRun(args) {
|
|
1432
|
+
const opts = parseAgentOptions(args);
|
|
1433
|
+
const { authToken, protocolFlag, jsonOutput, dryRun, positionalArgs, file: filePath, localAgent, format } = opts;
|
|
1434
|
+
|
|
1435
|
+
enforceStrictFlags(args, warnRemovedFlags(args));
|
|
1436
|
+
|
|
1437
|
+
// --local-agent <module>: spin the agent up in-process, seed fixtures,
|
|
1438
|
+
// run storyboards, tear down. Collapses the 300-line seller-side
|
|
1439
|
+
// bootstrap into one command. See `runAgainstLocalAgent` in
|
|
1440
|
+
// `@adcp/sdk/testing`.
|
|
1441
|
+
if (localAgent) {
|
|
1442
|
+
return handleLocalAgentStoryboardRun(localAgent, args, opts);
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
// Multi-instance mode: repeated --url flags round-robin steps across N
|
|
1446
|
+
// seller URLs. Must share a backing store to pass ā catches horizontal
|
|
1447
|
+
// scaling bugs where brand-scoped state lives in-process.
|
|
1448
|
+
const extraUrls = extractRepeatedUrlFlags(args);
|
|
1449
|
+
if (extraUrls.length > 0) {
|
|
1450
|
+
return handleMultiInstanceStoryboardRun(args, opts, extraUrls);
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
const agentArg = positionalArgs[0];
|
|
1454
|
+
const storyboardId = positionalArgs[1];
|
|
1455
|
+
|
|
1456
|
+
// --format junit: emit a JUnit XML report for any non-local run as well,
|
|
1457
|
+
// so CI pipelines fronting remote agents get the same format option.
|
|
1458
|
+
if (format && format === 'junit' && !storyboardId && !filePath) {
|
|
1459
|
+
console.error(
|
|
1460
|
+
'ERROR: --format junit requires a storyboard id, --file, or --local-agent. ' +
|
|
1461
|
+
'The capability-driven assessment emits a different report shape.'
|
|
1462
|
+
);
|
|
1463
|
+
process.exit(2);
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
if (!agentArg) {
|
|
1467
|
+
console.error(
|
|
1468
|
+
'Usage: adcp storyboard run <agent> [storyboard_id|--file path] [options]\n' +
|
|
1469
|
+
' Local agent: adcp storyboard run --local-agent <module> [storyboard_id|bundle_id]\n' +
|
|
1470
|
+
' Multi-instance: adcp storyboard run --url <url1> --url <url2> <storyboard_id|bundle_id>'
|
|
1471
|
+
);
|
|
1472
|
+
process.exit(2);
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
if (filePath && storyboardId) {
|
|
1476
|
+
console.error('ERROR: Cannot combine a storyboard ID with --file. Use one or the other.');
|
|
1477
|
+
process.exit(2);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
// Inline OAuth: if --oauth is set and the agent is a saved alias that
|
|
1481
|
+
// doesn't have valid tokens, run the browser flow now so the downstream
|
|
1482
|
+
// runner sees freshly-saved tokens via getAgent().
|
|
1483
|
+
await maybeRunInlineOAuth(agentArg, args, { jsonOutput });
|
|
1484
|
+
|
|
1485
|
+
// No storyboard ID and no --file ā capability-driven full assessment.
|
|
1486
|
+
if (!storyboardId && !filePath) {
|
|
1487
|
+
await runFullAssessment(agentArg, args, opts);
|
|
1488
|
+
return;
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
// Passing a bundle id expands to all storyboards in that bundle; route through comply().
|
|
1492
|
+
if (storyboardId) {
|
|
1493
|
+
await runFullAssessment(agentArg, args, { ...opts, explicitStoryboards: [storyboardId] });
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
const { loadStoryboardFile, runStoryboard } = await import('../dist/lib/testing/storyboard/index.js');
|
|
1498
|
+
let storyboard;
|
|
1499
|
+
try {
|
|
1500
|
+
storyboard = loadStoryboardFile(filePath);
|
|
1501
|
+
} catch (err) {
|
|
1502
|
+
console.error(`Failed to load storyboard from ${filePath}: ${err.message}`);
|
|
1503
|
+
process.exit(2);
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
const {
|
|
1507
|
+
agentUrl,
|
|
1508
|
+
protocol,
|
|
1509
|
+
authToken: resolvedAuth,
|
|
1510
|
+
oauthTokens: resolvedOauthTokens,
|
|
1511
|
+
oauthClient: resolvedOauthClient,
|
|
1512
|
+
oauthClientCredentials: resolvedOauthClientCredentials,
|
|
1513
|
+
} = await resolveAgent(agentArg, authToken, protocolFlag, jsonOutput);
|
|
1514
|
+
|
|
1515
|
+
// Parse webhook-receiver flags up front so malformed values fail the run
|
|
1516
|
+
// before the dry-run short-circuit, not only on a live execution. Auto-tunnel
|
|
1517
|
+
// is resolved after the dry-run gate ā spawning a tunnel for a preview-only
|
|
1518
|
+
// run would be wasteful ā but its flag-combination validation runs here so
|
|
1519
|
+
// conflicts surface in dry-run too.
|
|
1520
|
+
const webhookAutoTunnel = args.includes('--webhook-receiver-auto-tunnel');
|
|
1521
|
+
const webhookReceiverBase = extractWebhookReceiverOptions(args);
|
|
1522
|
+
validateAutoTunnelArgs(args, webhookReceiverBase);
|
|
1523
|
+
|
|
1524
|
+
// Load invariants before the dry-run gate so `--dry-run --invariants` fails
|
|
1525
|
+
// fast on bad module specifiers. Modules are pure registration side-effects
|
|
1526
|
+
// so importing them in preview mode is safe.
|
|
1527
|
+
await loadInvariantModules(args);
|
|
1528
|
+
|
|
1529
|
+
const stepCount = storyboard.phases.reduce((sum, p) => sum + p.steps.length, 0);
|
|
1530
|
+
|
|
1531
|
+
if (!jsonOutput) {
|
|
1532
|
+
console.error(`Running storyboard: ${storyboard.title}`);
|
|
1533
|
+
console.error(`Agent: ${agentUrl} (${protocol})`);
|
|
1534
|
+
console.error(`Steps: ${stepCount}`);
|
|
1535
|
+
if (opts.noSandbox) {
|
|
1536
|
+
console.error(`Run mode: production (account.sandbox=false on every request)`);
|
|
1537
|
+
}
|
|
1538
|
+
console.error('');
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
// --dry-run: preview mode ā show the plan without executing
|
|
1542
|
+
if (dryRun) {
|
|
1543
|
+
if (jsonOutput) {
|
|
1544
|
+
await writeJsonOutput({
|
|
1545
|
+
storyboard_id: storyboard.id,
|
|
1546
|
+
storyboard_title: storyboard.title,
|
|
1547
|
+
agent_url: agentUrl,
|
|
1548
|
+
protocol,
|
|
1549
|
+
preview: true,
|
|
1550
|
+
phases: storyboard.phases.map(p => ({
|
|
1551
|
+
phase: p.title,
|
|
1552
|
+
steps: p.steps.map(s => ({ id: s.id, title: s.title, task: s.task })),
|
|
1553
|
+
})),
|
|
1554
|
+
});
|
|
1555
|
+
} else {
|
|
1556
|
+
console.log(`\n${storyboard.title} (${storyboard.id})`);
|
|
1557
|
+
console.log('ā'.repeat(50));
|
|
1558
|
+
for (const phase of storyboard.phases) {
|
|
1559
|
+
console.log(`\nāā Phase: ${phase.title} āā`);
|
|
1560
|
+
for (const step of phase.steps) {
|
|
1561
|
+
console.log(` ${step.id}: ${step.title} ā ${step.task}`);
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
console.log(`\n${stepCount} step(s) would be executed. Use without --dry-run to run.`);
|
|
1565
|
+
}
|
|
1566
|
+
return;
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
const webhookReceiverOpts = webhookAutoTunnel
|
|
1570
|
+
? await resolveWebhookReceiverOptions(args, { jsonOutput })
|
|
1571
|
+
: webhookReceiverBase;
|
|
1572
|
+
|
|
1573
|
+
const options = {
|
|
1574
|
+
protocol,
|
|
1575
|
+
...buildResolvedAuthOption({
|
|
1576
|
+
resolvedAuth,
|
|
1577
|
+
resolvedOauthTokens,
|
|
1578
|
+
resolvedOauthClient,
|
|
1579
|
+
resolvedOauthClientCredentials,
|
|
1580
|
+
}),
|
|
1581
|
+
...(webhookReceiverOpts ?? {}),
|
|
1582
|
+
...(opts.noSandbox && { sandbox: false }),
|
|
1583
|
+
};
|
|
1584
|
+
|
|
1585
|
+
const restoreLogs = jsonOutput ? captureStdoutLogs() : null;
|
|
1586
|
+
let result;
|
|
1587
|
+
try {
|
|
1588
|
+
result = await runStoryboard(agentUrl, storyboard, options);
|
|
1589
|
+
} finally {
|
|
1590
|
+
if (restoreLogs) restoreLogs();
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
if (format === 'junit') {
|
|
1594
|
+
process.stdout.write(formatStoryboardResultsAsJUnit([result]));
|
|
1595
|
+
process.exit(result.overall_passed ? 0 : 3);
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
if (jsonOutput) {
|
|
1599
|
+
await writeJsonOutput(result);
|
|
1600
|
+
} else {
|
|
1601
|
+
// Human-readable output
|
|
1602
|
+
console.log(`\n${storyboard.title} (${storyboard.id})`);
|
|
1603
|
+
console.log('ā'.repeat(50));
|
|
1604
|
+
for (const phase of result.phases) {
|
|
1605
|
+
console.log(`\nāā Phase: ${phase.phase_title} āāāāāāāāāāāāāāāāāāāāāāāāāāāāāā`);
|
|
1606
|
+
const SKIP_ICONS = {
|
|
1607
|
+
missing_tool: 'š§',
|
|
1608
|
+
missing_test_controller: 'š§',
|
|
1609
|
+
not_applicable: 'āļø',
|
|
1610
|
+
no_phases: 'āļø',
|
|
1611
|
+
prerequisite_failed: 'āļø',
|
|
1612
|
+
unsatisfied_contract: 'āļø',
|
|
1613
|
+
};
|
|
1614
|
+
const SKIP_LABELS = {
|
|
1615
|
+
missing_tool: ' [missing tool]',
|
|
1616
|
+
missing_test_controller: ' [needs test controller]',
|
|
1617
|
+
not_applicable: ' [not applicable]',
|
|
1618
|
+
no_phases: ' [no phases]',
|
|
1619
|
+
prerequisite_failed: ' [prerequisite failed]',
|
|
1620
|
+
unsatisfied_contract: ' [contract out of scope]',
|
|
1621
|
+
};
|
|
1622
|
+
for (const step of phase.steps) {
|
|
1623
|
+
const icon = step.skipped ? (SKIP_ICONS[step.skip_reason] ?? 'āļø') : step.passed ? 'ā
' : 'ā';
|
|
1624
|
+
const skipLabel = SKIP_LABELS[step.skip_reason] ?? '';
|
|
1625
|
+
console.log(`\n${icon} ${step.title}${skipLabel} (${step.duration_ms}ms)`);
|
|
1626
|
+
console.log(` Task: ${step.task}`);
|
|
1627
|
+
if (step.error) {
|
|
1628
|
+
console.log(` Error: ${step.error}`);
|
|
1629
|
+
}
|
|
1630
|
+
for (const v of step.validations) {
|
|
1631
|
+
const vIcon = v.passed ? 'ā
' : 'ā';
|
|
1632
|
+
console.log(` ${vIcon} ${v.description}`);
|
|
1633
|
+
if (v.error) console.log(` ${v.error}`);
|
|
1634
|
+
// v.warning carries actionable hints (shape-drift recipes, strict
|
|
1635
|
+
// deltas, variant-fallback notices). Render it whether the step
|
|
1636
|
+
// passed or failed ā a passing step can still carry a warning.
|
|
1637
|
+
if (v.warning) console.log(` ā ļø ${v.warning}`);
|
|
1638
|
+
}
|
|
1639
|
+
// Hints land AFTER validations on a failing step so the
|
|
1640
|
+
// "what to do next" line is visually adjacent to the next step's
|
|
1641
|
+
// start ā not pushed up the screen by passing validations the
|
|
1642
|
+
// operator no longer needs to read.
|
|
1643
|
+
printStepHints(step.hints);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
console.log(`\n${'ā'.repeat(50)}`);
|
|
1648
|
+
const overallIcon = result.overall_passed ? 'ā
' : 'ā';
|
|
1649
|
+
// Hint count surfaces diagnostic info that lives on `step.hints[]` so
|
|
1650
|
+
// operators see "the run emitted N hints" without scrolling per-step
|
|
1651
|
+
// output. Stays silent when N=0 ā no useful signal in announcing zero.
|
|
1652
|
+
const hintCount = countHintsInResult(result);
|
|
1653
|
+
const hintTail = hintCount > 0 ? ` Ā· ${hintCount} hint${hintCount === 1 ? '' : 's'}` : '';
|
|
1654
|
+
console.log(
|
|
1655
|
+
`${overallIcon} ${result.passed_count} passed, ${result.failed_count} failed, ${result.skipped_count} skipped (${result.total_duration_ms}ms)${hintTail}`
|
|
1656
|
+
);
|
|
1657
|
+
printStrictSummary(result.strict_validation_summary);
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
process.exit(result.overall_passed ? 0 : 3);
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
/**
|
|
1664
|
+
* Extract every `--url <value>` occurrence from the CLI args and validate
|
|
1665
|
+
* each against the same policy the single-instance agent argument enforces:
|
|
1666
|
+
*
|
|
1667
|
+
* - value must be a parseable URL
|
|
1668
|
+
* - scheme must be http or https (http only allowed with --allow-http)
|
|
1669
|
+
* - no userinfo (`https://user:pass@host/` is rejected ā tokens go via --auth)
|
|
1670
|
+
*
|
|
1671
|
+
* Without these gates a hostile or typo'd `--url file:///etc/passwd` or
|
|
1672
|
+
* `--url https://attacker@victim/mcp` would flow straight into the MCP
|
|
1673
|
+
* transport and land in attribution output.
|
|
1674
|
+
*/
|
|
1675
|
+
/**
|
|
1676
|
+
* Parse `--webhook-receiver [mode]`, `--webhook-receiver-port <port>`, and
|
|
1677
|
+
* `--webhook-receiver-public-url <url>`. Returns a `{ webhook_receiver, contracts }`
|
|
1678
|
+
* pair suitable for spreading into `runStoryboard` / `comply` options, or
|
|
1679
|
+
* `null` if no webhook-receiver flag is set.
|
|
1680
|
+
*
|
|
1681
|
+
* The receiver's presence satisfies the `webhook_receiver_runner` test-kit
|
|
1682
|
+
* contract; storyboards with `requires_contract: webhook_receiver_runner`
|
|
1683
|
+
* (e.g. the `webhook-emission` and `idempotency` universals) otherwise skip.
|
|
1684
|
+
*
|
|
1685
|
+
* Exits with code 2 on invalid flag shape.
|
|
1686
|
+
*/
|
|
1687
|
+
function extractWebhookReceiverOptions(args) {
|
|
1688
|
+
const idx = args.indexOf('--webhook-receiver');
|
|
1689
|
+
const publicUrlIdx = args.indexOf('--webhook-receiver-public-url');
|
|
1690
|
+
const portIdx = args.indexOf('--webhook-receiver-port');
|
|
1691
|
+
|
|
1692
|
+
if (idx === -1 && publicUrlIdx === -1 && portIdx === -1) return null;
|
|
1693
|
+
|
|
1694
|
+
let mode = 'loopback_mock';
|
|
1695
|
+
if (idx !== -1) {
|
|
1696
|
+
const next = args[idx + 1];
|
|
1697
|
+
if (next !== undefined && !next.startsWith('--')) {
|
|
1698
|
+
if (next === 'loopback') mode = 'loopback_mock';
|
|
1699
|
+
else if (next === 'proxy') mode = 'proxy_url';
|
|
1700
|
+
else {
|
|
1701
|
+
console.error(`ERROR: --webhook-receiver value must be "loopback" or "proxy", got "${next}"`);
|
|
1702
|
+
console.error(' Omit the value to use the default (loopback).');
|
|
1703
|
+
process.exit(2);
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
let publicUrl;
|
|
1709
|
+
if (publicUrlIdx !== -1) {
|
|
1710
|
+
const val = args[publicUrlIdx + 1];
|
|
1711
|
+
if (val === undefined || val.startsWith('--')) {
|
|
1712
|
+
console.error('ERROR: --webhook-receiver-public-url requires a URL value');
|
|
1713
|
+
process.exit(2);
|
|
1714
|
+
}
|
|
1715
|
+
publicUrl = val;
|
|
1716
|
+
// --webhook-receiver-public-url without --webhook-receiver implies proxy mode.
|
|
1717
|
+
// With explicit `--webhook-receiver loopback`, the combination is a user
|
|
1718
|
+
// error ā loopback mode ignores public_url.
|
|
1719
|
+
if (idx === -1) mode = 'proxy_url';
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
if (mode === 'proxy_url' && !publicUrl) {
|
|
1723
|
+
console.error('ERROR: --webhook-receiver proxy requires --webhook-receiver-public-url <url>');
|
|
1724
|
+
process.exit(2);
|
|
1725
|
+
}
|
|
1726
|
+
if (mode === 'loopback_mock' && publicUrl) {
|
|
1727
|
+
console.error('ERROR: --webhook-receiver-public-url is only valid with --webhook-receiver proxy');
|
|
1728
|
+
process.exit(2);
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
let port;
|
|
1732
|
+
if (portIdx !== -1) {
|
|
1733
|
+
const raw = args[portIdx + 1];
|
|
1734
|
+
if (raw === undefined || raw.startsWith('--')) {
|
|
1735
|
+
console.error('ERROR: --webhook-receiver-port requires a port number');
|
|
1736
|
+
process.exit(2);
|
|
1737
|
+
}
|
|
1738
|
+
const parsed = Number(raw);
|
|
1739
|
+
if (!Number.isInteger(parsed) || String(parsed) !== raw) {
|
|
1740
|
+
console.error(`ERROR: --webhook-receiver-port must be an integer, got "${raw}"`);
|
|
1741
|
+
process.exit(2);
|
|
1742
|
+
}
|
|
1743
|
+
if (parsed < 0 || parsed > 65535) {
|
|
1744
|
+
console.error(`ERROR: --webhook-receiver-port must be between 0 and 65535, got ${parsed}`);
|
|
1745
|
+
process.exit(2);
|
|
1746
|
+
}
|
|
1747
|
+
port = parsed;
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
return {
|
|
1751
|
+
webhook_receiver: {
|
|
1752
|
+
mode,
|
|
1753
|
+
...(port !== undefined && { port }),
|
|
1754
|
+
...(publicUrl !== undefined && { public_url: publicUrl }),
|
|
1755
|
+
},
|
|
1756
|
+
contracts: ['webhook_receiver_runner'],
|
|
1757
|
+
};
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
/**
|
|
1761
|
+
* Dynamic-import modules listed in --invariants so their `registerAssertion(...)`
|
|
1762
|
+
* calls populate the storyboard assertion registry before the runner resolves
|
|
1763
|
+
* `storyboard.invariants`. Accepts a comma-separated list of specifiers:
|
|
1764
|
+
* relative paths (`./my-invariants.js`), absolute paths, or bare package
|
|
1765
|
+
* specifiers (`@org/invariants`). Relative paths are resolved against the CLI's
|
|
1766
|
+
* working directory; package specifiers are passed to dynamic import as-is.
|
|
1767
|
+
*
|
|
1768
|
+
* Exits with code 2 if --invariants is present without a value or if any
|
|
1769
|
+
* module fails to load. Does nothing when --invariants is absent.
|
|
1770
|
+
*/
|
|
1771
|
+
async function loadInvariantModules(args) {
|
|
1772
|
+
const idx = args.indexOf('--invariants');
|
|
1773
|
+
if (idx === -1) return;
|
|
1774
|
+
const raw = idx + 1 < args.length && !args[idx + 1].startsWith('--') ? args[idx + 1] : null;
|
|
1775
|
+
if (!raw) {
|
|
1776
|
+
console.error('ERROR: --invariants requires a value (comma-separated module specifiers).');
|
|
1777
|
+
process.exit(2);
|
|
1778
|
+
}
|
|
1779
|
+
const specs = raw
|
|
1780
|
+
.split(',')
|
|
1781
|
+
.map(s => s.trim())
|
|
1782
|
+
.filter(Boolean);
|
|
1783
|
+
if (specs.length === 0) {
|
|
1784
|
+
console.error('ERROR: --invariants requires at least one non-empty module specifier.');
|
|
1785
|
+
process.exit(2);
|
|
1786
|
+
}
|
|
1787
|
+
for (const spec of specs) {
|
|
1788
|
+
// Treat absolute paths and relative paths as filesystem paths; everything
|
|
1789
|
+
// else is a package specifier. `path.isAbsolute` gives Windows parity over
|
|
1790
|
+
// a naive `/`-prefix check.
|
|
1791
|
+
const specifier =
|
|
1792
|
+
spec.startsWith('.') || path.isAbsolute(spec) ? pathToFileURL(path.resolve(process.cwd(), spec)).href : spec;
|
|
1793
|
+
try {
|
|
1794
|
+
await import(specifier);
|
|
1795
|
+
} catch (err) {
|
|
1796
|
+
console.error(`ERROR: failed to load invariants module "${spec}": ${err.message}`);
|
|
1797
|
+
process.exit(2);
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
/**
|
|
1803
|
+
* `--webhook-receiver-auto-tunnel` autodetects a tunneling binary on PATH
|
|
1804
|
+
* (ngrok or cloudflared), spawns it pointed at the receiver port, extracts
|
|
1805
|
+
* the public URL, and plumbs it into `webhook_receiver` proxy mode ā so a
|
|
1806
|
+
* developer grading a remote agent from a laptop doesn't have to stand up
|
|
1807
|
+
* a tunnel by hand.
|
|
1808
|
+
*
|
|
1809
|
+
* Design notes:
|
|
1810
|
+
* - HTTP on the wire is unchanged. This satisfies the webhook_receiver_runner
|
|
1811
|
+
* parity invariant (loopback_mock ā” proxy_url ā same emitter path).
|
|
1812
|
+
* - No vendor pin: any binary on PATH works, and `$ADCP_WEBHOOK_TUNNEL`
|
|
1813
|
+
* overrides detection with a custom command template (`{port}` is
|
|
1814
|
+
* substituted). This keeps the CLI spec-compliant with the test-kit's
|
|
1815
|
+
* "MUST NOT require a specific tunnel vendor" rule.
|
|
1816
|
+
*
|
|
1817
|
+
* The detection logic is PATH-based (not exec-based) so we can fail fast
|
|
1818
|
+
* with a clear message when no tunnel is installed, instead of surfacing
|
|
1819
|
+
* ENOENT after a runStoryboard attempt is already in flight.
|
|
1820
|
+
*/
|
|
1821
|
+
function isOnPath(cmd) {
|
|
1822
|
+
const pathEnv = process.env.PATH || '';
|
|
1823
|
+
const pathExt = process.platform === 'win32' ? (process.env.PATHEXT || '.EXE').split(';') : [''];
|
|
1824
|
+
for (const dir of pathEnv.split(path.delimiter)) {
|
|
1825
|
+
if (!dir) continue;
|
|
1826
|
+
for (const ext of pathExt) {
|
|
1827
|
+
const full = path.join(dir, cmd + ext);
|
|
1828
|
+
try {
|
|
1829
|
+
if (statSync(full).isFile()) return true;
|
|
1830
|
+
} catch {
|
|
1831
|
+
/* not this dir */
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
return false;
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
function detectTunnelCommand() {
|
|
1839
|
+
const override = process.env.ADCP_WEBHOOK_TUNNEL;
|
|
1840
|
+
if (override) return { kind: 'custom', template: override };
|
|
1841
|
+
if (isOnPath('ngrok')) return { kind: 'ngrok' };
|
|
1842
|
+
if (isOnPath('cloudflared')) return { kind: 'cloudflared' };
|
|
1843
|
+
return null;
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
function parseTunnelTimeoutMs(raw) {
|
|
1847
|
+
const DEFAULT = 15000;
|
|
1848
|
+
if (raw === undefined || raw === '') return DEFAULT;
|
|
1849
|
+
const parsed = Number(raw);
|
|
1850
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
1851
|
+
console.error(
|
|
1852
|
+
`WARNING: ADCP_WEBHOOK_TUNNEL_TIMEOUT_MS=${JSON.stringify(raw)} is not a positive number; using default ${DEFAULT}ms.`
|
|
1853
|
+
);
|
|
1854
|
+
return DEFAULT;
|
|
1855
|
+
}
|
|
1856
|
+
return parsed;
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
function getFreePort() {
|
|
1860
|
+
return new Promise((resolve, reject) => {
|
|
1861
|
+
const srv = net.createServer();
|
|
1862
|
+
srv.unref();
|
|
1863
|
+
srv.on('error', reject);
|
|
1864
|
+
srv.listen(0, '127.0.0.1', () => {
|
|
1865
|
+
const { port } = srv.address();
|
|
1866
|
+
srv.close(() => resolve(port));
|
|
1867
|
+
});
|
|
1868
|
+
});
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
/**
|
|
1872
|
+
* Spawn a tunnel process pointed at `port`, extract its public URL from
|
|
1873
|
+
* stdout/stderr within `timeoutMs`, and return `{ publicUrl, cleanup }`.
|
|
1874
|
+
* Cleanup is idempotent and registered on process exit/SIGINT/SIGTERM so
|
|
1875
|
+
* we don't leave zombie tunnels behind on a Ctrl-C mid-run.
|
|
1876
|
+
*
|
|
1877
|
+
* Exits with code 2 on failure (no tunnel found, startup timeout, child
|
|
1878
|
+
* exit before URL emission) ā matching the rest of the CLI's validation
|
|
1879
|
+
* error contract.
|
|
1880
|
+
*/
|
|
1881
|
+
async function spawnAutoTunnel({ port, timeoutMs, jsonOutput }) {
|
|
1882
|
+
const detected = detectTunnelCommand();
|
|
1883
|
+
if (!detected) {
|
|
1884
|
+
console.error('ERROR: --webhook-receiver-auto-tunnel: no supported tunnel binary found on PATH.');
|
|
1885
|
+
console.error(' Install ngrok (https://ngrok.com/download) or cloudflared,');
|
|
1886
|
+
console.error(' or set $ADCP_WEBHOOK_TUNNEL="<cmd> {port}" to use a custom tunnel.');
|
|
1887
|
+
console.error(' Alternatively, run the tunnel yourself and pass');
|
|
1888
|
+
console.error(' --webhook-receiver proxy --webhook-receiver-public-url <url>.');
|
|
1889
|
+
process.exit(2);
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
let cmd;
|
|
1893
|
+
let cmdArgs;
|
|
1894
|
+
let urlRegex;
|
|
1895
|
+
if (detected.kind === 'ngrok') {
|
|
1896
|
+
cmd = 'ngrok';
|
|
1897
|
+
// logfmt output is stable across ngrok v2/v3 and keeps us off the TUI.
|
|
1898
|
+
cmdArgs = ['http', String(port), '--log=stdout', '--log-format=logfmt'];
|
|
1899
|
+
// Anchor on ngrok's `msg="started tunnel"` log line. Vendor-domain
|
|
1900
|
+
// allowlisting is fragile ā ngrok is migrating free-tier subdomains
|
|
1901
|
+
// from `.ngrok-free.app` to `.ngrok-free.dev`, paid tiers use
|
|
1902
|
+
// `.ngrok.app`, custom domains use anything. Scoping to the started-
|
|
1903
|
+
// tunnel line is the durable invariant: ngrok emits it exactly once
|
|
1904
|
+
// per tunnel creation with the forwarding URL in the `url=` field.
|
|
1905
|
+
urlRegex = /msg="started tunnel"[^\n]*url=(https:\/\/[^\s"]+)/;
|
|
1906
|
+
} else if (detected.kind === 'cloudflared') {
|
|
1907
|
+
cmd = 'cloudflared';
|
|
1908
|
+
cmdArgs = ['tunnel', '--url', `http://localhost:${port}`, '--no-autoupdate'];
|
|
1909
|
+
urlRegex = /(https:\/\/[a-z0-9-]+\.trycloudflare\.com)/;
|
|
1910
|
+
} else {
|
|
1911
|
+
const parts = detected.template
|
|
1912
|
+
.replace(/\{port\}/g, String(port))
|
|
1913
|
+
.split(/\s+/)
|
|
1914
|
+
.filter(Boolean);
|
|
1915
|
+
if (parts.length === 0) {
|
|
1916
|
+
console.error('ERROR: $ADCP_WEBHOOK_TUNNEL is empty.');
|
|
1917
|
+
process.exit(2);
|
|
1918
|
+
}
|
|
1919
|
+
cmd = parts[0];
|
|
1920
|
+
cmdArgs = parts.slice(1);
|
|
1921
|
+
// Custom templates must print `ADCP_TUNNEL_URL=<https://...>` on a line
|
|
1922
|
+
// somewhere in stdout/stderr. An unscoped "first https:// URL" match would
|
|
1923
|
+
// wire the tunnel destination to any docs/diagnostics URL the binary
|
|
1924
|
+
// happens to log on startup; the explicit marker is the contract.
|
|
1925
|
+
urlRegex = /ADCP_TUNNEL_URL=(https:\/\/[^\s"]+)/;
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
let child;
|
|
1929
|
+
try {
|
|
1930
|
+
child = spawn(cmd, cmdArgs, { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
1931
|
+
} catch (err) {
|
|
1932
|
+
console.error(`ERROR: failed to spawn ${cmd}: ${err.message}`);
|
|
1933
|
+
process.exit(2);
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
let settled = false;
|
|
1937
|
+
let publicUrl;
|
|
1938
|
+
// Rolling buffer across chunks: ngrok's `msg="started tunnel" ⦠url=ā¦` line
|
|
1939
|
+
// can straddle two `data` events (stdio pipes don't guarantee line-aligned
|
|
1940
|
+
// chunks), and matching each chunk in isolation would miss the anchor/URL
|
|
1941
|
+
// when they land on opposite sides of the boundary. Scan the concatenation
|
|
1942
|
+
// and cap retention so a runaway child can't balloon memory.
|
|
1943
|
+
let scanBuffer = '';
|
|
1944
|
+
const MAX_SCAN_BUFFER = 16_384;
|
|
1945
|
+
|
|
1946
|
+
const scan = chunk => {
|
|
1947
|
+
if (settled) return;
|
|
1948
|
+
scanBuffer += chunk.toString('utf8');
|
|
1949
|
+
if (scanBuffer.length > MAX_SCAN_BUFFER) {
|
|
1950
|
+
scanBuffer = scanBuffer.slice(-MAX_SCAN_BUFFER);
|
|
1951
|
+
}
|
|
1952
|
+
const m = scanBuffer.match(urlRegex);
|
|
1953
|
+
if (m) {
|
|
1954
|
+
publicUrl = m[1];
|
|
1955
|
+
settled = true;
|
|
1956
|
+
}
|
|
1957
|
+
};
|
|
1958
|
+
|
|
1959
|
+
const urlReady = new Promise((resolve, reject) => {
|
|
1960
|
+
const onResolved = () => resolve(publicUrl);
|
|
1961
|
+
const onRejected = err => reject(err);
|
|
1962
|
+
|
|
1963
|
+
child.stdout.on('data', c => {
|
|
1964
|
+
scan(c);
|
|
1965
|
+
if (publicUrl) onResolved();
|
|
1966
|
+
});
|
|
1967
|
+
child.stderr.on('data', c => {
|
|
1968
|
+
scan(c);
|
|
1969
|
+
if (publicUrl) onResolved();
|
|
1970
|
+
});
|
|
1971
|
+
child.once('error', err => {
|
|
1972
|
+
if (settled) return;
|
|
1973
|
+
settled = true;
|
|
1974
|
+
if (err.code === 'ENOENT') {
|
|
1975
|
+
onRejected(new Error(`${cmd} not on PATH at spawn time`));
|
|
1976
|
+
} else {
|
|
1977
|
+
onRejected(err);
|
|
1978
|
+
}
|
|
1979
|
+
});
|
|
1980
|
+
child.once('exit', (code, signal) => {
|
|
1981
|
+
if (settled) return;
|
|
1982
|
+
settled = true;
|
|
1983
|
+
onRejected(new Error(`${cmd} exited (code=${code}, signal=${signal}) before emitting a public URL`));
|
|
1984
|
+
});
|
|
1985
|
+
});
|
|
1986
|
+
|
|
1987
|
+
let timer;
|
|
1988
|
+
const timeout = new Promise((_, reject) => {
|
|
1989
|
+
timer = setTimeout(
|
|
1990
|
+
() => reject(new Error(`${cmd} did not emit a public URL within ${Math.round(timeoutMs / 1000)}s`)),
|
|
1991
|
+
timeoutMs
|
|
1992
|
+
);
|
|
1993
|
+
});
|
|
1994
|
+
|
|
1995
|
+
try {
|
|
1996
|
+
await Promise.race([urlReady, timeout]);
|
|
1997
|
+
} catch (err) {
|
|
1998
|
+
try {
|
|
1999
|
+
child.kill('SIGTERM');
|
|
2000
|
+
} catch {
|
|
2001
|
+
/* ignore */
|
|
2002
|
+
}
|
|
2003
|
+
if (timer) clearTimeout(timer);
|
|
2004
|
+
console.error(`ERROR: --webhook-receiver-auto-tunnel: ${err.message}`);
|
|
2005
|
+
process.exit(2);
|
|
2006
|
+
}
|
|
2007
|
+
clearTimeout(timer);
|
|
2008
|
+
|
|
2009
|
+
const cleanup = registerTunnelChildForCleanup(child);
|
|
2010
|
+
|
|
2011
|
+
if (!jsonOutput) {
|
|
2012
|
+
console.error(`Auto-tunnel (${cmd}): ${publicUrl} ā http://localhost:${port}`);
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
return { publicUrl, cleanup };
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
/**
|
|
2019
|
+
* Shared cleanup registry for spawned tunnel children. One `exit`/`SIGINT`/
|
|
2020
|
+
* `SIGTERM` listener is installed the first time a child is registered and
|
|
2021
|
+
* stays installed for the process lifetime ā `process.once` was a bug
|
|
2022
|
+
* waiting to happen (a second Ctrl-C would bypass teardown and leak
|
|
2023
|
+
* tunnels).
|
|
2024
|
+
*
|
|
2025
|
+
* Signal path escalates SIGTERM ā SIGKILL with a 250 ms grace so a tunnel
|
|
2026
|
+
* that ignores TERM still gets reaped. The `'exit'` path is best-effort:
|
|
2027
|
+
* Node cannot schedule timers after the `'exit'` event, so we only send
|
|
2028
|
+
* TERM there and rely on the OS to reap strays when the parent dies.
|
|
2029
|
+
*/
|
|
2030
|
+
const activeTunnelChildren = new Set();
|
|
2031
|
+
let tunnelSignalHandlersInstalled = false;
|
|
2032
|
+
let tunnelEscalating = false;
|
|
2033
|
+
|
|
2034
|
+
function termAllTunnels() {
|
|
2035
|
+
for (const child of activeTunnelChildren) {
|
|
2036
|
+
try {
|
|
2037
|
+
child.kill('SIGTERM');
|
|
2038
|
+
} catch {
|
|
2039
|
+
/* already gone */
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
function killAllTunnels() {
|
|
2045
|
+
for (const child of activeTunnelChildren) {
|
|
2046
|
+
try {
|
|
2047
|
+
child.kill('SIGKILL');
|
|
2048
|
+
} catch {
|
|
2049
|
+
/* already gone */
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
function installTunnelSignalHandlersOnce() {
|
|
2055
|
+
if (tunnelSignalHandlersInstalled) return;
|
|
2056
|
+
tunnelSignalHandlersInstalled = true;
|
|
2057
|
+
// `process.on` (not `once`) so a second Ctrl-C doesn't bypass cleanup.
|
|
2058
|
+
process.on('exit', termAllTunnels);
|
|
2059
|
+
const escalateAndExit = exitCode => () => {
|
|
2060
|
+
if (tunnelEscalating) {
|
|
2061
|
+
// Second signal during the grace window: force-kill now and bail.
|
|
2062
|
+
killAllTunnels();
|
|
2063
|
+
process.exit(exitCode);
|
|
2064
|
+
return;
|
|
2065
|
+
}
|
|
2066
|
+
tunnelEscalating = true;
|
|
2067
|
+
termAllTunnels();
|
|
2068
|
+
// Two properties worth keeping separate:
|
|
2069
|
+
// 1) We don't call process.exit synchronously ā the timer must run.
|
|
2070
|
+
// 2) We don't `.unref()` the timer ā Node must keep the event loop
|
|
2071
|
+
// alive for the full 250 ms so stubborn tunnels actually see KILL.
|
|
2072
|
+
setTimeout(() => {
|
|
2073
|
+
killAllTunnels();
|
|
2074
|
+
process.exit(exitCode);
|
|
2075
|
+
}, 250);
|
|
2076
|
+
};
|
|
2077
|
+
process.on('SIGINT', escalateAndExit(130));
|
|
2078
|
+
process.on('SIGTERM', escalateAndExit(143));
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
function registerTunnelChildForCleanup(child) {
|
|
2082
|
+
installTunnelSignalHandlersOnce();
|
|
2083
|
+
activeTunnelChildren.add(child);
|
|
2084
|
+
child.once('exit', () => activeTunnelChildren.delete(child));
|
|
2085
|
+
return () => {
|
|
2086
|
+
if (!activeTunnelChildren.delete(child)) return;
|
|
2087
|
+
try {
|
|
2088
|
+
child.kill('SIGTERM');
|
|
2089
|
+
} catch {
|
|
2090
|
+
/* already gone */
|
|
2091
|
+
}
|
|
2092
|
+
};
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
/**
|
|
2096
|
+
* Resolve `webhook_receiver` options with auto-tunnel support layered in.
|
|
2097
|
+
*
|
|
2098
|
+
* When `--webhook-receiver-auto-tunnel` is present, we allocate a port if
|
|
2099
|
+
* the operator didn't force one, spawn the tunnel, and synthesize a
|
|
2100
|
+
* proxy-mode receiver config around the captured public URL. The return
|
|
2101
|
+
* shape matches `extractWebhookReceiverOptions` so callers can spread it
|
|
2102
|
+
* into runner options unchanged.
|
|
2103
|
+
*/
|
|
2104
|
+
function validateAutoTunnelArgs(args, base) {
|
|
2105
|
+
if (!args.includes('--webhook-receiver-auto-tunnel')) return;
|
|
2106
|
+
if (base?.webhook_receiver.public_url) {
|
|
2107
|
+
console.error('ERROR: --webhook-receiver-auto-tunnel conflicts with --webhook-receiver-public-url.');
|
|
2108
|
+
console.error(' Pick one ā auto-tunnel mints a URL for you, public-url supplies your own.');
|
|
2109
|
+
process.exit(2);
|
|
2110
|
+
}
|
|
2111
|
+
// Auto-tunnel implies proxy mode and mints the URL itself. A coexisting
|
|
2112
|
+
// `--webhook-receiver [mode]` flag is always wrong: `loopback` contradicts
|
|
2113
|
+
// the minted URL, `proxy` without public-url is caught earlier in
|
|
2114
|
+
// extractWebhookReceiverOptions, and a bare `--webhook-receiver` (which
|
|
2115
|
+
// resolves to `loopback_mock`) would be silently overwritten. Reject all
|
|
2116
|
+
// three up front with a single clear message.
|
|
2117
|
+
if (args.includes('--webhook-receiver')) {
|
|
2118
|
+
console.error('ERROR: --webhook-receiver-auto-tunnel already implies proxy mode; drop `--webhook-receiver`.');
|
|
2119
|
+
process.exit(2);
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
async function resolveWebhookReceiverOptions(args, { jsonOutput } = {}) {
|
|
2124
|
+
const base = extractWebhookReceiverOptions(args);
|
|
2125
|
+
validateAutoTunnelArgs(args, base);
|
|
2126
|
+
if (!args.includes('--webhook-receiver-auto-tunnel')) return base;
|
|
2127
|
+
|
|
2128
|
+
const port = base?.webhook_receiver.port ?? (await getFreePort());
|
|
2129
|
+
const timeoutMs = parseTunnelTimeoutMs(process.env.ADCP_WEBHOOK_TUNNEL_TIMEOUT_MS);
|
|
2130
|
+
const { publicUrl } = await spawnAutoTunnel({ port, timeoutMs, jsonOutput });
|
|
2131
|
+
|
|
2132
|
+
return {
|
|
2133
|
+
webhook_receiver: { mode: 'proxy_url', port, public_url: publicUrl },
|
|
2134
|
+
contracts: ['webhook_receiver_runner'],
|
|
2135
|
+
};
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
/**
|
|
2139
|
+
* Parse `--multi-instance-strategy <round-robin|multi-pass>`. Defaults to
|
|
2140
|
+
* `round-robin` to keep CI time predictable; operators opt into `multi-pass`
|
|
2141
|
+
* when they want cross-replica coverage for writeāread pairs separated by an
|
|
2142
|
+
* even number of stateful steps (see adcontextprotocol/adcp-client#607).
|
|
2143
|
+
*/
|
|
2144
|
+
function extractMultiInstanceStrategy(args) {
|
|
2145
|
+
const idx = args.indexOf('--multi-instance-strategy');
|
|
2146
|
+
if (idx === -1) return 'round-robin';
|
|
2147
|
+
const raw = args[idx + 1];
|
|
2148
|
+
if (raw === undefined || raw.startsWith('--')) {
|
|
2149
|
+
console.error('ERROR: --multi-instance-strategy requires a value (round-robin|multi-pass)');
|
|
2150
|
+
process.exit(2);
|
|
2151
|
+
}
|
|
2152
|
+
if (raw !== 'round-robin' && raw !== 'multi-pass') {
|
|
2153
|
+
console.error(`ERROR: --multi-instance-strategy must be "round-robin" or "multi-pass", got "${raw}"`);
|
|
2154
|
+
process.exit(2);
|
|
2155
|
+
}
|
|
2156
|
+
return raw;
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2159
|
+
function extractRepeatedUrlFlags(args) {
|
|
2160
|
+
const allowHttp = args.includes('--allow-http');
|
|
2161
|
+
const values = [];
|
|
2162
|
+
for (let i = 0; i < args.length; i++) {
|
|
2163
|
+
if (args[i] !== '--url') continue;
|
|
2164
|
+
const raw = args[i + 1];
|
|
2165
|
+
if (raw === undefined || raw.startsWith('--')) {
|
|
2166
|
+
console.error('ERROR: --url requires a value (URL)');
|
|
2167
|
+
process.exit(2);
|
|
2168
|
+
}
|
|
2169
|
+
let parsed;
|
|
2170
|
+
try {
|
|
2171
|
+
parsed = new URL(raw);
|
|
2172
|
+
} catch {
|
|
2173
|
+
console.error(`ERROR: --url value is not a valid URL: ${raw}`);
|
|
2174
|
+
process.exit(2);
|
|
2175
|
+
}
|
|
2176
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
2177
|
+
console.error(`ERROR: --url must be http(s); got ${parsed.protocol} in "${raw}"`);
|
|
2178
|
+
process.exit(2);
|
|
2179
|
+
}
|
|
2180
|
+
if (parsed.protocol === 'http:' && !allowHttp) {
|
|
2181
|
+
console.error(`ERROR: --url with http:// requires --allow-http (got "${raw}")`);
|
|
2182
|
+
process.exit(2);
|
|
2183
|
+
}
|
|
2184
|
+
if (parsed.username || parsed.password) {
|
|
2185
|
+
console.error('ERROR: --url must not contain credentials (user:pass@). Pass tokens via --auth.');
|
|
2186
|
+
process.exit(2);
|
|
2187
|
+
}
|
|
2188
|
+
values.push(raw);
|
|
2189
|
+
}
|
|
2190
|
+
return values;
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
/**
|
|
2194
|
+
* Run a storyboard (or bundle) in multi-instance mode. Each step round-robins
|
|
2195
|
+
* across the supplied URLs. Positional agent is disallowed ā --url is the
|
|
2196
|
+
* multi-instance path; positional is the single-instance path.
|
|
2197
|
+
*
|
|
2198
|
+
* Full capability-driven assessment (no storyboard ID) is intentionally not
|
|
2199
|
+
* supported here: the compliance pipeline shares a single client across
|
|
2200
|
+
* storyboards for connection reuse, which is incompatible with per-step URL
|
|
2201
|
+
* dispatch. Use a specific storyboard or bundle ID.
|
|
2202
|
+
*/
|
|
2203
|
+
/**
|
|
2204
|
+
* `adcp storyboard run --local-agent <module> [id|bundle]`
|
|
2205
|
+
*
|
|
2206
|
+
* Imports the module, looks for a `createAgent` (default export preferred,
|
|
2207
|
+
* falls back to named `createAgent`), and delegates to
|
|
2208
|
+
* `runAgainstLocalAgent`. The module contract is the same as `serve()`'s
|
|
2209
|
+
* factory: `(ctx) => AdcpServer | McpServer` that closes over a stable
|
|
2210
|
+
* stateStore.
|
|
2211
|
+
*
|
|
2212
|
+
* Relative paths resolve against the CLI's working directory; bare
|
|
2213
|
+
* specifiers resolve as npm packages.
|
|
2214
|
+
*/
|
|
2215
|
+
async function handleLocalAgentStoryboardRun(modulePath, args, opts) {
|
|
2216
|
+
const { positionalArgs, jsonOutput, format, dryRun, debug } = opts;
|
|
2217
|
+
const storyboardId = positionalArgs[0];
|
|
2218
|
+
|
|
2219
|
+
if (dryRun) {
|
|
2220
|
+
console.error('ERROR: --dry-run is not supported with --local-agent (nothing to preview). Drop --dry-run.');
|
|
2221
|
+
process.exit(2);
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
const specifier =
|
|
2225
|
+
modulePath.startsWith('.') || path.isAbsolute(modulePath)
|
|
2226
|
+
? pathToFileURL(path.resolve(process.cwd(), modulePath)).href
|
|
2227
|
+
: modulePath;
|
|
2228
|
+
|
|
2229
|
+
let mod;
|
|
2230
|
+
try {
|
|
2231
|
+
mod = await import(specifier);
|
|
2232
|
+
} catch (err) {
|
|
2233
|
+
console.error(`ERROR: --local-agent failed to import "${modulePath}": ${err.message}`);
|
|
2234
|
+
if (debug) console.error(err.stack);
|
|
2235
|
+
process.exit(2);
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2238
|
+
const createAgent = mod.default?.createAgent || mod.default || mod.createAgent;
|
|
2239
|
+
if (typeof createAgent !== 'function') {
|
|
2240
|
+
console.error(
|
|
2241
|
+
`ERROR: --local-agent module "${modulePath}" must export \`createAgent\` (default export or named).\n` +
|
|
2242
|
+
' Expected signature: (ctx: ServeContext) => AdcpServer | McpServer'
|
|
2243
|
+
);
|
|
2244
|
+
process.exit(2);
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
await loadInvariantModules(args);
|
|
2248
|
+
|
|
2249
|
+
const { runAgainstLocalAgent } = await import('../dist/lib/testing/index.js');
|
|
2250
|
+
const { setAgentTesterLogger } = await import('../dist/lib/testing/client.js');
|
|
2251
|
+
if (!debug && !jsonOutput) {
|
|
2252
|
+
setAgentTesterLogger({ info: () => {}, error: () => {}, warn: () => {}, debug: () => {} });
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2255
|
+
const storyboardsSpec = storyboardId ? [storyboardId] : 'all';
|
|
2256
|
+
const restoreLogs = jsonOutput ? captureStdoutLogs() : null;
|
|
2257
|
+
let result;
|
|
2258
|
+
try {
|
|
2259
|
+
result = await runAgainstLocalAgent({
|
|
2260
|
+
createAgent,
|
|
2261
|
+
storyboards: storyboardsSpec,
|
|
2262
|
+
...(opts.noSandbox && { runStoryboardOptions: { sandbox: false } }),
|
|
2263
|
+
onStoryboardComplete:
|
|
2264
|
+
jsonOutput || format === 'junit'
|
|
2265
|
+
? undefined
|
|
2266
|
+
: (sb, i, total) => {
|
|
2267
|
+
const icon = sb.overall_passed ? 'ā
' : 'ā';
|
|
2268
|
+
console.error(
|
|
2269
|
+
`${icon} [${i + 1}/${total}] ${sb.storyboard_title} ā ${sb.passed_count} passed, ${sb.failed_count} failed, ${sb.skipped_count} skipped`
|
|
2270
|
+
);
|
|
2271
|
+
},
|
|
2272
|
+
});
|
|
2273
|
+
} catch (err) {
|
|
2274
|
+
if (restoreLogs) restoreLogs();
|
|
2275
|
+
console.error(`\nā Local agent run failed: ${err.message}`);
|
|
2276
|
+
if (debug) console.error(err.stack);
|
|
2277
|
+
process.exit(1);
|
|
2278
|
+
} finally {
|
|
2279
|
+
if (restoreLogs) restoreLogs();
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
if (format === 'junit') {
|
|
2283
|
+
process.stdout.write(formatStoryboardResultsAsJUnit(result.results));
|
|
2284
|
+
process.exit(result.overall_passed ? 0 : 3);
|
|
2285
|
+
}
|
|
2286
|
+
if (jsonOutput) {
|
|
2287
|
+
await writeJsonOutput(result);
|
|
2288
|
+
process.exit(result.overall_passed ? 0 : 3);
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2291
|
+
// Human-readable summary
|
|
2292
|
+
console.log(`\nLocal agent run ā ${result.results.length} storyboard(s), ${result.total_duration_ms}ms`);
|
|
2293
|
+
console.log(` Mount: ${result.agent_url}\n`);
|
|
2294
|
+
for (const sb of result.results) {
|
|
2295
|
+
const icon = sb.overall_passed ? 'ā
' : 'ā';
|
|
2296
|
+
console.log(
|
|
2297
|
+
`${icon} ${sb.storyboard_title} (${sb.storyboard_id}) ā ${sb.passed_count} passed, ${sb.failed_count} failed, ${sb.skipped_count} skipped`
|
|
2298
|
+
);
|
|
2299
|
+
}
|
|
2300
|
+
if (result.not_applicable.length > 0) {
|
|
2301
|
+
console.log(`\n${result.not_applicable.length} storyboard(s) not applicable (out of scope):`);
|
|
2302
|
+
for (const na of result.not_applicable) {
|
|
2303
|
+
console.log(` āļø ${na.storyboard_title} ā ${na.reason}`);
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
const overallIcon = result.overall_passed ? 'ā
' : 'ā';
|
|
2307
|
+
const aggregateHints = (result.results || []).reduce((n, sb) => n + countHintsInResult(sb), 0);
|
|
2308
|
+
const hintTail = aggregateHints > 0 ? ` Ā· ${aggregateHints} hint${aggregateHints === 1 ? '' : 's'}` : '';
|
|
2309
|
+
console.log(
|
|
2310
|
+
`\n${overallIcon} ${result.passed_count} passed, ${result.failed_count} failed, ${result.skipped_count} skipped across ${result.results.length} storyboard(s)${hintTail}`
|
|
2311
|
+
);
|
|
2312
|
+
printStrictSummary(aggregateStrictSummaries(result.results.map(r => r.strict_validation_summary)));
|
|
2313
|
+
process.exit(result.overall_passed ? 0 : 3);
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
/**
|
|
2317
|
+
* Print the strict/lenient response-schema summary as a one-liner beneath
|
|
2318
|
+
* the lenient pass/fail tally. Silent when the run had no strict-eligible
|
|
2319
|
+
* checks (observable: false); visible only when something was graded.
|
|
2320
|
+
* `strict_only_failures > 0` is the production-readiness signal ā tint
|
|
2321
|
+
* the icon to reflect it so scrolling eyes catch it.
|
|
2322
|
+
*/
|
|
2323
|
+
function printStrictSummary(summary) {
|
|
2324
|
+
if (!summary || !summary.observable) return;
|
|
2325
|
+
const { checked, passed, strict_only_failures: strictOnly } = summary;
|
|
2326
|
+
const icon = strictOnly > 0 ? 'ā ļø ' : 'ā
';
|
|
2327
|
+
const tail = strictOnly > 0 ? ` (${strictOnly} lenient-only ā strict dispatcher would reject)` : '';
|
|
2328
|
+
console.log(`${icon} strict: ${passed}/${checked} passed${tail}`);
|
|
2329
|
+
}
|
|
2330
|
+
|
|
2331
|
+
/**
|
|
2332
|
+
* Aggregate per-storyboard strict summaries into one. Runs are
|
|
2333
|
+
* independent grading passes against the same SDK; summing their
|
|
2334
|
+
* counters produces the run-total signal the CLI summary needs.
|
|
2335
|
+
* Returns a summary with `observable: true` iff any input was
|
|
2336
|
+
* observable.
|
|
2337
|
+
*/
|
|
2338
|
+
function aggregateStrictSummaries(summaries) {
|
|
2339
|
+
const out = {
|
|
2340
|
+
observable: false,
|
|
2341
|
+
checked: 0,
|
|
2342
|
+
passed: 0,
|
|
2343
|
+
failed: 0,
|
|
2344
|
+
strict_only_failures: 0,
|
|
2345
|
+
lenient_also_failed: 0,
|
|
2346
|
+
};
|
|
2347
|
+
for (const s of summaries) {
|
|
2348
|
+
if (!s) continue;
|
|
2349
|
+
if (s.observable) out.observable = true;
|
|
2350
|
+
out.checked += s.checked;
|
|
2351
|
+
out.passed += s.passed;
|
|
2352
|
+
out.failed += s.failed;
|
|
2353
|
+
out.strict_only_failures += s.strict_only_failures;
|
|
2354
|
+
out.lenient_also_failed += s.lenient_also_failed;
|
|
2355
|
+
}
|
|
2356
|
+
return out;
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
async function handleMultiInstanceStoryboardRun(args, opts, urls) {
|
|
2360
|
+
const { authToken, protocolFlag, jsonOutput, dryRun, positionalArgs, file: filePath } = opts;
|
|
2361
|
+
|
|
2362
|
+
if (urls.length < 2) {
|
|
2363
|
+
console.error('ERROR: Multi-instance mode requires 2+ --url flags. Drop --url for single-instance.');
|
|
2364
|
+
process.exit(2);
|
|
2365
|
+
}
|
|
2366
|
+
|
|
2367
|
+
const strategy = extractMultiInstanceStrategy(args);
|
|
2368
|
+
|
|
2369
|
+
// Parse webhook-receiver flags here so the multi-pass incompatibility fails
|
|
2370
|
+
// up front ā not after bundle resolution, connection setup, or dispatch.
|
|
2371
|
+
const webhookAutoTunnel = args.includes('--webhook-receiver-auto-tunnel');
|
|
2372
|
+
const webhookReceiverBase = extractWebhookReceiverOptions(args);
|
|
2373
|
+
validateAutoTunnelArgs(args, webhookReceiverBase);
|
|
2374
|
+
if ((webhookReceiverBase || webhookAutoTunnel) && strategy === 'multi-pass') {
|
|
2375
|
+
// The runner throws on this combination (each pass binds a fresh receiver
|
|
2376
|
+
// URL; agents caching pass-1 URLs would deliver to a dead port in pass 2).
|
|
2377
|
+
// Surface it as a CLI-level error so operators don't wait for dispatch.
|
|
2378
|
+
console.error(
|
|
2379
|
+
'ERROR: --webhook-receiver is incompatible with --multi-instance-strategy multi-pass. ' +
|
|
2380
|
+
'Use round-robin (the default) when hosting a webhook receiver.'
|
|
2381
|
+
);
|
|
2382
|
+
process.exit(2);
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2385
|
+
// Strip --url values that may have slipped past parseAgentOptions' positional filter.
|
|
2386
|
+
const cleanPositional = positionalArgs.filter(p => !urls.includes(p));
|
|
2387
|
+
const firstPositional = cleanPositional[0];
|
|
2388
|
+
|
|
2389
|
+
if (firstPositional && (firstPositional.startsWith('http://') || firstPositional.startsWith('https://'))) {
|
|
2390
|
+
console.error(
|
|
2391
|
+
'ERROR: Cannot combine a positional agent URL with --url flags. ' +
|
|
2392
|
+
'Use either a positional agent (single-instance) or repeated --url flags (multi-instance).'
|
|
2393
|
+
);
|
|
2394
|
+
process.exit(2);
|
|
2395
|
+
}
|
|
2396
|
+
|
|
2397
|
+
const storyboardId = firstPositional;
|
|
2398
|
+
|
|
2399
|
+
if (filePath && storyboardId) {
|
|
2400
|
+
console.error('ERROR: Cannot combine a storyboard ID with --file. Use one or the other.');
|
|
2401
|
+
process.exit(2);
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
if (!filePath && !storyboardId) {
|
|
2405
|
+
console.error(
|
|
2406
|
+
'ERROR: Multi-instance mode requires a storyboard ID, bundle ID, or --file. ' +
|
|
2407
|
+
'Capability-driven full assessment is not yet multi-instance aware.'
|
|
2408
|
+
);
|
|
2409
|
+
process.exit(2);
|
|
2410
|
+
}
|
|
2411
|
+
|
|
2412
|
+
const { loadStoryboardFile, runStoryboard, getComplianceStoryboardById, loadBundleStoryboards, findBundleById } =
|
|
2413
|
+
await import('../dist/lib/testing/storyboard/index.js');
|
|
2414
|
+
|
|
2415
|
+
// Load one or more storyboards (bundle IDs expand).
|
|
2416
|
+
const storyboards = [];
|
|
2417
|
+
if (filePath) {
|
|
2418
|
+
try {
|
|
2419
|
+
storyboards.push(loadStoryboardFile(filePath));
|
|
2420
|
+
} catch (err) {
|
|
2421
|
+
console.error(`Failed to load storyboard from ${filePath}: ${err.message}`);
|
|
2422
|
+
process.exit(2);
|
|
2423
|
+
}
|
|
2424
|
+
} else {
|
|
2425
|
+
const bundle = findBundleById(storyboardId);
|
|
2426
|
+
if (bundle) {
|
|
2427
|
+
const bundleStoryboards = loadBundleStoryboards(storyboardId);
|
|
2428
|
+
if (!bundleStoryboards || bundleStoryboards.length === 0) {
|
|
2429
|
+
console.error(`ERROR: Bundle "${storyboardId}" is empty.`);
|
|
2430
|
+
process.exit(2);
|
|
2431
|
+
}
|
|
2432
|
+
storyboards.push(...bundleStoryboards);
|
|
2433
|
+
} else {
|
|
2434
|
+
const sb = getComplianceStoryboardById(storyboardId);
|
|
2435
|
+
if (!sb) {
|
|
2436
|
+
console.error(
|
|
2437
|
+
`ERROR: Unknown storyboard or bundle ID: ${storyboardId}\n` + `Run 'adcp storyboard list' to see all options.`
|
|
2438
|
+
);
|
|
2439
|
+
process.exit(2);
|
|
2440
|
+
}
|
|
2441
|
+
storyboards.push(sb);
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2445
|
+
// Auto-detect protocol from the first URL. Multi-instance deployments
|
|
2446
|
+
// share a codebase across replicas, so one probe is representative.
|
|
2447
|
+
let protocol = protocolFlag;
|
|
2448
|
+
if (!protocol) {
|
|
2449
|
+
if (!jsonOutput) console.error('Auto-detecting protocol from first URL...');
|
|
2450
|
+
try {
|
|
2451
|
+
protocol = await detectProtocol(urls[0]);
|
|
2452
|
+
if (!jsonOutput) console.error(`Detected protocol: ${protocol.toUpperCase()}\n`);
|
|
2453
|
+
} catch (err) {
|
|
2454
|
+
console.error(`ERROR: Failed to detect protocol: ${err.message}`);
|
|
2455
|
+
process.exit(1);
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
|
|
2459
|
+
// Load invariants before the dry-run gate so bad module specifiers fail fast.
|
|
2460
|
+
await loadInvariantModules(args);
|
|
2461
|
+
|
|
2462
|
+
const totalSteps = storyboards.reduce(
|
|
2463
|
+
(sum, sb) => sum + sb.phases.reduce((phaseSum, p) => phaseSum + p.steps.length, 0),
|
|
2464
|
+
0
|
|
2465
|
+
);
|
|
2466
|
+
|
|
2467
|
+
if (!jsonOutput) {
|
|
2468
|
+
const strategyLabel = strategy === 'multi-pass' ? `multi-pass (${urls.length} passes)` : `round-robin (1 pass)`;
|
|
2469
|
+
console.error(`Multi-instance storyboard run (${strategyLabel} across ${urls.length} instances):`);
|
|
2470
|
+
urls.forEach((u, i) => console.error(` [#${i + 1}] ${u}`));
|
|
2471
|
+
console.error(` Protocol: ${protocol.toUpperCase()}`);
|
|
2472
|
+
console.error(` Storyboards: ${storyboards.map(s => s.id).join(', ')}`);
|
|
2473
|
+
const effectiveSteps = strategy === 'multi-pass' ? totalSteps * urls.length : totalSteps;
|
|
2474
|
+
console.error(
|
|
2475
|
+
` Total steps: ${effectiveSteps}${strategy === 'multi-pass' ? ` (${totalSteps} Ć ${urls.length} passes)` : ''}`
|
|
2476
|
+
);
|
|
2477
|
+
if (opts.noSandbox) {
|
|
2478
|
+
console.error(` Run mode: production (account.sandbox=false on every request)`);
|
|
2479
|
+
}
|
|
2480
|
+
console.error('');
|
|
2481
|
+
// N=2 is the deployment shape most operators have. Offset-shift preserves
|
|
2482
|
+
// pair parity there, so every even-distance writeāread pair lands
|
|
2483
|
+
// same-replica in every pass ā including the canonical property_lists
|
|
2484
|
+
// case. Print a visible caveat so operators don't read "multi-pass" as
|
|
2485
|
+
// "full cross-replica state coverage."
|
|
2486
|
+
if (strategy === 'multi-pass' && urls.length === 2) {
|
|
2487
|
+
console.error(
|
|
2488
|
+
'Caveat: multi-pass at N=2 does NOT cover cross-replica writeāread pairs at\n' +
|
|
2489
|
+
'even dispatch-index distance (e.g., write at step 0, read at step 2).\n' +
|
|
2490
|
+
'Use round-robin for adjacent pairs; see docs/guides/MULTI-INSTANCE-TESTING.md\n' +
|
|
2491
|
+
'for the full coverage story. Multi-pass is useful for catching single-replica\n' +
|
|
2492
|
+
'config/version/cache bugs that pure round-robin may miss.\n'
|
|
2493
|
+
);
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
// --dry-run: print the assignment plan and exit
|
|
2498
|
+
if (dryRun) {
|
|
2499
|
+
// Multi-pass runs the same storyboard once per pass, with the dispatcher
|
|
2500
|
+
// starting at a different replica each time; round-robin is the special
|
|
2501
|
+
// case of one pass.
|
|
2502
|
+
const passCount = strategy === 'multi-pass' ? urls.length : 1;
|
|
2503
|
+
const passOffsets = Array.from({ length: passCount }, (_, i) => i);
|
|
2504
|
+
const assignmentsFor = (sb, offset) => {
|
|
2505
|
+
const flat = sb.phases.flatMap(p => p.steps);
|
|
2506
|
+
return flat.map((s, idx) => {
|
|
2507
|
+
const pos = (idx + offset) % urls.length;
|
|
2508
|
+
return {
|
|
2509
|
+
step_id: s.id,
|
|
2510
|
+
task: s.task,
|
|
2511
|
+
instance_index: pos + 1,
|
|
2512
|
+
agent_url: urls[pos],
|
|
2513
|
+
};
|
|
2514
|
+
});
|
|
2515
|
+
};
|
|
2516
|
+
if (jsonOutput) {
|
|
2517
|
+
await writeJsonOutput({
|
|
2518
|
+
agent_urls: urls,
|
|
2519
|
+
multi_instance_strategy: strategy,
|
|
2520
|
+
protocol,
|
|
2521
|
+
preview: true,
|
|
2522
|
+
storyboards: storyboards.map(sb => ({
|
|
2523
|
+
storyboard_id: sb.id,
|
|
2524
|
+
storyboard_title: sb.title,
|
|
2525
|
+
...(strategy === 'multi-pass'
|
|
2526
|
+
? {
|
|
2527
|
+
passes: passOffsets.map(o => ({
|
|
2528
|
+
pass_index: o + 1,
|
|
2529
|
+
dispatch_offset: o,
|
|
2530
|
+
assignments: assignmentsFor(sb, o),
|
|
2531
|
+
})),
|
|
2532
|
+
}
|
|
2533
|
+
: { assignments: assignmentsFor(sb, 0) }),
|
|
2534
|
+
})),
|
|
2535
|
+
});
|
|
2536
|
+
} else {
|
|
2537
|
+
for (const sb of storyboards) {
|
|
2538
|
+
console.log(`\n${sb.title} (${sb.id})`);
|
|
2539
|
+
console.log('ā'.repeat(50));
|
|
2540
|
+
for (const offset of passOffsets) {
|
|
2541
|
+
if (strategy === 'multi-pass') {
|
|
2542
|
+
console.log(`\nāā Pass ${offset + 1} of ${passCount} (starts at [#${offset + 1}]) āā`);
|
|
2543
|
+
}
|
|
2544
|
+
let stepIdx = 0;
|
|
2545
|
+
for (const phase of sb.phases) {
|
|
2546
|
+
console.log(`\nāā Phase: ${phase.title} āā`);
|
|
2547
|
+
for (const step of phase.steps) {
|
|
2548
|
+
const inst = ((stepIdx + offset) % urls.length) + 1;
|
|
2549
|
+
console.log(` [#${inst}] ${step.id}: ${step.title} ā ${step.task}`);
|
|
2550
|
+
stepIdx++;
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
const effective = totalSteps * passCount;
|
|
2556
|
+
console.log(
|
|
2557
|
+
`\n${effective} step(s) would be executed across ${urls.length} instances${strategy === 'multi-pass' ? ` over ${passCount} passes` : ''}. Use without --dry-run to run.`
|
|
2558
|
+
);
|
|
2559
|
+
}
|
|
2560
|
+
return;
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
const webhookReceiverOpts = webhookAutoTunnel
|
|
2564
|
+
? await resolveWebhookReceiverOptions(args, { jsonOutput })
|
|
2565
|
+
: webhookReceiverBase;
|
|
2566
|
+
|
|
2567
|
+
const runOptions = {
|
|
2568
|
+
protocol,
|
|
2569
|
+
...(authToken ? { auth: { type: 'bearer', token: authToken } } : {}),
|
|
2570
|
+
...(opts.allowHttp && { allow_http: true }),
|
|
2571
|
+
multi_instance_strategy: strategy,
|
|
2572
|
+
...(webhookReceiverOpts ?? {}),
|
|
2573
|
+
...(opts.noSandbox && { sandbox: false }),
|
|
2574
|
+
};
|
|
2575
|
+
|
|
2576
|
+
const restoreLogs = jsonOutput ? captureStdoutLogs() : null;
|
|
2577
|
+
const results = [];
|
|
2578
|
+
let hadFailure = false;
|
|
2579
|
+
try {
|
|
2580
|
+
for (const sb of storyboards) {
|
|
2581
|
+
const result = await runStoryboard(urls, sb, runOptions);
|
|
2582
|
+
results.push(result);
|
|
2583
|
+
if (!result.overall_passed) hadFailure = true;
|
|
2584
|
+
}
|
|
2585
|
+
} finally {
|
|
2586
|
+
if (restoreLogs) restoreLogs();
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2589
|
+
if (jsonOutput) {
|
|
2590
|
+
await writeJsonOutput(
|
|
2591
|
+
results.length === 1
|
|
2592
|
+
? results[0]
|
|
2593
|
+
: {
|
|
2594
|
+
agent_urls: urls,
|
|
2595
|
+
multi_instance_strategy: strategy,
|
|
2596
|
+
storyboards: results,
|
|
2597
|
+
overall_passed: !hadFailure,
|
|
2598
|
+
}
|
|
2599
|
+
);
|
|
2600
|
+
} else {
|
|
2601
|
+
const SKIP_ICONS = { missing_test_harness: 'š§', not_testable: 'āļø', dependency_failed: 'āļø' };
|
|
2602
|
+
const SKIP_LABELS = {
|
|
2603
|
+
missing_test_harness: ' [needs test harness]',
|
|
2604
|
+
not_testable: ' [not testable]',
|
|
2605
|
+
dependency_failed: ' [dependency failed]',
|
|
2606
|
+
};
|
|
2607
|
+
for (const result of results) {
|
|
2608
|
+
console.log(`\n${result.storyboard_title} (${result.storyboard_id})`);
|
|
2609
|
+
console.log('ā'.repeat(50));
|
|
2610
|
+
for (const phase of result.phases) {
|
|
2611
|
+
console.log(`\nāā Phase: ${phase.phase_title} āāāāāāāāāāāāāāāāāāāāāāāāāāāāāā`);
|
|
2612
|
+
for (const step of phase.steps) {
|
|
2613
|
+
const icon = step.skipped ? (SKIP_ICONS[step.skip_reason] ?? 'āļø') : step.passed ? 'ā
' : 'ā';
|
|
2614
|
+
const skipLabel = SKIP_LABELS[step.skip_reason] ?? '';
|
|
2615
|
+
const instTag = step.agent_index ? `[#${step.agent_index}] ` : '';
|
|
2616
|
+
console.log(`\n${icon} ${instTag}${step.title}${skipLabel} (${step.duration_ms}ms)`);
|
|
2617
|
+
console.log(` Task: ${step.task}`);
|
|
2618
|
+
if (step.error) {
|
|
2619
|
+
console.log(` Error: ${step.error}`);
|
|
2620
|
+
}
|
|
2621
|
+
for (const v of step.validations) {
|
|
2622
|
+
const vIcon = v.passed ? 'ā
' : 'ā';
|
|
2623
|
+
console.log(` ${vIcon} ${v.description}`);
|
|
2624
|
+
if (v.error) console.log(` ${v.error}`);
|
|
2625
|
+
if (v.warning) console.log(` ā ļø ${v.warning}`);
|
|
2626
|
+
}
|
|
2627
|
+
// Hint after validations so the operator's eye lands on the
|
|
2628
|
+
// diagnostic at the bottom of the failing-step block ā not
|
|
2629
|
+
// pushed up the screen by passing validations.
|
|
2630
|
+
printStepHints(step.hints);
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
}
|
|
2634
|
+
console.log(`\n${'ā'.repeat(50)}`);
|
|
2635
|
+
const totals = results.reduce(
|
|
2636
|
+
(acc, r) => ({
|
|
2637
|
+
passed: acc.passed + r.passed_count,
|
|
2638
|
+
failed: acc.failed + r.failed_count,
|
|
2639
|
+
skipped: acc.skipped + r.skipped_count,
|
|
2640
|
+
duration: acc.duration + r.total_duration_ms,
|
|
2641
|
+
hints: acc.hints + countHintsInResult(r),
|
|
2642
|
+
}),
|
|
2643
|
+
{ passed: 0, failed: 0, skipped: 0, duration: 0, hints: 0 }
|
|
2644
|
+
);
|
|
2645
|
+
const overallIcon = !hadFailure ? 'ā
' : 'ā';
|
|
2646
|
+
const passSuffix =
|
|
2647
|
+
strategy === 'multi-pass'
|
|
2648
|
+
? ` across ${urls.length} passes Ć ${urls.length} instances`
|
|
2649
|
+
: ` across ${urls.length} instances`;
|
|
2650
|
+
const hintTail = totals.hints > 0 ? ` Ā· ${totals.hints} hint${totals.hints === 1 ? '' : 's'}` : '';
|
|
2651
|
+
console.log(
|
|
2652
|
+
`${overallIcon} ${totals.passed} passed, ${totals.failed} failed, ${totals.skipped} skipped (${totals.duration}ms)${passSuffix}${hintTail}`
|
|
2653
|
+
);
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
process.exit(hadFailure ? 3 : 0);
|
|
2657
|
+
}
|
|
2658
|
+
|
|
2659
|
+
// Shared implementation: run all matching storyboards against an agent
|
|
2660
|
+
async function runFullAssessment(agentArg, rawArgs, parsedOpts) {
|
|
2661
|
+
const opts = parsedOpts || parseAgentOptions(rawArgs);
|
|
2662
|
+
|
|
2663
|
+
const {
|
|
2664
|
+
agentUrl,
|
|
2665
|
+
protocol,
|
|
2666
|
+
authToken: finalAuthToken,
|
|
2667
|
+
oauthTokens,
|
|
2668
|
+
oauthClient,
|
|
2669
|
+
oauthClientCredentials,
|
|
2670
|
+
} = await resolveAgent(agentArg, opts.authToken, opts.protocolFlag, opts.jsonOutput);
|
|
2671
|
+
|
|
2672
|
+
// Parse --tracks
|
|
2673
|
+
const tracksIndex = rawArgs.indexOf('--tracks');
|
|
2674
|
+
let tracks;
|
|
2675
|
+
if (tracksIndex !== -1 && tracksIndex + 1 < rawArgs.length) {
|
|
2676
|
+
tracks = rawArgs[tracksIndex + 1].split(',');
|
|
2677
|
+
}
|
|
2678
|
+
|
|
2679
|
+
// Parse --storyboards (explicit bundle or storyboard IDs); positional overrides.
|
|
2680
|
+
const storyboardsIndex = rawArgs.indexOf('--storyboards');
|
|
2681
|
+
let storyboards = opts.explicitStoryboards;
|
|
2682
|
+
if (!storyboards && storyboardsIndex !== -1 && storyboardsIndex + 1 < rawArgs.length) {
|
|
2683
|
+
storyboards = rawArgs[storyboardsIndex + 1].split(',');
|
|
2684
|
+
}
|
|
2685
|
+
if (storyboards?.length) {
|
|
2686
|
+
const { listAllComplianceStoryboards, listBundles } = await import('../dist/lib/testing/storyboard/index.js');
|
|
2687
|
+
try {
|
|
2688
|
+
const knownStoryboardIds = new Set(listAllComplianceStoryboards().map(s => s.id));
|
|
2689
|
+
const knownBundleIds = new Set(listBundles().map(b => b.id));
|
|
2690
|
+
const unknown = storyboards.filter(id => !knownStoryboardIds.has(id) && !knownBundleIds.has(id));
|
|
2691
|
+
if (unknown.length > 0) {
|
|
2692
|
+
console.error(`ERROR: Unknown storyboard or bundle ID(s): ${unknown.join(', ')}`);
|
|
2693
|
+
console.error(`Run 'adcp storyboard list' to see all options.\n`);
|
|
2694
|
+
process.exit(2);
|
|
2695
|
+
}
|
|
2696
|
+
} catch (err) {
|
|
2697
|
+
console.error(`ERROR: ${err.message}`);
|
|
2698
|
+
process.exit(1);
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
|
|
2702
|
+
// Parse --timeout (seconds, default 120)
|
|
2703
|
+
const timeoutFlagIndex = rawArgs.indexOf('--timeout');
|
|
2704
|
+
const DEFAULT_TIMEOUT_S = 120;
|
|
2705
|
+
let timeoutMs = DEFAULT_TIMEOUT_S * 1000;
|
|
2706
|
+
if (timeoutFlagIndex !== -1) {
|
|
2707
|
+
if (timeoutFlagIndex + 1 >= rawArgs.length || rawArgs[timeoutFlagIndex + 1].startsWith('--')) {
|
|
2708
|
+
console.error('ERROR: --timeout requires a value (seconds)\n');
|
|
2709
|
+
process.exit(2);
|
|
2710
|
+
}
|
|
2711
|
+
const seconds = parseInt(rawArgs[timeoutFlagIndex + 1], 10);
|
|
2712
|
+
if (isNaN(seconds) || seconds <= 0) {
|
|
2713
|
+
console.error(`ERROR: --timeout must be a positive integer (seconds), got: ${rawArgs[timeoutFlagIndex + 1]}`);
|
|
2714
|
+
process.exit(2);
|
|
2715
|
+
}
|
|
2716
|
+
timeoutMs = seconds * 1000;
|
|
2717
|
+
}
|
|
2718
|
+
|
|
2719
|
+
const { auth: authOption } = buildResolvedAuthOption({
|
|
2720
|
+
resolvedAuth: finalAuthToken,
|
|
2721
|
+
resolvedOauthTokens: oauthTokens,
|
|
2722
|
+
resolvedOauthClient: oauthClient,
|
|
2723
|
+
resolvedOauthClientCredentials: oauthClientCredentials,
|
|
2724
|
+
});
|
|
2725
|
+
|
|
2726
|
+
const webhookReceiverOpts = await resolveWebhookReceiverOptions(rawArgs, { jsonOutput: opts.jsonOutput });
|
|
2727
|
+
|
|
2728
|
+
await loadInvariantModules(rawArgs);
|
|
2729
|
+
|
|
2730
|
+
const testOptions = {
|
|
2731
|
+
protocol,
|
|
2732
|
+
brief: opts.brief,
|
|
2733
|
+
tracks,
|
|
2734
|
+
storyboards,
|
|
2735
|
+
timeout_ms: timeoutMs,
|
|
2736
|
+
agent_alias: agentArg !== agentUrl ? agentArg : undefined,
|
|
2737
|
+
...(authOption && { auth: authOption }),
|
|
2738
|
+
...(opts.allowHttp && { allow_http: true }),
|
|
2739
|
+
...(webhookReceiverOpts ?? {}),
|
|
2740
|
+
...(opts.noSandbox && { sandbox: false }),
|
|
2741
|
+
};
|
|
2742
|
+
|
|
2743
|
+
if (!opts.jsonOutput) {
|
|
2744
|
+
const authLabel = !authOption
|
|
2745
|
+
? 'none'
|
|
2746
|
+
: authOption.type === 'oauth'
|
|
2747
|
+
? 'oauth (auto-refresh)'
|
|
2748
|
+
: authOption.type === 'oauth_client_credentials'
|
|
2749
|
+
? 'oauth client credentials (auto-refresh)'
|
|
2750
|
+
: 'bearer';
|
|
2751
|
+
console.log(`\nRunning storyboard assessment against ${agentUrl}`);
|
|
2752
|
+
console.log(` Protocol: ${protocol.toUpperCase()}`);
|
|
2753
|
+
if (storyboards) console.log(` Storyboards: ${storyboards.join(', ')}`);
|
|
2754
|
+
console.log(` Timeout: ${timeoutMs / 1000}s`);
|
|
2755
|
+
console.log(` Auth: ${authLabel}`);
|
|
2756
|
+
if (opts.allowHttp) console.log(` ā ļø --allow-http set ā results are not publishable`);
|
|
2757
|
+
console.log('');
|
|
2758
|
+
}
|
|
2759
|
+
|
|
2760
|
+
const restoreLogs = opts.jsonOutput ? captureStdoutLogs() : null;
|
|
2761
|
+
try {
|
|
2762
|
+
const { comply, formatComplianceResults, formatComplianceResultsJSON } =
|
|
2763
|
+
await import('../dist/lib/testing/compliance/index.js');
|
|
2764
|
+
|
|
2765
|
+
const { setAgentTesterLogger } = await import('../dist/lib/testing/client.js');
|
|
2766
|
+
if (!opts.debug) {
|
|
2767
|
+
setAgentTesterLogger({ info: () => {}, error: () => {}, warn: () => {}, debug: () => {} });
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2770
|
+
const result = await comply(agentUrl, testOptions);
|
|
2771
|
+
|
|
2772
|
+
if (opts.jsonOutput) {
|
|
2773
|
+
restoreLogs();
|
|
2774
|
+
await writeJsonOutput(formatComplianceResultsJSON(result));
|
|
2775
|
+
} else {
|
|
2776
|
+
console.log(formatComplianceResults(result));
|
|
2777
|
+
}
|
|
2778
|
+
|
|
2779
|
+
const hasFailures = result.summary.tracks_failed > 0;
|
|
2780
|
+
process.exit(hasFailures ? 3 : 0);
|
|
2781
|
+
} catch (error) {
|
|
2782
|
+
if (restoreLogs) restoreLogs();
|
|
2783
|
+
console.error(`\nAssessment failed: ${error.message}`);
|
|
2784
|
+
if (opts.debug) console.error(error.stack);
|
|
2785
|
+
process.exit(1);
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
|
|
2789
|
+
async function handleStoryboardStepCmd(args) {
|
|
2790
|
+
const { getComplianceStoryboardById, runStoryboardStep } = await import('../dist/lib/testing/storyboard/index.js');
|
|
2791
|
+
const { authToken, protocolFlag, jsonOutput, debug, positionalArgs } = parseAgentOptions(args);
|
|
2792
|
+
|
|
2793
|
+
enforceStrictFlags(args, warnRemovedFlags(args));
|
|
2794
|
+
|
|
2795
|
+
const agentArg = positionalArgs[0];
|
|
2796
|
+
const storyboardId = positionalArgs[1];
|
|
2797
|
+
const stepId = positionalArgs[2];
|
|
2798
|
+
|
|
2799
|
+
if (!agentArg || !storyboardId || !stepId) {
|
|
2800
|
+
console.error('Usage: adcp storyboard step <agent> <storyboard_id> <step_id> [options]');
|
|
2801
|
+
process.exit(2);
|
|
2802
|
+
}
|
|
2803
|
+
|
|
2804
|
+
const storyboard = getComplianceStoryboardById(storyboardId);
|
|
2805
|
+
if (!storyboard) {
|
|
2806
|
+
console.error(`Storyboard not found: ${storyboardId}`);
|
|
2807
|
+
process.exit(2);
|
|
2808
|
+
}
|
|
2809
|
+
|
|
2810
|
+
await maybeRunInlineOAuth(agentArg, args, { jsonOutput });
|
|
2811
|
+
|
|
2812
|
+
const {
|
|
2813
|
+
agentUrl,
|
|
2814
|
+
protocol,
|
|
2815
|
+
authToken: resolvedAuth,
|
|
2816
|
+
oauthTokens: resolvedOauthTokens,
|
|
2817
|
+
oauthClient: resolvedOauthClient,
|
|
2818
|
+
oauthClientCredentials: resolvedOauthClientCredentials,
|
|
2819
|
+
} = await resolveAgent(agentArg, authToken, protocolFlag, jsonOutput);
|
|
2820
|
+
|
|
2821
|
+
// Parse --context and --request flags (supports inline JSON or @file.json)
|
|
2822
|
+
let context = {};
|
|
2823
|
+
let request;
|
|
2824
|
+
const contextIndex = args.indexOf('--context');
|
|
2825
|
+
if (contextIndex !== -1 && args[contextIndex + 1]) {
|
|
2826
|
+
context = parseJsonFlag('--context', args[contextIndex + 1]);
|
|
2827
|
+
}
|
|
2828
|
+
const requestIndex = args.indexOf('--request');
|
|
2829
|
+
if (requestIndex !== -1 && args[requestIndex + 1]) {
|
|
2830
|
+
request = parseJsonFlag('--request', args[requestIndex + 1]);
|
|
2831
|
+
}
|
|
2832
|
+
|
|
2833
|
+
const options = {
|
|
2834
|
+
protocol,
|
|
2835
|
+
context,
|
|
2836
|
+
request,
|
|
2837
|
+
...buildResolvedAuthOption({
|
|
2838
|
+
resolvedAuth,
|
|
2839
|
+
resolvedOauthTokens,
|
|
2840
|
+
resolvedOauthClient,
|
|
2841
|
+
resolvedOauthClientCredentials,
|
|
2842
|
+
}),
|
|
2843
|
+
};
|
|
2844
|
+
|
|
2845
|
+
const restoreLogs = jsonOutput ? captureStdoutLogs() : null;
|
|
2846
|
+
let result;
|
|
2847
|
+
try {
|
|
2848
|
+
result = await runStoryboardStep(agentUrl, storyboard, stepId, options);
|
|
2849
|
+
} finally {
|
|
2850
|
+
if (restoreLogs) restoreLogs();
|
|
2851
|
+
}
|
|
2852
|
+
|
|
2853
|
+
if (jsonOutput) {
|
|
2854
|
+
await writeJsonOutput(result);
|
|
2855
|
+
} else {
|
|
2856
|
+
const icon = result.passed ? 'ā
' : 'ā';
|
|
2857
|
+
console.log(`\nāā Step: ${result.title} āāāāāāāāāāāāāāāāāāāāāāāāāāāāāā`);
|
|
2858
|
+
console.log(`Task: ${result.task}`);
|
|
2859
|
+
console.log(`\n${icon} ${result.passed ? 'Passed' : 'Failed'} (${result.duration_ms}ms)`);
|
|
2860
|
+
|
|
2861
|
+
if (result.error) {
|
|
2862
|
+
console.log(`Error: ${result.error}`);
|
|
2863
|
+
}
|
|
2864
|
+
// Hint renders at column zero to match this printer's Error/validation
|
|
2865
|
+
// style ā unlike the phase-nested storyboard printer which uses a
|
|
2866
|
+
// 3-space indent. See adcp-client#879.
|
|
2867
|
+
printStepHints(result.hints, '');
|
|
2868
|
+
|
|
2869
|
+
for (const v of result.validations) {
|
|
2870
|
+
const vIcon = v.passed ? 'ā
' : 'ā';
|
|
2871
|
+
console.log(` ${vIcon} ${v.description}`);
|
|
2872
|
+
if (v.error) console.log(` ${v.error}`);
|
|
2873
|
+
if (v.warning) console.log(` ā ļø ${v.warning}`);
|
|
2874
|
+
}
|
|
2875
|
+
|
|
2876
|
+
// Show context
|
|
2877
|
+
const contextKeys = Object.keys(result.context);
|
|
2878
|
+
if (contextKeys.length > 0) {
|
|
2879
|
+
console.log(`\nContext: ${contextKeys.map(k => `${k}=${JSON.stringify(result.context[k])}`).join(', ')}`);
|
|
2880
|
+
}
|
|
2881
|
+
|
|
2882
|
+
// Show next step preview
|
|
2883
|
+
if (result.next) {
|
|
2884
|
+
console.log(`\nāā Next: ${result.next.title} āāāāāāāāāāāāāāāāāāāāāāāāāāāāāā`);
|
|
2885
|
+
console.log(`Task: ${result.next.task}`);
|
|
2886
|
+
if (result.next.narrative) {
|
|
2887
|
+
// Show first line of narrative
|
|
2888
|
+
const firstLine = result.next.narrative.trim().split('\n')[0];
|
|
2889
|
+
console.log(firstLine);
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
|
|
2894
|
+
process.exit(result.passed ? 0 : 3);
|
|
2895
|
+
}
|
|
2896
|
+
|
|
2897
|
+
async function handleCheckNetworkCommand(args) {
|
|
2898
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
2899
|
+
console.log(`
|
|
2900
|
+
Validate a managed publisher network deployment.
|
|
2901
|
+
|
|
2902
|
+
USAGE:
|
|
2903
|
+
adcp check-network --url <authoritative-url> [options]
|
|
2904
|
+
adcp check-network --domains <domain1,domain2,...> [options]
|
|
2905
|
+
|
|
2906
|
+
OPTIONS:
|
|
2907
|
+
--url URL URL of the authoritative adagents.json
|
|
2908
|
+
--domains LIST Comma-separated domains to check
|
|
2909
|
+
--concurrency N Max parallel fetches (default: 10)
|
|
2910
|
+
--timeout MS Per-request timeout in ms (default: 10000)
|
|
2911
|
+
--json Output raw JSON
|
|
2912
|
+
--help, -h Show this help
|
|
2913
|
+
|
|
2914
|
+
EXAMPLES:
|
|
2915
|
+
adcp check-network --url https://network.example.com/adagents/v2/adagents.json
|
|
2916
|
+
adcp check-network --url https://network.example.com/adagents.json --domains extra1.com,extra2.com
|
|
2917
|
+
adcp check-network --domains cookingdaily.com,gardenweekly.com
|
|
2918
|
+
`);
|
|
2919
|
+
return;
|
|
2920
|
+
}
|
|
2921
|
+
|
|
2922
|
+
const urlIndex = args.indexOf('--url');
|
|
2923
|
+
const domainsIndex = args.indexOf('--domains');
|
|
2924
|
+
const concurrencyIndex = args.indexOf('--concurrency');
|
|
2925
|
+
const timeoutIndex = args.indexOf('--timeout');
|
|
2926
|
+
const jsonOutput = args.includes('--json');
|
|
2927
|
+
|
|
2928
|
+
const url = urlIndex !== -1 ? args[urlIndex + 1] : undefined;
|
|
2929
|
+
const domainsStr = domainsIndex !== -1 ? args[domainsIndex + 1] : undefined;
|
|
2930
|
+
const concurrency = concurrencyIndex !== -1 ? parseInt(args[concurrencyIndex + 1], 10) : undefined;
|
|
2931
|
+
const timeout = timeoutIndex !== -1 ? parseInt(args[timeoutIndex + 1], 10) : undefined;
|
|
2932
|
+
|
|
2933
|
+
if (concurrency !== undefined && (isNaN(concurrency) || concurrency < 1)) {
|
|
2934
|
+
console.error('ERROR: --concurrency must be a positive integer');
|
|
2935
|
+
process.exit(2);
|
|
2936
|
+
}
|
|
2937
|
+
if (timeout !== undefined && (isNaN(timeout) || timeout < 1)) {
|
|
2938
|
+
console.error('ERROR: --timeout must be a positive integer');
|
|
2939
|
+
process.exit(2);
|
|
2940
|
+
}
|
|
2941
|
+
|
|
2942
|
+
if (!url && !domainsStr) {
|
|
2943
|
+
console.error('ERROR: --url or --domains is required\n');
|
|
2944
|
+
console.error('Run "adcp check-network --help" for usage');
|
|
2945
|
+
process.exit(2);
|
|
2946
|
+
}
|
|
2947
|
+
|
|
2948
|
+
const domains = domainsStr
|
|
2949
|
+
? domainsStr
|
|
2950
|
+
.split(',')
|
|
2951
|
+
.map(d => d.trim())
|
|
2952
|
+
.filter(Boolean)
|
|
2953
|
+
: undefined;
|
|
2954
|
+
|
|
2955
|
+
const { NetworkConsistencyChecker } = require('../dist/lib/index.js');
|
|
2956
|
+
|
|
2957
|
+
const progressHandler = jsonOutput
|
|
2958
|
+
? undefined
|
|
2959
|
+
: ({ phase, completed, total }) => {
|
|
2960
|
+
process.stderr.write(`\r ${phase}: ${completed}/${total}`);
|
|
2961
|
+
if (completed === total) process.stderr.write('\n');
|
|
2962
|
+
};
|
|
2963
|
+
|
|
2964
|
+
const checker = new NetworkConsistencyChecker({
|
|
2965
|
+
authoritativeUrl: url,
|
|
2966
|
+
domains,
|
|
2967
|
+
concurrency,
|
|
2968
|
+
timeoutMs: timeout,
|
|
2969
|
+
logLevel: 'warn',
|
|
2970
|
+
onProgress: progressHandler,
|
|
2971
|
+
});
|
|
2972
|
+
|
|
2973
|
+
try {
|
|
2974
|
+
const report = await checker.check();
|
|
2975
|
+
|
|
2976
|
+
if (jsonOutput) {
|
|
2977
|
+
console.log(JSON.stringify(report, null, 2));
|
|
2978
|
+
process.exit(report.summary.totalIssues > 0 ? 1 : 0);
|
|
2979
|
+
return;
|
|
2980
|
+
}
|
|
2981
|
+
|
|
2982
|
+
// Pretty-print report
|
|
2983
|
+
console.log(`\nNetwork Consistency Report`);
|
|
2984
|
+
console.log(`${'='.repeat(50)}`);
|
|
2985
|
+
console.log(`Checked at: ${report.checkedAt}`);
|
|
2986
|
+
console.log(`Authoritative URL: ${report.authoritativeUrl}`);
|
|
2987
|
+
console.log(
|
|
2988
|
+
`Coverage: ${(report.coverage * 100).toFixed(1)}% (${report.summary.validPointers}/${report.summary.totalDomains})`
|
|
2989
|
+
);
|
|
2990
|
+
|
|
2991
|
+
if (report.schemaErrors.length > 0) {
|
|
2992
|
+
console.log(`\nSchema Errors (${report.schemaErrors.length}):`);
|
|
2993
|
+
for (const err of report.schemaErrors) {
|
|
2994
|
+
console.log(` - ${err.field}: ${err.message}`);
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2997
|
+
|
|
2998
|
+
if (report.agentHealth.length > 0) {
|
|
2999
|
+
console.log(`\nAgent Health:`);
|
|
3000
|
+
for (const agent of report.agentHealth) {
|
|
3001
|
+
const status = agent.reachable ? 'OK' : 'UNREACHABLE';
|
|
3002
|
+
const detail = agent.error ? ` (${agent.error})` : agent.statusCode ? ` (HTTP ${agent.statusCode})` : '';
|
|
3003
|
+
console.log(` ${status} ${agent.url}${detail}`);
|
|
3004
|
+
}
|
|
3005
|
+
}
|
|
3006
|
+
|
|
3007
|
+
if (report.missingPointers.length > 0) {
|
|
3008
|
+
console.log(`\nMissing Pointers (${report.missingPointers.length}):`);
|
|
3009
|
+
for (const p of report.missingPointers) {
|
|
3010
|
+
console.log(` - ${p.domain}: ${p.error}`);
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
|
|
3014
|
+
if (report.stalePointers.length > 0) {
|
|
3015
|
+
console.log(`\nStale Pointers (${report.stalePointers.length}):`);
|
|
3016
|
+
for (const p of report.stalePointers) {
|
|
3017
|
+
console.log(` - ${p.domain}: points to ${p.pointerUrl}, expected ${p.expectedUrl}`);
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
|
|
3021
|
+
if (report.orphanedPointers.length > 0) {
|
|
3022
|
+
console.log(`\nOrphaned Pointers (${report.orphanedPointers.length}):`);
|
|
3023
|
+
for (const p of report.orphanedPointers) {
|
|
3024
|
+
console.log(` - ${p.domain}: points to ${p.pointerUrl} but not listed in properties`);
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
3027
|
+
|
|
3028
|
+
if (report.summary.totalIssues === 0) {
|
|
3029
|
+
console.log(`\nAll checks passed.`);
|
|
3030
|
+
} else {
|
|
3031
|
+
console.log(`\n${report.summary.totalIssues} issue(s) found.`);
|
|
3032
|
+
}
|
|
3033
|
+
|
|
3034
|
+
process.exit(report.summary.totalIssues > 0 ? 1 : 0);
|
|
3035
|
+
} catch (error) {
|
|
3036
|
+
console.error(`ERROR: ${error.message}`);
|
|
3037
|
+
process.exit(2);
|
|
3038
|
+
}
|
|
3039
|
+
}
|
|
3040
|
+
|
|
3041
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
3042
|
+
// diagnose-auth command
|
|
3043
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
3044
|
+
|
|
3045
|
+
async function handleDiagnoseAuthCommand(args) {
|
|
3046
|
+
if (args.includes('--help') || args.includes('-h') || args.length === 0) {
|
|
3047
|
+
console.log(`
|
|
3048
|
+
Diagnose the OAuth handshake for a saved agent or URL.
|
|
3049
|
+
|
|
3050
|
+
Use this when: tools/call returns 401/403; a saved token has stopped working;
|
|
3051
|
+
a refresh succeeds but the next call fails; or you're not sure whether the
|
|
3052
|
+
agent or your client is at fault.
|
|
3053
|
+
|
|
3054
|
+
Probes the RFC 9728 protected-resource metadata, RFC 8414 auth-server metadata,
|
|
3055
|
+
decodes the saved access token, optionally attempts a refresh with resource
|
|
3056
|
+
indicator (RFC 8707), and calls tools/list + a tool on the agent. Reports
|
|
3057
|
+
ranked hypotheses about what's likely wrong.
|
|
3058
|
+
|
|
3059
|
+
USAGE:
|
|
3060
|
+
adcp diagnose-auth <alias|url> [options]
|
|
3061
|
+
|
|
3062
|
+
OPTIONS:
|
|
3063
|
+
--json Emit the full structured report as JSON
|
|
3064
|
+
--allow-http Allow http:// and private-IP targets (dev loops only)
|
|
3065
|
+
--skip-refresh Do not attempt a token refresh
|
|
3066
|
+
--skip-tool-call Do not attempt the authenticated tool_call probe
|
|
3067
|
+
--tool NAME Tool to exercise in the tool_call probe (default: get_products)
|
|
3068
|
+
--include-tokens Include raw access/refresh tokens in JSON output (default: redacted)
|
|
3069
|
+
--help, -h Show this help
|
|
3070
|
+
|
|
3071
|
+
EXIT CODES:
|
|
3072
|
+
0 No likely failures identified
|
|
3073
|
+
1 At least one hypothesis flagged as 'likely'
|
|
3074
|
+
2 Usage error (missing arg, invalid flag)
|
|
3075
|
+
|
|
3076
|
+
EXAMPLES:
|
|
3077
|
+
adcp diagnose-auth myagent
|
|
3078
|
+
adcp diagnose-auth myagent --json > diagnosis.json
|
|
3079
|
+
adcp diagnose-auth https://agent.example.com/mcp --allow-http
|
|
3080
|
+
`);
|
|
3081
|
+
return;
|
|
3082
|
+
}
|
|
3083
|
+
|
|
3084
|
+
const jsonOutput = args.includes('--json');
|
|
3085
|
+
const allowPrivateIp = args.includes('--allow-http');
|
|
3086
|
+
const skipRefresh = args.includes('--skip-refresh');
|
|
3087
|
+
const skipToolCall = args.includes('--skip-tool-call');
|
|
3088
|
+
const includeTokens = args.includes('--include-tokens');
|
|
3089
|
+
const toolIndex = args.indexOf('--tool');
|
|
3090
|
+
let probeToolName;
|
|
3091
|
+
if (toolIndex !== -1) {
|
|
3092
|
+
const value = args[toolIndex + 1];
|
|
3093
|
+
if (!value || value.startsWith('--')) {
|
|
3094
|
+
console.error('ERROR: --tool requires a tool name\n');
|
|
3095
|
+
process.exit(2);
|
|
3096
|
+
}
|
|
3097
|
+
probeToolName = value;
|
|
3098
|
+
}
|
|
3099
|
+
|
|
3100
|
+
const positional = args.filter((a, i) => {
|
|
3101
|
+
if (a.startsWith('--')) return false;
|
|
3102
|
+
if (i > 0 && args[i - 1] === '--tool') return false;
|
|
3103
|
+
return true;
|
|
3104
|
+
});
|
|
3105
|
+
const target = positional[0];
|
|
3106
|
+
if (!target) {
|
|
3107
|
+
console.error('ERROR: diagnose-auth requires an alias or URL\n');
|
|
3108
|
+
console.error('Run "adcp diagnose-auth --help" for usage');
|
|
3109
|
+
process.exit(2);
|
|
3110
|
+
}
|
|
3111
|
+
|
|
3112
|
+
// Resolve the agent config (alias, built-in, or bare URL). Protocol is fixed
|
|
3113
|
+
// to MCP because diagnose-auth exercises MCP-specific wire behavior.
|
|
3114
|
+
let agentConfig;
|
|
3115
|
+
if (BUILT_IN_AGENTS[target]) {
|
|
3116
|
+
const builtIn = BUILT_IN_AGENTS[target];
|
|
3117
|
+
agentConfig = {
|
|
3118
|
+
id: target,
|
|
3119
|
+
name: target,
|
|
3120
|
+
agent_uri: builtIn.url,
|
|
3121
|
+
protocol: builtIn.protocol || 'mcp',
|
|
3122
|
+
auth_token: builtIn.auth_token,
|
|
3123
|
+
};
|
|
3124
|
+
} else if (isAlias(target)) {
|
|
3125
|
+
const saved = getAgent(target);
|
|
3126
|
+
agentConfig = {
|
|
3127
|
+
id: target,
|
|
3128
|
+
name: target,
|
|
3129
|
+
agent_uri: saved.url,
|
|
3130
|
+
protocol: saved.protocol || 'mcp',
|
|
3131
|
+
oauth_tokens: saved.oauth_tokens,
|
|
3132
|
+
oauth_client: saved.oauth_client,
|
|
3133
|
+
auth_token: saved.auth_token,
|
|
3134
|
+
};
|
|
3135
|
+
} else if (target.startsWith('http://') || target.startsWith('https://')) {
|
|
3136
|
+
agentConfig = {
|
|
3137
|
+
id: target,
|
|
3138
|
+
name: target,
|
|
3139
|
+
agent_uri: target,
|
|
3140
|
+
protocol: 'mcp',
|
|
3141
|
+
};
|
|
3142
|
+
} else {
|
|
3143
|
+
console.error(`ERROR: '${target}' is not a valid alias or URL\n`);
|
|
3144
|
+
process.exit(2);
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3147
|
+
const { runAuthDiagnosis } = require('../dist/lib/auth/oauth/index.js');
|
|
3148
|
+
const report = await runAuthDiagnosis(agentConfig, {
|
|
3149
|
+
allowPrivateIp,
|
|
3150
|
+
skipRefresh,
|
|
3151
|
+
skipToolCall,
|
|
3152
|
+
probeToolName,
|
|
3153
|
+
includeTokens,
|
|
3154
|
+
});
|
|
3155
|
+
|
|
3156
|
+
if (jsonOutput) {
|
|
3157
|
+
console.log(JSON.stringify(report, null, 2));
|
|
3158
|
+
process.exit(hasLikelyHypothesis(report) ? 1 : 0);
|
|
3159
|
+
}
|
|
3160
|
+
|
|
3161
|
+
renderDiagnosisReport(report);
|
|
3162
|
+
process.exit(hasLikelyHypothesis(report) ? 1 : 0);
|
|
3163
|
+
}
|
|
3164
|
+
|
|
3165
|
+
function hasLikelyHypothesis(report) {
|
|
3166
|
+
return report.hypotheses.some(h => h.verdict === 'likely');
|
|
3167
|
+
}
|
|
3168
|
+
|
|
3169
|
+
const STEP_LABELS = {
|
|
3170
|
+
probe_protected_resource_metadata: 'RFC 9728 protected-resource metadata',
|
|
3171
|
+
probe_authorization_server_metadata: 'RFC 8414 authorization-server metadata',
|
|
3172
|
+
decode_current_token: 'Decode current access token',
|
|
3173
|
+
token_refresh_attempt: 'Refresh grant (RFC 8707 `resource`)',
|
|
3174
|
+
decode_refreshed_token: 'Decode refreshed access token',
|
|
3175
|
+
list_tools_probe: 'Unauthenticated tools/list probe',
|
|
3176
|
+
tool_call_probe: 'Authenticated tool_call probe',
|
|
3177
|
+
};
|
|
3178
|
+
|
|
3179
|
+
function renderDiagnosisReport(report) {
|
|
3180
|
+
console.log(`\nš OAuth Diagnosis ā ${report.agentUrl}`);
|
|
3181
|
+
if (report.aliasId && report.aliasId !== report.agentUrl) {
|
|
3182
|
+
console.log(` Alias: ${report.aliasId}`);
|
|
3183
|
+
}
|
|
3184
|
+
console.log(` Generated: ${report.generatedAt}\n`);
|
|
3185
|
+
|
|
3186
|
+
console.log(`WIRE STEPS`);
|
|
3187
|
+
for (const step of report.steps) {
|
|
3188
|
+
const label = STEP_LABELS[step.name] || step.name;
|
|
3189
|
+
const prefix = ` ⢠${label}`;
|
|
3190
|
+
if (step.error) {
|
|
3191
|
+
console.log(`${prefix} ā³ skipped: ${step.error}`);
|
|
3192
|
+
continue;
|
|
3193
|
+
}
|
|
3194
|
+
if (step.http) {
|
|
3195
|
+
const statusBadge = step.http.status === 0 ? 'ERR' : `HTTP ${step.http.status}`;
|
|
3196
|
+
console.log(`${prefix} ā³ ${step.http.method} ${step.http.url} ${statusBadge}`);
|
|
3197
|
+
if (step.http.error) console.log(` error: ${step.http.error}`);
|
|
3198
|
+
const wwwAuth = step.http.headers['www-authenticate'];
|
|
3199
|
+
if (wwwAuth) console.log(` WWW-Authenticate: ${wwwAuth}`);
|
|
3200
|
+
} else if (step.decodedToken) {
|
|
3201
|
+
const audClaim = step.decodedToken.claims.aud;
|
|
3202
|
+
const aud = audClaim === undefined ? '(missing)' : JSON.stringify(audClaim);
|
|
3203
|
+
const iss = step.decodedToken.claims.iss ?? '(missing)';
|
|
3204
|
+
const exp = step.decodedToken.claims.exp;
|
|
3205
|
+
const expStr = exp ? new Date(exp * 1000).toISOString() : '(missing)';
|
|
3206
|
+
console.log(`${prefix} ā³ JWT: iss=${iss} aud=${aud} exp=${expStr}`);
|
|
3207
|
+
} else {
|
|
3208
|
+
console.log(`${prefix} ā³ (no token / opaque token)`);
|
|
3209
|
+
}
|
|
3210
|
+
if (step.notes) {
|
|
3211
|
+
for (const note of step.notes) console.log(` note: ${note}`);
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
|
|
3215
|
+
console.log(`\nHYPOTHESES (ranked)`);
|
|
3216
|
+
for (const h of report.hypotheses) {
|
|
3217
|
+
const badge = formatVerdict(h.verdict);
|
|
3218
|
+
const id = h.id.padEnd(3);
|
|
3219
|
+
console.log(`\n ${id} ${badge} ${h.title}`);
|
|
3220
|
+
console.log(` ${h.summary}`);
|
|
3221
|
+
for (const ev of h.evidence) console.log(` Ā· ${ev}`);
|
|
3222
|
+
}
|
|
3223
|
+
|
|
3224
|
+
const likely = report.hypotheses.filter(h => h.verdict === 'likely');
|
|
3225
|
+
if (likely.length === 0) {
|
|
3226
|
+
console.log(`\nā
No likely failures identified.\n`);
|
|
3227
|
+
} else {
|
|
3228
|
+
console.log(`\nā ļø ${likely.length} likely issue(s) identified.\n`);
|
|
3229
|
+
console.log(`NEXT STEPS`);
|
|
3230
|
+
for (const h of likely) {
|
|
3231
|
+
const fix = h.evidence.find(e => e.startsWith('Fix:'));
|
|
3232
|
+
if (fix) {
|
|
3233
|
+
console.log(` ${h.id}: ${fix.replace(/^Fix:\s*/, '')}`);
|
|
3234
|
+
} else {
|
|
3235
|
+
console.log(` ${h.id}: ${h.summary}`);
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
console.log();
|
|
3239
|
+
}
|
|
3240
|
+
}
|
|
3241
|
+
|
|
3242
|
+
function formatVerdict(verdict) {
|
|
3243
|
+
switch (verdict) {
|
|
3244
|
+
case 'likely':
|
|
3245
|
+
return '[likely] ';
|
|
3246
|
+
case 'possible':
|
|
3247
|
+
return '[possible] ';
|
|
3248
|
+
case 'ruled_out':
|
|
3249
|
+
return '[ruled-out]';
|
|
3250
|
+
default:
|
|
3251
|
+
return '[n/a] ';
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
|
|
3255
|
+
async function main() {
|
|
3256
|
+
const args = process.argv.slice(2);
|
|
3257
|
+
|
|
3258
|
+
// `--version` / `-v` is handled before subcommands and before the
|
|
3259
|
+
// staleness probe ā it should be a fast, side-effect-free identity
|
|
3260
|
+
// check. Adds a (compat shim) note when invoked through @adcp/client
|
|
3261
|
+
// so users know which package they're actually running. The shim sets
|
|
3262
|
+
// ADCP_INVOKED_VIA_SHIM=1 in its bin wrapper.
|
|
3263
|
+
if (args[0] === '--version' || args[0] === '-v') {
|
|
3264
|
+
const viaShim = process.env.ADCP_INVOKED_VIA_SHIM === '1';
|
|
3265
|
+
process.stdout.write(`@adcp/sdk@${LIBRARY_VERSION}${viaShim ? ' (invoked via @adcp/client compat shim)' : ''}\n`);
|
|
3266
|
+
process.exit(0);
|
|
3267
|
+
}
|
|
3268
|
+
|
|
3269
|
+
// Fire a staleness check in the background so a months-old cached
|
|
3270
|
+
// CLI doesn't run silently. Fails silent on any network/FS hiccup;
|
|
3271
|
+
// skipped in CI, non-TTY, --json, and when ADCP_SKIP_VERSION_CHECK=1.
|
|
3272
|
+
scheduleVersionCheck(LIBRARY_VERSION);
|
|
3273
|
+
|
|
3274
|
+
// Global: suppress the v2-sunset warning before any subcommand runs.
|
|
3275
|
+
// v2 went unsupported on 2026-04-20 (AdCP 3.0 GA, adcp#2220) ā the library
|
|
3276
|
+
// warns whenever an agent advertises v2 capabilities. The flag is for
|
|
3277
|
+
// legacy holdouts who know what they're doing.
|
|
3278
|
+
if (args.includes('--allow-v2')) {
|
|
3279
|
+
process.env.ADCP_ALLOW_V2 = '1';
|
|
3280
|
+
}
|
|
3281
|
+
|
|
3282
|
+
// Handle subcommands before global --help so their own --help works
|
|
3283
|
+
if (args[0] === 'registry') {
|
|
3284
|
+
const code = await handleRegistryCommand(args.slice(1));
|
|
3285
|
+
process.exit(code);
|
|
3286
|
+
}
|
|
3287
|
+
|
|
3288
|
+
if (args[0] === 'test') {
|
|
3289
|
+
await handleTestCommand(args.slice(1));
|
|
3290
|
+
return;
|
|
3291
|
+
}
|
|
3292
|
+
|
|
3293
|
+
if (args[0] === 'comply') {
|
|
3294
|
+
await handleComplyCommand(args.slice(1));
|
|
3295
|
+
return;
|
|
3296
|
+
}
|
|
3297
|
+
|
|
3298
|
+
if (args[0] === 'storyboard') {
|
|
3299
|
+
await handleStoryboardCommand(args.slice(1));
|
|
3300
|
+
return;
|
|
3301
|
+
}
|
|
3302
|
+
|
|
3303
|
+
if (args[0] === 'check-network') {
|
|
3304
|
+
await handleCheckNetworkCommand(args.slice(1));
|
|
3305
|
+
return;
|
|
3306
|
+
}
|
|
3307
|
+
|
|
3308
|
+
if (args[0] === 'signing') {
|
|
3309
|
+
const { handleSigningCommand } = require('./adcp-signing.js');
|
|
3310
|
+
await handleSigningCommand(args.slice(1));
|
|
3311
|
+
return;
|
|
3312
|
+
}
|
|
3313
|
+
|
|
3314
|
+
if (args[0] === 'grade') {
|
|
3315
|
+
const { handleGradeCommand } = require('./adcp-grade.js');
|
|
3316
|
+
await handleGradeCommand(args.slice(1));
|
|
3317
|
+
return;
|
|
3318
|
+
}
|
|
3319
|
+
|
|
3320
|
+
if (args[0] === 'fuzz') {
|
|
3321
|
+
const { handleFuzzCommand } = require('./adcp-fuzz.js');
|
|
3322
|
+
await handleFuzzCommand(args.slice(1));
|
|
3323
|
+
return;
|
|
3324
|
+
}
|
|
3325
|
+
|
|
3326
|
+
if (args[0] === 'diagnose-auth') {
|
|
3327
|
+
await handleDiagnoseAuthCommand(args.slice(1));
|
|
3328
|
+
return;
|
|
3329
|
+
}
|
|
3330
|
+
|
|
3331
|
+
// `adcp diagnose oauth <alias>` ā subcommand alias for `adcp diagnose-auth`.
|
|
3332
|
+
// The hyphenated form remains canonical (historical + shorter to type); the
|
|
3333
|
+
// subcommand form matches the `<noun> <verb>` convention some docs and
|
|
3334
|
+
// tooling expect.
|
|
3335
|
+
if (args[0] === 'diagnose' && args[1] === 'oauth') {
|
|
3336
|
+
await handleDiagnoseAuthCommand(args.slice(2));
|
|
3337
|
+
return;
|
|
3338
|
+
}
|
|
3339
|
+
|
|
3340
|
+
// Handle help ā guarded so `--save-auth --help` falls through to the
|
|
3341
|
+
// subcommand's dedicated help block below (that flow has its own --help
|
|
3342
|
+
// handler at the top).
|
|
3343
|
+
if (args[0] !== '--save-auth' && (args.includes('--help') || args.includes('-h') || args.length === 0)) {
|
|
3344
|
+
printUsage();
|
|
3345
|
+
process.exit(0);
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
// Handle agent management commands
|
|
3349
|
+
if (args[0] === '--save-auth') {
|
|
3350
|
+
// `adcp --save-auth --help` / `-h`: dedicated subcommand help. Kept up
|
|
3351
|
+
// top so it short-circuits before the parser rejects a missing alias.
|
|
3352
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
3353
|
+
console.log(`
|
|
3354
|
+
adcp --save-auth <alias> <url> [protocol] [auth flags]
|
|
3355
|
+
|
|
3356
|
+
Save an agent URL under an alias in ~/.adcp/config.json so future commands
|
|
3357
|
+
can use the alias in place of the URL.
|
|
3358
|
+
|
|
3359
|
+
AUTH METHODS (pick one):
|
|
3360
|
+
Static bearer token:
|
|
3361
|
+
--auth <token> Pre-issued bearer token
|
|
3362
|
+
--no-auth Agent requires no auth
|
|
3363
|
+
|
|
3364
|
+
Browser OAuth (authorization code flow):
|
|
3365
|
+
--oauth Opens a browser to authorize; stores tokens
|
|
3366
|
+
so the SDK can refresh via refresh_token.
|
|
3367
|
+
|
|
3368
|
+
OAuth client credentials (machine-to-machine, RFC 6749 §4.4):
|
|
3369
|
+
--client-id <value> Literal client id
|
|
3370
|
+
--client-id-env <VAR> Env var holding the client id
|
|
3371
|
+
--client-secret <value> Literal client secret (stored in config 0600)
|
|
3372
|
+
--client-secret-env <VAR> Env var holding the secret (stored as
|
|
3373
|
+
'$ENV:VAR' ā nothing sensitive on disk)
|
|
3374
|
+
--scope <scope> OAuth scope, if required
|
|
3375
|
+
--oauth-token-url <url> Optional: AS token endpoint. Omit to discover
|
|
3376
|
+
from the agent's RFC 9728 metadata + RFC 8414
|
|
3377
|
+
authorization-server metadata.
|
|
3378
|
+
--oauth-auth-method basic|body
|
|
3379
|
+
Where to send creds on the token request.
|
|
3380
|
+
Default: basic (RFC 6749 §2.3.1). Some AS
|
|
3381
|
+
deployments only accept body.
|
|
3382
|
+
|
|
3383
|
+
EXAMPLES:
|
|
3384
|
+
# Static bearer (local dev)
|
|
3385
|
+
adcp --save-auth mine https://agent.example.com/mcp --auth AB12
|
|
3386
|
+
|
|
3387
|
+
# Browser OAuth
|
|
3388
|
+
adcp --save-auth mine https://agent.example.com/mcp --oauth
|
|
3389
|
+
|
|
3390
|
+
# Client credentials ā token endpoint discovered from the agent
|
|
3391
|
+
adcp --save-auth mine https://agent.example.com/mcp \\
|
|
3392
|
+
--client-id abc123 --client-secret xyz789 --scope adcp
|
|
3393
|
+
|
|
3394
|
+
# Client credentials with env-var indirection (CI)
|
|
3395
|
+
adcp --save-auth mine https://agent.example.com/mcp \\
|
|
3396
|
+
--client-id-env ADCP_CLIENT_ID --client-secret-env ADCP_CLIENT_SECRET
|
|
3397
|
+
|
|
3398
|
+
# Override the discovered token endpoint
|
|
3399
|
+
adcp --save-auth mine https://agent.example.com/mcp \\
|
|
3400
|
+
--oauth-token-url https://auth.example.com/oauth/token \\
|
|
3401
|
+
--client-id abc123 --client-secret xyz789
|
|
3402
|
+
|
|
3403
|
+
OTHER FLAGS:
|
|
3404
|
+
--dry-run Print the resolved plan (discovered token
|
|
3405
|
+
endpoint, scope, secret source) and exit
|
|
3406
|
+
without exchanging tokens or writing the
|
|
3407
|
+
config. Client-credentials only.
|
|
3408
|
+
|
|
3409
|
+
EXIT CODES:
|
|
3410
|
+
0 success
|
|
3411
|
+
1 runtime failure (discovery, exchange, network)
|
|
3412
|
+
2 usage / validation error
|
|
3413
|
+
|
|
3414
|
+
Secret storage: ~/.adcp/config.json is written with mode 0600. Treat it as
|
|
3415
|
+
credential material ā never sync or commit.
|
|
3416
|
+
`);
|
|
3417
|
+
process.exit(0);
|
|
3418
|
+
}
|
|
3419
|
+
|
|
3420
|
+
// Extract value-bearing flags and the positional args in one pass so we
|
|
3421
|
+
// don't have to reason about interleaving. Flags that take a value
|
|
3422
|
+
// consume the next token; boolean flags consume only themselves.
|
|
3423
|
+
const valueFlags = new Set([
|
|
3424
|
+
'--auth',
|
|
3425
|
+
'--oauth-token-url',
|
|
3426
|
+
'--client-id',
|
|
3427
|
+
'--client-id-env',
|
|
3428
|
+
'--client-secret',
|
|
3429
|
+
'--client-secret-env',
|
|
3430
|
+
'--scope',
|
|
3431
|
+
'--oauth-auth-method',
|
|
3432
|
+
]);
|
|
3433
|
+
const booleanFlags = new Set(['--no-auth', '--oauth', '--dry-run']);
|
|
3434
|
+
const parsedFlags = {};
|
|
3435
|
+
const positional = [];
|
|
3436
|
+
{
|
|
3437
|
+
const rest = args.slice(1);
|
|
3438
|
+
for (let i = 0; i < rest.length; i++) {
|
|
3439
|
+
const tok = rest[i];
|
|
3440
|
+
if (valueFlags.has(tok)) {
|
|
3441
|
+
const val = rest[i + 1];
|
|
3442
|
+
if (val === undefined || val.startsWith('--')) {
|
|
3443
|
+
console.error(`ERROR: ${tok} requires a value\n`);
|
|
3444
|
+
process.exit(2);
|
|
3445
|
+
}
|
|
3446
|
+
parsedFlags[tok] = val;
|
|
3447
|
+
i++;
|
|
3448
|
+
} else if (booleanFlags.has(tok)) {
|
|
3449
|
+
parsedFlags[tok] = true;
|
|
3450
|
+
} else {
|
|
3451
|
+
positional.push(tok);
|
|
3452
|
+
}
|
|
3453
|
+
}
|
|
3454
|
+
}
|
|
3455
|
+
|
|
3456
|
+
const providedAuthToken = parsedFlags['--auth'] ?? null;
|
|
3457
|
+
const noAuthFlag = parsedFlags['--no-auth'] === true;
|
|
3458
|
+
const oauthFlag = parsedFlags['--oauth'] === true;
|
|
3459
|
+
const dryRunFlag = parsedFlags['--dry-run'] === true;
|
|
3460
|
+
const oauthEndpoint = parsedFlags['--oauth-token-url'] ?? null;
|
|
3461
|
+
const clientId = parsedFlags['--client-id'] ?? null;
|
|
3462
|
+
const clientIdEnv = parsedFlags['--client-id-env'] ?? null;
|
|
3463
|
+
const clientSecret = parsedFlags['--client-secret'] ?? null;
|
|
3464
|
+
const clientSecretEnv = parsedFlags['--client-secret-env'] ?? null;
|
|
3465
|
+
const scope = parsedFlags['--scope'] ?? null;
|
|
3466
|
+
const oauthAuthMethod = parsedFlags['--oauth-auth-method'] ?? null;
|
|
3467
|
+
const clientCredentialsRequested =
|
|
3468
|
+
oauthEndpoint !== null ||
|
|
3469
|
+
clientId !== null ||
|
|
3470
|
+
clientIdEnv !== null ||
|
|
3471
|
+
clientSecret !== null ||
|
|
3472
|
+
clientSecretEnv !== null;
|
|
3473
|
+
|
|
3474
|
+
let alias = positional[0];
|
|
3475
|
+
let url = positional[1] || null;
|
|
3476
|
+
const protocol = positional[2] || null;
|
|
3477
|
+
|
|
3478
|
+
if (!alias) {
|
|
3479
|
+
console.error('ERROR: --save-auth requires an alias\n');
|
|
3480
|
+
console.error(
|
|
3481
|
+
'Usage: adcp --save-auth <alias> [url] [protocol] [--auth token | --no-auth | --oauth | --client-id ... --client-secret ...]\n'
|
|
3482
|
+
);
|
|
3483
|
+
console.error('Example: adcp --save-auth myagent https://agent.example.com --auth your_token\n');
|
|
3484
|
+
console.error(' adcp --save-auth myagent https://oauth-server.com/mcp --oauth\n');
|
|
3485
|
+
console.error(' adcp --save-auth myagent https://agent.example.com \\\n');
|
|
3486
|
+
console.error(' --client-id myid --client-secret mysecret --scope adcp\n');
|
|
3487
|
+
console.error(' (token endpoint discovered from the agent URL ā see --save-auth --help)\n');
|
|
3488
|
+
process.exit(2);
|
|
3489
|
+
}
|
|
3490
|
+
|
|
3491
|
+
// Check if first arg looks like a URL (common mistake)
|
|
3492
|
+
if (alias.startsWith('http://') || alias.startsWith('https://')) {
|
|
3493
|
+
console.error('\nā ļø It looks like you provided a URL without an alias.\n');
|
|
3494
|
+
console.error('The --save-auth command requires an alias name first:\n');
|
|
3495
|
+
console.error(` adcp --save-auth <alias> <url>\n`);
|
|
3496
|
+
console.error('Example:\n');
|
|
3497
|
+
console.error(` adcp --save-auth myagent ${alias}\n`);
|
|
3498
|
+
process.exit(2);
|
|
3499
|
+
}
|
|
3500
|
+
|
|
3501
|
+
// Mutex: --auth and --no-auth are incompatible with each other and with
|
|
3502
|
+
// any OAuth mode. Browser --oauth is incompatible with client-credentials
|
|
3503
|
+
// flags (they're two different OAuth flows). `--oauth` with credentials
|
|
3504
|
+
// is allowed ā harmless redundancy since credentials already imply M2M.
|
|
3505
|
+
if (providedAuthToken !== null && (noAuthFlag || oauthFlag || clientCredentialsRequested)) {
|
|
3506
|
+
console.error('ERROR: --auth cannot be combined with --no-auth, --oauth, or client-credentials flags\n');
|
|
3507
|
+
process.exit(2);
|
|
3508
|
+
}
|
|
3509
|
+
if (noAuthFlag && (oauthFlag || clientCredentialsRequested)) {
|
|
3510
|
+
console.error('ERROR: --no-auth cannot be combined with --oauth or client-credentials flags\n');
|
|
3511
|
+
process.exit(2);
|
|
3512
|
+
}
|
|
3513
|
+
if (oauthFlag && clientCredentialsRequested && !clientId && !clientIdEnv && !clientSecret && !clientSecretEnv) {
|
|
3514
|
+
// Only `--oauth-token-url` (no actual credentials) alongside `--oauth`
|
|
3515
|
+
// is ambiguous ā a token URL isn't useful for the browser flow.
|
|
3516
|
+
console.error(
|
|
3517
|
+
'ERROR: --oauth (browser) cannot be combined with --oauth-token-url; omit --oauth or supply --client-id / --client-secret\n'
|
|
3518
|
+
);
|
|
3519
|
+
process.exit(2);
|
|
3520
|
+
}
|
|
3521
|
+
|
|
3522
|
+
if (oauthAuthMethod !== null && !clientCredentialsRequested) {
|
|
3523
|
+
console.error('ERROR: --oauth-auth-method is only valid with client credentials\n');
|
|
3524
|
+
process.exit(2);
|
|
3525
|
+
}
|
|
3526
|
+
if (oauthAuthMethod !== null && oauthAuthMethod !== 'basic' && oauthAuthMethod !== 'body') {
|
|
3527
|
+
console.error("ERROR: --oauth-auth-method must be 'basic' or 'body'\n");
|
|
3528
|
+
process.exit(2);
|
|
3529
|
+
}
|
|
3530
|
+
|
|
3531
|
+
// Handle client credentials save flow (RFC 6749 §4.4 ā M2M OAuth)
|
|
3532
|
+
if (clientCredentialsRequested) {
|
|
3533
|
+
if (!url) {
|
|
3534
|
+
console.error('ERROR: client credentials require a URL\n');
|
|
3535
|
+
console.error(
|
|
3536
|
+
'Usage: adcp --save-auth <alias> <url> --client-id ID --client-secret SECRET [--scope adcp]\n' +
|
|
3537
|
+
' (token endpoint is discovered from the agent URL; pass --oauth-token-url to override)\n'
|
|
3538
|
+
);
|
|
3539
|
+
process.exit(2);
|
|
3540
|
+
}
|
|
3541
|
+
|
|
3542
|
+
// Arg-shape validation first ā these are pure flag checks, no reason
|
|
3543
|
+
// to do network discovery before we know the inputs even compose.
|
|
3544
|
+
if (clientId !== null && clientIdEnv !== null) {
|
|
3545
|
+
console.error('ERROR: Cannot combine --client-id and --client-id-env ā pick one\n');
|
|
3546
|
+
process.exit(2);
|
|
3547
|
+
}
|
|
3548
|
+
if (clientSecret !== null && clientSecretEnv !== null) {
|
|
3549
|
+
console.error('ERROR: Cannot combine --client-secret and --client-secret-env ā pick one\n');
|
|
3550
|
+
process.exit(2);
|
|
3551
|
+
}
|
|
3552
|
+
if (clientId === null && clientIdEnv === null) {
|
|
3553
|
+
console.error('ERROR: --client-id or --client-id-env is required for client credentials\n');
|
|
3554
|
+
process.exit(2);
|
|
3555
|
+
}
|
|
3556
|
+
if (clientSecret === null && clientSecretEnv === null) {
|
|
3557
|
+
console.error('ERROR: --client-secret or --client-secret-env is required for client credentials\n');
|
|
3558
|
+
process.exit(2);
|
|
3559
|
+
}
|
|
3560
|
+
|
|
3561
|
+
// Discover the token endpoint from the agent if --oauth-token-url was
|
|
3562
|
+
// omitted. Walks the RFC 9728 protected-resource metadata, RFC 8414
|
|
3563
|
+
// authorization-server metadata, and OIDC Discovery 1.0 fallback
|
|
3564
|
+
// (same probe that powers `adcp diagnose-auth`). `allowPrivateIp:
|
|
3565
|
+
// true` matches the CLI's operator-driven trust model (the operator
|
|
3566
|
+
// typed this URL).
|
|
3567
|
+
let resolvedOauthEndpoint = oauthEndpoint;
|
|
3568
|
+
let discoveredRequirements = null;
|
|
3569
|
+
if (!resolvedOauthEndpoint) {
|
|
3570
|
+
console.log(`\nš Discovering OAuth token endpoint from ${url}...`);
|
|
3571
|
+
console.log(' Probing /.well-known/oauth-protected-resource ā authorization-server metadata');
|
|
3572
|
+
try {
|
|
3573
|
+
discoveredRequirements = await discoverAuthorizationRequirements(url, { allowPrivateIp: true });
|
|
3574
|
+
if (discoveredRequirements && discoveredRequirements.tokenEndpoint) {
|
|
3575
|
+
resolvedOauthEndpoint = discoveredRequirements.tokenEndpoint;
|
|
3576
|
+
// Print only the host so the operator can confirm the discovered
|
|
3577
|
+
// realm without exposing query-string or path components that
|
|
3578
|
+
// sometimes carry tenant identifiers. CodeQL flags this site as
|
|
3579
|
+
// clear-text logging when it sees the full URL flowing from the
|
|
3580
|
+
// discovery probe.
|
|
3581
|
+
const endpointHost = (() => {
|
|
3582
|
+
try {
|
|
3583
|
+
return new URL(resolvedOauthEndpoint).host;
|
|
3584
|
+
} catch {
|
|
3585
|
+
return '<unparseable>';
|
|
3586
|
+
}
|
|
3587
|
+
})();
|
|
3588
|
+
console.log(` Found token endpoint host: ${endpointHost}`);
|
|
3589
|
+
if (discoveredRequirements.authorizationServer) {
|
|
3590
|
+
console.log(` Authorization server: ${discoveredRequirements.authorizationServer}`);
|
|
3591
|
+
}
|
|
3592
|
+
// PRM is allowed to list multiple authorization_servers. We take
|
|
3593
|
+
// [0] per RFC 9728 §3.3 preference ordering ā warn the operator
|
|
3594
|
+
// when there's more than one so a silently-wrong tenant surfaces
|
|
3595
|
+
// during debugging rather than at runtime.
|
|
3596
|
+
if (
|
|
3597
|
+
Array.isArray(discoveredRequirements.authorizationServers) &&
|
|
3598
|
+
discoveredRequirements.authorizationServers.length > 1
|
|
3599
|
+
) {
|
|
3600
|
+
console.log(
|
|
3601
|
+
` ā ļø Multiple authorization_servers advertised (${discoveredRequirements.authorizationServers.length}); using the first: ${discoveredRequirements.authorizationServers[0]}`
|
|
3602
|
+
);
|
|
3603
|
+
for (const alt of discoveredRequirements.authorizationServers.slice(1)) {
|
|
3604
|
+
console.log(` also: ${alt}`);
|
|
3605
|
+
}
|
|
3606
|
+
}
|
|
3607
|
+
if (discoveredRequirements.metadataSource === 'openid-configuration') {
|
|
3608
|
+
console.log(' (metadata via OpenID Connect Discovery fallback)');
|
|
3609
|
+
}
|
|
3610
|
+
} else {
|
|
3611
|
+
console.error('\nā Could not discover an OAuth token endpoint from the agent.\n');
|
|
3612
|
+
console.error(' The agent did not advertise RFC 9728 protected-resource metadata, or');
|
|
3613
|
+
console.error(' its authorization server metadata did not include a token_endpoint.\n');
|
|
3614
|
+
console.error(` Run 'adcp diagnose-auth ${url}' to see exactly what the agent advertises.`);
|
|
3615
|
+
console.error(' Or pass --oauth-token-url <url> explicitly.\n');
|
|
3616
|
+
process.exit(1);
|
|
3617
|
+
}
|
|
3618
|
+
} catch (err) {
|
|
3619
|
+
console.error(`\nā Token-endpoint discovery failed while probing the agent: ${err.message}\n`);
|
|
3620
|
+
console.error(` Run 'adcp diagnose-auth ${url}' for details, or pass --oauth-token-url explicitly.\n`);
|
|
3621
|
+
process.exit(1);
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
|
|
3625
|
+
// TLS enforcement. Parse as a URL so `http://localhost.attacker.com`
|
|
3626
|
+
// (which naively `startsWith`ed `http://localhost`) doesn't sneak
|
|
3627
|
+
// through. The library does the same check one call later, but the
|
|
3628
|
+
// CLI error message here is more actionable than the library's.
|
|
3629
|
+
{
|
|
3630
|
+
let parsedTokenUrl;
|
|
3631
|
+
try {
|
|
3632
|
+
parsedTokenUrl = new URL(resolvedOauthEndpoint);
|
|
3633
|
+
} catch {
|
|
3634
|
+
console.error(`ERROR: token endpoint is not a valid URL: ${resolvedOauthEndpoint}\n`);
|
|
3635
|
+
process.exit(2);
|
|
3636
|
+
}
|
|
3637
|
+
const tokenHost = parsedTokenUrl.hostname;
|
|
3638
|
+
const isLoopback =
|
|
3639
|
+
tokenHost === 'localhost' || tokenHost === '127.0.0.1' || tokenHost === '[::1]' || tokenHost === '::1';
|
|
3640
|
+
if (parsedTokenUrl.protocol !== 'https:' && !(parsedTokenUrl.protocol === 'http:' && isLoopback)) {
|
|
3641
|
+
console.error('ERROR: token endpoint must be an HTTPS URL (or http://localhost for testing)\n');
|
|
3642
|
+
process.exit(2);
|
|
3643
|
+
}
|
|
3644
|
+
if (parsedTokenUrl.username || parsedTokenUrl.password) {
|
|
3645
|
+
console.error(
|
|
3646
|
+
'ERROR: token endpoint must not contain user:pass@ userinfo ā use --client-id / --client-secret instead\n'
|
|
3647
|
+
);
|
|
3648
|
+
process.exit(2);
|
|
3649
|
+
}
|
|
3650
|
+
}
|
|
3651
|
+
|
|
3652
|
+
// Pre-check grant_types_supported when the AS published it. RFC 8414
|
|
3653
|
+
// says the field is optional (default: ["authorization_code",
|
|
3654
|
+
// "implicit"]), so absence is "unknown, try your grant"; presence
|
|
3655
|
+
// without `client_credentials` is a hard no and worth bailing on
|
|
3656
|
+
// before we leak the secret to an AS that can't use it.
|
|
3657
|
+
if (
|
|
3658
|
+
discoveredRequirements &&
|
|
3659
|
+
Array.isArray(discoveredRequirements.grantTypesSupported) &&
|
|
3660
|
+
!discoveredRequirements.grantTypesSupported.includes('client_credentials')
|
|
3661
|
+
) {
|
|
3662
|
+
console.error('\nā The discovered authorization server does not support the client_credentials grant.');
|
|
3663
|
+
console.error(
|
|
3664
|
+
` grant_types_supported = [${discoveredRequirements.grantTypesSupported.join(', ')}] at ${discoveredRequirements.authorizationServer}`
|
|
3665
|
+
);
|
|
3666
|
+
console.error(' Register a CC-capable client with the AS, or pass --oauth-token-url to override.\n');
|
|
3667
|
+
process.exit(1);
|
|
3668
|
+
}
|
|
3669
|
+
|
|
3670
|
+
const credentials = {
|
|
3671
|
+
token_endpoint: resolvedOauthEndpoint,
|
|
3672
|
+
client_id: clientIdEnv !== null ? toEnvSecretReference(clientIdEnv) : clientId,
|
|
3673
|
+
client_secret: clientSecretEnv !== null ? toEnvSecretReference(clientSecretEnv) : clientSecret,
|
|
3674
|
+
...(scope ? { scope } : {}),
|
|
3675
|
+
...(oauthAuthMethod ? { auth_method: oauthAuthMethod } : {}),
|
|
3676
|
+
};
|
|
3677
|
+
|
|
3678
|
+
console.log(`\nš Setting up OAuth client credentials for '${alias}'...`);
|
|
3679
|
+
if (oauthFlag) {
|
|
3680
|
+
// Accept --oauth alongside credentials but tell the user it's a
|
|
3681
|
+
// no-op ā credentials already imply M2M. Leaving it silent would be
|
|
3682
|
+
// a did-my-flag-do-anything moment.
|
|
3683
|
+
console.log(' Note: --oauth is redundant with client credentials and was ignored.');
|
|
3684
|
+
}
|
|
3685
|
+
console.log(`Agent URL: ${url}`);
|
|
3686
|
+
console.log(`Token URL: ${resolvedOauthEndpoint}${oauthEndpoint ? '' : ' (discovered)'}`);
|
|
3687
|
+
if (discoveredRequirements && discoveredRequirements.authorizationServer && !oauthEndpoint) {
|
|
3688
|
+
console.log(`AS: ${discoveredRequirements.authorizationServer}`);
|
|
3689
|
+
}
|
|
3690
|
+
console.log(`Scope: ${scope || '(none)'}`);
|
|
3691
|
+
console.log(
|
|
3692
|
+
`Secret source: ${clientSecretEnv !== null ? `env var $${clientSecretEnv}` : 'literal (stored in config)'}\n`
|
|
3693
|
+
);
|
|
3694
|
+
|
|
3695
|
+
if (dryRunFlag) {
|
|
3696
|
+
console.log('š§Ŗ Dry run ā would save the agent with the above config.');
|
|
3697
|
+
console.log(' No token exchange, no config file write. Rerun without --dry-run to persist.\n');
|
|
3698
|
+
process.exit(0);
|
|
3699
|
+
}
|
|
3700
|
+
|
|
3701
|
+
let tokens;
|
|
3702
|
+
try {
|
|
3703
|
+
console.log('Exchanging credentials for an access token...');
|
|
3704
|
+
// CLI is operator-driven ā the user explicitly pointed us at the URL,
|
|
3705
|
+
// so localhost / private-IP endpoints are expected for dev setups.
|
|
3706
|
+
// Library consumers accepting untrusted configs omit this flag and
|
|
3707
|
+
// get the default SSRF guard.
|
|
3708
|
+
tokens = await exchangeClientCredentials(credentials, { allowPrivateIp: true });
|
|
3709
|
+
} catch (err) {
|
|
3710
|
+
if (err instanceof MissingEnvSecretError) {
|
|
3711
|
+
console.error(`\nā ${err.message}\n`);
|
|
3712
|
+
process.exit(1);
|
|
3713
|
+
}
|
|
3714
|
+
if (err instanceof ClientCredentialsExchangeError) {
|
|
3715
|
+
console.error(`\nā ${err.message}`);
|
|
3716
|
+
if (err.oauthError === 'invalid_client') {
|
|
3717
|
+
console.error(' Check that --client-id and --client-secret are correct.');
|
|
3718
|
+
} else if (err.oauthError === 'invalid_scope') {
|
|
3719
|
+
console.error(' The authorization server rejected the requested --scope.');
|
|
3720
|
+
} else if (err.oauthError === 'unauthorized_client') {
|
|
3721
|
+
console.error(' The client is not authorized to use the client_credentials grant.');
|
|
3722
|
+
} else if (err.oauthError === 'invalid_grant') {
|
|
3723
|
+
console.error(" Confirm the client is enabled for the 'client_credentials' grant type.");
|
|
3724
|
+
} else if (err.oauthError === 'invalid_request') {
|
|
3725
|
+
console.error(' Token endpoint rejected the request shape.');
|
|
3726
|
+
console.error(' Try --oauth-auth-method body (or basic, if you used body).');
|
|
3727
|
+
} else if (err.kind === 'malformed' && !err.oauthError) {
|
|
3728
|
+
// The #1 CC footgun: user pastes the issuer URL (or the
|
|
3729
|
+
// authorization endpoint, or a .well-known metadata doc) as
|
|
3730
|
+
// --oauth-token-url. We land here for any non-OAuth response
|
|
3731
|
+
// shape ā HTML 200, redirect, 404/405, no-JSON-body, HTTP 200
|
|
3732
|
+
// without access_token. All the same user mistake.
|
|
3733
|
+
const statusHint = err.httpStatus ? `HTTP ${err.httpStatus} ` : '';
|
|
3734
|
+
console.error(` The token endpoint returned an unexpected ${statusHint}response.`);
|
|
3735
|
+
console.error(' The most common cause is --oauth-token-url pointing at the issuer,');
|
|
3736
|
+
console.error(' authorization endpoint, or a .well-known metadata URL instead of the');
|
|
3737
|
+
console.error(' token endpoint. Check the AS docs for the exact URL');
|
|
3738
|
+
console.error(' (commonly /oauth/token, /oauth2/token, or /connect/token).');
|
|
3739
|
+
} else if (err.kind === 'network') {
|
|
3740
|
+
console.error(' The token endpoint is unreachable. Check the URL, DNS, and firewall.');
|
|
3741
|
+
}
|
|
3742
|
+
console.error('');
|
|
3743
|
+
process.exit(1);
|
|
3744
|
+
}
|
|
3745
|
+
throw err;
|
|
3746
|
+
}
|
|
3747
|
+
|
|
3748
|
+
console.log(`ā
Token exchange succeeded (expires_in: ${tokens.expires_in ?? 'unspecified'})\n`);
|
|
3749
|
+
|
|
3750
|
+
saveAgent(alias, {
|
|
3751
|
+
url,
|
|
3752
|
+
protocol: protocol || 'mcp',
|
|
3753
|
+
oauth_client_credentials: credentials,
|
|
3754
|
+
oauth_tokens: tokens,
|
|
3755
|
+
});
|
|
3756
|
+
|
|
3757
|
+
console.log(`ā
Agent '${alias}' saved with client credentials.`);
|
|
3758
|
+
console.log(`Use: adcp ${alias} <tool> <payload>`);
|
|
3759
|
+
console.log('Tokens will refresh automatically when they expire.\n');
|
|
3760
|
+
process.exit(0);
|
|
3761
|
+
}
|
|
3762
|
+
|
|
3763
|
+
// Handle OAuth save flow
|
|
3764
|
+
if (oauthFlag) {
|
|
3765
|
+
if (!url) {
|
|
3766
|
+
console.error('ERROR: --oauth requires a URL\n');
|
|
3767
|
+
console.error('Usage: adcp --save-auth <alias> <url> --oauth\n');
|
|
3768
|
+
process.exit(2);
|
|
3769
|
+
}
|
|
3770
|
+
|
|
3771
|
+
// OAuth is only for MCP
|
|
3772
|
+
const detectedProtocol = protocol || (url.includes('/mcp') ? 'mcp' : null);
|
|
3773
|
+
if (detectedProtocol && detectedProtocol !== 'mcp') {
|
|
3774
|
+
console.error('ERROR: OAuth is only supported for MCP protocol\n');
|
|
3775
|
+
process.exit(2);
|
|
3776
|
+
}
|
|
3777
|
+
|
|
3778
|
+
// Inverse of the client-credentials `grant_types_supported` pre-check:
|
|
3779
|
+
// bail early if the AS the agent points at can't actually do the
|
|
3780
|
+
// browser flow. Don't gate when `grant_types_supported` is absent
|
|
3781
|
+
// (RFC 8414 default is ['authorization_code', 'implicit'], so absence
|
|
3782
|
+
// is still consistent with browser flow).
|
|
3783
|
+
try {
|
|
3784
|
+
const req = await discoverAuthorizationRequirements(url, { allowPrivateIp: true });
|
|
3785
|
+
if (req && Array.isArray(req.grantTypesSupported) && !req.grantTypesSupported.includes('authorization_code')) {
|
|
3786
|
+
console.error('\nā The discovered authorization server does not support the authorization_code grant.');
|
|
3787
|
+
console.error(
|
|
3788
|
+
` grant_types_supported = [${req.grantTypesSupported.join(', ')}] at ${req.authorizationServer}`
|
|
3789
|
+
);
|
|
3790
|
+
console.error(' Use client credentials instead: --client-id <id> --client-secret <secret>\n');
|
|
3791
|
+
process.exit(1);
|
|
3792
|
+
}
|
|
3793
|
+
} catch {
|
|
3794
|
+
// Discovery is best-effort for this pre-check ā if it fails, let the
|
|
3795
|
+
// MCP SDK's OAuth provider surface the real error at connect time.
|
|
3796
|
+
}
|
|
3797
|
+
|
|
3798
|
+
console.log(`\nš Setting up OAuth for '${alias}'...`);
|
|
3799
|
+
console.log(`URL: ${url}\n`);
|
|
3800
|
+
|
|
3801
|
+
// Create a temporary agent config for OAuth
|
|
3802
|
+
const tempAgent = {
|
|
3803
|
+
id: alias,
|
|
3804
|
+
name: alias,
|
|
3805
|
+
agent_uri: url,
|
|
3806
|
+
protocol: 'mcp',
|
|
3807
|
+
};
|
|
3808
|
+
|
|
3809
|
+
const { Client: MCPClient } = require('@modelcontextprotocol/sdk/client/index.js');
|
|
3810
|
+
const { StreamableHTTPClientTransport } = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
|
|
3811
|
+
const { UnauthorizedError } = require('@modelcontextprotocol/sdk/client/auth.js');
|
|
3812
|
+
|
|
3813
|
+
const oauthProvider = createCLIOAuthProvider(tempAgent);
|
|
3814
|
+
const mcpClient = new MCPClient({ name: 'adcp-cli', version: '1.0.0' });
|
|
3815
|
+
const createTransport = () => new StreamableHTTPClientTransport(new URL(url), { authProvider: oauthProvider });
|
|
3816
|
+
|
|
3817
|
+
let transport = createTransport();
|
|
3818
|
+
|
|
3819
|
+
try {
|
|
3820
|
+
console.log('Connecting to verify OAuth support...');
|
|
3821
|
+
await mcpClient.connect(transport);
|
|
3822
|
+
// If we connected without OAuth, the server doesn't require it
|
|
3823
|
+
console.log('\nā ļø Server connected without requiring OAuth.');
|
|
3824
|
+
console.log('Saving agent without OAuth tokens.\n');
|
|
3825
|
+
await oauthProvider.cleanup();
|
|
3826
|
+
await mcpClient.close();
|
|
3827
|
+
saveAgent(alias, { url, protocol: 'mcp' });
|
|
3828
|
+
console.log(`ā
Agent '${alias}' saved.`);
|
|
3829
|
+
console.log(`Use: adcp ${alias} <tool> <payload>\n`);
|
|
3830
|
+
} catch (error) {
|
|
3831
|
+
if (error instanceof UnauthorizedError || error.name === 'UnauthorizedError') {
|
|
3832
|
+
console.log('OAuth authorization required.');
|
|
3833
|
+
console.log('Opening browser for authentication...\n');
|
|
3834
|
+
|
|
3835
|
+
try {
|
|
3836
|
+
const code = await oauthProvider.waitForCallback();
|
|
3837
|
+
console.log('Authorization received!');
|
|
3838
|
+
await transport.finishAuth(code);
|
|
3839
|
+
|
|
3840
|
+
// Save agent with OAuth tokens
|
|
3841
|
+
const agentConfig = {
|
|
3842
|
+
url,
|
|
3843
|
+
protocol: 'mcp',
|
|
3844
|
+
oauth_tokens: tempAgent.oauth_tokens,
|
|
3845
|
+
oauth_client: tempAgent.oauth_client,
|
|
3846
|
+
};
|
|
3847
|
+
saveAgent(alias, agentConfig);
|
|
3848
|
+
|
|
3849
|
+
console.log(`\nā
Agent '${alias}' saved with OAuth tokens.`);
|
|
3850
|
+
console.log(`Use: adcp ${alias} <tool> <payload>\n`);
|
|
3851
|
+
|
|
3852
|
+
await oauthProvider.cleanup();
|
|
3853
|
+
await mcpClient.close();
|
|
3854
|
+
} catch (authError) {
|
|
3855
|
+
await oauthProvider.cleanup();
|
|
3856
|
+
console.error('\nā OAuth failed:', authError.message);
|
|
3857
|
+
process.exit(1);
|
|
3858
|
+
}
|
|
3859
|
+
} else {
|
|
3860
|
+
await oauthProvider.cleanup();
|
|
3861
|
+
console.error('\nā Connection failed:', error.message);
|
|
3862
|
+
process.exit(1);
|
|
3863
|
+
}
|
|
3864
|
+
}
|
|
3865
|
+
process.exit(0);
|
|
3866
|
+
}
|
|
3867
|
+
|
|
3868
|
+
// Determine mode:
|
|
3869
|
+
// - If URL provided AND (--auth or --no-auth): fully non-interactive
|
|
3870
|
+
// - Otherwise: interactive (prompts for missing values)
|
|
3871
|
+
const hasAuthDecision = providedAuthToken !== null || noAuthFlag;
|
|
3872
|
+
const nonInteractive = url && hasAuthDecision;
|
|
3873
|
+
|
|
3874
|
+
await interactiveSetup(alias, url, protocol, providedAuthToken, nonInteractive, noAuthFlag);
|
|
3875
|
+
process.exit(0);
|
|
3876
|
+
}
|
|
3877
|
+
|
|
3878
|
+
if (args[0] === '--list-agents') {
|
|
3879
|
+
const agents = listAgents();
|
|
3880
|
+
const aliases = Object.keys(agents);
|
|
3881
|
+
|
|
3882
|
+
if (aliases.length === 0) {
|
|
3883
|
+
console.log('\nNo saved agents found.');
|
|
3884
|
+
console.log('Use: adcp --save-auth <alias> <url>\n');
|
|
3885
|
+
process.exit(0);
|
|
3886
|
+
}
|
|
3887
|
+
|
|
3888
|
+
console.log('\nš Saved Agents:\n');
|
|
3889
|
+
aliases.forEach(alias => {
|
|
3890
|
+
const agent = agents[alias];
|
|
3891
|
+
console.log(` ${alias}`);
|
|
3892
|
+
console.log(` URL: ${agent.url}`);
|
|
3893
|
+
if (agent.protocol) {
|
|
3894
|
+
console.log(` Protocol: ${agent.protocol}`);
|
|
3895
|
+
}
|
|
3896
|
+
if (agent.auth_token) {
|
|
3897
|
+
console.log(` Auth: token configured`);
|
|
3898
|
+
}
|
|
3899
|
+
if (agent.oauth_client_credentials) {
|
|
3900
|
+
// Intentionally minimal: show only that CC is configured and the
|
|
3901
|
+
// token endpoint. Reading any other field from
|
|
3902
|
+
// oauth_client_credentials here trips CodeQL's clear-text-logging
|
|
3903
|
+
// rule regardless of whether the value is actually sensitive. For
|
|
3904
|
+
// the full secret-source breakdown, consult ~/.adcp/config.json
|
|
3905
|
+
// (via --show-config).
|
|
3906
|
+
console.log(' OAuth: client credentials');
|
|
3907
|
+
} else if (agent.oauth_tokens) {
|
|
3908
|
+
const hasValid = hasValidOAuthTokens(agent);
|
|
3909
|
+
console.log(` OAuth: ${hasValid ? 'valid tokens' : 'expired (use --oauth to refresh)'}`);
|
|
3910
|
+
}
|
|
3911
|
+
console.log('');
|
|
3912
|
+
});
|
|
3913
|
+
console.log(`Config: ${getConfigPath()}\n`);
|
|
3914
|
+
process.exit(0);
|
|
3915
|
+
}
|
|
3916
|
+
|
|
3917
|
+
if (args[0] === '--remove-agent') {
|
|
3918
|
+
const alias = args[1];
|
|
3919
|
+
|
|
3920
|
+
if (!alias) {
|
|
3921
|
+
console.error('ERROR: --remove-agent requires an alias\n');
|
|
3922
|
+
process.exit(2);
|
|
3923
|
+
}
|
|
3924
|
+
|
|
3925
|
+
if (removeAgent(alias)) {
|
|
3926
|
+
console.log(`\nā
Removed agent '${alias}'\n`);
|
|
3927
|
+
} else {
|
|
3928
|
+
console.error(`\nERROR: Agent '${alias}' not found\n`);
|
|
3929
|
+
process.exit(2);
|
|
3930
|
+
}
|
|
3931
|
+
process.exit(0);
|
|
3932
|
+
}
|
|
3933
|
+
|
|
3934
|
+
if (args[0] === '--show-config') {
|
|
3935
|
+
console.log(`\nConfig file: ${getConfigPath()}\n`);
|
|
3936
|
+
process.exit(0);
|
|
3937
|
+
}
|
|
3938
|
+
|
|
3939
|
+
// Handle --clear-oauth command
|
|
3940
|
+
if (args.includes('--clear-oauth')) {
|
|
3941
|
+
const positionalArgs = args.filter(arg => !arg.startsWith('--'));
|
|
3942
|
+
const alias = positionalArgs[0];
|
|
3943
|
+
|
|
3944
|
+
if (!alias) {
|
|
3945
|
+
console.error('ERROR: --clear-oauth requires an agent alias\n');
|
|
3946
|
+
console.error('Usage: adcp <alias> --clear-oauth\n');
|
|
3947
|
+
process.exit(2);
|
|
3948
|
+
}
|
|
3949
|
+
|
|
3950
|
+
if (!isAlias(alias)) {
|
|
3951
|
+
console.error(`ERROR: '${alias}' is not a saved agent alias\n`);
|
|
3952
|
+
process.exit(2);
|
|
3953
|
+
}
|
|
3954
|
+
|
|
3955
|
+
const agentConfig = getAgent(alias);
|
|
3956
|
+
if (!agentConfig.oauth_tokens) {
|
|
3957
|
+
console.log(`\nAgent '${alias}' has no OAuth tokens to clear.\n`);
|
|
3958
|
+
process.exit(0);
|
|
3959
|
+
}
|
|
3960
|
+
|
|
3961
|
+
// Clear OAuth tokens from agent config
|
|
3962
|
+
delete agentConfig.oauth_tokens;
|
|
3963
|
+
delete agentConfig.oauth_client;
|
|
3964
|
+
delete agentConfig.oauth_code_verifier;
|
|
3965
|
+
saveAgent(alias, agentConfig);
|
|
3966
|
+
|
|
3967
|
+
console.log(`\nā
Cleared OAuth tokens for '${alias}'`);
|
|
3968
|
+
console.log('Use --oauth to re-authenticate.\n');
|
|
3969
|
+
process.exit(0);
|
|
3970
|
+
}
|
|
3971
|
+
|
|
3972
|
+
// Parse arguments
|
|
3973
|
+
if (args.length < 1) {
|
|
3974
|
+
console.error('ERROR: Missing required arguments\n');
|
|
3975
|
+
printUsage();
|
|
3976
|
+
process.exit(2);
|
|
3977
|
+
}
|
|
3978
|
+
|
|
3979
|
+
// Parse options first
|
|
3980
|
+
const authIndex = args.indexOf('--auth');
|
|
3981
|
+
let authToken = authIndex !== -1 ? args[authIndex + 1] : process.env.ADCP_AUTH_TOKEN;
|
|
3982
|
+
const protocolIndex = args.indexOf('--protocol');
|
|
3983
|
+
const protocolFlag = protocolIndex !== -1 ? args[protocolIndex + 1] : null;
|
|
3984
|
+
const jsonOutput = args.includes('--json');
|
|
3985
|
+
const debug = args.includes('--debug') || process.env.ADCP_DEBUG === 'true';
|
|
3986
|
+
const waitForAsync = args.includes('--wait');
|
|
3987
|
+
const useLocalWebhook = args.includes('--local');
|
|
3988
|
+
const timeoutIndex = args.indexOf('--timeout');
|
|
3989
|
+
const timeout = timeoutIndex !== -1 ? parseInt(args[timeoutIndex + 1]) : 300000;
|
|
3990
|
+
const useOAuth = args.includes('--oauth');
|
|
3991
|
+
const clearOAuth = args.includes('--clear-oauth');
|
|
3992
|
+
|
|
3993
|
+
// Validate protocol flag if provided
|
|
3994
|
+
if (protocolFlag && protocolFlag !== 'mcp' && protocolFlag !== 'a2a') {
|
|
3995
|
+
console.error(`ERROR: Invalid protocol '${protocolFlag}'. Must be 'mcp' or 'a2a'\n`);
|
|
3996
|
+
printUsage();
|
|
3997
|
+
process.exit(2);
|
|
3998
|
+
}
|
|
3999
|
+
|
|
4000
|
+
// Filter out flag arguments to find positional arguments
|
|
4001
|
+
const positionalArgs = args.filter(
|
|
4002
|
+
arg =>
|
|
4003
|
+
!arg.startsWith('--') &&
|
|
4004
|
+
arg !== authToken && // Don't include the auth token value
|
|
4005
|
+
arg !== protocolFlag && // Don't include the protocol value
|
|
4006
|
+
arg !== (timeoutIndex !== -1 ? args[timeoutIndex + 1] : null) // Don't include timeout value
|
|
4007
|
+
);
|
|
4008
|
+
|
|
4009
|
+
// Determine if first arg is alias or URL
|
|
4010
|
+
let protocol = protocolFlag; // Start with flag if provided
|
|
4011
|
+
let agentUrl;
|
|
4012
|
+
let toolName;
|
|
4013
|
+
let payloadArg;
|
|
4014
|
+
let savedAgent = null;
|
|
4015
|
+
|
|
4016
|
+
const firstArg = positionalArgs[0];
|
|
4017
|
+
|
|
4018
|
+
// Check if first arg is a built-in alias or saved alias
|
|
4019
|
+
if (BUILT_IN_AGENTS[firstArg]) {
|
|
4020
|
+
// Built-in test helper mode
|
|
4021
|
+
savedAgent = BUILT_IN_AGENTS[firstArg];
|
|
4022
|
+
agentUrl = savedAgent.url;
|
|
4023
|
+
|
|
4024
|
+
// Protocol priority: --protocol flag > built-in config
|
|
4025
|
+
if (!protocol) {
|
|
4026
|
+
protocol = savedAgent.protocol;
|
|
4027
|
+
}
|
|
4028
|
+
|
|
4029
|
+
toolName = positionalArgs[1];
|
|
4030
|
+
payloadArg = positionalArgs[2] || '{}';
|
|
4031
|
+
|
|
4032
|
+
// Use built-in auth token if not overridden and available
|
|
4033
|
+
if (!authToken && savedAgent.auth_token) {
|
|
4034
|
+
authToken = savedAgent.auth_token;
|
|
4035
|
+
}
|
|
4036
|
+
|
|
4037
|
+
if (debug) {
|
|
4038
|
+
console.error(`DEBUG: Using built-in agent '${firstArg}'`);
|
|
4039
|
+
console.error(` ${savedAgent.description}`);
|
|
4040
|
+
console.error(` URL: ${agentUrl}`);
|
|
4041
|
+
console.error(` Protocol: ${protocol}`);
|
|
4042
|
+
console.error('');
|
|
4043
|
+
}
|
|
4044
|
+
} else if (isAlias(firstArg)) {
|
|
4045
|
+
// Alias mode - load saved agent config
|
|
4046
|
+
savedAgent = getAgent(firstArg);
|
|
4047
|
+
agentUrl = savedAgent.url;
|
|
4048
|
+
|
|
4049
|
+
// Protocol priority: --protocol flag > saved config > auto-detect
|
|
4050
|
+
if (!protocol) {
|
|
4051
|
+
protocol = savedAgent.protocol || null;
|
|
4052
|
+
}
|
|
4053
|
+
|
|
4054
|
+
toolName = positionalArgs[1];
|
|
4055
|
+
payloadArg = positionalArgs[2] || '{}';
|
|
4056
|
+
|
|
4057
|
+
if (!authToken) {
|
|
4058
|
+
authToken = getEffectiveAuthToken(savedAgent);
|
|
4059
|
+
}
|
|
4060
|
+
|
|
4061
|
+
if (debug) {
|
|
4062
|
+
console.error(`DEBUG: Using saved agent '${firstArg}'`);
|
|
4063
|
+
console.error(` URL: ${agentUrl}`);
|
|
4064
|
+
if (protocol) {
|
|
4065
|
+
console.error(` Protocol: ${protocol}`);
|
|
4066
|
+
}
|
|
4067
|
+
console.error('');
|
|
4068
|
+
}
|
|
4069
|
+
} else if (firstArg && (firstArg.startsWith('http://') || firstArg.startsWith('https://'))) {
|
|
4070
|
+
// URL mode
|
|
4071
|
+
agentUrl = firstArg;
|
|
4072
|
+
toolName = positionalArgs[1];
|
|
4073
|
+
payloadArg = positionalArgs[2] || '{}';
|
|
4074
|
+
// protocol already set from flag, or null for auto-detect
|
|
4075
|
+
} else {
|
|
4076
|
+
console.error(`ERROR: First argument must be an alias or URL\n`);
|
|
4077
|
+
console.error(`Available aliases: ${Object.keys(listAgents()).join(', ') || 'none'}\n`);
|
|
4078
|
+
printUsage();
|
|
4079
|
+
process.exit(2);
|
|
4080
|
+
}
|
|
4081
|
+
|
|
4082
|
+
// Parse payload
|
|
4083
|
+
let payload;
|
|
4084
|
+
try {
|
|
4085
|
+
if (payloadArg === '-') {
|
|
4086
|
+
// Read from stdin
|
|
4087
|
+
const stdin = readFileSync(0, 'utf-8');
|
|
4088
|
+
payload = JSON.parse(stdin);
|
|
4089
|
+
} else if (payloadArg.startsWith('@')) {
|
|
4090
|
+
// Read from file
|
|
4091
|
+
const filePath = payloadArg.substring(1);
|
|
4092
|
+
const fileContent = readFileSync(filePath, 'utf-8');
|
|
4093
|
+
payload = JSON.parse(fileContent);
|
|
4094
|
+
} else {
|
|
4095
|
+
// Parse inline JSON
|
|
4096
|
+
payload = JSON.parse(payloadArg);
|
|
4097
|
+
}
|
|
4098
|
+
} catch (error) {
|
|
4099
|
+
console.error(`ERROR: Invalid JSON payload: ${error.message}\n`);
|
|
4100
|
+
process.exit(2);
|
|
4101
|
+
}
|
|
4102
|
+
|
|
4103
|
+
// Auto-detect protocol if not specified
|
|
4104
|
+
if (!protocol) {
|
|
4105
|
+
if (debug || !jsonOutput) {
|
|
4106
|
+
console.error('š Auto-detecting protocol...');
|
|
4107
|
+
}
|
|
4108
|
+
|
|
4109
|
+
try {
|
|
4110
|
+
protocol = await detectProtocol(agentUrl);
|
|
4111
|
+
if (debug || !jsonOutput) {
|
|
4112
|
+
console.error(`ā Detected protocol: ${protocol.toUpperCase()}\n`);
|
|
4113
|
+
}
|
|
4114
|
+
} catch (error) {
|
|
4115
|
+
console.error(`ERROR: Failed to detect protocol: ${error.message}\n`);
|
|
4116
|
+
console.error('Please specify protocol explicitly: adcp mcp <url> or adcp a2a <url>\n');
|
|
4117
|
+
process.exit(2);
|
|
4118
|
+
}
|
|
4119
|
+
}
|
|
4120
|
+
|
|
4121
|
+
if (debug) {
|
|
4122
|
+
console.error('DEBUG: Configuration');
|
|
4123
|
+
console.error(` Protocol: ${protocol}`);
|
|
4124
|
+
console.error(` Agent URL: ${agentUrl}`);
|
|
4125
|
+
console.error(` Tool: ${toolName || '(list tools)'}`);
|
|
4126
|
+
console.error(` Auth: ${authToken ? 'provided' : useOAuth ? 'oauth' : 'none'}`);
|
|
4127
|
+
console.error(` Payload: ${JSON.stringify(payload, null, 2)}`);
|
|
4128
|
+
console.error('');
|
|
4129
|
+
}
|
|
4130
|
+
|
|
4131
|
+
// Check OAuth requirements
|
|
4132
|
+
if (useOAuth && protocol !== 'mcp') {
|
|
4133
|
+
console.error('\nā ERROR: OAuth is only supported for MCP protocol\n');
|
|
4134
|
+
console.error('Use --auth TOKEN for A2A protocol authentication.\n');
|
|
4135
|
+
process.exit(2);
|
|
4136
|
+
}
|
|
4137
|
+
|
|
4138
|
+
// Build agent config
|
|
4139
|
+
// If using OAuth (auth code or client credentials) with a saved alias,
|
|
4140
|
+
// attach the saved OAuth material so the library call path can refresh.
|
|
4141
|
+
let agentOAuthTokens = null;
|
|
4142
|
+
let agentOAuthClient = null;
|
|
4143
|
+
let agentOAuthClientCredentials = null;
|
|
4144
|
+
let agentAlias = null;
|
|
4145
|
+
|
|
4146
|
+
if (savedAgent && isAlias(firstArg)) {
|
|
4147
|
+
agentAlias = firstArg;
|
|
4148
|
+
const fullSavedConfig = getAgent(firstArg);
|
|
4149
|
+
if (fullSavedConfig.oauth_client_credentials) {
|
|
4150
|
+
agentOAuthClientCredentials = fullSavedConfig.oauth_client_credentials;
|
|
4151
|
+
agentOAuthTokens = fullSavedConfig.oauth_tokens ?? null;
|
|
4152
|
+
} else if (useOAuth && fullSavedConfig.oauth_tokens) {
|
|
4153
|
+
agentOAuthTokens = fullSavedConfig.oauth_tokens;
|
|
4154
|
+
agentOAuthClient = fullSavedConfig.oauth_client;
|
|
4155
|
+
if (!jsonOutput && hasValidOAuthTokens({ oauth_tokens: agentOAuthTokens })) {
|
|
4156
|
+
console.log('Using saved OAuth tokens...\n');
|
|
4157
|
+
}
|
|
4158
|
+
}
|
|
4159
|
+
}
|
|
4160
|
+
|
|
4161
|
+
// Create agent config
|
|
4162
|
+
const agentConfig = {
|
|
4163
|
+
id: 'cli-agent',
|
|
4164
|
+
name: 'CLI Agent',
|
|
4165
|
+
agent_uri: agentUrl,
|
|
4166
|
+
protocol: protocol,
|
|
4167
|
+
...(authToken && !useOAuth && !agentOAuthClientCredentials && { auth_token: authToken, requiresAuth: true }),
|
|
4168
|
+
...(agentOAuthTokens && { oauth_tokens: agentOAuthTokens }),
|
|
4169
|
+
...(agentOAuthClient && { oauth_client: agentOAuthClient }),
|
|
4170
|
+
...(agentOAuthClientCredentials && { oauth_client_credentials: agentOAuthClientCredentials }),
|
|
4171
|
+
};
|
|
4172
|
+
|
|
4173
|
+
// For saved aliases with any OAuth material, attach a file-backed storage
|
|
4174
|
+
// so token refreshes (SDK auto-refresh for auth-code flow, client-credentials
|
|
4175
|
+
// re-exchange for CC flow) persist back to the config file. The storage
|
|
4176
|
+
// keys writes under the actual alias regardless of the synthetic
|
|
4177
|
+
// `cli-agent` id we use in memory.
|
|
4178
|
+
if (agentAlias && (agentOAuthTokens || agentOAuthClientCredentials)) {
|
|
4179
|
+
const storage = createFileOAuthStorage({
|
|
4180
|
+
configPath: getConfigPath(),
|
|
4181
|
+
agentKey: agentAlias,
|
|
4182
|
+
});
|
|
4183
|
+
bindAgentStorage(agentConfig, storage);
|
|
4184
|
+
}
|
|
4185
|
+
|
|
4186
|
+
try {
|
|
4187
|
+
// If no tool name provided, display agent info
|
|
4188
|
+
if (!toolName) {
|
|
4189
|
+
if (debug) {
|
|
4190
|
+
console.error('DEBUG: No tool specified, displaying agent info...\n');
|
|
4191
|
+
}
|
|
4192
|
+
|
|
4193
|
+
// For OAuth without a tool, just authenticate and list tools
|
|
4194
|
+
if (useOAuth && protocol === 'mcp') {
|
|
4195
|
+
const { Client: MCPClient } = require('@modelcontextprotocol/sdk/client/index.js');
|
|
4196
|
+
const { StreamableHTTPClientTransport } = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
|
|
4197
|
+
const { UnauthorizedError } = require('@modelcontextprotocol/sdk/client/auth.js');
|
|
4198
|
+
|
|
4199
|
+
const oauthProvider = createCLIOAuthProvider(agentConfig, { quiet: jsonOutput });
|
|
4200
|
+
const mcpClient = new MCPClient({ name: 'adcp-cli', version: '1.0.0' });
|
|
4201
|
+
const createTransport = () =>
|
|
4202
|
+
new StreamableHTTPClientTransport(new URL(agentUrl), { authProvider: oauthProvider });
|
|
4203
|
+
|
|
4204
|
+
let transport = createTransport();
|
|
4205
|
+
|
|
4206
|
+
try {
|
|
4207
|
+
if (!jsonOutput) {
|
|
4208
|
+
console.log('Connecting to MCP agent...');
|
|
4209
|
+
}
|
|
4210
|
+
await mcpClient.connect(transport);
|
|
4211
|
+
} catch (error) {
|
|
4212
|
+
if (error instanceof UnauthorizedError || error.name === 'UnauthorizedError') {
|
|
4213
|
+
if (!jsonOutput) {
|
|
4214
|
+
console.log('\nOAuth authorization required.');
|
|
4215
|
+
console.log('Opening browser for authentication...\n');
|
|
4216
|
+
}
|
|
4217
|
+
const code = await oauthProvider.waitForCallback();
|
|
4218
|
+
await transport.finishAuth(code);
|
|
4219
|
+
if (agentAlias && agentConfig.oauth_tokens) {
|
|
4220
|
+
const savedConfig = getAgent(agentAlias);
|
|
4221
|
+
savedConfig.oauth_tokens = agentConfig.oauth_tokens;
|
|
4222
|
+
savedConfig.oauth_client = agentConfig.oauth_client;
|
|
4223
|
+
saveAgent(agentAlias, savedConfig);
|
|
4224
|
+
if (!jsonOutput) {
|
|
4225
|
+
console.log(`OAuth tokens saved to '${agentAlias}'.\n`);
|
|
4226
|
+
}
|
|
4227
|
+
}
|
|
4228
|
+
transport = createTransport();
|
|
4229
|
+
await mcpClient.connect(transport);
|
|
4230
|
+
} else {
|
|
4231
|
+
await oauthProvider.cleanup();
|
|
4232
|
+
throw error;
|
|
4233
|
+
}
|
|
4234
|
+
}
|
|
4235
|
+
|
|
4236
|
+
if (!jsonOutput) {
|
|
4237
|
+
console.log('Connected!\n');
|
|
4238
|
+
}
|
|
4239
|
+
|
|
4240
|
+
// List tools
|
|
4241
|
+
const toolsResult = await mcpClient.listTools();
|
|
4242
|
+
await oauthProvider.cleanup();
|
|
4243
|
+
await mcpClient.close();
|
|
4244
|
+
|
|
4245
|
+
if (jsonOutput) {
|
|
4246
|
+
console.log(JSON.stringify({ tools: toolsResult.tools, protocol: 'mcp', oauth: true }, null, 2));
|
|
4247
|
+
} else {
|
|
4248
|
+
console.log(`\nš Agent Information (OAuth)\n`);
|
|
4249
|
+
console.log(`Protocol: MCP`);
|
|
4250
|
+
console.log(`URL: ${agentUrl}`);
|
|
4251
|
+
console.log(`\nAvailable Tools (${toolsResult.tools.length}):\n`);
|
|
4252
|
+
toolsResult.tools.forEach((tool, i) => {
|
|
4253
|
+
console.log(`${i + 1}. ${tool.name}`);
|
|
4254
|
+
if (tool.description) {
|
|
4255
|
+
console.log(` ${tool.description}`);
|
|
4256
|
+
}
|
|
4257
|
+
console.log('');
|
|
4258
|
+
});
|
|
4259
|
+
}
|
|
4260
|
+
process.exit(0);
|
|
4261
|
+
}
|
|
4262
|
+
|
|
4263
|
+
await displayAgentInfo(agentConfig, jsonOutput);
|
|
4264
|
+
process.exit(0);
|
|
4265
|
+
}
|
|
4266
|
+
|
|
4267
|
+
// Set up webhook handler if --wait flag is used
|
|
4268
|
+
let webhookHandler = null;
|
|
4269
|
+
let webhookUrl = null;
|
|
4270
|
+
|
|
4271
|
+
if (waitForAsync) {
|
|
4272
|
+
const useNgrok = !useLocalWebhook;
|
|
4273
|
+
|
|
4274
|
+
// Check if ngrok is available (unless using --local)
|
|
4275
|
+
if (useNgrok) {
|
|
4276
|
+
const ngrokAvailable = await AsyncWebhookHandler.isNgrokAvailable();
|
|
4277
|
+
if (!ngrokAvailable) {
|
|
4278
|
+
console.error('\nā ERROR: --wait flag requires ngrok to be installed\n');
|
|
4279
|
+
console.error('Install ngrok:');
|
|
4280
|
+
console.error(' Mac: brew install ngrok');
|
|
4281
|
+
console.error(' Windows: choco install ngrok');
|
|
4282
|
+
console.error(' Linux: Download from https://ngrok.com/download');
|
|
4283
|
+
console.error('\nOr use --local flag for local agents (e.g., http://localhost:3000)\n');
|
|
4284
|
+
process.exit(2);
|
|
4285
|
+
}
|
|
4286
|
+
}
|
|
4287
|
+
|
|
4288
|
+
if (debug) {
|
|
4289
|
+
console.error(`DEBUG: Setting up ${useNgrok ? 'ngrok' : 'local'} webhook handler...\n`);
|
|
4290
|
+
}
|
|
4291
|
+
|
|
4292
|
+
webhookHandler = new AsyncWebhookHandler({
|
|
4293
|
+
timeout: timeout,
|
|
4294
|
+
debug: debug,
|
|
4295
|
+
});
|
|
4296
|
+
|
|
4297
|
+
try {
|
|
4298
|
+
webhookUrl = await webhookHandler.start(useNgrok);
|
|
4299
|
+
|
|
4300
|
+
if (!jsonOutput) {
|
|
4301
|
+
console.log(`\nš ${useNgrok ? 'Public webhook' : 'Local webhook'} endpoint ready`);
|
|
4302
|
+
console.log(` URL: ${webhookUrl}`);
|
|
4303
|
+
console.log(` Timeout: ${timeout / 1000}s`);
|
|
4304
|
+
if (useLocalWebhook) {
|
|
4305
|
+
console.log(` ā ļø Local mode: Agent must be accessible at localhost`);
|
|
4306
|
+
}
|
|
4307
|
+
console.log('');
|
|
4308
|
+
}
|
|
4309
|
+
} catch (error) {
|
|
4310
|
+
console.error('\nā ERROR: Failed to start webhook handler\n');
|
|
4311
|
+
console.error(error.message);
|
|
4312
|
+
if (debug) {
|
|
4313
|
+
console.error('\nStack trace:');
|
|
4314
|
+
console.error(error.stack);
|
|
4315
|
+
}
|
|
4316
|
+
process.exit(1);
|
|
4317
|
+
}
|
|
4318
|
+
}
|
|
4319
|
+
|
|
4320
|
+
// Handle OAuth flow for MCP if --oauth is specified
|
|
4321
|
+
if (useOAuth && protocol === 'mcp') {
|
|
4322
|
+
const { Client: MCPClient } = require('@modelcontextprotocol/sdk/client/index.js');
|
|
4323
|
+
const { StreamableHTTPClientTransport } = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
|
|
4324
|
+
const { UnauthorizedError } = require('@modelcontextprotocol/sdk/client/auth.js');
|
|
4325
|
+
|
|
4326
|
+
// Create OAuth provider
|
|
4327
|
+
const oauthProvider = createCLIOAuthProvider(agentConfig, {
|
|
4328
|
+
quiet: jsonOutput,
|
|
4329
|
+
});
|
|
4330
|
+
|
|
4331
|
+
// Create MCP client
|
|
4332
|
+
const mcpClient = new MCPClient({
|
|
4333
|
+
name: 'adcp-cli',
|
|
4334
|
+
version: '1.0.0',
|
|
4335
|
+
});
|
|
4336
|
+
|
|
4337
|
+
const createTransport = () =>
|
|
4338
|
+
new StreamableHTTPClientTransport(new URL(agentUrl), {
|
|
4339
|
+
authProvider: oauthProvider,
|
|
4340
|
+
});
|
|
4341
|
+
|
|
4342
|
+
let transport = createTransport();
|
|
4343
|
+
let needsOAuth = !hasValidOAuthTokens(agentConfig);
|
|
4344
|
+
|
|
4345
|
+
try {
|
|
4346
|
+
if (!jsonOutput) {
|
|
4347
|
+
console.log('Connecting to MCP agent...');
|
|
4348
|
+
}
|
|
4349
|
+
await mcpClient.connect(transport);
|
|
4350
|
+
} catch (error) {
|
|
4351
|
+
if (error instanceof UnauthorizedError || error.name === 'UnauthorizedError') {
|
|
4352
|
+
needsOAuth = true;
|
|
4353
|
+
if (!jsonOutput) {
|
|
4354
|
+
console.log('\nOAuth authorization required.');
|
|
4355
|
+
console.log('Opening browser for authentication...\n');
|
|
4356
|
+
}
|
|
4357
|
+
|
|
4358
|
+
try {
|
|
4359
|
+
// Wait for user to complete OAuth in browser
|
|
4360
|
+
const code = await oauthProvider.waitForCallback();
|
|
4361
|
+
if (!jsonOutput) {
|
|
4362
|
+
console.log('Authorization received!');
|
|
4363
|
+
}
|
|
4364
|
+
|
|
4365
|
+
// Finish OAuth flow
|
|
4366
|
+
await transport.finishAuth(code);
|
|
4367
|
+
|
|
4368
|
+
// Save tokens to alias if using a saved agent
|
|
4369
|
+
if (agentAlias && agentConfig.oauth_tokens) {
|
|
4370
|
+
const savedConfig = getAgent(agentAlias);
|
|
4371
|
+
savedConfig.oauth_tokens = agentConfig.oauth_tokens;
|
|
4372
|
+
savedConfig.oauth_client = agentConfig.oauth_client;
|
|
4373
|
+
saveAgent(agentAlias, savedConfig);
|
|
4374
|
+
if (!jsonOutput) {
|
|
4375
|
+
console.log(`OAuth tokens saved to '${agentAlias}'.\n`);
|
|
4376
|
+
}
|
|
4377
|
+
}
|
|
4378
|
+
|
|
4379
|
+
// Reconnect with new tokens
|
|
4380
|
+
if (!jsonOutput) {
|
|
4381
|
+
console.log('Reconnecting with OAuth tokens...');
|
|
4382
|
+
}
|
|
4383
|
+
transport = createTransport();
|
|
4384
|
+
await mcpClient.connect(transport);
|
|
4385
|
+
} catch (authError) {
|
|
4386
|
+
await oauthProvider.cleanup();
|
|
4387
|
+
throw authError;
|
|
4388
|
+
}
|
|
4389
|
+
} else {
|
|
4390
|
+
await oauthProvider.cleanup();
|
|
4391
|
+
throw error;
|
|
4392
|
+
}
|
|
4393
|
+
}
|
|
4394
|
+
|
|
4395
|
+
if (!jsonOutput) {
|
|
4396
|
+
console.log('Connected!\n');
|
|
4397
|
+
}
|
|
4398
|
+
|
|
4399
|
+
// Execute tool call directly via MCP
|
|
4400
|
+
try {
|
|
4401
|
+
const startTime = Date.now();
|
|
4402
|
+
const toolResult = await mcpClient.callTool({ name: toolName, arguments: payload });
|
|
4403
|
+
const responseTime = Date.now() - startTime;
|
|
4404
|
+
|
|
4405
|
+
await oauthProvider.cleanup();
|
|
4406
|
+
await mcpClient.close();
|
|
4407
|
+
|
|
4408
|
+
// Format result similar to AdCPClient response
|
|
4409
|
+
let resultData = toolResult;
|
|
4410
|
+
if (toolResult.content && Array.isArray(toolResult.content)) {
|
|
4411
|
+
const textContent = toolResult.content.find(c => c.type === 'text');
|
|
4412
|
+
if (textContent && textContent.text) {
|
|
4413
|
+
try {
|
|
4414
|
+
resultData = JSON.parse(textContent.text);
|
|
4415
|
+
} catch {
|
|
4416
|
+
resultData = textContent.text;
|
|
4417
|
+
}
|
|
4418
|
+
}
|
|
4419
|
+
}
|
|
4420
|
+
|
|
4421
|
+
if (jsonOutput) {
|
|
4422
|
+
console.log(
|
|
4423
|
+
JSON.stringify(
|
|
4424
|
+
{
|
|
4425
|
+
data: resultData,
|
|
4426
|
+
metadata: {
|
|
4427
|
+
protocol: 'mcp',
|
|
4428
|
+
responseTimeMs: responseTime,
|
|
4429
|
+
oauth: true,
|
|
4430
|
+
},
|
|
4431
|
+
},
|
|
4432
|
+
null,
|
|
4433
|
+
2
|
|
4434
|
+
)
|
|
4435
|
+
);
|
|
4436
|
+
} else {
|
|
4437
|
+
console.log('\nā
SUCCESS\n');
|
|
4438
|
+
console.log('Response:');
|
|
4439
|
+
console.log(JSON.stringify(resultData, null, 2));
|
|
4440
|
+
console.log('');
|
|
4441
|
+
console.log(`Protocol: MCP (OAuth)`);
|
|
4442
|
+
console.log(`Response Time: ${responseTime}ms`);
|
|
4443
|
+
}
|
|
4444
|
+
process.exit(0);
|
|
4445
|
+
} catch (toolError) {
|
|
4446
|
+
await oauthProvider.cleanup();
|
|
4447
|
+
await mcpClient.close();
|
|
4448
|
+
throw toolError;
|
|
4449
|
+
}
|
|
4450
|
+
}
|
|
4451
|
+
|
|
4452
|
+
// Create ADCP client with optional webhook configuration
|
|
4453
|
+
// Note: AdCPClient (multi-agent) expects an array of configs
|
|
4454
|
+
const client = new AdCPClient([agentConfig], {
|
|
4455
|
+
debug: debug,
|
|
4456
|
+
...(webhookUrl && {
|
|
4457
|
+
webhookUrlTemplate: webhookUrl,
|
|
4458
|
+
webhookSecret: 'cli-webhook-secret',
|
|
4459
|
+
}),
|
|
4460
|
+
});
|
|
4461
|
+
|
|
4462
|
+
if (debug) {
|
|
4463
|
+
console.error('DEBUG: Executing task...\n');
|
|
4464
|
+
}
|
|
4465
|
+
|
|
4466
|
+
// Execute the task using the single agent client API
|
|
4467
|
+
const agentClient = client.agent('cli-agent');
|
|
4468
|
+
const result = await agentClient.executeTask(toolName, payload);
|
|
4469
|
+
|
|
4470
|
+
// If waiting for async response, handle webhook
|
|
4471
|
+
if (waitForAsync && webhookHandler) {
|
|
4472
|
+
if (result.status === 'submitted' || result.status === 'working') {
|
|
4473
|
+
if (!jsonOutput) {
|
|
4474
|
+
console.log('š¤ Task submitted, waiting for async response...');
|
|
4475
|
+
}
|
|
4476
|
+
|
|
4477
|
+
try {
|
|
4478
|
+
const webhookResponse = await webhookHandler.waitForResponse();
|
|
4479
|
+
|
|
4480
|
+
// Clean up webhook handler
|
|
4481
|
+
await webhookHandler.cleanup();
|
|
4482
|
+
|
|
4483
|
+
// Output webhook response
|
|
4484
|
+
if (jsonOutput) {
|
|
4485
|
+
console.log(JSON.stringify(webhookResponse.result || webhookResponse, null, 2));
|
|
4486
|
+
} else {
|
|
4487
|
+
console.log('\nā
ASYNC RESPONSE RECEIVED\n');
|
|
4488
|
+
console.log('Response:');
|
|
4489
|
+
console.log(JSON.stringify(webhookResponse.result || webhookResponse, null, 2));
|
|
4490
|
+
}
|
|
4491
|
+
|
|
4492
|
+
process.exit(0);
|
|
4493
|
+
} catch (error) {
|
|
4494
|
+
await webhookHandler.cleanup();
|
|
4495
|
+
console.error('\nā WEBHOOK TIMEOUT\n');
|
|
4496
|
+
console.error(error.message);
|
|
4497
|
+
process.exit(3);
|
|
4498
|
+
}
|
|
4499
|
+
} else {
|
|
4500
|
+
// Task completed synchronously, clean up webhook
|
|
4501
|
+
await webhookHandler.cleanup();
|
|
4502
|
+
}
|
|
4503
|
+
}
|
|
4504
|
+
|
|
4505
|
+
// Check for deprecated assets_required usage in list_creative_formats response
|
|
4506
|
+
let deprecationWarnings = [];
|
|
4507
|
+
if (toolName === 'list_creative_formats' && result.success && result.data) {
|
|
4508
|
+
const formats = result.data.formats || result.data;
|
|
4509
|
+
const deprecatedFormats = checkDeprecatedFormats(formats);
|
|
4510
|
+
if (deprecatedFormats.length > 0) {
|
|
4511
|
+
deprecationWarnings.push({
|
|
4512
|
+
type: 'assets_required_deprecated',
|
|
4513
|
+
message: `ā ļø DEPRECATION: ${deprecatedFormats.length} format(s) using deprecated 'assets_required' field. Please migrate to use 'assets' instead.`,
|
|
4514
|
+
formats: deprecatedFormats,
|
|
4515
|
+
});
|
|
4516
|
+
}
|
|
4517
|
+
}
|
|
4518
|
+
|
|
4519
|
+
// Handle result
|
|
4520
|
+
if (result.success) {
|
|
4521
|
+
if (jsonOutput) {
|
|
4522
|
+
// Raw JSON output - include protocol metadata and warnings
|
|
4523
|
+
console.log(
|
|
4524
|
+
JSON.stringify(
|
|
4525
|
+
{
|
|
4526
|
+
data: result.data,
|
|
4527
|
+
metadata: {
|
|
4528
|
+
taskId: result.metadata.taskId,
|
|
4529
|
+
protocol: result.metadata.agent.protocol,
|
|
4530
|
+
responseTimeMs: result.metadata.responseTimeMs,
|
|
4531
|
+
...(result.conversation &&
|
|
4532
|
+
result.conversation.length > 0 && {
|
|
4533
|
+
protocolMessage: extractProtocolMessage(result.conversation, result.metadata.agent.protocol),
|
|
4534
|
+
contextId: result.metadata.taskId, // Using taskId as context identifier
|
|
4535
|
+
}),
|
|
4536
|
+
},
|
|
4537
|
+
...(deprecationWarnings.length > 0 && { warnings: deprecationWarnings }),
|
|
4538
|
+
},
|
|
4539
|
+
null,
|
|
4540
|
+
2
|
|
4541
|
+
)
|
|
4542
|
+
);
|
|
4543
|
+
} else {
|
|
4544
|
+
// Pretty output
|
|
4545
|
+
console.log('\nā
SUCCESS\n');
|
|
4546
|
+
|
|
4547
|
+
// Show deprecation warnings if any
|
|
4548
|
+
if (deprecationWarnings.length > 0) {
|
|
4549
|
+
for (const warning of deprecationWarnings) {
|
|
4550
|
+
console.log(warning.message);
|
|
4551
|
+
if (warning.formats && warning.formats.length > 0) {
|
|
4552
|
+
const displayFormats = warning.formats.slice(0, 5).join(', ');
|
|
4553
|
+
const remaining = warning.formats.length - 5;
|
|
4554
|
+
console.log(` Affected formats: ${displayFormats}${remaining > 0 ? `, (+${remaining} more)` : ''}`);
|
|
4555
|
+
}
|
|
4556
|
+
console.log('');
|
|
4557
|
+
}
|
|
4558
|
+
}
|
|
4559
|
+
|
|
4560
|
+
// Show protocol message if available
|
|
4561
|
+
if (result.conversation && result.conversation.length > 0) {
|
|
4562
|
+
const message = extractProtocolMessage(result.conversation, result.metadata.agent.protocol);
|
|
4563
|
+
if (message) {
|
|
4564
|
+
console.log('Protocol Message:');
|
|
4565
|
+
console.log(message);
|
|
4566
|
+
console.log('');
|
|
4567
|
+
}
|
|
4568
|
+
}
|
|
4569
|
+
|
|
4570
|
+
console.log('Response:');
|
|
4571
|
+
console.log(JSON.stringify(result.data, null, 2));
|
|
4572
|
+
console.log('');
|
|
4573
|
+
console.log(`Protocol: ${result.metadata.agent.protocol.toUpperCase()}`);
|
|
4574
|
+
console.log(`Response Time: ${result.metadata.responseTimeMs}ms`);
|
|
4575
|
+
console.log(`Task ID: ${result.metadata.taskId}`);
|
|
4576
|
+
if (result.conversation && result.conversation.length > 0) {
|
|
4577
|
+
console.log(`Context ID: ${result.metadata.taskId}`);
|
|
4578
|
+
}
|
|
4579
|
+
}
|
|
4580
|
+
process.exit(0);
|
|
4581
|
+
} else {
|
|
4582
|
+
console.error('\nā TASK FAILED\n');
|
|
4583
|
+
console.error(`Error: ${result.error || 'Unknown error'}`);
|
|
4584
|
+
if (result.metadata?.clarificationRounds) {
|
|
4585
|
+
console.error(`Clarifications: ${result.metadata.clarificationRounds}`);
|
|
4586
|
+
}
|
|
4587
|
+
if (debug) {
|
|
4588
|
+
if (result.metadata) {
|
|
4589
|
+
console.error('\nMetadata:');
|
|
4590
|
+
console.error(JSON.stringify(result.metadata, null, 2));
|
|
4591
|
+
}
|
|
4592
|
+
if (result.debug_logs && result.debug_logs.length > 0) {
|
|
4593
|
+
console.error('\nDebug Logs:');
|
|
4594
|
+
console.error(JSON.stringify(result.debug_logs, null, 2));
|
|
4595
|
+
}
|
|
4596
|
+
if (result.conversation && result.conversation.length > 0) {
|
|
4597
|
+
console.error('\nConversation:');
|
|
4598
|
+
console.error(JSON.stringify(result.conversation, null, 2));
|
|
4599
|
+
}
|
|
4600
|
+
}
|
|
4601
|
+
process.exit(3);
|
|
4602
|
+
}
|
|
4603
|
+
} catch (error) {
|
|
4604
|
+
// Defense-in-depth: the library already strips ASCII control chars from
|
|
4605
|
+
// server-supplied strings before storing them on `requirements`, but
|
|
4606
|
+
// re-apply at the output call site in case a downstream field is added
|
|
4607
|
+
// that bypasses the library's sanitizer.
|
|
4608
|
+
const safe = s => (typeof s === 'string' ? s.replace(/[\x00-\x08\x0b-\x1f\x7f]/g, '') : s);
|
|
4609
|
+
|
|
4610
|
+
// NeedsAuthorizationError carries walked discovery metadata. Route it
|
|
4611
|
+
// through the CLI's existing auto-OAuth flow when conditions are right,
|
|
4612
|
+
// so the user gets a browser prompt instead of a cold error message.
|
|
4613
|
+
if (error instanceof NeedsAuthorizationError) {
|
|
4614
|
+
// Auto-browser requires:
|
|
4615
|
+
// - stdout + stdin are TTYs (the OAuth flow blocks on stdin/terminal focus)
|
|
4616
|
+
// - no explicit opt-out (ADCP_NO_BROWSER) and not in CI
|
|
4617
|
+
// - a protocol we can drive interactively (MCP only today)
|
|
4618
|
+
// - no conflicting auth source already provided
|
|
4619
|
+
// - not asked for JSON (scripts/dashboards must stay deterministic)
|
|
4620
|
+
const canAutoBrowse =
|
|
4621
|
+
!jsonOutput &&
|
|
4622
|
+
!!process.stdout.isTTY &&
|
|
4623
|
+
!!process.stdin.isTTY &&
|
|
4624
|
+
!process.env.CI &&
|
|
4625
|
+
!process.env.ADCP_NO_BROWSER &&
|
|
4626
|
+
process.env.TERM !== 'dumb' &&
|
|
4627
|
+
protocol === 'mcp' &&
|
|
4628
|
+
!useOAuth &&
|
|
4629
|
+
!authToken;
|
|
4630
|
+
|
|
4631
|
+
if (!canAutoBrowse) {
|
|
4632
|
+
if (jsonOutput) {
|
|
4633
|
+
console.log(
|
|
4634
|
+
JSON.stringify(
|
|
4635
|
+
{
|
|
4636
|
+
error: {
|
|
4637
|
+
code: error.code,
|
|
4638
|
+
subCode: error.subCode,
|
|
4639
|
+
message: error.message,
|
|
4640
|
+
requirements: error.requirements,
|
|
4641
|
+
},
|
|
4642
|
+
},
|
|
4643
|
+
null,
|
|
4644
|
+
2
|
|
4645
|
+
)
|
|
4646
|
+
);
|
|
4647
|
+
} else {
|
|
4648
|
+
console.error('\nš Agent requires OAuth authorization.');
|
|
4649
|
+
console.error(` Authorization server: ${safe(error.requirements.authorizationServer) ?? '(unknown)'}`);
|
|
4650
|
+
if (error.requirements.registrationEndpoint) {
|
|
4651
|
+
console.error(` Dynamic client registration: supported`);
|
|
4652
|
+
}
|
|
4653
|
+
if (error.requirements.scopesSupported?.length) {
|
|
4654
|
+
console.error(` Scopes: ${error.requirements.scopesSupported.map(safe).join(', ')}`);
|
|
4655
|
+
}
|
|
4656
|
+
if (agentAlias) {
|
|
4657
|
+
console.error(`\n Run: adcp --save-auth ${agentAlias} ${agentUrl} --oauth`);
|
|
4658
|
+
} else {
|
|
4659
|
+
console.error(`\n Save the agent with OAuth: adcp --save-auth <alias> ${agentUrl} --oauth`);
|
|
4660
|
+
}
|
|
4661
|
+
console.error('');
|
|
4662
|
+
}
|
|
4663
|
+
process.exit(1);
|
|
4664
|
+
}
|
|
4665
|
+
|
|
4666
|
+
// Interactive context: print a short header on stderr (so stdout stays
|
|
4667
|
+
// clean for the eventual tool result) then fall through to the
|
|
4668
|
+
// auto-OAuth branch below which opens the browser and retries the call.
|
|
4669
|
+
console.error('\nš Agent requires OAuth authorization.');
|
|
4670
|
+
if (error.requirements.authorizationServer) {
|
|
4671
|
+
console.error(` Authorization server: ${safe(error.requirements.authorizationServer)}`);
|
|
4672
|
+
}
|
|
4673
|
+
if (error.requirements.scopesSupported?.length) {
|
|
4674
|
+
console.error(` Scopes: ${error.requirements.scopesSupported.map(safe).join(', ')}`);
|
|
4675
|
+
}
|
|
4676
|
+
// Let execution fall through to the auto-OAuth path below.
|
|
4677
|
+
}
|
|
4678
|
+
|
|
4679
|
+
// Check if this is an OAuth-required error for MCP and offer auto-authentication.
|
|
4680
|
+
// `NeedsAuthorizationError` is the richer form (already extended from
|
|
4681
|
+
// AuthenticationRequiredError); the string-match branches cover older
|
|
4682
|
+
// error shapes from the MCP SDK and other 401 paths.
|
|
4683
|
+
const isUnauthorized =
|
|
4684
|
+
error instanceof NeedsAuthorizationError ||
|
|
4685
|
+
error.name === 'UnauthorizedError' ||
|
|
4686
|
+
error.message?.toLowerCase().includes('unauthorized') ||
|
|
4687
|
+
error.message?.includes('401');
|
|
4688
|
+
|
|
4689
|
+
if (isUnauthorized && protocol === 'mcp' && !useOAuth && !authToken) {
|
|
4690
|
+
console.log('\nš Server requires authentication.');
|
|
4691
|
+
console.log('Starting OAuth authentication...\n');
|
|
4692
|
+
|
|
4693
|
+
// Run OAuth flow automatically
|
|
4694
|
+
const { Client: MCPClient } = require('@modelcontextprotocol/sdk/client/index.js');
|
|
4695
|
+
const { StreamableHTTPClientTransport } = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
|
|
4696
|
+
const { UnauthorizedError } = require('@modelcontextprotocol/sdk/client/auth.js');
|
|
4697
|
+
|
|
4698
|
+
const oauthProvider = createCLIOAuthProvider(agentConfig, { quiet: jsonOutput });
|
|
4699
|
+
const mcpClient = new MCPClient({ name: 'adcp-cli', version: '1.0.0' });
|
|
4700
|
+
const createTransport = () =>
|
|
4701
|
+
new StreamableHTTPClientTransport(new URL(agentUrl), { authProvider: oauthProvider });
|
|
4702
|
+
|
|
4703
|
+
let transport = createTransport();
|
|
4704
|
+
|
|
4705
|
+
try {
|
|
4706
|
+
await mcpClient.connect(transport);
|
|
4707
|
+
} catch (connectError) {
|
|
4708
|
+
if (connectError instanceof UnauthorizedError || connectError.name === 'UnauthorizedError') {
|
|
4709
|
+
console.log('Opening browser for authentication...\n');
|
|
4710
|
+
const code = await oauthProvider.waitForCallback();
|
|
4711
|
+
console.log('Authorization received!');
|
|
4712
|
+
await transport.finishAuth(code);
|
|
4713
|
+
|
|
4714
|
+
// Save tokens if using a saved alias
|
|
4715
|
+
if (agentAlias && agentConfig.oauth_tokens) {
|
|
4716
|
+
const savedConfig = getAgent(agentAlias);
|
|
4717
|
+
savedConfig.oauth_tokens = agentConfig.oauth_tokens;
|
|
4718
|
+
savedConfig.oauth_client = agentConfig.oauth_client;
|
|
4719
|
+
saveAgent(agentAlias, savedConfig);
|
|
4720
|
+
console.log(`OAuth tokens saved to '${agentAlias}'.\n`);
|
|
4721
|
+
}
|
|
4722
|
+
|
|
4723
|
+
// Reconnect and execute
|
|
4724
|
+
console.log('Reconnecting with OAuth tokens...');
|
|
4725
|
+
transport = createTransport();
|
|
4726
|
+
await mcpClient.connect(transport);
|
|
4727
|
+
console.log('Connected!\n');
|
|
4728
|
+
|
|
4729
|
+
// Execute the tool if specified
|
|
4730
|
+
if (toolName) {
|
|
4731
|
+
const startTime = Date.now();
|
|
4732
|
+
const toolResult = await mcpClient.callTool({ name: toolName, arguments: payload });
|
|
4733
|
+
const responseTime = Date.now() - startTime;
|
|
4734
|
+
|
|
4735
|
+
await oauthProvider.cleanup();
|
|
4736
|
+
await mcpClient.close();
|
|
4737
|
+
|
|
4738
|
+
let resultData = toolResult;
|
|
4739
|
+
if (toolResult.content && Array.isArray(toolResult.content)) {
|
|
4740
|
+
const textContent = toolResult.content.find(c => c.type === 'text');
|
|
4741
|
+
if (textContent && textContent.text) {
|
|
4742
|
+
try {
|
|
4743
|
+
resultData = JSON.parse(textContent.text);
|
|
4744
|
+
} catch {
|
|
4745
|
+
resultData = textContent.text;
|
|
4746
|
+
}
|
|
4747
|
+
}
|
|
4748
|
+
}
|
|
4749
|
+
|
|
4750
|
+
if (jsonOutput) {
|
|
4751
|
+
console.log(
|
|
4752
|
+
JSON.stringify(
|
|
4753
|
+
{
|
|
4754
|
+
data: resultData,
|
|
4755
|
+
metadata: { protocol: 'mcp', responseTimeMs: responseTime, oauth: true },
|
|
4756
|
+
},
|
|
4757
|
+
null,
|
|
4758
|
+
2
|
|
4759
|
+
)
|
|
4760
|
+
);
|
|
4761
|
+
} else {
|
|
4762
|
+
console.log('\nā
SUCCESS\n');
|
|
4763
|
+
console.log('Response:');
|
|
4764
|
+
console.log(JSON.stringify(resultData, null, 2));
|
|
4765
|
+
console.log('');
|
|
4766
|
+
console.log(`Protocol: MCP (OAuth)`);
|
|
4767
|
+
console.log(`Response Time: ${responseTime}ms`);
|
|
4768
|
+
}
|
|
4769
|
+
process.exit(0);
|
|
4770
|
+
} else {
|
|
4771
|
+
// List tools
|
|
4772
|
+
const toolsResult = await mcpClient.listTools();
|
|
4773
|
+
await oauthProvider.cleanup();
|
|
4774
|
+
await mcpClient.close();
|
|
4775
|
+
|
|
4776
|
+
if (jsonOutput) {
|
|
4777
|
+
console.log(JSON.stringify({ tools: toolsResult.tools, protocol: 'mcp', oauth: true }, null, 2));
|
|
4778
|
+
} else {
|
|
4779
|
+
console.log(`\nš Agent Information (OAuth)\n`);
|
|
4780
|
+
console.log(`Protocol: MCP`);
|
|
4781
|
+
console.log(`URL: ${agentUrl}`);
|
|
4782
|
+
console.log(`\nAvailable Tools (${toolsResult.tools.length}):\n`);
|
|
4783
|
+
toolsResult.tools.forEach((tool, i) => {
|
|
4784
|
+
console.log(`${i + 1}. ${tool.name}`);
|
|
4785
|
+
if (tool.description) console.log(` ${tool.description}`);
|
|
4786
|
+
console.log('');
|
|
4787
|
+
});
|
|
4788
|
+
}
|
|
4789
|
+
process.exit(0);
|
|
4790
|
+
}
|
|
4791
|
+
} else {
|
|
4792
|
+
await oauthProvider.cleanup();
|
|
4793
|
+
throw connectError;
|
|
4794
|
+
}
|
|
4795
|
+
}
|
|
4796
|
+
}
|
|
4797
|
+
|
|
4798
|
+
console.error('\nā ERROR\n');
|
|
4799
|
+
console.error(error.message);
|
|
4800
|
+
if (debug) {
|
|
4801
|
+
console.error('\nStack trace:');
|
|
4802
|
+
console.error(error.stack);
|
|
4803
|
+
}
|
|
4804
|
+
process.exit(1);
|
|
4805
|
+
}
|
|
4806
|
+
}
|
|
4807
|
+
|
|
4808
|
+
// Clean up cached MCP connections before exit to avoid hanging
|
|
4809
|
+
process.on('beforeExit', async () => {
|
|
4810
|
+
try {
|
|
4811
|
+
const { closeMCPConnections } = require('../dist/lib/protocols/mcp.js');
|
|
4812
|
+
await closeMCPConnections();
|
|
4813
|
+
} catch {
|
|
4814
|
+
/* ignore */
|
|
4815
|
+
}
|
|
4816
|
+
});
|
|
4817
|
+
|
|
4818
|
+
main().catch(error => {
|
|
4819
|
+
console.error('FATAL ERROR:', error.message);
|
|
4820
|
+
process.exit(1);
|
|
4821
|
+
});
|