zcf 2.12.13 → 3.0.1

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 (67) hide show
  1. package/README.md +94 -4
  2. package/dist/chunks/codex-config-switch.mjs +419 -0
  3. package/dist/chunks/codex-uninstaller.mjs +404 -0
  4. package/dist/chunks/simple-config.mjs +1869 -374
  5. package/dist/cli.mjs +672 -206
  6. package/dist/i18n/locales/en/cli.json +1 -0
  7. package/dist/i18n/locales/en/codex.json +102 -0
  8. package/dist/i18n/locales/en/common.json +4 -1
  9. package/dist/i18n/locales/en/configuration.json +10 -4
  10. package/dist/i18n/locales/en/language.json +8 -2
  11. package/dist/i18n/locales/en/mcp.json +4 -3
  12. package/dist/i18n/locales/en/menu.json +20 -0
  13. package/dist/i18n/locales/en/uninstall.json +0 -4
  14. package/dist/i18n/locales/zh-CN/cli.json +1 -0
  15. package/dist/i18n/locales/zh-CN/codex.json +102 -0
  16. package/dist/i18n/locales/zh-CN/common.json +4 -1
  17. package/dist/i18n/locales/zh-CN/configuration.json +10 -4
  18. package/dist/i18n/locales/zh-CN/language.json +8 -2
  19. package/dist/i18n/locales/zh-CN/mcp.json +4 -3
  20. package/dist/i18n/locales/zh-CN/menu.json +20 -0
  21. package/dist/i18n/locales/zh-CN/uninstall.json +0 -4
  22. package/dist/index.d.mts +11 -3
  23. package/dist/index.d.ts +11 -3
  24. package/dist/index.mjs +2 -1
  25. package/dist/shared/zcf.DGjQxTq_.mjs +34 -0
  26. package/package.json +11 -10
  27. package/templates/{common → claude-code/common}/settings.json +2 -1
  28. package/templates/codex/common/config.toml +0 -0
  29. package/templates/codex/en/system-prompt/engineer-professional.md +87 -0
  30. package/templates/codex/en/system-prompt/laowang-engineer.md +126 -0
  31. package/templates/codex/en/system-prompt/nekomata-engineer.md +119 -0
  32. package/templates/codex/en/workflow/sixStep/prompts/workflow.md +211 -0
  33. package/templates/codex/zh-CN/system-prompt/engineer-professional.md +88 -0
  34. package/templates/codex/zh-CN/system-prompt/laowang-engineer.md +126 -0
  35. package/templates/codex/zh-CN/system-prompt/nekomata-engineer.md +119 -0
  36. package/templates/codex/zh-CN/workflow/sixStep/prompts/workflow.md +211 -0
  37. /package/templates/{CLAUDE.md → claude-code/CLAUDE.md} +0 -0
  38. /package/templates/{en → claude-code/en}/output-styles/engineer-professional.md +0 -0
  39. /package/templates/{en → claude-code/en}/output-styles/laowang-engineer.md +0 -0
  40. /package/templates/{en → claude-code/en}/output-styles/nekomata-engineer.md +0 -0
  41. /package/templates/{en → claude-code/en}/workflow/bmad/commands/bmad-init.md +0 -0
  42. /package/templates/{en → claude-code/en}/workflow/common/agents/get-current-datetime.md +0 -0
  43. /package/templates/{en → claude-code/en}/workflow/common/agents/init-architect.md +0 -0
  44. /package/templates/{en → claude-code/en}/workflow/common/commands/init-project.md +0 -0
  45. /package/templates/{en → claude-code/en}/workflow/git/commands/git-cleanBranches.md +0 -0
  46. /package/templates/{en → claude-code/en}/workflow/git/commands/git-commit.md +0 -0
  47. /package/templates/{en → claude-code/en}/workflow/git/commands/git-rollback.md +0 -0
  48. /package/templates/{en → claude-code/en}/workflow/git/commands/git-worktree.md +0 -0
  49. /package/templates/{en → claude-code/en}/workflow/plan/agents/planner.md +0 -0
  50. /package/templates/{en → claude-code/en}/workflow/plan/agents/ui-ux-designer.md +0 -0
  51. /package/templates/{en → claude-code/en}/workflow/plan/commands/feat.md +0 -0
  52. /package/templates/{en → claude-code/en}/workflow/sixStep/commands/workflow.md +0 -0
  53. /package/templates/{zh-CN → claude-code/zh-CN}/output-styles/engineer-professional.md +0 -0
  54. /package/templates/{zh-CN → claude-code/zh-CN}/output-styles/laowang-engineer.md +0 -0
  55. /package/templates/{zh-CN → claude-code/zh-CN}/output-styles/nekomata-engineer.md +0 -0
  56. /package/templates/{zh-CN → claude-code/zh-CN}/workflow/bmad/commands/bmad-init.md +0 -0
  57. /package/templates/{zh-CN → claude-code/zh-CN}/workflow/common/agents/get-current-datetime.md +0 -0
  58. /package/templates/{zh-CN → claude-code/zh-CN}/workflow/common/agents/init-architect.md +0 -0
  59. /package/templates/{zh-CN → claude-code/zh-CN}/workflow/common/commands/init-project.md +0 -0
  60. /package/templates/{zh-CN → claude-code/zh-CN}/workflow/git/commands/git-cleanBranches.md +0 -0
  61. /package/templates/{zh-CN → claude-code/zh-CN}/workflow/git/commands/git-commit.md +0 -0
  62. /package/templates/{zh-CN → claude-code/zh-CN}/workflow/git/commands/git-rollback.md +0 -0
  63. /package/templates/{zh-CN → claude-code/zh-CN}/workflow/git/commands/git-worktree.md +0 -0
  64. /package/templates/{zh-CN → claude-code/zh-CN}/workflow/plan/agents/planner.md +0 -0
  65. /package/templates/{zh-CN → claude-code/zh-CN}/workflow/plan/agents/ui-ux-designer.md +0 -0
  66. /package/templates/{zh-CN → claude-code/zh-CN}/workflow/plan/commands/feat.md +0 -0
  67. /package/templates/{zh-CN → claude-code/zh-CN}/workflow/sixStep/commands/workflow.md +0 -0
package/dist/cli.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import cac from 'cac';
3
3
  import ansis from 'ansis';
