zcf 2.12.13 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -4
- package/dist/chunks/codex-config-switch.mjs +419 -0
- package/dist/chunks/codex-uninstaller.mjs +404 -0
- package/dist/chunks/simple-config.mjs +1869 -374
- package/dist/cli.mjs +672 -206
- package/dist/i18n/locales/en/cli.json +1 -0
- package/dist/i18n/locales/en/codex.json +102 -0
- package/dist/i18n/locales/en/common.json +4 -1
- package/dist/i18n/locales/en/configuration.json +10 -4
- package/dist/i18n/locales/en/language.json +8 -2
- package/dist/i18n/locales/en/mcp.json +4 -3
- package/dist/i18n/locales/en/menu.json +20 -0
- package/dist/i18n/locales/en/uninstall.json +0 -4
- package/dist/i18n/locales/zh-CN/cli.json +1 -0
- package/dist/i18n/locales/zh-CN/codex.json +102 -0
- package/dist/i18n/locales/zh-CN/common.json +4 -1
- package/dist/i18n/locales/zh-CN/configuration.json +10 -4
- package/dist/i18n/locales/zh-CN/language.json +8 -2
- package/dist/i18n/locales/zh-CN/mcp.json +4 -3
- package/dist/i18n/locales/zh-CN/menu.json +20 -0
- package/dist/i18n/locales/zh-CN/uninstall.json +0 -4
- package/dist/index.d.mts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.mjs +2 -1
- package/dist/shared/zcf.DGjQxTq_.mjs +34 -0
- package/package.json +11 -10
- package/templates/{common → claude-code/common}/settings.json +2 -1
- package/templates/codex/common/config.toml +0 -0
- package/templates/codex/en/system-prompt/engineer-professional.md +87 -0
- package/templates/codex/en/system-prompt/laowang-engineer.md +126 -0
- package/templates/codex/en/system-prompt/nekomata-engineer.md +119 -0
- package/templates/codex/en/workflow/sixStep/prompts/workflow.md +211 -0
- package/templates/codex/zh-CN/system-prompt/engineer-professional.md +88 -0
- package/templates/codex/zh-CN/system-prompt/laowang-engineer.md +126 -0
- package/templates/codex/zh-CN/system-prompt/nekomata-engineer.md +119 -0
- package/templates/codex/zh-CN/workflow/sixStep/prompts/workflow.md +211 -0
- /package/templates/{CLAUDE.md → claude-code/CLAUDE.md} +0 -0
- /package/templates/{en → claude-code/en}/output-styles/engineer-professional.md +0 -0
- /package/templates/{en → claude-code/en}/output-styles/laowang-engineer.md +0 -0
- /package/templates/{en → claude-code/en}/output-styles/nekomata-engineer.md +0 -0
- /package/templates/{en → claude-code/en}/workflow/bmad/commands/bmad-init.md +0 -0
- /package/templates/{en → claude-code/en}/workflow/common/agents/get-current-datetime.md +0 -0
- /package/templates/{en → claude-code/en}/workflow/common/agents/init-architect.md +0 -0
- /package/templates/{en → claude-code/en}/workflow/common/commands/init-project.md +0 -0
- /package/templates/{en → claude-code/en}/workflow/git/commands/git-cleanBranches.md +0 -0
- /package/templates/{en → claude-code/en}/workflow/git/commands/git-commit.md +0 -0
- /package/templates/{en → claude-code/en}/workflow/git/commands/git-rollback.md +0 -0
- /package/templates/{en → claude-code/en}/workflow/git/commands/git-worktree.md +0 -0
- /package/templates/{en → claude-code/en}/workflow/plan/agents/planner.md +0 -0
- /package/templates/{en → claude-code/en}/workflow/plan/agents/ui-ux-designer.md +0 -0
- /package/templates/{en → claude-code/en}/workflow/plan/commands/feat.md +0 -0
- /package/templates/{en → claude-code/en}/workflow/sixStep/commands/workflow.md +0 -0
- /package/templates/{zh-CN → claude-code/zh-CN}/output-styles/engineer-professional.md +0 -0
- /package/templates/{zh-CN → claude-code/zh-CN}/output-styles/laowang-engineer.md +0 -0
- /package/templates/{zh-CN → claude-code/zh-CN}/output-styles/nekomata-engineer.md +0 -0
- /package/templates/{zh-CN → claude-code/zh-CN}/workflow/bmad/commands/bmad-init.md +0 -0
- /package/templates/{zh-CN → claude-code/zh-CN}/workflow/common/agents/get-current-datetime.md +0 -0
- /package/templates/{zh-CN → claude-code/zh-CN}/workflow/common/agents/init-architect.md +0 -0
- /package/templates/{zh-CN → claude-code/zh-CN}/workflow/common/commands/init-project.md +0 -0
- /package/templates/{zh-CN → claude-code/zh-CN}/workflow/git/commands/git-cleanBranches.md +0 -0
- /package/templates/{zh-CN → claude-code/zh-CN}/workflow/git/commands/git-commit.md +0 -0
- /package/templates/{zh-CN → claude-code/zh-CN}/workflow/git/commands/git-rollback.md +0 -0
- /package/templates/{zh-CN → claude-code/zh-CN}/workflow/git/commands/git-worktree.md +0 -0
- /package/templates/{zh-CN → claude-code/zh-CN}/workflow/plan/agents/planner.md +0 -0
- /package/templates/{zh-CN → claude-code/zh-CN}/workflow/plan/agents/ui-ux-designer.md +0 -0
- /package/templates/{zh-CN → claude-code/zh-CN}/workflow/plan/commands/feat.md +0 -0
- /package/templates/{zh-CN → claude-code/zh-CN}/workflow/sixStep/commands/workflow.md +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readFileSync,
|
|
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 {
|
|
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 = "
|
|
19
|
+
const version = "3.0.1";
|
|
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.
|
|
219
|
-
description: i18n.t("mcp:services.
|
|
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
|
|
357
|
-
const ZCF_CONFIG_FILE = join(
|
|
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,
|
|
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
|
|
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(
|
|
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 (
|
|
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: "
|
|
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,1613 @@ async function installCcr() {
|
|
|
1987
2033
|
}
|
|
1988
2034
|
}
|
|
1989
2035
|
|
|
1990
|
-
function
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
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 existingAuth = readJsonConfig(CODEX_AUTH_FILE, { defaultValue: {} }) || {};
|
|
3099
|
+
const hasProviders = existingConfig?.providers && existingConfig.providers.length > 0;
|
|
3100
|
+
const modeChoices = [
|
|
3101
|
+
{ name: i18n.t("codex:apiModeOfficial"), value: "official" },
|
|
3102
|
+
{ name: i18n.t("codex:apiModeCustom"), value: "custom" }
|
|
3103
|
+
];
|
|
3104
|
+
if (hasProviders) {
|
|
3105
|
+
modeChoices.push({ name: i18n.t("codex:configSwitchMode"), value: "switch" });
|
|
3106
|
+
}
|
|
3107
|
+
const { mode } = await inquirer.prompt([{
|
|
3108
|
+
type: "list",
|
|
3109
|
+
name: "mode",
|
|
3110
|
+
message: i18n.t("codex:apiModePrompt"),
|
|
3111
|
+
choices: addNumbersToChoices(modeChoices),
|
|
3112
|
+
default: "custom"
|
|
3113
|
+
}]);
|
|
3114
|
+
if (!mode) {
|
|
3115
|
+
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
3116
|
+
return;
|
|
3117
|
+
}
|
|
3118
|
+
if (mode === "official") {
|
|
3119
|
+
const success = await switchToOfficialLogin();
|
|
3120
|
+
if (success) {
|
|
3121
|
+
updateZcfConfig({ codeToolType: "codex" });
|
|
3122
|
+
}
|
|
3123
|
+
return;
|
|
3124
|
+
}
|
|
3125
|
+
if (mode === "switch") {
|
|
3126
|
+
if (!hasProviders) {
|
|
3127
|
+
console.log(ansis.yellow(i18n.t("codex:noProvidersAvailable")));
|
|
3128
|
+
return;
|
|
3129
|
+
}
|
|
3130
|
+
const currentProvider = existingConfig?.modelProvider;
|
|
3131
|
+
const isCommented = existingConfig?.modelProviderCommented;
|
|
3132
|
+
const choices = createApiConfigChoices(existingConfig.providers, currentProvider, isCommented);
|
|
3133
|
+
const { selectedConfig } = await inquirer.prompt([{
|
|
3134
|
+
type: "list",
|
|
3135
|
+
name: "selectedConfig",
|
|
3136
|
+
message: i18n.t("codex:apiConfigSwitchPrompt"),
|
|
3137
|
+
choices: addNumbersToChoices(choices)
|
|
3138
|
+
}]);
|
|
3139
|
+
if (!selectedConfig) {
|
|
3140
|
+
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
3141
|
+
return;
|
|
3142
|
+
}
|
|
3143
|
+
let success = false;
|
|
3144
|
+
if (selectedConfig === "official") {
|
|
3145
|
+
success = await switchToOfficialLogin();
|
|
3146
|
+
} else {
|
|
3147
|
+
success = await switchToProvider(selectedConfig);
|
|
3148
|
+
}
|
|
3149
|
+
if (success) {
|
|
3150
|
+
updateZcfConfig({ codeToolType: "codex" });
|
|
3151
|
+
}
|
|
3152
|
+
return;
|
|
3153
|
+
}
|
|
3154
|
+
const managementMode = detectConfigManagementMode();
|
|
3155
|
+
if (managementMode.mode === "management" && managementMode.hasProviders) {
|
|
3156
|
+
const { default: { configureIncrementalManagement } } = await import('./codex-config-switch.mjs');
|
|
3157
|
+
await configureIncrementalManagement();
|
|
3158
|
+
return;
|
|
3159
|
+
}
|
|
3160
|
+
const backupPath = backupCodexComplete();
|
|
3161
|
+
if (backupPath) {
|
|
3162
|
+
console.log(ansis.gray(getBackupMessage(backupPath)));
|
|
3163
|
+
}
|
|
3164
|
+
const providers = [];
|
|
3165
|
+
const authEntries = {};
|
|
3166
|
+
const existingMap = new Map(existingConfig?.providers.map((provider) => [provider.id, provider]));
|
|
3167
|
+
const currentSessionProviders = /* @__PURE__ */ new Map();
|
|
3168
|
+
let addMore = true;
|
|
3169
|
+
const existingValues = existingMap.size ? Array.from(existingMap.values()) : [];
|
|
3170
|
+
const firstExisting = existingValues.length === 1 ? existingValues[0] : void 0;
|
|
3171
|
+
while (addMore) {
|
|
3172
|
+
const answers = await inquirer.prompt([
|
|
3173
|
+
{
|
|
3174
|
+
type: "input",
|
|
3175
|
+
name: "providerName",
|
|
3176
|
+
message: i18n.t("codex:providerNamePrompt"),
|
|
3177
|
+
default: firstExisting?.name,
|
|
3178
|
+
validate: (input) => {
|
|
3179
|
+
const sanitized = sanitizeProviderName(input);
|
|
3180
|
+
if (!sanitized)
|
|
3181
|
+
return i18n.t("codex:providerNameRequired");
|
|
3182
|
+
if (sanitized !== input.trim())
|
|
3183
|
+
return i18n.t("codex:providerNameInvalid");
|
|
3184
|
+
return true;
|
|
3185
|
+
}
|
|
3186
|
+
},
|
|
3187
|
+
{
|
|
3188
|
+
type: "input",
|
|
3189
|
+
name: "baseUrl",
|
|
3190
|
+
message: i18n.t("codex:providerBaseUrlPrompt"),
|
|
3191
|
+
default: (answers2) => existingMap.get(answers2.providerId)?.baseUrl || "https://api.openai.com/v1",
|
|
3192
|
+
validate: (input) => !!input || i18n.t("codex:providerBaseUrlRequired")
|
|
3193
|
+
},
|
|
3194
|
+
{
|
|
3195
|
+
type: "list",
|
|
3196
|
+
name: "wireApi",
|
|
3197
|
+
message: i18n.t("codex:providerProtocolPrompt"),
|
|
3198
|
+
choices: [
|
|
3199
|
+
{ name: i18n.t("codex:protocolResponses"), value: "responses" },
|
|
3200
|
+
{ name: i18n.t("codex:protocolChat"), value: "chat" }
|
|
3201
|
+
],
|
|
3202
|
+
default: (answers2) => existingMap.get(sanitizeProviderName(answers2.providerName))?.wireApi || "responses"
|
|
3203
|
+
},
|
|
3204
|
+
{
|
|
3205
|
+
type: "password",
|
|
3206
|
+
name: "apiKey",
|
|
3207
|
+
message: i18n.t("codex:providerApiKeyPrompt") + i18n.t("common:inputHidden"),
|
|
3208
|
+
validate: (input) => !!input || i18n.t("codex:providerApiKeyRequired")
|
|
3209
|
+
}
|
|
3210
|
+
]);
|
|
3211
|
+
const providerId = sanitizeProviderName(answers.providerName);
|
|
3212
|
+
const envKey = `${providerId.toUpperCase().replace(/-/g, "_")}_API_KEY`;
|
|
3213
|
+
const existingProvider = existingMap.get(providerId);
|
|
3214
|
+
const sessionProvider = currentSessionProviders.get(providerId);
|
|
3215
|
+
if (existingProvider || sessionProvider) {
|
|
3216
|
+
const sourceType = existingProvider ? "existing" : "session";
|
|
3217
|
+
const sourceProvider = existingProvider || sessionProvider;
|
|
3218
|
+
const { shouldOverwrite } = await inquirer.prompt([{
|
|
3219
|
+
type: "confirm",
|
|
3220
|
+
name: "shouldOverwrite",
|
|
3221
|
+
message: i18n.t("codex:providerDuplicatePrompt", {
|
|
3222
|
+
name: sourceProvider.name,
|
|
3223
|
+
source: sourceType === "existing" ? i18n.t("codex:existingConfig") : i18n.t("codex:currentSession")
|
|
3224
|
+
}),
|
|
3225
|
+
default: false
|
|
3226
|
+
}]);
|
|
3227
|
+
if (!shouldOverwrite) {
|
|
3228
|
+
console.log(ansis.yellow(i18n.t("codex:providerDuplicateSkipped")));
|
|
3229
|
+
continue;
|
|
3230
|
+
}
|
|
3231
|
+
if (sessionProvider) {
|
|
3232
|
+
currentSessionProviders.delete(providerId);
|
|
3233
|
+
const sessionIndex = providers.findIndex((p) => p.id === providerId);
|
|
3234
|
+
if (sessionIndex !== -1) {
|
|
3235
|
+
providers.splice(sessionIndex, 1);
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
3239
|
+
const newProvider = {
|
|
3240
|
+
id: providerId,
|
|
3241
|
+
name: answers.providerName,
|
|
3242
|
+
baseUrl: answers.baseUrl,
|
|
3243
|
+
wireApi: answers.wireApi || "responses",
|
|
3244
|
+
envKey,
|
|
3245
|
+
requiresOpenaiAuth: true
|
|
3246
|
+
};
|
|
3247
|
+
providers.push(newProvider);
|
|
3248
|
+
currentSessionProviders.set(providerId, newProvider);
|
|
3249
|
+
authEntries[envKey] = answers.apiKey;
|
|
3250
|
+
const { addAnother } = await inquirer.prompt([{
|
|
3251
|
+
type: "confirm",
|
|
3252
|
+
name: "addAnother",
|
|
3253
|
+
message: i18n.t("codex:addProviderPrompt"),
|
|
3254
|
+
default: false
|
|
3255
|
+
}]);
|
|
3256
|
+
addMore = addAnother;
|
|
3257
|
+
}
|
|
3258
|
+
if (providers.length === 0) {
|
|
3259
|
+
console.log(ansis.yellow(i18n.t("codex:noProvidersConfigured")));
|
|
3260
|
+
return;
|
|
3261
|
+
}
|
|
3262
|
+
const { defaultProvider } = await inquirer.prompt([{
|
|
3263
|
+
type: "list",
|
|
3264
|
+
name: "defaultProvider",
|
|
3265
|
+
message: i18n.t("codex:selectDefaultProviderPrompt"),
|
|
3266
|
+
choices: addNumbersToChoices(toProvidersList(providers)),
|
|
3267
|
+
default: existingConfig?.modelProvider || providers[0].id
|
|
3268
|
+
}]);
|
|
3269
|
+
const selectedProvider = providers.find((provider) => provider.id === defaultProvider);
|
|
3270
|
+
if (selectedProvider) {
|
|
3271
|
+
const envKey = selectedProvider.envKey;
|
|
3272
|
+
const defaultApiKey = authEntries[envKey] ?? existingAuth[envKey] ?? null;
|
|
3273
|
+
if (defaultApiKey)
|
|
3274
|
+
authEntries.OPENAI_API_KEY = defaultApiKey;
|
|
3275
|
+
}
|
|
3276
|
+
writeCodexConfig({
|
|
3277
|
+
model: existingConfig?.model || null,
|
|
3278
|
+
modelProvider: defaultProvider,
|
|
3279
|
+
providers,
|
|
3280
|
+
mcpServices: existingConfig?.mcpServices || [],
|
|
3281
|
+
otherConfig: existingConfig?.otherConfig || []
|
|
3282
|
+
});
|
|
3283
|
+
writeAuthFile(authEntries);
|
|
3284
|
+
updateZcfConfig({ codeToolType: "codex" });
|
|
3285
|
+
console.log(ansis.green(i18n.t("codex:apiConfigured")));
|
|
3286
|
+
}
|
|
3287
|
+
async function configureCodexMcp() {
|
|
3288
|
+
ensureI18nInitialized();
|
|
3289
|
+
const existingConfig = readCodexConfig();
|
|
3290
|
+
const backupPath = backupCodexComplete();
|
|
3291
|
+
if (backupPath) {
|
|
3292
|
+
console.log(ansis.gray(getBackupMessage(backupPath)));
|
|
3293
|
+
}
|
|
3294
|
+
const selectedIds = await selectMcpServices();
|
|
3295
|
+
if (!selectedIds)
|
|
3296
|
+
return;
|
|
3297
|
+
const servicesMeta = await getMcpServices();
|
|
3298
|
+
const baseProviders = existingConfig?.providers || [];
|
|
3299
|
+
const selection = [];
|
|
3300
|
+
const existingMap = new Map((existingConfig?.mcpServices || []).map((service) => [service.id, service]));
|
|
3301
|
+
if (selectedIds.length === 0) {
|
|
3302
|
+
console.log(ansis.yellow(i18n.t("codex:noMcpConfigured")));
|
|
3303
|
+
writeCodexConfig({
|
|
3304
|
+
model: existingConfig?.model || null,
|
|
3305
|
+
modelProvider: existingConfig?.modelProvider || null,
|
|
3306
|
+
providers: baseProviders,
|
|
3307
|
+
mcpServices: Array.from(existingMap.values()),
|
|
3308
|
+
otherConfig: existingConfig?.otherConfig || []
|
|
3309
|
+
});
|
|
3310
|
+
updateZcfConfig({ codeToolType: "codex" });
|
|
3311
|
+
return;
|
|
3312
|
+
}
|
|
3313
|
+
for (const id of selectedIds) {
|
|
3314
|
+
const configInfo = MCP_SERVICE_CONFIGS.find((service) => service.id === id);
|
|
3315
|
+
if (!configInfo)
|
|
3316
|
+
continue;
|
|
3317
|
+
const serviceMeta = servicesMeta.find((service) => service.id === id);
|
|
3318
|
+
let command = configInfo.config.command || id;
|
|
3319
|
+
const args = (configInfo.config.args || []).map((arg) => String(arg));
|
|
3320
|
+
if (isWindows() && command === "npx")
|
|
3321
|
+
command = "npx.cmd";
|
|
3322
|
+
const env = { ...configInfo.config.env || {} };
|
|
3323
|
+
if (configInfo.requiresApiKey && configInfo.apiKeyEnvVar) {
|
|
3324
|
+
const promptMessage = serviceMeta?.apiKeyPrompt || i18n.t("mcp:apiKeyPrompt");
|
|
3325
|
+
const { apiKey } = await inquirer.prompt([{
|
|
3326
|
+
type: "password",
|
|
3327
|
+
name: "apiKey",
|
|
3328
|
+
message: promptMessage + i18n.t("common:inputHidden"),
|
|
3329
|
+
validate: (input) => !!input || i18n.t("api:keyRequired")
|
|
3330
|
+
}]);
|
|
3331
|
+
if (!apiKey)
|
|
3332
|
+
continue;
|
|
3333
|
+
env[configInfo.apiKeyEnvVar] = apiKey;
|
|
3334
|
+
}
|
|
3335
|
+
selection.push({
|
|
3336
|
+
id: id.toLowerCase(),
|
|
3337
|
+
// Convert to lowercase for Codex compatibility
|
|
3338
|
+
command,
|
|
3339
|
+
args,
|
|
3340
|
+
env: Object.keys(env).length > 0 ? env : void 0,
|
|
3341
|
+
startup_timeout_ms: configInfo.config.startup_timeout_ms
|
|
3342
|
+
});
|
|
3343
|
+
}
|
|
3344
|
+
const selectionMap = new Map(selection.map((service) => [service.id, service]));
|
|
3345
|
+
const mergedMap = new Map(existingMap);
|
|
3346
|
+
for (const service of selectionMap.values())
|
|
3347
|
+
mergedMap.set(service.id, service);
|
|
3348
|
+
writeCodexConfig({
|
|
3349
|
+
model: existingConfig?.model || null,
|
|
3350
|
+
modelProvider: existingConfig?.modelProvider || null,
|
|
3351
|
+
providers: baseProviders,
|
|
3352
|
+
mcpServices: Array.from(mergedMap.values()),
|
|
3353
|
+
otherConfig: existingConfig?.otherConfig || []
|
|
3354
|
+
});
|
|
3355
|
+
updateZcfConfig({ codeToolType: "codex" });
|
|
3356
|
+
console.log(ansis.green(i18n.t("codex:mcpConfigured")));
|
|
3357
|
+
}
|
|
3358
|
+
async function runCodexFullInit() {
|
|
3359
|
+
ensureI18nInitialized();
|
|
3360
|
+
await installCodexCli();
|
|
3361
|
+
await runCodexWorkflowImport();
|
|
3362
|
+
await configureCodexApi();
|
|
3363
|
+
await configureCodexMcp();
|
|
3364
|
+
}
|
|
3365
|
+
async function runCodexUpdate(force = false, skipPrompt = false) {
|
|
3366
|
+
ensureI18nInitialized();
|
|
3367
|
+
const spinner = ora(i18n.t("codex:checkingVersion")).start();
|
|
3368
|
+
try {
|
|
3369
|
+
const { installed, currentVersion, latestVersion, needsUpdate } = await checkCodexUpdate();
|
|
3370
|
+
spinner.stop();
|
|
3371
|
+
if (!installed) {
|
|
3372
|
+
console.log(ansis.yellow(i18n.t("codex:notInstalled")));
|
|
3373
|
+
return false;
|
|
3374
|
+
}
|
|
3375
|
+
if (!needsUpdate && !force) {
|
|
3376
|
+
console.log(ansis.green(format(i18n.t("codex:upToDate"), { version: currentVersion || "" })));
|
|
3377
|
+
return true;
|
|
3378
|
+
}
|
|
3379
|
+
if (!latestVersion) {
|
|
3380
|
+
console.log(ansis.yellow(i18n.t("codex:cannotCheckVersion")));
|
|
3381
|
+
return false;
|
|
3382
|
+
}
|
|
3383
|
+
console.log(ansis.cyan(format(i18n.t("codex:currentVersion"), { version: currentVersion || "" })));
|
|
3384
|
+
console.log(ansis.cyan(format(i18n.t("codex:latestVersion"), { version: latestVersion })));
|
|
3385
|
+
if (!skipPrompt) {
|
|
3386
|
+
const { confirm } = await inquirer.prompt({
|
|
3387
|
+
type: "confirm",
|
|
3388
|
+
name: "confirm",
|
|
3389
|
+
message: i18n.t("codex:confirmUpdate"),
|
|
3390
|
+
default: true
|
|
3391
|
+
});
|
|
3392
|
+
if (!confirm) {
|
|
3393
|
+
console.log(ansis.gray(i18n.t("codex:updateSkipped")));
|
|
3394
|
+
return true;
|
|
3395
|
+
}
|
|
3396
|
+
} else {
|
|
3397
|
+
console.log(ansis.cyan(i18n.t("codex:autoUpdating")));
|
|
3398
|
+
}
|
|
3399
|
+
const updateSpinner = ora(i18n.t("codex:updating")).start();
|
|
3400
|
+
try {
|
|
3401
|
+
await executeCodexInstallation(true);
|
|
3402
|
+
updateSpinner.succeed(i18n.t("codex:updateSuccess"));
|
|
3403
|
+
return true;
|
|
3404
|
+
} catch (error) {
|
|
3405
|
+
updateSpinner.fail(i18n.t("codex:updateFailed"));
|
|
3406
|
+
console.error(ansis.red(error instanceof Error ? error.message : String(error)));
|
|
3407
|
+
return false;
|
|
3408
|
+
}
|
|
3409
|
+
} catch (error) {
|
|
3410
|
+
spinner.fail(i18n.t("codex:checkFailed"));
|
|
3411
|
+
console.error(ansis.red(error instanceof Error ? error.message : String(error)));
|
|
3412
|
+
return false;
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3415
|
+
async function runCodexUninstall() {
|
|
3416
|
+
ensureI18nInitialized();
|
|
3417
|
+
const { CodexUninstaller } = await import('./codex-uninstaller.mjs');
|
|
3418
|
+
const uninstaller = new CodexUninstaller("en");
|
|
3419
|
+
const { mode } = await inquirer.prompt([{
|
|
3420
|
+
type: "list",
|
|
3421
|
+
name: "mode",
|
|
3422
|
+
message: i18n.t("codex:uninstallModePrompt"),
|
|
3423
|
+
choices: addNumbersToChoices([
|
|
3424
|
+
{ name: i18n.t("codex:uninstallModeComplete"), value: "complete" },
|
|
3425
|
+
{ name: i18n.t("codex:uninstallModeCustom"), value: "custom" }
|
|
3426
|
+
]),
|
|
3427
|
+
default: "complete"
|
|
3428
|
+
}]);
|
|
3429
|
+
if (!mode) {
|
|
3430
|
+
handleUninstallCancellation();
|
|
3431
|
+
return;
|
|
3432
|
+
}
|
|
3433
|
+
try {
|
|
3434
|
+
if (mode === "complete") {
|
|
3435
|
+
const { confirm } = await inquirer.prompt([{
|
|
3436
|
+
type: "confirm",
|
|
3437
|
+
name: "confirm",
|
|
3438
|
+
message: i18n.t("codex:uninstallPrompt"),
|
|
3439
|
+
default: false
|
|
3440
|
+
}]);
|
|
3441
|
+
if (!confirm) {
|
|
3442
|
+
handleUninstallCancellation();
|
|
3443
|
+
return;
|
|
3444
|
+
}
|
|
3445
|
+
const result = await uninstaller.completeUninstall();
|
|
3446
|
+
displayUninstallResults([result]);
|
|
3447
|
+
} else if (mode === "custom") {
|
|
3448
|
+
const { items } = await inquirer.prompt([{
|
|
3449
|
+
type: "checkbox",
|
|
3450
|
+
name: "items",
|
|
3451
|
+
message: i18n.t("codex:customUninstallPrompt"),
|
|
3452
|
+
choices: addNumbersToChoices(getUninstallOptions())
|
|
3453
|
+
}]);
|
|
3454
|
+
if (!items || items.length === 0) {
|
|
3455
|
+
handleUninstallCancellation();
|
|
3456
|
+
return;
|
|
3457
|
+
}
|
|
3458
|
+
const results = await uninstaller.customUninstall(items);
|
|
3459
|
+
displayUninstallResults(results);
|
|
3460
|
+
}
|
|
3461
|
+
console.log(ansis.green(i18n.t("codex:uninstallSuccess")));
|
|
3462
|
+
} catch (error) {
|
|
3463
|
+
console.error(ansis.red(`Error during uninstall: ${error.message}`));
|
|
3464
|
+
throw error;
|
|
3465
|
+
}
|
|
3466
|
+
}
|
|
3467
|
+
function displayUninstallResults(results) {
|
|
3468
|
+
for (const result of results) {
|
|
3469
|
+
for (const item of result.removed) {
|
|
3470
|
+
console.log(ansis.green(`\u2714 ${i18n.t("codex:removedItem", { item })}`));
|
|
3471
|
+
}
|
|
3472
|
+
for (const config of result.removedConfigs) {
|
|
3473
|
+
console.log(ansis.green(`\u2714 ${i18n.t("codex:removedConfig", { config })}`));
|
|
3474
|
+
}
|
|
3475
|
+
for (const warning of result.warnings) {
|
|
3476
|
+
console.log(ansis.yellow(`\u26A0\uFE0F ${warning}`));
|
|
3477
|
+
}
|
|
3478
|
+
for (const error of result.errors) {
|
|
3479
|
+
console.log(ansis.red(`\u274C ${error}`));
|
|
3480
|
+
}
|
|
3481
|
+
}
|
|
3482
|
+
}
|
|
3483
|
+
async function getCurrentCodexProvider() {
|
|
3484
|
+
const config = readCodexConfig();
|
|
3485
|
+
return config?.modelProvider || null;
|
|
3486
|
+
}
|
|
3487
|
+
async function listCodexProviders() {
|
|
3488
|
+
const config = readCodexConfig();
|
|
3489
|
+
return config?.providers || [];
|
|
3490
|
+
}
|
|
3491
|
+
async function switchCodexProvider(providerId) {
|
|
3492
|
+
ensureI18nInitialized();
|
|
3493
|
+
const existingConfig = readCodexConfig();
|
|
3494
|
+
if (!existingConfig) {
|
|
3495
|
+
console.log(ansis.red(i18n.t("codex:configNotFound")));
|
|
3496
|
+
return false;
|
|
3497
|
+
}
|
|
3498
|
+
const providerExists = existingConfig.providers.some((provider) => provider.id === providerId);
|
|
3499
|
+
if (!providerExists) {
|
|
3500
|
+
console.log(ansis.red(i18n.t("codex:providerNotFound", { provider: providerId })));
|
|
3501
|
+
return false;
|
|
3502
|
+
}
|
|
3503
|
+
const backupPath = backupCodexComplete();
|
|
3504
|
+
if (backupPath) {
|
|
3505
|
+
console.log(ansis.gray(getBackupMessage(backupPath)));
|
|
3506
|
+
}
|
|
3507
|
+
const updatedConfig = {
|
|
3508
|
+
...existingConfig,
|
|
3509
|
+
modelProvider: providerId
|
|
3510
|
+
};
|
|
3511
|
+
try {
|
|
3512
|
+
writeCodexConfig(updatedConfig);
|
|
3513
|
+
console.log(ansis.green(i18n.t("codex:providerSwitchSuccess", { provider: providerId })));
|
|
3514
|
+
return true;
|
|
3515
|
+
} catch (error) {
|
|
3516
|
+
console.error(ansis.red(`Error switching provider: ${error.message}`));
|
|
3517
|
+
return false;
|
|
3518
|
+
}
|
|
3519
|
+
}
|
|
3520
|
+
async function switchToOfficialLogin() {
|
|
3521
|
+
ensureI18nInitialized();
|
|
3522
|
+
const existingConfig = readCodexConfig();
|
|
3523
|
+
if (!existingConfig) {
|
|
3524
|
+
console.log(ansis.red(i18n.t("codex:configNotFound")));
|
|
3525
|
+
return false;
|
|
3526
|
+
}
|
|
3527
|
+
const backupPath = backupCodexComplete();
|
|
3528
|
+
if (backupPath) {
|
|
3529
|
+
console.log(ansis.gray(getBackupMessage(backupPath)));
|
|
3530
|
+
}
|
|
3531
|
+
try {
|
|
3532
|
+
const updatedConfig = {
|
|
3533
|
+
...existingConfig,
|
|
3534
|
+
modelProvider: existingConfig.modelProvider,
|
|
3535
|
+
// Keep the current provider value
|
|
3536
|
+
modelProviderCommented: true
|
|
3537
|
+
// Mark as commented
|
|
3538
|
+
};
|
|
3539
|
+
writeCodexConfig(updatedConfig);
|
|
3540
|
+
const auth = readJsonConfig(CODEX_AUTH_FILE, { defaultValue: {} }) || {};
|
|
3541
|
+
auth.OPENAI_API_KEY = null;
|
|
3542
|
+
writeJsonConfig(CODEX_AUTH_FILE, auth, { pretty: true });
|
|
3543
|
+
console.log(ansis.green(i18n.t("codex:officialConfigured")));
|
|
3544
|
+
return true;
|
|
3545
|
+
} catch (error) {
|
|
3546
|
+
console.error(ansis.red(`Error switching to official login: ${error.message}`));
|
|
3547
|
+
return false;
|
|
3548
|
+
}
|
|
3549
|
+
}
|
|
3550
|
+
async function switchToProvider(providerId) {
|
|
3551
|
+
ensureI18nInitialized();
|
|
3552
|
+
const existingConfig = readCodexConfig();
|
|
3553
|
+
if (!existingConfig) {
|
|
3554
|
+
console.log(ansis.red(i18n.t("codex:configNotFound")));
|
|
3555
|
+
return false;
|
|
3556
|
+
}
|
|
3557
|
+
const provider = existingConfig.providers.find((p) => p.id === providerId);
|
|
3558
|
+
if (!provider) {
|
|
3559
|
+
console.log(ansis.red(i18n.t("codex:providerNotFound", { provider: providerId })));
|
|
3560
|
+
return false;
|
|
3561
|
+
}
|
|
3562
|
+
const backupPath = backupCodexComplete();
|
|
3563
|
+
if (backupPath) {
|
|
3564
|
+
console.log(ansis.gray(getBackupMessage(backupPath)));
|
|
3565
|
+
}
|
|
3566
|
+
try {
|
|
3567
|
+
const updatedConfig = {
|
|
3568
|
+
...existingConfig,
|
|
3569
|
+
modelProvider: providerId,
|
|
3570
|
+
modelProviderCommented: false
|
|
3571
|
+
// Ensure it's not commented
|
|
3572
|
+
};
|
|
3573
|
+
writeCodexConfig(updatedConfig);
|
|
3574
|
+
const auth = readJsonConfig(CODEX_AUTH_FILE, { defaultValue: {} }) || {};
|
|
3575
|
+
const envValue = auth[provider.envKey] || null;
|
|
3576
|
+
auth.OPENAI_API_KEY = envValue;
|
|
3577
|
+
writeJsonConfig(CODEX_AUTH_FILE, auth, { pretty: true });
|
|
3578
|
+
console.log(ansis.green(i18n.t("codex:providerSwitchSuccess", { provider: providerId })));
|
|
3579
|
+
return true;
|
|
3580
|
+
} catch (error) {
|
|
3581
|
+
console.error(ansis.red(`Error switching to provider: ${error.message}`));
|
|
3582
|
+
return false;
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3585
|
+
|
|
3586
|
+
const codex = {
|
|
3587
|
+
__proto__: null,
|
|
3588
|
+
CODEX_DIR: CODEX_DIR,
|
|
3589
|
+
backupCodexAgents: backupCodexAgents,
|
|
3590
|
+
backupCodexComplete: backupCodexComplete,
|
|
3591
|
+
backupCodexConfig: backupCodexConfig,
|
|
3592
|
+
backupCodexFiles: backupCodexFiles,
|
|
3593
|
+
backupCodexPrompts: backupCodexPrompts,
|
|
3594
|
+
checkCodexUpdate: checkCodexUpdate,
|
|
3595
|
+
configureCodexApi: configureCodexApi,
|
|
3596
|
+
configureCodexMcp: configureCodexMcp,
|
|
3597
|
+
createBackupDirectory: createBackupDirectory,
|
|
3598
|
+
getBackupMessage: getBackupMessage,
|
|
3599
|
+
getCodexVersion: getCodexVersion,
|
|
3600
|
+
getCurrentCodexProvider: getCurrentCodexProvider,
|
|
3601
|
+
installCodexCli: installCodexCli,
|
|
3602
|
+
isCodexInstalled: isCodexInstalled,
|
|
3603
|
+
listCodexProviders: listCodexProviders,
|
|
3604
|
+
parseCodexConfig: parseCodexConfig,
|
|
3605
|
+
readCodexConfig: readCodexConfig,
|
|
3606
|
+
renderCodexConfig: renderCodexConfig,
|
|
3607
|
+
runCodexFullInit: runCodexFullInit,
|
|
3608
|
+
runCodexSystemPromptSelection: runCodexSystemPromptSelection,
|
|
3609
|
+
runCodexUninstall: runCodexUninstall,
|
|
3610
|
+
runCodexUpdate: runCodexUpdate,
|
|
3611
|
+
runCodexWorkflowImport: runCodexWorkflowImport,
|
|
3612
|
+
runCodexWorkflowSelection: runCodexWorkflowSelection,
|
|
3613
|
+
switchCodexProvider: switchCodexProvider,
|
|
3614
|
+
switchToOfficialLogin: switchToOfficialLogin,
|
|
3615
|
+
switchToProvider: switchToProvider,
|
|
3616
|
+
writeAuthFile: writeAuthFile,
|
|
3617
|
+
writeCodexConfig: writeCodexConfig
|
|
3618
|
+
};
|
|
3619
|
+
|
|
3620
|
+
function getPlatformStatusLineConfig() {
|
|
3621
|
+
return {
|
|
3622
|
+
type: "command",
|
|
3623
|
+
command: isWindows() ? "%USERPROFILE%\\.claude\\ccline\\ccline.exe" : "~/.claude/ccline/ccline",
|
|
3624
|
+
padding: 0
|
|
3625
|
+
};
|
|
3626
|
+
}
|
|
3627
|
+
|
|
3628
|
+
function addCCometixLineConfig() {
|
|
3629
|
+
try {
|
|
3630
|
+
const statusLineConfig = getPlatformStatusLineConfig();
|
|
3631
|
+
let settings = {};
|
|
3632
|
+
if (exists(SETTINGS_FILE)) {
|
|
3633
|
+
settings = readJsonConfig(SETTINGS_FILE) || {};
|
|
3634
|
+
}
|
|
3635
|
+
settings.statusLine = statusLineConfig;
|
|
3636
|
+
writeJsonConfig(SETTINGS_FILE, settings);
|
|
3637
|
+
return true;
|
|
3638
|
+
} catch (error) {
|
|
3639
|
+
console.error("Failed to add CCometixLine configuration:", error);
|
|
3640
|
+
return false;
|
|
3641
|
+
}
|
|
3642
|
+
}
|
|
2013
3643
|
function hasCCometixLineConfig() {
|
|
2014
3644
|
try {
|
|
2015
3645
|
if (!exists(SETTINGS_FILE)) {
|
|
@@ -2082,59 +3712,6 @@ async function installCometixLine() {
|
|
|
2082
3712
|
}
|
|
2083
3713
|
}
|
|
2084
3714
|
|
|
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
3715
|
const OUTPUT_STYLES = [
|
|
2139
3716
|
// Custom styles (have template files)
|
|
2140
3717
|
{
|
|
@@ -2176,7 +3753,7 @@ async function copyOutputStyles(selectedStyles, lang) {
|
|
|
2176
3753
|
const currentFilePath = fileURLToPath(import.meta.url);
|
|
2177
3754
|
const distDir = dirname(dirname(currentFilePath));
|
|
2178
3755
|
const rootDir = dirname(distDir);
|
|
2179
|
-
const templateDir = join(rootDir, "templates", lang, "output-styles");
|
|
3756
|
+
const templateDir = join(rootDir, "templates", "claude-code", lang, "output-styles");
|
|
2180
3757
|
for (const styleId of selectedStyles) {
|
|
2181
3758
|
const style = OUTPUT_STYLES.find((s) => s.id === styleId);
|
|
2182
3759
|
if (!style || !style.isCustom || !style.filePath) {
|
|
@@ -2392,9 +3969,9 @@ async function configureApiCompletely(preselectedAuthType) {
|
|
|
2392
3969
|
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
2393
3970
|
return null;
|
|
2394
3971
|
}
|
|
2395
|
-
const keyMessage = authType === "auth_token" ? i18n.t("api:enterAuthToken") : i18n.t("api:enterApiKey");
|
|
3972
|
+
const keyMessage = authType === "auth_token" ? i18n.t("api:enterAuthToken") + i18n.t("common:inputHidden") : i18n.t("api:enterApiKey") + i18n.t("common:inputHidden");
|
|
2396
3973
|
const { key } = await inquirer.prompt({
|
|
2397
|
-
type: "
|
|
3974
|
+
type: "password",
|
|
2398
3975
|
name: "key",
|
|
2399
3976
|
message: keyMessage,
|
|
2400
3977
|
validate: async (value) => {
|
|
@@ -2465,9 +4042,9 @@ async function modifyApiConfigPartially(existingConfig) {
|
|
|
2465
4042
|
}
|
|
2466
4043
|
} else if (item === "key") {
|
|
2467
4044
|
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"));
|
|
4045
|
+
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
4046
|
const { key } = await inquirer.prompt({
|
|
2470
|
-
type: "
|
|
4047
|
+
type: "password",
|
|
2471
4048
|
name: "key",
|
|
2472
4049
|
message: keyMessage,
|
|
2473
4050
|
validate: async (value) => {
|
|
@@ -2661,14 +4238,16 @@ async function chooseInstallationMethod() {
|
|
|
2661
4238
|
}
|
|
2662
4239
|
async function handleMultipleInstallations(status) {
|
|
2663
4240
|
ensureI18nInitialized();
|
|
2664
|
-
const
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
if (previousChoice
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
4241
|
+
const tomlConfig = readTomlConfig(ZCF_CONFIG_FILE);
|
|
4242
|
+
if (tomlConfig && tomlConfig.general?.currentTool === "claude-code") {
|
|
4243
|
+
const previousChoice = tomlConfig.claudeCode?.installType;
|
|
4244
|
+
if (previousChoice) {
|
|
4245
|
+
if (previousChoice === "global" && status.hasGlobal) {
|
|
4246
|
+
return "global";
|
|
4247
|
+
}
|
|
4248
|
+
if (previousChoice === "local" && status.hasLocal) {
|
|
4249
|
+
return "local";
|
|
4250
|
+
}
|
|
2672
4251
|
}
|
|
2673
4252
|
}
|
|
2674
4253
|
if (!status.hasGlobal && !status.hasLocal) {
|
|
@@ -2704,17 +4283,17 @@ async function handleMultipleInstallations(status) {
|
|
|
2704
4283
|
await removeLocalClaudeCode();
|
|
2705
4284
|
console.log(ansis.green(`\u2714 ${i18n.t("installation:localInstallationRemoved")}`));
|
|
2706
4285
|
}
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
4286
|
+
updateTomlConfig(ZCF_CONFIG_FILE, {
|
|
4287
|
+
claudeCode: {
|
|
4288
|
+
installType: "global"
|
|
4289
|
+
}
|
|
2711
4290
|
});
|
|
2712
4291
|
} else {
|
|
2713
4292
|
console.log(ansis.green(`\u2714 ${i18n.t("installation:usingLocalInstallation")}`));
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
4293
|
+
updateTomlConfig(ZCF_CONFIG_FILE, {
|
|
4294
|
+
claudeCode: {
|
|
4295
|
+
installType: "local"
|
|
4296
|
+
}
|
|
2718
4297
|
});
|
|
2719
4298
|
}
|
|
2720
4299
|
return choice;
|
|
@@ -2728,130 +4307,13 @@ async function handleMultipleInstallations(status) {
|
|
|
2728
4307
|
}
|
|
2729
4308
|
}
|
|
2730
4309
|
}
|
|
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
4310
|
|
|
2850
4311
|
function getRootDir() {
|
|
2851
4312
|
const currentFilePath = fileURLToPath(import.meta.url);
|
|
2852
4313
|
const distDir = dirname(dirname(currentFilePath));
|
|
2853
4314
|
return dirname(distDir);
|
|
2854
4315
|
}
|
|
4316
|
+
const DEFAULT_CODE_TOOL_TEMPLATE = "claude-code";
|
|
2855
4317
|
async function selectAndInstallWorkflows(configLang, preselectedWorkflows) {
|
|
2856
4318
|
ensureI18nInitialized();
|
|
2857
4319
|
const workflows = getOrderedWorkflows();
|
|
@@ -2911,7 +4373,16 @@ async function installWorkflowWithDependencies(config, configLang) {
|
|
|
2911
4373
|
await mkdir(commandsDir, { recursive: true });
|
|
2912
4374
|
}
|
|
2913
4375
|
for (const commandFile of config.commands) {
|
|
2914
|
-
const commandSource = join(
|
|
4376
|
+
const commandSource = join(
|
|
4377
|
+
rootDir,
|
|
4378
|
+
"templates",
|
|
4379
|
+
DEFAULT_CODE_TOOL_TEMPLATE,
|
|
4380
|
+
configLang,
|
|
4381
|
+
"workflow",
|
|
4382
|
+
config.category,
|
|
4383
|
+
"commands",
|
|
4384
|
+
commandFile
|
|
4385
|
+
);
|
|
2915
4386
|
const destFileName = commandFile;
|
|
2916
4387
|
const commandDest = join(commandsDir, destFileName);
|
|
2917
4388
|
if (existsSync(commandSource)) {
|
|
@@ -2933,7 +4404,16 @@ async function installWorkflowWithDependencies(config, configLang) {
|
|
|
2933
4404
|
await mkdir(agentsCategoryDir, { recursive: true });
|
|
2934
4405
|
}
|
|
2935
4406
|
for (const agent of config.agents) {
|
|
2936
|
-
const agentSource = join(
|
|
4407
|
+
const agentSource = join(
|
|
4408
|
+
rootDir,
|
|
4409
|
+
"templates",
|
|
4410
|
+
DEFAULT_CODE_TOOL_TEMPLATE,
|
|
4411
|
+
configLang,
|
|
4412
|
+
"workflow",
|
|
4413
|
+
config.category,
|
|
4414
|
+
"agents",
|
|
4415
|
+
agent.filename
|
|
4416
|
+
);
|
|
2937
4417
|
const agentDest = join(agentsCategoryDir, agent.filename);
|
|
2938
4418
|
if (existsSync(agentSource)) {
|
|
2939
4419
|
try {
|
|
@@ -3109,6 +4589,15 @@ function validateSkipPromptOptions(options) {
|
|
|
3109
4589
|
options.workflows = WORKFLOW_CONFIG_BASE.map((w) => w.id);
|
|
3110
4590
|
}
|
|
3111
4591
|
}
|
|
4592
|
+
function resolveCodeToolType(optionValue, savedValue) {
|
|
4593
|
+
if (isCodeToolType(optionValue)) {
|
|
4594
|
+
return optionValue;
|
|
4595
|
+
}
|
|
4596
|
+
if (savedValue && isCodeToolType(savedValue)) {
|
|
4597
|
+
return savedValue;
|
|
4598
|
+
}
|
|
4599
|
+
return DEFAULT_CODE_TOOL_TYPE;
|
|
4600
|
+
}
|
|
3112
4601
|
async function init(options = {}) {
|
|
3113
4602
|
if (options.skipPrompt) {
|
|
3114
4603
|
validateSkipPromptOptions(options);
|
|
@@ -3122,32 +4611,34 @@ async function init(options = {}) {
|
|
|
3122
4611
|
\u2139 ${i18n.t("installation:termuxDetected")}`));
|
|
3123
4612
|
console.log(ansis.gray(i18n.t("installation:termuxEnvironmentInfo")));
|
|
3124
4613
|
}
|
|
4614
|
+
const zcfConfig = readZcfConfig();
|
|
3125
4615
|
let configLang = options.configLang;
|
|
3126
4616
|
if (!configLang && !options.skipPrompt) {
|
|
3127
|
-
const
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
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;
|
|
4617
|
+
const { resolveTemplateLanguage } = await Promise.resolve().then(function () { return prompts; });
|
|
4618
|
+
configLang = await resolveTemplateLanguage(
|
|
4619
|
+
options.configLang,
|
|
4620
|
+
// Command line option
|
|
4621
|
+
zcfConfig
|
|
4622
|
+
);
|
|
3147
4623
|
} else if (!configLang && options.skipPrompt) {
|
|
3148
4624
|
configLang = "en";
|
|
3149
4625
|
}
|
|
3150
|
-
const
|
|
4626
|
+
const codeToolType = resolveCodeToolType(options.codeType, zcfConfig?.codeToolType);
|
|
4627
|
+
options.codeType = codeToolType;
|
|
4628
|
+
if (codeToolType === "codex") {
|
|
4629
|
+
await runCodexFullInit();
|
|
4630
|
+
updateZcfConfig({
|
|
4631
|
+
version,
|
|
4632
|
+
preferredLang: i18n.language,
|
|
4633
|
+
// ZCF界面语言
|
|
4634
|
+
templateLang: configLang,
|
|
4635
|
+
// 模板语言
|
|
4636
|
+
aiOutputLang: options.aiOutputLang || "en",
|
|
4637
|
+
codeToolType
|
|
4638
|
+
});
|
|
4639
|
+
console.log(ansis.green(i18n.t("codex:setupComplete")));
|
|
4640
|
+
return;
|
|
4641
|
+
}
|
|
3151
4642
|
const aiOutputLang = options.skipPrompt ? options.aiOutputLang || "en" : await resolveAiOutputLanguage(i18n.language, options.aiOutputLang, zcfConfig);
|
|
3152
4643
|
const installationStatus = await getInstallationStatus();
|
|
3153
4644
|
if (installationStatus.hasGlobal || installationStatus.hasLocal) {
|
|
@@ -3468,9 +4959,9 @@ ${ansis.blue(`\u2139 ${i18n.t("api:existingApiConfig")}`)}`);
|
|
|
3468
4959
|
continue;
|
|
3469
4960
|
} else {
|
|
3470
4961
|
const response = await inquirer.prompt({
|
|
3471
|
-
type: "
|
|
4962
|
+
type: "password",
|
|
3472
4963
|
name: "apiKey",
|
|
3473
|
-
message: service.apiKeyPrompt,
|
|
4964
|
+
message: service.apiKeyPrompt + i18n.t("common:inputHidden"),
|
|
3474
4965
|
validate: (value) => !!value || i18n.t("api:keyRequired")
|
|
3475
4966
|
});
|
|
3476
4967
|
if (!response.apiKey) {
|
|
@@ -3523,7 +5014,11 @@ ${ansis.blue(`\u2139 ${i18n.t("api:existingApiConfig")}`)}`);
|
|
|
3523
5014
|
updateZcfConfig({
|
|
3524
5015
|
version,
|
|
3525
5016
|
preferredLang: i18n.language,
|
|
3526
|
-
|
|
5017
|
+
// ZCF界面语言
|
|
5018
|
+
templateLang: configLang,
|
|
5019
|
+
// 模板语言
|
|
5020
|
+
aiOutputLang,
|
|
5021
|
+
codeToolType
|
|
3527
5022
|
});
|
|
3528
5023
|
console.log(ansis.green(`\u2714 ${i18n.t("configuration:configSuccess")} ${CLAUDE_DIR}`));
|
|
3529
5024
|
console.log(`
|
|
@@ -3537,7 +5032,7 @@ ${ansis.cyan(i18n.t("common:complete"))}`);
|
|
|
3537
5032
|
|
|
3538
5033
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
3539
5034
|
function getTemplateSettings() {
|
|
3540
|
-
const templatePath = join(__dirname, "../../templates/common/settings.json");
|
|
5035
|
+
const templatePath = join(__dirname, "../../templates/claude-code/common/settings.json");
|
|
3541
5036
|
const content = readFileSync(templatePath, "utf-8");
|
|
3542
5037
|
return JSON.parse(content);
|
|
3543
5038
|
}
|
|
@@ -3613,4 +5108,4 @@ async function openSettingsJson() {
|
|
|
3613
5108
|
}
|
|
3614
5109
|
}
|
|
3615
5110
|
|
|
3616
|
-
export {
|
|
5111
|
+
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 };
|