claudmax 1.0.10 → 1.0.13

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 +154 -220
  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,47 +199,46 @@ 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.9',
210
+ version: '1.0.2',
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
- ANTHROPIC_BASE_URL: `${API_BASE}/v1/messages`,
230
+ ANTHROPIC_BASE_URL: `${API_BASE}`,
257
231
  ANTHROPIC_MODEL: 'Opus 4.6',
258
232
  ANTHROPIC_SMALL_FAST_MODEL: 'Haiku 4.5',
259
233
  ANTHROPIC_DEFAULT_SONNET_MODEL: 'Sonnet 4.5',
260
234
  ANTHROPIC_DEFAULT_OPUS_MODEL: 'Opus 4.6',
261
235
  ANTHROPIC_DEFAULT_HAIKU_MODEL: 'Haiku 4.5',
236
+ CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1',
262
237
  },
263
238
  hasCompletedOnboarding: true,
264
239
  });
265
240
  writeJson(settingsPath, settings);
266
- console.log(` ${CHECK} Wrote Claude Code settings: ${C.magenta(settingsPath)}`);
241
+ console.log(` ${CHECK} Claude Code settings ${C.dim('~/.claude/settings.json')}`);
267
242
 
268
243
  // .claude.json (MCP servers)
269
244
  const dotClaude = readJson(dotClaudePath) || {};
@@ -277,7 +252,7 @@ function configureClaudeCLI(apiKey) {
277
252
  },
278
253
  };
279
254
  writeJson(dotClaudePath, dotClaude);
280
- console.log(` ${CHECK} Registered ClaudMax MCP server: ${C.magenta(dotClaudePath)}`);
255
+ console.log(` ${CHECK} MCP server registered ${C.dim('~/.claude.json')}`);
281
256
  }
282
257
 
283
258
  // ── IDE configurators ────────────────────────────────────────────────────────
@@ -293,14 +268,12 @@ function getVSCodeSettingsPath() {
293
268
  }
294
269
 
295
270
  function configureVSCodeClaude(apiKey) {
296
- console.log(`\n${ARROW} ${C.bold('Configuring VS Code Claude Extension...')}`);
297
271
  configureClaudeCLI(apiKey);
298
- 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.')}`);
299
273
  }
300
274
 
301
275
  function configureCursor(apiKey) {
302
- console.log(`\n${ARROW} ${C.bold('Configuring Cursor...')}`);
303
-
276
+ console.log(` ${ARROW} ${C.bold('Cursor...')}`);
304
277
  const mcpPath = path.join(HOME, '.cursor', 'mcp.json');
305
278
  ensureDir(path.dirname(mcpPath));
306
279
  const existing = readJson(mcpPath) || {};
@@ -314,14 +287,13 @@ function configureCursor(apiKey) {
314
287
  },
315
288
  };
316
289
  writeJson(mcpPath, existing);
317
- console.log(` ${CHECK} Wrote Cursor MCP config: ${C.magenta(mcpPath)}`);
318
- console.log(` ${INFO} Set base URL in Cursor: Settings > Models > Add custom model`);
319
- 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')}`);
320
293
  }
321
294
 
322
295
  function configureWindsurf(apiKey) {
323
- console.log(`\n${ARROW} ${C.bold('Configuring Windsurf...')}`);
324
-
296
+ console.log(` ${ARROW} ${C.bold('Windsurf...')}`);
325
297
  const mcpPath = path.join(HOME, '.windsurf', 'mcp.json');
326
298
  ensureDir(path.dirname(mcpPath));
327
299
  const existing = readJson(mcpPath) || {};
@@ -335,13 +307,13 @@ function configureWindsurf(apiKey) {
335
307
  },
336
308
  };
337
309
  writeJson(mcpPath, existing);
338
- console.log(` ${CHECK} Wrote Windsurf MCP config: ${C.magenta(mcpPath)}`);
339
- console.log(` ${INFO} Set base URL in Windsurf: Settings > AI Provider`);
340
- 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')}`);
341
313
  }
342
314
 
