@visa/cli 4.1.0-rc.29 → 4.1.0-rc.291

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.
Files changed (94) hide show
  1. package/README.md +310 -46
  2. package/dist/checkout-engine/adapters/generic.d.ts +69 -0
  3. package/dist/checkout-engine/adapters/generic.js +383 -58
  4. package/dist/checkout-engine/adapters/index.d.ts +4 -1
  5. package/dist/checkout-engine/adapters/index.js +10 -3
  6. package/dist/checkout-engine/adapters/shopify.d.ts +98 -0
  7. package/dist/checkout-engine/adapters/shopify.js +744 -0
  8. package/dist/checkout-engine/amount.d.ts +17 -0
  9. package/dist/checkout-engine/amount.js +72 -0
  10. package/dist/checkout-engine/browser-launch.d.ts +9 -4
  11. package/dist/checkout-engine/browser-launch.js +19 -4
  12. package/dist/checkout-engine/browserbase-browser.d.ts +24 -0
  13. package/dist/checkout-engine/browserbase-browser.js +186 -0
  14. package/dist/checkout-engine/cli-engine.d.ts +241 -32
  15. package/dist/checkout-engine/cli-engine.js +960 -222
  16. package/dist/checkout-engine/confirmed-merchants.d.ts +31 -0
  17. package/dist/checkout-engine/confirmed-merchants.js +165 -0
  18. package/dist/checkout-engine/detect.d.ts +1 -1
  19. package/dist/checkout-engine/detect.js +6 -0
  20. package/dist/checkout-engine/evidence.d.ts +1 -1
  21. package/dist/checkout-engine/executor.d.ts +92 -4
  22. package/dist/checkout-engine/executor.js +688 -157
  23. package/dist/checkout-engine/hosted-approval.d.ts +69 -9
  24. package/dist/checkout-engine/hosted-approval.js +211 -21
  25. package/dist/checkout-engine/index.d.ts +9 -3
  26. package/dist/checkout-engine/index.js +7 -2
  27. package/dist/checkout-engine/instrument.d.ts +6 -0
  28. package/dist/checkout-engine/known-merchants.d.ts +10 -0
  29. package/dist/checkout-engine/known-merchants.js +38 -0
  30. package/dist/checkout-engine/live-fill-approval.d.ts +5 -11
  31. package/dist/checkout-engine/live-fill-approval.js +20 -34
  32. package/dist/checkout-engine/mandate/card-mandate.d.ts +6 -2
  33. package/dist/checkout-engine/mandate/card-mandate.js +10 -5
  34. package/dist/checkout-engine/mandate/mandate-ledger.d.ts +63 -23
  35. package/dist/checkout-engine/mandate/mandate-ledger.js +124 -17
  36. package/dist/checkout-engine/mandate.d.ts +8 -0
  37. package/dist/checkout-engine/mandate.js +44 -9
  38. package/dist/checkout-engine/receipt-dir.d.ts +6 -0
  39. package/dist/checkout-engine/receipt-dir.js +8 -0
  40. package/dist/checkout-engine/receipt.d.ts +56 -2
  41. package/dist/checkout-engine/receipt.js +55 -16
  42. package/dist/checkout-engine/shopify-primary-domain.d.ts +25 -0
  43. package/dist/checkout-engine/shopify-primary-domain.js +96 -0
  44. package/dist/checkout-engine/trace-handles.d.ts +8 -0
  45. package/dist/checkout-engine/trace-handles.js +12 -0
  46. package/dist/checkout-engine/types.d.ts +15 -2
  47. package/dist/checkout-engine/unresolved-charges.d.ts +34 -0
  48. package/dist/checkout-engine/unresolved-charges.js +134 -0
  49. package/dist/checkout-engine/vgs-gateway/server-mint-client.d.ts +78 -7
  50. package/dist/checkout-engine/vgs-gateway/server-mint-client.js +342 -27
  51. package/dist/checkout-engine/vgs-live-instrument.d.ts +11 -35
  52. package/dist/checkout-engine/vgs-live-instrument.js +14 -74
  53. package/dist/checkout-engine/vic-confirmation.d.ts +18 -0
  54. package/dist/checkout-engine/vic-confirmation.js +9 -3
  55. package/dist/checkout-engine/web-bot-auth.d.ts +98 -0
  56. package/dist/checkout-engine/web-bot-auth.js +218 -0
  57. package/dist/cli.js +936 -389
  58. package/dist/managed-runtime/resolve-and-update.mjs +268 -0
  59. package/dist/managed-runtime/runtime-readiness.mjs +126 -0
  60. package/dist/managed-runtime/update-and-restart.mjs +1079 -0
  61. package/dist/mcp-apps/ucp-checkout.html +280 -0
  62. package/dist/mcp-server/index.js +763 -257
  63. package/dist/merchant-ucp-mcp/index.js +7 -0
  64. package/dist/skills/pair-visa-agent/RUNTIMES.md +122 -79
  65. package/dist/skills/pair-visa-agent/SKILL.md +434 -318
  66. package/dist/skills/pair-visa-agent/scripts/__tests__/setup.test.mjs +407 -0
  67. package/dist/skills/pair-visa-agent/scripts/setup.mjs +310 -30
  68. package/dist/skills/visa-shopify-checkout/SKILL.md +122 -0
  69. package/dist/skills/visa-shopify-checkout/references/evidence-and-states.md +37 -0
  70. package/dist/skills/visa-ucp-shopping/SKILL.md +86 -0
  71. package/dist/subway-direct.mjs +1 -0
  72. package/install.ps1 +7 -6
  73. package/install.sh +3 -3
  74. package/native/bin/darwin-arm64/visa-runtime-signer +0 -0
  75. package/native/bin/darwin-x64/visa-runtime-signer +0 -0
  76. package/native/bin/linux-arm64/visa-runtime-signer +0 -0
  77. package/native/bin/linux-x64/visa-runtime-signer +0 -0
  78. package/native/bin/win32-arm64/visa-runtime-signer.exe +0 -0
  79. package/native/bin/win32-x64/visa-keychain-win.exe +0 -0
  80. package/native/bin/win32-x64/visa-runtime-signer.exe +0 -0
  81. package/package.json +33 -29
  82. package/server.json +4 -4
  83. package/dist/checkout-engine/inline-target.d.ts +0 -13
  84. package/dist/checkout-engine/inline-target.js +0 -37
  85. package/dist/checkout-engine/pay-args.d.ts +0 -14
  86. package/dist/checkout-engine/pay-args.js +0 -44
  87. package/dist/checkout-engine/pay.d.ts +0 -1
  88. package/dist/checkout-engine/pay.js +0 -13
  89. package/dist/checkout-engine/repo-env.d.ts +0 -11
  90. package/dist/checkout-engine/repo-env.js +0 -23
  91. package/dist/checkout-engine/run-live-fill.d.ts +0 -1
  92. package/dist/checkout-engine/run-live-fill.js +0 -493
  93. package/dist/checkout-engine/vgs-gateway/fetch-credential.d.mts +0 -74
  94. package/dist/checkout-engine/vgs-gateway/fetch-credential.mjs +0 -248