4
- import { R as ensureI18nInitialized, T as i18n, U as readCcrConfig, V as isCcrInstalled, W as installCcr, X as configureCcrFeature, Y as handleExitPromptError, _ as handleGeneralError, h as SUPPORTED_LANGS, $ as addNumbersToChoices, j as LANG_LABELS, a0 as updateZcfConfig, a1 as changeLanguage, o as openSettingsJson, d as importRecommendedPermissions, b as importRecommendedEnv, a2 as readZcfConfig, K as applyAiLanguageDirective, a3 as configureOutputStyle, I as getExistingModelConfig, F as updateCustomModel, G as updateDefaultModel, a4 as isWindows, r as readMcpConfig, s as fixWindowsMcpConfig, w as writeMcpConfig, a5 as selectMcpServices, n as backupMcpConfig, a6 as getMcpServices, q as buildMcpServerConfig, p as mergeMcpServers, J as getExistingApiConfig, a7 as formatApiKeyDisplay, t as addCompletedOnboarding, a8 as modifyApiConfigPartially, a9 as setupCcrConfiguration, aa as validateApiKey, D as configureApi, ab as COMETIX_COMMAND_NAME, ac as COMETIX_COMMANDS, ad as installCometixLine, ae as checkAndUpdateTools, af as readJsonConfig, ag as writeJsonConfig, ah as displayBanner, ai as resolveAiOutputLanguage, aj as updatePromptOnly, ak as selectAndInstallWorkflows, al as checkClaudeCodeVersionAndPrompt, am as version, an as displayBannerWithInfo, i as init, ao as readZcfConfigAsync, ap as initI18n, aq as selectScriptLanguage } from './chunks/simple-config.mjs';
4
+ import { a0 as ensureI18nInitialized, W as i18n, a3 as readCcrConfig, a4 as isCcrInstalled, a5 as installCcr, a6 as configureCcrFeature, a7 as handleExitPromptError, a8 as handleGeneralError, l as SUPPORTED_LANGS, a2 as addNumbersToChoices, n as LANG_LABELS, a9 as updateZcfConfig, aa as changeLanguage, ab as readZcfConfig, o as openSettingsJson, d as importRecommendedPermissions, b as importRecommendedEnv, P as applyAiLanguageDirective, ac as configureOutputStyle, N as getExistingModelConfig, J as updateCustomModel, K as updateDefaultModel, ad as isWindows, r as readMcpConfig, v as fixWindowsMcpConfig, w as writeMcpConfig, ae as selectMcpServices, s as backupMcpConfig, af as getMcpServices, u as buildMcpServerConfig, t as mergeMcpServers, O as getExistingApiConfig, ag as formatApiKeyDisplay, x as addCompletedOnboarding, ah as modifyApiConfigPartially, ai as setupCcrConfiguration, aj as validateApiKey, H as configureApi, ak as COMETIX_COMMAND_NAME, al as COMETIX_COMMANDS, am as installCometixLine, an as checkAndUpdateTools, ao as readJsonConfig, ap as writeJsonConfig, h as ZCF_CONFIG_FILE, aq as displayBanner, ar as runCodexUpdate, as as version, at as resolveAiOutputLanguage, au as updatePromptOnly, av as selectAndInstallWorkflows, aw as checkClaudeCodeVersionAndPrompt, k as isCodeToolType, D as DEFAULT_CODE_TOOL_TYPE, ax as displayBannerWithInfo, ay as runCodexUninstall, az as configureCodexMcp, aA as configureCodexApi, aB as runCodexWorkflowImport, aC as runCodexFullInit, i as init, aD as listCodexProviders, aE as getCurrentCodexProvider, aF as switchCodexProvider, X as readCodexConfig, aG as switchToOfficialLogin, aH as switchToProvider, aI as readZcfConfigAsync, aJ as initI18n, aK as selectScriptLanguage } from './chunks/simple-config.mjs';
5
5
  import { existsSync } from 'node:fs';
6
6
  import { homedir } from 'node:os';
7
7
  import inquirer from 'inquirer';
@@ -11,14 +11,16 @@ import { promisify } from 'node:util';
11
11
  import process from 'node:process';
12
12
  import { x, exec as exec$1 } from 'tinyexec';
13
13
  import { pathExists } from 'fs-extra';
14
- import trash from 'trash';
14
+ import { m as moveToTrash } from './shared/zcf.DGjQxTq_.mjs';
15
15
  import 'dayjs';
16
16
  import 'node:url';
17
17
  import 'ora';
18
18
  import 'semver';
19
+ import 'smol-toml';
19
20
  import 'node:fs/promises';
20
21
  import 'i18next';
21
22
  import 'i18next-fs-backend';
23
+ import 'trash';
22
24
 
23
25
  const execAsync$1 = promisify(exec);
24
26
  async function runCcrUi(apiKey) {
@@ -400,7 +402,7 @@ async function configureMcpFeature() {
400
402
  const existingConfig = readMcpConfig() || { mcpServers: {} };
401
403
  const fixedConfig = fixWindowsMcpConfig(existingConfig);
402
404
  writeMcpConfig(fixedConfig);
403
- console.log(ansis.green(`\u2714 Windows MCP configuration fixed`));
405
+ console.log(ansis.green(`\u2714 ${i18n.t("configuration:windowsMcpConfigFixed")}`));
404
406
  }
405
407
  }
406
408
  const selectedServices = await selectMcpServices();
