@inflowpayai/inflow 0.6.3 → 0.6.5

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 (3) hide show
  1. package/README.md +95 -22
  2. package/dist/cli.js +1122 -702
  3. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -8837,19 +8837,19 @@ var require_range = __commonJS({
8837
8837
  var replaceCaret = (comp, options) => {
8838
8838
  debug("caret", comp, options);
8839
8839
  const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET];
8840
- const z7 = options.includePrerelease ? "-0" : "";
8840
+ const z8 = options.includePrerelease ? "-0" : "";
8841
8841
  return comp.replace(r, (_, M, m, p, pr) => {
8842
8842
  debug("caret", comp, _, M, m, p, pr);
8843
8843
  let ret;
8844
8844
  if (isX(M)) {
8845
8845
  ret = "";
8846
8846
  } else if (isX(m)) {
8847
- ret = `>=${M}.0.0${z7} <${+M + 1}.0.0-0`;
8847
+ ret = `>=${M}.0.0${z8} <${+M + 1}.0.0-0`;
8848
8848
  } else if (isX(p)) {
8849
8849
  if (M === "0") {
8850
- ret = `>=${M}.${m}.0${z7} <${M}.${+m + 1}.0-0`;
8850
+ ret = `>=${M}.${m}.0${z8} <${M}.${+m + 1}.0-0`;
8851
8851
  } else {
8852
- ret = `>=${M}.${m}.0${z7} <${+M + 1}.0.0-0`;
8852
+ ret = `>=${M}.${m}.0${z8} <${+M + 1}.0.0-0`;
8853
8853
  }
8854
8854
  } else if (pr) {
8855
8855
  debug("replaceCaret pr", pr);
@@ -8866,9 +8866,9 @@ var require_range = __commonJS({
8866
8866
  debug("no pr");
8867
8867
  if (M === "0") {
8868
8868
  if (m === "0") {
8869
- ret = `>=${M}.${m}.${p}${z7} <${M}.${m}.${+p + 1}-0`;
8869
+ ret = `>=${M}.${m}.${p}${z8} <${M}.${m}.${+p + 1}-0`;
8870
8870
  } else {
8871
- ret = `>=${M}.${m}.${p}${z7} <${M}.${+m + 1}.0-0`;
8871
+ ret = `>=${M}.${m}.${p}${z8} <${M}.${+m + 1}.0-0`;
8872
8872
  }
8873
8873
  } else {
8874
8874
  ret = `>=${M}.${m}.${p} <${+M + 1}.0.0-0`;
@@ -11023,12 +11023,14 @@ function stripAnsi(string) {
11023
11023
  }
11024
11024
 
11025
11025
  // ../core/dist/index.js
11026
+ import { fromFoundationRequirements as fromFoundationRequirements2 } from "@inflowpayai/x402-buyer";
11027
+ import { sellerProbe as sellerProbe5 } from "@inflowpayai/x402-buyer/probe";
11026
11028
  import {
11027
11029
  describeBody as describeBody2,
11028
11030
  parseHeaderFlag,
11029
11031
  parseHeaderFlags,
11030
11032
  replayWithPayment as replayWithPayment2,
11031
- sellerProbe as sellerProbe5,
11033
+ sellerProbe as sellerProbe6,
11032
11034
  X402HeaderFlagFormatError
11033
11035
  } from "@inflowpayai/x402-buyer/probe";
11034
11036
  var REDACTED_BODY_FIELDS = /* @__PURE__ */ new Set([
@@ -11589,6 +11591,7 @@ function runAuthLogin(input) {
11589
11591
  input.authStorage.setAuth(outcome.value);
11590
11592
  input.authStorage.clearApiKey();
11591
11593
  input.authStorage.setConnection(input.connection);
11594
+ input.authStorage.clearPendingDeviceAuth();
11592
11595
  if (input.priorRefreshToken !== void 0) {
11593
11596
  input.authResource.revokeToken(input.priorRefreshToken).catch(() => {
11594
11597
  });
@@ -11730,6 +11733,15 @@ function buildNoFilteredMatchMessage(decoded, filters) {
11730
11733
  function isSuccessStatus(status) {
11731
11734
  return status >= 200 && status < 300;
11732
11735
  }
11736
+ function parseX402HeaderFromProbe(probe) {
11737
+ const headerValue = readHeader(Object.fromEntries(probe.headers.entries()), HEADERS.PAYMENT_REQUIRED);
11738
+ if (headerValue === void 0) return { kind: "absent" };
11739
+ try {
11740
+ return { kind: "parsed", decoded: decodePaymentRequiredHeader(headerValue) };
11741
+ } catch (err) {
11742
+ return { kind: "error", code: "DECODE_FAILED", message: err instanceof Error ? err.message : String(err) };
11743
+ }
11744
+ }
11733
11745
  function reduceX402Inspect(state, event) {
11734
11746
  switch (event.type) {
11735
11747
  case "accepts":
@@ -11774,8 +11786,8 @@ async function runInspectPipeline(deps, emit) {
11774
11786
  emit({ type: "no-payment", result: result2 });
11775
11787
  return;
11776
11788
  }
11777
- const headerValue = readHeader(Object.fromEntries(probe.headers.entries()), HEADERS.PAYMENT_REQUIRED);
11778
- if (headerValue === void 0) {
11789
+ const parse = parseX402HeaderFromProbe(probe);
11790
+ if (parse.kind === "absent") {
11779
11791
  emit({
11780
11792
  type: "errored",
11781
11793
  code: INVALID_402_CODE,
@@ -11783,17 +11795,11 @@ async function runInspectPipeline(deps, emit) {
11783
11795
  });
11784
11796
  return;
11785
11797
  }
11786
- let decoded;
11787
- try {
11788
- decoded = decodePaymentRequiredHeader(headerValue);
11789
- } catch (err) {
11790
- emit({
11791
- type: "errored",
11792
- code: "DECODE_FAILED",
11793
- message: err instanceof Error ? err.message : String(err)
11794
- });
11798
+ if (parse.kind === "error") {
11799
+ emit({ type: "errored", code: parse.code, message: parse.message });
11795
11800
  return;
11796
11801
  }
11802
+ const decoded = parse.decoded;
11797
11803
  const filters = {
11798
11804
  ...deps.schemeFilter !== void 0 ? { scheme: deps.schemeFilter } : {},
11799
11805
  ...deps.networkFilter !== void 0 ? { network: deps.networkFilter } : {},
@@ -12307,6 +12313,15 @@ function buildNoFilteredMatchMessage2(challenges, filters) {
12307
12313
  }).join(", ");
12308
12314
  return `Seller has no \`inflow\` challenge matching ${filterDescription}. Available: ${available || "(none)"}.`;
12309
12315
  }
12316
+ function parseMppHeaderFromProbe(probe) {
12317
+ const headerValues = readHeaderAll(probe.headers, HEADERS3.WWW_AUTHENTICATE);
12318
+ if (headerValues.length === 0) return { kind: "absent" };
12319
+ try {
12320
+ return { kind: "parsed", challenges: parseChallengeHeaders(headerValues) };
12321
+ } catch (err) {
12322
+ return { kind: "error", code: "DECODE_FAILED", message: err instanceof Error ? err.message : String(err) };
12323
+ }
12324
+ }
12310
12325
  function reduceMppInspect(state, event) {
12311
12326
  switch (event.type) {
12312
12327
  case "challenges":
@@ -12349,8 +12364,8 @@ async function runMppInspectPipeline(deps, emit) {
12349
12364
  });
12350
12365
  return;
12351
12366
  }
12352
- const headerValues = readHeaderAll(probe.headers, HEADERS3.WWW_AUTHENTICATE);
12353
- if (headerValues.length === 0) {
12367
+ const parse = parseMppHeaderFromProbe(probe);
12368
+ if (parse.kind === "absent") {
12354
12369
  emit({
12355
12370
  type: "errored",
12356
12371
  code: INVALID_402_CODE2,
@@ -12358,14 +12373,11 @@ async function runMppInspectPipeline(deps, emit) {
12358
12373
  });
12359
12374
  return;
12360
12375
  }
12361
- let challenges;
12362
- try {
12363
- challenges = parseChallengeHeaders(headerValues);
12364
- } catch (err) {
12365
- emit({ type: "errored", code: "DECODE_FAILED", message: err instanceof Error ? err.message : String(err) });
12376
+ if (parse.kind === "error") {
12377
+ emit({ type: "errored", code: parse.code, message: parse.message });
12366
12378
  return;
12367
12379
  }
12368
- const inflowChallenges = filterInflowChallenges(challenges);
12380
+ const inflowChallenges = filterInflowChallenges(parse.challenges);
12369
12381
  if (inflowChallenges.length === 0) {
12370
12382
  emit({ type: "errored", code: NO_INFLOW_MATCH_CODE2, message: NO_INFLOW_MATCH_MESSAGE2 });
12371
12383
  return;
@@ -12853,7 +12865,7 @@ function augmentMpp(mppResource, resolvedApiBaseUrl2) {
12853
12865
  var DEFAULT_RETRIES = 3;
12854
12866
  var DEFAULT_TIMEOUT_MS = 3e4;
12855
12867
  var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([429, 502, 503, 504]);
12856
- var SDK_USER_AGENT = `@inflowpayai/inflow-core/${true ? "0.6.1" : "0.0.0"}`;
12868
+ var SDK_USER_AGENT = `@inflowpayai/inflow-core/${true ? "0.6.2" : "0.0.0"}`;
12857
12869
  function sleep2(ms, signal) {
12858
12870
  return new Promise((resolve, reject) => {
12859
12871
  const onAbort = () => {
@@ -13495,6 +13507,85 @@ async function probeSession(userResource, options) {
13495
13507
  function hasSession(storage2, hasApiKey) {
13496
13508
  return hasApiKey() || storage2.isAuthenticated();
13497
13509
  }
13510
+ function reduceCombinedInspect(state, event) {
13511
+ switch (event.type) {
13512
+ case "inspected":
13513
+ return { kind: "inspected", result: event.result };
13514
+ case "no-payment":
13515
+ return { kind: "no-payment", result: event.result };
13516
+ case "errored":
13517
+ return { kind: "error", code: event.code, message: event.message };
13518
+ default:
13519
+ return state;
13520
+ }
13521
+ }
13522
+ function buildMppSection(probe) {
13523
+ const parse = parseMppHeaderFromProbe(probe);
13524
+ if (parse.kind === "absent") return { kind: "absent" };
13525
+ if (parse.kind === "error") return { kind: "error", code: parse.code, message: parse.message };
13526
+ const inflowChallenges = filterInflowChallenges(parse.challenges);
13527
+ if (inflowChallenges.length === 0) {
13528
+ const methods = [...new Set(parse.challenges.map((c) => c.method))].sort((a, b) => a.localeCompare(b));
13529
+ return { kind: "none-inflow", methods };
13530
+ }
13531
+ const realm = inflowChallenges[0]?.realm ?? "";
13532
+ return { kind: "challenges", realm, challenges: inflowChallenges.map(summarizeChallenge) };
13533
+ }
13534
+ function buildX402Section(probe) {
13535
+ const parse = parseX402HeaderFromProbe(probe);
13536
+ if (parse.kind === "absent") return { kind: "absent" };
13537
+ if (parse.kind === "error") return { kind: "error", code: parse.code, message: parse.message };
13538
+ const decoded = parse.decoded;
13539
+ return {
13540
+ kind: "accepts",
13541
+ resource: decoded.resource.url,
13542
+ x402Version: decoded.x402Version,
13543
+ accepts: fromFoundationRequirements2(decoded.accepts),
13544
+ ...decoded.extensions !== void 0 ? { extensions: decoded.extensions } : {}
13545
+ };
13546
+ }
13547
+ async function runCombinedInspectPipeline(deps, emit) {
13548
+ let probe;
13549
+ try {
13550
+ probe = await sellerProbe5(deps.url, deps.probeOptions);
13551
+ } catch (err) {
13552
+ emit({ type: "errored", code: "INSPECT_FAILED", message: err instanceof Error ? err.message : String(err) });
13553
+ return;
13554
+ }
13555
+ if (probe.status !== 402) {
13556
+ if (!isSuccessStatus(probe.status)) {
13557
+ emit({
13558
+ type: "errored",
13559
+ code: UNEXPECTED_PROBE_STATUS_CODE,
13560
+ message: `Seller returned status ${String(probe.status)} during probe; expected 2xx (no payment) or 402 (payment required).`
13561
+ });
13562
+ return;
13563
+ }
13564
+ emit({
13565
+ type: "no-payment",
13566
+ result: {
13567
+ outcome: "no-payment-required",
13568
+ url: deps.url,
13569
+ method: deps.probeOptions.method,
13570
+ status: probe.status,
13571
+ contentType: probe.contentType,
13572
+ bodySizeBytes: probe.bytes.byteLength
13573
+ }
13574
+ });
13575
+ return;
13576
+ }
13577
+ emit({
13578
+ type: "inspected",
13579
+ result: {
13580
+ outcome: "inspected",
13581
+ url: deps.url,
13582
+ method: deps.probeOptions.method,
13583
+ status: probe.status,
13584
+ mpp: buildMppSection(probe),
13585
+ x402: buildX402Section(probe)
13586
+ }
13587
+ });
13588
+ }
13498
13589
  async function runBalancesList(input) {
13499
13590
  return input.balanceResource.list();
13500
13591
  }
@@ -14575,94 +14666,11 @@ function createDepositAddressesCli(depositAddressResource, authStorage2, inflow2
14575
14666
  return cli2;
14576
14667
  }
14577
14668
 
14578
- // src/commands/mpp/index.tsx
14579
- import { chmodSync, writeFileSync as writeFileSync2 } from "fs";
14580
- import { resolve as resolvePath2 } from "path";
14581
- import { Cli as Cli4 } from "incur";
14582
-
14583
- // src/commands/mpp/cancel.tsx
14669
+ // src/commands/mpp/inspect.tsx
14584
14670
  import { Box as Box9, Text as Text10 } from "ink";
14585
14671
  import Spinner7 from "ink-spinner";
14586
- import { useCallback as useCallback5 } from "react";
14587
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
14588
- var CancelView = ({ approvalId, cancel, onComplete }) => {
14589
- const action = useCallback5(() => cancel(), [cancel]);
14590
- const { finish } = useFlowExit(onComplete);
14591
- const { status } = useFlowState(action, finish);
14592
- if (status === "loading") {
14593
- return /* @__PURE__ */ jsx12(Box9, { children: /* @__PURE__ */ jsxs9(Text10, { color: "cyan", children: [
14594
- /* @__PURE__ */ jsx12(Spinner7, { type: "dots" }),
14595
- " Cancelling approval ",
14596
- approvalId,
14597
- "..."
14598
- ] }) });
14599
- }
14600
- return /* @__PURE__ */ jsx12(Box9, { children: /* @__PURE__ */ jsxs9(Text10, { color: "green", children: [
14601
- "\u2713 Cancelled approval ",
14602
- approvalId,
14603
- " (best-effort)"
14604
- ] }) });
14605
- };
14606
-
14607
- // src/commands/mpp/decode.tsx
14608
- import { Box as Box10, Text as Text11 } from "ink";
14609
- import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
14610
- function ChallengeBody({ challenge }) {
14611
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [
14612
- /* @__PURE__ */ jsx13(Text11, { bold: true, children: "Challenge" }),
14613
- /* @__PURE__ */ jsxs10(Text11, { children: [
14614
- "method/intent: ",
14615
- /* @__PURE__ */ jsxs10(Text11, { color: "yellow", children: [
14616
- challenge.method,
14617
- " / ",
14618
- challenge.intent
14619
- ] })
14620
- ] }),
14621
- /* @__PURE__ */ jsx13(Text11, { children: `id: ${challenge.id}` }),
14622
- /* @__PURE__ */ jsx13(Text11, { children: `realm: ${challenge.realm}` }),
14623
- challenge.amount !== void 0 ? /* @__PURE__ */ jsx13(Text11, { children: `amount: ${challenge.amount}${challenge.currency !== void 0 ? ` ${challenge.currency}` : ""}` }) : null,
14624
- challenge.rail !== void 0 ? /* @__PURE__ */ jsx13(Text11, { children: `rail: ${challenge.rail}` }) : null,
14625
- challenge.expires !== void 0 ? /* @__PURE__ */ jsx13(Text11, { dimColor: true, children: `expires: ${challenge.expires}` }) : null
14626
- ] });
14627
- }
14628
- var DecodeView = ({ result }) => {
14629
- if (result.kind === "challenge") {
14630
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", paddingY: 1, children: [
14631
- /* @__PURE__ */ jsx13(Box10, { marginBottom: 1, children: /* @__PURE__ */ jsx13(Text11, { bold: true, children: "Decoded WWW-Authenticate: Payment" }) }),
14632
- /* @__PURE__ */ jsx13(ChallengeBody, { challenge: result.challenge })
14633
- ] });
14634
- }
14635
- if (result.kind === "credential") {
14636
- const { credential } = result;
14637
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", paddingY: 1, children: [
14638
- /* @__PURE__ */ jsx13(Box10, { marginBottom: 1, children: /* @__PURE__ */ jsx13(Text11, { bold: true, children: "Decoded Authorization: Payment credential" }) }),
14639
- /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [
14640
- /* @__PURE__ */ jsx13(Text11, { children: `challenge id: ${credential.challenge.id}` }),
14641
- /* @__PURE__ */ jsx13(Text11, { children: `method: ${credential.challenge.method}` }),
14642
- /* @__PURE__ */ jsx13(Text11, { children: `source: ${credential.source}` }),
14643
- /* @__PURE__ */ jsx13(Text11, { dimColor: true, children: `payload keys: ${Object.keys(credential.payload).join(", ") || "(none)"}` })
14644
- ] })
14645
- ] });
14646
- }
14647
- const { receipt } = result;
14648
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", paddingY: 1, children: [
14649
- /* @__PURE__ */ jsx13(Box10, { marginBottom: 1, children: /* @__PURE__ */ jsx13(Text11, { bold: true, children: "Decoded Payment-Receipt" }) }),
14650
- /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [
14651
- /* @__PURE__ */ jsxs10(Text11, { children: [
14652
- "status: ",
14653
- /* @__PURE__ */ jsx13(Text11, { color: "green", children: receipt.status })
14654
- ] }),
14655
- /* @__PURE__ */ jsx13(Text11, { children: `reference: ${receipt.reference}` }),
14656
- /* @__PURE__ */ jsx13(Text11, { dimColor: true, children: `timestamp: ${receipt.timestamp}` })
14657
- ] })
14658
- ] });
14659
- };
14660
-
14661
- // src/commands/mpp/inspect.tsx
14662
- import { Box as Box11, Text as Text12 } from "ink";
14663
- import Spinner8 from "ink-spinner";
14664
14672
  import { useEffect as useEffect6, useReducer as useReducer4 } from "react";
14665
- import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
14673
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
14666
14674
  function orDash(value) {
14667
14675
  return value === void 0 || value === "" ? "\u2014" : value;
14668
14676
  }
@@ -14693,8 +14701,8 @@ var InspectView = ({ url, method, deps, onComplete }) => {
14693
14701
  }
14694
14702
  }, [phase, finish]);
14695
14703
  if (phase.kind === "probing") {
14696
- return /* @__PURE__ */ jsx14(Box11, { children: /* @__PURE__ */ jsxs11(Text12, { color: "cyan", children: [
14697
- /* @__PURE__ */ jsx14(Spinner8, { type: "dots" }),
14704
+ return /* @__PURE__ */ jsx12(Box9, { children: /* @__PURE__ */ jsxs9(Text10, { color: "cyan", children: [
14705
+ /* @__PURE__ */ jsx12(Spinner7, { type: "dots" }),
14698
14706
  " Probing ",
14699
14707
  method,
14700
14708
  " ",
@@ -14704,37 +14712,37 @@ var InspectView = ({ url, method, deps, onComplete }) => {
14704
14712
  }
14705
14713
  if (phase.kind === "no-payment") {
14706
14714
  const { result: result2 } = phase;
14707
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
14708
- /* @__PURE__ */ jsx14(Text12, { color: "green", children: "\u2713 Seller accepted without payment" }),
14709
- /* @__PURE__ */ jsx14(Text12, { children: `status: ${String(result2.status)}` }),
14710
- result2.contentType !== void 0 ? /* @__PURE__ */ jsx14(Text12, { children: `content-type: ${result2.contentType}` }) : null,
14711
- /* @__PURE__ */ jsx14(Text12, { children: `response size: ${String(result2.bodySizeBytes)} bytes` }),
14712
- /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: "Use `mpp pay` to fetch the body." })
14715
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
14716
+ /* @__PURE__ */ jsx12(Text10, { color: "green", children: "\u2713 Seller accepted without payment" }),
14717
+ /* @__PURE__ */ jsx12(Text10, { children: `status: ${String(result2.status)}` }),
14718
+ result2.contentType !== void 0 ? /* @__PURE__ */ jsx12(Text10, { children: `content-type: ${result2.contentType}` }) : null,
14719
+ /* @__PURE__ */ jsx12(Text10, { children: `response size: ${String(result2.bodySizeBytes)} bytes` }),
14720
+ /* @__PURE__ */ jsx12(Text10, { dimColor: true, children: "Use `mpp pay` to fetch the body." })
14713
14721
  ] });
14714
14722
  }
14715
14723
  if (phase.kind === "error") {
14716
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
14717
- /* @__PURE__ */ jsxs11(Text12, { color: "red", children: [
14724
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
14725
+ /* @__PURE__ */ jsxs9(Text10, { color: "red", children: [
14718
14726
  "\u2717 ",
14719
14727
  phase.code
14720
14728
  ] }),
14721
- /* @__PURE__ */ jsx14(Text12, { color: "red", children: phase.message })
14729
+ /* @__PURE__ */ jsx12(Text10, { color: "red", children: phase.message })
14722
14730
  ] });
14723
14731
  }
14724
14732
  const { result } = phase;
14725
14733
  const count = result.challenges.length;
14726
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
14727
- /* @__PURE__ */ jsxs11(Text12, { children: [
14728
- /* @__PURE__ */ jsx14(Text12, { bold: true, children: "WWW-Authenticate: Payment" }),
14734
+ return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
14735
+ /* @__PURE__ */ jsxs9(Text10, { children: [
14736
+ /* @__PURE__ */ jsx12(Text10, { bold: true, children: "WWW-Authenticate: Payment" }),
14729
14737
  " for ",
14730
- /* @__PURE__ */ jsx14(Text12, { color: "cyan", children: result.url }),
14738
+ /* @__PURE__ */ jsx12(Text10, { color: "cyan", children: result.url }),
14731
14739
  " \xB7 ",
14732
- /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: `realm ${result.realm}` }),
14740
+ /* @__PURE__ */ jsx12(Text10, { dimColor: true, children: `realm ${result.realm}` }),
14733
14741
  " \xB7 ",
14734
- /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: `${String(count)} challenge${count === 1 ? "" : "s"}` })
14742
+ /* @__PURE__ */ jsx12(Text10, { dimColor: true, children: `${String(count)} challenge${count === 1 ? "" : "s"}` })
14735
14743
  ] }),
14736
- /* @__PURE__ */ jsx14(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx14(Table, { columns: COLUMNS3, rows: [...result.challenges] }) }),
14737
- /* @__PURE__ */ jsx14(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: "Use --format json to see challenge ids and digests." }) })
14744
+ /* @__PURE__ */ jsx12(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx12(Table, { columns: COLUMNS3, rows: [...result.challenges] }) }),
14745
+ /* @__PURE__ */ jsx12(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text10, { dimColor: true, children: "Use --format json to see challenge ids and digests." }) })
14738
14746
  ] });
14739
14747
  };
14740
14748
  function challengeToFrame(challenge) {
@@ -14775,63 +14783,53 @@ function buildNoPaymentFrame(result) {
14775
14783
  return frame;
14776
14784
  }
14777
14785
 
14778
- // src/commands/mpp/pay.tsx
14779
- import { Box as Box12, Text as Text13, useInput as useInput3 } from "ink";
14780
- import Spinner9 from "ink-spinner";
14781
- import { useEffect as useEffect7, useReducer as useReducer5, useState as useState3 } from "react";
14782
- import { Fragment, jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
14783
- var PayView = ({ url, method, deps, onComplete, onCancel }) => {
14786
+ // src/commands/x402/inspect.tsx
14787
+ import { Box as Box10, Text as Text11 } from "ink";
14788
+ import Spinner8 from "ink-spinner";
14789
+ import { useEffect as useEffect7, useReducer as useReducer5 } from "react";
14790
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
14791
+ function summarizeExtra(extra) {
14792
+ if (extra === void 0) return "\u2014";
14793
+ const keys = Object.keys(extra);
14794
+ if (keys.length === 0) return "\u2014";
14795
+ return [...keys].sort((a, b) => a.localeCompare(b)).join(", ");
14796
+ }
14797
+ function formatTimeout(seconds) {
14798
+ return `${String(seconds)}s`;
14799
+ }
14800
+ function formatAsset(asset) {
14801
+ return asset === "" ? "\u2014" : asset;
14802
+ }
14803
+ var COLUMNS4 = [
14804
+ { header: "Scheme", cell: (r) => r.scheme },
14805
+ { header: "Network", cell: (r) => r.network },
14806
+ { header: "Amount", cell: (r) => r.amount },
14807
+ { header: "Asset", cell: (r) => formatAsset(r.asset) },
14808
+ { header: "Pay To", cell: (r) => r.payTo },
14809
+ { header: "Timeout", cell: (r) => formatTimeout(r.maxTimeoutSeconds) },
14810
+ { header: "Extra", cell: (r) => summarizeExtra(r.extra) }
14811
+ ];
14812
+ var InspectView2 = ({ url, method, deps, onComplete }) => {
14784
14813
  const initial = { kind: "probing" };
14785
- const [phase, dispatch] = useReducer5(reduceMppPay, initial);
14786
- const [cancelling, setCancelling] = useState3(false);
14787
- const { finish, cancelThenFinish } = useFlowExit(onComplete);
14788
- const created = phase.kind === "created" ? phase.created : void 0;
14789
- const approvalUrl = created?.approvalUrl;
14790
- const approvalId = created?.approvalId;
14791
- useInput3(
14792
- (_input, key) => {
14793
- if (approvalUrl === void 0) return;
14794
- if (key.return) {
14795
- openUrl(approvalUrl);
14796
- return;
14797
- }
14798
- if (key.escape && approvalId !== void 0) {
14799
- setCancelling(true);
14800
- cancelThenFinish(() => onCancel?.(approvalId), {
14801
- kind: "error",
14802
- code: "APPROVAL_CANCELLED",
14803
- message: `Approval ${approvalId} cancelled.`
14804
- });
14805
- }
14806
- },
14807
- { isActive: approvalUrl !== void 0 && !cancelling }
14808
- );
14814
+ const [phase, dispatch] = useReducer5(reduceX402Inspect, initial);
14815
+ const { finish } = useFlowExit(onComplete);
14809
14816
  useEffect7(() => {
14810
- const controller = new AbortController();
14811
14817
  let cancelled = false;
14812
- const runDeps = { ...deps, signal: controller.signal };
14813
- void runMppPayPipeline(runDeps, (event) => {
14818
+ void runInspectPipeline(deps, (event) => {
14814
14819
  if (!cancelled) dispatch(event);
14815
14820
  });
14816
14821
  return () => {
14817
14822
  cancelled = true;
14818
- controller.abort();
14819
14823
  };
14820
14824
  }, [deps]);
14821
14825
  useEffect7(() => {
14822
- if (phase.kind === "success" || phase.kind === "seller-rejected" || phase.kind === "no-payment-final" || phase.kind === "error") {
14826
+ if (phase.kind === "accepts" || phase.kind === "no-payment" || phase.kind === "error") {
14823
14827
  finish(phase);
14824
14828
  }
14825
14829
  }, [phase, finish]);
14826
- if (cancelling) {
14827
- return /* @__PURE__ */ jsx15(Box12, { children: /* @__PURE__ */ jsxs12(Text13, { color: "yellow", children: [
14828
- /* @__PURE__ */ jsx15(Spinner9, { type: "dots" }),
14829
- " Cancelling approval..."
14830
- ] }) });
14831
- }
14832
14830
  if (phase.kind === "probing") {
14833
- return /* @__PURE__ */ jsx15(Box12, { children: /* @__PURE__ */ jsxs12(Text13, { color: "cyan", children: [
14834
- /* @__PURE__ */ jsx15(Spinner9, { type: "dots" }),
14831
+ return /* @__PURE__ */ jsx13(Box10, { children: /* @__PURE__ */ jsxs10(Text11, { color: "cyan", children: [
14832
+ /* @__PURE__ */ jsx13(Spinner8, { type: "dots" }),
14835
14833
  " Probing ",
14836
14834
  method,
14837
14835
  " ",
@@ -14840,193 +14838,720 @@ var PayView = ({ url, method, deps, onComplete, onCancel }) => {
14840
14838
  ] }) });
14841
14839
  }
14842
14840
  if (phase.kind === "no-payment") {
14843
- return /* @__PURE__ */ jsx15(Box12, { children: /* @__PURE__ */ jsxs12(Text13, { color: "cyan", children: [
14844
- /* @__PURE__ */ jsx15(Spinner9, { type: "dots" }),
14845
- " Seller accepted without payment (status ",
14846
- String(phase.probe.status),
14847
- "); finalising..."
14848
- ] }) });
14849
- }
14850
- if (phase.kind === "decoded") {
14851
- return /* @__PURE__ */ jsx15(Box12, { children: /* @__PURE__ */ jsxs12(Text13, { color: "cyan", children: [
14852
- /* @__PURE__ */ jsx15(Spinner9, { type: "dots" }),
14853
- " Fulfilling ",
14854
- phase.challenge.amount ?? "",
14855
- " ",
14856
- phase.challenge.currency ?? "",
14857
- " ",
14858
- "challenge..."
14859
- ] }) });
14841
+ return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
14842
+ /* @__PURE__ */ jsx13(Text11, { color: "green", children: "\u2713 Seller accepted without payment" }),
14843
+ /* @__PURE__ */ jsx13(Text11, { dimColor: true, children: "Use `x402 pay` to fetch the body." })
14844
+ ] });
14860
14845
  }
14861
- if (phase.kind === "created") {
14862
- const { created: created2 } = phase;
14863
- if (created2.state !== "pending") {
14864
- return /* @__PURE__ */ jsx15(Box12, { children: /* @__PURE__ */ jsxs12(Text13, { color: "cyan", children: [
14865
- /* @__PURE__ */ jsx15(Spinner9, { type: "dots" }),
14866
- " Transaction ",
14867
- created2.transactionId,
14868
- " ready; replaying..."
14869
- ] }) });
14870
- }
14871
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingY: 1, children: [
14872
- /* @__PURE__ */ jsx15(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsx15(Text13, { bold: true, children: "Approval required" }) }),
14873
- /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [
14874
- /* @__PURE__ */ jsx15(Text13, { children: `transaction: ${created2.transactionId}` }),
14875
- created2.approvalUrl !== void 0 ? /* @__PURE__ */ jsxs12(Fragment, { children: [
14876
- /* @__PURE__ */ jsxs12(Text13, { children: [
14877
- "Open: ",
14878
- /* @__PURE__ */ jsx15(Text13, { bold: true, color: "cyan", children: created2.approvalUrl })
14879
- ] }),
14880
- /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "Press Enter to open in browser." }),
14881
- /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "Press Escape to cancel." })
14882
- ] }) : null
14846
+ if (phase.kind === "error") {
14847
+ return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
14848
+ /* @__PURE__ */ jsxs10(Text11, { color: "red", children: [
14849
+ "\u2717 ",
14850
+ phase.code
14883
14851
  ] }),
14884
- /* @__PURE__ */ jsx15(Box12, { marginTop: 1, children: /* @__PURE__ */ jsxs12(Text13, { color: "cyan", children: [
14885
- /* @__PURE__ */ jsx15(Spinner9, { type: "dots" }),
14886
- " Waiting for approval..."
14887
- ] }) })
14852
+ /* @__PURE__ */ jsx13(Text11, { color: "red", children: phase.message })
14888
14853
  ] });
14889
14854
  }
14890
- if (phase.kind === "replaying") {
14891
- return /* @__PURE__ */ jsx15(Box12, { children: /* @__PURE__ */ jsxs12(Text13, { color: "cyan", children: [
14892
- /* @__PURE__ */ jsx15(Spinner9, { type: "dots" }),
14893
- " Replaying request with Authorization: Payment..."
14894
- ] }) });
14895
- }
14896
- if (phase.kind === "success") {
14897
- const { result } = phase;
14898
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
14899
- /* @__PURE__ */ jsxs12(Text13, { color: "green", children: [
14900
- "\u2713 Paid (intent ",
14901
- result.intent,
14902
- ")"
14855
+ const { result } = phase;
14856
+ const acceptsCount = result.accepts.length;
14857
+ const extensionsLine = result.extensions !== void 0 ? Object.keys(result.extensions).join(", ") : null;
14858
+ return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", children: [
14859
+ /* @__PURE__ */ jsxs10(Text11, { children: [
14860
+ /* @__PURE__ */ jsx13(Text11, { bold: true, children: "PAYMENT-REQUIRED" }),
14861
+ " for ",
14862
+ /* @__PURE__ */ jsx13(Text11, { color: "cyan", children: result.resource }),
14863
+ " \xB7 ",
14864
+ /* @__PURE__ */ jsx13(Text11, { dimColor: true, children: `x402Version ${String(result.x402Version)}` }),
14865
+ " \xB7 ",
14866
+ /* @__PURE__ */ jsx13(Text11, { dimColor: true, children: `${String(acceptsCount)} accept${acceptsCount === 1 ? "" : "s"}` })
14867
+ ] }),
14868
+ extensionsLine !== null ? /* @__PURE__ */ jsx13(Text11, { dimColor: true, children: `extensions: ${extensionsLine}` }) : null,
14869
+ /* @__PURE__ */ jsx13(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx13(Table, { columns: COLUMNS4, rows: result.accepts }) }),
14870
+ /* @__PURE__ */ jsx13(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text11, { dimColor: true, children: "Use --format json to inspect extras values." }) })
14871
+ ] });
14872
+ };
14873
+ function acceptToFrame(entry) {
14874
+ const row = {
14875
+ scheme: entry.scheme,
14876
+ network: entry.network,
14877
+ amount: entry.amount,
14878
+ asset: entry.asset,
14879
+ pay_to: entry.payTo,
14880
+ max_timeout_seconds: entry.maxTimeoutSeconds
14881
+ };
14882
+ if (entry.extra !== void 0) row.extra = entry.extra;
14883
+ return row;
14884
+ }
14885
+ function buildAcceptsFrame(result) {
14886
+ const frame = {
14887
+ outcome: "accepts",
14888
+ url: result.url,
14889
+ method: result.method,
14890
+ resource: result.resource,
14891
+ x402_version: result.x402Version,
14892
+ accepts: result.accepts.map(acceptToFrame)
14893
+ };
14894
+ if (result.extensions !== void 0) frame.extensions = result.extensions;
14895
+ return frame;
14896
+ }
14897
+ function buildNoPaymentFrame2(result) {
14898
+ const frame = {
14899
+ outcome: "no-payment-required",
14900
+ url: result.url,
14901
+ method: result.method,
14902
+ status: result.status,
14903
+ body_size_bytes: result.bodySizeBytes
14904
+ };
14905
+ if (result.contentType !== void 0) frame.content_type = result.contentType;
14906
+ return frame;
14907
+ }
14908
+
14909
+ // src/commands/inspect/combined-inspect-view.tsx
14910
+ import { Box as Box11, Text as Text12 } from "ink";
14911
+ import Spinner9 from "ink-spinner";
14912
+ import { useEffect as useEffect8, useReducer as useReducer6 } from "react";
14913
+ import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
14914
+ function orDash2(value) {
14915
+ return value === void 0 || value === "" ? "\u2014" : value;
14916
+ }
14917
+ var MPP_TRIAGE_COLUMNS = [
14918
+ { header: "Method", cell: (c) => c.method },
14919
+ { header: "Intent", cell: (c) => c.intent },
14920
+ { header: "Amount", cell: (c) => orDash2(c.amount) },
14921
+ { header: "Currency", cell: (c) => orDash2(c.currency) },
14922
+ { header: "Rail", cell: (c) => orDash2(c.rail) }
14923
+ ];
14924
+ var X402_TRIAGE_COLUMNS = [
14925
+ { header: "Scheme", cell: (r) => r.scheme },
14926
+ { header: "Network", cell: (r) => r.network },
14927
+ { header: "Amount", cell: (r) => r.amount },
14928
+ { header: "Asset", cell: (r) => orDash2(r.asset) }
14929
+ ];
14930
+ function detectedProtocols(mpp, x402) {
14931
+ const out = [];
14932
+ if (mpp.kind === "challenges" && mpp.challenges.length > 0) out.push("mpp");
14933
+ if (x402.kind === "accepts" && x402.accepts.length > 0) out.push("x402");
14934
+ return out;
14935
+ }
14936
+ var MppSectionView = ({ section }) => {
14937
+ if (section.kind === "absent") {
14938
+ return /* @__PURE__ */ jsxs11(Text12, { children: [
14939
+ /* @__PURE__ */ jsx14(Text12, { bold: true, children: "\u2500\u2500 MPP \u2500\u2500" }),
14940
+ " ",
14941
+ /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: "none advertised" })
14942
+ ] });
14943
+ }
14944
+ if (section.kind === "none-inflow") {
14945
+ const methods = section.methods.length > 0 ? section.methods.join(", ") : "(unknown)";
14946
+ return /* @__PURE__ */ jsxs11(Text12, { children: [
14947
+ /* @__PURE__ */ jsx14(Text12, { bold: true, children: "\u2500\u2500 MPP \u2500\u2500" }),
14948
+ " ",
14949
+ /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: `advertised method(s) not payable by InFlow: ${methods} (only \`inflow\` is supported)` })
14950
+ ] });
14951
+ }
14952
+ if (section.kind === "error") {
14953
+ return /* @__PURE__ */ jsxs11(Text12, { children: [
14954
+ /* @__PURE__ */ jsx14(Text12, { bold: true, children: "\u2500\u2500 MPP \u2500\u2500" }),
14955
+ " ",
14956
+ /* @__PURE__ */ jsx14(Text12, { color: "yellow", children: `header present but undecodable (${section.code})` })
14957
+ ] });
14958
+ }
14959
+ const count = section.challenges.length;
14960
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
14961
+ /* @__PURE__ */ jsxs11(Text12, { children: [
14962
+ /* @__PURE__ */ jsx14(Text12, { bold: true, children: "\u2500\u2500 MPP \u2500\u2500" }),
14963
+ " ",
14964
+ /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: "WWW-Authenticate: Payment" }),
14965
+ " \xB7 ",
14966
+ /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: `realm ${section.realm}` }),
14967
+ " \xB7 ",
14968
+ /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: `${String(count)} challenge${count === 1 ? "" : "s"}` })
14969
+ ] }),
14970
+ /* @__PURE__ */ jsx14(Table, { columns: MPP_TRIAGE_COLUMNS, rows: [...section.challenges] })
14971
+ ] });
14972
+ };
14973
+ var X402SectionView = ({ section }) => {
14974
+ if (section.kind === "absent") {
14975
+ return /* @__PURE__ */ jsxs11(Text12, { children: [
14976
+ /* @__PURE__ */ jsx14(Text12, { bold: true, children: "\u2500\u2500 x402 \u2500\u2500" }),
14977
+ " ",
14978
+ /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: "none advertised" })
14979
+ ] });
14980
+ }
14981
+ if (section.kind === "error") {
14982
+ return /* @__PURE__ */ jsxs11(Text12, { children: [
14983
+ /* @__PURE__ */ jsx14(Text12, { bold: true, children: "\u2500\u2500 x402 \u2500\u2500" }),
14984
+ " ",
14985
+ /* @__PURE__ */ jsx14(Text12, { color: "yellow", children: `header present but undecodable (${section.code})` })
14986
+ ] });
14987
+ }
14988
+ const count = section.accepts.length;
14989
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
14990
+ /* @__PURE__ */ jsxs11(Text12, { children: [
14991
+ /* @__PURE__ */ jsx14(Text12, { bold: true, children: "\u2500\u2500 x402 \u2500\u2500" }),
14992
+ " ",
14993
+ /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: "PAYMENT-REQUIRED" }),
14994
+ " \xB7 ",
14995
+ /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: `x402Version ${String(section.x402Version)}` }),
14996
+ " \xB7 ",
14997
+ /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: `${String(count)} accept${count === 1 ? "" : "s"}` })
14998
+ ] }),
14999
+ /* @__PURE__ */ jsx14(Table, { columns: X402_TRIAGE_COLUMNS, rows: [...section.accepts] })
15000
+ ] });
15001
+ };
15002
+ var CombinedInspectView = ({ url, method, deps, onComplete }) => {
15003
+ const initial = { kind: "probing" };
15004
+ const [phase, dispatch] = useReducer6(reduceCombinedInspect, initial);
15005
+ const { finish } = useFlowExit(onComplete);
15006
+ useEffect8(() => {
15007
+ let cancelled = false;
15008
+ void runCombinedInspectPipeline(deps, (event) => {
15009
+ if (!cancelled) dispatch(event);
15010
+ });
15011
+ return () => {
15012
+ cancelled = true;
15013
+ };
15014
+ }, [deps]);
15015
+ useEffect8(() => {
15016
+ if (phase.kind === "inspected" || phase.kind === "no-payment" || phase.kind === "error") {
15017
+ finish(phase);
15018
+ }
15019
+ }, [phase, finish]);
15020
+ if (phase.kind === "probing") {
15021
+ return /* @__PURE__ */ jsx14(Box11, { children: /* @__PURE__ */ jsxs11(Text12, { color: "cyan", children: [
15022
+ /* @__PURE__ */ jsx14(Spinner9, { type: "dots" }),
15023
+ " Probing ",
15024
+ method,
15025
+ " ",
15026
+ url,
15027
+ "..."
15028
+ ] }) });
15029
+ }
15030
+ if (phase.kind === "no-payment") {
15031
+ const { result: result2 } = phase;
15032
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
15033
+ /* @__PURE__ */ jsx14(Text12, { color: "green", children: "\u2713 Seller accepted without payment" }),
15034
+ /* @__PURE__ */ jsx14(Text12, { children: `status: ${String(result2.status)}` }),
15035
+ result2.contentType !== void 0 ? /* @__PURE__ */ jsx14(Text12, { children: `content-type: ${result2.contentType}` }) : null,
15036
+ /* @__PURE__ */ jsx14(Text12, { children: `response size: ${String(result2.bodySizeBytes)} bytes` }),
15037
+ /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: "No InFlow-payable challenge advertised." })
15038
+ ] });
15039
+ }
15040
+ if (phase.kind === "error") {
15041
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
15042
+ /* @__PURE__ */ jsxs11(Text12, { color: "red", children: [
15043
+ "\u2717 ",
15044
+ phase.code
15045
+ ] }),
15046
+ /* @__PURE__ */ jsx14(Text12, { color: "red", children: phase.message })
15047
+ ] });
15048
+ }
15049
+ const { result } = phase;
15050
+ const detected = detectedProtocols(result.mpp, result.x402);
15051
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
15052
+ /* @__PURE__ */ jsxs11(Text12, { children: [
15053
+ /* @__PURE__ */ jsx14(Text12, { bold: true, children: "PAYMENT-REQUIRED" }),
15054
+ " for ",
15055
+ /* @__PURE__ */ jsx14(Text12, { color: "cyan", children: result.url }),
15056
+ " \xB7 ",
15057
+ /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: `detected: ${detected.length > 0 ? detected.join(", ") : "none"}` })
15058
+ ] }),
15059
+ /* @__PURE__ */ jsx14(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx14(MppSectionView, { section: result.mpp }) }),
15060
+ /* @__PURE__ */ jsx14(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx14(X402SectionView, { section: result.x402 }) }),
15061
+ /* @__PURE__ */ jsx14(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text12, { dimColor: true, children: "Full detail (pay-to, timeout, extras, ids/digests): `inflow mpp inspect` / `inflow x402 inspect`, or --format json." }) })
15062
+ ] });
15063
+ };
15064
+
15065
+ // src/commands/inspect/schema.ts
15066
+ import { z as z4 } from "incur";
15067
+ var inspectArgs = z4.object({
15068
+ url: z4.string().describe("The resource URL to probe for MPP and/or x402 payment challenges. No payment is made.")
15069
+ });
15070
+ var inspectOptions = z4.object({
15071
+ method: z4.string().default("GET").describe("HTTP method for the probe request."),
15072
+ data: z4.string().optional().describe(
15073
+ "Request body for the probe. JSON or raw text. Content-Type defaults to application/json when --data is set unless a --header overrides it."
15074
+ ),
15075
+ header: z4.array(z4.string()).default([]).describe('Repeatable. "Name: Value" format.')
15076
+ });
15077
+
15078
+ // src/commands/inspect/index.tsx
15079
+ import { jsx as jsx15 } from "react/jsx-runtime";
15080
+ function parseHeaderFlagsOrFail(c, flags) {
15081
+ try {
15082
+ return parseHeaderFlags(flags);
15083
+ } catch (err) {
15084
+ c.error({ code: "INVALID_HEADER", message: err instanceof Error ? err.message : String(err) });
15085
+ }
15086
+ }
15087
+ function buildCombinedFrame(result) {
15088
+ const warnings = [];
15089
+ const mppRows = result.mpp.kind === "challenges" ? result.mpp.challenges.map(challengeToFrame) : [];
15090
+ if (result.mpp.kind === "none-inflow") {
15091
+ const offered = result.mpp.methods.length > 0 ? result.mpp.methods.join(", ") : "(unknown)";
15092
+ warnings.push({
15093
+ protocol: "mpp",
15094
+ code: "NO_INFLOW_MATCH",
15095
+ message: `WWW-Authenticate: Payment present, but no challenge uses the \`inflow\` method (only one the InFlow buyer can pay). Method(s) advertised: ${offered}.`,
15096
+ methods: result.mpp.methods
15097
+ });
15098
+ } else if (result.mpp.kind === "error") {
15099
+ warnings.push({ protocol: "mpp", code: result.mpp.code, message: result.mpp.message });
15100
+ }
15101
+ const x402Rows = result.x402.kind === "accepts" ? result.x402.accepts.map(acceptToFrame) : [];
15102
+ if (result.x402.kind === "error") {
15103
+ warnings.push({ protocol: "x402", code: result.x402.code, message: result.x402.message });
15104
+ }
15105
+ if (result.mpp.kind === "absent" && result.x402.kind === "absent") {
15106
+ warnings.push({
15107
+ protocol: "none",
15108
+ code: "NO_PAYMENT_CHALLENGE",
15109
+ message: "Seller returned 402 but carried neither a WWW-Authenticate: Payment nor a PAYMENT-REQUIRED header."
15110
+ });
15111
+ }
15112
+ const frame = {
15113
+ outcome: "inspected",
15114
+ url: result.url,
15115
+ method: result.method,
15116
+ detected: detectedProtocols(result.mpp, result.x402),
15117
+ mpp: mppRows,
15118
+ x402: x402Rows
15119
+ };
15120
+ if (result.x402.kind === "accepts") {
15121
+ frame.x402_resource = result.x402.resource;
15122
+ frame.x402_version = result.x402.x402Version;
15123
+ if (result.x402.extensions !== void 0) frame.x402_extensions = result.x402.extensions;
15124
+ }
15125
+ if (warnings.length > 0) frame.warnings = warnings;
15126
+ return frame;
15127
+ }
15128
+ function buildNoPaymentFrame3(result) {
15129
+ const frame = {
15130
+ outcome: "no-payment-required",
15131
+ url: result.url,
15132
+ method: result.method,
15133
+ status: result.status,
15134
+ body_size_bytes: result.bodySizeBytes
15135
+ };
15136
+ if (result.contentType !== void 0) frame.content_type = result.contentType;
15137
+ return frame;
15138
+ }
15139
+ async function runCombinedInspectCommand(c) {
15140
+ const probeHeaders = parseHeaderFlagsOrFail(c, c.options.header);
15141
+ const probeOptions = {
15142
+ method: c.options.method,
15143
+ headers: probeHeaders,
15144
+ ...c.options.data !== void 0 ? { data: c.options.data } : {}
15145
+ };
15146
+ const deps = { probeOptions, url: c.args.url };
15147
+ if (!c.agent && !c.formatExplicit) {
15148
+ let finalPhase = null;
15149
+ await renderInkUntilExit(
15150
+ /* @__PURE__ */ jsx15(
15151
+ CombinedInspectView,
15152
+ {
15153
+ url: c.args.url,
15154
+ method: c.options.method,
15155
+ deps,
15156
+ onComplete: (phase) => {
15157
+ finalPhase = phase;
15158
+ }
15159
+ }
15160
+ )
15161
+ );
15162
+ if (finalPhase !== null) {
15163
+ const phase = finalPhase;
15164
+ if (phase.kind === "error") {
15165
+ c.error({ code: phase.code, message: phase.message });
15166
+ }
15167
+ }
15168
+ return void 0;
15169
+ }
15170
+ let finalEvent = null;
15171
+ await runCombinedInspectPipeline(deps, (event) => {
15172
+ if (event.type === "errored") {
15173
+ finalEvent = { kind: "error", payload: event };
15174
+ return;
15175
+ }
15176
+ if (event.type === "inspected") {
15177
+ finalEvent = { kind: "inspected", payload: event.result };
15178
+ return;
15179
+ }
15180
+ if (event.type === "no-payment") {
15181
+ finalEvent = { kind: "no-payment", payload: event.result };
15182
+ }
15183
+ });
15184
+ if (finalEvent === null) {
15185
+ return c.error({ code: "INSPECT_FAILED", message: "Inspect pipeline produced no result." });
15186
+ }
15187
+ const { kind, payload } = finalEvent;
15188
+ if (kind === "error") {
15189
+ const err = payload;
15190
+ return c.error({ code: err.code, message: err.message });
15191
+ }
15192
+ if (kind === "inspected") {
15193
+ return sanitizeDeep(buildCombinedFrame(payload));
15194
+ }
15195
+ return sanitizeDeep(buildNoPaymentFrame3(payload));
15196
+ }
15197
+ function createInspectCommand() {
15198
+ return {
15199
+ description: "Detect a URL's payment protocol(s) and show MPP and x402 challenges together. Read-only probe \u2014 no auth, no payment. Read `detected` to choose a pay rail (MPP wins when both are present).",
15200
+ args: inspectArgs,
15201
+ options: inspectOptions,
15202
+ outputPolicy: "agent-only",
15203
+ examples: [
15204
+ {
15205
+ args: { url: "https://api.foo.dev/dataset.csv" },
15206
+ description: "Probe a URL and show every MPP and x402 challenge it advertises."
15207
+ },
15208
+ {
15209
+ args: { url: "https://api.foo.dev/widgets" },
15210
+ options: { method: "POST", data: '{"sku":"widget-1"}' },
15211
+ description: "Probe a POST-only paywalled endpoint."
15212
+ }
15213
+ ],
15214
+ async run(c) {
15215
+ return runCombinedInspectCommand(c);
15216
+ }
15217
+ };
15218
+ }
15219
+
15220
+ // src/commands/mpp/index.tsx
15221
+ import { chmodSync, writeFileSync as writeFileSync2 } from "fs";
15222
+ import { resolve as resolvePath2 } from "path";
15223
+ import { Cli as Cli4 } from "incur";
15224
+
15225
+ // src/commands/mpp/cancel.tsx
15226
+ import { Box as Box12, Text as Text13 } from "ink";
15227
+ import Spinner10 from "ink-spinner";
15228
+ import { useCallback as useCallback5 } from "react";
15229
+ import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
15230
+ var CancelView = ({ approvalId, cancel, onComplete }) => {
15231
+ const action = useCallback5(() => cancel(), [cancel]);
15232
+ const { finish } = useFlowExit(onComplete);
15233
+ const { status } = useFlowState(action, finish);
15234
+ if (status === "loading") {
15235
+ return /* @__PURE__ */ jsx16(Box12, { children: /* @__PURE__ */ jsxs12(Text13, { color: "cyan", children: [
15236
+ /* @__PURE__ */ jsx16(Spinner10, { type: "dots" }),
15237
+ " Cancelling approval ",
15238
+ approvalId,
15239
+ "..."
15240
+ ] }) });
15241
+ }
15242
+ return /* @__PURE__ */ jsx16(Box12, { children: /* @__PURE__ */ jsxs12(Text13, { color: "green", children: [
15243
+ "\u2713 Cancelled approval ",
15244
+ approvalId,
15245
+ " (best-effort)"
15246
+ ] }) });
15247
+ };
15248
+
15249
+ // src/commands/mpp/decode.tsx
15250
+ import { Box as Box13, Text as Text14 } from "ink";
15251
+ import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
15252
+ function ChallengeBody({ challenge }) {
15253
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [
15254
+ /* @__PURE__ */ jsx17(Text14, { bold: true, children: "Challenge" }),
15255
+ /* @__PURE__ */ jsxs13(Text14, { children: [
15256
+ "method/intent: ",
15257
+ /* @__PURE__ */ jsxs13(Text14, { color: "yellow", children: [
15258
+ challenge.method,
15259
+ " / ",
15260
+ challenge.intent
15261
+ ] })
15262
+ ] }),
15263
+ /* @__PURE__ */ jsx17(Text14, { children: `id: ${challenge.id}` }),
15264
+ /* @__PURE__ */ jsx17(Text14, { children: `realm: ${challenge.realm}` }),
15265
+ challenge.amount !== void 0 ? /* @__PURE__ */ jsx17(Text14, { children: `amount: ${challenge.amount}${challenge.currency !== void 0 ? ` ${challenge.currency}` : ""}` }) : null,
15266
+ challenge.rail !== void 0 ? /* @__PURE__ */ jsx17(Text14, { children: `rail: ${challenge.rail}` }) : null,
15267
+ challenge.expires !== void 0 ? /* @__PURE__ */ jsx17(Text14, { dimColor: true, children: `expires: ${challenge.expires}` }) : null
15268
+ ] });
15269
+ }
15270
+ var DecodeView = ({ result }) => {
15271
+ if (result.kind === "challenge") {
15272
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", paddingY: 1, children: [
15273
+ /* @__PURE__ */ jsx17(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsx17(Text14, { bold: true, children: "Decoded WWW-Authenticate: Payment" }) }),
15274
+ /* @__PURE__ */ jsx17(ChallengeBody, { challenge: result.challenge })
15275
+ ] });
15276
+ }
15277
+ if (result.kind === "credential") {
15278
+ const { credential } = result;
15279
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", paddingY: 1, children: [
15280
+ /* @__PURE__ */ jsx17(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsx17(Text14, { bold: true, children: "Decoded Authorization: Payment credential" }) }),
15281
+ /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [
15282
+ /* @__PURE__ */ jsx17(Text14, { children: `challenge id: ${credential.challenge.id}` }),
15283
+ /* @__PURE__ */ jsx17(Text14, { children: `method: ${credential.challenge.method}` }),
15284
+ /* @__PURE__ */ jsx17(Text14, { children: `source: ${credential.source}` }),
15285
+ /* @__PURE__ */ jsx17(Text14, { dimColor: true, children: `payload keys: ${Object.keys(credential.payload).join(", ") || "(none)"}` })
15286
+ ] })
15287
+ ] });
15288
+ }
15289
+ const { receipt } = result;
15290
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", paddingY: 1, children: [
15291
+ /* @__PURE__ */ jsx17(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsx17(Text14, { bold: true, children: "Decoded Payment-Receipt" }) }),
15292
+ /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [
15293
+ /* @__PURE__ */ jsxs13(Text14, { children: [
15294
+ "status: ",
15295
+ /* @__PURE__ */ jsx17(Text14, { color: "green", children: receipt.status })
15296
+ ] }),
15297
+ /* @__PURE__ */ jsx17(Text14, { children: `reference: ${receipt.reference}` }),
15298
+ /* @__PURE__ */ jsx17(Text14, { dimColor: true, children: `timestamp: ${receipt.timestamp}` })
15299
+ ] })
15300
+ ] });
15301
+ };
15302
+
15303
+ // src/commands/mpp/pay.tsx
15304
+ import { Box as Box14, Text as Text15, useInput as useInput3 } from "ink";
15305
+ import Spinner11 from "ink-spinner";
15306
+ import { useEffect as useEffect9, useReducer as useReducer7, useState as useState3 } from "react";
15307
+ import { Fragment, jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
15308
+ var PayView = ({ url, method, deps, onComplete, onCancel }) => {
15309
+ const initial = { kind: "probing" };
15310
+ const [phase, dispatch] = useReducer7(reduceMppPay, initial);
15311
+ const [cancelling, setCancelling] = useState3(false);
15312
+ const { finish, cancelThenFinish } = useFlowExit(onComplete);
15313
+ const created = phase.kind === "created" ? phase.created : void 0;
15314
+ const approvalUrl = created?.approvalUrl;
15315
+ const approvalId = created?.approvalId;
15316
+ useInput3(
15317
+ (_input, key) => {
15318
+ if (approvalUrl === void 0) return;
15319
+ if (key.return) {
15320
+ openUrl(approvalUrl);
15321
+ return;
15322
+ }
15323
+ if (key.escape && approvalId !== void 0) {
15324
+ setCancelling(true);
15325
+ cancelThenFinish(() => onCancel?.(approvalId), {
15326
+ kind: "error",
15327
+ code: "APPROVAL_CANCELLED",
15328
+ message: `Approval ${approvalId} cancelled.`
15329
+ });
15330
+ }
15331
+ },
15332
+ { isActive: approvalUrl !== void 0 && !cancelling }
15333
+ );
15334
+ useEffect9(() => {
15335
+ const controller = new AbortController();
15336
+ let cancelled = false;
15337
+ const runDeps = { ...deps, signal: controller.signal };
15338
+ void runMppPayPipeline(runDeps, (event) => {
15339
+ if (!cancelled) dispatch(event);
15340
+ });
15341
+ return () => {
15342
+ cancelled = true;
15343
+ controller.abort();
15344
+ };
15345
+ }, [deps]);
15346
+ useEffect9(() => {
15347
+ if (phase.kind === "success" || phase.kind === "seller-rejected" || phase.kind === "no-payment-final" || phase.kind === "error") {
15348
+ finish(phase);
15349
+ }
15350
+ }, [phase, finish]);
15351
+ if (cancelling) {
15352
+ return /* @__PURE__ */ jsx18(Box14, { children: /* @__PURE__ */ jsxs14(Text15, { color: "yellow", children: [
15353
+ /* @__PURE__ */ jsx18(Spinner11, { type: "dots" }),
15354
+ " Cancelling approval..."
15355
+ ] }) });
15356
+ }
15357
+ if (phase.kind === "probing") {
15358
+ return /* @__PURE__ */ jsx18(Box14, { children: /* @__PURE__ */ jsxs14(Text15, { color: "cyan", children: [
15359
+ /* @__PURE__ */ jsx18(Spinner11, { type: "dots" }),
15360
+ " Probing ",
15361
+ method,
15362
+ " ",
15363
+ url,
15364
+ "..."
15365
+ ] }) });
15366
+ }
15367
+ if (phase.kind === "no-payment") {
15368
+ return /* @__PURE__ */ jsx18(Box14, { children: /* @__PURE__ */ jsxs14(Text15, { color: "cyan", children: [
15369
+ /* @__PURE__ */ jsx18(Spinner11, { type: "dots" }),
15370
+ " Seller accepted without payment (status ",
15371
+ String(phase.probe.status),
15372
+ "); finalising..."
15373
+ ] }) });
15374
+ }
15375
+ if (phase.kind === "decoded") {
15376
+ return /* @__PURE__ */ jsx18(Box14, { children: /* @__PURE__ */ jsxs14(Text15, { color: "cyan", children: [
15377
+ /* @__PURE__ */ jsx18(Spinner11, { type: "dots" }),
15378
+ " Fulfilling ",
15379
+ phase.challenge.amount ?? "",
15380
+ " ",
15381
+ phase.challenge.currency ?? "",
15382
+ " ",
15383
+ "challenge..."
15384
+ ] }) });
15385
+ }
15386
+ if (phase.kind === "created") {
15387
+ const { created: created2 } = phase;
15388
+ if (created2.state !== "pending") {
15389
+ return /* @__PURE__ */ jsx18(Box14, { children: /* @__PURE__ */ jsxs14(Text15, { color: "cyan", children: [
15390
+ /* @__PURE__ */ jsx18(Spinner11, { type: "dots" }),
15391
+ " Transaction ",
15392
+ created2.transactionId,
15393
+ " ready; replaying..."
15394
+ ] }) });
15395
+ }
15396
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingY: 1, children: [
15397
+ /* @__PURE__ */ jsx18(Box14, { marginBottom: 1, children: /* @__PURE__ */ jsx18(Text15, { bold: true, children: "Approval required" }) }),
15398
+ /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [
15399
+ /* @__PURE__ */ jsx18(Text15, { children: `transaction: ${created2.transactionId}` }),
15400
+ created2.approvalUrl !== void 0 ? /* @__PURE__ */ jsxs14(Fragment, { children: [
15401
+ /* @__PURE__ */ jsxs14(Text15, { children: [
15402
+ "Open: ",
15403
+ /* @__PURE__ */ jsx18(Text15, { bold: true, color: "cyan", children: created2.approvalUrl })
15404
+ ] }),
15405
+ /* @__PURE__ */ jsx18(Text15, { dimColor: true, children: "Press Enter to open in browser." }),
15406
+ /* @__PURE__ */ jsx18(Text15, { dimColor: true, children: "Press Escape to cancel." })
15407
+ ] }) : null
15408
+ ] }),
15409
+ /* @__PURE__ */ jsx18(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs14(Text15, { color: "cyan", children: [
15410
+ /* @__PURE__ */ jsx18(Spinner11, { type: "dots" }),
15411
+ " Waiting for approval..."
15412
+ ] }) })
15413
+ ] });
15414
+ }
15415
+ if (phase.kind === "replaying") {
15416
+ return /* @__PURE__ */ jsx18(Box14, { children: /* @__PURE__ */ jsxs14(Text15, { color: "cyan", children: [
15417
+ /* @__PURE__ */ jsx18(Spinner11, { type: "dots" }),
15418
+ " Replaying request with Authorization: Payment..."
15419
+ ] }) });
15420
+ }
15421
+ if (phase.kind === "success") {
15422
+ const { result } = phase;
15423
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
15424
+ /* @__PURE__ */ jsxs14(Text15, { color: "green", children: [
15425
+ "\u2713 Paid (intent ",
15426
+ result.intent,
15427
+ ")"
14903
15428
  ] }),
14904
- /* @__PURE__ */ jsx15(Text13, { children: `status: ${String(result.responseStatus)}` }),
14905
- /* @__PURE__ */ jsx15(Text13, { children: `transaction: ${result.transactionId}` }),
14906
- result.settled !== void 0 ? /* @__PURE__ */ jsx15(Text13, { children: `settled: ${result.settled.status ?? "success"} (ref ${result.settled.reference ?? "\u2014"})` }) : null,
14907
- /* @__PURE__ */ jsx15(Text13, { children: `response size: ${String(result.bodySizeBytes)} bytes` }),
14908
- result.outputSavedTo !== void 0 ? /* @__PURE__ */ jsxs12(Text13, { children: [
15429
+ /* @__PURE__ */ jsx18(Text15, { children: `status: ${String(result.responseStatus)}` }),
15430
+ /* @__PURE__ */ jsx18(Text15, { children: `transaction: ${result.transactionId}` }),
15431
+ result.settled !== void 0 ? /* @__PURE__ */ jsx18(Text15, { children: `settled: ${result.settled.status ?? "success"} (ref ${result.settled.reference ?? "\u2014"})` }) : null,
15432
+ /* @__PURE__ */ jsx18(Text15, { children: `response size: ${String(result.bodySizeBytes)} bytes` }),
15433
+ result.outputSavedTo !== void 0 ? /* @__PURE__ */ jsxs14(Text15, { children: [
14909
15434
  "Saved to: ",
14910
- /* @__PURE__ */ jsx15(Text13, { bold: true, children: result.outputSavedTo })
15435
+ /* @__PURE__ */ jsx18(Text15, { bold: true, children: result.outputSavedTo })
14911
15436
  ] }) : null,
14912
- result.body !== void 0 ? /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
14913
- /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "response body:" }),
14914
- /* @__PURE__ */ jsx15(Text13, { children: result.body })
15437
+ result.body !== void 0 ? /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
15438
+ /* @__PURE__ */ jsx18(Text15, { dimColor: true, children: "response body:" }),
15439
+ /* @__PURE__ */ jsx18(Text15, { children: result.body })
14915
15440
  ] }) : null
