aihezu 2.8.7 → 2.8.9

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/aihezu.js CHANGED
@@ -40,7 +40,6 @@ function showHelp() {
40
40
  console.log(' aihezu usage 显示所有已配置服务的用量');
41
41
  console.log(' aihezu usage cc 只显示 Claude Code 用量');
42
42
  console.log(' aihezu usage codex 只显示 Codex 用量');
43
- console.log(' aihezu usage gemini 只显示 Google Gemini 用量');
44
43
  console.log(' aihezu usage --key sk-xxx 使用指定 API Key 查询');
45
44
  console.log('\n服务:');
46
45
  console.log(' claude Claude Code');
@@ -66,8 +66,9 @@ async function configCommand(service, args = []) {
66
66
  const urlObj = new URL(apiUrl);
67
67
  const hostname = urlObj.hostname;
68
68
 
69
- // Only add suffix for aihezu.dev and its subdomains
70
- if (hostname === 'aihezu.dev' || hostname.endsWith('.aihezu.dev')) {
69
+ // Only add suffix for aihezu.dev/aihezu.top and their subdomains
70
+ if (hostname === 'aihezu.dev' || hostname.endsWith('.aihezu.dev') ||
71
+ hostname === 'aihezu.top' || hostname.endsWith('.aihezu.top')) {
71
72
  const normalizedSuffix = suffix.startsWith('/') ? suffix : `/${suffix}`;
72
73
  const trimmedUrl = apiUrl.replace(/\/+$/, '');
73
74
  if (!trimmedUrl.endsWith(normalizedSuffix)) {
@@ -67,8 +67,9 @@ async function installCommand(service, args = []) {
67
67
  const urlObj = new URL(apiUrl);
68
68
  const hostname = urlObj.hostname;
69
69
 
70
- // Only add suffix for aihezu.dev and its subdomains
71
- if (hostname === 'aihezu.dev' || hostname.endsWith('.aihezu.dev')) {
70
+ // Only add suffix for aihezu.dev/aihezu.top and their subdomains
71
+ if (hostname === 'aihezu.dev' || hostname.endsWith('.aihezu.dev') ||
72
+ hostname === 'aihezu.top' || hostname.endsWith('.aihezu.top')) {
72
73
  const normalizedSuffix = suffix.startsWith('/') ? suffix : `/${suffix}`;
73
74
  const trimmedUrl = apiUrl.replace(/\/+$/, '');
74
75
  if (!trimmedUrl.endsWith(normalizedSuffix)) {
package/commands/usage.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const fs = require('fs');
2
2
  const os = require('os');
3
3
  const path = require('path');
4
- const { postJson } = require('../lib/http');
4
+ const { postJson, getJson } = require('../lib/http');
5
5
  const platform = require('../lib/platform');
6
6
 
7
7
  function normalizeHttpUrl(url) {
@@ -189,66 +189,6 @@ function readCodexConfig() {
189
189
  return configs;
190
190
  }
191
191
 
192
- // 读取 Gemini 配置
193
- function readGeminiConfig() {
194
- const configs = [];
195
-
196
- // 读取环境变量
197
- const envBaseUrl = process.env.GOOGLE_GEMINI_BASE_URL || '';
198
- const envAuthToken = process.env.GEMINI_API_KEY || '';
199
-
200
- if (envBaseUrl && envAuthToken) {
201
- configs.push({
202
- source: '环境变量',
203
- baseUrl: normalizeHttpUrl(envBaseUrl),
204
- authToken: envAuthToken.trim()
205
- });
206
- }
207
-
208
- // 读取配置文件
209
- const envFilePath = path.join(os.homedir(), '.gemini', '.env');
210
- if (fs.existsSync(envFilePath)) {
211
- try {
212
- const content = fs.readFileSync(envFilePath, 'utf8');
213
- const lines = content.split('\n');
214
-
215
- let fileBaseUrl = '';
216
- let fileAuthToken = '';
217
-
218
- for (const line of lines) {
219
- const match = line.match(/^(\w+)="?([^"]+)"?$/);
220
- if (match) {
221
- const [, key, value] = match;
222
- if (key === 'GOOGLE_GEMINI_BASE_URL') {
223
- fileBaseUrl = value;
224
- } else if (key === 'GEMINI_API_KEY') {
225
- fileAuthToken = value;
226
- }
227
- }
228
- }
229
-
230
- if (fileBaseUrl && fileAuthToken) {
231
- const isDuplicate = configs.some(c =>
232
- c.baseUrl === normalizeHttpUrl(fileBaseUrl) &&
233
- c.authToken === fileAuthToken.trim()
234
- );
235
-
236
- if (!isDuplicate) {
237
- configs.push({
238
- source: '配置文件',
239
- baseUrl: normalizeHttpUrl(fileBaseUrl),
240
- authToken: fileAuthToken.trim()
241
- });
242
- }
243
- }
244
- } catch (error) {
245
- // 忽略错误
246
- }
247
- }
248
-
249
- return configs;
250
- }
251
-
252
192
  function asNumber(value) {
253
193
  if (typeof value === 'number' && Number.isFinite(value)) return value;
254
194
  if (typeof value === 'string' && value.trim() !== '' && Number.isFinite(Number(value))) {
@@ -355,6 +295,167 @@ function usageHint(current, limit) {
355
295
  return '';
356
296
  }
357
297
 
298
+ function getCodexUsageBase(baseUrl) {
299
+ // 用户的 Codex base_url 形如 https://xxx.aihezu.dev/openai 或 https://xxx.aihezu.dev
300
+ // 新 usage 接口位于 /v1/usage,需要去掉可能存在的 /openai 后缀
301
+ try {
302
+ const url = new URL(baseUrl);
303
+ let pathname = url.pathname.replace(/\/+$/, '');
304
+ if (pathname.toLowerCase().endsWith('/openai')) {
305
+ pathname = pathname.slice(0, -'/openai'.length);
306
+ }
307
+ return `${url.origin}${pathname}`;
308
+ } catch (error) {
309
+ return baseUrl.replace(/\/+$/, '').replace(/\/openai$/i, '');
310
+ }
311
+ }
312
+
313
+ async function queryCodexUsage(baseUrl, authToken) {
314
+ try {
315
+ const apiBase = getCodexUsageBase(baseUrl);
316
+ const usageUrl = `${apiBase}/v1/usage`;
317
+ const res = await getJson(usageUrl, {
318
+ headers: { Authorization: `Bearer ${authToken}` }
319
+ });
320
+
321
+ if (res.statusCode < 200 || res.statusCode >= 300) {
322
+ const msg = res.json && (res.json.message || res.json.error || res.json.code);
323
+ return { error: msg ? `HTTP ${res.statusCode} - ${msg}` : `HTTP ${res.statusCode}` };
324
+ }
325
+
326
+ if (!res.json || typeof res.json !== 'object') {
327
+ return { error: '返回内容不是合法的 JSON' };
328
+ }
329
+
330
+ return { stats: res.json, origin: new URL(usageUrl).origin };
331
+ } catch (error) {
332
+ return { error: error.message };
333
+ }
334
+ }
335
+
336
+ function displayCodexUsageStats(stats, origin, source) {
337
+ const subscription = stats.subscription || {};
338
+ const today = (stats.usage && stats.usage.today) || {};
339
+ const total = (stats.usage && stats.usage.total) || {};
340
+
341
+ const dailyUsage = asNumber(subscription.daily_usage_usd);
342
+ const dailyLimit = asNumber(subscription.daily_limit_usd);
343
+ const weeklyUsage = asNumber(subscription.weekly_usage_usd);
344
+ const weeklyLimit = asNumber(subscription.weekly_limit_usd);
345
+ const monthlyUsage = asNumber(subscription.monthly_usage_usd);
346
+ const monthlyLimit = asNumber(subscription.monthly_limit_usd);
347
+
348
+ const unit = stats.unit || 'USD';
349
+ const planName = stats.planName || '-';
350
+ const mode = stats.mode || '-';
351
+ const isValid = stats.isValid === false ? '否' : '是';
352
+
353
+ console.log(`域名: ${origin}`);
354
+ console.log(`来源: ${source}`);
355
+ console.log(`套餐: ${planName} | 模式: ${mode} | 有效: ${isValid} | 单位: ${unit}`);
356
+ console.log('');
357
+
358
+ if (dailyUsage !== null || dailyLimit !== null) {
359
+ const usageText = formatCost(dailyUsage);
360
+ if (dailyLimit !== null && dailyLimit > 0) {
361
+ console.log(
362
+ `日额度: ${usageText} / ${formatCost(dailyLimit)} (${formatPercent(dailyUsage, dailyLimit)}) ` +
363
+ `${renderBar(dailyUsage, dailyLimit)} ${usageHint(dailyUsage, dailyLimit)}`.trimEnd()
364
+ );
365
+ const dailyRemaining = asNumber(stats.remaining);
366
+ if (dailyRemaining !== null) {
367
+ console.log(`日剩余: ${formatCost(dailyRemaining)}`);
368
+ } else if (dailyUsage !== null) {
369
+ console.log(`日剩余: ${formatCost(dailyLimit - dailyUsage)}`);
370
+ }
371
+ } else {
372
+ console.log(`日用量: ${usageText} (无限制)`);
373
+ }
374
+ }
375
+
376
+ if (weeklyUsage !== null && weeklyLimit !== null && weeklyLimit > 0) {
377
+ console.log(
378
+ `周额度: ${formatCost(weeklyUsage)} / ${formatCost(weeklyLimit)} (${formatPercent(weeklyUsage, weeklyLimit)}) ` +
379
+ `${renderBar(weeklyUsage, weeklyLimit)} ${usageHint(weeklyUsage, weeklyLimit)}`.trimEnd()
380
+ );
381
+ } else if (weeklyUsage !== null && weeklyUsage > 0) {
382
+ console.log(`周用量: ${formatCost(weeklyUsage)}`);
383
+ }
384
+
385
+ if (monthlyUsage !== null && monthlyLimit !== null && monthlyLimit > 0) {
386
+ console.log(
387
+ `月额度: ${formatCost(monthlyUsage)} / ${formatCost(monthlyLimit)} (${formatPercent(monthlyUsage, monthlyLimit)}) ` +
388
+ `${renderBar(monthlyUsage, monthlyLimit)} ${usageHint(monthlyUsage, monthlyLimit)}`.trimEnd()
389
+ );
390
+ } else if (monthlyUsage !== null && monthlyUsage > 0) {
391
+ console.log(`月用量: ${formatCost(monthlyUsage)}`);
392
+ }
393
+
394
+ const expiresAt = subscription.expires_at;
395
+ if (expiresAt) {
396
+ const expiresMs = Date.parse(expiresAt);
397
+ if (!Number.isNaN(expiresMs)) {
398
+ console.log(`套餐到期: ${formatDateTime(expiresMs)}`);
399
+ }
400
+ }
401
+
402
+ if (Object.keys(today).length > 0) {
403
+ console.log('');
404
+ console.log('今日:');
405
+ const todayParts = [];
406
+ if (asNumber(today.requests) !== null) todayParts.push(`请求 ${formatNumber(today.requests)} 次`);
407
+ if (asNumber(today.total_tokens) !== null) todayParts.push(`Token ${formatCompactNumber(today.total_tokens)}`);
408
+ if (asNumber(today.input_tokens) !== null) todayParts.push(`输入 ${formatCompactNumber(today.input_tokens)}`);
409
+ if (asNumber(today.output_tokens) !== null) todayParts.push(`输出 ${formatCompactNumber(today.output_tokens)}`);
410
+ if (asNumber(today.cache_read_tokens) !== null) todayParts.push(`缓存读 ${formatCompactNumber(today.cache_read_tokens)}`);
411
+ if (asNumber(today.cache_creation_tokens) !== null) todayParts.push(`缓存写 ${formatCompactNumber(today.cache_creation_tokens)}`);
412
+ if (todayParts.length) console.log(` ${todayParts.join(' | ')}`);
413
+ if (asNumber(today.cost) !== null) console.log(` 费用: ${formatCost(today.cost)}`);
414
+ }
415
+
416
+ if (Object.keys(total).length > 0 && total !== today) {
417
+ const totalRequests = asNumber(total.requests);
418
+ const totalCost = asNumber(total.cost);
419
+ if (totalRequests !== null || totalCost !== null) {
420
+ console.log('');
421
+ console.log('累计:');
422
+ const parts = [];
423
+ if (totalRequests !== null) parts.push(`请求 ${formatNumber(total.requests)} 次`);
424
+ if (asNumber(total.total_tokens) !== null) parts.push(`Token ${formatCompactNumber(total.total_tokens)}`);
425
+ if (totalCost !== null) parts.push(`费用 ${formatCost(total.cost)}`);
426
+ if (parts.length) console.log(` ${parts.join(' | ')}`);
427
+ }
428
+ }
429
+
430
+ const usage = stats.usage || {};
431
+ const rpm = asNumber(usage.rpm);
432
+ const tpm = asNumber(usage.tpm);
433
+ const avgDuration = asNumber(usage.average_duration_ms);
434
+ if (rpm !== null || tpm !== null || avgDuration !== null) {
435
+ const parts = [];
436
+ if (rpm !== null) parts.push(`RPM ${rpm}`);
437
+ if (tpm !== null) parts.push(`TPM ${tpm}`);
438
+ if (avgDuration !== null) parts.push(`平均耗时 ${avgDuration} ms`);
439
+ console.log(`实时: ${parts.join(' | ')}`);
440
+ }
441
+
442
+ if (Array.isArray(stats.model_stats) && stats.model_stats.length > 0) {
443
+ console.log('');
444
+ console.log('模型用量:');
445
+ for (const m of stats.model_stats) {
446
+ const parts = [
447
+ `${m.model || '-'}`,
448
+ `请求 ${formatNumber(m.requests)} 次`,
449
+ `Token ${formatCompactNumber(m.total_tokens)}`,
450
+ `费用 ${formatCost(m.cost)}`
451
+ ];
452
+ console.log(` - ${parts.join(' | ')}`);
453
+ }
454
+ }
455
+
456
+ console.log('');
457
+ }
458
+
358
459
  async function queryUsage(baseUrl, authToken) {
359
460
  try {
360
461
  const origin = new URL(baseUrl).origin;
@@ -494,7 +595,7 @@ function showUsageHelp() {
494
595
  console.log('用法: aihezu usage [service] [--json] [--key <apiKey>]');
495
596
  console.log('');
496
597
  console.log('说明:');
497
- console.log(' - 自动检测 Claude Code、Codex、Google Gemini 的配置');
598
+ console.log(' - 自动检测 Claude Code、Codex 的配置');
498
599
  console.log(' - 从环境变量和配置文件读取配置');
499
600
  console.log(' - 如果两者都存在且不同,将分别查询两个账号的用量');
500
601
  console.log(' - 使用 --key 可查询指定 API Key 的用量');
@@ -502,7 +603,6 @@ function showUsageHelp() {
502
603
  console.log('可选服务参数:');
503
604
  console.log(' cc, claude 只显示 Claude Code 用量');
504
605
  console.log(' codex 只显示 Codex 用量');
505
- console.log(' gemini 只显示 Google Gemini 用量');
506
606
  console.log(' (不指定) 显示所有已配置服务的用量');
507
607
  console.log('');
508
608
  console.log('可选参数:');
@@ -513,7 +613,6 @@ function showUsageHelp() {
513
613
  console.log(' npx aihezu usage # 显示所有服务');
514
614
  console.log(' npx aihezu usage cc # 只显示 Claude Code');
515
615
  console.log(' npx aihezu usage codex # 只显示 Codex');
516
- console.log(' npx aihezu usage gemini # 只显示 Gemini');
517
616
  console.log(' npx aihezu usage --json # JSON 格式输出所有服务');
518
617
  console.log(' npx aihezu usage cc --json # JSON 格式输出 Claude Code');
519
618
  console.log(' npx aihezu usage --key sk-xxx # 使用指定 Key 查询');
@@ -537,8 +636,7 @@ async function usageCommand(args = []) {
537
636
  const serviceAliases = {
538
637
  'cc': 'Claude Code',
539
638
  'claude': 'Claude Code',
540
- 'codex': 'Codex',
541
- 'gemini': 'Google Gemini'
639
+ 'codex': 'Codex'
542
640
  };
543
641
 
544
642
  let filterServiceName = null;
@@ -549,7 +647,7 @@ async function usageCommand(args = []) {
549
647
  if (!filterServiceName) {
550
648
  console.error(`[错误] 未知的服务: ${serviceFilter}`);
551
649
  console.error('');
552
- console.error('可用服务: cc, claude, codex, gemini');
650
+ console.error('可用服务: cc, claude, codex');
553
651
  console.error('');
554
652
  console.error('使用 "aihezu usage --help" 查看帮助');
555
653
  process.exit(1);
@@ -559,8 +657,7 @@ async function usageCommand(args = []) {
559
657
  // 收集所有服务的配置
560
658
  const allServices = [
561
659
  { name: 'Claude Code', configs: readClaudeConfig() },
562
- { name: 'Codex', configs: readCodexConfig() },
563
- { name: 'Google Gemini', configs: readGeminiConfig() }
660
+ { name: 'Codex', configs: readCodexConfig() }
564
661
  ];
565
662
 
566
663
  // 根据过滤参数筛选服务
@@ -591,10 +688,10 @@ async function usageCommand(args = []) {
591
688
  const effectiveKey = overrideKey || config.authToken;
592
689
  const sourceLabel = overrideKey ? `命令行 Key (${config.source})` : config.source;
593
690
  console.log(`[查询中] ${sourceLabel} - Token: ${maskToken(effectiveKey)}`);
594
- return {
595
- sourceLabel,
596
- promise: queryUsage(config.baseUrl, effectiveKey)
597
- };
691
+ const promise = service.name === 'Codex'
692
+ ? queryCodexUsage(config.baseUrl, effectiveKey)
693
+ : queryUsage(config.baseUrl, effectiveKey);
694
+ return { sourceLabel, promise };
598
695
  });
599
696
 
600
697
  const results = await Promise.allSettled(requests.map(item => item.promise));
@@ -615,7 +712,11 @@ async function usageCommand(args = []) {
615
712
  });
616
713
  } else {
617
714
  if (!outputJson) {
618
- displayUsageStats(result.stats, result.origin, sourceLabel);
715
+ if (service.name === 'Codex') {
716
+ displayCodexUsageStats(result.stats, result.origin, sourceLabel);
717
+ } else {
718
+ displayUsageStats(result.stats, result.origin, sourceLabel);
719
+ }
619
720
  }
620
721
  allResults[service.name].push({
621
722
  source: sourceLabel,
@@ -637,7 +738,6 @@ async function usageCommand(args = []) {
637
738
  console.log('请先运行以下命令进行配置:');
638
739
  console.log(' npx aihezu install claude # 配置 Claude Code');
639
740
  console.log(' npx aihezu install codex # 配置 Codex');
640
- console.log(' npx aihezu install gemini # 配置 Google Gemini');
641
741
  console.log('');
642
742
  console.log('或者手动设置环境变量:');
643
743
  console.log('');
@@ -243,7 +243,7 @@ function getTroubleshootingGuide(errorType)
243
243
 
244
244
  2. 永久设置(需要重启终端):
245
245
  setx ANTHROPIC_AUTH_TOKEN "sk-xxx"
246
- setx ANTHROPIC_BASE_URL "https://cn.aihezu.dev/api"
246
+ setx ANTHROPIC_BASE_URL "https://code.aihezu.top/api"
247
247
 
248
248
  3. 推荐:使用配置文件而非环境变量
249
249
  npx aihezu config claude
@@ -629,7 +629,7 @@ function getEnvVarGuide(varName) {
629
629
  '',
630
630
  '方式 2: 永久设置(需要重启终端)',
631
631
  ` setx ${varName} "your-value"`,
632
- ` setx ANTHROPIC_BASE_URL "https://cn.aihezu.dev/api"`,
632
+ ` setx ANTHROPIC_BASE_URL "https://code.aihezu.top/api"`,
633
633
  '',
634
634
  '⚠️ 注意: setx 后必须重启 PowerShell/CMD 才能生效',
635
635
  '',
package/lib/http.js CHANGED
@@ -8,11 +8,22 @@ function sleep(ms) {
8
8
  return new Promise(resolve => setTimeout(resolve, ms));
9
9
  }
10
10
 
11
- function sendJsonRequest(method, urlString, body, timeoutMs) {
11
+ function sendJsonRequest(method, urlString, body, timeoutMs, extraHeaders = {}) {
12
12
  const url = new URL(urlString);
13
- const payload = JSON.stringify(body ?? {});
13
+ const hasBody = body !== undefined && body !== null;
14
+ const payload = hasBody ? JSON.stringify(body) : '';
14
15
  const transport = url.protocol === 'https:' ? https : http;
15
16
 
17
+ const headers = {
18
+ 'Accept': 'application/json',
19
+ 'User-Agent': 'aihezu-cli',
20
+ ...extraHeaders
21
+ };
22
+ if (hasBody) {
23
+ headers['Content-Type'] = 'application/json';
24
+ headers['Content-Length'] = Buffer.byteLength(payload);
25
+ }
26
+
16
27
  return new Promise((resolve, reject) => {
17
28
  const req = transport.request(
18
29
  {
@@ -20,12 +31,7 @@ function sendJsonRequest(method, urlString, body, timeoutMs) {
20
31
  hostname: url.hostname,
21
32
  port: url.port || (url.protocol === 'https:' ? 443 : 80),
22
33
  path: `${url.pathname}${url.search || ''}`,
23
- headers: {
24
- 'Content-Type': 'application/json',
25
- 'Accept': 'application/json',
26
- 'Content-Length': Buffer.byteLength(payload),
27
- 'User-Agent': 'aihezu-cli'
28
- }
34
+ headers
29
35
  },
30
36
  res => {
31
37
  res.setEncoding('utf8');
@@ -57,7 +63,9 @@ function sendJsonRequest(method, urlString, body, timeoutMs) {
57
63
  req.destroy(new Error(`Request timed out after ${timeoutMs}ms`));
58
64
  });
59
65
 
60
- req.write(payload);
66
+ if (hasBody) {
67
+ req.write(payload);
68
+ }
61
69
  req.end();
62
70
  });
63
71
  }
@@ -67,7 +75,43 @@ async function postJson(urlString, body, options = {}) {
67
75
  timeoutMs = HTTP_TIMEOUT,
68
76
  retryCount = HTTP_RETRY_COUNT,
69
77
  retryDelayMs = HTTP_RETRY_DELAY,
70
- retryStatusCodes = DEFAULT_RETRY_STATUS_CODES
78
+ retryStatusCodes = DEFAULT_RETRY_STATUS_CODES,
79
+ headers = {}
80
+ } = options;
81
+
82
+ const retryCodes = retryStatusCodes instanceof Set ? retryStatusCodes : new Set(retryStatusCodes);
83
+ let attempt = 0;
84
+ let lastError = null;
85
+
86
+ while (attempt <= retryCount) {
87
+ try {
88
+ const response = await sendJsonRequest('POST', urlString, body, timeoutMs, headers);
89
+ if (retryCodes.has(response.statusCode) && attempt < retryCount) {
90
+ await sleep(retryDelayMs * Math.pow(2, attempt));
91
+ attempt += 1;
92
+ continue;
93
+ }
94
+ return response;
95
+ } catch (error) {
96
+ lastError = error;
97
+ if (attempt >= retryCount) {
98
+ break;
99
+ }
100
+ await sleep(retryDelayMs * Math.pow(2, attempt));
101
+ attempt += 1;
102
+ }
103
+ }
104
+
105
+ throw lastError || new Error('Request failed');
106
+ }
107
+
108
+ async function getJson(urlString, options = {}) {
109
+ const {
110
+ timeoutMs = HTTP_TIMEOUT,
111
+ retryCount = HTTP_RETRY_COUNT,
112
+ retryDelayMs = HTTP_RETRY_DELAY,
113
+ retryStatusCodes = DEFAULT_RETRY_STATUS_CODES,
114
+ headers = {}
71
115
  } = options;
72
116
 
73
117
  const retryCodes = retryStatusCodes instanceof Set ? retryStatusCodes : new Set(retryStatusCodes);
@@ -76,7 +120,7 @@ async function postJson(urlString, body, options = {}) {
76
120
 
77
121
  while (attempt <= retryCount) {
78
122
  try {
79
- const response = await sendJsonRequest('POST', urlString, body, timeoutMs);
123
+ const response = await sendJsonRequest('GET', urlString, null, timeoutMs, headers);
80
124
  if (retryCodes.has(response.statusCode) && attempt < retryCount) {
81
125
  await sleep(retryDelayMs * Math.pow(2, attempt));
82
126
  attempt += 1;
@@ -97,5 +141,6 @@ async function postJson(urlString, body, options = {}) {
97
141
  }
98
142
 
99
143
  module.exports = {
100
- postJson
144
+ postJson,
145
+ getJson
101
146
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aihezu",
3
- "version": "2.8.7",
3
+ "version": "2.8.9",
4
4
  "description": "AI 开发环境配置工具 - 支持 Claude Code, Codex, Google Gemini 的本地化配置、代理设置与缓存清理",
5
5
  "main": "bin/aihezu.js",
6
6
  "bin": {
@@ -10,7 +10,7 @@ const settingsPath = path.join(configDir, 'settings.json');
10
10
  module.exports = {
11
11
  name: 'claude',
12
12
  displayName: 'Claude Code',
13
- defaultApiUrl: 'https://cn.aihezu.dev/api',
13
+ defaultApiUrl: 'https://code.aihezu.top/api',
14
14
  apiSuffix: '/api',
15
15
 
16
16
  // Cache cleaning configuration