scalemax 0.1.22 → 0.1.23
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/README.md +4 -2
- package/dist/commands/helper-bot.d.ts +5 -0
- package/dist/commands/helper-bot.js +183 -9
- package/dist/index.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -113,13 +113,15 @@ Or ask one small question and exit:
|
|
|
113
113
|
npx scalemax@latest helper-bot "Why is my ScaleMax API key rejected in Codex?"
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
-
The helper uses the same stored key as the installer, verifies authentication, detects the API-credit or token-pack base URL automatically
|
|
116
|
+
The helper uses the same stored key as the installer, verifies authentication, and detects the API-credit or token-pack base URL automatically. General support questions default to `gpt-5.4` when that model is available to the key; each response is capped at 512 tokens and interactive history is bounded to the latest two turns. To choose a different model from `scalemax models`, use:
|
|
117
117
|
|
|
118
118
|
```bash
|
|
119
119
|
npx scalemax@latest helper-bot --model fable-5 "Help me configure ScaleMax in Cursor"
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
Recognized setup, repair, and verification requests execute the CLI's allowlisted client operations directly. For example, `setup vs code roo extension for claude` detects or installs the official Roo Code extension, writes its ScaleMax Claude profile with the stored key, verifies the handoff, and reports each step. The language model never generates or executes shell commands; only fixed ScaleMax client detection, configuration, verification, rollback, and the official Roo Code extension installer are available to the controller.
|
|
123
|
+
|
|
124
|
+
The helper refuses unrelated requests and redacts ScaleMax-style secrets from prompts, provider output, errors, and progress notifications. Use `/status` for non-secret connection details, `/help` for commands, and `/quit` to exit.
|
|
123
125
|
|
|
124
126
|
## Supported clients
|
|
125
127
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ChatCompletionOptions, type ChatCompletionResult, type ChatMessage, type ModelInfo } from '../utils/api.js';
|
|
2
2
|
import { loadApiKey } from '../utils/keyStore.js';
|
|
3
3
|
import { validateApiKey } from '../utils/api.js';
|
|
4
|
+
import type { ClientDefinition } from '../types/client.js';
|
|
4
5
|
export declare const SCALEMAX_HELPER_REFUSAL: string;
|
|
5
6
|
export declare const SCALEMAX_HELPER_SYSTEM_PROMPT: string;
|
|
6
7
|
export declare const SCALEMAX_HELPER_INVALID_PROVIDER_RESPONSE: string;
|
|
@@ -16,6 +17,7 @@ export interface HelperConnection {
|
|
|
16
17
|
providerScope?: 'openai' | 'anthropic' | 'both';
|
|
17
18
|
keyMode?: string;
|
|
18
19
|
availableModels?: string[];
|
|
20
|
+
modelCatalog?: ModelInfo[];
|
|
19
21
|
}
|
|
20
22
|
export type HelperCompletion = (options: ChatCompletionOptions) => Promise<ChatCompletionResult>;
|
|
21
23
|
export interface HelperBotDependencies {
|
|
@@ -23,6 +25,7 @@ export interface HelperBotDependencies {
|
|
|
23
25
|
validateKey: typeof validateApiKey;
|
|
24
26
|
complete: HelperCompletion;
|
|
25
27
|
write: (message: string) => void;
|
|
28
|
+
clientCatalog: ClientDefinition[];
|
|
26
29
|
}
|
|
27
30
|
export declare function parseHelperBotArgs(args: string[]): HelperBotArgs;
|
|
28
31
|
export declare function redactHelperSecrets(value: unknown, activeKey?: string): string;
|
|
@@ -38,4 +41,6 @@ export declare function helperConnectionSummary(connection: HelperConnection): s
|
|
|
38
41
|
export declare function localHelperReply(question: string, connection: HelperConnection): string | undefined;
|
|
39
42
|
export declare function selectHelperModel(models: ModelInfo[], requested?: string): string;
|
|
40
43
|
export declare function requestHelperReply(question: string, history: ChatMessage[], connection: HelperConnection, complete?: HelperCompletion): Promise<string>;
|
|
44
|
+
/** Execute only narrowly allowlisted ScaleMax client actions; never model-generated shell commands. */
|
|
45
|
+
export declare function executeHelperAction(question: string, connection: HelperConnection, home: string, clientCatalog?: ClientDefinition[], write?: (message: string) => void): Promise<string | undefined>;
|
|
41
46
|
export declare function helperBotCommand(args?: string[], home?: string, dependencies?: Partial<HelperBotDependencies>): Promise<void>;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import path from 'node:path';
|
|
2
3
|
import { createInterface } from 'node:readline/promises';
|
|
3
|
-
import {
|
|
4
|
+
import { execa } from 'execa';
|
|
5
|
+
import { clients } from '../clients.js';
|
|
6
|
+
import { createChatCompletion, isAnthropicModel } from '../utils/api.js';
|
|
4
7
|
import { redactApiKey } from '../utils/apiKey.js';
|
|
5
8
|
import { loadApiKey } from '../utils/keyStore.js';
|
|
6
9
|
import { homeDir } from '../utils/paths.js';
|
|
@@ -538,6 +541,9 @@ const CLAUDE_DESKTOP_PATTERN = /\bclaude\s+desktop\b/i;
|
|
|
538
541
|
const CLAUDE_DESKTOP_CONFIGURATION_PATTERN = /\b(?:configur(?:e|ation)|setup|set\s*up|gateway|base\s*url|api\s*key|connect(?:ion)?|third[- ]party|inference|field|install|verify)\b/i;
|
|
539
542
|
const CODEX_CLI_PATTERN = /\bcodex(?:\s+cli)?\b/i;
|
|
540
543
|
const CLIENT_CONFIGURATION_PATTERN = /\b(?:configur(?:e|ation)|setup|set\s*up|base\s*url|api\s*key|connect(?:ion)?|provider|install|repair|verify|update)\b/i;
|
|
544
|
+
const HELPER_MUTATION_PATTERN = /(?:^|\b(?:please|can\s+you|could\s+you|help\s+me(?:\s+to)?|i\s+(?:want|need)\s+you\s+to|how\s+(?:do|can)\s+i)\s+)(?:set\s*up|setup|configure|connect|install|repair|fix|update|reconfigure)\b/i;
|
|
545
|
+
const HELPER_VERIFICATION_PATTERN = /(?:^|\b(?:please|can\s+you|could\s+you|help\s+me(?:\s+to)?|i\s+(?:want|need)\s+you\s+to)\s+)(?:verify|check|test|diagnose)\b/i;
|
|
546
|
+
const ALL_CLIENTS_PATTERN = /\b(?:all|every)\b.{0,30}\b(?:client|provider|integration|app)s?\b/i;
|
|
541
547
|
const KNOWN_CONTEXT_REASK_PATTERN = /(?:\b(?:need|send|provide|share|tell)\b.{0,100}\b(?:api\s*(?:key|endpoint)|base\s*url|operating\s+system|\bos\b|model\s+(?:name|catalog))\b|YOUR-SCALEMAX-ENDPOINT|your-key)/is;
|
|
542
548
|
const PROVIDER_IDENTITY_OVERRIDE_PATTERNS = [
|
|
543
549
|
/\bkiro\b/i,
|
|
@@ -558,7 +564,8 @@ const defaultDependencies = {
|
|
|
558
564
|
loadKey: loadApiKey,
|
|
559
565
|
validateKey: validateApiKey,
|
|
560
566
|
complete: createChatCompletion,
|
|
561
|
-
write: message => console.log(message)
|
|
567
|
+
write: message => console.log(message),
|
|
568
|
+
clientCatalog: clients
|
|
562
569
|
};
|
|
563
570
|
export function parseHelperBotArgs(args) {
|
|
564
571
|
let model;
|
|
@@ -630,9 +637,9 @@ Mandatory behavior:
|
|
|
630
637
|
|
|
631
638
|
1. Treat the stored key, base URLs, operating system, provider scope, and model catalog as already known. Do not request them again.
|
|
632
639
|
2. Never output placeholders such as YOUR-SCALEMAX-ENDPOINT or your-key when an exact known value can be used.
|
|
633
|
-
3.
|
|
640
|
+
3. The CLI controller executes recognized safe configuration and verification requests before asking the model. Do not claim that an unrecognized action was executed.
|
|
634
641
|
4. The Helper request itself uses the stored customer key and therefore consumes the small number of tokens used by the selected Helper model. The key is never included in the prompt text.
|
|
635
|
-
5.
|
|
642
|
+
5. When user action is genuinely required, give the shortest exact instruction and clearly distinguish it from work already completed by the CLI controller.`;
|
|
636
643
|
}
|
|
637
644
|
export function helperConnectionSummary(connection) {
|
|
638
645
|
return `Authenticated ${helperBillingMode(connection)} key · ${helperPlatformName(connection.platform)} · ${connection.providerScope || 'both'} scope · ${connection.baseUrl} · helper model ${connection.model}`;
|
|
@@ -685,7 +692,7 @@ export function selectHelperModel(models, requested) {
|
|
|
685
692
|
throw new Error(`Model "${requested}" is not available to this API key. Run \`scalemax models\` to see available models.`);
|
|
686
693
|
return exact.id;
|
|
687
694
|
}
|
|
688
|
-
const preferred = ['gpt-5.
|
|
695
|
+
const preferred = ['gpt-5.4', 'gpt-5.4-mini', 'claude-haiku-4-5-20251001', 'gpt-5.6-luna', 'fable-5', 'gpt-5.6-terra', 'gpt-5.6-sol'];
|
|
689
696
|
for (const id of preferred) {
|
|
690
697
|
const match = models.find(model => model.id.toLowerCase() === id);
|
|
691
698
|
if (match)
|
|
@@ -731,8 +738,170 @@ For automatic configuration, exit with \`/quit\`, run \`scalemax update\`, then
|
|
|
731
738
|
}
|
|
732
739
|
return reply;
|
|
733
740
|
}
|
|
741
|
+
const HELPER_CLIENT_PATTERNS = [
|
|
742
|
+
{ id: 'roo-code', pattern: /\b(?:roo(?:\s+code)?|roo\s+(?:extension|plugin)|vscode\s+roo|vs\s+code\s+roo)\b/i },
|
|
743
|
+
{ id: 'openclaw', pattern: /\bopen\s*claw\b/i },
|
|
744
|
+
{ id: 'opencode', pattern: /\bopen\s*code\b/i },
|
|
745
|
+
{ id: 'cherry-studio', pattern: /\bcherry\s*studio\b/i },
|
|
746
|
+
{ id: 'api-code', pattern: /\bapi\s*code\b/i },
|
|
747
|
+
{ id: 'trae-solo', pattern: /\btrae(?:\s+solo)?\b/i },
|
|
748
|
+
{ id: 'cursor', pattern: /\bcursor\b/i },
|
|
749
|
+
{ id: 'hermes', pattern: /\bhermes\b/i },
|
|
750
|
+
{ id: 'codex', pattern: /\bcodex(?:\s+cli)?\b/i },
|
|
751
|
+
{ id: 'claude', pattern: /\bclaude\s+code\b/i }
|
|
752
|
+
];
|
|
753
|
+
function helperActionKind(question) {
|
|
754
|
+
if (HELPER_MUTATION_PATTERN.test(question))
|
|
755
|
+
return 'configure';
|
|
756
|
+
if (HELPER_VERIFICATION_PATTERN.test(question))
|
|
757
|
+
return 'verify';
|
|
758
|
+
return undefined;
|
|
759
|
+
}
|
|
760
|
+
function helperActionTarget(question) {
|
|
761
|
+
if (CLAUDE_DESKTOP_PATTERN.test(question))
|
|
762
|
+
return undefined;
|
|
763
|
+
if (ALL_CLIENTS_PATTERN.test(question))
|
|
764
|
+
return 'all';
|
|
765
|
+
return HELPER_CLIENT_PATTERNS.find(candidate => candidate.pattern.test(question))?.id;
|
|
766
|
+
}
|
|
767
|
+
function requestedProviderScope(question, target) {
|
|
768
|
+
if (/\b(?:both|openai\s*\+\s*claude|claude\s*\+\s*openai)\b/i.test(question))
|
|
769
|
+
return 'both';
|
|
770
|
+
if (/\b(?:claude|anthropic)\b/i.test(question))
|
|
771
|
+
return 'anthropic';
|
|
772
|
+
if (/\b(?:openai|chatgpt|gpt)\b/i.test(question) || target === 'codex')
|
|
773
|
+
return 'openai';
|
|
774
|
+
return undefined;
|
|
775
|
+
}
|
|
776
|
+
function actionModels(connection, requestedScope) {
|
|
777
|
+
const catalog = connection.modelCatalog?.length
|
|
778
|
+
? connection.modelCatalog
|
|
779
|
+
: (connection.availableModels || []).map(id => ({ id }));
|
|
780
|
+
if (!requestedScope || requestedScope === 'both')
|
|
781
|
+
return catalog;
|
|
782
|
+
return catalog.filter(model => requestedScope === 'anthropic' ? isAnthropicModel(model) : !isAnthropicModel(model));
|
|
783
|
+
}
|
|
784
|
+
function hasRooCodeExtension(paths) {
|
|
785
|
+
return paths.some(candidate => /^rooveterinaryinc\.roo-cline-/i.test(path.basename(candidate)));
|
|
786
|
+
}
|
|
787
|
+
async function installRooCodeExtension(ctx, client, write) {
|
|
788
|
+
let detection = await client.detect(ctx);
|
|
789
|
+
if (hasRooCodeExtension(detection.paths))
|
|
790
|
+
return;
|
|
791
|
+
if (!detection.executable)
|
|
792
|
+
throw new Error('VS Code and the Roo Code extension were not detected. Install VS Code first, then retry this request.');
|
|
793
|
+
write('→ Installing the official Roo Code extension in VS Code…');
|
|
794
|
+
const result = await execa('code', ['--install-extension', 'RooVeterinaryInc.roo-cline', '--force'], {
|
|
795
|
+
env: ctx.env,
|
|
796
|
+
reject: false,
|
|
797
|
+
all: true
|
|
798
|
+
});
|
|
799
|
+
if (result.exitCode !== 0)
|
|
800
|
+
throw new Error(`Roo Code extension installation failed: ${result.all?.trim() || `code exited with ${result.exitCode}`}`);
|
|
801
|
+
detection = await client.detect(ctx);
|
|
802
|
+
if (!hasRooCodeExtension(detection.paths))
|
|
803
|
+
throw new Error('VS Code reported a successful Roo Code installation, but the extension could not be detected afterward. Restart VS Code and retry.');
|
|
804
|
+
write('✓ Roo Code extension installed and detected.');
|
|
805
|
+
}
|
|
806
|
+
async function runOneHelperClientAction(kind, client, connection, home, requestedScope, write) {
|
|
807
|
+
const models = actionModels(connection, requestedScope);
|
|
808
|
+
if (!models.length)
|
|
809
|
+
throw new Error(`The authenticated key does not expose ${requestedScope === 'anthropic' ? 'Claude' : requestedScope === 'openai' ? 'OpenAI' : 'compatible'} models for ${client.name}. No configuration was changed.`);
|
|
810
|
+
if (client.id === 'codex' && models.every(isAnthropicModel))
|
|
811
|
+
throw new Error('Codex requires an OpenAI-compatible model, but this key exposes only Claude models. No configuration was changed.');
|
|
812
|
+
if (client.id === 'cursor' && connection.platform !== 'darwin')
|
|
813
|
+
throw new Error(`Automatic Cursor configuration is currently verified on macOS only. ${helperPlatformName(connection.platform)} was not modified.`);
|
|
814
|
+
const ctx = {
|
|
815
|
+
home,
|
|
816
|
+
platform: connection.platform || process.platform,
|
|
817
|
+
env: process.env,
|
|
818
|
+
apiKey: connection.apiKey,
|
|
819
|
+
baseUrl: connection.baseUrl,
|
|
820
|
+
providerScope: requestedScope || connection.providerScope || 'both',
|
|
821
|
+
models,
|
|
822
|
+
interactive: false,
|
|
823
|
+
allowAppModification: false
|
|
824
|
+
};
|
|
825
|
+
write(`→ Detecting ${client.name}…`);
|
|
826
|
+
let detection = await client.detect(ctx);
|
|
827
|
+
if (kind === 'configure' && client.id === 'roo-code') {
|
|
828
|
+
await installRooCodeExtension(ctx, client, write);
|
|
829
|
+
detection = await client.detect(ctx);
|
|
830
|
+
}
|
|
831
|
+
if (!detection.installed)
|
|
832
|
+
throw new Error(`${client.name} was not detected. No configuration was changed.`);
|
|
833
|
+
write(`✓ ${client.name} detected.`);
|
|
834
|
+
if (kind === 'verify') {
|
|
835
|
+
if (!client.verify) {
|
|
836
|
+
if (!detection.configured)
|
|
837
|
+
throw new Error(`${client.name} is installed but its ScaleMax configuration was not detected.`);
|
|
838
|
+
return `✓ ${client.name} ScaleMax configuration is present.`;
|
|
839
|
+
}
|
|
840
|
+
write(`→ Verifying ${client.name}…`);
|
|
841
|
+
const verified = await client.verify(ctx);
|
|
842
|
+
return `✓ ${client.name} ${verified.message}`;
|
|
843
|
+
}
|
|
844
|
+
write(`→ Configuring ${client.name} with the authenticated stored key…`);
|
|
845
|
+
const configured = await client.configure(ctx);
|
|
846
|
+
write(`✓ ${client.name} ${configured.message}`);
|
|
847
|
+
if (client.verify) {
|
|
848
|
+
write(`→ Verifying ${client.name} configuration…`);
|
|
849
|
+
try {
|
|
850
|
+
const verified = await client.verify(ctx);
|
|
851
|
+
write(`✓ ${client.name} ${verified.message}`);
|
|
852
|
+
}
|
|
853
|
+
catch (error) {
|
|
854
|
+
if (configured.changed) {
|
|
855
|
+
write(`→ Verification failed; removing the incomplete ScaleMax-managed ${client.name} configuration…`);
|
|
856
|
+
await client.remove(ctx).catch(() => undefined);
|
|
857
|
+
}
|
|
858
|
+
throw error;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
else {
|
|
862
|
+
detection = await client.detect(ctx);
|
|
863
|
+
if (!detection.configured)
|
|
864
|
+
throw new Error(`${client.name} configuration was written but could not be detected afterward.`);
|
|
865
|
+
write(`✓ ${client.name} configuration detected after write.`);
|
|
866
|
+
}
|
|
867
|
+
const activation = client.id === 'roo-code' ? ' Reload VS Code once so Roo Code imports the verified ScaleMax profile.' : '';
|
|
868
|
+
return `✅ Successfully completed: ${client.name} is configured and locally verified.${activation}`;
|
|
869
|
+
}
|
|
870
|
+
/** Execute only narrowly allowlisted ScaleMax client actions; never model-generated shell commands. */
|
|
871
|
+
export async function executeHelperAction(question, connection, home, clientCatalog = clients, write = message => console.log(message)) {
|
|
872
|
+
const cleanQuestion = redactHelperSecrets(question.trim(), connection.apiKey);
|
|
873
|
+
if (!isScaleMaxHelperQuestion(cleanQuestion))
|
|
874
|
+
return undefined;
|
|
875
|
+
const kind = helperActionKind(cleanQuestion);
|
|
876
|
+
const target = helperActionTarget(cleanQuestion);
|
|
877
|
+
if (!kind || !target)
|
|
878
|
+
return undefined;
|
|
879
|
+
const scope = requestedProviderScope(cleanQuestion, target);
|
|
880
|
+
const selected = target === 'all'
|
|
881
|
+
? clientCatalog.filter(client => client.id !== 'cursor')
|
|
882
|
+
: clientCatalog.filter(client => client.id === target);
|
|
883
|
+
if (!selected.length)
|
|
884
|
+
throw new Error('The requested ScaleMax integration is not supported by this CLI build.');
|
|
885
|
+
write(`✓ Stored ${helperBillingMode(connection)} key is authenticated; secrets remain hidden.`);
|
|
886
|
+
const completed = [];
|
|
887
|
+
const failures = [];
|
|
888
|
+
for (const client of selected) {
|
|
889
|
+
try {
|
|
890
|
+
completed.push(await runOneHelperClientAction(kind, client, connection, home, scope, write));
|
|
891
|
+
}
|
|
892
|
+
catch (error) {
|
|
893
|
+
const message = redactHelperSecrets(error instanceof Error ? error.message : String(error), connection.apiKey);
|
|
894
|
+
if (target !== 'all')
|
|
895
|
+
throw new Error(message);
|
|
896
|
+
failures.push(`${client.name}: ${message}`);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
if (!completed.length)
|
|
900
|
+
throw new Error(`No ScaleMax client action completed.\n${failures.map(item => `- ${item}`).join('\n')}`);
|
|
901
|
+
return `${completed.join('\n')}${failures.length ? `\n\nSkipped or failed:\n${failures.map(item => `- ${item}`).join('\n')}` : ''}`;
|
|
902
|
+
}
|
|
734
903
|
function printSessionHelp(write) {
|
|
735
|
-
write('Commands: /help shows this help; /status shows the authenticated non-secret connection details; /quit exits.
|
|
904
|
+
write('Commands: /help shows this help; /status shows the authenticated non-secret connection details; /quit exits. Setup, repair, and verification requests for supported clients are executed automatically with progress notifications.');
|
|
736
905
|
}
|
|
737
906
|
export async function helperBotCommand(args = [], home = homeDir(), dependencies = {}) {
|
|
738
907
|
const deps = { ...defaultDependencies, ...dependencies };
|
|
@@ -751,10 +920,15 @@ export async function helperBotCommand(args = [], home = homeDir(), dependencies
|
|
|
751
920
|
platform: process.platform,
|
|
752
921
|
providerScope: validation.key?.provider_scope || 'both',
|
|
753
922
|
keyMode: validation.key?.mode,
|
|
754
|
-
availableModels: validation.models.map(item => item.id)
|
|
923
|
+
availableModels: validation.models.map(item => item.id),
|
|
924
|
+
modelCatalog: validation.models
|
|
925
|
+
};
|
|
926
|
+
const respond = async (question, history) => {
|
|
927
|
+
const action = await executeHelperAction(question, connection, home, deps.clientCatalog, deps.write);
|
|
928
|
+
return action || requestHelperReply(question, history, connection, deps.complete);
|
|
755
929
|
};
|
|
756
930
|
if (options.question) {
|
|
757
|
-
deps.write(await
|
|
931
|
+
deps.write(await respond(options.question, []));
|
|
758
932
|
return;
|
|
759
933
|
}
|
|
760
934
|
if (!process.stdin.isTTY)
|
|
@@ -787,7 +961,7 @@ export async function helperBotCommand(args = [], home = homeDir(), dependencies
|
|
|
787
961
|
continue;
|
|
788
962
|
}
|
|
789
963
|
try {
|
|
790
|
-
const reply = await
|
|
964
|
+
const reply = await respond(input, history);
|
|
791
965
|
deps.write(reply);
|
|
792
966
|
if (reply !== SCALEMAX_HELPER_REFUSAL) {
|
|
793
967
|
history.push({ role: 'user', content: redactHelperSecrets(input, key) }, { role: 'assistant', content: reply });
|
package/dist/index.js
CHANGED
|
@@ -34,7 +34,7 @@ function welcome() {
|
|
|
34
34
|
}
|
|
35
35
|
function printHelp(command) {
|
|
36
36
|
if (command === 'helper-bot') {
|
|
37
|
-
console.log('Usage: scalemax helper-bot [--model <id>] ["question"]\n\
|
|
37
|
+
console.log('Usage: scalemax helper-bot [--model <id>] ["question"]\n\nExecute safe ScaleMax setup and verification actions, or open the ScaleMax-only troubleshooting assistant.');
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
40
|
const details = { update: 'Revalidate the API key and reconfigure every detected client.', remove: 'Restore backups or remove only ScaleMax-managed client configuration.', doctor: 'Validate the API key and verify detected client configuration.', models: 'List models available to the stored API key.', login: 'Store or replace the ScaleMax API key.', logout: 'Remove the locally stored ScaleMax API key.' };
|
|
@@ -52,7 +52,7 @@ Commands:
|
|
|
52
52
|
scalemax logout Remove API key
|
|
53
53
|
scalemax doctor Run diagnostics
|
|
54
54
|
scalemax models List available models
|
|
55
|
-
scalemax helper-bot
|
|
55
|
+
scalemax helper-bot Execute setup actions or open the ScaleMax Helper
|
|
56
56
|
scalemax update Reconfigure detected clients
|
|
57
57
|
scalemax remove Remove ScaleMax-generated configs
|
|
58
58
|
scalemax --version Show installed version
|