14916
15441
  ] });
14917
15442
  }
14918
15443
  if (phase.kind === "seller-rejected") {
14919
15444
  const { result } = phase;
14920
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
14921
- /* @__PURE__ */ jsx15(Text13, { color: "red", children: "\u2717 Payment not accepted by seller" }),
14922
- /* @__PURE__ */ jsx15(Text13, { children: `status: ${String(result.responseStatus)}` }),
14923
- /* @__PURE__ */ jsx15(Text13, { children: `transaction: ${result.transactionId}` }),
14924
- /* @__PURE__ */ jsx15(Text13, { children: `response size: ${String(result.bodySizeBytes)} bytes` }),
14925
- result.body !== void 0 ? /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
14926
- /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "response body:" }),
14927
- /* @__PURE__ */ jsx15(Text13, { children: result.body })
15445
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
15446
+ /* @__PURE__ */ jsx18(Text15, { color: "red", children: "\u2717 Payment not accepted by seller" }),
15447
+ /* @__PURE__ */ jsx18(Text15, { children: `status: ${String(result.responseStatus)}` }),
15448
+ /* @__PURE__ */ jsx18(Text15, { children: `transaction: ${result.transactionId}` }),
15449
+ /* @__PURE__ */ jsx18(Text15, { children: `response size: ${String(result.bodySizeBytes)} bytes` }),
15450
+ result.body !== void 0 ? /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
15451
+ /* @__PURE__ */ jsx18(Text15, { dimColor: true, children: "response body:" }),
15452
+ /* @__PURE__ */ jsx18(Text15, { children: result.body })
14928
15453
  ] }) : null
