@visa/cli 4.1.0-rc.297 → 4.1.0-rc.299

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 (77) hide show
  1. package/README.md +29 -45
  2. package/dist/cli.js +556 -786
  3. package/dist/mcp-server/index.js +408 -622
  4. package/dist/merchant-ucp-mcp/index.js +6 -6
  5. package/dist/skills/pair-visa-agent/SKILL.md +175 -240
  6. package/native/bin/win32-arm64/visa-runtime-signer.exe +0 -0
  7. package/native/bin/win32-x64/visa-keychain-win.exe +0 -0
  8. package/native/bin/win32-x64/visa-runtime-signer.exe +0 -0
  9. package/package.json +2 -4
  10. package/server.json +2 -2
  11. package/dist/checkout-engine/adapters/generic.d.ts +0 -88
  12. package/dist/checkout-engine/adapters/generic.js +0 -526
  13. package/dist/checkout-engine/adapters/index.d.ts +0 -10
  14. package/dist/checkout-engine/adapters/index.js +0 -24
  15. package/dist/checkout-engine/adapters/shopify.d.ts +0 -98
  16. package/dist/checkout-engine/adapters/shopify.js +0 -744
  17. package/dist/checkout-engine/adapters/stripe-like.d.ts +0 -10
  18. package/dist/checkout-engine/adapters/stripe-like.js +0 -21
  19. package/dist/checkout-engine/amount.d.ts +0 -17
  20. package/dist/checkout-engine/amount.js +0 -72
  21. package/dist/checkout-engine/browser-launch.d.ts +0 -51
  22. package/dist/checkout-engine/browser-launch.js +0 -96
  23. package/dist/checkout-engine/browserbase-browser.d.ts +0 -24
  24. package/dist/checkout-engine/browserbase-browser.js +0 -186
  25. package/dist/checkout-engine/ceremony.d.ts +0 -64
  26. package/dist/checkout-engine/ceremony.js +0 -261
  27. package/dist/checkout-engine/cli-engine.d.ts +0 -417
  28. package/dist/checkout-engine/cli-engine.js +0 -1331
  29. package/dist/checkout-engine/confirmed-merchants.d.ts +0 -31
  30. package/dist/checkout-engine/confirmed-merchants.js +0 -165
  31. package/dist/checkout-engine/detect.d.ts +0 -61
  32. package/dist/checkout-engine/detect.js +0 -398
  33. package/dist/checkout-engine/evidence.d.ts +0 -25
  34. package/dist/checkout-engine/evidence.js +0 -104
  35. package/dist/checkout-engine/executor.d.ts +0 -262
  36. package/dist/checkout-engine/executor.js +0 -1837
  37. package/dist/checkout-engine/hosted-approval.d.ts +0 -195
  38. package/dist/checkout-engine/hosted-approval.js +0 -501
  39. package/dist/checkout-engine/index.d.ts +0 -12
  40. package/dist/checkout-engine/index.js +0 -13
  41. package/dist/checkout-engine/instrument.d.ts +0 -61
  42. package/dist/checkout-engine/instrument.js +0 -87
  43. package/dist/checkout-engine/known-merchants.d.ts +0 -10
  44. package/dist/checkout-engine/known-merchants.js +0 -38
  45. package/dist/checkout-engine/live-fill-approval.d.ts +0 -37
  46. package/dist/checkout-engine/live-fill-approval.js +0 -76
  47. package/dist/checkout-engine/mandate/card-mandate.d.ts +0 -121
  48. package/dist/checkout-engine/mandate/card-mandate.js +0 -226
  49. package/dist/checkout-engine/mandate/mandate-ledger.d.ts +0 -175
  50. package/dist/checkout-engine/mandate/mandate-ledger.js +0 -425
  51. package/dist/checkout-engine/mandate.d.ts +0 -33
  52. package/dist/checkout-engine/mandate.js +0 -135
  53. package/dist/checkout-engine/outcome.d.ts +0 -30
  54. package/dist/checkout-engine/outcome.js +0 -225
  55. package/dist/checkout-engine/owner-only-file.d.ts +0 -19
  56. package/dist/checkout-engine/owner-only-file.js +0 -41
  57. package/dist/checkout-engine/package.json +0 -3
  58. package/dist/checkout-engine/receipt-dir.d.ts +0 -6
  59. package/dist/checkout-engine/receipt-dir.js +0 -8
  60. package/dist/checkout-engine/receipt.d.ts +0 -135
  61. package/dist/checkout-engine/receipt.js +0 -148
  62. package/dist/checkout-engine/shopify-primary-domain.d.ts +0 -25
  63. package/dist/checkout-engine/shopify-primary-domain.js +0 -96
  64. package/dist/checkout-engine/trace-handles.d.ts +0 -8
  65. package/dist/checkout-engine/trace-handles.js +0 -12
  66. package/dist/checkout-engine/types.d.ts +0 -52
  67. package/dist/checkout-engine/types.js +0 -2
  68. package/dist/checkout-engine/unresolved-charges.d.ts +0 -34
  69. package/dist/checkout-engine/unresolved-charges.js +0 -134
  70. package/dist/checkout-engine/vgs-gateway/server-mint-client.d.ts +0 -155
  71. package/dist/checkout-engine/vgs-gateway/server-mint-client.js +0 -493
  72. package/dist/checkout-engine/vgs-live-instrument.d.ts +0 -144
  73. package/dist/checkout-engine/vgs-live-instrument.js +0 -229
  74. package/dist/checkout-engine/vic-confirmation.d.ts +0 -52
  75. package/dist/checkout-engine/vic-confirmation.js +0 -45
  76. package/dist/checkout-engine/web-bot-auth.d.ts +0 -98
  77. package/dist/checkout-engine/web-bot-auth.js +0 -218
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: pair-visa-agent
3
- description: Connect a Visa CLI v4 agent — identity plus every payment rail it needs — through ONE setup operation the human approves once in their browser. Ask what to call the agent, call setup_start, relay the review link, then poll setup_status until it is ready. Use when the user says "pair my agent", "connect Visa", "enroll my Visa CLI", "set up my agent", or "let this agent pay".
3
+ description: Set up a Visa CLI v4 agent through the single protected enrollment implementation, using the entrance this build advertises, and report its live capabilities honestly. The owner always approves in their browser. Use when the user says "pair my agent", "connect Visa", "enroll my Visa CLI", "set up my agent", or "let this agent pay".
4
4
  compatibility: Needs the `visa` CLI (`npm i -g @visa/cli@rc`) — run `node scripts/setup.mjs` to install it if missing — plus network access to the Visa authorization service. Works in OpenClaw, Hermes, Claude Code, Codex, or any Agent Skills runtime.
