@daylenjeez/ccm-switch 1.3.0 → 1.3.2
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/i18n/index.js +3 -3
- package/dist/index.js +41 -13
- package/package.json +1 -2
- package/src/i18n/index.ts +3 -3
- package/src/index.ts +46 -14
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
Switch Claude Code custom model configurations from the terminal in seconds.
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/@daylenjeez/ccm-switch)
|
|
10
|
-
[](https://github.com/daylenjeez/ccm-switch/blob/main/LICENSE)
|
|
11
11
|
[](https://nodejs.org)
|
|
12
12
|
|
|
13
13
|
[中文文档](https://github.com/daylenjeez/ccm-switch/blob/main/README.zh-CN.md) | English
|
package/README.zh-CN.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
在终端几秒内完成 Claude Code 自定义模型配置的管理和切换。
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/@daylenjeez/ccm-switch)
|
|
10
|
-
[](https://github.com/daylenjeez/ccm-switch/blob/main/LICENSE)
|
|
11
11
|
[](https://nodejs.org)
|
|
12
12
|
|
|
13
13
|
[English](https://github.com/daylenjeez/ccm-switch/blob/main/README.md) | 中文文档
|
package/dist/i18n/index.js
CHANGED
|
@@ -11,8 +11,8 @@ function detectLocale() {
|
|
|
11
11
|
const lang = process.env.LC_ALL || process.env.LANG || "";
|
|
12
12
|
if (lang.startsWith("en"))
|
|
13
13
|
return "en";
|
|
14
|
-
// 3. Default to
|
|
15
|
-
return "
|
|
14
|
+
// 3. Default to English
|
|
15
|
+
return "en";
|
|
16
16
|
}
|
|
17
17
|
let currentLocale;
|
|
18
18
|
function getLocale() {
|
|
@@ -25,7 +25,7 @@ export function setLocale(locale) {
|
|
|
25
25
|
}
|
|
26
26
|
export function t(key, vars) {
|
|
27
27
|
const locale = getLocale();
|
|
28
|
-
let text = locales[locale][key] ?? locales.
|
|
28
|
+
let text = locales[locale][key] ?? locales.en[key] ?? key;
|
|
29
29
|
if (vars) {
|
|
30
30
|
for (const [k, v] of Object.entries(vars)) {
|
|
31
31
|
text = text.replace(new RegExp(`\\{${k}\\}`, "g"), v);
|
package/dist/index.js
CHANGED
|
@@ -20,14 +20,19 @@ program
|
|
|
20
20
|
.name("ccm")
|
|
21
21
|
.description(t("program.description"))
|
|
22
22
|
.version(packageJson.version);
|
|
23
|
-
// Helper: prompt user for input
|
|
24
|
-
function ask(question) {
|
|
23
|
+
// Helper: prompt user for input, optionally pre-filling the input field
|
|
24
|
+
function ask(question, prefill) {
|
|
25
25
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
26
26
|
return new Promise((resolve) => {
|
|
27
27
|
rl.question(question, (answer) => {
|
|
28
28
|
rl.close();
|
|
29
29
|
resolve(answer.trim());
|
|
30
30
|
});
|
|
31
|
+
if (prefill) {
|
|
32
|
+
rl.line = prefill;
|
|
33
|
+
rl.cursor = prefill.length;
|
|
34
|
+
rl._refreshLine();
|
|
35
|
+
}
|
|
31
36
|
});
|
|
32
37
|
}
|
|
33
38
|
// Helper: ensure store ready
|
|
@@ -387,12 +392,17 @@ program
|
|
|
387
392
|
}
|
|
388
393
|
console.log();
|
|
389
394
|
});
|
|
390
|
-
// ccm use
|
|
395
|
+
// ccm use [name]
|
|
391
396
|
program
|
|
392
|
-
.command("use
|
|
397
|
+
.command("use [name]")
|
|
393
398
|
.description(t("use.description"))
|
|
394
399
|
.action(async (name) => {
|
|
395
400
|
const store = ensureStore();
|
|
401
|
+
if (!name) {
|
|
402
|
+
// No argument: behave like `ls`
|
|
403
|
+
await program.commands.find((c) => c.name() === "list").parseAsync([]);
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
396
406
|
const profile = await resolveProfile(store, name);
|
|
397
407
|
if (!profile)
|
|
398
408
|
return;
|
|
@@ -461,6 +471,17 @@ async function saveAndSwitch(store, name, settingsConfig) {
|
|
|
461
471
|
console.log(chalk.gray(` ${t("use.restart")}`));
|
|
462
472
|
}
|
|
463
473
|
}
|
|
474
|
+
const BUILTIN_BASE_URLS = {
|
|
475
|
+
kimi: "https://api.moonshot.cn/v1",
|
|
476
|
+
"kimi-coding": "https://api.kimi.com/coding/",
|
|
477
|
+
openrouter: "https://openrouter.ai/api/v1",
|
|
478
|
+
deepseek: "https://api.deepseek.com",
|
|
479
|
+
zenmux: "https://zenmux.ai/api/anthropic",
|
|
480
|
+
fusecode: "https://www.fusecode.cc",
|
|
481
|
+
};
|
|
482
|
+
function getKnownBaseUrl(name) {
|
|
483
|
+
return BUILTIN_BASE_URLS[name.toLowerCase()];
|
|
484
|
+
}
|
|
464
485
|
// ccm add
|
|
465
486
|
program
|
|
466
487
|
.command("add")
|
|
@@ -492,7 +513,7 @@ program
|
|
|
492
513
|
// JSON mode: open editor with template
|
|
493
514
|
const template = {
|
|
494
515
|
env: {
|
|
495
|
-
ANTHROPIC_BASE_URL: "",
|
|
516
|
+
ANTHROPIC_BASE_URL: getKnownBaseUrl(name) ?? "",
|
|
496
517
|
ANTHROPIC_AUTH_TOKEN: "",
|
|
497
518
|
ANTHROPIC_MODEL: "",
|
|
498
519
|
ANTHROPIC_DEFAULT_OPUS_MODEL: "",
|
|
@@ -507,8 +528,10 @@ program
|
|
|
507
528
|
await saveAndSwitch(store, name, edited);
|
|
508
529
|
return;
|
|
509
530
|
}
|
|
531
|
+
// Interactive mode with step-based back support
|
|
532
|
+
const defaultBaseUrl = getKnownBaseUrl(name);
|
|
510
533
|
const steps = [
|
|
511
|
-
{ key: "ANTHROPIC_BASE_URL", prompt: t("add.prompt_base_url"), required: true },
|
|
534
|
+
{ key: "ANTHROPIC_BASE_URL", prompt: t("add.prompt_base_url"), required: true, defaultValue: defaultBaseUrl },
|
|
512
535
|
{ key: "ANTHROPIC_AUTH_TOKEN", prompt: t("add.prompt_auth_token"), required: true },
|
|
513
536
|
{ key: "ANTHROPIC_MODEL", prompt: t("add.prompt_model"), required: false },
|
|
514
537
|
{ key: "ANTHROPIC_DEFAULT_OPUS_MODEL", prompt: t("add.prompt_default_opus"), required: false },
|
|
@@ -520,18 +543,22 @@ program
|
|
|
520
543
|
let i = 0;
|
|
521
544
|
while (i < steps.length) {
|
|
522
545
|
const step = steps[i];
|
|
523
|
-
const
|
|
546
|
+
const promptText = step.defaultValue
|
|
547
|
+
? `${step.prompt}(${chalk.gray(step.defaultValue)}): `
|
|
548
|
+
: step.prompt;
|
|
549
|
+
const input = await ask(promptText, step.defaultValue);
|
|
524
550
|
if (input === "<") {
|
|
525
551
|
if (i > 0)
|
|
526
552
|
i--;
|
|
527
553
|
continue;
|
|
528
554
|
}
|
|
529
|
-
|
|
555
|
+
const value = input || step.defaultValue || "";
|
|
556
|
+
if (step.required && !value) {
|
|
530
557
|
console.log(chalk.red(t("add.field_required", { field: step.key })));
|
|
531
558
|
continue;
|
|
532
559
|
}
|
|
533
|
-
if (
|
|
534
|
-
values[step.key] =
|
|
560
|
+
if (value)
|
|
561
|
+
values[step.key] = value;
|
|
535
562
|
else
|
|
536
563
|
delete values[step.key];
|
|
537
564
|
i++;
|
|
@@ -677,9 +704,10 @@ program
|
|
|
677
704
|
let i = 0;
|
|
678
705
|
while (i < steps.length) {
|
|
679
706
|
const step = steps[i];
|
|
680
|
-
const cur = currentEnv[step.key]
|
|
681
|
-
|
|
682
|
-
const
|
|
707
|
+
const cur = currentEnv[step.key]
|
|
708
|
+
|| (step.key === "ANTHROPIC_BASE_URL" ? (getKnownBaseUrl(profile.name) ?? "") : "");
|
|
709
|
+
const hint = cur ? `(${chalk.gray(cur)})` : "";
|
|
710
|
+
const input = await ask(`${step.prompt}${hint}: `, cur || undefined);
|
|
683
711
|
if (input === "<") {
|
|
684
712
|
if (i > 0)
|
|
685
713
|
i--;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@daylenjeez/ccm-switch",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.2",
|
|
4
4
|
"description": "Claude Code Model Switcher - 快速切换 Claude Code 自定义模型配置",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@clack/prompts": "^1.2.0",
|
|
27
|
-
"@daylenjeez/ccm-switch": "^1.2.9",
|
|
28
27
|
"better-sqlite3": "^12.8.0",
|
|
29
28
|
"chalk": "^5.6.2",
|
|
30
29
|
"commander": "^14.0.3"
|
package/src/i18n/index.ts
CHANGED
|
@@ -15,8 +15,8 @@ function detectLocale(): Locale {
|
|
|
15
15
|
const lang = process.env.LC_ALL || process.env.LANG || "";
|
|
16
16
|
if (lang.startsWith("en")) return "en";
|
|
17
17
|
|
|
18
|
-
// 3. Default to
|
|
19
|
-
return "
|
|
18
|
+
// 3. Default to English
|
|
19
|
+
return "en";
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
let currentLocale: Locale | undefined;
|
|
@@ -32,7 +32,7 @@ export function setLocale(locale: Locale): void {
|
|
|
32
32
|
|
|
33
33
|
export function t(key: TranslationKey, vars?: Record<string, string>): string {
|
|
34
34
|
const locale = getLocale();
|
|
35
|
-
let text = locales[locale][key] ?? locales.
|
|
35
|
+
let text = locales[locale][key] ?? locales.en[key] ?? key;
|
|
36
36
|
if (vars) {
|
|
37
37
|
for (const [k, v] of Object.entries(vars)) {
|
|
38
38
|
text = text.replace(new RegExp(`\\{${k}\\}`, "g"), v);
|
package/src/index.ts
CHANGED
|
@@ -25,14 +25,19 @@ program
|
|
|
25
25
|
.description(t("program.description"))
|
|
26
26
|
.version(packageJson.version);
|
|
27
27
|
|
|
28
|
-
// Helper: prompt user for input
|
|
29
|
-
function ask(question: string): Promise<string> {
|
|
28
|
+
// Helper: prompt user for input, optionally pre-filling the input field
|
|
29
|
+
function ask(question: string, prefill?: string): Promise<string> {
|
|
30
30
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
31
31
|
return new Promise((resolve) => {
|
|
32
32
|
rl.question(question, (answer) => {
|
|
33
33
|
rl.close();
|
|
34
34
|
resolve(answer.trim());
|
|
35
35
|
});
|
|
36
|
+
if (prefill) {
|
|
37
|
+
(rl as any).line = prefill;
|
|
38
|
+
(rl as any).cursor = prefill.length;
|
|
39
|
+
(rl as any)._refreshLine();
|
|
40
|
+
}
|
|
36
41
|
});
|
|
37
42
|
}
|
|
38
43
|
|
|
@@ -430,12 +435,19 @@ program
|
|
|
430
435
|
console.log();
|
|
431
436
|
});
|
|
432
437
|
|
|
433
|
-
// ccm use
|
|
438
|
+
// ccm use [name]
|
|
434
439
|
program
|
|
435
|
-
.command("use
|
|
440
|
+
.command("use [name]")
|
|
436
441
|
.description(t("use.description"))
|
|
437
|
-
.action(async (name
|
|
442
|
+
.action(async (name?: string) => {
|
|
438
443
|
const store = ensureStore();
|
|
444
|
+
|
|
445
|
+
if (!name) {
|
|
446
|
+
// No argument: behave like `ls`
|
|
447
|
+
await program.commands.find((c) => c.name() === "list")!.parseAsync([]);
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
|
|
439
451
|
const profile = await resolveProfile(store, name);
|
|
440
452
|
if (!profile) return;
|
|
441
453
|
|
|
@@ -509,6 +521,19 @@ async function saveAndSwitch(store: ReturnType<typeof ensureStore>, name: string
|
|
|
509
521
|
}
|
|
510
522
|
}
|
|
511
523
|
|
|
524
|
+
const BUILTIN_BASE_URLS: Record<string, string> = {
|
|
525
|
+
kimi: "https://api.moonshot.cn/v1",
|
|
526
|
+
"kimi-coding": "https://api.kimi.com/coding/",
|
|
527
|
+
openrouter: "https://openrouter.ai/api/v1",
|
|
528
|
+
deepseek: "https://api.deepseek.com",
|
|
529
|
+
zenmux: "https://zenmux.ai/api/anthropic",
|
|
530
|
+
fusecode: "https://www.fusecode.cc",
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
function getKnownBaseUrl(name: string): string | undefined {
|
|
534
|
+
return BUILTIN_BASE_URLS[name.toLowerCase()];
|
|
535
|
+
}
|
|
536
|
+
|
|
512
537
|
// ccm add
|
|
513
538
|
program
|
|
514
539
|
.command("add")
|
|
@@ -544,7 +569,7 @@ program
|
|
|
544
569
|
// JSON mode: open editor with template
|
|
545
570
|
const template: Record<string, unknown> = {
|
|
546
571
|
env: {
|
|
547
|
-
ANTHROPIC_BASE_URL: "",
|
|
572
|
+
ANTHROPIC_BASE_URL: getKnownBaseUrl(name) ?? "",
|
|
548
573
|
ANTHROPIC_AUTH_TOKEN: "",
|
|
549
574
|
ANTHROPIC_MODEL: "",
|
|
550
575
|
ANTHROPIC_DEFAULT_OPUS_MODEL: "",
|
|
@@ -562,9 +587,10 @@ program
|
|
|
562
587
|
}
|
|
563
588
|
|
|
564
589
|
// Interactive mode with step-based back support
|
|
565
|
-
|
|
590
|
+
const defaultBaseUrl = getKnownBaseUrl(name);
|
|
591
|
+
interface Step { key: string; prompt: string; required: boolean; defaultValue?: string; }
|
|
566
592
|
const steps: Step[] = [
|
|
567
|
-
{ key: "ANTHROPIC_BASE_URL", prompt: t("add.prompt_base_url"), required: true },
|
|
593
|
+
{ key: "ANTHROPIC_BASE_URL", prompt: t("add.prompt_base_url"), required: true, defaultValue: defaultBaseUrl },
|
|
568
594
|
{ key: "ANTHROPIC_AUTH_TOKEN", prompt: t("add.prompt_auth_token"), required: true },
|
|
569
595
|
{ key: "ANTHROPIC_MODEL", prompt: t("add.prompt_model"), required: false },
|
|
570
596
|
{ key: "ANTHROPIC_DEFAULT_OPUS_MODEL", prompt: t("add.prompt_default_opus"), required: false },
|
|
@@ -577,19 +603,24 @@ program
|
|
|
577
603
|
let i = 0;
|
|
578
604
|
while (i < steps.length) {
|
|
579
605
|
const step = steps[i];
|
|
580
|
-
const
|
|
606
|
+
const promptText = step.defaultValue
|
|
607
|
+
? `${step.prompt}(${chalk.gray(step.defaultValue)}): `
|
|
608
|
+
: step.prompt;
|
|
609
|
+
const input = await ask(promptText, step.defaultValue);
|
|
581
610
|
|
|
582
611
|
if (input === "<") {
|
|
583
612
|
if (i > 0) i--;
|
|
584
613
|
continue;
|
|
585
614
|
}
|
|
586
615
|
|
|
587
|
-
|
|
616
|
+
const value = input || step.defaultValue || "";
|
|
617
|
+
|
|
618
|
+
if (step.required && !value) {
|
|
588
619
|
console.log(chalk.red(t("add.field_required", { field: step.key })));
|
|
589
620
|
continue;
|
|
590
621
|
}
|
|
591
622
|
|
|
592
|
-
if (
|
|
623
|
+
if (value) values[step.key] = value;
|
|
593
624
|
else delete values[step.key];
|
|
594
625
|
i++;
|
|
595
626
|
}
|
|
@@ -751,9 +782,10 @@ program
|
|
|
751
782
|
let i = 0;
|
|
752
783
|
while (i < steps.length) {
|
|
753
784
|
const step = steps[i];
|
|
754
|
-
const cur = currentEnv[step.key]
|
|
755
|
-
|
|
756
|
-
const
|
|
785
|
+
const cur = currentEnv[step.key]
|
|
786
|
+
|| (step.key === "ANTHROPIC_BASE_URL" ? (getKnownBaseUrl(profile.name) ?? "") : "");
|
|
787
|
+
const hint = cur ? `(${chalk.gray(cur)})` : "";
|
|
788
|
+
const input = await ask(`${step.prompt}${hint}: `, cur || undefined);
|
|
757
789
|
|
|
758
790
|
if (input === "<") {
|
|
759
791
|
if (i > 0) i--;
|