claudmax 1.0.15 → 1.0.18

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/bin/claudmax.js CHANGED
@@ -94,6 +94,8 @@ async function cmdConfigure() {
94
94
  printBanner();
95
95
  console.log(`${BOLD}Configure your ClaudMax API key${RESET}`);
96
96
  console.log('');
97
+ console.log(`${CYAN}Get Your API Key: https://www.claudmax.pro/support${RESET}`);
98
+ console.log('');
97
99
 
98
100
  const config = getConfig();
99
101
  if (config?.apiKey) {
Binary file
Binary file
package/index.js CHANGED
@@ -14,8 +14,6 @@ const MCP_PKG = 'claudmax-mcp';
14
14
  const API_BASE = 'https://api.claudmax.pro';
15
15
 
16
16
  const HOME = os.homedir();
17
- const CONFIG_DIR = path.join(HOME, '.claudmax');
18
- const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
19
17
 
20
18
  // ── Color helpers ─────────────────────────────────────────────────────────────
21
19
  const C = {
@@ -28,15 +26,12 @@ const C = {
28
26
  blue: (s) => `\x1b[34m${s}\x1b[0m`,
29
27
  magenta: (s) => `\x1b[35m${s}\x1b[0m`,
30
28
  cyan: (s) => `\x1b[36m${s}\x1b[0m`,
31
- white: (s) => `\x1b[37m${s}\x1b[0m`,
32
- purple: (s) => `\x1b[38;5;141m${s}\x1b[0m`,
33
29
  };
34
30
 
35
31
  const CHECK = C.green('\u2713');
36
32
  const CROSS = C.red('\u2717');
37
33
  const WARN = C.yellow('\u26A0');
38
34
  const INFO = C.cyan('\u2139');
39
- const ARROW = C.magenta('\u25b6');
40
35
 
41
36
  // ── Readline helper ────────────────────────────────────────────────────────────
42
37
  function createRL() {
@@ -75,99 +70,17 @@ function ensureDir(dir) {
75
70
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
76
71
  }
77
72
 
78
- // ── Version check helpers ─────────────────────────────────────────────────────
79
- function getCommandVersion(cmd) {
80
- try {
81
- const v = execSync(cmd + ' --version', { encoding: 'utf8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] });
82
- return v.trim().split('\n')[0];
83
- } catch { return null; }
84
- }
85
-
86
- function isCommandAvailable(cmd) {
87
- try {
88
- execSync(cmd + ' --version', { stdio: ['pipe', 'pipe', 'pipe'], timeout: 5000 });
89
- return true;
90
- } catch { return false; }
91
- }
92
-
93
- // ── Dependency installers ─────────────────────────────────────────────────────
94
- function installDep(label, installFn) {
95
- console.log(`\n${ARROW} ${C.bold('Installing ' + label + '...')}`);
96
- try {
97
- installFn();
98
- console.log(` ${CHECK} ${C.green(label + ' installed successfully.')}`);
99
- return true;
100
- } catch (err) {
101
- console.log(` ${CROSS} ${C.red('Failed to install ' + label + ': ' + (err.message || 'unknown error'))}`);
102
- return false;
103
- }
104
- }
105
-
106
- function installNode() {
107
- const platform = process.platform;
108
- let installCmd;
109
-
110
- if (platform === 'win32') {
111
- installCmd = 'winget install OpenJS.NodeJS.LTS';
112
- } else if (platform === 'darwin') {
113
- installCmd = 'brew install node';
114
- } else {
115
- // Linux
116
- if (isCommandAvailable('apt-get')) {
117
- execSync('curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - && sudo apt-get install -y nodejs', { stdio: 'inherit', timeout: 120000 });
118
- return;
119
- } else if (isCommandAvailable('yum')) {
120
- execSync('curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash - && sudo yum install -y nodejs', { stdio: 'inherit', timeout: 120000 });
121
- return;
122
- } else if (isCommandAvailable('pacman')) {
123
- execSync('sudo pacman -S nodejs npm', { stdio: 'inherit', timeout: 120000 });
124
- return;
125
- } else {
126
- throw new Error('No supported package manager found. Please install Node.js manually from https://nodejs.org');
127
- }
128
- return;
129
- }
130
-
131
- execSync(installCmd, { stdio: 'inherit', timeout: 120000 });
132
- }
133
-
134
- function installGit() {
135
- const platform = process.platform;
136
- if (platform === 'win32') {
137
- execSync('winget install Git.Git', { stdio: 'inherit', timeout: 120000 });
138
- } else if (platform === 'darwin') {
139
- execSync('brew install git', { stdio: 'inherit', timeout: 120000 });
140
- } else {
141
- if (isCommandAvailable('apt-get')) {
142
- execSync('sudo apt-get update && sudo apt-get install -y git', { stdio: 'inherit', timeout: 120000 });
143
- } else if (isCommandAvailable('yum')) {
144
- execSync('sudo yum install -y git', { stdio: 'inherit', timeout: 120000 });
145
- } else if (isCommandAvailable('pacman')) {
146
- execSync('sudo pacman -S git', { stdio: 'inherit', timeout: 120000 });
147
- }
148
- }
149
- }
150
-
151
- function installClaudeCLI() {
152
- const platform = process.platform;
153
- if (platform === 'win32') {
154
- execSync('npm install -g @anthropic-ai/claude-code', { stdio: 'inherit', timeout: 120000 });
155
- } else {
156
- execSync('npm install -g @anthropic-ai/claude-code', { stdio: 'inherit', timeout: 120000 });
157
- }
158
- }
159
-
160
- // ── HTTPS verification ────────────────────────────────────────────────────────
73
+ // ── API verification ────────────────────────────────────────────────────────
161
74
  function verifyConnection(apiKey) {
162
75
  return new Promise((resolve) => {
163
76
  const options = {
164
77
  hostname: API_BASE.replace('https://', ''),
165
78
  port: 443,
166
- path: '/v1/key-status',
79
+ path: '/api/v1/key-status',
167
80
  method: 'POST',
168
81
  headers: {
169
82
  'Content-Type': 'application/json',
170
- 'User-Agent': 'ClaudMax-CLI/1.0.0',
83
+ 'User-Agent': 'ClaudMax-CLI/1.0.18',
171
84
  },
172
85
  timeout: 15000,
173
86
  };
@@ -178,11 +91,7 @@ function verifyConnection(apiKey) {
178
91
  res.on('end', () => {
179
92
  try {
180
93
  const data = JSON.parse(body);
181
- if (res.statusCode === 200 || res.statusCode === 401) {
182
- resolve({ status: res.statusCode, data, ok: true });
183
- } else {
184
- resolve({ status: res.statusCode, error: body, ok: false });
185
- }
94
+ resolve({ status: res.statusCode, data, ok: true });
186
95
  } catch {
187
96
  resolve({ status: res.statusCode, error: body, ok: false });
188
97
  }
@@ -197,37 +106,21 @@ function verifyConnection(apiKey) {
197
106
  });
198
107
  }
199
108
 
200
- // ── System configuration ──────────────────────────────────────────────────────
201
- function configureSystem(apiKey) {
202
- console.log(` ${ARROW} ${C.bold('Saving configuration...')}`);
203
-
204
- // Save config file
205
- ensureDir(CONFIG_DIR);
206
- writeJson(CONFIG_FILE, {
207
- apiKey,
208
- baseUrl: API_BASE,
209
- configuredAt: new Date().toISOString(),
210
- version: '1.0.14',
211
- });
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.')}`);
214
- }
215
-
216
- // ── Claude Code CLI configuration ─────────────────────────────────────────────
109
+ // ── IDE configurators ────────────────────────────────────────────────────────
217
110
  function configureClaudeCLI(apiKey) {
218
- console.log(` ${ARROW} ${C.bold('Claude Code CLI...')}`);
111
+ process.stdout.write(` Configuring Claude Code (CLI)... `);
219
112
 
220
113
  const settingsPath = path.join(HOME, '.claude', 'settings.json');
221
114
  const dotClaudePath = path.join(HOME, '.claude.json');
222
115
 
223
116
  ensureDir(path.dirname(settingsPath));
224
117
 
225
- // settings.json
118
+ // settings.json — Claude Code reads ANTHROPIC_AUTH_TOKEN and ANTHROPIC_BASE_URL from here
226
119
  const settings = readJson(settingsPath) || {};
227
120
  deepMerge(settings, {
228
121
  env: {
229
122
  ANTHROPIC_AUTH_TOKEN: apiKey,
230
- ANTHROPIC_BASE_URL: `${API_BASE}`,
123
+ ANTHROPIC_BASE_URL: API_BASE + '/v1',
231
124
  ANTHROPIC_MODEL: 'Opus 4.6',
232
125
  ANTHROPIC_SMALL_FAST_MODEL: 'Haiku 4.5',
233
126
  ANTHROPIC_DEFAULT_SONNET_MODEL: 'Sonnet 4.5',
@@ -238,9 +131,10 @@ function configureClaudeCLI(apiKey) {
238
131
  hasCompletedOnboarding: true,
239
132
  });
240
133
  writeJson(settingsPath, settings);
241
- console.log(` ${CHECK} Claude Code settings ${C.dim('~/.claude/settings.json')}`);
134
+ process.stdout.write(`${CHECK} `);
135
+ process.stdout.write(`${C.dim(settingsPath + '\n')}`);
242
136
 
243
- // .claude.json (MCP servers)
137
+ // .claude.json MCP servers
244
138
  const dotClaude = readJson(dotClaudePath) || {};
245
139
  if (!dotClaude.mcpServers) dotClaude.mcpServers = {};
246
140
  dotClaude.mcpServers['ClaudMax'] = {
@@ -252,28 +146,11 @@ function configureClaudeCLI(apiKey) {
252
146
  },
253
147
  };
254
148
  writeJson(dotClaudePath, dotClaude);
255
- console.log(` ${CHECK} MCP server registered ${C.dim('~/.claude.json')}`);
256
- }
257
-
258
- // ── IDE configurators ────────────────────────────────────────────────────────
259
- function getVSCodeSettingsPath() {
260
- switch (process.platform) {
261
- case 'win32':
262
- return path.join(process.env.APPDATA || path.join(HOME, 'AppData', 'Roaming'), 'Code', 'User', 'settings.json');
263
- case 'darwin':
264
- return path.join(HOME, 'Library', 'Application Support', 'Code', 'User', 'settings.json');
265
- default:
266
- return path.join(HOME, '.config', 'Code', 'User', 'settings.json');
267
- }
268
- }
269
-
270
- function configureVSCodeClaude(apiKey) {
271
- configureClaudeCLI(apiKey);
272
- console.log(` ${INFO} Claude extension auto-detects Claude Code settings. ${C.dim('Restart VS Code after setup.')}`);
149
+ process.stdout.write(` ${CHECK} ${C.dim(dotClaudePath + '\n')}`);
273
150
  }
274
151
 
275
152
  function configureCursor(apiKey) {
276
- console.log(` ${ARROW} ${C.bold('Cursor...')}`);
153
+ process.stdout.write(` Configuring Cursor... `);
277
154
  const mcpPath = path.join(HOME, '.cursor', 'mcp.json');
278
155
  ensureDir(path.dirname(mcpPath));
279
156
  const existing = readJson(mcpPath) || {};
@@ -287,13 +164,11 @@ function configureCursor(apiKey) {
287
164
  },
288
165
  };
289
166
  writeJson(mcpPath, existing);
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('Anthropic Base URL: https://api.claudmax.pro')}`);
167
+ console.log(`${CHECK} ${C.dim(mcpPath)}`);
293
168
  }
294
169
 
295
170
  function configureWindsurf(apiKey) {
296
- console.log(` ${ARROW} ${C.bold('Windsurf...')}`);
171
+ process.stdout.write(` Configuring Windsurf... `);
297
172
  const mcpPath = path.join(HOME, '.windsurf', 'mcp.json');
298
173
  ensureDir(path.dirname(mcpPath));
299
174
  const existing = readJson(mcpPath) || {};
@@ -307,48 +182,57 @@ function configureWindsurf(apiKey) {
307
182
  },
308
183
  };
309
184
  writeJson(mcpPath, existing);
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')}`);
185
+ console.log(`${CHECK} ${C.dim(mcpPath)}`);
313
186
  }
314
187
 
315
188
  function configureCline(apiKey) {
316
- console.log(` ${ARROW} ${C.bold('Cline...')}`);
317
- const settingsPath = getVSCodeSettingsPath();
189
+ process.stdout.write(` Configuring Cline... `);
190
+ const settingsPath = path.join(HOME, 'Library', 'Application Support', 'Code', 'User', 'settings.json');
318
191
  ensureDir(path.dirname(settingsPath));
319
192
  const existing = readJson(settingsPath) || {};
320
193
  deepMerge(existing, {
321
194
  'cline.apiProvider': 'anthropic',
322
- 'cline.anthropicBaseUrl': API_BASE,
195
+ 'cline.anthropicBaseUrl': API_BASE + '/v1',
323
196
  'cline.apiKey': apiKey,
324
197
  });
325
198
  writeJson(settingsPath, existing);
326
- console.log(` ${CHECK} Cline configured ${C.dim(settingsPath.replace(HOME, '~'))}`);
199
+ console.log(`${CHECK} ${C.dim(settingsPath)}`);
327
200
  }
328
201
 
329
202
  function configureRooCode(apiKey) {
330
- console.log(` ${ARROW} ${C.bold('Roo Code...')}`);
331
- const settingsPath = getVSCodeSettingsPath();
203
+ process.stdout.write(` Configuring Roo Code... `);
204
+ const settingsPath = path.join(HOME, 'Library', 'Application Support', 'Code', 'User', 'settings.json');
332
205
  ensureDir(path.dirname(settingsPath));
333
206
  const existing = readJson(settingsPath) || {};
334
207
  deepMerge(existing, {
335
208
  'roo-cline.apiProvider': 'anthropic',
336
- 'roo-cline.anthropicBaseUrl': API_BASE,
209
+ 'roo-cline.anthropicBaseUrl': API_BASE + '/v1',
337
210
  'roo-cline.apiKey': apiKey,
338
211
  });
339
212
  writeJson(settingsPath, existing);
340
- console.log(` ${CHECK} Roo Code configured ${C.dim(settingsPath.replace(HOME, '~'))}`);
213
+ console.log(`${CHECK} ${C.dim(settingsPath)}`);
341
214
  }
342
215
 
343
- // ── MCP server install ───────────────────────────────────────────────────────
216
+ function configureVSCodeClaude(apiKey) {
217
+ configureClaudeCLI(apiKey);
218
+ console.log(` ${INFO} Claude extension auto-detects settings. Restart VS Code after setup.`);
219
+ }
220
+
221
+ // ── MCP server install ────────────────────────────────────────────────────────
344
222
  function installMCPServer() {
345
- console.log(` ${ARROW} ${C.bold('Installing MCP server...')}`);
223
+ process.stdout.write(` Installing ${MCP_PKG} globally... `);
346
224
  try {
347
- execSync('npm install -g ' + MCP_PKG, { stdio: 'pipe', timeout: 60000 });
348
- console.log(` ${CHECK} ${C.green('MCP server installed')}`);
225
+ execSync('npm install -g ' + MCP_PKG, { encoding: 'utf8', timeout: 60000 });
226
+ console.log(`${CHECK}`);
349
227
  return true;
350
228
  } catch (err) {
351
- console.log(` ${WARN} ${C.yellow('Could not install MCP server. Run manually:')} ${C.bold('npm install -g ' + MCP_PKG)}`);
229
+ const msg = err.message || '';
230
+ // Check if already installed
231
+ if (msg.includes('EACCES') || msg.includes('permission')) {
232
+ console.log(`${WARN} Permission denied — try: sudo npm install -g ${MCP_PKG}`);
233
+ } else {
234
+ console.log(`${WARN} npm install failed. Run manually: ${C.bold('npm install -g ' + MCP_PKG)}`);
235
+ }
352
236
  return false;
353
237
  }
354
238
  }
@@ -356,112 +240,19 @@ function installMCPServer() {
356
240
  // ── Banner ────────────────────────────────────────────────────────────────────
357
241
  function printBanner() {
358
242
  console.log('');
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(' ╚════════════════════════════════════════════════════════════════╝'));
365
- console.log('');
366
- }
367
-
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(' └─────────────────────────────────────────────────────────┘'));
374
- console.log('');
375
- }
376
-
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);
243
+ console.log(C.magenta(' ╔════════════════════════════════════════════════════════════╗'));
244
+ console.log(C.magenta(' ║') + C.bold(' ⚡ ClaudMax Setup ⚡ ') + C.magenta('║'));
245
+ console.log(C.magenta(' ╚════════════════════════════════════════════════════════════╝'));
388
246
  console.log('');
389
247
  }
390
248
 
391
249
  // ── Main ──────────────────────────────────────────────────────────────────────
392
250
  async function main() {
393
251
  const rl = createRL();
394
-
395
252
  printBanner();
396
253
 
397
- // ── Step 1: Check dependencies ─────────────────────────────────────────────
398
- printStep(1, 'System Dependencies');
399
-
400
- let nodeOk = isCommandAvailable('node');
401
- let gitOk = isCommandAvailable('git');
402
- let claudeOk = isCommandAvailable('claude');
403
-
404
- const deps = [
405
- { label: 'Node.js', ok: nodeOk, cmd: 'node --version' },
406
- { label: 'Git', ok: gitOk, cmd: 'git --version' },
407
- { label: 'Claude CLI', ok: claudeOk, cmd: 'claude --version' },
408
- ];
409
-
410
- for (const dep of deps) {
411
- if (dep.ok) {
412
- const version = getCommandVersion(dep.cmd);
413
- console.log(` ${CHECK} ${C.green(dep.label)} ${C.dim(version || '')}`);
414
- } else {
415
- console.log(` ${CROSS} ${C.red(dep.label)} ${C.dim('not found')}`);
416
- }
417
- }
418
-
419
- if (!nodeOk) {
420
- if (!installDep('Node.js', installNode)) {
421
- console.log(`\n ${CROSS} ${C.red('Node.js installation failed. Please install manually from https://nodejs.org')}`);
422
- } else {
423
- nodeOk = isCommandAvailable('node');
424
- }
425
- }
426
-
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
- ]);
454
-
455
- let apiKey = '';
456
- let attempts = 0;
457
- const maxAttempts = 3;
458
- while (!apiKey.trim() && attempts < maxAttempts) {
459
- if (attempts > 0) {
460
- console.log(` ${CROSS} ${C.red('API key cannot be empty. Please try again.')}`);
461
- }
462
- apiKey = await ask(rl, ` ${C.bold('API Key')}: `);
463
- attempts++;
464
- }
254
+ // ── API key ───────────────────────────────────────────────────────────────
255
+ let apiKey = await ask(rl, ` ${C.bold('Enter your ClaudMax API key')}: `);
465
256
  apiKey = apiKey.trim();
466
257
 
467
258
  if (!apiKey) {
@@ -470,46 +261,9 @@ async function main() {
470
261
  process.exit(1);
471
262
  }
472
263
 
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');
506
- configureSystem(apiKey);
507
-
508
- // ── Step 5: IDE selection ─────────────────────────────────────────────────
509
- printStep(5, 'IDE Configuration');
510
-
264
+ // ── IDE selection ────────────────────────────────────────────────────────
511
265
  const IDES = [
512
- { id: 1, name: 'Claude Code CLI', shortName: 'Claude Code', configure: configureClaudeCLI },
266
+ { id: 1, name: 'Claude Code (CLI)', shortName: 'Claude Code', configure: configureClaudeCLI },
513
267
  { id: 2, name: 'VS Code (Claude Extension)', shortName: 'VS Code', configure: configureVSCodeClaude },
514
268
  { id: 3, name: 'Cursor', shortName: 'Cursor', configure: configureCursor },
515
269
  { id: 4, name: 'Windsurf', shortName: 'Windsurf', configure: configureWindsurf },
@@ -517,13 +271,14 @@ async function main() {
517
271
  { id: 6, name: 'Roo Code (VS Code Extension)', shortName: 'Roo Code', configure: configureRooCode },
518
272
  ];
519
273
 
274
+ console.log('');
520
275
  for (const ide of IDES) {
521
- console.log(` ${C.purple('[' + ide.id + ']')} ${ide.name}`);
276
+ console.log(` ${C.magenta('[' + ide.id + ']')} ${ide.name}`);
522
277
  }
523
278
  console.log('');
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")}`);
279
+ console.log(` ${C.dim("Enter numbers separated by spaces, or 'a' for all:")}`);
525
280
 
526
- const choice = await ask(rl, ` ${C.bold('Your choice')}: `);
281
+ const choice = await ask(rl, ` ${C.bold('Your choice')}: `);
527
282
  let selectedIds = [];
528
283
 
529
284
  if (choice.trim().toLowerCase() === 'a') {
@@ -532,45 +287,54 @@ async function main() {
532
287
  selectedIds = choice.trim().split(/[\s,]+/).map(Number).filter((n) => n >= 1 && n <= IDES.length);
533
288
  }
534
289
 
290
+ console.log('');
291
+
292
+ // ── Configure IDEs ───────────────────────────────────────────────────────
535
293
  if (selectedIds.length > 0) {
536
294
  const selectedIDEs = IDES.filter((ide) => selectedIds.includes(ide.id));
537
295
  for (const ide of selectedIDEs) {
538
296
  try {
539
297
  ide.configure(apiKey);
540
298
  } catch (err) {
541
- console.log(` ${CROSS} ${C.red('Failed to configure')} ${ide.name}: ${err.message}`);
299
+ console.log(` ${CROSS} ${C.red('Failed to configure')} ${ide.name}: ${err.message}`);
542
300
  }
543
301
  }
302
+ console.log('');
544
303
  } else {
545
- console.log(` ${WARN} ${C.yellow('No IDEs selected. Configure them manually later with')} ${C.bold('claudmax configure')}`);
304
+ console.log(` ${WARN} ${C.yellow('No IDEs selected skipping configuration.')}`);
305
+ console.log('');
546
306
  }
547
307
 
548
- // ── Step 6: Install MCP server ───────────────────────────────────────────
549
- printStep(6, 'MCP Server Setup');
308
+ // ── Install MCP server ───────────────────────────────────────────────────
550
309
  installMCPServer();
551
-
552
- // ── Summary ───────────────────────────────────────────────────────────────
553
310
  console.log('');
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')}`);
311
+
312
+ // ── Verify API key ───────────────────────────────────────────────────────
313
+ process.stdout.write(` Verifying connection to ClaudMax API... `);
314
+ const result = await verifyConnection(apiKey);
315
+
316
+ if (result.ok && result.status === 200) {
317
+ console.log(`${CHECK} ${C.green('API key is valid.')}`);
318
+ } else if (result.ok && result.status === 401) {
319
+ console.log(`${CROSS} ${C.red('Invalid API key.')}`);
320
+ rl.close();
321
+ process.exit(1);
322
+ } else {
323
+ console.log(`${WARN} ${C.yellow('Could not verify — check your network.')}`);
324
+ }
325
+
326
+ // ── Summary ──────────────────────────────────────────────────────────────
563
327
  console.log('');
564
- console.log(` ${INFO} Config saved at: ${C.magenta(CONFIG_FILE)}`);
328
+ console.log(C.magenta(' ╔════════════════════════════════════════════════════════════╗'));
329
+ console.log(C.magenta(' ║') + C.green(' ✓ Setup complete! ') + C.magenta('║'));
330
+ console.log(C.magenta(' ║') + C.dim(' Restart your IDE(s) to apply. ') + C.magenta('║'));
331
+ console.log(C.magenta(' ╚════════════════════════════════════════════════════════════╝'));
565
332
  console.log('');
566
333
 
567
334
  rl.close();
568
335
  }
569
336
 
570
337
  main().catch((err) => {
571
- const msg = err && typeof err === 'object'
572
- ? (String(err.stderr || err.message || err).trim())
573
- : String(err);
574
- console.error('\n' + C.red('\u2717 Fatal error: ' + msg));
338
+ console.error('\n' + C.red('\u2717 Fatal error: ' + (err && err.message ? err.message : err)));
575
339
  process.exit(1);
576
340
  });
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "claudmax",
3
- "version": "1.0.15",
3
+ "version": "1.0.18",
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": {
7
- "claudmax": "./bin/claudmax.js"
7
+ "claudmax": "./index.js"
8
8
  },
9
9
  "scripts": {
10
10
  "start": "node ./index.js"
@@ -30,4 +30,4 @@
30
30
  "node": ">=16.0.0"
31
31
  },
32
32
  "preferGlobal": true
33
- }
33
+ }