UNPKG

accf

Version:

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

1,409 lines (1,399 loc) 92.4 kB
#!/usr/bin/env node import cac from 'cac'; import ansis from 'ansis'; import { a5 as ensureI18nInitialized, a0 as i18n, a8 as readCcrConfig, a9 as isCcrInstalled, aa as installCcr, ab as configureCcrFeature, ac as handleExitPromptError, ad as handleGeneralError, p as SUPPORTED_LANGS, a7 as addNumbersToChoices, q as LANG_LABELS, ae as updateZcfConfig, af as changeLanguage, ag as readZcfConfig, o as openSettingsJson, d as importRecommendedPermissions, b as importRecommendedEnv, T as applyAiLanguageDirective, ah as configureOutputStyle, Q as getExistingModelConfig, N as updateCustomModel, O as updateDefaultModel, ai as isWindows, t as readMcpConfig, y as fixWindowsMcpConfig, w as writeMcpConfig, aj as selectMcpServices, u as backupMcpConfig, ak as getMcpServices, x as buildMcpServerConfig, v as mergeMcpServers, al as setupCcrConfiguration, R as getExistingApiConfig, V as promptApiConfigurationAction, am as modifyApiConfigPartially, an as validateApiKey, K as configureApi, ao as formatApiKeyDisplay, U as switchToOfficialLogin, ap as COMETIX_COMMAND_NAME, aq as COMETIX_COMMANDS, ar as installCometixLine, as as checkAndUpdateTools, at as runCodexUpdate, au as resolveCodeType, av as readJsonConfig, aw as writeJsonConfig, j as ZCF_CONFIG_FILE, ax as displayBanner, ay as version, az as resolveAiOutputLanguage, aA as updatePromptOnly, aB as selectAndInstallWorkflows, aC as checkClaudeCodeVersionAndPrompt, n as isCodeToolType, D as DEFAULT_CODE_TOOL_TYPE, aD as displayBannerWithInfo, l as CODE_TOOL_BANNERS, aE as runCodexUninstall, aF as configureCodexMcp, aG as configureCodexApi, aH as runCodexWorkflowImport, aI as runCodexFullInit, i as init, aJ as listCodexProviders, aK as getCurrentCodexProvider, aL as switchCodexProvider, a1 as readCodexConfig, aM as switchToOfficialLogin$1, aN as switchToProvider, aO as readZcfConfigAsync, aP as initI18n, aQ as selectScriptLanguage } from './chunks/simple-config.mjs'; import { existsSync } from 'node:fs'; import { homedir } from 'node:os'; import inquirer from 'inquirer'; import { join } from 'pathe'; import { exec, spawn } from 'node:child_process'; import { promisify } from 'node:util'; import process from 'node:process'; import { x, exec as exec$1 } from 'tinyexec'; import { pathExists } from 'fs-extra'; import { m as moveToTrash } from './shared/accf.DGjQxTq_.mjs'; import 'dayjs'; import 'node:url'; import 'ora'; import 'semver'; import 'smol-toml'; import 'node:fs/promises'; import 'i18next'; import 'i18next-fs-backend'; import 'trash'; const execAsync$1 = promisify(exec); async function runCcrUi(apiKey) { ensureI18nInitialized(); console.log(ansis.cyan(` \u{1F5A5}\uFE0F ${i18n.t("ccr:startingCcrUi")}`)); if (apiKey) { console.log(ansis.bold.green(` \u{1F511} ${i18n.t("ccr:ccrUiApiKey") || "CCR UI API Key"}: ${apiKey}`)); console.log(ansis.gray(` ${i18n.t("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.t("ccr:ccrUiStarted")}`)); } catch (error) { console.error(ansis.red(`\u2716 ${i18n.t("ccr:ccrCommandFailed")}: ${error instanceof Error ? error.message : String(error)}`)); throw error; } } async function runCcrStatus() { ensureI18nInitialized(); console.log(ansis.cyan(` \u{1F4CA} ${i18n.t("ccr:checkingCcrStatus")}`)); try { const { stdout, stderr } = await execAsync$1("ccr status"); if (stdout) { console.log(` ${ansis.bold(i18n.t("ccr:ccrStatusTitle"))}`); console.log(stdout); } if (stderr) console.error(ansis.yellow(stderr)); } catch (error) { console.error(ansis.red(`\u2716 ${i18n.t("ccr:ccrCommandFailed")}: ${error instanceof Error ? error.message : String(error)}`)); throw error; } } async function runCcrRestart() { ensureI18nInitialized(); console.log(ansis.cyan(` \u{1F504} ${i18n.t("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.t("ccr:ccrRestarted")}`)); } catch (error) { console.error(ansis.red(`\u2716 ${i18n.t("ccr:ccrCommandFailed")}: ${error instanceof Error ? error.message : String(error)}`)); throw error; } } async function runCcrStart() { ensureI18nInitialized(); console.log(ansis.cyan(` \u25B6\uFE0F ${i18n.t("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.t("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.t("ccr:ccrStarted")}`)); } else { console.error(ansis.red(`\u2716 ${i18n.t("ccr:ccrCommandFailed")}: ${error instanceof Error ? error.message : String(error)}`)); throw error; } } } async function runCcrStop() { ensureI18nInitialized(); console.log(ansis.cyan(` \u23F9\uFE0F ${i18n.t("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.t("ccr:ccrStopped")}`)); } catch (error) { console.error(ansis.red(`\u2716 ${i18n.t("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; } 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 inquirer.prompt({ type: "confirm", name: "continueInCcr", message: i18n.t("common:returnToMenu"), default: true }); if (continueInCcr) { return await showCcrMenu(); } } return false; } catch (error) { if (!handleExitPromptError(error)) { handleGeneralError(error); } return false; } } async function handleCancellation() { ensureI18nInitialized(); console.log(ansis.yellow(i18n.t("common:cancelled"))); } async function handleOfficialLoginMode() { ensureI18nInitialized(); const success = switchToOfficialLogin(); if (success) { console.log(ansis.green(`\u2714 ${i18n.t("api:officialLoginConfigured")}`)); } else { console.log(ansis.red(i18n.t("api:officialLoginFailed"))); } } async function handleCustomApiMode() { ensureI18nInitialized(); const existingConfig = getExistingApiConfig(); if (existingConfig) { const configAction = await promptApiConfigurationAction(); if (configAction === "keep-existing") { console.log(ansis.green(`\u2714 ${i18n.t("api:keepExistingConfig")}`)); return; } else if (configAction === "modify-partial") { await modifyApiConfigPartially(existingConfig); return; } } const { apiChoice } = await inquirer.prompt({ type: "list", name: "apiChoice", message: i18n.t("api:configureApi"), choices: addNumbersToChoices([ { name: `${i18n.t("api:useAuthToken")} - ${ansis.gray(i18n.t("api:authTokenDesc"))}`, value: "auth_token", short: i18n.t("api:useAuthToken") }, { name: `${i18n.t("api:useApiKey")} - ${ansis.gray(i18n.t("api:apiKeyDesc"))}`, value: "api_key", short: i18n.t("api:useApiKey") }, { name: i18n.t("api:skipApi"), value: "skip" } ]) }); if (!apiChoice || apiChoice === "skip") { await handleCancellation(); return; } const { url } = await inquirer.prompt({ type: "input", name: "url", message: `${i18n.t("api:enterApiUrl")}${i18n.t("common:emptyToSkip")}`, validate: (value) => { if (!value) { return true; } try { void new URL(value); return true; } catch { return i18n.t("api:invalidUrl"); } } }); if (url === void 0 || !url) { await handleCancellation(); return; } const keyMessage = apiChoice === "auth_token" ? `${i18n.t("api:enterAuthToken")}${i18n.t("common:emptyToSkip")}` : `${i18n.t("api:enterApiKey")}${i18n.t("common:emptyToSkip")}`; const { key } = await inquirer.prompt({ type: "input", name: "key", message: keyMessage, validate: (value) => { if (!value) { return true; } const validation = validateApiKey(value); if (!validation.isValid) { return validation.error || i18n.t("api:invalidKeyFormat"); } return true; } }); if (key === void 0 || !key) { await handleCancellation(); return; } const apiConfig = { url, key, authType: apiChoice }; const configuredApi = configureApi(apiConfig); if (configuredApi) { console.log(ansis.green(`\u2714 ${i18n.t("api:apiConfigSuccess")}`)); console.log(ansis.gray(` URL: ${configuredApi.url}`)); console.log(ansis.gray(` Key: ${formatApiKeyDisplay(configuredApi.key)}`)); } } async function handleCcrProxyMode() { ensureI18nInitialized(); const ccrStatus = await isCcrInstalled(); if (!ccrStatus.hasCorrectPackage) { await installCcr(); } else { console.log(ansis.green(`\u2714 ${i18n.t("ccr:ccrAlreadyInstalled")}`)); } const ccrConfigured = await setupCcrConfiguration(); if (ccrConfigured) { console.log(ansis.green(`\u2714 ${i18n.t("ccr:ccrSetupComplete")}`)); } } async function configureApiFeature() { ensureI18nInitialized(); const { mode } = await inquirer.prompt({ type: "list", name: "mode", message: i18n.t("api:apiModePrompt"), choices: addNumbersToChoices([ { name: i18n.t("api:apiModeOfficial"), value: "official" }, { name: i18n.t("api:apiModeCustom"), value: "custom" }, { name: i18n.t("api:apiModeCcr"), value: "ccr" }, { name: i18n.t("api:apiModeSkip"), value: "skip" } ]) }); if (!mode || mode === "skip") { await handleCancellation(); return; } switch (mode) { case "official": await handleOfficialLoginMode(); break; case "custom": await handleCustomApiMode(); break; case "ccr": await handleCcrProxyMode(); break; default: await handleCancellation(); break; } } async function configureMcpFeature() { ensureI18nInitialized(); if (isWindows()) { const { fixWindows } = await inquirer.prompt({ type: "confirm", name: "fixWindows", message: i18n.t("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 ${i18n.t("configuration:windowsMcpConfigFixed")}`)); } } const selectedServices = await selectMcpServices(); if (!selectedServices) { return; } if (selectedServices.length > 0) { const mcpBackupPath = backupMcpConfig(); if (mcpBackupPath) { console.log(ansis.gray(`\u2714 ${i18n.t("mcp:mcpBackupSuccess")}: ${mcpBackupPath}`)); } const newServers = {}; for (const serviceId of selectedServices) { const service = (await getMcpServices()).find((s) => s.id === serviceId); if (!service) continue; let config = service.config; if (service.requiresApiKey) { const { apiKey } = await inquirer.prompt({ type: "password", name: "apiKey", message: service.apiKeyPrompt + i18n.t("common:inputHidden"), validate: async (value) => !!value || i18n.t("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.t("mcp:mcpConfigSuccess")}`)); } } async function configureDefaultModelFeature() { ensureI18nInitialized(); const existingModel = getExistingModelConfig(); if (existingModel) { console.log(` ${ansis.blue(`\u2139 ${i18n.t("configuration:existingModelConfig") || "Existing model configuration"}`)}`); const modelDisplay = existingModel === "default" ? i18n.t("configuration:defaultModelOption") || "Default (Let Claude Code choose)" : existingModel.charAt(0).toUpperCase() + existingModel.slice(1); console.log(ansis.gray(` ${i18n.t("configuration:currentModel") || "Current model"}: ${modelDisplay} `)); const { modify } = await inquirer.prompt({ type: "confirm", name: "modify", message: i18n.t("configuration:modifyModel") || "Modify model configuration?", default: false }); if (!modify) { console.log(ansis.green(`\u2714 ${i18n.t("configuration:keepModel") || "Keeping existing model configuration"}`)); return; } } const { model } = await inquirer.prompt({ type: "list", name: "model", message: i18n.t("configuration:selectDefaultModel") || "Select default model", choices: addNumbersToChoices([ { name: i18n.t("configuration:defaultModelOption") || "Default - Let Claude Code choose", value: "default" }, { name: i18n.t("configuration:opusModelOption") || "Opus - Only use opus, high token consumption, use with caution", value: "opus" }, { name: i18n.t("configuration:sonnet1mModelOption") || "Sonnet 1M - 1M context version", value: "sonnet[1m]" }, { name: i18n.t("configuration:customModelOption") || "Custom - Specify custom model names", value: "custom" } ]), default: existingModel ? ["default", "opus", "sonnet[1m]", "custom"].indexOf(existingModel) : 0 }); if (!model) { await handleCancellation(); return; } if (model === "custom") { const { primaryModel, fastModel } = await promptCustomModels(); if (!primaryModel.trim() && !fastModel.trim()) { console.log(ansis.yellow(`\u26A0 ${i18n.t("configuration:customModelSkipped") || "Custom model configuration skipped"}`)); return; } updateCustomModel(primaryModel, fastModel); console.log(ansis.green(`\u2714 ${i18n.t("configuration:customModelConfigured") || "Custom model configuration completed"}`)); return; } updateDefaultModel(model); console.log(ansis.green(`\u2714 ${i18n.t("configuration:modelConfigured") || "Default model configured"}`)); } async function promptCustomModels() { const { primaryModel } = await inquirer.prompt({ type: "input", name: "primaryModel", message: `${i18n.t("configuration:enterPrimaryModel")}${i18n.t("common:emptyToSkip")}`, default: "" }); const { fastModel } = await inquirer.prompt({ type: "input", name: "fastModel", message: `${i18n.t("configuration:enterFastModel")}${i18n.t("common:emptyToSkip")}`, default: "" }); return { primaryModel, fastModel }; } async function configureAiMemoryFeature() { ensureI18nInitialized(); const { option } = await inquirer.prompt({ type: "list", name: "option", message: i18n.t("configuration:selectMemoryOption") || "Select configuration option", choices: addNumbersToChoices([ { name: i18n.t("configuration:configureAiLanguage") || "Configure AI output language", value: "language" }, { name: i18n.t("configuration:configureOutputStyle") || "Configure global AI output style", value: "outputStyle" } ]) }); if (!option) { return; } if (option === "language") { const zcfConfig = readZcfConfig(); const existingLang = zcfConfig?.aiOutputLang; if (existingLang) { console.log( ` ${ansis.blue(`\u2139 ${i18n.t("configuration:existingLanguageConfig") || "Existing AI output language configuration"}`)}` ); console.log(ansis.gray(` ${i18n.t("configuration:currentLanguage") || "Current language"}: ${existingLang} `)); const { modify } = await inquirer.prompt({ type: "confirm", name: "modify", message: i18n.t("configuration:modifyLanguage") || "Modify AI output language?", default: false }); if (!modify) { console.log(ansis.green(`\u2714 ${i18n.t("configuration:keepLanguage") || "Keeping existing language configuration"}`)); return; } } const { selectAiOutputLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aS; }); const aiOutputLang = await selectAiOutputLanguage(); applyAiLanguageDirective(aiOutputLang); updateZcfConfig({ aiOutputLang }); console.log(ansis.green(`\u2714 ${i18n.t("configuration:aiLanguageConfigured") || "AI output language configured"}`)); } else if (option === "outputStyle") { await configureOutputStyle(); } } async function changeScriptLanguageFeature(currentLang) { ensureI18nInitialized(); const { lang } = await inquirer.prompt({ type: "list", name: "lang", message: i18n.t("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 }); await changeLanguage(lang); console.log(ansis.green(`\u2714 ${i18n.t("language:languageChanged") || "Language changed"}`)); return lang; } async function configureCodexDefaultModelFeature() { ensureI18nInitialized(); const { readCodexConfig } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aT; }); const existingConfig = readCodexConfig(); const currentModel = existingConfig?.model; if (currentModel) { console.log(` ${ansis.blue(`\u2139 ${i18n.t("configuration:existingModelConfig") || "Existing model configuration"}`)}`); const modelDisplay = currentModel === "gpt-5-codex" ? "GPT-5-Codex" : currentModel === "gpt-5" ? "GPT-5" : currentModel.charAt(0).toUpperCase() + currentModel.slice(1); console.log(ansis.gray(` ${i18n.t("configuration:currentModel") || "Current model"}: ${modelDisplay} `)); const { modify } = await inquirer.prompt({ type: "confirm", name: "modify", message: i18n.t("configuration:modifyModel") || "Modify model configuration?", default: false }); if (!modify) { console.log(ansis.green(`\u2714 ${i18n.t("configuration:keepModel") || "Keeping existing model configuration"}`)); return; } } const { model } = await inquirer.prompt({ type: "list", name: "model", message: i18n.t("configuration:selectDefaultModel") || "Select default model", choices: addNumbersToChoices([ { name: i18n.t("configuration:codexModelOptions.gpt5"), value: "gpt-5" }, { name: i18n.t("configuration:codexModelOptions.gpt5Codex"), value: "gpt-5-codex" }, { name: i18n.t("configuration:codexModelOptions.custom"), value: "custom" } ]), default: currentModel ? ["gpt-5", "gpt-5-codex", "custom"].indexOf(currentModel) : 1 // Default to gpt-5-codex }); if (!model) { await handleCancellation(); return; } if (model === "custom") { const { customModel } = await inquirer.prompt({ type: "input", name: "customModel", message: `${i18n.t("configuration:enterCustomModel")}${i18n.t("common:emptyToSkip")}`, default: "" }); if (!customModel.trim()) { console.log(ansis.yellow(`\u26A0 ${i18n.t("configuration:customModelSkipped") || "Custom model configuration skipped"}`)); return; } await updateCodexModelProvider(customModel.trim()); console.log(ansis.green(`\u2714 ${i18n.t("configuration:customModelConfigured") || "Custom model configuration completed"}`)); return; } await updateCodexModelProvider(model); console.log(ansis.green(`\u2714 ${i18n.t("configuration:modelConfigured") || "Default model configured"}`)); } async function configureCodexAiMemoryFeature() { ensureI18nInitialized(); const { option } = await inquirer.prompt({ type: "list", name: "option", message: i18n.t("configuration:selectMemoryOption") || "Select configuration option", choices: addNumbersToChoices([ { name: i18n.t("configuration:configureAiLanguage") || "Configure AI output language", value: "language" }, { name: i18n.t("configuration:configureSystemPromptStyle") || "Configure global AI system prompt style", value: "systemPrompt" } ]) }); if (!option) { return; } if (option === "language") { const zcfConfig = readZcfConfig(); const existingLang = zcfConfig?.aiOutputLang; if (existingLang) { console.log( ` ${ansis.blue(`\u2139 ${i18n.t("configuration:existingLanguageConfig") || "Existing AI output language configuration"}`)}` ); console.log(ansis.gray(` ${i18n.t("configuration:currentLanguage") || "Current language"}: ${existingLang} `)); const { modify } = await inquirer.prompt({ type: "confirm", name: "modify", message: i18n.t("configuration:modifyLanguage") || "Modify AI output language?", default: false }); if (!modify) { console.log(ansis.green(`\u2714 ${i18n.t("configuration:keepLanguage") || "Keeping existing language configuration"}`)); await ensureLanguageDirectiveInAgents(existingLang); return; } } const { selectAiOutputLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aS; }); const aiOutputLang = await selectAiOutputLanguage(); await updateCodexLanguageDirective(aiOutputLang); updateZcfConfig({ aiOutputLang }); console.log(ansis.green(`\u2714 ${i18n.t("configuration:aiLanguageConfigured") || "AI output language configured"}`)); } else if (option === "systemPrompt") { const zcfConfig = readZcfConfig(); const currentLang = zcfConfig?.aiOutputLang || "English"; const { runCodexSystemPromptSelection } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aT; }); await runCodexSystemPromptSelection(); await ensureLanguageDirectiveInAgents(currentLang); console.log(ansis.green(`\u2714 ${i18n.t("configuration:systemPromptConfigured")}`)); } } async function updateCodexModelProvider(modelProvider) { const { readCodexConfig, writeCodexConfig, backupCodexConfig, getBackupMessage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aT; }); const backupPath = backupCodexConfig(); if (backupPath) { console.log(ansis.gray(getBackupMessage(backupPath))); } const existingConfig = readCodexConfig(); const updatedConfig = { ...existingConfig, model: modelProvider, // Set the model field modelProvider: existingConfig?.modelProvider || null, // Preserve existing API provider providers: existingConfig?.providers || [], mcpServices: existingConfig?.mcpServices || [], managed: true, otherConfig: existingConfig?.otherConfig || [], modelProviderCommented: existingConfig?.modelProviderCommented }; writeCodexConfig(updatedConfig); } async function ensureLanguageDirectiveInAgents(aiOutputLang) { const { readFile, writeFile, exists } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aR; }); const { homedir } = await import('node:os'); const { join } = await import('pathe'); const CODEX_AGENTS_FILE = join(homedir(), ".codex", "AGENTS.md"); if (!exists(CODEX_AGENTS_FILE)) { console.log(ansis.yellow(i18n.t("codex:agentsFileNotFound"))); return; } const content = readFile(CODEX_AGENTS_FILE); const languageLabels = { "Chinese": "Chinese-simplified", "English": "English", "zh-CN": "Chinese-simplified", "en": "English" }; const langLabel = languageLabels[aiOutputLang] || aiOutputLang; const hasLanguageDirective = /\*\*Most Important:\s*Always respond in [^*]+\*\*/i.test(content); if (!hasLanguageDirective) { const { backupCodexAgents, getBackupMessage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aT; }); const backupPath = backupCodexAgents(); if (backupPath) { console.log(ansis.gray(getBackupMessage(backupPath))); } let updatedContent = content; if (!updatedContent.endsWith("\n")) { updatedContent += "\n"; } updatedContent += ` **Most Important:Always respond in ${langLabel}** `; writeFile(CODEX_AGENTS_FILE, updatedContent); console.log(ansis.gray(` ${i18n.t("configuration:addedLanguageDirective")}: ${langLabel}`)); } } async function updateCodexLanguageDirective(aiOutputLang) { const { readFile, writeFile, exists } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aR; }); const { backupCodexAgents, getBackupMessage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.aT; }); const { homedir } = await import('node:os'); const { join } = await import('pathe'); const CODEX_AGENTS_FILE = join(homedir(), ".codex", "AGENTS.md"); if (!exists(CODEX_AGENTS_FILE)) { console.log(ansis.yellow(i18n.t("codex:agentsFileNotFound"))); return; } const backupPath = backupCodexAgents(); if (backupPath) { console.log(ansis.gray(getBackupMessage(backupPath))); } let content = readFile(CODEX_AGENTS_FILE); const languageLabels = { "Chinese": "Chinese-simplified", "English": "English", "zh-CN": "Chinese-simplified", "en": "English" }; const langLabel = languageLabels[aiOutputLang] || aiOutputLang; content = content.replace(/\*\*Most Important:\s*Always respond in [^*]+\*\*\s*/g, ""); if (!content.endsWith("\n")) { content += "\n"; } content += ` **Most Important:Always respond in ${langLabel}** `; writeFile(CODEX_AGENTS_FILE, content); } async function configureEnvPermissionFeature() { ensureI18nInitialized(); const { choice } = await inquirer.prompt({ type: "list", name: "choice", message: i18n.t("configuration:selectEnvPermissionOption") || "Select option", choices: addNumbersToChoices([ { name: `${i18n.t("configuration:importRecommendedEnv") || "Import environment"} ${ansis.gray( `- ${i18n.t("configuration:importRecommendedEnvDesc") || "Import env settings"}` )}`, value: "env" }, { name: `${i18n.t("configuration:importRecommendedPermissions") || "Import permissions"} ${ansis.gray( `- ${i18n.t("configuration:importRecommendedPermissionsDesc") || "Import permission settings"}` )}`, value: "permissions" }, { name: `${i18n.t("configuration:openSettingsJson") || "Open settings"} ${ansis.gray( `- ${i18n.t("configuration:openSettingsJsonDesc") || "View settings file"}` )}`, value: "open" } ]) }); if (!choice) { await handleCancellation(); return; } try { switch (choice) { case "env": await importRecommendedEnv(); console.log(ansis.green(`\u2705 ${i18n.t("configuration:envImportSuccess")}`)); break; case "permissions": await importRecommendedPermissions(); console.log(ansis.green(`\u2705 ${i18n.t("configuration:permissionsImportSuccess") || "Permissions imported"}`)); break; case "open": console.log(ansis.cyan(i18n.t("configuration:openingSettingsJson") || "Opening settings.json...")); await openSettingsJson(); break; } } catch (error) { console.error(ansis.red(`${i18n.t("common:error")}: ${error.message}`)); } } 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 inquirer.prompt({ type: "confirm", name: "continueInCometix", message: i18n.t("common:returnToMenu"), default: 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(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 { await exec$1("npm", ["uninstall", "-g", "@anthropic-ai/claude-code"]); result.removed.push("@anthropic-ai/claude-code package"); result.success = true; } 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(`Failed to uninstall Claude Code package: ${npmError.message}`); } } } catch (error) { result.errors.push(`Failed to uninstall Claude Code: ${error.message}`); } return result; } /** * 10. Remove backup files */ async removeBackups() { const result = { suc