14929
15454
  ] });
14930
15455
  }
14931
15456
  if (phase.kind === "no-payment-final") {
14932
15457
  const { result } = phase;
14933
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
14934
- /* @__PURE__ */ jsx15(Text13, { color: "green", children: "\u2713 Seller accepted without payment" }),
14935
- /* @__PURE__ */ jsx15(Text13, { children: `status: ${String(result.status)}` }),
14936
- /* @__PURE__ */ jsx15(Text13, { children: `response size: ${String(result.bodySizeBytes)} bytes` }),
14937
- result.outputSavedTo !== void 0 ? /* @__PURE__ */ jsxs12(Text13, { children: [
15458
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
15459
+ /* @__PURE__ */ jsx18(Text15, { color: "green", children: "\u2713 Seller accepted without payment" }),
15460
+ /* @__PURE__ */ jsx18(Text15, { children: `status: ${String(result.status)}` }),
15461
+ /* @__PURE__ */ jsx18(Text15, { children: `response size: ${String(result.bodySizeBytes)} bytes` }),
15462
+ result.outputSavedTo !== void 0 ? /* @__PURE__ */ jsxs14(Text15, { children: [
14938
15463
  "Saved to: ",
14939
- /* @__PURE__ */ jsx15(Text13, { bold: true, children: result.outputSavedTo })
15464
+ /* @__PURE__ */ jsx18(Text15, { bold: true, children: result.outputSavedTo })
14940
15465
  ] }) : null,
14941
- result.body !== void 0 ? /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
14942
- /* @__PURE__ */ jsx15(Text13, { dimColor: true, children: "response body:" }),
14943
- /* @__PURE__ */ jsx15(Text13, { children: result.body })
15466
+ result.body !== void 0 ? /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
15467
+ /* @__PURE__ */ jsx18(Text15, { dimColor: true, children: "response body:" }),
15468
+ /* @__PURE__ */ jsx18(Text15, { children: result.body })
14944
15469
  ] }) : null
14945
15470
  ] });
14946
15471
  }
14947
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
14948
- /* @__PURE__ */ jsxs12(Text13, { color: "red", children: [
15472
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
15473
+ /* @__PURE__ */ jsxs14(Text15, { color: "red", children: [
14949
15474
  "\u2717 ",
14950
15475
  phase.code
14951
15476
  ] }),
14952
- /* @__PURE__ */ jsx15(Text13, { color: "red", children: phase.message })
15477
+ /* @__PURE__ */ jsx18(Text15, { color: "red", children: phase.message })
14953
15478
  ] });
14954
15479
  };
14955
15480
 
14956
15481
  // src/commands/mpp/schema.ts
