zcf 3.1.3 → 3.2.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 (37) hide show
  1. package/README.md +50 -21
  2. package/dist/chunks/claude-code-config-manager.mjs +705 -0
  3. package/dist/chunks/claude-code-incremental-manager.mjs +393 -0
  4. package/dist/chunks/codex-config-switch.mjs +2 -174
  5. package/dist/chunks/codex-provider-manager.mjs +193 -0
  6. package/dist/chunks/codex-uninstaller.mjs +1 -1
  7. package/dist/chunks/commands.mjs +117 -0
  8. package/dist/chunks/simple-config.mjs +578 -193
  9. package/dist/cli.mjs +284 -142
  10. package/dist/i18n/locales/en/api.json +1 -2
  11. package/dist/i18n/locales/en/cli.json +2 -0
  12. package/dist/i18n/locales/en/codex.json +0 -1
  13. package/dist/i18n/locales/en/common.json +2 -2
  14. package/dist/i18n/locales/en/errors.json +1 -0
  15. package/dist/i18n/locales/en/multi-config.json +61 -0
  16. package/dist/i18n/locales/zh-CN/api.json +1 -2
  17. package/dist/i18n/locales/zh-CN/cli.json +2 -0
  18. package/dist/i18n/locales/zh-CN/codex.json +0 -1
  19. package/dist/i18n/locales/zh-CN/common.json +2 -2
  20. package/dist/i18n/locales/zh-CN/errors.json +1 -0
  21. package/dist/i18n/locales/zh-CN/multi-config.json +61 -0
  22. package/dist/index.d.mts +6 -2
  23. package/dist/index.d.ts +6 -2
  24. package/dist/index.mjs +1 -1
  25. package/package.json +1 -1
  26. package/templates/claude-code/en/workflow/git/commands/git-commit.md +1 -0
  27. package/templates/claude-code/zh-CN/workflow/git/commands/git-commit.md +1 -0
  28. package/templates/codex/en/workflow/git/prompts/git-cleanBranches.md +102 -0
  29. package/templates/codex/en/workflow/git/prompts/git-commit.md +158 -0
  30. package/templates/codex/en/workflow/git/prompts/git-rollback.md +90 -0
  31. package/templates/codex/en/workflow/git/prompts/git-worktree.md +276 -0
  32. package/templates/codex/en/workflow/sixStep/prompts/workflow.md +140 -121
  33. package/templates/codex/zh-CN/workflow/git/prompts/git-cleanBranches.md +102 -0
  34. package/templates/codex/zh-CN/workflow/git/prompts/git-commit.md +158 -0
  35. package/templates/codex/zh-CN/workflow/git/prompts/git-rollback.md +90 -0
  36. package/templates/codex/zh-CN/workflow/git/prompts/git-worktree.md +276 -0
  37. package/templates/codex/zh-CN/workflow/sixStep/prompts/workflow.md +16 -33
@@ -1,4 +1,4 @@
1
- import { existsSync, readFileSync, mkdirSync, writeFileSync, copyFileSync, rmSync, rmdirSync, readdirSync, statSync, unlinkSync, renameSync } from 'node:fs';
1
+ import { existsSync, readFileSync, mkdirSync, copyFileSync, writeFileSync, rmSync, rmdirSync, readdirSync, statSync, unlinkSync, renameSync } from 'node:fs';
2
2
  import process from 'node:process';
3
3
  import ansis from 'ansis';
4
4
  import inquirer from 'inquirer';
@@ -10,13 +10,13 @@ import { dirname, join } from 'pathe';
10
10
  import { fileURLToPath } from 'node:url';
11
11
  import ora from 'ora';
12
12
  import semver from 'semver';
13
- import { parse, stringify } from 'smol-toml';
13
+ import { stringify, parse } from 'smol-toml';
14
14
  import { exec, x } from 'tinyexec';
15
15
  import { rm, mkdir, copyFile as copyFile$1 } from 'node:fs/promises';
16
16
  import i18next from 'i18next';
17
17
  import Backend from 'i18next-fs-backend';
18
18
 
19
- const version = "3.1.3";
19
+ const version = "3.2.0";
20
20
  const homepage = "https://github.com/UfoMiao/zcf";
21
21
 
22
22
  const i18n = i18next.createInstance();
