fogact 1.1.10 → 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=20260616-upstream2" />
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
 
@@ -3,98 +3,101 @@
3
3
  const prompts = require("prompts");
4
4
  const { listBackups, restoreBackup, clearBackups } = require("../services/backup-service");
5
5
 
6
+ function formatBackupTitle(backup) {
7
+ const service = backup.service === "codex" ? "Codex" : backup.service === "claude" ? "Claude Code" : backup.service;
8
+ const time = backup.timestamp ? new Date(backup.timestamp).toLocaleString("zh-CN") : "未知时间";
9
+ const count = Array.isArray(backup.files) ? ` · ${backup.files.length} 个文件` : "";
10
+ return `${service || "未知服务"} · ${time}${count}`;
11
+ }
12
+
6
13
  async function runRestoreCommand(options = {}) {
7
14
  console.log("");
8
- console.log("=== Restore Backup ===");
9
- console.log("");
15
+ console.log(" 恢复备份");
16
+ console.log(" ─────────────────────────────────────");
10
17
 
11
- // Step 1: Select service
12
18
  let service = options.service;
13
19
  if (!service) {
14
20
  const response = await prompts({
15
21
  type: "select",
16
22
  name: "service",
17
- message: "Select service",
23
+ message: "请选择要查看的备份",
18
24
  choices: [
19
25
  { title: "Claude Code", value: "claude" },
20
26
  { title: "Codex", value: "codex" },
21
- { title: "All services", value: null },
27
+ { title: "全部备份", value: null },
22
28
  ],
23
- });
29
+ initial: 2,
30
+ }, { onCancel: () => false });
24
31
 
25
32
  if (response.service === undefined) {
26
- console.log("Restore cancelled.");
33
+ console.log("");
34
+ console.log(" 已取消");
35
+ console.log("");
27
36
  return;
28
37
  }
29
-
30
38
  service = response.service;
31
39
  }
32
40
 
33
- // Step 2: List backups
34
41
  const backups = listBackups(service);
35
-
36
42
  if (backups.length === 0) {
37
- console.log("No backups found.");
43
+ console.log("");
44
+ console.log(" ℹ 暂无可恢复备份");
38
45
  console.log("");
39
46
  return;
40
47
  }
41
48
 
42
- console.log(`Found ${backups.length} backup(s):`);
43
- console.log("");
44
-
45
- // Step 3: Select backup or clear all
46
- const choices = backups.map((backup, index) => ({
47
- title: `${backup.service} - ${new Date(backup.timestamp).toLocaleString()}`,
48
- value: backup.path,
49
- }));
50
-
51
- choices.push({ title: "Clear all backups", value: "__clear__" });
52
-
53
49
  const response = await prompts({
54
50
  type: "select",
55
51
  name: "backup",
56
- message: "Select backup to restore",
57
- choices,
58
- });
52
+ message: "请选择要恢复的备份",
53
+ choices: [
54
+ ...backups.map((backup) => ({ title: formatBackupTitle(backup), value: backup.path })),
55
+ { title: "清空当前筛选的备份", value: "__clear__" },
56
+ ],
57
+ }, { onCancel: () => false });
59
58
 
60
59
  if (!response.backup) {
61
- console.log("Restore cancelled.");
60
+ console.log("");
61
+ console.log(" 已取消");
62
+ console.log("");
62
63
  return;
63
64
  }
64
65
 
65
- // Step 4: Handle clear all
66
66
  if (response.backup === "__clear__") {
67
67
  const confirm = await prompts({
68
68
  type: "confirm",
69
69
  name: "value",
70
- message: "Are you sure you want to clear all backups?",
70
+ message: "确认清空这些备份?",
71
71
  initial: false,
72
- });
72
+ }, { onCancel: () => false });
73
73
 
74
74
  if (!confirm.value) {
75
- console.log("Clear cancelled.");
75
+ console.log("");
76
+ console.log(" 已取消");
77
+ console.log("");
76
78
  return;
77
79
  }
78
80
 
79
81
  const count = clearBackups(service);
80
82
  console.log("");
81
- console.log(`✓ Cleared ${count} backup(s)`);
83
+ console.log(` ✓ 已清理 ${count} 个备份`);
82
84
  console.log("");
83
85
  return;
