cc-cast 1.3.7 → 1.3.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-cast",
3
- "version": "1.3.7",
3
+ "version": "1.3.9",
4
4
  "description": "Claude Code Model Switcher - 快速切换 Claude Code 自定义模型配置",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -9,8 +9,8 @@
9
9
  "ccc": "dist/index.js"
10
10
  },
11
11
  "scripts": {
12
- "build": "tsc",
13
- "dev": "tsc --watch"
12
+ "build": "tsup src/index.ts --format esm --target node18 --minify --clean --out-dir dist --splitting false --external better-sqlite3 chalk commander enquirer update-notifier && tsc --emitDeclarationOnly",
13
+ "dev": "tsup src/index.ts --format esm --target node18 --minify --clean --out-dir dist --splitting false --external better-sqlite3 chalk commander enquirer update-notifier --watch"
14
14
  },
15
15
  "keywords": [
16
16
  "claude",
@@ -27,11 +27,14 @@
27
27
  "better-sqlite3": "^12.8.0",
28
28
  "chalk": "^5.6.2",
29
29
  "commander": "^14.0.3",
30
- "enquirer": "^2.4.1"
30
+ "enquirer": "^2.4.1",
31
+ "update-notifier": "^7.3.1"
31
32
  },
32
33
  "devDependencies": {
33
34
  "@types/better-sqlite3": "^7.6.13",
34
35
  "@types/node": "^25.5.2",
36
+ "@types/update-notifier": "^6.0.8",
37
+ "tsup": "^8.5.1",
35
38
  "typescript": "^6.0.2"
36
39
  }
37
40
  }
package/src/index.ts CHANGED
@@ -13,6 +13,7 @@ import { join, dirname } from "path";
13
13
  import { fileURLToPath } from "url";
14
14
  import { t, setLocale, getLocale } from "./i18n/index.js";
15
15
  import Enquirer from "enquirer";
16
+ import updateNotifier from "update-notifier";
16
17
  const Select = (Enquirer as any).Select;
17
18
 