@@ -32,6 +32,7 @@ const NAMESPACES = [
32
32
  "language",
33
33
  "mcp",
34
34
  "menu",
35
+ "multi-config",
35
36
  "tools",
36
37
  "uninstall",
37
38
  "updater",
@@ -377,9 +378,22 @@ const CODE_TOOL_BANNERS = {
377
378
  "claude-code": "for Claude Code",
378
379
  "codex": "for Codex"
379
380
  };
381
+ const CODE_TOOL_ALIASES = {
382
+ cc: "claude-code",
383
+ cx: "codex"
384
+ };
380
385
  function isCodeToolType(value) {
381
386
  return CODE_TOOL_TYPES.includes(value);
382
387
  }
388
+ function resolveCodeToolType(value) {
389
+ if (isCodeToolType(value)) {
390
+ return value;
391
+ }
392
+ if (typeof value === "string" && value in CODE_TOOL_ALIASES) {
393
+ return CODE_TOOL_ALIASES[value];
394
+ }
395
+ return DEFAULT_CODE_TOOL_TYPE;
396
+ }
383
397
  const SUPPORTED_LANGS = ["zh-CN", "en"];
384
398
  const LANG_LABELS = {
385
399
  "zh-CN": "\u7B80\u4F53\u4E2D\u6587",
@@ -409,6 +423,7 @@ const constants = {
409
423
  CLAUDE_DIR: CLAUDE_DIR,
410
424
  CLAUDE_MD_FILE: CLAUDE_MD_FILE,
411
425
  CLAUDE_VSC_CONFIG_FILE: CLAUDE_VSC_CONFIG_FILE,
426
+ CODE_TOOL_ALIASES: CODE_TOOL_ALIASES,
412
427
  CODE_TOOL_BANNERS: CODE_TOOL_BANNERS,
413
428
  CODE_TOOL_TYPES: CODE_TOOL_TYPES,
414
429
  ClAUDE_CONFIG_FILE: ClAUDE_CONFIG_FILE,
@@ -420,7 +435,8 @@ const constants = {
420
435
  ZCF_CONFIG_DIR: ZCF_CONFIG_DIR,
421
436
  ZCF_CONFIG_FILE: ZCF_CONFIG_FILE,
422
437
  getAiOutputLanguageLabel: getAiOutputLanguageLabel,
423
- isCodeToolType: isCodeToolType
438
+ isCodeToolType: isCodeToolType,
439
+ resolveCodeToolType: resolveCodeToolType
424
440
  };
425
441
 
426
442
  function getDisplayWidth(str) {
@@ -825,6 +841,13 @@ function backupJsonConfig(path, backupDir) {
825
841
  }
826
842
  }
827
843
 
844
+ const jsonConfig = {
845
+ __proto__: null,
846
+ backupJsonConfig: backupJsonConfig,
847
+ readJsonConfig: readJsonConfig,
848
+ writeJsonConfig: writeJsonConfig
849
+ };
850
+
828
851
  function mergeArraysUnique(arr1, arr2) {
829
852
  const combined = [...arr1 || [], ...arr2 || []];
830
853
  return [...new Set(combined)];
@@ -1352,6 +1375,23 @@ ${ansis.blue(`\u2139 ${i18n.t("api:existingApiConfig")}`)}`);
1352
1375
  return choice || null;
1353
1376
  }
1354
1377
 
1378
+ const config$1 = {
1379
+ __proto__: null,
1380
+ applyAiLanguageDirective: applyAiLanguageDirective,
1381
+ backupExistingConfig: backupExistingConfig,
1382
+ configureApi: configureApi,
1383
+ copyConfigFiles: copyConfigFiles,
1384
+ ensureClaudeDir: ensureClaudeDir,
1385
+ getExistingApiConfig: getExistingApiConfig,
1386
+ getExistingModelConfig: getExistingModelConfig,
1387
+ mergeConfigs: mergeConfigs,
1388
+ mergeSettingsFile: mergeSettingsFile,
1389
+ promptApiConfigurationAction: promptApiConfigurationAction,
1390
+ switchToOfficialLogin: switchToOfficialLogin$1,
1391
+ updateCustomModel: updateCustomModel,
1392
+ updateDefaultModel: updateDefaultModel
1393
+ };
1394
+
1355
1395
  const PROVIDER_PRESETS_URL = "https://pub-0dc3e1677e894f07bbea11b17a29e032.r2.dev/providers.json";
1356
1396
  async function fetchProviderPresets() {
1357
1397
  try {
@@ -1793,6 +1833,22 @@ async function configureCcrFeature() {
1793
1833
  await setupCcrConfiguration();
1794
1834
  }
1795
1835
 
1836
+ const config = {
1837
+ __proto__: null,
1838
+ backupCcrConfig: backupCcrConfig,
1839
+ configureCcrFeature: configureCcrFeature,
1840
+ configureCcrProxy: configureCcrProxy,
1841
+ configureCcrWithPreset: configureCcrWithPreset,
1842
+ createDefaultCcrConfig: createDefaultCcrConfig,
1843
+ ensureCcrConfigDir: ensureCcrConfigDir,
1844
+ readCcrConfig: readCcrConfig,
1845
+ restartAndCheckCcrStatus: restartAndCheckCcrStatus,
1846
+ selectCcrPreset: selectCcrPreset,
1847
+ setupCcrConfiguration: setupCcrConfiguration,
1848
+ showConfigurationTips: showConfigurationTips,
1849
+ writeCcrConfig: writeCcrConfig
1850
+ };
1851
+
1796
1852
  const execAsync$3 = promisify(exec$1);
1797
1853
  async function getInstalledVersion(command, maxRetries = 3) {
1798
1854
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
@@ -2149,27 +2205,6 @@ async function installCcr() {
2149
2205
  }
2150
2206
  }
2151
2207
 
2152
- async function selectMcpServices() {
2153
- ensureI18nInitialized();
2154
- const mcpServices = await getMcpServices();
2155
- const choices = mcpServices.map((service) => ({
2156
- name: `${service.name} - ${ansis.gray(service.description)}`,
2157
- value: service.id,
2158
- selected: false
2159
- }));
2160
- const { services } = await inquirer.prompt({
2161
- type: "checkbox",
2162
- name: "services",
2163
- message: `${i18n.t("mcp:selectMcpServices")}${i18n.t("common:multiSelectHint")}`,
2164
- choices
2165
- });
2166
- if (services === void 0) {
2167
- console.log(ansis.yellow(i18n.t("common:cancelled")));
2168
- return void 0;
2169
- }
2170
- return services;
2171
- }
2172
-
2173
2208
  function addNumbersToChoices(choices, startFrom = 1, format = (n) => `${n}. `) {
2174
2209
  let currentNumber = startFrom;
2175
2210
  return choices.map((choice) => {
@@ -2230,7 +2265,9 @@ function createDefaultTomlConfig(preferredLang = "en", claudeCodeInstallType = "
2230
2265
  enabled: true,
2231
2266
  outputStyles: ["engineer-professional"],
2232
2267
  defaultOutputStyle: "engineer-professional",
2233
- installType: claudeCodeInstallType
2268
+ installType: claudeCodeInstallType,
2269
+ currentProfile: "",
2270
+ profiles: {}
2234
2271
  },
2235
2272
  codex: {
2236
2273
  enabled: false,
@@ -2255,7 +2292,9 @@ function migrateFromJsonConfig(jsonConfig) {
2255
2292
  enabled: jsonConfig.codeToolType === "claude-code",
2256
2293
  outputStyles: jsonConfig.outputStyles || defaultConfig.claudeCode.outputStyles,
2257
2294
  defaultOutputStyle: jsonConfig.defaultOutputStyle || defaultConfig.claudeCode.defaultOutputStyle,
2258
- installType: claudeCodeInstallType
2295
+ installType: claudeCodeInstallType,
2296
+ currentProfile: jsonConfig.currentProfileId || defaultConfig.claudeCode.currentProfile,
2297
+ profiles: jsonConfig.claudeCode?.profiles || {}
2259
2298
  },
2260
2299
  codex: {
2261
2300
  enabled: jsonConfig.codeToolType === "codex",
@@ -2392,6 +2431,17 @@ function writeZcfConfig(config) {
2392
2431
  if (nextSystemPromptStyle) {
2393
2432
  tomlConfig.codex.systemPromptStyle = nextSystemPromptStyle;
2394
2433
  }
2434
+ if (existingTomlConfig?.claudeCode) {
2435
+ if (existingTomlConfig.claudeCode.profiles) {
2436
+ tomlConfig.claudeCode.profiles = existingTomlConfig.claudeCode.profiles;
2437
+ }
2438
+ if (existingTomlConfig.claudeCode.currentProfile !== void 0) {
2439
+ tomlConfig.claudeCode.currentProfile = existingTomlConfig.claudeCode.currentProfile;
2440
+ }
2441
+ if (existingTomlConfig.claudeCode.version) {
2442
+ tomlConfig.claudeCode.version = existingTomlConfig.claudeCode.version;
2443
+ }
2444
+ }
2395
2445
  writeTomlConfig(ZCF_CONFIG_FILE, tomlConfig);
2396
2446
  } catch {
2397
2447
  }
@@ -2498,12 +2548,15 @@ async function selectScriptLanguage(currentLang) {
2498
2548
  });
2499
2549
  return scriptLang;
2500
2550
  }
2501
- async function resolveAiOutputLanguage(scriptLang, commandLineOption, savedConfig) {
2551
+ async function resolveAiOutputLanguage(scriptLang, commandLineOption, savedConfig, skipPrompt) {
2502
2552
  ensureI18nInitialized();
2503
2553
  if (commandLineOption) {
2504
2554
  return commandLineOption;
2505
2555
  }
2506
2556
  if (savedConfig?.aiOutputLang) {
2557
+ if (skipPrompt) {
2558
+ return savedConfig.aiOutputLang;
2559
+ }
2507
2560
  const currentLanguageLabel = getAiOutputLanguageLabel(savedConfig.aiOutputLang) || savedConfig.aiOutputLang;
2508
2561
  console.log(ansis.blue(`${i18n.t("language:currentConfigFound")}: ${currentLanguageLabel}`));
2509
2562
  const { shouldModify } = await inquirer.prompt({
@@ -2522,6 +2575,9 @@ async function resolveAiOutputLanguage(scriptLang, commandLineOption, savedConfi
2522
2575
  }
2523
2576
  return await selectAiOutputLanguage(scriptLang);
2524
2577
  }
2578
+ if (skipPrompt) {
2579
+ return scriptLang;
2580
+ }
2525
2581
  return await selectAiOutputLanguage(scriptLang);
2526
2582
  }
2527
2583
  async function selectTemplateLanguage() {
@@ -2547,12 +2603,15 @@ async function selectTemplateLanguage() {
2547
2603
  }
2548
2604
  return lang;
2549
2605
  }
2550
- async function resolveTemplateLanguage(commandLineOption, savedConfig) {
2606
+ async function resolveTemplateLanguage(commandLineOption, savedConfig, skipPrompt) {
2551
2607
  ensureI18nInitialized();
2552
2608
  if (commandLineOption) {
2553
2609
  return commandLineOption;
2554
2610
  }
2555
2611
  if (savedConfig?.templateLang) {
2612
+ if (skipPrompt) {
2613
+ return savedConfig.templateLang;
2614
+ }
2556
2615
  const currentLanguageLabel = LANG_LABELS[savedConfig.templateLang];
2557
2616
  console.log(ansis.blue(`${i18n.t("language:currentTemplateLanguageFound")}: ${currentLanguageLabel}`));
2558
2617
  const { shouldModify } = await inquirer.prompt({
@@ -2572,6 +2631,9 @@ async function resolveTemplateLanguage(commandLineOption, savedConfig) {
2572
2631
  return await selectTemplateLanguage();
2573
2632
  }
2574
2633
  if (savedConfig?.preferredLang && !savedConfig?.templateLang) {
2634
+ if (skipPrompt) {
2635
+ return savedConfig.preferredLang;
2636
+ }
2575
2637
  console.log(ansis.yellow(`${i18n.t("language:usingFallbackTemplate")}: ${LANG_LABELS[savedConfig.preferredLang]}`));
2576
2638
  const { shouldModify } = await inquirer.prompt({
2577
2639
  type: "confirm",
@@ -2588,9 +2650,12 @@ async function resolveTemplateLanguage(commandLineOption, savedConfig) {
2588
2650
  }
2589
2651
  return await selectTemplateLanguage();
2590
2652
  }
2653
+ if (skipPrompt) {
2654
+ return "en";
2655
+ }
2591
2656
  return await selectTemplateLanguage();
2592
2657
  }
2593
- async function resolveSystemPromptStyle(availablePrompts, commandLineOption, savedConfig) {
2658
+ async function resolveSystemPromptStyle(availablePrompts, commandLineOption, savedConfig, skipPrompt) {
2594
2659
  ensureI18nInitialized();
2595
2660
  if (commandLineOption && availablePrompts.some((p) => p.id === commandLineOption)) {
2596
2661
  return commandLineOption;
@@ -2599,6 +2664,9 @@ async function resolveSystemPromptStyle(availablePrompts, commandLineOption, sav
2599
2664
  const currentStyleId = savedConfig.codex.systemPromptStyle;
2600
2665
  const currentStyle = availablePrompts.find((p) => p.id === currentStyleId);
2601
2666
  if (currentStyle) {
2667
+ if (skipPrompt) {
2668
+ return currentStyleId;
2669
+ }
2602
2670
  console.log(ansis.blue(`${i18n.t("language:currentSystemPromptFound")}: ${currentStyle.name}`));
2603
2671
  const { shouldModify } = await inquirer.prompt({
2604
2672
  type: "confirm",
@@ -2616,6 +2684,9 @@ async function resolveSystemPromptStyle(availablePrompts, commandLineOption, sav
2616
2684
  }
2617
2685
  }
2618
2686
  }
2687
+ if (skipPrompt) {
2688
+ return "engineer-professional";
2689
+ }
2619
2690
  const { systemPrompt } = await inquirer.prompt([{
2620
2691
  type: "list",
2621
2692
  name: "systemPrompt",
@@ -2672,6 +2743,27 @@ function detectConfigManagementMode() {
2672
2743
  }
2673
2744
  }
2674
2745
 
2746
+ async function selectMcpServices() {
2747
+ ensureI18nInitialized();
2748
+ const mcpServices = await getMcpServices();
2749
+ const choices = mcpServices.map((service) => ({
2750
+ name: `${service.name} - ${ansis.gray(service.description)}`,
2751
+ value: service.id,
2752
+ selected: false
2753
+ }));
2754
+ const { services } = await inquirer.prompt({
2755
+ type: "checkbox",
2756
+ name: "services",
2757
+ message: `${i18n.t("mcp:selectMcpServices")}${i18n.t("common:multiSelectHint")}`,
2758
+ choices
2759
+ });
2760
+ if (services === void 0) {
2761
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
2762
+ return void 0;
2763
+ }
2764
+ return services;
2765
+ }
2766
+
2675
2767
  function applyCodexPlatformCommand(config) {
2676
2768
  if (config.command === "npx" && isWindows()) {
2677
2769
  const mcpCmd = getMcpCommand();
@@ -2679,6 +2771,118 @@ function applyCodexPlatformCommand(config) {
2679
2771
  config.args = [...mcpCmd.slice(1), ...config.args || []];
2680
2772
  }
2681
2773
  }
2774
+
2775
+ async function configureCodexMcp(options) {
2776
+ ensureI18nInitialized();
2777
+ const { skipPrompt = false } = options ?? {};
2778
+ const existingConfig = readCodexConfig();
2779
+ if (skipPrompt)
2780
+ return;
2781
+ const backupPath = backupCodexComplete();
2782
+ if (backupPath)
2783
+ console.log(ansis.gray(getBackupMessage(backupPath)));
2784
+ const selectedIds = await selectMcpServices();
2785
+ if (!selectedIds)
2786
+ return;
2787
+ const servicesMeta = await getMcpServices();
2788
+ const baseProviders = existingConfig?.providers || [];
2789
+ const selection = [];
2790
+ const existingServices = existingConfig?.mcpServices || [];
2791
+ if (selectedIds.length === 0) {
2792
+ console.log(ansis.yellow(i18n.t("codex:noMcpConfigured")));
2793
+ const preserved = (existingServices || []).map((svc) => {
2794
+ if (isWindows()) {
2795
+ const systemRoot = getSystemRoot();
2796
+ if (systemRoot) {
2797
+ return {
2798
+ ...svc,
2799
+ env: {
2800
+ ...svc.env || {},
2801
+ SYSTEMROOT: systemRoot
2802
+ }
2803
+ };
2804
+ }
2805
+ }
2806
+ return svc;
2807
+ });
2808
+ writeCodexConfig({
2809
+ model: existingConfig?.model || null,
2810
+ modelProvider: existingConfig?.modelProvider || null,
2811
+ providers: baseProviders,
2812
+ mcpServices: preserved,
2813
+ otherConfig: existingConfig?.otherConfig || []
2814
+ });
2815
+ updateZcfConfig({ codeToolType: "codex" });
2816
+ return;
2817
+ }
2818
+ for (const id of selectedIds) {
2819
+ const configInfo = MCP_SERVICE_CONFIGS.find((service) => service.id === id);
2820
+ if (!configInfo)
2821
+ continue;
2822
+ const serviceMeta = servicesMeta.find((service) => service.id === id);
2823
+ let command = configInfo.config.command || id;
2824
+ let args = (configInfo.config.args || []).map((arg) => String(arg));
2825
+ const serviceConfig = { id: id.toLowerCase(), command, args };
2826
+ applyCodexPlatformCommand(serviceConfig);
2827
+ command = serviceConfig.command;
2828
+ args = serviceConfig.args || [];
2829
+ const env = { ...configInfo.config.env || {} };
2830
+ if (isWindows()) {
2831
+ const systemRoot = getSystemRoot();
2832
+ if (systemRoot)
2833
+ env.SYSTEMROOT = systemRoot;
2834
+ }
2835
+ if (configInfo.requiresApiKey && configInfo.apiKeyEnvVar) {
2836
+ const promptMessage = serviceMeta?.apiKeyPrompt || i18n.t("mcp:apiKeyPrompt");
2837
+ const { apiKey } = await inquirer.prompt([{
2838
+ type: "password",
2839
+ name: "apiKey",
2840
+ message: promptMessage + i18n.t("common:inputHidden"),
2841
+ validate: (input) => !!input || i18n.t("api:keyRequired")
2842
+ }]);
2843
+ if (!apiKey)
2844
+ continue;
2845
+ env[configInfo.apiKeyEnvVar] = apiKey;
2846
+ }
2847
+ selection.push({
2848
+ id: id.toLowerCase(),
2849
+ command: serviceConfig.command,
2850
+ args: serviceConfig.args,
2851
+ env: Object.keys(env).length > 0 ? env : void 0,
2852
+ startup_timeout_ms: configInfo.config.startup_timeout_ms
2853
+ });
2854
+ }
2855
+ const mergedMap = /* @__PURE__ */ new Map();
2856
+ for (const svc of existingServices)
2857
+ mergedMap.set(svc.id.toLowerCase(), { ...svc });
2858
+ for (const svc of selection)
2859
+ mergedMap.set(svc.id.toLowerCase(), { ...svc });
2860
+ const finalServices = Array.from(mergedMap.values()).map((svc) => {
2861
+ if (isWindows()) {
2862
+ const systemRoot = getSystemRoot();
2863
+ if (systemRoot) {
2864
+ return {
2865
+ ...svc,
2866
+ env: {
2867
+ ...svc.env || {},
2868
+ SYSTEMROOT: systemRoot
2869
+ }
2870
+ };
2871
+ }
2872
+ }
2873
+ return svc;
2874
+ });
2875
+ writeCodexConfig({
2876
+ model: existingConfig?.model || null,
2877
+ modelProvider: existingConfig?.modelProvider || null,
2878
+ providers: baseProviders,
2879
+ mcpServices: finalServices,
2880
+ otherConfig: existingConfig?.otherConfig || []
2881
+ });
2882
+ updateZcfConfig({ codeToolType: "codex" });
2883
+ console.log(ansis.green(i18n.t("codex:mcpConfigured")));
2884
+ }
2885
+
2682
2886
  const CODEX_DIR = join(homedir(), ".codex");
2683
2887
  const CODEX_CONFIG_FILE = join(CODEX_DIR, "config.toml");
2684
2888
  const CODEX_AUTH_FILE = join(CODEX_DIR, "auth.json");
@@ -2921,7 +3125,9 @@ function parseCodexConfig(content) {
2921
3125
  modelProviderCommented
2922
3126
  };
2923
3127
  } catch (error) {
2924
- console.warn("TOML parsing failed, falling back to basic parsing:", error);
3128
+ if (process.env.NODE_ENV === "development" || process.env.DEBUG) {
3129
+ console.warn("TOML parsing failed, falling back to basic parsing:", error);
3130
+ }
2925
3131
  const cleaned = content.replace(/^\s*#\s*---\s*model provider added by ZCF\s*---\s*$/gim, "").replace(/^\s*#\s*---\s*MCP servers added by ZCF\s*---\s*$/gim, "").replace(/^\[model_providers\.[^\]]+\][\s\S]*?(?=^\[|$)/gim, "").replace(/^\[mcp_servers\.[^\]]+\][\s\S]*?(?=^\[|$)/gim, "").replace(/^\s*(?:#\s*)?model_provider\s*=.*$/gim, "").replace(/^\s*model\s*=.*$/gim, "").replace(/\n{3,}/g, "\n\n");
2926
3132
  const otherConfig = cleaned.split("\n").map((l) => l.replace(/\s+$/g, "")).filter((l) => l.trim().length > 0);
2927
3133
  return {
@@ -3115,30 +3321,25 @@ async function installCodexCli() {
3115
3321
  }
3116
3322
  await executeCodexInstallation(false);
3117
3323
  }
3118
- async function runCodexWorkflowImport() {
3119
- ensureI18nInitialized();
3120
- await runCodexSystemPromptSelection();
3121
- await runCodexWorkflowSelection();
3122
- console.log(ansis.green(i18n.t("codex:workflowInstall")));
3123
- }
3124
3324
  async function runCodexWorkflowImportWithLanguageSelection(options) {
3125
3325
  ensureI18nInitialized();
3126
3326
  const zcfConfig = readZcfConfig();
3127
- const { aiOutputLang: commandLineOption, skipPrompt } = options ?? {};
3128
- const aiOutputLang = skipPrompt ? commandLineOption || zcfConfig?.aiOutputLang || "en" : await resolveAiOutputLanguage(
3327
+ const { aiOutputLang: commandLineOption, skipPrompt = false } = options ?? {};
3328
+ const aiOutputLang = await resolveAiOutputLanguage(
3129
3329
  i18n.language,
3130
3330
  commandLineOption,
3131
- zcfConfig
3331
+ zcfConfig,
3332
+ skipPrompt
3132
3333
  );
3133
3334
  updateZcfConfig({ aiOutputLang });
3134
3335
  applyAiLanguageDirective(aiOutputLang);
3135
- await runCodexSystemPromptSelection();
3336
+ await runCodexSystemPromptSelection(skipPrompt);
3136
3337
  ensureCodexAgentsLanguageDirective(aiOutputLang);
3137
- await runCodexWorkflowSelection();
3338
+ await runCodexWorkflowSelection(options);
3138
3339
  console.log(ansis.green(i18n.t("codex:workflowInstall")));
3139
3340
  return aiOutputLang;
3140
3341
  }
3141
- async function runCodexSystemPromptSelection() {
3342
+ async function runCodexSystemPromptSelection(skipPrompt = false) {
3142
3343
  ensureI18nInitialized();
3143
3344
  const rootDir = getRootDir$1();
3144
3345
  const templateRoot = join(rootDir, "templates", "codex");
@@ -3149,7 +3350,9 @@ async function runCodexSystemPromptSelection() {
3149
3350
  const preferredLang = await resolveTemplateLanguage(
3150
3351
  void 0,
3151
3352
  // No command line option for this function
3152
- zcfConfig$1
3353
+ zcfConfig$1,
3354
+ skipPrompt
3355
+ // Pass skipPrompt flag
3153
3356
  );
3154
3357
  updateZcfConfig({ templateLang: preferredLang });
3155
3358
  let langDir = join(templateRoot, preferredLang);
@@ -3187,7 +3390,9 @@ async function runCodexSystemPromptSelection() {
3187
3390
  availablePrompts,
3188
3391
  void 0,
3189
3392
  // No command line option for this function
3190
- tomlConfig
3393
+ tomlConfig,
3394
+ skipPrompt
3395
+ // Pass skipPrompt flag
3191
3396
  );
3192
3397
  if (!systemPrompt)
3193
3398
  return;
@@ -3211,8 +3416,9 @@ async function runCodexSystemPromptSelection() {
3211
3416
  console.error("Failed to update ZCF config:", error);
3212
3417
  }
3213
3418
  }
3214
- async function runCodexWorkflowSelection() {
3419
+ async function runCodexWorkflowSelection(options) {
3215
3420
  ensureI18nInitialized();
3421
+ const { skipPrompt = false, workflows: presetWorkflows = [] } = options ?? {};
3216
3422
  const rootDir = getRootDir$1();
3217
3423
  const templateRoot = join(rootDir, "templates", "codex");
3218
3424
  const zcfConfig = readZcfConfig();
@@ -3227,6 +3433,29 @@ async function runCodexWorkflowSelection() {
3227
3433
  const allWorkflows = getAllWorkflowFiles(workflowSrc);
3228
3434
  if (allWorkflows.length === 0)
3229
3435
  return;
3436
+ if (skipPrompt) {
3437
+ ensureDir(CODEX_PROMPTS_DIR);
3438
+ const backupPath2 = backupCodexPrompts();
3439
+ if (backupPath2) {
3440
+ console.log(ansis.gray(getBackupMessage(backupPath2)));
3441
+ }
3442
+ let workflowsToInstall;
3443
+ if (presetWorkflows.length > 0) {
3444
+ const selectedWorkflows = allWorkflows.filter(
3445
+ (workflow) => presetWorkflows.includes(workflow.name)
3446
+ );
3447
+ workflowsToInstall = expandSelectedWorkflowPaths(selectedWorkflows.map((w) => w.path), workflowSrc);
3448
+ } else {
3449
+ workflowsToInstall = expandSelectedWorkflowPaths(allWorkflows.map((w) => w.path), workflowSrc);
3450
+ }
3451
+ for (const workflowPath of workflowsToInstall) {
3452
+ const content = readFile(workflowPath);
3453
+ const filename = workflowPath.split("/").pop() || "workflow.md";
3454
+ const targetPath = join(CODEX_PROMPTS_DIR, filename);
3455
+ writeFile(targetPath, content);
3456
+ }
3457
+ return;
3458
+ }
3230
3459
  const { workflows } = await inquirer.prompt([{
3231
3460
  type: "checkbox",
3232
3461
  name: "workflows",
@@ -3245,13 +3474,15 @@ async function runCodexWorkflowSelection() {
3245
3474
  if (backupPath) {
3246
3475
  console.log(ansis.gray(getBackupMessage(backupPath)));
3247
3476
  }
3248
- for (const workflowPath of workflows) {
3477
+ const finalWorkflowPaths = expandSelectedWorkflowPaths(workflows, workflowSrc);
3478
+ for (const workflowPath of finalWorkflowPaths) {
3249
3479
  const content = readFile(workflowPath);
3250
3480
  const filename = workflowPath.split("/").pop() || "workflow.md";
3251
3481
  const targetPath = join(CODEX_PROMPTS_DIR, filename);
3252
3482
  writeFile(targetPath, content);
3253
3483
  }
3254
3484
  }
3485
+ const GIT_GROUP_SENTINEL = "::gitGroup";
3255
3486
  function getAllWorkflowFiles(dirPath) {
3256
3487
  const workflows = [];
3257
3488
  const sixStepDir = join(dirPath, "sixStep", "prompts");
@@ -3264,8 +3495,43 @@ function getAllWorkflowFiles(dirPath) {
3264
3495
  });
3265
3496
  }
3266
3497
  }
3498
+ const gitPromptsDir = join(dirPath, "git", "prompts");
3499
+ if (exists(gitPromptsDir)) {
3500
+ workflows.push({
3501
+ name: i18n.t("workflow:workflowOption.gitWorkflow"),
3502
+ // Use sentinel path for grouped selection; expanded later
3503
+ path: GIT_GROUP_SENTINEL
3504
+ });
3505
+ }
3267
3506
  return workflows;
3268
3507
  }
3508
+ function expandSelectedWorkflowPaths(paths, workflowSrc) {
3509
+ const expanded = [];
3510
+ for (const p of paths) {
3511
+ if (p === GIT_GROUP_SENTINEL) {
3512
+ expanded.push(...getGitPromptFiles(workflowSrc));
3513
+ } else {
3514
+ expanded.push(p);
3515
+ }
3516
+ }
3517
+ return expanded;
3518
+ }
3519
+ function getGitPromptFiles(workflowSrc) {
3520
+ const gitDir = join(workflowSrc, "git", "prompts");
3521
+ const files = [
3522
+ "git-commit.md",
3523
+ "git-rollback.md",
3524
+ "git-cleanBranches.md",
3525
+ "git-worktree.md"
3526
+ ];
3527
+ const resolved = [];
3528
+ for (const f of files) {
3529
+ const full = join(gitDir, f);
3530
+ if (exists(full))
3531
+ resolved.push(full);
3532
+ }
3533
+ return resolved;
3534
+ }
3269
3535
  function toProvidersList(providers) {
3270
3536
  return providers.map((provider) => ({ name: provider.name || provider.id, value: provider.id }));
3271
3537
  }
@@ -3285,10 +3551,59 @@ function createApiConfigChoices(providers, currentProvider, isCommented) {
3285
3551
  });
3286
3552
  return choices;
3287
3553
  }
3288
- async function configureCodexApi() {
3554
+ async function applyCustomApiConfig(customApiConfig) {
3555
+ const { type, token, baseUrl } = customApiConfig;
3556
+ const backupPath = backupCodexComplete();
3557
+ if (backupPath) {
3558
+ console.log(ansis.gray(getBackupMessage(backupPath)));
3559
+ }
3560
+ const providers = [];
3561
+ const authEntries = {};
3562
+ const providerId = type === "auth_token" ? "official-auth-token" : "custom-api-key";
3563
+ const providerName = type === "auth_token" ? "Official Auth Token" : "Custom API Key";
3564
+ providers.push({
3565
+ id: providerId,
3566
+ name: providerName,
3567
+ baseUrl: baseUrl || "https://api.anthropic.com",
3568
+ wireApi: "claude",
3569
+ envKey: `${providerId.toUpperCase()}_API_KEY`,
3570
+ requiresOpenaiAuth: false
3571
+ });
3572
+ if (token) {
3573
+ authEntries[providerId] = token;
3574
+ }
3575
+ const configData = {
3576
+ model: "claude-3-5-sonnet-20241022",
3577
+ modelProvider: providerId,
3578
+ modelProviderCommented: false,
3579
+ providers,
3580
+ mcpServices: []};
3581
+ writeFile(CODEX_CONFIG_FILE, renderCodexConfig(configData));
3582
+ writeJsonConfig(CODEX_AUTH_FILE, authEntries);
3583
+ updateZcfConfig({ codeToolType: "codex" });
3584
+ console.log(ansis.green(`\u2714 ${i18n.t("codex:apiConfigured")}`));
3585
+ }
3586
+ async function configureCodexApi(options) {
3289
3587
  ensureI18nInitialized();
3588
+ const { skipPrompt = false, apiMode, customApiConfig } = options ?? {};
3290
3589
  const existingConfig = readCodexConfig();
3291
3590
  const existingAuth = readJsonConfig(CODEX_AUTH_FILE, { defaultValue: {} }) || {};
3591
+ if (skipPrompt) {
3592
+ if (apiMode === "skip") {
3593
+ return;
3594
+ }
3595
+ if (apiMode === "custom" && customApiConfig) {
3596
+ await applyCustomApiConfig(customApiConfig);
3597
+ return;
3598
+ }
3599
+ if (apiMode === "official") {
3600
+ const success = await switchToOfficialLogin();
3601
+ if (success) {
3602
+ updateZcfConfig({ codeToolType: "codex" });
3603
+ }
3604
+ return;
3605
+ }
3606
+ }
3292
3607
  const hasProviders = existingConfig?.providers && existingConfig.providers.length > 0;
3293
3608
  const modeChoices = [
3294
3609
  { name: i18n.t("codex:apiModeOfficial"), value: "official" },
@@ -3477,124 +3792,12 @@ async function configureCodexApi() {
3477
3792
  updateZcfConfig({ codeToolType: "codex" });
3478
3793
  console.log(ansis.green(i18n.t("codex:apiConfigured")));
3479
3794
  }
3480
- async function configureCodexMcp() {
3481
- ensureI18nInitialized();
3482
- const existingConfig = readCodexConfig();
3483
- const backupPath = backupCodexComplete();
3484
- if (backupPath) {
3485
- console.log(ansis.gray(getBackupMessage(backupPath)));
3486
- }
3487
- const selectedIds = await selectMcpServices();
3488
- if (!selectedIds)
3489
- return;
3490
- const servicesMeta = await getMcpServices();
3491
- const baseProviders = existingConfig?.providers || [];
3492
- const selection = [];
3493
- const existingServices = existingConfig?.mcpServices || [];
3494
- if (selectedIds.length === 0) {
3495
- console.log(ansis.yellow(i18n.t("codex:noMcpConfigured")));
3496
- const preserved = (existingServices || []).map((svc) => {
3497
- if (isWindows()) {
3498
- const systemRoot = getSystemRoot();
3499
- if (systemRoot) {
3500
- return {
3501
- ...svc,
3502
- env: {
3503
- ...svc.env || {},
3504
- SYSTEMROOT: systemRoot
3505
- }
3506
- };
3507
- }
3508
- }
3509
- return svc;
3510
- });
3511
- writeCodexConfig({
3512
- model: existingConfig?.model || null,
3513
- modelProvider: existingConfig?.modelProvider || null,
3514
- providers: baseProviders,
3515
- mcpServices: preserved,
3516
- otherConfig: existingConfig?.otherConfig || []
3517
- });
3518
- updateZcfConfig({ codeToolType: "codex" });
3519
- return;
3520
- }
3521
- for (const id of selectedIds) {
3522
- const configInfo = MCP_SERVICE_CONFIGS.find((service) => service.id === id);
3523
- if (!configInfo)
3524
- continue;
3525
- const serviceMeta = servicesMeta.find((service) => service.id === id);
3526
- let command = configInfo.config.command || id;
3527
- let args = (configInfo.config.args || []).map((arg) => String(arg));
3528
- const serviceConfig = { id: id.toLowerCase(), command, args };
3529
- applyCodexPlatformCommand(serviceConfig);
3530
- command = serviceConfig.command;
3531
- args = serviceConfig.args || [];
3532
- const env = { ...configInfo.config.env || {} };
3533
- if (isWindows()) {
3534
- const systemRoot = getSystemRoot();
3535
- if (systemRoot) {
3536
- env.SYSTEMROOT = systemRoot;
3537
- }
3538
- }
3539
- if (configInfo.requiresApiKey && configInfo.apiKeyEnvVar) {
3540
- const promptMessage = serviceMeta?.apiKeyPrompt || i18n.t("mcp:apiKeyPrompt");
3541
- const { apiKey } = await inquirer.prompt([{
3542
- type: "password",
3543
- name: "apiKey",
3544
- message: promptMessage + i18n.t("common:inputHidden"),
3545
- validate: (input) => !!input || i18n.t("api:keyRequired")
3546
- }]);
3547
- if (!apiKey)
3548
- continue;
3549
- env[configInfo.apiKeyEnvVar] = apiKey;
3550
- }
3551
- selection.push({
3552
- id: id.toLowerCase(),
3553
- // Convert to lowercase for Codex compatibility
3554
- command: serviceConfig.command,
3555
- args: serviceConfig.args,
3556
- env: Object.keys(env).length > 0 ? env : void 0,
3557
- startup_timeout_ms: configInfo.config.startup_timeout_ms
3558
- });
3559
- }
3560
- const mergedMap = /* @__PURE__ */ new Map();
3561
- for (const svc of existingServices) {
3562
- mergedMap.set(svc.id.toLowerCase(), { ...svc });
3563
- }
3564
- for (const svc of selection) {
3565
- mergedMap.set(svc.id.toLowerCase(), { ...svc });
3566
- }
3567
- const finalServices = Array.from(mergedMap.values()).map((svc) => {
3568
- if (isWindows()) {
3569
- const systemRoot = getSystemRoot();
3570
- if (systemRoot) {
3571
- return {
3572
- ...svc,
3573
- env: {
3574
- ...svc.env || {},
3575
- SYSTEMROOT: systemRoot
3576
- }
3577
- };
3578
- }
3579
- }
3580
- return svc;
3581
- });
3582
- writeCodexConfig({
3583
- model: existingConfig?.model || null,
3584
- modelProvider: existingConfig?.modelProvider || null,
3585
- providers: baseProviders,
3586
- mcpServices: finalServices,
3587
- otherConfig: existingConfig?.otherConfig || []
3588
- });
3589
- updateZcfConfig({ codeToolType: "codex" });
3590
- console.log(ansis.green(i18n.t("codex:mcpConfigured")));
3591
- }
3592
3795
  async function runCodexFullInit(options) {
3593
3796
  ensureI18nInitialized();
3594
3797
  await installCodexCli();
3595
3798
  const aiOutputLang = await runCodexWorkflowImportWithLanguageSelection(options);
3596
- await configureCodexApi();
3597
- await configureCodexMcp();
3799
+ await configureCodexApi(options);
3800
+ await configureCodexMcp(options);
3598
3801
  return aiOutputLang;
3599
3802
  }
3600
3803
  function ensureCodexAgentsLanguageDirective(aiOutputLang) {
@@ -3634,7 +3837,10 @@ function normalizeLanguageLabel(label) {
3634
3837
  }
3635
3838
  async function runCodexUpdate(force = false, skipPrompt = false) {
3636
3839
  ensureI18nInitialized();
3637
- const spinner = ora(i18n.t("codex:checkingVersion")).start();
3840
+ console.log(ansis.bold.cyan(`
3841
+ \u{1F50D} ${i18n.t("updater:checkingTools")}
3842
+ `));
3843
+ const spinner = ora(i18n.t("updater:checkingVersion")).start();
3638
3844
  try {
3639
3845
  const { installed, currentVersion, latestVersion, needsUpdate } = await checkCodexUpdate();
3640
3846
  spinner.stop();
@@ -3750,10 +3956,6 @@ function displayUninstallResults(results) {
3750
3956
  }
3751
3957
  }
3752
3958
  }
3753
- async function getCurrentCodexProvider() {
3754
- const config = readCodexConfig();
3755
- return config?.modelProvider || null;
3756
- }
3757
3959
  async function listCodexProviders() {
3758
3960
  const config = readCodexConfig();
3759
3961
  return config?.providers || [];
@@ -3865,6 +4067,7 @@ async function switchToProvider(providerId) {
3865
4067
  const codex = {
3866
4068
  __proto__: null,
3867
4069
  CODEX_DIR: CODEX_DIR,
4070
+ applyCodexPlatformCommand: applyCodexPlatformCommand,
3868
4071
  backupCodexAgents: backupCodexAgents,
3869
4072
  backupCodexComplete: backupCodexComplete,
3870
4073
  backupCodexConfig: backupCodexConfig,
@@ -3876,7 +4079,6 @@ const codex = {
3876
4079
  createBackupDirectory: createBackupDirectory,
3877
4080
  getBackupMessage: getBackupMessage,
3878
4081
  getCodexVersion: getCodexVersion,
3879
- getCurrentCodexProvider: getCurrentCodexProvider,
3880
4082
  installCodexCli: installCodexCli,
3881
4083
  isCodexInstalled: isCodexInstalled,
3882
4084
  listCodexProviders: listCodexProviders,
@@ -3887,7 +4089,6 @@ const codex = {
3887
4089
  runCodexSystemPromptSelection: runCodexSystemPromptSelection,
3888
4090
  runCodexUninstall: runCodexUninstall,
3889
4091
  runCodexUpdate: runCodexUpdate,
3890
- runCodexWorkflowImport: runCodexWorkflowImport,
3891
4092
  runCodexWorkflowImportWithLanguageSelection: runCodexWorkflowImportWithLanguageSelection,
3892
4093
  runCodexWorkflowSelection: runCodexWorkflowSelection,
3893
4094
  switchCodexProvider: switchCodexProvider,
@@ -3897,6 +4098,43 @@ const codex = {
3897
4098
  writeCodexConfig: writeCodexConfig
3898
4099
  };
3899
4100
 
4101
+ const CODE_TYPE_ABBREVIATIONS = {
4102
+ cc: "claude-code",
4103
+ cx: "codex"
4104
+ };
4105
+ async function resolveCodeType(codeTypeParam) {
4106
+ if (codeTypeParam) {
4107
+ const normalizedParam = codeTypeParam.toLowerCase().trim();
4108
+ if (normalizedParam in CODE_TYPE_ABBREVIATIONS) {
4109
+ return CODE_TYPE_ABBREVIATIONS[normalizedParam];
4110
+ }
4111
+ if (isValidCodeType(normalizedParam)) {
4112
+ return normalizedParam;
4113
+ }
4114
+ const validAbbreviations = Object.keys(CODE_TYPE_ABBREVIATIONS);
4115
+ const validFullTypes = Object.values(CODE_TYPE_ABBREVIATIONS);
4116
+ const validOptions = [...validAbbreviations, ...validFullTypes].join(", ");
4117
+ throw new Error(
4118
+ i18n.t(
4119
+ "errors:invalidCodeType",
4120
+ `Invalid code type: "${codeTypeParam}". Valid options are: ${validOptions}.`,
4121
+ { value: codeTypeParam, validOptions }
4122
+ )
4123
+ );
4124
+ }
4125
+ try {
4126
+ const config = await readZcfConfigAsync();
4127
+ if (config?.codeToolType && isValidCodeType(config.codeToolType)) {
4128
+ return config.codeToolType;
4129
+ }
4130
+ } catch {
4131
+ }
4132
+ return DEFAULT_CODE_TOOL_TYPE;
4133
+ }
4134
+ function isValidCodeType(value) {
4135
+ return ["claude-code", "codex"].includes(value);
4136
+ }
4137
+
3900
4138
  function getPlatformStatusLineConfig() {
3901
4139
  return {
3902
4140
  type: "command",
@@ -4793,12 +5031,6 @@ function validateSkipPromptOptions(options) {
4793
5031
  if (!options.configAction) {
4794
5032
  options.configAction = "backup";
4795
5033
  }
4796
- if (!options.configLang) {
4797
- options.configLang = "en";
4798
- }
4799
- if (!options.aiOutputLang) {
4800
- options.aiOutputLang = "en";
4801
- }
4802
5034
  if (typeof options.outputStyles === "string") {
4803
5035
  if (options.outputStyles === "skip") {
4804
5036
  options.outputStyles = false;
@@ -4830,6 +5062,9 @@ function validateSkipPromptOptions(options) {
4830
5062
  i18n.t("errors:invalidApiType", { value: options.apiType })
4831
5063
  );
4832
5064
  }
5065
+ if (options.apiConfigs && options.apiConfigsFile) {
5066
+ throw new Error("Cannot specify both --api-configs and --api-configs-file at the same time");
5067
+ }
4833
5068
  if (options.apiType === "api_key" && !options.apiKey) {
4834
5069
  throw new Error(i18n.t("errors:apiKeyRequiredForApiKey"));
4835
5070
  }
@@ -4893,22 +5128,20 @@ function validateSkipPromptOptions(options) {
4893
5128
  options.workflows = WORKFLOW_CONFIG_BASE.map((w) => w.id);
4894
5129
  }
4895
5130
  }
4896
- function resolveCodeToolType(optionValue, savedValue) {
4897
- if (isCodeToolType(optionValue)) {
4898
- return optionValue;
4899
- }
4900
- if (savedValue && isCodeToolType(savedValue)) {
4901
- return savedValue;
4902
- }
4903
- return DEFAULT_CODE_TOOL_TYPE;
4904
- }
4905
5131
  async function init(options = {}) {
4906
5132
  if (options.skipPrompt) {
4907
5133
  validateSkipPromptOptions(options);
4908
5134
  }
4909
5135
  try {
4910
5136
  const zcfConfig = readZcfConfig();
4911
- const codeToolType = resolveCodeToolType(options.codeType, zcfConfig?.codeToolType);
5137
+ let codeToolType;
5138
+ try {
5139
+ codeToolType = await resolveCodeType(options.codeType);
5140
+ } catch (error) {
5141
+ const errorMessage = error instanceof Error ? error.message : String(error);
5142
+ console.error(ansis.red(`${i18n.t("errors:generalError")} ${errorMessage}`));
5143
+ codeToolType = DEFAULT_CODE_TOOL_TYPE;
5144
+ }
4912
5145
  options.codeType = codeToolType;
4913
5146
  async function selectApiConfigurationMode() {
4914
5147
  const { apiMode } = await inquirer.prompt({
@@ -4937,6 +5170,11 @@ async function init(options = {}) {
4937
5170
  return apiMode;
4938
5171
  }
4939
5172
  async function handleCustomApiConfiguration(existingConfig) {
5173
+ if (codeToolType === "claude-code") {
5174
+ const { configureIncrementalManagement } = await import('./claude-code-incremental-manager.mjs');
5175
+ await configureIncrementalManagement();
5176
+ return null;
5177
+ }
4940
5178
  if (existingConfig) {
4941
5179
  const customConfigAction = await promptApiConfigurationAction();
4942
5180
  if (customConfigAction === "modify-partial") {
@@ -5002,23 +5240,39 @@ async function init(options = {}) {
5002
5240
  }
5003
5241
  }
5004
5242
  } else {
5005
- if (!configLang && !options.skipPrompt) {
5243
+ if (!configLang) {
5006
5244
  const { resolveTemplateLanguage } = await Promise.resolve().then(function () { return prompts; });
5007
5245
  configLang = await resolveTemplateLanguage(
5008
5246
  options.configLang,
5009
- zcfConfig
5247
+ zcfConfig,
5248
+ options.skipPrompt
5010
5249
  );
5011
- } else if (!configLang && options.skipPrompt) {
5012
- configLang = "en";
5013
5250
  }
5014
5251
  }
5015
5252
  if (!configLang) {
5016
5253
  configLang = "en";
5017
5254
  }
5018
5255
  if (codeToolType === "codex") {
5256
+ const apiMode = options.apiType === "auth_token" ? "official" : options.apiType === "api_key" ? "custom" : options.apiType === "skip" ? "skip" : options.skipPrompt ? "skip" : void 0;
5257
+ const customApiConfig = options.apiType === "api_key" && options.apiKey ? {
5258
+ type: "api_key",
5259
+ token: options.apiKey,
5260
+ baseUrl: options.apiUrl
5261
+ } : void 0;
5262
+ let selectedWorkflows;
5263
+ if (Array.isArray(options.workflows)) {
5264
+ selectedWorkflows = options.workflows;
5265
+ } else if (typeof options.workflows === "string") {
5266
+ selectedWorkflows = [options.workflows];
5267
+ } else if (options.workflows === true) {
5268
+ selectedWorkflows = [];
5269
+ }
5019
5270
  const resolvedAiOutputLang = await runCodexFullInit({
5020
5271
  aiOutputLang: options.aiOutputLang,
5021
- skipPrompt: options.skipPrompt
5272
+ skipPrompt: options.skipPrompt,
5273
+ apiMode,
5274
+ customApiConfig,
5275
+ workflows: selectedWorkflows
5022
5276
  });
5023
5277
  updateZcfConfig({
5024
5278
  version,
@@ -5032,7 +5286,7 @@ async function init(options = {}) {
5032
5286
  console.log(ansis.green(i18n.t("codex:setupComplete")));
5033
5287
  return;
5034
5288
  }
5035
- const aiOutputLang = options.skipPrompt ? options.aiOutputLang || "en" : await resolveAiOutputLanguage(i18n.language, options.aiOutputLang, zcfConfig);
5289
+ const aiOutputLang = await resolveAiOutputLanguage(i18n.language, options.aiOutputLang, zcfConfig, options.skipPrompt);
5036
5290
  const installationStatus = await getInstallationStatus();
5037
5291
  if (installationStatus.hasGlobal || installationStatus.hasLocal) {
5038
5292
  if (!options.skipPrompt) {
@@ -5115,7 +5369,10 @@ async function init(options = {}) {
5115
5369
  const isNewInstall = !existsSync(SETTINGS_FILE);
5116
5370
  if (action !== "docs-only" && (isNewInstall || ["backup", "merge", "new"].includes(action))) {
5117
5371
  if (options.skipPrompt) {
5118
- if (options.apiType === "auth_token" && options.apiKey) {
5372
+ if (options.apiConfigs || options.apiConfigsFile) {
5373
+ await handleMultiConfigurations(options, codeToolType);
5374
+ apiConfig = null;
5375
+ } else if (options.apiType === "auth_token" && options.apiKey) {
5119
5376
  apiConfig = {
5120
5377
  authType: "auth_token",
5121
5378
  key: options.apiKey,
@@ -5355,6 +5612,134 @@ ${ansis.cyan(i18n.t("common:complete"))}`);
5355
5612
  }
5356
5613
  }
5357
5614
  }
