@codespar/cli 0.14.1 → 0.17.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 +44 -17
- package/dist/commands/audit-replay.js +267 -0
- package/dist/commands/audit-replay.js.map +1 -0
- package/dist/commands/init.js +28 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mandate-verify.js +98 -19
- package/dist/commands/mandate-verify.js.map +1 -1
- package/dist/index.js +17 -3
- package/dist/index.js.map +1 -1
- package/dist/mandate-codec.js +31 -20
- package/dist/mandate-codec.js.map +1 -1
- package/dist/surface.js +4 -1
- package/dist/surface.js.map +1 -1
- package/package.json +1 -1
- package/templates/bills-agent/README.md +8 -5
- package/templates/bills-agent/agents/bills-agent/.env.example +3 -3
- 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 +62 -22
- package/templates/bills-agent/agents/bills-agent/SYSTEM_PROMPT.md +1 -1
- package/templates/bills-agent/agents/bills-agent/agent.yaml +2 -2
- package/templates/bills-agent/agents/bills-agent/package.json +14 -11
- package/templates/bills-agent/agents/bills-agent/src/kit.ts +193 -0
- package/templates/bills-agent/agents/bills-agent/test/adversarial.test.ts +8 -7
- package/templates/bills-agent/agents/bills-agent/test/check.test.ts +19 -2
- package/templates/bills-agent/agents/bills-agent/test/cli.test.ts +72 -24
- package/templates/bills-agent/agents/bills-agent/test/fixtures/excursao-300.transcript.jsonl +2 -0
- package/templates/bills-agent/agents/bills-agent/test/fixtures/material-400.transcript.jsonl +2 -0
- package/templates/bills-agent/agents/bills-agent/test/inspect.test.ts +124 -0
- package/templates/bills-agent/agents/bills-agent/test/provider.test.ts +25 -0
- package/templates/bills-agent/agents/bills-agent/test/scenarios.test.ts +10 -9
- package/templates/bills-agent/agents/bills-agent/tsconfig.json +0 -1
- package/templates/bills-agent/package.json +5 -2
- package/templates/bills-agent/packages/agent-core/README.md +2 -0
- package/templates/bills-agent/packages/agent-core/package.json +1 -1
- package/templates/bills-agent/packages/agent-core/src/api/charge-rail.ts +27 -6
- package/templates/bills-agent/packages/agent-core/src/api/rail.ts +16 -0
- package/templates/bills-agent/packages/agent-core/src/api/sandbox-payer.ts +20 -7
- package/templates/bills-agent/packages/agent-core/src/approval.ts +16 -2
- package/templates/bills-agent/packages/agent-core/src/bundle.ts +50 -4
- package/templates/bills-agent/packages/agent-core/src/channels.ts +140 -0
- package/templates/bills-agent/packages/agent-core/src/check.ts +90 -8
- package/templates/bills-agent/packages/agent-core/src/clock.ts +42 -0
- package/templates/bills-agent/packages/agent-core/src/engine.ts +119 -18
- package/templates/bills-agent/packages/agent-core/src/hash.ts +13 -0
- package/templates/bills-agent/packages/agent-core/src/index.ts +3 -0
- package/templates/bills-agent/packages/agent-core/src/manifest.ts +1 -1
- package/templates/bills-agent/packages/agent-core/src/rail.ts +16 -2
- package/templates/bills-agent/packages/agent-core/src/receipt-verification.ts +401 -0
- package/templates/bills-agent/packages/agent-core/src/state-machine.ts +3 -1
- package/templates/bills-agent/packages/agent-core/src/stubs/charge-rail.ts +2 -0
- package/templates/bills-agent/packages/agent-core/src/stubs/rail.ts +19 -2
- package/templates/bills-agent/packages/agent-core/src/types.ts +28 -0
- package/templates/bills-agent/packages/agent-core/test/approval.test.ts +36 -2
- package/templates/bills-agent/packages/agent-core/test/bundle.test.ts +85 -0
- package/templates/bills-agent/packages/agent-core/test/clock.test.ts +25 -0
- package/templates/bills-agent/packages/agent-core/test/engine.test.ts +73 -1
- package/templates/bills-agent/packages/agent-core/test/fixtures/staging-receipt-keys.json +18 -0
- package/templates/bills-agent/packages/agent-core/test/fixtures/staging-receipt.json +24 -0
- package/templates/bills-agent/packages/agent-core/test/helpers.ts +1 -1
- package/templates/bills-agent/packages/agent-core/test/manifest.test.ts +2 -2
- package/templates/bills-agent/packages/agent-core/test/receipt-verification.test.ts +316 -0
- package/templates/bills-agent/packages/agent-core/test/receivables.test.ts +51 -0
- package/templates/bills-agent/packages/agent-runtime/README.md +68 -0
- package/templates/bills-agent/packages/agent-runtime/bin.mjs +32 -0
- package/templates/bills-agent/packages/agent-runtime/package.json +23 -0
- package/templates/bills-agent/{agents/bills-agent → packages/agent-runtime}/src/adversarial.ts +36 -44
- package/templates/bills-agent/packages/agent-runtime/src/agent.ts +68 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/contact.ts +13 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/index.ts +72 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/rules.ts +120 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/types.ts +124 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +358 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +206 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/evidence.ts +109 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +225 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +143 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +47 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +113 -0
- package/templates/bills-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +113 -0
- package/templates/bills-agent/packages/agent-runtime/src/cli.ts +98 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/check.ts +15 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/decide.ts +63 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/eval.ts +58 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/inspect.ts +100 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +317 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/poll.ts +144 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/reconcile.ts +42 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/rerun.ts +86 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/resume.ts +43 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +131 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/start.ts +245 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/verify.ts +129 -0
- package/templates/bills-agent/packages/agent-runtime/src/commands/webhook.ts +39 -0
- package/templates/bills-agent/packages/agent-runtime/src/default-kit.ts +83 -0
- package/templates/bills-agent/packages/agent-runtime/src/index.ts +12 -0
- package/templates/bills-agent/packages/agent-runtime/src/inspect.ts +797 -0
- package/templates/bills-agent/packages/agent-runtime/src/kit.ts +206 -0
- package/templates/{collections-agent/agents/collections-agent → bills-agent/packages/agent-runtime}/src/poll.ts +22 -11
- package/templates/{collections-agent/agents/collections-agent → bills-agent/packages/agent-runtime}/src/scenarios.ts +50 -34
- package/templates/bills-agent/{agents/bills-agent → packages/agent-runtime}/src/setup.ts +88 -66
- package/templates/bills-agent/packages/agent-runtime/src/terminal.ts +154 -0
- package/templates/{collections-agent/agents/collections-agent/channels/webhook/index.ts → bills-agent/packages/agent-runtime/src/webhook.ts} +1 -1
- package/templates/bills-agent/packages/agent-runtime/test/inspect.test.ts +336 -0
- package/templates/bills-agent/packages/agent-runtime/test/verify-cli.test.ts +127 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +232 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +204 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-evidence.test.ts +94 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +174 -0
- package/templates/bills-agent/packages/agent-runtime/test/whatsapp-session.test.ts +135 -0
- package/templates/bills-agent/packages/agent-runtime/tsconfig.json +9 -0
- package/templates/bills-agent/vitest.config.ts +1 -1
- package/templates/collections-agent/README.md +8 -5
- package/templates/collections-agent/agents/collections-agent/.env.example +14 -0
- package/templates/collections-agent/agents/collections-agent/AGENTS.md +6 -4
- package/templates/collections-agent/agents/collections-agent/CLAUDE.md +6 -4
- package/templates/collections-agent/agents/collections-agent/README.md +184 -16
- package/templates/collections-agent/agents/collections-agent/agent.yaml +3 -3
- package/templates/collections-agent/agents/collections-agent/channels/whatsapp/README.md +111 -0
- package/templates/collections-agent/agents/collections-agent/channels/whatsapp/acordo-1042.json +11 -0
- package/templates/collections-agent/agents/collections-agent/channels/whatsapp/acordo-1103.json +11 -0
- package/templates/collections-agent/agents/collections-agent/channels/whatsapp/templates.json +23 -0
- package/templates/collections-agent/agents/collections-agent/package.json +12 -10
- package/templates/collections-agent/agents/collections-agent/runbook.md +52 -1
- package/templates/collections-agent/agents/collections-agent/src/kit.ts +265 -0
- package/templates/collections-agent/agents/collections-agent/test/adversarial.test.ts +9 -8
- package/templates/collections-agent/agents/collections-agent/test/check.test.ts +43 -1
- package/templates/collections-agent/agents/collections-agent/test/cli.test.ts +56 -18
- package/templates/collections-agent/agents/collections-agent/test/fixtures/agreed-1042-awaiting-payer.transcript.jsonl +4 -0
- package/templates/collections-agent/agents/collections-agent/test/scenarios.test.ts +11 -10
- package/templates/collections-agent/agents/collections-agent/test/webhook.test.ts +4 -7
- package/templates/collections-agent/agents/collections-agent/test/whatsapp-poll.test.ts +271 -0
- package/templates/collections-agent/agents/collections-agent/test/whatsapp.test.ts +213 -0
- package/templates/collections-agent/agents/collections-agent/tsconfig.json +0 -1
- package/templates/collections-agent/package.json +3 -1
- package/templates/collections-agent/packages/agent-core/README.md +2 -0
- package/templates/collections-agent/packages/agent-core/package.json +1 -1
- package/templates/collections-agent/packages/agent-core/src/api/charge-rail.ts +27 -6
- package/templates/collections-agent/packages/agent-core/src/api/rail.ts +16 -0
- package/templates/collections-agent/packages/agent-core/src/api/sandbox-payer.ts +20 -7
- package/templates/collections-agent/packages/agent-core/src/approval.ts +16 -2
- package/templates/collections-agent/packages/agent-core/src/bundle.ts +50 -4
- package/templates/collections-agent/packages/agent-core/src/channels.ts +140 -0
- package/templates/collections-agent/packages/agent-core/src/check.ts +90 -8
- package/templates/collections-agent/packages/agent-core/src/clock.ts +42 -0
- package/templates/collections-agent/packages/agent-core/src/engine.ts +119 -18
- package/templates/collections-agent/packages/agent-core/src/hash.ts +13 -0
- package/templates/collections-agent/packages/agent-core/src/index.ts +3 -0
- package/templates/collections-agent/packages/agent-core/src/manifest.ts +1 -1
- package/templates/collections-agent/packages/agent-core/src/rail.ts +16 -2
- package/templates/collections-agent/packages/agent-core/src/receipt-verification.ts +401 -0
- package/templates/collections-agent/packages/agent-core/src/state-machine.ts +3 -1
- package/templates/collections-agent/packages/agent-core/src/stubs/charge-rail.ts +2 -0
- package/templates/collections-agent/packages/agent-core/src/stubs/rail.ts +19 -2
- package/templates/collections-agent/packages/agent-core/src/types.ts +28 -0
- package/templates/collections-agent/packages/agent-core/test/approval.test.ts +36 -2
- package/templates/collections-agent/packages/agent-core/test/bundle.test.ts +85 -0
- package/templates/collections-agent/packages/agent-core/test/clock.test.ts +25 -0
- package/templates/collections-agent/packages/agent-core/test/engine.test.ts +73 -1
- package/templates/collections-agent/packages/agent-core/test/fixtures/staging-receipt-keys.json +18 -0
- package/templates/collections-agent/packages/agent-core/test/fixtures/staging-receipt.json +24 -0
- package/templates/collections-agent/packages/agent-core/test/helpers.ts +1 -1
- package/templates/collections-agent/packages/agent-core/test/manifest.test.ts +2 -2
- package/templates/collections-agent/packages/agent-core/test/receipt-verification.test.ts +316 -0
- package/templates/collections-agent/packages/agent-core/test/receivables.test.ts +51 -0
- package/templates/collections-agent/packages/agent-runtime/README.md +68 -0
- package/templates/collections-agent/packages/agent-runtime/bin.mjs +32 -0
- package/templates/collections-agent/packages/agent-runtime/package.json +23 -0
- package/templates/collections-agent/{agents/collections-agent → packages/agent-runtime}/src/adversarial.ts +29 -50
- package/templates/collections-agent/packages/agent-runtime/src/agent.ts +68 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/contact.ts +13 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/index.ts +72 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/rules.ts +120 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/types.ts +124 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +358 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +206 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/evidence.ts +109 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +225 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +143 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +47 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +113 -0
- package/templates/collections-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +113 -0
- package/templates/collections-agent/packages/agent-runtime/src/cli.ts +98 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/check.ts +15 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/decide.ts +63 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/eval.ts +58 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/inspect.ts +100 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +317 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/poll.ts +144 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/reconcile.ts +42 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/rerun.ts +86 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/resume.ts +43 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +131 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/start.ts +245 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/verify.ts +129 -0
- package/templates/collections-agent/packages/agent-runtime/src/commands/webhook.ts +39 -0
- package/templates/collections-agent/packages/agent-runtime/src/default-kit.ts +83 -0
- package/templates/collections-agent/packages/agent-runtime/src/index.ts +12 -0
- package/templates/collections-agent/packages/agent-runtime/src/inspect.ts +797 -0
- package/templates/collections-agent/packages/agent-runtime/src/kit.ts +206 -0
- package/templates/collections-agent/packages/agent-runtime/src/poll.ts +105 -0
- package/templates/{bills-agent/agents/bills-agent → collections-agent/packages/agent-runtime}/src/scenarios.ts +98 -26
- package/templates/collections-agent/packages/agent-runtime/src/setup.ts +229 -0
- package/templates/collections-agent/packages/agent-runtime/src/terminal.ts +154 -0
- package/templates/collections-agent/packages/agent-runtime/src/webhook.ts +131 -0
- package/templates/collections-agent/packages/agent-runtime/test/inspect.test.ts +336 -0
- package/templates/collections-agent/packages/agent-runtime/test/verify-cli.test.ts +127 -0
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +232 -0
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +204 -0
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-evidence.test.ts +94 -0
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +174 -0
- package/templates/collections-agent/packages/agent-runtime/test/whatsapp-session.test.ts +135 -0
- package/templates/collections-agent/packages/agent-runtime/tsconfig.json +9 -0
- package/templates/collections-agent/vitest.config.ts +1 -1
- package/templates/hello-agent/LICENSE +21 -0
- package/templates/hello-agent/README.md +23 -0
- package/templates/hello-agent/_gitignore +10 -0
- package/templates/hello-agent/agents/hello-agent/.env.example +5 -0
- package/templates/hello-agent/agents/hello-agent/AGENTS.md +15 -0
- package/templates/hello-agent/agents/hello-agent/CLAUDE.md +15 -0
- package/templates/hello-agent/agents/hello-agent/README.md +33 -0
- package/templates/hello-agent/agents/hello-agent/SYSTEM_PROMPT.md +19 -0
- package/templates/hello-agent/agents/hello-agent/agent.yaml +19 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/beneficiary-swap.json +6 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/beneficiary-swap.transcript.jsonl +2 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/exfiltration.json +6 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/exfiltration.transcript.jsonl +2 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/false-authority.json +6 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/false-authority.transcript.jsonl +2 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/fractioning.json +6 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/fractioning.transcript.jsonl +2 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/model-total.json +6 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/model-total.transcript.jsonl +2 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/prompt-injection.json +6 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/prompt-injection.transcript.jsonl +2 -0
- package/templates/hello-agent/agents/hello-agent/evals/adversarial/webhook-replay.json +6 -0
- package/templates/hello-agent/agents/hello-agent/evals/eval.yaml +7 -0
- package/templates/hello-agent/agents/hello-agent/guardrails.json +8 -0
- package/templates/hello-agent/agents/hello-agent/mandate.example.json +17 -0
- package/templates/hello-agent/agents/hello-agent/package.json +19 -0
- package/templates/hello-agent/agents/hello-agent/runbook.md +10 -0
- package/templates/hello-agent/agents/hello-agent/scenarios/happy-path.json +6 -0
- package/templates/hello-agent/agents/hello-agent/scenarios/happy-path.transcript.jsonl +2 -0
- package/templates/hello-agent/agents/hello-agent/scenarios/prompt-injection.json +6 -0
- package/templates/hello-agent/agents/hello-agent/scenarios/prompt-injection.transcript.jsonl +2 -0
- package/templates/hello-agent/agents/hello-agent/src/bills.ts +23 -0
- package/templates/hello-agent/agents/hello-agent/src/kit.ts +33 -0
- package/templates/hello-agent/agents/hello-agent/tools.json +11 -0
- package/templates/hello-agent/agents/hello-agent/tsconfig.json +9 -0
- package/templates/hello-agent/package.json +30 -0
- package/templates/hello-agent/packages/agent-core/README.md +21 -0
- package/templates/hello-agent/packages/agent-core/package.json +24 -0
- package/templates/hello-agent/packages/agent-core/src/agent.ts +125 -0
- package/templates/hello-agent/packages/agent-core/src/api/charge-rail.ts +175 -0
- package/templates/hello-agent/packages/agent-core/src/api/client.ts +53 -0
- package/templates/hello-agent/packages/agent-core/src/api/mandate-status.ts +58 -0
- package/templates/hello-agent/packages/agent-core/src/api/rail.ts +117 -0
- package/templates/hello-agent/packages/agent-core/src/api/sandbox-payer.ts +58 -0
- package/templates/hello-agent/packages/agent-core/src/approval.ts +123 -0
- package/templates/hello-agent/packages/agent-core/src/bundle.ts +159 -0
- package/templates/hello-agent/packages/agent-core/src/channels.ts +140 -0
- package/templates/hello-agent/packages/agent-core/src/check.ts +253 -0
- package/templates/hello-agent/packages/agent-core/src/clock.ts +42 -0
- package/templates/hello-agent/packages/agent-core/src/engine.ts +885 -0
- package/templates/hello-agent/packages/agent-core/src/escalate.ts +85 -0
- package/templates/hello-agent/packages/agent-core/src/events.ts +40 -0
- package/templates/hello-agent/packages/agent-core/src/guardrails.ts +45 -0
- package/templates/hello-agent/packages/agent-core/src/hash.ts +62 -0
- package/templates/hello-agent/packages/agent-core/src/ids.ts +10 -0
- package/templates/hello-agent/packages/agent-core/src/index.ts +32 -0
- package/templates/hello-agent/packages/agent-core/src/mandate.ts +100 -0
- package/templates/hello-agent/packages/agent-core/src/manifest.ts +76 -0
- package/templates/hello-agent/packages/agent-core/src/providers/anthropic.ts +76 -0
- package/templates/hello-agent/packages/agent-core/src/providers/replay.ts +63 -0
- package/templates/hello-agent/packages/agent-core/src/providers/types.ts +39 -0
- package/templates/hello-agent/packages/agent-core/src/rail.ts +101 -0
- package/templates/hello-agent/packages/agent-core/src/receipt-verification.ts +401 -0
- package/templates/hello-agent/packages/agent-core/src/revocation.ts +30 -0
- package/templates/hello-agent/packages/agent-core/src/secrets.ts +30 -0
- package/templates/hello-agent/packages/agent-core/src/state/store.ts +307 -0
- package/templates/hello-agent/packages/agent-core/src/state-machine.ts +148 -0
- package/templates/hello-agent/packages/agent-core/src/stubs/charge-rail.ts +195 -0
- package/templates/hello-agent/packages/agent-core/src/stubs/mandate-status.ts +57 -0
- package/templates/hello-agent/packages/agent-core/src/stubs/rail.ts +141 -0
- package/templates/hello-agent/packages/agent-core/src/tools.ts +55 -0
- package/templates/hello-agent/packages/agent-core/src/types.ts +134 -0
- package/templates/hello-agent/packages/agent-core/test/approval.test.ts +117 -0
- package/templates/hello-agent/packages/agent-core/test/bundle.test.ts +85 -0
- package/templates/hello-agent/packages/agent-core/test/clock.test.ts +25 -0
- package/templates/hello-agent/packages/agent-core/test/engine.test.ts +596 -0
- package/templates/hello-agent/packages/agent-core/test/escalate.test.ts +42 -0
- package/templates/hello-agent/packages/agent-core/test/fixtures/staging-receipt-keys.json +18 -0
- package/templates/hello-agent/packages/agent-core/test/fixtures/staging-receipt.json +24 -0
- package/templates/hello-agent/packages/agent-core/test/helpers.ts +139 -0
- package/templates/hello-agent/packages/agent-core/test/mandate-status.test.ts +153 -0
- package/templates/hello-agent/packages/agent-core/test/manifest.test.ts +45 -0
- package/templates/hello-agent/packages/agent-core/test/receipt-verification.test.ts +316 -0
- package/templates/hello-agent/packages/agent-core/test/receivables.test.ts +316 -0
- package/templates/hello-agent/packages/agent-core/test/secrets.test.ts +28 -0
- package/templates/hello-agent/packages/agent-core/test/state-machine.test.ts +67 -0
- package/templates/hello-agent/packages/agent-core/test/transitions.type-test.ts +59 -0
- package/templates/hello-agent/packages/agent-core/tsconfig.json +10 -0
- package/templates/hello-agent/packages/agent-runtime/README.md +68 -0
- package/templates/hello-agent/packages/agent-runtime/bin.mjs +32 -0
- package/templates/hello-agent/packages/agent-runtime/package.json +23 -0
- package/templates/hello-agent/packages/agent-runtime/src/adversarial.ts +169 -0
- package/templates/hello-agent/packages/agent-runtime/src/agent.ts +68 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/contact.ts +13 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/index.ts +72 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/rules.ts +120 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/types.ts +124 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +358 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +206 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/evidence.ts +109 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +225 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +143 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +47 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +113 -0
- package/templates/hello-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +113 -0
- package/templates/hello-agent/packages/agent-runtime/src/cli.ts +98 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/check.ts +15 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/decide.ts +63 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/eval.ts +58 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/inspect.ts +100 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +317 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/poll.ts +144 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/reconcile.ts +42 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/rerun.ts +86 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/resume.ts +43 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +131 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/start.ts +245 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/verify.ts +129 -0
- package/templates/hello-agent/packages/agent-runtime/src/commands/webhook.ts +39 -0
- package/templates/hello-agent/packages/agent-runtime/src/default-kit.ts +83 -0
- package/templates/hello-agent/packages/agent-runtime/src/index.ts +12 -0
- package/templates/hello-agent/packages/agent-runtime/src/inspect.ts +797 -0
- package/templates/hello-agent/packages/agent-runtime/src/kit.ts +206 -0
- package/templates/hello-agent/packages/agent-runtime/src/poll.ts +105 -0
- package/templates/hello-agent/packages/agent-runtime/src/scenarios.ts +268 -0
- package/templates/hello-agent/packages/agent-runtime/src/setup.ts +229 -0
- package/templates/hello-agent/packages/agent-runtime/src/terminal.ts +154 -0
- package/templates/hello-agent/packages/agent-runtime/src/webhook.ts +131 -0
- package/templates/hello-agent/packages/agent-runtime/test/inspect.test.ts +336 -0
- package/templates/hello-agent/packages/agent-runtime/test/verify-cli.test.ts +127 -0
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +232 -0
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +204 -0
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-evidence.test.ts +94 -0
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +174 -0
- package/templates/hello-agent/packages/agent-runtime/test/whatsapp-session.test.ts +135 -0
- package/templates/hello-agent/packages/agent-runtime/tsconfig.json +9 -0
- package/templates/hello-agent/tsconfig.base.json +16 -0
- package/templates/hello-agent/vitest.config.ts +12 -0
- package/templates/kits.lock.json +60 -12
- package/templates/supplier-payments-agent/LICENSE +21 -0
- package/templates/supplier-payments-agent/README.md +23 -0
- package/templates/supplier-payments-agent/_gitignore +10 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/.env.example +7 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/AGENTS.md +21 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/CLAUDE.md +21 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/README.md +118 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/SYSTEM_PROMPT.md +29 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/agent.yaml +26 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/batch-tampering.json +12 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/batch-tampering.transcript.jsonl +3 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/beneficiary-swap-mandate.json +9 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/beneficiary-swap.json +10 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/beneficiary-swap.transcript.jsonl +2 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/exfiltration.json +13 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/exfiltration.transcript.jsonl +3 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/false-authority.json +9 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/false-authority.transcript.jsonl +3 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/fractioning.json +15 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/fractioning.transcript.jsonl +6 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/model-total.json +10 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/model-total.transcript.jsonl +2 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/prompt-injection.json +9 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/prompt-injection.transcript.jsonl +2 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/adversarial/webhook-replay.json +9 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/evals/eval.yaml +9 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/guardrails.json +15 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/mandate.example.json +70 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/package.json +26 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/runbook.md +19 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/beneficiary-not-allowed.json +14 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/beneficiary-not-allowed.transcript.jsonl +2 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/cap-exceeded.json +12 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/cap-exceeded.transcript.jsonl +2 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/escalated-above-threshold.json +20 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/escalated-above-threshold.transcript.jsonl +7 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/happy-path.json +19 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/happy-path.transcript.jsonl +3 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/mandate-revoked.json +21 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/mandate-revoked.transcript.jsonl +9 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/partial-batch-failure.json +21 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/partial-batch-failure.transcript.jsonl +3 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/prompt-injection.json +12 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/scenarios/prompt-injection.transcript.jsonl +2 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/kit.ts +176 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/batch-payout.ts +345 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/modules/pix-out.ts +118 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/src/payables.ts +76 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/adversarial.test.ts +53 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/batch.test.ts +384 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/check.test.ts +109 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/test/scenarios.test.ts +81 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/tools.json +53 -0
- package/templates/supplier-payments-agent/agents/supplier-payments-agent/tsconfig.json +9 -0
- package/templates/supplier-payments-agent/package.json +36 -0
- package/templates/supplier-payments-agent/packages/agent-core/README.md +21 -0
- package/templates/supplier-payments-agent/packages/agent-core/package.json +24 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/agent.ts +125 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/api/charge-rail.ts +175 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/api/client.ts +53 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/api/mandate-status.ts +58 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/api/rail.ts +117 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/api/sandbox-payer.ts +58 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/approval.ts +123 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/bundle.ts +159 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/channels.ts +140 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/check.ts +253 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/clock.ts +42 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/engine.ts +885 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/escalate.ts +85 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/events.ts +40 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/guardrails.ts +45 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/hash.ts +62 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/ids.ts +10 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/index.ts +32 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/mandate.ts +100 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/manifest.ts +76 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/providers/anthropic.ts +76 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/providers/replay.ts +63 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/providers/types.ts +39 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/rail.ts +101 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/receipt-verification.ts +401 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/revocation.ts +30 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/secrets.ts +30 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/state/store.ts +307 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/state-machine.ts +148 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/stubs/charge-rail.ts +195 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/stubs/mandate-status.ts +57 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/stubs/rail.ts +141 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/tools.ts +55 -0
- package/templates/supplier-payments-agent/packages/agent-core/src/types.ts +134 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/approval.test.ts +117 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/bundle.test.ts +85 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/clock.test.ts +25 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/engine.test.ts +596 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/escalate.test.ts +42 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/fixtures/staging-receipt-keys.json +18 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/fixtures/staging-receipt.json +24 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/helpers.ts +139 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/mandate-status.test.ts +153 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/manifest.test.ts +45 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/receipt-verification.test.ts +316 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/receivables.test.ts +316 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/secrets.test.ts +28 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/state-machine.test.ts +67 -0
- package/templates/supplier-payments-agent/packages/agent-core/test/transitions.type-test.ts +59 -0
- package/templates/supplier-payments-agent/packages/agent-core/tsconfig.json +10 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/README.md +68 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/bin.mjs +32 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/package.json +23 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/adversarial.ts +169 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/agent.ts +68 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/contact.ts +13 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/index.ts +72 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/rules.ts +120 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/types.ts +124 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/cloud-api.ts +358 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/emulator.ts +206 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/evidence.ts +109 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/index.ts +225 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/open.ts +143 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/present.ts +47 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/run.ts +113 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/channels/whatsapp/session.ts +113 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/cli.ts +98 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/check.ts +15 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/decide.ts +63 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/eval.ts +58 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/inspect.ts +100 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll-whatsapp.ts +317 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/poll.ts +144 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/reconcile.ts +42 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/rerun.ts +86 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/resume.ts +43 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start-whatsapp.ts +131 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/start.ts +245 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/verify.ts +129 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/commands/webhook.ts +39 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/default-kit.ts +83 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/index.ts +12 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/inspect.ts +797 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/kit.ts +206 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/poll.ts +105 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/scenarios.ts +268 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/setup.ts +229 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/terminal.ts +154 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/src/webhook.ts +131 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/inspect.test.ts +336 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/verify-cli.test.ts +127 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-cloud-api.test.ts +232 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-emulator.integration.test.ts +204 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-evidence.test.ts +94 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-rules.test.ts +174 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/test/whatsapp-session.test.ts +135 -0
- package/templates/supplier-payments-agent/packages/agent-runtime/tsconfig.json +9 -0
- package/templates/supplier-payments-agent/tsconfig.base.json +16 -0
- package/templates/supplier-payments-agent/vitest.config.ts +12 -0
- package/templates/bills-agent/agents/bills-agent/channels/terminal/index.ts +0 -108
- package/templates/bills-agent/agents/bills-agent/src/commands/approve.ts +0 -9
- package/templates/bills-agent/agents/bills-agent/src/commands/check.ts +0 -13
- package/templates/bills-agent/agents/bills-agent/src/commands/consent.ts +0 -26
- package/templates/bills-agent/agents/bills-agent/src/commands/decide.ts +0 -45
- package/templates/bills-agent/agents/bills-agent/src/commands/deny.ts +0 -7
- package/templates/bills-agent/agents/bills-agent/src/commands/eval.ts +0 -37
- package/templates/bills-agent/agents/bills-agent/src/commands/reconcile.ts +0 -38
- package/templates/bills-agent/agents/bills-agent/src/commands/rerun.ts +0 -65
- package/templates/bills-agent/agents/bills-agent/src/commands/resume.ts +0 -30
- package/templates/bills-agent/agents/bills-agent/src/main.ts +0 -185
- package/templates/collections-agent/agents/collections-agent/channels/terminal/index.ts +0 -178
- package/templates/collections-agent/agents/collections-agent/src/commands/approve.ts +0 -10
- package/templates/collections-agent/agents/collections-agent/src/commands/check.ts +0 -13
- package/templates/collections-agent/agents/collections-agent/src/commands/decide.ts +0 -48
- package/templates/collections-agent/agents/collections-agent/src/commands/deny.ts +0 -7
- package/templates/collections-agent/agents/collections-agent/src/commands/eval.ts +0 -39
- package/templates/collections-agent/agents/collections-agent/src/commands/poll.ts +0 -35
- package/templates/collections-agent/agents/collections-agent/src/commands/reconcile.ts +0 -38
- package/templates/collections-agent/agents/collections-agent/src/commands/rerun.ts +0 -55
- package/templates/collections-agent/agents/collections-agent/src/commands/resume.ts +0 -30
- package/templates/collections-agent/agents/collections-agent/src/commands/webhook.ts +0 -36
- package/templates/collections-agent/agents/collections-agent/src/main.ts +0 -193
- package/templates/collections-agent/agents/collections-agent/src/setup.ts +0 -250
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { FIXED_CLOCK_ENV, InvalidFixedClockError, fixedClock, resolveFixedClock } from "../src/clock.js";
|
|
3
|
+
|
|
4
|
+
describe("fixedClock", () => {
|
|
5
|
+
it("starts at the instant and ticks one second per read, so no two events share a timestamp", () => {
|
|
6
|
+
const clock = fixedClock("2026-09-23T14:00:00-03:00");
|
|
7
|
+
expect(clock().toISOString()).toBe("2026-09-23T17:00:00.000Z");
|
|
8
|
+
expect(clock().toISOString()).toBe("2026-09-23T17:00:01.000Z");
|
|
9
|
+
expect(clock().toISOString()).toBe("2026-09-23T17:00:02.000Z");
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("refuses what Date cannot parse, and a bare date, naming the source", () => {
|
|
13
|
+
expect(() => fixedClock("yesterday")).toThrow(InvalidFixedClockError);
|
|
14
|
+
expect(() => fixedClock("2026-09-23", FIXED_CLOCK_ENV)).toThrow(/CODESPAR_AGENT_NOW must be an ISO 8601 instant/);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("resolveFixedClock", () => {
|
|
19
|
+
it("prefers the flag, falls back to the environment, and is undefined (the wall clock) without either", () => {
|
|
20
|
+
expect(resolveFixedClock(undefined, {})).toBeUndefined();
|
|
21
|
+
expect(resolveFixedClock(undefined, { [FIXED_CLOCK_ENV]: " " })).toBeUndefined();
|
|
22
|
+
expect(resolveFixedClock(undefined, { [FIXED_CLOCK_ENV]: "2026-09-23T20:08:00-03:00" })!().toISOString()).toBe("2026-09-23T23:08:00.000Z");
|
|
23
|
+
expect(resolveFixedClock("2026-09-23T14:00:00-03:00", { [FIXED_CLOCK_ENV]: "2026-09-23T20:08:00-03:00" })!().toISOString()).toBe("2026-09-23T17:00:00.000Z");
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, readdirSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { describe, expect, it } from "vitest";
|
|
4
|
-
import { ESCOLA, harness, MERCADO } from "./helpers.js";
|
|
4
|
+
import { ESCOLA, FUNCIONARIA, harness, MERCADO } from "./helpers.js";
|
|
5
5
|
|
|
6
6
|
const approver = { id: "usr_demo", channel: "terminal" };
|
|
7
7
|
|
|
@@ -521,4 +521,76 @@ describe("multi-item partial failure is named item by item", () => {
|
|
|
521
521
|
expect(h.store.getOutbox(out.idempotency_key)?.status).toBe("failed");
|
|
522
522
|
expect(h.store.getOutbox(out.idempotency_key)?.response).toEqual(out.outcomes);
|
|
523
523
|
});
|
|
524
|
+
|
|
525
|
+
it("a refusal in the MIDDLE does not stop the items after it: every attempt is sent and every one is named", async () => {
|
|
526
|
+
const h = harness({ mode: "human", rail: { refusePayees: [MERCADO] } });
|
|
527
|
+
const d = await h.engine.draft({ items: [{ payee: "escola", amount: 1000 }, { payee: "mercado", amount: 2000 }, { payee: "funcionaria", amount: 3000 }] });
|
|
528
|
+
if (!d.ok) throw new Error("refused");
|
|
529
|
+
const out = await h.engine.execute(h.engine.approve(d.execution.id, approver).id);
|
|
530
|
+
// Section 4.1: the execution closes `failed` because one attempt failed,
|
|
531
|
+
// and `outcomes` names EVERY item — including the one after the refusal.
|
|
532
|
+
expect(out.state).toBe("failed");
|
|
533
|
+
expect(out.outcomes.map((o) => o.status)).toEqual(["settled", "failed", "settled"]);
|
|
534
|
+
expect(h.rail.payCount).toBe(3); // all three reached the rail; the stub records a refusal too
|
|
535
|
+
expect(readdirSync(join(h.bundle.dir, "receipts"))).toHaveLength(2);
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
it("an unknown answer in the MIDDLE still sends the siblings, and the execution stays open until it is resolved", async () => {
|
|
539
|
+
const h = harness({ mode: "human", rail: { uncertainPayees: [MERCADO] } });
|
|
540
|
+
const d = await h.engine.draft({ items: [{ payee: "escola", amount: 1000 }, { payee: "mercado", amount: 2000 }, { payee: "funcionaria", amount: 3000 }] });
|
|
541
|
+
if (!d.ok) throw new Error("refused");
|
|
542
|
+
const out = await h.engine.execute(h.engine.approve(d.execution.id, approver).id);
|
|
543
|
+
// Open, not closed: one attempt has no outcome at all, and §4.1 says an
|
|
544
|
+
// execution closes only when every attempt has one.
|
|
545
|
+
expect(out.state).toBe("executing");
|
|
546
|
+
expect(out.reason).toBe("rail_uncertain");
|
|
547
|
+
expect(out.outcomes.map((o) => o.index)).toEqual([0, 2]);
|
|
548
|
+
expect(out.detail).toContain("psp_dispatch_uncertain");
|
|
549
|
+
// Reconciliation resolves the unknown one and only then does it close.
|
|
550
|
+
// The stub answers `in_flight` on the first look and finds the provider
|
|
551
|
+
// finished on the second, which is the shape a real timeout has.
|
|
552
|
+
expect((await h.engine.reconcile(d.execution.id)).state).toBe("executing");
|
|
553
|
+
const closed = await h.engine.reconcile(d.execution.id);
|
|
554
|
+
expect(closed.state).toBe("settled");
|
|
555
|
+
expect(closed.outcomes.map((o) => o.status)).toEqual(["settled", "settled", "settled"]);
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
it("an execution with a failed attempt AND an unknown one does not close as failed", async () => {
|
|
559
|
+
const h = harness({ mode: "human", rail: { refusePayees: [ESCOLA], uncertainPayees: [MERCADO] } });
|
|
560
|
+
const d = await h.engine.draft({ items: [{ payee: "escola", amount: 1000 }, { payee: "mercado", amount: 2000 }, { payee: "funcionaria", amount: 3000 }] });
|
|
561
|
+
if (!d.ok) throw new Error("refused");
|
|
562
|
+
const out = await h.engine.execute(h.engine.approve(d.execution.id, approver).id);
|
|
563
|
+
// "One of them failed and one of them we cannot see" is not a closed
|
|
564
|
+
// outcome: reporting `failed` here would call a batch finished while a
|
|
565
|
+
// payment may still be in flight.
|
|
566
|
+
expect(out.state).toBe("executing");
|
|
567
|
+
expect(out.outcomes.map((o) => o.status)).toEqual(["failed", "settled"]);
|
|
568
|
+
expect((await h.engine.reconcile(d.execution.id)).state).toBe("executing");
|
|
569
|
+
const closed = await h.engine.reconcile(d.execution.id);
|
|
570
|
+
expect(closed.state).toBe("failed");
|
|
571
|
+
expect(closed.outcomes.map((o) => o.status)).toEqual(["failed", "settled", "settled"]);
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
it("why the siblings are sent and not deferred: an attempt that was never sent is recovered by nothing", async () => {
|
|
575
|
+
// This is the measurement the choice rests on. `reconcile` is read-only by
|
|
576
|
+
// contract and never dispatches; `resumePending` dispatches only while the
|
|
577
|
+
// outbox row is still `pending`, and it flips to `sent` before the first
|
|
578
|
+
// rail call. So an attempt skipped at dispatch is not sent later — it is
|
|
579
|
+
// never sent, by any path the runtime has.
|
|
580
|
+
const h = harness({ mode: "human", rail: { uncertainPayees: [MERCADO] } });
|
|
581
|
+
const d = await h.engine.draft({ items: [{ payee: "escola", amount: 1000 }, { payee: "mercado", amount: 2000 }, { payee: "funcionaria", amount: 3000 }] });
|
|
582
|
+
if (!d.ok) throw new Error("refused");
|
|
583
|
+
const out = await h.engine.execute(h.engine.approve(d.execution.id, approver).id);
|
|
584
|
+
const third = `att_${out.idempotency_key.slice(4)}_2`;
|
|
585
|
+
// Under the fix the third attempt WAS sent, so the rail knows it.
|
|
586
|
+
expect(h.store.stubRailGet(third)).toBeDefined();
|
|
587
|
+
expect(h.store.getOutbox(out.idempotency_key)?.status).toBe("sent");
|
|
588
|
+
// And that is the only reason it is recoverable: `resumePending` on a
|
|
589
|
+
// `sent` row reconciles instead of dispatching, and never pays again.
|
|
590
|
+
const before = h.rail.payCount;
|
|
591
|
+
expect((await h.engine.resumePending(d.execution.id)).state).toBe("executing");
|
|
592
|
+
const resumed = await h.engine.resumePending(d.execution.id);
|
|
593
|
+
expect(h.rail.payCount).toBe(before); // reconciled, never re-sent
|
|
594
|
+
expect(resumed.state).toBe("settled");
|
|
595
|
+
});
|
|
524
596
|
});
|
package/templates/collections-agent/packages/agent-core/test/fixtures/staging-receipt-keys.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"issuer": "did:web:id.codespar.dev",
|
|
3
|
+
"algorithm": "Ed25519",
|
|
4
|
+
"signing_string": "codespar-receipt:v1:<receipt_id>:<chain>",
|
|
5
|
+
"keys": [
|
|
6
|
+
{
|
|
7
|
+
"kid": "did:web:id.codespar.dev#1",
|
|
8
|
+
"kty": "OKP",
|
|
9
|
+
"crv": "Ed25519",
|
|
10
|
+
"x": "u7hulmfhdU9wxv44pfychrNTF0RvUIwDn_QKi3j5Puk",
|
|
11
|
+
"alg": "EdDSA",
|
|
12
|
+
"use": "sig",
|
|
13
|
+
"status": "active",
|
|
14
|
+
"created_at": "2026-09-24T22:22:38.589Z",
|
|
15
|
+
"retired_at": null
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"receipt_id": "rcpt_BkYTo_9eJnlyzGsRjfFYHk",
|
|
3
|
+
"state": "paid",
|
|
4
|
+
"mandate": {
|
|
5
|
+
"id": "cm_8m6ew__uzvMrp2i3"
|
|
6
|
+
},
|
|
7
|
+
"payment": {
|
|
8
|
+
"amount_minor": 185000,
|
|
9
|
+
"payee": null,
|
|
10
|
+
"attempt_id": "att_50fa99e93ed1183520bfd185d350a7c4_0",
|
|
11
|
+
"money_moved": false,
|
|
12
|
+
"sandbox": true,
|
|
13
|
+
"at": "2026-09-24T22:42:41.242Z"
|
|
14
|
+
},
|
|
15
|
+
"chain": "cf5a00d44c4aea42bd7e4bcb48f37f077bfeae1ff5f6f4fff20438861a79e17d",
|
|
16
|
+
"receipt_sig": "9a63a12e9ab88e10c76f77d8ec0c3f4dec9ca1251579a608be1be260922b312c",
|
|
17
|
+
"receipt_sig_ed25519": "aQTf3A1UR8kdthPUwBDfAmnnpYyn8SUp1DYyKcvMylOYhLtznQS_h2SB-N9PxQtSS2wTSO-lp_YDrrVS5Nz1CA",
|
|
18
|
+
"receipt_sig_kid": "did:web:id.codespar.dev#1",
|
|
19
|
+
"actor": {
|
|
20
|
+
"type": "agent",
|
|
21
|
+
"agent": "bills-agent@0.1.0",
|
|
22
|
+
"on_behalf_of": "usr_demo_titular"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -26,7 +26,7 @@ export function testManifest(over: Partial<Manifest> = {}): Manifest {
|
|
|
26
26
|
default_approval: "human",
|
|
27
27
|
escalate_above: { amount: 150000, new_beneficiary: true, outside_hours: "22:00-07:00" },
|
|
28
28
|
mcp: "@codespar/mcp@0.5.8",
|
|
29
|
-
cli: "@codespar/cli@0.
|
|
29
|
+
cli: "@codespar/cli@0.14.0",
|
|
30
30
|
tools: "./tools.json",
|
|
31
31
|
guardrails: "./guardrails.json",
|
|
32
32
|
mandate_schema: "./mandate.example.json",
|
|
@@ -12,7 +12,7 @@ escalate_above:
|
|
|
12
12
|
new_beneficiary: true
|
|
13
13
|
outside_hours: "22:00-07:00"
|
|
14
14
|
mcp: "@codespar/mcp@0.5.8"
|
|
15
|
-
cli: "@codespar/cli@0.
|
|
15
|
+
cli: "@codespar/cli@0.14.0"
|
|
16
16
|
tools: ./tools.json
|
|
17
17
|
guardrails: ./guardrails.json
|
|
18
18
|
mandate_schema: ./mandate.example.json
|
|
@@ -36,7 +36,7 @@ describe("section 4.3: agent.yaml schema 1", () => {
|
|
|
36
36
|
|
|
37
37
|
it("refuses an unpinned mcp or cli, a wrong schema, and an unknown field", () => {
|
|
38
38
|
expect(() => parseManifest(valid.replace('"@codespar/mcp@0.5.8"', '"@codespar/mcp"'))).toThrow(/mcp/);
|
|
39
|
-
expect(() => parseManifest(valid.replace('"@codespar/cli@0.
|
|
39
|
+
expect(() => parseManifest(valid.replace('"@codespar/cli@0.14.0"', '"@codespar/cli@latest"'))).toThrow(/cli/);
|
|
40
40
|
expect(() => parseManifest(valid.replace("schema: 1", "schema: 2"))).toThrow();
|
|
41
41
|
expect(() => parseManifest(valid + "telemetry: true\n")).toThrow(/unrecognized/i);
|
|
42
42
|
expect(() => parseManifest(valid.replace("default_approval: human", "default_approval: mandate").replace("approval: [human, mandate]", "approval: [human]"))).toThrow(/default_approval/);
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wave-5 contract: a party with the receipt JSON and the published key set
|
|
3
|
+
* reaches the right answer, and the wrong answers stay apart from each other.
|
|
4
|
+
*
|
|
5
|
+
* The signatures here are made with stock `node:crypto` and a key generated in
|
|
6
|
+
* the test, never with the module under test: a test that signed with the
|
|
7
|
+
* verifier's own helper would prove the helper agrees with itself. The signed
|
|
8
|
+
* string is written out literally for the same reason — if the enterprise ever
|
|
9
|
+
* changes the shape, this line fails rather than following it.
|
|
10
|
+
*
|
|
11
|
+
* No network: the key set is a document, or a fetcher the test supplies.
|
|
12
|
+
*/
|
|
13
|
+
import { createPublicKey, generateKeyPairSync, sign as signDetached, verify as nodeVerify, type KeyObject } from "node:crypto";
|
|
14
|
+
import { readFileSync } from "node:fs";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { describe, expect, it } from "vitest";
|
|
17
|
+
import {
|
|
18
|
+
DEFAULT_RECEIPT_KEYS_URL,
|
|
19
|
+
RECEIPT_SIGNATURE_DOMAIN,
|
|
20
|
+
VERDICT_EXIT_CODES,
|
|
21
|
+
receiptKeysUrl,
|
|
22
|
+
receiptSigningString,
|
|
23
|
+
verifyReceipt,
|
|
24
|
+
verifyReceiptWithKeys,
|
|
25
|
+
type PublishedReceiptKey,
|
|
26
|
+
} from "../src/receipt-verification.js";
|
|
27
|
+
|
|
28
|
+
const KID = "did:web:id.codespar.dev#1";
|
|
29
|
+
const CHAIN = "9f2c4a1b6d0e8f3a5c7b9d1e2f4a6b8c0d2e4f6a8b0c2d4e6f8a0b2c4d6e8f01";
|
|
30
|
+
const RECEIPT_ID = "rcpt_V1StGXR8Z5jdHi6BmyT0sw";
|
|
31
|
+
|
|
32
|
+
function keypair() {
|
|
33
|
+
const { privateKey, publicKey } = generateKeyPairSync("ed25519");
|
|
34
|
+
const raw = publicKey.export({ format: "der", type: "spki" }).subarray(-32);
|
|
35
|
+
return { privateKey, x: Buffer.from(raw).toString("base64url") };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function publishedKey(x: string, over: Partial<PublishedReceiptKey> = {}): PublishedReceiptKey {
|
|
39
|
+
return { kid: KID, kty: "OKP", crv: "Ed25519", x, alg: "EdDSA", use: "sig", status: "active", ...over };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function keySet(...keys: PublishedReceiptKey[]) {
|
|
43
|
+
return { issuer: "did:web:id.codespar.dev", algorithm: "Ed25519", signing_string: `${RECEIPT_SIGNATURE_DOMAIN}:<receipt_id>:<chain>`, keys };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function seal(privateKey: KeyObject, receiptId = RECEIPT_ID, chain = CHAIN): string {
|
|
47
|
+
return signDetached(null, Buffer.from(`codespar-receipt:v1:${receiptId}:${chain}`, "utf8"), privateKey).toString("base64url");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function receipt(over: Record<string, unknown> = {}) {
|
|
51
|
+
return {
|
|
52
|
+
receipt_id: RECEIPT_ID,
|
|
53
|
+
state: "paid",
|
|
54
|
+
mandate: { id: "mnd_1" },
|
|
55
|
+
payment: { amount_minor: 12345, payee: "es***@exemplo.com.br", attempt_id: "att_1", money_moved: false, sandbox: true, at: "2026-09-24T12:00:00.000Z" },
|
|
56
|
+
chain: CHAIN,
|
|
57
|
+
receipt_sig: "hmac-half-not-read-here",
|
|
58
|
+
receipt_sig_ed25519: null,
|
|
59
|
+
receipt_sig_kid: null,
|
|
60
|
+
...over,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
describe("the signed string", () => {
|
|
65
|
+
it("is the enterprise's, byte for byte", () => {
|
|
66
|
+
expect(receiptSigningString(RECEIPT_ID, CHAIN)).toBe(`codespar-receipt:v1:${RECEIPT_ID}:${CHAIN}`);
|
|
67
|
+
expect(RECEIPT_SIGNATURE_DOMAIN).toBe("codespar-receipt:v1");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("names the key set of a deployment from its base url", () => {
|
|
71
|
+
expect(receiptKeysUrl("https://api.codespar.dev")).toBe(DEFAULT_RECEIPT_KEYS_URL);
|
|
72
|
+
expect(receiptKeysUrl("https://staging.example/v1/anything")).toBe("https://staging.example/.well-known/codespar-receipt-keys.json");
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe("verified", () => {
|
|
77
|
+
it("accepts a receipt CodeSpar sealed, and says which key signed it", () => {
|
|
78
|
+
const { privateKey, x } = keypair();
|
|
79
|
+
const report = verifyReceiptWithKeys(receipt({ receipt_sig_ed25519: seal(privateKey), receipt_sig_kid: KID }), keySet(publishedKey(x)));
|
|
80
|
+
expect(report.verdict).toBe("verified");
|
|
81
|
+
expect(report.receipt_id).toBe(RECEIPT_ID);
|
|
82
|
+
expect(report.kid).toBe(KID);
|
|
83
|
+
expect(report.key_status).toBe("active");
|
|
84
|
+
expect(report.signing_string).toBe(`codespar-receipt:v1:${RECEIPT_ID}:${CHAIN}`);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("accepts a signature made by a RETIRED key: rotation retires, it does not revoke", () => {
|
|
88
|
+
const { privateKey, x } = keypair();
|
|
89
|
+
const retired = publishedKey(x, { status: "retired", retired_at: "2026-09-01T00:00:00.000Z" });
|
|
90
|
+
const report = verifyReceiptWithKeys(receipt({ receipt_sig_ed25519: seal(privateKey), receipt_sig_kid: KID }), keySet(retired, publishedKey("ignored", { kid: "did:web:id.codespar.dev#2" })));
|
|
91
|
+
expect(report.verdict).toBe("verified");
|
|
92
|
+
expect(report.key_status).toBe("retired");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("still verifies the proof bundle's masked copy: the signature covers the id and the chain, not the body", () => {
|
|
96
|
+
const { privateKey, x } = keypair();
|
|
97
|
+
const sealed = receipt({ receipt_sig_ed25519: seal(privateKey), receipt_sig_kid: KID });
|
|
98
|
+
const masked = { ...sealed, payment: { ...sealed.payment, payee: "es***@exemplo.com.br" }, raw: undefined };
|
|
99
|
+
expect(verifyReceiptWithKeys(masked, keySet(publishedKey(x))).verdict).toBe("verified");
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe("tampered", () => {
|
|
104
|
+
it("refuses a receipt whose chain was changed after it was sealed", () => {
|
|
105
|
+
const { privateKey, x } = keypair();
|
|
106
|
+
const report = verifyReceiptWithKeys(receipt({ receipt_sig_ed25519: seal(privateKey), receipt_sig_kid: KID, chain: CHAIN.replace(/^9/, "8") }), keySet(publishedKey(x)));
|
|
107
|
+
expect(report.verdict).toBe("tampered");
|
|
108
|
+
expect(report.reason).toBe("signature_does_not_match");
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("refuses a signature lifted from another receipt: the id is in the signed string", () => {
|
|
112
|
+
const { privateKey, x } = keypair();
|
|
113
|
+
const other = seal(privateKey, "rcpt_somebodyelsesreceipt", CHAIN);
|
|
114
|
+
const report = verifyReceiptWithKeys(receipt({ receipt_sig_ed25519: other, receipt_sig_kid: KID }), keySet(publishedKey(x)));
|
|
115
|
+
expect(report.verdict).toBe("tampered");
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("refuses a signature made by a key that is not the published one, and names the deployment case", () => {
|
|
119
|
+
const { privateKey } = keypair();
|
|
120
|
+
const other = keypair();
|
|
121
|
+
// The shape of the staging-receipt-against-production-keys mistake: both
|
|
122
|
+
// deployments publish a key called `did:web:id.codespar.dev#1` and the two
|
|
123
|
+
// are not the same key, so the message has to offer that reading.
|
|
124
|
+
const report = verifyReceiptWithKeys(receipt({ receipt_sig_ed25519: seal(privateKey), receipt_sig_kid: KID }), keySet(publishedKey(other.x)));
|
|
125
|
+
expect(report.verdict).toBe("tampered");
|
|
126
|
+
expect(report.message).toContain("deployment");
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("refuses a signature that is not 64 base64url bytes", () => {
|
|
130
|
+
const { x } = keypair();
|
|
131
|
+
const report = verifyReceiptWithKeys(receipt({ receipt_sig_ed25519: "not-a-signature", receipt_sig_kid: KID }), keySet(publishedKey(x)));
|
|
132
|
+
expect(report.verdict).toBe("tampered");
|
|
133
|
+
expect(report.reason).toBe("signature_malformed");
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe("unsigned", () => {
|
|
138
|
+
it("is not a failure: it says the receipt predates the capability, and that the HMAC is unaffected", () => {
|
|
139
|
+
const report = verifyReceiptWithKeys(receipt(), keySet());
|
|
140
|
+
expect(report.verdict).toBe("unsigned");
|
|
141
|
+
expect(report.message).toContain("never will");
|
|
142
|
+
expect(report.message).toContain("HMAC");
|
|
143
|
+
expect(report.kid).toBeNull();
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("answers the same when the two fields are absent rather than null", () => {
|
|
147
|
+
const { receipt_sig_ed25519: _sig, receipt_sig_kid: _kid, ...older } = receipt();
|
|
148
|
+
expect(verifyReceiptWithKeys(older, keySet()).verdict).toBe("unsigned");
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("answers without a key set at all, and without fetching one", async () => {
|
|
152
|
+
let fetched = 0;
|
|
153
|
+
const report = await verifyReceipt(receipt(), {
|
|
154
|
+
url: "https://example.invalid/keys.json",
|
|
155
|
+
fetch: async () => {
|
|
156
|
+
fetched += 1;
|
|
157
|
+
return keySet();
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
expect(report.verdict).toBe("unsigned");
|
|
161
|
+
expect(fetched).toBe(0);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("covers a paid charge, which the API seals nothing for", () => {
|
|
165
|
+
const charge = { receipt_id: "chg_1", kind: "charge", state: "paid", chain: null, receipt_sig: null, receipt_sig_ed25519: null, receipt_sig_kid: null };
|
|
166
|
+
expect(verifyReceiptWithKeys(charge, keySet()).verdict).toBe("unsigned");
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe("unknown_key", () => {
|
|
171
|
+
it("refuses to guess when the kid is not published", () => {
|
|
172
|
+
const { privateKey, x } = keypair();
|
|
173
|
+
const report = verifyReceiptWithKeys(receipt({ receipt_sig_ed25519: seal(privateKey), receipt_sig_kid: "did:web:id.codespar.dev#9" }), keySet(publishedKey(x)));
|
|
174
|
+
expect(report.verdict).toBe("unknown_key");
|
|
175
|
+
expect(report.kid).toBe("did:web:id.codespar.dev#9");
|
|
176
|
+
expect(report.message).toContain("retired keys published");
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("does not fall back to the only key in the set", () => {
|
|
180
|
+
const { privateKey, x } = keypair();
|
|
181
|
+
const report = verifyReceiptWithKeys(receipt({ receipt_sig_ed25519: seal(privateKey), receipt_sig_kid: "did:web:other.example#1" }), keySet(publishedKey(x)));
|
|
182
|
+
expect(report.verdict).toBe("unknown_key");
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe("unreachable", () => {
|
|
187
|
+
it("is what a failed fetch answers — never `tampered`", async () => {
|
|
188
|
+
const { privateKey } = keypair();
|
|
189
|
+
const report = await verifyReceipt(receipt({ receipt_sig_ed25519: seal(privateKey), receipt_sig_kid: KID }), {
|
|
190
|
+
url: "https://example.invalid/keys.json",
|
|
191
|
+
fetch: async () => {
|
|
192
|
+
throw new Error("getaddrinfo ENOTFOUND example.invalid");
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
expect(report.verdict).toBe("unreachable");
|
|
196
|
+
expect(report.reason).toBe("fetch_failed");
|
|
197
|
+
expect(report.message).toContain("Nothing is proved and nothing is disproved");
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("is what a document that is not a key set answers", () => {
|
|
201
|
+
const { privateKey } = keypair();
|
|
202
|
+
const report = verifyReceiptWithKeys(receipt({ receipt_sig_ed25519: seal(privateKey), receipt_sig_kid: KID }), { error: "not found" });
|
|
203
|
+
expect(report.verdict).toBe("unreachable");
|
|
204
|
+
expect(report.reason).toBe("key_document_unreadable");
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("is what an unusable published key answers: a key we cannot read tells us nothing about the signature", () => {
|
|
208
|
+
const { privateKey } = keypair();
|
|
209
|
+
const report = verifyReceiptWithKeys(receipt({ receipt_sig_ed25519: seal(privateKey), receipt_sig_kid: KID }), keySet(publishedKey("AAAA")));
|
|
210
|
+
expect(report.verdict).toBe("unreachable");
|
|
211
|
+
expect(report.reason).toBe("key_unusable");
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("fetches the published set and verifies against it when the fetch works", async () => {
|
|
215
|
+
const { privateKey, x } = keypair();
|
|
216
|
+
const seen: string[] = [];
|
|
217
|
+
const report = await verifyReceipt(receipt({ receipt_sig_ed25519: seal(privateKey), receipt_sig_kid: KID }), {
|
|
218
|
+
fetch: async (url) => {
|
|
219
|
+
seen.push(url);
|
|
220
|
+
return keySet(publishedKey(x));
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
expect(seen).toEqual([DEFAULT_RECEIPT_KEYS_URL]);
|
|
224
|
+
expect(report.verdict).toBe("verified");
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
describe("malformed", () => {
|
|
229
|
+
it("does not call an arbitrary JSON file an unsigned receipt", () => {
|
|
230
|
+
const report = verifyReceiptWithKeys({ hello: "world" }, keySet());
|
|
231
|
+
expect(report.verdict).toBe("malformed");
|
|
232
|
+
expect(report.reason).toBe("receipt_id_missing");
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it("refuses a signature whose kid was deleted, instead of reading it as unsigned", () => {
|
|
236
|
+
const { privateKey } = keypair();
|
|
237
|
+
const report = verifyReceiptWithKeys(receipt({ receipt_sig_ed25519: seal(privateKey), receipt_sig_kid: null }), keySet());
|
|
238
|
+
expect(report.verdict).toBe("malformed");
|
|
239
|
+
expect(report.reason).toBe("kid_missing");
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("refuses a kid whose signature was deleted", () => {
|
|
243
|
+
const report = verifyReceiptWithKeys(receipt({ receipt_sig_kid: KID }), keySet());
|
|
244
|
+
expect(report.verdict).toBe("malformed");
|
|
245
|
+
expect(report.reason).toBe("signature_missing");
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it("refuses a signed receipt whose chain was deleted: the signed string cannot be rebuilt", () => {
|
|
249
|
+
const { privateKey } = keypair();
|
|
250
|
+
const report = verifyReceiptWithKeys(receipt({ receipt_sig_ed25519: seal(privateKey), receipt_sig_kid: KID, chain: null }), keySet());
|
|
251
|
+
expect(report.verdict).toBe("malformed");
|
|
252
|
+
expect(report.reason).toBe("chain_missing");
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it("refuses a JSON array or a string", () => {
|
|
256
|
+
expect(verifyReceiptWithKeys([], keySet()).verdict).toBe("malformed");
|
|
257
|
+
expect(verifyReceiptWithKeys("rcpt_1", keySet()).verdict).toBe("malformed");
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
describe("the exit codes", () => {
|
|
262
|
+
it("keep every verdict apart, and do not call an unsigned receipt a success", () => {
|
|
263
|
+
expect(VERDICT_EXIT_CODES.verified).toBe(0);
|
|
264
|
+
expect(new Set(Object.values(VERDICT_EXIT_CODES)).size).toBe(Object.keys(VERDICT_EXIT_CODES).length);
|
|
265
|
+
expect(Object.values(VERDICT_EXIT_CODES)).not.toContain(2); // 2 is the usage error every other command uses
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
describe("the check a third party reimplements", () => {
|
|
270
|
+
it("is four lines of node:crypto over the published JWK", () => {
|
|
271
|
+
const { privateKey, x } = keypair();
|
|
272
|
+
const signature = seal(privateKey);
|
|
273
|
+
// Exactly what someone outside CodeSpar writes, with no code of ours.
|
|
274
|
+
const ok = nodeVerify(
|
|
275
|
+
null,
|
|
276
|
+
Buffer.from(`codespar-receipt:v1:${RECEIPT_ID}:${CHAIN}`, "utf8"),
|
|
277
|
+
createPublicKey({ key: { kty: "OKP", crv: "Ed25519", x }, format: "jwk" }),
|
|
278
|
+
Buffer.from(signature, "base64url"),
|
|
279
|
+
);
|
|
280
|
+
expect(ok).toBe(true);
|
|
281
|
+
expect(verifyReceiptWithKeys(receipt({ receipt_sig_ed25519: signature, receipt_sig_kid: KID }), keySet(publishedKey(x))).verdict).toBe("verified");
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* The one fixture that is not this test's own: a receipt the CodeSpar sandbox
|
|
287
|
+
* actually sealed (bills-agent, staging, 2026-09-24), as the proof bundle
|
|
288
|
+
* wrote it, and the key set that deployment publishes, as it was served. Every
|
|
289
|
+
* other case here signs with a key the test made, which proves the module is
|
|
290
|
+
* self-consistent; this one proves it agrees with the signer.
|
|
291
|
+
*
|
|
292
|
+
* Offline: both are files. If the API ever changes the signed string, this is
|
|
293
|
+
* the case that fails.
|
|
294
|
+
*/
|
|
295
|
+
describe("a receipt the sandbox really sealed", () => {
|
|
296
|
+
const dir = join(import.meta.dirname, "fixtures");
|
|
297
|
+
const real = JSON.parse(readFileSync(join(dir, "staging-receipt.json"), "utf8")) as Record<string, unknown>;
|
|
298
|
+
const realKeys = JSON.parse(readFileSync(join(dir, "staging-receipt-keys.json"), "utf8")) as unknown;
|
|
299
|
+
|
|
300
|
+
it("verifies against the key set that deployment publishes", () => {
|
|
301
|
+
const report = verifyReceiptWithKeys(real, realKeys, "staging");
|
|
302
|
+
expect(report.verdict).toBe("verified");
|
|
303
|
+
expect(report.kid).toBe("did:web:id.codespar.dev#1");
|
|
304
|
+
expect(report.signing_string).toBe(`codespar-receipt:v1:${real["receipt_id"] as string}:${real["chain"] as string}`);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it("is refused when one character of the chain changes", () => {
|
|
308
|
+
const chain = real["chain"] as string;
|
|
309
|
+
const edited = { ...real, chain: chain.slice(0, -1) + (chain.endsWith("0") ? "1" : "0") };
|
|
310
|
+
expect(verifyReceiptWithKeys(edited, realKeys, "staging").verdict).toBe("tampered");
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it("is refused when the receipt id changes, which is why the id is in the signed string", () => {
|
|
314
|
+
expect(verifyReceiptWithKeys({ ...real, receipt_id: "rcpt_0000000000000000000000" }, realKeys, "staging").verdict).toBe("tampered");
|
|
315
|
+
});
|
|
316
|
+
});
|
|
@@ -263,3 +263,54 @@ describe("outcomeOf: the API's charge view, mapped by fields and never by prose"
|
|
|
263
263
|
expect(outcomeOf({ ...base, payment_in_flight: true, settlement: "pending" })).toMatchObject({ status: "accepted" });
|
|
264
264
|
});
|
|
265
265
|
});
|
|
266
|
+
|
|
267
|
+
describe("CodeSparChargeRail: what crosses the wire on a create", () => {
|
|
268
|
+
it("sends consumer_id, method boleto, due_date, the attempt id as idempotency_key and the amount in major units; refuses without a consumer", async () => {
|
|
269
|
+
const { CodeSparChargeRail } = await import("../src/api/charge-rail.js");
|
|
270
|
+
const calls: Array<{ path: string; body: Record<string, unknown> }> = [];
|
|
271
|
+
const api = {
|
|
272
|
+
post: async (path: string, opts: { body: Record<string, unknown> }) => {
|
|
273
|
+
calls.push({ path, body: opts.body });
|
|
274
|
+
return { id: "chg_wire_1", status: "PROCESSING", local_status: "pending", status_conflict: false, method: "boleto", currency: "BRL", amount: 1080, amount_minor: 108000, due_date: "2026-09-30", payable: false, boleto_bar_code: null, boleto_bank_line: null, pix_copy_paste: null, credit_correlation_armed: false, payment_in_flight: false, settlement: null, issuance_unconfirmed: false };
|
|
275
|
+
},
|
|
276
|
+
get: async () => { throw new Error("not called"); },
|
|
277
|
+
};
|
|
278
|
+
const rail = new CodeSparChargeRail(api as never);
|
|
279
|
+
const base = { attempt_id: "att_x_0", mandate_id: "pol_1", amount_minor: 108000, currency: "BRL", payee: DEBTOR, beneficiary: "Joana Ribeiro", purpose: "cobranca", agent_id: "collections-agent", description: "Acordo #1042 - parcela 1/1", due_date: "2026-09-30", actor: { type: "agent" as const, agent: "collections-agent@0.1.0", on_behalf_of: "merchant_demo_loja" } };
|
|
280
|
+
expect(await rail.pay(base)).toMatchObject({ status: "failed", code: "consumer_id_required" });
|
|
281
|
+
expect(calls).toHaveLength(0);
|
|
282
|
+
const out = await rail.pay({ ...base, consumer_id: "merchant_demo_loja" });
|
|
283
|
+
expect(out).toMatchObject({ status: "accepted", transaction_id: "chg_wire_1", instrument: { payable: false, status: "PROCESSING" } });
|
|
284
|
+
expect(calls[0]).toEqual({ path: "/v1/charges", body: { consumer_id: "merchant_demo_loja", amount: 1080, currency: "BRL", method: "boleto", description: "Acordo #1042 - parcela 1/1", buyer: { name: "Joana Ribeiro", document: DEBTOR }, due_date: "2026-09-30", idempotency_key: "att_x_0" } });
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
describe("paySandboxCharge: the SDK's typed call to the payer route", () => {
|
|
289
|
+
it("posts to /v1/test/charges/{id}/pay with the key, the project header and the amount; refuses a live key before any request", async () => {
|
|
290
|
+
const { paySandboxCharge } = await import("../src/api/sandbox-payer.js");
|
|
291
|
+
const seen: Array<{ url: string; init: RequestInit }> = [];
|
|
292
|
+
const realFetch = globalThis.fetch;
|
|
293
|
+
globalThis.fetch = (async (url: string | URL | Request, init?: RequestInit) => {
|
|
294
|
+
seen.push({ url: String(url), init: init ?? {} });
|
|
295
|
+
return new Response(JSON.stringify({ charge_id: "chg_1", status: "paid", local_status: "settled", simulated: true, settled_against: "sandbox_fixture", money_moved: false, quoted_minor: 1000, paid_minor: 1000, payment: "full", idempotent_replay: false }), { status: 200, headers: { "content-type": "application/json" } });
|
|
296
|
+
}) as typeof fetch;
|
|
297
|
+
try {
|
|
298
|
+
const live = await paySandboxCharge({ apiKey: ["csk", "live", "0000000000"].join("_") }, "chg_1").catch((e: Error) => e);
|
|
299
|
+
expect(live).toBeInstanceOf(Error);
|
|
300
|
+
expect(seen).toHaveLength(0);
|
|
301
|
+
const out = await paySandboxCharge({ apiKey: "csk_test_unit_0000", baseUrl: "https://api.example.test/", projectId: "prj_1" }, "chg_1", 1000);
|
|
302
|
+
expect(out).toMatchObject({ ok: true, state: { charge_id: "chg_1", status: "paid", simulated: true, money_moved: false } });
|
|
303
|
+
expect(seen[0]?.url).toBe("https://api.example.test/v1/test/charges/chg_1/pay");
|
|
304
|
+
const headers = new Headers(seen[0]?.init.headers);
|
|
305
|
+
expect(headers.get("authorization")).toBe("Bearer csk_test_unit_0000");
|
|
306
|
+
expect(headers.get("x-codespar-project")).toBe("prj_1");
|
|
307
|
+
expect(headers.get("content-type")).toBe("application/json");
|
|
308
|
+
expect(seen[0]?.init.body).toBe(JSON.stringify({ amount_minor: 1000 }));
|
|
309
|
+
const bare = await paySandboxCharge({ apiKey: "csk_test_unit_0000", baseUrl: "https://api.example.test/", projectId: "prj_1" }, "chg_1");
|
|
310
|
+
expect(bare).toMatchObject({ ok: true });
|
|
311
|
+
expect(seen[1]?.init.body).toBe("{}");
|
|
312
|
+
} finally {
|
|
313
|
+
globalThis.fetch = realFetch;
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# @codespar/agent-runtime
|
|
2
|
+
|
|
3
|
+
The runner every starter-kit agent shares. It is not published: it is a
|
|
4
|
+
workspace package the agents depend on, and it ships one binary,
|
|
5
|
+
`codespar-agent`, so an agent's `package.json` script is the command and
|
|
6
|
+
nothing else.
|
|
7
|
+
|
|
8
|
+
```json
|
|
9
|
+
"scripts": { "start": "codespar-agent start", "check": "codespar-agent check" }
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## What it owns
|
|
13
|
+
|
|
14
|
+
- The terminal channel: the banner, the approval question, the transitions it
|
|
15
|
+
prints, the receipt path.
|
|
16
|
+
- The WhatsApp channel (`src/channels/`): one adapter over two backends that
|
|
17
|
+
are the SAME code with a different base URL — a local Cloud API emulator
|
|
18
|
+
([`dyvit-wa-sim`](https://github.com/fabianocruz/whatsapp-simulator), MIT,
|
|
19
|
+
run at a pinned npm version by `npm run whatsapp:emulator`) and Meta's own
|
|
20
|
+
host.
|
|
21
|
+
`live` is derived from that host, which is what the consent-evidence builder
|
|
22
|
+
refuses on. The rules live in the adapter, above both — the collection
|
|
23
|
+
hours, the bound contact, the secrecy of the debt, the document rule, the
|
|
24
|
+
24-hour session window — so choosing a backend changes who carries the bytes
|
|
25
|
+
and nothing else. What an AGENT ships for this channel is the conversations
|
|
26
|
+
and its template registry, under `agents/<name>/channels/whatsapp/`.
|
|
27
|
+
- `poll --channel whatsapp` comes back to a conversation the run that opened it
|
|
28
|
+
has ended: it reads the window back from the bundle's `channel.jsonl` and
|
|
29
|
+
confirms the outcome free-form while the 24 hours are open, as an approved
|
|
30
|
+
template once they have shut.
|
|
31
|
+
- Every command: `start` (interactive, `--input`, `--scenario`, `--transcript`,
|
|
32
|
+
`--json`, `--approve`/`--deny`, `--now`, `--channel`, `--backend`,
|
|
33
|
+
`--conversation`, `--scripted`), `consent`, `approve`, `deny`, `resume`,
|
|
34
|
+
`rerun`, `reconcile`, `inspect` (`--json`, `--html <file>`), `poll`
|
|
35
|
+
(`--channel`, `--conversation`, `--backend`, `--wait`, `--simulate-payer`,
|
|
36
|
+
`--payer`, `--now`, `--json`), `webhook`, `check`, `eval`.
|
|
37
|
+
- Setup: the manifest, the guardrails, the tools file, the system prompt, the
|
|
38
|
+
local state, the signer, the proof bundle, the provider (Anthropic with a
|
|
39
|
+
real key, replay without one), and the pinned clock (`--now`,
|
|
40
|
+
`CODESPAR_AGENT_NOW`).
|
|
41
|
+
- The section 9 adversarial runner and the section 12 scenario runner.
|
|
42
|
+
- The `csk_test_` guard and the `.env.example` placeholder rule.
|
|
43
|
+
|
|
44
|
+
## What an agent owns
|
|
45
|
+
|
|
46
|
+
Its five files (`agent.yaml`, `SYSTEM_PROMPT.md`, `tools.json`,
|
|
47
|
+
`guardrails.json`, `mandate.example.json`), its `scenarios/` and `evals/`, and
|
|
48
|
+
one optional module, `src/kit.ts`:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { defineAgent, defaultKit } from "@codespar/agent-runtime";
|
|
52
|
+
|
|
53
|
+
export const agent = defineAgent(import.meta.url, {
|
|
54
|
+
...defaultKit,
|
|
55
|
+
handlers: () => ({ list_bills: listBills }),
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`AgentKit` (in `src/kit.ts`) is the whole seam: the rail adapter
|
|
60
|
+
(`buildRail`), the tool handlers, the `policyExtension`, the console labels,
|
|
61
|
+
what a one-shot prints as JSON, and — for an agent whose money comes IN — the
|
|
62
|
+
sandbox payer and the one message per outcome. An agent that declares none of
|
|
63
|
+
it gets `defaultKit`: the stub rail, the example mandate, no tools.
|
|
64
|
+
|
|
65
|
+
`defineAgent(import.meta.url, kit)` finds the nearest `agent.yaml` above the
|
|
66
|
+
module, which is what makes every path (`scenarios/`, `evals/`, `.codespar/`,
|
|
67
|
+
`runs/`) and every test-only environment variable (`BILLS_STATE_DIR`,
|
|
68
|
+
`COLLECTIONS_RUNS_DIR`) resolve per agent without the agent naming them.
|