scalemax 0.1.51 → 0.1.53

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.
@@ -7,6 +7,8 @@ export declare const ROO_MAX_OUTPUT_TOKENS = 32768;
7
7
  * a broken key. Same advice as the docs' Roo Code guide and troubleshooting page.
8
8
  */
9
9
  export declare const ROO_CODE_MODE_TIP = "Run tasks in Code or Debug mode. Ask and Architect modes cannot run terminal commands, so Roo says \"terminal tools are not available\" there. Switch modes; nothing is wrong with your key.";
10
+ /** Roo Code 3.54's built-in mode slugs. */
11
+ export declare const ROO_BUILT_IN_MODES: readonly ["code", "architect", "ask", "debug", "orchestrator"];
10
12
  export declare function configure(ctx: ConfigureContext): Promise<ConfigureResult>;
11
13
  export declare function verify(ctx: ConfigureContext): Promise<ConfigureResult>;
12
14
  export declare function remove(ctx: RemoveContext): Promise<ConfigureResult>;
@@ -2,10 +2,10 @@ import path from 'node:path';
2
2
  import fs from 'fs-extra';
3
3
  import JSON5 from 'json5';
4
4
  import { atomicWrite, backupFile, captureFileSnapshots, restoreFileSnapshots, snapshotRollback } from '../utils/fs.js';
5
- import { clientConfigPath } from './paths.js';
6
5
  import { anthropicModelIds, deepSeekChatModelIds, isDeepSeekChatModelId, modelIdKey, modelName, modelSupportsTools, openAiBaseUrl, openAiResponsesModelIds, preferredAnthropicModel, preferredChatCompletionsModel, preferredOpenAiResponsesModel } from './models.js';
7
6
  import { isAnthropicModel } from '../utils/api.js';
8
7
  import { rooRipgrepRepairNote } from '../repair/roo-ripgrep.js';
8
+ import { rooSettingsTargets } from '../detect/roo-code.js';
9
9
  const id = 'roo-code';
10
10
  const name = 'Roo Code (VS Code)';
11
11
  const importSetting = 'roo-cline.autoImportSettingsPath';
@@ -30,6 +30,8 @@ export const ROO_MAX_OUTPUT_TOKENS = 32_768;
30
30
  * a broken key. Same advice as the docs' Roo Code guide and troubleshooting page.
31
31
  */
32
32
  export const ROO_CODE_MODE_TIP = 'Run tasks in Code or Debug mode. Ask and Architect modes cannot run terminal commands, so Roo says "terminal tools are not available" there. Switch modes; nothing is wrong with your key.';