343
315
  function configureCline(apiKey) {
344
- console.log(`\n${ARROW} ${C.bold('Configuring Cline (VS Code)...')}`);
316
+ console.log(` ${ARROW} ${C.bold('Cline...')}`);
345
317
  const settingsPath = getVSCodeSettingsPath();
346
318
  ensureDir(path.dirname(settingsPath));
347
319
  const existing = readJson(settingsPath) || {};
@@ -351,11 +323,11 @@ function configureCline(apiKey) {
351
323
  'cline.apiKey': apiKey,
352
324
  });
353
325
  writeJson(settingsPath, existing);
354
- console.log(` ${CHECK} Wrote Cline settings: ${C.magenta(settingsPath)}`);
326
+ console.log(` ${CHECK} Cline configured ${C.dim(settingsPath.replace(HOME, '~'))}`);
355
327
  }
356
328
 
357
329
  function configureRooCode(apiKey) {
358
- console.log(`\n${ARROW} ${C.bold('Configuring Roo Code (VS Code)...')}`);
330
+ console.log(` ${ARROW} ${C.bold('Roo Code...')}`);
359
331
  const settingsPath = getVSCodeSettingsPath();
360
332
  ensureDir(path.dirname(settingsPath));
361
333
  const existing = readJson(settingsPath) || {};
@@ -365,20 +337,18 @@ function configureRooCode(apiKey) {
365
337
  'roo-cline.apiKey': apiKey,
366
338
  });
367
339
  writeJson(settingsPath, existing);
368
- console.log(` ${CHECK} Wrote Roo Code settings: ${C.magenta(settingsPath)}`);
340
+ console.log(` ${CHECK} Roo Code configured ${C.dim(settingsPath.replace(HOME, '~'))}`);
369
341
  }
370
342
 
371
343
  // ── MCP server install ───────────────────────────────────────────────────────
