From 29a2ddfc8c925d28217e5042b6a30b81fc0f4dd4 Mon Sep 17 00:00:00 2001 From: cjh <1054535289@qq.com> Date: Tue, 30 Sep 2025 20:23:18 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E2=9C=A8=20feat(claude):=20=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E4=BD=BF=E7=94=A8=20claude=20=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E5=B9=B6=E5=85=BC=E5=AE=B9=E8=80=81=E6=A0=BC=E5=BC=8F=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 ConfigManager.getClaudeConfig 方法以支持新旧配置格式兼容 - 各命令文件中替换 config 字段为 claude 并增强配置读取逻辑 - 更新示例配置与格式化逻辑以保持一致性 --- src/commands/claude/add.js | 4 +- src/commands/claude/apiuse.js | 9 ++-- src/commands/claude/delete.js | 18 +++++-- src/commands/claude/edit.js | 2 +- src/commands/claude/switch.js | 9 ++-- src/commands/codex/edit.js | 2 +- src/core/ConfigManager.js | 94 ++++++++++++++++++++++++++++++++--- src/utils/formatter.js | 13 ++--- 8 files changed, 121 insertions(+), 30 deletions(-) diff --git a/src/commands/claude/add.js b/src/commands/claude/add.js index fc9761e..c2af32f 100644 --- a/src/commands/claude/add.js +++ b/src/commands/claude/add.js @@ -301,10 +301,10 @@ class AddCommand { allConfigs = { sites: {} }; } - // 添加新配置 + // 添加新配置(使用标准的claude字段) allConfigs.sites[basicInfo.siteKey] = { url: url, // 站点URL - config: { + claude: { env: { ANTHROPIC_BASE_URL: url, ANTHROPIC_AUTH_TOKEN: tokens diff --git a/src/commands/claude/apiuse.js b/src/commands/claude/apiuse.js index 7a8863c..c4ce2cf 100644 --- a/src/commands/claude/apiuse.js +++ b/src/commands/claude/apiuse.js @@ -58,12 +58,15 @@ class ApiUseCommand { const siteConfig = allConfigs.sites[selectedSite]; + // 获取Claude配置(兼容老格式) + const claudeConfig = this.configManager.getClaudeConfig(siteConfig); + console.log(chalk.gray(`✓ 选择站点: ${selectedSite}`)); - console.log(chalk.gray(`✓ URL: ${siteConfig.config.env.ANTHROPIC_BASE_URL}`)); + console.log(chalk.gray(`✓ URL: ${claudeConfig.env.ANTHROPIC_BASE_URL}`)); // 2. 智能选择Token let selectedToken; - const rawTokens = siteConfig.config.env.ANTHROPIC_AUTH_TOKEN; + const rawTokens = claudeConfig.env.ANTHROPIC_AUTH_TOKEN; const tokens = typeof rawTokens === 'string' ? { '默认Token': rawTokens } : rawTokens; if (Object.keys(tokens).length === 1) { @@ -88,7 +91,7 @@ class ApiUseCommand { const config = { site: selectedSite, siteName: selectedSite, - ANTHROPIC_BASE_URL: siteConfig.config.env.ANTHROPIC_BASE_URL, + ANTHROPIC_BASE_URL: claudeConfig.env.ANTHROPIC_BASE_URL, token: selectedToken, tokenName: Object.keys(tokens).find(key => tokens[key] === selectedToken) }; diff --git a/src/commands/claude/delete.js b/src/commands/claude/delete.js index 62b99e7..f9107d8 100644 --- a/src/commands/claude/delete.js +++ b/src/commands/claude/delete.js @@ -133,18 +133,21 @@ class DeleteCommand { const siteConfig = allConfigs.sites[selectedSite]; + // 获取Claude配置(兼容老格式) + const claudeConfig = this.configManager.getClaudeConfig(siteConfig); + // 显示站点信息 console.log(chalk.white("\n📋 即将删除的站点信息:")); console.log(chalk.gray(`站点标识: ${selectedSite}`)); console.log( chalk.gray( - `ANTHROPIC_BASE_URL: ${siteConfig.config?.env?.ANTHROPIC_BASE_URL}` + `ANTHROPIC_BASE_URL: ${claudeConfig?.env?.ANTHROPIC_BASE_URL}` ) ); console.log( chalk.gray( `Token数量: ${ - Object.keys(siteConfig.config?.env?.ANTHROPIC_AUTH_TOKEN || {}).length + Object.keys(claudeConfig?.env?.ANTHROPIC_AUTH_TOKEN || {}).length }个` ) ); @@ -239,7 +242,10 @@ class DeleteCommand { ]); const siteConfig = allConfigs.sites[selectedSite]; - const tokens = siteConfig.config?.env?.ANTHROPIC_AUTH_TOKEN || {}; + + // 获取Claude配置(兼容老格式) + const claudeConfig = this.configManager.getClaudeConfig(siteConfig); + const tokens = claudeConfig?.env?.ANTHROPIC_AUTH_TOKEN || {}; // 检查Token数量 if (Object.keys(tokens).length === 0) { @@ -322,8 +328,12 @@ class DeleteCommand { const spinner = ora("正在删除Token...").start(); try { + // 获取Claude配置字段(需要直接操作原对象) + const siteConfig = allConfigs.sites[selectedSite]; + const claudeConfigField = siteConfig.claude ? 'claude' : 'config'; + // 删除Token - delete allConfigs.sites[selectedSite].config.env.ANTHROPIC_AUTH_TOKEN[ + delete allConfigs.sites[selectedSite][claudeConfigField].env.ANTHROPIC_AUTH_TOKEN[ selectedToken ]; diff --git a/src/commands/claude/edit.js b/src/commands/claude/edit.js index 593de5e..4b22dc0 100644 --- a/src/commands/claude/edit.js +++ b/src/commands/claude/edit.js @@ -53,7 +53,7 @@ class EditCommand { "示例站点": { "description": "这是一个示例配置,请根据需要修改", "url": "https://api.example.com", - "config": { + "claude": { "env": { "ANTHROPIC_BASE_URL": "https://api.example.com", "ANTHROPIC_AUTH_TOKEN": { diff --git a/src/commands/claude/switch.js b/src/commands/claude/switch.js index 84ef08c..1331be2 100644 --- a/src/commands/claude/switch.js +++ b/src/commands/claude/switch.js @@ -50,12 +50,15 @@ class SwitchCommand { const siteConfig = allConfigs.sites[selectedSite]; + // 获取Claude配置(兼容老格式) + const claudeConfig = this.configManager.getClaudeConfig(siteConfig); + console.log(chalk.gray(`✓ 选择站点: ${selectedSite}`)); - console.log(chalk.gray(`✓ URL: ${siteConfig.config.env.ANTHROPIC_BASE_URL}`)); + console.log(chalk.gray(`✓ URL: ${claudeConfig.env.ANTHROPIC_BASE_URL}`)); // 2. 智能选择Token let selectedToken; - const rawTokens = siteConfig.config.env.ANTHROPIC_AUTH_TOKEN; + const rawTokens = claudeConfig.env.ANTHROPIC_AUTH_TOKEN; const tokens = typeof rawTokens === 'string' ? { '默认Token': rawTokens } : rawTokens; if (Object.keys(tokens).length === 1) { @@ -78,7 +81,7 @@ class SwitchCommand { const config = { site: selectedSite, siteName: selectedSite, - ANTHROPIC_BASE_URL: siteConfig.config.env.ANTHROPIC_BASE_URL, + ANTHROPIC_BASE_URL: claudeConfig.env.ANTHROPIC_BASE_URL, token: selectedToken, tokenName: Object.keys(tokens).find(key => tokens[key] === selectedToken) }; diff --git a/src/commands/codex/edit.js b/src/commands/codex/edit.js index 861c3aa..ad3e01b 100644 --- a/src/commands/codex/edit.js +++ b/src/commands/codex/edit.js @@ -53,7 +53,7 @@ class CodexEditCommand { "示例站点": { "description": "这是一个示例配置,请根据需要修改", "url": "https://api.example.com", - "config": { + "claude": { "env": { "ANTHROPIC_BASE_URL": "https://api.example.com", "ANTHROPIC_AUTH_TOKEN": { diff --git a/src/core/ConfigManager.js b/src/core/ConfigManager.js index a0b26d4..633b61f 100644 --- a/src/core/ConfigManager.js +++ b/src/core/ConfigManager.js @@ -136,10 +136,13 @@ class ConfigManager { // 更新当前配置 allConfigs.currentConfig = configToSave; + // 规范化配置(清理冗余 + 迁移老格式) + const normalizedConfig = this.normalizeConfig(allConfigs); + // 保存到 api_configs.json await fs.writeFile( this.configPath, - JSON.stringify(allConfigs, null, 2), + JSON.stringify(normalizedConfig, null, 2), "utf8" ); } catch (error) { @@ -173,10 +176,13 @@ class ConfigManager { // 更新当前Codex配置 allConfigs.currentCodexConfig = configToSave; + // 规范化配置(清理冗余 + 迁移老格式) + const normalizedConfig = this.normalizeConfig(allConfigs); + // 保存到 api_configs.json await fs.writeFile( this.configPath, - JSON.stringify(allConfigs, null, 2), + JSON.stringify(normalizedConfig, null, 2), "utf8" ); } catch (error) { @@ -252,8 +258,11 @@ class ConfigManager { */ async switchConfig(site, token, siteConfig) { try { + // 获取Claude配置(兼容老格式) + const claudeConfig = this.getClaudeConfig(siteConfig); + // 找到Token的名称 - const rawTokens = siteConfig.config.env.ANTHROPIC_AUTH_TOKEN; + const rawTokens = claudeConfig.env.ANTHROPIC_AUTH_TOKEN; const tokens = typeof rawTokens === "string" ? { 默认Token: rawTokens } : rawTokens; const tokenName = Object.keys(tokens).find( @@ -263,7 +272,7 @@ class ConfigManager { const config = { site, siteName: site, - ANTHROPIC_BASE_URL: siteConfig.config.env.ANTHROPIC_BASE_URL, + ANTHROPIC_BASE_URL: claudeConfig.env.ANTHROPIC_BASE_URL, token, tokenName, }; @@ -283,7 +292,7 @@ class ConfigManager { delete currentSettings.model; // 准备合并的配置 - const configToMerge = { ...siteConfig.config }; + const configToMerge = { ...claudeConfig }; // 特殊处理:ANTHROPIC_AUTH_TOKEN使用选中的具体token值 if (configToMerge.env && configToMerge.env.ANTHROPIC_AUTH_TOKEN) { @@ -317,12 +326,17 @@ class ConfigManager { } for (const [siteKey, siteConfig] of Object.entries(config.sites)) { - if (!siteConfig.url || (!siteConfig.config && !siteConfig.claude)) { + if (!siteConfig.url) { return false; } - // 获取实际的配置对象(支持claude别名) - const actualConfig = siteConfig.config || siteConfig.claude; + // 尝试获取Claude配置 + let actualConfig; + try { + actualConfig = this.getClaudeConfig(siteConfig); + } catch (error) { + return false; // 没有claude或config字段 + } if ( !actualConfig.env || @@ -356,6 +370,70 @@ class ConfigManager { async configExists() { return await fs.pathExists(this.configPath); } + + /** + * 获取Claude配置(兼容老格式) + * @param {Object} siteConfig 站点配置对象 + * @returns {Object} Claude配置对象 + */ + getClaudeConfig(siteConfig) { + // 优先使用新格式的claude字段 + if (siteConfig.claude) { + return siteConfig.claude; + } + + // 兼容老格式的config字段 + if (siteConfig.config) { + return siteConfig.config; + } + + // 都没有则抛出错误 + throw new Error("站点配置缺少claude或config字段"); + } + + /** + * 规范化配置对象(清理冗余字段 + 迁移老格式) + * @param {Object} config 配置对象 + * @returns {Object} 规范化后的配置对象 + */ + normalizeConfig(config) { + if (!config.sites) { + return config; + } + + for (const siteKey in config.sites) { + const site = config.sites[siteKey]; + + // 情况1:只有config,没有claude -> 自动迁移为claude + if (site.config && !site.claude) { + site.claude = site.config; + delete site.config; + console.log( + chalk.gray(` ✓ 已自动迁移 ${siteKey}: config -> claude`) + ); + } + + // 情况2:同时存在claude和config,且内容相同 -> 删除冗余config + else if (site.claude && site.config) { + if (JSON.stringify(site.claude) === JSON.stringify(site.config)) { + delete site.config; + console.log(chalk.gray(` ✓ 已清理 ${siteKey} 的冗余config字段`)); + } + // 情况3:内容不同,保留两者(可能是特殊配置) + else { + console.log( + chalk.yellow( + ` ⚠️ ${siteKey} 的claude和config内容不同,已保留两者` + ) + ); + } + } + + // 情况4:只有claude -> 无需处理 + } + + return config; + } } export default ConfigManager; diff --git a/src/utils/formatter.js b/src/utils/formatter.js index 9bec651..77acbe8 100644 --- a/src/utils/formatter.js +++ b/src/utils/formatter.js @@ -109,10 +109,9 @@ function formatConfigList(allConfigs, currentConfig) { output += "\n"; - // ANTHROPIC_BASE_URL - const baseUrl = - siteConfig.config?.env?.ANTHROPIC_BASE_URL || - siteConfig.ANTHROPIC_BASE_URL; + // ANTHROPIC_BASE_URL - 兼容老格式 + const claudeConfig = siteConfig.claude || siteConfig.config; + const baseUrl = claudeConfig?.env?.ANTHROPIC_BASE_URL || siteConfig.ANTHROPIC_BASE_URL; const isCurrentUrl = currentConfig && currentConfig.site === siteKey && @@ -125,10 +124,8 @@ function formatConfigList(allConfigs, currentConfig) { } output += "\n"; - // ANTHROPIC_AUTH_TOKEN - const authTokens = - siteConfig.config?.env?.ANTHROPIC_AUTH_TOKEN || - siteConfig.ANTHROPIC_AUTH_TOKEN; + // ANTHROPIC_AUTH_TOKEN - 兼容老格式 + const authTokens = claudeConfig?.env?.ANTHROPIC_AUTH_TOKEN || siteConfig.ANTHROPIC_AUTH_TOKEN; const tokens = Object.entries(authTokens); output += `└─ 🔑 ANTHROPIC_AUTH_TOKEN (${tokens.length}个):\n`; From e499a7b6a011d36f816c2bde4a940465b984f2ea Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 30 Sep 2025 12:24:29 +0000 Subject: [PATCH 2/2] chore(release): 2.7.0 [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [2.7.0](https://github.com/cjh-store/cc-cli/compare/v2.6.4...v2.7.0) (2025-09-30) ### ✨ Features * **claude:** 统一使用 claude 字段并兼容老格式配置 ([29a2ddf](https://github.com/cjh-store/cc-cli/commit/29a2ddfc8c925d28217e5042b6a30b81fc0f4dd4)) --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6d6a7d..2dd526e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [2.7.0](https://github.com/cjh-store/cc-cli/compare/v2.6.4...v2.7.0) (2025-09-30) + +### ✨ Features + +* **claude:** 统一使用 claude 字段并兼容老格式配置 ([29a2ddf](https://github.com/cjh-store/cc-cli/commit/29a2ddfc8c925d28217e5042b6a30b81fc0f4dd4)) + ## [2.6.4](https://github.com/cjh-store/cc-cli/compare/v2.6.3...v2.6.4) (2025-09-30) ### ⚡ Performance diff --git a/package.json b/package.json index 41c17f0..06c972d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cjh0/cc-cli", - "version": "2.6.4", + "version": "2.7.0", "description": "Claude Code配置管理CLI工具", "main": "src/index.js", "type": "module",