zcf 2.12.12 → 3.0.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 (67) hide show
  1. package/README.md +92 -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 +1862 -374
  5. package/dist/cli.mjs +1416 -194
  6. package/dist/i18n/locales/en/cli.json +4 -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 +22 -2
  13. package/dist/i18n/locales/en/uninstall.json +56 -0
  14. package/dist/i18n/locales/zh-CN/cli.json +4 -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 +22 -2
  21. package/dist/i18n/locales/zh-CN/uninstall.json +56 -0
  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 +17 -13
  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,22 +1,26 @@
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, Z as ZCF_CONFIG_FILE, 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 displayBanner, ag as resolveAiOutputLanguage, ah as updatePromptOnly, ai as selectAndInstallWorkflows, aj as checkClaudeCodeVersionAndPrompt, ak as version, al as displayBannerWithInfo, i as init, am as readZcfConfigAsync, an as initI18n, ao as selectScriptLanguage } from './chunks/simple-config.mjs';
5
- import { existsSync, unlinkSync } from 'node:fs';
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
+ import { existsSync } from 'node:fs';
6
6
  import { homedir } from 'node:os';
7
7
  import inquirer from 'inquirer';
8
8
  import { join } from 'pathe';
9
9
  import { exec, spawn } from 'node:child_process';
10
10
  import { promisify } from 'node:util';
11
11
  import process from 'node:process';
12
- import { x } from 'tinyexec';
12
+ import { x, exec as exec$1 } from 'tinyexec';
13
+ import { pathExists } from 'fs-extra';
14
+ import { m as moveToTrash } from './shared/zcf.DGjQxTq_.mjs';
13
15
  import 'dayjs';
14
16
  import 'node:url';
15
17
  import 'ora';
16
18
  import 'semver';
19
+ import 'smol-toml';
17
20
  import 'node:fs/promises';
18
21
  import 'i18next';
19
22
  import 'i18next-fs-backend';
23
+ import 'trash';
20
24
 
21
25
  const execAsync$1 = promisify(exec);
22
26
  async function runCcrUi(apiKey) {
@@ -398,7 +402,7 @@ async function configureMcpFeature() {
398
402
  const existingConfig = readMcpConfig() || { mcpServers: {} };
399
403
  const fixedConfig = fixWindowsMcpConfig(existingConfig);
400
404
  writeMcpConfig(fixedConfig);
401
- console.log(ansis.green(`\u2714 Windows MCP configuration fixed`));
405
+ console.log(ansis.green(`\u2714 ${i18n.t("configuration:windowsMcpConfigFixed")}`));
402
406
  }
403
407
  }
404
408
  const selectedServices = await selectMcpServices();
