yymaxapi 1.0.65 → 1.0.67

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 +87 -38
  2. package/package.json +1 -1
package/bin/yymaxapi.js CHANGED
@@ -634,8 +634,9 @@ function writeClaudeCodeSettings(baseUrl, apiKey) {
634
634
  // 写入 shell 环境变量
635
635
  if (process.platform === 'win32') {
636
636
  try {
637
+ const cleanUrl = baseUrl.replace(/\/+$/, '');
637
638
  execSync(
638
- `powershell -NoProfile -Command "[Environment]::SetEnvironmentVariable('ANTHROPIC_BASE_URL','${baseUrl.replace(/\/+$/, '')}','User'); [Environment]::SetEnvironmentVariable('ANTHROPIC_AUTH_TOKEN','${apiKey}','User')"`,
639
+ `powershell -NoProfile -Command "[Environment]::SetEnvironmentVariable('ANTHROPIC_BASE_URL','${cleanUrl}','User'); [Environment]::SetEnvironmentVariable('ANTHROPIC_AUTH_TOKEN','${apiKey}','User'); [Environment]::SetEnvironmentVariable('NODE_TLS_REJECT_UNAUTHORIZED','0','User')"`,
639
640
  { stdio: 'pipe' }
640
641
  );
641
642
  } catch { /* best-effort */ }
@@ -643,7 +644,14 @@ function writeClaudeCodeSettings(baseUrl, apiKey) {
643
644
  const marker = '# >>> yymaxapi claude >>>';
644
645
  const markerEnd = '# <<< yymaxapi claude <<<';
645
646
  const cleanUrl = baseUrl.replace(/\/+$/, '');
646
- const block = [marker, `export ANTHROPIC_BASE_URL="${cleanUrl}"`, `export ANTHROPIC_AUTH_TOKEN="${apiKey}"`, markerEnd].join('\n');
647
+ const block = [
648
+ marker,
649
+ `export ANTHROPIC_BASE_URL="${cleanUrl}"`,
650
+ `export ANTHROPIC_AUTH_TOKEN="${apiKey}"`,
651
+ '# 中转站证书校验放宽,避免 unknown certificate verification error',
652
+ 'export NODE_TLS_REJECT_UNAUTHORIZED=0',
653
+ markerEnd
654
+ ].join('\n');
647
655
 
648
656
  const shellEnv = process.env.SHELL || '';
649
657
  const rcFiles = [];
@@ -718,6 +726,8 @@ function writeCodexConfig(baseUrl, apiKey) {
718
726
 
719
727
  function writeOpencodeConfig(claudeBaseUrl, codexBaseUrl, apiKey, modelId) {
720
728
  const home = os.homedir();
729
+
730
+ // ---- 1. opencode.json (CLI + 桌面版) ----
721
731
  const configDir = process.platform === 'win32'
722
732
  ? path.join(process.env.APPDATA || path.join(home, 'AppData', 'Roaming'), 'opencode')
723
733
  : path.join(home, '.config', 'opencode');
@@ -729,21 +739,14 @@ function writeOpencodeConfig(claudeBaseUrl, codexBaseUrl, apiKey, modelId) {
729
739
  try { existing = JSON.parse(fs.readFileSync(configPath, 'utf8')); } catch { existing = {}; }
730
740
  }
731
741
  const cleanClaudeUrl = claudeBaseUrl.replace(/\/+$/, '');
732
- let cleanCodexUrl = (codexBaseUrl || '').replace(/\/+$/, '');
733
- if (cleanCodexUrl && !cleanCodexUrl.endsWith('/v1')) cleanCodexUrl += '/v1';
742
+ const cleanCodexUrl = (codexBaseUrl || '').replace(/\/+$/, '');
734
743
  if (!existing.provider) existing.provider = {};
735
744
  existing.provider.anthropic = {
736
- options: {
737
- apiKey: apiKey,
738
- baseURL: cleanClaudeUrl
739
- }
745
+ options: { apiKey: apiKey, baseURL: cleanClaudeUrl }
740
746
  };
741
747
  if (cleanCodexUrl) {
742
748
  existing.provider.openai = {
743
- options: {
744
- apiKey: apiKey,
745
- baseURL: cleanCodexUrl
746
- }
749
+ options: { apiKey: apiKey, baseURL: cleanCodexUrl }
747
750
  };
748
751
  }
749
752
  const rawModelId = modelId || 'claude-sonnet-4-6';
@@ -752,10 +755,68 @@ function writeOpencodeConfig(claudeBaseUrl, codexBaseUrl, apiKey, modelId) {
752
755
  : `anthropic/${rawModelId}`;
753
756
  if (!existing.$schema) existing.$schema = 'https://opencode.ai/config.json';
754
757
  fs.writeFileSync(configPath, JSON.stringify(existing, null, 2), 'utf8');
755
- return configPath;
756
- } catch {
757
- return null;
758
- }
758
+ } catch { /* 非关键,静默失败 */ }
759
+
760
+ // ---- 2. ~/.codex/config.toml (opencode 也读此格式) ----
761
+ const codexDir = path.join(home, '.codex');
762
+ const codexConfigPath = path.join(codexDir, 'config.toml');
763
+ try {
764
+ if (!fs.existsSync(codexDir)) fs.mkdirSync(codexDir, { recursive: true });
765
+
766
+ const claudeUrl = claudeBaseUrl.replace(/\/+$/, '');
767
+ const codexUrl = (codexBaseUrl || '').replace(/\/+$/, '');
768
+
769
+ const marker = '# >>> yunyi opencode >>>';
770
+ const markerEnd = '# <<< yunyi opencode <<<';
771
+ let existing = '';
772
+ if (fs.existsSync(codexConfigPath)) {
773
+ existing = fs.readFileSync(codexConfigPath, 'utf8');
774
+ const re = new RegExp(`${marker.replace(/[.*+?^${}()|[\\]\\]/g, '\\$&')}[\\s\\S]*?${markerEnd.replace(/[.*+?^${}()|[\\]\\]/g, '\\$&')}\\n?`, 'g');
775
+ existing = existing.replace(re, '').trim();
776
+ }
777
+
778
+ const section = [
779
+ marker,
780
+ `model = "yunyi-claude/claude-sonnet-4-6"`,
781
+ `model_provider = "yunyi-claude"`,
782
+ `model_context_window = 1000000`,
783
+ `model_auto_compact_token_limit = 900000`,
784
+ `model_reasoning_effort = "xhigh"`,
785
+ '',
786
+ `[model_providers.yunyi-claude]`,
787
+ `name = "云翼 Claude"`,
788
+ `base_url = "${claudeUrl}"`,
789
+ `wire_api = "anthropic"`,
790
+ `env_key = "ANTHROPIC_API_KEY"`,
791
+ ];
792
+
793
+ if (codexUrl) {
794
+ section.push(
795
+ '',
796
+ `[model_providers.yunyi-codex]`,
797
+ `name = "云翼 Codex"`,
798
+ `base_url = "${codexUrl}"`,
799
+ `wire_api = "responses"`,
800
+ `requires_openai_auth = true`,
801
+ `env_key = "OPENAI_API_KEY"`,
802
+ );
803
+ }
804
+
805
+ section.push(markerEnd);
806
+ fs.writeFileSync(codexConfigPath, existing ? `${existing}\n\n${section.join('\n')}\n` : `${section.join('\n')}\n`, 'utf8');
807
+
808
+ // ~/.codex/auth.json
809
+ const authPath = path.join(codexDir, 'auth.json');
810
+ let auth = {};
811
+ if (fs.existsSync(authPath)) {
812
+ try { auth = JSON.parse(fs.readFileSync(authPath, 'utf8')); } catch { auth = {}; }
813
+ }
814
+ auth.ANTHROPIC_API_KEY = apiKey;
815
+ auth.OPENAI_API_KEY = apiKey;
816
+ fs.writeFileSync(authPath, JSON.stringify(auth, null, 2), 'utf8');
817
+ } catch { /* 非关键,静默失败 */ }
818
+
819
+ return configPath;
759
820
  }
760
821
 
761
822
  function syncExternalTools(type, baseUrl, apiKey, extra = {}) {
@@ -2778,6 +2839,8 @@ async function autoActivate(paths, args = {}) {
2778
2839
  console.log(chalk.gray(` 节点: ${selectedEndpoint.url} (${selectedEndpoint.name})`));
2779
2840
  console.log(chalk.gray(' API Key: 已设置'));
2780
2841
  if (extSynced.length > 0) console.log(chalk.gray(` 同步: ${extSynced.join(', ')}`));
2842
+ console.log(chalk.gray(' 若遇 certificate 报错,请新开终端或执行 source ~/.zshrc 后重试(已放宽 TLS 校验)'));
2843
+ console.log(chalk.gray(' 使用 OpenCode 时可在界面中切换 Claude Sonnet 4.6 / GPT 5.4;Codex 仅支持 GPT'));
2781
2844
 
2782
2845
  const gwPort = config.gateway?.port || 18789;
2783
2846
  const gwToken = config.gateway?.auth?.token;
@@ -2957,11 +3020,13 @@ async function activateOpencode(paths, args = {}) {
2957
3020
  console.log(chalk.green('\n✅ Opencode 配置完成!'));
2958
3021
  console.log(chalk.cyan(` Claude: ${claudeBaseUrl}`));
2959
3022
  console.log(chalk.cyan(` Codex: ${codexBaseUrl}`));
2960
- console.log(chalk.gray(` 模型: ${modelId}`));
3023
+ console.log(chalk.gray(` 默认模型: anthropic/${modelId}`));
2961
3024
  console.log(chalk.gray(' API Key: 已设置'));
2962
- if (configPath) {
2963
- console.log(chalk.gray(` 配置文件: ${configPath}`));
2964
- }
3025
+ console.log(chalk.gray('\n 已写入:'));
3026
+ console.log(chalk.gray(' ~/.config/opencode/opencode.json (CLI + 桌面版)'));
3027
+ console.log(chalk.gray(' • ~/.codex/config.toml (model_providers)'));
3028
+ console.log(chalk.gray(' • ~/.codex/auth.json (API Keys)'));
3029
+ console.log(chalk.yellow('\n 切换模型: 在 opencode 内使用 /model 命令切换 claude/gpt'));
2965
3030
  }
2966
3031
 
2967
3032
  // ============ yycode 精简模式(零交互一键配置) ============
@@ -3702,24 +3767,8 @@ async function testConnection(paths, args = {}) {
3702
3767
  // 检查当前激活的是哪个
3703
3768
  let primary = config.agents?.defaults?.model?.primary || '';
3704
3769
  if (!primary.includes('/')) {
3705
- // primary 未设置,尝试从已有 provider 自动选择
3706
- const providers = config.models?.providers || {};
3707
- const providerNames = Object.keys(providers);
3708
- if (providerNames.length === 0) {
3709
- console.log(chalk.yellow('⚠️ 请先设置主模型'));
3710
- return;
3711
- }
3712
- const preferOrder = ['maxapi', 'heibai', 'claude-yunyi', 'yunyi', 'maxapi-codex'];
3713
- const preferred = preferOrder.find(n => providerNames.includes(n));
3714
- const firstP = preferred || providerNames.find(n => n.includes('claude')) || providerNames[0];
3715
- const firstModels = providers[firstP]?.models || [];
3716
- if (firstModels.length > 0) {
3717
- primary = `${firstP}/${firstModels[0].id}`;
3718
- console.log(chalk.yellow(`⚠️ 主模型未设置,自动使用: ${primary}`));
3719
- } else {
3720
- console.log(chalk.yellow('⚠️ 请先设置主模型'));
3721
- return;
3722
- }
3770
+ console.log(chalk.yellow('⚠️ 主模型未设置,请先通过「切换模型」或「一键配置」设置主模型'));
3771
+ return;
3723
3772
  }
3724
3773
 
3725
3774
  const providerName = primary.split('/')[0];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yymaxapi",
3
- "version": "1.0.65",
3
+ "version": "1.0.67",
4
4
  "description": "跨平台 OpenClaw/Clawdbot 配置管理工具 - 管理中转地址、模型切换、API Keys、测速优化",
5
5
  "main": "bin/yymaxapi.js",
6
6
  "bin": {