@agentwonderland/mcp 0.1.23 → 0.1.24

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 (74) hide show
  1. package/dist/core/__tests__/card-setup.test.d.ts +1 -0
  2. package/dist/core/__tests__/card-setup.test.js +99 -0
  3. package/dist/core/__tests__/formatters.test.d.ts +1 -0
  4. package/dist/core/__tests__/formatters.test.js +15 -0
  5. package/dist/core/__tests__/passes.test.d.ts +1 -0
  6. package/dist/core/__tests__/passes.test.js +82 -0
  7. package/dist/core/__tests__/payments.test.d.ts +1 -0
  8. package/dist/core/__tests__/payments.test.js +52 -0
  9. package/dist/core/__tests__/principal.test.d.ts +1 -0
  10. package/dist/core/__tests__/principal.test.js +67 -0
  11. package/dist/core/api-client.d.ts +9 -4
  12. package/dist/core/api-client.js +52 -22
  13. package/dist/core/card-setup.d.ts +20 -13
  14. package/dist/core/card-setup.js +85 -29
  15. package/dist/core/config.d.ts +3 -0
  16. package/dist/core/config.js +24 -2
  17. package/dist/core/formatters.d.ts +2 -0
  18. package/dist/core/formatters.js +5 -1
  19. package/dist/core/index.d.ts +2 -0
  20. package/dist/core/index.js +2 -0
  21. package/dist/core/ows-adapter.d.ts +10 -2
  22. package/dist/core/ows-adapter.js +54 -10
  23. package/dist/core/passes.d.ts +40 -0
  24. package/dist/core/passes.js +32 -0
  25. package/dist/core/payments.d.ts +8 -0
  26. package/dist/core/payments.js +97 -13
  27. package/dist/core/principal.d.ts +2 -0
  28. package/dist/core/principal.js +109 -0
  29. package/dist/core/solana-charge.d.ts +9 -0
  30. package/dist/core/solana-charge.js +95 -0
  31. package/dist/core/types.d.ts +10 -0
  32. package/dist/index.js +8 -3
  33. package/dist/prompts/index.js +1 -1
  34. package/dist/resources/wallet.js +8 -1
  35. package/dist/tools/__tests__/_payment-confirmation.test.d.ts +1 -0
  36. package/dist/tools/__tests__/_payment-confirmation.test.js +30 -0
  37. package/dist/tools/_payment-confirmation.d.ts +6 -0
  38. package/dist/tools/_payment-confirmation.js +28 -0
  39. package/dist/tools/agent-info.js +14 -0
  40. package/dist/tools/index.d.ts +1 -0
  41. package/dist/tools/index.js +1 -0
  42. package/dist/tools/passes.d.ts +2 -0
  43. package/dist/tools/passes.js +157 -0
  44. package/dist/tools/run.js +113 -51
  45. package/dist/tools/solve.js +102 -44
  46. package/dist/tools/wallet.js +85 -50
  47. package/package.json +3 -1
  48. package/src/core/__tests__/card-setup.test.ts +118 -0
  49. package/src/core/__tests__/formatters.test.ts +17 -0
  50. package/src/core/__tests__/passes.test.ts +94 -0
  51. package/src/core/__tests__/payments.test.ts +60 -0
  52. package/src/core/__tests__/principal.test.ts +87 -0
  53. package/src/core/api-client.ts +70 -23
  54. package/src/core/card-setup.ts +109 -34
  55. package/src/core/config.ts +29 -3
  56. package/src/core/formatters.ts +7 -1
  57. package/src/core/index.ts +2 -0
  58. package/src/core/ows-adapter.ts +74 -8
  59. package/src/core/passes.ts +74 -0
  60. package/src/core/payments.ts +113 -13
  61. package/src/core/principal.ts +128 -0
  62. package/src/core/solana-charge.ts +149 -0
  63. package/src/core/types.ts +10 -0
  64. package/src/index.ts +8 -3
  65. package/src/prompts/index.ts +1 -1
  66. package/src/resources/wallet.ts +8 -1
  67. package/src/tools/__tests__/_payment-confirmation.test.ts +45 -0
  68. package/src/tools/_payment-confirmation.ts +52 -0
  69. package/src/tools/agent-info.ts +23 -0
  70. package/src/tools/index.ts +1 -0
  71. package/src/tools/passes.ts +234 -0
  72. package/src/tools/run.ts +171 -55
  73. package/src/tools/solve.ts +149 -56
  74. package/src/tools/wallet.ts +102 -52
