fogact 1.2.0 → 1.2.3

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 (51) hide show
  1. package/bin/web-server.js +829 -230
  2. package/frontend/admin/admin-panel-v2.js +8 -5
  3. package/frontend/user/assets/AnnouncementDetail-Dvxmwz0A-fogact-live.js +12 -0
  4. package/frontend/user/assets/Announcements-CS1tF2mx-fogact-live.js +11 -0
  5. package/frontend/user/assets/CardBind-CsCxihhP-fogact-live.js +21 -0
  6. package/frontend/user/assets/CardContent.vue_vue_type_script_setup_true_lang-D2L-uqSl-fogact-live.js +1 -0
  7. package/frontend/user/assets/CardDescription.vue_vue_type_script_setup_true_lang-D-v5Pl7F-fogact-live.js +1 -0
  8. package/frontend/user/assets/CardTitle.vue_vue_type_script_setup_true_lang-a0CCN6D5-fogact-live.js +1 -0
  9. package/frontend/user/assets/Dashboard-rPsmltm5-fogact-live.js +51 -0
  10. package/frontend/user/assets/Dashboard-rPsmltm5.js +1 -1
  11. package/frontend/user/assets/DashboardLayout-DDkxHYFj-fogact-live.js +80 -0
  12. package/frontend/user/assets/DashboardLayout-DDkxHYFj.js +2 -2
  13. package/frontend/user/assets/Input.vue_vue_type_script_setup_true_lang-B0SyPmYb-fogact-live.js +6 -0
  14. package/frontend/user/assets/Label.vue_vue_type_script_setup_true_lang-CxYORSgN-fogact-live.js +1 -0
  15. package/frontend/user/assets/Progress.vue_vue_type_script_setup_true_lang-2_QbPsEQ-fogact-live.js +1 -0
  16. package/frontend/user/assets/QuotaPack-B_tJ7Psm-fogact-live.js +6 -0
  17. package/frontend/user/assets/Renewal-BSDhDmwv-fogact-live.js +6 -0
  18. package/frontend/user/assets/ScrollArea.vue_vue_type_script_setup_true_lang-DMYwcfpz-fogact-live.js +1 -0
  19. package/frontend/user/assets/Separator.vue_vue_type_script_setup_true_lang-Ckg8EXj_-fogact-live.js +1 -0
  20. package/frontend/user/assets/Settings-CBdAa3lw-fogact-live.js +11 -0
  21. package/frontend/user/assets/TooltipTrigger.vue_vue_type_script_setup_true_lang-DtSBjzGo-fogact-live.js +16 -0
  22. package/frontend/user/assets/Welcome-Dtfp6oER-fogact-live.js +1 -0
  23. package/frontend/user/assets/Welcome-Dtfp6oER.js +1 -1
  24. package/frontend/user/assets/_plugin-vue_export-helper-5cjT4u0R-fogact-live.js +16 -0
  25. package/frontend/user/assets/activity-wYWtyqTJ-fogact-live.js +6 -0
  26. package/frontend/user/assets/announcement-35mOnjRL-fogact-live.js +16 -0
  27. package/frontend/user/assets/announcement-35mOnjRL.js +1 -1
  28. package/frontend/user/assets/calendar-BFNuCata-fogact-live.js +6 -0
  29. package/frontend/user/assets/chevron-down-kDbuU1Py-fogact-live.js +6 -0
  30. package/frontend/user/assets/chevron-right-BayASIm0-fogact-live.js +6 -0
  31. package/frontend/user/assets/eye-CY62vip0-fogact-live.js +6 -0
  32. package/frontend/user/assets/gauge-C5NQ-mV8-fogact-live.js +6 -0
  33. package/frontend/user/assets/index-Da98HOxL.js +3 -3
  34. package/frontend/user/assets/index-fogact-live.js +91 -0
  35. package/frontend/user/assets/link-2-DT5R5nGO-fogact-live.js +6 -0
  36. package/frontend/user/assets/package-rUbExUEn-fogact-live.js +6 -0
  37. package/frontend/user/assets/plus-CQc6C8wG-fogact-live.js +11 -0
  38. package/frontend/user/assets/refresh-cw-Y9hCloPL-fogact-live.js +6 -0
  39. package/frontend/user/assets/useUserPageRefresh-BYZvpNR9-fogact-live.js +1 -0
  40. package/frontend/user/assets/zap-l5zbZqrM-fogact-live.js +11 -0
  41. package/frontend/user/index.html +5 -5
  42. package/lib/commands/activate.js +1 -8
  43. package/lib/config/claude.js +1 -0
  44. package/lib/config/codex.js +1 -1
  45. package/lib/config/upstream.js +3 -0
  46. package/lib/index.js +109 -29
  47. package/lib/platforms/opencode.js +1 -1
  48. package/lib/services/activation-orchestrator.js +30 -166
  49. package/lib/services/database.js +47 -0
  50. package/lib/services/fogact-api.js +12 -9
  51. package/package.json +1 -1
