UNPKG

ccr-model-manager

Version:

A command-line tool for managing Claude Code Router (CCR) model configurations with interactive selection

402 lines (396 loc) 14.4 kB
#!/usr/bin/env node const require_select = require('./select-BTG1tPDJ.js'); let child_process = require("child_process"); child_process = require_select.__toESM(child_process); let chalk = require("chalk"); chalk = require_select.__toESM(chalk); let commander = require("commander"); commander = require_select.__toESM(commander); //#region src/commands/list.ts /** * List命令实现 */ var ListCommand = class { /** * 执行list命令 */ static async execute() { try { require_select.FormatUtils.showLoading(require_select.UI_MESSAGES.READING_CONFIG); const config = await require_select.ConfigService.getConfig(); const providers = await require_select.ConfigService.getActiveProviders(); if (providers.length === 0) { require_select.FormatUtils.showError(require_select.ERROR_MESSAGES.NO_PROVIDERS); return; } this.displayProviders(providers); require_select.FormatUtils.displayCurrentSelection(config); } catch (error) { this.handleError(error); } } /** * 显示提供商列表和模型 * @param providers 提供商列表 */ static displayProviders(providers) { require_select.FormatUtils.displayProviderList(providers); } /** * 显示简化版的提供商信息(带统计) * @param providers 提供商列表 */ static displayProvidersWithStats(providers) { console.log(require_select.FormatUtils.formatInfo("可用的模型提供商统计:")); console.log(""); if (providers.length === 0) { require_select.FormatUtils.showError("未找到任何提供商"); return; } const totalProviders = providers.length; const totalModels = providers.reduce((sum, provider) => sum + (provider.models?.length || 0), 0); const deprecatedCount = providers.filter((p) => p.deprecated).length; const activeCount = totalProviders - deprecatedCount; console.log(require_select.FormatUtils.formatInfo(`总提供商数: ${totalProviders}`)); console.log(require_select.FormatUtils.formatSuccess(`活跃提供商: ${activeCount}`)); console.log(require_select.FormatUtils.formatWarning(`已弃用: ${deprecatedCount}`)); console.log(require_select.FormatUtils.formatInfo(`总模型数: ${totalModels}`)); console.log(""); providers.forEach((provider, index) => { const status = provider.deprecated ? "🟡 已弃用" : "🟢 活跃"; const statusColor = provider.deprecated ? "yellow" : "green"; const modelCount = provider.models?.length || 0; console.log(`${index + 1}. ${chalk.default[statusColor](provider.name)} - ${status}`); console.log(` 模型数量: ${modelCount}`); if (provider.models && provider.models.length > 0) console.log(` 可用模型: ${provider.models.slice(0, 3).join(", ")}${provider.models.length > 3 ? "..." : ""}`); if (provider.api_base_url) console.log(` API地址: ${provider.api_base_url}`); console.log(""); }); } /** * 搜索提供商或模型 * @param query 搜索查询字符串 */ static async search(query) { try { require_select.FormatUtils.showLoading(`正在搜索 "${query}"...`); const providers = await require_select.ConfigService.getProviders(true); const lowerQuery = query.toLowerCase(); const matchingProviders = providers.filter((provider) => provider.name.toLowerCase().includes(lowerQuery)); const matchingModels = []; providers.forEach((provider) => { if (provider.models) provider.models.forEach((model) => { if (model.toLowerCase().includes(lowerQuery)) matchingModels.push({ provider, model }); }); }); this.displaySearchResults(matchingProviders, matchingModels, query); } catch (error) { this.handleError(error); } } /** * 显示搜索结果 * @param matchingProviders 匹配的提供商 * @param matchingModels 匹配的模型 * @param query 搜索查询 */ static displaySearchResults(matchingProviders, matchingModels, query) { console.log(require_select.FormatUtils.formatInfo(`搜索结果 for "${query}":`)); console.log(""); if (matchingProviders.length > 0) { console.log(require_select.FormatUtils.formatSuccess(`匹配的提供商 (${matchingProviders.length}):`)); matchingProviders.forEach((provider) => { const status = provider.deprecated ? "🟡 已弃用" : "🟢 活跃"; const statusColor = provider.deprecated ? "yellow" : "green"; console.log(` - ${chalk.default[statusColor](provider.name)} - ${status}`); }); console.log(""); } if (matchingModels.length > 0) { console.log(require_select.FormatUtils.formatSuccess(`匹配的模型 (${matchingModels.length}):`)); const modelsByProvider = matchingModels.reduce((acc, { provider, model }) => { if (!acc[provider.name]) acc[provider.name] = []; acc[provider.name].push(model); return acc; }, {}); Object.entries(modelsByProvider).forEach(([providerName, models]) => { const statusColor = (matchingModels.find((m) => m.provider.name === providerName)?.provider)?.deprecated ? "yellow" : "green"; console.log(` ${chalk.default[statusColor](providerName)}:`); models.forEach((model) => { console.log(` - ${model}`); }); }); console.log(""); } if (matchingProviders.length === 0 && matchingModels.length === 0) require_select.FormatUtils.showWarning(`未找到与 "${query}" 匹配的提供商或模型`); } /** * 导出提供商列表为JSON * @param outputPath 输出文件路径(可选) */ static async exportToJson(outputPath) { try { require_select.FormatUtils.showLoading("正在导出提供商数据..."); const providers = await require_select.ConfigService.getProviders(true); const exportData = { exportedAt: (/* @__PURE__ */ new Date()).toISOString(), totalProviders: providers.length, activeProviders: providers.filter((p) => !p.deprecated).length, providers: providers.map((provider) => ({ name: provider.name, status: provider.deprecated ? "deprecated" : "active", apiBaseUrl: provider.api_base_url, models: provider.models || [], modelCount: provider.models?.length || 0 })) }; const jsonData = JSON.stringify(exportData, null, 2); if (outputPath) { await (await import("fs-extra")).writeFile(outputPath, jsonData, "utf8"); require_select.FormatUtils.showSuccess(`提供商数据已导出到: ${outputPath}`); } else console.log(jsonData); } catch (error) { this.handleError(error); } } /** * 统一错误处理 * @param error 错误对象 */ static handleError(error) { if (error instanceof Error) require_select.FormatUtils.showError(`发生错误: ${error.message}`); else require_select.FormatUtils.showError("发生未知错误"); console.error(error); } }; //#endregion //#region src/commands/routers.ts /** * Routers命令实现 */ var RoutersCommand = class { /** * 执行routers命令 */ static async execute() { try { require_select.FormatUtils.showLoading(require_select.UI_MESSAGES.READING_CONFIG); const config = await require_select.ConfigService.getConfig(); const providers = await require_select.ConfigService.getProviders(true); if (!require_select.ValidatorService.isConfigUsable(config)) { require_select.FormatUtils.showError(require_select.ERROR_MESSAGES.NO_ROUTER_CONFIG); return; } require_select.FormatUtils.displayRouterTable(config, providers); } catch (error) { this.handleError(error); } } /** * 处理错误 * @param error 错误对象 */ static handleError(error) { if (error instanceof Error) require_select.FormatUtils.showError(`发生错误: ${error.message}`); else require_select.FormatUtils.showError("发生未知错误"); console.error(error); } }; //#endregion //#region src/services/updater.ts /** * 基于npm的更新服务类 */ var UpdateService = class { static { this.PACKAGE_NAME = "ccr-model-manager"; } /** * 获取当前版本 * @returns Promise<string> 当前版本 */ static async getCurrentVersion() { try { const versionMatch = (0, child_process.execSync)("cmm --version", { encoding: "utf8", timeout: 5e3 }).trim().match(/(\d+\.\d+\.\d+)/); if (versionMatch) return versionMatch[1]; throw new Error("无法解析版本号"); } catch (error) { try { const packagePath = require.resolve("../package.json"); return require(packagePath).version; } catch { throw new Error("无法获取当前版本信息"); } } } /** * 从npm获取最新版本 * @returns Promise<string> 最新版本 */ static async getLatestVersionFromNpm() { try { const output = (0, child_process.execSync)(`npm view ${this.PACKAGE_NAME} version --json`, { encoding: "utf8", timeout: 1e4 }).trim(); return JSON.parse(output); } catch (error) { if (error instanceof Error && error.message.includes("404")) throw new Error(`包 "${this.PACKAGE_NAME}" 在npm上不存在`); throw new Error("无法从npm获取版本信息"); } } /** * 比较版本号 * @param current 当前版本 * @param latest 最新版本 * @returns boolean 是否有更新 */ static isNewer(current, latest) { const currentParts = current.split(".").map(Number); const latestParts = latest.split(".").map(Number); for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) { const currentPart = currentParts[i] || 0; const latestPart = latestParts[i] || 0; if (latestPart > currentPart) return true; if (latestPart < currentPart) return false; } return false; } /** * 检查更新 * @returns Promise<UpdateInfo> 更新信息 */ static async checkForUpdates() { try { require_select.FormatUtils.showLoading("正在检查更新..."); const currentVersion = await this.getCurrentVersion(); const latestVersion = await this.getLatestVersionFromNpm(); const updateAvailable = this.isNewer(currentVersion, latestVersion); return { currentVersion, latestVersion, updateAvailable }; } catch (error) { if (error instanceof Error) throw new Error(`检查更新失败: ${error.message}`); throw new Error("检查更新失败: 未知错误"); } } /** * 执行更新 * @returns Promise<UpdateResult> 更新结果 */ static async performUpdate() { try { const updateInfo = await this.checkForUpdates(); if (!updateInfo.updateAvailable) return { success: true, message: "当前已是最新版本", currentVersion: updateInfo.currentVersion, newVersion: updateInfo.currentVersion }; console.log(require_select.FormatUtils.formatInfo("发现新版本!")); console.log(`${require_select.FormatUtils.formatSuccess("当前版本:")} ${updateInfo.currentVersion}`); console.log(`${require_select.FormatUtils.formatWarning("最新版本:")} ${updateInfo.latestVersion}`); console.log(""); require_select.FormatUtils.showLoading("正在从npm更新..."); try { (0, child_process.execSync)(`npm install -g ${this.PACKAGE_NAME}@latest`, { stdio: "inherit", timeout: 3e5 }); return { success: true, message: `更新成功: ${updateInfo.currentVersion} -> ${updateInfo.latestVersion}`, currentVersion: updateInfo.currentVersion, newVersion: updateInfo.latestVersion }; } catch (npmError) { if (npmError instanceof Error && npmError.message.includes("EACCES")) return { success: false, message: "权限不足,请使用管理员权限运行更新", error: "需要管理员权限", suggestion: `请运行: sudo npm install -g ${this.PACKAGE_NAME}@latest` }; if (npmError instanceof Error) return { success: false, message: `npm安装失败: ${npmError.message}`, error: npmError.message }; return { success: false, message: "npm安装失败", error: "未知npm错误" }; } } catch (error) { if (error instanceof Error) return { success: false, message: `更新失败: ${error.message}`, error: error.message }; return { success: false, message: "更新失败: 未知错误" }; } } }; //#endregion //#region src/commands/update.ts /** * Update命令实现 - 基于npm的简洁版本 */ var UpdateCommand = class { /** * 执行update命令 - 检查并更新到最新版本 */ static async execute() { try { const result = await UpdateService.performUpdate(); if (result.success) { require_select.FormatUtils.showSuccess(`🎉 ${result.message}`); if (result.currentVersion && result.newVersion && result.currentVersion !== result.newVersion) { console.log(`${require_select.FormatUtils.formatInfo("从:")} ${result.currentVersion}`); console.log(`${require_select.FormatUtils.formatSuccess("到:")} ${result.newVersion}`); console.log(""); console.log(require_select.FormatUtils.formatInfo("请重新启动命令行工具以使用新版本。")); } } else { require_select.FormatUtils.showError(`❌ ${result.message}`); if ("suggestion" in result) console.log(require_select.FormatUtils.formatWarning(`建议: ${result.suggestion}`)); if (result.error) console.log(require_select.FormatUtils.formatInfo(`错误详情: ${result.error}`)); } } catch (error) { if (error instanceof Error) if (error.message.includes("网络")) require_select.FormatUtils.showError("网络错误,请检查网络连接后重试。"); else if (error.message.includes("npm")) require_select.FormatUtils.showError("npm操作失败,请确保npm已正确安装。"); else require_select.FormatUtils.showError(`更新失败: ${error.message}`); else require_select.FormatUtils.showError("更新失败:未知错误"); console.error(error); } } }; //#endregion //#region src/index.ts const program = new commander.Command(); program.name("cmm").description("CCR模型管理器").version("1.3.0"); program.command("select").description("选择CCR模型提供商和模型ID").action(async () => { await require_select.SelectCommand.execute(); }); program.command("list").description("列出所有可用的模型提供商和模型ID").action(async () => { await ListCommand.execute(); }); program.command("routers").description("查看当前CCR所有router对应的模型信息").action(async () => { await RoutersCommand.execute(); }); program.command("update").description("更新ccr-model-manager到最新版本").action(async () => { await UpdateCommand.execute(); }); program.parse(); //#endregion