@@ -1,41 +1,50 @@
1
- import QRCode from "qrcode";
2
- import { apiPost, apiGet } from "./api-client.js";
3
- import { getApiUrl, setCardConfig } from "./config.js";
1
+ import { apiPost, apiGet, ApiError } from "./api-client.js";
2
+ import { getApiUrl, setCardConfig, getPendingCardSetupToken, setPendingCardSetupToken, } from "./config.js";
3
+ let cachedCapabilities = null;
4
+ function buildCardSetupUrl(token) {
5
+ return `${getApiUrl()}/card/handoff/${token}`;
6
+ }
4
7
  /**
5
- * Initiate card setup creates a Stripe Checkout session and returns
6
- * QR code + short URL for the user to scan.
8
+ * Create a new card setup session or resume the pending one from config.
7
9
  */
8
- export async function initiateCardSetup() {
9
- const { url: _checkoutUrl, token } = await apiPost("/card/setup", {});
10
- // Short redirect URL keeps the QR code small and scannable
11
- const apiUrl = getApiUrl();
12
- const shortUrl = `${apiUrl}/card/link/${token}`;
13
- const rawQr = await QRCode.toString(shortUrl, {
14
- type: "utf8",
15
- errorCorrectionLevel: "L",
16
- margin: 2,
17
- });
18
- // Pad every line with consistent leading spaces so the QR aligns
19
- // properly in terminal renderers that add prefixes to the first line
20
- const qr = rawQr.split("\n").map((line) => " " + line).join("\n");
21
- return { qr, url: shortUrl, token };
10
+ export async function getOrCreatePendingCardSetup() {
11
+ const pendingToken = getPendingCardSetupToken();
12
+ if (pendingToken) {
13
+ const url = buildCardSetupUrl(pendingToken);
14
+ return {
15
+ url,
16
+ token: pendingToken,
17
+ isNew: false,
18
+ };
19
+ }
20
+ const { token } = await apiPost("/card/setup", {});
21
+ setPendingCardSetupToken(token);
22
+ const url = buildCardSetupUrl(token);
23
+ return {
24
+ url,
25
+ token,
26
+ isNew: true,
27
+ };
22
28
  }
23
29
  /**
24
- * Format the card setup prompt as multiple content blocks.
25
- * Block 1: QR code (may be collapsed in some clients)
26
- * Block 2: URL + instructions (short, always visible)
30
+ * Format the card setup prompt as a single text block.
31
+ *
32
+ * Some MCP clients only surface one text chunk or collapse multi-part tool
33
+ * output, which can hide the QR code entirely. Keeping everything in one
34
+ * message makes the browser handoff much more reliable.
27
35
  */
28
- export function formatCardSetupBlocks(qr, url) {
36
+ export function formatCardSetupBlocks(url) {
29
37
  return [
30
- "\n" + qr.trim(),
31
38
  [
32
- `IMPORTANT: You MUST present this link to the user so they can connect a payment card:`,
39
+ "Open this setup page to connect your card:",
33
40
  "",
34
41
  url,
35
42
  "",
36
- `Tell the user: "Scan the QR code above or open this link to connect your card. Let me know when you're done."`,
43
+ "The setup page will take you to Stripe to securely save the card.",
44
+ "",
45
+ `Tell the user: "Open this setup page to connect your card. Let me know when you're done."`,
37
46
  `After they confirm, call wallet_setup({ action: "add-card" }) to complete setup.`,
38
- `Crypto wallets (Base/Tempo USDC) are also available via wallet_setup({ action: "create" }).`,
47
+ `Crypto wallets (Tempo, Base, or Solana USDC) are also available via wallet_setup({ action: "create" }).`,
39
48
  ].join("\n"),
40
49
  ];
41
50
  }
@@ -45,7 +54,6 @@ export function formatCardSetupBlocks(qr, url) {
45
54
  export async function pollCardSetup(token, timeoutMs = 120_000) {
46
55
  const deadline = Date.now() + timeoutMs;
47
56
  while (Date.now() < deadline) {
48
- await new Promise((r) => setTimeout(r, 3000));
49
57
  try {
50
58
  const status = await apiGet(`/card/status?token=${token}`);
51
59
  if (status.status === "complete" && status.consumer_token) {
@@ -61,12 +69,60 @@ export async function pollCardSetup(token, timeoutMs = 120_000) {
61
69
  last4: card.last4,
62
70
  brand: card.brand,
63
71
  });
72
+ setPendingCardSetupToken(null);
64
73
  return card;
65
74
  }
66
75
  }
67
- catch {
76
+ catch (err) {
77
+ if (err instanceof ApiError && err.status === 404) {
78
+ setPendingCardSetupToken(null);
79
+ return null;
80
+ }
68
81
  // Keep polling
69
82
  }
83
+ const remainingMs = deadline - Date.now();
84
+ if (remainingMs <= 0)
85
+ break;
86
+ await new Promise((r) => setTimeout(r, Math.min(3000, remainingMs)));
70
87
  }
71
88
  return null;
72
89
  }
90
+ export async function getCardCapabilities() {
91
+ const apiUrl = getApiUrl();
92
+ if (cachedCapabilities && cachedCapabilities.apiUrl === apiUrl && cachedCapabilities.expiresAt > Date.now()) {
93
+ return cachedCapabilities.value;
94
+ }
95
+ try {
96
+ const capabilities = await apiGet("/card/capabilities");
97
+ cachedCapabilities = {
98
+ value: capabilities,
99
+ apiUrl,
100
+ expiresAt: Date.now() + 30_000,
101
+ };
102
+ return capabilities;
103
+ }
104
+ catch (err) {
105
+ if (err instanceof ApiError) {
106
+ const fallback = {
107
+ spt_status: "unknown",
108
+ message: err.message,
109
+ };
110
+ cachedCapabilities = {
111
+ value: fallback,
112
+ apiUrl,
113
+ expiresAt: Date.now() + 10_000,
114
+ };
115
+ return fallback;
116
+ }
117
+ const fallback = {
118
+ spt_status: "unknown",
119
+ message: "Could not determine card payment availability.",
120
+ };
121
+ cachedCapabilities = {
122
+ value: fallback,
123
+ apiUrl,
124
+ expiresAt: Date.now() + 10_000,
125
+ };
126
+ return fallback;
127
+ }
128
+ }
@@ -21,6 +21,7 @@ export interface Config {
21
21
  defaultWallet: string | null;
22
22
  defaultPaymentMethod?: string;
23
23
  card: CardConfig | null;
24
+ pendingCardSetupToken?: string | null;
24
25
  favorites: string[];
25
26
  /** Require user confirmation before spending. Default: true. Set false for headless/automated use. */
26
27
  confirmBeforeSpend: boolean;
@@ -73,6 +74,8 @@ export declare function getCardConfig(): CardConfig | null;
73
74
  * Save card configuration after setup.
74
75
  */
75
76
  export declare function setCardConfig(card: CardConfig | null): void;
77
+ export declare function getPendingCardSetupToken(): string | null;
78
+ export declare function setPendingCardSetupToken(token: string | null): void;
76
79
  /**
77
80
  * Resolve a payment method string to a wallet + chain.
78
81
  * Accepts: wallet ID, chain name, or "card".
@@ -34,7 +34,9 @@ function migrateIfNeeded(raw) {
34
34
  userId: raw.userId ?? null,
35
35
  wallets: raw.wallets,
36
36
  defaultWallet: raw.defaultWallet ?? null,
37
+ defaultPaymentMethod: raw.defaultPaymentMethod ?? undefined,
37
38
  card: raw.card ?? null,
39
+ pendingCardSetupToken: r.pendingCardSetupToken ?? null,
38
40
  favorites: r.favorites ?? [],
39
41
  confirmBeforeSpend: r.confirmBeforeSpend !== false,
40
42
  defaultTipAmount: typeof r.defaultTipAmount === "number" ? r.defaultTipAmount : 0,
@@ -103,7 +105,9 @@ function migrateIfNeeded(raw) {
103
105
  userId: raw.userId ?? null,
104
106
  wallets,
105
107
  defaultWallet,
108
+ defaultPaymentMethod: raw.defaultPaymentMethod ?? undefined,
106
109
  card,
110
+ pendingCardSetupToken: null,
107
111
  favorites: [],
108
112
  confirmBeforeSpend: true,
109
113
  defaultTipAmount: 0,
@@ -124,6 +128,7 @@ export function getConfig() {
124
128
  wallets: [],
125
129
  defaultWallet: null,
126
130
  card: null,
131
+ pendingCardSetupToken: null,
127
132
  favorites: [],
128
133
  confirmBeforeSpend: true,
129
134
  defaultTipAmount: 0,
@@ -263,13 +268,30 @@ export function getCardConfig() {
263
268
  * Save card configuration after setup.
264
269
  */
265
270
  export function setCardConfig(card) {
271
+ const current = getConfig();
266
272
  if (card) {
267
- saveConfig({ card, defaultPaymentMethod: "card" });
273
+ saveConfig({
274
+ card,
275
+ defaultPaymentMethod: "card",
276
+ pendingCardSetupToken: null,
277
+ });
268
278
  }
269
279
  else {
270
- saveConfig({ card });
280
+ saveConfig({
281
+ card,
282
+ pendingCardSetupToken: null,
283
+ defaultPaymentMethod: current.defaultPaymentMethod === "card"
284
+ ? undefined
285
+ : current.defaultPaymentMethod,
286
+ });
271
287
  }
272
288
  }
289
+ export function getPendingCardSetupToken() {
290
+ return getConfig().pendingCardSetupToken ?? null;
291
+ }
292
+ export function setPendingCardSetupToken(token) {
293
+ saveConfig({ pendingCardSetupToken: token });
294
+ }
273
295
  /**
274
296
  * Resolve a payment method string to a wallet + chain.
275
297
  * Accepts: wallet ID, chain name, or "card".
@@ -43,6 +43,8 @@ interface RunResultLike {
43
43
  estimated_cost?: number;
44
44
  input_tokens?: number;
45
45
  tags?: string[];
46
+ consumption_mode?: string;
47
+ credit_pack_id?: string;
46
48
  }
47
49
  export declare function formatRunResult(result: RunResultLike, opts?: {
48
50
  paymentMethod?: string;
@@ -110,6 +110,7 @@ export function formatRunResult(result, opts) {
110
110
  }
111
111
  // Summary line
112
112
  const cost = result.cost ?? result.estimated_cost;
113
+ const usedCreditPack = result.consumption_mode === "credit_pack";
113
114
  const status = result.status === "success" || result.status === "completed" ? "✓" : "✗";
114
115
  const agent = result.agent_name ?? result.agent_id ?? "";
115
116
  const costStr = cost != null ? `$${cost.toFixed(cost < 0.01 ? 6 : 2)}` : "";
@@ -119,7 +120,10 @@ export function formatRunResult(result, opts) {
119
120
  if (result.error_code) {
120
121
  lines.push(`Error: ${result.error_code}`);
121
122
  }
122
- if (costStr) {
123
+ if (usedCreditPack) {
124
+ lines.push(`Covered by credit pack${result.credit_pack_id ? ` (${result.credit_pack_id})` : ""}`);
125
+ }
126
+ if (costStr && !usedCreditPack) {
123
127
  lines.push(`Paid: ${costStr}${method ? ` via ${method}` : ""}`);
124
128
  }
125
129
  if (result.job_id) {
@@ -1,6 +1,8 @@
1
1
  export * from "./api-client.js";
2
2
  export * from "./config.js";
3
3
  export * from "./payments.js";
4
+ export * from "./principal.js";
5
+ export * from "./passes.js";
4
6
  export * from "./ows-adapter.js";
5
7
  export * from "./formatters.js";
6
8
  export * from "./types.js";
@@ -1,6 +1,8 @@
1
1
  export * from "./api-client.js";
2
2
  export * from "./config.js";
3
3
  export * from "./payments.js";
4
+ export * from "./principal.js";
5
+ export * from "./passes.js";
4
6
  export * from "./ows-adapter.js";
5
7
  export * from "./formatters.js";
6
8
  export * from "./types.js";
@@ -8,6 +8,7 @@
8
8
  * ALL imports are dynamic so the MCP server works without OWS installed.
9
9
  */
10
10
  import type { LocalAccount } from "viem/accounts";
11
+ import type { Keypair } from "@solana/web3.js";
11
12
  /**
12
13
  * Check whether the OWS native module can be loaded.
13
14
  */
@@ -19,17 +20,19 @@ export declare function isOwsAvailable(): Promise<boolean>;
19
20
  * @param chain - OWS chain identifier (default "evm")
20
21
  */
21
22
  export declare function owsAccountFromWalletId(walletId: string, _chain?: string): Promise<LocalAccount>;
23
+ export declare function owsSolanaKeypairFromWalletId(walletId: string): Promise<Keypair>;
24
+ export declare function getOwsWalletAddress(walletId: string, chain?: "evm" | "solana"): Promise<string>;
22
25
  /**
23
26
  * Create a new OWS wallet and return its ID + EVM address.
24
27
  */
25
- export declare function createOwsWallet(name: string): Promise<{
28
+ export declare function createOwsWallet(name: string, chain?: "evm" | "solana"): Promise<{
26
29
  walletId: string;
27
30
  address: string;
28
31
  }>;
29
32
  /**
30
33
  * Import an existing EVM private key into OWS.
31
34
  */
32
- export declare function importKeyToOws(privateKey: string, name: string): Promise<{
35
+ export declare function importKeyToOws(privateKey: string, name: string, chain?: "evm" | "solana"): Promise<{
33
36
  walletId: string;
34
37
  address: string;
35
38
  }>;
@@ -41,3 +44,8 @@ export declare function listOwsWallets(): Promise<Array<{
41
44
  name: string;
42
45
  address: string;
43
46
  }>>;
47
+ export declare function listOwsWalletsByChain(chain?: "evm" | "solana"): Promise<Array<{
48
+ id: string;
49
+ name: string;
50
+ address: string;
51
+ }>>;
@@ -38,6 +38,26 @@ function findEvmAccount(wallet) {
38
38
  }
39
39
  return evm;
40
40
  }
41
+ function findSolanaAccount(wallet) {
42
+ const solana = wallet.accounts.find((a) => a.chainId.startsWith("solana"));
43
+ if (!solana) {
44
+ throw new Error(`Wallet "${wallet.name}" (${wallet.id}) has no Solana account.`);
45
+ }
46
+ return solana;
47
+ }
48
+ function ed25519HexToBytes(privateKeyHex) {
49
+ return Uint8Array.from(Buffer.from(privateKeyHex, "hex"));
50
+ }
51
+ function keypairFromEd25519Hex(privateKeyHex, KeypairCtor) {
52
+ const bytes = ed25519HexToBytes(privateKeyHex);
53
+ if (bytes.length === 32) {
54
+ return KeypairCtor.fromSeed(bytes);
55
+ }
56
+ if (bytes.length === 64) {
57
+ return KeypairCtor.fromSecretKey(bytes);
58
+ }
59
+ throw new Error(`Unsupported ed25519 key length: ${bytes.length} bytes.`);
60
+ }
41
61
  // ── Public API ───────────────────────────────────────────────────
42
62
  /**
43
63
  * Check whether the OWS native module can be loaded.
@@ -73,38 +93,62 @@ export async function owsAccountFromWalletId(walletId, _chain) {
73
93
  const { privateKeyToAccount } = await import("viem/accounts");
74
94
  return privateKeyToAccount(`0x${keys.secp256k1}`);
75
95
  }
96
+ export async function owsSolanaKeypairFromWalletId(walletId) {
97
+ const ows = await loadOws();
98
+ const wallet = ows.getWallet(walletId);
99
+ findSolanaAccount(wallet);
100
+ const exported = ows.exportWallet(walletId);
101
+ const keys = JSON.parse(exported);
102
+ if (!keys.ed25519) {
103
+ throw new Error(`Wallet "${wallet.name}" has no ed25519 key for Solana signing.`);
104
+ }
105
+ const { Keypair } = await import("@solana/web3.js");
106
+ return keypairFromEd25519Hex(keys.ed25519, Keypair);
107
+ }
108
+ export async function getOwsWalletAddress(walletId, chain = "evm") {
109
+ const ows = await loadOws();
110
+ const wallet = ows.getWallet(walletId);
111
+ return chain === "solana"
112
+ ? findSolanaAccount(wallet).address
113
+ : findEvmAccount(wallet).address;
114
+ }
76
115
  /**
77
116
  * Create a new OWS wallet and return its ID + EVM address.
78
117
  */
79
- export async function createOwsWallet(name) {
118
+ export async function createOwsWallet(name, chain = "evm") {
80
119
  const ows = await loadOws();
81
120
  const wallet = ows.createWallet(name);
82
- const evmAccount = findEvmAccount(wallet);
83
- return { walletId: wallet.id, address: evmAccount.address };
121
+ const account = chain === "solana" ? findSolanaAccount(wallet) : findEvmAccount(wallet);
122
+ return { walletId: wallet.id, address: account.address };
84
123
  }
85
124
  /**
86
125
  * Import an existing EVM private key into OWS.
87
126
  */
88
- export async function importKeyToOws(privateKey, name) {
127
+ export async function importKeyToOws(privateKey, name, chain = "evm") {
89
128
  const ows = await loadOws();
90
129
  const normalizedKey = privateKey.startsWith("0x")
91
130
  ? privateKey.slice(2)
92
131
  : privateKey;
93
- const wallet = ows.importWalletPrivateKey(name, normalizedKey, null, null, "evm");
94
- const evmAccount = findEvmAccount(wallet);
95
- return { walletId: wallet.id, address: evmAccount.address };
132
+ const wallet = ows.importWalletPrivateKey(name, normalizedKey, null, null, chain);
133
+ const account = chain === "solana" ? findSolanaAccount(wallet) : findEvmAccount(wallet);
134
+ return { walletId: wallet.id, address: account.address };
96
135
  }
97
136
  /**
98
137
  * List all OWS wallets that have an EVM account.
99
138
  */
100
139
  export async function listOwsWallets() {
140
+ return listOwsWalletsByChain("evm");
141
+ }
142
+ export async function listOwsWalletsByChain(chain = "evm") {
101
143
  const ows = await loadOws();
102
144
  const wallets = ows.listWallets();
103
145
  const result = [];
104
146
  for (const w of wallets) {
105
- const evm = w.accounts.find((a) => a.chainId.startsWith("eip155") || a.chainId.startsWith("evm"));
106
- if (evm) {
107
- result.push({ id: w.id, name: w.name, address: evm.address });
147
+ const account = chain === "solana"
148
+ ? w.accounts.find((a) => a.chainId.startsWith("solana"))
149
+ : w.accounts.find((a) => a.chainId.startsWith("eip155") || a.chainId.startsWith("evm"));
150
+ if (account) {
151
+ result.push({ id: w.id, name: w.name, address: account.address });
108
152
  }
109
153
  }
110
154
  return result;
@@ -0,0 +1,40 @@
1
+ import type { AgentRecord } from "./types.js";
2
+ export interface CreditPackOffer {
3
+ pack_id: string;
4
+ label: string;
5
+ included_units: number;
6
+ price_usd: string;
7
+ effective_price_per_unit_usd?: string;
8
+ }
9
+ export interface CreditPackRecord {
10
+ id: string;
11
+ status: string;
12
+ unit_type: string;
13
+ included_units: number;
14
+ remaining_units: number;
15
+ price_usd: string;
16
+ purchased_at: string;
17
+ pack?: {
18
+ name?: string | null;
19
+ key?: string | null;
20
+ };
21
+ }
22
+ export interface CreditPackProgramInfo {
23
+ unit_type?: string;
24
+ packs?: Array<{
25
+ key?: string;
26
+ name?: string;
27
+ included_units?: number;
28
+ price_usd?: string;
29
+ }>;
30
+ }
31
+ export interface CreditPackInventory {
32
+ consumer_principal: string | null;
33
+ offers: CreditPackOffer[];
34
+ balances: CreditPackRecord[];
35
+ }
36
+ export declare function getCreditPackProgram(agent: AgentRecord): CreditPackProgramInfo | null;
37
+ export declare function getCreditPackInventory(agentId: string): Promise<CreditPackInventory | null>;
38
+ export declare function getActiveCreditPack(inventory: CreditPackInventory | null): CreditPackRecord | null;
39
+ export declare function formatCreditPackOffer(offer: CreditPackOffer): string;
40
+ export declare function formatCreditPack(pack: CreditPackRecord): string;
@@ -0,0 +1,32 @@
1
+ import { apiGet } from "./api-client.js";
2
+ export function getCreditPackProgram(agent) {
3
+ const payment = (agent.payment ?? {});
4
+ const creditPacks = payment.credit_packs;
5
+ return creditPacks ?? null;
6
+ }
7
+ export async function getCreditPackInventory(agentId) {
8
+ try {
9
+ return await apiGet(`/agents/${agentId}/credit-packs`, { ensureConsumerPrincipal: true });
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ }
15
+ export function getActiveCreditPack(inventory) {
16
+ if (!inventory)
17
+ return null;
18
+ return inventory.balances
19
+ .filter((pack) => pack.status === "active" && pack.remaining_units > 0)
20
+ .sort((a, b) => new Date(a.purchased_at).getTime() - new Date(b.purchased_at).getTime())[0] ?? null;
21
+ }
22
+ export function formatCreditPackOffer(offer) {
23
+ const unitPrice = offer.effective_price_per_unit_usd
24
+ ? ` ($${Number(offer.effective_price_per_unit_usd).toFixed(2)}/unit)`
25
+ : "";
26
+ return `${offer.label} — ${offer.included_units} units for $${offer.price_usd}${unitPrice}`;
27
+ }
28
+ export function formatCreditPack(pack) {
29
+ const label = pack.pack?.name ?? pack.pack?.key ?? "Credit Pack";
30
+ const statusPrefix = pack.status === "active" ? "" : `${pack.status} • `;
31
+ return `${label}: ${statusPrefix}${pack.remaining_units}/${pack.included_units} ${pack.unit_type}s remaining`;
32
+ }
@@ -9,6 +9,7 @@
9
9
  * Users can configure multiple wallets with different chains and select
10
10
  * which to use per-request via `--pay-with <wallet-id|chain|card>`.
11
11
  */
12
+ import type { AgentRecord } from "./types.js";
12
13
  /**
13
14
  * Returns a payment-aware fetch for a specific method, or the best
14
15
  * available method if none is specified.
@@ -21,6 +22,11 @@ export declare function getPaymentFetch(method?: string): Promise<typeof fetch>;
21
22
  * (with default wallet's default chain first) + "card" if configured.
22
23
  */
23
24
  export declare function getConfiguredMethods(): string[];
25
+ /**
26
+ * Normalize a requested payment method into the MCP-visible method identifier.
27
+ * Accepts chain names, wallet IDs, or "card".
28
+ */
29
+ export declare function normalizePaymentMethod(method: string): string | null;
24
30
  /**
25
31
  * Human-friendly display name for a payment method identifier.
26
32
  */
@@ -31,6 +37,8 @@ export declare function paymentMethodDisplayName(method: string): string;
31
37
  * (tempo_usdc, base_usdc, stripe_card).
32
38
  */
33
39
  export declare function getAcceptedPaymentMethods(): string[];
40
+ export declare function toRegistryPaymentMethod(method: string): string | null;
41
+ export declare function getCompatiblePaymentMethods(agent: Pick<AgentRecord, "payment"> | null | undefined, configuredMethods?: string[]): string[];
34
42
  /**
35
43
  * Check whether any payment method is configured.
36
44
  */