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.
- package/bin/yymaxapi.js +87 -38
- 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','${
|
|
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 = [
|
|
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
|
-
|
|
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
|
-
|
|
756
|
-
|
|
757
|
-
|
|
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(`
|
|
3023
|
+
console.log(chalk.gray(` 默认模型: anthropic/${modelId}`));
|
|
2961
3024
|
console.log(chalk.gray(' API Key: 已设置'));
|
|
2962
|
-
|
|
2963
|
-
|
|
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
|
-
|
|
3706
|
-
|
|
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];
|