ccjk 16.0.6 → 16.3.0

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.
Files changed (69) hide show
  1. package/README.md +72 -316
  2. package/dist/chunks/claude-code-config-manager.mjs +28 -7
  3. package/dist/chunks/claude-code-incremental-manager.mjs +2 -2
  4. package/dist/chunks/codex-config-switch.mjs +3 -3
  5. package/dist/chunks/codex-presets.mjs +98 -0
  6. package/dist/chunks/codex-provider-manager.mjs +4 -4
  7. package/dist/chunks/codex-runtime.mjs +246 -0
  8. package/dist/chunks/codex-uninstaller.mjs +2 -2
  9. package/dist/chunks/commands.mjs +1 -1
  10. package/dist/chunks/features.mjs +35 -15
  11. package/dist/chunks/simple-config.mjs +659 -148
  12. package/dist/cli.mjs +1700 -908
  13. package/dist/i18n/locales/en/clean.json +24 -0
  14. package/dist/i18n/locales/en/codex.json +24 -1
  15. package/dist/i18n/locales/en/configuration.json +27 -12
  16. package/dist/i18n/locales/en/hub.json +30 -0
  17. package/dist/i18n/locales/en/menu.json +32 -8
  18. package/dist/i18n/locales/en/workflow.json +13 -1
  19. package/dist/i18n/locales/zh-CN/clean.json +24 -0
  20. package/dist/i18n/locales/zh-CN/codex.json +24 -1
  21. package/dist/i18n/locales/zh-CN/configuration.json +27 -12
  22. package/dist/i18n/locales/zh-CN/hub.json +30 -0
  23. package/dist/i18n/locales/zh-CN/menu.json +32 -8
  24. package/dist/i18n/locales/zh-CN/workflow.json +13 -1
  25. package/dist/index.d.mts +3 -1
  26. package/dist/index.d.ts +3 -1
  27. package/dist/index.mjs +1 -1
  28. package/dist/shared/{ccjk.BSLlI-JL.mjs → ccjk.TC1_-qhV.mjs} +1 -1
  29. package/package.json +1 -1
  30. package/templates/common/output-styles/en/agents-md-baseline.md +28 -0
  31. package/templates/common/output-styles/en/plan-first.md +30 -0
  32. package/templates/common/output-styles/en/surgical-diff.md +27 -0
  33. package/templates/common/output-styles/en/verify-and-ship.md +31 -0
  34. package/templates/common/output-styles/zh-CN/agents-md-baseline.md +28 -0
  35. package/templates/common/output-styles/zh-CN/plan-first.md +30 -0
  36. package/templates/common/output-styles/zh-CN/surgical-diff.md +27 -0
  37. package/templates/common/output-styles/zh-CN/verify-and-ship.md +31 -0
  38. package/templates/common/workflow/bmad/en/bmad-init.md +275 -0
  39. package/templates/common/workflow/bmad/zh-CN/bmad-init.md +275 -0
  40. package/templates/common/workflow/codeReview/en/code-review.md +34 -0
  41. package/templates/common/workflow/codeReview/zh-CN/code-review.md +34 -0
  42. package/templates/common/workflow/continuousDelivery/en/continuous-delivery.md +628 -0
  43. package/templates/common/workflow/continuousDelivery/zh-CN/continuous-delivery.md +628 -0
  44. package/templates/common/workflow/essential/en/agents/ccjk-config-agent.md +187 -0
  45. package/templates/common/workflow/essential/en/agents/ccjk-mcp-agent.md +191 -0
  46. package/templates/common/workflow/essential/en/agents/ccjk-skill-agent.md +249 -0
  47. package/templates/common/workflow/essential/en/agents/ccjk-workflow-agent.md +277 -0
  48. package/templates/common/workflow/essential/en/agents/get-current-datetime.md +29 -0
  49. package/templates/common/workflow/essential/en/agents/init-architect.md +115 -0
  50. package/templates/common/workflow/essential/en/agents/planner.md +116 -0
  51. package/templates/common/workflow/essential/en/agents/teamagent.md +102 -0
  52. package/templates/common/workflow/essential/en/agents/ui-ux-designer.md +91 -0
  53. package/templates/common/workflow/essential/en/feat.md +92 -0
  54. package/templates/common/workflow/essential/en/init-project.md +53 -0
  55. package/templates/common/workflow/essential/zh-CN/agents/get-current-datetime.md +29 -0
  56. package/templates/common/workflow/essential/zh-CN/agents/init-architect.md +115 -0
  57. package/templates/common/workflow/essential/zh-CN/agents/planner.md +116 -0
  58. package/templates/common/workflow/essential/zh-CN/agents/teamagent.md +102 -0
  59. package/templates/common/workflow/essential/zh-CN/agents/ui-ux-designer.md +91 -0
  60. package/templates/common/workflow/essential/zh-CN/feat.md +315 -0
  61. package/templates/common/workflow/essential/zh-CN/init-project.md +53 -0
  62. package/templates/common/workflow/interview/en/interview.md +67 -0
  63. package/templates/common/workflow/interview/zh-CN/interview.md +67 -0
  64. package/templates/common/workflow/linearMethod/en/linear-method.md +651 -0
  65. package/templates/common/workflow/linearMethod/zh-CN/linear-method.md +750 -0
  66. package/templates/common/workflow/refactoringMaster/en/refactoring-master.md +516 -0
  67. package/templates/common/workflow/refactoringMaster/zh-CN/refactoring-master.md +810 -0
  68. package/templates/common/workflow/specFirstTDD/en/spec-first-tdd.md +364 -0
  69. package/templates/common/workflow/specFirstTDD/zh-CN/spec-first-tdd.md +364 -0
package/dist/cli.mjs CHANGED
@@ -1,21 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
  import cac from 'cac';
3
3
  import ansis from 'ansis';
4
- import { aq as ensureI18nInitialized, as as i18n, aX as readCcrConfig, aS as isCcrInstalled, aT as installCcr, aY as configureCcrFeature, av as promptBoolean, aZ as handleExitPromptError, a_ as handleGeneralError, a$ as COMETIX_COMMAND_NAME, b0 as COMETIX_COMMANDS, b1 as installCometixLine, at as addNumbersToChoices, b2 as checkAndUpdateTools, b3 as runCodexUpdate, b4 as resolveCodeType$1, aB as readJsonConfig, b5 as writeJsonConfig, c as CCJK_CONFIG_FILE, aM as readCcjkConfig, D as DEFAULT_CODE_TOOL_TYPE, a2 as isCodeToolType, b6 as displayBanner, aK as updateCcjkConfig, b7 as version, b8 as resolveAiOutputLanguage, aO as isClaudeFamilyCodeTool, b9 as updatePromptOnly, ba as selectAndInstallWorkflows, bb as checkClaudeCodeVersionAndPrompt, af as resolveCodeToolType$1, v as activeSettingsFile, C as CCJK_CONFIG_DIR, aL as changeLanguage, u as SUPPORTED_LANGS, L as LANG_LABELS, bc as STARTUP_CODE_TOOL_CHOICES, bd as displayBannerWithInfo, q as CODE_TOOL_BANNERS, _ as init, be as runCodexUninstall, bf as manageCodexMcp, bg as configureCodexApi, bh as runCodexWorkflowImportWithLanguageSelection, bi as runCodexFullInit, bj as switchCodexProvider, bk as listCodexProviders, aH as readCodexConfig, bl as switchToOfficialLogin, bm as switchToProvider, bn as readCcjkConfigAsync, bo as initI18n, bp as selectScriptLanguage } from './chunks/simple-config.mjs';
4
+ import { as as ensureI18nInitialized, au as i18n, b2 as readCcrConfig, aZ as isCcrInstalled, a_ as installCcr, b3 as configureCcrFeature, ax as promptBoolean, b4 as handleExitPromptError, b5 as handleGeneralError, o as CODEX_DIR, d as CLAUDE_DIR, i as CLAVUE_DIR, al as settingsFileForTool, b6 as MCP_SERVICE_CONFIGS, av as addNumbersToChoices, aT as readCcjkConfig, aM as backupCodexComplete, b7 as getBackupMessage, b8 as deleteAllCodexMcpServices, aL as readCodexConfig, ad as readMcpConfig, az as exists, b9 as readDir, ba as isDirectory, aB as readFile, p as CODEX_PROMPTS_DIR, bb as deleteCodexMcpService, ar as writeMcpConfig, bc as listCodexMcpServiceIds, l as CODEX_AGENTS_FILE, ag as resolveCodeToolType$1, w as activeSettingsFile, aF as readJsonConfig, bd as displayBanner, be as runCodexUpdate, aP as updateCcjkConfig, bf as version, bg as resolveAiOutputLanguage, aV as isClaudeFamilyCodeTool, bh as updatePromptOnly, bi as selectAndInstallWorkflows, bj as checkClaudeCodeVersionAndPrompt, D as DEFAULT_CODE_TOOL_TYPE, a3 as isCodeToolType, bk as runCodexWorkflowImportWithLanguageSelection, bl as runCodexFullInit, $ as init, bm as manageCodexMcp, bn as configureCodexApi, bo as checkAndUpdateTools, bp as resolveCodeType$1, bq as writeJsonConfig, c as CCJK_CONFIG_FILE, C as CCJK_CONFIG_DIR, aQ as changeLanguage, v as SUPPORTED_LANGS, L as LANG_LABELS, br as STARTUP_CODE_TOOL_CHOICES, bs as displayBannerWithInfo, r as CODE_TOOL_BANNERS, bt as runCodexUninstall, bu as switchCodexProvider, bv as listCodexProviders, bw as switchToOfficialLogin, bx as switchToProvider, by as listProviderProfiles, bz as getActiveProviderProfileId, bA as getProviderProfile, bB as readCredentials, bC as readCcjkConfigAsync, bD as initI18n, bE as selectScriptLanguage } from './chunks/simple-config.mjs';
5
5
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
6
6
  import { homedir } from 'node:os';
7
7
  import inquirer from 'inquirer';
8
8
  import { join } from 'pathe';
9
9
  import { runCcrStop, runCcrStart, runCcrRestart, runCcrStatus, runCcrUi } from './chunks/commands.mjs';
10
- import { changeScriptLanguageFeature, configureEnvPermissionFeature, configureAiMemoryFeature, configureDefaultModelFeature, configureMcpFeature, configureApiFeature, configureCodexAiMemoryFeature, configureCodexDefaultModelFeature } from './chunks/features.mjs';
11
- import process$1 from 'node:process';
12
- import { x, exec as exec$1 } from 'tinyexec';
13
- import { exec, spawn, execSync, spawnSync } from 'node:child_process';
14
- import { promisify } from 'node:util';
15
- import { pathExists } from 'fs-extra';
10
+ import { detectCodexRuntimes, scanCodexConfigDoctorFindings, printCodexReloadHint } from './chunks/codex-runtime.mjs';
16
11
  import { m as moveToTrash } from './shared/ccjk.DGjQxTq_.mjs';
17
- import { g as getClaudeFamilyRuntimeLabel } from './shared/ccjk.BSLlI-JL.mjs';
12
+ import { g as getClaudeFamilyRuntimeLabel } from './shared/ccjk.TC1_-qhV.mjs';
13
+ import { execSync, spawnSync } from 'node:child_process';
18
14
  import { ClaudeCodeConfigManager } from './chunks/claude-code-config-manager.mjs';
15
+ import { configureCodexAiMemoryFeature, configureCodexDefaultModelFeature, configureEnvPermissionFeature, configureAiMemoryFeature, configureDefaultModelFeature, configureMcpFeature, configureApiFeature, changeScriptLanguageFeature } from './chunks/features.mjs';
16
+ import process$1 from 'node:process';
17
+ import { pathExists } from 'fs-extra';
18
+ import { exec, x } from 'tinyexec';
19
+ import 'node:util';
19
20
  import 'dayjs';
20
21
  import 'node:url';
21
22
  import 'inquirer-toggle';
@@ -148,201 +149,1332 @@ ${ansis.dim("\u2500".repeat(50))}
148
149
  }
149
150
  }
150
151
 
