agentic-x402 0.1.2 → 0.2.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.
package/README.md CHANGED
@@ -27,20 +27,26 @@ x402 --version
27
27
 
28
28
  ### Configure
29
29
 
30
- Set your wallet private key (required):
30
+ Run the interactive setup to create a new wallet:
31
31
 
32
32
  ```bash
33
- export EVM_PRIVATE_KEY=0x...your_private_key...
33
+ x402 setup
34
34
  ```
35
35
 
36
- Or create a persistent config file:
36
+ This will:
37
+ 1. Generate a new wallet (recommended) or accept an existing key
38
+ 2. Save configuration to `~/.x402/.env`
39
+ 3. Display your wallet address for funding
40
+ 4. Show your private key for backup
41
+
42
+ **Back up your private key immediately!** See [Backup](#backup-your-private-key) below.
43
+
44
+ #### Manual Configuration
45
+
46
+ Alternatively, set the environment variable directly:
37
47
 
38
48
  ```bash
39
- mkdir -p ~/.x402
40
- cat > ~/.x402/.env << 'EOF'
41
- EVM_PRIVATE_KEY=0x...your_private_key...
42
- X402_NETWORK=mainnet
43
- EOF
49
+ export EVM_PRIVATE_KEY=0x...your_private_key...
44
50
  ```
45
51
 
46
52
  ### Development / Local Install
@@ -56,24 +62,38 @@ cp config/example.env .env
56
62
  ## Quick Start
57
63
 
58
64
  ```bash
59
- # 1. Configure your wallet
60
- export EVM_PRIVATE_KEY=0x...your_private_key...
65
+ # 1. Create a wallet
66
+ x402 setup
61
67
 
62
- # 2. Check balance
68
+ # 2. Fund your wallet with USDC on Base (send to the address shown)
69
+
70
+ # 3. Check balance
63
71
  x402 balance
64
72
 
65
- # 3. Pay for a resource
73
+ # 4. Pay for a resource
66
74
  x402 pay https://api.example.com/paid-endpoint
67
75
 
68
- # 4. Fetch with auto-payment
76
+ # 5. Fetch with auto-payment
69
77
  x402 fetch https://api.example.com/data --json
70
78
 
71
- # 5. Create a payment link (requires x402-links-server)
79
+ # 6. Create a payment link (requires x402-links-server)
72
80
  x402 create-link --name "My API" --price 1.00 --url https://api.example.com/premium
73
81
  ```
74
82
 
75
83
  ## Commands
76
84
 
85
+ ### setup — Create or Configure Wallet
86
+
87
+ Interactive setup that generates a new wallet or accepts an existing private key. Saves configuration to `~/.x402/.env`.
88
+
89
+ ```bash
90
+ x402 setup
91
+ ```
92
+
93
+ **Security:** If you choose to use an existing private key, you'll see a warning. We recommend using a **dedicated wallet** with limited funds for automated agents.
94
+
95
+ ---
96
+
77
97
  ### balance — Check Wallet Balances
78
98
 
79
99
  Show your wallet address, USDC balance (for payments), and ETH balance (for gas). Warns if either balance is low.
@@ -223,6 +243,7 @@ Config is loaded from these locations (in order of priority):
223
243
 
224
244
  | Category | Command | Description |
225
245
  |----------|---------|-------------|
246
+ | **Setup** | `setup` | Create or configure your x402 wallet |
226
247
  | **Info** | `balance` | Check wallet USDC and ETH balances |
227
248
  | **Payments** | `pay <url>` | Pay for an x402-gated resource (verbose output) |
228
249
  | **Payments** | `fetch <url>` | Fetch with auto-payment (pipe-friendly `--json`/`--raw`) |
@@ -244,6 +265,50 @@ x402 fetch https://api.example.com/data --json
244
265
  x402 fetch https://api.example.com/data --raw
245
266
  ```
246
267
 
268
+ ## Backup Your Private Key
269
+
270
+ Your private key is stored in `~/.x402/.env`. **If lost, your funds cannot be recovered.**
271
+
272
+ ### Recommended Backup Methods
273
+
274
+ 1. **Password Manager** (Recommended)
275
+ - Store in 1Password, Bitwarden, or similar
276
+ - Create a secure note with your private key
277
+
278
+ 2. **Encrypted File**
279
+ ```bash
280
+ gpg -c ~/.x402/.env
281
+ # Store the encrypted .env.gpg file securely
282
+ ```
283
+
284
+ 3. **Paper Backup** (for larger amounts)
285
+ - Write down the private key
286
+ - Store in a safe or safety deposit box
287
+
288
+ ### View Your Private Key
289
+
290
+ ```bash
291
+ cat ~/.x402/.env | grep EVM_PRIVATE_KEY
292
+ ```
293
+
294
+ ### Recovery
295
+
296
+ ```bash
297
+ mkdir -p ~/.x402
298
+ echo "EVM_PRIVATE_KEY=0x...your_backed_up_key..." > ~/.x402/.env
299
+ chmod 600 ~/.x402/.env
300
+ x402 balance # verify
301
+ ```
302
+
303
+ ## Security Best Practices
304
+
305
+ - **Use a dedicated wallet** — Never use your main wallet with automated agents
306
+ - **Limit funds** — Only transfer what you need for payments
307
+ - **Set payment limits** — Configure `X402_MAX_PAYMENT_USD` to cap exposure
308
+ - **Test first** — Use `X402_NETWORK=testnet` before mainnet
309
+ - **Protect the config** — Keep `~/.x402/.env` with 600 permissions
310
+ - **Never share** — Your private key gives full access to your wallet
311
+
247
312
  ## License
248
313
 
249
314
  MIT
package/SKILL.md CHANGED
@@ -5,7 +5,7 @@ license: MIT
5
5
  compatibility: Requires Node.js 20+, network access to x402 facilitators and EVM chains
6
6
  metadata:
7
7
  author: monemetrics
8
- version: "0.1.0"
8
+ version: "0.2.1"
9
9
  allowed-tools: Bash(x402:*) Bash(npm:*) Read
10
10
  ---
11
11
 
@@ -17,6 +17,7 @@ Pay for x402-gated APIs and content using USDC on Base. This skill enables agent
17
17
 
18
18
  | Command | Description |
19
19
  |---------|-------------|
20
+ | `x402 setup` | Create or configure wallet |
20
21
  | `x402 balance` | Check USDC and ETH balances |
21
22
  | `x402 pay <url>` | Pay for a gated resource |
22
23
  | `x402 fetch <url>` | Fetch with auto-payment |
@@ -38,20 +39,33 @@ x402 --version
38
39
 
39
40
  ## Setup
40
41
 
41
- Configure your wallet private key (required):
42
+ Run the interactive setup to create a new wallet:
43
+
44
+ ```bash
45
+ x402 setup
46
+ ```
47
+
48
+ This will:
49
+ 1. Generate a new wallet (recommended) or accept an existing key
50
+ 2. Save configuration to `~/.x402/.env`
51
+ 3. Display your wallet address for funding
52
+
53
+ **Important:** Back up your private key immediately after setup!
54
+
55
+ ### Manual Configuration
56
+
57
+ Alternatively, set the environment variable directly:
42
58
 
43
59
  ```bash
44
60
  export EVM_PRIVATE_KEY=0x...your_private_key...
45
61
  ```
46
62
 
47
- Or create a persistent config file:
63
+ Or create a config file:
48
64
 
49
65
  ```bash
50
66
  mkdir -p ~/.x402
51
- cat > ~/.x402/.env << 'EOF'
52
- EVM_PRIVATE_KEY=0x...your_private_key...
53
- X402_NETWORK=mainnet
54
- EOF
67
+ echo "EVM_PRIVATE_KEY=0x..." > ~/.x402/.env
68
+ chmod 600 ~/.x402/.env
55
69
  ```
56
70
 
57
71
  Verify setup:
@@ -299,12 +313,53 @@ Ensure your wallet has funds on the correct network:
299
313
  - `X402_NETWORK=mainnet` → Base mainnet
300
314
  - `X402_NETWORK=testnet` → Base Sepolia
301
315
 
302
- ## Security Notes
316
+ ## Backup Your Private Key
317
+
318
+ Your private key is stored in `~/.x402/.env`. If lost, your funds cannot be recovered.
319
+
320
+ ### Recommended Backup Methods
321
+
322
+ 1. **Password Manager** (Recommended)
323
+ - Store in 1Password, Bitwarden, or similar
324
+ - Create a secure note with your private key
325
+ - Tag it for easy retrieval
326
+
327
+ 2. **Encrypted File**
328
+ ```bash
329
+ # Encrypt with GPG
330
+ gpg -c ~/.x402/.env
331
+ # Creates ~/.x402/.env.gpg - store this backup securely
332
+ ```
333
+
334
+ 3. **Paper Backup** (for larger amounts)
335
+ - Write down the private key
336
+ - Store in a safe or safety deposit box
337
+ - Never store digitally unencrypted
338
+
339
+ ### View Your Private Key
340
+
341
+ ```bash
342
+ cat ~/.x402/.env | grep EVM_PRIVATE_KEY
343
+ ```
344
+
345
+ ### Recovery
346
+
347
+ To restore from backup:
348
+ ```bash
349
+ mkdir -p ~/.x402
350
+ echo "EVM_PRIVATE_KEY=0x...your_backed_up_key..." > ~/.x402/.env
351
+ chmod 600 ~/.x402/.env
352
+ x402 balance # verify
353
+ ```
354
+
355
+ ## Security Best Practices
303
356
 
304
- - Never share your private key
305
- - Start with testnet to verify setup
306
- - Set reasonable payment limits
307
- - Review payment amounts before confirming
357
+ - **Use a dedicated wallet** — Never use your main wallet with automated agents
358
+ - **Limit funds** Only transfer what you need for payments
359
+ - **Set payment limits** — Configure `X402_MAX_PAYMENT_USD` to cap exposure
360
+ - **Test first** Use `X402_NETWORK=testnet` with test tokens before mainnet
361
+ - **Protect the config** — `~/.x402/.env` has 600 permissions; keep it that way
362
+ - **Never share** — Your private key gives full access to your wallet
308
363
 
309
364
  ## Links
310
365
 
package/bin/cli.ts CHANGED
@@ -11,10 +11,17 @@ const scriptsDir = resolve(__dirname, '../scripts');
11
11
  interface Command {
12
12
  script: string;
13
13
  description: string;
14
- category: 'info' | 'payments' | 'links';
14
+ category: 'setup' | 'info' | 'payments' | 'links';
15
15
  }
16
16
 
17
17
  const commands: Record<string, Command> = {
18
+ // Setup commands
19
+ setup: {
20
+ script: 'commands/setup.ts',
21
+ description: 'Create or configure your x402 wallet',
22
+ category: 'setup',
23
+ },
24
+
18
25
  // Info commands
19
26
  balance: {
20
27
  script: 'commands/balance.ts',
@@ -53,6 +60,9 @@ x402 - Agent skill for x402 payments
53
60
 
54
61
  Usage: x402 <command> [arguments]
55
62
 
63
+ Setup:
64
+ setup Create or configure your x402 wallet
65
+
56
66
  Info Commands:
57
67
  balance Check wallet USDC and ETH balances
58
68
 
@@ -68,26 +78,18 @@ Options:
68
78
  -h, --help Show this help
69
79
  -v, --version Show version
70
80
 
71
- Environment Variables:
72
- EVM_PRIVATE_KEY Wallet private key (required)
73
- X402_NETWORK Network: mainnet or testnet (default: mainnet)
74
- X402_MAX_PAYMENT_USD Max payment limit in USD (default: 10)
75
- X402_FACILITATOR_URL Custom facilitator URL
76
- X402_LINKS_API_URL x402-links-server URL (for link commands)
77
- X402_LINKS_API_KEY API key for x402-links-server
78
-
79
- Examples:
80
- x402 balance
81
- x402 pay https://api.example.com/data
82
- x402 fetch https://api.example.com/resource --json
83
- x402 create-link --name "Guide" --price 5.00 --url https://mysite.com/guide
81
+ Getting Started:
82
+ 1. Run "x402 setup" to create a new wallet
83
+ 2. Fund your wallet with USDC on Base
84
+ 3. Run "x402 balance" to verify
85
+ 4. Use "x402 pay <url>" to pay for resources
84
86
 
85
87
  For command-specific help: x402 <command> --help
86
88
  `);