@@ -420,9 +422,9 @@ async function configureMcpFeature() {
420
422
  let config = service.config;
421
423
  if (service.requiresApiKey) {
422
424
  const { apiKey } = await inquirer.prompt({
423
- type: "input",
425
+ type: "password",
424
426
  name: "apiKey",
425
- message: service.apiKeyPrompt,
427
+ message: service.apiKeyPrompt + i18n.t("common:inputHidden"),
426
428
  validate: async (value) => !!value || i18n.t("api:keyRequired")
427
429
  });
428
430
  if (apiKey) {
@@ -557,7 +559,7 @@ ${ansis.blue(`\u2139 ${i18n.t("configuration:existingLanguageConfig") || "Existi
557
559
  return;
558
560
  }
559
561
  }
560
- const { selectAiOutputLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.ar; });
562
+ const { selectAiOutputLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aM; });
561
563
  const aiOutputLang = await selectAiOutputLanguage();
562
564
  applyAiLanguageDirective(aiOutputLang);
563
565
  updateZcfConfig({ aiOutputLang });
@@ -588,6 +590,214 @@ async function changeScriptLanguageFeature(currentLang) {
588
590
  console.log(ansis.green(`\u2714 ${i18n.t("language:languageChanged") || "Language changed"}`));
589
591
  return lang;
590
592
  }
593
+ async function configureCodexDefaultModelFeature() {
594
+ ensureI18nInitialized();
595
+ const { readCodexConfig } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aN; });
596
+ const existingConfig = readCodexConfig();
597
+ const currentModel = existingConfig?.model;
598
+ if (currentModel) {
599
+ console.log(`
600
+ ${ansis.blue(`\u2139 ${i18n.t("configuration:existingModelConfig") || "Existing model configuration"}`)}`);
601
+ const modelDisplay = currentModel === "gpt-5-codex" ? "GPT-5-Codex" : currentModel === "gpt-5" ? "GPT-5" : currentModel.charAt(0).toUpperCase() + currentModel.slice(1);
602
+ console.log(ansis.gray(` ${i18n.t("configuration:currentModel") || "Current model"}: ${modelDisplay}
603
+ `));
604
+ const { modify } = await inquirer.prompt({
605
+ type: "confirm",
606
+ name: "modify",
607
+ message: i18n.t("configuration:modifyModel") || "Modify model configuration?",
608
+ default: false
609
+ });
610
+ if (!modify) {
611
+ console.log(ansis.green(`\u2714 ${i18n.t("configuration:keepModel") || "Keeping existing model configuration"}`));
612
+ return;
613
+ }
614
+ }
615
+ const { model } = await inquirer.prompt({
616
+ type: "list",
617
+ name: "model",
618
+ message: i18n.t("configuration:selectDefaultModel") || "Select default model",
619
+ choices: addNumbersToChoices([
620
+ {
621
+ name: i18n.t("configuration:codexModelOptions.gpt5"),
622
+ value: "gpt-5"
623
+ },
624
+ {
625
+ name: i18n.t("configuration:codexModelOptions.gpt5Codex"),
626
+ value: "gpt-5-codex"
627
+ },
628
+ {
629
+ name: i18n.t("configuration:codexModelOptions.custom"),
630
+ value: "custom"
631
+ }
632
+ ]),
633
+ default: currentModel ? ["gpt-5", "gpt-5-codex", "custom"].indexOf(currentModel) : 1
634
+ // Default to gpt-5-codex
635
+ });
636
+ if (!model) {
637
+ await handleCancellation();
638
+ return;
639
+ }
640
+ if (model === "custom") {
641
+ const { customModel } = await inquirer.prompt({
642
+ type: "input",
643
+ name: "customModel",
644
+ message: `${i18n.t("configuration:enterCustomModel")}${i18n.t("common:emptyToSkip")}`,
645
+ default: ""
646
+ });
647
+ if (!customModel.trim()) {
648
+ console.log(ansis.yellow(`\u26A0 ${i18n.t("configuration:customModelSkipped") || "Custom model configuration skipped"}`));
649
+ return;
650
+ }
651
+ await updateCodexModelProvider(customModel.trim());
652
+ console.log(ansis.green(`\u2714 ${i18n.t("configuration:customModelConfigured") || "Custom model configuration completed"}`));
653
+ return;
654
+ }
655
+ await updateCodexModelProvider(model);
656
+ console.log(ansis.green(`\u2714 ${i18n.t("configuration:modelConfigured") || "Default model configured"}`));
657
+ }
658
+ async function configureCodexAiMemoryFeature() {
659
+ ensureI18nInitialized();
660
+ const { option } = await inquirer.prompt({
661
+ type: "list",
662
+ name: "option",
663
+ message: i18n.t("configuration:selectMemoryOption") || "Select configuration option",
664
+ choices: addNumbersToChoices([
665
+ {
666
+ name: i18n.t("configuration:configureAiLanguage") || "Configure AI output language",
667
+ value: "language"
668
+ },
669
+ {
670
+ name: i18n.t("configuration:configureSystemPromptStyle") || "Configure global AI system prompt style",
671
+ value: "systemPrompt"
672
+ }
673
+ ])
674
+ });
675
+ if (!option) {
676
+ return;
677
+ }
678
+ if (option === "language") {
679
+ const zcfConfig = readZcfConfig();
680
+ const existingLang = zcfConfig?.aiOutputLang;
681
+ if (existingLang) {
682
+ console.log(
683
+ `
684
+ ${ansis.blue(`\u2139 ${i18n.t("configuration:existingLanguageConfig") || "Existing AI output language configuration"}`)}`
685
+ );
686
+ console.log(ansis.gray(` ${i18n.t("configuration:currentLanguage") || "Current language"}: ${existingLang}
687
+ `));
688
+ const { modify } = await inquirer.prompt({
689
+ type: "confirm",
690
+ name: "modify",
691
+ message: i18n.t("configuration:modifyLanguage") || "Modify AI output language?",
692
+ default: false
693
+ });
694
+ if (!modify) {
695
+ console.log(ansis.green(`\u2714 ${i18n.t("configuration:keepLanguage") || "Keeping existing language configuration"}`));
696
+ await ensureLanguageDirectiveInAgents(existingLang);
697
+ return;
698
+ }
699
+ }
700
+ const { selectAiOutputLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aM; });
701
+ const aiOutputLang = await selectAiOutputLanguage();
702
+ await updateCodexLanguageDirective(aiOutputLang);
703
+ updateZcfConfig({ aiOutputLang });
704
+ console.log(ansis.green(`\u2714 ${i18n.t("configuration:aiLanguageConfigured") || "AI output language configured"}`));
705
+ } else if (option === "systemPrompt") {
706
+ const zcfConfig = readZcfConfig();
707
+ const currentLang = zcfConfig?.aiOutputLang || "English";
708
+ const { runCodexSystemPromptSelection } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aN; });
709
+ await runCodexSystemPromptSelection();
710
+ await ensureLanguageDirectiveInAgents(currentLang);
711
+ console.log(ansis.green(`\u2714 ${i18n.t("configuration:systemPromptConfigured")}`));
712
+ }
713
+ }
714
+ async function updateCodexModelProvider(modelProvider) {
715
+ const { readCodexConfig, writeCodexConfig, backupCodexConfig, getBackupMessage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aN; });
716
+ const backupPath = backupCodexConfig();
717
+ if (backupPath) {
718
+ console.log(ansis.gray(getBackupMessage(backupPath)));
719
+ }
720
+ const existingConfig = readCodexConfig();
721
+ const updatedConfig = {
722
+ ...existingConfig,
723
+ model: modelProvider,
724
+ // Set the model field
725
+ modelProvider: existingConfig?.modelProvider || null,
726
+ // Preserve existing API provider
727
+ providers: existingConfig?.providers || [],
728
+ mcpServices: existingConfig?.mcpServices || [],
729
+ managed: true,
730
+ otherConfig: existingConfig?.otherConfig || [],
731
+ modelProviderCommented: existingConfig?.modelProviderCommented
732
+ };
733
+ writeCodexConfig(updatedConfig);
734
+ }
735
+ async function ensureLanguageDirectiveInAgents(aiOutputLang) {
736
+ const { readFile, writeFile, exists } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aL; });
737
+ const { homedir } = await import('node:os');
738
+ const { join } = await import('pathe');
739
+ const CODEX_AGENTS_FILE = join(homedir(), ".codex", "AGENTS.md");
740
+ if (!exists(CODEX_AGENTS_FILE)) {
741
+ console.log(ansis.yellow(i18n.t("codex:agentsFileNotFound")));
742
+ return;
743
+ }
744
+ const content = readFile(CODEX_AGENTS_FILE);
745
+ const languageLabels = {
746
+ "Chinese": "Chinese-simplified",
747
+ "English": "English",
748
+ "zh-CN": "Chinese-simplified",
749
+ "en": "English"
750
+ };
751
+ const langLabel = languageLabels[aiOutputLang] || aiOutputLang;
752
+ const hasLanguageDirective = /\*\*Most Important:\s*Always respond in [^*]+\*\*/i.test(content);
753
+ if (!hasLanguageDirective) {
754
+ const { backupCodexAgents, getBackupMessage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aN; });
755
+ const backupPath = backupCodexAgents();
756
+ if (backupPath) {
757
+ console.log(ansis.gray(getBackupMessage(backupPath)));
758
+ }
759
+ let updatedContent = content;
760
+ if (!updatedContent.endsWith("\n")) {
761
+ updatedContent += "\n";
762
+ }
763
+ updatedContent += `
764
+ **Most Important:Always respond in ${langLabel}**
765
+ `;
766
+ writeFile(CODEX_AGENTS_FILE, updatedContent);
767
+ console.log(ansis.gray(` ${i18n.t("configuration:addedLanguageDirective")}: ${langLabel}`));
768
+ }
769
+ }
770
+ async function updateCodexLanguageDirective(aiOutputLang) {
771
+ const { readFile, writeFile, exists } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aL; });
772
+ const { backupCodexAgents, getBackupMessage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aN; });
773
+ const { homedir } = await import('node:os');
774
+ const { join } = await import('pathe');
775
+ const CODEX_AGENTS_FILE = join(homedir(), ".codex", "AGENTS.md");
776
+ if (!exists(CODEX_AGENTS_FILE)) {
777
+ console.log(ansis.yellow(i18n.t("codex:agentsFileNotFound")));
778
+ return;
779
+ }
780
+ const backupPath = backupCodexAgents();
781
+ if (backupPath) {
782
+ console.log(ansis.gray(getBackupMessage(backupPath)));
783
+ }
784
+ let content = readFile(CODEX_AGENTS_FILE);
785
+ const languageLabels = {
786
+ "Chinese": "Chinese-simplified",
787
+ "English": "English",
788
+ "zh-CN": "Chinese-simplified",
789
+ "en": "English"
790
+ };
791
+ const langLabel = languageLabels[aiOutputLang] || aiOutputLang;
792
+ content = content.replace(/\*\*Most Important:\s*Always respond in [^*]+\*\*\s*/g, "");
793
+ if (!content.endsWith("\n")) {
794
+ content += "\n";
795
+ }
796
+ content += `
797
+ **Most Important:Always respond in ${langLabel}**
798
+ `;
799
+ writeFile(CODEX_AGENTS_FILE, content);
800
+ }
591
801
  async function configureEnvPermissionFeature() {
592
802
  ensureI18nInitialized();
593
803
  const { choice } = await inquirer.prompt({
@@ -849,36 +1059,6 @@ async function checkUpdates(options = {}) {
849
1059
  }
850
1060
  }
851
1061
 
852
- async function moveToTrash(paths) {
853
- const pathArray = Array.isArray(paths) ? paths : [paths];
854
- const results = [];
855
- for (const path of pathArray) {
856
- try {
857
- const exists = await pathExists(path);
858
- if (!exists) {
859
- results.push({
860
- success: false,
861
- path,
862
- error: "Path does not exist"
863
- });
864
- continue;
865
- }
866
- await trash(path);
867
- results.push({
868
- success: true,
869
- path
870
- });
871
- } catch (error) {
872
- results.push({
873
- success: false,
874
- path,
875
- error: error.message || "Unknown error occurred"
876
- });
877
- }
878
- }
879
- return results;
880
- }
881
-
882
1062
  class ZcfUninstaller {
883
1063
  _lang;
884
1064
  // Reserved for future i18n support
@@ -1223,13 +1403,14 @@ class ZcfUninstaller {
1223
1403
  warnings: []
1224
1404
  };
1225
1405
  try {
1226
- const zcfConfigPath = join(homedir(), ".zcf-config.json");
1406
+ const zcfConfigPath = ZCF_CONFIG_FILE;
1407
+ const relativeName = zcfConfigPath.replace(homedir(), "~");
1227
1408
  if (await pathExists(zcfConfigPath)) {
1228
1409
  const trashResult = await moveToTrash(zcfConfigPath);
1229
1410
  if (!trashResult[0]?.success) {
1230
1411
  result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
1231
1412
  }
1232
- result.removed.push(".zcf-config.json");
1413
+ result.removed.push(relativeName);
1233
1414
  result.success = true;
1234
1415
  } else {
1235
1416
  result.warnings.push(i18n.t("uninstall:zcfConfigNotFound"));
@@ -1615,33 +1796,46 @@ function displayUninstallResult(mode, results) {
1615
1796
  console.log("");
1616
1797
  }
1617
1798
 
1799
+ function resolveCodeToolType(optionValue, savedValue) {
1800
+ if (isCodeToolType(optionValue)) {
1801
+ return optionValue;
1802
+ }
1803
+ if (savedValue && isCodeToolType(savedValue)) {
1804
+ return savedValue;
1805
+ }
1806
+ return DEFAULT_CODE_TOOL_TYPE;
1807
+ }
1618
1808
  async function update(options = {}) {
1619
1809
  try {
1620
1810
  if (!options.skipBanner) {
1621
1811
  displayBanner(i18n.t("cli:banner.updateSubtitle"));
1622
1812
  }
1623
1813
  const zcfConfig = readZcfConfig();
1624
- let configLang = options.configLang;
1625
- if (!configLang) {
1626
- const LANG_HINT_KEYS = {
1627
- "zh-CN": i18n.t("language:configLangHint.zh-CN"),
1628
- "en": i18n.t("language:configLangHint.en")
1629
- };
1630
- const { lang } = await inquirer.prompt({
1631
- type: "list",
1632
- name: "lang",
1633
- message: i18n.t("language:updateConfigLangPrompt"),
1634
- choices: addNumbersToChoices(SUPPORTED_LANGS.map((l) => ({
1635
- name: `${LANG_LABELS[l]} - ${LANG_HINT_KEYS[l]}`,
1636
- value: l
1637
- })))
1638
- });
1639
- if (!lang) {
1640
- console.log(ansis.yellow(i18n.t("common:cancelled")));
1641
- process.exit(0);
1814
+ const codeToolType = resolveCodeToolType(options.codeType, zcfConfig?.codeToolType);
1815
+ options.codeType = codeToolType;
1816
+ if (codeToolType === "codex") {
1817
+ await runCodexUpdate();
1818
+ const newPreferredLang = options.configLang || zcfConfig?.preferredLang;
1819
+ if (newPreferredLang) {
1820
+ updateZcfConfig({
1821
+ version,
1822
+ preferredLang: newPreferredLang,
1823
+ codeToolType
1824
+ });
1825
+ } else {
1826
+ updateZcfConfig({
1827
+ version,
1828
+ codeToolType
1829
+ });
1642
1830
  }
1643
- configLang = lang;
1831
+ return;
1644
1832
  }
1833
+ const { resolveTemplateLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aM; });
1834
+ const configLang = await resolveTemplateLanguage(
1835
+ options.configLang,
1836
+ // Command line option
1837
+ zcfConfig
1838
+ );
1645
1839
  const aiOutputLang = await resolveAiOutputLanguage(i18n.language, options.aiOutputLang, zcfConfig);
1646
1840
  console.log(ansis.cyan(`
1647
1841
  ${i18n.t("configuration:updatingPrompts")}
@@ -1651,7 +1845,10 @@ ${i18n.t("configuration:updatingPrompts")}
1651
1845
  await checkClaudeCodeVersionAndPrompt(false);
1652
1846
  updateZcfConfig({
1653
1847
  version,
1654
- aiOutputLang
1848
+ templateLang: configLang,
1849
+ // 保存模板语言选择
1850
+ aiOutputLang,
1851
+ codeToolType
1655
1852
  });
1656
1853
  } catch (error) {
1657
1854
  if (!handleExitPromptError(error)) {
@@ -1660,156 +1857,321 @@ ${i18n.t("configuration:updatingPrompts")}
1660
1857
  }
1661
1858
  }
1662
1859
 
1860
+ const CODE_TOOL_LABELS = {
1861
+ "claude-code": "Claude Code",
1862
+ "codex": "Codex"
1863
+ };
1864
+ const CODE_TOOL_BANNERS = {
1865
+ "claude-code": "for Claude Code",
1866
+ "codex": "for Codex"
1867
+ };
1868
+ function getCurrentCodeTool() {
1869
+ const config = readZcfConfig();
1870
+ if (config?.codeToolType && isCodeToolType(config.codeToolType)) {
1871
+ return config.codeToolType;
1872
+ }
1873
+ return DEFAULT_CODE_TOOL_TYPE;
1874
+ }
1875
+ function printSeparator() {
1876
+ console.log(`
1877
+ ${ansis.dim("\u2500".repeat(50))}
1878
+ `);
1879
+ }
1880
+ function getCodeToolLabel(codeTool) {
1881
+ return CODE_TOOL_LABELS[codeTool] || codeTool;
1882
+ }
1883
+ async function promptCodeToolSelection(current) {
1884
+ const choices = addNumbersToChoices(Object.entries(CODE_TOOL_LABELS).map(([value, label]) => ({
1885
+ name: label,
1886
+ value,
1887
+ short: label
1888
+ })));
1889
+ const { tool } = await inquirer.prompt({
1890
+ type: "list",
1891
+ name: "tool",
1892
+ message: i18n.t("menu:switchCodeToolPrompt"),
1893
+ default: current,
1894
+ choices
1895
+ });
1896
+ if (!tool) {
1897
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
1898
+ return null;
1899
+ }
1900
+ return tool;
1901
+ }
1902
+ async function handleCodeToolSwitch(current) {
1903
+ const newTool = await promptCodeToolSelection(current);
1904
+ if (!newTool || newTool === current) {
1905
+ return false;
1906
+ }
1907
+ updateZcfConfig({ codeToolType: newTool });
1908
+ console.log(ansis.green(`\u2714 ${i18n.t("menu:codeToolSwitched", { tool: getCodeToolLabel(newTool) })}`));
1909
+ return true;
1910
+ }
1911
+ function printOtherToolsSection() {
1912
+ console.log(` --------- ${i18n.t("menu:menuSections.otherTools")} ----------`);
1913
+ console.log(
1914
+ ` ${ansis.cyan("R.")} ${i18n.t("menu:menuOptions.ccrManagement")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.ccrManagement")}`)}`
1915
+ );
1916
+ console.log(
1917
+ ` ${ansis.cyan("U.")} ${i18n.t("menu:menuOptions.ccusage")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.ccusage")}`)}`
1918
+ );
1919
+ console.log(
1920
+ ` ${ansis.cyan("L.")} ${i18n.t("menu:menuOptions.cometixLine")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.cometixLine")}`)}`
1921
+ );
1922
+ console.log("");
1923
+ }
1924
+ function printZcfSection(options) {
1925
+ console.log(" ------------ ZCF ------------");
1926
+ console.log(
1927
+ ` ${ansis.cyan("0.")} ${i18n.t("menu:menuOptions.changeLanguage")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.changeLanguage")}`)}`
1928
+ );
1929
+ console.log(
1930
+ ` ${ansis.cyan("S.")} ${i18n.t("menu:menuOptions.switchCodeTool")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.switchCodeTool")}`)}`
1931
+ );
1932
+ console.log(
1933
+ ` ${ansis.cyan("-.")} ${options.uninstallOption} ${ansis.gray(`- ${options.uninstallDescription}`)}`
1934
+ );
1935
+ console.log(
1936
+ ` ${ansis.cyan("+.")} ${options.updateOption} ${ansis.gray(`- ${options.updateDescription}`)}`
1937
+ );
1938
+ console.log(` ${ansis.red("Q.")} ${ansis.red(i18n.t("menu:menuOptions.exit"))}`);
1939
+ console.log("");
1940
+ }
1941
+ async function showClaudeCodeMenu() {
1942
+ console.log(ansis.cyan(i18n.t("menu:selectFunction")));
1943
+ console.log(" -------- Claude Code --------");
1944
+ console.log(
1945
+ ` ${ansis.cyan("1.")} ${i18n.t("menu:menuOptions.fullInit")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.fullInit")}`)}`
1946
+ );
1947
+ console.log(
1948
+ ` ${ansis.cyan("2.")} ${i18n.t("menu:menuOptions.importWorkflow")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.importWorkflow")}`)}`
1949
+ );
1950
+ console.log(
1951
+ ` ${ansis.cyan("3.")} ${i18n.t("menu:menuOptions.configureApiOrCcr")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureApiOrCcr")}`)}`
1952
+ );
1953
+ console.log(
1954
+ ` ${ansis.cyan("4.")} ${i18n.t("menu:menuOptions.configureMcp")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureMcp")}`)}`
1955
+ );
1956
+ console.log(
1957
+ ` ${ansis.cyan("5.")} ${i18n.t("menu:menuOptions.configureModel")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureModel")}`)}`
1958
+ );
1959
+ console.log(
1960
+ ` ${ansis.cyan("6.")} ${i18n.t("menu:menuOptions.configureAiMemory")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureAiMemory")}`)}`
1961
+ );
1962
+ console.log(
1963
+ ` ${ansis.cyan("7.")} ${i18n.t("menu:menuOptions.configureEnvPermission")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureEnvPermission")}`)}`
1964
+ );
1965
+ console.log("");
1966
+ printOtherToolsSection();
1967
+ printZcfSection({
1968
+ uninstallOption: i18n.t("menu:menuOptions.uninstall"),
1969
+ uninstallDescription: i18n.t("menu:menuDescriptions.uninstall"),
1970
+ updateOption: i18n.t("menu:menuOptions.checkUpdates"),
1971
+ updateDescription: i18n.t("menu:menuDescriptions.checkUpdates")
1972
+ });
1973
+ const { choice } = await inquirer.prompt({
1974
+ type: "input",
1975
+ name: "choice",
1976
+ message: i18n.t("common:enterChoice"),
1977
+ validate: (value) => {
1978
+ const valid = ["1", "2", "3", "4", "5", "6", "7", "r", "R", "u", "U", "l", "L", "0", "-", "+", "s", "S", "q", "Q"];
1979
+ return valid.includes(value) || i18n.t("common:invalidChoice");
1980
+ }
1981
+ });
1982
+ if (!choice) {
1983
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
1984
+ return "exit";
1985
+ }
1986
+ const normalized = choice.toLowerCase();
1987
+ switch (normalized) {
1988
+ case "1":
1989
+ await init({ skipBanner: true });
1990
+ break;
1991
+ case "2":
1992
+ await update({ skipBanner: true });
1993
+ break;
1994
+ case "3":
1995
+ await configureApiFeature();
1996
+ break;
1997
+ case "4":
1998
+ await configureMcpFeature();
1999
+ break;
2000
+ case "5":
2001
+ await configureDefaultModelFeature();
2002
+ break;
2003
+ case "6":
2004
+ await configureAiMemoryFeature();
2005
+ break;
2006
+ case "7":
2007
+ await configureEnvPermissionFeature();
2008
+ break;
2009
+ case "r":
2010
+ await runCcrMenuFeature();
2011
+ printSeparator();
2012
+ return void 0;
2013
+ case "u":
2014
+ await runCcusageFeature();
2015
+ printSeparator();
2016
+ return void 0;
2017
+ case "l":
2018
+ await runCometixMenuFeature();
2019
+ printSeparator();
2020
+ return void 0;
2021
+ case "0": {
2022
+ const currentLang = i18n.language;
2023
+ await changeScriptLanguageFeature(currentLang);
2024
+ printSeparator();
2025
+ return void 0;
2026
+ }
2027
+ case "-":
2028
+ await uninstall();
2029
+ printSeparator();
2030
+ return void 0;
2031
+ case "+":
2032
+ await checkUpdates();
2033
+ printSeparator();
2034
+ return void 0;
2035
+ case "s": {
2036
+ const switched = await handleCodeToolSwitch("claude-code");
2037
+ if (switched) {
2038
+ return "switch";
2039
+ }
2040
+ printSeparator();
2041
+ return void 0;
2042
+ }
2043
+ case "q":
2044
+ console.log(ansis.cyan(i18n.t("common:goodbye")));
2045
+ return "exit";
2046
+ default:
2047
+ return void 0;
2048
+ }
2049
+ printSeparator();
2050
+ const { continue: shouldContinue } = await inquirer.prompt({
2051
+ type: "confirm",
2052
+ name: "continue",
2053
+ message: i18n.t("common:returnToMenu"),
2054
+ default: true
2055
+ });
2056
+ if (!shouldContinue) {
2057
+ console.log(ansis.cyan(i18n.t("common:goodbye")));
2058
+ return "exit";
2059
+ }
2060
+ return void 0;
2061
+ }
2062
+ async function showCodexMenu() {
2063
+ console.log(ansis.cyan(i18n.t("menu:selectFunction")));
2064
+ console.log(" -------- Codex --------");
2065
+ console.log(
2066
+ ` ${ansis.cyan("1.")} ${i18n.t("menu:menuOptions.codexFullInit")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexFullInit")}`)}`
2067
+ );
2068
+ console.log(
2069
+ ` ${ansis.cyan("2.")} ${i18n.t("menu:menuOptions.codexImportWorkflow")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexImportWorkflow")}`)}`
2070
+ );
2071
+ console.log(
2072
+ ` ${ansis.cyan("3.")} ${i18n.t("menu:menuOptions.codexConfigureApi")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexConfigureApi")}`)}`
2073
+ );
2074
+ console.log(
2075
+ ` ${ansis.cyan("4.")} ${i18n.t("menu:menuOptions.codexConfigureMcp")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexConfigureMcp")}`)}`
2076
+ );
2077
+ console.log(
2078
+ ` ${ansis.cyan("5.")} ${i18n.t("menu:menuOptions.codexConfigureModel")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexConfigureModel")}`)}`
2079
+ );
2080
+ console.log(
2081
+ ` ${ansis.cyan("6.")} ${i18n.t("menu:menuOptions.codexConfigureAiMemory")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexConfigureAiMemory")}`)}`
2082
+ );
2083
+ console.log("");
2084
+ printZcfSection({
2085
+ uninstallOption: i18n.t("menu:menuOptions.codexUninstall"),
2086
+ uninstallDescription: i18n.t("menu:menuDescriptions.codexUninstall"),
2087
+ updateOption: i18n.t("menu:menuOptions.codexCheckUpdates"),
2088
+ updateDescription: i18n.t("menu:menuDescriptions.codexCheckUpdates")
2089
+ });
2090
+ const { choice } = await inquirer.prompt({
2091
+ type: "input",
2092
+ name: "choice",
2093
+ message: i18n.t("common:enterChoice"),
2094
+ validate: (value) => {
2095
+ const valid = ["1", "2", "3", "4", "5", "6", "0", "-", "+", "s", "S", "q", "Q"];
2096
+ return valid.includes(value) || i18n.t("common:invalidChoice");
2097
+ }
2098
+ });
2099
+ if (!choice) {
2100
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
2101
+ return "exit";
2102
+ }
2103
+ const normalized = choice.toLowerCase();
2104
+ switch (normalized) {
2105
+ case "1":
2106
+ await runCodexFullInit();
2107
+ break;
2108
+ case "2":
2109
+ await runCodexWorkflowImport();
2110
+ break;
2111
+ case "3":
2112
+ await configureCodexApi();
2113
+ break;
2114
+ case "4":
2115
+ await configureCodexMcp();
2116
+ break;
2117
+ case "5":
2118
+ await configureCodexDefaultModelFeature();
2119
+ break;
2120
+ case "6":
2121
+ await configureCodexAiMemoryFeature();
2122
+ break;
2123
+ case "0": {
2124
+ const currentLang = i18n.language;
2125
+ await changeScriptLanguageFeature(currentLang);
2126
+ printSeparator();
2127
+ return void 0;
2128
+ }
2129
+ case "-":
2130
+ await runCodexUninstall();
2131
+ printSeparator();
2132
+ return void 0;
2133
+ case "+":
2134
+ await runCodexUpdate();
2135
+ printSeparator();
2136
+ return void 0;
2137
+ case "s": {
2138
+ const switched = await handleCodeToolSwitch("codex");
2139
+ if (switched) {
2140
+ return "switch";
2141
+ }
2142
+ printSeparator();
2143
+ return void 0;
2144
+ }
2145
+ case "q":
2146
+ console.log(ansis.cyan(i18n.t("common:goodbye")));
2147
+ return "exit";
2148
+ default:
2149
+ return void 0;
2150
+ }
2151
+ printSeparator();
2152
+ const { continue: shouldContinue } = await inquirer.prompt({
2153
+ type: "confirm",
2154
+ name: "continue",
2155
+ message: i18n.t("common:returnToMenu"),
2156
+ default: true
2157
+ });
2158
+ if (!shouldContinue) {
2159
+ console.log(ansis.cyan(i18n.t("common:goodbye")));
2160
+ return "exit";
2161
+ }
2162
+ return void 0;
2163
+ }
1663
2164
  async function showMainMenu() {
1664
2165
  try {
1665
- displayBannerWithInfo();
1666
2166
  let exitMenu = false;
1667
2167
  while (!exitMenu) {
1668
- console.log(ansis.cyan(i18n.t("menu:selectFunction")));
1669
- console.log(" -------- Claude Code --------");
1670
- console.log(
1671
- ` ${ansis.cyan("1.")} ${i18n.t("menu:menuOptions.fullInit")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.fullInit")}`)}`
1672
- );
1673
- console.log(
1674
- ` ${ansis.cyan("2.")} ${i18n.t("menu:menuOptions.importWorkflow")} ${ansis.gray(
1675
- `- ${i18n.t("menu:menuDescriptions.importWorkflow")}`
1676
- )}`
1677
- );
1678
- console.log(
1679
- ` ${ansis.cyan("3.")} ${i18n.t("menu:menuOptions.configureApiOrCcr")} ${ansis.gray(
1680
- `- ${i18n.t("menu:menuDescriptions.configureApiOrCcr")}`
1681
- )}`
1682
- );
1683
- console.log(
1684
- ` ${ansis.cyan("4.")} ${i18n.t("menu:menuOptions.configureMcp")} ${ansis.gray(
1685
- `- ${i18n.t("menu:menuDescriptions.configureMcp")}`
1686
- )}`
1687
- );
1688
- console.log(
1689
- ` ${ansis.cyan("5.")} ${i18n.t("menu:menuOptions.configureModel")} ${ansis.gray(
1690
- `- ${i18n.t("menu:menuDescriptions.configureModel")}`
1691
- )}`
1692
- );
1693
- console.log(
1694
- ` ${ansis.cyan("6.")} ${i18n.t("menu:menuOptions.configureAiMemory")} ${ansis.gray(
1695
- `- ${i18n.t("menu:menuDescriptions.configureAiMemory")}`
1696
- )}`
1697
- );
1698
- console.log(
1699
- ` ${ansis.cyan("7.")} ${i18n.t("menu:menuOptions.configureEnvPermission")} ${ansis.gray(
1700
- `- ${i18n.t("menu:menuDescriptions.configureEnvPermission")}`
1701
- )}`
1702
- );
1703
- console.log("");
1704
- console.log(` --------- ${i18n.t("menu:menuSections.otherTools")} ----------`);
1705
- console.log(
1706
- ` ${ansis.cyan("R.")} ${i18n.t("menu:menuOptions.ccrManagement")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.ccrManagement")}`)}`
1707
- );
1708
- console.log(
1709
- ` ${ansis.cyan("U.")} ${i18n.t("menu:menuOptions.ccusage")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.ccusage")}`)}`
1710
- );
1711
- console.log(
1712
- ` ${ansis.cyan("L.")} ${i18n.t("menu:menuOptions.cometixLine")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.cometixLine")}`)}`
1713
- );
1714
- console.log("");
1715
- console.log(" ------------ ZCF ------------");
1716
- console.log(
1717
- ` ${ansis.cyan("0.")} ${i18n.t("menu:menuOptions.changeLanguage")} ${ansis.gray(
1718
- `- ${i18n.t("menu:menuDescriptions.changeLanguage")}`
1719
- )}`
1720
- );
1721
- console.log(
1722
- ` ${ansis.cyan("-.")} ${i18n.t("menu:menuOptions.uninstall")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.uninstall")}`)}`
1723
- );
1724
- console.log(
1725
- ` ${ansis.cyan("+.")} ${i18n.t("menu:menuOptions.checkUpdates")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.checkUpdates")}`)}`
1726
- );
1727
- console.log(` ${ansis.red("Q.")} ${ansis.red(i18n.t("menu:menuOptions.exit"))}`);
1728
- console.log("");
1729
- const { choice } = await inquirer.prompt({
1730
- type: "input",
1731
- name: "choice",
1732
- message: i18n.t("common:enterChoice"),
1733
- validate: (value) => {
1734
- const valid = ["1", "2", "3", "4", "5", "6", "7", "r", "R", "u", "U", "l", "L", "0", "-", "+", "q", "Q"];
1735
- return valid.includes(value) || i18n.t("common:invalidChoice");
1736
- }
1737
- });
1738
- if (!choice) {
1739
- console.log(ansis.yellow(i18n.t("common:cancelled")));
2168
+ const codeTool = getCurrentCodeTool();
2169
+ displayBannerWithInfo(CODE_TOOL_BANNERS[codeTool] || "ZCF");
2170
+ const result = codeTool === "codex" ? await showCodexMenu() : await showClaudeCodeMenu();
2171
+ if (result === "exit") {
1740
2172
  exitMenu = true;
1741
- break;
1742
- }
1743
- switch (choice.toLowerCase()) {
1744
- case "1":
1745
- await init({ skipBanner: true });
1746
- break;
1747
- case "2":
1748
- await update({ skipBanner: true });
1749
- break;
1750
- case "3":
1751
- await configureApiFeature();
1752
- break;
1753
- case "4":
1754
- await configureMcpFeature();
1755
- break;
1756
- case "5":
1757
- await configureDefaultModelFeature();
1758
- break;
1759
- case "6":
1760
- await configureAiMemoryFeature();
1761
- break;
1762
- case "7":
1763
- await configureEnvPermissionFeature();
1764
- break;
1765
- case "r":
1766
- case "R":
1767
- await runCcrMenuFeature();
1768
- break;
1769
- case "u":
1770
- case "U":
1771
- await runCcusageFeature();
1772
- break;
1773
- case "l":
1774
- case "L":
1775
- await runCometixMenuFeature();
1776
- break;
1777
- case "0": {
1778
- const currentLang = i18n.language;
1779
- await changeScriptLanguageFeature(currentLang);
1780
- break;
1781
- }
1782
- case "-":
1783
- await uninstall();
1784
- break;
1785
- case "+":
1786
- await checkUpdates();
1787
- break;
1788
- case "q":
1789
- exitMenu = true;
1790
- console.log(ansis.cyan(i18n.t("common:goodbye")));
1791
- break;
1792
- }
1793
- if (!exitMenu && choice.toLowerCase() !== "q") {
1794
- if (choice === "0" || choice === "-" || choice === "+" || choice.toLowerCase() === "u" || choice.toLowerCase() === "r" || choice.toLowerCase() === "l") {
1795
- console.log(`
1796
- ${ansis.dim("\u2500".repeat(50))}
1797
- `);
1798
- continue;
1799
- }
1800
- console.log(`
1801
- ${ansis.dim("\u2500".repeat(50))}
1802
- `);
1803
- const { continue: shouldContinue } = await inquirer.prompt({
1804
- type: "confirm",
1805
- name: "continue",
1806
- message: i18n.t("common:returnToMenu"),
1807
- default: true
1808
- });
1809
- if (!shouldContinue) {
1810
- exitMenu = true;
1811
- console.log(ansis.cyan(i18n.t("common:goodbye")));
1812
- }
2173
+ } else if (result === "switch") {
2174
+ continue;
1813
2175
  }
1814
2176
  }