33
+ /** Roo Code 3.54's built-in mode slugs. */
34
+ export const ROO_BUILT_IN_MODES = ['code', 'architect', 'ask', 'debug', 'orchestrator'];
33
35
  function exactChatProfile(ctx, model) {
34
36
  if (modelIdKey(model) === 'glm-5.2')
35
37
  return { name: glmProfileName, id: glmProfileId, model };
@@ -147,7 +149,12 @@ function handoff(ctx) {
147
149
  providerProfiles: {
148
150
  currentApiConfigName: current.name,
149
151
  apiConfigs,
150
- modeApiConfigs: {}
152
+ // Roo remembers a profile PER MODE, and a fresh install binds Code mode
153
+ // to its own empty "default" (OpenRouter) profile on first activation.
154
+ // With an empty map the import selected ScaleMax for the current mode
155
+ // only, so the first switch to Code mode sent the task to OpenRouter
156
+ // ("401 Missing Authentication header"). Pin every built-in mode.
157
+ modeApiConfigs: Object.fromEntries(ROO_BUILT_IN_MODES.map(mode => [mode, current.id]))
151
158
  },
152
159
  globalSettings: {
153
160
  // Roo 3.54 still probes an obsolete bundled-ripgrep path while building
@@ -167,23 +174,30 @@ export async function configure(ctx) {
167
174
  return note ? { ...result, note } : result;
168
175
  }
169
176
  async function configureHandoff(ctx) {
170
- const settingsFile = clientConfigPath(id, ctx.home, ctx.platform, ctx.env);
177
+ const targets = await rooSettingsTargets(ctx.home, ctx.platform, ctx.env);
171
178
  const profileFile = importPath(ctx.home);
172
- const snapshots = await captureFileSnapshots([settingsFile, profileFile]);
173
- const originalSettings = await fs.readFile(settingsFile, 'utf8').catch(() => '');
179
+ const snapshots = await captureFileSnapshots([...targets.map(target => target.settingsFile), profileFile]);
174
180
  const originalProfile = await fs.readFile(profileFile, 'utf8').catch(() => '');
175
- const settings = parseSettings(originalSettings, settingsFile);
176
- const nextSettings = JSON.stringify({ ...settings, [importSetting]: importSettingValue }, null, 2) + '\n';
181
+ const writes = [];
182
+ for (const target of targets) {
183
+ const original = await fs.readFile(target.settingsFile, 'utf8').catch(() => '');
184
+ const next = JSON.stringify({ ...parseSettings(original, target.settingsFile), [importSetting]: importSettingValue }, null, 2) + '\n';
185
+ if (original !== next)
186
+ writes.push({ file: target.settingsFile, text: next });
187
+ }
177
188
  const nextProfile = handoff(ctx);
178
- if (originalSettings === nextSettings && originalProfile === nextProfile) {
189
+ const editors = targets.map(target => target.editor).join(', ');
190
+ if (!writes.length && originalProfile === nextProfile) {
179
191
  await fs.chmod(profileFile, 0o600).catch(() => undefined);
180
- return { id, name, changed: false, path: profileFile, message: 'supported Roo Code auto-import handoff is already current; reload VS Code to consume it', tip: ROO_CODE_MODE_TIP };
192
+ return { id, name, changed: false, path: profileFile, message: `supported Roo Code auto-import handoff is already current (${editors}); reload the editor to consume it`, tip: ROO_CODE_MODE_TIP };
181
193
  }
182
- await backupFile(settingsFile, ctx.home);
194
+ for (const write of writes)
195
+ await backupFile(write.file, ctx.home);
183
196
  await backupFile(profileFile, ctx.home);
184
197
  try {
185
198
  await atomicWrite(profileFile, nextProfile, 0o600, ctx.platform);
186
- await atomicWrite(settingsFile, nextSettings, 0o600, ctx.platform);
199
+ for (const write of writes)
200
+ await atomicWrite(write.file, write.text, 0o600, ctx.platform);
187
201
  }
188
202
  catch (error) {
189
203
  try {
@@ -199,19 +213,23 @@ async function configureHandoff(ctx) {
199
213
  name,
200
214
  changed: true,
201
215
  path: profileFile,
202
- message: 'created a private, supported auto-import handoff; reload VS Code so Roo Code imports the profile into SecretStorage',
216
+ message: `created a private, supported auto-import handoff for ${editors}; reload the editor so Roo Code imports the profile into SecretStorage`,
203
217
  tip: ROO_CODE_MODE_TIP,
204
218
  rollback: snapshotRollback(snapshots, ctx.platform),
205
219
  };
206
220
  }
207
221
  export async function verify(ctx) {
208
- const settingsFile = clientConfigPath(id, ctx.home, ctx.platform, ctx.env);
209
222
  const profileFile = importPath(ctx.home);
210
- const settings = parseSettings(await fs.readFile(settingsFile, 'utf8'), settingsFile);
223
+ let handoffSet = true;
224
+ for (const target of await rooSettingsTargets(ctx.home, ctx.platform, ctx.env)) {
225
+ const settings = parseSettings(await fs.readFile(target.settingsFile, 'utf8'), target.settingsFile);
226
+ if (settings[importSetting] !== importSettingValue)
227
+ handoffSet = false;
228
+ }
211
229
  const profile = await fs.readJson(profileFile).catch(() => undefined);
212
230
  const expectedProfiles = profilesFor(ctx);
213
231
  const current = currentProfileFor(ctx, expectedProfiles);
214
- if (settings[importSetting] !== importSettingValue || profile?.providerProfiles?.currentApiConfigName !== current.name) {
232
+ if (!handoffSet || profile?.providerProfiles?.currentApiConfigName !== current.name) {
215
233
  throw new Error('Roo Code auto-import handoff is incomplete.');
216
234
  }
217
235
  if (profile?.globalSettings?.maxWorkspaceFiles !== 0) {
@@ -232,10 +250,11 @@ export async function verify(ctx) {
232
250
  return { id, name, changed: false, path: profileFile, message: 'verified supported auto-import handoff (runtime activation requires a VS Code reload)' };
233
251
  }
234
252
  export async function remove(ctx) {
235
- const settingsFile = clientConfigPath(id, ctx.home, ctx.platform, ctx.env);
236
253
  const profileFile = importPath(ctx.home);
237
254
  let changed = false;
238
- if (await fs.pathExists(settingsFile)) {
255
+ for (const { settingsFile } of await rooSettingsTargets(ctx.home, ctx.platform, ctx.env)) {
256
+ if (!(await fs.pathExists(settingsFile)))
257
+ continue;
239
258
  const text = await fs.readFile(settingsFile, 'utf8');
240
259
  const settings = parseSettings(text, settingsFile);
241
260
  if (settings[importSetting] === importSettingValue) {
@@ -5,6 +5,13 @@ export interface EditorExtensionRoot {
5
5
  editor: string;
6
6
  /** Path segments below the home folder. */
7
7
  segments: readonly string[];
8
+ /**
9
+ * The editor's user-data folder name under the platform config root
10
+ * (%APPDATA% / ~/Library/Application Support / ~/.config), whose
11
+ * `User/settings.json` Roo Code reads. Absent for remote servers, which have
12
+ * no local settings file of their own.
13
+ */
14
+ userDir?: string;
8
15
  }
9
16
  /**
10
17
  * VS Code's own per-user extension folders. Detection stays limited to these
@@ -17,6 +24,18 @@ export declare const VSCODE_EXTENSION_ROOTS: readonly EditorExtensionRoot[];
17
24
  * installed extension itself rather than writing editor settings.
18
25
  */
19
26
  export declare const ALL_EDITOR_EXTENSION_ROOTS: readonly EditorExtensionRoot[];
27
+ export interface RooSettingsTarget {
28
+ editor: string;
29
+ /** That editor's user settings.json, which holds roo-cline.autoImportSettingsPath. */
30
+ settingsFile: string;
31
+ }
32
+ /**
33
+ * Every settings.json Roo Code reads its auto-import path from: VS Code's
34
+ * (always, as before) plus each VS Code-family editor that has Roo Code
35
+ * installed. A fork reads only its own settings.json, so writing VS Code's
36
+ * alone left Roo in Antigravity, Cursor or Windsurf unconfigured.
37
+ */
38
+ export declare function rooSettingsTargets(home: string, platform: NodeJS.Platform, env?: NodeJS.ProcessEnv): Promise<RooSettingsTarget[]>;
20
39
  export interface RooExtensionDir {
21
40
  editor: string;
22
41
  /** Absolute extension folder, e.g. ~/.vscode/extensions/rooveterinaryinc.roo-cline-3.54.0 */
@@ -3,14 +3,15 @@ import fs from 'fs-extra';
3
3
  import JSON5 from 'json5';
4
4
  import { commandExists } from '../utils/exec.js';
5
5
  import { clientConfigPath } from '../configure/paths.js';
6
+ import { configRoot } from '../utils/paths.js';
6
7
  export const ROO_EXTENSION_PATTERN = /^rooveterinaryinc\.roo-cline-/i;
7
8
  /**
8
9
  * VS Code's own per-user extension folders. Detection stays limited to these
9
10
  * because configure writes VS Code's settings.json, which forks do not read.
10
11
  */
11
12
  export const VSCODE_EXTENSION_ROOTS = [
12
- { editor: 'VS Code', segments: ['.vscode', 'extensions'] },
13
- { editor: 'VS Code Insiders', segments: ['.vscode-insiders', 'extensions'] },
13
+ { editor: 'VS Code', segments: ['.vscode', 'extensions'], userDir: 'Code' },
14
+ { editor: 'VS Code Insiders', segments: ['.vscode-insiders', 'extensions'], userDir: 'Code - Insiders' },
14
15
  ];
15
16
  /**
16
17
  * Every per-user extension folder Roo Code can be installed into: VS Code,
@@ -19,14 +20,36 @@ export const VSCODE_EXTENSION_ROOTS = [
19
20
  */
20
21
  export const ALL_EDITOR_EXTENSION_ROOTS = [
21
22
  ...VSCODE_EXTENSION_ROOTS,
22
- { editor: 'Cursor', segments: ['.cursor', 'extensions'] },
23
- { editor: 'Windsurf', segments: ['.windsurf', 'extensions'] },
24
- { editor: 'VSCodium', segments: ['.vscode-oss', 'extensions'] },
23
+ { editor: 'Cursor', segments: ['.cursor', 'extensions'], userDir: 'Cursor' },
24
+ { editor: 'Windsurf', segments: ['.windsurf', 'extensions'], userDir: 'Windsurf' },
25
+ { editor: 'VSCodium', segments: ['.vscode-oss', 'extensions'], userDir: 'VSCodium' },
25
26
  { editor: 'VS Code Server', segments: ['.vscode-server', 'extensions'] },
26
27
  { editor: 'Cursor Server', segments: ['.cursor-server', 'extensions'] },
27
- { editor: 'Trae', segments: ['.trae', 'extensions'] },
28
- { editor: 'Kiro', segments: ['.kiro', 'extensions'] },
28
+ { editor: 'Trae', segments: ['.trae', 'extensions'], userDir: 'Trae' },
29
+ { editor: 'Kiro', segments: ['.kiro', 'extensions'], userDir: 'Kiro' },
30
+ // Google Antigravity (VS Code fork, Open VSX). Product.json on Windows,
31
+ // 2.5.5: dataFolderName ".antigravity-ide", user data "%APPDATA%\Antigravity IDE".
32
+ { editor: 'Antigravity IDE', segments: ['.antigravity-ide', 'extensions'], userDir: 'Antigravity IDE' },
33
+ { editor: 'Antigravity', segments: ['.antigravity', 'extensions'], userDir: 'Antigravity' },
29
34
  ];
35
+ /**
36
+ * Every settings.json Roo Code reads its auto-import path from: VS Code's
37
+ * (always, as before) plus each VS Code-family editor that has Roo Code
38
+ * installed. A fork reads only its own settings.json, so writing VS Code's
39
+ * alone left Roo in Antigravity, Cursor or Windsurf unconfigured.
40
+ */
41
+ export async function rooSettingsTargets(home, platform, env = process.env) {
42
+ const targets = [{ editor: 'VS Code', settingsFile: clientConfigPath('roo-code', home, platform, env) }];
43
+ const root = configRoot(home, platform, env);
44
+ const forks = ALL_EDITOR_EXTENSION_ROOTS.filter(entry => entry.userDir && entry.editor !== 'VS Code');
45
+ for (const hit of await findRooExtensionDirs(home, forks)) {
46
+ const fork = forks.find(entry => entry.editor === hit.editor);
47
+ const settingsFile = path.join(root, fork.userDir, 'User', 'settings.json');
48
+ if (!targets.some(target => target.settingsFile === settingsFile))
49
+ targets.push({ editor: hit.editor, settingsFile });
50
+ }
51
+ return targets;
52
+ }
30
53
  /** Roo Code extension folders under the given roots; missing roots are skipped. */
31
54
  export async function findRooExtensionDirs(home, roots = VSCODE_EXTENSION_ROOTS) {
32
55
  const hits = [];
@@ -42,7 +65,7 @@ export async function findRooExtensionDirs(home, roots = VSCODE_EXTENSION_ROOTS)
42
65
  return hits;
43
66
  }
44
67
  export async function detect(ctx) {
45
- const paths = (await findRooExtensionDirs(ctx.home)).map(hit => hit.dir);
68
+ const paths = (await findRooExtensionDirs(ctx.home, ALL_EDITOR_EXTENSION_ROOTS.filter(entry => entry.userDir))).map(hit => hit.dir);
46
69
  const executable = await commandExists('code', ctx.env);
47
70
  if (executable)
48
71
  paths.unshift('command:code');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scalemax",
3
- "version": "0.1.51",
3
+ "version": "0.1.53",
4
4
  "description": "Universal ScaleMax installer for AI coding clients",
5
5
  "type": "module",
6
6
  "bin": {