fogact 1.1.6 → 1.1.8
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 +6 -4
- package/README.zh-CN.md +6 -4
- package/bin/web-server.js +11 -3
- package/frontend/activate.html +1 -1
- package/frontend/admin/admin-panel-v2.js +2 -2
- package/frontend/admin/index.html +1 -1
- package/frontend/assets/market-ui.css +122 -134
- package/frontend/color-test.html +1 -1
- package/frontend/index.html +33 -14
- 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 +1 -1
- package/install.sh +25 -25
- package/lib/commands/activate.js +2 -2
- package/lib/commands/test.js +1 -1
- package/lib/config/codex.js +28 -22
- package/lib/config/upstream.js +1 -1
- package/lib/index.js +122 -2
- package/lib/platforms/editor-codex.js +2 -2
- package/lib/services/activation-orchestrator.js +73 -55
- package/lib/services/backup-service.js +1 -2
- package/lib/services/{cliproxy-api.js → fogact-api.js} +5 -4
- package/lib/services/newapi.js +2 -1
- package/lib/services/node-service.js +1 -1
- package/package.json +2 -9
package/frontend/user/index.html
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<script>
|
|
17
17
|
// 阻塞式主题初始化 — 防止 FOUC + 设置内联背景色
|
|
18
18
|
;(function () {
|
|
19
|
-
var t = localStorage.getItem('fogact_theme') ||
|
|
19
|
+
var t = localStorage.getItem('fogact_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) {
|
package/install.sh
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
set -eu
|
|
3
3
|
|
|
4
|
-
PACKAGE_NAME="${
|
|
5
|
-
GITHUB_REPO="${
|
|
6
|
-
GIT_REF="${
|
|
7
|
-
INSTALL_METHOD="${
|
|
8
|
-
INSTALL_DIR="${
|
|
9
|
-
SERVICE="${
|
|
10
|
-
CODE="${
|
|
11
|
-
API_KEY="${NEWAPI_API_KEY:-${
|
|
12
|
-
BASE_URL="${NEWAPI_BASE_URL:-${
|
|
13
|
-
|
|
14
|
-
PLATFORMS="${
|
|
15
|
-
RUN_WEB="${
|
|
16
|
-
WEB_PORT="${PORT:-${
|
|
17
|
-
ADMIN_PASSWORD_VALUE="${ADMIN_PASSWORD:-${
|
|
18
|
-
SKIP_VERIFY="${
|
|
19
|
-
ALL_PLATFORMS="${
|
|
20
|
-
NO_ACTIVATE="${
|
|
21
|
-
NO_REDEEM="${
|
|
22
|
-
CREATE_SYSTEMD="${
|
|
4
|
+
PACKAGE_NAME="${FOGACT_PACKAGE:-fogact}"
|
|
5
|
+
GITHUB_REPO="${FOGACT_GITHUB_REPO:-FogMaly/fogact}"
|
|
6
|
+
GIT_REF="${FOGACT_GIT_REF:-main}"
|
|
7
|
+
INSTALL_METHOD="${FOGACT_INSTALL_METHOD:-npm}"
|
|
8
|
+
INSTALL_DIR="${FOGACT_INSTALL_DIR:-}"
|
|
9
|
+
SERVICE="${FOGACT_SERVICE:-}"
|
|
10
|
+
CODE="${FOGACT_CODE:-}"
|
|
11
|
+
API_KEY="${NEWAPI_API_KEY:-${FOGACT_API_KEY:-}}"
|
|
12
|
+
BASE_URL="${NEWAPI_BASE_URL:-${FOGACT_BASE_URL:-}}"
|
|
13
|
+
FOGACT_API_BASE_VALUE="${FOGACT_API_BASE:-}"
|
|
14
|
+
PLATFORMS="${FOGACT_PLATFORMS:-}"
|
|
15
|
+
RUN_WEB="${FOGACT_RUN_WEB:-0}"
|
|
16
|
+
WEB_PORT="${PORT:-${FOGACT_WEB_PORT:-34020}}"
|
|
17
|
+
ADMIN_PASSWORD_VALUE="${ADMIN_PASSWORD:-${FOGACT_ADMIN_PASSWORD:-}}"
|
|
18
|
+
SKIP_VERIFY="${FOGACT_SKIP_VERIFY:-0}"
|
|
19
|
+
ALL_PLATFORMS="${FOGACT_ALL:-0}"
|
|
20
|
+
NO_ACTIVATE="${FOGACT_NO_ACTIVATE:-0}"
|
|
21
|
+
NO_REDEEM="${FOGACT_NO_REDEEM:-0}"
|
|
22
|
+
CREATE_SYSTEMD="${FOGACT_SYSTEMD:-0}"
|
|
23
23
|
|
|
24
24
|
log() { printf '%s\n' "==> $*"; }
|
|
25
25
|
warn() { printf '%s\n' "WARN: $*" >&2; }
|
|
@@ -40,7 +40,7 @@ Options:
|
|
|
40
40
|
--code <code> Activation / redeem code
|
|
41
41
|
--api-key <key> NewAPI key for direct activation
|
|
42
42
|
--base-url <url> NewAPI base URL for direct activation
|
|
43
|
-
--
|
|
43
|
+
--fogact-api-base <url> Activation backend URL for code mode
|
|
44
44
|
--platforms <ids> Comma-separated target platform ids
|
|
45
45
|
--all Configure all creatable optional platforms
|
|
46
46
|
--skip-verify Skip NewAPI /v1/models verification
|
|
@@ -53,9 +53,9 @@ Options:
|
|
|
53
53
|
-h, --help Show help
|
|
54
54
|
|
|
55
55
|
Environment variables mirror the options:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
FOGACT_PACKAGE=fogact, FOGACT_SERVICE, FOGACT_CODE, NEWAPI_BASE_URL, NEWAPI_API_KEY,
|
|
57
|
+
FOGACT_API_BASE, FOGACT_PLATFORMS, FOGACT_ALL=1,
|
|
58
|
+
FOGACT_SKIP_VERIFY=1, FOGACT_RUN_WEB=1, FOGACT_SYSTEMD=1
|
|
59
59
|
EOF
|
|
60
60
|
}
|
|
61
61
|
|
|
@@ -65,7 +65,7 @@ while [ "$#" -gt 0 ]; do
|
|
|
65
65
|
--code) CODE="${2:-}"; shift 2 ;;
|
|
66
66
|
--api-key) API_KEY="${2:-}"; shift 2 ;;
|
|
67
67
|
--base-url) BASE_URL="${2:-}"; shift 2 ;;
|
|
68
|
-
--
|
|
68
|
+
--fogact-api-base) FOGACT_API_BASE_VALUE="${2:-}"; shift 2 ;;
|
|
69
69
|
--platforms) PLATFORMS="${2:-}"; shift 2 ;;
|
|
70
70
|
--all) ALL_PLATFORMS=1; shift ;;
|
|
71
71
|
--skip-verify) SKIP_VERIFY=1; shift ;;
|
|
@@ -337,7 +337,7 @@ run_activation() {
|
|
|
337
337
|
|
|
338
338
|
if [ -n "$BASE_URL" ]; then export NEWAPI_BASE_URL="$BASE_URL"; fi
|
|
339
339
|
if [ -n "$API_KEY" ]; then export NEWAPI_API_KEY="$API_KEY"; fi
|
|
340
|
-
if [ -n "$
|
|
340
|
+
if [ -n "$FOGACT_API_BASE_VALUE" ]; then export FOGACT_API_BASE="$FOGACT_API_BASE_VALUE"; fi
|
|
341
341
|
|
|
342
342
|
set -- wizard --yes
|
|
343
343
|
if [ -n "$SERVICE" ]; then set -- "$@" --service "$SERVICE"; fi
|
package/lib/commands/activate.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const prompts = require("prompts");
|
|
4
|
-
const { verifyActivationCode, getNodes } = require("../services/
|
|
4
|
+
const { verifyActivationCode, getNodes } = require("../services/fogact-api");
|
|
5
5
|
const { testNodes, selectBestNode, formatNodeResults } = require("../services/node-service");
|
|
6
6
|
const { createBackup } = require("../services/backup-service");
|
|
7
7
|
const { writeClaudeConfig, getClaudeConfigPath } = require("../config/claude");
|
|
@@ -10,7 +10,7 @@ const { runActivationWizard, runNewApiActivation } = require("../services/activa
|
|
|
10
10
|
|
|
11
11
|
async function runLegacyCodeActivation(options = {}) {
|
|
12
12
|
console.log("");
|
|
13
|
-
console.log("===
|
|
13
|
+
console.log("=== FogAct Activation (Code Mode) ===");
|
|
14
14
|
console.log("");
|
|
15
15
|
|
|
16
16
|
let service = options.service;
|
package/lib/commands/test.js
CHANGED
package/lib/config/codex.js
CHANGED
|
@@ -4,10 +4,13 @@ const fs = require("fs");
|
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const os = require("os");
|
|
6
6
|
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
7
|
+
const FOGACT_PROVIDER = "fogact";
|
|
8
|
+
const FOGACT_MODEL = "gpt-5.3-codex";
|
|
9
|
+
const LEGACY_PROVIDER = ["yu", "nyi"].join("");
|
|
10
|
+
const LEGACY_COMMENT = ["# ", "云", "驿", " API 中转配置"].join("");
|
|
11
|
+
const LEGACY_AUTH_KEY = ["YU", "NYI", "_API_KEY"].join("");
|
|
12
|
+
const BLOCK_START = "# >>> fogact codex >>>";
|
|
13
|
+
const BLOCK_END = "# <<< fogact codex <<<";
|
|
11
14
|
|
|
12
15
|
function getCodexDir() {
|
|
13
16
|
return path.join(os.homedir(), ".codex");
|
|
@@ -53,12 +56,12 @@ function readCodexAuth() {
|
|
|
53
56
|
}
|
|
54
57
|
}
|
|
55
58
|
|
|
56
|
-
function
|
|
59
|
+
function stripFogactBlock(content) {
|
|
57
60
|
const lines = String(content || "").split(/\r?\n/);
|
|
58
61
|
const kept = [];
|
|
59
62
|
let inBlock = false;
|
|
60
63
|
let currentSection = null;
|
|
61
|
-
let
|
|
64
|
+
let inFogactProvider = false;
|
|
62
65
|
|
|
63
66
|
for (const line of lines) {
|
|
64
67
|
const trimmed = line.trim();
|
|
@@ -77,22 +80,23 @@ function stripYunyiBlock(content) {
|
|
|
77
80
|
const section = trimmed.match(/^\[([^\]]+)\]$/);
|
|
78
81
|
if (section) {
|
|
79
82
|
currentSection = section[1].trim();
|
|
80
|
-
|
|
81
|
-
if (
|
|
83
|
+
inFogactProvider = [`model_providers.${FOGACT_PROVIDER}`, `model_providers.${LEGACY_PROVIDER}`].some((prefix) => currentSection.toLowerCase().startsWith(prefix));
|
|
84
|
+
if (inFogactProvider) {
|
|
82
85
|
continue;
|
|
83
86
|
}
|
|
84
87
|
kept.push(line);
|
|
85
88
|
continue;
|
|
86
89
|
}
|
|
87
90
|
|
|
88
|
-
if (
|
|
91
|
+
if (inFogactProvider) {
|
|
89
92
|
continue;
|
|
90
93
|
}
|
|
91
94
|
|
|
92
|
-
const
|
|
95
|
+
const isRootFogactSetting =
|
|
93
96
|
!currentSection &&
|
|
94
97
|
(
|
|
95
|
-
trimmed === "#
|
|
98
|
+
trimmed === "# FogAct API 中转配置" ||
|
|
99
|
+
trimmed === LEGACY_COMMENT ||
|
|
96
100
|
/^#?\s*model_provider\s*=/.test(trimmed) ||
|
|
97
101
|
/^#?\s*model\s*=/.test(trimmed) ||
|
|
98
102
|
/^#?\s*model_reasoning_effort\s*=/.test(trimmed) ||
|
|
@@ -100,7 +104,7 @@ function stripYunyiBlock(content) {
|
|
|
100
104
|
/^#?\s*preferred_auth_method\s*=/.test(trimmed)
|
|
101
105
|
);
|
|
102
106
|
|
|
103
|
-
if (!
|
|
107
|
+
if (!isRootFogactSetting) {
|
|
104
108
|
kept.push(line);
|
|
105
109
|
}
|
|
106
110
|
}
|
|
@@ -109,17 +113,17 @@ function stripYunyiBlock(content) {
|
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
function buildCodexConfig(existingContent, baseUrl, apiKey) {
|
|
112
|
-
const cleaned =
|
|
113
|
-
const
|
|
116
|
+
const cleaned = stripFogactBlock(existingContent);
|
|
117
|
+
const fogactConfig = [
|
|
114
118
|
BLOCK_START,
|
|
115
|
-
`model_provider = "${
|
|
116
|
-
`model = "${
|
|
119
|
+
`model_provider = "${FOGACT_PROVIDER}"`,
|
|
120
|
+
`model = "${FOGACT_MODEL}"`,
|
|
117
121
|
'model_reasoning_effort = "high"',
|
|
118
122
|
"disable_response_storage = true",
|
|
119
123
|
'preferred_auth_method = "apikey"',
|
|
120
124
|
"",
|
|
121
|
-
`[model_providers.${
|
|
122
|
-
`name = "${
|
|
125
|
+
`[model_providers.${FOGACT_PROVIDER}]`,
|
|
126
|
+
`name = "${FOGACT_PROVIDER}"`,
|
|
123
127
|
`base_url = "${baseUrl}"`,
|
|
124
128
|
'wire_api = "responses"',
|
|
125
129
|
`experimental_bearer_token = "${apiKey}"`,
|
|
@@ -127,7 +131,7 @@ function buildCodexConfig(existingContent, baseUrl, apiKey) {
|
|
|
127
131
|
BLOCK_END,
|
|
128
132
|
].join("\n");
|
|
129
133
|
|
|
130
|
-
const result = cleaned ? `${
|
|
134
|
+
const result = cleaned ? `${fogactConfig}\n\n${cleaned}` : fogactConfig;
|
|
131
135
|
return result.endsWith("\n") ? result : `${result}\n`;
|
|
132
136
|
}
|
|
133
137
|
|
|
@@ -139,7 +143,9 @@ function writeCodexConfig(apiKey, baseUrl) {
|
|
|
139
143
|
const config = buildCodexConfig(readCodexConfig(), baseUrl, apiKey);
|
|
140
144
|
fs.writeFileSync(configPath, config, "utf8");
|
|
141
145
|
|
|
142
|
-
const
|
|
146
|
+
const auth = readCodexAuth();
|
|
147
|
+
delete auth.FOGACT_API_KEY;
|
|
148
|
+
delete auth[LEGACY_AUTH_KEY];
|
|
143
149
|
fs.writeFileSync(
|
|
144
150
|
authPath,
|
|
145
151
|
JSON.stringify({ ...auth, auth_mode: "apikey", OPENAI_API_KEY: apiKey }, null, 2),
|
|
@@ -152,13 +158,13 @@ function writeCodexConfig(apiKey, baseUrl) {
|
|
|
152
158
|
module.exports = {
|
|
153
159
|
BLOCK_START,
|
|
154
160
|
BLOCK_END,
|
|
155
|
-
|
|
161
|
+
FOGACT_MODEL,
|
|
156
162
|
getCodexDir,
|
|
157
163
|
getCodexConfigPath,
|
|
158
164
|
getCodexAuthPath,
|
|
159
165
|
readCodexConfig,
|
|
160
166
|
readCodexAuth,
|
|
161
|
-
|
|
167
|
+
stripFogactBlock,
|
|
162
168
|
buildCodexConfig,
|
|
163
169
|
writeCodexConfig,
|
|
164
170
|
};
|
package/lib/config/upstream.js
CHANGED
|
@@ -24,7 +24,7 @@ function trimTrailingSlash(value) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
function loadUpstreamConfig(options = {}) {
|
|
27
|
-
const configPath = options.configPath || process.env.
|
|
27
|
+
const configPath = options.configPath || process.env.FOGACT_UPSTREAM_CONFIG || DEFAULT_CONFIG_PATH;
|
|
28
28
|
const fileConfig = readJsonFile(configPath);
|
|
29
29
|
const baseUrl = trimTrailingSlash(
|
|
30
30
|
process.env.NEWAPI_BASE_URL ||
|
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");
|
|
@@ -15,6 +17,120 @@ const MENU_CHOICES = [
|
|
|
15
17
|
{ title: "4. 退出", value: "exit" },
|
|
16
18
|
];
|
|
17
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
|
+
|
|
18
134
|
function displayWidth(value) {
|
|
19
135
|
return Array.from(value).reduce((width, char) => {
|
|
20
136
|
return width + (char.charCodeAt(0) > 0xff ? 2 : 1);
|
|
@@ -188,7 +304,7 @@ function buildProgram() {
|
|
|
188
304
|
|
|
189
305
|
program
|
|
190
306
|
.command("wizard")
|
|
191
|
-
.description("Open
|
|
307
|
+
.description("Open FogAct activation wizard")
|
|
192
308
|
.option("-s, --service <service>", "target service: claude or codex")
|
|
193
309
|
.option("-k, --api-key <apiKey>", "NewAPI key")
|
|
194
310
|
.option("-c, --code <code>", "activation / redeem code")
|
|
@@ -202,7 +318,7 @@ function buildProgram() {
|
|
|
202
318
|
|
|
203
319
|
program
|
|
204
320
|
.command("test")
|
|
205
|
-
.description("Test
|
|
321
|
+
.description("Test FogAct nodes")
|
|
206
322
|
.action(runTestCommand);
|
|
207
323
|
|
|
208
324
|
program
|
|
@@ -230,6 +346,8 @@ function buildProgram() {
|
|
|
230
346
|
}
|
|
231
347
|
|
|
232
348
|
async function runCli(argv = process.argv) {
|
|
349
|
+
await ensureLatestVersion(argv);
|
|
350
|
+
|
|
233
351
|
const args = argv.slice(2).filter((arg) => arg !== "--help" && arg !== "-h");
|
|
234
352
|
|
|
235
353
|
if (args.length === 0) {
|
|
@@ -243,6 +361,8 @@ async function runCli(argv = process.argv) {
|
|
|
243
361
|
|
|
244
362
|
module.exports = {
|
|
245
363
|
buildProgram,
|
|
364
|
+
ensureLatestVersion,
|
|
365
|
+
isNewerVersion,
|
|
246
366
|
runCli,
|
|
247
367
|
runInteractiveMenu,
|
|
248
368
|
runToolsMenu,
|
|
@@ -52,7 +52,7 @@ function findWebviewAsset(extensionDir) {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
function isPatched(content) {
|
|
55
|
-
return content.includes("email:'
|
|
55
|
+
return content.includes("email:'FogAct'") || content.includes('email:"FogAct"');
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
function patchCodexExtension(editor) {
|
|
@@ -86,7 +86,7 @@ function patchCodexExtension(editor) {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
const pattern = /(\w+)=\{isLoading:(\w+),openAIAuth:(\w+),isCopilotApiAvailable:(\w+),authMethod:(\w+),requiresAuth:(\w+),userId:(\w+),accountId:(\w+),email:(\w+),planAtLogin:(\w+),setAuthMethod:(\w+)\}/;
|
|
89
|
-
const replacement = "$1={isLoading:$2,openAIAuth:$3,isCopilotApiAvailable:$4,authMethod:'chatgpt',requiresAuth:$6,userId:$7,accountId:$8,email:'
|
|
89
|
+
const replacement = "$1={isLoading:$2,openAIAuth:$3,isCopilotApiAvailable:$4,authMethod:'chatgpt',requiresAuth:$6,userId:$7,accountId:$8,email:'FogAct',planAtLogin:$10,setAuthMethod:$11}";
|
|
90
90
|
|
|
91
91
|
if (!pattern.test(content)) {
|
|
92
92
|
return {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const prompts = require("prompts");
|
|
4
|
-
const { detectPlatforms } = require("../platforms");
|
|
4
|
+
const { detectPlatforms, getPlatforms } = require("../platforms");
|
|
5
5
|
const { loadUpstreamConfig } = require("../config/upstream");
|
|
6
6
|
const { createActivationBackup } = require("./backup-service");
|
|
7
|
-
const { inspectActivationCode, redeemActivationCode } = require("./
|
|
7
|
+
const { inspectActivationCode, redeemActivationCode } = require("./fogact-api");
|
|
8
8
|
const { maskKey, verifyNewApiKey } = require("./newapi");
|
|
9
9
|
|
|
10
10
|
const SUPPORTED_SERVICES = ["codex", "claude"];
|
|
@@ -79,10 +79,42 @@ function normalizePlatformIds(...values) {
|
|
|
79
79
|
return ids;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
function inferServicesFromPlatformIds(platformIds) {
|
|
83
|
+
const ids = normalizePlatformIds(platformIds);
|
|
84
|
+
if (!ids.length) {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const platformServices = new Map(getPlatforms().map((platform) => [platform.id, platform.services]));
|
|
89
|
+
let commonServices = null;
|
|
90
|
+
|
|
91
|
+
for (const id of ids) {
|
|
92
|
+
const services = platformServices.get(id);
|
|
93
|
+
if (!services || !services.length) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
commonServices = commonServices
|
|
97
|
+
? commonServices.filter((service) => services.includes(service))
|
|
98
|
+
: [...services];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return commonServices || [];
|
|
102
|
+
}
|
|
103
|
+
|
|
82
104
|
function normalizeEntitlement(raw = {}, fallbackServices = []) {
|
|
83
105
|
const source = raw && typeof raw === "object" ? raw : {};
|
|
84
106
|
const data = source.data && typeof source.data === "object" ? source.data : source;
|
|
85
107
|
const capabilities = data.capabilities || data.capability || data.entitlement || data.ability || {};
|
|
108
|
+
const platforms = normalizePlatformIds(
|
|
109
|
+
data.platforms,
|
|
110
|
+
data.platform,
|
|
111
|
+
data.targets,
|
|
112
|
+
data.target,
|
|
113
|
+
capabilities.platforms,
|
|
114
|
+
capabilities.platform,
|
|
115
|
+
capabilities.targets,
|
|
116
|
+
capabilities.target
|
|
117
|
+
);
|
|
86
118
|
const services = normalizeServices(
|
|
87
119
|
data.services,
|
|
88
120
|
data.service,
|
|
@@ -91,6 +123,8 @@ function normalizeEntitlement(raw = {}, fallbackServices = []) {
|
|
|
91
123
|
data.scopes,
|
|
92
124
|
data.scope,
|
|
93
125
|
data.abilities,
|
|
126
|
+
data.provider,
|
|
127
|
+
data.type,
|
|
94
128
|
capabilities.services,
|
|
95
129
|
capabilities.service,
|
|
96
130
|
capabilities.products,
|
|
@@ -98,17 +132,10 @@ function normalizeEntitlement(raw = {}, fallbackServices = []) {
|
|
|
98
132
|
capabilities.scopes,
|
|
99
133
|
capabilities.scope,
|
|
100
134
|
capabilities.abilities,
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
data.platform,
|
|
106
|
-
data.targets,
|
|
107
|
-
data.target,
|
|
108
|
-
capabilities.platforms,
|
|
109
|
-
capabilities.platform,
|
|
110
|
-
capabilities.targets,
|
|
111
|
-
capabilities.target
|
|
135
|
+
capabilities.provider,
|
|
136
|
+
capabilities.type,
|
|
137
|
+
fallbackServices,
|
|
138
|
+
inferServicesFromPlatformIds(platforms)
|
|
112
139
|
);
|
|
113
140
|
|
|
114
141
|
return {
|
|
@@ -181,7 +208,9 @@ function parsePlatformIds(value) {
|
|
|
181
208
|
return normalizePlatformIds(value);
|
|
182
209
|
}
|
|
183
210
|
|
|
184
|
-
async function promptService(defaultService, entitlement = normalizeEntitlement()) {
|
|
211
|
+
async function promptService(defaultService, entitlement = normalizeEntitlement(), options = {}) {
|
|
212
|
+
const allowPrompt = options.allowPrompt !== false;
|
|
213
|
+
|
|
185
214
|
if (defaultService) {
|
|
186
215
|
const normalized = normalizeService(defaultService);
|
|
187
216
|
if (!SUPPORTED_SERVICES.includes(normalized)) {
|
|
@@ -190,21 +219,34 @@ async function promptService(defaultService, entitlement = normalizeEntitlement(
|
|
|
190
219
|
if (!isServiceAllowed(entitlement, normalized)) {
|
|
191
220
|
throw new Error(`当前激活码不支持 ${getServiceLabel(normalized)}`);
|
|
192
221
|
}
|
|
222
|
+
console.log(`能力范围: ${getServiceLabel(normalized)}`);
|
|
193
223
|
return normalized;
|
|
194
224
|
}
|
|
195
225
|
|
|
196
|
-
const allowedServices = entitlement.services.length ? entitlement.services :
|
|
226
|
+
const allowedServices = entitlement.services.length ? entitlement.services : [];
|
|
197
227
|
if (allowedServices.length === 1) {
|
|
198
228
|
console.log(`能力范围: ${getServiceLabel(allowedServices[0])}`);
|
|
199
229
|
return allowedServices[0];
|
|
200
230
|
}
|
|
201
231
|
|
|
232
|
+
if (!allowPrompt) {
|
|
233
|
+
if (allowedServices.length > 1) {
|
|
234
|
+
const service = allowedServices[0];
|
|
235
|
+
const labels = allowedServices.map(getServiceLabel).join(" / ");
|
|
236
|
+
console.log(`能力范围: ${labels},本次自动激活 ${getServiceLabel(service)}`);
|
|
237
|
+
return service;
|
|
238
|
+
}
|
|
239
|
+
console.log("✗ 激活码没有返回 Codex / Claude 能力,无法自动识别。请联系管理员重新生成激活码。");
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const promptServices = allowedServices.length ? allowedServices : SUPPORTED_SERVICES;
|
|
202
244
|
const response = await prompts({
|
|
203
245
|
type: "select",
|
|
204
246
|
name: "service",
|
|
205
247
|
message: "请选择要激活的能力",
|
|
206
248
|
hint: "↑↓ 选择,回车确认",
|
|
207
|
-
choices:
|
|
249
|
+
choices: promptServices.map((service) => ({ title: getServiceLabel(service), value: service })),
|
|
208
250
|
initial: 0,
|
|
209
251
|
}, { onCancel: () => false });
|
|
210
252
|
|
|
@@ -423,19 +465,8 @@ async function resolveCodeCredential(options, upstream) {
|
|
|
423
465
|
console.log("正在读取激活码能力...");
|
|
424
466
|
const inspection = await inspectActivationCode(code);
|
|
425
467
|
if (!inspection.valid) {
|
|
426
|
-
console.log(
|
|
427
|
-
|
|
428
|
-
return { cancelled: true };
|
|
429
|
-
}
|
|
430
|
-
const response = await prompts({
|
|
431
|
-
type: "confirm",
|
|
432
|
-
name: "fallback",
|
|
433
|
-
message: "是否按手动能力选择继续?",
|
|
434
|
-
initial: false,
|
|
435
|
-
}, { onCancel: () => false });
|
|
436
|
-
if (!response.fallback) {
|
|
437
|
-
return { cancelled: true };
|
|
438
|
-
}
|
|
468
|
+
console.log(`✗ 无法读取激活码能力: ${inspection.error || "接口未返回有效信息"}`);
|
|
469
|
+
return { cancelled: true };
|
|
439
470
|
}
|
|
440
471
|
|
|
441
472
|
const entitlement = normalizeEntitlement(inspection, options.service ? [options.service] : []);
|
|
@@ -580,28 +611,7 @@ async function runNewApiActivation(options = {}) {
|
|
|
580
611
|
async function runActivationWizard(options = {}) {
|
|
581
612
|
printBanner();
|
|
582
613
|
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
|
-
|
|
600
|
-
const credentialType = await promptCredentialType(options, baseUpstream);
|
|
601
|
-
if (!credentialType) {
|
|
602
|
-
console.log("已取消。");
|
|
603
|
-
return { success: false, cancelled: true };
|
|
604
|
-
}
|
|
614
|
+
const credentialType = !options.code && options.apiKey ? "api-key" : "code";
|
|
605
615
|
|
|
606
616
|
const credential = credentialType === "code"
|
|
607
617
|
? await resolveCodeCredential(options, baseUpstream)
|
|
@@ -618,6 +628,12 @@ async function runActivationWizard(options = {}) {
|
|
|
618
628
|
return { success: false, cancelled: true };
|
|
619
629
|
}
|
|
620
630
|
|
|
631
|
+
const service = await promptService(options.service, credential.entitlement, { allowPrompt: credentialType === "api-key" });
|
|
632
|
+
if (!service) {
|
|
633
|
+
console.log("已取消。");
|
|
634
|
+
return { success: false, cancelled: true };
|
|
635
|
+
}
|
|
636
|
+
|
|
621
637
|
console.log("");
|
|
622
638
|
if (credentialType === "api-key") {
|
|
623
639
|
const verification = await verifyCredential(upstream, credential.apiKey, options);
|
|
@@ -631,14 +647,16 @@ async function runActivationWizard(options = {}) {
|
|
|
631
647
|
const allDetectedPlatforms = detectPlatforms(service);
|
|
632
648
|
const allowedPlatforms = allDetectedPlatforms.filter((entry) => isPlatformAllowed(entry, credential.entitlement, service));
|
|
633
649
|
const blockedPlatforms = allDetectedPlatforms.filter((entry) => !allowedPlatforms.includes(entry));
|
|
634
|
-
const initialTargetIds = new Set(initialTargets.map(({ platform }) => platform.id));
|
|
635
650
|
|
|
636
|
-
|
|
651
|
+
console.log("");
|
|
652
|
+
printDetection(service, allowedPlatforms, blockedPlatforms);
|
|
653
|
+
|
|
654
|
+
const targets = await selectPlatforms(allowedPlatforms, options);
|
|
637
655
|
if (targets.length === 0) {
|
|
638
|
-
console.log("
|
|
656
|
+
console.log("没有选择任何平台,已取消。");
|
|
639
657
|
return { success: false, cancelled: true };
|
|
640
658
|
}
|
|
641
|
-
const skipped =
|
|
659
|
+
const skipped = allowedPlatforms.filter((entry) => !targets.includes(entry)).concat(blockedPlatforms);
|
|
642
660
|
|
|
643
661
|
printPlan(service, upstream, credential.apiKey, targets, skipped);
|
|
644
662
|
if (!(await confirmActivation(Boolean(options.yes || options.auto)))) {
|
|
@@ -4,8 +4,7 @@ const fs = require("fs");
|
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const os = require("os");
|
|
6
6
|
|
|
7
|
-
const BACKUP_DIR = process.env.
|
|
8
|
-
process.env.FOGIDC_BACKUP_DIR ||
|
|
7
|
+
const BACKUP_DIR = process.env.FOGACT_BACKUP_DIR ||
|
|
9
8
|
path.join(os.homedir(), ".fogact", "backups");
|
|
10
9
|
|
|
11
10
|
function ensureBackupDir() {
|