@@ -0,0 +1,6 @@
1
+ import{c as e}from"./index-fogact-live.js";/**
2
+ * @license lucide-vue-next v0.468.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const n=e("Link2Icon",[["path",{d:"M9 17H7A5 5 0 0 1 7 7h2",key:"8i5ue5"}],["path",{d:"M15 7h2a5 5 0 1 1 0 10h-2",key:"1b9ql8"}],["line",{x1:"8",x2:"16",y1:"12",y2:"12",key:"1jonct"}]]);export{n as L};
@@ -0,0 +1,6 @@
1
+ import{c as a}from"./index-fogact-live.js";/**
2
+ * @license lucide-vue-next v0.468.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const c=a("PackageIcon",[["path",{d:"M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z",key:"1a0edw"}],["path",{d:"M12 22V12",key:"d0xqtd"}],["path",{d:"m3.3 7 7.703 4.734a2 2 0 0 0 1.994 0L20.7 7",key:"yx3hmr"}],["path",{d:"m7.5 4.27 9 5.15",key:"1c824w"}]]);export{c as P};
@@ -0,0 +1,11 @@
1
+ import{c as a}from"./index-fogact-live.js";/**
2
+ * @license lucide-vue-next v0.468.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const s=a("LayersIcon",[["path",{d:"M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z",key:"zw3jo"}],["path",{d:"M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12",key:"1wduqc"}],["path",{d:"M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17",key:"kqbvx6"}]]);/**
7
+ * @license lucide-vue-next v0.468.0 - ISC
8
+ *
9
+ * This source code is licensed under the ISC license.
10
+ * See the LICENSE file in the root directory of this source tree.
11
+ */const t=a("PlusIcon",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);export{s as L,t as P};
@@ -0,0 +1,6 @@
1
+ import{c as e}from"./index-fogact-live.js";/**
2
+ * @license lucide-vue-next v0.468.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const t=e("RefreshCwIcon",[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]]);export{t as R};
@@ -0,0 +1 @@
1
+ import{u as c}from"./index-fogact-live.js";import{w as i,L as d,f as h}from"./chart-vendor-CULJE59K.js";const o=Symbol("user-page-refresh");function v(l,e={}){const n=c(),f=h(o,null);let t=0;async function a(r="custom"){var u;const s=++t;(u=e.resetBeforeLoad)==null||u.call(e,r),await l({reason:r,runId:s,isLatest:()=>s===t})}return e.reloadOnKeyChange!==!1&&i(()=>n.activeKeyId,(r,s)=>{r!==s&&a("active-key-change")}),e.reloadOnManualRefresh!==!1&&f&&i(()=>f.refreshTick.value,()=>{a("manual-refresh")}),e.immediate!==!1&&d(()=>{a("initial")}),{reload:a}}export{v as a,o as u};
@@ -0,0 +1,11 @@
1
+ import{c as a}from"./index-fogact-live.js";/**
2
+ * @license lucide-vue-next v0.468.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const e=a("ShieldIcon",[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}]]);/**
7
+ * @license lucide-vue-next v0.468.0 - ISC
8
+ *
9
+ * This source code is licensed under the ISC license.
10
+ * See the LICENSE file in the root directory of this source tree.
11
+ */const o=a("ZapIcon",[["path",{d:"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z",key:"1xq2db"}]]);export{e as S,o as Z};
@@ -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-fogact-live.js"></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,75 @@ function printBanner() {
170
170
  console.log(renderMenu(0));
