aico-cli 0.0.9 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -1,19 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import cac from 'cac';
3
3
  import ansis from 'ansis';
4
- import { J as readZcfConfig, K as updateZcfConfig, N as getTranslation, k as AI_OUTPUT_LANGUAGES, O as inquirer, P as addNumbersToChoices, Q as version, q as backupExistingConfig, r as copyConfigFiles, x as applyAiLanguageDirective, R as configureAiPersonality, C as CLAUDE_DIR, T as readJsonConfig, H as addCompletedOnboarding, S as SETTINGS_FILE, U as writeJsonConfig, o as openSettingsJson, b as importRecommendedPermissions, a as importRecommendedEnv, V as isWindows, z as readMcpConfig, G as fixWindowsMcpConfig, B as writeMcpConfig, W as selectMcpServices, D as backupMcpConfig, M as MCP_SERVICES, F as buildMcpServerConfig, X as EscapeKeyPressed, E as mergeMcpServers, Y as displayBanner, I as I18N, Z as selectAndInstallWorkflows, _ as handleExitPromptError, $ as handleGeneralError, a0 as displayBannerWithInfo, a1 as readZcfConfigAsync, i as init, a2 as executeWithEscapeSupport } from './shared/aico-cli.Ngtnxi15.mjs';
4
+ import { J as readAicoConfig, K as updateAicoConfig, N as getTranslation, k as AI_OUTPUT_LANGUAGES, O as inquirer, P as addNumbersToChoices, Q as version, q as backupExistingConfig, r as copyConfigFiles, x as applyAiLanguageDirective, R as configureAiPersonality, C as CLAUDE_DIR, I as I18N, T as readCcrConfig, U as isCcrInstalled, V as installCcr, W as configureCcrFeature, X as handleExitPromptError, Y as handleGeneralError, Z as readAicoConfigAsync, _ as COMETIX_COMMANDS, $ as COMETIX_COMMAND_NAME, a0 as installCometixLine, o as openSettingsJson, b as importRecommendedPermissions, a as importRecommendedEnv, a1 as isWindows, z as readMcpConfig, G as fixWindowsMcpConfig, B as writeMcpConfig, a2 as selectMcpServices, D as backupMcpConfig, M as MCP_SERVICES, F as buildMcpServerConfig, a3 as EscapeKeyPressed, E as mergeMcpServers, a4 as displayBanner, a5 as selectAndInstallWorkflows, a6 as displayBannerWithInfo, i as init, a7 as executeWithEscapeSupport, a8 as checkAndUpdateTools } from './shared/aico-cli.BEzpBbNi.mjs';
5
5
  import inquirer$1 from 'inquirer';
6
- import { existsSync, copyFileSync, mkdirSync } from 'node:fs';
7
- import { exec, spawn } from 'node:child_process';
8
- import { promisify } from 'node:util';
9
- import dayjs from 'dayjs';
6
+ import { existsSync } from 'node:fs';
7
+ import { x } from 'tinyexec';
10
8
  import { homedir } from 'node:os';
11
9
  import { join } from 'node:path';
12
- import { x } from 'tinyexec';
10
+ import { exec } from 'child_process';
11
+ import { promisify } from 'util';
12
+ import { exec as exec$1, spawn } from 'node:child_process';
13
+ import { promisify as promisify$1 } from 'node:util';
14
+ import 'dayjs';
13
15
  import 'pathe';
14
- import { exec as exec$1 } from 'child_process';
15
- import { promisify as promisify$1 } from 'util';
16
16
  import 'node:url';
17
+ import 'ora';
17
18
  import 'node:fs/promises';
18
19
 
