zcf 3.1.2 → 3.1.4

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.
@@ -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.1.2";
19
+ const version = "3.1.4";
20
20
  const homepage = "https://github.com/UfoMiao/zcf";
21
21
 
22
22
  const i18n = i18next.createInstance();
@@ -543,11 +543,15 @@ function getMcpCommand() {
543
543
  return ["npx"];
544
544
  }
545
545
  function getSystemRoot() {
546
- if (isWindows()) {
547
- const systemRoot = process.env.SYSTEMROOT || process.env.SystemRoot || "C:Windows";
548
- return systemRoot.replace(/\\/g, "\\\\");
549
- }
550
- return null;
546
+ if (!isWindows())
547
+ return null;
548
+ const env = process.env;
549
+ let systemRoot = "C:\\Windows";
550
+ if (Object.prototype.hasOwnProperty.call(env, "SYSTEMROOT") && env.SYSTEMROOT)
551
+ systemRoot = env.SYSTEMROOT;
552
+ else if (Object.prototype.hasOwnProperty.call(env, "SystemRoot") && env.SystemRoot)
553
+ systemRoot = env.SystemRoot;
554
+ return systemRoot.replace(/\\+/g, "/").replace(/\/+/g, "/");
551
555
  }
552
556
  async function commandExists(command) {
553
557
  try {
@@ -2494,12 +2498,15 @@ async function selectScriptLanguage(currentLang) {
2494
2498
  });
2495
2499
  return scriptLang;
2496
2500
  }
