@visa/cli 4.1.0-rc.37 → 4.1.0-rc.39

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 CHANGED
@@ -1,21 +1,19 @@
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 silently create a wallet,
6
+ card credential, budget, mailbox, `.visa` name, or TAP listing.
7
+
8
+ The product flow has three explicit parts:
9
+
10
+ 1. **Identity** `enroll_agent` (or `visa agent enroll`) opens one browser
11
+ review for the exact runtime and public-key fingerprint. The private key
12
+ stays on the runtime device.
13
+ 2. **Capabilities** — payment methods, spend grants, email and directory
14
+ bindings are configured separately, each with its own human-visible terms.
15
+ 3. **Use** when a separately provisioned capability exists, the wallet and
16
+ VIC commands enforce that capability's own policy and approval boundary.
19
17
 
20
18
  ## Install
21
19
 
@@ -65,27 +63,59 @@ args = ["<npm root -g>/@visa/cli/dist/mcp-server/index.js"]
65
63
 
66
64
  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
65
 
68
- ## Enroll a Verified Agent
66
+ ## Pair an agent identity
67
+
68
+ From MCP, call **`enroll_agent`** with `{"action":"start"}`. It creates the
69
+ runtime's Ed25519 key locally, verifies the terminal/browser channel, and opens
70
+ the identity-only review. After the human approves, call `enroll_agent` with
71
+ `{"action":"claim"}` to activate and durably store the identity.
72
+
73
+ ```bash
74
+ visa agent enroll # opens the one human review page
75
+ visa agent enroll-claim # resumes delivery/activation after approval
76
+ visa agent list
77
+ visa agent show <agent-id>
78
+ ```
69
79
 
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.
80
+ The advanced `create` `claim` `verify` `resume` commands are the
81
+ split-device choreography of this same v2 ceremony, not a second enrollment
82
+ system. The review shows the runtime, context, stable agent ID, full public-key
83
+ fingerprint, and expiry. It grants identity only; no spend limits or instruments
84
+ are implied.
71
85
 
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.
86
+ On macOS and Linux, the private identity key is stored under
87
+ `~/.visa-cli/agents` in an owner-only directory with file mode `0600`. It is
88
+ currently an exportable local file: copying it transfers identity proof, and
89
+ losing it blocks new proofs because same-agent key recovery is not yet
90
+ available. Protocol-v2 identity pairing fails closed on Windows until the CLI
91
+ can apply and verify an owner-only Windows ACL. The pairing link contains no
92
+ credential or private key.
74
93
 
75
- ## Connect an agent runtime (pairing)
94
+ ## Recover an existing account session
76
95
 
77
- Enrollment mints identity; **pairing is what lets a runtime sign payments.**
96
+ `visa agent login` opens the Turnkey-first web sign-in for an existing v4
97
+ account, then `visa agent login-claim` stores the returned account session in
98
+ the OS keychain. `--wait` keeps the first command polling for the full
99
+ 15-minute browser window.
78
100
 
79
101
  ```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
102
+ visa agent login # sign in and display the terminal confirmation code
103
+ visa agent login-claim # resume pickup after returning from the browser
84
104
  ```
85
105
 
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.
106
+ This is account-session recovery, not agent pairing. It does not create or
107
+ replace an identity key, delegate a wallet, select a card, set a budget, or
108
+ grant spend authority. The pending PKCE verifier is kept under
109
+ `~/.visa-cli/session-recovery/` in owner-only local state and is pinned to the
110
+ exact web origin that started the flow.
111
+ Session recovery currently fails closed on Windows until the CLI can apply and
112
+ verify an owner-only ACL for this pending verifier.
113
+
114
+ ## Existing wallet capability: caps, then funding
87
115
 
88
- ## Caps, then funding strict order
116
+ These commands apply only to a pre-cutover/test runtime that already has a
117
+ valid, separately provisioned wallet credential. Pairing again cannot create or
118
+ repair that payment capability.
89
119
 
