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.
- package/README.md +72 -316
- package/dist/chunks/claude-code-config-manager.mjs +28 -7
- package/dist/chunks/claude-code-incremental-manager.mjs +2 -2
- package/dist/chunks/codex-config-switch.mjs +3 -3
- package/dist/chunks/codex-presets.mjs +98 -0
- package/dist/chunks/codex-provider-manager.mjs +4 -4
- package/dist/chunks/codex-runtime.mjs +246 -0
- package/dist/chunks/codex-uninstaller.mjs +2 -2
- package/dist/chunks/commands.mjs +1 -1
- package/dist/chunks/features.mjs +35 -15
- package/dist/chunks/simple-config.mjs +659 -148
- package/dist/cli.mjs +1700 -908
- package/dist/i18n/locales/en/clean.json +24 -0
- package/dist/i18n/locales/en/codex.json +24 -1
- package/dist/i18n/locales/en/configuration.json +27 -12
- package/dist/i18n/locales/en/hub.json +30 -0
- package/dist/i18n/locales/en/menu.json +32 -8
- package/dist/i18n/locales/en/workflow.json +13 -1
- package/dist/i18n/locales/zh-CN/clean.json +24 -0
- package/dist/i18n/locales/zh-CN/codex.json +24 -1
- package/dist/i18n/locales/zh-CN/configuration.json +27 -12
- package/dist/i18n/locales/zh-CN/hub.json +30 -0
- package/dist/i18n/locales/zh-CN/menu.json +32 -8
- package/dist/i18n/locales/zh-CN/workflow.json +13 -1
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.mjs +1 -1
- package/dist/shared/{ccjk.BSLlI-JL.mjs → ccjk.TC1_-qhV.mjs} +1 -1
- package/package.json +1 -1
- package/templates/common/output-styles/en/agents-md-baseline.md +28 -0
- package/templates/common/output-styles/en/plan-first.md +30 -0
- package/templates/common/output-styles/en/surgical-diff.md +27 -0
- package/templates/common/output-styles/en/verify-and-ship.md +31 -0
- package/templates/common/output-styles/zh-CN/agents-md-baseline.md +28 -0
- package/templates/common/output-styles/zh-CN/plan-first.md +30 -0
- package/templates/common/output-styles/zh-CN/surgical-diff.md +27 -0
- package/templates/common/output-styles/zh-CN/verify-and-ship.md +31 -0
- package/templates/common/workflow/bmad/en/bmad-init.md +275 -0
- package/templates/common/workflow/bmad/zh-CN/bmad-init.md +275 -0
- package/templates/common/workflow/codeReview/en/code-review.md +34 -0
- package/templates/common/workflow/codeReview/zh-CN/code-review.md +34 -0
- package/templates/common/workflow/continuousDelivery/en/continuous-delivery.md +628 -0
- package/templates/common/workflow/continuousDelivery/zh-CN/continuous-delivery.md +628 -0
- package/templates/common/workflow/essential/en/agents/ccjk-config-agent.md +187 -0
- package/templates/common/workflow/essential/en/agents/ccjk-mcp-agent.md +191 -0
- package/templates/common/workflow/essential/en/agents/ccjk-skill-agent.md +249 -0
- package/templates/common/workflow/essential/en/agents/ccjk-workflow-agent.md +277 -0
- package/templates/common/workflow/essential/en/agents/get-current-datetime.md +29 -0
- package/templates/common/workflow/essential/en/agents/init-architect.md +115 -0
- package/templates/common/workflow/essential/en/agents/planner.md +116 -0
- package/templates/common/workflow/essential/en/agents/teamagent.md +102 -0
- package/templates/common/workflow/essential/en/agents/ui-ux-designer.md +91 -0
- package/templates/common/workflow/essential/en/feat.md +92 -0
- package/templates/common/workflow/essential/en/init-project.md +53 -0
- package/templates/common/workflow/essential/zh-CN/agents/get-current-datetime.md +29 -0
- package/templates/common/workflow/essential/zh-CN/agents/init-architect.md +115 -0
- package/templates/common/workflow/essential/zh-CN/agents/planner.md +116 -0
- package/templates/common/workflow/essential/zh-CN/agents/teamagent.md +102 -0
- package/templates/common/workflow/essential/zh-CN/agents/ui-ux-designer.md +91 -0
- package/templates/common/workflow/essential/zh-CN/feat.md +315 -0
- package/templates/common/workflow/essential/zh-CN/init-project.md +53 -0
- package/templates/common/workflow/interview/en/interview.md +67 -0
- package/templates/common/workflow/interview/zh-CN/interview.md +67 -0
- package/templates/common/workflow/linearMethod/en/linear-method.md +651 -0
- package/templates/common/workflow/linearMethod/zh-CN/linear-method.md +750 -0
- package/templates/common/workflow/refactoringMaster/en/refactoring-master.md +516 -0
- package/templates/common/workflow/refactoringMaster/zh-CN/refactoring-master.md +810 -0
- package/templates/common/workflow/specFirstTDD/en/spec-first-tdd.md +364 -0
- 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 {
|
|
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 {
|
|
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.
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
|
|
170
|
-
|
|
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
|
-
|
|
177
|
-
|
|
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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
648
|
+
console.log("");
|
|
190
649
|
}
|
|
650
|
+
return true;
|
|
191
651
|
}
|
|
192
|
-
|
|
652
|
+
function scanEnvironmentIssues(purgeAll = false) {
|
|
193
653
|
ensureI18nInitialized();
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
${
|
|
227
|
-
console.log(
|
|
228
|
-
console.log(
|
|
229
|
-
`);
|
|
230
|
-
|
|
231
|
-
console.log(
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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 (
|
|
245
|
-
case "
|
|
246
|
-
|
|
913
|
+
switch (action) {
|
|
914
|
+
case "scan":
|
|
915
|
+
printEnvironmentScanReport();
|
|
247
916
|
break;
|
|
248
|
-
case "
|
|
249
|
-
await
|
|
917
|
+
case "probe":
|
|
918
|
+
await probeCommand();
|
|
250
919
|
break;
|
|
251
|
-
case "
|
|
252
|
-
await
|
|
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
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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
|
|
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
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
name:
|
|
295
|
-
|
|
296
|
-
|
|
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 (
|
|
1341
|
+
if (!confirmed) {
|
|
1342
|
+
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
299
1343
|
return;
|
|
300
1344
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
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
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
await inquirer.prompt({
|
|
336
|
-
type: "
|
|
337
|
-
name: "
|
|
338
|
-
message:
|
|
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
|
|
342
|
-
await
|
|
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
|
|
345
|
-
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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.
|
|
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(
|
|
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 =
|
|
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\
|
|
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 (!
|
|
2736
|
+
if (!tool) {
|
|
2066
2737
|
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
2067
|
-
return
|
|
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
|
-
|
|
2070
|
-
|
|
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
|
-
|
|
2754
|
+
await init({ skipBanner: true, codeType: tool });
|
|
2755
|
+
return "handled";
|
|
2074
2756
|
case "2":
|
|
2075
|
-
await update({ skipBanner: true });
|
|
2076
|
-
|
|
2757
|
+
await update({ skipBanner: true, codeType: tool });
|
|
2758
|
+
return "handled";
|
|
2077
2759
|
case "3":
|
|
2078
2760
|
await configureApiFeature();
|
|
2079
|
-
|
|
2761
|
+
return "handled";
|
|
2080
2762
|
case "4":
|
|
2081
2763
|
await configureMcpFeature();
|
|
2082
|
-
|
|
2764
|
+
return "handled";
|
|
2083
2765
|
case "5":
|
|
2084
2766
|
await configureDefaultModelFeature();
|
|
2085
|
-
|
|
2767
|
+
return "handled";
|
|
2086
2768
|
case "6":
|
|
2087
2769
|
await configureAiMemoryFeature();
|
|
2088
|
-
|
|
2770
|
+
return "handled";
|
|
2089
2771
|
case "7":
|
|
2090
2772
|
await configureEnvPermissionFeature();
|
|
2091
|
-
|
|
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
|
|
2156
|
-
|
|
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
|
-
|
|
2782
|
+
return "handled";
|
|
2201
2783
|
case "2":
|
|
2202
2784
|
await runCodexWorkflowImportWithLanguageSelection();
|
|
2203
|
-
|
|
2785
|
+
return "handled";
|
|
2204
2786
|
case "3":
|
|
2205
2787
|
await configureCodexApi();
|
|
2206
|
-
|
|
2788
|
+
return "handled";
|
|
2207
2789
|
case "4":
|
|
2208
2790
|
await manageCodexMcp();
|
|
2209
|
-
|
|
2791
|
+
return "handled";
|
|
2210
2792
|
case "5":
|
|
2211
2793
|
await configureCodexDefaultModelFeature();
|
|
2212
|
-
|
|
2794
|
+
return "handled";
|
|
2213
2795
|
case "6":
|
|
2214
2796
|
await configureCodexAiMemoryFeature();
|
|
2215
|
-
|
|
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
|
|
2256
|
-
|
|
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
|
-
|
|
2806
|
+
return "handled";
|
|
2290
2807
|
case "2":
|
|
2291
2808
|
await grokCommand();
|
|
2292
|
-
|
|
2293
|
-
|
|
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
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
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
|
-
|
|
2312
|
-
return void 0;
|
|
2830
|
+
return "continue";
|
|
2313
2831
|
case "x":
|
|
2314
2832
|
await reasonixCommand();
|
|
2315
|
-
|
|
2316
|
-
return void 0;
|
|
2833
|
+
return "continue";
|
|
2317
2834
|
case "0": {
|
|
2318
2835
|
const currentLang = i18n.language;
|
|
2319
2836
|
await changeScriptLanguageFeature(currentLang);
|
|
2320
|
-
|
|
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(
|
|
2333
|
-
|
|
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 =
|
|
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.
|
|
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
|
|
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 (
|
|
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("
|
|
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));
|