yymaxapi 1.0.104 → 1.0.109
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/README.md
CHANGED
|
@@ -8,8 +8,14 @@
|
|
|
8
8
|
```bash
|
|
9
9
|
npx yymaxapi@latest
|
|
10
10
|
```
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
按提示选择模型并输入 Key 即可,默认会直接使用预设默认节点。
|
|
12
|
+
主菜单已简化为:一键配置 / 配置外部工具 / 测速节点 / 测试连接 / 查看配置 / 恢复 / 退出。
|
|
13
|
+
|
|
14
|
+
**需要手动测速时**
|
|
15
|
+
```bash
|
|
16
|
+
npx yymaxapi@latest speed-test
|
|
17
|
+
```
|
|
18
|
+
或在具体配置命令后追加 `--speed-test`,按测速结果手动选点。
|
|
13
19
|
|
|
14
20
|
**方式二:一键配置 Claude**
|
|
15
21
|
```bash
|
package/bin/yymaxapi.js
CHANGED
|
@@ -607,6 +607,77 @@ async function testFallbackEndpoints() {
|
|
|
607
607
|
return testAllEndpoints(FALLBACK_EPS, { label: '检测备用节点', autoFallback: false });
|
|
608
608
|
}
|
|
609
609
|
|
|
610
|
+
function shouldRunEndpointSpeedTest(args = {}) {
|
|
611
|
+
const raw = args['speed-test'] !== undefined ? args['speed-test'] : args.speedTest;
|
|
612
|
+
if (raw === undefined) return false;
|
|
613
|
+
if (typeof raw === 'string') {
|
|
614
|
+
return !['false', '0', 'no'].includes(raw.toLowerCase());
|
|
615
|
+
}
|
|
616
|
+
return !!raw;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
async function resolveEndpointSelection(args = {}, options = {}) {
|
|
620
|
+
const defaultEndpoint = options.defaultEndpoint || ENDPOINTS[0];
|
|
621
|
+
if (!defaultEndpoint) return null;
|
|
622
|
+
if (!shouldRunEndpointSpeedTest(args)) return defaultEndpoint;
|
|
623
|
+
|
|
624
|
+
const speedIntro = options.speedIntro || '📡 开始测速节点...\n';
|
|
625
|
+
const proceedMessage = options.proceedMessage || '仍要写入默认节点配置吗?';
|
|
626
|
+
const chooseMessage = options.chooseMessage || '选择节点:';
|
|
627
|
+
|
|
628
|
+
console.log(chalk.cyan(`${speedIntro}`));
|
|
629
|
+
const speedResult = await testAllEndpoints(ENDPOINTS, { autoFallback: true });
|
|
630
|
+
const sorted = speedResult.ranked || [];
|
|
631
|
+
|
|
632
|
+
if (sorted.length > 0) {
|
|
633
|
+
const { selectedIndex } = await inquirer.prompt([{
|
|
634
|
+
type: 'list',
|
|
635
|
+
name: 'selectedIndex',
|
|
636
|
+
message: chooseMessage,
|
|
637
|
+
choices: [
|
|
638
|
+
{ name: `* 使用默认节点 (${defaultEndpoint.name})`, value: -1 },
|
|
639
|
+
new inquirer.Separator(' ---- 或按测速结果选择 ----'),
|
|
640
|
+
...sorted.map((endpoint, index) => ({
|
|
641
|
+
name: `${endpoint.name} - ${endpoint.latency}ms (评分:${endpoint.score})`,
|
|
642
|
+
value: index
|
|
643
|
+
}))
|
|
644
|
+
]
|
|
645
|
+
}]);
|
|
646
|
+
|
|
647
|
+
const selectedEndpoint = selectedIndex === -1 ? defaultEndpoint : sorted[selectedIndex];
|
|
648
|
+
if (speedResult.usedFallback) {
|
|
649
|
+
console.log(chalk.yellow('\n⚠ 当前使用备用节点\n'));
|
|
650
|
+
}
|
|
651
|
+
return selectedEndpoint;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
console.log(chalk.red('\n⚠️ 所有节点(含备用)均不可达'));
|
|
655
|
+
const { proceed } = await inquirer.prompt([{
|
|
656
|
+
type: 'confirm',
|
|
657
|
+
name: 'proceed',
|
|
658
|
+
message: proceedMessage,
|
|
659
|
+
default: false
|
|
660
|
+
}]);
|
|
661
|
+
if (!proceed) {
|
|
662
|
+
console.log(chalk.gray('已取消'));
|
|
663
|
+
return null;
|
|
664
|
+
}
|
|
665
|
+
return defaultEndpoint;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
async function speedTestNodes() {
|
|
669
|
+
console.log(chalk.cyan.bold('\n📡 节点测速\n'));
|
|
670
|
+
const speedResult = await testAllEndpoints(ENDPOINTS, { autoFallback: true });
|
|
671
|
+
const defaultEndpoint = ENDPOINTS[0];
|
|
672
|
+
|
|
673
|
+
if (defaultEndpoint) {
|
|
674
|
+
console.log(chalk.gray(`\n默认配置当前直连: ${defaultEndpoint.name} (${defaultEndpoint.url})`));
|
|
675
|
+
}
|
|
676
|
+
if (speedResult.best && defaultEndpoint && speedResult.best.url !== defaultEndpoint.url) {
|
|
677
|
+
console.log(chalk.yellow('如需按测速结果选点,可在对应配置命令后追加 --speed-test'));
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
610
681
|
// ============ API Key 验证 ============
|
|
611
682
|
function httpGetJson(url, headers = {}, timeout = 10000) {
|
|
612
683
|
return new Promise((resolve, reject) => {
|
|
@@ -967,11 +1038,13 @@ function writeClaudeCodeSettings(baseUrl, apiKey, modelId = getDefaultClaudeMode
|
|
|
967
1038
|
if (fs.existsSync(settingsPath)) {
|
|
968
1039
|
try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch { settings = {}; }
|
|
969
1040
|
}
|
|
970
|
-
|
|
1041
|
+
const normalizedBaseUrl = baseUrl.replace(/\/+$/, '');
|
|
1042
|
+
settings.apiBaseUrl = normalizedBaseUrl;
|
|
971
1043
|
if (!settings.env) settings.env = {};
|
|
972
|
-
settings.env.
|
|
1044
|
+
settings.env.ANTHROPIC_API_KEY = apiKey;
|
|
1045
|
+
settings.env.ANTHROPIC_BASE_URL = normalizedBaseUrl;
|
|
1046
|
+
delete settings.env.ANTHROPIC_AUTH_TOKEN;
|
|
973
1047
|
delete settings.availableModels;
|
|
974
|
-
delete settings.env.ANTHROPIC_BASE_URL;
|
|
975
1048
|
delete settings.env.ANTHROPIC_MODEL;
|
|
976
1049
|
if (!fs.existsSync(claudeDir)) fs.mkdirSync(claudeDir, { recursive: true });
|
|
977
1050
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
|
@@ -3318,6 +3391,15 @@ async function confirmImmediateTest(args = {}, message = '是否立即测试连
|
|
|
3318
3391
|
return shouldTest;
|
|
3319
3392
|
}
|
|
3320
3393
|
|
|
3394
|
+
async function pauseBeforeReturningToMenu(args = {}, message = '测试完成,按回车返回主菜单') {
|
|
3395
|
+
if (!args.fromMenu) return;
|
|
3396
|
+
await inquirer.prompt([{
|
|
3397
|
+
type: 'input',
|
|
3398
|
+
name: 'continue',
|
|
3399
|
+
message
|
|
3400
|
+
}]);
|
|
3401
|
+
}
|
|
3402
|
+
|
|
3321
3403
|
function extendPathEnv(preferredNodePath) {
|
|
3322
3404
|
const current = process.env.PATH || '';
|
|
3323
3405
|
const parts = current.split(path.delimiter).filter(Boolean);
|
|
@@ -3560,7 +3642,7 @@ function readTextIfExists(filePath) {
|
|
|
3560
3642
|
}
|
|
3561
3643
|
|
|
3562
3644
|
function getHermesDataDir() {
|
|
3563
|
-
const envDir = String(process.env.HERMES_DATA_DIR || '').trim();
|
|
3645
|
+
const envDir = String(process.env.HERMES_HOME || process.env.HERMES_DATA_DIR || '').trim();
|
|
3564
3646
|
return envDir || path.join(os.homedir(), '.hermes');
|
|
3565
3647
|
}
|
|
3566
3648
|
|
|
@@ -3795,6 +3877,32 @@ function readHermesYamlConfig(configPath = getHermesConfigPath()) {
|
|
|
3795
3877
|
};
|
|
3796
3878
|
}
|
|
3797
3879
|
|
|
3880
|
+
function readHermesCliConfig() {
|
|
3881
|
+
const yamlConfig = readHermesYamlConfig();
|
|
3882
|
+
const envPath = getHermesEnvPath();
|
|
3883
|
+
const envEntries = parseEnvFile(readTextIfExists(envPath));
|
|
3884
|
+
const modelConfig = yamlConfig.config?.model && typeof yamlConfig.config.model === 'object'
|
|
3885
|
+
? yamlConfig.config.model
|
|
3886
|
+
: {};
|
|
3887
|
+
const modelId = String(modelConfig.default || '').trim() || getDefaultClaudeModel().id;
|
|
3888
|
+
const provider = String(modelConfig.provider || '').trim().toLowerCase();
|
|
3889
|
+
const type = resolveHermesModelType(modelId, provider);
|
|
3890
|
+
const apiKey = type === 'codex'
|
|
3891
|
+
? (envEntries.OPENAI_API_KEY || process.env.OPENAI_API_KEY || process.env.OPENAI_AUTH_TOKEN || '')
|
|
3892
|
+
: (envEntries.ANTHROPIC_API_KEY || envEntries.ANTHROPIC_TOKEN || process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_TOKEN || process.env.CLAUDE_CODE_OAUTH_TOKEN || '');
|
|
3893
|
+
|
|
3894
|
+
return {
|
|
3895
|
+
configPath: yamlConfig.configPath,
|
|
3896
|
+
envPath,
|
|
3897
|
+
configured: yamlConfig.configured || fs.existsSync(envPath),
|
|
3898
|
+
modelId,
|
|
3899
|
+
provider,
|
|
3900
|
+
type,
|
|
3901
|
+
baseUrl: String(modelConfig.base_url || '').trim(),
|
|
3902
|
+
apiKey
|
|
3903
|
+
};
|
|
3904
|
+
}
|
|
3905
|
+
|
|
3798
3906
|
function getOpencodeConfigPath() {
|
|
3799
3907
|
const home = os.homedir();
|
|
3800
3908
|
return process.platform === 'win32'
|
|
@@ -3813,11 +3921,20 @@ function getCodexCliPaths() {
|
|
|
3813
3921
|
function readClaudeCodeCliConfig() {
|
|
3814
3922
|
const settingsPath = getClaudeCodeSettingsPath();
|
|
3815
3923
|
const settings = readJsonIfExists(settingsPath) || {};
|
|
3924
|
+
const settingsEnv = settings.env && typeof settings.env === 'object' ? settings.env : {};
|
|
3925
|
+
const settingsApiKey = String(settingsEnv.ANTHROPIC_API_KEY || '').trim();
|
|
3926
|
+
const settingsLegacyAuthToken = String(settingsEnv.ANTHROPIC_AUTH_TOKEN || '').trim();
|
|
3927
|
+
const settingsBaseUrl = String(settingsEnv.ANTHROPIC_BASE_URL || settings.apiBaseUrl || '').trim();
|
|
3816
3928
|
return {
|
|
3817
3929
|
settingsPath,
|
|
3818
|
-
modelId: settings.model ||
|
|
3819
|
-
baseUrl:
|
|
3820
|
-
apiKey:
|
|
3930
|
+
modelId: settings.model || settingsEnv.ANTHROPIC_MODEL || process.env.ANTHROPIC_MODEL || getDefaultClaudeModel().id,
|
|
3931
|
+
baseUrl: settingsBaseUrl || process.env.ANTHROPIC_BASE_URL || '',
|
|
3932
|
+
apiKey: settingsApiKey || settingsLegacyAuthToken || process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_AUTH_TOKEN || process.env.CLAUDE_API_KEY || '',
|
|
3933
|
+
settingsBaseUrl,
|
|
3934
|
+
settingsApiKey,
|
|
3935
|
+
settingsLegacyAuthToken,
|
|
3936
|
+
hasLegacyAuthTokenInSettings: !!settingsLegacyAuthToken,
|
|
3937
|
+
usesLegacyAuthTokenOnly: !settingsApiKey && !!settingsLegacyAuthToken,
|
|
3821
3938
|
configured: fs.existsSync(settingsPath)
|
|
3822
3939
|
};
|
|
3823
3940
|
}
|
|
@@ -3872,6 +3989,23 @@ function summarizeCliTestOutput(text) {
|
|
|
3872
3989
|
return lines[0].slice(0, 160);
|
|
3873
3990
|
}
|
|
3874
3991
|
|
|
3992
|
+
function extractHermesCliReply(text) {
|
|
3993
|
+
const lines = cleanCliTestOutput(text)
|
|
3994
|
+
.split('\n')
|
|
3995
|
+
.map(line => line.trim())
|
|
3996
|
+
.filter(Boolean)
|
|
3997
|
+
.filter(line => !/^session_id:/i.test(line))
|
|
3998
|
+
.filter(line => !/^resume this session/i.test(line))
|
|
3999
|
+
.filter(line => !/^session:/i.test(line))
|
|
4000
|
+
.filter(line => !/^duration:/i.test(line))
|
|
4001
|
+
.filter(line => !/^messages:/i.test(line))
|
|
4002
|
+
.filter(line => !/^[╭╰│─]+/.test(line));
|
|
4003
|
+
|
|
4004
|
+
const okLine = lines.find(line => /^OK$/i.test(line));
|
|
4005
|
+
if (okLine) return okLine;
|
|
4006
|
+
return lines[0] || '';
|
|
4007
|
+
}
|
|
4008
|
+
|
|
3875
4009
|
function buildReadableAgentError(text, fallback = '') {
|
|
3876
4010
|
const cleaned = cleanCliTestOutput(text);
|
|
3877
4011
|
if (!cleaned) return fallback;
|
|
@@ -3887,6 +4021,11 @@ function looksLikeCliTestError(text) {
|
|
|
3887
4021
|
'all models failed',
|
|
3888
4022
|
'auth_permanent',
|
|
3889
4023
|
'auth issue',
|
|
4024
|
+
'authentication_error',
|
|
4025
|
+
'failed to authenticate',
|
|
4026
|
+
'invalid bearer token',
|
|
4027
|
+
'invalid api key',
|
|
4028
|
+
'fix external api key',
|
|
3890
4029
|
'unauthorized',
|
|
3891
4030
|
'forbidden',
|
|
3892
4031
|
'missing environment variable',
|
|
@@ -3914,17 +4053,28 @@ function testClaudeCodeCliConnection() {
|
|
|
3914
4053
|
|
|
3915
4054
|
const config = readClaudeCodeCliConfig();
|
|
3916
4055
|
if (!config.configured) return { name: 'Claude Code CLI', status: 'skipped', detail: '未检测到 ~/.claude/settings.json' };
|
|
3917
|
-
if (
|
|
4056
|
+
if (config.usesLegacyAuthTokenOnly) {
|
|
4057
|
+
return {
|
|
4058
|
+
name: 'Claude Code CLI',
|
|
4059
|
+
status: 'failed',
|
|
4060
|
+
detail: '检测到旧版 Claude Code 配置字段 ANTHROPIC_AUTH_TOKEN,请重新运行 yymaxapi 以改写为 ANTHROPIC_API_KEY'
|
|
4061
|
+
};
|
|
4062
|
+
}
|
|
4063
|
+
if (!config.settingsBaseUrl || !config.settingsApiKey) {
|
|
4064
|
+
return { name: 'Claude Code CLI', status: 'failed', detail: 'Claude Code 配置缺少 settings.json 中的 Base URL 或 API Key' };
|
|
4065
|
+
}
|
|
3918
4066
|
|
|
3919
4067
|
const env = {
|
|
3920
4068
|
...process.env,
|
|
3921
4069
|
PATH: extendPathEnv(null),
|
|
3922
|
-
ANTHROPIC_BASE_URL: config.baseUrl,
|
|
3923
|
-
ANTHROPIC_AUTH_TOKEN: config.apiKey,
|
|
3924
|
-
ANTHROPIC_MODEL: config.modelId,
|
|
3925
4070
|
NODE_TLS_REJECT_UNAUTHORIZED: '0',
|
|
3926
4071
|
NODE_NO_WARNINGS: '1'
|
|
3927
4072
|
};
|
|
4073
|
+
delete env.ANTHROPIC_BASE_URL;
|
|
4074
|
+
delete env.ANTHROPIC_API_KEY;
|
|
4075
|
+
delete env.ANTHROPIC_AUTH_TOKEN;
|
|
4076
|
+
delete env.ANTHROPIC_MODEL;
|
|
4077
|
+
delete env.CLAUDE_API_KEY;
|
|
3928
4078
|
|
|
3929
4079
|
return runCliTestCandidates('Claude Code CLI', [
|
|
3930
4080
|
`${shellQuote(cliBinary)} -p --model ${shellQuote(config.modelId)} --output-format text ${shellQuote('请只回复 OK')}`,
|
|
@@ -3976,14 +4126,62 @@ function testCodexCliConnection() {
|
|
|
3976
4126
|
], env);
|
|
3977
4127
|
}
|
|
3978
4128
|
|
|
4129
|
+
function testHermesCliConnection() {
|
|
4130
|
+
const cliBinary = resolveCommandBinary('hermes');
|
|
4131
|
+
if (!cliBinary) return { name: 'Hermes CLI', status: 'skipped', detail: '未安装 hermes 命令' };
|
|
4132
|
+
|
|
4133
|
+
const config = readHermesCliConfig();
|
|
4134
|
+
if (!config.configured) return { name: 'Hermes CLI', status: 'skipped', detail: '未检测到 ~/.hermes/config.yaml 或 ~/.hermes/.env' };
|
|
4135
|
+
if (!config.apiKey) return { name: 'Hermes CLI', status: 'failed', detail: 'Hermes 配置缺少 API Key' };
|
|
4136
|
+
|
|
4137
|
+
const env = {
|
|
4138
|
+
...process.env,
|
|
4139
|
+
PATH: extendPathEnv(null),
|
|
4140
|
+
NODE_TLS_REJECT_UNAUTHORIZED: '0',
|
|
4141
|
+
NODE_NO_WARNINGS: '1'
|
|
4142
|
+
};
|
|
4143
|
+
|
|
4144
|
+
if (config.type === 'codex') {
|
|
4145
|
+
env.OPENAI_API_KEY = config.apiKey;
|
|
4146
|
+
delete env.ANTHROPIC_API_KEY;
|
|
4147
|
+
delete env.ANTHROPIC_TOKEN;
|
|
4148
|
+
delete env.CLAUDE_CODE_OAUTH_TOKEN;
|
|
4149
|
+
} else {
|
|
4150
|
+
env.ANTHROPIC_API_KEY = config.apiKey;
|
|
4151
|
+
if (config.baseUrl) env.ANTHROPIC_BASE_URL = config.baseUrl;
|
|
4152
|
+
delete env.ANTHROPIC_TOKEN;
|
|
4153
|
+
delete env.CLAUDE_CODE_OAUTH_TOKEN;
|
|
4154
|
+
}
|
|
4155
|
+
|
|
4156
|
+
const providerArg = config.provider === 'anthropic' ? ' --provider anthropic' : '';
|
|
4157
|
+
const result = safeExec(`${shellQuote(cliBinary)} chat -Q -q ${shellQuote('请只回复 OK')}${providerArg}`, {
|
|
4158
|
+
timeout: 120000,
|
|
4159
|
+
env,
|
|
4160
|
+
maxBuffer: 1024 * 1024
|
|
4161
|
+
});
|
|
4162
|
+
const combined = cleanCliTestOutput(`${result.output || ''}\n${result.stdout || ''}\n${result.stderr || ''}`);
|
|
4163
|
+
const reply = extractHermesCliReply(combined);
|
|
4164
|
+
|
|
4165
|
+
if (result.ok && /^OK$/i.test(reply) && !looksLikeCliTestError(combined)) {
|
|
4166
|
+
return { name: 'Hermes CLI', status: 'success', detail: 'OK' };
|
|
4167
|
+
}
|
|
4168
|
+
|
|
4169
|
+
return {
|
|
4170
|
+
name: 'Hermes CLI',
|
|
4171
|
+
status: 'failed',
|
|
4172
|
+
detail: reply || summarizeCliTestOutput(combined) || result.error || '命令执行失败'
|
|
4173
|
+
};
|
|
4174
|
+
}
|
|
4175
|
+
|
|
3979
4176
|
async function testAdditionalCliConnections(args = {}, options = {}) {
|
|
3980
4177
|
if (args['no-app-test'] || args.noAppTest) return;
|
|
3981
4178
|
|
|
3982
|
-
const requested = new Set((options.only || ['claude', 'opencode', 'codex']).map(item => String(item)));
|
|
4179
|
+
const requested = new Set((options.only || ['claude', 'opencode', 'codex', 'hermes']).map(item => String(item)));
|
|
3983
4180
|
const results = [];
|
|
3984
4181
|
if (requested.has('claude')) results.push(testClaudeCodeCliConnection());
|
|
3985
4182
|
if (requested.has('opencode')) results.push(testOpencodeCliConnection());
|
|
3986
4183
|
if (requested.has('codex')) results.push(testCodexCliConnection());
|
|
4184
|
+
if (requested.has('hermes')) results.push(testHermesCliConnection());
|
|
3987
4185
|
if (results.length === 0) return;
|
|
3988
4186
|
|
|
3989
4187
|
console.log(chalk.cyan('\n附加测试: 其他 CLI 连接...'));
|
|
@@ -4670,47 +4868,15 @@ async function quickSetup(paths, args = {}) {
|
|
|
4670
4868
|
}
|
|
4671
4869
|
|
|
4672
4870
|
async function presetClaude(paths, args = {}) {
|
|
4673
|
-
console.log(chalk.cyan.bold('\n🚀 Claude
|
|
4871
|
+
console.log(chalk.cyan.bold('\n🚀 Claude 快速配置(默认节点直连)\n'));
|
|
4674
4872
|
|
|
4675
4873
|
const apiConfig = API_CONFIG.claude;
|
|
4676
4874
|
const providerPrefix = (args['provider-prefix'] || args.prefix || apiConfig.providerName).toString().trim() || apiConfig.providerName;
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
if (
|
|
4682
|
-
console.log(chalk.cyan('📡 开始测速 Claude 节点...\n'));
|
|
4683
|
-
const speedResult = await testAllEndpoints(ENDPOINTS, { autoFallback: true });
|
|
4684
|
-
|
|
4685
|
-
const sorted = speedResult.ranked || [];
|
|
4686
|
-
if (sorted.length > 0) {
|
|
4687
|
-
const defaultEp = ENDPOINTS[0];
|
|
4688
|
-
const { selectedIndex } = await inquirer.prompt([{
|
|
4689
|
-
type: 'list',
|
|
4690
|
-
name: 'selectedIndex',
|
|
4691
|
-
message: '选择节点:',
|
|
4692
|
-
choices: [
|
|
4693
|
-
{ name: `* 使用默认节点 (${defaultEp.name})`, value: -1 },
|
|
4694
|
-
new inquirer.Separator(' ---- 或按测速结果选择 ----'),
|
|
4695
|
-
...sorted.map((e, i) => ({
|
|
4696
|
-
name: `${e.name} - ${e.latency}ms (评分:${e.score})`,
|
|
4697
|
-
value: i
|
|
4698
|
-
}))
|
|
4699
|
-
]
|
|
4700
|
-
}]);
|
|
4701
|
-
selectedEndpoint = selectedIndex === -1 ? defaultEp : sorted[selectedIndex];
|
|
4702
|
-
if (speedResult.usedFallback) {
|
|
4703
|
-
console.log(chalk.yellow(`\n⚠ 当前使用备用节点\n`));
|
|
4704
|
-
}
|
|
4705
|
-
} else {
|
|
4706
|
-
console.log(chalk.red('\n⚠️ 所有节点(含备用)均不可达'));
|
|
4707
|
-
const { proceed } = await inquirer.prompt([{
|
|
4708
|
-
type: 'confirm', name: 'proceed',
|
|
4709
|
-
message: '仍要写入默认节点配置吗?', default: false
|
|
4710
|
-
}]);
|
|
4711
|
-
if (!proceed) { console.log(chalk.gray('已取消')); return; }
|
|
4712
|
-
}
|
|
4713
|
-
}
|
|
4875
|
+
const selectedEndpoint = await resolveEndpointSelection(args, {
|
|
4876
|
+
speedIntro: '📡 开始测速 Claude 节点...\n',
|
|
4877
|
+
proceedMessage: '仍要写入默认节点配置吗?'
|
|
4878
|
+
});
|
|
4879
|
+
if (!selectedEndpoint) return;
|
|
4714
4880
|
|
|
4715
4881
|
const config = ensureConfigStructure(readConfig(paths.openclawConfig) || {});
|
|
4716
4882
|
const repairResult = applyConfigRepairsWithSync(config, paths);
|
|
@@ -4722,6 +4888,8 @@ async function presetClaude(paths, args = {}) {
|
|
|
4722
4888
|
|
|
4723
4889
|
const apiKeyEnvFallbacks = [
|
|
4724
4890
|
'OPENCLAW_CLAUDE_KEY',
|
|
4891
|
+
'ANTHROPIC_API_KEY',
|
|
4892
|
+
'ANTHROPIC_AUTH_TOKEN',
|
|
4725
4893
|
'CLAUDE_API_KEY',
|
|
4726
4894
|
'OPENCLAW_API_KEY'
|
|
4727
4895
|
];
|
|
@@ -4853,48 +5021,16 @@ async function presetClaude(paths, args = {}) {
|
|
|
4853
5021
|
}
|
|
4854
5022
|
|
|
4855
5023
|
async function presetCodex(paths, args = {}) {
|
|
4856
|
-
console.log(chalk.cyan.bold('\n🚀 Codex
|
|
5024
|
+
console.log(chalk.cyan.bold('\n🚀 Codex 快速配置(默认节点直连)\n'));
|
|
4857
5025
|
|
|
4858
5026
|
const apiConfig = API_CONFIG.codex;
|
|
4859
5027
|
const providerPrefix = (args['provider-prefix'] || args.prefix || apiConfig.providerName).toString().trim() || apiConfig.providerName;
|
|
4860
5028
|
const providerName = (args['provider-name'] || args.provider || providerPrefix).toString().trim() || apiConfig.providerName;
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
if (
|
|
4866
|
-
console.log(chalk.cyan('📡 开始测速 Codex 节点...\n'));
|
|
4867
|
-
const speedResult = await testAllEndpoints(ENDPOINTS, { autoFallback: true });
|
|
4868
|
-
|
|
4869
|
-
const sorted = speedResult.ranked || [];
|
|
4870
|
-
if (sorted.length > 0) {
|
|
4871
|
-
const defaultEp = ENDPOINTS[0];
|
|
4872
|
-
const { selectedIndex } = await inquirer.prompt([{
|
|
4873
|
-
type: 'list',
|
|
4874
|
-
name: 'selectedIndex',
|
|
4875
|
-
message: '选择节点:',
|
|
4876
|
-
choices: [
|
|
4877
|
-
{ name: `* 使用默认节点 (${defaultEp.name})`, value: -1 },
|
|
4878
|
-
new inquirer.Separator(' ---- 或按测速结果选择 ----'),
|
|
4879
|
-
...sorted.map((e, i) => ({
|
|
4880
|
-
name: `${e.name} - ${e.latency}ms (评分:${e.score})`,
|
|
4881
|
-
value: i
|
|
4882
|
-
}))
|
|
4883
|
-
]
|
|
4884
|
-
}]);
|
|
4885
|
-
selectedEndpoint = selectedIndex === -1 ? defaultEp : sorted[selectedIndex];
|
|
4886
|
-
if (speedResult.usedFallback) {
|
|
4887
|
-
console.log(chalk.yellow(`\n⚠ 当前使用备用节点\n`));
|
|
4888
|
-
}
|
|
4889
|
-
} else {
|
|
4890
|
-
console.log(chalk.red('\n⚠️ 所有节点(含备用)均不可达'));
|
|
4891
|
-
const { proceed } = await inquirer.prompt([{
|
|
4892
|
-
type: 'confirm', name: 'proceed',
|
|
4893
|
-
message: '仍要写入默认节点配置吗?', default: false
|
|
4894
|
-
}]);
|
|
4895
|
-
if (!proceed) { console.log(chalk.gray('已取消')); return; }
|
|
4896
|
-
}
|
|
4897
|
-
}
|
|
5029
|
+
const selectedEndpoint = await resolveEndpointSelection(args, {
|
|
5030
|
+
speedIntro: '📡 开始测速 Codex 节点...\n',
|
|
5031
|
+
proceedMessage: '仍要写入默认节点配置吗?'
|
|
5032
|
+
});
|
|
5033
|
+
if (!selectedEndpoint) return;
|
|
4898
5034
|
|
|
4899
5035
|
const config = ensureConfigStructure(readConfig(paths.openclawConfig) || {});
|
|
4900
5036
|
const repairResult = applyConfigRepairsWithSync(config, paths);
|
|
@@ -5048,6 +5184,8 @@ async function autoActivate(paths, args = {}) {
|
|
|
5048
5184
|
const apiKeyEnvFallbacks = [
|
|
5049
5185
|
'OPENCLAW_CLAUDE_KEY',
|
|
5050
5186
|
'OPENCLAW_CODEX_KEY',
|
|
5187
|
+
'ANTHROPIC_API_KEY',
|
|
5188
|
+
'ANTHROPIC_AUTH_TOKEN',
|
|
5051
5189
|
'CLAUDE_API_KEY',
|
|
5052
5190
|
'OPENAI_API_KEY',
|
|
5053
5191
|
'OPENCLAW_API_KEY'
|
|
@@ -5258,40 +5396,10 @@ async function autoActivate(paths, args = {}) {
|
|
|
5258
5396
|
async function activateClaudeCode(paths, args = {}) {
|
|
5259
5397
|
console.log(chalk.cyan.bold('\n🔧 配置 Claude Code CLI\n'));
|
|
5260
5398
|
const selectedModel = await promptClaudeModelSelection(args);
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
if (shouldTest) {
|
|
5267
|
-
console.log(chalk.cyan('📡 开始测速节点...\n'));
|
|
5268
|
-
const speedResult = await testAllEndpoints(ENDPOINTS, { autoFallback: true });
|
|
5269
|
-
const sorted = speedResult.ranked || [];
|
|
5270
|
-
if (sorted.length > 0) {
|
|
5271
|
-
const defaultEp = ENDPOINTS[0];
|
|
5272
|
-
const { selectedIndex } = await inquirer.prompt([{
|
|
5273
|
-
type: 'list',
|
|
5274
|
-
name: 'selectedIndex',
|
|
5275
|
-
message: '选择节点:',
|
|
5276
|
-
choices: [
|
|
5277
|
-
{ name: `* 使用默认节点 (${defaultEp.name})`, value: -1 },
|
|
5278
|
-
new inquirer.Separator(' ---- 或按测速结果选择 ----'),
|
|
5279
|
-
...sorted.map((e, i) => ({
|
|
5280
|
-
name: `${e.name} - ${e.latency}ms (评分:${e.score})`,
|
|
5281
|
-
value: i
|
|
5282
|
-
}))
|
|
5283
|
-
]
|
|
5284
|
-
}]);
|
|
5285
|
-
selectedEndpoint = selectedIndex === -1 ? defaultEp : sorted[selectedIndex];
|
|
5286
|
-
} else {
|
|
5287
|
-
console.log(chalk.red('\n⚠️ 所有节点均不可达'));
|
|
5288
|
-
const { proceed } = await inquirer.prompt([{
|
|
5289
|
-
type: 'confirm', name: 'proceed',
|
|
5290
|
-
message: '仍要使用默认节点配置吗?', default: false
|
|
5291
|
-
}]);
|
|
5292
|
-
if (!proceed) { console.log(chalk.gray('已取消')); return; }
|
|
5293
|
-
}
|
|
5294
|
-
}
|
|
5399
|
+
const selectedEndpoint = await resolveEndpointSelection(args, {
|
|
5400
|
+
proceedMessage: '仍要使用默认节点配置吗?'
|
|
5401
|
+
});
|
|
5402
|
+
if (!selectedEndpoint) return;
|
|
5295
5403
|
|
|
5296
5404
|
// ---- API Key ----
|
|
5297
5405
|
const directKey = (args['api-key'] || args.apiKey || args.key || '').toString().trim();
|
|
@@ -5299,7 +5407,7 @@ async function activateClaudeCode(paths, args = {}) {
|
|
|
5299
5407
|
if (directKey) {
|
|
5300
5408
|
apiKey = directKey;
|
|
5301
5409
|
} else {
|
|
5302
|
-
const envKey = process.env.ANTHROPIC_AUTH_TOKEN || process.env.CLAUDE_API_KEY || '';
|
|
5410
|
+
const envKey = process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_AUTH_TOKEN || process.env.CLAUDE_API_KEY || '';
|
|
5303
5411
|
apiKey = await promptApiKey('请输入 API Key:', envKey);
|
|
5304
5412
|
}
|
|
5305
5413
|
if (!apiKey) { console.log(chalk.gray('已取消')); return; }
|
|
@@ -5327,11 +5435,12 @@ async function activateClaudeCode(paths, args = {}) {
|
|
|
5327
5435
|
console.log(chalk.gray(' API Key: 已设置'));
|
|
5328
5436
|
console.log(chalk.gray('\n 已写入:'));
|
|
5329
5437
|
console.log(chalk.gray(' • ~/.claude/settings.json'));
|
|
5330
|
-
console.log(chalk.gray(' • 最小字段: apiBaseUrl + env.
|
|
5438
|
+
console.log(chalk.gray(' • 最小字段: apiBaseUrl + env.ANTHROPIC_API_KEY + env.ANTHROPIC_BASE_URL'));
|
|
5331
5439
|
console.log(chalk.yellow('\n 提示: 如果 Claude Code 已在运行,重新打开一个会话即可读取新配置'));
|
|
5332
5440
|
|
|
5333
5441
|
if (await confirmImmediateTest(args, '是否立即测试 Claude Code CLI 连接?')) {
|
|
5334
5442
|
await testAdditionalCliConnections(args, { only: ['claude'] });
|
|
5443
|
+
await pauseBeforeReturningToMenu(args);
|
|
5335
5444
|
}
|
|
5336
5445
|
}
|
|
5337
5446
|
|
|
@@ -5339,40 +5448,10 @@ async function activateClaudeCode(paths, args = {}) {
|
|
|
5339
5448
|
async function activateOpencode(paths, args = {}) {
|
|
5340
5449
|
console.log(chalk.cyan.bold('\n🔧 配置 Opencode\n'));
|
|
5341
5450
|
const defaultModel = await promptOpencodeDefaultModelSelection(args);
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
if (shouldTest) {
|
|
5348
|
-
console.log(chalk.cyan('📡 开始测速节点...\n'));
|
|
5349
|
-
const speedResult = await testAllEndpoints(ENDPOINTS, { autoFallback: true });
|
|
5350
|
-
const sorted = speedResult.ranked || [];
|
|
5351
|
-
if (sorted.length > 0) {
|
|
5352
|
-
const defaultEp = ENDPOINTS[0];
|
|
5353
|
-
const { selectedIndex } = await inquirer.prompt([{
|
|
5354
|
-
type: 'list',
|
|
5355
|
-
name: 'selectedIndex',
|
|
5356
|
-
message: '选择节点:',
|
|
5357
|
-
choices: [
|
|
5358
|
-
{ name: `* 使用默认节点 (${defaultEp.name})`, value: -1 },
|
|
5359
|
-
new inquirer.Separator(' ---- 或按测速结果选择 ----'),
|
|
5360
|
-
...sorted.map((e, i) => ({
|
|
5361
|
-
name: `${e.name} - ${e.latency}ms (评分:${e.score})`,
|
|
5362
|
-
value: i
|
|
5363
|
-
}))
|
|
5364
|
-
]
|
|
5365
|
-
}]);
|
|
5366
|
-
selectedEndpoint = selectedIndex === -1 ? defaultEp : sorted[selectedIndex];
|
|
5367
|
-
} else {
|
|
5368
|
-
console.log(chalk.red('\n⚠️ 所有节点均不可达'));
|
|
5369
|
-
const { proceed } = await inquirer.prompt([{
|
|
5370
|
-
type: 'confirm', name: 'proceed',
|
|
5371
|
-
message: '仍要使用默认节点配置吗?', default: false
|
|
5372
|
-
}]);
|
|
5373
|
-
if (!proceed) { console.log(chalk.gray('已取消')); return; }
|
|
5374
|
-
}
|
|
5375
|
-
}
|
|
5451
|
+
const selectedEndpoint = await resolveEndpointSelection(args, {
|
|
5452
|
+
proceedMessage: '仍要使用默认节点配置吗?'
|
|
5453
|
+
});
|
|
5454
|
+
if (!selectedEndpoint) return;
|
|
5376
5455
|
|
|
5377
5456
|
// ---- API Key ----
|
|
5378
5457
|
const directKey = (args['api-key'] || args.apiKey || args.key || '').toString().trim();
|
|
@@ -5380,7 +5459,7 @@ async function activateOpencode(paths, args = {}) {
|
|
|
5380
5459
|
if (directKey) {
|
|
5381
5460
|
apiKey = directKey;
|
|
5382
5461
|
} else {
|
|
5383
|
-
const envKey = process.env.ANTHROPIC_AUTH_TOKEN || process.env.CLAUDE_API_KEY || '';
|
|
5462
|
+
const envKey = process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_AUTH_TOKEN || process.env.CLAUDE_API_KEY || '';
|
|
5384
5463
|
apiKey = await promptApiKey('请输入 API Key:', envKey);
|
|
5385
5464
|
}
|
|
5386
5465
|
if (!apiKey) { console.log(chalk.gray('已取消')); return; }
|
|
@@ -5416,6 +5495,7 @@ async function activateOpencode(paths, args = {}) {
|
|
|
5416
5495
|
|
|
5417
5496
|
if (await confirmImmediateTest(args, '是否立即测试 Opencode CLI 连接?')) {
|
|
5418
5497
|
await testAdditionalCliConnections(args, { only: ['opencode'] });
|
|
5498
|
+
await pauseBeforeReturningToMenu(args);
|
|
5419
5499
|
}
|
|
5420
5500
|
}
|
|
5421
5501
|
|
|
@@ -5436,39 +5516,10 @@ async function activateCodex(paths, args = {}) {
|
|
|
5436
5516
|
}
|
|
5437
5517
|
const modelConfig = CODEX_MODELS.find(m => m.id === modelId) || { id: modelId, name: modelId };
|
|
5438
5518
|
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
if (shouldTest) {
|
|
5444
|
-
console.log(chalk.cyan('📡 开始测速节点...\n'));
|
|
5445
|
-
const speedResult = await testAllEndpoints(ENDPOINTS, { autoFallback: true });
|
|
5446
|
-
const sorted = speedResult.ranked || [];
|
|
5447
|
-
if (sorted.length > 0) {
|
|
5448
|
-
const defaultEp = ENDPOINTS[0];
|
|
5449
|
-
const { selectedIndex } = await inquirer.prompt([{
|
|
5450
|
-
type: 'list',
|
|
5451
|
-
name: 'selectedIndex',
|
|
5452
|
-
message: '选择节点:',
|
|
5453
|
-
choices: [
|
|
5454
|
-
{ name: `* 使用默认节点 (${defaultEp.name})`, value: -1 },
|
|
5455
|
-
new inquirer.Separator(' ---- 或按测速结果选择 ----'),
|
|
5456
|
-
...sorted.map((e, i) => ({
|
|
5457
|
-
name: `${e.name} - ${e.latency}ms (评分:${e.score})`,
|
|
5458
|
-
value: i
|
|
5459
|
-
}))
|
|
5460
|
-
]
|
|
5461
|
-
}]);
|
|
5462
|
-
selectedEndpoint = selectedIndex === -1 ? defaultEp : sorted[selectedIndex];
|
|
5463
|
-
} else {
|
|
5464
|
-
console.log(chalk.red('\n⚠️ 所有节点均不可达'));
|
|
5465
|
-
const { proceed } = await inquirer.prompt([{
|
|
5466
|
-
type: 'confirm', name: 'proceed',
|
|
5467
|
-
message: '仍要使用默认节点配置吗?', default: false
|
|
5468
|
-
}]);
|
|
5469
|
-
if (!proceed) { console.log(chalk.gray('已取消')); return; }
|
|
5470
|
-
}
|
|
5471
|
-
}
|
|
5519
|
+
const selectedEndpoint = await resolveEndpointSelection(args, {
|
|
5520
|
+
proceedMessage: '仍要使用默认节点配置吗?'
|
|
5521
|
+
});
|
|
5522
|
+
if (!selectedEndpoint) return;
|
|
5472
5523
|
|
|
5473
5524
|
// ---- API Key ----
|
|
5474
5525
|
const directKey = (args['api-key'] || args.apiKey || args.key || '').toString().trim();
|
|
@@ -5509,6 +5560,7 @@ async function activateCodex(paths, args = {}) {
|
|
|
5509
5560
|
|
|
5510
5561
|
if (await confirmImmediateTest(args, '是否立即测试 Codex CLI 连接?')) {
|
|
5511
5562
|
await testAdditionalCliConnections(args, { only: ['codex'] });
|
|
5563
|
+
await pauseBeforeReturningToMenu(args);
|
|
5512
5564
|
}
|
|
5513
5565
|
}
|
|
5514
5566
|
|
|
@@ -5518,39 +5570,10 @@ async function activateHermes(paths, args = {}) {
|
|
|
5518
5570
|
const selection = await promptHermesModelSelection(args, '选择 Hermes 默认模型:');
|
|
5519
5571
|
const selectedModel = selection.model;
|
|
5520
5572
|
const selectedType = selection.type;
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
if (shouldTest) {
|
|
5526
|
-
console.log(chalk.cyan('📡 开始测速节点...\n'));
|
|
5527
|
-
const speedResult = await testAllEndpoints(ENDPOINTS, { autoFallback: true });
|
|
5528
|
-
const sorted = speedResult.ranked || [];
|
|
5529
|
-
if (sorted.length > 0) {
|
|
5530
|
-
const defaultEp = ENDPOINTS[0];
|
|
5531
|
-
const { selectedIndex } = await inquirer.prompt([{
|
|
5532
|
-
type: 'list',
|
|
5533
|
-
name: 'selectedIndex',
|
|
5534
|
-
message: '选择节点:',
|
|
5535
|
-
choices: [
|
|
5536
|
-
{ name: `* 使用默认节点 (${defaultEp.name})`, value: -1 },
|
|
5537
|
-
new inquirer.Separator(' ---- 或按测速结果选择 ----'),
|
|
5538
|
-
...sorted.map((e, i) => ({
|
|
5539
|
-
name: `${e.name} - ${e.latency}ms (评分:${e.score})`,
|
|
5540
|
-
value: i
|
|
5541
|
-
}))
|
|
5542
|
-
]
|
|
5543
|
-
}]);
|
|
5544
|
-
selectedEndpoint = selectedIndex === -1 ? defaultEp : sorted[selectedIndex];
|
|
5545
|
-
} else {
|
|
5546
|
-
console.log(chalk.red('\n⚠️ 所有节点均不可达'));
|
|
5547
|
-
const { proceed } = await inquirer.prompt([{
|
|
5548
|
-
type: 'confirm', name: 'proceed',
|
|
5549
|
-
message: '仍要使用默认节点配置吗?', default: false
|
|
5550
|
-
}]);
|
|
5551
|
-
if (!proceed) { console.log(chalk.gray('已取消')); return; }
|
|
5552
|
-
}
|
|
5553
|
-
}
|
|
5573
|
+
const selectedEndpoint = await resolveEndpointSelection(args, {
|
|
5574
|
+
proceedMessage: '仍要使用默认节点配置吗?'
|
|
5575
|
+
});
|
|
5576
|
+
if (!selectedEndpoint) return;
|
|
5554
5577
|
|
|
5555
5578
|
const directKey = (args['api-key'] || args.apiKey || args.key || '').toString().trim();
|
|
5556
5579
|
let apiKey;
|
|
@@ -5592,8 +5615,13 @@ async function activateHermes(paths, args = {}) {
|
|
|
5592
5615
|
if (hermesPaths.wslConfigPath && hermesPaths.wslEnvPath) {
|
|
5593
5616
|
console.log(chalk.gray(' • 已额外同步到 WSL ~/.hermes'));
|
|
5594
5617
|
}
|
|
5595
|
-
console.log(chalk.yellow('\n 提示: Hermes
|
|
5596
|
-
console.log(chalk.yellow(' 建议:
|
|
5618
|
+
console.log(chalk.yellow('\n 提示: Hermes doctor 当前会固定检查官方 Anthropic /v1/models,不会读取 model.base_url;第三方 Anthropic 中转可能被误报为 invalid API key'));
|
|
5619
|
+
console.log(chalk.yellow(' 建议: 以 yymaxapi 的 Hermes CLI 运行时测试,或 `hermes chat -Q -q "请只回复 OK"` 的结果为准'));
|
|
5620
|
+
|
|
5621
|
+
if (await confirmImmediateTest(args, '是否立即测试 Hermes CLI 连接?')) {
|
|
5622
|
+
await testAdditionalCliConnections(args, { only: ['hermes'] });
|
|
5623
|
+
await pauseBeforeReturningToMenu(args);
|
|
5624
|
+
}
|
|
5597
5625
|
}
|
|
5598
5626
|
|
|
5599
5627
|
// ============ 主程序 ============
|
|
@@ -5635,6 +5663,10 @@ async function main() {
|
|
|
5635
5663
|
await testConnection(paths, args);
|
|
5636
5664
|
return;
|
|
5637
5665
|
}
|
|
5666
|
+
if (args._.includes('speed-test') || args._.includes('speedtest')) {
|
|
5667
|
+
await speedTestNodes();
|
|
5668
|
+
return;
|
|
5669
|
+
}
|
|
5638
5670
|
|
|
5639
5671
|
while (true) {
|
|
5640
5672
|
// 显示当前状态
|
|
@@ -5661,6 +5693,7 @@ async function main() {
|
|
|
5661
5693
|
new inquirer.Separator(' -- 工具 --'),
|
|
5662
5694
|
{ name: ' 切换 OpenClaw 模型', value: 'switch_model' },
|
|
5663
5695
|
{ name: ` 权限管理${getToolsProfileTag(paths)}`, value: 'tools_profile' },
|
|
5696
|
+
{ name: ' 测速节点', value: 'speed_test_nodes' },
|
|
5664
5697
|
{ name: ' 测试连接', value: 'test_connection' },
|
|
5665
5698
|
{ name: ' 查看配置', value: 'view_config' },
|
|
5666
5699
|
{ name: ' 恢复默认', value: 'restore' },
|
|
@@ -5684,6 +5717,9 @@ async function main() {
|
|
|
5684
5717
|
case 'test_connection':
|
|
5685
5718
|
await testConnection(paths, {});
|
|
5686
5719
|
break;
|
|
5720
|
+
case 'speed_test_nodes':
|
|
5721
|
+
await speedTestNodes();
|
|
5722
|
+
break;
|
|
5687
5723
|
case 'switch_model':
|
|
5688
5724
|
await switchModel(paths);
|
|
5689
5725
|
break;
|
|
@@ -5697,16 +5733,16 @@ async function main() {
|
|
|
5697
5733
|
await restore(paths);
|
|
5698
5734
|
break;
|
|
5699
5735
|
case 'activate_claude_code':
|
|
5700
|
-
await activateClaudeCode(paths);
|
|
5736
|
+
await activateClaudeCode(paths, { fromMenu: true });
|
|
5701
5737
|
break;
|
|
5702
5738
|
case 'activate_hermes':
|
|
5703
|
-
await activateHermes(paths);
|
|
5739
|
+
await activateHermes(paths, { fromMenu: true });
|
|
5704
5740
|
break;
|
|
5705
5741
|
case 'activate_opencode':
|
|
5706
|
-
await activateOpencode(paths);
|
|
5742
|
+
await activateOpencode(paths, { fromMenu: true });
|
|
5707
5743
|
break;
|
|
5708
5744
|
case 'activate_codex':
|
|
5709
|
-
await activateCodex(paths);
|
|
5745
|
+
await activateCodex(paths, { fromMenu: true });
|
|
5710
5746
|
break;
|
|
5711
5747
|
}
|
|
5712
5748
|
} catch (error) {
|
|
@@ -6888,6 +6924,8 @@ function testGatewayViaAgent(model, agentId = '') {
|
|
|
6888
6924
|
}
|
|
6889
6925
|
const nodeInfo = findCompatibleNode(nodeMajor);
|
|
6890
6926
|
const env = { ...process.env, PATH: extendPathEnv(nodeInfo ? nodeInfo.path : null), NODE_NO_WARNINGS: '1' };
|
|
6927
|
+
delete env.ANTHROPIC_API_KEY;
|
|
6928
|
+
delete env.ANTHROPIC_AUTH_TOKEN;
|
|
6891
6929
|
delete env.CLAUDE_API_KEY;
|
|
6892
6930
|
delete env.OPENCLAW_CLAUDE_KEY;
|
|
6893
6931
|
delete env.OPENCLAW_API_KEY;
|
|
@@ -155,7 +155,8 @@ npx yymaxapi@latest
|
|
|
155
155
|
{
|
|
156
156
|
"apiBaseUrl": "https://yunyi.rdzhvip.com/claude",
|
|
157
157
|
"env": {
|
|
158
|
-
"
|
|
158
|
+
"ANTHROPIC_API_KEY": "<你的云翼 API Key>",
|
|
159
|
+
"ANTHROPIC_BASE_URL": "https://yunyi.rdzhvip.com/claude"
|
|
159
160
|
}
|
|
160
161
|
}
|
|
161
162
|
```
|