19
20
  async function selectAiOutputLanguage(scriptLang, defaultLang) {
@@ -61,12 +62,12 @@ async function selectAiOutputLanguage(scriptLang, defaultLang) {
61
62
  return aiOutputLang;
62
63
  }
63
64
  async function selectScriptLanguage(currentLang) {
64
- const zcfConfig = readZcfConfig();
65
- if (zcfConfig?.preferredLang) {
66
- return zcfConfig.preferredLang;
65
+ const aicoConfig = readAicoConfig();
66
+ if (aicoConfig?.preferredLang) {
67
+ return aicoConfig.preferredLang;
67
68
  }
68
69
  const scriptLang = "zh-CN";
69
- updateZcfConfig({
70
+ updateAicoConfig({
70
71
  version,
71
72
  preferredLang: scriptLang
72
73
  });
@@ -103,457 +104,323 @@ async function updatePromptOnly(configLang, scriptLang, aiOutputLang) {
103
104
  console.log("\n" + ansis.cyan(i18n.common.complete));
104
105
  }
105
106
 
106
- const execAsync$2 = promisify(exec);
107
- async function isCcrInstalled() {
107
+ const execAsync$1 = promisify(exec);
108
+ async function runCcrUi(scriptLang, apiKey) {
109
+ const i18n = I18N[scriptLang];
110
+ console.log(ansis.cyan(`
111
+ \u{1F5A5}\uFE0F ${i18n.ccr.startingCcrUi}`));
112
+ if (apiKey) {
113
+ console.log(ansis.bold.green(`
114
+ \u{1F511} ${i18n.ccr.ccrUiApiKey || "CCR UI API Key"}: ${apiKey}`));
115
+ console.log(ansis.gray(` ${i18n.ccr.ccrUiApiKeyHint || "Use this API key to login to CCR UI"}
116
+ `));
117
+ }
108
118
  try {
109
- await execAsync$2("ccr version");
110
- return true;
111
- } catch {
112
- try {
113
- await execAsync$2("which ccr");
114
- return true;
115
- } catch {
116
- return false;
117
- }
119
+ const { stdout, stderr } = await execAsync$1("ccr ui");
120
+ if (stdout) console.log(stdout);
121
+ if (stderr) console.error(ansis.yellow(stderr));
122
+ console.log(ansis.green(`\u2714 ${i18n.ccr.ccrUiStarted}`));
123
+ } catch (error) {
124
+ console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`));
125
+ throw error;
118
126
  }
119
127
  }
120
- async function installCcr(scriptLang) {
121
- const i18n = getTranslation(scriptLang);
122
- const installed = await isCcrInstalled();
123
- if (installed) {
124
- console.log(ansis.green(`\u2714 ${i18n.ccr.ccrAlreadyInstalled}`));
125
- return;
126
- }
127
- console.log(ansis.cyan(`\u{1F4E6} ${i18n.ccr.installingCcr}`));
128
+ async function runCcrStatus(scriptLang) {
129
+ const i18n = I18N[scriptLang];
130
+ console.log(ansis.cyan(`
131
+ \u{1F4CA} ${i18n.ccr.checkingCcrStatus}`));
128
132
  try {
129
- await execAsync$2("npm install -g claude-code-router --force");
130
- console.log(ansis.green(`\u2714 ${i18n.ccr.ccrInstallSuccess}`));
131
- } catch (error) {
132
- if (error.message?.includes("EEXIST")) {
133
- console.log(ansis.yellow(`\u26A0 ${i18n.ccr.ccrAlreadyInstalled}`));
134
- return;
133
+ const { stdout, stderr } = await execAsync$1("ccr status");
134
+ if (stdout) {
135
+ console.log("\n" + ansis.bold(i18n.ccr.ccrStatusTitle));
136
+ console.log(stdout);
135
137
  }
136
- console.error(ansis.red(`\u2716 ${i18n.ccr.ccrInstallFailed}`));
138
+ if (stderr) console.error(ansis.yellow(stderr));
139
+ } catch (error) {
140
+ console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`));
137
141
  throw error;
138
142
  }
139
143
  }
140
-
141
- const PROVIDER_PRESETS_URL = "https://pub-0dc3e1677e894f07bbea11b17a29e032.r2.dev/providers.json";
142
- async function fetchProviderPresets() {
144
+ async function runCcrRestart(scriptLang) {
145
+ const i18n = I18N[scriptLang];
146
+ console.log(ansis.cyan(`
147
+ \u{1F504} ${i18n.ccr.restartingCcr}`));
143
148
  try {
144
- const controller = new AbortController();
145
- const timeoutId = setTimeout(() => controller.abort(), 5e3);
146
- const response = await fetch(PROVIDER_PRESETS_URL, {
147
- signal: controller.signal
148
- });
149
- clearTimeout(timeoutId);
150
- if (!response.ok) {
151
- throw new Error(`HTTP error! status: ${response.status}`);
152
- }
153
- const data = await response.json();
154
- const presets = [];
155
- if (Array.isArray(data)) {
156
- for (const provider of data) {
157
- if (provider && typeof provider === "object") {
158
- presets.push({
159
- name: provider.name || "",
160
- provider: provider.name || "",
161
- baseURL: provider.api_base_url || provider.baseURL || provider.url,
162
- requiresApiKey: provider.api_key === "" || provider.requiresApiKey !== false,
163
- models: provider.models || [],
164
- description: provider.description || provider.name || "",
165
- transformer: provider.transformer
166
- });
167
- }
168
- }
169
- } else if (data && typeof data === "object") {
170
- for (const [key, value] of Object.entries(data)) {
171
- if (typeof value === "object" && value !== null) {
172
- const provider = value;
173
- presets.push({
174
- name: provider.name || key,
175
- provider: key,
176
- baseURL: provider.api_base_url || provider.baseURL || provider.url,
177
- requiresApiKey: provider.api_key === "" || provider.requiresApiKey !== false,
178
- models: provider.models || [],
179
- description: provider.description || "",
180
- transformer: provider.transformer
181
- });
182
- }
183
- }
184
- }
185
- return presets;
149
+ const { stdout, stderr } = await execAsync$1("ccr restart");
150
+ if (stdout) console.log(stdout);
151
+ if (stderr) console.error(ansis.yellow(stderr));
152
+ console.log(ansis.green(`\u2714 ${i18n.ccr.ccrRestarted}`));
186
153
  } catch (error) {
187
- return getFallbackPresets();
154
+ console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`));
155
+ throw error;
188
156
  }
189
157
  }
190
- function getFallbackPresets() {
191
- return [
192
- {
193
- name: "dashscope",
194
- provider: "dashscope",
195
- baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions",
196
- requiresApiKey: true,
197
- models: ["qwen3-coder-plus"],
198
- description: "Alibaba DashScope",
199
- transformer: {
200
- use: [["maxtoken", { max_tokens: 65536 }]],
201
- "qwen3-coder-plus": {
202
- use: ["enhancetool"]
203
- }
204
- }
205
- },
206
- {
207
- name: "deepseek",
208
- provider: "deepseek",
209
- baseURL: "https://api.deepseek.com/chat/completions",
210
- requiresApiKey: true,
211
- models: ["deepseek-chat", "deepseek-reasoner"],
212
- description: "DeepSeek AI models",
213
- transformer: {
214
- use: ["deepseek"],
215
- "deepseek-chat": {
216
- use: ["tooluse"]
217
- }
218
- }
219
- },
220
- {
221
- name: "gemini",
222
- provider: "gemini",
223
- baseURL: "https://generativelanguage.googleapis.com/v1beta/models/",
224
- requiresApiKey: true,
225
- models: ["gemini-2.5-flash", "gemini-2.5-pro"],
226
- description: "Google Gemini models",
227
- transformer: {
228
- use: ["gemini"]
229
- }
230
- },
231
- {
232
- name: "modelscope",
233
- provider: "modelscope",
234
- baseURL: "https://api-inference.modelscope.cn/v1/chat/completions",
235
- requiresApiKey: true,
236
- models: ["Qwen/Qwen3-Coder-480B-A35B-Instruct", "Qwen/Qwen3-235B-A22B-Thinking-2507", "ZhipuAI/GLM-4.5"],
237
- description: "ModelScope AI models",
238
- transformer: {
239
- use: [["maxtoken", { max_tokens: 65536 }]],
240
- "Qwen/Qwen3-Coder-480B-A35B-Instruct": {
241
- use: ["enhancetool"]
242
- },
243
- "Qwen/Qwen3-235B-A22B-Thinking-2507": {
244
- use: ["reasoning"]
245
- }
246
- }
247
- },
248
- {
249
- name: "openrouter",
250
- provider: "openrouter",
251
- baseURL: "https://openrouter.ai/api/v1/chat/completions",
252
- requiresApiKey: true,
253
- models: [
254
- "google/gemini-2.5-pro-preview",
255
- "anthropic/claude-sonnet-4",
256
- "anthropic/claude-3.5-sonnet",
257
- "anthropic/claude-3.7-sonnet:thinking"
258
- ],
259
- description: "OpenRouter API",
260
- transformer: {
261
- use: ["openrouter"]
262
- }
263
- },
264
- {
265
- name: "siliconflow",
266
- provider: "siliconflow",
267
- baseURL: "https://api.siliconflow.cn/v1/chat/completions",
268
- requiresApiKey: true,
269
- models: ["moonshotai/Kimi-K2-Instruct"],
270
- description: "SiliconFlow AI",
271
- transformer: {
272
- use: [["maxtoken", { max_tokens: 16384 }]]
273
- }
274
- },
275
- {
276
- name: "volcengine",
277
- provider: "volcengine",
278
- baseURL: "https://ark.cn-beijing.volces.com/api/v3/chat/completions",
279
- requiresApiKey: true,
280
- models: ["deepseek-v3-250324", "deepseek-r1-250528"],
281
- description: "Volcengine AI",
282
- transformer: {
283
- use: ["deepseek"]
284
- }
158
+ async function runCcrStart(scriptLang) {
159
+ const i18n = I18N[scriptLang];
160
+ console.log(ansis.cyan(`
161
+ \u25B6\uFE0F ${i18n.ccr.startingCcr}`));
162
+ try {
163
+ const { stdout, stderr } = await execAsync$1("ccr start");
164
+ if (stdout) console.log(stdout);
165
+ if (stderr) console.error(ansis.yellow(stderr));
166
+ console.log(ansis.green(`\u2714 ${i18n.ccr.ccrStarted}`));
167
+ } catch (error) {
168
+ if (error.stdout && error.stdout.includes("Loaded JSON config from:")) {
169
+ console.log(error.stdout);
170
+ if (error.stderr) console.error(ansis.yellow(error.stderr));
171
+ console.log(ansis.green(`\u2714 ${i18n.ccr.ccrStarted}`));
172
+ } else {
173
+ console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`));
174
+ throw error;
285
175
  }
286
- ];
287
- }
288
-
289
- const execAsync$1 = promisify(exec);
290
- const CCR_CONFIG_DIR = join(homedir(), ".claude-code-router");
291
- const CCR_CONFIG_FILE = join(CCR_CONFIG_DIR, "config.json");
292
- const CCR_BACKUP_DIR = CCR_CONFIG_DIR;
293
- function ensureCcrConfigDir() {
294
- if (!existsSync(CCR_CONFIG_DIR)) {
295
- mkdirSync(CCR_CONFIG_DIR, { recursive: true });
296
176
  }
297
177
  }
298
- function backupCcrConfig(scriptLang) {
299
- const i18n = getTranslation(scriptLang);
178
+ async function runCcrStop(scriptLang) {
179
+ const i18n = I18N[scriptLang];
180
+ console.log(ansis.cyan(`
181
+ \u23F9\uFE0F ${i18n.ccr.stoppingCcr}`));
300
182
  try {
301
- if (!existsSync(CCR_CONFIG_FILE)) {
302
- return null;
303
- }
304
- const timestamp = dayjs().format("YYYY-MM-DDTHH-mm-ss-SSS") + "Z";
305
- const backupFileName = `config.json.${timestamp}.bak`;
306
- const backupPath = join(CCR_BACKUP_DIR, backupFileName);
307
- console.log(ansis.cyan(`${i18n.ccr.backupCcrConfig}`));
308
- copyFileSync(CCR_CONFIG_FILE, backupPath);
309
- console.log(ansis.green(`\u2714 ${i18n.ccr.ccrBackupSuccess.replace("{path}", backupPath)}`));
310
- return backupPath;
183
+ const { stdout, stderr } = await execAsync$1("ccr stop");
184
+ if (stdout) console.log(stdout);
185
+ if (stderr) console.error(ansis.yellow(stderr));
186
+ console.log(ansis.green(`\u2714 ${i18n.ccr.ccrStopped}`));
311
187
  } catch (error) {
312
- console.error(ansis.red(`${i18n.ccr.ccrBackupFailed}:`), error.message);
313
- return null;
188
+ console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`));
189
+ throw error;
314
190
  }
315
191
  }
316
- function readCcrConfig() {
192
+
193
+ function isCcrConfigured() {
194
+ const CCR_CONFIG_FILE = join(homedir(), ".claude-code-router", "config.json");
317
195
  if (!existsSync(CCR_CONFIG_FILE)) {
318
- return null;
319
- }
320
- return readJsonConfig(CCR_CONFIG_FILE);
321
- }
322
- function writeCcrConfig(config) {
323
- ensureCcrConfigDir();
324
- writeJsonConfig(CCR_CONFIG_FILE, config);
325
- }
326
- async function configureCcrProxy(ccrConfig) {
327
- const settings = readJsonConfig(SETTINGS_FILE) || {};
328
- const host = ccrConfig.HOST || "127.0.0.1";
329
- const port = ccrConfig.PORT || 3456;
330
- const apiKey = ccrConfig.APIKEY || "sk-aico-x-ccr";
331
- if (!settings.env) {
332
- settings.env = {};
196
+ return false;
333
197
  }
334
- settings.env.ANTHROPIC_BASE_URL = `http://${host}:${port}`;
335
- settings.env.ANTHROPIC_API_KEY = apiKey;
336
- writeJsonConfig(SETTINGS_FILE, settings);
198
+ const config = readCcrConfig();
199
+ return config !== null && config.Providers && config.Providers.length > 0;
337
200
  }
338
- async function selectCcrPreset(scriptLang) {
339
- const i18n = getTranslation(scriptLang);
340
- console.log(ansis.cyan(`${i18n.ccr.fetchingPresets}`));
341
- const presets = await fetchProviderPresets();
342
- if (!presets || presets.length === 0) {
343
- console.log(ansis.yellow(`${i18n.ccr.noPresetsAvailable}`));
344
- return null;
345
- }
201
+ async function showCcrMenu(scriptLang) {
346
202
  try {
347
- const choices = [
348
- ...presets.map((p, index) => ({
349
- name: `${index + 1}. ${p.name}`,
350
- value: p
351
- })),
352
- {
353
- name: `${presets.length + 1}. ${i18n.ccr.skipOption}`,
354
- value: "skip"
203
+ const i18n = I18N[scriptLang];
204
+ console.log("\n" + ansis.cyan("\u2550".repeat(50)));
205
+ console.log(ansis.bold.cyan(` ${i18n.ccr.ccrMenuTitle}`));
206
+ console.log(ansis.cyan("\u2550".repeat(50)) + "\n");
207
+ console.log(` ${ansis.cyan("1.")} ${i18n.ccr.ccrMenuOptions.initCcr} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.initCcr)}`);
208
+ console.log(` ${ansis.cyan("2.")} ${i18n.ccr.ccrMenuOptions.startUi} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.startUi)}`);
209
+ console.log(` ${ansis.cyan("3.")} ${i18n.ccr.ccrMenuOptions.checkStatus} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.checkStatus)}`);
210
+ console.log(` ${ansis.cyan("4.")} ${i18n.ccr.ccrMenuOptions.restart} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.restart)}`);
211
+ console.log(` ${ansis.cyan("5.")} ${i18n.ccr.ccrMenuOptions.start} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.start)}`);
212
+ console.log(` ${ansis.cyan("6.")} ${i18n.ccr.ccrMenuOptions.stop} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.stop)}`);
213
+ console.log(` ${ansis.yellow("0.")} ${i18n.ccr.ccrMenuOptions.back}`);
214
+ console.log("");
215
+ const { choice } = await inquirer$1.prompt({
216
+ type: "input",
217
+ name: "choice",
218
+ message: i18n.common.enterChoice,
219
+ validate: (value) => {
220
+ const valid = ["1", "2", "3", "4", "5", "6", "0"];
221
+ return valid.includes(value) || i18n.common.invalidChoice;
355
222
  }
356
- ];
357
- const { preset } = await inquirer.prompt({
358
- type: "list",
359
- name: "preset",
360
- message: i18n.ccr.selectCcrPreset,
361
- choices
362
223
  });
363
- return preset;
364
- } catch (error) {
365
- if (error.name === "ExitPromptError") {
366
- console.log(ansis.yellow(i18n.common.cancelled));
367
- return null;
224
+ switch (choice) {
225
+ case "1":
226
+ const ccrStatus = await isCcrInstalled();
227
+ if (!ccrStatus.hasCorrectPackage) {
228
+ await installCcr(scriptLang);
229
+ } else {
230
+ console.log(ansis.green(`\u2714 ${i18n.ccr.ccrAlreadyInstalled}`));
231
+ }
232
+ await configureCcrFeature(scriptLang);
233
+ console.log(ansis.green(`
234
+ \u2714 ${i18n.ccr.ccrSetupComplete}`));
235
+ break;
236
+ case "2":
237
+ if (!isCcrConfigured()) {
238
+ console.log(ansis.yellow(`
239
+ \u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`));
240
+ console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."}
241
+ `));
242
+ } else {
243
+ const config = readCcrConfig();
244
+ await runCcrUi(scriptLang, config?.APIKEY);
245
+ }
246
+ break;
247
+ case "3":
248
+ if (!isCcrConfigured()) {
249
+ console.log(ansis.yellow(`
250
+ \u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`));
251
+ console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."}
252
+ `));
253
+ } else {
254
+ await runCcrStatus(scriptLang);
255
+ }
256
+ break;
257
+ case "4":
258
+ if (!isCcrConfigured()) {
259
+ console.log(ansis.yellow(`
260
+ \u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`));
261
+ console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."}
262
+ `));
263
+ } else {
264
+ await runCcrRestart(scriptLang);
265
+ }
266
+ break;
267
+ case "5":
268
+ if (!isCcrConfigured()) {
269
+ console.log(ansis.yellow(`
270
+ \u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`));
271
+ console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."}
272
+ `));
273
+ } else {
274
+ await runCcrStart(scriptLang);
275
+ }
276
+ break;
277
+ case "6":
278
+ if (!isCcrConfigured()) {
279
+ console.log(ansis.yellow(`
280
+ \u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`));
281
+ console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."}
282
+ `));
283
+ } else {
284
+ await runCcrStop(scriptLang);
285
+ }
286
+ break;
287
+ case "0":
288
+ return false;
368
289
  }
369
- throw error;
370
- }
371
- }
372
- async function configureCcrWithPreset(preset, scriptLang) {
373
- const i18n = getTranslation(scriptLang);
374
- const provider = {
375
- name: preset.name,
376
- // Use the original name from JSON
377
- api_base_url: preset.baseURL || "",
378
- api_key: "",
379
- models: preset.models
380
- };
381
- if (preset.transformer) {
382
- provider.transformer = preset.transformer;
383
- }
384
- if (preset.requiresApiKey) {
385
- try {
386
- const { apiKey } = await inquirer.prompt({
387
- type: "input",
388
- name: "apiKey",
389
- message: i18n.ccr.enterApiKeyForProvider.replace("{provider}", preset.name),
390
- validate: (value) => !!value || i18n.api.keyRequired
290
+ if (choice !== "0") {
291
+ console.log("\n" + ansis.dim("\u2500".repeat(50)) + "\n");
292
+ const { continueInCcr } = await inquirer$1.prompt({
293
+ type: "confirm",
294
+ name: "continueInCcr",
295
+ message: i18n.common.returnToMenu || "Return to CCR menu?",
296
+ default: true
391
297
  });
392
- provider.api_key = apiKey;
393
- } catch (error) {
394
- if (error.name === "ExitPromptError") {
395
- throw error;
298
+ if (continueInCcr) {
299
+ return await showCcrMenu(scriptLang);
396
300
  }
397
- throw error;
398
301
  }
399
- } else {
400
- provider.api_key = "sk-free";
401
- }
402
- let defaultModel = preset.models[0];
403
- if (preset.models.length > 1) {
404
- try {
405
- const { model } = await inquirer.prompt({
406
- type: "list",
407
- name: "model",
408
- message: i18n.ccr.selectDefaultModelForProvider.replace("{provider}", preset.name),
409
- choices: preset.models.map((m, index) => ({
410
- name: `${index + 1}. ${m}`,
411
- value: m
412
- }))
413
- });
414
- defaultModel = model;
415
- } catch (error) {
416
- if (error.name === "ExitPromptError") {
417
- throw error;
418
- }
419
- throw error;
302
+ return false;
303
+ } catch (error) {
304
+ if (!handleExitPromptError(error)) {
305
+ handleGeneralError(error, scriptLang);
420
306
  }
307
+ return false;
421
308
  }
422
- const router = {
423
- default: `${preset.name},${defaultModel}`,
424
- // Use the original name
425
- background: `${preset.name},${defaultModel}`,
426
- think: `${preset.name},${defaultModel}`,
427
- longContext: `${preset.name},${defaultModel}`,
428
- longContextThreshold: 6e4,
429
- webSearch: `${preset.name},${defaultModel}`
430
- };
431
- const config = {
432
- LOG: true,
433
- CLAUDE_PATH: "",
434
- HOST: "127.0.0.1",
435
- PORT: 3456,
436
- APIKEY: "sk-aico-x-ccr",
437
- API_TIMEOUT_MS: "600000",
438
- PROXY_URL: "",
439
- transformers: [],
440
- Providers: [provider],
441
- Router: router
442
- };
443
- return config;
444
309
  }
445
- async function restartAndCheckCcrStatus(scriptLang) {
446
- const i18n = getTranslation(scriptLang);
310
+
311
+ function getValidLanguage(lang) {
312
+ return lang && lang in I18N ? lang : "en";
313
+ }
314
+
315
+ async function executeCcusage(args = []) {
447
316
  try {
448
- console.log(ansis.cyan(`${i18n.ccr.restartingCcr}`));
449
- await execAsync$1("ccr restart");
450
- console.log(ansis.green(`\u2714 ${i18n.ccr.ccrRestartSuccess}`));
451
- console.log(ansis.cyan(`${i18n.ccr.checkingCcrStatus}`));
452
- const { stdout } = await execAsync$1("ccr status");
453
- console.log(ansis.gray(stdout));
317
+ let lang = "en";
318
+ try {
319
+ const aicoConfig = await readAicoConfigAsync();
320
+ const rawLang = aicoConfig?.preferredLang || "en";
321
+ lang = getValidLanguage(rawLang);
322
+ } catch {
323
+ lang = "en";
324
+ }
325
+ const i18n = I18N[lang];
326
+ const command = "npx";
327
+ const commandArgs = ["ccusage@latest", ...args || []];
328
+ console.log(ansis.cyan(i18n.tools.runningCcusage));
329
+ console.log(ansis.gray(`$ npx ccusage@latest ${(args || []).join(" ")}`));
330
+ console.log("");
331
+ await x(command, commandArgs, {
332
+ nodeOptions: {
333
+ stdio: "inherit"
334
+ }
335
+ });
454
336
  } catch (error) {
455
- console.error(ansis.red(`${i18n.ccr.ccrRestartFailed}:`), error.message || error);
337
+ let lang = "en";
338
+ try {
339
+ const aicoConfig = await readAicoConfigAsync();
340
+ const rawLang = aicoConfig?.preferredLang || "en";
341
+ lang = getValidLanguage(rawLang);
342
+ } catch {
343
+ lang = "en";
344
+ }
345
+ const i18n = I18N[lang];
346
+ console.error(ansis.red(i18n.tools.ccusageFailed));
347
+ console.error(ansis.yellow(i18n.tools.checkNetworkConnection));
456
348
  if (process.env.DEBUG) {
457
- console.error("Full error:", error);
349
+ console.error(ansis.gray(i18n.tools.errorDetails), error);
350
+ }
351
+ if (process.env.NODE_ENV !== "test") {
352
+ process.exit(1);
458
353
  }
354
+ throw error;
459
355
  }
460
356
  }
461
- function showConfigurationTips(scriptLang, apiKey) {
357
+
358
+ const execAsync = promisify$1(exec$1);
359
+ async function runCometixPrintConfig(scriptLang) {
462
360
  const i18n = getTranslation(scriptLang);
463
- console.log(ansis.bold.cyan(`
464
- \u{1F4CC} ${i18n.ccr.configTips}:`));
465
- console.log(ansis.blue(` \u2022 ${i18n.ccr.advancedConfigTip}`));
466
- console.log(ansis.blue(` \u2022 ${i18n.ccr.manualConfigTip}`));
467
- console.log(ansis.bold.yellow(` \u2022 ${i18n.ccr.useClaudeCommand}`));
468
- if (apiKey) {
469
- console.log(ansis.bold.green(` \u2022 ${i18n.ccr.ccrUiApiKey || "CCR UI API Key"}: ${apiKey}`));
470
- console.log(ansis.gray(` ${i18n.ccr.ccrUiApiKeyHint || "Use this API key to login to CCR UI"}`));
361
+ try {
362
+ console.log(ansis.blue(`${i18n.cometix.printingConfig}`));
363
+ const { stdout } = await execAsync(COMETIX_COMMANDS.PRINT_CONFIG);
364
+ console.log(stdout);
365
+ } catch (error) {
366
+ if (error.message.includes(`command not found: ${COMETIX_COMMAND_NAME}`)) {
367
+ console.error(ansis.red(`\u2717 ${i18n.cometix.commandNotFound}`));
368
+ } else {
369
+ console.error(ansis.red(`\u2717 ${i18n.cometix.printConfigFailed}: ${error}`));
370
+ }
371
+ throw error;
471
372
  }
472
- console.log("");
473
373
  }
474
- async function setupCcrConfiguration(scriptLang) {
475
- const i18n = getTranslation(scriptLang);
374
+
375
+ async function showCometixMenu(scriptLang) {
476
376
  try {
477
- const existingConfig = readCcrConfig();
478
- if (existingConfig) {
479
- console.log(ansis.blue(`\u2139 ${i18n.ccr.existingCcrConfig}`));
480
- let shouldBackupAndReconfigure = false;
481
- try {
482
- const result = await inquirer.prompt({
483
- type: "confirm",
484
- name: "overwrite",
485
- message: i18n.ccr.overwriteCcrConfig,
486
- default: false
487
- });
488
- shouldBackupAndReconfigure = result.overwrite;
489
- } catch (error) {
490
- if (error.name === "ExitPromptError") {
491
- console.log(ansis.yellow(i18n.common.cancelled));
492
- return false;
493
- }
494
- throw error;
495
- }
496
- if (!shouldBackupAndReconfigure) {
497
- console.log(ansis.yellow(`${i18n.ccr.keepingExistingConfig}`));
498
- await configureCcrProxy(existingConfig);
499
- return true;
377
+ const i18n = getTranslation(scriptLang);
378
+ console.log("\n" + ansis.cyan("\u2550".repeat(50)));
379
+ console.log(ansis.bold.cyan(` ${i18n.cometix.cometixMenuTitle}`));
380
+ console.log(ansis.cyan("\u2550".repeat(50)) + "\n");
381
+ console.log(` ${ansis.cyan("1.")} ${i18n.cometix.cometixMenuOptions.installOrUpdate} ${ansis.gray("- " + i18n.cometix.cometixMenuDescriptions.installOrUpdate)}`);
382
+ console.log(` ${ansis.cyan("2.")} ${i18n.cometix.cometixMenuOptions.printConfig} ${ansis.gray("- " + i18n.cometix.cometixMenuDescriptions.printConfig)}`);
383
+ console.log(` ${ansis.yellow("0.")} ${i18n.cometix.cometixMenuOptions.back}`);
384
+ console.log("");
385
+ const { choice } = await inquirer$1.prompt({
386
+ type: "input",
387
+ name: "choice",
388
+ message: i18n.common.enterChoice,
389
+ validate: (value) => {
390
+ const valid = ["1", "2", "0"];
391
+ return valid.includes(value) || i18n.common.invalidChoice;
500
392
  }
501
- backupCcrConfig(scriptLang);
502
- }
503
- const preset = await selectCcrPreset(scriptLang);
504
- if (!preset) {
505
- return false;
506
- }
507
- let config;
508
- if (preset === "skip") {
509
- console.log(ansis.yellow(`${i18n.ccr.skipConfiguring}`));
510
- config = {
511
- LOG: false,
512
- CLAUDE_PATH: "",
513
- HOST: "127.0.0.1",
514
- PORT: 3456,
515
- APIKEY: "sk-aico-x-ccr",
516
- API_TIMEOUT_MS: "600000",
517
- PROXY_URL: "",
518
- transformers: [],
519
- Providers: [],
520
- // Empty providers array
521
- Router: {
522
- // Empty router configuration - user will configure in CCR UI
523
- }
524
- };
525
- } else {
526
- config = await configureCcrWithPreset(preset, scriptLang);
393
+ });
394
+ switch (choice) {
395
+ case "1":
396
+ await installCometixLine(scriptLang);
397
+ break;
398
+ case "2":
399
+ await runCometixPrintConfig(scriptLang);
400
+ break;
401
+ case "0":
402
+ return false;
527
403
  }
528
- writeCcrConfig(config);
529
- console.log(ansis.green(`\u2714 ${i18n.ccr.ccrConfigSuccess}`));
530
- await configureCcrProxy(config);
531
- console.log(ansis.green(`\u2714 ${i18n.ccr.proxyConfigSuccess}`));
532
- await restartAndCheckCcrStatus(scriptLang);
533
- showConfigurationTips(scriptLang, config.APIKEY);
534
- try {
535
- addCompletedOnboarding();
536
- } catch (error) {
537
- console.error(ansis.red(i18n.configuration.failedToSetOnboarding), error);
404
+ if (choice !== "0") {
405
+ console.log("\n" + ansis.dim("\u2500".repeat(50)) + "\n");
406
+ const { continueInCometix } = await inquirer$1.prompt({
407
+ type: "confirm",
408
+ name: "continueInCometix",
409
+ message: i18n.common.returnToMenu,
410
+ default: true
411
+ });
412
+ if (continueInCometix) {
413
+ return await showCometixMenu(scriptLang);
414
+ }
538
415
  }
539
- return true;
416
+ return false;
540
417
  } catch (error) {
541
- if (error.name === "ExitPromptError") {
542
- console.log(ansis.yellow(i18n.common.cancelled));
543
- return false;
418
+ if (!handleExitPromptError(error)) {
419
+ handleGeneralError(error, scriptLang);
544
420
  }
545
- console.error(ansis.red(`${i18n.ccr.ccrConfigFailed}:`), error);
546
421
  return false;
547
422
  }
548
423
  }
549
- async function configureCcrFeature(scriptLang) {
550
- const i18n = getTranslation(scriptLang);
551
- const backupDir = backupExistingConfig();
552
- if (backupDir) {
553
- console.log(ansis.gray(`\u2714 ${i18n.configuration.backupSuccess}: ${backupDir}`));
554
- }
555
- await setupCcrConfiguration(scriptLang);
556
- }
557
424
 
558
425
  function handleCancellation(scriptLang) {
559
426
  const i18n = getTranslation(scriptLang);
@@ -746,14 +613,14 @@ async function configureAiMemoryFeature(scriptLang) {
746
613
  return;
747
614
  }
748
615
  if (option === "language") {
749
- const zcfConfig = readZcfConfig();
616
+ const aicoConfig = readAicoConfig();
750
617
  const aiOutputLang = await resolveAiOutputLanguage(
751
618
  scriptLang,
752
619
  void 0,
753
- zcfConfig
620
+ aicoConfig
754
621
  );
755
622
  applyAiLanguageDirective(aiOutputLang);
756
- updateZcfConfig({ aiOutputLang });
623
+ updateAicoConfig({ aiOutputLang });
757
624
  console.log(
758
625
  ansis.green(
759
626
  `\u2714 ${i18n.configuration.aiLanguageConfigured || "AI output language configured"}`
@@ -763,6 +630,17 @@ async function configureAiMemoryFeature(scriptLang) {
763
630
  await configureAiPersonality(scriptLang);
764
631
  }
765
632
  }
633
+ async function configureCCR(scriptLang) {
634
+ const i18n = getTranslation(scriptLang);
635
+ const backupDir = backupExistingConfig();
636
+ if (backupDir) {
637
+ console.log(ansis.gray(`\u2714 ${i18n.configuration.backupSuccess}: ${backupDir}`));
638
+ }
639
+ await configureCcrFeature(scriptLang);
640
+ }
641
+ async function configureCCometixLine(scriptLang) {
642
+ await showCometixMenu(scriptLang);
643
+ }
766
644
  async function configureEnvPermissionFeature(scriptLang) {
767
645
  const i18n = getTranslation(scriptLang);
768
646
  const { choice } = await inquirer.prompt({
@@ -928,6 +806,17 @@ async function updateAicoCli() {
928
806
  shell: isWindows
929
807
  // Windows 上使用 shell
930
808
  });
809
+ const claudeCodeUpdate = spawn(
810
+ "npm",
811
+ ["install", "-g", "@anthropic-ai/claude-code@latest", "--force"],
812
+ {
813
+ stdio: "ignore",
814
+ // 忽略输出,避免干扰主更新过程
815
+ cwd: process.cwd(),
816
+ shell: isWindows
817
+ }
818
+ );
819
+ claudeCodeUpdate.unref();
931
820
  const timeout = setTimeout(() => {
932
821
  console.log(ansis.yellow("\n\u26A0\uFE0F \u66F4\u65B0\u65F6\u95F4\u8F83\u957F\uFF0C\u53EF\u80FD\u9047\u5230\u7F51\u7EDC\u95EE\u9898"));
933
822
  console.log(ansis.cyan("\u{1F4A1} \u5EFA\u8BAE\u6309 Ctrl+C \u53D6\u6D88\uFF0C\u7136\u540E\u624B\u52A8\u6267\u884C:"));
@@ -981,16 +870,16 @@ async function update(options = {}) {
981
870
  displayBanner("Update configuration for Claude Code");
982
871
  }
983
872
  const scriptLang = await selectScriptLanguage();
984
- const zcfConfig = readZcfConfig();
873
+ const aicoConfig = readAicoConfig();
985
874
  const i18n = I18N[scriptLang];
986
875
  const configLang = options.configLang || "zh-CN";
987
- const aiOutputLang = await resolveAiOutputLanguage(scriptLang, options.aiOutputLang, zcfConfig);
876
+ const aiOutputLang = await resolveAiOutputLanguage(scriptLang, options.aiOutputLang, aicoConfig);
988
877
  console.log(ansis.cyan(`
989
878
  ${i18n.configuration.updatingPrompts}
990
879
  `));
991
880
  await updatePromptOnly(configLang, scriptLang, aiOutputLang);
992
881
  await selectAndInstallWorkflows(configLang, scriptLang);
993
- updateZcfConfig({
882
+ updateAicoConfig({
994
883
  version,
995
884
  preferredLang: scriptLang,
996
885
  aiOutputLang
@@ -1005,9 +894,10 @@ ${i18n.configuration.updatingPrompts}
1005
894
  async function showMainMenu() {
1006
895
  try {
1007
896
  displayBannerWithInfo();
1008
- const zcfConfig = await readZcfConfigAsync();
1009
- let scriptLang = zcfConfig?.preferredLang || await selectScriptLanguage();
897
+ const aicoConfig = await readAicoConfigAsync();
898
+ let scriptLang = aicoConfig?.preferredLang || await selectScriptLanguage();
1010
899
  const menuProcessors = {
900
+ // 基础配置 - 放在前面
1011
901
  "1": {
1012
902
  key: "1",
1013
903
  labelKey: "fullInit",
@@ -1022,34 +912,53 @@ async function showMainMenu() {
1022
912
  },
1023
913
  "3": {
1024
914
  key: "3",
1025
- labelKey: "configureMcp",
1026
- processor: () => configureMcpFeature(scriptLang),
915
+ labelKey: "updateVersion",
916
+ processor: () => updateAicoCli(),
1027
917
  section: "\u57FA\u7840\u914D\u7F6E"
1028
918
  },
919
+ // 个性化配置 - 放在后面
1029
920
  "4": {
1030
921
  key: "4",
1031
- labelKey: "configureAiMemory",
1032
- processor: () => configureAiMemoryFeature(scriptLang),
1033
- section: "\u57FA\u7840\u914D\u7F6E"
922
+ labelKey: "configureMcp",
923
+ processor: () => configureMcpFeature(scriptLang),
924
+ section: "\u4E2A\u6027\u5316\u914D\u7F6E"
1034
925
  },
1035
926
  "5": {
1036
927
  key: "5",
1037
- labelKey: "configureEnvPermission",
1038
- processor: () => configureEnvPermissionFeature(scriptLang),
1039
- section: "\u57FA\u7840\u914D\u7F6E"
928
+ labelKey: "configureAiMemory",
929
+ processor: () => configureAiMemoryFeature(scriptLang),
930
+ section: "\u4E2A\u6027\u5316\u914D\u7F6E"
1040
931
  },
1041
932
  "6": {
1042
933
  key: "6",
1043
- labelKey: "importWorkflow",
1044
- processor: () => update({ skipBanner: true }),
1045
- section: "\u57FA\u7840\u914D\u7F6E"
934
+ labelKey: "configureEnvPermission",
935
+ processor: () => configureEnvPermissionFeature(scriptLang),
936
+ section: "\u4E2A\u6027\u5316\u914D\u7F6E"
1046
937
  },
1047
938
  "7": {
1048
939
  key: "7",
1049
- labelKey: "updateVersion",
1050
- processor: () => updateAicoCli(),
1051
- section: "\u57FA\u7840\u914D\u7F6E"
940
+ labelKey: "importWorkflow",
941
+ processor: () => update({ skipBanner: true }),
942
+ section: "\u4E2A\u6027\u5316\u914D\u7F6E"
943
+ },
944
+ "8": {
945
+ key: "8",
946
+ labelKey: "configureCCR",
947
+ processor: () => configureCCR(scriptLang),
948
+ section: "\u4E2A\u6027\u5316\u914D\u7F6E"
949
+ },
950
+ "9": {
951
+ key: "9",
952
+ labelKey: "configureCCometixLine",
953
+ processor: () => configureCCometixLine(scriptLang),
954
+ section: "\u4E2A\u6027\u5316\u914D\u7F6E"
1052
955
  }
956
+ // "10": {
957
+ // key: "10",
958
+ // labelKey: "configureCCUsage",
959
+ // processor: () => configureCCUsage(scriptLang),
960
+ // section: "个性化配置",
961
+ // },
1053
962
  };
1054
963
  let exitMenu = false;
1055
964
  while (!exitMenu) {
@@ -1143,259 +1052,13 @@ ${i18n.common.returnToPrevious || "\u8FD4\u56DE\u4E0A\u4E00\u6B65"}`)
1143
1052
  }
1144
1053
  }
1145
1054
 
1146
- const execAsync = promisify$1(exec$1);
1147
- async function runCcrUi(scriptLang, apiKey) {
1148
- const i18n = I18N[scriptLang];
1149
- console.log(ansis.cyan(`
1150
- \u{1F5A5}\uFE0F ${i18n.ccr.startingCcrUi}`));
1151
- if (apiKey) {
1152
- console.log(ansis.bold.green(`
1153
- \u{1F511} ${i18n.ccr.ccrUiApiKey || "CCR UI API Key"}: ${apiKey}`));
1154
- console.log(ansis.gray(` ${i18n.ccr.ccrUiApiKeyHint || "Use this API key to login to CCR UI"}
1155
- `));
1156
- }
1157
- try {
1158
- const { stdout, stderr } = await execAsync("ccr ui");
1159
- if (stdout) console.log(stdout);
1160
- if (stderr) console.error(ansis.yellow(stderr));
1161
- console.log(ansis.green(`\u2714 ${i18n.ccr.ccrUiStarted}`));
1162
- } catch (error) {
1163
- console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`));
1164
- throw error;
1165
- }
1166
- }
1167
- async function runCcrStatus(scriptLang) {
1168
- const i18n = I18N[scriptLang];
1169
- console.log(ansis.cyan(`
1170
- \u{1F4CA} ${i18n.ccr.checkingCcrStatus}`));
1171
- try {
1172
- const { stdout, stderr } = await execAsync("ccr status");
1173
- if (stdout) {
1174
- console.log("\n" + ansis.bold(i18n.ccr.ccrStatusTitle));
1175
- console.log(stdout);
1176
- }
1177
- if (stderr) console.error(ansis.yellow(stderr));
1178
- } catch (error) {
1179
- console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`));
1180
- throw error;
1181
- }
1182
- }
1183
- async function runCcrRestart(scriptLang) {
1184
- const i18n = I18N[scriptLang];
1185
- console.log(ansis.cyan(`
1186
- \u{1F504} ${i18n.ccr.restartingCcr}`));
1187
- try {
1188
- const { stdout, stderr } = await execAsync("ccr restart");
1189
- if (stdout) console.log(stdout);
1190
- if (stderr) console.error(ansis.yellow(stderr));
1191
- console.log(ansis.green(`\u2714 ${i18n.ccr.ccrRestarted}`));
1192
- } catch (error) {
1193
- console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`));
1194
- throw error;
1195
- }
1196
- }
1197
- async function runCcrStart(scriptLang) {
1198
- const i18n = I18N[scriptLang];
1199
- console.log(ansis.cyan(`
1200
- \u25B6\uFE0F ${i18n.ccr.startingCcr}`));
1201
- try {
1202
- const { stdout, stderr } = await execAsync("ccr start");
1203
- if (stdout) console.log(stdout);
1204
- if (stderr) console.error(ansis.yellow(stderr));
1205
- console.log(ansis.green(`\u2714 ${i18n.ccr.ccrStarted}`));
1206
- } catch (error) {
1207
- console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`));
1208
- throw error;
1209
- }
1210
- }
1211
- async function runCcrStop(scriptLang) {
1212
- const i18n = I18N[scriptLang];
1213
- console.log(ansis.cyan(`
1214
- \u23F9\uFE0F ${i18n.ccr.stoppingCcr}`));
1215
- try {
1216
- const { stdout, stderr } = await execAsync("ccr stop");
1217
- if (stdout) console.log(stdout);
1218
- if (stderr) console.error(ansis.yellow(stderr));
1219
- console.log(ansis.green(`\u2714 ${i18n.ccr.ccrStopped}`));
1220
- } catch (error) {
1221
- console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`));
1222
- throw error;
1223
- }
1224
- }
1225
-
1226
- function isCcrConfigured() {
1227
- const CCR_CONFIG_FILE = join(homedir(), ".claude-code-router", "config.json");
1228
- if (!existsSync(CCR_CONFIG_FILE)) {
1229
- return false;
1230
- }
1231
- const config = readCcrConfig();
1232
- return config !== null && config.Providers && config.Providers.length > 0;
1233
- }
1234
- async function showCcrMenu(scriptLang) {
1235
- try {
1236
- const i18n = I18N[scriptLang];
1237
- console.log("\n" + ansis.cyan("\u2550".repeat(50)));
1238
- console.log(ansis.bold.cyan(` ${i18n.ccr.ccrMenuTitle}`));
1239
- console.log(ansis.cyan("\u2550".repeat(50)) + "\n");
1240
- console.log(` ${ansis.cyan("1.")} ${i18n.ccr.ccrMenuOptions.initCcr} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.initCcr)}`);
1241
- console.log(` ${ansis.cyan("2.")} ${i18n.ccr.ccrMenuOptions.startUi} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.startUi)}`);
1242
- console.log(` ${ansis.cyan("3.")} ${i18n.ccr.ccrMenuOptions.checkStatus} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.checkStatus)}`);
1243
- console.log(` ${ansis.cyan("4.")} ${i18n.ccr.ccrMenuOptions.restart} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.restart)}`);
1244
- console.log(` ${ansis.cyan("5.")} ${i18n.ccr.ccrMenuOptions.start} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.start)}`);
1245
- console.log(` ${ansis.cyan("6.")} ${i18n.ccr.ccrMenuOptions.stop} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.stop)}`);
1246
- console.log(` ${ansis.yellow("0.")} ${i18n.ccr.ccrMenuOptions.back}`);
1247
- console.log("");
1248
- const { choice } = await inquirer.prompt({
1249
- type: "input",
1250
- name: "choice",
1251
- message: i18n.common.enterChoice,
1252
- validate: (value) => {
1253
- const valid = ["1", "2", "3", "4", "5", "6", "0"];
1254
- return valid.includes(value) || i18n.common.invalidChoice;
1255
- }
1256
- });
1257
- switch (choice) {
1258
- case "1":
1259
- const ccrInstalled = await isCcrInstalled();
1260
- if (!ccrInstalled) {
1261
- console.log(ansis.yellow(`${i18n.ccr.installingCcr}`));
1262
- await installCcr(scriptLang);
1263
- } else {
1264
- console.log(ansis.green(`\u2714 ${i18n.ccr.ccrAlreadyInstalled}`));
1265
- }
1266
- await configureCcrFeature(scriptLang);
1267
- console.log(ansis.green(`
1268
- \u2714 ${i18n.ccr.ccrSetupComplete}`));
1269
- break;
1270
- case "2":
1271
- if (!isCcrConfigured()) {
1272
- console.log(ansis.yellow(`
1273
- \u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`));
1274
- console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."}
1275
- `));
1276
- } else {
1277
- const config = readCcrConfig();
1278
- await runCcrUi(scriptLang, config?.APIKEY);
1279
- }
1280
- break;
1281
- case "3":
1282
- if (!isCcrConfigured()) {
1283
- console.log(ansis.yellow(`
1284
- \u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`));
1285
- console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."}
1286
- `));
1287
- } else {
1288
- await runCcrStatus(scriptLang);
1289
- }
1290
- break;
1291
- case "4":
1292
- if (!isCcrConfigured()) {
1293
- console.log(ansis.yellow(`
1294
- \u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`));
1295
- console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."}
1296
- `));
1297
- } else {
1298
- await runCcrRestart(scriptLang);
1299
- }
1300
- break;
1301
- case "5":
1302
- if (!isCcrConfigured()) {
1303
- console.log(ansis.yellow(`
1304
- \u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`));
1305
- console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."}
1306
- `));
1307
- } else {
1308
- await runCcrStart(scriptLang);
1309
- }
1310
- break;
1311
- case "6":
1312
- if (!isCcrConfigured()) {
1313
- console.log(ansis.yellow(`
1314
- \u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`));
1315
- console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."}
1316
- `));
1317
- } else {
1318
- await runCcrStop(scriptLang);
1319
- }
1320
- break;
1321
- case "0":
1322
- return false;
1323
- }
1324
- if (choice !== "0") {
1325
- console.log("\n" + ansis.dim("\u2500".repeat(50)) + "\n");
1326
- const { continueInCcr } = await inquirer.prompt({
1327
- type: "confirm",
1328
- name: "continueInCcr",
1329
- message: i18n.common.returnToMenu || "Return to CCR menu?",
1330
- default: true
1331
- });
1332
- if (continueInCcr) {
1333
- return await showCcrMenu(scriptLang);
1334
- }
1335
- }
1336
- return false;
1337
- } catch (error) {
1338
- if (!handleExitPromptError(error)) {
1339
- handleGeneralError(error, scriptLang);
1340
- }
1341
- return false;
1342
- }
1343
- }
1344
-
1345
- function getValidLanguage(lang) {
1346
- return lang && lang in I18N ? lang : "en";
1347
- }
1348
-
1349
- async function executeCcusage(args = []) {
1350
- try {
1351
- let lang = "en";
1352
- try {
1353
- const zcfConfig = await readZcfConfigAsync();
1354
- const rawLang = zcfConfig?.preferredLang || "en";
1355
- lang = getValidLanguage(rawLang);
1356
- } catch {
1357
- lang = "en";
1358
- }
1359
- const i18n = I18N[lang];
1360
- const command = "npx";
1361
- const commandArgs = ["ccusage@latest", ...args || []];
1362
- console.log(ansis.cyan(i18n.tools.runningCcusage));
1363
- console.log(ansis.gray(`$ npx ccusage@latest ${(args || []).join(" ")}`));
1364
- console.log("");
1365
- await x(command, commandArgs, {
1366
- nodeOptions: {
1367
- stdio: "inherit"
1368
- }
1369
- });
1370
- } catch (error) {
1371
- let lang = "en";
1372
- try {
1373
- const zcfConfig = await readZcfConfigAsync();
1374
- const rawLang = zcfConfig?.preferredLang || "en";
1375
- lang = getValidLanguage(rawLang);
1376
- } catch {
1377
- lang = "en";
1378
- }
1379
- const i18n = I18N[lang];
1380
- console.error(ansis.red(i18n.tools.ccusageFailed));
1381
- console.error(ansis.yellow(i18n.tools.checkNetworkConnection));
1382
- if (process.env.DEBUG) {
1383
- console.error(ansis.gray(i18n.tools.errorDetails), error);
1384
- }
1385
- if (process.env.NODE_ENV !== "test") {
1386
- process.exit(1);
1387
- }
1388
- throw error;
1389
- }
1390
- }
1391
-
1392
1055
  async function ccr(options = {}) {
1393
1056
  try {
1394
1057
  if (!options.skipBanner) {
1395
1058
  displayBannerWithInfo();
1396
1059
  }
1397
- const zcfConfig = await readZcfConfigAsync();
1398
- const scriptLang = options.lang || zcfConfig?.preferredLang || await selectScriptLanguage();
1060
+ const aicoConfig = await readAicoConfigAsync();
1061
+ const scriptLang = options.lang || aicoConfig?.preferredLang || await selectScriptLanguage();
1399
1062
  const continueInCcr = await showCcrMenu(scriptLang);
1400
1063
  if (!continueInCcr && !options.skipBanner) {
1401
1064
  await showMainMenu();
@@ -1407,11 +1070,21 @@ async function ccr(options = {}) {
1407
1070
  }
1408
1071
  }
1409
1072
 
1073
+ async function checkUpdates(options = {}) {
1074
+ const scriptLang = options.lang || await selectScriptLanguage();
1075
+ try {
1076
+ await checkAndUpdateTools(scriptLang);
1077
+ } catch (error) {
1078
+ console.error(ansis.red("Error checking updates:"), error);
1079
+ process.exit(1);
1080
+ }
1081
+ }
1082
+
1410
1083
  function setupCommands(cli) {
1411
1084
  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) => {
1412
1085
  await handleDefaultCommand(lang, options);
1413
1086
  });
1414
- cli.command("init", "Initialize Claude Code configuration").alias("i").option("--lang, -l <lang>", "AICO 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").action(async (options) => {
1087
+ cli.command("init", "Initialize Claude Code configuration").alias("i").option("--lang, -l <lang>", "AICO 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) => {
1415
1088
  await handleInitCommand(options);
1416
1089
  });
1417
1090
  cli.command("update", "Update Claude Code prompts only").alias("u").option("--config-lang, -c <lang>", "Configuration language (zh-CN, en)").action(async (options) => {
@@ -1423,6 +1096,9 @@ function setupCommands(cli) {
1423
1096
  cli.command("ccu [...args]", "Run Claude Code usage analysis tool").allowUnknownOptions().action(async (args) => {
1424
1097
  await executeCcusage(args);
1425
1098
  });
1099
+ 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) => {
1100
+ await checkUpdates({ lang: options.lang });
1101
+ });
1426
1102
  cli.help((sections) => customizeHelp(sections));
1427
1103
  cli.version(version);
1428
1104
  }
@@ -1442,7 +1118,17 @@ async function handleInitCommand(options) {
1442
1118
  lang: options.lang,
1443
1119
  configLang: options.configLang,
1444
1120
  aiOutputLang: options.aiOutputLang,
1445
- force: options.force
1121
+ force: options.force,
1122
+ skipPrompt: options.skipPrompt,
1123
+ configAction: options.configAction,
1124
+ apiType: options.apiType,
1125
+ apiKey: options.apiKey,
1126
+ apiUrl: options.apiUrl,
1127
+ mcpServices: options.mcpServices,
1128
+ workflows: options.workflows,
1129
+ aiPersonality: options.aiPersonality,
1130
+ allLang: options.allLang,
1131
+ installCometixLine: options.installCometixLine
1446
1132
  });
1447
1133
  }