package/README.md CHANGED
@@ -1,21 +1,23 @@
1
1
  # @visa/cli
2
2
 
3
- Visa CLI v4 gives an AI agent a **Visa Verified Agent** identity and a scoped,
4
- human-capped signer for a Turnkey-managed wallet. Agents discover paid
5
- x402/MPP services and pay with USDC over MCP (Model Context Protocol); the
6
- human approves the limits and every payment is checked against on-device policy
7
- before anything is signed. Larger browser purchases use a separately approved
8
- VIC credential and card mandate.
9
-
10
- The v4 flow has three parts, always in this order:
11
-
12
- 1. **Identity** — the human enrolls in the browser (email or Google sign-in, card on file, bank verification) and mints a `.visa` name bound to the agent.
13
- 2. **Delegation** — a pairing ceremony gives the runtime a scoped, revocable
14
- Turnkey signer with human-approved per-transaction and daily caps. The
15
- runtime never receives the human wallet's root key.
16
- 3. **Payment** — `find → inspect → pay` handles x402/MPP purchases with gasless
17
- USDC and explicit maxima; `checkout` / `mandate` handles larger VIC browser
18
- purchases.
3
+ Visa CLI v4 pairs an AI runtime to a human-approved **Visa agent identity**.
4
+ The pairing ceremony creates one stable agent ID and activates one
5
+ runtime-custodied Ed25519 identity key. It does not create payment authority,
6
+ a mailbox, or a `.visa` name. New paired agents request publication of their
7
+ public key to the TAP directory by default; owners can durably remove it with
8
+ `visa agent tap-opt-out <agent-id>`.
9
+
10
+ The product flow has three explicit parts:
11
+
12
+ 1. **Identity** — `setup_start` (or `visa setup start`) opens ONE browser
13
+ review that covers the exact runtime, its public-key fingerprint, and every
14
+ requested rail in a single owner approval. The private key stays on the
15
+ runtime device. The older identity-only doors remain callable for an
16
+ already-started integration but are hidden from normal discovery.
17
+ 2. **Capabilities** — payment methods, spend grants, email and directory
18
+ bindings are configured separately, each with its own human-visible terms.
19
+ 3. **Use** — when a separately provisioned capability exists, the wallet and
20
+ VIC commands enforce that capability's own policy and approval boundary.
19
21
 
20
22
  ## Install
21
23
 
@@ -31,7 +33,17 @@ Windows PowerShell:
31
33
  iwr -useb https://app.visacli.sh/install.ps1 | iex
