@visa/cli 4.1.0-rc.26 → 4.1.0-rc.261

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 (83) hide show
  1. package/README.md +202 -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 +80 -0
  7. package/dist/checkout-engine/adapters/shopify.js +688 -0
  8. package/dist/checkout-engine/amount.d.ts +15 -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 +206 -32
  15. package/dist/checkout-engine/cli-engine.js +772 -216
  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 +61 -3
  22. package/dist/checkout-engine/executor.js +550 -144
  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 +6 -2
  26. package/dist/checkout-engine/index.js +5 -1
  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/receipt-dir.d.ts +6 -0
  37. package/dist/checkout-engine/receipt-dir.js +8 -0
  38. package/dist/checkout-engine/receipt.d.ts +56 -2
  39. package/dist/checkout-engine/receipt.js +55 -16
  40. package/dist/checkout-engine/shopify-primary-domain.d.ts +25 -0
  41. package/dist/checkout-engine/shopify-primary-domain.js +96 -0
  42. package/dist/checkout-engine/trace-handles.d.ts +8 -0
  43. package/dist/checkout-engine/trace-handles.js +12 -0
  44. package/dist/checkout-engine/types.d.ts +15 -2
  45. package/dist/checkout-engine/unresolved-charges.d.ts +34 -0
  46. package/dist/checkout-engine/unresolved-charges.js +134 -0
  47. package/dist/checkout-engine/vgs-gateway/server-mint-client.d.ts +26 -7
  48. package/dist/checkout-engine/vgs-gateway/server-mint-client.js +43 -3
  49. package/dist/checkout-engine/vgs-live-instrument.d.ts +11 -35
  50. package/dist/checkout-engine/vgs-live-instrument.js +14 -74
  51. package/dist/checkout-engine/vic-confirmation.d.ts +18 -0
  52. package/dist/checkout-engine/vic-confirmation.js +9 -3
  53. package/dist/checkout-engine/web-bot-auth.d.ts +98 -0
  54. package/dist/checkout-engine/web-bot-auth.js +218 -0
  55. package/dist/cli.js +899 -387
  56. package/dist/mcp-apps/ucp-checkout.html +280 -0
  57. package/dist/mcp-server/index.js +725 -254
  58. package/dist/merchant-ucp-mcp/index.js +6 -0
  59. package/dist/skills/pair-visa-agent/RUNTIMES.md +122 -79
  60. package/dist/skills/pair-visa-agent/SKILL.md +433 -318
  61. package/dist/skills/pair-visa-agent/scripts/__tests__/setup.test.mjs +407 -0
  62. package/dist/skills/pair-visa-agent/scripts/setup.mjs +310 -30
  63. package/dist/skills/visa-shopify-checkout/SKILL.md +122 -0
  64. package/dist/skills/visa-shopify-checkout/references/evidence-and-states.md +37 -0
  65. package/dist/skills/visa-ucp-shopping/SKILL.md +86 -0
  66. package/dist/subway-direct.mjs +1 -0
  67. package/install.ps1 +7 -6
  68. package/install.sh +3 -3
  69. package/native/bin/win32-x64/visa-keychain-win.exe +0 -0
  70. package/package.json +31 -28
  71. package/server.json +4 -4
  72. package/dist/checkout-engine/inline-target.d.ts +0 -13
  73. package/dist/checkout-engine/inline-target.js +0 -37
  74. package/dist/checkout-engine/pay-args.d.ts +0 -14
  75. package/dist/checkout-engine/pay-args.js +0 -44
  76. package/dist/checkout-engine/pay.d.ts +0 -1
  77. package/dist/checkout-engine/pay.js +0 -13
  78. package/dist/checkout-engine/repo-env.d.ts +0 -11
  79. package/dist/checkout-engine/repo-env.js +0 -23
  80. package/dist/checkout-engine/run-live-fill.d.ts +0 -1
  81. package/dist/checkout-engine/run-live-fill.js +0 -493
  82. package/dist/checkout-engine/vgs-gateway/fetch-credential.d.mts +0 -74
  83. package/dist/checkout-engine/vgs-gateway/fetch-credential.mjs +0 -248
