zcf
Version:
Zero-Config Code Flow - One-click configuration tool for Code Cli
1,478 lines (1,467 loc) • 77.3 kB
JavaScript
#!/usr/bin/env node
import cac from 'cac';
import ansis from 'ansis';
import { ak as ensureI18nInitialized, al as i18n, aO as readCcrConfig, aJ as isCcrInstalled, aK as installCcr, aP as configureCcrFeature, ao as promptBoolean, aQ as handleExitPromptError, aR as handleGeneralError, aS as COMETIX_COMMAND_NAME, aT as COMETIX_COMMANDS, aU as installCometixLine, am as addNumbersToChoices, aV as checkAndUpdateTools, aW as runCodexUpdate, aX as resolveCodeType$1, at as readJsonConfig, aY as writeJsonConfig, q as ZCF_CONFIG_FILE, aE as readZcfConfig, D as DEFAULT_CODE_TOOL_TYPE, u as isCodeToolType, aZ as displayBanner, aC as updateZcfConfig, a_ as version, a$ as resolveAiOutputLanguage, b0 as updatePromptOnly, b1 as selectAndInstallWorkflows, b2 as checkClaudeCodeVersionAndPrompt, w as resolveCodeToolType$1, b3 as displayBannerWithInfo, s as CODE_TOOL_BANNERS, b4 as runCodexUninstall, b5 as configureCodexMcp, b6 as configureCodexApi, b7 as runCodexWorkflowImportWithLanguageSelection, b8 as runCodexFullInit, i as init, b9 as switchCodexProvider, ba as listCodexProviders, ay as readCodexConfig, bb as switchToOfficialLogin, bc as switchToProvider, bd as readZcfConfigAsync, be as initI18n, bf as selectScriptLanguage, aD as changeLanguage } from './chunks/simple-config.mjs';
import { existsSync } from 'node:fs';
import { homedir } from 'node:os';
import inquirer from 'inquirer';
import { join } from 'pathe';
import { runCcrStop, runCcrStart, runCcrRestart, runCcrStatus, runCcrUi } from './chunks/commands.mjs';
import { changeScriptLanguageFeature, configureCodexAiMemoryFeature, configureCodexDefaultModelFeature, configureEnvPermissionFeature, configureAiMemoryFeature, configureDefaultModelFeature, configureMcpFeature, configureApiFeature } from './chunks/features.mjs';
import process from 'node:process';
import { x, exec as exec$1 } from 'tinyexec';
import { exec, spawn } from 'node:child_process';
import { promisify } from 'node:util';
import { pathExists } from 'fs-extra';
import { m as moveToTrash } from './shared/zcf.DGjQxTq_.mjs';
import { ClaudeCodeConfigManager } from './chunks/claude-code-config-manager.mjs';
import 'dayjs';
import 'node:url';
import 'inquirer-toggle';
import 'ora';
import 'semver';
import 'smol-toml';
import 'node:fs/promises';
import 'i18next';
import 'i18next-fs-backend';
import 'trash';
function isCcrConfigured() {
const CCR_CONFIG_FILE = join(homedir(), ".claude-code-router", "config.json");
if (!existsSync(CCR_CONFIG_FILE)) {
return false;
}
const config = readCcrConfig();
return config !== null;
}
async function showCcrMenu() {
try {
ensureI18nInitialized();
console.log(`
${ansis.cyan("\u2550".repeat(50))}`);
console.log(ansis.bold.cyan(` ${i18n.t("ccr:ccrMenuTitle")}`));
console.log(`${ansis.cyan("\u2550".repeat(50))}
`);
console.log(` ${ansis.cyan("1.")} ${i18n.t("ccr:ccrMenuOptions.initCcr")} ${ansis.gray(`- ${i18n.t("ccr:ccrMenuDescriptions.initCcr")}`)}`);
console.log(` ${ansis.cyan("2.")} ${i18n.t("ccr:ccrMenuOptions.startUi")} ${ansis.gray(`- ${i18n.t("ccr:ccrMenuDescriptions.startUi")}`)}`);
console.log(` ${ansis.cyan("3.")} ${i18n.t("ccr:ccrMenuOptions.checkStatus")} ${ansis.gray(`- ${i18n.t("ccr:ccrMenuDescriptions.checkStatus")}`)}`);
console.log(` ${ansis.cyan("4.")} ${i18n.t("ccr:ccrMenuOptions.restart")} ${ansis.gray(`- ${i18n.t("ccr:ccrMenuDescriptions.restart")}`)}`);
console.log(` ${ansis.cyan("5.")} ${i18n.t("ccr:ccrMenuOptions.start")} ${ansis.gray(`- ${i18n.t("ccr:ccrMenuDescriptions.start")}`)}`);
console.log(` ${ansis.cyan("6.")} ${i18n.t("ccr:ccrMenuOptions.stop")} ${ansis.gray(`- ${i18n.t("ccr:ccrMenuDescriptions.stop")}`)}`);
console.log(` ${ansis.yellow("0.")} ${i18n.t("ccr:ccrMenuOptions.back")}`);
console.log("");
const { choice } = await inquirer.prompt({
type: "input",
name: "choice",
message: i18n.t("common:enterChoice"),
validate: (value) => {
const valid = ["1", "2", "3", "4", "5", "6", "0"];
return valid.includes(value) || i18n.t("common:invalidChoice");
}
});
switch (choice) {
case "1": {
const ccrStatus = await isCcrInstalled();
if (!ccrStatus.hasCorrectPackage) {
await installCcr();
} else {
console.log(ansis.green(`\u2714 ${i18n.t("ccr:ccrAlreadyInstalled")}`));
}
await configureCcrFeature();
console.log(ansis.green(`
\u2714 ${i18n.t("ccr:ccrSetupComplete")}`));
break;
}
case "2":
if (!isCcrConfigured()) {
console.log(ansis.yellow(`
\u26A0\uFE0F ${i18n.t("ccr:ccrNotConfigured")}`));
console.log(ansis.cyan(` ${i18n.t("ccr:pleaseInitFirst")}
`));
} else {
const config = readCcrConfig();
await runCcrUi(config?.APIKEY);
}
break;
case "3":
if (!isCcrConfigured()) {
console.log(ansis.yellow(`
\u26A0\uFE0F ${i18n.t("ccr:ccrNotConfigured")}`));
console.log(ansis.cyan(` ${i18n.t("ccr:pleaseInitFirst")}
`));
} else {
await runCcrStatus();
}
break;
case "4":
if (!isCcrConfigured()) {
console.log(ansis.yellow(`
\u26A0\uFE0F ${i18n.t("ccr:ccrNotConfigured")}`));
console.log(ansis.cyan(` ${i18n.t("ccr:pleaseInitFirst")}
`));
} else {
await runCcrRestart();
}
break;
case "5":
if (!isCcrConfigured()) {
console.log(ansis.yellow(`
\u26A0\uFE0F ${i18n.t("ccr:ccrNotConfigured")}`));
console.log(ansis.cyan(` ${i18n.t("ccr:pleaseInitFirst")}
`));
} else {
await runCcrStart();
}
break;
case "6":
if (!isCcrConfigured()) {
console.log(ansis.yellow(`
\u26A0\uFE0F ${i18n.t("ccr:ccrNotConfigured")}`));
console.log(ansis.cyan(` ${i18n.t("ccr:pleaseInitFirst")}
`));
} else {
await runCcrStop();
}
break;
case "0":
return false;
}
if (choice !== "0") {
console.log(`
${ansis.dim("\u2500".repeat(50))}
`);
const continueInCcr = await promptBoolean({
message: i18n.t("common:returnToMenu"),
defaultValue: true
});
if (continueInCcr) {
return await showCcrMenu();
}
}
return false;
} catch (error) {
if (!handleExitPromptError(error)) {
handleGeneralError(error);
}
return false;
}
}
async function executeCcusage(args = []) {
try {
const command = "npx";
const commandArgs = ["ccusage@latest", ...args || []];
console.log(ansis.cyan(i18n.t("tools:runningCcusage")));
console.log(ansis.gray(`$ npx ccusage@latest ${(args || []).join(" ")}`));
console.log("");
await x(command, commandArgs, {
nodeOptions: {
stdio: "inherit"
}
});
} catch (error) {
console.error(ansis.red(i18n.t("tools:ccusageFailed")));
console.error(ansis.yellow(i18n.t("tools:checkNetworkConnection")));
if (process.env.DEBUG) {
console.error(ansis.gray(i18n.t("tools:errorDetails")), error);
}
if (process.env.NODE_ENV !== "test") {
process.exit(1);
}
throw error;
}
}
const execAsync = promisify(exec);
async function runCometixPrintConfig() {
ensureI18nInitialized();
try {
console.log(ansis.blue(`${i18n.t("cometix:printingConfig")}`));
const { stdout } = await execAsync(COMETIX_COMMANDS.PRINT_CONFIG);
console.log(stdout);
} catch (error) {
if (error.message.includes(`command not found: ${COMETIX_COMMAND_NAME}`)) {
console.error(ansis.red(`\u2717 ${i18n.t("cometix:commandNotFound")}`));
} else {
console.error(ansis.red(`\u2717 ${i18n.t("cometix:printConfigFailed")}: ${error}`));
}
throw error;
}
}
async function runCometixTuiConfig() {
ensureI18nInitialized();
return new Promise((resolve, reject) => {
console.log(ansis.blue(`${i18n.t("cometix:enteringTuiConfig")}`));
const child = spawn(COMETIX_COMMAND_NAME, ["-c"], {
stdio: "inherit",
// This allows the TUI to interact directly with the terminal
shell: true
});
child.on("close", (code) => {
if (code === 0) {
console.log(ansis.green(`\u2713 ${i18n.t("cometix:tuiConfigSuccess")}`));
resolve();
} else {
const error = new Error(`${COMETIX_COMMAND_NAME} -c exited with code ${code}`);
console.error(ansis.red(`\u2717 ${i18n.t("cometix:tuiConfigFailed")}: ${error.message}`));
reject(error);
}
});
child.on("error", (error) => {
if (error.message.includes(`command not found`) || error.message.includes("ENOENT")) {
console.error(ansis.red(`\u2717 ${i18n.t("cometix:commandNotFound")}`));
} else {
console.error(ansis.red(`\u2717 ${i18n.t("cometix:tuiConfigFailed")}: ${error.message}`));
}
reject(error);
});
});
}
async function showCometixMenu() {
try {
ensureI18nInitialized();
console.log(`
${ansis.cyan("\u2550".repeat(50))}`);
console.log(ansis.bold.cyan(` ${i18n.t("cometix:cometixMenuTitle")}`));
console.log(`${ansis.cyan("\u2550".repeat(50))}
`);
console.log(` ${ansis.cyan("1.")} ${i18n.t("cometix:cometixMenuOptions.installOrUpdate")} ${ansis.gray(`- ${i18n.t("cometix:cometixMenuDescriptions.installOrUpdate")}`)}`);
console.log(` ${ansis.cyan("2.")} ${i18n.t("cometix:cometixMenuOptions.printConfig")} ${ansis.gray(`- ${i18n.t("cometix:cometixMenuDescriptions.printConfig")}`)}`);
console.log(` ${ansis.cyan("3.")} ${i18n.t("cometix:cometixMenuOptions.customConfig")} ${ansis.gray(`- ${i18n.t("cometix:cometixMenuDescriptions.customConfig")}`)}`);
console.log(` ${ansis.yellow("0.")} ${i18n.t("cometix:cometixMenuOptions.back")}`);
console.log("");
const { choice } = await inquirer.prompt({
type: "input",
name: "choice",
message: i18n.t("common:enterChoice"),
validate: async (value) => {
const valid = ["1", "2", "3", "0"];
return valid.includes(value) || i18n.t("common:invalidChoice");
}
});
switch (choice) {
case "1":
await installCometixLine();
break;
case "2":
await runCometixPrintConfig();
break;
case "3":
await runCometixTuiConfig();
break;
case "0":
return false;
}
if (choice !== "0") {
console.log(`
${ansis.dim("\u2500".repeat(50))}
`);
const continueInCometix = await promptBoolean({
message: i18n.t("common:returnToMenu"),
defaultValue: true
});
if (continueInCometix) {
return await showCometixMenu();
}
}
return false;
} catch (error) {
if (!handleExitPromptError(error)) {
handleGeneralError(error);
}
return false;
}
}
async function runCcusageFeature() {
ensureI18nInitialized();
console.log("");
console.log(ansis.cyan(i18n.t("menu:menuOptions.ccusage")));
console.log(ansis.gray(`${i18n.t("tools:ccusageDescription")}`));
console.log("");
const choices = [
{ name: i18n.t("tools:ccusageModes.daily"), value: "daily" },
{ name: i18n.t("tools:ccusageModes.monthly"), value: "monthly" },
{ name: i18n.t("tools:ccusageModes.session"), value: "session" },
{ name: i18n.t("tools:ccusageModes.blocks"), value: "blocks" },
{ name: i18n.t("tools:ccusageModes.custom"), value: "custom" },
{ name: i18n.t("common:back"), value: "back" }
];
const { mode } = await inquirer.prompt({
type: "list",
name: "mode",
message: i18n.t("tools:selectAnalysisMode"),
choices: addNumbersToChoices(choices)
});
if (mode === "back") {
return;
}
let args = [];
if (mode === "custom") {
const { customArgs } = await inquirer.prompt({
type: "input",
name: "customArgs",
message: i18n.t("tools:enterCustomArgs"),
default: ""
});
if (customArgs === null || customArgs === void 0 || customArgs === "") {
args = [];
} else {
const argsString = String(customArgs).trim();
if (!argsString) {
args = [];
} else {
const argPattern = /"([^"]*)"|'([^']*)'|(\S+)/g;
const matches = [];
let match = argPattern.exec(argsString);
while (match !== null) {
const value = match[1] || match[2] || match[3];
if (value) {
matches.push(value);
}
match = argPattern.exec(argsString);
}
args = matches;
}
}
} else {
args = [mode];
}
console.log("");
await executeCcusage(args);
console.log("");
await inquirer.prompt({
type: "input",
name: "continue",
message: ansis.gray(i18n.t("tools:pressEnterToContinue"))
});
}
async function runCcrMenuFeature() {
await showCcrMenu();
}
async function runCometixMenuFeature() {
await showCometixMenu();
}
class ToolUpdateScheduler {
/**
* Update tools based on code type
* @param codeType - The code tool type to update
* @param skipPrompt - Whether to skip interactive prompts
*/
async updateByCodeType(codeType, skipPrompt = false) {
await ensureI18nInitialized();
switch (codeType) {
case "claude-code":
await this.updateClaudeCodeTools(skipPrompt);
break;
case "codex":
await this.updateCodexTools(skipPrompt);
break;
default:
throw new Error(`Unsupported code type: ${codeType}`);
}
}
/**
* Update Claude Code related tools
* @param skipPrompt - Whether to skip interactive prompts
*/
async updateClaudeCodeTools(skipPrompt) {
await checkAndUpdateTools(skipPrompt);
}
/**
* Update Codex tools
* @param skipPrompt - Whether to skip interactive prompts
*/
async updateCodexTools(skipPrompt) {
await runCodexUpdate(false, skipPrompt);
}
}
async function checkUpdates(options = {}) {
try {
const skipPrompt = options.skipPrompt || false;
let codeType;
try {
codeType = await resolveCodeType$1(options.codeType);
} catch (err) {
const errorMessage = err instanceof Error ? err.message : String(err);
console.error(ansis.red(`${errorMessage}
Defaulting to "claude-code".`));
codeType = "claude-code";
}
const scheduler = new ToolUpdateScheduler();
await scheduler.updateByCodeType(codeType, skipPrompt);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(ansis.red(`${i18n.t("updater:errorCheckingUpdates")} ${errorMessage}`));
process.exit(1);
}
}
class ZcfUninstaller {
_lang;
// Reserved for future i18n support
conflictResolution = /* @__PURE__ */ new Map();
constructor(lang = "en") {
this._lang = lang;
this.conflictResolution.set("claude-code", ["mcps"]);
void this._lang;
}
/**
* 1. Remove outputStyle field from settings.json and output-styles directory
*/
async removeOutputStyles() {
const result = {
success: false,
removed: [],
removedConfigs: [],
errors: [],
warnings: []
};
try {
const settingsPath = join(homedir(), ".claude", "settings.json");
const outputStylesPath = join(homedir(), ".claude", "output-styles");
if (await pathExists(settingsPath)) {
const settings = readJsonConfig(settingsPath) || {};
if (settings.outputStyle) {
delete settings.outputStyle;
writeJsonConfig(settingsPath, settings);
result.removedConfigs.push("outputStyle field from settings.json");
}
} else {
result.warnings.push(i18n.t("uninstall:settingsJsonNotFound"));
}
if (await pathExists(outputStylesPath)) {
const trashResult = await moveToTrash(outputStylesPath);
if (!trashResult[0]?.success) {
result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
}
result.removed.push("~/.claude/output-styles/");
} else {
result.warnings.push(i18n.t("uninstall:outputStylesDirectoryNotFound"));
}
result.success = true;
} catch (error) {
result.errors.push(`Failed to remove output styles: ${error.message}`);
}
return result;
}
/**
* 2. Remove custom commands directory (commands/zcf/)
*/
async removeCustomCommands() {
const result = {
success: false,
removed: [],
removedConfigs: [],
errors: [],
warnings: []
};
try {
const commandsPath = join(homedir(), ".claude", "commands", "zcf");
if (await pathExists(commandsPath)) {
const trashResult = await moveToTrash(commandsPath);
if (!trashResult[0]?.success) {
result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
}
result.removed.push("commands/zcf/");
result.success = true;
} else {
result.warnings.push(i18n.t("uninstall:commandsNotFound"));
result.success = true;
}
} catch (error) {
result.errors.push(`Failed to remove custom commands: ${error.message}`);
}
return result;
}
/**
* 3. Remove custom agents directory (agents/zcf/)
*/
async removeCustomAgents() {
const result = {
success: false,
removed: [],
removedConfigs: [],
errors: [],
warnings: []
};
try {
const agentsPath = join(homedir(), ".claude", "agents", "zcf");
if (await pathExists(agentsPath)) {
const trashResult = await moveToTrash(agentsPath);
if (!trashResult[0]?.success) {
result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
}
result.removed.push("agents/zcf/");
result.success = true;
} else {
result.warnings.push(i18n.t("uninstall:agentsNotFound"));
result.success = true;
}
} catch (error) {
result.errors.push(`Failed to remove custom agents: ${error.message}`);
}
return result;
}
/**
* 4. Remove global memory file (CLAUDE.md)
*/
async removeClaudeMd() {
const result = {
success: false,
removed: [],
removedConfigs: [],
errors: [],
warnings: []
};
try {
const claudeMdPath = join(homedir(), ".claude", "CLAUDE.md");
if (await pathExists(claudeMdPath)) {
const trashResult = await moveToTrash(claudeMdPath);
if (!trashResult[0]?.success) {
result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
}
result.removed.push("CLAUDE.md");
result.success = true;
} else {
result.warnings.push(i18n.t("uninstall:claudeMdNotFound"));
result.success = true;
}
} catch (error) {
result.errors.push(`Failed to remove CLAUDE.md: ${error.message}`);
}
return result;
}
/**
* 5. Remove permissions and environment variables
*/
async removePermissionsAndEnvs() {
const result = {
success: false,
removed: [],
removedConfigs: [],
errors: [],
warnings: []
};
try {
const settingsPath = join(homedir(), ".claude", "settings.json");
if (await pathExists(settingsPath)) {
const settings = readJsonConfig(settingsPath) || {};
let modified = false;
if (settings.permissions) {
delete settings.permissions;
result.removedConfigs.push("permissions configuration");
modified = true;
}
if (settings.env) {
delete settings.env;
result.removedConfigs.push("environment variables");
modified = true;
}
if (modified) {
writeJsonConfig(settingsPath, settings);
}
result.success = true;
} else {
result.warnings.push(i18n.t("uninstall:settingsJsonNotFound"));
result.success = true;
}
} catch (error) {
result.errors.push(`Failed to remove permissions and envs: ${error.message}`);
}
return result;
}
/**
* 6. Remove MCP servers from .claude.json (mcpServers field only)
*/
async removeMcps() {
const result = {
success: false,
removed: [],
removedConfigs: [],
errors: [],
warnings: []
};
try {
const claudeJsonPath = join(homedir(), ".claude.json");
if (await pathExists(claudeJsonPath)) {
const config = readJsonConfig(claudeJsonPath) || {};
if (config.mcpServers) {
delete config.mcpServers;
writeJsonConfig(claudeJsonPath, config);
result.removedConfigs.push("mcpServers from .claude.json");
}
result.success = true;
} else {
result.warnings.push(i18n.t("uninstall:claudeJsonNotFound"));
result.success = true;
}
} catch (error) {
result.errors.push(`Failed to remove MCP servers: ${error.message}`);
}
return result;
}
/**
* 7. Uninstall Claude Code Router and remove configuration
*/
async uninstallCcr() {
const result = {
success: false,
removed: [],
removedConfigs: [],
errors: [],
warnings: []
};
try {
const ccrPath = join(homedir(), ".claude-code-router");
if (await pathExists(ccrPath)) {
const trashResult = await moveToTrash(ccrPath);
if (!trashResult[0]?.success) {
result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
}
result.removed.push(".claude-code-router/");
}
try {
await exec$1("npm", ["uninstall", "-g", "@musistudio/claude-code-router"]);
result.removed.push("@musistudio/claude-code-router package");
result.success = true;
} catch (npmError) {
if (npmError.message.includes("not found") || npmError.message.includes("not installed")) {
result.warnings.push(i18n.t("uninstall:ccrPackageNotFound"));
result.success = true;
} else {
result.errors.push(`Failed to uninstall CCR package: ${npmError.message}`);
}
}
} catch (error) {
result.errors.push(`Failed to uninstall CCR: ${error.message}`);
}
return result;
}
/**
* 8. Uninstall CCometixLine
*/
async uninstallCcline() {
const result = {
success: false,
removed: [],
removedConfigs: [],
errors: [],
warnings: []
};
try {
await exec$1("npm", ["uninstall", "-g", "@cometix/ccline"]);
result.removed.push("@cometix/ccline package");
result.success = true;
} catch (error) {
if (error.message.includes("not found") || error.message.includes("not installed")) {
result.warnings.push(i18n.t("uninstall:cclinePackageNotFound"));
result.success = true;
} else {
result.errors.push(`Failed to uninstall CCometixLine: ${error.message}`);
}
}
return result;
}
/**
* 9. Uninstall Claude Code and remove entire .claude.json
*/
async uninstallClaudeCode() {
const result = {
success: false,
removed: [],
removedConfigs: [],
errors: [],
warnings: []
};
try {
const claudeJsonPath = join(homedir(), ".claude.json");
if (await pathExists(claudeJsonPath)) {
const trashResult = await moveToTrash(claudeJsonPath);
if (!trashResult[0]?.success) {
result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
}
result.removed.push(".claude.json (includes MCP configuration)");
}
try {
const { uninstallCodeTool } = await import('./chunks/simple-config.mjs').then(function (n) { return n.bo; });
const success = await uninstallCodeTool("claude-code");
if (success) {
result.removed.push("@anthropic-ai/claude-code");
result.success = true;
} else {
result.errors.push(i18n.t("uninstall:uninstallFailed", { codeType: i18n.t("common:claudeCode"), message: "" }));
}
} catch (npmError) {
if (npmError.message.includes("not found") || npmError.message.includes("not installed")) {
result.warnings.push(i18n.t("uninstall:claudeCodePackageNotFound"));
result.success = true;
} else {
result.errors.push(i18n.t("uninstall:uninstallFailed", { codeType: i18n.t("common:claudeCode"), message: `: ${npmError.message}` }));
}
}
} catch (error) {
result.errors.push(i18n.t("uninstall:uninstallFailed", { codeType: i18n.t("common:claudeCode"), message: `: ${error.message}` }));
}
return result;
}
/**
* 10. Remove backup files
*/
async removeBackups() {
const result = {
success: false,
removed: [],
removedConfigs: [],
errors: [],
warnings: []
};
try {
const backupPath = join(homedir(), ".claude", "backup");
if (await pathExists(backupPath)) {
const trashResult = await moveToTrash(backupPath);
if (!trashResult[0]?.success) {
result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
}
result.removed.push("backup/");
result.success = true;
} else {
result.warnings.push(i18n.t("uninstall:backupsNotFound"));
result.success = true;
}
} catch (error) {
result.errors.push(`Failed to remove backups: ${error.message}`);
}
return result;
}
/**
* 11. Remove ZCF preference configuration
*/
async removeZcfConfig() {
const result = {
success: false,
removed: [],
removedConfigs: [],
errors: [],
warnings: []
};
try {
const zcfConfigPath = ZCF_CONFIG_FILE;
const relativeName = zcfConfigPath.replace(homedir(), "~");
if (await pathExists(zcfConfigPath)) {
const trashResult = await moveToTrash(zcfConfigPath);
if (!trashResult[0]?.success) {
result.warnings.push(trashResult[0]?.error || "Failed to move to trash");
}
result.removed.push(relativeName);
result.success = true;
} else {
result.warnings.push(i18n.t("uninstall:zcfConfigNotFound"));
result.success = true;
}
} catch (error) {
result.errors.push(`Failed to remove ZCF config: ${error.message}`);
}
return result;
}
/**
* Complete uninstall - remove all directories and packages
*/
async completeUninstall() {
const result = {
success: true,
removed: [],
removedConfigs: [],
errors: [],
warnings: []
};
try {
const directoriesToRemove = [
{ path: join(homedir(), ".claude"), name: "~/.claude/" },
{ path: join(homedir(), ".claude.json"), name: "~/.claude.json" },
{ path: join(homedir(), ".claude-code-router"), name: "~/.claude-code-router/" }
];
for (const dir of directoriesToRemove) {
try {
if (await pathExists(dir.path)) {
const trashResult = await moveToTrash(dir.path);
if (!trashResult[0]?.success) {
result.warnings.push(`Failed to move ${dir.name} to trash: ${trashResult[0]?.error || "Unknown error"}`);
}
result.removed.push(dir.name);
}
} catch (error) {
result.warnings.push(`Failed to remove ${dir.name}: ${error.message}`);
}
}
const packagesToUninstall = [
"@musistudio/claude-code-router",
"@cometix/ccline",
"@anthropic-ai/claude-code"
];
for (const pkg of packagesToUninstall) {
try {
await exec$1("npm", ["uninstall", "-g", pkg]);
result.removed.push(`${pkg} package`);
} catch (error) {
if (error.message.includes("not found") || error.message.includes("not installed")) {
if (pkg.includes("claude-code-router")) {
result.warnings.push(i18n.t("uninstall:ccrPackageNotFound"));
} else if (pkg.includes("ccline")) {
result.warnings.push(i18n.t("uninstall:cclinePackageNotFound"));
} else {
result.warnings.push(i18n.t("uninstall:claudeCodePackageNotFound"));
}
} else {
result.warnings.push(`Failed to uninstall ${pkg}: ${error.message}`);
}
}
}
} catch (error) {
result.errors.push(`Complete uninstall failed: ${error.message}`);
result.success = false;
}
return result;
}
/**
* Custom uninstall with conflict resolution
*/
async customUninstall(selectedItems) {
const resolvedItems = this.resolveConflicts(selectedItems);
const results = [];
for (const item of resolvedItems) {
try {
const result = await this.executeUninstallItem(item);
results.push(result);
} catch (error) {
results.push({
success: false,
removed: [],
removedConfigs: [],
errors: [`Failed to execute ${item}: ${error.message}`],
warnings: []
});
}
}
return results;
}
/**
* Resolve conflicts between uninstall items
*/
resolveConflicts(items) {
const resolved = [...items];
for (const [primary, conflicts] of this.conflictResolution) {
if (resolved.includes(primary)) {
conflicts.forEach((conflict) => {
const index = resolved.indexOf(conflict);
if (index > -1) {
resolved.splice(index, 1);
}
});
}
}
return resolved;
}
/**
* Execute uninstall for a specific item
*/
async executeUninstallItem(item) {
switch (item) {
case "output-styles":
return await this.removeOutputStyles();
case "commands":
return await this.removeCustomCommands();
case "agents":
return await this.removeCustomAgents();
case "claude-md":
return await this.removeClaudeMd();
case "permissions-envs":
return await this.removePermissionsAndEnvs();
case "mcps":
return await this.removeMcps();
case "ccr":
return await this.uninstallCcr();
case "ccline":
return await this.uninstallCcline();
case "claude-code":
return await this.uninstallClaudeCode();
case "backups":
return await this.removeBackups();
case "zcf-config":
return await this.removeZcfConfig();
default:
return {
success: false,
removed: [],
removedConfigs: [],
errors: [`Unknown uninstall item: ${item}`],
warnings: []
};
}
}
}
async function uninstall(options = {}) {
try {
ensureI18nInitialized();
let codeType;
if (options.codeType) {
try {
codeType = await resolveCodeType$1(options.codeType);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(ansis.red(`${i18n.t("errors:generalError")} ${errorMessage}`));
const config = readZcfConfig();
codeType = config?.codeToolType && isCodeToolType(config.codeToolType) ? config.codeToolType : DEFAULT_CODE_TOOL_TYPE;
}
} else {
const config = readZcfConfig();
codeType = config?.codeToolType && isCodeToolType(config.codeToolType) ? config.codeToolType : DEFAULT_CODE_TOOL_TYPE;
}
const uninstaller = new ZcfUninstaller(options.lang || "en");
if (codeType === "codex") {
const { runCodexUninstall } = await import('./chunks/simple-config.mjs').then(function (n) { return n.bn; });
await runCodexUninstall();
return;
}
if (options.mode && options.mode !== "interactive") {
if (options.mode === "complete") {
await executeCompleteUninstall(uninstaller);
return;
} else if (options.mode === "custom" && options.items) {
let items;
if (typeof options.items === "string") {
items = options.items.split(",").map((item) => item.trim());
} else {
items = options.items;
}
await executeCustomUninstall(uninstaller, items);
return;
}
}
await showInteractiveUninstall(uninstaller);
} catch (error) {
if (!handleExitPromptError(error)) {
handleGeneralError(error);
}
}
}
async function showInteractiveUninstall(uninstaller) {
console.log(ansis.cyan.bold(i18n.t("uninstall:title")));
console.log("");
const { mainChoice } = await inquirer.prompt({
type: "list",
name: "mainChoice",
message: i18n.t("uninstall:selectMainOption"),
choices: addNumbersToChoices([
{
name: `${i18n.t("uninstall:completeUninstall")} - ${ansis.gray(i18n.t("uninstall:completeUninstallDesc"))}`,
value: "complete",
short: i18n.t("uninstall:completeUninstall")
},
{
name: `${i18n.t("uninstall:customUninstall")} - ${ansis.gray(i18n.t("uninstall:customUninstallDesc"))}`,
value: "custom",
short: i18n.t("uninstall:customUninstall")
}
])
});
if (!mainChoice) {
console.log(ansis.yellow(i18n.t("common:cancelled")));
return;
}
if (mainChoice === "complete") {
await executeCompleteUninstall(uninstaller);
} else {
await showCustomUninstallMenu(uninstaller);
}
}
async function showCustomUninstallMenu(uninstaller) {
console.log("");
console.log(ansis.cyan(i18n.t("uninstall:selectCustomItems")));
const { customItems } = await inquirer.prompt({
type: "checkbox",
name: "customItems",
message: `${i18n.t("uninstall:selectItemsToRemove")} ${i18n.t("common:multiSelectHint")}`,
choices: [
{
name: i18n.t("uninstall:outputStyles"),
value: "output-styles"
},
{
name: i18n.t("uninstall:commands"),
value: "commands"
},
{
name: i18n.t("uninstall:agents"),
value: "agents"
},
{
name: i18n.t("uninstall:claudeMd"),
value: "claude-md"
},
{
name: i18n.t("uninstall:permissionsEnvs"),
value: "permissions-envs"
},
{
name: i18n.t("uninstall:mcps"),
value: "mcps"
},
{
name: i18n.t("uninstall:ccr"),
value: "ccr"
},
{
name: i18n.t("uninstall:ccline"),
value: "ccline"
},
{
name: i18n.t("uninstall:claudeCode"),
value: "claude-code"
},
{
name: i18n.t("uninstall:backups"),
value: "backups"
},
{
name: i18n.t("uninstall:zcfConfig"),
value: "zcf-config"
}
],
validate: (answers) => {
if (answers.length === 0) {
return i18n.t("uninstall:selectAtLeastOne");
}
return true;
}
});
if (!customItems || customItems.length === 0) {
console.log(ansis.yellow(i18n.t("common:cancelled")));
return;
}
await executeCustomUninstall(uninstaller, customItems);
}
async function executeCompleteUninstall(uninstaller) {
console.log("");
console.log(ansis.red.bold(i18n.t("uninstall:executingComplete")));
console.log(ansis.yellow(i18n.t("uninstall:completeWarning")));
const confirm = await promptBoolean({
message: i18n.t("uninstall:confirmComplete"),
defaultValue: false
});
if (!confirm) {
console.log(ansis.yellow(i18n.t("common:cancelled")));
return;
}
console.log("");
console.log(ansis.cyan(i18n.t("uninstall:processingComplete")));
const result = await uninstaller.completeUninstall();
displayUninstallResult("complete", [result]);
}
async function executeCustomUninstall(uninstaller, items) {
console.log("");
console.log(ansis.cyan(i18n.t("uninstall:executingCustom")));
console.log(ansis.gray(i18n.t("uninstall:selectedItems")));
items.forEach((item) => {
console.log(` \u2022 ${i18n.t(`uninstall:${item}`)}`);
});
const confirm = await promptBoolean({
message: i18n.t("uninstall:confirmCustom"),
defaultValue: false
});
if (!confirm) {
console.log(ansis.yellow(i18n.t("common:cancelled")));
return;
}
console.log("");
console.log(ansis.cyan(i18n.t("uninstall:processingCustom")));
const results = await uninstaller.customUninstall(items);
displayUninstallResult("custom", results);
}
function displayUninstallResult(mode, results) {
console.log("");
console.log(ansis.cyan("\u2500".repeat(50)));
let totalSuccess = 0;
let totalErrors = 0;
let totalWarnings = 0;
results.forEach((result) => {
if (result.success) {
totalSuccess++;
}
if (result.removed && result.removed.length > 0) {
console.log(ansis.green(`\u{1F5D1}\uFE0F ${i18n.t("uninstall:movedToTrash")}:`));
result.removed.forEach((item) => {
console.log(ansis.gray(` \u2022 ${item}`));
});
}
if (result.removedConfigs && result.removedConfigs.length > 0) {
console.log(ansis.green(`\u2714 ${i18n.t("uninstall:removedConfigs")}:`));
result.removedConfigs.forEach((item) => {
console.log(ansis.gray(` \u2022 ${item}`));
});
}
if (result.errors && result.errors.length > 0) {
totalErrors += result.errors.length;
console.log(ansis.red(`\u2716 ${i18n.t("uninstall:errors")}:`));
result.errors.forEach((error) => {
console.log(ansis.red(` \u2022 ${error}`));
});
}
if (result.warnings && result.warnings.length > 0) {
totalWarnings += result.warnings.length;
console.log(ansis.yellow(`\u26A0 ${i18n.t("uninstall:warnings")}:`));
result.warnings.forEach((warning) => {
console.log(ansis.yellow(` \u2022 ${warning}`));
});
}
});
const totalRemovedFiles = results.reduce((count, result) => count + (result.removed?.length || 0), 0);
const totalRemovedConfigs = results.reduce((count, result) => count + (result.removedConfigs?.length || 0), 0);
console.log("");
console.log(ansis.cyan("\u2500".repeat(50)));
if (mode === "complete") {
if (totalErrors === 0) {
console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:completeSuccess")}`));
} else {
console.log(ansis.yellow.bold(`\u26A0 ${i18n.t("uninstall:completePartialSuccess")}`));
}
} else {
if (totalRemovedFiles > 0 && totalRemovedConfigs > 0) {
console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccessBoth", {
fileCount: totalRemovedFiles,
configCount: totalRemovedConfigs
})}`));
} else if (totalRemovedFiles > 0) {
console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccessFiles", {
count: totalRemovedFiles
})}`));
} else if (totalRemovedConfigs > 0) {
console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccessConfigs", {
count: totalRemovedConfigs
})}`));
} else {
console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccess", { count: totalSuccess })}`));
}
if (totalErrors > 0) {
console.log(ansis.red(`\u2716 ${i18n.t("uninstall:errorsCount", { count: totalErrors })}`));
}
if (totalWarnings > 0) {
console.log(ansis.yellow(`\u26A0 ${i18n.t("uninstall:warningsCount", { count: totalWarnings })}`));
}
}
console.log("");
}
function resolveCodeToolType(optionValue, savedValue) {
if (optionValue !== void 0) {
const resolved = resolveCodeToolType$1(optionValue);
if (resolved !== DEFAULT_CODE_TOOL_TYPE || optionValue === DEFAULT_CODE_TOOL_TYPE) {
return resolved;
}
}
if (savedValue && isCodeToolType(savedValue)) {
return savedValue;
}
return DEFAULT_CODE_TOOL_TYPE;
}
async function update(options = {}) {
try {
if (!options.skipBanner) {
displayBanner(i18n.t("cli:banner.updateSubtitle"));
}
const zcfConfig = readZcfConfig();
const codeToolType = resolveCodeToolType(options.codeType, zcfConfig?.codeToolType);
options.codeType = codeToolType;
if (codeToolType === "codex") {
await runCodexUpdate();
const newPreferredLang = options.configLang || zcfConfig?.preferredLang;
if (newPreferredLang) {
updateZcfConfig({
version,
preferredLang: newPreferredLang,
codeToolType
});
} else {
updateZcfConfig({
version,
codeToolType
});
}
return;
}
const { resolveTemplateLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.bm; });
const configLang = await resolveTemplateLanguage(
options.configLang,
// Command line option
zcfConfig,
options.skipPrompt
// Non-interactive mode flag
);
const aiOutputLang = await resolveAiOutputLanguage(i18n.language, options.aiOutputLang, zcfConfig, options.skipPrompt);
console.log(ansis.cyan(`
${i18n.t("configuration:updatingPrompts")}
`));
await updatePromptOnly(aiOutputLang);
await selectAndInstallWorkflows(configLang);
await checkClaudeCodeVersionAndPrompt(false);
updateZcfConfig({
version,
templateLang: configLang,
// 保存模板语言选择
aiOutputLang,
codeToolType
});
} catch (error) {
if (!handleExitPromptError(error)) {
handleGeneralError(error);
}
}
}
const CODE_TOOL_LABELS = {
"claude-code": "Claude Code",
"codex": "Codex"
};
function getCurrentCodeTool() {
const config = readZcfConfig();
if (config?.codeToolType && isCodeToolType(config.codeToolType)) {
return config.codeToolType;
}
return DEFAULT_CODE_TOOL_TYPE;
}
function printSeparator() {
console.log(`
${ansis.dim("\u2500".repeat(50))}
`);
}
function getCodeToolLabel(codeTool) {
return CODE_TOOL_LABELS[codeTool] || codeTool;
}
async function promptCodeToolSelection(current) {
const choices = addNumbersToChoices(Object.entries(CODE_TOOL_LABELS).map(([value, label]) => ({
name: label,
value,
short: label
})));
const { tool } = await inquirer.prompt({
type: "list",
name: "tool",
message: i18n.t("menu:switchCodeToolPrompt"),
default: current,
choices
});
if (!tool) {
console.log(ansis.yellow(i18n.t("common:cancelled")));
return null;
}
return tool;
}
async function handleCodeToolSwitch(current) {
const newTool = await promptCodeToolSelection(current);
if (!newTool || newTool === current) {
return false;
}
updateZcfConfig({ codeToolType: newTool });
console.log(ansis.green(`\u2714 ${i18n.t("menu:codeToolSwitched", { tool: getCodeToolLabel(newTool) })}`));
return true;
}
function printOtherToolsSection() {
console.log(` --------- ${i18n.t("menu:menuSections.otherTools")} ----------`);
console.log(
` ${ansis.cyan("R.")} ${i18n.t("menu:menuOptions.ccrManagement")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.ccrManagement")}`)}`
);
console.log(
` ${ansis.cyan("U.")} ${i18n.t("menu:menuOptions.ccusage")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.ccusage")}`)}`
);
console.log(
` ${ansis.cyan("L.")} ${i18n.t("menu:menuOptions.cometixLine")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.cometixLine")}`)}`
);
console.log("");
}
function printZcfSection(options) {
console.log(" ------------ ZCF ------------");
console.log(
` ${ansis.cyan("0.")} ${i18n.t("menu:menuOptions.changeLanguage")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.changeLanguage")}`)}`
);
console.log(
` ${ansis.cyan("S.")} ${i18n.t("menu:menuOptions.switchCodeTool")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.switchCodeTool")}`)}`
);
console.log(
` ${ansis.cyan("-.")} ${options.uninstallOption} ${ansis.gray(`- ${options.uninstallDescription}`)}`
);
console.log(
` ${ansis.cyan("+.")} ${options.updateOption} ${ansis.gray(`- ${options.updateDescription}`)}`
);
console.log(` ${ansis.red("Q.")} ${ansis.red(i18n.t("menu:menuOptions.exit"))}`);
console.log("");
}
async function showClaudeCodeMenu() {
console.log(ansis.cyan(i18n.t("menu:selectFunction")));
console.log(" -------- Claude Code --------");
console.log(
` ${ansis.cyan("1.")} ${i18n.t("menu:menuOptions.fullInit")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.fullInit")}`)}`
);
console.log(
` ${ansis.cyan("2.")} ${i18n.t("menu:menuOptions.importWorkflow")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.importWorkflow")}`)}`
);
console.log(
` ${ansis.cyan("3.")} ${i18n.t("menu:menuOptions.configureApiOrCcr")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureApiOrCcr")}`)}`
);
console.log(
` ${ansis.cyan("4.")} ${i18n.t("menu:menuOptions.configureMcp")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureMcp")}`)}`
);
console.log(
` ${ansis.cyan("5.")} ${i18n.t("menu:menuOptions.configureModel")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureModel")}`)}`
);
console.log(
` ${ansis.cyan("6.")} ${i18n.t("menu:menuOptions.configureAiMemory")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureAiMemory")}`)}`
);
console.log(
` ${ansis.cyan("7.")} ${i18n.t("menu:menuOptions.configureEnvPermission")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureEnvPermission")}`)}`
);
console.log("");
printOtherToolsSection();
printZcfSection({
uninstallOption: i18n.t("menu:menuOptions.uninstall"),
uninstallDescription: i18n.t("menu:menuDescriptions.uninstall"),
updateOption: i18n.t("menu:menuOptions.checkUpdates"),
updateDescription: i18n.t("menu:menuDescriptions.checkUpdates")
});
const { choice } = await inquirer.prompt({
type: "input",
name: "choice",
message: i18n.t("common:enterChoice"),
validate: (value) => {
const valid = ["1", "2", "3", "4", "5", "6", "7", "r", "R", "u", "U", "l", "L", "0", "-", "+", "s", "S", "q", "Q"];
return valid.includes(value) || i18n.t("common:invalidChoice");
}
});
if (!choice) {
console.log(ansis.yellow(i18n.t("common:cancelled")));
return "exit";
}
const normalized = choice.toLowerCase();
switch (normalized) {
case "1":
await init({ skipBanner: true });
break;
case "2":
await update({ skipBanner: true });
break;
case "3":
await configureApiFeature();
break;
case "4":
await configureMcpFeature();
break;
case "5":
await configureDefaultModelFeature();
break;
case "6":
await configureAiMemoryFeature();
break;
case "7":
await configureEnvPermissionFeature();
break;
case "r":
await runCcrMenuFeature();
printSeparator();
return void 0;
case "u":
await runCcusageFeature();
printSeparator();
return void 0;
case "l":
await runCometixMenuFeature();
printSeparator();
return void 0;
case "0": {
const currentLang = i18n.language;
await changeScriptLanguageFeature(currentLang);
printSeparator();
return void 0;
}
case "-":
await uninstall();
printSeparator();
return void 0;
case "+":
await checkUpdates();
printSeparator();
return void 0;
case "s": {
const switched = await handleCodeToolSwitch("claude-code");
if (switched) {
return "switch";
}
printSeparator();
return void 0;
}
case "q":
console.log(ansis.cyan(i18n.t("common:goodbye")));
return "exit";
default:
return void 0;
}
printSeparator();
const shouldContinue = await promptBoolean({
message: i18n.t("common:returnToMenu"),
defaultValue: true
});
if (!shouldContinue) {
console.log(ansis.cyan(i18n.t("common:goodbye")));
return "exit";
}
return void 0;
}
async function showCodexMenu() {
console.log(ansis.cyan(i18n.t("menu:selectFunction")));
console.log(" -------- Codex --------");
console.log(
` ${ansis.cyan("1.")} ${i18n.t("menu:menuOptions.codexFullInit")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexFullInit")}`)}`
);
console.log(
` ${ansis.cyan("2.")} ${i18n.t("menu:menuOptions.codexImportWorkflow")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexImportWorkflow")}`)}`
);
console.log(
` ${ansis.cyan("3.")} ${i18n.t("menu:menuOptions.codexConfigureApi")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexConfigureApi")}`)}`
);
console.log(
` ${ansis.cyan("4.")} ${i18n.t("menu:menuOptions.codexConfigureMcp")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexConfigureMcp")}`)}`
);
console.log(
` ${ansis.cyan("5.")} ${i18n.t("menu:menuOptions.codexConfigureModel")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexConfigureModel")}`)}`
);
console.log(
` ${ansis.cyan("6.")} ${i18n.t("menu:menuOptions.codexConfigureAiMemory")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexConfigureAiMemory")}`)}`
);
console.log("");
printZcfSection({
uninstallOption: i18n.t("menu:menuOptions.codexUninstall"),
uninstallDescription: i18n.t("menu:menuDescriptions.codexUninstall"),
updateOption: i18n.t("menu:menuOptions.codexCheckUpdates"),
updateDescription: i18n.t("menu:menuDescriptions.codexCheckUpdates")
});
const { choice } = await inquirer.prompt({
type: "input",
name: "choice",
message: i18n.t("common:enterChoice"),
validate: (value) => {
const valid = ["1", "2", "3", "4", "5", "6", "0", "-", "+", "s", "S", "q", "Q"];
return valid.includes(value) || i18n.t("common:invalidChoice");
}
});
if (!choice) {
console.log(ansis.yellow(i18n.t("common:cancelled")));
return "exit";
}
const normalized = choice.toLowerCase();
switch (normalized) {
case "1":
await runCodexFullInit();
break;
case "2":
await runCodexWorkflowImportWithLanguageSelection();
break;
case "3":
await configureCodexApi();
break;
case "4":
await configureCodexMcp();
break;
case "5":
await configureCodexDefaultModelFeature();
bre