zcf
Version:
Zero-Config Claude-Code Flow - One-click configuration tool for Claude Code
1,230 lines (1,216 loc) • 47.7 kB
JavaScript
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);