fogact 1.1.4 → 1.1.6
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 +40 -196
- package/README.zh-CN.md +40 -196
- 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 +75 -1
- package/frontend/index.html +66 -30
- package/frontend/user/index.html +4 -4
- package/install.sh +5 -14
- package/lib/index.js +118 -32
- package/lib/services/activation-orchestrator.js +26 -15
- package/lib/services/cliproxy-api.js +1 -1
- package/lib/services/newapi.js +1 -1
- package/package.json +2 -2
package/frontend/index.html
CHANGED
|
@@ -3,13 +3,22 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>
|
|
7
|
-
<meta name="description" content="
|
|
6
|
+
<title>FogAct | 多平台激活与配额管理</title>
|
|
7
|
+
<meta name="description" content="FogAct 提供用户中心、激活码管理、配额查看和多平台 CLI 接入入口。" />
|
|
8
|
+
<script>
|
|
9
|
+
;(function () {
|
|
10
|
+
var theme = localStorage.getItem('fogact_theme') || localStorage.getItem('admin_theme') || localStorage.getItem('yunyi_user_theme') || 'system';
|
|
11
|
+
var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
12
|
+
var isDark = theme === 'dark' || (theme === 'system' && prefersDark);
|
|
13
|
+
document.documentElement.classList.toggle('dark', isDark);
|
|
14
|
+
document.documentElement.style.colorScheme = isDark ? 'dark' : 'light';
|
|
15
|
+
})();
|
|
16
|
+
</script>
|
|
8
17
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
9
18
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
10
19
|
<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" />
|
|
11
20
|
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" rel="stylesheet" />
|
|
12
|
-
<link rel="stylesheet" href="/assets/market-ui.css?v=
|
|
21
|
+
<link rel="stylesheet" href="/assets/market-ui.css?v=20260619-theme1" />
|
|
13
22
|
</head>
|
|
14
23
|
<body class="market-page">
|
|
15
24
|
<span class="market-mouse-light" aria-hidden="true"></span>
|
|
@@ -19,8 +28,8 @@
|
|
|
19
28
|
<a class="market-brand" href="/">
|
|
20
29
|
<span class="market-logo">F</span>
|
|
21
30
|
<span>
|
|
22
|
-
<span class="market-brand-title">
|
|
23
|
-
<span class="market-brand-subtitle"
|
|
31
|
+
<span class="market-brand-title">FogAct</span>
|
|
32
|
+
<span class="market-brand-subtitle">多平台激活工作台</span>
|
|
24
33
|
</span>
|
|
25
34
|
</a>
|
|
26
35
|
|
|
@@ -31,6 +40,9 @@
|
|
|
31
40
|
</nav>
|
|
32
41
|
|
|
33
42
|
<div class="market-actions">
|
|
43
|
+
<button type="button" class="market-button market-theme-toggle" data-theme-toggle aria-label="切换暗黑模式">
|
|
44
|
+
<span class="material-symbols-outlined" data-theme-icon>light_mode</span>
|
|
45
|
+
</button>
|
|
34
46
|
<a class="market-button" href="/api/stats">API</a>
|
|
35
47
|
<a class="market-button market-button-primary" href="/user/">
|
|
36
48
|
<span class="material-symbols-outlined">bolt</span>
|
|
@@ -42,10 +54,10 @@
|
|
|
42
54
|
<main>
|
|
43
55
|
<section class="market-hero" aria-labelledby="hero-title">
|
|
44
56
|
<div class="market-hero-main">
|
|
45
|
-
<div class="market-kicker"><span class="market-kicker-dot"></span>
|
|
46
|
-
<h1 id="hero-title" class="market-title"
|
|
57
|
+
<div class="market-kicker"><span class="market-kicker-dot"></span> CLI 激活与配额管理</div>
|
|
58
|
+
<h1 id="hero-title" class="market-title">统一管理 Codex、Claude 与更多 <span>CLI 服务</span></h1>
|
|
47
59
|
<p class="market-copy">
|
|
48
|
-
|
|
60
|
+
在一个入口完成激活码发放、用户绑定、额度查看和服务配置,减少来回切换。
|
|
49
61
|
</p>
|
|
50
62
|
|
|
51
63
|
<label class="market-search" aria-label="搜索功能入口">
|
|
@@ -70,31 +82,31 @@
|
|
|
70
82
|
</div>
|
|
71
83
|
</div>
|
|
72
84
|
|
|
73
|
-
<aside class="market-hero-side" aria-label="
|
|
85
|
+
<aside class="market-hero-side" aria-label="服务状态概览">
|
|
74
86
|
<div class="market-preview-stack">
|
|
75
87
|
<div class="market-mini-card">
|
|
76
|
-
<span class="market-icon material-symbols-outlined">
|
|
88
|
+
<span class="market-icon material-symbols-outlined">hub</span>
|
|
77
89
|
<div>
|
|
78
|
-
<p class="market-mini-title"
|
|
79
|
-
<p class="market-mini-copy"
|
|
90
|
+
<p class="market-mini-title">服务接入</p>
|
|
91
|
+
<p class="market-mini-copy">统一承载 Codex、Claude Code、OpenCode 与 OpenClaw 等 CLI 场景。</p>
|
|
80
92
|
</div>
|
|
81
|
-
<span class="market-status-pill"
|
|
93
|
+
<span class="market-status-pill">已接入</span>
|
|
82
94
|
</div>
|
|
83
95
|
<div class="market-mini-card">
|
|
84
|
-
<span class="market-icon material-symbols-outlined">
|
|
96
|
+
<span class="market-icon material-symbols-outlined">key_vertical</span>
|
|
85
97
|
<div>
|
|
86
|
-
<p class="market-mini-title"
|
|
87
|
-
<p class="market-mini-copy"
|
|
98
|
+
<p class="market-mini-title">激活码管理</p>
|
|
99
|
+
<p class="market-mini-copy">支持生成、导出、绑定、过期状态追踪,方便批量运营。</p>
|
|
88
100
|
</div>
|
|
89
|
-
<span class="market-status-pill">
|
|
101
|
+
<span class="market-status-pill">CDK</span>
|
|
90
102
|
</div>
|
|
91
103
|
<div class="market-mini-card">
|
|
92
104
|
<span class="market-icon material-symbols-outlined">speed</span>
|
|
93
105
|
<div>
|
|
94
|
-
<p class="market-mini-title"
|
|
95
|
-
<p class="market-mini-copy"
|
|
106
|
+
<p class="market-mini-title">配额监控</p>
|
|
107
|
+
<p class="market-mini-copy">快速查看请求、额度、用户状态和服务健康度。</p>
|
|
96
108
|
</div>
|
|
97
|
-
<span class="market-status-pill"
|
|
109
|
+
<span class="market-status-pill">监控</span>
|
|
98
110
|
</div>
|
|
99
111
|
</div>
|
|
100
112
|
|
|
@@ -104,7 +116,7 @@
|
|
|
104
116
|
<span class="market-status-pill"><span class="market-kicker-dot"></span> 34020</span>
|
|
105
117
|
</div>
|
|
106
118
|
<p class="market-mini-copy" style="margin-top: 14px; font-size: 14px; line-height: 1.7;">
|
|
107
|
-
|
|
119
|
+
本地 Web 服务默认运行在 34020 端口,提供首页、用户中心、管理中心和激活入口。
|
|
108
120
|
</p>
|
|
109
121
|
</div>
|
|
110
122
|
</aside>
|
|
@@ -114,7 +126,7 @@
|
|
|
114
126
|
<div class="market-section-head">
|
|
115
127
|
<div>
|
|
116
128
|
<h2 id="section-title">工作区入口</h2>
|
|
117
|
-
<p
|
|
129
|
+
<p>按使用角色拆分入口:查看用量、管理资源、完成激活,各自保持清晰路径。</p>
|
|
118
130
|
</div>
|
|
119
131
|
<a class="market-button" href="/admin/">打开管理中心</a>
|
|
120
132
|
</div>
|
|
@@ -126,9 +138,9 @@
|
|
|
126
138
|
<span class="market-widget market-widget-graph"><i></i><i></i><i></i><i></i></span>
|
|
127
139
|
</div>
|
|
128
140
|
<div class="market-card-content">
|
|
129
|
-
<h3
|
|
130
|
-
<p
|
|
131
|
-
<div class="market-card-footer"><span class="market-tag"
|
|
141
|
+
<h3>用户中心</h3>
|
|
142
|
+
<p>查看额度、请求趋势、公告和个人配置,适合作为用户自助入口。</p>
|
|
143
|
+
<div class="market-card-footer"><span class="market-tag">用户入口</span><span class="market-arrow">→</span></div>
|
|
132
144
|
</div>
|
|
133
145
|
</a>
|
|
134
146
|
|
|
@@ -139,8 +151,8 @@
|
|
|
139
151
|
</div>
|
|
140
152
|
<div class="market-card-content">
|
|
141
153
|
<h3>管理控制台</h3>
|
|
142
|
-
<p
|
|
143
|
-
<div class="market-card-footer"><span class="market-tag"
|
|
154
|
+
<p>集中维护用户、激活码、日志和系统设置,适合管理员日常操作。</p>
|
|
155
|
+
<div class="market-card-footer"><span class="market-tag">管理入口</span><span class="market-arrow">→</span></div>
|
|
144
156
|
</div>
|
|
145
157
|
</a>
|
|
146
158
|
|
|
@@ -151,9 +163,9 @@
|
|
|
151
163
|
<span class="market-widget market-widget-badge material-symbols-outlined">bolt</span>
|
|
152
164
|
</div>
|
|
153
165
|
<div class="market-card-content">
|
|
154
|
-
<h3>CDK
|
|
155
|
-
<p
|
|
156
|
-
<div class="market-card-footer"><span class="market-tag"
|
|
166
|
+
<h3>CDK 激活</h3>
|
|
167
|
+
<p>输入激活码即可完成服务绑定,并返回额度、服务类型和有效期。</p>
|
|
168
|
+
<div class="market-card-footer"><span class="market-tag">激活入口</span><span class="market-arrow">→</span></div>
|
|
157
169
|
</div>
|
|
158
170
|
</a>
|
|
159
171
|
</div>
|
|
@@ -179,6 +191,8 @@
|
|
|
179
191
|
});
|
|
180
192
|
});
|
|
181
193
|
|
|
194
|
+
initThemeToggle();
|
|
195
|
+
|
|
182
196
|
document.querySelectorAll('.market-card-lab').forEach((card) => {
|
|
183
197
|
card.addEventListener('pointermove', (event) => {
|
|
184
198
|
const rect = card.getBoundingClientRect();
|
|
@@ -186,6 +200,28 @@
|
|
|
186
200
|
card.style.setProperty('--my', `${((event.clientY - rect.top) / rect.height) * 100}%`);
|
|
187
201
|
});
|
|
188
202
|
});
|
|
203
|
+
|
|
204
|
+
function initThemeToggle() {
|
|
205
|
+
const button = document.querySelector('[data-theme-toggle]');
|
|
206
|
+
const icon = document.querySelector('[data-theme-icon]');
|
|
207
|
+
if (!button || !icon) return;
|
|
208
|
+
|
|
209
|
+
const sync = () => {
|
|
210
|
+
const isDark = document.documentElement.classList.contains('dark');
|
|
211
|
+
icon.textContent = isDark ? 'dark_mode' : 'light_mode';
|
|
212
|
+
button.setAttribute('aria-label', isDark ? '切换浅色模式' : '切换暗黑模式');
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
button.addEventListener('click', () => {
|
|
216
|
+
const isDark = !document.documentElement.classList.contains('dark');
|
|
217
|
+
document.documentElement.classList.toggle('dark', isDark);
|
|
218
|
+
document.documentElement.style.colorScheme = isDark ? 'dark' : 'light';
|
|
219
|
+
localStorage.setItem('fogact_theme', isDark ? 'dark' : 'light');
|
|
220
|
+
sync();
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
sync();
|
|
224
|
+
}
|
|
189
225
|
</script>
|
|
190
226
|
</body>
|
|
191
227
|
</html>
|
package/frontend/user/index.html
CHANGED
|
@@ -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>
|
|
12
|
-
<meta name="description" content="
|
|
11
|
+
<title>FogAct 用户中心 | 用量与配额监控</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_theme') || localStorage.getItem('yunyi_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) {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
<script type="module" crossorigin src="assets/index-Da98HOxL.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=
|
|
34
|
+
<link rel="stylesheet" href="/assets/market-ui.css?v=20260619-theme1" />
|
|
35
35
|
</head>
|
|
36
36
|
<body class="market-user min-h-screen">
|
|
37
37
|
<span class="market-mouse-light" aria-hidden="true"></span>
|
package/install.sh
CHANGED
|
@@ -359,20 +359,11 @@ run_activation() {
|
|
|
359
359
|
print_next_steps() {
|
|
360
360
|
cat <<EOF
|
|
361
361
|
|
|
362
|
-
Next
|
|
363
|
-
fogact
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
fogact
|
|
367
|
-
|
|
368
|
-
For code mode with a remote activation backend:
|
|
369
|
-
export CLIPROXY_API_BASE="https://your-activator.example.com"
|
|
370
|
-
fogact wizard --code YOUR_CODE --yes
|
|
371
|
-
|
|
372
|
-
For direct NewAPI mode:
|
|
373
|
-
export NEWAPI_BASE_URL="https://newapi.example.com"
|
|
374
|
-
export NEWAPI_API_KEY="sk-your-key"
|
|
375
|
-
fogact activate --service codex --yes
|
|
362
|
+
Next command:
|
|
363
|
+
fogact
|
|
364
|
+
|
|
365
|
+
This opens the same interactive activation menu as:
|
|
366
|
+
npx fogact
|
|
376
367
|
EOF
|
|
377
368
|
}
|
|
378
369
|
|
package/lib/index.js
CHANGED
|
@@ -8,37 +8,129 @@ const { runTestCommand } = require("./commands/test");
|
|
|
8
8
|
const { runRestoreCommand } = require("./commands/restore");
|
|
9
9
|
const { runActivationWizard } = require("./services/activation-orchestrator");
|
|
10
10
|
|
|
11
|
+
const MENU_CHOICES = [
|
|
12
|
+
{ title: "1. 激活服务", value: "activate" },
|
|
13
|
+
{ title: "2. 测试节点", value: "test" },
|
|
14
|
+
{ title: "3. 恢复备份", value: "restore" },
|
|
15
|
+
{ title: "4. 退出", value: "exit" },
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
function displayWidth(value) {
|
|
19
|
+
return Array.from(value).reduce((width, char) => {
|
|
20
|
+
return width + (char.charCodeAt(0) > 0xff ? 2 : 1);
|
|
21
|
+
}, 0);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function padLine(value, width) {
|
|
25
|
+
const padding = Math.max(0, width - displayWidth(value));
|
|
26
|
+
const left = Math.floor(padding / 2);
|
|
27
|
+
const right = padding - left;
|
|
28
|
+
return `${" ".repeat(left)}${value}${" ".repeat(right)}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function renderMenu(cursor = 0) {
|
|
32
|
+
const version = packageJson.version;
|
|
33
|
+
const title = `FogAct 激活器 v${version}`;
|
|
34
|
+
const lines = [
|
|
35
|
+
"",
|
|
36
|
+
" ╭─────────────────────────────────────╮",
|
|
37
|
+
` │${padLine(title, 37)}│`,
|
|
38
|
+
" │ Claude Code / Codex 配置工具 │",
|
|
39
|
+
" ╰─────────────────────────────────────╯",
|
|
40
|
+
"",
|
|
41
|
+
"? 请选择操作:",
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
MENU_CHOICES.forEach((choice, index) => {
|
|
45
|
+
lines.push(`${index === cursor ? "❯" : " "} ${choice.title}`);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
lines.push("");
|
|
49
|
+
lines.push("↑↓ navigate • ⏎ select");
|
|
50
|
+
return lines.join("\n");
|
|
51
|
+
}
|
|
52
|
+
|
|
11
53
|
function printBanner() {
|
|
12
|
-
console.log(
|
|
13
|
-
console.log("一键激活 Codex / Claude / OpenCode / OpenClaw");
|
|
14
|
-
console.log("");
|
|
54
|
+
console.log(renderMenu(0));
|
|
15
55
|
}
|
|
16
56
|
|
|
17
57
|
async function runInteractiveMenu() {
|
|
18
58
|
await runActivationWizard();
|
|
19
59
|
}
|
|
20
60
|
|
|
61
|
+
function selectMenuAction() {
|
|
62
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
63
|
+
printBanner();
|
|
64
|
+
return Promise.resolve(null);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return new Promise((resolve) => {
|
|
68
|
+
let cursor = 0;
|
|
69
|
+
let renderedLines = 0;
|
|
70
|
+
const stdin = process.stdin;
|
|
71
|
+
|
|
72
|
+
const render = () => {
|
|
73
|
+
if (renderedLines > 0) {
|
|
74
|
+
process.stdout.write(`\x1b[${renderedLines}A`);
|
|
75
|
+
process.stdout.write("\x1b[J");
|
|
76
|
+
}
|
|
77
|
+
const output = renderMenu(cursor);
|
|
78
|
+
renderedLines = output.split("\n").length;
|
|
79
|
+
process.stdout.write(output);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const cleanup = () => {
|
|
83
|
+
stdin.off("data", onData);
|
|
84
|
+
if (stdin.isRaw) stdin.setRawMode(false);
|
|
85
|
+
stdin.pause();
|
|
86
|
+
process.stdout.write("\x1b[?25h\n");
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const submit = () => {
|
|
90
|
+
const choice = MENU_CHOICES[cursor];
|
|
91
|
+
cleanup();
|
|
92
|
+
resolve(choice.value);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const cancel = () => {
|
|
96
|
+
cleanup();
|
|
97
|
+
resolve("exit");
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const onData = (data) => {
|
|
101
|
+
const key = data.toString("utf8");
|
|
102
|
+
if (key === "\u0003" || key === "\u001b") {
|
|
103
|
+
cancel();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (key === "\r" || key === "\n") {
|
|
107
|
+
submit();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (key === "\u001b[A") {
|
|
111
|
+
cursor = cursor === 0 ? MENU_CHOICES.length - 1 : cursor - 1;
|
|
112
|
+
render();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (key === "\u001b[B") {
|
|
116
|
+
cursor = cursor === MENU_CHOICES.length - 1 ? 0 : cursor + 1;
|
|
117
|
+
render();
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
process.stdout.write("\x1b[?25l");
|
|
122
|
+
render();
|
|
123
|
+
stdin.resume();
|
|
124
|
+
stdin.setEncoding("utf8");
|
|
125
|
+
stdin.setRawMode(true);
|
|
126
|
+
stdin.on("data", onData);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
21
130
|
async function runToolsMenu() {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
{
|
|
26
|
-
type: "select",
|
|
27
|
-
name: "action",
|
|
28
|
-
message: "请选择操作",
|
|
29
|
-
choices: [
|
|
30
|
-
{ title: "多平台激活", value: "activate" },
|
|
31
|
-
{ title: "测试节点", value: "test" },
|
|
32
|
-
{ title: "恢复备份", value: "restore" },
|
|
33
|
-
{ title: "启动 Web UI", value: "web" },
|
|
34
|
-
{ title: "退出", value: "exit" },
|
|
35
|
-
],
|
|
36
|
-
initial: 0,
|
|
37
|
-
},
|
|
38
|
-
{ onCancel: () => false }
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
switch (response.action) {
|
|
131
|
+
const action = await selectMenuAction();
|
|
132
|
+
|
|
133
|
+
switch (action) {
|
|
42
134
|
case "activate":
|
|
43
135
|
await runActivationWizard();
|
|
44
136
|
break;
|
|
@@ -48,10 +140,8 @@ async function runToolsMenu() {
|
|
|
48
140
|
case "restore":
|
|
49
141
|
await runRestoreCommand();
|
|
50
142
|
break;
|
|
51
|
-
case "web":
|
|
52
|
-
runWebServer();
|
|
53
|
-
break;
|
|
54
143
|
default:
|
|
144
|
+
console.log("");
|
|
55
145
|
console.log("再见。");
|
|
56
146
|
console.log("");
|
|
57
147
|
break;
|
|
@@ -76,11 +166,7 @@ function buildProgram() {
|
|
|
76
166
|
"Examples:",
|
|
77
167
|
" npx fogact",
|
|
78
168
|
" fogact",
|
|
79
|
-
" fogact
|
|
80
|
-
" fogact activate --service claude --api-key sk-... --yes",
|
|
81
|
-
" fogact activate --code K1DHPY3P-4B2W-F1A4-DC4P-Y74TCQZXPNYT",
|
|
82
|
-
" fogact test",
|
|
83
|
-
" fogact restore --service claude",
|
|
169
|
+
" fogact web",
|
|
84
170
|
].join("\n")
|
|
85
171
|
);
|
|
86
172
|
|
|
@@ -144,7 +230,7 @@ function buildProgram() {
|
|
|
144
230
|
}
|
|
145
231
|
|
|
146
232
|
async function runCli(argv = process.argv) {
|
|
147
|
-
const args = argv.slice(2);
|
|
233
|
+
const args = argv.slice(2).filter((arg) => arg !== "--help" && arg !== "-h");
|
|
148
234
|
|
|
149
235
|
if (args.length === 0) {
|
|
150
236
|
await runToolsMenu();
|
|
@@ -203,6 +203,7 @@ async function promptService(defaultService, entitlement = normalizeEntitlement(
|
|
|
203
203
|
type: "select",
|
|
204
204
|
name: "service",
|
|
205
205
|
message: "请选择要激活的能力",
|
|
206
|
+
hint: "↑↓ 选择,回车确认",
|
|
206
207
|
choices: allowedServices.map((service) => ({ title: getServiceLabel(service), value: service })),
|
|
207
208
|
initial: 0,
|
|
208
209
|
}, { onCancel: () => false });
|
|
@@ -267,9 +268,10 @@ async function promptCredentialType(options, upstream) {
|
|
|
267
268
|
type: "select",
|
|
268
269
|
name: "credentialType",
|
|
269
270
|
message: "请选择激活方式",
|
|
271
|
+
hint: "↑↓ 选择,回车确认",
|
|
270
272
|
choices: [
|
|
271
|
-
{ title: "输入 NewAPI API Key", value: "api-key" },
|
|
272
273
|
{ title: "输入激活码 / 兑换码", value: "code" },
|
|
274
|
+
{ title: "输入 NewAPI API Key", value: "api-key" },
|
|
273
275
|
],
|
|
274
276
|
initial: 0,
|
|
275
277
|
}, { onCancel: () => false });
|
|
@@ -312,8 +314,8 @@ function getBackupPaths(targets) {
|
|
|
312
314
|
function printBanner() {
|
|
313
315
|
console.log("");
|
|
314
316
|
console.log("╭────────────────────────────────────────╮");
|
|
315
|
-
console.log("│
|
|
316
|
-
console.log("│
|
|
317
|
+
console.log("│ FogAct 激活向导 │");
|
|
318
|
+
console.log("│ Claude Code / Codex 配置工具 │");
|
|
317
319
|
console.log("╰────────────────────────────────────────╯");
|
|
318
320
|
console.log("");
|
|
319
321
|
}
|
|
@@ -578,6 +580,23 @@ async function runNewApiActivation(options = {}) {
|
|
|
578
580
|
async function runActivationWizard(options = {}) {
|
|
579
581
|
printBanner();
|
|
580
582
|
const baseUpstream = loadUpstreamConfig({ configPath: options.upstreamConfig });
|
|
583
|
+
|
|
584
|
+
const service = await promptService(options.service, normalizeEntitlement());
|
|
585
|
+
if (!service) {
|
|
586
|
+
console.log("已取消。");
|
|
587
|
+
return { success: false, cancelled: true };
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
const initialDetectedPlatforms = detectPlatforms(service);
|
|
591
|
+
console.log("");
|
|
592
|
+
printDetection(service, initialDetectedPlatforms);
|
|
593
|
+
|
|
594
|
+
const initialTargets = await selectPlatforms(initialDetectedPlatforms, options);
|
|
595
|
+
if (initialTargets.length === 0) {
|
|
596
|
+
console.log("没有选择任何平台,已取消。");
|
|
597
|
+
return { success: false, cancelled: true };
|
|
598
|
+
}
|
|
599
|
+
|
|
581
600
|
const credentialType = await promptCredentialType(options, baseUpstream);
|
|
582
601
|
if (!credentialType) {
|
|
583
602
|
console.log("已取消。");
|
|
@@ -599,12 +618,6 @@ async function runActivationWizard(options = {}) {
|
|
|
599
618
|
return { success: false, cancelled: true };
|
|
600
619
|
}
|
|
601
620
|
|
|
602
|
-
const service = await promptService(options.service, credential.entitlement);
|
|
603
|
-
if (!service) {
|
|
604
|
-
console.log("已取消。");
|
|
605
|
-
return { success: false, cancelled: true };
|
|
606
|
-
}
|
|
607
|
-
|
|
608
621
|
console.log("");
|
|
609
622
|
if (credentialType === "api-key") {
|
|
610
623
|
const verification = await verifyCredential(upstream, credential.apiKey, options);
|
|
@@ -618,16 +631,14 @@ async function runActivationWizard(options = {}) {
|
|
|
618
631
|
const allDetectedPlatforms = detectPlatforms(service);
|
|
619
632
|
const allowedPlatforms = allDetectedPlatforms.filter((entry) => isPlatformAllowed(entry, credential.entitlement, service));
|
|
620
633
|
const blockedPlatforms = allDetectedPlatforms.filter((entry) => !allowedPlatforms.includes(entry));
|
|
634
|
+
const initialTargetIds = new Set(initialTargets.map(({ platform }) => platform.id));
|
|
621
635
|
|
|
622
|
-
|
|
623
|
-
printDetection(service, allowedPlatforms, blockedPlatforms);
|
|
624
|
-
|
|
625
|
-
const targets = await selectPlatforms(allowedPlatforms, options);
|
|
636
|
+
const targets = allowedPlatforms.filter((entry) => initialTargetIds.has(entry.platform.id));
|
|
626
637
|
if (targets.length === 0) {
|
|
627
|
-
console.log("
|
|
638
|
+
console.log("当前激活能力不包含已选择的平台,已取消。");
|
|
628
639
|
return { success: false, cancelled: true };
|
|
629
640
|
}
|
|
630
|
-
const skipped =
|
|
641
|
+
const skipped = allDetectedPlatforms.filter((entry) => !targets.includes(entry) || blockedPlatforms.includes(entry));
|
|
631
642
|
|
|
632
643
|
printPlan(service, upstream, credential.apiKey, targets, skipped);
|
|
633
644
|
if (!(await confirmActivation(Boolean(options.yes || options.auto)))) {
|
package/lib/services/newapi.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fogact",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "FogAct
|
|
3
|
+
"version": "1.1.6",
|
|
4
|
+
"description": "FogAct activation helper for Claude Code and Codex",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fogact",
|
|
7
7
|
"cliproxy",
|