ccjk 16.0.7 → 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 +12 -12
- package/dist/chunks/simple-config.mjs +485 -130
- package/dist/cli.mjs +1730 -760
- 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 +20 -12
- package/dist/i18n/locales/en/hub.json +30 -0
- package/dist/i18n/locales/en/menu.json +30 -0
- 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 +20 -12
- package/dist/i18n/locales/zh-CN/hub.json +30 -0
- package/dist/i18n/locales/zh-CN/menu.json +30 -0
- 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,20 +1,21 @@
|
|
|
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 { pathExists } from 'fs-extra';
|
|
13
|
-
import { exec, x } from 'tinyexec';
|
|
10
|
+
import { detectCodexRuntimes, scanCodexConfigDoctorFindings, printCodexReloadHint } from './chunks/codex-runtime.mjs';
|
|
14
11
|
import { m as moveToTrash } from './shared/ccjk.DGjQxTq_.mjs';
|
|
15
|
-
import { g as getClaudeFamilyRuntimeLabel } from './shared/ccjk.
|
|
12
|
+
import { g as getClaudeFamilyRuntimeLabel } from './shared/ccjk.TC1_-qhV.mjs';
|
|
16
13
|
import { execSync, spawnSync } from 'node:child_process';
|
|
17
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';
|
|
18
19
|
import 'node:util';
|
|
19
20
|
import 'dayjs';
|
|
20
21
|
import 'node:url';
|
|
@@ -148,6 +149,1334 @@ ${ansis.dim("\u2500".repeat(50))}
|
|
|
148
149
|
}
|
|
149
150
|
}
|
|
150
151
|
|
|
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
|
+
});
|
|
338
|
+
}
|
|
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
|
+
});
|
|
386
|
+
}
|
|
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;
|
|
456
|
+
}
|
|
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() {
|
|
552
|
+
ensureI18nInitialized();
|
|
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
|
+
);
|
|
647
|
+
}
|
|
648
|
+
console.log("");
|
|
649
|
+
}
|
|
650
|
+
return true;
|
|
651
|
+
}
|
|
652
|
+
function scanEnvironmentIssues(purgeAll = false) {
|
|
653
|
+
ensureI18nInitialized();
|
|
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);
|
|
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
|
+
})))
|
|
755
|
+
});
|
|
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
|
|
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
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
|
|
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;
|
|
820
|
+
console.log(`
|
|
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")
|
|
905
|
+
}
|
|
906
|
+
]);
|
|
907
|
+
const { action } = await inquirer.prompt({
|
|
908
|
+
type: "list",
|
|
909
|
+
name: "action",
|
|
910
|
+
message: i18n.t("menu:selectFunction"),
|
|
911
|
+
choices
|
|
912
|
+
});
|
|
913
|
+
switch (action) {
|
|
914
|
+
case "scan":
|
|
915
|
+
printEnvironmentScanReport();
|
|
916
|
+
break;
|
|
917
|
+
case "probe":
|
|
918
|
+
await probeCommand();
|
|
919
|
+
break;
|
|
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;
|
|
928
|
+
break;
|
|
929
|
+
}
|
|
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
|
+
});
|
|
967
|
+
}
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
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
|
+
});
|
|
995
|
+
} catch (error) {
|
|
996
|
+
if (!handleExitPromptError(error)) {
|
|
997
|
+
handleGeneralError(error);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
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
|
|
1340
|
+
});
|
|
1341
|
+
if (!confirmed) {
|
|
1342
|
+
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
1343
|
+
return;
|
|
1344
|
+
}
|
|
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;
|
|
1404
|
+
}
|
|
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
|
+
])
|
|
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
|
+
}
|
|
1439
|
+
}
|
|
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
|
+
}
|
|
1465
|
+
}
|
|
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);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
151
1480
|
class ToolUpdateScheduler {
|
|
152
1481
|
/**
|
|
153
1482
|
* Update tools based on code type
|
|
@@ -491,7 +1820,7 @@ class CcjkUninstaller {
|
|
|
491
1820
|
result.removed.push(".claude.json (includes MCP configuration)");
|
|
492
1821
|
}
|
|
493
1822
|
try {
|
|
494
|
-
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; });
|
|
495
1824
|
const success = await uninstallCodeTool("claude-code");
|
|
496
1825
|
if (success) {
|
|
497
1826
|
result.removed.push("@anthropic-ai/claude-code");
|
|
@@ -727,7 +2056,7 @@ async function uninstall(options = {}) {
|
|
|
727
2056
|
}
|
|
728
2057
|
const uninstaller = new CcjkUninstaller(options.lang || "en");
|
|
729
2058
|
if (codeType === "codex") {
|
|
730
|
-
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; });
|
|
731
2060
|
await runCodexUninstall();
|
|
732
2061
|
return;
|
|
733
2062
|
}
|
|
@@ -901,256 +2230,63 @@ function displayUninstallResult(mode, results) {
|
|
|
901
2230
|
result.removed.forEach((item) => {
|
|
902
2231
|
console.log(ansis.gray(` \u2022 ${item}`));
|
|
903
2232
|
});
|
|
904
|
-
}
|
|
905
|
-
if (result.removedConfigs && result.removedConfigs.length > 0) {
|
|
906
|
-
console.log(ansis.green(`\u2714 ${i18n.t("uninstall:removedConfigs")}:`));
|
|
907
|
-
result.removedConfigs.forEach((item) => {
|
|
908
|
-
console.log(ansis.gray(` \u2022 ${item}`));
|
|
909
|
-
});
|
|
910
|
-
}
|
|
911
|
-
if (result.errors && result.errors.length > 0) {
|
|
912
|
-
totalErrors += result.errors.length;
|
|
913
|
-
console.log(ansis.red(`\u2716 ${i18n.t("uninstall:errors")}:`));
|
|
914
|
-
result.errors.forEach((error) => {
|
|
915
|
-
console.log(ansis.red(` \u2022 ${error}`));
|
|
916
|
-
});
|
|
917
|
-
}
|
|
918
|
-
if (result.warnings && result.warnings.length > 0) {
|
|
919
|
-
totalWarnings += result.warnings.length;
|
|
920
|
-
console.log(ansis.yellow(`\u26A0 ${i18n.t("uninstall:warnings")}:`));
|
|
921
|
-
result.warnings.forEach((warning) => {
|
|
922
|
-
console.log(ansis.yellow(` \u2022 ${warning}`));
|
|
923
|
-
});
|
|
924
|
-
}
|
|
925
|
-
});
|
|
926
|
-
const totalRemovedFiles = results.reduce((count, result) => count + (result.removed?.length || 0), 0);
|
|
927
|
-
const totalRemovedConfigs = results.reduce((count, result) => count + (result.removedConfigs?.length || 0), 0);
|
|
928
|
-
console.log("");
|
|
929
|
-
console.log(ansis.cyan("\u2500".repeat(50)));
|
|
930
|
-
if (mode === "complete") {
|
|
931
|
-
if (totalErrors === 0) {
|
|
932
|
-
console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:completeSuccess")}`));
|
|
933
|
-
} else {
|
|
934
|
-
console.log(ansis.yellow.bold(`\u26A0 ${i18n.t("uninstall:completePartialSuccess")}`));
|
|
935
|
-
}
|
|
936
|
-
} else {
|
|
937
|
-
if (totalRemovedFiles > 0 && totalRemovedConfigs > 0) {
|
|
938
|
-
console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccessBoth", {
|
|
939
|
-
fileCount: totalRemovedFiles,
|
|
940
|
-
configCount: totalRemovedConfigs
|
|
941
|
-
})}`));
|
|
942
|
-
} else if (totalRemovedFiles > 0) {
|
|
943
|
-
console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccessFiles", {
|
|
944
|
-
count: totalRemovedFiles
|
|
945
|
-
})}`));
|
|
946
|
-
} else if (totalRemovedConfigs > 0) {
|
|
947
|
-
console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccessConfigs", {
|
|
948
|
-
count: totalRemovedConfigs
|
|
949
|
-
})}`));
|
|
950
|
-
} else {
|
|
951
|
-
console.log(ansis.green.bold(`\u2714 ${i18n.t("uninstall:customSuccess", { count: totalSuccess })}`));
|
|
952
|
-
}
|
|
953
|
-
if (totalErrors > 0) {
|
|
954
|
-
console.log(ansis.red(`\u2716 ${i18n.t("uninstall:errorsCount", { count: totalErrors })}`));
|
|
955
|
-
}
|
|
956
|
-
if (totalWarnings > 0) {
|
|
957
|
-
console.log(ansis.yellow(`\u26A0 ${i18n.t("uninstall:warningsCount", { count: totalWarnings })}`));
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
console.log("");
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
function resolveCodeToolType(optionValue, savedValue) {
|
|
964
|
-
if (optionValue !== void 0) {
|
|
965
|
-
const resolved = resolveCodeToolType$1(optionValue);
|
|
966
|
-
if (resolved !== DEFAULT_CODE_TOOL_TYPE || optionValue === DEFAULT_CODE_TOOL_TYPE) {
|
|
967
|
-
return resolved;
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
if (savedValue && isCodeToolType(savedValue)) {
|
|
971
|
-
return savedValue;
|
|
972
|
-
}
|
|
973
|
-
return DEFAULT_CODE_TOOL_TYPE;
|
|
974
|
-
}
|
|
975
|
-
async function update(options = {}) {
|
|
976
|
-
try {
|
|
977
|
-
if (!options.skipBanner) {
|
|
978
|
-
displayBanner(i18n.t("cli:banner.updateSubtitle"));
|
|
979
|
-
}
|
|
980
|
-
const ccjkConfig = readCcjkConfig();
|
|
981
|
-
const codeToolType = resolveCodeToolType(options.codeType, ccjkConfig?.codeToolType);
|
|
982
|
-
options.codeType = codeToolType;
|
|
983
|
-
if (codeToolType === "codex") {
|
|
984
|
-
await runCodexUpdate();
|
|
985
|
-
const newPreferredLang = options.configLang || ccjkConfig?.preferredLang;
|
|
986
|
-
if (newPreferredLang) {
|
|
987
|
-
updateCcjkConfig({
|
|
988
|
-
version,
|
|
989
|
-
preferredLang: newPreferredLang,
|
|
990
|
-
codeToolType
|
|
991
|
-
});
|
|
992
|
-
} else {
|
|
993
|
-
updateCcjkConfig({
|
|
994
|
-
version,
|
|
995
|
-
codeToolType
|
|
996
|
-
});
|
|
997
|
-
}
|
|
998
|
-
return;
|
|
999
|
-
}
|
|
1000
|
-
const { resolveTemplateLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.bv; });
|
|
1001
|
-
const configLang = await resolveTemplateLanguage(
|
|
1002
|
-
options.configLang,
|
|
1003
|
-
// Command line option
|
|
1004
|
-
ccjkConfig,
|
|
1005
|
-
options.skipPrompt
|
|
1006
|
-
// Non-interactive mode flag
|
|
1007
|
-
);
|
|
1008
|
-
const aiOutputLang = await resolveAiOutputLanguage(i18n.language, options.aiOutputLang, ccjkConfig, options.skipPrompt);
|
|
1009
|
-
const runtimeLabel = isClaudeFamilyCodeTool(codeToolType) ? getClaudeFamilyRuntimeLabel(codeToolType) : "Claude Code";
|
|
1010
|
-
console.log(ansis.cyan(`
|
|
1011
|
-
${i18n.t("configuration:updatingPrompts", { runtime: runtimeLabel })}
|
|
1012
|
-
`));
|
|
1013
|
-
await updatePromptOnly(aiOutputLang);
|
|
1014
|
-
await selectAndInstallWorkflows(configLang, void 0, { codeToolType: isClaudeFamilyCodeTool(codeToolType) ? codeToolType : "claude-code" });
|
|
1015
|
-
if (codeToolType === "claude-code") {
|
|
1016
|
-
await checkClaudeCodeVersionAndPrompt(false);
|
|
1017
|
-
}
|
|
1018
|
-
updateCcjkConfig({
|
|
1019
|
-
version,
|
|
1020
|
-
templateLang: configLang,
|
|
1021
|
-
// 保存模板语言选择
|
|
1022
|
-
aiOutputLang,
|
|
1023
|
-
codeToolType
|
|
1024
|
-
});
|
|
1025
|
-
} catch (error) {
|
|
1026
|
-
if (!handleExitPromptError(error)) {
|
|
1027
|
-
handleGeneralError(error);
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
const LEGACY_PROFILES_DIR = join(homedir(), ".ccjk", "profiles");
|
|
1033
|
-
function fromClaudeProfile(profile) {
|
|
1034
|
-
return {
|
|
1035
|
-
name: profile.name,
|
|
1036
|
-
baseUrl: profile.baseUrl,
|
|
1037
|
-
apiKey: profile.apiKey,
|
|
1038
|
-
model: profile.primaryModel
|
|
1039
|
-
};
|
|
1040
|
-
}
|
|
1041
|
-
function readLegacyJsonProfile(name) {
|
|
1042
|
-
const profilePath = join(LEGACY_PROFILES_DIR, `${name}.json`);
|
|
1043
|
-
if (!existsSync(profilePath)) {
|
|
1044
|
-
return null;
|
|
1045
|
-
}
|
|
1046
|
-
try {
|
|
1047
|
-
const data = JSON.parse(readFileSync(profilePath, "utf-8"));
|
|
1048
|
-
return data.name ? data : { ...data, name };
|
|
1049
|
-
} catch {
|
|
1050
|
-
return null;
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
function readCcjkProfileByName(name) {
|
|
1054
|
-
const byName = ClaudeCodeConfigManager.getProfileByName(name);
|
|
1055
|
-
if (byName) {
|
|
1056
|
-
return fromClaudeProfile(byName);
|
|
1057
|
-
}
|
|
1058
|
-
const byId = ClaudeCodeConfigManager.getProfileById(name);
|
|
1059
|
-
if (byId) {
|
|
1060
|
-
return fromClaudeProfile(byId);
|
|
1061
|
-
}
|
|
1062
|
-
return readLegacyJsonProfile(name);
|
|
1063
|
-
}
|
|
1064
|
-
function listCcjkProfileNames() {
|
|
1065
|
-
return ClaudeCodeConfigManager.listProfiles().map((profile) => profile.name);
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
|
-
const GROK_AUTH_FILE = join(homedir(), ".grok", "auth.json");
|
|
1069
|
-
function isGrokInstalled() {
|
|
1070
|
-
try {
|
|
1071
|
-
execSync("command -v grok", { stdio: "ignore" });
|
|
1072
|
-
return true;
|
|
1073
|
-
} catch {
|
|
1074
|
-
return false;
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
function isGrokLoggedIn() {
|
|
1078
|
-
if (!existsSync(GROK_AUTH_FILE)) return false;
|
|
1079
|
-
try {
|
|
1080
|
-
const data = JSON.parse(readFileSync(GROK_AUTH_FILE, "utf-8"));
|
|
1081
|
-
return Object.keys(data).some((k) => k.includes("auth.x.ai"));
|
|
1082
|
-
} catch {
|
|
1083
|
-
return false;
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
function getGrokQuickStatus() {
|
|
1087
|
-
if (!isGrokInstalled()) {
|
|
1088
|
-
return {
|
|
1089
|
-
installed: false,
|
|
1090
|
-
loggedIn: false,
|
|
1091
|
-
hint: "\u672A\u5B89\u88C5\uFF1Acurl -fsSL https://x.ai/cli/install.sh | bash"
|
|
1092
|
-
};
|
|
1093
|
-
}
|
|
1094
|
-
const loggedIn = isGrokLoggedIn();
|
|
1095
|
-
return {
|
|
1096
|
-
installed: true,
|
|
1097
|
-
loggedIn,
|
|
1098
|
-
hint: loggedIn ? "\u5DF2\u767B\u5F55\uFF08OAuth\uFF0C~/.grok/auth.json\uFF09" : "\u672A\u767B\u5F55\uFF0C\u8FD0\u884C `grok login`"
|
|
1099
|
-
};
|
|
1100
|
-
}
|
|
1101
|
-
function buildGrokHints() {
|
|
1102
|
-
const s = getGrokQuickStatus();
|
|
1103
|
-
const lines = [];
|
|
1104
|
-
if (!s.installed) {
|
|
1105
|
-
lines.push(ansis.dim(" \u5B89\u88C5: ") + ansis.cyan("curl -fsSL https://x.ai/cli/install.sh | bash"));
|
|
1106
|
-
return lines;
|
|
1107
|
-
}
|
|
1108
|
-
if (!s.loggedIn) {
|
|
1109
|
-
lines.push(ansis.yellow(" \u767B\u5F55: ") + ansis.cyan("grok login"));
|
|
1110
|
-
}
|
|
1111
|
-
lines.push(ansis.dim(" \u542F\u52A8: ") + ansis.cyan("grok"));
|
|
1112
|
-
lines.push(ansis.dim(" \u6A21\u578B: ") + ansis.cyan("grok models"));
|
|
1113
|
-
return lines;
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
async function grokCommand(profileName) {
|
|
1117
|
-
if (profileName) {
|
|
1118
|
-
await launchWithProfile$1(profileName);
|
|
1119
|
-
return;
|
|
1120
|
-
}
|
|
1121
|
-
const status = getGrokQuickStatus();
|
|
1122
|
-
console.log(ansis.bold("\nGrok CLI"));
|
|
1123
|
-
console.log(` \u5B89\u88C5: ${status.installed ? ansis.green("\u662F") : ansis.gray("\u5426")} \u767B\u5F55: ${status.loggedIn ? ansis.green("\u662F") : ansis.yellow("\u5426")}`);
|
|
1124
|
-
for (const line of buildGrokHints()) console.log(line);
|
|
1125
|
-
const names = listCcjkProfileNames();
|
|
1126
|
-
if (names.length > 0) {
|
|
1127
|
-
console.log(ansis.dim(`
|
|
1128
|
-
\u53EF\u7528 profile: ${names.join(", ")}`));
|
|
1129
|
-
}
|
|
1130
|
-
console.log(ansis.dim(" ccjk grok <profile> \u2014 \u7528 ~/.ccjk/config.toml \u4E2D\u7684 profile \u542F\u52A8\n"));
|
|
1131
|
-
}
|
|
1132
|
-
async function launchWithProfile$1(name) {
|
|
1133
|
-
const profile = readCcjkProfileByName(name);
|
|
1134
|
-
if (!profile) {
|
|
1135
|
-
console.log(ansis.red(`Profile "${name}" \u4E0D\u5B58\u5728`));
|
|
1136
|
-
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"));
|
|
1137
|
-
return;
|
|
1138
|
-
}
|
|
1139
|
-
const env = { ...process.env };
|
|
1140
|
-
if (profile.baseUrl) {
|
|
1141
|
-
env.OPENAI_BASE_URL = profile.baseUrl;
|
|
1142
|
-
env.ANTHROPIC_BASE_URL = profile.baseUrl;
|
|
1143
|
-
}
|
|
1144
|
-
if (profile.apiKey) {
|
|
1145
|
-
env.OPENAI_API_KEY = profile.apiKey;
|
|
1146
|
-
env.ANTHROPIC_API_KEY = profile.apiKey;
|
|
1147
|
-
env.ANTHROPIC_AUTH_TOKEN = profile.apiKey;
|
|
2233
|
+
}
|
|
2234
|
+
if (result.removedConfigs && result.removedConfigs.length > 0) {
|
|
2235
|
+
console.log(ansis.green(`\u2714 ${i18n.t("uninstall:removedConfigs")}:`));
|
|
2236
|
+
result.removedConfigs.forEach((item) => {
|
|
2237
|
+
console.log(ansis.gray(` \u2022 ${item}`));
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
if (result.errors && result.errors.length > 0) {
|
|
2241
|
+
totalErrors += result.errors.length;
|
|
2242
|
+
console.log(ansis.red(`\u2716 ${i18n.t("uninstall:errors")}:`));
|
|
2243
|
+
result.errors.forEach((error) => {
|
|
2244
|
+
console.log(ansis.red(` \u2022 ${error}`));
|
|
2245
|
+
});
|
|
2246
|
+
}
|
|
2247
|
+
if (result.warnings && result.warnings.length > 0) {
|
|
2248
|
+
totalWarnings += result.warnings.length;
|
|
2249
|
+
console.log(ansis.yellow(`\u26A0 ${i18n.t("uninstall:warnings")}:`));
|
|
2250
|
+
result.warnings.forEach((warning) => {
|
|
2251
|
+
console.log(ansis.yellow(` \u2022 ${warning}`));
|
|
2252
|
+
});
|
|
2253
|
+
}
|
|
2254
|
+
});
|
|
2255
|
+
const totalRemovedFiles = results.reduce((count, result) => count + (result.removed?.length || 0), 0);
|
|
2256
|
+
const totalRemovedConfigs = results.reduce((count, result) => count + (result.removedConfigs?.length || 0), 0);
|
|
2257
|
+
console.log("");
|
|
2258
|
+
console.log(ansis.cyan("\u2500".repeat(50)));
|
|
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
|
+
}
|
|
1148
2288
|
}
|
|
1149
|
-
console.log(
|
|
1150
|
-
\u4F7F\u7528 profile "${name}" \u542F\u52A8 grok...
|
|
1151
|
-
`));
|
|
1152
|
-
const res = spawnSync("grok", [], { stdio: "inherit", env });
|
|
1153
|
-
if (res.error) console.log(ansis.red(`\u542F\u52A8\u5931\u8D25: ${res.error.message}`));
|
|
2289
|
+
console.log("");
|
|
1154
2290
|
}
|
|
1155
2291
|
|
|
1156
2292
|
const REASONIX_GLOBAL_CONFIG = join(homedir(), ".config", "reasonix", "config.toml");
|
|
@@ -1400,71 +2536,6 @@ function buildRunArgs(model, prompt) {
|
|
|
1400
2536
|
return args;
|
|
1401
2537
|
}
|
|
1402
2538
|
|
|
1403
|
-
const TIMEOUT_MS = 1e4;
|
|
1404
|
-
const EXIT_CODE = {
|
|
1405
|
-
ok: 0,
|
|
1406
|
-
"auth-failed": 1,
|
|
1407
|
-
unreachable: 2,
|
|
1408
|
-
unexpected: 3
|
|
1409
|
-
};
|
|
1410
|
-
async function probeCommand(opts = {}) {
|
|
1411
|
-
const creds = readActiveApiCreds();
|
|
1412
|
-
if (!creds.baseUrl) {
|
|
1413
|
-
throw new Error("\u672A\u627E\u5230 API \u914D\u7F6E\uFF0C\u8BF7\u5148\u8FD0\u884C ccjk init \u6216\u83DC\u5355 3 \u914D\u7F6E API");
|
|
1414
|
-
}
|
|
1415
|
-
const result = await runProbe(creds.baseUrl, creds.apiKey, creds.authToken);
|
|
1416
|
-
if (opts.json) {
|
|
1417
|
-
console.log(JSON.stringify(result, null, 2));
|
|
1418
|
-
} else {
|
|
1419
|
-
const color = result.status === "ok" ? ansis.green : ansis.red;
|
|
1420
|
-
console.log(`
|
|
1421
|
-
\u63A2\u6D3B ${creds.baseUrl}`);
|
|
1422
|
-
console.log(color(` \u72B6\u6001: ${result.status}`));
|
|
1423
|
-
if (result.httpStatus) console.log(ansis.dim(` HTTP: ${result.httpStatus}`));
|
|
1424
|
-
if (result.latencyMs) console.log(ansis.dim(` \u5EF6\u8FDF: ${result.latencyMs}ms`));
|
|
1425
|
-
if (result.error) console.log(ansis.dim(` \u9519\u8BEF: ${result.error}`));
|
|
1426
|
-
console.log();
|
|
1427
|
-
}
|
|
1428
|
-
process.exitCode = EXIT_CODE[result.status];
|
|
1429
|
-
}
|
|
1430
|
-
function readActiveApiCreds() {
|
|
1431
|
-
const tool = readCcjkConfig()?.codeToolType ?? "clavue";
|
|
1432
|
-
const file = activeSettingsFile(tool === "codex" || tool === "grok" ? "claude-code" : tool);
|
|
1433
|
-
const settings = readJsonConfig(file) || {};
|
|
1434
|
-
const env = settings.env || {};
|
|
1435
|
-
return {
|
|
1436
|
-
baseUrl: env.ANTHROPIC_BASE_URL || "",
|
|
1437
|
-
apiKey: env.ANTHROPIC_API_KEY || "",
|
|
1438
|
-
authToken: env.ANTHROPIC_AUTH_TOKEN || env.ANTHROPIC_API_KEY || ""
|
|
1439
|
-
};
|
|
1440
|
-
}
|
|
1441
|
-
async function runProbe(baseUrl, apiKey, authToken) {
|
|
1442
|
-
const url = `${baseUrl.replace(/\/$/, "")}/v1/messages`;
|
|
1443
|
-
const headers = {
|
|
1444
|
-
"content-type": "application/json",
|
|
1445
|
-
"anthropic-version": "2023-06-01"
|
|
1446
|
-
};
|
|
1447
|
-
if (authToken) headers.authorization = `Bearer ${authToken}`;
|
|
1448
|
-
else if (apiKey) headers["x-api-key"] = apiKey;
|
|
1449
|
-
const body = JSON.stringify({
|
|
1450
|
-
model: "claude-3-5-haiku-20241022",
|
|
1451
|
-
max_tokens: 1,
|
|
1452
|
-
messages: [{ role: "user", content: "ping" }]
|
|
1453
|
-
});
|
|
1454
|
-
const t0 = Date.now();
|
|
1455
|
-
try {
|
|
1456
|
-
const res = await fetch(url, { method: "POST", headers, body, signal: AbortSignal.timeout(TIMEOUT_MS) });
|
|
1457
|
-
const latencyMs = Date.now() - t0;
|
|
1458
|
-
if (res.status === 401 || res.status === 403) {
|
|
1459
|
-
return { baseUrl, status: "auth-failed", httpStatus: res.status, latencyMs };
|
|
1460
|
-
}
|
|
1461
|
-
if (res.ok) return { baseUrl, status: "ok", httpStatus: res.status, latencyMs };
|
|
1462
|
-
return { baseUrl, status: "unexpected", httpStatus: res.status, latencyMs };
|
|
1463
|
-
} catch (e) {
|
|
1464
|
-
return { baseUrl, status: "unreachable", error: e.message, latencyMs: Date.now() - t0 };
|
|
1465
|
-
}
|
|
1466
|
-
}
|
|
1467
|
-
|
|
1468
2539
|
const ONBOARDING_STATE_FILE = join(CCJK_CONFIG_DIR, "onboarding.json");
|
|
1469
2540
|
const LANGUAGE_SELECTION_MESSAGES = {
|
|
1470
2541
|
selectLanguage: "Select CCJK display language / \u9009\u62E9 CCJK \u663E\u793A\u8BED\u8A00"
|
|
@@ -1645,404 +2716,129 @@ function printSeparator() {
|
|
|
1645
2716
|
${ansis.dim("\u2500".repeat(50))}
|
|
1646
2717
|
`);
|
|
1647
2718
|
}
|
|
1648
|
-
function getCodeToolLabel(codeTool) {
|
|
1649
|
-
return CODE_TOOL_LABELS[codeTool] || codeTool;
|
|
1650
|
-
}
|
|
1651
|
-
async function promptCodeToolSelection(current) {
|
|
1652
|
-
const choices = addNumbersToChoices(Object.entries(CODE_TOOL_LABELS).map(([value, label]) => ({
|
|
1653
|
-
name: label,
|
|
1654
|
-
value,
|
|
1655
|
-
short: label
|
|
1656
|
-
})));
|
|
1657
|
-
const { tool } = await inquirer.prompt({
|
|
1658
|
-
type: "list",
|
|
1659
|
-
name: "tool",
|
|
1660
|
-
message: i18n.t("menu:switchCodeToolPrompt"),
|
|
1661
|
-
default: current,
|
|
1662
|
-
choices
|
|
1663
|
-
});
|
|
1664
|
-
if (!tool) {
|
|
1665
|
-
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
1666
|
-
return null;
|
|
1667
|
-
}
|
|
1668
|
-
return tool;
|
|
1669
|
-
}
|
|
1670
|
-
async function handleCodeToolSwitch(current) {
|
|
1671
|
-
const newTool = await promptCodeToolSelection(current);
|
|
1672
|
-
if (!newTool || newTool === current) {
|
|
1673
|
-
return false;
|
|
1674
|
-
}
|
|
1675
|
-
updateCcjkConfig({ codeToolType: newTool });
|
|
1676
|
-
console.log(ansis.green(`\u2714 ${i18n.t("menu:codeToolSwitched", { tool: getCodeToolLabel(newTool) })}`));
|
|
1677
|
-
return true;
|
|
1678
|
-
}
|
|
1679
|
-
function printOtherToolsSection() {
|
|
1680
|
-
console.log(` --------- ${i18n.t("menu:menuSections.otherTools")} ----------`);
|
|
1681
|
-
console.log(
|
|
1682
|
-
` ${ansis.cyan("P.")} Probe API ${ansis.gray("- HTTP \u63A2\u6D3B\u5F53\u524D\u914D\u7F6E")}`
|
|
1683
|
-
);
|
|
1684
|
-
console.log(
|
|
1685
|
-
` ${ansis.cyan("G.")} Grok CLI ${ansis.gray("- \u72B6\u6001 / \u542F\u52A8\u6307\u5F15")}`
|
|
1686
|
-
);
|
|
1687
|
-
console.log(
|
|
1688
|
-
` ${ansis.cyan("X.")} Reasonix ${ansis.gray("- DeepSeek agent \u72B6\u6001 / \u542F\u52A8\u6307\u5F15")}`
|
|
1689
|
-
);
|
|
1690
|
-
console.log("");
|
|
1691
|
-
}
|
|
1692
|
-
function printCcjkSection(options) {
|
|
1693
|
-
console.log(" ------------ CCJK ------------");
|
|
1694
|
-
console.log(
|
|
1695
|
-
` ${ansis.cyan("0.")} ${i18n.t("menu:menuOptions.changeLanguage")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.changeLanguage")}`)}`
|
|
1696
|
-
);
|
|
1697
|
-
console.log(
|
|
1698
|
-
` ${ansis.cyan("S.")} ${i18n.t("menu:menuOptions.switchCodeTool")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.switchCodeTool")}`)}`
|
|
1699
|
-
);
|
|
1700
|
-
console.log(
|
|
1701
|
-
` ${ansis.cyan("-.")} ${options.uninstallOption} ${ansis.gray(`- ${options.uninstallDescription}`)}`
|
|
1702
|
-
);
|
|
1703
|
-
console.log(
|
|
1704
|
-
` ${ansis.cyan("+.")} ${options.updateOption} ${ansis.gray(`- ${options.updateDescription}`)}`
|
|
1705
|
-
);
|
|
1706
|
-
console.log(` ${ansis.red("Q.")} ${ansis.red(i18n.t("menu:menuOptions.exit"))}`);
|
|
1707
|
-
console.log("");
|
|
1708
|
-
}
|
|
1709
|
-
async function showClavueMenu() {
|
|
1710
|
-
console.log(ansis.cyan(i18n.t("menu:selectFunction")));
|
|
1711
|
-
console.log(" -------- Clavue --------");
|
|
1712
|
-
console.log(
|
|
1713
|
-
` ${ansis.cyan("1.")} ${i18n.t("menu:menuOptions.clavueFullInit")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.clavueFullInit")}`)}`
|
|
1714
|
-
);
|
|
1715
|
-
console.log(
|
|
1716
|
-
` ${ansis.cyan("2.")} ${i18n.t("menu:menuOptions.clavueUpdateWorkflow")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.clavueUpdateWorkflow")}`)}`
|
|
1717
|
-
);
|
|
1718
|
-
console.log(
|
|
1719
|
-
` ${ansis.cyan("3.")} ${i18n.t("menu:menuOptions.clavueConfigureApi")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.clavueConfigureApi")}`)}`
|
|
1720
|
-
);
|
|
1721
|
-
console.log(
|
|
1722
|
-
` ${ansis.cyan("4.")} ${i18n.t("menu:menuOptions.clavueConfigureMcp")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.clavueConfigureMcp")}`)}`
|
|
1723
|
-
);
|
|
1724
|
-
console.log(
|
|
1725
|
-
` ${ansis.cyan("5.")} ${i18n.t("menu:menuOptions.clavueConfigureModel")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.clavueConfigureModel")}`)}`
|
|
1726
|
-
);
|
|
1727
|
-
console.log(
|
|
1728
|
-
` ${ansis.cyan("6.")} ${i18n.t("menu:menuOptions.clavueConfigureAiMemory")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.clavueConfigureAiMemory")}`)}`
|
|
1729
|
-
);
|
|
1730
|
-
console.log(
|
|
1731
|
-
` ${ansis.cyan("7.")} ${i18n.t("menu:menuOptions.clavueConfigureEnvPermission")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.clavueConfigureEnvPermission")}`)}`
|
|
1732
|
-
);
|
|
1733
|
-
console.log(
|
|
1734
|
-
` ${ansis.cyan("8.")} ${i18n.t("menu:menuOptions.clavueStatus")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.clavueStatus")}`)}`
|
|
1735
|
-
);
|
|
1736
|
-
console.log("");
|
|
1737
|
-
printOtherToolsSection();
|
|
1738
|
-
printCcjkSection({
|
|
1739
|
-
uninstallOption: i18n.t("menu:menuOptions.clavueUninstall"),
|
|
1740
|
-
uninstallDescription: i18n.t("menu:menuDescriptions.clavueUninstall"),
|
|
1741
|
-
updateOption: i18n.t("menu:menuOptions.clavueCheckUpdates"),
|
|
1742
|
-
updateDescription: i18n.t("menu:menuDescriptions.clavueCheckUpdates")
|
|
1743
|
-
});
|
|
1744
|
-
const { choice } = await inquirer.prompt({
|
|
1745
|
-
type: "input",
|
|
1746
|
-
name: "choice",
|
|
1747
|
-
message: i18n.t("common:enterChoice"),
|
|
1748
|
-
validate: (value) => {
|
|
1749
|
-
const valid = ["1", "2", "3", "4", "5", "6", "7", "8", "p", "P", "g", "G", "x", "X", "0", "-", "+", "s", "S", "q", "Q"];
|
|
1750
|
-
return valid.includes(value) || i18n.t("common:invalidChoice");
|
|
1751
|
-
}
|
|
1752
|
-
});
|
|
1753
|
-
if (!choice) {
|
|
1754
|
-
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
1755
|
-
return "exit";
|
|
1756
|
-
}
|
|
1757
|
-
const normalized = choice.toLowerCase();
|
|
1758
|
-
switch (normalized) {
|
|
1759
|
-
case "1":
|
|
1760
|
-
await init({ skipBanner: true, codeType: "clavue" });
|
|
1761
|
-
break;
|
|
1762
|
-
case "2":
|
|
1763
|
-
await update({ skipBanner: true, codeType: "clavue" });
|
|
1764
|
-
break;
|
|
1765
|
-
case "3":
|
|
1766
|
-
await configureApiFeature();
|
|
1767
|
-
break;
|
|
1768
|
-
case "4":
|
|
1769
|
-
await configureMcpFeature();
|
|
1770
|
-
break;
|
|
1771
|
-
case "5":
|
|
1772
|
-
await configureDefaultModelFeature();
|
|
1773
|
-
break;
|
|
1774
|
-
case "6":
|
|
1775
|
-
await configureAiMemoryFeature();
|
|
1776
|
-
break;
|
|
1777
|
-
case "7":
|
|
1778
|
-
await configureEnvPermissionFeature();
|
|
1779
|
-
break;
|
|
1780
|
-
case "8":
|
|
1781
|
-
case "p":
|
|
1782
|
-
await probeCommand();
|
|
1783
|
-
printSeparator();
|
|
1784
|
-
return void 0;
|
|
1785
|
-
case "g":
|
|
1786
|
-
await grokCommand();
|
|
1787
|
-
printSeparator();
|
|
1788
|
-
return void 0;
|
|
1789
|
-
case "x":
|
|
1790
|
-
await reasonixCommand();
|
|
1791
|
-
printSeparator();
|
|
1792
|
-
return void 0;
|
|
1793
|
-
case "0": {
|
|
1794
|
-
const currentLang = i18n.language;
|
|
1795
|
-
await changeScriptLanguageFeature(currentLang);
|
|
1796
|
-
printSeparator();
|
|
1797
|
-
return void 0;
|
|
1798
|
-
}
|
|
1799
|
-
case "-":
|
|
1800
|
-
await uninstall();
|
|
1801
|
-
printSeparator();
|
|
1802
|
-
return void 0;
|
|
1803
|
-
case "+":
|
|
1804
|
-
await checkUpdates();
|
|
1805
|
-
printSeparator();
|
|
1806
|
-
return void 0;
|
|
1807
|
-
case "s": {
|
|
1808
|
-
const switched = await handleCodeToolSwitch("clavue");
|
|
1809
|
-
if (switched) {
|
|
1810
|
-
return "switch";
|
|
1811
|
-
}
|
|
1812
|
-
printSeparator();
|
|
1813
|
-
return void 0;
|
|
1814
|
-
}
|
|
1815
|
-
case "q":
|
|
1816
|
-
console.log(ansis.cyan(i18n.t("common:goodbye")));
|
|
1817
|
-
return "exit";
|
|
1818
|
-
default:
|
|
1819
|
-
return void 0;
|
|
1820
|
-
}
|
|
1821
|
-
printSeparator();
|
|
1822
|
-
const shouldContinue = await promptBoolean({
|
|
1823
|
-
message: i18n.t("common:returnToMenu"),
|
|
1824
|
-
defaultValue: true
|
|
1825
|
-
});
|
|
1826
|
-
if (!shouldContinue) {
|
|
1827
|
-
console.log(ansis.cyan(i18n.t("common:goodbye")));
|
|
1828
|
-
return "exit";
|
|
1829
|
-
}
|
|
1830
|
-
return void 0;
|
|
2719
|
+
function getCodeToolLabel(codeTool) {
|
|
2720
|
+
return CODE_TOOL_LABELS[codeTool] || codeTool;
|
|
1831
2721
|
}
|
|
1832
|
-
async function
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
` ${ansis.cyan("4.")} ${i18n.t("menu:menuOptions.configureMcp")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureMcp")}`)}`
|
|
1846
|
-
);
|
|
1847
|
-
console.log(
|
|
1848
|
-
` ${ansis.cyan("5.")} ${i18n.t("menu:menuOptions.configureModel")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureModel")}`)}`
|
|
1849
|
-
);
|
|
1850
|
-
console.log(
|
|
1851
|
-
` ${ansis.cyan("6.")} ${i18n.t("menu:menuOptions.configureAiMemory")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureAiMemory")}`)}`
|
|
1852
|
-
);
|
|
1853
|
-
console.log(
|
|
1854
|
-
` ${ansis.cyan("7.")} ${i18n.t("menu:menuOptions.configureEnvPermission")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.configureEnvPermission")}`)}`
|
|
1855
|
-
);
|
|
1856
|
-
console.log("");
|
|
1857
|
-
printOtherToolsSection();
|
|
1858
|
-
printCcjkSection({
|
|
1859
|
-
uninstallOption: i18n.t("menu:menuOptions.uninstall"),
|
|
1860
|
-
uninstallDescription: i18n.t("menu:menuDescriptions.uninstall"),
|
|
1861
|
-
updateOption: i18n.t("menu:menuOptions.checkUpdates"),
|
|
1862
|
-
updateDescription: i18n.t("menu:menuDescriptions.checkUpdates")
|
|
1863
|
-
});
|
|
1864
|
-
const { choice } = await inquirer.prompt({
|
|
1865
|
-
type: "input",
|
|
1866
|
-
name: "choice",
|
|
1867
|
-
message: i18n.t("common:enterChoice"),
|
|
1868
|
-
validate: (value) => {
|
|
1869
|
-
const valid = ["1", "2", "3", "4", "5", "6", "7", "p", "P", "g", "G", "x", "X", "0", "-", "+", "s", "S", "q", "Q"];
|
|
1870
|
-
return valid.includes(value) || i18n.t("common:invalidChoice");
|
|
1871
|
-
}
|
|
2722
|
+
async function promptCodeToolSelection(current) {
|
|
2723
|
+
const { addNumbersToChoices } = await import('./chunks/simple-config.mjs').then(function (n) { return n.bM; });
|
|
2724
|
+
const choices = addNumbersToChoices(Object.entries(CODE_TOOL_LABELS).map(([value, label]) => ({
|
|
2725
|
+
name: label,
|
|
2726
|
+
value,
|
|
2727
|
+
short: label
|
|
2728
|
+
})));
|
|
2729
|
+
const { tool } = await inquirer.prompt({
|
|
2730
|
+
type: "list",
|
|
2731
|
+
name: "tool",
|
|
2732
|
+
message: i18n.t("menu:switchCodeToolPrompt"),
|
|
2733
|
+
default: current,
|
|
2734
|
+
choices
|
|
1872
2735
|
});
|
|
1873
|
-
if (!
|
|
2736
|
+
if (!tool) {
|
|
1874
2737
|
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
1875
|
-
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;
|
|
1876
2746
|
}
|
|
1877
|
-
|
|
1878
|
-
|
|
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) {
|
|
1879
2753
|
case "1":
|
|
1880
|
-
await init({ skipBanner: true });
|
|
1881
|
-
|
|
2754
|
+
await init({ skipBanner: true, codeType: tool });
|
|
2755
|
+
return "handled";
|
|
1882
2756
|
case "2":
|
|
1883
|
-
await update({ skipBanner: true });
|
|
1884
|
-
|
|
2757
|
+
await update({ skipBanner: true, codeType: tool });
|
|
2758
|
+
return "handled";
|
|
1885
2759
|
case "3":
|
|
1886
2760
|
await configureApiFeature();
|
|
1887
|
-
|
|
2761
|
+
return "handled";
|
|
1888
2762
|
case "4":
|
|
1889
2763
|
await configureMcpFeature();
|
|
1890
|
-
|
|
2764
|
+
return "handled";
|
|
1891
2765
|
case "5":
|
|
1892
2766
|
await configureDefaultModelFeature();
|
|
1893
|
-
|
|
2767
|
+
return "handled";
|
|
1894
2768
|
case "6":
|
|
1895
2769
|
await configureAiMemoryFeature();
|
|
1896
|
-
|
|
2770
|
+
return "handled";
|
|
1897
2771
|
case "7":
|
|
1898
2772
|
await configureEnvPermissionFeature();
|
|
1899
|
-
|
|
1900
|
-
case "p":
|
|
1901
|
-
await probeCommand();
|
|
1902
|
-
printSeparator();
|
|
1903
|
-
return void 0;
|
|
1904
|
-
case "g":
|
|
1905
|
-
await grokCommand();
|
|
1906
|
-
printSeparator();
|
|
1907
|
-
return void 0;
|
|
1908
|
-
case "x":
|
|
1909
|
-
await reasonixCommand();
|
|
1910
|
-
printSeparator();
|
|
1911
|
-
return void 0;
|
|
1912
|
-
case "0": {
|
|
1913
|
-
const currentLang = i18n.language;
|
|
1914
|
-
await changeScriptLanguageFeature(currentLang);
|
|
1915
|
-
printSeparator();
|
|
1916
|
-
return void 0;
|
|
1917
|
-
}
|
|
1918
|
-
case "-":
|
|
1919
|
-
await uninstall();
|
|
1920
|
-
printSeparator();
|
|
1921
|
-
return void 0;
|
|
1922
|
-
case "+":
|
|
1923
|
-
await checkUpdates();
|
|
1924
|
-
printSeparator();
|
|
1925
|
-
return void 0;
|
|
1926
|
-
case "s": {
|
|
1927
|
-
const switched = await handleCodeToolSwitch("claude-code");
|
|
1928
|
-
if (switched) {
|
|
1929
|
-
return "switch";
|
|
1930
|
-
}
|
|
1931
|
-
printSeparator();
|
|
1932
|
-
return void 0;
|
|
1933
|
-
}
|
|
1934
|
-
case "q":
|
|
1935
|
-
console.log(ansis.cyan(i18n.t("common:goodbye")));
|
|
1936
|
-
return "exit";
|
|
2773
|
+
return "handled";
|
|
1937
2774
|
default:
|
|
1938
2775
|
return void 0;
|
|
1939
2776
|
}
|
|
1940
|
-
printSeparator();
|
|
1941
|
-
const shouldContinue = await promptBoolean({
|
|
1942
|
-
message: i18n.t("common:returnToMenu"),
|
|
1943
|
-
defaultValue: true
|
|
1944
|
-
});
|
|
1945
|
-
if (!shouldContinue) {
|
|
1946
|
-
console.log(ansis.cyan(i18n.t("common:goodbye")));
|
|
1947
|
-
return "exit";
|
|
1948
|
-
}
|
|
1949
|
-
return void 0;
|
|
1950
2777
|
}
|
|
1951
|
-
async function
|
|
1952
|
-
|
|
1953
|
-
console.log(" -------- Codex --------");
|
|
1954
|
-
console.log(
|
|
1955
|
-
` ${ansis.cyan("1.")} ${i18n.t("menu:menuOptions.codexFullInit")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexFullInit")}`)}`
|
|
1956
|
-
);
|
|
1957
|
-
console.log(
|
|
1958
|
-
` ${ansis.cyan("2.")} ${i18n.t("menu:menuOptions.codexImportWorkflow")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexImportWorkflow")}`)}`
|
|
1959
|
-
);
|
|
1960
|
-
console.log(
|
|
1961
|
-
` ${ansis.cyan("3.")} ${i18n.t("menu:menuOptions.codexConfigureApi")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexConfigureApi")}`)}`
|
|
1962
|
-
);
|
|
1963
|
-
console.log(
|
|
1964
|
-
` ${ansis.cyan("4.")} ${i18n.t("menu:menuOptions.codexConfigureMcp")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexConfigureMcp")}`)}`
|
|
1965
|
-
);
|
|
1966
|
-
console.log(
|
|
1967
|
-
` ${ansis.cyan("5.")} ${i18n.t("menu:menuOptions.codexConfigureModel")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexConfigureModel")}`)}`
|
|
1968
|
-
);
|
|
1969
|
-
console.log(
|
|
1970
|
-
` ${ansis.cyan("6.")} ${i18n.t("menu:menuOptions.codexConfigureAiMemory")} ${ansis.gray(`- ${i18n.t("menu:menuDescriptions.codexConfigureAiMemory")}`)}`
|
|
1971
|
-
);
|
|
1972
|
-
console.log("");
|
|
1973
|
-
printOtherToolsSection();
|
|
1974
|
-
printCcjkSection({
|
|
1975
|
-
uninstallOption: i18n.t("menu:menuOptions.codexUninstall"),
|
|
1976
|
-
uninstallDescription: i18n.t("menu:menuDescriptions.codexUninstall"),
|
|
1977
|
-
updateOption: i18n.t("menu:menuOptions.codexCheckUpdates"),
|
|
1978
|
-
updateDescription: i18n.t("menu:menuDescriptions.codexCheckUpdates")
|
|
1979
|
-
});
|
|
1980
|
-
const { choice } = await inquirer.prompt({
|
|
1981
|
-
type: "input",
|
|
1982
|
-
name: "choice",
|
|
1983
|
-
message: i18n.t("common:enterChoice"),
|
|
1984
|
-
validate: (value) => {
|
|
1985
|
-
const valid = ["1", "2", "3", "4", "5", "6", "p", "P", "g", "G", "x", "X", "0", "-", "+", "s", "S", "q", "Q"];
|
|
1986
|
-
return valid.includes(value) || i18n.t("common:invalidChoice");
|
|
1987
|
-
}
|
|
1988
|
-
});
|
|
1989
|
-
if (!choice) {
|
|
1990
|
-
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
1991
|
-
return "exit";
|
|
1992
|
-
}
|
|
1993
|
-
const normalized = choice.toLowerCase();
|
|
1994
|
-
switch (normalized) {
|
|
2778
|
+
async function handleCodexChoice(choice) {
|
|
2779
|
+
switch (choice) {
|
|
1995
2780
|
case "1":
|
|
1996
2781
|
await runCodexFullInit();
|
|
1997
|
-
|
|
2782
|
+
return "handled";
|
|
1998
2783
|
case "2":
|
|
1999
2784
|
await runCodexWorkflowImportWithLanguageSelection();
|
|
2000
|
-
|
|
2785
|
+
return "handled";
|
|
2001
2786
|
case "3":
|
|
2002
2787
|
await configureCodexApi();
|
|
2003
|
-
|
|
2788
|
+
return "handled";
|
|
2004
2789
|
case "4":
|
|
2005
2790
|
await manageCodexMcp();
|
|
2006
|
-
|
|
2791
|
+
return "handled";
|
|
2007
2792
|
case "5":
|
|
2008
2793
|
await configureCodexDefaultModelFeature();
|
|
2009
|
-
|
|
2794
|
+
return "handled";
|
|
2010
2795
|
case "6":
|
|
2011
2796
|
await configureCodexAiMemoryFeature();
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
await probeCommand();
|
|
2015
|
-
printSeparator();
|
|
2797
|
+
return "handled";
|
|
2798
|
+
default:
|
|
2016
2799
|
return void 0;
|
|
2017
|
-
|
|
2800
|
+
}
|
|
2801
|
+
}
|
|
2802
|
+
async function handleGrokChoice(choice) {
|
|
2803
|
+
switch (choice) {
|
|
2804
|
+
case "1":
|
|
2805
|
+
await init({ skipBanner: true, codeType: "grok" });
|
|
2806
|
+
return "handled";
|
|
2807
|
+
case "2":
|
|
2018
2808
|
await grokCommand();
|
|
2019
|
-
|
|
2809
|
+
return "handled";
|
|
2810
|
+
default:
|
|
2811
|
+
return void 0;
|
|
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:
|
|
2020
2823
|
return void 0;
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
async function handleSharedChoice(tool, choice) {
|
|
2827
|
+
switch (choice) {
|
|
2828
|
+
case "g":
|
|
2829
|
+
await grokCommand();
|
|
2830
|
+
return "continue";
|
|
2021
2831
|
case "x":
|
|
2022
2832
|
await reasonixCommand();
|
|
2023
|
-
|
|
2024
|
-
return void 0;
|
|
2833
|
+
return "continue";
|
|
2025
2834
|
case "0": {
|
|
2026
2835
|
const currentLang = i18n.language;
|
|
2027
2836
|
await changeScriptLanguageFeature(currentLang);
|
|
2028
|
-
|
|
2029
|
-
return void 0;
|
|
2837
|
+
return "continue";
|
|
2030
2838
|
}
|
|
2031
|
-
case "-":
|
|
2032
|
-
await runCodexUninstall();
|
|
2033
|
-
printSeparator();
|
|
2034
|
-
return void 0;
|
|
2035
|
-
case "+":
|
|
2036
|
-
await runCodexUpdate();
|
|
2037
|
-
printSeparator();
|
|
2038
|
-
return void 0;
|
|
2039
2839
|
case "s": {
|
|
2040
|
-
const switched = await handleCodeToolSwitch(
|
|
2041
|
-
|
|
2042
|
-
return "switch";
|
|
2043
|
-
}
|
|
2044
|
-
printSeparator();
|
|
2045
|
-
return void 0;
|
|
2840
|
+
const switched = await handleCodeToolSwitch(tool);
|
|
2841
|
+
return switched ? "switch" : "continue";
|
|
2046
2842
|
}
|
|
2047
2843
|
case "q":
|
|
2048
2844
|
console.log(ansis.cyan(i18n.t("common:goodbye")));
|
|
@@ -2050,94 +2846,69 @@ async function showCodexMenu() {
|
|
|
2050
2846
|
default:
|
|
2051
2847
|
return void 0;
|
|
2052
2848
|
}
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
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";
|
|
2061
2866
|
}
|
|
2062
2867
|
return void 0;
|
|
2063
2868
|
}
|
|
2064
|
-
async function
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
);
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
);
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
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);
|
|
2081
2893
|
const { choice } = await inquirer.prompt({
|
|
2082
|
-
type: "
|
|
2894
|
+
type: "list",
|
|
2083
2895
|
name: "choice",
|
|
2084
|
-
message: i18n.t("
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
return valid.includes(value) || i18n.t("common:invalidChoice");
|
|
2088
|
-
}
|
|
2896
|
+
message: i18n.t("menu:selectFunction"),
|
|
2897
|
+
choices: buildMenuListChoices(tool),
|
|
2898
|
+
pageSize: 20
|
|
2089
2899
|
});
|
|
2090
2900
|
if (!choice) {
|
|
2091
2901
|
console.log(ansis.yellow(i18n.t("common:cancelled")));
|
|
2092
2902
|
return "exit";
|
|
2093
2903
|
}
|
|
2094
|
-
const
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
case "p":
|
|
2103
|
-
await probeCommand();
|
|
2104
|
-
printSeparator();
|
|
2105
|
-
return void 0;
|
|
2106
|
-
case "g":
|
|
2107
|
-
await grokCommand();
|
|
2108
|
-
printSeparator();
|
|
2109
|
-
return void 0;
|
|
2110
|
-
case "x":
|
|
2111
|
-
await reasonixCommand();
|
|
2112
|
-
printSeparator();
|
|
2113
|
-
return void 0;
|
|
2114
|
-
case "0": {
|
|
2115
|
-
const currentLang = i18n.language;
|
|
2116
|
-
await changeScriptLanguageFeature(currentLang);
|
|
2117
|
-
printSeparator();
|
|
2118
|
-
return void 0;
|
|
2119
|
-
}
|
|
2120
|
-
case "-":
|
|
2121
|
-
await uninstall();
|
|
2122
|
-
printSeparator();
|
|
2123
|
-
return void 0;
|
|
2124
|
-
case "+":
|
|
2125
|
-
await checkUpdates();
|
|
2126
|
-
printSeparator();
|
|
2127
|
-
return void 0;
|
|
2128
|
-
case "s": {
|
|
2129
|
-
const switched = await handleCodeToolSwitch("grok");
|
|
2130
|
-
if (switched) {
|
|
2131
|
-
return "switch";
|
|
2132
|
-
}
|
|
2133
|
-
printSeparator();
|
|
2134
|
-
return void 0;
|
|
2135
|
-
}
|
|
2136
|
-
case "q":
|
|
2137
|
-
console.log(ansis.cyan(i18n.t("common:goodbye")));
|
|
2138
|
-
return "exit";
|
|
2139
|
-
default:
|
|
2140
|
-
return void 0;
|
|
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;
|
|
2141
2912
|
}
|
|
2142
2913
|
printSeparator();
|
|
2143
2914
|
const shouldContinue = await promptBoolean({
|
|
@@ -2172,7 +2943,7 @@ async function showMainMenu(options = {}) {
|
|
|
2172
2943
|
while (!exitMenu) {
|
|
2173
2944
|
const codeTool = getCurrentCodeTool();
|
|
2174
2945
|
displayBannerWithInfo(CODE_TOOL_BANNERS[codeTool] || "CCJK");
|
|
2175
|
-
const result =
|
|
2946
|
+
const result = await showToolMenu(codeTool);
|
|
2176
2947
|
if (result === "exit") {
|
|
2177
2948
|
exitMenu = true;
|
|
2178
2949
|
} else if (result === "switch") {
|
|
@@ -2281,7 +3052,7 @@ async function listCodexProvidersWithDisplay() {
|
|
|
2281
3052
|
console.log(ansis.cyan(i18n.t("codex:currentProvider", { provider: currentProvider })));
|
|
2282
3053
|
console.log();
|
|
2283
3054
|
}
|
|
2284
|
-
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; });
|
|
2285
3056
|
const profileFiles = listCodexProfileFiles();
|
|
2286
3057
|
if (profileFiles.length > 0) {
|
|
2287
3058
|
console.log(ansis.bold("Codex 0.135+ profiles (.config.toml):"));
|
|
@@ -2514,6 +3285,194 @@ async function benchCommand(opts = {}) {
|
|
|
2514
3285
|
await probeCommand({ json: opts.json });
|
|
2515
3286
|
}
|
|
2516
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
|
+
|
|
2517
3476
|
async function resolveAndSwitchLanguage(lang, options, skipPrompt = false) {
|
|
2518
3477
|
const ccjkConfig = await readCcjkConfigAsync();
|
|
2519
3478
|
const targetLang = options?.allLang || lang || options?.lang || ccjkConfig?.preferredLang || (skipPrompt ? "en" : await selectScriptLanguage());
|
|
@@ -2648,7 +3607,7 @@ async function setupCommands(cli) {
|
|
|
2648
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) => {
|
|
2649
3608
|
await showMainMenu({ codeType: options.codeType });
|
|
2650
3609
|
}, true));
|
|
2651
|
-
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) => {
|
|
2652
3611
|
await init(options);
|
|
2653
3612
|
}));
|
|
2654
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) => {
|
|
@@ -2667,6 +3626,14 @@ async function setupCommands(cli) {
|
|
|
2667
3626
|
list: options.list
|
|
2668
3627
|
});
|
|
2669
3628
|
}));
|
|
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
|
+
}));
|
|
2670
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) => {
|
|
2671
3638
|
await uninstall(options);
|
|
2672
3639
|
}));
|
|
@@ -2682,9 +3649,12 @@ async function setupCommands(cli) {
|
|
|
2682
3649
|
}));
|
|
2683
3650
|
cli.command("probe", "HTTP probe current API configuration").option("--json", "JSON output").action(await withLanguageResolution(async (options) => {
|
|
2684
3651
|
await probeCommand({ json: options.json });
|
|
2685
|
-
}));
|
|
3652
|
+
}, true));
|
|
2686
3653
|
cli.command("bench", "Lightweight latency benchmark (probe)").option("--json", "JSON output").action(await withLanguageResolution(async (options) => {
|
|
2687
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 });
|
|
2688
3658
|
}));
|
|
2689
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) => {
|
|
2690
3660
|
await checkUpdates(options);
|