90
120
  ```bash
91
121
  visa wallet limits --per-transaction 0.25 --daily 2.00 # BEFORE any funds arrive
@@ -120,8 +150,8 @@ command.
120
150
 
121
151
  | Tool | Description |
122
152
  |------|-------------|
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 |
153
+ | `enroll_agent` | Two-step identity-only pairing: start opens the exact runtime/key review; `{"action":"claim"}` activates and stores the agent identity |
154
+ | `wallet_status` | Separately provisioned wallet address, network, and policy state |
125
155
  | `wallet_policy_set` | Set per-transaction / daily caps (with human approval) |
126
156
  | `wallet_discover` | Sweep x402 directories for services, with live re-probing |
127
157
  | `wallet_probe` | Fetch a service's live 402 challenge without paying |
@@ -163,7 +193,15 @@ visa pay <listing-id> --max <usd>
163
193
  visa activity
164
194
  visa receipt <receipt-id>
165
195
 
166
- # Human-approved agent runtime pairing
196
+ # Primary same-machine v2 identity pairing
197
+ visa agent enroll
198
+ visa agent enroll-claim
199
+
200
+ # Existing-account session recovery (separate from identity pairing)
201
+ visa agent login
202
+ visa agent login-claim
203
+
204
+ # Advanced split-device form of the same v2 ceremony
167
205
  visa agent create
168
206
  visa agent claim <pairing-id> --runtime <name> --context "<purpose>"
169
207
  visa agent verify <pairing-id> <code>
@@ -200,14 +238,18 @@ visa-cli feedback # submit feedback
200
238
 
201
239
  | Path | Contents |
202
240
  |------|----------|
203
- | `~/.visa-mcp/agent-credential.json` | Verified Agent enrollment credential (mode 0600) |
204
- | `~/.visa-cli/` | Pairing / delegated signer credentials (mode 0600) |
241
+ | `~/.visa-cli/pairings/` | Pending ceremony verifier or runtime identity key (owner-only mode 0600 on macOS/Linux; v2 pairing currently disabled on Windows) |
242
+ | `~/.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) |
243
+ | `~/.visa-cli/session-recovery/` | Pending login-only PKCE verifier and pinned web origin (owner-only mode 0600 on macOS/Linux) |
244
+ | `~/.visa-mcp/agent-credential.json` | Legacy checkout-credential compatibility record (mode 0600) |
205
245
  | `~/.visa-v4/policy.json` | Wallet spend policy — never edit by hand; use `visa wallet limits` |
206
246
 
207
247
  ## Troubleshooting
208
248
 
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.
249
+ **Wallet commands report that payment setup is required**
250
+ Identity pairing deliberately grants no payment authority. Complete the
251
+ separate wallet/instrument and spend-policy setup when available; pairing again
252
+ will not upgrade an identity into a signer.
211
253
 
212
254
  **`policy refused` from `pay`**
213
255
  A cap or allowlist said no; nothing was signed. Raise caps only via `visa wallet limits` with the human's approval.