87
89
  }
88
90
 
89
91
  function showVersion() {
90
- console.log('agentic-x402 v0.1.0');
92
+ console.log('agentic-x402 v0.2.1');
91
93
  }
92
94
 
93
95
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-x402",
3
- "version": "0.1.2",
3
+ "version": "0.2.1",
4
4
  "description": "Agent skill for x402 payments - pay for and sell gated content",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,6 +14,7 @@
14
14
  "SKILL.md"
15
15
  ],
16
16
  "scripts": {
17
+ "setup": "tsx scripts/commands/setup.ts",
17
18
  "pay": "tsx scripts/commands/pay.ts",
18
19
  "fetch": "tsx scripts/commands/fetch-paid.ts",
19
20
  "balance": "tsx scripts/commands/balance.ts",
@@ -0,0 +1,296 @@
1
+ #!/usr/bin/env npx tsx
2
+ // x402 Agent Skill - Wallet Setup
3
+ // Creates a new wallet or configures an existing one
4
+
5
+ import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
6
+ import * as fs from 'fs';
7
+ import * as path from 'path';
8
+ import * as readline from 'readline';
9
+ import { homedir } from 'os';
10
+
11
+ // Global config directory: ~/.x402/
12
+ const CONFIG_DIR = path.join(homedir(), '.x402');
13
+ const CONFIG_PATH = path.join(CONFIG_DIR, '.env');
14
+
15
+ interface SetupResult {
16
+ success: boolean;
17
+ walletAddress?: string;
18
+ privateKey?: string;
19
+ isNewWallet?: boolean;
20
+ error?: string;
21
+ }
22
+
23
+ function createReadline(): readline.Interface {
24
+ return readline.createInterface({
25
+ input: process.stdin,
26
+ output: process.stdout,
27
+ });
28
+ }
29
+
30
+ function prompt(rl: readline.Interface, question: string): Promise<string> {
31
+ return new Promise((resolve) => {
32
+ rl.question(question, (answer) => {
33
+ resolve(answer.trim());
34
+ });
35
+ });
36
+ }
37
+
38
+ function isValidPrivateKey(key: string): boolean {
39
+ return /^0x[a-fA-F0-9]{64}$/.test(key);
40
+ }
41
+
42
+ function ensureConfigDir(): void {
43
+ if (!fs.existsSync(CONFIG_DIR)) {
44
+ fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
45
+ }
46
+ }
47
+
48
+ function backupExistingConfig(): string | null {
49
+ if (!fs.existsSync(CONFIG_PATH)) {
50
+ return null;
51
+ }
52
+
53
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
54
+ const backupPath = path.join(CONFIG_DIR, `.env.backup.${timestamp}`);
55
+
56
+ fs.copyFileSync(CONFIG_PATH, backupPath);
57
+ fs.chmodSync(backupPath, 0o600);
58
+
59
+ return backupPath;
60
+ }
61
+
62
+ async function main(): Promise<SetupResult> {
63
+ console.log('x402 Agent Skill - Wallet Setup');
64
+ console.log('================================\n');
65
+
66
+ // Check if config already exists
67
+ if (fs.existsSync(CONFIG_PATH)) {
68
+ console.log('Existing config found!');
69
+ console.log(`Location: ${CONFIG_PATH}\n`);
70
+
71
+ // Read existing config and show wallet address
72
+ const envContent = fs.readFileSync(CONFIG_PATH, 'utf-8');
73
+ const keyMatch = envContent.match(/EVM_PRIVATE_KEY=0x([a-fA-F0-9]{64})/);
74
+
75
+ if (keyMatch) {
76
+ const existingKey = `0x${keyMatch[1]}` as `0x${string}`;
77
+ const account = privateKeyToAccount(existingKey);
78
+
79
+ console.log('Current Configuration');
80
+ console.log('---------------------');
81
+ console.log(`Wallet Address: ${account.address}`);
82
+ console.log(`Config File: ${CONFIG_PATH}`);
83
+
84
+ const rl = createReadline();
85
+ console.log('\nOptions:');
86
+ console.log(' 1) Keep existing config (exit)');
87
+ console.log(' 2) Create new wallet (backs up existing config)\n');
88
+
89
+ let choice = '';
90
+ while (choice !== '1' && choice !== '2') {
91
+ choice = await prompt(rl, 'Enter choice (1 or 2): ');
92
+ if (choice !== '1' && choice !== '2') {
93
+ console.log('Please enter 1 or 2');
94
+ }
95
+ }
96
+
97
+ if (choice === '1') {
98
+ rl.close();
99
+ console.log('\nKeeping existing config.');
100
+ console.log(`\nTo check your balance:`);
101
+ console.log(` x402 balance`);
102
+
103
+ return {
104
+ success: true,
105
+ walletAddress: account.address,
106
+ };
107
+ }
108
+
109
+ // User wants to reconfigure - backup first
110
+ rl.close();
111
+ const backupPath = backupExistingConfig();
112
+ console.log(`\nExisting config backed up to:`);
113
+ console.log(` ${backupPath}`);
114
+ console.log('');
115
+
116
+ // Continue with setup flow below...
117
+ } else {
118
+ // Config exists but is invalid - back it up and continue
119
+ const backupPath = backupExistingConfig();
120
+ console.log('Invalid config file found (missing private key).');
121
+ console.log(`Backed up to: ${backupPath}\n`);
122
+ }
123
+ }
124
+
125
+ const rl = createReadline();
126
+
127
+ // Step 1: Wallet choice
128
+ console.log('Step 1/2: Wallet Setup');
129
+ console.log('----------------------');
130
+ console.log('Do you have an existing wallet private key?\n');
131
+ console.log(' 1) Generate a NEW wallet (Recommended for agents)');
132
+ console.log(' 2) Use an EXISTING private key\n');
133
+
134
+ let choice = '';
135
+ while (choice !== '1' && choice !== '2') {
136
+ choice = await prompt(rl, 'Enter choice (1 or 2): ');
137
+ if (choice !== '1' && choice !== '2') {
138
+ console.log('Please enter 1 or 2');
139
+ }
140
+ }
141
+
142
+ let privateKey: `0x${string}`;
143
+ let isNewWallet = false;
144
+
145
+ if (choice === '1') {
146
+ // Generate new wallet (recommended)
147
+ console.log('\nGenerating new wallet...');
148
+ privateKey = generatePrivateKey();
149
+ isNewWallet = true;
150
+ console.log('New wallet created!\n');
151
+ } else {
152
+ // User wants to use existing key - show warnings
153
+ console.log('\n' + '='.repeat(60));
154
+ console.log(' SECURITY WARNING');
155
+ console.log('='.repeat(60));
156
+ console.log('\nUsing your main wallet with automated agents is RISKY:');
157
+ console.log('');
158
+ console.log(' - Agents can sign transactions without your approval');
159
+ console.log(' - A bug or misconfiguration could drain funds');
160
+ console.log(' - Private keys stored in env files can be exposed');
161
+ console.log('');
162
+ console.log('RECOMMENDED: Use a DEDICATED wallet with limited funds.');
163
+ console.log('Only transfer what you need for payments to this wallet.');
164
+ console.log('='.repeat(60) + '\n');
165
+
166
+ const confirm = await prompt(rl, 'I understand the risks (type "yes" to continue): ');
167
+
168
+ if (confirm.toLowerCase() !== 'yes') {
169
+ console.log('\nSetup cancelled. Run "x402 setup" again to generate a new wallet.');
170
+ rl.close();
171
+ return { success: false, error: 'User cancelled setup' };
172
+ }
173
+
174
+ console.log('\nEnter your private key (0x... format):\n');
175
+
176
+ // Loop until we get a valid key
177
+ let inputKey = '';
178
+ while (!isValidPrivateKey(inputKey)) {
179
+ inputKey = await prompt(rl, 'Private key: ');
180
+
181
+ if (!isValidPrivateKey(inputKey)) {
182
+ console.log('Invalid private key format. Must be 0x followed by 64 hex characters.');
183
+ console.log('Example: 0x1234...abcd (66 characters total)\n');
184
+ }
185
+ }
186
+
187
+ privateKey = inputKey as `0x${string}`;
188
+ console.log('\nPrivate key accepted');
189
+ }
190
+
191
+ rl.close();
192
+
193
+ // Derive account from private key
194
+ const account = privateKeyToAccount(privateKey);
195
+ console.log(`Wallet Address: ${account.address}\n`);
196
+
197
+ // Step 2: Create config
198
+ console.log('Step 2/2: Saving configuration...');
199
+ ensureConfigDir();
200
+
201
+ const envContent = `# x402 Agent Skill Configuration
202
+ # Location: ~/.x402/.env
203
+ # Created: ${new Date().toISOString()}
204
+ #
205
+ # WARNING: Keep this file secret! Never share your private key!
206
+ # This wallet can sign payment transactions automatically.
207
+
208
+ # Your wallet private key (required)
209
+ EVM_PRIVATE_KEY=${privateKey}
210
+
211
+ # Network: mainnet or testnet
212
+ # mainnet = Base (chain 8453) - real USDC
213
+ # testnet = Base Sepolia (chain 84532) - test tokens
214
+ X402_NETWORK=mainnet
215
+
216
+ # Maximum payment limit in USD (safety feature)
217
+ # Payments exceeding this will be rejected
218
+ X402_MAX_PAYMENT_USD=10
219
+
220
+ # Verbose logging (0 = off, 1 = on)
221
+ X402_VERBOSE=0
222
+ `;
223
+
224
+ fs.writeFileSync(CONFIG_PATH, envContent, { mode: 0o600 });
225
+ console.log(`Config saved to: ${CONFIG_PATH}\n`);
226
+
227
+ // Final summary
228
+ console.log('='.repeat(50));
229
+ console.log(' SETUP COMPLETE!');
230
+ console.log('='.repeat(50) + '\n');
231
+
232
+ console.log('Your x402 Payment Wallet');
233
+ console.log('------------------------');
234
+ console.log(`Address: ${account.address}`);
235
+ console.log(`Network: Base Mainnet (chain 8453)`);
236
+ console.log(`Config: ${CONFIG_PATH}`);
237
+
238
+ if (isNewWallet) {
239
+ console.log('\n' + '!'.repeat(50));
240
+ console.log(' BACKUP YOUR PRIVATE KEY NOW!');
241
+ console.log('!'.repeat(50));
242
+ console.log('\nYour private key (save this securely):');
243
+ console.log(`\n ${privateKey}\n`);
244
+ console.log('Store this in a password manager or secure location.');
245
+ console.log('If lost, your funds CANNOT be recovered!');
246
+ console.log('!'.repeat(50));
247
+ }
248
+
249
+ console.log('\nNext Steps');
250
+ console.log('----------');
251
+ console.log('1. Fund your wallet with USDC on Base:');
252
+ console.log(` Address: ${account.address}`);
253
+ console.log('');
254
+ console.log('2. Add a small amount of ETH for gas (optional):');
255
+ console.log(' ~0.001 ETH is enough for many transactions');
256
+ console.log('');
257
+ console.log('3. Check your balance:');
258
+ console.log(' x402 balance');
259
+ console.log('');
260
+ console.log('4. Try paying for an x402 resource:');
261
+ console.log(' x402 pay https://some-x402-api.com/endpoint');
262
+
263
+ console.log('\nBackup Reminder');
264
+ console.log('---------------');
265
+ console.log(`Your config is stored at: ${CONFIG_PATH}`);
266
+ console.log('Back up this file or your private key securely!');
267
+ console.log('Consider using a password manager like 1Password or Bitwarden.');
268
+
269
+ console.log('\nSecurity Tips');
270
+ console.log('-------------');
271
+ console.log('- Only fund this wallet with what you need');
272
+ console.log('- Set X402_MAX_PAYMENT_USD to limit exposure');
273
+ console.log('- Never share your private key or config file');
274
+ console.log('- Use testnet first to verify everything works');
275
+
276
+ return {
277
+ success: true,
278
+ walletAddress: account.address,
279
+ privateKey: privateKey,
280
+ isNewWallet,
281
+ };
282
+ }
283
+
284
+ // Export for programmatic use
285
+ export { main as setup };
286
+
287
+ // Run if executed directly
288
+ main().then(result => {
289
+ if (!result.success) {
290
+ console.error(`\nSetup failed: ${result.error}`);
291
+ process.exit(1);
292
+ }
293
+ }).catch(error => {
294
+ console.error('Setup error:', error);
295
+ process.exit(1);
296
+ });