@@ -418,9 +422,9 @@ async function configureMcpFeature() {
418
422
  let config = service.config;
419
423
  if (service.requiresApiKey) {
420
424
  const { apiKey } = await inquirer.prompt({
421
- type: "input",
425
+ type: "password",
422
426
  name: "apiKey",
423
- message: service.apiKeyPrompt,
427
+ message: service.apiKeyPrompt + i18n.t("common:inputHidden"),
424
428
  validate: async (value) => !!value || i18n.t("api:keyRequired")
425
429
  });
426
430
  if (apiKey) {
@@ -555,7 +559,7 @@ ${ansis.blue(`\u2139 ${i18n.t("configuration:existingLanguageConfig") || "Existi
555
559
  return;
556
560
  }
557
561
  }
558
- const { selectAiOutputLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.ap; });
562
+ const { selectAiOutputLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aM; });
559
563
  const aiOutputLang = await selectAiOutputLanguage();
560
564
  applyAiLanguageDirective(aiOutputLang);
561
565
  updateZcfConfig({ aiOutputLang });
@@ -564,25 +568,6 @@ ${ansis.blue(`\u2139 ${i18n.t("configuration:existingLanguageConfig") || "Existi
564
568
  await configureOutputStyle();
565
569
  }
566
570
  }
567
- async function clearZcfCacheFeature() {
568
- ensureI18nInitialized();
569
- const { confirm } = await inquirer.prompt({
570
- type: "confirm",
571
- name: "confirm",
572
- message: i18n.t("configuration:confirmClearCache") || "Clear all ZCF preferences cache?",
573
- default: false
574
- });
575
- if (!confirm) {
576
- await handleCancellation();
577
- return;
578
- }
579
- if (existsSync(ZCF_CONFIG_FILE)) {
580
- unlinkSync(ZCF_CONFIG_FILE);
581
- console.log(ansis.green(`\u2714 ${i18n.t("configuration:cacheCleared") || "ZCF cache cleared"}`));
582
- } else {
583
- console.log(ansis.yellow("No cache found"));
584
- }
585
- }
586
571
  async function changeScriptLanguageFeature(currentLang) {
587
572
  ensureI18nInitialized();
588
573
  const { lang } = await inquirer.prompt({
@@ -605,6 +590,214 @@ async function changeScriptLanguageFeature(currentLang) {
605
590
  console.log(ansis.green(`\u2714 ${i18n.t("language:languageChanged") || "Language changed"}`));
606
591
  return lang;
607
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
+ }
608
801
  async function configureEnvPermissionFeature() {
609
802
  ensureI18nInitialized();
610
803
  const { choice } = await inquirer.prompt({
@@ -866,33 +1059,783 @@ async function checkUpdates(options = {}) {
866
1059
  }
867
1060
  }
868
1061
 
1062
+ class ZcfUninstaller {
1063
+ _lang;
1064
+ // Reserved for future i18n support
1065
+ conflictResolution = /* @__PURE__ */ new Map();
1066
+ constructor(lang = "en") {
1067
+ this._lang = lang;
1068
+ this.conflictResolution.set("claude-code", ["mcps"]);
1069
+ void this._lang;
1070
+ }
1071
+ /**
1072
+ * 1. Remove outputStyle field from settings.json and output-styles directory
1073
+ */
1074
+ async removeOutputStyles() {
1075
+ const result = {
1076
+ success: false,
1077
+ removed: [],
1078
+ removedConfigs: [],
1079
+ errors: [],
1080
+ warnings: []
1081
+ };
1082
+ try {
1083
+ const settingsPath = join(homedir(), ".claude", "settings.json");
1084
+ const outputStylesPath = join(homedir(), ".claude", "output-styles");
1085
+ if (await pathExists(settingsPath)) {
1086
+ const settings = readJsonConfig(settingsPath) || {};
1087
+ if (settings.outputStyle) {
1088
+ delete settings.outputStyle;
1089
+ writeJsonConfig(settingsPath, settings);
1090
+ result.removedConfigs.push("outputStyle field from settings.json");
1091
+ }
1092
+ } else {
1093
+ result.warnings.push(i18n.t("uninstall:settingsJsonNotFound"));
1094
+ }
1095
+ if (await pathExists(outputStylesPath)) {
1096
+ const trashResult = await moveToTrash(outputStylesPath);
1097
+ if (!trashResult[0]?.success) {
1098
+ result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
1099
+ }
1100
+ result.removed.push("~/.claude/output-styles/");
1101
+ } else {
1102
+ result.warnings.push(i18n.t("uninstall:outputStylesDirectoryNotFound"));
1103
+ }
1104
+ result.success = true;
1105
+ } catch (error) {
1106
+ result.errors.push(`Failed to remove output styles: ${error.message}`);
1107
+ }
1108
+ return result;
1109
+ }
1110
+ /**
1111
+ * 2. Remove custom commands directory (commands/zcf/)
1112
+ */
1113
+ async removeCustomCommands() {
1114
+ const result = {
1115
+ success: false,
1116
+ removed: [],
1117
+ removedConfigs: [],
1118
+ errors: [],
1119
+ warnings: []
1120
+ };
1121
+ try {
1122
+ const commandsPath = join(homedir(), ".claude", "commands", "zcf");
1123
+ if (await pathExists(commandsPath)) {
1124
+ const trashResult = await moveToTrash(commandsPath);
1125
+ if (!trashResult[0]?.success) {
1126
+ result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
1127
+ }
1128
+ result.removed.push("commands/zcf/");
1129
+ result.success = true;
1130
+ } else {
1131
+ result.warnings.push(i18n.t("uninstall:commandsNotFound"));
1132
+ result.success = true;
1133
+ }
1134
+ } catch (error) {
1135
+ result.errors.push(`Failed to remove custom commands: ${error.message}`);
1136
+ }
1137
+ return result;
1138
+ }
1139
+ /**
1140
+ * 3. Remove custom agents directory (agents/zcf/)
1141
+ */
1142
+ async removeCustomAgents() {
1143
+ const result = {
1144
+ success: false,
1145
+ removed: [],
1146
+ removedConfigs: [],
1147
+ errors: [],
1148
+ warnings: []
1149
+ };
1150
+ try {
1151
+ const agentsPath = join(homedir(), ".claude", "agents", "zcf");
1152
+ if (await pathExists(agentsPath)) {
1153
+ const trashResult = await moveToTrash(agentsPath);
1154
+ if (!trashResult[0]?.success) {
1155
+ result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
1156
+ }
1157
+ result.removed.push("agents/zcf/");
1158
+ result.success = true;
1159
+ } else {
1160
+ result.warnings.push(i18n.t("uninstall:agentsNotFound"));
1161
+ result.success = true;
1162
+ }
1163
+ } catch (error) {
1164
+ result.errors.push(`Failed to remove custom agents: ${error.message}`);
1165
+ }
1166
+ return result;
1167
+ }
1168
+ /**
1169
+ * 4. Remove global memory file (CLAUDE.md)
1170
+ */
1171
+ async removeClaudeMd() {
1172
+ const result = {
1173
+ success: false,
1174
+ removed: [],
1175
+ removedConfigs: [],
1176
+ errors: [],
1177
+ warnings: []
1178
+ };
1179
+ try {
1180
+ const claudeMdPath = join(homedir(), ".claude", "CLAUDE.md");
1181
+ if (await pathExists(claudeMdPath)) {
1182
+ const trashResult = await moveToTrash(claudeMdPath);
1183
+ if (!trashResult[0]?.success) {
1184
+ result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
1185
+ }
1186
+ result.removed.push("CLAUDE.md");
1187
+ result.success = true;
1188
+ } else {
1189
+ result.warnings.push(i18n.t("uninstall:claudeMdNotFound"));
1190
+ result.success = true;
1191
+ }
1192
+ } catch (error) {
1193
+ result.errors.push(`Failed to remove CLAUDE.md: ${error.message}`);
1194
+ }
1195
+ return result;
1196
+ }
1197
+ /**
1198
+ * 5. Remove permissions and environment variables
1199
+ */
1200
+ async removePermissionsAndEnvs() {
1201
+ const result = {
1202
+ success: false,
1203
+ removed: [],
1204
+ removedConfigs: [],
1205
+ errors: [],
1206
+ warnings: []
1207
+ };
1208
+ try {
1209
+ const settingsPath = join(homedir(), ".claude", "settings.json");
1210
+ if (await pathExists(settingsPath)) {
1211
+ const settings = readJsonConfig(settingsPath) || {};
1212
+ let modified = false;
1213
+ if (settings.permissions) {
1214
+ delete settings.permissions;
1215
+ result.removedConfigs.push("permissions configuration");
1216
+ modified = true;
1217
+ }
1218
+ if (settings.env) {
1219
+ delete settings.env;
1220
+ result.removedConfigs.push("environment variables");
1221
+ modified = true;
1222
+ }
1223
+ if (modified) {
1224
+ writeJsonConfig(settingsPath, settings);
1225
+ }
1226
+ result.success = true;
1227
+ } else {
1228
+ result.warnings.push(i18n.t("uninstall:settingsJsonNotFound"));
1229
+ result.success = true;
1230
+ }
1231
+ } catch (error) {
1232
+ result.errors.push(`Failed to remove permissions and envs: ${error.message}`);
1233
+ }
1234
+ return result;
1235
+ }
1236
+ /**
1237
+ * 6. Remove MCP servers from .claude.json (mcpServers field only)
1238
+ */
1239
+ async removeMcps() {
1240
+ const result = {
1241
+ success: false,
1242
+ removed: [],
1243
+ removedConfigs: [],
1244
+ errors: [],
1245
+ warnings: []
1246
+ };
1247
+ try {
1248
+ const claudeJsonPath = join(homedir(), ".claude.json");
1249
+ if (await pathExists(claudeJsonPath)) {
1250
+ const config = readJsonConfig(claudeJsonPath) || {};
1251
+ if (config.mcpServers) {
1252
+ delete config.mcpServers;
1253
+ writeJsonConfig(claudeJsonPath, config);
1254
+ result.removedConfigs.push("mcpServers from .claude.json");
1255
+ }
1256
+ result.success = true;
1257
+ } else {
1258
+ result.warnings.push(i18n.t("uninstall:claudeJsonNotFound"));
1259
+ result.success = true;
1260
+ }
1261
+ } catch (error) {
1262
+ result.errors.push(`Failed to remove MCP servers: ${error.message}`);
1263
+ }
1264
+ return result;
1265
+ }
1266
+ /**
1267
+ * 7. Uninstall Claude Code Router and remove configuration
1268
+ */
1269
+ async uninstallCcr() {
1270
+ const result = {
1271
+ success: false,
1272
+ removed: [],
1273
+ removedConfigs: [],
1274
+ errors: [],
1275
+ warnings: []
1276
+ };
1277
+ try {
1278
+ const ccrPath = join(homedir(), ".claude-code-router");
1279
+ if (await pathExists(ccrPath)) {
1280
+ const trashResult = await moveToTrash(ccrPath);
1281
+ if (!trashResult[0]?.success) {
1282
+ result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
1283
+ }
1284
+ result.removed.push(".claude-code-router/");
1285
+ }
1286
+ try {
1287
+ await exec$1("npm", ["uninstall", "-g", "@musistudio/claude-code-router"]);
1288
+ result.removed.push("@musistudio/claude-code-router package");
1289
+ result.success = true;
1290
+ } catch (npmError) {
1291
+ if (npmError.message.includes("not found") || npmError.message.includes("not installed")) {
1292
+ result.warnings.push(i18n.t("uninstall:ccrPackageNotFound"));
1293
+ result.success = true;
1294
+ } else {
1295
+ result.errors.push(`Failed to uninstall CCR package: ${npmError.message}`);
1296
+ }
1297
+ }
1298
+ } catch (error) {
1299
+ result.errors.push(`Failed to uninstall CCR: ${error.message}`);
1300
+ }
1301
+ return result;
1302
+ }
1303
+ /**
1304
+ * 8. Uninstall CCometixLine
1305
+ */
1306
+ async uninstallCcline() {
1307
+ const result = {
1308
+ success: false,
1309
+ removed: [],
1310
+ removedConfigs: [],
1311
+ errors: [],
1312
+ warnings: []
1313
+ };
1314
+ try {
1315
+ await exec$1("npm", ["uninstall", "-g", "@cometix/ccline"]);
1316
+ result.removed.push("@cometix/ccline package");
1317
+ result.success = true;
1318
+ } catch (error) {
1319
+ if (error.message.includes("not found") || error.message.includes("not installed")) {
1320
+ result.warnings.push(i18n.t("uninstall:cclinePackageNotFound"));
1321
+ result.success = true;
1322
+ } else {
1323
+ result.errors.push(`Failed to uninstall CCometixLine: ${error.message}`);
1324
+ }
1325
+ }
1326
+ return result;
1327
+ }
1328
+ /**
1329
+ * 9. Uninstall Claude Code and remove entire .claude.json
1330
+ */
1331
+ async uninstallClaudeCode() {
1332
+ const result = {
1333
+ success: false,
1334
+ removed: [],
1335
+ removedConfigs: [],
1336
+ errors: [],
1337
+ warnings: []
1338
+ };
1339
+ try {
1340
+ const claudeJsonPath = join(homedir(), ".claude.json");
1341
+ if (await pathExists(claudeJsonPath)) {
1342
+ const trashResult = await moveToTrash(claudeJsonPath);
1343
+ if (!trashResult[0]?.success) {
1344
+ result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
1345
+ }
1346
+ result.removed.push(".claude.json (includes MCP configuration)");
1347
+ }
1348
+ try {
1349
+ await exec$1("npm", ["uninstall", "-g", "@anthropic-ai/claude-code"]);
1350
+ result.removed.push("@anthropic-ai/claude-code package");
1351
+ result.success = true;
1352
+ } catch (npmError) {
1353
+ if (npmError.message.includes("not found") || npmError.message.includes("not installed")) {
1354
+ result.warnings.push(i18n.t("uninstall:claudeCodePackageNotFound"));
1355
+ result.success = true;
1356
+ } else {
1357
+ result.errors.push(`Failed to uninstall Claude Code package: ${npmError.message}`);
1358
+ }
1359
+ }
1360
+ } catch (error) {
1361
+ result.errors.push(`Failed to uninstall Claude Code: ${error.message}`);
1362
+ }
1363
+ return result;
1364
+ }
1365
+ /**
1366
+ * 10. Remove backup files
1367
+ */
1368
+ async removeBackups() {
1369
+ const result = {
1370
+ success: false,
1371
+ removed: [],
1372
+ removedConfigs: [],
1373
+ errors: [],
1374
+ warnings: []
1375
+ };
1376
+ try {
1377
+ const backupPath = join(homedir(), ".claude", "backup");
1378
+ if (await pathExists(backupPath)) {
1379
+ const trashResult = await moveToTrash(backupPath);
1380
+ if (!trashResult[0]?.success) {
1381
+ result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
1382
+ }
1383
+ result.removed.push("backup/");
1384
+ result.success = true;
1385
+ } else {
1386
+ result.warnings.push(i18n.t("uninstall:backupsNotFound"));
1387
+ result.success = true;
1388
+ }
1389
+ } catch (error) {
1390
+ result.errors.push(`Failed to remove backups: ${error.message}`);
1391
+ }
1392
+ return result;
1393
+ }
1394
+ /**
1395
+ * 11. Remove ZCF preference configuration
1396
+ */
1397
+ async removeZcfConfig() {
1398
+ const result = {
1399
+ success: false,
1400
+ removed: [],
1401
+ removedConfigs: [],
1402
+ errors: [],
1403
+ warnings: []
1404
+ };
1405
+ try {
1406
+ const zcfConfigPath = ZCF_CONFIG_FILE;
1407
+ const relativeName = zcfConfigPath.replace(homedir(), "~");
1408
+ if (await pathExists(zcfConfigPath)) {
1409
+ const trashResult = await moveToTrash(zcfConfigPath);
1410
+ if (!trashResult[0]?.success) {
1411
+ result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
1412
+ }
1413
+ result.removed.push(relativeName);
1414
+ result.success = true;
1415
+ } else {
1416
+ result.warnings.push(i18n.t("uninstall:zcfConfigNotFound"));
1417
+ result.success = true;
1418
+ }
1419
+ } catch (error) {
1420
+ result.errors.push(`Failed to remove ZCF config: ${error.message}`);
1421
+ }
1422
+ return result;
1423
+ }
1424
+ /**
1425
+ * Complete uninstall - remove all directories and packages
1426
+ */
1427
+ async completeUninstall() {
1428
+ const result = {
1429
+ success: true,
1430
+ removed: [],
1431
+ removedConfigs: [],
1432
+ errors: [],
1433
+ warnings: []
1434
+ };
1435
+ try {
1436
+ const directoriesToRemove = [
1437
+ { path: join(homedir(), ".claude"), name: "~/.claude/" },
1438
+ { path: join(homedir(), ".claude.json"), name: "~/.claude.json" },
1439
+ { path: join(homedir(), ".claude-code-router"), name: "~/.claude-code-router/" }
1440
+ ];
1441
+ for (const dir of directoriesToRemove) {
1442
+ try {
1443
+ if (await pathExists(dir.path)) {
1444
+ const trashResult = await moveToTrash(dir.path);
1445
+ if (!trashResult[0]?.success) {
1446
+ result.warnings.push(`Failed to move ${dir.name} to trash: ${trashResult[0]?.error || "Unknown error"}`);
1447
+ }
1448
+ result.removed.push(dir.name);
1449
+ }
1450
+ } catch (error) {
1451
+ result.warnings.push(`Failed to remove ${dir.name}: ${error.message}`);
1452
+ }
1453
+ }
1454
+ const packagesToUninstall = [
1455
+ "@musistudio/claude-code-router",
1456
+ "@cometix/ccline",
1457
+ "@anthropic-ai/claude-code"
1458
+ ];
1459
+ for (const pkg of packagesToUninstall) {
1460
+ try {
1461
+ await exec$1("npm", ["uninstall", "-g", pkg]);
1462
+ result.removed.push(`${pkg} package`);
1463
+ } catch (error) {
1464
+ if (error.message.includes("not found") || error.message.includes("not installed")) {
1465
+ if (pkg.includes("claude-code-router")) {
1466
+ result.warnings.push(i18n.t("uninstall:ccrPackageNotFound"));
1467
+ } else if (pkg.includes("ccline")) {
1468
+ result.warnings.push(i18n.t("uninstall:cclinePackageNotFound"));
1469
+ } else {
1470
+ result.warnings.push(i18n.t("uninstall:claudeCodePackageNotFound"));
1471
+ }
1472
+ } else {
1473
+ result.warnings.push(`Failed to uninstall ${pkg}: ${error.message}`);
1474
+ }
1475
+ }
1476
+ }
1477
+ } catch (error) {
1478
+ result.errors.push(`Complete uninstall failed: ${error.message}`);
1479
+ result.success = false;
1480
+ }
1481
+ return result;
1482
+ }
1483
+ /**
1484
+ * Custom uninstall with conflict resolution
1485
+ */
1486
+ async customUninstall(selectedItems) {
1487
+ const resolvedItems = this.resolveConflicts(selectedItems);
1488
+ const results = [];
1489
+ for (const item of resolvedItems) {
1490
+ try {
1491
+ const result = await this.executeUninstallItem(item);
1492
+ results.push(result);
1493
+ } catch (error) {
1494
+ results.push({
1495
+ success: false,
1496
+ removed: [],
1497
+ removedConfigs: [],
1498
+ errors: [`Failed to execute ${item}: ${error.message}`],
1499
+ warnings: []
1500
+ });
1501
+ }
1502
+ }
1503
+ return results;
1504
+ }
1505
+ /**
1506
+ * Resolve conflicts between uninstall items
1507
+ */
1508
+ resolveConflicts(items) {
1509
+ const resolved = [...items];
1510
+ for (const [primary, conflicts] of this.conflictResolution) {
1511
+ if (resolved.includes(primary)) {
1512
+ conflicts.forEach((conflict) => {
1513
+ const index = resolved.indexOf(conflict);
1514
+ if (index > -1) {
1515
+ resolved.splice(index, 1);
1516
+ }
1517
+ });
1518
+ }
1519
+ }
1520
+ return resolved;
1521
+ }
1522
+ /**
1523
+ * Execute uninstall for a specific item
1524
+ */
1525
+ async executeUninstallItem(item) {
1526
+ switch (item) {
1527
+ case "output-styles":
1528
+ return await this.removeOutputStyles();
1529
+ case "commands":
1530
+ return await this.removeCustomCommands();
1531
+ case "agents":
1532
+ return await this.removeCustomAgents();
1533
+ case "claude-md":
1534
+ return await this.removeClaudeMd();
1535
+ case "permissions-envs":
1536
+ return await this.removePermissionsAndEnvs();
1537
+ case "mcps":
1538
+ return await this.removeMcps();
1539
+ case "ccr":
1540
+ return await this.uninstallCcr();
1541
+ case "ccline":
1542
+ return await this.uninstallCcline();
1543
+ case "claude-code":
1544
+ return await this.uninstallClaudeCode();
1545
+ case "backups":
1546
+ return await this.removeBackups();
1547
+ case "zcf-config":
1548
+ return await this.removeZcfConfig();
1549
+ default:
1550
+ return {
1551
+ success: false,
1552
+ removed: [],
1553
+ removedConfigs: [],
1554
+ errors: [`Unknown uninstall item: ${item}`],
1555
+ warnings: []
1556
+ };
1557
+ }
1558
+ }
1559
+ }
1560
+
1561
+ async function uninstall(options = {}) {
1562
+ try {
1563
+ ensureI18nInitialized();
1564
+ const uninstaller = new ZcfUninstaller(options.lang || "en");
1565
+ if (options.mode && options.mode !== "interactive") {
1566
+ if (options.mode === "complete") {
1567
+ await executeCompleteUninstall(uninstaller);
1568
+ return;
1569
+ } else if (options.mode === "custom" && options.items) {
1570
+ let items;
1571
+ if (typeof options.items === "string") {
1572
+ items = options.items.split(",").map((item) => item.trim());
1573
+ } else {
1574
+ items = options.items;
1575
+ }
1576
+ await executeCustomUninstall(uninstaller, items);
1577
+ return;
1578
+ }
1579
+ }
1580
+ await showInteractiveUninstall(uninstaller);
1581
+ } catch (error) {
1582
+ if (!handleExitPromptError(error)) {
1583
+ handleGeneralError(error);
1584
+ }
1585
+ }
1586
+ }
1587
+ async function showInteractiveUninstall(uninstaller) {
1588
+ console.log(ansis.cyan.bold(i18n.t("uninstall:title")));
1589
+ console.log(ansis.yellow(i18n.t("uninstall:warning")));
1590
+ console.log("");
1591
+ const { mainChoice } = await inquirer.prompt({
1592
+ type: "list",
1593
+ name: "mainChoice",
1594
+ message: i18n.t("uninstall:selectMainOption"),
1595
+ choices: addNumbersToChoices([
1596
+ {
1597
+ name: `${i18n.t("uninstall:completeUninstall")} - ${ansis.gray(i18n.t("uninstall:completeUninstallDesc"))}`,
1598
+ value: "complete",
1599
+ short: i18n.t("uninstall:completeUninstall")
1600
+ },
1601
+ {
1602
+ name: `${i18n.t("uninstall:customUninstall")} - ${ansis.gray(i18n.t("uninstall:customUninstallDesc"))}`,
1603
+ value: "custom",
1604
+ short: i18n.t("uninstall:customUninstall")
1605
+ }
1606
+ ])
1607
+ });
1608
+ if (!mainChoice) {
1609
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
1610
+ return;
1611
+ }
1612
+ if (mainChoice === "complete") {
1613
+ await executeCompleteUninstall(uninstaller);
1614
+ } else {
1615
+ await showCustomUninstallMenu(uninstaller);
1616
+ }
1617
+ }
1618
+ async function showCustomUninstallMenu(uninstaller) {
1619
+ console.log("");
1620
+ console.log(ansis.cyan(i18n.t("uninstall:selectCustomItems")));
1621
+ const { customItems } = await inquirer.prompt({
1622
+ type: "checkbox",
1623
+ name: "customItems",
1624
+ message: `${i18n.t("uninstall:selectItemsToRemove")} ${i18n.t("common:multiSelectHint")}`,
1625
+ choices: [
1626
+ {
1627
+ name: i18n.t("uninstall:outputStyles"),
1628
+ value: "output-styles"
1629
+ },
1630
+ {
1631
+ name: i18n.t("uninstall:commands"),
1632
+ value: "commands"
1633
+ },
1634
+ {
1635
+ name: i18n.t("uninstall:agents"),
1636
+ value: "agents"
1637
+ },
1638
+ {
1639
+ name: i18n.t("uninstall:claudeMd"),
1640
+ value: "claude-md"
1641
+ },
1642
+ {
1643
+ name: i18n.t("uninstall:permissionsEnvs"),
1644
+ value: "permissions-envs"
1645
+ },
1646
+ {
1647
+ name: i18n.t("uninstall:mcps"),
1648
+ value: "mcps"
1649
+ },
1650
+ {
1651
+ name: i18n.t("uninstall:ccr"),
1652
+ value: "ccr"
1653
+ },
1654
+ {
1655
+ name: i18n.t("uninstall:ccline"),
1656
+ value: "ccline"
1657
+ },
1658
+ {
1659
+ name: i18n.t("uninstall:claudeCode"),
1660
+ value: "claude-code"
1661
+ },
1662
+ {
1663
+ name: i18n.t("uninstall:backups"),
1664
+ value: "backups"
1665
+ },
1666
+ {
1667
+ name: i18n.t("uninstall:zcfConfig"),
1668
+ value: "zcf-config"
1669
+ }
1670
+ ],
1671
+ validate: (answers) => {
1672
+ if (answers.length === 0) {
1673
+ return i18n.t("uninstall:selectAtLeastOne");
1674
+ }
1675
+ return true;
1676
+ }
1677
+ });
1678
+ if (!customItems || customItems.length === 0) {
1679
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
1680
+ return;
1681
+ }
1682
+ await executeCustomUninstall(uninstaller, customItems);
1683
+ }
1684
+ async function executeCompleteUninstall(uninstaller) {
1685
+ console.log("");
1686
+ console.log(ansis.red.bold(i18n.t("uninstall:executingComplete")));
1687
+ console.log(ansis.yellow(i18n.t("uninstall:completeWarning")));
1688
+ const { confirm } = await inquirer.prompt({
1689
+ type: "confirm",
1690
+ name: "confirm",
1691
+ message: i18n.t("uninstall:confirmComplete"),
1692
+ default: false
1693
+ });
1694
+ if (!confirm) {
1695
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
1696
+ return;
1697
+ }
1698
+ console.log("");
1699
+ console.log(ansis.cyan(i18n.t("uninstall:processingComplete")));
1700
+ const result = await uninstaller.completeUninstall();
1701
+ displayUninstallResult("complete", [result]);
1702
+ }
1703
+ async function executeCustomUninstall(uninstaller, items) {
1704
+ console.log("");
1705
+ console.log(ansis.cyan(i18n.t("uninstall:executingCustom")));
1706
+ console.log(ansis.gray(i18n.t("uninstall:selectedItems")));
1707
+ items.forEach((item) => {
1708
+ console.log(` \u2022 ${i18n.t(`uninstall:${item}`)}`);
1709
+ });
1710
+ const { confirm } = await inquirer.prompt({
1711
+ type: "confirm",
1712
+ name: "confirm",
1713
+ message: i18n.t("uninstall:confirmCustom"),
1714
+ default: false
1715
+ });
1716
+ if (!confirm) {
1717
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
1718
+ return;
1719
+ }
1720
+ console.log("");
1721
+ console.log(ansis.cyan(i18n.t("uninstall:processingCustom")));
1722
+ const results = await uninstaller.customUninstall(items);
1723
+ displayUninstallResult("custom", results);
1724
+ }
1725
+ function displayUninstallResult(mode, results) {
1726
+ console.log("");
1727
+ console.log(ansis.cyan("\u2500".repeat(50)));
1728
+ let totalSuccess = 0;
1729
+ let totalErrors = 0;
1730
+ let totalWarnings = 0;
1731
+ results.forEach((result) => {
1732
+ if (result.success) {
1733
+ totalSuccess++;
1734
+ }
1735
+ if (result.removed && result.removed.length > 0) {
1736
+ console.log(ansis.green(`\u{1F5D1}\uFE0F ${i18n.t("uninstall:movedToTrash")}:`));
1737
+ result.removed.forEach((item) => {
1738
+ console.log(ansis.gray(` \u2022 ${item}`));
1739
+ });
1740
+ }
1741
+ if (result.removedConfigs && result.removedConfigs.length > 0) {
1742
+ console.log(ansis.green(`\u2714 ${i18n.t("uninstall:removedConfigs")}:`));
1743
+ result.removedConfigs.forEach((item) => {
1744
+ console.log(ansis.gray(` \u2022 ${item}`));
1745
+ });
1746
+ }
1747
+ if (result.errors && result.errors.length > 0) {
1748
+ totalErrors += result.errors.length;
1749
+ console.log(ansis.red(`\u2716 ${i18n.t("uninstall:errors")}:`));
1750
+ result.errors.forEach((error) => {
1751
+ console.log(ansis.red(` \u2022 ${error}`));
1752
+ });
1753
+ }
1754
+ if (result.warnings && result.warnings.length > 0) {
1755
+ totalWarnings += result.warnings.length;
1756
+ console.log(ansis.yellow(`\u26A0 ${i18n.t("uninstall:warnings")}:`));
1757
+ result.warnings.forEach((warning) => {
1758
+ console.log(ansis.yellow(` \u2022 ${warning}`));
1759
+ });
1760
+ }
1761
+ });
1762
+ const totalRemovedFiles = results.reduce((count, result) => count + (result.removed?.length || 0), 0);
1763
+ const totalRemovedConfigs = results.reduce((count, result) => count + (result.removedConfigs?.length || 0), 0);
1764
+ console.log("");
1765
+ console.log(ansis.cyan("\u2500".repeat(50)));
1766
+ if (mode === "complete") {
1767
+ if (totalErrors === 0) {
1768
+ console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:completeSuccess")}`));
1769
+ } else {
1770
+ console.log(ansis.yellow.bold(`\u26A0 ${i18n.t("uninstall:completePartialSuccess")}`));
1771
+ }
1772
+ } else {
1773
+ if (totalRemovedFiles > 0 && totalRemovedConfigs > 0) {
1774
+ console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccessBoth", {
1775
+ fileCount: totalRemovedFiles,
1776
+ configCount: totalRemovedConfigs
1777
+ })}`));
1778
+ } else if (totalRemovedFiles > 0) {
1779
+ console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccessFiles", {
1780
+ count: totalRemovedFiles
1781
+ })}`));
1782
+ } else if (totalRemovedConfigs > 0) {
1783
+ console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccessConfigs", {
1784
+ count: totalRemovedConfigs
1785
+ })}`));
1786
+ } else {
1787
+ console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccess", { count: totalSuccess })}`));
1788
+ }
1789
+ if (totalErrors > 0) {
1790
+ console.log(ansis.red(`\u2716 ${i18n.t("uninstall:errorsCount", { count: totalErrors })}`));
1791
+ }
1792
+ if (totalWarnings > 0) {
1793
+ console.log(ansis.yellow(`\u26A0 ${i18n.t("uninstall:warningsCount", { count: totalWarnings })}`));
1794
+ }
1795
+ }
1796
+ console.log("");
1797
+ }
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
+ }
869
1808
  async function update(options = {}) {
870
1809
  try {
871
1810
  if (!options.skipBanner) {
872
1811
  displayBanner(i18n.t("cli:banner.updateSubtitle"));
873
1812
  }
874
1813
  const zcfConfig = readZcfConfig();
875
- let configLang = options.configLang;
876
- if (!configLang) {
877
- const LANG_HINT_KEYS = {
878
- "zh-CN": i18n.t("language:configLangHint.zh-CN"),
879
- "en": i18n.t("language:configLangHint.en")
880
- };
881
- const { lang } = await inquirer.prompt({
882
- type: "list",
883
- name: "lang",
884
- message: i18n.t("language:updateConfigLangPrompt"),
885
- choices: addNumbersToChoices(SUPPORTED_LANGS.map((l) => ({
886
- name: `${LANG_LABELS[l]} - ${LANG_HINT_KEYS[l]}`,
887
- value: l
888
- })))
889
- });
890
- if (!lang) {
891
- console.log(ansis.yellow(i18n.t("common:cancelled")));
892
- 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
+ });
893
1830
  }
894
- configLang = lang;
1831
+ return;
895
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
+ );
896
1839
  const aiOutputLang = await resolveAiOutputLanguage(i18n.language, options.aiOutputLang, zcfConfig);