32
34
  ```
33
35
 
34
- Node.js 18+ is required. macOS, Windows, and Linux are supported for the v4 wallet flow.
36
+ Node.js 20+ is required. macOS, Windows, and Linux are supported for the v4 wallet flow.
37
+
38
+ ### Managed runtime convergence
39
+
40
+ The RC package also installs `visa-runtime-converge` for supervisor-owned
41
+ OpenClaw/Hermes/Telegram deployments. A scheduled invocation resolves the
42
+ preview server's recommended exact RC, stages and integrity-checks it, restarts
43
+ through the configured supervisor, verifies the loaded version/environment, and
44
+ rolls back a failed activation. It never updates an interactive owner-managed
45
+ installation. Configuration and readiness contracts are documented in
46
+ [`packages/visa-cli-openclaw/RUNTIMES.md`](https://github.com/Visa-Crypto-Labs/Visa-mono/blob/staging/packages/visa-cli-openclaw/RUNTIMES.md).
35
47
 
36
48
  ## MCP setup
37
49
 
@@ -65,44 +77,170 @@ args = ["<npm root -g>/@visa/cli/dist/mcp-server/index.js"]
65
77
 
66
78
  There is no CLI subcommand for starting the MCP server directly — the MCP server is the bundled `dist/mcp-server/index.js` entrypoint, which `visa-cli connect <client>` registers for you.
67
79
 
68
- ## Enroll a Verified Agent
80
+ ### UCP commerce bundle
81
+
82
+ Install the Visa pairing skill, discovery-first UCP shopping skill, bounded
83
+ Shopify checkout skill, and both Visa and Shopify UCP MCP entries in one step:
84
+
85
+ ```bash
86
+ visa agent skill --commerce --runtime codex
87
+ # runtimes with writable MCP config: codex, openclaw, hermes
88
+
89
+ # Inspect the installed local bundle without changing skills or MCP config:
90
+ visa agent skill --commerce --runtime codex --check
91
+ ```
92
+
93
+ The shopping skill turns broad requests into a short seller/variant list and
94
+ requires an exact selection plus an all-in ceiling before checkout. The pinned
95
+ Shopify UCP server requires Node.js 22 or newer. A successful run
96
+ reports both MCP entries as mounted or already mounted; restart or reload the
97
+ agent before using the new tools. The installer never performs discovery or a
98
+ checkout itself. The install-only command exits successfully after writing the
99
+ bundle, but reports `commerceReady: false` / `ucp_check_required` until the
100
+ explicit `--check` gate passes. `commerceReady` is a compatibility alias for
101
+ local bundle readiness only; it never proves that a merchant purchase can be
102
+ completed. The JSON result keeps `purchase.ready: false` until a separate live
103
+ checkout preflight is performed.
104
+
105
+ Checked readiness is read-only: missing or modified skills and missing,
106
+ conflicting, or malformed MCP entries are reported without installing or
107
+ rewriting anything. It parses the active local profile and its pinned Shopify
108
+ profile contract directly from disk, without starting `npx`, and reports the
109
+ exact profile initialization command if local state is missing or invalid. It
110
+ also refuses to claim local natural-language shopping readiness when a
111
+ top-level `ucp` or `shop` skill with a `SKILL.md` is present in the same runtime
112
+ directory. The installer reports those paths but never deletes or disables
113
+ user-owned skills.
114
+
115
+ If the selected runtime already has a non-equivalent `shopify-ucp` entry, the
116
+ command fails without changing that entry or its environment, authentication,
117
+ timeout, or filtering fields. Rename or remove the existing entry explicitly
118
+ before rerunning; the installer does not silently replace or downgrade it.
119
+
120
+ ### MCP 2026-07-28 compatibility
121
+
122
+ This release speaks the modern, stateless MCP `2026-07-28` protocol over stdio and deliberately rejects the legacy `initialize` handshake. Your client must support per-request protocol envelopes and `server/discover`; update the client before upgrading Visa CLI if it still sends MCP `2025-*` traffic. `visa-cli connect` can write configuration for every listed client, but configuration support does not imply that an older installed client understands the new wire revision.
123
+
124
+ The server now exposes:
125
+
126
+ - JSON Schema 2020-12 tool inputs and outputs, `structuredContent`, namespaced result metadata, cache hints, and receipt `resource_link` blocks.
127
+ - Resources for agent status, capabilities, recent activity, and canonical `visa://receipt/{transactionId}` receipts.
128
+ - Prompts for pairing/funding, spend inspection, safe purchasing, and receipt reconciliation, with completion support.
129
+ - The `io.modelcontextprotocol/tasks` extension for durable, pollable `pay_merchant` approval work. Task lifecycle is owner-scoped in the auth service; an MCP-process restart fails an in-flight checkout closed instead of replaying it.
130
+ - Multi-round-trip `input_required` URL elicitation with HMAC-protected, client-bound request state when the client supports URL elicitation but not Tasks.
131
+ - The `io.modelcontextprotocol/ui` Visa Control Center MCP App at `ui://visa/control-center`.
132
+
133
+ Visa sidebands no longer pollute business JSON. Clients receive keys such as `io.visa/visa-receipt` and `io.visa/update-available` in result `_meta`.
134
+
135
+ ## Setup doors
136
+
137
+ There is one blessed door for each transition. Recovery commands are kept
138
+ discoverable only where a shipped flow prints them; legacy starts remain callable
139
+ for compatibility but do not appear in normal CLI or MCP discovery.
140
+
141
+ | Transition | Blessed door | Status |
142
+ |---|---|---|
143
+ | New agent from an AI runtime or terminal | `setup_start` / `visa setup start` | Canonical: identity and requested rails on one review page |
144
+ | Agent already created in Console | `agent_handoff_claim` / `visa agent handoff-claim <code>` | Canonical Console handoff |
145
+ | Existing owner account on this device | `agent_login` / `visa agent login` | Canonical sign-in |
146
+ | Resume the canonical setup after restart | `setup_status`, then `setup_resume` / `visa setup status`, then `visa setup open` | Canonical recovery |
147
+ | Finish an already-started legacy pairing | `enroll_agent` action `claim` / `visa agent enroll-claim`, `claim`, or `pairing-resume` as printed | Recovery compatibility only |
148
+ | Resume a paused agent | `visa agent resume <agent-id>` | Live lifecycle control, not enrollment |
149
+ | Start an identity-only legacy pairing | `enroll_agent` / `visa agent enroll`, `pair`, `create`, `verify` | Hidden compatibility; do not start here |
150
+
151
+ ## Pair an agent identity
152
+
153
+ For a NEW agent, call **`setup_start`** with the name the human chooses: one
154
+ resumable setup covers identity plus every requested rail in a single owner
155
+ approval on one review page, and `setup_status` / `setup_resume` carry it
156
+ across restarts. From a terminal, `visa setup start "<name>"` begins the same
157
+ operation.
158
+
159
+ For a wallet setup, `completed` on the server is necessary but not sufficient
160
+ for the runtime to report ready. `setup_status` first verifies the exact-agent
161
+ local signing path used by wallet preflight and payments; managed runtimes make
162
+ one bounded recovery attempt. Until that evidence is readable, the result is
163
+ `wallet_runtime_not_ready`, no payment is attempted, and the setup record stays
164
+ available for a later resume.
165
+
166
+ The identity-only legacy handler remains callable for an existing integration or
167
+ an already-started ceremony, but it is deliberately absent from normal discovery.
168
+ Do not start a new agent there.
169
+
170
+ ```bash
171
+ visa setup start "Name" # one review page, one approval, every rail
172
+ visa agent list
173
+ visa agent show <agent-id>
174
+ ```
175
+
176
+ The advanced `create` → `claim` → `verify` → `pairing-resume` commands are the
177
+ split-device choreography of this same v2 ceremony, not a second enrollment
178
+ system. The review shows the runtime, context, stable agent ID, full public-key
179
+ fingerprint, and expiry. It grants identity only; no spend limits or instruments
180
+ are implied.
69
181
 
