fogact 1.1.8 → 1.1.9

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 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 this check.
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 最新版本;检测到旧版本会先更新,再进入菜单。需要跳过检查时可设置 `FOGACT_SKIP_UPDATE=1`。
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
- code: updatedCode.code,
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;
@@ -103,40 +103,14 @@
103
103
  </div>
104
104
  </div>
105
105
 
106
- <div class="market-service-card">
107
- <div class="market-service-head">
108
- <span class="market-service-icon material-symbols-outlined">conversion_path</span>
109
- <div>
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-service-copy">
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>
@@ -4,8 +4,9 @@ const packageJson = require("../../package.json");
4
4
  const https = require("https");
5
5
  const http = require("http");
6
6
 
7
- // 支持环境变量配置 API 地址
8
- const API_BASE = process.env.FOGACT_API_BASE || "http://localhost:34020";
7
+ // 支持环境变量覆盖 API 地址;默认连接公网 FogAct 面板。
8
+ const DEFAULT_API_BASE = "https://cliproxy.fogidc.com";
9
+ const API_BASE = process.env.FOGACT_API_BASE || process.env.CLIPROXY_API_BASE || DEFAULT_API_BASE;
9
10
 
10
11
  function makeRequest(path, options = {}) {
11
12
  return new Promise((resolve, reject) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fogact",
3
- "version": "1.1.8",
3
+ "version": "1.1.9",
4
4
  "description": "FogAct activation helper for Claude Code and Codex",
5
5
  "keywords": [
6
6
  "fogact",