@clawcard/cli 3.2.1 → 3.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawcard/cli",
3
- "version": "3.2.1",
3
+ "version": "3.2.4",
4
4
  "description": "The ClawCard CLI — manage your agent keys, billing, and setup from the terminal",
5
5
  "bin": {
6
6
  "clawcard": "./bin/clawcard.mjs"
package/skill/SKILL.md CHANGED
@@ -98,11 +98,15 @@ Close card:
98
98
  clawcard agent cards close <card-id> --json
99
99
  ```
100
100
 
101
- ## Stablecoin Wallet (USDC on Base)
101
+ ## Stablecoin Wallet (USDC + pathUSD on Base)
102
102
 
103
- Your agent can have a USDC wallet for crypto payments, agent-to-agent transfers, and x402 API access.
103
+ Your agent has a wallet on Base with three balances:
104
104
 
105
- **Use wallet for:** x402 APIs (HTTP 402 responses), crypto transfers, micropayments
105
+ - **ETH** gas fees (needed for on-chain transactions)
106
+ - **USDC** — x402 protocol payments and direct transfers
107
+ - **pathUSD** — MPP (Machine Payments Protocol) payments via Tempo/Stripe
108
+
109
+ **Use wallet for:** x402 APIs (HTTP 402 responses), MPP services, crypto transfers, micropayments
106
110
  **Use cards for:** traditional merchant checkouts, websites with payment forms
107
111
 
108
112
  ### Setup
@@ -116,7 +120,7 @@ If you get `"No wallet found"`, create one via the API or run `clawcard agent wa
116
120
 
117
121
  ### Commands
118
122
 
119
- Check balance (shows USDC + FIAT spending power):
123
+ Check balance (shows ETH, USDC, and pathUSD balances):
120
124
  ```
121
125
  clawcard agent wallet balance --json
122
126
  ```
@@ -131,21 +135,42 @@ Pay a URL via x402 (default — when a service returns HTTP 402):
131
135
  clawcard agent wallet send --url https://api.example.com/data --json
132
136
  ```
133
137
 
134
- Pay a URL via MPP (Machine Payments Protocol — Stripe/Tempo):
138
+ Pay a URL via MPP (Machine Payments Protocol — Stripe/Tempo, uses pathUSD):
135
139
  ```
136
140
  clawcard agent wallet send --url https://api.example.com/data --protocol mpp --json
137
141
  ```
138
142
 
143
+ **Explorer links:** Payment responses include explorer URLs. x402 transactions link to Basescan (`basescan.org/tx/...`), MPP and bridge transactions link to Tempo Explorer (`explore.tempo.xyz/receipt/...`).
144
+
139
145
  View transaction history:
140
146
  ```
141
147
  clawcard agent wallet transactions --json
142
148
  ```
143
149
 
144
- Fund your wallet (opens Coinbase — buy USDC with card, zero fees, sent directly to wallet):
150
+ ### Fund Wizard (3 options)
151
+
152
+ The fund command is a wizard with three funding options:
153
+
154
+ 1. **Gas fees (ETH)** — opens Coinbase Onramp to buy ETH (needed for on-chain transactions)
155
+ 2. **x402 services (USDC)** — opens Coinbase Onramp to buy USDC (for x402 protocol payments)
156
+ 3. **MPP services (pathUSD)** — bridges USDC from your existing balance to pathUSD on Tempo (for MPP payments)
157
+
158
+ Fund your wallet interactively (runs the wizard):
159
+ ```
160
+ clawcard agent wallet fund
161
+ ```
162
+
163
+ Fund via JSON (opens Coinbase Onramp for USDC/ETH):
145
164
  ```
146
165
  clawcard agent wallet fund --amount 10.00 --json
147
166
  ```
148
167
 
168
+ ### Bridge USDC to pathUSD
169
+
170
+ To pay for MPP services, you need pathUSD. The fund wizard's "MPP services" option converts USDC from your wallet balance to pathUSD on Tempo. This is a bridge operation (USDC on Base -> pathUSD on Tempo).
171
+
172
+ The bridge response includes both a Basescan link (Base transaction) and a Tempo Explorer link (Tempo receipt).
173
+
149
174
  Or send USDC directly to your wallet address on Base. Check your address with `clawcard agent wallet --json`.
150
175
 
151
176
  ## Discover Services
package/src/agent-api.js CHANGED
@@ -177,3 +177,13 @@ export const registerOnChainIdentity = (agentId, data = {}) =>
177
177
  // A2A Agent Card
178
178
  export const getAgentCard = (agentId) =>
179
179
  agentRequest(`/api/agents/${agentId}/agent-card`);
180
+
181
+ // Card access
182
+ export const getCardAccess = () =>
183
+ agentRequest("/api/cards-access");
184
+
185
+ export const requestCardAccess = (data) =>
186
+ agentRequest("/api/cards-access", {
187
+ method: "POST",
188
+ body: JSON.stringify(data),
189
+ });
@@ -23,6 +23,7 @@ import {
23
23
  walletSend,
24
24
  walletTransactions as walletTransactionsApi,
25
25
  discoverServices,
26
+ requestCardAccess,
26
27
  getOnChainIdentity,
27
28
  registerOnChainIdentity,
28
29
  getAgentCard,
@@ -183,13 +184,92 @@ export async function agentCardsCmd(options) {
183
184
  console.log();
184
185
  }
185
186
 
187
+ export async function agentCardsRequestCmd(options) {
188
+ if (options.json) {
189
+ try {
190
+ const result = await requestCardAccess({});
191
+ return output(result, true);
192
+ } catch (err) {
193
+ return output({ error: err.message }, true);
194
+ }
195
+ }
196
+
197
+ const prompts = await import("@clack/prompts");
198
+
199
+ console.log();
200
+ console.log(` ${orange.bold("Request Virtual Card Access")}`);
201
+ console.log();
202
+ console.log(chalk.dim(" Virtual cards let your agent make purchases on traditional websites."));
203
+ console.log(chalk.dim(" We review requests to ensure compliance. Usually approved within 24 hours."));
204
+ console.log();
205
+
206
+ const country = await prompts.text({
207
+ message: "What country are you based in?",
208
+ placeholder: "United States",
209
+ validate: (v) => { if (!v?.trim()) return "Required"; },
210
+ });
211
+ if (prompts.isCancel(country)) return;
212
+
213
+ const useCase = await prompts.text({
214
+ message: "What will your agent use cards for?",
215
+ placeholder: "Buying domains, hosting, SaaS subscriptions",
216
+ validate: (v) => { if (!v?.trim()) return "Required"; },
217
+ });
218
+ if (prompts.isCancel(useCase)) return;
219
+
220
+ const company = await prompts.text({
221
+ message: "Company or project name (optional)",
222
+ placeholder: "My AI Startup",
223
+ });
224
+ if (prompts.isCancel(company)) return;
225
+
226
+ const s = prompts.spinner();
227
+ s.start("Submitting request...");
228
+
229
+ try {
230
+ const result = await requestCardAccess({
231
+ country,
232
+ useCase,
233
+ company: company || "",
234
+ });
235
+
236
+ if (result.alreadyApproved) {
237
+ s.stop(chalk.green("You're already approved! Create cards with: clawcard agent cards create"));
238
+ } else {
239
+ s.stop(chalk.green("Request submitted!"));
240
+ console.log();
241
+ console.log(` ${result.message}`);
242
+ console.log(chalk.dim(" Questions? team@clawcard.dev"));
243
+ }
244
+ } catch (err) {
245
+ s.stop("Failed");
246
+ console.log(` Error: ${err.message}`);
247
+ }
248
+ console.log();
249
+ }
250
+
186
251
  export async function agentCardsCreateCmd(options) {
187
252
  const agentId = await getAgentId();
188
- const result = await createCard(agentId, {
189
- amountCents: parseInt(options.amount),
190
- type: options.type,
191
- memo: options.memo || "Agent card",
192
- });
253
+ let result;
254
+ try {
255
+ result = await createCard(agentId, {
256
+ amountCents: parseInt(options.amount),
257
+ type: options.type,
258
+ memo: options.memo || "Agent card",
259
+ });
260
+ } catch (err) {
261
+ if (err.message?.includes("approval") || err.message?.includes("needsApproval")) {
262
+ if (options.json) return output({ error: "Card access not approved. Run: clawcard agent cards request", needsApproval: true }, true);
263
+ console.log();
264
+ console.log(` ${orange("Virtual cards require approval.")}`);
265
+ console.log(` Run: ${chalk.bold("clawcard agent cards request")}`);
266
+ console.log();
267
+ return;
268
+ }
269
+ if (options.json) return output({ error: err.message }, true);
270
+ console.log(` Error: ${err.message}`);
271
+ return;
272
+ }
193
273
  if (options.json) return output(result, true);
194
274
 
195
275
  console.log();
package/src/index.js CHANGED
@@ -169,6 +169,14 @@ agentCards
169
169
  const { agentCardsCmd } = await import("./commands/agent.js");
170
170
  await agentCardsCmd(options);
171
171
  });
172
+ agentCards
173
+ .command("request")
174
+ .description("Request access to virtual cards")
175
+ .option("--json", "Output as JSON")
176
+ .action(async (options) => {
177
+ const { agentCardsRequestCmd } = await import("./commands/agent.js");
178
+ await agentCardsRequestCmd(options);
179
+ });
172
180
  agentCards
173
181
  .command("create")
174
182
  .requiredOption("--amount <cents>", "Spend limit in cents")
@@ -489,49 +497,30 @@ if (process.argv.length <= 2) {
489
497
  ];
490
498
  } else {
491
499
  // Check user state to show contextual nudges
492
- let hasBalance = true;
493
500
  let hasAgent = true;
494
501
 
495
502
  try {
496
- const { getBalance, listAgents } = await import("./api.js");
497
- const [balance, agents] = await Promise.all([
498
- getBalance().catch(() => ({ amountCents: 0 })),
499
- listAgents().catch(() => []),
500
- ]);
501
- hasBalance = balance.amountCents >= 500;
503
+ const { listAgents } = await import("./api.js");
504
+ const agents = await listAgents().catch(() => []);
502
505
  hasAgent = agents.some((a) => a.status === "active");
503
506
  } catch {
504
507
  // couldn't check — show full menu
505
508
  }
506
509
 
507
- if (!hasBalance) {
508
- p.log.warn(
509
- `Account balance is under $5. Run ${orange("clawcard billing topup")} to add funds.`
510
- );
511
- }
512
-
513
- if (!hasAgent && !hasBalance) {
510
+ if (!hasAgent) {
514
511
  p.log.info(
515
- chalk.dim("You need at least $5 balance before creating an agent.")
516
- );
517
- } else if (!hasAgent) {
518
- p.log.warn(
519
- `You have balance but no agent yet. Run ${orange("clawcard keys create")} to create one.`
512
+ `No agent yet. Run ${orange("clawcard keys create")} to create one.`
520
513
  );
521
514
  }
522
515
 
523
516
  options = [
524
517
  ...(hasAgent
525
518
  ? [
526
- { value: "agent", label: "View agent details", hint: "phone, email, budget" },
527
- { value: "agent-fund", label: "Fund my agent", hint: "allocate budget from your balance" },
519
+ { value: "agent", label: "View agent details", hint: "phone, email, wallet, budget" },
528
520
  { value: "setup", label: "Configure", hint: "install skill for your agent" },
529
521
  ]
530
- : hasBalance
531
- ? [{ value: "keys-create", label: "Create agent", hint: "you have balance create your agent now" }]
532
- : []),
533
- { value: "topup", label: "Top up my account", hint: "add balance (10% fee)" },
534
- { value: "referral", label: "Referral", hint: "share & earn $5" },
522
+ : [{ value: "keys-create", label: "Create agent", hint: "create your first agent" }]),
523
+ { value: "topup", label: "Top up account", hint: "add balance for virtual cards (10% fee)" },
535
524
  { value: "settings", label: "Settings", hint: "billing address & preferences" },
536
525
  { value: "whoami", label: "Who am I?", hint: "show current account" },
537
526
  { value: "dashboard", label: "Open dashboard", hint: "open in browser" },
@@ -555,7 +544,7 @@ if (process.argv.length <= 2) {
555
544
  signup: () => import("./commands/signup.js").then((m) => m.signupCommand()),
556
545
  logout: () => import("./commands/logout.js").then((m) => m.logoutCommand()),
557
546
  whoami: () => import("./commands/whoami.js").then((m) => m.whoamiCommand()),
558
- agent: () => import("./commands/keys.js").then((m) => m.agentStatusCommand()),
547
+ agent: () => import("./commands/agent.js").then((m) => m.agentInfoCmd({})),
559
548
  "agent-fund": () => import("./commands/keys.js").then((m) => m.agentFundCommand()),
560
549
  "keys-create": () => import("./commands/keys.js").then((m) => m.keysCreateCommand()),
561
550
  "topup": () => import("./commands/billing.js").then((m) => m.billingTopupCommand()),