yymaxapi 1.0.50 → 1.0.52

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 +90 -58
  2. package/package.json +1 -1
package/bin/yymaxapi.js CHANGED
@@ -140,8 +140,6 @@ const DEFAULT_API_CONFIG = {
140
140
 
141
141
  const SKIP_API_VALIDATION = false;
142
142
 
143
- const SKIP_API_VALIDATION = false;
144
-
145
143
  function normalizeEndpoints(raw, fallback) {
146
144
  if (!Array.isArray(raw)) return fallback;
147
145
  const normalized = raw
@@ -1184,8 +1182,17 @@ function coerceModelsRecord(value) {
1184
1182
  return record;
1185
1183
  }
1186
1184
 
1185
+ const OPENCLAW_INVALID_ROOT_KEYS = ['model'];
1186
+
1187
+ function sanitizeRootKeys(config) {
1188
+ for (const key of OPENCLAW_INVALID_ROOT_KEYS) {
1189
+ if (key in config) delete config[key];
1190
+ }
1191
+ }
1192
+
1187
1193
  function ensureConfigStructure(config) {
1188
1194
  const next = config || {};
1195
+ sanitizeRootKeys(next);
1189
1196
  if (!next.models) next.models = {};
1190
1197
  if (!next.models.providers) next.models.providers = {};
1191
1198
  if (!next.agents) next.agents = {};
@@ -2668,25 +2675,54 @@ async function autoActivate(paths, args = {}) {
2668
2675
  // ---- 构建配置 ----
2669
2676
  const config = ensureConfigStructure(readConfig(paths.openclawConfig) || {});
2670
2677
 
2671
- // 增量写入: 只添加/更新云翼 provider,保留其他已有配置
2672
-
2673
- // Claude 侧 — 让用户选模型
2674
2678
  const claudeBaseUrl = buildFullUrl(selectedEndpoint.url, 'claude');
2675
- let claudeModelId = (args['claude-model'] || '').toString().trim();
2676
- if (!claudeModelId && CLAUDE_MODELS.length > 1) {
2677
- const { picked } = await inquirer.prompt([{
2678
- type: 'list',
2679
- name: 'picked',
2680
- message: '选择 Claude 模型:',
2681
- choices: CLAUDE_MODELS.map(m => ({ name: m.name, value: m.id })),
2682
- default: CLAUDE_MODELS[0].id
2683
- }]);
2684
- claudeModelId = picked;
2679
+ const codexBaseUrl = buildFullUrl(selectedEndpoint.url, 'codex');
2680
+
2681
+ // 检测单一模式:Claude Codex 只有一个模型且 id 相同(如 maxapi 的 heibai)
2682
+ const isSingleMode = CLAUDE_MODELS.length === 1 && CODEX_MODELS.length === 1
2683
+ && CLAUDE_MODELS[0].id === CODEX_MODELS[0].id;
2684
+
2685
+ let claudeModelId, codexModelId;
2686
+
2687
+ if (isSingleMode) {
2688
+ // 单一模式:固定模型,不选择,不分 Claude/Codex
2689
+ claudeModelId = CLAUDE_MODELS[0].id;
2690
+ codexModelId = CODEX_MODELS[0].id;
2691
+ } else {
2692
+ // 多模型模式:让用户选模型
2693
+ claudeModelId = (args['claude-model'] || '').toString().trim();
2694
+ if (!claudeModelId && CLAUDE_MODELS.length > 1) {
2695
+ const { picked } = await inquirer.prompt([{
2696
+ type: 'list',
2697
+ name: 'picked',
2698
+ message: '选择 Claude 模型:',
2699
+ choices: CLAUDE_MODELS.map(m => ({ name: m.name, value: m.id })),
2700
+ default: CLAUDE_MODELS[0].id
2701
+ }]);
2702
+ claudeModelId = picked;
2703
+ }
2704
+ if (!claudeModelId) claudeModelId = CLAUDE_MODELS[0]?.id || 'claude-sonnet-4-6';
2705
+
2706
+ codexModelId = (args['codex-model'] || '').toString().trim();
2707
+ if (!codexModelId && CODEX_MODELS.length > 1) {
2708
+ const { pickedCodex } = await inquirer.prompt([{
2709
+ type: 'list',
2710
+ name: 'pickedCodex',
2711
+ message: '选择 Codex 模型:',
2712
+ choices: CODEX_MODELS.map(m => ({ name: m.name, value: m.id })),
2713
+ default: CODEX_MODELS[0].id
2714
+ }]);
2715
+ codexModelId = pickedCodex;
2716
+ }
2717
+ if (!codexModelId) codexModelId = CODEX_MODELS[0]?.id || 'gpt-5.3-codex';
2685
2718
  }
2686
- if (!claudeModelId) claudeModelId = CLAUDE_MODELS[0]?.id || 'claude-sonnet-4-6';
2719
+
2687
2720
  const claudeModel = CLAUDE_MODELS.find(m => m.id === claudeModelId) || { id: claudeModelId, name: claudeModelId };
2721
+ const codexModel = CODEX_MODELS.find(m => m.id === codexModelId) || { id: codexModelId, name: codexModelId };
2688
2722
  const claudeModelKey = `${claudeProviderName}/${claudeModelId}`;
2723
+ const codexModelKey = `${codexProviderName}/${codexModelId}`;
2689
2724
 
2725
+ // 写入 Claude provider
2690
2726
  config.models.providers[claudeProviderName] = {
2691
2727
  baseUrl: claudeBaseUrl,
2692
2728
  auth: DEFAULT_AUTH_MODE,
@@ -2704,23 +2740,7 @@ async function autoActivate(paths, args = {}) {
2704
2740
  config.auth.profiles[`${claudeProviderName}:default`] = { provider: claudeProviderName, mode: 'api_key' };
2705
2741
  config.agents.defaults.models[claudeModelKey] = { alias: claudeProviderName };
2706
2742
 
2707
- // Codex 侧 — 让用户选模型
2708
- const codexBaseUrl = buildFullUrl(selectedEndpoint.url, 'codex');
2709
- let codexModelId = (args['codex-model'] || '').toString().trim();
2710
- if (!codexModelId && CODEX_MODELS.length > 1) {
2711
- const { pickedCodex } = await inquirer.prompt([{
2712
- type: 'list',
2713
- name: 'pickedCodex',
2714
- message: '选择 Codex 模型:',
2715
- choices: CODEX_MODELS.map(m => ({ name: m.name, value: m.id })),
2716
- default: CODEX_MODELS[0].id
2717
- }]);
2718
- codexModelId = pickedCodex;
2719
- }
2720
- if (!codexModelId) codexModelId = CODEX_MODELS[0]?.id || 'gpt-5.3-codex';
2721
- const codexModel = CODEX_MODELS.find(m => m.id === codexModelId) || { id: codexModelId, name: codexModelId };
2722
- const codexModelKey = `${codexProviderName}/${codexModelId}`;
2723
-
2743
+ // 写入 Codex provider(单一模式下仍写入,保证配置完整)
2724
2744
  config.models.providers[codexProviderName] = {
2725
2745
  baseUrl: codexBaseUrl,
2726
2746
  auth: DEFAULT_AUTH_MODE,
@@ -2739,27 +2759,34 @@ async function autoActivate(paths, args = {}) {
2739
2759
  config.agents.defaults.models[codexModelKey] = { alias: codexProviderName };
2740
2760
 
2741
2761
  // ---- 选择主力 ----
2742
- let primaryType = 'claude';
2743
- if (args.primary === 'claude') {
2744
- primaryType = 'claude';
2745
- } else if (args.primary === 'codex') {
2746
- primaryType = 'codex';
2762
+ let primaryModelKey, fallbackModelKey;
2763
+ if (isSingleMode) {
2764
+ // 单一模式:直接用 Claude provider 作为 primary,不需要用户选
2765
+ primaryModelKey = claudeModelKey;
2766
+ fallbackModelKey = codexModelKey;
2747
2767
  } else {
2748
- const { picked } = await inquirer.prompt([{
2749
- type: 'list',
2750
- name: 'picked',
2751
- message: '选择主力工具(默认启动哪个):',
2752
- choices: [
2753
- { name: 'Claude Code', value: 'claude' },
2754
- { name: 'Codex (GPT)', value: 'codex' }
2755
- ]
2756
- }]);
2757
- primaryType = picked;
2768
+ let primaryType = 'claude';
2769
+ if (args.primary === 'claude') {
2770
+ primaryType = 'claude';
2771
+ } else if (args.primary === 'codex') {
2772
+ primaryType = 'codex';
2773
+ } else {
2774
+ const { picked } = await inquirer.prompt([{
2775
+ type: 'list',
2776
+ name: 'picked',
2777
+ message: '选择主力工具(默认启动哪个):',
2778
+ choices: [
2779
+ { name: 'Claude Code', value: 'claude' },
2780
+ { name: 'Codex (GPT)', value: 'codex' }
2781
+ ]
2782
+ }]);
2783
+ primaryType = picked;
2784
+ }
2785
+ primaryModelKey = primaryType === 'claude' ? claudeModelKey : codexModelKey;
2786
+ fallbackModelKey = primaryType === 'claude' ? codexModelKey : claudeModelKey;
2758
2787
  }
2759
2788
 
2760
- const primaryModelKey = primaryType === 'claude' ? claudeModelKey : codexModelKey;
2761
2789
  config.agents.defaults.model.primary = primaryModelKey;
2762
- const fallbackModelKey = primaryType === 'claude' ? codexModelKey : claudeModelKey;
2763
2790
  config.agents.defaults.model.fallbacks = [fallbackModelKey];
2764
2791
 
2765
2792
  // ---- 写入配置 ----
@@ -2775,13 +2802,19 @@ async function autoActivate(paths, args = {}) {
2775
2802
  writeSpinner.succeed('配置写入完成');
2776
2803
 
2777
2804
  // ---- 输出结果 ----
2778
- const primaryTag = primaryType === 'claude' ? ' (主)' : '';
2779
- const codexTag = primaryType === 'codex' ? ' (主)' : '';
2780
2805
  console.log(chalk.green('\n✅ 一键激活完成!'));
2781
- console.log(chalk.cyan(` Claude Code${primaryTag}: ${claudeBaseUrl}`));
2782
- console.log(chalk.gray(` 模型: ${claudeModel.name}`));
2783
- console.log(chalk.cyan(` Codex${codexTag}: ${codexBaseUrl}`));
2784
- console.log(chalk.gray(` 模型: ${codexModel.name}`));
2806
+ if (isSingleMode) {
2807
+ console.log(chalk.cyan(` 节点: ${selectedEndpoint.url}`));
2808
+ console.log(chalk.gray(` 模型: ${claudeModel.name}`));
2809
+ } else {
2810
+ const primaryType = primaryModelKey === claudeModelKey ? 'claude' : 'codex';
2811
+ const primaryTag = primaryType === 'claude' ? ' (主)' : '';
2812
+ const codexTag = primaryType === 'codex' ? ' (主)' : '';
2813
+ console.log(chalk.cyan(` Claude Code${primaryTag}: ${claudeBaseUrl}`));
2814
+ console.log(chalk.gray(` 模型: ${claudeModel.name}`));
2815
+ console.log(chalk.cyan(` Codex${codexTag}: ${codexBaseUrl}`));
2816
+ console.log(chalk.gray(` 模型: ${codexModel.name}`));
2817
+ }
2785
2818
  console.log(chalk.gray(' API Key: 已设置'));
2786
2819
  if (extSynced.length > 0) console.log(chalk.gray(` 同步: ${extSynced.join(', ')}`));
2787
2820
 
@@ -3665,8 +3698,7 @@ async function testConnection(paths, args = {}) {
3665
3698
  console.log(chalk.yellow('⚠️ 请先设置主模型'));
3666
3699
  return;
3667
3700
  }
3668
- // 优先选云翼/maxapi provider
3669
- const preferOrder = ['claude-yunyi', 'yunyi', 'heibai'];
3701
+ const preferOrder = ['maxapi', 'heibai', 'claude-yunyi', 'yunyi', 'maxapi-codex'];
3670
3702
  const preferred = preferOrder.find(n => providerNames.includes(n));
3671
3703
  const firstP = preferred || providerNames.find(n => n.includes('claude')) || providerNames[0];
3672
3704
  const firstModels = providers[firstP]?.models || [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yymaxapi",
3
- "version": "1.0.50",
3
+ "version": "1.0.52",
4
4
  "description": "跨平台 OpenClaw/Clawdbot 配置管理工具 - 管理中转地址、模型切换、API Keys、测速优化",
5
5
  "main": "bin/yymaxapi.js",
6
6
  "bin": {