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.
- package/index.js +182 -125
- 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.
|
|
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
|
|
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
|
-
--
|
|
50
|
-
--
|
|
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
|
-
|
|
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 =
|
|
168
|
+
const backup = readJson(BACKUP_FILE);
|
|
96
169
|
if (!backup) {
|
|
97
|
-
console.log(C.yellow('\u26A0 No backup found.
|
|
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 =
|
|
103
|
-
if (settings.env) {
|
|
104
|
-
delete settings.env[
|
|
105
|
-
delete settings.env
|
|
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
|
-
|
|
115
|
-
console.log(` ${C.
|
|
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 =
|
|
119
|
-
if (dotClaude.mcpServers
|
|
190
|
+
const dotClaude = readJson(dotClaudePath) || {};
|
|
191
|
+
if (dotClaude.mcpServers) {
|
|
120
192
|
delete dotClaude.mcpServers['ClaudMax'];
|
|
121
|
-
|
|
122
|
-
|
|
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.
|
|
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) =>
|
|
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
|
-
|
|
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 —
|
|
208
|
-
|
|
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:
|
|
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.
|
|
275
|
+
console.log(` ${C.green('\u2713')} Wrote ${settingsPath}`);
|
|
224
276
|
|
|
225
|
-
// .claude.json —
|
|
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:
|
|
290
|
+
ANTHROPIC_BASE_URL: apiBase,
|
|
235
291
|
},
|
|
236
292
|
},
|
|
237
293
|
},
|
|
238
294
|
});
|
|
239
295
|
writeJson(dotClaudePath, dotClaude);
|
|
240
|
-
console.log(` ${C.
|
|
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:
|
|
315
|
+
ANTHROPIC_BASE_URL: apiBase,
|
|
259
316
|
},
|
|
260
317
|
},
|
|
261
318
|
},
|
|
262
319
|
});
|
|
263
320
|
writeJson(mcpPath, existing);
|
|
264
|
-
console.log(` ${C.
|
|
265
|
-
console.log(` ${C.magenta('i')} For API routing, open Cursor Settings > Models > Add OpenAI-compatible model with base URL: ${C.bold(
|
|
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:
|
|
335
|
+
ANTHROPIC_BASE_URL: apiBase,
|
|
279
336
|
},
|
|
280
337
|
},
|
|
281
338
|
},
|
|
282
339
|
});
|
|
283
340
|
writeJson(mcpPath, existing);
|
|
284
|
-
console.log(` ${C.
|
|
285
|
-
console.log(` ${C.magenta('i')} For API routing, open Windsurf Settings > AI Provider and set base URL: ${C.bold(
|
|
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':
|
|
350
|
+
'cline.anthropicBaseUrl': apiBase + '/v1',
|
|
294
351
|
'cline.apiKey': apiKey,
|
|
295
352
|
});
|
|
296
353
|
writeJson(settingsPath, existing);
|
|
297
|
-
console.log(` ${C.
|
|
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':
|
|
362
|
+
'roo-cline.anthropicBaseUrl': apiBase + '/v1',
|
|
306
363
|
'roo-cline.apiKey': apiKey,
|
|
307
364
|
});
|
|
308
365
|
writeJson(settingsPath, existing);
|
|
309
|
-
console.log(` ${C.
|
|
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:
|
|
379
|
+
ANTHROPIC_BASE_URL: apiBase,
|
|
323
380
|
},
|
|
324
381
|
},
|
|
325
382
|
},
|
|
326
383
|
});
|
|
327
384
|
writeJson(mcpPath, existing);
|
|
328
|
-
console.log(` ${C.
|
|
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',
|
|
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)',
|
|
339
|
-
{ id: 7, name: 'Antigravity',
|
|
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
|
|
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.
|
|
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.
|
|
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!
|
|
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