1815
2177
  } catch (error) {
@@ -1835,6 +2197,103 @@ async function ccr(options = {}) {
1835
2197
  }
1836
2198
  }
1837
2199
 
2200
+ async function configSwitchCommand(options) {
2201
+ try {
2202
+ ensureI18nInitialized();
2203
+ if (options.list) {
2204
+ await handleListProviders();
2205
+ return;
2206
+ }
2207
+ if (options.provider) {
2208
+ await handleDirectSwitch(options.provider);
2209
+ return;
2210
+ }
2211
+ await handleInteractiveSwitch();
2212
+ } catch (error) {
2213
+ if (process.env.NODE_ENV === "test" || process.env.VITEST) {
2214
+ throw error;
2215
+ }
2216
+ handleGeneralError(error);
2217
+ }
2218
+ }
2219
+ async function handleListProviders() {
2220
+ const providers = await listCodexProviders();
2221
+ const currentProvider = await getCurrentCodexProvider();
2222
+ console.log(ansis.cyan(i18n.t("codex:listProvidersTitle")));
2223
+ console.log("");
2224
+ if (providers.length === 0) {
2225
+ console.log(ansis.yellow(i18n.t("codex:noProvidersAvailable")));
2226
+ return;
2227
+ }
2228
+ if (currentProvider) {
2229
+ console.log(ansis.green(`${i18n.t("codex:currentProvider", { provider: currentProvider })}`));
2230
+ console.log("");
2231
+ }
2232
+ for (const provider of providers) {
2233
+ const marker = currentProvider === provider.id ? ansis.green("\u25CF ") : " ";
2234
+ console.log(`${marker}${ansis.cyan(provider.id)} - ${provider.name}`);
2235
+ console.log(` ${ansis.gray(provider.baseUrl)}`);
2236
+ }
2237
+ }
2238
+ async function handleDirectSwitch(providerId) {
2239
+ await switchCodexProvider(providerId);
2240
+ }
2241
+ async function handleInteractiveSwitch() {
2242
+ const providers = await listCodexProviders();
2243
+ if (!providers || providers.length === 0) {
2244
+ console.log(ansis.yellow(i18n.t("codex:noProvidersAvailable")));
2245
+ return;
2246
+ }
2247
+ const existingConfig = readCodexConfig();
2248
+ const currentProvider = existingConfig?.modelProvider;
2249
+ const isCommented = existingConfig?.modelProviderCommented;
2250
+ const createApiConfigChoices = (providers2, currentProvider2, isCommented2) => {
2251
+ const choices2 = [];
2252
+ const isOfficialMode = !currentProvider2 || isCommented2;
2253
+ choices2.push({
2254
+ name: isOfficialMode ? `${ansis.green("\u25CF ")}${i18n.t("codex:useOfficialLogin")} ${ansis.yellow("(\u5F53\u524D)")}` : ` ${i18n.t("codex:useOfficialLogin")}`,
2255
+ value: "official"
2256
+ });
2257
+ providers2.forEach((provider) => {
2258
+ const isCurrent = currentProvider2 === provider.id && !isCommented2;
2259
+ choices2.push({
2260
+ name: isCurrent ? `${ansis.green("\u25CF ")}${provider.name} - ${ansis.gray(provider.id)} ${ansis.yellow("(\u5F53\u524D)")}` : ` ${provider.name} - ${ansis.gray(provider.id)}`,
2261
+ value: provider.id
2262
+ });
2263
+ });
2264
+ return choices2;
2265
+ };
2266
+ const choices = createApiConfigChoices(providers, currentProvider, isCommented);
2267
+ try {
2268
+ const { selectedConfig } = await inquirer.prompt([{
2269
+ type: "list",
2270
+ name: "selectedConfig",
2271
+ message: i18n.t("codex:apiConfigSwitchPrompt"),
2272
+ choices: addNumbersToChoices(choices)
2273
+ }]);
2274
+ if (!selectedConfig) {
2275
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
2276
+ return;
2277
+ }
2278
+ let success = false;
2279
+ if (selectedConfig === "official") {
2280
+ success = await switchToOfficialLogin();
2281
+ } else {
2282
+ success = await switchToProvider(selectedConfig);
2283
+ }
2284
+ if (!success) {
2285
+ console.log(ansis.red(i18n.t("common:operationFailed")));
2286
+ }
2287
+ } catch (error) {
2288
+ if (error.name === "ExitPromptError") {
2289
+ console.log(ansis.cyan(`
2290
+ ${i18n.t("common:goodbye")}`));
2291
+ return;
2292
+ }
2293
+ throw error;
2294
+ }
2295
+ }
2296
+
1838
2297
  async function resolveAndSwitchLanguage(lang, options, skipPrompt = false) {
1839
2298
  const zcfConfig = await readZcfConfigAsync();
1840
2299
  const targetLang = options?.allLang || lang || options?.lang || zcfConfig?.preferredLang || (skipPrompt ? "en" : await selectScriptLanguage());
@@ -1865,7 +2324,7 @@ function extractLanguageOptions(options) {
1865
2324
  function customizeHelp(sections) {
1866
2325
  sections.unshift({
1867
2326
  title: "",
1868
- body: ansis.cyan.bold(`ZCF - Zero-Config Claude-Code Flow v${version}`)
2327
+ body: ansis.cyan.bold(`ZCF - Zero-Config Code Flow v${version}`)
1869
2328
  });
1870
2329
  sections.push({
1871
2330
  title: ansis.yellow(i18n.t("cli:help.commands")),
@@ -1907,6 +2366,7 @@ function customizeHelp(sections) {
1907
2366
  ` ${ansis.green("--workflows, -w")} <list> ${i18n.t("cli:help.optionDescriptions.workflows")} (${i18n.t("cli:help.defaults.prefix")} all workflows)`,
1908
2367
  ` ${ansis.green("--output-styles, -o")} <styles> ${i18n.t("cli:help.optionDescriptions.outputStyles")} (${i18n.t("cli:help.defaults.prefix")} all custom styles)`,
1909
2368
  ` ${ansis.green("--default-output-style, -d")} <style> ${i18n.t("cli:help.optionDescriptions.defaultOutputStyle")} (${i18n.t("cli:help.defaults.prefix")} engineer-professional)`,
2369
+ ` ${ansis.green("--code-type, -T")} <type> ${i18n.t("cli:help.optionDescriptions.codeToolType")} (claude-code, codex)`,
1910
2370
  ` ${ansis.green("--install-cometix-line, -x")} <value> ${i18n.t("cli:help.optionDescriptions.installStatuslineTool")} (${i18n.t("cli:help.defaults.prefix")} true)`
1911
2371
  ].join("\n")
1912
2372
  });
@@ -1953,10 +2413,10 @@ async function setupCommands(cli) {
1953
2413
  await initI18n(defaultLang);
1954
2414
  } catch {
1955
2415
  }
1956
- cli.command("", "Show interactive menu (default)").option("--lang, -l <lang>", "ZCF display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--config-lang, -c <lang>", "Configuration language (zh-CN, en)").option("--force, -f", "Force overwrite existing configuration").action(await withLanguageResolution(async () => {
2416
+ cli.command("", "Show interactive menu (default)").option("--lang, -l <lang>", "ZCF display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--config-lang, -c <lang>", "Configuration language (zh-CN, en)").option("--force, -f", "Force overwrite existing configuration").option("--code-type, -T <codeType>", "Select code tool type (claude-code, codex)", { default: DEFAULT_CODE_TOOL_TYPE }).action(await withLanguageResolution(async () => {
1957
2417
  await showMainMenu();
1958
2418
  }));
1959
- cli.command("init", "Initialize Claude Code configuration").alias("i").option("--lang, -l <lang>", "ZCF display language (zh-CN, en)").option("--config-lang, -c <lang>", "Configuration language (zh-CN, en)").option("--ai-output-lang, -a <lang>", "AI output language").option("--force, -f", "Force overwrite existing configuration").option("--skip-prompt, -s", "Skip all interactive prompts (non-interactive mode)").option("--config-action, -r <action>", `Config handling (new/backup/merge/docs-only/skip), ${i18n.t("cli:help.defaults.prefix")} backup`).option("--api-type, -t <type>", "API type (auth_token/api_key/ccr_proxy/skip)").option("--api-key, -k <key>", "API key (used for both API key and auth token types)").option("--api-url, -u <url>", "Custom API URL").option("--mcp-services, -m <services>", `Comma-separated MCP services to install (context7,mcp-deepwiki,Playwright,exa), "skip" to skip all, "all" for all non-key services, ${i18n.t("cli:help.defaults.prefix")} all`).option("--workflows, -w <workflows>", `Comma-separated workflows to install (sixStepsWorkflow,featPlanUx,gitWorkflow,bmadWorkflow), "skip" to skip all, "all" for all workflows, ${i18n.t("cli:help.defaults.prefix")} all`).option("--output-styles, -o <styles>", `Comma-separated output styles (engineer-professional,nekomata-engineer,laowang-engineer,default,explanatory,learning), "skip" to skip all, "all" for all custom styles, ${i18n.t("cli:help.defaults.prefix")} all`).option("--default-output-style, -d <style>", `Default output style, ${i18n.t("cli:help.defaults.prefix")} engineer-professional`).option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--install-cometix-line, -x <value>", `Install CCometixLine statusline tool (true/false), ${i18n.t("cli:help.defaults.prefix")} true`).action(await withLanguageResolution(async (options) => {
2419
+ cli.command("init", "Initialize Claude Code configuration").alias("i").option("--lang, -l <lang>", "ZCF display language (zh-CN, en)").option("--config-lang, -c <lang>", "Configuration language (zh-CN, en)").option("--ai-output-lang, -a <lang>", "AI output language").option("--force, -f", "Force overwrite existing configuration").option("--skip-prompt, -s", "Skip all interactive prompts (non-interactive mode)").option("--config-action, -r <action>", `Config handling (new/backup/merge/docs-only/skip), ${i18n.t("cli:help.defaults.prefix")} backup`).option("--api-type, -t <type>", "API type (auth_token/api_key/ccr_proxy/skip)").option("--api-key, -k <key>", "API key (used for both API key and auth token types)").option("--api-url, -u <url>", "Custom API URL").option("--mcp-services, -m <services>", `Comma-separated MCP services to install (context7,mcp-deepwiki,Playwright,exa), "skip" to skip all, "all" for all non-key services, ${i18n.t("cli:help.defaults.prefix")} all`).option("--workflows, -w <workflows>", `Comma-separated workflows to install (sixStepsWorkflow,featPlanUx,gitWorkflow,bmadWorkflow), "skip" to skip all, "all" for all workflows, ${i18n.t("cli:help.defaults.prefix")} all`).option("--output-styles, -o <styles>", `Comma-separated output styles (engineer-professional,nekomata-engineer,laowang-engineer,default,explanatory,learning), "skip" to skip all, "all" for all custom styles, ${i18n.t("cli:help.defaults.prefix")} all`).option("--default-output-style, -d <style>", `Default output style, ${i18n.t("cli:help.defaults.prefix")} engineer-professional`).option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--code-type, -T <codeType>", "Select code tool type (claude-code, codex)", { default: DEFAULT_CODE_TOOL_TYPE }).option("--install-cometix-line, -x <value>", `Install CCometixLine statusline tool (true/false), ${i18n.t("cli:help.defaults.prefix")} true`).action(await withLanguageResolution(async (options) => {
1960
2420
  await init(options);
1961
2421
  }));
1962
2422
  cli.command("update", "Update Claude Code prompts only").alias("u").option("--lang, -l <lang>", "ZCF display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--config-lang, -c <lang>", "Configuration language (zh-CN, en)").action(await withLanguageResolution(async (options) => {
@@ -1968,6 +2428,12 @@ async function setupCommands(cli) {
1968
2428
  cli.command("ccu [...args]", "Run Claude Code usage analysis tool").option("--lang, -l <lang>", "ZCF display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").allowUnknownOptions().action(await withLanguageResolution(async (args) => {
1969
2429
  await executeCcusage(args);
1970
2430
  }));
2431
+ cli.command("config-switch [provider]", "Switch Codex provider or list available providers").alias("cs").option("--lang, -l <lang>", "ZCF display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--list", "List available providers").action(await withLanguageResolution(async (provider, options) => {
2432
+ await configSwitchCommand({
2433
+ provider,
2434
+ list: options.list
2435
+ });
2436
+ }));
1971
2437
  cli.command("uninstall", "Remove ZCF configurations and tools").option("--lang, -l <lang>", "ZCF display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--mode, -m <mode>", "Uninstall mode (complete/custom/interactive), default: interactive").option("--items, -i <items>", "Comma-separated items for custom uninstall mode").action(await withLanguageResolution(async (options) => {
1972
2438
  await uninstall(options);
1973
2439
  }));