claudmax 1.0.12 → 1.0.14

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 (2) hide show
  1. package/index.js +152 -219
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -7,25 +7,16 @@ const fs = require('fs');
7
7
  const path = require('path');
8
8
  const os = require('os');
9
9
  const https = require('https');
10
- const { execSync, exec } = require('child_process');
10
+ const { execSync } = require('child_process');
11
11
 
12
12
  // ── Constants ─────────────────────────────────────────────────────────────────
13
- const PKG_NAME = 'ClaudMax';
14
- const API_BASE = 'https://api.claudmax.pro';
15
13
  const MCP_PKG = 'claudmax-mcp';
14
+ const API_BASE = 'https://api.claudmax.pro';
16
15
 
17
16
  const HOME = os.homedir();
18
17
  const CONFIG_DIR = path.join(HOME, '.claudmax');
19
18
  const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
20
19
 
21
- // Detect shell profile
22
- function getShellProfile() {
23
- const profile = process.env.SHELL?.includes('zsh') !== false
24
- ? path.join(HOME, '.zshrc')
25
- : path.join(HOME, '.bashrc');
26
- return profile;
27
- }
28
-
29
20
  // ── Color helpers ─────────────────────────────────────────────────────────────
30
21
  const C = {
31
22
  reset: '\x1b[0m',
@@ -84,21 +75,6 @@ function ensureDir(dir) {
84
75
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
85
76
  }
86
77
 
87
- function fileContains(filePath, substring) {
88
- try {
89
- return fs.readFileSync(filePath, 'utf8').includes(substring);
90
- } catch { return false; }
91
- }
92
-
93
- function appendToFile(filePath, content) {
94
- const current = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : '';
95
- if (!current.includes(content.trim())) {
96
- fs.appendFileSync(filePath, '\n' + content + '\n');
97
- return true;
98
- }
99
- return false;
100
- }
101
-
102
78
  // ── Version check helpers ─────────────────────────────────────────────────────
103
79
  function getCommandVersion(cmd) {
104
80
  try {
@@ -185,7 +161,7 @@ function installClaudeCLI() {
185
161
  function verifyConnection(apiKey) {
186
162
  return new Promise((resolve) => {
187
163
  const options = {
188
- hostname: 'api.claudmax.pro',
164
+ hostname: API_BASE.replace('https://', ''),
189
165
  port: 443,
190
166
  path: '/v1/key-status',
191
167
  method: 'POST',
@@ -223,34 +199,32 @@ function verifyConnection(apiKey) {
223
199
 
224
200
  // ── System configuration ──────────────────────────────────────────────────────
225
201
  function configureSystem(apiKey) {
226
- console.log(`\n${ARROW} ${C.bold('Configuring system for ' + PKG_NAME + '...')}`);
202
+ console.log(` ${ARROW} ${C.bold('Saving configuration...')}`);
227
203
 
228
- // 1. Save config file
204
+ // Save config file
229
205
  ensureDir(CONFIG_DIR);
230
206
  writeJson(CONFIG_FILE, {
231
207
  apiKey,
232
208
  baseUrl: API_BASE,
233
209
  configuredAt: new Date().toISOString(),
234
- version: '1.0.12',
210
+ version: '1.0.14',
235
211
  });
236
- console.log(` ${CHECK} Saved config to ${C.magenta(CONFIG_FILE)}`);
237
- console.log(` ${INFO} ${C.dim('Claude Code CLI uses settings.json — no shell profile modification needed.')}`);
238
-
239
- return null;
212
+ console.log(` ${CHECK} Config saved to ${C.magenta('~/.claudmax/config.json')}`);
213
+ console.log(` ${INFO} ${C.dim('Claude Code CLI reads settings.json — no shell profile modification needed.')}`);
240
214
  }
241
215
 
242
216
  // ── Claude Code CLI configuration ─────────────────────────────────────────────
243
217
  function configureClaudeCLI(apiKey) {
244
- console.log(`\n${ARROW} ${C.bold('Configuring Claude Code CLI...')}`);
218
+ console.log(` ${ARROW} ${C.bold('Claude Code CLI...')}`);
245
219
 
246
220
  const settingsPath = path.join(HOME, '.claude', 'settings.json');
247
221
  const dotClaudePath = path.join(HOME, '.claude.json');
248
222
 
249
223
  ensureDir(path.dirname(settingsPath));
250
224
 
251
- // settings.json — use deepMerge to preserve OpusCode settings
252
- const existing = readJson(settingsPath) || {};
253
- const settings = deepMerge(existing, {
225
+ // settings.json
226
+ const settings = readJson(settingsPath) || {};
227
+ deepMerge(settings, {
254
228
  env: {
255
229
  ANTHROPIC_AUTH_TOKEN: apiKey,
256
230
  ANTHROPIC_BASE_URL: `${API_BASE}`,
@@ -264,7 +238,7 @@ function configureClaudeCLI(apiKey) {
264
238
  hasCompletedOnboarding: true,
265
239
  });
266
240
  writeJson(settingsPath, settings);
267
- console.log(` ${CHECK} Wrote Claude Code settings: ${C.magenta(settingsPath)}`);
241
+ console.log(` ${CHECK} Claude Code settings ${C.dim('~/.claude/settings.json')}`);
268
242
 
269
243
  // .claude.json (MCP servers)
270
244
  const dotClaude = readJson(dotClaudePath) || {};
@@ -278,7 +252,7 @@ function configureClaudeCLI(apiKey) {
278
252
  },
279
253
  };
280
254
  writeJson(dotClaudePath, dotClaude);
281
- console.log(` ${CHECK} Registered ClaudMax MCP server: ${C.magenta(dotClaudePath)}`);
255
+ console.log(` ${CHECK} MCP server registered ${C.dim('~/.claude.json')}`);
282
256
  }
283
257
 
284
258
  // ── IDE configurators ────────────────────────────────────────────────────────
@@ -294,14 +268,12 @@ function getVSCodeSettingsPath() {
294
268
  }
295
269
 
296
270
  function configureVSCodeClaude(apiKey) {
297
- console.log(`\n${ARROW} ${C.bold('Configuring VS Code Claude Extension...')}`);
298
271
  configureClaudeCLI(apiKey);
299
- console.log(` ${INFO} Claude extension auto-detects Claude Code CLI settings. Restart VS Code after setup.`);
272
+ console.log(` ${INFO} Claude extension auto-detects Claude Code settings. ${C.dim('Restart VS Code after setup.')}`);
300
273
  }
301
274
 
302
275
  function configureCursor(apiKey) {
303
- console.log(`\n${ARROW} ${C.bold('Configuring Cursor...')}`);
304
-
276
+ console.log(` ${ARROW} ${C.bold('Cursor...')}`);
305
277
  const mcpPath = path.join(HOME, '.cursor', 'mcp.json');
306
278
  ensureDir(path.dirname(mcpPath));
307
279
  const existing = readJson(mcpPath) || {};
@@ -315,14 +287,13 @@ function configureCursor(apiKey) {
315
287
  },
316
288
  };
317
289
  writeJson(mcpPath, existing);
318
- console.log(` ${CHECK} Wrote Cursor MCP config: ${C.magenta(mcpPath)}`);
319
- console.log(` ${INFO} Set base URL in Cursor: Settings > Models > Add custom model`);
320
- console.log(` ${C.dim('https://api.claudmax.pro/v1/chat')}`);
290
+ console.log(` ${CHECK} Cursor configured ${C.dim('~/.cursor/mcp.json')}`);
291
+ console.log(` ${INFO} ${C.dim('Add model in Cursor: Settings > Models > Add custom model')}`);
292
+ console.log(` ${C.dim('Base URL: https://api.claudmax.pro/v1/chat')}`);
321
293
  }
322
294
 
323
295
  function configureWindsurf(apiKey) {
324
- console.log(`\n${ARROW} ${C.bold('Configuring Windsurf...')}`);
325
-
296
+ console.log(` ${ARROW} ${C.bold('Windsurf...')}`);
326
297
  const mcpPath = path.join(HOME, '.windsurf', 'mcp.json');
327
298
  ensureDir(path.dirname(mcpPath));
328
299
  const existing = readJson(mcpPath) || {};
@@ -336,13 +307,13 @@ function configureWindsurf(apiKey) {
336
307
  },
337
308
  };
338
309
  writeJson(mcpPath, existing);
339
- console.log(` ${CHECK} Wrote Windsurf MCP config: ${C.magenta(mcpPath)}`);
340
- console.log(` ${INFO} Set base URL in Windsurf: Settings > AI Provider`);
341
- console.log(` ${C.dim('https://api.claudmax.pro/v1/chat')}`);
310
+ console.log(` ${CHECK} Windsurf configured ${C.dim('~/.windsurf/mcp.json')}`);
311
+ console.log(` ${INFO} ${C.dim('Set base URL in Windsurf: Settings > AI Provider')}`);
312
+ console.log(` ${C.dim('https://api.claudmax.pro/v1/chat')}`);
342
313
  }
343
314
 
344
315
  function configureCline(apiKey) {
345
- console.log(`\n${ARROW} ${C.bold('Configuring Cline (VS Code)...')}`);
316
+ console.log(` ${ARROW} ${C.bold('Cline...')}`);
346
317
  const settingsPath = getVSCodeSettingsPath();
347
318
  ensureDir(path.dirname(settingsPath));
348
319
  const existing = readJson(settingsPath) || {};
@@ -352,11 +323,11 @@ function configureCline(apiKey) {
352
323
  'cline.apiKey': apiKey,
353
324
  });
354
325
  writeJson(settingsPath, existing);
355
- console.log(` ${CHECK} Wrote Cline settings: ${C.magenta(settingsPath)}`);
326
+ console.log(` ${CHECK} Cline configured ${C.dim(settingsPath.replace(HOME, '~'))}`);
356
327
  }
357
328
 
358
329
  function configureRooCode(apiKey) {
359
- console.log(`\n${ARROW} ${C.bold('Configuring Roo Code (VS Code)...')}`);
330
+ console.log(` ${ARROW} ${C.bold('Roo Code...')}`);
360
331
  const settingsPath = getVSCodeSettingsPath();
361
332
  ensureDir(path.dirname(settingsPath));
362
333
  const existing = readJson(settingsPath) || {};
@@ -366,20 +337,18 @@ function configureRooCode(apiKey) {
366
337
  'roo-cline.apiKey': apiKey,
367
338
  });
368
339
  writeJson(settingsPath, existing);
369
- console.log(` ${CHECK} Wrote Roo Code settings: ${C.magenta(settingsPath)}`);
340
+ console.log(` ${CHECK} Roo Code configured ${C.dim(settingsPath.replace(HOME, '~'))}`);
370
341
  }
371
342
 
372
343
  // ── MCP server install ───────────────────────────────────────────────────────
373
344
  function installMCPServer() {
374
- console.log(`\n${ARROW} ${C.bold('Installing ClaudMax MCP server globally...')}`);
345
+ console.log(` ${ARROW} ${C.bold('Installing MCP server...')}`);
375
346
  try {
376
347
  execSync('npm install -g ' + MCP_PKG, { stdio: 'pipe', timeout: 60000 });
377
- console.log(` ${CHECK} ${C.green(MCP_PKG + ' installed successfully.')}`);
348
+ console.log(` ${CHECK} ${C.green('MCP server installed')}`);
378
349
  return true;
379
350
  } catch (err) {
380
- const errMsg = String(err.stderr || err.message || '');
381
- console.log(` ${WARN} Could not install ${MCP_PKG}: ${C.dim(String(errMsg).trim())}`);
382
- console.log(` ${INFO} Install manually later: ${C.bold('npm install -g ' + MCP_PKG)}`);
351
+ console.log(` ${WARN} ${C.yellow('Could not install MCP server. Run manually:')} ${C.bold('npm install -g ' + MCP_PKG)}`);
383
352
  return false;
384
353
  }
385
354
  }
@@ -387,122 +356,46 @@ function installMCPServer() {
387
356
  // ── Banner ────────────────────────────────────────────────────────────────────
388
357
  function printBanner() {
389
358
  console.log('');
390
- console.log(C.magenta('\u2554' + '\u2550'.repeat(44) + '\u2557'));
391
- console.log(C.magenta('\u2551') + C.bold(' \u26A1 ClaudMax Setup ') + C.magenta('\u2551'));
392
- console.log(C.magenta('\u255A' + '\u2550'.repeat(44) + '\u255D'));
359
+ console.log(C.purple(' ╔════════════════════════════════════════════════════════════════╗'));
360
+ console.log(C.purple('') + C.bold(' ') + C.purple(''));
361
+ console.log(C.purple('') + C.bold(' ⚡ ClaudMax CLI Setup Wizard ⚡ ') + C.purple(''));
362
+ console.log(C.purple(' ║') + C.dim(' One-command setup for Claude API ') + C.purple('║'));
363
+ console.log(C.purple(' ║') + C.bold(' ') + C.purple('║'));
364
+ console.log(C.purple(' ╚════════════════════════════════════════════════════════════════╝'));
393
365
  console.log('');
394
366
  }
395
367
 
396
- // ── CLI argument parsing ────────────────────────────────────────────────────────
397
- const args = process.argv.slice(2);
398
- const command = args[0];
399
-
400
- // ── Status command ─────────────────────────────────────────────────────────────
401
- async function showStatus() {
402
- const config = readJson(CONFIG_FILE);
403
- if (!config || !config.apiKey) {
404
- console.log(`\n${WARN} No API key configured. Run ${C.bold('npx claudmax')} first.\n`);
405
- process.exit(1);
406
- }
407
-
408
- console.log(`\n${C.magenta('\u2554' + '\u2550'.repeat(48) + '\u2557')}`);
409
- console.log(C.magenta('\u2551') + C.bold(' \u2726 ClaudMax Status \u2726 ') + C.magenta('\u2551'));
410
- console.log(C.magenta('\u255A' + '\u2550'.repeat(48) + '\u255D'));
368
+ // ── Step header ────────────────────────────────────────────────────────────────
369
+ function printStep(stepNum, title) {
370
+ console.log('');
371
+ console.log(C.bold(' ┌─────────────────────────────────────────────────────────┐'));
372
+ console.log(C.bold(' │ ') + C.purple('Step ' + stepNum) + C.bold(' ' + title.padEnd(42) + '│'));
373
+ console.log(C.bold(' └─────────────────────────────────────────────────────────┘'));
411
374
  console.log('');
412
-
413
- // Fetch key status
414
- const body = JSON.stringify({ apiKey: config.apiKey });
415
- const postData = Buffer.from(body);
416
-
417
- const options = {
418
- hostname: 'api.claudmax.pro',
419
- port: 443,
420
- path: '/v1/key-status',
421
- method: 'POST',
422
- headers: {
423
- 'Content-Type': 'application/json',
424
- 'Content-Length': postData.length,
425
- 'User-Agent': 'ClaudMax-CLI/1.0.0',
426
- },
427
- timeout: 15000,
428
- };
429
-
430
- return new Promise((resolve) => {
431
- const req = https.request(options, (res) => {
432
- let data = '';
433
- res.on('data', (chunk) => { data += chunk; });
434
- res.on('end', () => {
435
- try {
436
- const json = JSON.parse(data);
437
- if (res.statusCode === 200) {
438
- const pct = json.tokensLimit > 0 ? Math.min(100, (json.tokensUsed / json.tokensLimit) * 100) : 0;
439
- const tierColors = { free: C.dim('Gray'), '5x': C.cyan('Blue'), '20x': C.magenta('Purple'), unlimited: C.green('Gold') };
440
- console.log(` ${CHECK} ${C.green('API Key is active')}`);
441
- console.log(` ${INFO} Name: ${C.bold(json.name || 'ClaudMax Key')}`);
442
- console.log(` ${INFO} Prefix: ${C.magenta(json.prefix)}••••••`);
443
- console.log(` ${INFO} Tier: ${tierColors[json.tier] || C.dim('Free')} (${C.bold(json.tier?.toUpperCase() || 'FREE')})`);
444
- console.log(` ${INFO} Status: ${json.isActive ? C.green('Active') : C.red('Inactive')}`);
445
- console.log('');
446
- console.log(` ${C.bold('Usage (5h window):')}`);
447
- const barLen = 30;
448
- const filled = Math.round((pct / 100) * barLen);
449
- const bar = C.purple('\u2588'.repeat(filled)) + C.dim('\u2591'.repeat(barLen - filled));
450
- console.log(` ${bar} ${C.dim(`${pct.toFixed(1)}%`)}`);
451
- console.log(` ${INFO} Requests: ${C.cyan(json.requestsUsed?.toLocaleString() || 0)} / ${C.cyan(json.requestsLimit?.toLocaleString() || 'N/A')}`);
452
- console.log(` ${INFO} Tokens: ${C.cyan((json.tokensUsed || 0).toLocaleString())} / ${C.cyan((json.tokensLimit || 0).toLocaleString())}`);
453
- console.log('');
454
- if (json.windowResetAt) {
455
- const reset = new Date(json.windowResetAt);
456
- console.log(` ${INFO} Resets: ${C.dim(reset.toLocaleString())}`);
457
- }
458
- } else {
459
- console.log(` ${CROSS} ${C.red('Failed to fetch status: ' + (json.error || `HTTP ${res.statusCode}`))}`);
460
- }
461
- } catch {
462
- console.log(` ${CROSS} ${C.red('Failed to parse response')}`);
463
- }
464
- console.log('');
465
- resolve();
466
- });
467
- });
468
- req.on('error', (err) => {
469
- console.log(` ${WARN} ${C.yellow('Network error: ' + err.message)}`);
470
- console.log('');
471
- resolve();
472
- });
473
- req.on('timeout', () => { req.destroy(); console.log(` ${CROSS} ${C.red('Request timed out')}\n`); resolve(); });
474
- req.write(postData);
475
- req.end();
476
- });
477
375
  }
478
376
 
479
- // ── Help ───────────────────────────────────────────────────────────────────────
480
- function showHelp() {
481
- console.log(`\n${C.bold('ClaudMax CLI')} — Configure Claude Code and other IDEs to use ClaudMax API.\n`);
482
- console.log(` ${C.cyan('npx claudmax')} ${C.dim('Launch the interactive setup wizard')}`);
483
- console.log(` ${C.cyan('npx claudmax status')} ${C.dim('Check your API key usage and limits')}`);
484
- console.log(` ${C.cyan('npx claudmax --help')} ${C.dim('Show this help message')}`);
377
+ // ── Section box ────────────────────────────────────────────────────────────────
378
+ function printBox(lines) {
379
+ const maxLen = Math.max(...lines.map(l => l.length), 40);
380
+ const top = ' ' + C.dim('\u250C' + '\u2500'.repeat(maxLen + 4) + '\u2510');
381
+ const bot = ' ' + C.dim('\u2514' + '\u2500'.repeat(maxLen + 4) + '\u2518');
382
+ console.log(top);
383
+ lines.forEach(line => {
384
+ const padded = line + ' '.repeat(maxLen - line.length);
385
+ console.log(' ' + C.dim('\u2502') + ' ' + padded + ' ' + C.dim('\u2502'));
386
+ });
387
+ console.log(bot);
485
388
  console.log('');
486
389
  }
487
390
 
488
391
  // ── Main ──────────────────────────────────────────────────────────────────────
489
392
  async function main() {
490
- if (command === 'status') {
491
- await showStatus();
492
- return;
493
- }
494
- if (command === '--help' || command === '-h') {
495
- showHelp();
496
- return;
497
- }
498
-
499
- // Default: interactive setup wizard
500
393
  const rl = createRL();
501
394
 
502
395
  printBanner();
503
396
 
504
397
  // ── Step 1: Check dependencies ─────────────────────────────────────────────
505
- console.log(C.bold('Step 1: Checking system dependencies...\n'));
398
+ printStep(1, 'System Dependencies');
506
399
 
507
400
  let nodeOk = isCommandAvailable('node');
508
401
  let gitOk = isCommandAvailable('git');
@@ -517,56 +410,120 @@ async function main() {
517
410
  for (const dep of deps) {
518
411
  if (dep.ok) {
519
412
  const version = getCommandVersion(dep.cmd);
520
- console.log(` ${CHECK} ${C.green(dep.label)} ${C.dim(version || '')}`);
413
+ console.log(` ${CHECK} ${C.green(dep.label)} ${C.dim(version || '')}`);
521
414
  } else {
522
- console.log(` ${CROSS} ${C.red(dep.label)} ${C.dim('not found')}`);
415
+ console.log(` ${CROSS} ${C.red(dep.label)} ${C.dim('not found')}`);
523
416
  }
524
417
  }
525
418
 
526
- // Install missing deps
527
419
  if (!nodeOk) {
528
420
  if (!installDep('Node.js', installNode)) {
529
- console.log(`\n${C.red('Node.js installation failed. Please install manually from https://nodejs.org')}`);
421
+ console.log(`\n ${CROSS} ${C.red('Node.js installation failed. Please install manually from https://nodejs.org')}`);
530
422
  } else {
531
423
  nodeOk = isCommandAvailable('node');
532
424
  }
533
425
  }
534
426
 
535
- // ── Step 1: API key prompt ───────────────────────────────────────────────
536
- console.log(C.bold('\nStep 1: Enter your ClaudMax API key\n'));
427
+ if (nodeOk && !gitOk) {
428
+ if (!installDep('Git', installGit)) {
429
+ console.log(`\n ${WARN} ${C.yellow('Git installation failed. You can install it manually.')}`);
430
+ } else {
431
+ gitOk = isCommandAvailable('git');
432
+ }
433
+ }
434
+
435
+ if (nodeOk && !claudeOk) {
436
+ const installClaude = await ask(rl, `\n ${WARN} ${C.yellow('Claude CLI not found. Install it?')} ${C.bold('[Y/n]: ')}`);
437
+ if (!installClaude || installClaude.toLowerCase() === 'y' || installClaude.toLowerCase() === 'yes') {
438
+ if (!installDep('Claude CLI', installClaudeCLI)) {
439
+ console.log(`\n ${WARN} ${C.yellow('Claude CLI installation failed. Run: npm i -g @anthropic-ai/claude-code')}`);
440
+ } else {
441
+ claudeOk = isCommandAvailable('claude');
442
+ }
443
+ }
444
+ }
445
+
446
+ // ── Step 2: API key prompt ───────────────────────────────────────────────
447
+ printStep(2, 'API Key Configuration');
448
+
449
+ printBox([
450
+ C.bold(' Enter your API key to get started.'),
451
+ '',
452
+
453
+ ]);
537
454
 
538
455
  let apiKey = '';
539
- while (!apiKey.trim()) {
540
- apiKey = await ask(rl, ` ${C.bold('API Key')}: `);
541
- if (!apiKey.trim()) {
456
+ let attempts = 0;
457
+ const maxAttempts = 3;
458
+ while (!apiKey.trim() && attempts < maxAttempts) {
459
+ if (attempts > 0) {
542
460
  console.log(` ${CROSS} ${C.red('API key cannot be empty. Please try again.')}`);
543
461
  }
462
+ apiKey = await ask(rl, ` ${C.bold('API Key')}: `);
463
+ attempts++;
544
464
  }
545
465
  apiKey = apiKey.trim();
546
- console.log('');
547
466
 
548
- // ── Configure system ──────────────────────────────────────────────────────
467
+ if (!apiKey) {
468
+ console.log(`\n ${CROSS} ${C.red('No API key provided. Run')} ${C.bold('npx claudmax')} ${C.red('to try again.')}`);
469
+ rl.close();
470
+ process.exit(1);
471
+ }
472
+
473
+ // Mask the displayed key
474
+ const maskedKey = apiKey.length > 8
475
+ ? apiKey.slice(0, 4) + '\u2022'.repeat(apiKey.length - 8) + apiKey.slice(-4)
476
+ : '\u2022'.repeat(apiKey.length);
477
+ console.log(` ${CHECK} ${C.green('Key received')} ${C.dim(maskedKey)}`);
478
+
479
+ // ── Step 3: Verify API key ───────────────────────────────────────────────
480
+ printStep(3, 'Validating Credentials');
481
+
482
+ process.stdout.write(` ${C.dim('Verifying...')} `);
483
+ const result = await verifyConnection(apiKey);
484
+
485
+ if (result.ok) {
486
+ if (result.status === 401) {
487
+ console.log(`\n ${CROSS} ${C.red('Invalid API key. Please check your key and try again.')}`);
488
+ console.log(` ${INFO} ${C.dim('Get a valid key at: https://claudmax.pro/admin/dashboard')}`);
489
+ rl.close();
490
+ process.exit(1);
491
+ } else {
492
+ const data = result.data;
493
+ const tier = (data.tier || 'free').toUpperCase();
494
+ const limit = data.requestsLimit?.toLocaleString() || 'N/A';
495
+ const tokenLimit = data.tokensLimit ? (data.tokensLimit >= 1e9 ? 'Unlimited' : (data.tokensLimit / 1e6).toFixed(0) + 'M tokens/5h') : 'N/A';
496
+ console.log(`\n ${CHECK} ${C.green('Authentication successful')}`);
497
+ console.log(` ${C.dim('Plan:')} ${C.magenta(tier)} ${C.dim('Requests:')} ${C.cyan(limit + '/5h')} ${C.dim('Tokens:')} ${C.cyan(tokenLimit)}`);
498
+ }
499
+ } else {
500
+ console.log(`\n ${WARN} ${C.yellow('Could not verify (network error). Continuing anyway...')}`);
501
+ console.log(` ${INFO} ${C.dim(result.error || 'Connection failed')}`);
502
+ }
503
+
504
+ // ── Step 4: Configure system ──────────────────────────────────────────────
505
+ printStep(4, 'System Configuration');
549
506
  configureSystem(apiKey);
550
507
 
551
- // ── Step 2: IDE selection ─────────────────────────────────────────────────
552
- console.log(C.bold('Step 2: Select IDEs to configure\n'));
508
+ // ── Step 5: IDE selection ─────────────────────────────────────────────────
509
+ printStep(5, 'IDE Configuration');
553
510
 
554
511
  const IDES = [
555
- { id: 1, name: 'Claude Code (CLI)', shortName: 'Claude Code', configure: configureClaudeCLI },
512
+ { id: 1, name: 'Claude Code CLI', shortName: 'Claude Code', configure: configureClaudeCLI },
556
513
  { id: 2, name: 'VS Code (Claude Extension)', shortName: 'VS Code', configure: configureVSCodeClaude },
557
- { id: 3, name: 'Cursor', shortName: 'Cursor', configure: configureCursor },
558
- { id: 4, name: 'Windsurf', shortName: 'Windsurf', configure: configureWindsurf },
514
+ { id: 3, name: 'Cursor', shortName: 'Cursor', configure: configureCursor },
515
+ { id: 4, name: 'Windsurf', shortName: 'Windsurf', configure: configureWindsurf },
559
516
  { id: 5, name: 'Cline (VS Code Extension)', shortName: 'Cline', configure: configureCline },
560
517
  { id: 6, name: 'Roo Code (VS Code Extension)', shortName: 'Roo Code', configure: configureRooCode },
561
518
  ];
562
519
 
563
520
  for (const ide of IDES) {
564
- console.log(` ${C.purple('[' + ide.id + ']')} ${ide.name}`);
521
+ console.log(` ${C.purple('[' + ide.id + ']')} ${ide.name}`);
565
522
  }
566
523
  console.log('');
567
- console.log(` ${C.dim("Enter numbers separated by spaces (e.g. 1 3 4), or " + C.bold("'a'") + " for all")}`);
524
+ console.log(` ${C.dim("Enter numbers separated by spaces (e.g. 1 3 4), " + C.bold("'a'") + " for all, or press Enter to skip")}`);
568
525
 
569
- const choice = await ask(rl, ` ${C.bold('Your choice')}: `);
526
+ const choice = await ask(rl, ` ${C.bold('Your choice')}: `);
570
527
  let selectedIds = [];
571
528
 
572
529
  if (choice.trim().toLowerCase() === 'a') {
@@ -575,66 +532,42 @@ async function main() {
575
532
  selectedIds = choice.trim().split(/[\s,]+/).map(Number).filter((n) => n >= 1 && n <= IDES.length);
576
533
  }
577
534
 
578
- console.log('');
579
-
580
- // ── Configure selected IDEs ──────────────────────────────────────────────
581
535
  if (selectedIds.length > 0) {
582
536
  const selectedIDEs = IDES.filter((ide) => selectedIds.includes(ide.id));
583
537
  for (const ide of selectedIDEs) {
584
538
  try {
585
539
  ide.configure(apiKey);
586
540
  } catch (err) {
587
- console.log(` ${CROSS} Failed to configure ${ide.name}: ${String(err && err.message ? err.message : err)}`);
541
+ console.log(` ${CROSS} ${C.red('Failed to configure')} ${ide.name}: ${err.message}`);
588
542
  }
589
543
  }
590
544
  } else {
591
- console.log(` ${WARN} ${C.yellow('No IDEs selected. Skipping IDE configuration.')}`);
545
+ console.log(` ${WARN} ${C.yellow('No IDEs selected. Configure them manually later with')} ${C.bold('claudmax configure')}`);
592
546
  }
593
547
 
594
- // ── Install MCP server ───────────────────────────────────────────────────
548
+ // ── Step 6: Install MCP server ───────────────────────────────────────────
549
+ printStep(6, 'MCP Server Setup');
595
550
  installMCPServer();
596
551
 
597
- // ── Verify connection ─────────────────────────────────────────────────────
598
- console.log(`\n${ARROW} ${C.bold('Verifying connection to ClaudMax API...')}`);
599
- const result = await verifyConnection(apiKey);
600
-
601
- if (result.ok) {
602
- const data = result.data;
603
- if (result.status === 401) {
604
- console.log(` ${CROSS} ${C.red('Invalid API key. Please check and try again.')}`);
605
- console.log(` ${INFO} ${C.dim(data.error || 'Authentication failed')}`);
606
- rl.close();
607
- process.exit(1);
608
- } else {
609
- console.log(` ${CHECK} ${C.green('Connected — API key is valid.')}`);
610
- const tier = (data.tier || 'free').toUpperCase();
611
- const limit = data.requestsLimit?.toLocaleString() || 'N/A';
612
- const tokenLimit = data.tokensLimit ? (data.tokensLimit >= 1e9 ? 'Unlimited' : (data.tokensLimit / 1e6).toFixed(0) + 'M tokens/5h') : 'N/A';
613
- console.log(` ${INFO} Plan: ${C.magenta(tier)} | Requests: ${C.cyan(limit)} | Tokens: ${C.cyan(tokenLimit)}`);
614
- }
615
- } else {
616
- console.log(` ${WARN} ${C.yellow('Could not verify API key (network error).')}`);
617
- console.log(` ${INFO} ${C.dim(result.error || 'Connection failed')}`);
618
- }
619
-
620
552
  // ── Summary ───────────────────────────────────────────────────────────────
621
553
  console.log('');
622
- console.log(C.magenta('\u2554' + '\u2550'.repeat(44) + '\u2557'));
623
- console.log(C.magenta('\u2551') + C.bold(' \u2713 Setup complete! ') + C.magenta('\u2551'));
624
- console.log(C.magenta('\u2551') + C.green(' Restart your IDE(s) to apply. ') + C.magenta('\u2551'));
625
- console.log(C.magenta('\u255A' + '\u2550'.repeat(44) + '\u255D'));
554
+ console.log(C.green(' \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510'));
555
+ console.log(C.green(' \u2502') + C.bold(' \u2726 Setup Complete! \u2726 ') + C.green('\u2502'));
556
+ console.log(C.green(' \u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534'));
557
+ console.log('');
558
+ console.log(` ${INFO} ${C.bold('Next steps:')}`);
559
+ console.log(` 1. ${C.dim('Restart your IDE(s) to apply settings.')}`);
560
+ console.log(` 2. ${C.dim('Test it:')} ${C.bold('claude --version')}`);
561
+ console.log(` 3. ${C.dim('Start chatting:')} ${C.bold('claude')}`);
562
+ console.log(` 4. ${C.dim('Check usage:')} ${C.bold('npx claudmax status')}`);
626
563
  console.log('');
627
- console.log(` ${INFO} ${C.bold('Next steps:')}`);
628
- console.log(` 1. ${C.dim('Restart your IDE(s) to apply.')}`);
629
- console.log(` 2. ${C.dim('Verify with:')} ${C.bold('claude --version')}`);
630
- console.log(` 3. ${C.dim('Start chatting:')} ${C.bold('claude')}`);
631
- console.log(` 4. ${C.dim('Check usage:')} ${C.bold('npx claudmax status')}`);
564
+ console.log(` ${INFO} Config saved at: ${C.magenta(CONFIG_FILE)}`);
632
565
  console.log('');
633
566
 
634
567
  rl.close();
635
568
  }
636
569
 
637
570
  main().catch((err) => {
638
- console.error('\n' + C.red('\u2717 Fatal error: ' + String(err.message || err)));
571
+ console.error('\n' + C.red('\u2717 Fatal error: ' + err.message));
639
572
  process.exit(1);
640
573
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudmax",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "description": "ClaudMax CLI — Configure Claude Code, Cursor, Windsurf, Cline, and Roo Code to use ClaudMax API gateway with one command",
5
5
  "main": "index.js",
6
6
  "bin": {