UNPKG

zcf

Version:

Zero-Config Claude-Code Flow - One-click configuration tool for Claude Code

1,230 lines (1,216 loc) 47.7 kB
#!/usr/bin/env node import cac from 'cac'; import ansis from 'ansis'; import { I as I18N, J as readCcrConfig, K as isCcrInstalled, N as installCcr, O as configureCcrFeature, P as handleExitPromptError, Q as handleGeneralError, R as getTranslation, Z as ZCF_CONFIG_FILE, h as SUPPORTED_LANGS, T as addNumbersToChoices, j as LANG_LABELS, U as updateZcfConfig, o as openSettingsJson, d as importRecommendedPermissions, b as importRecommendedEnv, V as readZcfConfig, v as applyAiLanguageDirective, W as configureAiPersonality, s as getExistingModelConfig, u as updateDefaultModel, X as isWindows, z as readMcpConfig, G as fixWindowsMcpConfig, B as writeMcpConfig, Y as selectMcpServices, D as backupMcpConfig, M as MCP_SERVICES, F as buildMcpServerConfig, E as mergeMcpServers, t as getExistingApiConfig, _ as formatApiKeyDisplay, H as addCompletedOnboarding, $ as modifyApiConfigPartially, a0 as setupCcrConfiguration, a1 as validateApiKey, p as configureApi, a2 as readZcfConfigAsync, a3 as COMETIX_COMMAND_NAME, a4 as COMETIX_COMMANDS, a5 as installCometixLine, a6 as selectScriptLanguage, a7 as checkAndUpdateTools, a8 as displayBanner, a9 as resolveAiOutputLanguage, aa as updatePromptOnly, ab as selectAndInstallWorkflows, ac as version, ad as displayBannerWithInfo, i as init } from './chunks/simple-config.mjs'; import { existsSync, unlinkSync } from 'node:fs'; import { homedir } from 'node:os'; import { join } from 'node:path'; import inquirer from 'inquirer'; import { exec, spawn } from 'node:child_process'; import { promisify } from 'node:util'; import process from 'node:process'; import { x } from 'tinyexec'; import 'pathe'; import 'dayjs'; import 'node:url'; import 'ora'; import 'semver'; import 'node:fs/promises'; const execAsync$1 = promisify(exec); async function runCcrUi(scriptLang, apiKey) { const i18n = I18N[scriptLang]; console.log(ansis.cyan(` \u{1F5A5}\uFE0F ${i18n.ccr.startingCcrUi}`)); if (apiKey) { console.log(ansis.bold.green(` \u{1F511} ${i18n.ccr.ccrUiApiKey || "CCR UI API Key"}: ${apiKey}`)); console.log(ansis.gray(` ${i18n.ccr.ccrUiApiKeyHint || "Use this API key to login to CCR UI"} `)); } try { const { stdout, stderr } = await execAsync$1("ccr ui"); if (stdout) console.log(stdout); if (stderr) console.error(ansis.yellow(stderr)); console.log(ansis.green(`\u2714 ${i18n.ccr.ccrUiStarted}`)); } catch (error) { console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`)); throw error; } } async function runCcrStatus(scriptLang) { const i18n = I18N[scriptLang]; console.log(ansis.cyan(` \u{1F4CA} ${i18n.ccr.checkingCcrStatus}`)); try { const { stdout, stderr } = await execAsync$1("ccr status"); if (stdout) { console.log(` ${ansis.bold(i18n.ccr.ccrStatusTitle)}`); console.log(stdout); } if (stderr) console.error(ansis.yellow(stderr)); } catch (error) { console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`)); throw error; } } async function runCcrRestart(scriptLang) { const i18n = I18N[scriptLang]; console.log(ansis.cyan(` \u{1F504} ${i18n.ccr.restartingCcr}`)); try { const { stdout, stderr } = await execAsync$1("ccr restart"); if (stdout) console.log(stdout); if (stderr) console.error(ansis.yellow(stderr)); console.log(ansis.green(`\u2714 ${i18n.ccr.ccrRestarted}`)); } catch (error) { console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`)); throw error; } } async function runCcrStart(scriptLang) { const i18n = I18N[scriptLang]; console.log(ansis.cyan(` \u25B6\uFE0F ${i18n.ccr.startingCcr}`)); try { const { stdout, stderr } = await execAsync$1("ccr start"); if (stdout) console.log(stdout); if (stderr) console.error(ansis.yellow(stderr)); console.log(ansis.green(`\u2714 ${i18n.ccr.ccrStarted}`)); } catch (error) { if (error.stdout && error.stdout.includes("Loaded JSON config from:")) { console.log(error.stdout); if (error.stderr) console.error(ansis.yellow(error.stderr)); console.log(ansis.green(`\u2714 ${i18n.ccr.ccrStarted}`)); } else { console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`)); throw error; } } } async function runCcrStop(scriptLang) { const i18n = I18N[scriptLang]; console.log(ansis.cyan(` \u23F9\uFE0F ${i18n.ccr.stoppingCcr}`)); try { const { stdout, stderr } = await execAsync$1("ccr stop"); if (stdout) console.log(stdout); if (stderr) console.error(ansis.yellow(stderr)); console.log(ansis.green(`\u2714 ${i18n.ccr.ccrStopped}`)); } catch (error) { console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`)); throw error; } } 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 && config.Providers && config.Providers.length > 0; } async function showCcrMenu(scriptLang) { try { const i18n = I18N[scriptLang]; console.log(` ${ansis.cyan("\u2550".repeat(50))}`); console.log(ansis.bold.cyan(` ${i18n.ccr.ccrMenuTitle}`)); console.log(`${ansis.cyan("\u2550".repeat(50))} `); console.log(` ${ansis.cyan("1.")} ${i18n.ccr.ccrMenuOptions.initCcr} ${ansis.gray(`- ${i18n.ccr.ccrMenuDescriptions.initCcr}`)}`); console.log(` ${ansis.cyan("2.")} ${i18n.ccr.ccrMenuOptions.startUi} ${ansis.gray(`- ${i18n.ccr.ccrMenuDescriptions.startUi}`)}`); console.log(` ${ansis.cyan("3.")} ${i18n.ccr.ccrMenuOptions.checkStatus} ${ansis.gray(`- ${i18n.ccr.ccrMenuDescriptions.checkStatus}`)}`); console.log(` ${ansis.cyan("4.")} ${i18n.ccr.ccrMenuOptions.restart} ${ansis.gray(`- ${i18n.ccr.ccrMenuDescriptions.restart}`)}`); console.log(` ${ansis.cyan("5.")} ${i18n.ccr.ccrMenuOptions.start} ${ansis.gray(`- ${i18n.ccr.ccrMenuDescriptions.start}`)}`); console.log(` ${ansis.cyan("6.")} ${i18n.ccr.ccrMenuOptions.stop} ${ansis.gray(`- ${i18n.ccr.ccrMenuDescriptions.stop}`)}`); console.log(` ${ansis.yellow("0.")} ${i18n.ccr.ccrMenuOptions.back}`); console.log(""); const { choice } = await inquirer.prompt({ type: "input", name: "choice", message: i18n.common.enterChoice, validate: (value) => { const valid = ["1", "2", "3", "4", "5", "6", "0"]; return valid.includes(value) || i18n.common.invalidChoice; } }); switch (choice) { case "1": { const ccrStatus = await isCcrInstalled(); if (!ccrStatus.hasCorrectPackage) { await installCcr(scriptLang); } else { console.log(ansis.green(`\u2714 ${i18n.ccr.ccrAlreadyInstalled}`)); } await configureCcrFeature(scriptLang); console.log(ansis.green(` \u2714 ${i18n.ccr.ccrSetupComplete}`)); break; } case "2": if (!isCcrConfigured()) { console.log(ansis.yellow(` \u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`)); console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."} `)); } else { const config = readCcrConfig(); await runCcrUi(scriptLang, config?.APIKEY); } break; case "3": if (!isCcrConfigured()) { console.log(ansis.yellow(` \u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`)); console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."} `)); } else { await runCcrStatus(scriptLang); } break; case "4": if (!isCcrConfigured()) { console.log(ansis.yellow(` \u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`)); console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."} `)); } else { await runCcrRestart(scriptLang); } break; case "5": if (!isCcrConfigured()) { console.log(ansis.yellow(` \u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`)); console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."} `)); } else { await runCcrStart(scriptLang); } break; case "6": if (!isCcrConfigured()) { console.log(ansis.yellow(` \u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`)); console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."} `)); } else { await runCcrStop(scriptLang); } break; case "0": return false; } if (choice !== "0") { console.log(` ${ansis.dim("\u2500".repeat(50))} `); const { continueInCcr } = await inquirer.prompt({ type: "confirm", name: "continueInCcr", message: i18n.common.returnToMenu || "Return to CCR menu?", default: true }); if (continueInCcr) { return await showCcrMenu(scriptLang); } } return false; } catch (error) { if (!handleExitPromptError(error)) { handleGeneralError(error, scriptLang); } return false; } } function handleCancellation(scriptLang) { const i18n = getTranslation(scriptLang); console.log(ansis.yellow(i18n.common.cancelled)); } async function configureApiFeature(scriptLang) { const i18n = getTranslation(scriptLang); const existingApiConfig = getExistingApiConfig(); if (existingApiConfig) { console.log(` ${ansis.blue(`\u2139 ${i18n.api.existingApiConfig}`)}`); console.log(ansis.gray(` ${i18n.api.apiConfigUrl}: ${existingApiConfig.url || i18n.common.notConfigured}`)); console.log( ansis.gray( ` ${i18n.api.apiConfigKey}: ${existingApiConfig.key ? formatApiKeyDisplay(existingApiConfig.key) : i18n.common.notConfigured}` ) ); console.log( ansis.gray(` ${i18n.api.apiConfigAuthType}: ${existingApiConfig.authType || i18n.common.notConfigured} `) ); const { action } = await inquirer.prompt({ type: "list", name: "action", message: i18n.api.selectApiAction, choices: addNumbersToChoices([ { name: i18n.api.keepExistingConfig, value: "keep" }, { name: i18n.api.modifyAllConfig, value: "modify-all" }, { name: i18n.api.modifyPartialConfig, value: "modify-partial" }, { name: i18n.api.useCcrProxy, value: "use-ccr" } ]) }); if (!action) { handleCancellation(scriptLang); return; } if (action === "keep") { console.log(ansis.green(`\u2714 ${i18n.api.keepExistingConfig}`)); try { addCompletedOnboarding(); } catch (error) { console.error(ansis.red(i18n.configuration.failedToSetOnboarding), error); } return; } else if (action === "modify-partial") { await modifyApiConfigPartially(existingApiConfig, i18n, scriptLang); return; } else if (action === "use-ccr") { const ccrStatus = await isCcrInstalled(); if (!ccrStatus.hasCorrectPackage) { await installCcr(scriptLang); } else { console.log(ansis.green(`\u2714 ${i18n.ccr.ccrAlreadyInstalled}`)); } const ccrConfigured = await setupCcrConfiguration(scriptLang); if (ccrConfigured) { console.log(ansis.green(`\u2714 ${i18n.ccr.ccrSetupComplete}`)); } return; } } const { apiChoice } = await inquirer.prompt({ type: "list", name: "apiChoice", message: i18n.api.configureApi, choices: addNumbersToChoices([ { name: `${i18n.api.useAuthToken} - ${ansis.gray(i18n.api.authTokenDesc)}`, value: "auth_token", short: i18n.api.useAuthToken }, { name: `${i18n.api.useApiKey} - ${ansis.gray(i18n.api.apiKeyDesc)}`, value: "api_key", short: i18n.api.useApiKey }, { name: `${i18n.api.useCcrProxy} - ${ansis.gray(i18n.api.ccrProxyDesc)}`, value: "ccr_proxy", short: i18n.api.useCcrProxy }, { name: i18n.api.skipApi, value: "skip" } ]) }); if (!apiChoice || apiChoice === "skip") { return; } if (apiChoice === "ccr_proxy") { const ccrStatus = await isCcrInstalled(); if (!ccrStatus.hasCorrectPackage) { await installCcr(scriptLang); } else { console.log(ansis.green(`\u2714 ${i18n.ccr.ccrAlreadyInstalled}`)); } const ccrConfigured = await setupCcrConfiguration(scriptLang); if (ccrConfigured) { console.log(ansis.green(`\u2714 ${i18n.ccr.ccrSetupComplete}`)); } return; } const { url } = await inquirer.prompt({ type: "input", name: "url", message: i18n.api.enterApiUrl, validate: (value) => { if (!value) return i18n.api.urlRequired; try { void new URL(value); return true; } catch { return i18n.api.invalidUrl; } } }); if (!url) { handleCancellation(scriptLang); return; } const keyMessage = apiChoice === "auth_token" ? i18n.api.enterAuthToken : i18n.api.enterApiKey; const { key } = await inquirer.prompt({ type: "input", name: "key", message: keyMessage, validate: (value) => { if (!value) { return i18n.api.keyRequired; } const validation = validateApiKey(value, scriptLang); if (!validation.isValid) { return validation.error || i18n.api.invalidKeyFormat; } return true; } }); if (!key) { handleCancellation(scriptLang); return; } const apiConfig = { url, key, authType: apiChoice }; const configuredApi = configureApi(apiConfig); if (configuredApi) { console.log(ansis.green(`\u2714 ${i18n.api.apiConfigSuccess}`)); console.log(ansis.gray(` URL: ${configuredApi.url}`)); console.log(ansis.gray(` Key: ${formatApiKeyDisplay(configuredApi.key)}`)); } } async function configureMcpFeature(scriptLang) { const i18n = getTranslation(scriptLang); if (isWindows()) { const { fixWindows } = await inquirer.prompt({ type: "confirm", name: "fixWindows", message: i18n.configuration.fixWindowsMcp || "Fix Windows MCP configuration?", default: true }); if (fixWindows) { const existingConfig = readMcpConfig() || { mcpServers: {} }; const fixedConfig = fixWindowsMcpConfig(existingConfig); writeMcpConfig(fixedConfig); console.log(ansis.green(`\u2714 Windows MCP configuration fixed`)); } } const selectedServices = await selectMcpServices(scriptLang); if (!selectedServices) { return; } if (selectedServices.length > 0) { const mcpBackupPath = backupMcpConfig(); if (mcpBackupPath) { console.log(ansis.gray(`\u2714 ${i18n.mcp.mcpBackupSuccess}: ${mcpBackupPath}`)); } const newServers = {}; for (const serviceId of selectedServices) { const service = MCP_SERVICES.find((s) => s.id === serviceId); if (!service) continue; let config = service.config; if (service.requiresApiKey) { const { apiKey } = await inquirer.prompt({ type: "input", name: "apiKey", message: service.apiKeyPrompt[scriptLang], validate: (value) => !!value || i18n.api.keyRequired }); if (apiKey) { config = buildMcpServerConfig(service.config, apiKey, service.apiKeyPlaceholder, service.apiKeyEnvVar); } else { continue; } } newServers[service.id] = config; } const existingConfig = readMcpConfig(); let mergedConfig = mergeMcpServers(existingConfig, newServers); mergedConfig = fixWindowsMcpConfig(mergedConfig); writeMcpConfig(mergedConfig); console.log(ansis.green(`\u2714 ${i18n.mcp.mcpConfigSuccess}`)); } } async function configureDefaultModelFeature(scriptLang) { const i18n = getTranslation(scriptLang); const existingModel = getExistingModelConfig(); if (existingModel) { console.log(` ${ansis.blue(`\u2139 ${i18n.configuration.existingModelConfig || "Existing model configuration"}`)}`); const modelDisplay = existingModel === "default" ? i18n.configuration.defaultModelOption || "Default (Let Claude Code choose)" : existingModel.charAt(0).toUpperCase() + existingModel.slice(1); console.log(ansis.gray(` ${i18n.configuration.currentModel || "Current model"}: ${modelDisplay} `)); const { modify } = await inquirer.prompt({ type: "confirm", name: "modify", message: i18n.configuration.modifyModel || "Modify model configuration?", default: false }); if (!modify) { console.log(ansis.green(`\u2714 ${i18n.configuration.keepModel || "Keeping existing model configuration"}`)); return; } } const { model } = await inquirer.prompt({ type: "list", name: "model", message: i18n.configuration.selectDefaultModel || "Select default model", choices: addNumbersToChoices([ { name: i18n.configuration.defaultModelOption || "Default - Let Claude Code choose", value: "default" }, { name: i18n.configuration.opusModelOption || "Opus - Only use opus, high token consumption, use with caution", value: "opus" }, { name: i18n.configuration.opusPlanModelOption || "OpusPlan - Use Opus for planning, write code with sonnet, recommended", value: "opusplan" } ]), default: existingModel ? ["default", "opus", "opusplan"].indexOf(existingModel) : 0 }); if (!model) { handleCancellation(scriptLang); return; } updateDefaultModel(model); console.log(ansis.green(`\u2714 ${i18n.configuration.modelConfigured || "Default model configured"}`)); } async function configureAiMemoryFeature(scriptLang) { const i18n = getTranslation(scriptLang); const { option } = await inquirer.prompt({ type: "list", name: "option", message: i18n.configuration.selectMemoryOption || "Select configuration option", choices: addNumbersToChoices([ { name: i18n.configuration.configureAiLanguage || "Configure AI output language", value: "language" }, { name: i18n.configuration.configureAiPersonality || "Configure AI personality", value: "personality" } ]) }); if (!option) { return; } if (option === "language") { const zcfConfig = readZcfConfig(); const existingLang = zcfConfig?.aiOutputLang; if (existingLang) { console.log( ` ${ansis.blue(`\u2139 ${i18n.configuration.existingLanguageConfig || "Existing AI output language configuration"}`)}` ); console.log(ansis.gray(` ${i18n.configuration.currentLanguage || "Current language"}: ${existingLang} `)); const { modify } = await inquirer.prompt({ type: "confirm", name: "modify", message: i18n.configuration.modifyLanguage || "Modify AI output language?", default: false }); if (!modify) { console.log(ansis.green(`\u2714 ${i18n.configuration.keepLanguage || "Keeping existing language configuration"}`)); return; } } const { selectAiOutputLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.ae; }); const aiOutputLang = await selectAiOutputLanguage(scriptLang, scriptLang); applyAiLanguageDirective(aiOutputLang); updateZcfConfig({ aiOutputLang }); console.log(ansis.green(`\u2714 ${i18n.configuration.aiLanguageConfigured || "AI output language configured"}`)); } else { await configureAiPersonality(scriptLang); } } async function clearZcfCacheFeature(scriptLang) { const i18n = getTranslation(scriptLang); const { confirm } = await inquirer.prompt({ type: "confirm", name: "confirm", message: i18n.configuration.confirmClearCache || "Clear all ZCF preferences cache?", default: false }); if (!confirm) { handleCancellation(scriptLang); return; } if (existsSync(ZCF_CONFIG_FILE)) { unlinkSync(ZCF_CONFIG_FILE); console.log(ansis.green(`\u2714 ${i18n.configuration.cacheCleared || "ZCF cache cleared"}`)); } else { console.log(ansis.yellow("No cache found")); } } async function changeScriptLanguageFeature(currentLang) { const i18n = getTranslation(currentLang); const { lang } = await inquirer.prompt({ type: "list", name: "lang", message: i18n.language.selectScriptLang, choices: addNumbersToChoices( SUPPORTED_LANGS.map((l) => ({ name: LANG_LABELS[l], value: l })) ), default: SUPPORTED_LANGS.indexOf(currentLang) }); if (!lang) { return currentLang; } updateZcfConfig({ preferredLang: lang }); const newI18n = getTranslation(lang); console.log(ansis.green(`\u2714 ${newI18n.language.languageChanged || "Language changed"}`)); return lang; } async function configureEnvPermissionFeature(scriptLang) { const i18n = getTranslation(scriptLang); const { choice } = await inquirer.prompt({ type: "list", name: "choice", message: i18n.configuration?.selectEnvPermissionOption || "Select option", choices: addNumbersToChoices([ { name: `${i18n.configuration?.importRecommendedEnv || "Import environment"} ${ansis.gray( `- ${i18n.configuration?.importRecommendedEnvDesc || "Import env settings"}` )}`, value: "env" }, { name: `${i18n.configuration?.importRecommendedPermissions || "Import permissions"} ${ansis.gray( `- ${i18n.configuration?.importRecommendedPermissionsDesc || "Import permission settings"}` )}`, value: "permissions" }, { name: `${i18n.configuration?.openSettingsJson || "Open settings"} ${ansis.gray( `- ${i18n.configuration?.openSettingsJsonDesc || "View settings file"}` )}`, value: "open" } ]) }); if (!choice) { handleCancellation(scriptLang); return; } try { switch (choice) { case "env": await importRecommendedEnv(); console.log(ansis.green(`\u2705 ${i18n.configuration.envImportSuccess}`)); break; case "permissions": await importRecommendedPermissions(); console.log(ansis.green(`\u2705 ${i18n.configuration?.permissionsImportSuccess || "Permissions imported"}`)); break; case "open": console.log(ansis.cyan(i18n.configuration?.openingSettingsJson || "Opening settings.json...")); await openSettingsJson(); break; } } catch (error) { console.error(ansis.red(`${i18n.common.error}: ${error.message}`)); } } async function executeCcusage(args = []) { try { let lang = "en"; try { const zcfConfig = await readZcfConfigAsync(); const rawLang = zcfConfig?.preferredLang || "en"; lang = getValidLanguage(rawLang); } catch { lang = "en"; } const i18n = I18N[lang]; const command = "npx"; const commandArgs = ["ccusage@latest", ...args || []]; console.log(ansis.cyan(i18n.tools.runningCcusage)); console.log(ansis.gray(`$ npx ccusage@latest ${(args || []).join(" ")}`)); console.log(""); await x(command, commandArgs, { nodeOptions: { stdio: "inherit" } }); } catch (error) { let lang = "en"; try { const zcfConfig = await readZcfConfigAsync(); const rawLang = zcfConfig?.preferredLang || "en"; lang = getValidLanguage(rawLang); } catch { lang = "en"; } const i18n = I18N[lang]; console.error(ansis.red(i18n.tools.ccusageFailed)); console.error(ansis.yellow(i18n.tools.checkNetworkConnection)); if (process.env.DEBUG) { console.error(ansis.gray(i18n.tools.errorDetails), error); } if (process.env.NODE_ENV !== "test") { process.exit(1); } throw error; } } const execAsync = promisify(exec); async function runCometixPrintConfig(scriptLang) { const i18n = getTranslation(scriptLang); try { console.log(ansis.blue(`${i18n.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.cometix.commandNotFound}`)); } else { console.error(ansis.red(`\u2717 ${i18n.cometix.printConfigFailed}: ${error}`)); } throw error; } } async function runCometixTuiConfig(scriptLang) { const i18n = getTranslation(scriptLang); return new Promise((resolve, reject) => { console.log(ansis.blue(`${i18n.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.cometix.tuiConfigSuccess}`)); resolve(); } else { const error = new Error(`${COMETIX_COMMAND_NAME} -c exited with code ${code}`); console.error(ansis.red(`\u2717 ${i18n.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.cometix.commandNotFound}`)); } else { console.error(ansis.red(`\u2717 ${i18n.cometix.tuiConfigFailed}: ${error.message}`)); } reject(error); }); }); } async function showCometixMenu(scriptLang) { try { const i18n = getTranslation(scriptLang); console.log(` ${ansis.cyan("\u2550".repeat(50))}`); console.log(ansis.bold.cyan(` ${i18n.cometix.cometixMenuTitle}`)); console.log(`${ansis.cyan("\u2550".repeat(50))} `); console.log(` ${ansis.cyan("1.")} ${i18n.cometix.cometixMenuOptions.installOrUpdate} ${ansis.gray(`- ${i18n.cometix.cometixMenuDescriptions.installOrUpdate}`)}`); console.log(` ${ansis.cyan("2.")} ${i18n.cometix.cometixMenuOptions.printConfig} ${ansis.gray(`- ${i18n.cometix.cometixMenuDescriptions.printConfig}`)}`); console.log(` ${ansis.cyan("3.")} ${i18n.cometix.cometixMenuOptions.customConfig} ${ansis.gray(`- ${i18n.cometix.cometixMenuDescriptions.customConfig}`)}`); console.log(` ${ansis.yellow("0.")} ${i18n.cometix.cometixMenuOptions.back}`); console.log(""); const { choice } = await inquirer.prompt({ type: "input", name: "choice", message: i18n.common.enterChoice, validate: (value) => { const valid = ["1", "2", "3", "0"]; return valid.includes(value) || i18n.common.invalidChoice; } }); switch (choice) { case "1": await installCometixLine(scriptLang); break; case "2": await runCometixPrintConfig(scriptLang); break; case "3": await runCometixTuiConfig(scriptLang); break; case "0": return false; } if (choice !== "0") { console.log(` ${ansis.dim("\u2500".repeat(50))} `); const { continueInCometix } = await inquirer.prompt({ type: "confirm", name: "continueInCometix", message: i18n.common.returnToMenu, default: true }); if (continueInCometix) { return await showCometixMenu(scriptLang); } } return false; } catch (error) { if (!handleExitPromptError(error)) { handleGeneralError(error, scriptLang); } return false; } } function getValidLanguage(lang) { return lang && lang in I18N ? lang : "en"; } async function runCcusageFeature(scriptLang) { const validLang = getValidLanguage(scriptLang); const i18n = getTranslation(validLang); console.log(""); console.log(ansis.cyan(i18n.menu.menuOptions.ccusage)); console.log(ansis.gray(`${i18n.tools.ccusageDescription}`)); console.log(""); const choices = [ { name: i18n.tools.ccusageModes.daily, value: "daily" }, { name: i18n.tools.ccusageModes.monthly, value: "monthly" }, { name: i18n.tools.ccusageModes.session, value: "session" }, { name: i18n.tools.ccusageModes.blocks, value: "blocks" }, { name: i18n.tools.ccusageModes.custom, value: "custom" }, { name: i18n.common.back, value: "back" } ]; const { mode } = await inquirer.prompt({ type: "list", name: "mode", message: i18n.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.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.tools.pressEnterToContinue) }); } async function runCcrMenuFeature(scriptLang) { const validLang = getValidLanguage(scriptLang); await showCcrMenu(validLang); } async function runCometixMenuFeature(scriptLang) { const validLang = getValidLanguage(scriptLang); await showCometixMenu(validLang); } async function checkUpdates(options = {}) { const scriptLang = options.lang || await selectScriptLanguage(); try { await checkAndUpdateTools(scriptLang); } catch (error) { console.error(ansis.red("Error checking updates:"), error); process.exit(1); } } async function update(options = {}) { try { if (!options.skipBanner) { displayBanner("Update configuration for Claude Code"); } const scriptLang = await selectScriptLanguage(); const zcfConfig = readZcfConfig(); const i18n = I18N[scriptLang]; let configLang = options.configLang; if (!configLang) { const { lang } = await inquirer.prompt({ type: "list", name: "lang", message: i18n.language.updateConfigLangPrompt, choices: addNumbersToChoices(SUPPORTED_LANGS.map((l) => ({ name: `${LANG_LABELS[l]} - ${i18n.language.configLangHint[l]}`, value: l }))) }); if (!lang) { console.log(ansis.yellow(i18n.common.cancelled)); process.exit(0); } configLang = lang; } const aiOutputLang = await resolveAiOutputLanguage(scriptLang, options.aiOutputLang, zcfConfig); console.log(ansis.cyan(` ${i18n.configuration.updatingPrompts} `)); await updatePromptOnly(configLang, scriptLang, aiOutputLang); await selectAndInstallWorkflows(configLang, scriptLang); updateZcfConfig({ version, preferredLang: scriptLang, aiOutputLang }); } catch (error) { if (!handleExitPromptError(error)) { handleGeneralError(error); } } } async function showMainMenu() { try { displayBannerWithInfo(); const zcfConfig = await readZcfConfigAsync(); let scriptLang = zcfConfig?.preferredLang || await selectScriptLanguage(); let exitMenu = false; while (!exitMenu) { const i18n = I18N[scriptLang]; console.log(ansis.cyan(i18n.menu.selectFunction)); console.log(" -------- Claude Code --------"); console.log( ` ${ansis.cyan("1.")} ${i18n.menu.menuOptions.fullInit} ${ansis.gray(`- ${i18n.menu.menuDescriptions.fullInit}`)}` ); console.log( ` ${ansis.cyan("2.")} ${i18n.menu.menuOptions.importWorkflow} ${ansis.gray( `- ${i18n.menu.menuDescriptions.importWorkflow}` )}` ); console.log( ` ${ansis.cyan("3.")} ${i18n.menu.menuOptions.configureApiOrCcr} ${ansis.gray( `- ${i18n.menu.menuDescriptions.configureApiOrCcr}` )}` ); console.log( ` ${ansis.cyan("4.")} ${i18n.menu.menuOptions.configureMcp} ${ansis.gray( `- ${i18n.menu.menuDescriptions.configureMcp}` )}` ); console.log( ` ${ansis.cyan("5.")} ${i18n.menu.menuOptions.configureModel} ${ansis.gray( `- ${i18n.menu.menuDescriptions.configureModel}` )}` ); console.log( ` ${ansis.cyan("6.")} ${i18n.menu.menuOptions.configureAiMemory} ${ansis.gray( `- ${i18n.menu.menuDescriptions.configureAiMemory}` )}` ); console.log( ` ${ansis.cyan("7.")} ${i18n.menu.menuOptions.configureEnvPermission} ${ansis.gray( `- ${i18n.menu.menuDescriptions.configureEnvPermission}` )}` ); console.log(""); console.log(` --------- ${i18n.menu.menuSections.otherTools} ----------`); console.log( ` ${ansis.cyan("R.")} ${i18n.menu.menuOptions.ccrManagement} ${ansis.gray(`- ${i18n.menu.menuDescriptions.ccrManagement}`)}` ); console.log( ` ${ansis.cyan("U.")} ${i18n.menu.menuOptions.ccusage} ${ansis.gray(`- ${i18n.menu.menuDescriptions.ccusage}`)}` ); console.log( ` ${ansis.cyan("L.")} ${i18n.menu.menuOptions.cometixLine} ${ansis.gray(`- ${i18n.menu.menuDescriptions.cometixLine}`)}` ); console.log(""); console.log(" ------------ ZCF ------------"); console.log( ` ${ansis.cyan("0.")} ${i18n.menu.menuOptions.changeLanguage} ${ansis.gray( `- ${i18n.menu.menuDescriptions.changeLanguage}` )}` ); console.log( ` ${ansis.cyan("-.")} ${i18n.menu.menuOptions.clearCache} ${ansis.gray(`- ${i18n.menu.menuDescriptions.clearCache}`)}` ); console.log( ` ${ansis.cyan("+.")} ${i18n.menu.menuOptions.checkUpdates} ${ansis.gray(`- ${i18n.menu.menuDescriptions.checkUpdates}`)}` ); console.log(` ${ansis.red("Q.")} ${ansis.red(i18n.menu.menuOptions.exit)}`); console.log(""); const { choice } = await inquirer.prompt({ type: "input", name: "choice", message: i18n.common.enterChoice, validate: (value) => { const valid = ["1", "2", "3", "4", "5", "6", "7", "r", "R", "u", "U", "l", "L", "0", "-", "+", "q", "Q"]; return valid.includes(value) || i18n.common.invalidChoice; } }); if (!choice) { console.log(ansis.yellow(i18n.common.cancelled)); exitMenu = true; break; } switch (choice.toLowerCase()) { case "1": await init({ lang: scriptLang, skipBanner: true }); break; case "2": await update({ skipBanner: true }); break; case "3": await configureApiFeature(scriptLang); break; case "4": await configureMcpFeature(scriptLang); break; case "5": await configureDefaultModelFeature(scriptLang); break; case "6": await configureAiMemoryFeature(scriptLang); break; case "7": await configureEnvPermissionFeature(scriptLang); break; case "r": case "R": await runCcrMenuFeature(scriptLang); break; case "u": case "U": await runCcusageFeature(scriptLang); break; case "l": case "L": await runCometixMenuFeature(scriptLang); break; case "0": { const newLang = await changeScriptLanguageFeature(scriptLang); if (newLang !== scriptLang) { scriptLang = newLang; } break; } case "-": await clearZcfCacheFeature(scriptLang); break; case "+": await checkUpdates({ lang: scriptLang }); break; case "q": exitMenu = true; console.log(ansis.cyan(i18n.common.goodbye)); break; } if (!exitMenu && choice.toLowerCase() !== "q") { if (choice === "0" || choice === "-" || choice === "+" || choice.toLowerCase() === "u" || choice.toLowerCase() === "r" || choice.toLowerCase() === "l") { console.log(` ${ansis.dim("\u2500".repeat(50))} `); continue; } console.log(` ${ansis.dim("\u2500".repeat(50))} `); const { continue: shouldContinue } = await inquirer.prompt({ type: "confirm", name: "continue", message: i18n.common.returnToMenu, default: true }); if (!shouldContinue) { exitMenu = true; console.log(ansis.cyan(i18n.common.goodbye)); } } } } catch (error) { if (!handleExitPromptError(error)) { handleGeneralError(error); } } } async function ccr(options = {}) { try { if (!options.skipBanner) { displayBannerWithInfo(); } const zcfConfig = await readZcfConfigAsync(); const scriptLang = options.lang || zcfConfig?.preferredLang || await selectScriptLanguage(); const continueInCcr = await showCcrMenu(scriptLang); if (!continueInCcr && !options.skipBanner) { await showMainMenu(); } } catch (error) { if (!handleExitPromptError(error)) { handleGeneralError(error, options.lang); } } } function setupCommands(cli) { cli.command("[lang]", "Show interactive menu (default)").option("--init", "Run full initialization directly").option("--config-lang, -c <lang>", "Configuration language (zh-CN, en)").option("--force, -f", "Force overwrite existing configuration").action(async (lang, options) => { await handleDefaultCommand(lang, options); }); cli.command("init", "Initialize Claude Code configuration").alias("i").option("--lang, -l <lang>", "ZCF display language (zh-CN, en)").option("--config-lang, -c <lang>", "Configuration language (zh-CN, en)").option("--ai-output-lang, -a <lang>", "AI output language").option("--force, -f", "Force overwrite existing configuration").option("--skip-prompt, -s", "Skip all interactive prompts (non-interactive mode)").option("--config-action, -o <action>", "Config handling (new/backup/merge/docs-only/skip), default: backup").option("--api-type, -t <type>", "API type (auth_token/api_key/ccr_proxy/skip)").option("--api-key, -k <key>", "API key (used for both API key and auth token types)").option("--api-url, -u <url>", "Custom API URL").option("--mcp-services, -m <services>", 'Comma-separated MCP services to install (context7,mcp-deepwiki,Playwright,exa), "skip" to skip all, "all" for all non-key services, default: all').option("--workflows, -w <workflows>", 'Comma-separated workflows to install (sixStepsWorkflow,featPlanUx,gitWorkflow,bmadWorkflow), "skip" to skip all, "all" for all workflows, default: all').option("--ai-personality, -p <type>", "AI personality type (professional,catgirl,friendly,mentor,custom), default: professional").option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--install-cometix-line, -x <value>", "Install CCometixLine statusline tool (true/false), default: true").action(async (options) => { await handleInitCommand(options); }); cli.command("update", "Update Claude Code prompts only").alias("u").option("--config-lang, -c <lang>", "Configuration language (zh-CN, en)").action(async (options) => { await handleUpdateCommand(options); }); cli.command("ccr", "Configure Claude Code Router for model proxy").option("--lang, -l <lang>", "Display language (zh-CN, en)").action(async (options) => { await ccr({ lang: options.lang }); }); cli.command("ccu [...args]", "Run Claude Code usage analysis tool").allowUnknownOptions().action(async (args) => { await executeCcusage(args); }); cli.command("check-updates", "Check and update Claude Code and CCR to latest versions").alias("check").option("--lang, -l <lang>", "Display language (zh-CN, en)").action(async (options) => { await checkUpdates({ lang: options.lang }); }); cli.help((sections) => customizeHelp(sections)); cli.version(version); } async function handleDefaultCommand(lang, options) { if (options.init) { await init({ lang: lang || options.lang, configLang: options.configLang, force: options.force }); } else { await showMainMenu(); } } async function handleInitCommand(options) { await init({ lang: options.lang, configLang: options.configLang, aiOutputLang: options.aiOutputLang, force: options.force, skipPrompt: options.skipPrompt, configAction: options.configAction, apiType: options.apiType, apiKey: options.apiKey, apiUrl: options.apiUrl, mcpServices: options.mcpServices, workflows: options.workflows, aiPersonality: options.aiPersonality, allLang: options.allLang, installCometixLine: options.installCometixLine }); } async function handleUpdateCommand(options) { await update({ configLang: options.configLang }); } function customizeHelp(sections) { sections.unshift({ title: "", body: ansis.cyan.bold(`ZCF - Zero-Config Claude-Code Flow v${version}`) }); sections.push({ title: ansis.yellow("Commands / \u547D\u4EE4:"), body: [ ` ${ansis.cyan("zcf")} Show interactive menu (default) / \u663E\u793A\u4EA4\u4E92\u5F0F\u83DC\u5355\uFF08\u9ED8\u8BA4\uFF09`, ` ${ansis.cyan("zcf init")} | ${ansis.cyan( "i" )} Initialize Claude Code configuration / \u521D\u59CB\u5316 Claude Code \u914D\u7F6E`, ` ${ansis.cyan("zcf update")} | ${ansis.cyan("u")} Update workflow-related md files / \u4EC5\u66F4\u65B0\u5DE5\u4F5C\u6D41\u76F8\u5173md`, ` ${ansis.cyan("zcf ccr")} Configure Claude Code Router for model proxy / \u914D\u7F6E\u6A21\u578B\u8DEF\u7531\u4EE3\u7406`, ` ${ansis.cyan("zcf ccu")} [args] Claude Code usage statistics analysis / Claude Code \u7528\u91CF\u7EDF\u8BA1\u5206\u6790`, ` ${ansis.cyan("zcf check-updates")} Check and update to latest versions / \u68C0\u67E5\u5E76\u66F4\u65B0\u5230\u6700\u65B0\u7248\u672C`, "", ansis.gray(" Shortcuts / \u5FEB\u6377\u65B9\u5F0F:"), ` ${ansis.cyan("zcf i")} Quick init / \u5FEB\u901F\u521D\u59CB\u5316`, ` ${ansis.cyan("zcf u")} Quick update / \u5FEB\u901F\u66F4\u65B0`, ` ${ansis.cyan("zcf check")} Quick check updates / \u5FEB\u901F\u68C0\u67E5\u66F4\u65B0` ].join("\n") }); sections.push({ title: ansis.yellow("Options / \u9009\u9879:"), body: [ ` ${ansis.green("--init")} Run full initialization directly / \u76F4\u63A5\u8FD0\u884C\u5B8C\u6574\u521D\u59CB\u5316`, ` ${ansis.green("--config-lang, -c")} <lang> Configuration language / \u914D\u7F6E\u8BED\u8A00 (zh-CN, en)`, ` ${ansis.green("--force, -f")} Force overwrite / \u5F3A\u5236\u8986\u76D6\u73B0\u6709\u914D\u7F6E`, ` ${ansis.green("--help, -h")} Display help / \u663E\u793A\u5E2E\u52A9`, ` ${ansis.green("--version, -v")} Display version / \u663E\u793A\u7248\u672C`, "", ansis.gray(" Non-interactive mode (for CI/CD) / \u975E\u4EA4\u4E92\u6A21\u5F0F\uFF08\u9002\u7528\u4E8ECI/CD\uFF09:"), ` ${ansis.green("--skip-prompt, -s")} Skip all prompts / \u8DF3\u8FC7\u6240\u6709\u4EA4\u4E92\u63D0\u793A`, ` ${ansis.green("--api-type, -t")} <type> API type / API\u7C7B\u578B (auth_token, api_key, ccr_proxy, skip)`, ` ${ansis.green("--api-key, -k")} <key> API key (for both types) / API\u5BC6\u94A5\uFF08\u9002\u7528\u4E8E\u6240\u6709\u7C7B\u578B\uFF09`, ` ${ansis.green("--api-url, -u")} <url> Custom API URL / \u81EA\u5B9A\u4E49API\u5730\u5740`, ` ${ansis.green("--ai-output-lang, -a")} <lang> AI output language / AI\u8F93\u51FA\u8BED\u8A00`, ` ${ansis.green("--all-lang, -g")} <lang> Set all language params / \u7EDF\u4E00\u8BBE\u7F6E\u6240\u6709\u8BED\u8A00\u53C2\u6570`, ` ${ansis.green("--config-action, -o")} <action> Config handling / \u914D\u7F6E\u5904\u7406 (default: backup)`, ` ${ansis.green("--mcp-services, -m")} <list> MCP services / MCP\u670D\u52A1 (default: all non-key services)`, ` ${ansis.green("--workflows, -w")} <list> Workflows / \u5DE5\u4F5C\u6D41 (default: all workflows)`, ` ${ansis.green("--ai-personality, -p")} <type> AI personality / AI\u4E2A\u6027 (default: professional)`, ` ${ansis.green("--install-cometix-line, -x")} <value> Install statusline tool / \u5B89\u88C5\u72B6\u6001\u680F\u5DE5\u5177 (default: true)` ].join("\n") }); sections.push({ title: ansis.yellow("Examples / \u793A\u4F8B:"), body: [ ansis.gray(" # Show interactive menu / \u663E\u793A\u4EA4\u4E92\u5F0F\u83DC\u5355"), ` ${ansis.cyan("npx zcf")}`, "", ansis.gray(" # Run full initialization / \u8FD0\u884C\u5B8C\u6574\u521D\u59CB\u5316"), ` ${ansis.cyan("npx zcf init")}`, ` ${ansis.cyan("npx zcf i")}`, ` ${ansis.cyan("npx zcf --init")}`, "", ansis.gray(" # Update workflow-related md files only / \u4EC5\u66F4\u65B0\u5DE5\u4F5C\u6D41\u76F8\u5173md\u6587\u4EF6"), ` ${ansis.cyan("npx zcf u")}`, "", ansis.gray(" # Configure Claude Code Router / \u914D\u7F6E Claude Code Router"), ` ${ansis.cyan("npx zcf ccr")}`, "", ansis.gray(" # Run Claude Code usage analysis / \u8FD0\u884C Claude Code \u7528\u91CF\u5206\u6790"), ` ${ansis.cyan("npx zcf ccu")} ${ansis.gray("# Daily usage (default)")}`, ` ${ansis.cyan("npx zcf ccu monthly --json")}`, "", ansis.gray(" # Check and update tools / \u68C0\u67E5\u5E76\u66F4\u65B0\u5DE5\u5177"), ` ${ansis.cyan("npx zcf check-updates")} ${ansis.gray("# Update Claude Code, CCR and CCometixLine")}`, ` ${ansis.cyan("npx zcf check")}`, "", ansis.gray(" # Non-interactive mode (CI/CD) / \u975E\u4EA4\u4E92\u6A21\u5F0F\uFF08CI/CD\uFF09"), ` ${ansis.cyan('npx zcf i --skip-prompt --api-type api_key --api-key "sk-ant-..."')}`, ` ${ansis.cyan('npx zcf i --skip-prompt --all-lang zh-CN --api-type api_key --api-key "key"')}`, ` ${ansis.cyan("npx zcf i --skip-prompt --api-type ccr_proxy")}`, "", ansis.gray(" # Force overwrite with Chinese config / \u5F3A\u5236\u4F7F\u7528\u4E2D\u6587\u914D\u7F6E\u8986\u76D6"), ` ${ansis.cyan("npx zcf --init -c zh-CN -f")}`, ` ${ansis.cyan("npx zcf --init --config-lang zh-CN --force")}` ].join("\n") }); return sections; } async function main() { const cli = cac("zcf"); setupCommands(cli); cli.parse(); } main().catch(console.error);