151
- async function executeCcusage(args = []) {
152
- try {
153
- const command = "npx";
154
- const commandArgs = ["ccusage@latest", ...args || []];
155
- console.log(ansis.cyan(i18n.t("tools:runningCcusage")));
156
- console.log(ansis.gray(`$ npx ccusage@latest ${(args || []).join(" ")}`));
157
- console.log("");
158
- await x(command, commandArgs, {
159
- nodeOptions: {
160
- stdio: "inherit"
161
- }
162
- });
163
- } catch (error) {
164
- console.error(ansis.red(i18n.t("tools:ccusageFailed")));
165
- console.error(ansis.yellow(i18n.t("tools:checkNetworkConnection")));
166
- if (process$1.env.DEBUG) {
167
- console.error(ansis.gray(i18n.t("tools:errorDetails")), error);
152
+ const GROK_DIR = join(homedir(), ".grok");
153
+ const AGENTS_SKILLS_DIR = join(homedir(), ".agents", "skills");
154
+ const CLAUDE_FAMILY_CAPABILITIES = {
155
+ fullInit: true,
156
+ updateWorkflow: true,
157
+ configureApi: true,
158
+ configureMcp: true,
159
+ configureModel: true,
160
+ configureAiMemory: true,
161
+ configureEnvPermission: true,
162
+ cleanEnvironment: true,
163
+ uninstall: true,
164
+ checkUpdates: true,
165
+ setupPresets: false
166
+ };
167
+ const CLAUDE_FAMILY_DOCTOR = [
168
+ "mcp-unmanaged",
169
+ "mcp-broken",
170
+ "mcp-bloat",
171
+ "skill-missing-file",
172
+ "skill-empty"
173
+ ];
174
+ const CLAUDE_FAMILY_OPERATOR$1 = [
175
+ "init-full",
176
+ "update-workflow",
177
+ "configure-api",
178
+ "configure-mcp",
179
+ "configure-model",
180
+ "configure-ai-memory",
181
+ "configure-env-permission",
182
+ "clean-environment"
183
+ ];
184
+ const TOOL_MATRIX = {
185
+ clavue: {
186
+ id: "clavue",
187
+ displayName: "Clavue",
188
+ configRoot: CLAVUE_DIR,
189
+ configFile: settingsFileForTool("clavue"),
190
+ skillsDirs: [join(CLAVUE_DIR, "skills"), AGENTS_SKILLS_DIR],
191
+ mcpFormat: "settings-json",
192
+ profileStorage: "settings-json",
193
+ roles: ["both"],
194
+ capabilities: { ...CLAUDE_FAMILY_CAPABILITIES },
195
+ doctorChecks: [...CLAUDE_FAMILY_DOCTOR],
196
+ operatorActions: [...CLAUDE_FAMILY_OPERATOR$1]
197
+ },
198
+ "claude-code": {
199
+ id: "claude-code",
200
+ displayName: "Claude Code",
201
+ configRoot: CLAUDE_DIR,
202
+ configFile: settingsFileForTool("claude-code"),
203
+ skillsDirs: [join(CLAUDE_DIR, "skills"), AGENTS_SKILLS_DIR],
204
+ mcpFormat: "settings-json",
205
+ profileStorage: "settings-json",
206
+ roles: ["both"],
207
+ capabilities: { ...CLAUDE_FAMILY_CAPABILITIES },
208
+ doctorChecks: [...CLAUDE_FAMILY_DOCTOR],
209
+ operatorActions: [...CLAUDE_FAMILY_OPERATOR$1]
210
+ },
211
+ codex: {
212
+ id: "codex",
213
+ displayName: "Codex (CLI / \u684C\u9762 / IDE)",
214
+ configRoot: CODEX_DIR,
215
+ configFile: settingsFileForTool("codex"),
216
+ skillsDirs: [join(CODEX_DIR, "skills")],
217
+ mcpFormat: "config-toml",
218
+ profileStorage: "config-toml",
219
+ roles: ["both"],
220
+ capabilities: {
221
+ fullInit: true,
222
+ updateWorkflow: true,
223
+ configureApi: true,
224
+ configureMcp: true,
225
+ configureModel: true,
226
+ configureAiMemory: true,
227
+ configureEnvPermission: false,
228
+ cleanEnvironment: true,
229
+ uninstall: true,
230
+ checkUpdates: true,
231
+ setupPresets: true
232
+ },
233
+ doctorChecks: [
234
+ "runtime-status",
235
+ "config-feature-risk",
236
+ "mcp-unmanaged",
237
+ "mcp-broken",
238
+ "mcp-orphan-toml",
239
+ "mcp-bloat",
240
+ "skill-missing-file",
241
+ "skill-empty",
242
+ "prompt-stale",
243
+ "agents-file-stale"
244
+ ],
245
+ operatorActions: [
246
+ "init-preset-clean",
247
+ "init-preset-optimized",
248
+ "init-preset-custom",
249
+ "update-workflow",
250
+ "configure-api",
251
+ "configure-mcp",
252
+ "configure-model",
253
+ "configure-ai-memory",
254
+ "clean-environment"
255
+ ]
256
+ },
257
+ grok: {
258
+ id: "grok",
259
+ displayName: "Grok CLI",
260
+ configRoot: GROK_DIR,
261
+ configFile: join(GROK_DIR, "config.toml"),
262
+ skillsDirs: [
263
+ join(GROK_DIR, "skills"),
264
+ join(GROK_DIR, "bundled", "skills")
265
+ ],
266
+ mcpFormat: "none",
267
+ profileStorage: "ccjk-profile",
268
+ roles: ["both"],
269
+ capabilities: {
270
+ fullInit: true,
271
+ updateWorkflow: false,
272
+ configureApi: true,
273
+ configureMcp: false,
274
+ configureModel: false,
275
+ configureAiMemory: false,
276
+ configureEnvPermission: false,
277
+ cleanEnvironment: true,
278
+ uninstall: false,
279
+ checkUpdates: false,
280
+ setupPresets: false
281
+ },
282
+ doctorChecks: [
283
+ "skill-purge-all",
284
+ "grok-auth-status"
285
+ ],
286
+ operatorActions: [
287
+ "save-ccjk-profile",
288
+ "launch-with-profile",
289
+ "clean-environment"
290
+ ]
291
+ }
292
+ };
293
+
294
+ const MANAGED_MCP_IDS = new Set(MCP_SERVICE_CONFIGS.map((service) => service.id.toLowerCase()));
295
+ function skillDirsForTool(tool) {
296
+ if (tool === "agents")
297
+ return TOOL_MATRIX.clavue.skillsDirs.filter((dir) => dir.includes(".agents"));
298
+ if (tool === "grok")
299
+ return TOOL_MATRIX.grok.skillsDirs;
300
+ if (tool === "codex")
301
+ return TOOL_MATRIX.codex.skillsDirs;
302
+ if (tool === "claude")
303
+ return TOOL_MATRIX["claude-code"].skillsDirs.filter((dir) => !dir.includes(".agents"));
304
+ return [];
305
+ }
306
+ function scanSkillDirectory(baseDir, tool) {
307
+ const results = [];
308
+ if (!exists(baseDir))
309
+ return results;
310
+ for (const entry of readDir(baseDir)) {
311
+ const fullPath = join(baseDir, entry);
312
+ if (!isDirectory(fullPath))
313
+ continue;
314
+ const skillFile = join(fullPath, "SKILL.md");
315
+ if (!exists(skillFile)) {
316
+ results.push({
317
+ id: `skill:${tool}:${entry}:missing-skill-md`,
318
+ category: "skill",
319
+ tool,
320
+ label: entry,
321
+ path: fullPath,
322
+ reason: i18n.t("clean:reason.skillMissingFile"),
323
+ checked: true
324
+ });
325
+ continue;
326
+ }
327
+ const content = readFile(skillFile).trim();
328
+ if (content.length < 40) {
329
+ results.push({
330
+ id: `skill:${tool}:${entry}:empty-skill`,
331
+ category: "skill",
332
+ tool,
333
+ label: entry,
334
+ path: fullPath,
335
+ reason: i18n.t("clean:reason.skillEmpty"),
336
+ checked: true
337
+ });
168
338
  }
169
- if (process$1.env.NODE_ENV !== "test") {
170
- process$1.exit(1);
339
+ }
340
+ return results;
341
+ }
342
+ function scanCodexMcpCandidates() {
343
+ const config = readCodexConfig();
344
+ if (!config?.mcpServices?.length)
345
+ return [];
346
+ const seen = /* @__PURE__ */ new Set();
347
+ const results = [];
348
+ for (const service of config.mcpServices) {
349
+ const id = service.id.toLowerCase();
350
+ if (seen.has(id)) {
351
+ results.push({
352
+ id: `mcp:codex:${id}:duplicate`,
353
+ category: "mcp",
354
+ tool: "codex",
355
+ label: service.id,
356
+ configKey: service.id,
357
+ reason: i18n.t("clean:reason.mcpDuplicate"),
358
+ checked: true
359
+ });
360
+ }
361
+ seen.add(id);
362
+ const hasCommand = Boolean(service.command?.trim());
363
+ const hasUrl = Boolean(service.url?.trim());
364
+ if (!hasCommand && !hasUrl) {
365
+ results.push({
366
+ id: `mcp:codex:${id}:broken`,
367
+ category: "mcp",
368
+ tool: "codex",
369
+ label: service.id,
370
+ configKey: service.id,
371
+ reason: i18n.t("clean:reason.mcpBroken"),
372
+ checked: true
373
+ });
374
+ continue;
375
+ }
376
+ if (!MANAGED_MCP_IDS.has(id)) {
377
+ results.push({
378
+ id: `mcp:codex:${id}:unmanaged`,
379
+ category: "mcp",
380
+ tool: "codex",
381
+ label: service.id,
382
+ configKey: service.id,
383
+ reason: i18n.t("clean:reason.mcpUnmanaged"),
384
+ checked: true
385
+ });
171
386
  }
172
- throw error;
173
387
  }
388
+ if (config.mcpServices.length > 3) {
389
+ for (const service of config.mcpServices) {
390
+ const id = service.id.toLowerCase();
391
+ if (results.some((item) => item.configKey === service.id))
392
+ continue;
393
+ results.push({
394
+ id: `mcp:codex:${id}:bloat`,
395
+ category: "mcp",
396
+ tool: "codex",
397
+ label: service.id,
398
+ configKey: service.id,
399
+ reason: i18n.t("clean:reason.mcpBloat", { count: config.mcpServices.length }),
400
+ checked: false
401
+ });
402
+ }
403
+ }
404
+ return results;
405
+ }
406
+ function scanClaudeMcpCandidates() {
407
+ const config = readMcpConfig("claude-code");
408
+ if (!config?.mcpServers)
409
+ return [];
410
+ const results = [];
411
+ const entries = Object.entries(config.mcpServers);
412
+ if (entries.length > 3) {
413
+ for (const [name] of entries) {
414
+ results.push({
415
+ id: `mcp:claude:${name}:bloat`,
416
+ category: "mcp",
417
+ tool: "claude",
418
+ label: name,
419
+ configKey: name,
420
+ reason: i18n.t("clean:reason.mcpBloat", { count: entries.length }),
421
+ checked: false
422
+ });
423
+ }
424
+ }
425
+ for (const [name, server] of entries) {
426
+ const hasCommand = Boolean(server.command?.trim());
427
+ const hasUrl = Boolean(server.url?.trim());
428
+ if (!hasCommand && !hasUrl) {
429
+ results.push({
430
+ id: `mcp:claude:${name}:broken`,
431
+ category: "mcp",
432
+ tool: "claude",
433
+ label: name,
434
+ configKey: name,
435
+ reason: i18n.t("clean:reason.mcpBroken"),
436
+ checked: true
437
+ });
438
+ continue;
439
+ }
440
+ if (!MANAGED_MCP_IDS.has(name.toLowerCase())) {
441
+ const already = results.some((item) => item.configKey === name);
442
+ if (!already) {
443
+ results.push({
444
+ id: `mcp:claude:${name}:unmanaged`,
445
+ category: "mcp",
446
+ tool: "claude",
447
+ label: name,
448
+ configKey: name,
449
+ reason: i18n.t("clean:reason.mcpUnmanaged"),
450
+ checked: true
451
+ });
452
+ }
453
+ }
454
+ }
455
+ return results;
174
456
  }
175
-
176
- const execAsync = promisify(exec);
177
- async function runCometixPrintConfig() {
457
+ function scanCodexPromptCandidates() {
458
+ if (!exists(CODEX_PROMPTS_DIR))
459
+ return [];
460
+ return readDir(CODEX_PROMPTS_DIR).filter((file) => file.endsWith(".md")).map((file) => {
461
+ const fullPath = join(CODEX_PROMPTS_DIR, file);
462
+ return {
463
+ id: `prompt:codex:${file}`,
464
+ category: "prompt",
465
+ tool: "codex",
466
+ label: file,
467
+ path: fullPath,
468
+ reason: i18n.t("clean:reason.promptInstalled"),
469
+ checked: false
470
+ };
471
+ });
472
+ }
473
+ function scanAllSkillDirectories(baseDir, tool) {
474
+ if (!exists(baseDir))
475
+ return [];
476
+ const results = [];
477
+ for (const entry of readDir(baseDir)) {
478
+ if (entry === "." || entry === "..")
479
+ continue;
480
+ const fullPath = join(baseDir, entry);
481
+ if (!isDirectory(fullPath))
482
+ continue;
483
+ results.push({
484
+ id: `skill:${tool}:${entry}:all`,
485
+ category: "skill",
486
+ tool,
487
+ label: entry,
488
+ path: fullPath,
489
+ reason: i18n.t("clean:reason.skillPurgeAll"),
490
+ checked: true
491
+ });
492
+ }
493
+ return results;
494
+ }
495
+ function scanAgentsFileCandidates() {
496
+ const files = [
497
+ CODEX_AGENTS_FILE,
498
+ join(TOOL_MATRIX.codex.configRoot, "AGENTS.override.md")
499
+ ];
500
+ const results = [];
501
+ for (const filePath of files) {
502
+ if (!exists(filePath))
503
+ continue;
504
+ const name = filePath.split("/").pop() || filePath;
505
+ results.push({
506
+ id: `agents-file:codex:${name}`,
507
+ category: "agents-file",
508
+ tool: "codex",
509
+ label: name,
510
+ path: filePath,
511
+ reason: i18n.t("clean:reason.agentsFileStale"),
512
+ checked: true
513
+ });
514
+ }
515
+ return results;
516
+ }
517
+ function scanAllCodexMcpCandidates() {
518
+ const parsedIds = new Set(
519
+ (readCodexConfig()?.mcpServices || []).map((service) => service.id.toLowerCase())
520
+ );
521
+ const rawIds = listCodexMcpServiceIds();
522
+ const ids = /* @__PURE__ */ new Set();
523
+ for (const id of rawIds)
524
+ ids.add(id);
525
+ for (const id of parsedIds)
526
+ ids.add(id);
527
+ return Array.from(ids).map((id) => ({
528
+ id: `mcp:codex:${id.toLowerCase()}:all`,
529
+ category: "mcp",
530
+ tool: "codex",
531
+ label: id,
532
+ configKey: id,
533
+ reason: parsedIds.has(id.toLowerCase()) ? i18n.t("clean:reason.mcpPurgeAll") : i18n.t("clean:reason.mcpOrphan"),
534
+ checked: true
535
+ }));
536
+ }
537
+ function scanAllClaudeMcpCandidates() {
538
+ const config = readMcpConfig("claude-code");
539
+ if (!config?.mcpServers)
540
+ return [];
541
+ return Object.keys(config.mcpServers).map((name) => ({
542
+ id: `mcp:claude:${name}:all`,
543
+ category: "mcp",
544
+ tool: "claude",
545
+ label: name,
546
+ configKey: name,
547
+ reason: i18n.t("clean:reason.mcpPurgeAll"),
548
+ checked: true
549
+ }));
550
+ }
551
+ function scanPurgeAllEnvironment() {
178
552
  ensureI18nInitialized();
179
- try {
180
- console.log(ansis.blue(`${i18n.t("cometix:printingConfig")}`));
181
- const { stdout } = await execAsync(COMETIX_COMMANDS.PRINT_CONFIG);
182
- console.log(stdout);
183
- } catch (error) {
184
- if (error.message.includes(`command not found: ${COMETIX_COMMAND_NAME}`)) {
185
- console.error(ansis.red(`\u2717 ${i18n.t("cometix:commandNotFound")}`));
186
- } else {
187
- console.error(ansis.red(`\u2717 ${i18n.t("cometix:printConfigFailed")}: ${error}`));
553
+ const candidates = [
554
+ ...scanAllCodexMcpCandidates(),
555
+ ...scanAllClaudeMcpCandidates(),
556
+ ...scanAllSkillDirectories(skillDirsForTool("codex")[0], "codex"),
557
+ ...skillDirsForTool("claude").flatMap((dir) => scanAllSkillDirectories(dir, "claude")),
558
+ ...skillDirsForTool("agents").flatMap((dir) => scanAllSkillDirectories(dir, "agents")),
559
+ ...skillDirsForTool("grok").flatMap((dir) => scanAllSkillDirectories(dir, "grok")),
560
+ ...scanCodexPromptCandidates().map((item) => ({ ...item, checked: true, reason: i18n.t("clean:reason.promptPurgeAll") })),
561
+ ...scanAgentsFileCandidates()
562
+ ];
563
+ const unique = /* @__PURE__ */ new Map();
564
+ for (const item of candidates)
565
+ unique.set(item.id, item);
566
+ return { candidates: Array.from(unique.values()) };
567
+ }
568
+ const SCAN_SECTION_KEYS = {
569
+ mcp: "hub:doctor.scanSection.mcp",
570
+ skill: "hub:doctor.scanSection.skill",
571
+ prompt: "hub:doctor.scanSection.prompt",
572
+ "agents-file": "hub:doctor.scanSection.agents",
573
+ config: "hub:doctor.scanSection.config"
574
+ };
575
+ function scanCodexConfigCandidates() {
576
+ const findings = scanCodexConfigDoctorFindings();
577
+ return findings.filter((finding) => finding.severity === "warn").map((finding) => {
578
+ const label = finding.messageParams ? i18n.t(finding.messageKey, finding.messageParams) : i18n.t(finding.messageKey);
579
+ return {
580
+ id: `config:codex:${finding.id}`,
581
+ category: "config",
582
+ tool: "codex",
583
+ label,
584
+ reason: i18n.t("clean:reason.configDoctor"),
585
+ checked: true
586
+ };
587
+ });
588
+ }
589
+ function printCodexRuntimeStatus() {
590
+ ensureI18nInitialized();
591
+ const summary = detectCodexRuntimes();
592
+ console.log(ansis.white(` ${i18n.t("hub:doctor.scanSection.runtime")}`));
593
+ console.log(ansis.gray(` ${i18n.t("codex:runtime.sharedConfig", { path: summary.configHome })}`));
594
+ if (summary.configHomeFromEnv)
595
+ console.log(ansis.gray(` ${i18n.t("codex:runtime.codexHomeEnv")}`));
596
+ for (const runtime of summary.runtimes) {
597
+ const label = i18n.t(`codex:runtime.kind.${runtime.kind}`);
598
+ if (!runtime.detected) {
599
+ console.log(ansis.dim(` ${label}: ${i18n.t("codex:runtime.notDetected")}`));
600
+ continue;
601
+ }
602
+ const pathText = runtime.path ? ansis.gray(` (${runtime.path})`) : "";
603
+ const weak = runtime.weakSignal ? ansis.yellow(` \u2014 ${i18n.t("codex:runtime.weakDesktopSignal")}`) : "";
604
+ console.log(` ${label}: ${ansis.green(i18n.t("codex:runtime.detected"))}${pathText}${weak}`);
605
+ }
606
+ console.log("");
607
+ }
608
+ function printEnvironmentScanReport() {
609
+ ensureI18nInitialized();
610
+ const smart = scanEnvironmentIssues(false).candidates;
611
+ const all = scanEnvironmentIssues(true).candidates;
612
+ const configFindings = scanCodexConfigCandidates();
613
+ console.log(ansis.cyan(`
614
+ ${i18n.t("hub:doctor.scanReport")}
615
+ `));
616
+ printCodexRuntimeStatus();
617
+ console.log(ansis.gray(` ${i18n.t("hub:doctor.scanHint", { smart: smart.length, all: all.length })}
618
+ `));
619
+ if (configFindings.length > 0) {
620
+ console.log(ansis.white(` ${i18n.t("hub:doctor.scanSection.config")} (${configFindings.length})`));
621
+ for (const item of configFindings)
622
+ console.log(` ${ansis.yellow("[codex]")} ${item.label}`);
623
+ console.log("");
624
+ }
625
+ if (smart.length === 0 && configFindings.length === 0) {
626
+ console.log(ansis.green(` ${i18n.t("clean:nothingFound")}
627
+ `));
628
+ return false;
629
+ }
630
+ if (smart.length === 0) {
631
+ console.log(ansis.green(` ${i18n.t("clean:nothingFound")}
632
+ `));
633
+ return configFindings.length > 0;
634
+ }
635
+ const grouped = /* @__PURE__ */ new Map();
636
+ for (const item of smart) {
637
+ const list = grouped.get(item.category) || [];
638
+ list.push(item);
639
+ grouped.set(item.category, list);
640
+ }
641
+ for (const [category, items] of grouped) {
642
+ console.log(ansis.white(` ${i18n.t(SCAN_SECTION_KEYS[category])} (${items.length})`));
643
+ for (const item of items) {
644
+ console.log(
645
+ ` ${ansis.cyan(`[${item.tool}]`)} ${item.label} ${ansis.gray(`\u2014 ${item.reason}`)}`
646
+ );
188
647
  }
189
- throw error;
648
+ console.log("");
190
649
  }
650
+ return true;
191
651
  }
192
- async function runCometixTuiConfig() {
652
+ function scanEnvironmentIssues(purgeAll = false) {
193
653
  ensureI18nInitialized();
194
- return new Promise((resolve, reject) => {
195
- console.log(ansis.blue(`${i18n.t("cometix:enteringTuiConfig")}`));
196
- const child = spawn(COMETIX_COMMAND_NAME, ["-c"], {
197
- stdio: "inherit",
198
- // This allows the TUI to interact directly with the terminal
199
- shell: true
200
- });
201
- child.on("close", (code) => {
202
- if (code === 0) {
203
- console.log(ansis.green(`\u2713 ${i18n.t("cometix:tuiConfigSuccess")}`));
204
- resolve();
205
- } else {
206
- const error = new Error(`${COMETIX_COMMAND_NAME} -c exited with code ${code}`);
207
- console.error(ansis.red(`\u2717 ${i18n.t("cometix:tuiConfigFailed")}: ${error.message}`));
208
- reject(error);
654
+ if (purgeAll)
655
+ return scanPurgeAllEnvironment();
656
+ const candidates = [
657
+ ...scanCodexMcpCandidates(),
658
+ ...scanClaudeMcpCandidates(),
659
+ ...skillDirsForTool("agents").flatMap((dir) => scanSkillDirectory(dir, "agents")),
660
+ ...skillDirsForTool("claude").flatMap((dir) => scanSkillDirectory(dir, "claude")),
661
+ ...skillDirsForTool("codex").flatMap((dir) => scanSkillDirectory(dir, "codex")),
662
+ ...scanCodexPromptCandidates()
663
+ ];
664
+ const unique = /* @__PURE__ */ new Map();
665
+ for (const item of candidates)
666
+ unique.set(item.id, item);
667
+ return { candidates: Array.from(unique.values()) };
668
+ }
669
+ async function removeCodexMcp(serviceId) {
670
+ deleteCodexMcpService(serviceId);
671
+ }
672
+ async function removeClaudeMcp(serviceId) {
673
+ const config = readMcpConfig("claude-code");
674
+ if (!config?.mcpServers?.[serviceId])
675
+ return;
676
+ const next = { ...config, mcpServers: { ...config.mcpServers } };
677
+ delete next.mcpServers[serviceId];
678
+ writeMcpConfig(next, "claude-code");
679
+ }
680
+ async function executeCleanup(selected, options = {}) {
681
+ const removed = [];
682
+ const errors = [];
683
+ const backupPath = backupCodexComplete();
684
+ if (backupPath)
685
+ console.log(ansis.gray(getBackupMessage(backupPath)));
686
+ const codexMcpItems = selected.filter((item) => item.category === "mcp" && item.tool === "codex");
687
+ if (options.purgeAllMcp && codexMcpItems.length > 0) {
688
+ try {
689
+ deleteAllCodexMcpServices();
690
+ for (const item of codexMcpItems)
691
+ removed.push(`codex MCP: ${item.label}`);
692
+ } catch (error) {
693
+ errors.push(`codex MCP: ${error instanceof Error ? error.message : String(error)}`);
694
+ }
695
+ }
696
+ for (const item of selected) {
697
+ if (options.purgeAllMcp && item.category === "mcp" && item.tool === "codex")
698
+ continue;
699
+ try {
700
+ if (item.category === "mcp" && item.configKey) {
701
+ if (item.tool === "codex")
702
+ await removeCodexMcp(item.configKey);
703
+ else if (item.tool === "claude")
704
+ await removeClaudeMcp(item.configKey);
705
+ removed.push(`${item.tool} MCP: ${item.label}`);
706
+ } else if ((item.category === "skill" || item.category === "prompt" || item.category === "agents-file") && item.path) {
707
+ const result = await moveToTrash(item.path);
708
+ if (result[0]?.success)
709
+ removed.push(`${item.category === "agents-file" ? "AGENTS" : item.category}: ${item.label}`);
710
+ else
711
+ errors.push(result[0]?.error || item.path);
209
712
  }
713
+ } catch (error) {
714
+ errors.push(`${item.label}: ${error instanceof Error ? error.message : String(error)}`);
715
+ }
716
+ }
717
+ return { removed, errors };
718
+ }
719
+ function resolveCodeTool() {
720
+ const config = readCcjkConfig();
721
+ if (config?.codeToolType === "claude-code" || config?.codeToolType === "codex")
722
+ return config.codeToolType;
723
+ return "codex";
724
+ }
725
+ async function runEnvironmentCleanup(options = {}) {
726
+ ensureI18nInitialized();
727
+ void resolveCodeTool();
728
+ void options.codeToolType;
729
+ if (options.purgeAll && !options.skipPrompt) {
730
+ console.log(ansis.yellow(`
731
+ ${i18n.t("clean:purgeAllWarning")}
732
+ `));
733
+ }
734
+ const { candidates } = scanEnvironmentIssues(options.purgeAll);
735
+ if (candidates.length === 0) {
736
+ console.log(ansis.green(i18n.t("clean:nothingFound")));
737
+ return { removed: [], errors: [] };
738
+ }
739
+ let selected = candidates;
740
+ if (options.aggressive)
741
+ selected = candidates;
742
+ if (!options.skipPrompt) {
743
+ console.log(ansis.cyan(`
744
+ ${i18n.t("clean:scanSummary", { count: candidates.length })}
745
+ `));
746
+ const { picked } = await inquirer.prompt({
747
+ type: "checkbox",
748
+ name: "picked",
749
+ message: `${i18n.t("clean:selectItems")}${i18n.t("common:multiSelectHint")}`,
750
+ choices: addNumbersToChoices(candidates.map((item) => ({
751
+ name: `${ansis.cyan(`[${item.tool}]`)} ${item.label} - ${ansis.gray(item.reason)}`,
752
+ value: item.id,
753
+ checked: options.purgeAll || options.aggressive ? true : item.checked
754
+ })))
210
755
  });
211
- child.on("error", (error) => {
212
- if (error.message.includes(`command not found`) || error.message.includes("ENOENT")) {
213
- console.error(ansis.red(`\u2717 ${i18n.t("cometix:commandNotFound")}`));
214
- } else {
215
- console.error(ansis.red(`\u2717 ${i18n.t("cometix:tuiConfigFailed")}: ${error.message}`));
216
- }
217
- reject(error);
756
+ if (!picked?.length) {
757
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
758
+ return { removed: [], errors: [] };
759
+ }
760
+ selected = candidates.filter((item) => picked.includes(item.id));
761
+ const { confirmed } = await inquirer.prompt({
762
+ type: "confirm",
763
+ name: "confirmed",
764
+ message: i18n.t("clean:confirmCleanup", { count: selected.length }),
765
+ default: false
218
766
  });
767
+ if (!confirmed) {
768
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
769
+ return { removed: [], errors: [] };
770
+ }
771
+ } else if (options.purgeAll || options.aggressive) {
772
+ selected = candidates;
773
+ } else {
774
+ selected = candidates.filter((item) => item.checked);
775
+ }
776
+ const result = await executeCleanup(selected, { purgeAllMcp: options.purgeAll });
777
+ if (result.removed.length > 0) {
778
+ console.log(ansis.green(`
779
+ ${i18n.t("clean:cleanupDone", { count: result.removed.length })}`));
780
+ for (const line of result.removed)
781
+ console.log(ansis.gray(` \u2714 ${line}`));
782
+ }
783
+ if (result.errors.length > 0) {
784
+ console.log(ansis.red(`
785
+ ${i18n.t("clean:cleanupErrors", { count: result.errors.length })}`));
786
+ for (const line of result.errors)
787
+ console.log(ansis.red(` \u2717 ${line}`));
788
+ }
789
+ return result;
790
+ }
791
+
792
+ async function cleanCommand(options = {}) {
793
+ ensureI18nInitialized();
794
+ const codeToolType = options.codeType ? resolveCodeToolType$1(options.codeType) : void 0;
795
+ await runEnvironmentCleanup({
796
+ codeToolType,
797
+ skipPrompt: options.skipPrompt,
798
+ aggressive: options.aggressive,
799
+ purgeAll: options.purgeAll
219
800
  });
220
801
  }
221
802
 
222
- async function showCometixMenu() {
223
- try {
224
- ensureI18nInitialized();
803
+ const TIMEOUT_MS = 1e4;
804
+ const EXIT_CODE = {
805
+ ok: 0,
806
+ "auth-failed": 1,
807
+ unreachable: 2,
808
+ unexpected: 3
809
+ };
810
+ async function probeCommand(opts = {}) {
811
+ const creds = readActiveApiCreds();
812
+ if (!creds.baseUrl) {
813
+ throw new Error("\u672A\u627E\u5230 API \u914D\u7F6E\uFF0C\u8BF7\u5148\u8FD0\u884C ccjk init \u6216\u83DC\u5355 3 \u914D\u7F6E API");
814
+ }
815
+ const result = await runProbe(creds.baseUrl, creds.apiKey, creds.authToken);
816
+ if (opts.json) {
817
+ console.log(JSON.stringify(result, null, 2));
818
+ } else {
819
+ const color = result.status === "ok" ? ansis.green : ansis.red;
225
820
  console.log(`
226
- ${ansis.cyan("\u2550".repeat(50))}`);
227
- console.log(ansis.bold.cyan(` ${i18n.t("cometix:cometixMenuTitle")}`));
228
- console.log(`${ansis.cyan("\u2550".repeat(50))}
229
- `);
230
- console.log(` ${ansis.cyan("1.")} ${i18n.t("cometix:cometixMenuOptions.installOrUpdate")} ${ansis.gray(`- ${i18n.t("cometix:cometixMenuDescriptions.installOrUpdate")}`)}`);
231
- console.log(` ${ansis.cyan("2.")} ${i18n.t("cometix:cometixMenuOptions.printConfig")} ${ansis.gray(`- ${i18n.t("cometix:cometixMenuDescriptions.printConfig")}`)}`);
232
- console.log(` ${ansis.cyan("3.")} ${i18n.t("cometix:cometixMenuOptions.customConfig")} ${ansis.gray(`- ${i18n.t("cometix:cometixMenuDescriptions.customConfig")}`)}`);
233
- console.log(` ${ansis.yellow("0.")} ${i18n.t("cometix:cometixMenuOptions.back")}`);
234
- console.log("");
235
- const { choice } = await inquirer.prompt({
236
- type: "input",
237
- name: "choice",
238
- message: i18n.t("common:enterChoice"),
239
- validate: async (value) => {
240
- const valid = ["1", "2", "3", "0"];
241
- return valid.includes(value) || i18n.t("common:invalidChoice");
821
+ \u63A2\u6D3B ${creds.baseUrl}`);
822
+ console.log(color(` \u72B6\u6001: ${result.status}`));
823
+ if (result.httpStatus) console.log(ansis.dim(` HTTP: ${result.httpStatus}`));
824
+ if (result.latencyMs) console.log(ansis.dim(` \u5EF6\u8FDF: ${result.latencyMs}ms`));
825
+ if (result.error) console.log(ansis.dim(` \u9519\u8BEF: ${result.error}`));
826
+ console.log();
827
+ }
828
+ process.exitCode = EXIT_CODE[result.status];
829
+ }
830
+ function readActiveApiCreds() {
831
+ const tool = readCcjkConfig()?.codeToolType ?? "clavue";
832
+ const file = activeSettingsFile(tool === "codex" || tool === "grok" ? "claude-code" : tool);
833
+ const settings = readJsonConfig(file) || {};
834
+ const env = settings.env || {};
835
+ return {
836
+ baseUrl: env.ANTHROPIC_BASE_URL || "",
837
+ apiKey: env.ANTHROPIC_API_KEY || "",
838
+ authToken: env.ANTHROPIC_AUTH_TOKEN || env.ANTHROPIC_API_KEY || ""
839
+ };
840
+ }
841
+ async function runProbe(baseUrl, apiKey, authToken) {
842
+ const url = `${baseUrl.replace(/\/$/, "")}/v1/messages`;
843
+ const headers = {
844
+ "content-type": "application/json",
845
+ "anthropic-version": "2023-06-01"
846
+ };
847
+ if (authToken) headers.authorization = `Bearer ${authToken}`;
848
+ else if (apiKey) headers["x-api-key"] = apiKey;
849
+ const body = JSON.stringify({
850
+ model: "claude-3-5-haiku-20241022",
851
+ max_tokens: 1,
852
+ messages: [{ role: "user", content: "ping" }]
853
+ });
854
+ const t0 = Date.now();
855
+ try {
856
+ const res = await fetch(url, { method: "POST", headers, body, signal: AbortSignal.timeout(TIMEOUT_MS) });
857
+ const latencyMs = Date.now() - t0;
858
+ if (res.status === 401 || res.status === 403) {
859
+ return { baseUrl, status: "auth-failed", httpStatus: res.status, latencyMs };
860
+ }
861
+ if (res.ok) return { baseUrl, status: "ok", httpStatus: res.status, latencyMs };
862
+ return { baseUrl, status: "unexpected", httpStatus: res.status, latencyMs };
863
+ } catch (e) {
864
+ return { baseUrl, status: "unreachable", error: e.message, latencyMs: Date.now() - t0 };
865
+ }
866
+ }
867
+
868
+ async function runDoctorHub(tool) {
869
+ ensureI18nInitialized();
870
+ const supportsProbe = tool !== "grok";
871
+ let exitHub = false;
872
+ while (!exitHub) {
873
+ console.log(ansis.cyan(`
874
+ ${i18n.t("hub:doctor.title")}`));
875
+ console.log(ansis.gray(` ${i18n.t("hub:doctor.subtitle")}`));
876
+ console.log(ansis.dim(` ${TOOL_MATRIX[tool].displayName}
877
+ `));
878
+ if (tool === "codex")
879
+ printCodexRuntimeStatus();
880
+ const choices = addNumbersToChoices([
881
+ {
882
+ name: `${i18n.t("hub:doctor.scanReport")} \u2014 ${ansis.gray(i18n.t("hub:doctor.scanReportDesc"))}`,
883
+ value: "scan",
884
+ short: i18n.t("hub:doctor.scanReport")
885
+ },
886
+ ...supportsProbe ? [{
887
+ name: i18n.t("hub:doctor.probeApi"),
888
+ value: "probe",
889
+ short: i18n.t("hub:doctor.probeApi")
890
+ }] : [],
891
+ {
892
+ name: `${i18n.t("hub:doctor.smartClean")} \u2014 ${ansis.gray(i18n.t("hub:doctor.smartCleanDesc"))}`,
893
+ value: "smart",
894
+ short: i18n.t("hub:doctor.smartClean")
895
+ },
896
+ {
897
+ name: `${i18n.t("hub:doctor.purgeAll")} \u2014 ${ansis.gray(i18n.t("hub:doctor.purgeAllDesc"))}`,
898
+ value: "purge",
899
+ short: i18n.t("hub:doctor.purgeAll")
900
+ },
901
+ {
902
+ name: i18n.t("common:back"),
903
+ value: "back",
904
+ short: i18n.t("common:back")
242
905
  }
906
+ ]);
907
+ const { action } = await inquirer.prompt({
908
+ type: "list",
909
+ name: "action",
910
+ message: i18n.t("menu:selectFunction"),
911
+ choices
243
912
  });
244
- switch (choice) {
245
- case "1":
246
- await installCometixLine();
913
+ switch (action) {
914
+ case "scan":
915
+ printEnvironmentScanReport();
247
916
  break;
248
- case "2":
249
- await runCometixPrintConfig();
917
+ case "probe":
918
+ await probeCommand();
250
919
  break;
251
- case "3":
252
- await runCometixTuiConfig();
920
+ case "smart":
921
+ await cleanCommand({ codeType: tool });
922
+ break;
923
+ case "purge":
924
+ await cleanCommand({ codeType: tool, purgeAll: true });
925
+ break;
926
+ case "back":
927
+ exitHub = true;
253
928
  break;
254
- case "0":
255
- return false;
256
929
  }
257
- if (choice !== "0") {
258
- console.log(`
259
- ${ansis.dim("\u2500".repeat(50))}
260
- `);
261
- const continueInCometix = await promptBoolean({
262
- message: i18n.t("common:returnToMenu"),
263
- defaultValue: true
264
- });
265
- if (continueInCometix) {
266
- return await showCometixMenu();
930
+ }
931
+ }
932
+
933
+ function resolveCodeToolType(optionValue, savedValue) {
934
+ if (optionValue !== void 0) {
935
+ const resolved = resolveCodeToolType$1(optionValue);
936
+ if (resolved !== DEFAULT_CODE_TOOL_TYPE || optionValue === DEFAULT_CODE_TOOL_TYPE) {
937
+ return resolved;
938
+ }
939
+ }
940
+ if (savedValue && isCodeToolType(savedValue)) {
941
+ return savedValue;
942
+ }
943
+ return DEFAULT_CODE_TOOL_TYPE;
944
+ }
945
+ async function update(options = {}) {
946
+ try {
947
+ if (!options.skipBanner) {
948
+ displayBanner(i18n.t("cli:banner.updateSubtitle"));
949
+ }
950
+ const ccjkConfig = readCcjkConfig();
951
+ const codeToolType = resolveCodeToolType(options.codeType, ccjkConfig?.codeToolType);
952
+ options.codeType = codeToolType;
953
+ if (codeToolType === "codex") {
954
+ await runCodexUpdate();
955
+ const newPreferredLang = options.configLang || ccjkConfig?.preferredLang;
956
+ if (newPreferredLang) {
957
+ updateCcjkConfig({
958
+ version,
959
+ preferredLang: newPreferredLang,
960
+ codeToolType
961
+ });
962
+ } else {
963
+ updateCcjkConfig({
964
+ version,
965
+ codeToolType
966
+ });
267
967
  }
968
+ return;
268
969
  }
269
- return false;
970
+ const { resolveTemplateLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.bN; });
971
+ const configLang = await resolveTemplateLanguage(
972
+ options.configLang,
973
+ // Command line option
974
+ ccjkConfig,
975
+ options.skipPrompt
976
+ // Non-interactive mode flag
977
+ );
978
+ const aiOutputLang = await resolveAiOutputLanguage(i18n.language, options.aiOutputLang, ccjkConfig, options.skipPrompt);
979
+ const runtimeLabel = isClaudeFamilyCodeTool(codeToolType) ? getClaudeFamilyRuntimeLabel(codeToolType) : "Claude Code";
980
+ console.log(ansis.cyan(`
981
+ ${i18n.t("configuration:updatingPrompts", { runtime: runtimeLabel })}
982
+ `));
983
+ await updatePromptOnly(aiOutputLang);
984
+ await selectAndInstallWorkflows(configLang, void 0, { codeToolType: isClaudeFamilyCodeTool(codeToolType) ? codeToolType : "claude-code" });
985
+ if (codeToolType === "claude-code") {
986
+ await checkClaudeCodeVersionAndPrompt(false);
987
+ }
988
+ updateCcjkConfig({
989
+ version,
990
+ templateLang: configLang,
991
+ // 保存模板语言选择
992
+ aiOutputLang,
993
+ codeToolType
994
+ });
270
995
  } catch (error) {
271
996
  if (!handleExitPromptError(error)) {
272
997
  handleGeneralError(error);
273
998
  }
274
- return false;
275
999
  }
276
1000
  }
277
-
278
- async function runCcusageFeature() {
279
- ensureI18nInitialized();
280
- console.log("");
281
- console.log(ansis.cyan(i18n.t("menu:menuOptions.ccusage")));
282
- console.log(ansis.gray(`${i18n.t("tools:ccusageDescription")}`));
283
- console.log("");
284
- const choices = [
285
- { name: i18n.t("tools:ccusageModes.daily"), value: "daily" },
286
- { name: i18n.t("tools:ccusageModes.monthly"), value: "monthly" },
287
- { name: i18n.t("tools:ccusageModes.session"), value: "session" },
288
- { name: i18n.t("tools:ccusageModes.blocks"), value: "blocks" },
289
- { name: i18n.t("tools:ccusageModes.custom"), value: "custom" },
290
- { name: i18n.t("common:back"), value: "back" }
291
- ];
292
- const { mode } = await inquirer.prompt({
293
- type: "list",
294
- name: "mode",
295
- message: i18n.t("tools:selectAnalysisMode"),
296
- choices: addNumbersToChoices(choices)
1001
+
1002
+ const LEGACY_PROFILES_DIR = join(homedir(), ".ccjk", "profiles");
1003
+ function fromClaudeProfile(profile) {
1004
+ return {
1005
+ name: profile.name,
1006
+ baseUrl: profile.baseUrl,
1007
+ apiKey: profile.apiKey,
1008
+ model: profile.primaryModel
1009
+ };
1010
+ }
1011
+ function readLegacyJsonProfile(name) {
1012
+ const profilePath = join(LEGACY_PROFILES_DIR, `${name}.json`);
1013
+ if (!existsSync(profilePath)) {
1014
+ return null;
1015
+ }
1016
+ try {
1017
+ const data = JSON.parse(readFileSync(profilePath, "utf-8"));
1018
+ return data.name ? data : { ...data, name };
1019
+ } catch {
1020
+ return null;
1021
+ }
1022
+ }
1023
+ function readCcjkProfileByName(name) {
1024
+ const byName = ClaudeCodeConfigManager.getProfileByName(name);
1025
+ if (byName) {
1026
+ return fromClaudeProfile(byName);
1027
+ }
1028
+ const byId = ClaudeCodeConfigManager.getProfileById(name);
1029
+ if (byId) {
1030
+ return fromClaudeProfile(byId);
1031
+ }
1032
+ return readLegacyJsonProfile(name);
1033
+ }
1034
+ function listCcjkProfileNames() {
1035
+ return ClaudeCodeConfigManager.listProfiles().map((profile) => profile.name);
1036
+ }
1037
+
1038
+ const GROK_AUTH_FILE = join(homedir(), ".grok", "auth.json");
1039
+ function isGrokInstalled() {
1040
+ try {
1041
+ execSync("command -v grok", { stdio: "ignore" });
1042
+ return true;
1043
+ } catch {
1044
+ return false;
1045
+ }
1046
+ }
1047
+ function isGrokLoggedIn() {
1048
+ if (!existsSync(GROK_AUTH_FILE)) return false;
1049
+ try {
1050
+ const data = JSON.parse(readFileSync(GROK_AUTH_FILE, "utf-8"));
1051
+ return Object.keys(data).some((k) => k.includes("auth.x.ai"));
1052
+ } catch {
1053
+ return false;
1054
+ }
1055
+ }
1056
+ function getGrokQuickStatus() {
1057
+ if (!isGrokInstalled()) {
1058
+ return {
1059
+ installed: false,
1060
+ loggedIn: false,
1061
+ hint: "\u672A\u5B89\u88C5\uFF1Acurl -fsSL https://x.ai/cli/install.sh | bash"
1062
+ };
1063
+ }
1064
+ const loggedIn = isGrokLoggedIn();
1065
+ return {
1066
+ installed: true,
1067
+ loggedIn,
1068
+ hint: loggedIn ? "\u5DF2\u767B\u5F55\uFF08OAuth\uFF0C~/.grok/auth.json\uFF09" : "\u672A\u767B\u5F55\uFF0C\u8FD0\u884C `grok login`"
1069
+ };
1070
+ }
1071
+ function buildGrokHints() {
1072
+ const s = getGrokQuickStatus();
1073
+ const lines = [];
1074
+ if (!s.installed) {
1075
+ lines.push(ansis.dim(" \u5B89\u88C5: ") + ansis.cyan("curl -fsSL https://x.ai/cli/install.sh | bash"));
1076
+ return lines;
1077
+ }
1078
+ if (!s.loggedIn) {
1079
+ lines.push(ansis.yellow(" \u767B\u5F55: ") + ansis.cyan("grok login"));
1080
+ }
1081
+ lines.push(ansis.dim(" \u542F\u52A8: ") + ansis.cyan("grok"));
1082
+ lines.push(ansis.dim(" \u6A21\u578B: ") + ansis.cyan("grok models"));
1083
+ return lines;
1084
+ }
1085
+
1086
+ async function grokCommand(profileName) {
1087
+ if (profileName) {
1088
+ await launchWithProfile$1(profileName);
1089
+ return;
1090
+ }
1091
+ const status = getGrokQuickStatus();
1092
+ console.log(ansis.bold("\nGrok CLI"));
1093
+ console.log(` \u5B89\u88C5: ${status.installed ? ansis.green("\u662F") : ansis.gray("\u5426")} \u767B\u5F55: ${status.loggedIn ? ansis.green("\u662F") : ansis.yellow("\u5426")}`);
1094
+ for (const line of buildGrokHints()) console.log(line);
1095
+ const names = listCcjkProfileNames();
1096
+ if (names.length > 0) {
1097
+ console.log(ansis.dim(`
1098
+ \u53EF\u7528 profile: ${names.join(", ")}`));
1099
+ }
1100
+ console.log(ansis.dim(" ccjk grok <profile> \u2014 \u7528 ~/.ccjk/config.toml \u4E2D\u7684 profile \u542F\u52A8\n"));
1101
+ }
1102
+ async function launchWithProfile$1(name) {
1103
+ const profile = readCcjkProfileByName(name);
1104
+ if (!profile) {
1105
+ console.log(ansis.red(`Profile "${name}" \u4E0D\u5B58\u5728`));
1106
+ console.log(ansis.dim(" \u5148\u8FD0\u884C ccjk init -T grok \u6216\u83DC\u5355\u914D\u7F6E API\uFF08profile \u4FDD\u5B58\u5728 ~/.ccjk/config.toml\uFF09\n"));
1107
+ return;
1108
+ }
1109
+ const env = { ...process.env };
1110
+ if (profile.baseUrl) {
1111
+ env.OPENAI_BASE_URL = profile.baseUrl;
1112
+ env.ANTHROPIC_BASE_URL = profile.baseUrl;
1113
+ }
1114
+ if (profile.apiKey) {
1115
+ env.OPENAI_API_KEY = profile.apiKey;
1116
+ env.ANTHROPIC_API_KEY = profile.apiKey;
1117
+ env.ANTHROPIC_AUTH_TOKEN = profile.apiKey;
1118
+ }
1119
+ console.log(ansis.cyan(`
1120
+ \u4F7F\u7528 profile "${name}" \u542F\u52A8 grok...
1121
+ `));
1122
+ const res = spawnSync("grok", [], { stdio: "inherit", env });
1123
+ if (res.error) console.log(ansis.red(`\u542F\u52A8\u5931\u8D25: ${res.error.message}`));
1124
+ }
1125
+
1126
+ function line(key, labelKey, descKey) {
1127
+ return { key, labelKey, descKey };
1128
+ }
1129
+ const CROSS_TOOL_LINES = [
1130
+ line("g", "menu:menuOptions.grokCrossTool", "menu:menuDescriptions.grokCrossTool"),
1131
+ line("x", "menu:menuOptions.reasonixCrossTool", "menu:menuDescriptions.reasonixCrossTool")
1132
+ ];
1133
+ const DOCTOR_HUB = line("h", "menu:menuOptions.doctorHub", "menu:menuDescriptions.doctorHub");
1134
+ const OPERATOR_HUB = line("w", "menu:menuOptions.operatorHub", "menu:menuDescriptions.operatorHub");
1135
+ const CLAUDE_FAMILY_OPERATOR = [
1136
+ line("1", "menu:menuOptions.fullInit", "menu:menuDescriptions.fullInit"),
1137
+ line("2", "menu:menuOptions.importWorkflow", "menu:menuDescriptions.importWorkflow"),
1138
+ line("3", "menu:menuOptions.configureApiOrCcr", "menu:menuDescriptions.configureApiOrCcr"),
1139
+ line("4", "menu:menuOptions.configureMcp", "menu:menuDescriptions.configureMcp"),
1140
+ line("5", "menu:menuOptions.configureModel", "menu:menuDescriptions.configureModel"),
1141
+ line("6", "menu:menuOptions.configureAiMemory", "menu:menuDescriptions.configureAiMemory"),
1142
+ line("7", "menu:menuOptions.configureEnvPermission", "menu:menuDescriptions.configureEnvPermission")
1143
+ ];
1144
+ const TOOL_MENU_LAYOUTS = {
1145
+ clavue: {
1146
+ toolLabelKey: "menu:toolHeaders.clavue",
1147
+ operatorLines: [
1148
+ line("1", "menu:menuOptions.clavueFullInit", "menu:menuDescriptions.clavueFullInit"),
1149
+ line("2", "menu:menuOptions.clavueUpdateWorkflow", "menu:menuDescriptions.clavueUpdateWorkflow"),
1150
+ line("3", "menu:menuOptions.clavueConfigureApi", "menu:menuDescriptions.clavueConfigureApi"),
1151
+ line("4", "menu:menuOptions.clavueConfigureMcp", "menu:menuDescriptions.clavueConfigureMcp"),
1152
+ line("5", "menu:menuOptions.clavueConfigureModel", "menu:menuDescriptions.clavueConfigureModel"),
1153
+ line("6", "menu:menuOptions.clavueConfigureAiMemory", "menu:menuDescriptions.clavueConfigureAiMemory"),
1154
+ line("7", "menu:menuOptions.clavueConfigureEnvPermission", "menu:menuDescriptions.clavueConfigureEnvPermission")
1155
+ ],
1156
+ doctorLines: [DOCTOR_HUB],
1157
+ ccjkUninstallKey: "menu:menuOptions.clavueUninstall",
1158
+ ccjkUninstallDescKey: "menu:menuDescriptions.clavueUninstall",
1159
+ ccjkUpdateKey: "menu:menuOptions.clavueCheckUpdates",
1160
+ ccjkUpdateDescKey: "menu:menuDescriptions.clavueCheckUpdates"
1161
+ },
1162
+ "claude-code": {
1163
+ toolLabelKey: "menu:toolHeaders.claudeCode",
1164
+ operatorLines: CLAUDE_FAMILY_OPERATOR,
1165
+ doctorLines: [DOCTOR_HUB],
1166
+ ccjkUninstallKey: "menu:menuOptions.uninstall",
1167
+ ccjkUninstallDescKey: "menu:menuDescriptions.uninstall",
1168
+ ccjkUpdateKey: "menu:menuOptions.checkUpdates",
1169
+ ccjkUpdateDescKey: "menu:menuDescriptions.checkUpdates"
1170
+ },
1171
+ codex: {
1172
+ toolLabelKey: "menu:toolHeaders.codex",
1173
+ operatorLines: [
1174
+ line("1", "menu:menuOptions.codexFullInit", "menu:menuDescriptions.codexFullInitWithPreset"),
1175
+ line("2", "menu:menuOptions.codexImportWorkflow", "menu:menuDescriptions.codexImportWorkflow"),
1176
+ line("3", "menu:menuOptions.codexConfigureApi", "menu:menuDescriptions.codexConfigureApi"),
1177
+ line("4", "menu:menuOptions.codexConfigureMcp", "menu:menuDescriptions.codexConfigureMcp"),
1178
+ line("5", "menu:menuOptions.codexConfigureModel", "menu:menuDescriptions.codexConfigureModel"),
1179
+ line("6", "menu:menuOptions.codexConfigureAiMemory", "menu:menuDescriptions.codexConfigureAiMemory")
1180
+ ],
1181
+ doctorLines: [DOCTOR_HUB],
1182
+ ccjkUninstallKey: "menu:menuOptions.codexUninstall",
1183
+ ccjkUninstallDescKey: "menu:menuDescriptions.codexUninstall",
1184
+ ccjkUpdateKey: "menu:menuOptions.codexCheckUpdates",
1185
+ ccjkUpdateDescKey: "menu:menuDescriptions.codexCheckUpdates"
1186
+ },
1187
+ grok: {
1188
+ toolLabelKey: "menu:toolHeaders.grok",
1189
+ operatorLines: [
1190
+ line("1", "menu:menuOptions.grokInit", "menu:menuDescriptions.grokInit"),
1191
+ line("2", "menu:menuOptions.grokStatus", "menu:menuDescriptions.grokStatus")
1192
+ ],
1193
+ doctorLines: [DOCTOR_HUB],
1194
+ ccjkUninstallKey: "menu:menuOptions.uninstall",
1195
+ ccjkUninstallDescKey: "menu:menuDescriptions.uninstall",
1196
+ ccjkUpdateKey: "menu:menuOptions.checkUpdates",
1197
+ ccjkUpdateDescKey: "menu:menuDescriptions.checkUpdates"
1198
+ }
1199
+ };
1200
+ function shortenHomePath(path) {
1201
+ const home = homedir();
1202
+ if (path.startsWith(home))
1203
+ return `~${path.slice(home.length)}`;
1204
+ return path;
1205
+ }
1206
+ function formatChoiceLabel(item) {
1207
+ return `${item.key.toUpperCase()}. ${i18n.t(item.labelKey)} ${ansis.gray(`\u2014 ${i18n.t(item.descKey)}`)}`;
1208
+ }
1209
+ function sectionSeparator(titleKey) {
1210
+ return {
1211
+ name: ansis.dim(`\u2500\u2500 ${i18n.t(titleKey)} \u2500\u2500`),
1212
+ value: `__section_${titleKey}`,
1213
+ disabled: true
1214
+ };
1215
+ }
1216
+ function buildMenuListChoices(tool) {
1217
+ const layout = TOOL_MENU_LAYOUTS[tool];
1218
+ const choices = [
1219
+ sectionSeparator("menu:menuSections.operator"),
1220
+ {
1221
+ name: formatChoiceLabel(OPERATOR_HUB),
1222
+ value: OPERATOR_HUB.key
1223
+ },
1224
+ ...layout.operatorLines.map((item) => ({
1225
+ name: formatChoiceLabel(item),
1226
+ value: item.key
1227
+ })),
1228
+ sectionSeparator("menu:menuSections.doctor"),
1229
+ ...layout.doctorLines.map((item) => ({
1230
+ name: formatChoiceLabel(item),
1231
+ value: item.key
1232
+ })),
1233
+ sectionSeparator("menu:menuSections.crossTool"),
1234
+ ...CROSS_TOOL_LINES.map((item) => ({
1235
+ name: formatChoiceLabel(item),
1236
+ value: item.key
1237
+ })),
1238
+ sectionSeparator("menu:menuSections.ccjk"),
1239
+ {
1240
+ name: formatChoiceLabel(line("0", "menu:menuOptions.changeLanguage", "menu:menuDescriptions.changeLanguage")),
1241
+ value: "0"
1242
+ },
1243
+ {
1244
+ name: formatChoiceLabel(line("s", "menu:menuOptions.switchCodeTool", "menu:menuDescriptions.switchCodeTool")),
1245
+ value: "s"
1246
+ },
1247
+ {
1248
+ name: formatChoiceLabel(line("-", layout.ccjkUninstallKey, layout.ccjkUninstallDescKey)),
1249
+ value: "-"
1250
+ },
1251
+ {
1252
+ name: formatChoiceLabel(line("+", layout.ccjkUpdateKey, layout.ccjkUpdateDescKey)),
1253
+ value: "+"
1254
+ },
1255
+ {
1256
+ name: `${ansis.red("Q.")} ${ansis.red(i18n.t("menu:menuOptions.exit"))}`,
1257
+ value: "q"
1258
+ }
1259
+ ];
1260
+ return choices;
1261
+ }
1262
+ function printToolMenuHeader(tool) {
1263
+ const entry = TOOL_MATRIX[tool];
1264
+ const layout = TOOL_MENU_LAYOUTS[tool];
1265
+ const configRoot = shortenHomePath(entry.configRoot);
1266
+ const roles = entry.roles.includes("both") ? i18n.t("menu:roleBadge.both") : entry.roles.includes("doctor") ? i18n.t("menu:roleBadge.doctor") : i18n.t("menu:roleBadge.operator");
1267
+ console.log(ansis.dim(`
1268
+ ${i18n.t("menu:tagline")}`));
1269
+ console.log(
1270
+ ansis.white(
1271
+ ` ${i18n.t(layout.toolLabelKey)} ${ansis.dim("|")} ${ansis.gray(i18n.t("menu:configRoot", { path: configRoot }))} ${ansis.dim("|")} ${roles}`
1272
+ )
1273
+ );
1274
+ console.log("");
1275
+ }
1276
+ function getToolMenuLayout(tool) {
1277
+ return TOOL_MENU_LAYOUTS[tool];
1278
+ }
1279
+
1280
+ async function finishCodexOperatorAction() {
1281
+ printCodexReloadHint();
1282
+ }
1283
+ async function promptTuneSingle(tool) {
1284
+ const layout = getToolMenuLayout(tool);
1285
+ const tuneLines = layout.operatorLines.filter((line) => !["1", "2"].includes(line.key));
1286
+ const { picked } = await inquirer.prompt({
1287
+ type: "list",
1288
+ name: "picked",
1289
+ message: i18n.t("hub:operator.pickTune"),
1290
+ choices: addNumbersToChoices(tuneLines.map((line) => ({
1291
+ name: `${i18n.t(line.labelKey)} \u2014 ${ansis.gray(i18n.t(line.descKey))}`,
1292
+ value: line.key,
1293
+ short: i18n.t(line.labelKey)
1294
+ })))
1295
+ });
1296
+ if (tool === "codex") {
1297
+ switch (picked) {
1298
+ case "3":
1299
+ await configureCodexApi();
1300
+ break;
1301
+ case "4":
1302
+ await manageCodexMcp();
1303
+ break;
1304
+ case "5":
1305
+ await configureCodexDefaultModelFeature();
1306
+ break;
1307
+ case "6":
1308
+ await configureCodexAiMemoryFeature();
1309
+ break;
1310
+ }
1311
+ await finishCodexOperatorAction();
1312
+ return;
1313
+ }
1314
+ if (tool === "clavue" || tool === "claude-code") {
1315
+ switch (picked) {
1316
+ case "3":
1317
+ await configureApiFeature();
1318
+ break;
1319
+ case "4":
1320
+ await configureMcpFeature();
1321
+ break;
1322
+ case "5":
1323
+ await configureDefaultModelFeature();
1324
+ break;
1325
+ case "6":
1326
+ await configureAiMemoryFeature();
1327
+ break;
1328
+ case "7":
1329
+ await configureEnvPermissionFeature();
1330
+ break;
1331
+ }
1332
+ }
1333
+ }
1334
+ async function runCodexFreshStart() {
1335
+ const { confirmed } = await inquirer.prompt({
1336
+ type: "confirm",
1337
+ name: "confirmed",
1338
+ message: i18n.t("hub:operator.freshStartConfirm"),
1339
+ default: false
297
1340
  });
298
- if (mode === "back") {
1341
+ if (!confirmed) {
1342
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
299
1343
  return;
300
1344
  }
301
- let args = [];
302
- if (mode === "custom") {
303
- const { customArgs } = await inquirer.prompt({
304
- type: "input",
305
- name: "customArgs",
306
- message: i18n.t("tools:enterCustomArgs"),
307
- default: ""
308
- });
309
- if (customArgs === null || customArgs === void 0 || customArgs === "") {
310
- args = [];
311
- } else {
312
- const argsString = String(customArgs).trim();
313
- if (!argsString) {
314
- args = [];
315
- } else {
316
- const argPattern = /"([^"]*)"|'([^']*)'|(\S+)/g;
317
- const matches = [];
318
- let match = argPattern.exec(argsString);
319
- while (match !== null) {
320
- const value = match[1] || match[2] || match[3];
321
- if (value) {
322
- matches.push(value);
323
- }
324
- match = argPattern.exec(argsString);
325
- }
326
- args = matches;
327
- }
328
- }
329
- } else {
330
- args = [mode];
1345
+ await cleanCommand({ codeType: "codex", purgeAll: true, skipPrompt: true });
1346
+ const { applyCodexSetupPreset, getCodexPresetChoices } = await import('./chunks/codex-presets.mjs');
1347
+ const { preset } = await inquirer.prompt({
1348
+ type: "list",
1349
+ name: "preset",
1350
+ message: i18n.t("codex:preset.selectPrompt"),
1351
+ choices: addNumbersToChoices(
1352
+ getCodexPresetChoices().filter((choice) => choice.id !== "custom").map((choice) => ({
1353
+ name: `${choice.name} \u2014 ${ansis.gray(choice.description)}`,
1354
+ value: choice.id,
1355
+ short: choice.name
1356
+ }))
1357
+ ),
1358
+ default: "optimized"
1359
+ });
1360
+ const presetOptions = applyCodexSetupPreset(preset, { setupPreset: preset, skipPrompt: true });
1361
+ await runCodexFullInit(presetOptions);
1362
+ await finishCodexOperatorAction();
1363
+ }
1364
+ async function runCodexOperatorHub() {
1365
+ const { action } = await inquirer.prompt({
1366
+ type: "list",
1367
+ name: "action",
1368
+ message: i18n.t("menu:selectFunction"),
1369
+ choices: addNumbersToChoices([
1370
+ {
1371
+ name: `${i18n.t("hub:operator.fullInit")} \u2014 ${ansis.gray(i18n.t("menu:menuDescriptions.codexFullInitWithPreset"))}`,
1372
+ value: "init"
1373
+ },
1374
+ {
1375
+ name: i18n.t("hub:operator.updateWorkflow"),
1376
+ value: "workflow"
1377
+ },
1378
+ {
1379
+ name: `${i18n.t("hub:operator.tuneSingle")} \u2014 ${ansis.gray(i18n.t("hub:operator.tuneSingleDesc"))}`,
1380
+ value: "tune"
1381
+ },
1382
+ {
1383
+ name: `${i18n.t("hub:operator.freshStart")} \u2014 ${ansis.gray(i18n.t("hub:operator.freshStartDesc"))}`,
1384
+ value: "fresh"
1385
+ },
1386
+ { name: i18n.t("common:back"), value: "back" }
1387
+ ])
1388
+ });
1389
+ switch (action) {
1390
+ case "init":
1391
+ await runCodexFullInit();
1392
+ await finishCodexOperatorAction();
1393
+ break;
1394
+ case "workflow":
1395
+ await runCodexWorkflowImportWithLanguageSelection();
1396
+ await finishCodexOperatorAction();
1397
+ break;
1398
+ case "tune":
1399
+ await promptTuneSingle("codex");
1400
+ break;
1401
+ case "fresh":
1402
+ await runCodexFreshStart();
1403
+ break;
331
1404
  }
332
- console.log("");
333
- await executeCcusage(args);
334
- console.log("");
335
- await inquirer.prompt({
336
- type: "input",
337
- name: "continue",
338
- message: ansis.gray(i18n.t("tools:pressEnterToContinue"))
1405
+ }
1406
+ async function runClaudeFamilyOperatorHub(tool) {
1407
+ const initDesc = tool === "clavue" ? i18n.t("menu:menuDescriptions.clavueFullInit") : i18n.t("menu:menuDescriptions.fullInit");
1408
+ const { action } = await inquirer.prompt({
1409
+ type: "list",
1410
+ name: "action",
1411
+ message: i18n.t("menu:selectFunction"),
1412
+ choices: addNumbersToChoices([
1413
+ {
1414
+ name: `${i18n.t("hub:operator.fullInit")} \u2014 ${ansis.gray(initDesc)}`,
1415
+ value: "init"
1416
+ },
1417
+ {
1418
+ name: i18n.t("hub:operator.updateWorkflow"),
1419
+ value: "workflow"
1420
+ },
1421
+ {
1422
+ name: `${i18n.t("hub:operator.tuneSingle")} \u2014 ${ansis.gray(i18n.t("hub:operator.tuneSingleDesc"))}`,
1423
+ value: "tune"
1424
+ },
1425
+ { name: i18n.t("common:back"), value: "back" }
1426
+ ])
339
1427
  });
1428
+ switch (action) {
1429
+ case "init":
1430
+ await init({ skipBanner: true, codeType: tool });
1431
+ break;
1432
+ case "workflow":
1433
+ await update({ skipBanner: true, codeType: tool });
1434
+ break;
1435
+ case "tune":
1436
+ await promptTuneSingle(tool);
1437
+ break;
1438
+ }
340
1439
  }
341
- async function runCcrMenuFeature() {
342
- await showCcrMenu();
1440
+ async function runGrokOperatorHub() {
1441
+ const { action } = await inquirer.prompt({
1442
+ type: "list",
1443
+ name: "action",
1444
+ message: i18n.t("menu:selectFunction"),
1445
+ choices: addNumbersToChoices([
1446
+ {
1447
+ name: `${i18n.t("hub:operator.grokProfile")} \u2014 ${ansis.gray(i18n.t("menu:menuDescriptions.grokInit"))}`,
1448
+ value: "profile"
1449
+ },
1450
+ {
1451
+ name: `${i18n.t("hub:operator.grokLaunch")} \u2014 ${ansis.gray(i18n.t("menu:menuDescriptions.grokStatus"))}`,
1452
+ value: "launch"
1453
+ },
1454
+ { name: i18n.t("common:back"), value: "back" }
1455
+ ])
1456
+ });
1457
+ switch (action) {
1458
+ case "profile":
1459
+ await init({ skipBanner: true, codeType: "grok" });
1460
+ break;
1461
+ case "launch":
1462
+ await grokCommand();
1463
+ break;
1464
+ }
343
1465
  }
344
- async function runCometixMenuFeature() {
345
- await showCometixMenu();
1466
+ async function runOperatorHub(tool) {
1467
+ ensureI18nInitialized();
1468
+ console.log(ansis.cyan(`
1469
+ ${i18n.t("hub:operator.title")}`));
1470
+ console.log(ansis.gray(` ${i18n.t("hub:operator.subtitle")}`));
1471
+ console.log(ansis.dim(` ${TOOL_MATRIX[tool].displayName}
1472
+ `));
1473
+ if (tool === "codex")
1474
+ return runCodexOperatorHub();
1475
+ if (tool === "grok")
1476
+ return runGrokOperatorHub();
1477
+ return runClaudeFamilyOperatorHub(tool);
346
1478
  }
347
1479
 
348
1480
  class ToolUpdateScheduler {
@@ -626,7 +1758,7 @@ class CcjkUninstaller {
626
1758
  result.removed.push(".claude-code-router/");
627
1759
  }
628
1760
  try {
629
- await exec$1("npm", ["uninstall", "-g", "@musistudio/claude-code-router"]);
1761
+ await exec("npm", ["uninstall", "-g", "@musistudio/claude-code-router"]);
630
1762
  result.removed.push("@musistudio/claude-code-router package");
631
1763
  result.success = true;
632
1764
  } catch (npmError) {
@@ -654,7 +1786,7 @@ class CcjkUninstaller {
654
1786
  warnings: []
655
1787
  };
656
1788
  try {
657
- await exec$1("npm", ["uninstall", "-g", "@cometix/ccline"]);
1789
+ await exec("npm", ["uninstall", "-g", "@cometix/ccline"]);
658
1790
  result.removed.push("@cometix/ccline package");
659
1791
  result.success = true;
660
1792
  } catch (error) {
@@ -688,7 +1820,7 @@ class CcjkUninstaller {
688
1820
  result.removed.push(".claude.json (includes MCP configuration)");
689
1821
  }
690
1822
  try {
691
- const { uninstallCodeTool } = await import('./chunks/simple-config.mjs').then(function (n) { return n.bA; });
1823
+ const { uninstallCodeTool } = await import('./chunks/simple-config.mjs').then(function (n) { return n.bR; });
692
1824
  const success = await uninstallCodeTool("claude-code");
693
1825
  if (success) {
694
1826
  result.removed.push("@anthropic-ai/claude-code");
@@ -805,7 +1937,7 @@ class CcjkUninstaller {
805
1937
  ];
806
1938
  for (const pkg of packagesToUninstall) {
807
1939
  try {
808
- await exec$1("npm", ["uninstall", "-g", pkg]);
1940
+ await exec("npm", ["uninstall", "-g", pkg]);
809
1941
  result.removed.push(`${pkg} package`);
810
1942
  } catch (error) {
811
1943
  if (error.message.includes("not found") || error.message.includes("not installed")) {
@@ -924,7 +2056,7 @@ async function uninstall(options = {}) {
924
2056
  }
925
2057
  const uninstaller = new CcjkUninstaller(options.lang || "en");
926
2058
  if (codeType === "codex") {
927
- const { runCodexUninstall } = await import('./chunks/simple-config.mjs').then(function (n) { return n.bz; });
2059
+ const { runCodexUninstall } = await import('./chunks/simple-config.mjs').then(function (n) { return n.bQ; });
928
2060
  await runCodexUninstall();
929
2061
  return;
930
2062
  }
@@ -1124,199 +2256,37 @@ function displayUninstallResult(mode, results) {
1124
2256
  const totalRemovedConfigs = results.reduce((count, result) => count + (result.removedConfigs?.length || 0), 0);
1125
2257
  console.log("");
1126
2258
  console.log(ansis.cyan("\u2500".repeat(50)));
1127
- if (mode === "complete") {
1128
- if (totalErrors === 0) {
1129
- console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:completeSuccess")}`));
1130
- } else {
1131
- console.log(ansis.yellow.bold(`\u26A0 ${i18n.t("uninstall:completePartialSuccess")}`));
1132
- }
1133
- } else {
1134
- if (totalRemovedFiles > 0 && totalRemovedConfigs > 0) {
1135
- console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccessBoth", {
1136
- fileCount: totalRemovedFiles,
1137
- configCount: totalRemovedConfigs
1138
- })}`));
1139
- } else if (totalRemovedFiles > 0) {
1140
- console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccessFiles", {
1141
- count: totalRemovedFiles
1142
- })}`));
1143
- } else if (totalRemovedConfigs > 0) {
1144
- console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccessConfigs", {
1145
- count: totalRemovedConfigs
1146
- })}`));
1147
- } else {
1148
- console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccess", { count: totalSuccess })}`));
1149
- }
1150
- if (totalErrors > 0) {
1151
- console.log(ansis.red(`\u2716 ${i18n.t("uninstall:errorsCount", { count: totalErrors })}`));
1152
- }
1153
- if (totalWarnings > 0) {
1154
- console.log(ansis.yellow(`\u26A0 ${i18n.t("uninstall:warningsCount", { count: totalWarnings })}`));
1155
- }
1156
- }
1157
- console.log("");
1158
- }
1159
-
1160
- function resolveCodeToolType(optionValue, savedValue) {
1161
- if (optionValue !== void 0) {
1162
- const resolved = resolveCodeToolType$1(optionValue);
1163
- if (resolved !== DEFAULT_CODE_TOOL_TYPE || optionValue === DEFAULT_CODE_TOOL_TYPE) {
1164
- return resolved;
1165
- }
1166
- }
1167
- if (savedValue && isCodeToolType(savedValue)) {
1168
- return savedValue;
1169
- }
1170
- return DEFAULT_CODE_TOOL_TYPE;
1171
- }
1172
- async function update(options = {}) {
1173
- try {
1174
- if (!options.skipBanner) {
1175
- displayBanner(i18n.t("cli:banner.updateSubtitle"));
1176
- }
1177
- const ccjkConfig = readCcjkConfig();
1178
- const codeToolType = resolveCodeToolType(options.codeType, ccjkConfig?.codeToolType);
1179
- options.codeType = codeToolType;
1180
- if (codeToolType === "codex") {
1181
- await runCodexUpdate();
1182
- const newPreferredLang = options.configLang || ccjkConfig?.preferredLang;
1183
- if (newPreferredLang) {
1184
- updateCcjkConfig({
1185
- version,
1186
- preferredLang: newPreferredLang,
1187
- codeToolType
1188
- });
1189
- } else {
1190
- updateCcjkConfig({
1191
- version,
1192
- codeToolType
1193
- });
1194
- }
1195
- return;
1196
- }
1197
- const { resolveTemplateLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.bw; });
1198
- const configLang = await resolveTemplateLanguage(
1199
- options.configLang,
1200
- // Command line option
1201
- ccjkConfig,
1202
- options.skipPrompt
1203
- // Non-interactive mode flag
1204
- );
1205
- const aiOutputLang = await resolveAiOutputLanguage(i18n.language, options.aiOutputLang, ccjkConfig, options.skipPrompt);
1206
- const runtimeLabel = isClaudeFamilyCodeTool(codeToolType) ? getClaudeFamilyRuntimeLabel(codeToolType) : "Claude Code";
1207
- console.log(ansis.cyan(`
1208
- ${i18n.t("configuration:updatingPrompts", { runtime: runtimeLabel })}
1209
- `));
1210
- await updatePromptOnly(aiOutputLang);
1211
- await selectAndInstallWorkflows(configLang, void 0, { codeToolType: isClaudeFamilyCodeTool(codeToolType) ? codeToolType : "claude-code" });
1212
- if (codeToolType === "claude-code") {
1213
- await checkClaudeCodeVersionAndPrompt(false);
1214
- }
1215
- updateCcjkConfig({
1216
- version,
1217
- templateLang: configLang,
1218
- // 保存模板语言选择
1219
- aiOutputLang,
1220
- codeToolType
1221
- });
1222
- } catch (error) {
1223
- if (!handleExitPromptError(error)) {
1224
- handleGeneralError(error);
1225
- }
1226
- }
1227
- }
1228
-
1229
- const GROK_AUTH_FILE = join(homedir(), ".grok", "auth.json");
1230
- function isGrokInstalled() {
1231
- try {
1232
- execSync("command -v grok", { stdio: "ignore" });
1233
- return true;
1234
- } catch {
1235
- return false;
1236
- }
1237
- }
1238
- function isGrokLoggedIn() {
1239
- if (!existsSync(GROK_AUTH_FILE)) return false;
1240
- try {
1241
- const data = JSON.parse(readFileSync(GROK_AUTH_FILE, "utf-8"));
1242
- return Object.keys(data).some((k) => k.includes("auth.x.ai"));
1243
- } catch {
1244
- return false;
1245
- }
1246
- }
1247
- function getGrokQuickStatus() {
1248
- if (!isGrokInstalled()) {
1249
- return {
1250
- installed: false,
1251
- loggedIn: false,
1252
- hint: "\u672A\u5B89\u88C5\uFF1Acurl -fsSL https://x.ai/cli/install.sh | bash"
1253
- };
1254
- }
1255
- const loggedIn = isGrokLoggedIn();
1256
- return {
1257
- installed: true,
1258
- loggedIn,
1259
- hint: loggedIn ? "\u5DF2\u767B\u5F55\uFF08OAuth\uFF0C~/.grok/auth.json\uFF09" : "\u672A\u767B\u5F55\uFF0C\u8FD0\u884C `grok login`"
1260
- };
1261
- }
1262
- function buildGrokHints() {
1263
- const s = getGrokQuickStatus();
1264
- const lines = [];
1265
- if (!s.installed) {
1266
- lines.push(ansis.dim(" \u5B89\u88C5: ") + ansis.cyan("curl -fsSL https://x.ai/cli/install.sh | bash"));
1267
- return lines;
1268
- }
1269
- if (!s.loggedIn) {
1270
- lines.push(ansis.yellow(" \u767B\u5F55: ") + ansis.cyan("grok login"));
1271
- }
1272
- lines.push(ansis.dim(" \u542F\u52A8: ") + ansis.cyan("grok"));
1273
- lines.push(ansis.dim(" \u6A21\u578B: ") + ansis.cyan("grok models"));
1274
- return lines;
1275
- }
1276
-
1277
- const PROFILES_DIR$1 = join(homedir(), ".ccjk", "profiles");
1278
- function readProfile$1(name) {
1279
- const p = join(PROFILES_DIR$1, `${name}.json`);
1280
- if (!existsSync(p)) return null;
1281
- try {
1282
- return JSON.parse(readFileSync(p, "utf-8"));
1283
- } catch {
1284
- return null;
1285
- }
1286
- }
1287
- async function grokCommand(profileName) {
1288
- if (profileName) {
1289
- await launchWithProfile$1(profileName);
1290
- return;
1291
- }
1292
- const status = getGrokQuickStatus();
1293
- console.log(ansis.bold("\nGrok CLI"));
1294
- console.log(` \u5B89\u88C5: ${status.installed ? ansis.green("\u662F") : ansis.gray("\u5426")} \u767B\u5F55: ${status.loggedIn ? ansis.green("\u662F") : ansis.yellow("\u5426")}`);
1295
- for (const line of buildGrokHints()) console.log(line);
1296
- console.log(ansis.dim("\n ccjk grok <profile> \u2014 \u7528 ~/.ccjk/profiles \u914D\u7F6E\u542F\u52A8\n"));
1297
- }
1298
- async function launchWithProfile$1(name) {
1299
- const profile = readProfile$1(name);
1300
- if (!profile) {
1301
- console.log(ansis.red(`Profile "${name}" \u4E0D\u5B58\u5728`));
1302
- console.log(ansis.dim(" \u5148\u8FD0\u884C ccjk init \u914D\u7F6E API\uFF08\u4F1A\u81EA\u52A8\u4FDD\u5B58 profile\uFF09\n"));
1303
- return;
1304
- }
1305
- const env = { ...process.env };
1306
- if (profile.baseUrl) {
1307
- env.OPENAI_BASE_URL = profile.baseUrl;
1308
- env.ANTHROPIC_BASE_URL = profile.baseUrl;
1309
- }
1310
- if (profile.apiKey) {
1311
- env.OPENAI_API_KEY = profile.apiKey;
1312
- env.ANTHROPIC_API_KEY = profile.apiKey;
1313
- env.ANTHROPIC_AUTH_TOKEN = profile.apiKey;
2259
+ if (mode === "complete") {
2260
+ if (totalErrors === 0) {
2261
+ console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:completeSuccess")}`));
2262
+ } else {
2263
+ console.log(ansis.yellow.bold(`\u26A0 ${i18n.t("uninstall:completePartialSuccess")}`));
2264
+ }
2265
+ } else {
2266
+ if (totalRemovedFiles > 0 && totalRemovedConfigs > 0) {
2267
+ console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccessBoth", {
2268
+ fileCount: totalRemovedFiles,
2269
+ configCount: totalRemovedConfigs
2270
+ })}`));
2271
+ } else if (totalRemovedFiles > 0) {
2272
+ console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccessFiles", {
2273
+ count: totalRemovedFiles
2274
+ })}`));
2275
+ } else if (totalRemovedConfigs > 0) {
2276
+ console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccessConfigs", {
2277
+ count: totalRemovedConfigs
2278
+ })}`));
2279
+ } else {
2280
+ console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccess", { count: totalSuccess })}`));
2281
+ }
2282
+ if (totalErrors > 0) {
2283
+ console.log(ansis.red(`\u2716 ${i18n.t("uninstall:errorsCount", { count: totalErrors })}`));
2284
+ }
2285
+ if (totalWarnings > 0) {
2286
+ console.log(ansis.yellow(`\u26A0 ${i18n.t("uninstall:warningsCount", { count: totalWarnings })}`));
2287
+ }
1314
2288
  }
