yymaxapi 1.0.78 → 1.0.80
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 +172 -65
- package/package.json +1 -1
package/bin/yymaxapi.js
CHANGED
|
@@ -468,6 +468,53 @@ function buildAuthCandidates(baseDirs) {
|
|
|
468
468
|
return auths;
|
|
469
469
|
}
|
|
470
470
|
|
|
471
|
+
function buildPosixAuthCandidates(baseDirs) {
|
|
472
|
+
const auths = [];
|
|
473
|
+
for (const baseDir of baseDirs) {
|
|
474
|
+
auths.push(
|
|
475
|
+
path.posix.join(baseDir, 'agents', 'main', 'agent', 'auth-profiles.json'),
|
|
476
|
+
path.posix.join(baseDir, 'agent', 'auth-profiles.json')
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
return auths;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function findExistingWslFile(candidates = []) {
|
|
483
|
+
for (const candidate of candidates) {
|
|
484
|
+
const check = safeExec(`wsl -- bash -c "test -f '${candidate}' && echo yes"`, { timeout: 5000 });
|
|
485
|
+
if (check.ok && check.output.trim() === 'yes') {
|
|
486
|
+
return candidate;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return null;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function getWslMirrorInfo() {
|
|
493
|
+
if (process.platform !== 'win32' || !isWslAvailable()) {
|
|
494
|
+
return { configPath: null, authProfiles: null };
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
const wslHome = getWslHome() || '/root';
|
|
498
|
+
const configCandidates = [
|
|
499
|
+
`${wslHome}/.openclaw/openclaw.json`,
|
|
500
|
+
`${wslHome}/.openclaw/moltbot.json`,
|
|
501
|
+
`${wslHome}/.clawdbot/openclaw.json`,
|
|
502
|
+
`${wslHome}/.clawdbot/clawdbot.json`,
|
|
503
|
+
'/root/.openclaw/openclaw.json',
|
|
504
|
+
'/root/.openclaw/moltbot.json',
|
|
505
|
+
'/root/.clawdbot/openclaw.json',
|
|
506
|
+
'/root/.clawdbot/clawdbot.json'
|
|
507
|
+
];
|
|
508
|
+
|
|
509
|
+
const configPath = findExistingWslFile(configCandidates);
|
|
510
|
+
const authBases = configPath
|
|
511
|
+
? [path.posix.dirname(configPath)]
|
|
512
|
+
: [`${wslHome}/.openclaw`, `${wslHome}/.clawdbot`, '/root/.openclaw', '/root/.clawdbot'];
|
|
513
|
+
const authProfiles = findExistingWslFile(buildPosixAuthCandidates(authBases));
|
|
514
|
+
|
|
515
|
+
return { configPath, authProfiles };
|
|
516
|
+
}
|
|
517
|
+
|
|
471
518
|
function getConfigPath() {
|
|
472
519
|
const homeDir = os.homedir();
|
|
473
520
|
const openclawStateDir = process.env.OPENCLAW_STATE_DIR || path.join(homeDir, '.openclaw');
|
|
@@ -516,29 +563,24 @@ function getConfigPath() {
|
|
|
516
563
|
}
|
|
517
564
|
|
|
518
565
|
// Windows + WSL: 尝试读取 WSL 内的配置文件
|
|
566
|
+
let wslConfigPath = null;
|
|
567
|
+
let wslAuthProfiles = null;
|
|
519
568
|
if (process.platform === 'win32' && isWslAvailable()) {
|
|
520
569
|
try {
|
|
521
|
-
const
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
if (check.ok && check.output.trim() === 'yes') {
|
|
532
|
-
// 将 WSL 配置复制到 Windows 侧,保持同步
|
|
533
|
-
const winDest = path.join(openclawStateDir, path.basename(wp));
|
|
534
|
-
try {
|
|
535
|
-
const content = execFileSync('wsl', ['bash', '-c', `cat '${wp}'`], { encoding: 'utf8', timeout: 10000, stdio: 'pipe' });
|
|
536
|
-
if (!fs.existsSync(openclawStateDir)) fs.mkdirSync(openclawStateDir, { recursive: true });
|
|
570
|
+
const mirrorInfo = getWslMirrorInfo();
|
|
571
|
+
wslConfigPath = mirrorInfo.configPath;
|
|
572
|
+
wslAuthProfiles = mirrorInfo.authProfiles;
|
|
573
|
+
|
|
574
|
+
if (wslConfigPath) {
|
|
575
|
+
const winDest = path.join(openclawStateDir, path.basename(wslConfigPath));
|
|
576
|
+
try {
|
|
577
|
+
if (!fs.existsSync(openclawStateDir)) fs.mkdirSync(openclawStateDir, { recursive: true });
|
|
578
|
+
if (!fs.existsSync(winDest)) {
|
|
579
|
+
const content = execFileSync('wsl', ['bash', '-c', `cat '${wslConfigPath}'`], { encoding: 'utf8', timeout: 10000, stdio: 'pipe' });
|
|
537
580
|
fs.writeFileSync(winDest, content, 'utf8');
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
}
|
|
581
|
+
}
|
|
582
|
+
if (!candidates.includes(winDest)) candidates.unshift(winDest);
|
|
583
|
+
} catch { }
|
|
542
584
|
}
|
|
543
585
|
} catch { }
|
|
544
586
|
}
|
|
@@ -559,6 +601,9 @@ function getConfigPath() {
|
|
|
559
601
|
: [...baseAuthCandidates, ...moltbotAuthCandidates];
|
|
560
602
|
|
|
561
603
|
const authProfiles = authCandidates.find(p => fs.existsSync(p)) || authCandidates[0];
|
|
604
|
+
const authSyncTargets = process.platform === 'win32'
|
|
605
|
+
? [...new Set(buildAuthCandidates([openclawStateDir, clawdbotStateDir]))].filter(p => p !== authProfiles)
|
|
606
|
+
: [];
|
|
562
607
|
|
|
563
608
|
const syncTargets = [];
|
|
564
609
|
if (openclawConfig.startsWith(openclawStateDir) && fs.existsSync(clawdbotStateDir)) {
|
|
@@ -568,7 +613,7 @@ function getConfigPath() {
|
|
|
568
613
|
);
|
|
569
614
|
}
|
|
570
615
|
|
|
571
|
-
return { openclawConfig, authProfiles, configDir, syncTargets };
|
|
616
|
+
return { openclawConfig, authProfiles, configDir, syncTargets, authSyncTargets, wslConfigPath, wslAuthProfiles };
|
|
572
617
|
}
|
|
573
618
|
|
|
574
619
|
// ============ 配置读写 ============
|
|
@@ -688,7 +733,7 @@ function writeCodexConfig(baseUrl, apiKey, modelId = 'gpt-5.4') {
|
|
|
688
733
|
const markerEnd = '# <<< maxapi codex <<<';
|
|
689
734
|
const topMarker = '# >>> maxapi codex top >>>';
|
|
690
735
|
const topMarkerEnd = '# <<< maxapi codex top <<<';
|
|
691
|
-
const providerKey = '
|
|
736
|
+
const providerKey = 'yunyi-codex';
|
|
692
737
|
// 确保 base_url 以 /v1 结尾(Codex CLI 要求)
|
|
693
738
|
let normalizedUrl = baseUrl.replace(/\/+$/, '');
|
|
694
739
|
if (!normalizedUrl.endsWith('/v1')) normalizedUrl += '/v1';
|
|
@@ -702,9 +747,11 @@ function writeCodexConfig(baseUrl, apiKey, modelId = 'gpt-5.4') {
|
|
|
702
747
|
// 移除旧的 maxapi top-level block
|
|
703
748
|
const topRe = new RegExp(`${topMarker.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[\\s\\S]*?${topMarkerEnd.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\n?`, 'g');
|
|
704
749
|
existing = existing.replace(topRe, '');
|
|
705
|
-
//
|
|
750
|
+
// 兼容旧版:移除散落的 model/model_provider、旧 openclaw-relay、旧 yunyi opencode 标记块
|
|
706
751
|
existing = existing.replace(/^model\s*=\s*"[^"]*"\s*$/gm, '');
|
|
707
752
|
existing = existing.replace(/^model_provider\s*=\s*"[^"]*"\s*$/gm, '');
|
|
753
|
+
existing = existing.replace(/\[model_providers\.openclaw-relay\]\n(?:(?!\[)[^\n]*\n?)*/g, '');
|
|
754
|
+
existing = existing.replace(/# >>> yunyi opencode >>>[\s\S]*?# <<< yunyi opencode <<<\n?/g, '');
|
|
708
755
|
existing = existing.replace(/\n{3,}/g, '\n\n').trim();
|
|
709
756
|
}
|
|
710
757
|
|
|
@@ -720,7 +767,7 @@ function writeCodexConfig(baseUrl, apiKey, modelId = 'gpt-5.4') {
|
|
|
720
767
|
const providerBlock = [
|
|
721
768
|
marker,
|
|
722
769
|
`[model_providers.${providerKey}]`,
|
|
723
|
-
`name = "
|
|
770
|
+
`name = "云翼 Codex"`,
|
|
724
771
|
`base_url = "${normalizedUrl}"`,
|
|
725
772
|
`wire_api = "responses"`,
|
|
726
773
|
`experimental_bearer_token = "${apiKey}"`,
|
|
@@ -819,31 +866,14 @@ function writeOpencodeConfig(claudeBaseUrl, codexBaseUrl, apiKey, modelId) {
|
|
|
819
866
|
// 移除旧标记块(仅移除 yunyi opencode 自己的)
|
|
820
867
|
content = content.replace(/# >>> yunyi opencode >>>[\s\S]*?# <<< yunyi opencode <<<\n?/g, '');
|
|
821
868
|
|
|
822
|
-
//
|
|
823
|
-
content = content.replace(/\[model_providers\.yunyi
|
|
824
|
-
|
|
825
|
-
// 只追加 yunyi-codex provider(Claude 配置仅在 opencode.json 中,Codex CLI 不支持 wire_api=anthropic)
|
|
826
|
-
const providers = [''];
|
|
827
|
-
if (codexUrl) {
|
|
828
|
-
providers.push(
|
|
829
|
-
'# >>> yunyi opencode >>>',
|
|
830
|
-
'[model_providers.yunyi-codex]',
|
|
831
|
-
'name = "云翼 Codex"',
|
|
832
|
-
`base_url = "${codexUrl}"`,
|
|
833
|
-
'wire_api = "responses"',
|
|
834
|
-
`experimental_bearer_token = "${apiKey}"`,
|
|
835
|
-
'requires_openai_auth = false',
|
|
836
|
-
'# <<< yunyi opencode <<<'
|
|
837
|
-
);
|
|
838
|
-
}
|
|
869
|
+
// 移除旧版 yunyi-cli 写入的 [model_providers.yunyi] 和 [model_providers.yunyi-claude](不动 yunyi-codex,由 writeCodexConfig 管理)
|
|
870
|
+
content = content.replace(/\[model_providers\.yunyi\]\n(?:(?!\[)[^\n]*\n?)*/g, '');
|
|
871
|
+
content = content.replace(/\[model_providers\.yunyi-claude\]\n(?:(?!\[)[^\n]*\n?)*/g, '');
|
|
839
872
|
|
|
840
873
|
// 清理多余空行
|
|
841
874
|
content = content.replace(/\n{3,}/g, '\n\n').trim();
|
|
842
875
|
|
|
843
|
-
//
|
|
844
|
-
if (providers.length > 1) {
|
|
845
|
-
content += '\n\n' + providers.join('\n') + '\n';
|
|
846
|
-
}
|
|
876
|
+
// yunyi-codex provider 由 writeCodexConfig 统一管理,此处不再重复写入
|
|
847
877
|
|
|
848
878
|
fs.writeFileSync(codexConfigPath, content, 'utf8');
|
|
849
879
|
|
|
@@ -894,10 +924,15 @@ function syncClawdbotConfigs(paths, config) {
|
|
|
894
924
|
function writeConfigWithSync(paths, config) {
|
|
895
925
|
writeConfig(paths.openclawConfig, config);
|
|
896
926
|
syncClawdbotConfigs(paths, config);
|
|
927
|
+
const hasWslMirror = process.platform === 'win32' && !!paths.wslConfigPath;
|
|
928
|
+
if (hasWslMirror) {
|
|
929
|
+
syncConfigToWsl(paths.openclawConfig, paths.wslConfigPath);
|
|
930
|
+
}
|
|
931
|
+
invalidateGatewayEnvCache();
|
|
897
932
|
// 如果 Gateway 在 WSL,自动同步配置过去
|
|
898
933
|
const gwEnv = detectGatewayEnv();
|
|
899
|
-
if (gwEnv === 'wsl') {
|
|
900
|
-
syncConfigToWsl(paths.openclawConfig);
|
|
934
|
+
if (!hasWslMirror && gwEnv === 'wsl') {
|
|
935
|
+
syncConfigToWsl(paths.openclawConfig, paths.wslConfigPath);
|
|
901
936
|
}
|
|
902
937
|
// 如果 Gateway 在 Docker 容器内,自动同步配置过去
|
|
903
938
|
if (gwEnv === 'docker' && _selectedDockerContainer) {
|
|
@@ -1096,6 +1131,10 @@ let _gwEnvCache = null;
|
|
|
1096
1131
|
let _wslAvailCache = null;
|
|
1097
1132
|
let _wslHomeCache = undefined; // undefined = 未检测, null = 检测失败
|
|
1098
1133
|
|
|
1134
|
+
function invalidateGatewayEnvCache() {
|
|
1135
|
+
_gwEnvCache = null;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1099
1138
|
function isWslAvailable() {
|
|
1100
1139
|
if (process.platform !== 'win32') return false;
|
|
1101
1140
|
if (_wslAvailCache !== null) return _wslAvailCache;
|
|
@@ -1221,16 +1260,12 @@ function execAsyncInGatewayEnv(cmd, options = {}) {
|
|
|
1221
1260
|
}
|
|
1222
1261
|
|
|
1223
1262
|
// 同步配置到 WSL(仅在 Gateway 环境为 WSL 时调用)
|
|
1224
|
-
function syncConfigToWsl(windowsConfigPath) {
|
|
1263
|
+
function syncConfigToWsl(windowsConfigPath, wslDestPath) {
|
|
1225
1264
|
try {
|
|
1226
1265
|
const wslHome = getWslHome();
|
|
1227
|
-
if (!wslHome) return;
|
|
1228
|
-
const
|
|
1229
|
-
|
|
1230
|
-
if (!match) return;
|
|
1231
|
-
const wslSrc = `/mnt/${match[1].toLowerCase()}/${match[2]}`;
|
|
1232
|
-
const wslDest = `${wslHome}/.openclaw/openclaw.json`;
|
|
1233
|
-
execFileSync('wsl', ['bash', '-c', `mkdir -p "${wslHome}/.openclaw" && cp "${wslSrc}" "${wslDest}"`], { timeout: 10000, stdio: 'pipe' });
|
|
1266
|
+
if (!wslHome && !wslDestPath) return;
|
|
1267
|
+
const target = wslDestPath || `${wslHome}/.openclaw/openclaw.json`;
|
|
1268
|
+
syncFileToWsl(windowsConfigPath, target);
|
|
1234
1269
|
} catch { /* best-effort */ }
|
|
1235
1270
|
}
|
|
1236
1271
|
|
|
@@ -1427,9 +1462,70 @@ function readAuthStore(authProfilesPath) {
|
|
|
1427
1462
|
}
|
|
1428
1463
|
|
|
1429
1464
|
function writeAuthStore(authProfilesPath, store) {
|
|
1465
|
+
const authDir = path.dirname(authProfilesPath);
|
|
1466
|
+
if (!fs.existsSync(authDir)) {
|
|
1467
|
+
fs.mkdirSync(authDir, { recursive: true });
|
|
1468
|
+
}
|
|
1430
1469
|
fs.writeFileSync(authProfilesPath, JSON.stringify(store, null, 2), 'utf8');
|
|
1431
1470
|
}
|
|
1432
1471
|
|
|
1472
|
+
function toWslMountPath(windowsPath) {
|
|
1473
|
+
const winNorm = String(windowsPath || '').replace(/\\/g, '/');
|
|
1474
|
+
const match = winNorm.match(/^([A-Za-z]):\/(.*)/);
|
|
1475
|
+
if (!match) return null;
|
|
1476
|
+
return `/mnt/${match[1].toLowerCase()}/${match[2]}`;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
function syncFileToWsl(windowsPath, wslDestPath) {
|
|
1480
|
+
if (process.platform !== 'win32' || !wslDestPath) return false;
|
|
1481
|
+
const wslSrc = toWslMountPath(windowsPath);
|
|
1482
|
+
if (!wslSrc) return false;
|
|
1483
|
+
|
|
1484
|
+
const wslDir = path.posix.dirname(wslDestPath);
|
|
1485
|
+
execFileSync('wsl', ['bash', '-lc', `mkdir -p ${shellQuote(wslDir)} && cp ${shellQuote(wslSrc)} ${shellQuote(wslDestPath)}`], {
|
|
1486
|
+
timeout: 10000,
|
|
1487
|
+
stdio: 'pipe'
|
|
1488
|
+
});
|
|
1489
|
+
return true;
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
function syncAuthProfilesToWsl(windowsAuthProfilesPath, wslDestPath) {
|
|
1493
|
+
try {
|
|
1494
|
+
const wslHome = getWslHome();
|
|
1495
|
+
if (!wslHome && !wslDestPath) return;
|
|
1496
|
+
const target = wslDestPath || path.posix.join(wslHome, '.openclaw', 'agents', 'main', 'agent', 'auth-profiles.json');
|
|
1497
|
+
syncFileToWsl(windowsAuthProfilesPath, target);
|
|
1498
|
+
} catch { /* best-effort */ }
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
function syncMirroredAuthStores(paths) {
|
|
1502
|
+
if (!paths?.authProfiles) return;
|
|
1503
|
+
|
|
1504
|
+
const store = readAuthStore(paths.authProfiles);
|
|
1505
|
+
for (const target of [...new Set(paths.authSyncTargets || [])]) {
|
|
1506
|
+
if (!target || target === paths.authProfiles) continue;
|
|
1507
|
+
try {
|
|
1508
|
+
writeAuthStore(target, store);
|
|
1509
|
+
} catch { /* best-effort */ }
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
if (process.platform === 'win32' && (paths.wslAuthProfiles || paths.wslConfigPath)) {
|
|
1513
|
+
const derivedWslAuthPath = paths.wslAuthProfiles || path.posix.join(path.posix.dirname(paths.wslConfigPath), 'agents', 'main', 'agent', 'auth-profiles.json');
|
|
1514
|
+
syncAuthProfilesToWsl(paths.authProfiles, derivedWslAuthPath);
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
function pruneAuthProfilesExceptWithSync(paths, keepProviders = []) {
|
|
1519
|
+
const removed = pruneAuthProfilesExcept(paths.authProfiles, keepProviders);
|
|
1520
|
+
syncMirroredAuthStores(paths);
|
|
1521
|
+
return removed;
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
function updateAuthProfilesWithSync(paths, providerName, apiKey) {
|
|
1525
|
+
updateAuthProfiles(paths.authProfiles, providerName, apiKey);
|
|
1526
|
+
syncMirroredAuthStores(paths);
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1433
1529
|
function pruneAuthProfilesByPrefix(authProfilesPath, prefixBase, keepProviders = []) {
|
|
1434
1530
|
const keepSet = new Set(keepProviders);
|
|
1435
1531
|
const store = readAuthStore(authProfilesPath);
|
|
@@ -2313,7 +2409,7 @@ async function quickSetup(paths, args = {}) {
|
|
|
2313
2409
|
|
|
2314
2410
|
if (toRemove.length > 0) {
|
|
2315
2411
|
pruneProvidersExcept(config, [providerName]);
|
|
2316
|
-
|
|
2412
|
+
pruneAuthProfilesExceptWithSync(paths, [providerName]);
|
|
2317
2413
|
}
|
|
2318
2414
|
|
|
2319
2415
|
config.models.providers[providerName] = {
|
|
@@ -2351,7 +2447,7 @@ async function quickSetup(paths, args = {}) {
|
|
|
2351
2447
|
ensureGatewaySettings(config);
|
|
2352
2448
|
if (apiConfig.api.startsWith('openai')) cleanupConflictingEnvVars(config, normalizedBaseUrl, apiKey);
|
|
2353
2449
|
writeConfigWithSync(paths, config);
|
|
2354
|
-
|
|
2450
|
+
updateAuthProfilesWithSync(paths, providerName, apiKey);
|
|
2355
2451
|
ws.succeed('配置写入完成');
|
|
2356
2452
|
|
|
2357
2453
|
console.log(chalk.green(`\n✅ ${typeLabel} 中转已配置完成!`));
|
|
@@ -2431,7 +2527,7 @@ async function presetClaude(paths, args = {}) {
|
|
|
2431
2527
|
? pruneProvidersExcept(config, [providerName])
|
|
2432
2528
|
: [];
|
|
2433
2529
|
if (removedProviders.length > 0) {
|
|
2434
|
-
|
|
2530
|
+
pruneAuthProfilesExceptWithSync(paths, [providerName]);
|
|
2435
2531
|
}
|
|
2436
2532
|
|
|
2437
2533
|
const baseUrl = buildFullUrl(selectedEndpoint.url, 'claude');
|
|
@@ -2535,7 +2631,7 @@ async function presetClaude(paths, args = {}) {
|
|
|
2535
2631
|
createTimestampedBackup(paths.openclawConfig, paths.configDir, 'claude');
|
|
2536
2632
|
ensureGatewaySettings(config);
|
|
2537
2633
|
writeConfigWithSync(paths, config);
|
|
2538
|
-
|
|
2634
|
+
updateAuthProfilesWithSync(paths, providerName, apiKey);
|
|
2539
2635
|
const extSynced = syncExternalTools('claude', baseUrl, apiKey);
|
|
2540
2636
|
writeSpinner.succeed('配置写入完成');
|
|
2541
2637
|
|
|
@@ -2625,7 +2721,7 @@ async function presetCodex(paths, args = {}) {
|
|
|
2625
2721
|
? pruneProvidersExcept(config, [providerName])
|
|
2626
2722
|
: [];
|
|
2627
2723
|
if (removedProviders.length > 0) {
|
|
2628
|
-
|
|
2724
|
+
pruneAuthProfilesExceptWithSync(paths, [providerName]);
|
|
2629
2725
|
}
|
|
2630
2726
|
|
|
2631
2727
|
const baseUrl = buildFullUrl(selectedEndpoint.url, 'codex');
|
|
@@ -2729,7 +2825,7 @@ async function presetCodex(paths, args = {}) {
|
|
|
2729
2825
|
ensureGatewaySettings(config);
|
|
2730
2826
|
cleanupConflictingEnvVars(config, baseUrl, apiKey);
|
|
2731
2827
|
writeConfigWithSync(paths, config);
|
|
2732
|
-
|
|
2828
|
+
updateAuthProfilesWithSync(paths, providerName, apiKey);
|
|
2733
2829
|
const extSynced2 = syncExternalTools('codex', baseUrl, apiKey);
|
|
2734
2830
|
writeSpinner2.succeed('配置写入完成');
|
|
2735
2831
|
|
|
@@ -2913,8 +3009,8 @@ async function autoActivate(paths, args = {}) {
|
|
|
2913
3009
|
ensureGatewaySettings(config);
|
|
2914
3010
|
cleanupConflictingEnvVars(config, codexBaseUrl, apiKey);
|
|
2915
3011
|
writeConfigWithSync(paths, config);
|
|
2916
|
-
|
|
2917
|
-
|
|
3012
|
+
updateAuthProfilesWithSync(paths, claudeProviderName, apiKey);
|
|
3013
|
+
updateAuthProfilesWithSync(paths, codexProviderName, apiKey);
|
|
2918
3014
|
const extSynced = [];
|
|
2919
3015
|
try { syncExternalTools('claude', claudeBaseUrl, apiKey, { codexBaseUrl }); extSynced.push('Claude Code settings'); } catch { /* ignore */ }
|
|
2920
3016
|
try { syncExternalTools('codex', codexBaseUrl, apiKey); extSynced.push('Codex CLI config'); } catch { /* ignore */ }
|
|
@@ -3348,8 +3444,8 @@ async function yycodeQuickSetup(paths) {
|
|
|
3348
3444
|
ensureGatewaySettings(config);
|
|
3349
3445
|
cleanupConflictingEnvVars(config, codexBaseUrl, apiKey);
|
|
3350
3446
|
writeConfigWithSync(paths, config);
|
|
3351
|
-
|
|
3352
|
-
|
|
3447
|
+
updateAuthProfilesWithSync(paths, claudeProviderName, apiKey);
|
|
3448
|
+
updateAuthProfilesWithSync(paths, codexProviderName, apiKey);
|
|
3353
3449
|
try { syncExternalTools('claude', claudeBaseUrl, apiKey, { codexBaseUrl }); } catch { /* ignore */ }
|
|
3354
3450
|
try { syncExternalTools('codex', codexBaseUrl, apiKey); } catch { /* ignore */ }
|
|
3355
3451
|
writeSpinner.succeed('配置写入完成');
|
|
@@ -3943,6 +4039,7 @@ async function manageToolsProfile(paths) {
|
|
|
3943
4039
|
// ============ 测试连接 ============
|
|
3944
4040
|
async function testConnection(paths, args = {}) {
|
|
3945
4041
|
console.log(chalk.cyan('🧪 测试 OpenClaw Gateway 连接\n'));
|
|
4042
|
+
invalidateGatewayEnvCache();
|
|
3946
4043
|
|
|
3947
4044
|
const config = readConfig(paths.openclawConfig);
|
|
3948
4045
|
|
|
@@ -4079,6 +4176,15 @@ async function testConnection(paths, args = {}) {
|
|
|
4079
4176
|
console.log(chalk.red(` 期望: ${primary}`));
|
|
4080
4177
|
console.log(chalk.cyan(` 实际: ${actualModelKey}`));
|
|
4081
4178
|
console.log(chalk.gray(` 这意味着 ${primary} 无法正常工作,请检查该模型的中转配置`));
|
|
4179
|
+
const configuredFallbacks = config.agents?.defaults?.model?.fallbacks || [];
|
|
4180
|
+
if (configuredFallbacks.length > 0 && !configuredFallbacks.includes(actualModelKey)) {
|
|
4181
|
+
console.log(chalk.yellow(` ⚠️ 实际回退模型不在当前配置的 fallbacks 中,疑似读到了另一份配置`));
|
|
4182
|
+
console.log(chalk.gray(` 当前 fallbacks: ${configuredFallbacks.join(', ')}`));
|
|
4183
|
+
console.log(chalk.gray(` 当前配置文件: ${paths.openclawConfig}`));
|
|
4184
|
+
if (process.platform === 'win32') {
|
|
4185
|
+
console.log(chalk.gray(' Windows 请重点检查: %USERPROFILE%\\.openclaw、%USERPROFILE%\\.clawdbot、WSL ~/.openclaw'));
|
|
4186
|
+
}
|
|
4187
|
+
}
|
|
4082
4188
|
// 检查是否可能是 api 字段错误导致的 502
|
|
4083
4189
|
const expectedProvider = primary.split('/')[0];
|
|
4084
4190
|
const providerCfg = config.models?.providers?.[expectedProvider];
|
|
@@ -4200,6 +4306,7 @@ async function testConnection(paths, args = {}) {
|
|
|
4200
4306
|
// ============ 重启 Gateway ============
|
|
4201
4307
|
async function restartGateway({ silent = false } = {}) {
|
|
4202
4308
|
if (!silent) console.log(chalk.cyan('\n正在重启 OpenClaw Gateway...'));
|
|
4309
|
+
invalidateGatewayEnvCache();
|
|
4203
4310
|
|
|
4204
4311
|
const gwEnv = detectGatewayEnv();
|
|
4205
4312
|
const configPaths = getConfigPath();
|