70
- Enrollment starts from the agent, not the terminal: the agent calls the **`enroll_agent`** MCP tool, which opens the enrollment page in the browser and prints a 6-character confirmation code in the terminal. The human signs in with **email or Google**, chooses the agent's `.visa` name, adds a card, completes the bank's verification step, and types the confirmation code. When the browser reports the credential was sent to the CLI, the agent calls `enroll_agent` with `{"action":"claim"}` to park the credential on the device.
182
+ On macOS and Linux, the private identity key is stored under
183
+ `~/.visa-cli/agents` in an owner-only directory with file mode `0600`. It is
184
+ currently an exportable local file: copying it transfers identity proof, and
185
+ losing it blocks new proofs because same-agent key recovery is not yet
186
+ available. Protocol-v2 identity pairing fails closed on Windows until the CLI
187
+ can apply and verify an owner-only Windows ACL. The pairing link contains no
188
+ credential or private key.
71
189
 
72
- Only enter a confirmation code you watched your own terminal print. Enrollment
73
- must begin with `enroll_agent` and present Turnkey email or Google sign-in.
190
+ ## Recover an existing account session
74
191
 
75
- ## Connect an agent runtime (pairing)
192
+ `visa agent login` opens the Turnkey-first web sign-in for an existing v4
193
+ account, then `visa agent login-claim` stores the returned account session in
194
+ the OS keychain. `--wait` keeps the first command polling for the full
195
+ 15-minute browser window.
76
196
 
77
- Enrollment mints identity; **pairing is what lets a runtime sign payments.**
197
+ ```bash
198
+ visa agent login # sign in and display the terminal confirmation code
199
+ visa agent login-claim # resume pickup after returning from the browser
200
+ ```
201
+
202
+ This is account-session recovery, not agent pairing. It does not create or
203
+ replace an identity key, delegate a wallet, select a card, set a budget, or
204
+ grant spend authority. The pending PKCE verifier is kept under
205
+ `~/.visa-cli/session-recovery/` in owner-only local state and is pinned to the
206
+ exact web origin that started the flow.
207
+ Session recovery currently fails closed on Windows until the CLI can apply and
208
+ verify an owner-only ACL for this pending verifier.
209
+
210
+ ## Wallet capability: grant, caps, then funding
211
+
212
+ Pairing never creates or repairs payment authority — the owner delegates it in
213
+ a separate grant ceremony, and re-pairing is not a substitute:
78
214
 
79
215
  ```bash
80
- visa agent create # in the human's terminal — prints the pairing id
81
- visa agent claim <pairing-id> --runtime <name> --context "<one-line purpose>"
82
- visa agent verify <pairing-id> <code> # verifies the channel, opens the authorization page
83
- visa agent list # shows the activated runtime
216
+ visa agent login # owner account session, once
217
+ visa agent grant-wallet <agent-id> --ceiling 25 --per-transaction 1 --wait
84
218
  ```
85
219
 
86
- The browser authorization is the human gate: it shows the runtime and context and sets the **per-transaction and daily spend caps**. If the runtime lost its network response, `visa agent resume <pairing-id>` reprints the code and resumes delivery; `visa agent cancel [pairing-id]` abandons an unapproved request. Pairing credentials are stored on the agent machine with mode `0600`; the pairing link contains no credential.
220
+ The owner approves once in the browser; the runtime polls to activation and
221
+ receives a delegated, capped, revocable signer (it can never mint one itself).
222
+ `visa agent pause <agent-id>` temporarily blocks new Visa CLI card and wallet payments at the canonical authority service (mandates remain intact; resume with `visa agent resume <agent-id>`). `visa agent revoke <agent-id>` withdraws the current server grant without touching identity; provider-credential removal is a separate lifecycle.
87
223
 
