zcf 3.2.2 → 3.3.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 (40) hide show
  1. package/README.md +131 -24
  2. package/dist/chunks/api-providers.mjs +76 -0
  3. package/dist/chunks/claude-code-config-manager.mjs +21 -7
  4. package/dist/chunks/claude-code-incremental-manager.mjs +59 -17
  5. package/dist/chunks/codex-config-switch.mjs +72 -13
  6. package/dist/chunks/codex-provider-manager.mjs +18 -8
  7. package/dist/chunks/codex-uninstaller.mjs +1 -1
  8. package/dist/chunks/commands.mjs +1 -1
  9. package/dist/chunks/features.mjs +637 -0
  10. package/dist/chunks/simple-config.mjs +192 -40
  11. package/dist/cli.mjs +28 -615
  12. package/dist/i18n/locales/en/api.json +6 -1
  13. package/dist/i18n/locales/en/common.json +0 -1
  14. package/dist/i18n/locales/en/errors.json +2 -1
  15. package/dist/i18n/locales/en/multi-config.json +2 -1
  16. package/dist/i18n/locales/zh-CN/api.json +6 -1
  17. package/dist/i18n/locales/zh-CN/common.json +0 -1
  18. package/dist/i18n/locales/zh-CN/errors.json +2 -1
  19. package/dist/i18n/locales/zh-CN/multi-config.json +2 -1
  20. package/dist/index.d.mts +8 -1
  21. package/dist/index.d.ts +8 -1
  22. package/dist/index.mjs +1 -1
  23. package/package.json +1 -1
  24. package/templates/CLAUDE.md +190 -0
  25. package/templates/claude-code/en/output-styles/engineer-professional.md +2 -1
  26. package/templates/claude-code/en/output-styles/laowang-engineer.md +1 -0
  27. package/templates/claude-code/en/output-styles/nekomata-engineer.md +1 -0
  28. package/templates/claude-code/en/output-styles/ojousama-engineer.md +1 -0
  29. package/templates/claude-code/zh-CN/output-styles/engineer-professional.md +2 -1
  30. package/templates/claude-code/zh-CN/output-styles/laowang-engineer.md +1 -0
  31. package/templates/claude-code/zh-CN/output-styles/nekomata-engineer.md +1 -0
  32. package/templates/claude-code/zh-CN/output-styles/ojousama-engineer.md +1 -0
  33. package/templates/codex/en/system-prompt/engineer-professional.md +2 -1
  34. package/templates/codex/en/system-prompt/laowang-engineer.md +1 -0
  35. package/templates/codex/en/system-prompt/nekomata-engineer.md +1 -0
  36. package/templates/codex/en/system-prompt/ojousama-engineer.md +1 -0
  37. package/templates/codex/zh-CN/system-prompt/engineer-professional.md +2 -1
  38. package/templates/codex/zh-CN/system-prompt/laowang-engineer.md +1 -0
  39. package/templates/codex/zh-CN/system-prompt/nekomata-engineer.md +1 -0
  40. package/templates/codex/zh-CN/system-prompt/ojousama-engineer.md +1 -0
@@ -16,7 +16,7 @@ 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.2.2";
19
+ const version = "3.3.0";
20
20
  const homepage = "https://github.com/UfoMiao/zcf";
21
21
 
22
22
  const i18n = i18next.createInstance();
