claudmax 3.4.2 → 3.4.4

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 +182 -125
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -13,6 +13,7 @@ const C = {
13
13
  bold: (s) => `\x1b[1m${s}\x1b[0m`,
14
14
  yellow: (s) => `\x1b[33m${s}\x1b[0m`,
15
15
  red: (s) => `\x1b[31m${s}\x1b[0m`,
16
+ green: (s) => `\x1b[32m${s}\x1b[0m`,
16
17
  reset: '\x1b[0m',
17
18
  };
18
19
 
@@ -25,7 +26,81 @@ const BANNER_SIDE = C.magenta('\u2551');
25
26
  const MCP_PKG = 'claudmax-mcp';
26
27
  const API_BASE = 'https://api.claudmax.pro';
27
28
  const HOME = os.homedir();
28
- const VERSION = '3.4.1';
29
+ const VERSION = '3.4.4';
30
+
31
+ // ── Helpers ────────────────────────────────────────────────────────────────────
32
+ function readJson(filePath) {
33
+ try { return JSON.parse(fs.readFileSync(filePath, 'utf8')); }
34
+ catch { return null; }
35
+ }
36
+
37
+ function writeJson(filePath, data) {
38
+ const dir = path.dirname(filePath);
39
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
40
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n');
41
+ }
42
+
43
+ function deepMerge(target, source) {
44
+ for (const key of Object.keys(source)) {
45
+ if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
46
+ if (!target[key]) target[key] = {};
47
+ deepMerge(target[key], source[key]);
48
+ } else {
49
+ target[key] = source[key];
50
+ }
51
+ }
52
+ return target;
53
+ }
54
+
55
+ function removeKeys(obj, keys) {
56
+ for (const k of keys) delete obj[k];
57
+ }
58
+
59
+ function getVSCodeSettingsPath() {
60
+ switch (process.platform) {
61
+ case 'win32':
62
+ return path.join(process.env.APPDATA || path.join(HOME, 'AppData', 'Roaming'), 'Code', 'User', 'settings.json');
63
+ case 'darwin':
64
+ return path.join(HOME, 'Library', 'Application Support', 'Code', 'User', 'settings.json');
65
+ default:
66
+ return path.join(HOME, '.config', 'Code', 'User', 'settings.json');
67
+ }
68
+ }
69
+
70
+ // ── Clean all proxy artifacts ─────────────────────────────────────────────────
71
+ const ALL_PROXY_KEYS = [
72
+ 'ANTHROPIC_AUTH_TOKEN', 'ANTHROPIC_API_KEY', 'ANTHROPIC_BASE_URL',
73
+ 'ANTHROPIC_MODEL', 'ANTHROPIC_SMALL_FAST_MODEL',
74
+ 'ANTHROPIC_DEFAULT_SONNET_MODEL', 'ANTHROPIC_DEFAULT_OPUS_MODEL',
75
+ 'ANTHROPIC_DEFAULT_HAIKU_MODEL', 'CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC',
76
+ 'OPUSMAX_API_KEY', 'OPUSMAX_URL',
77
+ ];
78
+
79
+ function cleanAllProxyConfig() {
80
+ const settingsPath = path.join(HOME, '.claude', 'settings.json');
81
+ const dotClaudePath = path.join(HOME, '.claude.json');
82
+ const backupFile = path.join(HOME, '.claudmax', '.backup.json');
83
+
84
+ // Clean settings.json env
85
+ const settings = readJson(settingsPath);
86
+ if (settings && settings.env) {
87
+ removeKeys(settings.env, ALL_PROXY_KEYS);
88
+ if (Object.keys(settings.env).length === 0) delete settings.env;
89
+ writeJson(settingsPath, settings);
90
+ }
91
+
92
+ // Clean .claude.json mcpServers
93
+ const dotClaude = readJson(dotClaudePath);
94
+ if (dotClaude && dotClaude.mcpServers) {
95
+ delete dotClaude.mcpServers['ClaudMax'];
96
+ delete dotClaude.mcpServers['OpusMax'];
97
+ if (Object.keys(dotClaude.mcpServers).length === 0) delete dotClaude.mcpServers;
98
+ writeJson(dotClaudePath, dotClaude);
99
+ }
100
+
101
+ // Delete backup (may have OpusMax keys)
102
+ try { fs.unlinkSync(backupFile); } catch { /* ignore */ }
103
+ }
29
104
 