14957
- import { z as z4 } from "incur";
14958
- var payArgs = z4.object({
14959
- url: z4.string().describe("The MPP-protected resource URL to pay for.")
15482
+ import { z as z5 } from "incur";
15483
+ var payArgs = z5.object({
15484
+ url: z5.string().describe("The MPP-protected resource URL to pay for.")
14960
15485
  });
14961
- var payOptions = z4.object({
14962
- paymentMethod: z4.string().optional().describe('Only consider challenges with this payment method (e.g. "inflow").'),
14963
- intent: z4.string().optional().describe('Only consider challenges with this intent (e.g. "charge").'),
14964
- currency: z4.string().optional().describe('Only consider challenges in this currency (e.g. "USDC").'),
14965
- rail: z4.string().optional().describe('Only consider challenges on this settlement rail (e.g. "balance", "instrument").'),
14966
- method: z4.string().default("GET").describe("HTTP method for the seller request."),
14967
- data: z4.string().optional().describe(
15486
+ var payOptions = z5.object({
15487
+ paymentMethod: z5.string().optional().describe('Only consider challenges with this payment method (e.g. "inflow").'),
15488
+ intent: z5.string().optional().describe('Only consider challenges with this intent (e.g. "charge").'),
15489
+ currency: z5.string().optional().describe('Only consider challenges in this currency (e.g. "USDC").'),
15490
+ rail: z5.string().optional().describe('Only consider challenges on this settlement rail (e.g. "balance", "instrument").'),
15491
+ method: z5.string().default("GET").describe("HTTP method for the seller request."),
15492
+ data: z5.string().optional().describe(
14968
15493
  "Request body. JSON or raw text. Content-Type defaults to application/json when --data is set unless a --header overrides it."
14969
15494
  ),
14970
- header: z4.array(z4.string()).default([]).describe('Repeatable. "Name: Value" format.'),
14971
- interval: z4.coerce.number().default(0).describe(
15495
+ header: z5.array(z5.string()).default([]).describe('Repeatable. "Name: Value" format.'),
15496
+ interval: z5.coerce.number().default(0).describe(
14972
15497
  "Inline poll cadence in seconds while a transaction is pending. 0 returns the transaction id and a follow-up command hint without blocking."
14973
15498
  ),
14974
- maxAttempts: z4.coerce.number().default(0).describe("Hard cap on poll attempts when --interval > 0. 0 means unlimited."),
14975
- timeout: z4.coerce.number().default(900).describe("Polling deadline in seconds. Default 900s (matches the server-side approval expiry)."),
14976
- instrumentId: z4.string().optional().describe(
15499
+ maxAttempts: z5.coerce.number().default(0).describe("Hard cap on poll attempts when --interval > 0. 0 means unlimited."),
15500
+ timeout: z5.coerce.number().default(900).describe("Polling deadline in seconds. Default 900s (matches the server-side approval expiry)."),
15501
+ instrumentId: z5.string().optional().describe(
14977
15502
  "Funding instrument id (UUID) for an instrument-rail challenge. The buyer does not choose the rail \u2014 it is derived from the seller challenge; this is the only buyer-supplied payment option."
14978
15503
  ),
14979
- showBody: z4.boolean().default(true).describe(
15504
+ showBody: z5.boolean().default(true).describe(
14980
15505
  "Include the seller response body in the result. Default true so AI assistants paying for content receive the deliverable. Pass --no-show-body to suppress (e.g. for binary downloads paired with --output-file)."
14981
15506
  ),
14982
- outputFile: z4.string().optional().describe(
15507
+ outputFile: z5.string().optional().describe(
14983
15508
  "Write the seller response body bytes to this file path (overwrites silently). When set, the result frame includes `output_saved_to: <absolute_path>` instead of `body` / `body_base64`. Natural choice for binary content (PDFs, images, downloads)."
14984
15509
  ),
14985
- credentialFile: z4.string().optional().describe(
15510
+ credentialFile: z5.string().optional().describe(
14986
15511
  "Write the base64url `Authorization: Payment` credential to this file path (mode 0o600, overwrites silently). When set, the result frame includes `credential_saved_to: <absolute_path>` instead of `credential`. Use to keep one-time payment credentials out of chat transcripts and logs."
14987
15512
  )
14988
15513
  });
14989
- var statusArgs = z4.object({
14990
- transactionId: z4.string().describe("The transaction id returned by `mpp pay`.")
15514
+ var statusArgs = z5.object({
15515
+ transactionId: z5.string().describe("The transaction id returned by `mpp pay`.")
14991
15516
  });
14992
- var statusOptions2 = z4.object({
14993
- interval: z4.coerce.number().default(0).describe(
15517
+ var statusOptions2 = z5.object({
15518
+ interval: z5.coerce.number().default(0).describe(
14994
15519
  "Poll cadence in seconds. 0 returns the current snapshot; positive values yield on every change until ready or terminal."
14995
15520
  ),
14996
- maxAttempts: z4.coerce.number().default(0).describe("Hard cap on poll attempts. 0 means unlimited."),
14997
- timeout: z4.coerce.number().default(900).describe("Polling deadline in seconds."),
14998
- credentialFile: z4.string().optional().describe(
15521
+ maxAttempts: z5.coerce.number().default(0).describe("Hard cap on poll attempts. 0 means unlimited."),
15522
+ timeout: z5.coerce.number().default(900).describe("Polling deadline in seconds."),
15523
+ credentialFile: z5.string().optional().describe(
14999
15524
  "Write the base64url `Authorization: Payment` credential to this file path (mode 0o600, overwrites silently). When set, the ready frame includes `credential_saved_to: <absolute_path>` instead of `credential`. Use to keep one-time payment credentials out of chat transcripts and logs."
15000
15525
  )
15001
15526
  });
15002
- var cancelArgs = z4.object({
15003
- approvalId: z4.string().describe("The approval id returned by `mpp pay` (on the pending frame).")
15527
+ var cancelArgs = z5.object({
15528
+ approvalId: z5.string().describe("The approval id returned by `mpp pay` (on the pending frame).")
15004
15529
  });
15005
- var decodeArgs = z4.object({
15006
- value: z4.string().describe(
15530
+ var decodeArgs = z5.object({
15531
+ value: z5.string().describe(
15007
15532
  "A raw `WWW-Authenticate: Payment` header value, or a base64url `Authorization: Payment` credential / `Payment-Receipt`. The kind is auto-detected."
15008
15533
  )
15009
15534
  });
15010
- var inspectArgs = z4.object({
15011
- url: z4.string().describe("The MPP-protected resource URL to probe. No payment is made.")
15535
+ var inspectArgs2 = z5.object({
15536
+ url: z5.string().describe("The MPP-protected resource URL to probe. No payment is made.")
15012
15537
  });
15013
- var inspectOptions = z4.object({
15014
- paymentMethod: z4.string().optional().describe('Only show challenges with this payment method (e.g. "inflow").'),
15015
- intent: z4.string().optional().describe('Only show challenges with this intent (e.g. "charge").'),
15016
- currency: z4.string().optional().describe('Only show challenges in this currency (e.g. "USDC").'),
15017
- rail: z4.string().optional().describe('Only show challenges on this settlement rail (e.g. "balance", "instrument").'),
15018
- method: z4.string().default("GET").describe("HTTP method for the probe request."),
15019
- data: z4.string().optional().describe(
15538
+ var inspectOptions2 = z5.object({
15539
+ paymentMethod: z5.string().optional().describe('Only show challenges with this payment method (e.g. "inflow").'),
15540
+ intent: z5.string().optional().describe('Only show challenges with this intent (e.g. "charge").'),
15541
+ currency: z5.string().optional().describe('Only show challenges in this currency (e.g. "USDC").'),
15542
+ rail: z5.string().optional().describe('Only show challenges on this settlement rail (e.g. "balance", "instrument").'),
15543
+ method: z5.string().default("GET").describe("HTTP method for the probe request."),
15544
+ data: z5.string().optional().describe(
15020
15545
  "Request body for the probe. JSON or raw text. Content-Type defaults to application/json when --data is set unless a --header overrides it."
15021
15546
  ),
15022
- header: z4.array(z4.string()).default([]).describe('Repeatable. "Name: Value" format.')
15547
+ header: z5.array(z5.string()).default([]).describe('Repeatable. "Name: Value" format.')
15023
15548
  });
15024
15549
 
15025
15550
  // src/commands/mpp/status.tsx
15026
- import { Box as Box13, Text as Text14 } from "ink";
15027
- import Spinner10 from "ink-spinner";
15028
- import { useEffect as useEffect8, useReducer as useReducer6 } from "react";
15029
- import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
15551
+ import { Box as Box15, Text as Text16 } from "ink";
15552
+ import Spinner12 from "ink-spinner";
15553
+ import { useEffect as useEffect10, useReducer as useReducer8 } from "react";
15554
+ import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
15030
15555
  var MppStatusView = ({
15031
15556
  transactionId,
15032
15557
  fetchOnce,
@@ -15036,9 +15561,9 @@ var MppStatusView = ({
15036
15561
  onComplete
15037
15562
  }) => {
15038
15563
  const initial = { kind: "polling" };
15039
- const [phase, dispatch] = useReducer6(reduceMppStatus, initial);
15564
+ const [phase, dispatch] = useReducer8(reduceMppStatus, initial);
15040
15565
  const { finish } = useFlowExit(onComplete);
15041
- useEffect8(() => {
15566
+ useEffect10(() => {
15042
15567
  const run = runMppStatus({ fetchOnce, interval, maxAttempts, timeout });
15043
15568
  let cancelled = false;
15044
15569
  void (async () => {
@@ -15051,15 +15576,15 @@ var MppStatusView = ({
15051
15576
  cancelled = true;
15052
15577
  };
15053
15578
  }, [fetchOnce, interval, maxAttempts, timeout]);
15054
- useEffect8(() => {
15579
+ useEffect10(() => {
15055
15580
  if (phase.kind === "ready" || phase.kind === "failed" || phase.kind === "expired" || phase.kind === "timeout" || phase.kind === "error") {
15056
15581
  finish(phase);
15057
15582
  }
15058
15583
  }, [phase, finish]);
15059
15584
  if (phase.kind === "polling") {
15060
15585
  const stateText = phase.latest?.state ?? "pending";
15061
- return /* @__PURE__ */ jsx16(Box13, { flexDirection: "column", children: /* @__PURE__ */ jsxs13(Text14, { color: "cyan", children: [
15062
- /* @__PURE__ */ jsx16(Spinner10, { type: "dots" }),
15586
+ return /* @__PURE__ */ jsx19(Box15, { flexDirection: "column", children: /* @__PURE__ */ jsxs15(Text16, { color: "cyan", children: [
15587
+ /* @__PURE__ */ jsx19(Spinner12, { type: "dots" }),
15063
15588
  " Polling transaction ",
15064
15589
  transactionId,
15065
15590
  " (state: ",
@@ -15070,38 +15595,38 @@ var MppStatusView = ({
15070
15595
  if (phase.kind === "ready") {
15071
15596
  const credential = phase.response.credential ?? "";
15072
15597
  const preview = credential.length > 32 ? `${credential.slice(0, 32)}...` : credential;
15073
- return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
15074
- /* @__PURE__ */ jsx16(Text14, { color: "green", children: "\u2713 Ready" }),
15075
- /* @__PURE__ */ jsx16(Text14, { children: `credential: ${preview}` }),
15076
- phase.response.expires !== void 0 ? /* @__PURE__ */ jsx16(Text14, { dimColor: true, children: `expires: ${phase.response.expires}` }) : null
15598
+ return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", children: [
15599
+ /* @__PURE__ */ jsx19(Text16, { color: "green", children: "\u2713 Ready" }),
15600
+ /* @__PURE__ */ jsx19(Text16, { children: `credential: ${preview}` }),
15601
+ phase.response.expires !== void 0 ? /* @__PURE__ */ jsx19(Text16, { dimColor: true, children: `expires: ${phase.response.expires}` }) : null
15077
15602
  ] });
15078
15603
  }
15079
15604
  if (phase.kind === "failed") {
15080
- return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
15081
- /* @__PURE__ */ jsx16(Text14, { color: "red", children: "\u2717 Transaction failed" }),
15082
- phase.response.problem !== void 0 ? /* @__PURE__ */ jsx16(Text14, { color: "red", children: phase.response.problem.detail ?? phase.response.problem.title }) : null
15605
+ return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", children: [
15606
+ /* @__PURE__ */ jsx19(Text16, { color: "red", children: "\u2717 Transaction failed" }),
15607
+ phase.response.problem !== void 0 ? /* @__PURE__ */ jsx19(Text16, { color: "red", children: phase.response.problem.detail ?? phase.response.problem.title }) : null
15083
15608
  ] });
15084
15609
  }
15085
15610
  if (phase.kind === "expired") {
15086
- return /* @__PURE__ */ jsx16(Box13, { flexDirection: "column", children: /* @__PURE__ */ jsx16(Text14, { color: "yellow", children: "Transaction expired before it was ready." }) });
15611
+ return /* @__PURE__ */ jsx19(Box15, { flexDirection: "column", children: /* @__PURE__ */ jsx19(Text16, { color: "yellow", children: "Transaction expired before it was ready." }) });
15087
15612
  }
15088
15613
  if (phase.kind === "timeout") {
15089
- return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
15090
- /* @__PURE__ */ jsx16(Text14, { color: "yellow", children: "Polling timed out before the transaction reached a ready state." }),
15091
- phase.response !== void 0 ? /* @__PURE__ */ jsx16(Text14, { children: `last state: ${phase.response.state}` }) : null
15614
+ return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", children: [
15615
+ /* @__PURE__ */ jsx19(Text16, { color: "yellow", children: "Polling timed out before the transaction reached a ready state." }),
15616
+ phase.response !== void 0 ? /* @__PURE__ */ jsx19(Text16, { children: `last state: ${phase.response.state}` }) : null
15092
15617
  ] });
15093
15618
  }
15094
- return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
15095
- /* @__PURE__ */ jsx16(Text14, { color: "red", children: "\u2717 Polling failed" }),
15096
- /* @__PURE__ */ jsx16(Text14, { color: "red", children: phase.message })
15619
+ return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", children: [
15620
+ /* @__PURE__ */ jsx19(Text16, { color: "red", children: "\u2717 Polling failed" }),
15621
+ /* @__PURE__ */ jsx19(Text16, { color: "red", children: phase.message })
15097
15622
  ] });
15098
15623
  };
15099
15624
 
15100
15625
  // src/commands/mpp/supported.tsx
15101
- import { Box as Box14, Text as Text15 } from "ink";
15102
- import Spinner11 from "ink-spinner";
15626
+ import { Box as Box16, Text as Text17 } from "ink";
15627
+ import Spinner13 from "ink-spinner";
15103
15628
  import { useCallback as useCallback6 } from "react";
15104
- import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
15629
+ import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
15105
15630
  function flattenKinds(response) {
15106
15631
  const rows = [];
15107
15632
  for (const kind of response.kinds) {
@@ -15118,7 +15643,7 @@ function flattenKinds(response) {
15118
15643
  }
15119
15644
  return rows;
15120
15645
  }
15121
- var COLUMNS4 = [
15646
+ var COLUMNS5 = [
15122
15647
  { header: "Method", cell: (r) => r.method },
15123
15648
  { header: "Intent", cell: (r) => r.intent },
15124
15649
  { header: "Rail", cell: (r) => r.rail },
@@ -15129,34 +15654,33 @@ var SupportedView = ({ load, onComplete }) => {
15129
15654
  const { finish } = useFlowExit(onComplete);
15130
15655
  const { status, data, error } = useFlowState(action, finish);
15131
15656
  if (status === "loading") {
15132
- return /* @__PURE__ */ jsx17(Box14, { children: /* @__PURE__ */ jsxs14(Text15, { color: "cyan", children: [
15133
- /* @__PURE__ */ jsx17(Spinner11, { type: "dots" }),
15657
+ return /* @__PURE__ */ jsx20(Box16, { children: /* @__PURE__ */ jsxs16(Text17, { color: "cyan", children: [
15658
+ /* @__PURE__ */ jsx20(Spinner13, { type: "dots" }),
15134
15659
  " Loading supported MPP methods..."
15135
15660
  ] }) });
15136
15661
  }
15137
15662
  if (status === "error") {
15138
- return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
15139
- /* @__PURE__ */ jsx17(Text15, { color: "red", children: "Failed to load supported MPP methods" }),
15140
- /* @__PURE__ */ jsx17(Text15, { color: "red", children: error })
15663
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
15664
+ /* @__PURE__ */ jsx20(Text17, { color: "red", children: "Failed to load supported MPP methods" }),
15665
+ /* @__PURE__ */ jsx20(Text17, { color: "red", children: error })
15141
15666
  ] });
15142
15667
  }
15143
15668
  const rows = data ? flattenKinds(data) : [];
15144
15669
  if (rows.length === 0) {
15145
- return /* @__PURE__ */ jsx17(Box14, { flexDirection: "column", children: /* @__PURE__ */ jsx17(Text15, { children: "No supported MPP methods returned for this account." }) });
15670
+ return /* @__PURE__ */ jsx20(Box16, { flexDirection: "column", children: /* @__PURE__ */ jsx20(Text17, { children: "No supported MPP methods returned for this account." }) });
15146
15671
  }
15147
- return /* @__PURE__ */ jsx17(Table, { columns: COLUMNS4, rows });
15672
+ return /* @__PURE__ */ jsx20(Table, { columns: COLUMNS5, rows });
15148
15673
  };
15149
15674
 
15150
15675
  // src/commands/mpp/index.tsx
15151
- import { jsx as jsx18 } from "react/jsx-runtime";
15676
+ import { jsx as jsx21 } from "react/jsx-runtime";
15152
15677
  var POST_CREATE_INSTRUCTION = "Present the approval_url to the user and ask them to approve in the InFlow mobile app or dashboard. Then call `mpp status <transaction_id> --interval 5 --max-attempts 60` to poll until ready. Once ready, replay the request manually with the credential as the `Authorization: Payment <credential>` header.";
15153
15678
  var POLLING_INSTRUCTION = "Approval polling is happening inline. The yield stream emits each state change; the final frame includes the result once the transaction is ready and replayed.";
15154
- function parseHeaderFlagsOrFail(c, flags) {
15155
- try {
15156
- return parseHeaderFlags(flags);
15157
- } catch (err) {
15158
- c.error({ code: "INVALID_HEADER", message: err instanceof Error ? err.message : String(err) });
15159
- }
15679
+ function invalidHeaderError(err) {
15680
+ return {
15681
+ code: "INVALID_HEADER",
15682
+ message: err instanceof Error ? err.message : String(err)
15683
+ };
15160
15684
  }
15161
15685
  function decorateCredentialField(frame, credential, credentialFile) {
15162
15686
  if (credentialFile !== void 0 && credentialFile.length > 0) {
@@ -15169,16 +15693,15 @@ function decorateCredentialField(frame, credential, credentialFile) {
15169
15693
  frame.credential = credential;
15170
15694
  }
15171
15695
  function probeOptionsFrom(c) {
15172
- const headers = parseHeaderFlagsOrFail(c, c.options.header);
15173
15696
  return {
15174
15697
  method: c.options.method,
15175
- headers,
15698
+ headers: parseHeaderFlags(c.options.header),
15176
15699
  ...c.options.data !== void 0 ? { data: c.options.data } : {}
15177
15700
  };
15178
15701
  }
15179
- function buildPayPipelineInput(c) {
15702
+ function buildPayPipelineInput(c, probeOptions) {
15180
15703
  return {
15181
- probeOptions: probeOptionsFrom(c),
15704
+ probeOptions,
15182
15705
  url: c.args.url,
15183
15706
  showBody: c.options.showBody,
15184
15707
  interval: c.options.interval,
@@ -15280,17 +15803,23 @@ function toStatusFrame(response, credentialFile) {
15280
15803
  }
15281
15804
  async function* runPayCommand(c, inflow2, authStorage2, apiBaseUrl2) {
15282
15805
  assertSessionGuard(c, authStorage2, inflow2);
15806
+ let probeOptions;
15807
+ try {
15808
+ probeOptions = probeOptionsFrom(c);
15809
+ } catch (err) {
15810
+ return c.error(invalidHeaderError(err));
15811
+ }
15283
15812
  if (!c.agent && !c.formatExplicit) {
15284
15813
  const client = await inflow2.mpp.client();
15285
15814
  let finalPhase = null;
15286
15815
  await renderInkUntilExit(
15287
- /* @__PURE__ */ jsx18(
15816
+ /* @__PURE__ */ jsx21(
15288
15817
  PayView,
15289
15818
  {
15290
15819
  url: c.args.url,
15291
15820
  method: c.options.method,
15292
15821
  deps: {
15293
- ...buildPayPipelineInput(c),
15822
+ ...buildPayPipelineInput(c, probeOptions),
15294
15823
  client,
15295
15824
  apiBaseUrl: apiBaseUrl2,
15296
15825
  awaitPayment: true
@@ -15305,19 +15834,19 @@ async function* runPayCommand(c, inflow2, authStorage2, apiBaseUrl2) {
15305
15834
  if (finalPhase !== null) {
15306
15835
  const phase = finalPhase;
15307
15836
  if (phase.kind === "seller-rejected") {
15308
- c.error({
15837
+ return c.error({
15309
15838
  code: PAYMENT_NOT_ACCEPTED_CODE2,
15310
15839
  message: `Seller rejected the credential with status ${String(phase.result.responseStatus)}. The transaction was ready but the seller did not honour the payment.`
15311
15840
  });
15312
15841
  }
15313
15842
  if (phase.kind === "error") {
15314
- c.error({ code: phase.code, message: phase.message });
15843
+ return c.error({ code: phase.code, message: phase.message });
15315
15844
  }
15316
15845
  }
15317
15846
  return;
15318
15847
  }
15319
15848
  const run = inflow2.mpp.pay({
15320
- ...buildPayPipelineInput(c),
15849
+ ...buildPayPipelineInput(c, probeOptions),
15321
15850
  awaitPayment: c.options.interval > 0
15322
15851
  });
15323
15852
  for await (const event of run.events) {
@@ -15335,14 +15864,13 @@ async function* runPayCommand(c, inflow2, authStorage2, apiBaseUrl2) {
15335
15864
  }
15336
15865
  if (event.type === "rejected") {
15337
15866
  yield sanitizeDeep(rejectedFrameFromResult(event.result));
15338
- c.error({
15867
+ return c.error({
15339
15868
  code: PAYMENT_NOT_ACCEPTED_CODE2,
15340
15869
  message: `Seller rejected the credential with status ${String(event.result.responseStatus)}. The transaction was ready but the seller did not honour the payment; see the previous frame for details.`
15341
15870
  });
15342
- return;
15343
15871
  }
15344
15872
  if (event.type === "errored") {
15345
- c.error({ code: event.code, message: event.message });
15873
+ return c.error({ code: event.code, message: event.message });
15346
15874
  }
15347
15875
  }
15348
15876
  }
@@ -15351,7 +15879,7 @@ async function* runStatusCommand(c, inflow2, authStorage2) {
15351
15879
  if (!c.agent && !c.formatExplicit) {
15352
15880
  const client2 = await inflow2.mpp.client();
15353
15881
  await renderInkUntilExit(
15354
- /* @__PURE__ */ jsx18(
15882
+ /* @__PURE__ */ jsx21(
15355
15883
  MppStatusView,
15356
15884
  {
15357
15885
  transactionId: c.args.transactionId,
@@ -15389,27 +15917,27 @@ async function* runStatusCommand(c, inflow2, authStorage2) {
15389
15917
  }
15390
15918
  if (event.type === "failed") {
15391
15919
  yield sanitizeDeep(toStatusFrame(event.response, c.options.credentialFile));
15392
- c.error({
15920
+ return c.error({
15393
15921
  code: "PAYMENT_FAILED",
15394
15922
  message: event.response.problem?.detail ?? event.response.problem?.title ?? "MPP transaction failed."
15395
15923
  });
15396
15924
  }
15397
15925
  if (event.type === "expired") {
15398
15926
  yield sanitizeDeep(toStatusFrame(event.response, c.options.credentialFile));
15399
- c.error({ code: "PAYMENT_EXPIRED", message: "MPP transaction expired before it was ready." });
15927
+ return c.error({ code: "PAYMENT_EXPIRED", message: "MPP transaction expired before it was ready." });
15400
15928
  }
15401
15929
  if (event.type === "timedOut") {
15402
15930
  if (event.response !== void 0) {
15403
15931
  yield sanitizeDeep(toStatusFrame(event.response, c.options.credentialFile));
15404
15932
  }
15405
- c.error({
15933
+ return c.error({
15406
15934
  code: "POLLING_TIMEOUT",
15407
15935
  message: "Polling timed out before the transaction reached a ready state.",
15408
15936
  retryable: true
15409
15937
  });
15410
15938
  }
15411
15939
  if (event.type === "crashed") {
15412
- c.error({ code: "PAYMENT_FAILED", message: event.message });
15940
+ return c.error({ code: "PAYMENT_FAILED", message: event.message });
15413
15941
  }
15414
15942
  }
15415
15943
  }
@@ -15417,7 +15945,7 @@ async function runCancelCommand(c, inflow2, authStorage2) {
15417
15945
  assertSessionGuard(c, authStorage2, inflow2);
15418
15946
  if (!c.agent && !c.formatExplicit) {
15419
15947
  await renderInkUntilExit(
15420
- /* @__PURE__ */ jsx18(
15948
+ /* @__PURE__ */ jsx21(
15421
15949
  CancelView,
15422
15950
  {
15423
15951
  approvalId: c.args.approvalId,
@@ -15438,7 +15966,7 @@ async function runDecodeCommand(c) {
15438
15966
  return c.error({ code: "DECODE_FAILED", message: err instanceof Error ? err.message : String(err) });
15439
15967
  }
15440
15968
  if (!c.agent && !c.formatExplicit) {
15441
- await renderInkUntilExit(/* @__PURE__ */ jsx18(DecodeView, { result }));
15969
+ await renderInkUntilExit(/* @__PURE__ */ jsx21(DecodeView, { result }));
15442
15970
  return void 0;
15443
15971
  }
15444
15972
  return sanitizeDeep(result);
@@ -15446,15 +15974,21 @@ async function runDecodeCommand(c) {
15446
15974
  async function runSupportedCommand(c, inflow2, authStorage2) {
15447
15975
  assertSessionGuard(c, authStorage2, inflow2);
15448
15976
  if (!c.agent && !c.formatExplicit) {
15449
- await renderInkUntilExit(/* @__PURE__ */ jsx18(SupportedView, { load: () => inflow2.mpp.supported(), onComplete: () => void 0 }));
15977
+ await renderInkUntilExit(/* @__PURE__ */ jsx21(SupportedView, { load: () => inflow2.mpp.supported(), onComplete: () => void 0 }));
15450
15978
  return void 0;
15451
15979
  }
15452
15980
  const response = await inflow2.mpp.supported();
15453
15981
  return sanitizeDeep(response);
15454
15982
  }
15455
15983
  async function runInspectCommand(c) {
15984
+ let probeOptions;
15985
+ try {
15986
+ probeOptions = probeOptionsFrom(c);
15987
+ } catch (err) {
15988
+ return c.error(invalidHeaderError(err));
15989
+ }
15456
15990
  const deps = {
15457
- probeOptions: probeOptionsFrom(c),
15991
+ probeOptions,
15458
15992
  url: c.args.url,
15459
15993
  ...c.options.paymentMethod !== void 0 ? { paymentMethodFilter: c.options.paymentMethod } : {},
15460
15994
  ...c.options.intent !== void 0 ? { intentFilter: c.options.intent } : {},
@@ -15464,7 +15998,7 @@ async function runInspectCommand(c) {
15464
15998
  if (!c.agent && !c.formatExplicit) {
15465
15999
  let finalPhase = null;
15466
16000
  await renderInkUntilExit(
15467
- /* @__PURE__ */ jsx18(
16001
+ /* @__PURE__ */ jsx21(
15468
16002
  InspectView,
15469
16003
  {
15470
16004
  url: c.args.url,
@@ -15479,7 +16013,7 @@ async function runInspectCommand(c) {
15479
16013
  if (finalPhase !== null) {
15480
16014
  const phase = finalPhase;
15481
16015
  if (phase.kind === "error") {
15482
- c.error({ code: phase.code, message: phase.message });
16016
+ return c.error({ code: phase.code, message: phase.message });
15483
16017
  }
15484
16018
  }
15485
16019
  return void 0;
@@ -15558,8 +16092,8 @@ function createMppCli(inflow2, authStorage2, apiBaseUrl2) {
15558
16092
  });
15559
16093
  cli2.command("inspect", {
15560
16094
  description: "Show the seller's MPP challenge(s) for a URL. Read-only probe \u2014 no auth, no payment.",
15561
- args: inspectArgs,
15562
- options: inspectOptions,
16095
+ args: inspectArgs2,
16096
+ options: inspectOptions2,
15563
16097
  outputPolicy: "agent-only",
15564
16098
  async run(c) {
15565
16099
  return runInspectCommand(c);
@@ -15573,10 +16107,10 @@ import { Cli as Cli5, Errors as Errors2 } from "incur";
15573
16107
  import "react";
15574
16108
 
15575
16109
  // src/commands/user/get.tsx
15576
- import { Box as Box15, Text as Text16 } from "ink";
15577
- import Spinner12 from "ink-spinner";
16110
+ import { Box as Box17, Text as Text18 } from "ink";
16111
+ import Spinner14 from "ink-spinner";
15578
16112
  import { useCallback as useCallback7, useRef as useRef3 } from "react";
15579
- import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
16113
+ import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
15580
16114
  var UserGet = ({ userResource, onComplete }) => {
15581
16115
  const action = useCallback7(() => userResource.retrieve(), [userResource]);
15582
16116
  const { finish } = useFlowExit(onComplete);
@@ -15597,38 +16131,38 @@ var UserGet = ({ userResource, onComplete }) => {
15597
16131
  const { status, data: user, error } = useFlowState(action, handleLinger);
15598
16132
  lastErrorRef.current = error;
15599
16133
  if (status === "loading") {
15600
- return /* @__PURE__ */ jsx19(Box15, { children: /* @__PURE__ */ jsxs15(Text16, { color: "cyan", children: [
15601
- /* @__PURE__ */ jsx19(Spinner12, { type: "dots" }),
16134
+ return /* @__PURE__ */ jsx22(Box17, { children: /* @__PURE__ */ jsxs17(Text18, { color: "cyan", children: [
16135
+ /* @__PURE__ */ jsx22(Spinner14, { type: "dots" }),
15602
16136
  " Loading user..."
15603
16137
  ] }) });
15604
16138
  }
15605
16139
  if (status === "error") {
15606
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", children: [
15607
- /* @__PURE__ */ jsx19(Text16, { color: "red", children: "\u2717 Failed to retrieve user" }),
15608
- /* @__PURE__ */ jsx19(Text16, { color: "red", children: error })
16140
+ return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", children: [
16141
+ /* @__PURE__ */ jsx22(Text18, { color: "red", children: "\u2717 Failed to retrieve user" }),
16142
+ /* @__PURE__ */ jsx22(Text18, { color: "red", children: error })
15609
16143
  ] });
15610
16144
  }
15611
16145
  if (user === null) return null;
15612
16146
  const rows = buildProfileRows(user);
15613
- return /* @__PURE__ */ jsx19(Box15, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: rows.map((row) => /* @__PURE__ */ jsxs15(Text16, { children: [
16147
+ return /* @__PURE__ */ jsx22(Box17, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: rows.map((row) => /* @__PURE__ */ jsxs17(Text18, { children: [
15614
16148
  `${row.label}: `,
15615
- row.value !== null ? /* @__PURE__ */ jsx19(Text16, { bold: true, children: row.value }) : /* @__PURE__ */ jsx19(Text16, { dimColor: true, children: "\u2014" })
16149
+ row.value !== null ? /* @__PURE__ */ jsx22(Text18, { bold: true, children: row.value }) : /* @__PURE__ */ jsx22(Text18, { dimColor: true, children: "\u2014" })
15616
16150
  ] }, row.label)) });
15617
16151
  };
15618
16152
 
15619
16153
  // src/commands/user/schema.ts
15620
- import { z as z5 } from "incur";
15621
- var getOptions = z5.object({});
16154
+ import { z as z6 } from "incur";
16155
+ var getOptions = z6.object({});
15622
16156
 
15623
16157
  // src/commands/user/index.tsx
15624
- import { jsx as jsx20 } from "react/jsx-runtime";
16158
+ import { jsx as jsx23 } from "react/jsx-runtime";
15625
16159
  var TTY_NO_RESULT_MESSAGE = "inflow user get exited without producing a result.";
15626
16160
  async function runUserGet2(c, deps) {
15627
16161
  assertSessionGuard(c, deps.authStorage, deps.inflow);
15628
16162
  if (!c.agent && !c.formatExplicit) {
15629
16163
  let captured = null;
15630
16164
  const outcome = await renderInkUntilExit(
15631
- /* @__PURE__ */ jsx20(
16165
+ /* @__PURE__ */ jsx23(
15632
16166
  UserGet,
15633
16167
  {
15634
16168
  userResource: deps.user,
@@ -15674,23 +16208,23 @@ import { resolve as resolvePath3 } from "path";
15674
16208
  import { Cli as Cli6 } from "incur";
15675
16209
 
15676
16210
  // src/commands/x402/cancel.tsx
15677
- import { Box as Box16, Text as Text17 } from "ink";
15678
- import Spinner13 from "ink-spinner";
16211
+ import { Box as Box18, Text as Text19 } from "ink";
16212
+ import Spinner15 from "ink-spinner";
15679
16213
  import { useCallback as useCallback8 } from "react";
15680
- import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
16214
+ import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
15681
16215
  var CancelView2 = ({ approvalId, cancel, onComplete }) => {
15682
16216
  const action = useCallback8(() => cancel(), [cancel]);
15683
16217
  const { finish } = useFlowExit(onComplete);
15684
16218
  const { status } = useFlowState(action, finish);
15685
16219
  if (status === "loading") {
15686
- return /* @__PURE__ */ jsx21(Box16, { children: /* @__PURE__ */ jsxs16(Text17, { color: "cyan", children: [
15687
- /* @__PURE__ */ jsx21(Spinner13, { type: "dots" }),
16220
+ return /* @__PURE__ */ jsx24(Box18, { children: /* @__PURE__ */ jsxs18(Text19, { color: "cyan", children: [
16221
+ /* @__PURE__ */ jsx24(Spinner15, { type: "dots" }),
15688
16222
  " Cancelling approval ",
15689
16223
  approvalId,
15690
16224
  "..."
15691
16225
  ] }) });
15692
16226
  }
15693
- return /* @__PURE__ */ jsx21(Box16, { children: /* @__PURE__ */ jsxs16(Text17, { color: "green", children: [
16227
+ return /* @__PURE__ */ jsx24(Box18, { children: /* @__PURE__ */ jsxs18(Text19, { color: "green", children: [
15694
16228
  "\u2713 Cancelled approval ",
15695
16229
  approvalId,
15696
16230
  " (best-effort)"
@@ -15698,166 +16232,44 @@ var CancelView2 = ({ approvalId, cancel, onComplete }) => {
15698
16232
  };
15699
16233
 
15700
16234
  // src/commands/x402/decode.tsx
15701
- import { fromFoundationRequirements as fromFoundationRequirements2 } from "@inflowpayai/x402-buyer";
15702
- import { Box as Box17, Text as Text18 } from "ink";
15703
- import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
16235
+ import { fromFoundationRequirements as fromFoundationRequirements3 } from "@inflowpayai/x402-buyer";
16236
+ import { Box as Box19, Text as Text20 } from "ink";
16237
+ import { jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
15704
16238
  var DecodeView2 = ({ decoded }) => {
15705
- const summary = summarizeAccepts(fromFoundationRequirements2(decoded.accepts));
15706
- return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", paddingY: 1, children: [
15707
- /* @__PURE__ */ jsx22(Box17, { marginBottom: 1, children: /* @__PURE__ */ jsx22(Text18, { bold: true, children: "Decoded PAYMENT-REQUIRED" }) }),
15708
- /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [
15709
- /* @__PURE__ */ jsxs17(Text18, { children: [
16239
+ const summary = summarizeAccepts(fromFoundationRequirements3(decoded.accepts));
16240
+ return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", paddingY: 1, children: [
16241
+ /* @__PURE__ */ jsx25(Box19, { marginBottom: 1, children: /* @__PURE__ */ jsx25(Text20, { bold: true, children: "Decoded PAYMENT-REQUIRED" }) }),
16242
+ /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [
16243
+ /* @__PURE__ */ jsxs19(Text20, { children: [
15710
16244
  "x402Version: ",
15711
- /* @__PURE__ */ jsx22(Text18, { color: "cyan", children: String(decoded.x402Version) })
16245
+ /* @__PURE__ */ jsx25(Text20, { color: "cyan", children: String(decoded.x402Version) })
15712
16246
  ] }),
15713
- /* @__PURE__ */ jsxs17(Text18, { children: [
16247
+ /* @__PURE__ */ jsxs19(Text20, { children: [
15714
16248
  "resource: ",
15715
- /* @__PURE__ */ jsx22(Text18, { color: "cyan", children: decoded.resource.url })
16249
+ /* @__PURE__ */ jsx25(Text20, { color: "cyan", children: decoded.resource.url })
15716
16250
  ] }),
15717
- /* @__PURE__ */ jsx22(Text18, { children: `accepts (${String(summary.length)}):` }),
15718
- summary.map((entry, idx) => /* @__PURE__ */ jsxs17(Text18, { children: [
16251
+ /* @__PURE__ */ jsx25(Text20, { children: `accepts (${String(summary.length)}):` }),
16252
+ summary.map((entry, idx) => /* @__PURE__ */ jsxs19(Text20, { children: [
15719
16253
  " ",
15720
- /* @__PURE__ */ jsx22(Text18, { color: "yellow", children: entry.scheme }),
16254
+ /* @__PURE__ */ jsx25(Text20, { color: "yellow", children: entry.scheme }),
15721
16255
  " / ",
15722
- /* @__PURE__ */ jsx22(Text18, { color: "yellow", children: entry.network }),
16256
+ /* @__PURE__ */ jsx25(Text20, { color: "yellow", children: entry.network }),
15723
16257
  entry.amount !== void 0 ? ` \xB7 amount ${entry.amount}` : "",
15724
16258
  entry.asset !== void 0 ? ` \xB7 ${entry.asset}` : ""
15725
16259
  ] }, `${entry.scheme}-${entry.network}-${String(idx)}`)),
15726
- decoded.extensions !== void 0 ? /* @__PURE__ */ jsx22(Text18, { dimColor: true, children: `extensions: ${Object.keys(decoded.extensions).join(", ")}` }) : null
16260
+ decoded.extensions !== void 0 ? /* @__PURE__ */ jsx25(Text20, { dimColor: true, children: `extensions: ${Object.keys(decoded.extensions).join(", ")}` }) : null
15727
16261
  ] })
15728
16262
  ] });
15729
16263
  };
15730
16264
 
15731
- // src/commands/x402/inspect.tsx
15732
- import { Box as Box18, Text as Text19 } from "ink";
15733
- import Spinner14 from "ink-spinner";
15734
- import { useEffect as useEffect9, useReducer as useReducer7 } from "react";
15735
- import { jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
15736
- function summarizeExtra(extra) {
15737
- if (extra === void 0) return "\u2014";
15738
- const keys = Object.keys(extra);
15739
- if (keys.length === 0) return "\u2014";
15740
- return [...keys].sort((a, b) => a.localeCompare(b)).join(", ");
15741
- }
15742
- function formatTimeout(seconds) {
15743
- return `${String(seconds)}s`;
15744
- }
15745
- function formatAsset(asset) {
15746
- return asset === "" ? "\u2014" : asset;
15747
- }
15748
- var COLUMNS5 = [
15749
- { header: "Scheme", cell: (r) => r.scheme },
15750
- { header: "Network", cell: (r) => r.network },
15751
- { header: "Amount", cell: (r) => r.amount },
15752
- { header: "Asset", cell: (r) => formatAsset(r.asset) },
15753
- { header: "Pay To", cell: (r) => r.payTo },
15754
- { header: "Timeout", cell: (r) => formatTimeout(r.maxTimeoutSeconds) },
15755
- { header: "Extra", cell: (r) => summarizeExtra(r.extra) }
15756
- ];
15757
- var InspectView2 = ({ url, method, deps, onComplete }) => {
15758
- const initial = { kind: "probing" };
15759
- const [phase, dispatch] = useReducer7(reduceX402Inspect, initial);
15760
- const { finish } = useFlowExit(onComplete);
15761
- useEffect9(() => {
15762
- let cancelled = false;
15763
- void runInspectPipeline(deps, (event) => {
15764
- if (!cancelled) dispatch(event);
15765
- });
15766
- return () => {
15767
- cancelled = true;
15768
- };
15769
- }, [deps]);
15770
- useEffect9(() => {
15771
- if (phase.kind === "accepts" || phase.kind === "no-payment" || phase.kind === "error") {
15772
- finish(phase);
15773
- }
15774
- }, [phase, finish]);
15775
- if (phase.kind === "probing") {
15776
- return /* @__PURE__ */ jsx23(Box18, { children: /* @__PURE__ */ jsxs18(Text19, { color: "cyan", children: [
15777
- /* @__PURE__ */ jsx23(Spinner14, { type: "dots" }),
15778
- " Probing ",
15779
- method,
15780
- " ",
15781
- url,
15782
- "..."
15783
- ] }) });
15784
- }
15785
- if (phase.kind === "no-payment") {
15786
- return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", children: [
15787
- /* @__PURE__ */ jsx23(Text19, { color: "green", children: "\u2713 Seller accepted without payment" }),
15788
- /* @__PURE__ */ jsx23(Text19, { dimColor: true, children: "Use `x402 pay` to fetch the body." })
15789
- ] });
15790
- }
15791
- if (phase.kind === "error") {
15792
- return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", children: [
15793
- /* @__PURE__ */ jsxs18(Text19, { color: "red", children: [
15794
- "\u2717 ",
15795
- phase.code
15796
- ] }),
15797
- /* @__PURE__ */ jsx23(Text19, { color: "red", children: phase.message })
15798
- ] });
15799
- }
15800
- const { result } = phase;
15801
- const acceptsCount = result.accepts.length;
15802
- const extensionsLine = result.extensions !== void 0 ? Object.keys(result.extensions).join(", ") : null;
15803
- return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", children: [
15804
- /* @__PURE__ */ jsxs18(Text19, { children: [
15805
- /* @__PURE__ */ jsx23(Text19, { bold: true, children: "PAYMENT-REQUIRED" }),
15806
- " for ",
15807
- /* @__PURE__ */ jsx23(Text19, { color: "cyan", children: result.resource }),
15808
- " \xB7 ",
15809
- /* @__PURE__ */ jsx23(Text19, { dimColor: true, children: `x402Version ${String(result.x402Version)}` }),
15810
- " \xB7 ",
15811
- /* @__PURE__ */ jsx23(Text19, { dimColor: true, children: `${String(acceptsCount)} accept${acceptsCount === 1 ? "" : "s"}` })
15812
- ] }),
15813
- extensionsLine !== null ? /* @__PURE__ */ jsx23(Text19, { dimColor: true, children: `extensions: ${extensionsLine}` }) : null,
15814
- /* @__PURE__ */ jsx23(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx23(Table, { columns: COLUMNS5, rows: result.accepts }) }),
15815
- /* @__PURE__ */ jsx23(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx23(Text19, { dimColor: true, children: "Use --format json to inspect extras values." }) })
15816
- ] });
15817
- };
15818
- function buildAcceptsFrame(result) {
15819
- const frame = {
15820
- outcome: "accepts",
15821
- url: result.url,
15822
- method: result.method,
15823
- resource: result.resource,
15824
- x402_version: result.x402Version,
15825
- accepts: result.accepts.map((entry) => {
15826
- const row = {
15827
- scheme: entry.scheme,
15828
- network: entry.network,
15829
- amount: entry.amount,
15830
- asset: entry.asset,
15831
- pay_to: entry.payTo,
15832
- max_timeout_seconds: entry.maxTimeoutSeconds
15833
- };
15834
- if (entry.extra !== void 0) row.extra = entry.extra;
15835
- return row;
15836
- })
15837
- };
15838
- if (result.extensions !== void 0) frame.extensions = result.extensions;
15839
- return frame;
15840
- }
15841
- function buildNoPaymentFrame2(result) {
15842
- const frame = {
15843
- outcome: "no-payment-required",
15844
- url: result.url,
15845
- method: result.method,
15846
- status: result.status,
15847
- body_size_bytes: result.bodySizeBytes
15848
- };
15849
- if (result.contentType !== void 0) frame.content_type = result.contentType;
15850
- return frame;
15851
- }
15852
-
15853
16265
  // src/commands/x402/pay.tsx
15854
- import { Box as Box19, Text as Text20, useInput as useInput4 } from "ink";
15855
- import Spinner15 from "ink-spinner";
15856
- import { useEffect as useEffect10, useReducer as useReducer8, useState as useState4 } from "react";
15857
- import { jsx as jsx24, jsxs as jsxs19 } from "react/jsx-runtime";
16266
+ import { Box as Box20, Text as Text21, useInput as useInput4 } from "ink";
16267
+ import Spinner16 from "ink-spinner";
16268
+ import { useEffect as useEffect11, useReducer as useReducer9, useState as useState4 } from "react";
16269
+ import { jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
15858
16270
  var PayView2 = ({ url, method, deps, onComplete, onCancel }) => {
15859
16271
  const initial = { kind: "probing" };
15860
- const [phase, dispatch] = useReducer8(reducePay, initial);
16272
+ const [phase, dispatch] = useReducer9(reducePay, initial);
15861
16273
  const [cancelling, setCancelling] = useState4(false);
15862
16274
  const { finish, cancelThenFinish } = useFlowExit(onComplete);
15863
16275
  useInput4(
@@ -15879,7 +16291,7 @@ var PayView2 = ({ url, method, deps, onComplete, onCancel }) => {
15879
16291
  },
15880
16292
  { isActive: phase.kind === "awaiting-approval" && !cancelling }
15881
16293
  );
15882
- useEffect10(() => {
16294
+ useEffect11(() => {
15883
16295
  const controller = new AbortController();
15884
16296
  let cancelled = false;
15885
16297
  const runDeps = { ...deps, signOptions: { ...deps.signOptions, signal: controller.signal } };
@@ -15891,20 +16303,20 @@ var PayView2 = ({ url, method, deps, onComplete, onCancel }) => {
15891
16303
  controller.abort();
15892
16304
  };
15893
16305
  }, [deps]);
15894
- useEffect10(() => {
16306
+ useEffect11(() => {
15895
16307
  if (phase.kind === "success" || phase.kind === "replay-rejected" || phase.kind === "no-payment-final" || phase.kind === "error") {
15896
16308
  finish(phase);
15897
16309
  }
15898
16310
  }, [phase, finish]);
15899
16311
  if (cancelling) {
15900
- return /* @__PURE__ */ jsx24(Box19, { children: /* @__PURE__ */ jsxs19(Text20, { color: "yellow", children: [
15901
- /* @__PURE__ */ jsx24(Spinner15, { type: "dots" }),
16312
+ return /* @__PURE__ */ jsx26(Box20, { children: /* @__PURE__ */ jsxs20(Text21, { color: "yellow", children: [
16313
+ /* @__PURE__ */ jsx26(Spinner16, { type: "dots" }),
15902
16314
  " Cancelling approval..."
15903
16315
  ] }) });
15904
16316
  }
15905
16317
  if (phase.kind === "probing") {
15906
- return /* @__PURE__ */ jsx24(Box19, { children: /* @__PURE__ */ jsxs19(Text20, { color: "cyan", children: [
15907
- /* @__PURE__ */ jsx24(Spinner15, { type: "dots" }),
16318
+ return /* @__PURE__ */ jsx26(Box20, { children: /* @__PURE__ */ jsxs20(Text21, { color: "cyan", children: [
16319
+ /* @__PURE__ */ jsx26(Spinner16, { type: "dots" }),
15908
16320
  " Probing ",
15909
16321
  method,
15910
16322
  " ",
@@ -15913,23 +16325,23 @@ var PayView2 = ({ url, method, deps, onComplete, onCancel }) => {
15913
16325
  ] }) });
15914
16326
  }
15915
16327
  if (phase.kind === "no-payment") {
15916
- return /* @__PURE__ */ jsx24(Box19, { children: /* @__PURE__ */ jsxs19(Text20, { color: "cyan", children: [
15917
- /* @__PURE__ */ jsx24(Spinner15, { type: "dots" }),
16328
+ return /* @__PURE__ */ jsx26(Box20, { children: /* @__PURE__ */ jsxs20(Text21, { color: "cyan", children: [
16329
+ /* @__PURE__ */ jsx26(Spinner16, { type: "dots" }),
15918
16330
  " Seller accepted without payment (status ",
15919
16331
  String(phase.probe.status),
15920
16332
  "); finalising..."
15921
16333
  ] }) });
15922
16334
  }
15923
16335
  if (phase.kind === "matching") {
15924
- return /* @__PURE__ */ jsx24(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsxs19(Text20, { color: "cyan", children: [
15925
- /* @__PURE__ */ jsx24(Spinner15, { type: "dots" }),
16336
+ return /* @__PURE__ */ jsx26(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsxs20(Text21, { color: "cyan", children: [
16337
+ /* @__PURE__ */ jsx26(Spinner16, { type: "dots" }),
15926
16338
  " Decoding seller requirements..."
15927
16339
  ] }) });
15928
16340
  }
15929
16341
  if (phase.kind === "preparing") {
15930
16342
  const summary = summarizeAccepts([phase.requirement]);
15931
- return /* @__PURE__ */ jsx24(Box19, { flexDirection: "column", children: /* @__PURE__ */ jsxs19(Text20, { color: "cyan", children: [
15932
- /* @__PURE__ */ jsx24(Spinner15, { type: "dots" }),
16343
+ return /* @__PURE__ */ jsx26(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsxs20(Text21, { color: "cyan", children: [
16344
+ /* @__PURE__ */ jsx26(Spinner16, { type: "dots" }),
15933
16345
  " Preparing payment (",
15934
16346
  summary[0]?.scheme ?? phase.requirement.scheme,
15935
16347
  " /",
@@ -15939,167 +16351,167 @@ var PayView2 = ({ url, method, deps, onComplete, onCancel }) => {
15939
16351
  ] }) });
15940
16352
  }
15941
16353
  if (phase.kind === "awaiting-approval") {
15942
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", paddingY: 1, children: [
15943
- /* @__PURE__ */ jsx24(Box19, { marginBottom: 1, children: /* @__PURE__ */ jsx24(Text20, { bold: true, children: "Approval required" }) }),
15944
- /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [
15945
- /* @__PURE__ */ jsxs19(Text20, { children: [
16354
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", paddingY: 1, children: [
16355
+ /* @__PURE__ */ jsx26(Box20, { marginBottom: 1, children: /* @__PURE__ */ jsx26(Text21, { bold: true, children: "Approval required" }) }),
16356
+ /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, children: [
16357
+ /* @__PURE__ */ jsxs20(Text21, { children: [
15946
16358
  "Open: ",
15947
- /* @__PURE__ */ jsx24(Text20, { bold: true, color: "cyan", children: phase.approvalUrl })
16359
+ /* @__PURE__ */ jsx26(Text21, { bold: true, color: "cyan", children: phase.approvalUrl })
15948
16360
  ] }),
15949
- /* @__PURE__ */ jsx24(Text20, { dimColor: true, children: "Press Enter to open in browser." }),
15950
- /* @__PURE__ */ jsx24(Text20, { dimColor: true, children: "Press Escape to cancel." })
16361
+ /* @__PURE__ */ jsx26(Text21, { dimColor: true, children: "Press Enter to open in browser." }),
16362
+ /* @__PURE__ */ jsx26(Text21, { dimColor: true, children: "Press Escape to cancel." })
15951
16363
  ] }),
15952
- /* @__PURE__ */ jsx24(Box19, { marginTop: 1, children: /* @__PURE__ */ jsxs19(Text20, { color: "cyan", children: [
15953
- /* @__PURE__ */ jsx24(Spinner15, { type: "dots" }),
16364
+ /* @__PURE__ */ jsx26(Box20, { marginTop: 1, children: /* @__PURE__ */ jsxs20(Text21, { color: "cyan", children: [
16365
+ /* @__PURE__ */ jsx26(Spinner16, { type: "dots" }),
15954
16366
  " Waiting for approval..."
15955
16367
  ] }) })
15956
16368
  ] });
15957
16369
  }
15958
16370
  if (phase.kind === "replaying") {
15959
- return /* @__PURE__ */ jsx24(Box19, { children: /* @__PURE__ */ jsxs19(Text20, { color: "cyan", children: [
15960
- /* @__PURE__ */ jsx24(Spinner15, { type: "dots" }),
16371
+ return /* @__PURE__ */ jsx26(Box20, { children: /* @__PURE__ */ jsxs20(Text21, { color: "cyan", children: [
16372
+ /* @__PURE__ */ jsx26(Spinner16, { type: "dots" }),
15961
16373
  " Replaying request with PAYMENT-SIGNATURE..."
15962
16374
  ] }) });
15963
16375
  }
15964
16376
  if (phase.kind === "success") {
15965
16377
  const { result } = phase;
15966
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", children: [
15967
- /* @__PURE__ */ jsxs19(Text20, { color: "green", children: [
16378
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
16379
+ /* @__PURE__ */ jsxs20(Text21, { color: "green", children: [
15968
16380
  "\u2713 Paid ",
15969
16381
  result.scheme,
15970
16382
  " / ",
15971
16383
  result.network
15972
16384
  ] }),
15973
- /* @__PURE__ */ jsx24(Text20, { children: `transaction: ${result.transactionId}` }),
15974
- result.settled?.network !== void 0 ? /* @__PURE__ */ jsx24(Text20, { children: `settled via: ${result.settled.network}${result.settled.transaction !== void 0 ? ` (${result.settled.transaction})` : ""}` }) : null,
15975
- result.outputSavedTo !== void 0 ? /* @__PURE__ */ jsxs19(Text20, { children: [
16385
+ /* @__PURE__ */ jsx26(Text21, { children: `transaction: ${result.transactionId}` }),
16386
+ result.settled?.network !== void 0 ? /* @__PURE__ */ jsx26(Text21, { children: `settled via: ${result.settled.network}${result.settled.transaction !== void 0 ? ` (${result.settled.transaction})` : ""}` }) : null,
16387
+ result.outputSavedTo !== void 0 ? /* @__PURE__ */ jsxs20(Text21, { children: [
15976
16388
  "Saved to: ",
15977
- /* @__PURE__ */ jsx24(Text20, { bold: true, children: result.outputSavedTo })
16389
+ /* @__PURE__ */ jsx26(Text21, { bold: true, children: result.outputSavedTo })
15978
16390
  ] }) : null,
15979
- result.body !== void 0 ? /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, flexDirection: "column", children: [
15980
- /* @__PURE__ */ jsx24(Text20, { dimColor: true, children: "response body:" }),
15981
- /* @__PURE__ */ jsx24(Text20, { children: result.body })
16391
+ result.body !== void 0 ? /* @__PURE__ */ jsxs20(Box20, { marginTop: 1, flexDirection: "column", children: [
16392
+ /* @__PURE__ */ jsx26(Text21, { dimColor: true, children: "response body:" }),
16393
+ /* @__PURE__ */ jsx26(Text21, { children: result.body })
15982
16394
  ] }) : null
15983
16395
  ] });
15984
16396
  }
15985
16397
  if (phase.kind === "replay-rejected") {
15986
16398
  const { result } = phase;
15987
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", children: [
15988
- /* @__PURE__ */ jsxs19(Text20, { color: "red", children: [
16399
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
16400
+ /* @__PURE__ */ jsxs20(Text21, { color: "red", children: [
15989
16401
  "\u2717 Payment not accepted (",
15990
16402
  result.scheme,
15991
16403
  " / ",
15992
16404
  result.network,
15993
16405
  ")"
15994
16406
  ] }),
15995
- /* @__PURE__ */ jsx24(Text20, { children: `transaction: ${result.transactionId}` }),
15996
- /* @__PURE__ */ jsx24(Text20, { children: `approval: ${result.approvalId}` }),
15997
- /* @__PURE__ */ jsx24(Text20, { children: `approval url: ${result.approvalUrl}` }),
15998
- result.outputSavedTo !== void 0 ? /* @__PURE__ */ jsxs19(Text20, { children: [
16407
+ /* @__PURE__ */ jsx26(Text21, { children: `transaction: ${result.transactionId}` }),
16408
+ /* @__PURE__ */ jsx26(Text21, { children: `approval: ${result.approvalId}` }),
16409
+ /* @__PURE__ */ jsx26(Text21, { children: `approval url: ${result.approvalUrl}` }),
16410
+ result.outputSavedTo !== void 0 ? /* @__PURE__ */ jsxs20(Text21, { children: [
15999
16411
  "Saved to: ",
16000
- /* @__PURE__ */ jsx24(Text20, { bold: true, children: result.outputSavedTo })
16412
+ /* @__PURE__ */ jsx26(Text21, { bold: true, children: result.outputSavedTo })
16001
16413
  ] }) : null,
16002
- result.body !== void 0 ? /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, flexDirection: "column", children: [
16003
- /* @__PURE__ */ jsx24(Text20, { dimColor: true, children: "response body:" }),
16004
- /* @__PURE__ */ jsx24(Text20, { children: result.body })
16414
+ result.body !== void 0 ? /* @__PURE__ */ jsxs20(Box20, { marginTop: 1, flexDirection: "column", children: [
16415
+ /* @__PURE__ */ jsx26(Text21, { dimColor: true, children: "response body:" }),
16416
+ /* @__PURE__ */ jsx26(Text21, { children: result.body })
16005
16417
  ] }) : null
16006
16418
  ] });
16007
16419
  }
16008
16420
  if (phase.kind === "no-payment-final") {
16009
16421
  const { result } = phase;
16010
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", children: [
16011
- /* @__PURE__ */ jsx24(Text20, { color: "green", children: "\u2713 Seller accepted without payment" }),
16012
- result.outputSavedTo !== void 0 ? /* @__PURE__ */ jsxs19(Text20, { children: [
16422
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
16423
+ /* @__PURE__ */ jsx26(Text21, { color: "green", children: "\u2713 Seller accepted without payment" }),
16424
+ result.outputSavedTo !== void 0 ? /* @__PURE__ */ jsxs20(Text21, { children: [
16013
16425
  "Saved to: ",
16014
- /* @__PURE__ */ jsx24(Text20, { bold: true, children: result.outputSavedTo })
16426
+ /* @__PURE__ */ jsx26(Text21, { bold: true, children: result.outputSavedTo })
16015
16427
  ] }) : null,
16016
- result.body !== void 0 ? /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, flexDirection: "column", children: [
16017
- /* @__PURE__ */ jsx24(Text20, { dimColor: true, children: "response body:" }),
16018
- /* @__PURE__ */ jsx24(Text20, { children: result.body })
16428
+ result.body !== void 0 ? /* @__PURE__ */ jsxs20(Box20, { marginTop: 1, flexDirection: "column", children: [
16429
+ /* @__PURE__ */ jsx26(Text21, { dimColor: true, children: "response body:" }),
16430
+ /* @__PURE__ */ jsx26(Text21, { children: result.body })
16019
16431
  ] }) : null
16020
16432
  ] });
16021
16433
  }
16022
- return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", children: [
16023
- /* @__PURE__ */ jsxs19(Text20, { color: "red", children: [
16434
+ return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
16435
+ /* @__PURE__ */ jsxs20(Text21, { color: "red", children: [
16024
16436
  "\u2717 ",
16025
16437
  phase.code
16026
16438
  ] }),
16027
- /* @__PURE__ */ jsx24(Text20, { color: "red", children: phase.message })
16439
+ /* @__PURE__ */ jsx26(Text21, { color: "red", children: phase.message })
16028
16440
  ] });
16029
16441
  };
16030
16442
 
16031
16443
  // src/commands/x402/schema.ts
16032
- import { z as z6 } from "incur";
16033
- var payArgs2 = z6.object({
16034
- url: z6.string().describe("The x402-protected resource URL to pay for.")
16444
+ import { z as z7 } from "incur";
16445
+ var payArgs2 = z7.object({
16446
+ url: z7.string().describe("The x402-protected resource URL to pay for.")
16035
16447
  });
16036
- var payOptions2 = z6.object({
16037
- scheme: z6.string().optional().describe('Only consider `accepts[]` entries with this scheme (e.g. "exact", "balance").'),
16038
- network: z6.string().optional().describe('Only consider entries on this network (e.g. "eip155:84532").'),
16039
- asset: z6.string().optional().describe("Only consider entries with this on-chain asset id (ERC-20 address or SVM mint)."),
16040
- assetName: z6.string().optional().describe('Only consider entries whose `extra.assetName` symbol matches (e.g. "USDC").'),
16041
- method: z6.string().default("GET").describe("HTTP method for the seller request."),
16042
- data: z6.string().optional().describe(
16448
+ var payOptions2 = z7.object({
16449
+ scheme: z7.string().optional().describe('Only consider `accepts[]` entries with this scheme (e.g. "exact", "balance").'),
16450
+ network: z7.string().optional().describe('Only consider entries on this network (e.g. "eip155:84532").'),
16451
+ asset: z7.string().optional().describe("Only consider entries with this on-chain asset id (ERC-20 address or SVM mint)."),
16452
+ assetName: z7.string().optional().describe('Only consider entries whose `extra.assetName` symbol matches (e.g. "USDC").'),
16453
+ method: z7.string().default("GET").describe("HTTP method for the seller request."),
16454
+ data: z7.string().optional().describe(
16043
16455
  "Request body. JSON or raw text. Content-Type defaults to application/json when --data is set unless a --header overrides it."
16044
16456
  ),
16045
- header: z6.array(z6.string()).default([]).describe('Repeatable. "Name: Value" format.'),
16046
- interval: z6.coerce.number().default(0).describe(
16457
+ header: z7.array(z7.string()).default([]).describe('Repeatable. "Name: Value" format.'),
16458
+ interval: z7.coerce.number().default(0).describe(
16047
16459
  "Inline poll cadence in seconds while awaiting approval. 0 returns the approval URL and a follow-up command hint without blocking."
16048
16460
  ),
16049
- maxAttempts: z6.coerce.number().default(0).describe("Hard cap on poll attempts when --interval > 0. 0 means unlimited."),
16050
- timeout: z6.coerce.number().default(900).describe("Polling deadline in seconds. Default 900s (matches x402-buyer)."),
16051
- paymentId: z6.string().min(16).max(128).regex(/^[a-zA-Z0-9_-]+$/).optional().describe(
16461
+ maxAttempts: z7.coerce.number().default(0).describe("Hard cap on poll attempts when --interval > 0. 0 means unlimited."),
16462
+ timeout: z7.coerce.number().default(900).describe("Polling deadline in seconds. Default 900s (matches x402-buyer)."),
16463
+ paymentId: z7.string().min(16).max(128).regex(/^[a-zA-Z0-9_-]+$/).optional().describe(
16052
16464
  "Caller-supplied payment identifier. 16-128 chars, ^[a-zA-Z0-9_-]+$. Forwarded to the server as remotePaymentId."
16053
16465
  ),
16054
- showBody: z6.boolean().default(true).describe(
16466
+ showBody: z7.boolean().default(true).describe(
16055
16467
  "Include the seller response body in the result. Default true so AI assistants paying for content receive the deliverable. Pass --no-show-body to suppress (e.g. for binary downloads paired with --output-file)."
16056
16468
  ),
16057
- outputFile: z6.string().optional().describe(
16469
+ outputFile: z7.string().optional().describe(
16058
16470
  "Write the seller response body bytes to this file path (overwrites silently). When set, the result frame includes `output_saved_to: <absolute_path>` instead of `body` / `body_base64`. Natural choice for binary content (PDFs, images, downloads)."
16059
16471
  ),
16060
- payloadFile: z6.string().optional().describe(
16472
+ payloadFile: z7.string().optional().describe(
16061
16473
  "Write the signed `encoded_payload` bytes to this file path (mode 0o600, overwrites silently). When set, the result frame includes `payload_saved_to: <absolute_path>` instead of `encoded_payload`. Use to keep one-time payment credentials out of chat transcripts and logs."
16062
16474
  )
16063
16475
  });
16064
- var statusArgs2 = z6.object({
16065
- transactionId: z6.string().describe("The transaction id returned by `x402 pay`.")
16476
+ var statusArgs2 = z7.object({
16477
+ transactionId: z7.string().describe("The transaction id returned by `x402 pay`.")
16066
16478
  });
16067
- var statusOptions3 = z6.object({
16068
- interval: z6.coerce.number().default(0).describe(
16479
+ var statusOptions3 = z7.object({
16480
+ interval: z7.coerce.number().default(0).describe(
16069
16481
  "Poll cadence in seconds. 0 returns the current snapshot; positive values yield on every change until signed or terminal."
16070
16482
  ),
16071
- maxAttempts: z6.coerce.number().default(0).describe("Hard cap on poll attempts. 0 means unlimited."),
16072
- timeout: z6.coerce.number().default(900).describe("Polling deadline in seconds."),
16073
- payloadFile: z6.string().optional().describe(
16483
+ maxAttempts: z7.coerce.number().default(0).describe("Hard cap on poll attempts. 0 means unlimited."),
16484
+ timeout: z7.coerce.number().default(900).describe("Polling deadline in seconds."),
16485
+ payloadFile: z7.string().optional().describe(
16074
16486
  "Write the signed `encoded_payload` bytes to this file path (mode 0o600, overwrites silently). When set, status frames include `payload_saved_to: <absolute_path>` instead of `encoded_payload`. Use to keep one-time payment credentials out of chat transcripts and logs."
16075
16487
  )
16076
16488
  });
16077
- var cancelArgs2 = z6.object({
16078
- approvalId: z6.string().describe("The approval id returned by `x402 pay`.")
16489
+ var cancelArgs2 = z7.object({
16490
+ approvalId: z7.string().describe("The approval id returned by `x402 pay`.")
16079
16491
  });
16080
- var decodeArgs2 = z6.object({
16081
- header: z6.string().describe("Raw PAYMENT-REQUIRED header value (base64).")
16492
+ var decodeArgs2 = z7.object({
16493
+ header: z7.string().describe("Raw PAYMENT-REQUIRED header value (base64).")
16082
16494
  });
16083
- var inspectArgs2 = z6.object({
16084
- url: z6.string().describe("The x402-protected resource URL to probe. No payment is made.")
16495
+ var inspectArgs3 = z7.object({
16496
+ url: z7.string().describe("The x402-protected resource URL to probe. No payment is made.")
16085
16497
  });
16086
- var inspectOptions2 = z6.object({
16087
- scheme: z6.string().optional().describe('Only show `accepts[]` entries with this scheme (e.g. "exact", "balance").'),
16088
- network: z6.string().optional().describe('Only show entries on this network (e.g. "eip155:84532").'),
16089
- asset: z6.string().optional().describe("Only show entries with this on-chain asset id (ERC-20 address or SVM mint)."),
16090
- assetName: z6.string().optional().describe('Only show entries whose `extra.assetName` symbol matches (e.g. "USDC").'),
16091
- method: z6.string().default("GET").describe("HTTP method for the probe request."),
16092
- data: z6.string().optional().describe(
16498
+ var inspectOptions3 = z7.object({
16499
+ scheme: z7.string().optional().describe('Only show `accepts[]` entries with this scheme (e.g. "exact", "balance").'),
16500
+ network: z7.string().optional().describe('Only show entries on this network (e.g. "eip155:84532").'),
16501
+ asset: z7.string().optional().describe("Only show entries with this on-chain asset id (ERC-20 address or SVM mint)."),
16502
+ assetName: z7.string().optional().describe('Only show entries whose `extra.assetName` symbol matches (e.g. "USDC").'),
16503
+ method: z7.string().default("GET").describe("HTTP method for the probe request."),
16504
+ data: z7.string().optional().describe(
16093
16505
  "Request body for the probe. JSON or raw text. Content-Type defaults to application/json when --data is set unless a --header overrides it."
16094
16506
  ),
16095
- header: z6.array(z6.string()).default([]).describe('Repeatable. "Name: Value" format.')
16507
+ header: z7.array(z7.string()).default([]).describe('Repeatable. "Name: Value" format.')
16096
16508
  });
16097
16509
 
16098
16510
  // src/commands/x402/status.tsx
16099
- import { Box as Box20, Text as Text21 } from "ink";
16100
- import Spinner16 from "ink-spinner";
16101
- import { useEffect as useEffect11, useReducer as useReducer9 } from "react";
16102
- import { jsx as jsx25, jsxs as jsxs20 } from "react/jsx-runtime";
16511
+ import { Box as Box21, Text as Text22 } from "ink";
16512
+ import Spinner17 from "ink-spinner";
16513
+ import { useEffect as useEffect12, useReducer as useReducer10 } from "react";
16514
+ import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
16103
16515
  var X402StatusView = ({
16104
16516
  transactionId,
16105
16517
  fetchOnce,
@@ -16109,9 +16521,9 @@ var X402StatusView = ({
16109
16521
  onComplete
16110
16522
  }) => {
16111
16523
  const initial = { kind: "polling" };
16112
- const [phase, dispatch] = useReducer9(reduceX402Status, initial);
16524
+ const [phase, dispatch] = useReducer10(reduceX402Status, initial);
16113
16525
  const { finish } = useFlowExit(onComplete);
16114
- useEffect11(() => {
16526
+ useEffect12(() => {
16115
16527
  const run = runX402Status({ fetchOnce, interval, maxAttempts, timeout });
16116
16528
  let cancelled = false;
16117
16529
  void (async () => {
@@ -16124,15 +16536,15 @@ var X402StatusView = ({
16124
16536
  cancelled = true;
16125
16537
  };
16126
16538
  }, [fetchOnce, interval, maxAttempts, timeout]);
16127
- useEffect11(() => {
16539
+ useEffect12(() => {
16128
16540
  if (phase.kind === "signed" || phase.kind === "failed" || phase.kind === "timeout" || phase.kind === "error") {
16129
16541
  finish(phase);
16130
16542
  }
16131
16543
  }, [phase, finish]);
16132
16544
  if (phase.kind === "polling") {
16133
16545
  const statusText = phase.latest?.status ?? "pending";
16134
- return /* @__PURE__ */ jsx25(Box20, { flexDirection: "column", children: /* @__PURE__ */ jsxs20(Text21, { color: "cyan", children: [
16135
- /* @__PURE__ */ jsx25(Spinner16, { type: "dots" }),
16546
+ return /* @__PURE__ */ jsx27(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsxs21(Text22, { color: "cyan", children: [
16547
+ /* @__PURE__ */ jsx27(Spinner17, { type: "dots" }),
16136
16548
  " Polling transaction ",
16137
16549
  transactionId,
16138
16550
  " (status: ",
@@ -16143,35 +16555,35 @@ var X402StatusView = ({
16143
16555
  if (phase.kind === "signed") {
16144
16556
  const encoded = phase.response.encodedPayload ?? "";
16145
16557
  const preview = encoded.length > 32 ? `${encoded.slice(0, 32)}...` : encoded;
16146
- return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
16147
- /* @__PURE__ */ jsx25(Text21, { color: "green", children: "\u2713 Signed" }),
16148
- /* @__PURE__ */ jsx25(Text21, { children: `status: ${phase.response.status}` }),
16149
- /* @__PURE__ */ jsx25(Text21, { children: `encodedPayload: ${preview}` })
16558
+ return /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", children: [
16559
+ /* @__PURE__ */ jsx27(Text22, { color: "green", children: "\u2713 Signed" }),
16560
+ /* @__PURE__ */ jsx27(Text22, { children: `status: ${phase.response.status}` }),
16561
+ /* @__PURE__ */ jsx27(Text22, { children: `encodedPayload: ${preview}` })
16150
16562
  ] });
16151
16563
  }
16152
16564
  if (phase.kind === "failed") {
16153
- return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
16154
- /* @__PURE__ */ jsx25(Text21, { color: "red", children: "\u2717 Approval did not settle" }),
16155
- /* @__PURE__ */ jsx25(Text21, { color: "red", children: `status: ${phase.response.status}` })
16565
+ return /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", children: [
16566
+ /* @__PURE__ */ jsx27(Text22, { color: "red", children: "\u2717 Approval did not settle" }),
16567
+ /* @__PURE__ */ jsx27(Text22, { color: "red", children: `status: ${phase.response.status}` })
16156
16568
  ] });
16157
16569
  }
16158
16570
  if (phase.kind === "timeout") {
16159
- return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
16160
- /* @__PURE__ */ jsx25(Text21, { color: "yellow", children: "Polling timed out before the transaction reached a signed state." }),
16161
- phase.response !== void 0 ? /* @__PURE__ */ jsx25(Text21, { children: `last status: ${phase.response.status}` }) : null
16571
+ return /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", children: [
16572
+ /* @__PURE__ */ jsx27(Text22, { color: "yellow", children: "Polling timed out before the transaction reached a signed state." }),
16573
+ phase.response !== void 0 ? /* @__PURE__ */ jsx27(Text22, { children: `last status: ${phase.response.status}` }) : null
16162
16574
  ] });
16163
16575
  }
16164
- return /* @__PURE__ */ jsxs20(Box20, { flexDirection: "column", children: [
16165
- /* @__PURE__ */ jsx25(Text21, { color: "red", children: "\u2717 Polling failed" }),
16166
- /* @__PURE__ */ jsx25(Text21, { color: "red", children: phase.message })
16576
+ return /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", children: [
16577
+ /* @__PURE__ */ jsx27(Text22, { color: "red", children: "\u2717 Polling failed" }),
16578
+ /* @__PURE__ */ jsx27(Text22, { color: "red", children: phase.message })
16167
16579
  ] });
16168
16580
  };
16169
16581
 
16170
16582
  // src/commands/x402/supported.tsx
16171
- import { Box as Box21, Text as Text22 } from "ink";
16172
- import Spinner17 from "ink-spinner";
16583
+ import { Box as Box22, Text as Text23 } from "ink";
16584
+ import Spinner18 from "ink-spinner";
16173
16585
  import { useCallback as useCallback9 } from "react";
16174
- import { jsx as jsx26, jsxs as jsxs21 } from "react/jsx-runtime";
16586
+ import { jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
16175
16587
  var COLUMNS6 = [
16176
16588
  { header: "Scheme", cell: (k) => k.scheme },
16177
16589
  { header: "Network", cell: (k) => k.network }
@@ -16181,26 +16593,26 @@ var SupportedView2 = ({ load, onComplete }) => {
16181
16593
  const { finish } = useFlowExit(onComplete);
16182
16594
  const { status, data, error } = useFlowState(action, finish);
16183
16595
  if (status === "loading") {
16184
- return /* @__PURE__ */ jsx26(Box21, { children: /* @__PURE__ */ jsxs21(Text22, { color: "cyan", children: [
16185
- /* @__PURE__ */ jsx26(Spinner17, { type: "dots" }),
16596
+ return /* @__PURE__ */ jsx28(Box22, { children: /* @__PURE__ */ jsxs22(Text23, { color: "cyan", children: [
16597
+ /* @__PURE__ */ jsx28(Spinner18, { type: "dots" }),
16186
16598
  " Loading supported schemes..."
16187
16599
  ] }) });
16188
16600
  }
16189
16601
  if (status === "error") {
16190
- return /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", children: [
16191
- /* @__PURE__ */ jsx26(Text22, { color: "red", children: "Failed to load supported schemes" }),
16192
- /* @__PURE__ */ jsx26(Text22, { color: "red", children: error })
16602
+ return /* @__PURE__ */ jsxs22(Box22, { flexDirection: "column", children: [
16603
+ /* @__PURE__ */ jsx28(Text23, { color: "red", children: "Failed to load supported schemes" }),
16604
+ /* @__PURE__ */ jsx28(Text23, { color: "red", children: error })
16193
16605
  ] });
16194
16606
  }
16195
16607
  const kinds = data?.kinds ?? [];
16196
16608
  if (kinds.length === 0) {
16197
- return /* @__PURE__ */ jsx26(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx26(Text22, { children: "No supported (scheme, network) pairs returned for this account." }) });
16609
+ return /* @__PURE__ */ jsx28(Box22, { flexDirection: "column", children: /* @__PURE__ */ jsx28(Text23, { children: "No supported (scheme, network) pairs returned for this account." }) });
16198
16610
  }
16199
- return /* @__PURE__ */ jsx26(Table, { columns: COLUMNS6, rows: kinds });
16611
+ return /* @__PURE__ */ jsx28(Table, { columns: COLUMNS6, rows: kinds });
16200
16612
  };
16201
16613
 
16202
16614
  // src/commands/x402/index.tsx
16203
- import { jsx as jsx27 } from "react/jsx-runtime";
16615
+ import { jsx as jsx29 } from "react/jsx-runtime";
16204
16616
  var POST_PAY_INSTRUCTION = "Present the approval_url to the user and ask them to approve in the InFlow mobile app or dashboard. Then call `x402 status <transaction_id> --interval 5 --max-attempts 60` to poll until signed. Once the transaction is signed, replay the request manually using the encoded_payload from the status response as the PAYMENT-SIGNATURE header.";
16205
16617
  var POLLING_INSTRUCTION2 = "Approval polling is happening inline. The yield stream emits each status change; the final frame includes the encoded_payload when signing completes.";
16206
16618
  function buildSignOptions(options) {
@@ -16209,15 +16621,11 @@ function buildSignOptions(options) {
16209
16621
  if (options.paymentId !== void 0) out.paymentId = options.paymentId;
16210
16622
  return out;
16211
16623
  }
16212
- function parseHeaderFlagsOrFail2(c, flags) {
16213
- try {
16214
- return parseHeaderFlags(flags);
16215
- } catch (err) {
16216
- c.error({
16217
- code: "INVALID_HEADER",
16218
- message: err instanceof Error ? err.message : String(err)
16219
- });
16220
- }
16624
+ function invalidHeaderError2(err) {
16625
+ return {
16626
+ code: "INVALID_HEADER",
16627
+ message: err instanceof Error ? err.message : String(err)
16628
+ };
16221
16629
  }
16222
16630
  function decoratePayloadField(frame, encoded, payloadFile) {
16223
16631
  if (payloadFile !== void 0 && payloadFile.length > 0) {
@@ -16229,13 +16637,14 @@ function decoratePayloadField(frame, encoded, payloadFile) {
16229
16637
  }
16230
16638
  frame.encoded_payload = encoded;
16231
16639
  }
16232
- function buildPayPipelineInput2(c) {
16233
- const probeHeaders = parseHeaderFlagsOrFail2(c, c.options.header);
16234
- const probeOptions = {
16640
+ function probeOptionsFrom2(c) {
16641
+ return {
16235
16642
  method: c.options.method,
16236
- headers: probeHeaders,
16643
+ headers: parseHeaderFlags(c.options.header),
16237
16644
  ...c.options.data !== void 0 ? { data: c.options.data } : {}
16238
16645
  };
16646
+ }
16647
+ function buildPayPipelineInput2(c, probeOptions) {
16239
16648
  return {
16240
16649
  probeOptions,
16241
16650
  url: c.args.url,
@@ -16316,17 +16725,17 @@ function rejectedFrameFromResult2(result) {
16316
16725
  }
16317
16726
  async function* runPayCommand2(c, inflow2, authStorage2, apiBaseUrl2) {
16318
16727
  assertSessionGuard(c, authStorage2, inflow2);
16728
+ let probeOptions;
16729
+ try {
16730
+ probeOptions = probeOptionsFrom2(c);
16731
+ } catch (err) {
16732
+ return c.error(invalidHeaderError2(err));
16733
+ }
16319
16734
  if (!c.agent && !c.formatExplicit) {
16320
16735
  const client = await inflow2.x402.client();
16321
- const probeHeaders = parseHeaderFlagsOrFail2(c, c.options.header);
16322
- const probeOptions = {
16323
- method: c.options.method,
16324
- headers: probeHeaders,
16325
- ...c.options.data !== void 0 ? { data: c.options.data } : {}
16326
- };
16327
16736
  let finalPhase = null;
16328
16737
  await renderInkUntilExit(
16329
- /* @__PURE__ */ jsx27(
16738
+ /* @__PURE__ */ jsx29(
16330
16739
  PayView2,
16331
16740
  {
16332
16741
  url: c.args.url,
@@ -16354,19 +16763,19 @@ async function* runPayCommand2(c, inflow2, authStorage2, apiBaseUrl2) {
16354
16763
  if (finalPhase !== null) {
16355
16764
  const phase = finalPhase;
16356
16765
  if (phase.kind === "replay-rejected") {
16357
- c.error({
16766
+ return c.error({
16358
16767
  code: PAYMENT_NOT_ACCEPTED_CODE,
16359
16768
  message: `Seller rejected the signed payment with status ${String(phase.result.responseStatus)}. The approval was completed but the seller did not honour the payment.`
16360
16769
  });
16361
16770
  }
16362
16771
  if (phase.kind === "error") {
16363
- c.error({ code: phase.code, message: phase.message });
16772
+ return c.error({ code: phase.code, message: phase.message });
16364
16773
  }
16365
16774
  }
16366
16775
  return;
16367
16776
  }
16368
16777
  const run = inflow2.x402.pay({
16369
- ...buildPayPipelineInput2(c),
16778
+ ...buildPayPipelineInput2(c, probeOptions),
16370
16779
  awaitPayment: c.options.interval > 0
16371
16780
  });
16372
16781
  for await (const event of run.events) {
@@ -16384,14 +16793,13 @@ async function* runPayCommand2(c, inflow2, authStorage2, apiBaseUrl2) {
16384
16793
  }
16385
16794
  if (event.type === "rejected") {
16386
16795
  yield sanitizeDeep(rejectedFrameFromResult2(event.result));
16387
- c.error({
16796
+ return c.error({
16388
16797
  code: PAYMENT_NOT_ACCEPTED_CODE,
16389
16798
  message: `Seller rejected the signed payment with status ${String(event.result.responseStatus)}. The approval was completed but the seller did not honour the payment; see approval_url in the previous frame for details.`
16390
16799
  });
16391
- return;
16392
16800
  }
16393
16801
  if (event.type === "errored") {
16394
- c.error({ code: event.code, message: event.message });
16802
+ return c.error({ code: event.code, message: event.message });
16395
16803
  }
16396
16804
  }
16397
16805
  }
@@ -16400,7 +16808,7 @@ async function* runStatusCommand2(c, inflow2, authStorage2) {
16400
16808
  if (!c.agent && !c.formatExplicit) {
16401
16809
  const client2 = await inflow2.x402.client();
16402
16810
  await renderInkUntilExit(
16403
- /* @__PURE__ */ jsx27(
16811
+ /* @__PURE__ */ jsx29(
16404
16812
  X402StatusView,
16405
16813
  {
16406
16814
  transactionId: c.args.transactionId,
@@ -16433,14 +16841,14 @@ async function* runStatusCommand2(c, inflow2, authStorage2) {
16433
16841
  yield sanitizeDeep(toStatusFrame2(c.args.transactionId, outcome.value, c.options.payloadFile));
16434
16842
  if (!outcome.terminal) continue;
16435
16843
  if (outcome.reason !== void 0) {
16436
- c.error({
16844
+ return c.error({
16437
16845
  code: "POLLING_TIMEOUT",
16438
16846
  message: outcome.reason === "timeout" ? "Polling timed out before the transaction reached a signed state." : "Reached the configured maximum poll attempts before signed state.",
16439
16847
  retryable: true
16440
16848
  });
16441
16849
  }
16442
16850
  if (classifyPayloadResponse(outcome.value) === "failed") {
16443
- c.error({
16851
+ return c.error({
16444
16852
  code: "APPROVAL_FAILED",
16445
16853
  message: `Transaction ${c.args.transactionId} terminated as ${outcome.value.status} with no payload.`
16446
16854
  });
@@ -16463,7 +16871,7 @@ async function runCancelCommand2(c, inflow2, authStorage2) {
16463
16871
  assertSessionGuard(c, authStorage2, inflow2);
16464
16872
  if (!c.agent && !c.formatExplicit) {
16465
16873
  await renderInkUntilExit(
16466
- /* @__PURE__ */ jsx27(
16874
+ /* @__PURE__ */ jsx29(
16467
16875
  CancelView2,
16468
16876
  {
16469
16877
  approvalId: c.args.approvalId,
@@ -16485,13 +16893,13 @@ async function runDecodeCommand2(c) {
16485
16893
  try {
16486
16894
  decoded = decodeHeader(c.args.header);
16487
16895
  } catch (err) {
16488
- c.error({
16896
+ return c.error({
16489
16897
  code: "DECODE_FAILED",
16490
16898
  message: err instanceof Error ? err.message : String(err)
16491
16899
  });
16492
16900
  }
16493
16901
  if (!c.agent && !c.formatExplicit) {
16494
- await renderInkUntilExit(/* @__PURE__ */ jsx27(DecodeView2, { decoded }));
16902
+ await renderInkUntilExit(/* @__PURE__ */ jsx29(DecodeView2, { decoded }));
16495
16903
  return void 0;
16496
16904
  }
16497
16905
  return sanitizeDeep(decoded);
@@ -16499,19 +16907,19 @@ async function runDecodeCommand2(c) {
16499
16907
  async function runSupportedCommand2(c, inflow2, authStorage2) {
16500
16908
  assertSessionGuard(c, authStorage2, inflow2);
16501
16909
  if (!c.agent && !c.formatExplicit) {
16502
- await renderInkUntilExit(/* @__PURE__ */ jsx27(SupportedView2, { load: () => inflow2.x402.supported(), onComplete: () => void 0 }));
16910
+ await renderInkUntilExit(/* @__PURE__ */ jsx29(SupportedView2, { load: () => inflow2.x402.supported(), onComplete: () => void 0 }));
16503
16911
  return void 0;
16504
16912
  }
16505
16913
  const response = await inflow2.x402.supported();
16506
16914
  return sanitizeDeep(response);
16507
16915
  }
16508
16916
  async function runInspectCommand2(c) {
16509
- const probeHeaders = parseHeaderFlagsOrFail2(c, c.options.header);
16510
- const probeOptions = {
16511
- method: c.options.method,
16512
- headers: probeHeaders,
16513
- ...c.options.data !== void 0 ? { data: c.options.data } : {}
16514
- };
16917
+ let probeOptions;
16918
+ try {
16919
+ probeOptions = probeOptionsFrom2(c);
16920
+ } catch (err) {
16921
+ return c.error(invalidHeaderError2(err));
16922
+ }
16515
16923
  const deps = {
16516
16924
  probeOptions,
16517
16925
  url: c.args.url,
@@ -16523,7 +16931,7 @@ async function runInspectCommand2(c) {
16523
16931
  if (!c.agent && !c.formatExplicit) {
16524
16932
  let finalPhase = null;
16525
16933
  await renderInkUntilExit(
16526
- /* @__PURE__ */ jsx27(
16934
+ /* @__PURE__ */ jsx29(
16527
16935
  InspectView2,
16528
16936
  {
16529
16937
  url: c.args.url,
@@ -16538,7 +16946,7 @@ async function runInspectCommand2(c) {
16538
16946
  if (finalPhase !== null) {
16539
16947
  const phase = finalPhase;
16540
16948
  if (phase.kind === "error") {
16541
- c.error({ code: phase.code, message: phase.message });
16949
+ return c.error({ code: phase.code, message: phase.message });
16542
16950
  }
16543
16951
  }
16544
16952
  return void 0;
@@ -16558,12 +16966,12 @@ async function runInspectCommand2(c) {
16558
16966
  }
16559
16967
  });
16560
16968
  if (finalEvent === null) {
16561
- c.error({ code: "INSPECT_FAILED", message: "Inspect pipeline produced no result." });
16969
+ return c.error({ code: "INSPECT_FAILED", message: "Inspect pipeline produced no result." });
16562
16970
  }
16563
16971
  const { kind, payload } = finalEvent;
16564
16972
  if (kind === "error") {
16565
16973
  const err = payload;
16566
- c.error({ code: err.code, message: err.message });
16974
+ return c.error({ code: err.code, message: err.message });
16567
16975
  }
16568
16976
  if (kind === "accepts") {
16569
16977
  return sanitizeDeep(buildAcceptsFrame(payload));
@@ -16617,8 +17025,8 @@ function createX402Cli(inflow2, authStorage2, apiBaseUrl2) {
16617
17025
  });
16618
17026
  cli2.command("inspect", {
16619
17027
  description: "Show the seller's PAYMENT-REQUIRED accepts for a URL. Read-only probe \u2014 no auth, no payment.",
16620
- args: inspectArgs2,
16621
- options: inspectOptions2,
17028
+ args: inspectArgs3,
17029
+ options: inspectOptions3,
16622
17030
  outputPolicy: "agent-only",
16623
17031
  async run(c) {
16624
17032
  return runInspectCommand2(c);
@@ -16695,9 +17103,9 @@ function formatUpdateNotice(info) {
16695
17103
  }
16696
17104
 
16697
17105
  // src/cli.tsx
16698
- var cliVersion = "0.6.3";
17106
+ var cliVersion = "0.6.5";
16699
17107
  var cliName = "@inflowpayai/inflow";
16700
- var skillBody = '# Agentic Payments\n\nPay HTTP 402-protected resources on the user\'s behalf. InFlow speaks two payment protocols \u2014 **MPP** and **x402** \u2014 but the flow is the same for both: shared setup (install, run, authenticate), then a **router** that picks the protocol from the seller\'s 402 header, then one **Paying a 402 resource** section that covers both. A per-protocol **delta table** at the top of that section lists the handful of real differences (header name, credential name, filters, error codes); read your row, then follow the shared steps.\n\n## Installing\n\nInstall with `npm install -g @inflowpayai/inflow`. Or run directly with `npx @inflowpayai/inflow`.\n\n## Running\n\nInFlow runs as a **standalone CLI** or an **MCP server**.\n\n**MCP**: add an `inflow` server to your MCP client config that runs `npx -y @inflowpayai/inflow --mcp`. Keep the `-y` flag \u2014 it suppresses npx\'s confirmation prompt, without which the MCP host can stall on first run.\n\n**MCP mode** exposes every CLI command as a tool. Call `tools/list` on the MCP server for the authoritative inventory; arguments mirror the CLI flags one-to-one.\n\n### Common commands / options\n\n**The CLI is the source of truth for exact flags, enums, and output shapes** \u2014 run `inflow <command> --schema` for one command, or `inflow --llms-full` for everything. This playbook covers *when and why*, not exhaustive parameter lists; when you need a precise flag name, value set, or response shape, query the CLI rather than guessing.\n\n- `inflow --llms` (or `--llms-full` for parameter detail) \u2014 discover all commands. `inflow <command> --schema` for a single command\'s JSON Schema.\n- `inflow --skill` \u2014 print this playbook (no frontmatter) to stdout. Use it to paste into the system-prompt field of an MCP host that doesn\'t natively load skills: `inflow --skill | pbcopy`.\n- Default output is `toon`. Override with `--format <fmt>`; for programmatic parsing prefer `json` (single document) or `jsonl` (line-delimited).\n- Multi-step flows return `_next.command` \u2014 run it to continue.\n- `--auth <path>` overrides the credentials file location.\n- `--api-key <key>` or `INFLOW_API_KEY=<key>` is an alternative to device-flow auth.\n\n## Authenticate\n\nAuthentication is shared by both protocols \u2014 do it once, before either payment flow. **Don\'t start a payment until the user is authenticated.**\n\nCheck the current state first \u2014 the user may already be logged in:\n\n```bash\ninflow auth status\n```\n\nA successful `auth status` returns `authenticated: true` plus `auth_method` (`device_token` or `api_key`), a truncated `access_token` preview (never the full token), `credentials_path`, `connection`, and possibly an `update` field. For the user\'s identity (email, handle, account id), call `inflow user get` \u2014 `auth status` deliberately omits it. Run the command to see the full shape.\n\nIf the response includes an `update` field, a newer version of `inflow` is published.\n\n**Surface and defer.** Tell the user a newer version is available and how to upgrade \u2014 `npm install -g @inflowpayai/inflow@latest` (or `npx @inflowpayai/inflow@latest`). Then **proceed with the current version**. Only block on the upgrade if a subsequent command fails with `VERSION_UNSUPPORTED` (or an HTTP 426 from the API), at which point the upgrade is mandatory and you should not retry until it lands.\n\nIf `authenticated` is `false`, start the device flow:\n\n```bash\ninflow auth login --client-name "<your-agent-name>"\n```\n\nReplace `<your-agent-name>` with the name of your agent or application (for example `"Personal Assistant"`, `"Shopping Bot"`). The device-authorization page in the user\'s browser displays this name when they approve the connection. Use a clear, unique, identifiable name.\n\nThe response includes a `verification_url` (present this to the user), a `phrase`, and a `_next.command`. Run that command immediately to poll until authenticated. **Do not wait for the user to respond before starting the poll.**\n\nIf your environment can\'t relay the verification phrase to the user while a separate polling command blocks I/O, use inline polling instead:\n\n```bash\ninflow auth login --client-name "<name>" --interval 5 --timeout 300\n```\n\n**API key alternative:** if the user provides an API key, set `INFLOW_API_KEY=<key>` in the environment (or pass `--api-key <key>` to any command) instead of running `auth login`. The API key takes precedence over a saved device token.\n\n## Which protocol? \u2014 start here\n\nBefore paying, decide which protocol the resource uses. **You do not choose it \u2014 the seller\'s 402 challenge header decides.** Detection is read-only and needs no auth.\n\n1. Get the 402 challenge header. If a prior HTTP call already returned a 402 (e.g. the browsing tool hit a paywall), use that response. Otherwise make a plain, **unauthenticated GET** to the URL and read the headers of the 402.\n2. Branch on the header \u2014 **check for MPP first:**\n\n| 402 carries\u2026 | Protocol | Then |\n| --- | --- | --- |\n| `WWW-Authenticate: Payment` | **MPP** | Go to [\xA7 Paying a 402 resource](#paying-a-402-resource); use the **MPP** column of the delta table |\n| `WWW-Authenticate: Payment` **and** `PAYMENT-REQUIRED` | **MPP** (MPP wins when both are present) | Go to [\xA7 Paying a 402 resource](#paying-a-402-resource); use the **MPP** column |\n| `PAYMENT-REQUIRED` only | **x402** | Go to [\xA7 Paying a 402 resource](#paying-a-402-resource); use the **x402** column |\n| neither header, or the response isn\'t a 402 | not InFlow-payable | Stop. Tell the user the resource isn\'t a supported 402 endpoint. |\n\nNote: the `inspect` and `decode` commands are protocol-specific (`inflow mpp \u2026` vs `inflow x402 \u2026`), which is why you detect the header *first*, then use that protocol\'s tools.\n\n---\n\n## Paying a 402 resource\n\nOne flow for both protocols. Prerequisite: you are authenticated (see [Authenticate](#authenticate)). First find your protocol\'s row in the **Protocol deltas** table below \u2014 it names the 402 header that selected it, the matching model, the filter flags, and the credential and replay header you\'ll use. Everything else in this section applies to both protocols.\n\n**Sequencing.** Run pre-flight before pay \u2014 `pay` fails or double-charges if the pre-flight checks didn\'t clear. `inspect` and `decode` are read-only and need no auth, so they may run before you authenticate if useful (e.g. sizing up a paywall first).\n\n### Protocol deltas\n\n| Aspect | MPP | x402 |\n| --- | --- | --- |\n| Selected when the 402 carries | `WWW-Authenticate: Payment` | `PAYMENT-REQUIRED` (and no `WWW-Authenticate: Payment`) |\n| Command prefix | `inflow mpp \u2026` | `inflow x402 \u2026` |\n| Matching model | The seller\'s challenge **pins the rail** \u2014 the buyer does not choose scheme/network/asset | Pay where `inspect.accepts \u2229 supported.kinds` is non-empty |\n| Filter flags | `--payment-method`, `--intent`, `--currency`, `--rail`, `--instrument-id` | `--scheme`, `--network`, `--asset`, `--asset-name` |\n| Credential field (after approval) | `credential` (from `mpp status` when `state` is `ready`) | `encoded_payload` (from `x402 status` after approval) |\n| Replay header | `Authorization: Payment <credential>` | `PAYMENT-SIGNATURE: <encoded_payload>` |\n| Write-credential-to-disk flag | `--credential-file <path>` | `--payload-file <path>` |\n| Idempotency | \u2014 | `--payment-id` (see Step 2) |\n| Cancel uses | `approval_id` | `approval_id` |\n| Protocol-specific error codes | `PAYMENT_FAILED`, `PAYMENT_EXPIRED`, `PAYMENT_NOT_ACCEPTED` | `APPROVAL_TIMEOUT`, `APPROVAL_FAILED`, `APPROVAL_CANCELLED` |\n\nThroughout this section `<mpp|x402>` means "use your protocol\'s prefix." For the exact parameters and output shape of any command below, run `inflow <command> --schema`.\n\n### Step 1: Pre-flight evaluation\n\n```bash\n# 1. Parse what the seller will accept \u2014 read-only, no auth\ninflow <mpp|x402> inspect <url>\n\n# (Already have the 402 header from a prior response? Decode it directly instead of re-probing:)\ninflow <mpp|x402> decode \'<402 header value>\'\n\n# 2. List what the buyer\'s account can pay with\ninflow <mpp|x402> supported\n\n# 3. Check balances for the candidate currency/asset(s)\ninflow balances list\n```\n\n`inspect` / `decode` return what the seller accepts \u2014 the price is the `amount` field (for x402 the human-readable symbol is `extra.assetName`); `decode` also accepts a base64url credential / receipt. `supported` returns what the account can pay with; `balances list` returns `available` per currency. Run the commands to see the exact shapes.\n\nDecide whether you can pay (apply your protocol\'s matching model from the delta table):\n\n| Condition | Meaning | Action |\n| --- | --- | --- |\n| No payable match between the seller and the buyer\'s `supported` methods | No payable rail | Stop \u2192 `NO_INFLOW_MATCH`. Tell the user the seller\'s rails aren\'t supported by their account. |\n| A match exists, but `balances.available < amount` for every match | Right rail, not enough funds | Stop \u2192 run `inflow deposit-addresses list`, surface the address(es) in full, ask the user to fund a matching network. |\n| A match exists **and** \u22651 match has `balances.available \u2265 amount` | Payable | Proceed to Step 2. |\n\n**Optional filters** narrow *which* offer to fulfil \u2014 optional, AND-combined, applied on both `pay` and `inspect`, and an empty result fails with `NO_FILTERED_MATCH` (it does not fall through to a default order). One non-obvious case: MPP\'s `--instrument-id` picks *how* to fund (an instrument-rail / fiat challenge), not which challenge. For the exact filter flags and accepted values per protocol, run `inflow <mpp|x402> pay --schema`.\n\n**Decimal precision.** `balances.available` and the challenge/`amount` value are decimal strings preserving BigDecimal precision. **Never parse them to a JS `Number`** \u2014 that drops precision. Compare as strings, or use a `BigInt` / `decimal.js`-style library.\n\n### Step 2: Pay\n\nBefore initiating the call, summarize the intent to the user in chat: amount, currency, resource URL, and the method/rail (MPP) or scheme/network (x402). The user verifies the canonical details on the approval screen; the chat summary is what they read first. Example:\n\n> "I\'m about to pay 0.10 USDC to api.foo.dev for /dataset.csv. Requesting approval next."\n\n**Fast path (recommended).** When the agent can block until the payment finishes, set `--interval N` and let the CLI run the whole flow in one call \u2014 probe, decode, prepare, await approval, replay against the seller, return the body:\n\n```bash\ninflow <mpp|x402> pay <url> --interval 5 --max-attempts 180\n```\n\nThe result includes `outcome`, `transaction_id`, `response_status`, `settled`, the seller body inline (or `output_saved_to` if `--output-file` is set), and the now-consumed credential (`credential` for MPP, `encoded_payload` for x402). On the fast path the CLI has already replayed that credential to fetch the body \u2014 it appears in the result for reference only; **do not replay it yourself.** To surface `approval_url` *before* the call returns, add `--format jsonl` \u2014 frames stream line-by-line. With the default `json` (or `toon`), the agent only sees the final buffered result.\n\n**`outcome` values.** A completed `pay` returns one of three terminal outcomes \u2014 branch on it, don\'t assume `paid`:\n\n| `outcome` | Meaning | What to do |\n| --- | --- | --- |\n| `paid` | Settled and the seller returned 2xx | Deliver the body to the user |\n| `no-payment-required` | The resource wasn\'t paywalled, or was already paid | Tell the user nothing was charged; return the body |\n| `replay-rejected` | Payment was approved (funds in transit) but the seller replied non-2xx on the replay | Do NOT report success. Tell the user the seller\'s response failed; because the payment didn\'t complete, the in-transit funds are reverted to their InFlow balance. Offer to retry |\n\n**Two-step path.** Use this when the agent\'s host can\'t block I/O long enough for the user to approve (chat UIs that yield between turns). Drop `--interval`; the first call returns `transaction_id` + `approval_id` + `approval_url` + a `_next` `status` command, and the agent drives the replay itself once a credential arrives.\n\n```bash\ninflow <mpp|x402> pay <url>\n# -> { "transaction_id": "txn_abc", "approval_id": "appr_xyz", "approval_url": "https://app.inflowpay.ai/approvals/appr_xyz", "_next": { "command": "<mpp|x402> status txn_abc --interval 5 --max-attempts 180" } }\n```\n\nMind the two distinct ids: poll, replay, and resume all use `transaction_id`; **cancel uses `approval_id`** (`inflow <mpp|x402> cancel <approval_id>`). Both are returned by `pay`.\n\nFor non-GET requests, pass `--method`, `--data`, `--header` (repeatable):\n\n```bash\ninflow <mpp|x402> pay https://seller.example.com/api/widgets --method POST --data \'{"sku":"widget-1"}\' --header "X-Custom: value" --interval 5 --max-attempts 180\n```\n\n**Idempotency (x402 only).** Set `--payment-id <id>` whenever a retry on transport failure is possible \u2014 the server treats two requests with the same id as the same logical payment, so a retry after a network blip won\'t double-charge. Use a stable random opaque value generated once per intent; reuse the same id on transport retry; regenerate only when the user explicitly wants a fresh charge. Don\'t tie the id to wall-clock time \u2014 a date-based id silently double-charges on next-day "buy this again" requests. Without `--payment-id`, the server generates one each call \u2014 fine for one-shots, unsafe for retries. (Format constraints: `inflow x402 pay --schema`.)\n\n```bash\ninflow x402 pay <url> --payment-id "<stable-opaque-id>"\n```\n\n**Sensitive / binary output.** The one-time bearer credential (`credential` for MPP, `encoded_payload` for x402; returned after approval and echoed in the fast-path result) must not be echoed back in chat. Write it to disk at mode `0o600` with your protocol\'s flag (`--credential-file <path>` for MPP, `--payload-file <path>` for x402); replay then reads from that file. For the seller\'s response body, `--output-file <path>` writes bytes to disk and replaces `body` / `body_base64` with `output_saved_to: <path>` \u2014 pair with `--no-show-body` for binary content (PDFs, images, audio, datasets) so bytes never appear inline as base64:\n\n```bash\ninflow <mpp|x402> pay https://api.foo.dev/dataset.csv --interval 5 --max-attempts 180 --output-file /tmp/dataset.csv --no-show-body\n```\n\n**Polling discipline.** Persist `transaction_id` as soon as `pay` returns it. Then:\n\n- Run `_next.command` (or `<mpp|x402> status <transaction_id> --interval N`) immediately. Don\'t wait for the user to confirm before polling starts.\n- If polling is interrupted \u2014 network drop, session bounce, user kills the agent \u2014 resume with `inflow <mpp|x402> status <transaction_id> --interval 5 --max-attempts 180`. Only create a new transaction if the original expired (`PAYMENT_EXPIRED` for MPP, `APPROVAL_TIMEOUT` for x402), was denied/cancelled, or its credential is already consumed.\n- If `POLLING_TIMEOUT` fires before approval, ask the user whether to keep waiting or cancel \u2014 don\'t silently restart the poll.\n- If >12 minutes elapsed without a user response (\u22483 min before the 15-minute approval window closes), surface that explicitly so they can act before the window closes.\n- If the user aborts ("nevermind", "cancel that"), call `inflow <mpp|x402> cancel <approval_id>` before exiting. Otherwise the approval sits pending for 15 minutes and triggers phantom notifications in the user\'s InFlow app.\n\nOnce `status` reports the credential (MPP: `state: ready` with `credential`; x402: `encoded_payload`), replay the original seller request with your protocol\'s replay header from the delta table \u2014 `Authorization: Payment <credential>` (MPP) or `PAYMENT-SIGNATURE: <encoded_payload>` (x402); use `$(cat <file>)` if you wrote it to disk with `--credential-file` / `--payload-file`. The seller\'s protected response comes back on the replay.\n\n### Limits\n\n| Limit | Value |\n| --- | --- |\n| Approval window | 15 minutes from `pay` creating the transaction (`--timeout` overrides the polling deadline) |\n| Polling stop condition | Polling ends at whichever fires first: `--max-attempts` (count, default `0` = unlimited) or `--timeout` (seconds, default `900` = the full 15-min window). The examples use `--interval 5 --max-attempts 180` (= 900 s) so a copied command covers the whole window \u2014 `--interval 5 --max-attempts 60` (= 300 s) would stop polling at 5 min, well before approval can land |\n| Credential reuse | One-time. The credential (`credential` for MPP, `encoded_payload` for x402) is consumed by the first seller replay \u2014 not reusable; a failed seller call requires a new `pay` |\n\n### Worked example (MPP)\n\nA user asks the agent to fetch a paywalled dataset at `https://api.foo.dev/dataset.csv` that answered 402 with `WWW-Authenticate: Payment`.\n\nPre-flight: `inflow mpp inspect <url>` (the seller\'s challenges), `inflow mpp supported` (methods the buyer can pay with), `inflow balances list`. The seller offers the `inflow` method in USDC; the user\'s 100.5 USDC balance covers the 0.10 USDC price. Summarize intent, then pay:\n\n```bash\ninflow mpp pay https://api.foo.dev/dataset.csv --interval 5 --max-attempts 180 --output-file /tmp/dataset.csv --no-show-body\n# Persist transaction_id from the response in case polling is interrupted.\n# Returns outcome "paid" with output_saved_to /tmp/dataset.csv.\n```\n\n> "Approval requested \u2014 confirm in the InFlow app: https://app.inflowpay.ai/approvals/appr_xyz\n> I\'ll keep polling. 15-min window."\n\nOnce the result arrives:\n\n> "Paid 0.10 USDC. Transaction txn_abc. Saved the dataset to /tmp/dataset.csv."\n\n**Two-step variant** (host can\'t block): follow Step 2\'s two-step path; once `mpp status` reports `state: ready`, replay with `Authorization: Payment <credential>` (or `$(cat <path>)` via `--credential-file` to keep it out of chat).\n\n### Worked example (x402)\n\nA user asks the agent to fetch a paywalled article at `https://api.foo.dev/article-3` that answered 402 with `PAYMENT-REQUIRED`.\n\nPre-flight: the intersection lands on `exact` \xD7 `solana:mainnet`, and the user\'s 100.5 USDC balance easily covers the 0.10 USDC the seller requires. Proceed.\n\n> "I\'m about to pay 0.10 USDC on Solana mainnet to api.foo.dev for /article-3.\n> Your balance is 100.5 USDC \u2014 plenty. Requesting approval next."\n\n```bash\ninflow x402 pay https://api.foo.dev/article-3 --payment-id "<stable-opaque-id>" --interval 5 --max-attempts 180\n# Persist transaction_id from the response in case polling gets interrupted.\n# Returns outcome "paid"; body contains the article JSON.\n```\n\n> "Approval requested \u2014 confirm in the InFlow app: https://app.inflowpay.ai/approvals/appr_xyz\n> I\'ll keep polling. 15-min window."\n\nOnce the result arrives:\n\n> "Paid 0.10 USDC. Transaction txn_abc. Server returned: \'How to brew coffee \u2014 ...\'"\n\n**Two-step variant** (host can\'t block): follow Step 2\'s two-step path; once `x402 status` returns the `encoded_payload`, replay with `PAYMENT-SIGNATURE: <encoded_payload>` (use `--payload-file` to keep it out of chat).\n\n### MPP errors\n\nAll errors in agent mode are JSON with `code` and `message` fields and exit code 1. MPP-specific codes (shared codes are in [\xA7 Shared errors](#shared-errors)). "What to tell the user" is the prompt to surface \u2014 don\'t dump the raw error:\n\n| Error code | Recovery | What to tell the user |\n| --- | --- | --- |\n| `PAYMENT_FAILED` | `inflow mpp status <transaction_id>` for the precise state, then create a new transaction with `inflow mpp pay`. (Terminal `failed` state, or no credential produced.) | "The payment didn\'t go through \u2014 it was declined, underfunded, or the transaction failed. Want me to try again, switch funding, or stop?" |\n| `PAYMENT_EXPIRED` | Start a new `inflow mpp pay`. | "The payment window expired before it was ready to settle. Want me to start a new one, or stop here?" |\n| `PAYMENT_NOT_ACCEPTED` | `inflow mpp inspect <url>` to re-check the challenge; adjust and retry. | \u2014 |\n\n### x402 errors\n\nAll errors in agent mode are JSON with `code` and `message` fields and exit code 1. x402-specific codes (shared codes are in [\xA7 Shared errors](#shared-errors)). "What to tell the user" is the prompt to surface \u2014 don\'t dump the raw error:\n\n| Error code | Recovery | What to tell the user |\n| --- | --- | --- |\n| `APPROVAL_TIMEOUT` | `inflow x402 status <transaction_id>` for the precise reason, then create a new transaction. | "You didn\'t approve within 15 minutes, so the request expired. Want me to start a new payment, or stop here?" |\n| `APPROVAL_FAILED` | Same recovery as `APPROVAL_TIMEOUT` (declined / insufficient funds in the matched asset / generic). | "Approval didn\'t go through (declined or insufficient funds in the matched asset). Want me to try a different funding source, top up, or stop?" |\n| `APPROVAL_CANCELLED` | Same recovery (cancelled via `x402 cancel` or server-side). | "You cancelled the approval. Stopping here unless you want to start a new payment." |\n| `INVALID_PAYMENT_ID` | `--payment-id` violated the format (see `inflow x402 pay --schema`). Adjust or omit the payment id. | \u2014 |\n\n---\n\n## Security & data handling\n\nApplies to both protocols.\n\n- Treat OAuth tokens and API keys as secrets \u2014 never echo them. The one-time bearer credential (`encoded_payload` for x402, `credential` for MPP) returned after approval should be replayed directly against the seller and discarded, not pasted back to the user.\n- Respect `/agents.txt` and `/llm.txt` on sites you browse.\n- Avoid suspicious 402 endpoints \u2014 if the domain doesn\'t match what the user asked to pay, or the price is different from expectation, stop and ask.\n- When displaying deposit addresses to the user, print the full address (don\'t truncate). Truncating breaks copy-paste.\n\n## Shared errors\n\nThese apply to both protocols (in addition to each section\'s protocol-specific codes). All are JSON with `code` and `message` and exit code 1. Where a command is protocol-specific, use your prefix (`<mpp|x402>`). "What to tell the user" is the prompt to surface \u2014 don\'t dump the raw error:\n\n| Error code | Recovery | What to tell the user |\n| --- | --- | --- |\n| `NOT_AUTHENTICATED` | No saved device token and no `--api-key` / `INFLOW_API_KEY` configured. Run `inflow auth login` or set the API key env var. | \u2014 |\n| `NO_INFLOW_MATCH` | Seller\'s rails aren\'t supported by the account. Fund a matching method/chain, or use a different seller. | "The seller wants `<method/rail or scheme\xD7network>`, but your account can\'t pay on that rail. Either fund a matching method, or pick a different seller." |\n| `NO_FILTERED_MATCH` | A filter emptied the candidate list. Loosen it, or re-check with `inflow <mpp|x402> inspect <url>` (filter flags per the delta table). | "Your filter removed every option the seller accepts. Loosen it or check the seller\'s options with `inflow <mpp|x402> inspect`." |\n| `INVALID_402` / `DECODE_FAILED` | Seller returned 402 but the protocol\'s header was missing (`INVALID_402`) or unparseable (`DECODE_FAILED`). Verify the URL is payable; pass the raw header to `inflow <mpp|x402> decode` for the detailed parse error. | \u2014 |\n| `POLLING_TIMEOUT` | `--interval` polling reached its max-attempts or timeout. Retryable \u2014 resume with `inflow <mpp|x402> status <transaction_id> --interval 5 --max-attempts 180`. | "Still waiting on your approval \u2014 want me to keep polling, or cancel the request? (`inflow <mpp|x402> cancel <approval_id>` cancels it.)" |\n| `api_error` | Non-2xx from the InFlow API on the plain data calls (`user`, `balances`, `deposit-addresses`); discriminate on `httpStatus`. `401` \u2014 saved auth rejected, re-run `inflow auth login`. `426` (`VERSION_UNSUPPORTED`) \u2014 upgrade and retry. `5xx` \u2014 server-side; wait and retry. (Note: `pay`/`status` rejections instead surface the server\'s own code, e.g. `INSUFFICIENT_FUNDS`, or the protocol\'s terminal code \u2014 not `api_error`.) | \u2014 |\n| `VERSION_UNSUPPORTED` / HTTP 426 | Installed `inflow` CLI is below the minimum supported version. `npm install -g @inflowpayai/inflow@latest`, then retry; don\'t retry on the old version. | \u2014 |\n| `transport_error` | Network failure \u2014 check connectivity; retry. | \u2014 |\n\n## Out of scope\n\nThis skill covers programmatic HTTP 402 payments (MPP and x402) only. It does NOT handle:\n\n- **Traditional merchant checkouts** No PANs (credit card forms, hosted checkouts).\n- **Card issuance** or wallet management beyond `balances list` and `deposit-addresses list`.\n- **Refunds, disputes, chargebacks** \u2014 handled out of band via support.\n- **Peer-to-peer transfers** between users or wallets.\n- **FX / currency conversion.** Buyer logic matches the seller\'s accepted rails against the account\'s supported assets.\n- **Subscriptions / recurring payments.** Each `pay` is one-shot.\n\nFor any of the above, point the user to https://app.inflowpay.ai or support.\n\n## Further docs\n\n- MPP protocol: https://mpp.dev\n- x402 protocol: https://x402.org\n- InFlow: https://app.inflowpay.ai\n';
17108
+ var skillBody = '# Agentic Payments\n\nPay HTTP 402-protected resources on the user\'s behalf. InFlow speaks two payment protocols \u2014 **MPP** and **x402** \u2014 but the flow is the same for both: shared setup (install, run, authenticate), then a **router** that picks the protocol from the seller\'s 402 header, then one **Paying a 402 resource** section that covers both. A per-protocol **delta table** at the top of that section lists the handful of real differences (header name, credential name, filters, error codes); read your row, then follow the shared steps.\n\n## Installing\n\nInstall with `npm install -g @inflowpayai/inflow`. Or run directly with `npx @inflowpayai/inflow`.\n\n## Running\n\nInFlow runs as a **standalone CLI** or an **MCP server**.\n\n**MCP**: add an `inflow` server to your MCP client config that runs `npx -y @inflowpayai/inflow --mcp`. Keep the `-y` flag \u2014 it suppresses npx\'s confirmation prompt, without which the MCP host can stall on first run.\n\n**MCP mode** exposes every CLI command as a tool. Call `tools/list` on the MCP server for the authoritative inventory; arguments mirror the CLI flags one-to-one.\n\n### Common commands / options\n\n**The CLI is the source of truth for exact flags, enums, and output shapes** \u2014 run `inflow <command> --schema` for one command, or `inflow --llms-full` for everything. This playbook covers *when and why*, not exhaustive parameter lists; when you need a precise flag name, value set, or response shape, query the CLI rather than guessing.\n\n- `inflow --llms` (or `--llms-full` for parameter detail) \u2014 discover all commands. `inflow <command> --schema` for a single command\'s JSON Schema.\n- `inflow --skill` \u2014 print this playbook (no frontmatter) to stdout. Use it to paste into the system-prompt field of an MCP host that doesn\'t natively load skills: `inflow --skill | pbcopy`.\n- Default output is `toon`. Override with `--format <fmt>`; for programmatic parsing prefer `json` (single document) or `jsonl` (line-delimited).\n- Multi-step flows return `_next.command` \u2014 run it to continue.\n- `--auth <path>` overrides the credentials file location.\n- `--api-key <key>` or `INFLOW_API_KEY=<key>` is an alternative to device-flow auth.\n\n## Authenticate\n\nAuthentication is shared by both protocols \u2014 do it once, before either payment flow. **Don\'t start a payment until the user is authenticated.**\n\nCheck the current state first \u2014 the user may already be logged in:\n\n```bash\ninflow auth status\n```\n\nA successful `auth status` returns `authenticated: true` plus `auth_method` (`device_token` or `api_key`), a truncated `access_token` preview (never the full token), `credentials_path`, `connection`, and possibly an `update` field. For the user\'s identity (email, handle, account id), call `inflow user get` \u2014 `auth status` deliberately omits it. Run the command to see the full shape.\n\nIf the response includes an `update` field, a newer version of `inflow` is published.\n\n**Surface and defer.** Tell the user a newer version is available and how to upgrade \u2014 `npm install -g @inflowpayai/inflow@latest` (or `npx @inflowpayai/inflow@latest`). Then **proceed with the current version**. Only block on the upgrade if a subsequent command fails with `VERSION_UNSUPPORTED` (or an HTTP 426 from the API), at which point the upgrade is mandatory and you should not retry until it lands.\n\nIf `authenticated` is `false`, start the device flow:\n\n```bash\ninflow auth login --client-name "<your-agent-name>"\n```\n\nReplace `<your-agent-name>` with the name of your agent or application (for example `"Personal Assistant"`, `"Shopping Bot"`). The device-authorization page in the user\'s browser displays this name when they approve the connection. Use a clear, unique, identifiable name.\n\nThe response includes a `verification_url` (present this to the user), a `phrase`, and a `_next.command`. Run that command immediately to poll until authenticated. **Do not wait for the user to respond before starting the poll.**\n\nIf your environment can\'t relay the verification phrase to the user while a separate polling command blocks I/O, use inline polling instead:\n\n```bash\ninflow auth login --client-name "<name>" --interval 5 --timeout 300\n```\n\n**API key alternative:** if the user provides an API key, set `INFLOW_API_KEY=<key>` in the environment (or pass `--api-key <key>` to any command) instead of running `auth login`. The API key takes precedence over a saved device token.\n\n## Which protocol? \u2014 start here\n\nBefore paying, decide which protocol the resource uses. **You do not choose it \u2014 the seller\'s 402 challenge decides.** Run one read-only, no-auth command and let it detect both:\n\n```bash\ninflow inspect <url>\n```\n\n`inflow inspect` probes the URL **once** and decodes both MPP and x402 challenges from the same 402. Read its `detected` array to pick the pay rail:\n\n| `detected` | Pay with |\n| --- | --- |\n| `["mpp"]` | `inflow mpp pay <url>` |\n| `["x402"]` | `inflow x402 pay <url>` |\n| `["mpp", "x402"]` | `inflow mpp pay <url>` \u2014 **MPP wins when both are present** |\n| `[]` (seller still returned 402) | Not InFlow-payable on this account. Stop and tell the user; check `warnings` for why. |\n\nIf `inspect` returns `outcome: "no-payment-required"`, the URL isn\'t paywalled \u2014 there\'s nothing to pay.\n\n---\n\n## Paying a 402 resource\n\nOne flow for both protocols. Prerequisite: you are authenticated (see [Authenticate](#authenticate)). First find your protocol\'s row in the **Protocol deltas** table below \u2014 it names the 402 header that selected it, the matching model, the filter flags, and the credential and replay header you\'ll use. Everything else in this section applies to both protocols.\n\n**Sequencing.** Run pre-flight before pay \u2014 `pay` fails or double-charges if the pre-flight checks didn\'t clear. `inspect` and `decode` are read-only and need no auth, so they may run before you authenticate if useful (e.g. sizing up a paywall first).\n\n### Protocol deltas\n\n| Aspect | MPP | x402 |\n| --- | --- | --- |\n| Selected when the 402 carries | `WWW-Authenticate: Payment` | `PAYMENT-REQUIRED` (and no `WWW-Authenticate: Payment`) |\n| Command prefix | `inflow mpp \u2026` | `inflow x402 \u2026` |\n| Matching model | The seller\'s challenge **pins the rail** \u2014 the buyer does not choose scheme/network/asset | Pay where the x402 `accepts` \u2229 `supported.kinds` is non-empty |\n| Filter flags | `--payment-method`, `--intent`, `--currency`, `--rail`, `--instrument-id` | `--scheme`, `--network`, `--asset`, `--asset-name` |\n| Credential field (after approval) | `credential` (from `mpp status` when `state` is `ready`) | `encoded_payload` (from `x402 status` after approval) |\n| Replay header | `Authorization: Payment <credential>` | `PAYMENT-SIGNATURE: <encoded_payload>` |\n| Write-credential-to-disk flag | `--credential-file <path>` | `--payload-file <path>` |\n| Idempotency | \u2014 | `--payment-id` (see Step 2) |\n| Cancel uses | `approval_id` | `approval_id` |\n| Protocol-specific error codes | `PAYMENT_FAILED`, `PAYMENT_EXPIRED`, `PAYMENT_NOT_ACCEPTED` | `APPROVAL_TIMEOUT`, `APPROVAL_FAILED`, `APPROVAL_CANCELLED` |\n\nThroughout this section `<mpp|x402>` means "use your protocol\'s prefix." For the exact parameters and output shape of any command below, run `inflow <command> --schema`.\n\n### Step 1: Pre-flight evaluation\n\n```bash\n# 1. Parse what the seller will accept \u2014 read-only, no auth (both protocols in one probe)\ninflow inspect <url>\n\n# (Already have the raw 402 header from a prior response? Decode it directly instead of re-probing:)\ninflow <mpp|x402> decode \'<402 header value>\'\n\n# 2. List what the buyer\'s account can pay with (use the protocol from `detected`)\ninflow <mpp|x402> supported\n\n# 3. Check balances for the candidate currency/asset(s)\ninflow balances list\n```\n\n`inflow inspect` returns what the seller accepts under its `mpp` and `x402` keys \u2014 the price is each challenge\'s `amount` field (raw atomic units for x402; the asset is the on-chain contract address, not a symbol). `decode` parses a single raw header you already hold (and also accepts a base64url credential / receipt). `supported` returns what the account can pay with; `balances list` returns `available` per currency. Run the commands to see the exact shapes.\n\nDecide whether you can pay (apply your protocol\'s matching model from the delta table):\n\n| Condition | Meaning | Action |\n| --- | --- | --- |\n| No payable match between the seller and the buyer\'s `supported` methods | No payable rail | Stop \u2192 `NO_INFLOW_MATCH`. Tell the user the seller\'s rails aren\'t supported by their account. |\n| A match exists, but `balances.available < amount` for every match | Right rail, not enough funds | Stop \u2192 run `inflow deposit-addresses list`, surface the address(es) in full, ask the user to fund a matching network. |\n| A match exists **and** \u22651 match has `balances.available \u2265 amount` | Payable | Proceed to Step 2. |\n\n**Optional filters** narrow *which* offer to fulfil \u2014 optional, AND-combined, applied on `pay`, and an empty result fails with `NO_FILTERED_MATCH` (it does not fall through to a default order). One non-obvious case: MPP\'s `--instrument-id` picks *how* to fund (an instrument-rail / fiat challenge), not which challenge. For the exact filter flags and accepted values per protocol, run `inflow <mpp|x402> pay --schema`.\n\n**Decimal precision.** `balances.available` and the challenge/`amount` value are decimal strings preserving BigDecimal precision. **Never parse them to a JS `Number`** \u2014 that drops precision. Compare as strings, or use a `BigInt` / `decimal.js`-style library.\n\n### Step 2: Pay\n\nBefore initiating the call, summarize the intent to the user in chat: amount, currency, resource URL, and the method/rail (MPP) or scheme/network (x402). The user verifies the canonical details on the approval screen; the chat summary is what they read first. Example:\n\n> "I\'m about to pay 0.10 USDC to api.foo.dev for /dataset.csv. Requesting approval next."\n\n**Fast path (recommended).** When the agent can block until the payment finishes, set `--interval N` and let the CLI run the whole flow in one call \u2014 probe, decode, prepare, await approval, replay against the seller, return the body:\n\n```bash\ninflow <mpp|x402> pay <url> --interval 5 --max-attempts 180\n```\n\nThe result includes `outcome`, `transaction_id`, `response_status`, `settled`, the seller body inline (or `output_saved_to` if `--output-file` is set), and the now-consumed credential (`credential` for MPP, `encoded_payload` for x402). On the fast path the CLI has already replayed that credential to fetch the body \u2014 it appears in the result for reference only; **do not replay it yourself.** To surface `approval_url` *before* the call returns, add `--format jsonl` \u2014 frames stream line-by-line. With the default `json` (or `toon`), the agent only sees the final buffered result.\n\n**`outcome` values.** A completed `pay` returns one of three terminal outcomes \u2014 branch on it, don\'t assume `paid`:\n\n| `outcome` | Meaning | What to do |\n| --- | --- | --- |\n| `paid` | Settled and the seller returned 2xx | Deliver the body to the user |\n| `no-payment-required` | The resource wasn\'t paywalled, or was already paid | Tell the user nothing was charged; return the body |\n| `replay-rejected` | Payment was approved (funds in transit) but the seller replied non-2xx on the replay | Do NOT report success. Tell the user the seller\'s response failed; because the payment didn\'t complete, the in-transit funds are reverted to their InFlow balance. Offer to retry |\n\n**Two-step path.** Use this when the agent\'s host can\'t block I/O long enough for the user to approve (chat UIs that yield between turns). Drop `--interval`; the first call returns `transaction_id` + `approval_id` + `approval_url` + a `_next` `status` command, and the agent drives the replay itself once a credential arrives.\n\n```bash\ninflow <mpp|x402> pay <url>\n# -> { "transaction_id": "txn_abc", "approval_id": "appr_xyz", "approval_url": "https://app.inflowpay.ai/approvals/appr_xyz", "_next": { "command": "<mpp|x402> status txn_abc --interval 5 --max-attempts 180" } }\n```\n\nMind the two distinct ids: poll, replay, and resume all use `transaction_id`; **cancel uses `approval_id`** (`inflow <mpp|x402> cancel <approval_id>`). Both are returned by `pay`.\n\nFor non-GET requests, pass `--method`, `--data`, `--header` (repeatable):\n\n```bash\ninflow <mpp|x402> pay https://seller.example.com/api/widgets --method POST --data \'{"sku":"widget-1"}\' --header "X-Custom: value" --interval 5 --max-attempts 180\n```\n\n**Idempotency (x402 only).** Set `--payment-id <id>` whenever a retry on transport failure is possible \u2014 the server treats two requests with the same id as the same logical payment, so a retry after a network blip won\'t double-charge. Use a stable random opaque value generated once per intent; reuse the same id on transport retry; regenerate only when the user explicitly wants a fresh charge. Don\'t tie the id to wall-clock time \u2014 a date-based id silently double-charges on next-day "buy this again" requests. Without `--payment-id`, the server generates one each call \u2014 fine for one-shots, unsafe for retries. (Format constraints: `inflow x402 pay --schema`.)\n\n```bash\ninflow x402 pay <url> --payment-id "<stable-opaque-id>"\n```\n\n**Sensitive / binary output.** The one-time bearer credential (`credential` for MPP, `encoded_payload` for x402; returned after approval and echoed in the fast-path result) must not be echoed back in chat. Write it to disk at mode `0o600` with your protocol\'s flag (`--credential-file <path>` for MPP, `--payload-file <path>` for x402); replay then reads from that file. For the seller\'s response body, `--output-file <path>` writes bytes to disk and replaces `body` / `body_base64` with `output_saved_to: <path>` \u2014 pair with `--no-show-body` for binary content (PDFs, images, audio, datasets) so bytes never appear inline as base64:\n\n```bash\ninflow <mpp|x402> pay https://api.foo.dev/dataset.csv --interval 5 --max-attempts 180 --output-file /tmp/dataset.csv --no-show-body\n```\n\n**Polling discipline.** Persist `transaction_id` as soon as `pay` returns it. Then:\n\n- Run `_next.command` (or `<mpp|x402> status <transaction_id> --interval N`) immediately. Don\'t wait for the user to confirm before polling starts.\n- If polling is interrupted \u2014 network drop, session bounce, user kills the agent \u2014 resume with `inflow <mpp|x402> status <transaction_id> --interval 5 --max-attempts 180`. Only create a new transaction if the original expired (`PAYMENT_EXPIRED` for MPP, `APPROVAL_TIMEOUT` for x402), was denied/cancelled, or its credential is already consumed.\n- If `POLLING_TIMEOUT` fires before approval, ask the user whether to keep waiting or cancel \u2014 don\'t silently restart the poll.\n- If >12 minutes elapsed without a user response (\u22483 min before the 15-minute approval window closes), surface that explicitly so they can act before the window closes.\n- If the user aborts ("nevermind", "cancel that"), call `inflow <mpp|x402> cancel <approval_id>` before exiting. Otherwise the approval sits pending for 15 minutes and triggers phantom notifications in the user\'s InFlow app.\n\nOnce `status` reports the credential (MPP: `state: ready` with `credential`; x402: `encoded_payload`), replay the original seller request with your protocol\'s replay header from the delta table \u2014 `Authorization: Payment <credential>` (MPP) or `PAYMENT-SIGNATURE: <encoded_payload>` (x402); use `$(cat <file>)` if you wrote it to disk with `--credential-file` / `--payload-file`. The seller\'s protected response comes back on the replay.\n\n### Limits\n\n| Limit | Value |\n| --- | --- |\n| Approval window | 15 minutes from `pay` creating the transaction (`--timeout` overrides the polling deadline) |\n| Polling stop condition | Polling ends at whichever fires first: `--max-attempts` (count, default `0` = unlimited) or `--timeout` (seconds, default `900` = the full 15-min window). The examples use `--interval 5 --max-attempts 180` (= 900 s) so a copied command covers the whole window \u2014 `--interval 5 --max-attempts 60` (= 300 s) would stop polling at 5 min, well before approval can land |\n| Credential reuse | One-time. The credential (`credential` for MPP, `encoded_payload` for x402) is consumed by the first seller replay \u2014 not reusable; a failed seller call requires a new `pay` |\n\n### Worked example (MPP)\n\nA user asks the agent to fetch a paywalled dataset at `https://api.foo.dev/dataset.csv`.\n\nPre-flight: `inflow inspect <url>` reports `detected: ["mpp"]` with the seller\'s challenges; then `inflow mpp supported` (methods the buyer can pay with) and `inflow balances list`. The seller offers the `inflow` method in USDC; the user\'s 100.5 USDC balance covers the 0.10 USDC price. Summarize intent, then pay:\n\n```bash\ninflow mpp pay https://api.foo.dev/dataset.csv --interval 5 --max-attempts 180 --output-file /tmp/dataset.csv --no-show-body\n# Persist transaction_id from the response in case polling is interrupted.\n# Returns outcome "paid" with output_saved_to /tmp/dataset.csv.\n```\n\n> "Approval requested \u2014 confirm in the InFlow app: https://app.inflowpay.ai/approvals/appr_xyz\n> I\'ll keep polling. 15-min window."\n\nOnce the result arrives:\n\n> "Paid 0.10 USDC. Transaction txn_abc. Saved the dataset to /tmp/dataset.csv."\n\n**Two-step variant** (host can\'t block): follow Step 2\'s two-step path; once `mpp status` reports `state: ready`, replay with `Authorization: Payment <credential>` (or `$(cat <path>)` via `--credential-file` to keep it out of chat).\n\n### Worked example (x402)\n\nA user asks the agent to fetch a paywalled article at `https://api.foo.dev/article-3`.\n\nPre-flight: `inflow inspect <url>` reports `detected: ["x402"]`; the intersection lands on `exact` \xD7 `solana:mainnet`, and the user\'s 100.5 USDC balance easily covers the 0.10 USDC the seller requires. Proceed.\n\n> "I\'m about to pay 0.10 USDC on Solana mainnet to api.foo.dev for /article-3.\n> Your balance is 100.5 USDC \u2014 plenty. Requesting approval next."\n\n```bash\ninflow x402 pay https://api.foo.dev/article-3 --payment-id "<stable-opaque-id>" --interval 5 --max-attempts 180\n# Persist transaction_id from the response in case polling gets interrupted.\n# Returns outcome "paid"; body contains the article JSON.\n```\n\n> "Approval requested \u2014 confirm in the InFlow app: https://app.inflowpay.ai/approvals/appr_xyz\n> I\'ll keep polling. 15-min window."\n\nOnce the result arrives:\n\n> "Paid 0.10 USDC. Transaction txn_abc. Server returned: \'How to brew coffee \u2014 ...\'"\n\n**Two-step variant** (host can\'t block): follow Step 2\'s two-step path; once `x402 status` returns the `encoded_payload`, replay with `PAYMENT-SIGNATURE: <encoded_payload>` (use `--payload-file` to keep it out of chat).\n\n### MPP errors\n\nAll errors in agent mode are JSON with `code` and `message` fields and exit code 1. MPP-specific codes (shared codes are in [\xA7 Shared errors](#shared-errors)). "What to tell the user" is the prompt to surface \u2014 don\'t dump the raw error:\n\n| Error code | Recovery | What to tell the user |\n| --- | --- | --- |\n| `PAYMENT_FAILED` | `inflow mpp status <transaction_id>` for the precise state, then create a new transaction with `inflow mpp pay`. (Terminal `failed` state, or no credential produced.) | "The payment didn\'t go through \u2014 it was declined, underfunded, or the transaction failed. Want me to try again, switch funding, or stop?" |\n| `PAYMENT_EXPIRED` | Start a new `inflow mpp pay`. | "The payment window expired before it was ready to settle. Want me to start a new one, or stop here?" |\n| `PAYMENT_NOT_ACCEPTED` | `inflow inspect <url>` to re-check the challenge; adjust and retry. | \u2014 |\n\n### x402 errors\n\nAll errors in agent mode are JSON with `code` and `message` fields and exit code 1. x402-specific codes (shared codes are in [\xA7 Shared errors](#shared-errors)). "What to tell the user" is the prompt to surface \u2014 don\'t dump the raw error:\n\n| Error code | Recovery | What to tell the user |\n| --- | --- | --- |\n| `APPROVAL_TIMEOUT` | `inflow x402 status <transaction_id>` for the precise reason, then create a new transaction. | "You didn\'t approve within 15 minutes, so the request expired. Want me to start a new payment, or stop here?" |\n| `APPROVAL_FAILED` | Same recovery as `APPROVAL_TIMEOUT` (declined / insufficient funds in the matched asset / generic). | "Approval didn\'t go through (declined or insufficient funds in the matched asset). Want me to try a different funding source, top up, or stop?" |\n| `APPROVAL_CANCELLED` | Same recovery (cancelled via `x402 cancel` or server-side). | "You cancelled the approval. Stopping here unless you want to start a new payment." |\n| `INVALID_PAYMENT_ID` | `--payment-id` violated the format (see `inflow x402 pay --schema`). Adjust or omit the payment id. | \u2014 |\n\n---\n\n## Security & data handling\n\nApplies to both protocols.\n\n- Treat OAuth tokens and API keys as secrets \u2014 never echo them. The one-time bearer credential (`encoded_payload` for x402, `credential` for MPP) returned after approval should be replayed directly against the seller and discarded, not pasted back to the user.\n- Respect `/agents.txt` and `/llm.txt` on sites you browse.\n- Avoid suspicious 402 endpoints \u2014 if the domain doesn\'t match what the user asked to pay, or the price is different from expectation, stop and ask.\n- When displaying deposit addresses to the user, print the full address (don\'t truncate). Truncating breaks copy-paste.\n\n## Shared errors\n\nThese apply to both protocols (in addition to each section\'s protocol-specific codes). All are JSON with `code` and `message` and exit code 1. Where a command is protocol-specific, use your prefix (`<mpp|x402>`). "What to tell the user" is the prompt to surface \u2014 don\'t dump the raw error:\n\n| Error code | Recovery | What to tell the user |\n| --- | --- | --- |\n| `NOT_AUTHENTICATED` | No saved device token and no `--api-key` / `INFLOW_API_KEY` configured. Run `inflow auth login` or set the API key env var. | \u2014 |\n| `NO_INFLOW_MATCH` | Seller\'s rails aren\'t supported by the account. Fund a matching method/chain, or use a different seller. | "The seller wants `<method/rail or scheme\xD7network>`, but your account can\'t pay on that rail. Either fund a matching method, or pick a different seller." |\n| `NO_FILTERED_MATCH` | A `pay` filter emptied the candidate list. Loosen the filter (flags per the delta table), or re-check the seller\'s unfiltered options with `inflow inspect <url>`. | "Your filter removed every option the seller accepts. Loosen it or re-check the seller\'s options with `inflow inspect`." |\n| `INVALID_402` / `DECODE_FAILED` | Seller returned 402 but the protocol\'s header was missing (`INVALID_402`) or unparseable (`DECODE_FAILED`). Verify the URL is payable; pass the raw header to `inflow <mpp|x402> decode` for the detailed parse error. | \u2014 |\n| `POLLING_TIMEOUT` | `--interval` polling reached its max-attempts or timeout. Retryable \u2014 resume with `inflow <mpp|x402> status <transaction_id> --interval 5 --max-attempts 180`. | "Still waiting on your approval \u2014 want me to keep polling, or cancel the request? (`inflow <mpp|x402> cancel <approval_id>` cancels it.)" |\n| `api_error` | Non-2xx from the InFlow API on the plain data calls (`user`, `balances`, `deposit-addresses`); discriminate on `httpStatus`. `401` \u2014 saved auth rejected, re-run `inflow auth login`. `426` (`VERSION_UNSUPPORTED`) \u2014 upgrade and retry. `5xx` \u2014 server-side; wait and retry. (Note: `pay`/`status` rejections instead surface the server\'s own code, e.g. `INSUFFICIENT_FUNDS`, or the protocol\'s terminal code \u2014 not `api_error`.) | \u2014 |\n| `VERSION_UNSUPPORTED` / HTTP 426 | Installed `inflow` CLI is below the minimum supported version. `npm install -g @inflowpayai/inflow@latest`, then retry; don\'t retry on the old version. | \u2014 |\n| `transport_error` | Network failure \u2014 check connectivity; retry. | \u2014 |\n\n## Out of scope\n\nThis skill covers programmatic HTTP 402 payments (MPP and x402) only. It does NOT handle:\n\n- **Traditional merchant checkouts** No PANs (credit card forms, hosted checkouts).\n- **Card issuance** or wallet management beyond `balances list` and `deposit-addresses list`.\n- **Refunds, disputes, chargebacks** \u2014 handled out of band via support.\n- **Peer-to-peer transfers** between users or wallets.\n- **FX / currency conversion.** Buyer logic matches the seller\'s accepted rails against the account\'s supported assets.\n- **Subscriptions / recurring payments.** Each `pay` is one-shot.\n\nFor any of the above, point the user to https://app.inflowpay.ai or support.\n\n## Further docs\n\n- MPP protocol: https://mpp.dev\n- x402 protocol: https://x402.org\n- InFlow: https://app.inflowpay.ai\n';
16701
17109
  if (process9.argv.includes("--skill")) {
16702
17110
  process9.stdout.write(skillBody.endsWith("\n") ? skillBody : `${skillBody}
16703
17111
  `);
@@ -16717,9 +17125,20 @@ function extractFlag(name) {
16717
17125
  }
16718
17126
  function extractBooleanFlag(name) {
16719
17127
  const idx = process9.argv.indexOf(name);
16720
- if (idx === -1) return false;
16721
- process9.argv.splice(idx, 1);
16722
- return true;
17128
+ if (idx !== -1) {
17129
+ process9.argv.splice(idx, 1);
17130
+ return true;
17131
+ }
17132
+ const prefix = `${name}=`;
17133
+ const assignmentIdx = process9.argv.findIndex((arg2) => arg2.startsWith(prefix));
17134
+ if (assignmentIdx === -1) return false;
17135
+ const [arg] = process9.argv.splice(assignmentIdx, 1);
17136
+ const value = arg?.slice(prefix.length) ?? "";
17137
+ if (value === "true") return true;
17138
+ if (value === "false") return false;
17139
+ process9.stderr.write(`Invalid ${name} value: ${value}. Expected 'true' or 'false'.
17140
+ `);
17141
+ process9.exit(2);
16723
17142
  }
16724
17143
  var credentialFilePath = extractFlag("--auth") ?? process9.env.INFLOW_AUTH_FILE;
16725
17144
  var baseUrlFromFlag = extractFlag("--base-url");
@@ -16729,7 +17148,7 @@ var authBaseUrlFromFlag = extractFlag("--auth-base-url");
16729
17148
  var environmentFromFlag = extractFlag("--environment");
16730
17149
  var sandboxFlag = extractBooleanFlag("--sandbox");
16731
17150
  var apiKeyFromFlag = extractFlag("--api-key");
16732
- var verbose = process9.argv.includes("--verbose");
17151
+ var verbose = extractBooleanFlag("--verbose");
16733
17152
  var authStorage = credentialFilePath ? new Storage({ configPath: credentialFilePath }) : storage;
16734
17153
  var apiKeyFromEnv = process9.env.INFLOW_API_KEY;
16735
17154
  function readSavedApiKey() {
@@ -16824,6 +17243,7 @@ cli.command(createBalancesCli(inflow.balances, authStorage, inflow));
16824
17243
  cli.command(createDepositAddressesCli(inflow.depositAddresses, authStorage, inflow));
16825
17244
  cli.command(createX402Cli(inflow, authStorage, resolvedApiBaseUrl));
16826
17245
  cli.command(createMppCli(inflow, authStorage, resolvedApiBaseUrl));
17246
+ cli.command("inspect", createInspectCommand());
16827
17247
  await cli.serve();
16828
17248
  var cli_default = cli;
16829
17249
  export {