1315
- console.log(ansis.cyan(`
1316
- \u4F7F\u7528 profile "${name}" \u542F\u52A8 grok...
1317
- `));
1318
- const res = spawnSync("grok", [], { stdio: "inherit", env });
1319
- if (res.error) console.log(ansis.red(`\u542F\u52A8\u5931\u8D25: ${res.error.message}`));
2289
+ console.log("");
1320
2290
  }
1321
2291
 
1322
2292
  const REASONIX_GLOBAL_CONFIG = join(homedir(), ".config", "reasonix", "config.toml");
@@ -1496,16 +2466,6 @@ function buildReasonixHints(cwd = process.cwd()) {
1496
2466
  return lines;
1497
2467
  }
1498
2468
 
1499
- const PROFILES_DIR = join(homedir(), ".ccjk", "profiles");
1500
- function readProfile(name) {
1501
- const p = join(PROFILES_DIR, `${name}.json`);
1502
- if (!existsSync(p)) return null;
1503
- try {
1504
- return JSON.parse(readFileSync(p, "utf-8"));
1505
- } catch {
1506
- return null;
1507
- }
1508
- }
1509
2469
  async function reasonixCommand(profileName, options = {}) {
1510
2470
  if (profileName) {
1511
2471
  await launchWithProfile(profileName, options);
@@ -1514,14 +2474,19 @@ async function reasonixCommand(profileName, options = {}) {
1514
2474
  for (const line of buildReasonixHints()) {
1515
2475
  console.log(line);
1516
2476
  }
2477
+ const names = listCcjkProfileNames();
2478
+ if (names.length > 0) {
2479
+ console.log(ansis.dim(`
2480
+ \u53EF\u7528 profile: ${names.join(", ")}`));
2481
+ }
1517
2482
  console.log(ansis.dim("\n ccjk reasonix <profile> \u2014 \u6CE8\u5165 key \u5E76\u542F\u52A8\uFF08\u65E0 reasonix.toml \u65F6\u81EA\u52A8\u751F\u6210\uFF09"));
1518
2483
  console.log(ansis.dim(' ccjk reasonix <profile> --run -p "task" \u2014 \u5355\u6B21 reasonix run\n'));
1519
2484
  }
1520
2485
  async function launchWithProfile(name, options) {
1521
- const profile = readProfile(name);
2486
+ const profile = readCcjkProfileByName(name);
1522
2487
  if (!profile) {
1523
2488
  console.log(ansis.red(`Profile "${name}" \u4E0D\u5B58\u5728`));
1524
- console.log(ansis.dim(" \u5148\u8FD0\u884C ccjk init \u914D\u7F6E API\uFF0C\u6216\u786E\u8BA4 ~/.ccjk/profiles/<name>.json \u5B58\u5728\n"));
2489
+ console.log(ansis.dim(" \u5148\u8FD0\u884C ccjk init \u914D\u7F6E API\uFF08profile \u4FDD\u5B58\u5728 ~/.ccjk/config.toml\uFF09\n"));
1525
2490
  return;
1526
2491
  }
1527
2492
  if (!isReasonixInstalled()) {
@@ -1571,71 +2536,6 @@ function buildRunArgs(model, prompt) {
1571
2536
  return args;
1572
2537
  }
1573
2538
 
1574
- const TIMEOUT_MS = 1e4;
1575
- const EXIT_CODE = {
1576
- ok: 0,
1577
- "auth-failed": 1,
1578
- unreachable: 2,
1579
- unexpected: 3
1580
- };
1581
- async function probeCommand(opts = {}) {
1582
- const creds = readActiveApiCreds();
1583
- if (!creds.baseUrl) {
1584
- throw new Error("\u672A\u627E\u5230 API \u914D\u7F6E\uFF0C\u8BF7\u5148\u8FD0\u884C ccjk init \u6216\u83DC\u5355 3 \u914D\u7F6E API");
1585
- }
1586
- const result = await runProbe(creds.baseUrl, creds.apiKey, creds.authToken);
1587
- if (opts.json) {
1588
- console.log(JSON.stringify(result, null, 2));
1589
- } else {
1590
- const color = result.status === "ok" ? ansis.green : ansis.red;
1591
- console.log(`
1592
- \u63A2\u6D3B ${creds.baseUrl}`);
1593
- console.log(color(` \u72B6\u6001: ${result.status}`));
1594
- if (result.httpStatus) console.log(ansis.dim(` HTTP: ${result.httpStatus}`));
1595
- if (result.latencyMs) console.log(ansis.dim(` \u5EF6\u8FDF: ${result.latencyMs}ms`));
1596
- if (result.error) console.log(ansis.dim(` \u9519\u8BEF: ${result.error}`));
1597
- console.log();
1598
- }
1599
- process.exitCode = EXIT_CODE[result.status];
1600
- }
1601
- function readActiveApiCreds() {
1602
- const tool = readCcjkConfig()?.codeToolType ?? "clavue";
1603
- const file = activeSettingsFile(tool === "codex" || tool === "grok" ? "claude-code" : tool);
1604
- const settings = readJsonConfig(file) || {};
1605
- const env = settings.env || {};
1606
- return {
1607
- baseUrl: env.ANTHROPIC_BASE_URL || "",
1608
- apiKey: env.ANTHROPIC_API_KEY || "",
1609
- authToken: env.ANTHROPIC_AUTH_TOKEN || env.ANTHROPIC_API_KEY || ""
1610
- };
1611
- }
1612
- async function runProbe(baseUrl, apiKey, authToken) {
1613
- const url = `${baseUrl.replace(/\/$/, "")}/v1/messages`;
1614
- const headers = {
1615
- "content-type": "application/json",
1616
- "anthropic-version": "2023-06-01"
1617
- };
1618
- if (authToken) headers.authorization = `Bearer ${authToken}`;
1619
- else if (apiKey) headers["x-api-key"] = apiKey;
1620
- const body = JSON.stringify({
1621
- model: "claude-3-5-haiku-20241022",
1622
- max_tokens: 1,
1623
- messages: [{ role: "user", content: "ping" }]
1624
- });
1625
- const t0 = Date.now();
1626
- try {
1627
- const res = await fetch(url, { method: "POST", headers, body, signal: AbortSignal.timeout(TIMEOUT_MS) });
1628
- const latencyMs = Date.now() - t0;
1629
- if (res.status === 401 || res.status === 403) {
1630
- return { baseUrl, status: "auth-failed", httpStatus: res.status, latencyMs };
1631
- }
1632
- if (res.ok) return { baseUrl, status: "ok", httpStatus: res.status, latencyMs };
1633
- return { baseUrl, status: "unexpected", httpStatus: res.status, latencyMs };
1634
- } catch (e) {
1635
- return { baseUrl, status: "unreachable", error: e.message, latencyMs: Date.now() - t0 };
1636
- }
1637
- }
1638
-
1639
2539
  const ONBOARDING_STATE_FILE = join(CCJK_CONFIG_DIR, "onboarding.json");
1640
2540
  const LANGUAGE_SELECTION_MESSAGES = {
1641
2541
  selectLanguage: "Select CCJK display language / \u9009\u62E9 CCJK \u663E\u793A\u8BED\u8A00"
@@ -1820,521 +2720,125 @@ function getCodeToolLabel(codeTool) {
1820
2720
  return CODE_TOOL_LABELS[codeTool] || codeTool;
1821
2721
  }
1822
2722
  async function promptCodeToolSelection(current) {
2723
+ const { addNumbersToChoices } = await import('./chunks/simple-config.mjs').then(function (n) { return n.bM; });
1823
2724
  const choices = addNumbersToChoices(Object.entries(CODE_TOOL_LABELS).map(([value, label]) => ({
1824
2725
  name: label,
1825
2726
  value,
1826
2727
  short: label
1827
2728
  })));
1828
- const { tool } = await inquirer.prompt({
1829
- type: "list",
1830
- name: "tool",
1831
- message: i18n.t("menu:switchCodeToolPrompt"),
1832
- default: current,
1833
- choices
1834
- });
1835
- if (!tool) {
1836
- console.log(ansis.yellow(i18n.t("common:cancelled")));
1837
- return null;
1838
- }
1839
- return tool;
1840
- }
1841
- async function handleCodeToolSwitch(current) {
1842
- const newTool = await promptCodeToolSelection(current);
1843
- if (!newTool || newTool === current) {
1844
- return false;
1845
- }
1846
- updateCcjkConfig({ codeToolType: newTool });
1847
- console.log(ansis.green(`\u2714 ${i18n.t("menu:codeToolSwitched", { tool: getCodeToolLabel(newTool) })}`));
1848
- return true;
1849
- }
1850
- function printOtherToolsSection() {
1851
- console.log(` --------- ${i18n.t("menu:menuSections.otherTools")} ----------`);
1852
- console.log(
1853
- ` ${ansis.cyan("R.")} ${i18n.t("menu:menuOptions.ccrManagement")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.ccrManagement")}`)}`
1854
- );
1855
- console.log(
1856
- ` ${ansis.cyan("U.")} ${i18n.t("menu:menuOptions.ccusage")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.ccusage")}`)}`
1857
- );
1858
- console.log(
1859
- ` ${ansis.cyan("L.")} ${i18n.t("menu:menuOptions.cometixLine")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.cometixLine")}`)}`
1860
- );
1861
- console.log(
1862
- ` ${ansis.cyan("P.")} Probe API ${ansis.gray("- HTTP \u63A2\u6D3B\u5F53\u524D\u914D\u7F6E")}`
1863
- );
1864
- console.log(
1865
- ` ${ansis.cyan("G.")} Grok CLI ${ansis.gray("- \u72B6\u6001 / \u542F\u52A8\u6307\u5F15")}`
1866
- );
1867
- console.log(
1868
- ` ${ansis.cyan("X.")} Reasonix ${ansis.gray("- DeepSeek agent \u72B6\u6001 / \u542F\u52A8\u6307\u5F15")}`
1869
- );
1870
- console.log("");
1871
- }
1872
- function printCcjkSection(options) {
1873
- console.log(" ------------ CCJK ------------");
1874
- console.log(
1875
- ` ${ansis.cyan("0.")} ${i18n.t("menu:menuOptions.changeLanguage")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.changeLanguage")}`)}`
1876
- );
1877
- console.log(
1878
- ` ${ansis.cyan("S.")} ${i18n.t("menu:menuOptions.switchCodeTool")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.switchCodeTool")}`)}`
1879
- );
1880
- console.log(
1881
- ` ${ansis.cyan("-.")} ${options.uninstallOption} ${ansis.gray(`- ${options.uninstallDescription}`)}`
1882
- );
1883
- console.log(
1884
- ` ${ansis.cyan("+.")} ${options.updateOption} ${ansis.gray(`- ${options.updateDescription}`)}`
1885
- );
1886
- console.log(` ${ansis.red("Q.")} ${ansis.red(i18n.t("menu:menuOptions.exit"))}`);
1887
- console.log("");
1888
- }
1889
- async function showClavueMenu() {
1890
- console.log(ansis.cyan(i18n.t("menu:selectFunction")));
1891
- console.log(" -------- Clavue --------");
1892
- console.log(
1893
- ` ${ansis.cyan("1.")} ${i18n.t("menu:menuOptions.clavueFullInit")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.clavueFullInit")}`)}`
1894
- );
1895
- console.log(
1896
- ` ${ansis.cyan("2.")} ${i18n.t("menu:menuOptions.clavueUpdateWorkflow")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.clavueUpdateWorkflow")}`)}`
1897
- );
1898
- console.log(
1899
- ` ${ansis.cyan("3.")} ${i18n.t("menu:menuOptions.clavueConfigureApi")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.clavueConfigureApi")}`)}`
1900
- );
1901
- console.log(
1902
- ` ${ansis.cyan("4.")} ${i18n.t("menu:menuOptions.clavueConfigureMcp")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.clavueConfigureMcp")}`)}`
1903
- );
1904
- console.log(
1905
- ` ${ansis.cyan("5.")} ${i18n.t("menu:menuOptions.clavueConfigureModel")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.clavueConfigureModel")}`)}`
1906
- );
1907
- console.log(
1908
- ` ${ansis.cyan("6.")} ${i18n.t("menu:menuOptions.clavueConfigureAiMemory")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.clavueConfigureAiMemory")}`)}`
1909
- );
1910
- console.log(
1911
- ` ${ansis.cyan("7.")} ${i18n.t("menu:menuOptions.clavueConfigureEnvPermission")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.clavueConfigureEnvPermission")}`)}`
1912
- );
1913
- console.log(
1914
- ` ${ansis.cyan("8.")} ${i18n.t("menu:menuOptions.clavueStatus")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.clavueStatus")}`)}`
1915
- );
1916
- console.log("");
1917
- printOtherToolsSection();
1918
- printCcjkSection({
1919
- uninstallOption: i18n.t("menu:menuOptions.clavueUninstall"),
1920
- uninstallDescription: i18n.t("menu:menuDescriptions.clavueUninstall"),
1921
- updateOption: i18n.t("menu:menuOptions.clavueCheckUpdates"),
1922
- updateDescription: i18n.t("menu:menuDescriptions.clavueCheckUpdates")
1923
- });
1924
- const { choice } = await inquirer.prompt({
1925
- type: "input",
1926
- name: "choice",
1927
- message: i18n.t("common:enterChoice"),
1928
- validate: (value) => {
1929
- const valid = ["1", "2", "3", "4", "5", "6", "7", "8", "r", "R", "u", "U", "l", "L", "p", "P", "g", "G", "x", "X", "0", "-", "+", "s", "S", "q", "Q"];
1930
- return valid.includes(value) || i18n.t("common:invalidChoice");
1931
- }
1932
- });
1933
- if (!choice) {
1934
- console.log(ansis.yellow(i18n.t("common:cancelled")));
1935
- return "exit";
1936
- }
1937
- const normalized = choice.toLowerCase();
1938
- switch (normalized) {
1939
- case "1":
1940
- await init({ skipBanner: true, codeType: "clavue" });
1941
- break;
1942
- case "2":
1943
- await update({ skipBanner: true, codeType: "clavue" });
1944
- break;
1945
- case "3":
1946
- await configureApiFeature();
1947
- break;
1948
- case "4":
1949
- await configureMcpFeature();
1950
- break;
1951
- case "5":
1952
- await configureDefaultModelFeature();
1953
- break;
1954
- case "6":
1955
- await configureAiMemoryFeature();
1956
- break;
1957
- case "7":
1958
- await configureEnvPermissionFeature();
1959
- break;
1960
- case "8":
1961
- case "p":
1962
- await probeCommand();
1963
- printSeparator();
1964
- return void 0;
1965
- case "r":
1966
- await runCcrMenuFeature();
1967
- printSeparator();
1968
- return void 0;
1969
- case "u":
1970
- await runCcusageFeature();
1971
- printSeparator();
1972
- return void 0;
1973
- case "l":
1974
- await runCometixMenuFeature();
1975
- printSeparator();
1976
- return void 0;
1977
- case "g":
1978
- await grokCommand();
1979
- printSeparator();
1980
- return void 0;
1981
- case "x":
1982
- await reasonixCommand();
1983
- printSeparator();
1984
- return void 0;
1985
- case "0": {
1986
- const currentLang = i18n.language;
1987
- await changeScriptLanguageFeature(currentLang);
1988
- printSeparator();
1989
- return void 0;
1990
- }
1991
- case "-":
1992
- await uninstall();
1993
- printSeparator();
1994
- return void 0;
1995
- case "+":
1996
- await checkUpdates();
1997
- printSeparator();
1998
- return void 0;
1999
- case "s": {
2000
- const switched = await handleCodeToolSwitch("clavue");
2001
- if (switched) {
2002
- return "switch";
2003
- }
2004
- printSeparator();
2005
- return void 0;
2006
- }
2007
- case "q":
2008
- console.log(ansis.cyan(i18n.t("common:goodbye")));
2009
- return "exit";
2010
- default:
2011
- return void 0;
2012
- }
2013
- printSeparator();
2014
- const shouldContinue = await promptBoolean({
2015
- message: i18n.t("common:returnToMenu"),
2016
- defaultValue: true
2017
- });
2018
- if (!shouldContinue) {
2019
- console.log(ansis.cyan(i18n.t("common:goodbye")));
2020
- return "exit";
2021
- }
2022
- return void 0;
2023
- }
2024
- async function showClaudeCodeMenu() {
2025
- console.log(ansis.cyan(i18n.t("menu:selectFunction")));
2026
- console.log(" -------- Claude Code --------");
2027
- console.log(
2028
- ` ${ansis.cyan("1.")} ${i18n.t("menu:menuOptions.fullInit")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.fullInit")}`)}`
2029
- );
2030
- console.log(
2031
- ` ${ansis.cyan("2.")} ${i18n.t("menu:menuOptions.importWorkflow")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.importWorkflow")}`)}`
2032
- );
2033
- console.log(
2034
- ` ${ansis.cyan("3.")} ${i18n.t("menu:menuOptions.configureApiOrCcr")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureApiOrCcr")}`)}`
2035
- );
2036
- console.log(
2037
- ` ${ansis.cyan("4.")} ${i18n.t("menu:menuOptions.configureMcp")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureMcp")}`)}`
2038
- );
2039
- console.log(
2040
- ` ${ansis.cyan("5.")} ${i18n.t("menu:menuOptions.configureModel")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureModel")}`)}`
2041
- );
2042
- console.log(
2043
- ` ${ansis.cyan("6.")} ${i18n.t("menu:menuOptions.configureAiMemory")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureAiMemory")}`)}`
2044
- );
2045
- console.log(
2046
- ` ${ansis.cyan("7.")} ${i18n.t("menu:menuOptions.configureEnvPermission")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureEnvPermission")}`)}`
2047
- );
2048
- console.log("");
2049
- printOtherToolsSection();
2050
- printCcjkSection({
2051
- uninstallOption: i18n.t("menu:menuOptions.uninstall"),
2052
- uninstallDescription: i18n.t("menu:menuDescriptions.uninstall"),
2053
- updateOption: i18n.t("menu:menuOptions.checkUpdates"),
2054
- updateDescription: i18n.t("menu:menuDescriptions.checkUpdates")
2055
- });
2056
- const { choice } = await inquirer.prompt({
2057
- type: "input",
2058
- name: "choice",
2059
- message: i18n.t("common:enterChoice"),
2060
- validate: (value) => {
2061
- const valid = ["1", "2", "3", "4", "5", "6", "7", "r", "R", "u", "U", "l", "L", "p", "P", "g", "G", "0", "-", "+", "s", "S", "q", "Q"];
2062
- return valid.includes(value) || i18n.t("common:invalidChoice");
2063
- }
2729
+ const { tool } = await inquirer.prompt({
2730
+ type: "list",
2731
+ name: "tool",
2732
+ message: i18n.t("menu:switchCodeToolPrompt"),
2733
+ default: current,
2734
+ choices
2064
2735
  });
2065
- if (!choice) {
2736
+ if (!tool) {
2066
2737
  console.log(ansis.yellow(i18n.t("common:cancelled")));
2067
- return "exit";
2738
+ return null;
2739
+ }
2740
+ return tool;
2741
+ }
2742
+ async function handleCodeToolSwitch(current) {
2743
+ const newTool = await promptCodeToolSelection(current);
2744
+ if (!newTool || newTool === current) {
2745
+ return false;
2068
2746
  }
2069
- const normalized = choice.toLowerCase();
2070
- switch (normalized) {
2747
+ updateCcjkConfig({ codeToolType: newTool });
2748
+ console.log(ansis.green(`\u2714 ${i18n.t("menu:codeToolSwitched", { tool: getCodeToolLabel(newTool) })}`));
2749
+ return true;
2750
+ }
2751
+ async function handleClaudeFamilyChoice(tool, choice) {
2752
+ switch (choice) {
2071
2753
  case "1":
2072
- await init({ skipBanner: true });
2073
- break;
2754
+ await init({ skipBanner: true, codeType: tool });
2755
+ return "handled";
2074
2756
  case "2":
2075
- await update({ skipBanner: true });
2076
- break;
2757
+ await update({ skipBanner: true, codeType: tool });
2758
+ return "handled";
2077
2759
  case "3":
2078
2760
  await configureApiFeature();
2079
- break;
2761
+ return "handled";
2080
2762
  case "4":
2081
2763
  await configureMcpFeature();
2082
- break;
2764
+ return "handled";
2083
2765
  case "5":
2084
2766
  await configureDefaultModelFeature();
2085
- break;
2767
+ return "handled";
2086
2768
  case "6":
2087
2769
  await configureAiMemoryFeature();
2088
- break;
2770
+ return "handled";
2089
2771
  case "7":
2090
2772
  await configureEnvPermissionFeature();
2091
- break;
2092
- case "r":
2093
- await runCcrMenuFeature();
2094
- printSeparator();
2095
- return void 0;
2096
- case "u":
2097
- await runCcusageFeature();
2098
- printSeparator();
2099
- return void 0;
2100
- case "l":
2101
- await runCometixMenuFeature();
2102
- printSeparator();
2103
- return void 0;
2104
- case "p":
2105
- await probeCommand();
2106
- printSeparator();
2107
- return void 0;
2108
- case "g":
2109
- await grokCommand();
2110
- printSeparator();
2111
- return void 0;
2112
- case "x":
2113
- await reasonixCommand();
2114
- printSeparator();
2115
- return void 0;
2116
- case "0": {
2117
- const currentLang = i18n.language;
2118
- await changeScriptLanguageFeature(currentLang);
2119
- printSeparator();
2120
- return void 0;
2121
- }
2122
- case "-":
2123
- await uninstall();
2124
- printSeparator();
2125
- return void 0;
2126
- case "+":
2127
- await checkUpdates();
2128
- printSeparator();
2129
- return void 0;
2130
- case "s": {
2131
- const switched = await handleCodeToolSwitch("claude-code");
2132
- if (switched) {
2133
- return "switch";
2134
- }
2135
- printSeparator();
2136
- return void 0;
2137
- }
2138
- case "q":
2139
- console.log(ansis.cyan(i18n.t("common:goodbye")));
2140
- return "exit";
2773
+ return "handled";
2141
2774
  default:
2142
2775
  return void 0;
2143
2776
  }
2144
- printSeparator();
2145
- const shouldContinue = await promptBoolean({
2146
- message: i18n.t("common:returnToMenu"),
2147
- defaultValue: true
2148
- });
2149
- if (!shouldContinue) {
2150
- console.log(ansis.cyan(i18n.t("common:goodbye")));
2151
- return "exit";
2152
- }
2153
- return void 0;
2154
2777
  }
2155
- async function showCodexMenu() {
2156
- console.log(ansis.cyan(i18n.t("menu:selectFunction")));
2157
- console.log(" -------- Codex --------");
2158
- console.log(
2159
- ` ${ansis.cyan("1.")} ${i18n.t("menu:menuOptions.codexFullInit")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexFullInit")}`)}`
2160
- );
2161
- console.log(
2162
- ` ${ansis.cyan("2.")} ${i18n.t("menu:menuOptions.codexImportWorkflow")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexImportWorkflow")}`)}`
2163
- );
2164
- console.log(
2165
- ` ${ansis.cyan("3.")} ${i18n.t("menu:menuOptions.codexConfigureApi")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexConfigureApi")}`)}`
2166
- );
2167
- console.log(
2168
- ` ${ansis.cyan("4.")} ${i18n.t("menu:menuOptions.codexConfigureMcp")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexConfigureMcp")}`)}`
2169
- );
2170
- console.log(
2171
- ` ${ansis.cyan("5.")} ${i18n.t("menu:menuOptions.codexConfigureModel")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexConfigureModel")}`)}`
2172
- );
2173
- console.log(
2174
- ` ${ansis.cyan("6.")} ${i18n.t("menu:menuOptions.codexConfigureAiMemory")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexConfigureAiMemory")}`)}`
2175
- );
2176
- console.log("");
2177
- printCcjkSection({
2178
- uninstallOption: i18n.t("menu:menuOptions.codexUninstall"),
2179
- uninstallDescription: i18n.t("menu:menuDescriptions.codexUninstall"),
2180
- updateOption: i18n.t("menu:menuOptions.codexCheckUpdates"),
2181
- updateDescription: i18n.t("menu:menuDescriptions.codexCheckUpdates")
2182
- });
2183
- const { choice } = await inquirer.prompt({
2184
- type: "input",
2185
- name: "choice",
2186
- message: i18n.t("common:enterChoice"),
2187
- validate: (value) => {
2188
- const valid = ["1", "2", "3", "4", "5", "6", "0", "-", "+", "s", "S", "q", "Q"];
2189
- return valid.includes(value) || i18n.t("common:invalidChoice");
2190
- }
2191
- });
2192
- if (!choice) {
2193
- console.log(ansis.yellow(i18n.t("common:cancelled")));
2194
- return "exit";
2195
- }
2196
- const normalized = choice.toLowerCase();
2197
- switch (normalized) {
2778
+ async function handleCodexChoice(choice) {
2779
+ switch (choice) {
2198
2780
  case "1":
2199
2781
  await runCodexFullInit();
2200
- break;
2782
+ return "handled";
2201
2783
  case "2":
2202
2784
  await runCodexWorkflowImportWithLanguageSelection();
2203
- break;
2785
+ return "handled";
2204
2786
  case "3":
2205
2787
  await configureCodexApi();
2206
- break;
2788
+ return "handled";
2207
2789
  case "4":
2208
2790
  await manageCodexMcp();
2209
- break;
2791
+ return "handled";
2210
2792
  case "5":
2211
2793
  await configureCodexDefaultModelFeature();
2212
- break;
2794
+ return "handled";
2213
2795
  case "6":
2214
2796
  await configureCodexAiMemoryFeature();
2215
- break;
2216
- case "0": {
2217
- const currentLang = i18n.language;
2218
- await changeScriptLanguageFeature(currentLang);
2219
- printSeparator();
2220
- return void 0;
2221
- }
2222
- case "-":
2223
- await runCodexUninstall();
2224
- printSeparator();
2225
- return void 0;
2226
- case "+":
2227
- await runCodexUpdate();
2228
- printSeparator();
2229
- return void 0;
2230
- case "s": {
2231
- const switched = await handleCodeToolSwitch("codex");
2232
- if (switched) {
2233
- return "switch";
2234
- }
2235
- printSeparator();
2236
- return void 0;
2237
- }
2238
- case "q":
2239
- console.log(ansis.cyan(i18n.t("common:goodbye")));
2240
- return "exit";
2797
+ return "handled";
2241
2798
  default:
2242
2799
  return void 0;
2243
2800
  }
2244
- printSeparator();
2245
- const shouldContinue = await promptBoolean({
2246
- message: i18n.t("common:returnToMenu"),
2247
- defaultValue: true
2248
- });
2249
- if (!shouldContinue) {
2250
- console.log(ansis.cyan(i18n.t("common:goodbye")));
2251
- return "exit";
2252
- }
2253
- return void 0;
2254
2801
  }
2255
- async function showGrokMenu() {
2256
- console.log(ansis.cyan(i18n.t("menu:selectFunction")));
2257
- console.log(" -------- Grok CLI --------");
2258
- console.log(
2259
- ` ${ansis.cyan("1.")} ${i18n.t("menu:menuOptions.grokInit")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.grokInit")}`)}`
2260
- );
2261
- console.log(
2262
- ` ${ansis.cyan("2.")} ${i18n.t("menu:menuOptions.grokStatus")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.grokStatus")}`)}`
2263
- );
2264
- console.log("");
2265
- printOtherToolsSection();
2266
- printCcjkSection({
2267
- uninstallOption: i18n.t("menu:menuOptions.uninstall"),
2268
- uninstallDescription: i18n.t("menu:menuDescriptions.uninstall"),
2269
- updateOption: i18n.t("menu:menuOptions.checkUpdates"),
2270
- updateDescription: i18n.t("menu:menuDescriptions.checkUpdates")
2271
- });
2272
- const { choice } = await inquirer.prompt({
2273
- type: "input",
2274
- name: "choice",
2275
- message: i18n.t("common:enterChoice"),
2276
- validate: (value) => {
2277
- const valid = ["1", "2", "r", "R", "u", "U", "l", "L", "p", "P", "g", "G", "x", "X", "0", "-", "+", "s", "S", "q", "Q"];
2278
- return valid.includes(value) || i18n.t("common:invalidChoice");
2279
- }
2280
- });
2281
- if (!choice) {
2282
- console.log(ansis.yellow(i18n.t("common:cancelled")));
2283
- return "exit";
2284
- }
2285
- const normalized = choice.toLowerCase();
2286
- switch (normalized) {
2802
+ async function handleGrokChoice(choice) {
2803
+ switch (choice) {
2287
2804
  case "1":
2288
2805
  await init({ skipBanner: true, codeType: "grok" });
2289
- break;
2806
+ return "handled";
2290
2807
  case "2":
2291
2808
  await grokCommand();
2292
- break;
2293
- case "r":
2294
- await runCcrMenuFeature();
2295
- printSeparator();
2296
- return void 0;
2297
- case "u":
2298
- await runCcusageFeature();
2299
- printSeparator();
2300
- return void 0;
2301
- case "l":
2302
- await runCometixMenuFeature();
2303
- printSeparator();
2809
+ return "handled";
2810
+ default:
2304
2811
  return void 0;
2305
- case "p":
2306
- await probeCommand();
2307
- printSeparator();
2812
+ }
2813
+ }
2814
+ async function handleHubChoice(tool, choice) {
2815
+ switch (choice) {
2816
+ case "h":
2817
+ await runDoctorHub(tool);
2818
+ return "continue";
2819
+ case "w":
2820
+ await runOperatorHub(tool);
2821
+ return "handled";
2822
+ default:
2308
2823
  return void 0;
2824
+ }
2825
+ }
2826
+ async function handleSharedChoice(tool, choice) {
2827
+ switch (choice) {
2309
2828
  case "g":
2310
2829
  await grokCommand();
2311
- printSeparator();
2312
- return void 0;
2830
+ return "continue";
2313
2831
  case "x":
2314
2832
  await reasonixCommand();
2315
- printSeparator();
2316
- return void 0;
2833
+ return "continue";
2317
2834
  case "0": {
2318
2835
  const currentLang = i18n.language;
2319
2836
  await changeScriptLanguageFeature(currentLang);
2320
- printSeparator();
2321
- return void 0;
2837
+ return "continue";
2322
2838
  }
2323
- case "-":
2324
- await uninstall();
2325
- printSeparator();
2326
- return void 0;
2327
- case "+":
2328
- await checkUpdates();
2329
- printSeparator();
2330
- return void 0;
2331
2839
  case "s": {
2332
- const switched = await handleCodeToolSwitch("grok");
2333
- if (switched) {
2334
- return "switch";
2335
- }
2336
- printSeparator();
2337
- return void 0;
2840
+ const switched = await handleCodeToolSwitch(tool);
2841
+ return switched ? "switch" : "continue";
2338
2842
  }
2339
2843
  case "q":
2340
2844
  console.log(ansis.cyan(i18n.t("common:goodbye")));
@@ -2342,6 +2846,70 @@ async function showGrokMenu() {
2342
2846
  default:
2343
2847
  return void 0;
2344
2848
  }
2849
+ }
2850
+ async function handleToolSpecificMaintenance(tool, choice) {
2851
+ if (choice === "-") {
2852
+ if (tool === "codex") {
2853
+ await runCodexUninstall();
2854
+ } else {
2855
+ await uninstall();
2856
+ }
2857
+ return "continue";
2858
+ }
2859
+ if (choice === "+") {
2860
+ if (tool === "codex") {
2861
+ await runCodexUpdate();
2862
+ } else {
2863
+ await checkUpdates();
2864
+ }
2865
+ return "continue";
2866
+ }
2867
+ return void 0;
2868
+ }
2869
+ async function dispatchMenuChoice(tool, rawChoice) {
2870
+ const choice = rawChoice.toLowerCase();
2871
+ const hubResult = ["h", "w"].includes(choice) ? await handleHubChoice(tool, choice) : void 0;
2872
+ if (hubResult)
2873
+ return hubResult;
2874
+ const sharedResult = await handleSharedChoice(tool, choice);
2875
+ if (sharedResult)
2876
+ return sharedResult;
2877
+ const maintenanceResult = await handleToolSpecificMaintenance(tool, choice);
2878
+ if (maintenanceResult)
2879
+ return maintenanceResult;
2880
+ const layout = getToolMenuLayout(tool);
2881
+ if (!layout.operatorLines.some((item) => item.key === choice))
2882
+ return void 0;
2883
+ if (tool === "clavue" || tool === "claude-code")
2884
+ return await handleClaudeFamilyChoice(tool, choice);
2885
+ if (tool === "codex")
2886
+ return await handleCodexChoice(choice);
2887
+ if (tool === "grok")
2888
+ return await handleGrokChoice(choice);
2889
+ return void 0;
2890
+ }
2891
+ async function showToolMenu(tool) {
2892
+ printToolMenuHeader(tool);
2893
+ const { choice } = await inquirer.prompt({
2894
+ type: "list",
2895
+ name: "choice",
2896
+ message: i18n.t("menu:selectFunction"),
2897
+ choices: buildMenuListChoices(tool),
2898
+ pageSize: 20
2899
+ });
2900
+ if (!choice) {
2901
+ console.log(ansis.yellow(i18n.t("common:cancelled")));
2902
+ return "exit";
2903
+ }
2904
+ const result = await dispatchMenuChoice(tool, choice);
2905
+ if (result === "exit")
2906
+ return "exit";
2907
+ if (result === "switch")
2908
+ return "switch";
2909
+ if (result === "continue") {
2910
+ printSeparator();
2911
+ return void 0;
2912
+ }
2345
2913
  printSeparator();
2346
2914
  const shouldContinue = await promptBoolean({
2347
2915
  message: i18n.t("common:returnToMenu"),
@@ -2375,7 +2943,7 @@ async function showMainMenu(options = {}) {
2375
2943
  while (!exitMenu) {
2376
2944
  const codeTool = getCurrentCodeTool();
2377
2945
  displayBannerWithInfo(CODE_TOOL_BANNERS[codeTool] || "CCJK");
2378
- const result = codeTool === "clavue" ? await showClavueMenu() : codeTool === "codex" ? await showCodexMenu() : codeTool === "grok" ? await showGrokMenu() : await showClaudeCodeMenu();
2946
+ const result = await showToolMenu(codeTool);
2379
2947
  if (result === "exit") {
2380
2948
  exitMenu = true;
2381
2949
  } else if (result === "switch") {
@@ -2405,6 +2973,31 @@ async function ccr(options = {}) {
2405
2973
  }
2406
2974
  }
2407
2975
 
2976
+ async function executeCcusage(args = []) {
2977
+ try {
2978
+ const command = "npx";
2979
+ const commandArgs = ["ccusage@latest", ...args || []];
2980
+ console.log(ansis.cyan(i18n.t("tools:runningCcusage")));
2981
+ console.log(ansis.gray(`$ npx ccusage@latest ${(args || []).join(" ")}`));
2982
+ console.log("");
2983
+ await x(command, commandArgs, {
2984
+ nodeOptions: {
2985
+ stdio: "inherit"
2986
+ }
2987
+ });
2988
+ } catch (error) {
2989
+ console.error(ansis.red(i18n.t("tools:ccusageFailed")));
2990
+ console.error(ansis.yellow(i18n.t("tools:checkNetworkConnection")));
2991
+ if (process$1.env.DEBUG) {
2992
+ console.error(ansis.gray(i18n.t("tools:errorDetails")), error);
2993
+ }
2994
+ if (process$1.env.NODE_ENV !== "test") {
2995
+ process$1.exit(1);
2996
+ }
2997
+ throw error;
2998
+ }
2999
+ }
3000
+
2408
3001
  async function configSwitchCommand(options) {
2409
3002
  try {
2410
3003
  ensureI18nInitialized();
@@ -2459,7 +3052,7 @@ async function listCodexProvidersWithDisplay() {
2459
3052
  console.log(ansis.cyan(i18n.t("codex:currentProvider", { provider: currentProvider })));
2460
3053
  console.log();
2461
3054
  }
2462
- const { listCodexProfileFiles, codexProfileLaunchHint } = await import('./chunks/simple-config.mjs').then(function (n) { return n.bx; });
3055
+ const { listCodexProfileFiles, codexProfileLaunchHint } = await import('./chunks/simple-config.mjs').then(function (n) { return n.bO; });
2463
3056
  const profileFiles = listCodexProfileFiles();
2464
3057
  if (profileFiles.length > 0) {
2465
3058
  console.log(ansis.bold("Codex 0.135+ profiles (.config.toml):"));
@@ -2692,6 +3285,194 @@ async function benchCommand(opts = {}) {
2692
3285
  await probeCommand({ json: opts.json });
2693
3286
  }
2694
3287
 
3288
+ async function providerCommand(options) {
3289
+ const { action, profileId, json } = options;
3290
+ const subAction = action || "list";
3291
+ if (subAction === "list") {
3292
+ await listAction(json);
3293
+ } else if (subAction === "current") {
3294
+ await currentAction(json);
3295
+ } else if (subAction === "validate") {
3296
+ await validateAction(profileId, json);
3297
+ } else {
3298
+ await validateAction(subAction, json);
3299
+ }
3300
+ }
3301
+ async function listAction(json) {
3302
+ const profiles = listProviderProfiles();
3303
+ const activeId = getActiveProviderProfileId();
3304
+ if (json) {
3305
+ console.log(JSON.stringify({ profiles, activeId }, null, 2));
3306
+ return;
3307
+ }
3308
+ if (profiles.length === 0) {
3309
+ console.log(ansis.dim("\n No provider profiles found.\n"));
3310
+ return;
3311
+ }
3312
+ console.log(ansis.bold("\nProvider Profiles (Clavue 9.x)"));
3313
+ console.log(ansis.dim("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
3314
+ for (const profile of profiles) {
3315
+ const isActive = profile.id === activeId;
3316
+ const prefix = isActive ? ansis.green("\u25B6") : " ";
3317
+ const activeLabel = isActive ? ansis.green(" (active)") : "";
3318
+ const modeLabel = profile.modelMode ? ansis.dim(` ${profile.modelMode}`) : "";
3319
+ console.log(`${prefix} ${ansis.cyan(profile.id)}${activeLabel}${modeLabel}`);
3320
+ console.log(` URL: ${ansis.dim(profile.baseUrl)}`);
3321
+ console.log(` Auth: ${ansis.dim(profile.authType)}`);
3322
+ const mr = profile.modelRouting;
3323
+ const parts = [];
3324
+ if (mr.primaryModel) parts.push(`Primary: ${mr.primaryModel}`);
3325
+ if (mr.smallFastModel) parts.push(`Haiku: ${mr.smallFastModel}`);
3326
+ if (mr.subagentModel) parts.push(`Sonnet: ${mr.subagentModel}`);
3327
+ if (mr.planModel) parts.push(`Opus: ${mr.planModel}`);
3328
+ console.log(` ${ansis.dim(parts.join(" | "))}`);
3329
+ console.log();
3330
+ }
3331
+ }
3332
+ async function currentAction(json) {
3333
+ const activeId = getActiveProviderProfileId();
3334
+ if (!activeId) {
3335
+ if (json) {
3336
+ console.log(JSON.stringify({ error: "No active profile" }));
3337
+ } else {
3338
+ console.log(ansis.yellow("\n No active provider profile.\n"));
3339
+ }
3340
+ return;
3341
+ }
3342
+ const profile = getProviderProfile(activeId);
3343
+ if (!profile) {
3344
+ if (json) {
3345
+ console.log(JSON.stringify({ error: `Active profile "${activeId}" not found` }));
3346
+ } else {
3347
+ console.log(ansis.red(`
3348
+ Active profile "${activeId}" not found.
3349
+ `));
3350
+ }
3351
+ return;
3352
+ }
3353
+ if (json) {
3354
+ console.log(JSON.stringify({ active: profile }, null, 2));
3355
+ return;
3356
+ }
3357
+ renderProfileDetail(profile);
3358
+ }
3359
+ function renderProfileDetail(profile) {
3360
+ console.log(ansis.bold(`
3361
+ Active Profile: ${ansis.cyan(profile.name)}`));
3362
+ console.log(` ID: ${ansis.dim(profile.id)}`);
3363
+ if (profile.modelMode) {
3364
+ console.log(` Mode: ${ansis.dim(profile.modelMode)}`);
3365
+ }
3366
+ console.log(` URL: ${ansis.dim(profile.baseUrl)}`);
3367
+ console.log(` Auth: ${ansis.dim(profile.authType)}`);
3368
+ console.log(" Model Routing:");
3369
+ const mr = profile.modelRouting;
3370
+ console.log(` Primary: ${ansis.dim(mr.primaryModel || "-")}`);
3371
+ console.log(` Haiku: ${ansis.dim(mr.smallFastModel || "-")}`);
3372
+ console.log(` Sonnet: ${ansis.dim(mr.subagentModel || "-")}`);
3373
+ console.log(` Opus/Plan: ${ansis.dim(mr.planModel || "-")}`);
3374
+ if (mr.subagentModel) {
3375
+ console.log(` Subagent: ${ansis.dim(mr.subagentModel)}`);
3376
+ }
3377
+ if (mr.generalModel) {
3378
+ console.log(` General: ${ansis.dim(mr.generalModel)}`);
3379
+ }
3380
+ const created = new Date(profile.createdAt).toISOString().slice(0, 10);
3381
+ const updated = new Date(profile.updatedAt).toISOString().slice(0, 10);
3382
+ console.log(` Created: ${ansis.dim(created)}`);
3383
+ console.log(` Updated: ${ansis.dim(updated)}`);
3384
+ console.log();
3385
+ }
3386
+ const PROBE_TIMEOUT_MS = 1e4;
3387
+ async function validateAction(profileId, json) {
3388
+ const targetId = profileId || getActiveProviderProfileId();
3389
+ if (!targetId) {
3390
+ if (json) {
3391
+ console.log(JSON.stringify({ error: "No profile specified and no active profile" }));
3392
+ } else {
3393
+ console.log(ansis.yellow("\n Please specify a profile ID or set an active profile.\n"));
3394
+ }
3395
+ return;
3396
+ }
3397
+ const profile = getProviderProfile(targetId);
3398
+ if (!profile) {
3399
+ if (json) {
3400
+ console.log(JSON.stringify({ error: `Profile "${targetId}" not found` }));
3401
+ } else {
3402
+ console.log(ansis.red(`
3403
+ Profile "${targetId}" not found.
3404
+ `));
3405
+ }
3406
+ return;
3407
+ }
3408
+ if (json) {
3409
+ const result = await buildValidationResultJson(profile);
3410
+ console.log(JSON.stringify(result, null, 2));
3411
+ return;
3412
+ }
3413
+ console.log(ansis.bold(`
3414
+ Validating ${ansis.cyan(targetId)}...`));
3415
+ let probeOk = false;
3416
+ let probeDisplay = "";
3417
+ try {
3418
+ const probeUrl = profile.baseUrl.replace(/\/$/, "");
3419
+ const res = await fetch(probeUrl, { signal: AbortSignal.timeout(PROBE_TIMEOUT_MS) });
3420
+ probeOk = res.ok;
3421
+ probeDisplay = res.ok ? ansis.green(`OK (${res.status})`) : ansis.red(`${res.status}`);
3422
+ } catch (e) {
3423
+ probeDisplay = ansis.red(`Unreachable: ${e.message}`);
3424
+ }
3425
+ console.log(` Probe ${ansis.dim(profile.baseUrl)}... ${probeDisplay}`);
3426
+ console.log(` Auth type: ${ansis.dim(profile.authType)}`);
3427
+ const mr = profile.modelRouting;
3428
+ console.log(` Primary model: ${renderSlot(mr.primaryModel)}`);
3429
+ console.log(` Haiku model: ${renderSlot(mr.smallFastModel)}`);
3430
+ console.log(` Sonnet model: ${renderSlot(mr.subagentModel)}`);
3431
+ console.log(` Opus model: ${renderSlot(mr.planModel)}`);
3432
+ const credentials = readCredentials();
3433
+ const hasCredential = !!credentials.providerProfiles[profile.id];
3434
+ console.log(` Credential: ${hasCredential ? ansis.green("stored \u2713") : ansis.red("missing")}`);
3435
+ const issues = [];
3436
+ if (!probeOk) issues.push("base URL unreachable");
3437
+ if (!mr.primaryModel) issues.push("primary model unset");
3438
+ if (!hasCredential) issues.push("credential missing");
3439
+ const statusLabel = issues.length === 0 ? ansis.green("Healthy") : ansis.yellow(`Issues: ${issues.join(", ")}`);
3440
+ console.log(`Status: ${statusLabel}`);
3441
+ console.log();
3442
+ }
3443
+ function renderSlot(value) {
3444
+ if (value) return ansis.green(`${value} (set)`);
3445
+ return ansis.yellow("(unset)");
3446
+ }
3447
+ async function buildValidationResultJson(profile) {
3448
+ let probe = { ok: false };
3449
+ try {
3450
+ const probeUrl = profile.baseUrl.replace(/\/$/, "");
3451
+ const res = await fetch(probeUrl, { signal: AbortSignal.timeout(PROBE_TIMEOUT_MS) });
3452
+ probe = { ok: res.ok, status: res.status };
3453
+ } catch (e) {
3454
+ probe = { ok: false, error: e.message };
3455
+ }
3456
+ const credentials = readCredentials();
3457
+ const hasCredential = !!credentials.providerProfiles[profile.id];
3458
+ const mr = profile.modelRouting;
3459
+ const probeOk = probe.ok;
3460
+ return {
3461
+ profile: profile.id,
3462
+ baseUrl: profile.baseUrl,
3463
+ probe,
3464
+ authType: profile.authType,
3465
+ modelRouting: {
3466
+ primaryModel: { value: mr.primaryModel || null, set: !!mr.primaryModel },
3467
+ haikuModel: { value: mr.smallFastModel || null, set: !!mr.smallFastModel },
3468
+ sonnetModel: { value: mr.subagentModel || null, set: !!mr.subagentModel },
3469
+ opusModel: { value: mr.planModel || null, set: !!mr.planModel }
3470
+ },
3471
+ credentialStored: hasCredential,
3472
+ healthy: probeOk && !!mr.primaryModel && hasCredential
3473
+ };
3474
+ }
3475
+
2695
3476
  async function resolveAndSwitchLanguage(lang, options, skipPrompt = false) {
2696
3477
  const ccjkConfig = await readCcjkConfigAsync();
2697
3478
  const targetLang = options?.allLang || lang || options?.lang || ccjkConfig?.preferredLang || (skipPrompt ? "en" : await selectScriptLanguage());
@@ -2768,7 +3549,7 @@ function customizeHelp(sections) {
2768
3549
  ` ${ansis.green("--workflows, -w")} <list> ${i18n.t("cli:help.optionDescriptions.workflows")} (${i18n.t("cli:help.defaults.prefix")} all workflows)`,
2769
3550
  ` ${ansis.green("--output-styles, -o")} <styles> ${i18n.t("cli:help.optionDescriptions.outputStyles")} (${i18n.t("cli:help.defaults.prefix")} none)`,
2770
3551
  ` ${ansis.green("--default-output-style, -d")} <style> ${i18n.t("cli:help.optionDescriptions.defaultOutputStyle")} (${i18n.t("cli:help.defaults.prefix")} none)`,
2771
- ` ${ansis.green("--code-type, -T")} <type> ${i18n.t("cli:help.optionDescriptions.codeToolType")} (claude-code, codex, cc=claude-code, cx=codex)`,
3552
+ ` ${ansis.green("--code-type, -T")} <type> ${i18n.t("cli:help.optionDescriptions.codeToolType")} (clavue, claude-code, codex, grok, cv, cc, cx, gk)`,
2772
3553
  ` ${ansis.green("--install-cometix-line, -x")} <value> ${i18n.t("cli:help.optionDescriptions.installStatuslineTool")} (${i18n.t("cli:help.defaults.prefix")} true)`
2773
3554
  ].join("\n")
2774
3555
  });
@@ -2826,7 +3607,7 @@ async function setupCommands(cli) {
2826
3607
  cli.command("", "Show interactive menu (default)").option("--lang, -l <lang>", "CCJK display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--config-lang, -c <lang>", "Configuration language (zh-CN, en)").option("--force, -f", "Force overwrite existing configuration").option("--code-type, -T <codeType>", "Select code tool type (clavue, claude-code, codex, grok, cv, cc, cx, gk)").action(await withLanguageResolution(async (options) => {
2827
3608
  await showMainMenu({ codeType: options.codeType });
2828
3609
  }, true));
2829
- cli.command("init", "Initialize Claude Code configuration").alias("i").option("--lang, -l <lang>", "CCJK 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, -r <action>", `Config handling (new/backup/merge/docs-only/skip), ${i18n.t("cli:help.defaults.prefix")} 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("--api-model, -M <model>", "Primary API model (e.g., claude-sonnet-4-5)").option("--api-haiku-model, -H <model>", "Default Haiku model (e.g., claude-haiku-4-5)").option("--api-sonnet-model, -S <model>", "Default Sonnet model (e.g., claude-sonnet-4-5)").option("--api-opus-model, -O <model>", "Default Opus model (e.g., claude-opus-4-5)").option("--provider, -p <provider>", "API provider preset (302ai, glm, minimax, kimi, custom)").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, ${i18n.t("cli:help.defaults.prefix")} all`).option("--workflows, -w <workflows>", `Comma-separated workflows to install (sixStepsWorkflow,featPlanUx,gitWorkflow,bmadWorkflow), "skip" to skip all, "all" for all workflows, ${i18n.t("cli:help.defaults.prefix")} all`).option("--output-styles, -o <styles>", `Comma-separated output styles (linus-mode,uncle-bob-mode,dhh-mode,carmack-mode,jobs-mode,evan-you-mode,default,explanatory,learning), "skip" to skip all, "all" for zcf curated styles, ${i18n.t("cli:help.defaults.prefix")} none`).option("--default-output-style, -d <style>", `Default output style (or "none" to keep original behavior), ${i18n.t("cli:help.defaults.prefix")} none`).option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--code-type, -T <codeType>", "Select code tool type (claude-code, codex, cc, cx)").option("--install-cometix-line, -x <value>", `Install CCometixLine statusline tool (true/false), ${i18n.t("cli:help.defaults.prefix")} true`).option("--api-configs <configs>", "API configurations as JSON string for multiple profiles").option("--api-configs-file <file>", "Path to JSON file containing API configurations").action(await withLanguageResolution(async (options) => {
3610
+ cli.command("init", "Initialize Claude Code configuration").alias("i").option("--lang, -l <lang>", "CCJK 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, -r <action>", `Config handling (new/backup/merge/docs-only/skip), ${i18n.t("cli:help.defaults.prefix")} 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("--api-model, -M <model>", "Primary API model (e.g., claude-sonnet-4-5)").option("--api-haiku-model, -H <model>", "Default Haiku model (e.g., claude-haiku-4-5)").option("--api-sonnet-model, -S <model>", "Default Sonnet model (e.g., claude-sonnet-4-5)").option("--api-opus-model, -O <model>", "Default Opus model (e.g., claude-opus-4-5)").option("--provider, -p <provider>", "API provider preset (302ai, glm, minimax, kimi, custom)").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, ${i18n.t("cli:help.defaults.prefix")} all`).option("--workflows, -w <workflows>", `Comma-separated workflows to install (sixStepsWorkflow,featPlanUx,gitWorkflow,bmadWorkflow), "skip" to skip all, "all" for all workflows, ${i18n.t("cli:help.defaults.prefix")} all`).option("--output-styles, -o <styles>", `Comma-separated output styles (agents-md-baseline,plan-first,verify-and-ship,surgical-diff,engineer-professional,default,explanatory,learning), "skip" to skip all, "all" for practical engineering styles, ${i18n.t("cli:help.defaults.prefix")} none`).option("--default-output-style, -d <style>", `Default output style (or "none" to keep original behavior), ${i18n.t("cli:help.defaults.prefix")} none`).option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--code-type, -T <codeType>", "Select code tool type (clavue, claude-code, codex, grok, cv, cc, cx, gk)").option("--install-cometix-line, -x <value>", `Install CCometixLine statusline tool (true/false), ${i18n.t("cli:help.defaults.prefix")} true`).option("--api-configs <configs>", "API configurations as JSON string for multiple profiles").option("--api-configs-file <file>", "Path to JSON file containing API configurations").action(await withLanguageResolution(async (options) => {
2830
3611
  await init(options);
2831
3612
  }));
2832
3613
  cli.command("update", "Update Claude Code prompts only").alias("u").option("--lang, -l <lang>", "CCJK display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--config-lang, -c <lang>", "Configuration language (zh-CN, en)").action(await withLanguageResolution(async (options) => {
@@ -2838,14 +3619,22 @@ async function setupCommands(cli) {
2838
3619
  cli.command("ccu [...args]", "Run Claude Code usage analysis tool").option("--lang, -l <lang>", "CCJK display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").allowUnknownOptions().action(await withLanguageResolution(async (args) => {
2839
3620
  await executeCcusage(args);
2840
3621
  }));
2841
- cli.command("config-switch [target]", "Switch Codex provider or Claude Code configuration, or list available configurations").alias("cs").option("--code-type, -T <type>", "Code tool type (claude-code, codex, cc, cx)").option("--lang <lang>", "CCJK display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--list, -l", "List available configurations").action(await withLanguageResolution(async (target, options) => {
3622
+ cli.command("config-switch [target]", "Switch Codex provider or Claude Code configuration, or list available configurations").alias("cs").option("--code-type, -T <type>", "Code tool type (clavue, claude-code, codex, grok, cv, cc, cx, gk)").option("--lang <lang>", "CCJK display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--list, -l", "List available configurations").action(await withLanguageResolution(async (target, options) => {
2842
3623
  await configSwitchCommand({
2843
3624
  target,
2844
3625
  codeType: options.codeType,
2845
3626
  list: options.list
2846
3627
  });
2847
3628
  }));
2848
- cli.command("uninstall", "Remove CCJK configurations and tools").option("--lang, -l <lang>", "CCJK display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--code-type, -T <codeType>", "Select code tool type (claude-code, codex, cc, cx)").option("--mode, -m <mode>", "Uninstall mode (complete/custom/interactive), default: interactive").option("--items, -i <items>", "Comma-separated items for custom uninstall mode").action(await withLanguageResolution(async (options) => {
3629
+ cli.command("clean", "Clean dirty MCP servers, skills, and redundant prompts").option("--code-type, -T <codeType>", "Code tool context (clavue, claude-code, codex, grok)").option("-s, --skip-prompt", "Non-interactive: clean only high-confidence items").option("--aggressive", "Select all detected issues in non-interactive mode").option("--purge-all", "Remove ALL MCP, skills, prompts, and ~/.codex/AGENTS.md").action(await withLanguageResolution(async (options) => {
3630
+ await cleanCommand({
3631
+ codeType: options.codeType,
3632
+ skipPrompt: options.skipPrompt,
3633
+ aggressive: options.aggressive,
3634
+ purgeAll: options.purgeAll
3635
+ });
3636
+ }));
3637
+ cli.command("uninstall", "Remove CCJK configurations and tools").option("--lang, -l <lang>", "CCJK display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--code-type, -T <codeType>", "Select code tool type (clavue, claude-code, codex, grok, cv, cc, cx, gk)").option("--mode, -m <mode>", "Uninstall mode (complete/custom/interactive), default: interactive").option("--items, -i <items>", "Comma-separated items for custom uninstall mode").action(await withLanguageResolution(async (options) => {
2849
3638
  await uninstall(options);
2850
3639
  }));
2851
3640
  cli.command("grok [profile]", "Grok CLI status and launch with optional profile").action(await withLanguageResolution(async (profile) => {
@@ -2860,11 +3649,14 @@ async function setupCommands(cli) {
2860
3649
  }));
2861
3650
  cli.command("probe", "HTTP probe current API configuration").option("--json", "JSON output").action(await withLanguageResolution(async (options) => {
2862
3651
  await probeCommand({ json: options.json });
2863
- }));
3652
+ }, true));
2864
3653
  cli.command("bench", "Lightweight latency benchmark (probe)").option("--json", "JSON output").action(await withLanguageResolution(async (options) => {
2865
3654
  await benchCommand({ json: options.json });
3655
+ }, true));
3656
+ cli.command("provider [action] [profileId]", "Manage Clavue provider profiles").option("--json", "JSON output").action(await withLanguageResolution(async (action, profileId, options) => {
3657
+ await providerCommand({ action, profileId, json: options.json });
2866
3658
  }));
2867
- cli.command("check-updates", "Check and update Claude Code and CCR to latest versions").alias("check").option("--lang, -l <lang>", "CCJK display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--code-type, -T <codeType>", "Select code tool type (claude-code, codex, cc, cx)").option("--skip-prompt, -s", "Skip all interactive prompts (non-interactive mode)").action(await withLanguageResolution(async (options) => {
3659
+ cli.command("check-updates", "Check and update Claude Code and CCR to latest versions").alias("check").option("--lang, -l <lang>", "CCJK display language (zh-CN, en)").option("--all-lang, -g <lang>", "Set all language parameters to this value").option("--code-type, -T <codeType>", "Select code tool type (clavue, claude-code, codex, grok, cv, cc, cx, gk)").option("--skip-prompt, -s", "Skip all interactive prompts (non-interactive mode)").action(await withLanguageResolution(async (options) => {
2868
3660
  await checkUpdates(options);
2869
3661
  }));
2870
3662
  cli.help((sections) => customizeHelp(sections));