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.
- package/index.js +154 -220
- 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
|
|
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:
|
|
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(
|
|
202
|
+
console.log(` ${ARROW} ${C.bold('Saving configuration...')}`);
|
|
227
203
|
|
|
228
|
-
//
|
|
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.
|
|
210
|
+
version: '1.0.2',
|
|
235
211
|
});
|
|
236
|
-
console.log(`
|
|
237
|
-
console.log(`
|
|
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(
|
|
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
|
|
252
|
-
const
|
|
253
|
-
|
|
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}
|
|
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(`
|
|
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(`
|
|
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(`
|
|
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(
|
|
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(`
|
|
318
|
-
console.log(`
|
|
319
|
-
console.log(`
|
|
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(
|
|
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(`
|
|
339
|
-
console.log(`
|
|
340
|
-
console.log(`
|
|
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(
|
|
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(`
|
|
326
|
+
console.log(` ${CHECK} Cline configured ${C.dim(settingsPath.replace(HOME, '~'))}`);
|
|
355
327
|
}
|
|
356
328
|
|
|
357
329
|
function configureRooCode(apiKey) {
|
|
358
|
-
console.log(
|
|
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(`
|
|
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(
|
|
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(`
|
|
348
|
+
console.log(` ${CHECK} ${C.green('MCP server installed')}`);
|
|
377
349
|
return true;
|
|
378
350
|
} catch (err) {
|
|
379
|
-
|
|
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.
|
|
390
|
-
console.log(C.
|
|
391
|
-
console.log(C.
|
|
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
|
-
// ──
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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
|
-
// ──
|
|
479
|
-
function
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
console.log(
|
|
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
|
-
|
|
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(`
|
|
413
|
+
console.log(` ${CHECK} ${C.green(dep.label)} ${C.dim(version || '')}`);
|
|
520
414
|
} else {
|
|
521
|
-
console.log(`
|
|
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
|
-
|
|
535
|
-
|
|
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
|
-
|
|
539
|
-
|
|
540
|
-
|
|
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
|
-
|
|
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
|
|
551
|
-
|
|
508
|
+
// ── Step 5: IDE selection ─────────────────────────────────────────────────
|
|
509
|
+
printStep(5, 'IDE Configuration');
|
|
552
510
|
|
|
553
511
|
const IDES = [
|
|
554
|
-
{ id: 1, name: 'Claude Code
|
|
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',
|
|
557
|
-
{ id: 4, name: 'Windsurf',
|
|
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(`
|
|
521
|
+
console.log(` ${C.purple('[' + ide.id + ']')} ${ide.name}`);
|
|
564
522
|
}
|
|
565
523
|
console.log('');
|
|
566
|
-
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")}`);
|
|
567
525
|
|
|
568
|
-
const choice = await ask(rl, `
|
|
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(`
|
|
541
|
+
console.log(` ${CROSS} ${C.red('Failed to configure')} ${ide.name}: ${err.message}`);
|
|
587
542
|
}
|
|
588
543
|
}
|
|
589
544
|
} else {
|
|
590
|
-
console.log(`
|
|
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.
|
|
622
|
-
console.log(C.
|
|
623
|
-
console.log(C.
|
|
624
|
-
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')}`);
|
|
625
563
|
console.log('');
|
|
626
|
-
console.log(`
|
|
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: ' +
|
|
571
|
+
console.error('\n' + C.red('\u2717 Fatal error: ' + err.message));
|
|
638
572
|
process.exit(1);
|
|
639
573
|
});
|
package/package.json
CHANGED