@@ -216,7 +258,8 @@ A cap or allowlist said no; nothing was signed. Raise caps only via `visa wallet
216
258
  That URL isn't payment-gated — probe the service's actual paid route (`wallet_probe` / `visa find`).
217
259
 
218
260
  **Pairing ended `expired` or `cancelled`**
219
- The ceremony timed out — re-run `visa agent create` and claim the new pairing id.
261
+ The ceremony timed out — restart with `visa agent enroll`, then run
262
+ `visa agent enroll-claim` after approving the new browser review.
220
263
 
221
264
  **Tools don't appear in the AI client**
222
265
  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.
@@ -2,7 +2,7 @@ import { type Browser } from 'playwright-core';
2
2
  import { prepareCheckout as realPrepareCheckout, submitApprovedCheckout as realSubmitApprovedCheckout, type PreparedCheckoutSessionStore } from './executor.js';
3
3
  import { runHostedApproval as realRunHostedApproval } from './hosted-approval.js';
4
4
  import { type VgsCheckoutTarget } from './vgs-live-instrument.js';
5
- import { serverFetchCryptogram } from './vgs-gateway/server-mint-client.js';
5
+ import { serverFetchCryptogram, serverPostConfirmation } from './vgs-gateway/server-mint-client.js';
6
6
  import { type CardMandateFacts } from './mandate/card-mandate.js';
7
7
  import { MandateLedger } from './mandate/mandate-ledger.js';
8
8
  import { writeReceipt as realWriteReceipt } from './receipt.js';
@@ -61,20 +61,13 @@ export type CliReceiptFacts = {
61
61
  remainingMinor: number | null;
62
62
  };
63
63
  export type CliStartMandateInput = {
64
- /** The merchant URL for a merchant-scoped mandate. Optional (and ignored) when
65
- * `anyMerchant` is set — a budget mandate is not tied to a merchant. */
66
- url?: string;
64
+ /** Optional local card-capability selector (legacy name or exact request-key JKT). */
65
+ agentRef?: string;
67
66
  ceiling: string;
68
67
  currency: string;
69
68
  credentialPath: string;
70
69
  contact: Contact;
71
70
  approvalBaseUrl: string;
72
- merchantName?: string;
73
- merchantCountryCode?: string;
74
- /** ISO 8601 mandate expiry; defaults to now + 24h. */
75
- expiresAt?: string;
76
- /** Max draws the ceiling intent may fulfil. */
77
- maxDraws?: number;
78
71
  /**
79
72
  * Per-purchase cap (decimal string, > 0 and <= ceiling). Registered with the
80
73
  * approval context so the operator reads it as a worst-case term, and carried
@@ -86,12 +79,6 @@ export type CliStartMandateInput = {
86
79
  * "written by the agent" block — provenance for the human, never trusted.
87
80
  */
88
81
  intent?: string;
89
- /**
90
- * BUDGET mode: create a mandate spendable at ANY merchant (no merchant lock),
91
- * bounded by the ceiling + per-transaction limit. The passkey approval shows
92
- * "spend budget mandate" so the owner consents to the broader scope.
93
- */
94
- anyMerchant?: boolean;
95
82
  };
96
83
  export type CliMandateFacts = CardMandateFacts & {
97
84
  merchantHost: string;
@@ -99,8 +86,8 @@ export type CliMandateFacts = CardMandateFacts & {
99
86
  * True when the mandate minted its ceiling intent but the #5942 register
100
87
  * handshake failed, so `findCovering` will SKIP it and no tap-free draw is
101
88
  * possible. The mandate exists but is not usable — the caller must surface
102
- * this (not report a plain success). Absent/false registered (or no
103
- * delegated binding was present, so register was intentionally not attempted).
89
+ * this (not report a plain success). Absent/false means registration succeeded;
90
+ * mandate-start now refuses before approval when no capability can register.
104
91
  */
105
92
  registerFailed?: boolean;
106
93
  };
@@ -128,7 +115,7 @@ export interface CardDrawVerdictCapability {
128
115
  authBaseUrl: string;
129
116
  }
130
117
  export interface CardDrawVerdictSeam {
131
- loadCapability: () => CardDrawVerdictCapability | null;
118
+ loadCapability: (agentRef?: string) => CardDrawVerdictCapability | null;
132
119
  fetchVerdict: (input: {
133
120
  authBaseUrl: string;
134
121
  agentKey: unknown;
@@ -141,7 +128,7 @@ export interface CardDrawVerdictSeam {
141
128
  }>;
142
129
  }
143
130
  export interface CardMandateRegisterSeam {
144
- loadCapability: () => {
131
+ loadCapability: (agentRef?: string) => {
145
132
  agentKey: unknown;
146
133
  agentJkt: string;
147
134
  authBaseUrl: string;
@@ -185,18 +172,18 @@ export type CliEngineDeps = {
185
172
  * markUnhonored path with no network.
186
173
  */
187
174
  serverFetchCryptogram?: typeof serverFetchCryptogram;
175
+ /** Injectable confirmation transport; defaults to verify-web. */
176
+ serverPostConfirmation?: typeof serverPostConfirmation;
188
177
  /**
189
178
  * #5923 delegated card-draw verdict seam (see {@link CardDrawVerdictSeam}).
190
- * Injected by the CLI when the agent holds a mode='card' delegated binding;
191
- * when absent the covering-mandate draw keeps using the bearer mint token (the
192
- * shipped #5917 flow, unchanged).
179
+ * Injected by the CLI when the runtime holds separately provisioned card
180
+ * authority. When absent, a covering-mandate draw fails before cryptogram mint.
193
181
  */
194
182
  cardDrawVerdict?: CardDrawVerdictSeam;
195
183
  /**
196
184
  * #5942 delegated card-mandate register seam (see {@link CardMandateRegisterSeam}).
197
- * Injected by the CLI when the agent holds a mode='card' delegated binding;
198
- * when absent mandate-start skips the register (best-effort the bearer path
199
- * still works, only the delegated draw needs the register row).
185
+ * Required by mandate-start. When absent, the ceremony is refused before
186
+ * passkey approval because a budget token cannot act as draw authority.
200
187
  */
201
188
  cardMandateRegister?: CardMandateRegisterSeam;
202
189
  };