@@ -1666,9 +1666,9 @@ async function configureCcrWithPreset(preset) {
1666
1666
  if (preset.requiresApiKey) {
1667
1667
  try {
1668
1668
  const { apiKey } = await inquirer.prompt({
1669
- type: "password",
1669
+ type: "input",
1670
1670
  name: "apiKey",
1671
- message: i18n.t("ccr:enterApiKeyForProvider").replace("{provider}", preset.name) + i18n.t("common:inputHidden"),
1671
+ message: i18n.t("ccr:enterApiKeyForProvider").replace("{provider}", preset.name),
1672
1672
  validate: async (value) => !!value || i18n.t("api:keyRequired")
1673
1673
  });
1674
1674
  provider.api_key = apiKey;
@@ -2867,9 +2867,9 @@ async function configureCodexMcp(options) {
2867
2867
  if (configInfo.requiresApiKey && configInfo.apiKeyEnvVar) {
2868
2868
  const promptMessage = serviceMeta?.apiKeyPrompt || i18n.t("mcp:apiKeyPrompt");
2869
2869
  const { apiKey } = await inquirer.prompt([{
2870
- type: "password",
2870
+ type: "input",
2871
2871
  name: "apiKey",
2872
- message: promptMessage + i18n.t("common:inputHidden"),
2872
+ message: promptMessage,
2873
2873
  validate: (input) => !!input || i18n.t("api:keyRequired")
2874
2874
  }]);
2875
2875
  if (!apiKey)
@@ -3032,7 +3032,7 @@ function sanitizeProviderName(input) {
3032
3032
  const cleaned = input.trim();
3033
3033
  if (!cleaned)
3034
3034
  return "";
3035
- return cleaned.replace(/[^\w.-]/g, "");
3035
+ return cleaned.toLowerCase().replace(/\./g, "-").replace(/\s+/g, "-").replace(/[^a-z0-9\-]/g, "");
3036
3036
  }
3037
3037
  function parseCodexConfig(content) {
3038
3038
  if (!content.trim()) {
@@ -3061,7 +3061,9 @@ function parseCodexConfig(content) {
3061
3061
  baseUrl: provider.base_url || "",
3062
3062
  wireApi: provider.wire_api || "responses",
3063
3063
  envKey: provider.env_key || "OPENAI_API_KEY",
3064
- requiresOpenaiAuth: provider.requires_openai_auth !== false
3064
+ requiresOpenaiAuth: provider.requires_openai_auth !== false,
3065
+ model: provider.model || void 0
3066
+ // Parse model field from provider
3065
3067
  });
3066
3068
  }
3067
3069
  }
@@ -3211,7 +3213,7 @@ function renderCodexConfig(data) {
3211
3213
  return false;
3212
3214
  if (/^#?\s*model_provider\s*=/.test(l))
3213
3215
  return false;
3214
- if (/^\s*model\s*=/.test(l))
3216
+ if (/^\s*model\s*=/.test(l) && !l.includes("["))
3215
3217
  return false;
3216
3218
  return true;
3217
3219
  });
@@ -3231,6 +3233,9 @@ function renderCodexConfig(data) {
3231
3233
  lines.push(`wire_api = "${provider.wireApi}"`);
3232
3234
  lines.push(`env_key = "${provider.envKey}"`);
3233
3235
  lines.push(`requires_openai_auth = ${provider.requiresOpenaiAuth}`);
3236
+ if (provider.model) {
3237
+ lines.push(`model = "${provider.model}"`);
3238
+ }
3234
3239
  }
3235
3240
  }
3236
3241
  if (data.mcpServices.length > 0) {
@@ -3710,12 +3715,36 @@ async function configureCodexApi(options) {
3710
3715
  const existingValues = existingMap.size ? Array.from(existingMap.values()) : [];
3711
3716
  const firstExisting = existingValues.length === 1 ? existingValues[0] : void 0;
3712
3717
  while (addMore) {
3718
+ const { getApiProviders } = await import('./api-providers.mjs');
3719
+ const apiProviders = getApiProviders("codex");
3720
+ const providerChoices = [
3721
+ { name: i18n.t("api:customProvider"), value: "custom" },
3722
+ ...apiProviders.map((p) => ({ name: p.name, value: p.id }))
3723
+ ];
3724
+ const { selectedProvider: selectedProvider2 } = await inquirer.prompt([{
3725
+ type: "list",
3726
+ name: "selectedProvider",
3727
+ message: i18n.t("api:selectApiProvider"),
3728
+ choices: addNumbersToChoices(providerChoices)
3729
+ }]);
3730
+ let prefilledBaseUrl;
3731
+ let prefilledWireApi;
3732
+ let prefilledModel;
3733
+ if (selectedProvider2 !== "custom") {
3734
+ const provider = apiProviders.find((p) => p.id === selectedProvider2);
3735
+ if (provider?.codex) {
3736
+ prefilledBaseUrl = provider.codex.baseUrl;
3737
+ prefilledWireApi = provider.codex.wireApi;
3738
+ prefilledModel = provider.codex.defaultModel;
3739
+ console.log(ansis.gray(i18n.t("api:providerSelected", { name: provider.name })));
3740
+ }
3741
+ }
3713
3742
  const answers = await inquirer.prompt([
3714
3743
  {
3715
3744
  type: "input",
3716
3745
  name: "providerName",
3717
3746
  message: i18n.t("codex:providerNamePrompt"),
3718
- default: firstExisting?.name,
3747
+ default: selectedProvider2 !== "custom" ? apiProviders.find((p) => p.id === selectedProvider2)?.name : firstExisting?.name,
3719
3748
  validate: (input) => {
3720
3749
  const sanitized = sanitizeProviderName(input);
3721
3750
  if (!sanitized)
@@ -3729,7 +3758,8 @@ async function configureCodexApi(options) {
3729
3758
  type: "input",
3730
3759
  name: "baseUrl",
3731
3760
  message: i18n.t("codex:providerBaseUrlPrompt"),
3732
- default: (answers2) => existingMap.get(answers2.providerId)?.baseUrl || "https://api.openai.com/v1",
3761
+ default: prefilledBaseUrl || ((answers2) => existingMap.get(answers2.providerId)?.baseUrl || "https://api.openai.com/v1"),
3762
+ when: () => selectedProvider2 === "custom",
3733
3763
  validate: (input) => !!input || i18n.t("codex:providerBaseUrlRequired")
3734
3764
  },
3735
3765
  {
@@ -3740,15 +3770,29 @@ async function configureCodexApi(options) {
3740
3770
  { name: i18n.t("codex:protocolResponses"), value: "responses" },
3741
3771
  { name: i18n.t("codex:protocolChat"), value: "chat" }
3742
3772
  ],
3743
- default: (answers2) => existingMap.get(sanitizeProviderName(answers2.providerName))?.wireApi || "responses"
3773
+ default: prefilledWireApi || ((answers2) => existingMap.get(sanitizeProviderName(answers2.providerName))?.wireApi || "responses"),
3774
+ when: () => selectedProvider2 === "custom"
3775
+ // Only ask if custom
3744
3776
  },
3745
3777
  {
3746
- type: "password",
3778
+ type: "input",
3747
3779
  name: "apiKey",
3748
- message: i18n.t("codex:providerApiKeyPrompt") + i18n.t("common:inputHidden"),
3780
+ message: selectedProvider2 !== "custom" ? i18n.t("api:enterProviderApiKey", { provider: apiProviders.find((p) => p.id === selectedProvider2)?.name || selectedProvider2 }) : i18n.t("codex:providerApiKeyPrompt"),
3749
3781
  validate: (input) => !!input || i18n.t("codex:providerApiKeyRequired")
3750
3782
  }
3751
3783
  ]);
3784
+ let customModel;
3785
+ if (selectedProvider2 === "custom") {
3786
+ const { model } = await inquirer.prompt([{
3787
+ type: "input",
3788
+ name: "model",
3789
+ message: `${i18n.t("configuration:enterCustomModel")}${i18n.t("common:emptyToSkip")}`,
3790
+ default: "gpt-5-codex"
3791
+ }]);
3792
+ if (model.trim()) {
3793
+ customModel = model.trim();
3794
+ }
3795
+ }
3752
3796
  const providerId = sanitizeProviderName(answers.providerName);
3753
3797
  const envKey = `${providerId.toUpperCase().replace(/-/g, "_")}_API_KEY`;
3754
3798
  const existingProvider = existingMap.get(providerId);
@@ -3780,10 +3824,12 @@ async function configureCodexApi(options) {
3780
3824
  const newProvider = {
3781
3825
  id: providerId,
3782
3826
  name: answers.providerName,
3783
- baseUrl: answers.baseUrl,
3784
- wireApi: answers.wireApi || "responses",
3827
+ baseUrl: selectedProvider2 === "custom" ? answers.baseUrl : prefilledBaseUrl,
3828
+ wireApi: selectedProvider2 === "custom" ? answers.wireApi || "responses" : prefilledWireApi,
3785
3829
  envKey,
3786
- requiresOpenaiAuth: true
3830
+ requiresOpenaiAuth: true,
3831
+ model: customModel || prefilledModel || "gpt-5-codex"
3832
+ // Use custom model, provider's default model, or fallback
3787
3833
  };
3788
3834
  providers.push(newProvider);
3789
3835
  currentSessionProviders.set(providerId, newProvider);
@@ -4078,8 +4124,18 @@ async function switchToProvider(providerId) {
4078
4124
  console.log(ansis.gray(getBackupMessage(backupPath)));
4079
4125
  }
4080
4126
  try {
4127
+ let targetModel = existingConfig.model;
4128
+ if (provider.model) {
4129
+ targetModel = provider.model;
4130
+ } else {
4131
+ const currentModel = existingConfig.model;
4132
+ if (currentModel !== "gpt-5" && currentModel !== "gpt-5-codex") {
4133
+ targetModel = "gpt-5-codex";
4134
+ }
4135
+ }
4081
4136
  const updatedConfig = {
4082
4137
  ...existingConfig,
4138
+ model: targetModel,
4083
4139
  modelProvider: providerId,
4084
4140
  modelProviderCommented: false
4085
4141
  // Ensure it's not commented
@@ -4147,12 +4203,16 @@ async function resolveCodeType(codeTypeParam) {
4147
4203
  const validAbbreviations = Object.keys(CODE_TYPE_ABBREVIATIONS);
4148
4204
  const validFullTypes = Object.values(CODE_TYPE_ABBREVIATIONS);
4149
4205
  const validOptions = [...validAbbreviations, ...validFullTypes].join(", ");
4206
+ let defaultValue = DEFAULT_CODE_TOOL_TYPE;
4207
+ try {
4208
+ const config = await readZcfConfigAsync();
4209
+ if (config?.codeToolType && isValidCodeType(config.codeToolType)) {
4210
+ defaultValue = config.codeToolType;
4211
+ }
4212
+ } catch {
4213
+ }
4150
4214
  throw new Error(
4151
- i18n.t(
4152
- "errors:invalidCodeType",
4153
- `Invalid code type: "${codeTypeParam}". Valid options are: ${validOptions}.`,
4154
- { value: codeTypeParam, validOptions }
4155
- )
4215
+ i18n.t("errors:invalidCodeType", { value: codeTypeParam, validOptions, defaultValue })
4156
4216
  );
4157
4217
  }
4158
4218
  try {
@@ -4544,9 +4604,9 @@ async function configureApiCompletely(preselectedAuthType) {
4544
4604
  console.log(ansis.yellow(i18n.t("common:cancelled")));
4545
4605
  return null;
4546
4606
  }
4547
- const keyMessage = authType === "auth_token" ? i18n.t("api:enterAuthToken") + i18n.t("common:inputHidden") : i18n.t("api:enterApiKey") + i18n.t("common:inputHidden");
4607
+ const keyMessage = authType === "auth_token" ? i18n.t("api:enterAuthToken") : i18n.t("api:enterApiKey");
4548
4608
  const { key } = await inquirer.prompt({
4549
- type: "password",
4609
+ type: "input",
4550
4610
  name: "key",
4551
4611
  message: keyMessage,
4552
4612
  validate: async (value) => {
@@ -4617,9 +4677,9 @@ async function modifyApiConfigPartially(existingConfig) {
4617
4677
  }
4618
4678
  } else if (item === "key") {
4619
4679
  const authType = currentConfig.authType || "auth_token";
4620
- const keyMessage = authType === "auth_token" ? i18n.t("api:enterNewApiKey").replace("{key}", currentConfig.key ? formatApiKeyDisplay(currentConfig.key) : i18n.t("common:none")) + i18n.t("common:inputHidden") : i18n.t("api:enterNewApiKey").replace("{key}", currentConfig.key ? formatApiKeyDisplay(currentConfig.key) : i18n.t("common:none")) + i18n.t("common:inputHidden");
4680
+ const keyMessage = authType === "auth_token" ? i18n.t("api:enterNewApiKey").replace("{key}", currentConfig.key ? formatApiKeyDisplay(currentConfig.key) : i18n.t("common:none")) : i18n.t("api:enterNewApiKey").replace("{key}", currentConfig.key ? formatApiKeyDisplay(currentConfig.key) : i18n.t("common:none"));
4621
4681
  const { key } = await inquirer.prompt({
4622
- type: "password",
4682
+ type: "input",
4623
4683
  name: "key",
4624
4684
  message: keyMessage,
4625
4685
  validate: async (value) => {
@@ -4708,6 +4768,7 @@ async function installClaudeCode() {
4708
4768
  if (installed) {
4709
4769
  console.log(ansis.green(`\u2714 ${i18n.t("installation:alreadyInstalled")}`));
4710
4770
  await updateClaudeCode();
4771
+ await setInstallMethod("npm");
4711
4772
  return;
4712
4773
  }
4713
4774
  if (isTermux()) {
@@ -4730,6 +4791,7 @@ async function installClaudeCode() {
4730
4791
  try {
4731
4792
  await exec("npm", ["install", "-g", "@anthropic-ai/claude-code"]);
4732
4793
  console.log(`\u2714 ${i18n.t("installation:installSuccess")}`);
4794
+ await setInstallMethod("npm");
4733
4795
  if (isTermux()) {
4734
4796
  console.log(ansis.gray(`
4735
4797
  Claude Code installed to: ${getTermuxPrefix()}/bin/claude`));
@@ -4779,6 +4841,19 @@ async function removeLocalClaudeCode() {
4779
4841
  throw new Error(`${i18n.t("installation:failedToRemoveLocalInstallation")}: ${error}`);
4780
4842
  }
4781
4843
  }
4844
+ async function setInstallMethod(method = "npm") {
4845
+ try {
4846
+ const { readMcpConfig, writeMcpConfig } = await Promise.resolve().then(function () { return claudeConfig; });
4847
+ let config = readMcpConfig();
4848
+ if (!config) {
4849
+ config = { mcpServers: {} };
4850
+ }
4851
+ config.installMethod = method;
4852
+ writeMcpConfig(config);
4853
+ } catch (error) {
4854
+ console.error("Failed to set installMethod in ~/.claude.json:", error);
4855
+ }
4856
+ }
4782
4857
 
4783
4858
  const installer = {
4784
4859
  __proto__: null,
@@ -4786,7 +4861,8 @@ const installer = {
4786
4861
  installClaudeCode: installClaudeCode,
4787
4862
  isClaudeCodeInstalled: isClaudeCodeInstalled,
4788
4863
  isLocalClaudeCodeInstalled: isLocalClaudeCodeInstalled,
4789
- removeLocalClaudeCode: removeLocalClaudeCode
4864
+ removeLocalClaudeCode: removeLocalClaudeCode,
4865
+ setInstallMethod: setInstallMethod
4790
4866
  };
4791
4867
 
4792
4868
  async function chooseInstallationMethod() {
@@ -5051,7 +5127,7 @@ async function cleanupOldVersionFiles() {
5051
5127
  }
5052
5128
  }
5053
5129
 
5054
- function validateSkipPromptOptions(options) {
5130
+ async function validateSkipPromptOptions(options) {
5055
5131
  if (options.allLang) {
5056
5132
  if (options.allLang === "zh-CN" || options.allLang === "en") {
5057
5133
  options.configLang = options.allLang;
@@ -5061,6 +5137,22 @@ function validateSkipPromptOptions(options) {
5061
5137
  options.aiOutputLang = options.allLang;
5062
5138
  }
5063
5139
  }
5140
+ if (options.provider) {
5141
+ const { getValidProviderIds, getProviderPreset } = await import('./api-providers.mjs');
5142
+ const validProviders = [...getValidProviderIds(), "custom"];
5143
+ if (!validProviders.includes(options.provider)) {
5144
+ throw new Error(
5145
+ i18n.t("errors:invalidProvider", {
5146
+ provider: options.provider,
5147
+ validProviders: validProviders.join(", ")
5148
+ })
5149
+ );
5150
+ }
5151
+ if (!options.apiType) {
5152
+ const preset = options.provider !== "custom" ? getProviderPreset(options.provider) : null;
5153
+ options.apiType = preset?.claudeCode?.authType || "api_key";
5154
+ }
5155
+ }
5064
5156
  if (!options.configAction) {
5065
5157
  options.configAction = "backup";
5066
5158
  }
@@ -5173,7 +5265,7 @@ function validateSkipPromptOptions(options) {
5173
5265
  }
5174
5266
  async function init(options = {}) {
5175
5267
  if (options.skipPrompt) {
5176
- validateSkipPromptOptions(options);
5268
+ await validateSkipPromptOptions(options);
5177
5269
  }
5178
5270
  try {
5179
5271
  const zcfConfig = readZcfConfig();
@@ -5417,6 +5509,18 @@ async function init(options = {}) {
5417
5509
  if (options.apiConfigs || options.apiConfigsFile) {
5418
5510
  await handleMultiConfigurations(options, codeToolType);
5419
5511
  apiConfig = null;
5512
+ } else if (options.provider && options.apiKey) {
5513
+ const { getProviderPreset } = await import('./api-providers.mjs');
5514
+ const preset = options.provider !== "custom" ? getProviderPreset(options.provider) : null;
5515
+ apiConfig = {
5516
+ authType: preset?.claudeCode?.authType || "api_key",
5517
+ key: options.apiKey,
5518
+ url: preset?.claudeCode?.baseUrl || options.apiUrl || API_DEFAULT_URL
5519
+ };
5520
+ if (preset?.claudeCode?.defaultModels && preset.claudeCode.defaultModels.length >= 2) {
5521
+ options.apiModel = options.apiModel || preset.claudeCode.defaultModels[0];
5522
+ options.apiFastModel = options.apiFastModel || preset.claudeCode.defaultModels[1];
5523
+ }
5420
5524
  } else if (options.apiType === "auth_token" && options.apiKey) {
5421
5525
  apiConfig = {
5422
5526
  authType: "auth_token",
@@ -5613,9 +5717,9 @@ async function init(options = {}) {
5613
5717
  continue;
5614
5718
  } else {
5615
5719
  const response = await inquirer.prompt({
5616
- type: "password",
5720
+ type: "input",
5617
5721
  name: "apiKey",
5618
- message: service.apiKeyPrompt + i18n.t("common:inputHidden"),
5722
+ message: service.apiKeyPrompt,
5619
5723
  validate: (value) => !!value || i18n.t("api:keyRequired")
5620
5724
  });
5621
5725
  if (!response.apiKey) {
@@ -5704,7 +5808,7 @@ async function handleMultiConfigurations(options, codeToolType) {
5704
5808
  throw new Error(i18n.t("multi-config:fileReadFailed", { error: error instanceof Error ? error.message : String(error) }));
5705
5809
  }
5706
5810
  }
5707
- validateApiConfigs(configs);
5811
+ await validateApiConfigs(configs);
5708
5812
  if (codeToolType === "claude-code") {
5709
5813
  await handleClaudeCodeConfigs(configs);
5710
5814
  } else if (codeToolType === "codex") {
@@ -5716,12 +5820,29 @@ async function handleMultiConfigurations(options, codeToolType) {
5716
5820
  throw error;
5717
5821
  }
5718
5822
  }
5719
- function validateApiConfigs(configs) {
5823
+ async function validateApiConfigs(configs) {
5720
5824
  if (!Array.isArray(configs)) {
5721
5825
  throw new TypeError(i18n.t("multi-config:mustBeArray"));
5722
5826
  }
5827
+ const { getValidProviderIds } = await import('./api-providers.mjs');
5828
+ const validProviders = [...getValidProviderIds(), "custom"];
5723
5829
  const names = /* @__PURE__ */ new Set();
5724
5830
  for (const config of configs) {
5831
+ if (config.provider && !config.type) {
5832
+ config.type = "api_key";
5833
+ }
5834
+ if (config.provider && !config.name) {
5835
+ config.name = config.provider.toUpperCase();
5836
+ }
5837
+ if (!config.provider && !config.type) {
5838
+ throw new Error(i18n.t("multi-config:providerOrTypeRequired"));
5839
+ }
5840
+ if (config.provider && !validProviders.includes(config.provider)) {
5841
+ throw new Error(i18n.t("errors:invalidProvider", {
5842
+ provider: config.provider,
5843
+ validProviders: validProviders.join(", ")
5844
+ }));
5845
+ }
5725
5846
  if (!config.name || typeof config.name !== "string" || config.name.trim() === "") {
5726
5847
  throw new Error(i18n.t("multi-config:mustHaveValidName"));
5727
5848
  }
@@ -5772,7 +5893,7 @@ async function handleCodexConfigs(configs) {
5772
5893
  const { addProviderToExisting } = await import('./codex-provider-manager.mjs');
5773
5894
  for (const config of configs) {
5774
5895
  try {
5775
- const provider = convertToCodexProvider(config);
5896
+ const provider = await convertToCodexProvider(config);
5776
5897
  const result = await addProviderToExisting(provider, config.key || "");
5777
5898
  if (!result.success) {
5778
5899
  throw new Error(i18n.t("multi-config:providerAddFailed", { name: config.name, error: result.error }));
@@ -5795,23 +5916,54 @@ async function handleCodexConfigs(configs) {
5795
5916
  }
5796
5917
  async function convertToClaudeCodeProfile(config) {
5797
5918
  const { ClaudeCodeConfigManager } = await import('./claude-code-config-manager.mjs');
5919
+ let baseUrl = config.url;
5920
+ let primaryModel = config.primaryModel;
5921
+ let fastModel = config.fastModel;
5922
+ let authType = config.type || "api_key";
5923
+ if (config.provider && config.provider !== "custom") {
5924
+ const { getProviderPreset } = await import('./api-providers.mjs');
5925
+ const preset = getProviderPreset(config.provider);
5926
+ if (preset?.claudeCode) {
5927
+ baseUrl = baseUrl || preset.claudeCode.baseUrl;
5928
+ authType = preset.claudeCode.authType;
5929
+ if (preset.claudeCode.defaultModels && preset.claudeCode.defaultModels.length >= 2) {
5930
+ primaryModel = primaryModel || preset.claudeCode.defaultModels[0];
5931
+ fastModel = fastModel || preset.claudeCode.defaultModels[1];
5932
+ }
5933
+ }
5934
+ }
5798
5935
  const profile = {
5799
5936
  name: config.name,
5800
- authType: config.type,
5937
+ authType,
5801
5938
  apiKey: config.key,
5802
- baseUrl: config.url,
5939
+ baseUrl,
5940
+ primaryModel,
5941
+ fastModel,
5803
5942
  id: ClaudeCodeConfigManager.generateProfileId(config.name)
5804
5943
  };
5805
5944
  return profile;
5806
5945
  }
5807
- function convertToCodexProvider(config) {
5946
+ async function convertToCodexProvider(config) {
5947
+ let baseUrl = config.url || API_DEFAULT_URL;
5948
+ let model = config.primaryModel || "gpt-5-codex";
5949
+ let wireApi = "chat";
5950
+ if (config.provider && config.provider !== "custom") {
5951
+ const { getProviderPreset } = await import('./api-providers.mjs');
5952
+ const preset = getProviderPreset(config.provider);
5953
+ if (preset?.codex) {
5954
+ baseUrl = config.url || preset.codex.baseUrl;
5955
+ model = config.primaryModel || preset.codex.defaultModel || model;
5956
+ wireApi = preset.codex.wireApi;
5957
+ }
5958
+ }
5808
5959
  return {
5809
5960
  id: config.name.toLowerCase().replace(/[^a-z0-9]/g, "-"),
5810
5961
  name: config.name,
5811
- baseUrl: config.url || API_DEFAULT_URL,
5812
- wireApi: "chat",
5962
+ baseUrl,
5963
+ wireApi,
5813
5964
  envKey: API_ENV_KEY,
5814
- requiresOpenaiAuth: false
5965
+ requiresOpenaiAuth: false,
5966
+ model
5815
5967
  };
5816
5968
  }
5817
5969
 
@@ -5893,4 +6045,4 @@ async function openSettingsJson() {
5893
6045
  }
5894
6046
  }
5895
6047
 
5896
- export { isClaudeCodeInstalled as $, API_DEFAULT_URL as A, mergeMcpServers as B, CLAUDE_DIR as C, DEFAULT_CODE_TOOL_TYPE as D, buildMcpServerConfig as E, fixWindowsMcpConfig as F, addCompletedOnboarding as G, ensureApiKeyApproved as H, removeApiKeyFromRejected as I, manageApiKeyApproval as J, setPrimaryApiKey as K, LEGACY_ZCF_CONFIG_FILES as L, ensureClaudeDir as M, backupExistingConfig as N, copyConfigFiles as O, configureApi as P, mergeConfigs as Q, updateCustomModel as R, SETTINGS_FILE as S, updateDefaultModel as T, mergeSettingsFile as U, getExistingModelConfig as V, getExistingApiConfig as W, applyAiLanguageDirective as X, switchToOfficialLogin$1 as Y, ZCF_CONFIG_DIR as Z, promptApiConfigurationAction as _, commandExists as a, fsOperations as a$, installClaudeCode as a0, isLocalClaudeCodeInstalled as a1, getInstallationStatus as a2, removeLocalClaudeCode as a3, ensureI18nInitialized as a4, i18n as a5, addNumbersToChoices as a6, validateApiKey as a7, ensureDir as a8, readDefaultTomlConfig as a9, COMETIX_COMMAND_NAME as aA, COMETIX_COMMANDS as aB, installCometixLine as aC, checkAndUpdateTools as aD, runCodexUpdate as aE, resolveCodeType as aF, writeJsonConfig as aG, displayBanner as aH, version as aI, resolveAiOutputLanguage as aJ, updatePromptOnly as aK, selectAndInstallWorkflows as aL, checkClaudeCodeVersionAndPrompt as aM, displayBannerWithInfo as aN, runCodexUninstall as aO, configureCodexMcp as aP, configureCodexApi as aQ, runCodexWorkflowImportWithLanguageSelection as aR, runCodexFullInit as aS, switchCodexProvider as aT, listCodexProviders as aU, switchToOfficialLogin as aV, switchToProvider as aW, readZcfConfigAsync as aX, initI18n as aY, selectScriptLanguage as aZ, index as a_, createDefaultTomlConfig as aa, exists as ab, readJsonConfig as ac, writeTomlConfig as ad, copyFile as ae, detectConfigManagementMode as af, readCodexConfig as ag, backupCodexComplete as ah, writeCodexConfig as ai, writeAuthFile as aj, readCcrConfig as ak, isCcrInstalled as al, installCcr as am, configureCcrFeature as an, handleExitPromptError as ao, handleGeneralError as ap, updateZcfConfig as aq, changeLanguage as ar, readZcfConfig as as, configureOutputStyle as at, isWindows as au, selectMcpServices as av, getMcpServices as aw, setupCcrConfiguration as ax, modifyApiConfigPartially as ay, formatApiKeyDisplay as az, importRecommendedEnv as b, jsonConfig as b0, claudeConfig as b1, config$1 as b2, config as b3, prompts as b4, codex as b5, 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, API_ENV_KEY as q, resolveCodeToolType as r, SUPPORTED_LANGS as s, LANG_LABELS as t, AI_OUTPUT_LANGUAGES as u, getAiOutputLanguageLabel as v, getMcpConfigPath as w, readMcpConfig as x, writeMcpConfig as y, backupMcpConfig as z };
6048
+ export { isClaudeCodeInstalled as $, API_DEFAULT_URL as A, mergeMcpServers as B, CLAUDE_DIR as C, DEFAULT_CODE_TOOL_TYPE as D, buildMcpServerConfig as E, fixWindowsMcpConfig as F, addCompletedOnboarding as G, ensureApiKeyApproved as H, removeApiKeyFromRejected as I, manageApiKeyApproval as J, setPrimaryApiKey as K, LEGACY_ZCF_CONFIG_FILES as L, ensureClaudeDir as M, backupExistingConfig as N, copyConfigFiles as O, configureApi as P, mergeConfigs as Q, updateCustomModel as R, SETTINGS_FILE as S, updateDefaultModel as T, mergeSettingsFile as U, getExistingModelConfig as V, getExistingApiConfig as W, applyAiLanguageDirective as X, switchToOfficialLogin$1 as Y, ZCF_CONFIG_DIR as Z, promptApiConfigurationAction as _, commandExists as a, index as a$, installClaudeCode as a0, isLocalClaudeCodeInstalled as a1, getInstallationStatus as a2, removeLocalClaudeCode as a3, setInstallMethod as a4, ensureI18nInitialized as a5, i18n as a6, addNumbersToChoices as a7, validateApiKey as a8, ensureDir as a9, handleGeneralError as aA, COMETIX_COMMAND_NAME as aB, COMETIX_COMMANDS as aC, installCometixLine as aD, checkAndUpdateTools as aE, runCodexUpdate as aF, resolveCodeType as aG, writeJsonConfig as aH, displayBanner as aI, version as aJ, resolveAiOutputLanguage as aK, updatePromptOnly as aL, selectAndInstallWorkflows as aM, checkClaudeCodeVersionAndPrompt as aN, displayBannerWithInfo as aO, runCodexUninstall as aP, configureCodexMcp as aQ, configureCodexApi as aR, runCodexWorkflowImportWithLanguageSelection as aS, runCodexFullInit as aT, switchCodexProvider as aU, listCodexProviders as aV, switchToOfficialLogin as aW, switchToProvider as aX, readZcfConfigAsync as aY, initI18n as aZ, selectScriptLanguage as a_, readDefaultTomlConfig as aa, createDefaultTomlConfig as ab, exists as ac, readJsonConfig as ad, writeTomlConfig as ae, copyFile as af, detectConfigManagementMode as ag, readCodexConfig as ah, backupCodexComplete as ai, writeCodexConfig as aj, writeAuthFile as ak, updateZcfConfig as al, changeLanguage as am, readZcfConfig as an, configureOutputStyle as ao, isWindows as ap, selectMcpServices as aq, getMcpServices as ar, isCcrInstalled as as, installCcr as at, setupCcrConfiguration as au, modifyApiConfigPartially as av, formatApiKeyDisplay as aw, readCcrConfig as ax, configureCcrFeature as ay, handleExitPromptError as az, importRecommendedEnv as b, fsOperations as b0, jsonConfig as b1, claudeConfig as b2, config$1 as b3, config as b4, prompts as b5, codex as b6, 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, API_ENV_KEY as q, resolveCodeToolType as r, SUPPORTED_LANGS as s, LANG_LABELS as t, AI_OUTPUT_LANGUAGES as u, getAiOutputLanguageLabel as v, getMcpConfigPath as w, readMcpConfig as x, writeMcpConfig as y, backupMcpConfig as z };