@zqagent/core 0.2.10 → 0.2.12
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.oss.en.md +1 -1
- package/README.oss.md +1 -1
- package/README.oss.zh-TW.md +1 -1
- package/dist/cli/index.cjs +1929 -1507
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +1810 -1388
- package/dist/cli/index.js.map +1 -1
- package/dist/server/index.cjs +212 -110
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.js +212 -110
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -553,7 +553,7 @@ var init_wire = __esm({
|
|
|
553
553
|
init_esm_shims();
|
|
554
554
|
import "dotenv/config";
|
|
555
555
|
import * as fs34 from "fs";
|
|
556
|
-
import * as
|
|
556
|
+
import * as readline3 from "readline";
|
|
557
557
|
import * as path43 from "path";
|
|
558
558
|
import { exec } from "child_process";
|
|
559
559
|
import { promisify } from "util";
|
|
@@ -10077,6 +10077,38 @@ function countRawEscapes(chunk) {
|
|
|
10077
10077
|
for (const ch of cleaned) if (ch === "\x1B") escCount++;
|
|
10078
10078
|
return escCount;
|
|
10079
10079
|
}
|
|
10080
|
+
function patchReadlineHistoryNav(rl2) {
|
|
10081
|
+
const iface = rl2;
|
|
10082
|
+
const orig = iface._ttyWrite;
|
|
10083
|
+
let draft = null;
|
|
10084
|
+
iface._ttyWrite = function(s, key) {
|
|
10085
|
+
const k = key;
|
|
10086
|
+
const name = k?.name;
|
|
10087
|
+
const plainArrow = (name === "up" || name === "down") && !k?.ctrl && !k?.meta && !k?.shift;
|
|
10088
|
+
if (plainArrow) {
|
|
10089
|
+
if (name === "up" && iface.historyIndex === -1) {
|
|
10090
|
+
draft = { line: iface.line, cursor: iface.cursor };
|
|
10091
|
+
}
|
|
10092
|
+
if (iface.cursor > 0) {
|
|
10093
|
+
iface._moveCursor(-iface.cursor);
|
|
10094
|
+
}
|
|
10095
|
+
}
|
|
10096
|
+
const prevHistoryIndex = iface.historyIndex;
|
|
10097
|
+
orig.call(rl2, s, key);
|
|
10098
|
+
if (plainArrow && name === "down" && prevHistoryIndex >= 0 && iface.historyIndex === -1) {
|
|
10099
|
+
const saved = draft;
|
|
10100
|
+
draft = null;
|
|
10101
|
+
if (saved) {
|
|
10102
|
+
iface.line = saved.line;
|
|
10103
|
+
iface.cursor = Math.min(saved.cursor, saved.line.length);
|
|
10104
|
+
iface._refreshLine?.();
|
|
10105
|
+
}
|
|
10106
|
+
}
|
|
10107
|
+
};
|
|
10108
|
+
rl2.on("line", () => {
|
|
10109
|
+
draft = null;
|
|
10110
|
+
});
|
|
10111
|
+
}
|
|
10080
10112
|
var PASTE_PLACEHOLDER_PREFIX = "\u7C98\u8D34\u6587\u672C #";
|
|
10081
10113
|
var InputRouter = class {
|
|
10082
10114
|
rl;
|
|
@@ -10464,7 +10496,8 @@ function renderTerminalTutorial() {
|
|
|
10464
10496
|
|
|
10465
10497
|
// src/cli/link.ts
|
|
10466
10498
|
init_esm_shims();
|
|
10467
|
-
import * as
|
|
10499
|
+
import * as path28 from "path";
|
|
10500
|
+
import * as readline2 from "readline";
|
|
10468
10501
|
|
|
10469
10502
|
// src/server/store.ts
|
|
10470
10503
|
init_esm_shims();
|
|
@@ -10872,726 +10905,368 @@ async function hubEnrollByAccount(baseUrl, input) {
|
|
|
10872
10905
|
return { hubUrl: baseUrl.replace(/\/$/, ""), ...data };
|
|
10873
10906
|
}
|
|
10874
10907
|
|
|
10875
|
-
// src/cli/
|
|
10908
|
+
// src/cli/account-enroll.ts
|
|
10876
10909
|
init_esm_shims();
|
|
10877
|
-
import
|
|
10878
|
-
import * as
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
|
|
10883
|
-
|
|
10884
|
-
|
|
10885
|
-
|
|
10886
|
-
|
|
10887
|
-
|
|
10888
|
-
|
|
10889
|
-
|
|
10890
|
-
|
|
10891
|
-
|
|
10892
|
-
|
|
10893
|
-
|
|
10894
|
-
|
|
10895
|
-
for (let i = at + 1; i < argv.length; i++) {
|
|
10896
|
-
const arg = argv[i];
|
|
10897
|
-
if (arg === "--data-dir" && argv[i + 1]) {
|
|
10898
|
-
dataDir = argv[++i];
|
|
10899
|
-
} else if (arg.startsWith("--data-dir=")) {
|
|
10900
|
-
dataDir = arg.slice("--data-dir=".length);
|
|
10901
|
-
} else if (arg === "--host" && argv[i + 1]) {
|
|
10902
|
-
host = argv[++i];
|
|
10903
|
-
} else if (arg.startsWith("--host=")) {
|
|
10904
|
-
host = arg.slice("--host=".length);
|
|
10905
|
-
} else if (arg === "--port" && argv[i + 1]) {
|
|
10906
|
-
port = Number(argv[++i]);
|
|
10907
|
-
} else if (arg.startsWith("--port=")) {
|
|
10908
|
-
port = Number(arg.slice("--port=".length));
|
|
10909
|
-
}
|
|
10910
|
-
}
|
|
10911
|
-
if (!Number.isFinite(port) || port <= 0) port = DEFAULT_SERVE_PORT;
|
|
10912
|
-
if (host === "0.0.0.0" || host === "::" || host === "") host = DEFAULT_SERVE_HOST;
|
|
10913
|
-
return { dataDir, host, port };
|
|
10910
|
+
import * as path25 from "path";
|
|
10911
|
+
import * as readline from "readline/promises";
|
|
10912
|
+
|
|
10913
|
+
// src/server/projects.ts
|
|
10914
|
+
init_esm_shims();
|
|
10915
|
+
import * as path24 from "path";
|
|
10916
|
+
|
|
10917
|
+
// src/server/session.ts
|
|
10918
|
+
init_esm_shims();
|
|
10919
|
+
import * as path23 from "path";
|
|
10920
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
10921
|
+
|
|
10922
|
+
// src/server/mcpConfig.ts
|
|
10923
|
+
init_esm_shims();
|
|
10924
|
+
import fs18 from "fs";
|
|
10925
|
+
import path21 from "path";
|
|
10926
|
+
function isValidMcpConfig(v) {
|
|
10927
|
+
return !!v && typeof v === "object" && typeof v.name === "string" && (v.type === "stdio" || v.type === "http");
|
|
10914
10928
|
}
|
|
10915
|
-
function
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
if (!
|
|
10929
|
+
function readConfigFile(file) {
|
|
10930
|
+
if (!file) return [];
|
|
10931
|
+
try {
|
|
10932
|
+
if (!fs18.existsSync(file)) return [];
|
|
10933
|
+
const raw = JSON.parse(fs18.readFileSync(file, "utf8"));
|
|
10934
|
+
const list = Array.isArray(raw) ? raw : raw && typeof raw === "object" && Array.isArray(raw.servers) ? raw.servers : [];
|
|
10935
|
+
return list.filter(isValidMcpConfig);
|
|
10936
|
+
} catch (err) {
|
|
10937
|
+
console.error(`[mcp] \u8BFB\u53D6\u914D\u7F6E\u5931\u8D25 ${file}: ${err.message}`);
|
|
10938
|
+
return [];
|
|
10919
10939
|
}
|
|
10920
|
-
return out;
|
|
10921
|
-
}
|
|
10922
|
-
function isWindowsAbsolute(p) {
|
|
10923
|
-
return /^[A-Za-z]:[\\/]/.test(p) || /^\\\\/.test(p);
|
|
10924
10940
|
}
|
|
10925
|
-
function
|
|
10926
|
-
|
|
10941
|
+
function hasServerMcpConfig() {
|
|
10942
|
+
if (readConfigFile(process.env.MCP_CONFIG_PATH).length > 0) return true;
|
|
10943
|
+
const workspace = process.env.WORKSPACE;
|
|
10944
|
+
if (!workspace) return false;
|
|
10945
|
+
return readConfigFile(path21.join(workspace, ".agent", "mcp.json")).length > 0;
|
|
10927
10946
|
}
|
|
10928
|
-
function
|
|
10929
|
-
|
|
10947
|
+
function loadServerMcpConfigs(tenant) {
|
|
10948
|
+
const fromEnv = readConfigFile(process.env.MCP_CONFIG_PATH);
|
|
10949
|
+
if (fromEnv.length > 0) return fromEnv;
|
|
10950
|
+
if (Array.isArray(tenant.mcpServers) && tenant.mcpServers.length > 0) {
|
|
10951
|
+
return tenant.mcpServers.filter(isValidMcpConfig);
|
|
10952
|
+
}
|
|
10953
|
+
const workspace = tenant.workspaceRoot ?? process.env.WORKSPACE;
|
|
10954
|
+
if (workspace)
|
|
10955
|
+
return readConfigFile(path21.join(workspace, ".agent", "mcp.json"));
|
|
10956
|
+
return [];
|
|
10930
10957
|
}
|
|
10931
|
-
|
|
10932
|
-
|
|
10933
|
-
|
|
10934
|
-
|
|
10935
|
-
|
|
10936
|
-
const
|
|
10937
|
-
|
|
10938
|
-
const portMatch = /--port(?:=|\s+)(\d+)/.exec(line);
|
|
10939
|
-
const port = Number(portMatch?.[1] ?? DEFAULT_SERVE_PORT);
|
|
10958
|
+
|
|
10959
|
+
// src/server/nodeLlm.ts
|
|
10960
|
+
init_esm_shims();
|
|
10961
|
+
var GLOBAL_PROVIDER_ID = "__env__";
|
|
10962
|
+
function envProvider() {
|
|
10963
|
+
const apiKey = process.env.OPENAI_API_KEY;
|
|
10964
|
+
if (!apiKey) return null;
|
|
10940
10965
|
return {
|
|
10941
|
-
|
|
10942
|
-
|
|
10943
|
-
|
|
10966
|
+
id: GLOBAL_PROVIDER_ID,
|
|
10967
|
+
name: process.env.OPENAI_MODEL || process.env.MODEL || "\u5168\u5C40 LLM",
|
|
10968
|
+
type: "env",
|
|
10969
|
+
baseURL: process.env.OPENAI_BASE_URL ?? "",
|
|
10970
|
+
model: process.env.OPENAI_MODEL || process.env.MODEL || "",
|
|
10971
|
+
apiKey
|
|
10944
10972
|
};
|
|
10945
10973
|
}
|
|
10946
|
-
function
|
|
10947
|
-
|
|
10948
|
-
return fs18.readlinkSync(`/proc/${pid}/cwd`);
|
|
10949
|
-
} catch {
|
|
10950
|
-
return null;
|
|
10951
|
-
}
|
|
10974
|
+
function normReasoningEffort(v) {
|
|
10975
|
+
return v === "low" || v === "medium" || v === "high" ? v : null;
|
|
10952
10976
|
}
|
|
10953
|
-
function
|
|
10954
|
-
|
|
10955
|
-
|
|
10956
|
-
|
|
10957
|
-
|
|
10958
|
-
|
|
10959
|
-
|
|
10960
|
-
|
|
10961
|
-
|
|
10977
|
+
function normalizeModelList(v) {
|
|
10978
|
+
if (!Array.isArray(v)) return void 0;
|
|
10979
|
+
const out = [];
|
|
10980
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10981
|
+
for (const x of v) {
|
|
10982
|
+
const s = String(x ?? "").trim();
|
|
10983
|
+
if (!s || seen.has(s)) continue;
|
|
10984
|
+
seen.add(s);
|
|
10985
|
+
out.push(s);
|
|
10986
|
+
if (out.length >= 500) break;
|
|
10962
10987
|
}
|
|
10963
10988
|
return out;
|
|
10964
10989
|
}
|
|
10965
|
-
function
|
|
10966
|
-
const
|
|
10967
|
-
|
|
10968
|
-
|
|
10990
|
+
function nodeLlmView(cfg) {
|
|
10991
|
+
const g = envProvider();
|
|
10992
|
+
const providers = [
|
|
10993
|
+
...g ? [
|
|
10994
|
+
{
|
|
10995
|
+
id: g.id,
|
|
10996
|
+
name: g.name,
|
|
10997
|
+
type: g.type,
|
|
10998
|
+
baseURL: g.baseURL,
|
|
10999
|
+
model: g.model,
|
|
11000
|
+
hasApiKey: true,
|
|
11001
|
+
global: true
|
|
11002
|
+
}
|
|
11003
|
+
] : [],
|
|
11004
|
+
...cfg.providers.map((p) => ({
|
|
11005
|
+
id: p.id,
|
|
11006
|
+
name: p.name,
|
|
11007
|
+
type: p.type ?? "",
|
|
11008
|
+
baseURL: p.baseURL,
|
|
11009
|
+
model: p.model,
|
|
11010
|
+
hasApiKey: Boolean(p.apiKey),
|
|
11011
|
+
models: p.models ?? [],
|
|
11012
|
+
nonChat: p.nonChat ?? [],
|
|
11013
|
+
modelMeta: p.modelMeta ?? [],
|
|
11014
|
+
reasoningEffort: p.reasoningEffort ?? null,
|
|
11015
|
+
global: false
|
|
11016
|
+
}))
|
|
11017
|
+
];
|
|
11018
|
+
return {
|
|
11019
|
+
defaultProviderId: cfg.defaultProviderId ?? null,
|
|
11020
|
+
providers,
|
|
11021
|
+
/** 未显式设置默认时,是否由环境变量全局配置兜底 */
|
|
11022
|
+
globalIsDefault: !cfg.defaultProviderId && Boolean(g)
|
|
11023
|
+
};
|
|
10969
11024
|
}
|
|
10970
|
-
function
|
|
10971
|
-
const
|
|
10972
|
-
|
|
10973
|
-
|
|
10974
|
-
|
|
10975
|
-
|
|
10976
|
-
|
|
11025
|
+
function applyNodeLlmPatch(cfg, raw) {
|
|
11026
|
+
const next = { providers: cfg.providers, defaultProviderId: cfg.defaultProviderId };
|
|
11027
|
+
if (Array.isArray(raw?.providers)) {
|
|
11028
|
+
const old = new Map(cfg.providers.map((p) => [p.id, p]));
|
|
11029
|
+
next.providers = raw.providers.filter((x) => Boolean(x) && typeof x === "object").filter((x) => x.global !== true && String(x.id ?? "") !== GLOBAL_PROVIDER_ID).map((x) => {
|
|
11030
|
+
const id = String(x.id ?? "").trim();
|
|
11031
|
+
if (!id) throw new ApiError(400, "bad_request", "\u4F9B\u5E94\u5546 id \u4E0D\u80FD\u4E3A\u7A7A");
|
|
11032
|
+
const prev = old.get(id);
|
|
11033
|
+
const apiKey = String(x.apiKey ?? "").trim();
|
|
11034
|
+
const models = normalizeModelList(x.models) ?? prev?.models;
|
|
11035
|
+
const nonChat = normalizeModelList(x.nonChat) ?? prev?.nonChat;
|
|
11036
|
+
const modelMeta = normalizeModelMeta(x.modelMeta) ?? prev?.modelMeta;
|
|
11037
|
+
return {
|
|
11038
|
+
id,
|
|
11039
|
+
name: String(x.name ?? prev?.name ?? id).trim(),
|
|
11040
|
+
type: x.type == null ? prev?.type : String(x.type),
|
|
11041
|
+
baseURL: String(x.baseURL ?? prev?.baseURL ?? "").trim(),
|
|
11042
|
+
model: String(x.model ?? prev?.model ?? "").trim(),
|
|
11043
|
+
apiKey: apiKey || prev?.apiKey,
|
|
11044
|
+
reasoningEffort: x.reasoningEffort === void 0 ? prev?.reasoningEffort ?? null : normReasoningEffort(x.reasoningEffort),
|
|
11045
|
+
...models ? { models } : {},
|
|
11046
|
+
...nonChat ? { nonChat } : {},
|
|
11047
|
+
...modelMeta ? { modelMeta } : {}
|
|
11048
|
+
};
|
|
11049
|
+
});
|
|
10977
11050
|
}
|
|
10978
|
-
|
|
10979
|
-
|
|
10980
|
-
|
|
10981
|
-
|
|
10982
|
-
|
|
10983
|
-
try {
|
|
10984
|
-
argv = fs18.readFileSync(`/proc/${pid}/cmdline`, "utf-8").split("\0").filter(Boolean);
|
|
10985
|
-
} catch {
|
|
10986
|
-
continue;
|
|
10987
|
-
}
|
|
10988
|
-
const parsed = parseServeArgs(argv);
|
|
10989
|
-
if (!parsed) continue;
|
|
10990
|
-
const dataDir = resolveDataDir(parsed.dataDir, processCwd(pid), processEnv(pid));
|
|
10991
|
-
if (!dataDir) continue;
|
|
10992
|
-
out.push({ dataDir, host: parsed.host, port: parsed.port });
|
|
11051
|
+
if (typeof raw?.defaultProviderId === "string") {
|
|
11052
|
+
const id = raw.defaultProviderId.trim();
|
|
11053
|
+
next.defaultProviderId = id || void 0;
|
|
11054
|
+
} else if (raw?.defaultProviderId === null) {
|
|
11055
|
+
next.defaultProviderId = void 0;
|
|
10993
11056
|
}
|
|
10994
|
-
return
|
|
11057
|
+
return next;
|
|
10995
11058
|
}
|
|
10996
|
-
function
|
|
10997
|
-
|
|
10998
|
-
|
|
10999
|
-
|
|
11000
|
-
for (const line of res.stdout.split("\n")) {
|
|
11001
|
-
const inst = parseServeCommandLine(line);
|
|
11002
|
-
if (inst) out.push(inst);
|
|
11003
|
-
}
|
|
11004
|
-
return out;
|
|
11059
|
+
function findNodeProvider(store, id) {
|
|
11060
|
+
if (!id) return null;
|
|
11061
|
+
if (id === GLOBAL_PROVIDER_ID) return envProvider();
|
|
11062
|
+
return store.loadNodeLlm().providers.find((p) => p.id === id) ?? null;
|
|
11005
11063
|
}
|
|
11006
|
-
function
|
|
11007
|
-
const
|
|
11008
|
-
|
|
11009
|
-
|
|
11010
|
-
"powershell.exe",
|
|
11011
|
-
["-NoProfile", "-NonInteractive", "-Command", script],
|
|
11012
|
-
{ encoding: "utf-8", timeout: 15e3, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
|
|
11013
|
-
);
|
|
11014
|
-
if (res.status !== 0 || !res.stdout) return out;
|
|
11015
|
-
for (const line of res.stdout.replace(/^\uFEFF/, "").split(/\r?\n/)) {
|
|
11016
|
-
const inst = parseServeCommandLine(line);
|
|
11017
|
-
if (inst) out.push(inst);
|
|
11018
|
-
}
|
|
11019
|
-
return out;
|
|
11064
|
+
function nodeDefaultProvider(store) {
|
|
11065
|
+
const cfg = store.loadNodeLlm();
|
|
11066
|
+
if (cfg.providers.length === 0) return null;
|
|
11067
|
+
return cfg.providers.find((p) => p.id === cfg.defaultProviderId) ?? cfg.providers[0] ?? null;
|
|
11020
11068
|
}
|
|
11021
|
-
function
|
|
11022
|
-
const
|
|
11023
|
-
|
|
11024
|
-
|
|
11025
|
-
if (
|
|
11026
|
-
|
|
11027
|
-
|
|
11028
|
-
|
|
11069
|
+
function resolveSessionProvider(store, tenant, providerId) {
|
|
11070
|
+
const own = tenant.provider ?? {};
|
|
11071
|
+
if (providerId) {
|
|
11072
|
+
const picked = findNodeProvider(store, providerId);
|
|
11073
|
+
if (picked) {
|
|
11074
|
+
return {
|
|
11075
|
+
apiKey: picked.apiKey || own.apiKey,
|
|
11076
|
+
baseURL: picked.baseURL || own.baseURL,
|
|
11077
|
+
model: picked.model,
|
|
11078
|
+
providerId,
|
|
11079
|
+
reasoningEffort: picked.reasoningEffort ?? null,
|
|
11080
|
+
...picked.modelMeta ? { modelMeta: picked.modelMeta } : {}
|
|
11081
|
+
};
|
|
11082
|
+
}
|
|
11083
|
+
}
|
|
11084
|
+
if (own.apiKey) return { ...own, model: tenant.model };
|
|
11085
|
+
const def = nodeDefaultProvider(store);
|
|
11086
|
+
if (def?.apiKey) {
|
|
11087
|
+
return {
|
|
11088
|
+
apiKey: def.apiKey,
|
|
11089
|
+
baseURL: own.baseURL || def.baseURL,
|
|
11090
|
+
model: def.model || tenant.model,
|
|
11091
|
+
reasoningEffort: def.reasoningEffort ?? null,
|
|
11092
|
+
...def.modelMeta ? { modelMeta: def.modelMeta } : {}
|
|
11093
|
+
};
|
|
11094
|
+
}
|
|
11095
|
+
return { ...own, model: tenant.model };
|
|
11029
11096
|
}
|
|
11030
11097
|
|
|
11031
|
-
// src/
|
|
11032
|
-
|
|
11033
|
-
|
|
11034
|
-
|
|
11035
|
-
|
|
11036
|
-
|
|
11037
|
-
|
|
11098
|
+
// src/server/usage.ts
|
|
11099
|
+
init_esm_shims();
|
|
11100
|
+
import * as fs19 from "fs";
|
|
11101
|
+
import * as path22 from "path";
|
|
11102
|
+
var LEDGER_RETENTION_MONTHS = 12;
|
|
11103
|
+
var USAGE_SCHEMA = 1;
|
|
11104
|
+
var DEFAULT_PRICING = {
|
|
11105
|
+
schema: USAGE_SCHEMA,
|
|
11106
|
+
base: "USD",
|
|
11107
|
+
rate: { CNY: 7.2 },
|
|
11108
|
+
vendors: {
|
|
11109
|
+
openai: {
|
|
11110
|
+
"gpt-4o": { input: 2.5, output: 10, cacheRead: 1.25 },
|
|
11111
|
+
"gpt-4o-mini": { input: 0.15, output: 0.6, cacheRead: 0.075 },
|
|
11112
|
+
"gpt-4.1": { input: 2, output: 8, cacheRead: 0.5 }
|
|
11113
|
+
},
|
|
11114
|
+
deepseek: {
|
|
11115
|
+
"deepseek-flash": {
|
|
11116
|
+
input: 0.27,
|
|
11117
|
+
output: 1.1,
|
|
11118
|
+
cacheRead: 0.027,
|
|
11119
|
+
cacheWrite: 0.27
|
|
11120
|
+
},
|
|
11121
|
+
"deepseek-reasoner": {
|
|
11122
|
+
input: 0.55,
|
|
11123
|
+
output: 2.19,
|
|
11124
|
+
cacheRead: 0.055,
|
|
11125
|
+
cacheWrite: 0.55
|
|
11126
|
+
},
|
|
11127
|
+
"deepseek-*": {
|
|
11128
|
+
input: 0.27,
|
|
11129
|
+
output: 1.1,
|
|
11130
|
+
cacheRead: 0.027,
|
|
11131
|
+
cacheWrite: 0.27
|
|
11132
|
+
}
|
|
11133
|
+
},
|
|
11134
|
+
qwen: {
|
|
11135
|
+
"qwen-plus": { input: 0.4, output: 1.2 },
|
|
11136
|
+
"qwen-turbo": { input: 0.05, output: 0.2 }
|
|
11137
|
+
},
|
|
11138
|
+
zhipu: { "glm-4-plus": { input: 0.7, output: 0.7 } },
|
|
11139
|
+
moonshot: { "moonshot-v1-8k": { input: 1.68, output: 1.68 } },
|
|
11140
|
+
xiaomi: {},
|
|
11141
|
+
custom: {},
|
|
11142
|
+
env: {}
|
|
11143
|
+
},
|
|
11144
|
+
fallback: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }
|
|
11145
|
+
};
|
|
11146
|
+
function zeroAgg() {
|
|
11147
|
+
return {
|
|
11148
|
+
calls: 0,
|
|
11149
|
+
input: 0,
|
|
11150
|
+
output: 0,
|
|
11151
|
+
cacheRead: 0,
|
|
11152
|
+
cacheWrite: 0,
|
|
11153
|
+
costUsd: 0,
|
|
11154
|
+
unpriced: 0
|
|
11155
|
+
};
|
|
11038
11156
|
}
|
|
11039
|
-
function
|
|
11040
|
-
|
|
11041
|
-
|
|
11042
|
-
|
|
11157
|
+
function addAgg(into, tokens, costUsd) {
|
|
11158
|
+
into.calls += 1;
|
|
11159
|
+
into.input += tokens.input;
|
|
11160
|
+
into.output += tokens.output;
|
|
11161
|
+
into.cacheRead += tokens.cacheRead;
|
|
11162
|
+
into.cacheWrite += tokens.cacheWrite;
|
|
11163
|
+
if (costUsd == null) into.unpriced += 1;
|
|
11164
|
+
else into.costUsd += costUsd;
|
|
11043
11165
|
}
|
|
11044
|
-
function
|
|
11045
|
-
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
|
|
11049
|
-
|
|
11050
|
-
|
|
11051
|
-
|
|
11052
|
-
|
|
11053
|
-
|
|
11054
|
-
|
|
11055
|
-
|
|
11056
|
-
out.dataDir = val;
|
|
11057
|
-
i++;
|
|
11058
|
-
} else if (a === "--label") {
|
|
11059
|
-
out.label = val;
|
|
11060
|
-
i++;
|
|
11061
|
-
} else if (a === "--host") {
|
|
11062
|
-
out.host = val;
|
|
11063
|
-
i++;
|
|
11064
|
-
} else if (a === "--port") {
|
|
11065
|
-
out.port = Number(val);
|
|
11066
|
-
i++;
|
|
11067
|
-
} else if (a === "-h" || a === "--help") {
|
|
11068
|
-
out.help = true;
|
|
11069
|
-
}
|
|
11166
|
+
function utcDay(iso) {
|
|
11167
|
+
return iso.slice(0, 10);
|
|
11168
|
+
}
|
|
11169
|
+
function monthOf(iso) {
|
|
11170
|
+
return iso.slice(0, 7);
|
|
11171
|
+
}
|
|
11172
|
+
function retainedMonths(now = /* @__PURE__ */ new Date()) {
|
|
11173
|
+
const out = /* @__PURE__ */ new Set();
|
|
11174
|
+
const d = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));
|
|
11175
|
+
for (let i = 0; i < LEDGER_RETENTION_MONTHS; i += 1) {
|
|
11176
|
+
out.add(d.toISOString().slice(0, 7));
|
|
11177
|
+
d.setUTCMonth(d.getUTCMonth() - 1);
|
|
11070
11178
|
}
|
|
11071
11179
|
return out;
|
|
11072
11180
|
}
|
|
11073
|
-
function
|
|
11074
|
-
|
|
11075
|
-
|
|
11076
|
-
|
|
11077
|
-
|
|
11078
|
-
}
|
|
11079
|
-
return id;
|
|
11181
|
+
function atomicWrite(file, content) {
|
|
11182
|
+
fs19.mkdirSync(path22.dirname(file), { recursive: true });
|
|
11183
|
+
const tmp = `${file}.tmp`;
|
|
11184
|
+
fs19.writeFileSync(tmp, content, "utf-8");
|
|
11185
|
+
fs19.renameSync(tmp, file);
|
|
11080
11186
|
}
|
|
11081
|
-
|
|
11082
|
-
|
|
11083
|
-
|
|
11084
|
-
|
|
11085
|
-
const res = await fetch(`http://${host}:${port}/api/v1/fleet/status`, {
|
|
11086
|
-
headers: { Authorization: `Bearer ${adminKey}` },
|
|
11087
|
-
signal: ctrl.signal
|
|
11088
|
-
});
|
|
11089
|
-
return res.ok;
|
|
11090
|
-
} catch {
|
|
11091
|
-
return false;
|
|
11092
|
-
} finally {
|
|
11093
|
-
clearTimeout(timer);
|
|
11187
|
+
var UsageLedger = class {
|
|
11188
|
+
constructor(root) {
|
|
11189
|
+
this.root = root;
|
|
11190
|
+
this.dir = path22.join(root, "usage");
|
|
11094
11191
|
}
|
|
11095
|
-
|
|
11096
|
-
|
|
11097
|
-
|
|
11098
|
-
|
|
11099
|
-
|
|
11100
|
-
|
|
11101
|
-
|
|
11102
|
-
|
|
11103
|
-
|
|
11104
|
-
});
|
|
11105
|
-
const text = await res.text();
|
|
11106
|
-
let payload = null;
|
|
11107
|
-
try {
|
|
11108
|
-
payload = text ? JSON.parse(text) : null;
|
|
11109
|
-
} catch {
|
|
11192
|
+
root;
|
|
11193
|
+
dir;
|
|
11194
|
+
rollup;
|
|
11195
|
+
pricing;
|
|
11196
|
+
rollupDirty = false;
|
|
11197
|
+
rollupTimer = null;
|
|
11198
|
+
inited = false;
|
|
11199
|
+
get ledgerDir() {
|
|
11200
|
+
return this.dir;
|
|
11110
11201
|
}
|
|
11111
|
-
|
|
11112
|
-
|
|
11202
|
+
ledgerFile(month) {
|
|
11203
|
+
return path22.join(this.ledgerDir, `ledger-${month}.jsonl`);
|
|
11113
11204
|
}
|
|
11114
|
-
|
|
11115
|
-
|
|
11116
|
-
async function linkNode(opts) {
|
|
11117
|
-
const rawDataDir = opts.dataDir?.trim() || process.env.DATA_DIR?.trim() || void 0;
|
|
11118
|
-
const explicitDataDir = rawDataDir ? expandHome(rawDataDir) : void 0;
|
|
11119
|
-
const host = opts.host?.trim() || process.env.HOST?.trim() || DEFAULT_SERVE_HOST;
|
|
11120
|
-
const port = opts.port ?? Number(process.env.PORT ?? DEFAULT_SERVE_PORT);
|
|
11121
|
-
const running = discoverRunningServeInstances();
|
|
11122
|
-
const candidates = buildHotCandidates(explicitDataDir, running, { host, port });
|
|
11123
|
-
for (const inst of candidates) {
|
|
11124
|
-
const store2 = new Store(inst.dataDir);
|
|
11125
|
-
const adminKey = process.env.ADMIN_API_KEY ?? store2.loadAdminKey();
|
|
11126
|
-
if (!adminKey) continue;
|
|
11127
|
-
if (!await probeServer(inst.host, inst.port, adminKey)) continue;
|
|
11128
|
-
const status = await enrollViaServer(inst.host, inst.port, adminKey, opts);
|
|
11129
|
-
return { mode: "hot", ...status, dataDir: inst.dataDir };
|
|
11205
|
+
get rollupFile() {
|
|
11206
|
+
return path22.join(this.ledgerDir, "rollup.json");
|
|
11130
11207
|
}
|
|
11131
|
-
|
|
11132
|
-
|
|
11133
|
-
const nodeId = ensureNodeId(store);
|
|
11134
|
-
const cred = await hubEnrollByCode(opts.hubUrl, {
|
|
11135
|
-
code: opts.code,
|
|
11136
|
-
nodeId,
|
|
11137
|
-
label: opts.label
|
|
11138
|
-
});
|
|
11139
|
-
try {
|
|
11140
|
-
store.saveFleetCredential({
|
|
11141
|
-
...cred,
|
|
11142
|
-
label: opts.label ?? cred.label,
|
|
11143
|
-
enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11144
|
-
});
|
|
11145
|
-
} catch (e) {
|
|
11146
|
-
const err = e;
|
|
11147
|
-
if (err.code === "EACCES" || err.code === "EPERM") {
|
|
11148
|
-
throw new Error(
|
|
11149
|
-
`\u65E0\u6CD5\u5199\u5165\u6570\u636E\u76EE\u5F55 ${dataDir}\uFF08${err.code}: ${err.message}\uFF09
|
|
11150
|
-
\u8BE5\u76EE\u5F55\u5F53\u524D\u7528\u6237\u6CA1\u6709\u5199\u6743\u9650\u3002\u4E24\u79CD\u6539\u6CD5\uFF1A
|
|
11151
|
-
1) \u53BB\u6389 --data-dir\uFF0C\u8BA9 link \u81EA\u52A8\u53D1\u73B0\u672C\u673A\u8FD0\u884C\u7684\u8282\u70B9\uFF08\u63A8\u8350\uFF09\uFF1B
|
|
11152
|
-
2) \u7528\u5F53\u524D\u7528\u6237\u53EF\u5199\u7684\u76EE\u5F55\uFF0C\u672C\u5E73\u53F0\u5B89\u88C5\u811A\u672C\u9ED8\u8BA4\uFF1A${installDataDirHint()}
|
|
11153
|
-
\uFF08\u63A5\u5165\u7801\u4E00\u6B21\u6027\uFF0C\u9700\u8981\u91CD\u65B0\u751F\u6210\uFF09`
|
|
11154
|
-
);
|
|
11155
|
-
}
|
|
11156
|
-
throw e;
|
|
11208
|
+
get pricingFile() {
|
|
11209
|
+
return path22.join(this.ledgerDir, "pricing.json");
|
|
11157
11210
|
}
|
|
11158
|
-
|
|
11159
|
-
|
|
11160
|
-
|
|
11161
|
-
|
|
11162
|
-
|
|
11163
|
-
|
|
11164
|
-
|
|
11165
|
-
|
|
11166
|
-
dataDir,
|
|
11167
|
-
explicitDataDir: Boolean(explicitDataDir),
|
|
11168
|
-
runningServiceDirs: otherRunningDirs
|
|
11169
|
-
};
|
|
11170
|
-
}
|
|
11171
|
-
function printLinkHelp() {
|
|
11172
|
-
cliLog("\u7528\u6CD5: zqagent link --hub <url> --code <\u6CE8\u518C\u7801> [--label \u540D\u79F0] [--data-dir \u76EE\u5F55]");
|
|
11173
|
-
cliLog(" \u5728 Hub \u7528\u6237\u4E2D\u5FC3\u751F\u6210\u4E00\u6B21\u6027\u6CE8\u518C\u7801\u540E\uFF0C\u4E8E\u8282\u70B9\u673A\u5668\u6267\u884C\u672C\u547D\u4EE4\u5373\u53EF\u63A5\u5165\u3002");
|
|
11174
|
-
cliLog(" \u5DF2\u6709\u672C\u673A server \u65F6\u70ED\u63A5\u5165\uFF08\u514D\u91CD\u542F\uFF0C\u4F1A\u81EA\u52A8\u53D1\u73B0\u8FD0\u884C\u4E2D\u670D\u52A1\u7684 --data-dir\uFF09\uFF1B");
|
|
11175
|
-
cliLog(" \u5426\u5219\u5199\u5165 <\u6570\u636E\u76EE\u5F55>/fleet.json\uFF0C\u4E0B\u6B21\u542F\u52A8\u81EA\u52A8\u63A5\u5165\u3002");
|
|
11176
|
-
}
|
|
11177
|
-
async function runLinkCommand(argv) {
|
|
11178
|
-
const args = parseLinkArgs(argv);
|
|
11179
|
-
if (args.help) {
|
|
11180
|
-
printLinkHelp();
|
|
11181
|
-
return true;
|
|
11182
|
-
}
|
|
11183
|
-
const hubUrl = (args.hubUrl ?? process.env.HUB_URL ?? "").trim().replace(/\/$/, "");
|
|
11184
|
-
const code = (args.code ?? "").trim();
|
|
11185
|
-
if (!hubUrl || !code) {
|
|
11186
|
-
cliErr("\u7F3A\u5C11 --hub \u6216 --code\u3002");
|
|
11187
|
-
printLinkHelp();
|
|
11188
|
-
return false;
|
|
11211
|
+
// ===================== 初始化 =====================
|
|
11212
|
+
init(now = /* @__PURE__ */ new Date()) {
|
|
11213
|
+
if (this.inited) return;
|
|
11214
|
+
fs19.mkdirSync(this.ledgerDir, { recursive: true });
|
|
11215
|
+
this.pricing = this.loadPricing();
|
|
11216
|
+
this.rollup = this.loadRollup(now);
|
|
11217
|
+
this.pruneLedgers(now);
|
|
11218
|
+
this.inited = true;
|
|
11189
11219
|
}
|
|
11190
|
-
|
|
11191
|
-
|
|
11192
|
-
|
|
11193
|
-
|
|
11194
|
-
|
|
11195
|
-
|
|
11196
|
-
|
|
11197
|
-
|
|
11198
|
-
|
|
11199
|
-
|
|
11200
|
-
|
|
11201
|
-
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
|
|
11206
|
-
|
|
11207
|
-
|
|
11208
|
-
|
|
11209
|
-
|
|
11210
|
-
|
|
11211
|
-
|
|
11212
|
-
|
|
11213
|
-
|
|
11214
|
-
|
|
11215
|
-
cliLog(" \u6B63\u5728\u8FD0\u884C\u7684\u670D\u52A1\u8BFB\u4E0D\u5230\u8FD9\u4EFD\u51ED\u636E\uFF0CHub \u4F1A\u4E00\u76F4\u663E\u793A\u672A\u63A5\u5165\u3002");
|
|
11216
|
-
cliLog(" \u8BF7\u786E\u8BA4\u670D\u52A1\u7684\u6570\u636E\u76EE\u5F55\u540E\u91CD\u65B0\u6267\u884C\uFF08\u63A5\u5165\u7801\u4E00\u6B21\u6027\uFF0C\u9700\u8981\u91CD\u65B0\u751F\u6210\uFF09\uFF1A");
|
|
11217
|
-
cliLog(` zqagent link --hub <Hub\u5730\u5740> --code <\u65B0\u63A5\u5165\u7801> --data-dir "${r.runningServiceDirs[0]}"`);
|
|
11218
|
-
} else if (!r.explicitDataDir) {
|
|
11219
|
-
cliLog("");
|
|
11220
|
-
cliLog("\u26A0\uFE0F \u672A\u6307\u5B9A --data-dir\uFF0C\u51ED\u636E\u5199\u5165\u4E86\u5F53\u524D\u76EE\u5F55\u4E0B\u7684 .zqagent_data\u3002");
|
|
11221
|
-
cliLog(" \u82E5\u672C\u673A\u670D\u52A1\u662F\u7531\u5B89\u88C5\u811A\u672C\uFF08systemd / launchd\uFF09\u542F\u52A8\u7684\uFF0C\u5B83\u8BFB\u4E0D\u5230\u8FD9\u4EFD\u51ED\u636E\uFF0C");
|
|
11222
|
-
cliLog(" Hub \u4F1A\u4E00\u76F4\u663E\u793A\u672A\u5728\u7EBF\u3002\u8BF7\u7528\u670D\u52A1\u7684\u6570\u636E\u76EE\u5F55\u91CD\u65B0\u6267\u884C\uFF1A");
|
|
11223
|
-
cliLog(" zqagent link --hub <Hub\u5730\u5740> --code <\u65B0\u63A5\u5165\u7801> --data-dir <\u670D\u52A1\u6570\u636E\u76EE\u5F55>");
|
|
11224
|
-
cliLog(` \uFF08\u672C\u5E73\u53F0\u5B89\u88C5\u811A\u672C\u9ED8\u8BA4\uFF1A${installDataDirHint()}\uFF1B\u63A5\u5165\u7801\u4E00\u6B21\u6027\uFF0C\u9700\u8981\u91CD\u65B0\u751F\u6210\uFF09`);
|
|
11220
|
+
loadPricing() {
|
|
11221
|
+
try {
|
|
11222
|
+
const raw = fs19.readFileSync(this.pricingFile, "utf-8");
|
|
11223
|
+
const parsed = JSON.parse(raw);
|
|
11224
|
+
const vendors = {};
|
|
11225
|
+
for (const v of /* @__PURE__ */ new Set([
|
|
11226
|
+
...Object.keys(DEFAULT_PRICING.vendors),
|
|
11227
|
+
...Object.keys(parsed.vendors ?? {})
|
|
11228
|
+
])) {
|
|
11229
|
+
vendors[v] = {
|
|
11230
|
+
...DEFAULT_PRICING.vendors[v] ?? {},
|
|
11231
|
+
...(parsed.vendors ?? {})[v] ?? {}
|
|
11232
|
+
};
|
|
11233
|
+
}
|
|
11234
|
+
return {
|
|
11235
|
+
schema: USAGE_SCHEMA,
|
|
11236
|
+
base: "USD",
|
|
11237
|
+
rate: { ...DEFAULT_PRICING.rate, ...parsed.rate ?? {} },
|
|
11238
|
+
vendors,
|
|
11239
|
+
fallback: { ...DEFAULT_PRICING.fallback, ...parsed.fallback ?? {} }
|
|
11240
|
+
};
|
|
11241
|
+
} catch {
|
|
11242
|
+
try {
|
|
11243
|
+
atomicWrite(this.pricingFile, JSON.stringify(DEFAULT_PRICING, null, 2));
|
|
11244
|
+
} catch {
|
|
11225
11245
|
}
|
|
11246
|
+
return JSON.parse(JSON.stringify(DEFAULT_PRICING));
|
|
11226
11247
|
}
|
|
11227
|
-
return true;
|
|
11228
|
-
} catch (e) {
|
|
11229
|
-
cliErr(`\u63A5\u5165\u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`);
|
|
11230
|
-
return false;
|
|
11231
|
-
}
|
|
11232
|
-
}
|
|
11233
|
-
|
|
11234
|
-
// src/cli/serve.ts
|
|
11235
|
-
init_esm_shims();
|
|
11236
|
-
|
|
11237
|
-
// src/server/runtime.ts
|
|
11238
|
-
init_esm_shims();
|
|
11239
|
-
import * as fs31 from "fs";
|
|
11240
|
-
import * as path38 from "path";
|
|
11241
|
-
|
|
11242
|
-
// src/server/session.ts
|
|
11243
|
-
init_esm_shims();
|
|
11244
|
-
import * as path25 from "path";
|
|
11245
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
11246
|
-
|
|
11247
|
-
// src/server/mcpConfig.ts
|
|
11248
|
-
init_esm_shims();
|
|
11249
|
-
import fs19 from "fs";
|
|
11250
|
-
import path23 from "path";
|
|
11251
|
-
function isValidMcpConfig(v) {
|
|
11252
|
-
return !!v && typeof v === "object" && typeof v.name === "string" && (v.type === "stdio" || v.type === "http");
|
|
11253
|
-
}
|
|
11254
|
-
function readConfigFile(file) {
|
|
11255
|
-
if (!file) return [];
|
|
11256
|
-
try {
|
|
11257
|
-
if (!fs19.existsSync(file)) return [];
|
|
11258
|
-
const raw = JSON.parse(fs19.readFileSync(file, "utf8"));
|
|
11259
|
-
const list = Array.isArray(raw) ? raw : raw && typeof raw === "object" && Array.isArray(raw.servers) ? raw.servers : [];
|
|
11260
|
-
return list.filter(isValidMcpConfig);
|
|
11261
|
-
} catch (err) {
|
|
11262
|
-
console.error(`[mcp] \u8BFB\u53D6\u914D\u7F6E\u5931\u8D25 ${file}: ${err.message}`);
|
|
11263
|
-
return [];
|
|
11264
|
-
}
|
|
11265
|
-
}
|
|
11266
|
-
function hasServerMcpConfig() {
|
|
11267
|
-
if (readConfigFile(process.env.MCP_CONFIG_PATH).length > 0) return true;
|
|
11268
|
-
const workspace = process.env.WORKSPACE;
|
|
11269
|
-
if (!workspace) return false;
|
|
11270
|
-
return readConfigFile(path23.join(workspace, ".agent", "mcp.json")).length > 0;
|
|
11271
|
-
}
|
|
11272
|
-
function loadServerMcpConfigs(tenant) {
|
|
11273
|
-
const fromEnv = readConfigFile(process.env.MCP_CONFIG_PATH);
|
|
11274
|
-
if (fromEnv.length > 0) return fromEnv;
|
|
11275
|
-
if (Array.isArray(tenant.mcpServers) && tenant.mcpServers.length > 0) {
|
|
11276
|
-
return tenant.mcpServers.filter(isValidMcpConfig);
|
|
11277
|
-
}
|
|
11278
|
-
const workspace = tenant.workspaceRoot ?? process.env.WORKSPACE;
|
|
11279
|
-
if (workspace)
|
|
11280
|
-
return readConfigFile(path23.join(workspace, ".agent", "mcp.json"));
|
|
11281
|
-
return [];
|
|
11282
|
-
}
|
|
11283
|
-
|
|
11284
|
-
// src/server/nodeLlm.ts
|
|
11285
|
-
init_esm_shims();
|
|
11286
|
-
var GLOBAL_PROVIDER_ID = "__env__";
|
|
11287
|
-
function envProvider() {
|
|
11288
|
-
const apiKey = process.env.OPENAI_API_KEY;
|
|
11289
|
-
if (!apiKey) return null;
|
|
11290
|
-
return {
|
|
11291
|
-
id: GLOBAL_PROVIDER_ID,
|
|
11292
|
-
name: process.env.OPENAI_MODEL || process.env.MODEL || "\u5168\u5C40 LLM",
|
|
11293
|
-
type: "env",
|
|
11294
|
-
baseURL: process.env.OPENAI_BASE_URL ?? "",
|
|
11295
|
-
model: process.env.OPENAI_MODEL || process.env.MODEL || "",
|
|
11296
|
-
apiKey
|
|
11297
|
-
};
|
|
11298
|
-
}
|
|
11299
|
-
function normReasoningEffort(v) {
|
|
11300
|
-
return v === "low" || v === "medium" || v === "high" ? v : null;
|
|
11301
|
-
}
|
|
11302
|
-
function normalizeModelList(v) {
|
|
11303
|
-
if (!Array.isArray(v)) return void 0;
|
|
11304
|
-
const out = [];
|
|
11305
|
-
const seen = /* @__PURE__ */ new Set();
|
|
11306
|
-
for (const x of v) {
|
|
11307
|
-
const s = String(x ?? "").trim();
|
|
11308
|
-
if (!s || seen.has(s)) continue;
|
|
11309
|
-
seen.add(s);
|
|
11310
|
-
out.push(s);
|
|
11311
|
-
if (out.length >= 500) break;
|
|
11312
11248
|
}
|
|
11313
|
-
|
|
11314
|
-
|
|
11315
|
-
|
|
11316
|
-
|
|
11317
|
-
const providers = [
|
|
11318
|
-
...g ? [
|
|
11319
|
-
{
|
|
11320
|
-
id: g.id,
|
|
11321
|
-
name: g.name,
|
|
11322
|
-
type: g.type,
|
|
11323
|
-
baseURL: g.baseURL,
|
|
11324
|
-
model: g.model,
|
|
11325
|
-
hasApiKey: true,
|
|
11326
|
-
global: true
|
|
11327
|
-
}
|
|
11328
|
-
] : [],
|
|
11329
|
-
...cfg.providers.map((p) => ({
|
|
11330
|
-
id: p.id,
|
|
11331
|
-
name: p.name,
|
|
11332
|
-
type: p.type ?? "",
|
|
11333
|
-
baseURL: p.baseURL,
|
|
11334
|
-
model: p.model,
|
|
11335
|
-
hasApiKey: Boolean(p.apiKey),
|
|
11336
|
-
models: p.models ?? [],
|
|
11337
|
-
nonChat: p.nonChat ?? [],
|
|
11338
|
-
modelMeta: p.modelMeta ?? [],
|
|
11339
|
-
reasoningEffort: p.reasoningEffort ?? null,
|
|
11340
|
-
global: false
|
|
11341
|
-
}))
|
|
11342
|
-
];
|
|
11343
|
-
return {
|
|
11344
|
-
defaultProviderId: cfg.defaultProviderId ?? null,
|
|
11345
|
-
providers,
|
|
11346
|
-
/** 未显式设置默认时,是否由环境变量全局配置兜底 */
|
|
11347
|
-
globalIsDefault: !cfg.defaultProviderId && Boolean(g)
|
|
11348
|
-
};
|
|
11349
|
-
}
|
|
11350
|
-
function applyNodeLlmPatch(cfg, raw) {
|
|
11351
|
-
const next = { providers: cfg.providers, defaultProviderId: cfg.defaultProviderId };
|
|
11352
|
-
if (Array.isArray(raw?.providers)) {
|
|
11353
|
-
const old = new Map(cfg.providers.map((p) => [p.id, p]));
|
|
11354
|
-
next.providers = raw.providers.filter((x) => Boolean(x) && typeof x === "object").filter((x) => x.global !== true && String(x.id ?? "") !== GLOBAL_PROVIDER_ID).map((x) => {
|
|
11355
|
-
const id = String(x.id ?? "").trim();
|
|
11356
|
-
if (!id) throw new ApiError(400, "bad_request", "\u4F9B\u5E94\u5546 id \u4E0D\u80FD\u4E3A\u7A7A");
|
|
11357
|
-
const prev = old.get(id);
|
|
11358
|
-
const apiKey = String(x.apiKey ?? "").trim();
|
|
11359
|
-
const models = normalizeModelList(x.models) ?? prev?.models;
|
|
11360
|
-
const nonChat = normalizeModelList(x.nonChat) ?? prev?.nonChat;
|
|
11361
|
-
const modelMeta = normalizeModelMeta(x.modelMeta) ?? prev?.modelMeta;
|
|
11249
|
+
loadRollup(now) {
|
|
11250
|
+
try {
|
|
11251
|
+
const raw = fs19.readFileSync(this.rollupFile, "utf-8");
|
|
11252
|
+
const parsed = JSON.parse(raw);
|
|
11362
11253
|
return {
|
|
11363
|
-
|
|
11364
|
-
|
|
11365
|
-
|
|
11366
|
-
|
|
11367
|
-
|
|
11368
|
-
|
|
11369
|
-
|
|
11370
|
-
...models ? { models } : {},
|
|
11371
|
-
...nonChat ? { nonChat } : {},
|
|
11372
|
-
...modelMeta ? { modelMeta } : {}
|
|
11254
|
+
schema: USAGE_SCHEMA,
|
|
11255
|
+
since: parsed.since ?? now.toISOString(),
|
|
11256
|
+
legacy: parsed.legacy,
|
|
11257
|
+
total: { ...zeroAgg(), ...parsed.total },
|
|
11258
|
+
byDay: parsed.byDay ?? {},
|
|
11259
|
+
byModel: parsed.byModel ?? {},
|
|
11260
|
+
byProject: parsed.byProject ?? {}
|
|
11373
11261
|
};
|
|
11374
|
-
}
|
|
11375
|
-
}
|
|
11376
|
-
if (typeof raw?.defaultProviderId === "string") {
|
|
11377
|
-
const id = raw.defaultProviderId.trim();
|
|
11378
|
-
next.defaultProviderId = id || void 0;
|
|
11379
|
-
} else if (raw?.defaultProviderId === null) {
|
|
11380
|
-
next.defaultProviderId = void 0;
|
|
11381
|
-
}
|
|
11382
|
-
return next;
|
|
11383
|
-
}
|
|
11384
|
-
function findNodeProvider(store, id) {
|
|
11385
|
-
if (!id) return null;
|
|
11386
|
-
if (id === GLOBAL_PROVIDER_ID) return envProvider();
|
|
11387
|
-
return store.loadNodeLlm().providers.find((p) => p.id === id) ?? null;
|
|
11388
|
-
}
|
|
11389
|
-
function nodeDefaultProvider(store) {
|
|
11390
|
-
const cfg = store.loadNodeLlm();
|
|
11391
|
-
if (cfg.providers.length === 0) return null;
|
|
11392
|
-
return cfg.providers.find((p) => p.id === cfg.defaultProviderId) ?? cfg.providers[0] ?? null;
|
|
11393
|
-
}
|
|
11394
|
-
function resolveSessionProvider(store, tenant, providerId) {
|
|
11395
|
-
const own = tenant.provider ?? {};
|
|
11396
|
-
if (providerId) {
|
|
11397
|
-
const picked = findNodeProvider(store, providerId);
|
|
11398
|
-
if (picked) {
|
|
11262
|
+
} catch {
|
|
11399
11263
|
return {
|
|
11400
|
-
|
|
11401
|
-
|
|
11402
|
-
|
|
11403
|
-
|
|
11404
|
-
|
|
11405
|
-
|
|
11406
|
-
};
|
|
11407
|
-
}
|
|
11408
|
-
}
|
|
11409
|
-
if (own.apiKey) return { ...own, model: tenant.model };
|
|
11410
|
-
const def = nodeDefaultProvider(store);
|
|
11411
|
-
if (def?.apiKey) {
|
|
11412
|
-
return {
|
|
11413
|
-
apiKey: def.apiKey,
|
|
11414
|
-
baseURL: own.baseURL || def.baseURL,
|
|
11415
|
-
model: def.model || tenant.model,
|
|
11416
|
-
reasoningEffort: def.reasoningEffort ?? null,
|
|
11417
|
-
...def.modelMeta ? { modelMeta: def.modelMeta } : {}
|
|
11418
|
-
};
|
|
11419
|
-
}
|
|
11420
|
-
return { ...own, model: tenant.model };
|
|
11421
|
-
}
|
|
11422
|
-
|
|
11423
|
-
// src/server/usage.ts
|
|
11424
|
-
init_esm_shims();
|
|
11425
|
-
import * as fs20 from "fs";
|
|
11426
|
-
import * as path24 from "path";
|
|
11427
|
-
var LEDGER_RETENTION_MONTHS = 12;
|
|
11428
|
-
var USAGE_SCHEMA = 1;
|
|
11429
|
-
var DEFAULT_PRICING = {
|
|
11430
|
-
schema: USAGE_SCHEMA,
|
|
11431
|
-
base: "USD",
|
|
11432
|
-
rate: { CNY: 7.2 },
|
|
11433
|
-
vendors: {
|
|
11434
|
-
openai: {
|
|
11435
|
-
"gpt-4o": { input: 2.5, output: 10, cacheRead: 1.25 },
|
|
11436
|
-
"gpt-4o-mini": { input: 0.15, output: 0.6, cacheRead: 0.075 },
|
|
11437
|
-
"gpt-4.1": { input: 2, output: 8, cacheRead: 0.5 }
|
|
11438
|
-
},
|
|
11439
|
-
deepseek: {
|
|
11440
|
-
"deepseek-flash": {
|
|
11441
|
-
input: 0.27,
|
|
11442
|
-
output: 1.1,
|
|
11443
|
-
cacheRead: 0.027,
|
|
11444
|
-
cacheWrite: 0.27
|
|
11445
|
-
},
|
|
11446
|
-
"deepseek-reasoner": {
|
|
11447
|
-
input: 0.55,
|
|
11448
|
-
output: 2.19,
|
|
11449
|
-
cacheRead: 0.055,
|
|
11450
|
-
cacheWrite: 0.55
|
|
11451
|
-
},
|
|
11452
|
-
"deepseek-*": {
|
|
11453
|
-
input: 0.27,
|
|
11454
|
-
output: 1.1,
|
|
11455
|
-
cacheRead: 0.027,
|
|
11456
|
-
cacheWrite: 0.27
|
|
11457
|
-
}
|
|
11458
|
-
},
|
|
11459
|
-
qwen: {
|
|
11460
|
-
"qwen-plus": { input: 0.4, output: 1.2 },
|
|
11461
|
-
"qwen-turbo": { input: 0.05, output: 0.2 }
|
|
11462
|
-
},
|
|
11463
|
-
zhipu: { "glm-4-plus": { input: 0.7, output: 0.7 } },
|
|
11464
|
-
moonshot: { "moonshot-v1-8k": { input: 1.68, output: 1.68 } },
|
|
11465
|
-
xiaomi: {},
|
|
11466
|
-
custom: {},
|
|
11467
|
-
env: {}
|
|
11468
|
-
},
|
|
11469
|
-
fallback: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }
|
|
11470
|
-
};
|
|
11471
|
-
function zeroAgg() {
|
|
11472
|
-
return {
|
|
11473
|
-
calls: 0,
|
|
11474
|
-
input: 0,
|
|
11475
|
-
output: 0,
|
|
11476
|
-
cacheRead: 0,
|
|
11477
|
-
cacheWrite: 0,
|
|
11478
|
-
costUsd: 0,
|
|
11479
|
-
unpriced: 0
|
|
11480
|
-
};
|
|
11481
|
-
}
|
|
11482
|
-
function addAgg(into, tokens, costUsd) {
|
|
11483
|
-
into.calls += 1;
|
|
11484
|
-
into.input += tokens.input;
|
|
11485
|
-
into.output += tokens.output;
|
|
11486
|
-
into.cacheRead += tokens.cacheRead;
|
|
11487
|
-
into.cacheWrite += tokens.cacheWrite;
|
|
11488
|
-
if (costUsd == null) into.unpriced += 1;
|
|
11489
|
-
else into.costUsd += costUsd;
|
|
11490
|
-
}
|
|
11491
|
-
function utcDay(iso) {
|
|
11492
|
-
return iso.slice(0, 10);
|
|
11493
|
-
}
|
|
11494
|
-
function monthOf(iso) {
|
|
11495
|
-
return iso.slice(0, 7);
|
|
11496
|
-
}
|
|
11497
|
-
function retainedMonths(now = /* @__PURE__ */ new Date()) {
|
|
11498
|
-
const out = /* @__PURE__ */ new Set();
|
|
11499
|
-
const d = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));
|
|
11500
|
-
for (let i = 0; i < LEDGER_RETENTION_MONTHS; i += 1) {
|
|
11501
|
-
out.add(d.toISOString().slice(0, 7));
|
|
11502
|
-
d.setUTCMonth(d.getUTCMonth() - 1);
|
|
11503
|
-
}
|
|
11504
|
-
return out;
|
|
11505
|
-
}
|
|
11506
|
-
function atomicWrite(file, content) {
|
|
11507
|
-
fs20.mkdirSync(path24.dirname(file), { recursive: true });
|
|
11508
|
-
const tmp = `${file}.tmp`;
|
|
11509
|
-
fs20.writeFileSync(tmp, content, "utf-8");
|
|
11510
|
-
fs20.renameSync(tmp, file);
|
|
11511
|
-
}
|
|
11512
|
-
var UsageLedger = class {
|
|
11513
|
-
constructor(root) {
|
|
11514
|
-
this.root = root;
|
|
11515
|
-
this.dir = path24.join(root, "usage");
|
|
11516
|
-
}
|
|
11517
|
-
root;
|
|
11518
|
-
dir;
|
|
11519
|
-
rollup;
|
|
11520
|
-
pricing;
|
|
11521
|
-
rollupDirty = false;
|
|
11522
|
-
rollupTimer = null;
|
|
11523
|
-
inited = false;
|
|
11524
|
-
get ledgerDir() {
|
|
11525
|
-
return this.dir;
|
|
11526
|
-
}
|
|
11527
|
-
ledgerFile(month) {
|
|
11528
|
-
return path24.join(this.ledgerDir, `ledger-${month}.jsonl`);
|
|
11529
|
-
}
|
|
11530
|
-
get rollupFile() {
|
|
11531
|
-
return path24.join(this.ledgerDir, "rollup.json");
|
|
11532
|
-
}
|
|
11533
|
-
get pricingFile() {
|
|
11534
|
-
return path24.join(this.ledgerDir, "pricing.json");
|
|
11535
|
-
}
|
|
11536
|
-
// ===================== 初始化 =====================
|
|
11537
|
-
init(now = /* @__PURE__ */ new Date()) {
|
|
11538
|
-
if (this.inited) return;
|
|
11539
|
-
fs20.mkdirSync(this.ledgerDir, { recursive: true });
|
|
11540
|
-
this.pricing = this.loadPricing();
|
|
11541
|
-
this.rollup = this.loadRollup(now);
|
|
11542
|
-
this.pruneLedgers(now);
|
|
11543
|
-
this.inited = true;
|
|
11544
|
-
}
|
|
11545
|
-
loadPricing() {
|
|
11546
|
-
try {
|
|
11547
|
-
const raw = fs20.readFileSync(this.pricingFile, "utf-8");
|
|
11548
|
-
const parsed = JSON.parse(raw);
|
|
11549
|
-
const vendors = {};
|
|
11550
|
-
for (const v of /* @__PURE__ */ new Set([
|
|
11551
|
-
...Object.keys(DEFAULT_PRICING.vendors),
|
|
11552
|
-
...Object.keys(parsed.vendors ?? {})
|
|
11553
|
-
])) {
|
|
11554
|
-
vendors[v] = {
|
|
11555
|
-
...DEFAULT_PRICING.vendors[v] ?? {},
|
|
11556
|
-
...(parsed.vendors ?? {})[v] ?? {}
|
|
11557
|
-
};
|
|
11558
|
-
}
|
|
11559
|
-
return {
|
|
11560
|
-
schema: USAGE_SCHEMA,
|
|
11561
|
-
base: "USD",
|
|
11562
|
-
rate: { ...DEFAULT_PRICING.rate, ...parsed.rate ?? {} },
|
|
11563
|
-
vendors,
|
|
11564
|
-
fallback: { ...DEFAULT_PRICING.fallback, ...parsed.fallback ?? {} }
|
|
11565
|
-
};
|
|
11566
|
-
} catch {
|
|
11567
|
-
try {
|
|
11568
|
-
atomicWrite(this.pricingFile, JSON.stringify(DEFAULT_PRICING, null, 2));
|
|
11569
|
-
} catch {
|
|
11570
|
-
}
|
|
11571
|
-
return JSON.parse(JSON.stringify(DEFAULT_PRICING));
|
|
11572
|
-
}
|
|
11573
|
-
}
|
|
11574
|
-
loadRollup(now) {
|
|
11575
|
-
try {
|
|
11576
|
-
const raw = fs20.readFileSync(this.rollupFile, "utf-8");
|
|
11577
|
-
const parsed = JSON.parse(raw);
|
|
11578
|
-
return {
|
|
11579
|
-
schema: USAGE_SCHEMA,
|
|
11580
|
-
since: parsed.since ?? now.toISOString(),
|
|
11581
|
-
legacy: parsed.legacy,
|
|
11582
|
-
total: { ...zeroAgg(), ...parsed.total },
|
|
11583
|
-
byDay: parsed.byDay ?? {},
|
|
11584
|
-
byModel: parsed.byModel ?? {},
|
|
11585
|
-
byProject: parsed.byProject ?? {}
|
|
11586
|
-
};
|
|
11587
|
-
} catch {
|
|
11588
|
-
return {
|
|
11589
|
-
schema: USAGE_SCHEMA,
|
|
11590
|
-
since: now.toISOString(),
|
|
11591
|
-
total: zeroAgg(),
|
|
11592
|
-
byDay: {},
|
|
11593
|
-
byModel: {},
|
|
11594
|
-
byProject: {}
|
|
11264
|
+
schema: USAGE_SCHEMA,
|
|
11265
|
+
since: now.toISOString(),
|
|
11266
|
+
total: zeroAgg(),
|
|
11267
|
+
byDay: {},
|
|
11268
|
+
byModel: {},
|
|
11269
|
+
byProject: {}
|
|
11595
11270
|
};
|
|
11596
11271
|
}
|
|
11597
11272
|
}
|
|
@@ -11600,10 +11275,10 @@ var UsageLedger = class {
|
|
|
11600
11275
|
const keep = retainedMonths(now);
|
|
11601
11276
|
let changed = false;
|
|
11602
11277
|
try {
|
|
11603
|
-
for (const f of
|
|
11278
|
+
for (const f of fs19.readdirSync(this.ledgerDir)) {
|
|
11604
11279
|
const m = /^ledger-(\d{4}-\d{2})\.jsonl$/.exec(f);
|
|
11605
11280
|
if (m && !keep.has(m[1])) {
|
|
11606
|
-
|
|
11281
|
+
fs19.unlinkSync(path22.join(this.ledgerDir, f));
|
|
11607
11282
|
}
|
|
11608
11283
|
}
|
|
11609
11284
|
} catch {
|
|
@@ -11680,7 +11355,7 @@ var UsageLedger = class {
|
|
|
11680
11355
|
};
|
|
11681
11356
|
const line = JSON.stringify(rec) + "\n";
|
|
11682
11357
|
try {
|
|
11683
|
-
|
|
11358
|
+
fs19.appendFileSync(this.ledgerFile(monthOf(rec.ts)), line);
|
|
11684
11359
|
} catch (e) {
|
|
11685
11360
|
console.error(`[usage] \u5199\u8D26\u672C\u5931\u8D25: ${String(e)}`);
|
|
11686
11361
|
}
|
|
@@ -11852,10 +11527,10 @@ var UsageLedger = class {
|
|
|
11852
11527
|
const rows = [];
|
|
11853
11528
|
for (const month of months) {
|
|
11854
11529
|
const file = this.ledgerFile(month);
|
|
11855
|
-
if (!
|
|
11530
|
+
if (!fs19.existsSync(file)) continue;
|
|
11856
11531
|
let content = "";
|
|
11857
11532
|
try {
|
|
11858
|
-
content =
|
|
11533
|
+
content = fs19.readFileSync(file, "utf-8");
|
|
11859
11534
|
} catch {
|
|
11860
11535
|
continue;
|
|
11861
11536
|
}
|
|
@@ -11964,10 +11639,10 @@ var UsageLedger = class {
|
|
|
11964
11639
|
const seen = /* @__PURE__ */ new Set();
|
|
11965
11640
|
for (const month of this.monthsInRange("", "")) {
|
|
11966
11641
|
const file = this.ledgerFile(month);
|
|
11967
|
-
if (!
|
|
11642
|
+
if (!fs19.existsSync(file)) continue;
|
|
11968
11643
|
let content = "";
|
|
11969
11644
|
try {
|
|
11970
|
-
content =
|
|
11645
|
+
content = fs19.readFileSync(file, "utf-8");
|
|
11971
11646
|
} catch {
|
|
11972
11647
|
continue;
|
|
11973
11648
|
}
|
|
@@ -13278,7 +12953,7 @@ data: ${JSON.stringify(entry.data)}
|
|
|
13278
12953
|
softThresholdPct: parseRatio(process.env.COMPACTION_SOFT_THRESHOLD_PCT),
|
|
13279
12954
|
capTokens: parseOptionalPositiveNumber(process.env.COMPACTION_CAP_TOKENS) ?? null,
|
|
13280
12955
|
// 超预算工具结果按租户/工作区隔离落盘(多租户共用一个状态目录会混内容)
|
|
13281
|
-
toolResultDir:
|
|
12956
|
+
toolResultDir: path23.join(workspace, ".agent", "tool-results")
|
|
13282
12957
|
});
|
|
13283
12958
|
engine.setApprover(this._makeApprover(rt));
|
|
13284
12959
|
const mcpConfigs = loadServerMcpConfigs(tenant);
|
|
@@ -13452,132 +13127,912 @@ var ApiError = class extends Error {
|
|
|
13452
13127
|
this.status = status;
|
|
13453
13128
|
this.code = code;
|
|
13454
13129
|
}
|
|
13455
|
-
status;
|
|
13456
|
-
code;
|
|
13457
|
-
};
|
|
13458
|
-
|
|
13459
|
-
// src/server/
|
|
13460
|
-
|
|
13461
|
-
|
|
13462
|
-
|
|
13130
|
+
status;
|
|
13131
|
+
code;
|
|
13132
|
+
};
|
|
13133
|
+
|
|
13134
|
+
// src/server/projects.ts
|
|
13135
|
+
var DEFAULT_MODEL = () => process.env.OPENAI_MODEL || process.env.MODEL || "gpt-4o";
|
|
13136
|
+
function toProjectSummary(store, tenant) {
|
|
13137
|
+
return {
|
|
13138
|
+
id: tenant.id,
|
|
13139
|
+
name: tenant.name ?? tenant.id,
|
|
13140
|
+
model: tenant.model,
|
|
13141
|
+
baseURL: tenant.provider?.baseURL ?? "",
|
|
13142
|
+
hasApiKey: Boolean(tenant.provider?.apiKey),
|
|
13143
|
+
workspaceRoot: tenant.workspaceRoot ?? null,
|
|
13144
|
+
sessionCount: store.listSessions(tenant.id).length
|
|
13145
|
+
};
|
|
13146
|
+
}
|
|
13147
|
+
function providerViews(tenant) {
|
|
13148
|
+
return {
|
|
13149
|
+
activeProviderId: tenant.activeProviderId ?? null,
|
|
13150
|
+
providers: (tenant.llmProviders ?? []).map((p) => ({
|
|
13151
|
+
id: p.id,
|
|
13152
|
+
name: p.name,
|
|
13153
|
+
type: p.type ?? "",
|
|
13154
|
+
baseURL: p.baseURL,
|
|
13155
|
+
model: p.model,
|
|
13156
|
+
models: p.models ?? [],
|
|
13157
|
+
modelMeta: p.modelMeta ?? [],
|
|
13158
|
+
hasApiKey: Boolean(p.apiKey)
|
|
13159
|
+
}))
|
|
13160
|
+
};
|
|
13161
|
+
}
|
|
13162
|
+
function applyProvidersPatch(tenant, raw) {
|
|
13163
|
+
if (Array.isArray(raw.providers)) {
|
|
13164
|
+
const existing = new Map((tenant.llmProviders ?? []).map((p) => [p.id, p]));
|
|
13165
|
+
const next = [];
|
|
13166
|
+
for (const item of raw.providers) {
|
|
13167
|
+
if (!item || typeof item !== "object") continue;
|
|
13168
|
+
const o = item;
|
|
13169
|
+
const id = String(o.id ?? "").trim() || newId();
|
|
13170
|
+
const prev = existing.get(id);
|
|
13171
|
+
const apiKey = typeof o.apiKey === "string" && o.apiKey.trim() ? o.apiKey.trim() : prev?.apiKey;
|
|
13172
|
+
const models = normalizeModelList(o.models) ?? prev?.models;
|
|
13173
|
+
const modelMeta = normalizeModelMeta(o.modelMeta) ?? prev?.modelMeta;
|
|
13174
|
+
next.push({
|
|
13175
|
+
id,
|
|
13176
|
+
name: String(o.name ?? "").trim() || id,
|
|
13177
|
+
type: typeof o.type === "string" ? o.type : prev?.type,
|
|
13178
|
+
baseURL: String(o.baseURL ?? "").trim(),
|
|
13179
|
+
model: String(o.model ?? "").trim(),
|
|
13180
|
+
...apiKey ? { apiKey } : {},
|
|
13181
|
+
...models ? { models } : {},
|
|
13182
|
+
...modelMeta ? { modelMeta } : {}
|
|
13183
|
+
});
|
|
13184
|
+
}
|
|
13185
|
+
tenant.llmProviders = next;
|
|
13186
|
+
}
|
|
13187
|
+
if (typeof raw.activeProviderId === "string") {
|
|
13188
|
+
const activeId = raw.activeProviderId.trim();
|
|
13189
|
+
tenant.activeProviderId = activeId || void 0;
|
|
13190
|
+
const entry = (tenant.llmProviders ?? []).find((p) => p.id === activeId);
|
|
13191
|
+
if (entry) {
|
|
13192
|
+
tenant.provider = tenant.provider ?? {};
|
|
13193
|
+
tenant.provider.baseURL = entry.baseURL || void 0;
|
|
13194
|
+
if (entry.apiKey) tenant.provider.apiKey = entry.apiKey;
|
|
13195
|
+
if (entry.model) tenant.model = entry.model;
|
|
13196
|
+
}
|
|
13197
|
+
}
|
|
13198
|
+
}
|
|
13199
|
+
function allProjectSummaries(store) {
|
|
13200
|
+
return store.listTenants().map((id) => store.loadTenant(id)).filter((t) => t !== null).map((t) => toProjectSummary(store, t));
|
|
13201
|
+
}
|
|
13202
|
+
function lastUserMessage(rec) {
|
|
13203
|
+
const sent = (rec.lastInput ?? "").trim();
|
|
13204
|
+
if (sent) {
|
|
13205
|
+
return sent.length > LAST_USER_MESSAGE_MAX ? `${sent.slice(0, LAST_USER_MESSAGE_MAX)}\u2026` : sent;
|
|
13206
|
+
}
|
|
13207
|
+
const msgs = rec.messages;
|
|
13208
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
13209
|
+
const m = msgs[i];
|
|
13210
|
+
if (!m || m.role !== "user" || typeof m.content !== "string") continue;
|
|
13211
|
+
const text = m.content.trim();
|
|
13212
|
+
if (!text) continue;
|
|
13213
|
+
return text.length > LAST_USER_MESSAGE_MAX ? `${text.slice(0, LAST_USER_MESSAGE_MAX)}\u2026` : text;
|
|
13214
|
+
}
|
|
13215
|
+
return null;
|
|
13216
|
+
}
|
|
13217
|
+
function lastCompletedAt(rec) {
|
|
13218
|
+
if (rec.lastCompletedAt) return rec.lastCompletedAt;
|
|
13219
|
+
if (rec.status !== "completed") return null;
|
|
13220
|
+
const msgs = rec.messages;
|
|
13221
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
13222
|
+
const m = msgs[i];
|
|
13223
|
+
if (!m || m.role !== "assistant") continue;
|
|
13224
|
+
if (typeof m.ts === "number" && Number.isFinite(m.ts)) {
|
|
13225
|
+
return new Date(m.ts).toISOString();
|
|
13226
|
+
}
|
|
13227
|
+
return null;
|
|
13228
|
+
}
|
|
13229
|
+
return null;
|
|
13230
|
+
}
|
|
13231
|
+
function allSessionStates(store, manager) {
|
|
13232
|
+
const out = [];
|
|
13233
|
+
for (const id of store.listTenants()) {
|
|
13234
|
+
const t = store.loadTenant(id);
|
|
13235
|
+
if (!t) continue;
|
|
13236
|
+
try {
|
|
13237
|
+
for (const s of manager.listSessions(t.id)) {
|
|
13238
|
+
out.push({
|
|
13239
|
+
projectId: t.id,
|
|
13240
|
+
projectName: t.name ?? t.id,
|
|
13241
|
+
sessionId: s.sessionId,
|
|
13242
|
+
name: s.name ?? null,
|
|
13243
|
+
status: s.status,
|
|
13244
|
+
lastUserMessage: lastUserMessage(s),
|
|
13245
|
+
lastCompletedAt: lastCompletedAt(s)
|
|
13246
|
+
});
|
|
13247
|
+
}
|
|
13248
|
+
} catch {
|
|
13249
|
+
}
|
|
13250
|
+
}
|
|
13251
|
+
return out;
|
|
13252
|
+
}
|
|
13253
|
+
function ensureNodeId(store) {
|
|
13254
|
+
let id = store.loadNodeId();
|
|
13255
|
+
if (!id) {
|
|
13256
|
+
id = newId();
|
|
13257
|
+
store.saveNodeId(id);
|
|
13258
|
+
}
|
|
13259
|
+
return id;
|
|
13260
|
+
}
|
|
13261
|
+
function createProject(store, input) {
|
|
13262
|
+
const raw = input ?? {};
|
|
13263
|
+
const id = String(raw.id ?? "").trim() || newId();
|
|
13264
|
+
if (store.loadTenant(id)) {
|
|
13265
|
+
throw new ApiError(409, "project_exists", `\u9879\u76EE ${id} \u5DF2\u5B58\u5728`);
|
|
13266
|
+
}
|
|
13267
|
+
const workspaceRoot = typeof raw.workspaceRoot === "string" && raw.workspaceRoot.trim() ? path24.resolve(raw.workspaceRoot.trim()) : void 0;
|
|
13268
|
+
const explicitName = typeof raw.name === "string" && raw.name.trim() ? raw.name.trim() : "";
|
|
13269
|
+
const defaultName = workspaceRoot ? path24.basename(workspaceRoot) : id;
|
|
13270
|
+
const tenant = {
|
|
13271
|
+
id,
|
|
13272
|
+
name: explicitName || defaultName,
|
|
13273
|
+
apiKey: generateApiKey(),
|
|
13274
|
+
model: typeof raw.model === "string" && raw.model.trim() ? raw.model.trim() : DEFAULT_MODEL(),
|
|
13275
|
+
provider: {
|
|
13276
|
+
apiKey: typeof raw.providerApiKey === "string" && raw.providerApiKey.trim() ? raw.providerApiKey.trim() : void 0,
|
|
13277
|
+
baseURL: typeof raw.baseURL === "string" && raw.baseURL.trim() ? raw.baseURL.trim() : void 0
|
|
13278
|
+
},
|
|
13279
|
+
workspaceRoot,
|
|
13280
|
+
allowedCommands: Array.isArray(raw.allowedCommands) ? raw.allowedCommands.map((c) => String(c)) : []
|
|
13281
|
+
};
|
|
13282
|
+
const def = nodeDefaultProvider(store);
|
|
13283
|
+
if (def) {
|
|
13284
|
+
if (!tenant.provider?.apiKey && def.apiKey) tenant.provider = { ...tenant.provider, apiKey: def.apiKey };
|
|
13285
|
+
if (!tenant.provider?.baseURL && def.baseURL) tenant.provider = { ...tenant.provider, baseURL: def.baseURL };
|
|
13286
|
+
if (!(typeof raw.model === "string" && raw.model.trim()) && def.model) tenant.model = def.model;
|
|
13287
|
+
const nodeCfg = store.loadNodeLlm();
|
|
13288
|
+
tenant.llmProviders = nodeCfg.providers.map((p) => ({ ...p }));
|
|
13289
|
+
tenant.activeProviderId = nodeCfg.defaultProviderId ?? nodeCfg.providers[0]?.id;
|
|
13290
|
+
}
|
|
13291
|
+
store.saveTenant(tenant);
|
|
13292
|
+
return tenant;
|
|
13293
|
+
}
|
|
13294
|
+
function buildNodeInfo(store, opts) {
|
|
13295
|
+
return {
|
|
13296
|
+
nodeId: opts.nodeId ?? ensureNodeId(store),
|
|
13297
|
+
platform: process.platform,
|
|
13298
|
+
mode: process.env.NODE_MODE ?? "standalone",
|
|
13299
|
+
version: "0.2.12",
|
|
13300
|
+
admin: opts.admin,
|
|
13301
|
+
projects: opts.projects
|
|
13302
|
+
};
|
|
13303
|
+
}
|
|
13304
|
+
|
|
13305
|
+
// src/server/fleet-config.ts
|
|
13306
|
+
init_esm_shims();
|
|
13307
|
+
function fleetConfigFromEnv(store) {
|
|
13308
|
+
const fleetToken = process.env.FLEET_TOKEN;
|
|
13309
|
+
const fleetSecret = process.env.FLEET_SECRET;
|
|
13310
|
+
if (!fleetToken || !fleetSecret) return null;
|
|
13311
|
+
return {
|
|
13312
|
+
hubUrl: process.env.HUB_URL,
|
|
13313
|
+
fleetToken,
|
|
13314
|
+
fleetSecret,
|
|
13315
|
+
nodeId: ensureNodeId(store),
|
|
13316
|
+
gatewayUrl: process.env.FLEET_GATEWAY_URL
|
|
13317
|
+
};
|
|
13318
|
+
}
|
|
13319
|
+
function resolveFleetConfig(store) {
|
|
13320
|
+
const saved = store.loadFleetCredential();
|
|
13321
|
+
if (saved?.fleetToken && saved.fleetSecret) {
|
|
13322
|
+
return { ...saved, nodeId: saved.nodeId || ensureNodeId(store) };
|
|
13323
|
+
}
|
|
13324
|
+
return fleetConfigFromEnv(store);
|
|
13325
|
+
}
|
|
13326
|
+
|
|
13327
|
+
// src/cli/account-enroll.ts
|
|
13328
|
+
var SKIP_ANSWERS = /* @__PURE__ */ new Set(["-", "skip", "none", "no"]);
|
|
13329
|
+
function resolveDefaultHub(hubUrl, env3 = process.env) {
|
|
13330
|
+
return (hubUrl ?? env3.HUB_URL ?? DEFAULT_HUB_URL).trim().replace(/\/$/, "");
|
|
13331
|
+
}
|
|
13332
|
+
function parseHubAnswer(answer, fallback) {
|
|
13333
|
+
const a = answer.trim();
|
|
13334
|
+
if (SKIP_ANSWERS.has(a.toLowerCase())) return null;
|
|
13335
|
+
return (a || fallback).replace(/\/$/, "");
|
|
13336
|
+
}
|
|
13337
|
+
async function promptHubUrl(rl2, hubUrl) {
|
|
13338
|
+
const fallback = resolveDefaultHub(hubUrl);
|
|
13339
|
+
const answer = await rl2.question(`Hub \u5730\u5740 [${fallback}]\uFF1A`);
|
|
13340
|
+
return parseHubAnswer(answer, fallback);
|
|
13341
|
+
}
|
|
13342
|
+
async function promptAccountLogin(rl2, hubUrl) {
|
|
13343
|
+
cliLog("\u767B\u5F55\u65B9\u5F0F\uFF1A1) \u90AE\u7BB1 + \u5BC6\u7801 2) \u624B\u673A\u53F7 + \u5BC6\u7801 3) \u624B\u673A\u53F7 + \u77ED\u4FE1\u9A8C\u8BC1\u7801");
|
|
13344
|
+
const mode = (await rl2.question("\u8BF7\u9009\u62E9 [1]\uFF1A")).trim() || "1";
|
|
13345
|
+
const input = {};
|
|
13346
|
+
if (mode === "1") {
|
|
13347
|
+
input.email = (await rl2.question("\u90AE\u7BB1\uFF1A")).trim();
|
|
13348
|
+
input.password = await askHidden(rl2, "\u5BC6\u7801\uFF1A");
|
|
13349
|
+
if (!input.email || !input.password) {
|
|
13350
|
+
cliErr("\u90AE\u7BB1\u4E0E\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
13351
|
+
return null;
|
|
13352
|
+
}
|
|
13353
|
+
} else if (mode === "2") {
|
|
13354
|
+
input.phone = (await rl2.question("\u624B\u673A\u53F7\uFF1A")).trim();
|
|
13355
|
+
input.password = await askHidden(rl2, "\u5BC6\u7801\uFF1A");
|
|
13356
|
+
if (!input.phone || !input.password) {
|
|
13357
|
+
cliErr("\u624B\u673A\u53F7\u4E0E\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
13358
|
+
return null;
|
|
13359
|
+
}
|
|
13360
|
+
} else if (mode === "3") {
|
|
13361
|
+
input.phone = (await rl2.question("\u624B\u673A\u53F7\uFF1A")).trim();
|
|
13362
|
+
if (!input.phone) {
|
|
13363
|
+
cliErr("\u624B\u673A\u53F7\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
13364
|
+
return null;
|
|
13365
|
+
}
|
|
13366
|
+
try {
|
|
13367
|
+
const sent = await hubSendSms(resolveDefaultHub(hubUrl), {
|
|
13368
|
+
phone: input.phone,
|
|
13369
|
+
purpose: "login"
|
|
13370
|
+
});
|
|
13371
|
+
if (sent.debugCode) cliLog(`\uFF08\u8C03\u8BD5\u6A21\u5F0F\u9A8C\u8BC1\u7801\uFF1A${sent.debugCode}\uFF09`);
|
|
13372
|
+
else cliLog("\u9A8C\u8BC1\u7801\u5DF2\u53D1\u9001\uFF0C5 \u5206\u949F\u5185\u6709\u6548\u3002");
|
|
13373
|
+
} catch (e) {
|
|
13374
|
+
cliErr(`\u77ED\u4FE1\u9A8C\u8BC1\u7801\u53D1\u9001\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
13375
|
+
cliLog(" \u53EF\u6539\u7528\u65B9\u5F0F 1/2\uFF08\u5BC6\u7801\u767B\u5F55\uFF09\uFF0C\u6216\u5728\u7F51\u9875\u7AEF\u751F\u6210\u63A5\u5165\u7801\u540E\u6267\u884C\uFF1A");
|
|
13376
|
+
cliLog(" zqagent link --hub <Hub\u5730\u5740> --code <\u63A5\u5165\u7801>");
|
|
13377
|
+
return null;
|
|
13378
|
+
}
|
|
13379
|
+
input.code = (await rl2.question("\u77ED\u4FE1\u9A8C\u8BC1\u7801\uFF1A")).trim();
|
|
13380
|
+
if (!input.code) {
|
|
13381
|
+
cliErr("\u9A8C\u8BC1\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
13382
|
+
return null;
|
|
13383
|
+
}
|
|
13384
|
+
} else {
|
|
13385
|
+
cliErr("\u672A\u77E5\u7684\u767B\u5F55\u65B9\u5F0F\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
13386
|
+
return null;
|
|
13387
|
+
}
|
|
13388
|
+
return input;
|
|
13389
|
+
}
|
|
13390
|
+
async function promptLinkAccount(rl2, hubUrl, opts = {}) {
|
|
13391
|
+
const fallback = resolveDefaultHub(hubUrl);
|
|
13392
|
+
let resolved = fallback;
|
|
13393
|
+
if (opts.askHub !== false) {
|
|
13394
|
+
const answer = await promptHubUrl(rl2, fallback);
|
|
13395
|
+
if (!answer) {
|
|
13396
|
+
cliLog("\u5DF2\u8DF3\u8FC7\u63A5\u5165\uFF1A\u8282\u70B9\u4FDD\u6301\u7EAF\u672C\u5730\u8FD0\u884C\u3002");
|
|
13397
|
+
return null;
|
|
13398
|
+
}
|
|
13399
|
+
resolved = answer;
|
|
13400
|
+
}
|
|
13401
|
+
const auth = await promptAccountLogin(rl2, resolved);
|
|
13402
|
+
if (!auth) return null;
|
|
13403
|
+
return { hubUrl: resolved, auth };
|
|
13404
|
+
}
|
|
13405
|
+
async function promptPassword(rl2, prompt = "\u5BC6\u7801\uFF1A") {
|
|
13406
|
+
return askHidden(rl2, prompt);
|
|
13407
|
+
}
|
|
13408
|
+
function resolveDataDir(dataDir) {
|
|
13409
|
+
return path25.resolve(dataDir ?? process.env.DATA_DIR ?? DEFAULT_DATA_DIR);
|
|
13410
|
+
}
|
|
13411
|
+
async function maybeAccountEnroll(opts = {}) {
|
|
13412
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) return;
|
|
13413
|
+
let store;
|
|
13414
|
+
try {
|
|
13415
|
+
store = new Store(resolveDataDir(opts.dataDir));
|
|
13416
|
+
if (resolveFleetConfig(store)) return;
|
|
13417
|
+
} catch (e) {
|
|
13418
|
+
cliErr(`\u63A5\u5165\u68C0\u67E5\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
13419
|
+
return;
|
|
13420
|
+
}
|
|
13421
|
+
const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
13422
|
+
try {
|
|
13423
|
+
await runWizard(rl2, store, opts);
|
|
13424
|
+
} catch (e) {
|
|
13425
|
+
cliErr(`\u63A5\u5165\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
13426
|
+
cliLog(" \u53EF\u7A0D\u540E\u5728\u63A7\u5236\u53F0\u751F\u6210\u63A5\u5165\u7801\uFF0C\u518D\u6267\u884C\uFF1Azqagent link --hub <Hub\u5730\u5740> --code <\u63A5\u5165\u7801>");
|
|
13427
|
+
} finally {
|
|
13428
|
+
rl2.close();
|
|
13429
|
+
}
|
|
13430
|
+
}
|
|
13431
|
+
async function runWizard(rl2, store, opts) {
|
|
13432
|
+
cliLog("");
|
|
13433
|
+
cliLog("\u672C\u673A\u5C1A\u672A\u63A5\u5165 Hub\u3002\u53EF\u7528 Hub \u8D26\u53F7\u63A5\u5165\uFF08\u8282\u70B9\u9ED8\u8BA4\u8FDB\u5165\u300C\u672A\u5206\u7EC4\u300D\uFF09\uFF1B\u8F93\u5165 - \u8DF3\u8FC7\u4FDD\u6301\u7EAF\u672C\u5730\u3002");
|
|
13434
|
+
const prompted = await promptLinkAccount(rl2, opts.hubUrl);
|
|
13435
|
+
if (!prompted) return;
|
|
13436
|
+
const nodeId = ensureNodeId(store);
|
|
13437
|
+
const cred = await hubEnrollByAccount(prompted.hubUrl, {
|
|
13438
|
+
...prompted.auth,
|
|
13439
|
+
nodeId,
|
|
13440
|
+
label: opts.label
|
|
13441
|
+
});
|
|
13442
|
+
store.saveFleetCredential({
|
|
13443
|
+
...cred,
|
|
13444
|
+
label: opts.label ?? cred.label,
|
|
13445
|
+
enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
13446
|
+
});
|
|
13447
|
+
cliLog(`\u2705 \u5DF2\u63A5\u5165 Hub\uFF1A\u8282\u70B9 ${cred.nodeId}\uFF08\u7F51\u5173 ${cred.gatewayUrl ?? "\u672A\u4E0B\u53D1"}\uFF09`);
|
|
13448
|
+
cliLog(" \u51ED\u636E\u5DF2\u4FDD\u5B58\u5230 fleet.json\uFF0C\u672C\u6B21\u542F\u52A8\u5373\u8FDE\u63A5 Hub\u3002");
|
|
13449
|
+
}
|
|
13450
|
+
async function askHidden(rl2, prompt) {
|
|
13451
|
+
if (!process.stdin.isTTY) return (await rl2.question(prompt)).trim();
|
|
13452
|
+
return new Promise((resolve24) => {
|
|
13453
|
+
const saved = process.stdin.listeners("data");
|
|
13454
|
+
process.stdin.removeAllListeners("data");
|
|
13455
|
+
cliWrite(prompt);
|
|
13456
|
+
rl2.pause();
|
|
13457
|
+
process.stdin.setRawMode(true);
|
|
13458
|
+
process.stdin.resume();
|
|
13459
|
+
let buf = "";
|
|
13460
|
+
const cleanup = () => {
|
|
13461
|
+
process.stdin.removeListener("data", onData);
|
|
13462
|
+
for (const listener of saved) {
|
|
13463
|
+
process.stdin.on("data", listener);
|
|
13464
|
+
}
|
|
13465
|
+
process.stdin.setRawMode(true);
|
|
13466
|
+
rl2.resume();
|
|
13467
|
+
};
|
|
13468
|
+
const onData = (chunk) => {
|
|
13469
|
+
const s = chunk.toString().replace(/\x1b\[[0-9;?]*[A-Za-z~]/g, "").replace(/\x1bO[A-Za-z]/g, "");
|
|
13470
|
+
for (const ch of s) {
|
|
13471
|
+
if (ch === "\r" || ch === "\n") {
|
|
13472
|
+
cleanup();
|
|
13473
|
+
cliWrite("\n");
|
|
13474
|
+
resolve24(buf);
|
|
13475
|
+
return;
|
|
13476
|
+
}
|
|
13477
|
+
if (ch === "") {
|
|
13478
|
+
cleanup();
|
|
13479
|
+
cliWrite("\n");
|
|
13480
|
+
resolve24("");
|
|
13481
|
+
return;
|
|
13482
|
+
}
|
|
13483
|
+
if (ch === "\x7F" || ch === "\b") {
|
|
13484
|
+
if (buf.length > 0) {
|
|
13485
|
+
buf = buf.slice(0, -1);
|
|
13486
|
+
cliWrite("\b \b");
|
|
13487
|
+
}
|
|
13488
|
+
} else if (ch >= " ") {
|
|
13489
|
+
buf += ch;
|
|
13490
|
+
cliWrite("*");
|
|
13491
|
+
}
|
|
13492
|
+
}
|
|
13493
|
+
};
|
|
13494
|
+
process.stdin.on("data", onData);
|
|
13495
|
+
});
|
|
13496
|
+
}
|
|
13497
|
+
|
|
13498
|
+
// src/cli/serve-instances.ts
|
|
13499
|
+
init_esm_shims();
|
|
13500
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
13501
|
+
import * as fs21 from "fs";
|
|
13502
|
+
import * as os5 from "os";
|
|
13503
|
+
import * as path27 from "path";
|
|
13504
|
+
|
|
13505
|
+
// src/update/platform.ts
|
|
13506
|
+
init_esm_shims();
|
|
13507
|
+
import * as fs20 from "fs";
|
|
13508
|
+
import * as os4 from "os";
|
|
13509
|
+
import * as path26 from "path";
|
|
13510
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
13511
|
+
import { createRequire as createRequire3 } from "module";
|
|
13512
|
+
function currentVersion() {
|
|
13513
|
+
const injected = "0.2.12"?.trim();
|
|
13514
|
+
if (injected) return injected;
|
|
13515
|
+
try {
|
|
13516
|
+
const req2 = createRequire3(import.meta.url);
|
|
13517
|
+
const pkg = req2("../../package.json");
|
|
13518
|
+
if (pkg?.version) return pkg.version;
|
|
13519
|
+
} catch {
|
|
13520
|
+
}
|
|
13521
|
+
return "dev";
|
|
13522
|
+
}
|
|
13523
|
+
function isSeaRuntime() {
|
|
13524
|
+
if (process.env.ZQAGENT_SEA === "1") return true;
|
|
13525
|
+
const base = path26.basename(process.execPath).toLowerCase().replace(/\.exe$/, "");
|
|
13526
|
+
return base !== "node" && base !== "nodejs";
|
|
13527
|
+
}
|
|
13528
|
+
var DEFAULT_SERVICE_NAME = "zqagent";
|
|
13529
|
+
var DEFAULT_SERVICE_LABEL = "com.zqagent.node";
|
|
13530
|
+
function serviceManagerFromCgroup(cgroup, serviceName = DEFAULT_SERVICE_NAME) {
|
|
13531
|
+
const unitName = `${serviceName}.service`;
|
|
13532
|
+
for (const line of cgroup.split("\n")) {
|
|
13533
|
+
const idx = line.lastIndexOf(":");
|
|
13534
|
+
if (idx < 0) continue;
|
|
13535
|
+
const unitPath = line.slice(idx + 1).trim();
|
|
13536
|
+
if (unitPath.split("/").includes(unitName)) return "systemd";
|
|
13537
|
+
}
|
|
13538
|
+
return null;
|
|
13539
|
+
}
|
|
13540
|
+
function launchdDomain() {
|
|
13541
|
+
const uid = typeof process.getuid === "function" ? process.getuid() : -1;
|
|
13542
|
+
return uid === 0 ? "system" : `gui/${uid}`;
|
|
13543
|
+
}
|
|
13544
|
+
function launchdLabel() {
|
|
13545
|
+
return process.env.ZQAGENT_SERVICE_LABEL?.trim() || DEFAULT_SERVICE_LABEL;
|
|
13546
|
+
}
|
|
13547
|
+
function launchdPlistPath() {
|
|
13548
|
+
const label = launchdLabel();
|
|
13549
|
+
const uid = typeof process.getuid === "function" ? process.getuid() : -1;
|
|
13550
|
+
if (uid === 0) return `/Library/LaunchDaemons/${label}.plist`;
|
|
13551
|
+
return path26.join(os4.homedir(), "Library", "LaunchAgents", `${label}.plist`);
|
|
13552
|
+
}
|
|
13553
|
+
function serviceManagerFromLaunchctl(output, pid, execPath, sea = true) {
|
|
13554
|
+
const pidMatch = /^\s*pid = (\d+)\s*$/m.exec(output);
|
|
13555
|
+
if (pidMatch && Number(pidMatch[1]) === pid) return "launchd";
|
|
13556
|
+
const program = /^\s*program = (.+?)\s*$/m.exec(output);
|
|
13557
|
+
if (program) {
|
|
13558
|
+
const shown = program[1].replace(/^"|"$/g, "");
|
|
13559
|
+
if (path26.resolve(shown) === path26.resolve(execPath)) return "launchd";
|
|
13560
|
+
}
|
|
13561
|
+
if (!sea && /^\s*state = /m.test(output)) return "launchd";
|
|
13562
|
+
return null;
|
|
13563
|
+
}
|
|
13564
|
+
function parseLaunchdEnvironment(xml) {
|
|
13565
|
+
const out = {};
|
|
13566
|
+
const marker = xml.indexOf("<key>EnvironmentVariables</key>");
|
|
13567
|
+
if (marker < 0) return out;
|
|
13568
|
+
const open = xml.indexOf("<dict>", marker);
|
|
13569
|
+
if (open < 0) return out;
|
|
13570
|
+
const close = xml.indexOf("</dict>", open);
|
|
13571
|
+
if (close < 0) return out;
|
|
13572
|
+
const body = xml.slice(open + "<dict>".length, close);
|
|
13573
|
+
for (const m of body.matchAll(/<key>([^<]+)<\/key>\s*<string>([^<]*)<\/string>/g)) {
|
|
13574
|
+
out[m[1]] = m[2];
|
|
13575
|
+
}
|
|
13576
|
+
return out;
|
|
13577
|
+
}
|
|
13578
|
+
function detectServiceManager() {
|
|
13579
|
+
if (process.platform === "darwin") return detectLaunchd();
|
|
13580
|
+
if (process.platform !== "linux") return null;
|
|
13581
|
+
const serviceName = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME;
|
|
13582
|
+
try {
|
|
13583
|
+
return serviceManagerFromCgroup(
|
|
13584
|
+
fs20.readFileSync("/proc/self/cgroup", "utf8"),
|
|
13585
|
+
serviceName
|
|
13586
|
+
);
|
|
13587
|
+
} catch {
|
|
13588
|
+
return null;
|
|
13589
|
+
}
|
|
13590
|
+
}
|
|
13591
|
+
function detectLaunchd() {
|
|
13592
|
+
try {
|
|
13593
|
+
const res = spawnSync2(
|
|
13594
|
+
"launchctl",
|
|
13595
|
+
["print", `${launchdDomain()}/${launchdLabel()}`],
|
|
13596
|
+
{ encoding: "utf8", timeout: 3e3 }
|
|
13597
|
+
);
|
|
13598
|
+
if (res.status !== 0 || !res.stdout) return null;
|
|
13599
|
+
return serviceManagerFromLaunchctl(
|
|
13600
|
+
res.stdout,
|
|
13601
|
+
process.pid,
|
|
13602
|
+
process.execPath,
|
|
13603
|
+
isSeaRuntime()
|
|
13604
|
+
);
|
|
13605
|
+
} catch {
|
|
13606
|
+
return null;
|
|
13607
|
+
}
|
|
13608
|
+
}
|
|
13609
|
+
function serviceManager() {
|
|
13610
|
+
const v = process.env.ZQAGENT_SERVICE_MANAGER?.trim().toLowerCase();
|
|
13611
|
+
if (v === "systemd" || v === "launchd") return v;
|
|
13612
|
+
return detectServiceManager();
|
|
13613
|
+
}
|
|
13614
|
+
function parseServiceEnvironment(raw) {
|
|
13615
|
+
const out = {};
|
|
13616
|
+
for (const token of raw.trim().split(/\s+/)) {
|
|
13617
|
+
const idx = token.indexOf("=");
|
|
13618
|
+
if (idx > 0) out[token.slice(0, idx)] = token.slice(idx + 1);
|
|
13619
|
+
}
|
|
13620
|
+
return out;
|
|
13621
|
+
}
|
|
13622
|
+
var cachedServiceEnv = null;
|
|
13623
|
+
function readServiceEnvironment() {
|
|
13624
|
+
const serviceName = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME;
|
|
13625
|
+
try {
|
|
13626
|
+
const res = spawnSync2(
|
|
13627
|
+
"systemctl",
|
|
13628
|
+
["show", serviceName, "--property=Environment", "--value", "--no-pager"],
|
|
13629
|
+
{ encoding: "utf8", timeout: 3e3 }
|
|
13630
|
+
);
|
|
13631
|
+
if (res.status !== 0 || !res.stdout) return {};
|
|
13632
|
+
return parseServiceEnvironment(res.stdout);
|
|
13633
|
+
} catch {
|
|
13634
|
+
return {};
|
|
13635
|
+
}
|
|
13636
|
+
}
|
|
13637
|
+
function serviceEnvValue(key) {
|
|
13638
|
+
if (process.platform === "darwin") {
|
|
13639
|
+
if (serviceManager() !== "launchd") return void 0;
|
|
13640
|
+
cachedLaunchdEnv ??= readLaunchdEnvironment();
|
|
13641
|
+
return cachedLaunchdEnv[key];
|
|
13642
|
+
}
|
|
13643
|
+
if (process.platform !== "linux") return void 0;
|
|
13644
|
+
if (serviceManager() !== "systemd") return void 0;
|
|
13645
|
+
cachedServiceEnv ??= readServiceEnvironment();
|
|
13646
|
+
return cachedServiceEnv[key];
|
|
13647
|
+
}
|
|
13648
|
+
var cachedLaunchdEnv = null;
|
|
13649
|
+
function readLaunchdEnvironment() {
|
|
13650
|
+
try {
|
|
13651
|
+
return parseLaunchdEnvironment(fs20.readFileSync(launchdPlistPath(), "utf8"));
|
|
13652
|
+
} catch {
|
|
13653
|
+
return {};
|
|
13654
|
+
}
|
|
13655
|
+
}
|
|
13656
|
+
function selfUpdateCapability(hasPublicKey) {
|
|
13657
|
+
if (!isSeaRuntime()) {
|
|
13658
|
+
return {
|
|
13659
|
+
ok: false,
|
|
13660
|
+
reason: "\u5F53\u524D\u4E0D\u662F\u5355\u6587\u4EF6\uFF08SEA\uFF09\u5F62\u6001\uFF1A\u8BF7\u7528 npm \u5347\u7EA7\uFF08npm i -g @zqagent/core@latest\uFF09"
|
|
13661
|
+
};
|
|
13662
|
+
}
|
|
13663
|
+
if (!serviceManager()) {
|
|
13664
|
+
return {
|
|
13665
|
+
ok: false,
|
|
13666
|
+
reason: "\u672A\u88AB systemd/launchd \u6258\u7BA1\uFF1A\u8BF7\u7528 deploy/service/install.sh \u5B89\u88C5\uFF0C\u6216\u624B\u52A8\u5347\u7EA7"
|
|
13667
|
+
};
|
|
13668
|
+
}
|
|
13669
|
+
if (!hasPublicKey) {
|
|
13670
|
+
return { ok: false, reason: "\u672A\u914D\u7F6E ZQAGENT_UPDATE_PUBKEY\uFF0C\u65E0\u6CD5\u9A8C\u7B7E\uFF0C\u5DF2\u7981\u7528\u81EA\u52A8\u66F4\u65B0" };
|
|
13671
|
+
}
|
|
13672
|
+
return { ok: true };
|
|
13673
|
+
}
|
|
13463
13674
|
|
|
13464
|
-
// src/
|
|
13465
|
-
|
|
13466
|
-
|
|
13467
|
-
var
|
|
13468
|
-
|
|
13469
|
-
|
|
13470
|
-
|
|
13471
|
-
|
|
13472
|
-
|
|
13473
|
-
|
|
13474
|
-
|
|
13475
|
-
|
|
13476
|
-
|
|
13675
|
+
// src/cli/serve-instances.ts
|
|
13676
|
+
var DEFAULT_SERVE_HOST = "127.0.0.1";
|
|
13677
|
+
var DEFAULT_SERVE_PORT = 8787;
|
|
13678
|
+
var DEFAULT_SERVICE_NAME2 = "zqagent";
|
|
13679
|
+
var DEFAULT_SERVICE_LABEL2 = "com.zqagent.node";
|
|
13680
|
+
function serveSubcommandIndex(argv) {
|
|
13681
|
+
for (let i = 1; i < argv.length; i++) {
|
|
13682
|
+
if (argv[i].startsWith("-")) continue;
|
|
13683
|
+
return argv[i] === "serve" ? i : -1;
|
|
13684
|
+
}
|
|
13685
|
+
return -1;
|
|
13686
|
+
}
|
|
13687
|
+
function parseServeArgs(argv) {
|
|
13688
|
+
const at = serveSubcommandIndex(argv);
|
|
13689
|
+
if (at < 0) return null;
|
|
13690
|
+
let dataDir = null;
|
|
13691
|
+
let host = DEFAULT_SERVE_HOST;
|
|
13692
|
+
let port = DEFAULT_SERVE_PORT;
|
|
13693
|
+
for (let i = at + 1; i < argv.length; i++) {
|
|
13694
|
+
const arg = argv[i];
|
|
13695
|
+
if (arg === "--data-dir" && argv[i + 1]) {
|
|
13696
|
+
dataDir = argv[++i];
|
|
13697
|
+
} else if (arg.startsWith("--data-dir=")) {
|
|
13698
|
+
dataDir = arg.slice("--data-dir=".length);
|
|
13699
|
+
} else if (arg === "--host" && argv[i + 1]) {
|
|
13700
|
+
host = argv[++i];
|
|
13701
|
+
} else if (arg.startsWith("--host=")) {
|
|
13702
|
+
host = arg.slice("--host=".length);
|
|
13703
|
+
} else if (arg === "--port" && argv[i + 1]) {
|
|
13704
|
+
port = Number(argv[++i]);
|
|
13705
|
+
} else if (arg.startsWith("--port=")) {
|
|
13706
|
+
port = Number(arg.slice("--port=".length));
|
|
13707
|
+
}
|
|
13708
|
+
}
|
|
13709
|
+
if (!Number.isFinite(port) || port <= 0) port = DEFAULT_SERVE_PORT;
|
|
13710
|
+
if (host === "0.0.0.0" || host === "::" || host === "") host = DEFAULT_SERVE_HOST;
|
|
13711
|
+
return { dataDir, host, port };
|
|
13712
|
+
}
|
|
13713
|
+
function buildHotCandidates(explicitDataDir, discovered, fallback) {
|
|
13714
|
+
const out = [];
|
|
13715
|
+
const push = (inst) => {
|
|
13716
|
+
if (!out.some((o) => o.dataDir === inst.dataDir)) out.push(inst);
|
|
13477
13717
|
};
|
|
13718
|
+
if (explicitDataDir) push({ dataDir: path27.resolve(explicitDataDir), ...fallback });
|
|
13719
|
+
for (const inst of discovered) if (inst.managed) push(inst);
|
|
13720
|
+
for (const inst of discovered) if (!inst.managed) push(inst);
|
|
13721
|
+
if (!explicitDataDir) push({ dataDir: path27.resolve(DEFAULT_DATA_DIR), ...fallback });
|
|
13722
|
+
return out;
|
|
13478
13723
|
}
|
|
13479
|
-
function
|
|
13724
|
+
function isWindowsAbsolute(p) {
|
|
13725
|
+
return /^[A-Za-z]:[\\/]/.test(p) || /^\\\\/.test(p);
|
|
13726
|
+
}
|
|
13727
|
+
function isAbsolutePath(p) {
|
|
13728
|
+
return path27.isAbsolute(p) || isWindowsAbsolute(p);
|
|
13729
|
+
}
|
|
13730
|
+
function normalizePath(p) {
|
|
13731
|
+
return isWindowsAbsolute(p) ? path27.win32.normalize(p) : path27.normalize(p);
|
|
13732
|
+
}
|
|
13733
|
+
function parseServeCommandLine(line) {
|
|
13734
|
+
if (!/(?:^|\s)["']?serve["']?(?=\s|$)/.test(line)) return null;
|
|
13735
|
+
const m = /--data-dir(?:=|\s+)(?:"([^"]+)"|'([^']+)'|(.+?))(?=\s+--\w|\s*$)/.exec(line);
|
|
13736
|
+
const rawDataDir = (m?.[1] ?? m?.[2] ?? m?.[3] ?? "").trim();
|
|
13737
|
+
if (!rawDataDir || !isAbsolutePath(rawDataDir)) return null;
|
|
13738
|
+
const host = /--host(?:=|\s+)(?:"([^"]+)"|'([^']+)'|(\S+))/.exec(line);
|
|
13739
|
+
const rawHost = (host?.[1] ?? host?.[2] ?? host?.[3] ?? DEFAULT_SERVE_HOST).trim();
|
|
13740
|
+
const portMatch = /--port(?:=|\s+)(\d+)/.exec(line);
|
|
13741
|
+
const port = Number(portMatch?.[1] ?? DEFAULT_SERVE_PORT);
|
|
13480
13742
|
return {
|
|
13481
|
-
|
|
13482
|
-
|
|
13483
|
-
|
|
13484
|
-
name: p.name,
|
|
13485
|
-
type: p.type ?? "",
|
|
13486
|
-
baseURL: p.baseURL,
|
|
13487
|
-
model: p.model,
|
|
13488
|
-
models: p.models ?? [],
|
|
13489
|
-
modelMeta: p.modelMeta ?? [],
|
|
13490
|
-
hasApiKey: Boolean(p.apiKey)
|
|
13491
|
-
}))
|
|
13743
|
+
dataDir: normalizePath(rawDataDir),
|
|
13744
|
+
host: rawHost === "0.0.0.0" || rawHost === "::" || rawHost === "" ? DEFAULT_SERVE_HOST : rawHost,
|
|
13745
|
+
port: Number.isFinite(port) && port > 0 ? port : DEFAULT_SERVE_PORT
|
|
13492
13746
|
};
|
|
13493
13747
|
}
|
|
13494
|
-
function
|
|
13495
|
-
|
|
13496
|
-
|
|
13497
|
-
|
|
13498
|
-
|
|
13499
|
-
|
|
13500
|
-
|
|
13501
|
-
|
|
13502
|
-
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
|
|
13508
|
-
name: String(o.name ?? "").trim() || id,
|
|
13509
|
-
type: typeof o.type === "string" ? o.type : prev?.type,
|
|
13510
|
-
baseURL: String(o.baseURL ?? "").trim(),
|
|
13511
|
-
model: String(o.model ?? "").trim(),
|
|
13512
|
-
...apiKey ? { apiKey } : {},
|
|
13513
|
-
...models ? { models } : {},
|
|
13514
|
-
...modelMeta ? { modelMeta } : {}
|
|
13515
|
-
});
|
|
13748
|
+
function processCwd(pid) {
|
|
13749
|
+
try {
|
|
13750
|
+
return fs21.readlinkSync(`/proc/${pid}/cwd`);
|
|
13751
|
+
} catch {
|
|
13752
|
+
return null;
|
|
13753
|
+
}
|
|
13754
|
+
}
|
|
13755
|
+
function processEnv(pid) {
|
|
13756
|
+
const out = {};
|
|
13757
|
+
try {
|
|
13758
|
+
const raw = fs21.readFileSync(`/proc/${pid}/environ`, "utf-8");
|
|
13759
|
+
for (const entry of raw.split("\0")) {
|
|
13760
|
+
const eq = entry.indexOf("=");
|
|
13761
|
+
if (eq > 0) out[entry.slice(0, eq)] = entry.slice(eq + 1);
|
|
13516
13762
|
}
|
|
13517
|
-
|
|
13763
|
+
} catch {
|
|
13518
13764
|
}
|
|
13519
|
-
|
|
13520
|
-
|
|
13521
|
-
|
|
13522
|
-
|
|
13523
|
-
|
|
13524
|
-
|
|
13525
|
-
|
|
13526
|
-
|
|
13527
|
-
|
|
13765
|
+
return out;
|
|
13766
|
+
}
|
|
13767
|
+
function resolveDataDir2(rawDataDir, cwd, env3) {
|
|
13768
|
+
const pick = rawDataDir ?? env3.DATA_DIR ?? null;
|
|
13769
|
+
if (pick) return path27.isAbsolute(pick) ? path27.normalize(pick) : cwd ? path27.resolve(cwd, pick) : null;
|
|
13770
|
+
return cwd ? path27.resolve(cwd, DEFAULT_DATA_DIR) : null;
|
|
13771
|
+
}
|
|
13772
|
+
function isManagedBySystemd(pid, env3) {
|
|
13773
|
+
if (env3.ZQAGENT_SERVICE_MANAGER?.trim()) return true;
|
|
13774
|
+
try {
|
|
13775
|
+
const cgroup = fs21.readFileSync(`/proc/${pid}/cgroup`, "utf-8");
|
|
13776
|
+
const serviceName = env3.ZQAGENT_SERVICE_NAME?.trim() || "zqagent";
|
|
13777
|
+
return serviceManagerFromCgroup(cgroup, serviceName) !== null;
|
|
13778
|
+
} catch {
|
|
13779
|
+
return false;
|
|
13780
|
+
}
|
|
13781
|
+
}
|
|
13782
|
+
function discoverFromProc() {
|
|
13783
|
+
const out = [];
|
|
13784
|
+
let pids;
|
|
13785
|
+
try {
|
|
13786
|
+
pids = fs21.readdirSync("/proc");
|
|
13787
|
+
} catch {
|
|
13788
|
+
return out;
|
|
13789
|
+
}
|
|
13790
|
+
for (const name of pids) {
|
|
13791
|
+
if (!/^\d+$/.test(name)) continue;
|
|
13792
|
+
const pid = Number(name);
|
|
13793
|
+
if (pid === process.pid) continue;
|
|
13794
|
+
let argv;
|
|
13795
|
+
let env3;
|
|
13796
|
+
try {
|
|
13797
|
+
argv = fs21.readFileSync(`/proc/${pid}/cmdline`, "utf-8").split("\0").filter(Boolean);
|
|
13798
|
+
env3 = processEnv(pid);
|
|
13799
|
+
} catch {
|
|
13800
|
+
continue;
|
|
13528
13801
|
}
|
|
13802
|
+
const parsed = parseServeArgs(argv);
|
|
13803
|
+
if (!parsed) continue;
|
|
13804
|
+
const dataDir = resolveDataDir2(parsed.dataDir, processCwd(pid), env3);
|
|
13805
|
+
if (!dataDir) continue;
|
|
13806
|
+
out.push({
|
|
13807
|
+
dataDir,
|
|
13808
|
+
host: parsed.host,
|
|
13809
|
+
port: parsed.port,
|
|
13810
|
+
managed: isManagedBySystemd(pid, env3)
|
|
13811
|
+
});
|
|
13529
13812
|
}
|
|
13813
|
+
return out;
|
|
13530
13814
|
}
|
|
13531
|
-
function
|
|
13532
|
-
|
|
13815
|
+
function discoverFromPs() {
|
|
13816
|
+
const out = [];
|
|
13817
|
+
const res = spawnSync3("ps", ["-axo", "command="], { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] });
|
|
13818
|
+
if (res.status !== 0 || !res.stdout) return out;
|
|
13819
|
+
for (const line of res.stdout.split("\n")) {
|
|
13820
|
+
const inst = parseServeCommandLine(line);
|
|
13821
|
+
if (inst) out.push(inst);
|
|
13822
|
+
}
|
|
13823
|
+
return out;
|
|
13533
13824
|
}
|
|
13534
|
-
function
|
|
13535
|
-
const
|
|
13536
|
-
|
|
13537
|
-
|
|
13825
|
+
function discoverFromWindows() {
|
|
13826
|
+
const out = [];
|
|
13827
|
+
const script = `[Console]::OutputEncoding=[Text.Encoding]::UTF8; Get-CimInstance Win32_Process -Filter "Name='zqagent.exe' OR Name='node.exe'" | ForEach-Object { $_.CommandLine }`;
|
|
13828
|
+
const res = spawnSync3(
|
|
13829
|
+
"powershell.exe",
|
|
13830
|
+
["-NoProfile", "-NonInteractive", "-Command", script],
|
|
13831
|
+
{ encoding: "utf-8", timeout: 15e3, windowsHide: true, stdio: ["ignore", "pipe", "ignore"] }
|
|
13832
|
+
);
|
|
13833
|
+
if (res.status !== 0 || !res.stdout) return out;
|
|
13834
|
+
for (const line of res.stdout.replace(/^\uFEFF/, "").split(/\r?\n/)) {
|
|
13835
|
+
const inst = parseServeCommandLine(line);
|
|
13836
|
+
if (inst) out.push(inst);
|
|
13538
13837
|
}
|
|
13539
|
-
|
|
13540
|
-
|
|
13541
|
-
|
|
13542
|
-
|
|
13543
|
-
|
|
13544
|
-
|
|
13545
|
-
|
|
13838
|
+
return out;
|
|
13839
|
+
}
|
|
13840
|
+
function decodeXmlEntities(s) {
|
|
13841
|
+
return s.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, "&");
|
|
13842
|
+
}
|
|
13843
|
+
function parseLaunchdProgramArguments(xml) {
|
|
13844
|
+
const marker = xml.indexOf("<key>ProgramArguments</key>");
|
|
13845
|
+
if (marker < 0) return [];
|
|
13846
|
+
const open = xml.indexOf("<array>", marker);
|
|
13847
|
+
if (open < 0) return [];
|
|
13848
|
+
const close = xml.indexOf("</array>", open);
|
|
13849
|
+
if (close < 0) return [];
|
|
13850
|
+
return [...xml.slice(open + "<array>".length, close).matchAll(/<string>([^<]*)<\/string>/g)].map(
|
|
13851
|
+
(m) => decodeXmlEntities(m[1])
|
|
13852
|
+
);
|
|
13853
|
+
}
|
|
13854
|
+
function launchdServiceInstances() {
|
|
13855
|
+
if (process.platform !== "darwin") return [];
|
|
13856
|
+
const label = process.env.ZQAGENT_SERVICE_LABEL?.trim() || DEFAULT_SERVICE_LABEL2;
|
|
13857
|
+
const plists = [
|
|
13858
|
+
`/Library/LaunchDaemons/${label}.plist`,
|
|
13859
|
+
path27.join(os5.homedir(), "Library", "LaunchAgents", `${label}.plist`)
|
|
13860
|
+
];
|
|
13861
|
+
const out = [];
|
|
13862
|
+
for (const plist of plists) {
|
|
13863
|
+
let xml;
|
|
13864
|
+
try {
|
|
13865
|
+
xml = fs21.readFileSync(plist, "utf-8");
|
|
13866
|
+
} catch {
|
|
13867
|
+
continue;
|
|
13868
|
+
}
|
|
13869
|
+
const parsed = parseServeArgs(parseLaunchdProgramArguments(xml));
|
|
13870
|
+
if (!parsed?.dataDir || !isAbsolutePath(parsed.dataDir)) continue;
|
|
13871
|
+
out.push({
|
|
13872
|
+
dataDir: normalizePath(parsed.dataDir),
|
|
13873
|
+
host: parsed.host,
|
|
13874
|
+
port: parsed.port,
|
|
13875
|
+
managed: true
|
|
13876
|
+
});
|
|
13546
13877
|
}
|
|
13547
|
-
return
|
|
13878
|
+
return out;
|
|
13548
13879
|
}
|
|
13549
|
-
function
|
|
13550
|
-
|
|
13551
|
-
|
|
13552
|
-
|
|
13553
|
-
for (
|
|
13554
|
-
const
|
|
13555
|
-
if (
|
|
13556
|
-
|
|
13557
|
-
|
|
13880
|
+
function parseSystemdUnit(text) {
|
|
13881
|
+
let dataDir = null;
|
|
13882
|
+
let host = DEFAULT_SERVE_HOST;
|
|
13883
|
+
let port = DEFAULT_SERVE_PORT;
|
|
13884
|
+
for (const line of text.split("\n")) {
|
|
13885
|
+
const trimmed = line.trim();
|
|
13886
|
+
if (trimmed.startsWith("WorkingDirectory=")) {
|
|
13887
|
+
const v = trimmed.slice("WorkingDirectory=".length).trim();
|
|
13888
|
+
if (v && isAbsolutePath(v)) dataDir = v;
|
|
13889
|
+
} else if (trimmed.startsWith("ExecStart=")) {
|
|
13890
|
+
const tokens = trimmed.slice("ExecStart=".length).trim().split(/\s+/).map((t) => t.replace(/^["']|["']$/g, ""));
|
|
13891
|
+
const parsed = parseServeArgs(tokens);
|
|
13892
|
+
if (!parsed) continue;
|
|
13893
|
+
if (parsed.dataDir && isAbsolutePath(parsed.dataDir)) dataDir = parsed.dataDir;
|
|
13894
|
+
host = parsed.host;
|
|
13895
|
+
port = parsed.port;
|
|
13896
|
+
}
|
|
13897
|
+
}
|
|
13898
|
+
if (!dataDir) return null;
|
|
13899
|
+
return { dataDir: normalizePath(dataDir), host, port, managed: true };
|
|
13900
|
+
}
|
|
13901
|
+
function systemdServiceInstances() {
|
|
13902
|
+
if (process.platform !== "linux") return [];
|
|
13903
|
+
const unit = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME2;
|
|
13904
|
+
const configHome = process.env.XDG_CONFIG_HOME?.trim() || path27.join(os5.homedir(), ".config");
|
|
13905
|
+
const units = [
|
|
13906
|
+
`/etc/systemd/system/${unit}.service`,
|
|
13907
|
+
path27.join(configHome, "systemd", "user", `${unit}.service`)
|
|
13908
|
+
];
|
|
13909
|
+
const out = [];
|
|
13910
|
+
for (const file of units) {
|
|
13911
|
+
let text;
|
|
13912
|
+
try {
|
|
13913
|
+
text = fs21.readFileSync(file, "utf-8");
|
|
13914
|
+
} catch {
|
|
13915
|
+
continue;
|
|
13558
13916
|
}
|
|
13559
|
-
|
|
13917
|
+
const inst = parseSystemdUnit(text);
|
|
13918
|
+
if (inst) out.push(inst);
|
|
13919
|
+
}
|
|
13920
|
+
return out;
|
|
13921
|
+
}
|
|
13922
|
+
function windowsServiceInstances() {
|
|
13923
|
+
if (process.platform !== "win32") return [];
|
|
13924
|
+
const appdata = process.env.APPDATA?.trim();
|
|
13925
|
+
if (!appdata) return [];
|
|
13926
|
+
const base = path27.join(appdata, "zqagent");
|
|
13927
|
+
try {
|
|
13928
|
+
const raw = fs21.readFileSync(path27.join(base, "runtime", "service.json"), "utf-8");
|
|
13929
|
+
const v = JSON.parse(raw);
|
|
13930
|
+
const dataDir = v.dataDir && isAbsolutePath(v.dataDir) ? v.dataDir : base;
|
|
13931
|
+
const port = Number(v.port);
|
|
13932
|
+
return [
|
|
13933
|
+
{
|
|
13934
|
+
dataDir: normalizePath(dataDir),
|
|
13935
|
+
host: DEFAULT_SERVE_HOST,
|
|
13936
|
+
port: Number.isFinite(port) && port > 0 ? port : DEFAULT_SERVE_PORT,
|
|
13937
|
+
managed: true
|
|
13938
|
+
}
|
|
13939
|
+
];
|
|
13940
|
+
} catch {
|
|
13941
|
+
return [];
|
|
13942
|
+
}
|
|
13943
|
+
}
|
|
13944
|
+
function mergeServeInstances(discovered, managed) {
|
|
13945
|
+
const out = [];
|
|
13946
|
+
const push = (inst) => {
|
|
13947
|
+
if (!out.some((o) => o.dataDir === inst.dataDir)) out.push(inst);
|
|
13948
|
+
};
|
|
13949
|
+
for (const inst of discovered) {
|
|
13950
|
+
const hit = managed.find((m) => m.dataDir === inst.dataDir);
|
|
13951
|
+
push(hit ? { ...inst, managed: true } : inst);
|
|
13560
13952
|
}
|
|
13561
|
-
|
|
13953
|
+
for (const inst of managed) push(inst);
|
|
13954
|
+
return out;
|
|
13562
13955
|
}
|
|
13563
|
-
function
|
|
13564
|
-
const
|
|
13565
|
-
|
|
13566
|
-
|
|
13567
|
-
|
|
13568
|
-
|
|
13569
|
-
|
|
13570
|
-
|
|
13571
|
-
|
|
13572
|
-
|
|
13573
|
-
|
|
13574
|
-
|
|
13575
|
-
|
|
13576
|
-
|
|
13577
|
-
|
|
13578
|
-
|
|
13579
|
-
|
|
13580
|
-
|
|
13956
|
+
function discoverRunningServeInstances() {
|
|
13957
|
+
const found = process.platform === "linux" ? discoverFromProc() : process.platform === "win32" ? discoverFromWindows() : discoverFromPs();
|
|
13958
|
+
const declared = process.platform === "linux" ? systemdServiceInstances() : process.platform === "win32" ? windowsServiceInstances() : launchdServiceInstances();
|
|
13959
|
+
return mergeServeInstances(found, declared);
|
|
13960
|
+
}
|
|
13961
|
+
|
|
13962
|
+
// src/cli/link.ts
|
|
13963
|
+
function expandHome(p) {
|
|
13964
|
+
const home = process.env.HOME || process.env.USERPROFILE;
|
|
13965
|
+
if (!home) return p;
|
|
13966
|
+
if (p === "~") return home;
|
|
13967
|
+
if (p.startsWith("~/") || p.startsWith("~\\")) return path28.join(home, p.slice(2));
|
|
13968
|
+
return p;
|
|
13969
|
+
}
|
|
13970
|
+
function installDataDirHint() {
|
|
13971
|
+
if (process.platform === "darwin") return "$HOME/Library/Application Support/zqagent";
|
|
13972
|
+
if (process.platform === "win32") return "%APPDATA%\\zqagent";
|
|
13973
|
+
return "/var/lib/zqagent\uFF08\u9700 root\uFF1B\u666E\u901A\u7528\u6237\u7528 ~/.zqagent_data\uFF09";
|
|
13974
|
+
}
|
|
13975
|
+
function buildAccountAuth(flags, env3 = process.env) {
|
|
13976
|
+
const username = (flags.username ?? env3.ZQAGENT_HUB_USERNAME ?? "").trim();
|
|
13977
|
+
let email = (flags.email ?? "").trim();
|
|
13978
|
+
let phone = (flags.phone ?? "").trim();
|
|
13979
|
+
if (username && !email && !phone) {
|
|
13980
|
+
if (username.includes("@")) email = username;
|
|
13981
|
+
else phone = username;
|
|
13982
|
+
}
|
|
13983
|
+
if (!email && !phone) return null;
|
|
13984
|
+
const password = flags.password ?? env3.ZQAGENT_HUB_PASSWORD ?? "";
|
|
13985
|
+
const smsCode = (flags.smsCode ?? env3.ZQAGENT_HUB_SMS_CODE ?? "").trim();
|
|
13986
|
+
return {
|
|
13987
|
+
email: email ? email.toLowerCase() : void 0,
|
|
13988
|
+
phone: phone || void 0,
|
|
13989
|
+
password: password || void 0,
|
|
13990
|
+
smsCode: smsCode || void 0
|
|
13991
|
+
};
|
|
13992
|
+
}
|
|
13993
|
+
function isCompleteAccount(account) {
|
|
13994
|
+
return Boolean(account && (account.password || account.smsCode));
|
|
13995
|
+
}
|
|
13996
|
+
function parseLinkArgs(argv) {
|
|
13997
|
+
const out = {};
|
|
13998
|
+
for (let i = 0; i < argv.length; i++) {
|
|
13999
|
+
const a = argv[i];
|
|
14000
|
+
const val = argv[i + 1];
|
|
14001
|
+
if (a === "--hub") {
|
|
14002
|
+
out.hubUrl = val;
|
|
14003
|
+
i++;
|
|
14004
|
+
} else if (a === "--code") {
|
|
14005
|
+
out.code = val;
|
|
14006
|
+
i++;
|
|
14007
|
+
} else if (a === "--username" || a === "--user") {
|
|
14008
|
+
out.username = val;
|
|
14009
|
+
i++;
|
|
14010
|
+
} else if (a === "--email") {
|
|
14011
|
+
out.email = val;
|
|
14012
|
+
i++;
|
|
14013
|
+
} else if (a === "--phone") {
|
|
14014
|
+
out.phone = val;
|
|
14015
|
+
i++;
|
|
14016
|
+
} else if (a === "--password") {
|
|
14017
|
+
out.password = val;
|
|
14018
|
+
i++;
|
|
14019
|
+
} else if (a === "--sms-code") {
|
|
14020
|
+
out.smsCode = val;
|
|
14021
|
+
i++;
|
|
14022
|
+
} else if (a === "--data-dir") {
|
|
14023
|
+
out.dataDir = val;
|
|
14024
|
+
i++;
|
|
14025
|
+
} else if (a === "--label") {
|
|
14026
|
+
out.label = val;
|
|
14027
|
+
i++;
|
|
14028
|
+
} else if (a === "--host") {
|
|
14029
|
+
out.host = val;
|
|
14030
|
+
i++;
|
|
14031
|
+
} else if (a === "--port") {
|
|
14032
|
+
out.port = Number(val);
|
|
14033
|
+
i++;
|
|
14034
|
+
} else if (a === "-h" || a === "--help") {
|
|
14035
|
+
out.help = true;
|
|
13581
14036
|
}
|
|
13582
14037
|
}
|
|
13583
14038
|
return out;
|
|
@@ -13590,50 +14045,285 @@ function ensureNodeId2(store) {
|
|
|
13590
14045
|
}
|
|
13591
14046
|
return id;
|
|
13592
14047
|
}
|
|
13593
|
-
function
|
|
13594
|
-
const
|
|
13595
|
-
const
|
|
13596
|
-
|
|
13597
|
-
|
|
14048
|
+
async function probeServer(host, port, adminKey) {
|
|
14049
|
+
const ctrl = new AbortController();
|
|
14050
|
+
const timer = setTimeout(() => ctrl.abort(), 1500);
|
|
14051
|
+
try {
|
|
14052
|
+
const res = await fetch(`http://${host}:${port}/api/v1/fleet/status`, {
|
|
14053
|
+
headers: { Authorization: `Bearer ${adminKey}` },
|
|
14054
|
+
signal: ctrl.signal
|
|
14055
|
+
});
|
|
14056
|
+
return res.ok;
|
|
14057
|
+
} catch {
|
|
14058
|
+
return false;
|
|
14059
|
+
} finally {
|
|
14060
|
+
clearTimeout(timer);
|
|
13598
14061
|
}
|
|
13599
|
-
|
|
13600
|
-
|
|
13601
|
-
const
|
|
13602
|
-
|
|
13603
|
-
|
|
13604
|
-
|
|
13605
|
-
|
|
13606
|
-
model: typeof raw.model === "string" && raw.model.trim() ? raw.model.trim() : DEFAULT_MODEL(),
|
|
13607
|
-
provider: {
|
|
13608
|
-
apiKey: typeof raw.providerApiKey === "string" && raw.providerApiKey.trim() ? raw.providerApiKey.trim() : void 0,
|
|
13609
|
-
baseURL: typeof raw.baseURL === "string" && raw.baseURL.trim() ? raw.baseURL.trim() : void 0
|
|
14062
|
+
}
|
|
14063
|
+
async function enrollViaServer(host, port, adminKey, opts) {
|
|
14064
|
+
const res = await fetch(`http://${host}:${port}/api/v1/fleet/enroll`, {
|
|
14065
|
+
method: "POST",
|
|
14066
|
+
headers: {
|
|
14067
|
+
"Content-Type": "application/json",
|
|
14068
|
+
Authorization: `Bearer ${adminKey}`
|
|
13610
14069
|
},
|
|
13611
|
-
|
|
13612
|
-
|
|
13613
|
-
|
|
13614
|
-
|
|
13615
|
-
|
|
13616
|
-
|
|
13617
|
-
|
|
13618
|
-
|
|
13619
|
-
|
|
13620
|
-
|
|
13621
|
-
|
|
14070
|
+
body: JSON.stringify({
|
|
14071
|
+
hubUrl: opts.hubUrl,
|
|
14072
|
+
code: opts.code,
|
|
14073
|
+
email: opts.account?.email,
|
|
14074
|
+
phone: opts.account?.phone,
|
|
14075
|
+
password: opts.account?.password,
|
|
14076
|
+
smsCode: opts.account?.smsCode,
|
|
14077
|
+
label: opts.label
|
|
14078
|
+
})
|
|
14079
|
+
});
|
|
14080
|
+
const text = await res.text();
|
|
14081
|
+
let payload = null;
|
|
14082
|
+
try {
|
|
14083
|
+
payload = text ? JSON.parse(text) : null;
|
|
14084
|
+
} catch {
|
|
13622
14085
|
}
|
|
13623
|
-
|
|
13624
|
-
|
|
14086
|
+
if (!res.ok) {
|
|
14087
|
+
throw new Error(payload?.error?.message ?? `HTTP ${res.status}`);
|
|
14088
|
+
}
|
|
14089
|
+
return payload?.data;
|
|
13625
14090
|
}
|
|
13626
|
-
function
|
|
14091
|
+
function hotWarnings(inst, running) {
|
|
14092
|
+
const warnings = [];
|
|
14093
|
+
const managed = running.filter((r) => r.managed && r.dataDir !== inst.dataDir);
|
|
14094
|
+
if (!inst.managed && managed.length > 0) {
|
|
14095
|
+
warnings.push(
|
|
14096
|
+
`\u51ED\u636E\u5199\u5165\u4E86\u975E\u6258\u7BA1\u5B9E\u4F8B ${inst.dataDir}\uFF0C\u4F46\u672C\u673A\u6258\u7BA1\u670D\u52A1\u4F7F\u7528\u7684\u662F ${managed.map((m) => m.dataDir).join("\u3001")}\u3002`
|
|
14097
|
+
);
|
|
14098
|
+
warnings.push(
|
|
14099
|
+
"\u6258\u7BA1\u670D\u52A1\u8BFB\u4E0D\u5230\u8FD9\u4EFD\u51ED\u636E\uFF08\u91CD\u542F\u540E\u4E5F\u4E0D\u4F1A\u81EA\u52A8\u4E0A\u7EBF\uFF09\uFF0C\u8BF7\u7528 --data-dir \u6307\u5411\u5B83\u7684\u6570\u636E\u76EE\u5F55\u91CD\u65B0\u63A5\u5165\u3002"
|
|
14100
|
+
);
|
|
14101
|
+
}
|
|
14102
|
+
const others = [...new Set(running.map((r) => r.dataDir).filter((d) => d !== inst.dataDir))];
|
|
14103
|
+
if (others.length > 0) {
|
|
14104
|
+
warnings.push(`\u672C\u673A\u8FD8\u6709\u5176\u5B83\u8FD0\u884C\u4E2D\u7684\u8282\u70B9\u5B9E\u4F8B\uFF08\u672A\u5199\u5165\u51ED\u636E\uFF09\uFF1A${others.join("\u3001")}\u3002`);
|
|
14105
|
+
}
|
|
14106
|
+
return warnings;
|
|
14107
|
+
}
|
|
14108
|
+
async function linkNode(opts) {
|
|
14109
|
+
if (!opts.code && !isCompleteAccount(opts.account ?? null)) {
|
|
14110
|
+
throw new Error("\u7F3A\u5C11\u63A5\u5165\u7801\uFF0C\u6216 Hub \u8D26\u53F7\u5BC6\u7801/\u77ED\u4FE1\u9A8C\u8BC1\u7801");
|
|
14111
|
+
}
|
|
14112
|
+
const hubUrl = opts.hubUrl.trim().replace(/\/$/, "");
|
|
14113
|
+
if (!hubUrl) throw new Error("\u7F3A\u5C11 Hub \u5730\u5740");
|
|
14114
|
+
const rawDataDir = opts.dataDir?.trim() || process.env.DATA_DIR?.trim() || void 0;
|
|
14115
|
+
const explicitDataDir = rawDataDir ? expandHome(rawDataDir) : void 0;
|
|
14116
|
+
const host = opts.host?.trim() || process.env.HOST?.trim() || DEFAULT_SERVE_HOST;
|
|
14117
|
+
const port = opts.port ?? Number(process.env.PORT ?? DEFAULT_SERVE_PORT);
|
|
14118
|
+
const running = discoverRunningServeInstances();
|
|
14119
|
+
const candidates = buildHotCandidates(explicitDataDir, running, { host, port });
|
|
14120
|
+
for (const inst of candidates) {
|
|
14121
|
+
const store2 = new Store(inst.dataDir);
|
|
14122
|
+
const adminKey = process.env.ADMIN_API_KEY ?? store2.loadAdminKey();
|
|
14123
|
+
if (!adminKey) continue;
|
|
14124
|
+
if (!await probeServer(inst.host, inst.port, adminKey)) continue;
|
|
14125
|
+
const status = await enrollViaServer(inst.host, inst.port, adminKey, { ...opts, hubUrl });
|
|
14126
|
+
return {
|
|
14127
|
+
mode: "hot",
|
|
14128
|
+
...status,
|
|
14129
|
+
dataDir: inst.dataDir,
|
|
14130
|
+
managed: inst.managed,
|
|
14131
|
+
warnings: hotWarnings(inst, running)
|
|
14132
|
+
};
|
|
14133
|
+
}
|
|
14134
|
+
const managedDir = running.find((r) => r.managed)?.dataDir;
|
|
14135
|
+
const dataDir = path28.resolve(explicitDataDir ?? managedDir ?? DEFAULT_DATA_DIR);
|
|
14136
|
+
const targetedService = !explicitDataDir && Boolean(managedDir) && dataDir === managedDir;
|
|
14137
|
+
const store = new Store(dataDir);
|
|
14138
|
+
const nodeId = ensureNodeId2(store);
|
|
14139
|
+
const account = opts.account;
|
|
14140
|
+
const cred = account && isCompleteAccount(account) ? await hubEnrollByAccount(hubUrl, {
|
|
14141
|
+
email: account.email,
|
|
14142
|
+
phone: account.phone,
|
|
14143
|
+
password: account.password,
|
|
14144
|
+
code: account.smsCode,
|
|
14145
|
+
nodeId,
|
|
14146
|
+
label: opts.label
|
|
14147
|
+
}) : await hubEnrollByCode(hubUrl, {
|
|
14148
|
+
code: opts.code,
|
|
14149
|
+
nodeId,
|
|
14150
|
+
label: opts.label
|
|
14151
|
+
});
|
|
14152
|
+
try {
|
|
14153
|
+
store.saveFleetCredential({
|
|
14154
|
+
...cred,
|
|
14155
|
+
label: opts.label ?? cred.label,
|
|
14156
|
+
enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
14157
|
+
});
|
|
14158
|
+
} catch (e) {
|
|
14159
|
+
const err = e;
|
|
14160
|
+
if (err.code === "EACCES" || err.code === "EPERM") {
|
|
14161
|
+
throw new Error(
|
|
14162
|
+
`\u65E0\u6CD5\u5199\u5165\u6570\u636E\u76EE\u5F55 ${dataDir}\uFF08${err.code}: ${err.message}\uFF09
|
|
14163
|
+
\u8BE5\u76EE\u5F55\u5F53\u524D\u7528\u6237\u6CA1\u6709\u5199\u6743\u9650\u3002\u4E24\u79CD\u6539\u6CD5\uFF1A
|
|
14164
|
+
1) \u53BB\u6389 --data-dir\uFF0C\u8BA9 link \u81EA\u52A8\u53D1\u73B0\u672C\u673A\u8FD0\u884C\u7684\u8282\u70B9\uFF08\u63A8\u8350\uFF09\uFF1B
|
|
14165
|
+
2) \u7528\u5F53\u524D\u7528\u6237\u53EF\u5199\u7684\u76EE\u5F55\uFF0C\u672C\u5E73\u53F0\u5B89\u88C5\u811A\u672C\u9ED8\u8BA4\uFF1A${installDataDirHint()}
|
|
14166
|
+
\uFF08\u63A5\u5165\u7801\u4E00\u6B21\u6027\uFF0C\u9700\u8981\u91CD\u65B0\u751F\u6210\uFF1B\u8D26\u53F7\u65B9\u5F0F\u53EF\u91CD\u590D\u4F7F\u7528\uFF09`
|
|
14167
|
+
);
|
|
14168
|
+
}
|
|
14169
|
+
throw e;
|
|
14170
|
+
}
|
|
14171
|
+
const otherRunningDirs = [
|
|
14172
|
+
...new Set(running.map((r) => r.dataDir).filter((d) => d !== dataDir))
|
|
14173
|
+
];
|
|
13627
14174
|
return {
|
|
13628
|
-
|
|
13629
|
-
|
|
13630
|
-
|
|
13631
|
-
|
|
13632
|
-
|
|
13633
|
-
|
|
14175
|
+
mode: "saved",
|
|
14176
|
+
nodeId,
|
|
14177
|
+
gatewayUrl: cred.gatewayUrl,
|
|
14178
|
+
label: opts.label,
|
|
14179
|
+
dataDir,
|
|
14180
|
+
explicitDataDir: Boolean(explicitDataDir),
|
|
14181
|
+
runningServiceDirs: otherRunningDirs,
|
|
14182
|
+
targetedService
|
|
14183
|
+
};
|
|
14184
|
+
}
|
|
14185
|
+
function printLinkHelp() {
|
|
14186
|
+
cliLog("\u7528\u6CD5: zqagent link [--hub <url>] [--username <\u90AE\u7BB1/\u624B\u673A\u53F7> --password <\u5BC6\u7801>] [--label \u540D\u79F0]");
|
|
14187
|
+
cliLog(" zqagent link [--hub <url>] --code <\u4E00\u6B21\u6027\u63A5\u5165\u7801> [--label \u540D\u79F0]");
|
|
14188
|
+
cliLog(" \u65B9\u5F0F\u4E00\uFF08\u63A8\u8350\uFF09\uFF1A\u7528 Hub \u5DF2\u6CE8\u518C\u7684\u8D26\u53F7\u76F4\u63A5\u63A5\u5165\uFF1A");
|
|
14189
|
+
cliLog(" zqagent link --hub https://hub.cd-zq.com --username you@example.com --password '<\u5BC6\u7801>'");
|
|
14190
|
+
cliLog(" zqagent link --hub https://hub.cd-zq.com --username 13800000000 --password '<\u5BC6\u7801>'");
|
|
14191
|
+
cliLog(" zqagent link --hub https://hub.cd-zq.com --username 13800000000 --sms-code <\u9A8C\u8BC1\u7801>");
|
|
14192
|
+
cliLog(" \u65B9\u5F0F\u4E8C\uFF1A\u5728 Hub\u300C\u8282\u70B9\u7BA1\u7406\u300D\u751F\u6210\u4E00\u6B21\u6027\u63A5\u5165\u7801\uFF0815 \u5206\u949F\u6709\u6548\uFF09\uFF1A");
|
|
14193
|
+
cliLog(" zqagent link --hub https://hub.cd-zq.com --code <\u63A5\u5165\u7801>");
|
|
14194
|
+
cliLog(" \u4E0D\u5E26\u51ED\u636E\u53C2\u6570\u65F6\u8FDB\u5165\u4EA4\u4E92\u5411\u5BFC\uFF08\u9700\u7EC8\u7AEF\uFF09\uFF1B\u5BC6\u7801\u4E5F\u53EF\u7528 ZQAGENT_HUB_PASSWORD \u63D0\u4F9B\u3002");
|
|
14195
|
+
cliLog(" \u672C\u673A\u5DF2\u88C5\u8282\u70B9\u670D\u52A1\uFF08install.sh / \u684C\u9762\u7AEF\uFF09\u65F6\u4F1A\u81EA\u52A8\u53D1\u73B0\u5B83\u7684\u6570\u636E\u76EE\u5F55\u5E76\u70ED\u63A5\u5165\uFF0C");
|
|
14196
|
+
cliLog(" \u4E0D\u9700\u8981\u624B\u52A8\u6307\u5B9A --data-dir\uFF1B\u670D\u52A1\u6CA1\u5728\u8FD0\u884C\u65F6\u4F1A\u5199\u5165\u5B83\u7684\u76EE\u5F55\uFF0C\u4E0B\u6B21\u542F\u52A8\u5373\u63A5\u5165\u3002");
|
|
14197
|
+
cliLog(" \u4EC5\u5F53\u672C\u673A\u5B8C\u5168\u6CA1\u6709\u670D\u52A1\u65F6\u624D\u9700\u8981 --data-dir \u6307\u5B9A\u76EE\u5F55\uFF08\u4E0B\u6B21\u542F\u52A8 serve \u65F6\u751F\u6548\uFF09\u3002");
|
|
14198
|
+
}
|
|
14199
|
+
async function runLinkCommand(argv, ctx = {}) {
|
|
14200
|
+
const args = parseLinkArgs(argv);
|
|
14201
|
+
if (args.help) {
|
|
14202
|
+
printLinkHelp();
|
|
14203
|
+
return true;
|
|
14204
|
+
}
|
|
14205
|
+
const explicitHub = Boolean((args.hubUrl ?? process.env.HUB_URL ?? "").trim());
|
|
14206
|
+
let hubUrl = (args.hubUrl ?? process.env.HUB_URL ?? DEFAULT_HUB_URL).trim().replace(/\/$/, "");
|
|
14207
|
+
const code = (args.code ?? "").trim();
|
|
14208
|
+
let account = buildAccountAuth(args);
|
|
14209
|
+
const interactive = ctx.interactive ?? (process.stdin.isTTY && process.stdout.isTTY);
|
|
14210
|
+
if (code && account) {
|
|
14211
|
+
cliErr("--code \u4E0E Hub \u8D26\u53F7\uFF08--username/--email/--phone/--password\uFF09\u53EA\u80FD\u4E8C\u9009\u4E00\u3002");
|
|
14212
|
+
return false;
|
|
14213
|
+
}
|
|
14214
|
+
if (!account && (args.password || args.smsCode)) {
|
|
14215
|
+
cliErr("\u63D0\u4F9B\u4E86\u5BC6\u7801/\u77ED\u4FE1\u9A8C\u8BC1\u7801\uFF0C\u4F46\u7F3A\u5C11\u8D26\u53F7\uFF1A\u8BF7\u52A0 --username\u3001--email \u6216 --phone\u3002");
|
|
14216
|
+
return false;
|
|
14217
|
+
}
|
|
14218
|
+
const asPrompter = (rl2) => ({
|
|
14219
|
+
question: (q) => new Promise((resolve24) => rl2.question(q, resolve24)),
|
|
14220
|
+
pause: () => rl2.pause(),
|
|
14221
|
+
resume: () => rl2.resume()
|
|
14222
|
+
});
|
|
14223
|
+
let ownedRl = null;
|
|
14224
|
+
const getRl = () => {
|
|
14225
|
+
if (ctx.rl) return asPrompter(ctx.rl);
|
|
14226
|
+
if (!interactive) return null;
|
|
14227
|
+
ownedRl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
14228
|
+
return asPrompter(ownedRl);
|
|
13634
14229
|
};
|
|
14230
|
+
const closeOwnedRl = () => {
|
|
14231
|
+
if (ownedRl) ownedRl.close();
|
|
14232
|
+
};
|
|
14233
|
+
try {
|
|
14234
|
+
if (!code && !isCompleteAccount(account)) {
|
|
14235
|
+
const rl2 = getRl();
|
|
14236
|
+
if (!rl2) {
|
|
14237
|
+
cliErr("\u7F3A\u5C11\u63A5\u5165\u51ED\u636E\uFF1A\u8BF7\u7528 --username/--password\uFF0C\u6216 --code <\u63A5\u5165\u7801>\u3002");
|
|
14238
|
+
printLinkHelp();
|
|
14239
|
+
return false;
|
|
14240
|
+
}
|
|
14241
|
+
if (account) {
|
|
14242
|
+
const password = await promptPassword(rl2);
|
|
14243
|
+
if (!password) {
|
|
14244
|
+
cliErr("\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u53D6\u6D88\u63A5\u5165\u3002");
|
|
14245
|
+
return false;
|
|
14246
|
+
}
|
|
14247
|
+
account = { ...account, password };
|
|
14248
|
+
} else {
|
|
14249
|
+
const prompted = await promptLinkAccount(rl2, hubUrl, { askHub: !explicitHub });
|
|
14250
|
+
if (!prompted) return true;
|
|
14251
|
+
hubUrl = prompted.hubUrl;
|
|
14252
|
+
account = {
|
|
14253
|
+
email: prompted.auth.email,
|
|
14254
|
+
phone: prompted.auth.phone,
|
|
14255
|
+
password: prompted.auth.password,
|
|
14256
|
+
smsCode: prompted.auth.code
|
|
14257
|
+
};
|
|
14258
|
+
}
|
|
14259
|
+
}
|
|
14260
|
+
const r = await linkNode({
|
|
14261
|
+
hubUrl,
|
|
14262
|
+
code: code || void 0,
|
|
14263
|
+
account: account ?? void 0,
|
|
14264
|
+
dataDir: args.dataDir,
|
|
14265
|
+
label: args.label,
|
|
14266
|
+
host: args.host,
|
|
14267
|
+
port: args.port
|
|
14268
|
+
});
|
|
14269
|
+
if (r.mode === "hot") {
|
|
14270
|
+
cliLog("\u2705 \u5DF2\u63A5\u5165 Hub\uFF08\u70ED\u63A5\u5165\uFF0C\u514D\u91CD\u542F\uFF09");
|
|
14271
|
+
cliLog(` \u8282\u70B9: ${r.nodeId}${r.label ? ` (${r.label})` : ""}`);
|
|
14272
|
+
cliLog(` \u7F51\u5173: ${r.gatewayUrl ?? "\uFF08\u672A\u4E0B\u53D1\uFF09"} \u5728\u7EBF: ${r.online ? "\u662F" : "\u8FDE\u63A5\u4E2D\u2026"}`);
|
|
14273
|
+
cliLog(` \u6570\u636E\u76EE\u5F55: ${r.dataDir}${r.managed ? "\uFF08\u6258\u7BA1\u670D\u52A1\uFF0C\u5F00\u673A\u81EA\u542F\uFF09" : ""}`);
|
|
14274
|
+
if (r.warnings.length > 0) {
|
|
14275
|
+
cliLog("");
|
|
14276
|
+
for (const w of r.warnings) cliLog(`\u26A0\uFE0F ${w}`);
|
|
14277
|
+
}
|
|
14278
|
+
} else {
|
|
14279
|
+
cliLog("\u2705 \u63A5\u5165\u51ED\u636E\u5DF2\u4FDD\u5B58\uFF08\u672C\u673A\u6682\u65E0\u8FD0\u884C\u4E2D\u7684 server\uFF09");
|
|
14280
|
+
cliLog(` \u8282\u70B9: ${r.nodeId}`);
|
|
14281
|
+
cliLog(` \u7F51\u5173: ${r.gatewayUrl ?? "\uFF08\u672A\u4E0B\u53D1\uFF09"}`);
|
|
14282
|
+
cliLog(` \u6570\u636E\u76EE\u5F55: ${r.dataDir}`);
|
|
14283
|
+
cliLog(" \u4E0B\u6B21\u542F\u52A8 server \u5373\u81EA\u52A8\u63A5\u5165\uFF1B\u6216\u8FD0\u884C zqagent serve \u5E38\u9A7B\u4E3A\u8282\u70B9\u3002");
|
|
14284
|
+
if (r.targetedService) {
|
|
14285
|
+
cliLog("");
|
|
14286
|
+
cliLog("\u2705 \u51ED\u636E\u5DF2\u5199\u5165\u672C\u673A\u6258\u7BA1\u670D\u52A1\u7684\u6570\u636E\u76EE\u5F55\uFF0C\u670D\u52A1\u542F\u52A8\u65F6\u81EA\u52A8\u63A5\u5165\uFF0C\u65E0\u9700 --data-dir\u3002");
|
|
14287
|
+
cliLog(" \u7ACB\u5373\u751F\u6548\uFF1A\u91CD\u542F\u8BE5\u670D\u52A1\uFF08Linux: systemctl restart zqagent\uFF1B");
|
|
14288
|
+
cliLog(" macOS: launchctl kickstart -k gui/$(id -u)/com.zqagent.node\uFF09\u3002");
|
|
14289
|
+
} else if (r.runningServiceDirs.length > 0) {
|
|
14290
|
+
cliLog("");
|
|
14291
|
+
cliLog("\u26A0\uFE0F \u672C\u673A\u6709\u6B63\u5728\u8FD0\u884C\u7684\u8282\u70B9\uFF0C\u4F46\u6570\u636E\u76EE\u5F55\u4E0E\u672C\u6B21\u5199\u5165\u7684\u4E0D\u4E00\u81F4\uFF1A");
|
|
14292
|
+
cliLog(` \u672C\u6B21\u5199\u5165: ${r.dataDir}`);
|
|
14293
|
+
for (const d of r.runningServiceDirs) cliLog(` \u670D\u52A1\u4F7F\u7528: ${d}`);
|
|
14294
|
+
cliLog(" \u6B63\u5728\u8FD0\u884C\u7684\u670D\u52A1\u8BFB\u4E0D\u5230\u8FD9\u4EFD\u51ED\u636E\uFF0CHub \u4F1A\u4E00\u76F4\u663E\u793A\u672A\u63A5\u5165\u3002");
|
|
14295
|
+
cliLog(" \u8BF7\u786E\u8BA4\u670D\u52A1\u7684\u6570\u636E\u76EE\u5F55\u540E\u91CD\u65B0\u6267\u884C\uFF08\u63A5\u5165\u7801\u4E00\u6B21\u6027\uFF1B\u8D26\u53F7\u65B9\u5F0F\u53EF\u91CD\u590D\u4F7F\u7528\uFF09\uFF1A");
|
|
14296
|
+
cliLog(` zqagent link --hub <Hub\u5730\u5740> --username <\u90AE\u7BB1/\u624B\u673A\u53F7> --password '<\u5BC6\u7801>' --data-dir "${r.runningServiceDirs[0]}"`);
|
|
14297
|
+
} else if (!r.explicitDataDir) {
|
|
14298
|
+
cliLog("");
|
|
14299
|
+
cliLog("\u26A0\uFE0F \u672A\u53D1\u73B0\u672C\u673A\u8282\u70B9\u670D\u52A1\uFF0C\u51ED\u636E\u5199\u5165\u4E86\u5F53\u524D\u76EE\u5F55\u4E0B\u7684 .zqagent_data\u3002");
|
|
14300
|
+
cliLog(" \u5982\u679C\u8FD9\u53F0\u673A\u5668\u6253\u7B97\u957F\u671F\u8FD0\u884C\u8282\u70B9\uFF0C\u8BF7\u5148\u5B89\u88C5\u5F00\u673A\u670D\u52A1\uFF0C\u4E4B\u540E link \u4F1A\u81EA\u52A8\u5199\u5165\u5B83\u7684\u76EE\u5F55\uFF1A");
|
|
14301
|
+
cliLog(" curl -fsSL https://agent.cd-zq.com/install.sh | sh");
|
|
14302
|
+
cliLog(` \uFF08\u670D\u52A1\u9ED8\u8BA4\u6570\u636E\u76EE\u5F55\uFF1A${installDataDirHint()}\uFF09`);
|
|
14303
|
+
}
|
|
14304
|
+
}
|
|
14305
|
+
return true;
|
|
14306
|
+
} catch (e) {
|
|
14307
|
+
cliErr(`\u63A5\u5165\u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`);
|
|
14308
|
+
return false;
|
|
14309
|
+
} finally {
|
|
14310
|
+
closeOwnedRl();
|
|
14311
|
+
}
|
|
13635
14312
|
}
|
|
13636
14313
|
|
|
14314
|
+
// src/cli/serve.ts
|
|
14315
|
+
init_esm_shims();
|
|
14316
|
+
|
|
14317
|
+
// src/server/runtime.ts
|
|
14318
|
+
init_esm_shims();
|
|
14319
|
+
import * as fs31 from "fs";
|
|
14320
|
+
import * as path39 from "path";
|
|
14321
|
+
|
|
14322
|
+
// src/server/routes.ts
|
|
14323
|
+
init_esm_shims();
|
|
14324
|
+
import { createServer } from "http";
|
|
14325
|
+
import * as path32 from "path";
|
|
14326
|
+
|
|
13637
14327
|
// src/server/auth.ts
|
|
13638
14328
|
init_esm_shims();
|
|
13639
14329
|
import * as crypto4 from "crypto";
|
|
@@ -13807,34 +14497,34 @@ async function handleHubProxy(req2, res) {
|
|
|
13807
14497
|
|
|
13808
14498
|
// src/server/fsBrowser.ts
|
|
13809
14499
|
init_esm_shims();
|
|
13810
|
-
import * as
|
|
13811
|
-
import * as
|
|
13812
|
-
import * as
|
|
14500
|
+
import * as fs22 from "fs";
|
|
14501
|
+
import * as os6 from "os";
|
|
14502
|
+
import * as path29 from "path";
|
|
13813
14503
|
var MAX_ENTRIES = 2e3;
|
|
13814
14504
|
var DEFAULT_SEARCH_LIMIT = 200;
|
|
13815
14505
|
var MAX_SEARCH_LIMIT = 1e3;
|
|
13816
14506
|
function listDirs(input) {
|
|
13817
|
-
const base = (input ?? "").trim() ||
|
|
13818
|
-
const target =
|
|
14507
|
+
const base = (input ?? "").trim() || os6.homedir();
|
|
14508
|
+
const target = path29.resolve(base);
|
|
13819
14509
|
let st;
|
|
13820
14510
|
try {
|
|
13821
|
-
st =
|
|
14511
|
+
st = fs22.statSync(target);
|
|
13822
14512
|
} catch {
|
|
13823
14513
|
throw new Error(`\u8DEF\u5F84\u4E0D\u5B58\u5728: ${target}`);
|
|
13824
14514
|
}
|
|
13825
14515
|
if (!st.isDirectory()) throw new Error(`\u4E0D\u662F\u76EE\u5F55: ${target}`);
|
|
13826
14516
|
let dirents;
|
|
13827
14517
|
try {
|
|
13828
|
-
dirents =
|
|
14518
|
+
dirents = fs22.readdirSync(target, { withFileTypes: true });
|
|
13829
14519
|
} catch {
|
|
13830
14520
|
throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF08\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09: ${target}`);
|
|
13831
14521
|
}
|
|
13832
14522
|
const entries = dirents.map((d) => {
|
|
13833
|
-
const full =
|
|
14523
|
+
const full = path29.join(target, d.name);
|
|
13834
14524
|
let isDir = d.isDirectory();
|
|
13835
14525
|
if (d.isSymbolicLink()) {
|
|
13836
14526
|
try {
|
|
13837
|
-
isDir =
|
|
14527
|
+
isDir = fs22.statSync(full).isDirectory();
|
|
13838
14528
|
} catch {
|
|
13839
14529
|
}
|
|
13840
14530
|
}
|
|
@@ -13843,7 +14533,7 @@ function listDirs(input) {
|
|
|
13843
14533
|
entries.sort(
|
|
13844
14534
|
(a, b) => a.type === b.type ? a.name.localeCompare(b.name) : a.type === "dir" ? -1 : 1
|
|
13845
14535
|
);
|
|
13846
|
-
const parentDir =
|
|
14536
|
+
const parentDir = path29.dirname(target);
|
|
13847
14537
|
return {
|
|
13848
14538
|
path: target,
|
|
13849
14539
|
parent: parentDir !== target ? parentDir : null,
|
|
@@ -13874,7 +14564,7 @@ var NAME_CACHE_MAX_DIRS = 4;
|
|
|
13874
14564
|
var NAME_CACHE_MAX_ENTRIES = 5e4;
|
|
13875
14565
|
var nameCache = /* @__PURE__ */ new Map();
|
|
13876
14566
|
function invalidateDirNames(target) {
|
|
13877
|
-
nameCache.delete(
|
|
14567
|
+
nameCache.delete(path29.resolve(target));
|
|
13878
14568
|
}
|
|
13879
14569
|
async function loadDirNames(target) {
|
|
13880
14570
|
const now = Date.now();
|
|
@@ -13886,7 +14576,7 @@ async function loadDirNames(target) {
|
|
|
13886
14576
|
}
|
|
13887
14577
|
let dirents;
|
|
13888
14578
|
try {
|
|
13889
|
-
dirents = await
|
|
14579
|
+
dirents = await fs22.promises.readdir(target, { withFileTypes: true });
|
|
13890
14580
|
} catch {
|
|
13891
14581
|
throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF08\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09: ${target}`);
|
|
13892
14582
|
}
|
|
@@ -13909,22 +14599,22 @@ async function loadDirNames(target) {
|
|
|
13909
14599
|
return entries;
|
|
13910
14600
|
}
|
|
13911
14601
|
async function toDirEntry(dir, e) {
|
|
13912
|
-
const full =
|
|
14602
|
+
const full = path29.join(dir, e.name);
|
|
13913
14603
|
let isDir = e.isDir;
|
|
13914
14604
|
if (e.isLink) {
|
|
13915
14605
|
try {
|
|
13916
|
-
isDir = (await
|
|
14606
|
+
isDir = (await fs22.promises.stat(full)).isDirectory();
|
|
13917
14607
|
} catch {
|
|
13918
14608
|
}
|
|
13919
14609
|
}
|
|
13920
14610
|
return { name: e.name, path: full, type: isDir ? "dir" : "file" };
|
|
13921
14611
|
}
|
|
13922
14612
|
async function searchDirs(input, query, limit) {
|
|
13923
|
-
const base = (input ?? "").trim() ||
|
|
13924
|
-
const target =
|
|
14613
|
+
const base = (input ?? "").trim() || os6.homedir();
|
|
14614
|
+
const target = path29.resolve(base);
|
|
13925
14615
|
let st;
|
|
13926
14616
|
try {
|
|
13927
|
-
st = await
|
|
14617
|
+
st = await fs22.promises.stat(target);
|
|
13928
14618
|
} catch {
|
|
13929
14619
|
throw new Error(`\u8DEF\u5F84\u4E0D\u5B58\u5728: ${target}`);
|
|
13930
14620
|
}
|
|
@@ -13954,7 +14644,7 @@ async function searchDirs(input, query, limit) {
|
|
|
13954
14644
|
);
|
|
13955
14645
|
const hit = scored.slice(0, max);
|
|
13956
14646
|
const entries = await Promise.all(hit.map(({ entry }) => toDirEntry(target, entry)));
|
|
13957
|
-
const parentDir =
|
|
14647
|
+
const parentDir = path29.dirname(target);
|
|
13958
14648
|
return {
|
|
13959
14649
|
path: target,
|
|
13960
14650
|
parent: parentDir !== target ? parentDir : null,
|
|
@@ -13965,52 +14655,52 @@ async function searchDirs(input, query, limit) {
|
|
|
13965
14655
|
};
|
|
13966
14656
|
}
|
|
13967
14657
|
function makeDirIn(parentInput, name) {
|
|
13968
|
-
const parent =
|
|
14658
|
+
const parent = path29.resolve((parentInput ?? "").trim() || os6.homedir());
|
|
13969
14659
|
const clean = (name ?? "").trim();
|
|
13970
14660
|
if (!clean) throw new Error("\u76EE\u5F55\u540D\u4E0D\u80FD\u4E3A\u7A7A");
|
|
13971
14661
|
if (clean === "." || clean === "..") throw new Error("\u76EE\u5F55\u540D\u975E\u6CD5");
|
|
13972
|
-
const target =
|
|
13973
|
-
const rel =
|
|
13974
|
-
if (!rel || rel.startsWith("..") ||
|
|
14662
|
+
const target = path29.resolve(parent, clean);
|
|
14663
|
+
const rel = path29.relative(parent, target);
|
|
14664
|
+
if (!rel || rel.startsWith("..") || path29.isAbsolute(rel)) {
|
|
13975
14665
|
throw new Error("\u76EE\u5F55\u540D\u4E0D\u80FD\u8D8A\u51FA\u5F53\u524D\u76EE\u5F55");
|
|
13976
14666
|
}
|
|
13977
14667
|
let st = null;
|
|
13978
14668
|
try {
|
|
13979
|
-
st =
|
|
14669
|
+
st = fs22.statSync(target);
|
|
13980
14670
|
} catch {
|
|
13981
14671
|
st = null;
|
|
13982
14672
|
}
|
|
13983
14673
|
if (st && !st.isDirectory()) throw new Error(`\u5DF2\u5B58\u5728\u540C\u540D\u6587\u4EF6: ${target}`);
|
|
13984
14674
|
try {
|
|
13985
|
-
|
|
14675
|
+
fs22.mkdirSync(target, { recursive: true });
|
|
13986
14676
|
} catch (e) {
|
|
13987
14677
|
throw new Error(`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`);
|
|
13988
14678
|
}
|
|
13989
14679
|
invalidateDirNames(parent);
|
|
13990
|
-
return { name:
|
|
14680
|
+
return { name: path29.basename(target), path: target, type: "dir" };
|
|
13991
14681
|
}
|
|
13992
14682
|
|
|
13993
14683
|
// src/server/projectFiles.ts
|
|
13994
14684
|
init_esm_shims();
|
|
13995
|
-
import * as
|
|
13996
|
-
import * as
|
|
14685
|
+
import * as fs23 from "fs";
|
|
14686
|
+
import * as path30 from "path";
|
|
13997
14687
|
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
13998
14688
|
var MAX_DOWNLOAD_BYTES = 16 * 1024 * 1024;
|
|
13999
14689
|
var MAX_ENTRIES2 = 2e3;
|
|
14000
14690
|
function toPosix(p) {
|
|
14001
|
-
return p.split(
|
|
14691
|
+
return p.split(path30.sep).join("/");
|
|
14002
14692
|
}
|
|
14003
14693
|
function projectRoot(workspaceRoot) {
|
|
14004
14694
|
const r = (workspaceRoot ?? "").trim();
|
|
14005
14695
|
if (!r) {
|
|
14006
14696
|
throw new Error("\u9879\u76EE\u672A\u8BBE\u7F6E\u5DE5\u4F5C\u533A\u76EE\u5F55\uFF08workspaceRoot\uFF09\uFF0C\u65E0\u6CD5\u6D4F\u89C8\u6587\u4EF6");
|
|
14007
14697
|
}
|
|
14008
|
-
const abs =
|
|
14009
|
-
if (!
|
|
14698
|
+
const abs = path30.resolve(r);
|
|
14699
|
+
if (!fs23.existsSync(abs)) {
|
|
14010
14700
|
throw new Error(`\u5DE5\u4F5C\u533A\u76EE\u5F55\u4E0D\u5B58\u5728: ${abs}`);
|
|
14011
14701
|
}
|
|
14012
14702
|
try {
|
|
14013
|
-
return
|
|
14703
|
+
return fs23.realpathSync(abs);
|
|
14014
14704
|
} catch {
|
|
14015
14705
|
return abs;
|
|
14016
14706
|
}
|
|
@@ -14028,37 +14718,37 @@ function listProjectFiles(workspaceRoot, relPath) {
|
|
|
14028
14718
|
const dir = resolveWithin(base, relPath ?? "");
|
|
14029
14719
|
let st;
|
|
14030
14720
|
try {
|
|
14031
|
-
st =
|
|
14721
|
+
st = fs23.statSync(dir);
|
|
14032
14722
|
} catch {
|
|
14033
|
-
throw new Error(`\u76EE\u5F55\u4E0D\u5B58\u5728: ${toPosix(
|
|
14723
|
+
throw new Error(`\u76EE\u5F55\u4E0D\u5B58\u5728: ${toPosix(path30.relative(base, dir)) || "/"}`);
|
|
14034
14724
|
}
|
|
14035
14725
|
if (!st.isDirectory()) throw new Error("\u76EE\u6807\u4E0D\u662F\u76EE\u5F55");
|
|
14036
14726
|
let dirents;
|
|
14037
14727
|
try {
|
|
14038
|
-
dirents =
|
|
14728
|
+
dirents = fs23.readdirSync(dir, { withFileTypes: true });
|
|
14039
14729
|
} catch {
|
|
14040
14730
|
throw new Error("\u65E0\u6CD5\u8BFB\u53D6\u76EE\u5F55\uFF08\u6743\u9650\u4E0D\u8DB3\uFF1F\uFF09");
|
|
14041
14731
|
}
|
|
14042
14732
|
const entries = dirents.map((d) => {
|
|
14043
|
-
const full =
|
|
14733
|
+
const full = path30.join(dir, d.name);
|
|
14044
14734
|
let isDir = d.isDirectory();
|
|
14045
14735
|
if (d.isSymbolicLink()) {
|
|
14046
14736
|
try {
|
|
14047
|
-
isDir =
|
|
14737
|
+
isDir = fs23.statSync(full).isDirectory();
|
|
14048
14738
|
} catch {
|
|
14049
14739
|
}
|
|
14050
14740
|
}
|
|
14051
14741
|
let size = 0;
|
|
14052
14742
|
let mtime = "";
|
|
14053
14743
|
try {
|
|
14054
|
-
const s =
|
|
14744
|
+
const s = fs23.statSync(full);
|
|
14055
14745
|
size = s.size;
|
|
14056
14746
|
mtime = s.mtime.toISOString();
|
|
14057
14747
|
} catch {
|
|
14058
14748
|
}
|
|
14059
14749
|
return {
|
|
14060
14750
|
name: d.name,
|
|
14061
|
-
path: toPosix(
|
|
14751
|
+
path: toPosix(path30.relative(base, full)),
|
|
14062
14752
|
type: isDir ? "dir" : "file",
|
|
14063
14753
|
size,
|
|
14064
14754
|
mtime
|
|
@@ -14067,12 +14757,12 @@ function listProjectFiles(workspaceRoot, relPath) {
|
|
|
14067
14757
|
entries.sort(
|
|
14068
14758
|
(a, b) => a.type === b.type ? a.name.localeCompare(b.name) : a.type === "dir" ? -1 : 1
|
|
14069
14759
|
);
|
|
14070
|
-
const relDir = toPosix(
|
|
14071
|
-
const parentAbs =
|
|
14760
|
+
const relDir = toPosix(path30.relative(base, dir));
|
|
14761
|
+
const parentAbs = path30.dirname(dir);
|
|
14072
14762
|
return {
|
|
14073
14763
|
root: base,
|
|
14074
14764
|
path: relDir,
|
|
14075
|
-
parent: isWithinRoot(base, parentAbs) ? toPosix(
|
|
14765
|
+
parent: isWithinRoot(base, parentAbs) ? toPosix(path30.relative(base, parentAbs)) : null,
|
|
14076
14766
|
entries: entries.slice(0, MAX_ENTRIES2)
|
|
14077
14767
|
};
|
|
14078
14768
|
}
|
|
@@ -14081,17 +14771,17 @@ function readProjectFile(workspaceRoot, relPath) {
|
|
|
14081
14771
|
const file = resolveWithin(base, relPath ?? "");
|
|
14082
14772
|
let st;
|
|
14083
14773
|
try {
|
|
14084
|
-
st =
|
|
14774
|
+
st = fs23.statSync(file);
|
|
14085
14775
|
} catch {
|
|
14086
14776
|
throw new Error("\u6587\u4EF6\u4E0D\u5B58\u5728");
|
|
14087
14777
|
}
|
|
14088
14778
|
if (!st.isFile()) throw new Error("\u76EE\u6807\u4E0D\u662F\u6587\u4EF6");
|
|
14089
|
-
const buf =
|
|
14779
|
+
const buf = fs23.readFileSync(file);
|
|
14090
14780
|
const binary = isBinary(buf);
|
|
14091
14781
|
const truncated = buf.length > MAX_FILE_BYTES;
|
|
14092
14782
|
const slice = truncated ? buf.subarray(0, MAX_FILE_BYTES) : buf;
|
|
14093
14783
|
return {
|
|
14094
|
-
path: toPosix(
|
|
14784
|
+
path: toPosix(path30.relative(base, file)),
|
|
14095
14785
|
size: st.size,
|
|
14096
14786
|
binary,
|
|
14097
14787
|
truncated,
|
|
@@ -14103,7 +14793,7 @@ function downloadProjectFile(workspaceRoot, relPath) {
|
|
|
14103
14793
|
const file = resolveWithin(base, relPath ?? "");
|
|
14104
14794
|
let st;
|
|
14105
14795
|
try {
|
|
14106
|
-
st =
|
|
14796
|
+
st = fs23.statSync(file);
|
|
14107
14797
|
} catch {
|
|
14108
14798
|
throw new Error("\u6587\u4EF6\u4E0D\u5B58\u5728");
|
|
14109
14799
|
}
|
|
@@ -14111,10 +14801,10 @@ function downloadProjectFile(workspaceRoot, relPath) {
|
|
|
14111
14801
|
if (st.size > MAX_DOWNLOAD_BYTES) {
|
|
14112
14802
|
throw new Error(`\u6587\u4EF6\u8D85\u8FC7\u4E0B\u8F7D\u4E0A\u9650\uFF08${MAX_DOWNLOAD_BYTES / (1024 * 1024)}MB\uFF09`);
|
|
14113
14803
|
}
|
|
14114
|
-
const buf =
|
|
14804
|
+
const buf = fs23.readFileSync(file);
|
|
14115
14805
|
return {
|
|
14116
|
-
path: toPosix(
|
|
14117
|
-
name:
|
|
14806
|
+
path: toPosix(path30.relative(base, file)),
|
|
14807
|
+
name: path30.basename(file),
|
|
14118
14808
|
size: buf.length,
|
|
14119
14809
|
base64: buf.toString("base64")
|
|
14120
14810
|
};
|
|
@@ -14136,12 +14826,12 @@ function writeProjectFile(workspaceRoot, relPath, content) {
|
|
|
14136
14826
|
throw new Error("\u5185\u5BB9\u8D85\u8FC7 2MB \u4E0A\u9650\uFF0C\u65E0\u6CD5\u4FDD\u5B58");
|
|
14137
14827
|
}
|
|
14138
14828
|
try {
|
|
14139
|
-
|
|
14140
|
-
|
|
14829
|
+
fs23.mkdirSync(path30.dirname(file), { recursive: true });
|
|
14830
|
+
fs23.writeFileSync(file, buf);
|
|
14141
14831
|
} catch (e) {
|
|
14142
14832
|
throw new Error(`\u5199\u5165\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
14143
14833
|
}
|
|
14144
|
-
return { path: toPosix(
|
|
14834
|
+
return { path: toPosix(path30.relative(base, file)), size: buf.length };
|
|
14145
14835
|
}
|
|
14146
14836
|
function createProjectDir(workspaceRoot, relPath) {
|
|
14147
14837
|
const base = projectRoot(workspaceRoot);
|
|
@@ -14149,26 +14839,26 @@ function createProjectDir(workspaceRoot, relPath) {
|
|
|
14149
14839
|
if (!rel) throw new Error("\u76EE\u5F55\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A");
|
|
14150
14840
|
const dir = resolveWithin(base, rel);
|
|
14151
14841
|
try {
|
|
14152
|
-
|
|
14842
|
+
fs23.mkdirSync(dir, { recursive: true });
|
|
14153
14843
|
} catch (e) {
|
|
14154
14844
|
throw new Error(`\u521B\u5EFA\u76EE\u5F55\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
14155
14845
|
}
|
|
14156
|
-
return { path: toPosix(
|
|
14846
|
+
return { path: toPosix(path30.relative(base, dir)) };
|
|
14157
14847
|
}
|
|
14158
14848
|
function createProjectFile(workspaceRoot, relPath, content = "") {
|
|
14159
14849
|
const base = projectRoot(workspaceRoot);
|
|
14160
14850
|
const rel = (relPath ?? "").trim();
|
|
14161
14851
|
if (!rel) throw new Error("\u6587\u4EF6\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A");
|
|
14162
14852
|
const file = resolveWithin(base, rel);
|
|
14163
|
-
if (
|
|
14853
|
+
if (fs23.existsSync(file)) throw new Error("\u6587\u4EF6\u5DF2\u5B58\u5728");
|
|
14164
14854
|
const buf = Buffer.from(String(content ?? ""), "utf-8");
|
|
14165
14855
|
try {
|
|
14166
|
-
|
|
14167
|
-
|
|
14856
|
+
fs23.mkdirSync(path30.dirname(file), { recursive: true });
|
|
14857
|
+
fs23.writeFileSync(file, buf);
|
|
14168
14858
|
} catch (e) {
|
|
14169
14859
|
throw new Error(`\u521B\u5EFA\u6587\u4EF6\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
14170
14860
|
}
|
|
14171
|
-
return { path: toPosix(
|
|
14861
|
+
return { path: toPosix(path30.relative(base, file)), size: buf.length };
|
|
14172
14862
|
}
|
|
14173
14863
|
function searchProjectFiles(workspaceRoot, query) {
|
|
14174
14864
|
const base = projectRoot(workspaceRoot);
|
|
@@ -14191,7 +14881,7 @@ function searchProjectFiles(workspaceRoot, query) {
|
|
|
14191
14881
|
if (out.length >= LIMIT) return;
|
|
14192
14882
|
let dirents;
|
|
14193
14883
|
try {
|
|
14194
|
-
dirents =
|
|
14884
|
+
dirents = fs23.readdirSync(dir, { withFileTypes: true });
|
|
14195
14885
|
} catch {
|
|
14196
14886
|
return;
|
|
14197
14887
|
}
|
|
@@ -14202,7 +14892,7 @@ function searchProjectFiles(workspaceRoot, query) {
|
|
|
14202
14892
|
let isDir = d.isDirectory();
|
|
14203
14893
|
if (d.isSymbolicLink()) {
|
|
14204
14894
|
try {
|
|
14205
|
-
isDir =
|
|
14895
|
+
isDir = fs23.statSync(path30.join(dir, d.name)).isDirectory();
|
|
14206
14896
|
} catch {
|
|
14207
14897
|
isDir = false;
|
|
14208
14898
|
}
|
|
@@ -14210,7 +14900,7 @@ function searchProjectFiles(workspaceRoot, query) {
|
|
|
14210
14900
|
if (d.name.toLowerCase().includes(q)) {
|
|
14211
14901
|
out.push({ path: rel, type: isDir ? "dir" : "file" });
|
|
14212
14902
|
}
|
|
14213
|
-
if (isDir) walk(
|
|
14903
|
+
if (isDir) walk(path30.join(dir, d.name), rel);
|
|
14214
14904
|
}
|
|
14215
14905
|
};
|
|
14216
14906
|
walk(base, "");
|
|
@@ -14219,8 +14909,8 @@ function searchProjectFiles(workspaceRoot, query) {
|
|
|
14219
14909
|
|
|
14220
14910
|
// src/server/projectOps.ts
|
|
14221
14911
|
init_esm_shims();
|
|
14222
|
-
import * as
|
|
14223
|
-
import * as
|
|
14912
|
+
import * as os7 from "os";
|
|
14913
|
+
import * as path31 from "path";
|
|
14224
14914
|
var MAX_STDOUT2 = 2e4;
|
|
14225
14915
|
var MAX_STDERR2 = 1e4;
|
|
14226
14916
|
var MAX_BUFFER3 = 1024 * 1024 * 5;
|
|
@@ -14234,7 +14924,7 @@ function resolveInvocation2(spec, prepared) {
|
|
|
14234
14924
|
}
|
|
14235
14925
|
function workRoot(workspaceRoot) {
|
|
14236
14926
|
const r = (workspaceRoot ?? "").trim();
|
|
14237
|
-
return r ?
|
|
14927
|
+
return r ? path31.resolve(r) : os7.homedir();
|
|
14238
14928
|
}
|
|
14239
14929
|
async function runProjectCommand(workspaceRoot, command, timeoutSeconds) {
|
|
14240
14930
|
const cmd = String(command ?? "");
|
|
@@ -14545,11 +15235,11 @@ function projectStats(manager, tenantId) {
|
|
|
14545
15235
|
|
|
14546
15236
|
// src/server/nodeHost.ts
|
|
14547
15237
|
init_esm_shims();
|
|
14548
|
-
import * as
|
|
14549
|
-
import * as
|
|
15238
|
+
import * as fs24 from "fs";
|
|
15239
|
+
import * as os8 from "os";
|
|
14550
15240
|
function diskInfo(pathStr) {
|
|
14551
15241
|
try {
|
|
14552
|
-
const st =
|
|
15242
|
+
const st = fs24.statfsSync(pathStr);
|
|
14553
15243
|
return {
|
|
14554
15244
|
path: pathStr,
|
|
14555
15245
|
total: Number(st.blocks) * Number(st.bsize),
|
|
@@ -14561,7 +15251,7 @@ function diskInfo(pathStr) {
|
|
|
14561
15251
|
}
|
|
14562
15252
|
function networkInfo() {
|
|
14563
15253
|
const out = [];
|
|
14564
|
-
const ifaces =
|
|
15254
|
+
const ifaces = os8.networkInterfaces();
|
|
14565
15255
|
for (const [name, list] of Object.entries(ifaces)) {
|
|
14566
15256
|
for (const info of list ?? []) {
|
|
14567
15257
|
out.push({
|
|
@@ -14612,23 +15302,23 @@ function overview(store, manager) {
|
|
|
14612
15302
|
return { projects, sessions: { total, running, waiting, items }, usage: { tokensIn, tokensOut } };
|
|
14613
15303
|
}
|
|
14614
15304
|
function buildNodeHost(store, manager, diskPath) {
|
|
14615
|
-
const cpus2 =
|
|
15305
|
+
const cpus2 = os8.cpus();
|
|
14616
15306
|
const ov = overview(store, manager);
|
|
14617
15307
|
return {
|
|
14618
15308
|
nodeId: store.loadNodeId() ?? "",
|
|
14619
|
-
hostname:
|
|
15309
|
+
hostname: os8.hostname(),
|
|
14620
15310
|
platform: process.platform,
|
|
14621
15311
|
arch: process.arch,
|
|
14622
|
-
release:
|
|
14623
|
-
uptimeSec: Math.round(
|
|
14624
|
-
version: "0.2.
|
|
15312
|
+
release: os8.release(),
|
|
15313
|
+
uptimeSec: Math.round(os8.uptime()),
|
|
15314
|
+
version: "0.2.12",
|
|
14625
15315
|
mode: process.env.NODE_MODE ?? "standalone",
|
|
14626
15316
|
cpu: {
|
|
14627
15317
|
count: cpus2.length,
|
|
14628
15318
|
model: cpus2[0]?.model ?? "",
|
|
14629
|
-
loadAvg:
|
|
15319
|
+
loadAvg: os8.loadavg().map((n) => Math.round(n * 100) / 100)
|
|
14630
15320
|
},
|
|
14631
|
-
memory: { total:
|
|
15321
|
+
memory: { total: os8.totalmem(), free: os8.freemem() },
|
|
14632
15322
|
network: networkInfo(),
|
|
14633
15323
|
disk: diskInfo(diskPath || process.cwd()),
|
|
14634
15324
|
...ov
|
|
@@ -14991,7 +15681,7 @@ function createApp(store, manager, opts = {}) {
|
|
|
14991
15681
|
ok(res, opts.fleet.status());
|
|
14992
15682
|
}
|
|
14993
15683
|
},
|
|
14994
|
-
//
|
|
15684
|
+
// 运行时热接入:凭一次性注册码或 Hub 账号接入(落盘 fleet.json + 立即连接,免重启)
|
|
14995
15685
|
{
|
|
14996
15686
|
method: "POST",
|
|
14997
15687
|
pattern: ["fleet", "enroll"],
|
|
@@ -15003,15 +15693,42 @@ function createApp(store, manager, opts = {}) {
|
|
|
15003
15693
|
const raw = body ?? {};
|
|
15004
15694
|
const hubUrl = String(raw.hubUrl ?? "").trim().replace(/\/$/, "");
|
|
15005
15695
|
const code = String(raw.code ?? "").trim();
|
|
15006
|
-
|
|
15007
|
-
|
|
15696
|
+
const email = String(raw.email ?? "").trim();
|
|
15697
|
+
const phone = String(raw.phone ?? "").trim();
|
|
15698
|
+
const password = String(raw.password ?? "");
|
|
15699
|
+
const smsCode = String(raw.smsCode ?? "").trim();
|
|
15700
|
+
const hasAccount = Boolean(email || phone);
|
|
15701
|
+
if (!hubUrl) {
|
|
15702
|
+
throw new ApiError(400, "bad_request", "hubUrl \u5FC5\u586B");
|
|
15703
|
+
}
|
|
15704
|
+
if (code && hasAccount) {
|
|
15705
|
+
throw new ApiError(400, "bad_request", "code \u4E0E\u8D26\u53F7\u51ED\u636E\u53EA\u80FD\u4E8C\u9009\u4E00");
|
|
15706
|
+
}
|
|
15707
|
+
if (!code && !hasAccount) {
|
|
15708
|
+
throw new ApiError(400, "bad_request", "\u9700\u8981 code\uFF0C\u6216 email/phone + password/smsCode");
|
|
15709
|
+
}
|
|
15710
|
+
if (hasAccount && !password && !smsCode) {
|
|
15711
|
+
throw new ApiError(400, "bad_request", "\u8D26\u53F7\u63A5\u5165\u9700\u8981 password \u6216 smsCode");
|
|
15008
15712
|
}
|
|
15009
15713
|
const label = typeof raw.label === "string" ? raw.label.trim() : void 0;
|
|
15010
15714
|
try {
|
|
15011
|
-
ok(
|
|
15715
|
+
ok(
|
|
15716
|
+
res,
|
|
15717
|
+
await opts.fleet.enroll({
|
|
15718
|
+
hubUrl,
|
|
15719
|
+
code: code || void 0,
|
|
15720
|
+
account: hasAccount ? {
|
|
15721
|
+
email: email || void 0,
|
|
15722
|
+
phone: phone || void 0,
|
|
15723
|
+
password: password || void 0,
|
|
15724
|
+
smsCode: smsCode || void 0
|
|
15725
|
+
} : void 0,
|
|
15726
|
+
label
|
|
15727
|
+
})
|
|
15728
|
+
);
|
|
15012
15729
|
} catch (e) {
|
|
15013
15730
|
const code2 = e.code;
|
|
15014
|
-
const status = code2 === "code_expired" ? 410 : code2 === "code_used" || code2 === "node_taken" ? 409 : code2 === "not_found" ? 404 : code2 === "plan_limit" || code2 === "subscription_required" ? 402 : 400;
|
|
15731
|
+
const status = code2 === "code_expired" ? 410 : code2 === "unauthorized" ? 401 : code2 === "account_disabled" ? 403 : code2 === "code_used" || code2 === "node_taken" ? 409 : code2 === "not_found" ? 404 : code2 === "plan_limit" || code2 === "subscription_required" ? 402 : 400;
|
|
15015
15732
|
const msg = e instanceof Error ? e.message : String(e);
|
|
15016
15733
|
throw new ApiError(
|
|
15017
15734
|
status,
|
|
@@ -15196,7 +15913,7 @@ function createApp(store, manager, opts = {}) {
|
|
|
15196
15913
|
applyProvidersPatch(tenant, raw);
|
|
15197
15914
|
if (typeof raw.workspaceRoot === "string") {
|
|
15198
15915
|
const ws = raw.workspaceRoot.trim();
|
|
15199
|
-
const next = ws ?
|
|
15916
|
+
const next = ws ? path32.resolve(ws) : void 0;
|
|
15200
15917
|
if (tenant.workspaceRoot) {
|
|
15201
15918
|
if (next !== tenant.workspaceRoot) {
|
|
15202
15919
|
throw new ApiError(
|
|
@@ -16183,7 +16900,7 @@ function createApp(store, manager, opts = {}) {
|
|
|
16183
16900
|
json(res, 200, {
|
|
16184
16901
|
status: "ok",
|
|
16185
16902
|
// 版本让运维/探针能确认线上跑的是哪个构建(更新与回滚据此判断)
|
|
16186
|
-
version: "0.2.
|
|
16903
|
+
version: "0.2.12",
|
|
16187
16904
|
features: { mcp: hasServerMcpConfig() }
|
|
16188
16905
|
});
|
|
16189
16906
|
return;
|
|
@@ -16278,7 +16995,7 @@ function createApp(store, manager, opts = {}) {
|
|
|
16278
16995
|
|
|
16279
16996
|
// src/server/fleet/FleetNodeBridge.ts
|
|
16280
16997
|
init_esm_shims();
|
|
16281
|
-
import * as
|
|
16998
|
+
import * as os9 from "os";
|
|
16282
16999
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
16283
17000
|
|
|
16284
17001
|
// src/server/fleet/FleetCommands.ts
|
|
@@ -17472,7 +18189,7 @@ function withTimeout(p, ms) {
|
|
|
17472
18189
|
}
|
|
17473
18190
|
function primaryIp() {
|
|
17474
18191
|
let v6;
|
|
17475
|
-
for (const infos of Object.values(
|
|
18192
|
+
for (const infos of Object.values(os9.networkInterfaces())) {
|
|
17476
18193
|
for (const info of infos ?? []) {
|
|
17477
18194
|
if (info.internal) continue;
|
|
17478
18195
|
if (info.family === "IPv4") return info.address;
|
|
@@ -17486,7 +18203,7 @@ function primaryIp() {
|
|
|
17486
18203
|
var FleetNodeBridge = class {
|
|
17487
18204
|
constructor(opts) {
|
|
17488
18205
|
this.opts = opts;
|
|
17489
|
-
this.nodeId = opts.nodeId ??
|
|
18206
|
+
this.nodeId = opts.nodeId ?? ensureNodeId(opts.deps.store);
|
|
17490
18207
|
}
|
|
17491
18208
|
opts;
|
|
17492
18209
|
/** 是否成功连接过(区分「一直连不上」与「连上后断线」) */
|
|
@@ -17821,7 +18538,7 @@ var FleetNodeBridge = class {
|
|
|
17821
18538
|
label: this.opts.deps.store.loadNodeLabel() ?? void 0,
|
|
17822
18539
|
platform: process.platform,
|
|
17823
18540
|
mode: process.env.NODE_MODE ?? "standalone",
|
|
17824
|
-
version: "0.2.
|
|
18541
|
+
version: "0.2.12",
|
|
17825
18542
|
ip: primaryIp()
|
|
17826
18543
|
};
|
|
17827
18544
|
}
|
|
@@ -17876,7 +18593,7 @@ var FleetNodeBridge = class {
|
|
|
17876
18593
|
label: this.opts.deps.store.loadNodeLabel() ?? void 0,
|
|
17877
18594
|
platform: process.platform,
|
|
17878
18595
|
mode: process.env.NODE_MODE ?? "standalone",
|
|
17879
|
-
version: "0.2.
|
|
18596
|
+
version: "0.2.12",
|
|
17880
18597
|
ip: primaryIp(),
|
|
17881
18598
|
projects,
|
|
17882
18599
|
totals,
|
|
@@ -18064,28 +18781,6 @@ var FleetNodeBridge = class {
|
|
|
18064
18781
|
}
|
|
18065
18782
|
};
|
|
18066
18783
|
|
|
18067
|
-
// src/server/fleet-config.ts
|
|
18068
|
-
init_esm_shims();
|
|
18069
|
-
function fleetConfigFromEnv(store) {
|
|
18070
|
-
const fleetToken = process.env.FLEET_TOKEN;
|
|
18071
|
-
const fleetSecret = process.env.FLEET_SECRET;
|
|
18072
|
-
if (!fleetToken || !fleetSecret) return null;
|
|
18073
|
-
return {
|
|
18074
|
-
hubUrl: process.env.HUB_URL,
|
|
18075
|
-
fleetToken,
|
|
18076
|
-
fleetSecret,
|
|
18077
|
-
nodeId: ensureNodeId2(store),
|
|
18078
|
-
gatewayUrl: process.env.FLEET_GATEWAY_URL
|
|
18079
|
-
};
|
|
18080
|
-
}
|
|
18081
|
-
function resolveFleetConfig(store) {
|
|
18082
|
-
const saved = store.loadFleetCredential();
|
|
18083
|
-
if (saved?.fleetToken && saved.fleetSecret) {
|
|
18084
|
-
return { ...saved, nodeId: saved.nodeId || ensureNodeId2(store) };
|
|
18085
|
-
}
|
|
18086
|
-
return fleetConfigFromEnv(store);
|
|
18087
|
-
}
|
|
18088
|
-
|
|
18089
18784
|
// src/server/notify/index.ts
|
|
18090
18785
|
init_esm_shims();
|
|
18091
18786
|
|
|
@@ -18645,8 +19340,8 @@ init_esm_shims();
|
|
|
18645
19340
|
|
|
18646
19341
|
// src/server/qq/bindings.ts
|
|
18647
19342
|
init_esm_shims();
|
|
18648
|
-
import * as
|
|
18649
|
-
import * as
|
|
19343
|
+
import * as fs25 from "fs";
|
|
19344
|
+
import * as path33 from "path";
|
|
18650
19345
|
function conversationKey(target) {
|
|
18651
19346
|
switch (target.kind) {
|
|
18652
19347
|
case "c2c":
|
|
@@ -18685,12 +19380,12 @@ var QqBindingsStore = class _QqBindingsStore {
|
|
|
18685
19380
|
cache = null;
|
|
18686
19381
|
/** 基于 DATA_DIR 构造 */
|
|
18687
19382
|
static in(dataDir) {
|
|
18688
|
-
return new _QqBindingsStore(
|
|
19383
|
+
return new _QqBindingsStore(path33.join(dataDir, "qq", "bindings.json"));
|
|
18689
19384
|
}
|
|
18690
19385
|
load() {
|
|
18691
19386
|
if (this.cache) return this.cache;
|
|
18692
19387
|
try {
|
|
18693
|
-
const raw = JSON.parse(
|
|
19388
|
+
const raw = JSON.parse(fs25.readFileSync(this.file, "utf-8"));
|
|
18694
19389
|
this.cache = {
|
|
18695
19390
|
conversations: raw.conversations ?? {}
|
|
18696
19391
|
};
|
|
@@ -18722,8 +19417,8 @@ var QqBindingsStore = class _QqBindingsStore {
|
|
|
18722
19417
|
return null;
|
|
18723
19418
|
}
|
|
18724
19419
|
persist() {
|
|
18725
|
-
|
|
18726
|
-
|
|
19420
|
+
fs25.mkdirSync(path33.dirname(this.file), { recursive: true });
|
|
19421
|
+
fs25.writeFileSync(this.file, JSON.stringify(this.cache, null, 2), "utf-8");
|
|
18727
19422
|
}
|
|
18728
19423
|
};
|
|
18729
19424
|
|
|
@@ -19135,8 +19830,8 @@ ${lines.join("\n")}`, msgId);
|
|
|
19135
19830
|
|
|
19136
19831
|
// src/server/qq/QqManager.ts
|
|
19137
19832
|
init_esm_shims();
|
|
19138
|
-
import * as
|
|
19139
|
-
import * as
|
|
19833
|
+
import * as fs26 from "fs";
|
|
19834
|
+
import * as path34 from "path";
|
|
19140
19835
|
var QqManager = class {
|
|
19141
19836
|
constructor(opts) {
|
|
19142
19837
|
this.opts = opts;
|
|
@@ -19145,7 +19840,7 @@ var QqManager = class {
|
|
|
19145
19840
|
adapter = null;
|
|
19146
19841
|
config = null;
|
|
19147
19842
|
get configFile() {
|
|
19148
|
-
return
|
|
19843
|
+
return path34.join(this.opts.dataDir, "qq", "config.json");
|
|
19149
19844
|
}
|
|
19150
19845
|
/** 启动:读配置(env 优先,其次文件),有则建连接 */
|
|
19151
19846
|
start() {
|
|
@@ -19183,7 +19878,7 @@ var QqManager = class {
|
|
|
19183
19878
|
/** 清空配置:删除文件 + 断开 */
|
|
19184
19879
|
clearConfig() {
|
|
19185
19880
|
try {
|
|
19186
|
-
|
|
19881
|
+
fs26.rmSync(this.configFile, { force: true });
|
|
19187
19882
|
} catch {
|
|
19188
19883
|
}
|
|
19189
19884
|
this.stop();
|
|
@@ -19225,7 +19920,7 @@ var QqManager = class {
|
|
|
19225
19920
|
}
|
|
19226
19921
|
_readConfigFile() {
|
|
19227
19922
|
try {
|
|
19228
|
-
const raw = JSON.parse(
|
|
19923
|
+
const raw = JSON.parse(fs26.readFileSync(this.configFile, "utf-8"));
|
|
19229
19924
|
if (raw.appId && raw.appSecret) {
|
|
19230
19925
|
return {
|
|
19231
19926
|
appId: raw.appId,
|
|
@@ -19238,8 +19933,8 @@ var QqManager = class {
|
|
|
19238
19933
|
return null;
|
|
19239
19934
|
}
|
|
19240
19935
|
_persistConfig(cfg) {
|
|
19241
|
-
|
|
19242
|
-
|
|
19936
|
+
fs26.mkdirSync(path34.dirname(this.configFile), { recursive: true });
|
|
19937
|
+
fs26.writeFileSync(this.configFile, JSON.stringify(cfg, null, 2), "utf-8");
|
|
19243
19938
|
}
|
|
19244
19939
|
};
|
|
19245
19940
|
|
|
@@ -19288,16 +19983,16 @@ var PairingCodeStore = class {
|
|
|
19288
19983
|
// src/update/controller.ts
|
|
19289
19984
|
init_esm_shims();
|
|
19290
19985
|
import * as fs30 from "fs";
|
|
19291
|
-
import * as
|
|
19986
|
+
import * as path38 from "path";
|
|
19292
19987
|
|
|
19293
19988
|
// src/update/downloader.ts
|
|
19294
19989
|
init_esm_shims();
|
|
19295
19990
|
import { createHash as createHash3 } from "crypto";
|
|
19296
|
-
import * as
|
|
19991
|
+
import * as fs27 from "fs";
|
|
19297
19992
|
import { Readable as Readable2 } from "stream";
|
|
19298
19993
|
import { pipeline as pipeline2 } from "stream/promises";
|
|
19299
|
-
import { spawnSync as
|
|
19300
|
-
import * as
|
|
19994
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
19995
|
+
import * as path35 from "path";
|
|
19301
19996
|
|
|
19302
19997
|
// src/update/manifest.ts
|
|
19303
19998
|
init_esm_shims();
|
|
@@ -19463,267 +20158,97 @@ async function fetchManifest(url, publicKey, opts = {}) {
|
|
|
19463
20158
|
}
|
|
19464
20159
|
let parsed;
|
|
19465
20160
|
try {
|
|
19466
|
-
parsed = JSON.parse(raw.toString("utf-8"));
|
|
19467
|
-
} catch (err) {
|
|
19468
|
-
return { error: `\u6E05\u5355\u4E0D\u662F\u5408\u6CD5 JSON\uFF1A${err.message}` };
|
|
19469
|
-
}
|
|
19470
|
-
const { manifest, error: error2 } = parseManifest(parsed, opts);
|
|
19471
|
-
if (!manifest) return { error: error2 };
|
|
19472
|
-
return { manifest, raw };
|
|
19473
|
-
}
|
|
19474
|
-
async function downloadBinary(bin, destPath, log = () => {
|
|
19475
|
-
}) {
|
|
19476
|
-
const partPath = `${destPath}.part`;
|
|
19477
|
-
fs26.mkdirSync(path33.dirname(destPath), { recursive: true });
|
|
19478
|
-
fs26.rmSync(partPath, { force: true });
|
|
19479
|
-
let res;
|
|
19480
|
-
try {
|
|
19481
|
-
res = await fetch(bin.url, { signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS2) });
|
|
19482
|
-
} catch (err) {
|
|
19483
|
-
return { error: `\u4E0B\u8F7D\u5931\u8D25\uFF1A${err.message}` };
|
|
19484
|
-
}
|
|
19485
|
-
if (!res.ok) return { error: `\u4E0B\u8F7D\u5931\u8D25 HTTP ${res.status}` };
|
|
19486
|
-
if (!res.body) return { error: "\u4E0B\u8F7D\u54CD\u5E94\u6CA1\u6709 body" };
|
|
19487
|
-
const expected = bin.size && bin.size > 0 ? bin.size : void 0;
|
|
19488
|
-
const limit = expected ? Math.max(expected * 2, 1024 * 1024) : MAX_BINARY_BYTES;
|
|
19489
|
-
const hash = createHash3("sha256");
|
|
19490
|
-
let bytes = 0;
|
|
19491
|
-
try {
|
|
19492
|
-
const source = Readable2.fromWeb(res.body);
|
|
19493
|
-
await pipeline2(
|
|
19494
|
-
source,
|
|
19495
|
-
async function* (chunks) {
|
|
19496
|
-
for await (const chunk of chunks) {
|
|
19497
|
-
bytes += chunk.length;
|
|
19498
|
-
if (bytes > limit) throw new Error(`\u4EA7\u7269\u8D85\u8FC7\u5927\u5C0F\u4E0A\u9650\uFF08>${limit} \u5B57\u8282\uFF09`);
|
|
19499
|
-
hash.update(chunk);
|
|
19500
|
-
yield chunk;
|
|
19501
|
-
}
|
|
19502
|
-
},
|
|
19503
|
-
fs26.createWriteStream(partPath, { mode: 493 })
|
|
19504
|
-
);
|
|
19505
|
-
} catch (err) {
|
|
19506
|
-
fs26.rmSync(partPath, { force: true });
|
|
19507
|
-
return { error: `\u4E0B\u8F7D\u4E2D\u65AD\uFF1A${err.message}` };
|
|
19508
|
-
}
|
|
19509
|
-
const actual = hash.digest("hex");
|
|
19510
|
-
if (actual !== bin.sha256) {
|
|
19511
|
-
fs26.rmSync(partPath, { force: true });
|
|
19512
|
-
return { error: `SHA-256 \u4E0D\u5339\u914D\uFF08\u671F\u671B ${bin.sha256.slice(0, 12)}\u2026\uFF0C\u5B9E\u9645 ${actual.slice(0, 12)}\u2026\uFF09` };
|
|
19513
|
-
}
|
|
19514
|
-
if (expected && bytes !== expected) {
|
|
19515
|
-
fs26.rmSync(partPath, { force: true });
|
|
19516
|
-
return { error: `\u4EA7\u7269\u5927\u5C0F\u4E0D\u5339\u914D\uFF08\u671F\u671B ${expected}\uFF0C\u5B9E\u9645 ${bytes}\uFF09` };
|
|
19517
|
-
}
|
|
19518
|
-
fs26.rmSync(destPath, { force: true });
|
|
19519
|
-
fs26.renameSync(partPath, destPath);
|
|
19520
|
-
fs26.chmodSync(destPath, 493);
|
|
19521
|
-
log(`\u5DF2\u4E0B\u8F7D ${path33.basename(destPath)}\uFF08${Math.round(bytes / 1024 / 1024)}MB\uFF0C\u6821\u9A8C\u901A\u8FC7\uFF09`);
|
|
19522
|
-
return { bytes };
|
|
19523
|
-
}
|
|
19524
|
-
function selfCheck(binPath, expectedVersion) {
|
|
19525
|
-
try {
|
|
19526
|
-
const r = spawnSync3(binPath, ["--version"], {
|
|
19527
|
-
timeout: 2e4,
|
|
19528
|
-
encoding: "utf-8",
|
|
19529
|
-
env: { ...process.env, ZQAGENT_AUTO_UPDATE: "0" }
|
|
19530
|
-
});
|
|
19531
|
-
if (r.error) return { ok: false, error: `\u6267\u884C\u81EA\u68C0\u5931\u8D25\uFF1A${r.error.message}` };
|
|
19532
|
-
if (r.status !== 0) return { ok: false, error: `\u81EA\u68C0\u9000\u51FA\u7801 ${r.status}\uFF1A${(r.stderr || "").trim()}` };
|
|
19533
|
-
const out = `${r.stdout ?? ""}${r.stderr ?? ""}`;
|
|
19534
|
-
if (!out.includes(expectedVersion)) {
|
|
19535
|
-
return { ok: false, error: `\u81EA\u68C0\u7248\u672C\u4E0D\u7B26\uFF08\u671F\u671B ${expectedVersion}\uFF0C\u8F93\u51FA\uFF1A${out.trim().slice(0, 120)}\uFF09` };
|
|
19536
|
-
}
|
|
19537
|
-
return { ok: true };
|
|
19538
|
-
} catch (err) {
|
|
19539
|
-
return { ok: false, error: `\u81EA\u68C0\u5F02\u5E38\uFF1A${err.message}` };
|
|
19540
|
-
}
|
|
19541
|
-
}
|
|
19542
|
-
|
|
19543
|
-
// src/update/platform.ts
|
|
19544
|
-
init_esm_shims();
|
|
19545
|
-
import * as fs27 from "fs";
|
|
19546
|
-
import * as os8 from "os";
|
|
19547
|
-
import * as path34 from "path";
|
|
19548
|
-
import { spawnSync as spawnSync4 } from "child_process";
|
|
19549
|
-
import { createRequire as createRequire3 } from "module";
|
|
19550
|
-
function currentVersion() {
|
|
19551
|
-
const injected = "0.2.10"?.trim();
|
|
19552
|
-
if (injected) return injected;
|
|
19553
|
-
try {
|
|
19554
|
-
const req2 = createRequire3(import.meta.url);
|
|
19555
|
-
const pkg = req2("../../package.json");
|
|
19556
|
-
if (pkg?.version) return pkg.version;
|
|
19557
|
-
} catch {
|
|
19558
|
-
}
|
|
19559
|
-
return "dev";
|
|
19560
|
-
}
|
|
19561
|
-
function isSeaRuntime() {
|
|
19562
|
-
if (process.env.ZQAGENT_SEA === "1") return true;
|
|
19563
|
-
const base = path34.basename(process.execPath).toLowerCase().replace(/\.exe$/, "");
|
|
19564
|
-
return base !== "node" && base !== "nodejs";
|
|
19565
|
-
}
|
|
19566
|
-
var DEFAULT_SERVICE_NAME = "zqagent";
|
|
19567
|
-
var DEFAULT_SERVICE_LABEL = "com.zqagent.node";
|
|
19568
|
-
function serviceManagerFromCgroup(cgroup, serviceName = DEFAULT_SERVICE_NAME) {
|
|
19569
|
-
const unitName = `${serviceName}.service`;
|
|
19570
|
-
for (const line of cgroup.split("\n")) {
|
|
19571
|
-
const idx = line.lastIndexOf(":");
|
|
19572
|
-
if (idx < 0) continue;
|
|
19573
|
-
const unitPath = line.slice(idx + 1).trim();
|
|
19574
|
-
if (unitPath.split("/").includes(unitName)) return "systemd";
|
|
19575
|
-
}
|
|
19576
|
-
return null;
|
|
19577
|
-
}
|
|
19578
|
-
function launchdDomain() {
|
|
19579
|
-
const uid = typeof process.getuid === "function" ? process.getuid() : -1;
|
|
19580
|
-
return uid === 0 ? "system" : `gui/${uid}`;
|
|
19581
|
-
}
|
|
19582
|
-
function launchdLabel() {
|
|
19583
|
-
return process.env.ZQAGENT_SERVICE_LABEL?.trim() || DEFAULT_SERVICE_LABEL;
|
|
19584
|
-
}
|
|
19585
|
-
function launchdPlistPath() {
|
|
19586
|
-
const label = launchdLabel();
|
|
19587
|
-
const uid = typeof process.getuid === "function" ? process.getuid() : -1;
|
|
19588
|
-
if (uid === 0) return `/Library/LaunchDaemons/${label}.plist`;
|
|
19589
|
-
return path34.join(os8.homedir(), "Library", "LaunchAgents", `${label}.plist`);
|
|
19590
|
-
}
|
|
19591
|
-
function serviceManagerFromLaunchctl(output, pid, execPath, sea = true) {
|
|
19592
|
-
const pidMatch = /^\s*pid = (\d+)\s*$/m.exec(output);
|
|
19593
|
-
if (pidMatch && Number(pidMatch[1]) === pid) return "launchd";
|
|
19594
|
-
const program = /^\s*program = (.+?)\s*$/m.exec(output);
|
|
19595
|
-
if (program) {
|
|
19596
|
-
const shown = program[1].replace(/^"|"$/g, "");
|
|
19597
|
-
if (path34.resolve(shown) === path34.resolve(execPath)) return "launchd";
|
|
19598
|
-
}
|
|
19599
|
-
if (!sea && /^\s*state = /m.test(output)) return "launchd";
|
|
19600
|
-
return null;
|
|
19601
|
-
}
|
|
19602
|
-
function parseLaunchdEnvironment(xml) {
|
|
19603
|
-
const out = {};
|
|
19604
|
-
const marker = xml.indexOf("<key>EnvironmentVariables</key>");
|
|
19605
|
-
if (marker < 0) return out;
|
|
19606
|
-
const open = xml.indexOf("<dict>", marker);
|
|
19607
|
-
if (open < 0) return out;
|
|
19608
|
-
const close = xml.indexOf("</dict>", open);
|
|
19609
|
-
if (close < 0) return out;
|
|
19610
|
-
const body = xml.slice(open + "<dict>".length, close);
|
|
19611
|
-
for (const m of body.matchAll(/<key>([^<]+)<\/key>\s*<string>([^<]*)<\/string>/g)) {
|
|
19612
|
-
out[m[1]] = m[2];
|
|
19613
|
-
}
|
|
19614
|
-
return out;
|
|
19615
|
-
}
|
|
19616
|
-
function detectServiceManager() {
|
|
19617
|
-
if (process.platform === "darwin") return detectLaunchd();
|
|
19618
|
-
if (process.platform !== "linux") return null;
|
|
19619
|
-
const serviceName = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME;
|
|
19620
|
-
try {
|
|
19621
|
-
return serviceManagerFromCgroup(
|
|
19622
|
-
fs27.readFileSync("/proc/self/cgroup", "utf8"),
|
|
19623
|
-
serviceName
|
|
19624
|
-
);
|
|
19625
|
-
} catch {
|
|
19626
|
-
return null;
|
|
19627
|
-
}
|
|
19628
|
-
}
|
|
19629
|
-
function detectLaunchd() {
|
|
19630
|
-
try {
|
|
19631
|
-
const res = spawnSync4(
|
|
19632
|
-
"launchctl",
|
|
19633
|
-
["print", `${launchdDomain()}/${launchdLabel()}`],
|
|
19634
|
-
{ encoding: "utf8", timeout: 3e3 }
|
|
19635
|
-
);
|
|
19636
|
-
if (res.status !== 0 || !res.stdout) return null;
|
|
19637
|
-
return serviceManagerFromLaunchctl(
|
|
19638
|
-
res.stdout,
|
|
19639
|
-
process.pid,
|
|
19640
|
-
process.execPath,
|
|
19641
|
-
isSeaRuntime()
|
|
19642
|
-
);
|
|
19643
|
-
} catch {
|
|
19644
|
-
return null;
|
|
19645
|
-
}
|
|
19646
|
-
}
|
|
19647
|
-
function serviceManager() {
|
|
19648
|
-
const v = process.env.ZQAGENT_SERVICE_MANAGER?.trim().toLowerCase();
|
|
19649
|
-
if (v === "systemd" || v === "launchd") return v;
|
|
19650
|
-
return detectServiceManager();
|
|
19651
|
-
}
|
|
19652
|
-
function parseServiceEnvironment(raw) {
|
|
19653
|
-
const out = {};
|
|
19654
|
-
for (const token of raw.trim().split(/\s+/)) {
|
|
19655
|
-
const idx = token.indexOf("=");
|
|
19656
|
-
if (idx > 0) out[token.slice(0, idx)] = token.slice(idx + 1);
|
|
19657
|
-
}
|
|
19658
|
-
return out;
|
|
19659
|
-
}
|
|
19660
|
-
var cachedServiceEnv = null;
|
|
19661
|
-
function readServiceEnvironment() {
|
|
19662
|
-
const serviceName = process.env.ZQAGENT_SERVICE_NAME?.trim() || DEFAULT_SERVICE_NAME;
|
|
19663
|
-
try {
|
|
19664
|
-
const res = spawnSync4(
|
|
19665
|
-
"systemctl",
|
|
19666
|
-
["show", serviceName, "--property=Environment", "--value", "--no-pager"],
|
|
19667
|
-
{ encoding: "utf8", timeout: 3e3 }
|
|
19668
|
-
);
|
|
19669
|
-
if (res.status !== 0 || !res.stdout) return {};
|
|
19670
|
-
return parseServiceEnvironment(res.stdout);
|
|
19671
|
-
} catch {
|
|
19672
|
-
return {};
|
|
20161
|
+
parsed = JSON.parse(raw.toString("utf-8"));
|
|
20162
|
+
} catch (err) {
|
|
20163
|
+
return { error: `\u6E05\u5355\u4E0D\u662F\u5408\u6CD5 JSON\uFF1A${err.message}` };
|
|
19673
20164
|
}
|
|
20165
|
+
const { manifest, error: error2 } = parseManifest(parsed, opts);
|
|
20166
|
+
if (!manifest) return { error: error2 };
|
|
20167
|
+
return { manifest, raw };
|
|
19674
20168
|
}
|
|
19675
|
-
function
|
|
19676
|
-
|
|
19677
|
-
|
|
19678
|
-
|
|
19679
|
-
|
|
20169
|
+
async function downloadBinary(bin, destPath, log = () => {
|
|
20170
|
+
}) {
|
|
20171
|
+
const partPath = `${destPath}.part`;
|
|
20172
|
+
fs27.mkdirSync(path35.dirname(destPath), { recursive: true });
|
|
20173
|
+
fs27.rmSync(partPath, { force: true });
|
|
20174
|
+
let res;
|
|
20175
|
+
try {
|
|
20176
|
+
res = await fetch(bin.url, { signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS2) });
|
|
20177
|
+
} catch (err) {
|
|
20178
|
+
return { error: `\u4E0B\u8F7D\u5931\u8D25\uFF1A${err.message}` };
|
|
19680
20179
|
}
|
|
19681
|
-
if (
|
|
19682
|
-
if (
|
|
19683
|
-
|
|
19684
|
-
|
|
19685
|
-
|
|
19686
|
-
|
|
19687
|
-
function readLaunchdEnvironment() {
|
|
20180
|
+
if (!res.ok) return { error: `\u4E0B\u8F7D\u5931\u8D25 HTTP ${res.status}` };
|
|
20181
|
+
if (!res.body) return { error: "\u4E0B\u8F7D\u54CD\u5E94\u6CA1\u6709 body" };
|
|
20182
|
+
const expected = bin.size && bin.size > 0 ? bin.size : void 0;
|
|
20183
|
+
const limit = expected ? Math.max(expected * 2, 1024 * 1024) : MAX_BINARY_BYTES;
|
|
20184
|
+
const hash = createHash3("sha256");
|
|
20185
|
+
let bytes = 0;
|
|
19688
20186
|
try {
|
|
19689
|
-
|
|
19690
|
-
|
|
19691
|
-
|
|
20187
|
+
const source = Readable2.fromWeb(res.body);
|
|
20188
|
+
await pipeline2(
|
|
20189
|
+
source,
|
|
20190
|
+
async function* (chunks) {
|
|
20191
|
+
for await (const chunk of chunks) {
|
|
20192
|
+
bytes += chunk.length;
|
|
20193
|
+
if (bytes > limit) throw new Error(`\u4EA7\u7269\u8D85\u8FC7\u5927\u5C0F\u4E0A\u9650\uFF08>${limit} \u5B57\u8282\uFF09`);
|
|
20194
|
+
hash.update(chunk);
|
|
20195
|
+
yield chunk;
|
|
20196
|
+
}
|
|
20197
|
+
},
|
|
20198
|
+
fs27.createWriteStream(partPath, { mode: 493 })
|
|
20199
|
+
);
|
|
20200
|
+
} catch (err) {
|
|
20201
|
+
fs27.rmSync(partPath, { force: true });
|
|
20202
|
+
return { error: `\u4E0B\u8F7D\u4E2D\u65AD\uFF1A${err.message}` };
|
|
19692
20203
|
}
|
|
19693
|
-
|
|
19694
|
-
|
|
19695
|
-
|
|
19696
|
-
return {
|
|
19697
|
-
ok: false,
|
|
19698
|
-
reason: "\u5F53\u524D\u4E0D\u662F\u5355\u6587\u4EF6\uFF08SEA\uFF09\u5F62\u6001\uFF1A\u8BF7\u7528 npm \u5347\u7EA7\uFF08npm i -g @zqagent/core@latest\uFF09"
|
|
19699
|
-
};
|
|
20204
|
+
const actual = hash.digest("hex");
|
|
20205
|
+
if (actual !== bin.sha256) {
|
|
20206
|
+
fs27.rmSync(partPath, { force: true });
|
|
20207
|
+
return { error: `SHA-256 \u4E0D\u5339\u914D\uFF08\u671F\u671B ${bin.sha256.slice(0, 12)}\u2026\uFF0C\u5B9E\u9645 ${actual.slice(0, 12)}\u2026\uFF09` };
|
|
19700
20208
|
}
|
|
19701
|
-
if (
|
|
19702
|
-
|
|
19703
|
-
|
|
19704
|
-
reason: "\u672A\u88AB systemd/launchd \u6258\u7BA1\uFF1A\u8BF7\u7528 deploy/service/install.sh \u5B89\u88C5\uFF0C\u6216\u624B\u52A8\u5347\u7EA7"
|
|
19705
|
-
};
|
|
20209
|
+
if (expected && bytes !== expected) {
|
|
20210
|
+
fs27.rmSync(partPath, { force: true });
|
|
20211
|
+
return { error: `\u4EA7\u7269\u5927\u5C0F\u4E0D\u5339\u914D\uFF08\u671F\u671B ${expected}\uFF0C\u5B9E\u9645 ${bytes}\uFF09` };
|
|
19706
20212
|
}
|
|
19707
|
-
|
|
19708
|
-
|
|
20213
|
+
fs27.rmSync(destPath, { force: true });
|
|
20214
|
+
fs27.renameSync(partPath, destPath);
|
|
20215
|
+
fs27.chmodSync(destPath, 493);
|
|
20216
|
+
log(`\u5DF2\u4E0B\u8F7D ${path35.basename(destPath)}\uFF08${Math.round(bytes / 1024 / 1024)}MB\uFF0C\u6821\u9A8C\u901A\u8FC7\uFF09`);
|
|
20217
|
+
return { bytes };
|
|
20218
|
+
}
|
|
20219
|
+
function selfCheck(binPath, expectedVersion) {
|
|
20220
|
+
try {
|
|
20221
|
+
const r = spawnSync4(binPath, ["--version"], {
|
|
20222
|
+
timeout: 2e4,
|
|
20223
|
+
encoding: "utf-8",
|
|
20224
|
+
env: { ...process.env, ZQAGENT_AUTO_UPDATE: "0" }
|
|
20225
|
+
});
|
|
20226
|
+
if (r.error) return { ok: false, error: `\u6267\u884C\u81EA\u68C0\u5931\u8D25\uFF1A${r.error.message}` };
|
|
20227
|
+
if (r.status !== 0) return { ok: false, error: `\u81EA\u68C0\u9000\u51FA\u7801 ${r.status}\uFF1A${(r.stderr || "").trim()}` };
|
|
20228
|
+
const out = `${r.stdout ?? ""}${r.stderr ?? ""}`;
|
|
20229
|
+
if (!out.includes(expectedVersion)) {
|
|
20230
|
+
return { ok: false, error: `\u81EA\u68C0\u7248\u672C\u4E0D\u7B26\uFF08\u671F\u671B ${expectedVersion}\uFF0C\u8F93\u51FA\uFF1A${out.trim().slice(0, 120)}\uFF09` };
|
|
20231
|
+
}
|
|
20232
|
+
return { ok: true };
|
|
20233
|
+
} catch (err) {
|
|
20234
|
+
return { ok: false, error: `\u81EA\u68C0\u5F02\u5E38\uFF1A${err.message}` };
|
|
19709
20235
|
}
|
|
19710
|
-
return { ok: true };
|
|
19711
20236
|
}
|
|
19712
20237
|
|
|
19713
20238
|
// src/update/installer.ts
|
|
19714
20239
|
init_esm_shims();
|
|
19715
20240
|
import * as fs29 from "fs";
|
|
19716
|
-
import * as
|
|
20241
|
+
import * as path37 from "path";
|
|
19717
20242
|
|
|
19718
20243
|
// src/update/state.ts
|
|
19719
20244
|
init_esm_shims();
|
|
19720
20245
|
import * as fs28 from "fs";
|
|
19721
|
-
import * as
|
|
20246
|
+
import * as path36 from "path";
|
|
19722
20247
|
function updatesDir(dataDir) {
|
|
19723
|
-
return
|
|
20248
|
+
return path36.join(dataDir, "updates");
|
|
19724
20249
|
}
|
|
19725
20250
|
function statePath(dataDir) {
|
|
19726
|
-
return
|
|
20251
|
+
return path36.join(updatesDir(dataDir), "state.json");
|
|
19727
20252
|
}
|
|
19728
20253
|
function loadState(dataDir) {
|
|
19729
20254
|
try {
|
|
@@ -19750,12 +20275,12 @@ function patchState(dataDir, patch) {
|
|
|
19750
20275
|
|
|
19751
20276
|
// src/update/installer.ts
|
|
19752
20277
|
function backupDir(dataDir) {
|
|
19753
|
-
return
|
|
20278
|
+
return path37.join(updatesDir(dataDir), "backup");
|
|
19754
20279
|
}
|
|
19755
20280
|
function backupCurrent(dataDir, execPath, version) {
|
|
19756
20281
|
const dir = backupDir(dataDir);
|
|
19757
20282
|
fs29.mkdirSync(dir, { recursive: true });
|
|
19758
|
-
const target =
|
|
20283
|
+
const target = path37.join(dir, `zqagent-${version}${process.platform === "win32" ? ".exe" : ""}`);
|
|
19759
20284
|
fs29.copyFileSync(execPath, target);
|
|
19760
20285
|
fs29.chmodSync(target, 493);
|
|
19761
20286
|
return target;
|
|
@@ -19787,7 +20312,7 @@ function installStaged(opts) {
|
|
|
19787
20312
|
const from = currentVersion();
|
|
19788
20313
|
log(`\u6B63\u5728\u5B89\u88C5 v${opts.version}\uFF08\u5F53\u524D v${from}\uFF09`);
|
|
19789
20314
|
const backupPath = backupCurrent(opts.dataDir, opts.execPath, from);
|
|
19790
|
-
log(`\u5DF2\u5907\u4EFD\u5F53\u524D\u7248\u672C\u5230 ${
|
|
20315
|
+
log(`\u5DF2\u5907\u4EFD\u5F53\u524D\u7248\u672C\u5230 ${path37.basename(backupPath)}`);
|
|
19791
20316
|
replaceExecutable(opts.execPath, opts.stagedPath);
|
|
19792
20317
|
return patchState(opts.dataDir, {
|
|
19793
20318
|
stagedVersion: void 0,
|
|
@@ -19831,7 +20356,7 @@ function rollback(dataDir, execPath, log = () => {
|
|
|
19831
20356
|
}
|
|
19832
20357
|
function readRollbackTarget(dataDir) {
|
|
19833
20358
|
try {
|
|
19834
|
-
const raw = fs29.readFileSync(
|
|
20359
|
+
const raw = fs29.readFileSync(path37.join(updatesDir(dataDir), "state.json"), "utf-8");
|
|
19835
20360
|
const s = JSON.parse(raw);
|
|
19836
20361
|
if (s.backupPath && s.backupVersion) return s;
|
|
19837
20362
|
} catch {
|
|
@@ -20008,7 +20533,7 @@ var UpdateController = class {
|
|
|
20008
20533
|
if (!bin) return `\u6E05\u5355\u6CA1\u6709\u5F53\u524D\u5E73\u53F0\uFF08${platformKey()}\uFF09\u7684\u4EA7\u7269`;
|
|
20009
20534
|
let stagedPath = state.stagedPath;
|
|
20010
20535
|
if (!(state.stagedVersion === manifest.version && stagedPath && fs30.existsSync(stagedPath))) {
|
|
20011
|
-
stagedPath =
|
|
20536
|
+
stagedPath = path38.join(
|
|
20012
20537
|
updatesDir(this.opts.dataDir),
|
|
20013
20538
|
"staged",
|
|
20014
20539
|
`zqagent-${manifest.version}${process.platform === "win32" ? ".exe" : ""}`
|
|
@@ -20183,7 +20708,7 @@ function seedDemoTenant(store) {
|
|
|
20183
20708
|
apiKey: env2("OPENAI_API_KEY"),
|
|
20184
20709
|
baseURL: env2("OPENAI_BASE_URL")
|
|
20185
20710
|
},
|
|
20186
|
-
workspaceRoot: workspace ?
|
|
20711
|
+
workspaceRoot: workspace ? path39.resolve(workspace) : void 0,
|
|
20187
20712
|
allowedCommands: []
|
|
20188
20713
|
};
|
|
20189
20714
|
store.saveTenant(demo);
|
|
@@ -20237,9 +20762,9 @@ function syncTenantModels(store) {
|
|
|
20237
20762
|
tenant.model = model;
|
|
20238
20763
|
changed = true;
|
|
20239
20764
|
}
|
|
20240
|
-
if (workspace && tenant.workspaceRoot !==
|
|
20241
|
-
console.log(`[sync] \u79DF\u6237 ${id} workspaceRoot \u5DF2\u540C\u6B65: ${tenant.workspaceRoot ?? "(\u6C99\u7BB1)"} \u2192 ${
|
|
20242
|
-
tenant.workspaceRoot =
|
|
20765
|
+
if (workspace && tenant.workspaceRoot !== path39.resolve(workspace)) {
|
|
20766
|
+
console.log(`[sync] \u79DF\u6237 ${id} workspaceRoot \u5DF2\u540C\u6B65: ${tenant.workspaceRoot ?? "(\u6C99\u7BB1)"} \u2192 ${path39.resolve(workspace)}`);
|
|
20767
|
+
tenant.workspaceRoot = path39.resolve(workspace);
|
|
20243
20768
|
changed = true;
|
|
20244
20769
|
}
|
|
20245
20770
|
if (apiKey && tenant.provider.apiKey !== apiKey) {
|
|
@@ -20300,7 +20825,7 @@ function listenWithPortFallback(server, startPort, host, dataDir, limit = PORT_F
|
|
|
20300
20825
|
}
|
|
20301
20826
|
try {
|
|
20302
20827
|
fs31.mkdirSync(dataDir, { recursive: true });
|
|
20303
|
-
fs31.writeFileSync(
|
|
20828
|
+
fs31.writeFileSync(path39.join(dataDir, "server-port"), `${actualPort}
|
|
20304
20829
|
`);
|
|
20305
20830
|
} catch {
|
|
20306
20831
|
}
|
|
@@ -20311,7 +20836,7 @@ function listenWithPortFallback(server, startPort, host, dataDir, limit = PORT_F
|
|
|
20311
20836
|
});
|
|
20312
20837
|
}
|
|
20313
20838
|
function startServer(opts = {}) {
|
|
20314
|
-
const dataDir =
|
|
20839
|
+
const dataDir = path39.resolve(opts.dataDir ?? env2("DATA_DIR") ?? DEFAULT_DATA_DIR);
|
|
20315
20840
|
const port = opts.port ?? Number(env2("PORT") ?? 8787);
|
|
20316
20841
|
const host = opts.host ?? env2("HOST") ?? "127.0.0.1";
|
|
20317
20842
|
exitWhenOrphaned();
|
|
@@ -20341,7 +20866,7 @@ function startServer(opts = {}) {
|
|
|
20341
20866
|
}
|
|
20342
20867
|
const adminKey = ensureAdminKey();
|
|
20343
20868
|
const secretKey = env2("SECRET_KEY");
|
|
20344
|
-
const secretBox = secretKey ? SecretBox.fromHex(secretKey) : SecretBox.fromFile(
|
|
20869
|
+
const secretBox = secretKey ? SecretBox.fromHex(secretKey) : SecretBox.fromFile(path39.join(dataDir, "secret.key"));
|
|
20345
20870
|
if (secretKey && !secretBox) {
|
|
20346
20871
|
console.warn("[crypto] SECRET_KEY \u975E\u6CD5\uFF08\u9700 64 \u4F4D hex\uFF09\uFF0C\u901A\u77E5\u51ED\u636E\u5C06\u9000\u5316\u4E3A\u660E\u6587");
|
|
20347
20872
|
}
|
|
@@ -20350,7 +20875,7 @@ function startServer(opts = {}) {
|
|
|
20350
20875
|
let fleet = null;
|
|
20351
20876
|
let fleetCred = null;
|
|
20352
20877
|
function connectFleet(cred) {
|
|
20353
|
-
const localId =
|
|
20878
|
+
const localId = ensureNodeId(store);
|
|
20354
20879
|
const nodeId = (cred.nodeId ?? "").trim() || localId;
|
|
20355
20880
|
if (nodeId !== localId) store.saveNodeId(nodeId);
|
|
20356
20881
|
fleet?.close();
|
|
@@ -20378,7 +20903,7 @@ function startServer(opts = {}) {
|
|
|
20378
20903
|
function fleetStatus() {
|
|
20379
20904
|
return {
|
|
20380
20905
|
linked: fleet !== null,
|
|
20381
|
-
nodeId:
|
|
20906
|
+
nodeId: ensureNodeId(store),
|
|
20382
20907
|
hubUrl: fleetCred?.hubUrl,
|
|
20383
20908
|
gatewayUrl: fleetCred?.gatewayUrl ?? env2("FLEET_GATEWAY_URL"),
|
|
20384
20909
|
online: fleet?.isConnected() ?? false,
|
|
@@ -20390,8 +20915,15 @@ function startServer(opts = {}) {
|
|
|
20390
20915
|
const fleetController = {
|
|
20391
20916
|
status: fleetStatus,
|
|
20392
20917
|
async enroll(input) {
|
|
20393
|
-
const nodeId =
|
|
20394
|
-
const cred = await
|
|
20918
|
+
const nodeId = ensureNodeId(store);
|
|
20919
|
+
const cred = input.account ? await hubEnrollByAccount(input.hubUrl, {
|
|
20920
|
+
email: input.account.email,
|
|
20921
|
+
phone: input.account.phone,
|
|
20922
|
+
password: input.account.password,
|
|
20923
|
+
code: input.account.smsCode,
|
|
20924
|
+
nodeId,
|
|
20925
|
+
label: input.label
|
|
20926
|
+
}) : await hubEnrollByCode(input.hubUrl, {
|
|
20395
20927
|
code: input.code,
|
|
20396
20928
|
nodeId,
|
|
20397
20929
|
label: input.label
|
|
@@ -20417,7 +20949,7 @@ function startServer(opts = {}) {
|
|
|
20417
20949
|
gatewayUrl: fleetCred.gatewayUrl ?? env2("FLEET_GATEWAY_URL"),
|
|
20418
20950
|
fleetToken: fleetCred.fleetToken,
|
|
20419
20951
|
fleetSecret: fleetCred.fleetSecret,
|
|
20420
|
-
nodeId:
|
|
20952
|
+
nodeId: ensureNodeId(store)
|
|
20421
20953
|
};
|
|
20422
20954
|
}
|
|
20423
20955
|
};
|
|
@@ -20570,7 +21102,7 @@ function printReady(info, qq) {
|
|
|
20570
21102
|
`zqagent server \u76D1\u542C http://${info.host}:${info.port}`,
|
|
20571
21103
|
`\u6570\u636E\u76EE\u5F55: ${info.dataDir}`,
|
|
20572
21104
|
`\u5BA1\u6279\u6302\u8D77\u8D85\u65F6: ${env2("APPROVAL_TIMEOUT_SECONDS") ?? 900}s\uFF08\u8D85\u65F6\u540E\u56DE\u6536\u5185\u5B58\u4EFB\u52A1\uFF0C\u53EF\u7ECF resume \u6062\u590D\uFF09`,
|
|
20573
|
-
env2("ZQAGENT_LOG_ADMIN_KEY") === "0" ? `\u7BA1\u7406\u5458\u5BC6\u94A5: ${maskKey(info.adminKey)}\uFF08\u5DF2\u8131\u654F\uFF0C\u5B8C\u6574\u503C\u89C1 ${
|
|
21105
|
+
env2("ZQAGENT_LOG_ADMIN_KEY") === "0" ? `\u7BA1\u7406\u5458\u5BC6\u94A5: ${maskKey(info.adminKey)}\uFF08\u5DF2\u8131\u654F\uFF0C\u5B8C\u6574\u503C\u89C1 ${path39.join(info.dataDir, "admin.json")}\uFF09` : `\u7BA1\u7406\u5458\u5BC6\u94A5: ${info.adminKey}\uFF08\u63A7\u5236\u53F0\u591A\u9879\u76EE\u5165\u53E3\uFF1A/api/v1/projects\uFF1B\u9879\u76EE\u7EA7\u63A5\u53E3\u52A0 X-Project-Id \u5934\uFF09`
|
|
20574
21106
|
];
|
|
20575
21107
|
if (info.fleetNodeId) {
|
|
20576
21108
|
lines.push(
|
|
@@ -20589,152 +21121,6 @@ function printReady(info, qq) {
|
|
|
20589
21121
|
for (const l of lines) console.log(l);
|
|
20590
21122
|
}
|
|
20591
21123
|
|
|
20592
|
-
// src/cli/account-enroll.ts
|
|
20593
|
-
init_esm_shims();
|
|
20594
|
-
import * as path39 from "path";
|
|
20595
|
-
import * as readline from "readline/promises";
|
|
20596
|
-
var SKIP_ANSWERS = /* @__PURE__ */ new Set(["-", "skip", "none", "no"]);
|
|
20597
|
-
function resolveDefaultHub(hubUrl, env3 = process.env) {
|
|
20598
|
-
return (hubUrl ?? env3.HUB_URL ?? DEFAULT_HUB_URL).trim().replace(/\/$/, "");
|
|
20599
|
-
}
|
|
20600
|
-
function parseHubAnswer(answer, fallback) {
|
|
20601
|
-
const a = answer.trim();
|
|
20602
|
-
if (SKIP_ANSWERS.has(a.toLowerCase())) return null;
|
|
20603
|
-
return (a || fallback).replace(/\/$/, "");
|
|
20604
|
-
}
|
|
20605
|
-
function resolveDataDir2(dataDir) {
|
|
20606
|
-
return path39.resolve(dataDir ?? process.env.DATA_DIR ?? DEFAULT_DATA_DIR);
|
|
20607
|
-
}
|
|
20608
|
-
async function maybeAccountEnroll(opts = {}) {
|
|
20609
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) return;
|
|
20610
|
-
let store;
|
|
20611
|
-
try {
|
|
20612
|
-
store = new Store(resolveDataDir2(opts.dataDir));
|
|
20613
|
-
if (resolveFleetConfig(store)) return;
|
|
20614
|
-
} catch (e) {
|
|
20615
|
-
cliErr(`\u63A5\u5165\u68C0\u67E5\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
20616
|
-
return;
|
|
20617
|
-
}
|
|
20618
|
-
const rl2 = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
20619
|
-
try {
|
|
20620
|
-
await runWizard(rl2, store, opts);
|
|
20621
|
-
} catch (e) {
|
|
20622
|
-
cliErr(`\u63A5\u5165\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
20623
|
-
cliLog(" \u53EF\u7A0D\u540E\u5728\u63A7\u5236\u53F0\u751F\u6210\u63A5\u5165\u7801\uFF0C\u518D\u6267\u884C\uFF1Azqagent link --hub <Hub\u5730\u5740> --code <\u63A5\u5165\u7801>");
|
|
20624
|
-
} finally {
|
|
20625
|
-
rl2.close();
|
|
20626
|
-
}
|
|
20627
|
-
}
|
|
20628
|
-
async function runWizard(rl2, store, opts) {
|
|
20629
|
-
cliLog("");
|
|
20630
|
-
cliLog("\u672C\u673A\u5C1A\u672A\u63A5\u5165 Hub\u3002\u53EF\u7528 Hub \u8D26\u53F7\u63A5\u5165\uFF08\u8282\u70B9\u9ED8\u8BA4\u8FDB\u5165\u300C\u672A\u5206\u7EC4\u300D\uFF09\uFF1B\u8F93\u5165 - \u8DF3\u8FC7\u4FDD\u6301\u7EAF\u672C\u5730\u3002");
|
|
20631
|
-
const fallback = resolveDefaultHub(opts.hubUrl);
|
|
20632
|
-
const answer = await rl2.question(`Hub \u5730\u5740 [${fallback}]\uFF1A`);
|
|
20633
|
-
const hubUrl = parseHubAnswer(answer, fallback);
|
|
20634
|
-
if (!hubUrl) {
|
|
20635
|
-
cliLog("\u5DF2\u8DF3\u8FC7\u63A5\u5165\uFF1A\u8282\u70B9\u4FDD\u6301\u7EAF\u672C\u5730\u8FD0\u884C\u3002");
|
|
20636
|
-
return;
|
|
20637
|
-
}
|
|
20638
|
-
cliLog("\u767B\u5F55\u65B9\u5F0F\uFF1A1) \u90AE\u7BB1 + \u5BC6\u7801 2) \u624B\u673A\u53F7 + \u5BC6\u7801 3) \u624B\u673A\u53F7 + \u77ED\u4FE1\u9A8C\u8BC1\u7801");
|
|
20639
|
-
const mode = (await rl2.question("\u8BF7\u9009\u62E9 [1]\uFF1A")).trim() || "1";
|
|
20640
|
-
const input = {};
|
|
20641
|
-
if (mode === "1") {
|
|
20642
|
-
input.email = (await rl2.question("\u90AE\u7BB1\uFF1A")).trim();
|
|
20643
|
-
input.password = await askHidden(rl2, "\u5BC6\u7801\uFF1A");
|
|
20644
|
-
if (!input.email || !input.password) {
|
|
20645
|
-
cliErr("\u90AE\u7BB1\u4E0E\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
20646
|
-
return;
|
|
20647
|
-
}
|
|
20648
|
-
} else if (mode === "2") {
|
|
20649
|
-
input.phone = (await rl2.question("\u624B\u673A\u53F7\uFF1A")).trim();
|
|
20650
|
-
input.password = await askHidden(rl2, "\u5BC6\u7801\uFF1A");
|
|
20651
|
-
if (!input.phone || !input.password) {
|
|
20652
|
-
cliErr("\u624B\u673A\u53F7\u4E0E\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
20653
|
-
return;
|
|
20654
|
-
}
|
|
20655
|
-
} else if (mode === "3") {
|
|
20656
|
-
input.phone = (await rl2.question("\u624B\u673A\u53F7\uFF1A")).trim();
|
|
20657
|
-
if (!input.phone) {
|
|
20658
|
-
cliErr("\u624B\u673A\u53F7\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
20659
|
-
return;
|
|
20660
|
-
}
|
|
20661
|
-
try {
|
|
20662
|
-
const sent = await hubSendSms(hubUrl, { phone: input.phone, purpose: "login" });
|
|
20663
|
-
if (sent.debugCode) cliLog(`\uFF08\u8C03\u8BD5\u6A21\u5F0F\u9A8C\u8BC1\u7801\uFF1A${sent.debugCode}\uFF09`);
|
|
20664
|
-
else cliLog("\u9A8C\u8BC1\u7801\u5DF2\u53D1\u9001\uFF0C5 \u5206\u949F\u5185\u6709\u6548\u3002");
|
|
20665
|
-
} catch (e) {
|
|
20666
|
-
cliErr(`\u77ED\u4FE1\u9A8C\u8BC1\u7801\u53D1\u9001\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
20667
|
-
cliLog(" \u53EF\u6539\u7528\u65B9\u5F0F 1/2\uFF08\u5BC6\u7801\u767B\u5F55\uFF09\uFF0C\u6216\u5728\u7F51\u9875\u7AEF\u751F\u6210\u63A5\u5165\u7801\u540E\u6267\u884C\uFF1A");
|
|
20668
|
-
cliLog(" zqagent link --hub <Hub\u5730\u5740> --code <\u63A5\u5165\u7801>");
|
|
20669
|
-
return;
|
|
20670
|
-
}
|
|
20671
|
-
input.code = (await rl2.question("\u77ED\u4FE1\u9A8C\u8BC1\u7801\uFF1A")).trim();
|
|
20672
|
-
if (!input.code) {
|
|
20673
|
-
cliErr("\u9A8C\u8BC1\u7801\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
20674
|
-
return;
|
|
20675
|
-
}
|
|
20676
|
-
} else {
|
|
20677
|
-
cliErr("\u672A\u77E5\u7684\u767B\u5F55\u65B9\u5F0F\uFF0C\u5DF2\u8DF3\u8FC7\u63A5\u5165\u3002");
|
|
20678
|
-
return;
|
|
20679
|
-
}
|
|
20680
|
-
const nodeId = ensureNodeId2(store);
|
|
20681
|
-
const cred = await hubEnrollByAccount(hubUrl, { ...input, nodeId, label: opts.label });
|
|
20682
|
-
store.saveFleetCredential({
|
|
20683
|
-
...cred,
|
|
20684
|
-
label: opts.label ?? cred.label,
|
|
20685
|
-
enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
20686
|
-
});
|
|
20687
|
-
cliLog(`\u2705 \u5DF2\u63A5\u5165 Hub\uFF1A\u8282\u70B9 ${cred.nodeId}\uFF08\u7F51\u5173 ${cred.gatewayUrl ?? "\u672A\u4E0B\u53D1"}\uFF09`);
|
|
20688
|
-
cliLog(" \u51ED\u636E\u5DF2\u4FDD\u5B58\u5230 fleet.json\uFF0C\u672C\u6B21\u542F\u52A8\u5373\u8FDE\u63A5 Hub\u3002");
|
|
20689
|
-
}
|
|
20690
|
-
async function askHidden(rl2, prompt) {
|
|
20691
|
-
if (!process.stdin.isTTY) return (await rl2.question(prompt)).trim();
|
|
20692
|
-
return new Promise((resolve24) => {
|
|
20693
|
-
const saved = process.stdin.listeners("data");
|
|
20694
|
-
process.stdin.removeAllListeners("data");
|
|
20695
|
-
cliWrite(prompt);
|
|
20696
|
-
rl2.pause();
|
|
20697
|
-
process.stdin.setRawMode(true);
|
|
20698
|
-
process.stdin.resume();
|
|
20699
|
-
let buf = "";
|
|
20700
|
-
const cleanup = () => {
|
|
20701
|
-
process.stdin.removeListener("data", onData);
|
|
20702
|
-
for (const listener of saved) {
|
|
20703
|
-
process.stdin.on("data", listener);
|
|
20704
|
-
}
|
|
20705
|
-
process.stdin.setRawMode(true);
|
|
20706
|
-
rl2.resume();
|
|
20707
|
-
};
|
|
20708
|
-
const onData = (chunk) => {
|
|
20709
|
-
const s = chunk.toString().replace(/\x1b\[[0-9;?]*[A-Za-z~]/g, "").replace(/\x1bO[A-Za-z]/g, "");
|
|
20710
|
-
for (const ch of s) {
|
|
20711
|
-
if (ch === "\r" || ch === "\n") {
|
|
20712
|
-
cleanup();
|
|
20713
|
-
cliWrite("\n");
|
|
20714
|
-
resolve24(buf);
|
|
20715
|
-
return;
|
|
20716
|
-
}
|
|
20717
|
-
if (ch === "") {
|
|
20718
|
-
cleanup();
|
|
20719
|
-
cliWrite("\n");
|
|
20720
|
-
resolve24("");
|
|
20721
|
-
return;
|
|
20722
|
-
}
|
|
20723
|
-
if (ch === "\x7F" || ch === "\b") {
|
|
20724
|
-
if (buf.length > 0) {
|
|
20725
|
-
buf = buf.slice(0, -1);
|
|
20726
|
-
cliWrite("\b \b");
|
|
20727
|
-
}
|
|
20728
|
-
} else if (ch >= " ") {
|
|
20729
|
-
buf += ch;
|
|
20730
|
-
cliWrite("*");
|
|
20731
|
-
}
|
|
20732
|
-
}
|
|
20733
|
-
};
|
|
20734
|
-
process.stdin.on("data", onData);
|
|
20735
|
-
});
|
|
20736
|
-
}
|
|
20737
|
-
|
|
20738
21124
|
// src/cli/serve.ts
|
|
20739
21125
|
function parse2(argv) {
|
|
20740
21126
|
const out = {};
|
|
@@ -20747,6 +21133,21 @@ function parse2(argv) {
|
|
|
20747
21133
|
} else if (a === "--enroll-code" || a === "--code") {
|
|
20748
21134
|
out.code = v;
|
|
20749
21135
|
i++;
|
|
21136
|
+
} else if (a === "--username" || a === "--user") {
|
|
21137
|
+
out.username = v;
|
|
21138
|
+
i++;
|
|
21139
|
+
} else if (a === "--email") {
|
|
21140
|
+
out.email = v;
|
|
21141
|
+
i++;
|
|
21142
|
+
} else if (a === "--phone") {
|
|
21143
|
+
out.phone = v;
|
|
21144
|
+
i++;
|
|
21145
|
+
} else if (a === "--password") {
|
|
21146
|
+
out.password = v;
|
|
21147
|
+
i++;
|
|
21148
|
+
} else if (a === "--sms-code") {
|
|
21149
|
+
out.smsCode = v;
|
|
21150
|
+
i++;
|
|
20750
21151
|
} else if (a === "--label") {
|
|
20751
21152
|
out.label = v;
|
|
20752
21153
|
i++;
|
|
@@ -20767,7 +21168,32 @@ async function runServeCommand(argv) {
|
|
|
20767
21168
|
const args = parse2(argv);
|
|
20768
21169
|
const hubUrl = (args.hubUrl ?? process.env.HUB_URL ?? "").trim();
|
|
20769
21170
|
const code = (args.code ?? process.env.HUB_ENROLL_CODE ?? "").trim();
|
|
20770
|
-
|
|
21171
|
+
const account = buildAccountAuth(args);
|
|
21172
|
+
if (code && account) {
|
|
21173
|
+
cliErr("--enroll-code \u4E0E Hub \u8D26\u53F7\u53C2\u6570\uFF08--username/--password \u7B49\uFF09\u53EA\u80FD\u4E8C\u9009\u4E00\u3002");
|
|
21174
|
+
return;
|
|
21175
|
+
}
|
|
21176
|
+
if (account && !isCompleteAccount(account) && !process.stdin.isTTY) {
|
|
21177
|
+
cliErr("\u8D26\u53F7\u53C2\u6570\u7F3A\u5C11\u5BC6\u7801\u6216\u77ED\u4FE1\u9A8C\u8BC1\u7801\uFF1A\u975E\u4EA4\u4E92\u73AF\u5883\u8BF7\u8865 --password \u6216 --sms-code\u3002");
|
|
21178
|
+
}
|
|
21179
|
+
if (!code && isCompleteAccount(account)) {
|
|
21180
|
+
try {
|
|
21181
|
+
const r = await linkNode({
|
|
21182
|
+
hubUrl: resolveDefaultHub(args.hubUrl || void 0),
|
|
21183
|
+
account,
|
|
21184
|
+
dataDir: args.dataDir,
|
|
21185
|
+
label: args.label,
|
|
21186
|
+
host: args.host,
|
|
21187
|
+
port: args.port
|
|
21188
|
+
});
|
|
21189
|
+
cliLog(
|
|
21190
|
+
r.mode === "hot" ? `\u2705 \u5DF2\u901A\u8FC7 Hub \u8D26\u53F7\u63A5\u5165\uFF08\u8282\u70B9 ${r.nodeId}\uFF09` : `\u2705 \u5DF2\u4FDD\u5B58 Hub \u63A5\u5165\u51ED\u636E\uFF08\u8282\u70B9 ${r.nodeId}\uFF09`
|
|
21191
|
+
);
|
|
21192
|
+
} catch (e) {
|
|
21193
|
+
cliErr(`Hub \u8D26\u53F7\u63A5\u5165\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
21194
|
+
}
|
|
21195
|
+
}
|
|
21196
|
+
if (!(hubUrl && code) && !isCompleteAccount(account)) {
|
|
20771
21197
|
await maybeAccountEnroll({ dataDir: args.dataDir, hubUrl: args.hubUrl, label: args.label });
|
|
20772
21198
|
}
|
|
20773
21199
|
const handle = startServer({
|
|
@@ -20906,7 +21332,7 @@ function updateSessionMetaFile(stateDir2, sessionId, patch) {
|
|
|
20906
21332
|
// src/cli/debug.ts
|
|
20907
21333
|
init_esm_shims();
|
|
20908
21334
|
import * as fs33 from "fs";
|
|
20909
|
-
import * as
|
|
21335
|
+
import * as os10 from "os";
|
|
20910
21336
|
import * as path42 from "path";
|
|
20911
21337
|
var LOG_NAME = "zqagent-debug.log";
|
|
20912
21338
|
var TRUTHY = /^(1|true|yes|on)$/i;
|
|
@@ -20920,7 +21346,7 @@ function resolveLogFile() {
|
|
|
20920
21346
|
const explicit = process.env.ZQAGENT_DEBUG_LOG;
|
|
20921
21347
|
if (explicit) return path42.resolve(explicit);
|
|
20922
21348
|
const dir = process.env.ZQAGENT_DEBUG_DIR;
|
|
20923
|
-
return path42.join(dir ? path42.resolve(dir) :
|
|
21349
|
+
return path42.join(dir ? path42.resolve(dir) : os10.tmpdir(), LOG_NAME);
|
|
20924
21350
|
}
|
|
20925
21351
|
function enableDebug(argv = process.argv) {
|
|
20926
21352
|
if (enabled) return true;
|
|
@@ -21342,7 +21768,7 @@ function cycleMode(engine) {
|
|
|
21342
21768
|
engine.permissions.mode = next;
|
|
21343
21769
|
return next;
|
|
21344
21770
|
}
|
|
21345
|
-
var rl =
|
|
21771
|
+
var rl = readline3.createInterface({
|
|
21346
21772
|
input: process.stdin,
|
|
21347
21773
|
output: process.stdout
|
|
21348
21774
|
});
|
|
@@ -21358,20 +21784,7 @@ var _exitHandler = null;
|
|
|
21358
21784
|
rl.on("SIGINT", () => {
|
|
21359
21785
|
_exitHandler?.();
|
|
21360
21786
|
});
|
|
21361
|
-
|
|
21362
|
-
const iface = rl;
|
|
21363
|
-
const orig = iface._ttyWrite;
|
|
21364
|
-
iface._ttyWrite = function(s, key) {
|
|
21365
|
-
const k = key;
|
|
21366
|
-
if (k && (k.name === "up" || k.name === "down") && !k.ctrl && !k.meta && !k.shift) {
|
|
21367
|
-
if (iface.cursor > 0) {
|
|
21368
|
-
iface._moveCursor(-iface.cursor);
|
|
21369
|
-
}
|
|
21370
|
-
}
|
|
21371
|
-
orig.call(rl, s, key);
|
|
21372
|
-
};
|
|
21373
|
-
}
|
|
21374
|
-
patchReadlineHistoryNav();
|
|
21787
|
+
patchReadlineHistoryNav(rl);
|
|
21375
21788
|
dlog("init", "\u6A21\u5757\u521D\u59CB\u5316\u5B8C\u6210\uFF08readline / \u8F93\u5165\u8DEF\u7531 / \u5386\u53F2\u5BFC\u822A\u5C31\u7EEA\uFF09");
|
|
21376
21789
|
function question(prompt) {
|
|
21377
21790
|
return inputRouter.ask(prompt);
|
|
@@ -21835,7 +22248,7 @@ async function offerTerminalSetup(engine, canUseAgent) {
|
|
|
21835
22248
|
}
|
|
21836
22249
|
var KNOWN_SUBCOMMANDS = /* @__PURE__ */ new Set(["link", "serve", "update"]);
|
|
21837
22250
|
function cliVersion() {
|
|
21838
|
-
const env3 = "0.2.
|
|
22251
|
+
const env3 = "0.2.12"?.trim();
|
|
21839
22252
|
if (env3) return env3;
|
|
21840
22253
|
try {
|
|
21841
22254
|
const req2 = createRequire4(import.meta.url);
|
|
@@ -21853,11 +22266,13 @@ function printCliUsage() {
|
|
|
21853
22266
|
cliLog(" zqagent serve [\u9009\u9879] \u4EE5 headless \u65B9\u5F0F\u5E38\u9A7B\u4E3A\u53EF\u88AB Hub \u7BA1\u7406\u7684\u8282\u70B9");
|
|
21854
22267
|
cliLog(" zqagent update [--status|--check|--now|--rollback]");
|
|
21855
22268
|
cliLog(" \u67E5\u770B/\u624B\u52A8\u89E6\u53D1\u8282\u70B9\u81EA\u52A8\u66F4\u65B0");
|
|
21856
|
-
cliLog(" zqagent link --hub <url> --
|
|
21857
|
-
cliLog("
|
|
22269
|
+
cliLog(" zqagent link [--hub <url>] [--username <\u90AE\u7BB1/\u624B\u673A\u53F7> --password <\u5BC6\u7801>]");
|
|
22270
|
+
cliLog(" [--code <\u63A5\u5165\u7801>] [--label \u540D\u79F0]");
|
|
22271
|
+
cliLog(" \u628A\u672C\u673A\u8282\u70B9\u63A5\u5165 Hub\uFF08\u8D26\u53F7\u76F4\u8FDE\u6216\u63A5\u5165\u7801\uFF1B\u672C\u673A\u6709 server \u65F6\u70ED\u63A5\u5165\uFF09");
|
|
21858
22272
|
cliLog("");
|
|
21859
22273
|
cliLog("serve \u9009\u9879\uFF1A--port <n> --host <addr> --data-dir <dir>");
|
|
21860
22274
|
cliLog(" --hub <url> --enroll-code <\u7801> --label <\u540D\u79F0> \uFF08\u542F\u52A8\u5373\u63A5\u5165\uFF09");
|
|
22275
|
+
cliLog(" --hub <url> --username <\u90AE\u7BB1/\u624B\u673A\u53F7> --password <\u5BC6\u7801>\uFF08\u8D26\u53F7\u63A5\u5165\uFF09");
|
|
21861
22276
|
cliLog("\u5176\u5B83\u9009\u9879\uFF1A--resume <\u4F1A\u8BDDID> --debug --help/-h --version/-v");
|
|
21862
22277
|
}
|
|
21863
22278
|
async function main() {
|
|
@@ -21874,7 +22289,10 @@ async function main() {
|
|
|
21874
22289
|
process.exit(0);
|
|
21875
22290
|
}
|
|
21876
22291
|
if (subcommand === "link") {
|
|
21877
|
-
const ok2 = await runLinkCommand(process.argv.slice(3)
|
|
22292
|
+
const ok2 = await runLinkCommand(process.argv.slice(3), {
|
|
22293
|
+
rl,
|
|
22294
|
+
interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY)
|
|
22295
|
+
});
|
|
21878
22296
|
rl.close();
|
|
21879
22297
|
process.exit(ok2 ? 0 : 1);
|
|
21880
22298
|
}
|
|
@@ -22775,7 +23193,11 @@ async function main() {
|
|
|
22775
23193
|
case "/link": {
|
|
22776
23194
|
const code = parts[1];
|
|
22777
23195
|
const hub = parts[2] ?? process.env.HUB_URL;
|
|
22778
|
-
if (!code
|
|
23196
|
+
if (!code) {
|
|
23197
|
+
await runLinkCommand([], { rl, interactive: true });
|
|
23198
|
+
break;
|
|
23199
|
+
}
|
|
23200
|
+
if (!hub) {
|
|
22779
23201
|
cliLog("\u7528\u6CD5: /link <\u6CE8\u518C\u7801> [Hub\u5730\u5740]\uFF08Hub\u5730\u5740\u4E5F\u53EF\u7531 HUB_URL \u73AF\u5883\u53D8\u91CF\u63D0\u4F9B\uFF09");
|
|
22780
23202
|
break;
|
|
22781
23203
|
}
|