zcf 2.7.1 → 2.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -23
- package/bin/zcf.mjs +1 -1
- package/dist/{shared/zcf.CZ3RjfyP.mjs → chunks/simple-config.mjs} +1362 -329
- package/dist/cli.mjs +492 -131
- package/dist/index.d.mts +22 -240
- package/dist/index.d.ts +22 -240
- package/dist/index.mjs +12 -1
- package/package.json +6 -1
package/dist/cli.mjs
CHANGED
|
@@ -1,82 +1,138 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import cac from 'cac';
|
|
3
3
|
import ansis from 'ansis';
|
|
4
|
-
import {
|
|
4
|
+
import { J as getTranslation, Z as ZCF_CONFIG_FILE, h as SUPPORTED_LANGS, K as addNumbersToChoices, j as LANG_LABELS, N as updateZcfConfig, o as openSettingsJson, b as importRecommendedPermissions, a as importRecommendedEnv, O as readZcfConfig, x as applyAiLanguageDirective, P as configureAiPersonality, v as getExistingModelConfig, u as updateDefaultModel, Q as isWindows, z as readMcpConfig, G as fixWindowsMcpConfig, B as writeMcpConfig, R as selectMcpServices, D as backupMcpConfig, M as MCP_SERVICES, F as buildMcpServerConfig, E as mergeMcpServers, w as getExistingApiConfig, T as formatApiKeyDisplay, H as addCompletedOnboarding, U as modifyApiConfigPartially, V as isCcrInstalled, W as installCcr, X as setupCcrConfiguration, Y as validateApiKey, r as configureApi, _ as readZcfConfigAsync, I as I18N, $ as readCcrConfig, a0 as configureCcrFeature, a1 as handleExitPromptError, a2 as handleGeneralError, a3 as displayBanner, a4 as selectScriptLanguage, a5 as resolveAiOutputLanguage, a6 as updatePromptOnly, a7 as selectAndInstallWorkflows, a8 as version, a9 as displayBannerWithInfo, i as init, aa as checkAndUpdateTools } from './chunks/simple-config.mjs';
|
|
5
5
|
import inquirer from 'inquirer';
|
|
6
6
|
import { existsSync, unlinkSync } from 'node:fs';
|
|
7
7
|
import { x } from 'tinyexec';
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { exec } from 'child_process';
|
|
11
|
+
import { promisify } from 'util';
|
|
8
12
|
import 'pathe';
|
|
9
13
|
import 'dayjs';
|
|
10
14
|
import 'node:url';
|
|
15
|
+
import 'ora';
|
|
16
|
+
import 'prompts';
|
|
17
|
+
import 'fs/promises';
|
|
18
|
+
import 'path';
|
|
19
|
+
import 'os';
|
|
20
|
+
import 'semver';
|
|
11
21
|
import 'node:fs/promises';
|
|
12
|
-
import 'node:
|
|
22
|
+
import 'node:child_process';
|
|
23
|
+
import 'node:util';
|
|
13
24
|
|
|
14
25
|
function handleCancellation(scriptLang) {
|
|
15
|
-
|
|
26
|
+
const i18n = getTranslation(scriptLang);
|
|
27
|
+
console.log(ansis.yellow(i18n.common.cancelled));
|
|
16
28
|
}
|
|
17
29
|
async function configureApiFeature(scriptLang) {
|
|
18
|
-
const i18n =
|
|
30
|
+
const i18n = getTranslation(scriptLang);
|
|
19
31
|
const existingApiConfig = getExistingApiConfig();
|
|
20
32
|
if (existingApiConfig) {
|
|
21
|
-
console.log("\n" + ansis.blue(`\u2139 ${i18n.existingApiConfig}`));
|
|
22
|
-
console.log(ansis.gray(` ${i18n.apiConfigUrl}: ${existingApiConfig.url || i18n.notConfigured}`));
|
|
23
|
-
console.log(
|
|
24
|
-
|
|
25
|
-
`)
|
|
33
|
+
console.log("\n" + ansis.blue(`\u2139 ${i18n.api.existingApiConfig}`));
|
|
34
|
+
console.log(ansis.gray(` ${i18n.api.apiConfigUrl}: ${existingApiConfig.url || i18n.common.notConfigured}`));
|
|
35
|
+
console.log(
|
|
36
|
+
ansis.gray(
|
|
37
|
+
` ${i18n.api.apiConfigKey}: ${existingApiConfig.key ? formatApiKeyDisplay(existingApiConfig.key) : i18n.common.notConfigured}`
|
|
38
|
+
)
|
|
39
|
+
);
|
|
40
|
+
console.log(
|
|
41
|
+
ansis.gray(` ${i18n.api.apiConfigAuthType}: ${existingApiConfig.authType || i18n.common.notConfigured}
|
|
42
|
+
`)
|
|
43
|
+
);
|
|
26
44
|
const { action } = await inquirer.prompt({
|
|
27
45
|
type: "list",
|
|
28
46
|
name: "action",
|
|
29
|
-
message: i18n.selectApiAction,
|
|
30
|
-
choices: [
|
|
31
|
-
{ name: i18n.keepExistingConfig, value: "keep" },
|
|
32
|
-
{ name: i18n.modifyAllConfig, value: "modify-all" },
|
|
33
|
-
{ name: i18n.modifyPartialConfig, value: "modify-partial" }
|
|
34
|
-
|
|
47
|
+
message: i18n.api.selectApiAction,
|
|
48
|
+
choices: addNumbersToChoices([
|
|
49
|
+
{ name: i18n.api.keepExistingConfig, value: "keep" },
|
|
50
|
+
{ name: i18n.api.modifyAllConfig, value: "modify-all" },
|
|
51
|
+
{ name: i18n.api.modifyPartialConfig, value: "modify-partial" },
|
|
52
|
+
{ name: i18n.api.useCcrProxy, value: "use-ccr" }
|
|
53
|
+
])
|
|
35
54
|
});
|
|
36
55
|
if (!action) {
|
|
37
56
|
handleCancellation(scriptLang);
|
|
38
57
|
return;
|
|
39
58
|
}
|
|
40
59
|
if (action === "keep") {
|
|
41
|
-
console.log(ansis.green(`\u2714 ${i18n.keepExistingConfig}`));
|
|
60
|
+
console.log(ansis.green(`\u2714 ${i18n.api.keepExistingConfig}`));
|
|
61
|
+
try {
|
|
62
|
+
addCompletedOnboarding();
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error(ansis.red(i18n.configuration.failedToSetOnboarding), error);
|
|
65
|
+
}
|
|
42
66
|
return;
|
|
43
67
|
} else if (action === "modify-partial") {
|
|
44
68
|
await modifyApiConfigPartially(existingApiConfig, i18n, scriptLang);
|
|
45
69
|
return;
|
|
70
|
+
} else if (action === "use-ccr") {
|
|
71
|
+
const ccrInstalled = await isCcrInstalled();
|
|
72
|
+
if (!ccrInstalled) {
|
|
73
|
+
console.log(ansis.yellow(`${i18n.ccr.installingCcr}`));
|
|
74
|
+
await installCcr(scriptLang);
|
|
75
|
+
} else {
|
|
76
|
+
console.log(ansis.green(`\u2714 ${i18n.ccr.ccrAlreadyInstalled}`));
|
|
77
|
+
}
|
|
78
|
+
const ccrConfigured = await setupCcrConfiguration(scriptLang);
|
|
79
|
+
if (ccrConfigured) {
|
|
80
|
+
console.log(ansis.green(`\u2714 ${i18n.ccr.ccrSetupComplete}`));
|
|
81
|
+
}
|
|
82
|
+
return;
|
|
46
83
|
}
|
|
47
84
|
}
|
|
48
85
|
const { apiChoice } = await inquirer.prompt({
|
|
49
86
|
type: "list",
|
|
50
87
|
name: "apiChoice",
|
|
51
|
-
message: i18n.configureApi,
|
|
52
|
-
choices: [
|
|
88
|
+
message: i18n.api.configureApi,
|
|
89
|
+
choices: addNumbersToChoices([
|
|
53
90
|
{
|
|
54
|
-
name: `${i18n.useAuthToken} - ${ansis.gray(i18n.authTokenDesc)}`,
|
|
91
|
+
name: `${i18n.api.useAuthToken} - ${ansis.gray(i18n.api.authTokenDesc)}`,
|
|
55
92
|
value: "auth_token",
|
|
56
|
-
short: i18n.useAuthToken
|
|
93
|
+
short: i18n.api.useAuthToken
|
|
57
94
|
},
|
|
58
95
|
{
|
|
59
|
-
name: `${i18n.useApiKey} - ${ansis.gray(i18n.apiKeyDesc)}`,
|
|
96
|
+
name: `${i18n.api.useApiKey} - ${ansis.gray(i18n.api.apiKeyDesc)}`,
|
|
60
97
|
value: "api_key",
|
|
61
|
-
short: i18n.useApiKey
|
|
98
|
+
short: i18n.api.useApiKey
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: `${i18n.api.useCcrProxy} - ${ansis.gray(i18n.api.ccrProxyDesc)}`,
|
|
102
|
+
value: "ccr_proxy",
|
|
103
|
+
short: i18n.api.useCcrProxy
|
|
62
104
|
},
|
|
63
|
-
{ name: i18n.skipApi, value: "skip" }
|
|
64
|
-
]
|
|
105
|
+
{ name: i18n.api.skipApi, value: "skip" }
|
|
106
|
+
])
|
|
65
107
|
});
|
|
66
108
|
if (!apiChoice || apiChoice === "skip") {
|
|
67
109
|
return;
|
|
68
110
|
}
|
|
111
|
+
if (apiChoice === "ccr_proxy") {
|
|
112
|
+
const ccrInstalled = await isCcrInstalled();
|
|
113
|
+
if (!ccrInstalled) {
|
|
114
|
+
console.log(ansis.yellow(`${i18n.ccr.installingCcr}`));
|
|
115
|
+
await installCcr(scriptLang);
|
|
116
|
+
} else {
|
|
117
|
+
console.log(ansis.green(`\u2714 ${i18n.ccr.ccrAlreadyInstalled}`));
|
|
118
|
+
}
|
|
119
|
+
const ccrConfigured = await setupCcrConfiguration(scriptLang);
|
|
120
|
+
if (ccrConfigured) {
|
|
121
|
+
console.log(ansis.green(`\u2714 ${i18n.ccr.ccrSetupComplete}`));
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
69
125
|
const { url } = await inquirer.prompt({
|
|
70
126
|
type: "input",
|
|
71
127
|
name: "url",
|
|
72
|
-
message: i18n.enterApiUrl,
|
|
128
|
+
message: i18n.api.enterApiUrl,
|
|
73
129
|
validate: (value) => {
|
|
74
|
-
if (!value) return i18n.urlRequired;
|
|
130
|
+
if (!value) return i18n.api.urlRequired;
|
|
75
131
|
try {
|
|
76
132
|
new URL(value);
|
|
77
133
|
return true;
|
|
78
134
|
} catch {
|
|
79
|
-
return i18n.invalidUrl;
|
|
135
|
+
return i18n.api.invalidUrl;
|
|
80
136
|
}
|
|
81
137
|
}
|
|
82
138
|
});
|
|
@@ -84,18 +140,18 @@ async function configureApiFeature(scriptLang) {
|
|
|
84
140
|
handleCancellation(scriptLang);
|
|
85
141
|
return;
|
|
86
142
|
}
|
|
87
|
-
const keyMessage = apiChoice === "auth_token" ? i18n.enterAuthToken : i18n.enterApiKey;
|
|
143
|
+
const keyMessage = apiChoice === "auth_token" ? i18n.api.enterAuthToken : i18n.api.enterApiKey;
|
|
88
144
|
const { key } = await inquirer.prompt({
|
|
89
145
|
type: "input",
|
|
90
146
|
name: "key",
|
|
91
147
|
message: keyMessage,
|
|
92
148
|
validate: (value) => {
|
|
93
149
|
if (!value) {
|
|
94
|
-
return i18n.keyRequired;
|
|
150
|
+
return i18n.api.keyRequired;
|
|
95
151
|
}
|
|
96
152
|
const validation = validateApiKey(value, scriptLang);
|
|
97
153
|
if (!validation.isValid) {
|
|
98
|
-
return validation.error || i18n.invalidKeyFormat;
|
|
154
|
+
return validation.error || i18n.api.invalidKeyFormat;
|
|
99
155
|
}
|
|
100
156
|
return true;
|
|
101
157
|
}
|
|
@@ -107,25 +163,25 @@ async function configureApiFeature(scriptLang) {
|
|
|
107
163
|
const apiConfig = { url, key, authType: apiChoice };
|
|
108
164
|
const configuredApi = configureApi(apiConfig);
|
|
109
165
|
if (configuredApi) {
|
|
110
|
-
console.log(ansis.green(`\u2714 ${i18n.apiConfigSuccess}`));
|
|
166
|
+
console.log(ansis.green(`\u2714 ${i18n.api.apiConfigSuccess}`));
|
|
111
167
|
console.log(ansis.gray(` URL: ${configuredApi.url}`));
|
|
112
168
|
console.log(ansis.gray(` Key: ${formatApiKeyDisplay(configuredApi.key)}`));
|
|
113
169
|
}
|
|
114
170
|
}
|
|
115
171
|
async function configureMcpFeature(scriptLang) {
|
|
116
|
-
const i18n =
|
|
172
|
+
const i18n = getTranslation(scriptLang);
|
|
117
173
|
if (isWindows()) {
|
|
118
174
|
const { fixWindows } = await inquirer.prompt({
|
|
119
175
|
type: "confirm",
|
|
120
176
|
name: "fixWindows",
|
|
121
|
-
message: i18n.fixWindowsMcp || "Fix Windows MCP configuration?",
|
|
177
|
+
message: i18n.configuration.fixWindowsMcp || "Fix Windows MCP configuration?",
|
|
122
178
|
default: true
|
|
123
179
|
});
|
|
124
180
|
if (fixWindows) {
|
|
125
181
|
const existingConfig = readMcpConfig() || { mcpServers: {} };
|
|
126
182
|
const fixedConfig = fixWindowsMcpConfig(existingConfig);
|
|
127
183
|
writeMcpConfig(fixedConfig);
|
|
128
|
-
console.log(ansis.green(`\u2714
|
|
184
|
+
console.log(ansis.green(`\u2714 Windows MCP configuration fixed`));
|
|
129
185
|
}
|
|
130
186
|
}
|
|
131
187
|
const selectedServices = await selectMcpServices(scriptLang);
|
|
@@ -135,7 +191,7 @@ async function configureMcpFeature(scriptLang) {
|
|
|
135
191
|
if (selectedServices.length > 0) {
|
|
136
192
|
const mcpBackupPath = backupMcpConfig();
|
|
137
193
|
if (mcpBackupPath) {
|
|
138
|
-
console.log(ansis.gray(`\u2714 ${i18n.mcpBackupSuccess}: ${mcpBackupPath}`));
|
|
194
|
+
console.log(ansis.gray(`\u2714 ${i18n.mcp.mcpBackupSuccess}: ${mcpBackupPath}`));
|
|
139
195
|
}
|
|
140
196
|
const newServers = {};
|
|
141
197
|
for (const serviceId of selectedServices) {
|
|
@@ -147,7 +203,7 @@ async function configureMcpFeature(scriptLang) {
|
|
|
147
203
|
type: "input",
|
|
148
204
|
name: "apiKey",
|
|
149
205
|
message: service.apiKeyPrompt[scriptLang],
|
|
150
|
-
validate: (value) => !!value || i18n.keyRequired
|
|
206
|
+
validate: (value) => !!value || i18n.api.keyRequired
|
|
151
207
|
});
|
|
152
208
|
if (apiKey) {
|
|
153
209
|
config = buildMcpServerConfig(service.config, apiKey, service.apiKeyPlaceholder, service.apiKeyEnvVar);
|
|
@@ -161,63 +217,104 @@ async function configureMcpFeature(scriptLang) {
|
|
|
161
217
|
let mergedConfig = mergeMcpServers(existingConfig, newServers);
|
|
162
218
|
mergedConfig = fixWindowsMcpConfig(mergedConfig);
|
|
163
219
|
writeMcpConfig(mergedConfig);
|
|
164
|
-
console.log(ansis.green(`\u2714 ${i18n.mcpConfigSuccess}`));
|
|
220
|
+
console.log(ansis.green(`\u2714 ${i18n.mcp.mcpConfigSuccess}`));
|
|
165
221
|
}
|
|
166
222
|
}
|
|
167
223
|
async function configureDefaultModelFeature(scriptLang) {
|
|
168
|
-
const i18n =
|
|
224
|
+
const i18n = getTranslation(scriptLang);
|
|
225
|
+
const existingModel = getExistingModelConfig();
|
|
226
|
+
if (existingModel) {
|
|
227
|
+
console.log("\n" + ansis.blue(`\u2139 ${i18n.configuration.existingModelConfig || "Existing model configuration"}`));
|
|
228
|
+
const modelDisplay = existingModel === "default" ? i18n.configuration.defaultModelOption || "Default (Let Claude Code choose)" : existingModel.charAt(0).toUpperCase() + existingModel.slice(1);
|
|
229
|
+
console.log(ansis.gray(` ${i18n.configuration.currentModel || "Current model"}: ${modelDisplay}
|
|
230
|
+
`));
|
|
231
|
+
const { modify } = await inquirer.prompt({
|
|
232
|
+
type: "confirm",
|
|
233
|
+
name: "modify",
|
|
234
|
+
message: i18n.configuration.modifyModel || "Modify model configuration?",
|
|
235
|
+
default: false
|
|
236
|
+
});
|
|
237
|
+
if (!modify) {
|
|
238
|
+
console.log(ansis.green(`\u2714 ${i18n.configuration.keepModel || "Keeping existing model configuration"}`));
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
169
242
|
const { model } = await inquirer.prompt({
|
|
170
243
|
type: "list",
|
|
171
244
|
name: "model",
|
|
172
|
-
message: i18n.selectDefaultModel || "Select default model",
|
|
173
|
-
choices: [
|
|
245
|
+
message: i18n.configuration.selectDefaultModel || "Select default model",
|
|
246
|
+
choices: addNumbersToChoices([
|
|
247
|
+
{
|
|
248
|
+
name: i18n.configuration.defaultModelOption || "Default (Let Claude Code choose)",
|
|
249
|
+
value: "default"
|
|
250
|
+
},
|
|
174
251
|
{ name: "Opus", value: "opus" },
|
|
175
252
|
{ name: "Sonnet", value: "sonnet" }
|
|
176
|
-
]
|
|
253
|
+
]),
|
|
254
|
+
default: existingModel ? ["opus", "sonnet", "default"].indexOf(existingModel) : 2
|
|
177
255
|
});
|
|
178
256
|
if (!model) {
|
|
179
257
|
handleCancellation(scriptLang);
|
|
180
258
|
return;
|
|
181
259
|
}
|
|
182
260
|
updateDefaultModel(model);
|
|
183
|
-
console.log(ansis.green(`\u2714 ${i18n.
|
|
261
|
+
console.log(ansis.green(`\u2714 ${i18n.configuration.modelConfigured || "Default model configured"}`));
|
|
184
262
|
}
|
|
185
263
|
async function configureAiMemoryFeature(scriptLang) {
|
|
186
|
-
const i18n =
|
|
264
|
+
const i18n = getTranslation(scriptLang);
|
|
187
265
|
const { option } = await inquirer.prompt({
|
|
188
266
|
type: "list",
|
|
189
267
|
name: "option",
|
|
190
|
-
message:
|
|
191
|
-
choices: [
|
|
268
|
+
message: "Select configuration option",
|
|
269
|
+
choices: addNumbersToChoices([
|
|
192
270
|
{
|
|
193
|
-
name: i18n.configureAiLanguage || "Configure AI output language",
|
|
271
|
+
name: i18n.configuration.configureAiLanguage || "Configure AI output language",
|
|
194
272
|
value: "language"
|
|
195
273
|
},
|
|
196
274
|
{
|
|
197
|
-
name: i18n.configureAiPersonality || "Configure AI personality",
|
|
275
|
+
name: i18n.configuration.configureAiPersonality || "Configure AI personality",
|
|
198
276
|
value: "personality"
|
|
199
277
|
}
|
|
200
|
-
]
|
|
278
|
+
])
|
|
201
279
|
});
|
|
202
280
|
if (!option) {
|
|
203
281
|
return;
|
|
204
282
|
}
|
|
205
283
|
if (option === "language") {
|
|
206
284
|
const zcfConfig = readZcfConfig();
|
|
207
|
-
const
|
|
285
|
+
const existingLang = zcfConfig?.aiOutputLang;
|
|
286
|
+
if (existingLang) {
|
|
287
|
+
console.log(
|
|
288
|
+
"\n" + ansis.blue(`\u2139 ${i18n.configuration.existingLanguageConfig || "Existing AI output language configuration"}`)
|
|
289
|
+
);
|
|
290
|
+
console.log(ansis.gray(` ${i18n.configuration.currentLanguage || "Current language"}: ${existingLang}
|
|
291
|
+
`));
|
|
292
|
+
const { modify } = await inquirer.prompt({
|
|
293
|
+
type: "confirm",
|
|
294
|
+
name: "modify",
|
|
295
|
+
message: i18n.configuration.modifyLanguage || "Modify AI output language?",
|
|
296
|
+
default: false
|
|
297
|
+
});
|
|
298
|
+
if (!modify) {
|
|
299
|
+
console.log(ansis.green(`\u2714 ${i18n.configuration.keepLanguage || "Keeping existing language configuration"}`));
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const { selectAiOutputLanguage } = await import('./chunks/simple-config.mjs').then(function (n) { return n.ab; });
|
|
304
|
+
const aiOutputLang = await selectAiOutputLanguage(scriptLang, scriptLang);
|
|
208
305
|
applyAiLanguageDirective(aiOutputLang);
|
|
209
306
|
updateZcfConfig({ aiOutputLang });
|
|
210
|
-
console.log(ansis.green(`\u2714 ${i18n.aiLanguageConfigured || "AI output language configured"}`));
|
|
307
|
+
console.log(ansis.green(`\u2714 ${i18n.configuration.aiLanguageConfigured || "AI output language configured"}`));
|
|
211
308
|
} else {
|
|
212
309
|
await configureAiPersonality(scriptLang);
|
|
213
310
|
}
|
|
214
311
|
}
|
|
215
312
|
async function clearZcfCacheFeature(scriptLang) {
|
|
216
|
-
const i18n =
|
|
313
|
+
const i18n = getTranslation(scriptLang);
|
|
217
314
|
const { confirm } = await inquirer.prompt({
|
|
218
315
|
type: "confirm",
|
|
219
316
|
name: "confirm",
|
|
220
|
-
message: i18n.confirmClearCache || "Clear all ZCF preferences cache?",
|
|
317
|
+
message: i18n.configuration.confirmClearCache || "Clear all ZCF preferences cache?",
|
|
221
318
|
default: false
|
|
222
319
|
});
|
|
223
320
|
if (!confirm) {
|
|
@@ -226,50 +323,59 @@ async function clearZcfCacheFeature(scriptLang) {
|
|
|
226
323
|
}
|
|
227
324
|
if (existsSync(ZCF_CONFIG_FILE)) {
|
|
228
325
|
unlinkSync(ZCF_CONFIG_FILE);
|
|
229
|
-
console.log(ansis.green(`\u2714 ${i18n.cacheCleared || "ZCF cache cleared"}`));
|
|
326
|
+
console.log(ansis.green(`\u2714 ${i18n.configuration.cacheCleared || "ZCF cache cleared"}`));
|
|
230
327
|
} else {
|
|
231
|
-
console.log(ansis.yellow(
|
|
328
|
+
console.log(ansis.yellow("No cache found"));
|
|
232
329
|
}
|
|
233
330
|
}
|
|
234
331
|
async function changeScriptLanguageFeature(currentLang) {
|
|
235
|
-
const i18n =
|
|
332
|
+
const i18n = getTranslation(currentLang);
|
|
236
333
|
const { lang } = await inquirer.prompt({
|
|
237
334
|
type: "list",
|
|
238
335
|
name: "lang",
|
|
239
|
-
message: i18n.selectScriptLang,
|
|
240
|
-
choices:
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
336
|
+
message: i18n.language.selectScriptLang,
|
|
337
|
+
choices: addNumbersToChoices(
|
|
338
|
+
SUPPORTED_LANGS.map((l) => ({
|
|
339
|
+
name: LANG_LABELS[l],
|
|
340
|
+
value: l
|
|
341
|
+
}))
|
|
342
|
+
),
|
|
244
343
|
default: SUPPORTED_LANGS.indexOf(currentLang)
|
|
245
344
|
});
|
|
246
345
|
if (!lang) {
|
|
247
346
|
return currentLang;
|
|
248
347
|
}
|
|
249
348
|
updateZcfConfig({ preferredLang: lang });
|
|
250
|
-
|
|
349
|
+
const newI18n = getTranslation(lang);
|
|
350
|
+
console.log(ansis.green(`\u2714 ${newI18n.language.languageChanged || "Language changed"}`));
|
|
251
351
|
return lang;
|
|
252
352
|
}
|
|
253
353
|
async function configureEnvPermissionFeature(scriptLang) {
|
|
254
|
-
const i18n =
|
|
354
|
+
const i18n = getTranslation(scriptLang);
|
|
255
355
|
const { choice } = await inquirer.prompt({
|
|
256
356
|
type: "list",
|
|
257
357
|
name: "choice",
|
|
258
|
-
message: i18n.selectEnvPermissionOption,
|
|
259
|
-
choices: [
|
|
358
|
+
message: i18n.configuration?.selectEnvPermissionOption || "Select option",
|
|
359
|
+
choices: addNumbersToChoices([
|
|
260
360
|
{
|
|
261
|
-
name: `${i18n.importRecommendedEnv} ${ansis.gray(
|
|
361
|
+
name: `${i18n.configuration?.importRecommendedEnv || "Import environment"} ${ansis.gray(
|
|
362
|
+
"- " + (i18n.configuration?.importRecommendedEnvDesc || "Import env settings")
|
|
363
|
+
)}`,
|
|
262
364
|
value: "env"
|
|
263
365
|
},
|
|
264
366
|
{
|
|
265
|
-
name: `${i18n.importRecommendedPermissions} ${ansis.gray(
|
|
367
|
+
name: `${i18n.configuration?.importRecommendedPermissions || "Import permissions"} ${ansis.gray(
|
|
368
|
+
"- " + (i18n.configuration?.importRecommendedPermissionsDesc || "Import permission settings")
|
|
369
|
+
)}`,
|
|
266
370
|
value: "permissions"
|
|
267
371
|
},
|
|
268
372
|
{
|
|
269
|
-
name: `${i18n.openSettingsJson} ${ansis.gray(
|
|
373
|
+
name: `${i18n.configuration?.openSettingsJson || "Open settings"} ${ansis.gray(
|
|
374
|
+
"- " + (i18n.configuration?.openSettingsJsonDesc || "View settings file")
|
|
375
|
+
)}`,
|
|
270
376
|
value: "open"
|
|
271
377
|
}
|
|
272
|
-
]
|
|
378
|
+
])
|
|
273
379
|
});
|
|
274
380
|
if (!choice) {
|
|
275
381
|
handleCancellation(scriptLang);
|
|
@@ -279,32 +385,37 @@ async function configureEnvPermissionFeature(scriptLang) {
|
|
|
279
385
|
switch (choice) {
|
|
280
386
|
case "env":
|
|
281
387
|
await importRecommendedEnv();
|
|
282
|
-
console.log(ansis.green(`\u2705 ${i18n.envImportSuccess}`));
|
|
388
|
+
console.log(ansis.green(`\u2705 ${i18n.configuration.envImportSuccess}`));
|
|
283
389
|
break;
|
|
284
390
|
case "permissions":
|
|
285
391
|
await importRecommendedPermissions();
|
|
286
|
-
console.log(ansis.green(`\u2705 ${i18n.permissionsImportSuccess}`));
|
|
392
|
+
console.log(ansis.green(`\u2705 ${i18n.configuration?.permissionsImportSuccess || "Permissions imported"}`));
|
|
287
393
|
break;
|
|
288
394
|
case "open":
|
|
289
|
-
console.log(ansis.cyan(i18n.openingSettingsJson));
|
|
395
|
+
console.log(ansis.cyan(i18n.configuration?.openingSettingsJson || "Opening settings.json..."));
|
|
290
396
|
await openSettingsJson();
|
|
291
397
|
break;
|
|
292
398
|
}
|
|
293
399
|
} catch (error) {
|
|
294
|
-
console.error(ansis.red(`${i18n.error}: ${error.message}`));
|
|
400
|
+
console.error(ansis.red(`${i18n.common.error}: ${error.message}`));
|
|
295
401
|
}
|
|
296
402
|
}
|
|
297
403
|
|
|
298
404
|
async function executeCcusage(args = []) {
|
|
299
405
|
try {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
406
|
+
let lang = "en";
|
|
407
|
+
try {
|
|
408
|
+
const zcfConfig = await readZcfConfigAsync();
|
|
409
|
+
const rawLang = zcfConfig?.preferredLang || "en";
|
|
410
|
+
lang = getValidLanguage(rawLang);
|
|
411
|
+
} catch {
|
|
412
|
+
lang = "en";
|
|
413
|
+
}
|
|
303
414
|
const i18n = I18N[lang];
|
|
304
415
|
const command = "npx";
|
|
305
|
-
const commandArgs = ["ccusage@latest", ...args];
|
|
306
|
-
console.log(ansis.cyan(i18n.runningCcusage));
|
|
307
|
-
console.log(ansis.gray(`$ npx ccusage@latest ${args.join(" ")}`));
|
|
416
|
+
const commandArgs = ["ccusage@latest", ...args || []];
|
|
417
|
+
console.log(ansis.cyan(i18n.tools.runningCcusage));
|
|
418
|
+
console.log(ansis.gray(`$ npx ccusage@latest ${(args || []).join(" ")}`));
|
|
308
419
|
console.log("");
|
|
309
420
|
await x(command, commandArgs, {
|
|
310
421
|
nodeOptions: {
|
|
@@ -312,14 +423,19 @@ async function executeCcusage(args = []) {
|
|
|
312
423
|
}
|
|
313
424
|
});
|
|
314
425
|
} catch (error) {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
426
|
+
let lang = "en";
|
|
427
|
+
try {
|
|
428
|
+
const zcfConfig = await readZcfConfigAsync();
|
|
429
|
+
const rawLang = zcfConfig?.preferredLang || "en";
|
|
430
|
+
lang = getValidLanguage(rawLang);
|
|
431
|
+
} catch {
|
|
432
|
+
lang = "en";
|
|
433
|
+
}
|
|
318
434
|
const i18n = I18N[lang];
|
|
319
|
-
console.error(ansis.red(i18n.ccusageFailed));
|
|
320
|
-
console.error(ansis.yellow(i18n.checkNetworkConnection));
|
|
435
|
+
console.error(ansis.red(i18n.tools.ccusageFailed));
|
|
436
|
+
console.error(ansis.yellow(i18n.tools.checkNetworkConnection));
|
|
321
437
|
if (process.env.DEBUG) {
|
|
322
|
-
console.error(ansis.gray(i18n.errorDetails), error);
|
|
438
|
+
console.error(ansis.gray(i18n.tools.errorDetails), error);
|
|
323
439
|
}
|
|
324
440
|
if (process.env.NODE_ENV !== "test") {
|
|
325
441
|
process.exit(1);
|
|
@@ -328,29 +444,228 @@ async function executeCcusage(args = []) {
|
|
|
328
444
|
}
|
|
329
445
|
}
|
|
330
446
|
|
|
447
|
+
const execAsync = promisify(exec);
|
|
448
|
+
async function runCcrUi(scriptLang, apiKey) {
|
|
449
|
+
const i18n = I18N[scriptLang];
|
|
450
|
+
console.log(ansis.cyan(`
|
|
451
|
+
\u{1F5A5}\uFE0F ${i18n.ccr.startingCcrUi}`));
|
|
452
|
+
if (apiKey) {
|
|
453
|
+
console.log(ansis.bold.green(`
|
|
454
|
+
\u{1F511} ${i18n.ccr.ccrUiApiKey || "CCR UI API Key"}: ${apiKey}`));
|
|
455
|
+
console.log(ansis.gray(` ${i18n.ccr.ccrUiApiKeyHint || "Use this API key to login to CCR UI"}
|
|
456
|
+
`));
|
|
457
|
+
}
|
|
458
|
+
try {
|
|
459
|
+
const { stdout, stderr } = await execAsync("ccr ui");
|
|
460
|
+
if (stdout) console.log(stdout);
|
|
461
|
+
if (stderr) console.error(ansis.yellow(stderr));
|
|
462
|
+
console.log(ansis.green(`\u2714 ${i18n.ccr.ccrUiStarted}`));
|
|
463
|
+
} catch (error) {
|
|
464
|
+
console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`));
|
|
465
|
+
throw error;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
async function runCcrStatus(scriptLang) {
|
|
469
|
+
const i18n = I18N[scriptLang];
|
|
470
|
+
console.log(ansis.cyan(`
|
|
471
|
+
\u{1F4CA} ${i18n.ccr.checkingCcrStatus}`));
|
|
472
|
+
try {
|
|
473
|
+
const { stdout, stderr } = await execAsync("ccr status");
|
|
474
|
+
if (stdout) {
|
|
475
|
+
console.log("\n" + ansis.bold(i18n.ccr.ccrStatusTitle));
|
|
476
|
+
console.log(stdout);
|
|
477
|
+
}
|
|
478
|
+
if (stderr) console.error(ansis.yellow(stderr));
|
|
479
|
+
} catch (error) {
|
|
480
|
+
console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`));
|
|
481
|
+
throw error;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
async function runCcrRestart(scriptLang) {
|
|
485
|
+
const i18n = I18N[scriptLang];
|
|
486
|
+
console.log(ansis.cyan(`
|
|
487
|
+
\u{1F504} ${i18n.ccr.restartingCcr}`));
|
|
488
|
+
try {
|
|
489
|
+
const { stdout, stderr } = await execAsync("ccr restart");
|
|
490
|
+
if (stdout) console.log(stdout);
|
|
491
|
+
if (stderr) console.error(ansis.yellow(stderr));
|
|
492
|
+
console.log(ansis.green(`\u2714 ${i18n.ccr.ccrRestarted}`));
|
|
493
|
+
} catch (error) {
|
|
494
|
+
console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`));
|
|
495
|
+
throw error;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
async function runCcrStart(scriptLang) {
|
|
499
|
+
const i18n = I18N[scriptLang];
|
|
500
|
+
console.log(ansis.cyan(`
|
|
501
|
+
\u25B6\uFE0F ${i18n.ccr.startingCcr}`));
|
|
502
|
+
try {
|
|
503
|
+
const { stdout, stderr } = await execAsync("ccr start");
|
|
504
|
+
if (stdout) console.log(stdout);
|
|
505
|
+
if (stderr) console.error(ansis.yellow(stderr));
|
|
506
|
+
console.log(ansis.green(`\u2714 ${i18n.ccr.ccrStarted}`));
|
|
507
|
+
} catch (error) {
|
|
508
|
+
console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`));
|
|
509
|
+
throw error;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
async function runCcrStop(scriptLang) {
|
|
513
|
+
const i18n = I18N[scriptLang];
|
|
514
|
+
console.log(ansis.cyan(`
|
|
515
|
+
\u23F9\uFE0F ${i18n.ccr.stoppingCcr}`));
|
|
516
|
+
try {
|
|
517
|
+
const { stdout, stderr } = await execAsync("ccr stop");
|
|
518
|
+
if (stdout) console.log(stdout);
|
|
519
|
+
if (stderr) console.error(ansis.yellow(stderr));
|
|
520
|
+
console.log(ansis.green(`\u2714 ${i18n.ccr.ccrStopped}`));
|
|
521
|
+
} catch (error) {
|
|
522
|
+
console.error(ansis.red(`\u2716 ${i18n.ccr.ccrCommandFailed}: ${error instanceof Error ? error.message : String(error)}`));
|
|
523
|
+
throw error;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
function isCcrConfigured() {
|
|
528
|
+
const CCR_CONFIG_FILE = join(homedir(), ".claude-code-router", "config.json");
|
|
529
|
+
if (!existsSync(CCR_CONFIG_FILE)) {
|
|
530
|
+
return false;
|
|
531
|
+
}
|
|
532
|
+
const config = readCcrConfig();
|
|
533
|
+
return config !== null && config.Providers && config.Providers.length > 0;
|
|
534
|
+
}
|
|
535
|
+
async function showCcrMenu(scriptLang) {
|
|
536
|
+
try {
|
|
537
|
+
const i18n = I18N[scriptLang];
|
|
538
|
+
console.log("\n" + ansis.cyan("\u2550".repeat(50)));
|
|
539
|
+
console.log(ansis.bold.cyan(` ${i18n.ccr.ccrMenuTitle}`));
|
|
540
|
+
console.log(ansis.cyan("\u2550".repeat(50)) + "\n");
|
|
541
|
+
console.log(` ${ansis.cyan("1.")} ${i18n.ccr.ccrMenuOptions.initCcr} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.initCcr)}`);
|
|
542
|
+
console.log(` ${ansis.cyan("2.")} ${i18n.ccr.ccrMenuOptions.startUi} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.startUi)}`);
|
|
543
|
+
console.log(` ${ansis.cyan("3.")} ${i18n.ccr.ccrMenuOptions.checkStatus} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.checkStatus)}`);
|
|
544
|
+
console.log(` ${ansis.cyan("4.")} ${i18n.ccr.ccrMenuOptions.restart} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.restart)}`);
|
|
545
|
+
console.log(` ${ansis.cyan("5.")} ${i18n.ccr.ccrMenuOptions.start} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.start)}`);
|
|
546
|
+
console.log(` ${ansis.cyan("6.")} ${i18n.ccr.ccrMenuOptions.stop} ${ansis.gray("- " + i18n.ccr.ccrMenuDescriptions.stop)}`);
|
|
547
|
+
console.log(` ${ansis.yellow("0.")} ${i18n.ccr.ccrMenuOptions.back}`);
|
|
548
|
+
console.log("");
|
|
549
|
+
const { choice } = await inquirer.prompt({
|
|
550
|
+
type: "input",
|
|
551
|
+
name: "choice",
|
|
552
|
+
message: i18n.common.enterChoice,
|
|
553
|
+
validate: (value) => {
|
|
554
|
+
const valid = ["1", "2", "3", "4", "5", "6", "0"];
|
|
555
|
+
return valid.includes(value) || i18n.common.invalidChoice;
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
switch (choice) {
|
|
559
|
+
case "1":
|
|
560
|
+
const ccrInstalled = await isCcrInstalled();
|
|
561
|
+
if (!ccrInstalled) {
|
|
562
|
+
console.log(ansis.yellow(`${i18n.ccr.installingCcr}`));
|
|
563
|
+
await installCcr(scriptLang);
|
|
564
|
+
} else {
|
|
565
|
+
console.log(ansis.green(`\u2714 ${i18n.ccr.ccrAlreadyInstalled}`));
|
|
566
|
+
}
|
|
567
|
+
await configureCcrFeature(scriptLang);
|
|
568
|
+
console.log(ansis.green(`
|
|
569
|
+
\u2714 ${i18n.ccr.ccrSetupComplete}`));
|
|
570
|
+
break;
|
|
571
|
+
case "2":
|
|
572
|
+
if (!isCcrConfigured()) {
|
|
573
|
+
console.log(ansis.yellow(`
|
|
574
|
+
\u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`));
|
|
575
|
+
console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."}
|
|
576
|
+
`));
|
|
577
|
+
} else {
|
|
578
|
+
const config = readCcrConfig();
|
|
579
|
+
await runCcrUi(scriptLang, config?.APIKEY);
|
|
580
|
+
}
|
|
581
|
+
break;
|
|
582
|
+
case "3":
|
|
583
|
+
if (!isCcrConfigured()) {
|
|
584
|
+
console.log(ansis.yellow(`
|
|
585
|
+
\u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`));
|
|
586
|
+
console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."}
|
|
587
|
+
`));
|
|
588
|
+
} else {
|
|
589
|
+
await runCcrStatus(scriptLang);
|
|
590
|
+
}
|
|
591
|
+
break;
|
|
592
|
+
case "4":
|
|
593
|
+
if (!isCcrConfigured()) {
|
|
594
|
+
console.log(ansis.yellow(`
|
|
595
|
+
\u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`));
|
|
596
|
+
console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."}
|
|
597
|
+
`));
|
|
598
|
+
} else {
|
|
599
|
+
await runCcrRestart(scriptLang);
|
|
600
|
+
}
|
|
601
|
+
break;
|
|
602
|
+
case "5":
|
|
603
|
+
if (!isCcrConfigured()) {
|
|
604
|
+
console.log(ansis.yellow(`
|
|
605
|
+
\u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`));
|
|
606
|
+
console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."}
|
|
607
|
+
`));
|
|
608
|
+
} else {
|
|
609
|
+
await runCcrStart(scriptLang);
|
|
610
|
+
}
|
|
611
|
+
break;
|
|
612
|
+
case "6":
|
|
613
|
+
if (!isCcrConfigured()) {
|
|
614
|
+
console.log(ansis.yellow(`
|
|
615
|
+
\u26A0\uFE0F ${i18n.ccr.ccrNotConfigured || "CCR is not configured yet. Please initialize CCR first."}`));
|
|
616
|
+
console.log(ansis.cyan(` ${i18n.ccr.pleaseInitFirst || "Please select option 1 to initialize CCR."}
|
|
617
|
+
`));
|
|
618
|
+
} else {
|
|
619
|
+
await runCcrStop(scriptLang);
|
|
620
|
+
}
|
|
621
|
+
break;
|
|
622
|
+
case "0":
|
|
623
|
+
return false;
|
|
624
|
+
}
|
|
625
|
+
if (choice !== "0") {
|
|
626
|
+
console.log("\n" + ansis.dim("\u2500".repeat(50)) + "\n");
|
|
627
|
+
const { continueInCcr } = await inquirer.prompt({
|
|
628
|
+
type: "confirm",
|
|
629
|
+
name: "continueInCcr",
|
|
630
|
+
message: i18n.common.returnToMenu || "Return to CCR menu?",
|
|
631
|
+
default: true
|
|
632
|
+
});
|
|
633
|
+
if (continueInCcr) {
|
|
634
|
+
return await showCcrMenu(scriptLang);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
return false;
|
|
638
|
+
} catch (error) {
|
|
639
|
+
if (!handleExitPromptError(error)) {
|
|
640
|
+
handleGeneralError(error, scriptLang);
|
|
641
|
+
}
|
|
642
|
+
return false;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
331
646
|
function getValidLanguage(lang) {
|
|
332
647
|
return lang && lang in I18N ? lang : "en";
|
|
333
648
|
}
|
|
334
649
|
async function runCcusageFeature(scriptLang) {
|
|
335
650
|
const validLang = getValidLanguage(scriptLang);
|
|
336
|
-
const i18n =
|
|
651
|
+
const i18n = getTranslation(validLang);
|
|
337
652
|
console.log("");
|
|
338
|
-
console.log(ansis.cyan(i18n.menuOptions.ccusage));
|
|
339
|
-
console.log(ansis.gray(`${i18n.ccusageDescription} - https://github.com/ryoppippi/ccusage`));
|
|
653
|
+
console.log(ansis.cyan(i18n.menu.menuOptions.ccusage));
|
|
654
|
+
console.log(ansis.gray(`${i18n.tools.ccusageDescription} - https://github.com/ryoppippi/ccusage`));
|
|
340
655
|
console.log("");
|
|
341
656
|
const choices = [
|
|
342
|
-
{ name: i18n.ccusageModes.daily, value: "daily" },
|
|
343
|
-
{ name: i18n.ccusageModes.monthly, value: "monthly" },
|
|
344
|
-
{ name: i18n.ccusageModes.session, value: "session" },
|
|
345
|
-
{ name: i18n.ccusageModes.blocks, value: "blocks" },
|
|
346
|
-
{ name: i18n.ccusageModes.custom, value: "custom" },
|
|
347
|
-
{ name: i18n.back, value: "back" }
|
|
657
|
+
{ name: i18n.tools.ccusageModes.daily, value: "daily" },
|
|
658
|
+
{ name: i18n.tools.ccusageModes.monthly, value: "monthly" },
|
|
659
|
+
{ name: i18n.tools.ccusageModes.session, value: "session" },
|
|
660
|
+
{ name: i18n.tools.ccusageModes.blocks, value: "blocks" },
|
|
661
|
+
{ name: i18n.tools.ccusageModes.custom, value: "custom" },
|
|
662
|
+
{ name: i18n.common.back, value: "back" }
|
|
348
663
|
];
|
|
349
664
|
const { mode } = await inquirer.prompt({
|
|
350
665
|
type: "list",
|
|
351
666
|
name: "mode",
|
|
352
|
-
message: i18n.selectAnalysisMode,
|
|
353
|
-
choices
|
|
667
|
+
message: i18n.tools.selectAnalysisMode,
|
|
668
|
+
choices: addNumbersToChoices(choices)
|
|
354
669
|
});
|
|
355
670
|
if (mode === "back") {
|
|
356
671
|
return;
|
|
@@ -360,7 +675,7 @@ async function runCcusageFeature(scriptLang) {
|
|
|
360
675
|
const { customArgs } = await inquirer.prompt({
|
|
361
676
|
type: "input",
|
|
362
677
|
name: "customArgs",
|
|
363
|
-
message: i18n.enterCustomArgs,
|
|
678
|
+
message: i18n.tools.enterCustomArgs,
|
|
364
679
|
default: ""
|
|
365
680
|
});
|
|
366
681
|
if (customArgs === null || customArgs === void 0 || customArgs === "") {
|
|
@@ -391,9 +706,13 @@ async function runCcusageFeature(scriptLang) {
|
|
|
391
706
|
await inquirer.prompt({
|
|
392
707
|
type: "input",
|
|
393
708
|
name: "continue",
|
|
394
|
-
message: ansis.gray(i18n.pressEnterToContinue)
|
|
709
|
+
message: ansis.gray(i18n.tools.pressEnterToContinue)
|
|
395
710
|
});
|
|
396
711
|
}
|
|
712
|
+
async function runCcrMenuFeature(scriptLang) {
|
|
713
|
+
const validLang = getValidLanguage(scriptLang);
|
|
714
|
+
await showCcrMenu(validLang);
|
|
715
|
+
}
|
|
397
716
|
|
|
398
717
|
async function update(options = {}) {
|
|
399
718
|
try {
|
|
@@ -408,21 +727,21 @@ async function update(options = {}) {
|
|
|
408
727
|
const { lang } = await inquirer.prompt({
|
|
409
728
|
type: "list",
|
|
410
729
|
name: "lang",
|
|
411
|
-
message: i18n.updateConfigLangPrompt,
|
|
412
|
-
choices: SUPPORTED_LANGS.map((l) => ({
|
|
413
|
-
name: `${LANG_LABELS[l]} - ${i18n.configLangHint[l]}`,
|
|
730
|
+
message: i18n.language.updateConfigLangPrompt,
|
|
731
|
+
choices: addNumbersToChoices(SUPPORTED_LANGS.map((l) => ({
|
|
732
|
+
name: `${LANG_LABELS[l]} - ${i18n.language.configLangHint[l]}`,
|
|
414
733
|
value: l
|
|
415
|
-
}))
|
|
734
|
+
})))
|
|
416
735
|
});
|
|
417
736
|
if (!lang) {
|
|
418
|
-
console.log(ansis.yellow(i18n.cancelled));
|
|
737
|
+
console.log(ansis.yellow(i18n.common.cancelled));
|
|
419
738
|
process.exit(0);
|
|
420
739
|
}
|
|
421
740
|
configLang = lang;
|
|
422
741
|
}
|
|
423
742
|
const aiOutputLang = await resolveAiOutputLanguage(scriptLang, options.aiOutputLang, zcfConfig);
|
|
424
743
|
console.log(ansis.cyan(`
|
|
425
|
-
${i18n.updatingPrompts}
|
|
744
|
+
${i18n.workflow.updatingPrompts}
|
|
426
745
|
`));
|
|
427
746
|
await updatePromptOnly(configLang, scriptLang, aiOutputLang);
|
|
428
747
|
await selectAndInstallWorkflows(configLang, scriptLang);
|
|
@@ -446,69 +765,72 @@ async function showMainMenu() {
|
|
|
446
765
|
let exitMenu = false;
|
|
447
766
|
while (!exitMenu) {
|
|
448
767
|
const i18n = I18N[scriptLang];
|
|
449
|
-
console.log(ansis.cyan(i18n.selectFunction));
|
|
768
|
+
console.log(ansis.cyan(i18n.menu.selectFunction));
|
|
450
769
|
console.log(" -------- Claude Code --------");
|
|
451
770
|
console.log(
|
|
452
|
-
` ${ansis.cyan("1.")} ${i18n.menuOptions.fullInit} ${ansis.gray("- " + i18n.menuDescriptions.fullInit)}`
|
|
771
|
+
` ${ansis.cyan("1.")} ${i18n.menu.menuOptions.fullInit} ${ansis.gray("- " + i18n.menu.menuDescriptions.fullInit)}`
|
|
453
772
|
);
|
|
454
773
|
console.log(
|
|
455
|
-
` ${ansis.cyan("2.")} ${i18n.menuOptions.importWorkflow} ${ansis.gray(
|
|
456
|
-
"- " + i18n.menuDescriptions.importWorkflow
|
|
774
|
+
` ${ansis.cyan("2.")} ${i18n.menu.menuOptions.importWorkflow} ${ansis.gray(
|
|
775
|
+
"- " + i18n.menu.menuDescriptions.importWorkflow
|
|
457
776
|
)}`
|
|
458
777
|
);
|
|
459
778
|
console.log(
|
|
460
|
-
` ${ansis.cyan("3.")} ${i18n.menuOptions.
|
|
461
|
-
"- " + i18n.menuDescriptions.
|
|
779
|
+
` ${ansis.cyan("3.")} ${i18n.menu.menuOptions.configureApiOrCcr} ${ansis.gray(
|
|
780
|
+
"- " + i18n.menu.menuDescriptions.configureApiOrCcr
|
|
462
781
|
)}`
|
|
463
782
|
);
|
|
464
783
|
console.log(
|
|
465
|
-
` ${ansis.cyan("4.")} ${i18n.menuOptions.configureMcp} ${ansis.gray(
|
|
466
|
-
"- " + i18n.menuDescriptions.configureMcp
|
|
784
|
+
` ${ansis.cyan("4.")} ${i18n.menu.menuOptions.configureMcp} ${ansis.gray(
|
|
785
|
+
"- " + i18n.menu.menuDescriptions.configureMcp
|
|
467
786
|
)}`
|
|
468
787
|
);
|
|
469
788
|
console.log(
|
|
470
|
-
` ${ansis.cyan("5.")} ${i18n.menuOptions.configureModel} ${ansis.gray(
|
|
471
|
-
"- " + i18n.menuDescriptions.configureModel
|
|
789
|
+
` ${ansis.cyan("5.")} ${i18n.menu.menuOptions.configureModel} ${ansis.gray(
|
|
790
|
+
"- " + i18n.menu.menuDescriptions.configureModel
|
|
472
791
|
)}`
|
|
473
792
|
);
|
|
474
793
|
console.log(
|
|
475
|
-
` ${ansis.cyan("6.")} ${i18n.menuOptions.configureAiMemory} ${ansis.gray(
|
|
476
|
-
"- " + i18n.menuDescriptions.configureAiMemory
|
|
794
|
+
` ${ansis.cyan("6.")} ${i18n.menu.menuOptions.configureAiMemory} ${ansis.gray(
|
|
795
|
+
"- " + i18n.menu.menuDescriptions.configureAiMemory
|
|
477
796
|
)}`
|
|
478
797
|
);
|
|
479
798
|
console.log(
|
|
480
|
-
` ${ansis.cyan("7.")} ${i18n.menuOptions.configureEnvPermission} ${ansis.gray(
|
|
481
|
-
"- " + i18n.menuDescriptions.configureEnvPermission
|
|
799
|
+
` ${ansis.cyan("7.")} ${i18n.menu.menuOptions.configureEnvPermission} ${ansis.gray(
|
|
800
|
+
"- " + i18n.menu.menuDescriptions.configureEnvPermission
|
|
482
801
|
)}`
|
|
483
802
|
);
|
|
484
803
|
console.log("");
|
|
485
|
-
console.log(` --------- ${i18n.menuSections.otherTools} ----------`);
|
|
804
|
+
console.log(` --------- ${i18n.menu.menuSections.otherTools} ----------`);
|
|
486
805
|
console.log(
|
|
487
|
-
` ${ansis.cyan("
|
|
806
|
+
` ${ansis.cyan("R.")} ${i18n.menu.menuOptions.ccrManagement} ${ansis.gray("- " + i18n.menu.menuDescriptions.ccrManagement)}`
|
|
807
|
+
);
|
|
808
|
+
console.log(
|
|
809
|
+
` ${ansis.cyan("U.")} ${i18n.menu.menuOptions.ccusage} ${ansis.gray("- " + i18n.menu.menuDescriptions.ccusage)}`
|
|
488
810
|
);
|
|
489
811
|
console.log("");
|
|
490
812
|
console.log(" ------------ ZCF ------------");
|
|
491
813
|
console.log(
|
|
492
|
-
` ${ansis.cyan("0.")} ${i18n.menuOptions.changeLanguage} ${ansis.gray(
|
|
493
|
-
"- " + i18n.menuDescriptions.changeLanguage
|
|
814
|
+
` ${ansis.cyan("0.")} ${i18n.menu.menuOptions.changeLanguage} ${ansis.gray(
|
|
815
|
+
"- " + i18n.menu.menuDescriptions.changeLanguage
|
|
494
816
|
)}`
|
|
495
817
|
);
|
|
496
818
|
console.log(
|
|
497
|
-
` ${ansis.cyan("-.")} ${i18n.menuOptions.clearCache} ${ansis.gray("- " + i18n.menuDescriptions.clearCache)}`
|
|
819
|
+
` ${ansis.cyan("-.")} ${i18n.menu.menuOptions.clearCache} ${ansis.gray("- " + i18n.menu.menuDescriptions.clearCache)}`
|
|
498
820
|
);
|
|
499
|
-
console.log(` ${ansis.red("Q.")} ${ansis.red(i18n.menuOptions.exit)}`);
|
|
821
|
+
console.log(` ${ansis.red("Q.")} ${ansis.red(i18n.menu.menuOptions.exit)}`);
|
|
500
822
|
console.log("");
|
|
501
823
|
const { choice } = await inquirer.prompt({
|
|
502
824
|
type: "input",
|
|
503
825
|
name: "choice",
|
|
504
|
-
message: i18n.enterChoice,
|
|
826
|
+
message: i18n.common.enterChoice,
|
|
505
827
|
validate: (value) => {
|
|
506
|
-
const valid = ["1", "2", "3", "4", "5", "6", "7", "u", "U", "0", "-", "q", "Q"];
|
|
507
|
-
return valid.includes(value) || i18n.invalidChoice;
|
|
828
|
+
const valid = ["1", "2", "3", "4", "5", "6", "7", "r", "R", "u", "U", "0", "-", "q", "Q"];
|
|
829
|
+
return valid.includes(value) || i18n.common.invalidChoice;
|
|
508
830
|
}
|
|
509
831
|
});
|
|
510
832
|
if (!choice) {
|
|
511
|
-
console.log(ansis.yellow(i18n.cancelled));
|
|
833
|
+
console.log(ansis.yellow(i18n.common.cancelled));
|
|
512
834
|
exitMenu = true;
|
|
513
835
|
break;
|
|
514
836
|
}
|
|
@@ -534,6 +856,10 @@ async function showMainMenu() {
|
|
|
534
856
|
case "7":
|
|
535
857
|
await configureEnvPermissionFeature(scriptLang);
|
|
536
858
|
break;
|
|
859
|
+
case "r":
|
|
860
|
+
case "R":
|
|
861
|
+
await runCcrMenuFeature(scriptLang);
|
|
862
|
+
break;
|
|
537
863
|
case "u":
|
|
538
864
|
case "U":
|
|
539
865
|
await runCcusageFeature(scriptLang);
|
|
@@ -549,11 +875,11 @@ async function showMainMenu() {
|
|
|
549
875
|
break;
|
|
550
876
|
case "q":
|
|
551
877
|
exitMenu = true;
|
|
552
|
-
console.log(ansis.cyan(i18n.goodbye));
|
|
878
|
+
console.log(ansis.cyan(i18n.common.goodbye));
|
|
553
879
|
break;
|
|
554
880
|
}
|
|
555
881
|
if (!exitMenu && choice.toLowerCase() !== "q") {
|
|
556
|
-
if (choice === "0" || choice === "-" || choice.toLowerCase() === "u") {
|
|
882
|
+
if (choice === "0" || choice === "-" || choice.toLowerCase() === "u" || choice.toLowerCase() === "r") {
|
|
557
883
|
console.log("\n" + ansis.dim("\u2500".repeat(50)) + "\n");
|
|
558
884
|
continue;
|
|
559
885
|
}
|
|
@@ -561,12 +887,12 @@ async function showMainMenu() {
|
|
|
561
887
|
const { continue: shouldContinue } = await inquirer.prompt({
|
|
562
888
|
type: "confirm",
|
|
563
889
|
name: "continue",
|
|
564
|
-
message: i18n.returnToMenu,
|
|
890
|
+
message: i18n.common.returnToMenu,
|
|
565
891
|
default: true
|
|
566
892
|
});
|
|
567
893
|
if (!shouldContinue) {
|
|
568
894
|
exitMenu = true;
|
|
569
|
-
console.log(ansis.cyan(i18n.goodbye));
|
|
895
|
+
console.log(ansis.cyan(i18n.common.goodbye));
|
|
570
896
|
}
|
|
571
897
|
}
|
|
572
898
|
}
|
|
@@ -577,6 +903,34 @@ async function showMainMenu() {
|
|
|
577
903
|
}
|
|
578
904
|
}
|
|
579
905
|
|
|
906
|
+
async function ccr(options = {}) {
|
|
907
|
+
try {
|
|
908
|
+
if (!options.skipBanner) {
|
|
909
|
+
displayBannerWithInfo();
|
|
910
|
+
}
|
|
911
|
+
const zcfConfig = await readZcfConfigAsync();
|
|
912
|
+
const scriptLang = options.lang || zcfConfig?.preferredLang || await selectScriptLanguage();
|
|
913
|
+
const continueInCcr = await showCcrMenu(scriptLang);
|
|
914
|
+
if (!continueInCcr && !options.skipBanner) {
|
|
915
|
+
await showMainMenu();
|
|
916
|
+
}
|
|
917
|
+
} catch (error) {
|
|
918
|
+
if (!handleExitPromptError(error)) {
|
|
919
|
+
handleGeneralError(error, options.lang);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
async function checkUpdates(options = {}) {
|
|
925
|
+
const scriptLang = options.lang || await selectScriptLanguage();
|
|
926
|
+
try {
|
|
927
|
+
await checkAndUpdateTools(scriptLang);
|
|
928
|
+
} catch (error) {
|
|
929
|
+
console.error(ansis.red("Error checking updates:"), error);
|
|
930
|
+
process.exit(1);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
580
934
|
function setupCommands(cli) {
|
|
581
935
|
cli.command("[lang]", "Show interactive menu (default)").option("--init", "Run full initialization directly").option("--config-lang, -c <lang>", "Configuration language (zh-CN, en)").option("--force, -f", "Force overwrite existing configuration").action(async (lang, options) => {
|
|
582
936
|
await handleDefaultCommand(lang, options);
|
|
@@ -587,9 +941,15 @@ function setupCommands(cli) {
|
|
|
587
941
|
cli.command("update", "Update Claude Code prompts only").alias("u").option("--config-lang, -c <lang>", "Configuration language (zh-CN, en)").action(async (options) => {
|
|
588
942
|
await handleUpdateCommand(options);
|
|
589
943
|
});
|
|
944
|
+
cli.command("ccr", "Configure Claude Code Router for model proxy").option("--lang, -l <lang>", "Display language (zh-CN, en)").action(async (options) => {
|
|
945
|
+
await ccr({ lang: options.lang });
|
|
946
|
+
});
|
|
590
947
|
cli.command("ccu [...args]", "Run Claude Code usage analysis tool").allowUnknownOptions().action(async (args) => {
|
|
591
948
|
await executeCcusage(args);
|
|
592
949
|
});
|
|
950
|
+
cli.command("check-updates", "Check and update Claude Code and CCR to latest versions").alias("check").option("--lang, -l <lang>", "Display language (zh-CN, en)").action(async (options) => {
|
|
951
|
+
await checkUpdates({ lang: options.lang });
|
|
952
|
+
});
|
|
593
953
|
cli.help((sections) => customizeHelp(sections));
|
|
594
954
|
cli.version(version);
|
|
595
955
|
}
|
|
@@ -628,6 +988,7 @@ function customizeHelp(sections) {
|
|
|
628
988
|
"i"
|
|
629
989
|
)} Initialize Claude Code configuration / \u521D\u59CB\u5316 Claude Code \u914D\u7F6E`,
|
|
630
990
|
` ${ansis.cyan("zcf update")} | ${ansis.cyan("u")} Update workflow-related md files / \u4EC5\u66F4\u65B0\u5DE5\u4F5C\u6D41\u76F8\u5173md`,
|
|
991
|
+
` ${ansis.cyan("zcf ccr")} Configure Claude Code Router / \u914D\u7F6E\u6A21\u578B\u4EE3\u7406`,
|
|
631
992
|
` ${ansis.cyan("zcf ccu")} [args] Run Claude Code usage analysis / \u8FD0\u884C Claude Code \u7528\u91CF\u5206\u6790`,
|
|
632
993
|
"",
|
|
633
994
|
ansis.gray(" Shortcuts / \u5FEB\u6377\u65B9\u5F0F:"),
|