zcf 2.12.13 → 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 +90 -3
  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 +1861 -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
@@ -1,4 +1,4 @@
1
- import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync, rmSync, rmdirSync, readdirSync, statSync, unlinkSync } from 'node:fs';
1
+ import { existsSync, readFileSync, mkdirSync, writeFileSync, copyFileSync, rmSync, rmdirSync, readdirSync, statSync, unlinkSync, renameSync } from 'node:fs';
2
2
  import process from 'node:process';
3
3
  import ansis from 'ansis';
4
4
  import inquirer from 'inquirer';
@@ -10,12 +10,13 @@ import { dirname, join } from 'pathe';
10
10
  import { fileURLToPath } from 'node:url';
11
11
  import ora from 'ora';
12
12
  import semver from 'semver';
13
- import { exec } from 'tinyexec';
13
+ import { parse, stringify } from 'smol-toml';
14
+ import { exec, x } from 'tinyexec';
14
15
  import { rm, mkdir, copyFile as copyFile$1 } from 'node:fs/promises';
15
16
  import i18next from 'i18next';
16
17
  import Backend from 'i18next-fs-backend';
17
18
 
18
- const version = "2.12.13";
19
+ const version = "3.0.0";
19
20
  const homepage = "https://github.com/UfoMiao/zcf";
20
21
 
21
22
  const i18n = i18next.createInstance();
@@ -34,7 +35,8 @@ const NAMESPACES = [
34
35
  "tools",
35
36
  "uninstall",
36
37
  "updater",
37
- "workflow"
38
+ "workflow",
39
+ "codex"
38
40
  ];