2497
- async function resolveAiOutputLanguage(scriptLang, commandLineOption, savedConfig) {
2501
+ async function resolveAiOutputLanguage(scriptLang, commandLineOption, savedConfig, skipPrompt) {
2498
2502
  ensureI18nInitialized();
2499
2503
  if (commandLineOption) {
2500
2504
  return commandLineOption;
2501
2505
  }
2502
2506
  if (savedConfig?.aiOutputLang) {
2507
+ if (skipPrompt) {
2508
+ return savedConfig.aiOutputLang;
2509
+ }
2503
2510
  const currentLanguageLabel = getAiOutputLanguageLabel(savedConfig.aiOutputLang) || savedConfig.aiOutputLang;
2504
2511
  console.log(ansis.blue(`${i18n.t("language:currentConfigFound")}: ${currentLanguageLabel}`));
2505
2512
  const { shouldModify } = await inquirer.prompt({
@@ -2518,6 +2525,9 @@ async function resolveAiOutputLanguage(scriptLang, commandLineOption, savedConfi
2518
2525
  }
2519
2526
  return await selectAiOutputLanguage(scriptLang);
2520
2527
  }
2528
+ if (skipPrompt) {
2529
+ return scriptLang;
2530
+ }
2521
2531
  return await selectAiOutputLanguage(scriptLang);
2522
2532
  }
2523
2533
  async function selectTemplateLanguage() {
@@ -2543,12 +2553,15 @@ async function selectTemplateLanguage() {
2543
2553
  }
2544
2554
  return lang;
2545
2555
  }
2546
- async function resolveTemplateLanguage(commandLineOption, savedConfig) {
2556
+ async function resolveTemplateLanguage(commandLineOption, savedConfig, skipPrompt) {
2547
2557
  ensureI18nInitialized();
2548
2558
  if (commandLineOption) {
2549
2559
  return commandLineOption;
2550
2560
  }
2551
2561
  if (savedConfig?.templateLang) {
2562
+ if (skipPrompt) {
2563
+ return savedConfig.templateLang;
2564
+ }
2552
2565
  const currentLanguageLabel = LANG_LABELS[savedConfig.templateLang];
2553
2566
  console.log(ansis.blue(`${i18n.t("language:currentTemplateLanguageFound")}: ${currentLanguageLabel}`));
2554
2567
  const { shouldModify } = await inquirer.prompt({
@@ -2568,6 +2581,9 @@ async function resolveTemplateLanguage(commandLineOption, savedConfig) {
2568
2581
  return await selectTemplateLanguage();
2569
2582
  }
2570
2583
  if (savedConfig?.preferredLang && !savedConfig?.templateLang) {
2584
+ if (skipPrompt) {
2585
+ return savedConfig.preferredLang;
2586
+ }
2571
2587
  console.log(ansis.yellow(`${i18n.t("language:usingFallbackTemplate")}: ${LANG_LABELS[savedConfig.preferredLang]}`));
2572
2588
  const { shouldModify } = await inquirer.prompt({
2573
2589
  type: "confirm",
@@ -2584,9 +2600,12 @@ async function resolveTemplateLanguage(commandLineOption, savedConfig) {
2584
2600
  }
2585
2601
  return await selectTemplateLanguage();
2586
2602
  }
2603
+ if (skipPrompt) {
2604
+ return "en";
2605
+ }
2587
2606
  return await selectTemplateLanguage();
2588
2607
  }
2589
- async function resolveSystemPromptStyle(availablePrompts, commandLineOption, savedConfig) {
2608
+ async function resolveSystemPromptStyle(availablePrompts, commandLineOption, savedConfig, skipPrompt) {
2590
2609
  ensureI18nInitialized();
2591
2610
  if (commandLineOption && availablePrompts.some((p) => p.id === commandLineOption)) {
2592
2611
  return commandLineOption;
@@ -2595,6 +2614,9 @@ async function resolveSystemPromptStyle(availablePrompts, commandLineOption, sav
2595
2614
  const currentStyleId = savedConfig.codex.systemPromptStyle;
2596
2615
  const currentStyle = availablePrompts.find((p) => p.id === currentStyleId);
2597
2616
  if (currentStyle) {
2617
+ if (skipPrompt) {
2618
+ return currentStyleId;
2619
+ }
2598
2620
  console.log(ansis.blue(`${i18n.t("language:currentSystemPromptFound")}: ${currentStyle.name}`));
2599
2621
  const { shouldModify } = await inquirer.prompt({
2600
2622
  type: "confirm",
@@ -2612,6 +2634,9 @@ async function resolveSystemPromptStyle(availablePrompts, commandLineOption, sav
2612
2634
  }
2613
2635
  }
2614
2636
  }
2637
+ if (skipPrompt) {
2638
+ return "engineer-professional";
2639
+ }
2615
2640
  const { systemPrompt } = await inquirer.prompt([{
2616
2641
  type: "list",
2617
2642
  name: "systemPrompt",
@@ -2807,7 +2832,10 @@ function parseCodexConfig(content) {
2807
2832
  };
2808
2833
  }
2809
2834
  try {
2810
- const tomlData = parse(content);
2835
+ const normalizedContent = content.replace(/(SYSTEMROOT\s*=\s*")[^"\n]+("?)/g, (match) => {
2836
+ return match.replace(/\\\\/g, "/").replace(/\\/g, "/").replace('C:/Windows"?', 'C:/Windows"');
2837
+ });
2838
+ const tomlData = parse(normalizedContent);
2811
2839
  const providers = [];
2812
2840
  if (tomlData.model_providers) {
2813
2841
  for (const [id, providerData] of Object.entries(tomlData.model_providers)) {
@@ -2876,21 +2904,30 @@ function parseCodexConfig(content) {
2876
2904
  const otherConfig = [];
2877
2905
  const lines = content.split("\n");
2878
2906
  let skipCurrentSection = false;
2879
- let currentSection = "";
2880
2907
  for (const line of lines) {
2881
- const trimmedLine = line.trim();
2882
- if (trimmedLine.includes("--- model provider added by ZCF ---") || trimmedLine.includes("--- MCP servers added by ZCF ---") || trimmedLine.includes("Managed by ZCF")) {
2908
+ const trimmed = line.trim();
2909
+ if (!trimmed)
2883
2910
  continue;
2884
- }
2885
- const sectionMatch = trimmedLine.match(/^\[([^\]]+)\]/);
2886
- if (sectionMatch) {
2887
- currentSection = sectionMatch[1];
2888
- skipCurrentSection = currentSection.startsWith("model_providers.") || currentSection.startsWith("mcp_servers.");
2889
- }
2890
- if (!skipCurrentSection && (trimmedLine.startsWith("model_provider") || trimmedLine.startsWith("# model_provider") || /^model\s*=/.test(trimmedLine))) {
2911
+ if (/^#\s*---\s*model provider added by ZCF\s*---\s*$/i.test(trimmed))
2912
+ continue;
2913
+ if (/^#\s*---\s*MCP servers added by ZCF\s*---\s*$/i.test(trimmed))
2914
+ continue;
2915
+ if (/Managed by ZCF/i.test(trimmed))
2916
+ continue;
2917
+ const sec = trimmed.match(/^\[([^\]]+)\]/);
2918
+ if (sec) {
2919
+ const name = sec[1];
2920
+ skipCurrentSection = name.startsWith("model_providers.") || name.startsWith("mcp_servers.");
2921
+ if (skipCurrentSection)
2922
+ continue;
2923
+ otherConfig.push(line);
2891
2924
  continue;
2892
2925
  }
2893
- if (!skipCurrentSection && trimmedLine) {
2926
+ if (/^#?\s*model_provider\s*=/.test(trimmed))
2927
+ continue;
2928
+ if (/^model\s*=/.test(trimmed))
2929
+ continue;
2930
+ if (!skipCurrentSection) {
2894
2931
  otherConfig.push(line);
2895
2932
  }
2896
2933
  }
@@ -2906,13 +2943,15 @@ function parseCodexConfig(content) {
2906
2943
  };
2907
2944
  } catch (error) {
2908
2945
  console.warn("TOML parsing failed, falling back to basic parsing:", error);
2946
+ 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");
2947
+ const otherConfig = cleaned.split("\n").map((l) => l.replace(/\s+$/g, "")).filter((l) => l.trim().length > 0);
2909
2948
  return {
2910
2949
  model: null,
2911
2950
  modelProvider: null,
2912
2951
  providers: [],
2913
2952
  mcpServices: [],
2914
2953
  managed: false,
2915
- otherConfig: content.split("\n"),
2954
+ otherConfig,
2916
2955
  modelProviderCommented: void 0
2917
2956
  };
2918
2957
  }
@@ -2941,9 +2980,29 @@ function renderCodexConfig(data) {
2941
2980
  lines.push("");
2942
2981
  }
2943
2982
  if (data.otherConfig && data.otherConfig.length > 0) {
2944
- lines.push(...data.otherConfig);
2945
- if (data.providers.length > 0 || data.mcpServices.length > 0) {
2946
- lines.push("");
2983
+ const preserved = data.otherConfig.filter((raw) => {
2984
+ const l = String(raw).trim();
2985
+ if (!l)
2986
+ return false;
2987
+ if (/^#\s*---\s*model provider added by ZCF\s*---\s*$/i.test(l))
2988
+ return false;
2989
+ if (/^#\s*---\s*MCP servers added by ZCF\s*---\s*$/i.test(l))
2990
+ return false;
2991
+ if (/^\[\s*mcp_servers\./i.test(l))
2992
+ return false;
2993
+ if (/^\[\s*model_providers\./i.test(l))
2994
+ return false;
2995
+ if (/^#?\s*model_provider\s*=/.test(l))
2996
+ return false;
2997
+ if (/^\s*model\s*=/.test(l))
2998
+ return false;
2999
+ return true;
3000
+ });
3001
+ if (preserved.length > 0) {
3002
+ lines.push(...preserved);
3003
+ if (data.providers.length > 0 || data.mcpServices.length > 0) {
3004
+ lines.push("");
3005
+ }
2947
3006
  }
2948
3007
  }
2949
3008
  if (data.providers.length > 0) {
@@ -3086,21 +3145,22 @@ async function runCodexWorkflowImport() {
3086
3145
  async function runCodexWorkflowImportWithLanguageSelection(options) {
3087
3146
  ensureI18nInitialized();
3088
3147
  const zcfConfig = readZcfConfig();
3089
- const { aiOutputLang: commandLineOption, skipPrompt } = options ?? {};
3090
- const aiOutputLang = skipPrompt ? commandLineOption || zcfConfig?.aiOutputLang || "en" : await resolveAiOutputLanguage(
3148
+ const { aiOutputLang: commandLineOption, skipPrompt = false } = options ?? {};
3149
+ const aiOutputLang = await resolveAiOutputLanguage(
3091
3150
  i18n.language,
3092
3151
  commandLineOption,
3093
- zcfConfig
3152
+ zcfConfig,
3153
+ skipPrompt
3094
3154
  );
3095
3155
  updateZcfConfig({ aiOutputLang });
3096
3156
  applyAiLanguageDirective(aiOutputLang);
3097
- await runCodexSystemPromptSelection();
3157
+ await runCodexSystemPromptSelection(skipPrompt);
3098
3158
  ensureCodexAgentsLanguageDirective(aiOutputLang);
3099
- await runCodexWorkflowSelection();
3159
+ await runCodexWorkflowSelection(options);
3100
3160
  console.log(ansis.green(i18n.t("codex:workflowInstall")));
3101
3161
  return aiOutputLang;
3102
3162
  }
3103
- async function runCodexSystemPromptSelection() {
3163
+ async function runCodexSystemPromptSelection(skipPrompt = false) {
3104
3164
  ensureI18nInitialized();
3105
3165
  const rootDir = getRootDir$1();
3106
3166
  const templateRoot = join(rootDir, "templates", "codex");
@@ -3111,7 +3171,9 @@ async function runCodexSystemPromptSelection() {
3111
3171
  const preferredLang = await resolveTemplateLanguage(
3112
3172
  void 0,
3113
3173
  // No command line option for this function
3114
- zcfConfig$1
3174
+ zcfConfig$1,
3175
+ skipPrompt
3176
+ // Pass skipPrompt flag
3115
3177
  );
3116
3178
  updateZcfConfig({ templateLang: preferredLang });
3117
3179
  let langDir = join(templateRoot, preferredLang);
@@ -3149,7 +3211,9 @@ async function runCodexSystemPromptSelection() {
3149
3211
  availablePrompts,
3150
3212
  void 0,
3151
3213
  // No command line option for this function
3152
- tomlConfig
3214
+ tomlConfig,
3215
+ skipPrompt
3216
+ // Pass skipPrompt flag
3153
3217
  );
3154
3218
  if (!systemPrompt)
3155
3219
  return;
@@ -3173,8 +3237,9 @@ async function runCodexSystemPromptSelection() {
3173
3237
  console.error("Failed to update ZCF config:", error);
3174
3238
  }
3175
3239
  }
3176
- async function runCodexWorkflowSelection() {
3240
+ async function runCodexWorkflowSelection(options) {
3177
3241
  ensureI18nInitialized();
3242
+ const { skipPrompt = false, workflows: presetWorkflows = [] } = options ?? {};
3178
3243
  const rootDir = getRootDir$1();
3179
3244
  const templateRoot = join(rootDir, "templates", "codex");
3180
3245
  const zcfConfig = readZcfConfig();
@@ -3189,6 +3254,29 @@ async function runCodexWorkflowSelection() {
3189
3254
  const allWorkflows = getAllWorkflowFiles(workflowSrc);
3190
3255
  if (allWorkflows.length === 0)
3191
3256
  return;
3257
+ if (skipPrompt) {
3258
+ ensureDir(CODEX_PROMPTS_DIR);
3259
+ const backupPath2 = backupCodexPrompts();
3260
+ if (backupPath2) {
3261
+ console.log(ansis.gray(getBackupMessage(backupPath2)));
3262
+ }
3263
+ let workflowsToInstall;
3264
+ if (presetWorkflows.length > 0) {
3265
+ const selectedWorkflows = allWorkflows.filter(
3266
+ (workflow) => presetWorkflows.includes(workflow.name)
3267
+ );
3268
+ workflowsToInstall = expandSelectedWorkflowPaths(selectedWorkflows.map((w) => w.path), workflowSrc);
3269
+ } else {
3270
+ workflowsToInstall = expandSelectedWorkflowPaths(allWorkflows.map((w) => w.path), workflowSrc);
3271
+ }
3272
+ for (const workflowPath of workflowsToInstall) {
3273
+ const content = readFile(workflowPath);
3274
+ const filename = workflowPath.split("/").pop() || "workflow.md";
3275
+ const targetPath = join(CODEX_PROMPTS_DIR, filename);
3276
+ writeFile(targetPath, content);
3277
+ }
3278
+ return;
3279
+ }
3192
3280
  const { workflows } = await inquirer.prompt([{
3193
3281
  type: "checkbox",
3194
3282
  name: "workflows",
@@ -3207,13 +3295,15 @@ async function runCodexWorkflowSelection() {
3207
3295
  if (backupPath) {
3208
3296
  console.log(ansis.gray(getBackupMessage(backupPath)));
3209
3297
  }
3210
- for (const workflowPath of workflows) {
3298
+ const finalWorkflowPaths = expandSelectedWorkflowPaths(workflows, workflowSrc);
3299
+ for (const workflowPath of finalWorkflowPaths) {
3211
3300
  const content = readFile(workflowPath);
3212
3301
  const filename = workflowPath.split("/").pop() || "workflow.md";
3213
3302
  const targetPath = join(CODEX_PROMPTS_DIR, filename);
3214
3303
  writeFile(targetPath, content);
3215
3304
  }
3216
3305
  }
3306
+ const GIT_GROUP_SENTINEL = "::gitGroup";
3217
3307
  function getAllWorkflowFiles(dirPath) {
3218
3308
  const workflows = [];
3219
3309
  const sixStepDir = join(dirPath, "sixStep", "prompts");
@@ -3226,8 +3316,43 @@ function getAllWorkflowFiles(dirPath) {
3226
3316
  });
3227
3317
  }
3228
3318
  }
3319
+ const gitPromptsDir = join(dirPath, "git", "prompts");
3320
+ if (exists(gitPromptsDir)) {
3321
+ workflows.push({
3322
+ name: i18n.t("workflow:workflowOption.gitWorkflow"),
3323
+ // Use sentinel path for grouped selection; expanded later
3324
+ path: GIT_GROUP_SENTINEL
3325
+ });
3326
+ }
3229
3327
  return workflows;
3230
3328
  }
3329
+ function expandSelectedWorkflowPaths(paths, workflowSrc) {
3330
+ const expanded = [];
3331
+ for (const p of paths) {
3332
+ if (p === GIT_GROUP_SENTINEL) {
3333
+ expanded.push(...getGitPromptFiles(workflowSrc));
3334
+ } else {
3335
+ expanded.push(p);
3336
+ }
3337
+ }
3338
+ return expanded;
3339
+ }
3340
+ function getGitPromptFiles(workflowSrc) {
3341
+ const gitDir = join(workflowSrc, "git", "prompts");
3342
+ const files = [
3343
+ "git-commit.md",
3344
+ "git-rollback.md",
3345
+ "git-cleanBranches.md",
3346
+ "git-worktree.md"
3347
+ ];
3348
+ const resolved = [];
3349
+ for (const f of files) {
3350
+ const full = join(gitDir, f);
3351
+ if (exists(full))
3352
+ resolved.push(full);
3353
+ }
3354
+ return resolved;
3355
+ }
3231
3356
  function toProvidersList(providers) {
3232
3357
  return providers.map((provider) => ({ name: provider.name || provider.id, value: provider.id }));
3233
3358
  }
@@ -3247,10 +3372,59 @@ function createApiConfigChoices(providers, currentProvider, isCommented) {
3247
3372
  });
3248
3373
  return choices;
3249
3374
  }
3250
- async function configureCodexApi() {
3375
+ async function applyCustomApiConfig(customApiConfig) {
3376
+ const { type, token, baseUrl } = customApiConfig;
3377
+ const backupPath = backupCodexComplete();
3378
+ if (backupPath) {
3379
+ console.log(ansis.gray(getBackupMessage(backupPath)));
3380
+ }
3381
+ const providers = [];
3382
+ const authEntries = {};
3383
+ const providerId = type === "auth_token" ? "official-auth-token" : "custom-api-key";
3384
+ const providerName = type === "auth_token" ? "Official Auth Token" : "Custom API Key";
3385
+ providers.push({
3386
+ id: providerId,
3387
+ name: providerName,
3388
+ baseUrl: baseUrl || "https://api.anthropic.com",
3389
+ wireApi: "claude",
3390
+ envKey: `${providerId.toUpperCase()}_API_KEY`,
3391
+ requiresOpenaiAuth: false
3392
+ });
3393
+ if (token) {
3394
+ authEntries[providerId] = token;
3395
+ }
3396
+ const configData = {
3397
+ model: "claude-3-5-sonnet-20241022",
3398
+ modelProvider: providerId,
3399
+ modelProviderCommented: false,
3400
+ providers,
3401
+ mcpServices: []};
3402
+ writeFile(CODEX_CONFIG_FILE, renderCodexConfig(configData));
3403
+ writeJsonConfig(CODEX_AUTH_FILE, authEntries);
3404
+ updateZcfConfig({ codeToolType: "codex" });
3405
+ console.log(ansis.green(`\u2714 ${i18n.t("codex:apiConfigured")}`));
3406
+ }
3407
+ async function configureCodexApi(options) {
3251
3408
  ensureI18nInitialized();
3409
+ const { skipPrompt = false, apiMode, customApiConfig } = options ?? {};
3252
3410
  const existingConfig = readCodexConfig();
3253
3411
  const existingAuth = readJsonConfig(CODEX_AUTH_FILE, { defaultValue: {} }) || {};
3412
+ if (skipPrompt) {
3413
+ if (apiMode === "skip") {
3414
+ return;
3415
+ }
3416
+ if (apiMode === "custom" && customApiConfig) {
3417
+ await applyCustomApiConfig(customApiConfig);
3418
+ return;
3419
+ }
3420
+ if (apiMode === "official") {
3421
+ const success = await switchToOfficialLogin();
3422
+ if (success) {
3423
+ updateZcfConfig({ codeToolType: "codex" });
3424
+ }
3425
+ return;
3426
+ }
3427
+ }
3254
3428
  const hasProviders = existingConfig?.providers && existingConfig.providers.length > 0;
3255
3429
  const modeChoices = [
3256
3430
  { name: i18n.t("codex:apiModeOfficial"), value: "official" },
@@ -3439,9 +3613,13 @@ async function configureCodexApi() {
3439
3613
  updateZcfConfig({ codeToolType: "codex" });
3440
3614
  console.log(ansis.green(i18n.t("codex:apiConfigured")));
3441
3615
  }
3442
- async function configureCodexMcp() {
3616
+ async function configureCodexMcp(options) {
3443
3617
  ensureI18nInitialized();
3618
+ const { skipPrompt = false } = options ?? {};
3444
3619
  const existingConfig = readCodexConfig();
3620
+ if (skipPrompt) {
3621
+ return;
3622
+ }
3445
3623
  const backupPath = backupCodexComplete();
3446
3624
  if (backupPath) {
3447
3625
  console.log(ansis.gray(getBackupMessage(backupPath)));
@@ -3452,14 +3630,29 @@ async function configureCodexMcp() {
3452
3630
  const servicesMeta = await getMcpServices();
3453
3631
  const baseProviders = existingConfig?.providers || [];
3454
3632
  const selection = [];
3455
- const existingMap = new Map((existingConfig?.mcpServices || []).map((service) => [service.id, service]));
3633
+ const existingServices = existingConfig?.mcpServices || [];
3456
3634
  if (selectedIds.length === 0) {
3457
3635
  console.log(ansis.yellow(i18n.t("codex:noMcpConfigured")));
3636
+ const preserved = (existingServices || []).map((svc) => {
3637
+ if (isWindows()) {
3638
+ const systemRoot = getSystemRoot();
3639
+ if (systemRoot) {
3640
+ return {
3641
+ ...svc,
3642
+ env: {
3643
+ ...svc.env || {},
3644
+ SYSTEMROOT: systemRoot
3645
+ }
3646
+ };
3647
+ }
3648
+ }
3649
+ return svc;
3650
+ });
3458
3651
  writeCodexConfig({
3459
3652
  model: existingConfig?.model || null,
3460
3653
  modelProvider: existingConfig?.modelProvider || null,
3461
3654
  providers: baseProviders,
3462
- mcpServices: Array.from(existingMap.values()),
3655
+ mcpServices: preserved,
3463
3656
  otherConfig: existingConfig?.otherConfig || []
3464
3657
  });
3465
3658
  updateZcfConfig({ codeToolType: "codex" });
@@ -3504,15 +3697,33 @@ async function configureCodexMcp() {
3504
3697
  startup_timeout_ms: configInfo.config.startup_timeout_ms
3505
3698
  });
3506
3699
  }
3507
- const selectionMap = new Map(selection.map((service) => [service.id, service]));
3508
- const mergedMap = new Map(existingMap);
3509
- for (const service of selectionMap.values())
3510
- mergedMap.set(service.id, service);
3700
+ const mergedMap = /* @__PURE__ */ new Map();
3701
+ for (const svc of existingServices) {
3702
+ mergedMap.set(svc.id.toLowerCase(), { ...svc });
3703
+ }
3704
+ for (const svc of selection) {
3705
+ mergedMap.set(svc.id.toLowerCase(), { ...svc });
3706
+ }
3707
+ const finalServices = Array.from(mergedMap.values()).map((svc) => {
3708
+ if (isWindows()) {
3709
+ const systemRoot = getSystemRoot();
3710
+ if (systemRoot) {
3711
+ return {
3712
+ ...svc,
3713
+ env: {
3714
+ ...svc.env || {},
3715
+ SYSTEMROOT: systemRoot
3716
+ }
3717
+ };
3718
+ }
3719
+ }
3720
+ return svc;
3721
+ });
3511
3722
  writeCodexConfig({
3512
3723
  model: existingConfig?.model || null,
3513
3724
  modelProvider: existingConfig?.modelProvider || null,
3514
3725
  providers: baseProviders,
3515
- mcpServices: Array.from(mergedMap.values()),
3726
+ mcpServices: finalServices,
3516
3727
  otherConfig: existingConfig?.otherConfig || []
3517
3728
  });
3518
3729
  updateZcfConfig({ codeToolType: "codex" });
@@ -3522,8 +3733,8 @@ async function runCodexFullInit(options) {
3522
3733
  ensureI18nInitialized();
3523
3734
  await installCodexCli();
3524
3735
  const aiOutputLang = await runCodexWorkflowImportWithLanguageSelection(options);
3525
- await configureCodexApi();
3526
- await configureCodexMcp();
3736
+ await configureCodexApi(options);
3737
+ await configureCodexMcp(options);
3527
3738
  return aiOutputLang;
3528
3739
  }
3529
3740
  function ensureCodexAgentsLanguageDirective(aiOutputLang) {
@@ -3563,7 +3774,10 @@ function normalizeLanguageLabel(label) {
3563
3774
  }
3564
3775
  async function runCodexUpdate(force = false, skipPrompt = false) {
3565
3776
  ensureI18nInitialized();
3566
- const spinner = ora(i18n.t("codex:checkingVersion")).start();
3777
+ console.log(ansis.bold.cyan(`
3778
+ \u{1F50D} ${i18n.t("updater:checkingTools")}
3779
+ `));
3780
+ const spinner = ora(i18n.t("updater:checkingVersion")).start();
3567
3781
  try {
3568
3782
  const { installed, currentVersion, latestVersion, needsUpdate } = await checkCodexUpdate();
3569
3783
  spinner.stop();
@@ -3826,6 +4040,43 @@ const codex = {
3826
4040
  writeCodexConfig: writeCodexConfig
3827
4041
  };
3828
4042
 
4043
+ const CODE_TYPE_ABBREVIATIONS = {
4044
+ cc: "claude-code",
4045
+ cx: "codex"
4046
+ };
4047
+ async function resolveCodeType(codeTypeParam) {
4048
+ if (codeTypeParam) {
4049
+ const normalizedParam = codeTypeParam.toLowerCase().trim();
4050
+ if (normalizedParam in CODE_TYPE_ABBREVIATIONS) {
4051
+ return CODE_TYPE_ABBREVIATIONS[normalizedParam];
4052
+ }
4053
+ if (isValidCodeType(normalizedParam)) {
4054
+ return normalizedParam;
4055
+ }
4056
+ const validAbbreviations = Object.keys(CODE_TYPE_ABBREVIATIONS);
4057
+ const validFullTypes = Object.values(CODE_TYPE_ABBREVIATIONS);
4058
+ const validOptions = [...validAbbreviations, ...validFullTypes].join(", ");
4059
+ throw new Error(
4060
+ i18n.t(
4061
+ "errors:invalidCodeType",
4062
+ `Invalid code type: "${codeTypeParam}". Valid options are: ${validOptions}.`,
4063
+ { value: codeTypeParam, validOptions }
4064
+ )
4065
+ );
4066
+ }
4067
+ try {
4068
+ const config = await readZcfConfigAsync();
4069
+ if (config?.codeToolType && isValidCodeType(config.codeToolType)) {
4070
+ return config.codeToolType;
4071
+ }
4072
+ } catch {
4073
+ }
4074
+ return DEFAULT_CODE_TOOL_TYPE;
4075
+ }
4076
+ function isValidCodeType(value) {
4077
+ return ["claude-code", "codex"].includes(value);
4078
+ }
4079
+
3829
4080
  function getPlatformStatusLineConfig() {
3830
4081
  return {
3831
4082
  type: "command",
@@ -4722,12 +4973,6 @@ function validateSkipPromptOptions(options) {
4722
4973
  if (!options.configAction) {
4723
4974
  options.configAction = "backup";
4724
4975
  }
4725
- if (!options.configLang) {
4726
- options.configLang = "en";
4727
- }
4728
- if (!options.aiOutputLang) {
4729
- options.aiOutputLang = "en";
4730
- }
4731
4976
  if (typeof options.outputStyles === "string") {
4732
4977
  if (options.outputStyles === "skip") {
4733
4978
  options.outputStyles = false;
@@ -4822,22 +5067,20 @@ function validateSkipPromptOptions(options) {
4822
5067
  options.workflows = WORKFLOW_CONFIG_BASE.map((w) => w.id);
4823
5068
  }
4824
5069
  }
4825
- function resolveCodeToolType(optionValue, savedValue) {
4826
- if (isCodeToolType(optionValue)) {
4827
- return optionValue;
4828
- }
4829
- if (savedValue && isCodeToolType(savedValue)) {
4830
- return savedValue;
4831
- }
4832
- return DEFAULT_CODE_TOOL_TYPE;
4833
- }
4834
5070
  async function init(options = {}) {
4835
5071
  if (options.skipPrompt) {
4836
5072
  validateSkipPromptOptions(options);
4837
5073
  }
4838
5074
  try {
4839
5075
  const zcfConfig = readZcfConfig();
4840
- const codeToolType = resolveCodeToolType(options.codeType, zcfConfig?.codeToolType);
5076
+ let codeToolType;
5077
+ try {
5078
+ codeToolType = await resolveCodeType(options.codeType);
5079
+ } catch (error) {
5080
+ const errorMessage = error instanceof Error ? error.message : String(error);
5081
+ console.error(ansis.red(`${i18n.t("errors:generalError")} ${errorMessage}`));
5082
+ codeToolType = DEFAULT_CODE_TOOL_TYPE;
5083
+ }
4841
5084
  options.codeType = codeToolType;
4842
5085
  async function selectApiConfigurationMode() {
4843
5086
  const { apiMode } = await inquirer.prompt({
@@ -4931,23 +5174,39 @@ async function init(options = {}) {
4931
5174
  }
4932
5175
  }
4933
5176
  } else {
4934
- if (!configLang && !options.skipPrompt) {
5177
+ if (!configLang) {
4935
5178
  const { resolveTemplateLanguage } = await Promise.resolve().then(function () { return prompts; });
4936
5179
  configLang = await resolveTemplateLanguage(
4937
5180
  options.configLang,
4938
- zcfConfig
5181
+ zcfConfig,
5182
+ options.skipPrompt
4939
5183
  );
4940
- } else if (!configLang && options.skipPrompt) {
4941
- configLang = "en";
4942
5184
  }
4943
5185
  }
4944
5186
  if (!configLang) {
4945
5187
  configLang = "en";
4946
5188
  }
4947
5189
  if (codeToolType === "codex") {
5190
+ const apiMode = options.apiType === "auth_token" ? "official" : options.apiType === "api_key" ? "custom" : options.apiType === "skip" ? "skip" : options.skipPrompt ? "skip" : void 0;
5191
+ const customApiConfig = options.apiType === "api_key" && options.apiKey ? {
5192
+ type: "api_key",
5193
+ token: options.apiKey,
5194
+ baseUrl: options.apiUrl
5195
+ } : void 0;
5196
+ let selectedWorkflows;
5197
+ if (Array.isArray(options.workflows)) {
5198
+ selectedWorkflows = options.workflows;
5199
+ } else if (typeof options.workflows === "string") {
5200
+ selectedWorkflows = [options.workflows];
5201
+ } else if (options.workflows === true) {
5202
+ selectedWorkflows = [];
5203
+ }
4948
5204
  const resolvedAiOutputLang = await runCodexFullInit({
4949
5205
  aiOutputLang: options.aiOutputLang,
4950
- skipPrompt: options.skipPrompt
5206
+ skipPrompt: options.skipPrompt,
5207
+ apiMode,
5208
+ customApiConfig,
5209
+ workflows: selectedWorkflows
4951
5210
  });
4952
5211
  updateZcfConfig({
4953
5212
  version,
@@ -4961,7 +5220,7 @@ async function init(options = {}) {
4961
5220
  console.log(ansis.green(i18n.t("codex:setupComplete")));
4962
5221
  return;
4963
5222
  }
4964
- const aiOutputLang = options.skipPrompt ? options.aiOutputLang || "en" : await resolveAiOutputLanguage(i18n.language, options.aiOutputLang, zcfConfig);
5223
+ const aiOutputLang = await resolveAiOutputLanguage(i18n.language, options.aiOutputLang, zcfConfig, options.skipPrompt);
4965
5224
  const installationStatus = await getInstallationStatus();
4966
5225
  if (installationStatus.hasGlobal || installationStatus.hasLocal) {
4967
5226
  if (!options.skipPrompt) {
@@ -5363,4 +5622,4 @@ async function openSettingsJson() {
5363
5622
  }
5364
5623
  }
5365
5624
 
5366
- 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 };
5625
+ 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, updatePromptOnly as aA, selectAndInstallWorkflows as aB, checkClaudeCodeVersionAndPrompt as aC, displayBannerWithInfo as aD, runCodexUninstall as aE, configureCodexMcp as aF, configureCodexApi as aG, runCodexWorkflowImport as aH, runCodexFullInit as aI, listCodexProviders as aJ, getCurrentCodexProvider as aK, switchCodexProvider as aL, switchToOfficialLogin as aM, switchToProvider as aN, readZcfConfigAsync as aO, initI18n as aP, selectScriptLanguage as aQ, fsOperations as aR, prompts as aS, codex as aT, 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, runCodexUpdate as at, resolveCodeType as au, readJsonConfig as av, writeJsonConfig as aw, displayBanner as ax, version as ay, resolveAiOutputLanguage 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 };