372
344
  function installMCPServer() {
373
- console.log(`\n${ARROW} ${C.bold('Installing ClaudMax MCP server globally...')}`);
345
+ console.log(` ${ARROW} ${C.bold('Installing MCP server...')}`);
374
346
  try {
375
347
  execSync('npm install -g ' + MCP_PKG, { stdio: 'pipe', timeout: 60000 });
376
- console.log(` ${CHECK} ${C.green(MCP_PKG + ' installed successfully.')}`);
348
+ console.log(` ${CHECK} ${C.green('MCP server installed')}`);
377
349
  return true;
378
350
  } catch (err) {
379
- const errMsg = String(err.stderr || err.message || '');
380
- console.log(` ${WARN} Could not install ${MCP_PKG}: ${C.dim(String(errMsg).trim())}`);
381
- 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)}`);
382
352
  return false;
383
353
  }
384
354
  }
@@ -386,122 +356,46 @@ function installMCPServer() {
386
356
  // ── Banner ────────────────────────────────────────────────────────────────────
387
357
  function printBanner() {
388
358
  console.log('');
389
- console.log(C.magenta('\u2554' + '\u2550'.repeat(44) + '\u2557'));
390
- console.log(C.magenta('\u2551') + C.bold(' \u26A1 ClaudMax Setup ') + C.magenta('\u2551'));
391
- 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(' ╚════════════════════════════════════════════════════════════════╝'));
392
365
  console.log('');
393
366
  }
394
367
 
395
- // ── CLI argument parsing ────────────────────────────────────────────────────────
396
- const args = process.argv.slice(2);
397
- const command = args[0];
398
-
399
- // ── Status command ─────────────────────────────────────────────────────────────
400
- async function showStatus() {
401
- const config = readJson(CONFIG_FILE);
402
- if (!config || !config.apiKey) {
403
- console.log(`\n${WARN} No API key configured. Run ${C.bold('npx claudmax')} first.\n`);
404
- process.exit(1);
405
- }
406
-
407
- console.log(`\n${C.magenta('\u2554' + '\u2550'.repeat(48) + '\u2557')}`);
408
- console.log(C.magenta('\u2551') + C.bold(' \u2726 ClaudMax Status \u2726 ') + C.magenta('\u2551'));
409
- 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(' └─────────────────────────────────────────────────────────┘'));
410
374
  console.log('');
411
-
412
- // Fetch key status
413
- const body = JSON.stringify({ apiKey: config.apiKey });
414
- const postData = Buffer.from(body);
415
-
416
- const options = {
417
- hostname: 'api.claudmax.pro',
418
- port: 443,
419
- path: '/v1/key-status',
420
- method: 'POST',
421
- headers: {
422
- 'Content-Type': 'application/json',
423
- 'Content-Length': postData.length,
424
- 'User-Agent': 'ClaudMax-CLI/1.0.0',
425
- },
426
- timeout: 15000,
427
- };
428
-
429
- return new Promise((resolve) => {
430
- const req = https.request(options, (res) => {
431
- let data = '';
432
- res.on('data', (chunk) => { data += chunk; });
433
- res.on('end', () => {
434
- try {
435
- const json = JSON.parse(data);
436
- if (res.statusCode === 200) {
437
- const pct = json.tokensLimit > 0 ? Math.min(100, (json.tokensUsed / json.tokensLimit) * 100) : 0;
438
- const tierColors = { free: C.dim('Gray'), '5x': C.cyan('Blue'), '20x': C.magenta('Purple'), unlimited: C.green('Gold') };
439
- console.log(` ${CHECK} ${C.green('API Key is active')}`);
440
- console.log(` ${INFO} Name: ${C.bold(json.name || 'ClaudMax Key')}`);
441
- console.log(` ${INFO} Prefix: ${C.magenta(json.prefix)}••••••`);
442
- console.log(` ${INFO} Tier: ${tierColors[json.tier] || C.dim('Free')} (${C.bold(json.tier?.toUpperCase() || 'FREE')})`);
443
- console.log(` ${INFO} Status: ${json.isActive ? C.green('Active') : C.red('Inactive')}`);
444
- console.log('');
445
- console.log(` ${C.bold('Usage (5h window):')}`);
446
- const barLen = 30;
447
- const filled = Math.round((pct / 100) * barLen);
448
- const bar = C.purple('\u2588'.repeat(filled)) + C.dim('\u2591'.repeat(barLen - filled));
449
- console.log(` ${bar} ${C.dim(`${pct.toFixed(1)}%`)}`);
450
- console.log(` ${INFO} Requests: ${C.cyan(json.requestsUsed?.toLocaleString() || 0)} / ${C.cyan(json.requestsLimit?.toLocaleString() || 'N/A')}`);
451
- console.log(` ${INFO} Tokens: ${C.cyan((json.tokensUsed || 0).toLocaleString())} / ${C.cyan((json.tokensLimit || 0).toLocaleString())}`);
452
- console.log('');
453
- if (json.windowResetAt) {
454
- const reset = new Date(json.windowResetAt);
455
- console.log(` ${INFO} Resets: ${C.dim(reset.toLocaleString())}`);
456
- }
457
- } else {
458
- console.log(` ${CROSS} ${C.red('Failed to fetch status: ' + (json.error || `HTTP ${res.statusCode}`))}`);
459
- }
460
- } catch {
461
- console.log(` ${CROSS} ${C.red('Failed to parse response')}`);
462
- }
463
- console.log('');
464
- resolve();
465
- });
466
- });
467
- req.on('error', (err) => {
468
- console.log(` ${WARN} ${C.yellow('Network error: ' + err.message)}`);
469
- console.log('');
470
- resolve();
471
- });
472
- req.on('timeout', () => { req.destroy(); console.log(` ${CROSS} ${C.red('Request timed out')}\n`); resolve(); });
473
- req.write(postData);
474
- req.end();
475
- });
476
375
  }
477
376
 
478
- // ── Help ───────────────────────────────────────────────────────────────────────
479
- function showHelp() {
480
- console.log(`\n${C.bold('ClaudMax CLI')} — Configure Claude Code and other IDEs to use ClaudMax API.\n`);
481
- console.log(` ${C.cyan('npx claudmax')} ${C.dim('Launch the interactive setup wizard')}`);
482
- console.log(` ${C.cyan('npx claudmax status')} ${C.dim('Check your API key usage and limits')}`);
483
- 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);
484
388
  console.log('');
485
389
  }
486
390
 
487
391
  // ── Main ──────────────────────────────────────────────────────────────────────
488
392
  async function main() {
489
- if (command === 'status') {
490
- await showStatus();
491
- return;
492
- }
493
- if (command === '--help' || command === '-h') {
494
- showHelp();
495
- return;
496
- }
497
-
498
- // Default: interactive setup wizard
499
393
  const rl = createRL();
500
394
 
501
395
  printBanner();
502
396
 
503
397
  // ── Step 1: Check dependencies ─────────────────────────────────────────────
504
- console.log(C.bold('Step 1: Checking system dependencies...\n'));
398
+ printStep(1, 'System Dependencies');
505
399
 
506
400
  let nodeOk = isCommandAvailable('node');
507
401
  let gitOk = isCommandAvailable('git');
@@ -516,56 +410,120 @@ async function main() {
516
410
  for (const dep of deps) {
517
411
  if (dep.ok) {
518
412
  const version = getCommandVersion(dep.cmd);
519
- console.log(` ${CHECK} ${C.green(dep.label)} ${C.dim(version || '')}`);
413
+ console.log(` ${CHECK} ${C.green(dep.label)} ${C.dim(version || '')}`);
520
414
  } else {
521
- console.log(` ${CROSS} ${C.red(dep.label)} ${C.dim('not found')}`);
415
+ console.log(` ${CROSS} ${C.red(dep.label)} ${C.dim('not found')}`);
522
416
  }
523
417
  }
524
418
 
525
- // Install missing deps
526
419
  if (!nodeOk) {
527
420
  if (!installDep('Node.js', installNode)) {
528
- 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')}`);
529
422
  } else {
530
423
  nodeOk = isCommandAvailable('node');
531
424
  }