84
86
  }
85
87
 
86
- // Step 5: Restore backup
87
88
  console.log("");
88
- console.log("Restoring backup...");
89
-
89
+ console.log(" 正在恢复备份...");
90
90
  try {
91
- const restoredPath = restoreBackup(response.backup);
92
- console.log(`✓ Backup restored: ${restoredPath}`);
91
+ const restoredPaths = restoreBackup(response.backup);
92
+ console.log(" ✓ 备份已恢复");
93
+ for (const restoredPath of restoredPaths) {
94
+ console.log(` ${restoredPath}`);
95
+ }
93
96
  console.log("");
94
- console.log("Please restart your application to apply changes.");
97
+ console.log(" 请重启相关工具以应用恢复后的配置");
95
98
  console.log("");
96
99
  } catch (err) {
97
- console.log(`✗ Restore failed: ${err.message}`);
100
+ console.log(` ✗ 恢复失败: ${err.message}`);
98
101
  console.log("");
99
102
  }
100
103
  }
@@ -5,33 +5,27 @@ const { testNodes, formatNodeResults } = require("../services/node-service");
5
5
 
6
6
  async function runTestCommand() {
7
7
  console.log("");
8
- console.log("=== Node Testing ===");
9
- console.log("");
8
+ console.log(" 测试节点");
9
+ console.log(" ─────────────────────────────────────");
10
10
 
11
- // Test Claude nodes
12
- console.log("Testing Claude Code nodes...");
13
- const claudeNodes = await getNodes("claude");
11
+ const services = [
12
+ { key: "claude", label: "Claude Code" },
13
+ { key: "codex", label: "Codex" },
14
+ ];
14
15
 
15
- if (claudeNodes.length > 0) {
16
- const claudeResults = await testNodes(claudeNodes);
16
+ for (const service of services) {
17
17
  console.log("");
18
- console.log(formatNodeResults(claudeResults));
19
- } else {
20
- console.log(" No Claude nodes available");
21
- }
22
-
23
- console.log("");
18
+ console.log(` 正在测试 ${service.label} 节点...`);
19
+ const nodes = await getNodes(service.key);
24
20
 
25
- // Test Codex nodes
26
- console.log("Testing Codex nodes...");
27
- const codexNodes = await getNodes("codex");
21
+ if (nodes.length === 0) {
22
+ console.log(" 暂无可用节点");
23
+ continue;
24
+ }
28
25
 
29
- if (codexNodes.length > 0) {
30
- const codexResults = await testNodes(codexNodes);
26
+ const results = await testNodes(nodes);
31
27
  console.log("");
32
- console.log(formatNodeResults(codexResults));
33
- } else {
34
- console.log(" No Codex nodes available");
28
+ console.log(formatNodeResults(results));
35
29
  }
36
30
 
37
31
  console.log("");
@@ -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,8 +170,55 @@ 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
- await runActivationWizard();
221
+ await runToolsMenu();
175
222
  }
176
223
 
177
224
  function selectMenuAction() {
@@ -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
  };
@@ -244,23 +290,25 @@ function selectMenuAction() {
244
290
  }
245
291
 
246
292
  async function runToolsMenu() {
247
- const action = await selectMenuAction();
248
-
249
- switch (action) {
250
- case "activate":
251
- await runActivationWizard();
252
- break;
253
- case "test":
254
- await runTestCommand();
255
- break;
256
- case "restore":
257
- await runRestoreCommand();
258
- break;
259
- default:
260
- console.log("");
261
- console.log("再见。");
262
- console.log("");
263
- break;
293
+ for (;;) {
294
+ const action = await selectMenuAction();
295
+
296
+ switch (action) {
297
+ case "activate":
298
+ await runActivationWizard();
299
+ break;
300
+ case "test":
301
+ await runTestCommand();
302
+ break;
303
+ case "restore":
304
+ await runRestoreCommand();
305
+ break;
306
+ default:
307
+ console.log("");
308
+ console.log(" 再见!");
309
+ console.log("");
310
+ return;
311
+ }
264
312
  }
265
313
  }
266
314
 
@@ -290,15 +338,11 @@ function buildProgram() {
290
338
  .command("activate")
291
339
  .description("Open the multi-platform activation flow")
292
340
  .option("-s, --service <service>", "target service: claude or codex")
293
- .option("-k, --api-key <apiKey>", "NewAPI key; defaults to config/upstream.json or NEWAPI_API_KEY")
294
341
  .option("-y, --yes", "auto-confirm activation plan")
295
342
  .option("--auto", "alias for --yes")
296
343
  .option("--all", "configure optional platforms even when their config files do not exist")
297
344
  .option("--platforms <ids>", "comma-separated platform ids to activate")
298
- .option("--skip-verify", "skip upstream /v1/models key verification")
299
- .option("--upstream-config <path>", "path to upstream config JSON")
300
345
  .option("-c, --code <code>", "activation / redeem code")
301
- .option("--legacy", "use legacy activation-code node switching flow")
302
346
  .option("--no-redeem", "do not mark activation code as redeemed after writing config")
303
347
  .action(runActivateCommand);
304
348
 
@@ -306,13 +350,10 @@ function buildProgram() {
306
350
  .command("wizard")
307
351
  .description("Open FogAct activation wizard")
308
352
  .option("-s, --service <service>", "target service: claude or codex")
309
- .option("-k, --api-key <apiKey>", "NewAPI key")
310
353
  .option("-c, --code <code>", "activation / redeem code")
311
354
  .option("--platforms <ids>", "comma-separated platform ids to activate")
312
355
  .option("--all", "select all configurable platforms")
313
356
  .option("--yes", "auto-confirm activation plan")
314
- .option("--skip-verify", "skip upstream /v1/models key verification")
315
- .option("--upstream-config <path>", "path to upstream config JSON")
316
357
  .option("--no-redeem", "do not mark activation code as redeemed after writing config")
317
358
  .action(runActivationWizard);
318
359
 
@@ -360,6 +401,7 @@ async function runCli(argv = process.argv) {
360
401
  }
361
402
 
362
403
  module.exports = {
404
+ applyMenuInput,
363
405
  buildProgram,
364
406
  ensureLatestVersion,
365
407
  isNewerVersion,
@@ -22,7 +22,7 @@ function buildClaudeConfig(existingConfig, baseUrl, apiKey) {
22
22
  models: {
23
23
  mode: "merge",
24
24
  providers: {
25
- "newapi-claude": {
25
+ "fogact-claude": {
26
26
  baseUrl,
27
27
  apiKey,
28
28
  auth: "api-key",
@@ -37,7 +37,7 @@ function buildClaudeConfig(existingConfig, baseUrl, apiKey) {
37
37
  ...agentRest,
38
38
  defaults: {
39
39
  model: {
40
- primary: "newapi-claude/claude-opus-4-6",
40
+ primary: "fogact-claude/claude-opus-4-6",
41
41
  },
42
42
  },
43
43
  },
@@ -52,7 +52,7 @@ function buildCodexConfig(existingConfig, baseUrl, apiKey) {
52
52
  models: {
53
53
  mode: "merge",
54
54
  providers: {
55
- "newapi-codex": {
55
+ "fogact-codex": {
56
56
  baseUrl,
57
57
  apiKey,
58
58
  auth: "api-key",
@@ -77,7 +77,7 @@ function buildCodexConfig(existingConfig, baseUrl, apiKey) {
77
77
  ...agentRest,
78
78
  defaults: {
79
79
  model: {
80
- primary: "newapi-codex/gpt-5.2",
80
+ primary: "fogact-codex/gpt-5.2",
81
81
  },
82
82
  },
83
83
  },
@@ -18,10 +18,10 @@ function buildClaudeConfig(existingConfig, baseUrl, apiKey) {
18
18
  const { model, small_model, ...rest } = existingConfig || {};
19
19
  const provider = rest.provider || {};
20
20
  provider.anthropic = {
21
- name: "newapi-claude",
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
  };
@@ -38,7 +38,7 @@ function buildCodexConfig(existingConfig, baseUrl, apiKey) {
38
38
  const { model, small_model, ...rest } = existingConfig || {};
39
39
  const provider = rest.provider || {};
40
40
  provider.openai = {
41
- name: "newapi-codex",
41
+ name: "fogact-codex",
42
42
  npm: "@ai-sdk/openai",
43
43
  api: "responses",
44
44
  options: {