30
105
  // ── Args ──────────────────────────────────────────────────────────────────────
31
106
  const args = process.argv.slice(2);
@@ -36,7 +111,7 @@ for (let i = 0; i < args.length; i++) {
36
111
  }
37
112
  }
38
113
 
39
- // ── Help / Version / Uninstall ─────────────────────────────────────────────────
114
+ // ── Help / Version ──────────────────────────────────────────────────────────────
40
115
  if (args.includes('--help') || args.includes('-h')) {
41
116
  console.log(`
42
117
  ${BANNER_TOP}
@@ -46,11 +121,13 @@ ${BANNER_BOTTOM}
46
121
  Usage: npx claudmax
47
122
 
48
123
  Options:
49
- --uninstall, -u Restore previous config and remove ClaudMax entry
50
- --version, -v Show version number
124
+ --reset, -r Clean all ClaudMax + OpusMax proxy config (before reinstalling)
125
+ --uninstall, -u Remove ClaudMax and restore previous config
126
+ --version, -v Show version number
51
127
 
52
128
  Examples:
53
129
  npx claudmax Interactive setup
130
+ npx claudmax --reset && npx claudmax Full clean reinstall
54
131
  npx claudmax --uninstall Remove ClaudMax, restore previous config
55
132
  `);
56
133
  process.exit(0);
@@ -61,30 +138,26 @@ if (args.includes('--version') || args.includes('-v')) {
61
138
  process.exit(0);
62
139
  }
63
140
 
141
+ // ── Reset: clean all proxy config ───────────────────────────────────────────────
142
+ if (flags.reset || flags.r) {
143
+ console.log('');
144
+ console.log(BANNER_TOP);
145
+ console.log(BANNER_SIDE + C.bold(' \u2726 ClaudMax Reset ') + BANNER_SIDE);
146
+ console.log(BANNER_BOTTOM);
147
+ console.log('');
148
+ cleanAllProxyConfig();
149
+ console.log(` ${C.green('\u2713')} Cleaned all proxy config from ~/.claude/settings.json`);
150
+ console.log(` ${C.green('\u2713')} Removed ClaudMax + OpusMax from ~/.claude.json mcpServers`);
151
+ console.log(` ${C.green('\u2713')} Deleted ~/.claudmax backup`);
152
+ console.log('');
153
+ console.log(` ${C.yellow('\u26A0')} Restart your terminal before running ${C.bold('npx claudmax')} again.`);
154
+ console.log('');
155
+ process.exit(0);
156
+ }
157
+
158
+ // ── Uninstall ─────────────────────────────────────────────────────────────────
64
159
  if (flags.uninstall || flags.u) {
65
- // Restore from backup
66
- const BACKUP_DIR = path.join(HOME, '.claudmax');
67
- const BACKUP_FILE = path.join(BACKUP_DIR, '.backup.json');
68
- function readJsonSafe(filePath) {
69
- try { return JSON.parse(fs.readFileSync(filePath, 'utf8')); }
70
- catch { return null; }
71
- }
72
- function writeJsonF(filePath, data) {
73
- const dir = path.dirname(filePath);
74
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
75
- fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n');
76
- }
77
- function deepMerge(target, source) {
78
- for (const key of Object.keys(source)) {
79
- if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
80
- if (!target[key]) target[key] = {};
81
- deepMerge(target[key], source[key]);
82
- } else {
83
- target[key] = source[key];
84
- }
85
- }
86
- return target;
87
- }
160
+ const BACKUP_FILE = path.join(HOME, '.claudmax', '.backup.json');
88
161
 
89
162
  console.log('');
90
163
  console.log(BANNER_TOP);
@@ -92,86 +165,52 @@ if (flags.uninstall || flags.u) {
92
165
  console.log(BANNER_BOTTOM);
93
166
  console.log('');
94
167
 
95
- const backup = readJsonSafe(BACKUP_FILE);
168
+ const backup = readJson(BACKUP_FILE);
96
169
  if (!backup) {
97
- console.log(C.yellow('\u26A0 No backup found. Nothing to restore.'));
170
+ console.log(C.yellow('\u26A0 No backup found. Performing clean removal...'));
171
+ cleanAllProxyConfig();
172
+ console.log(` ${C.green('\u2713')} Proxy config removed.`);
173
+ console.log('');
174
+ console.log(` ${C.green('\u2713')} ClaudMax uninstalled.`);
175
+ console.log('');
98
176
  process.exit(0);
99
177
  }
100
178
 
179
+ // Restore from backup (only the keys ClaudMax originally owned)
101
180
  const settingsPath = path.join(HOME, '.claude', 'settings.json');
102
- const settings = readJsonSafe(settingsPath) || {};
103
- if (settings.env) {
104
- delete settings.env['ANTHROPIC_AUTH_TOKEN'];
105
- delete settings.env['ANTHROPIC_BASE_URL'];
106
- delete settings.env['ANTHROPIC_MODEL'];
107
- delete settings.env['ANTHROPIC_SMALL_FAST_MODEL'];
108
- delete settings.env['ANTHROPIC_DEFAULT_SONNET_MODEL'];
109
- delete settings.env['ANTHROPIC_DEFAULT_OPUS_MODEL'];
110
- delete settings.env['ANTHROPIC_DEFAULT_HAIKU_MODEL'];
111
- delete settings.env['CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC'];
112
- if (Object.keys(settings.env).length === 0) delete settings.env;
181
+ const settings = readJson(settingsPath) || {};
182
+ if (backup.settings && backup.settings.env) {
183
+ for (const k of ALL_PROXY_KEYS) delete settings.env?.[k];
184
+ if (settings.env && Object.keys(settings.env).length === 0) delete settings.env;
113
185
  }
114
- writeJsonF(settingsPath, settings);
115
- console.log(` ${C.magenta('\u2713')} Restored ${settingsPath}`);
186
+ writeJson(settingsPath, settings);
187
+ console.log(` ${C.green('\u2713')} Restored ${settingsPath}`);
116
188
 
117
189
  const dotClaudePath = path.join(HOME, '.claude.json');
118
- const dotClaude = readJsonSafe(dotClaudePath) || {};
119
- if (dotClaude.mcpServers && dotClaude.mcpServers['ClaudMax']) {
190
+ const dotClaude = readJson(dotClaudePath) || {};
191
+ if (dotClaude.mcpServers) {
120
192
  delete dotClaude.mcpServers['ClaudMax'];
121
- writeJsonF(dotClaudePath, dotClaude);
122
- console.log(` ${C.magenta('\u2713')} Removed ClaudMax from ${dotClaudePath}`);
193
+ if (Object.keys(dotClaude.mcpServers).length === 0) delete dotClaude.mcpServers;
194
+ writeJson(dotClaudePath, dotClaude);
195
+ console.log(` ${C.green('\u2713')} Removed ClaudMax from ${dotClaudePath}`);
123
196
  }
124
197
 
125
198
  try { fs.unlinkSync(BACKUP_FILE); } catch { /* ignore */ }
126
199
  console.log('');
127
- console.log(` ${C.magenta('\u2713')} ClaudMax uninstalled. Previous config restored.`);
200
+ console.log(` ${C.green('\u2713')} ClaudMax uninstalled. Previous config restored.`);
128
201
  console.log('');
129
202
  process.exit(0);
130
203
  }
131
204
 
132
- // ── JSON helpers ──────────────────────────────────────────────────────────────
133
- function readJson(filePath) {
134
- try { return JSON.parse(fs.readFileSync(filePath, 'utf8')); }
135
- catch { return {}; }
136
- }
137
-
138
- function writeJson(filePath, data) {
139
- const dir = path.dirname(filePath);
140
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
141
- fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n');
142
- }
143
-
144
- function deepMerge(target, source) {
145
- for (const key of Object.keys(source)) {
146
- if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
147
- if (!target[key]) target[key] = {};
148
- deepMerge(target[key], source[key]);
149
- } else {
150
- target[key] = source[key];
151
- }
152
- }
153
- return target;
154
- }
155
-
156
- // ── Platform paths ─────────────────────────────────────────────────────────────
157
- function getVSCodeSettingsPath() {
158
- switch (process.platform) {
159
- case 'win32':
160
- return path.join(process.env.APPDATA || path.join(HOME, 'AppData', 'Roaming'), 'Code', 'User', 'settings.json');
161
- case 'darwin':
162
- return path.join(HOME, 'Library', 'Application Support', 'Code', 'User', 'settings.json');
163
- default:
164
- return path.join(HOME, '.config', 'Code', 'User', 'settings.json');
165
- }
166
- }
167
-
168
205
  // ── Readline helper ────────────────────────────────────────────────────────────
169
206
  function createRL() {
170
207
  return readline.createInterface({ input: process.stdin, output: process.stdout });
171
208
  }
172
209
 
173
210
  function ask(rl, question) {
174
- return new Promise((resolve) => rl.question(question, resolve));
211
+ return new Promise((resolve) => {
212
+ rl.question(question, (answer) => resolve(answer));
213
+ });
175
214
  }
176
215
 
177
216
  // ── HTTPS verification ─────────────────────────────────────────────────────────
@@ -200,16 +239,29 @@ function verifyConnection(apiKey) {
200
239
  }
201
240
 
202
241
  // ── IDE configurators ──────────────────────────────────────────────────────────
203
- function configureClaudeCodeCLI(apiKey) {
242
+ // Clean up conflicting proxy keys BEFORE writing new config
243
+ function preCleanForClaudeCodeCLI() {
244
+ const settingsPath = path.join(HOME, '.claude', 'settings.json');
245
+ const settings = readJson(settingsPath);
246
+ if (settings && settings.env) {
247
+ removeKeys(settings.env, ALL_PROXY_KEYS);
248
+ if (Object.keys(settings.env).length === 0) delete settings.env;
249
+ writeJson(settingsPath, settings);
250
+ }
251
+ }
252
+
253
+ function configureClaudeCodeCLI(apiKey, apiBase) {
204
254
  const settingsPath = path.join(HOME, '.claude', 'settings.json');
205
255
  const dotClaudePath = path.join(HOME, '.claude.json');
206
256
 
207
- // settings.json — deep merge only OpusMax's keys, preserve all others
208
- const settings = readJson(settingsPath);
257
+ // settings.json — MUST set ANTHROPIC_AUTH_TOKEN + ANTHROPIC_BASE_URL
258
+ // These are essential for Claude Code to route API calls through the proxy.
259
+ preCleanForClaudeCodeCLI();
260
+ const settings = readJson(settingsPath) || {};
209
261
  deepMerge(settings, {
210
262
  env: {
211
263
  ANTHROPIC_AUTH_TOKEN: apiKey,
212
- ANTHROPIC_BASE_URL: API_BASE,
264
+ ANTHROPIC_BASE_URL: apiBase,
213
265
  ANTHROPIC_MODEL: 'Opus 4.6',
214
266
  ANTHROPIC_SMALL_FAST_MODEL: 'Haiku 4.5',
215
267
  ANTHROPIC_DEFAULT_SONNET_MODEL: 'Sonnet 4.5',
@@ -220,10 +272,14 @@ function configureClaudeCodeCLI(apiKey) {
220
272
  hasCompletedOnboarding: true,
221
273
  });
222
274
  writeJson(settingsPath, settings);
223
- console.log(` ${C.magenta('\u2713')} Wrote ${C.magenta(settingsPath)}`);
275
+ console.log(` ${C.green('\u2713')} Wrote ${settingsPath}`);
224
276
 
225
- // .claude.json — deep merge only ClaudMax MCP entry, preserve all others
226
- const dotClaude = readJson(dotClaudePath);
277
+ // .claude.json — MCP server for routing (cleans OpusMax first)
278
+ const dotClaude = readJson(dotClaudePath) || {};
279
+ // Remove OpusMax to avoid auth conflicts
280
+ if (dotClaude.mcpServers) {
281
+ delete dotClaude.mcpServers['OpusMax'];
282
+ }
227
283
  deepMerge(dotClaude, {
228
284
  mcpServers: {
229
285
  ClaudMax: {
@@ -231,23 +287,24 @@ function configureClaudeCodeCLI(apiKey) {
231
287
  args: ['-y', MCP_PKG],
232
288
  env: {
233
289
  ANTHROPIC_API_KEY: apiKey,
234
- ANTHROPIC_BASE_URL: API_BASE,
290
+ ANTHROPIC_BASE_URL: apiBase,
235
291
  },
236
292
  },
237
293
  },
238
294
  });
239
295
  writeJson(dotClaudePath, dotClaude);
240
- console.log(` ${C.magenta('\u2713')} Wrote ${C.magenta(dotClaudePath)}`);
296
+ console.log(` ${C.green('\u2713')} Wrote ${dotClaudePath}`);
297
+ console.log(` ${C.magenta('i')} Removed OpusMax MCP entry to avoid auth conflict.`);
241
298
  }
242
299
 
243
- function configureVSCodeClaude(apiKey) {
244
- configureClaudeCodeCLI(apiKey);
300
+ function configureVSCodeClaude(apiKey, apiBase) {
301
+ configureClaudeCodeCLI(apiKey, apiBase);
245
302
  console.log(` ${C.magenta('i')} VS Code Claude extension uses the same config as Claude Code CLI.`);
246
303
  }
247
304
 
248
- function configureCursor(apiKey) {
305
+ function configureCursor(apiKey, apiBase) {
249
306
  const mcpPath = path.join(HOME, '.cursor', 'mcp.json');
250
- const existing = readJson(mcpPath);
307
+ const existing = readJson(mcpPath) || {};
251
308
  deepMerge(existing, {
252
309
  mcpServers: {
253
310
  ClaudMax: {
@@ -255,19 +312,19 @@ function configureCursor(apiKey) {
255
312
  args: ['-y', MCP_PKG],
256
313
  env: {
257
314
  ANTHROPIC_API_KEY: apiKey,
258
- ANTHROPIC_BASE_URL: API_BASE,
315
+ ANTHROPIC_BASE_URL: apiBase,
259
316
  },
260
317
  },
261
318
  },
262
319
  });
263
320
  writeJson(mcpPath, existing);
264
- console.log(` ${C.magenta('\u2713')} Wrote ${C.magenta(mcpPath)}`);
265
- console.log(` ${C.magenta('i')} For API routing, open Cursor Settings > Models > Add OpenAI-compatible model with base URL: ${C.bold(API_BASE + '/v1')}`);
321
+ console.log(` ${C.green('\u2713')} Wrote ${mcpPath}`);
322
+ console.log(` ${C.magenta('i')} For API routing, open Cursor Settings > Models > Add OpenAI-compatible model with base URL: ${C.bold(apiBase + '/v1')}`);
266
323
  }
267
324
 
268
- function configureWindsurf(apiKey) {
325
+ function configureWindsurf(apiKey, apiBase) {
269
326
  const mcpPath = path.join(HOME, '.windsurf', 'mcp.json');
270
- const existing = readJson(mcpPath);
327
+ const existing = readJson(mcpPath) || {};
271
328
  deepMerge(existing, {
272
329
  mcpServers: {
273
330
  ClaudMax: {
@@ -275,43 +332,43 @@ function configureWindsurf(apiKey) {
275
332
  args: ['-y', MCP_PKG],
276
333
  env: {
277
334
  ANTHROPIC_API_KEY: apiKey,
278
- ANTHROPIC_BASE_URL: API_BASE,
335
+ ANTHROPIC_BASE_URL: apiBase,
279
336
  },
280
337
  },
281
338
  },
282
339
  });
283
340
  writeJson(mcpPath, existing);
284
- console.log(` ${C.magenta('\u2713')} Wrote ${C.magenta(mcpPath)}`);
285
- console.log(` ${C.magenta('i')} For API routing, open Windsurf Settings > AI Provider and set base URL: ${C.bold(API_BASE + '/v1')}`);
341
+ console.log(` ${C.green('\u2713')} Wrote ${mcpPath}`);
342
+ console.log(` ${C.magenta('i')} For API routing, open Windsurf Settings > AI Provider and set base URL: ${C.bold(apiBase + '/v1')}`);
286
343
  }
287
344
 
288
- function configureCline(apiKey) {
345
+ function configureCline(apiKey, apiBase) {
289
346
  const settingsPath = getVSCodeSettingsPath();
290
- const existing = readJson(settingsPath);
347
+ const existing = readJson(settingsPath) || {};
291
348
  deepMerge(existing, {
292
349
  'cline.apiProvider': 'anthropic',
293
- 'cline.anthropicBaseUrl': API_BASE + '/v1',
350
+ 'cline.anthropicBaseUrl': apiBase + '/v1',
294
351
  'cline.apiKey': apiKey,
295
352
  });
296
353
  writeJson(settingsPath, existing);
297
- console.log(` ${C.magenta('\u2713')} Wrote ${C.magenta(settingsPath)}`);
354
+ console.log(` ${C.green('\u2713')} Wrote ${settingsPath}`);
298
355
  }
299
356
 
300
- function configureRooCode(apiKey) {
357
+ function configureRooCode(apiKey, apiBase) {
301
358
  const settingsPath = getVSCodeSettingsPath();
302
- const existing = readJson(settingsPath);
359
+ const existing = readJson(settingsPath) || {};
303
360
  deepMerge(existing, {
304
361
  'roo-cline.apiProvider': 'anthropic',
305
- 'roo-cline.anthropicBaseUrl': API_BASE + '/v1',
362
+ 'roo-cline.anthropicBaseUrl': apiBase + '/v1',
306
363
  'roo-cline.apiKey': apiKey,
307
364
  });
308
365
  writeJson(settingsPath, existing);
309
- console.log(` ${C.magenta('\u2713')} Wrote ${C.magenta(settingsPath)}`);
366
+ console.log(` ${C.green('\u2713')} Wrote ${settingsPath}`);
310
367
  }
311
368
 
312
- function configureAntigravity(apiKey) {
369
+ function configureAntigravity(apiKey, apiBase) {
313
370
  const mcpPath = path.join(HOME, '.config', 'antigravity', 'mcp.json');
314
- const existing = readJson(mcpPath);
371
+ const existing = readJson(mcpPath) || {};
315
372
  deepMerge(existing, {
316
373
  mcpServers: {
317
374
  ClaudMax: {
@@ -319,13 +376,13 @@ function configureAntigravity(apiKey) {
319
376
  args: ['-y', MCP_PKG],
320
377
  env: {
321
378
  ANTHROPIC_API_KEY: apiKey,
322
- ANTHROPIC_BASE_URL: API_BASE,
379
+ ANTHROPIC_BASE_URL: apiBase,
323
380
  },
324
381
  },
325
382
  },
326
383
  });
327
384
  writeJson(mcpPath, existing);
328
- console.log(` ${C.magenta('\u2713')} Wrote ${C.magenta(mcpPath)}`);
385
+ console.log(` ${C.green('\u2713')} Wrote ${mcpPath}`);
329
386
  }
330
387
 
331
388
  // ── IDE registry ───────────────────────────────────────────────────────────────
@@ -333,10 +390,10 @@ const IDES = [
333
390
  { id: 1, name: 'Claude Code (CLI)', configure: configureClaudeCodeCLI },
334
391
  { id: 2, name: 'VS Code (Claude Extension)', configure: configureVSCodeClaude },
335
392
  { id: 3, name: 'Cursor', configure: configureCursor },
336
- { id: 4, name: 'Windsurf', configure: configureWindsurf },
393
+ { id: 4, name: 'Windsurf', configure: configureWindsurf },
337
394
  { id: 5, name: 'Cline (VS Code Extension)', configure: configureCline },
338
- { id: 6, name: 'Roo Code (VS Code Extension)', configure: configureRooCode },
339
- { id: 7, name: 'Antigravity', configure: configureAntigravity },
395
+ { id: 6, name: 'Roo Code (VS Code Extension)', configure: configureRooCode },
396
+ { id: 7, name: 'Antigravity', configure: configureAntigravity },
340
397
  ];
341
398
 
342
399
  // ── Main ───────────────────────────────────────────────────────────────────────
@@ -350,7 +407,7 @@ async function main() {
350
407
  console.log(BANNER_BOTTOM);
351
408
  console.log('');
352
409
 
353
- // 2. API key prompt (always interactive — no flags)
410
+ // 2. API key prompt
354
411
  let apiKey = '';
355
412
  while (!apiKey.trim()) {
356
413
  apiKey = await ask(rl, C.bold('Enter your ClaudMax API key: '));
@@ -394,7 +451,7 @@ async function main() {
394
451
  for (const ide of selectedIDEs) {
395
452
  console.log(C.bold(`\nConfiguring ${C.magenta(ide.name)}...`));
396
453
  try {
397
- ide.configure(apiKey);
454
+ ide.configure(apiKey, API_BASE);
398
455
  } catch (err) {
399
456
  console.log(` ${C.red('\u2717')} Failed to configure ${ide.name}: ${err.message}`);
400
457
  }
@@ -410,7 +467,7 @@ async function main() {
410
467
  stdio: ['pipe', 'pipe', 'pipe'],
411
468
  timeout: 60000,
412
469
  });
413
- console.log(` ${C.magenta('\u2713')} claudmax-mcp installed successfully.`);
470
+ console.log(` ${C.green('\u2713')} claudmax-mcp installed successfully.`);
414
471
  } catch (err) {
415
472
  console.log(` ${C.yellow('\u26A0')} Could not install claudmax-mcp globally: ${(err.stderr || err.message || '').trim()}`);
416
473
  console.log(` ${C.yellow('\u26A0')} You can install it manually later: ${C.bold('npm i -g claudmax-mcp')}`);
@@ -423,7 +480,7 @@ async function main() {
423
480
  const result = await verifyConnection(apiKey);
424
481
 
425
482
  if (result.status === 200) {
426
- console.log(` ${C.magenta('\u2713')} Connected \u2014 API key is valid.`);
483
+ console.log(` ${C.green('\u2713')} Connected \u2014 API key is valid.`);
427
484
  } else if (result.status > 0) {
428
485
  console.log(` ${C.yellow('\u26A0')} HTTP ${result.status} \u2014 the server responded, but the key may be invalid.`);
429
486
  } else {
@@ -433,7 +490,7 @@ async function main() {
433
490
  // 7. Summary
434
491
  console.log('');
435
492
  console.log(BANNER_TOP);
436
- console.log(BANNER_SIDE + C.bold(' \u2713 Setup complete! ') + BANNER_SIDE);
493
+ console.log(BANNER_SIDE + C.bold(' \u2713 Setup complete! ') + BANNER_SIDE);
437
494
  console.log(BANNER_SIDE + ' Restart your IDE(s) to apply. ' + BANNER_SIDE);
438
495
  console.log(BANNER_BOTTOM);
439
496
  console.log('');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudmax",
3
- "version": "3.4.2",
3
+ "version": "3.4.4",
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": {