fogact 1.2.0 → 1.2.2

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.
@@ -8,15 +8,15 @@
8
8
  href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z'%3E%3C/path%3E%3C/svg%3E"
9
9
  />
10
10
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
11
- <title>CLIProxy - API 使用监控</title>
12
- <meta name="description" content="CLIProxy API 使用量监控平台" />
11
+ <title>FogAct - API 使用监控</title>
12
+ <meta name="description" content="FogAct API 使用量监控平台" />
13
13
  <link rel="preconnect" href="https://fonts.googleapis.com" />
14
14
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
15
15
  <link href="https://fonts.googleapis.com/css2?family=Manrope:wght@600;700;800&family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
16
16
  <script>
17
17
  // 阻塞式主题初始化 — 防止 FOUC + 设置内联背景色
18
18
  ;(function () {
19
- var t = localStorage.getItem('yunyi_user_theme') || 'system'
19
+ var t = localStorage.getItem('fogact_user_theme') || 'system'
20
20
  var d = t === 'dark' || (t === 'system' && matchMedia('(prefers-color-scheme: dark)').matches)
21
21
  var el = document.documentElement
22
22
  if (d) {
@@ -28,10 +28,10 @@
28
28
  }
29
29
  })()
30
30
  </script>
31
- <script type="module" crossorigin src="assets/index-Da98HOxL.js"></script>
31
+ <script type="module" crossorigin src="assets/index-Da98HOxL.js?v=20260619-fogact-loading-fix"></script>
32
32
  <link rel="modulepreload" crossorigin href="assets/chart-vendor-CULJE59K.js">
33
33
  <link rel="stylesheet" crossorigin href="assets/index-B8QSyYhS.css">
34
- <link rel="stylesheet" href="/assets/market-ui.css?v=20260619-user-restore" />
34
+ <link rel="stylesheet" href="/assets/market-ui.css?v=20260619-fogact-copy2" />
35
35
  </head>
36
36
  <body class="market-user min-h-screen">
37
37
  <span class="market-mouse-light" aria-hidden="true"></span>
@@ -6,7 +6,7 @@ const { testNodes, selectBestNode, formatNodeResults } = require("../services/no
6
6
  const { createBackup } = require("../services/backup-service");
7
7
  const { writeClaudeConfig, getClaudeConfigPath } = require("../config/claude");
8
8
  const { writeCodexConfig, getCodexConfigPath } = require("../config/codex");
9
- const { runActivationWizard, runNewApiActivation } = require("../services/activation-orchestrator");
9
+ const { runActivationWizard } = require("../services/activation-orchestrator");
10
10
 
11
11
  async function runLegacyCodeActivation(options = {}) {
12
12
  console.log("");
@@ -131,13 +131,6 @@ async function runActivateCommand(options = {}) {
131
131
  return;
132
132
  }
133
133
 
134
- if (options.service && options.apiKey && (options.yes || options.auto)) {
135
- console.log("");
136
- console.log("=== NewAPI Multi-Platform Activation ===");
137
- await runNewApiActivation(options);
138
- return;
139
- }
140
-
141
134
  await runActivationWizard(options);
142
135
  }
143
136
 
@@ -59,6 +59,7 @@ function writeClaudeConfig(apiKey, baseUrl) {
59
59
  ...existingEnv,
60
60
  ANTHROPIC_BASE_URL: baseUrl,
61
61
  ANTHROPIC_AUTH_TOKEN: apiKey,
62
+ FOGACT_ACTIVATION_CODE: apiKey,
62
63
  },
63
64
  });
64
65
 
