yymaxapi 1.0.77 → 1.0.79

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 +41 -32
  2. package/package.json +1 -1
package/bin/yymaxapi.js CHANGED
@@ -680,11 +680,15 @@ function writeCodexConfig(baseUrl, apiKey, modelId = 'gpt-5.4') {
680
680
  const codexDir = path.join(os.homedir(), '.codex');
681
681
  if (!fs.existsSync(codexDir)) fs.mkdirSync(codexDir, { recursive: true });
682
682
 
683
- // ~/.codex/config.toml — section marker 管理
683
+ // ~/.codex/config.toml — 顶层设置和 section 分开管理
684
+ // TOML 规范:[section] 之后的 key=value 属于该 section,不是顶层
685
+ // 所以 model / model_provider 必须在所有 [section] 之前
684
686
  const configPath = path.join(codexDir, 'config.toml');
685
687
  const marker = '# >>> maxapi codex >>>';
686
688
  const markerEnd = '# <<< maxapi codex <<<';
687
- const providerKey = 'openclaw-relay';
689
+ const topMarker = '# >>> maxapi codex top >>>';
690
+ const topMarkerEnd = '# <<< maxapi codex top <<<';
691
+ const providerKey = 'yunyi-codex';
688
692
  // 确保 base_url 以 /v1 结尾(Codex CLI 要求)
689
693
  let normalizedUrl = baseUrl.replace(/\/+$/, '');
690
694
  if (!normalizedUrl.endsWith('/v1')) normalizedUrl += '/v1';
@@ -692,24 +696,46 @@ function writeCodexConfig(baseUrl, apiKey, modelId = 'gpt-5.4') {
692
696
  let existing = '';
693
697
  if (fs.existsSync(configPath)) {
694
698
  existing = fs.readFileSync(configPath, 'utf8');
695
- // 移除旧的 maxapi section
699
+ // 移除旧的 maxapi section(provider block)
696
700
  const re = new RegExp(`${marker.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[\\s\\S]*?${markerEnd.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\n?`, 'g');
697
- existing = existing.replace(re, '').trim();
698
- }
699
- const section = [
700
- marker,
701
+ existing = existing.replace(re, '');
702
+ // 移除旧的 maxapi top-level block
703
+ const topRe = new RegExp(`${topMarker.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[\\s\\S]*?${topMarkerEnd.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\n?`, 'g');
704
+ existing = existing.replace(topRe, '');
705
+ // 兼容旧版:移除散落的 model/model_provider、旧 openclaw-relay、旧 yunyi opencode 标记块
706
+ existing = existing.replace(/^model\s*=\s*"[^"]*"\s*$/gm, '');
707
+ existing = existing.replace(/^model_provider\s*=\s*"[^"]*"\s*$/gm, '');
708
+ existing = existing.replace(/\[model_providers\.openclaw-relay\]\n(?:(?!\[)[^\n]*\n?)*/g, '');
709
+ existing = existing.replace(/# >>> yunyi opencode >>>[\s\S]*?# <<< yunyi opencode <<<\n?/g, '');
710
+ existing = existing.replace(/\n{3,}/g, '\n\n').trim();
711
+ }
712
+
713
+ // 顶层设置(MUST 在所有 [section] 之前)
714
+ const topBlock = [
715
+ topMarker,
701
716
  `model = "${modelId}"`,
702
717
  `model_provider = "${providerKey}"`,
703
- ``,
718
+ topMarkerEnd
719
+ ].join('\n');
720
+
721
+ // Provider section(追加在文件末尾)
722
+ const providerBlock = [
723
+ marker,
704
724
  `[model_providers.${providerKey}]`,
705
- `name = "OpenClaw Relay"`,
725
+ `name = "云翼 Codex"`,
706
726
  `base_url = "${normalizedUrl}"`,
707
727
  `wire_api = "responses"`,
708
728
  `experimental_bearer_token = "${apiKey}"`,
709
- `requires_openai_auth = true`,
710
729
  markerEnd
711
730
  ].join('\n');
712
- const content = existing ? `${existing}\n\n${section}\n` : `${section}\n`;
731
+
732
+ // 组装:顶层设置 → 原有内容 → provider section
733
+ let content;
734
+ if (existing) {
735
+ content = `${topBlock}\n\n${existing}\n\n${providerBlock}\n`;
736
+ } else {
737
+ content = `${topBlock}\n\n${providerBlock}\n`;
738
+ }
713
739
  fs.writeFileSync(configPath, content, 'utf8');
714
740
  } catch { /* 非关键,静默失败 */ }
715
741
 
@@ -795,31 +821,14 @@ function writeOpencodeConfig(claudeBaseUrl, codexBaseUrl, apiKey, modelId) {
795
821
  // 移除旧标记块(仅移除 yunyi opencode 自己的)
796
822
  content = content.replace(/# >>> yunyi opencode >>>[\s\S]*?# <<< yunyi opencode <<<\n?/g, '');
797
823
 
798
- // 移除旧的 yunyi model_providers 段落(包括 yunyi-cli 写入的 [model_providers.yunyi]
799
- content = content.replace(/\[model_providers\.yunyi[^\]]*\]\n(?:(?!\[)[^\n]*\n?)*/g, '');
800
-
801
- // 只追加 yunyi-codex provider(Claude 配置仅在 opencode.json 中,Codex CLI 不支持 wire_api=anthropic)
802
- const providers = [''];
803
- if (codexUrl) {
804
- providers.push(
805
- '# >>> yunyi opencode >>>',
806
- '[model_providers.yunyi-codex]',
807
- 'name = "云翼 Codex"',
808
- `base_url = "${codexUrl}"`,
809
- 'wire_api = "responses"',
810
- `experimental_bearer_token = "${apiKey}"`,
811
- 'requires_openai_auth = true',
812
- '# <<< yunyi opencode <<<'
813
- );
814
- }
824
+ // 移除旧版 yunyi-cli 写入的 [model_providers.yunyi] 和 [model_providers.yunyi-claude](不动 yunyi-codex,由 writeCodexConfig 管理)
825
+ content = content.replace(/\[model_providers\.yunyi\]\n(?:(?!\[)[^\n]*\n?)*/g, '');
826
+ content = content.replace(/\[model_providers\.yunyi-claude\]\n(?:(?!\[)[^\n]*\n?)*/g, '');
815
827
 
816
828
  // 清理多余空行
817
829
  content = content.replace(/\n{3,}/g, '\n\n').trim();
818
830
 
819
- // 追加 provider section
820
- if (providers.length > 1) {
821
- content += '\n\n' + providers.join('\n') + '\n';
822
- }
831
+ // yunyi-codex provider 由 writeCodexConfig 统一管理,此处不再重复写入
823
832
 
824
833
  fs.writeFileSync(codexConfigPath, content, 'utf8');
825
834
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yymaxapi",
3
- "version": "1.0.77",
3
+ "version": "1.0.79",
4
4
  "description": "跨平台 OpenClaw/Clawdbot 配置管理工具 - 管理中转地址、模型切换、API Keys、测速优化",
5
5
  "main": "bin/yymaxapi.js",
6
6
  "bin": {