agentspend 0.1.5 → 0.1.6

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.
@@ -93,7 +93,10 @@ function registerCardCommands(program) {
93
93
  if (status.status === "ready") {
94
94
  console.log(`Card is ready!`);
95
95
  if (status.card_id) {
96
- await (0, promises_1.writeFile)(CARD_FILE, JSON.stringify({ card_id: status.card_id }, null, 2));
96
+ await (0, promises_1.writeFile)(CARD_FILE, JSON.stringify({
97
+ card_id: status.card_id,
98
+ card_secret: status.card_secret,
99
+ }, null, 2));
97
100
  console.log(`Card ID saved to ${CARD_FILE}`);
98
101
  }
99
102
  // Clean up setup file
@@ -7,10 +7,11 @@ const node_path_1 = require("node:path");
7
7
  const CONFIG_DIR = (0, node_path_1.join)((0, node_os_1.homedir)(), ".agentspend");
8
8
  const CARD_FILE = (0, node_path_1.join)(CONFIG_DIR, "card.json");
9
9
  const WALLET_FILE = (0, node_path_1.join)(CONFIG_DIR, "wallet.json");
10
+ const API_BASE = process.env.AGENTSPEND_API_URL ?? "https://api.agentspend.co";
10
11
  async function readCardConfig() {
11
12
  try {
12
13
  const data = JSON.parse(await (0, promises_1.readFile)(CARD_FILE, "utf-8"));
13
- if (typeof data.card_id === "string" && data.card_id) {
14
+ if (typeof data.card_id === "string" && data.card_id && typeof data.card_secret === "string" && data.card_secret) {
14
15
  return data;
15
16
  }
16
17
  }
@@ -42,31 +43,73 @@ function parseHeaders(headerArgs) {
42
43
  }
43
44
  return headers;
44
45
  }
45
- async function payWithCard(url, cardId, body, extraHeaders) {
46
+ async function payWithCard(url, cardConfig, body, extraHeaders) {
46
47
  const headers = {
47
48
  ...extraHeaders,
48
- "x-card-id": cardId,
49
+ "x-card-id": cardConfig.card_id,
49
50
  };
50
51
  if (body) {
51
52
  headers["content-type"] = "application/json";
52
53
  }
54
+ // Try with x-card-id
53
55
  const res = await fetch(url, {
54
56
  method: "POST",
55
57
  headers,
56
58
  body: body ?? undefined,
57
59
  });
58
- const data = await res.text();
59
- if (!res.ok) {
60
- console.error(`Request failed (${res.status}): ${data}`);
61
- process.exit(1);
62
- }
63
- console.log("Payment successful (card)");
64
- try {
65
- console.log(JSON.stringify(JSON.parse(data), null, 2));
60
+ // Success
61
+ if (res.ok) {
62
+ console.log("Payment successful (card)");
63
+ const data = await res.text();
64
+ try {
65
+ console.log(JSON.stringify(JSON.parse(data), null, 2));
66
+ }
67
+ catch {
68
+ console.log(data);
69
+ }
70
+ return;
66
71
  }
67
- catch {
68
- console.log(data);
72
+ // 402 with agentspend.service_id — need to bind
73
+ if (res.status === 402) {
74
+ const errorBody = await res.json().catch(() => ({}));
75
+ const agentspend = errorBody?.agentspend;
76
+ const serviceId = agentspend?.service_id;
77
+ if (serviceId) {
78
+ console.log(`Binding to service ${serviceId}...`);
79
+ const bindRes = await fetch(`${API_BASE}/v1/card/${encodeURIComponent(cardConfig.card_id)}/bind`, {
80
+ method: "POST",
81
+ headers: { "content-type": "application/json" },
82
+ body: JSON.stringify({
83
+ card_secret: cardConfig.card_secret,
84
+ service_id: serviceId,
85
+ }),
86
+ });
87
+ if (!bindRes.ok) {
88
+ const bindError = await bindRes.text();
89
+ console.error(`Failed to bind (${bindRes.status}): ${bindError}`);
90
+ process.exit(1);
91
+ }
92
+ console.log("Bound. Retrying payment...");
93
+ // Retry with x-card-id
94
+ const retryRes = await fetch(url, { method: "POST", headers, body: body ?? undefined });
95
+ if (!retryRes.ok) {
96
+ console.error(`Retry failed (${retryRes.status}): ${await retryRes.text()}`);
97
+ process.exit(1);
98
+ }
99
+ console.log("Payment successful (card)");
100
+ const data = await retryRes.text();
101
+ try {
102
+ console.log(JSON.stringify(JSON.parse(data), null, 2));
103
+ }
104
+ catch {
105
+ console.log(data);
106
+ }
107
+ return;
108
+ }
69
109
  }
110
+ // Other error
111
+ console.error(`Request failed (${res.status}): ${await res.text().catch(() => "")}`);
112
+ process.exit(1);
70
113
  }
71
114
  async function payWithCrypto(url, walletConfig, body, extraHeaders) {
72
115
  const headers = { ...extraHeaders };
@@ -148,7 +191,7 @@ function registerPayCommand(program) {
148
191
  console.error("No card configured. Run: agentspend card setup");
149
192
  process.exit(1);
150
193
  }
151
- await payWithCard(url, card.card_id, opts.body, extraHeaders);
194
+ await payWithCard(url, card, opts.body, extraHeaders);
152
195
  return;
153
196
  }
154
197
  if (opts.method === "crypto") {
@@ -163,7 +206,7 @@ function registerPayCommand(program) {
163
206
  // Auto-detect: try card first, then crypto
164
207
  const card = await readCardConfig();
165
208
  if (card) {
166
- await payWithCard(url, card.card_id, opts.body, extraHeaders);
209
+ await payWithCard(url, card, opts.body, extraHeaders);
167
210
  return;
168
211
  }
169
212
  const wallet = await readWalletConfig();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentspend",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "CLI for AgentSpend — manage cards and crypto wallets for AI agent payments",
5
5
  "repository": {
6
6
  "type": "git",
@@ -18,6 +18,7 @@ interface CardSetupStatusResponse {
18
18
  status: CardSetupStatus;
19
19
  expires_at: string;
20
20
  card_id?: string;
21
+ card_secret?: string;
21
22
  }
22
23
 
23
24
  const CONFIG_DIR = join(homedir(), ".agentspend");
@@ -121,7 +122,10 @@ export function registerCardCommands(program: Command): void {
121
122
  if (status.status === "ready") {
122
123
  console.log(`Card is ready!`);
123
124
  if (status.card_id) {
124
- await writeFile(CARD_FILE, JSON.stringify({ card_id: status.card_id }, null, 2));
125
+ await writeFile(CARD_FILE, JSON.stringify({
126
+ card_id: status.card_id,
127
+ card_secret: status.card_secret,
128
+ }, null, 2));
125
129
  console.log(`Card ID saved to ${CARD_FILE}`);
126
130
  }
127
131
  // Clean up setup file
@@ -6,9 +6,11 @@ import { join } from "node:path";
6
6
  const CONFIG_DIR = join(homedir(), ".agentspend");
7
7
  const CARD_FILE = join(CONFIG_DIR, "card.json");
8
8
  const WALLET_FILE = join(CONFIG_DIR, "wallet.json");
9
+ const API_BASE = process.env.AGENTSPEND_API_URL ?? "https://api.agentspend.co";
9
10
 
10
11
  interface CardConfig {
11
12
  card_id: string;
13
+ card_secret: string;
12
14
  }
13
15
 
14
16
  interface WalletConfig {
@@ -20,7 +22,7 @@ interface WalletConfig {
20
22
  async function readCardConfig(): Promise<CardConfig | null> {
21
23
  try {
22
24
  const data = JSON.parse(await readFile(CARD_FILE, "utf-8"));
23
- if (typeof data.card_id === "string" && data.card_id) {
25
+ if (typeof data.card_id === "string" && data.card_id && typeof data.card_secret === "string" && data.card_secret) {
24
26
  return data as CardConfig;
25
27
  }
26
28
  } catch {
@@ -55,36 +57,80 @@ function parseHeaders(headerArgs: string[]): Record<string, string> {
55
57
 
56
58
  async function payWithCard(
57
59
  url: string,
58
- cardId: string,
60
+ cardConfig: CardConfig,
59
61
  body: string | undefined,
60
62
  extraHeaders: Record<string, string>
61
63
  ): Promise<void> {
62
64
  const headers: Record<string, string> = {
63
65
  ...extraHeaders,
64
- "x-card-id": cardId,
66
+ "x-card-id": cardConfig.card_id,
65
67
  };
66
68
  if (body) {
67
69
  headers["content-type"] = "application/json";
68
70
  }
69
71
 
72
+ // Try with x-card-id
70
73
  const res = await fetch(url, {
71
74
  method: "POST",
72
75
  headers,
73
76
  body: body ?? undefined,
74
77
  });
75
78
 
76
- const data = await res.text();
77
- if (!res.ok) {
78
- console.error(`Request failed (${res.status}): ${data}`);
79
- process.exit(1);
79
+ // Success
80
+ if (res.ok) {
81
+ console.log("Payment successful (card)");
82
+ const data = await res.text();
83
+ try { console.log(JSON.stringify(JSON.parse(data), null, 2)); }
84
+ catch { console.log(data); }
85
+ return;
80
86
  }
81
87
 
82
- console.log("Payment successful (card)");
83
- try {
84
- console.log(JSON.stringify(JSON.parse(data), null, 2));
85
- } catch {
86
- console.log(data);
88
+ // 402 with agentspend.service_id need to bind
89
+ if (res.status === 402) {
90
+ const errorBody = await res.json().catch(() => ({})) as Record<string, unknown>;
91
+ const agentspend = errorBody?.agentspend as Record<string, unknown> | undefined;
92
+ const serviceId = agentspend?.service_id as string | undefined;
93
+
94
+ if (serviceId) {
95
+ console.log(`Binding to service ${serviceId}...`);
96
+ const bindRes = await fetch(
97
+ `${API_BASE}/v1/card/${encodeURIComponent(cardConfig.card_id)}/bind`,
98
+ {
99
+ method: "POST",
100
+ headers: { "content-type": "application/json" },
101
+ body: JSON.stringify({
102
+ card_secret: cardConfig.card_secret,
103
+ service_id: serviceId,
104
+ }),
105
+ }
106
+ );
107
+
108
+ if (!bindRes.ok) {
109
+ const bindError = await bindRes.text();
110
+ console.error(`Failed to bind (${bindRes.status}): ${bindError}`);
111
+ process.exit(1);
112
+ }
113
+
114
+ console.log("Bound. Retrying payment...");
115
+
116
+ // Retry with x-card-id
117
+ const retryRes = await fetch(url, { method: "POST", headers, body: body ?? undefined });
118
+ if (!retryRes.ok) {
119
+ console.error(`Retry failed (${retryRes.status}): ${await retryRes.text()}`);
120
+ process.exit(1);
121
+ }
122
+
123
+ console.log("Payment successful (card)");
124
+ const data = await retryRes.text();
125
+ try { console.log(JSON.stringify(JSON.parse(data), null, 2)); }
126
+ catch { console.log(data); }
127
+ return;
128
+ }
87
129
  }
130
+
131
+ // Other error
132
+ console.error(`Request failed (${res.status}): ${await res.text().catch(() => "")}`);
133
+ process.exit(1);
88
134
  }
89
135
 
90
136
  async function payWithCrypto(
@@ -185,7 +231,7 @@ export function registerPayCommand(program: Command): void {
185
231
  console.error("No card configured. Run: agentspend card setup");
186
232
  process.exit(1);
187
233
  }
188
- await payWithCard(url, card.card_id, opts.body, extraHeaders);
234
+ await payWithCard(url, card, opts.body, extraHeaders);
189
235
  return;
190
236
  }
191
237
 
@@ -202,7 +248,7 @@ export function registerPayCommand(program: Command): void {
202
248
  // Auto-detect: try card first, then crypto
203
249
  const card = await readCardConfig();
204
250
  if (card) {
205
- await payWithCard(url, card.card_id, opts.body, extraHeaders);
251
+ await payWithCard(url, card, opts.body, extraHeaders);
206
252
  return;
207
253
  }
208
254