yymaxapi 1.0.50 → 1.0.51

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 +96 -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,23 @@ function coerceModelsRecord(value) {
1184
1182
  return record;
1185
1183
  }
1186
1184
 
1185
+ const OPENCLAW_KNOWN_ROOT_KEYS = new Set([
1186
+ 'models', 'agents', 'auth', 'gateway', 'tools',
1187
+ 'channels', 'mcpServers', 'globalShortcut', 'customModes',
1188
+ 'permissions', 'proxy', 'env', 'hooks', 'storage',
1189
+ ]);
1190
+
1191
+ function sanitizeRootKeys(config) {
1192
+ for (const key of Object.keys(config)) {
1193
+ if (!OPENCLAW_KNOWN_ROOT_KEYS.has(key)) {
1194
+ delete config[key];
1195
+ }
1196
+ }
1197
+ }
1198
+
1187
1199
  function ensureConfigStructure(config) {
1188
1200
  const next = config || {};
1201
+ sanitizeRootKeys(next);
1189
1202
  if (!next.models) next.models = {};
1190
1203
  if (!next.models.providers) next.models.providers = {};
1191
1204
  if (!next.agents) next.agents = {};
@@ -2668,25 +2681,54 @@ async function autoActivate(paths, args = {}) {
2668
2681
  // ---- 构建配置 ----
2669
2682
  const config = ensureConfigStructure(readConfig(paths.openclawConfig) || {});
2670
2683
 
2671
- // 增量写入: 只添加/更新云翼 provider,保留其他已有配置
2672
-
2673
- // Claude 侧 — 让用户选模型
2674
2684
  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;
2685
+ const codexBaseUrl = buildFullUrl(selectedEndpoint.url, 'codex');
2686
+
2687
+ // 检测单一模式:Claude Codex 只有一个模型且 id 相同(如 maxapi 的 heibai)
2688
+ const isSingleMode = CLAUDE_MODELS.length === 1 && CODEX_MODELS.length === 1
2689
+ && CLAUDE_MODELS[0].id === CODEX_MODELS[0].id;
2690
+
2691
+ let claudeModelId, codexModelId;
2692
+
2693
+ if (isSingleMode) {
2694
+ // 单一模式:固定模型,不选择,不分 Claude/Codex
2695
+ claudeModelId = CLAUDE_MODELS[0].id;
2696
+ codexModelId = CODEX_MODELS[0].id;
2697
+ } else {
2698
+ // 多模型模式:让用户选模型
2699
+ claudeModelId = (args['claude-model'] || '').toString().trim();
2700
+ if (!claudeModelId && CLAUDE_MODELS.length > 1) {
2701
+ const { picked } = await inquirer.prompt([{
2702
+ type: 'list',
2703
+ name: 'picked',
2704
+ message: '选择 Claude 模型:',
2705
+ choices: CLAUDE_MODELS.map(m => ({ name: m.name, value: m.id })),
2706
+ default: CLAUDE_MODELS[0].id
2707
+ }]);
2708
+ claudeModelId = picked;
2709
+ }
2710
+ if (!claudeModelId) claudeModelId = CLAUDE_MODELS[0]?.id || 'claude-sonnet-4-6';
2711
+
2712
+ codexModelId = (args['codex-model'] || '').toString().trim();
2713
+ if (!codexModelId && CODEX_MODELS.length > 1) {
2714
+ const { pickedCodex } = await inquirer.prompt([{
2715
+ type: 'list',
2716
+ name: 'pickedCodex',
2717
+ message: '选择 Codex 模型:',
2718
+ choices: CODEX_MODELS.map(m => ({ name: m.name, value: m.id })),
2719
+ default: CODEX_MODELS[0].id
2720
+ }]);
2721
+ codexModelId = pickedCodex;
2722
+ }
2723
+ if (!codexModelId) codexModelId = CODEX_MODELS[0]?.id || 'gpt-5.3-codex';
2685
2724
  }
2686
- if (!claudeModelId) claudeModelId = CLAUDE_MODELS[0]?.id || 'claude-sonnet-4-6';
2725
+
2687
2726
  const claudeModel = CLAUDE_MODELS.find(m => m.id === claudeModelId) || { id: claudeModelId, name: claudeModelId };
2727
+ const codexModel = CODEX_MODELS.find(m => m.id === codexModelId) || { id: codexModelId, name: codexModelId };
2688
2728
  const claudeModelKey = `${claudeProviderName}/${claudeModelId}`;
2729
+ const codexModelKey = `${codexProviderName}/${codexModelId}`;
2689
2730
 
2731
+ // 写入 Claude provider
2690
2732
  config.models.providers[claudeProviderName] = {
2691
2733
  baseUrl: claudeBaseUrl,
2692
2734
  auth: DEFAULT_AUTH_MODE,
@@ -2704,23 +2746,7 @@ async function autoActivate(paths, args = {}) {
2704
2746
  config.auth.profiles[`${claudeProviderName}:default`] = { provider: claudeProviderName, mode: 'api_key' };
2705
2747
  config.agents.defaults.models[claudeModelKey] = { alias: claudeProviderName };
2706
2748
 
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
-
2749
+ // 写入 Codex provider(单一模式下仍写入,保证配置完整)
2724
2750
  config.models.providers[codexProviderName] = {
2725
2751
  baseUrl: codexBaseUrl,
2726
2752
  auth: DEFAULT_AUTH_MODE,
@@ -2739,27 +2765,34 @@ async function autoActivate(paths, args = {}) {
2739
2765
  config.agents.defaults.models[codexModelKey] = { alias: codexProviderName };
2740
2766
 
2741
2767
  // ---- 选择主力 ----
2742
- let primaryType = 'claude';
2743
- if (args.primary === 'claude') {
2744
- primaryType = 'claude';
2745
- } else if (args.primary === 'codex') {
2746
- primaryType = 'codex';
2768
+ let primaryModelKey, fallbackModelKey;
2769
+ if (isSingleMode) {
2770
+ // 单一模式:直接用 Claude provider 作为 primary,不需要用户选
2771
+ primaryModelKey = claudeModelKey;
2772
+ fallbackModelKey = codexModelKey;
2747
2773
  } 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;
2774
+ let primaryType = 'claude';
2775
+ if (args.primary === 'claude') {
2776
+ primaryType = 'claude';
2777
+ } else if (args.primary === 'codex') {
2778
+ primaryType = 'codex';
2779
+ } else {
2780
+ const { picked } = await inquirer.prompt([{
2781
+ type: 'list',
2782
+ name: 'picked',
2783
+ message: '选择主力工具(默认启动哪个):',
2784
+ choices: [
2785
+ { name: 'Claude Code', value: 'claude' },
2786
+ { name: 'Codex (GPT)', value: 'codex' }
2787
+ ]
2788
+ }]);
2789
+ primaryType = picked;
2790
+ }
2791
+ primaryModelKey = primaryType === 'claude' ? claudeModelKey : codexModelKey;
2792
+ fallbackModelKey = primaryType === 'claude' ? codexModelKey : claudeModelKey;
2758
2793
  }
2759
2794
 
2760
- const primaryModelKey = primaryType === 'claude' ? claudeModelKey : codexModelKey;
2761
2795
  config.agents.defaults.model.primary = primaryModelKey;
2762
- const fallbackModelKey = primaryType === 'claude' ? codexModelKey : claudeModelKey;
2763
2796
  config.agents.defaults.model.fallbacks = [fallbackModelKey];
2764
2797
 
2765
2798
  // ---- 写入配置 ----
@@ -2775,13 +2808,19 @@ async function autoActivate(paths, args = {}) {
2775
2808
  writeSpinner.succeed('配置写入完成');
2776
2809
 
2777
2810
  // ---- 输出结果 ----
2778
- const primaryTag = primaryType === 'claude' ? ' (主)' : '';
2779
- const codexTag = primaryType === 'codex' ? ' (主)' : '';
2780
2811
  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}`));
2812
+ if (isSingleMode) {
2813
+ console.log(chalk.cyan(` 节点: ${selectedEndpoint.url}`));
2814
+ console.log(chalk.gray(` 模型: ${claudeModel.name}`));
2815
+ } else {
2816
+ const primaryType = primaryModelKey === claudeModelKey ? 'claude' : 'codex';
2817
+ const primaryTag = primaryType === 'claude' ? ' (主)' : '';
2818
+ const codexTag = primaryType === 'codex' ? ' (主)' : '';
2819
+ console.log(chalk.cyan(` Claude Code${primaryTag}: ${claudeBaseUrl}`));
2820
+ console.log(chalk.gray(` 模型: ${claudeModel.name}`));
2821
+ console.log(chalk.cyan(` Codex${codexTag}: ${codexBaseUrl}`));
2822
+ console.log(chalk.gray(` 模型: ${codexModel.name}`));
2823
+ }
2785
2824
  console.log(chalk.gray(' API Key: 已设置'));
2786
2825
  if (extSynced.length > 0) console.log(chalk.gray(` 同步: ${extSynced.join(', ')}`));
2787
2826
 
@@ -3665,8 +3704,7 @@ async function testConnection(paths, args = {}) {
3665
3704
  console.log(chalk.yellow('⚠️ 请先设置主模型'));
3666
3705
  return;
3667
3706
  }
3668
- // 优先选云翼/maxapi provider
3669
- const preferOrder = ['claude-yunyi', 'yunyi', 'heibai'];
3707
+ const preferOrder = ['maxapi', 'heibai', 'claude-yunyi', 'yunyi', 'maxapi-codex'];
3670
3708
  const preferred = preferOrder.find(n => providerNames.includes(n));
3671
3709
  const firstP = preferred || providerNames.find(n => n.includes('claude')) || providerNames[0];
3672
3710
  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.51",
4
4
  "description": "跨平台 OpenClaw/Clawdbot 配置管理工具 - 管理中转地址、模型切换、API Keys、测速优化",
5
5
  "main": "bin/yymaxapi.js",
6
6
  "bin": {