5615
+ async function handleMultiConfigurations(options, codeToolType) {
5616
+ const { ensureI18nInitialized } = await Promise.resolve().then(function () { return index; });
5617
+ ensureI18nInitialized();
5618
+ try {
5619
+ let configs = [];
5620
+ if (options.apiConfigs) {
5621
+ try {
5622
+ configs = JSON.parse(options.apiConfigs);
5623
+ } catch (error) {
5624
+ throw new Error(`Invalid API configs JSON: ${error instanceof Error ? error.message : String(error)}`);
5625
+ }
5626
+ }
5627
+ if (options.apiConfigsFile) {
5628
+ try {
5629
+ const { readFile } = await Promise.resolve().then(function () { return fsOperations; });
5630
+ const fileContent = readFile(options.apiConfigsFile);
5631
+ configs = JSON.parse(fileContent);
5632
+ } catch (error) {
5633
+ throw new Error(`Failed to read API configs file: ${error instanceof Error ? error.message : String(error)}`);
5634
+ }
5635
+ }
5636
+ validateApiConfigs(configs);
5637
+ if (codeToolType === "claude-code") {
5638
+ await handleClaudeCodeConfigs(configs);
5639
+ } else if (codeToolType === "codex") {
5640
+ await handleCodexConfigs(configs);
5641
+ }
5642
+ console.log(ansis.green(`\u2714 ${i18n.t("multi-config:configsAddedSuccessfully")}`));
5643
+ } catch (error) {
5644
+ console.error(ansis.red(`${i18n.t("multi-config:configsFailed")}: ${error instanceof Error ? error.message : String(error)}`));
5645
+ throw error;
5646
+ }
5647
+ }
5648
+ function validateApiConfigs(configs) {
5649
+ if (!Array.isArray(configs)) {
5650
+ throw new TypeError("API configs must be an array");
5651
+ }
5652
+ const names = /* @__PURE__ */ new Set();
5653
+ for (const config of configs) {
5654
+ if (!config.name || typeof config.name !== "string" || config.name.trim() === "") {
5655
+ throw new Error("Each config must have a valid name");
5656
+ }
5657
+ if (!["api_key", "auth_token", "ccr_proxy"].includes(config.type)) {
5658
+ throw new Error(`Invalid auth type: ${config.type}`);
5659
+ }
5660
+ if (names.has(config.name)) {
5661
+ throw new Error(`Duplicate config name: ${config.name}`);
5662
+ }
5663
+ names.add(config.name);
5664
+ if (config.type !== "ccr_proxy" && !config.key) {
5665
+ throw new Error(`Config "${config.name}" requires API key`);
5666
+ }
5667
+ }
5668
+ }
5669
+ async function handleClaudeCodeConfigs(configs) {
5670
+ const { ClaudeCodeConfigManager } = await import('./claude-code-config-manager.mjs');
5671
+ const addedProfiles = [];
5672
+ for (const config of configs) {
5673
+ if (config.type === "ccr_proxy") {
5674
+ throw new Error(`CCR proxy type is reserved and cannot be added manually (config: "${config.name}")`);
5675
+ }
5676
+ const profile = await convertToClaudeCodeProfile(config);
5677
+ const result = await ClaudeCodeConfigManager.addProfile(profile);
5678
+ if (!result.success) {
5679
+ throw new Error(`Failed to add profile "${config.name}": ${result.error}`);
5680
+ }
5681
+ const storedProfile = result.addedProfile || ClaudeCodeConfigManager.getProfileByName(config.name) || profile;
5682
+ addedProfiles.push(storedProfile);
5683
+ console.log(ansis.green(`\u2714 ${i18n.t("multi-config:profileAdded", { name: config.name })}`));
5684
+ }
5685
+ if (addedProfiles.length > 0) {
5686
+ const summary = addedProfiles.map((profile) => `${profile.name} [${profile.authType}]`).join(", ");
5687
+ console.log(ansis.gray(` \u2022 ${ClaudeCodeConfigManager.CONFIG_FILE}: ${summary}`));
5688
+ }
5689
+ const defaultConfig = configs.find((c) => c.default);
5690
+ if (defaultConfig) {
5691
+ const profile = addedProfiles.find((p) => p.name === defaultConfig.name) || ClaudeCodeConfigManager.getProfileByName(defaultConfig.name);
5692
+ if (profile && profile.id) {
5693
+ await ClaudeCodeConfigManager.switchProfile(profile.id);
5694
+ await ClaudeCodeConfigManager.applyProfileSettings(profile);
5695
+ console.log(ansis.green(`\u2714 ${i18n.t("multi-config:defaultProfileSet", { name: defaultConfig.name })}`));
5696
+ }
5697
+ }
5698
+ await ClaudeCodeConfigManager.syncCcrProfile();
5699
+ }
5700
+ async function handleCodexConfigs(configs) {
5701
+ const { addProviderToExisting } = await import('./codex-provider-manager.mjs');
5702
+ for (const config of configs) {
5703
+ try {
5704
+ const provider = convertToCodexProvider(config);
5705
+ const result = await addProviderToExisting(provider, config.key || "");
5706
+ if (!result.success) {
5707
+ throw new Error(`Failed to add provider "${config.name}": ${result.error}`);
5708
+ }
5709
+ console.log(ansis.green(`\u2714 ${i18n.t("multi-config:providerAdded", { name: config.name })}`));
5710
+ } catch (error) {
5711
+ console.error(ansis.red(`Failed to add provider "${config.name}": ${error instanceof Error ? error.message : String(error)}`));
5712
+ throw error;
5713
+ }
5714
+ }
5715
+ const defaultConfig = configs.find((c) => c.default);
5716
+ if (defaultConfig) {
5717
+ const { switchCodexProvider } = await Promise.resolve().then(function () { return codex; });
5718
+ await switchCodexProvider(defaultConfig.name);
5719
+ console.log(ansis.green(`\u2714 ${i18n.t("multi-config:defaultProviderSet", { name: defaultConfig.name })}`));
5720
+ }
5721
+ }
5722
+ async function convertToClaudeCodeProfile(config) {
5723
+ const { ClaudeCodeConfigManager } = await import('./claude-code-config-manager.mjs');
5724
+ const profile = {
5725
+ name: config.name,
5726
+ authType: config.type,
5727
+ apiKey: config.key,
5728
+ baseUrl: config.url,
5729
+ id: ClaudeCodeConfigManager.generateProfileId(config.name)
5730
+ };
5731
+ return profile;
5732
+ }
5733
+ function convertToCodexProvider(config) {
5734
+ return {
5735
+ id: config.name.toLowerCase().replace(/[^a-z0-9]/g, "-"),
5736
+ name: config.name,
5737
+ baseUrl: config.url || "https://api.anthropic.com",
5738
+ wireApi: "chat",
5739
+ envKey: "ANTHROPIC_API_KEY",
5740
+ requiresOpenaiAuth: false
5741
+ };
5742
+ }
5358
5743
 