88
- ## Caps, then funding — strict order
224
+ With a wallet delegated, set caps before funding:
89
225
 
90
226
  ```bash
91
- visa wallet limits --per-transaction 0.25 --daily 2.00 # BEFORE any funds arrive
92
- visa wallet show # address, network, policy
93
- visa wallet fund # funding instructions
227
+ visa wallet limits --agent <agent-id> --per-transaction 0.25 --daily 2.00
228
+ visa wallet show --agent <agent-id> # address, network, policy
229
+ visa wallet fund --agent <agent-id> # funding instructions
94
230
  ```
95
231
 
96
232
  Fund the wallet with USDC only after limits are set. Payments are gasless — no ETH is ever needed. Mainnet (Base) is the production default; set `VISA_V4_NETWORK=base-sepolia` for testnet, where `visa wallet fund` points at the faucet.
97
233
 
234
+ Updating wallet limits preserves the active session budget window and its spent exposure. Reapplying the same limits is a no-op; `wallet limits` does not provide an implicit session-spend reset.
235
+
98
236
  ## Discover and pay
99
237
 
100
238
  ```bash
101
239
  visa find "current weather by city" --max 0.10 # discovery; spends nothing
102
240
  visa inspect <listing-id> # fetches the live 402 challenge; spends nothing
103
- visa pay <listing-id> --max 0.05 # policy check → sign → settle
104
- visa activity # recent payments
105
- visa receipt <receipt-id> # journaled proof with on-chain tx
241
+ visa pay <listing-id> --agent <agent-id> --max 0.05 # policy check → sign → settle
242
+ visa activity --agent <agent-id> # recent payments
243
+ visa receipt <receipt-id> --agent <agent-id> # journaled proof with on-chain tx
106
244
 
107
245
  # Advanced direct-URL mode uses the same probe, policy, and receipt path.
108
246
  visa inspect --url https://provider.example/paid
@@ -116,12 +254,25 @@ owned by `apps/mpp`, and VIC uses the checkout/mandate surface. Unsupported
116
254
  rails are refused before signing. The wallet exposes no agent key-export
117
255
  command.
118
256
 
257
+ Each wallet-enabled agent has an isolated Turnkey credential, policy, journal,
258
+ receipts, and paid-response directory. `--agent` / the MCP `agent` field may be
259
+ omitted while exactly one wallet authority exists; with multiple authorities it
260
+ is required so the CLI never guesses which agent can spend.
261
+
119
262
  ## MCP tools (v4 surface)
120
263
 
121
264
  | Tool | Description |
122
265
  |------|-------------|
123
- | `enroll_agent` | Two-step Verified Agent enrollment: default opens the browser flow with a hand-off challenge; `{"action":"claim"}` stores the enrollment credential on this device |
124
- | `wallet_status` | Wallet address, network, policy, and pairing state |
266
+ | `agent_capabilities` | Derived live capability map (identity, wallet, card, mail, tap, subway) with upgrade paths |
267
+ | `setup_agent` | Next-step resolver for the wallet rail: `{state, nextAction, blockedBy, steps}`; never spends |
268
+ | `agent_login` | Start/claim the owner's device account session (required before a grant) |
269
+ | `setup_start` | Start ONE resumable setup (identity + rails) in a single human approval; returns the review link and this device's half of the compare code |
270
+ | `setup_status` | Read the server's one `nextAction` and polling cadence; terminal wallet results additionally require exact-agent local signing evidence before reporting ready |
271
+ | `setup_resume` | Put the review link and compare code back in front of the human after a restart or a closed tab |
272
+ | `setup_cancel` | Abandon a setup still waiting on the human; never undoes an approval |
273
+ | `agent_connect` | Initiate an owner-approved spending grant for a paired agent |
274
+ | `agent_connect_poll` | Poll that grant ceremony to activation (returns caps, and the funding address for wallet) |
275
+ | `wallet_status` | Delegated wallet address, network, and policy state |
125
276
  | `wallet_policy_set` | Set per-transaction / daily caps (with human approval) |
126
277
  | `wallet_discover` | Sweep x402 directories for services, with live re-probing |
127
278
  | `wallet_probe` | Fetch a service's live 402 challenge without paying |
@@ -129,6 +280,7 @@ command.
129
280
  | `wallet_directory_pay` | Directory find + pay in one call, same policy path |
130
281
  | `wallet_history` | Journaled payment receipts |
131
282
  | `wallet_fund` | Funding instructions for the wallet address |
283
+ | `checkout_merchants` | Read-only: merchants where your card has completed real checkouts, from this device's receipts |
132
284
  | `get_status` | Account and wallet state summary |
133
285
  | `feedback` | Submit feedback on a tool result |
134
286
  | `reset` | Clear local auth state and credentials |
@@ -163,11 +315,19 @@ visa pay <listing-id> --max <usd>
163
315
  visa activity
164
316
  visa receipt <receipt-id>
165
317
 
166
- # Human-approved agent runtime pairing
318
+ # Primary same-machine setup
319
+ visa setup start "Name" --rails card,wallet
320
+ visa setup status
321
+
322
+ # Existing-account session recovery (separate from identity pairing)
323
+ visa agent login
324
+ visa agent login-claim
325
+
326
+ # Recovery compatibility for a legacy split-device ceremony already in flight
167
327
  visa agent create
168
328
  visa agent claim <pairing-id> --runtime <name> --context "<purpose>"
169
329
  visa agent verify <pairing-id> <code>
170
- visa agent resume <pairing-id>
330
+ visa agent pairing-resume <pairing-id>
171
331
  visa agent cancel [pairing-id]
172
332
  visa agent list
173
333
 
@@ -200,14 +360,19 @@ visa-cli feedback # submit feedback
200
360
 
201
361
  | Path | Contents |
202
362
  |------|----------|
203
- | `~/.visa-mcp/agent-credential.json` | Verified Agent enrollment credential (mode 0600) |
204
- | `~/.visa-cli/` | Pairing / delegated signer credentials (mode 0600) |
205
- | `~/.visa-v4/policy.json` | Wallet spend policy — never edit by hand; use `visa wallet limits` |
363
+ | `~/.visa-cli/pairings/` | Pending ceremony verifier or runtime identity key (owner-only mode 0600 on macOS/Linux; v2 pairing currently disabled on Windows) |
364
+ | `~/.visa-cli/agents/` | Activated agent identity, runtime private key, and signed activation credentials (owner-only mode 0600 on macOS/Linux; v2 pairing currently disabled on Windows) |
365
+ | `~/.visa-cli/session-recovery/` | Pending login-only PKCE verifier and pinned web origin (owner-only mode 0600 on macOS/Linux) |
366
+ | `~/.visa-cli/removed-agents/` | Records of agents deleted on the server, kept 30 days then dropped. Written automatically; nothing reads it |
367
+ | `~/.visa-mcp/agent-credential.json` | Legacy checkout-credential compatibility record (mode 0600) |
368
+ | `~/.visa-v4/agents/<agentId>/` | Per-agent Turnkey credential, spend policy, reservation journal, receipts, and paid responses — never edit by hand |
206
369
 
207
370
  ## Troubleshooting
208
371
 
209
- **Wallet commands report pairing is required**
210
- Payments on a production network require the paired delegated credential — complete enrollment and pairing first. There is no local fallback wallet on mainnet, by design.
372
+ **Wallet commands report that payment setup is required**
373
+ Identity pairing deliberately grants no payment authority. Complete the
374
+ separate wallet/instrument and spend-policy setup when available; pairing again
375
+ will not upgrade an identity into a signer.
211
376
 
212
377
  **`policy refused` from `pay`**
213
378
  A cap or allowlist said no; nothing was signed. Raise caps only via `visa wallet limits` with the human's approval.
@@ -215,12 +380,111 @@ A cap or allowlist said no; nothing was signed. Raise caps only via `visa wallet
215
380
  **`expected 402 from <url>`**