@@ -1,13 +1,13 @@
1
1
  import { type Browser } from 'playwright-core';
2
- import { prepareCheckout as realPrepareCheckout, submitApprovedCheckout as realSubmitApprovedCheckout, type PreparedCheckoutSessionStore } from './executor.js';
3
- import { runHostedApproval as realRunHostedApproval } from './hosted-approval.js';
2
+ import { prepareCheckout as realPrepareCheckout, submitApprovedCheckout as realSubmitApprovedCheckout, type CheckoutMode, type CheckoutOutcome, type CheckoutFailureCode, type CheckoutResult, type PreparedCheckoutSessionStore } from './executor.js';
3
+ import { claimMandatePickup as realClaimMandatePickup, 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';
9
9
  import { reportVicOutcome as realReportVicOutcome, type VicConfirmationReport } from './vic-confirmation.js';
10
- import type { Contact } from './types.js';
10
+ import type { Contact, OtpResolver } from './types.js';
11
11
  /**
12
12
  * A card-mandate draw failed transiently (retryable) rather than definitively.
13
13
  * Gateway 5xx, "server cryptogram not completed / try again", and network
@@ -16,15 +16,45 @@ import type { Contact } from './types.js';
16
16
  * is classified by its underlying gateway error. Exported for tests.
17
17
  */
18
18
  export declare function isTransientDrawFailure(err: unknown): boolean;
19
+ /**
20
+ * A verdict refusal may be wrapped by drawFromMandate after its local
21
+ * reservation is released. Walk the cause chain so the original auth status +
22
+ * reasons still decide whether the mandate is permanently disabled.
23
+ */
24
+ export declare function classifyCardDrawVerdictFailure(err: unknown): {
25
+ transient: boolean;
26
+ grantCapacity: boolean;
27
+ reasons: string[];
28
+ } | null;
19
29
  export type CliReviewInput = {
20
30
  url: string;
31
+ checkoutRoute: 'guest-card';
21
32
  amount: string;
22
33
  currency: string;
23
34
  credentialPath: string;
35
+ /** See {@link CardInstrumentSource}. */
36
+ cardTokenId?: string;
37
+ /** Exact request-key identity selected by the caller. */
38
+ agentJkt?: string;
39
+ /** Owner-facing selected-agent label for the compact local receipt. */
40
+ agentName?: string;
41
+ /** Safe display suffix derived from the selected card grant label. */
42
+ cardLast4?: string;
24
43
  contact: Contact;
25
44
  approvalBaseUrl: string;
45
+ /**
46
+ * #8047: agent-authored purchase narrative captured at review time and
47
+ * replayed into the card draw's Transaction Intent Journal at pay time.
48
+ */
49
+ intentNarrative?: CardIntentNarrative;
26
50
  merchantName?: string;
27
51
  merchantCountryCode?: string;
52
+ trustedMerchantIdentity?: Readonly<{
53
+ handoffId: string;
54
+ checkoutId: string;
55
+ allowedOrigins: readonly string[];
56
+ expiresAt: string;
57
+ }>;
28
58
  };
29
59
  export type CliReviewFacts = {
30
60
  reviewId: string;
@@ -34,41 +64,75 @@ export type CliReviewFacts = {
34
64
  submitTargetFingerprint: string;
35
65
  detectedRoles: string[];
36
66
  };
67
+ /**
68
+ * A checkout was inspected successfully but cannot be reviewed safely.
69
+ *
70
+ * The explicit fields survive the CLI's copied-engine boundary structurally,
71
+ * so MCP callers do not have to parse the human-readable message.
72
+ */
73
+ export declare class CheckoutReviewRefusedError extends Error {
74
+ readonly code = "CHECKOUT_REVIEW_REFUSED";
75
+ readonly checkoutOutcome: CheckoutOutcome;
76
+ readonly failureCode?: CheckoutFailureCode;
77
+ readonly requiresAdapter: string[];
78
+ readonly detectedRoles: string[];
79
+ readonly receiptWrite: ReceiptWriteObservation;
80
+ readonly detail?: string;
81
+ constructor(result: CheckoutResult, receiptWrite: ReceiptWriteObservation);
82
+ }
37
83
  export type CliPayInput = CliReviewInput & {
38
84
  reviewId: string;
39
85
  submit: boolean;
86
+ /**
87
+ * Headless handoff for this payment attempt. The MCP layer uses it to return
88
+ * the hosted passkey URL to a messaging surface while the engine continues
89
+ * waiting in-process.
90
+ */
91
+ onApprovalUrl?: (url: string) => void;
40
92
  };
41
93
  export type CliReceiptFacts = {
42
- outcome: string;
94
+ outcome: CheckoutOutcome;
43
95
  confirmationRef: string | null;
44
96
  receiptPath: string | null;
45
97
  detail: string | null;
46
98
  vicConfirmation: VicConfirmationReport | null;
47
99
  /**
48
100
  * Which credential path actually ran: `mandate` = tap-free draw against an
49
- * existing card mandate; `fresh-tap` = today's 1:1 hosted-passkey mint; `null`
50
- * = neither ran (a pre-flight refusal, e.g. no prepared review). Transparency,
51
- * never magic — the caller can always see whether a passkey was skipped.
101
+ * existing card mandate; `null` = none ran (a pre-flight refusal, e.g. no
102
+ * prepared review or no covering mandate). Transparency, never magic — the
103
+ * caller can always see whether a passkey was skipped.
52
104
  */
53
- source: 'mandate' | 'fresh-tap' | null;
105
+ source: 'mandate' | null;
54
106
  /** Remaining mandate budget (minor units) after a mandate draw; else null. */
55
107
  remainingMinor: number | null;
108
+ /**
109
+ * Immutable VIC/VGS intent used for server-side receipt correlation. This is
110
+ * an opaque non-credential identifier; it never carries the mint/verdict
111
+ * bearer that authorizes a cryptogram or confirmation. Present only after a
112
+ * card confirmation target exists.
113
+ */
114
+ processorIntentId?: string | null;
115
+ /** True only when the checkout engine recorded a credential-minted step. */
116
+ credentialIssued: boolean;
117
+ /** True only when at least one payment field was successfully filled. */
118
+ credentialDisclosed: boolean;
119
+ /** Privacy-safe local receipt persistence outcome for centralized correlation. */
120
+ receiptWrite?: ReceiptWriteObservation;
121
+ };
122
+ type PayAttempt = {
123
+ fingerprint: string;
124
+ promise: Promise<CliReceiptFacts>;
56
125
  };
57
126
  export type CliStartMandateInput = {
58
- /** The merchant URL for a merchant-scoped mandate. Optional (and ignored) when
59
- * `anyMerchant` is set — a budget mandate is not tied to a merchant. */
60
- url?: string;
127
+ /** Optional local card-capability selector (legacy name or exact request-key JKT). */
128
+ agentRef?: string;
61
129
  ceiling: string;
62
130
  currency: string;
63
131
  credentialPath: string;
132
+ /** See {@link CardInstrumentSource}. */
133
+ cardTokenId?: string;
64
134
  contact: Contact;
65
135
  approvalBaseUrl: string;
66
- merchantName?: string;
67
- merchantCountryCode?: string;
68
- /** ISO 8601 mandate expiry; defaults to now + 24h. */
69
- expiresAt?: string;
70
- /** Max draws the ceiling intent may fulfil. */
71
- maxDraws?: number;
72
136
  /**
73
137
  * Per-purchase cap (decimal string, > 0 and <= ceiling). Registered with the
74
138
  * approval context so the operator reads it as a worst-case term, and carried
@@ -81,11 +145,33 @@ export type CliStartMandateInput = {
81
145
  */
82
146
  intent?: string;
83
147
  /**
84
- * BUDGET mode: create a mandate spendable at ANY merchant (no merchant lock),
85
- * bounded by the ceiling + per-transaction limit. The passkey approval shows
86
- * "spend budget mandate" so the owner consents to the broader scope.
148
+ * Per-call relay of the hosted-approval URL, the moment it is known and
149
+ * BEFORE the (up-to-timeout) wait. Takes precedence over the engine-level
150
+ * `deps.onApprovalUrl`.
151
+ *
152
+ * The engine seam was deps-only, and the MCP surface builds its engine once
153
+ * per process without it — so `start_card_mandate` produced an approval URL,
154
+ * printed it to stderr, and blocked the agent's turn for minutes with no way
155
+ * to tell the human what to open. A per-call hook lets one caller relay the
156
+ * URL without every caller sharing one engine-wide callback.
87
157
  */
88
- anyMerchant?: boolean;
158
+ onApprovalUrl?: (url: string) => void;
159
+ };
160
+ export type CliClaimMandateInput = {
161
+ /** Optional local card-capability selector (legacy name or exact request-key JKT). */
162
+ agentRef?: string;
163
+ /** Single-use pickup code the owner handed over from the panel. */
164
+ pickupCode: string;
165
+ /**
166
+ * The agent handoff this runtime just redeemed, when the pickup code rode
167
+ * inside its claim code. A dialog-minted budget pins that handoff instead of
168
+ * a key — there was no key yet — so this is what the pin is checked against.
169
+ */
170
+ expectedHandoffId?: string;
171
+ credentialPath: string;
172
+ /** See {@link CardInstrumentSource}. */
173
+ cardTokenId?: string;
174
+ approvalBaseUrl: string;
89
175
  };
90
176
  export type CliMandateFacts = CardMandateFacts & {
91
177
  merchantHost: string;
@@ -93,19 +179,49 @@ export type CliMandateFacts = CardMandateFacts & {
93
179
  * True when the mandate minted its ceiling intent but the #5942 register
94
180
  * handshake failed, so `findCovering` will SKIP it and no tap-free draw is
95
181
  * possible. The mandate exists but is not usable — the caller must surface
96
- * this (not report a plain success). Absent/false registered (or no
97
- * delegated binding was present, so register was intentionally not attempted).
182
+ * this (not report a plain success). Absent/false means registration succeeded;
183
+ * mandate-start now refuses before approval when no capability can register.
98
184
  */
99
185
  registerFailed?: boolean;
186
+ /**
187
+ * The server's refusal reason when {@link registerFailed} is true, verbatim.
188
+ * Carried out so the CLI can distinguish causes that need DIFFERENT operator
189
+ * actions — notably `token_mismatch`, which means the on-device grant record's
190
+ * cached token no longer matches the owner's live agentic token (they
191
+ * re-enrolled a card after the grant) and is fixed by re-running `grant-card`,
192
+ * not by retrying `mandate start`. Without the reason every failure reads as
193
+ * "the auth server was unreachable", which sends the operator in a loop.
194
+ */
195
+ registerFailureReason?: string;
100
196
  };
101
197
  type Session = {
102
198
  browser: Browser;
199
+ /** Exact caller URL repeated at pay time; may contain a UCP capability. */
200
+ requestUrl: string;
201
+ checkoutRoute: 'guest-card';
103
202
  target: VgsCheckoutTarget;
104
203
  amountMinor: number;
105
204
  currency: string;
106
205
  contact: Contact;
206
+ agentJkt?: string;
207
+ /** #8047: narrative for this review's journal, carried review -> pay. */
208
+ intentNarrative?: CardIntentNarrative;
107
209
  cleanupTimer: ReturnType<typeof setTimeout>;
108
210
  };
211
+ /**
212
+ * #8047 Transaction Intent Journal narrative — the agent-authored half of the
213
+ * journal. Structural mirror of the CLI card client's `CardIntentNarrative`;
214
+ * the engine only threads it through and never interprets it.
215
+ */
216
+ export interface CardIntentNarrative {
217
+ userRequest: string;
218
+ product: string;
219
+ purpose?: string;
220
+ quantity?: number;
221
+ expectedResult?: string;
222
+ recurring?: boolean;
223
+ userIntentSalt?: string;
224
+ }
109
225
  export interface CardDrawVerdictDraw {
110
226
  tokenId: string;
111
227
  amount: string;
@@ -117,32 +233,39 @@ export interface CardDrawVerdictDraw {
117
233
  export interface CardDrawVerdictCapability {
118
234
  /** Opaque to the engine — passed straight back to {@link CardDrawVerdictSeam.fetchVerdict}. */
119
235
  agentKey: unknown;
236
+ /** Root-signed delegation for a short-lived device key. */
237
+ runtimeCertificate?: string;
120
238
  agentJkt: string;
121
239
  /** Auth origin that minted the binding and hosts the /v4/card/draw* routes. */
122
240
  authBaseUrl: string;
123
241
  }
124
242
  export interface CardDrawVerdictSeam {
125
- loadCapability: () => CardDrawVerdictCapability | null;
243
+ loadCapability: (agentRef?: string) => CardDrawVerdictCapability | null;
126
244
  fetchVerdict: (input: {
127
245
  authBaseUrl: string;
128
246
  agentKey: unknown;
247
+ runtimeCertificate?: string;
129
248
  mandateId: string;
130
249
  drawId: string;
131
250
  draw: CardDrawVerdictDraw;
251
+ /** #8047: narrative the client turns into the draw's journal sidecar. */
252
+ intentNarrative?: CardIntentNarrative;
132
253
  }) => Promise<{
133
254
  verdict: string;
134
255
  remainingCents: number;
135
256
  }>;
136
257
  }
137
258
  export interface CardMandateRegisterSeam {
138
- loadCapability: () => {
259
+ loadCapability: (agentRef?: string) => {
139
260
  agentKey: unknown;
261
+ runtimeCertificate?: string;
140
262
  agentJkt: string;
141
263
  authBaseUrl: string;
142
264
  } | null;
143
265
  register: (input: {
144
266
  authBaseUrl: string;
145
267
  agentKey: unknown;
268
+ runtimeCertificate?: string;
146
269
  mandateId: string;
147
270
  mintToken: string;
148
271
  ceiling: string;
@@ -150,6 +273,12 @@ export interface CardMandateRegisterSeam {
150
273
  }) => Promise<{
151
274
  ok: boolean;
152
275
  reason?: string;
276
+ /**
277
+ * The ceiling the server committed — `min(requested, the owner's live card
278
+ * grant cap)`. Omitted by an older auth that does not report it, in which
279
+ * case the requested ceiling stands.
280
+ */
281
+ approvedCeilingMinor?: number;
153
282
  }>;
154
283
  }
155
284
  export type CliEngineDeps = {
@@ -157,6 +286,8 @@ export type CliEngineDeps = {
157
286
  prepareCheckout?: typeof realPrepareCheckout;
158
287
  submitApprovedCheckout?: typeof realSubmitApprovedCheckout;
159
288
  runHostedApproval?: typeof realRunHostedApproval;
289
+ /** Injectable pickup-code redeem for claimCardMandate — tests pass a fake. */
290
+ claimMandatePickup?: typeof realClaimMandatePickup;
160
291
  /**
161
292
  * Relay the hosted-approval URL to the caller as DATA the moment it is known,
162
293
  * before the (up-to-timeout) poll wait. A headless agent surface wires this to
@@ -166,8 +297,18 @@ export type CliEngineDeps = {
166
297
  onApprovalUrl?: (url: string) => void;
167
298
  reportVicOutcome?: typeof realReportVicOutcome;
168
299
  writeReceipt?: typeof realWriteReceipt;
300
+ /**
301
+ * Privacy-safe receipt persistence lifecycle signal. The event deliberately
302
+ * excludes the receipt body, checkout URL, filesystem path, and raw error.
303
+ * Observer failures are swallowed so logging can never alter checkout state.
304
+ */
305
+ onReceiptWrite?: (event: ReceiptWriteObservation) => void | Promise<void>;
306
+ /** Injectable privacy-safe id source for terminal observations before reviewId exists. */
307
+ createObservationId?: () => string;
169
308
  store?: PreparedCheckoutSessionStore;
170
309
  sessions?: Map<string, Session>;
310
+ /** Exact-review singleflight registry; tests inject a fresh map for isolation. */
311
+ payAttempts?: Map<string, PayAttempt>;
171
312
  ttlMs?: number;
172
313
  /** Owner-only card-mandate ledger — defaults to the ~/.visa-mcp singleton. */
173
314
  ledger?: MandateLedger;
@@ -179,24 +320,57 @@ export type CliEngineDeps = {
179
320
  * markUnhonored path with no network.
180
321
  */
181
322
  serverFetchCryptogram?: typeof serverFetchCryptogram;
323
+ /** Injectable confirmation transport; defaults to verify-web. */
324
+ serverPostConfirmation?: typeof serverPostConfirmation;
182
325
  /**
183
326
  * #5923 delegated card-draw verdict seam (see {@link CardDrawVerdictSeam}).
184
- * Injected by the CLI when the agent holds a mode='card' delegated binding;
185
- * when absent the covering-mandate draw keeps using the bearer mint token (the
186
- * shipped #5917 flow, unchanged).
327
+ * Injected by the CLI when the runtime holds separately provisioned card
328
+ * authority. When absent, a covering-mandate draw fails before cryptogram mint.
187
329
  */
188
330
  cardDrawVerdict?: CardDrawVerdictSeam;
189
331
  /**
190
332
  * #5942 delegated card-mandate register seam (see {@link CardMandateRegisterSeam}).
191
- * Injected by the CLI when the agent holds a mode='card' delegated binding;
192
- * when absent mandate-start skips the register (best-effort the bearer path
193
- * still works, only the delegated draw needs the register row).
333
+ * Required by mandate-start. When absent, the ceremony is refused before
334
+ * passkey approval because a budget token cannot act as draw authority.
194
335
  */
195
336
  cardMandateRegister?: CardMandateRegisterSeam;
337
+ /**
338
+ * Canonical mailbox OTP reader supplied by the runtime. The checkout engine
339
+ * owns no mailbox credential and never imports an email provider package.
340
+ */
341
+ resolveEmailOtp?: OtpResolver;
342
+ };
343
+ export type ReceiptWriteObservation = {
344
+ event: 'checkout_receipt_write';
345
+ status: 'written' | 'failed';
346
+ mode: CheckoutMode;
347
+ checkoutOutcome: CheckoutOutcome;
348
+ merchantHost: string;
349
+ observationId: string;
350
+ failureCode: string | null;
351
+ errorCode: string | null;
352
+ panRedactions: number | null;
196
353
  };
197
354
  export declare function createCliCheckoutEngine(deps?: CliEngineDeps): {
198
355
  startCardMandate(input: CliStartMandateInput): Promise<CliMandateFacts>;
356
+ claimCardMandate(input: CliClaimMandateInput): Promise<CliMandateFacts>;
199
357
  review(input: CliReviewInput): Promise<CliReviewFacts>;
358
+ /**
359
+ * Give up a prepared review without paying it (#7100).
360
+ *
361
+ * The retained browser is what lets a same-process MCP `review` → `pay`
362
+ * draw against the checkout it already inspected. A TERMINAL review-only
363
+ * run has no such second call — that process tells the operator to re-RUN
364
+ * with `--submit`, and the new process cannot reach this one's in-memory
365
+ * session. So the browser sat open for the full TTL, and because a live
366
+ * browser connection keeps the event loop alive, a command that had already
367
+ * succeeded looked hung until Ctrl-C.
368
+ *
369
+ * Idempotent and non-throwing: an unknown or already-released id is a
370
+ * no-op, so it is safe on an error path that may not have prepared anything
371
+ * and safe to call twice.
372
+ */
373
+ releaseReview(reviewId: string): Promise<void>;
200
374
  pay(input: CliPayInput): Promise<CliReceiptFacts>;
201
375
  };
202
376
  export {};