897
1840
  console.log(ansis.cyan(`
898
1841
  ${i18n.t("configuration:updatingPrompts")}
@@ -902,7 +1845,10 @@ ${i18n.t("configuration:updatingPrompts")}
902
1845
  await checkClaudeCodeVersionAndPrompt(false);
903
1846
  updateZcfConfig({
904
1847
  version,
905
- aiOutputLang
1848
+ templateLang: configLang,
1849
+ // 保存模板语言选择
1850
+ aiOutputLang,
1851
+ codeToolType
906
1852
  });
907
1853
  } catch (error) {
908
1854
  if (!handleExitPromptError(error)) {
@@ -911,156 +1857,321 @@ ${i18n.t("configuration:updatingPrompts")}
911
1857
  }
912
1858
  }
913
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
+ }
914
2164
  async function showMainMenu() {
915
2165
  try {
916
- displayBannerWithInfo();
917
2166
  let exitMenu = false;
918
2167
  while (!exitMenu) {
919
- console.log(ansis.cyan(i18n.t("menu:selectFunction")));
920
- console.log(" -------- Claude Code --------");
921
- console.log(
922
- ` ${ansis.cyan("1.")} ${i18n.t("menu:menuOptions.fullInit")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.fullInit")}`)}`
923
- );
924
- console.log(
925
- ` ${ansis.cyan("2.")} ${i18n.t("menu:menuOptions.importWorkflow")} ${ansis.gray(
926
- `- ${i18n.t("menu:menuDescriptions.importWorkflow")}`
927
- )}`
928
- );
929
- console.log(
930
- ` ${ansis.cyan("3.")} ${i18n.t("menu:menuOptions.configureApiOrCcr")} ${ansis.gray(
931
- `- ${i18n.t("menu:menuDescriptions.configureApiOrCcr")}`
932
- )}`
933
- );
934
- console.log(
935
- ` ${ansis.cyan("4.")} ${i18n.t("menu:menuOptions.configureMcp")} ${ansis.gray(
936
- `- ${i18n.t("menu:menuDescriptions.configureMcp")}`
937
- )}`
938
- );
939
- console.log(
940
- ` ${ansis.cyan("5.")} ${i18n.t("menu:menuOptions.configureModel")} ${ansis.gray(
941
- `- ${i18n.t("menu:menuDescriptions.configureModel")}`
942
- )}`
943
- );
944
- console.log(
945
- ` ${ansis.cyan("6.")} ${i18n.t("menu:menuOptions.configureAiMemory")} ${ansis.gray(
946
- `- ${i18n.t("menu:menuDescriptions.configureAiMemory")}`
947
- )}`
948
- );
949
- console.log(
950
- ` ${ansis.cyan("7.")} ${i18n.t("menu:menuOptions.configureEnvPermission")} ${ansis.gray(
951
- `- ${i18n.t("menu:menuDescriptions.configureEnvPermission")}`
952
- )}`
953
- );
954
- console.log("");
955
- console.log(` --------- ${i18n.t("menu:menuSections.otherTools")} ----------`);
956
- console.log(
957
- ` ${ansis.cyan("R.")} ${i18n.t("menu:menuOptions.ccrManagement")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.ccrManagement")}`)}`
958
- );
959
- console.log(
960
- ` ${ansis.cyan("U.")} ${i18n.t("menu:menuOptions.ccusage")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.ccusage")}`)}`
961
- );
962
- console.log(
963
- ` ${ansis.cyan("L.")} ${i18n.t("menu:menuOptions.cometixLine")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.cometixLine")}`)}`
964
- );
965
- console.log("");
966
- console.log(" ------------ ZCF ------------");
967
- console.log(
968
- ` ${ansis.cyan("0.")} ${i18n.t("menu:menuOptions.changeLanguage")} ${ansis.gray(
969
- `- ${i18n.t("menu:menuDescriptions.changeLanguage")}`
970
- )}`
971
- );
972
- console.log(
973
- ` ${ansis.cyan("-.")} ${i18n.t("menu:menuOptions.clearCache")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.clearCache")}`)}`
974
- );
975
- console.log(
976
- ` ${ansis.cyan("+.")} ${i18n.t("menu:menuOptions.checkUpdates")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.checkUpdates")}`)}`
977
- );
978
- console.log(` ${ansis.red("Q.")} ${ansis.red(i18n.t("menu:menuOptions.exit"))}`);
979
- console.log("");
980
- const { choice } = await inquirer.prompt({
981
- type: "input",
982
- name: "choice",
983
- message: i18n.t("common:enterChoice"),
984
- validate: (value) => {
985
- const valid = ["1", "2", "3", "4", "5", "6", "7", "r", "R", "u", "U", "l", "L", "0", "-", "+", "q", "Q"];
986
- return valid.includes(value) || i18n.t("common:invalidChoice");
987
- }
988
- });
989
- if (!choice) {
990
- 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") {
991
2172
  exitMenu = true;
992
- break;
993
- }
994
- switch (choice.toLowerCase()) {
995
- case "1":
996
- await init({ skipBanner: true });
997
- break;
998
- case "2":
999
- await update({ skipBanner: true });
1000
- break;
1001
- case "3":
1002
- await configureApiFeature();
1003
- break;
1004
- case "4":
1005
- await configureMcpFeature();
1006
- break;
1007
- case "5":
1008
- await configureDefaultModelFeature();
1009
- break;
1010
- case "6":
1011
- await configureAiMemoryFeature();
1012
- break;
1013
- case "7":
1014
- await configureEnvPermissionFeature();
1015
- break;
1016
- case "r":
1017
- case "R":
1018
- await runCcrMenuFeature();
1019
- break;
1020
- case "u":
1021
- case "U":
1022
- await runCcusageFeature();
1023
- break;
1024
- case "l":
1025
- case "L":
1026
- await runCometixMenuFeature();
1027
- break;
1028
- case "0": {
1029
- const currentLang = i18n.language;
1030
- await changeScriptLanguageFeature(currentLang);
1031
- break;
1032
- }
1033
- case "-":
1034
- await clearZcfCacheFeature();
1035
- break;
1036
- case "+":
1037
- await checkUpdates();
1038
- break;
1039
- case "q":
1040
- exitMenu = true;
1041
- console.log(ansis.cyan(i18n.t("common:goodbye")));
1042
- break;
1043
- }
1044
- if (!exitMenu && choice.toLowerCase() !== "q") {
1045
- if (choice === "0" || choice === "-" || choice === "+" || choice.toLowerCase() === "u" || choice.toLowerCase() === "r" || choice.toLowerCase() === "l") {
1046
- console.log(`
1047
- ${ansis.dim("\u2500".repeat(50))}
1048
- `);
1049
- continue;
1050
- }
1051
- console.log(`
1052
- ${ansis.dim("\u2500".repeat(50))}
1053
- `);
1054
- const { continue: shouldContinue } = await inquirer.prompt({
1055
- type: "confirm",
1056
- name: "continue",
1057
- message: i18n.t("common:returnToMenu"),
1058
- default: true
1059
- });
1060
- if (!shouldContinue) {
1061
- exitMenu = true;
1062
- console.log(ansis.cyan(i18n.t("common:goodbye")));
1063
- }
2173
+ } else if (result === "switch") {
2174
+ continue;
1064
2175
  }
1065
2176
  }
1066
2177
  } catch (error) {
@@ -1086,6 +2197,103 @@ async function ccr(options = {}) {
1086
2197
  }
1087
2198
  }
1088
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
+
1089
2297
  async function resolveAndSwitchLanguage(lang, options, skipPrompt = false) {
1090
2298
  const zcfConfig = await readZcfConfigAsync();
1091
2299
  const targetLang = options?.allLang || lang || options?.lang || zcfConfig?.preferredLang || (skipPrompt ? "en" : await selectScriptLanguage());
@@ -1116,7 +2324,7 @@ function extractLanguageOptions(options) {
1116
2324
  function customizeHelp(sections) {
1117
2325
  sections.unshift({
1118
2326
  title: "",
1119
- body: ansis.cyan.bold(`ZCF - Zero-Config Claude-Code Flow v${version}`)
2327
+ body: ansis.cyan.bold(`ZCF - Zero-Config Code Flow v${version}`)
1120
2328
  });
1121
2329
  sections.push({
1122
2330
  title: ansis.yellow(i18n.t("cli:help.commands")),
@@ -1128,6 +2336,7 @@ function customizeHelp(sections) {
1128
2336
  ` ${ansis.cyan("zcf update")} | ${ansis.cyan("u")} ${i18n.t("cli:help.commandDescriptions.updateWorkflowFiles")}`,
1129
2337
  ` ${ansis.cyan("zcf ccr")} ${i18n.t("cli:help.commandDescriptions.configureCcrProxy")}`,
1130
2338
  ` ${ansis.cyan("zcf ccu")} [args] ${i18n.t("cli:help.commandDescriptions.claudeCodeUsageAnalysis")}`,
2339
+ ` ${ansis.cyan("zcf uninstall")} ${i18n.t("cli:help.commandDescriptions.uninstallConfigurations")}`,
1131
2340
  ` ${ansis.cyan("zcf check-updates")} ${i18n.t("cli:help.commandDescriptions.checkUpdateVersions")}`,
1132
2341
  "",
1133
2342
  ansis.gray(` ${i18n.t("cli:help.shortcuts")}`),
@@ -1157,6 +2366,7 @@ function customizeHelp(sections) {
1157
2366
  ` ${ansis.green("--workflows, -w")} <list> ${i18n.t("cli:help.optionDescriptions.workflows")} (${i18n.t("cli:help.defaults.prefix")} all workflows)`,
1158
2367
  ` ${ansis.green("--output-styles, -o")} <styles> ${i18n.t("cli:help.optionDescriptions.outputStyles")} (${i18n.t("cli:help.defaults.prefix")} all custom styles)`,
1159
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)`,
1160
2370
  ` ${ansis.green("--install-cometix-line, -x")} <value> ${i18n.t("cli:help.optionDescriptions.installStatuslineTool")} (${i18n.t("cli:help.defaults.prefix")} true)`
