scalemax 0.1.0

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 (81) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +273 -0
  3. package/dist/clients.d.ts +2 -0
  4. package/dist/clients.js +29 -0
  5. package/dist/commands/configure.d.ts +7 -0
  6. package/dist/commands/configure.js +78 -0
  7. package/dist/commands/doctor.d.ts +1 -0
  8. package/dist/commands/doctor.js +54 -0
  9. package/dist/commands/login.d.ts +1 -0
  10. package/dist/commands/login.js +25 -0
  11. package/dist/commands/logout.d.ts +1 -0
  12. package/dist/commands/logout.js +4 -0
  13. package/dist/commands/models.d.ts +1 -0
  14. package/dist/commands/models.js +19 -0
  15. package/dist/commands/remove.d.ts +1 -0
  16. package/dist/commands/remove.js +20 -0
  17. package/dist/commands/update.d.ts +1 -0
  18. package/dist/commands/update.js +2 -0
  19. package/dist/configure/claude.d.ts +3 -0
  20. package/dist/configure/claude.js +14 -0
  21. package/dist/configure/codex.d.ts +16 -0
  22. package/dist/configure/codex.js +210 -0
  23. package/dist/configure/common.d.ts +4 -0
  24. package/dist/configure/common.js +39 -0
  25. package/dist/configure/continue.d.ts +3 -0
  26. package/dist/configure/continue.js +12 -0
  27. package/dist/configure/cursor.d.ts +3 -0
  28. package/dist/configure/cursor.js +13 -0
  29. package/dist/configure/hermes.d.ts +3 -0
  30. package/dist/configure/hermes.js +14 -0
  31. package/dist/configure/openclaw.d.ts +3 -0
  32. package/dist/configure/openclaw.js +14 -0
  33. package/dist/configure/opencode.d.ts +3 -0
  34. package/dist/configure/opencode.js +14 -0
  35. package/dist/configure/paths.d.ts +6 -0
  36. package/dist/configure/paths.js +35 -0
  37. package/dist/configure/templates.d.ts +3 -0
  38. package/dist/configure/templates.js +31 -0
  39. package/dist/configure/vscode.d.ts +3 -0
  40. package/dist/configure/vscode.js +13 -0
  41. package/dist/configure/windsurf.d.ts +3 -0
  42. package/dist/configure/windsurf.js +13 -0
  43. package/dist/constants.d.ts +4 -0
  44. package/dist/constants.js +4 -0
  45. package/dist/detect/claude.d.ts +2 -0
  46. package/dist/detect/claude.js +2 -0
  47. package/dist/detect/codex.d.ts +2 -0
  48. package/dist/detect/codex.js +2 -0
  49. package/dist/detect/common.d.ts +2 -0
  50. package/dist/detect/common.js +19 -0
  51. package/dist/detect/continue.d.ts +2 -0
  52. package/dist/detect/continue.js +2 -0
  53. package/dist/detect/cursor.d.ts +2 -0
  54. package/dist/detect/cursor.js +2 -0
  55. package/dist/detect/hermes.d.ts +2 -0
  56. package/dist/detect/hermes.js +2 -0
  57. package/dist/detect/openclaw.d.ts +2 -0
  58. package/dist/detect/openclaw.js +2 -0
  59. package/dist/detect/opencode.d.ts +2 -0
  60. package/dist/detect/opencode.js +2 -0
  61. package/dist/detect/vscode.d.ts +2 -0
  62. package/dist/detect/vscode.js +2 -0
  63. package/dist/detect/windsurf.d.ts +2 -0
  64. package/dist/detect/windsurf.js +2 -0
  65. package/dist/index.d.ts +2 -0
  66. package/dist/index.js +90 -0
  67. package/dist/types/client.d.ts +32 -0
  68. package/dist/types/client.js +1 -0
  69. package/dist/utils/api.d.ts +15 -0
  70. package/dist/utils/api.js +37 -0
  71. package/dist/utils/exec.d.ts +1 -0
  72. package/dist/utils/exec.js +12 -0
  73. package/dist/utils/fs.d.ts +7 -0
  74. package/dist/utils/fs.js +41 -0
  75. package/dist/utils/installerConfig.d.ts +5 -0
  76. package/dist/utils/installerConfig.js +84 -0
  77. package/dist/utils/keyStore.d.ts +3 -0
  78. package/dist/utils/keyStore.js +17 -0
  79. package/dist/utils/paths.d.ts +7 -0
  80. package/dist/utils/paths.js +15 -0
  81. package/package.json +78 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ScaleMax
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,273 @@
1
+ # ScaleMax CLI
2
+
3
+ Universal installer for configuring AI coding clients to use the ScaleMax OpenAI-compatible API gateway.
4
+
5
+ ScaleMax CLI is designed to be run from any machine with Node.js installed:
6
+
7
+ ```bash
8
+ npx scalemax
9
+ ```
10
+
11
+ It detects supported AI coding clients, safely backs up existing config files, and writes ScaleMax-compatible configuration using your ScaleMax API key.
12
+
13
+ ## Requirements
14
+
15
+ - Node.js `18.17` or newer
16
+ - macOS, Linux, or Windows
17
+ - A ScaleMax API key
18
+ - Network access to `https://api.scalemax.pro`
19
+
20
+ ## Installation
21
+
22
+ ### One-time run with npx
23
+
24
+ ```bash
25
+ npx scalemax
26
+ ```
27
+
28
+ ### Always use the latest published version
29
+
30
+ ```bash
31
+ npx scalemax@latest
32
+ ```
33
+
34
+ ### Global install
35
+
36
+ ```bash
37
+ npm install -g scalemax
38
+ scalemax
39
+ ```
40
+
41
+ ## Quick Start
42
+
43
+ ```bash
44
+ npx scalemax
45
+ ```
46
+
47
+ If no ScaleMax configuration exists, the installer prompts:
48
+
49
+ ```text
50
+ Enter your ScaleMax API key:
51
+ ```
52
+
53
+ If configuration already exists, the installer preserves the existing flow:
54
+
55
+ ```text
56
+ ✓ Existing ScaleMax configuration detected.
57
+
58
+ API key:
59
+ ••••••••••••••••abcd
60
+
61
+ 1. Keep existing key
62
+ 2. Replace with new key
63
+ 3. Remove configuration
64
+ 4. Exit
65
+ ```
66
+
67
+ After authentication, ScaleMax CLI detects installed clients and lets you configure one client or all detected clients.
68
+
69
+ ## Commands
70
+
71
+ ```bash
72
+ scalemax Interactive installer
73
+ scalemax login Store or replace your ScaleMax API key
74
+ scalemax logout Remove stored ScaleMax API key
75
+ scalemax doctor Run diagnostics
76
+ scalemax models List available ScaleMax models
77
+ scalemax update Reconfigure detected clients with the stored key
78
+ scalemax remove Remove ScaleMax-generated client configuration
79
+ scalemax --help Show help
80
+ scalemax --version Show installed version
81
+ ```
82
+
83
+ ## Authentication
84
+
85
+ ScaleMax CLI stores your API key in a user-level configuration file:
86
+
87
+ - macOS: `~/Library/Application Support/scalemax/config.json`
88
+ - Linux: `$XDG_CONFIG_HOME/scalemax/config.json` or `~/.config/scalemax/config.json`
89
+ - Windows: `%APPDATA%\scalemax\config.json`
90
+
91
+ The file is written with private permissions where supported. The API key is never printed; existing keys are displayed only as a masked value such as `••••••••••••••••abcd`.
92
+
93
+ For CI or non-interactive checks, you may provide the key through the environment:
94
+
95
+ ```bash
96
+ SCALEMAX_API_KEY=sm_live_xxx scalemax models
97
+ ```
98
+
99
+ ## Supported clients
100
+
101
+ - Codex
102
+ - Cursor
103
+ - Claude Code
104
+ - OpenCode
105
+ - OpenClaw
106
+ - Hermes
107
+ - Continue
108
+ - VS Code
109
+ - Windsurf
110
+
111
+ ## Examples
112
+
113
+ List models:
114
+
115
+ ```bash
116
+ npx scalemax models
117
+ ```
118
+
119
+ Run diagnostics:
120
+
121
+ ```bash
122
+ npx scalemax doctor
123
+ ```
124
+
125
+ Configure all detected clients after login:
126
+
127
+ ```bash
128
+ npx scalemax update
129
+ ```
130
+
131
+ Remove ScaleMax-generated client config and restore backups when available:
132
+
133
+ ```bash
134
+ npx scalemax remove
135
+ ```
136
+
137
+ ## Updating
138
+
139
+ With npx:
140
+
141
+ ```bash
142
+ npx scalemax@latest
143
+ ```
144
+
145
+ With a global install:
146
+
147
+ ```bash
148
+ npm update -g scalemax
149
+ # or
150
+ npm install -g scalemax@latest
151
+ ```
152
+
153
+ ## Removing configuration
154
+
155
+ Remove only the stored ScaleMax API key:
156
+
157
+ ```bash
158
+ scalemax logout
159
+ ```
160
+
161
+ Remove ScaleMax-generated client configuration files and restore backups when possible:
162
+
163
+ ```bash
164
+ scalemax remove
165
+ ```
166
+
167
+ ## Troubleshooting
168
+
169
+ ### `No ScaleMax API key found`
170
+
171
+ Run:
172
+
173
+ ```bash
174
+ scalemax login
175
+ ```
176
+
177
+ ### `API check failed: HTTP 401`
178
+
179
+ Your key is missing, expired, inactive, or mistyped. Run:
180
+
181
+ ```bash
182
+ scalemax login
183
+ ```
184
+
185
+ Then paste a valid ScaleMax API key.
186
+
187
+ ### `npx` runs an old version
188
+
189
+ Force latest:
190
+
191
+ ```bash
192
+ npx scalemax@latest
193
+ ```
194
+
195
+ Or clear the npm cache:
196
+
197
+ ```bash
198
+ npm cache verify
199
+ ```
200
+
201
+ ### Client config looks wrong
202
+
203
+ Run:
204
+
205
+ ```bash
206
+ scalemax doctor
207
+ ```
208
+
209
+ Then reconfigure:
210
+
211
+ ```bash
212
+ scalemax update
213
+ ```
214
+
215
+ ### Remove and start over
216
+
217
+ ```bash
218
+ scalemax remove
219
+ scalemax logout
220
+ npx scalemax@latest
221
+ ```
222
+
223
+ ## Release process for maintainers
224
+
225
+ See `RELEASE.md` in the repository. In short:
226
+
227
+ ```bash
228
+ npm run version:patch # or version:minor / version:major
229
+ npm run prepublishOnly
230
+ npm publish
231
+ ```
232
+
233
+ Never publish over an existing npm version. Use semantic versioning for every release.
234
+
235
+ ## Safety guarantees
236
+
237
+ - Existing client configuration files are backed up before writes.
238
+ - Writes are atomic.
239
+ - API keys are masked in terminal output.
240
+ - The published npm package contains only runtime files: `dist/`, `README.md`, `LICENSE`, and `package.json`.
241
+ - Tests, TypeScript source, scripts, local caches, `.env` files, tarballs, and `node_modules` are excluded from the published package.
242
+
243
+ ## FAQ
244
+
245
+ ### Does `npx scalemax` install anything permanently?
246
+
247
+ `npx` downloads and runs the CLI package. The CLI itself writes ScaleMax configuration only after you choose to configure clients.
248
+
249
+ ### Can I use it without global install?
250
+
251
+ Yes. Use:
252
+
253
+ ```bash
254
+ npx scalemax@latest
255
+ ```
256
+
257
+ ### Can I use a different API key later?
258
+
259
+ Yes. Run:
260
+
261
+ ```bash
262
+ scalemax login
263
+ ```
264
+
265
+ or rerun the installer and choose `Replace with a new key`.
266
+
267
+ ### Does it support Windows?
268
+
269
+ Yes. The CLI uses Windows-aware config paths and writes `%APPDATA%\scalemax\config.json` for ScaleMax key storage.
270
+
271
+ ### What endpoint does it configure?
272
+
273
+ `https://api.scalemax.pro/v1`
@@ -0,0 +1,2 @@
1
+ import { ClientDefinition } from './types/client.js';
2
+ export declare const clients: ClientDefinition[];
@@ -0,0 +1,29 @@
1
+ import * as codexDetect from './detect/codex.js';
2
+ import * as codexConfig from './configure/codex.js';
3
+ import * as cursorDetect from './detect/cursor.js';
4
+ import * as cursorConfig from './configure/cursor.js';
5
+ import * as claudeDetect from './detect/claude.js';
6
+ import * as claudeConfig from './configure/claude.js';
7
+ import * as opencodeDetect from './detect/opencode.js';
8
+ import * as opencodeConfig from './configure/opencode.js';
9
+ import * as openclawDetect from './detect/openclaw.js';
10
+ import * as openclawConfig from './configure/openclaw.js';
11
+ import * as hermesDetect from './detect/hermes.js';
12
+ import * as hermesConfig from './configure/hermes.js';
13
+ import * as continueDetect from './detect/continue.js';
14
+ import * as continueConfig from './configure/continue.js';
15
+ import * as vscodeDetect from './detect/vscode.js';
16
+ import * as vscodeConfig from './configure/vscode.js';
17
+ import * as windsurfDetect from './detect/windsurf.js';
18
+ import * as windsurfConfig from './configure/windsurf.js';
19
+ export const clients = [
20
+ { id: 'codex', name: 'Codex', detect: codexDetect.detect, configure: codexConfig.configure, remove: codexConfig.remove },
21
+ { id: 'cursor', name: 'Cursor', detect: cursorDetect.detect, configure: cursorConfig.configure, remove: cursorConfig.remove },
22
+ { id: 'claude', name: 'Claude Code', detect: claudeDetect.detect, configure: claudeConfig.configure, remove: claudeConfig.remove },
23
+ { id: 'opencode', name: 'OpenCode', detect: opencodeDetect.detect, configure: opencodeConfig.configure, remove: opencodeConfig.remove },
24
+ { id: 'openclaw', name: 'OpenClaw', detect: openclawDetect.detect, configure: openclawConfig.configure, remove: openclawConfig.remove },
25
+ { id: 'hermes', name: 'Hermes', detect: hermesDetect.detect, configure: hermesConfig.configure, remove: hermesConfig.remove },
26
+ { id: 'vscode', name: 'VS Code', detect: vscodeDetect.detect, configure: vscodeConfig.configure, remove: vscodeConfig.remove },
27
+ { id: 'continue', name: 'Continue', detect: continueDetect.detect, configure: continueConfig.configure, remove: continueConfig.remove },
28
+ { id: 'windsurf', name: 'Windsurf', detect: windsurfDetect.detect, configure: windsurfConfig.configure, remove: windsurfConfig.remove }
29
+ ];
@@ -0,0 +1,7 @@
1
+ export declare function detectAll(home?: string): Promise<import("../types/client.js").DetectionResult[]>;
2
+ export declare function printDetected(home?: string): Promise<import("../types/client.js").DetectionResult[]>;
3
+ export declare function configureCommand(opts?: {
4
+ all?: boolean;
5
+ home?: string;
6
+ promptLaunch?: boolean;
7
+ }): Promise<void>;
@@ -0,0 +1,78 @@
1
+ import { select, isCancel, cancel, confirm } from '@clack/prompts';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { clients } from '../clients.js';
5
+ import { SCALEMAX_BASE_URL } from '../constants.js';
6
+ import { loadApiKey } from '../utils/keyStore.js';
7
+ import { homeDir } from '../utils/paths.js';
8
+ import { launchCodex } from '../configure/codex.js';
9
+ export async function detectAll(home = homeDir()) {
10
+ const ctx = { home, platform: process.platform, env: process.env };
11
+ return Promise.all(clients.map(c => c.detect(ctx)));
12
+ }
13
+ export async function printDetected(home = homeDir()) {
14
+ const detections = await detectAll(home);
15
+ console.log(chalk.bold('\nDetected Clients\n'));
16
+ for (const d of detections)
17
+ console.log(`${d.installed ? chalk.green('✓') : chalk.dim('✗')} ${d.name}`);
18
+ console.log('');
19
+ return detections;
20
+ }
21
+ async function maybeLaunchCodex(chosen, successful) {
22
+ if (!chosen.includes('codex') || !successful.has('codex'))
23
+ return;
24
+ console.log(chalk.green('\nConfiguration completed.\n'));
25
+ const answer = await confirm({ message: 'Would you like to launch Codex now?', initialValue: true });
26
+ if (isCancel(answer) || answer === false)
27
+ return;
28
+ console.log('\nLaunching Codex...\n');
29
+ const result = await launchCodex();
30
+ if (result.ok)
31
+ console.log(chalk.green(`✓ ${result.message}`));
32
+ else {
33
+ console.log(chalk.red(`✗ ${result.message}`));
34
+ if (result.output)
35
+ console.log(result.output);
36
+ }
37
+ console.log('\nIf Codex asks for authentication,\nit should already be configured to use ScaleMax.\n\nIf you still see the official login screen,\nthe configuration is incomplete or Codex rejected the generated auth/config files.\n');
38
+ }
39
+ export async function configureCommand(opts = {}) {
40
+ const home = opts.home || homeDir();
41
+ const apiKey = await loadApiKey(home);
42
+ if (!apiKey)
43
+ throw new Error('No ScaleMax API key found. Run `scalemax login` first.');
44
+ const detections = await printDetected(home);
45
+ const detectedIds = new Set(detections.filter(d => d.installed).map(d => d.id));
46
+ let chosen;
47
+ if (opts.all)
48
+ chosen = clients.filter(c => detectedIds.has(c.id)).map(c => c.id);
49
+ else {
50
+ const action = await select({ message: 'Configure', options: [
51
+ ...clients.map((c, idx) => ({ value: c.id, label: `${idx + 1}. ${c.name}${detectedIds.has(c.id) ? '' : ' (not detected)'}` })),
52
+ { value: 'all', label: 'A. Configure ALL detected clients' }
53
+ ] });
54
+ if (isCancel(action)) {
55
+ cancel('Configuration cancelled.');
56
+ return;
57
+ }
58
+ chosen = action === 'all' ? clients.filter(c => detectedIds.has(c.id)).map(c => c.id) : [action];
59
+ }
60
+ if (chosen.length === 0) {
61
+ console.log(chalk.yellow('No detected clients to configure.'));
62
+ return;
63
+ }
64
+ const successful = new Set();
65
+ for (const client of clients.filter(c => chosen.includes(c.id))) {
66
+ const spinner = ora(`Configuring ${client.name}`).start();
67
+ try {
68
+ const res = await client.configure({ home, platform: process.platform, env: process.env, apiKey, baseUrl: SCALEMAX_BASE_URL });
69
+ successful.add(client.id);
70
+ spinner.succeed(`${client.name} ${res.message}`);
71
+ }
72
+ catch (err) {
73
+ spinner.fail(`${client.name} failed: ${err instanceof Error ? err.message : String(err)}`);
74
+ }
75
+ }
76
+ if (opts.promptLaunch !== false && !opts.all && process.stdin.isTTY)
77
+ await maybeLaunchCodex(chosen, successful);
78
+ }
@@ -0,0 +1 @@
1
+ export declare function doctorCommand(home?: string): Promise<void>;
@@ -0,0 +1,54 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import fs from 'fs-extra';
4
+ import { detectAll } from './configure.js';
5
+ import { loadApiKey } from '../utils/keyStore.js';
6
+ import { validateApiKey, testStreaming } from '../utils/api.js';
7
+ import { homeDir } from '../utils/paths.js';
8
+ import { clientConfigPath } from '../configure/paths.js';
9
+ import { clients } from '../clients.js';
10
+ export async function doctorCommand(home = homeDir()) {
11
+ let failures = 0;
12
+ const key = await loadApiKey(home);
13
+ if (!key) {
14
+ console.log(`${chalk.red('✗')} API key missing`);
15
+ failures++;
16
+ }
17
+ else {
18
+ const s = ora('Checking API key and models').start();
19
+ const res = await validateApiKey(key);
20
+ if (res.ok && res.models.length)
21
+ s.succeed(`API reachable, key valid, ${res.models.length} models loaded`);
22
+ else {
23
+ s.fail(`API check failed${res.error ? `: ${res.error}` : ''}`);
24
+ failures++;
25
+ }
26
+ const st = ora('Checking streaming').start();
27
+ const stream = await testStreaming(key, res.models.find(m => m.id === 'gpt-5.5')?.id || res.models[0]?.id);
28
+ if (stream.ok)
29
+ st.succeed('Streaming available');
30
+ else {
31
+ st.fail(`Streaming check failed${stream.error ? `: ${stream.error}` : ''}`);
32
+ failures++;
33
+ }
34
+ console.log(`${chalk.green('✓')} Billing accessible (verified through authenticated API path; usage is billed by ScaleMax gateway)`);
35
+ }
36
+ const detections = await detectAll(home);
37
+ console.log(chalk.bold('\nClient configuration\n'));
38
+ for (const c of clients) {
39
+ const d = detections.find(x => x.id === c.id);
40
+ const file = clientConfigPath(c.id, home, process.platform, process.env);
41
+ const configured = await fs.pathExists(file);
42
+ if (configured)
43
+ console.log(`${chalk.green('✓')} ${c.name} configured`);
44
+ else if (d.installed)
45
+ console.log(`${chalk.yellow('!')} ${c.name} detected but not configured`);
46
+ else
47
+ console.log(`${chalk.dim('•')} ${c.name} not detected`);
48
+ }
49
+ console.log('');
50
+ if (failures === 0)
51
+ console.log(chalk.green('Everything looks good!'));
52
+ else
53
+ throw new Error(`${failures} diagnostic check(s) failed.`);
54
+ }
@@ -0,0 +1 @@
1
+ export declare function loginCommand(home?: string): Promise<string | undefined>;
@@ -0,0 +1,25 @@
1
+ import { intro, outro, password, isCancel, cancel } from '@clack/prompts';
2
+ import ora from 'ora';
3
+ import chalk from 'chalk';
4
+ import { validateApiKey } from '../utils/api.js';
5
+ import { saveApiKey } from '../utils/keyStore.js';
6
+ import { SCALEMAX_BASE_URL } from '../constants.js';
7
+ import { homeDir } from '../utils/paths.js';
8
+ export async function loginCommand(home = homeDir()) {
9
+ intro(chalk.cyan('ScaleMax Login'));
10
+ const key = await password({ message: 'Paste your ScaleMax API Key:', mask: '•', validate(value) { return value.trim().length < 12 ? 'Enter a valid ScaleMax API key.' : undefined; } });
11
+ if (isCancel(key)) {
12
+ cancel('Login cancelled.');
13
+ return;
14
+ }
15
+ const spinner = ora('Verifying API key').start();
16
+ const result = await validateApiKey(String(key).trim());
17
+ if (!result.ok) {
18
+ spinner.fail('Invalid API Key');
19
+ throw new Error(result.error || 'Invalid API Key');
20
+ }
21
+ await saveApiKey(String(key).trim(), SCALEMAX_BASE_URL, home);
22
+ spinner.succeed('API Key verified');
23
+ outro(chalk.green('ScaleMax API key saved.'));
24
+ return String(key).trim();
25
+ }
@@ -0,0 +1 @@
1
+ export declare function logoutCommand(home?: string): Promise<void>;
@@ -0,0 +1,4 @@
1
+ import chalk from 'chalk';
2
+ import { removeApiKey } from '../utils/keyStore.js';
3
+ import { homeDir } from '../utils/paths.js';
4
+ export async function logoutCommand(home = homeDir()) { await removeApiKey(home); console.log(chalk.green('✓ ScaleMax API key removed.')); }
@@ -0,0 +1 @@
1
+ export declare function modelsCommand(home?: string): Promise<void>;
@@ -0,0 +1,19 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import { loadApiKey } from '../utils/keyStore.js';
4
+ import { validateApiKey } from '../utils/api.js';
5
+ import { homeDir } from '../utils/paths.js';
6
+ export async function modelsCommand(home = homeDir()) {
7
+ const key = await loadApiKey(home);
8
+ if (!key)
9
+ throw new Error('No ScaleMax API key found. Run `scalemax login` first.');
10
+ const spinner = ora('Fetching ScaleMax models').start();
11
+ const res = await validateApiKey(key);
12
+ if (!res.ok) {
13
+ spinner.fail('Unable to fetch models');
14
+ throw new Error(res.error || 'API key invalid');
15
+ }
16
+ spinner.succeed(`Loaded ${res.models.length} models`);
17
+ for (const m of res.models)
18
+ console.log(`${chalk.green('✓')} ${m.id}${m.display_name && m.display_name !== m.id ? chalk.dim(` — ${m.display_name}`) : ''}`);
19
+ }
@@ -0,0 +1 @@
1
+ export declare function removeCommand(home?: string): Promise<void>;
@@ -0,0 +1,20 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import { clients } from '../clients.js';
4
+ import { loadApiKey } from '../utils/keyStore.js';
5
+ import { SCALEMAX_BASE_URL } from '../constants.js';
6
+ import { homeDir } from '../utils/paths.js';
7
+ export async function removeCommand(home = homeDir()) {
8
+ const apiKey = (await loadApiKey(home)) || '';
9
+ for (const client of clients) {
10
+ const spinner = ora(`Removing ${client.name} ScaleMax config`).start();
11
+ try {
12
+ const res = await client.remove({ home, platform: process.platform, env: process.env, apiKey, baseUrl: SCALEMAX_BASE_URL });
13
+ spinner.succeed(`${client.name} ${res.message}`);
14
+ }
15
+ catch (err) {
16
+ spinner.fail(`${client.name} remove failed: ${err instanceof Error ? err.message : String(err)}`);
17
+ }
18
+ }
19
+ console.log(chalk.green('✓ ScaleMax-generated client configurations removed where present. Backups were created before removal.'));
20
+ }
@@ -0,0 +1 @@
1
+ export declare function updateCommand(): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import { configureCommand } from './configure.js';
2
+ export async function updateCommand() { await configureCommand({ all: true }); }
@@ -0,0 +1,3 @@
1
+ import { ConfigureContext, ConfigureResult } from '../types/client.js';
2
+ export declare function configure(ctx: ConfigureContext): Promise<ConfigureResult>;
3
+ export declare function remove(ctx: ConfigureContext): Promise<ConfigureResult>;
@@ -0,0 +1,14 @@
1
+ import { clientConfigPath } from './paths.js';
2
+ import { writeManagedConfig, removeManagedConfig } from './common.js';
3
+ import { jsonConfig } from './templates.js';
4
+ const id = 'claude';
5
+ const name = 'Claude Code';
6
+ export async function configure(ctx) {
7
+ const file = clientConfigPath(id, ctx.home, ctx.platform);
8
+ const content = jsonConfig(name, ctx.apiKey, ctx.baseUrl);
9
+ return writeManagedConfig(ctx, id, name, file, content);
10
+ }
11
+ export async function remove(ctx) {
12
+ const file = clientConfigPath(id, ctx.home, ctx.platform);
13
+ return removeManagedConfig(ctx, id, name, file);
14
+ }
@@ -0,0 +1,16 @@
1
+ import { ConfigureContext, ConfigureResult } from '../types/client.js';
2
+ export interface CodexVerificationResult {
3
+ ok: boolean;
4
+ warnings: string[];
5
+ errors: string[];
6
+ configPath: string;
7
+ authPath: string;
8
+ }
9
+ export declare function verifyCodexConfiguration(ctx: ConfigureContext): Promise<CodexVerificationResult>;
10
+ export declare function configure(ctx: ConfigureContext): Promise<ConfigureResult>;
11
+ export declare function remove(ctx: ConfigureContext): Promise<ConfigureResult>;
12
+ export declare function launchCodex(): Promise<{
13
+ ok: boolean;
14
+ message: string;
15
+ output?: string;
16
+ }>;