39
41
  function ensureI18nInitialized() {
40
42
  if (!i18n.isInitialized) {
@@ -128,7 +130,7 @@ const MCP_SERVICE_CONFIGS = [
128
130
  config: {
129
131
  type: "stdio",
130
132
  command: "npx",
131
- args: ["-y", "@upstash/context7-mcp"],
133
+ args: ["-y", "@upstash/context7-mcp@latest"],
132
134
  env: {}
133
135
  }
134
136
  },
@@ -183,7 +185,7 @@ const MCP_SERVICE_CONFIGS = [
183
185
  config: {
184
186
  type: "stdio",
185
187
  command: "npx",
186
- args: ["-y", "exa-mcp-server"],
188
+ args: ["-y", "exa-mcp-server@latest"],
187
189
  env: {
188
190
  EXA_API_KEY: "YOUR_EXA_API_KEY"
189
191
  }
@@ -215,8 +217,8 @@ async function getMcpServices() {
215
217
  },
216
218
  {
217
219
  id: "Playwright",
218
- name: i18n.t("mcp:services.Playwright.name"),
219
- description: i18n.t("mcp:services.Playwright.description")
220
+ name: i18n.t("mcp:services.playwright.name"),
221
+ description: i18n.t("mcp:services.playwright.description")
220
222
  },
221
223
  {
222
224
  id: "exa",
@@ -353,8 +355,17 @@ const CLAUDE_DIR = join(homedir(), ".claude");
353
355
  const SETTINGS_FILE = join(CLAUDE_DIR, "settings.json");
354
356
  const CLAUDE_MD_FILE = join(CLAUDE_DIR, "CLAUDE.md");
355
357
  const ClAUDE_CONFIG_FILE = join(homedir(), ".claude.json");
356
- const LEGACY_ZCF_CONFIG_FILE = join(homedir(), ".zcf.json");
357
- const ZCF_CONFIG_FILE = join(CLAUDE_DIR, ".zcf-config.json");
358
+ const ZCF_CONFIG_DIR = join(homedir(), ".ufomiao", "zcf");
359
+ const ZCF_CONFIG_FILE = join(ZCF_CONFIG_DIR, "config.toml");
360
+ const LEGACY_ZCF_CONFIG_FILES = [
361
+ join(CLAUDE_DIR, ".zcf-config.json"),
362
+ join(homedir(), ".zcf.json")
363
+ ];
364
+ const CODE_TOOL_TYPES = ["claude-code", "codex"];
365
+ const DEFAULT_CODE_TOOL_TYPE = "claude-code";
366
+ function isCodeToolType(value) {
367
+ return CODE_TOOL_TYPES.includes(value);
368
+ }
358
369
  const SUPPORTED_LANGS = ["zh-CN", "en"];
359
370
  const LANG_LABELS = {
360
371
  "zh-CN": "\u7B80\u4F53\u4E2D\u6587",
@@ -378,6 +389,24 @@ function getAiOutputLanguageLabel(lang) {
378
389
  return lang;
379
390
  }
380
391
 
392
+ const constants = {
393
+ __proto__: null,
394
+ AI_OUTPUT_LANGUAGES: AI_OUTPUT_LANGUAGES,
395
+ CLAUDE_DIR: CLAUDE_DIR,
396
+ CLAUDE_MD_FILE: CLAUDE_MD_FILE,
397
+ CODE_TOOL_TYPES: CODE_TOOL_TYPES,
398
+ ClAUDE_CONFIG_FILE: ClAUDE_CONFIG_FILE,
399
+ DEFAULT_CODE_TOOL_TYPE: DEFAULT_CODE_TOOL_TYPE,
400
+ LANG_LABELS: LANG_LABELS,
401
+ LEGACY_ZCF_CONFIG_FILES: LEGACY_ZCF_CONFIG_FILES,
402
+ SETTINGS_FILE: SETTINGS_FILE,
403
+ SUPPORTED_LANGS: SUPPORTED_LANGS,
404
+ ZCF_CONFIG_DIR: ZCF_CONFIG_DIR,
405
+ ZCF_CONFIG_FILE: ZCF_CONFIG_FILE,
406
+ getAiOutputLanguageLabel: getAiOutputLanguageLabel,
407
+ isCodeToolType: isCodeToolType
408
+ };
409
+
381
410
  function getDisplayWidth(str) {
382
411
  let width = 0;
383
412
  for (const char of str) {
@@ -398,7 +427,8 @@ function displayBanner(subtitle) {
398
427
  ensureI18nInitialized();
399
428
  const defaultSubtitle = i18n.t("cli:banner.subtitle");
400
429
  const subtitleText = subtitle || defaultSubtitle;
401
- const paddedSubtitle = padToDisplayWidth(subtitleText, 60);
430
+ const paddedSubtitle = padToDisplayWidth(subtitleText, 30);
431
+ const paddedTitle = padToDisplayWidth("Zero-Config Code Flow", 60);
402
432
  console.log(
403
433
  ansis.cyan.bold(`
404
434
  \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
@@ -408,10 +438,9 @@ function displayBanner(subtitle) {
408
438
  \u2551 \u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2557 \u2551
409
439
  \u2551 \u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u255D \u2551
410
440
  \u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2551
411
- \u2551 \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u2551
441
+ \u2551 \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D ${ansis.gray(paddedSubtitle)} \u2551
412
442
  \u2551 \u2551
413
- \u2551 ${ansis.white.bold("Zero-Config Claude-Code Flow")} \u2551
414
- \u2551 ${ansis.gray(paddedSubtitle)} \u2551
443
+ \u2551 ${ansis.white.bold(paddedTitle)} \u2551
415
444
  \u2551 \u2551
416
445
  \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
417
446
  `)
@@ -423,6 +452,118 @@ function displayBannerWithInfo(subtitle) {
423
452
  `));
424
453
  }
425
454
 
455
+ function getPlatform() {
456
+ const p = platform();
457
+ if (p === "win32")
458
+ return "windows";
459
+ if (p === "darwin")
460
+ return "macos";
461
+ return "linux";
462
+ }
463
+ function isTermux() {
464
+ return !!(process.env.PREFIX && process.env.PREFIX.includes("com.termux")) || !!process.env.TERMUX_VERSION || existsSync("/data/data/com.termux/files/usr");
465
+ }
466
+ function getTermuxPrefix() {
467
+ return process.env.PREFIX || "/data/data/com.termux/files/usr";
468
+ }
469
+ function isWindows() {
470
+ return getPlatform() === "windows";
471
+ }
472
+ function isWSL() {
473
+ if (process.env.WSL_DISTRO_NAME) {
474
+ return true;
475
+ }
476
+ if (existsSync("/proc/version")) {
477
+ try {
478
+ const version = readFileSync("/proc/version", "utf8");
479
+ if (version.includes("Microsoft") || version.includes("WSL")) {
480
+ return true;
481
+ }
482
+ } catch {
483
+ }
484
+ }
485
+ if (existsSync("/mnt/c")) {
486
+ return true;
487
+ }
488
+ return false;
489
+ }
490
+ function getWSLDistro() {
491
+ if (process.env.WSL_DISTRO_NAME) {
492
+ return process.env.WSL_DISTRO_NAME;
493
+ }
494
+ if (existsSync("/etc/os-release")) {
495
+ try {
496
+ const osRelease = readFileSync("/etc/os-release", "utf8");
497
+ const nameMatch = osRelease.match(/^PRETTY_NAME="(.+)"$/m);
498
+ if (nameMatch) {
499
+ return nameMatch[1];
500
+ }
501
+ } catch {
502
+ }
503
+ }
504
+ return null;
505
+ }
506
+ function getWSLInfo() {
507
+ if (!isWSL()) {
508
+ return null;
509
+ }
510
+ let version = null;
511
+ if (existsSync("/proc/version")) {
512
+ try {
513
+ version = readFileSync("/proc/version", "utf8").trim();
514
+ } catch {
515
+ }
516
+ }
517
+ return {
518
+ isWSL: true,
519
+ distro: getWSLDistro(),
520
+ version
521
+ };
522
+ }
523
+ function getMcpCommand() {
524
+ if (isWindows()) {
525
+ return ["cmd", "/c", "npx"];
526
+ }
527
+ return ["npx"];
528
+ }
529
+ async function commandExists(command) {
530
+ try {
531
+ const cmd = getPlatform() === "windows" ? "where" : "which";
532
+ const res = await exec(cmd, [command]);
533
+ if (res.exitCode === 0) {
534
+ return true;
535
+ }
536
+ } catch {
537
+ }
538
+ if (isTermux()) {
539
+ const termuxPrefix = getTermuxPrefix();
540
+ const possiblePaths = [
541
+ `${termuxPrefix}/bin/${command}`,
542
+ `${termuxPrefix}/usr/bin/${command}`,
543
+ `/data/data/com.termux/files/usr/bin/${command}`
544
+ ];
545
+ for (const path of possiblePaths) {
546
+ if (existsSync(path)) {
547
+ return true;
548
+ }
549
+ }
550
+ }
551
+ if (getPlatform() !== "windows") {
552
+ const commonPaths = [
553
+ `/usr/local/bin/${command}`,
554
+ `/usr/bin/${command}`,
555
+ `/bin/${command}`,
556
+ `${process.env.HOME}/.local/bin/${command}`
557
+ ];
558
+ for (const path of commonPaths) {
559
+ if (existsSync(path)) {
560
+ return true;
561
+ }
562
+ }
563
+ }
564
+ return false;
565
+ }
566
+
426
567
  class FileSystemError extends Error {
427
568
  constructor(message, path, cause) {
428
569
  super(message);
@@ -546,7 +687,7 @@ async function isExecutable(path) {
546
687
  if (!stats.isFile()) {
547
688
  return false;
548
689
  }
549
- if (process.platform !== "win32") {
690
+ if (!isWindows()) {
550
691
  const mode = stats.mode;
551
692
  const executePermission = 73;
552
693
  return (mode & executePermission) !== 0;
@@ -593,6 +734,23 @@ async function remove(path) {
593
734
  }
594
735
  }
595
736
 
737
+ const fsOperations = {
738
+ __proto__: null,
739
+ FileSystemError: FileSystemError,
740
+ copyDir: copyDir,
741
+ copyFile: copyFile,
742
+ ensureDir: ensureDir,
743
+ ensureFileDir: ensureFileDir,
744
+ exists: exists,
745
+ getStats: getStats,
746
+ isExecutable: isExecutable,
747
+ readDir: readDir,
748
+ readFile: readFile,
749
+ remove: remove,
750
+ removeFile: removeFile,
751
+ writeFile: writeFile
752
+ };
753
+
596
754
  function readJsonConfig(path, options = {}) {
597
755
  const { defaultValue = null, validate, sanitize } = options;
598
756
  if (!exists(path)) {
@@ -701,118 +859,6 @@ function deepClone(obj) {
701
859
  return obj;
702
860
  }
703
861
 
704
- function getPlatform() {
705
- const p = platform();
706
- if (p === "win32")
707
- return "windows";
708
- if (p === "darwin")
709
- return "macos";
710
- return "linux";
711
- }
712
- function isTermux() {
713
- return !!(process.env.PREFIX && process.env.PREFIX.includes("com.termux")) || !!process.env.TERMUX_VERSION || existsSync("/data/data/com.termux/files/usr");
714
- }
715
- function getTermuxPrefix() {
716
- return process.env.PREFIX || "/data/data/com.termux/files/usr";
717
- }
718
- function isWindows() {
719
- return getPlatform() === "windows";
720
- }
721
- function isWSL() {
722
- if (process.env.WSL_DISTRO_NAME) {
723
- return true;
724
- }
725
- if (existsSync("/proc/version")) {
726
- try {
727
- const version = readFileSync("/proc/version", "utf8");
728
- if (version.includes("Microsoft") || version.includes("WSL")) {
729
- return true;
730
- }
731
- } catch {
732
- }
733
- }
734
- if (existsSync("/mnt/c")) {
735
- return true;
736
- }
737
- return false;
738
- }
739
- function getWSLDistro() {
740
- if (process.env.WSL_DISTRO_NAME) {
741
- return process.env.WSL_DISTRO_NAME;
742
- }
743
- if (existsSync("/etc/os-release")) {
744
- try {
745
- const osRelease = readFileSync("/etc/os-release", "utf8");
746
- const nameMatch = osRelease.match(/^PRETTY_NAME="(.+)"$/m);
747
- if (nameMatch) {
748
- return nameMatch[1];
749
- }
750
- } catch {
751
- }
752
- }
753
- return null;
754
- }
755
- function getWSLInfo() {
756
- if (!isWSL()) {
757
- return null;
758
- }
759
- let version = null;
760
- if (existsSync("/proc/version")) {
761
- try {
762
- version = readFileSync("/proc/version", "utf8").trim();
763
- } catch {
764
- }
765
- }
766
- return {
767
- isWSL: true,
768
- distro: getWSLDistro(),
769
- version
770
- };
771
- }
772
- function getMcpCommand() {
773
- if (isWindows()) {
774
- return ["cmd", "/c", "npx"];
775
- }
776
- return ["npx"];
777
- }
778
- async function commandExists(command) {
779
- try {
780
- const cmd = getPlatform() === "windows" ? "where" : "which";
781
- const res = await exec(cmd, [command]);
782
- if (res.exitCode === 0) {
783
- return true;
784
- }
785
- } catch {
786
- }
787
- if (isTermux()) {
788
- const termuxPrefix = getTermuxPrefix();
789
- const possiblePaths = [
790
- `${termuxPrefix}/bin/${command}`,
791
- `${termuxPrefix}/usr/bin/${command}`,
792
- `/data/data/com.termux/files/usr/bin/${command}`
793
- ];
794
- for (const path of possiblePaths) {
795
- if (existsSync(path)) {
796
- return true;
797
- }
798
- }
799
- }
800
- if (getPlatform() !== "windows") {
801
- const commonPaths = [
802
- `/usr/local/bin/${command}`,
803
- `/usr/bin/${command}`,
804
- `/bin/${command}`,
805
- `${process.env.HOME}/.local/bin/${command}`
806
- ];
807
- for (const path of commonPaths) {
808
- if (existsSync(path)) {
809
- return true;
810
- }
811
- }
812
- }
813
- return false;
814
- }
815
-
816
862
  function getMcpConfigPath() {
817
863
  return ClAUDE_CONFIG_FILE;
818
864
  }
@@ -1008,7 +1054,7 @@ function copyConfigFiles(onlyMd = false) {
1008
1054
  const currentFilePath = fileURLToPath(import.meta.url);
1009
1055
  const distDir = dirname(dirname(currentFilePath));
1010
1056
  const rootDir = dirname(distDir);
1011
- const baseTemplateDir = join(rootDir, "templates");
1057
+ const baseTemplateDir = join(rootDir, "templates", "claude-code");
1012
1058
  if (!onlyMd) {
1013
1059
  const baseSettingsPath = join(baseTemplateDir, "common", "settings.json");
1014
1060
  const destSettingsPath = join(CLAUDE_DIR, "settings.json");
@@ -1022,7 +1068,7 @@ function getDefaultSettings() {
1022
1068
  const currentFilePath = fileURLToPath(import.meta.url);
1023
1069
  const distDir = dirname(dirname(currentFilePath));
1024
1070
  const rootDir = dirname(distDir);
1025
- const templateSettingsPath = join(rootDir, "templates", "common", "settings.json");
1071
+ const templateSettingsPath = join(rootDir, "templates", "claude-code", "common", "settings.json");
1026
1072
  return readJsonConfig(templateSettingsPath) || {};
1027
1073
  } catch (error) {
1028
1074
  console.error("Failed to read template settings", error);
@@ -1442,9 +1488,9 @@ async function configureCcrWithPreset(preset) {
1442
1488
  if (preset.requiresApiKey) {
1443
1489
  try {
1444
1490
  const { apiKey } = await inquirer.prompt({
1445
- type: "input",
1491
+ type: "password",
1446
1492
  name: "apiKey",
1447
- message: i18n.t("ccr:enterApiKeyForProvider").replace("{provider}", preset.name),
1493
+ message: i18n.t("ccr:enterApiKeyForProvider").replace("{provider}", preset.name) + i18n.t("common:inputHidden"),
1448
1494
  validate: async (value) => !!value || i18n.t("api:keyRequired")
1449
1495
  });
1450
1496
  provider.api_key = apiKey;
@@ -1987,29 +2033,1605 @@ async function installCcr() {
1987
2033
  }
1988
2034
  }
1989
2035
 
1990
- function getPlatformStatusLineConfig() {
1991
- return {
1992
- type: "command",
1993
- command: isWindows() ? "%USERPROFILE%\\.claude\\ccline\\ccline.exe" : "~/.claude/ccline/ccline",
1994
- padding: 0
1995
- };
1996
- }
1997
-
1998
- function addCCometixLineConfig() {
1999
- try {
2000
- const statusLineConfig = getPlatformStatusLineConfig();
2001
- let settings = {};
2002
- if (exists(SETTINGS_FILE)) {
2003
- settings = readJsonConfig(SETTINGS_FILE) || {};
2004
- }
2005
- settings.statusLine = statusLineConfig;
2006
- writeJsonConfig(SETTINGS_FILE, settings);
2007
- return true;
2008
- } catch (error) {
2009
- console.error("Failed to add CCometixLine configuration:", error);
2010
- return false;
2011
- }
2012
- }
2036
+ async function selectMcpServices() {
2037
+ ensureI18nInitialized();
2038
+ const mcpServices = await getMcpServices();
2039
+ const choices = mcpServices.map((service) => ({
2040
+ name: `${service.name} - ${ansis.gray(service.description)}`,
2041
+ value: service.id,
2042
+ selected: false
2043
+ }));
2044
+ const { services } = await inquirer.prompt({
2045
+ type: "checkbox",
2046
+ name: "services",
2047
+ message: `${i18n.t("mcp:selectMcpServices")}${i18n.t("common:multiSelectHint")}`,
2048
+ choices
2049
+ });
2050
+ if (services === void 0) {
2051
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
2052
+ return void 0;
2053
+ }
2054
+ return services;
2055
+ }
2056
+
2057
+ function addNumbersToChoices(choices, startFrom = 1, format = (n) => `${n}. `) {
2058
+ let currentNumber = startFrom;
2059
+ return choices.map((choice) => {
2060
+ if (choice.disabled) {
2061
+ return choice;
2062
+ }
2063
+ const numbered = {
2064
+ ...choice,
2065
+ name: `${format(currentNumber)}${choice.name}`
2066
+ };
2067
+ currentNumber++;
2068
+ return numbered;
2069
+ });
2070
+ }
2071
+
2072
+ function isSupportedLang(value) {
2073
+ return SUPPORTED_LANGS.includes(value);
2074
+ }
2075
+ function sanitizePreferredLang(lang) {
2076
+ return isSupportedLang(lang) ? lang : "en";
2077
+ }
2078
+ function sanitizeCodeToolType(codeTool) {
2079
+ return isCodeToolType(codeTool) ? codeTool : DEFAULT_CODE_TOOL_TYPE;
2080
+ }
2081
+ function readTomlConfig(configPath) {
2082
+ try {
2083
+ if (!exists(configPath)) {
2084
+ return null;
2085
+ }
2086
+ const content = readFile(configPath);
2087
+ const parsed = parse(content);
2088
+ return parsed;
2089
+ } catch {
2090
+ return null;
2091
+ }
2092
+ }
2093
+ function writeTomlConfig(configPath, config) {
2094
+ try {
2095
+ const configDir = dirname(configPath);
2096
+ ensureDir(configDir);
2097
+ const tomlContent = stringify(config);
2098
+ writeFile(configPath, tomlContent);
2099
+ } catch {
2100
+ }
2101
+ }
2102
+ function createDefaultTomlConfig(preferredLang = "en", claudeCodeInstallType = "global") {
2103
+ return {
2104
+ version: "1.0.0",
2105
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
2106
+ general: {
2107
+ preferredLang,
2108
+ templateLang: preferredLang,
2109
+ // Default templateLang to preferredLang for new installations
2110
+ aiOutputLang: preferredLang === "zh-CN" ? "zh-CN" : void 0,
2111
+ currentTool: DEFAULT_CODE_TOOL_TYPE
2112
+ },
2113
+ claudeCode: {
2114
+ enabled: true,
2115
+ outputStyles: ["engineer-professional"],
2116
+ defaultOutputStyle: "engineer-professional",
2117
+ installType: claudeCodeInstallType
2118
+ },
2119
+ codex: {
2120
+ enabled: false,
2121
+ systemPromptStyle: "engineer-professional"
2122
+ }
2123
+ };
2124
+ }
2125
+ function migrateFromJsonConfig(jsonConfig) {
2126
+ const claudeCodeInstallType = jsonConfig.claudeCodeInstallation?.type || "global";
2127
+ const defaultConfig = createDefaultTomlConfig("en", claudeCodeInstallType);
2128
+ const tomlConfig = {
2129
+ version: jsonConfig.version || defaultConfig.version,
2130
+ lastUpdated: jsonConfig.lastUpdated || (/* @__PURE__ */ new Date()).toISOString(),
2131
+ general: {
2132
+ preferredLang: jsonConfig.preferredLang || defaultConfig.general.preferredLang,
2133
+ templateLang: jsonConfig.templateLang || jsonConfig.preferredLang || defaultConfig.general.preferredLang,
2134
+ // Backward compatibility: use preferredLang as default
2135
+ aiOutputLang: jsonConfig.aiOutputLang || defaultConfig.general.aiOutputLang,
2136
+ currentTool: jsonConfig.codeToolType || defaultConfig.general.currentTool
2137
+ },
2138
+ claudeCode: {
2139
+ enabled: jsonConfig.codeToolType === "claude-code",
2140
+ outputStyles: jsonConfig.outputStyles || defaultConfig.claudeCode.outputStyles,
2141
+ defaultOutputStyle: jsonConfig.defaultOutputStyle || defaultConfig.claudeCode.defaultOutputStyle,
2142
+ installType: claudeCodeInstallType
2143
+ },
2144
+ codex: {
2145
+ enabled: jsonConfig.codeToolType === "codex",
2146
+ systemPromptStyle: jsonConfig.systemPromptStyle || defaultConfig.codex.systemPromptStyle
2147
+ }
2148
+ };
2149
+ return tomlConfig;
2150
+ }
2151
+ function updateTomlConfig(configPath, updates) {
2152
+ const existingConfig = readTomlConfig(configPath) || createDefaultTomlConfig();
2153
+ const updatedConfig = {
2154
+ version: updates.version || existingConfig.version,
2155
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
2156
+ general: {
2157
+ ...existingConfig.general,
2158
+ ...updates.general
2159
+ },
2160
+ claudeCode: {
2161
+ ...existingConfig.claudeCode,
2162
+ ...updates.claudeCode
2163
+ },
2164
+ codex: {
2165
+ ...existingConfig.codex,
2166
+ ...updates.codex
2167
+ }
2168
+ };
2169
+ writeTomlConfig(configPath, updatedConfig);
2170
+ return updatedConfig;
2171
+ }
2172
+ function convertTomlToLegacyConfig(tomlConfig) {
2173
+ return {
2174
+ version: tomlConfig.version,
2175
+ preferredLang: tomlConfig.general.preferredLang,
2176
+ templateLang: tomlConfig.general.templateLang,
2177
+ aiOutputLang: tomlConfig.general.aiOutputLang,
2178
+ outputStyles: tomlConfig.claudeCode.outputStyles,
2179
+ defaultOutputStyle: tomlConfig.claudeCode.defaultOutputStyle,
2180
+ codeToolType: tomlConfig.general.currentTool,
2181
+ lastUpdated: tomlConfig.lastUpdated
2182
+ };
2183
+ }
2184
+ function convertLegacyToTomlConfig(legacyConfig) {
2185
+ return migrateFromJsonConfig(legacyConfig);
2186
+ }
2187
+ function normalizeZcfConfig(config) {
2188
+ if (!config) {
2189
+ return null;
2190
+ }
2191
+ return {
2192
+ version: typeof config.version === "string" ? config.version : "1.0.0",
2193
+ preferredLang: sanitizePreferredLang(config.preferredLang),
2194
+ templateLang: config.templateLang ? sanitizePreferredLang(config.templateLang) : void 0,
2195
+ aiOutputLang: config.aiOutputLang,
2196
+ outputStyles: Array.isArray(config.outputStyles) ? config.outputStyles : void 0,
2197
+ defaultOutputStyle: typeof config.defaultOutputStyle === "string" ? config.defaultOutputStyle : void 0,
2198
+ codeToolType: sanitizeCodeToolType(config.codeToolType),
2199
+ lastUpdated: typeof config.lastUpdated === "string" ? config.lastUpdated : (/* @__PURE__ */ new Date()).toISOString()
2200
+ };
2201
+ }
2202
+ function migrateZcfConfigIfNeeded() {
2203
+ const target = ZCF_CONFIG_FILE;
2204
+ const removed = [];
2205
+ const targetExists = existsSync(target);
2206
+ const legacySources = LEGACY_ZCF_CONFIG_FILES.filter((path) => existsSync(path));
2207
+ if (!targetExists && legacySources.length > 0) {
2208
+ const source = legacySources[0];
2209
+ if (!existsSync(ZCF_CONFIG_DIR)) {
2210
+ mkdirSync(ZCF_CONFIG_DIR, { recursive: true });
2211
+ }
2212
+ renameSync(source, target);
2213
+ for (const leftover of legacySources.slice(1)) {
2214
+ try {
2215
+ rmSync(leftover, { force: true });
2216
+ removed.push(leftover);
2217
+ } catch {
2218
+ }
2219
+ }
2220
+ return { migrated: true, source, target, removed };
2221
+ }
2222
+ if (targetExists && legacySources.length > 0) {
2223
+ for (const source of legacySources) {
2224
+ try {
2225
+ rmSync(source, { force: true });
2226
+ removed.push(source);
2227
+ } catch {
2228
+ }
2229
+ }
2230
+ return { migrated: false, target, removed };
2231
+ }
2232
+ return { migrated: false, target, removed };
2233
+ }
2234
+ function readZcfConfig() {
2235
+ migrateZcfConfigIfNeeded();
2236
+ const tomlConfig = readTomlConfig(ZCF_CONFIG_FILE);
2237
+ if (tomlConfig) {
2238
+ return convertTomlToLegacyConfig(tomlConfig);
2239
+ }
2240
+ const raw = readJsonConfig(ZCF_CONFIG_FILE.replace(".toml", ".json"));
2241
+ const normalized = normalizeZcfConfig(raw || null);
2242
+ if (normalized) {
2243
+ return normalized;
2244
+ }
2245
+ for (const legacyPath of LEGACY_ZCF_CONFIG_FILES) {
2246
+ if (existsSync(legacyPath)) {
2247
+ const legacyRaw = readJsonConfig(legacyPath);
2248
+ const legacyNormalized = normalizeZcfConfig(legacyRaw || null);
2249
+ if (legacyNormalized) {
2250
+ return legacyNormalized;
2251
+ }
2252
+ }
2253
+ }
2254
+ return null;
2255
+ }
2256
+ async function readZcfConfigAsync() {
2257
+ return readZcfConfig();
2258
+ }
2259
+ function writeZcfConfig(config) {
2260
+ try {
2261
+ const sanitizedConfig = {
2262
+ ...config,
2263
+ codeToolType: sanitizeCodeToolType(config.codeToolType)
2264
+ };
2265
+ const tomlConfig = convertLegacyToTomlConfig(sanitizedConfig);
2266
+ writeTomlConfig(ZCF_CONFIG_FILE, tomlConfig);
2267
+ } catch {
2268
+ }
2269
+ }
2270
+ function updateZcfConfig(updates) {
2271
+ const existingConfig = readZcfConfig();
2272
+ const newConfig = {
2273
+ version: updates.version || existingConfig?.version || "1.0.0",
2274
+ preferredLang: updates.preferredLang || existingConfig?.preferredLang || "en",
2275
+ templateLang: updates.templateLang !== void 0 ? updates.templateLang : existingConfig?.templateLang,
2276
+ aiOutputLang: updates.aiOutputLang || existingConfig?.aiOutputLang,
2277
+ outputStyles: updates.outputStyles !== void 0 ? updates.outputStyles : existingConfig?.outputStyles,
2278
+ defaultOutputStyle: updates.defaultOutputStyle !== void 0 ? updates.defaultOutputStyle : existingConfig?.defaultOutputStyle,
2279
+ codeToolType: updates.codeToolType || existingConfig?.codeToolType || DEFAULT_CODE_TOOL_TYPE,
2280
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
2281
+ };
2282
+ writeZcfConfig(newConfig);
2283
+ }
2284
+ function readDefaultTomlConfig() {
2285
+ return readTomlConfig(ZCF_CONFIG_FILE);
2286
+ }
2287
+
2288
+ const zcfConfig = {
2289
+ __proto__: null,
2290
+ createDefaultTomlConfig: createDefaultTomlConfig,
2291
+ migrateFromJsonConfig: migrateFromJsonConfig,
2292
+ migrateZcfConfigIfNeeded: migrateZcfConfigIfNeeded,
2293
+ readDefaultTomlConfig: readDefaultTomlConfig,
2294
+ readTomlConfig: readTomlConfig,
2295
+ readZcfConfig: readZcfConfig,
2296
+ readZcfConfigAsync: readZcfConfigAsync,
2297
+ updateTomlConfig: updateTomlConfig,
2298
+ updateZcfConfig: updateZcfConfig,
2299
+ writeTomlConfig: writeTomlConfig,
2300
+ writeZcfConfig: writeZcfConfig
2301
+ };
2302
+
2303
+ async function selectAiOutputLanguage(defaultLang) {
2304
+ ensureI18nInitialized();
2305
+ console.log(ansis.dim(`
2306
+ ${i18n.t("language:aiOutputLangHint")}
2307
+ `));
2308
+ const aiLangChoices = Object.entries(AI_OUTPUT_LANGUAGES).map(([key]) => ({
2309
+ title: getAiOutputLanguageLabel(key),
2310
+ value: key
2311
+ }));
2312
+ const defaultChoice = defaultLang || "en";
2313
+ const { lang } = await inquirer.prompt({
2314
+ type: "list",
2315
+ name: "lang",
2316
+ message: i18n.t("language:selectAiOutputLang"),
2317
+ choices: addNumbersToChoices(aiLangChoices.map((choice) => ({
2318
+ name: choice.title,
2319
+ value: choice.value
2320
+ }))),
2321
+ default: defaultChoice
2322
+ });
2323
+ if (!lang) {
2324
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
2325
+ process.exit(0);
2326
+ }
2327
+ const aiOutputLang = lang;
2328
+ if (aiOutputLang === "custom") {
2329
+ const { customLang } = await inquirer.prompt({
2330
+ type: "input",
2331
+ name: "customLang",
2332
+ message: i18n.t("language:enterCustomLanguage"),
2333
+ validate: async (value) => !!value || i18n.t("language:languageRequired") || "Language is required"
2334
+ });
2335
+ if (!customLang) {
2336
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
2337
+ process.exit(0);
2338
+ }
2339
+ return customLang;
2340
+ }
2341
+ return aiOutputLang;
2342
+ }
2343
+ const LANGUAGE_SELECTION_MESSAGES = {
2344
+ selectLanguage: "Select ZCF display language / \u9009\u62E9ZCF\u663E\u793A\u8BED\u8A00",
2345
+ operationCancelled: "Operation cancelled / \u64CD\u4F5C\u5DF2\u53D6\u6D88"
2346
+ };
2347
+ async function selectScriptLanguage(currentLang) {
2348
+ const zcfConfig = readZcfConfig();
2349
+ if (zcfConfig?.preferredLang) {
2350
+ return zcfConfig.preferredLang;
2351
+ }
2352
+ const { lang } = await inquirer.prompt({
2353
+ type: "list",
2354
+ name: "lang",
2355
+ message: LANGUAGE_SELECTION_MESSAGES.selectLanguage,
2356
+ choices: addNumbersToChoices(SUPPORTED_LANGS.map((l) => ({
2357
+ name: LANG_LABELS[l],
2358
+ value: l
2359
+ })))
2360
+ });
2361
+ if (!lang) {
2362
+ console.log(ansis.yellow(LANGUAGE_SELECTION_MESSAGES.operationCancelled));
2363
+ process.exit(0);
2364
+ }
2365
+ const scriptLang = lang;
2366
+ updateZcfConfig({
2367
+ version,
2368
+ preferredLang: scriptLang
2369
+ });
2370
+ return scriptLang;
2371
+ }
2372
+ async function resolveAiOutputLanguage(scriptLang, commandLineOption, savedConfig) {
2373
+ ensureI18nInitialized();
2374
+ if (commandLineOption) {
2375
+ return commandLineOption;
2376
+ }
2377
+ if (savedConfig?.aiOutputLang) {
2378
+ const currentLanguageLabel = getAiOutputLanguageLabel(savedConfig.aiOutputLang) || savedConfig.aiOutputLang;
2379
+ console.log(ansis.blue(`${i18n.t("language:currentConfigFound")}: ${currentLanguageLabel}`));
2380
+ const { shouldModify } = await inquirer.prompt({
2381
+ type: "confirm",
2382
+ name: "shouldModify",
2383
+ message: i18n.t("language:modifyConfigPrompt"),
2384
+ default: false
2385
+ });
2386
+ if (shouldModify === void 0) {
2387
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
2388
+ process.exit(0);
2389
+ }
2390
+ if (!shouldModify) {
2391
+ console.log(ansis.gray(`\u2714 ${i18n.t("language:aiOutputLangHint")}: ${currentLanguageLabel}`));
2392
+ return savedConfig.aiOutputLang;
2393
+ }
2394
+ return await selectAiOutputLanguage(scriptLang);
2395
+ }
2396
+ return await selectAiOutputLanguage(scriptLang);
2397
+ }
2398
+ async function selectTemplateLanguage() {
2399
+ ensureI18nInitialized();
2400
+ const LANG_HINT_KEYS = {
2401
+ "zh-CN": i18n.t("language:configLangHint.zh-CN"),
2402
+ "en": i18n.t("language:configLangHint.en")
2403
+ };
2404
+ const { lang } = await inquirer.prompt({
2405
+ type: "list",
2406
+ name: "lang",
2407
+ message: i18n.t("language:selectConfigLang"),
2408
+ choices: addNumbersToChoices(
2409
+ SUPPORTED_LANGS.map((l) => ({
2410
+ name: `${LANG_LABELS[l]} - ${LANG_HINT_KEYS[l]}`,
2411
+ value: l
2412
+ }))
2413
+ )
2414
+ });
2415
+ if (!lang) {
2416
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
2417
+ process.exit(0);
2418
+ }
2419
+ return lang;
2420
+ }
2421
+ async function resolveTemplateLanguage(commandLineOption, savedConfig) {
2422
+ ensureI18nInitialized();
2423
+ if (commandLineOption) {
2424
+ return commandLineOption;
2425
+ }
2426
+ if (savedConfig?.templateLang) {
2427
+ const currentLanguageLabel = LANG_LABELS[savedConfig.templateLang];
2428
+ console.log(ansis.blue(`${i18n.t("language:currentTemplateLanguageFound")}: ${currentLanguageLabel}`));
2429
+ const { shouldModify } = await inquirer.prompt({
2430
+ type: "confirm",
2431
+ name: "shouldModify",
2432
+ message: i18n.t("language:modifyTemplateLanguagePrompt"),
2433
+ default: false
2434
+ });
2435
+ if (shouldModify === void 0) {
2436
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
2437
+ process.exit(0);
2438
+ }
2439
+ if (!shouldModify) {
2440
+ console.log(ansis.gray(`\u2714 ${i18n.t("language:selectConfigLang")}: ${currentLanguageLabel}`));
2441
+ return savedConfig.templateLang;
2442
+ }
2443
+ return await selectTemplateLanguage();
2444
+ }
2445
+ if (savedConfig?.preferredLang && !savedConfig?.templateLang) {
2446
+ console.log(ansis.yellow(`${i18n.t("language:usingFallbackTemplate")}: ${LANG_LABELS[savedConfig.preferredLang]}`));
2447
+ const { shouldModify } = await inquirer.prompt({
2448
+ type: "confirm",
2449
+ name: "shouldModify",
2450
+ message: i18n.t("language:modifyTemplateLanguagePrompt"),
2451
+ default: false
2452
+ });
2453
+ if (shouldModify === void 0) {
2454
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
2455
+ process.exit(0);
2456
+ }
2457
+ if (!shouldModify) {
2458
+ return savedConfig.preferredLang;
2459
+ }
2460
+ return await selectTemplateLanguage();
2461
+ }
2462
+ return await selectTemplateLanguage();
2463
+ }
2464
+ async function resolveSystemPromptStyle(availablePrompts, commandLineOption, savedConfig) {
2465
+ ensureI18nInitialized();
2466
+ if (commandLineOption && availablePrompts.some((p) => p.id === commandLineOption)) {
2467
+ return commandLineOption;
2468
+ }
2469
+ if (savedConfig?.codex?.systemPromptStyle) {
2470
+ const currentStyleId = savedConfig.codex.systemPromptStyle;
2471
+ const currentStyle = availablePrompts.find((p) => p.id === currentStyleId);
2472
+ if (currentStyle) {
2473
+ console.log(ansis.blue(`${i18n.t("language:currentSystemPromptFound")}: ${currentStyle.name}`));
2474
+ const { shouldModify } = await inquirer.prompt({
2475
+ type: "confirm",
2476
+ name: "shouldModify",
2477
+ message: i18n.t("language:modifySystemPromptPrompt"),
2478
+ default: false
2479
+ });
2480
+ if (shouldModify === void 0) {
2481
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
2482
+ process.exit(0);
2483
+ }
2484
+ if (!shouldModify) {
2485
+ console.log(ansis.gray(`\u2714 ${i18n.t("language:currentSystemPromptFound")}: ${currentStyle.name}`));
2486
+ return currentStyleId;
2487
+ }
2488
+ }
2489
+ }
2490
+ const { systemPrompt } = await inquirer.prompt([{
2491
+ type: "list",
2492
+ name: "systemPrompt",
2493
+ message: i18n.t("codex:systemPromptPrompt"),
2494
+ choices: addNumbersToChoices(availablePrompts.map((style) => ({
2495
+ name: `${style.name} - ${ansis.gray(style.description)}`,
2496
+ value: style.id
2497
+ }))),
2498
+ default: "engineer-professional"
2499
+ // Default to engineer-professional
2500
+ }]);
2501
+ if (!systemPrompt) {
2502
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
2503
+ process.exit(0);
2504
+ }
2505
+ return systemPrompt;
2506
+ }
2507
+
2508
+ const prompts = {
2509
+ __proto__: null,
2510
+ resolveAiOutputLanguage: resolveAiOutputLanguage,
2511
+ resolveSystemPromptStyle: resolveSystemPromptStyle,
2512
+ resolveTemplateLanguage: resolveTemplateLanguage,
2513
+ selectAiOutputLanguage: selectAiOutputLanguage,
2514
+ selectScriptLanguage: selectScriptLanguage,
2515
+ selectTemplateLanguage: selectTemplateLanguage
2516
+ };
2517
+
2518
+ function detectConfigManagementMode() {
2519
+ try {
2520
+ const config = readCodexConfig();
2521
+ if (!config || !config.providers || config.providers.length === 0) {
2522
+ return {
2523
+ mode: "initial",
2524
+ hasProviders: false,
2525
+ providerCount: 0
2526
+ };
2527
+ }
2528
+ return {
2529
+ mode: "management",
2530
+ hasProviders: true,
2531
+ providerCount: config.providers.length,
2532
+ currentProvider: config.modelProvider,
2533
+ providers: config.providers,
2534
+ isUnmanaged: config.managed === false ? true : void 0
2535
+ };
2536
+ } catch (error) {
2537
+ return {
2538
+ mode: "initial",
2539
+ hasProviders: false,
2540
+ providerCount: 0,
2541
+ error: error instanceof Error ? error.message : "Unknown error"
2542
+ };
2543
+ }
2544
+ }
2545
+
2546
+ const CODEX_DIR = join(homedir(), ".codex");
2547
+ const CODEX_CONFIG_FILE = join(CODEX_DIR, "config.toml");
2548
+ const CODEX_AUTH_FILE = join(CODEX_DIR, "auth.json");
2549
+ const CODEX_AGENTS_FILE = join(CODEX_DIR, "AGENTS.md");
2550
+ const CODEX_PROMPTS_DIR = join(CODEX_DIR, "prompts");
2551
+ function getRootDir$1() {
2552
+ const currentFilePath = fileURLToPath(import.meta.url);
2553
+ let dir = dirname(currentFilePath);
2554
+ while (dir !== dirname(dir)) {
2555
+ if (exists(join(dir, "templates"))) {
2556
+ return dir;
2557
+ }
2558
+ dir = dirname(dir);
2559
+ }
2560
+ return dirname(currentFilePath);
2561
+ }
2562
+ async function executeCodexInstallation(isUpdate) {
2563
+ const action = isUpdate ? "update" : "install";
2564
+ if (isUpdate) {
2565
+ console.log(ansis.cyan(i18n.t("codex:updatingCli")));
2566
+ } else {
2567
+ console.log(ansis.cyan(i18n.t("codex:installingCli")));
2568
+ }
2569
+ const result = await x("npm", ["install", "-g", "@openai/codex"]);
2570
+ if (result.exitCode !== 0) {
2571
+ throw new Error(`Failed to ${action} codex CLI: exit code ${result.exitCode}`);
2572
+ }
2573
+ if (isUpdate) {
2574
+ console.log(ansis.green(i18n.t("codex:updateSuccess")));
2575
+ } else {
2576
+ console.log(ansis.green(i18n.t("codex:installSuccess")));
2577
+ }
2578
+ }
2579
+ function getUninstallOptions() {
2580
+ return [
2581
+ { name: i18n.t("codex:uninstallItemConfig"), value: "config" },
2582
+ { name: i18n.t("codex:uninstallItemAuth"), value: "auth" },
2583
+ { name: i18n.t("codex:uninstallItemApiConfig"), value: "api-config" },
2584
+ { name: i18n.t("codex:uninstallItemMcpConfig"), value: "mcp-config" },
2585
+ { name: i18n.t("codex:uninstallItemSystemPrompt"), value: "system-prompt" },
2586
+ { name: i18n.t("codex:uninstallItemWorkflow"), value: "workflow" },
2587
+ { name: i18n.t("codex:uninstallItemCliPackage"), value: "cli-package" },
2588
+ { name: i18n.t("codex:uninstallItemBackups"), value: "backups" }
2589
+ ];
2590
+ }
2591
+ function handleUninstallCancellation() {
2592
+ console.log(ansis.yellow(i18n.t("codex:uninstallCancelled")));
2593
+ }
2594
+ function createBackupDirectory(timestamp) {
2595
+ const backupBaseDir = join(CODEX_DIR, "backup");
2596
+ const backupDir = join(backupBaseDir, `backup_${timestamp}`);
2597
+ ensureDir(backupDir);
2598
+ return backupDir;
2599
+ }
2600
+ function backupCodexFiles() {
2601
+ if (!exists(CODEX_DIR))
2602
+ return null;
2603
+ const timestamp = dayjs().format("YYYY-MM-DD_HH-mm-ss");
2604
+ const backupDir = createBackupDirectory(timestamp);
2605
+ const filter = (path) => {
2606
+ return !path.includes("/backup");
2607
+ };
2608
+ copyDir(CODEX_DIR, backupDir, { filter });
2609
+ return backupDir;
2610
+ }
2611
+ function backupCodexComplete() {
2612
+ return backupCodexFiles();
2613
+ }
2614
+ function backupCodexConfig() {
2615
+ if (!exists(CODEX_CONFIG_FILE))
2616
+ return null;
2617
+ try {
2618
+ const timestamp = dayjs().format("YYYY-MM-DD_HH-mm-ss");
2619
+ const backupDir = createBackupDirectory(timestamp);
2620
+ const backupPath = join(backupDir, "config.toml");
2621
+ copyFile(CODEX_CONFIG_FILE, backupPath);
2622
+ return backupPath;
2623
+ } catch {
2624
+ return null;
2625
+ }
2626
+ }
2627
+ function backupCodexAgents() {
2628
+ if (!exists(CODEX_AGENTS_FILE))
2629
+ return null;
2630
+ try {
2631
+ const timestamp = dayjs().format("YYYY-MM-DD_HH-mm-ss");
2632
+ const backupDir = createBackupDirectory(timestamp);
2633
+ const backupPath = join(backupDir, "AGENTS.md");
2634
+ copyFile(CODEX_AGENTS_FILE, backupPath);
2635
+ return backupPath;
2636
+ } catch {
2637
+ return null;
2638
+ }
2639
+ }
2640
+ function backupCodexPrompts() {
2641
+ if (!exists(CODEX_PROMPTS_DIR))
2642
+ return null;
2643
+ try {
2644
+ const timestamp = dayjs().format("YYYY-MM-DD_HH-mm-ss");
2645
+ const backupDir = createBackupDirectory(timestamp);
2646
+ const backupPath = join(backupDir, "prompts");
2647
+ copyDir(CODEX_PROMPTS_DIR, backupPath);
2648
+ return backupPath;
2649
+ } catch {
2650
+ return null;
2651
+ }
2652
+ }
2653
+ function getBackupMessage(path) {
2654
+ if (!path)
2655
+ return "";
2656
+ ensureI18nInitialized();
2657
+ return i18n.t("codex:backupSuccess", { path });
2658
+ }
2659
+ function sanitizeProviderName(input) {
2660
+ const cleaned = input.trim();
2661
+ if (!cleaned)
2662
+ return "";
2663
+ return cleaned.replace(/[^\w.-]/g, "");
2664
+ }
2665
+ function parseCodexConfig(content) {
2666
+ if (!content.trim()) {
2667
+ return {
2668
+ model: null,
2669
+ modelProvider: null,
2670
+ providers: [],
2671
+ mcpServices: [],
2672
+ managed: false,
2673
+ otherConfig: [],
2674
+ modelProviderCommented: void 0
2675
+ };
2676
+ }
2677
+ try {
2678
+ const tomlData = parse(content);
2679
+ const providers = [];
2680
+ if (tomlData.model_providers) {
2681
+ for (const [id, providerData] of Object.entries(tomlData.model_providers)) {
2682
+ const provider = providerData;
2683
+ providers.push({
2684
+ id,
2685
+ name: provider.name || id,
2686
+ baseUrl: provider.base_url || "",
2687
+ wireApi: provider.wire_api || "responses",
2688
+ envKey: provider.env_key || "OPENAI_API_KEY",
2689
+ requiresOpenaiAuth: provider.requires_openai_auth !== false
2690
+ });
2691
+ }
2692
+ }
2693
+ const mcpServices = [];
2694
+ if (tomlData.mcp_servers) {
2695
+ for (const [id, mcpData] of Object.entries(tomlData.mcp_servers)) {
2696
+ const mcp = mcpData;
2697
+ mcpServices.push({
2698
+ id,
2699
+ command: mcp.command || id,
2700
+ args: mcp.args || [],
2701
+ env: Object.keys(mcp.env || {}).length > 0 ? mcp.env : void 0,
2702
+ startup_timeout_ms: mcp.startup_timeout_ms
2703
+ });
2704
+ }
2705
+ }
2706
+ const model = tomlData.model || null;
2707
+ let modelProvider = null;
2708
+ let modelProviderCommented;
2709
+ const commentedMatch = content.match(/^(\s*)#\s*model_provider\s*=\s*"([^"]+)"/m);
2710
+ if (commentedMatch) {
2711
+ modelProvider = commentedMatch[2];
2712
+ modelProviderCommented = true;
2713
+ } else {
2714
+ const lines2 = content.split("\n");
2715
+ let inSection = false;
2716
+ for (const line of lines2) {
2717
+ const trimmedLine = line.trim();
2718
+ if (!trimmedLine)
2719
+ continue;
2720
+ if (trimmedLine.startsWith("[")) {
2721
+ inSection = true;
2722
+ continue;
2723
+ }
2724
+ if (trimmedLine.startsWith("#")) {
2725
+ if (trimmedLine.includes("--- model provider added by ZCF ---")) {
2726
+ inSection = false;
2727
+ }
2728
+ continue;
2729
+ }
2730
+ if (!inSection && trimmedLine.startsWith("model_provider")) {
2731
+ const match = trimmedLine.match(/model_provider\s*=\s*"([^"]+)"/);
2732
+ if (match) {
2733
+ modelProvider = match[1];
2734
+ modelProviderCommented = false;
2735
+ break;
2736
+ }
2737
+ }
2738
+ }
2739
+ if (!modelProvider) {
2740
+ modelProvider = tomlData.model_provider || null;
2741
+ modelProviderCommented = false;
2742
+ }
2743
+ }
2744
+ const otherConfig = [];
2745
+ const lines = content.split("\n");
2746
+ let skipCurrentSection = false;
2747
+ let currentSection = "";
2748
+ for (const line of lines) {
2749
+ const trimmedLine = line.trim();
2750
+ if (trimmedLine.includes("--- model provider added by ZCF ---") || trimmedLine.includes("--- MCP servers added by ZCF ---") || trimmedLine.includes("Managed by ZCF")) {
2751
+ continue;
2752
+ }
2753
+ const sectionMatch = trimmedLine.match(/^\[([^\]]+)\]/);
2754
+ if (sectionMatch) {
2755
+ currentSection = sectionMatch[1];
2756
+ skipCurrentSection = currentSection.startsWith("model_providers.") || currentSection.startsWith("mcp_servers.");
2757
+ }
2758
+ if (!skipCurrentSection && (trimmedLine.startsWith("model_provider") || trimmedLine.startsWith("# model_provider") || /^model\s*=/.test(trimmedLine))) {
2759
+ continue;
2760
+ }
2761
+ if (!skipCurrentSection && trimmedLine) {
2762
+ otherConfig.push(line);
2763
+ }
2764
+ }
2765
+ const managed = providers.length > 0 || mcpServices.length > 0 || modelProvider !== null || model !== null;
2766
+ return {
2767
+ model,
2768
+ modelProvider,
2769
+ providers,
2770
+ mcpServices,
2771
+ managed,
2772
+ otherConfig,
2773
+ modelProviderCommented
2774
+ };
2775
+ } catch (error) {
2776
+ console.warn("TOML parsing failed, falling back to basic parsing:", error);
2777
+ return {
2778
+ model: null,
2779
+ modelProvider: null,
2780
+ providers: [],
2781
+ mcpServices: [],
2782
+ managed: false,
2783
+ otherConfig: content.split("\n"),
2784
+ modelProviderCommented: void 0
2785
+ };
2786
+ }
2787
+ }
2788
+ function readCodexConfig() {
2789
+ if (!exists(CODEX_CONFIG_FILE))
2790
+ return null;
2791
+ try {
2792
+ const content = readFile(CODEX_CONFIG_FILE);
2793
+ return parseCodexConfig(content);
2794
+ } catch {
2795
+ return null;
2796
+ }
2797
+ }
2798
+ function renderCodexConfig(data) {
2799
+ const lines = [];
2800
+ if (data.model || data.modelProvider || data.providers.length > 0 || data.modelProviderCommented) {
2801
+ lines.push("# --- model provider added by ZCF ---");
2802
+ if (data.model) {
2803
+ lines.push(`model = "${data.model}"`);
2804
+ }
2805
+ if (data.modelProvider) {
2806
+ const commentPrefix = data.modelProviderCommented ? "# " : "";
2807
+ lines.push(`${commentPrefix}model_provider = "${data.modelProvider}"`);
2808
+ }
2809
+ lines.push("");
2810
+ }
2811
+ if (data.otherConfig && data.otherConfig.length > 0) {
2812
+ lines.push(...data.otherConfig);
2813
+ if (data.providers.length > 0 || data.mcpServices.length > 0) {
2814
+ lines.push("");
2815
+ }
2816
+ }
2817
+ if (data.providers.length > 0) {
2818
+ for (const provider of data.providers) {
2819
+ lines.push("");
2820
+ lines.push(`[model_providers.${provider.id}]`);
2821
+ lines.push(`name = "${provider.name}"`);
2822
+ lines.push(`base_url = "${provider.baseUrl}"`);
2823
+ lines.push(`wire_api = "${provider.wireApi}"`);
2824
+ lines.push(`env_key = "${provider.envKey}"`);
2825
+ lines.push(`requires_openai_auth = ${provider.requiresOpenaiAuth}`);
2826
+ }
2827
+ }
2828
+ if (data.mcpServices.length > 0) {
2829
+ lines.push("");
2830
+ lines.push("# --- MCP servers added by ZCF ---");
2831
+ for (const service of data.mcpServices) {
2832
+ lines.push(`[mcp_servers.${service.id}]`);
2833
+ lines.push(`command = "${service.command}"`);
2834
+ const argsString = service.args.length > 0 ? service.args.map((arg) => `"${arg}"`).join(", ") : "";
2835
+ lines.push(`args = [${argsString}]`);
2836
+ if (service.env && Object.keys(service.env).length > 0) {
2837
+ const envEntries = Object.entries(service.env).map(([key, value]) => `${key} = "${value}"`).join(", ");
2838
+ lines.push(`env = {${envEntries}}`);
2839
+ }
2840
+ if (service.startup_timeout_ms) {
2841
+ lines.push(`startup_timeout_ms = ${service.startup_timeout_ms}`);
2842
+ }
2843
+ lines.push("");
2844
+ }
2845
+ if (lines[lines.length - 1] === "") {
2846
+ lines.pop();
2847
+ }
2848
+ }
2849
+ let result = lines.join("\n");
2850
+ if (result && !result.endsWith("\n")) {
2851
+ result += "\n";
2852
+ }
2853
+ return result;
2854
+ }
2855
+ function writeCodexConfig(data) {
2856
+ ensureDir(CODEX_DIR);
2857
+ writeFile(CODEX_CONFIG_FILE, renderCodexConfig(data));
2858
+ }
2859
+ function writeAuthFile(newEntries) {
2860
+ ensureDir(CODEX_DIR);
2861
+ const existing = readJsonConfig(CODEX_AUTH_FILE, { defaultValue: {} }) || {};
2862
+ const merged = { ...existing, ...newEntries };
2863
+ writeJsonConfig(CODEX_AUTH_FILE, merged, { pretty: true });
2864
+ }
2865
+ async function isCodexInstalled() {
2866
+ try {
2867
+ const result = await x("npm", ["list", "-g", "--depth=0"]);
2868
+ if (result.exitCode !== 0) {
2869
+ return false;
2870
+ }
2871
+ return result.stdout.includes("@openai/codex@");
2872
+ } catch {
2873
+ return false;
2874
+ }
2875
+ }
2876
+ async function getCodexVersion() {
2877
+ try {
2878
+ const result = await x("npm", ["list", "-g", "--depth=0"]);
2879
+ if (result.exitCode !== 0) {
2880
+ return null;
2881
+ }
2882
+ const match = result.stdout.match(/@openai\/codex@(\S+)/);
2883
+ return match ? match[1] : null;
2884
+ } catch {
2885
+ return null;
2886
+ }
2887
+ }
2888
+ async function checkCodexUpdate() {
2889
+ try {
2890
+ const currentVersion = await getCodexVersion();
2891
+ if (!currentVersion) {
2892
+ return {
2893
+ installed: false,
2894
+ currentVersion: null,
2895
+ latestVersion: null,
2896
+ needsUpdate: false
2897
+ };
2898
+ }
2899
+ const result = await x("npm", ["view", "@openai/codex", "--json"]);
2900
+ if (result.exitCode !== 0) {
2901
+ return {
2902
+ installed: true,
2903
+ currentVersion,
2904
+ latestVersion: null,
2905
+ needsUpdate: false
2906
+ };
2907
+ }
2908
+ const packageInfo = JSON.parse(result.stdout);
2909
+ const latestVersion = packageInfo["dist-tags"]?.latest;
2910
+ if (!latestVersion) {
2911
+ return {
2912
+ installed: true,
2913
+ currentVersion,
2914
+ latestVersion: null,
2915
+ needsUpdate: false
2916
+ };
2917
+ }
2918
+ const needsUpdate = semver.gt(latestVersion, currentVersion);
2919
+ return {
2920
+ installed: true,
2921
+ currentVersion,
2922
+ latestVersion,
2923
+ needsUpdate
2924
+ };
2925
+ } catch {
2926
+ return {
2927
+ installed: false,
2928
+ currentVersion: null,
2929
+ latestVersion: null,
2930
+ needsUpdate: false
2931
+ };
2932
+ }
2933
+ }
2934
+ async function installCodexCli() {
2935
+ ensureI18nInitialized();
2936
+ if (await isCodexInstalled()) {
2937
+ const { needsUpdate } = await checkCodexUpdate();
2938
+ if (needsUpdate) {
2939
+ await executeCodexInstallation(true);
2940
+ return;
2941
+ } else {
2942
+ console.log(ansis.yellow(i18n.t("codex:alreadyInstalled")));
2943
+ return;
2944
+ }
2945
+ }
2946
+ await executeCodexInstallation(false);
2947
+ }
2948
+ async function runCodexWorkflowImport() {
2949
+ ensureI18nInitialized();
2950
+ await runCodexSystemPromptSelection();
2951
+ await runCodexWorkflowSelection();
2952
+ console.log(ansis.green(i18n.t("codex:workflowInstall")));
2953
+ }
2954
+ async function runCodexSystemPromptSelection() {
2955
+ ensureI18nInitialized();
2956
+ const rootDir = getRootDir$1();
2957
+ const templateRoot = join(rootDir, "templates", "codex");
2958
+ const zcfConfig$1 = readZcfConfig();
2959
+ const { readDefaultTomlConfig } = await Promise.resolve().then(function () { return zcfConfig; });
2960
+ const tomlConfig = readDefaultTomlConfig();
2961
+ const { resolveTemplateLanguage } = await Promise.resolve().then(function () { return prompts; });
2962
+ const preferredLang = await resolveTemplateLanguage(
2963
+ void 0,
2964
+ // No command line option for this function
2965
+ zcfConfig$1
2966
+ );
2967
+ let langDir = join(templateRoot, preferredLang);
2968
+ if (!exists(langDir))
2969
+ langDir = join(templateRoot, "zh-CN");
2970
+ const systemPromptSrc = join(langDir, "system-prompt");
2971
+ if (!exists(systemPromptSrc))
2972
+ return;
2973
+ const availablePrompts = [
2974
+ {
2975
+ id: "engineer-professional",
2976
+ name: i18n.t("configuration:outputStyles.engineer-professional.name"),
2977
+ description: i18n.t("configuration:outputStyles.engineer-professional.description")
2978
+ },
2979
+ {
2980
+ id: "laowang-engineer",
2981
+ name: i18n.t("configuration:outputStyles.laowang-engineer.name"),
2982
+ description: i18n.t("configuration:outputStyles.laowang-engineer.description")
2983
+ },
2984
+ {
2985
+ id: "nekomata-engineer",
2986
+ name: i18n.t("configuration:outputStyles.nekomata-engineer.name"),
2987
+ description: i18n.t("configuration:outputStyles.nekomata-engineer.description")
2988
+ }
2989
+ ].filter((style) => exists(join(systemPromptSrc, `${style.id}.md`)));
2990
+ if (availablePrompts.length === 0)
2991
+ return;
2992
+ const { resolveSystemPromptStyle } = await Promise.resolve().then(function () { return prompts; });
2993
+ const systemPrompt = await resolveSystemPromptStyle(
2994
+ availablePrompts,
2995
+ void 0,
2996
+ // No command line option for this function
2997
+ tomlConfig
2998
+ );
2999
+ if (!systemPrompt)
3000
+ return;
3001
+ const promptFile = join(systemPromptSrc, `${systemPrompt}.md`);
3002
+ const content = readFile(promptFile);
3003
+ ensureDir(CODEX_DIR);
3004
+ const backupPath = backupCodexAgents();
3005
+ if (backupPath) {
3006
+ console.log(ansis.gray(getBackupMessage(backupPath)));
3007
+ }
3008
+ writeFile(CODEX_AGENTS_FILE, content);
3009
+ try {
3010
+ const { updateTomlConfig } = await Promise.resolve().then(function () { return zcfConfig; });
3011
+ const { ZCF_CONFIG_FILE } = await Promise.resolve().then(function () { return constants; });
3012
+ updateTomlConfig(ZCF_CONFIG_FILE, {
3013
+ codex: {
3014
+ systemPromptStyle: systemPrompt
3015
+ }
3016
+ });
3017
+ } catch (error) {
3018
+ console.error("Failed to update ZCF config:", error);
3019
+ }
3020
+ }
3021
+ async function runCodexWorkflowSelection() {
3022
+ ensureI18nInitialized();
3023
+ const rootDir = getRootDir$1();
3024
+ const templateRoot = join(rootDir, "templates", "codex");
3025
+ const zcfConfig = readZcfConfig();
3026
+ const templateLang = zcfConfig?.templateLang || zcfConfig?.preferredLang || "en";
3027
+ const preferredLang = templateLang === "en" ? "en" : "zh-CN";
3028
+ let langDir = join(templateRoot, preferredLang);
3029
+ if (!exists(langDir))
3030
+ langDir = join(templateRoot, "zh-CN");
3031
+ const workflowSrc = join(langDir, "workflow");
3032
+ if (!exists(workflowSrc))
3033
+ return;
3034
+ const allWorkflows = getAllWorkflowFiles(workflowSrc);
3035
+ if (allWorkflows.length === 0)
3036
+ return;
3037
+ const { workflows } = await inquirer.prompt([{
3038
+ type: "checkbox",
3039
+ name: "workflows",
3040
+ message: i18n.t("codex:workflowSelectionPrompt"),
3041
+ choices: addNumbersToChoices(allWorkflows.map((workflow) => ({
3042
+ name: workflow.name,
3043
+ value: workflow.path,
3044
+ checked: true
3045
+ // Default all selected
3046
+ })))
3047
+ }]);
3048
+ if (!workflows || workflows.length === 0)
3049
+ return;
3050
+ ensureDir(CODEX_PROMPTS_DIR);
3051
+ const backupPath = backupCodexPrompts();
3052
+ if (backupPath) {
3053
+ console.log(ansis.gray(getBackupMessage(backupPath)));
3054
+ }
3055
+ for (const workflowPath of workflows) {
3056
+ const content = readFile(workflowPath);
3057
+ const filename = workflowPath.split("/").pop() || "workflow.md";
3058
+ const targetPath = join(CODEX_PROMPTS_DIR, filename);
3059
+ writeFile(targetPath, content);
3060
+ }
3061
+ }
3062
+ function getAllWorkflowFiles(dirPath) {
3063
+ const workflows = [];
3064
+ const sixStepDir = join(dirPath, "sixStep", "prompts");
3065
+ if (exists(sixStepDir)) {
3066
+ const workflowFile = join(sixStepDir, "workflow.md");
3067
+ if (exists(workflowFile)) {
3068
+ workflows.push({
3069
+ name: i18n.t("workflow:workflowOption.sixStepsWorkflow"),
3070
+ path: workflowFile
3071
+ });
3072
+ }
3073
+ }
3074
+ return workflows;
3075
+ }
3076
+ function toProvidersList(providers) {
3077
+ return providers.map((provider) => ({ name: provider.name || provider.id, value: provider.id }));
3078
+ }
3079
+ function createApiConfigChoices(providers, currentProvider, isCommented) {
3080
+ const choices = [];
3081
+ const isOfficialMode = !currentProvider || isCommented;
3082
+ choices.push({
3083
+ name: isOfficialMode ? `${ansis.green("\u25CF ")}${i18n.t("codex:useOfficialLogin")} ${ansis.yellow("(\u5F53\u524D)")}` : ` ${i18n.t("codex:useOfficialLogin")}`,
3084
+ value: "official"
3085
+ });
3086
+ providers.forEach((provider) => {
3087
+ const isCurrent = currentProvider === provider.id && !isCommented;
3088
+ choices.push({
3089
+ name: isCurrent ? `${ansis.green("\u25CF ")}${provider.name} - ${ansis.gray(provider.id)} ${ansis.yellow("(\u5F53\u524D)")}` : ` ${provider.name} - ${ansis.gray(provider.id)}`,
3090
+ value: provider.id
3091
+ });
3092
+ });
3093
+ return choices;
3094
+ }
3095
+ async function configureCodexApi() {
3096
+ ensureI18nInitialized();
3097
+ const existingConfig = readCodexConfig();
3098
+ const hasProviders = existingConfig?.providers && existingConfig.providers.length > 0;
3099
+ const modeChoices = [
3100
+ { name: i18n.t("codex:apiModeOfficial"), value: "official" },
3101
+ { name: i18n.t("codex:apiModeCustom"), value: "custom" }
3102
+ ];
3103
+ if (hasProviders) {
3104
+ modeChoices.push({ name: i18n.t("codex:configSwitchMode"), value: "switch" });
3105
+ }
3106
+ const { mode } = await inquirer.prompt([{
3107
+ type: "list",
3108
+ name: "mode",
3109
+ message: i18n.t("codex:apiModePrompt"),
3110
+ choices: addNumbersToChoices(modeChoices),
3111
+ default: "custom"
3112
+ }]);
3113
+ if (!mode) {
3114
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
3115
+ return;
3116
+ }
3117
+ if (mode === "official") {
3118
+ const success = await switchToOfficialLogin();
3119
+ if (success) {
3120
+ updateZcfConfig({ codeToolType: "codex" });
3121
+ }
3122
+ return;
3123
+ }
3124
+ if (mode === "switch") {
3125
+ if (!hasProviders) {
3126
+ console.log(ansis.yellow(i18n.t("codex:noProvidersAvailable")));
3127
+ return;
3128
+ }
3129
+ const currentProvider = existingConfig?.modelProvider;
3130
+ const isCommented = existingConfig?.modelProviderCommented;
3131
+ const choices = createApiConfigChoices(existingConfig.providers, currentProvider, isCommented);
3132
+ const { selectedConfig } = await inquirer.prompt([{
3133
+ type: "list",
3134
+ name: "selectedConfig",
3135
+ message: i18n.t("codex:apiConfigSwitchPrompt"),
3136
+ choices: addNumbersToChoices(choices)
3137
+ }]);
3138
+ if (!selectedConfig) {
3139
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
3140
+ return;
3141
+ }
3142
+ let success = false;
3143
+ if (selectedConfig === "official") {
3144
+ success = await switchToOfficialLogin();
3145
+ } else {
3146
+ success = await switchToProvider(selectedConfig);
3147
+ }
3148
+ if (success) {
3149
+ updateZcfConfig({ codeToolType: "codex" });
3150
+ }
3151
+ return;
3152
+ }
3153
+ const managementMode = detectConfigManagementMode();
3154
+ if (managementMode.mode === "management" && managementMode.hasProviders) {
3155
+ const { default: { configureIncrementalManagement } } = await import('./codex-config-switch.mjs');
3156
+ await configureIncrementalManagement();
3157
+ return;
3158
+ }
3159
+ const backupPath = backupCodexComplete();
3160
+ if (backupPath) {
3161
+ console.log(ansis.gray(getBackupMessage(backupPath)));
3162
+ }
3163
+ const providers = [];
3164
+ const authEntries = {};
3165
+ const existingMap = new Map(existingConfig?.providers.map((provider) => [provider.id, provider]));
3166
+ const currentSessionProviders = /* @__PURE__ */ new Map();
3167
+ let addMore = true;
3168
+ const existingValues = existingMap.size ? Array.from(existingMap.values()) : [];
3169
+ const firstExisting = existingValues.length === 1 ? existingValues[0] : void 0;
3170
+ while (addMore) {
3171
+ const answers = await inquirer.prompt([
3172
+ {
3173
+ type: "input",
3174
+ name: "providerName",
3175
+ message: i18n.t("codex:providerNamePrompt"),
3176
+ default: firstExisting?.name,
3177
+ validate: (input) => {
3178
+ const sanitized = sanitizeProviderName(input);
3179
+ if (!sanitized)
3180
+ return i18n.t("codex:providerNameRequired");
3181
+ if (sanitized !== input.trim())
3182
+ return i18n.t("codex:providerNameInvalid");
3183
+ return true;
3184
+ }
3185
+ },
3186
+ {
3187
+ type: "input",
3188
+ name: "baseUrl",
3189
+ message: i18n.t("codex:providerBaseUrlPrompt"),
3190
+ default: (answers2) => existingMap.get(answers2.providerId)?.baseUrl || "https://api.openai.com/v1",
3191
+ validate: (input) => !!input || i18n.t("codex:providerBaseUrlRequired")
3192
+ },
3193
+ {
3194
+ type: "list",
3195
+ name: "wireApi",
3196
+ message: i18n.t("codex:providerProtocolPrompt"),
3197
+ choices: [
3198
+ { name: i18n.t("codex:protocolResponses"), value: "responses" },
3199
+ { name: i18n.t("codex:protocolChat"), value: "chat" }
3200
+ ],
3201
+ default: (answers2) => existingMap.get(sanitizeProviderName(answers2.providerName))?.wireApi || "responses"
3202
+ },
3203
+ {
3204
+ type: "password",
3205
+ name: "apiKey",
3206
+ message: i18n.t("codex:providerApiKeyPrompt") + i18n.t("common:inputHidden"),
3207
+ validate: (input) => !!input || i18n.t("codex:providerApiKeyRequired")
3208
+ }
3209
+ ]);
3210
+ const providerId = sanitizeProviderName(answers.providerName);
3211
+ const envKey = `${providerId.toUpperCase().replace(/-/g, "_")}_API_KEY`;
3212
+ const existingProvider = existingMap.get(providerId);
3213
+ const sessionProvider = currentSessionProviders.get(providerId);
3214
+ if (existingProvider || sessionProvider) {
3215
+ const sourceType = existingProvider ? "existing" : "session";
3216
+ const sourceProvider = existingProvider || sessionProvider;
3217
+ const { shouldOverwrite } = await inquirer.prompt([{
3218
+ type: "confirm",
3219
+ name: "shouldOverwrite",
3220
+ message: i18n.t("codex:providerDuplicatePrompt", {
3221
+ name: sourceProvider.name,
3222
+ source: sourceType === "existing" ? i18n.t("codex:existingConfig") : i18n.t("codex:currentSession")
3223
+ }),
3224
+ default: false
3225
+ }]);
3226
+ if (!shouldOverwrite) {
3227
+ console.log(ansis.yellow(i18n.t("codex:providerDuplicateSkipped")));
3228
+ continue;
3229
+ }
3230
+ if (sessionProvider) {
3231
+ currentSessionProviders.delete(providerId);
3232
+ const sessionIndex = providers.findIndex((p) => p.id === providerId);
3233
+ if (sessionIndex !== -1) {
3234
+ providers.splice(sessionIndex, 1);
3235
+ }
3236
+ }
3237
+ }
3238
+ const newProvider = {
3239
+ id: providerId,
3240
+ name: answers.providerName,
3241
+ baseUrl: answers.baseUrl,
3242
+ wireApi: answers.wireApi || "responses",
3243
+ envKey,
3244
+ requiresOpenaiAuth: true
3245
+ };
3246
+ providers.push(newProvider);
3247
+ currentSessionProviders.set(providerId, newProvider);
3248
+ authEntries[envKey] = answers.apiKey;
3249
+ const { addAnother } = await inquirer.prompt([{
3250
+ type: "confirm",
3251
+ name: "addAnother",
3252
+ message: i18n.t("codex:addProviderPrompt"),
3253
+ default: false
3254
+ }]);
3255
+ addMore = addAnother;
3256
+ }
3257
+ if (providers.length === 0) {
3258
+ console.log(ansis.yellow(i18n.t("codex:noProvidersConfigured")));
3259
+ return;
3260
+ }
3261
+ const { defaultProvider } = await inquirer.prompt([{
3262
+ type: "list",
3263
+ name: "defaultProvider",
3264
+ message: i18n.t("codex:selectDefaultProviderPrompt"),
3265
+ choices: addNumbersToChoices(toProvidersList(providers)),
3266
+ default: existingConfig?.modelProvider || providers[0].id
3267
+ }]);
3268
+ writeCodexConfig({
3269
+ model: existingConfig?.model || null,
3270
+ modelProvider: defaultProvider,
3271
+ providers,
3272
+ mcpServices: existingConfig?.mcpServices || [],
3273
+ otherConfig: existingConfig?.otherConfig || []
3274
+ });
3275
+ writeAuthFile(authEntries);
3276
+ updateZcfConfig({ codeToolType: "codex" });
3277
+ console.log(ansis.green(i18n.t("codex:apiConfigured")));
3278
+ }
3279
+ async function configureCodexMcp() {
3280
+ ensureI18nInitialized();
3281
+ const existingConfig = readCodexConfig();
3282
+ const backupPath = backupCodexComplete();
3283
+ if (backupPath) {
3284
+ console.log(ansis.gray(getBackupMessage(backupPath)));
3285
+ }
3286
+ const selectedIds = await selectMcpServices();
3287
+ if (!selectedIds)
3288
+ return;
3289
+ const servicesMeta = await getMcpServices();
3290
+ const baseProviders = existingConfig?.providers || [];
3291
+ const selection = [];
3292
+ const existingMap = new Map((existingConfig?.mcpServices || []).map((service) => [service.id, service]));
3293
+ if (selectedIds.length === 0) {
3294
+ console.log(ansis.yellow(i18n.t("codex:noMcpConfigured")));
3295
+ writeCodexConfig({
3296
+ model: existingConfig?.model || null,
3297
+ modelProvider: existingConfig?.modelProvider || null,
3298
+ providers: baseProviders,
3299
+ mcpServices: Array.from(existingMap.values()),
3300
+ otherConfig: existingConfig?.otherConfig || []
3301
+ });
3302
+ updateZcfConfig({ codeToolType: "codex" });
3303
+ return;
3304
+ }
3305
+ for (const id of selectedIds) {
3306
+ const configInfo = MCP_SERVICE_CONFIGS.find((service) => service.id === id);
3307
+ if (!configInfo)
3308
+ continue;
3309
+ const serviceMeta = servicesMeta.find((service) => service.id === id);
3310
+ let command = configInfo.config.command || id;
3311
+ const args = (configInfo.config.args || []).map((arg) => String(arg));
3312
+ if (isWindows() && command === "npx")
3313
+ command = "npx.cmd";
3314
+ const env = { ...configInfo.config.env || {} };
3315
+ if (configInfo.requiresApiKey && configInfo.apiKeyEnvVar) {
3316
+ const promptMessage = serviceMeta?.apiKeyPrompt || i18n.t("mcp:apiKeyPrompt");
3317
+ const { apiKey } = await inquirer.prompt([{
3318
+ type: "password",
3319
+ name: "apiKey",
3320
+ message: promptMessage + i18n.t("common:inputHidden"),
3321
+ validate: (input) => !!input || i18n.t("api:keyRequired")
3322
+ }]);
3323
+ if (!apiKey)
3324
+ continue;
3325
+ env[configInfo.apiKeyEnvVar] = apiKey;
3326
+ }
3327
+ selection.push({
3328
+ id: id.toLowerCase(),
3329
+ // Convert to lowercase for Codex compatibility
3330
+ command,
3331
+ args,
3332
+ env: Object.keys(env).length > 0 ? env : void 0,
3333
+ startup_timeout_ms: configInfo.config.startup_timeout_ms
3334
+ });
3335
+ }
3336
+ const selectionMap = new Map(selection.map((service) => [service.id, service]));
3337
+ const mergedMap = new Map(existingMap);
3338
+ for (const service of selectionMap.values())
3339
+ mergedMap.set(service.id, service);
3340
+ writeCodexConfig({
3341
+ model: existingConfig?.model || null,
3342
+ modelProvider: existingConfig?.modelProvider || null,
3343
+ providers: baseProviders,
3344
+ mcpServices: Array.from(mergedMap.values()),
3345
+ otherConfig: existingConfig?.otherConfig || []
3346
+ });
3347
+ updateZcfConfig({ codeToolType: "codex" });
3348
+ console.log(ansis.green(i18n.t("codex:mcpConfigured")));
3349
+ }
3350
+ async function runCodexFullInit() {
3351
+ ensureI18nInitialized();
3352
+ await installCodexCli();
3353
+ await runCodexWorkflowImport();
3354
+ await configureCodexApi();
3355
+ await configureCodexMcp();
3356
+ }
3357
+ async function runCodexUpdate(force = false, skipPrompt = false) {
3358
+ ensureI18nInitialized();
3359
+ const spinner = ora(i18n.t("codex:checkingVersion")).start();
3360
+ try {
3361
+ const { installed, currentVersion, latestVersion, needsUpdate } = await checkCodexUpdate();
3362
+ spinner.stop();
3363
+ if (!installed) {
3364
+ console.log(ansis.yellow(i18n.t("codex:notInstalled")));
3365
+ return false;
3366
+ }
3367
+ if (!needsUpdate && !force) {
3368
+ console.log(ansis.green(format(i18n.t("codex:upToDate"), { version: currentVersion || "" })));
3369
+ return true;
3370
+ }
3371
+ if (!latestVersion) {
3372
+ console.log(ansis.yellow(i18n.t("codex:cannotCheckVersion")));
3373
+ return false;
3374
+ }
3375
+ console.log(ansis.cyan(format(i18n.t("codex:currentVersion"), { version: currentVersion || "" })));
3376
+ console.log(ansis.cyan(format(i18n.t("codex:latestVersion"), { version: latestVersion })));
3377
+ if (!skipPrompt) {
3378
+ const { confirm } = await inquirer.prompt({
3379
+ type: "confirm",
3380
+ name: "confirm",
3381
+ message: i18n.t("codex:confirmUpdate"),
3382
+ default: true
3383
+ });
3384
+ if (!confirm) {
3385
+ console.log(ansis.gray(i18n.t("codex:updateSkipped")));
3386
+ return true;
3387
+ }
3388
+ } else {
3389
+ console.log(ansis.cyan(i18n.t("codex:autoUpdating")));
3390
+ }
3391
+ const updateSpinner = ora(i18n.t("codex:updating")).start();
3392
+ try {
3393
+ await executeCodexInstallation(true);
3394
+ updateSpinner.succeed(i18n.t("codex:updateSuccess"));
3395
+ return true;
3396
+ } catch (error) {
3397
+ updateSpinner.fail(i18n.t("codex:updateFailed"));
3398
+ console.error(ansis.red(error instanceof Error ? error.message : String(error)));
3399
+ return false;
3400
+ }
3401
+ } catch (error) {
3402
+ spinner.fail(i18n.t("codex:checkFailed"));
3403
+ console.error(ansis.red(error instanceof Error ? error.message : String(error)));
3404
+ return false;
3405
+ }
3406
+ }
3407
+ async function runCodexUninstall() {
3408
+ ensureI18nInitialized();
3409
+ const { CodexUninstaller } = await import('./codex-uninstaller.mjs');
3410
+ const uninstaller = new CodexUninstaller("en");
3411
+ const { mode } = await inquirer.prompt([{
3412
+ type: "list",
3413
+ name: "mode",
3414
+ message: i18n.t("codex:uninstallModePrompt"),
3415
+ choices: addNumbersToChoices([
3416
+ { name: i18n.t("codex:uninstallModeComplete"), value: "complete" },
3417
+ { name: i18n.t("codex:uninstallModeCustom"), value: "custom" }
3418
+ ]),
3419
+ default: "complete"
3420
+ }]);
3421
+ if (!mode) {
3422
+ handleUninstallCancellation();
3423
+ return;
3424
+ }
3425
+ try {
3426
+ if (mode === "complete") {
3427
+ const { confirm } = await inquirer.prompt([{
3428
+ type: "confirm",
3429
+ name: "confirm",
3430
+ message: i18n.t("codex:uninstallPrompt"),
3431
+ default: false
3432
+ }]);
3433
+ if (!confirm) {
3434
+ handleUninstallCancellation();
3435
+ return;
3436
+ }
3437
+ const result = await uninstaller.completeUninstall();
3438
+ displayUninstallResults([result]);
3439
+ } else if (mode === "custom") {
3440
+ const { items } = await inquirer.prompt([{
3441
+ type: "checkbox",
3442
+ name: "items",
3443
+ message: i18n.t("codex:customUninstallPrompt"),
3444
+ choices: addNumbersToChoices(getUninstallOptions())
3445
+ }]);
3446
+ if (!items || items.length === 0) {
3447
+ handleUninstallCancellation();
3448
+ return;
3449
+ }
3450
+ const results = await uninstaller.customUninstall(items);
3451
+ displayUninstallResults(results);
3452
+ }
3453
+ console.log(ansis.green(i18n.t("codex:uninstallSuccess")));
3454
+ } catch (error) {
3455
+ console.error(ansis.red(`Error during uninstall: ${error.message}`));
3456
+ throw error;
3457
+ }
3458
+ }
3459
+ function displayUninstallResults(results) {
3460
+ for (const result of results) {
3461
+ for (const item of result.removed) {
3462
+ console.log(ansis.green(`\u2714 ${i18n.t("codex:removedItem", { item })}`));
3463
+ }
3464
+ for (const config of result.removedConfigs) {
3465
+ console.log(ansis.green(`\u2714 ${i18n.t("codex:removedConfig", { config })}`));
3466
+ }
3467
+ for (const warning of result.warnings) {
3468
+ console.log(ansis.yellow(`\u26A0\uFE0F ${warning}`));
3469
+ }
3470
+ for (const error of result.errors) {
3471
+ console.log(ansis.red(`\u274C ${error}`));
3472
+ }
3473
+ }
3474
+ }
3475
+ async function getCurrentCodexProvider() {
3476
+ const config = readCodexConfig();
3477
+ return config?.modelProvider || null;
3478
+ }
3479
+ async function listCodexProviders() {
3480
+ const config = readCodexConfig();
3481
+ return config?.providers || [];
3482
+ }
3483
+ async function switchCodexProvider(providerId) {
3484
+ ensureI18nInitialized();
3485
+ const existingConfig = readCodexConfig();
3486
+ if (!existingConfig) {
3487
+ console.log(ansis.red(i18n.t("codex:configNotFound")));
3488
+ return false;
3489
+ }
3490
+ const providerExists = existingConfig.providers.some((provider) => provider.id === providerId);
3491
+ if (!providerExists) {
3492
+ console.log(ansis.red(i18n.t("codex:providerNotFound", { provider: providerId })));
3493
+ return false;
3494
+ }
3495
+ const backupPath = backupCodexComplete();
3496
+ if (backupPath) {
3497
+ console.log(ansis.gray(getBackupMessage(backupPath)));
3498
+ }
3499
+ const updatedConfig = {
3500
+ ...existingConfig,
3501
+ modelProvider: providerId
3502
+ };
3503
+ try {
3504
+ writeCodexConfig(updatedConfig);
3505
+ console.log(ansis.green(i18n.t("codex:providerSwitchSuccess", { provider: providerId })));
3506
+ return true;
3507
+ } catch (error) {
3508
+ console.error(ansis.red(`Error switching provider: ${error.message}`));
3509
+ return false;
3510
+ }
3511
+ }
3512
+ async function switchToOfficialLogin() {
3513
+ ensureI18nInitialized();
3514
+ const existingConfig = readCodexConfig();
3515
+ if (!existingConfig) {
3516
+ console.log(ansis.red(i18n.t("codex:configNotFound")));
3517
+ return false;
3518
+ }
3519
+ const backupPath = backupCodexComplete();
3520
+ if (backupPath) {
3521
+ console.log(ansis.gray(getBackupMessage(backupPath)));
3522
+ }
3523
+ try {
3524
+ const updatedConfig = {
3525
+ ...existingConfig,
3526
+ modelProvider: existingConfig.modelProvider,
3527
+ // Keep the current provider value
3528
+ modelProviderCommented: true
3529
+ // Mark as commented
3530
+ };
3531
+ writeCodexConfig(updatedConfig);
3532
+ const auth = readJsonConfig(CODEX_AUTH_FILE, { defaultValue: {} }) || {};
3533
+ auth.OPENAI_API_KEY = null;
3534
+ writeJsonConfig(CODEX_AUTH_FILE, auth, { pretty: true });
3535
+ console.log(ansis.green(i18n.t("codex:officialConfigured")));
3536
+ return true;
3537
+ } catch (error) {
3538
+ console.error(ansis.red(`Error switching to official login: ${error.message}`));
3539
+ return false;
3540
+ }
3541
+ }
3542
+ async function switchToProvider(providerId) {
3543
+ ensureI18nInitialized();
3544
+ const existingConfig = readCodexConfig();
3545
+ if (!existingConfig) {
3546
+ console.log(ansis.red(i18n.t("codex:configNotFound")));
3547
+ return false;
3548
+ }
3549
+ const provider = existingConfig.providers.find((p) => p.id === providerId);
3550
+ if (!provider) {
3551
+ console.log(ansis.red(i18n.t("codex:providerNotFound", { provider: providerId })));
3552
+ return false;
3553
+ }
3554
+ const backupPath = backupCodexComplete();
3555
+ if (backupPath) {
3556
+ console.log(ansis.gray(getBackupMessage(backupPath)));
3557
+ }
3558
+ try {
3559
+ const updatedConfig = {
3560
+ ...existingConfig,
3561
+ modelProvider: providerId,
3562
+ modelProviderCommented: false
3563
+ // Ensure it's not commented
3564
+ };
3565
+ writeCodexConfig(updatedConfig);
3566
+ const auth = readJsonConfig(CODEX_AUTH_FILE, { defaultValue: {} }) || {};
3567
+ const envValue = auth[provider.envKey] || null;
3568
+ auth.OPENAI_API_KEY = envValue;
3569
+ writeJsonConfig(CODEX_AUTH_FILE, auth, { pretty: true });
3570
+ console.log(ansis.green(i18n.t("codex:providerSwitchSuccess", { provider: providerId })));
3571
+ return true;
3572
+ } catch (error) {
3573
+ console.error(ansis.red(`Error switching to provider: ${error.message}`));
3574
+ return false;
3575
+ }
3576
+ }
3577
+
3578
+ const codex = {
3579
+ __proto__: null,
3580
+ CODEX_DIR: CODEX_DIR,
3581
+ backupCodexAgents: backupCodexAgents,
3582
+ backupCodexComplete: backupCodexComplete,
3583
+ backupCodexConfig: backupCodexConfig,
3584
+ backupCodexFiles: backupCodexFiles,
3585
+ backupCodexPrompts: backupCodexPrompts,
3586
+ checkCodexUpdate: checkCodexUpdate,
3587
+ configureCodexApi: configureCodexApi,
3588
+ configureCodexMcp: configureCodexMcp,
3589
+ createBackupDirectory: createBackupDirectory,
3590
+ getBackupMessage: getBackupMessage,
3591
+ getCodexVersion: getCodexVersion,
3592
+ getCurrentCodexProvider: getCurrentCodexProvider,
3593
+ installCodexCli: installCodexCli,
3594
+ isCodexInstalled: isCodexInstalled,
3595
+ listCodexProviders: listCodexProviders,
3596
+ parseCodexConfig: parseCodexConfig,
3597
+ readCodexConfig: readCodexConfig,
3598
+ renderCodexConfig: renderCodexConfig,
3599
+ runCodexFullInit: runCodexFullInit,
3600
+ runCodexSystemPromptSelection: runCodexSystemPromptSelection,
3601
+ runCodexUninstall: runCodexUninstall,
3602
+ runCodexUpdate: runCodexUpdate,
3603
+ runCodexWorkflowImport: runCodexWorkflowImport,
3604
+ runCodexWorkflowSelection: runCodexWorkflowSelection,
3605
+ switchCodexProvider: switchCodexProvider,
3606
+ switchToOfficialLogin: switchToOfficialLogin,
3607
+ switchToProvider: switchToProvider,
3608
+ writeAuthFile: writeAuthFile,
3609
+ writeCodexConfig: writeCodexConfig
3610
+ };
3611
+
3612
+ function getPlatformStatusLineConfig() {
3613
+ return {
3614
+ type: "command",
3615
+ command: isWindows() ? "%USERPROFILE%\\.claude\\ccline\\ccline.exe" : "~/.claude/ccline/ccline",
3616
+ padding: 0
3617
+ };
3618
+ }
3619
+
3620
+ function addCCometixLineConfig() {
3621
+ try {
3622
+ const statusLineConfig = getPlatformStatusLineConfig();
3623
+ let settings = {};
3624
+ if (exists(SETTINGS_FILE)) {
3625
+ settings = readJsonConfig(SETTINGS_FILE) || {};
3626
+ }
3627
+ settings.statusLine = statusLineConfig;
3628
+ writeJsonConfig(SETTINGS_FILE, settings);
3629
+ return true;
3630
+ } catch (error) {
3631
+ console.error("Failed to add CCometixLine configuration:", error);
3632
+ return false;
3633
+ }
3634
+ }
2013
3635
  function hasCCometixLineConfig() {
2014
3636
  try {
2015
3637
  if (!exists(SETTINGS_FILE)) {
@@ -2082,59 +3704,6 @@ async function installCometixLine() {
2082
3704
  }
2083
3705
  }
2084
3706
 
2085
- function addNumbersToChoices(choices, startFrom = 1, format = (n) => `${n}. `) {
2086
- let currentNumber = startFrom;
2087
- return choices.map((choice) => {
2088
- if (choice.disabled) {
2089
- return choice;
2090
- }
2091
- const numbered = {
2092
- ...choice,
2093
- name: `${format(currentNumber)}${choice.name}`
2094
- };
2095
- currentNumber++;
2096
- return numbered;
2097
- });
2098
- }
2099
-
2100
- function readZcfConfig() {
2101
- let config = readJsonConfig(ZCF_CONFIG_FILE);
2102
- if (!config && existsSync(LEGACY_ZCF_CONFIG_FILE)) {
2103
- config = readJsonConfig(LEGACY_ZCF_CONFIG_FILE);
2104
- }
2105
- return config;
2106
- }
2107
- async function readZcfConfigAsync() {
2108
- return readZcfConfig();
2109
- }
2110
- function writeZcfConfig(config) {
2111
- try {
2112
- writeJsonConfig(ZCF_CONFIG_FILE, config);
2113
- } catch {
2114
- }
2115
- }
2116
- function updateZcfConfig(updates) {
2117
- const existingConfig = readZcfConfig();
2118
- const newConfig = {
2119
- version: updates.version || existingConfig?.version || "1.0.0",
2120
- preferredLang: updates.preferredLang || existingConfig?.preferredLang || "en",
2121
- aiOutputLang: updates.aiOutputLang || existingConfig?.aiOutputLang,
2122
- outputStyles: updates.outputStyles !== void 0 ? updates.outputStyles : existingConfig?.outputStyles,
2123
- defaultOutputStyle: updates.defaultOutputStyle !== void 0 ? updates.defaultOutputStyle : existingConfig?.defaultOutputStyle,
2124
- claudeCodeInstallation: updates.claudeCodeInstallation !== void 0 ? updates.claudeCodeInstallation : existingConfig?.claudeCodeInstallation,
2125
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
2126
- };
2127
- writeZcfConfig(newConfig);
2128
- }
2129
- function getZcfConfig() {
2130
- const config = readZcfConfig();
2131
- return config || {
2132
- version: "1.0.0",
2133
- preferredLang: "en",
2134
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
2135
- };
2136
- }
2137
-
2138
3707
  const OUTPUT_STYLES = [
2139
3708
  // Custom styles (have template files)
2140
3709
  {
@@ -2176,7 +3745,7 @@ async function copyOutputStyles(selectedStyles, lang) {
2176
3745
  const currentFilePath = fileURLToPath(import.meta.url);
2177
3746
  const distDir = dirname(dirname(currentFilePath));
2178
3747
  const rootDir = dirname(distDir);
2179
- const templateDir = join(rootDir, "templates", lang, "output-styles");
3748
+ const templateDir = join(rootDir, "templates", "claude-code", lang, "output-styles");
2180
3749
  for (const styleId of selectedStyles) {
2181
3750
  const style = OUTPUT_STYLES.find((s) => s.id === styleId);
2182
3751
  if (!style || !style.isCustom || !style.filePath) {
@@ -2392,9 +3961,9 @@ async function configureApiCompletely(preselectedAuthType) {
2392
3961
  console.log(ansis.yellow(i18n.t("common:cancelled")));
2393
3962
  return null;
2394
3963
  }
2395
- const keyMessage = authType === "auth_token" ? i18n.t("api:enterAuthToken") : i18n.t("api:enterApiKey");
3964
+ const keyMessage = authType === "auth_token" ? i18n.t("api:enterAuthToken") + i18n.t("common:inputHidden") : i18n.t("api:enterApiKey") + i18n.t("common:inputHidden");
2396
3965
  const { key } = await inquirer.prompt({
2397
- type: "input",
3966
+ type: "password",
2398
3967
  name: "key",
2399
3968
  message: keyMessage,
2400
3969
  validate: async (value) => {
@@ -2465,9 +4034,9 @@ async function modifyApiConfigPartially(existingConfig) {
2465
4034
  }
2466
4035
  } else if (item === "key") {
2467
4036
  const authType = currentConfig.authType || "auth_token";
2468
- const keyMessage = authType === "auth_token" ? i18n.t("api:enterNewApiKey").replace("{key}", currentConfig.key ? formatApiKeyDisplay(currentConfig.key) : i18n.t("common:none")) : i18n.t("api:enterNewApiKey").replace("{key}", currentConfig.key ? formatApiKeyDisplay(currentConfig.key) : i18n.t("common:none"));
4037
+ const keyMessage = authType === "auth_token" ? i18n.t("api:enterNewApiKey").replace("{key}", currentConfig.key ? formatApiKeyDisplay(currentConfig.key) : i18n.t("common:none")) + i18n.t("common:inputHidden") : i18n.t("api:enterNewApiKey").replace("{key}", currentConfig.key ? formatApiKeyDisplay(currentConfig.key) : i18n.t("common:none")) + i18n.t("common:inputHidden");
2469
4038
  const { key } = await inquirer.prompt({
2470
- type: "input",
4039
+ type: "password",
2471
4040
  name: "key",
2472
4041
  message: keyMessage,
2473
4042
  validate: async (value) => {
@@ -2661,14 +4230,16 @@ async function chooseInstallationMethod() {
2661
4230
  }
2662
4231
  async function handleMultipleInstallations(status) {
2663
4232
  ensureI18nInitialized();
2664
- const existingConfig = getZcfConfig();
2665
- const previousChoice = existingConfig.claudeCodeInstallation;
2666
- if (previousChoice) {
2667
- if (previousChoice.type === "global" && status.hasGlobal) {
2668
- return "global";
2669
- }
2670
- if (previousChoice.type === "local" && status.hasLocal) {
2671
- return "local";
4233
+ const tomlConfig = readTomlConfig(ZCF_CONFIG_FILE);
4234
+ if (tomlConfig && tomlConfig.general?.currentTool === "claude-code") {
4235
+ const previousChoice = tomlConfig.claudeCode?.installType;
4236
+ if (previousChoice) {
4237
+ if (previousChoice === "global" && status.hasGlobal) {
4238
+ return "global";
4239
+ }
4240
+ if (previousChoice === "local" && status.hasLocal) {
4241
+ return "local";
4242
+ }
2672
4243
  }
2673
4244
  }
2674
4245
  if (!status.hasGlobal && !status.hasLocal) {
@@ -2704,17 +4275,17 @@ async function handleMultipleInstallations(status) {
2704
4275
  await removeLocalClaudeCode();
2705
4276
  console.log(ansis.green(`\u2714 ${i18n.t("installation:localInstallationRemoved")}`));
2706
4277
  }
2707
- await saveInstallationConfig({
2708
- type: "global",
2709
- path: "claude",
2710
- configDir: CLAUDE_DIR
4278
+ updateTomlConfig(ZCF_CONFIG_FILE, {
4279
+ claudeCode: {
4280
+ installType: "global"
4281
+ }
2711
4282
  });
2712
4283
  } else {
2713
4284
  console.log(ansis.green(`\u2714 ${i18n.t("installation:usingLocalInstallation")}`));
2714
- await saveInstallationConfig({
2715
- type: "local",
2716
- path: status.localPath,
2717
- configDir: join(homedir(), ".claude")
4285
+ updateTomlConfig(ZCF_CONFIG_FILE, {
4286
+ claudeCode: {
4287
+ installType: "local"
4288
+ }
2718
4289
  });
2719
4290
  }
2720
4291
  return choice;
@@ -2728,130 +4299,13 @@ async function handleMultipleInstallations(status) {
2728
4299
  }
2729
4300
  }
2730
4301
  }
2731
- async function saveInstallationConfig(installation) {
2732
- try {
2733
- updateZcfConfig({
2734
- claudeCodeInstallation: installation
2735
- });
2736
- } catch (error) {
2737
- console.error(ansis.red(`\u2716 ${i18n.t("installation:failedToSaveInstallationConfig")}: ${error}`));
2738
- }
2739
- }
2740
-
2741
- async function selectMcpServices() {
2742
- ensureI18nInitialized();
2743
- const mcpServices = await getMcpServices();
2744
- const choices = mcpServices.map((service) => ({
2745
- name: `${service.name} - ${ansis.gray(service.description)}`,
2746
- value: service.id,
2747
- selected: false
2748
- }));
2749
- const { services } = await inquirer.prompt({
2750
- type: "checkbox",
2751
- name: "services",
2752
- message: `${i18n.t("mcp:selectMcpServices")}${i18n.t("common:multiSelectHint")}`,
2753
- choices
2754
- });
2755
- if (services === void 0) {
2756
- console.log(ansis.yellow(i18n.t("common:cancelled")));
2757
- return void 0;
2758
- }
2759
- return services;
2760
- }
2761
-
2762
- async function selectAiOutputLanguage(defaultLang) {
2763
- ensureI18nInitialized();
2764
- console.log(ansis.dim(`
2765
- ${i18n.t("language:aiOutputLangHint")}
2766
- `));
2767
- const aiLangChoices = Object.entries(AI_OUTPUT_LANGUAGES).map(([key]) => ({
2768
- title: getAiOutputLanguageLabel(key),
2769
- value: key
2770
- }));
2771
- const defaultChoice = defaultLang || "en";
2772
- const { lang } = await inquirer.prompt({
2773
- type: "list",
2774
- name: "lang",
2775
- message: i18n.t("language:selectAiOutputLang"),
2776
- choices: addNumbersToChoices(aiLangChoices.map((choice) => ({
2777
- name: choice.title,
2778
- value: choice.value
2779
- }))),
2780
- default: defaultChoice
2781
- });
2782
- if (!lang) {
2783
- console.log(ansis.yellow(i18n.t("common:cancelled")));
2784
- process.exit(0);
2785
- }
2786
- const aiOutputLang = lang;
2787
- if (aiOutputLang === "custom") {
2788
- const { customLang } = await inquirer.prompt({
2789
- type: "input",
2790
- name: "customLang",
2791
- message: i18n.t("language:enterCustomLanguage"),
2792
- validate: async (value) => !!value || i18n.t("language:languageRequired") || "Language is required"
2793
- });
2794
- if (!customLang) {
2795
- console.log(ansis.yellow(i18n.t("common:cancelled")));
2796
- process.exit(0);
2797
- }
2798
- return customLang;
2799
- }
2800
- return aiOutputLang;
2801
- }
2802
- const LANGUAGE_SELECTION_MESSAGES = {
2803
- selectLanguage: "Select ZCF display language / \u9009\u62E9ZCF\u663E\u793A\u8BED\u8A00",
2804
- operationCancelled: "Operation cancelled / \u64CD\u4F5C\u5DF2\u53D6\u6D88"
2805
- };
2806
- async function selectScriptLanguage(currentLang) {
2807
- const zcfConfig = readZcfConfig();
2808
- if (zcfConfig?.preferredLang) {
2809
- return zcfConfig.preferredLang;
2810
- }
2811
- const { lang } = await inquirer.prompt({
2812
- type: "list",
2813
- name: "lang",
2814
- message: LANGUAGE_SELECTION_MESSAGES.selectLanguage,
2815
- choices: addNumbersToChoices(SUPPORTED_LANGS.map((l) => ({
2816
- name: LANG_LABELS[l],
2817
- value: l
2818
- })))
2819
- });
2820
- if (!lang) {
2821
- console.log(ansis.yellow(LANGUAGE_SELECTION_MESSAGES.operationCancelled));
2822
- process.exit(0);
2823
- }
2824
- const scriptLang = lang;
2825
- updateZcfConfig({
2826
- version,
2827
- preferredLang: scriptLang
2828
- });
2829
- return scriptLang;
2830
- }
2831
- async function resolveAiOutputLanguage(scriptLang, commandLineOption, savedConfig) {
2832
- ensureI18nInitialized();
2833
- if (commandLineOption) {
2834
- return commandLineOption;
2835
- }
2836
- if (savedConfig?.aiOutputLang) {
2837
- console.log(ansis.gray(`\u2714 ${i18n.t("language:aiOutputLangHint")}: ${savedConfig.aiOutputLang}`));
2838
- return savedConfig.aiOutputLang;
2839
- }
2840
- return await selectAiOutputLanguage(scriptLang);
2841
- }
2842
-
2843
- const prompts = {
2844
- __proto__: null,
2845
- resolveAiOutputLanguage: resolveAiOutputLanguage,
2846
- selectAiOutputLanguage: selectAiOutputLanguage,
2847
- selectScriptLanguage: selectScriptLanguage
2848
- };
2849
4302
 
2850
4303
  function getRootDir() {
2851
4304
  const currentFilePath = fileURLToPath(import.meta.url);
2852
4305
  const distDir = dirname(dirname(currentFilePath));
2853
4306
  return dirname(distDir);
2854
4307
  }
4308
+ const DEFAULT_CODE_TOOL_TEMPLATE = "claude-code";
2855
4309
  async function selectAndInstallWorkflows(configLang, preselectedWorkflows) {
2856
4310
  ensureI18nInitialized();
2857
4311
  const workflows = getOrderedWorkflows();
@@ -2911,7 +4365,16 @@ async function installWorkflowWithDependencies(config, configLang) {
2911
4365
  await mkdir(commandsDir, { recursive: true });
2912
4366
  }
2913
4367
  for (const commandFile of config.commands) {
2914
- const commandSource = join(rootDir, "templates", configLang, "workflow", config.category, "commands", commandFile);
4368
+ const commandSource = join(
4369
+ rootDir,
4370
+ "templates",
4371
+ DEFAULT_CODE_TOOL_TEMPLATE,
4372
+ configLang,
4373
+ "workflow",
4374
+ config.category,
4375
+ "commands",
4376
+ commandFile
4377
+ );
2915
4378
  const destFileName = commandFile;
2916
4379
  const commandDest = join(commandsDir, destFileName);
2917
4380
  if (existsSync(commandSource)) {
@@ -2933,7 +4396,16 @@ async function installWorkflowWithDependencies(config, configLang) {
2933
4396
  await mkdir(agentsCategoryDir, { recursive: true });
2934
4397
  }
2935
4398
  for (const agent of config.agents) {
2936
- const agentSource = join(rootDir, "templates", configLang, "workflow", config.category, "agents", agent.filename);
4399
+ const agentSource = join(
4400
+ rootDir,
4401
+ "templates",
4402
+ DEFAULT_CODE_TOOL_TEMPLATE,
4403
+ configLang,
4404
+ "workflow",
4405
+ config.category,
4406
+ "agents",
4407
+ agent.filename
4408
+ );
2937
4409
  const agentDest = join(agentsCategoryDir, agent.filename);
2938
4410
  if (existsSync(agentSource)) {
2939
4411
  try {
@@ -3109,6 +4581,15 @@ function validateSkipPromptOptions(options) {
3109
4581
  options.workflows = WORKFLOW_CONFIG_BASE.map((w) => w.id);
3110
4582
  }
3111
4583
  }
4584
+ function resolveCodeToolType(optionValue, savedValue) {
4585
+ if (isCodeToolType(optionValue)) {
4586
+ return optionValue;
4587
+ }
4588
+ if (savedValue && isCodeToolType(savedValue)) {
4589
+ return savedValue;
4590
+ }
4591
+ return DEFAULT_CODE_TOOL_TYPE;
4592
+ }
3112
4593
  async function init(options = {}) {
3113
4594
  if (options.skipPrompt) {
3114
4595
  validateSkipPromptOptions(options);
@@ -3122,32 +4603,34 @@ async function init(options = {}) {
3122
4603
  \u2139 ${i18n.t("installation:termuxDetected")}`));
3123
4604
  console.log(ansis.gray(i18n.t("installation:termuxEnvironmentInfo")));
3124
4605
  }
4606
+ const zcfConfig = readZcfConfig();
3125
4607
  let configLang = options.configLang;
3126
4608
  if (!configLang && !options.skipPrompt) {
3127
- const LANG_HINT_KEYS = {
3128
- "zh-CN": i18n.t("language:configLangHint.zh-CN"),
3129
- "en": i18n.t("language:configLangHint.en")
3130
- };
3131
- const { lang } = await inquirer.prompt({
3132
- type: "list",
3133
- name: "lang",
3134
- message: i18n.t("language:selectConfigLang"),
3135
- choices: addNumbersToChoices(
3136
- SUPPORTED_LANGS.map((l) => ({
3137
- name: `${LANG_LABELS[l]} - ${LANG_HINT_KEYS[l]}`,
3138
- value: l
3139
- }))
3140
- )
3141
- });
3142
- if (!lang) {
3143
- console.log(ansis.yellow(i18n.t("common:cancelled")));
3144
- process.exit(0);
3145
- }
3146
- configLang = lang;
4609
+ const { resolveTemplateLanguage } = await Promise.resolve().then(function () { return prompts; });
4610
+ configLang = await resolveTemplateLanguage(
4611
+ options.configLang,
4612
+ // Command line option
4613
+ zcfConfig
4614
+ );
3147
4615
  } else if (!configLang && options.skipPrompt) {
3148
4616
  configLang = "en";
3149
4617
  }
3150
- const zcfConfig = readZcfConfig();
4618
+ const codeToolType = resolveCodeToolType(options.codeType, zcfConfig?.codeToolType);
4619
+ options.codeType = codeToolType;
4620
+ if (codeToolType === "codex") {
4621
+ await runCodexFullInit();
4622
+ updateZcfConfig({
4623
+ version,
4624
+ preferredLang: i18n.language,
4625
+ // ZCF界面语言
4626
+ templateLang: configLang,
4627
+ // 模板语言
4628
+ aiOutputLang: options.aiOutputLang || "en",
4629
+ codeToolType
4630
+ });
4631
+ console.log(ansis.green(i18n.t("codex:setupComplete")));
4632
+ return;
4633
+ }
3151
4634
  const aiOutputLang = options.skipPrompt ? options.aiOutputLang || "en" : await resolveAiOutputLanguage(i18n.language, options.aiOutputLang, zcfConfig);
3152
4635
  const installationStatus = await getInstallationStatus();
3153
4636
  if (installationStatus.hasGlobal || installationStatus.hasLocal) {
@@ -3468,9 +4951,9 @@ ${ansis.blue(`\u2139 ${i18n.t("api:existingApiConfig")}`)}`);
3468
4951
  continue;
3469
4952
  } else {
3470
4953
  const response = await inquirer.prompt({
3471
- type: "input",
4954
+ type: "password",
3472
4955
  name: "apiKey",
3473
- message: service.apiKeyPrompt,
4956
+ message: service.apiKeyPrompt + i18n.t("common:inputHidden"),
3474
4957
  validate: (value) => !!value || i18n.t("api:keyRequired")
3475
4958
  });
3476
4959
  if (!response.apiKey) {
@@ -3523,7 +5006,11 @@ ${ansis.blue(`\u2139 ${i18n.t("api:existingApiConfig")}`)}`);
3523
5006
  updateZcfConfig({
3524
5007
  version,
3525
5008
  preferredLang: i18n.language,
3526
- aiOutputLang
5009
+ // ZCF界面语言
5010
+ templateLang: configLang,
5011
+ // 模板语言
5012
+ aiOutputLang,
5013
+ codeToolType
3527
5014
  });
3528
5015
  console.log(ansis.green(`\u2714 ${i18n.t("configuration:configSuccess")} ${CLAUDE_DIR}`));
3529
5016
  console.log(`
@@ -3537,7 +5024,7 @@ ${ansis.cyan(i18n.t("common:complete"))}`);
3537
5024
 
3538
5025
  const __dirname = dirname(fileURLToPath(import.meta.url));
3539
5026
  function getTemplateSettings() {
3540
- const templatePath = join(__dirname, "../../templates/common/settings.json");
5027
+ const templatePath = join(__dirname, "../../templates/claude-code/common/settings.json");
3541
5028
  const content = readFileSync(templatePath, "utf-8");
3542
5029
  return JSON.parse(content);
3543
5030
  }
@@ -3613,4 +5100,4 @@ async function openSettingsJson() {
3613
5100
  }
3614
5101
  }
3615
5102
 
3616
- export { addNumbersToChoices as $, AI_OUTPUT_LANGUAGES as A, copyConfigFiles as B, CLAUDE_DIR as C, configureApi as D, mergeConfigs as E, updateCustomModel as F, updateDefaultModel as G, mergeSettingsFile as H, getExistingModelConfig as I, getExistingApiConfig as J, applyAiLanguageDirective as K, LEGACY_ZCF_CONFIG_FILE as L, isClaudeCodeInstalled as M, installClaudeCode as N, isLocalClaudeCodeInstalled as O, getInstallationStatus as P, removeLocalClaudeCode as Q, ensureI18nInitialized as R, SETTINGS_FILE as S, i18n as T, readCcrConfig as U, isCcrInstalled as V, installCcr as W, configureCcrFeature as X, handleExitPromptError as Y, ZCF_CONFIG_FILE as Z, handleGeneralError as _, commandExists as a, updateZcfConfig as a0, changeLanguage as a1, readZcfConfig as a2, configureOutputStyle as a3, isWindows as a4, selectMcpServices as a5, getMcpServices as a6, formatApiKeyDisplay as a7, modifyApiConfigPartially as a8, setupCcrConfiguration as a9, validateApiKey as aa, COMETIX_COMMAND_NAME as ab, COMETIX_COMMANDS as ac, installCometixLine as ad, checkAndUpdateTools as ae, readJsonConfig as af, writeJsonConfig as ag, displayBanner as ah, resolveAiOutputLanguage as ai, updatePromptOnly as aj, selectAndInstallWorkflows as ak, checkClaudeCodeVersionAndPrompt as al, version as am, displayBannerWithInfo as an, readZcfConfigAsync as ao, initI18n as ap, selectScriptLanguage as aq, prompts as ar, importRecommendedEnv as b, cleanupPermissions as c, importRecommendedPermissions as d, CLAUDE_MD_FILE as e, ClAUDE_CONFIG_FILE as f, getPlatform as g, SUPPORTED_LANGS as h, init as i, LANG_LABELS as j, getAiOutputLanguageLabel as k, getMcpConfigPath as l, mergeAndCleanPermissions as m, backupMcpConfig as n, openSettingsJson as o, mergeMcpServers as p, buildMcpServerConfig as q, readMcpConfig as r, fixWindowsMcpConfig as s, addCompletedOnboarding as t, ensureApiKeyApproved as u, removeApiKeyFromRejected as v, writeMcpConfig as w, manageApiKeyApproval as x, ensureClaudeDir as y, backupExistingConfig as z };
5103
+ export { writeAuthFile as $, AI_OUTPUT_LANGUAGES as A, manageApiKeyApproval as B, CLAUDE_DIR as C, DEFAULT_CODE_TOOL_TYPE as D, ensureClaudeDir as E, backupExistingConfig as F, copyConfigFiles as G, configureApi as H, mergeConfigs as I, updateCustomModel as J, updateDefaultModel as K, LEGACY_ZCF_CONFIG_FILES as L, mergeSettingsFile as M, getExistingModelConfig as N, getExistingApiConfig as O, applyAiLanguageDirective as P, isClaudeCodeInstalled as Q, installClaudeCode as R, SETTINGS_FILE as S, isLocalClaudeCodeInstalled as T, getInstallationStatus as U, removeLocalClaudeCode as V, i18n as W, readCodexConfig as X, backupCodexComplete as Y, ZCF_CONFIG_DIR as Z, writeCodexConfig as _, commandExists as a, ensureI18nInitialized as a0, detectConfigManagementMode as a1, addNumbersToChoices as a2, readCcrConfig as a3, isCcrInstalled as a4, installCcr as a5, configureCcrFeature as a6, handleExitPromptError as a7, handleGeneralError as a8, updateZcfConfig as a9, configureCodexApi as aA, runCodexWorkflowImport as aB, runCodexFullInit as aC, listCodexProviders as aD, getCurrentCodexProvider as aE, switchCodexProvider as aF, switchToOfficialLogin as aG, switchToProvider as aH, readZcfConfigAsync as aI, initI18n as aJ, selectScriptLanguage as aK, fsOperations as aL, prompts as aM, codex as aN, changeLanguage as aa, readZcfConfig as ab, configureOutputStyle as ac, isWindows as ad, selectMcpServices as ae, getMcpServices as af, formatApiKeyDisplay as ag, modifyApiConfigPartially as ah, setupCcrConfiguration as ai, validateApiKey as aj, COMETIX_COMMAND_NAME as ak, COMETIX_COMMANDS as al, installCometixLine as am, checkAndUpdateTools as an, readJsonConfig as ao, writeJsonConfig as ap, displayBanner as aq, runCodexUpdate as ar, version as as, resolveAiOutputLanguage as at, updatePromptOnly as au, selectAndInstallWorkflows as av, checkClaudeCodeVersionAndPrompt as aw, displayBannerWithInfo as ax, runCodexUninstall as ay, configureCodexMcp as az, importRecommendedEnv as b, cleanupPermissions as c, importRecommendedPermissions as d, CLAUDE_MD_FILE as e, ClAUDE_CONFIG_FILE as f, getPlatform as g, ZCF_CONFIG_FILE as h, init as i, CODE_TOOL_TYPES as j, isCodeToolType as k, SUPPORTED_LANGS as l, mergeAndCleanPermissions as m, LANG_LABELS as n, openSettingsJson as o, getAiOutputLanguageLabel as p, getMcpConfigPath as q, readMcpConfig as r, backupMcpConfig as s, mergeMcpServers as t, buildMcpServerConfig as u, fixWindowsMcpConfig as v, writeMcpConfig as w, addCompletedOnboarding as x, ensureApiKeyApproved as y, removeApiKeyFromRejected as z };