216
381
  That URL isn't payment-gated — probe the service's actual paid route (`wallet_probe` / `visa find`).
217
382
 
218
- **Pairing ended `expired` or `cancelled`**
219
- The ceremony timed out — re-run `visa agent create` and claim the new pairing id.
383
+ **Setup ended `expired` or `cancelled`**
384
+ The ceremony timed out — restart with `visa setup start "Name"`, then follow
385
+ `visa setup status` until it reports the next action.
220
386
 
221
387
  **Tools don't appear in the AI client**
222
388
  Restart the client or reconnect the MCP server (`/mcp` → `visa-cli` → reconnect in Claude Code). Re-run `visa-cli connect <client>` to rewrite the config.
223
389
 
390
+ **Branching on failures from `--format json`**
391
+ Every failure envelope carries `code`, `kind`, `fix`, and `nextAction`. Branch on
392
+ `code` (stable, append-only) and `kind` (`caller` = fix it yourself and retry;
393
+ `platform` = stop and escalate to a human), never on the English `error` text.
394
+ Deterministic preconditions always resolve to a specific code:
395
+
396
+ | Condition | `code` | `kind` |
397
+ |-----------|--------|--------|
398
+ | Not logged in (`find`, `activity`, `receipt`) | `session_required` | `caller` |
399
+ | No wallet grant on this runtime (`wallet show\|fund\|limits`, `pay`, `--local` reads) | `wallet_credential_required` | `platform` |
400
+ | Wallet grant approved but not fully delivered (`pay`) | `wallet_delivery_required` | `platform` |
401
+ | Local identity record missing for the selected agent (`pay`) | `identity_required` | `caller` |
402
+ | Identity root migrated; direct signing retired (`pay`) | `universal_required_managed_only` | `platform` |
403
+ | Managed wallet limits are owner-set (`wallet limits` with caps) | `managed_limits_owner_controlled` | `platform` |
404
+ | Listing is not x402 (`pay <listing-id>`) | `invalid_argument` | `caller` |
405
+ | Activity id not found or not attributable (`receipt`) | `activity_entry_not_found` | `caller` |
406
+
407
+ `unspecified_error` (`platform`) is reserved for failures the CLI cannot
408
+ classify and is intentionally kept on two guards: a wallet binding that does not
409
+ match the signed-in owner profile (an integrity refusal, not a caller state),
410
+ and a `wallet limits` change that would broaden policy without the operator's
411
+ `VISA_V4_WALLET_ALLOW_POLICY_RAISE=1`. Both need a human; escalate rather than retry.
412
+
224
413
  ## Monorepo context