1448
1134
  async function handleUpdateCommand(options) {
@@ -1461,12 +1147,14 @@ function customizeHelp(sections) {
1461
1147
  "i"
1462
1148
  )} Initialize Claude Code configuration / \u521D\u59CB\u5316 Claude Code \u914D\u7F6E`,
1463
1149
  ` ${ansis.cyan("aico update")} | ${ansis.cyan("u")} Update workflow-related md files / \u4EC5\u66F4\u65B0\u5DE5\u4F5C\u6D41\u76F8\u5173md`,
1464
- ` ${ansis.cyan("aico ccr")} Configure Claude Code Router / \u914D\u7F6E\u6A21\u578B\u4EE3\u7406`,
1465
- ` ${ansis.cyan("aico ccu")} [args] Run Claude Code usage analysis / \u8FD0\u884C Claude Code \u7528\u91CF\u5206\u6790`,
1150
+ ` ${ansis.cyan("aico ccr")} Configure Claude Code Router for model proxy / \u914D\u7F6E\u6A21\u578B\u8DEF\u7531\u4EE3\u7406`,
1151
+ ` ${ansis.cyan("aico ccu")} [args] Claude Code usage statistics analysis / Claude Code \u7528\u91CF\u7EDF\u8BA1\u5206\u6790`,
1152
+ ` ${ansis.cyan("aico check-updates")} Check and update to latest versions / \u68C0\u67E5\u5E76\u66F4\u65B0\u5230\u6700\u65B0\u7248\u672C`,
1466
1153
  "",
1467
1154
  ansis.gray(" Shortcuts / \u5FEB\u6377\u65B9\u5F0F:"),
1468
1155
  ` ${ansis.cyan("aico i")} Quick init / \u5FEB\u901F\u521D\u59CB\u5316`,
1469
- ` ${ansis.cyan("aico u")} Quick update / \u5FEB\u901F\u66F4\u65B0`
1156
+ ` ${ansis.cyan("aico u")} Quick update / \u5FEB\u901F\u66F4\u65B0`,
1157
+ ` ${ansis.cyan("aico check")} Quick check updates / \u5FEB\u901F\u68C0\u67E5\u66F4\u65B0`
1470
1158
  ].join("\n")
1471
1159
  });
1472
1160
  sections.push({
@@ -1476,7 +1164,20 @@ function customizeHelp(sections) {
1476
1164
  ` ${ansis.green("--config-lang, -c")} <lang> Configuration language / \u914D\u7F6E\u8BED\u8A00 (zh-CN, en)`,
1477
1165
  ` ${ansis.green("--force, -f")} Force overwrite / \u5F3A\u5236\u8986\u76D6\u73B0\u6709\u914D\u7F6E`,
1478
1166
  ` ${ansis.green("--help, -h")} Display help / \u663E\u793A\u5E2E\u52A9`,
1479
- ` ${ansis.green("--version, -v")} Display version / \u663E\u793A\u7248\u672C`
1167
+ ` ${ansis.green("--version, -v")} Display version / \u663E\u793A\u7248\u672C`,
1168
+ "",
1169
+ ansis.gray(" Non-interactive mode (for CI/CD) / \u975E\u4EA4\u4E92\u6A21\u5F0F\uFF08\u9002\u7528\u4E8ECI/CD\uFF09:"),
1170
+ ` ${ansis.green("--skip-prompt, -s")} Skip all prompts / \u8DF3\u8FC7\u6240\u6709\u4EA4\u4E92\u63D0\u793A`,
1171
+ ` ${ansis.green("--api-type, -t")} <type> API type / API\u7C7B\u578B (auth_token, api_key, ccr_proxy, skip)`,
1172
+ ` ${ansis.green("--api-key, -k")} <key> API key (for both types) / API\u5BC6\u94A5\uFF08\u9002\u7528\u4E8E\u6240\u6709\u7C7B\u578B\uFF09`,
1173
+ ` ${ansis.green("--api-url, -u")} <url> Custom API URL / \u81EA\u5B9A\u4E49API\u5730\u5740`,
1174
+ ` ${ansis.green("--ai-output-lang, -a")} <lang> AI output language / AI\u8F93\u51FA\u8BED\u8A00`,
1175
+ ` ${ansis.green("--all-lang, -g")} <lang> Set all language params / \u7EDF\u4E00\u8BBE\u7F6E\u6240\u6709\u8BED\u8A00\u53C2\u6570`,
1176
+ ` ${ansis.green("--config-action, -o")} <action> Config handling / \u914D\u7F6E\u5904\u7406 (default: backup)`,
1177
+ ` ${ansis.green("--mcp-services, -m")} <list> MCP services / MCP\u670D\u52A1 (default: all non-key services)`,
1178
+ ` ${ansis.green("--workflows, -w")} <list> Workflows / \u5DE5\u4F5C\u6D41 (default: all workflows)`,
1179
+ ` ${ansis.green("--ai-personality, -p")} <type> AI personality / AI\u4E2A\u6027 (default: professional)`,
1180
+ ` ${ansis.green("--install-cometix-line, -x")} <value> Install statusline tool / \u5B89\u88C5\u72B6\u6001\u680F\u5DE5\u5177 (default: true)`
1480
1181
  ].join("\n")
1481
1182
  });
1482
1183
  sections.push({
@@ -1493,10 +1194,22 @@ function customizeHelp(sections) {
1493
1194
  ansis.gray(" # Update workflow-related md files only / \u4EC5\u66F4\u65B0\u5DE5\u4F5C\u6D41\u76F8\u5173md\u6587\u4EF6"),
1494
1195
  ` ${ansis.cyan("npx aico u")}`,
1495
1196
  "",
1197
+ ansis.gray(" # Configure Claude Code Router / \u914D\u7F6E Claude Code Router"),
1198
+ ` ${ansis.cyan("npx aico ccr")}`,
1199
+ "",
1496
1200
  ansis.gray(" # Run Claude Code usage analysis / \u8FD0\u884C Claude Code \u7528\u91CF\u5206\u6790"),
1497
1201
  ` ${ansis.cyan("npx aico ccu")} ${ansis.gray("# Daily usage (default)")}`,
1498
1202
  ` ${ansis.cyan("npx aico ccu monthly --json")}`,
1499
1203
  "",
1204
+ ansis.gray(" # Check and update tools / \u68C0\u67E5\u5E76\u66F4\u65B0\u5DE5\u5177"),
1205
+ ` ${ansis.cyan("npx aico check-updates")} ${ansis.gray("# Update Claude Code, CCR and CCometixLine")}`,
1206
+ ` ${ansis.cyan("npx aico check")}`,
1207
+ "",
1208
+ ansis.gray(" # Non-interactive mode (CI/CD) / \u975E\u4EA4\u4E92\u6A21\u5F0F\uFF08CI/CD\uFF09"),
1209
+ ` ${ansis.cyan('npx aico i --skip-prompt --api-type api_key --api-key "sk-ant-..."')}`,
1210
+ ` ${ansis.cyan('npx aico i --skip-prompt --all-lang zh-CN --api-type api_key --api-key "key"')}`,
1211
+ ` ${ansis.cyan("npx aico i --skip-prompt --api-type ccr_proxy")}`,
1212
+ "",
1500
1213
  ansis.gray(" # Force overwrite with Chinese config / \u5F3A\u5236\u4F7F\u7528\u4E2D\u6587\u914D\u7F6E\u8986\u76D6"),
1501
1214
  ` ${ansis.cyan("npx aico --init -c zh-CN -f")}`,
1502
1215
  ` ${ansis.cyan("npx aico --init --config-lang zh-CN --force")}`