@@ -148,7 +148,7 @@ function writeCodexConfig(apiKey, baseUrl) {
148
148
  delete auth[LEGACY_AUTH_KEY];
149
149
  fs.writeFileSync(
150
150
  authPath,
151
- JSON.stringify({ ...auth, auth_mode: "apikey", OPENAI_API_KEY: apiKey }, null, 2),
151
+ JSON.stringify({ ...auth, auth_mode: "apikey", OPENAI_API_KEY: apiKey, FOGACT_ACTIVATION_CODE: apiKey }, null, 2),
152
152
  "utf8"
153
153
  );
154
154
 
@@ -56,6 +56,9 @@ function loadUpstreamConfig(options = {}) {
56
56
  }
57
57
 
58
58
  function getServiceBaseUrl(config, service) {
59
+ if (config && config.proxy === true && config.baseUrl) {
60
+ return trimTrailingSlash(config.baseUrl);
61
+ }
59
62
  const serviceConfig = (config.services && config.services[service]) || {};
60
63
  return trimTrailingSlash(serviceConfig.baseUrl || config.baseUrl);
61
64
  }
package/lib/index.js CHANGED
@@ -170,6 +170,53 @@ function printBanner() {
170
170
  console.log(renderMenu(0));
171
171
  }
172
172
 
173
+ function moveMenuCursor(cursor, direction, total) {
174
+ return (cursor + direction + total) % total;
175
+ }
176
+
177
+ function applyMenuInput(input, cursor, total = MENU_CHOICES.length) {
178
+ const text = String(input || "");
179
+ const result = { cursor, action: null };
180
+ const tokenPattern = /\u001b(?:\[[0-9;]*[AB]|O[AB])|\r|\n|\u0003|\u001b|[1-9jksw]/gi;
181
+ let match;
182
+
183
+ while ((match = tokenPattern.exec(text)) !== null) {
184
+ const token = match[0];
185
+ const lower = token.toLowerCase();
186
+
187
+ if (token === "\u0003" || token === "\u001b") {
188
+ result.action = "exit";
189
+ break;
190
+ }
191
+
192
+ if (token === "\r" || token === "\n") {
193
+ result.action = "submit";
194
+ break;
195
+ }
196
+
197
+ if (/^\u001b(?:\[[0-9;]*A|OA)$/i.test(token) || lower === "k" || lower === "w") {
198
+ result.cursor = moveMenuCursor(result.cursor, -1, total);
199
+ continue;
200
+ }
201
+
202
+ if (/^\u001b(?:\[[0-9;]*B|OB)$/i.test(token) || lower === "j" || lower === "s") {
203
+ result.cursor = moveMenuCursor(result.cursor, 1, total);
204
+ continue;
205
+ }
206
+
207
+ if (/^[1-9]$/.test(token)) {
208
+ const selected = Number(token) - 1;
209
+ if (selected >= 0 && selected < total) {
210
+ result.cursor = selected;
211
+ result.action = "submit";
212
+ break;
213
+ }
214
+ }
215
+ }
216
+
217
+ return result;
218
+ }
219
+
173
220
  async function runInteractiveMenu() {
174
221
  await runToolsMenu();
175
222
  }
@@ -214,22 +261,21 @@ function selectMenuAction() {
214
261
  };
215
262
 
216
263
  const onData = (data) => {
217
- const key = data.toString("utf8");
218
- if (key === "\u0003" || key === "\u001b") {
264
+ const next = applyMenuInput(data.toString("utf8"), cursor, MENU_CHOICES.length);
265
+ const cursorChanged = next.cursor !== cursor;
266
+ cursor = next.cursor;
267
+
268
+ if (next.action === "exit") {
219
269
  cancel();
220
270
  return;
221
271
  }
222
- if (key === "\r" || key === "\n") {
272
+
273
+ if (next.action === "submit") {
223
274
  submit();
224
275
  return;
225
276
  }
226
- if (key === "\u001b[A") {
227
- cursor = cursor === 0 ? MENU_CHOICES.length - 1 : cursor - 1;
228
- render();
229
- return;
230
- }
231
- if (key === "\u001b[B") {
232
- cursor = cursor === MENU_CHOICES.length - 1 ? 0 : cursor + 1;
277
+
278
+ if (cursorChanged) {
233
279
  render();
234
280
  }
235
281
  };
@@ -292,15 +338,11 @@ function buildProgram() {
292
338
  .command("activate")
293
339
  .description("Open the multi-platform activation flow")
294
340
  .option("-s, --service <service>", "target service: claude or codex")
295
- .option("-k, --api-key <apiKey>", "NewAPI key; defaults to config/upstream.json or NEWAPI_API_KEY")
296
341
  .option("-y, --yes", "auto-confirm activation plan")
297
342
  .option("--auto", "alias for --yes")
298
343
  .option("--all", "configure optional platforms even when their config files do not exist")
299
344
  .option("--platforms <ids>", "comma-separated platform ids to activate")
300
- .option("--skip-verify", "skip upstream /v1/models key verification")
301
- .option("--upstream-config <path>", "path to upstream config JSON")
302
345
  .option("-c, --code <code>", "activation / redeem code")
303
- .option("--legacy", "use legacy activation-code node switching flow")
304
346
  .option("--no-redeem", "do not mark activation code as redeemed after writing config")
305
347
  .action(runActivateCommand);
306
348
 
@@ -308,13 +350,10 @@ function buildProgram() {
308
350
  .command("wizard")
309
351
  .description("Open FogAct activation wizard")
310
352
  .option("-s, --service <service>", "target service: claude or codex")
311
- .option("-k, --api-key <apiKey>", "NewAPI key")
312
353
  .option("-c, --code <code>", "activation / redeem code")
313
354
  .option("--platforms <ids>", "comma-separated platform ids to activate")
314
355
  .option("--all", "select all configurable platforms")
315
356
  .option("--yes", "auto-confirm activation plan")
316
- .option("--skip-verify", "skip upstream /v1/models key verification")
317
- .option("--upstream-config <path>", "path to upstream config JSON")
318
357
  .option("--no-redeem", "do not mark activation code as redeemed after writing config")
319
358
  .action(runActivationWizard);
320
359
 
@@ -362,6 +401,7 @@ async function runCli(argv = process.argv) {
362
401
  }
363
402
 
364
403
  module.exports = {
404
+ applyMenuInput,
365
405
  buildProgram,
366
406
  ensureLatestVersion,
367
407
  isNewerVersion,
@@ -21,7 +21,7 @@ function buildClaudeConfig(existingConfig, baseUrl, apiKey) {
21
21
  name: "fogact-claude",
22
22
  npm: "@ai-sdk/anthropic",
23
23
  options: {
24
- baseURL: `${baseUrl.replace(/\/+$/, "")}/v1`,
24
+ baseURL: baseUrl.replace(/\/+$/, ""),
25
25
  apiKey,
26
26
  },
27
27
  };
@@ -2,10 +2,9 @@
2
2
 
3
3
  const prompts = require("prompts");
4
4
  const { detectPlatforms, getPlatforms } = require("../platforms");
5
- const { loadUpstreamConfig } = require("../config/upstream");
6
5
  const { createActivationBackup } = require("./backup-service");
7
- const { getNodes, inspectActivationCode, redeemActivationCode, testNode } = require("./fogact-api");
8
- const { maskKey, verifyNewApiKey } = require("./newapi");
6
+ const { getNodes, inspectActivationCode, testNode, verifyActivationCode } = require("./fogact-api");
7
+ const { maskKey } = require("./newapi");
9
8
 
10
9
  const SUPPORTED_SERVICES = ["codex", "claude"];
11
10
  const SERVICE_LABELS = {
@@ -149,6 +148,9 @@ function normalizeEntitlement(raw = {}, fallbackServices = []) {
149
148
  function extractApiKeyFromEntitlement(entitlement, fallback) {
150
149
  const raw = entitlement && entitlement.raw ? entitlement.raw : {};
151
150
  const credential = raw.credential || raw.credentials || {};
151
+ if (raw.proxy === true) {
152
+ return String(raw.apiKey || raw.key || raw.token || fallback || "").trim();
153
+ }
152
154
  return String(
153
155
  raw.apiKey ||
154
156
  raw.key ||
@@ -176,6 +178,16 @@ function extractBaseUrlFromEntitlement(entitlement) {
176
178
  ).trim().replace(/\/+$/, "");
177
179
  }
178
180
 
181
+ function extractProxyBaseUrlFromEntitlement(entitlement) {
182
+ const raw = entitlement && entitlement.raw ? entitlement.raw : {};
183
+ const service = raw.serviceKey || (entitlement.services && entitlement.services[0]);
184
+ return String(
185
+ raw.baseUrl ||
186
+ (raw.publicBaseUrl && service === "codex" ? `${String(raw.publicBaseUrl).replace(/\/+$/, "")}/v1` : raw.publicBaseUrl) ||
187
+ ""
188
+ ).trim().replace(/\/+$/, "");
189
+ }
190
+
179
191
  function isServiceAllowed(entitlement, service) {
180
192
  return !entitlement.services.length || entitlement.services.includes(service);
181
193
  }
@@ -249,36 +261,6 @@ async function promptService(defaultService, entitlement = normalizeEntitlement(
249
261
  return response.service || null;
250
262
  }
251
263
 
252
- async function promptApiKey(defaultApiKey) {
253
- if (defaultApiKey) {
254
- return defaultApiKey;
255
- }
256
-
257
- const response = await prompts({
258
- type: "password",
259
- name: "apiKey",
260
- message: "请输入 NewAPI API Key",
261
- validate: (value) => value && value.trim() ? true : "API Key 不能为空",
262
- }, { onCancel: () => false });
263
-
264
- return response.apiKey ? response.apiKey.trim() : null;
265
- }
266
-
267
- async function promptBaseUrl(defaultBaseUrl) {
268
- if (defaultBaseUrl) {
269
- return defaultBaseUrl;
270
- }
271
-
272
- const response = await prompts({
273
- type: "text",
274
- name: "baseUrl",
275
- message: "请输入 NewAPI Base URL",
276
- validate: (value) => value && value.trim() ? true : "Base URL 不能为空",
277
- }, { onCancel: () => false });
278
-
279
- return response.baseUrl ? response.baseUrl.trim().replace(/\/+$/, "") : null;
280
- }
281
-
282
264
  async function promptActivationCode(defaultCode) {
283
265
  if (defaultCode) {
284
266
  return defaultCode;
@@ -287,36 +269,13 @@ async function promptActivationCode(defaultCode) {
287
269
  const response = await prompts({
288
270
  type: "password",
289
271
  name: "code",
290
- message: "请输入 API Key / 激活码:",
291
- validate: (value) => value && value.trim() ? true : "API Key / 激活码不能为空",
272
+ message: "请输入激活码:",
273
+ validate: (value) => value && value.trim() ? true : "激活码不能为空",
292
274
  }, { onCancel: () => false });
293
275
 
294
276
  return response.code ? response.code.trim() : null;
295
277
  }
296
278
 
297
- async function promptCredentialType(options, upstream) {
298
- if (options.code) {
299
- return "code";
300
- }
301
- if (options.apiKey || upstream.apiKey) {
302
- return "api-key";
303
- }
304
-
305
- const response = await prompts({
306
- type: "select",
307
- name: "credentialType",
308
- message: "请选择激活方式",
309
- hint: "↑↓ 选择,回车确认",
310
- choices: [
311
- { title: "输入激活码 / 兑换码", value: "code" },
312
- { title: "输入 NewAPI API Key", value: "api-key" },
313
- ],
314
- initial: 0,
315
- }, { onCancel: () => false });
316
-
317
- return response.credentialType || null;
318
- }
319
-
320
279
  async function confirmActivation(yes, service) {
321
280
  if (yes) {
322
281
  return true;
@@ -368,7 +327,7 @@ function printCredentialProfile(service, upstream, apiKey, entitlement) {
368
327
  console.log(divider());
369
328
  console.log(` 服务类型: ${getServiceLabel(service)}`);
370
329
  console.log(` 接入地址: ${upstream.baseUrl}`);
371
- console.log(` API Key: ${maskKey(apiKey)}`);
330
+ console.log(` 激活码: ${maskKey(apiKey)}`);
372
331
  if (entitlement.planName) {
373
332
  console.log(` 套餐名称: ${entitlement.planName}`);
374
333
  }
@@ -454,9 +413,6 @@ function printResultSummary(service, backupPath, results, redeemResult) {
454
413
  if (failed.length) {
455
414
  console.log(` 激活完成:${succeeded.length} 成功,${failed.length} 失败,${skipped.length} 跳过`);
456
415
  }
457
- if (redeemResult) {
458
- console.log(` 兑换记录: ${redeemResult.valid ? "已完成" : `未完成(${redeemResult.error || "接口不可用"})`}`);
459
- }
460
416
  if (service === "claude") {
461
417
  const tools = ["Claude Code"];
462
418
  if (byId.get("opencode")?.result.success) tools.push("OpenCode");
@@ -516,28 +472,20 @@ async function resolveCodeCredential(options, upstream) {
516
472
 
517
473
  const entitlement = normalizeEntitlement(inspection, options.service ? [options.service] : []);
518
474
  const apiKey = extractApiKeyFromEntitlement(entitlement, code);
519
- const entitlementBaseUrl = extractBaseUrlFromEntitlement(entitlement);
475
+ const entitlementBaseUrl = extractProxyBaseUrlFromEntitlement(entitlement);
476
+ if (!apiKey || !entitlementBaseUrl || entitlement.raw.proxy !== true) {
477
+ console.log("✗ 激活接口没有返回 FogAct 中转配置,请联系管理员检查服务端代理设置。");
478
+ return { cancelled: true };
479
+ }
520
480
  return {
521
481
  activationCode: code,
522
482
  apiKey,
523
483
  entitlement,
524
- upstream: entitlementBaseUrl ? { ...upstream, baseUrl: entitlementBaseUrl } : upstream,
484
+ upstream: { services: {}, baseUrl: entitlementBaseUrl, proxy: true },
525
485
  inspection,
526
486
  };
527
487
  }
528
488
 
529
- async function resolveApiKeyCredential(options, upstream) {
530
- const apiKey = await promptApiKey(options.apiKey || upstream.apiKey);
531
- if (!apiKey) {
532
- return { cancelled: true };
533
- }
534
- return {
535
- apiKey,
536
- entitlement: normalizeEntitlement({}, options.service ? [options.service] : []),
537
- upstream,
538
- };
539
- }
540
-
541
489
  async function activateTargets({ service, upstream, apiKey, targets, activationCode, options = {} }) {
542
490
  const backupPath = createActivationBackup(service, getBackupPaths(targets), {
543
491
  upstream: upstream.baseUrl,
@@ -558,85 +506,15 @@ async function activateTargets({ service, upstream, apiKey, targets, activationC
558
506
  }
559
507
  }
560
508
 
561
- let redeemResult = null;
509
+ let activationRecord = null;
562
510
  const failures = results.filter(({ result }) => !result.success && !result.skipped);
563
- if (activationCode && failures.length === 0 && !options.noRedeem) {
564
- redeemResult = await redeemActivationCode(activationCode, service);
511
+ if (activationCode && failures.length === 0) {
512
+ activationRecord = await verifyActivationCode(activationCode, service);
565
513
  }
566
514
 
567
- return { backupPath, results, redeemResult };
515
+ return { backupPath, results, redeemResult: null, activationRecord };
568
516
  }
569
517
 
570
- async function verifyCredential(upstream, apiKey, options = {}) {
571
- if (options.skipVerify) {
572
- console.log("跳过 NewAPI 连通性验证。");
573
- return { valid: true, skipped: true };
574
- }
575
-
576
- console.log("正在验证 NewAPI Key...");
577
- const verification = await verifyNewApiKey(upstream, apiKey);
578
- if (!verification.valid) {
579
- console.log(`✗ NewAPI 验证失败: ${verification.error}`);
580
- return verification;
581
- }
582
- console.log(`✓ NewAPI 验证通过(可见 ${verification.models.length} 个模型)`);
583
- return verification;
584
- }
585
-
586
- async function runNewApiActivation(options = {}) {
587
- const baseUpstream = loadUpstreamConfig({ configPath: options.upstreamConfig });
588
- const upstream = { ...baseUpstream };
589
- upstream.baseUrl = await promptBaseUrl(upstream.baseUrl);
590
- if (!upstream.baseUrl) {
591
- console.log("Activation cancelled.");
592
- return { success: false, cancelled: true };
593
- }
594
-
595
- const apiKey = await promptApiKey(options.apiKey || upstream.apiKey);
596
- if (!apiKey) {
597
- console.log("Activation cancelled.");
598
- return { success: false, cancelled: true };
599
- }
600
-
601
- const entitlement = normalizeEntitlement({}, options.service ? [options.service] : []);
602
- const service = await promptService(options.service, entitlement);
603
- if (!service) {
604
- console.log("Activation cancelled.");
605
- return { success: false, cancelled: true };
606
- }
607
-
608
- console.log("");
609
- const verification = await verifyCredential(upstream, apiKey, options);
610
- if (!verification.valid) {
611
- return { success: false, verification };
612
- }
613
-
614
- const detectedPlatforms = detectPlatforms(service);
615
- const selectedPlatformIds = options.platforms ? parsePlatformIds(options.platforms) : null;
616
- const targets = getActivationTargets(detectedPlatforms, Boolean(options.all), selectedPlatformIds);
617
-
618
- printCredentialProfile(service, upstream, apiKey, entitlement);
619
-
620
- if (!(await confirmActivation(Boolean(options.yes || options.auto), service))) {
621
- console.log("");
622
- console.log(" 已取消");
623
- console.log("");
624
- return { success: false, cancelled: true };
625
- }
626
-
627
- console.log("");
628
- console.log(" 正在写入配置...");
629
- const activation = await activateTargets({ service, upstream, apiKey, targets, options });
630
- const failures = activation.results.filter(({ result }) => !result.success && !result.skipped);
631
- console.log(" 配置完成");
632
- printResultSummary(service, activation.backupPath, activation.results, activation.redeemResult);
633
-
634
- return {
635
- success: failures.length === 0,
636
- backupPath: activation.backupPath,
637
- results: activation.results,
638
- };
639
- }
640
518
 
641
519
  async function runActivationWizard(options = {}) {
642
520
  if (!options.noNodeCheck) {
@@ -646,37 +524,24 @@ async function runActivationWizard(options = {}) {
646
524
  }
647
525
  }
648
526
 
649
- const baseUpstream = loadUpstreamConfig({ configPath: options.upstreamConfig });
650
- const credentialType = !options.code && options.apiKey ? "api-key" : "code";
651
-
652
- const credential = credentialType === "code"
653
- ? await resolveCodeCredential(options, baseUpstream)
654
- : await resolveApiKeyCredential(options, baseUpstream);
527
+ const credential = await resolveCodeCredential(options, {});
655
528
  if (credential.cancelled) {
656
529
  console.log("已取消。");
657
530
  return { success: false, cancelled: true };
658
531
  }
659
532
 
660
533
  const upstream = { ...credential.upstream };
661
- upstream.baseUrl = await promptBaseUrl(upstream.baseUrl);
662
534
  if (!upstream.baseUrl) {
663
535
  console.log("已取消。");
664
536
  return { success: false, cancelled: true };
665
537
  }
666
538
 
667
- const service = await promptService(options.service, credential.entitlement, { allowPrompt: credentialType === "api-key" });
539
+ const service = await promptService(options.service, credential.entitlement, { allowPrompt: false });
668
540
  if (!service) {
669
541
  console.log("已取消。");
670
542
  return { success: false, cancelled: true };
671
543
  }
672
544
 
673
- console.log("");
674
- if (credentialType === "api-key") {
675
- const verification = await verifyCredential(upstream, credential.apiKey, options);
676
- if (!verification.valid) {
677
- return { success: false, verification };
678
- }
679
- }
680
545
 
681
546
  const allDetectedPlatforms = detectPlatforms(service);
682
547
  const allowedPlatforms = allDetectedPlatforms.filter((entry) => isPlatformAllowed(entry, credential.entitlement, service));
@@ -727,5 +592,4 @@ module.exports = {
727
592
  normalizeServices,
728
593
  parsePlatformIds,
729
594
  runActivationWizard,
730
- runNewApiActivation,
731
595
  };
@@ -6,7 +6,7 @@ const http = require("http");
6
6
 
7
7
  // 支持环境变量覆盖 API 地址;默认连接公网 FogAct 面板。
8
8
  const DEFAULT_API_BASE = "https://cliproxy.fogidc.com";
9
- const API_BASE = process.env.FOGACT_API_BASE || process.env.CLIPROXY_API_BASE || DEFAULT_API_BASE;
9
+ const API_BASE = process.env.FOGACT_API_BASE || DEFAULT_API_BASE;
10
10
 
11
11
  function makeRequest(path, options = {}) {
12
12
  return new Promise((resolve, reject) => {
@@ -57,7 +57,6 @@ function makeRequest(path, options = {}) {
57
57
 
58
58
  async function verifyActivationCode(code, service) {
59
59
  try {
60
- // 调用本地激活 API
61
60
  const response = await makeRequest("/api/activate", {
62
61
  method: "POST",
63
62
  body: {
@@ -67,17 +66,18 @@ async function verifyActivationCode(code, service) {
67
66
  },
68
67
  });
69
68
 
70
- if (response.status === 200 && response.data.success) {
69
+ const normalized = normalizeActivationResponse(response);
70
+
71
+ if (response.status >= 200 && response.status < 300 && normalized.valid) {
71
72
  return {
72
73
  valid: true,
73
- service: response.data.data.service,
74
- expiresAt: response.data.data.expiresAt,
75
- quota: response.data.data.quota,
76
- nodes: response.data.data.nodes || [],
74
+ ...normalized.data,
75
+ data: normalized.data,
76
+ nodes: normalized.data.nodes || [],
77
77
  };
78
78
  }
79
79
 
80
- return { valid: false, error: response.data.message || "Invalid code" };
80
+ return { valid: false, error: normalized.message || "Invalid code" };
81
81
  } catch (err) {
82
82
  return { valid: false, error: err.message };
83
83
  }
@@ -116,7 +116,10 @@ async function inspectActivationCode(code) {
116
116
  }
117
117
 
118
118
  async function redeemActivationCode(code, service) {
119
- return verifyActivationCode(code, service);
119
+ const result = await inspectActivationCode(code);
120
+ return result.valid
121
+ ? { valid: true, service: result.service, expiresAt: result.expiresAt, quota: result.quota, nodes: result.nodes || [] }
122
+ : result;
120
123
  }
121
124
 
122
125
  async function getNodes(service) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fogact",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "FogAct activation helper for Claude Code and Codex",
5
5
  "keywords": [
6
6
  "fogact",