225
414
 
226
415
  Request routing (MCP vs MPP vs web): [docs/agents/ARCHITECTURE.md](../../docs/agents/ARCHITECTURE.md). Branches and deploy: [docs/agents/PIPELINE.md](../../docs/agents/PIPELINE.md). Contributor workflow: [AGENTS.md](../../AGENTS.md), doc index: [docs/agents/README.md](../../docs/agents/README.md).
416
+
417
+ ### Native device TAP lifecycle
418
+
419
+ `visa agent keychain connect-device --agent <name-or-id>` selects this device for
420
+ identity-only TAP signing after the existing browser owner ceremony verifies its
421
+ certificate, delegation, Gate authorization and native key binding. The selected
422
+ native profile serves actual TAP consumers; unavailable custody or invalid selected
423
+ metadata fails closed. Wallet/card keys and payment authority remain separate.
424
+
425
+ `--agent` accepts either a locally paired agent or the stable UUID of a protected
426
+ agent created by `visa agent enroll-protected`; the latter has no Auth-paired record
427
+ and resolves its owner root from the independently claimed selection. The device
428
+ ceremonies (`connect-device`, `renew`, `resume`, `revoke --purpose tap`) travel the
429
+ public identity-device relay with native possession proofs, so a missing or expired
430
+ `visa agent login` never blocks them; the owner approval and owner revocation pages
431
+ remain required. Hosted purposes (`card:vic`, `wallet:x402`, hosted `tap`, `subway`)
432
+ still need a locally paired agent and its Auth session.
433
+
434
+ `visa agent keychain renew --agent <name-or-id> --purpose tap` creates an independently
435
+ addressed successor for the same runtime and opens the owner review page. Both keys
436
+ survive interruption. `visa agent keychain resume --agent <name-or-id>` resumes the
437
+ exact pending operation, including a locked-keychain cleanup retry. `--no-open`
438
+ prints the owner URL. Expired locators require another owner ceremony using the
439
+ preserved successor key. `keychain status` reports the selected profile and local
440
+ renewal phase; it is a local projection, not a live authority check.
441
+
442
+ Only public certificates/proposals and opaque native handles enter the durable
443
+ renewal journal. Selection changes after verified owner activation. The previous
444
+ handle is deleted only after possession-authenticated protected readback proves
445
+ that exact prior generation retired; uncertain readback preserves it. Native
446
+ custody uses the configured OS store or explicit headless KEK descriptor.
447
+
448
+ `visa agent keychain revoke --agent <name-or-id> --purpose tap` opens an independent
449
+ owner review for the selected native runtime. The protected owner action stops current
450
+ and pending TAP authority, including an interrupted renewal. Local locks or unreadable
451
+ recovery journals do not prevent opening the owner review. The CLI preserves every known
452
+ handle until exact terminal readback, then deletes keys idempotently; `keychain resume`
453
+ retries locked cleanup. A public revoked selection tombstone prevents legacy TAP fallback.
454
+ After cleanup completes, `connect-device` explicitly enrolls a new runtime.
455
+
456
+ ### Native Subway owner certificates
457
+
458
+ New `agent keychain renew --purpose subway --advanced` requests keep the Subway
459
+ child key in native custody. Complete the existing offline browser owner certificate
460
+ review and import its response with `--response <file>`. Repeating the response
461
+ command resumes interrupted certification, prior-runtime revocation, or locked-key
462
+ cleanup. An expired unsigned request keeps its native key and produces a fresh
463
+ owner request. `keychain status` reports pending work and the selected native profile.
464
+
465
+ Register the Subway name again after renewal so its peer key matches the selected
466
+ child. WebSocket messages and direct libp2p Noise authentication use structured
467
+ native signing operations. Invalid, expired, revoked, or unavailable native selection
468
+ fails closed. Existing unpaired mesh usage retains its current behavior.
469
+
470
+ The public renewal journal preserves both generations until the runtime service
471
+ confirms revocation of the exact previous child. Only then does cleanup remove its
472
+ native handle or isolated legacy Subway key file. `keychain revoke --purpose subway`
473
+ revokes the selected child before deleting its key; repeat it to retry locked cleanup.
474
+ Wallet and card custody are separate.
475
+
476
+ ### Protected managed-wallet rollout
477
+
478
+ Protected authority onboarding is opt-in with `visa config set wallet.protectedAuthority true` until its deployment is ready. The default retains the existing fresh-enrollment and locally verified legacy managed-wallet path. This setting never downgrades saved protected devices: native pending/active/history records and protected wallet bindings always require protected recovery, including when the authority is unavailable. Existing direct configurations retain their scoped local-credential checks.
479
+
480
+ A managed reconnect without verifiable local enrollment history requires recovery; restore the saved device records or complete independent owner classification through the protected authority deployment. Auth's execution-mode response alone cannot classify that missing history. No automatic retry through legacy setup occurs after an authority error.
481
+
482
+ ### Fresh protected native agent
483
+
484
+ An operator must supply the independently trusted HTTPS authority origin. Start from an empty CLI home with:
485
+
486
+ ```sh
487
+ visa agent enroll-protected --authority-url https://YOUR-TRUSTED-AUTHORITY --wait
488
+ ```
489
+
490
+ Enter the terminal code in the existing browser owner ceremony, then approve the native device and its spending limits. Repeat the same command to resume after interruption; use `--no-open` to print links. `--url` selects the browser origin independently. `--auth-url` selects the HTTPS policy transport (default: local Auth configuration); its exact origin is saved with enrollment and cannot change on resume. Signing uses the existing bearer-free policy/slip adapter at that origin, while identity pickup and protected wallet recovery use the independently trusted authority. No Auth login is needed, but the policy transport must be reachable to authorize a new purchase. An unclaimed expired request can be replaced with `--restart`. This path creates a new authority-owned namespace and preserves any existing Auth login profile. It requires the protected authority's CLI-claim migration and direct HTTPS routes to be deployed; an Auth-supplied origin is not a trusted substitute.
@@ -5,13 +5,82 @@ import type { Contact, FillResult, FilledField } from '../types.js';
5
5
  export interface CheckoutAdapter {
6
6
  name: string;
7
7
  matches(detected: DetectResult): boolean;
8
+ prepareContact?: (page: Page, contact: Contact) => Promise<FillResult>;
8
9
  fill(page: Page, fields: FieldMap, credential: CardCredential, contact: Contact): Promise<FillResult>;
9
10
  }
