fogact 1.1.5 → 1.1.7
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/README.md +2 -0
- package/README.zh-CN.md +2 -0
- package/frontend/activate.html +56 -17
- package/frontend/admin/admin-panel-v2.js +27 -21
- package/frontend/admin/index.html +21 -11
- package/frontend/assets/market-ui.css +227 -30
- package/frontend/index.html +97 -37
- package/frontend/user/index.html +4 -4
- package/lib/index.js +233 -35
- package/lib/services/cliproxy-api.js +1 -1
- package/lib/services/newapi.js +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
const https = require("https");
|
|
4
|
+
const { spawnSync } = require("child_process");
|
|
3
5
|
const { Command } = require("commander");
|
|
4
6
|
const prompts = require("prompts");
|
|
5
7
|
const packageJson = require("../package.json");
|
|
@@ -8,51 +10,243 @@ const { runTestCommand } = require("./commands/test");
|
|
|
8
10
|
const { runRestoreCommand } = require("./commands/restore");
|
|
9
11
|
const { runActivationWizard } = require("./services/activation-orchestrator");
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
const MENU_CHOICES = [
|
|
14
|
+
{ title: "1. 激活服务", value: "activate" },
|
|
15
|
+
{ title: "2. 测试节点", value: "test" },
|
|
16
|
+
{ title: "3. 恢复备份", value: "restore" },
|
|
17
|
+
{ title: "4. 退出", value: "exit" },
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const UPDATE_TIMEOUT_MS = 2500;
|
|
21
|
+
|
|
22
|
+
function parseVersion(version) {
|
|
23
|
+
return String(version || "")
|
|
24
|
+
.split("-")[0]
|
|
25
|
+
.split(".")
|
|
26
|
+
.map((part) => Number.parseInt(part, 10) || 0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function isNewerVersion(latest, current) {
|
|
30
|
+
const latestParts = parseVersion(latest);
|
|
31
|
+
const currentParts = parseVersion(current);
|
|
32
|
+
const length = Math.max(latestParts.length, currentParts.length);
|
|
33
|
+
for (let index = 0; index < length; index += 1) {
|
|
34
|
+
const latestPart = latestParts[index] || 0;
|
|
35
|
+
const currentPart = currentParts[index] || 0;
|
|
36
|
+
if (latestPart > currentPart) return true;
|
|
37
|
+
if (latestPart < currentPart) return false;
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function fetchLatestVersion() {
|
|
43
|
+
return new Promise((resolve) => {
|
|
44
|
+
const request = https.get(
|
|
45
|
+
"https://registry.npmjs.org/fogact/latest",
|
|
46
|
+
{
|
|
47
|
+
timeout: UPDATE_TIMEOUT_MS,
|
|
48
|
+
headers: {
|
|
49
|
+
Accept: "application/json",
|
|
50
|
+
"User-Agent": `fogact/${packageJson.version}`,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
(response) => {
|
|
54
|
+
if (response.statusCode !== 200) {
|
|
55
|
+
response.resume();
|
|
56
|
+
resolve(null);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let body = "";
|
|
61
|
+
response.setEncoding("utf8");
|
|
62
|
+
response.on("data", (chunk) => {
|
|
63
|
+
body += chunk;
|
|
64
|
+
});
|
|
65
|
+
response.on("end", () => {
|
|
66
|
+
try {
|
|
67
|
+
const metadata = JSON.parse(body);
|
|
68
|
+
resolve(metadata.version || null);
|
|
69
|
+
} catch (_error) {
|
|
70
|
+
resolve(null);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
request.on("timeout", () => {
|
|
77
|
+
request.destroy();
|
|
78
|
+
resolve(null);
|
|
79
|
+
});
|
|
80
|
+
request.on("error", () => resolve(null));
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function isNpmExecRun() {
|
|
85
|
+
const argvPath = process.argv[1] || "";
|
|
86
|
+
const npmCommand = process.env.npm_command || "";
|
|
87
|
+
const npmExecPath = process.env.npm_execpath || "";
|
|
88
|
+
return argvPath.includes("/_npx/") || npmCommand === "exec" || npmCommand === "x" || npmExecPath.includes("npx-cli");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function runLatestWithNpmExec(latestVersion, args, env) {
|
|
92
|
+
return spawnSync(
|
|
93
|
+
"npm",
|
|
94
|
+
["exec", "--yes", "--package", `fogact@${latestVersion}`, "--", "fogact", ...args],
|
|
95
|
+
{ stdio: "inherit", env }
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function ensureLatestVersion(argv = process.argv) {
|
|
100
|
+
if (process.env.FOGACT_SKIP_UPDATE === "1" || process.env.FOGACT_NO_UPDATE === "1") {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const latestVersion = await fetchLatestVersion();
|
|
105
|
+
if (!latestVersion || !isNewerVersion(latestVersion, packageJson.version)) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const args = argv.slice(2);
|
|
110
|
+
const env = { ...process.env, FOGACT_SKIP_UPDATE: "1" };
|
|
111
|
+
console.log(`检测到新版本 v${latestVersion},正在自动更新...`);
|
|
112
|
+
|
|
113
|
+
if (isNpmExecRun()) {
|
|
114
|
+
const result = runLatestWithNpmExec(latestVersion, args, env);
|
|
115
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const update = spawnSync("npm", ["install", "-g", `fogact@${latestVersion}`], {
|
|
119
|
+
stdio: "inherit",
|
|
120
|
+
env,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
if (update.status === 0) {
|
|
124
|
+
console.log("更新完成,正在重新启动...");
|
|
125
|
+
const restart = spawnSync(process.execPath, argv.slice(1), { stdio: "inherit", env });
|
|
126
|
+
process.exit(restart.status === null ? 1 : restart.status);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
console.log("自动更新失败,正在尝试直接运行最新版...");
|
|
130
|
+
const result = runLatestWithNpmExec(latestVersion, args, env);
|
|
131
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function displayWidth(value) {
|
|
135
|
+
return Array.from(value).reduce((width, char) => {
|
|
15
136
|
return width + (char.charCodeAt(0) > 0xff ? 2 : 1);
|
|
16
137
|
}, 0);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function padLine(value, width) {
|
|
141
|
+
const padding = Math.max(0, width - displayWidth(value));
|
|
142
|
+
const left = Math.floor(padding / 2);
|
|
143
|
+
const right = padding - left;
|
|
144
|
+
return `${" ".repeat(left)}${value}${" ".repeat(right)}`;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function renderMenu(cursor = 0) {
|
|
148
|
+
const version = packageJson.version;
|
|
149
|
+
const title = `FogAct 激活器 v${version}`;
|
|
150
|
+
const lines = [
|
|
151
|
+
"",
|
|
152
|
+
" ╭─────────────────────────────────────╮",
|
|
153
|
+
` │${padLine(title, 37)}│`,
|
|
154
|
+
" │ Claude Code / Codex 配置工具 │",
|
|
155
|
+
" ╰─────────────────────────────────────╯",
|
|
156
|
+
"",
|
|
157
|
+
"? 请选择操作:",
|
|
158
|
+
];
|
|
159
|
+
|
|
160
|
+
MENU_CHOICES.forEach((choice, index) => {
|
|
161
|
+
lines.push(`${index === cursor ? "❯" : " "} ${choice.title}`);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
lines.push("");
|
|
165
|
+
lines.push("↑↓ navigate • ⏎ select");
|
|
166
|
+
return lines.join("\n");
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function printBanner() {
|
|
170
|
+
console.log(renderMenu(0));
|
|
29
171
|
}
|
|
30
172
|
|
|
31
173
|
async function runInteractiveMenu() {
|
|
32
174
|
await runActivationWizard();
|
|
33
175
|
}
|
|
34
176
|
|
|
177
|
+
function selectMenuAction() {
|
|
178
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
179
|
+
printBanner();
|
|
180
|
+
return Promise.resolve(null);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return new Promise((resolve) => {
|
|
184
|
+
let cursor = 0;
|
|
185
|
+
let renderedLines = 0;
|
|
186
|
+
const stdin = process.stdin;
|
|
187
|
+
|
|
188
|
+
const render = () => {
|
|
189
|
+
if (renderedLines > 0) {
|
|
190
|
+
process.stdout.write(`\x1b[${renderedLines}A`);
|
|
191
|
+
process.stdout.write("\x1b[J");
|
|
192
|
+
}
|
|
193
|
+
const output = renderMenu(cursor);
|
|
194
|
+
renderedLines = output.split("\n").length;
|
|
195
|
+
process.stdout.write(output);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const cleanup = () => {
|
|
199
|
+
stdin.off("data", onData);
|
|
200
|
+
if (stdin.isRaw) stdin.setRawMode(false);
|
|
201
|
+
stdin.pause();
|
|
202
|
+
process.stdout.write("\x1b[?25h\n");
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const submit = () => {
|
|
206
|
+
const choice = MENU_CHOICES[cursor];
|
|
207
|
+
cleanup();
|
|
208
|
+
resolve(choice.value);
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const cancel = () => {
|
|
212
|
+
cleanup();
|
|
213
|
+
resolve("exit");
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const onData = (data) => {
|
|
217
|
+
const key = data.toString("utf8");
|
|
218
|
+
if (key === "\u0003" || key === "\u001b") {
|
|
219
|
+
cancel();
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (key === "\r" || key === "\n") {
|
|
223
|
+
submit();
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
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;
|
|
233
|
+
render();
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
process.stdout.write("\x1b[?25l");
|
|
238
|
+
render();
|
|
239
|
+
stdin.resume();
|
|
240
|
+
stdin.setEncoding("utf8");
|
|
241
|
+
stdin.setRawMode(true);
|
|
242
|
+
stdin.on("data", onData);
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
35
246
|
async function runToolsMenu() {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const response = await prompts(
|
|
39
|
-
{
|
|
40
|
-
type: "select",
|
|
41
|
-
name: "action",
|
|
42
|
-
message: "请选择操作:",
|
|
43
|
-
hint: "↑↓ 选择,回车确认",
|
|
44
|
-
choices: [
|
|
45
|
-
{ title: "1. 激活服务", value: "activate" },
|
|
46
|
-
{ title: "2. 测试节点", value: "test" },
|
|
47
|
-
{ title: "3. 恢复备份", value: "restore" },
|
|
48
|
-
{ title: "4. 退出", value: "exit" },
|
|
49
|
-
],
|
|
50
|
-
initial: 0,
|
|
51
|
-
},
|
|
52
|
-
{ onCancel: () => false }
|
|
53
|
-
);
|
|
247
|
+
const action = await selectMenuAction();
|
|
54
248
|
|
|
55
|
-
switch (
|
|
249
|
+
switch (action) {
|
|
56
250
|
case "activate":
|
|
57
251
|
await runActivationWizard();
|
|
58
252
|
break;
|
|
@@ -152,6 +346,8 @@ function buildProgram() {
|
|
|
152
346
|
}
|
|
153
347
|
|
|
154
348
|
async function runCli(argv = process.argv) {
|
|
349
|
+
await ensureLatestVersion(argv);
|
|
350
|
+
|
|
155
351
|
const args = argv.slice(2).filter((arg) => arg !== "--help" && arg !== "-h");
|
|
156
352
|
|
|
157
353
|
if (args.length === 0) {
|
|
@@ -165,6 +361,8 @@ async function runCli(argv = process.argv) {
|
|
|
165
361
|
|
|
166
362
|
module.exports = {
|
|
167
363
|
buildProgram,
|
|
364
|
+
ensureLatestVersion,
|
|
365
|
+
isNewerVersion,
|
|
168
366
|
runCli,
|
|
169
367
|
runInteractiveMenu,
|
|
170
368
|
runToolsMenu,
|
package/lib/services/newapi.js
CHANGED