fogact 1.1.8 → 1.1.10
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/bin/web-server.js +72 -16
- package/frontend/assets/market-ui.css +0 -122
- package/frontend/index.html +8 -34
- package/frontend/user/assets/DashboardLayout-DDkxHYFj.js +1 -1
- package/frontend/user/assets/Welcome-Dtfp6oER.js +1 -1
- package/frontend/user/assets/announcement-35mOnjRL.js +1 -1
- package/frontend/user/assets/index-Da98HOxL.js +2 -2
- package/frontend/user/index.html +4 -4
- package/lib/services/activation-orchestrator.js +1 -25
- package/lib/services/fogact-api.js +3 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ That is the user-facing command. Running it opens the interactive menu:
|
|
|
27
27
|
|
|
28
28
|
Do not run `npm fogact`; npm treats that as an npm subcommand. Use `npx fogact`.
|
|
29
29
|
|
|
30
|
-
FogAct checks npm for the latest version before opening the menu. If an older installed version is detected, it updates first and then continues. Set `FOGACT_SKIP_UPDATE=1` to skip
|
|
30
|
+
FogAct checks npm for the latest version before opening the menu. If an older installed version is detected, it updates first and then continues. Activation codes use the public panel `https://cliproxy.fogidc.com` by default; set `FOGACT_API_BASE` to use another backend. Set `FOGACT_SKIP_UPDATE=1` to skip the update check.
|
|
31
31
|
|
|
32
32
|
## Clean VPS
|
|
33
33
|
|
package/README.zh-CN.md
CHANGED
|
@@ -27,7 +27,7 @@ npx fogact
|
|
|
27
27
|
|
|
28
28
|
不要运行 `npm fogact`;npm 会把它当成 npm 子命令。正确方式是 `npx fogact`。
|
|
29
29
|
|
|
30
|
-
FogAct 启动时会自动检查 npm
|
|
30
|
+
FogAct 启动时会自动检查 npm 最新版本;检测到旧版本会先更新,再进入菜单。激活码默认连接公网面板 `https://cliproxy.fogidc.com`,需要切换测试后端时可设置 `FOGACT_API_BASE`。需要跳过更新检查时可设置 `FOGACT_SKIP_UPDATE=1`。
|
|
31
31
|
|
|
32
32
|
## 干净 VPS
|
|
33
33
|
|
package/bin/web-server.js
CHANGED
|
@@ -6,7 +6,7 @@ const fs = require("fs");
|
|
|
6
6
|
const path = require("path");
|
|
7
7
|
const os = require("os");
|
|
8
8
|
const { userDb, codeDb, initializeSampleData } = require("../lib/services/database");
|
|
9
|
-
const { DEFAULT_CONFIG_PATH, loadUpstreamConfig } = require("../lib/config/upstream");
|
|
9
|
+
const { DEFAULT_CONFIG_PATH, getServiceBaseUrl, loadUpstreamConfig } = require("../lib/config/upstream");
|
|
10
10
|
const { readJsonFile, writeJsonFile } = require("../lib/utils/json-file");
|
|
11
11
|
const { maskKey, verifyNewApiKey } = require("../lib/services/newapi");
|
|
12
12
|
|
|
@@ -213,6 +213,65 @@ function serializeCode(code) {
|
|
|
213
213
|
};
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
function getActivationPlatforms(serviceKey) {
|
|
217
|
+
if (serviceKey === "codex") return ["codex-cli"];
|
|
218
|
+
if (serviceKey === "claude") return ["claude-code"];
|
|
219
|
+
return [];
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function buildActivationData(serializedCode) {
|
|
223
|
+
const serviceKey = serializedCode.serviceKey;
|
|
224
|
+
const upstream = loadUpstreamConfig({ configPath: getUpstreamConfigPath() });
|
|
225
|
+
const serviceConfig = serializedCode.serviceConfig || {};
|
|
226
|
+
const baseUrl = trimTrailingSlash(
|
|
227
|
+
serializedCode.baseUrl ||
|
|
228
|
+
serializedCode.baseURL ||
|
|
229
|
+
serializedCode.url ||
|
|
230
|
+
serviceConfig.baseUrl ||
|
|
231
|
+
serviceConfig.baseURL ||
|
|
232
|
+
serviceConfig.url ||
|
|
233
|
+
getServiceBaseUrl(upstream, serviceKey) ||
|
|
234
|
+
upstream.baseUrl
|
|
235
|
+
);
|
|
236
|
+
const apiKey = String(
|
|
237
|
+
serializedCode.apiKey ||
|
|
238
|
+
serializedCode.key ||
|
|
239
|
+
serializedCode.token ||
|
|
240
|
+
serviceConfig.apiKey ||
|
|
241
|
+
serviceConfig.key ||
|
|
242
|
+
serviceConfig.token ||
|
|
243
|
+
upstream.apiKey ||
|
|
244
|
+
""
|
|
245
|
+
).trim();
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
code: serializedCode.code,
|
|
249
|
+
service: serializedCode.service,
|
|
250
|
+
serviceKey,
|
|
251
|
+
services: [serviceKey],
|
|
252
|
+
platforms: getActivationPlatforms(serviceKey),
|
|
253
|
+
allowedModels: serializedCode.allowedModels,
|
|
254
|
+
quota: serializedCode.quota,
|
|
255
|
+
expiresAt: serializedCode.expiresAt,
|
|
256
|
+
baseUrl,
|
|
257
|
+
apiKey,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function ensureActivationDataReady(res, activationData) {
|
|
262
|
+
if (activationData.baseUrl && activationData.apiKey) {
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
267
|
+
res.end(JSON.stringify({
|
|
268
|
+
success: false,
|
|
269
|
+
valid: false,
|
|
270
|
+
message: '上游服务未配置完整,请先在管理面板设置 NewAPI Base URL 和 API Key'
|
|
271
|
+
}));
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
|
|
216
275
|
function trimTrailingSlash(value) {
|
|
217
276
|
return String(value || "").trim().replace(/\/+$/, "");
|
|
218
277
|
}
|
|
@@ -865,6 +924,11 @@ const server = http.createServer((req, res) => {
|
|
|
865
924
|
return;
|
|
866
925
|
}
|
|
867
926
|
|
|
927
|
+
const activationData = buildActivationData(serializedCode);
|
|
928
|
+
if (!ensureActivationDataReady(res, activationData)) {
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
|
|
868
932
|
// 更新激活码状态
|
|
869
933
|
const updatedCode = codeDb.update(code.id, {
|
|
870
934
|
status: 'used',
|
|
@@ -886,12 +950,7 @@ const server = http.createServer((req, res) => {
|
|
|
886
950
|
success: true,
|
|
887
951
|
message: '激活成功',
|
|
888
952
|
data: {
|
|
889
|
-
|
|
890
|
-
service: serializeCode(updatedCode).service,
|
|
891
|
-
serviceKey: serializeCode(updatedCode).serviceKey,
|
|
892
|
-
allowedModels: serializeCode(updatedCode).allowedModels,
|
|
893
|
-
quota: updatedCode.quota,
|
|
894
|
-
expiresAt: updatedCode.expiresAt,
|
|
953
|
+
...buildActivationData(serializeCode(updatedCode)),
|
|
895
954
|
activatedAt: updatedCode.lastUsedAt
|
|
896
955
|
}
|
|
897
956
|
}));
|
|
@@ -1095,20 +1154,17 @@ const server = http.createServer((req, res) => {
|
|
|
1095
1154
|
return;
|
|
1096
1155
|
}
|
|
1097
1156
|
|
|
1157
|
+
const activationData = buildActivationData(serializedCode);
|
|
1158
|
+
if (!ensureActivationDataReady(res, activationData)) {
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1098
1162
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1099
1163
|
res.end(JSON.stringify({
|
|
1100
1164
|
success: true,
|
|
1101
1165
|
valid: true,
|
|
1102
1166
|
message: '验证成功',
|
|
1103
|
-
data:
|
|
1104
|
-
code: serializedCode.code,
|
|
1105
|
-
service: serializedCode.service,
|
|
1106
|
-
services: [serializedCode.serviceKey],
|
|
1107
|
-
platforms: serializedCode.serviceKey === 'codex' ? ['codex-cli'] : ['claude-code'],
|
|
1108
|
-
allowedModels: serializedCode.allowedModels,
|
|
1109
|
-
quota: serializedCode.quota,
|
|
1110
|
-
expiresAt: serializedCode.expiresAt
|
|
1111
|
-
}
|
|
1167
|
+
data: activationData
|
|
1112
1168
|
}));
|
|
1113
1169
|
return;
|
|
1114
1170
|
}
|
|
@@ -731,128 +731,6 @@ body.market-dark .market-auth-card::before {
|
|
|
731
731
|
color: var(--market-primary);
|
|
732
732
|
}
|
|
733
733
|
|
|
734
|
-
.market-service-card {
|
|
735
|
-
position: relative;
|
|
736
|
-
overflow: hidden;
|
|
737
|
-
border: 1px solid var(--market-line);
|
|
738
|
-
border-radius: 28px;
|
|
739
|
-
padding: 18px;
|
|
740
|
-
background:
|
|
741
|
-
radial-gradient(circle at 8% 0%, color-mix(in srgb, var(--market-primary) 14%, transparent), transparent 42%),
|
|
742
|
-
var(--market-panel);
|
|
743
|
-
box-shadow: var(--market-shadow-soft);
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
.market-service-head {
|
|
747
|
-
display: grid;
|
|
748
|
-
grid-template-columns: 44px 1fr auto;
|
|
749
|
-
gap: 12px;
|
|
750
|
-
align-items: center;
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
.market-service-icon {
|
|
754
|
-
display: inline-flex;
|
|
755
|
-
align-items: center;
|
|
756
|
-
justify-content: center;
|
|
757
|
-
width: 44px;
|
|
758
|
-
height: 44px;
|
|
759
|
-
border-radius: 16px;
|
|
760
|
-
color: #fff;
|
|
761
|
-
background: linear-gradient(135deg, var(--market-primary), var(--market-primary-3));
|
|
762
|
-
box-shadow: 0 14px 32px color-mix(in srgb, var(--market-primary) 24%, transparent);
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
.market-service-head p,
|
|
766
|
-
.market-service-head h3,
|
|
767
|
-
.market-service-copy {
|
|
768
|
-
margin: 0;
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
.market-service-head p {
|
|
772
|
-
color: var(--market-muted);
|
|
773
|
-
font-size: 12px;
|
|
774
|
-
font-weight: 900;
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
.market-service-head h3 {
|
|
778
|
-
margin-top: 3px;
|
|
779
|
-
color: var(--market-ink);
|
|
780
|
-
font-family: var(--market-headline);
|
|
781
|
-
font-size: 17px;
|
|
782
|
-
letter-spacing: -0.04em;
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
.market-port-badge {
|
|
786
|
-
display: inline-flex;
|
|
787
|
-
align-items: center;
|
|
788
|
-
gap: 6px;
|
|
789
|
-
height: 32px;
|
|
790
|
-
padding: 0 10px;
|
|
791
|
-
border: 1px solid var(--market-line);
|
|
792
|
-
border-radius: 999px;
|
|
793
|
-
color: var(--market-muted);
|
|
794
|
-
background: var(--market-panel-muted);
|
|
795
|
-
font-size: 12px;
|
|
796
|
-
font-weight: 900;
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
.market-service-copy {
|
|
800
|
-
margin-top: 14px;
|
|
801
|
-
color: var(--market-muted);
|
|
802
|
-
font-size: 13px;
|
|
803
|
-
line-height: 1.65;
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
.market-entry-grid {
|
|
807
|
-
display: grid;
|
|
808
|
-
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
809
|
-
gap: 10px;
|
|
810
|
-
margin-top: 16px;
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
.market-entry-card {
|
|
814
|
-
display: grid;
|
|
815
|
-
gap: 5px;
|
|
816
|
-
min-height: 92px;
|
|
817
|
-
border: 1px solid var(--market-line);
|
|
818
|
-
border-radius: 18px;
|
|
819
|
-
padding: 13px;
|
|
820
|
-
color: var(--market-ink);
|
|
821
|
-
background: color-mix(in srgb, var(--market-panel-strong) 78%, transparent);
|
|
822
|
-
text-decoration: none;
|
|
823
|
-
transition: transform 0.18s ease, border-color 0.18s ease, background 0.18s ease, box-shadow 0.18s ease;
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
.market-entry-card .material-symbols-outlined {
|
|
827
|
-
width: 30px;
|
|
828
|
-
height: 30px;
|
|
829
|
-
border-radius: 12px;
|
|
830
|
-
display: inline-flex;
|
|
831
|
-
align-items: center;
|
|
832
|
-
justify-content: center;
|
|
833
|
-
color: var(--market-primary);
|
|
834
|
-
background: color-mix(in srgb, var(--market-primary) 12%, transparent);
|
|
835
|
-
font-size: 18px;
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
.market-entry-card strong {
|
|
839
|
-
font-size: 13px;
|
|
840
|
-
font-weight: 900;
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
.market-entry-card small {
|
|
844
|
-
color: var(--market-muted);
|
|
845
|
-
font-size: 12px;
|
|
846
|
-
font-weight: 700;
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
.market-entry-card:hover {
|
|
850
|
-
transform: translateY(-2px);
|
|
851
|
-
border-color: color-mix(in srgb, var(--market-primary) 42%, var(--market-line));
|
|
852
|
-
background: color-mix(in srgb, var(--market-primary) 8%, var(--market-panel-strong));
|
|
853
|
-
box-shadow: var(--market-shadow-soft);
|
|
854
|
-
}
|
|
855
|
-
|
|
856
734
|
.market-result-list {
|
|
857
735
|
display: grid;
|
|
858
736
|
gap: 10px;
|
package/frontend/index.html
CHANGED
|
@@ -55,9 +55,9 @@
|
|
|
55
55
|
<section class="market-hero" aria-labelledby="hero-title">
|
|
56
56
|
<div class="market-hero-main">
|
|
57
57
|
<div class="market-kicker"><span class="market-kicker-dot"></span> CLI 激活与配额管理</div>
|
|
58
|
-
<h1 id="hero-title" class="market-title"
|
|
58
|
+
<h1 id="hero-title" class="market-title"><span>Fog Coding</span><br />网关入口</h1>
|
|
59
59
|
<p class="market-copy">
|
|
60
|
-
|
|
60
|
+
连接 Codex、Claude 等服务,处理激活码、用户和额度,一站完成。
|
|
61
61
|
</p>
|
|
62
62
|
|
|
63
63
|
<label class="market-search" aria-label="搜索功能入口">
|
|
@@ -103,40 +103,14 @@
|
|
|
103
103
|
</div>
|
|
104
104
|
</div>
|
|
105
105
|
|
|
106
|
-
<div class="market-
|
|
107
|
-
<div class="market-
|
|
108
|
-
<span class="market-
|
|
109
|
-
<
|
|
110
|
-
<p>本地服务</p>
|
|
111
|
-
<h3>选择要进入的工作区</h3>
|
|
112
|
-
</div>
|
|
113
|
-
<span class="market-port-badge"><span class="market-kicker-dot"></span> :34020</span>
|
|
106
|
+
<div class="market-panel" style="border-radius: 26px; padding: 18px;">
|
|
107
|
+
<div class="market-card-footer">
|
|
108
|
+
<span class="market-tag">本地服务</span>
|
|
109
|
+
<span class="market-status-pill"><span class="market-kicker-dot"></span> 34020</span>
|
|
114
110
|
</div>
|
|
115
|
-
<p class="market-
|
|
116
|
-
Web
|
|
111
|
+
<p class="market-mini-copy" style="margin-top: 14px; font-size: 14px; line-height: 1.7;">
|
|
112
|
+
本地 Web 服务默认运行在 34020 端口,提供首页、用户中心、管理中心和激活入口。
|
|
117
113
|
</p>
|
|
118
|
-
<div class="market-entry-grid" aria-label="本地服务快捷入口">
|
|
119
|
-
<a class="market-entry-card" href="/">
|
|
120
|
-
<span class="material-symbols-outlined">home</span>
|
|
121
|
-
<strong>首页</strong>
|
|
122
|
-
<small>查看入口总览</small>
|
|
123
|
-
</a>
|
|
124
|
-
<a class="market-entry-card" href="/user/">
|
|
125
|
-
<span class="material-symbols-outlined">person</span>
|
|
126
|
-
<strong>用户中心</strong>
|
|
127
|
-
<small>用量与配额</small>
|
|
128
|
-
</a>
|
|
129
|
-
<a class="market-entry-card" href="/admin/">
|
|
130
|
-
<span class="material-symbols-outlined">admin_panel_settings</span>
|
|
131
|
-
<strong>管理中心</strong>
|
|
132
|
-
<small>用户与 CDK</small>
|
|
133
|
-
</a>
|
|
134
|
-
<a class="market-entry-card" href="/activate.html">
|
|
135
|
-
<span class="material-symbols-outlined">bolt</span>
|
|
136
|
-
<strong>激活入口</strong>
|
|
137
|
-
<small>绑定服务</small>
|
|
138
|
-
</a>
|
|
139
|
-
</div>
|
|
140
114
|
</div>
|
|
141
115
|
</aside>
|
|
142
116
|
</section>
|