171
171
  }
172
172
 
173
+ function shouldUseFixedMenuScreen(env = process.env, stdout = process.stdout) {
174
+ if (!stdout.isTTY) return false;
175
+ if (env.FOGACT_NO_FIXED_MENU === "1" || env.FOGACT_PLAIN_MENU === "1") return false;
176
+ return String(env.TERM || "").toLowerCase() !== "dumb";
177
+ }
178
+
179
+ function enterFixedMenuScreen(stdout = process.stdout) {
180
+ stdout.write("\x1b[?1049h\x1b[?25l\x1b[?7l");
181
+ }
182
+
183
+ function leaveFixedMenuScreen(stdout = process.stdout) {
184
+ stdout.write("\x1b[?7h\x1b[?25h\x1b[?1049l");
185
+ }
186
+
187
+ function saveMenuCursor(stdout = process.stdout) {
188
+ stdout.write("\x1b7\x1b[s\x1b[?25l");
189
+ }
190
+
191
+ function restoreMenuCursor(stdout = process.stdout) {
192
+ stdout.write("\x1b8\x1b[u\x1b[J");
193
+ }
194
+
195
+ function moveMenuCursor(cursor, direction, total) {
196
+ return (cursor + direction + total) % total;
197
+ }
198
+
199
+ function applyMenuInput(input, cursor, total = MENU_CHOICES.length) {
200
+ const text = String(input || "");
201
+ const result = { cursor, action: null };
202
+ const tokenPattern = /\u001b(?:\[[0-9;]*[AB]|O[AB])|\r|\n|\u0003|\u001b|[1-9jksw]/gi;
203
+ let match;
204
+
205
+ while ((match = tokenPattern.exec(text)) !== null) {
206
+ const token = match[0];
207
+ const lower = token.toLowerCase();
208
+
209
+ if (token === "\u0003" || token === "\u001b") {
210
+ result.action = "exit";
211
+ break;
212
+ }
213
+
214
+ if (token === "\r" || token === "\n") {
215
+ result.action = "submit";
216
+ break;
217
+ }
218
+
219
+ if (/^\u001b(?:\[[0-9;]*A|OA)$/i.test(token) || lower === "k" || lower === "w") {
220
+ result.cursor = moveMenuCursor(result.cursor, -1, total);
221
+ continue;
222
+ }
223
+
224
+ if (/^\u001b(?:\[[0-9;]*B|OB)$/i.test(token) || lower === "j" || lower === "s") {
225
+ result.cursor = moveMenuCursor(result.cursor, 1, total);
226
+ continue;
227
+ }
228
+
229
+ if (/^[1-9]$/.test(token)) {
230
+ const selected = Number(token) - 1;
231
+ if (selected >= 0 && selected < total) {
232
+ result.cursor = selected;
233
+ result.action = "submit";
234
+ break;
235
+ }
236
+ }
237
+ }
238
+
239
+ return result;
240
+ }
241
+
173
242
  async function runInteractiveMenu() {
174
243
  await runToolsMenu();
175
244
  }
@@ -182,24 +251,33 @@ function selectMenuAction() {
182
251
 
183
252
  return new Promise((resolve) => {
184
253
  let cursor = 0;
185
- let renderedLines = 0;
254
+ let closed = false;
186
255
  const stdin = process.stdin;
256
+ const stdout = process.stdout;
257
+ const useFixedScreen = shouldUseFixedMenuScreen(process.env, stdout);
258
+ const wasRaw = Boolean(stdin.isRaw);
187
259
 
188
260
  const render = () => {
189
- if (renderedLines > 0) {
190
- process.stdout.write(`\x1b[${renderedLines}A`);
191
- process.stdout.write("\x1b[J");
261
+ if (useFixedScreen) {
262
+ stdout.write("\x1b[H\x1b[2J");
263
+ } else {
264
+ restoreMenuCursor(stdout);
192
265
  }
193
- const output = renderMenu(cursor);
194
- renderedLines = output.split("\n").length;
195
- process.stdout.write(output);
266
+ stdout.write(renderMenu(cursor));
196
267
  };
197
268
 
198
269
  const cleanup = () => {
270
+ if (closed) return;
271
+ closed = true;
199
272
  stdin.off("data", onData);
200
- if (stdin.isRaw) stdin.setRawMode(false);
273
+ if (stdin.isTTY && stdin.isRaw !== wasRaw) stdin.setRawMode(wasRaw);
201
274
  stdin.pause();
202
- process.stdout.write("\x1b[?25h\n");
275
+ if (useFixedScreen) {
276
+ leaveFixedMenuScreen(stdout);
277
+ } else {
278
+ restoreMenuCursor(stdout);
279
+ stdout.write("\x1b[?25h");
280
+ }
203
281
  };
204
282
 
205
283
  const submit = () => {
@@ -214,31 +292,35 @@ function selectMenuAction() {
214
292
  };
215
293
 
216
294
  const onData = (data) => {
217
- const key = data.toString("utf8");
218
- if (key === "\u0003" || key === "\u001b") {
295
+ const next = applyMenuInput(String(data), cursor, MENU_CHOICES.length);
296
+ const cursorChanged = next.cursor !== cursor;
297
+ cursor = next.cursor;
298
+
299
+ if (next.action === "exit") {
219
300
  cancel();
220
301
  return;
221
302
  }
222
- if (key === "\r" || key === "\n") {
303
+
304
+ if (next.action === "submit") {
223
305
  submit();
224
306
  return;
225
307
  }
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;
308
+
309
+ if (cursorChanged) {
233
310
  render();
234
311
  }
235
312
  };
236
313
 
237
- process.stdout.write("\x1b[?25l");
238
- render();
239
- stdin.resume();
240
314
  stdin.setEncoding("utf8");
241
315
  stdin.setRawMode(true);
316
+ stdin.resume();
317
+
318
+ if (useFixedScreen) {
319
+ enterFixedMenuScreen(stdout);
320
+ } else {
321
+ saveMenuCursor(stdout);
322
+ }
323
+ render();
242
324
  stdin.on("data", onData);
243
325
  });
244
326
  }
@@ -292,15 +374,11 @@ function buildProgram() {
292
374
  .command("activate")
293
375
  .description("Open the multi-platform activation flow")
294
376
  .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
377
  .option("-y, --yes", "auto-confirm activation plan")
297
378
  .option("--auto", "alias for --yes")
298
379
  .option("--all", "configure optional platforms even when their config files do not exist")
299
380
  .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
381
  .option("-c, --code <code>", "activation / redeem code")
303
- .option("--legacy", "use legacy activation-code node switching flow")
304
382
  .option("--no-redeem", "do not mark activation code as redeemed after writing config")
305
383
  .action(runActivateCommand);
306
384
 
@@ -308,13 +386,10 @@ function buildProgram() {
308
386
  .command("wizard")
309
387
  .description("Open FogAct activation wizard")
310
388
  .option("-s, --service <service>", "target service: claude or codex")
311
- .option("-k, --api-key <apiKey>", "NewAPI key")
312
389
  .option("-c, --code <code>", "activation / redeem code")
313
390
  .option("--platforms <ids>", "comma-separated platform ids to activate")
314
391
  .option("--all", "select all configurable platforms")
315
392
  .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
393
  .option("--no-redeem", "do not mark activation code as redeemed after writing config")
319
394
  .action(runActivationWizard);
320
395
 
@@ -362,7 +437,12 @@ async function runCli(argv = process.argv) {
362
437
  }
363
438
 
364
439
  module.exports = {
440
+ applyMenuInput,
365
441
  buildProgram,
442
+ enterFixedMenuScreen,
443
+ leaveFixedMenuScreen,
444
+ renderMenu,
445
+ shouldUseFixedMenuScreen,
366
446
  ensureLatestVersion,
367
447
  isNewerVersion,
368
448
  runCli,
@@ -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
  };