claude-multi 0.6.4 → 0.8.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 (3) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/dist/cli.js +1047 -672
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -7300,15 +7300,31 @@ function getApiKeyPlaceholder(providerName) {
7300
7300
  return prefix ? `${prefix}...` : "sk-...";
7301
7301
  }
7302
7302
  function providerHasRegions(providerName) {
7303
- return providerName === "mimo-token";
7303
+ return providerName in PROVIDER_REGION_MAPS;
7304
+ }
7305
+ function getProviderRegions(providerName) {
7306
+ return PROVIDER_REGION_MAPS[providerName];
7307
+ }
7308
+ function detectRegionFromBaseUrl(baseUrl) {
7309
+ for (const regionMap of Object.values(PROVIDER_REGION_MAPS)) {
7310
+ for (const [regionCode, config] of Object.entries(regionMap)) {
7311
+ const escaped = config.baseUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7312
+ const regex = new RegExp(`^${escaped}/?$`);
7313
+ if (regex.test(baseUrl)) {
7314
+ return regionCode;
7315
+ }
7316
+ }
7317
+ }
7318
+ return null;
7304
7319
  }
7305
7320
  function resolveRegionTemplate(template, region) {
7306
7321
  if (!providerHasRegions(template.name)) {
7307
7322
  return template;
7308
7323
  }
7309
- const regionConfig = MIMO_TOKEN_REGIONS[region];
7324
+ const regionMap = PROVIDER_REGION_MAPS[template.name];
7325
+ const regionConfig = regionMap?.[region];
7310
7326
  if (!regionConfig) {
7311
- throw new Error(`Unknown region '${region}' for ${template.name}. Available: ${Object.keys(MIMO_TOKEN_REGIONS).join(", ")}`);
7327
+ throw new Error(`Unknown region '${region}' for ${template.name}. Available: ${regionMap ? Object.keys(regionMap).join(", ") : "none"}`);
7312
7328
  }
7313
7329
  const resolved = structuredClone(template);
7314
7330
  resolved.settings.env.ANTHROPIC_BASE_URL = regionConfig.baseUrl;
@@ -7338,7 +7354,8 @@ function getProviderByBaseUrl(baseUrl) {
7338
7354
  if (baseUrl === templateUrl)
7339
7355
  return name;
7340
7356
  }
7341
- if (baseUrl.startsWith("https://token-plan-") && baseUrl.endsWith(".xiaomimimo.com/anthropic")) {
7357
+ const regionCode = detectRegionFromBaseUrl(baseUrl);
7358
+ if (regionCode) {
7342
7359
  return "mimo-token";
7343
7360
  }
7344
7361
  return null;
@@ -7357,7 +7374,7 @@ function detectProvider(configDir) {
7357
7374
  return null;
7358
7375
  }
7359
7376
  }
7360
- var PROVIDER_COMMON_ENV, PROVIDER_TEMPLATES, API_KEY_PREFIXES, MIMO_TOKEN_REGIONS;
7377
+ var PROVIDER_COMMON_ENV, PROVIDER_TEMPLATES, API_KEY_PREFIXES, MIMO_TOKEN_REGIONS, PROVIDER_REGION_MAPS;
7361
7378
  var init_templates = __esm(() => {
7362
7379
  PROVIDER_COMMON_ENV = {};
7363
7380
  PROVIDER_TEMPLATES = {
@@ -7379,7 +7396,9 @@ var init_templates = __esm(() => {
7379
7396
  REASONING_EFFORT: "high",
7380
7397
  MAX_THINKING_TOKENS: "8000",
7381
7398
  ENABLE_STREAMING: "true",
7382
- MAX_OUTPUT_TOKENS: "64000"
7399
+ MAX_OUTPUT_TOKENS: "64000",
7400
+ CLAUDE_CODE_AUTO_COMPACT_WINDOW: "131072",
7401
+ CLAUDE_AUTOCOMPACT_PCT_OVERRIDE: "75"
7383
7402
  },
7384
7403
  includeCoAuthoredBy: false,
7385
7404
  alwaysThinkingEnabled: false
@@ -7388,25 +7407,26 @@ var init_templates = __esm(() => {
7388
7407
  minimax: {
7389
7408
  name: "minimax",
7390
7409
  displayName: "MiniMax",
7391
- description: "MiniMax-M2.7 model via minimax.io",
7410
+ description: "MiniMax-M3 — 1M context, frontier coding/agentic, native multimodal — via minimax.io",
7392
7411
  settings: {
7393
7412
  env: {
7394
7413
  ANTHROPIC_AUTH_TOKEN: "",
7395
7414
  ANTHROPIC_BASE_URL: "https://api.minimax.io/anthropic",
7396
7415
  API_TIMEOUT_MS: "3000000",
7397
7416
  CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1",
7398
- ANTHROPIC_MODEL: "MiniMax-M2.7",
7399
- ANTHROPIC_SMALL_FAST_MODEL: "MiniMax-M2.7",
7400
- ANTHROPIC_DEFAULT_SONNET_MODEL: "MiniMax-M2.7",
7401
- ANTHROPIC_DEFAULT_OPUS_MODEL: "MiniMax-M2.7",
7402
- ANTHROPIC_DEFAULT_HAIKU_MODEL: "MiniMax-M2.7",
7417
+ ANTHROPIC_MODEL: "MiniMax-M3",
7418
+ ANTHROPIC_SMALL_FAST_MODEL: "MiniMax-M3",
7419
+ ANTHROPIC_DEFAULT_SONNET_MODEL: "MiniMax-M3",
7420
+ ANTHROPIC_DEFAULT_OPUS_MODEL: "MiniMax-M3",
7421
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: "MiniMax-M3",
7403
7422
  ENABLE_THINKING: "true",
7404
7423
  REASONING_EFFORT: "high",
7405
- MAX_OUTPUT_TOKENS: "64000",
7406
- MAX_THINKING_TOKENS: "32000"
7424
+ MAX_OUTPUT_TOKENS: "512000",
7425
+ MAX_THINKING_TOKENS: "32000",
7426
+ CLAUDE_CODE_EFFORT_LEVEL: "max"
7407
7427
  },
7408
7428
  includeCoAuthoredBy: false,
7409
- alwaysThinkingEnabled: true
7429
+ alwaysThinkingEnabled: false
7410
7430
  }
7411
7431
  },
7412
7432
  deepseek: {
@@ -7493,7 +7513,9 @@ var init_templates = __esm(() => {
7493
7513
  ENABLE_THINKING: "true",
7494
7514
  REASONING_EFFORT: "high",
7495
7515
  MAX_THINKING_TOKENS: "16000",
7496
- MAX_OUTPUT_TOKENS: "65536"
7516
+ MAX_OUTPUT_TOKENS: "65536",
7517
+ CLAUDE_CODE_AUTO_COMPACT_WINDOW: "131072",
7518
+ CLAUDE_AUTOCOMPACT_PCT_OVERRIDE: "75"
7497
7519
  },
7498
7520
  includeCoAuthoredBy: false,
7499
7521
  alwaysThinkingEnabled: false
@@ -7516,7 +7538,9 @@ var init_templates = __esm(() => {
7516
7538
  ENABLE_THINKING: "true",
7517
7539
  REASONING_EFFORT: "high",
7518
7540
  MAX_THINKING_TOKENS: "16000",
7519
- MAX_OUTPUT_TOKENS: "65536"
7541
+ MAX_OUTPUT_TOKENS: "65536",
7542
+ CLAUDE_CODE_AUTO_COMPACT_WINDOW: "131072",
7543
+ CLAUDE_AUTOCOMPACT_PCT_OVERRIDE: "75"
7520
7544
  },
7521
7545
  includeCoAuthoredBy: false,
7522
7546
  alwaysThinkingEnabled: false
@@ -7539,7 +7563,9 @@ var init_templates = __esm(() => {
7539
7563
  ENABLE_THINKING: "true",
7540
7564
  REASONING_EFFORT: "high",
7541
7565
  MAX_THINKING_TOKENS: "16000",
7542
- MAX_OUTPUT_TOKENS: "65536"
7566
+ MAX_OUTPUT_TOKENS: "65536",
7567
+ CLAUDE_CODE_AUTO_COMPACT_WINDOW: "131072",
7568
+ CLAUDE_AUTOCOMPACT_PCT_OVERRIDE: "75"
7543
7569
  },
7544
7570
  includeCoAuthoredBy: false,
7545
7571
  alwaysThinkingEnabled: false
@@ -7563,6 +7589,9 @@ var init_templates = __esm(() => {
7563
7589
  baseUrl: "https://token-plan-ams.xiaomimimo.com/anthropic"
7564
7590
  }
7565
7591
  };
7592
+ PROVIDER_REGION_MAPS = {
7593
+ "mimo-token": MIMO_TOKEN_REGIONS
7594
+ };
7566
7595
  });
7567
7596
 
7568
7597
  // src/util/json-file.ts
@@ -7665,6 +7694,22 @@ var init_constants = __esm(() => {
7665
7694
  };
7666
7695
  });
7667
7696
 
7697
+ // src/constants/env.ts
7698
+ var TUNABLE_ENV_VARS;
7699
+ var init_env = __esm(() => {
7700
+ TUNABLE_ENV_VARS = new Set([
7701
+ "MAX_OUTPUT_TOKENS",
7702
+ "MAX_THINKING_TOKENS",
7703
+ "REASONING_EFFORT",
7704
+ "ENABLE_THINKING",
7705
+ "ENABLE_STREAMING",
7706
+ "API_TIMEOUT_MS",
7707
+ "CLAUDE_CODE_EFFORT_LEVEL",
7708
+ "CLAUDE_CODE_AUTO_COMPACT_WINDOW",
7709
+ "CLAUDE_AUTOCOMPACT_PCT_OVERRIDE"
7710
+ ]);
7711
+ });
7712
+
7668
7713
  // node_modules/semver/internal/constants.js
7669
7714
  var require_constants = __commonJS((exports, module) => {
7670
7715
  var SEMVER_SPEC_VERSION = "2.0.0";
@@ -9492,22 +9537,11 @@ var require_semver2 = __commonJS((exports, module) => {
9492
9537
  });
9493
9538
 
9494
9539
  // src/paths.ts
9495
- var exports_paths = {};
9496
- __export(exports_paths, {
9497
- getBaseDir: () => getBaseDir,
9498
- PINNED_CLAUDE_BIN: () => PINNED_CLAUDE_BIN,
9499
- PINNED_BIN_DIR: () => PINNED_BIN_DIR
9500
- });
9501
9540
  import { homedir } from "node:os";
9502
- import { join as join2 } from "node:path";
9503
9541
  function getBaseDir() {
9504
9542
  return process.env.CLAUDE_MULTI_HOME || homedir();
9505
9543
  }
9506
- var PINNED_BIN_DIR, PINNED_CLAUDE_BIN;
9507
- var init_paths = __esm(() => {
9508
- PINNED_BIN_DIR = join2(homedir(), ".claude-multi", "bin");
9509
- PINNED_CLAUDE_BIN = process.platform === "win32" ? join2(PINNED_BIN_DIR, "node_modules", ".bin", "claude.cmd") : join2(PINNED_BIN_DIR, "node_modules", ".bin", "claude");
9510
- });
9544
+ var init_paths = () => {};
9511
9545
 
9512
9546
  // src/util/runtime.ts
9513
9547
  function detectPackageManager() {
@@ -9521,27 +9555,12 @@ function detectPackageManager() {
9521
9555
  }
9522
9556
 
9523
9557
  // src/version.ts
9524
- var exports_version = {};
9525
- __export(exports_version, {
9526
- upgradeClaudeMulti: () => upgradeClaudeMulti,
9527
- updateClaudeCode: () => updateClaudeCode,
9528
- isThirdPartyApiBroken: () => isThirdPartyApiBroken,
9529
- installPinnedClaude: () => installPinnedClaude,
9530
- getPinnedBinaryVersion: () => getPinnedBinaryVersion,
9531
- getLatestVersion: () => getLatestVersion,
9532
- getLatestClaudeMultiVersion: () => getLatestClaudeMultiVersion,
9533
- getCurrentVersion: () => getCurrentVersion,
9534
- getClaudeMultiVersion: () => getClaudeMultiVersion,
9535
- checkForUpdates: () => checkForUpdates,
9536
- checkForClaudeMultiUpdates: () => checkForClaudeMultiUpdates,
9537
- COMPATIBLE_CLAUDE_VERSION: () => COMPATIBLE_CLAUDE_VERSION
9538
- });
9539
9558
  import { execSync } from "node:child_process";
9540
- import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync, mkdirSync } from "node:fs";
9541
- import { join as join3, dirname } from "node:path";
9559
+ import { readFileSync as readFileSync2 } from "node:fs";
9560
+ import { join as join2, dirname } from "node:path";
9542
9561
  import { fileURLToPath } from "node:url";
9543
9562
  function getClaudeMultiVersion() {
9544
- const pkgPath = join3(dirname(fileURLToPath(import.meta.url)), "..", "package.json");
9563
+ const pkgPath = join2(dirname(fileURLToPath(import.meta.url)), "..", "package.json");
9545
9564
  const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
9546
9565
  if (typeof pkg !== "object" || pkg === null || typeof pkg.version !== "string") {
9547
9566
  throw new ClaudeMultiError(ErrorCode.CONFIG_CORRUPTED, "Could not read package version");
@@ -9601,40 +9620,6 @@ function getCurrentVersion() {
9601
9620
  return null;
9602
9621
  }
9603
9622
  }
9604
- function isThirdPartyApiBroken(version) {
9605
- return import_semver.default.gte(version, "2.1.154") && import_semver.default.lt(version, "2.1.156");
9606
- }
9607
- function getPinnedBinaryVersion() {
9608
- const pkgJsonPath = join3(PINNED_BIN_DIR, "node_modules", "@anthropic-ai", "claude-code", "package.json");
9609
- try {
9610
- if (!existsSync2(pkgJsonPath))
9611
- return null;
9612
- const pkg = JSON.parse(readFileSync2(pkgJsonPath, "utf-8"));
9613
- return pkg.version ?? null;
9614
- } catch {
9615
- return null;
9616
- }
9617
- }
9618
- function installPinnedClaude() {
9619
- const pm = detectPackageManager();
9620
- mkdirSync(PINNED_BIN_DIR, { recursive: true });
9621
- const pkgJsonPath = join3(PINNED_BIN_DIR, "package.json");
9622
- if (!existsSync2(pkgJsonPath)) {
9623
- writeFileSync(pkgJsonPath, JSON.stringify({ dependencies: {} }, null, 2));
9624
- }
9625
- const pkg = `@anthropic-ai/claude-code@${COMPATIBLE_CLAUDE_VERSION}`;
9626
- const commands = {
9627
- bun: `bun add --cwd ${PINNED_BIN_DIR} ${pkg}`,
9628
- npm: `npm install --prefix ${PINNED_BIN_DIR} ${pkg}`,
9629
- pnpm: `pnpm add --dir ${PINNED_BIN_DIR} ${pkg}`,
9630
- deno: `cd ${PINNED_BIN_DIR} && npm install ${pkg}`
9631
- };
9632
- try {
9633
- execSync(commands[pm], { stdio: "inherit" });
9634
- } catch (err) {
9635
- throw new ClaudeMultiError(ErrorCode.UPDATE_FAILED, `Failed to install pinned Claude v${COMPATIBLE_CLAUDE_VERSION}: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
9636
- }
9637
- }
9638
9623
  async function getLatestVersion() {
9639
9624
  try {
9640
9625
  const response = await fetch("https://registry.npmjs.org/@anthropic-ai/claude-code/latest");
@@ -9669,20 +9654,15 @@ function updateClaudeCode() {
9669
9654
  throw new ClaudeMultiError(ErrorCode.UPDATE_FAILED, `Failed to update @anthropic-ai/claude-code: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
9670
9655
  }
9671
9656
  }
9672
- var import_semver, COMPATIBLE_CLAUDE_VERSION = "2.1.156";
9673
9657
  var init_version = __esm(() => {
9674
9658
  init_errors();
9675
- init_paths();
9676
- import_semver = __toESM(require_semver2(), 1);
9677
9659
  });
9678
9660
 
9679
9661
  // src/wrapper.ts
9680
9662
  var exports_wrapper = {};
9681
9663
  __export(exports_wrapper, {
9682
- tryGetGlobalClaudePath: () => tryGetGlobalClaudePath,
9683
9664
  tryGetClaudePath: () => tryGetClaudePath,
9684
9665
  removeWrapper: () => removeWrapper,
9685
- getGlobalClaudePath: () => getGlobalClaudePath,
9686
9666
  getDefaultBinaryPath: () => getDefaultBinaryPath,
9687
9667
  getClaudePath: () => getClaudePath,
9688
9668
  generateWrapperScriptSafe: () => generateWrapperScriptSafe,
@@ -9691,7 +9671,7 @@ __export(exports_wrapper, {
9691
9671
  createWrapper: () => createWrapper,
9692
9672
  buildWrapperScript: () => buildWrapperScript
9693
9673
  });
9694
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, chmodSync, unlinkSync } from "node:fs";
9674
+ import { existsSync as existsSync2, mkdirSync, chmodSync, unlinkSync } from "node:fs";
9695
9675
  import { writeFile as writeFile2 } from "node:fs/promises";
9696
9676
  import { resolve, dirname as dirname2 } from "node:path";
9697
9677
  import { execSync as execSync2 } from "node:child_process";
@@ -9699,19 +9679,15 @@ function getClaudePath() {
9699
9679
  const override = process.env.CLAUDE_MULTI_CLAUDE_PATH;
9700
9680
  if (override) {
9701
9681
  const resolved = resolve(override);
9702
- if (!existsSync3(resolved)) {
9682
+ if (!existsSync2(resolved)) {
9703
9683
  throw new ClaudeMultiError(ErrorCode.CLAUDE_NOT_FOUND, `CLAUDE_MULTI_CLAUDE_PATH points to ${resolved} but that file does not exist`);
9704
9684
  }
9705
9685
  return resolved;
9706
9686
  }
9707
- if (existsSync3(PINNED_CLAUDE_BIN)) {
9708
- return PINNED_CLAUDE_BIN;
9709
- }
9710
9687
  try {
9711
9688
  const command = process.platform === "win32" ? "where claude" : "which claude";
9712
9689
  const claudePath = execSync2(command, { encoding: "utf-8" }).trim();
9713
- const firstPath = claudePath.split(`
9714
- `)[0];
9690
+ const firstPath = claudePath.split(/\r?\n/)[0];
9715
9691
  if (!firstPath) {
9716
9692
  throw new ClaudeMultiError(ErrorCode.CLAUDE_NOT_FOUND, "Could not determine Claude path");
9717
9693
  }
@@ -9729,37 +9705,6 @@ function tryGetClaudePath() {
9729
9705
  return null;
9730
9706
  }
9731
9707
  }
9732
- function getGlobalClaudePath() {
9733
- const override = process.env.CLAUDE_MULTI_CLAUDE_PATH;
9734
- if (override) {
9735
- const resolved = resolve(override);
9736
- if (!existsSync3(resolved)) {
9737
- throw new ClaudeMultiError(ErrorCode.CLAUDE_NOT_FOUND, `CLAUDE_MULTI_CLAUDE_PATH points to ${resolved} but that file does not exist`);
9738
- }
9739
- return resolved;
9740
- }
9741
- try {
9742
- const command = process.platform === "win32" ? "where claude" : "which claude";
9743
- const claudePath = execSync2(command, { encoding: "utf-8" }).trim();
9744
- const firstPath = claudePath.split(`
9745
- `)[0];
9746
- if (!firstPath) {
9747
- throw new ClaudeMultiError(ErrorCode.CLAUDE_NOT_FOUND, "Could not determine Claude path");
9748
- }
9749
- return firstPath.trim();
9750
- } catch (err) {
9751
- if (err instanceof ClaudeMultiError)
9752
- throw err;
9753
- throw new ClaudeMultiError(ErrorCode.CLAUDE_NOT_FOUND, "Claude Code is not installed. Please install @anthropic-ai/claude-code first.", { cause: err });
9754
- }
9755
- }
9756
- function tryGetGlobalClaudePath() {
9757
- try {
9758
- return getGlobalClaudePath();
9759
- } catch {
9760
- return null;
9761
- }
9762
- }
9763
9708
  function generateWrapperScriptSafe(options) {
9764
9709
  const claudePath = tryGetClaudePath();
9765
9710
  if (!claudePath)
@@ -9791,11 +9736,11 @@ set "CLAUDE_CONFIG_DIR=${options.configDir}"
9791
9736
  async function createWrapper(options) {
9792
9737
  const { binaryPath, configDir } = options;
9793
9738
  const binDir = dirname2(binaryPath);
9794
- if (!existsSync3(binDir)) {
9795
- mkdirSync2(binDir, { recursive: true });
9739
+ if (!existsSync2(binDir)) {
9740
+ mkdirSync(binDir, { recursive: true });
9796
9741
  }
9797
- if (!existsSync3(configDir)) {
9798
- mkdirSync2(configDir, { recursive: true });
9742
+ if (!existsSync2(configDir)) {
9743
+ mkdirSync(configDir, { recursive: true });
9799
9744
  }
9800
9745
  if (process.platform === "win32") {
9801
9746
  const script = generateWindowsWrapperScript(options);
@@ -9807,7 +9752,7 @@ async function createWrapper(options) {
9807
9752
  }
9808
9753
  }
9809
9754
  function removeWrapper(binaryPath) {
9810
- if (existsSync3(binaryPath)) {
9755
+ if (existsSync2(binaryPath)) {
9811
9756
  unlinkSync(binaryPath);
9812
9757
  }
9813
9758
  }
@@ -9832,7 +9777,6 @@ function getDefaultBinaryPath(name) {
9832
9777
  }
9833
9778
  var init_wrapper = __esm(() => {
9834
9779
  init_errors();
9835
- init_paths();
9836
9780
  });
9837
9781
 
9838
9782
  // src/migration.ts
@@ -9849,11 +9793,11 @@ __export(exports_migration, {
9849
9793
  LEGACY_INSTANCE_VERSION: () => LEGACY_INSTANCE_VERSION,
9850
9794
  CONFIG_VERSION: () => CONFIG_VERSION
9851
9795
  });
9852
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync, copyFileSync, readFileSync as readFileSync3, rmSync, writeFileSync as writeFileSync2, chmodSync as chmodSync2 } from "node:fs";
9853
- import { join as join4, dirname as dirname3 } from "node:path";
9796
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync, copyFileSync, readFileSync as readFileSync3, rmSync, writeFileSync, chmodSync as chmodSync2 } from "node:fs";
9797
+ import { join as join3, dirname as dirname3 } from "node:path";
9854
9798
  function updateClaudeJson(configDir) {
9855
- const stateFile = join4(configDir, ".claude.json");
9856
- if (!existsSync4(stateFile))
9799
+ const stateFile = join3(configDir, ".claude.json");
9800
+ if (!existsSync3(stateFile))
9857
9801
  return;
9858
9802
  try {
9859
9803
  const raw = JSON.parse(readFileSync3(stateFile, "utf-8"));
@@ -9863,7 +9807,7 @@ function updateClaudeJson(configDir) {
9863
9807
  changed = true;
9864
9808
  }
9865
9809
  if (changed) {
9866
- writeFileSync2(stateFile, JSON.stringify(raw, null, 2), "utf-8");
9810
+ writeFileSync(stateFile, JSON.stringify(raw, null, 2), "utf-8");
9867
9811
  }
9868
9812
  } catch {}
9869
9813
  }
@@ -9872,10 +9816,10 @@ function needsInstanceMigration(config) {
9872
9816
  const stored = config.instanceMigrationVersion;
9873
9817
  if (!stored)
9874
9818
  return INSTANCE_MIGRATIONS.length > 0;
9875
- const storedCoerced = import_semver2.default.coerce(stored);
9819
+ const storedCoerced = import_semver.default.coerce(stored);
9876
9820
  if (!storedCoerced)
9877
9821
  return INSTANCE_MIGRATIONS.length > 0;
9878
- return INSTANCE_MIGRATIONS.some((m) => import_semver2.default.gt(m.version, storedCoerced) && import_semver2.default.lte(m.version, current));
9822
+ return INSTANCE_MIGRATIONS.some((m) => import_semver.default.gt(m.version, storedCoerced) && import_semver.default.lte(m.version, current));
9879
9823
  }
9880
9824
  async function runInstanceMigrations(config) {
9881
9825
  if (!needsInstanceMigration(config))
@@ -9885,8 +9829,8 @@ async function runInstanceMigrations(config) {
9885
9829
  try {
9886
9830
  createBackup(config);
9887
9831
  const currentVersion = getClaudeMultiVersion();
9888
- const stored = import_semver2.default.coerce(config.instanceMigrationVersion || "0.0.0");
9889
- const applicable = INSTANCE_MIGRATIONS.filter((m) => stored ? import_semver2.default.gt(m.version, stored) && import_semver2.default.lte(m.version, currentVersion) : true).toSorted((a, b) => import_semver2.default.compare(a.version, b.version));
9832
+ const stored = import_semver.default.coerce(config.instanceMigrationVersion || "0.0.0");
9833
+ const applicable = INSTANCE_MIGRATIONS.filter((m) => stored ? import_semver.default.gt(m.version, stored) && import_semver.default.lte(m.version, currentVersion) : true).toSorted((a, b) => import_semver.default.compare(a.version, b.version));
9890
9834
  for (const migration of applicable) {
9891
9835
  for (let i = 0;i < config.instances.length; i++) {
9892
9836
  const migrated = await migration.migrate({ ...config.instances[i] }, config);
@@ -9900,26 +9844,31 @@ async function runInstanceMigrations(config) {
9900
9844
  }
9901
9845
  }
9902
9846
  function getBackupDir() {
9903
- return join4(getBaseDir(), ".claude-multi", "backups");
9847
+ return join3(getBaseDir(), ".claude-multi", "backups");
9904
9848
  }
9905
9849
  function getLockFile() {
9906
- return join4(getBaseDir(), ".claude-multi", ".migration.lock");
9850
+ return join3(getBaseDir(), ".claude-multi", ".migration.lock");
9907
9851
  }
9908
9852
  function createLock() {
9909
9853
  const lockFile = getLockFile();
9910
9854
  const lockDir = dirname3(lockFile);
9911
- if (!existsSync4(lockDir))
9912
- mkdirSync3(lockDir, { recursive: true });
9913
- if (existsSync4(lockFile)) {
9855
+ if (!existsSync3(lockDir))
9856
+ mkdirSync2(lockDir, { recursive: true });
9857
+ if (existsSync3(lockFile)) {
9914
9858
  try {
9915
9859
  const raw = JSON.parse(readFileSync3(lockFile, "utf-8"));
9916
9860
  if (typeof raw === "object" && raw !== null && "pid" in raw && typeof raw.pid === "number") {
9917
9861
  const lock = raw;
9918
- try {
9919
- process.kill(lock.pid, 0);
9920
- return false;
9921
- } catch {
9862
+ const lockAge = Date.now() - new Date(lock.startedAt).getTime();
9863
+ if (lockAge > 30 * 60 * 1000) {
9922
9864
  rmSync(lockFile, { force: true });
9865
+ } else {
9866
+ try {
9867
+ process.kill(lock.pid, 0);
9868
+ return false;
9869
+ } catch {
9870
+ rmSync(lockFile, { force: true });
9871
+ }
9923
9872
  }
9924
9873
  } else {
9925
9874
  rmSync(lockFile, { force: true });
@@ -9928,7 +9877,7 @@ function createLock() {
9928
9877
  rmSync(lockFile, { force: true });
9929
9878
  }
9930
9879
  }
9931
- writeFileSync2(lockFile, JSON.stringify({
9880
+ writeFileSync(lockFile, JSON.stringify({
9932
9881
  pid: process.pid,
9933
9882
  startedAt: new Date().toISOString()
9934
9883
  }), "utf-8");
@@ -9953,30 +9902,30 @@ function clearMigrationFailure(config) {
9953
9902
  }
9954
9903
  function createBackup(config) {
9955
9904
  const backupDir = getBackupDir();
9956
- if (!existsSync4(backupDir)) {
9957
- mkdirSync3(backupDir, { recursive: true });
9905
+ if (!existsSync3(backupDir)) {
9906
+ mkdirSync2(backupDir, { recursive: true });
9958
9907
  }
9959
9908
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
9960
9909
  const rand = Math.random().toString(36).slice(2, 6);
9961
9910
  const fromV = config.version || "1.0.0";
9962
- const backupPath = join4(backupDir, `${ts}-${rand}-v${fromV}-to-v${CONFIG_VERSION}`);
9963
- mkdirSync3(backupPath, { recursive: true });
9964
- const configSrc = join4(getBaseDir(), ".claude-multi", "config.json");
9965
- if (existsSync4(configSrc)) {
9966
- copyFileSync(configSrc, join4(backupPath, "config.json"));
9911
+ const backupPath = join3(backupDir, `${ts}-${rand}-v${fromV}-to-v${CONFIG_VERSION}`);
9912
+ mkdirSync2(backupPath, { recursive: true });
9913
+ const configSrc = join3(getBaseDir(), ".claude-multi", "config.json");
9914
+ if (existsSync3(configSrc)) {
9915
+ copyFileSync(configSrc, join3(backupPath, "config.json"));
9967
9916
  }
9968
- const instancesDir = join4(backupPath, "instances");
9917
+ const instancesDir = join3(backupPath, "instances");
9969
9918
  for (const inst of config.instances) {
9970
- const settingsFile = join4(inst.configDir, "settings.json");
9971
- if (existsSync4(settingsFile)) {
9972
- const instDir = join4(instancesDir, inst.name);
9973
- mkdirSync3(instDir, { recursive: true });
9974
- copyFileSync(settingsFile, join4(instDir, "settings.json"));
9919
+ const settingsFile = join3(inst.configDir, "settings.json");
9920
+ if (existsSync3(settingsFile)) {
9921
+ const instDir = join3(instancesDir, inst.name);
9922
+ mkdirSync2(instDir, { recursive: true });
9923
+ copyFileSync(settingsFile, join3(instDir, "settings.json"));
9975
9924
  }
9976
9925
  }
9977
9926
  const backups = readdirSync(backupDir).toSorted();
9978
9927
  for (let i = 0;i < backups.length - 3; i++) {
9979
- rmSync(join4(backupDir, backups[i]), { force: true, recursive: true });
9928
+ rmSync(join3(backupDir, backups[i]), { force: true, recursive: true });
9980
9929
  }
9981
9930
  return backupPath;
9982
9931
  }
@@ -9994,7 +9943,7 @@ function runMigration(config) {
9994
9943
  if (!inst.name || !inst.configDir || !inst.binaryPath) {
9995
9944
  warnings.push(`Instance entry missing required fields, skipping: ${JSON.stringify(inst)}`);
9996
9945
  }
9997
- if (inst.configDir && !existsSync4(inst.configDir)) {
9946
+ if (inst.configDir && !existsSync3(inst.configDir)) {
9998
9947
  warnings.push(`Instance '${inst.name}' configDir does not exist: ${inst.configDir}`);
9999
9948
  }
10000
9949
  }
@@ -10027,18 +9976,19 @@ function getMigrationStatus(config) {
10027
9976
  }
10028
9977
  function listBackups() {
10029
9978
  const backupDir = getBackupDir();
10030
- if (!existsSync4(backupDir))
9979
+ if (!existsSync3(backupDir))
10031
9980
  return [];
10032
9981
  return readdirSync(backupDir).toSorted().toReversed();
10033
9982
  }
10034
- var import_semver2, CONFIG_VERSION = "2.0.0", LEGACY_INSTANCE_VERSION = "0.5", INSTANCE_MIGRATIONS;
9983
+ var import_semver, CONFIG_VERSION = "2.0.0", LEGACY_INSTANCE_VERSION = "0.5", INSTANCE_MIGRATIONS;
10035
9984
  var init_migration = __esm(() => {
10036
9985
  init_paths();
10037
9986
  init_constants();
10038
9987
  init_version();
9988
+ init_env();
10039
9989
  init_wrapper();
10040
9990
  init_templates();
10041
- import_semver2 = __toESM(require_semver2(), 1);
9991
+ import_semver = __toESM(require_semver2(), 1);
10042
9992
  INSTANCE_MIGRATIONS = [
10043
9993
  {
10044
9994
  version: "0.6.2",
@@ -10048,17 +9998,19 @@ var init_migration = __esm(() => {
10048
9998
  if (instance.createdWithVersion && instance.createdWithVersion !== LEGACY_INSTANCE_VERSION && instance.createdWithVersion === currentVersion) {
10049
9999
  return Promise.resolve(instance);
10050
10000
  }
10051
- if (existsSync4(instance.binaryPath)) {
10052
- const claudePath = tryGetGlobalClaudePath();
10001
+ if (existsSync3(instance.binaryPath)) {
10002
+ const claudePath = tryGetClaudePath();
10053
10003
  if (claudePath !== null) {
10054
10004
  const expected = buildWrapperScript(instance, claudePath);
10055
10005
  try {
10056
10006
  const current = readFileSync3(instance.binaryPath, "utf-8");
10057
10007
  if (current !== expected) {
10058
- writeFileSync2(instance.binaryPath, expected, { mode: 493 });
10008
+ writeFileSync(instance.binaryPath, expected, { mode: 493 });
10059
10009
  chmodSync2(instance.binaryPath, 493);
10060
10010
  }
10061
10011
  } catch {}
10012
+ } else {
10013
+ console.warn(`[migration] Could not find claude binary, skipping wrapper regeneration for instance: ${instance.name}`);
10062
10014
  }
10063
10015
  }
10064
10016
  updateClaudeJson(instance.configDir);
@@ -10069,28 +10021,53 @@ var init_migration = __esm(() => {
10069
10021
  version: "0.6.3",
10070
10022
  description: "Sync provider template env vars (model names, thinking/output limits) to latest",
10071
10023
  migrate: (instance) => {
10024
+ const currentVersion = getClaudeMultiVersion();
10025
+ if (instance.createdWithVersion && instance.createdWithVersion !== LEGACY_INSTANCE_VERSION && instance.createdWithVersion === currentVersion) {
10026
+ return Promise.resolve(instance);
10027
+ }
10072
10028
  const providerName = instance.providerTemplate ?? detectProvider(instance.configDir);
10073
10029
  if (!providerName)
10074
10030
  return Promise.resolve(instance);
10075
- const template = getProviderTemplate(providerName);
10031
+ let template = getProviderTemplate(providerName);
10076
10032
  if (!template)
10077
10033
  return Promise.resolve(instance);
10078
- const settingsFile = join4(instance.configDir, "settings.json");
10034
+ const settingsFile = join3(instance.configDir, "settings.json");
10079
10035
  try {
10080
- if (!existsSync4(settingsFile))
10036
+ if (!existsSync3(settingsFile))
10081
10037
  return Promise.resolve(instance);
10082
10038
  const existing = JSON.parse(readFileSync3(settingsFile, "utf-8"));
10083
10039
  const existingEnv = existing.env ?? {};
10084
10040
  const apiKey = existingEnv.ANTHROPIC_AUTH_TOKEN ?? "";
10041
+ const existingBaseUrl = existingEnv.ANTHROPIC_BASE_URL;
10042
+ let resolvedRegional = false;
10043
+ if (providerHasRegions(providerName)) {
10044
+ const providerRegions = getProviderRegions(providerName);
10045
+ const detectedRegion = detectRegionFromBaseUrl(existingBaseUrl ?? "") ?? instance.providerRegion;
10046
+ if (detectedRegion && providerRegions && detectedRegion in providerRegions) {
10047
+ template = resolveRegionTemplate(template, detectedRegion);
10048
+ instance.providerRegion = detectedRegion;
10049
+ resolvedRegional = true;
10050
+ }
10051
+ }
10085
10052
  const templateSettings = structuredClone(template.settings);
10086
10053
  const newEnv = { ...templateSettings.env, ANTHROPIC_AUTH_TOKEN: apiKey };
10054
+ if (providerHasRegions(providerName) && !resolvedRegional && existingBaseUrl) {
10055
+ newEnv.ANTHROPIC_BASE_URL = existingBaseUrl;
10056
+ }
10057
+ for (const key of TUNABLE_ENV_VARS) {
10058
+ if (key in existingEnv && existingEnv[key] !== templateSettings.env[key]) {
10059
+ newEnv[key] = existingEnv[key];
10060
+ }
10061
+ }
10087
10062
  existing.env = { ...existingEnv, ...newEnv };
10088
10063
  existing.includeCoAuthoredBy = template.settings.includeCoAuthoredBy;
10089
10064
  existing.alwaysThinkingEnabled = template.settings.alwaysThinkingEnabled;
10090
- writeFileSync2(settingsFile, JSON.stringify(existing, null, 2), "utf-8");
10091
- } catch {}
10092
- if (!instance.providerTemplate) {
10093
- instance.providerTemplate = providerName;
10065
+ writeFileSync(settingsFile, JSON.stringify(existing, null, 2), "utf-8");
10066
+ if (!instance.providerTemplate) {
10067
+ instance.providerTemplate = providerName;
10068
+ }
10069
+ } catch (err) {
10070
+ console.warn(`[migration] Failed to sync provider template for '${instance.name}': ${err instanceof Error ? err.message : String(err)}`);
10094
10071
  }
10095
10072
  return Promise.resolve(instance);
10096
10073
  }
@@ -10105,6 +10082,7 @@ __export(exports_config, {
10105
10082
  validatePluginOperation: () => validatePluginOperation,
10106
10083
  updateInstanceAutoSync: () => updateInstanceAutoSync,
10107
10084
  unsyncPluginsAndSkills: () => unsyncPluginsAndSkills,
10085
+ syncProviderTemplateForInstance: () => syncProviderTemplateForInstance,
10108
10086
  syncPluginsAndSkills: () => syncPluginsAndSkills,
10109
10087
  setTestDefaultClaudeDir: () => setTestDefaultClaudeDir,
10110
10088
  setTestConfigDir: () => setTestConfigDir,
@@ -10151,11 +10129,11 @@ __export(exports_config, {
10151
10129
  clearTestConfigDir: () => clearTestConfigDir,
10152
10130
  addInstance: () => addInstance
10153
10131
  });
10154
- import { existsSync as existsSync5, mkdirSync as mkdirSync4, readdirSync as readdirSync2, statSync, readlinkSync, rmSync as rmSync2, lstatSync, readFileSync as readFileSync4, renameSync } from "node:fs";
10132
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync2, statSync, readlinkSync, rmSync as rmSync2, lstatSync, readFileSync as readFileSync4, writeFileSync as writeFileSync2, renameSync } from "node:fs";
10155
10133
  import { readFile as readFile2, writeFile as writeFile3, copyFile, mkdir, symlink } from "node:fs/promises";
10156
10134
  import { homedir as homedir2 } from "node:os";
10157
10135
  import { randomBytes as randomBytes2 } from "node:crypto";
10158
- import { dirname as dirname4, isAbsolute, join as join5, relative, resolve as resolve2 } from "node:path";
10136
+ import { dirname as dirname4, isAbsolute, join as join4, relative, resolve as resolve2 } from "node:path";
10159
10137
  function setTestConfigDir(dir) {
10160
10138
  _testConfigDir = dir;
10161
10139
  }
@@ -10163,19 +10141,19 @@ function clearTestConfigDir() {
10163
10141
  _testConfigDir = undefined;
10164
10142
  }
10165
10143
  function getConfigDir() {
10166
- return _testConfigDir ?? join5(homedir2(), ".claude-multi");
10144
+ return _testConfigDir ?? join4(homedir2(), ".claude-multi");
10167
10145
  }
10168
10146
  function getConfigFile() {
10169
- return join5(getConfigDir(), "config.json");
10147
+ return join4(getConfigDir(), "config.json");
10170
10148
  }
10171
10149
  async function copyDirRecursive(source, target) {
10172
- if (!existsSync5(target)) {
10150
+ if (!existsSync4(target)) {
10173
10151
  await mkdir(target, { recursive: true });
10174
10152
  }
10175
10153
  const entries = readdirSync2(source);
10176
10154
  await Promise.all(entries.map(async (entry) => {
10177
- const src = join5(source, entry);
10178
- const tgt = join5(target, entry);
10155
+ const src = join4(source, entry);
10156
+ const tgt = join4(target, entry);
10179
10157
  const s = statSync(src);
10180
10158
  if (s.isDirectory()) {
10181
10159
  await copyDirRecursive(src, tgt);
@@ -10192,8 +10170,8 @@ function lstatSafe(path) {
10192
10170
  }
10193
10171
  }
10194
10172
  function ensureConfigDir() {
10195
- if (!existsSync5(getConfigDir())) {
10196
- mkdirSync4(getConfigDir(), { recursive: true });
10173
+ if (!existsSync4(getConfigDir())) {
10174
+ mkdirSync3(getConfigDir(), { recursive: true });
10197
10175
  }
10198
10176
  }
10199
10177
  function isConfig(raw) {
@@ -10201,7 +10179,7 @@ function isConfig(raw) {
10201
10179
  }
10202
10180
  async function loadConfig() {
10203
10181
  ensureConfigDir();
10204
- if (!existsSync5(getConfigFile())) {
10182
+ if (!existsSync4(getConfigFile())) {
10205
10183
  const defaultConfig = {
10206
10184
  instances: [],
10207
10185
  version: "2.0.0"
@@ -10297,7 +10275,7 @@ function getDefaultClaudeDir() {
10297
10275
  if (_testDefaultClaudeDir) {
10298
10276
  return _testDefaultClaudeDir;
10299
10277
  }
10300
- return join5(homedir2(), ".claude");
10278
+ return join4(homedir2(), ".claude");
10301
10279
  }
10302
10280
  function isBrokenSymlink(path) {
10303
10281
  try {
@@ -10313,7 +10291,7 @@ function isBrokenSymlink(path) {
10313
10291
  } else {
10314
10292
  targetPath = resolve2(dirname4(path), target);
10315
10293
  }
10316
- return !existsSync5(targetPath);
10294
+ return !existsSync4(targetPath);
10317
10295
  } catch {
10318
10296
  return false;
10319
10297
  }
@@ -10321,7 +10299,7 @@ function isBrokenSymlink(path) {
10321
10299
  function detectBrokenSymlinks(configDir) {
10322
10300
  const result = { broken: [], all: [] };
10323
10301
  for (const dir of SYNC_DIRS) {
10324
- const targetPath = join5(configDir, dir);
10302
+ const targetPath = join4(configDir, dir);
10325
10303
  try {
10326
10304
  const stats = lstatSync(targetPath);
10327
10305
  result.all.push(dir);
@@ -10334,13 +10312,13 @@ function detectBrokenSymlinks(configDir) {
10334
10312
  }
10335
10313
  function hasDefaultClaudeConfig() {
10336
10314
  const defaultDir = getDefaultClaudeDir();
10337
- const settingsFile = join5(defaultDir, "settings.json");
10338
- return existsSync5(defaultDir) && existsSync5(settingsFile);
10315
+ const settingsFile = join4(defaultDir, "settings.json");
10316
+ return existsSync4(defaultDir) && existsSync4(settingsFile);
10339
10317
  }
10340
10318
  async function copySettingsFromDefault(targetConfigDir) {
10341
10319
  const defaultDir = getDefaultClaudeDir();
10342
- const sourceSettings = join5(defaultDir, "settings.json");
10343
- if (!existsSync5(sourceSettings)) {
10320
+ const sourceSettings = join4(defaultDir, "settings.json");
10321
+ if (!existsSync4(sourceSettings)) {
10344
10322
  throw new ClaudeMultiError(ErrorCode.DEFAULT_SETTINGS_NOT_FOUND, "Default Claude settings.json not found");
10345
10323
  }
10346
10324
  const content = await readFile2(sourceSettings, "utf-8");
@@ -10356,18 +10334,18 @@ async function copySettingsFromDefault(targetConfigDir) {
10356
10334
  safeSettings[key] = settings[key];
10357
10335
  }
10358
10336
  }
10359
- if (!existsSync5(targetConfigDir)) {
10337
+ if (!existsSync4(targetConfigDir)) {
10360
10338
  await mkdir(targetConfigDir, { recursive: true });
10361
10339
  }
10362
- const targetSettings = join5(targetConfigDir, "settings.json");
10340
+ const targetSettings = join4(targetConfigDir, "settings.json");
10363
10341
  await writeFile3(targetSettings, JSON.stringify(safeSettings, null, 2), "utf-8");
10364
10342
  }
10365
10343
  async function copyAllFromDefault(targetConfigDir, autoSync = false) {
10366
10344
  const defaultDir = getDefaultClaudeDir();
10367
- if (!existsSync5(defaultDir)) {
10345
+ if (!existsSync4(defaultDir)) {
10368
10346
  throw new ClaudeMultiError(ErrorCode.DEFAULT_DIR_NOT_FOUND, "Default Claude directory not found");
10369
10347
  }
10370
- if (!existsSync5(targetConfigDir)) {
10348
+ if (!existsSync4(targetConfigDir)) {
10371
10349
  await mkdir(targetConfigDir, { recursive: true });
10372
10350
  }
10373
10351
  const excludeFiles = [
@@ -10390,8 +10368,8 @@ async function copyAllFromDefault(targetConfigDir, autoSync = false) {
10390
10368
  const copyRecursive = async (source, target) => {
10391
10369
  const entries = readdirSync2(source);
10392
10370
  for (const entry of entries) {
10393
- const sourcePath = join5(source, entry);
10394
- const targetPath = join5(target, entry);
10371
+ const sourcePath = join4(source, entry);
10372
+ const targetPath = join4(target, entry);
10395
10373
  const stat = statSync(sourcePath);
10396
10374
  if (excludeSet.has(entry)) {
10397
10375
  continue;
@@ -10415,7 +10393,7 @@ async function copyAllFromDefault(targetConfigDir, autoSync = false) {
10415
10393
  await symlink(sourcePath, targetPath, "dir");
10416
10394
  console.log(` Symlinked: ${entry} -> ${sourcePath}`);
10417
10395
  } else {
10418
- if (!existsSync5(targetPath)) {
10396
+ if (!existsSync4(targetPath)) {
10419
10397
  await mkdir(targetPath, { recursive: true });
10420
10398
  }
10421
10399
  await copyRecursive(sourcePath, targetPath);
@@ -10428,11 +10406,11 @@ async function copyAllFromDefault(targetConfigDir, autoSync = false) {
10428
10406
  await copyRecursive(defaultDir, targetConfigDir);
10429
10407
  }
10430
10408
  async function detectMcpConfigurations(configDir) {
10431
- if (!existsSync5(configDir)) {
10409
+ if (!existsSync4(configDir)) {
10432
10410
  return null;
10433
10411
  }
10434
- const settingsFile = join5(configDir, "settings.json");
10435
- if (existsSync5(settingsFile)) {
10412
+ const settingsFile = join4(configDir, "settings.json");
10413
+ if (existsSync4(settingsFile)) {
10436
10414
  try {
10437
10415
  const settingsContent = await readFile2(settingsFile, "utf-8");
10438
10416
  const settings = JSON.parse(settingsContent);
@@ -10443,8 +10421,8 @@ async function detectMcpConfigurations(configDir) {
10443
10421
  }
10444
10422
  const mcpFiles = ["mcp.json", "mcp-servers.json", "claude-mcp.json"];
10445
10423
  for (const mcpFile of mcpFiles) {
10446
- const mcpFilePath = join5(configDir, mcpFile);
10447
- if (existsSync5(mcpFilePath)) {
10424
+ const mcpFilePath = join4(configDir, mcpFile);
10425
+ if (existsSync4(mcpFilePath)) {
10448
10426
  try {
10449
10427
  const mcpContent = await readFile2(mcpFilePath, "utf-8");
10450
10428
  const mcpConfig = JSON.parse(mcpContent);
@@ -10463,12 +10441,12 @@ async function hasDefaultMcpConfig() {
10463
10441
  }
10464
10442
  async function copyMcpServersFromDefault(targetConfigDir) {
10465
10443
  const defaultDir = getDefaultClaudeDir();
10466
- if (!existsSync5(targetConfigDir)) {
10444
+ if (!existsSync4(targetConfigDir)) {
10467
10445
  await mkdir(targetConfigDir, { recursive: true });
10468
10446
  }
10469
- const pluginsDir = join5(targetConfigDir, "plugins");
10470
- const defaultPluginsDir = join5(defaultDir, "plugins");
10471
- if (existsSync5(defaultPluginsDir) && !existsSync5(pluginsDir)) {
10447
+ const pluginsDir = join4(targetConfigDir, "plugins");
10448
+ const defaultPluginsDir = join4(defaultDir, "plugins");
10449
+ if (existsSync4(defaultPluginsDir) && !existsSync4(pluginsDir)) {
10472
10450
  await copyDirRecursive(defaultPluginsDir, pluginsDir);
10473
10451
  }
10474
10452
  const mcpConfig = await detectMcpConfigurations(defaultDir);
@@ -10488,8 +10466,8 @@ async function copyMcpServersFromDefault(targetConfigDir) {
10488
10466
  }
10489
10467
  }
10490
10468
  async function writeMcpConfiguration(targetConfigDir, mcpConfig) {
10491
- const settingsFile = join5(targetConfigDir, "settings.json");
10492
- if (existsSync5(settingsFile)) {
10469
+ const settingsFile = join4(targetConfigDir, "settings.json");
10470
+ if (existsSync4(settingsFile)) {
10493
10471
  try {
10494
10472
  const settingsContent = await readFile2(settingsFile, "utf-8");
10495
10473
  const settings = JSON.parse(settingsContent);
@@ -10498,7 +10476,7 @@ async function writeMcpConfiguration(targetConfigDir, mcpConfig) {
10498
10476
  return;
10499
10477
  } catch {}
10500
10478
  }
10501
- const mcpFile = join5(targetConfigDir, "mcp.json");
10479
+ const mcpFile = join4(targetConfigDir, "mcp.json");
10502
10480
  await writeFile3(mcpFile, JSON.stringify(mcpConfig, null, 2), "utf-8");
10503
10481
  }
10504
10482
  async function copyMcpServersBetweenInstances(sourceInstanceName, targetInstanceName) {
@@ -10527,18 +10505,18 @@ async function listMcpServers(instanceName) {
10527
10505
  return mcpConfig?.mcpServers || null;
10528
10506
  }
10529
10507
  async function createSettingsFromTemplate(targetConfigDir, template, apiKey) {
10530
- if (!existsSync5(targetConfigDir)) {
10508
+ if (!existsSync4(targetConfigDir)) {
10531
10509
  await mkdir(targetConfigDir, { recursive: true });
10532
10510
  }
10533
10511
  const settings = applyProviderTemplate(template, apiKey);
10534
- const settingsFile = join5(targetConfigDir, "settings.json");
10512
+ const settingsFile = join4(targetConfigDir, "settings.json");
10535
10513
  await writeFile3(settingsFile, JSON.stringify(settings, null, 2), "utf-8");
10536
10514
  }
10537
10515
  async function initializeInstanceState(configDir) {
10538
- const stateFile = join5(configDir, ".claude.json");
10539
- if (existsSync5(stateFile))
10516
+ const stateFile = join4(configDir, ".claude.json");
10517
+ if (existsSync4(stateFile))
10540
10518
  return;
10541
- if (!existsSync5(configDir)) {
10519
+ if (!existsSync4(configDir)) {
10542
10520
  await mkdir(configDir, { recursive: true });
10543
10521
  }
10544
10522
  const state = {
@@ -10561,9 +10539,9 @@ async function initializeInstanceState(configDir) {
10561
10539
  await writeFile3(stateFile, JSON.stringify(state, null, 2), "utf-8");
10562
10540
  }
10563
10541
  async function mergeProviderEnv(configDir, template, apiKey) {
10564
- const settingsFile = join5(configDir, "settings.json");
10542
+ const settingsFile = join4(configDir, "settings.json");
10565
10543
  let existing = {};
10566
- if (existsSync5(settingsFile)) {
10544
+ if (existsSync4(settingsFile)) {
10567
10545
  const raw = await readFile2(settingsFile, "utf-8");
10568
10546
  existing = JSON.parse(raw);
10569
10547
  }
@@ -10573,22 +10551,81 @@ async function mergeProviderEnv(configDir, template, apiKey) {
10573
10551
  existing.includeCoAuthoredBy = template.settings.includeCoAuthoredBy;
10574
10552
  await writeFile3(settingsFile, JSON.stringify(existing, null, 2), "utf-8");
10575
10553
  }
10554
+ async function syncProviderTemplateForInstance(instance) {
10555
+ const providerName = instance.providerTemplate ?? detectProvider(instance.configDir);
10556
+ if (!providerName) {
10557
+ throw new ClaudeMultiError(ErrorCode.INSTANCE_NOT_FOUND, `Could not detect provider for '${instance.name}'`);
10558
+ }
10559
+ let template = getProviderTemplate(providerName);
10560
+ if (!template) {
10561
+ throw new ClaudeMultiError(ErrorCode.INSTANCE_NOT_FOUND, `Unknown provider template '${providerName}'`);
10562
+ }
10563
+ const settingsFile = join4(instance.configDir, "settings.json");
10564
+ if (!existsSync4(settingsFile)) {
10565
+ throw new ClaudeMultiError(ErrorCode.INSTANCE_DIR_NOT_FOUND, `No settings.json found for '${instance.name}'`);
10566
+ }
10567
+ const raw = JSON.parse(readFileSync4(settingsFile, "utf-8"));
10568
+ const existingEnv = raw.env ?? {};
10569
+ const apiKey = existingEnv.ANTHROPIC_AUTH_TOKEN ?? "";
10570
+ const existingBaseUrl = existingEnv.ANTHROPIC_BASE_URL;
10571
+ let resolvedRegion = null;
10572
+ if (providerHasRegions(providerName)) {
10573
+ const detectedRegion = existingBaseUrl ? detectRegionFromBaseUrl(existingBaseUrl) ?? instance.providerRegion : instance.providerRegion;
10574
+ if (detectedRegion) {
10575
+ const providerRegions = getProviderRegions(providerName);
10576
+ if (providerRegions && detectedRegion in providerRegions) {
10577
+ template = resolveRegionTemplate(template, detectedRegion);
10578
+ resolvedRegion = detectedRegion;
10579
+ }
10580
+ }
10581
+ }
10582
+ const templateSettings = structuredClone(template.settings);
10583
+ const newEnv = { ...templateSettings.env, ANTHROPIC_AUTH_TOKEN: apiKey };
10584
+ if (providerHasRegions(providerName) && !resolvedRegion && existingBaseUrl) {
10585
+ newEnv.ANTHROPIC_BASE_URL = existingBaseUrl;
10586
+ }
10587
+ for (const key of TUNABLE_ENV_VARS) {
10588
+ if (key in existingEnv && existingEnv[key] !== templateSettings.env[key]) {
10589
+ newEnv[key] = existingEnv[key];
10590
+ }
10591
+ }
10592
+ raw.env = { ...existingEnv, ...newEnv };
10593
+ raw.includeCoAuthoredBy = template.settings.includeCoAuthoredBy;
10594
+ raw.alwaysThinkingEnabled = template.settings.alwaysThinkingEnabled;
10595
+ writeFileSync2(settingsFile, JSON.stringify(raw, null, 2), "utf-8");
10596
+ let needsSave = false;
10597
+ const config = await loadConfig();
10598
+ const inst = config.instances.find((i) => i.name === instance.name);
10599
+ if (inst) {
10600
+ if (!inst.providerTemplate) {
10601
+ inst.providerTemplate = providerName;
10602
+ needsSave = true;
10603
+ }
10604
+ if (providerHasRegions(providerName) && resolvedRegion && !inst.providerRegion) {
10605
+ inst.providerRegion = resolvedRegion;
10606
+ needsSave = true;
10607
+ }
10608
+ if (needsSave) {
10609
+ await saveConfigAtomic(config);
10610
+ }
10611
+ }
10612
+ }
10576
10613
  async function syncPluginsAndSkills(configDir) {
10577
10614
  const defaultDir = getDefaultClaudeDir();
10578
- if (!existsSync5(configDir)) {
10615
+ if (!existsSync4(configDir)) {
10579
10616
  throw new ClaudeMultiError(ErrorCode.INSTANCE_DIR_NOT_FOUND, "Instance config directory does not exist");
10580
10617
  }
10581
10618
  await Promise.all(SYNC_DIRS.map(async (dir) => {
10582
- const targetPath = join5(configDir, dir);
10583
- const sourcePath = join5(defaultDir, dir);
10584
- if (!existsSync5(sourcePath)) {
10619
+ const targetPath = join4(configDir, dir);
10620
+ const sourcePath = join4(defaultDir, dir);
10621
+ if (!existsSync4(sourcePath)) {
10585
10622
  console.log(source_default.yellow(` ⚠ Source ${dir} not found in ${defaultDir}, skipping`));
10586
10623
  return;
10587
10624
  }
10588
- if (existsSync5(targetPath)) {
10625
+ if (existsSync4(targetPath)) {
10589
10626
  try {
10590
10627
  const linkTarget = readlinkSync(targetPath);
10591
- if (linkTarget === sourcePath || linkTarget === join5("..", "..", ".claude", dir)) {
10628
+ if (linkTarget === sourcePath || linkTarget === join4("..", "..", ".claude", dir)) {
10592
10629
  console.log(source_default.gray(` ✓ ${dir} already synced`));
10593
10630
  return;
10594
10631
  }
@@ -10605,8 +10642,8 @@ async function syncPluginsAndSkills(configDir) {
10605
10642
  async function copyFilesRecursive(source, target) {
10606
10643
  const entries = readdirSync2(source);
10607
10644
  await Promise.all(entries.map(async (entry) => {
10608
- const sourceEntry = join5(source, entry);
10609
- const targetEntry = join5(target, entry);
10645
+ const sourceEntry = join4(source, entry);
10646
+ const targetEntry = join4(target, entry);
10610
10647
  const stat = statSync(sourceEntry);
10611
10648
  if (stat.isDirectory()) {
10612
10649
  await mkdir(targetEntry, { recursive: true });
@@ -10618,13 +10655,13 @@ async function copyFilesRecursive(source, target) {
10618
10655
  }
10619
10656
  async function unsyncPluginsAndSkills(configDir) {
10620
10657
  const defaultDir = getDefaultClaudeDir();
10621
- if (!existsSync5(configDir)) {
10658
+ if (!existsSync4(configDir)) {
10622
10659
  throw new ClaudeMultiError(ErrorCode.INSTANCE_DIR_NOT_FOUND, "Instance config directory does not exist");
10623
10660
  }
10624
10661
  await Promise.all(SYNC_DIRS.map(async (dir) => {
10625
- const targetPath = join5(configDir, dir);
10626
- const sourcePath = join5(defaultDir, dir);
10627
- if (!existsSync5(sourcePath)) {
10662
+ const targetPath = join4(configDir, dir);
10663
+ const sourcePath = join4(defaultDir, dir);
10664
+ if (!existsSync4(sourcePath)) {
10628
10665
  console.log(source_default.yellow(` ⚠ Source ${dir} not found in ${defaultDir}, skipping`));
10629
10666
  return;
10630
10667
  }
@@ -10636,7 +10673,7 @@ async function unsyncPluginsAndSkills(configDir) {
10636
10673
  if (isSymlink) {
10637
10674
  rmSync2(targetPath, { force: true });
10638
10675
  console.log(source_default.gray(` ✓ Removed symlink for ${dir}`));
10639
- } else if (!existsSync5(targetPath)) {} else {
10676
+ } else if (!existsSync4(targetPath)) {} else {
10640
10677
  console.log(source_default.yellow(` ⚠ ${dir} is already a regular directory, skipping`));
10641
10678
  return;
10642
10679
  }
@@ -10646,8 +10683,8 @@ async function unsyncPluginsAndSkills(configDir) {
10646
10683
  }));
10647
10684
  }
10648
10685
  async function readClaudeSettings(configDir) {
10649
- const settingsFile = join5(configDir, "settings.json");
10650
- if (!existsSync5(settingsFile)) {
10686
+ const settingsFile = join4(configDir, "settings.json");
10687
+ if (!existsSync4(settingsFile)) {
10651
10688
  return null;
10652
10689
  }
10653
10690
  try {
@@ -10659,10 +10696,10 @@ async function readClaudeSettings(configDir) {
10659
10696
  }
10660
10697
  }
10661
10698
  async function writeClaudeSettings(configDir, settings) {
10662
- if (!existsSync5(configDir)) {
10699
+ if (!existsSync4(configDir)) {
10663
10700
  await mkdir(configDir, { recursive: true });
10664
10701
  }
10665
- await writeJsonFileAtomic(join5(configDir, "settings.json"), settings);
10702
+ await writeJsonFileAtomic(join4(configDir, "settings.json"), settings);
10666
10703
  }
10667
10704
  async function getEnabledPlugins(configDir) {
10668
10705
  const settings = await readClaudeSettings(configDir);
@@ -10712,18 +10749,18 @@ function readMcpJsonFile(mcpPath) {
10712
10749
  }
10713
10750
  function scanPluginDir(baseDir, category, enabledPlugins) {
10714
10751
  const subDir = category === PluginCategory.Internal ? "plugins" : "external_plugins";
10715
- const dir = join5(baseDir, MARKETPLACE_REL, subDir);
10716
- if (!existsSync5(dir))
10752
+ const dir = join4(baseDir, MARKETPLACE_REL, subDir);
10753
+ if (!existsSync4(dir))
10717
10754
  return [];
10718
10755
  const results = [];
10719
10756
  for (const entry of readdirSync2(dir, { withFileTypes: true })) {
10720
10757
  if (!entry.isDirectory())
10721
10758
  continue;
10722
- const pluginPath = join5(dir, entry.name);
10759
+ const pluginPath = join4(dir, entry.name);
10723
10760
  let name = entry.name;
10724
10761
  let description = "";
10725
- const metaFile = join5(pluginPath, ".claude-plugin", "plugin.json");
10726
- if (existsSync5(metaFile)) {
10762
+ const metaFile = join4(pluginPath, ".claude-plugin", "plugin.json");
10763
+ if (existsSync4(metaFile)) {
10727
10764
  try {
10728
10765
  const meta = JSON.parse(readFileSync4(metaFile, "utf-8"));
10729
10766
  if (meta.name)
@@ -10734,8 +10771,8 @@ function scanPluginDir(baseDir, category, enabledPlugins) {
10734
10771
  console.error(source_default.yellow(`Warning: Could not parse plugin metadata for ${entry.name}`));
10735
10772
  }
10736
10773
  }
10737
- const mcpFile = join5(pluginPath, ".mcp.json");
10738
- const hasMcp = existsSync5(mcpFile);
10774
+ const mcpFile = join4(pluginPath, ".mcp.json");
10775
+ const hasMcp = existsSync4(mcpFile);
10739
10776
  let mcpServerNames;
10740
10777
  if (hasMcp) {
10741
10778
  const servers = readMcpJsonFile(mcpFile);
@@ -10758,8 +10795,8 @@ function scanPluginDir(baseDir, category, enabledPlugins) {
10758
10795
  }
10759
10796
  function scanPluginsFromDir(baseDir) {
10760
10797
  let enabledPlugins = {};
10761
- const settingsFile = join5(baseDir, "settings.json");
10762
- if (existsSync5(settingsFile)) {
10798
+ const settingsFile = join4(baseDir, "settings.json");
10799
+ if (existsSync4(settingsFile)) {
10763
10800
  try {
10764
10801
  const s = JSON.parse(readFileSync4(settingsFile, "utf-8"));
10765
10802
  if (s.enabledPlugins)
@@ -10779,7 +10816,7 @@ function listInstancePlugins(configDir) {
10779
10816
  return scanPluginsFromDir(configDir);
10780
10817
  }
10781
10818
  function isPluginsSymlinked(configDir) {
10782
- const pluginsPath = join5(configDir, "plugins");
10819
+ const pluginsPath = join4(configDir, "plugins");
10783
10820
  const st = lstatSafe(pluginsPath);
10784
10821
  return st?.isSymbolicLink() ?? false;
10785
10822
  }
@@ -10795,8 +10832,8 @@ function isClaudeCodeRunning(configDir) {
10795
10832
  }
10796
10833
  }
10797
10834
  function readInstalledPlugins(pluginsDir) {
10798
- const filePath = join5(pluginsDir, "installed_plugins.json");
10799
- if (!existsSync5(filePath)) {
10835
+ const filePath = join4(pluginsDir, "installed_plugins.json");
10836
+ if (!existsSync4(filePath)) {
10800
10837
  return { version: 2, plugins: {} };
10801
10838
  }
10802
10839
  try {
@@ -10806,16 +10843,16 @@ function readInstalledPlugins(pluginsDir) {
10806
10843
  }
10807
10844
  }
10808
10845
  async function writeInstalledPlugins(pluginsDir, data) {
10809
- await writeJsonFileAtomic(join5(pluginsDir, "installed_plugins.json"), data);
10846
+ await writeJsonFileAtomic(join4(pluginsDir, "installed_plugins.json"), data);
10810
10847
  }
10811
10848
  async function addPluginToInstalledPlugins(configDir, pluginId) {
10812
- const pluginsDir = join5(configDir, "plugins");
10849
+ const pluginsDir = join4(configDir, "plugins");
10813
10850
  const data = readInstalledPlugins(pluginsDir);
10814
10851
  const key = `${pluginId}@claude-plugins-official`;
10815
10852
  if (!data.plugins[key]) {
10816
10853
  data.plugins[key] = [];
10817
10854
  }
10818
- const cachePath = join5(configDir, MARKETPLACE_REL);
10855
+ const cachePath = join4(configDir, MARKETPLACE_REL);
10819
10856
  const entry = {
10820
10857
  scope: "user",
10821
10858
  installPath: cachePath,
@@ -10827,7 +10864,7 @@ async function addPluginToInstalledPlugins(configDir, pluginId) {
10827
10864
  await writeInstalledPlugins(pluginsDir, data);
10828
10865
  }
10829
10866
  async function removePluginFromInstalledPlugins(configDir, pluginId) {
10830
- const pluginsDir = join5(configDir, "plugins");
10867
+ const pluginsDir = join4(configDir, "plugins");
10831
10868
  const data = readInstalledPlugins(pluginsDir);
10832
10869
  const key = `${pluginId}@claude-plugins-official`;
10833
10870
  delete data.plugins[key];
@@ -10837,7 +10874,7 @@ function estimatePluginSize(pluginPath) {
10837
10874
  let total = 0;
10838
10875
  try {
10839
10876
  for (const entry of readdirSync2(pluginPath, { withFileTypes: true })) {
10840
- const fullPath = join5(pluginPath, entry.name);
10877
+ const fullPath = join4(pluginPath, entry.name);
10841
10878
  if (entry.isDirectory()) {
10842
10879
  total += estimatePluginSize(fullPath);
10843
10880
  } else {
@@ -10855,8 +10892,8 @@ function detectMcpCollisions(configDir, newPluginIds) {
10855
10892
  const defaultDir = getDefaultClaudeDir();
10856
10893
  for (const pluginId of newPluginIds) {
10857
10894
  for (const subDir of ["plugins", "external_plugins"]) {
10858
- const mcpFile = join5(defaultDir, MARKETPLACE_REL, subDir, pluginId, ".mcp.json");
10859
- if (!existsSync5(mcpFile))
10895
+ const mcpFile = join4(defaultDir, MARKETPLACE_REL, subDir, pluginId, ".mcp.json");
10896
+ if (!existsSync4(mcpFile))
10860
10897
  continue;
10861
10898
  const newServers = readMcpJsonFile(mcpFile);
10862
10899
  for (const name of Object.keys(newServers)) {
@@ -10875,10 +10912,10 @@ function detectMcpCollisions(configDir, newPluginIds) {
10875
10912
  function validatePluginOperation(configDir, operation, pluginId) {
10876
10913
  const errors = [];
10877
10914
  const warnings = [];
10878
- if (!existsSync5(configDir)) {
10915
+ if (!existsSync4(configDir)) {
10879
10916
  errors.push("Instance config directory does not exist");
10880
10917
  }
10881
- if (existsSync5(configDir) && isPluginsSymlinked(configDir)) {
10918
+ if (existsSync4(configDir) && isPluginsSymlinked(configDir)) {
10882
10919
  errors.push("Plugins directory is symlinked (auto-sync). Disable auto-sync first.");
10883
10920
  }
10884
10921
  if (operation === PluginAction.Install && pluginId) {
@@ -10893,7 +10930,7 @@ function validatePluginOperation(configDir, operation, pluginId) {
10893
10930
  errors.push(`Plugin '${pluginId}' not installed in this instance`);
10894
10931
  }
10895
10932
  }
10896
- if (operation === PluginAction.Install && pluginId && existsSync5(configDir)) {
10933
+ if (operation === PluginAction.Install && pluginId && existsSync4(configDir)) {
10897
10934
  const collisions = detectMcpCollisions(configDir, [pluginId]);
10898
10935
  for (const c of collisions) {
10899
10936
  warnings.push(`MCP server name collision: '${c.serverName}'`);
@@ -10904,27 +10941,27 @@ function validatePluginOperation(configDir, operation, pluginId) {
10904
10941
  async function copySinglePlugin(targetConfigDir, pluginId, category) {
10905
10942
  const defaultDir = getDefaultClaudeDir();
10906
10943
  const subDir = category === PluginCategory.Internal ? "plugins" : "external_plugins";
10907
- const sourcePlugin = join5(defaultDir, MARKETPLACE_REL, subDir, pluginId);
10908
- const targetPlugin = join5(targetConfigDir, MARKETPLACE_REL, subDir, pluginId);
10909
- if (!existsSync5(sourcePlugin)) {
10944
+ const sourcePlugin = join4(defaultDir, MARKETPLACE_REL, subDir, pluginId);
10945
+ const targetPlugin = join4(targetConfigDir, MARKETPLACE_REL, subDir, pluginId);
10946
+ if (!existsSync4(sourcePlugin)) {
10910
10947
  throw new ClaudeMultiError(ErrorCode.PLUGIN_NOT_FOUND, `Plugin '${pluginId}' not found in default Claude`);
10911
10948
  }
10912
- const scaffoldDir = join5(targetConfigDir, MARKETPLACE_REL, subDir);
10913
- if (!existsSync5(scaffoldDir)) {
10949
+ const scaffoldDir = join4(targetConfigDir, MARKETPLACE_REL, subDir);
10950
+ if (!existsSync4(scaffoldDir)) {
10914
10951
  await mkdir(scaffoldDir, { recursive: true });
10915
10952
  }
10916
- const marketplaceDir = join5(targetConfigDir, MARKETPLACE_REL);
10917
- if (!existsSync5(marketplaceDir)) {
10953
+ const marketplaceDir = join4(targetConfigDir, MARKETPLACE_REL);
10954
+ if (!existsSync4(marketplaceDir)) {
10918
10955
  await mkdir(marketplaceDir, { recursive: true });
10919
10956
  }
10920
10957
  for (const metaFile of ["known_marketplaces.json", "blocklist.json"]) {
10921
- const src = join5(defaultDir, MARKETPLACE_REL, metaFile);
10922
- const tgt = join5(marketplaceDir, metaFile);
10923
- if (existsSync5(src) && !existsSync5(tgt)) {
10958
+ const src = join4(defaultDir, MARKETPLACE_REL, metaFile);
10959
+ const tgt = join4(marketplaceDir, metaFile);
10960
+ if (existsSync4(src) && !existsSync4(tgt)) {
10924
10961
  await copyFile(src, tgt);
10925
10962
  }
10926
10963
  }
10927
- if (existsSync5(targetPlugin)) {
10964
+ if (existsSync4(targetPlugin)) {
10928
10965
  rmSync2(targetPlugin, { force: true, recursive: true });
10929
10966
  }
10930
10967
  await copyDirRecursive(sourcePlugin, targetPlugin);
@@ -10943,15 +10980,15 @@ async function copySelectedPlugins(targetConfigDir, selections) {
10943
10980
  const defaultDir = getDefaultClaudeDir();
10944
10981
  for (const sel of selections) {
10945
10982
  const subDir = sel.category === PluginCategory.Internal ? "plugins" : "external_plugins";
10946
- const source = join5(defaultDir, MARKETPLACE_REL, subDir, sel.id);
10947
- if (!existsSync5(source)) {
10983
+ const source = join4(defaultDir, MARKETPLACE_REL, subDir, sel.id);
10984
+ if (!existsSync4(source)) {
10948
10985
  throw new ClaudeMultiError(ErrorCode.PLUGIN_NOT_FOUND, `Plugin '${sel.id}' not found in default Claude`);
10949
10986
  }
10950
10987
  }
10951
10988
  let totalSize = 0;
10952
10989
  for (const sel of selections) {
10953
10990
  const subDir = sel.category === PluginCategory.Internal ? "plugins" : "external_plugins";
10954
- totalSize += estimatePluginSize(join5(defaultDir, MARKETPLACE_REL, subDir, sel.id));
10991
+ totalSize += estimatePluginSize(join4(defaultDir, MARKETPLACE_REL, subDir, sel.id));
10955
10992
  }
10956
10993
  if (totalSize > 104857600) {
10957
10994
  throw new ClaudeMultiError(ErrorCode.PLUGIN_TOO_LARGE, `Selected plugins total ${(totalSize / 1024 / 1024).toFixed(1)}MB. Ensure sufficient disk space.`);
@@ -10966,8 +11003,8 @@ async function copySelectedPlugins(targetConfigDir, selections) {
10966
11003
  for (const done of completed) {
10967
11004
  try {
10968
11005
  const subDir = done.category === PluginCategory.Internal ? "plugins" : "external_plugins";
10969
- const targetPath = join5(targetConfigDir, MARKETPLACE_REL, subDir, done.id);
10970
- if (existsSync5(targetPath)) {
11006
+ const targetPath = join4(targetConfigDir, MARKETPLACE_REL, subDir, done.id);
11007
+ if (existsSync4(targetPath)) {
10971
11008
  rmSync2(targetPath, { force: true, recursive: true });
10972
11009
  }
10973
11010
  await removePluginFromInstalledPlugins(targetConfigDir, done.id);
@@ -10983,8 +11020,8 @@ async function removeSinglePlugin(configDir, pluginId, category) {
10983
11020
  throw new ClaudeMultiError(ErrorCode.SYMLINK_CONFLICT, "Cannot remove plugins from a symlinked instance. Disable auto-sync first.");
10984
11021
  }
10985
11022
  const subDir = category === PluginCategory.Internal ? "plugins" : "external_plugins";
10986
- const pluginPath = join5(configDir, MARKETPLACE_REL, subDir, pluginId);
10987
- if (!existsSync5(pluginPath)) {
11023
+ const pluginPath = join4(configDir, MARKETPLACE_REL, subDir, pluginId);
11024
+ if (!existsSync4(pluginPath)) {
10988
11025
  throw new ClaudeMultiError(ErrorCode.PLUGIN_NOT_FOUND, `Plugin '${pluginId}' not found in this instance`);
10989
11026
  }
10990
11027
  const backupPath = pluginPath + ".removing";
@@ -11007,16 +11044,16 @@ async function removeSinglePlugin(configDir, pluginId, category) {
11007
11044
  }
11008
11045
  function getMcpServersFromPlugins(configDir) {
11009
11046
  const result = {};
11010
- const basePlugins = join5(configDir, MARKETPLACE_REL);
11047
+ const basePlugins = join4(configDir, MARKETPLACE_REL);
11011
11048
  for (const subDir of ["plugins", "external_plugins"]) {
11012
- const dir = join5(basePlugins, subDir);
11013
- if (!existsSync5(dir))
11049
+ const dir = join4(basePlugins, subDir);
11050
+ if (!existsSync4(dir))
11014
11051
  continue;
11015
11052
  for (const entry of readdirSync2(dir, { withFileTypes: true })) {
11016
11053
  if (!entry.isDirectory())
11017
11054
  continue;
11018
- const mcpFile = join5(dir, entry.name, ".mcp.json");
11019
- if (!existsSync5(mcpFile))
11055
+ const mcpFile = join4(dir, entry.name, ".mcp.json");
11056
+ if (!existsSync4(mcpFile))
11020
11057
  continue;
11021
11058
  const servers = readMcpJsonFile(mcpFile);
11022
11059
  Object.assign(result, servers);
@@ -11051,6 +11088,7 @@ var init_config = __esm(() => {
11051
11088
  init_json_file();
11052
11089
  init_errors();
11053
11090
  init_constants();
11091
+ init_env();
11054
11092
  init_source();
11055
11093
  SYNC_DIRS = ["plugins", "skills"];
11056
11094
  });
@@ -33330,7 +33368,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
33330
33368
  return 0;
33331
33369
  };
33332
33370
  var validate2 = function validate3(version) {
33333
- return typeof version === "string" && /^[v\d]/.test(version) && semver3.test(version);
33371
+ return typeof version === "string" && /^[v\d]/.test(version) && semver2.test(version);
33334
33372
  };
33335
33373
  var compare = function compare2(v1, v2, operator) {
33336
33374
  assertValidOperator(operator);
@@ -33364,12 +33402,12 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
33364
33402
  return false;
33365
33403
  return true;
33366
33404
  };
33367
- var semver3 = /^[v^~<>=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i;
33405
+ var semver2 = /^[v^~<>=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i;
33368
33406
  var validateAndParse = function validateAndParse2(version) {
33369
33407
  if (typeof version !== "string") {
33370
33408
  throw new TypeError("Invalid argument expected string");
33371
33409
  }
33372
- var match = version.match(semver3);
33410
+ var match = version.match(semver2);
33373
33411
  if (!match) {
33374
33412
  throw new Error("Invalid argument not valid semver ('".concat(version, "' received)"));
33375
33413
  }
@@ -56046,6 +56084,18 @@ function useConfig() {
56046
56084
  }
56047
56085
  await reload();
56048
56086
  }, [reload]);
56087
+ const syncTemplateEnv = import_react66.useCallback(async (instance) => {
56088
+ await syncProviderTemplateForInstance(instance);
56089
+ await reload();
56090
+ }, [reload]);
56091
+ const regenerateWrapper = import_react66.useCallback(async (instance) => {
56092
+ await createWrapper({
56093
+ name: instance.name,
56094
+ configDir: instance.configDir,
56095
+ binaryPath: instance.binaryPath
56096
+ });
56097
+ await reload();
56098
+ }, [reload]);
56049
56099
  const migrationStatus = config ? getMigrationStatus(config) : null;
56050
56100
  return {
56051
56101
  config,
@@ -56056,6 +56106,8 @@ function useConfig() {
56056
56106
  addInstance: addInstance2,
56057
56107
  removeInstance: removeInstance2,
56058
56108
  toggleAutoSync,
56109
+ syncTemplateEnv,
56110
+ regenerateWrapper,
56059
56111
  migrationStatus,
56060
56112
  instanceMigrationVersion: config?.instanceMigrationVersion,
56061
56113
  getInstance,
@@ -56125,7 +56177,7 @@ var exports_AddInstance = {};
56125
56177
  __export(exports_AddInstance, {
56126
56178
  AddInstance: () => AddInstance
56127
56179
  });
56128
- import { join as join7 } from "node:path";
56180
+ import { join as join6 } from "node:path";
56129
56181
  import { homedir as homedir3 } from "node:os";
56130
56182
  function stepNumber(step) {
56131
56183
  return STEP_FLOW.indexOf(step) + 1;
@@ -56169,6 +56221,9 @@ function reducer5(state, action) {
56169
56221
  case "SET_ERROR":
56170
56222
  return { ...state, error: action.error };
56171
56223
  case "SELECT_PROVIDER":
56224
+ if (!action.provider || !providerHasRegions(action.provider)) {
56225
+ return { ...state, selectedProvider: action.provider, useProvider: action.useProvider, selectedRegion: null };
56226
+ }
56172
56227
  return { ...state, selectedProvider: action.provider, useProvider: action.useProvider };
56173
56228
  case "SET_REGION":
56174
56229
  return { ...state, selectedRegion: action.region };
@@ -56291,34 +56346,37 @@ var import_react67, jsx_dev_runtime4, AddResult = ({
56291
56346
  onChange: onSelect
56292
56347
  }, undefined, false, undefined, this)
56293
56348
  ]
56294
- }, undefined, true, undefined, this), ProviderRegionStep = ({ state, onSelect }) => /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
56295
- flexDirection: "column",
56296
- gap: 1,
56297
- children: [
56298
- /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
56299
- children: "Select your subscription region:"
56300
- }, undefined, false, undefined, this),
56301
- /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
56302
- borderStyle: "round",
56303
- borderColor: "yellow",
56304
- paddingX: 1,
56305
- children: /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
56306
- bold: true,
56307
- color: "yellow",
56308
- children: "Check your Xiaomi account console to confirm the correct region for your subscription."
56349
+ }, undefined, true, undefined, this), ProviderRegionStep = ({ state, onSelect }) => {
56350
+ const regions = state.selectedProvider ? getProviderRegions(state.selectedProvider) : undefined;
56351
+ return /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
56352
+ flexDirection: "column",
56353
+ gap: 1,
56354
+ children: [
56355
+ /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
56356
+ children: "Select your subscription region:"
56357
+ }, undefined, false, undefined, this),
56358
+ /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
56359
+ borderStyle: "round",
56360
+ borderColor: "yellow",
56361
+ paddingX: 1,
56362
+ children: /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
56363
+ bold: true,
56364
+ color: "yellow",
56365
+ children: "Check your account console to confirm the correct region for your subscription."
56366
+ }, undefined, false, undefined, this)
56367
+ }, undefined, false, undefined, this),
56368
+ /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Select, {
56369
+ options: regions ? Object.entries(regions).map(([key, val]) => ({
56370
+ label: `${val.label} — ${val.baseUrl}`,
56371
+ value: key
56372
+ })) : [],
56373
+ visibleOptionCount: 3,
56374
+ defaultValue: state.selectedRegion ?? undefined,
56375
+ onChange: onSelect
56309
56376
  }, undefined, false, undefined, this)
56310
- }, undefined, false, undefined, this),
56311
- /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Select, {
56312
- options: Object.entries(MIMO_TOKEN_REGIONS).map(([key, val]) => ({
56313
- label: `${val.label} — ${val.baseUrl}`,
56314
- value: key
56315
- })),
56316
- visibleOptionCount: 3,
56317
- defaultValue: state.selectedRegion ?? undefined,
56318
- onChange: onSelect
56319
- }, undefined, false, undefined, this)
56320
- ]
56321
- }, undefined, true, undefined, this), ProviderApiKeyStep = ({ state, onSubmit }) => /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
56377
+ ]
56378
+ }, undefined, true, undefined, this);
56379
+ }, ProviderApiKeyStep = ({ state, onSubmit }) => /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Box_default, {
56322
56380
  flexDirection: "column",
56323
56381
  gap: 1,
56324
56382
  children: [
@@ -56345,7 +56403,7 @@ var import_react67, jsx_dev_runtime4, AddResult = ({
56345
56403
  dimColor: true,
56346
56404
  children: [
56347
56405
  "Config: ",
56348
- join7(homedir3(), `.claude-${state.name}`)
56406
+ join6(homedir3(), `.claude-${state.name}`)
56349
56407
  ]
56350
56408
  }, undefined, true, undefined, this),
56351
56409
  /* @__PURE__ */ jsx_dev_runtime4.jsxDEV(Text, {
@@ -56475,7 +56533,7 @@ var import_react67, jsx_dev_runtime4, AddResult = ({
56475
56533
  dispatch({ type: "SET_STEP", step: "creating" /* Creating */ });
56476
56534
  dispatch({ type: "SET_ERROR", error: "" });
56477
56535
  try {
56478
- const cDir = join7(homedir3(), `.claude-${state.name}`);
56536
+ const cDir = join6(homedir3(), `.claude-${state.name}`);
56479
56537
  const bPath = cfg.getDefaultBinaryPath(state.name);
56480
56538
  const instance = {
56481
56539
  name: state.name,
@@ -56483,7 +56541,9 @@ var import_react67, jsx_dev_runtime4, AddResult = ({
56483
56541
  binaryPath: bPath,
56484
56542
  createdAt: new Date().toISOString(),
56485
56543
  autoSync: sync,
56486
- createdWithVersion: getClaudeMultiVersion()
56544
+ createdWithVersion: getClaudeMultiVersion(),
56545
+ ...state.useProvider && state.selectedProvider ? { providerTemplate: state.selectedProvider } : {},
56546
+ ...state.selectedRegion && state.useProvider && state.selectedProvider && providerHasRegions(state.selectedProvider) ? { providerRegion: state.selectedRegion } : {}
56487
56547
  };
56488
56548
  await cfg.addInstance(instance);
56489
56549
  await Promise.all([
@@ -56717,10 +56777,11 @@ __export(exports_health, {
56717
56777
  dismissIssue: () => dismissIssue,
56718
56778
  dismissAllIssues: () => dismissAllIssues
56719
56779
  });
56720
- import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync3, mkdirSync as mkdirSync5 } from "node:fs";
56721
- import { join as join8 } from "node:path";
56780
+ import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, renameSync as renameSync2, unlinkSync as unlinkSync2 } from "node:fs";
56781
+ import { randomBytes as randomBytes3 } from "node:crypto";
56782
+ import { join as join7 } from "node:path";
56722
56783
  function getHealthFile() {
56723
- return join8(getBaseDir(), ".claude-multi", "health-status.json");
56784
+ return join7(getBaseDir(), ".claude-multi", "health-status.json");
56724
56785
  }
56725
56786
  function runHealthChecks(instances2, migrationStatus, instanceMigrationVersion) {
56726
56787
  const now2 = new Date().toISOString();
@@ -56757,7 +56818,7 @@ function runHealthChecks(instances2, migrationStatus, instanceMigrationVersion)
56757
56818
  });
56758
56819
  }
56759
56820
  for (const inst of instances2) {
56760
- if (!existsSync7(inst.configDir)) {
56821
+ if (!existsSync6(inst.configDir)) {
56761
56822
  issues.push({
56762
56823
  id: `configdir-missing-${inst.name}`,
56763
56824
  severity: "error",
@@ -56773,7 +56834,7 @@ function runHealthChecks(instances2, migrationStatus, instanceMigrationVersion)
56773
56834
  });
56774
56835
  continue;
56775
56836
  }
56776
- if (!existsSync7(inst.binaryPath)) {
56837
+ if (!existsSync6(inst.binaryPath)) {
56777
56838
  issues.push({
56778
56839
  id: `binary-missing-${inst.name}`,
56779
56840
  severity: "warning",
@@ -56788,10 +56849,11 @@ function runHealthChecks(instances2, migrationStatus, instanceMigrationVersion)
56788
56849
  resolutionHint: "Re-create the instance or run 'claude-multi sync'"
56789
56850
  });
56790
56851
  }
56791
- const settingsFile = join8(inst.configDir, "settings.json");
56792
- if (existsSync7(settingsFile)) {
56852
+ const settingsFile = join7(inst.configDir, "settings.json");
56853
+ if (existsSync6(settingsFile)) {
56854
+ let parsed = null;
56793
56855
  try {
56794
- JSON.parse(readFileSync6(settingsFile, "utf-8"));
56856
+ parsed = JSON.parse(readFileSync6(settingsFile, "utf-8"));
56795
56857
  } catch {
56796
56858
  issues.push({
56797
56859
  id: `settings-corrupt-${inst.name}`,
@@ -56807,6 +56869,29 @@ function runHealthChecks(instances2, migrationStatus, instanceMigrationVersion)
56807
56869
  resolutionHint: "Fix or delete the corrupted settings.json"
56808
56870
  });
56809
56871
  }
56872
+ if (parsed && inst.providerTemplate && providerHasRegions(inst.providerTemplate)) {
56873
+ const env3 = parsed.env;
56874
+ const actualUrl = env3?.ANTHROPIC_BASE_URL;
56875
+ const actualRegion = actualUrl ? detectRegionFromBaseUrl(actualUrl) : null;
56876
+ if (inst.providerRegion && actualRegion && inst.providerRegion !== actualRegion) {
56877
+ const providerRegions = getProviderRegions(inst.providerTemplate);
56878
+ const expectedUrl = providerRegions?.[inst.providerRegion]?.baseUrl;
56879
+ issues.push({
56880
+ id: `region-mismatch-${inst.name}`,
56881
+ severity: "warning",
56882
+ category: "settings",
56883
+ title: "Region URL mismatch",
56884
+ message: `Instance '${inst.name}' stored region is ${inst.providerRegion} but base URL points to ${actualRegion}`,
56885
+ detail: `Stored region: ${inst.providerRegion} (${expectedUrl})
56886
+ Actual URL: ${actualUrl}`,
56887
+ instanceName: inst.name,
56888
+ timestamp: now2,
56889
+ dismissed: false,
56890
+ resolved: false,
56891
+ resolutionHint: `Edit settings.json to set ANTHROPIC_BASE_URL to ${expectedUrl}, or run 'claude-multi doctor fix'`
56892
+ });
56893
+ }
56894
+ }
56810
56895
  }
56811
56896
  const symlinks = detectBrokenSymlinks(inst.configDir);
56812
56897
  if (symlinks.broken.length > 0) {
@@ -56824,13 +56909,15 @@ function runHealthChecks(instances2, migrationStatus, instanceMigrationVersion)
56824
56909
  resolutionHint: "Re-sync symlinks from the home screen"
56825
56910
  });
56826
56911
  }
56827
- if (existsSync7(inst.binaryPath) && existsSync7(PINNED_CLAUDE_BIN)) {
56912
+ const expectedClaudePath = tryGetClaudePath();
56913
+ if (existsSync6(inst.binaryPath) && expectedClaudePath) {
56828
56914
  try {
56829
56915
  const wrapperContent = readFileSync6(inst.binaryPath, "utf-8");
56830
56916
  const shellMatch = wrapperContent.match(/exec\s+"([^"]+)"/);
56917
+ const cmdMatch = wrapperContent.match(/"([^"]+)"\s+%\*/);
56831
56918
  const nodeMatch = wrapperContent.match(/spawn\("([^"]+)"/);
56832
- const currentBin = shellMatch?.[1] ?? nodeMatch?.[1];
56833
- if (currentBin && currentBin !== PINNED_CLAUDE_BIN) {
56919
+ const currentBin = shellMatch?.[1] ?? cmdMatch?.[1] ?? nodeMatch?.[1];
56920
+ if (currentBin && currentBin !== expectedClaudePath) {
56834
56921
  issues.push({
56835
56922
  id: `wrong-claude-version-${inst.name}`,
56836
56923
  severity: "error",
@@ -56838,7 +56925,7 @@ function runHealthChecks(instances2, migrationStatus, instanceMigrationVersion)
56838
56925
  title: "Wrong Claude binary",
56839
56926
  message: `Instance '${inst.name}' uses a Claude version that may break 3rd-party providers`,
56840
56927
  detail: `Current: ${currentBin}
56841
- Expected: ${PINNED_CLAUDE_BIN}`,
56928
+ Expected: ${expectedClaudePath}`,
56842
56929
  instanceName: inst.name,
56843
56930
  timestamp: now2,
56844
56931
  dismissed: false,
@@ -56868,7 +56955,7 @@ Expected: ${PINNED_CLAUDE_BIN}`,
56868
56955
  }
56869
56956
  function loadHealthStatus() {
56870
56957
  const healthFile = getHealthFile();
56871
- if (!existsSync7(healthFile)) {
56958
+ if (!existsSync6(healthFile)) {
56872
56959
  return { lastChecked: "", issues: [] };
56873
56960
  }
56874
56961
  try {
@@ -56878,10 +56965,21 @@ function loadHealthStatus() {
56878
56965
  }
56879
56966
  }
56880
56967
  function saveHealthStatus(status) {
56881
- const dir = join8(getBaseDir(), ".claude-multi");
56882
- if (!existsSync7(dir))
56883
- mkdirSync5(dir, { recursive: true });
56884
- writeFileSync3(getHealthFile(), JSON.stringify(status, null, 2), "utf-8");
56968
+ const dir = join7(getBaseDir(), ".claude-multi");
56969
+ if (!existsSync6(dir))
56970
+ mkdirSync4(dir, { recursive: true });
56971
+ const healthFile = getHealthFile();
56972
+ const tmpPath = `${healthFile}.tmp.${randomBytes3(4).toString("hex")}`;
56973
+ try {
56974
+ writeFileSync3(tmpPath, JSON.stringify(status, null, 2), "utf-8");
56975
+ JSON.parse(readFileSync6(tmpPath, "utf-8"));
56976
+ renameSync2(tmpPath, healthFile);
56977
+ } catch (err) {
56978
+ try {
56979
+ unlinkSync2(tmpPath);
56980
+ } catch {}
56981
+ throw err;
56982
+ }
56885
56983
  }
56886
56984
  function dismissIssue(id) {
56887
56985
  const status = loadHealthStatus();
@@ -56899,20 +56997,22 @@ function dismissAllIssues() {
56899
56997
  saveHealthStatus(status);
56900
56998
  }
56901
56999
  function fixWrapperVersions(instances2) {
56902
- if (!existsSync7(PINNED_CLAUDE_BIN))
57000
+ const expectedClaudePath = tryGetClaudePath();
57001
+ if (!expectedClaudePath)
56903
57002
  return [];
56904
57003
  const fixed = [];
56905
57004
  for (const inst of instances2) {
56906
- if (!existsSync7(inst.binaryPath))
57005
+ if (!existsSync6(inst.binaryPath))
56907
57006
  continue;
56908
57007
  try {
56909
57008
  const content = readFileSync6(inst.binaryPath, "utf-8");
56910
57009
  const shellMatch = content.match(/exec\s+"([^"]+)"/);
57010
+ const cmdMatch = content.match(/"([^"]+)"\s+%\*/);
56911
57011
  const nodeMatch = content.match(/spawn\("([^"]+)"/);
56912
- const currentBin = shellMatch?.[1] ?? nodeMatch?.[1];
56913
- if (!currentBin || currentBin === PINNED_CLAUDE_BIN)
57012
+ const currentBin = shellMatch?.[1] ?? cmdMatch?.[1] ?? nodeMatch?.[1];
57013
+ if (!currentBin || currentBin === expectedClaudePath)
56914
57014
  continue;
56915
- const newContent = buildWrapperScript(inst, PINNED_CLAUDE_BIN);
57015
+ const newContent = buildWrapperScript(inst, expectedClaudePath);
56916
57016
  if (content !== newContent) {
56917
57017
  writeFileSync3(inst.binaryPath, newContent, { mode: 493 });
56918
57018
  }
@@ -56928,6 +57028,7 @@ var init_health = __esm(() => {
56928
57028
  init_version();
56929
57029
  init_migration();
56930
57030
  init_wrapper();
57031
+ init_templates();
56931
57032
  });
56932
57033
 
56933
57034
  // src/ink/components/Footer.tsx
@@ -57071,12 +57172,12 @@ var jsx_dev_runtime6, WarningBanner = ({
57071
57172
  children: [
57072
57173
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
57073
57174
  color: "red",
57074
- children: " ⚠ Some instances use a Claude version incompatible with 3rd-party APIs. "
57175
+ children: " ⚠ Some instances have version issues. "
57075
57176
  }, undefined, false, undefined, this),
57076
57177
  /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Text, {
57077
57178
  color: "red",
57078
57179
  bold: true,
57079
- children: "Press ! to auto-fix."
57180
+ children: "Press ! to review and fix."
57080
57181
  }, undefined, false, undefined, this)
57081
57182
  ]
57082
57183
  }, undefined, true, undefined, this)
@@ -57348,7 +57449,110 @@ var init_InstanceSelectMenu = __esm(async () => {
57348
57449
  jsx_dev_runtime9 = __toESM(require_jsx_dev_runtime(), 1);
57349
57450
  });
57350
57451
 
57452
+ // src/ink/util/instance-diagnostics.ts
57453
+ import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
57454
+ import { join as join8 } from "node:path";
57455
+ function tryResolveRegionalTemplate(template2, region) {
57456
+ if (!template2)
57457
+ return;
57458
+ try {
57459
+ const providerRegions = getProviderRegions(template2.name);
57460
+ if (providerRegions && region in providerRegions) {
57461
+ return resolveRegionTemplate(template2, region);
57462
+ }
57463
+ } catch {}
57464
+ return;
57465
+ }
57466
+ function detectTemplateMismatch(instance) {
57467
+ const providerName = instance.providerTemplate ?? detectProvider(instance.configDir);
57468
+ if (!providerName) {
57469
+ return { status: "unknown", providerName: null };
57470
+ }
57471
+ let template2 = getProviderTemplate(providerName);
57472
+ if (!template2) {
57473
+ return { status: "unknown", providerName };
57474
+ }
57475
+ const settingsFile = join8(instance.configDir, "settings.json");
57476
+ if (!existsSync7(settingsFile)) {
57477
+ return { status: "unknown", providerName };
57478
+ }
57479
+ let existingEnv = {};
57480
+ try {
57481
+ const raw = JSON.parse(readFileSync7(settingsFile, "utf-8"));
57482
+ existingEnv = raw.env ?? {};
57483
+ } catch {
57484
+ return { status: "unknown", providerName };
57485
+ }
57486
+ if (providerHasRegions(providerName)) {
57487
+ const existingUrl = existingEnv.ANTHROPIC_BASE_URL;
57488
+ const detectedRegion = existingUrl ? detectRegionFromBaseUrl(existingUrl) ?? instance.providerRegion : instance.providerRegion;
57489
+ if (detectedRegion) {
57490
+ const resolved = tryResolveRegionalTemplate(template2, detectedRegion);
57491
+ if (resolved) {
57492
+ template2 = resolved;
57493
+ }
57494
+ }
57495
+ }
57496
+ const templateEnv = template2.settings.env;
57497
+ for (const [key, expectedValue] of Object.entries(templateEnv)) {
57498
+ if (key === "ANTHROPIC_AUTH_TOKEN")
57499
+ continue;
57500
+ if (TUNABLE_ENV_VARS.has(key))
57501
+ continue;
57502
+ if (existingEnv[key] !== expectedValue) {
57503
+ return { status: "mismatch", providerName };
57504
+ }
57505
+ }
57506
+ return { status: "match", providerName };
57507
+ }
57508
+ function detectWrapperMismatch(instance) {
57509
+ if (!existsSync7(instance.binaryPath)) {
57510
+ return { status: "missing" };
57511
+ }
57512
+ const expected = generateWrapperScriptSafe({
57513
+ name: instance.name,
57514
+ configDir: instance.configDir,
57515
+ binaryPath: instance.binaryPath
57516
+ });
57517
+ if (expected === null) {
57518
+ return { status: "unknown" };
57519
+ }
57520
+ try {
57521
+ const current = readFileSync7(instance.binaryPath, "utf-8");
57522
+ return current === expected ? { status: "match" } : { status: "mismatch" };
57523
+ } catch {
57524
+ return { status: "unknown" };
57525
+ }
57526
+ }
57527
+ var init_instance_diagnostics = __esm(() => {
57528
+ init_templates();
57529
+ init_wrapper();
57530
+ init_env();
57531
+ });
57532
+
57351
57533
  // src/ink/screens/ShowInstanceInfo.tsx
57534
+ function templateStatusLabel(status) {
57535
+ switch (status) {
57536
+ case "match":
57537
+ return "✓ up to date";
57538
+ case "mismatch":
57539
+ return "⚠ mismatch detected";
57540
+ case "unknown":
57541
+ return "? unknown";
57542
+ }
57543
+ }
57544
+ function wrapperStatusLabel(status) {
57545
+ switch (status) {
57546
+ case "match":
57547
+ return "✓ up to date";
57548
+ case "mismatch":
57549
+ return "⚠ mismatch detected";
57550
+ case "missing":
57551
+ return "✗ wrapper missing";
57552
+ case "unknown":
57553
+ return "? unknown";
57554
+ }
57555
+ }
57352
57556
  var import_react69, jsx_dev_runtime10, DetailRow = ({
57353
57557
  label,
57354
57558
  value,
@@ -57382,19 +57586,74 @@ var import_react69, jsx_dev_runtime10, DetailRow = ({
57382
57586
  }, undefined, false, undefined, this)
57383
57587
  ]
57384
57588
  }, undefined, true, undefined, this);
57385
- }, EMPTY_INFO, ShowInstanceInfo = ({ onBack }) => {
57386
- const { instances: instances2, listInstancePlugins: listInstancePlugins2, getInstanceMcpServers: getInstanceMcpServers2 } = useConfig();
57589
+ }, EMPTY_INFO, ACTION_VALUES, ShowInstanceInfo = ({ onBack }) => {
57590
+ const { exit } = use_app_default();
57591
+ const { instances: instances2, listInstancePlugins: listInstancePlugins2, getInstanceMcpServers: getInstanceMcpServers2, syncTemplateEnv, regenerateWrapper } = useConfig();
57387
57592
  const [step, setStep] = import_react69.useState("select");
57388
57593
  const [selected, setSelected] = import_react69.useState(null);
57389
57594
  const [infoData, setInfoData] = import_react69.useState(EMPTY_INFO);
57390
- useNavigation(() => {
57391
- if (step === "info") {
57392
- setStep("select");
57393
- setSelected(null);
57394
- } else {
57395
- onBack();
57595
+ const [templateStatus, setTemplateStatus] = import_react69.useState("unknown");
57596
+ const [wrapperStatus, setWrapperStatus] = import_react69.useState("unknown");
57597
+ const [providerName, setProviderName] = import_react69.useState(null);
57598
+ const [actionResult, setActionResult] = import_react69.useState(null);
57599
+ const [executing, setExecuting] = import_react69.useState(false);
57600
+ const liveSelected = selected ? instances2.find((i) => i.name === selected.name) ?? selected : null;
57601
+ const runDiagnostics = import_react69.useCallback((inst) => {
57602
+ const tmpl = detectTemplateMismatch(inst);
57603
+ const wrap2 = detectWrapperMismatch(inst);
57604
+ setTemplateStatus(tmpl.status);
57605
+ setWrapperStatus(wrap2.status);
57606
+ setProviderName(tmpl.providerName);
57607
+ }, []);
57608
+ const loadInstanceInfo = import_react69.useCallback(async (inst) => {
57609
+ try {
57610
+ const plugins = listInstancePlugins2(inst.configDir);
57611
+ const mcpData = await getInstanceMcpServers2(inst.configDir);
57612
+ setInfoData({
57613
+ pluginCount: plugins.length,
57614
+ enabledCount: plugins.filter((p) => p.enabled).length,
57615
+ mcpPluginCount: Object.keys(mcpData.fromPlugins).length,
57616
+ mcpCustomCount: Object.keys(mcpData.fromSettings).length,
57617
+ mcpCount: Object.keys(mcpData.all).length
57618
+ });
57619
+ } catch {
57620
+ setInfoData(EMPTY_INFO);
57621
+ }
57622
+ }, [listInstancePlugins2, getInstanceMcpServers2]);
57623
+ use_input_default((input, key) => {
57624
+ if (executing)
57625
+ return;
57626
+ if (input === "q") {
57627
+ exit();
57628
+ return;
57629
+ }
57630
+ if (key.escape) {
57631
+ if (step === "info") {
57632
+ setStep("select");
57633
+ setSelected(null);
57634
+ } else if (step === "actions") {
57635
+ setStep("info");
57636
+ } else if (step === "result") {
57637
+ goToInfo();
57638
+ } else {
57639
+ onBack();
57640
+ }
57641
+ } else if (key.return) {
57642
+ if (step === "info") {
57643
+ setStep("actions");
57644
+ } else if (step === "result") {
57645
+ goToInfo();
57646
+ }
57396
57647
  }
57397
57648
  });
57649
+ const goToInfo = () => {
57650
+ const inst = liveSelected;
57651
+ if (inst) {
57652
+ runDiagnostics(inst);
57653
+ loadInstanceInfo(inst);
57654
+ }
57655
+ setStep("info");
57656
+ };
57398
57657
  if (instances2.length === 0) {
57399
57658
  return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
57400
57659
  flexDirection: "column",
@@ -57425,20 +57684,62 @@ var import_react69, jsx_dev_runtime10, DetailRow = ({
57425
57684
  return;
57426
57685
  setSelected(inst);
57427
57686
  setStep("info");
57687
+ runDiagnostics(inst);
57688
+ await loadInstanceInfo(inst);
57689
+ };
57690
+ const handleAction = async (value) => {
57691
+ if (executing)
57692
+ return;
57693
+ if (value === ACTION_VALUES.Back || !selected) {
57694
+ setStep("info");
57695
+ return;
57696
+ }
57697
+ setActionResult(null);
57698
+ setExecuting(true);
57699
+ setStep("executing");
57428
57700
  try {
57429
- const plugins = listInstancePlugins2(inst.configDir);
57430
- const mcpData = await getInstanceMcpServers2(inst.configDir);
57431
- setInfoData({
57432
- pluginCount: plugins.length,
57433
- enabledCount: plugins.filter((p) => p.enabled).length,
57434
- mcpPluginCount: Object.keys(mcpData.fromPlugins).length,
57435
- mcpCustomCount: Object.keys(mcpData.fromSettings).length,
57436
- mcpCount: Object.keys(mcpData.all).length
57701
+ if (value === ACTION_VALUES.SyncTemplate) {
57702
+ await syncTemplateEnv(liveSelected ?? selected);
57703
+ setActionResult({ message: `Settings template updated for '${selected.name}'`, type: "success" });
57704
+ } else if (value === ACTION_VALUES.UpdateWrapper || value === ACTION_VALUES.OverrideWrapper) {
57705
+ await regenerateWrapper(liveSelected ?? selected);
57706
+ setActionResult({ message: `Alias wrapper regenerated for '${selected.name}'`, type: "success" });
57707
+ }
57708
+ } catch (err) {
57709
+ setActionResult({
57710
+ message: err instanceof Error ? err.message : String(err),
57711
+ type: "error"
57437
57712
  });
57438
- } catch {
57439
- setInfoData(EMPTY_INFO);
57440
57713
  }
57714
+ setExecuting(false);
57715
+ setStep("result");
57716
+ };
57717
+ const buildActionOptions = () => {
57718
+ const options = [];
57719
+ if (providerName) {
57720
+ options.push({
57721
+ label: `\uD83D\uDD04 Update settings template [${templateStatusLabel(templateStatus)}]`,
57722
+ value: ACTION_VALUES.SyncTemplate
57723
+ });
57724
+ }
57725
+ options.push({
57726
+ label: `\uD83D\uDD27 Update alias wrapper [${wrapperStatusLabel(wrapperStatus)}]`,
57727
+ value: ACTION_VALUES.UpdateWrapper
57728
+ });
57729
+ if (wrapperStatus === "mismatch" || wrapperStatus === "missing") {
57730
+ options.push({
57731
+ label: `\uD83D\uDD28 Override alias to standard`,
57732
+ value: ACTION_VALUES.OverrideWrapper
57733
+ });
57734
+ }
57735
+ options.push({ label: "← Back", value: ACTION_VALUES.Back });
57736
+ return options;
57441
57737
  };
57738
+ const hasPlugins = infoData.pluginCount !== null;
57739
+ const hasMcp = infoData.mcpCount !== null;
57740
+ const hasProvider = providerName !== null;
57741
+ const lastRow = hasMcp ? "mcp" : hasPlugins ? "plugins" : hasProvider ? "provider" : "version";
57742
+ const displayInstance = liveSelected ?? selected;
57442
57743
  return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
57443
57744
  flexDirection: "column",
57444
57745
  width: "100",
@@ -57452,7 +57753,7 @@ var import_react69, jsx_dev_runtime10, DetailRow = ({
57452
57753
  instances: instances2,
57453
57754
  onSelect: handleInstanceSelect
57454
57755
  }, undefined, false, undefined, this),
57455
- step === "info" && selected && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
57756
+ step === "info" && displayInstance && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
57456
57757
  flexDirection: "column",
57457
57758
  gap: 0,
57458
57759
  children: [
@@ -57466,7 +57767,7 @@ var import_react69, jsx_dev_runtime10, DetailRow = ({
57466
57767
  /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
57467
57768
  bold: true,
57468
57769
  color: "cyan",
57469
- children: selected.name
57770
+ children: displayInstance.name
57470
57771
  }, undefined, false, undefined, this)
57471
57772
  ]
57472
57773
  }, undefined, true, undefined, this),
@@ -57476,53 +57777,186 @@ var import_react69, jsx_dev_runtime10, DetailRow = ({
57476
57777
  children: [
57477
57778
  /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DetailRow, {
57478
57779
  label: "Binary",
57479
- value: selected.binaryPath,
57780
+ value: displayInstance.binaryPath,
57480
57781
  delay: 50
57481
57782
  }, undefined, false, undefined, this),
57482
57783
  /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DetailRow, {
57483
57784
  label: "Config",
57484
- value: selected.configDir,
57785
+ value: displayInstance.configDir,
57485
57786
  delay: 100
57486
57787
  }, undefined, false, undefined, this),
57487
57788
  /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DetailRow, {
57488
57789
  label: "Created",
57489
- value: new Date(selected.createdAt).toLocaleString(),
57790
+ value: new Date(displayInstance.createdAt).toLocaleString(),
57490
57791
  delay: 150
57491
57792
  }, undefined, false, undefined, this),
57492
57793
  /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DetailRow, {
57493
57794
  label: "Auto-sync",
57494
- value: selected.autoSync !== false ? "✓ Enabled" : "✗ Disabled",
57495
- color: selected.autoSync !== false ? "green" : "red",
57795
+ value: displayInstance.autoSync !== false ? "✓ Enabled" : "✗ Disabled",
57796
+ color: displayInstance.autoSync !== false ? "green" : "red",
57496
57797
  delay: 200
57497
57798
  }, undefined, false, undefined, this),
57498
57799
  /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DetailRow, {
57499
57800
  label: "Version",
57500
- value: selected.createdWithVersion === LEGACY_INSTANCE_VERSION ? "before version tracking" : selected.createdWithVersion,
57501
- color: selected.createdWithVersion === LEGACY_INSTANCE_VERSION ? "yellow" : undefined,
57801
+ value: displayInstance.createdWithVersion === LEGACY_INSTANCE_VERSION ? "before version tracking" : displayInstance.createdWithVersion,
57802
+ color: displayInstance.createdWithVersion === LEGACY_INSTANCE_VERSION ? "yellow" : undefined,
57803
+ last: lastRow === "version",
57502
57804
  delay: 250
57503
57805
  }, undefined, false, undefined, this),
57504
- infoData.pluginCount !== null && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DetailRow, {
57806
+ hasProvider && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DetailRow, {
57807
+ label: "Provider",
57808
+ value: providerName,
57809
+ color: templateStatus === "match" ? undefined : templateStatus === "mismatch" ? "yellow" : undefined,
57810
+ last: lastRow === "provider",
57811
+ delay: 275
57812
+ }, undefined, false, undefined, this),
57813
+ hasPlugins && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DetailRow, {
57505
57814
  label: "Plugins",
57506
57815
  value: `${infoData.pluginCount} installed, ${infoData.enabledCount} enabled`,
57816
+ last: lastRow === "plugins",
57507
57817
  delay: 300
57508
57818
  }, undefined, false, undefined, this),
57509
- infoData.mcpCount !== null && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DetailRow, {
57819
+ hasMcp && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(DetailRow, {
57510
57820
  label: "MCP Servers",
57511
57821
  value: `${infoData.mcpCount} total (${infoData.mcpPluginCount} from plugins, ${infoData.mcpCustomCount} custom)`,
57512
- last: true,
57822
+ last: lastRow === "mcp",
57513
57823
  delay: 350
57514
57824
  }, undefined, false, undefined, this)
57515
57825
  ]
57516
57826
  }, undefined, true, undefined, this)
57517
57827
  ]
57518
57828
  }, undefined, true, undefined, this),
57829
+ step === "actions" && displayInstance && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
57830
+ flexDirection: "column",
57831
+ gap: 1,
57832
+ children: [
57833
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
57834
+ gap: 1,
57835
+ children: [
57836
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
57837
+ color: "cyan",
57838
+ children: "●"
57839
+ }, undefined, false, undefined, this),
57840
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
57841
+ bold: true,
57842
+ color: "cyan",
57843
+ children: displayInstance.name
57844
+ }, undefined, false, undefined, this)
57845
+ ]
57846
+ }, undefined, true, undefined, this),
57847
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
57848
+ marginTop: 1,
57849
+ children: /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
57850
+ bold: true,
57851
+ children: "Actions:"
57852
+ }, undefined, false, undefined, this)
57853
+ }, undefined, false, undefined, this),
57854
+ (() => {
57855
+ const actionOptions = buildActionOptions();
57856
+ return /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Select, {
57857
+ options: actionOptions,
57858
+ visibleOptionCount: actionOptions.length,
57859
+ onChange: handleAction
57860
+ }, undefined, false, undefined, this);
57861
+ })()
57862
+ ]
57863
+ }, undefined, true, undefined, this),
57864
+ step === "executing" && displayInstance && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
57865
+ flexDirection: "column",
57866
+ gap: 1,
57867
+ children: [
57868
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
57869
+ gap: 1,
57870
+ children: [
57871
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
57872
+ color: "cyan",
57873
+ children: "●"
57874
+ }, undefined, false, undefined, this),
57875
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
57876
+ bold: true,
57877
+ color: "cyan",
57878
+ children: displayInstance.name
57879
+ }, undefined, false, undefined, this)
57880
+ ]
57881
+ }, undefined, true, undefined, this),
57882
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
57883
+ marginTop: 1,
57884
+ children: /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Spinner, {
57885
+ label: "Updating..."
57886
+ }, undefined, false, undefined, this)
57887
+ }, undefined, false, undefined, this)
57888
+ ]
57889
+ }, undefined, true, undefined, this),
57890
+ step === "result" && displayInstance && actionResult && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
57891
+ flexDirection: "column",
57892
+ gap: 1,
57893
+ children: [
57894
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
57895
+ gap: 1,
57896
+ children: [
57897
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
57898
+ color: "cyan",
57899
+ children: "●"
57900
+ }, undefined, false, undefined, this),
57901
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
57902
+ bold: true,
57903
+ color: "cyan",
57904
+ children: displayInstance.name
57905
+ }, undefined, false, undefined, this)
57906
+ ]
57907
+ }, undefined, true, undefined, this),
57908
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
57909
+ marginTop: 1,
57910
+ children: /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(StatusBar, {
57911
+ message: actionResult.message,
57912
+ type: actionResult.type
57913
+ }, undefined, false, undefined, this)
57914
+ }, undefined, false, undefined, this)
57915
+ ]
57916
+ }, undefined, true, undefined, this),
57519
57917
  /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
57520
57918
  marginTop: 1,
57521
- children: /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
57522
- dimColor: true,
57523
- children: "ESC to go back"
57524
- }, undefined, false, undefined, this)
57525
- }, undefined, false, undefined, this)
57919
+ children: [
57920
+ step === "info" && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
57921
+ gap: 2,
57922
+ children: [
57923
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
57924
+ dimColor: true,
57925
+ children: "Enter for actions"
57926
+ }, undefined, false, undefined, this),
57927
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
57928
+ dimColor: true,
57929
+ children: "ESC to go back"
57930
+ }, undefined, false, undefined, this),
57931
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
57932
+ dimColor: true,
57933
+ children: "q quit"
57934
+ }, undefined, false, undefined, this)
57935
+ ]
57936
+ }, undefined, true, undefined, this),
57937
+ step === "actions" && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
57938
+ dimColor: true,
57939
+ children: "↑↓ navigate │ Enter select │ ESC back │ q quit"
57940
+ }, undefined, false, undefined, this),
57941
+ step === "result" && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
57942
+ gap: 2,
57943
+ children: [
57944
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
57945
+ dimColor: true,
57946
+ children: "Enter/ESC to return"
57947
+ }, undefined, false, undefined, this),
57948
+ /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
57949
+ dimColor: true,
57950
+ children: "q quit"
57951
+ }, undefined, false, undefined, this)
57952
+ ]
57953
+ }, undefined, true, undefined, this),
57954
+ step === "select" && /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Text, {
57955
+ dimColor: true,
57956
+ children: "ESC to go back │ q quit"
57957
+ }, undefined, false, undefined, this)
57958
+ ]
57959
+ }, undefined, true, undefined, this)
57526
57960
  ]
57527
57961
  }, undefined, true, undefined, this);
57528
57962
  };
@@ -57530,10 +57964,12 @@ var init_ShowInstanceInfo = __esm(async () => {
57530
57964
  init_useConfig();
57531
57965
  init_useAnimations();
57532
57966
  init_migration();
57967
+ init_instance_diagnostics();
57533
57968
  await __promiseAll([
57534
57969
  init_build2(),
57970
+ init_build3(),
57535
57971
  init_Header(),
57536
- init_useNavigation(),
57972
+ init_StatusBar(),
57537
57973
  init_InstanceSelectMenu()
57538
57974
  ]);
57539
57975
  import_react69 = __toESM(require_react(), 1);
@@ -57545,6 +57981,12 @@ var init_ShowInstanceInfo = __esm(async () => {
57545
57981
  mcpPluginCount: null,
57546
57982
  mcpCustomCount: null
57547
57983
  };
57984
+ ACTION_VALUES = {
57985
+ SyncTemplate: "sync-template",
57986
+ UpdateWrapper: "update-wrapper",
57987
+ OverrideWrapper: "override-wrapper",
57988
+ Back: "back"
57989
+ };
57548
57990
  });
57549
57991
 
57550
57992
  // src/ink/screens/RemoveInstance.tsx
@@ -58965,61 +59407,8 @@ var init_ManageMcp = __esm(async () => {
58965
59407
  };
58966
59408
  });
58967
59409
 
58968
- // src/ink/components/IssueCard.tsx
58969
- var jsx_dev_runtime16, SEVERITY_ICONS, SEVERITY_COLORS, IssueCard = ({
58970
- issue,
58971
- index
58972
- }) => {
58973
- const visible = useFadeIn(index * 60 + 50);
58974
- if (!visible)
58975
- return null;
58976
- const icon = SEVERITY_ICONS[issue.severity] ?? "•";
58977
- const color = SEVERITY_COLORS[issue.severity] ?? "white";
58978
- return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
58979
- flexDirection: "column",
58980
- marginLeft: 2,
58981
- children: [
58982
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
58983
- gap: 1,
58984
- children: [
58985
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
58986
- children: icon
58987
- }, undefined, false, undefined, this),
58988
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
58989
- bold: true,
58990
- color,
58991
- children: issue.title
58992
- }, undefined, false, undefined, this)
58993
- ]
58994
- }, undefined, true, undefined, this),
58995
- /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
58996
- marginLeft: 2,
58997
- children: /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
58998
- dimColor: true,
58999
- children: issue.message
59000
- }, undefined, false, undefined, this)
59001
- }, undefined, false, undefined, this)
59002
- ]
59003
- }, undefined, true, undefined, this);
59004
- };
59005
- var init_IssueCard = __esm(async () => {
59006
- init_useAnimations();
59007
- await init_build2();
59008
- jsx_dev_runtime16 = __toESM(require_jsx_dev_runtime(), 1);
59009
- SEVERITY_ICONS = {
59010
- error: "❌",
59011
- warning: "⚠",
59012
- info: "ℹ️"
59013
- };
59014
- SEVERITY_COLORS = {
59015
- error: "red",
59016
- warning: "yellow",
59017
- info: "gray"
59018
- };
59019
- });
59020
-
59021
59410
  // src/ink/screens/HealthScreen.tsx
59022
- var import_react76, jsx_dev_runtime17, HealthScreen = ({
59411
+ var import_react76, jsx_dev_runtime16, SEVERITY_ICONS, HealthScreen = ({
59023
59412
  issues,
59024
59413
  onDismiss,
59025
59414
  onDismissAll,
@@ -59029,7 +59418,6 @@ var import_react76, jsx_dev_runtime17, HealthScreen = ({
59029
59418
  }) => {
59030
59419
  const [step, setStep] = import_react76.useState("list");
59031
59420
  const [selectedIssue, setSelectedIssue] = import_react76.useState(null);
59032
- const showActions = useFadeIn(100);
59033
59421
  useNavigation(() => {
59034
59422
  if (step === "detail") {
59035
59423
  setStep("list");
@@ -59039,38 +59427,39 @@ var import_react76, jsx_dev_runtime17, HealthScreen = ({
59039
59427
  }
59040
59428
  });
59041
59429
  use_input_default((input) => {
59042
- if (step !== "list")
59043
- return;
59044
- if (input === "d" && selectedIssue) {
59045
- onDismiss(selectedIssue.id);
59046
- setSelectedIssue(null);
59047
- } else if (input === "D") {
59048
- onDismissAll();
59049
- } else if (input === "r") {
59050
- onRetry();
59051
- } else if (input === "f") {
59052
- onFix();
59053
- } else if (input === " " && selectedIssue) {
59054
- setStep("detail");
59430
+ if (step === "list") {
59431
+ if (input === "D") {
59432
+ onDismissAll();
59433
+ } else if (input === "r") {
59434
+ onRetry();
59435
+ } else if (input === "f") {
59436
+ onFix();
59437
+ }
59438
+ } else if (step === "detail" && selectedIssue) {
59439
+ if (input === "d") {
59440
+ onDismiss(selectedIssue.id);
59441
+ setSelectedIssue(null);
59442
+ setStep("list");
59443
+ }
59055
59444
  }
59056
59445
  });
59057
59446
  if (issues.length === 0) {
59058
- return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59447
+ return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
59059
59448
  flexDirection: "column",
59060
59449
  width: "100",
59061
59450
  paddingX: 2,
59062
59451
  paddingY: 1,
59063
59452
  children: [
59064
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Header, {
59453
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Header, {
59065
59454
  title: "\uD83D\uDC9A System Health"
59066
59455
  }, undefined, false, undefined, this),
59067
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(StatusBar, {
59456
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(StatusBar, {
59068
59457
  message: "All systems healthy!",
59069
59458
  type: "success"
59070
59459
  }, undefined, false, undefined, this),
59071
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59460
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
59072
59461
  marginTop: 1,
59073
- children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59462
+ children: /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59074
59463
  dimColor: true,
59075
59464
  children: "ESC to go back"
59076
59465
  }, undefined, false, undefined, this)
@@ -59079,137 +59468,167 @@ var import_react76, jsx_dev_runtime17, HealthScreen = ({
59079
59468
  }, undefined, true, undefined, this);
59080
59469
  }
59081
59470
  const hasVersionIssues = issues.some((i) => i.category === "version");
59082
- return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59471
+ const handleIssueSelect = (value) => {
59472
+ const issue = issues.find((i) => i.id === value);
59473
+ if (issue) {
59474
+ setSelectedIssue(issue);
59475
+ setStep("detail");
59476
+ }
59477
+ };
59478
+ const issueOptions = issues.map((issue) => ({
59479
+ label: `${SEVERITY_ICONS[issue.severity] ?? "•"} ${issue.title}`,
59480
+ value: issue.id
59481
+ }));
59482
+ return /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
59083
59483
  flexDirection: "column",
59084
59484
  width: "100",
59085
59485
  paddingX: 2,
59086
59486
  paddingY: 1,
59087
59487
  children: [
59088
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Header, {
59488
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Header, {
59089
59489
  title: "⚠ System Health"
59090
59490
  }, undefined, false, undefined, this),
59091
- step === "list" && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59491
+ step === "list" && /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
59092
59492
  flexDirection: "column",
59093
59493
  gap: 1,
59094
59494
  children: [
59095
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59495
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59096
59496
  bold: true,
59097
59497
  children: [
59098
59498
  issues.length,
59099
- " issue(s) found:"
59499
+ " issue(s) found — select one to view:"
59100
59500
  ]
59101
59501
  }, undefined, true, undefined, this),
59102
- issues.map((issue, i) => /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(IssueCard, {
59103
- issue,
59104
- index: i
59105
- }, issue.id, false, undefined, this)),
59106
- showActions && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59502
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Select, {
59503
+ options: issueOptions,
59504
+ visibleOptionCount: issueOptions.length,
59505
+ onChange: handleIssueSelect
59506
+ }, undefined, false, undefined, this),
59507
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
59107
59508
  marginTop: 1,
59108
59509
  flexDirection: "column",
59109
59510
  children: [
59110
- hasVersionIssues && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59511
+ hasVersionIssues && /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
59111
59512
  marginBottom: 1,
59112
59513
  children: [
59113
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59514
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59114
59515
  color: "cyan",
59115
59516
  bold: true,
59116
59517
  children: "f"
59117
59518
  }, undefined, false, undefined, this),
59118
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59519
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59119
59520
  color: "cyan",
59120
59521
  children: " fix wrappers "
59121
59522
  }, undefined, false, undefined, this),
59122
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59523
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59123
59524
  dimColor: true,
59124
59525
  children: "│"
59125
59526
  }, undefined, false, undefined, this)
59126
59527
  ]
59127
59528
  }, undefined, true, undefined, this),
59128
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59529
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59129
59530
  dimColor: true,
59130
- children: "Space view detail │ d dismiss │ D dismiss all │ r retry │ ESC back"
59531
+ children: "D dismiss all │ r retry │ ESC back"
59131
59532
  }, undefined, false, undefined, this)
59132
59533
  ]
59133
59534
  }, undefined, true, undefined, this)
59134
59535
  ]
59135
59536
  }, undefined, true, undefined, this),
59136
- step === "detail" && selectedIssue && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59537
+ step === "detail" && selectedIssue && /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
59137
59538
  flexDirection: "column",
59138
59539
  gap: 1,
59139
59540
  children: [
59140
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59541
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59141
59542
  bold: true,
59142
59543
  children: selectedIssue.title
59143
59544
  }, undefined, false, undefined, this),
59144
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59545
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
59145
59546
  marginLeft: 2,
59146
59547
  flexDirection: "column",
59147
59548
  children: [
59148
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59549
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
59149
59550
  gap: 1,
59150
59551
  children: [
59151
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59552
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59152
59553
  dimColor: true,
59153
59554
  children: "├─"
59154
59555
  }, undefined, false, undefined, this),
59155
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59556
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59156
59557
  dimColor: true,
59157
59558
  bold: true,
59158
59559
  children: "Severity:"
59159
59560
  }, undefined, false, undefined, this),
59160
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59561
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59161
59562
  color: selectedIssue.severity === "error" ? "red" : "yellow",
59162
59563
  children: selectedIssue.severity
59163
59564
  }, undefined, false, undefined, this)
59164
59565
  ]
59165
59566
  }, undefined, true, undefined, this),
59166
- selectedIssue.instanceName && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59567
+ selectedIssue.instanceName && /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
59167
59568
  gap: 1,
59168
59569
  children: [
59169
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59570
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59170
59571
  dimColor: true,
59171
59572
  children: "├─"
59172
59573
  }, undefined, false, undefined, this),
59173
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59574
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59174
59575
  dimColor: true,
59175
59576
  bold: true,
59176
59577
  children: "Instance:"
59177
59578
  }, undefined, false, undefined, this),
59178
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59579
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59179
59580
  children: selectedIssue.instanceName
59180
59581
  }, undefined, false, undefined, this)
59181
59582
  ]
59182
59583
  }, undefined, true, undefined, this),
59183
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59584
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
59184
59585
  gap: 1,
59185
59586
  children: [
59186
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59587
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59187
59588
  dimColor: true,
59188
59589
  children: "├─"
59189
59590
  }, undefined, false, undefined, this),
59190
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59591
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59191
59592
  dimColor: true,
59192
59593
  bold: true,
59193
59594
  children: "Detail:"
59194
59595
  }, undefined, false, undefined, this),
59195
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59596
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59196
59597
  children: selectedIssue.message
59197
59598
  }, undefined, false, undefined, this)
59198
59599
  ]
59199
59600
  }, undefined, true, undefined, this),
59200
- selectedIssue.resolutionHint && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59601
+ selectedIssue.detail && /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
59201
59602
  gap: 1,
59202
59603
  children: [
59203
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59604
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59605
+ dimColor: true,
59606
+ children: "├─"
59607
+ }, undefined, false, undefined, this),
59608
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59609
+ dimColor: true,
59610
+ bold: true,
59611
+ children: "Info:"
59612
+ }, undefined, false, undefined, this),
59613
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59614
+ dimColor: true,
59615
+ children: selectedIssue.detail
59616
+ }, undefined, false, undefined, this)
59617
+ ]
59618
+ }, undefined, true, undefined, this),
59619
+ selectedIssue.resolutionHint && /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
59620
+ gap: 1,
59621
+ children: [
59622
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59204
59623
  dimColor: true,
59205
59624
  children: "└─"
59206
59625
  }, undefined, false, undefined, this),
59207
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59626
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59208
59627
  dimColor: true,
59209
59628
  bold: true,
59210
59629
  children: "Fix:"
59211
59630
  }, undefined, false, undefined, this),
59212
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59631
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59213
59632
  dimColor: true,
59214
59633
  children: selectedIssue.resolutionHint
59215
59634
  }, undefined, false, undefined, this)
@@ -59217,18 +59636,18 @@ var import_react76, jsx_dev_runtime17, HealthScreen = ({
59217
59636
  }, undefined, true, undefined, this)
59218
59637
  ]
59219
59638
  }, undefined, true, undefined, this),
59220
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59639
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
59221
59640
  marginTop: 1,
59222
- children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59641
+ children: /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59223
59642
  dimColor: true,
59224
59643
  children: "d dismiss │ ESC back"
59225
59644
  }, undefined, false, undefined, this)
59226
59645
  }, undefined, false, undefined, this)
59227
59646
  ]
59228
59647
  }, undefined, true, undefined, this),
59229
- /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59648
+ /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Box_default, {
59230
59649
  marginTop: 1,
59231
- children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59650
+ children: /* @__PURE__ */ jsx_dev_runtime16.jsxDEV(Text, {
59232
59651
  dimColor: true,
59233
59652
  children: "ESC to go back"
59234
59653
  }, undefined, false, undefined, this)
@@ -59237,16 +59656,20 @@ var import_react76, jsx_dev_runtime17, HealthScreen = ({
59237
59656
  }, undefined, true, undefined, this);
59238
59657
  };
59239
59658
  var init_HealthScreen = __esm(async () => {
59240
- init_useAnimations();
59241
59659
  await __promiseAll([
59242
59660
  init_build2(),
59661
+ init_build3(),
59243
59662
  init_Header(),
59244
59663
  init_StatusBar(),
59245
- init_IssueCard(),
59246
59664
  init_useNavigation()
59247
59665
  ]);
59248
59666
  import_react76 = __toESM(require_react(), 1);
59249
- jsx_dev_runtime17 = __toESM(require_jsx_dev_runtime(), 1);
59667
+ jsx_dev_runtime16 = __toESM(require_jsx_dev_runtime(), 1);
59668
+ SEVERITY_ICONS = {
59669
+ error: "❌",
59670
+ warning: "⚠",
59671
+ info: "ℹ️"
59672
+ };
59250
59673
  });
59251
59674
 
59252
59675
  // src/ink/screens/UpdateScreen.tsx
@@ -59257,59 +59680,59 @@ function VersionCard({
59257
59680
  hasUpdate,
59258
59681
  failed
59259
59682
  }) {
59260
- return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59683
+ return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59261
59684
  flexDirection: "column",
59262
59685
  marginTop: 1,
59263
59686
  children: [
59264
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59265
- children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
59687
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59688
+ children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59266
59689
  bold: true,
59267
59690
  children: label
59268
59691
  }, undefined, false, undefined, this)
59269
59692
  }, undefined, false, undefined, this),
59270
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59693
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59271
59694
  marginLeft: 2,
59272
59695
  children: [
59273
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
59696
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59274
59697
  dimColor: true,
59275
59698
  children: "Current: "
59276
59699
  }, undefined, false, undefined, this),
59277
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
59700
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59278
59701
  color: failed ? "red" : hasUpdate ? "yellow" : "green",
59279
59702
  children: current || (failed ? "check failed" : "not installed")
59280
59703
  }, undefined, false, undefined, this)
59281
59704
  ]
59282
59705
  }, undefined, true, undefined, this),
59283
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59706
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59284
59707
  marginLeft: 2,
59285
59708
  children: [
59286
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
59709
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59287
59710
  dimColor: true,
59288
59711
  children: "Latest: "
59289
59712
  }, undefined, false, undefined, this),
59290
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
59713
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59291
59714
  bold: true,
59292
59715
  children: latest || (failed ? "unreachable" : "unknown")
59293
59716
  }, undefined, false, undefined, this)
59294
59717
  ]
59295
59718
  }, undefined, true, undefined, this),
59296
- failed && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59719
+ failed && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59297
59720
  marginLeft: 2,
59298
- children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
59721
+ children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59299
59722
  color: "red",
59300
59723
  children: "✗ Could not reach npm registry"
59301
59724
  }, undefined, false, undefined, this)
59302
59725
  }, undefined, false, undefined, this),
59303
- !failed && hasUpdate && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59726
+ !failed && hasUpdate && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59304
59727
  marginLeft: 2,
59305
- children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
59728
+ children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59306
59729
  color: "yellow",
59307
59730
  children: "▲ Update available"
59308
59731
  }, undefined, false, undefined, this)
59309
59732
  }, undefined, false, undefined, this),
59310
- !failed && !hasUpdate && current && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59733
+ !failed && !hasUpdate && current && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59311
59734
  marginLeft: 2,
59312
- children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
59735
+ children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59313
59736
  color: "green",
59314
59737
  children: "✓ Up to date"
59315
59738
  }, undefined, false, undefined, this)
@@ -59317,7 +59740,7 @@ function VersionCard({
59317
59740
  ]
59318
59741
  }, undefined, true, undefined, this);
59319
59742
  }
59320
- var import_react77, jsx_dev_runtime18, UpdateScreen = ({ onBack }) => {
59743
+ var import_react77, jsx_dev_runtime17, UpdateScreen = ({ onBack }) => {
59321
59744
  const { exit } = use_app_default();
59322
59745
  const fadeIn = useFadeIn();
59323
59746
  const { error, success, setError, setSuccess, clear } = useMessage();
@@ -59390,41 +59813,41 @@ var import_react77, jsx_dev_runtime18, UpdateScreen = ({ onBack }) => {
59390
59813
  return null;
59391
59814
  if (step === "loading" || step === "check-failed") {
59392
59815
  const isFailed = step === "check-failed";
59393
- return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59816
+ return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59394
59817
  flexDirection: "column",
59395
59818
  width: "100",
59396
59819
  paddingX: 2,
59397
59820
  paddingY: 1,
59398
59821
  children: [
59399
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Header, {
59822
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Header, {
59400
59823
  title: "\uD83D\uDCE6 Updates"
59401
59824
  }, undefined, false, undefined, this),
59402
- isFailed ? /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(jsx_dev_runtime18.Fragment, {
59825
+ isFailed ? /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(jsx_dev_runtime17.Fragment, {
59403
59826
  children: [
59404
- multiInfo && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(VersionCard, {
59827
+ multiInfo && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(VersionCard, {
59405
59828
  label: "claude-multi",
59406
59829
  current: multiInfo.current || null,
59407
59830
  latest: multiInfo.latest,
59408
59831
  hasUpdate: multiInfo.updateAvailable,
59409
59832
  failed: !multiInfo.current && !multiInfo.latest
59410
59833
  }, undefined, false, undefined, this),
59411
- claudeInfo && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(VersionCard, {
59834
+ claudeInfo && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(VersionCard, {
59412
59835
  label: "@anthropic-ai/claude-code",
59413
59836
  current: claudeInfo.current,
59414
59837
  latest: claudeInfo.latest,
59415
59838
  hasUpdate: claudeInfo.updateAvailable,
59416
59839
  failed: !claudeInfo.current && !claudeInfo.latest
59417
59840
  }, undefined, false, undefined, this),
59418
- error && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59841
+ error && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59419
59842
  marginTop: 1,
59420
- children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(StatusBar, {
59843
+ children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(StatusBar, {
59421
59844
  message: error,
59422
59845
  type: "error"
59423
59846
  }, undefined, false, undefined, this)
59424
59847
  }, undefined, false, undefined, this),
59425
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59848
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59426
59849
  marginTop: 1,
59427
- children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Select, {
59850
+ children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Select, {
59428
59851
  options: [
59429
59852
  { label: "\uD83D\uDD04 Retry", value: "recheck" },
59430
59853
  { label: "↩️ Back to menu", value: "back" }
@@ -59442,9 +59865,9 @@ var import_react77, jsx_dev_runtime18, UpdateScreen = ({ onBack }) => {
59442
59865
  }, undefined, false, undefined, this)
59443
59866
  }, undefined, false, undefined, this)
59444
59867
  ]
59445
- }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59868
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59446
59869
  marginTop: 1,
59447
- children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Spinner, {
59870
+ children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Spinner, {
59448
59871
  label: "Checking for updates..."
59449
59872
  }, undefined, false, undefined, this)
59450
59873
  }, undefined, false, undefined, this)
@@ -59452,24 +59875,24 @@ var import_react77, jsx_dev_runtime18, UpdateScreen = ({ onBack }) => {
59452
59875
  }, undefined, true, undefined, this);
59453
59876
  }
59454
59877
  if (step === "updating") {
59455
- return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59878
+ return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59456
59879
  flexDirection: "column",
59457
59880
  width: "100",
59458
59881
  paddingX: 2,
59459
59882
  paddingY: 1,
59460
59883
  children: [
59461
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Header, {
59884
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Header, {
59462
59885
  title: "\uD83D\uDCE6 Updates"
59463
59886
  }, undefined, false, undefined, this),
59464
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59887
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59465
59888
  marginTop: 1,
59466
- children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Spinner, {
59889
+ children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Spinner, {
59467
59890
  label: `Updating ${updatingTarget === "multi" ? "claude-multi" : "@anthropic-ai/claude-code"}...`
59468
59891
  }, undefined, false, undefined, this)
59469
59892
  }, undefined, false, undefined, this),
59470
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59893
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59471
59894
  marginTop: 1,
59472
- children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
59895
+ children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text, {
59473
59896
  dimColor: true,
59474
59897
  children: "Do not press ESC: update in progress"
59475
59898
  }, undefined, false, undefined, this)
@@ -59488,44 +59911,44 @@ var import_react77, jsx_dev_runtime18, UpdateScreen = ({ onBack }) => {
59488
59911
  }
59489
59912
  actionOptions.push({ label: "\uD83D\uDD04 Re-check versions", value: "recheck" });
59490
59913
  actionOptions.push({ label: "↩️ Back to menu", value: "back" });
59491
- return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59914
+ return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59492
59915
  flexDirection: "column",
59493
59916
  width: "100",
59494
59917
  paddingX: 2,
59495
59918
  paddingY: 1,
59496
59919
  children: [
59497
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Header, {
59920
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Header, {
59498
59921
  title: "\uD83D\uDCE6 Updates"
59499
59922
  }, undefined, false, undefined, this),
59500
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(VersionCard, {
59923
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(VersionCard, {
59501
59924
  label: "claude-multi",
59502
59925
  current: multiInfo?.current ?? null,
59503
59926
  latest: multiInfo?.latest ?? "",
59504
59927
  hasUpdate: multiUpdate
59505
59928
  }, undefined, false, undefined, this),
59506
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(VersionCard, {
59929
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(VersionCard, {
59507
59930
  label: "@anthropic-ai/claude-code",
59508
59931
  current: claudeInfo?.current ?? null,
59509
59932
  latest: claudeInfo?.latest ?? "",
59510
59933
  hasUpdate: claudeUpdate
59511
59934
  }, undefined, false, undefined, this),
59512
- error && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59935
+ error && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59513
59936
  marginTop: 1,
59514
- children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(StatusBar, {
59937
+ children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(StatusBar, {
59515
59938
  message: error,
59516
59939
  type: "error"
59517
59940
  }, undefined, false, undefined, this)
59518
59941
  }, undefined, false, undefined, this),
59519
- success && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59942
+ success && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59520
59943
  marginTop: 1,
59521
- children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(StatusBar, {
59944
+ children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(StatusBar, {
59522
59945
  message: success,
59523
59946
  type: "success"
59524
59947
  }, undefined, false, undefined, this)
59525
59948
  }, undefined, false, undefined, this),
59526
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59949
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
59527
59950
  marginTop: 1,
59528
- children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Select, {
59951
+ children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Select, {
59529
59952
  options: actionOptions,
59530
59953
  onChange: (value) => {
59531
59954
  if (value === "back") {
@@ -59543,7 +59966,7 @@ var import_react77, jsx_dev_runtime18, UpdateScreen = ({ onBack }) => {
59543
59966
  }
59544
59967
  }, undefined, false, undefined, this)
59545
59968
  }, undefined, false, undefined, this),
59546
- /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Footer, {}, undefined, false, undefined, this)
59969
+ /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Footer, {}, undefined, false, undefined, this)
59547
59970
  ]
59548
59971
  }, undefined, true, undefined, this);
59549
59972
  };
@@ -59559,7 +59982,7 @@ var init_UpdateScreen = __esm(async () => {
59559
59982
  init_Footer()
59560
59983
  ]);
59561
59984
  import_react77 = __toESM(require_react(), 1);
59562
- jsx_dev_runtime18 = __toESM(require_jsx_dev_runtime(), 1);
59985
+ jsx_dev_runtime17 = __toESM(require_jsx_dev_runtime(), 1);
59563
59986
  });
59564
59987
 
59565
59988
  // src/ink/App.tsx
@@ -59567,75 +59990,59 @@ var exports_App = {};
59567
59990
  __export(exports_App, {
59568
59991
  App: () => App2
59569
59992
  });
59570
- import { execSync as execSync3 } from "node:child_process";
59571
- import { existsSync as existsSync8 } from "node:fs";
59572
- var import_react78, jsx_dev_runtime19, GoodbyeScreen = () => {
59993
+ var import_react78, jsx_dev_runtime18, GoodbyeScreen = () => {
59573
59994
  const msg = useTypewriter("\uD83D\uDC4B Goodbye!", 40);
59574
- return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
59995
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59575
59996
  paddingX: 2,
59576
59997
  paddingY: 1,
59577
- children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
59998
+ children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
59578
59999
  dimColor: true,
59579
60000
  children: msg
59580
60001
  }, undefined, false, undefined, this)
59581
60002
  }, undefined, false, undefined, this);
59582
- }, DoctorResultScreen = ({ fixedCount, migratedCount, installFailed, onBack }) => {
60003
+ }, DoctorResultScreen = ({ fixedCount, migratedCount, onBack }) => {
59583
60004
  useNavigation(onBack);
59584
- return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
60005
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59585
60006
  flexDirection: "column",
59586
60007
  width: "100",
59587
60008
  paddingX: 2,
59588
60009
  paddingY: 1,
59589
60010
  children: [
59590
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Header, {
59591
- title: "\uD83D\uDD27 Doctor Fix"
60011
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Header, {
60012
+ title: "Doctor Fix"
59592
60013
  }, undefined, false, undefined, this),
59593
- installFailed ? /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(jsx_dev_runtime19.Fragment, {
59594
- children: [
59595
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(StatusBar, {
59596
- message: "Failed to install pinned Claude binary",
59597
- type: "error"
59598
- }, undefined, false, undefined, this),
59599
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
59600
- marginTop: 1,
59601
- children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
59602
- dimColor: true,
59603
- children: "Check your network connection and try again."
59604
- }, undefined, false, undefined, this)
59605
- }, undefined, false, undefined, this)
59606
- ]
59607
- }, undefined, true, undefined, this) : fixedCount > 0 || migratedCount > 0 ? /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(jsx_dev_runtime19.Fragment, {
60014
+ fixedCount > 0 || migratedCount > 0 ? /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(jsx_dev_runtime18.Fragment, {
59608
60015
  children: [
59609
- fixedCount > 0 && /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(jsx_dev_runtime19.Fragment, {
60016
+ fixedCount > 0 && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(jsx_dev_runtime18.Fragment, {
59610
60017
  children: [
59611
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(StatusBar, {
59612
- message: `Fixed ${fixedCount} wrapper(s) to use pinned Claude v${COMPATIBLE_CLAUDE_VERSION}!`,
60018
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(StatusBar, {
60019
+ message: `Fixed ${fixedCount} wrapper(s) to use global Claude binary`,
59613
60020
  type: "success"
59614
60021
  }, undefined, false, undefined, this),
59615
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
60022
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59616
60023
  marginTop: 1,
59617
- children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
60024
+ children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
59618
60025
  dimColor: true,
59619
- children: "All 3rd-party API instances now use the correct Claude binary."
60026
+ children: "All instances now use the globally installed Claude binary."
59620
60027
  }, undefined, false, undefined, this)
59621
60028
  }, undefined, false, undefined, this)
59622
60029
  ]
59623
60030
  }, undefined, true, undefined, this),
59624
- migratedCount > 0 && /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
60031
+ migratedCount > 0 && /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59625
60032
  marginTop: fixedCount > 0 ? 1 : 0,
59626
- children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(StatusBar, {
60033
+ children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(StatusBar, {
59627
60034
  message: `Migrated ${migratedCount} instance(s) to v${getClaudeMultiVersion()}`,
59628
60035
  type: "success"
59629
60036
  }, undefined, false, undefined, this)
59630
60037
  }, undefined, false, undefined, this)
59631
60038
  ]
59632
- }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(StatusBar, {
60039
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(StatusBar, {
59633
60040
  message: "All wrappers already use the correct Claude version",
59634
60041
  type: "info"
59635
60042
  }, undefined, false, undefined, this),
59636
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
60043
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59637
60044
  marginTop: 1,
59638
- children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
60045
+ children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
59639
60046
  dimColor: true,
59640
60047
  children: "ESC to go back"
59641
60048
  }, undefined, false, undefined, this)
@@ -59646,9 +60053,9 @@ var import_react78, jsx_dev_runtime19, GoodbyeScreen = () => {
59646
60053
  const visible = useFadeIn(100);
59647
60054
  if (!visible || instances2.length === 0)
59648
60055
  return null;
59649
- return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
60056
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59650
60057
  marginBottom: 1,
59651
- children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
60058
+ children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Text, {
59652
60059
  dimColor: true,
59653
60060
  children: [
59654
60061
  instances2.length,
@@ -59660,23 +60067,15 @@ var import_react78, jsx_dev_runtime19, GoodbyeScreen = () => {
59660
60067
  }, undefined, false, undefined, this);
59661
60068
  }, App2 = () => {
59662
60069
  const { exit } = use_app_default();
59663
- const { instances: instances2, loading, migrationStatus, instanceMigrationVersion } = useConfig();
60070
+ const { instances: instances2, loading, migrationStatus, instanceMigrationVersion, reload } = useConfig();
59664
60071
  const { issues, dismiss, dismissAll, retry } = useHealthCheck(instances2, migrationStatus, instanceMigrationVersion);
59665
60072
  const [screen, setScreen] = import_react78.useState("menu");
59666
60073
  const [menuKey, setMenuKey] = import_react78.useState(0);
59667
- const [ccVersion] = import_react78.useState(() => {
59668
- try {
59669
- const output = execSync3("claude --version 2>/dev/null", { encoding: "utf-8", timeout: 5000 }).trim();
59670
- return output.split(" ")[0] || null;
59671
- } catch {
59672
- return null;
59673
- }
59674
- });
59675
60074
  const [doctorResult, setDoctorResult] = import_react78.useState({
59676
60075
  fixedCount: 0,
59677
- migratedCount: 0,
59678
- installFailed: false
60076
+ migratedCount: 0
59679
60077
  });
60078
+ const [doctorRunning, setDoctorRunning] = import_react78.useState(false);
59680
60079
  use_input_default((input, key) => {
59681
60080
  if (screen !== "menu")
59682
60081
  return;
@@ -59688,10 +60087,10 @@ var import_react78, jsx_dev_runtime19, GoodbyeScreen = () => {
59688
60087
  }
59689
60088
  });
59690
60089
  if (loading) {
59691
- return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
60090
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59692
60091
  paddingX: 2,
59693
60092
  paddingY: 1,
59694
- children: /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Spinner, {
60093
+ children: /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Spinner, {
59695
60094
  label: "Loading..."
59696
60095
  }, undefined, false, undefined, this)
59697
60096
  }, undefined, false, undefined, this);
@@ -59701,45 +60100,35 @@ var import_react78, jsx_dev_runtime19, GoodbyeScreen = () => {
59701
60100
  setMenuKey((k) => k + 1);
59702
60101
  };
59703
60102
  const handleDoctorFix = async () => {
59704
- let installFailed = false;
59705
- if (!existsSync8(PINNED_CLAUDE_BIN)) {
60103
+ if (doctorRunning)
60104
+ return;
60105
+ setDoctorRunning(true);
60106
+ try {
60107
+ const fixed = fixWrapperVersions(instances2);
60108
+ let migrated = 0;
59706
60109
  try {
59707
- installPinnedClaude();
59708
- } catch {
59709
- installFailed = true;
59710
- }
59711
- } else {
59712
- const pinnedVer = getPinnedBinaryVersion();
59713
- if (pinnedVer && isThirdPartyApiBroken(pinnedVer)) {
59714
- try {
59715
- installPinnedClaude();
59716
- } catch {
59717
- installFailed = true;
60110
+ const fullConfig = await loadConfig();
60111
+ if (needsInstanceMigration(fullConfig)) {
60112
+ const before2 = fullConfig.instanceMigrationVersion;
60113
+ const migratedConfig = await runInstanceMigrations(fullConfig);
60114
+ if (migratedConfig.instanceMigrationVersion !== before2) {
60115
+ await saveConfigAtomic(migratedConfig);
60116
+ migrated = fullConfig.instances.length;
60117
+ }
59718
60118
  }
59719
- }
60119
+ } catch {}
60120
+ setDoctorResult({ fixedCount: fixed.length, migratedCount: migrated });
60121
+ await reload();
60122
+ setScreen("doctor-result");
60123
+ } finally {
60124
+ setDoctorRunning(false);
59720
60125
  }
59721
- const fixed = installFailed ? [] : fixWrapperVersions(instances2);
59722
- let migrated = 0;
59723
- try {
59724
- const fullConfig = await loadConfig();
59725
- if (needsInstanceMigration(fullConfig)) {
59726
- const before2 = fullConfig.instanceMigrationVersion;
59727
- const migratedConfig = await runInstanceMigrations(fullConfig);
59728
- if (migratedConfig.instanceMigrationVersion !== before2) {
59729
- await saveConfigAtomic(migratedConfig);
59730
- migrated = fullConfig.instances.length;
59731
- }
59732
- }
59733
- } catch {}
59734
- setDoctorResult({ fixedCount: fixed.length, migratedCount: migrated, installFailed });
59735
- retry();
59736
- setScreen("doctor-result");
59737
60126
  };
59738
60127
  if (screen === "goodbye") {
59739
- return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(GoodbyeScreen, {}, undefined, false, undefined, this);
60128
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(GoodbyeScreen, {}, undefined, false, undefined, this);
59740
60129
  }
59741
60130
  if (screen === "health") {
59742
- return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(HealthScreen, {
60131
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(HealthScreen, {
59743
60132
  issues,
59744
60133
  onDismiss: dismiss,
59745
60134
  onDismissAll: dismissAll,
@@ -59749,17 +60138,16 @@ var import_react78, jsx_dev_runtime19, GoodbyeScreen = () => {
59749
60138
  }, undefined, false, undefined, this);
59750
60139
  }
59751
60140
  if (screen === "doctor-result") {
59752
- return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(DoctorResultScreen, {
60141
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(DoctorResultScreen, {
59753
60142
  fixedCount: doctorResult.fixedCount,
59754
60143
  migratedCount: doctorResult.migratedCount,
59755
- installFailed: doctorResult.installFailed,
59756
60144
  onBack: goToMenu
59757
60145
  }, undefined, false, undefined, this);
59758
60146
  }
59759
60147
  if (screen !== "menu") {
59760
60148
  const ScreenComponent = SCREEN_MAP[screen];
59761
60149
  if (ScreenComponent) {
59762
- return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(ScreenComponent, {
60150
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(ScreenComponent, {
59763
60151
  onBack: goToMenu
59764
60152
  }, undefined, false, undefined, this);
59765
60153
  }
@@ -59790,44 +60178,26 @@ var import_react78, jsx_dev_runtime19, GoodbyeScreen = () => {
59790
60178
  { label: "\uD83D\uDCE6 Check for updates", value: "update" },
59791
60179
  { label: "\uD83D\uDEAA Exit", value: "exit" }
59792
60180
  ];
59793
- return /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
60181
+ return /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Box_default, {
59794
60182
  flexDirection: "column",
59795
60183
  width: "100",
59796
60184
  paddingX: 2,
59797
60185
  paddingY: 1,
59798
60186
  children: [
59799
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Header, {
60187
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Header, {
59800
60188
  title: "\uD83E\uDD16 Claude Multi",
59801
60189
  subtitle: "Interactive Mode"
59802
60190
  }, undefined, false, undefined, this),
59803
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(WarningBanner, {
60191
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(WarningBanner, {
59804
60192
  issueCount: issues.length,
59805
60193
  errorCount,
59806
60194
  warningCount,
59807
60195
  hasVersionIssues
59808
60196
  }, undefined, false, undefined, this),
59809
- ccVersion && isThirdPartyApiBroken(ccVersion) && /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Box_default, {
59810
- marginBottom: 1,
59811
- children: [
59812
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
59813
- color: "red",
59814
- bold: true,
59815
- children: [
59816
- "⚠ Claude Code v",
59817
- ccVersion,
59818
- " does not work with 3rd-party APIs. "
59819
- ]
59820
- }, undefined, true, undefined, this),
59821
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Text, {
59822
- color: "red",
59823
- children: "Run 'claude-multi doctor fix' to install a compatible version."
59824
- }, undefined, false, undefined, this)
59825
- ]
59826
- }, undefined, true, undefined, this),
59827
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(InstanceLine, {
60197
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(InstanceLine, {
59828
60198
  instances: instances2
59829
60199
  }, undefined, false, undefined, this),
59830
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Select, {
60200
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Select, {
59831
60201
  options: menuOptions,
59832
60202
  visibleOptionCount: menuOptions.length,
59833
60203
  onChange: async (value) => {
@@ -59843,7 +60213,7 @@ var import_react78, jsx_dev_runtime19, GoodbyeScreen = () => {
59843
60213
  }
59844
60214
  }
59845
60215
  }, menuKey, false, undefined, this),
59846
- /* @__PURE__ */ jsx_dev_runtime19.jsxDEV(Footer, {
60216
+ /* @__PURE__ */ jsx_dev_runtime18.jsxDEV(Footer, {
59847
60217
  showHealthHint: issues.length > 0
59848
60218
  }, undefined, false, undefined, this)
59849
60219
  ]
@@ -59851,7 +60221,6 @@ var import_react78, jsx_dev_runtime19, GoodbyeScreen = () => {
59851
60221
  }, SCREEN_MAP;
59852
60222
  var init_App2 = __esm(async () => {
59853
60223
  init_version();
59854
- init_paths();
59855
60224
  init_useConfig();
59856
60225
  init_useHealthCheck();
59857
60226
  init_useAnimations();
@@ -59878,7 +60247,7 @@ var init_App2 = __esm(async () => {
59878
60247
  init_UpdateScreen()
59879
60248
  ]);
59880
60249
  import_react78 = __toESM(require_react(), 1);
59881
- jsx_dev_runtime19 = __toESM(require_jsx_dev_runtime(), 1);
60250
+ jsx_dev_runtime18 = __toESM(require_jsx_dev_runtime(), 1);
59882
60251
  SCREEN_MAP = {
59883
60252
  add: AddInstance,
59884
60253
  list: ListInstances,
@@ -59919,7 +60288,7 @@ init_errors();
59919
60288
  init_constants();
59920
60289
  var import_prompts = __toESM(require_prompts3(), 1);
59921
60290
  import { homedir as homedir4 } from "node:os";
59922
- import { join as join9 } from "node:path";
60291
+ import { join as join9, dirname as dirname5, delimiter } from "node:path";
59923
60292
  function exitWithCode(code) {
59924
60293
  process.exit(code);
59925
60294
  }
@@ -59956,6 +60325,7 @@ program2.command("add <name>").description("Add a new Claude Code instance").opt
59956
60325
  let providerTemplate = null;
59957
60326
  let apiKey = "";
59958
60327
  let autoSync = !options.manual;
60328
+ let providerRegion;
59959
60329
  if (options.provider) {
59960
60330
  providerTemplate = getProviderTemplate(options.provider);
59961
60331
  if (!providerTemplate) {
@@ -59970,12 +60340,19 @@ program2.command("add <name>").description("Add a new Claude Code instance").opt
59970
60340
  useProviderTemplate = true;
59971
60341
  if (providerHasRegions(providerTemplate.name)) {
59972
60342
  const region = options.region || "cn";
60343
+ if (!options.region) {
60344
+ const regions = getProviderRegions(providerTemplate.name);
60345
+ console.log(source_default.yellow(`⚠ No --region specified, defaulting to cn. Available: ${regions ? Object.keys(regions).join(", ") : "cn"}`));
60346
+ }
60347
+ providerRegion = region;
59973
60348
  try {
59974
60349
  providerTemplate = resolveRegionTemplate(providerTemplate, region);
59975
60350
  } catch (err) {
59976
60351
  console.error(source_default.red(`✗ ${toMessage(err)}`));
59977
60352
  exitWithCode(1);
59978
60353
  }
60354
+ } else if (options.region) {
60355
+ console.log(source_default.yellow(`⚠ --region is ignored for non-regional provider '${providerTemplate.name}'`));
59979
60356
  }
59980
60357
  }
59981
60358
  if (options.copySettings || options.copyAll || options.copyMcp || options.skipPrompts || options.provider) {
@@ -60040,7 +60417,9 @@ Found existing Claude Code configuration at ~/.claude`));
60040
60417
  binaryPath,
60041
60418
  createdAt: new Date().toISOString(),
60042
60419
  autoSync,
60043
- createdWithVersion: getClaudeMultiVersion()
60420
+ createdWithVersion: getClaudeMultiVersion(),
60421
+ ...useProviderTemplate && providerTemplate ? { providerTemplate: providerTemplate.name } : {},
60422
+ ...providerRegion ? { providerRegion } : {}
60044
60423
  };
60045
60424
  await addInstance(instance);
60046
60425
  try {
@@ -60080,9 +60459,9 @@ Found existing Claude Code configuration at ~/.claude`));
60080
60459
  console.log(source_default.gray(` Binary: ${binaryPath}`));
60081
60460
  console.log(source_default.gray(` Config: ${configDir}`));
60082
60461
  console.log();
60083
- const binDir = binaryPath.substring(0, binaryPath.lastIndexOf("/"));
60462
+ const binDir = dirname5(binaryPath);
60084
60463
  const pathEnv = process.env.PATH || "";
60085
- const isInPath = pathEnv.split(":").some((p) => p === binDir);
60464
+ const isInPath = pathEnv.split(delimiter).some((p) => p === binDir);
60086
60465
  if (!isInPath) {
60087
60466
  console.log(source_default.yellow(`⚠ Warning: ${binDir} is not in your PATH`));
60088
60467
  console.log(source_default.gray(`Add to PATH by running:`));
@@ -60136,6 +60515,10 @@ program2.command("list").alias("ls").description("List all Claude Code instances
60136
60515
  console.log(source_default.gray(` Binary: ${instance.binaryPath}`));
60137
60516
  console.log(source_default.gray(` Config: ${instance.configDir}`));
60138
60517
  console.log(source_default.gray(` Created: ${new Date(instance.createdAt).toLocaleString()}`));
60518
+ if (instance.providerTemplate) {
60519
+ const region = instance.providerRegion ? ` (${instance.providerRegion})` : "";
60520
+ console.log(source_default.gray(` Provider: ${instance.providerTemplate}${region}`));
60521
+ }
60139
60522
  const autoSyncStatus = instance.autoSync !== false ? source_default.green("on") : source_default.yellow("off");
60140
60523
  console.log(source_default.gray(` Auto-sync: ${autoSyncStatus}`));
60141
60524
  console.log(source_default.gray(` Version: ${formatVersionLabel(instance.createdWithVersion)}`));
@@ -60157,6 +60540,10 @@ program2.command("info <name>").description("Show details about a specific insta
60157
60540
  const autoSyncStatus = instance.autoSync !== false ? source_default.green("✓ Enabled") : source_default.yellow("✗ Disabled");
60158
60541
  console.log(`${source_default.gray("Auto-sync:")} ${autoSyncStatus}`);
60159
60542
  console.log(`${source_default.gray("Version:")} ${formatVersionLabel(instance.createdWithVersion)}`);
60543
+ if (instance.providerTemplate) {
60544
+ const region = instance.providerRegion ? ` (${instance.providerRegion})` : "";
60545
+ console.log(`${source_default.gray("Provider:")} ${instance.providerTemplate}${region}`);
60546
+ }
60160
60547
  } catch (error) {
60161
60548
  console.error(source_default.red(`✗ Error: ${toMessage(error)}`));
60162
60549
  exitWithCode(1);
@@ -60232,17 +60619,13 @@ program2.command("doctor").description("Diagnose and fix common issues").argumen
60232
60619
  const [
60233
60620
  instances2,
60234
60621
  { runHealthChecks: runHealthChecks2, fixWrapperVersions: fixWrapperVersions2 },
60235
- { existsSync: existsSync9 },
60236
- { PINNED_CLAUDE_BIN: PINNED_CLAUDE_BIN2 },
60237
- { installPinnedClaude: installPinnedClaude2, getPinnedBinaryVersion: getPinnedBinaryVersion2, isThirdPartyApiBroken: isThirdPartyApiBroken2, COMPATIBLE_CLAUDE_VERSION: COMPATIBLE_CLAUDE_VERSION2 },
60622
+ { tryGetClaudePath: tryGetClaudePath2 },
60238
60623
  { needsInstanceMigration: needsInstanceMigration2, runInstanceMigrations: runInstanceMigrations2 },
60239
60624
  { loadConfig: loadConfig2, saveConfigAtomic: saveConfigAtomic2 }
60240
60625
  ] = await Promise.all([
60241
60626
  listInstances(),
60242
60627
  Promise.resolve().then(() => (init_health(), exports_health)),
60243
- import("node:fs"),
60244
- Promise.resolve().then(() => (init_paths(), exports_paths)),
60245
- Promise.resolve().then(() => (init_version(), exports_version)),
60628
+ Promise.resolve().then(() => (init_wrapper(), exports_wrapper)),
60246
60629
  Promise.resolve().then(() => (init_migration(), exports_migration)),
60247
60630
  Promise.resolve().then(() => (init_config(), exports_config))
60248
60631
  ]);
@@ -60250,23 +60633,15 @@ program2.command("doctor").description("Diagnose and fix common issues").argumen
60250
60633
  console.log(source_default.bold(`
60251
60634
  \uD83D\uDD27 Doctor Fix
60252
60635
  `));
60253
- if (!existsSync9(PINNED_CLAUDE_BIN2)) {
60254
- console.log(source_default.cyan(`Installing compatible Claude v${COMPATIBLE_CLAUDE_VERSION2}...`));
60255
- installPinnedClaude2();
60256
- console.log(source_default.green(`✓ Installed pinned Claude v${COMPATIBLE_CLAUDE_VERSION2}`));
60257
- } else {
60258
- const pinnedVer = getPinnedBinaryVersion2();
60259
- const needsReinstall = !pinnedVer || isThirdPartyApiBroken2(pinnedVer) || pinnedVer !== COMPATIBLE_CLAUDE_VERSION2;
60260
- if (needsReinstall) {
60261
- const reason = !pinnedVer ? "version unknown" : isThirdPartyApiBroken2(pinnedVer) ? "incompatible" : "outdated";
60262
- console.log(source_default.yellow(`Pinned binary is ${pinnedVer ? `v${pinnedVer}` : reason}. Reinstalling v${COMPATIBLE_CLAUDE_VERSION2}...`));
60263
- installPinnedClaude2();
60264
- console.log(source_default.green(`✓ Reinstalled pinned Claude v${COMPATIBLE_CLAUDE_VERSION2}`));
60265
- }
60636
+ const claudePath = tryGetClaudePath2();
60637
+ if (!claudePath) {
60638
+ console.error(source_default.red("Claude Code not found in PATH. Please install it first."));
60639
+ process.exit(1);
60266
60640
  }
60641
+ console.log(source_default.gray(`Using claude at: ${claudePath}`));
60267
60642
  const fixed = fixWrapperVersions2(instances2);
60268
60643
  if (fixed.length > 0) {
60269
- console.log(source_default.green(`✓ Fixed ${fixed.length} wrapper(s) to use pinned Claude version:`));
60644
+ console.log(source_default.green(`✓ Fixed ${fixed.length} wrapper(s) to use resolved Claude version:`));
60270
60645
  for (const name of fixed) {
60271
60646
  console.log(source_default.gray(` • ${name}`));
60272
60647
  }