532
425
  }
533
426
 
534
- // ── Step 1: API key prompt ───────────────────────────────────────────────
535
- 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
+ ]);
536
454
 
537
455
  let apiKey = '';
538
- while (!apiKey.trim()) {
539
- apiKey = await ask(rl, ` ${C.bold('API Key')}: `);
540
- if (!apiKey.trim()) {
456
+ let attempts = 0;
457
+ const maxAttempts = 3;
458
+ while (!apiKey.trim() && attempts < maxAttempts) {
459
+ if (attempts > 0) {
541
460
  console.log(` ${CROSS} ${C.red('API key cannot be empty. Please try again.')}`);
542
461
  }
462
+ apiKey = await ask(rl, ` ${C.bold('API Key')}: `);
463
+ attempts++;
543
464
  }
544
465
  apiKey = apiKey.trim();
545
- console.log('');
546
466
 
547
- // ── 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');
548
506
  configureSystem(apiKey);
549
507
 
550
- // ── Step 2: IDE selection ─────────────────────────────────────────────────
551
- console.log(C.bold('Step 2: Select IDEs to configure\n'));
508
+ // ── Step 5: IDE selection ─────────────────────────────────────────────────
509
+ printStep(5, 'IDE Configuration');
552
510
 
553
511
  const IDES = [
554
- { id: 1, name: 'Claude Code (CLI)', shortName: 'Claude Code', configure: configureClaudeCLI },
512
+ { id: 1, name: 'Claude Code CLI', shortName: 'Claude Code', configure: configureClaudeCLI },
555
513
  { id: 2, name: 'VS Code (Claude Extension)', shortName: 'VS Code', configure: configureVSCodeClaude },
556
- { id: 3, name: 'Cursor', shortName: 'Cursor', configure: configureCursor },
557
- { 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 },
558
516
  { id: 5, name: 'Cline (VS Code Extension)', shortName: 'Cline', configure: configureCline },
559
517
  { id: 6, name: 'Roo Code (VS Code Extension)', shortName: 'Roo Code', configure: configureRooCode },
560
518
  ];
561
519
 
562
520
  for (const ide of IDES) {
563
- console.log(` ${C.purple('[' + ide.id + ']')} ${ide.name}`);
521
+ console.log(` ${C.purple('[' + ide.id + ']')} ${ide.name}`);
564
522
  }
565
523
  console.log('');
566
- 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")}`);
567
525
 
568
- const choice = await ask(rl, ` ${C.bold('Your choice')}: `);
526
+ const choice = await ask(rl, ` ${C.bold('Your choice')}: `);
569
527
  let selectedIds = [];
570
528
 
571
529
  if (choice.trim().toLowerCase() === 'a') {
@@ -574,66 +532,42 @@ async function main() {
574
532
  selectedIds = choice.trim().split(/[\s,]+/).map(Number).filter((n) => n >= 1 && n <= IDES.length);
575
533
  }
576
534
 
577
- console.log('');
578
-
579
- // ── Configure selected IDEs ──────────────────────────────────────────────
580
535
  if (selectedIds.length > 0) {
581
536
  const selectedIDEs = IDES.filter((ide) => selectedIds.includes(ide.id));
582
537
  for (const ide of selectedIDEs) {
583
538
  try {
584
539
  ide.configure(apiKey);
585
540
  } catch (err) {
586
- 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}`);
587
542
  }
588
543
  }
589
544
  } else {
590
- 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')}`);
591
546
  }
592
547
 
593
- // ── Install MCP server ───────────────────────────────────────────────────
548
+ // ── Step 6: Install MCP server ───────────────────────────────────────────
549
+ printStep(6, 'MCP Server Setup');
594
550
  installMCPServer();
595
551
 
596
- // ── Verify connection ─────────────────────────────────────────────────────
597
- console.log(`\n${ARROW} ${C.bold('Verifying connection to ClaudMax API...')}`);
598
- const result = await verifyConnection(apiKey);
599
-
600
- if (result.ok) {
601
- const data = result.data;
602
- if (result.status === 401) {
603
- console.log(` ${CROSS} ${C.red('Invalid API key. Please check and try again.')}`);
604
- console.log(` ${INFO} ${C.dim(data.error || 'Authentication failed')}`);
605
- rl.close();
606
- process.exit(1);
607
- } else {
608
- console.log(` ${CHECK} ${C.green('Connected — API key is valid.')}`);
609
- const tier = (data.tier || 'free').toUpperCase();
610
- const limit = data.requestsLimit?.toLocaleString() || 'N/A';
611
- const tokenLimit = data.tokensLimit ? (data.tokensLimit >= 1e9 ? 'Unlimited' : (data.tokensLimit / 1e6).toFixed(0) + 'M tokens/5h') : 'N/A';
612
- console.log(` ${INFO} Plan: ${C.magenta(tier)} | Requests: ${C.cyan(limit)} | Tokens: ${C.cyan(tokenLimit)}`);
613
- }
614
- } else {
615
- console.log(` ${WARN} ${C.yellow('Could not verify API key (network error).')}`);
616
- console.log(` ${INFO} ${C.dim(result.error || 'Connection failed')}`);
617
- }
618
-
619
552
  // ── Summary ───────────────────────────────────────────────────────────────
620
553
  console.log('');
621
- console.log(C.magenta('\u2554' + '\u2550'.repeat(44) + '\u2557'));
622
- console.log(C.magenta('\u2551') + C.bold(' \u2713 Setup complete! ') + C.magenta('\u2551'));
623
- console.log(C.magenta('\u2551') + C.green(' Restart your IDE(s) to apply. ') + C.magenta('\u2551'));
624
- 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')}`);
625
563
  console.log('');
626
- console.log(` ${INFO} ${C.bold('Next steps:')}`);
627
- console.log(` 1. ${C.dim('Restart your IDE(s) to apply.')}`);
628
- console.log(` 2. ${C.dim('Verify with:')} ${C.bold('claude --version')}`);
629
- console.log(` 3. ${C.dim('Start chatting:')} ${C.bold('claude')}`);
630
- console.log(` 4. ${C.dim('Check usage:')} ${C.bold('npx claudmax status')}`);
564
+ console.log(` ${INFO} Config saved at: ${C.magenta(CONFIG_FILE)}`);
631
565
  console.log('');
632
566
 
633
567
  rl.close();
634
568
  }
635
569
 
636
570
  main().catch((err) => {
637
- console.error('\n' + C.red('\u2717 Fatal error: ' + String(err.message || err)));
571
+ console.error('\n' + C.red('\u2717 Fatal error: ' + err.message));
638
572
  process.exit(1);
639
573
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudmax",
3
- "version": "1.0.10",
3
+ "version": "1.0.13",
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": {