@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 CHANGED
@@ -7,7 +7,7 @@
7
7
  Switch Claude Code custom model configurations from the terminal in seconds.
8
8
 
9
9
  [![npm version](https://img.shields.io/npm/v/@daylenjeez/ccm-switch.svg?style=flat-square)](https://www.npmjs.com/package/@daylenjeez/ccm-switch)
10
- [![license](https://img.shields.io/npm/l/@daylenjeez/ccm-switch.svg?style=flat-square)](https://github.com/daylenjeez/ccm-switch/blob/main/LICENSE)
10
+ [![license](https://img.shields.io/github/license/daylenjeez/ccm-switch?style=flat-square)](https://github.com/daylenjeez/ccm-switch/blob/main/LICENSE)
11
11
  [![node](https://img.shields.io/badge/node-%3E%3D18-brightgreen?style=flat-square)](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
  [![npm version](https://img.shields.io/npm/v/@daylenjeez/ccm-switch.svg?style=flat-square)](https://www.npmjs.com/package/@daylenjeez/ccm-switch)
10
- [![license](https://img.shields.io/npm/l/@daylenjeez/ccm-switch.svg?style=flat-square)](https://github.com/daylenjeez/ccm-switch/blob/main/LICENSE)
10
+ [![license](https://img.shields.io/github/license/daylenjeez/ccm-switch?style=flat-square)](https://github.com/daylenjeez/ccm-switch/blob/main/LICENSE)
11
11
  [![node](https://img.shields.io/badge/node-%3E%3D18-brightgreen?style=flat-square)](https://nodejs.org)
12
12
 
13
13
  [English](https://github.com/daylenjeez/ccm-switch/blob/main/README.md) | 中文文档
@@ -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 Chinese
15
- return "zh";
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.zh[key] ?? key;
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 <name>
395
+ // ccm use [name]
391
396
  program
392
- .command("use <name>")
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 input = await ask(step.prompt);
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
- if (step.required && !input) {
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 (input)
534
- values[step.key] = input;
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
- const hint = cur ? chalk.gray(` [${cur}]`) : "";
682
- const input = await ask(`${step.prompt}${hint}: `);
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.0",
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 Chinese
19
- return "zh";
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.zh[key] ?? key;
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 <name>
438
+ // ccm use [name]
434
439
  program
435
- .command("use <name>")
440
+ .command("use [name]")
436
441
  .description(t("use.description"))
437
- .action(async (name: string) => {
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
- interface Step { key: string; prompt: string; required: boolean; }
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 input = await ask(step.prompt);
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
- if (step.required && !input) {
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 (input) values[step.key] = input;
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
- const hint = cur ? chalk.gray(` [${cur}]`) : "";
756
- const input = await ask(`${step.prompt}${hint}: `);
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--;