1161
2371
  ].join("\n")
1162
2372
  });
@@ -1180,6 +2390,9 @@ function customizeHelp(sections) {
1180
2390
  ` ${ansis.cyan("npx zcf ccu")} ${ansis.gray(`# ${i18n.t("cli:help.defaults.dailyUsage")}`)}`,
1181
2391
  ` ${ansis.cyan("npx zcf ccu monthly --json")}`,
1182
2392
  "",
2393
+ ansis.gray(` # ${i18n.t("cli:help.exampleDescriptions.uninstallConfigurations")}`),
2394
+ ` ${ansis.cyan("npx zcf uninstall")} ${ansis.gray(`# ${i18n.t("cli:help.defaults.interactiveUninstall")}`)}`,
2395
+ "",
1183
2396
  ansis.gray(` # ${i18n.t("cli:help.exampleDescriptions.checkAndUpdateTools")}`),
1184
2397
  ` ${ansis.cyan("npx zcf check-updates")} ${ansis.gray(`# ${i18n.t("cli:help.defaults.updateTools")}`)}`,
1185
2398
  ` ${ansis.cyan("npx zcf check")}`,
@@ -1200,10 +2413,10 @@ async function setupCommands(cli) {
1200
2413
  await initI18n(defaultLang);
1201
2414
  } catch {
1202
2415
  }
1203
- 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 () => {
1204
2417
  await showMainMenu();
1205
2418
  }));
1206
- 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) => {
1207
2420
  await init(options);
1208
2421
  }));
1209
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) => {
@@ -1215,6 +2428,15 @@ async function setupCommands(cli) {
1215
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) => {
1216
2429
  await executeCcusage(args);
1217
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
+ }));
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) => {
2438
+ await uninstall(options);
2439
+ }));
1218
2440
  cli.command("check-updates", "Check and update Claude Code and CCR to latest versions").alias("check").option("--lang, -l <lang>", "ZCF display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").action(await withLanguageResolution(async () => {
1219
2441
  await checkUpdates();
1220
2442
  }));