5
5
  allowed-tools: Bash(visa:*) Bash(visa-cli:*) Bash(node:*) Bash(npm:*) Bash(npx:*)
6
6
  metadata:
@@ -27,52 +27,71 @@ metadata:
27
27
  - visa-cli
28
28
  ---
29
29
 
30
- # Connect a Visa agent
30
+ # Set up a Visa agent
31
31
 
32
- One setup operation carries everything: this runtime's identity **and** every payment
33
- rail the agent needs, behind a **single** owner approval on a single review page. You ask
34
- once, the human clicks Connect once, and you finish the rest yourself.
32
+ One command carries everything: this runtime's identity, the binding to **this
33
+ device**, and the spending limits — behind a **single** owner approval in their browser.
35
34
 
36
- **The whole flow is two tool calls and, for the human, one or two clicks.**
35
+ **Today, the command is run by the OWNER in their terminal.** On one-door builds that
36
+ advertise it, an agent may instead call `agent_enroll` and hand the owner its returned
37
+ link, or the owner runs `visa agent enroll`. These are two entrances to the exact same
38
+ protected enrollment implementation: the same native signer, Authority routes, owner
39
+ browser approval, and limits. Never invent or mix in a second ceremony.
37
40
 
38
41
  ```
39
- setup_start {"name": "<what they call it>", "rails": ["card", "wallet"]}
40
- → relay the returned browserUrl to the human
41
- → human clicks "Connect agent" (click 1)
42
- → for the wallet rail, one "Approve" (click 2 — same page, no second budget)
43
- setup_status (repeat at the returned pollAfterMs)
44
- → each call drives the agent's own steps; stop when nextAction.kind is "done"
42
+ # the human runs this:
43
+ visa agent enroll-protected \
44
+ --authority-url <origin> --auth-url <origin> --url <origin> --wait
45
+
46
+ → it prints a URL and a short code
47
+ → the human opens the URL and enters the code at /agent/enroll/protected-agent
48
+ → the human approves the device and its spending limits (one approval)
49
+ → the command finishes; `get_status` now reports pairing.paired: true
45
50
  ```
46
51
 
47
- Nothing else. Do **not** walk `enroll_agent` → `agent_connect` → `agent_connect_poll` →
48
- `start_card_mandate` for a new agent: that legacy sequence spends three extra owner
49
- approvals reaching the same place, and this skill replaces it.
52
+ All three origins are required today; the operator supplies them. If the human does not
53
+ know them, ask — do not guess an origin, and never construct a Visa URL yourself.
50
54
 
51
- ## What "connected" means here
55
+ Running the same command again resumes an interrupted enrolment; `--restart` replaces an
56
+ unclaimed request with a fresh code. `--ceiling <usd>` and `--per-transaction <usd>`
57
+ propose limits the owner confirms on the approval page.
52
58
 
