yymaxapi 1.0.45 → 1.0.46

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.
Files changed (2) hide show
  1. package/bin/yymaxapi.js +74 -51
  2. package/package.json +1 -1
package/bin/yymaxapi.js CHANGED
@@ -2660,22 +2660,7 @@ async function autoActivate(paths, args = {}) {
2660
2660
  // ---- 构建配置 ----
2661
2661
  const config = ensureConfigStructure(readConfig(paths.openclawConfig) || {});
2662
2662
 
2663
- const existingProviders = Object.keys(config.models.providers || {});
2664
- const toRemove = existingProviders.filter(n => n !== claudeProviderName && n !== codexProviderName);
2665
- if (toRemove.length > 0 && !args.force) {
2666
- const { overwrite } = await inquirer.prompt([{
2667
- type: 'confirm',
2668
- name: 'overwrite',
2669
- message: `检测到已有中转配置: ${existingProviders.join(', ')},将替换为 ${claudeProviderName} + ${codexProviderName}。是否继续?`,
2670
- default: false
2671
- }]);
2672
- if (!overwrite) { console.log(chalk.gray('已取消')); return; }
2673
- }
2674
-
2675
- if (toRemove.length > 0) {
2676
- pruneProvidersExcept(config, [claudeProviderName, codexProviderName]);
2677
- pruneAuthProfilesExcept(paths.authProfiles, [claudeProviderName, codexProviderName]);
2678
- }
2663
+ // 增量写入: 只添加/更新云翼 provider,保留其他已有配置
2679
2664
 
2680
2665
  // Claude 侧
2681
2666
  const claudeBaseUrl = buildFullUrl(selectedEndpoint.url, 'claude');
@@ -3042,13 +3027,7 @@ async function yycodeQuickSetup(paths) {
3042
3027
  // ---- 写入两套配置 ----
3043
3028
  const config = ensureConfigStructure(readConfig(paths.openclawConfig) || {});
3044
3029
 
3045
- // 清理旧 provider
3046
- const existingProviders = Object.keys(config.models.providers || {});
3047
- const toRemove = existingProviders.filter(n => n !== claudeProviderName && n !== codexProviderName);
3048
- if (toRemove.length > 0) {
3049
- pruneProvidersExcept(config, [claudeProviderName, codexProviderName]);
3050
- pruneAuthProfilesExcept(paths.authProfiles, [claudeProviderName, codexProviderName]);
3051
- }
3030
+ // 增量写入: 只添加/更新云翼 provider,保留其他已有配置
3052
3031
 
3053
3032
  // Claude 侧
3054
3033
  const claudeBaseUrl = buildFullUrl(selectedEndpoint.url, 'claude');
@@ -3404,59 +3383,103 @@ async function activate(paths, type) {
3404
3383
 
3405
3384
  // ============ 切换模型 ============
3406
3385
  async function switchModel(paths) {
3407
- console.log(chalk.cyan('🔄 切换 Claude 模型\n'));
3386
+ console.log(chalk.cyan('🔄 切换模型\n'));
3408
3387
 
3409
3388
  const config = ensureConfigStructure(readConfig(paths.openclawConfig) || {});
3410
3389
  const primary = config.agents?.defaults?.model?.primary || '';
3390
+ const providers = config.models?.providers || {};
3411
3391
 
3412
- if (!primary.includes('/')) {
3413
- console.log(chalk.yellow('⚠️ 请先通过「一键激活」设置主模型'));
3392
+ if (Object.keys(providers).length === 0) {
3393
+ console.log(chalk.yellow('⚠️ 未找到任何中转配置,请先通过「一键配置」设置'));
3414
3394
  return;
3415
3395
  }
3416
3396
 
3417
- const providerName = primary.split('/')[0];
3418
- const currentModelId = primary.split('/')[1] || '';
3419
- const provider = config.models?.providers?.[providerName];
3397
+ // 已知 provider 别名映射
3398
+ const PROVIDER_LABELS = {
3399
+ 'claude-yunyi': '云翼 Claude (包月)',
3400
+ 'yunyi': '云翼 Codex (包月)',
3401
+ 'heibai': 'MAXAPI (按量)',
3402
+ };
3420
3403
 
3421
- if (!provider) {
3422
- console.log(chalk.yellow(`⚠️ 主模型对应的中转站不存在: ${providerName}`));
3423
- return;
3404
+ // 收集所有 provider 的所有模型
3405
+ const choices = [];
3406
+ for (const [providerName, providerConfig] of Object.entries(providers)) {
3407
+ const label = PROVIDER_LABELS[providerName] || providerName;
3408
+ const models = providerConfig.models || [];
3409
+ if (models.length === 0) continue;
3410
+
3411
+ choices.push(new inquirer.Separator(` -- ${label} --`));
3412
+ for (const m of models) {
3413
+ const modelKey = `${providerName}/${m.id}`;
3414
+ const isCurrent = modelKey === primary;
3415
+ choices.push({
3416
+ name: isCurrent ? `${m.name || m.id} (当前)` : (m.name || m.id),
3417
+ value: modelKey,
3418
+ });
3419
+ }
3424
3420
  }
3425
3421
 
3426
- const models = [
3427
- { id: 'claude-opus-4-6', name: 'Claude Opus 4.6' },
3428
- { id: 'claude-sonnet-4-6', name: 'Claude Sonnet 4.6' },
3429
- ];
3422
+ // 也把 agents.defaults.models 里注册过但 provider.models 里没列出的补上
3423
+ const registeredKeys = Object.keys(config.agents?.defaults?.models || {});
3424
+ const listedKeys = new Set(choices.filter(c => c.value).map(c => c.value));
3425
+ for (const modelKey of registeredKeys) {
3426
+ if (listedKeys.has(modelKey)) continue;
3427
+ const [pName, mId] = modelKey.split('/');
3428
+ if (!pName || !mId) continue;
3429
+ const label = PROVIDER_LABELS[pName] || pName;
3430
+ const isCurrent = modelKey === primary;
3431
+ choices.push({
3432
+ name: isCurrent ? `${label} / ${mId} (当前)` : `${label} / ${mId}`,
3433
+ value: modelKey,
3434
+ });
3435
+ }
3436
+
3437
+ if (choices.filter(c => c.value).length === 0) {
3438
+ console.log(chalk.yellow('⚠️ 未找到任何可用模型'));
3439
+ return;
3440
+ }
3430
3441
 
3431
- console.log(chalk.gray(`当前模型: ${currentModelId}`));
3432
- console.log(chalk.gray(`中转节点: ${provider.baseUrl}\n`));
3442
+ const currentProvider = primary.split('/')[0] || '';
3443
+ const currentProviderConfig = providers[currentProvider];
3444
+ console.log(chalk.gray(`当前模型: ${primary || '未设置'}`));
3445
+ if (currentProviderConfig) {
3446
+ console.log(chalk.gray(`中转节点: ${currentProviderConfig.baseUrl}`));
3447
+ }
3448
+ console.log('');
3433
3449
 
3434
3450
  const { selected } = await inquirer.prompt([{
3435
3451
  type: 'list',
3436
3452
  name: 'selected',
3437
3453
  message: '选择模型:',
3438
- default: currentModelId,
3439
- choices: models.map(m => ({
3440
- name: m.id === currentModelId ? `${m.name} (当前)` : m.name,
3441
- value: m.id,
3442
- })),
3454
+ default: primary,
3455
+ pageSize: 15,
3456
+ choices,
3443
3457
  }]);
3444
3458
 
3445
- if (selected === currentModelId) {
3459
+ if (selected === primary) {
3446
3460
  console.log(chalk.gray('\n模型未变更'));
3447
3461
  return;
3448
3462
  }
3449
3463
 
3450
- const newPrimary = `${providerName}/${selected}`;
3451
- config.agents.defaults.model.primary = newPrimary;
3452
- if (!config.agents.defaults.models[newPrimary]) {
3453
- config.agents.defaults.models[newPrimary] = { alias: providerName };
3464
+ const selectedProvider = selected.split('/')[0];
3465
+ config.agents.defaults.model.primary = selected;
3466
+ if (!config.agents.defaults.models[selected]) {
3467
+ config.agents.defaults.models[selected] = { alias: selectedProvider };
3468
+ }
3469
+ config.agents.defaults.model.fallbacks = (config.agents.defaults.model.fallbacks || []).filter(k => k !== selected);
3470
+ // 把旧的 primary 加入 fallbacks (如果存在且不同)
3471
+ if (primary && primary !== selected && !config.agents.defaults.model.fallbacks.includes(primary)) {
3472
+ config.agents.defaults.model.fallbacks.push(primary);
3454
3473
  }
3455
3474
  writeConfigWithSync(paths, config);
3456
3475
 
3457
- const selectedName = models.find(m => m.id === selected).name;
3458
- console.log(chalk.green(`\n✅ 已切换到 ${selectedName}`));
3459
- console.log(chalk.gray(` ${newPrimary}`));
3476
+ const selectedProviderConfig = providers[selectedProvider];
3477
+ const selectedLabel = PROVIDER_LABELS[selectedProvider] || selectedProvider;
3478
+ console.log(chalk.green(`\n✅ 已切换到 ${selected}`));
3479
+ console.log(chalk.gray(` 来源: ${selectedLabel}`));
3480
+ if (selectedProviderConfig) {
3481
+ console.log(chalk.gray(` 节点: ${selectedProviderConfig.baseUrl}`));
3482
+ }
3460
3483
  console.log(chalk.yellow('\n💡 切换后建议重启 Gateway: openclaw gateway restart'));
3461
3484
 
3462
3485
  const gwPort = config.gateway?.port || 18789;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yymaxapi",
3
- "version": "1.0.45",
3
+ "version": "1.0.46",
4
4
  "description": "跨平台 OpenClaw/Clawdbot 配置管理工具 - 管理中转地址、模型切换、API Keys、测速优化",
5
5
  "main": "bin/yymaxapi.js",
6
6
  "bin": {