5359
5744
  const __dirname = dirname(fileURLToPath(import.meta.url));
5360
5745
  function getTemplateSettings() {
@@ -5434,4 +5819,4 @@ async function openSettingsJson() {
5434
5819
  }
5435
5820
  }
5436
5821
 
5437
- export { removeLocalClaudeCode as $, AI_OUTPUT_LANGUAGES as A, ensureApiKeyApproved as B, CLAUDE_DIR as C, DEFAULT_CODE_TOOL_TYPE as D, removeApiKeyFromRejected as E, manageApiKeyApproval as F, setPrimaryApiKey as G, ensureClaudeDir as H, backupExistingConfig as I, copyConfigFiles as J, configureApi as K, LEGACY_ZCF_CONFIG_FILES as L, mergeConfigs as M, updateCustomModel as N, updateDefaultModel as O, mergeSettingsFile as P, getExistingModelConfig as Q, getExistingApiConfig as R, SETTINGS_FILE as S, applyAiLanguageDirective as T, switchToOfficialLogin$1 as U, promptApiConfigurationAction as V, isClaudeCodeInstalled as W, installClaudeCode as X, isLocalClaudeCodeInstalled as Y, ZCF_CONFIG_DIR as Z, getInstallationStatus as _, commandExists as a, i18n as a0, readCodexConfig as a1, backupCodexComplete as a2, writeCodexConfig as a3, writeAuthFile as a4, ensureI18nInitialized as a5, detectConfigManagementMode as a6, addNumbersToChoices as a7, readCcrConfig as a8, isCcrInstalled as a9, selectAndInstallWorkflows as aA, checkClaudeCodeVersionAndPrompt as aB, displayBannerWithInfo as aC, runCodexUninstall as aD, configureCodexMcp as aE, configureCodexApi as aF, runCodexWorkflowImport as aG, runCodexFullInit as aH, listCodexProviders as aI, getCurrentCodexProvider as aJ, switchCodexProvider as aK, switchToOfficialLogin as aL, switchToProvider as aM, readZcfConfigAsync as aN, initI18n as aO, selectScriptLanguage as aP, fsOperations as aQ, prompts as aR, codex as aS, installCcr as aa, configureCcrFeature as ab, handleExitPromptError as ac, handleGeneralError as ad, updateZcfConfig as ae, changeLanguage as af, readZcfConfig as ag, configureOutputStyle as ah, isWindows as ai, selectMcpServices as aj, getMcpServices as ak, setupCcrConfiguration as al, modifyApiConfigPartially as am, validateApiKey as an, formatApiKeyDisplay as ao, COMETIX_COMMAND_NAME as ap, COMETIX_COMMANDS as aq, installCometixLine as ar, checkAndUpdateTools as as, readJsonConfig as at, writeJsonConfig as au, displayBanner as av, runCodexUpdate as aw, version as ax, resolveAiOutputLanguage as ay, updatePromptOnly as az, importRecommendedEnv as b, 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, ZCF_CONFIG_FILE as j, CODE_TOOL_TYPES as k, CODE_TOOL_BANNERS as l, mergeAndCleanPermissions as m, isCodeToolType as n, openSettingsJson as o, SUPPORTED_LANGS as p, LANG_LABELS as q, getAiOutputLanguageLabel as r, getMcpConfigPath as s, readMcpConfig as t, backupMcpConfig as u, mergeMcpServers as v, writeMcpConfig as w, buildMcpServerConfig as x, fixWindowsMcpConfig as y, addCompletedOnboarding as z };
5822
+ export { isLocalClaudeCodeInstalled as $, AI_OUTPUT_LANGUAGES as A, fixWindowsMcpConfig as B, CLAUDE_DIR as C, DEFAULT_CODE_TOOL_TYPE as D, addCompletedOnboarding as E, ensureApiKeyApproved as F, removeApiKeyFromRejected as G, manageApiKeyApproval as H, setPrimaryApiKey as I, ensureClaudeDir as J, backupExistingConfig as K, LEGACY_ZCF_CONFIG_FILES as L, copyConfigFiles as M, configureApi as N, mergeConfigs as O, updateCustomModel as P, updateDefaultModel as Q, mergeSettingsFile as R, SETTINGS_FILE as S, getExistingModelConfig as T, getExistingApiConfig as U, applyAiLanguageDirective as V, switchToOfficialLogin$1 as W, promptApiConfigurationAction as X, isClaudeCodeInstalled as Y, ZCF_CONFIG_DIR as Z, installClaudeCode as _, commandExists as a, claudeConfig as a$, getInstallationStatus as a0, removeLocalClaudeCode as a1, ensureI18nInitialized as a2, i18n as a3, addNumbersToChoices as a4, validateApiKey as a5, ensureDir as a6, readDefaultTomlConfig as a7, createDefaultTomlConfig as a8, exists as a9, installCometixLine as aA, checkAndUpdateTools as aB, runCodexUpdate as aC, resolveCodeType as aD, writeJsonConfig as aE, displayBanner as aF, version as aG, resolveAiOutputLanguage as aH, updatePromptOnly as aI, selectAndInstallWorkflows as aJ, checkClaudeCodeVersionAndPrompt as aK, displayBannerWithInfo as aL, runCodexUninstall as aM, configureCodexMcp as aN, configureCodexApi as aO, runCodexWorkflowImportWithLanguageSelection as aP, runCodexFullInit as aQ, switchCodexProvider as aR, listCodexProviders as aS, switchToOfficialLogin as aT, switchToProvider as aU, readZcfConfigAsync as aV, initI18n as aW, selectScriptLanguage as aX, index as aY, fsOperations as aZ, jsonConfig as a_, readJsonConfig as aa, writeTomlConfig as ab, copyFile as ac, detectConfigManagementMode as ad, readCodexConfig as ae, backupCodexComplete as af, writeCodexConfig as ag, writeAuthFile as ah, readCcrConfig as ai, isCcrInstalled as aj, installCcr as ak, configureCcrFeature as al, handleExitPromptError as am, handleGeneralError as an, updateZcfConfig as ao, changeLanguage as ap, readZcfConfig as aq, configureOutputStyle as ar, isWindows as as, selectMcpServices as at, getMcpServices as au, setupCcrConfiguration as av, modifyApiConfigPartially as aw, formatApiKeyDisplay as ax, COMETIX_COMMAND_NAME as ay, COMETIX_COMMANDS as az, importRecommendedEnv as b, config$1 as b0, config as b1, prompts as b2, codex as b3, 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, ZCF_CONFIG_FILE as j, CODE_TOOL_TYPES as k, CODE_TOOL_BANNERS as l, mergeAndCleanPermissions as m, CODE_TOOL_ALIASES as n, openSettingsJson as o, isCodeToolType as p, SUPPORTED_LANGS as q, resolveCodeToolType as r, LANG_LABELS as s, getAiOutputLanguageLabel as t, getMcpConfigPath as u, readMcpConfig as v, writeMcpConfig as w, backupMcpConfig as x, mergeMcpServers as y, buildMcpServerConfig as z };