zcf 3.4.2 → 3.4.3

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.
@@ -11,14 +11,14 @@ import { dirname, join } from 'pathe';
11
11
  import { fileURLToPath } from 'node:url';
12
12
  import toggleModule from 'inquirer-toggle';
13
13
  import ora from 'ora';
14
+ import { exec, x } from 'tinyexec';
14
15
  import semver from 'semver';
15
16
  import { stringify, parse } from 'smol-toml';
16
- import { exec, x } from 'tinyexec';
17
17
  import { rm, mkdir, copyFile as copyFile$1 } from 'node:fs/promises';
18
18
  import i18next from 'i18next';
19
19
  import Backend from 'i18next-fs-backend';
20
20
 
21
- const version = "3.4.2";
21
+ const version = "3.4.3";
22
22
  const homepage = "https://github.com/UfoMiao/zcf";
23
23
 
24
24
  const i18n = i18next.createInstance();
@@ -1309,6 +1309,20 @@ const claudeConfig = {
1309
1309
  writeMcpConfig: writeMcpConfig
1310
1310
  };
1311
1311
 
1312
+ const MODEL_ENV_KEYS = [
1313
+ "ANTHROPIC_MODEL",
1314
+ "ANTHROPIC_DEFAULT_HAIKU_MODEL",
1315
+ "ANTHROPIC_DEFAULT_SONNET_MODEL",
1316
+ "ANTHROPIC_DEFAULT_OPUS_MODEL",
1317
+ // Deprecated but still cleaned to avoid stale values
1318
+ "ANTHROPIC_SMALL_FAST_MODEL"
1319
+ ];
1320
+ function clearModelEnv(env) {
1321
+ for (const key of MODEL_ENV_KEYS) {
1322
+ delete env[key];
1323
+ }
1324
+ }
1325
+
1312
1326
  function cleanupPermissions(templatePermissions, userPermissions) {
1313
1327
  const templateSet = new Set(templatePermissions);
1314
1328
  const cleanedPermissions = userPermissions.filter((permission) => {
@@ -1426,8 +1440,8 @@ function mergeConfigs(sourceFile, targetFile) {
1426
1440
  const merged = deepMerge(target, source);
1427
1441
  writeJsonConfig(targetFile, merged);
1428
1442
  }
1429
- function updateCustomModel(primaryModel, fastModel) {
1430
- if (!primaryModel?.trim() && !fastModel?.trim()) {
1443
+ function updateCustomModel(primaryModel, haikuModel, sonnetModel, opusModel) {
1444
+ if (!primaryModel?.trim() && !haikuModel?.trim() && !sonnetModel?.trim() && !opusModel?.trim()) {
1431
1445
  return;
1432
1446
  }
1433
1447
  let settings = getDefaultSettings();
@@ -1437,12 +1451,16 @@ function updateCustomModel(primaryModel, fastModel) {
1437
1451
  }
1438
1452
  delete settings.model;
1439
1453
  settings.env = settings.env || {};
1454
+ clearModelEnv(settings.env);
1440
1455
  if (primaryModel?.trim()) {
1441
1456
  settings.env.ANTHROPIC_MODEL = primaryModel.trim();
1442
1457
  }
1443
- if (fastModel?.trim()) {
1444
- settings.env.ANTHROPIC_SMALL_FAST_MODEL = fastModel.trim();
1445
- }
1458
+ if (haikuModel?.trim())
1459
+ settings.env.ANTHROPIC_DEFAULT_HAIKU_MODEL = haikuModel.trim();
1460
+ if (sonnetModel?.trim())
1461
+ settings.env.ANTHROPIC_DEFAULT_SONNET_MODEL = sonnetModel.trim();
1462
+ if (opusModel?.trim())
1463
+ settings.env.ANTHROPIC_DEFAULT_OPUS_MODEL = opusModel.trim();
1446
1464
  writeJsonConfig(SETTINGS_FILE, settings);
1447
1465
  }
1448
1466
  function updateDefaultModel(model) {
@@ -1454,13 +1472,10 @@ function updateDefaultModel(model) {
1454
1472
  if (!settings.env) {
1455
1473
  settings.env = {};
1456
1474
  }
1457
- if (model !== "custom" && settings.env) {
1458
- delete settings.env.ANTHROPIC_MODEL;
1459
- delete settings.env.ANTHROPIC_SMALL_FAST_MODEL;
1475
+ if (model !== "custom") {
1476
+ clearModelEnv(settings.env);
1460
1477
  }
1461
- if (model === "default") {
1462
- delete settings.model;
1463
- } else if (model === "custom") {
1478
+ if (model === "default" || model === "custom") {
1464
1479
  delete settings.model;
1465
1480
  } else {
1466
1481
  settings.model = model;
@@ -1511,13 +1526,18 @@ function getExistingModelConfig() {
1511
1526
  if (!settings) {
1512
1527
  return null;
1513
1528
  }
1514
- if (settings.env && (settings.env.ANTHROPIC_MODEL || settings.env.ANTHROPIC_SMALL_FAST_MODEL)) {
1529
+ const hasModelEnv = MODEL_ENV_KEYS.some((key) => settings.env?.[key]);
1530
+ if (hasModelEnv) {
1515
1531
  return "custom";
1516
1532
  }
1517
1533
  if (!settings.model) {
1518
1534
  return "default";
1519
1535
  }
1520
- return settings.model;
1536
+ const validModels = ["opus", "sonnet", "sonnet[1m]"];
1537
+ if (validModels.includes(settings.model)) {
1538
+ return settings.model;
1539
+ }
1540
+ return "default";
1521
1541
  }
1522
1542
  function getExistingApiConfig() {
1523
1543
  const settings = readJsonConfig(SETTINGS_FILE);
@@ -1787,7 +1807,7 @@ function getFallbackPresets() {
1787
1807
  ];
1788
1808
  }
1789
1809
 
1790
- const execAsync$4 = promisify(exec$1);
1810
+ const execAsync$3 = promisify(exec$1);
1791
1811
  const CCR_CONFIG_DIR = join(homedir(), ".claude-code-router");
1792
1812
  const CCR_CONFIG_FILE = join(CCR_CONFIG_DIR, "config.json");
1793
1813
  const CCR_BACKUP_DIR = CCR_CONFIG_DIR;
@@ -1953,10 +1973,10 @@ async function restartAndCheckCcrStatus() {
1953
1973
  ensureI18nInitialized();
1954
1974
  try {
1955
1975
  console.log(ansis.cyan(`${i18n.t("ccr:restartingCcr")}`));
1956
- await execAsync$4("ccr restart");
1976
+ await execAsync$3("ccr restart");
1957
1977
  console.log(ansis.green(`\u2714 ${i18n.t("ccr:ccrRestartSuccess")}`));
1958
1978
  console.log(ansis.cyan(`${i18n.t("ccr:checkingCcrStatus")}`));
1959
- const { stdout } = await execAsync$4("ccr status");
1979
+ const { stdout } = await execAsync$3("ccr status");
1960
1980
  console.log(ansis.gray(stdout));
1961
1981
  } catch (error) {
1962
1982
  console.error(ansis.red(`${i18n.t("ccr:ccrRestartFailed")}:`), error.message || error);
@@ -2093,16 +2113,16 @@ const config = {
2093
2113
  writeCcrConfig: writeCcrConfig
2094
2114
  };
2095
2115
 
2096
- const execAsync$3 = promisify(exec$1);
2116
+ const execAsync$2 = promisify(exec$1);
2097
2117
  async function getInstalledVersion(command, maxRetries = 3) {
2098
2118
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
2099
2119
  try {
2100
2120
  let stdout;
2101
2121
  try {
2102
- const result = await execAsync$3(`${command} -v`);
2122
+ const result = await execAsync$2(`${command} -v`);
2103
2123
  stdout = result.stdout;
2104
2124
  } catch {
2105
- const result = await execAsync$3(`${command} --version`);
2125
+ const result = await execAsync$2(`${command} --version`);
2106
2126
  stdout = result.stdout;
2107
2127
  }
2108
2128
  const versionMatch = stdout.match(/(\d+\.\d+\.\d+(?:-[\w.]+)?)/);
@@ -2119,7 +2139,7 @@ async function getInstalledVersion(command, maxRetries = 3) {
2119
2139
  async function getLatestVersion(packageName, maxRetries = 3) {
2120
2140
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
2121
2141
  try {
2122
- const { stdout } = await execAsync$3(`npm view ${packageName} version`);
2142
+ const { stdout } = await execAsync$2(`npm view ${packageName} version`);
2123
2143
  return stdout.trim();
2124
2144
  } catch {
2125
2145
  if (attempt === maxRetries) {
@@ -2148,7 +2168,7 @@ async function getClaudeCodeInstallationSource() {
2148
2168
  return { isHomebrew: true, commandPath, source: "homebrew-cask" };
2149
2169
  }
2150
2170
  try {
2151
- const { stdout: realPath } = await execAsync$3(`readlink -f "${commandPath}" 2>/dev/null || realpath "${commandPath}" 2>/dev/null || echo "${commandPath}"`);
2171
+ const { stdout: realPath } = await execAsync$2(`readlink -f "${commandPath}" 2>/dev/null || realpath "${commandPath}" 2>/dev/null || echo "${commandPath}"`);
2152
2172
  const resolvedPath = realPath.trim();
2153
2173
  if (resolvedPath.includes("/Caskroom/claude-code/")) {
2154
2174
  return { isHomebrew: true, commandPath, source: "homebrew-cask" };
@@ -2167,7 +2187,7 @@ async function detectAllClaudeCodeInstallations() {
2167
2187
  let activeResolvedPath = null;
2168
2188
  if (activeCommandPath) {
2169
2189
  try {
2170
- const { stdout } = await execAsync$3(`readlink -f "${activeCommandPath}" 2>/dev/null || realpath "${activeCommandPath}" 2>/dev/null || echo "${activeCommandPath}"`);
2190
+ const { stdout } = await execAsync$2(`readlink -f "${activeCommandPath}" 2>/dev/null || realpath "${activeCommandPath}" 2>/dev/null || echo "${activeCommandPath}"`);
2171
2191
  activeResolvedPath = stdout.trim();
2172
2192
  } catch {
2173
2193
  activeResolvedPath = activeCommandPath;
@@ -2175,7 +2195,7 @@ async function detectAllClaudeCodeInstallations() {
2175
2195
  }
2176
2196
  async function getVersionFromPath(path) {
2177
2197
  try {
2178
- const { stdout } = await execAsync$3(`"${path}" -v 2>/dev/null || "${path}" --version 2>/dev/null`);
2198
+ const { stdout } = await execAsync$2(`"${path}" -v 2>/dev/null || "${path}" --version 2>/dev/null`);
2179
2199
  const versionMatch = stdout.match(/(\d+\.\d+\.\d+(?:-[\w.]+)?)/);
2180
2200
  return versionMatch ? versionMatch[1] : null;
2181
2201
  } catch {
@@ -2190,7 +2210,7 @@ async function detectAllClaudeCodeInstallations() {
2190
2210
  async function addInstallation(path, source) {
2191
2211
  let resolvedPath = path;
2192
2212
  try {
2193
- const { stdout } = await execAsync$3(`readlink -f "${path}" 2>/dev/null || realpath "${path}" 2>/dev/null || echo "${path}"`);
2213
+ const { stdout } = await execAsync$2(`readlink -f "${path}" 2>/dev/null || realpath "${path}" 2>/dev/null || echo "${path}"`);
2194
2214
  resolvedPath = stdout.trim();
2195
2215
  } catch {
2196
2216
  }
@@ -2226,7 +2246,7 @@ async function detectAllClaudeCodeInstallations() {
2226
2246
  }
2227
2247
  }
2228
2248
  try {
2229
- await execAsync$3("brew list --cask claude-code");
2249
+ await execAsync$2("brew list --cask claude-code");
2230
2250
  const homebrewPrefixes = ["/opt/homebrew", "/usr/local"];
2231
2251
  for (const prefix of homebrewPrefixes) {
2232
2252
  const caskroomPath = `${prefix}/Caskroom/claude-code`;
@@ -2251,7 +2271,7 @@ async function detectAllClaudeCodeInstallations() {
2251
2271
  if (nodeFs.existsSync(path)) {
2252
2272
  let resolvedPath = path;
2253
2273
  try {
2254
- const { stdout } = await execAsync$3(`readlink -f "${path}" 2>/dev/null || realpath "${path}" 2>/dev/null || echo "${path}"`);
2274
+ const { stdout } = await execAsync$2(`readlink -f "${path}" 2>/dev/null || realpath "${path}" 2>/dev/null || echo "${path}"`);
2255
2275
  resolvedPath = stdout.trim();
2256
2276
  } catch {
2257
2277
  }
@@ -2441,7 +2461,7 @@ async function handleDuplicateInstallations(skipPrompt = false) {
2441
2461
  }
2442
2462
  async function getHomebrewClaudeCodeVersion() {
2443
2463
  try {
2444
- const { stdout } = await execAsync$3("brew info --cask claude-code --json=v2");
2464
+ const { stdout } = await execAsync$2("brew info --cask claude-code --json=v2");
2445
2465
  const info = JSON.parse(stdout);
2446
2466
  if (info.casks && info.casks.length > 0) {
2447
2467
  return info.casks[0].version;
@@ -2514,7 +2534,24 @@ async function checkClaudeCodeVersionAndPrompt(skipPrompt = false) {
2514
2534
  }
2515
2535
  }
2516
2536
 
2517
- const execAsync$2 = promisify(exec$1);
2537
+ async function execWithSudoIfNeeded(command, args) {
2538
+ const needsSudo = shouldUseSudoForGlobalInstall();
2539
+ if (needsSudo) {
2540
+ console.log(ansis.yellow(`
2541
+ ${i18n.t("updater:usingSudo")}`));
2542
+ const result = await exec("sudo", [command, ...args]);
2543
+ if (result.exitCode !== 0) {
2544
+ throw new Error(result.stderr || `Command failed with exit code ${result.exitCode}`);
2545
+ }
2546
+ return { usedSudo: true };
2547
+ } else {
2548
+ const result = await exec(command, args);
2549
+ if (result.exitCode !== 0) {
2550
+ throw new Error(result.stderr || `Command failed with exit code ${result.exitCode}`);
2551
+ }
2552
+ return { usedSudo: false };
2553
+ }
2554
+ }
2518
2555
  async function updateCcr(force = false, skipPrompt = false) {
2519
2556
  ensureI18nInitialized();
2520
2557
  const spinner = ora(i18n.t("updater:checkingVersion")).start();
@@ -2549,7 +2586,7 @@ async function updateCcr(force = false, skipPrompt = false) {
2549
2586
  }
2550
2587
  const updateSpinner = ora(format(i18n.t("updater:updating"), { tool: "CCR" })).start();
2551
2588
  try {
2552
- await execAsync$2("npm update -g @musistudio/claude-code-router");
2589
+ await execWithSudoIfNeeded("npm", ["update", "-g", "@musistudio/claude-code-router"]);
2553
2590
  updateSpinner.succeed(format(i18n.t("updater:updateSuccess"), { tool: "CCR" }));
2554
2591
  return true;
2555
2592
  } catch (error) {
@@ -2599,9 +2636,12 @@ async function updateClaudeCode(force = false, skipPrompt = false) {
2599
2636
  const updateSpinner = ora(format(i18n.t("updater:updating"), { tool: toolName })).start();
2600
2637
  try {
2601
2638
  if (isHomebrew) {
2602
- await execAsync$2("brew upgrade --cask claude-code");
2639
+ const result = await exec("brew", ["upgrade", "--cask", "claude-code"]);
2640
+ if (result.exitCode !== 0) {
2641
+ throw new Error(result.stderr || `Command failed with exit code ${result.exitCode}`);
2642
+ }
2603
2643
  } else {
2604
- await execAsync$2("claude update");
2644
+ await execWithSudoIfNeeded("claude", ["update"]);
2605
2645
  }
2606
2646
  updateSpinner.succeed(format(i18n.t("updater:updateSuccess"), { tool: "Claude Code" }));
2607
2647
  return true;
@@ -2650,7 +2690,7 @@ async function updateCometixLine(force = false, skipPrompt = false) {
2650
2690
  }
2651
2691
  const updateSpinner = ora(format(i18n.t("updater:updating"), { tool: "CCometixLine" })).start();
2652
2692
  try {
2653
- await execAsync$2("npm update -g @cometix/ccline");
2693
+ await execWithSudoIfNeeded("npm", ["update", "-g", "@cometix/ccline"]);
2654
2694
  updateSpinner.succeed(format(i18n.t("updater:updateSuccess"), { tool: "CCometixLine" }));
2655
2695
  return true;
2656
2696
  } catch (error) {
@@ -2721,6 +2761,7 @@ async function checkAndUpdateTools(skipPrompt = false) {
2721
2761
  const autoUpdater = {
2722
2762
  __proto__: null,
2723
2763
  checkAndUpdateTools: checkAndUpdateTools,
2764
+ execWithSudoIfNeeded: execWithSudoIfNeeded,
2724
2765
  updateCcr: updateCcr,
2725
2766
  updateClaudeCode: updateClaudeCode,
2726
2767
  updateCometixLine: updateCometixLine
@@ -3342,11 +3383,83 @@ async function configureCodexMcp(options) {
3342
3383
  ensureI18nInitialized();
3343
3384
  const { skipPrompt = false } = options ?? {};
3344
3385
  const existingConfig = readCodexConfig();
3345
- if (skipPrompt)
3346
- return;
3347
3386
  const backupPath = backupCodexComplete();
3348
3387
  if (backupPath)
3349
3388
  console.log(ansis.gray(getBackupMessage(backupPath)));
3389
+ if (skipPrompt) {
3390
+ const { runCodexWorkflowSelection } = await Promise.resolve().then(function () { return codex; });
3391
+ await runCodexWorkflowSelection({ skipPrompt: true, workflows: options?.workflows ?? [] });
3392
+ if (options?.mcpServices === false) {
3393
+ updateZcfConfig({ codeToolType: "codex" });
3394
+ console.log(ansis.green(i18n.t("codex:mcpConfigured")));
3395
+ return;
3396
+ }
3397
+ const defaultServiceIds = Array.isArray(options?.mcpServices) ? options.mcpServices : MCP_SERVICE_CONFIGS.filter((service) => !service.requiresApiKey).map((service) => service.id);
3398
+ const baseProviders2 = existingConfig?.providers || [];
3399
+ const existingServices2 = existingConfig?.mcpServices || [];
3400
+ const selection2 = [];
3401
+ for (const id of defaultServiceIds) {
3402
+ const configInfo = MCP_SERVICE_CONFIGS.find((service) => service.id === id);
3403
+ if (!configInfo)
3404
+ continue;
3405
+ let command = configInfo.config.command || id;
3406
+ let args = (configInfo.config.args || []).map((arg) => String(arg));
3407
+ if (id === "serena") {
3408
+ const idx = args.indexOf("--context");
3409
+ if (idx >= 0 && idx + 1 < args.length)
3410
+ args[idx + 1] = "codex";
3411
+ else
3412
+ args.push("--context", "codex");
3413
+ }
3414
+ const serviceConfig = { id: id.toLowerCase(), command, args };
3415
+ applyCodexPlatformCommand(serviceConfig);
3416
+ command = serviceConfig.command;
3417
+ args = serviceConfig.args || [];
3418
+ const env = { ...configInfo.config.env || {} };
3419
+ if (isWindows()) {
3420
+ const systemRoot = getSystemRoot();
3421
+ if (systemRoot)
3422
+ env.SYSTEMROOT = systemRoot;
3423
+ }
3424
+ selection2.push({
3425
+ id: id.toLowerCase(),
3426
+ command,
3427
+ args,
3428
+ env: Object.keys(env).length > 0 ? env : void 0,
3429
+ startup_timeout_sec: 30
3430
+ });
3431
+ }
3432
+ const mergedMap2 = /* @__PURE__ */ new Map();
3433
+ for (const svc of existingServices2)
3434
+ mergedMap2.set(svc.id.toLowerCase(), { ...svc });
3435
+ for (const svc of selection2)
3436
+ mergedMap2.set(svc.id.toLowerCase(), { ...svc });
3437
+ const finalServices2 = Array.from(mergedMap2.values()).map((svc) => {
3438
+ if (isWindows()) {
3439
+ const systemRoot = getSystemRoot();
3440
+ if (systemRoot) {
3441
+ return {
3442
+ ...svc,
3443
+ env: {
3444
+ ...svc.env || {},
3445
+ SYSTEMROOT: systemRoot
3446
+ }
3447
+ };
3448
+ }
3449
+ }
3450
+ return svc;
3451
+ });
3452
+ writeCodexConfig({
3453
+ model: existingConfig?.model || null,
3454
+ modelProvider: existingConfig?.modelProvider || null,
3455
+ providers: baseProviders2,
3456
+ mcpServices: finalServices2,
3457
+ otherConfig: existingConfig?.otherConfig || []
3458
+ });
3459
+ updateZcfConfig({ codeToolType: "codex" });
3460
+ console.log(ansis.green(i18n.t("codex:mcpConfigured")));
3461
+ return;
3462
+ }
3350
3463
  const selectedIds = await selectMcpServices();
3351
3464
  if (!selectedIds)
3352
3465
  return;
@@ -3457,6 +3570,7 @@ async function configureCodexMcp(options) {
3457
3570
  console.log(ansis.green(i18n.t("codex:mcpConfigured")));
3458
3571
  }
3459
3572
 
3573
+ let cachedSkipPromptBackup = null;
3460
3574
  function getRootDir$1() {
3461
3575
  const currentFilePath = fileURLToPath(import.meta.url);
3462
3576
  let dir = dirname(currentFilePath);
@@ -3545,12 +3659,16 @@ function createBackupDirectory(timestamp) {
3545
3659
  function backupCodexFiles() {
3546
3660
  if (!exists(CODEX_DIR))
3547
3661
  return null;
3662
+ if (process.env.ZCF_CODEX_SKIP_PROMPT_SINGLE_BACKUP === "true" && cachedSkipPromptBackup)
3663
+ return cachedSkipPromptBackup;
3548
3664
  const timestamp = dayjs().format("YYYY-MM-DD_HH-mm-ss");
3549
3665
  const backupDir = createBackupDirectory(timestamp);
3550
3666
  const filter = (path) => {
3551
3667
  return !path.includes("/backup");
3552
3668
  };
3553
3669
  copyDir(CODEX_DIR, backupDir, { filter });
3670
+ if (process.env.ZCF_CODEX_SKIP_PROMPT_SINGLE_BACKUP === "true")
3671
+ cachedSkipPromptBackup = backupDir;
3554
3672
  return backupDir;
3555
3673
  }
3556
3674
  function backupCodexComplete() {
@@ -3570,6 +3688,8 @@ function backupCodexConfig() {
3570
3688
  }
3571
3689
  }
3572
3690
  function backupCodexAgents() {
3691
+ if (process.env.ZCF_CODEX_SKIP_PROMPT_SINGLE_BACKUP === "true" && cachedSkipPromptBackup)
3692
+ return cachedSkipPromptBackup;
3573
3693
  if (!exists(CODEX_AGENTS_FILE))
3574
3694
  return null;
3575
3695
  try {
@@ -3583,6 +3703,8 @@ function backupCodexAgents() {
3583
3703
  }
3584
3704
  }
3585
3705
  function backupCodexPrompts() {
3706
+ if (process.env.ZCF_CODEX_SKIP_PROMPT_SINGLE_BACKUP === "true" && cachedSkipPromptBackup)
3707
+ return cachedSkipPromptBackup;
3586
3708
  if (!exists(CODEX_PROMPTS_DIR))
3587
3709
  return null;
3588
3710
  try {
@@ -4353,29 +4475,39 @@ async function applyCustomApiConfig(customApiConfig) {
4353
4475
  if (backupPath) {
4354
4476
  console.log(ansis.gray(getBackupMessage(backupPath)));
4355
4477
  }
4478
+ const existingConfig = readCodexConfig();
4479
+ const existingAuth = readJsonConfig(CODEX_AUTH_FILE, { defaultValue: {} }) || {};
4356
4480
  const providers = [];
4357
- const authEntries = {};
4481
+ const authEntries = { ...existingAuth };
4358
4482
  const providerId = type === "auth_token" ? "official-auth-token" : "custom-api-key";
4359
4483
  const providerName = type === "auth_token" ? "Official Auth Token" : "Custom API Key";
4484
+ const existingProvider = existingConfig?.providers.find((p) => p.id === providerId);
4360
4485
  providers.push({
4361
4486
  id: providerId,
4362
4487
  name: providerName,
4363
- baseUrl: baseUrl || "https://api.anthropic.com",
4364
- wireApi: "claude",
4365
- tempEnvKey: `${providerId.toUpperCase()}_API_KEY`,
4366
- requiresOpenaiAuth: false
4488
+ baseUrl: baseUrl || existingProvider?.baseUrl || "https://api.anthropic.com",
4489
+ wireApi: existingProvider?.wireApi || "responses",
4490
+ tempEnvKey: existingProvider?.tempEnvKey || `${providerId.toUpperCase()}_API_KEY`,
4491
+ requiresOpenaiAuth: existingProvider?.requiresOpenaiAuth ?? false,
4492
+ model: model || existingProvider?.model
4367
4493
  });
4494
+ if (existingConfig?.providers) {
4495
+ providers.push(...existingConfig.providers.filter((p) => p.id !== providerId));
4496
+ }
4368
4497
  if (token) {
4369
4498
  authEntries[providerId] = token;
4499
+ authEntries.OPENAI_API_KEY = token;
4370
4500
  }
4371
4501
  const configData = {
4372
- model: model || "claude-3-5-sonnet-20241022",
4373
- // Use provided model or default
4502
+ model: model || existingConfig?.model || "claude-3-5-sonnet-20241022",
4503
+ // Prefer provided model, then existing, fallback default
4374
4504
  modelProvider: providerId,
4375
4505
  modelProviderCommented: false,
4376
4506
  providers,
4377
- mcpServices: []};
4378
- writeFile(CODEX_CONFIG_FILE, renderCodexConfig(configData));
4507
+ mcpServices: existingConfig?.mcpServices || [],
4508
+ otherConfig: existingConfig?.otherConfig || []
4509
+ };
4510
+ writeCodexConfig(configData);
4379
4511
  writeJsonConfig(CODEX_AUTH_FILE, authEntries);
4380
4512
  updateZcfConfig({ codeToolType: "codex" });
4381
4513
  console.log(ansis.green(`\u2714 ${i18n.t("codex:apiConfigured")}`));
@@ -6508,15 +6640,18 @@ async function validateSkipPromptOptions(options) {
6508
6640
  if (options.apiConfigs && options.apiConfigsFile) {
6509
6641
  throw new Error(i18n.t("multi-config:conflictingParams"));
6510
6642
  }
6511
- if (options.apiModel && typeof options.apiModel !== "string") {
6512
- throw new Error(
6513
- i18n.t("errors:invalidApiModel", { value: options.apiModel })
6514
- );
6515
- }
6516
- if (options.apiFastModel && typeof options.apiFastModel !== "string") {
6517
- throw new Error(
6518
- i18n.t("errors:invalidApiFastModel", { value: options.apiFastModel })
6519
- );
6643
+ const modelParams = [
6644
+ ["apiModel", options.apiModel],
6645
+ ["apiHaikuModel", options.apiHaikuModel],
6646
+ ["apiSonnetModel", options.apiSonnetModel],
6647
+ ["apiOpusModel", options.apiOpusModel]
6648
+ ];
6649
+ for (const [key, value] of modelParams) {
6650
+ if (value !== void 0 && typeof value !== "string") {
6651
+ if (key === "apiModel")
6652
+ throw new Error(i18n.t("errors:invalidApiModel", { value }));
6653
+ throw new Error(i18n.t("errors:invalidModelParam", { key, value }));
6654
+ }
6520
6655
  }
6521
6656
  if (options.apiType === "api_key" && !options.apiKey) {
6522
6657
  throw new Error(i18n.t("errors:apiKeyRequiredForApiKey"));
@@ -6706,8 +6841,11 @@ async function init(options = {}) {
6706
6841
  configLang = "en";
6707
6842
  }
6708
6843
  if (codeToolType === "codex") {
6709
- const apiMode = options.apiType === "auth_token" ? "official" : options.apiType === "api_key" ? "custom" : options.apiType === "skip" ? "skip" : options.skipPrompt ? "skip" : void 0;
6710
- const customApiConfig = options.apiType === "api_key" && options.apiKey ? {
6844
+ if (options.skipPrompt)
6845
+ process.env.ZCF_CODEX_SKIP_PROMPT_SINGLE_BACKUP = "true";
6846
+ const hasApiConfigs = Boolean(options.apiConfigs || options.apiConfigsFile);
6847
+ const apiMode = hasApiConfigs ? "skip" : options.apiType === "auth_token" ? "official" : options.apiType === "api_key" ? "custom" : options.apiType === "skip" ? "skip" : options.skipPrompt ? "skip" : void 0;
6848
+ const customApiConfig = !hasApiConfigs && options.apiType === "api_key" && options.apiKey ? {
6711
6849
  type: "api_key",
6712
6850
  token: options.apiKey,
6713
6851
  baseUrl: options.apiUrl,
@@ -6722,6 +6860,9 @@ async function init(options = {}) {
6722
6860
  } else if (options.workflows === true) {
6723
6861
  selectedWorkflows = [];
6724
6862
  }
6863
+ if (hasApiConfigs) {
6864
+ await handleMultiConfigurations(options, "codex");
6865
+ }
6725
6866
  const resolvedAiOutputLang = await runCodexFullInit({
6726
6867
  aiOutputLang: options.aiOutputLang,
6727
6868
  skipPrompt: options.skipPrompt,
@@ -6840,9 +6981,12 @@ async function init(options = {}) {
6840
6981
  key: options.apiKey,
6841
6982
  url: preset?.claudeCode?.baseUrl || options.apiUrl || API_DEFAULT_URL
6842
6983
  };
6843
- if (preset?.claudeCode?.defaultModels && preset.claudeCode.defaultModels.length >= 2) {
6844
- options.apiModel = options.apiModel || preset.claudeCode.defaultModels[0];
6845
- options.apiFastModel = options.apiFastModel || preset.claudeCode.defaultModels[1];
6984
+ if (preset?.claudeCode?.defaultModels && preset.claudeCode.defaultModels.length > 0) {
6985
+ const [primary, haiku, sonnet, opus] = preset.claudeCode.defaultModels;
6986
+ options.apiModel = options.apiModel || primary;
6987
+ options.apiHaikuModel = options.apiHaikuModel || haiku;
6988
+ options.apiSonnetModel = options.apiSonnetModel || sonnet;
6989
+ options.apiOpusModel = options.apiOpusModel || opus;
6846
6990
  }
6847
6991
  await saveSingleConfigToToml(apiConfig, options.provider, options);
6848
6992
  } else if (options.apiType === "auth_token" && options.apiKey) {
@@ -6969,20 +7113,26 @@ async function init(options = {}) {
6969
7113
  console.log(ansis.gray(` Key: ${formatApiKeyDisplay(configuredApi.key)}`));
6970
7114
  }
6971
7115
  }
6972
- if ((options.apiModel || options.apiFastModel) && action !== "docs-only" && codeToolType === "claude-code") {
7116
+ const hasModelParams = options.apiModel || options.apiHaikuModel || options.apiSonnetModel || options.apiOpusModel;
7117
+ if (hasModelParams && action !== "docs-only" && codeToolType === "claude-code") {
6973
7118
  if (options.skipPrompt) {
6974
7119
  const { updateCustomModel } = await Promise.resolve().then(function () { return config$1; });
6975
7120
  updateCustomModel(
6976
7121
  options.apiModel || void 0,
6977
- options.apiFastModel || void 0
7122
+ options.apiHaikuModel || void 0,
7123
+ options.apiSonnetModel || void 0,
7124
+ options.apiOpusModel || void 0
6978
7125
  );
6979
7126
  console.log(ansis.green(`\u2714 ${i18n.t("api:modelConfigSuccess")}`));
6980
7127
  if (options.apiModel) {
6981
7128
  console.log(ansis.gray(` ${i18n.t("api:primaryModel")}: ${options.apiModel}`));
6982
7129
  }
6983
- if (options.apiFastModel) {
6984
- console.log(ansis.gray(` ${i18n.t("api:fastModel")}: ${options.apiFastModel}`));
6985
- }
7130
+ if (options.apiHaikuModel)
7131
+ console.log(ansis.gray(` Haiku: ${options.apiHaikuModel}`));
7132
+ if (options.apiSonnetModel)
7133
+ console.log(ansis.gray(` Sonnet: ${options.apiSonnetModel}`));
7134
+ if (options.apiOpusModel)
7135
+ console.log(ansis.gray(` Opus: ${options.apiOpusModel}`));
6986
7136
  }
6987
7137
  }
6988
7138
  if (action !== "docs-only") {
@@ -7205,6 +7355,7 @@ async function handleClaudeCodeConfigs(configs) {
7205
7355
  }
7206
7356
  async function handleCodexConfigs(configs) {
7207
7357
  const { addProviderToExisting } = await import('./codex-provider-manager.mjs');
7358
+ const addedProviderIds = [];
7208
7359
  for (const config of configs) {
7209
7360
  try {
7210
7361
  const provider = await convertToCodexProvider(config);
@@ -7212,6 +7363,7 @@ async function handleCodexConfigs(configs) {
7212
7363
  if (!result.success) {
7213
7364
  throw new Error(i18n.t("multi-config:providerAddFailed", { name: config.name, error: result.error }));
7214
7365
  }
7366
+ addedProviderIds.push(provider.id);
7215
7367
  console.log(ansis.green(`\u2714 ${i18n.t("multi-config:providerAdded", { name: config.name })}`));
7216
7368
  } catch (error) {
7217
7369
  console.error(ansis.red(i18n.t("multi-config:providerAddFailed", {
@@ -7224,8 +7376,14 @@ async function handleCodexConfigs(configs) {
7224
7376
  const defaultConfig = configs.find((c) => c.default);
7225
7377
  if (defaultConfig) {
7226
7378
  const { switchCodexProvider } = await Promise.resolve().then(function () { return codex; });
7227
- await switchCodexProvider(defaultConfig.name);
7228
- console.log(ansis.green(`\u2714 ${i18n.t("multi-config:defaultProviderSet", { name: defaultConfig.name })}`));
7379
+ const displayName = defaultConfig.name || defaultConfig.provider || "custom";
7380
+ const providerId = displayName.toLowerCase().replace(/[^a-z0-9]/g, "-");
7381
+ if (addedProviderIds.includes(providerId)) {
7382
+ await switchCodexProvider(providerId);
7383
+ console.log(ansis.green(`\u2714 ${i18n.t("multi-config:defaultProviderSet", { name: displayName })}`));
7384
+ } else {
7385
+ console.log(ansis.red(i18n.t("multi-config:providerAddFailed", { name: displayName, error: "provider not added" })));
7386
+ }
7229
7387
  }
7230
7388
  }
7231
7389
  async function saveSingleConfigToToml(apiConfig, provider, options) {
@@ -7252,7 +7410,9 @@ async function convertSingleConfigToProfile(apiConfig, provider, options) {
7252
7410
  const configName = provider && provider !== "custom" ? provider : "custom-config";
7253
7411
  let baseUrl = apiConfig.url || API_DEFAULT_URL;
7254
7412
  let primaryModel = options?.apiModel;
7255
- let fastModel = options?.apiFastModel;
7413
+ let defaultHaikuModel = options?.apiHaikuModel;
7414
+ let defaultSonnetModel = options?.apiSonnetModel;
7415
+ let defaultOpusModel = options?.apiOpusModel;
7256
7416
  let authType = apiConfig.authType;
7257
7417
  if (provider && provider !== "custom") {
7258
7418
  const { getProviderPreset } = await import('./api-providers.mjs');
@@ -7260,9 +7420,12 @@ async function convertSingleConfigToProfile(apiConfig, provider, options) {
7260
7420
  if (preset?.claudeCode) {
7261
7421
  baseUrl = apiConfig.url || preset.claudeCode.baseUrl;
7262
7422
  authType = preset.claudeCode.authType;
7263
- if (preset.claudeCode.defaultModels && preset.claudeCode.defaultModels.length >= 2) {
7264
- primaryModel = primaryModel || preset.claudeCode.defaultModels[0];
7265
- fastModel = fastModel || preset.claudeCode.defaultModels[1];
7423
+ if (preset.claudeCode.defaultModels && preset.claudeCode.defaultModels.length > 0) {
7424
+ const [p, h, s, o] = preset.claudeCode.defaultModels;
7425
+ primaryModel = primaryModel || p;
7426
+ defaultHaikuModel = defaultHaikuModel || h;
7427
+ defaultSonnetModel = defaultSonnetModel || s;
7428
+ defaultOpusModel = defaultOpusModel || o;
7266
7429
  }
7267
7430
  }
7268
7431
  }
@@ -7272,7 +7435,9 @@ async function convertSingleConfigToProfile(apiConfig, provider, options) {
7272
7435
  apiKey: apiConfig.key,
7273
7436
  baseUrl,
7274
7437
  primaryModel,
7275
- fastModel,
7438
+ defaultHaikuModel,
7439
+ defaultSonnetModel,
7440
+ defaultOpusModel,
7276
7441
  id: ClaudeCodeConfigManager.generateProfileId(configName)
7277
7442
  };
7278
7443
  return profile;
@@ -7281,7 +7446,9 @@ async function convertToClaudeCodeProfile(config) {
7281
7446
  const { ClaudeCodeConfigManager } = await import('./claude-code-config-manager.mjs');
7282
7447
  let baseUrl = config.url;
7283
7448
  let primaryModel = config.primaryModel;
7284
- let fastModel = config.fastModel;
7449
+ let defaultHaikuModel = config.defaultHaikuModel;
7450
+ let defaultSonnetModel = config.defaultSonnetModel;
7451
+ let defaultOpusModel = config.defaultOpusModel;
7285
7452
  let authType = config.type || "api_key";
7286
7453
  if (config.provider && config.provider !== "custom") {
7287
7454
  const { getProviderPreset } = await import('./api-providers.mjs');
@@ -7289,9 +7456,12 @@ async function convertToClaudeCodeProfile(config) {
7289
7456
  if (preset?.claudeCode) {
7290
7457
  baseUrl = baseUrl || preset.claudeCode.baseUrl;
7291
7458
  authType = preset.claudeCode.authType;
7292
- if (preset.claudeCode.defaultModels && preset.claudeCode.defaultModels.length >= 2) {
7293
- primaryModel = primaryModel || preset.claudeCode.defaultModels[0];
7294
- fastModel = fastModel || preset.claudeCode.defaultModels[1];
7459
+ if (preset.claudeCode.defaultModels && preset.claudeCode.defaultModels.length > 0) {
7460
+ const [p, h, s, o] = preset.claudeCode.defaultModels;
7461
+ primaryModel = primaryModel || p;
7462
+ defaultHaikuModel = defaultHaikuModel || h;
7463
+ defaultSonnetModel = defaultSonnetModel || s;
7464
+ defaultOpusModel = defaultOpusModel || o;
7295
7465
  }
7296
7466
  }
7297
7467
  }
@@ -7301,15 +7471,19 @@ async function convertToClaudeCodeProfile(config) {
7301
7471
  apiKey: config.key,
7302
7472
  baseUrl,
7303
7473
  primaryModel,
7304
- fastModel,
7474
+ defaultHaikuModel,
7475
+ defaultSonnetModel,
7476
+ defaultOpusModel,
7305
7477
  id: ClaudeCodeConfigManager.generateProfileId(config.name)
7306
7478
  };
7307
7479
  return profile;
7308
7480
  }
7309
7481
  async function convertToCodexProvider(config) {
7482
+ const displayName = config.name || config.provider || "custom";
7483
+ const providerId = displayName.toLowerCase().replace(/[^a-z0-9]/g, "-");
7310
7484
  let baseUrl = config.url || API_DEFAULT_URL;
7311
7485
  let model = config.primaryModel || "gpt-5-codex";
7312
- let wireApi = "chat";
7486
+ let wireApi = "responses";
7313
7487
  if (config.provider && config.provider !== "custom") {
7314
7488
  const { getProviderPreset } = await import('./api-providers.mjs');
7315
7489
  const preset = getProviderPreset(config.provider);
@@ -7320,11 +7494,11 @@ async function convertToCodexProvider(config) {
7320
7494
  }
7321
7495
  }
7322
7496
  return {
7323
- id: config.name.toLowerCase().replace(/[^a-z0-9]/g, "-"),
7324
- name: config.name,
7497
+ id: providerId,
7498
+ name: displayName,
7325
7499
  baseUrl,
7326
7500
  wireApi,
7327
- tempEnvKey: API_ENV_KEY,
7501
+ tempEnvKey: `${displayName}_API_KEY`.replace(/\W/g, "_").toUpperCase(),
7328
7502
  requiresOpenaiAuth: false,
7329
7503
  model
7330
7504
  };
@@ -7408,4 +7582,4 @@ async function openSettingsJson() {
7408
7582
  }
7409
7583
  }
7410
7584
 
7411
- export { getExistingModelConfig as $, API_DEFAULT_URL as A, getAiOutputLanguageLabel as B, CLAUDE_DIR as C, DEFAULT_CODE_TOOL_TYPE as D, getMcpConfigPath as E, readMcpConfig as F, writeMcpConfig as G, backupMcpConfig as H, mergeMcpServers as I, buildMcpServerConfig as J, fixWindowsMcpConfig as K, LEGACY_ZCF_CONFIG_FILES as L, addCompletedOnboarding as M, ensureApiKeyApproved as N, removeApiKeyFromRejected as O, manageApiKeyApproval as P, setPrimaryApiKey as Q, ensureClaudeDir as R, SETTINGS_FILE as S, backupExistingConfig as T, copyConfigFiles as U, configureApi as V, mergeConfigs as W, updateCustomModel as X, updateDefaultModel as Y, ZCF_CONFIG_DIR as Z, mergeSettingsFile as _, commandExists as a, updatePromptOnly as a$, getExistingApiConfig as a0, applyAiLanguageDirective as a1, switchToOfficialLogin$1 as a2, promptApiConfigurationAction as a3, isClaudeCodeInstalled as a4, installClaudeCode as a5, isCodexInstalled as a6, installCodex as a7, isLocalClaudeCodeInstalled as a8, getInstallationStatus as a9, writeAuthFile as aA, updateZcfConfig as aB, changeLanguage as aC, readZcfConfig as aD, configureOutputStyle as aE, isWindows as aF, selectMcpServices as aG, getMcpServices as aH, isCcrInstalled as aI, installCcr as aJ, setupCcrConfiguration as aK, modifyApiConfigPartially as aL, formatApiKeyDisplay as aM, readCcrConfig as aN, configureCcrFeature as aO, handleExitPromptError as aP, handleGeneralError as aQ, COMETIX_COMMAND_NAME as aR, COMETIX_COMMANDS as aS, installCometixLine as aT, checkAndUpdateTools as aU, runCodexUpdate as aV, resolveCodeType as aW, writeJsonConfig as aX, displayBanner as aY, version as aZ, resolveAiOutputLanguage as a_, removeLocalClaudeCode as aa, uninstallCodeTool as ab, setInstallMethod as ac, detectInstalledVersion as ad, selectInstallMethod as ae, executeInstallMethod as af, handleInstallFailure as ag, verifyInstallation as ah, createHomebrewSymlink as ai, displayVerificationResult as aj, ensureI18nInitialized as ak, i18n as al, addNumbersToChoices as am, validateApiKey as an, promptBoolean as ao, ensureDir as ap, readDefaultTomlConfig as aq, createDefaultTomlConfig as ar, exists as as, readJsonConfig as at, writeTomlConfig as au, copyFile as av, detectConfigManagementMode as aw, readCodexConfig as ax, backupCodexComplete as ay, writeCodexConfig as az, importRecommendedEnv as b, selectAndInstallWorkflows as b0, checkClaudeCodeVersionAndPrompt as b1, displayBannerWithInfo as b2, runCodexUninstall as b3, configureCodexMcp as b4, configureCodexApi as b5, runCodexWorkflowImportWithLanguageSelection as b6, runCodexFullInit as b7, switchCodexProvider as b8, listCodexProviders as b9, switchToOfficialLogin as ba, switchToProvider as bb, readZcfConfigAsync as bc, initI18n as bd, selectScriptLanguage as be, index as bf, fsOperations as bg, jsonConfig as bh, claudeConfig as bi, config$1 as bj, config as bk, prompts as bl, codex as bm, installer as bn, cleanupPermissions as c, importRecommendedPermissions as d, CLAUDE_MD_FILE as e, ClAUDE_CONFIG_FILE as f, getPlatform as g, CLAUDE_VSC_CONFIG_FILE as h, init as i, CODEX_DIR as j, CODEX_CONFIG_FILE as k, CODEX_AUTH_FILE as l, mergeAndCleanPermissions as m, CODEX_AGENTS_FILE as n, openSettingsJson as o, CODEX_PROMPTS_DIR as p, ZCF_CONFIG_FILE as q, CODE_TOOL_TYPES as r, CODE_TOOL_BANNERS as s, CODE_TOOL_ALIASES as t, isCodeToolType as u, API_ENV_KEY as v, resolveCodeToolType as w, SUPPORTED_LANGS as x, LANG_LABELS as y, AI_OUTPUT_LANGUAGES as z };
7585
+ export { getExistingModelConfig as $, API_DEFAULT_URL as A, getAiOutputLanguageLabel as B, CLAUDE_DIR as C, DEFAULT_CODE_TOOL_TYPE as D, getMcpConfigPath as E, readMcpConfig as F, writeMcpConfig as G, backupMcpConfig as H, mergeMcpServers as I, buildMcpServerConfig as J, fixWindowsMcpConfig as K, LEGACY_ZCF_CONFIG_FILES as L, addCompletedOnboarding as M, ensureApiKeyApproved as N, removeApiKeyFromRejected as O, manageApiKeyApproval as P, setPrimaryApiKey as Q, ensureClaudeDir as R, SETTINGS_FILE as S, backupExistingConfig as T, copyConfigFiles as U, configureApi as V, mergeConfigs as W, updateCustomModel as X, updateDefaultModel as Y, ZCF_CONFIG_DIR as Z, mergeSettingsFile as _, commandExists as a, resolveAiOutputLanguage as a$, getExistingApiConfig as a0, applyAiLanguageDirective as a1, switchToOfficialLogin$1 as a2, promptApiConfigurationAction as a3, isClaudeCodeInstalled as a4, installClaudeCode as a5, isCodexInstalled as a6, installCodex as a7, isLocalClaudeCodeInstalled as a8, getInstallationStatus as a9, writeCodexConfig as aA, writeAuthFile as aB, updateZcfConfig as aC, changeLanguage as aD, readZcfConfig as aE, configureOutputStyle as aF, isWindows as aG, selectMcpServices as aH, getMcpServices as aI, isCcrInstalled as aJ, installCcr as aK, setupCcrConfiguration as aL, modifyApiConfigPartially as aM, formatApiKeyDisplay as aN, readCcrConfig as aO, configureCcrFeature as aP, handleExitPromptError as aQ, handleGeneralError as aR, COMETIX_COMMAND_NAME as aS, COMETIX_COMMANDS as aT, installCometixLine as aU, checkAndUpdateTools as aV, runCodexUpdate as aW, resolveCodeType as aX, writeJsonConfig as aY, displayBanner as aZ, version as a_, removeLocalClaudeCode as aa, uninstallCodeTool as ab, setInstallMethod as ac, detectInstalledVersion as ad, selectInstallMethod as ae, executeInstallMethod as af, handleInstallFailure as ag, verifyInstallation as ah, createHomebrewSymlink as ai, displayVerificationResult as aj, ensureI18nInitialized as ak, i18n as al, addNumbersToChoices as am, validateApiKey as an, promptBoolean as ao, ensureDir as ap, readDefaultTomlConfig as aq, createDefaultTomlConfig as ar, exists as as, readJsonConfig as at, writeTomlConfig as au, clearModelEnv as av, copyFile as aw, detectConfigManagementMode as ax, readCodexConfig as ay, backupCodexComplete as az, importRecommendedEnv as b, updatePromptOnly as b0, selectAndInstallWorkflows as b1, checkClaudeCodeVersionAndPrompt as b2, displayBannerWithInfo as b3, runCodexUninstall as b4, configureCodexMcp as b5, configureCodexApi as b6, runCodexWorkflowImportWithLanguageSelection as b7, runCodexFullInit as b8, switchCodexProvider as b9, listCodexProviders as ba, switchToOfficialLogin as bb, switchToProvider as bc, readZcfConfigAsync as bd, initI18n as be, selectScriptLanguage as bf, index as bg, fsOperations as bh, jsonConfig as bi, claudeConfig as bj, config$1 as bk, config as bl, prompts as bm, codex as bn, installer as bo, cleanupPermissions as c, importRecommendedPermissions as d, CLAUDE_MD_FILE as e, ClAUDE_CONFIG_FILE as f, getPlatform as g, CLAUDE_VSC_CONFIG_FILE as h, init as i, CODEX_DIR as j, CODEX_CONFIG_FILE as k, CODEX_AUTH_FILE as l, mergeAndCleanPermissions as m, CODEX_AGENTS_FILE as n, openSettingsJson as o, CODEX_PROMPTS_DIR as p, ZCF_CONFIG_FILE as q, CODE_TOOL_TYPES as r, CODE_TOOL_BANNERS as s, CODE_TOOL_ALIASES as t, isCodeToolType as u, API_ENV_KEY as v, resolveCodeToolType as w, SUPPORTED_LANGS as x, LANG_LABELS as y, AI_OUTPUT_LANGUAGES as z };