yymaxapi 1.0.67 → 1.0.68
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 +92 -44
- package/package.json +1 -1
package/bin/yymaxapi.js
CHANGED
|
@@ -726,6 +726,8 @@ function writeCodexConfig(baseUrl, apiKey) {
|
|
|
726
726
|
|
|
727
727
|
function writeOpencodeConfig(claudeBaseUrl, codexBaseUrl, apiKey, modelId) {
|
|
728
728
|
const home = os.homedir();
|
|
729
|
+
const claudeUrl = claudeBaseUrl.replace(/\/+$/, '');
|
|
730
|
+
const codexUrl = (codexBaseUrl || '').replace(/\/+$/, '');
|
|
729
731
|
|
|
730
732
|
// ---- 1. opencode.json (CLI + 桌面版) ----
|
|
731
733
|
const configDir = process.platform === 'win32'
|
|
@@ -738,21 +740,42 @@ function writeOpencodeConfig(claudeBaseUrl, codexBaseUrl, apiKey, modelId) {
|
|
|
738
740
|
if (fs.existsSync(configPath)) {
|
|
739
741
|
try { existing = JSON.parse(fs.readFileSync(configPath, 'utf8')); } catch { existing = {}; }
|
|
740
742
|
}
|
|
741
|
-
const cleanClaudeUrl = claudeBaseUrl.replace(/\/+$/, '');
|
|
742
|
-
const cleanCodexUrl = (codexBaseUrl || '').replace(/\/+$/, '');
|
|
743
743
|
if (!existing.provider) existing.provider = {};
|
|
744
|
-
|
|
745
|
-
|
|
744
|
+
|
|
745
|
+
// Claude provider (@ai-sdk/anthropic)
|
|
746
|
+
existing.provider['yunyi-claude'] = {
|
|
747
|
+
name: '云翼 Claude',
|
|
748
|
+
npm: '@ai-sdk/anthropic',
|
|
749
|
+
models: { 'claude-sonnet-4-6': { name: 'Claude Sonnet 4.6' } },
|
|
750
|
+
options: { apiKey, baseURL: `${claudeUrl}/v1` }
|
|
746
751
|
};
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
752
|
+
|
|
753
|
+
// Codex provider (@ai-sdk/openai)
|
|
754
|
+
if (codexUrl) {
|
|
755
|
+
existing.provider['yunyi-codex'] = {
|
|
756
|
+
name: '云翼 Codex',
|
|
757
|
+
npm: '@ai-sdk/openai',
|
|
758
|
+
models: { 'gpt-5.4': { name: 'GPT 5.4' } },
|
|
759
|
+
options: { apiKey, baseURL: codexUrl }
|
|
750
760
|
};
|
|
751
761
|
}
|
|
762
|
+
|
|
763
|
+
// 清理旧版写入的通用 provider 名(之前的 bug)
|
|
764
|
+
if (existing.provider.anthropic && existing.provider.anthropic.options
|
|
765
|
+
&& existing.provider.anthropic.options.baseURL && existing.provider.anthropic.options.baseURL.includes('yunyi')) {
|
|
766
|
+
delete existing.provider.anthropic;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// 设置默认模型
|
|
752
770
|
const rawModelId = modelId || 'claude-sonnet-4-6';
|
|
753
|
-
existing.model = rawModelId
|
|
754
|
-
|
|
755
|
-
|
|
771
|
+
existing.model = `yunyi-claude/${rawModelId}`;
|
|
772
|
+
|
|
773
|
+
// 从 disabled_providers 中移除我们的 provider
|
|
774
|
+
if (Array.isArray(existing.disabled_providers)) {
|
|
775
|
+
existing.disabled_providers = existing.disabled_providers.filter(p => p !== 'yunyi-claude' && p !== 'yunyi-codex');
|
|
776
|
+
if (existing.disabled_providers.length === 0) delete existing.disabled_providers;
|
|
777
|
+
}
|
|
778
|
+
|
|
756
779
|
if (!existing.$schema) existing.$schema = 'https://opencode.ai/config.json';
|
|
757
780
|
fs.writeFileSync(configPath, JSON.stringify(existing, null, 2), 'utf8');
|
|
758
781
|
} catch { /* 非关键,静默失败 */ }
|
|
@@ -763,49 +786,74 @@ function writeOpencodeConfig(claudeBaseUrl, codexBaseUrl, apiKey, modelId) {
|
|
|
763
786
|
try {
|
|
764
787
|
if (!fs.existsSync(codexDir)) fs.mkdirSync(codexDir, { recursive: true });
|
|
765
788
|
|
|
766
|
-
|
|
767
|
-
const codexUrl = (codexBaseUrl || '').replace(/\/+$/, '');
|
|
768
|
-
|
|
769
|
-
const marker = '# >>> yunyi opencode >>>';
|
|
770
|
-
const markerEnd = '# <<< yunyi opencode <<<';
|
|
771
|
-
let existing = '';
|
|
789
|
+
let content = '';
|
|
772
790
|
if (fs.existsSync(codexConfigPath)) {
|
|
773
|
-
|
|
774
|
-
const re = new RegExp(`${marker.replace(/[.*+?^${}()|[\\]\\]/g, '\\$&')}[\\s\\S]*?${markerEnd.replace(/[.*+?^${}()|[\\]\\]/g, '\\$&')}\\n?`, 'g');
|
|
775
|
-
existing = existing.replace(re, '').trim();
|
|
791
|
+
content = fs.readFileSync(codexConfigPath, 'utf8');
|
|
776
792
|
}
|
|
777
793
|
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
794
|
+
// 移除旧标记块(yunyi opencode / maxapi codex)
|
|
795
|
+
content = content.replace(/# >>> yunyi opencode >>>[\s\S]*?# <<< yunyi opencode <<<\n?/g, '');
|
|
796
|
+
content = content.replace(/# >>> maxapi codex >>>[\s\S]*?# <<< maxapi codex <<<\n?/g, '');
|
|
797
|
+
|
|
798
|
+
// 移除旧的 yunyi model_providers 段落(包括 yunyi-cli 写入的 [model_providers.yunyi])
|
|
799
|
+
content = content.replace(/\[model_providers\.yunyi[^\]]*\]\n(?:(?!\[)[^\n]*\n?)*/g, '');
|
|
800
|
+
|
|
801
|
+
// 替换或插入顶层设置
|
|
802
|
+
const topSettings = {
|
|
803
|
+
model_provider: '"yunyi-claude"',
|
|
804
|
+
model: '"claude-sonnet-4-6"',
|
|
805
|
+
model_context_window: '1000000',
|
|
806
|
+
model_auto_compact_token_limit: '900000',
|
|
807
|
+
model_reasoning_effort: '"xhigh"',
|
|
808
|
+
disable_response_storage: 'true',
|
|
809
|
+
};
|
|
810
|
+
for (const [key, value] of Object.entries(topSettings)) {
|
|
811
|
+
const re = new RegExp(`^${key}\\s*=\\s*[^\\n]*`, 'm');
|
|
812
|
+
if (re.test(content)) {
|
|
813
|
+
content = content.replace(re, `${key} = ${value}`);
|
|
814
|
+
} else {
|
|
815
|
+
// 插入到第一个 section 之前
|
|
816
|
+
const firstSection = content.search(/^\[/m);
|
|
817
|
+
if (firstSection > 0) {
|
|
818
|
+
content = content.slice(0, firstSection) + `${key} = ${value}\n` + content.slice(firstSection);
|
|
819
|
+
} else if (firstSection === 0) {
|
|
820
|
+
content = `${key} = ${value}\n` + content;
|
|
821
|
+
} else {
|
|
822
|
+
content += `${key} = ${value}\n`;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// 清理多余空行
|
|
828
|
+
content = content.replace(/\n{3,}/g, '\n\n').trim();
|
|
829
|
+
|
|
830
|
+
// 追加 model_providers 段落
|
|
831
|
+
const providers = [
|
|
785
832
|
'',
|
|
786
|
-
|
|
787
|
-
|
|
833
|
+
'# >>> yunyi opencode >>>',
|
|
834
|
+
'[model_providers.yunyi-claude]',
|
|
835
|
+
'name = "云翼 Claude"',
|
|
788
836
|
`base_url = "${claudeUrl}"`,
|
|
789
|
-
|
|
790
|
-
`
|
|
837
|
+
'wire_api = "anthropic"',
|
|
838
|
+
`experimental_bearer_token = "${apiKey}"`,
|
|
791
839
|
];
|
|
792
|
-
|
|
793
840
|
if (codexUrl) {
|
|
794
|
-
|
|
841
|
+
providers.push(
|
|
795
842
|
'',
|
|
796
|
-
|
|
797
|
-
|
|
843
|
+
'[model_providers.yunyi-codex]',
|
|
844
|
+
'name = "云翼 Codex"',
|
|
798
845
|
`base_url = "${codexUrl}"`,
|
|
799
|
-
|
|
800
|
-
`
|
|
801
|
-
|
|
846
|
+
'wire_api = "responses"',
|
|
847
|
+
`experimental_bearer_token = "${apiKey}"`,
|
|
848
|
+
'requires_openai_auth = true',
|
|
802
849
|
);
|
|
803
850
|
}
|
|
851
|
+
providers.push('# <<< yunyi opencode <<<');
|
|
852
|
+
content += '\n\n' + providers.join('\n') + '\n';
|
|
804
853
|
|
|
805
|
-
|
|
806
|
-
fs.writeFileSync(codexConfigPath, existing ? `${existing}\n\n${section.join('\n')}\n` : `${section.join('\n')}\n`, 'utf8');
|
|
854
|
+
fs.writeFileSync(codexConfigPath, content, 'utf8');
|
|
807
855
|
|
|
808
|
-
// ~/.codex/auth.json
|
|
856
|
+
// ---- 3. ~/.codex/auth.json ----
|
|
809
857
|
const authPath = path.join(codexDir, 'auth.json');
|
|
810
858
|
let auth = {};
|
|
811
859
|
if (fs.existsSync(authPath)) {
|
|
@@ -3018,15 +3066,15 @@ async function activateOpencode(paths, args = {}) {
|
|
|
3018
3066
|
writeSpinner.succeed('Opencode 配置写入完成');
|
|
3019
3067
|
|
|
3020
3068
|
console.log(chalk.green('\n✅ Opencode 配置完成!'));
|
|
3021
|
-
console.log(chalk.cyan(` Claude: ${claudeBaseUrl}`));
|
|
3022
|
-
console.log(chalk.cyan(` Codex: ${codexBaseUrl}`));
|
|
3023
|
-
console.log(chalk.gray(` 默认模型:
|
|
3069
|
+
console.log(chalk.cyan(` Claude: ${claudeBaseUrl} → claude-sonnet-4-6`));
|
|
3070
|
+
console.log(chalk.cyan(` Codex: ${codexBaseUrl} → gpt-5.4`));
|
|
3071
|
+
console.log(chalk.gray(` 默认模型: yunyi-claude/${modelId}`));
|
|
3024
3072
|
console.log(chalk.gray(' API Key: 已设置'));
|
|
3025
3073
|
console.log(chalk.gray('\n 已写入:'));
|
|
3026
3074
|
console.log(chalk.gray(' • ~/.config/opencode/opencode.json (CLI + 桌面版)'));
|
|
3027
3075
|
console.log(chalk.gray(' • ~/.codex/config.toml (model_providers)'));
|
|
3028
3076
|
console.log(chalk.gray(' • ~/.codex/auth.json (API Keys)'));
|
|
3029
|
-
console.log(chalk.yellow('\n 切换模型: 在 opencode 内使用 /model 命令切换 claude/
|
|
3077
|
+
console.log(chalk.yellow('\n 切换模型: 在 opencode 内使用 /model 命令切换 yunyi-claude / yunyi-codex'));
|
|
3030
3078
|
}
|
|
3031
3079
|
|
|
3032
3080
|
// ============ yycode 精简模式(零交互一键配置) ============
|