yymaxapi 1.0.86 → 1.0.88

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 +37 -108
  2. package/package.json +1 -1
package/bin/yymaxapi.js CHANGED
@@ -56,6 +56,20 @@ function safeExec(cmd, options = {}) {
56
56
  }
57
57
  }
58
58
 
59
+ function shouldSuppressProcessWarning(warning) {
60
+ const message = typeof warning === 'string' ? warning : String(warning?.message || '');
61
+ return message.includes("Setting the NODE_TLS_REJECT_UNAUTHORIZED environment variable to '0'");
62
+ }
63
+
64
+ if (!process.__yymaxapiWarningFilterInstalled && typeof process.emitWarning === 'function') {
65
+ const originalEmitWarning = process.emitWarning.bind(process);
66
+ process.emitWarning = function patchedEmitWarning(warning, ...args) {
67
+ if (shouldSuppressProcessWarning(warning)) return;
68
+ return originalEmitWarning(warning, ...args);
69
+ };
70
+ process.__yymaxapiWarningFilterInstalled = true;
71
+ }
72
+
59
73
  // ============ 预设 (由 build.js 从 provider config 生成) ============
60
74
  const DEFAULT_ENDPOINTS = [
61
75
  {
@@ -493,41 +507,8 @@ async function validateApiKey(nodeUrl, apiKey) {
493
507
  try {
494
508
  const res = await httpGetJson(verifyUrl, { Authorization: `Bearer ${apiKey}` });
495
509
  if (res.status === 200 && res.data) {
496
- spinner.succeed('API Key 验证成功');
497
- const d = res.data;
498
- // 基本信息
499
- if (d.service_type) console.log(chalk.gray(` 服务类型: ${d.service_type}`));
500
- if (d.billing_mode) console.log(chalk.gray(` 计费模式: ${d.billing_mode}`));
501
- if (d.status && d.status !== 'active') console.log(chalk.yellow(` ⚠ 状态: ${d.status}`));
502
- // 配额信息
503
- if (d.total_quota !== undefined || d.remaining_quota !== undefined) {
504
- const total = d.total_quota || 0;
505
- const remaining = d.remaining_quota !== undefined ? d.remaining_quota : total;
506
- const used = total - remaining;
507
- const pct = total > 0 ? Math.round((used / total) * 100) : 0;
508
- const barLen = 20;
509
- const filled = Math.round(barLen * pct / 100);
510
- const bar = chalk.green('█'.repeat(filled)) + chalk.gray('░'.repeat(barLen - filled));
511
- console.log(chalk.gray(` 总配额: ${total}`) + (d.max_requests ? chalk.gray(` | 最大请求: ${d.max_requests}`) : ''));
512
- console.log(chalk.gray(` 已用/剩余: ${used} / ${remaining}`));
513
- console.log(` [${bar}] ${pct}%`);
514
- }
515
- // 每日配额
516
- if (d.daily_quota !== undefined || d.daily_remaining !== undefined) {
517
- const dTotal = d.daily_quota || 0;
518
- const dRemain = d.daily_remaining !== undefined ? d.daily_remaining : dTotal;
519
- const dUsed = d.daily_used !== undefined ? d.daily_used : (dTotal - dRemain);
520
- console.log(chalk.gray(` 今日配额: ${dTotal} | 已用: ${dUsed} | 剩余: ${dRemain}`));
521
- }
522
- // 有效期
523
- if (d.activated_at) console.log(chalk.gray(` 激活时间: ${new Date(d.activated_at).toLocaleDateString()}`));
524
- if (d.expires_at) {
525
- const exp = new Date(d.expires_at);
526
- const daysLeft = Math.ceil((exp - Date.now()) / 86400000);
527
- const expColor = daysLeft <= 7 ? chalk.red : daysLeft <= 30 ? chalk.yellow : chalk.gray;
528
- console.log(expColor(` 有效期至: ${exp.toLocaleDateString()} (${daysLeft > 0 ? `剩余 ${daysLeft} 天` : '已过期'})`));
529
- }
530
- return { valid: true, data: d };
510
+ spinner.succeed('API Key 可用');
511
+ return { valid: true, data: res.data };
531
512
  } else {
532
513
  spinner.fail('API Key 验证失败');
533
514
  console.log(chalk.red(` HTTP ${res.status}`));
@@ -2368,13 +2349,10 @@ function applyManagedYunyiOpenClawLayout(config, options = {}) {
2368
2349
 
2369
2350
  function printYunyiOpenClawSwitchHint(result = {}) {
2370
2351
  if (!result?.applied) return;
2371
- if (result.preservedMain && result.claudeAgentId === YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID) {
2372
- console.log(chalk.gray(' 已保留你现有的 main;Yunyi Claude 入口为 yunyi-claude'));
2373
- } else {
2374
- console.log(chalk.gray(' 默认主入口是 yunyi-claude'));
2375
- }
2376
- console.log(chalk.gray(' GPT 入口是 yunyi-gpt'));
2377
- console.log(chalk.yellow(' 提示: 当前 OpenClaw Web 顶部模型下拉跨 provider 切换可能报错,建议通过左侧会话/agent 切换 Claude 和 GPT'));
2352
+ const summary = result.preservedMain && result.claudeAgentId === YYMAXAPI_OPENCLAW_ALT_CLAUDE_AGENT_ID
2353
+ ? 'OpenClaw: main 已保留, Claude=yunyi-claude, GPT=yunyi-gpt'
2354
+ : 'OpenClaw: main=yunyi-claude, GPT=yunyi-gpt';
2355
+ console.log(chalk.cyan(` ${summary}`));
2378
2356
  }
2379
2357
 
2380
2358
  function pruneProvidersByPrefix(config, prefixBase, keepProviders = []) {
@@ -3948,17 +3926,13 @@ async function presetClaude(paths, args = {}) {
3948
3926
  updateAuthProfilesWithSync(paths, YYMAXAPI_OPENCLAW_CLAUDE_PROVIDER, apiKey);
3949
3927
  updateAuthProfilesWithSync(paths, YYMAXAPI_OPENCLAW_GPT_PROVIDER, apiKey);
3950
3928
  }
3951
- const extSynced = syncExternalTools('claude', baseUrl, apiKey, { claudeModelId: modelId, opencodeDefaultModelKey: `yunyi-claude/${modelId}` });
3929
+ syncExternalTools('claude', baseUrl, apiKey, { claudeModelId: modelId, opencodeDefaultModelKey: `yunyi-claude/${modelId}` });
3952
3930
  writeSpinner.succeed('配置写入完成');
3953
3931
 
3954
3932
  console.log(chalk.green('\n✅ Claude 节点配置完成!'));
3955
- const tag = setPrimary ? ' (主)' : '';
3956
- console.log(chalk.cyan(` ${providerName}${tag}: ${buildFullUrl(selectedEndpoint.url, 'claude')}`));
3957
- console.log(chalk.gray(` 模型: ${modelName}`));
3958
- console.log(chalk.gray(' API Key: 已设置'));
3959
- if (extSynced.length > 0) console.log(chalk.gray(` 同步: ${extSynced.join(', ')}`));
3933
+ console.log(chalk.cyan(` Claude: ${modelName}`));
3960
3934
  if (repairResult.renamedProviders.length > 0) {
3961
- console.log(chalk.gray(` 已保留并修复冲突 provider: ${repairResult.renamedProviders.map(item => `${item.from}→${item.to}`).join(', ')}`));
3935
+ console.log(chalk.cyan(` 已修复 provider 冲突: ${repairResult.renamedProviders.map(item => `${item.from}→${item.to}`).join(', ')}`));
3962
3936
  }
3963
3937
  printYunyiOpenClawSwitchHint(yunyiLayoutResult);
3964
3938
 
@@ -4135,17 +4109,13 @@ async function presetCodex(paths, args = {}) {
4135
4109
  updateAuthProfilesWithSync(paths, YYMAXAPI_OPENCLAW_CLAUDE_PROVIDER, apiKey);
4136
4110
  updateAuthProfilesWithSync(paths, YYMAXAPI_OPENCLAW_GPT_PROVIDER, apiKey);
4137
4111
  }
4138
- const extSynced2 = syncExternalTools('codex', baseUrl, apiKey, { modelId });
4112
+ syncExternalTools('codex', baseUrl, apiKey, { modelId });
4139
4113
  writeSpinner2.succeed('配置写入完成');
4140
4114
 
4141
4115
  console.log(chalk.green('\n✅ Codex 节点配置完成!'));
4142
- const tag = setPrimary ? ' (主)' : '';
4143
- console.log(chalk.cyan(` ${providerName}${tag}: ${baseUrl}`));
4144
- console.log(chalk.gray(` 模型: ${modelName}`));
4145
- console.log(chalk.gray(' API Key: 已设置'));
4146
- if (extSynced2.length > 0) console.log(chalk.gray(` 同步: ${extSynced2.join(', ')}`));
4116
+ console.log(chalk.cyan(` Codex: ${modelName}`));
4147
4117
  if (repairResult.renamedProviders.length > 0) {
4148
- console.log(chalk.gray(` 已保留并修复冲突 provider: ${repairResult.renamedProviders.map(item => `${item.from}→${item.to}`).join(', ')}`));
4118
+ console.log(chalk.cyan(` 已修复 provider 冲突: ${repairResult.renamedProviders.map(item => `${item.from}→${item.to}`).join(', ')}`));
4149
4119
  }
4150
4120
  printYunyiOpenClawSwitchHint(yunyiLayoutResult);
4151
4121
 
@@ -4330,22 +4300,15 @@ async function autoActivate(paths, args = {}) {
4330
4300
  writeConfigWithSync(paths, config);
4331
4301
  updateAuthProfilesWithSync(paths, claudeProviderName, apiKey);
4332
4302
  updateAuthProfilesWithSync(paths, codexProviderName, apiKey);
4333
- const extSynced = [];
4334
4303
  const opencodeDefaultModelKey = isClaudePrimary ? `yunyi-claude/${claudeModelId}` : `yunyi-codex/${codexModelId}`;
4335
- try { extSynced.push(...syncExternalTools('claude', claudeBaseUrl, apiKey, { codexBaseUrl, claudeModelId, opencodeDefaultModelKey })); } catch { /* ignore */ }
4336
- try { extSynced.push(...syncExternalTools('codex', codexBaseUrl, apiKey, { modelId: codexModelId })); } catch { /* ignore */ }
4304
+ try { syncExternalTools('claude', claudeBaseUrl, apiKey, { codexBaseUrl, claudeModelId, opencodeDefaultModelKey }); } catch { /* ignore */ }
4305
+ try { syncExternalTools('codex', codexBaseUrl, apiKey, { modelId: codexModelId }); } catch { /* ignore */ }
4337
4306
  writeSpinner.succeed('配置写入完成');
4338
4307
 
4339
4308
  // ---- 输出结果 ----
4340
- const primaryLabel = isClaudePrimary ? 'Claude' : 'GPT';
4341
4309
  const selectedModel = isClaudePrimary ? claudeModel : codexModel;
4342
4310
  console.log(chalk.green('\n✅ 配置完成!'));
4343
- console.log(chalk.cyan(` 外部工具默认: ${selectedModel.name} (${primaryLabel})`));
4344
- console.log(chalk.gray(` 节点: ${selectedEndpoint.url} (${selectedEndpoint.name})`));
4345
- console.log(chalk.gray(' API Key: 已设置'));
4346
- if (extSynced.length > 0) console.log(chalk.gray(` 同步: ${extSynced.join(', ')}`));
4347
- console.log(chalk.gray(' 若遇 certificate 报错,请新开终端或执行 source ~/.zshrc 后重试(已放宽 TLS 校验)'));
4348
- console.log(chalk.gray(` 使用 OpenCode 时可在界面中切换 ${getOpencodeSwitchHint()};Codex 仅支持 GPT`));
4311
+ console.log(chalk.cyan(` 外部工具默认: ${selectedModel.name}`));
4349
4312
  printYunyiOpenClawSwitchHint(yunyiLayoutResult);
4350
4313
 
4351
4314
  const gwPort = config.gateway?.port || 18789;
@@ -4790,12 +4753,8 @@ async function yycodeQuickSetup(paths) {
4790
4753
 
4791
4754
  // ---- 结果 ----
4792
4755
  console.log(chalk.green('\n✅ 配置完成!'));
4793
- console.log(chalk.cyan(` Claude Code: ${claudeBaseUrl}`));
4794
- console.log(chalk.gray(` 模型: ${claudeModel.name}`));
4795
- console.log(chalk.cyan(` Codex CLI: ${codexBaseUrl}`));
4796
- console.log(chalk.gray(` 模型: ${codexModel.name}`));
4797
- console.log(chalk.gray(' API Key: 已设置'));
4798
- console.log(chalk.gray(' 同步: Claude Code settings, Opencode config, Codex CLI config'));
4756
+ console.log(chalk.cyan(` Claude Code: ${claudeModel.name}`));
4757
+ console.log(chalk.cyan(` Codex CLI: ${codexModel.name}`));
4799
4758
  printYunyiOpenClawSwitchHint(yunyiLayoutResult);
4800
4759
  console.log('');
4801
4760
  }
@@ -5072,9 +5031,7 @@ async function selectNode(paths, type) {
5072
5031
  if (managedGptKey) updateAuthProfilesWithSync(paths, YYMAXAPI_OPENCLAW_GPT_PROVIDER, managedGptKey);
5073
5032
 
5074
5033
  console.log(chalk.green(`\n✅ ${typeLabel} 节点配置完成!`));
5075
- console.log(chalk.cyan(` 节点: ${selectedEndpoint.name} (${selectedEndpoint.url})`));
5076
- console.log(chalk.gray(` 模型: ${modelConfig.name} (主模型)`));
5077
- console.log(chalk.gray(` API Key: ${oldApiKey ? '已设置' : '未设置'}`));
5034
+ console.log(chalk.cyan(` ${typeLabel}: ${modelConfig.name}`));
5078
5035
  printYunyiOpenClawSwitchHint(yunyiLayoutResult);
5079
5036
  }
5080
5037
 
@@ -5129,9 +5086,7 @@ async function activate(paths, type) {
5129
5086
  writeAuthStore(paths.authProfiles, authStore);
5130
5087
 
5131
5088
  console.log(chalk.green(`\n✅ 已激活 ${typeLabel}`));
5132
- console.log(chalk.cyan(` 节点: ${provider.baseUrl}`));
5133
- console.log(chalk.gray(` 模型: ${modelConfig.name}`));
5134
- console.log(chalk.gray(` API Key: 已设置`));
5089
+ console.log(chalk.cyan(` ${typeLabel}: ${modelConfig.name}`));
5135
5090
  printYunyiOpenClawSwitchHint(yunyiLayoutResult);
5136
5091
  }
5137
5092
 
@@ -5438,16 +5393,11 @@ async function testConnection(paths, args = {}) {
5438
5393
  // 获取 Gateway 配置
5439
5394
  const gatewayPort = config.gateway?.port || 18789;
5440
5395
 
5441
- console.log(chalk.gray(`当前测试: ${typeLabel}`));
5396
+ console.log(chalk.cyan(`当前测试: ${typeLabel}`));
5442
5397
  if (testTarget.agentId) {
5443
- console.log(chalk.gray(`测试入口: ${testTarget.agentId}${testTarget.agentName ? ` (${testTarget.agentName})` : ''}`));
5444
- }
5445
- if (testTarget.agentId && testTarget.defaultPrimary && testTarget.defaultPrimary !== primary) {
5446
- console.log(chalk.gray(`默认主入口: ${testTarget.defaultPrimary}`));
5398
+ console.log(chalk.cyan(`测试入口: ${testTarget.agentId}${testTarget.agentName ? ` (${testTarget.agentName})` : ''}`));
5447
5399
  }
5448
- console.log(chalk.gray(`中转节点: ${provider.baseUrl}`));
5449
- console.log(chalk.gray(`模型: ${primary}`));
5450
- console.log(chalk.gray(`Gateway: http://127.0.0.1:${gatewayPort}\n`));
5400
+ console.log(chalk.cyan(`模型: ${primary}\n`));
5451
5401
  // 获取 Gateway token
5452
5402
  const gatewayToken = config.gateway?.auth?.token;
5453
5403
  if (!gatewayToken) {
@@ -5574,17 +5524,6 @@ async function testConnection(paths, args = {}) {
5574
5524
  console.log(chalk.cyan(` Provider: ${cliResult.provider}`));
5575
5525
  console.log(chalk.cyan(` Model: ${cliResult.model}`));
5576
5526
  }
5577
- if (cliResult.message) {
5578
- const reply = sanitizeModelReply(cliResult.message, {
5579
- provider: cliResult.provider,
5580
- model: cliResult.model,
5581
- modelKey: primary
5582
- });
5583
- console.log(chalk.yellow(` 模型回复: ${reply}`));
5584
- }
5585
- if (!isFallback) {
5586
- console.log(chalk.gray(' 将继续验证 Web 鉴权端点(避免"CLI 正常但网页 401")...'));
5587
- }
5588
5527
  }
5589
5528
  }
5590
5529
 
@@ -5615,7 +5554,6 @@ async function testConnection(paths, args = {}) {
5615
5554
  const primaryApi = config.models?.providers?.[primaryProvider]?.api || '';
5616
5555
  const isAnthropic = primaryApi.startsWith('anthropic');
5617
5556
  const testEndpoint = isAnthropic ? '/v1/messages' : '/v1/chat/completions';
5618
- console.log(chalk.gray(` 端点: http://127.0.0.1:${gatewayPort}${testEndpoint}`));
5619
5557
  const startTime = Date.now();
5620
5558
  let result = await testGatewayApi(gatewayPort, gatewayToken, primary, testEndpoint);
5621
5559
  const latency = Date.now() - startTime;
@@ -5623,26 +5561,17 @@ async function testConnection(paths, args = {}) {
5623
5561
  // 回退:如果首选端点返回 404/405,尝试另一个
5624
5562
  if (!result.success && result.reachable && [404, 405].includes(result.status)) {
5625
5563
  const fallbackEndpoint = isAnthropic ? '/v1/chat/completions' : '/v1/responses';
5626
- console.log(chalk.gray(` ${testEndpoint} 不支持,回退测试 ${fallbackEndpoint}...`));
5627
5564
  result = await testGatewayApi(gatewayPort, gatewayToken, primary, fallbackEndpoint);
5628
5565
  }
5629
5566
 
5630
5567
  // CLI 对话已成功 + Gateway 可达(404/405)= Dashboard 通过 WebSocket 工作,视为通过
5631
5568
  if (!result.success && cliPassed && result.reachable && [404, 405].includes(result.status)) {
5632
5569
  console.log(chalk.green(`\n✅ Gateway 测试通过`));
5633
- console.log(chalk.cyan(` CLI 对话正常,Gateway 可达`));
5634
- console.log(chalk.gray(` 注: Gateway Dashboard 通过 WebSocket 通信,REST 端点返回 405 属正常现象`));
5635
5570
  console.log(chalk.green(`\n🌐 Web Dashboard 访问地址:`));
5636
5571
  console.log(chalk.cyan(` http://127.0.0.1:${gatewayPort}/#token=${gatewayToken}`));
5637
5572
  } else if (result.success) {
5638
- console.log(chalk.green(`\n✅ Gateway 测试成功!Web Dashboard 可正常使用`));
5573
+ console.log(chalk.green(`\n✅ Gateway 测试通过`));
5639
5574
  console.log(chalk.cyan(` 响应时间: ${latency}ms`));
5640
- const reply = sanitizeModelReply(result.message, {
5641
- provider: providerName,
5642
- model: primary.includes('/') ? primary.split('/')[1] : '',
5643
- modelKey: primary
5644
- });
5645
- console.log(chalk.yellow(` 模型回复: ${reply}`));
5646
5575
  console.log(chalk.green(`\n🌐 Web Dashboard 访问地址:`));
5647
5576
  console.log(chalk.cyan(` http://127.0.0.1:${gatewayPort}/#token=${gatewayToken}`));
5648
5577
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yymaxapi",
3
- "version": "1.0.86",
3
+ "version": "1.0.88",
4
4
  "description": "跨平台 OpenClaw/Clawdbot 配置管理工具 - 管理中转地址、模型切换、API Keys、测速优化",
5
5
  "main": "bin/yymaxapi.js",
6
6
  "bin": {