@codespar/cli 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/package.json +1 -1
- package/templates/bills-agent/README.md +1 -1
- package/templates/bills-agent/agents/bills-agent/AGENTS.md +1 -1
- package/templates/bills-agent/agents/bills-agent/CLAUDE.md +1 -1
- package/templates/bills-agent/agents/bills-agent/README.md +6 -5
- package/templates/bills-agent/agents/bills-agent/src/modules/embedded-consent.ts +5 -4
- package/templates/bills-agent/packages/agent-core/README.md +14 -1
- package/templates/bills-agent/packages/agent-core/package.json +1 -1
- package/templates/bills-agent/packages/agent-core/src/agent.ts +39 -1
- package/templates/bills-agent/packages/agent-core/src/api/charge-rail.ts +54 -34
- package/templates/bills-agent/packages/agent-core/src/api/client.ts +28 -5
- package/templates/bills-agent/packages/agent-core/src/api/mandate-status.ts +28 -12
- package/templates/bills-agent/packages/agent-core/src/api/rail.ts +62 -26
- package/templates/bills-agent/packages/agent-core/src/api/sandbox-payer.ts +3 -18
- package/templates/bills-agent/packages/agent-core/src/approval.ts +14 -2
- package/templates/bills-agent/packages/agent-core/src/bundle.ts +35 -3
- package/templates/bills-agent/packages/agent-core/src/channels.ts +49 -3
- package/templates/bills-agent/packages/agent-core/src/check.ts +25 -2
- package/templates/bills-agent/packages/agent-core/src/engine.ts +235 -46
- package/templates/bills-agent/packages/agent-core/src/hash.ts +57 -1
- package/templates/bills-agent/packages/agent-core/src/index.ts +2 -0
- package/templates/bills-agent/packages/agent-core/src/quote.ts +50 -0
- package/templates/bills-agent/packages/agent-core/src/rail.ts +89 -4
- package/templates/bills-agent/packages/agent-core/src/receipt-chain.ts +270 -0
- package/templates/bills-agent/packages/agent-core/src/receipt-verification.ts +194 -18
- package/templates/bills-agent/packages/agent-core/src/revocation.ts +1 -1
- package/templates/bills-agent/packages/agent-core/src/state-machine.ts +10 -1
- package/templates/bills-agent/packages/agent-core/src/stubs/mandate-status.ts +4 -3
- package/templates/bills-agent/packages/agent-core/src/stubs/rail.ts +100 -32
- package/templates/bills-agent/packages/agent-core/src/tools.ts +17 -6
- package/templates/bills-agent/packages/agent-core/src/types.ts +54 -1
- package/templates/bills-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
- package/templates/bills-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
- package/templates/bills-agent/packages/agent-core/test/composition.test.ts +204 -0
- package/templates/bills-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
- package/templates/bills-agent/packages/agent-core/test/helpers.ts +4 -1
- package/templates/bills-agent/packages/agent-core/test/mandate-status.test.ts +85 -9
- package/templates/bills-agent/packages/agent-core/test/quote.test.ts +198 -0
- package/templates/bills-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
- package/templates/bills-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
- package/templates/bills-agent/packages/agent-core/test/receivables.test.ts +103 -3
- package/templates/bills-agent/packages/agent-runtime/README.md +12 -0
- package/templates/bills-agent/packages/agent-runtime/src/adversarial.ts +32 -2
- package/templates/bills-agent/packages/agent-runtime/src/channels/types.ts +53 -4
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +123 -22
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +30 -20
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +146 -21
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +40 -3
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -1
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +16 -2
- package/templates/bills-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +70 -20
- package/templates/bills-agent/packages/agent-runtime/src/commands/poll.ts +2 -1
- package/templates/bills-agent/packages/agent-runtime/src/commands/resume.ts +8 -2
- package/templates/bills-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +3 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/start.ts +6 -3
- package/templates/bills-agent/packages/agent-runtime/src/commands/verify.ts +239 -38
- package/templates/bills-agent/packages/agent-runtime/src/commands/webhook.ts +3 -2
- package/templates/bills-agent/packages/agent-runtime/src/index.ts +1 -0
- package/templates/bills-agent/packages/agent-runtime/src/inspect.ts +5 -1
- package/templates/bills-agent/packages/agent-runtime/src/kit.ts +25 -2
- package/templates/bills-agent/packages/agent-runtime/src/scenarios.ts +8 -2
- package/templates/bills-agent/packages/agent-runtime/src/setup.ts +13 -3
- package/templates/bills-agent/packages/agent-runtime/src/terminal.ts +127 -18
- package/templates/bills-agent/packages/agent-runtime/test/verify-cli.test.ts +211 -9
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +45 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-session.test.ts +32 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
- package/templates/checkout-agent/LICENSE +21 -0
- package/templates/checkout-agent/README.md +28 -0
- package/templates/checkout-agent/_gitignore +10 -0
- package/templates/checkout-agent/agents/checkout-agent/.env.example +5 -0
- package/templates/checkout-agent/agents/checkout-agent/AGENTS.md +20 -0
- package/templates/checkout-agent/agents/checkout-agent/CLAUDE.md +20 -0
- package/templates/checkout-agent/agents/checkout-agent/README.md +94 -0
- package/templates/checkout-agent/agents/checkout-agent/SYSTEM_PROMPT.md +36 -0
- package/templates/checkout-agent/agents/checkout-agent/agent.yaml +30 -0
- package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/README.md +28 -0
- package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/pedido-beatriz.json +11 -0
- package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/pedido-marina-retomada.json +10 -0
- package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/pedido-marina.json +11 -0
- package/templates/checkout-agent/agents/checkout-agent/channels/whatsapp/templates.json +49 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap-human.json +12 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap.json +11 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/beneficiary-swap.transcript.jsonl +5 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/coupon-unknown.json +13 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/coupon-unknown.transcript.jsonl +4 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/exfiltration.json +26 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/exfiltration.transcript.jsonl +3 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/false-authority.json +11 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/false-authority.transcript.jsonl +5 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/fractioning.json +12 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/fractioning.transcript.jsonl +5 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/model-total.json +13 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/model-total.transcript.jsonl +5 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/payment-claimed.json +15 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/payment-claimed.transcript.jsonl +7 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/price-injected.json +12 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/price-injected.transcript.jsonl +5 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/prompt-injection.json +13 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/prompt-injection.transcript.jsonl +4 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped-human.json +16 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped-human.transcript.jsonl +9 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped.json +15 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/quantity-swapped.transcript.jsonl +8 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/adversarial/webhook-replay.json +11 -0
- package/templates/checkout-agent/agents/checkout-agent/evals/eval.yaml +11 -0
- package/templates/checkout-agent/agents/checkout-agent/guardrails.json +25 -0
- package/templates/checkout-agent/agents/checkout-agent/mandate.example.json +28 -0
- package/templates/checkout-agent/agents/checkout-agent/package.json +33 -0
- package/templates/checkout-agent/agents/checkout-agent/runbook.md +19 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/beneficiary-not-allowed.json +42 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +4 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/cap-exceeded.json +32 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/cap-exceeded.transcript.jsonl +4 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-recomposed.json +61 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-recomposed.transcript.jsonl +9 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-replaced.json +61 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/cart-replaced.transcript.jsonl +9 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/charge-expired.json +36 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/charge-expired.transcript.jsonl +6 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/coupon-unknown.json +23 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/coupon-unknown.transcript.jsonl +4 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/escalated-above-threshold.json +72 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/escalated-above-threshold.transcript.jsonl +9 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/happy-path.json +15 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/happy-path.transcript.jsonl +6 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/item-unavailable.json +23 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/item-unavailable.transcript.jsonl +3 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/mandate-revoked.json +42 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/mandate-revoked.transcript.jsonl +12 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/nfse-failed.json +14 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/nfse-failed.transcript.jsonl +9 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/payment-claimed.json +34 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/payment-claimed.transcript.jsonl +7 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/price-injected.json +33 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/price-injected.transcript.jsonl +4 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/prompt-injection.json +32 -0
- package/templates/checkout-agent/agents/checkout-agent/scenarios/prompt-injection.transcript.jsonl +4 -0
- package/templates/checkout-agent/agents/checkout-agent/src/catalog.ts +92 -0
- package/templates/checkout-agent/agents/checkout-agent/src/kit.ts +338 -0
- package/templates/checkout-agent/agents/checkout-agent/src/modules/bolepix-receivables.ts +179 -0
- package/templates/checkout-agent/agents/checkout-agent/src/modules/nfse-invoice.ts +374 -0
- package/templates/checkout-agent/agents/checkout-agent/src/modules/storefront-cart.ts +220 -0
- package/templates/checkout-agent/agents/checkout-agent/src/pricing.ts +297 -0
- package/templates/checkout-agent/agents/checkout-agent/test/adversarial.test.ts +117 -0
- package/templates/checkout-agent/agents/checkout-agent/test/check.test.ts +67 -0
- package/templates/checkout-agent/agents/checkout-agent/test/cli.test.ts +169 -0
- package/templates/checkout-agent/agents/checkout-agent/test/fixtures/order-marina.transcript.jsonl +5 -0
- package/templates/checkout-agent/agents/checkout-agent/test/fixtures/ordered-marina-awaiting-payer.transcript.jsonl +6 -0
- package/templates/checkout-agent/agents/checkout-agent/test/fixtures/tap-falar-agora-marina.transcript.jsonl +2 -0
- package/templates/checkout-agent/agents/checkout-agent/test/nfse.test.ts +170 -0
- package/templates/checkout-agent/agents/checkout-agent/test/pricing.test.ts +138 -0
- package/templates/checkout-agent/agents/checkout-agent/test/scenarios.test.ts +113 -0
- package/templates/checkout-agent/agents/checkout-agent/test/whatsapp.test.ts +171 -0
- package/templates/checkout-agent/agents/checkout-agent/tools.json +68 -0
- package/templates/checkout-agent/agents/checkout-agent/tsconfig.json +10 -0
- package/templates/checkout-agent/package.json +38 -0
- package/templates/checkout-agent/packages/agent-core/README.md +34 -0
- package/templates/checkout-agent/packages/agent-core/package.json +24 -0
- package/templates/checkout-agent/packages/agent-core/src/agent.ts +163 -0
- package/templates/checkout-agent/packages/agent-core/src/api/charge-rail.ts +195 -0
- package/templates/checkout-agent/packages/agent-core/src/api/client.ts +76 -0
- package/templates/checkout-agent/packages/agent-core/src/api/mandate-status.ts +74 -0
- package/templates/checkout-agent/packages/agent-core/src/api/rail.ts +153 -0
- package/templates/checkout-agent/packages/agent-core/src/api/sandbox-payer.ts +43 -0
- package/templates/checkout-agent/packages/agent-core/src/approval.ts +135 -0
- package/templates/checkout-agent/packages/agent-core/src/bundle.ts +191 -0
- package/templates/checkout-agent/packages/agent-core/src/channels.ts +186 -0
- package/templates/checkout-agent/packages/agent-core/src/check.ts +276 -0
- package/templates/checkout-agent/packages/agent-core/src/clock.ts +42 -0
- package/templates/checkout-agent/packages/agent-core/src/engine.ts +1074 -0
- package/templates/checkout-agent/packages/agent-core/src/escalate.ts +85 -0
- package/templates/checkout-agent/packages/agent-core/src/events.ts +40 -0
- package/templates/checkout-agent/packages/agent-core/src/guardrails.ts +45 -0
- package/templates/checkout-agent/packages/agent-core/src/hash.ts +118 -0
- package/templates/checkout-agent/packages/agent-core/src/ids.ts +10 -0
- package/templates/checkout-agent/packages/agent-core/src/index.ts +34 -0
- package/templates/checkout-agent/packages/agent-core/src/mandate.ts +100 -0
- package/templates/checkout-agent/packages/agent-core/src/manifest.ts +76 -0
- package/templates/checkout-agent/packages/agent-core/src/providers/anthropic.ts +76 -0
- package/templates/checkout-agent/packages/agent-core/src/providers/replay.ts +63 -0
- package/templates/checkout-agent/packages/agent-core/src/providers/types.ts +39 -0
- package/templates/checkout-agent/packages/agent-core/src/quote.ts +50 -0
- package/templates/checkout-agent/packages/agent-core/src/rail.ts +186 -0
- package/templates/checkout-agent/packages/agent-core/src/receipt-chain.ts +270 -0
- package/templates/checkout-agent/packages/agent-core/src/receipt-verification.ts +577 -0
- package/templates/checkout-agent/packages/agent-core/src/revocation.ts +30 -0
- package/templates/checkout-agent/packages/agent-core/src/secrets.ts +30 -0
- package/templates/checkout-agent/packages/agent-core/src/state/store.ts +307 -0
- package/templates/checkout-agent/packages/agent-core/src/state-machine.ts +157 -0
- package/templates/checkout-agent/packages/agent-core/src/stubs/charge-rail.ts +195 -0
- package/templates/checkout-agent/packages/agent-core/src/stubs/mandate-status.ts +58 -0
- package/templates/checkout-agent/packages/agent-core/src/stubs/rail.ts +209 -0
- package/templates/checkout-agent/packages/agent-core/src/tools.ts +66 -0
- package/templates/checkout-agent/packages/agent-core/src/types.ts +187 -0
- package/templates/checkout-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
- package/templates/checkout-agent/packages/agent-core/test/approval.test.ts +117 -0
- package/templates/checkout-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
- package/templates/checkout-agent/packages/agent-core/test/bundle.test.ts +85 -0
- package/templates/checkout-agent/packages/agent-core/test/clock.test.ts +25 -0
- package/templates/checkout-agent/packages/agent-core/test/composition.test.ts +204 -0
- package/templates/checkout-agent/packages/agent-core/test/engine.test.ts +596 -0
- package/templates/checkout-agent/packages/agent-core/test/escalate.test.ts +42 -0
- package/templates/checkout-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
- package/templates/checkout-agent/packages/agent-core/test/fixtures/staging-receipt-keys.json +18 -0
- package/templates/checkout-agent/packages/agent-core/test/fixtures/staging-receipt.json +24 -0
- package/templates/checkout-agent/packages/agent-core/test/helpers.ts +142 -0
- package/templates/checkout-agent/packages/agent-core/test/mandate-status.test.ts +229 -0
- package/templates/checkout-agent/packages/agent-core/test/manifest.test.ts +45 -0
- package/templates/checkout-agent/packages/agent-core/test/quote.test.ts +198 -0
- package/templates/checkout-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
- package/templates/checkout-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
- package/templates/checkout-agent/packages/agent-core/test/receipt-verification.test.ts +316 -0
- package/templates/checkout-agent/packages/agent-core/test/receivables.test.ts +416 -0
- package/templates/checkout-agent/packages/agent-core/test/secrets.test.ts +28 -0
- package/templates/checkout-agent/packages/agent-core/test/state-machine.test.ts +67 -0
- package/templates/checkout-agent/packages/agent-core/test/transitions.type-test.ts +59 -0
- package/templates/checkout-agent/packages/agent-core/tsconfig.json +10 -0
- package/templates/checkout-agent/packages/agent-runtime/README.md +80 -0
- package/templates/checkout-agent/packages/agent-runtime/bin.mjs +32 -0
- package/templates/checkout-agent/packages/agent-runtime/package.json +23 -0
- package/templates/checkout-agent/packages/agent-runtime/src/adversarial.ts +199 -0
- package/templates/checkout-agent/packages/agent-runtime/src/agent.ts +68 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/contact.ts +13 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/index.ts +72 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/rules.ts +120 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/types.ts +173 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +459 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +216 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/evidence.ts +109 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +350 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +180 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +47 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +120 -0
- package/templates/checkout-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +127 -0
- package/templates/checkout-agent/packages/agent-runtime/src/cli.ts +98 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/check.ts +15 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/decide.ts +63 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/eval.ts +58 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/inspect.ts +100 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +367 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/poll.ts +145 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/reconcile.ts +42 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/rerun.ts +86 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/resume.ts +49 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +134 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/start.ts +248 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/verify.ts +330 -0
- package/templates/checkout-agent/packages/agent-runtime/src/commands/webhook.ts +40 -0
- package/templates/checkout-agent/packages/agent-runtime/src/default-kit.ts +83 -0
- package/templates/checkout-agent/packages/agent-runtime/src/index.ts +13 -0
- package/templates/checkout-agent/packages/agent-runtime/src/inspect.ts +801 -0
- package/templates/checkout-agent/packages/agent-runtime/src/kit.ts +229 -0
- package/templates/checkout-agent/packages/agent-runtime/src/poll.ts +105 -0
- package/templates/checkout-agent/packages/agent-runtime/src/scenarios.ts +274 -0
- package/templates/checkout-agent/packages/agent-runtime/src/setup.ts +239 -0
- package/templates/checkout-agent/packages/agent-runtime/src/terminal.ts +263 -0
- package/templates/checkout-agent/packages/agent-runtime/src/webhook.ts +131 -0
- package/templates/checkout-agent/packages/agent-runtime/test/inspect.test.ts +336 -0
- package/templates/checkout-agent/packages/agent-runtime/test/verify-cli.test.ts +329 -0
- package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +277 -0
- package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-evidence.test.ts +94 -0
- package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +174 -0
- package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-session.test.ts +167 -0
- package/templates/checkout-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
- package/templates/checkout-agent/packages/agent-runtime/tsconfig.json +9 -0
- package/templates/checkout-agent/scripts/whatsapp-emulator.mjs +84 -0
- package/templates/checkout-agent/tsconfig.base.json +16 -0
- package/templates/checkout-agent/vitest.config.ts +12 -0
- package/templates/collections-agent/README.md +6 -1
- package/templates/collections-agent/agents/collections-agent/README.md +12 -8
- package/templates/collections-agent/agents/collections-agent/channels/whatsapp/README.md +8 -0
- package/templates/collections-agent/agents/collections-agent/channels/whatsapp/acordo-1042-retomada.json +10 -0
- package/templates/collections-agent/agents/collections-agent/channels/whatsapp/templates.json +27 -1
- package/templates/collections-agent/agents/collections-agent/src/kit.ts +2 -0
- package/templates/collections-agent/agents/collections-agent/src/modules/bolepix-receivables.ts +12 -2
- package/templates/collections-agent/agents/collections-agent/test/ambiguous-charge.test.ts +55 -0
- package/templates/collections-agent/agents/collections-agent/test/fixtures/tap-emitir-nova-1042.transcript.jsonl +2 -0
- package/templates/collections-agent/agents/collections-agent/test/whatsapp-poll.test.ts +12 -6
- package/templates/collections-agent/agents/collections-agent/test/whatsapp-status-replies.test.ts +148 -0
- package/templates/collections-agent/agents/collections-agent/test/whatsapp.test.ts +5 -0
- package/templates/collections-agent/package.json +1 -0
- package/templates/collections-agent/packages/agent-core/README.md +14 -1
- package/templates/collections-agent/packages/agent-core/package.json +1 -1
- package/templates/collections-agent/packages/agent-core/src/agent.ts +39 -1
- package/templates/collections-agent/packages/agent-core/src/api/charge-rail.ts +54 -34
- package/templates/collections-agent/packages/agent-core/src/api/client.ts +28 -5
- package/templates/collections-agent/packages/agent-core/src/api/mandate-status.ts +28 -12
- package/templates/collections-agent/packages/agent-core/src/api/rail.ts +62 -26
- package/templates/collections-agent/packages/agent-core/src/api/sandbox-payer.ts +3 -18
- package/templates/collections-agent/packages/agent-core/src/approval.ts +14 -2
- package/templates/collections-agent/packages/agent-core/src/bundle.ts +35 -3
- package/templates/collections-agent/packages/agent-core/src/channels.ts +49 -3
- package/templates/collections-agent/packages/agent-core/src/check.ts +25 -2
- package/templates/collections-agent/packages/agent-core/src/engine.ts +235 -46
- package/templates/collections-agent/packages/agent-core/src/hash.ts +57 -1
- package/templates/collections-agent/packages/agent-core/src/index.ts +2 -0
- package/templates/collections-agent/packages/agent-core/src/quote.ts +50 -0
- package/templates/collections-agent/packages/agent-core/src/rail.ts +89 -4
- package/templates/collections-agent/packages/agent-core/src/receipt-chain.ts +270 -0
- package/templates/collections-agent/packages/agent-core/src/receipt-verification.ts +194 -18
- package/templates/collections-agent/packages/agent-core/src/revocation.ts +1 -1
- package/templates/collections-agent/packages/agent-core/src/state-machine.ts +10 -1
- package/templates/collections-agent/packages/agent-core/src/stubs/mandate-status.ts +4 -3
- package/templates/collections-agent/packages/agent-core/src/stubs/rail.ts +100 -32
- package/templates/collections-agent/packages/agent-core/src/tools.ts +17 -6
- package/templates/collections-agent/packages/agent-core/src/types.ts +54 -1
- package/templates/collections-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
- package/templates/collections-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
- package/templates/collections-agent/packages/agent-core/test/composition.test.ts +204 -0
- package/templates/collections-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
- package/templates/collections-agent/packages/agent-core/test/helpers.ts +4 -1
- package/templates/collections-agent/packages/agent-core/test/mandate-status.test.ts +85 -9
- package/templates/collections-agent/packages/agent-core/test/quote.test.ts +198 -0
- package/templates/collections-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
- package/templates/collections-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
- package/templates/collections-agent/packages/agent-core/test/receivables.test.ts +103 -3
- package/templates/collections-agent/packages/agent-runtime/README.md +12 -0
- package/templates/collections-agent/packages/agent-runtime/src/adversarial.ts +32 -2
- package/templates/collections-agent/packages/agent-runtime/src/channels/types.ts +53 -4
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +123 -22
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +30 -20
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +146 -21
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +40 -3
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -1
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +16 -2
- package/templates/collections-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +70 -20
- package/templates/collections-agent/packages/agent-runtime/src/commands/poll.ts +2 -1
- package/templates/collections-agent/packages/agent-runtime/src/commands/resume.ts +8 -2
- package/templates/collections-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +3 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/start.ts +6 -3
- package/templates/collections-agent/packages/agent-runtime/src/commands/verify.ts +239 -38
- package/templates/collections-agent/packages/agent-runtime/src/commands/webhook.ts +3 -2
- package/templates/collections-agent/packages/agent-runtime/src/index.ts +1 -0
- package/templates/collections-agent/packages/agent-runtime/src/inspect.ts +5 -1
- package/templates/collections-agent/packages/agent-runtime/src/kit.ts +25 -2
- package/templates/collections-agent/packages/agent-runtime/src/scenarios.ts +8 -2
- package/templates/collections-agent/packages/agent-runtime/src/setup.ts +13 -3
- package/templates/collections-agent/packages/agent-runtime/src/terminal.ts +127 -18
- package/templates/collections-agent/packages/agent-runtime/test/verify-cli.test.ts +211 -9
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +45 -0
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-session.test.ts +32 -0
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
- package/templates/collections-agent/scripts/whatsapp-emulator.mjs +84 -0
- package/templates/hello-agent/README.md +1 -1
- package/templates/hello-agent/packages/agent-core/README.md +14 -1
- package/templates/hello-agent/packages/agent-core/package.json +1 -1
- package/templates/hello-agent/packages/agent-core/src/agent.ts +39 -1
- package/templates/hello-agent/packages/agent-core/src/api/charge-rail.ts +54 -34
- package/templates/hello-agent/packages/agent-core/src/api/client.ts +28 -5
- package/templates/hello-agent/packages/agent-core/src/api/mandate-status.ts +28 -12
- package/templates/hello-agent/packages/agent-core/src/api/rail.ts +62 -26
- package/templates/hello-agent/packages/agent-core/src/api/sandbox-payer.ts +3 -18
- package/templates/hello-agent/packages/agent-core/src/approval.ts +14 -2
- package/templates/hello-agent/packages/agent-core/src/bundle.ts +35 -3
- package/templates/hello-agent/packages/agent-core/src/channels.ts +49 -3
- package/templates/hello-agent/packages/agent-core/src/check.ts +25 -2
- package/templates/hello-agent/packages/agent-core/src/engine.ts +235 -46
- package/templates/hello-agent/packages/agent-core/src/hash.ts +57 -1
- package/templates/hello-agent/packages/agent-core/src/index.ts +2 -0
- package/templates/hello-agent/packages/agent-core/src/quote.ts +50 -0
- package/templates/hello-agent/packages/agent-core/src/rail.ts +89 -4
- package/templates/hello-agent/packages/agent-core/src/receipt-chain.ts +270 -0
- package/templates/hello-agent/packages/agent-core/src/receipt-verification.ts +194 -18
- package/templates/hello-agent/packages/agent-core/src/revocation.ts +1 -1
- package/templates/hello-agent/packages/agent-core/src/state-machine.ts +10 -1
- package/templates/hello-agent/packages/agent-core/src/stubs/mandate-status.ts +4 -3
- package/templates/hello-agent/packages/agent-core/src/stubs/rail.ts +100 -32
- package/templates/hello-agent/packages/agent-core/src/tools.ts +17 -6
- package/templates/hello-agent/packages/agent-core/src/types.ts +54 -1
- package/templates/hello-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
- package/templates/hello-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
- package/templates/hello-agent/packages/agent-core/test/composition.test.ts +204 -0
- package/templates/hello-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
- package/templates/hello-agent/packages/agent-core/test/helpers.ts +4 -1
- package/templates/hello-agent/packages/agent-core/test/mandate-status.test.ts +85 -9
- package/templates/hello-agent/packages/agent-core/test/quote.test.ts +198 -0
- package/templates/hello-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
- package/templates/hello-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
- package/templates/hello-agent/packages/agent-core/test/receivables.test.ts +103 -3
- package/templates/hello-agent/packages/agent-runtime/README.md +12 -0
- package/templates/hello-agent/packages/agent-runtime/src/adversarial.ts +32 -2
- package/templates/hello-agent/packages/agent-runtime/src/channels/types.ts +53 -4
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +123 -22
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +30 -20
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +146 -21
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +40 -3
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -1
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +16 -2
- package/templates/hello-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +70 -20
- package/templates/hello-agent/packages/agent-runtime/src/commands/poll.ts +2 -1
- package/templates/hello-agent/packages/agent-runtime/src/commands/resume.ts +8 -2
- package/templates/hello-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +3 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/start.ts +6 -3
- package/templates/hello-agent/packages/agent-runtime/src/commands/verify.ts +239 -38
- package/templates/hello-agent/packages/agent-runtime/src/commands/webhook.ts +3 -2
- package/templates/hello-agent/packages/agent-runtime/src/index.ts +1 -0
- package/templates/hello-agent/packages/agent-runtime/src/inspect.ts +5 -1
- package/templates/hello-agent/packages/agent-runtime/src/kit.ts +25 -2
- package/templates/hello-agent/packages/agent-runtime/src/scenarios.ts +8 -2
- package/templates/hello-agent/packages/agent-runtime/src/setup.ts +13 -3
- package/templates/hello-agent/packages/agent-runtime/src/terminal.ts +127 -18
- package/templates/hello-agent/packages/agent-runtime/test/verify-cli.test.ts +211 -9
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +45 -0
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-session.test.ts +32 -0
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
- package/templates/kits.lock.json +29 -6
- package/templates/supplier-payments-agent/README.md +1 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/AGENTS.md +1 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/CLAUDE.md +1 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/README.md +11 -9
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/kit.ts +1 -1
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/batch-payout.ts +67 -20
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/batch.test.ts +504 -5
- package/templates/supplier-payments-agent/packages/agent-core/README.md +14 -1
- package/templates/supplier-payments-agent/packages/agent-core/package.json +1 -1
- package/templates/supplier-payments-agent/packages/agent-core/src/agent.ts +39 -1
- package/templates/supplier-payments-agent/packages/agent-core/src/api/charge-rail.ts +54 -34
- package/templates/supplier-payments-agent/packages/agent-core/src/api/client.ts +28 -5
- package/templates/supplier-payments-agent/packages/agent-core/src/api/mandate-status.ts +28 -12
- package/templates/supplier-payments-agent/packages/agent-core/src/api/rail.ts +62 -26
- package/templates/supplier-payments-agent/packages/agent-core/src/api/sandbox-payer.ts +3 -18
- package/templates/supplier-payments-agent/packages/agent-core/src/approval.ts +14 -2
- package/templates/supplier-payments-agent/packages/agent-core/src/bundle.ts +35 -3
- package/templates/supplier-payments-agent/packages/agent-core/src/channels.ts +49 -3
- package/templates/supplier-payments-agent/packages/agent-core/src/check.ts +25 -2
- package/templates/supplier-payments-agent/packages/agent-core/src/engine.ts +235 -46
- package/templates/supplier-payments-agent/packages/agent-core/src/hash.ts +57 -1
- package/templates/supplier-payments-agent/packages/agent-core/src/index.ts +2 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/quote.ts +50 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/rail.ts +89 -4
- package/templates/supplier-payments-agent/packages/agent-core/src/receipt-chain.ts +270 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/receipt-verification.ts +194 -18
- package/templates/supplier-payments-agent/packages/agent-core/src/revocation.ts +1 -1
- package/templates/supplier-payments-agent/packages/agent-core/src/state-machine.ts +10 -1
- package/templates/supplier-payments-agent/packages/agent-core/src/stubs/mandate-status.ts +4 -3
- package/templates/supplier-payments-agent/packages/agent-core/src/stubs/rail.ts +100 -32
- package/templates/supplier-payments-agent/packages/agent-core/src/tools.ts +17 -6
- package/templates/supplier-payments-agent/packages/agent-core/src/types.ts +54 -1
- package/templates/supplier-payments-agent/packages/agent-core/test/approval-seal.test.ts +233 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/attempt-replay.test.ts +265 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/composition.test.ts +204 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/fixtures/production-receipt-keys.json +1 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/helpers.ts +4 -1
- package/templates/supplier-payments-agent/packages/agent-core/test/mandate-status.test.ts +85 -9
- package/templates/supplier-payments-agent/packages/agent-core/test/quote.test.ts +198 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/receipt-chain.test.ts +220 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/receipt-read-verification.test.ts +197 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/receivables.test.ts +103 -3
- package/templates/supplier-payments-agent/packages/agent-runtime/README.md +12 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/adversarial.ts +32 -2
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/types.ts +53 -4
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +123 -22
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +30 -20
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +146 -21
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +40 -3
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +8 -1
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +16 -2
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +70 -20
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll.ts +2 -1
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/resume.ts +8 -2
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +3 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start.ts +6 -3
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/verify.ts +239 -38
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/webhook.ts +3 -2
- package/templates/supplier-payments-agent/packages/agent-runtime/src/index.ts +1 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/inspect.ts +5 -1
- package/templates/supplier-payments-agent/packages/agent-runtime/src/kit.ts +25 -2
- package/templates/supplier-payments-agent/packages/agent-runtime/src/scenarios.ts +8 -2
- package/templates/supplier-payments-agent/packages/agent-runtime/src/setup.ts +13 -3
- package/templates/supplier-payments-agent/packages/agent-runtime/src/terminal.ts +127 -18
- package/templates/supplier-payments-agent/packages/agent-runtime/test/verify-cli.test.ts +211 -9
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +45 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-session.test.ts +32 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-status-replies.test.ts +182 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +0 -204
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +0 -204
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +0 -204
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +0 -204
|
@@ -0,0 +1,801 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section 11: the proof bundle read back as a timeline. A run folder answers
|
|
3
|
+
* "why could the agent pay this", but only to somebody willing to join six
|
|
4
|
+
* files by hand. `inspect` does the join: who proposed what, who approved it
|
|
5
|
+
* and when, under which version of the mandate, every state transition with
|
|
6
|
+
* its actor, which call went out and what the rail answered, and which
|
|
7
|
+
* receipts came back.
|
|
8
|
+
*
|
|
9
|
+
* It reads the bundle and nothing else — no state.db, no network, no kit — so
|
|
10
|
+
* it works on any agent's run, and on a bundle somebody copied to a laptop
|
|
11
|
+
* that has never seen the agent.
|
|
12
|
+
*
|
|
13
|
+
* Masking is the bundle's: `maskPayee` is what wrote the mandate snapshot and
|
|
14
|
+
* the receipts, and it is applied again here to the payees the event log and
|
|
15
|
+
* the approval artifact still hold raw. It is idempotent on its own output, so
|
|
16
|
+
* a value the bundle already masked passes through unchanged. Nothing here
|
|
17
|
+
* un-masks anything, and the conversation is reported as counts, never as
|
|
18
|
+
* text: a debtor's own words are in `transcript.jsonl` and are not this
|
|
19
|
+
* command's to re-publish.
|
|
20
|
+
*/
|
|
21
|
+
import { maskPayee, type ApprovalArtifact, type ExecutionBatch, type ExecutionComposition, type ProofBundle } from "@codespar/agent-core";
|
|
22
|
+
import { formatMinor } from "./default-kit.js";
|
|
23
|
+
|
|
24
|
+
export interface InspectItem {
|
|
25
|
+
beneficiary: string;
|
|
26
|
+
/** Masked exactly as the bundle masks it. */
|
|
27
|
+
payee: string;
|
|
28
|
+
amount_minor: number;
|
|
29
|
+
currency: string;
|
|
30
|
+
description: string | null;
|
|
31
|
+
due_date: string | null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface InspectTransition {
|
|
35
|
+
at: string;
|
|
36
|
+
from: string | null;
|
|
37
|
+
to: string;
|
|
38
|
+
actor: string;
|
|
39
|
+
reason: string | null;
|
|
40
|
+
detail: string | null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface InspectAttempt {
|
|
44
|
+
attempt_id: string;
|
|
45
|
+
idempotency_key: string | null;
|
|
46
|
+
payee: string | null;
|
|
47
|
+
amount_minor: number | null;
|
|
48
|
+
rail: string | null;
|
|
49
|
+
dispatched_at: string | null;
|
|
50
|
+
/** What the rail said when it was called, and ONLY that: a later settlement does not rewrite the answer it gave. */
|
|
51
|
+
answer: {
|
|
52
|
+
at: string;
|
|
53
|
+
status: string;
|
|
54
|
+
code: string | null;
|
|
55
|
+
message: string | null;
|
|
56
|
+
transaction_id: string | null;
|
|
57
|
+
receipt_id: string | null;
|
|
58
|
+
money_moved: boolean | null;
|
|
59
|
+
sandbox: boolean | null;
|
|
60
|
+
} | null;
|
|
61
|
+
/** The attempt's outcome as last known, from the call, a later look or a settlement event. */
|
|
62
|
+
status: string | null;
|
|
63
|
+
transaction_id: string | null;
|
|
64
|
+
receipt_id: string | null;
|
|
65
|
+
/** What a later look at the same attempt found. `reconcile` never re-sends; it reads. */
|
|
66
|
+
reconciles: Array<{ at: string; found: string }>;
|
|
67
|
+
/** The payable legs of a receivable, as the issuer last registered them. */
|
|
68
|
+
instrument: Array<{ at: string; status: string; payable: boolean; due_date: string | null }>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface InspectExecution {
|
|
72
|
+
execution_id: string;
|
|
73
|
+
final_state: string;
|
|
74
|
+
mode: string | null;
|
|
75
|
+
proposed_at: string | null;
|
|
76
|
+
items: InspectItem[];
|
|
77
|
+
total_minor: number | null;
|
|
78
|
+
/** What the model claimed the total was. Recorded, never used to pay. */
|
|
79
|
+
model_claimed_total: number | null;
|
|
80
|
+
/** The batch this execution is one line of, when it is one: which list, and where in it. */
|
|
81
|
+
batch: ExecutionBatch | null;
|
|
82
|
+
approval: {
|
|
83
|
+
approval_id: string;
|
|
84
|
+
approver: ApprovalArtifact["approver"];
|
|
85
|
+
approved_at: string;
|
|
86
|
+
expires_at: string;
|
|
87
|
+
items_hash: string;
|
|
88
|
+
/** The set binding as the ARTIFACT carries it, which is the signed copy. */
|
|
89
|
+
batch: ExecutionBatch | null;
|
|
90
|
+
/** What the single amount was composed of (a cart), as the artifact signed it. */
|
|
91
|
+
composition?: ExecutionComposition;
|
|
92
|
+
mandate: { id: string; version: number };
|
|
93
|
+
escalation: { trigger: string; detail: string } | null;
|
|
94
|
+
} | null;
|
|
95
|
+
transitions: InspectTransition[];
|
|
96
|
+
attempts: InspectAttempt[];
|
|
97
|
+
receipts: string[];
|
|
98
|
+
/** Lines that are neither a transition nor a rail call: an uncertain outcome, a resumed dispatch, a total the core overrode. */
|
|
99
|
+
notes: Array<{ at: string; type: string; detail: string }>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface InspectReceipt {
|
|
103
|
+
receipt_id: string;
|
|
104
|
+
file: string;
|
|
105
|
+
state: string | null;
|
|
106
|
+
amount_minor: number | null;
|
|
107
|
+
payee: string | null;
|
|
108
|
+
money_moved: boolean | null;
|
|
109
|
+
sandbox: boolean | null;
|
|
110
|
+
at: string | null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* One batch the run touched, assembled from the `batch_hash` its executions
|
|
115
|
+
* carry. This is what lets a reader see "3 of 4 lines" instead of three
|
|
116
|
+
* timelines with nothing to compare against: `count` is what the list held
|
|
117
|
+
* when it was presented for approval, and everything below is measured
|
|
118
|
+
* against it.
|
|
119
|
+
*
|
|
120
|
+
* Keyed by (ref, batch_hash) and not by ref alone. A bundle that holds two
|
|
121
|
+
* lists under one ref is a bundle where the list changed, and collapsing
|
|
122
|
+
* them into one header would hide exactly the thing `batch_hash` exists to
|
|
123
|
+
* show.
|
|
124
|
+
*/
|
|
125
|
+
export interface InspectBatch {
|
|
126
|
+
ref: string;
|
|
127
|
+
batch_hash: string;
|
|
128
|
+
/** Lines the list held when it was presented. */
|
|
129
|
+
count: number;
|
|
130
|
+
/** The lines this bundle holds an execution for, by their position in the list. */
|
|
131
|
+
lines: Array<{ index: number; execution_id: string; final_state: string; attested: boolean }>;
|
|
132
|
+
/** How many of the lines carry an approval artifact. The "3" of "3 of 4". */
|
|
133
|
+
attested: number;
|
|
134
|
+
/** Positions of the presented list this bundle holds no execution for at all. */
|
|
135
|
+
missing: number[];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface InspectReport {
|
|
139
|
+
run: {
|
|
140
|
+
run_id: string;
|
|
141
|
+
agent: string | null;
|
|
142
|
+
mode: string | null;
|
|
143
|
+
rail: string | null;
|
|
144
|
+
mandate_id: string | null;
|
|
145
|
+
mandate_version: number | null;
|
|
146
|
+
started_at: string | null;
|
|
147
|
+
bundle_dir: string;
|
|
148
|
+
};
|
|
149
|
+
mandate: {
|
|
150
|
+
id: string;
|
|
151
|
+
version: number;
|
|
152
|
+
status: string;
|
|
153
|
+
expires_at: string;
|
|
154
|
+
currency: string;
|
|
155
|
+
per_tx_cap_minor: number;
|
|
156
|
+
cap_minor: number;
|
|
157
|
+
periodic_cap: { window: string; cap_minor: number } | null;
|
|
158
|
+
beneficiaries: Array<{ alias: string; name: string; payee: string }>;
|
|
159
|
+
} | null;
|
|
160
|
+
executions: InspectExecution[];
|
|
161
|
+
/** The batches this run's executions belong to. Empty for a run that ran no batch. */
|
|
162
|
+
batches: InspectBatch[];
|
|
163
|
+
/** Events the run holds that belong to no execution: a proposal refused before it was drafted, a tool outside `tools.json`. */
|
|
164
|
+
run_events: Array<{ at: string; type: string; detail: string }>;
|
|
165
|
+
receipts: InspectReceipt[];
|
|
166
|
+
conversation: { turns: number; tool_calls: number; tools: string[]; refused_tools: string[] };
|
|
167
|
+
/** Section 11: `verify.json` is the output of `codespar audit replay`, which is not a registered CLI command. */
|
|
168
|
+
verify: { present: boolean; note: string };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export const VERIFY_NOTE =
|
|
172
|
+
"absent by design: verify.json is the output of `codespar audit replay`, which is not a registered command of @codespar/cli, and the spec forbids a second implementation of the hash-chain check (sections 11 and 14.5)";
|
|
173
|
+
|
|
174
|
+
type Event = Record<string, unknown>;
|
|
175
|
+
|
|
176
|
+
function str(value: unknown): string | null {
|
|
177
|
+
return typeof value === "string" ? value : null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function num(value: unknown): number | null {
|
|
181
|
+
return typeof value === "number" ? value : null;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function bool(value: unknown): boolean | null {
|
|
185
|
+
return typeof value === "boolean" ? value : null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function payload(event: Event): Record<string, unknown> {
|
|
189
|
+
const p = event["payload"];
|
|
190
|
+
return p !== null && typeof p === "object" ? (p as Record<string, unknown>) : {};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** `agent bills-agent@0.1.0 for usr_x`, `usr_x (person, terminal)`: who acted, in one phrase. */
|
|
194
|
+
export function actorLabel(actor: unknown): string {
|
|
195
|
+
if (actor === null || typeof actor !== "object") return "unknown";
|
|
196
|
+
const a = actor as Record<string, unknown>;
|
|
197
|
+
if (a["type"] === "agent") return `agent ${String(a["agent"])} for ${String(a["on_behalf_of"])}`;
|
|
198
|
+
if (a["type"] === "human") return `${String(a["id"])} (person, ${String(a["channel"])})`;
|
|
199
|
+
if (a["type"] === "person") return `${String(a["id"])} (person, ${String(a["channel"])})`;
|
|
200
|
+
if (a["type"] === "mandate") return `the mandate ${String(a["id"])}`;
|
|
201
|
+
return "unknown";
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function maskMaybe(value: unknown): string | null {
|
|
205
|
+
const s = str(value);
|
|
206
|
+
return s === null ? null : maskPayee(s);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* A payee key also turns up inside free text: an escalation detail names the
|
|
211
|
+
* payee it escalated on, a refusal names the one it refused. Masking the
|
|
212
|
+
* `payee` field alone would leave the same key readable one line below, so
|
|
213
|
+
* every raw payee the bundle holds is replaced by its mask wherever it
|
|
214
|
+
* appears. Longest first, or a key that is a prefix of another masks it twice.
|
|
215
|
+
*/
|
|
216
|
+
export function redactorFor(rawPayees: Iterable<string>): (value: string | null) => string | null {
|
|
217
|
+
const pairs = [...new Set([...rawPayees].filter((p) => p.length > 0 && p !== "*"))]
|
|
218
|
+
.sort((a, b) => b.length - a.length)
|
|
219
|
+
.map((raw) => [raw, maskPayee(raw)] as const)
|
|
220
|
+
.filter(([raw, masked]) => raw !== masked);
|
|
221
|
+
if (!pairs.length) return (value) => value;
|
|
222
|
+
return (value) => {
|
|
223
|
+
if (value === null) return null;
|
|
224
|
+
let out = value;
|
|
225
|
+
for (const [raw, masked] of pairs) out = out.split(raw).join(masked);
|
|
226
|
+
return out;
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** Every raw payee this bundle holds: the drafted items, the rail calls, the settlement events and the approval artifacts. */
|
|
231
|
+
function rawPayeesOf(events: Event[], approvals: ApprovalArtifact[]): string[] {
|
|
232
|
+
const out: string[] = [];
|
|
233
|
+
const push = (value: unknown) => {
|
|
234
|
+
const s = str(value);
|
|
235
|
+
if (s) out.push(s);
|
|
236
|
+
};
|
|
237
|
+
for (const event of events) {
|
|
238
|
+
const p = payload(event);
|
|
239
|
+
push(p["payee"]);
|
|
240
|
+
if (Array.isArray(p["items"])) for (const i of p["items"] as Array<Record<string, unknown>>) push(i?.["payee"]);
|
|
241
|
+
}
|
|
242
|
+
for (const artifact of approvals) for (const i of artifact.items) push(i.payee);
|
|
243
|
+
return out;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* A batch binding as the bundle holds it, refusing anything that is not one.
|
|
248
|
+
* A bundle is a file somebody may have edited, so "line 5 of 3" is read as no
|
|
249
|
+
* binding at all rather than rendered as a count a reader would then trust.
|
|
250
|
+
*/
|
|
251
|
+
function batchBinding(raw: unknown): ExecutionBatch | null {
|
|
252
|
+
if (raw === null || typeof raw !== "object") return null;
|
|
253
|
+
const b = raw as Record<string, unknown>;
|
|
254
|
+
const ref = str(b["ref"]);
|
|
255
|
+
const hash = str(b["batch_hash"]);
|
|
256
|
+
const index = num(b["index"]);
|
|
257
|
+
const count = num(b["count"]);
|
|
258
|
+
if (!ref || !hash || index === null || count === null) return null;
|
|
259
|
+
if (!Number.isInteger(index) || !Number.isInteger(count) || count < 1 || index < 0 || index >= count) return null;
|
|
260
|
+
return { ref, batch_hash: hash, index, count };
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function item(raw: unknown, currency: string): InspectItem {
|
|
264
|
+
const i = (raw ?? {}) as Record<string, unknown>;
|
|
265
|
+
return {
|
|
266
|
+
beneficiary: str(i["beneficiary"]) ?? str(i["alias"]) ?? "unknown",
|
|
267
|
+
payee: maskMaybe(i["payee"]) ?? "unknown",
|
|
268
|
+
amount_minor: num(i["amount"]) ?? 0,
|
|
269
|
+
currency: str(i["currency"]) ?? currency,
|
|
270
|
+
description: str(i["description"]),
|
|
271
|
+
due_date: str(i["due_date"]),
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function attemptOf(attempts: Map<string, InspectAttempt>, attemptId: string): InspectAttempt {
|
|
276
|
+
const existing = attempts.get(attemptId);
|
|
277
|
+
if (existing) return existing;
|
|
278
|
+
const fresh: InspectAttempt = {
|
|
279
|
+
attempt_id: attemptId,
|
|
280
|
+
idempotency_key: null,
|
|
281
|
+
payee: null,
|
|
282
|
+
amount_minor: null,
|
|
283
|
+
rail: null,
|
|
284
|
+
dispatched_at: null,
|
|
285
|
+
answer: null,
|
|
286
|
+
status: null,
|
|
287
|
+
transaction_id: null,
|
|
288
|
+
receipt_id: null,
|
|
289
|
+
reconciles: [],
|
|
290
|
+
instrument: [],
|
|
291
|
+
};
|
|
292
|
+
attempts.set(attemptId, fresh);
|
|
293
|
+
return fresh;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* The bundle, joined. Every field comes from a file in the run folder; a run
|
|
298
|
+
* that is missing one is reported with nulls rather than refused, because an
|
|
299
|
+
* interrupted run is exactly when somebody wants to look at it.
|
|
300
|
+
*/
|
|
301
|
+
export function assembleTimeline(bundle: ProofBundle): InspectReport {
|
|
302
|
+
const meta = bundle.readMeta() ?? {};
|
|
303
|
+
const events = bundle.readEvents();
|
|
304
|
+
const approvals = bundle.readApprovals();
|
|
305
|
+
const snapshot = bundle.readMandateSnapshot();
|
|
306
|
+
const currency = str(snapshot?.["currency"]) ?? "BRL";
|
|
307
|
+
|
|
308
|
+
const redact = redactorFor(rawPayeesOf(events, approvals));
|
|
309
|
+
const executions = new Map<string, InspectExecution>();
|
|
310
|
+
const attemptsBy = new Map<string, Map<string, InspectAttempt>>();
|
|
311
|
+
const runEvents: InspectReport["run_events"] = [];
|
|
312
|
+
|
|
313
|
+
const executionOf = (id: string): InspectExecution => {
|
|
314
|
+
const existing = executions.get(id);
|
|
315
|
+
if (existing) return existing;
|
|
316
|
+
const fresh: InspectExecution = {
|
|
317
|
+
execution_id: id,
|
|
318
|
+
final_state: "unknown",
|
|
319
|
+
mode: null,
|
|
320
|
+
proposed_at: null,
|
|
321
|
+
items: [],
|
|
322
|
+
total_minor: null,
|
|
323
|
+
model_claimed_total: null,
|
|
324
|
+
batch: null,
|
|
325
|
+
approval: null,
|
|
326
|
+
transitions: [],
|
|
327
|
+
attempts: [],
|
|
328
|
+
receipts: [],
|
|
329
|
+
notes: [],
|
|
330
|
+
};
|
|
331
|
+
executions.set(id, fresh);
|
|
332
|
+
attemptsBy.set(id, new Map());
|
|
333
|
+
return fresh;
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
for (const event of events) {
|
|
337
|
+
const type = str(event["type"]) ?? "unknown";
|
|
338
|
+
const at = str(event["at"]) ?? "";
|
|
339
|
+
const executionId = str(event["execution_id"]);
|
|
340
|
+
const p = payload(event);
|
|
341
|
+
|
|
342
|
+
if (!executionId) {
|
|
343
|
+
const detail = str(p["detail"]) ?? str(p["reason"]) ?? str(event["reason"]) ?? str(event["tool"]) ?? str(event["message"]) ?? "";
|
|
344
|
+
const tool = str(event["tool"]);
|
|
345
|
+
runEvents.push({ at, type, detail: redact(tool ? `${tool}: ${detail || String(event["reason"] ?? "")}` : detail) ?? "" });
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const execution = executionOf(executionId);
|
|
350
|
+
const attempts = attemptsBy.get(executionId)!;
|
|
351
|
+
|
|
352
|
+
switch (type) {
|
|
353
|
+
case "execution.drafted": {
|
|
354
|
+
execution.proposed_at = at;
|
|
355
|
+
execution.items = Array.isArray(p["items"]) ? (p["items"] as unknown[]).map((i) => item(i, currency)) : [];
|
|
356
|
+
execution.total_minor = num(p["total"]);
|
|
357
|
+
execution.model_claimed_total = num(p["model_claimed_total"]);
|
|
358
|
+
execution.mode = str(p["mode"]);
|
|
359
|
+
execution.batch = batchBinding(p["batch"]);
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
case "execution.transition": {
|
|
363
|
+
const to = str(p["to"]) ?? "unknown";
|
|
364
|
+
execution.transitions.push({ at: str(p["at"]) ?? at, from: str(p["from"]), to, actor: actorLabel(p["actor"] ?? event["actor"]), reason: str(p["reason"]), detail: redact(str(p["detail"])) });
|
|
365
|
+
execution.final_state = to;
|
|
366
|
+
break;
|
|
367
|
+
}
|
|
368
|
+
case "approval.created":
|
|
369
|
+
// The artifact itself is `approval.json`; the event is only the stamp that says when it was written.
|
|
370
|
+
break;
|
|
371
|
+
case "rail.dispatch": {
|
|
372
|
+
const attemptId = str(p["attempt_id"]);
|
|
373
|
+
if (!attemptId) break;
|
|
374
|
+
const attempt = attemptOf(attempts, attemptId);
|
|
375
|
+
attempt.dispatched_at = at;
|
|
376
|
+
attempt.payee = maskMaybe(p["payee"]);
|
|
377
|
+
attempt.amount_minor = num(p["amount"]);
|
|
378
|
+
attempt.rail = str(p["rail"]);
|
|
379
|
+
attempt.idempotency_key = str(p["idempotency_key"]);
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
case "rail.outcome": {
|
|
383
|
+
const attemptId = str(p["attempt_id"]);
|
|
384
|
+
if (!attemptId) break;
|
|
385
|
+
const attempt = attemptOf(attempts, attemptId);
|
|
386
|
+
attempt.answer = {
|
|
387
|
+
at,
|
|
388
|
+
status: str(p["status"]) ?? "unknown",
|
|
389
|
+
code: str(p["code"]),
|
|
390
|
+
message: redact(str(p["message"])),
|
|
391
|
+
transaction_id: str(p["transaction_id"]),
|
|
392
|
+
receipt_id: str(p["receipt_id"]),
|
|
393
|
+
money_moved: bool(p["money_moved"]),
|
|
394
|
+
sandbox: bool(p["sandbox"]),
|
|
395
|
+
};
|
|
396
|
+
attempt.status = attempt.answer.status;
|
|
397
|
+
attempt.transaction_id = attempt.answer.transaction_id ?? attempt.transaction_id;
|
|
398
|
+
attempt.receipt_id = attempt.answer.receipt_id ?? attempt.receipt_id;
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
case "rail.uncertain": {
|
|
402
|
+
const attemptId = str(p["attempt_id"]);
|
|
403
|
+
const attempt = attemptId ? attemptOf(attempts, attemptId) : undefined;
|
|
404
|
+
if (attempt?.answer) {
|
|
405
|
+
attempt.answer.message = redact(str(p["message"])) ?? attempt.answer.message;
|
|
406
|
+
attempt.answer.code = str(p["code"]) ?? attempt.answer.code;
|
|
407
|
+
}
|
|
408
|
+
break;
|
|
409
|
+
}
|
|
410
|
+
case "rail.reconcile": {
|
|
411
|
+
const attemptId = str(p["attempt_id"]);
|
|
412
|
+
if (!attemptId) break;
|
|
413
|
+
const found = str(p["found"]) ?? "unknown";
|
|
414
|
+
const attempt = attemptOf(attempts, attemptId);
|
|
415
|
+
attempt.reconciles.push({ at, found });
|
|
416
|
+
if (found !== "absent" && found !== "unknown") attempt.status = found;
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
case "charge.instrument": {
|
|
420
|
+
const attemptId = str(p["attempt_id"]);
|
|
421
|
+
if (!attemptId) break;
|
|
422
|
+
const attempt = attemptOf(attempts, attemptId);
|
|
423
|
+
attempt.transaction_id = str(p["charge_id"]) ?? attempt.transaction_id;
|
|
424
|
+
attempt.instrument.push({ at, status: str(p["status"]) ?? "unknown", payable: bool(p["payable"]) ?? false, due_date: str(p["due_date"]) });
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
case "receipt.saved": {
|
|
428
|
+
const receiptId = str(p["receipt_id"]);
|
|
429
|
+
if (receiptId && !execution.receipts.includes(receiptId)) execution.receipts.push(receiptId);
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
default: {
|
|
433
|
+
const attemptId = str(p["attempt_id"]);
|
|
434
|
+
if (type.startsWith("commerce.")) {
|
|
435
|
+
// The rail's own settlement event, which may be the ONLY place a receipt id appears (a webhook closed the attempt).
|
|
436
|
+
const receiptId = str(p["receipt_id"]);
|
|
437
|
+
if (attemptId) {
|
|
438
|
+
const attempt = attemptOf(attempts, attemptId);
|
|
439
|
+
attempt.receipt_id = receiptId ?? attempt.receipt_id;
|
|
440
|
+
}
|
|
441
|
+
execution.notes.push({ at, type, detail: [attemptId ? `attempt ${attemptId}` : "", receiptId ? `receipt ${receiptId}` : ""].filter(Boolean).join(" · ") });
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
execution.notes.push({ at, type, detail: redact(str(p["detail"]) ?? str(p["message"]) ?? str(p["reason"]) ?? "") ?? "" });
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
for (const artifact of approvals) {
|
|
450
|
+
const execution = executionOf(artifact.execution_id);
|
|
451
|
+
execution.approval = {
|
|
452
|
+
approval_id: artifact.approval_id,
|
|
453
|
+
approver: artifact.approver,
|
|
454
|
+
approved_at: artifact.approved_at,
|
|
455
|
+
expires_at: artifact.expires_at,
|
|
456
|
+
items_hash: artifact.items_hash,
|
|
457
|
+
batch: batchBinding(artifact.batch),
|
|
458
|
+
...(artifact.composition ? { composition: artifact.composition } : {}),
|
|
459
|
+
mandate: artifact.mandate,
|
|
460
|
+
escalation: artifact.escalation ? { trigger: artifact.escalation.trigger, detail: redact(artifact.escalation.detail) ?? "" } : null,
|
|
461
|
+
};
|
|
462
|
+
// A run whose event log was truncated still knows what was approved.
|
|
463
|
+
if (execution.items.length === 0) execution.items = artifact.items.map((i) => item(i, currency));
|
|
464
|
+
if (!execution.batch) execution.batch = batchBinding(artifact.batch);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
for (const [id, attempts] of attemptsBy) executionOf(id).attempts = [...attempts.values()];
|
|
468
|
+
|
|
469
|
+
const receipts: InspectReceipt[] = bundle.listReceipts().map((file) => {
|
|
470
|
+
const raw = bundle.readReceipt(file) ?? {};
|
|
471
|
+
const payment = (raw["payment"] ?? {}) as Record<string, unknown>;
|
|
472
|
+
return {
|
|
473
|
+
receipt_id: str(raw["receipt_id"]) ?? file.replace(/\.json$/, ""),
|
|
474
|
+
file: `receipts/${file}`,
|
|
475
|
+
state: str(raw["state"]),
|
|
476
|
+
amount_minor: num(payment["amount_minor"]),
|
|
477
|
+
payee: maskMaybe(payment["payee"]),
|
|
478
|
+
money_moved: bool(payment["money_moved"]),
|
|
479
|
+
sandbox: bool(payment["sandbox"]),
|
|
480
|
+
at: str(payment["at"]),
|
|
481
|
+
};
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
const transcript = bundle.readTranscript();
|
|
485
|
+
const toolCalls = transcript.filter((l) => l.kind === "tool_call");
|
|
486
|
+
const refusedTools = transcript.filter((l) => l.kind === "tool_result" && l["refused"] === true).map((l) => String(l["name"]));
|
|
487
|
+
|
|
488
|
+
return {
|
|
489
|
+
run: {
|
|
490
|
+
run_id: bundle.runId,
|
|
491
|
+
agent: str(meta["agent"]),
|
|
492
|
+
mode: str(meta["mode"]),
|
|
493
|
+
rail: str(meta["rail"]),
|
|
494
|
+
mandate_id: str(meta["mandate_id"]),
|
|
495
|
+
mandate_version: num(meta["mandate_version"]) ?? num(snapshot?.["version"]),
|
|
496
|
+
started_at: str(meta["started_at"]),
|
|
497
|
+
bundle_dir: bundle.dir,
|
|
498
|
+
},
|
|
499
|
+
mandate: snapshot
|
|
500
|
+
? {
|
|
501
|
+
id: str(snapshot["id"]) ?? "unknown",
|
|
502
|
+
version: num(snapshot["version"]) ?? 0,
|
|
503
|
+
status: str(snapshot["status"]) ?? "unknown",
|
|
504
|
+
expires_at: str(snapshot["expires_at"]) ?? "unknown",
|
|
505
|
+
currency,
|
|
506
|
+
per_tx_cap_minor: num(snapshot["per_tx_cap_minor"]) ?? 0,
|
|
507
|
+
cap_minor: num(snapshot["cap_minor"]) ?? 0,
|
|
508
|
+
periodic_cap: snapshot["periodic_cap"] && typeof snapshot["periodic_cap"] === "object" ? { window: String((snapshot["periodic_cap"] as Record<string, unknown>)["window"]), cap_minor: Number((snapshot["periodic_cap"] as Record<string, unknown>)["cap_minor"]) } : null,
|
|
509
|
+
beneficiaries: Array.isArray(snapshot["beneficiaries"])
|
|
510
|
+
? (snapshot["beneficiaries"] as Array<Record<string, unknown>>).map((b) => ({ alias: String(b["alias"]), name: String(b["name"]), payee: maskMaybe(b["payee"]) ?? "unknown" }))
|
|
511
|
+
: [],
|
|
512
|
+
}
|
|
513
|
+
: null,
|
|
514
|
+
executions: [...executions.values()],
|
|
515
|
+
batches: assembleBatches([...executions.values()]),
|
|
516
|
+
run_events: runEvents,
|
|
517
|
+
receipts,
|
|
518
|
+
conversation: {
|
|
519
|
+
turns: transcript.filter((l) => l.kind === "user").length,
|
|
520
|
+
tool_calls: toolCalls.length,
|
|
521
|
+
tools: [...new Set(toolCalls.map((l) => String(l["name"])))],
|
|
522
|
+
refused_tools: [...new Set(refusedTools)],
|
|
523
|
+
},
|
|
524
|
+
verify: { present: bundle.hasVerify(), note: VERIFY_NOTE },
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* The batches of a run, from the bindings its executions carry. A line is
|
|
530
|
+
* `attested` when the bundle holds its approval artifact: a line a person
|
|
531
|
+
* DENIED has an execution and no artifact, and a line dropped before it ran
|
|
532
|
+
* has neither, so the two are counted apart and both are visible.
|
|
533
|
+
*/
|
|
534
|
+
function assembleBatches(executions: InspectExecution[]): InspectBatch[] {
|
|
535
|
+
const batches = new Map<string, InspectBatch>();
|
|
536
|
+
for (const execution of executions) {
|
|
537
|
+
const binding = execution.batch;
|
|
538
|
+
if (!binding) continue;
|
|
539
|
+
const key = `${binding.ref}\u0000${binding.batch_hash}`;
|
|
540
|
+
const entry = batches.get(key) ?? { ref: binding.ref, batch_hash: binding.batch_hash, count: binding.count, lines: [], attested: 0, missing: [] };
|
|
541
|
+
entry.lines.push({ index: binding.index, execution_id: execution.execution_id, final_state: execution.final_state, attested: execution.approval !== null });
|
|
542
|
+
batches.set(key, entry);
|
|
543
|
+
}
|
|
544
|
+
for (const entry of batches.values()) {
|
|
545
|
+
entry.lines.sort((a, b) => a.index - b.index);
|
|
546
|
+
entry.attested = entry.lines.filter((l) => l.attested).length;
|
|
547
|
+
const held = new Set(entry.lines.map((l) => l.index));
|
|
548
|
+
entry.missing = [...Array(entry.count).keys()].filter((i) => !held.has(i));
|
|
549
|
+
}
|
|
550
|
+
return [...batches.values()];
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// ---- the terminal rendering --------------------------------------------
|
|
554
|
+
|
|
555
|
+
function clock(at: string | null): string {
|
|
556
|
+
if (!at) return "--:--:--";
|
|
557
|
+
const m = /T(\d{2}:\d{2}:\d{2})/.exec(at);
|
|
558
|
+
return m?.[1] ?? at;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function approverLabel(approver: ApprovalArtifact["approver"]): string {
|
|
562
|
+
return approver.type === "person" ? `${approver.id} (person, ${approver.channel})` : `the mandate ${approver.id}`;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/** One ordered list of lines per execution: the proposal, the decision, every transition, the call and its answer. */
|
|
566
|
+
function executionLines(execution: InspectExecution): Array<{ at: string; label: string; text: string; wrapped: string[] }> {
|
|
567
|
+
const lines: Array<{ at: string; label: string; text: string; wrapped: string[] }> = [];
|
|
568
|
+
|
|
569
|
+
if (execution.proposed_at) {
|
|
570
|
+
const wrapped = execution.items.map((i) => `${i.beneficiary} <${i.payee}> ${formatMinor(i.amount_minor)}${i.description ? ` ${i.description}` : ""}${i.due_date ? ` due ${i.due_date}` : ""}`);
|
|
571
|
+
if (execution.total_minor !== null) {
|
|
572
|
+
wrapped.push(`total ${formatMinor(execution.total_minor)} computed by the core${execution.model_claimed_total !== null ? `; the model said ${formatMinor(execution.model_claimed_total)}` : ""}`);
|
|
573
|
+
}
|
|
574
|
+
lines.push({ at: execution.proposed_at, label: "proposed", text: `${execution.items.length} item(s)${execution.mode ? ` in ${execution.mode} mode` : ""}`, wrapped });
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
const approval = execution.approval;
|
|
578
|
+
if (approval) {
|
|
579
|
+
const wrapped = [`${approval.approval_id} · items_hash ${approval.items_hash}`, `under mandate ${approval.mandate.id} v${approval.mandate.version} · the artifact expires ${clock(approval.expires_at)}`];
|
|
580
|
+
if (approval.batch) wrapped.push(`line ${approval.batch.index + 1} of ${approval.batch.count} of batch ${approval.batch.ref} · batch_hash ${approval.batch.batch_hash}`);
|
|
581
|
+
if (approval.composition) wrapped.push(`composed of ${approval.composition.line_count} line(s) of ${approval.composition.ref} · composition_hash ${approval.composition.composition_hash}`);
|
|
582
|
+
if (approval.escalation) wrapped.push(`escalated by ${approval.escalation.trigger}: ${approval.escalation.detail}`);
|
|
583
|
+
lines.push({ at: approval.approved_at, label: "approved", text: approverLabel(approval.approver), wrapped });
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
for (const t of execution.transitions) {
|
|
587
|
+
const suffix = [t.reason ? `reason ${t.reason}` : "", t.detail ?? ""].filter(Boolean).join(" · ");
|
|
588
|
+
lines.push({ at: t.at, label: "state", text: `${t.from ?? "-"} -> ${t.to} by ${t.actor}`, wrapped: suffix ? [suffix] : [] });
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
for (const a of execution.attempts) {
|
|
592
|
+
if (a.dispatched_at) {
|
|
593
|
+
const wrapped = a.idempotency_key ? [`idempotency_key ${a.idempotency_key}`] : [];
|
|
594
|
+
lines.push({ at: a.dispatched_at, label: "call out", text: `${a.attempt_id} -> ${a.rail ?? "rail"}${a.amount_minor !== null ? ` ${formatMinor(a.amount_minor)}` : ""}${a.payee ? ` to ${a.payee}` : ""}`, wrapped });
|
|
595
|
+
}
|
|
596
|
+
const answer = a.answer;
|
|
597
|
+
if (answer) {
|
|
598
|
+
const bits = [answer.transaction_id ? `tx ${answer.transaction_id}` : "", answer.receipt_id ? `receipt ${answer.receipt_id}` : "", answer.money_moved !== null ? `money_moved ${answer.money_moved}` : "", answer.sandbox ? "sandbox" : ""].filter(Boolean);
|
|
599
|
+
const why = [answer.code, answer.message].filter(Boolean).join(": ");
|
|
600
|
+
lines.push({ at: answer.at, label: "rail says", text: `${answer.status}${why ? ` ${why}` : ""}`, wrapped: bits.length ? [bits.join(" · ")] : [] });
|
|
601
|
+
}
|
|
602
|
+
for (const i of a.instrument) lines.push({ at: i.at, label: "instrument", text: `${a.attempt_id} ${i.status}${i.payable ? ", payable" : ", not payable yet"}${i.due_date ? `, due ${i.due_date}` : ""}`, wrapped: [] });
|
|
603
|
+
for (const r of a.reconciles) lines.push({ at: r.at, label: "look again", text: `${a.attempt_id} the rail says ${r.found}`, wrapped: [] });
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
for (const n of execution.notes) lines.push({ at: n.at, label: n.type.startsWith("commerce.") ? "rail event" : "note", text: `${n.type}${n.detail ? ` ${n.detail}` : ""}`, wrapped: [] });
|
|
607
|
+
|
|
608
|
+
return lines.sort((a, b) => (a.at === b.at ? 0 : a.at < b.at ? -1 : 1));
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* The batch header, in the words a reader needs: how many lines the approved
|
|
613
|
+
* list held, how many of them this bundle attests, and which positions it
|
|
614
|
+
* holds nothing for. "3 of 4 lines attested" is the sentence; the rest of the
|
|
615
|
+
* block says which 3 and which 4th.
|
|
616
|
+
*/
|
|
617
|
+
export function batchSummary(batch: InspectBatch): string {
|
|
618
|
+
const bits = [`${batch.attested} of ${batch.count} line(s) attested`];
|
|
619
|
+
if (batch.lines.length !== batch.attested) bits.push(`${batch.lines.length} with an execution`);
|
|
620
|
+
if (batch.missing.length) bits.push(`no execution for line(s) ${batch.missing.map((i) => i + 1).join(", ")}`);
|
|
621
|
+
return bits.join(" · ");
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/** One row per position of the presented list, present in the bundle or not. */
|
|
625
|
+
export function batchLineRows(batch: InspectBatch): string[] {
|
|
626
|
+
const byIndex = new Map(batch.lines.map((l) => [l.index, l]));
|
|
627
|
+
return [...Array(batch.count).keys()].map((i) => {
|
|
628
|
+
const line = byIndex.get(i);
|
|
629
|
+
const where = `line ${i + 1} of ${batch.count}`;
|
|
630
|
+
if (!line) return `${where} — no execution in this bundle: approved as part of this list, and nothing here says it ran`;
|
|
631
|
+
return `${where} ${line.execution_id} ${line.final_state} ${line.attested ? "approval artifact present" : "no approval artifact"}`;
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/** `execution exe_x — settled` gains ` · folha-2026-10 line 2 of 3` when it is one line of a batch. */
|
|
636
|
+
function executionHeading(execution: InspectExecution): string {
|
|
637
|
+
const b = execution.batch;
|
|
638
|
+
return `execution ${execution.execution_id} — ${execution.final_state}${b ? ` · ${b.ref} line ${b.index + 1} of ${b.count}` : ""}`;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
export function renderText(report: InspectReport): string {
|
|
642
|
+
const out: string[] = [];
|
|
643
|
+
const r = report.run;
|
|
644
|
+
out.push(`${r.run_id}${r.agent ? ` — ${r.agent}` : ""}`);
|
|
645
|
+
out.push(` mode ${r.mode ?? "?"} · rail ${r.rail ?? "?"} · mandate ${r.mandate_id ?? "?"}${r.mandate_version !== null ? ` v${r.mandate_version}` : ""}${r.started_at ? ` · started ${r.started_at}` : ""}`);
|
|
646
|
+
const m = report.mandate;
|
|
647
|
+
if (m) {
|
|
648
|
+
const caps = [`per payment ${formatMinor(m.per_tx_cap_minor)}`, m.periodic_cap ? `per ${m.periodic_cap.window} ${formatMinor(m.periodic_cap.cap_minor)}` : "", `lifetime ${formatMinor(m.cap_minor)}`].filter(Boolean);
|
|
649
|
+
out.push(` mandate ${m.status}, expires ${m.expires_at} · ${caps.join(" · ")}`);
|
|
650
|
+
if (m.beneficiaries.length) out.push(` named payees: ${m.beneficiaries.map((b) => `${b.name} <${b.payee}>`).join(", ")}`);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
for (const batch of report.batches) {
|
|
654
|
+
out.push("");
|
|
655
|
+
out.push(`batch ${batch.ref} — ${batchSummary(batch)}`);
|
|
656
|
+
out.push(` batch_hash ${batch.batch_hash}`);
|
|
657
|
+
for (const row of batchLineRows(batch)) out.push(` ${row}`);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
for (const execution of report.executions) {
|
|
661
|
+
out.push("");
|
|
662
|
+
out.push(executionHeading(execution));
|
|
663
|
+
for (const line of executionLines(execution)) {
|
|
664
|
+
out.push(` ${clock(line.at)} ${line.label.padEnd(10)} ${line.text}`);
|
|
665
|
+
for (const w of line.wrapped) out.push(` ${" ".repeat(8)} ${" ".repeat(10)} ${w}`);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
if (report.run_events.length) {
|
|
670
|
+
out.push("");
|
|
671
|
+
out.push("outside any execution");
|
|
672
|
+
for (const e of report.run_events) out.push(` ${clock(e.at)} ${e.type.padEnd(10)} ${e.detail}`);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
out.push("");
|
|
676
|
+
out.push(`receipts (${report.receipts.length})`);
|
|
677
|
+
for (const receipt of report.receipts) {
|
|
678
|
+
const bits = [receipt.state ?? "?", receipt.amount_minor !== null ? formatMinor(receipt.amount_minor) : "", receipt.payee ?? "", receipt.sandbox ? "sandbox" : "", receipt.money_moved === false ? "no money moved" : ""].filter(Boolean);
|
|
679
|
+
out.push(` ${receipt.receipt_id} ${bits.join(" ")}`);
|
|
680
|
+
out.push(` ${receipt.file}`);
|
|
681
|
+
}
|
|
682
|
+
if (!report.receipts.length) out.push(" none");
|
|
683
|
+
|
|
684
|
+
out.push("");
|
|
685
|
+
const c = report.conversation;
|
|
686
|
+
out.push(`conversation: ${c.turns} turn(s), ${c.tool_calls} tool call(s)${c.tools.length ? ` (${c.tools.join(", ")})` : ""}${c.refused_tools.length ? ` · refused: ${c.refused_tools.join(", ")}` : ""}`);
|
|
687
|
+
out.push(`verify.json: ${report.verify.present ? "present" : report.verify.note}`);
|
|
688
|
+
return out.join("\n") + "\n";
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// ---- the static HTML rendering ------------------------------------------
|
|
692
|
+
|
|
693
|
+
function escapeHtml(value: string): string {
|
|
694
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* One file, no network: the CSS is inline, there is no script, and nothing is
|
|
699
|
+
* fetched. A bundle inspected on an air-gapped machine renders the same as on
|
|
700
|
+
* a connected one, which is the whole point of a proof you can hand over.
|
|
701
|
+
*/
|
|
702
|
+
export function renderHtml(report: InspectReport): string {
|
|
703
|
+
const r = report.run;
|
|
704
|
+
const m = report.mandate;
|
|
705
|
+
const esc = escapeHtml;
|
|
706
|
+
|
|
707
|
+
const header = [
|
|
708
|
+
`<h1>${esc(r.run_id)}</h1>`,
|
|
709
|
+
`<p class="lede">${esc(r.agent ?? "unknown agent")} · mode <b>${esc(r.mode ?? "?")}</b> · rail <b>${esc(r.rail ?? "?")}</b> · mandate <b>${esc(r.mandate_id ?? "?")}</b>${r.mandate_version !== null ? ` v${r.mandate_version}` : ""}${r.started_at ? ` · started ${esc(r.started_at)}` : ""}</p>`,
|
|
710
|
+
m
|
|
711
|
+
? `<p class="lede">mandate ${esc(m.status)}, expires ${esc(m.expires_at)} · per payment ${esc(formatMinor(m.per_tx_cap_minor))}${m.periodic_cap ? ` · per ${esc(m.periodic_cap.window)} ${esc(formatMinor(m.periodic_cap.cap_minor))}` : ""} · lifetime ${esc(formatMinor(m.cap_minor))}</p>`
|
|
712
|
+
: "",
|
|
713
|
+
m && m.beneficiaries.length ? `<p class="lede">named payees: ${m.beneficiaries.map((b) => `${esc(b.name)} <code>${esc(b.payee)}</code>`).join(", ")}</p>` : "",
|
|
714
|
+
].join("\n");
|
|
715
|
+
|
|
716
|
+
// The batch header comes before the timelines it is a header FOR: a reader
|
|
717
|
+
// must know the list held four lines before reading the three that ran.
|
|
718
|
+
const batches = report.batches
|
|
719
|
+
.map((batch) => {
|
|
720
|
+
const rows = batchLineRows(batch)
|
|
721
|
+
.map((row) => `<tr><td>${esc(row)}</td></tr>`)
|
|
722
|
+
.join("\n");
|
|
723
|
+
return `<section><h2>batch ${esc(batch.ref)} <span class="state">${esc(batchSummary(batch))}</span></h2><p class="lede">batch_hash <code>${esc(batch.batch_hash)}</code></p><table>${rows}</table></section>`;
|
|
724
|
+
})
|
|
725
|
+
.join("\n");
|
|
726
|
+
|
|
727
|
+
const executions = report.executions
|
|
728
|
+
.map((execution) => {
|
|
729
|
+
const rows = executionLines(execution)
|
|
730
|
+
.map((line) => {
|
|
731
|
+
const extra = line.wrapped.map((w) => `<div class="sub">${esc(w)}</div>`).join("");
|
|
732
|
+
return `<tr><td class="t">${esc(clock(line.at))}</td><td class="k"><span class="tag tag-${esc(line.label.replace(/\s+/g, "-"))}">${esc(line.label)}</span></td><td>${esc(line.text)}${extra}</td></tr>`;
|
|
733
|
+
})
|
|
734
|
+
.join("\n");
|
|
735
|
+
const b = execution.batch;
|
|
736
|
+
const where = b ? `<span class="state">${esc(`${b.ref} line ${b.index + 1} of ${b.count}`)}</span>` : "";
|
|
737
|
+
return `<section><h2>execution ${esc(execution.execution_id)} <span class="state state-${esc(execution.final_state)}">${esc(execution.final_state)}</span> ${where}</h2><table>${rows}</table></section>`;
|
|
738
|
+
})
|
|
739
|
+
.join("\n");
|
|
740
|
+
|
|
741
|
+
const runEvents = report.run_events.length
|
|
742
|
+
? `<section><h2>outside any execution</h2><table>${report.run_events.map((e) => `<tr><td class="t">${esc(clock(e.at))}</td><td class="k">${esc(e.type)}</td><td>${esc(e.detail)}</td></tr>`).join("")}</table></section>`
|
|
743
|
+
: "";
|
|
744
|
+
|
|
745
|
+
const receipts = report.receipts.length
|
|
746
|
+
? `<table>${report.receipts
|
|
747
|
+
.map((receipt) => {
|
|
748
|
+
const bits = [receipt.state ?? "?", receipt.amount_minor !== null ? formatMinor(receipt.amount_minor) : "", receipt.payee ?? "", receipt.sandbox ? "sandbox" : "", receipt.money_moved === false ? "no money moved" : ""].filter(Boolean).join(" · ");
|
|
749
|
+
return `<tr><td class="k"><code>${esc(receipt.receipt_id)}</code></td><td>${esc(bits)}<div class="sub">${esc(receipt.file)}</div></td></tr>`;
|
|
750
|
+
})
|
|
751
|
+
.join("")}</table>`
|
|
752
|
+
: "<p class=\"lede\">none</p>";
|
|
753
|
+
|
|
754
|
+
const c = report.conversation;
|
|
755
|
+
const footer = `<p class="lede">conversation: ${c.turns} turn(s), ${c.tool_calls} tool call(s)${c.tools.length ? ` (${esc(c.tools.join(", "))})` : ""}${c.refused_tools.length ? ` · refused: ${esc(c.refused_tools.join(", "))}` : ""}</p><p class="lede">verify.json: ${report.verify.present ? "present" : esc(report.verify.note)}</p><p class="lede">Payees are masked the way the proof bundle masks them. The conversation is reported as counts; its text stays in transcript.jsonl.</p>`;
|
|
756
|
+
|
|
757
|
+
return `<!doctype html>
|
|
758
|
+
<html lang="en">
|
|
759
|
+
<head>
|
|
760
|
+
<meta charset="utf-8">
|
|
761
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
762
|
+
<title>${esc(r.run_id)} — CodeSpar proof bundle</title>
|
|
763
|
+
<style>
|
|
764
|
+
:root { color-scheme: light dark; --bg: #fbfbfa; --fg: #1a1a18; --muted: #6b6b63; --line: #e2e2dc; --card: #ffffff; --accent: #2f5d50; }
|
|
765
|
+
@media (prefers-color-scheme: dark) { :root { --bg: #16171a; --fg: #e8e8e4; --muted: #9a9a92; --line: #2c2d31; --card: #1d1e22; --accent: #7fc3ae; } }
|
|
766
|
+
* { box-sizing: border-box; }
|
|
767
|
+
body { margin: 0; padding: 32px 16px 64px; background: var(--bg); color: var(--fg); font: 15px/1.5 ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
|
|
768
|
+
main { max-width: 980px; margin: 0 auto; }
|
|
769
|
+
h1 { font-size: 20px; margin: 0 0 4px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; word-break: break-all; }
|
|
770
|
+
h2 { font-size: 15px; margin: 0 0 10px; font-weight: 600; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; word-break: break-all; }
|
|
771
|
+
h3 { font-size: 15px; margin: 28px 0 10px; }
|
|
772
|
+
.lede { color: var(--muted); margin: 2px 0; font-size: 13px; }
|
|
773
|
+
section { background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 16px; margin: 20px 0; }
|
|
774
|
+
table { width: 100%; border-collapse: collapse; }
|
|
775
|
+
td { padding: 5px 8px 5px 0; vertical-align: top; border-top: 1px solid var(--line); font-size: 13px; }
|
|
776
|
+
tr:first-child td { border-top: 0; }
|
|
777
|
+
td.t { width: 78px; color: var(--muted); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; white-space: nowrap; }
|
|
778
|
+
td.k { width: 120px; white-space: nowrap; }
|
|
779
|
+
.sub { color: var(--muted); font-size: 12px; margin-top: 2px; word-break: break-word; }
|
|
780
|
+
code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; overflow-wrap: anywhere; }
|
|
781
|
+
.tag { display: inline-block; padding: 1px 7px; border-radius: 999px; border: 1px solid var(--line); font-size: 11px; color: var(--muted); }
|
|
782
|
+
.tag-proposed, .tag-approved { border-color: var(--accent); color: var(--accent); }
|
|
783
|
+
.state { display: inline-block; padding: 1px 8px; border-radius: 999px; border: 1px solid var(--line); font-size: 11px; font-family: ui-sans-serif, system-ui, sans-serif; color: var(--muted); }
|
|
784
|
+
.state-settled { border-color: var(--accent); color: var(--accent); }
|
|
785
|
+
.state-denied, .state-failed, .state-expired { border-color: #b4552f; color: #b4552f; }
|
|
786
|
+
@media (max-width: 620px) { td.t, td.k { width: auto; white-space: normal; } body { padding: 20px 12px 48px; } }
|
|
787
|
+
</style>
|
|
788
|
+
</head>
|
|
789
|
+
<body>
|
|
790
|
+
<main>
|
|
791
|
+
${header}
|
|
792
|
+
${batches}
|
|
793
|
+
${executions}
|
|
794
|
+
${runEvents}
|
|
795
|
+
<section><h2>receipts (${report.receipts.length})</h2>${receipts}</section>
|
|
796
|
+
${footer}
|
|
797
|
+
</main>
|
|
798
|
+
</body>
|
|
799
|
+
</html>
|
|
800
|
+
`;
|
|
801
|
+
}
|