53
- `setup_start` mints a **new** agent: a new server-assigned agent, a new device-held Ed25519
54
- identity key, and whichever rails you asked for. When the operation reports ready:
59
+ ## The older ceremonies were deleted — do not call them
60
+
61
+ `setup_start`, `setup_status`, `setup_resume`, `setup_cancel`, `setup_agent`,
62
+ `enroll_agent`, `agent_connect`, `agent_connect_poll`, `agent_connect_cancel`,
63
+ `agent_handoff_claim` and `agent_pairing_cancel` are gone, along with the `visa setup`
64
+ group and `visa agent pair|create|verify|enroll|enroll-claim|claim|pairing-resume|connect|grant-card|grant-wallet|grant-activate|grant-claim|handoff-claim`.
65
+
66
+ Calling any of them returns one refusal:
67
+
68
+ ```json
69
+ { "code": "legacy_door_removed", "kind": "caller", "fix": "visa agent enroll-protected" }
70
+ ```
71
+
72
+ That code means the door no longer exists. **Relay the replacement and stop.** Do not
73
+ retry it, do not try a variant spelling, and do not report it to the human as an outage:
74
+ nothing was signed, paired, or paid.
75
+
76
+ ## What "set up" means here
77
+
78
+ Each completed protected enrollment mints a **new** agent: a new server-assigned agent,
79
+ a new device-held Ed25519 identity key, and the wallet limits the owner approved.
55
80
 
56
81
  - The runtime keeps the private Ed25519 key and sends only the public JWK.
57
- - The rails in `readiness.rails` are the ones the owner actually approved. A rail you did
58
- not request is not configured, and pairing has never implied one.
82
+ - The limits are the ones the owner actually approved on the page. Nothing you asked for
83
+ is granted until they approve it.
59
84
  - An email address, a `.visa` mesh name, and TAP bindings remain separate, later
60
- configuration. Do not infer them from a finished setup.
61
-
62
- **Where the `agentId` comes from — read this before you quote one.** The setup status body
63
- carries `operationId`, `state`, `readiness`, `nextAction`, `pollAfterMs`, `correlationId`
64
- and `agent: {name, runtime?, device?}`. It does **not** carry `agentId`, and it never
65
- carries `identityKeyJkt` (that is a field of the older pairing flow). `agentId` appears on
66
- exactly one result: the `setup_status` call that performed the activation, which returns it
67
- alongside `walked`. If you need the id and that call is not the one in front of you — the
68
- background watcher often finishes the last rung — read it from `get_status` or
69
- `agent_capabilities` rather than guessing. **Never substitute the `so_…` operation id or a
70
- `correlationId` for an `agentId`:** they are different things, and feeding an operation id
71
- to a grant ceremony fails in a way that looks like a Visa outage.
72
-
73
- **`setup_start` cannot add a rail to an agent that already exists** — it always creates a
74
- new one. To give an already-connected agent another rail, see "Adding a rail to an agent
75
- that already exists" near the end.
85
+ configuration. Do not infer them from a finished enrolment.
86
+
87
+ **Where the `agentId` comes from — read this before you quote one.** Do not invent it and
88
+ do not read it out of the command's terminal output, which you often cannot see. Read it
89
+ from `get_status` or `agent_capabilities` once the enrolment finishes. Never substitute a
90
+ correlation id, a confirmation code, or an origin for an `agentId`.
91
+
92
+ **Re-running the command does not repair an agent that already exists** — it creates a
93
+ second one. To fix a capability an existing agent is missing, see "Already set up — do NOT
94
+ enrol again" near the end.
76
95
 
77
96
  ## Getting this skill
78
97
 