10
11
  export declare function resolveLocator(page: Page, entry: FieldEntry): Locator;
11
12
  export declare function scrubFillErrorMessage(message: string, value: string): string;
13
+ /**
14
+ * A fill failure in a few words, for a message a human reads.
15
+ *
16
+ * Playwright's error is a multi-line call log — useful in the evidence file,
17
+ * unreadable in a refusal message and in the receipt an operator opens a week
18
+ * later. The refusal names WHICH fields refused; without this it never says
19
+ * WHY, so diagnosing a merchant we cannot drive means either reproducing it or
20
+ * reading someone's evidence JSON. Each cause maps to a different fix:
21
+ *
22
+ * not editable — the input exists but is readonly/disabled at fill time
23
+ * (a custom widget owning the value, or a not-yet-ready
24
+ * form). Typing will not help; the field needs an adapter
25
+ * or a longer wait.
26
+ * not a text field — a non-input element pretending to be one. Needs an
27
+ * adapter that drives the widget.
28
+ * not visible /
29
+ * detached — a re-render race. The reveal loop is the lever.
30
+ *
31
+ * Input is already scrubbed by scrubFillErrorMessage; this only ever shortens.
32
+ */
33
+ export declare function summarizeFillFailure(error: string | undefined): string;
34
+ /**
35
+ * The contact record and the page rarely agree on name shape: the record may
36
+ * carry fullName while the page wants first/last inputs, or vice versa. Derive
37
+ * the missing shape so either page can be filled from either record.
38
+ */
39
+ export declare function contactNameShapes(contact: Contact, cardholderName?: string): {
40
+ fullName?: string;
41
+ first?: string;
42
+ last?: string;
43
+ };
44
+ export declare function fillContactFieldMap(page: Page, fields: FieldMap, contact: Contact, opts?: {
45
+ fillTimeoutMs?: number;
46
+ detect?: (page: Page) => Promise<DetectResult>;
47
+ }): Promise<FilledField[]>;
12
48
  export declare function fillFieldMap(page: Page, fields: FieldMap, credential: CardCredential, contact: Contact, opts?: {
13
49
  fillTimeoutMs?: number;
50
+ detect?: (page: Page) => Promise<DetectResult>;
14
51
  }): Promise<FilledField[]>;
52
+ /**
53
+ * Re-detect and adopt fresh entries for every card field after the panel is
54
+ * unfolded. Injected for tests; the executor's own detector is used in
55
+ * production.
56
+ */
57
+ export declare function refreshCardGroupFromPage(page: Page, fields: FieldMap, detect?: (page: Page) => Promise<DetectResult>): Promise<string[]>;
58
+ /**
59
+ * Reveal card fields that a checkout keeps collapsed until a payment method is
60
+ * chosen.
61
+ *
62
+ * `fillFields` skips any entry with `visible === false`, so a card-number input
63
+ * sitting inside a folded panel is never even attempted — the generic adapter
64
+ * then reports `ok: false` ("fill incomplete") without having typed anything.
65
+ * That is the correct default: filling an invisible input is how a credential
66
+ * gets typed into the wrong place. But a payment-method `<select>` guarding the
67
+ * card panel is common enough to be worth handling, and the recovery is a
68
+ * single deterministic interaction rather than a guess.
69
+ *
70
+ * We only ever SELECT a card option — never a wallet, bank transfer, or
71
+ * anything else — and we only act when the card field is already detected but
72
+ * hidden. If nothing changes, the caller proceeds exactly as before and still
73
+ * fails closed.
74
+ *
75
+ * Mutates `fields.number.visible` on success so the subsequent fill attempts
76
+ * the field it just revealed.
77
+ */
78
+ export declare function revealCollapsedCardSection(page: Page, fields: FieldMap, opts?: {
79
+ timeoutMs?: number;
80
+ }): Promise<{
81
+ revealed: boolean;
82
+ via: string | null;
83
+ }>;
15
84
  export declare class GenericAdapter implements CheckoutAdapter {
16
85
  name: string;
17
86
  matches(_detected: DetectResult): boolean;