18
19
  function createSelect(options: any) {
@@ -45,6 +46,9 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
45
46
  const packageJsonPath = join(__dirname, "..", "package.json");
46
47
  const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
47
48
 
49
+ const notifier = updateNotifier({ pkg: packageJson, updateCheckInterval: 1000 * 60 * 60 * 24 });
50
+ notifier.notify({ isGlobal: true, defer: true });
51
+
48
52
  const program = new Command();
49
53
 
50
54
  program
package/dist/claude.js DELETED
@@ -1,27 +0,0 @@
1
- import { homedir } from "os";
2
- import { join } from "path";
3
- import { existsSync, readFileSync, writeFileSync } from "fs";
4
- const SETTINGS_PATH = join(homedir(), ".claude", "settings.json");
5
- export function readClaudeSettings() {
6
- if (!existsSync(SETTINGS_PATH))
7
- return {};
8
- return JSON.parse(readFileSync(SETTINGS_PATH, "utf-8"));
9
- }
10
- export function applyProfile(_name, settingsConfig) {
11
- const current = readClaudeSettings();
12
- // 保留用户级字段,用 profile 的配置覆盖
13
- const preserved = {};
14
- const USER_FIELDS = ["language", "permissions"];
15
- for (const key of USER_FIELDS) {
16
- if (key in current) {
17
- preserved[key] = current[key];
18
- }
19
- }
20
- // Merge instead of replace: keep any top-level keys from the existing file
21
- // that the profile does not explicitly set (e.g. common snippets from cc-switch)
22
- const merged = { ...current, ...preserved, ...settingsConfig };
23
- writeFileSync(SETTINGS_PATH, JSON.stringify(merged, null, 2));
24
- }
25
- export function getSettingsPath() {
26
- return SETTINGS_PATH;
27
- }
package/dist/i18n/en.js DELETED
@@ -1,139 +0,0 @@
1
- const en = {
2
- // program
3
- "program.description": "Claude Code Model Switcher - Quickly switch Claude Code custom model configurations",
4
- // common
5
- "common.not_init": "Not initialized yet. Run: cc-cast init",
6
- "common.model": "Model",
7
- "common.model_default": "default",
8
- "common.source": "Source",
9
- "common.cancelled": "cancelled",
10
- // error
11
- "error.not_found": 'Configuration "{name}" not found',
12
- "error.alias_target_missing": 'Alias "{alias}" points to "{target}", but it does not exist',
13
- "error.invalid_choice": "Invalid choice",
14
- // suggest
15
- "suggest.did_you_mean": "Did you mean: {name}?",
16
- "suggest.did_you_mean_header": "Did you mean:",
17
- "suggest.use_list": "Use cc-cast list to see all available configurations",
18
- // init
19
- "init.description": "Initialize cc-cast",
20
- "init.cc_switch_found": "cc-switch detected. Import configurations from it? (Y/n) ",
21
- "init.cc_switch_mode": "✓ cc-switch detected — cc-cast will use cc-switch's configuration store directly",
22
- "init.cc_switch_migrate": "Standalone cc-cast configurations found. Migrate them to cc-switch? (Y/n) ",
23
- "init.cc_switch_migrate_done": "✓ Migrated {count} configurations to cc-switch",
24
- "init.done": "✓ Initialized",
25
- // list
26
- "list.description": "List and select configurations",
27
- "list.empty": "No configurations yet. Use cc-cast save <name> to save current config",
28
- "list.header": "Available configurations:",
29
- "list.select": "Select configuration:",
30
- "list.current_marker": "(current)",
31
- "list.choose_number": "Enter number to switch (Enter to skip): ",
32
- // current
33
- "current.description": "Show the currently active configuration",
34
- "current.none": "No active configuration",
35
- "current.settings_header": "Current settings.json:",
36
- "current.not_exist": 'Current configuration "{name}" no longer exists',
37
- "current.header": "Current configuration: {name}",
38
- // use
39
- "use.description": "Switch to a specified configuration",
40
- "use.done": "✓ Switched to {name}",
41
- "use.restart": "Restart Claude Code to apply",
42
- "use.cc_switch_running": "cc-switch GUI is running. To avoid config conflicts, only the active marker was updated. Please switch manually in cc-switch GUI, or quit GUI and try again.",
43
- // save
44
- "save.description": "Save current settings.json as a new configuration",
45
- "save.overwrite": 'Configuration "{name}" already exists, will overwrite',
46
- "save.done": '✓ Saved current configuration as "{name}"',
47
- // show
48
- "show.description": "View configuration details (defaults to current)",
49
- "show.no_current": "No active configuration. Specify a name: cc-cast show <name>",
50
- "show.all_header": "All configurations:",
51
- // remove
52
- "remove.description": "Delete a configuration",
53
- "remove.select": "Select configuration to delete:",
54
- "remove.confirm": 'Delete "{name}"? (y/N) ',
55
- "remove.done": '✓ Deleted "{name}"',
56
- // alias
57
- "alias.description": "Manage aliases",
58
- "alias.set_description": "Set alias, e.g.: cc-cast alias set or openrouter-opus4.6",
59
- "alias.set_done": "✓ Alias set: {short} → {name}",
60
- "alias.rm_description": "Remove an alias",
61
- "alias.rm_not_found": 'Alias "{short}" not found',
62
- "alias.rm_done": '✓ Removed alias "{short}"',
63
- "alias.list_description": "List all aliases",
64
- "alias.list_empty": "No aliases yet. Use cc-cast alias set <short> <name> to add one",
65
- "alias.list_header": "Aliases:",
66
- // locale
67
- "locale.description": "Manage interface language",
68
- "locale.current": "Current language: {locale}",
69
- "locale.set_description": "Set language (zh/en)",
70
- "locale.set_done": "✓ Language set to {locale}",
71
- "locale.set_invalid": "Unsupported language: {locale}. Available: zh, en",
72
- "locale.list_description": "List and select language",
73
- "locale.list_header": "Supported languages:",
74
- "locale.list_current_marker": "(current)",
75
- "locale.select": "Select language:",
76
- "locale.choose_number": "Enter number to switch (Enter to skip): ",
77
- // add
78
- "add.description": "Interactively add a new configuration",
79
- "add.prompt_name": "Provider name (e.g. OpenRouter): ",
80
- "add.prompt_base_url": "ANTHROPIC_BASE_URL: ",
81
- "add.prompt_auth_token": "ANTHROPIC_AUTH_TOKEN: ",
82
- "add.prompt_model": "ANTHROPIC_MODEL: ",
83
- "add.prompt_default_opus": "ANTHROPIC_DEFAULT_OPUS_MODEL (press Enter to skip): ",
84
- "add.prompt_default_sonnet": "ANTHROPIC_DEFAULT_SONNET_MODEL (press Enter to skip): ",
85
- "add.prompt_default_haiku": "ANTHROPIC_DEFAULT_HAIKU_MODEL (press Enter to skip): ",
86
- "add.mode_select": "Choose how to add:",
87
- "add.mode_interactive": "Step by step",
88
- "add.mode_json": "Write JSON directly",
89
- "add.mode_choose": "Choose (1/2): ",
90
- "add.json_template_hint": "Fill in the configuration in editor, save and exit",
91
- "add.json_parse_error": "JSON parse error, please check format",
92
- "add.back_hint": "Type < to go back",
93
- "add.name_required": "Provider name cannot be empty",
94
- "add.field_required": "{field} cannot be empty",
95
- "add.already_exists": 'Configuration "{name}" already exists. Overwrite? (y/N) ',
96
- "add.edit_confirm": "Edit configuration in editor? (y/N) ",
97
- "add.preview_header": "Configuration preview:",
98
- "add.done": '✓ Saved configuration "{name}"',
99
- "add.switch_confirm": "Switch to this configuration now? (Y/n) ",
100
- "add.cancelled": "Cancelled",
101
- // modify
102
- "modify.description": "Modify an existing configuration",
103
- "modify.select": "Select configuration to modify:",
104
- "modify.done": '✓ Updated configuration "{name}"',
105
- "modify.no_change": "No changes made",
106
- // alias conflict
107
- "alias.is_alias": '"{name}" is an alias for "{target}"',
108
- "alias.conflict": '"{name}" is both an alias (→ {target}) and a config name. Which one?',
109
- "alias.conflict_alias": "Alias (→ {target})",
110
- "alias.conflict_config": "Config {name}",
111
- "alias.choose_conflict": "Choose (1/2): ",
112
- "alias.rm_which": "Which one to delete?",
113
- "alias.rm_alias": "Alias {name}",
114
- "alias.rm_config": "Config {target}",
115
- "alias.rm_choose": "Choose (1/2): ",
116
- // sync
117
- "sync.description": "Sync configurations from cc-switch",
118
- "sync.no_cc_switch": "cc-switch database not detected",
119
- "sync.empty": "No Claude configurations found in cc-switch",
120
- "sync.done": "✓ Synced {count} configurations",
121
- "sync.current": "Active: {name}",
122
- "sync.no_current": "No active configuration",
123
- // clear
124
- "clear.description": "Clean up cc-cast data files",
125
- "clear.confirm": "Delete all cc-cast data files? (y/N) ",
126
- "clear.cancelled": "Cancelled",
127
- "clear.removed": "✓ Deleted {path}",
128
- "clear.done": "✓ Cleanup complete",
129
- // import
130
- "import.description": "Import configurations from JSON (file or stdin)",
131
- "import.paste_hint": "Paste JSON and press Ctrl+D (or Ctrl+Z on Windows) to finish:",
132
- "import.file_not_found": 'File not found: {file}',
133
- "import.json_parse_error": "Invalid JSON format",
134
- "import.invalid_format": "Invalid format: expected object with configuration names as keys",
135
- "import.done": "✓ Imported {count} configurations",
136
- // store errors
137
- "store.db_not_found": "cc-switch database not found: {path}",
138
- };
139
- export default en;
@@ -1,36 +0,0 @@
1
- import zh from "./zh.js";
2
- import en from "./en.js";
3
- import { readRc } from "../utils.js";
4
- const locales = { zh, en };
5
- function detectLocale() {
6
- // 1. rc.json locale setting takes priority
7
- const rc = readRc();
8
- if (rc?.locale && rc.locale in locales)
9
- return rc.locale;
10
- // 2. Fallback to system LANG/LC_ALL
11
- const lang = process.env.LC_ALL || process.env.LANG || "";
12
- if (lang.startsWith("en"))
13
- return "en";
14
- // 3. Default to English
15
- return "en";
16
- }
17
- let currentLocale;
18
- function getLocale() {
19
- if (!currentLocale)
20
- currentLocale = detectLocale();
21
- return currentLocale;
22
- }
23
- export function setLocale(locale) {
24
- currentLocale = locale;
25
- }
26
- export function t(key, vars) {
27
- const locale = getLocale();
28
- let text = locales[locale][key] ?? locales.en[key] ?? key;
29
- if (vars) {
30
- for (const [k, v] of Object.entries(vars)) {
31
- text = text.replace(new RegExp(`\\{${k}\\}`, "g"), v);
32
- }
33
- }
34
- return text;
35
- }
36
- export { getLocale };
package/dist/i18n/zh.js DELETED
@@ -1,139 +0,0 @@
1
- const zh = {
2
- // program
3
- "program.description": "Claude Code Model Switcher - 快速切换 Claude Code 自定义模型配置",
4
- // common
5
- "common.not_init": "尚未初始化,请先运行: cc-cast init",
6
- "common.model": "模型",
7
- "common.model_default": "默认",
8
- "common.source": "来源",
9
- "common.cancelled": "已取消",
10
- // error
11
- "error.not_found": '配置 "{name}" 不存在',
12
- "error.alias_target_missing": '别名 "{alias}" 指向 "{target}",但该配置不存在',
13
- "error.invalid_choice": "无效选择",
14
- // suggest
15
- "suggest.did_you_mean": "你是不是想说: {name}?",
16
- "suggest.did_you_mean_header": "你是不是想说:",
17
- "suggest.use_list": "使用 cc-cast list 查看所有可用配置",
18
- // init
19
- "init.description": "初始化 cc-cast",
20
- "init.cc_switch_found": "检测到 cc-switch 已安装,是否从中导入配置?(Y/n) ",
21
- "init.cc_switch_mode": "✓ 检测到 cc-switch,cc-cast 将直接使用 cc-switch 配置库",
22
- "init.cc_switch_migrate": "发现 cc-cast 独立配置,是否将其迁移至 cc-switch?(Y/n) ",
23
- "init.cc_switch_migrate_done": "✓ 已迁移 {count} 个配置至 cc-switch",
24
- "init.done": "✓ 初始化完成",
25
- // list
26
- "list.description": "列出并选择配置方案",
27
- "list.empty": "暂无配置方案。使用 cc-cast save <name> 保存当前配置",
28
- "list.header": "可用配置:",
29
- "list.select": "选择配置:",
30
- "list.current_marker": "(当前)",
31
- "list.choose_number": "输入序号切换 (回车跳过): ",
32
- // current
33
- "current.description": "显示当前生效的配置",
34
- "current.none": "当前无激活配置",
35
- "current.settings_header": "当前 settings.json:",
36
- "current.not_exist": '当前配置 "{name}" 已不存在',
37
- "current.header": "当前配置: {name}",
38
- // use
39
- "use.description": "切换到指定配置方案",
40
- "use.done": "✓ 已切换到 {name}",
41
- "use.restart": "重启 Claude Code 生效",
42
- "use.cc_switch_running": "检测到 cc-switch GUI 正在运行,为避免配置冲突,仅更新了当前配置标记。请在 cc-switch GUI 中手动切换,或退出 GUI 后重试。",
43
- // save
44
- "save.description": "从当前 settings.json 保存为新配置",
45
- "save.overwrite": '配置 "{name}" 已存在,将覆盖',
46
- "save.done": '✓ 已保存当前配置为 "{name}"',
47
- // show
48
- "show.description": "查看配置详情(不指定则显示当前)",
49
- "show.no_current": "当前无激活配置,请指定名称: cc-cast show <name>",
50
- "show.all_header": "所有配置:",
51
- // remove
52
- "remove.description": "删除配置方案",
53
- "remove.select": "选择要删除的配置:",
54
- "remove.confirm": '确认删除 "{name}"?(y/N) ',
55
- "remove.done": '✓ 已删除 "{name}"',
56
- // alias
57
- "alias.description": "管理别名",
58
- "alias.set_description": "设置别名,如: cc-cast alias set or openrouter-opus4.6",
59
- "alias.set_done": "✓ 别名已设置: {short} → {name}",
60
- "alias.rm_description": "删除别名",
61
- "alias.rm_not_found": '别名 "{short}" 不存在',
62
- "alias.rm_done": '✓ 已删除别名 "{short}"',
63
- "alias.list_description": "列出所有别名",
64
- "alias.list_empty": "暂无别名。使用 cc-cast alias set <short> <name> 添加",
65
- "alias.list_header": "别名列表:",
66
- // locale
67
- "locale.description": "管理界面语言",
68
- "locale.current": "当前语言: {locale}",
69
- "locale.set_description": "设置语言 (zh/en)",
70
- "locale.set_done": "✓ 语言已设置为 {locale}",
71
- "locale.set_invalid": "不支持的语言: {locale},可选: zh, en",
72
- "locale.list_description": "列出并选择语言",
73
- "locale.list_header": "支持的语言:",
74
- "locale.list_current_marker": "(当前)",
75
- "locale.select": "选择语言:",
76
- "locale.choose_number": "输入序号切换 (回车跳过): ",
77
- // add
78
- "add.description": "交互式添加新配置",
79
- "add.prompt_name": "供应商名称 (如 OpenRouter): ",
80
- "add.prompt_base_url": "ANTHROPIC_BASE_URL: ",
81
- "add.prompt_auth_token": "ANTHROPIC_AUTH_TOKEN: ",
82
- "add.prompt_model": "ANTHROPIC_MODEL: ",
83
- "add.prompt_default_opus": "ANTHROPIC_DEFAULT_OPUS_MODEL (回车跳过): ",
84
- "add.prompt_default_sonnet": "ANTHROPIC_DEFAULT_SONNET_MODEL (回车跳过): ",
85
- "add.prompt_default_haiku": "ANTHROPIC_DEFAULT_HAIKU_MODEL (回车跳过): ",
86
- "add.mode_select": "选择添加方式:",
87
- "add.mode_interactive": "逐步填写",
88
- "add.mode_json": "直接编写 JSON",
89
- "add.mode_choose": "请选择 (1/2): ",
90
- "add.json_template_hint": "请在编辑器中填写配置,保存并退出",
91
- "add.json_parse_error": "JSON 解析失败,请检查格式",
92
- "add.back_hint": "输入 < 返回上一步",
93
- "add.name_required": "供应商名称不能为空",
94
- "add.field_required": "{field} 不能为空",
95
- "add.already_exists": '配置 "{name}" 已存在,是否覆盖?(y/N) ',
96
- "add.edit_confirm": "是否在编辑器中编辑配置?(y/N) ",
97
- "add.preview_header": "配置预览:",
98
- "add.done": '✓ 已保存配置 "{name}"',
99
- "add.switch_confirm": "是否立即切换到此配置?(Y/n) ",
100
- "add.cancelled": "已取消",
101
- // modify
102
- "modify.description": "修改已有配置",
103
- "modify.select": "选择要修改的配置:",
104
- "modify.done": '✓ 已更新配置 "{name}"',
105
- "modify.no_change": "未做任何修改",
106
- // alias conflict
107
- "alias.is_alias": '"{name}" 是别名,指向 "{target}"',
108
- "alias.conflict": '"{name}" 同时是别名(→ {target})和配置名,使用哪个?',
109
- "alias.conflict_alias": "别名(→ {target})",
110
- "alias.conflict_config": "配置 {name}",
111
- "alias.choose_conflict": "请选择 (1/2): ",
112
- "alias.rm_which": "要删除哪个?",
113
- "alias.rm_alias": "别名 {name}",
114
- "alias.rm_config": "配置 {target}",
115
- "alias.rm_choose": "请选择 (1/2): ",
116
- // sync
117
- "sync.description": "从 cc-switch 同步配置",
118
- "sync.no_cc_switch": "未检测到 cc-switch 数据库",
119
- "sync.empty": "cc-switch 中没有找到 Claude 配置",
120
- "sync.done": "✓ 已同步 {count} 个配置",
121
- "sync.current": "当前激活: {name}",
122
- "sync.no_current": "当前无激活配置",
123
- // clear
124
- "clear.description": "清理 cc-cast 数据文件",
125
- "clear.confirm": "确认删除所有 cc-cast 数据文件?(y/N) ",
126
- "clear.cancelled": "已取消清理",
127
- "clear.removed": "✓ 已删除 {path}",
128
- "clear.done": "✓ 清理完成",
129
- // import
130
- "import.description": "从 JSON 导入配置(文件或粘贴)",
131
- "import.paste_hint": "粘贴 JSON,按 Ctrl+D(或 Windows 的 Ctrl+Z)结束:",
132
- "import.file_not_found": '文件不存在: {file}',
133
- "import.json_parse_error": "JSON 格式无效",
134
- "import.invalid_format": "格式错误: 应为以配置名称为键的对象",
135
- "import.done": "✓ 已导入 {count} 个配置",
136
- // store errors
137
- "store.db_not_found": "cc-switch 数据库不存在: {path}",
138
- };
139
- export default zh;
@@ -1,114 +0,0 @@
1
- import Database from "better-sqlite3";
2
- import { homedir } from "os";
3
- import { join } from "path";
4
- import { existsSync, readFileSync, writeFileSync } from "fs";
5
- import { t } from "../i18n/index.js";
6
- const DB_PATH = join(homedir(), ".cc-switch", "cc-switch.db");
7
- const SETTINGS_PATH = join(homedir(), ".cc-switch", "settings.json");
8
- export function ccSwitchExists() {
9
- return existsSync(DB_PATH);
10
- }
11
- export class CcSwitchStore {
12
- db;
13
- constructor() {
14
- if (!existsSync(DB_PATH)) {
15
- throw new Error(t("store.db_not_found", { path: DB_PATH }));
16
- }
17
- this.db = new Database(DB_PATH);
18
- }
19
- list() {
20
- const rows = this.db
21
- .prepare(`SELECT id, name, settings_config FROM providers WHERE app_type = 'claude' ORDER BY sort_index`)
22
- .all();
23
- return rows.map((row) => ({
24
- id: row.id,
25
- name: row.name,
26
- settingsConfig: JSON.parse(row.settings_config),
27
- }));
28
- }
29
- get(name) {
30
- const row = this.db
31
- .prepare(`SELECT id, name, settings_config FROM providers WHERE app_type = 'claude' AND name = ?`)
32
- .get(name);
33
- if (!row)
34
- return undefined;
35
- return {
36
- id: row.id,
37
- name: row.name,
38
- settingsConfig: JSON.parse(row.settings_config),
39
- };
40
- }
41
- save(name, settingsConfig) {
42
- const existing = this.get(name);
43
- if (existing) {
44
- this.db
45
- .prepare(`UPDATE providers SET settings_config = ? WHERE app_type = 'claude' AND name = ?`)
46
- .run(JSON.stringify(settingsConfig), name);
47
- }
48
- else {
49
- const maxSort = this.db
50
- .prepare(`SELECT COALESCE(MAX(sort_index), -1) as max_sort FROM providers WHERE app_type = 'claude'`)
51
- .get();
52
- const sortIndex = (maxSort?.max_sort ?? -1) + 1;
53
- const id = crypto.randomUUID();
54
- this.db
55
- .prepare(`INSERT INTO providers (
56
- id, app_type, name, settings_config, website_url, category,
57
- created_at, sort_index, notes, icon, icon_color, meta, is_current, in_failover_queue
58
- ) VALUES (?, 'claude', ?, ?, NULL, NULL, ?, ?, NULL, NULL, NULL, '{}', 0, 0)`)
59
- .run(id, name, JSON.stringify(settingsConfig), Date.now(), sortIndex);
60
- }
61
- }
62
- remove(name) {
63
- const result = this.db
64
- .prepare(`DELETE FROM providers WHERE app_type = 'claude' AND name = ?`)
65
- .run(name);
66
- return result.changes > 0;
67
- }
68
- getCurrent() {
69
- // Prefer DB is_current so we stay in sync with cc-switch UI
70
- const dbRow = this.db
71
- .prepare(`SELECT name FROM providers WHERE app_type = 'claude' AND is_current = 1 LIMIT 1`)
72
- .get();
73
- if (dbRow)
74
- return dbRow.name;
75
- // Fallback to settings.json
76
- if (!existsSync(SETTINGS_PATH))
77
- return undefined;
78
- try {
79
- const settings = JSON.parse(readFileSync(SETTINGS_PATH, "utf-8"));
80
- const currentId = settings.currentProviderClaude;
81
- if (!currentId)
82
- return undefined;
83
- const row = this.db
84
- .prepare(`SELECT name FROM providers WHERE app_type = 'claude' AND id = ?`)
85
- .get(currentId);
86
- return row?.name;
87
- }
88
- catch {
89
- return undefined;
90
- }
91
- }
92
- setCurrent(name) {
93
- const profile = this.get(name);
94
- if (!profile)
95
- throw new Error(t("error.not_found", { name }));
96
- const tx = this.db.transaction(() => {
97
- this.db
98
- .prepare(`UPDATE providers SET is_current = 0 WHERE app_type = 'claude'`)
99
- .run();
100
- this.db
101
- .prepare(`UPDATE providers SET is_current = 1 WHERE app_type = 'claude' AND id = ?`)
102
- .run(profile.id);
103
- });
104
- tx();
105
- const settings = existsSync(SETTINGS_PATH)
106
- ? JSON.parse(readFileSync(SETTINGS_PATH, "utf-8"))
107
- : {};
108
- settings.currentProviderClaude = profile.id;
109
- writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
110
- }
111
- close() {
112
- this.db.close();
113
- }
114
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,65 +0,0 @@
1
- import { homedir } from "os";
2
- import { join } from "path";
3
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
4
- import { t } from "../i18n/index.js";
5
- const CC_CAST_DIR = join(homedir(), ".cc-cast");
6
- const CONFIG_PATH = join(CC_CAST_DIR, "config.json");
7
- function ensureDir() {
8
- if (!existsSync(CC_CAST_DIR)) {
9
- mkdirSync(CC_CAST_DIR, { recursive: true });
10
- }
11
- }
12
- function readConfig() {
13
- if (!existsSync(CONFIG_PATH)) {
14
- return { profiles: {} };
15
- }
16
- return JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
17
- }
18
- function writeConfig(config) {
19
- ensureDir();
20
- writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
21
- }
22
- export class StandaloneStore {
23
- list() {
24
- const config = readConfig();
25
- return Object.entries(config.profiles).map(([name, settingsConfig]) => ({
26
- id: name,
27
- name,
28
- settingsConfig,
29
- }));
30
- }
31
- get(name) {
32
- const config = readConfig();
33
- const settingsConfig = config.profiles[name];
34
- if (!settingsConfig)
35
- return undefined;
36
- return { id: name, name, settingsConfig };
37
- }
38
- save(name, settingsConfig) {
39
- const config = readConfig();
40
- config.profiles[name] = settingsConfig;
41
- writeConfig(config);
42
- }
43
- remove(name) {
44
- const config = readConfig();
45
- if (!(name in config.profiles))
46
- return false;
47
- delete config.profiles[name];
48
- if (config.current === name) {
49
- config.current = undefined;
50
- }
51
- writeConfig(config);
52
- return true;
53
- }
54
- getCurrent() {
55
- return readConfig().current;
56
- }
57
- setCurrent(name) {
58
- const config = readConfig();
59
- if (!(name in config.profiles)) {
60
- throw new Error(t("error.not_found", { name }));
61
- }
62
- config.current = name;
63
- writeConfig(config);
64
- }
65
- }
package/dist/types.js DELETED
@@ -1 +0,0 @@
1
- export {};
package/dist/utils.js DELETED
@@ -1,42 +0,0 @@
1
- import { homedir } from "os";
2
- import { join } from "path";
3
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
4
- import { spawnSync } from "child_process";
5
- import { StandaloneStore } from "./store/standalone.js";
6
- import { CcSwitchStore, ccSwitchExists } from "./store/cc-switch.js";
7
- const CC_CAST_DIR = join(homedir(), ".cc-cast");
8
- const RC_PATH = join(CC_CAST_DIR, "rc.json");
9
- export function readRc() {
10
- if (!existsSync(RC_PATH)) {
11
- writeRc({});
12
- return {};
13
- }
14
- try {
15
- return JSON.parse(readFileSync(RC_PATH, "utf-8"));
16
- }
17
- catch {
18
- writeRc({});
19
- return {};
20
- }
21
- }
22
- export function writeRc(rc) {
23
- if (!existsSync(CC_CAST_DIR)) {
24
- mkdirSync(CC_CAST_DIR, { recursive: true });
25
- }
26
- writeFileSync(RC_PATH, JSON.stringify(rc, null, 2));
27
- }
28
- export function getStore() {
29
- if (ccSwitchExists()) {
30
- return new CcSwitchStore();
31
- }
32
- return new StandaloneStore();
33
- }
34
- export function isCcSwitchGuiRunning() {
35
- try {
36
- const result = spawnSync("pgrep", ["-f", "cc-switch"], { encoding: "utf-8" });
37
- return result.status === 0 && (result.stdout?.trim().length ?? 0) > 0;
38
- }
39
- catch {
40
- return false;
41
- }
42
- }