agentspend 0.1.1

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.
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerCardCommands(program: Command): void;
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerCardCommands = registerCardCommands;
4
+ const promises_1 = require("node:fs/promises");
5
+ const node_os_1 = require("node:os");
6
+ const node_path_1 = require("node:path");
7
+ const node_child_process_1 = require("node:child_process");
8
+ const node_process_1 = require("node:process");
9
+ const CONFIG_DIR = (0, node_path_1.join)((0, node_os_1.homedir)(), ".agentspend");
10
+ const SETUP_FILE = (0, node_path_1.join)(CONFIG_DIR, "setup.json");
11
+ const CARD_FILE = (0, node_path_1.join)(CONFIG_DIR, "card.json");
12
+ const API_BASE = process.env.AGENTSPEND_API_URL ?? "https://api.agentspend.co";
13
+ async function ensureConfigDir() {
14
+ await (0, promises_1.mkdir)(CONFIG_DIR, { recursive: true });
15
+ }
16
+ function openUrl(url) {
17
+ const cmd = node_process_1.platform === "darwin" ? "open" : node_process_1.platform === "win32" ? "start" : "xdg-open";
18
+ (0, node_child_process_1.exec)(`${cmd} ${JSON.stringify(url)}`);
19
+ }
20
+ async function readSetupId() {
21
+ try {
22
+ const data = JSON.parse(await (0, promises_1.readFile)(SETUP_FILE, "utf-8"));
23
+ if (typeof data.setup_id === "string" && data.setup_id) {
24
+ return data.setup_id;
25
+ }
26
+ }
27
+ catch {
28
+ // file doesn't exist or is invalid
29
+ }
30
+ throw new Error("No setup_id found. Run 'agentspend card setup' first.");
31
+ }
32
+ async function createCard() {
33
+ const response = await fetch(`${API_BASE}/v1/card/create`, {
34
+ method: "POST",
35
+ headers: { "content-type": "application/json" },
36
+ body: JSON.stringify({})
37
+ });
38
+ if (!response.ok) {
39
+ const body = await response.text();
40
+ throw new Error(`Failed to create card (${response.status}): ${body}`);
41
+ }
42
+ return (await response.json());
43
+ }
44
+ async function getSetupStatus(setupId) {
45
+ const response = await fetch(`${API_BASE}/v1/card/setup/${encodeURIComponent(setupId)}`);
46
+ if (!response.ok) {
47
+ const body = await response.text();
48
+ throw new Error(`Failed to get setup status (${response.status}): ${body}`);
49
+ }
50
+ return (await response.json());
51
+ }
52
+ function sleep(ms) {
53
+ return new Promise((resolve) => setTimeout(resolve, ms));
54
+ }
55
+ function registerCardCommands(program) {
56
+ const card = program
57
+ .command("card")
58
+ .description("Manage AgentSpend cards");
59
+ card
60
+ .command("status")
61
+ .description("Check the setup status of a pending card")
62
+ .action(async () => {
63
+ try {
64
+ const setupId = await readSetupId();
65
+ const status = await getSetupStatus(setupId);
66
+ console.log(`Setup ID: ${status.setup_id}`);
67
+ console.log(`Status: ${status.status}`);
68
+ console.log(`Expires: ${status.expires_at}`);
69
+ if (status.card_id) {
70
+ console.log(`Card ID: ${status.card_id}`);
71
+ }
72
+ }
73
+ catch (err) {
74
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
75
+ process.exit(1);
76
+ }
77
+ });
78
+ card
79
+ .command("setup")
80
+ .description("Set up a card and wait until setup is complete")
81
+ .action(async () => {
82
+ try {
83
+ const result = await createCard();
84
+ console.log(`Setup ID: ${result.setup_id}`);
85
+ console.log(`Opening setup URL in browser...`);
86
+ openUrl(result.setup_url);
87
+ await ensureConfigDir();
88
+ await (0, promises_1.writeFile)(SETUP_FILE, JSON.stringify({ setup_id: result.setup_id }, null, 2));
89
+ console.log("Waiting for setup to complete...");
90
+ while (true) {
91
+ await sleep(3000);
92
+ const status = await getSetupStatus(result.setup_id);
93
+ if (status.status === "ready") {
94
+ console.log(`Card is ready!`);
95
+ if (status.card_id) {
96
+ await (0, promises_1.writeFile)(CARD_FILE, JSON.stringify({ card_id: status.card_id }, null, 2));
97
+ console.log(`Card ID saved to ${CARD_FILE}`);
98
+ }
99
+ // Clean up setup file
100
+ await (0, promises_1.unlink)(SETUP_FILE).catch(() => { });
101
+ break;
102
+ }
103
+ if (status.status === "expired" || status.status === "failed") {
104
+ await (0, promises_1.unlink)(SETUP_FILE).catch(() => { });
105
+ throw new Error(`Setup ${status.status}. Please try again.`);
106
+ }
107
+ process.stdout.write(".");
108
+ }
109
+ }
110
+ catch (err) {
111
+ console.error(`\nError: ${err instanceof Error ? err.message : err}`);
112
+ process.exit(1);
113
+ }
114
+ });
115
+ }
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerCryptoWalletCommands(program: Command): void;
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerCryptoWalletCommands = registerCryptoWalletCommands;
4
+ const promises_1 = require("node:fs/promises");
5
+ const node_os_1 = require("node:os");
6
+ const node_path_1 = require("node:path");
7
+ const CONFIG_DIR = (0, node_path_1.join)((0, node_os_1.homedir)(), ".agentspend");
8
+ const CRYPTO_WALLET_FILE = (0, node_path_1.join)(CONFIG_DIR, "crypto-wallet.json");
9
+ async function ensureConfigDir() {
10
+ await (0, promises_1.mkdir)(CONFIG_DIR, { recursive: true });
11
+ }
12
+ async function readCryptoWalletConfig() {
13
+ try {
14
+ const data = JSON.parse(await (0, promises_1.readFile)(CRYPTO_WALLET_FILE, "utf-8"));
15
+ if (typeof data.address === "string" && data.address) {
16
+ return data;
17
+ }
18
+ }
19
+ catch {
20
+ // file doesn't exist or is invalid
21
+ }
22
+ return null;
23
+ }
24
+ function registerCryptoWalletCommands(program) {
25
+ const cryptoWallet = program
26
+ .command("crypto-wallet")
27
+ .description("Manage AgentSpend crypto wallets");
28
+ cryptoWallet
29
+ .command("setup")
30
+ .description("Set up a crypto wallet from a private key")
31
+ .requiredOption("--private-key <key>", "Ethereum private key (0x...)")
32
+ .option("--network <network>", "Chain identifier", "eip155:8453")
33
+ .action(async (opts) => {
34
+ try {
35
+ const privateKey = opts.privateKey.trim();
36
+ if (!privateKey.startsWith("0x") || privateKey.length !== 66) {
37
+ console.error("Error: Private key must be a 0x-prefixed 32-byte hex string (66 characters)");
38
+ process.exit(1);
39
+ }
40
+ // Derive address from private key using viem
41
+ let address;
42
+ try {
43
+ const { privateKeyToAccount } = await import("viem/accounts");
44
+ const account = privateKeyToAccount(privateKey);
45
+ address = account.address;
46
+ }
47
+ catch (err) {
48
+ console.error(`Error: Failed to derive address from private key: ${err instanceof Error ? err.message : err}`);
49
+ process.exit(1);
50
+ }
51
+ await ensureConfigDir();
52
+ const config = {
53
+ address,
54
+ network: opts.network
55
+ };
56
+ // Store the private key (in production, this should be encrypted)
57
+ // For now, store it so @x402/fetch can use it
58
+ const fullConfig = {
59
+ ...config,
60
+ private_key: privateKey
61
+ };
62
+ await (0, promises_1.writeFile)(CRYPTO_WALLET_FILE, JSON.stringify(fullConfig, null, 2));
63
+ console.log(`Crypto wallet configured.`);
64
+ console.log(` Address: ${address}`);
65
+ console.log(` Network: ${opts.network}`);
66
+ console.log(` Saved to: ${CRYPTO_WALLET_FILE}`);
67
+ }
68
+ catch (err) {
69
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
70
+ process.exit(1);
71
+ }
72
+ });
73
+ cryptoWallet
74
+ .command("status")
75
+ .description("Show configured crypto wallet address, network, and USDC balance")
76
+ .action(async () => {
77
+ try {
78
+ const config = await readCryptoWalletConfig();
79
+ if (!config) {
80
+ console.log("No crypto wallet configured.");
81
+ console.log("Run: agentspend crypto-wallet setup --private-key 0x...");
82
+ process.exit(0);
83
+ }
84
+ console.log(`Address: ${config.address}`);
85
+ console.log(`Network: ${config.network}`);
86
+ // Fetch USDC balance on Base
87
+ try {
88
+ const { createPublicClient, http, parseAbi } = await import("viem");
89
+ const { base } = await import("viem/chains");
90
+ const client = createPublicClient({
91
+ chain: base,
92
+ transport: http()
93
+ });
94
+ const usdcAddress = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
95
+ const balance = await client.readContract({
96
+ address: usdcAddress,
97
+ abi: parseAbi(["function balanceOf(address) view returns (uint256)"]),
98
+ functionName: "balanceOf",
99
+ args: [config.address]
100
+ });
101
+ const usdcBalance = Number(balance) / 1e6;
102
+ console.log(`USDC Balance: ${usdcBalance.toFixed(2)} USDC`);
103
+ }
104
+ catch {
105
+ console.log("USDC Balance: (unable to fetch)");
106
+ }
107
+ }
108
+ catch (err) {
109
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
110
+ process.exit(1);
111
+ }
112
+ });
113
+ }
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerWalletCommands(program: Command): void;
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerWalletCommands = registerWalletCommands;
4
+ const promises_1 = require("node:fs/promises");
5
+ const node_os_1 = require("node:os");
6
+ const node_path_1 = require("node:path");
7
+ const CONFIG_DIR = (0, node_path_1.join)((0, node_os_1.homedir)(), ".agentspend");
8
+ const WALLET_FILE = (0, node_path_1.join)(CONFIG_DIR, "wallet.json");
9
+ async function ensureConfigDir() {
10
+ await (0, promises_1.mkdir)(CONFIG_DIR, { recursive: true });
11
+ }
12
+ async function readWalletConfig() {
13
+ try {
14
+ const data = JSON.parse(await (0, promises_1.readFile)(WALLET_FILE, "utf-8"));
15
+ if (typeof data.address === "string" && data.address) {
16
+ return data;
17
+ }
18
+ }
19
+ catch {
20
+ // file doesn't exist or is invalid
21
+ }
22
+ return null;
23
+ }
24
+ function registerWalletCommands(program) {
25
+ const wallet = program
26
+ .command("wallet")
27
+ .description("Manage AgentSpend crypto wallets");
28
+ wallet
29
+ .command("create")
30
+ .description("Generate a new crypto wallet for x402 payments")
31
+ .option("--network <network>", "Chain identifier", "eip155:8453")
32
+ .action(async (opts) => {
33
+ try {
34
+ const existing = await readWalletConfig();
35
+ if (existing) {
36
+ console.log(`Wallet already exists.`);
37
+ console.log(` Address: ${existing.address}`);
38
+ console.log(` Network: ${existing.network}`);
39
+ console.log(` Saved at: ${WALLET_FILE}`);
40
+ process.exit(0);
41
+ }
42
+ const { generatePrivateKey, privateKeyToAccount } = await import("viem/accounts");
43
+ const privateKey = generatePrivateKey();
44
+ const account = privateKeyToAccount(privateKey);
45
+ await ensureConfigDir();
46
+ const config = {
47
+ address: account.address,
48
+ network: opts.network,
49
+ private_key: privateKey,
50
+ };
51
+ await (0, promises_1.writeFile)(WALLET_FILE, JSON.stringify(config, null, 2));
52
+ console.log(`Wallet created. Address: ${account.address} — Fund it with USDC on Base.`);
53
+ }
54
+ catch (err) {
55
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
56
+ process.exit(1);
57
+ }
58
+ });
59
+ wallet
60
+ .command("status")
61
+ .description("Show wallet address, network, and USDC balance")
62
+ .action(async () => {
63
+ try {
64
+ const config = await readWalletConfig();
65
+ if (!config) {
66
+ console.log("No wallet configured.");
67
+ console.log("Run: agentspend wallet create");
68
+ process.exit(0);
69
+ }
70
+ console.log(`Address: ${config.address}`);
71
+ console.log(`Network: ${config.network}`);
72
+ // Fetch USDC balance on Base
73
+ try {
74
+ const { createPublicClient, http, parseAbi } = await import("viem");
75
+ const { base } = await import("viem/chains");
76
+ const client = createPublicClient({
77
+ chain: base,
78
+ transport: http(),
79
+ });
80
+ const usdcAddress = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
81
+ const balance = await client.readContract({
82
+ address: usdcAddress,
83
+ abi: parseAbi(["function balanceOf(address) view returns (uint256)"]),
84
+ functionName: "balanceOf",
85
+ args: [config.address],
86
+ });
87
+ const usdcBalance = Number(balance) / 1e6;
88
+ console.log(`USDC Balance: ${usdcBalance.toFixed(2)} USDC`);
89
+ }
90
+ catch {
91
+ console.log("USDC Balance: (unable to fetch)");
92
+ }
93
+ }
94
+ catch (err) {
95
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
96
+ process.exit(1);
97
+ }
98
+ });
99
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const commander_1 = require("commander");
5
+ const card_js_1 = require("./commands/card.js");
6
+ const wallet_js_1 = require("./commands/wallet.js");
7
+ const program = new commander_1.Command();
8
+ program
9
+ .name("agentspend")
10
+ .description("AgentSpend CLI — manage cards and billing")
11
+ .version("0.1.0");
12
+ (0, card_js_1.registerCardCommands)(program);
13
+ (0, wallet_js_1.registerWalletCommands)(program);
14
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "agentspend",
3
+ "version": "0.1.1",
4
+ "bin": {
5
+ "agentspend": "dist/index.js"
6
+ },
7
+ "dependencies": {
8
+ "commander": "^13.0.0",
9
+ "viem": "^2.0.0"
10
+ },
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "typecheck": "tsc --noEmit"
14
+ }
15
+ }
@@ -0,0 +1,144 @@
1
+ import { Command } from "commander";
2
+ import { readFile, writeFile, mkdir, unlink } from "node:fs/promises";
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { exec } from "node:child_process";
6
+ import { platform } from "node:process";
7
+ type CardSetupStatus = "awaiting_card" | "ready" | "expired" | "failed";
8
+
9
+ interface CardCreateResponse {
10
+ setup_id: string;
11
+ setup_url: string;
12
+ status: CardSetupStatus;
13
+ expires_at: string;
14
+ }
15
+
16
+ interface CardSetupStatusResponse {
17
+ setup_id: string;
18
+ status: CardSetupStatus;
19
+ expires_at: string;
20
+ card_id?: string;
21
+ }
22
+
23
+ const CONFIG_DIR = join(homedir(), ".agentspend");
24
+ const SETUP_FILE = join(CONFIG_DIR, "setup.json");
25
+ const CARD_FILE = join(CONFIG_DIR, "card.json");
26
+ const API_BASE = process.env.AGENTSPEND_API_URL ?? "https://api.agentspend.co";
27
+
28
+ async function ensureConfigDir(): Promise<void> {
29
+ await mkdir(CONFIG_DIR, { recursive: true });
30
+ }
31
+
32
+ function openUrl(url: string): void {
33
+ const cmd = platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open";
34
+ exec(`${cmd} ${JSON.stringify(url)}`);
35
+ }
36
+
37
+ async function readSetupId(): Promise<string> {
38
+ try {
39
+ const data = JSON.parse(await readFile(SETUP_FILE, "utf-8"));
40
+ if (typeof data.setup_id === "string" && data.setup_id) {
41
+ return data.setup_id;
42
+ }
43
+ } catch {
44
+ // file doesn't exist or is invalid
45
+ }
46
+ throw new Error("No setup_id found. Run 'agentspend card setup' first.");
47
+ }
48
+
49
+ async function createCard(): Promise<CardCreateResponse> {
50
+ const response = await fetch(`${API_BASE}/v1/card/create`, {
51
+ method: "POST",
52
+ headers: { "content-type": "application/json" },
53
+ body: JSON.stringify({})
54
+ });
55
+
56
+ if (!response.ok) {
57
+ const body = await response.text();
58
+ throw new Error(`Failed to create card (${response.status}): ${body}`);
59
+ }
60
+
61
+ return (await response.json()) as CardCreateResponse;
62
+ }
63
+
64
+ async function getSetupStatus(setupId: string): Promise<CardSetupStatusResponse> {
65
+ const response = await fetch(`${API_BASE}/v1/card/setup/${encodeURIComponent(setupId)}`);
66
+
67
+ if (!response.ok) {
68
+ const body = await response.text();
69
+ throw new Error(`Failed to get setup status (${response.status}): ${body}`);
70
+ }
71
+
72
+ return (await response.json()) as CardSetupStatusResponse;
73
+ }
74
+
75
+ function sleep(ms: number): Promise<void> {
76
+ return new Promise((resolve) => setTimeout(resolve, ms));
77
+ }
78
+
79
+ export function registerCardCommands(program: Command): void {
80
+ const card = program
81
+ .command("card")
82
+ .description("Manage AgentSpend cards");
83
+
84
+ card
85
+ .command("status")
86
+ .description("Check the setup status of a pending card")
87
+ .action(async () => {
88
+ try {
89
+ const setupId = await readSetupId();
90
+ const status = await getSetupStatus(setupId);
91
+ console.log(`Setup ID: ${status.setup_id}`);
92
+ console.log(`Status: ${status.status}`);
93
+ console.log(`Expires: ${status.expires_at}`);
94
+ if (status.card_id) {
95
+ console.log(`Card ID: ${status.card_id}`);
96
+ }
97
+ } catch (err: unknown) {
98
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
99
+ process.exit(1);
100
+ }
101
+ });
102
+
103
+ card
104
+ .command("setup")
105
+ .description("Set up a card and wait until setup is complete")
106
+ .action(async () => {
107
+ try {
108
+ const result = await createCard();
109
+ console.log(`Setup ID: ${result.setup_id}`);
110
+ console.log(`Opening setup URL in browser...`);
111
+ openUrl(result.setup_url);
112
+
113
+ await ensureConfigDir();
114
+ await writeFile(SETUP_FILE, JSON.stringify({ setup_id: result.setup_id }, null, 2));
115
+
116
+ console.log("Waiting for setup to complete...");
117
+ while (true) {
118
+ await sleep(3000);
119
+ const status = await getSetupStatus(result.setup_id);
120
+
121
+ if (status.status === "ready") {
122
+ console.log(`Card is ready!`);
123
+ if (status.card_id) {
124
+ await writeFile(CARD_FILE, JSON.stringify({ card_id: status.card_id }, null, 2));
125
+ console.log(`Card ID saved to ${CARD_FILE}`);
126
+ }
127
+ // Clean up setup file
128
+ await unlink(SETUP_FILE).catch(() => {});
129
+ break;
130
+ }
131
+
132
+ if (status.status === "expired" || status.status === "failed") {
133
+ await unlink(SETUP_FILE).catch(() => {});
134
+ throw new Error(`Setup ${status.status}. Please try again.`);
135
+ }
136
+
137
+ process.stdout.write(".");
138
+ }
139
+ } catch (err: unknown) {
140
+ console.error(`\nError: ${err instanceof Error ? err.message : err}`);
141
+ process.exit(1);
142
+ }
143
+ });
144
+ }
@@ -0,0 +1,115 @@
1
+ import { Command } from "commander";
2
+ import { readFile, writeFile, mkdir } from "node:fs/promises";
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
5
+
6
+ const CONFIG_DIR = join(homedir(), ".agentspend");
7
+ const WALLET_FILE = join(CONFIG_DIR, "wallet.json");
8
+
9
+ async function ensureConfigDir(): Promise<void> {
10
+ await mkdir(CONFIG_DIR, { recursive: true });
11
+ }
12
+
13
+ interface WalletConfig {
14
+ address: string;
15
+ network: string;
16
+ private_key: string;
17
+ }
18
+
19
+ async function readWalletConfig(): Promise<WalletConfig | null> {
20
+ try {
21
+ const data = JSON.parse(await readFile(WALLET_FILE, "utf-8"));
22
+ if (typeof data.address === "string" && data.address) {
23
+ return data as WalletConfig;
24
+ }
25
+ } catch {
26
+ // file doesn't exist or is invalid
27
+ }
28
+ return null;
29
+ }
30
+
31
+ export function registerWalletCommands(program: Command): void {
32
+ const wallet = program
33
+ .command("wallet")
34
+ .description("Manage AgentSpend crypto wallets");
35
+
36
+ wallet
37
+ .command("create")
38
+ .description("Generate a new crypto wallet for x402 payments")
39
+ .option("--network <network>", "Chain identifier", "eip155:8453")
40
+ .action(async (opts: { network: string }) => {
41
+ try {
42
+ const existing = await readWalletConfig();
43
+ if (existing) {
44
+ console.log(`Wallet already exists.`);
45
+ console.log(` Address: ${existing.address}`);
46
+ console.log(` Network: ${existing.network}`);
47
+ console.log(` Saved at: ${WALLET_FILE}`);
48
+ process.exit(0);
49
+ }
50
+
51
+ const { generatePrivateKey, privateKeyToAccount } = await import("viem/accounts");
52
+ const privateKey = generatePrivateKey();
53
+ const account = privateKeyToAccount(privateKey);
54
+
55
+ await ensureConfigDir();
56
+
57
+ const config: WalletConfig = {
58
+ address: account.address,
59
+ network: opts.network,
60
+ private_key: privateKey,
61
+ };
62
+
63
+ await writeFile(WALLET_FILE, JSON.stringify(config, null, 2));
64
+
65
+ console.log(`Wallet created. Address: ${account.address} — Fund it with USDC on Base.`);
66
+ } catch (err: unknown) {
67
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
68
+ process.exit(1);
69
+ }
70
+ });
71
+
72
+ wallet
73
+ .command("status")
74
+ .description("Show wallet address, network, and USDC balance")
75
+ .action(async () => {
76
+ try {
77
+ const config = await readWalletConfig();
78
+ if (!config) {
79
+ console.log("No wallet configured.");
80
+ console.log("Run: agentspend wallet create");
81
+ process.exit(0);
82
+ }
83
+
84
+ console.log(`Address: ${config.address}`);
85
+ console.log(`Network: ${config.network}`);
86
+
87
+ // Fetch USDC balance on Base
88
+ try {
89
+ const { createPublicClient, http, parseAbi } = await import("viem");
90
+ const { base } = await import("viem/chains");
91
+
92
+ const client = createPublicClient({
93
+ chain: base,
94
+ transport: http(),
95
+ });
96
+
97
+ const usdcAddress = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" as `0x${string}`;
98
+ const balance = await client.readContract({
99
+ address: usdcAddress,
100
+ abi: parseAbi(["function balanceOf(address) view returns (uint256)"]),
101
+ functionName: "balanceOf",
102
+ args: [config.address as `0x${string}`],
103
+ });
104
+
105
+ const usdcBalance = Number(balance) / 1e6;
106
+ console.log(`USDC Balance: ${usdcBalance.toFixed(2)} USDC`);
107
+ } catch {
108
+ console.log("USDC Balance: (unable to fetch)");
109
+ }
110
+ } catch (err: unknown) {
111
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
112
+ process.exit(1);
113
+ }
114
+ });
115
+ }
package/src/index.ts ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from "commander";
4
+ import { registerCardCommands } from "./commands/card.js";
5
+ import { registerWalletCommands } from "./commands/wallet.js";
6
+
7
+ const program = new Command();
8
+
9
+ program
10
+ .name("agentspend")
11
+ .description("AgentSpend CLI — manage cards and billing")
12
+ .version("0.1.0");
13
+
14
+ registerCardCommands(program);
15
+ registerWalletCommands(program);
16
+
17
+ program.parse();
package/tsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "outDir": "dist"
6
+ },
7
+ "include": ["src"]
8
+ }