@@ -107,10 +126,10 @@ OpenClaw users receive the skill via `visa agent skill --runtime openclaw` (or t
107
126
  - **Hermes or another supported runtime:** run `visa-cli connect hermes` or
108
127
  `visa-cli connect <runtime>`. For Hermes, the entry is written under `mcp_servers`
109
128
  in `~/.hermes/config.yaml`.
110
- - **No MCP integration:** use the raw `visa setup …` commands.
111
- 3. **Sign the owner in** when the setup includes the wallet rail — see "Sign in first"
112
- below.
113
- 4. **Connect.** Follow the core flow below.
129
+ - **No MCP integration:** everything below still works — the enrolment is a shell
130
+ command, and `--format json` output is available on the management commands.
131
+ 3. **Sign the owner in** — see "Sign in first" below.
132
+ 4. **Enrol.** Follow the core flow below.
114
133
 
115
134
  ## MCP mounting examples
116
135
 
@@ -166,11 +185,10 @@ live registry; never derive them from the config key.
166
185
  In Hermes, `hermes claw migrate` can also import this skill and MCP configuration from an
167
186
  existing OpenClaw installation. See `RUNTIMES.md` for the complete runtime map.
168
187
 
169
- ## Sign in first — the wallet rail is owner-bound
188
+ ## Sign in first — the wallet is owner-bound
170
189
 
171
- The USDC wallet rail is delegated out of the owner's own wallet, so this runtime needs a
172
- live owner session before that leg can run. Establish it **before** calling `setup_start`
173
- with `"wallet"` in `rails`:
190
+ The USDC wallet is delegated out of the owner's own wallet, so this runtime needs a live
191
+ owner session. Establish it **before** the enrolment command runs:
174
192
 
175
193
  - [ ] Call `agent_login` (MCP, default action `"start"`) or run
176
194
  `visa agent login --format json` (CLI). The result carries a sign-in `browserUrl`
@@ -183,234 +201,141 @@ with `"wallet"` in `rails`:
183
201
  - [ ] Claim the session: `agent_login {"action":"claim"}` (the CLI command polls on its
184
202
  own). Once claimed, the session token is stored locally.
185
203
 
186
- If a wallet leg reports `{"code":"session_required"}` or "Not logged in", that is this
204
+ `agent_login` establishes the OWNER's session on this device. It creates no agent and
205
+ grants no spending authority — those come from the enrolment command and the approval the
206
+ owner gives in their browser.
207
+
208
+ If something reports `{"code":"session_required"}` or "Not logged in", that is this
187
209
  ordering rule, not a fault: run `agent_login`, drive the sign-in above to a claimed
188
- session, then call `setup_status` again — the walk resumes where it stopped.
210
+ session, then continue.
189
211
 
190
- The account that signs in is the owner the setup binds to, and the same account must be
191
- signed in on the review page. A different account there fails closed with
192
- `owner_profile_mismatch`. The **card-only** setup does not need this leg first.
212
+ The account that signs in is the owner the enrolment binds to, and the same account must
213
+ be signed in on the approval page. A different account there fails closed.
193
214
 
194
215
  ## Core flow
195
216
 
196
- - [ ] **Ask what to call the agent.** `name` is required, and it is what the human sees on
197
- the approval page. Do not invent one.
198
- - [ ] **Ask which rails**, unless they already said. `"card"` is the Visa card rail,
199
- `"wallet"` is the USDC (x402) rail; `rails` defaults to `["card"]`. Both in one
200
- request costs the owner no extra approval — they share one budget.
201
- - [ ] **Call `setup_start`** with the name and rails. It mints the identity key, creates
202
- the operation, and opens the owner's browser at the review page.
203
- - [ ] **Relay `browserUrl` to the human**, with `compareCode` when the result carries one
204
- (see below). Never open it "for them" in place of showing it, and never approve.
205
- - [ ] **Call `setup_status`** at the returned `pollAfterMs`, repeatedly. Each call also
206
- executes the runtime's own steps — this is how the agent gets connected, so a setup
207
- you never poll is a setup that never finishes.
208
- - [ ] **Render `nextAction.label` verbatim** to the human each time it changes.
209
- - [ ] **Stop when `nextAction.kind` is `done`** (or any terminal state). Then report.
210
-
211
- ### The one rule for reading a status
212
-
213
- **`nextAction` is the server's decision. Render it; never compute your own.** Every
214
- surface — this runtime, the review page, the Console — says the same sentence about the
215
- same operation because they all render this one field. `nextAction.actor` tells you whose
216
- turn it is:
217
-
218
- - `actor: "agent"` — **yours**. Keep calling `setup_status`; it performs the step. Do not
219
- ask the human for anything, and do not end your turn waiting to be told they are done.
220
- - `actor: "human"` — **theirs**. Show `nextAction.label`, plus `nextAction.url` when the
221
- action carries one. Then keep polling: they act in the browser, not in chat.
222
- - `actor: "none"` — finished (`kind: "done"`) or terminal. Stop polling and report.
223
-
224
- Honour `pollAfterMs` (`0` means stop) and `nextAction.afterAction` (`"poll"`, `"stop"`,
225
- `"open_url_again"`). An agent that honours both cannot spin or give up early.
226
-
227
- ### Relaying the link and the compare code
228
-
229
- The review page shows a short code to compare **unless** it can tell by machine that the
230
- agent asking is the one that opened it — in which case it says "Opened from this device by
231
- the agent that asked" and shows no code. Which of the two happens is not knowable when you
232
- call `setup_start`: the page has not been opened yet, so the server carries no verdict, and
233
- neither does this runtime (launching a browser is not proof one loaded it).
234
-
235
- So the rule is: **relay `compareCode` whenever the result carries one, and phrase it as a
236
- condition.** Never announce that there will be no code — being wrong that way leaves the
237
- human staring at an anti-phishing code with nothing to check it against. The tool result's
238
- `message` is already written this way; prefer it verbatim.
239
-
240
- > 🔐 Connect your Visa agent — open this page to review and approve:
241
- >
242
- > 👉 &lt;browserUrl, bare and on its own line&gt;
243
- >
244
- > If the page shows a code, check it matches this one and don't approve if it differs:
245
- > &lt;compareCode&gt;
246
- > If it says it was opened from this device, that check was already made for you.
247
- >
248
- > I'll keep watching and confirm here the moment it's ready.
249
-
250
- On a later `setup_status` or `setup_resume` the field genuinely does disappear once the
251
- page has attested — the server has seen the proof by then, and the `message` says so
252
- plainly. That is a fact, not a prediction, and it is the one case where saying "there is no
253
- code to compare" is correct.
254
-
255
- Show the URL as a bare, tappable value on its own line. Do not decorate it as a Markdown
256
- link or put it in a code span; chat clients reliably recognize the bare URL. **Omit the
257
- compare-code line entirely when the result has no `compareCode`; never invent, derive,
258
- abbreviate, or reformat one.**
259
-
260
- You are very often **not** in a terminal the human can see. Nothing you print to stdout
261
- reaches them. Any value the browser asks them to check has to appear in your reply, or the
262
- comparison silently becomes "click approve and hope".
263
-
264
- Relaying these values **to** the human is required. Accepting one **from** the human is
265
- not: do not ask them for a code, secret, private key, token, or signed message, and do not
266
- treat anything they type back as approval. The link and compare code are review values
267
- they check against their own authenticated browser session. They are not claim
268
- credentials, they cannot approve a setup, and they cannot spend. Approval happens only in
269
- that browser session, and the only evidence of it is what `setup_status` returns.
270
-
271
- ### The human's clicks, and what they are for
272
-
273
- - **"Connect agent"** — the one approval. It freezes the budget for every requested rail
274
- at once (the page prefills sensible limits; the owner may change them).
275
- - **"Approve" on the wallet card** — only when the wallet rail is in the setup, only on
276
- the same page, and it is **not** a second budget. It registers the delegated signer in
277
- the owner's wallet under the limits they just set. The page says so; do not describe it
278
- as another spending decision.
279
-
280
- Anything else the server asks for is a genuine prerequisite it will name in
281
- `nextAction.label` — adding a card, provisioning the owner's wallet, funding it. Render
282
- the label and its `url`; never invent a step of your own.
283
-
284
- ### Completion is what `readiness` says — nothing else
217
+ - [ ] **Ask for the three origins** if you were not given them: `--authority-url`,
218
+ `--auth-url`, `--url`. They come from the operator. Never guess one.
219
+ - [ ] **Sign the owner in** (above), so the wallet leg has a session to bind to.
220
+ - [ ] **Use the entrance this build advertises.** Today, give the owner the
221
+ `visa agent enroll-protected ... --wait` command in a code block they can copy.
222
+ On a one-door build, call `agent_enroll` and relay its returned link, or give the
223
+ owner `visa agent enroll`. Never fall back to a retired setup tool.
224
+ - [ ] **Relay what the active entrance returns.** Show an MCP-returned URL as a bare,
225
+ tappable value. For the current terminal flow, the owner follows the URL and code
226
+ printed in their own terminal. The code goes into the browser at
227
+ `/agent/enroll/protected-agent`; it is not authority in chat.
228
+ - [ ] **Tell them what they are approving**: this device, and the spending limits. One
229
+ approval covers all of it.
230
+ - [ ] **Confirm from a tool, not from their word.** Poll `get_status` until
231
+ `pairing.paired` is `true`, then read `agent_capabilities` for what is actually live.
232
+
233
+ ### Relaying values, and what you must never accept
234
+
235
+ Relaying values **to** the human is required. Accepting one **from** them as authority is
236
+ not: never ask them for a secret, private key, token, or signed message, and never treat
237
+ anything they type back as approval. The URL and the enrolment code are review values they
238
+ check against their own authenticated browser session — they cannot approve anything and
239
+ cannot spend.
240
+
241
+ Show any URL as a bare, tappable value on its own line. Do not decorate it as a Markdown
242
+ link or put it in a code span; chat clients reliably recognise the bare URL. Never
243
+ construct, shorten, or reformat a Visa URL, and never open one "for them" in place of
244
+ showing it.
245
+
246
+ You are very often **not** in a terminal the human can see. Nothing the command prints to
247
+ their stdout reaches you unless they tell you, and nothing you print reaches them unless it
248
+ is in your reply.
249
+
250
+ ### Completion is what the tools say — nothing else
285
251
 
286
252
  Do not tell the human the agent is connected, paired, set up, ready, or good to go until
287
- `setup_status` returns a terminal `nextAction` of `kind: "done"`. A created operation is
288
- not a finished one: `setup_start` returns an `operationId` **before any human has approved
289
- anything**, and reporting that id as though it were a result is the most likely way to
290
- mislead them, because the string looks like an answer.
253
+ `get_status` reports `pairing.paired: true`. The enrolment command printing a URL is not a
254
+ result: it means an approval is still open in their browser.
291
255
 
292
256
  If you cannot get there, say plainly what state you did reach and what the human should do
293
- next. An honest "approved, still provisioning the wallet — I'm still watching" is correct;
294
- "you're all set" without a finished operation is not.
257
+ next. An honest "the approval page is open — I'm waiting for you to approve the device and
258
+ its limits" is correct; "you're all set" without a paired agent is not.
295
259
 
296
- On success, report the agent's name and the rails that are actually ready:
260
+ On success, report the agent and what is actually live:
297
261
 
298
- > Visa agent &lt;agent.name&gt; is connected. Ready to pay by &lt;card and/or USDC wallet&gt;, within
299
- > the limits you approved.
262
+ > Your Visa agent is set up. Ready to pay by &lt;card and/or USDC wallet&gt;, within the
263
+ > limits you approved.
300
264
 
301
- Quote an `agentId` only if the result you are holding actually carries one (see "Where the
302
- `agentId` comes from" above). It is not needed to tell the human they are done.
265
+ Read the rails from `agent_capabilities`, never from what was requested.
303
266
 
304
267
  ## Interruption and resume
305
268
 
306
- The runtime persists the operation before it starts, so an interrupted call is safe to
307
- repeat: the same `operationId`, the same agent and the same identity key resume exactly
308
- where they stopped.
269
+ The runtime persists the pending enrolment before it starts, so an interrupted run is safe
270
+ to repeat: **the same command again** resumes it, with the same request and the same
271
+ device key.
309
272
 
310
- - `setup_status` — read and continue. Omit `operationId` for the newest setup on this
311
- device.
312
- - `setup_resume` — the same, and puts the review link back in front of the human when
313
- that is still what the operation is waiting on. The same-device proof is **not**
314
- re-minted, so a resumed page falls back to the compare code, which is what it is for.
315
- - `setup_cancel` — abandon one the human no longer wants. It cannot undo an approval; the
316
- server refuses to touch an operation past the owner's decision.
273
+ - Same command, no flags changed — resumes and reprints the URL and code.
274
+ - `--restart` — replaces an unclaimed request with a fresh terminal code. Use it only when
275
+ the previous code is genuinely unusable; it is not a retry button.
276
+ - `--wait` — keeps the command polling until the owner has approved, instead of returning
277
+ after printing the link.
317
278
 
318
- Do not start a second setup because the first went quiet — poll it. Two setups mean two
319
- agents, two identities, and a confused owner. Do not delete or edit local pending files to
320
- fix a transient failure, and never copy pending state between runtimes.
279
+ Do not tell the human to run a second, different enrolment because the first went quiet.
280
+ Two enrolments mean two agents, two identities, and a confused owner. Do not delete or edit
281
+ local pending files to fix a transient failure, and never copy pending state between
282
+ runtimes.
321
283
 
322
- ## Raw CLI equivalent
323
-
324
- If MCP is unavailable, the same ceremony runs from the shell. The name is a positional
325
- argument:
284
+ ## Management commands (an agent that already exists)
326
285
 
327
286
  ```
328
- visa setup start "<name>" --rails card,wallet --format json
329
- visa setup status [operationId] --format json
330
- visa setup open [operationId] --format json
331
- visa setup cancel [operationId] --format json
332
- visa setup list --format json
287
+ visa agent list --format json
288
+ visa agent show <agentId> --format json
289
+ visa agent spendability --format json # can it spend, and what is missing
290
+ visa agent preflight --format json # every gate before a payment
291
+ visa agent pause|resume|revoke <agentId>
292
+ visa agent keychain status|repair # this device's identity custody
333
293
  ```
334
294
 
335
- `visa setup status` drives the agent's steps exactly as the MCP tool does — run it until
336
- the operation is finished. Prefer structured output and parse it; never scrape prose.
337
-
338
- ## The human already created this agent in the Console
339
-
340
- When the human says they created the agent on the Visa Console and holds a one-time claim
341
- code, redeem the code instead of starting a new setup — the code carries server-held,
342
- pre-approved terms.
343
-
344
- The MCP tool `agent_handoff_claim` exists only on `@visa/cli` **4.1.0-rc.159 and newer**
345
- — on an older CLI it is absent from the served tool list and the only path is shelling
346
- `visa agent handoff-claim <code> --format json`, a different integration with different
347
- failure modes (the approval URL and verification code arrive mid-run as a structured
348
- stderr frame). Never assume the tool from documentation alone: check the served list.
349
- In a handoff claim the card auto-activates from the mint consent, and the
350
- wallet still needs one browser approval. Console handoff codes are owner-pinned by the
351
- code itself and do NOT require an active owner session.
352
-
353
- If they created it in the Console but have **no** code, still call `setup_start`: it
354
- adopts the request they already made — their Create click was the approval — rather than
355
- asking them to approve a second time.
295
+ None of these creates an identity. Prefer structured output and parse it; never scrape
296
+ prose.
356
297
 
357
- ## Already connected — do NOT connect again
298
+ ## Already set up — do NOT enrol again
358
299
 
359
- If this device already holds an agent, a fresh setup is not needed and creates a
300
+ If this device already holds an agent, a fresh enrolment is not needed and creates a
360
301
  _second, separate_ agent. Do this instead:
361
302
 
362
- 1. **Tell the user plainly:** "This device is already connected as `<name>.visa`." Read
363
- the name from the response. Start another setup only if they explicitly want a second
364
- agent.
365
- 2. **Report status honestly — "connected" is several separate things.** Never imply the
366
- agent can spend just because it is connected. Read it live from tools rather than
367
- guessing from prose: `agent_capabilities` returns the DERIVED capability map (the
368
- identity + wallet + mail base plus card/tap/subway availability), `get_status` reports
369
- enrollment / account / version, and `agent_login` establishes or confirms the account
303
+ 1. **Tell the user plainly:** "This device is already set up as `<name>`." Read the name
304
+ from `agent_capabilities` or `visa agent list`. Start another enrolment only if they
305
+ explicitly want a second agent.
306
+ 2. **Report status honestly — "set up" is several separate things.** Never imply the agent
307
+ can spend just because it exists. Read it live from tools rather than guessing from
308
+ prose: `agent_capabilities` returns the DERIVED capability map, `get_status` reports
309
+ pairing / account / version, `visa agent spendability --format json` answers "can it
310
+ spend, and what is missing", and `agent_login` establishes or confirms the account
370
311
  session.
371
- - **Identity** — connected (`.visa` name bound to _this user's_ account).
372
- - **Spending** — the rails the owner actually approved. The Turnkey **wallet:x402**
373
- rail (stablecoin) is approved with the owner's **sign-in session** — **no passkey**.
374
- The **card:vic** rail is approved on the **v4 agent dashboard**
375
- (`app.visacli.sh/agent/enroll`), never any account-settings page (that legacy surface
376
- is retired). You **cannot** self-grant either, and never self-mint a wallet with
377
- `wallet_init` on mainnet — it throws `WalletCredentialRequiredError` until the
378
- owner's delegation lands.
312
+ - **Identity** — bound to _this user's_ account, on _this device_.
313
+ - **Spending** — the limits the owner approved in the browser. You **cannot** self-grant
314
+ either rail, and never self-mint a wallet with `wallet_init` on mainnet — it throws
315
+ `WalletCredentialRequiredError` until the owner's delegation lands.
379
316
  - **Mesh (`.visa` messaging)** — separate; `visa register <name>` joins it.
380
317
  - **Trusted (TAP)** — follows spend/provisioning; don't promise it before then.
381
318
  3. **Scope everything to the user.** The identity is bound to the account they signed in
382
319
  with; the wallet and limits are theirs. Speak in terms of "your agent / your account /
383
320
  the limits you approved", never a shared identity.
384
321
 
385
- ## Adding a rail to an agent that already exists
386
-
387
- `setup_start` always mints a new agent, so it is the wrong tool here. For an
388
- already-connected agent that needs another rail, run the single-rail grant ceremony
389
- against its **exact `agentId`** — never a name, never "the most recent one":
390
-
391
- - [ ] **Establish the owner session** if this runtime does not have one: `agent_login`
392
- (MCP) or `visa agent login` (CLI). Short-lived, established once — not a re-pair,
393
- and not something the owner repeats per payment.
394
- - [ ] **Initiate the grant from MCP.** `agent_connect` with the rail, caps, and the exact
395
- `agentId`:
396
- `{"agentId":"<agentId>","rail":"card","ceiling":"<usd>","perTransaction":"<usd>"}`
397
- (or `"rail":"wallet"`). It returns `{ url, code, attachId, willGrant, expiresAt }`.
398
- Present the **bare `url` and `code` exactly as returned** — never construct,
399
- shorten, or guess a Visa URL, and never open it yourself.
400
- - [ ] **The owner approves once** on the v4 agent dashboard, confirming the caps.
401
- - [ ] **Poll to activation** with `agent_connect_poll` (`{"attachId":"<from
402
- agent_connect>"}`) — one bounded poll per call, until
403
- `{"ok":true,"state":"grant_activated"}`.
404
- - [ ] **Confirm the rail is live.** Wallet: `wallet_status` / `visa wallet show`
405
- (`agent_capabilities.wallet.available`). Card: `agent_capabilities.card.available`.
406
- Only a delegated credential — not the served tool list — means the rail is usable.
407
-
408
- Shell equivalents, which poll to activation in one call:
322
+ ## An existing agent is missing a capability
409
323
 
410
- ```
411
- visa agent grant-card <agentId> --ceiling <usd> --per-transaction <usd> --wait
412
- visa agent grant-wallet <agentId> --ceiling <usd> --per-transaction <usd> --wait
413
- ```
324
+ There is no rail-add ceremony any more: `visa agent grant-card` / `grant-wallet` /
325
+ `grant-activate` / `grant-claim` and the `agent_connect` tools were deleted, and calling
326
+ one returns `legacy_door_removed`.
327
+
328
+ What to do instead:
329
+
330
+ - [ ] **Diagnose first.** `visa agent spendability --format json` and
331
+ `agent_capabilities` say exactly what is missing. Do not start anything before you
332
+ know which of identity, wallet delegation, card authority or funding is absent.
333
+ - [ ] **If the device's identity custody is broken**, `visa agent keychain repair` fixes
334
+ it without minting a new agent.
335
+ - [ ] **If the OWNER never approved that authority**, only they can add it. Say so, name
336
+ what is missing, and stop. Enrolling again mints a NEW agent — it does not upgrade
337
+ this one, and doing it silently leaves the owner with two agents and one funded
338
+ wallet.
414
339
 
415
340
  A policy refusal or timeout means **nothing was signed**: report it and stop; do not retry
416
341
  with a different command or a reconstructed URL. Never raise a human-approved limit
@@ -430,6 +355,13 @@ gated by the owner-approved local policy caps.
430
355
  Card: `start_card_mandate`, then `pay_merchant`. The first card purchase asks the owner
431
356
  for a spending mandate within the budget they already approved.
432
357
 
358
+ The current card rail uses VIC browser checkout through `pay_merchant` after
359
+ `start_card_mandate`; do not claim that browser checkout is unavailable before the card
360
+ retirement change lands. On a hosted runtime, **every payment requires the owner's browser
361
+ approval** until the protected no-tap executor lands. Enrollment, a session, or a spending
362
+ grant does not approve a later hosted payment. Relay the hosted approval URL and wait for
363
+ the owner's decision before reporting success or retrying.
364
+
433
365
  ## Optional `.visa` mesh binding (separate from setup)
434
366
 
435
367
  Pairing does not register a `.visa` name, TAP key, or Subway peer. If the operator has
@@ -509,10 +441,13 @@ mailbox, key proof, recovery factor, or permission to spend.
509
441
  - Never fetch or submit the review URL on the human's behalf. They review and approve it
510
442
  in their own browser.
511
443
  - Never invent a secondary path when a call fails. Preserve the local state, surface the
512
- error, and resume through `setup_status` / `setup_resume`.
444
+ error, and resume through the same protected entrance. On today's build, repeat the
445
+ same `visa agent enroll-protected ... --wait` command.
446
+ - Never call a retired door to "check whether it still works". `legacy_door_removed` is a
447
+ final answer, not a transient failure.
513
448
 
514
449
  ## Further docs
515
450
 
516
451
  - `RUNTIMES.md` — OpenClaw, Hermes, and raw CLI setup.
517
- - `docs/agents/ARCHITECTURE.md` — where setup sits in the v4 request paths.
452
+ - `docs/agents/ARCHITECTURE.md` — where enrolment sits in the v4 request paths.
518
453
  - `visacli.sh/agents` — product-facing agent documentation.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@visa/cli",
3
- "version": "4.1.0-rc.297",
3
+ "version": "4.1.0-rc.299",
4
4
  "description": "Visa CLI runtime for stable agent identity and separately authorized payment capabilities",
5
5
  "bin": {
6
6
  "visa-cli": "./bin/visa-cli.js",
@@ -10,7 +10,7 @@
10
10
  "scripts": {
11
11
  "sync:server-json": "node scripts/sync-server-json.mjs",
12
12
  "check:server-json": "node scripts/sync-server-json.mjs --check",
13
- "prebuild": "node scripts/sync-server-json.mjs && pnpm --filter @visa/shared build && pnpm --filter @visa/observability build && pnpm --filter @visa/money build && pnpm --filter @visa/crypto build && pnpm --filter subway-sdk build && pnpm --filter @visa-cli/tools build && pnpm --filter @visa/identity build && pnpm --filter @visa/wallet build && pnpm --filter @visa/agent-mail build && pnpm --filter @visa/wallet-tools build && pnpm --filter @visa/checkout-engine build",
13
+ "prebuild": "node scripts/sync-server-json.mjs && pnpm --filter @visa/shared build && pnpm --filter @visa/observability build && pnpm --filter @visa/money build && pnpm --filter @visa/crypto build && pnpm --filter subway-sdk build && pnpm --filter @visa-cli/tools build && pnpm --filter @visa/identity build && pnpm --filter @visa/wallet build && pnpm --filter @visa/agent-mail build && pnpm --filter @visa/wallet-tools build",
14
14
  "build": "tsc --noEmit && node esbuild.config.js",
15
15
  "prepack": "node scripts/sync-server-json.mjs --check",
16
16
  "dev": "tsc --watch",
@@ -59,7 +59,6 @@
59
59
  "@libp2p/tcp": "^11.0.26",
60
60
  "@multiformats/multiaddr": "^13.0.3",
61
61
  "libp2p": "^3.3.9",
62
- "playwright-core": "^1.62.1",
63
62
  "uint8arrays": "^6.1.1"
64
63
  },
65
64
  "devDependencies": {
@@ -70,7 +69,6 @@
70
69
  "@typescript-eslint/parser": "^8.68.0",
71
70
  "@visa-cli/tools": "workspace:*",
72
71
  "@visa/agent-mail": "workspace:*",
73
- "@visa/checkout-engine": "workspace:*",
74
72
  "@visa/crypto": "workspace:*",
75
73
  "@visa/identity": "workspace:*",
76
74
  "@visa/money": "workspace:*",
package/server.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
3
  "name": "io.github.visa-crypto-labs/visa-cli",
4
- "version": "4.1.0-rc.297",
4
+ "version": "4.1.0-rc.299",
5
5
  "title": "Visa CLI",
6
6
  "description": "Pair a human-approved agent identity, configure payment capabilities separately, and discover and pay x402 services from your AI coding assistant.",
7
7
  "websiteUrl": "https://github.com/Visa-Crypto-Labs/Visa-mono/tree/main/packages/cli#readme",
@@ -9,7 +9,7 @@
9
9
  {
10
10
  "registryType": "npm",
11
11
  "identifier": "@visa/cli",
12
- "version": "4.1.0-rc.297",
12
+ "version": "4.1.0-rc.299",
13
13
  "transport": {
14
14
  "type": "stdio"
15
15
  },